From eead50cce68a59b96726c2f7b95f4867c30d1fb7 Mon Sep 17 00:00:00 2001 From: Nick Whitlock Date: Wed, 24 May 2023 02:05:32 -0400 Subject: [PATCH 1/3] Merged base and d3xp together. After this commit, all of the DOOM 3 base code and Resurrection of Evil SDK code exist as one unified codebase, producing two DLLs but sharing 90% of the same code. Anything that is different between them (should) be `#ifdef`'d out. The primary motivation for doing this is to eliminate code reuse. I want to develop a mod for both Resurrection of Evil and the base game, but I don't want to make my changes twice. Thus, having a unified codebase like this makes a lot of sense. --- CMakeLists.txt | 100 +- d3xp/AF.cpp | 1272 --- d3xp/AF.h | 127 - d3xp/AFEntity.cpp | 3695 --------- d3xp/AFEntity.h | 616 -- d3xp/Actor.cpp | 3405 -------- d3xp/Actor.h | 344 - d3xp/BrittleFracture.cpp | 1382 ---- d3xp/BrittleFracture.h | 138 - d3xp/Camera.cpp | 725 -- d3xp/Camera.h | 135 - d3xp/EndLevel.cpp | 187 - d3xp/EndLevel.h | 72 - d3xp/Entity.cpp | 5615 ------------- d3xp/Entity.h | 629 -- d3xp/Fx.cpp | 824 -- d3xp/Fx.h | 110 - d3xp/GameBase.h | 81 - d3xp/GameEdit.cpp | 1148 --- d3xp/GameEdit.h | 125 - d3xp/Game_local.cpp | 5029 ------------ d3xp/Game_local.h | 719 -- d3xp/Game_network.cpp | 1803 ----- d3xp/IK.cpp | 1130 --- d3xp/IK.h | 187 - d3xp/Item.cpp | 2168 ----- d3xp/Item.h | 316 - d3xp/Light.cpp | 1165 --- d3xp/Light.h | 139 - d3xp/Misc.cpp | 3762 --------- d3xp/Misc.h | 900 --- d3xp/Moveable.cpp | 1358 ---- d3xp/Moveable.h | 222 - d3xp/Mover.cpp | 4695 ----------- d3xp/Mover.h | 563 -- d3xp/MultiplayerGame.cpp | 4390 ---------- d3xp/MultiplayerGame.h | 488 -- d3xp/Player.cpp | 10125 ------------------------ d3xp/Player.h | 852 -- d3xp/PlayerIcon.cpp | 199 - d3xp/PlayerIcon.h | 66 - d3xp/PlayerView.cpp | 1855 ----- d3xp/PlayerView.h | 437 - d3xp/Projectile.cpp | 2656 ------- d3xp/Projectile.h | 288 - d3xp/Pvs.cpp | 1457 ---- d3xp/Pvs.h | 137 - d3xp/SecurityCamera.cpp | 586 -- d3xp/SecurityCamera.h | 99 - d3xp/SmokeParticles.cpp | 449 -- d3xp/SmokeParticles.h | 111 - d3xp/Sound.cpp | 304 - d3xp/Sound.h | 78 - d3xp/Target.cpp | 1798 ----- d3xp/Target.h | 581 -- d3xp/Trigger.cpp | 1326 ---- d3xp/Trigger.h | 321 - d3xp/Weapon.cpp | 3952 --------- d3xp/Weapon.h | 435 - d3xp/WorldSpawn.cpp | 141 - d3xp/WorldSpawn.h | 57 - d3xp/ai/AAS.cpp | 276 - d3xp/ai/AAS.h | 143 - d3xp/ai/AAS_debug.cpp | 499 -- d3xp/ai/AAS_local.h | 188 - d3xp/ai/AAS_pathing.cpp | 715 -- d3xp/ai/AAS_routing.cpp | 1348 ---- d3xp/ai/AI.cpp | 5350 ------------- d3xp/ai/AI.h | 745 -- d3xp/ai/AI_Vagary.cpp | 150 - d3xp/ai/AI_events.cpp | 2906 ------- d3xp/ai/AI_pathing.cpp | 1536 ---- d3xp/anim/Anim.cpp | 1090 --- d3xp/anim/Anim.h | 634 -- d3xp/anim/Anim_Blend.cpp | 5119 ------------ d3xp/anim/Anim_Import.cpp | 570 -- d3xp/anim/Anim_Testmodel.cpp | 931 --- d3xp/anim/Anim_Testmodel.h | 99 - d3xp/gamesys/Callbacks.cpp | 2626 ------ d3xp/gamesys/Class.cpp | 1002 --- d3xp/gamesys/Class.h | 362 - d3xp/gamesys/DebugGraph.cpp | 94 - d3xp/gamesys/DebugGraph.h | 47 - d3xp/gamesys/Event.cpp | 1066 --- d3xp/gamesys/Event.h | 216 - d3xp/gamesys/NoGameTypeInfo.h | 79 - d3xp/gamesys/SaveGame.cpp | 1563 ---- d3xp/gamesys/SaveGame.h | 186 - d3xp/gamesys/SysCmds.cpp | 2520 ------ d3xp/gamesys/SysCmds.h | 34 - d3xp/gamesys/SysCvar.cpp | 419 - d3xp/gamesys/SysCvar.h | 306 - d3xp/gamesys/TypeInfo.cpp | 1448 ---- d3xp/gamesys/TypeInfo.h | 56 - d3xp/physics/Clip.cpp | 1674 ---- d3xp/physics/Clip.h | 357 - d3xp/physics/Force.cpp | 92 - d3xp/physics/Force.h | 68 - d3xp/physics/Force_Constant.cpp | 136 - d3xp/physics/Force_Constant.h | 73 - d3xp/physics/Force_Drag.cpp | 157 - d3xp/physics/Force_Drag.h | 76 - d3xp/physics/Force_Field.cpp | 261 - d3xp/physics/Force_Field.h | 99 - d3xp/physics/Force_Spring.cpp | 165 - d3xp/physics/Force_Spring.h | 77 - d3xp/physics/Physics.cpp | 80 - d3xp/physics/Physics.h | 189 - d3xp/physics/Physics_AF.cpp | 8014 ------------------- d3xp/physics/Physics_AF.h | 1051 --- d3xp/physics/Physics_Actor.cpp | 382 - d3xp/physics/Physics_Actor.h | 115 - d3xp/physics/Physics_Base.cpp | 838 -- d3xp/physics/Physics_Base.h | 168 - d3xp/physics/Physics_Monster.cpp | 807 -- d3xp/physics/Physics_Monster.h | 156 - d3xp/physics/Physics_Parametric.cpp | 1181 --- d3xp/physics/Physics_Parametric.h | 181 - d3xp/physics/Physics_Player.cpp | 2058 ----- d3xp/physics/Physics_Player.h | 197 - d3xp/physics/Physics_RigidBody.cpp | 1542 ---- d3xp/physics/Physics_RigidBody.h | 200 - d3xp/physics/Physics_Static.cpp | 846 -- d3xp/physics/Physics_Static.h | 160 - d3xp/physics/Physics_StaticMulti.cpp | 1053 --- d3xp/physics/Physics_StaticMulti.h | 156 - d3xp/physics/Push.cpp | 1448 ---- d3xp/physics/Push.h | 120 - d3xp/script/Script_Compiler.cpp | 2700 ------- d3xp/script/Script_Compiler.h | 282 - d3xp/script/Script_Interpreter.cpp | 1835 ----- d3xp/script/Script_Interpreter.h | 291 - d3xp/script/Script_Program.cpp | 2223 ------ d3xp/script/Script_Program.h | 652 -- d3xp/script/Script_Thread.cpp | 1923 ----- d3xp/script/Script_Thread.h | 344 - game/AFEntity.cpp | 821 +- game/AFEntity.h | 138 + game/Actor.cpp | 129 +- game/Actor.h | 21 + game/BrittleFracture.cpp | 96 +- game/BrittleFracture.h | 4 + game/Camera.cpp | 4 + game/EndLevel.cpp | 4 +- game/Entity.cpp | 224 +- game/Entity.h | 95 + game/Fx.cpp | 30 + game/GameBase.h | 3 + game/Game_local.cpp | 674 +- game/Game_local.h | 62 +- game/Game_network.cpp | 47 +- {d3xp => game}/Grabber.cpp | 0 {d3xp => game}/Grabber.h | 0 game/Item.cpp | 829 +- game/Item.h | 87 + game/Light.cpp | 7 + game/Misc.cpp | 630 +- game/Misc.h | 132 + game/Moveable.cpp | 187 +- game/Moveable.h | 18 + game/Mover.cpp | 223 +- game/Mover.h | 10 + game/MultiplayerGame.cpp | 1029 ++- game/MultiplayerGame.h | 116 +- game/Player.cpp | 1712 +++- game/Player.h | 124 +- game/PlayerIcon.cpp | 20 +- game/PlayerIcon.h | 4 + game/PlayerView.cpp | 1412 +++- game/PlayerView.h | 309 +- game/Projectile.cpp | 286 + game/Projectile.h | 15 + game/Pvs.cpp | 35 + game/Pvs.h | 4 + game/SmokeParticles.cpp | 35 +- game/SmokeParticles.h | 10 +- game/Target.cpp | 36 + game/Target.h | 11 + game/Trigger.cpp | 134 + game/Trigger.h | 31 + game/Weapon.cpp | 797 +- game/Weapon.h | 65 + game/ai/AAS_debug.cpp | 2 +- game/ai/AAS_routing.cpp | 8 +- game/ai/AI.cpp | 294 +- game/ai/AI.h | 47 + game/ai/AI_events.cpp | 198 + game/ai/AI_pathing.cpp | 3 - game/anim/Anim.h | 6 + game/anim/Anim_Blend.cpp | 86 + game/anim/Anim_Import.cpp | 16 +- game/anim/Anim_Testmodel.cpp | 8 +- game/gamesys/Class.cpp | 9 + game/gamesys/Event.cpp | 198 +- game/gamesys/Event.h | 3 + game/gamesys/SaveGame.cpp | 10 + game/gamesys/SysCmds.cpp | 107 +- game/gamesys/SysCvar.cpp | 84 +- game/gamesys/SysCvar.h | 49 + game/gamesys/TypeInfo.cpp | 5 +- game/physics/Clip.cpp | 10 +- {d3xp => game}/physics/Force_Grab.cpp | 0 {d3xp => game}/physics/Force_Grab.h | 0 game/physics/Physics_AF.cpp | 3 +- game/script/Script_Compiler.cpp | 4 +- game/script/Script_Interpreter.cpp | 2 +- game/script/Script_Program.h | 18 +- game/script/Script_Thread.cpp | 80 + game/script/Script_Thread.h | 11 + 209 files changed, 11628 insertions(+), 147117 deletions(-) delete mode 100644 d3xp/AF.cpp delete mode 100644 d3xp/AF.h delete mode 100644 d3xp/AFEntity.cpp delete mode 100644 d3xp/AFEntity.h delete mode 100644 d3xp/Actor.cpp delete mode 100644 d3xp/Actor.h delete mode 100644 d3xp/BrittleFracture.cpp delete mode 100644 d3xp/BrittleFracture.h delete mode 100644 d3xp/Camera.cpp delete mode 100644 d3xp/Camera.h delete mode 100644 d3xp/EndLevel.cpp delete mode 100644 d3xp/EndLevel.h delete mode 100644 d3xp/Entity.cpp delete mode 100644 d3xp/Entity.h delete mode 100644 d3xp/Fx.cpp delete mode 100644 d3xp/Fx.h delete mode 100644 d3xp/GameBase.h delete mode 100644 d3xp/GameEdit.cpp delete mode 100644 d3xp/GameEdit.h delete mode 100644 d3xp/Game_local.cpp delete mode 100644 d3xp/Game_local.h delete mode 100644 d3xp/Game_network.cpp delete mode 100644 d3xp/IK.cpp delete mode 100644 d3xp/IK.h delete mode 100644 d3xp/Item.cpp delete mode 100644 d3xp/Item.h delete mode 100644 d3xp/Light.cpp delete mode 100644 d3xp/Light.h delete mode 100644 d3xp/Misc.cpp delete mode 100644 d3xp/Misc.h delete mode 100644 d3xp/Moveable.cpp delete mode 100644 d3xp/Moveable.h delete mode 100644 d3xp/Mover.cpp delete mode 100644 d3xp/Mover.h delete mode 100644 d3xp/MultiplayerGame.cpp delete mode 100644 d3xp/MultiplayerGame.h delete mode 100644 d3xp/Player.cpp delete mode 100644 d3xp/Player.h delete mode 100644 d3xp/PlayerIcon.cpp delete mode 100644 d3xp/PlayerIcon.h delete mode 100644 d3xp/PlayerView.cpp delete mode 100644 d3xp/PlayerView.h delete mode 100644 d3xp/Projectile.cpp delete mode 100644 d3xp/Projectile.h delete mode 100644 d3xp/Pvs.cpp delete mode 100644 d3xp/Pvs.h delete mode 100644 d3xp/SecurityCamera.cpp delete mode 100644 d3xp/SecurityCamera.h delete mode 100644 d3xp/SmokeParticles.cpp delete mode 100644 d3xp/SmokeParticles.h delete mode 100644 d3xp/Sound.cpp delete mode 100644 d3xp/Sound.h delete mode 100644 d3xp/Target.cpp delete mode 100644 d3xp/Target.h delete mode 100644 d3xp/Trigger.cpp delete mode 100644 d3xp/Trigger.h delete mode 100644 d3xp/Weapon.cpp delete mode 100644 d3xp/Weapon.h delete mode 100644 d3xp/WorldSpawn.cpp delete mode 100644 d3xp/WorldSpawn.h delete mode 100644 d3xp/ai/AAS.cpp delete mode 100644 d3xp/ai/AAS.h delete mode 100644 d3xp/ai/AAS_debug.cpp delete mode 100644 d3xp/ai/AAS_local.h delete mode 100644 d3xp/ai/AAS_pathing.cpp delete mode 100644 d3xp/ai/AAS_routing.cpp delete mode 100644 d3xp/ai/AI.cpp delete mode 100644 d3xp/ai/AI.h delete mode 100644 d3xp/ai/AI_Vagary.cpp delete mode 100644 d3xp/ai/AI_events.cpp delete mode 100644 d3xp/ai/AI_pathing.cpp delete mode 100644 d3xp/anim/Anim.cpp delete mode 100644 d3xp/anim/Anim.h delete mode 100644 d3xp/anim/Anim_Blend.cpp delete mode 100644 d3xp/anim/Anim_Import.cpp delete mode 100644 d3xp/anim/Anim_Testmodel.cpp delete mode 100644 d3xp/anim/Anim_Testmodel.h delete mode 100644 d3xp/gamesys/Callbacks.cpp delete mode 100644 d3xp/gamesys/Class.cpp delete mode 100644 d3xp/gamesys/Class.h delete mode 100644 d3xp/gamesys/DebugGraph.cpp delete mode 100644 d3xp/gamesys/DebugGraph.h delete mode 100644 d3xp/gamesys/Event.cpp delete mode 100644 d3xp/gamesys/Event.h delete mode 100644 d3xp/gamesys/NoGameTypeInfo.h delete mode 100644 d3xp/gamesys/SaveGame.cpp delete mode 100644 d3xp/gamesys/SaveGame.h delete mode 100644 d3xp/gamesys/SysCmds.cpp delete mode 100644 d3xp/gamesys/SysCmds.h delete mode 100644 d3xp/gamesys/SysCvar.cpp delete mode 100644 d3xp/gamesys/SysCvar.h delete mode 100644 d3xp/gamesys/TypeInfo.cpp delete mode 100644 d3xp/gamesys/TypeInfo.h delete mode 100644 d3xp/physics/Clip.cpp delete mode 100644 d3xp/physics/Clip.h delete mode 100644 d3xp/physics/Force.cpp delete mode 100644 d3xp/physics/Force.h delete mode 100644 d3xp/physics/Force_Constant.cpp delete mode 100644 d3xp/physics/Force_Constant.h delete mode 100644 d3xp/physics/Force_Drag.cpp delete mode 100644 d3xp/physics/Force_Drag.h delete mode 100644 d3xp/physics/Force_Field.cpp delete mode 100644 d3xp/physics/Force_Field.h delete mode 100644 d3xp/physics/Force_Spring.cpp delete mode 100644 d3xp/physics/Force_Spring.h delete mode 100644 d3xp/physics/Physics.cpp delete mode 100644 d3xp/physics/Physics.h delete mode 100644 d3xp/physics/Physics_AF.cpp delete mode 100644 d3xp/physics/Physics_AF.h delete mode 100644 d3xp/physics/Physics_Actor.cpp delete mode 100644 d3xp/physics/Physics_Actor.h delete mode 100644 d3xp/physics/Physics_Base.cpp delete mode 100644 d3xp/physics/Physics_Base.h delete mode 100644 d3xp/physics/Physics_Monster.cpp delete mode 100644 d3xp/physics/Physics_Monster.h delete mode 100644 d3xp/physics/Physics_Parametric.cpp delete mode 100644 d3xp/physics/Physics_Parametric.h delete mode 100644 d3xp/physics/Physics_Player.cpp delete mode 100644 d3xp/physics/Physics_Player.h delete mode 100644 d3xp/physics/Physics_RigidBody.cpp delete mode 100644 d3xp/physics/Physics_RigidBody.h delete mode 100644 d3xp/physics/Physics_Static.cpp delete mode 100644 d3xp/physics/Physics_Static.h delete mode 100644 d3xp/physics/Physics_StaticMulti.cpp delete mode 100644 d3xp/physics/Physics_StaticMulti.h delete mode 100644 d3xp/physics/Push.cpp delete mode 100644 d3xp/physics/Push.h delete mode 100644 d3xp/script/Script_Compiler.cpp delete mode 100644 d3xp/script/Script_Compiler.h delete mode 100644 d3xp/script/Script_Interpreter.cpp delete mode 100644 d3xp/script/Script_Interpreter.h delete mode 100644 d3xp/script/Script_Program.cpp delete mode 100644 d3xp/script/Script_Program.h delete mode 100644 d3xp/script/Script_Thread.cpp delete mode 100644 d3xp/script/Script_Thread.h rename {d3xp => game}/Grabber.cpp (100%) rename {d3xp => game}/Grabber.h (100%) rename {d3xp => game}/physics/Force_Grab.cpp (100%) rename {d3xp => game}/physics/Force_Grab.h (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index a1079c1a..df74ffd4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -324,22 +324,23 @@ endif() set(src_game + game/Actor.cpp game/AF.cpp game/AFEntity.cpp - game/Actor.cpp + game/BrittleFracture.cpp game/Camera.cpp game/Entity.cpp - game/BrittleFracture.cpp game/Fx.cpp game/GameEdit.cpp game/Game_local.cpp game/Game_network.cpp - game/Item.cpp + game/Grabber.cpp game/IK.cpp + game/Item.cpp game/Light.cpp game/Misc.cpp - game/Mover.cpp game/Moveable.cpp + game/Mover.cpp game/MultiplayerGame.cpp game/Player.cpp game/PlayerIcon.cpp @@ -361,8 +362,8 @@ set(src_game game/ai/AI_events.cpp game/ai/AI_pathing.cpp game/ai/AI_Vagary.cpp - game/gamesys/DebugGraph.cpp game/gamesys/Class.cpp + game/gamesys/DebugGraph.cpp game/gamesys/Event.cpp game/gamesys/SaveGame.cpp game/gamesys/SysCmds.cpp @@ -381,6 +382,7 @@ set(src_game game/physics/Force_Constant.cpp game/physics/Force_Drag.cpp game/physics/Force_Field.cpp + game/physics/Force_Grab.cpp game/physics/Force_Spring.cpp game/physics/Physics.cpp game/physics/Physics_AF.cpp @@ -399,84 +401,6 @@ set(src_game add_globbed_headers(src_game "game") -set(src_d3xp - d3xp/AF.cpp - d3xp/AFEntity.cpp - d3xp/Actor.cpp - d3xp/Camera.cpp - d3xp/Entity.cpp - d3xp/BrittleFracture.cpp - d3xp/Fx.cpp - d3xp/GameEdit.cpp - d3xp/Game_local.cpp - d3xp/Game_network.cpp - d3xp/Item.cpp - d3xp/IK.cpp - d3xp/Light.cpp - d3xp/Misc.cpp - d3xp/Mover.cpp - d3xp/Moveable.cpp - d3xp/MultiplayerGame.cpp - d3xp/Player.cpp - d3xp/PlayerIcon.cpp - d3xp/PlayerView.cpp - d3xp/Projectile.cpp - d3xp/Pvs.cpp - d3xp/SecurityCamera.cpp - d3xp/SmokeParticles.cpp - d3xp/Sound.cpp - d3xp/Target.cpp - d3xp/Trigger.cpp - d3xp/Weapon.cpp - d3xp/WorldSpawn.cpp - d3xp/ai/AAS.cpp - d3xp/ai/AAS_debug.cpp - d3xp/ai/AAS_pathing.cpp - d3xp/ai/AAS_routing.cpp - d3xp/ai/AI.cpp - d3xp/ai/AI_events.cpp - d3xp/ai/AI_pathing.cpp - d3xp/ai/AI_Vagary.cpp - d3xp/gamesys/DebugGraph.cpp - d3xp/gamesys/Class.cpp - d3xp/gamesys/Event.cpp - d3xp/gamesys/SaveGame.cpp - d3xp/gamesys/SysCmds.cpp - d3xp/gamesys/SysCvar.cpp - d3xp/gamesys/TypeInfo.cpp - d3xp/anim/Anim.cpp - d3xp/anim/Anim_Blend.cpp - d3xp/anim/Anim_Import.cpp - d3xp/anim/Anim_Testmodel.cpp - d3xp/script/Script_Compiler.cpp - d3xp/script/Script_Interpreter.cpp - d3xp/script/Script_Program.cpp - d3xp/script/Script_Thread.cpp - d3xp/physics/Clip.cpp - d3xp/physics/Force.cpp - d3xp/physics/Force_Constant.cpp - d3xp/physics/Force_Drag.cpp - d3xp/physics/Force_Field.cpp - d3xp/physics/Force_Spring.cpp - d3xp/physics/Physics.cpp - d3xp/physics/Physics_AF.cpp - d3xp/physics/Physics_Actor.cpp - d3xp/physics/Physics_Base.cpp - d3xp/physics/Physics_Monster.cpp - d3xp/physics/Physics_Parametric.cpp - d3xp/physics/Physics_Player.cpp - d3xp/physics/Physics_RigidBody.cpp - d3xp/physics/Physics_Static.cpp - d3xp/physics/Physics_StaticMulti.cpp - d3xp/physics/Push.cpp - d3xp/Grabber.cpp - d3xp/physics/Force_Grab.cpp - - ${src_d3xp_mod} -) - -add_globbed_headers(src_d3xp "d3xp") - set(src_idlib idlib/bv/Bounds.cpp idlib/bv/Frustum.cpp @@ -593,19 +517,19 @@ endif() if(D3XP) if (AROS) - add_executable(d3xp sys/aros/dll/dllglue.c ${src_d3xp}) + add_executable(d3xp sys/aros/dll/dllglue.c ${src_game}) set_target_properties(d3xp PROPERTIES OUTPUT_NAME "${D3XP_NAME}.aros-${AROS_ARCH}") else() - add_library(d3xp SHARED ${src_d3xp}) + add_library(d3xp SHARED ${src_game}) # so mods can create whatever.dll instead of d3xp.dll from the code in d3xp/ set_target_properties(d3xp PROPERTIES OUTPUT_NAME "${D3XP_NAME}") endif() - source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX neo FILES ${src_d3xp}) + source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX neo FILES ${src_game}) set_target_properties(d3xp PROPERTIES PREFIX "") - set_target_properties(d3xp PROPERTIES COMPILE_DEFINITIONS "${D3XP_DEFS}") - target_include_directories(d3xp PRIVATE "${CMAKE_SOURCE_DIR}/d3xp") + set_target_properties(d3xp PROPERTIES COMPILE_DEFINITIONS "${D3XP_DEFS} _D3XP") + target_include_directories(d3xp PRIVATE "${CMAKE_SOURCE_DIR}/game") set_target_properties(d3xp PROPERTIES LINK_FLAGS "${ldflags}") set_target_properties(d3xp PROPERTIES INSTALL_NAME_DIR "@executable_path") if (AROS) diff --git a/d3xp/AF.cpp b/d3xp/AF.cpp deleted file mode 100644 index e527b14e..00000000 --- a/d3xp/AF.cpp +++ /dev/null @@ -1,1272 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "idlib/geometry/JointTransform.h" - -#include "gamesys/SysCvar.h" - -#include "AF.h" - -/* -=============================================================================== - - Articulated figure controller. - -=============================================================================== -*/ -#define ARTICULATED_FIGURE_ANIM "af_pose" -#define POSE_BOUNDS_EXPANSION 5.0f - -/* -================ -idAF::idAF -================ -*/ -idAF::idAF( void ) { - self = NULL; - animator = NULL; - modifiedAnim = 0; - baseOrigin.Zero(); - baseAxis.Identity(); - poseTime = -1; - restStartTime = -1; - isLoaded = false; - isActive = false; - hasBindConstraints = false; -} - -/* -================ -idAF::~idAF -================ -*/ -idAF::~idAF( void ) { -} - -/* -================ -idAF::Save -================ -*/ -void idAF::Save( idSaveGame *savefile ) const { - savefile->WriteObject( self ); - savefile->WriteString( GetName() ); - savefile->WriteBool( hasBindConstraints ); - savefile->WriteVec3( baseOrigin ); - savefile->WriteMat3( baseAxis ); - savefile->WriteInt( poseTime ); - savefile->WriteInt( restStartTime ); - savefile->WriteBool( isLoaded ); - savefile->WriteBool( isActive ); - savefile->WriteStaticObject( physicsObj ); -} - -/* -================ -idAF::Restore -================ -*/ -void idAF::Restore( idRestoreGame *savefile ) { - savefile->ReadObject( reinterpret_cast( self ) ); - savefile->ReadString( name ); - savefile->ReadBool( hasBindConstraints ); - savefile->ReadVec3( baseOrigin ); - savefile->ReadMat3( baseAxis ); - savefile->ReadInt( poseTime ); - savefile->ReadInt( restStartTime ); - savefile->ReadBool( isLoaded ); - savefile->ReadBool( isActive ); - - animator = NULL; - modifiedAnim = 0; - - if ( self ) { - SetAnimator( self->GetAnimator() ); - Load( self, name ); - if ( hasBindConstraints ) { - AddBindConstraints(); - } - } - - savefile->ReadStaticObject( physicsObj ); - - if ( self ) { - if ( isActive ) { - // clear all animations - animator->ClearAllAnims( gameLocal.time, 0 ); - animator->ClearAllJoints(); - - // switch to articulated figure physics - self->RestorePhysics( &physicsObj ); - physicsObj.EnableClip(); - } - UpdateAnimation(); - } -} - -/* -================ -idAF::UpdateAnimation -================ -*/ -bool idAF::UpdateAnimation( void ) { - int i; - idVec3 origin, renderOrigin, bodyOrigin; - idMat3 axis, renderAxis, bodyAxis; - renderEntity_t *renderEntity; - - if ( !IsLoaded() ) { - return false; - } - - if ( !IsActive() ) { - return false; - } - - renderEntity = self->GetRenderEntity(); - if ( !renderEntity ) { - return false; - } - - if ( physicsObj.IsAtRest() ) { - if ( restStartTime == physicsObj.GetRestStartTime() ) { - return false; - } - restStartTime = physicsObj.GetRestStartTime(); - } - - // get the render position - origin = physicsObj.GetOrigin( 0 ); - axis = physicsObj.GetAxis( 0 ); - renderAxis = baseAxis.Transpose() * axis; - renderOrigin = origin - baseOrigin * renderAxis; - - // create an animation frame which reflects the current pose of the articulated figure - animator->InitAFPose(); - for ( i = 0; i < jointMods.Num(); i++ ) { - // check for the origin joint - if ( jointMods[i].jointHandle == 0 ) { - continue; - } - bodyOrigin = physicsObj.GetOrigin( jointMods[i].bodyId ); - bodyAxis = physicsObj.GetAxis( jointMods[i].bodyId ); - axis = jointMods[i].jointBodyAxis.Transpose() * ( bodyAxis * renderAxis.Transpose() ); - origin = ( bodyOrigin - jointMods[i].jointBodyOrigin * axis - renderOrigin ) * renderAxis.Transpose(); - animator->SetAFPoseJointMod( jointMods[i].jointHandle, jointMods[i].jointMod, axis, origin ); - } - animator->FinishAFPose( modifiedAnim, GetBounds().Expand( POSE_BOUNDS_EXPANSION ), gameLocal.time ); - animator->SetAFPoseBlendWeight( 1.0f ); - - return true; -} - -/* -================ -idAF::GetBounds - - returns bounds for the current pose -================ -*/ -idBounds idAF::GetBounds( void ) const { - int i; - idAFBody *body; - idVec3 origin, entityOrigin; - idMat3 axis, entityAxis; - idBounds bounds, b; - - bounds.Clear(); - - // get model base transform - origin = physicsObj.GetOrigin( 0 ); - axis = physicsObj.GetAxis( 0 ); - - entityAxis = baseAxis.Transpose() * axis; - entityOrigin = origin - baseOrigin * entityAxis; - - // get bounds relative to base - for ( i = 0; i < jointMods.Num(); i++ ) { - body = physicsObj.GetBody( jointMods[i].bodyId ); - origin = ( body->GetWorldOrigin() - entityOrigin ) * entityAxis.Transpose(); - axis = body->GetWorldAxis() * entityAxis.Transpose(); - b.FromTransformedBounds( body->GetClipModel()->GetBounds(), origin, axis ); - - bounds += b; - } - - return bounds; -} - -/* -================ -idAF::SetupPose - - Transforms the articulated figure to match the current animation pose of the given entity. -================ -*/ -void idAF::SetupPose( idEntity *ent, int time ) { - int i; - idAFBody *body; - idVec3 origin; - idMat3 axis; - idAnimator *animatorPtr; - renderEntity_t *renderEntity; - - if ( !IsLoaded() || !ent ) { - return; - } - - animatorPtr = ent->GetAnimator(); - if ( !animatorPtr ) { - return; - } - - renderEntity = ent->GetRenderEntity(); - if ( !renderEntity ) { - return; - } - - // if the animation is driven by the physics - if ( self->GetPhysics() == &physicsObj ) { - return; - } - - // if the pose was already updated this frame - if ( poseTime == time ) { - return; - } - poseTime = time; - - for ( i = 0; i < jointMods.Num(); i++ ) { - body = physicsObj.GetBody( jointMods[i].bodyId ); - animatorPtr->GetJointTransform( jointMods[i].jointHandle, time, origin, axis ); - body->SetWorldOrigin( renderEntity->origin + ( origin + jointMods[i].jointBodyOrigin * axis ) * renderEntity->axis ); - body->SetWorldAxis( jointMods[i].jointBodyAxis * axis * renderEntity->axis ); - } - - if ( isActive ) { - physicsObj.UpdateClipModels(); - } -} - -/* -================ -idAF::ChangePose - - Change the articulated figure to match the current animation pose of the given entity - and set the velocity relative to the previous pose. -================ -*/ -void idAF::ChangePose( idEntity *ent, int time ) { - int i; - float invDelta; - idAFBody *body; - idVec3 origin, lastOrigin; - idMat3 axis; - idAnimator *animatorPtr; - renderEntity_t *renderEntity; - - if ( !IsLoaded() || !ent ) { - return; - } - - animatorPtr = ent->GetAnimator(); - if ( !animatorPtr ) { - return; - } - - renderEntity = ent->GetRenderEntity(); - if ( !renderEntity ) { - return; - } - - // if the animation is driven by the physics - if ( self->GetPhysics() == &physicsObj ) { - return; - } - - // if the pose was already updated this frame - if ( poseTime == time ) { - return; - } - invDelta = 1.0f / MS2SEC( time - poseTime ); - poseTime = time; - - for ( i = 0; i < jointMods.Num(); i++ ) { - body = physicsObj.GetBody( jointMods[i].bodyId ); - animatorPtr->GetJointTransform( jointMods[i].jointHandle, time, origin, axis ); - lastOrigin = body->GetWorldOrigin(); - body->SetWorldOrigin( renderEntity->origin + ( origin + jointMods[i].jointBodyOrigin * axis ) * renderEntity->axis ); - body->SetWorldAxis( jointMods[i].jointBodyAxis * axis * renderEntity->axis ); - body->SetLinearVelocity( ( body->GetWorldOrigin() - lastOrigin ) * invDelta ); - } - - physicsObj.UpdateClipModels(); -} - -/* -================ -idAF::EntitiesTouchingAF -================ -*/ -int idAF::EntitiesTouchingAF( afTouch_t touchList[ MAX_GENTITIES ] ) const { - int i, j, numClipModels; - idAFBody *body; - idClipModel *cm; - idClipModel *clipModels[ MAX_GENTITIES ]; - int numTouching; - - if ( !IsLoaded() ) { - return 0; - } - - numTouching = 0; - numClipModels = gameLocal.clip.ClipModelsTouchingBounds( physicsObj.GetAbsBounds(), -1, clipModels, MAX_GENTITIES ); - - for ( i = 0; i < jointMods.Num(); i++ ) { - body = physicsObj.GetBody( jointMods[i].bodyId ); - - for ( j = 0; j < numClipModels; j++ ) { - cm = clipModels[j]; - - if ( !cm || cm->GetEntity() == self ) { - continue; - } - - if ( !cm->IsTraceModel() ) { - continue; - } - - if ( !body->GetClipModel()->GetAbsBounds().IntersectsBounds( cm->GetAbsBounds() ) ) { - continue; - } - - if ( gameLocal.clip.ContentsModel( body->GetWorldOrigin(), body->GetClipModel(), body->GetWorldAxis(), -1, cm->Handle(), cm->GetOrigin(), cm->GetAxis() ) ) { - touchList[ numTouching ].touchedByBody = body; - touchList[ numTouching ].touchedClipModel = cm; - touchList[ numTouching ].touchedEnt = cm->GetEntity(); - numTouching++; - clipModels[j] = NULL; - } - } - } - - return numTouching; -} - -/* -================ -idAF::BodyForClipModelId -================ -*/ -int idAF::BodyForClipModelId( int id ) const { - if ( id >= 0 ) { - return id; - } else { - id = CLIPMODEL_ID_TO_JOINT_HANDLE( id ); - if ( id < jointBody.Num() ) { - return jointBody[id]; - } else { - return 0; - } - } -} - -/* -================ -idAF::GetPhysicsToVisualTransform -================ -*/ -void idAF::GetPhysicsToVisualTransform( idVec3 &origin, idMat3 &axis ) const { - origin = - baseOrigin; - axis = baseAxis.Transpose(); -} - -/* -================ -idAF::GetImpactInfo -================ -*/ -void idAF::GetImpactInfo( idEntity *ent, int id, const idVec3 &point, impactInfo_t *info ) { - SetupPose( self, gameLocal.time ); - physicsObj.GetImpactInfo( BodyForClipModelId( id ), point, info ); -} - -/* -================ -idAF::ApplyImpulse -================ -*/ -void idAF::ApplyImpulse( idEntity *ent, int id, const idVec3 &point, const idVec3 &impulse ) { - SetupPose( self, gameLocal.time ); - physicsObj.ApplyImpulse( BodyForClipModelId( id ), point, impulse ); -} - -/* -================ -idAF::AddForce -================ -*/ -void idAF::AddForce( idEntity *ent, int id, const idVec3 &point, const idVec3 &force ) { - SetupPose( self, gameLocal.time ); - physicsObj.AddForce( BodyForClipModelId( id ), point, force ); -} - -/* -================ -idAF::AddBody - - Adds a body. -================ -*/ -void idAF::AddBody( idAFBody *body, const idJointMat *joints, const char *jointName, const AFJointModType_t mod ) { - int index; - jointHandle_t handle; - idVec3 origin; - idMat3 axis; - - handle = animator->GetJointHandle( jointName ); - if ( handle == INVALID_JOINT ) { - gameLocal.Error( "idAF for entity '%s' at (%s) modifies unknown joint '%s'", self->name.c_str(), self->GetPhysics()->GetOrigin().ToString(0), jointName ); - } - - assert( handle < animator->NumJoints() ); - origin = joints[ handle ].ToVec3(); - axis = joints[ handle ].ToMat3(); - - index = jointMods.Num(); - jointMods.SetNum( index + 1, false ); - jointMods[index].bodyId = physicsObj.GetBodyId( body ); - jointMods[index].jointHandle = handle; - jointMods[index].jointMod = mod; - jointMods[index].jointBodyOrigin = ( body->GetWorldOrigin() - origin ) * axis.Transpose(); - jointMods[index].jointBodyAxis = body->GetWorldAxis() * axis.Transpose(); -} - -/* -================ -idAF::SetBase - - Sets the base body. -================ -*/ -void idAF::SetBase( idAFBody *body, const idJointMat *joints ) { - physicsObj.ForceBodyId( body, 0 ); - baseOrigin = body->GetWorldOrigin(); - baseAxis = body->GetWorldAxis(); - AddBody( body, joints, animator->GetJointName( animator->GetFirstChild( "origin" ) ), AF_JOINTMOD_AXIS ); -} - -/* -================ -idAF::LoadBody -================ -*/ -bool idAF::LoadBody( const idDeclAF_Body *fb, const idJointMat *joints ) { - int id, i; - float length, mass; - idTraceModel trm; - idClipModel *clip; - idAFBody *body; - idMat3 axis, inertiaTensor; - idVec3 centerOfMass, origin; - idBounds bounds; - idList jointList; - - origin = fb->origin.ToVec3(); - axis = fb->angles.ToMat3(); - bounds[0] = fb->v1.ToVec3(); - bounds[1] = fb->v2.ToVec3(); - - switch( fb->modelType ) { - case TRM_BOX: { - trm.SetupBox( bounds ); - break; - } - case TRM_OCTAHEDRON: { - trm.SetupOctahedron( bounds ); - break; - } - case TRM_DODECAHEDRON: { - trm.SetupDodecahedron( bounds ); - break; - } - case TRM_CYLINDER: { - trm.SetupCylinder( bounds, fb->numSides ); - break; - } - case TRM_CONE: { - // place the apex at the origin - bounds[0].z -= bounds[1].z; - bounds[1].z = 0.0f; - trm.SetupCone( bounds, fb->numSides ); - break; - } - case TRM_BONE: { - // direction of bone - axis[2] = fb->v2.ToVec3() - fb->v1.ToVec3(); - length = axis[2].Normalize(); - // axis of bone trace model - axis[2].NormalVectors( axis[0], axis[1] ); - axis[1] = -axis[1]; - // create bone trace model - trm.SetupBone( length, fb->width ); - break; - } - default: - assert( 0 ); - break; - } - trm.GetMassProperties( 1.0f, mass, centerOfMass, inertiaTensor ); - trm.Translate( -centerOfMass ); - origin += centerOfMass * axis; - - body = physicsObj.GetBody( fb->name ); - if ( body ) { - clip = body->GetClipModel(); - if ( !clip->IsEqual( trm ) ) { - clip = new idClipModel( trm ); - clip->SetContents( fb->contents ); - clip->Link( gameLocal.clip, self, 0, origin, axis ); - body->SetClipModel( clip ); - } - clip->SetContents( fb->contents ); - body->SetDensity( fb->density, fb->inertiaScale ); - body->SetWorldOrigin( origin ); - body->SetWorldAxis( axis ); - id = physicsObj.GetBodyId( body ); - } - else { - clip = new idClipModel( trm ); - clip->SetContents( fb->contents ); - clip->Link( gameLocal.clip, self, 0, origin, axis ); - body = new idAFBody( fb->name, clip, fb->density ); - if ( fb->inertiaScale != mat3_identity ) { - body->SetDensity( fb->density, fb->inertiaScale ); - } - id = physicsObj.AddBody( body ); - } - if ( fb->linearFriction != -1.0f ) { - body->SetFriction( fb->linearFriction, fb->angularFriction, fb->contactFriction ); - } - body->SetClipMask( fb->clipMask ); - body->SetSelfCollision( fb->selfCollision ); - - if ( fb->jointName == "origin" ) { - SetBase( body, joints ); - } else { - AFJointModType_t mod; - if ( fb->jointMod == DECLAF_JOINTMOD_AXIS ) { - mod = AF_JOINTMOD_AXIS; - } else if ( fb->jointMod == DECLAF_JOINTMOD_ORIGIN ) { - mod = AF_JOINTMOD_ORIGIN; - } else if ( fb->jointMod == DECLAF_JOINTMOD_BOTH ) { - mod = AF_JOINTMOD_BOTH; - } else { - mod = AF_JOINTMOD_AXIS; - } - AddBody( body, joints, fb->jointName, mod ); - } - - if ( fb->frictionDirection.ToVec3() != vec3_origin ) { - body->SetFrictionDirection( fb->frictionDirection.ToVec3() ); - } - if ( fb->contactMotorDirection.ToVec3() != vec3_origin ) { - body->SetContactMotorDirection( fb->contactMotorDirection.ToVec3() ); - } - - // update table to find the nearest articulated figure body for a joint of the skeletal model - animator->GetJointList( fb->containedJoints, jointList ); - for( i = 0; i < jointList.Num(); i++ ) { - if ( jointBody[ jointList[ i ] ] != -1 ) { - gameLocal.Warning( "%s: joint '%s' is already contained by body '%s'", - name.c_str(), animator->GetJointName( (jointHandle_t)jointList[i] ), - physicsObj.GetBody( jointBody[ jointList[ i ] ] )->GetName().c_str() ); - } - jointBody[ jointList[ i ] ] = id; - } - - return true; -} - -/* -================ -idAF::LoadConstraint -================ -*/ -bool idAF::LoadConstraint( const idDeclAF_Constraint *fc ) { - idAFBody *body1, *body2; - idAngles angles; - idMat3 axis; - - body1 = physicsObj.GetBody( fc->body1 ); - body2 = physicsObj.GetBody( fc->body2 ); - - switch( fc->type ) { - case DECLAF_CONSTRAINT_FIXED: { - idAFConstraint_Fixed *c; - c = static_cast(physicsObj.GetConstraint( fc->name )); - if ( c ) { - c->SetBody1( body1 ); - c->SetBody2( body2 ); - } - else { - c = new idAFConstraint_Fixed( fc->name, body1, body2 ); - physicsObj.AddConstraint( c ); - } - break; - } - case DECLAF_CONSTRAINT_BALLANDSOCKETJOINT: { - idAFConstraint_BallAndSocketJoint *c; - c = static_cast(physicsObj.GetConstraint( fc->name )); - if ( c ) { - c->SetBody1( body1 ); - c->SetBody2( body2 ); - } - else { - c = new idAFConstraint_BallAndSocketJoint( fc->name, body1, body2 ); - physicsObj.AddConstraint( c ); - } - c->SetAnchor( fc->anchor.ToVec3() ); - c->SetFriction( fc->friction ); - switch( fc->limit ) { - case idDeclAF_Constraint::LIMIT_CONE: { - c->SetConeLimit( fc->limitAxis.ToVec3(), fc->limitAngles[0], fc->shaft[0].ToVec3() ); - break; - } - case idDeclAF_Constraint::LIMIT_PYRAMID: { - angles = fc->limitAxis.ToVec3().ToAngles(); - angles.roll = fc->limitAngles[2]; - axis = angles.ToMat3(); - c->SetPyramidLimit( axis[0], axis[1], fc->limitAngles[0], fc->limitAngles[1], fc->shaft[0].ToVec3() ); - break; - } - default: { - c->SetNoLimit(); - break; - } - } - break; - } - case DECLAF_CONSTRAINT_UNIVERSALJOINT: { - idAFConstraint_UniversalJoint *c; - c = static_cast(physicsObj.GetConstraint( fc->name )); - if ( c ) { - c->SetBody1( body1 ); - c->SetBody2( body2 ); - } - else { - c = new idAFConstraint_UniversalJoint( fc->name, body1, body2 ); - physicsObj.AddConstraint( c ); - } - c->SetAnchor( fc->anchor.ToVec3() ); - c->SetShafts( fc->shaft[0].ToVec3(), fc->shaft[1].ToVec3() ); - c->SetFriction( fc->friction ); - switch( fc->limit ) { - case idDeclAF_Constraint::LIMIT_CONE: { - c->SetConeLimit( fc->limitAxis.ToVec3(), fc->limitAngles[0] ); - break; - } - case idDeclAF_Constraint::LIMIT_PYRAMID: { - angles = fc->limitAxis.ToVec3().ToAngles(); - angles.roll = fc->limitAngles[2]; - axis = angles.ToMat3(); - c->SetPyramidLimit( axis[0], axis[1], fc->limitAngles[0], fc->limitAngles[1] ); - break; - } - default: { - c->SetNoLimit(); - break; - } - } - break; - } - case DECLAF_CONSTRAINT_HINGE: { - idAFConstraint_Hinge *c; - c = static_cast(physicsObj.GetConstraint( fc->name )); - if ( c ) { - c->SetBody1( body1 ); - c->SetBody2( body2 ); - } - else { - c = new idAFConstraint_Hinge( fc->name, body1, body2 ); - physicsObj.AddConstraint( c ); - } - c->SetAnchor( fc->anchor.ToVec3() ); - c->SetAxis( fc->axis.ToVec3() ); - c->SetFriction( fc->friction ); - switch( fc->limit ) { - case idDeclAF_Constraint::LIMIT_CONE: { - idVec3 left, up, axis, shaft; - fc->axis.ToVec3().OrthogonalBasis( left, up ); - axis = left * idRotation( vec3_origin, fc->axis.ToVec3(), fc->limitAngles[0] ); - shaft = left * idRotation( vec3_origin, fc->axis.ToVec3(), fc->limitAngles[2] ); - c->SetLimit( axis, fc->limitAngles[1], shaft ); - break; - } - default: { - c->SetNoLimit(); - break; - } - } - break; - } - case DECLAF_CONSTRAINT_SLIDER: { - idAFConstraint_Slider *c; - c = static_cast(physicsObj.GetConstraint( fc->name )); - if ( c ) { - c->SetBody1( body1 ); - c->SetBody2( body2 ); - } - else { - c = new idAFConstraint_Slider( fc->name, body1, body2 ); - physicsObj.AddConstraint( c ); - } - c->SetAxis( fc->axis.ToVec3() ); - break; - } - case DECLAF_CONSTRAINT_SPRING: { - idAFConstraint_Spring *c; - c = static_cast(physicsObj.GetConstraint( fc->name )); - if ( c ) { - c->SetBody1( body1 ); - c->SetBody2( body2 ); - } - else { - c = new idAFConstraint_Spring( fc->name, body1, body2 ); - physicsObj.AddConstraint( c ); - } - c->SetAnchor( fc->anchor.ToVec3(), fc->anchor2.ToVec3() ); - c->SetSpring( fc->stretch, fc->compress, fc->damping, fc->restLength ); - c->SetLimit( fc->minLength, fc->maxLength ); - break; - } - } - return true; -} - -/* -================ -GetJointTransform -================ -*/ -static bool GetJointTransform( void *model, const idJointMat *frame, const char *jointName, idVec3 &origin, idMat3 &axis ) { - jointHandle_t joint; - - joint = reinterpret_cast(model)->GetJointHandle( jointName ); - if ( ( joint >= 0 ) && ( joint < reinterpret_cast(model)->NumJoints() ) ) { - origin = frame[ joint ].ToVec3(); - axis = frame[ joint ].ToMat3(); - return true; - } else { - return false; - } -} - -/* -================ -idAF::Load -================ -*/ -bool idAF::Load( idEntity *ent, const char *fileName ) { - int i, j; - const idDeclAF *file; - const idDeclModelDef *modelDef; - idRenderModel *model; - int numJoints; - idJointMat *joints; - - assert( ent ); - - self = ent; - physicsObj.SetSelf( self ); - - if ( animator == NULL ) { - gameLocal.Warning( "Couldn't load af '%s' for entity '%s' at (%s): NULL animator\n", name.c_str(), ent->name.c_str(), ent->GetPhysics()->GetOrigin().ToString(0) ); - return false; - } - - name = fileName; - name.StripFileExtension(); - - file = static_cast( declManager->FindType( DECL_AF, name ) ); - if ( !file ) { - gameLocal.Warning( "Couldn't load af '%s' for entity '%s' at (%s)\n", name.c_str(), ent->name.c_str(), ent->GetPhysics()->GetOrigin().ToString(0) ); - return false; - } - - if ( file->bodies.Num() == 0 || file->bodies[0]->jointName != "origin" ) { - gameLocal.Warning( "idAF::Load: articulated figure '%s' for entity '%s' at (%s) has no body which modifies the origin joint.", - name.c_str(), ent->name.c_str(), ent->GetPhysics()->GetOrigin().ToString(0) ); - return false; - } - - modelDef = animator->ModelDef(); - if ( modelDef == NULL || modelDef->GetState() == DS_DEFAULTED ) { - gameLocal.Warning( "idAF::Load: articulated figure '%s' for entity '%s' at (%s) has no or defaulted modelDef '%s'", - name.c_str(), ent->name.c_str(), ent->GetPhysics()->GetOrigin().ToString(0), modelDef ? modelDef->GetName() : "" ); - return false; - } - - model = animator->ModelHandle(); - if ( model == NULL || model->IsDefaultModel() ) { - gameLocal.Warning( "idAF::Load: articulated figure '%s' for entity '%s' at (%s) has no or defaulted model '%s'", - name.c_str(), ent->name.c_str(), ent->GetPhysics()->GetOrigin().ToString(0), model ? model->Name() : "" ); - return false; - } - - // get the modified animation - modifiedAnim = animator->GetAnim( ARTICULATED_FIGURE_ANIM ); - if ( !modifiedAnim ) { - gameLocal.Warning( "idAF::Load: articulated figure '%s' for entity '%s' at (%s) has no modified animation '%s'", - name.c_str(), ent->name.c_str(), ent->GetPhysics()->GetOrigin().ToString(0), ARTICULATED_FIGURE_ANIM ); - return false; - } - - // create the animation frame used to setup the articulated figure - numJoints = animator->NumJoints(); - joints = ( idJointMat * )_alloca16( numJoints * sizeof( joints[0] ) ); - gameEdit->ANIM_CreateAnimFrame( model, animator->GetAnim( modifiedAnim )->MD5Anim( 0 ), numJoints, joints, 1, animator->ModelDef()->GetVisualOffset(), animator->RemoveOrigin() ); - - // set all vector positions from model joints - file->Finish( GetJointTransform, joints, animator ); - - // initialize articulated figure physics - physicsObj.SetGravity( gameLocal.GetGravity() ); - physicsObj.SetClipMask( file->clipMask ); - physicsObj.SetDefaultFriction( file->defaultLinearFriction, file->defaultAngularFriction, file->defaultContactFriction ); - physicsObj.SetSuspendSpeed( file->suspendVelocity, file->suspendAcceleration ); - physicsObj.SetSuspendTolerance( file->noMoveTime, file->noMoveTranslation, file->noMoveRotation ); - physicsObj.SetSuspendTime( file->minMoveTime, file->maxMoveTime ); - physicsObj.SetSelfCollision( file->selfCollision ); - - // clear the list with transforms from joints to bodies - jointMods.SetNum( 0, false ); - - // clear the joint to body conversion list - jointBody.AssureSize( animator->NumJoints() ); - for ( i = 0; i < jointBody.Num(); i++ ) { - jointBody[i] = -1; - } - - // delete any bodies in the physicsObj that are no longer in the idDeclAF - for ( i = 0; i < physicsObj.GetNumBodies(); i++ ) { - idAFBody *body = physicsObj.GetBody( i ); - for ( j = 0; j < file->bodies.Num(); j++ ) { - if ( file->bodies[j]->name.Icmp( body->GetName() ) == 0 ) { - break; - } - } - if ( j >= file->bodies.Num() ) { - physicsObj.DeleteBody( i ); - i--; - } - } - - // delete any constraints in the physicsObj that are no longer in the idDeclAF - for ( i = 0; i < physicsObj.GetNumConstraints(); i++ ) { - idAFConstraint *constraint = physicsObj.GetConstraint( i ); - for ( j = 0; j < file->constraints.Num(); j++ ) { - if ( file->constraints[j]->name.Icmp( constraint->GetName() ) == 0 && - file->constraints[j]->type == constraint->GetType() ) { - break; - } - } - if ( j >= file->constraints.Num() ) { - physicsObj.DeleteConstraint( i ); - i--; - } - } - - // load bodies from the file - for ( i = 0; i < file->bodies.Num(); i++ ) { - LoadBody( file->bodies[i], joints ); - } - - // load constraints from the file - for ( i = 0; i < file->constraints.Num(); i++ ) { - LoadConstraint( file->constraints[i] ); - } - - physicsObj.UpdateClipModels(); - - // check if each joint is contained by a body - for( i = 0; i < animator->NumJoints(); i++ ) { - if ( jointBody[i] == -1 ) { - gameLocal.Warning( "idAF::Load: articulated figure '%s' for entity '%s' at (%s) joint '%s' is not contained by a body", - name.c_str(), self->name.c_str(), self->GetPhysics()->GetOrigin().ToString(0), animator->GetJointName( (jointHandle_t)i ) ); - } - } - - physicsObj.SetMass( file->totalMass ); - physicsObj.SetChanged(); - - // disable the articulated figure for collision detection until activated - physicsObj.DisableClip(); - - isLoaded = true; - - return true; -} - -/* -================ -idAF::Start -================ -*/ -void idAF::Start( void ) { - if ( !IsLoaded() ) { - return; - } - // clear all animations - animator->ClearAllAnims( gameLocal.time, 0 ); - animator->ClearAllJoints(); - // switch to articulated figure physics - self->SetPhysics( &physicsObj ); - // start the articulated figure physics simulation - physicsObj.EnableClip(); - physicsObj.Activate(); - isActive = true; -} - -/* -================ -idAF::TestSolid -================ -*/ -bool idAF::TestSolid( void ) const { - int i; - idAFBody *body; - trace_t trace; - idStr str; - bool solid; - - if ( !IsLoaded() ) { - return false; - } - - if ( !af_testSolid.GetBool() ) { - return false; - } - - solid = false; - - for ( i = 0; i < physicsObj.GetNumBodies(); i++ ) { - body = physicsObj.GetBody( i ); - if ( gameLocal.clip.Translation( trace, body->GetWorldOrigin(), body->GetWorldOrigin(), body->GetClipModel(), body->GetWorldAxis(), body->GetClipMask(), self ) ) { - float depth = idMath::Fabs( trace.c.point * trace.c.normal - trace.c.dist ); - - body->SetWorldOrigin( body->GetWorldOrigin() + trace.c.normal * ( depth + 8.0f ) ); - - gameLocal.DWarning( "%s: body '%s' stuck in %d (normal = %.2f %.2f %.2f, depth = %.2f)", self->name.c_str(), - body->GetName().c_str(), trace.c.contents, trace.c.normal.x, trace.c.normal.y, trace.c.normal.z, depth ); - solid = true; - - } - } - return solid; -} - -/* -================ -idAF::StartFromCurrentPose -================ -*/ -void idAF::StartFromCurrentPose( int inheritVelocityTime ) { - - if ( !IsLoaded() ) { - return; - } - - // if the ragdoll should inherit velocity from the animation - if ( inheritVelocityTime > 0 ) { - - // make sure the ragdoll is at rest - physicsObj.PutToRest(); - - // set the pose for some time back - SetupPose( self, gameLocal.time - inheritVelocityTime ); - - // change the pose for the current time and set velocities - ChangePose( self, gameLocal.time ); - } - else { - // transform the articulated figure to reflect the current animation pose - SetupPose( self, gameLocal.time ); - } - - physicsObj.UpdateClipModels(); - - TestSolid(); - - Start(); - - UpdateAnimation(); - - // update the render entity origin and axis - self->UpdateModel(); - - // make sure the renderer gets the updated origin and axis - self->Present(); -} - -/* -================ -idAF::Stop -================ -*/ -void idAF::Stop( void ) { - // disable the articulated figure for collision detection - physicsObj.UnlinkClip(); - isActive = false; -} - -/* -================ -idAF::Rest -================ -*/ -void idAF::Rest( void ) { - physicsObj.PutToRest(); -} - -/* -================ -idAF::SetConstraintPosition - - Only moves constraints that bind the entity to another entity. -================ -*/ -void idAF::SetConstraintPosition( const char *name, const idVec3 &pos ) { - idAFConstraint *constraint; - - constraint = GetPhysics()->GetConstraint( name ); - - if ( !constraint ) { - gameLocal.Warning( "can't find a constraint with the name '%s'", name ); - return; - } - - if ( constraint->GetBody2() != NULL ) { - gameLocal.Warning( "constraint '%s' does not bind to another entity", name ); - return; - } - - switch( constraint->GetType() ) { - case CONSTRAINT_BALLANDSOCKETJOINT: { - idAFConstraint_BallAndSocketJoint *bs = static_cast(constraint); - bs->Translate( pos - bs->GetAnchor() ); - break; - } - case CONSTRAINT_UNIVERSALJOINT: { - idAFConstraint_UniversalJoint *uj = static_cast(constraint); - uj->Translate( pos - uj->GetAnchor() ); - break; - } - case CONSTRAINT_HINGE: { - idAFConstraint_Hinge *hinge = static_cast(constraint); - hinge->Translate( pos - hinge->GetAnchor() ); - break; - } - default: { - gameLocal.Warning( "cannot set the constraint position for '%s'", name ); - break; - } - } -} - -/* -================ -idAF::SaveState -================ -*/ -void idAF::SaveState( idDict &args ) const { - int i; - idAFBody *body; - idStr key, value; - - for ( i = 0; i < jointMods.Num(); i++ ) { - body = physicsObj.GetBody( jointMods[i].bodyId ); - - key = "body " + body->GetName(); - value = body->GetWorldOrigin().ToString( 8 ); - value += " "; - value += body->GetWorldAxis().ToAngles().ToString( 8 ); - args.Set( key, value ); - } -} - -/* -================ -idAF::LoadState -================ -*/ -void idAF::LoadState( const idDict &args ) { - const idKeyValue *kv; - idStr name; - idAFBody *body; - idVec3 origin; - idAngles angles; - - kv = args.MatchPrefix( "body ", NULL ); - while ( kv ) { - - name = kv->GetKey(); - name.Strip( "body " ); - body = physicsObj.GetBody( name ); - if ( body ) { - sscanf( kv->GetValue(), "%f %f %f %f %f %f", &origin.x, &origin.y, &origin.z, &angles.pitch, &angles.yaw, &angles.roll ); - body->SetWorldOrigin( origin ); - body->SetWorldAxis( angles.ToMat3() ); - } else { - gameLocal.Warning("Unknown body part %s in articulated figure %s", name.c_str(), this->name.c_str()); - } - - kv = args.MatchPrefix( "body ", kv ); - } - - physicsObj.UpdateClipModels(); -} - -/* -================ -idAF::AddBindConstraints -================ -*/ -void idAF::AddBindConstraints( void ) { - const idKeyValue *kv; - idStr name; - idAFBody *body; - idLexer lexer; - idToken type, bodyName, jointName; - idVec3 origin, renderOrigin; - idMat3 axis, renderAxis; - - if ( !IsLoaded() ) { - return; - } - - const idDict &args = self->spawnArgs; - - // get the render position - origin = physicsObj.GetOrigin( 0 ); - axis = physicsObj.GetAxis( 0 ); - renderAxis = baseAxis.Transpose() * axis; - renderOrigin = origin - baseOrigin * renderAxis; - - // parse all the bind constraints - for ( kv = args.MatchPrefix( "bindConstraint ", NULL ); kv; kv = args.MatchPrefix( "bindConstraint ", kv ) ) { - name = kv->GetKey(); - name.Strip( "bindConstraint " ); - - lexer.LoadMemory( kv->GetValue(), kv->GetValue().Length(), kv->GetKey() ); - lexer.ReadToken( &type ); - - lexer.ReadToken( &bodyName ); - body = physicsObj.GetBody( bodyName ); - if ( !body ) { - gameLocal.Warning( "idAF::AddBindConstraints: body '%s' not found on entity '%s'", bodyName.c_str(), self->name.c_str() ); - lexer.FreeSource(); - continue; - } - - if ( type.Icmp( "fixed" ) == 0 ) { - idAFConstraint_Fixed *c; - - c = new idAFConstraint_Fixed( name, body, NULL ); - physicsObj.AddConstraint( c ); - } - else if ( type.Icmp( "ballAndSocket" ) == 0 ) { - idAFConstraint_BallAndSocketJoint *c; - - c = new idAFConstraint_BallAndSocketJoint( name, body, NULL ); - physicsObj.AddConstraint( c ); - lexer.ReadToken( &jointName ); - - jointHandle_t joint = animator->GetJointHandle( jointName ); - if ( joint == INVALID_JOINT ) { - gameLocal.Warning( "idAF::AddBindConstraints: joint '%s' not found", jointName.c_str() ); - } - - animator->GetJointTransform( joint, gameLocal.time, origin, axis ); - c->SetAnchor( renderOrigin + origin * renderAxis ); - } - else if ( type.Icmp( "universal" ) == 0 ) { - idAFConstraint_UniversalJoint *c; - - c = new idAFConstraint_UniversalJoint( name, body, NULL ); - physicsObj.AddConstraint( c ); - lexer.ReadToken( &jointName ); - - jointHandle_t joint = animator->GetJointHandle( jointName ); - if ( joint == INVALID_JOINT ) { - gameLocal.Warning( "idAF::AddBindConstraints: joint '%s' not found", jointName.c_str() ); - } - animator->GetJointTransform( joint, gameLocal.time, origin, axis ); - c->SetAnchor( renderOrigin + origin * renderAxis ); - c->SetShafts( idVec3( 0, 0, 1 ), idVec3( 0, 0, -1 ) ); - } - else { - gameLocal.Warning( "idAF::AddBindConstraints: unknown constraint type '%s' on entity '%s'", type.c_str(), self->name.c_str() ); - } - - lexer.FreeSource(); - } - - hasBindConstraints = true; -} - -/* -================ -idAF::RemoveBindConstraints -================ -*/ -void idAF::RemoveBindConstraints( void ) { - const idKeyValue *kv; - - if ( !IsLoaded() ) { - return; - } - - const idDict &args = self->spawnArgs; - idStr name; - - kv = args.MatchPrefix( "bindConstraint ", NULL ); - while ( kv ) { - name = kv->GetKey(); - name.Strip( "bindConstraint " ); - - if ( physicsObj.GetConstraint( name ) ) { - physicsObj.DeleteConstraint( name ); - } - - kv = args.MatchPrefix( "bindConstraint ", kv ); - } - - hasBindConstraints = false; -} diff --git a/d3xp/AF.h b/d3xp/AF.h deleted file mode 100644 index 79e3751b..00000000 --- a/d3xp/AF.h +++ /dev/null @@ -1,127 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __GAME_AF_H__ -#define __GAME_AF_H__ - -#include "idlib/Parser.h" -#include "framework/DeclAF.h" -#include "renderer/Model.h" - -#include "physics/Physics_AF.h" -#include "Entity.h" -#include "anim/Anim.h" - -/* -=============================================================================== - - Articulated figure controller. - -=============================================================================== -*/ - -typedef struct jointConversion_s { - int bodyId; // id of the body - jointHandle_t jointHandle; // handle of joint this body modifies - AFJointModType_t jointMod; // modify joint axis, origin or both - idVec3 jointBodyOrigin; // origin of body relative to joint - idMat3 jointBodyAxis; // axis of body relative to joint -} jointConversion_t; - -typedef struct afTouch_s { - idEntity * touchedEnt; - idClipModel * touchedClipModel; - idAFBody * touchedByBody; -} afTouch_t; - -class idAF { -public: - idAF( void ); - ~idAF( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void SetAnimator( idAnimator *a ) { animator = a; } - bool Load( idEntity *ent, const char *fileName ); - bool IsLoaded( void ) const { return isLoaded && self != NULL; } - const char * GetName( void ) const { return name.c_str(); } - void SetupPose( idEntity *ent, int time ); - void ChangePose( idEntity *ent, int time ); - int EntitiesTouchingAF( afTouch_t touchList[ MAX_GENTITIES ] ) const; - void Start( void ); - void StartFromCurrentPose( int inheritVelocityTime ); - void Stop( void ); - void Rest( void ); - bool IsActive( void ) const { return isActive; } - void SetConstraintPosition( const char *name, const idVec3 &pos ); - - idPhysics_AF * GetPhysics( void ) { return &physicsObj; } - const idPhysics_AF * GetPhysics( void ) const { return &physicsObj; } - idBounds GetBounds( void ) const; - bool UpdateAnimation( void ); - - void GetPhysicsToVisualTransform( idVec3 &origin, idMat3 &axis ) const; - void GetImpactInfo( idEntity *ent, int id, const idVec3 &point, impactInfo_t *info ); - void ApplyImpulse( idEntity *ent, int id, const idVec3 &point, const idVec3 &impulse ); - void AddForce( idEntity *ent, int id, const idVec3 &point, const idVec3 &force ); - int BodyForClipModelId( int id ) const; - - void SaveState( idDict &args ) const; - void LoadState( const idDict &args ); - - void AddBindConstraints( void ); - void RemoveBindConstraints( void ); - -protected: - idStr name; // name of the loaded .af file - idPhysics_AF physicsObj; // articulated figure physics - idEntity * self; // entity using the animated model - idAnimator * animator; // animator on entity - int modifiedAnim; // anim to modify - idVec3 baseOrigin; // offset of base body relative to skeletal model origin - idMat3 baseAxis; // axis of base body relative to skeletal model origin - idListjointMods; // list with transforms from skeletal model joints to articulated figure bodies - idList jointBody; // table to find the nearest articulated figure body for a joint of the skeletal model - int poseTime; // last time the articulated figure was transformed to reflect the current animation pose - int restStartTime; // time the articulated figure came to rest - bool isLoaded; // true when the articulated figure is properly loaded - bool isActive; // true if the articulated figure physics is active - bool hasBindConstraints; // true if the bind constraints have been added - -protected: - void SetBase( idAFBody *body, const idJointMat *joints ); - void AddBody( idAFBody *body, const idJointMat *joints, const char *jointName, const AFJointModType_t mod ); - - bool LoadBody( const idDeclAF_Body *fb, const idJointMat *joints ); - bool LoadConstraint( const idDeclAF_Constraint *fc ); - - bool TestSolid( void ) const; -}; - -#endif /* !__GAME_AF_H__ */ diff --git a/d3xp/AFEntity.cpp b/d3xp/AFEntity.cpp deleted file mode 100644 index 2ebb5132..00000000 --- a/d3xp/AFEntity.cpp +++ /dev/null @@ -1,3695 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "idlib/geometry/JointTransform.h" -#include "renderer/ModelManager.h" - -#include "gamesys/SysCvar.h" -#include "Item.h" -#include "Player.h" -#include "Fx.h" -#include "SmokeParticles.h" - -#include "AFEntity.h" - -/* -=============================================================================== - - idMultiModelAF - -=============================================================================== -*/ - -CLASS_DECLARATION( idEntity, idMultiModelAF ) -END_CLASS - -/* -================ -idMultiModelAF::Spawn -================ -*/ -void idMultiModelAF::Spawn( void ) { - physicsObj.SetSelf( this ); -} - -/* -================ -idMultiModelAF::~idMultiModelAF -================ -*/ -idMultiModelAF::~idMultiModelAF( void ) { - int i; - - for ( i = 0; i < modelDefHandles.Num(); i++ ) { - if ( modelDefHandles[i] != -1 ) { - gameRenderWorld->FreeEntityDef( modelDefHandles[i] ); - modelDefHandles[i] = -1; - } - } -} - -/* -================ -idMultiModelAF::SetModelForId -================ -*/ -void idMultiModelAF::SetModelForId( int id, const idStr &modelName ) { - modelHandles.AssureSize( id+1, NULL ); - modelDefHandles.AssureSize( id+1, -1 ); - modelHandles[id] = renderModelManager->FindModel( modelName ); -} - -/* -================ -idMultiModelAF::Present -================ -*/ -void idMultiModelAF::Present( void ) { - int i; - - // don't present to the renderer if the entity hasn't changed - if ( !( thinkFlags & TH_UPDATEVISUALS ) ) { - return; - } - BecomeInactive( TH_UPDATEVISUALS ); - - for ( i = 0; i < modelHandles.Num(); i++ ) { - - if ( !modelHandles[i] ) { - continue; - } - - renderEntity.origin = physicsObj.GetOrigin( i ); - renderEntity.axis = physicsObj.GetAxis( i ); - renderEntity.hModel = modelHandles[i]; - renderEntity.bodyId = i; - - // add to refresh list - if ( modelDefHandles[i] == -1 ) { - modelDefHandles[i] = gameRenderWorld->AddEntityDef( &renderEntity ); - } else { - gameRenderWorld->UpdateEntityDef( modelDefHandles[i], &renderEntity ); - } - } -} - -/* -================ -idMultiModelAF::Think -================ -*/ -void idMultiModelAF::Think( void ) { - RunPhysics(); - Present(); -} - - -/* -=============================================================================== - - idChain - -=============================================================================== -*/ - -CLASS_DECLARATION( idMultiModelAF, idChain ) -END_CLASS - -/* -================ -idChain::BuildChain - - builds a chain hanging down from the ceiling - the highest link is a child of the link below it etc. - this allows an object to be attached to multiple chains while keeping a single tree structure -================ -*/ -void idChain::BuildChain( const idStr &name, const idVec3 &origin, float linkLength, float linkWidth, float density, int numLinks, bool bindToWorld ) { - int i; - float halfLinkLength = linkLength * 0.5f; - idTraceModel trm; - idClipModel *clip; - idAFBody *body, *lastBody; - idAFConstraint_BallAndSocketJoint *bsj; - idAFConstraint_UniversalJoint *uj; - idVec3 org; - - // create a trace model - trm = idTraceModel( linkLength, linkWidth ); - trm.Translate( -trm.offset ); - - org = origin - idVec3( 0, 0, halfLinkLength ); - - lastBody = NULL; - for ( i = 0; i < numLinks; i++ ) { - - // add body - clip = new idClipModel( trm ); - clip->SetContents( CONTENTS_SOLID ); - clip->Link( gameLocal.clip, this, 0, org, mat3_identity ); - body = new idAFBody( name + idStr(i), clip, density ); - physicsObj.AddBody( body ); - - // visual model for body - SetModelForId( physicsObj.GetBodyId( body ), spawnArgs.GetString( "model" ) ); - - // add constraint - if ( bindToWorld ) { - if ( !lastBody ) { - uj = new idAFConstraint_UniversalJoint( name + idStr(i), body, lastBody ); - uj->SetShafts( idVec3( 0, 0, -1 ), idVec3( 0, 0, 1 ) ); - //uj->SetConeLimit( idVec3( 0, 0, -1 ), 30.0f ); - //uj->SetPyramidLimit( idVec3( 0, 0, -1 ), idVec3( 1, 0, 0 ), 90.0f, 30.0f ); - } - else { - uj = new idAFConstraint_UniversalJoint( name + idStr(i), lastBody, body ); - uj->SetShafts( idVec3( 0, 0, 1 ), idVec3( 0, 0, -1 ) ); - //uj->SetConeLimit( idVec3( 0, 0, 1 ), 30.0f ); - } - uj->SetAnchor( org + idVec3( 0, 0, halfLinkLength ) ); - uj->SetFriction( 0.9f ); - physicsObj.AddConstraint( uj ); - } - else { - if ( lastBody ) { - bsj = new idAFConstraint_BallAndSocketJoint( "joint" + idStr(i), lastBody, body ); - bsj->SetAnchor( org + idVec3( 0, 0, halfLinkLength ) ); - bsj->SetConeLimit( idVec3( 0, 0, 1 ), 60.0f, idVec3( 0, 0, 1 ) ); - physicsObj.AddConstraint( bsj ); - } - } - - org[2] -= linkLength; - - lastBody = body; - } -} - -/* -================ -idChain::Spawn -================ -*/ -void idChain::Spawn( void ) { - int numLinks; - float length, linkLength, linkWidth, density; - bool drop; - idVec3 origin; - - spawnArgs.GetBool( "drop", "0", drop ); - spawnArgs.GetInt( "links", "3", numLinks ); - spawnArgs.GetFloat( "length", idStr( numLinks * 32.0f ), length ); - spawnArgs.GetFloat( "width", "8", linkWidth ); - spawnArgs.GetFloat( "density", "0.2", density ); - linkLength = length / numLinks; - origin = GetPhysics()->GetOrigin(); - - // initialize physics - physicsObj.SetSelf( this ); - physicsObj.SetGravity( gameLocal.GetGravity() ); - physicsObj.SetClipMask( MASK_SOLID | CONTENTS_BODY ); - SetPhysics( &physicsObj ); - - BuildChain( "link", origin, linkLength, linkWidth, density, numLinks, !drop ); -} - -/* -=============================================================================== - - idAFAttachment - -=============================================================================== -*/ - -CLASS_DECLARATION( idAnimatedEntity, idAFAttachment ) -END_CLASS - -/* -===================== -idAFAttachment::idAFAttachment -===================== -*/ -idAFAttachment::idAFAttachment( void ) { - body = NULL; - combatModel = NULL; - idleAnim = 0; - attachJoint = INVALID_JOINT; -} - -/* -===================== -idAFAttachment::~idAFAttachment -===================== -*/ -idAFAttachment::~idAFAttachment( void ) { - - StopSound( SND_CHANNEL_ANY, false ); - - delete combatModel; - combatModel = NULL; -} - -/* -===================== -idAFAttachment::Spawn -===================== -*/ -void idAFAttachment::Spawn( void ) { - idleAnim = animator.GetAnim( "idle" ); -} - -/* -===================== -idAFAttachment::SetBody -===================== -*/ -void idAFAttachment::SetBody( idEntity *bodyEnt, const char *model, jointHandle_t attachJoint ) { - bool bleed; - - body = bodyEnt; - this->attachJoint = attachJoint; - SetModel( model ); - fl.takedamage = true; - - bleed = body->spawnArgs.GetBool( "bleed" ); - spawnArgs.SetBool( "bleed", bleed ); -} - -/* -===================== -idAFAttachment::ClearBody -===================== -*/ -void idAFAttachment::ClearBody( void ) { - body = NULL; - attachJoint = INVALID_JOINT; - Hide(); -} - -/* -===================== -idAFAttachment::GetBody -===================== -*/ -idEntity *idAFAttachment::GetBody( void ) const { - return body; -} - -/* -================ -idAFAttachment::Save - -archive object for savegame file -================ -*/ -void idAFAttachment::Save( idSaveGame *savefile ) const { - savefile->WriteObject( body ); - savefile->WriteInt( idleAnim ); - savefile->WriteJoint( attachJoint ); -} - -/* -================ -idAFAttachment::Restore - -unarchives object from save game file -================ -*/ -void idAFAttachment::Restore( idRestoreGame *savefile ) { - savefile->ReadObject( reinterpret_cast( body ) ); - savefile->ReadInt( idleAnim ); - savefile->ReadJoint( attachJoint ); - - SetCombatModel(); - LinkCombat(); -} - -/* -================ -idAFAttachment::Hide -================ -*/ -void idAFAttachment::Hide( void ) { - idEntity::Hide(); - UnlinkCombat(); -} - -/* -================ -idAFAttachment::Show -================ -*/ -void idAFAttachment::Show( void ) { - idEntity::Show(); - LinkCombat(); -} - -/* -============ -idAFAttachment::Damage - -Pass damage to body at the bindjoint -============ -*/ -void idAFAttachment::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, - const char *damageDefName, const float damageScale, const int location ) { - - if ( body ) { - body->Damage( inflictor, attacker, dir, damageDefName, damageScale, attachJoint ); - } -} - -/* -================ -idAFAttachment::AddDamageEffect -================ -*/ -void idAFAttachment::AddDamageEffect( const trace_t &collision, const idVec3 &velocity, const char *damageDefName ) { - if ( body ) { - trace_t c = collision; - c.c.id = JOINT_HANDLE_TO_CLIPMODEL_ID( attachJoint ); - body->AddDamageEffect( c, velocity, damageDefName ); - } -} - -/* -================ -idAFAttachment::GetImpactInfo -================ -*/ -void idAFAttachment::GetImpactInfo( idEntity *ent, int id, const idVec3 &point, impactInfo_t *info ) { - if ( body ) { - body->GetImpactInfo( ent, JOINT_HANDLE_TO_CLIPMODEL_ID( attachJoint ), point, info ); - } else { - idEntity::GetImpactInfo( ent, id, point, info ); - } -} - -/* -================ -idAFAttachment::ApplyImpulse -================ -*/ -void idAFAttachment::ApplyImpulse( idEntity *ent, int id, const idVec3 &point, const idVec3 &impulse ) { - if ( body ) { - body->ApplyImpulse( ent, JOINT_HANDLE_TO_CLIPMODEL_ID( attachJoint ), point, impulse ); - } else { - idEntity::ApplyImpulse( ent, id, point, impulse ); - } -} - -/* -================ -idAFAttachment::AddForce -================ -*/ -void idAFAttachment::AddForce( idEntity *ent, int id, const idVec3 &point, const idVec3 &force ) { - if ( body ) { - body->AddForce( ent, JOINT_HANDLE_TO_CLIPMODEL_ID( attachJoint ), point, force ); - } else { - idEntity::AddForce( ent, id, point, force ); - } -} - -/* -================ -idAFAttachment::PlayIdleAnim -================ -*/ -void idAFAttachment::PlayIdleAnim( int blendTime ) { - if ( idleAnim && ( idleAnim != animator.CurrentAnim( ANIMCHANNEL_ALL )->AnimNum() ) ) { - animator.CycleAnim( ANIMCHANNEL_ALL, idleAnim, gameLocal.time, blendTime ); - } -} - -/* -================ -idAfAttachment::Think -================ -*/ -void idAFAttachment::Think( void ) { - idAnimatedEntity::Think(); - if ( thinkFlags & TH_UPDATEPARTICLES ) { - UpdateDamageEffects(); - } -} - -/* -================ -idAFAttachment::SetCombatModel -================ -*/ -void idAFAttachment::SetCombatModel( void ) { - if ( combatModel ) { - combatModel->Unlink(); - combatModel->LoadModel( modelDefHandle ); - } else { - combatModel = new idClipModel( modelDefHandle ); - } - combatModel->SetOwner( body ); -} - -/* -================ -idAFAttachment::GetCombatModel -================ -*/ -idClipModel *idAFAttachment::GetCombatModel( void ) const { - return combatModel; -} - -/* -================ -idAFAttachment::LinkCombat -================ -*/ -void idAFAttachment::LinkCombat( void ) { - if ( fl.hidden ) { - return; - } - - if ( combatModel ) { - combatModel->Link( gameLocal.clip, this, 0, renderEntity.origin, renderEntity.axis, modelDefHandle ); - } -} - -/* -================ -idAFAttachment::UnlinkCombat -================ -*/ -void idAFAttachment::UnlinkCombat( void ) { - if ( combatModel ) { - combatModel->Unlink(); - } -} - - -/* -=============================================================================== - - idAFEntity_Base - -=============================================================================== -*/ - -const idEventDef EV_SetConstraintPosition( "SetConstraintPosition", "sv" ); - -CLASS_DECLARATION( idAnimatedEntity, idAFEntity_Base ) - EVENT( EV_SetConstraintPosition, idAFEntity_Base::Event_SetConstraintPosition ) -END_CLASS - -static const float BOUNCE_SOUND_MIN_VELOCITY = 80.0f; -static const float BOUNCE_SOUND_MAX_VELOCITY = 200.0f; - -/* -================ -idAFEntity_Base::idAFEntity_Base -================ -*/ -idAFEntity_Base::idAFEntity_Base( void ) { - combatModel = NULL; - combatModelContents = 0; - nextSoundTime = 0; - spawnOrigin.Zero(); - spawnAxis.Identity(); -} - -/* -================ -idAFEntity_Base::~idAFEntity_Base -================ -*/ -idAFEntity_Base::~idAFEntity_Base( void ) { - delete combatModel; - combatModel = NULL; -} - -/* -================ -idAFEntity_Base::Save -================ -*/ -void idAFEntity_Base::Save( idSaveGame *savefile ) const { - savefile->WriteInt( combatModelContents ); - savefile->WriteClipModel( combatModel ); - savefile->WriteVec3( spawnOrigin ); - savefile->WriteMat3( spawnAxis ); - savefile->WriteInt( nextSoundTime ); - af.Save( savefile ); -} - -/* -================ -idAFEntity_Base::Restore -================ -*/ -void idAFEntity_Base::Restore( idRestoreGame *savefile ) { - savefile->ReadInt( combatModelContents ); - savefile->ReadClipModel( combatModel ); - savefile->ReadVec3( spawnOrigin ); - savefile->ReadMat3( spawnAxis ); - savefile->ReadInt( nextSoundTime ); - LinkCombat(); - - af.Restore( savefile ); -} - -/* -================ -idAFEntity_Base::Spawn -================ -*/ -void idAFEntity_Base::Spawn( void ) { - spawnOrigin = GetPhysics()->GetOrigin(); - spawnAxis = GetPhysics()->GetAxis(); - nextSoundTime = 0; -} - -/* -================ -idAFEntity_Base::LoadAF -================ -*/ -bool idAFEntity_Base::LoadAF( void ) { - idStr fileName; - - if ( !spawnArgs.GetString( "articulatedFigure", "*unknown*", fileName ) ) { - return false; - } - - af.SetAnimator( GetAnimator() ); - if ( !af.Load( this, fileName ) ) { - gameLocal.Error( "idAFEntity_Base::LoadAF: Couldn't load af file '%s' on entity '%s'", fileName.c_str(), name.c_str() ); - } - - af.Start(); - - af.GetPhysics()->Rotate( spawnAxis.ToRotation() ); - af.GetPhysics()->Translate( spawnOrigin ); - - LoadState( spawnArgs ); - - af.UpdateAnimation(); - animator.CreateFrame( gameLocal.time, true ); - UpdateVisuals(); - - return true; -} - -/* -================ -idAFEntity_Base::Think -================ -*/ -void idAFEntity_Base::Think( void ) { - RunPhysics(); - UpdateAnimation(); - if ( thinkFlags & TH_UPDATEVISUALS ) { - Present(); - LinkCombat(); - } -} - -/* -================ -idAFEntity_Base::BodyForClipModelId -================ -*/ -int idAFEntity_Base::BodyForClipModelId( int id ) const { - return af.BodyForClipModelId( id ); -} - -/* -================ -idAFEntity_Base::SaveState -================ -*/ -void idAFEntity_Base::SaveState( idDict &args ) const { - const idKeyValue *kv; - - // save the ragdoll pose - af.SaveState( args ); - - // save all the bind constraints - kv = spawnArgs.MatchPrefix( "bindConstraint ", NULL ); - while ( kv ) { - args.Set( kv->GetKey(), kv->GetValue() ); - kv = spawnArgs.MatchPrefix( "bindConstraint ", kv ); - } - - // save the bind if it exists - kv = spawnArgs.FindKey( "bind" ); - if ( kv ) { - args.Set( kv->GetKey(), kv->GetValue() ); - } - kv = spawnArgs.FindKey( "bindToJoint" ); - if ( kv ) { - args.Set( kv->GetKey(), kv->GetValue() ); - } - kv = spawnArgs.FindKey( "bindToBody" ); - if ( kv ) { - args.Set( kv->GetKey(), kv->GetValue() ); - } -} - -/* -================ -idAFEntity_Base::LoadState -================ -*/ -void idAFEntity_Base::LoadState( const idDict &args ) { - af.LoadState( args ); -} - -/* -================ -idAFEntity_Base::AddBindConstraints -================ -*/ -void idAFEntity_Base::AddBindConstraints( void ) { - af.AddBindConstraints(); -} - -/* -================ -idAFEntity_Base::RemoveBindConstraints -================ -*/ -void idAFEntity_Base::RemoveBindConstraints( void ) { - af.RemoveBindConstraints(); -} - -/* -================ -idAFEntity_Base::GetImpactInfo -================ -*/ -void idAFEntity_Base::GetImpactInfo( idEntity *ent, int id, const idVec3 &point, impactInfo_t *info ) { - if ( af.IsActive() ) { - af.GetImpactInfo( ent, id, point, info ); - } else { - idEntity::GetImpactInfo( ent, id, point, info ); - } -} - -/* -================ -idAFEntity_Base::ApplyImpulse -================ -*/ -void idAFEntity_Base::ApplyImpulse( idEntity *ent, int id, const idVec3 &point, const idVec3 &impulse ) { - if ( af.IsLoaded() ) { - af.ApplyImpulse( ent, id, point, impulse ); - } - if ( !af.IsActive() ) { - idEntity::ApplyImpulse( ent, id, point, impulse ); - } -} - -/* -================ -idAFEntity_Base::AddForce -================ -*/ -void idAFEntity_Base::AddForce( idEntity *ent, int id, const idVec3 &point, const idVec3 &force ) { - if ( af.IsLoaded() ) { - af.AddForce( ent, id, point, force ); - } - if ( !af.IsActive() ) { - idEntity::AddForce( ent, id, point, force ); - } -} - -/* -================ -idAFEntity_Base::Collide -================ -*/ -bool idAFEntity_Base::Collide( const trace_t &collision, const idVec3 &velocity ) { - float v, f; - - if ( af.IsActive() ) { - v = -( velocity * collision.c.normal ); - if ( v > BOUNCE_SOUND_MIN_VELOCITY && gameLocal.time > nextSoundTime ) { - f = v > BOUNCE_SOUND_MAX_VELOCITY ? 1.0f : idMath::Sqrt( v - BOUNCE_SOUND_MIN_VELOCITY ) * ( 1.0f / idMath::Sqrt( BOUNCE_SOUND_MAX_VELOCITY - BOUNCE_SOUND_MIN_VELOCITY ) ); - if ( StartSound( "snd_bounce", SND_CHANNEL_ANY, 0, false, NULL ) ) { - // don't set the volume unless there is a bounce sound as it overrides the entire channel - // which causes footsteps on ai's to not honor their shader parms - SetSoundVolume( f ); - } - nextSoundTime = gameLocal.time + 500; - } - } - - return false; -} - -/* -================ -idAFEntity_Base::GetPhysicsToVisualTransform -================ -*/ -bool idAFEntity_Base::GetPhysicsToVisualTransform( idVec3 &origin, idMat3 &axis ) { - if ( af.IsActive() ) { - af.GetPhysicsToVisualTransform( origin, axis ); - return true; - } - return idEntity::GetPhysicsToVisualTransform( origin, axis ); -} - -/* -================ -idAFEntity_Base::UpdateAnimationControllers -================ -*/ -bool idAFEntity_Base::UpdateAnimationControllers( void ) { - if ( af.IsActive() ) { - if ( af.UpdateAnimation() ) { - return true; - } - } - return false; -} - -/* -================ -idAFEntity_Base::SetCombatModel -================ -*/ -void idAFEntity_Base::SetCombatModel( void ) { - if ( combatModel ) { - combatModel->Unlink(); - combatModel->LoadModel( modelDefHandle ); - } else { - combatModel = new idClipModel( modelDefHandle ); - } -} - -/* -================ -idAFEntity_Base::GetCombatModel -================ -*/ -idClipModel *idAFEntity_Base::GetCombatModel( void ) const { - return combatModel; -} - -/* -================ -idAFEntity_Base::SetCombatContents -================ -*/ -void idAFEntity_Base::SetCombatContents( bool enable ) { - assert( combatModel ); - if ( enable && combatModelContents ) { - assert( !combatModel->GetContents() ); - combatModel->SetContents( combatModelContents ); - combatModelContents = 0; - } else if ( !enable && combatModel->GetContents() ) { - assert( !combatModelContents ); - combatModelContents = combatModel->GetContents(); - combatModel->SetContents( 0 ); - } -} - -/* -================ -idAFEntity_Base::LinkCombat -================ -*/ -void idAFEntity_Base::LinkCombat( void ) { - if ( fl.hidden ) { - return; - } - if ( combatModel ) { - combatModel->Link( gameLocal.clip, this, 0, renderEntity.origin, renderEntity.axis, modelDefHandle ); - } -} - -/* -================ -idAFEntity_Base::UnlinkCombat -================ -*/ -void idAFEntity_Base::UnlinkCombat( void ) { - if ( combatModel ) { - combatModel->Unlink(); - } -} - -/* -================ -idAFEntity_Base::FreeModelDef -================ -*/ -void idAFEntity_Base::FreeModelDef( void ) { - UnlinkCombat(); - idEntity::FreeModelDef(); -} - -/* -=============== -idAFEntity_Base::ShowEditingDialog -=============== -*/ -void idAFEntity_Base::ShowEditingDialog( void ) { - common->InitTool( EDITOR_AF, &spawnArgs ); -} - -/* -================ -idAFEntity_Base::DropAFs - - The entity should have the following key/value pairs set: - "def_dropAF" "af def" - "dropSkin" "skin name" - To drop multiple articulated figures the following key/value pairs can be used: - "def_dropAF*" "af def" - where * is an aribtrary string. -================ -*/ -void idAFEntity_Base::DropAFs( idEntity *ent, const char *type, idList *list ) { - const idKeyValue *kv; - const char *skinName; - idEntity *newEnt; - idAFEntity_Base *af; - idDict args; - const idDeclSkin *skin; - - // drop the articulated figures - kv = ent->spawnArgs.MatchPrefix( va( "def_drop%sAF", type ), NULL ); - while ( kv ) { - - args.Set( "classname", kv->GetValue() ); - gameLocal.SpawnEntityDef( args, &newEnt ); - - if ( newEnt && newEnt->IsType( idAFEntity_Base::Type ) ) { - af = static_cast(newEnt); - af->GetPhysics()->SetOrigin( ent->GetPhysics()->GetOrigin() ); - af->GetPhysics()->SetAxis( ent->GetPhysics()->GetAxis() ); - af->af.SetupPose( ent, gameLocal.time ); - if ( list ) { - list->Append( af ); - } - } - - kv = ent->spawnArgs.MatchPrefix( va( "def_drop%sAF", type ), kv ); - } - - // change the skin to hide all the dropped articulated figures - skinName = ent->spawnArgs.GetString( va( "skin_drop%s", type ) ); - if ( skinName[0] ) { - skin = declManager->FindSkin( skinName ); - ent->SetSkin( skin ); - } -} - -/* -================ -idAFEntity_Base::Event_SetConstraintPosition -================ -*/ -void idAFEntity_Base::Event_SetConstraintPosition( const char *name, const idVec3 &pos ) { - af.SetConstraintPosition( name, pos ); -} - -/* -=============================================================================== - -idAFEntity_Gibbable - -=============================================================================== -*/ - -const idEventDef EV_Gib( "gib", "s" ); -const idEventDef EV_Gibbed( "" ); - -CLASS_DECLARATION( idAFEntity_Base, idAFEntity_Gibbable ) - EVENT( EV_Gib, idAFEntity_Gibbable::Event_Gib ) - EVENT( EV_Gibbed, idAFEntity_Base::Event_Remove ) -END_CLASS - - -/* -================ -idAFEntity_Gibbable::idAFEntity_Gibbable -================ -*/ -idAFEntity_Gibbable::idAFEntity_Gibbable( void ) { - skeletonModel = NULL; - skeletonModelDefHandle = -1; - gibbed = false; -#ifdef _D3XP - wasThrown = false; -#endif -} - -/* -================ -idAFEntity_Gibbable::~idAFEntity_Gibbable -================ -*/ -idAFEntity_Gibbable::~idAFEntity_Gibbable() { - if ( skeletonModelDefHandle != -1 ) { - gameRenderWorld->FreeEntityDef( skeletonModelDefHandle ); - skeletonModelDefHandle = -1; - } -} - -/* -================ -idAFEntity_Gibbable::Save -================ -*/ -void idAFEntity_Gibbable::Save( idSaveGame *savefile ) const { - savefile->WriteBool( gibbed ); - savefile->WriteBool( combatModel != NULL ); -#ifdef _D3XP - savefile->WriteBool( wasThrown ); -#endif -} - -/* -================ -idAFEntity_Gibbable::Restore -================ -*/ -void idAFEntity_Gibbable::Restore( idRestoreGame *savefile ) { - bool hasCombatModel; - - savefile->ReadBool( gibbed ); - savefile->ReadBool( hasCombatModel ); -#ifdef _D3XP - savefile->ReadBool( wasThrown ); -#endif - - InitSkeletonModel(); - - if ( hasCombatModel ) { - SetCombatModel(); - LinkCombat(); - } -} - -/* -================ -idAFEntity_Gibbable::Spawn -================ -*/ -void idAFEntity_Gibbable::Spawn( void ) { - InitSkeletonModel(); - - gibbed = false; -#ifdef _D3XP - wasThrown = false; -#endif -} - -/* -================ -idAFEntity_Gibbable::InitSkeletonModel -================ -*/ -void idAFEntity_Gibbable::InitSkeletonModel( void ) { - const char *modelName; - const idDeclModelDef *modelDef; - - skeletonModel = NULL; - skeletonModelDefHandle = -1; - - modelName = spawnArgs.GetString( "model_gib" ); - - modelDef = NULL; - if ( modelName[0] != '\0' ) { - modelDef = static_cast( declManager->FindType( DECL_MODELDEF, modelName, false ) ); - if ( modelDef ) { - skeletonModel = modelDef->ModelHandle(); - } else { - skeletonModel = renderModelManager->FindModel( modelName ); - } - if ( skeletonModel != NULL && renderEntity.hModel != NULL ) { - if ( skeletonModel->NumJoints() != renderEntity.hModel->NumJoints() ) { - gameLocal.Error( "gib model '%s' has different number of joints than model '%s'", - skeletonModel->Name(), renderEntity.hModel->Name() ); - } - } - } -} - -/* -================ -idAFEntity_Gibbable::Present -================ -*/ -void idAFEntity_Gibbable::Present( void ) { - renderEntity_t skeleton; - - if ( !gameLocal.isNewFrame ) { - return; - } - - // don't present to the renderer if the entity hasn't changed - if ( !( thinkFlags & TH_UPDATEVISUALS ) ) { - return; - } - - // update skeleton model - if ( gibbed && !IsHidden() && skeletonModel != NULL ) { - skeleton = renderEntity; - skeleton.hModel = skeletonModel; - // add to refresh list - if ( skeletonModelDefHandle == -1 ) { - skeletonModelDefHandle = gameRenderWorld->AddEntityDef( &skeleton ); - } else { - gameRenderWorld->UpdateEntityDef( skeletonModelDefHandle, &skeleton ); - } - } - - idEntity::Present(); -} - -/* -================ -idAFEntity_Gibbable::Damage -================ -*/ -void idAFEntity_Gibbable::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location ) { - if ( !fl.takedamage ) { - return; - } - idAFEntity_Base::Damage( inflictor, attacker, dir, damageDefName, damageScale, location ); - if ( health < -20 && spawnArgs.GetBool( "gib" ) ) { - Gib( dir, damageDefName ); - } -} - -#ifdef _D3XP -/* -===================== -idAFEntity_Gibbable::SetThrown -===================== -*/ -void idAFEntity_Gibbable::SetThrown( bool isThrown ) { - - if ( isThrown ) { - int i, num = af.GetPhysics()->GetNumBodies(); - - for ( i=0; iGetBody( i ); - body->SetClipMask( MASK_MONSTERSOLID ); - } - } - - wasThrown = isThrown; -} - -/* -===================== -idAFEntity_Gibbable::Collide -===================== -*/ -bool idAFEntity_Gibbable::Collide( const trace_t &collision, const idVec3 &velocity ) { - - if ( !gibbed && wasThrown ) { - - // Everything gibs (if possible) - if ( spawnArgs.GetBool( "gib" ) ) { - idEntity *ent; - - ent = gameLocal.entities[ collision.c.entityNum ]; - if ( ent->fl.takedamage ) { - ent->Damage( this, gameLocal.GetLocalPlayer(), collision.c.normal, "damage_thrown_ragdoll", 1.f, CLIPMODEL_ID_TO_JOINT_HANDLE( collision.c.id ) ); - } - - idVec3 vel = velocity; - vel.NormalizeFast(); - Gib( vel, "damage_gib" ); - } - } - - return idAFEntity_Base::Collide( collision, velocity ); -} -#endif - -/* -===================== -idAFEntity_Gibbable::SpawnGibs -===================== -*/ -void idAFEntity_Gibbable::SpawnGibs( const idVec3 &dir, const char *damageDefName ) { - int i; - bool gibNonSolid; - idVec3 entityCenter, velocity; - idList list; - - assert( !gameLocal.isClient ); - - const idDict *damageDef = gameLocal.FindEntityDefDict( damageDefName ); - if ( !damageDef ) { - gameLocal.Error( "Unknown damageDef '%s'", damageDefName ); - } - - // spawn gib articulated figures - idAFEntity_Base::DropAFs( this, "gib", &list ); - - // spawn gib items - idMoveableItem::DropItems( this, "gib", &list ); - - // blow out the gibs in the given direction away from the center of the entity - entityCenter = GetPhysics()->GetAbsBounds().GetCenter(); - gibNonSolid = damageDef->GetBool( "gibNonSolid" ); - for ( i = 0; i < list.Num(); i++ ) { - if ( gibNonSolid ) { - list[i]->GetPhysics()->SetContents( 0 ); - list[i]->GetPhysics()->SetClipMask( 0 ); - list[i]->GetPhysics()->UnlinkClip(); - list[i]->GetPhysics()->PutToRest(); - } else { -#ifdef _D3XP - list[i]->GetPhysics()->SetContents( 0 ); -#else - list[i]->GetPhysics()->SetContents( CONTENTS_CORPSE ); -#endif - list[i]->GetPhysics()->SetClipMask( CONTENTS_SOLID ); - velocity = list[i]->GetPhysics()->GetAbsBounds().GetCenter() - entityCenter; - velocity.NormalizeFast(); - velocity += ( i & 1 ) ? dir : -dir; - list[i]->GetPhysics()->SetLinearVelocity( velocity * 75.0f ); - } -#ifdef _D3XP - // Don't allow grabber to pick up temporary gibs - list[i]->noGrab = true; -#endif - list[i]->GetRenderEntity()->noShadow = true; - list[i]->GetRenderEntity()->shaderParms[ SHADERPARM_TIME_OF_DEATH ] = gameLocal.time * 0.001f; - list[i]->PostEventSec( &EV_Remove, 4.0f ); - } -} - -/* -============ -idAFEntity_Gibbable::Gib -============ -*/ -void idAFEntity_Gibbable::Gib( const idVec3 &dir, const char *damageDefName ) { - // only gib once - if ( gibbed ) { - return; - } - -#ifdef _D3XP - // Don't grab this ent after it's been gibbed (and now invisible!) - noGrab = true; -#endif - - const idDict *damageDef = gameLocal.FindEntityDefDict( damageDefName ); - if ( !damageDef ) { - gameLocal.Error( "Unknown damageDef '%s'", damageDefName ); - } - - if ( damageDef->GetBool( "gibNonSolid" ) ) { - GetAFPhysics()->SetContents( 0 ); - GetAFPhysics()->SetClipMask( 0 ); - GetAFPhysics()->UnlinkClip(); - GetAFPhysics()->PutToRest(); - } else { - GetAFPhysics()->SetContents( CONTENTS_CORPSE ); - GetAFPhysics()->SetClipMask( CONTENTS_SOLID ); - } - - UnlinkCombat(); - - if ( g_bloodEffects.GetBool() ) { - if ( gameLocal.time > gameLocal.GetGibTime() ) { - gameLocal.SetGibTime( gameLocal.time + GIB_DELAY ); - SpawnGibs( dir, damageDefName ); - renderEntity.noShadow = true; - renderEntity.shaderParms[ SHADERPARM_TIME_OF_DEATH ] = gameLocal.time * 0.001f; - StartSound( "snd_gibbed", SND_CHANNEL_ANY, 0, false, NULL ); - gibbed = true; - } - } else { - gibbed = true; - } - - - PostEventSec( &EV_Gibbed, 4.0f ); -} - -/* -============ -idAFEntity_Gibbable::Event_Gib -============ -*/ -void idAFEntity_Gibbable::Event_Gib( const char *damageDefName ) { - Gib( idVec3( 0, 0, 1 ), damageDefName ); -} - -/* -=============================================================================== - - idAFEntity_Generic - -=============================================================================== -*/ - -CLASS_DECLARATION( idAFEntity_Gibbable, idAFEntity_Generic ) - EVENT( EV_Activate, idAFEntity_Generic::Event_Activate ) -END_CLASS - -/* -================ -idAFEntity_Generic::idAFEntity_Generic -================ -*/ -idAFEntity_Generic::idAFEntity_Generic( void ) { - keepRunningPhysics = false; -} - -/* -================ -idAFEntity_Generic::~idAFEntity_Generic -================ -*/ -idAFEntity_Generic::~idAFEntity_Generic( void ) { -} - -/* -================ -idAFEntity_Generic::Save -================ -*/ -void idAFEntity_Generic::Save( idSaveGame *savefile ) const { - savefile->WriteBool( keepRunningPhysics ); -} - -/* -================ -idAFEntity_Generic::Restore -================ -*/ -void idAFEntity_Generic::Restore( idRestoreGame *savefile ) { - savefile->ReadBool( keepRunningPhysics ); -} - -/* -================ -idAFEntity_Generic::Think -================ -*/ -void idAFEntity_Generic::Think( void ) { - idAFEntity_Base::Think(); - - if ( keepRunningPhysics ) { - BecomeActive( TH_PHYSICS ); - } -} - -/* -================ -idAFEntity_Generic::Spawn -================ -*/ -void idAFEntity_Generic::Spawn( void ) { - if ( !LoadAF() ) { - gameLocal.Error( "Couldn't load af file on entity '%s'", name.c_str() ); - } - - SetCombatModel(); - - SetPhysics( af.GetPhysics() ); - - af.GetPhysics()->PutToRest(); - if ( !spawnArgs.GetBool( "nodrop", "0" ) ) { - af.GetPhysics()->Activate(); - } - - fl.takedamage = true; -} - -/* -================ -idAFEntity_Generic::Event_Activate -================ -*/ -void idAFEntity_Generic::Event_Activate( idEntity *activator ) { - float delay; - idVec3 init_velocity, init_avelocity; - - Show(); - - af.GetPhysics()->EnableImpact(); - af.GetPhysics()->Activate(); - - spawnArgs.GetVector( "init_velocity", "0 0 0", init_velocity ); - spawnArgs.GetVector( "init_avelocity", "0 0 0", init_avelocity ); - - delay = spawnArgs.GetFloat( "init_velocityDelay", "0" ); - if ( delay == 0.0f ) { - af.GetPhysics()->SetLinearVelocity( init_velocity ); - } else { - PostEventSec( &EV_SetLinearVelocity, delay, init_velocity ); - } - - delay = spawnArgs.GetFloat( "init_avelocityDelay", "0" ); - if ( delay == 0.0f ) { - af.GetPhysics()->SetAngularVelocity( init_avelocity ); - } else { - PostEventSec( &EV_SetAngularVelocity, delay, init_avelocity ); - } -} - - -/* -=============================================================================== - - idAFEntity_WithAttachedHead - -=============================================================================== -*/ - -CLASS_DECLARATION( idAFEntity_Gibbable, idAFEntity_WithAttachedHead ) - EVENT( EV_Gib, idAFEntity_WithAttachedHead::Event_Gib ) - EVENT( EV_Activate, idAFEntity_WithAttachedHead::Event_Activate ) -END_CLASS - -/* -================ -idAFEntity_WithAttachedHead::idAFEntity_WithAttachedHead -================ -*/ -idAFEntity_WithAttachedHead::idAFEntity_WithAttachedHead() { - head = NULL; -} - -/* -================ -idAFEntity_WithAttachedHead::~idAFEntity_WithAttachedHead -================ -*/ -idAFEntity_WithAttachedHead::~idAFEntity_WithAttachedHead() { - if ( head.GetEntity() ) { - head.GetEntity()->ClearBody(); - head.GetEntity()->PostEventMS( &EV_Remove, 0 ); - } -} - -/* -================ -idAFEntity_WithAttachedHead::Spawn -================ -*/ -void idAFEntity_WithAttachedHead::Spawn( void ) { - SetupHead(); - - LoadAF(); - - SetCombatModel(); - - SetPhysics( af.GetPhysics() ); - - af.GetPhysics()->PutToRest(); - if ( !spawnArgs.GetBool( "nodrop", "0" ) ) { - af.GetPhysics()->Activate(); - } - - fl.takedamage = true; - - if ( head.GetEntity() ) { - int anim = head.GetEntity()->GetAnimator()->GetAnim( "dead" ); - - if ( anim ) { - head.GetEntity()->GetAnimator()->SetFrame( ANIMCHANNEL_ALL, anim, 0, gameLocal.time, 0 ); - } - } -} - -/* -================ -idAFEntity_WithAttachedHead::Save -================ -*/ -void idAFEntity_WithAttachedHead::Save( idSaveGame *savefile ) const { - head.Save( savefile ); -} - -/* -================ -idAFEntity_WithAttachedHead::Restore -================ -*/ -void idAFEntity_WithAttachedHead::Restore( idRestoreGame *savefile ) { - head.Restore( savefile ); -} - -/* -================ -idAFEntity_WithAttachedHead::SetupHead -================ -*/ -void idAFEntity_WithAttachedHead::SetupHead( void ) { - idAFAttachment *headEnt; - idStr jointName; - const char *headModel; - jointHandle_t joint; - idVec3 origin; - idMat3 axis; - - headModel = spawnArgs.GetString( "def_head", "" ); - if ( headModel[ 0 ] ) { - jointName = spawnArgs.GetString( "head_joint" ); - joint = animator.GetJointHandle( jointName ); - if ( joint == INVALID_JOINT ) { - gameLocal.Error( "Joint '%s' not found for 'head_joint' on '%s'", jointName.c_str(), name.c_str() ); - } - - headEnt = static_cast( gameLocal.SpawnEntityType( idAFAttachment::Type, NULL ) ); - headEnt->SetName( va( "%s_head", name.c_str() ) ); - headEnt->SetBody( this, headModel, joint ); - headEnt->SetCombatModel(); - head = headEnt; - -#ifdef _D3XP - idStr xSkin; - if ( spawnArgs.GetString( "skin_head_xray", "", xSkin ) ) { - headEnt->xraySkin = declManager->FindSkin( xSkin.c_str() ); - headEnt->UpdateModel(); - } -#endif - animator.GetJointTransform( joint, gameLocal.time, origin, axis ); - origin = renderEntity.origin + origin * renderEntity.axis; - headEnt->SetOrigin( origin ); - headEnt->SetAxis( renderEntity.axis ); - headEnt->BindToJoint( this, joint, true ); - } -} - -/* -================ -idAFEntity_WithAttachedHead::Think -================ -*/ -void idAFEntity_WithAttachedHead::Think( void ) { - idAFEntity_Base::Think(); -} - -/* -================ -idAFEntity_WithAttachedHead::LinkCombat -================ -*/ -void idAFEntity_WithAttachedHead::LinkCombat( void ) { - idAFAttachment *headEnt; - - if ( fl.hidden ) { - return; - } - - if ( combatModel ) { - combatModel->Link( gameLocal.clip, this, 0, renderEntity.origin, renderEntity.axis, modelDefHandle ); - } - headEnt = head.GetEntity(); - if ( headEnt ) { - headEnt->LinkCombat(); - } -} - -/* -================ -idAFEntity_WithAttachedHead::UnlinkCombat -================ -*/ -void idAFEntity_WithAttachedHead::UnlinkCombat( void ) { - idAFAttachment *headEnt; - - if ( combatModel ) { - combatModel->Unlink(); - } - headEnt = head.GetEntity(); - if ( headEnt ) { - headEnt->UnlinkCombat(); - } -} - -/* -================ -idAFEntity_WithAttachedHead::Hide -================ -*/ -void idAFEntity_WithAttachedHead::Hide( void ) { - idAFEntity_Base::Hide(); - if ( head.GetEntity() ) { - head.GetEntity()->Hide(); - } - UnlinkCombat(); -} - -/* -================ -idAFEntity_WithAttachedHead::Show -================ -*/ -void idAFEntity_WithAttachedHead::Show( void ) { - idAFEntity_Base::Show(); - if ( head.GetEntity() ) { - head.GetEntity()->Show(); - } - LinkCombat(); -} - -/* -================ -idAFEntity_WithAttachedHead::ProjectOverlay -================ -*/ -void idAFEntity_WithAttachedHead::ProjectOverlay( const idVec3 &origin, const idVec3 &dir, float size, const char *material ) { - - idEntity::ProjectOverlay( origin, dir, size, material ); - - if ( head.GetEntity() ) { - head.GetEntity()->ProjectOverlay( origin, dir, size, material ); - } -} - -/* -============ -idAFEntity_WithAttachedHead::Gib -============ -*/ -void idAFEntity_WithAttachedHead::Gib( const idVec3 &dir, const char *damageDefName ) { - // only gib once - if ( gibbed ) { - return; - } - idAFEntity_Gibbable::Gib( dir, damageDefName ); - if ( head.GetEntity() ) { - head.GetEntity()->Hide(); - } -} - -/* -============ -idAFEntity_WithAttachedHead::Event_Gib -============ -*/ -void idAFEntity_WithAttachedHead::Event_Gib( const char *damageDefName ) { - Gib( idVec3( 0, 0, 1 ), damageDefName ); -} - -/* -================ -idAFEntity_WithAttachedHead::Event_Activate -================ -*/ -void idAFEntity_WithAttachedHead::Event_Activate( idEntity *activator ) { - float delay; - idVec3 init_velocity, init_avelocity; - - Show(); - - af.GetPhysics()->EnableImpact(); - af.GetPhysics()->Activate(); - - spawnArgs.GetVector( "init_velocity", "0 0 0", init_velocity ); - spawnArgs.GetVector( "init_avelocity", "0 0 0", init_avelocity ); - - delay = spawnArgs.GetFloat( "init_velocityDelay", "0" ); - if ( delay == 0.0f ) { - af.GetPhysics()->SetLinearVelocity( init_velocity ); - } else { - PostEventSec( &EV_SetLinearVelocity, delay, init_velocity ); - } - - delay = spawnArgs.GetFloat( "init_avelocityDelay", "0" ); - if ( delay == 0.0f ) { - af.GetPhysics()->SetAngularVelocity( init_avelocity ); - } else { - PostEventSec( &EV_SetAngularVelocity, delay, init_avelocity ); - } -} - - -/* -=============================================================================== - - idAFEntity_Vehicle - -=============================================================================== -*/ - -CLASS_DECLARATION( idAFEntity_Base, idAFEntity_Vehicle ) -END_CLASS - -/* -================ -idAFEntity_Vehicle::idAFEntity_Vehicle -================ -*/ -idAFEntity_Vehicle::idAFEntity_Vehicle( void ) { - player = NULL; - eyesJoint = INVALID_JOINT; - steeringWheelJoint = INVALID_JOINT; - wheelRadius = 0.0f; - steerAngle = 0.0f; - steerSpeed = 0.0f; - dustSmoke = NULL; -} - -/* -================ -idAFEntity_Vehicle::Spawn -================ -*/ -void idAFEntity_Vehicle::Spawn( void ) { - const char *eyesJointName = spawnArgs.GetString( "eyesJoint", "eyes" ); - const char *steeringWheelJointName = spawnArgs.GetString( "steeringWheelJoint", "steeringWheel" ); - - LoadAF(); - - SetCombatModel(); - - SetPhysics( af.GetPhysics() ); - - fl.takedamage = true; - - if ( !eyesJointName[0] ) { - gameLocal.Error( "idAFEntity_Vehicle '%s' no eyes joint specified", name.c_str() ); - } - eyesJoint = animator.GetJointHandle( eyesJointName ); - if ( !steeringWheelJointName[0] ) { - gameLocal.Error( "idAFEntity_Vehicle '%s' no steering wheel joint specified", name.c_str() ); - } - steeringWheelJoint = animator.GetJointHandle( steeringWheelJointName ); - - spawnArgs.GetFloat( "wheelRadius", "20", wheelRadius ); - spawnArgs.GetFloat( "steerSpeed", "5", steerSpeed ); - - player = NULL; - steerAngle = 0.0f; - - const char *smokeName = spawnArgs.GetString( "smoke_vehicle_dust", "muzzlesmoke" ); - if ( *smokeName != '\0' ) { - dustSmoke = static_cast( declManager->FindType( DECL_PARTICLE, smokeName ) ); - } -} - -/* -================ -idAFEntity_Vehicle::Use -================ -*/ -void idAFEntity_Vehicle::Use( idPlayer *other ) { - idVec3 origin; - idMat3 axis; - - if ( player ) { - if ( player == other ) { - other->Unbind(); - player = NULL; - - af.GetPhysics()->SetComeToRest( true ); - } - } - else { - player = other; - animator.GetJointTransform( eyesJoint, gameLocal.time, origin, axis ); - origin = renderEntity.origin + origin * renderEntity.axis; - player->GetPhysics()->SetOrigin( origin ); - player->BindToBody( this, 0, true ); - - af.GetPhysics()->SetComeToRest( false ); - af.GetPhysics()->Activate(); - } -} - -/* -================ -idAFEntity_Vehicle::GetSteerAngle -================ -*/ -float idAFEntity_Vehicle::GetSteerAngle( void ) { - float idealSteerAngle, angleDelta; - - idealSteerAngle = player->usercmd.rightmove * ( 30.0f / 128.0f ); - angleDelta = idealSteerAngle - steerAngle; - - if ( angleDelta > steerSpeed ) { - steerAngle += steerSpeed; - } else if ( angleDelta < -steerSpeed ) { - steerAngle -= steerSpeed; - } else { - steerAngle = idealSteerAngle; - } - - return steerAngle; -} - - -/* -=============================================================================== - - idAFEntity_VehicleSimple - -=============================================================================== -*/ - -CLASS_DECLARATION( idAFEntity_Vehicle, idAFEntity_VehicleSimple ) -END_CLASS - -/* -================ -idAFEntity_VehicleSimple::idAFEntity_VehicleSimple -================ -*/ -idAFEntity_VehicleSimple::idAFEntity_VehicleSimple( void ) { - int i; - for ( i = 0; i < 4; i++ ) { - suspension[i] = NULL; - } -} - -/* -================ -idAFEntity_VehicleSimple::~idAFEntity_VehicleSimple -================ -*/ -idAFEntity_VehicleSimple::~idAFEntity_VehicleSimple( void ) { - delete wheelModel; - wheelModel = NULL; -} - -/* -================ -idAFEntity_VehicleSimple::Spawn -================ -*/ -void idAFEntity_VehicleSimple::Spawn( void ) { - static const char *wheelJointKeys[] = { - "wheelJointFrontLeft", - "wheelJointFrontRight", - "wheelJointRearLeft", - "wheelJointRearRight" - }; - static idVec3 wheelPoly[4] = { idVec3( 2, 2, 0 ), idVec3( 2, -2, 0 ), idVec3( -2, -2, 0 ), idVec3( -2, 2, 0 ) }; - - int i; - idVec3 origin; - idMat3 axis; - idTraceModel trm; - - trm.SetupPolygon( wheelPoly, 4 ); - trm.Translate( idVec3( 0, 0, -wheelRadius ) ); - wheelModel = new idClipModel( trm ); - - for ( i = 0; i < 4; i++ ) { - const char *wheelJointName = spawnArgs.GetString( wheelJointKeys[i], "" ); - if ( !wheelJointName[0] ) { - gameLocal.Error( "idAFEntity_VehicleSimple '%s' no '%s' specified", name.c_str(), wheelJointKeys[i] ); - } - wheelJoints[i] = animator.GetJointHandle( wheelJointName ); - if ( wheelJoints[i] == INVALID_JOINT ) { - gameLocal.Error( "idAFEntity_VehicleSimple '%s' can't find wheel joint '%s'", name.c_str(), wheelJointName ); - } - - GetAnimator()->GetJointTransform( wheelJoints[i], 0, origin, axis ); - origin = renderEntity.origin + origin * renderEntity.axis; - - suspension[i] = new idAFConstraint_Suspension(); - suspension[i]->Setup( va( "suspension%d", i ), af.GetPhysics()->GetBody( 0 ), origin, af.GetPhysics()->GetAxis( 0 ), wheelModel ); - suspension[i]->SetSuspension( g_vehicleSuspensionUp.GetFloat(), - g_vehicleSuspensionDown.GetFloat(), - g_vehicleSuspensionKCompress.GetFloat(), - g_vehicleSuspensionDamping.GetFloat(), - g_vehicleTireFriction.GetFloat() ); - - af.GetPhysics()->AddConstraint( suspension[i] ); - } - - memset( wheelAngles, 0, sizeof( wheelAngles ) ); - BecomeActive( TH_THINK ); -} - -/* -================ -idAFEntity_VehicleSimple::Think -================ -*/ -void idAFEntity_VehicleSimple::Think( void ) { - int i; - float force = 0.0f, velocity = 0.0f, steerAngle = 0.0f; - idVec3 origin; - idMat3 axis; - idRotation wheelRotation, steerRotation; - - if ( thinkFlags & TH_THINK ) { - - if ( player ) { - // capture the input from a player - velocity = g_vehicleVelocity.GetFloat(); - if ( player->usercmd.forwardmove < 0 ) { - velocity = -velocity; - } - force = idMath::Fabs( player->usercmd.forwardmove * g_vehicleForce.GetFloat() ) * (1.0f / 128.0f); - steerAngle = GetSteerAngle(); - } - - // update the wheel motor force and steering - for ( i = 0; i < 2; i++ ) { - - // front wheel drive - if ( velocity != 0.0f ) { - suspension[i]->EnableMotor( true ); - } else { - suspension[i]->EnableMotor( false ); - } - suspension[i]->SetMotorVelocity( velocity ); - suspension[i]->SetMotorForce( force ); - - // update the wheel steering - suspension[i]->SetSteerAngle( steerAngle ); - } - - // adjust wheel velocity for better steering because there are no differentials between the wheels - if ( steerAngle < 0.0f ) { - suspension[0]->SetMotorVelocity( velocity * 0.5f ); - } else if ( steerAngle > 0.0f ) { - suspension[1]->SetMotorVelocity( velocity * 0.5f ); - } - - // update suspension with latest cvar settings - for ( i = 0; i < 4; i++ ) { - suspension[i]->SetSuspension( g_vehicleSuspensionUp.GetFloat(), - g_vehicleSuspensionDown.GetFloat(), - g_vehicleSuspensionKCompress.GetFloat(), - g_vehicleSuspensionDamping.GetFloat(), - g_vehicleTireFriction.GetFloat() ); - } - - // run the physics - RunPhysics(); - - // move and rotate the wheels visually - for ( i = 0; i < 4; i++ ) { - idAFBody *body = af.GetPhysics()->GetBody( 0 ); - - origin = suspension[i]->GetWheelOrigin(); - velocity = body->GetPointVelocity( origin ) * body->GetWorldAxis()[0]; - wheelAngles[i] += velocity * MS2SEC( gameLocal.msec ) / wheelRadius; - - // additional rotation about the wheel axis - wheelRotation.SetAngle( RAD2DEG( wheelAngles[i] ) ); - wheelRotation.SetVec( 0, -1, 0 ); - - if ( i < 2 ) { - // rotate the wheel for steering - steerRotation.SetAngle( steerAngle ); - steerRotation.SetVec( 0, 0, 1 ); - // set wheel rotation - animator.SetJointAxis( wheelJoints[i], JOINTMOD_WORLD, wheelRotation.ToMat3() * steerRotation.ToMat3() ); - } else { - // set wheel rotation - animator.SetJointAxis( wheelJoints[i], JOINTMOD_WORLD, wheelRotation.ToMat3() ); - } - - // set wheel position for suspension - origin = ( origin - renderEntity.origin ) * renderEntity.axis.Transpose(); - GetAnimator()->SetJointPos( wheelJoints[i], JOINTMOD_WORLD_OVERRIDE, origin ); - } -/* - // spawn dust particle effects - if ( force != 0.0f && !( gameLocal.framenum & 7 ) ) { - int numContacts; - idAFConstraint_Contact *contacts[2]; - for ( i = 0; i < 4; i++ ) { - numContacts = af.GetPhysics()->GetBodyContactConstraints( wheels[i]->GetClipModel()->GetId(), contacts, 2 ); - for ( int j = 0; j < numContacts; j++ ) { - gameLocal.smokeParticles->EmitSmoke( dustSmoke, gameLocal.time, gameLocal.random.RandomFloat(), contacts[j]->GetContact().point, contacts[j]->GetContact().normal.ToMat3() ); - } - } - } -*/ - } - - UpdateAnimation(); - if ( thinkFlags & TH_UPDATEVISUALS ) { - Present(); - LinkCombat(); - } -} - - -/* -=============================================================================== - - idAFEntity_VehicleFourWheels - -=============================================================================== -*/ - -CLASS_DECLARATION( idAFEntity_Vehicle, idAFEntity_VehicleFourWheels ) -END_CLASS - - -/* -================ -idAFEntity_VehicleFourWheels::idAFEntity_VehicleFourWheels -================ -*/ -idAFEntity_VehicleFourWheels::idAFEntity_VehicleFourWheels( void ) { - int i; - - for ( i = 0; i < 4; i++ ) { - wheels[i] = NULL; - wheelJoints[i] = INVALID_JOINT; - wheelAngles[i] = 0.0f; - } - steering[0] = NULL; - steering[1] = NULL; -} - -/* -================ -idAFEntity_VehicleFourWheels::Spawn -================ -*/ -void idAFEntity_VehicleFourWheels::Spawn( void ) { - int i; - static const char *wheelBodyKeys[] = { - "wheelBodyFrontLeft", - "wheelBodyFrontRight", - "wheelBodyRearLeft", - "wheelBodyRearRight" - }; - static const char *wheelJointKeys[] = { - "wheelJointFrontLeft", - "wheelJointFrontRight", - "wheelJointRearLeft", - "wheelJointRearRight" - }; - static const char *steeringHingeKeys[] = { - "steeringHingeFrontLeft", - "steeringHingeFrontRight", - }; - - const char *wheelBodyName, *wheelJointName, *steeringHingeName; - - for ( i = 0; i < 4; i++ ) { - wheelBodyName = spawnArgs.GetString( wheelBodyKeys[i], "" ); - if ( !wheelBodyName[0] ) { - gameLocal.Error( "idAFEntity_VehicleFourWheels '%s' no '%s' specified", name.c_str(), wheelBodyKeys[i] ); - } - wheels[i] = af.GetPhysics()->GetBody( wheelBodyName ); - if ( !wheels[i] ) { - gameLocal.Error( "idAFEntity_VehicleFourWheels '%s' can't find wheel body '%s'", name.c_str(), wheelBodyName ); - } - wheelJointName = spawnArgs.GetString( wheelJointKeys[i], "" ); - if ( !wheelJointName[0] ) { - gameLocal.Error( "idAFEntity_VehicleFourWheels '%s' no '%s' specified", name.c_str(), wheelJointKeys[i] ); - } - wheelJoints[i] = animator.GetJointHandle( wheelJointName ); - if ( wheelJoints[i] == INVALID_JOINT ) { - gameLocal.Error( "idAFEntity_VehicleFourWheels '%s' can't find wheel joint '%s'", name.c_str(), wheelJointName ); - } - } - - for ( i = 0; i < 2; i++ ) { - steeringHingeName = spawnArgs.GetString( steeringHingeKeys[i], "" ); - if ( !steeringHingeName[0] ) { - gameLocal.Error( "idAFEntity_VehicleFourWheels '%s' no '%s' specified", name.c_str(), steeringHingeKeys[i] ); - } - steering[i] = static_cast(af.GetPhysics()->GetConstraint( steeringHingeName )); - if ( !steering[i] ) { - gameLocal.Error( "idAFEntity_VehicleFourWheels '%s': can't find steering hinge '%s'", name.c_str(), steeringHingeName ); - } - } - - memset( wheelAngles, 0, sizeof( wheelAngles ) ); - BecomeActive( TH_THINK ); -} - -/* -================ -idAFEntity_VehicleFourWheels::Think -================ -*/ -void idAFEntity_VehicleFourWheels::Think( void ) { - int i; - float force = 0.0f, velocity = 0.0f, steerAngle = 0.0f; - idVec3 origin; - idMat3 axis; - idRotation rotation; - - if ( thinkFlags & TH_THINK ) { - - if ( player ) { - // capture the input from a player - velocity = g_vehicleVelocity.GetFloat(); - if ( player->usercmd.forwardmove < 0 ) { - velocity = -velocity; - } - force = idMath::Fabs( player->usercmd.forwardmove * g_vehicleForce.GetFloat() ) * (1.0f / 128.0f); - steerAngle = GetSteerAngle(); - } - - // update the wheel motor force - for ( i = 0; i < 2; i++ ) { - wheels[2+i]->SetContactMotorVelocity( velocity ); - wheels[2+i]->SetContactMotorForce( force ); - } - - // adjust wheel velocity for better steering because there are no differentials between the wheels - if ( steerAngle < 0.0f ) { - wheels[2]->SetContactMotorVelocity( velocity * 0.5f ); - } - else if ( steerAngle > 0.0f ) { - wheels[3]->SetContactMotorVelocity( velocity * 0.5f ); - } - - // update the wheel steering - steering[0]->SetSteerAngle( steerAngle ); - steering[1]->SetSteerAngle( steerAngle ); - for ( i = 0; i < 2; i++ ) { - steering[i]->SetSteerSpeed( 3.0f ); - } - - // update the steering wheel - animator.GetJointTransform( steeringWheelJoint, gameLocal.time, origin, axis ); - rotation.SetVec( axis[2] ); - rotation.SetAngle( -steerAngle ); - animator.SetJointAxis( steeringWheelJoint, JOINTMOD_WORLD, rotation.ToMat3() ); - - // run the physics - RunPhysics(); - - // rotate the wheels visually - for ( i = 0; i < 4; i++ ) { - if ( force == 0.0f ) { - velocity = wheels[i]->GetLinearVelocity() * wheels[i]->GetWorldAxis()[0]; - } - wheelAngles[i] += velocity * MS2SEC( gameLocal.msec ) / wheelRadius; - // give the wheel joint an additional rotation about the wheel axis - rotation.SetAngle( RAD2DEG( wheelAngles[i] ) ); - axis = af.GetPhysics()->GetAxis( 0 ); - rotation.SetVec( (wheels[i]->GetWorldAxis() * axis.Transpose())[2] ); - animator.SetJointAxis( wheelJoints[i], JOINTMOD_WORLD, rotation.ToMat3() ); - } - - // spawn dust particle effects - if ( force != 0.0f && !( gameLocal.framenum & 7 ) ) { - int numContacts; - idAFConstraint_Contact *contacts[2]; - for ( i = 0; i < 4; i++ ) { - numContacts = af.GetPhysics()->GetBodyContactConstraints( wheels[i]->GetClipModel()->GetId(), contacts, 2 ); - for ( int j = 0; j < numContacts; j++ ) { - gameLocal.smokeParticles->EmitSmoke( dustSmoke, gameLocal.time, gameLocal.random.RandomFloat(), contacts[j]->GetContact().point, contacts[j]->GetContact().normal.ToMat3(), timeGroup /* D3XP */ ); - } - } - } - } - - UpdateAnimation(); - if ( thinkFlags & TH_UPDATEVISUALS ) { - Present(); - LinkCombat(); - } -} - - -/* -=============================================================================== - - idAFEntity_VehicleSixWheels - -=============================================================================== -*/ - -CLASS_DECLARATION( idAFEntity_Vehicle, idAFEntity_VehicleSixWheels ) -END_CLASS - - /* -================ -idAFEntity_VehicleSixWheels::idAFEntity_VehicleSixWheels -================ -*/ -idAFEntity_VehicleSixWheels::idAFEntity_VehicleSixWheels( void ) { - int i; - - for ( i = 0; i < 6; i++ ) { - wheels[i] = NULL; - wheelJoints[i] = INVALID_JOINT; - wheelAngles[i] = 0.0f; - } - steering[0] = NULL; - steering[1] = NULL; - steering[2] = NULL; - steering[3] = NULL; -} - -/* -================ -idAFEntity_VehicleSixWheels::Spawn -================ -*/ -void idAFEntity_VehicleSixWheels::Spawn( void ) { - int i; - static const char *wheelBodyKeys[] = { - "wheelBodyFrontLeft", - "wheelBodyFrontRight", - "wheelBodyMiddleLeft", - "wheelBodyMiddleRight", - "wheelBodyRearLeft", - "wheelBodyRearRight" - }; - static const char *wheelJointKeys[] = { - "wheelJointFrontLeft", - "wheelJointFrontRight", - "wheelJointMiddleLeft", - "wheelJointMiddleRight", - "wheelJointRearLeft", - "wheelJointRearRight" - }; - static const char *steeringHingeKeys[] = { - "steeringHingeFrontLeft", - "steeringHingeFrontRight", - "steeringHingeRearLeft", - "steeringHingeRearRight" - }; - - const char *wheelBodyName, *wheelJointName, *steeringHingeName; - - for ( i = 0; i < 6; i++ ) { - wheelBodyName = spawnArgs.GetString( wheelBodyKeys[i], "" ); - if ( !wheelBodyName[0] ) { - gameLocal.Error( "idAFEntity_VehicleSixWheels '%s' no '%s' specified", name.c_str(), wheelBodyKeys[i] ); - } - wheels[i] = af.GetPhysics()->GetBody( wheelBodyName ); - if ( !wheels[i] ) { - gameLocal.Error( "idAFEntity_VehicleSixWheels '%s' can't find wheel body '%s'", name.c_str(), wheelBodyName ); - } - wheelJointName = spawnArgs.GetString( wheelJointKeys[i], "" ); - if ( !wheelJointName[0] ) { - gameLocal.Error( "idAFEntity_VehicleSixWheels '%s' no '%s' specified", name.c_str(), wheelJointKeys[i] ); - } - wheelJoints[i] = animator.GetJointHandle( wheelJointName ); - if ( wheelJoints[i] == INVALID_JOINT ) { - gameLocal.Error( "idAFEntity_VehicleSixWheels '%s' can't find wheel joint '%s'", name.c_str(), wheelJointName ); - } - } - - for ( i = 0; i < 4; i++ ) { - steeringHingeName = spawnArgs.GetString( steeringHingeKeys[i], "" ); - if ( !steeringHingeName[0] ) { - gameLocal.Error( "idAFEntity_VehicleSixWheels '%s' no '%s' specified", name.c_str(), steeringHingeKeys[i] ); - } - steering[i] = static_cast(af.GetPhysics()->GetConstraint( steeringHingeName )); - if ( !steering[i] ) { - gameLocal.Error( "idAFEntity_VehicleSixWheels '%s': can't find steering hinge '%s'", name.c_str(), steeringHingeName ); - } - } - - memset( wheelAngles, 0, sizeof( wheelAngles ) ); - BecomeActive( TH_THINK ); -} - -/* -================ -idAFEntity_VehicleSixWheels::Think -================ -*/ -void idAFEntity_VehicleSixWheels::Think( void ) { - int i; -#ifndef _D3XP - float force = 0.0f, velocity = 0.0f, steerAngle = 0.0f; -#endif - idVec3 origin; - idMat3 axis; - idRotation rotation; - - if ( thinkFlags & TH_THINK ) { - - if ( player ) { - // capture the input from a player - velocity = g_vehicleVelocity.GetFloat(); - if ( player->usercmd.forwardmove < 0 ) { - velocity = -velocity; - } - force = idMath::Fabs( player->usercmd.forwardmove * g_vehicleForce.GetFloat() ) * (1.0f / 128.0f); - steerAngle = GetSteerAngle(); - } - - // update the wheel motor force - for ( i = 0; i < 6; i++ ) { - wheels[i]->SetContactMotorVelocity( velocity ); - wheels[i]->SetContactMotorForce( force ); - } - - // adjust wheel velocity for better steering because there are no differentials between the wheels - if ( steerAngle < 0.0f ) { - for ( i = 0; i < 3; i++ ) { - wheels[(i<<1)]->SetContactMotorVelocity( velocity * 0.5f ); - } - } - else if ( steerAngle > 0.0f ) { - for ( i = 0; i < 3; i++ ) { - wheels[1+(i<<1)]->SetContactMotorVelocity( velocity * 0.5f ); - } - } - - // update the wheel steering - steering[0]->SetSteerAngle( steerAngle ); - steering[1]->SetSteerAngle( steerAngle ); - steering[2]->SetSteerAngle( -steerAngle ); - steering[3]->SetSteerAngle( -steerAngle ); - for ( i = 0; i < 4; i++ ) { - steering[i]->SetSteerSpeed( 3.0f ); - } - - // update the steering wheel - animator.GetJointTransform( steeringWheelJoint, gameLocal.time, origin, axis ); - rotation.SetVec( axis[2] ); - rotation.SetAngle( -steerAngle ); - animator.SetJointAxis( steeringWheelJoint, JOINTMOD_WORLD, rotation.ToMat3() ); - - // run the physics - RunPhysics(); - - // rotate the wheels visually - for ( i = 0; i < 6; i++ ) { - if ( force == 0.0f ) { - velocity = wheels[i]->GetLinearVelocity() * wheels[i]->GetWorldAxis()[0]; - } - wheelAngles[i] += velocity * MS2SEC( gameLocal.msec ) / wheelRadius; - // give the wheel joint an additional rotation about the wheel axis - rotation.SetAngle( RAD2DEG( wheelAngles[i] ) ); - axis = af.GetPhysics()->GetAxis( 0 ); - rotation.SetVec( (wheels[i]->GetWorldAxis() * axis.Transpose())[2] ); - animator.SetJointAxis( wheelJoints[i], JOINTMOD_WORLD, rotation.ToMat3() ); - } - - // spawn dust particle effects - if ( force != 0.0f && !( gameLocal.framenum & 7 ) ) { - int numContacts; - idAFConstraint_Contact *contacts[2]; - for ( i = 0; i < 6; i++ ) { - numContacts = af.GetPhysics()->GetBodyContactConstraints( wheels[i]->GetClipModel()->GetId(), contacts, 2 ); - for ( int j = 0; j < numContacts; j++ ) { - gameLocal.smokeParticles->EmitSmoke( dustSmoke, gameLocal.time, gameLocal.random.RandomFloat(), contacts[j]->GetContact().point, contacts[j]->GetContact().normal.ToMat3(), timeGroup /* D3XP */ ); - } - } - } - } - - UpdateAnimation(); - if ( thinkFlags & TH_UPDATEVISUALS ) { - Present(); - LinkCombat(); - } -} - -#ifdef _D3XP -/* -=============================================================================== - -idAFEntity_VehicleAutomated - -=============================================================================== -*/ -const idEventDef EV_Vehicle_setVelocity( "setVelocity", "f" ); -const idEventDef EV_Vehicle_setTorque( "setTorque", "f" ); -const idEventDef EV_Vehicle_setSteeringSpeed( "setSteeringSpeed", "f" ); -const idEventDef EV_Vehicle_setWaypoint( "setWaypoint", "e" ); - -CLASS_DECLARATION( idAFEntity_VehicleSixWheels, idAFEntity_VehicleAutomated ) -EVENT( EV_PostSpawn, idAFEntity_VehicleAutomated::PostSpawn ) -EVENT( EV_Vehicle_setVelocity, idAFEntity_VehicleAutomated::Event_SetVelocity ) -EVENT( EV_Vehicle_setTorque, idAFEntity_VehicleAutomated::Event_SetTorque ) -EVENT( EV_Vehicle_setSteeringSpeed, idAFEntity_VehicleAutomated::Event_SetSteeringSpeed ) -EVENT( EV_Vehicle_setWaypoint, idAFEntity_VehicleAutomated::Event_SetWayPoint ) -END_CLASS - -/* -================ -idAFEntity_VehicleAutomated::Spawn -================ -*/ -void idAFEntity_VehicleAutomated::Spawn( void ) { - - velocity = force = steerAngle = 0.f; - currentSteering = steeringSpeed = 0.f; - originHeight = 0.f; - waypoint = NULL; - - spawnArgs.GetFloat( "velocity", "150", velocity ); - spawnArgs.GetFloat( "torque", "200000", force ); - spawnArgs.GetFloat( "steeringSpeed", "1", steeringSpeed ); - spawnArgs.GetFloat( "originHeight", "0", originHeight ); - - PostEventMS( &EV_PostSpawn, 0 ); -} - -/* -================ -idAFEntity_VehicleAutomated::PostSpawn -================ -*/ -void idAFEntity_VehicleAutomated::PostSpawn( void ) { - - if ( targets.Num() ) { - waypoint = targets[0].GetEntity(); - } -} - -/* -================ -idAFEntity_VehicleAutomated::Event_SetVelocity -================ -*/ -void idAFEntity_VehicleAutomated::Event_SetVelocity( float _velocity ) { - velocity = _velocity; -} - -/* -================ -idAFEntity_VehicleAutomated::Event_SetTorque -================ -*/ -void idAFEntity_VehicleAutomated::Event_SetTorque( float _torque ) { - force = _torque; -} - -/* -================ -idAFEntity_VehicleAutomated::Event_SetSteeringSpeed -================ -*/ -void idAFEntity_VehicleAutomated::Event_SetSteeringSpeed( float _steeringSpeed ) { - steeringSpeed = _steeringSpeed; -} - -/* -================ -idAFEntity_VehicleAutomated::Event_SetWayPoint -================ -*/ -void idAFEntity_VehicleAutomated::Event_SetWayPoint( idEntity *_waypoint ) { - waypoint = _waypoint; -} - -/* -================ -idAFEntity_VehicleAutomated::Think -================ -*/ -#define HIT_WAYPOINT_THRESHOLD 80.f - -void idAFEntity_VehicleAutomated::Think( void ) { - - // If we don't have a waypoint, coast to a stop - if ( !waypoint ) { - velocity = force = steerAngle = 0.f; - idAFEntity_VehicleSixWheels::Think(); - return; - } - - idVec3 waypoint_origin, vehicle_origin; - idVec3 travel_vector; - float distance_from_waypoint; - - // Set up the vector from the vehicle origin, to the waypoint - vehicle_origin = GetPhysics()->GetOrigin(); - vehicle_origin.z -= originHeight; - - waypoint_origin = waypoint->GetPhysics()->GetOrigin(); - - travel_vector = waypoint_origin - vehicle_origin; - distance_from_waypoint = travel_vector.Length(); - - // Check if we've hit the waypoint (within a certain threshold) - if ( distance_from_waypoint < HIT_WAYPOINT_THRESHOLD ) { - idStr callfunc; - const function_t *func; - idThread *thread; - - // Waypoints can call script functions - waypoint->spawnArgs.GetString( "call", "", callfunc ); - if ( callfunc.Length() ) { - func = gameLocal.program.FindFunction( callfunc ); - if ( func != NULL ) { - thread = new idThread( func ); - thread->DelayedStart( 0 ); - } - } - - // Get next waypoint - if ( waypoint->targets.Num() ) { - waypoint = waypoint->targets[0].GetEntity(); - } else { - waypoint = NULL; - } - - // We are switching waypoints, adjust steering next frame - idAFEntity_VehicleSixWheels::Think(); - return; - } - - idAngles vehicle_angles, travel_angles; - - // Get the angles we need to steer towards - travel_angles = travel_vector.ToAngles().Normalize360(); - vehicle_angles = this->GetPhysics()->GetAxis().ToAngles().Normalize360(); - - float delta_yaw; - - // Get the shortest steering angle towards the travel angles - delta_yaw = vehicle_angles.yaw - travel_angles.yaw; - if ( idMath::Fabs( delta_yaw ) > 180.f ) { - if ( delta_yaw > 0 ) { - delta_yaw = delta_yaw - 360; - } else { - delta_yaw = delta_yaw + 360; - } - } - - // Maximum steering angle is 35 degrees - delta_yaw = idMath::ClampFloat( -35.f, 35.f, delta_yaw ); - - idealSteering = delta_yaw; - - // Adjust steering incrementally so it doesn't snap to the ideal angle - if ( idMath::Fabs( (idealSteering - currentSteering) ) > steeringSpeed ) { - if ( idealSteering > currentSteering ) { - currentSteering += steeringSpeed; - } else { - currentSteering -= steeringSpeed; - } - } else { - currentSteering = idealSteering; - } - - // DEBUG - if ( g_vehicleDebug.GetBool() ) { - gameRenderWorld->DebugBounds( colorRed, idBounds(idVec3(-4,-4,-4),idVec3(4,4,4)), vehicle_origin ); - gameRenderWorld->DebugBounds( colorRed, idBounds(idVec3(-4,-4,-4),idVec3(4,4,4)), waypoint_origin ); - gameRenderWorld->DrawText( waypoint->name.c_str(), waypoint_origin + idVec3(0,0,16), 0.25f, colorYellow, gameLocal.GetLocalPlayer()->viewAxis ); - gameRenderWorld->DebugArrow( colorWhite, vehicle_origin, waypoint_origin, 12.f ); - } - - // Set the final steerAngle for the vehicle - steerAngle = currentSteering; - - idAFEntity_VehicleSixWheels::Think(); -} -#endif - -/* -=============================================================================== - - idAFEntity_SteamPipe - -=============================================================================== -*/ - -CLASS_DECLARATION( idAFEntity_Base, idAFEntity_SteamPipe ) -END_CLASS - - -/* -================ -idAFEntity_SteamPipe::idAFEntity_SteamPipe -================ -*/ -idAFEntity_SteamPipe::idAFEntity_SteamPipe( void ) { - steamBody = 0; - steamForce = 0.0f; - steamUpForce = 0.0f; - steamModelDefHandle = -1; - memset( &steamRenderEntity, 0, sizeof( steamRenderEntity ) ); -} - -/* -================ -idAFEntity_SteamPipe::~idAFEntity_SteamPipe -================ -*/ -idAFEntity_SteamPipe::~idAFEntity_SteamPipe( void ) { - if ( steamModelDefHandle >= 0 ){ - gameRenderWorld->FreeEntityDef( steamModelDefHandle ); - } -} - -/* -================ -idAFEntity_SteamPipe::Save -================ -*/ -void idAFEntity_SteamPipe::Save( idSaveGame *savefile ) const { -} - -/* -================ -idAFEntity_SteamPipe::Restore -================ -*/ -void idAFEntity_SteamPipe::Restore( idRestoreGame *savefile ) { - Spawn(); -} - -/* -================ -idAFEntity_SteamPipe::Spawn -================ -*/ -void idAFEntity_SteamPipe::Spawn( void ) { - idVec3 steamDir; - const char *steamBodyName; - - LoadAF(); - - SetCombatModel(); - - SetPhysics( af.GetPhysics() ); - - fl.takedamage = true; - - steamBodyName = spawnArgs.GetString( "steamBody", "" ); - steamForce = spawnArgs.GetFloat( "steamForce", "2000" ); - steamUpForce = spawnArgs.GetFloat( "steamUpForce", "10" ); - steamDir = af.GetPhysics()->GetAxis( steamBody )[2]; - steamBody = af.GetPhysics()->GetBodyId( steamBodyName ); - force.SetPosition( af.GetPhysics(), steamBody, af.GetPhysics()->GetOrigin( steamBody ) ); - force.SetForce( steamDir * -steamForce ); - - InitSteamRenderEntity(); - - BecomeActive( TH_THINK ); -} - -/* -================ -idAFEntity_SteamPipe::InitSteamRenderEntity -================ -*/ -void idAFEntity_SteamPipe::InitSteamRenderEntity( void ) { - const char *temp; - const idDeclModelDef *modelDef; - - memset( &steamRenderEntity, 0, sizeof( steamRenderEntity ) ); - steamRenderEntity.shaderParms[ SHADERPARM_RED ] = 1.0f; - steamRenderEntity.shaderParms[ SHADERPARM_GREEN ] = 1.0f; - steamRenderEntity.shaderParms[ SHADERPARM_BLUE ] = 1.0f; - modelDef = NULL; - temp = spawnArgs.GetString ( "model_steam" ); - if ( *temp != '\0' ) { - if ( !strstr( temp, "." ) ) { - modelDef = static_cast( declManager->FindType( DECL_MODELDEF, temp, false ) ); - if ( modelDef ) { - steamRenderEntity.hModel = modelDef->ModelHandle(); - } - } - - if ( !steamRenderEntity.hModel ) { - steamRenderEntity.hModel = renderModelManager->FindModel( temp ); - } - - if ( steamRenderEntity.hModel ) { - steamRenderEntity.bounds = steamRenderEntity.hModel->Bounds( &steamRenderEntity ); - } else { - steamRenderEntity.bounds.Zero(); - } - steamRenderEntity.origin = af.GetPhysics()->GetOrigin( steamBody ); - steamRenderEntity.axis = af.GetPhysics()->GetAxis( steamBody ); - steamModelDefHandle = gameRenderWorld->AddEntityDef( &steamRenderEntity ); - } -} - -/* -================ -idAFEntity_SteamPipe::Think -================ -*/ -void idAFEntity_SteamPipe::Think( void ) { - idVec3 steamDir; - - if ( thinkFlags & TH_THINK ) { - steamDir.x = gameLocal.random.CRandomFloat() * steamForce; - steamDir.y = gameLocal.random.CRandomFloat() * steamForce; - steamDir.z = steamUpForce; - force.SetForce( steamDir ); - force.Evaluate( gameLocal.time ); - //gameRenderWorld->DebugArrow( colorWhite, af.GetPhysics()->GetOrigin( steamBody ), af.GetPhysics()->GetOrigin( steamBody ) - 10.0f * steamDir, 4 ); - } - - if ( steamModelDefHandle >= 0 ){ - steamRenderEntity.origin = af.GetPhysics()->GetOrigin( steamBody ); - steamRenderEntity.axis = af.GetPhysics()->GetAxis( steamBody ); - gameRenderWorld->UpdateEntityDef( steamModelDefHandle, &steamRenderEntity ); - } - - idAFEntity_Base::Think(); -} - - -/* -=============================================================================== - - idAFEntity_ClawFourFingers - -=============================================================================== -*/ - -const idEventDef EV_SetFingerAngle( "setFingerAngle", "f" ); -const idEventDef EV_StopFingers( "stopFingers" ); - -CLASS_DECLARATION( idAFEntity_Base, idAFEntity_ClawFourFingers ) - EVENT( EV_SetFingerAngle, idAFEntity_ClawFourFingers::Event_SetFingerAngle ) - EVENT( EV_StopFingers, idAFEntity_ClawFourFingers::Event_StopFingers ) -END_CLASS - -static const char *clawConstraintNames[] = { - "claw1", "claw2", "claw3", "claw4" -}; - -/* -================ -idAFEntity_ClawFourFingers::idAFEntity_ClawFourFingers -================ -*/ -idAFEntity_ClawFourFingers::idAFEntity_ClawFourFingers( void ) { - fingers[0] = NULL; - fingers[1] = NULL; - fingers[2] = NULL; - fingers[3] = NULL; -} - -/* -================ -idAFEntity_ClawFourFingers::Save -================ -*/ -void idAFEntity_ClawFourFingers::Save( idSaveGame *savefile ) const { - int i; - - for ( i = 0; i < 4; i++ ) { - fingers[i]->Save( savefile ); - } -} - -/* -================ -idAFEntity_ClawFourFingers::Restore -================ -*/ -void idAFEntity_ClawFourFingers::Restore( idRestoreGame *savefile ) { - int i; - - for ( i = 0; i < 4; i++ ) { - fingers[i] = static_cast(af.GetPhysics()->GetConstraint( clawConstraintNames[i] )); - fingers[i]->Restore( savefile ); - } - - SetCombatModel(); - LinkCombat(); -} - -/* -================ -idAFEntity_ClawFourFingers::Spawn -================ -*/ -void idAFEntity_ClawFourFingers::Spawn( void ) { - int i; - - LoadAF(); - - SetCombatModel(); - - af.GetPhysics()->LockWorldConstraints( true ); - af.GetPhysics()->SetForcePushable( true ); - SetPhysics( af.GetPhysics() ); - - fl.takedamage = true; - - for ( i = 0; i < 4; i++ ) { - fingers[i] = static_cast(af.GetPhysics()->GetConstraint( clawConstraintNames[i] )); - if ( !fingers[i] ) { - gameLocal.Error( "idClaw_FourFingers '%s': can't find claw constraint '%s'", name.c_str(), clawConstraintNames[i] ); - } - } -} - -/* -================ -idAFEntity_ClawFourFingers::Event_SetFingerAngle -================ -*/ -void idAFEntity_ClawFourFingers::Event_SetFingerAngle( float angle ) { - int i; - - for ( i = 0; i < 4; i++ ) { - fingers[i]->SetSteerAngle( angle ); - fingers[i]->SetSteerSpeed( 0.5f ); - } - af.GetPhysics()->Activate(); -} - -/* -================ -idAFEntity_ClawFourFingers::Event_StopFingers -================ -*/ -void idAFEntity_ClawFourFingers::Event_StopFingers( void ) { - int i; - - for ( i = 0; i < 4; i++ ) { - fingers[i]->SetSteerAngle( fingers[i]->GetAngle() ); - } -} - - -/* -=============================================================================== - - editor support routines - -=============================================================================== -*/ - - -/* -================ -idGameEdit::AF_SpawnEntity -================ -*/ -bool idGameEdit::AF_SpawnEntity( const char *fileName ) { - idDict args; - idPlayer *player; - idAFEntity_Generic *ent; - const idDeclAF *af; - idVec3 org; - float yaw; - - player = gameLocal.GetLocalPlayer(); - if ( !player || !gameLocal.CheatsOk( false ) ) { - return false; - } - - af = static_cast( declManager->FindType( DECL_AF, fileName ) ); - if ( !af ) { - return false; - } - - yaw = player->viewAngles.yaw; - args.Set( "angle", va( "%f", yaw + 180 ) ); - org = player->GetPhysics()->GetOrigin() + idAngles( 0, yaw, 0 ).ToForward() * 80 + idVec3( 0, 0, 1 ); - args.Set( "origin", org.ToString() ); - args.Set( "spawnclass", "idAFEntity_Generic" ); - if ( af->model[0] ) { - args.Set( "model", af->model.c_str() ); - } else { - args.Set( "model", fileName ); - } - if ( af->skin[0] ) { - args.Set( "skin", af->skin.c_str() ); - } - args.Set( "articulatedFigure", fileName ); - args.Set( "nodrop", "1" ); - ent = static_cast(gameLocal.SpawnEntityType( idAFEntity_Generic::Type, &args)); - - // always update this entity - ent->BecomeActive( TH_THINK ); - ent->KeepRunningPhysics(); - ent->fl.forcePhysicsUpdate = true; - - player->dragEntity.SetSelected( ent ); - - return true; -} - -/* -================ -idGameEdit::AF_UpdateEntities -================ -*/ -void idGameEdit::AF_UpdateEntities( const char *fileName ) { - idEntity *ent; - idAFEntity_Base *af; - idStr name; - - name = fileName; - name.StripFileExtension(); - - // reload any idAFEntity_Generic which uses the given articulated figure file - for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) { - if ( ent->IsType( idAFEntity_Base::Type ) ) { - af = static_cast(ent); - if ( name.Icmp( af->GetAFName() ) == 0 ) { - af->LoadAF(); - af->GetAFPhysics()->PutToRest(); - } - } - } -} - -/* -================ -idGameEdit::AF_UndoChanges -================ -*/ -void idGameEdit::AF_UndoChanges( void ) { - int i, c; - idEntity *ent; - idAFEntity_Base *af; - idDeclAF *decl; - - c = declManager->GetNumDecls( DECL_AF ); - for ( i = 0; i < c; i++ ) { - decl = static_cast( const_cast( declManager->DeclByIndex( DECL_AF, i, false ) ) ); - if ( !decl->modified ) { - continue; - } - - decl->Invalidate(); - declManager->FindType( DECL_AF, decl->GetName() ); - - // reload all AF entities using the file - for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) { - if ( ent->IsType( idAFEntity_Base::Type ) ) { - af = static_cast(ent); - if ( idStr::Icmp( decl->GetName(), af->GetAFName() ) == 0 ) { - af->LoadAF(); - } - } - } - } -} - -/* -================ -GetJointTransform -================ -*/ -typedef struct { - renderEntity_t *ent; - const idMD5Joint *joints; -} jointTransformData_t; - -static bool GetJointTransform( void *model, const idJointMat *frame, const char *jointName, idVec3 &origin, idMat3 &axis ) { - int i; - jointTransformData_t *data = reinterpret_cast(model); - - for ( i = 0; i < data->ent->numJoints; i++ ) { - if ( data->joints[i].name.Icmp( jointName ) == 0 ) { - break; - } - } - if ( i >= data->ent->numJoints ) { - return false; - } - origin = frame[i].ToVec3(); - axis = frame[i].ToMat3(); - return true; -} - -/* -================ -GetArgString -================ -*/ -static const char *GetArgString( const idDict &args, const idDict *defArgs, const char *key ) { - const char *s; - - s = args.GetString( key ); - if ( !s[0] && defArgs ) { - s = defArgs->GetString( key ); - } - return s; -} - -/* -================ -idGameEdit::AF_CreateMesh -================ -*/ -idRenderModel *idGameEdit::AF_CreateMesh( const idDict &args, idVec3 &meshOrigin, idMat3 &meshAxis, bool &poseIsSet ) { - int i, jointNum; - const idDeclAF *af; - const idDeclAF_Body *fb; - renderEntity_t ent; - idVec3 origin, *bodyOrigin, *newBodyOrigin, *modifiedOrigin; - idMat3 axis, *bodyAxis, *newBodyAxis, *modifiedAxis; - declAFJointMod_t *jointMod; - idAngles angles; - const idDict *defArgs; - const idKeyValue *arg; - idStr name; - jointTransformData_t data; - const char *classname, *afName, *modelName; - idRenderModel *md5; - const idDeclModelDef *modelDef; - const idMD5Anim *MD5anim; - const idMD5Joint *MD5joint; - const idMD5Joint *MD5joints; - int numMD5joints; - idJointMat *originalJoints; - int parentNum; - - poseIsSet = false; - meshOrigin.Zero(); - meshAxis.Identity(); - - classname = args.GetString( "classname" ); - defArgs = gameLocal.FindEntityDefDict( classname ); - - // get the articulated figure - afName = GetArgString( args, defArgs, "articulatedFigure" ); - af = static_cast( declManager->FindType( DECL_AF, afName ) ); - if ( !af ) { - return NULL; - } - - // get the md5 model - modelName = GetArgString( args, defArgs, "model" ); - modelDef = static_cast< const idDeclModelDef *>( declManager->FindType( DECL_MODELDEF, modelName, false ) ); - if ( !modelDef ) { - return NULL; - } - - // make sure model hasn't been purged - if ( modelDef->ModelHandle() && !modelDef->ModelHandle()->IsLoaded() ) { - modelDef->ModelHandle()->LoadModel(); - } - - // get the md5 - md5 = modelDef->ModelHandle(); - if ( !md5 || md5->IsDefaultModel() ) { - return NULL; - } - - // get the articulated figure pose anim - int animNum = modelDef->GetAnim( "af_pose" ); - if ( !animNum ) { - return NULL; - } - const idAnim *anim = modelDef->GetAnim( animNum ); - if ( !anim ) { - return NULL; - } - MD5anim = anim->MD5Anim( 0 ); - MD5joints = md5->GetJoints(); - numMD5joints = md5->NumJoints(); - - // setup a render entity - memset( &ent, 0, sizeof( ent ) ); - ent.customSkin = modelDef->GetSkin(); - ent.bounds.Clear(); - ent.numJoints = numMD5joints; - ent.joints = ( idJointMat * )_alloca16( ent.numJoints * sizeof( *ent.joints ) ); - - // create animation from of the af_pose - ANIM_CreateAnimFrame( md5, MD5anim, ent.numJoints, ent.joints, 1, modelDef->GetVisualOffset(), false ); - - // buffers to store the initial origin and axis for each body - bodyOrigin = (idVec3 *) _alloca16( af->bodies.Num() * sizeof( idVec3 ) ); - bodyAxis = (idMat3 *) _alloca16( af->bodies.Num() * sizeof( idMat3 ) ); - newBodyOrigin = (idVec3 *) _alloca16( af->bodies.Num() * sizeof( idVec3 ) ); - newBodyAxis = (idMat3 *) _alloca16( af->bodies.Num() * sizeof( idMat3 ) ); - - // finish the AF positions - data.ent = &ent; - data.joints = MD5joints; - af->Finish( GetJointTransform, ent.joints, &data ); - - // get the initial origin and axis for each AF body - for ( i = 0; i < af->bodies.Num(); i++ ) { - fb = af->bodies[i]; - - if ( fb->modelType == TRM_BONE ) { - // axis of bone trace model - axis[2] = fb->v2.ToVec3() - fb->v1.ToVec3(); - axis[2].Normalize(); - axis[2].NormalVectors( axis[0], axis[1] ); - axis[1] = -axis[1]; - } else { - axis = fb->angles.ToMat3(); - } - - newBodyOrigin[i] = bodyOrigin[i] = fb->origin.ToVec3(); - newBodyAxis[i] = bodyAxis[i] = axis; - } - - // get any new body transforms stored in the key/value pairs - for ( arg = args.MatchPrefix( "body ", NULL ); arg; arg = args.MatchPrefix( "body ", arg ) ) { - name = arg->GetKey(); - name.Strip( "body " ); - for ( i = 0; i < af->bodies.Num(); i++ ) { - fb = af->bodies[i]; - if ( fb->name.Icmp( name ) == 0 ) { - break; - } - } - if ( i >= af->bodies.Num() ) { - continue; - } - sscanf( arg->GetValue(), "%f %f %f %f %f %f", &origin.x, &origin.y, &origin.z, &angles.pitch, &angles.yaw, &angles.roll ); - - if ( fb->jointName.Icmp( "origin" ) == 0 ) { - meshAxis = bodyAxis[i].Transpose() * angles.ToMat3(); - meshOrigin = origin - bodyOrigin[i] * meshAxis; - poseIsSet = true; - } else { - newBodyOrigin[i] = origin; - newBodyAxis[i] = angles.ToMat3(); - } - } - - // save the original joints - originalJoints = ( idJointMat * )_alloca16( numMD5joints * sizeof( originalJoints[0] ) ); - memcpy( originalJoints, ent.joints, numMD5joints * sizeof( originalJoints[0] ) ); - - // buffer to store the joint mods - jointMod = (declAFJointMod_t *) _alloca16( numMD5joints * sizeof( declAFJointMod_t ) ); - memset( jointMod, -1, numMD5joints * sizeof( declAFJointMod_t ) ); - modifiedOrigin = (idVec3 *) _alloca16( numMD5joints * sizeof( idVec3 ) ); - memset( modifiedOrigin, 0, numMD5joints * sizeof( idVec3 ) ); - modifiedAxis = (idMat3 *) _alloca16( numMD5joints * sizeof( idMat3 ) ); - memset( modifiedAxis, 0, numMD5joints * sizeof( idMat3 ) ); - - // get all the joint modifications - for ( i = 0; i < af->bodies.Num(); i++ ) { - fb = af->bodies[i]; - - if ( fb->jointName.Icmp( "origin" ) == 0 ) { - continue; - } - - for ( jointNum = 0; jointNum < numMD5joints; jointNum++ ) { - if ( MD5joints[jointNum].name.Icmp( fb->jointName ) == 0 ) { - break; - } - } - - if ( jointNum >= 0 && jointNum < ent.numJoints ) { - jointMod[ jointNum ] = fb->jointMod; - modifiedAxis[ jointNum ] = ( bodyAxis[i] * originalJoints[jointNum].ToMat3().Transpose() ).Transpose() * ( newBodyAxis[i] * meshAxis.Transpose() ); - // FIXME: calculate correct modifiedOrigin - modifiedOrigin[ jointNum ] = originalJoints[ jointNum ].ToVec3(); - } - } - - // apply joint modifications to the skeleton - MD5joint = MD5joints + 1; - for( i = 1; i < numMD5joints; i++, MD5joint++ ) { - - parentNum = MD5joint->parent - MD5joints; - idMat3 parentAxis = originalJoints[ parentNum ].ToMat3(); - idMat3 localm = originalJoints[i].ToMat3() * parentAxis.Transpose(); - idVec3 localt = ( originalJoints[i].ToVec3() - originalJoints[ parentNum ].ToVec3() ) * parentAxis.Transpose(); - - switch( jointMod[i] ) { - case DECLAF_JOINTMOD_ORIGIN: { - ent.joints[ i ].SetRotation( localm * ent.joints[ parentNum ].ToMat3() ); - ent.joints[ i ].SetTranslation( modifiedOrigin[ i ] ); - break; - } - case DECLAF_JOINTMOD_AXIS: { - ent.joints[ i ].SetRotation( modifiedAxis[ i ] ); - ent.joints[ i ].SetTranslation( ent.joints[ parentNum ].ToVec3() + localt * ent.joints[ parentNum ].ToMat3() ); - break; - } - case DECLAF_JOINTMOD_BOTH: { - ent.joints[ i ].SetRotation( modifiedAxis[ i ] ); - ent.joints[ i ].SetTranslation( modifiedOrigin[ i ] ); - break; - } - default: { - ent.joints[ i ].SetRotation( localm * ent.joints[ parentNum ].ToMat3() ); - ent.joints[ i ].SetTranslation( ent.joints[ parentNum ].ToVec3() + localt * ent.joints[ parentNum ].ToMat3() ); - break; - } - } - } - - // instantiate a mesh using the joint information from the render entity - return md5->InstantiateDynamicModel( &ent, NULL, NULL ); -} - -#ifdef _D3XP - -/* -=============================================================================== -idHarvestable -=============================================================================== -*/ - -const idEventDef EV_Harvest_SpawnHarvestTrigger( "", NULL ); - -CLASS_DECLARATION( idEntity, idHarvestable ) -EVENT( EV_Harvest_SpawnHarvestTrigger, idHarvestable::Event_SpawnHarvestTrigger ) -EVENT( EV_Touch, idHarvestable::Event_Touch ) -END_CLASS - -idHarvestable::idHarvestable() { - trigger = NULL; - parentEnt = NULL; -} - -idHarvestable::~idHarvestable() { - if ( trigger ) { - delete trigger; - trigger = NULL; - } -} - -void idHarvestable::Spawn() { - - startTime = 0; - - spawnArgs.GetFloat( "triggersize", "120", triggersize ); - spawnArgs.GetFloat( "give_delay", "3", giveDelay); - giveDelay *= 1000; - given = false; - - removeDelay = spawnArgs.GetFloat( "remove_delay") * 1000.0f; - - fxFollowPlayer = spawnArgs.GetBool("fx_follow_player", "1"); - fxOrient = spawnArgs.GetString("fx_orient"); - - -} - -void idHarvestable::Init(idEntity* parent) { - - assert(parent); - - parentEnt = parent; - - GetPhysics()->SetOrigin( parent->GetPhysics()->GetOrigin() ); - this->Bind(parent, true); - - //Set the skin of the entity to the harvest skin - idStr skin = parent->spawnArgs.GetString("skin_harvest", ""); - if(skin.Length()) { - parent->SetSkin(declManager->FindSkin(skin.c_str())); - } - - idEntity* head = NULL; - if(parent->IsType(idActor::Type)) { - idActor* withHead = (idActor*)parent; - head = withHead->GetHeadEntity(); - } - if(parent->IsType(idAFEntity_WithAttachedHead::Type)) { - idAFEntity_WithAttachedHead* withHead = (idAFEntity_WithAttachedHead*)parent; - head = withHead->head.GetEntity(); - } - if(head) { - idStr headskin = parent->spawnArgs.GetString("skin_harvest_head", ""); - if(headskin.Length()) { - head->SetSkin(declManager->FindSkin(headskin.c_str())); - } - } - - idStr sound = parent->spawnArgs.GetString("harvest_sound"); - if(sound.Length() > 0) { - parent->StartSound( sound.c_str(), SND_CHANNEL_ANY, 0, false, NULL); - } - - - PostEventMS( &EV_Harvest_SpawnHarvestTrigger, 0 ); -} - -void idHarvestable::Save( idSaveGame *savefile ) const { - savefile->WriteFloat( triggersize ); - savefile->WriteClipModel( trigger ); - savefile->WriteFloat( giveDelay ); - savefile->WriteFloat( removeDelay ); - savefile->WriteBool( given ); - - player.Save( savefile ); - savefile->WriteInt( startTime ); - - savefile->WriteBool( fxFollowPlayer ); - fx.Save( savefile ); - savefile->WriteString( fxOrient ); - - parentEnt.Save(savefile); -} - -void idHarvestable::Restore( idRestoreGame *savefile ) { - savefile->ReadFloat( triggersize ); - savefile->ReadClipModel( trigger ); - savefile->ReadFloat( giveDelay ); - savefile->ReadFloat( removeDelay ); - savefile->ReadBool( given ); - - player.Restore( savefile ); - savefile->ReadInt( startTime ); - - savefile->ReadBool( fxFollowPlayer ); - fx.Restore( savefile ); - savefile->ReadString( fxOrient ); - - parentEnt.Restore(savefile); -} - -void idHarvestable::SetParent(idEntity* parent) { - parentEnt = parent; -} - -void idHarvestable::Think() { - - idEntity* parent = parentEnt.GetEntity(); - if(!parent) { - return; - } - - //Update the orientation of the box - if(trigger && parent && !parent->GetPhysics()->IsAtRest()) { - trigger->Link( gameLocal.clip, this, 0, parent->GetPhysics()->GetOrigin(), parent->GetPhysics()->GetAxis()); - } - - if(startTime && gameLocal.slow.time - startTime > giveDelay && ! given) { - idPlayer *thePlayer = player.GetEntity(); - - thePlayer->Give(spawnArgs.GetString("give_item"), spawnArgs.GetString("give_value")); - thePlayer->harvest_lock = false; - given = true; - } - - if(startTime && gameLocal.slow.time - startTime > removeDelay) { - parent->PostEventMS( &EV_Remove, 0 ); - PostEventMS( &EV_Remove, 0 ); - } - - if(fxFollowPlayer) { - idEntityFx* fxEnt = fx.GetEntity(); - - if(fxEnt) { - idMat3 orientAxisLocal; - if(GetFxOrientationAxis(orientAxisLocal)) { - //gameRenderWorld->DebugAxis(fxEnt->GetPhysics()->GetOrigin(), orientAxisLocal); - fxEnt->GetPhysics()->SetAxis(orientAxisLocal); - } - } - } -} - -/* -================ -idAFEntity_Harvest::Gib -Called when the parent object has been gibbed. -================ -*/ -void idHarvestable::Gib() { - //Stop any looping sound that was playing - idEntity* parent = parentEnt.GetEntity(); - if(parent) { - idStr sound = parent->spawnArgs.GetString("harvest_sound"); - if(sound.Length() > 0) { - parent->StopSound(SND_CHANNEL_ANY, false); - } - } -} - -/* -================ -idAFEntity_Harvest::BeginBurn -================ -*/ -void idHarvestable::BeginBurn() { - - idEntity* parent = parentEnt.GetEntity(); - if(!parent) { - return; - } - - if(!spawnArgs.GetBool("burn")) { - return; - } - - - //Switch Skins if the parent would like us to. - idStr skin = parent->spawnArgs.GetString("skin_harvest_burn", ""); - if(skin.Length()) { - parent->SetSkin(declManager->FindSkin(skin.c_str())); - } - parent->GetRenderEntity()->noShadow = true; - parent->SetShaderParm( SHADERPARM_TIME_OF_DEATH, gameLocal.slow.time * 0.001f ); - - idEntity* head = NULL; - if(parent->IsType(idActor::Type)) { - idActor* withHead = (idActor*)parent; - head = withHead->GetHeadEntity(); - } - if(parent->IsType(idAFEntity_WithAttachedHead::Type)) { - idAFEntity_WithAttachedHead* withHead = (idAFEntity_WithAttachedHead*)parent; - head = withHead->head.GetEntity(); - } - if(head) { - idStr headskin = parent->spawnArgs.GetString("skin_harvest_burn_head", ""); - if(headskin.Length()) { - head->SetSkin(declManager->FindSkin(headskin.c_str())); - } - - head->GetRenderEntity()->noShadow = true; - head->SetShaderParm( SHADERPARM_TIME_OF_DEATH, gameLocal.slow.time * 0.001f ); - } - - - -} - -/* -================ -idAFEntity_Harvest::BeginFX -================ -*/ -void idHarvestable::BeginFX() { - if(strlen(spawnArgs.GetString("fx")) <= 0) { - return; - } - - idMat3* orientAxis = NULL; - idMat3 orientAxisLocal; - - if(GetFxOrientationAxis(orientAxisLocal)) { - orientAxis = &orientAxisLocal; - } - fx = idEntityFx::StartFx( spawnArgs.GetString("fx"), NULL, orientAxis, this, spawnArgs.GetBool("fx_bind") ); -} - -/* -================ -idAFEntity_Harvest::CalcTriggerBounds -================ -*/ -void idHarvestable::CalcTriggerBounds( float size, idBounds &bounds ) { - - idEntity* parent = parentEnt.GetEntity(); - if(!parent) { - return; - } - - //Simple trigger bounds is the absolute bounds of the AF plus a defined size - bounds = parent->GetPhysics()->GetAbsBounds(); - bounds.ExpandSelf(size); - bounds[0] -= parent->GetPhysics()->GetOrigin(); - bounds[1] -= parent->GetPhysics()->GetOrigin(); -} - -bool idHarvestable::GetFxOrientationAxis(idMat3& mat) { - - idEntity* parent = parentEnt.GetEntity(); - if(!parent) { - return false; - } - - idPlayer *thePlayer = player.GetEntity(); - - if(!fxOrient.Icmp("up")) { - //Orient up - idVec3 grav = parent->GetPhysics()->GetGravityNormal()*-1; - idVec3 left, up; - - grav.OrthogonalBasis(left, up); - idMat3 temp(left.x, left.y, left.z, up.x, up.y, up.z, grav.x, grav.y, grav.z); - mat = temp; - - return true; - - } else if(!fxOrient.Icmp("weapon")) { - //Orient the fx towards the muzzle of the weapon - jointHandle_t joint; - idVec3 joint_origin; - idMat3 joint_axis; - - joint = thePlayer->weapon.GetEntity()->GetAnimator()->GetJointHandle( spawnArgs.GetString("fx_weapon_joint") ); - if ( joint != INVALID_JOINT ) { - thePlayer->weapon.GetEntity()->GetJointWorldTransform( joint, gameLocal.slow.time, joint_origin, joint_axis ); - } else { - joint_origin = thePlayer->GetPhysics()->GetOrigin(); - } - - idVec3 toPlayer = joint_origin-parent->GetPhysics()->GetOrigin(); - toPlayer.NormalizeFast(); - - idVec3 left, up; - toPlayer.OrthogonalBasis(left, up); - idMat3 temp(left.x, left.y, left.z, up.x, up.y, up.z, toPlayer.x, toPlayer.y, toPlayer.z); - mat = temp; - - return true; - - } else if(!fxOrient.Icmp("player")) { - //Orient the fx towards the eye of the player - idVec3 eye = thePlayer->GetEyePosition(); - idVec3 toPlayer = eye-parent->GetPhysics()->GetOrigin(); - - toPlayer.Normalize(); - - idVec3 left, up; - up.Set(0, 1, 0); - left = toPlayer.Cross(up); - up = left.Cross(toPlayer); - - - //common->Printf("%.2f %.2f %.2f - %.2f %.2f %.2f - %.2f %.2f %.2f\n", toPlayer.x, toPlayer.y, toPlayer.z, left.x, left.y, left.z, up.x, up.y, up.z ); - - idMat3 temp(left.x, left.y, left.z, up.x, up.y, up.z, toPlayer.x, toPlayer.y, toPlayer.z); - - mat = temp; - - return true; - } - - //Returning false indicates that the orientation is not used; - return false; -} - -/* -================ -idAFEntity_Harvest::Event_SpawnHarvestTrigger -================ -*/ -void idHarvestable::Event_SpawnHarvestTrigger( void ) { - idBounds bounds; - - idEntity* parent = parentEnt.GetEntity(); - if(!parent) { - return; - } - - CalcTriggerBounds( triggersize, bounds ); - - // create a trigger clip model - trigger = new idClipModel( idTraceModel( bounds ) ); - trigger->Link( gameLocal.clip, this, 255, parent->GetPhysics()->GetOrigin(), mat3_identity); - trigger->SetContents( CONTENTS_TRIGGER ); - - startTime = 0; -} - -/* -================ -idAFEntity_Harvest::Event_Touch -================ -*/ -void idHarvestable::Event_Touch( idEntity *other, trace_t *trace ) { - - idEntity* parent = parentEnt.GetEntity(); - if(!parent) { - return; - } - if(parent->IsType(idAFEntity_Gibbable::Type)) { - idAFEntity_Gibbable* gibParent = (idAFEntity_Gibbable*)parent; - if(gibParent->IsGibbed()) - return; - } - - - if(!startTime && other && other->IsType(idPlayer::Type)) { - idPlayer *thePlayer = static_cast(other); - - if(thePlayer->harvest_lock) { - //Don't harvest if the player is in mid harvest - return; - } - - player = thePlayer; - - bool okToGive = true; - idStr requiredWeapons = spawnArgs.GetString("required_weapons"); - - if(requiredWeapons.Length() > 0) { - idStr playerWeap = thePlayer->GetCurrentWeapon(); - if(playerWeap.Length() == 0 || requiredWeapons.Find(playerWeap, false) == -1) { - okToGive = false; - } - } - - if(okToGive) { - if(thePlayer->CanGive(spawnArgs.GetString("give_item"), spawnArgs.GetString("give_value"))) { - - startTime = gameLocal.slow.time; - - //Lock the player from harvesting to prevent multiple harvests when only one is needed - thePlayer->harvest_lock = true; - - idWeapon* weap = (idWeapon*)thePlayer->weapon.GetEntity(); - if(weap) { - //weap->PostEventMS(&EV_Weapon_State, 0, "Charge", 8); - weap->ProcessEvent(&EV_Weapon_State, "Charge", 8); - } - - BeginBurn(); - BeginFX(); - - //Stop any looping sound that was playing - idStr sound = parent->spawnArgs.GetString("harvest_sound"); - if(sound.Length() > 0) { - parent->StopSound(SND_CHANNEL_ANY, false); - } - - //Make the parent object non-solid - parent->GetPhysics()->SetContents( 0 ); - parent->GetPhysics()->GetClipModel()->Unlink(); - - //Turn of the trigger so it doesn't process twice - trigger->SetContents( 0 ); - } - } - } -} - - -/* -=============================================================================== - -idAFEntity_Harvest - -=============================================================================== -*/ - -const idEventDef EV_Harvest_SpawnHarvestEntity( "", NULL ); - -CLASS_DECLARATION( idAFEntity_WithAttachedHead, idAFEntity_Harvest ) -EVENT( EV_Harvest_SpawnHarvestEntity, idAFEntity_Harvest::Event_SpawnHarvestEntity ) -END_CLASS - -/* -================ -idAFEntity_Harvest::idAFEntity_Harvest -================ -*/ -idAFEntity_Harvest::idAFEntity_Harvest() { - harvestEnt = NULL; -} - -/* -================ -idAFEntity_Harvest::~idAFEntity_Harvest -================ -*/ -idAFEntity_Harvest::~idAFEntity_Harvest() { - - if ( harvestEnt.GetEntity() ) { - harvestEnt.GetEntity()->PostEventMS( &EV_Remove, 0 ); - } - -} - -/* -================ -idAFEntity_Harvest::Save -================ -*/ -void idAFEntity_Harvest::Save( idSaveGame *savefile ) const { - harvestEnt.Save(savefile); -} - -/* -================ -idAFEntity_Harvest::Restore -================ -*/ -void idAFEntity_Harvest::Restore( idRestoreGame *savefile ) { - harvestEnt.Restore(savefile); - //if(harvestEnt.GetEntity()) { - // harvestEnt.GetEntity()->SetParent(this); - //} -} - -/* -================ -idAFEntity_Harvest::Spawn -================ -*/ -void idAFEntity_Harvest::Spawn( void ) { - - PostEventMS( &EV_Harvest_SpawnHarvestEntity, 0 ); -} - -/* -================ -idAFEntity_Harvest::Think -================ -*/ -void idAFEntity_Harvest::Think( void ) { - - idAFEntity_WithAttachedHead::Think(); - -} - -void idAFEntity_Harvest::Event_SpawnHarvestEntity( void ) { - - const idDict *harvestDef = gameLocal.FindEntityDefDict( spawnArgs.GetString("def_harvest_type"), false ); - if ( harvestDef ) { - idEntity *temp; - gameLocal.SpawnEntityDef( *harvestDef, &temp, false ); - harvestEnt = static_cast(temp); - } - - if(harvestEnt.GetEntity()) { - //Let the harvest entity set itself up - harvestEnt.GetEntity()->Init(this); - harvestEnt.GetEntity()->BecomeActive( TH_THINK ); - } -} - -void idAFEntity_Harvest::Gib( const idVec3 &dir, const char *damageDefName ) { - if(harvestEnt.GetEntity()) { - //Let the harvest ent know that we gibbed - harvestEnt.GetEntity()->Gib(); - } - idAFEntity_WithAttachedHead::Gib(dir, damageDefName); -} - -#endif diff --git a/d3xp/AFEntity.h b/d3xp/AFEntity.h deleted file mode 100644 index a63dda9a..00000000 --- a/d3xp/AFEntity.h +++ /dev/null @@ -1,616 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __GAME_AFENTITY_H__ -#define __GAME_AFENTITY_H__ - -#include "physics/Physics_AF.h" -#include "physics/Force_Constant.h" -#include "Entity.h" -#include "AF.h" - -/* -=============================================================================== - -idMultiModelAF - -Entity using multiple separate visual models animated with a single -articulated figure. Only used for debugging! - -=============================================================================== -*/ -const int GIB_DELAY = 200; // only gib this often to keep performace hits when blowing up several mobs - -class idMultiModelAF : public idEntity { -public: - CLASS_PROTOTYPE( idMultiModelAF ); - - void Spawn( void ); - ~idMultiModelAF( void ); - - virtual void Think( void ); - virtual void Present( void ); - -protected: - idPhysics_AF physicsObj; - - void SetModelForId( int id, const idStr &modelName ); - -private: - idList modelHandles; - idList modelDefHandles; -}; - - -/* -=============================================================================== - -idChain - -Chain hanging down from the ceiling. Only used for debugging! - -=============================================================================== -*/ - -class idChain : public idMultiModelAF { -public: - CLASS_PROTOTYPE( idChain ); - - void Spawn( void ); - -protected: - void BuildChain( const idStr &name, const idVec3 &origin, float linkLength, float linkWidth, float density, int numLinks, bool bindToWorld = true ); -}; - - -/* -=============================================================================== - -idAFAttachment - -=============================================================================== -*/ - -class idAFAttachment : public idAnimatedEntity { -public: - CLASS_PROTOTYPE( idAFAttachment ); - - idAFAttachment( void ); - virtual ~idAFAttachment( void ); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void SetBody( idEntity *bodyEnt, const char *headModel, jointHandle_t attachJoint ); - void ClearBody( void ); - idEntity * GetBody( void ) const; - - virtual void Think( void ); - - virtual void Hide( void ); - virtual void Show( void ); - - void PlayIdleAnim( int blendTime ); - - virtual void GetImpactInfo( idEntity *ent, int id, const idVec3 &point, impactInfo_t *info ); - virtual void ApplyImpulse( idEntity *ent, int id, const idVec3 &point, const idVec3 &impulse ); - virtual void AddForce( idEntity *ent, int id, const idVec3 &point, const idVec3 &force ); - - virtual void Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location ); - virtual void AddDamageEffect( const trace_t &collision, const idVec3 &velocity, const char *damageDefName ); - - void SetCombatModel( void ); - idClipModel * GetCombatModel( void ) const; - virtual void LinkCombat( void ); - virtual void UnlinkCombat( void ); - -protected: - idEntity * body; - idClipModel * combatModel; // render model for hit detection of head - int idleAnim; - jointHandle_t attachJoint; -}; - - -/* -=============================================================================== - -idAFEntity_Base - -=============================================================================== -*/ - -class idAFEntity_Base : public idAnimatedEntity { -public: - CLASS_PROTOTYPE( idAFEntity_Base ); - - idAFEntity_Base( void ); - virtual ~idAFEntity_Base( void ); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - virtual void Think( void ); - virtual void GetImpactInfo( idEntity *ent, int id, const idVec3 &point, impactInfo_t *info ); - virtual void ApplyImpulse( idEntity *ent, int id, const idVec3 &point, const idVec3 &impulse ); - virtual void AddForce( idEntity *ent, int id, const idVec3 &point, const idVec3 &force ); - virtual bool Collide( const trace_t &collision, const idVec3 &velocity ); - virtual bool GetPhysicsToVisualTransform( idVec3 &origin, idMat3 &axis ); - virtual bool UpdateAnimationControllers( void ); - virtual void FreeModelDef( void ); - - virtual bool LoadAF( void ); - bool IsActiveAF( void ) const { return af.IsActive(); } - const char * GetAFName( void ) const { return af.GetName(); } - idPhysics_AF * GetAFPhysics( void ) { return af.GetPhysics(); } - - void SetCombatModel( void ); - idClipModel * GetCombatModel( void ) const; - // contents of combatModel can be set to 0 or re-enabled (mp) - void SetCombatContents( bool enable ); - virtual void LinkCombat( void ); - virtual void UnlinkCombat( void ); - - int BodyForClipModelId( int id ) const; - - void SaveState( idDict &args ) const; - void LoadState( const idDict &args ); - - void AddBindConstraints( void ); - void RemoveBindConstraints( void ); - - virtual void ShowEditingDialog( void ); - - static void DropAFs( idEntity *ent, const char *type, idList *list ); - -protected: - idAF af; // articulated figure - idClipModel * combatModel; // render model for hit detection - int combatModelContents; - idVec3 spawnOrigin; // spawn origin - idMat3 spawnAxis; // rotation axis used when spawned - int nextSoundTime; // next time this can make a sound - - void Event_SetConstraintPosition( const char *name, const idVec3 &pos ); -}; - -/* -=============================================================================== - -idAFEntity_Gibbable - -=============================================================================== -*/ - -extern const idEventDef EV_Gib; -extern const idEventDef EV_Gibbed; - -class idAFEntity_Gibbable : public idAFEntity_Base { -public: - CLASS_PROTOTYPE( idAFEntity_Gibbable ); - - idAFEntity_Gibbable( void ); - ~idAFEntity_Gibbable( void ); - - void Spawn( void ); - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - virtual void Present( void ); - virtual void Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location ); -#ifdef _D3XP - void SetThrown( bool isThrown ); - virtual bool Collide( const trace_t &collision, const idVec3 &velocity ); -#endif - virtual void SpawnGibs( const idVec3 &dir, const char *damageDefName ); - -#ifdef _D3XP - bool IsGibbed() { return gibbed; }; -#endif - -protected: - idRenderModel * skeletonModel; - int skeletonModelDefHandle; - bool gibbed; - -#ifdef _D3XP - bool wasThrown; -#endif - - virtual void Gib( const idVec3 &dir, const char *damageDefName ); - void InitSkeletonModel( void ); - - void Event_Gib( const char *damageDefName ); -}; - -/* -=============================================================================== - - idAFEntity_Generic - -=============================================================================== -*/ - -class idAFEntity_Generic : public idAFEntity_Gibbable { -public: - CLASS_PROTOTYPE( idAFEntity_Generic ); - - idAFEntity_Generic( void ); - ~idAFEntity_Generic( void ); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - virtual void Think( void ); - void KeepRunningPhysics( void ) { keepRunningPhysics = true; } - -private: - void Event_Activate( idEntity *activator ); - - bool keepRunningPhysics; -}; - - -/* -=============================================================================== - -idAFEntity_WithAttachedHead - -=============================================================================== -*/ - -class idAFEntity_WithAttachedHead : public idAFEntity_Gibbable { -public: - CLASS_PROTOTYPE( idAFEntity_WithAttachedHead ); - - idAFEntity_WithAttachedHead(); - ~idAFEntity_WithAttachedHead(); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void SetupHead( void ); - - virtual void Think( void ); - - virtual void Hide( void ); - virtual void Show( void ); - virtual void ProjectOverlay( const idVec3 &origin, const idVec3 &dir, float size, const char *material ); - - virtual void LinkCombat( void ); - virtual void UnlinkCombat( void ); - -protected: - virtual void Gib( const idVec3 &dir, const char *damageDefName ); - -#ifndef _D3XP -private: -#else -public: -#endif - idEntityPtr head; - - void Event_Gib( const char *damageDefName ); - void Event_Activate( idEntity *activator ); -}; - - -/* -=============================================================================== - -idAFEntity_Vehicle - -=============================================================================== -*/ - -class idAFEntity_Vehicle : public idAFEntity_Base { -public: - CLASS_PROTOTYPE( idAFEntity_Vehicle ); - - idAFEntity_Vehicle( void ); - - void Spawn( void ); - void Use( idPlayer *player ); - -protected: - idPlayer * player; - jointHandle_t eyesJoint; - jointHandle_t steeringWheelJoint; - float wheelRadius; - float steerAngle; - float steerSpeed; - const idDeclParticle * dustSmoke; - - float GetSteerAngle( void ); -}; - - -/* -=============================================================================== - -idAFEntity_VehicleSimple - -=============================================================================== -*/ - -class idAFEntity_VehicleSimple : public idAFEntity_Vehicle { -public: - CLASS_PROTOTYPE( idAFEntity_VehicleSimple ); - - idAFEntity_VehicleSimple( void ); - ~idAFEntity_VehicleSimple( void ); - - void Spawn( void ); - virtual void Think( void ); - -protected: - idClipModel * wheelModel; - idAFConstraint_Suspension * suspension[4]; - jointHandle_t wheelJoints[4]; - float wheelAngles[4]; -}; - - -/* -=============================================================================== - -idAFEntity_VehicleFourWheels - -=============================================================================== -*/ - -class idAFEntity_VehicleFourWheels : public idAFEntity_Vehicle { -public: - CLASS_PROTOTYPE( idAFEntity_VehicleFourWheels ); - - idAFEntity_VehicleFourWheels( void ); - - void Spawn( void ); - virtual void Think( void ); - -protected: - idAFBody * wheels[4]; - idAFConstraint_Hinge * steering[2]; - jointHandle_t wheelJoints[4]; - float wheelAngles[4]; -}; - - -/* -=============================================================================== - -idAFEntity_VehicleSixWheels - -=============================================================================== -*/ - -class idAFEntity_VehicleSixWheels : public idAFEntity_Vehicle { -public: - CLASS_PROTOTYPE( idAFEntity_VehicleSixWheels ); - - idAFEntity_VehicleSixWheels( void ); - - void Spawn( void ); - virtual void Think( void ); - -#ifdef _D3XP - float force; - float velocity; - float steerAngle; -#endif - -private: - idAFBody * wheels[6]; - idAFConstraint_Hinge * steering[4]; - jointHandle_t wheelJoints[6]; - float wheelAngles[6]; -}; - -#ifdef _D3XP -/* -=============================================================================== - -idAFEntity_VehicleAutomated - -=============================================================================== -*/ - -class idAFEntity_VehicleAutomated : public idAFEntity_VehicleSixWheels { -public: - CLASS_PROTOTYPE( idAFEntity_VehicleAutomated ); - - void Spawn( void ); - void PostSpawn( void ); - virtual void Think( void ); - -private: - - idEntity *waypoint; - float steeringSpeed; - float currentSteering; - float idealSteering; - float originHeight; - - void Event_SetVelocity( float _velocity ); - void Event_SetTorque( float _torque ); - void Event_SetSteeringSpeed( float _steeringSpeed ); - void Event_SetWayPoint( idEntity *_waypoint ); -}; -#endif - -/* -=============================================================================== - -idAFEntity_SteamPipe - -=============================================================================== -*/ - -class idAFEntity_SteamPipe : public idAFEntity_Base { -public: - CLASS_PROTOTYPE( idAFEntity_SteamPipe ); - - idAFEntity_SteamPipe( void ); - ~idAFEntity_SteamPipe( void ); - - void Spawn( void ); - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - virtual void Think( void ); - -private: - int steamBody; - float steamForce; - float steamUpForce; - idForce_Constant force; - renderEntity_t steamRenderEntity; - qhandle_t steamModelDefHandle; - - void InitSteamRenderEntity( void ); -}; - - -/* -=============================================================================== - -idAFEntity_ClawFourFingers - -=============================================================================== -*/ - -class idAFEntity_ClawFourFingers : public idAFEntity_Base { -public: - CLASS_PROTOTYPE( idAFEntity_ClawFourFingers ); - - idAFEntity_ClawFourFingers( void ); - - void Spawn( void ); - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - -private: - idAFConstraint_Hinge * fingers[4]; - - void Event_SetFingerAngle( float angle ); - void Event_StopFingers( void ); -}; - -#ifdef _D3XP - -/** -* idHarvestable contains all of the code required to turn an entity into a harvestable -* entity. The entity must create an instance of this class and call the appropriate -* interface methods at the correct time. -*/ -class idHarvestable : public idEntity { -public: - CLASS_PROTOTYPE( idHarvestable ); - - idHarvestable(); - ~idHarvestable(); - - void Spawn(); - void Init(idEntity* parent); - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void SetParent(idEntity* parent); - - void Think(); - void Gib(); - -protected: - idEntityPtr parentEnt; - float triggersize; - idClipModel * trigger; - float giveDelay; - float removeDelay; - bool given; - - idEntityPtr player; - int startTime; - - bool fxFollowPlayer; - idEntityPtr fx; - idStr fxOrient; - -protected: - void BeginBurn(); - void BeginFX(); - void CalcTriggerBounds( float size, idBounds &bounds ); - - bool GetFxOrientationAxis(idMat3& mat); - - void Event_SpawnHarvestTrigger( void ); - void Event_Touch( idEntity *other, trace_t *trace ); -} ; - - -/* -=============================================================================== - -idAFEntity_Harvest - -=============================================================================== -*/ - - - -class idAFEntity_Harvest : public idAFEntity_WithAttachedHead { -public: - CLASS_PROTOTYPE( idAFEntity_Harvest ); - - idAFEntity_Harvest(); - ~idAFEntity_Harvest(); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - virtual void Think( void ); - - virtual void Gib( const idVec3 &dir, const char *damageDefName ); - -protected: - idEntityPtr harvestEnt; -protected: - void Event_SpawnHarvestEntity( void ); - -}; -#endif - -#endif /* !__GAME_AFENTITY_H__ */ diff --git a/d3xp/Actor.cpp b/d3xp/Actor.cpp deleted file mode 100644 index 39cec391..00000000 --- a/d3xp/Actor.cpp +++ /dev/null @@ -1,3405 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "gamesys/SysCvar.h" -#include "script/Script_Thread.h" -#include "Item.h" -#include "Light.h" -#include "Projectile.h" -#include "WorldSpawn.h" - -#include "Actor.h" - - -/*********************************************************************** - - idAnimState - -***********************************************************************/ - -/* -===================== -idAnimState::idAnimState -===================== -*/ -idAnimState::idAnimState() { - self = NULL; - animator = NULL; - thread = NULL; - idleAnim = true; - disabled = true; - channel = ANIMCHANNEL_ALL; - animBlendFrames = 0; - lastAnimBlendFrames = 0; -} - -/* -===================== -idAnimState::~idAnimState -===================== -*/ -idAnimState::~idAnimState() { - delete thread; -} - -/* -===================== -idAnimState::Save -===================== -*/ -void idAnimState::Save( idSaveGame *savefile ) const { - - savefile->WriteObject( self ); - - // Save the entity owner of the animator - savefile->WriteObject( animator->GetEntity() ); - - savefile->WriteObject( thread ); - - savefile->WriteString( state ); - - savefile->WriteInt( animBlendFrames ); - savefile->WriteInt( lastAnimBlendFrames ); - savefile->WriteInt( channel ); - savefile->WriteBool( idleAnim ); - savefile->WriteBool( disabled ); -} - -/* -===================== -idAnimState::Restore -===================== -*/ -void idAnimState::Restore( idRestoreGame *savefile ) { - savefile->ReadObject( reinterpret_cast( self ) ); - - idEntity *animowner; - savefile->ReadObject( reinterpret_cast( animowner ) ); - if ( animowner ) { - animator = animowner->GetAnimator(); - } - - savefile->ReadObject( reinterpret_cast( thread ) ); - - savefile->ReadString( state ); - - savefile->ReadInt( animBlendFrames ); - savefile->ReadInt( lastAnimBlendFrames ); - savefile->ReadInt( channel ); - savefile->ReadBool( idleAnim ); - savefile->ReadBool( disabled ); -} - -/* -===================== -idAnimState::Init -===================== -*/ -void idAnimState::Init( idActor *owner, idAnimator *_animator, int animchannel ) { - assert( owner ); - assert( _animator ); - self = owner; - animator = _animator; - channel = animchannel; - - if ( !thread ) { - thread = new idThread(); - thread->ManualDelete(); - } - thread->EndThread(); - thread->ManualControl(); -} - -/* -===================== -idAnimState::Shutdown -===================== -*/ -void idAnimState::Shutdown( void ) { - delete thread; - thread = NULL; -} - -/* -===================== -idAnimState::SetState -===================== -*/ -void idAnimState::SetState( const char *statename, int blendFrames ) { - const function_t *func; - - func = self->scriptObject.GetFunction( statename ); - if ( !func ) { - assert( 0 ); - gameLocal.Error( "Can't find function '%s' in object '%s'", statename, self->scriptObject.GetTypeName() ); - } - - state = statename; - disabled = false; - animBlendFrames = blendFrames; - lastAnimBlendFrames = blendFrames; - thread->CallFunction( self, func, true ); - - animBlendFrames = blendFrames; - lastAnimBlendFrames = blendFrames; - disabled = false; - idleAnim = false; - - if ( ai_debugScript.GetInteger() == self->entityNumber ) { - gameLocal.Printf( "%d: %s: Animstate: %s\n", gameLocal.time, self->name.c_str(), state.c_str() ); - } -} - -/* -===================== -idAnimState::StopAnim -===================== -*/ -void idAnimState::StopAnim( int frames ) { - animBlendFrames = 0; - animator->Clear( channel, gameLocal.time, FRAME2MS( frames ) ); -} - -/* -===================== -idAnimState::PlayAnim -===================== -*/ -void idAnimState::PlayAnim( int anim ) { - if ( anim ) { - animator->PlayAnim( channel, anim, gameLocal.time, FRAME2MS( animBlendFrames ) ); - } - animBlendFrames = 0; -} - -/* -===================== -idAnimState::CycleAnim -===================== -*/ -void idAnimState::CycleAnim( int anim ) { - if ( anim ) { - animator->CycleAnim( channel, anim, gameLocal.time, FRAME2MS( animBlendFrames ) ); - } - animBlendFrames = 0; -} - -/* -===================== -idAnimState::BecomeIdle -===================== -*/ -void idAnimState::BecomeIdle( void ) { - idleAnim = true; -} - -/* -===================== -idAnimState::Disabled -===================== -*/ -bool idAnimState::Disabled( void ) const { - return disabled; -} - -/* -===================== -idAnimState::AnimDone -===================== -*/ -bool idAnimState::AnimDone( int blendFrames ) const { - int animDoneTime; - - animDoneTime = animator->CurrentAnim( channel )->GetEndTime(); - if ( animDoneTime < 0 ) { - // playing a cycle - return false; - } else if ( animDoneTime - FRAME2MS( blendFrames ) <= gameLocal.time ) { - return true; - } else { - return false; - } -} - -/* -===================== -idAnimState::IsIdle -===================== -*/ -bool idAnimState::IsIdle( void ) const { - return disabled || idleAnim; -} - -/* -===================== -idAnimState::GetAnimFlags -===================== -*/ -animFlags_t idAnimState::GetAnimFlags( void ) const { - animFlags_t flags; - - memset( &flags, 0, sizeof( flags ) ); - if ( !disabled && !AnimDone( 0 ) ) { - flags = animator->GetAnimFlags( animator->CurrentAnim( channel )->AnimNum() ); - } - - return flags; -} - -/* -===================== -idAnimState::Enable -===================== -*/ -void idAnimState::Enable( int blendFrames ) { - if ( disabled ) { - disabled = false; - animBlendFrames = blendFrames; - lastAnimBlendFrames = blendFrames; - if ( state.Length() ) { - SetState( state.c_str(), blendFrames ); - } - } -} - -/* -===================== -idAnimState::Disable -===================== -*/ -void idAnimState::Disable( void ) { - disabled = true; - idleAnim = false; -} - -/* -===================== -idAnimState::UpdateState -===================== -*/ -bool idAnimState::UpdateState( void ) { - if ( disabled ) { - return false; - } - - if ( ai_debugScript.GetInteger() == self->entityNumber ) { - thread->EnableDebugInfo(); - } else { - thread->DisableDebugInfo(); - } - - thread->Execute(); - - return true; -} - -/*********************************************************************** - - idActor - -***********************************************************************/ - -const idEventDef AI_EnableEyeFocus( "enableEyeFocus" ); -const idEventDef AI_DisableEyeFocus( "disableEyeFocus" ); -const idEventDef EV_Footstep( "footstep" ); -const idEventDef EV_FootstepLeft( "leftFoot" ); -const idEventDef EV_FootstepRight( "rightFoot" ); -const idEventDef EV_EnableWalkIK( "EnableWalkIK" ); -const idEventDef EV_DisableWalkIK( "DisableWalkIK" ); -const idEventDef EV_EnableLegIK( "EnableLegIK", "d" ); -const idEventDef EV_DisableLegIK( "DisableLegIK", "d" ); -const idEventDef AI_StopAnim( "stopAnim", "dd" ); -const idEventDef AI_PlayAnim( "playAnim", "ds", 'd' ); -const idEventDef AI_PlayCycle( "playCycle", "ds", 'd' ); -const idEventDef AI_IdleAnim( "idleAnim", "ds", 'd' ); -const idEventDef AI_SetSyncedAnimWeight( "setSyncedAnimWeight", "ddf" ); -const idEventDef AI_SetBlendFrames( "setBlendFrames", "dd" ); -const idEventDef AI_GetBlendFrames( "getBlendFrames", "d", 'd' ); -const idEventDef AI_AnimState( "animState", "dsd" ); -const idEventDef AI_GetAnimState( "getAnimState", "d", 's' ); -const idEventDef AI_InAnimState( "inAnimState", "ds", 'd' ); -const idEventDef AI_FinishAction( "finishAction", "s" ); -const idEventDef AI_AnimDone( "animDone", "dd", 'd' ); -const idEventDef AI_OverrideAnim( "overrideAnim", "d" ); -const idEventDef AI_EnableAnim( "enableAnim", "dd" ); -const idEventDef AI_PreventPain( "preventPain", "f" ); -const idEventDef AI_DisablePain( "disablePain" ); -const idEventDef AI_EnablePain( "enablePain" ); -const idEventDef AI_GetPainAnim( "getPainAnim", NULL, 's' ); -const idEventDef AI_SetAnimPrefix( "setAnimPrefix", "s" ); -const idEventDef AI_HasAnim( "hasAnim", "ds", 'f' ); -const idEventDef AI_CheckAnim( "checkAnim", "ds" ); -const idEventDef AI_ChooseAnim( "chooseAnim", "ds", 's' ); -const idEventDef AI_AnimLength( "animLength", "ds", 'f' ); -const idEventDef AI_AnimDistance( "animDistance", "ds", 'f' ); -const idEventDef AI_HasEnemies( "hasEnemies", NULL, 'd' ); -const idEventDef AI_NextEnemy( "nextEnemy", "E", 'e' ); -const idEventDef AI_ClosestEnemyToPoint( "closestEnemyToPoint", "v", 'e' ); -const idEventDef AI_SetNextState( "setNextState", "s" ); -const idEventDef AI_SetState( "setState", "s" ); -const idEventDef AI_GetState( "getState", NULL, 's' ); -const idEventDef AI_GetHead( "getHead", NULL, 'e' ); -#ifdef _D3XP -const idEventDef EV_SetDamageGroupScale( "setDamageGroupScale", "sf" ); -const idEventDef EV_SetDamageGroupScaleAll( "setDamageGroupScaleAll", "f" ); -const idEventDef EV_GetDamageGroupScale( "getDamageGroupScale", "s", 'f' ); -const idEventDef EV_SetDamageCap( "setDamageCap", "f" ); -const idEventDef EV_SetWaitState( "setWaitState" , "s" ); -const idEventDef EV_GetWaitState( "getWaitState", NULL, 's' ); -#endif - -CLASS_DECLARATION( idAFEntity_Gibbable, idActor ) - EVENT( AI_EnableEyeFocus, idActor::Event_EnableEyeFocus ) - EVENT( AI_DisableEyeFocus, idActor::Event_DisableEyeFocus ) - EVENT( EV_Footstep, idActor::Event_Footstep ) - EVENT( EV_FootstepLeft, idActor::Event_Footstep ) - EVENT( EV_FootstepRight, idActor::Event_Footstep ) - EVENT( EV_EnableWalkIK, idActor::Event_EnableWalkIK ) - EVENT( EV_DisableWalkIK, idActor::Event_DisableWalkIK ) - EVENT( EV_EnableLegIK, idActor::Event_EnableLegIK ) - EVENT( EV_DisableLegIK, idActor::Event_DisableLegIK ) - EVENT( AI_PreventPain, idActor::Event_PreventPain ) - EVENT( AI_DisablePain, idActor::Event_DisablePain ) - EVENT( AI_EnablePain, idActor::Event_EnablePain ) - EVENT( AI_GetPainAnim, idActor::Event_GetPainAnim ) - EVENT( AI_SetAnimPrefix, idActor::Event_SetAnimPrefix ) - EVENT( AI_StopAnim, idActor::Event_StopAnim ) - EVENT( AI_PlayAnim, idActor::Event_PlayAnim ) - EVENT( AI_PlayCycle, idActor::Event_PlayCycle ) - EVENT( AI_IdleAnim, idActor::Event_IdleAnim ) - EVENT( AI_SetSyncedAnimWeight, idActor::Event_SetSyncedAnimWeight ) - EVENT( AI_SetBlendFrames, idActor::Event_SetBlendFrames ) - EVENT( AI_GetBlendFrames, idActor::Event_GetBlendFrames ) - EVENT( AI_AnimState, idActor::Event_AnimState ) - EVENT( AI_GetAnimState, idActor::Event_GetAnimState ) - EVENT( AI_InAnimState, idActor::Event_InAnimState ) - EVENT( AI_FinishAction, idActor::Event_FinishAction ) - EVENT( AI_AnimDone, idActor::Event_AnimDone ) - EVENT( AI_OverrideAnim, idActor::Event_OverrideAnim ) - EVENT( AI_EnableAnim, idActor::Event_EnableAnim ) - EVENT( AI_HasAnim, idActor::Event_HasAnim ) - EVENT( AI_CheckAnim, idActor::Event_CheckAnim ) - EVENT( AI_ChooseAnim, idActor::Event_ChooseAnim ) - EVENT( AI_AnimLength, idActor::Event_AnimLength ) - EVENT( AI_AnimDistance, idActor::Event_AnimDistance ) - EVENT( AI_HasEnemies, idActor::Event_HasEnemies ) - EVENT( AI_NextEnemy, idActor::Event_NextEnemy ) - EVENT( AI_ClosestEnemyToPoint, idActor::Event_ClosestEnemyToPoint ) - EVENT( EV_StopSound, idActor::Event_StopSound ) - EVENT( AI_SetNextState, idActor::Event_SetNextState ) - EVENT( AI_SetState, idActor::Event_SetState ) - EVENT( AI_GetState, idActor::Event_GetState ) - EVENT( AI_GetHead, idActor::Event_GetHead ) -#ifdef _D3XP - EVENT( EV_SetDamageGroupScale, idActor::Event_SetDamageGroupScale ) - EVENT( EV_SetDamageGroupScaleAll, idActor::Event_SetDamageGroupScaleAll ) - EVENT( EV_GetDamageGroupScale, idActor::Event_GetDamageGroupScale ) - EVENT( EV_SetDamageCap, idActor::Event_SetDamageCap ) - EVENT( EV_SetWaitState, idActor::Event_SetWaitState ) - EVENT( EV_GetWaitState, idActor::Event_GetWaitState ) -#endif -END_CLASS - -/* -===================== -idActor::idActor -===================== -*/ -idActor::idActor( void ) { - viewAxis.Identity(); - - scriptThread = NULL; // initialized by ConstructScriptObject, which is called by idEntity::Spawn - - use_combat_bbox = false; - head = NULL; - - team = 0; - rank = 0; - fovDot = 0.0f; - eyeOffset.Zero(); - pain_debounce_time = 0; - pain_delay = 0; - pain_threshold = 0; - - state = NULL; - idealState = NULL; - - leftEyeJoint = INVALID_JOINT; - rightEyeJoint = INVALID_JOINT; - soundJoint = INVALID_JOINT; - - modelOffset.Zero(); - deltaViewAngles.Zero(); - - painTime = 0; - allowPain = false; - allowEyeFocus = false; - - waitState = ""; - - blink_anim = 0; - blink_time = 0; - blink_min = 0; - blink_max = 0; - - finalBoss = false; - - attachments.SetGranularity( 1 ); - - enemyNode.SetOwner( this ); - enemyList.SetOwner( this ); - -#ifdef _D3XP - damageCap = -1; -#endif -} - -/* -===================== -idActor::~idActor -===================== -*/ -idActor::~idActor( void ) { - int i; - idEntity *ent; - - DeconstructScriptObject(); - scriptObject.Free(); - - StopSound( SND_CHANNEL_ANY, false ); - - delete combatModel; - combatModel = NULL; - - if ( head.GetEntity() ) { - head.GetEntity()->ClearBody(); - head.GetEntity()->PostEventMS( &EV_Remove, 0 ); - } - - // remove any attached entities - for( i = 0; i < attachments.Num(); i++ ) { - ent = attachments[ i ].ent.GetEntity(); - if ( ent ) { - ent->PostEventMS( &EV_Remove, 0 ); - } - } - - ShutdownThreads(); -} - -/* -===================== -idActor::Spawn -===================== -*/ -void idActor::Spawn( void ) { - idEntity *ent; - idStr jointName; - float fovDegrees; - copyJoints_t copyJoint; - - animPrefix = ""; - state = NULL; - idealState = NULL; - - spawnArgs.GetInt( "rank", "0", rank ); - spawnArgs.GetInt( "team", "0", team ); - spawnArgs.GetVector( "offsetModel", "0 0 0", modelOffset ); - - spawnArgs.GetBool( "use_combat_bbox", "0", use_combat_bbox ); - - viewAxis = GetPhysics()->GetAxis(); - - spawnArgs.GetFloat( "fov", "90", fovDegrees ); - SetFOV( fovDegrees ); - - pain_debounce_time = 0; - - pain_delay = SEC2MS( spawnArgs.GetFloat( "pain_delay" ) ); - pain_threshold = spawnArgs.GetInt( "pain_threshold" ); - - LoadAF(); - - walkIK.Init( this, IK_ANIM, modelOffset ); - - // the animation used to be set to the IK_ANIM at this point, but that was fixed, resulting in - // attachments not binding correctly, so we're stuck setting the IK_ANIM before attaching things. - animator.ClearAllAnims( gameLocal.time, 0 ); - animator.SetFrame( ANIMCHANNEL_ALL, animator.GetAnim( IK_ANIM ), 0, 0, 0 ); - - // spawn any attachments we might have - const idKeyValue *kv = spawnArgs.MatchPrefix( "def_attach", NULL ); - while ( kv ) { - idDict args; - - args.Set( "classname", kv->GetValue().c_str() ); - - // make items non-touchable so the player can't take them out of the character's hands - args.Set( "no_touch", "1" ); - - // don't let them drop to the floor - args.Set( "dropToFloor", "0" ); - - gameLocal.SpawnEntityDef( args, &ent ); - if ( !ent ) { - gameLocal.Error( "Couldn't spawn '%s' to attach to entity '%s'", kv->GetValue().c_str(), name.c_str() ); - } else { - Attach( ent ); - } - kv = spawnArgs.MatchPrefix( "def_attach", kv ); - } - - SetupDamageGroups(); - SetupHead(); - - // clear the bind anim - animator.ClearAllAnims( gameLocal.time, 0 ); - - idEntity *headEnt = head.GetEntity(); - idAnimator *headAnimator; - if ( headEnt ) { - headAnimator = headEnt->GetAnimator(); - } else { - headAnimator = &animator; - } - - if ( headEnt ) { - // set up the list of joints to copy to the head - for( kv = spawnArgs.MatchPrefix( "copy_joint", NULL ); kv != NULL; kv = spawnArgs.MatchPrefix( "copy_joint", kv ) ) { - if ( kv->GetValue() == "" ) { - // probably clearing out inherited key, so skip it - continue; - } - - jointName = kv->GetKey(); - if ( jointName.StripLeadingOnce( "copy_joint_world " ) ) { - copyJoint.mod = JOINTMOD_WORLD_OVERRIDE; - } else { - jointName.StripLeadingOnce( "copy_joint " ); - copyJoint.mod = JOINTMOD_LOCAL_OVERRIDE; - } - - copyJoint.from = animator.GetJointHandle( jointName ); - if ( copyJoint.from == INVALID_JOINT ) { - gameLocal.Warning( "Unknown copy_joint '%s' on entity %s", jointName.c_str(), name.c_str() ); - continue; - } - - jointName = kv->GetValue(); - copyJoint.to = headAnimator->GetJointHandle( jointName ); - if ( copyJoint.to == INVALID_JOINT ) { - gameLocal.Warning( "Unknown copy_joint '%s' on head of entity %s", jointName.c_str(), name.c_str() ); - continue; - } - - copyJoints.Append( copyJoint ); - } - } - - // set up blinking - blink_anim = headAnimator->GetAnim( "blink" ); - blink_time = 0; // it's ok to blink right away - blink_min = SEC2MS( spawnArgs.GetFloat( "blink_min", "0.5" ) ); - blink_max = SEC2MS( spawnArgs.GetFloat( "blink_max", "8" ) ); - - // set up the head anim if necessary - int headAnim = headAnimator->GetAnim( "def_head" ); - if ( headAnim ) { - if ( headEnt ) { - headAnimator->CycleAnim( ANIMCHANNEL_ALL, headAnim, gameLocal.time, 0 ); - } else { - headAnimator->CycleAnim( ANIMCHANNEL_HEAD, headAnim, gameLocal.time, 0 ); - } - } - - if ( spawnArgs.GetString( "sound_bone", "", jointName ) ) { - soundJoint = animator.GetJointHandle( jointName ); - if ( soundJoint == INVALID_JOINT ) { - gameLocal.Warning( "idAnimated '%s' at (%s): cannot find joint '%s' for sound playback", name.c_str(), GetPhysics()->GetOrigin().ToString(0), jointName.c_str() ); - } - } - - finalBoss = spawnArgs.GetBool( "finalBoss" ); - - FinishSetup(); -} - -/* -================ -idActor::FinishSetup -================ -*/ -void idActor::FinishSetup( void ) { - const char *scriptObjectName; - - // setup script object - if ( spawnArgs.GetString( "scriptobject", NULL, &scriptObjectName ) ) { - if ( !scriptObject.SetType( scriptObjectName ) ) { - gameLocal.Error( "Script object '%s' not found on entity '%s'.", scriptObjectName, name.c_str() ); - } - - ConstructScriptObject(); - } - - SetupBody(); -} - -/* -================ -idActor::SetupHead -================ -*/ -void idActor::SetupHead( void ) { - idAFAttachment *headEnt; - idStr jointName; - const char *headModel; - jointHandle_t joint; - jointHandle_t damageJoint; - int i; - const idKeyValue *sndKV; - - if ( gameLocal.isClient ) { - return; - } - - headModel = spawnArgs.GetString( "def_head", "" ); - if ( headModel[ 0 ] ) { - jointName = spawnArgs.GetString( "head_joint" ); - joint = animator.GetJointHandle( jointName ); - if ( joint == INVALID_JOINT ) { - gameLocal.Error( "Joint '%s' not found for 'head_joint' on '%s'", jointName.c_str(), name.c_str() ); - } - - // set the damage joint to be part of the head damage group - damageJoint = joint; - for( i = 0; i < damageGroups.Num(); i++ ) { - if ( damageGroups[ i ] == "head" ) { - damageJoint = static_cast( i ); - break; - } - } - - // copy any sounds in case we have frame commands on the head - idDict args; - sndKV = spawnArgs.MatchPrefix( "snd_", NULL ); - while( sndKV ) { - args.Set( sndKV->GetKey(), sndKV->GetValue() ); - sndKV = spawnArgs.MatchPrefix( "snd_", sndKV ); - } - -#ifdef _D3XP - // copy slowmo param to the head - args.SetBool( "slowmo", spawnArgs.GetBool("slowmo", "1") ); -#endif - - - headEnt = static_cast( gameLocal.SpawnEntityType( idAFAttachment::Type, &args ) ); - headEnt->SetName( va( "%s_head", name.c_str() ) ); - headEnt->SetBody( this, headModel, damageJoint ); - head = headEnt; - -#ifdef _D3XP - idStr xSkin; - if ( spawnArgs.GetString( "skin_head_xray", "", xSkin ) ) { - headEnt->xraySkin = declManager->FindSkin( xSkin.c_str() ); - headEnt->UpdateModel(); - } -#endif - - idVec3 origin; - idMat3 axis; - idAttachInfo &attach = attachments.Alloc(); - attach.channel = animator.GetChannelForJoint( joint ); - animator.GetJointTransform( joint, gameLocal.time, origin, axis ); - origin = renderEntity.origin + ( origin + modelOffset ) * renderEntity.axis; - attach.ent = headEnt; - headEnt->SetOrigin( origin ); - headEnt->SetAxis( renderEntity.axis ); - headEnt->BindToJoint( this, joint, true ); - } -} - -/* -================ -idActor::CopyJointsFromBodyToHead -================ -*/ -void idActor::CopyJointsFromBodyToHead( void ) { - idEntity *headEnt = head.GetEntity(); - idAnimator *headAnimator; - int i; - idMat3 mat; - idMat3 axis; - idVec3 pos; - - if ( !headEnt ) { - return; - } - - headAnimator = headEnt->GetAnimator(); - - // copy the animation from the body to the head - for( i = 0; i < copyJoints.Num(); i++ ) { - if ( copyJoints[ i ].mod == JOINTMOD_WORLD_OVERRIDE ) { - mat = headEnt->GetPhysics()->GetAxis().Transpose(); - GetJointWorldTransform( copyJoints[ i ].from, gameLocal.time, pos, axis ); - pos -= headEnt->GetPhysics()->GetOrigin(); - headAnimator->SetJointPos( copyJoints[ i ].to, copyJoints[ i ].mod, pos * mat ); - headAnimator->SetJointAxis( copyJoints[ i ].to, copyJoints[ i ].mod, axis * mat ); - } else { - animator.GetJointLocalTransform( copyJoints[ i ].from, gameLocal.time, pos, axis ); - headAnimator->SetJointPos( copyJoints[ i ].to, copyJoints[ i ].mod, pos ); - headAnimator->SetJointAxis( copyJoints[ i ].to, copyJoints[ i ].mod, axis ); - } - } -} - -/* -================ -idActor::Restart -================ -*/ -void idActor::Restart( void ) { - assert( !head.GetEntity() ); - SetupHead(); - FinishSetup(); -} - -/* -================ -idActor::Save - -archive object for savegame file -================ -*/ -void idActor::Save( idSaveGame *savefile ) const { - idActor *ent; - int i; - - savefile->WriteInt( team ); - savefile->WriteInt( rank ); - savefile->WriteMat3( viewAxis ); - - savefile->WriteInt( enemyList.Num() ); - for ( ent = enemyList.Next(); ent != NULL; ent = ent->enemyNode.Next() ) { - savefile->WriteObject( ent ); - } - - savefile->WriteFloat( fovDot ); - savefile->WriteVec3( eyeOffset ); - savefile->WriteVec3( modelOffset ); - savefile->WriteAngles( deltaViewAngles ); - - savefile->WriteInt( pain_debounce_time ); - savefile->WriteInt( pain_delay ); - savefile->WriteInt( pain_threshold ); - - savefile->WriteInt( damageGroups.Num() ); - for( i = 0; i < damageGroups.Num(); i++ ) { - savefile->WriteString( damageGroups[ i ] ); - } - - savefile->WriteInt( damageScale.Num() ); - for( i = 0; i < damageScale.Num(); i++ ) { - savefile->WriteFloat( damageScale[ i ] ); - } - - savefile->WriteBool( use_combat_bbox ); - head.Save( savefile ); - - savefile->WriteInt( copyJoints.Num() ); - for( i = 0; i < copyJoints.Num(); i++ ) { - savefile->WriteInt( copyJoints[i].mod ); - savefile->WriteJoint( copyJoints[i].from ); - savefile->WriteJoint( copyJoints[i].to ); - } - - savefile->WriteJoint( leftEyeJoint ); - savefile->WriteJoint( rightEyeJoint ); - savefile->WriteJoint( soundJoint ); - - walkIK.Save( savefile ); - - savefile->WriteString( animPrefix ); - savefile->WriteString( painAnim ); - - savefile->WriteInt( blink_anim ); - savefile->WriteInt( blink_time ); - savefile->WriteInt( blink_min ); - savefile->WriteInt( blink_max ); - - // script variables - savefile->WriteObject( scriptThread ); - - savefile->WriteString( waitState ); - - headAnim.Save( savefile ); - torsoAnim.Save( savefile ); - legsAnim.Save( savefile ); - - savefile->WriteBool( allowPain ); - savefile->WriteBool( allowEyeFocus ); - - savefile->WriteInt( painTime ); - - savefile->WriteInt( attachments.Num() ); - for ( i = 0; i < attachments.Num(); i++ ) { - attachments[i].ent.Save( savefile ); - savefile->WriteInt( attachments[i].channel ); - } - - savefile->WriteBool( finalBoss ); - - idToken token; - - //FIXME: this is unneccesary - if ( state ) { - idLexer src( state->Name(), idStr::Length( state->Name() ), "idAI::Save" ); - - src.ReadTokenOnLine( &token ); - src.ExpectTokenString( "::" ); - src.ReadTokenOnLine( &token ); - - savefile->WriteString( token ); - } else { - savefile->WriteString( "" ); - } - - if ( idealState ) { - idLexer src( idealState->Name(), idStr::Length( idealState->Name() ), "idAI::Save" ); - - src.ReadTokenOnLine( &token ); - src.ExpectTokenString( "::" ); - src.ReadTokenOnLine( &token ); - - savefile->WriteString( token ); - } else { - savefile->WriteString( "" ); - } - -#ifdef _D3XP - savefile->WriteInt(damageCap); -#endif - -} - -/* -================ -idActor::Restore - -unarchives object from save game file -================ -*/ -void idActor::Restore( idRestoreGame *savefile ) { - int i, num; - idActor *ent; - - savefile->ReadInt( team ); - savefile->ReadInt( rank ); - savefile->ReadMat3( viewAxis ); - - savefile->ReadInt( num ); - for ( i = 0; i < num; i++ ) { - savefile->ReadObject( reinterpret_cast( ent ) ); - assert( ent ); - if ( ent ) { - ent->enemyNode.AddToEnd( enemyList ); - } - } - - savefile->ReadFloat( fovDot ); - savefile->ReadVec3( eyeOffset ); - savefile->ReadVec3( modelOffset ); - savefile->ReadAngles( deltaViewAngles ); - - savefile->ReadInt( pain_debounce_time ); - savefile->ReadInt( pain_delay ); - savefile->ReadInt( pain_threshold ); - - savefile->ReadInt( num ); - damageGroups.SetGranularity( 1 ); - damageGroups.SetNum( num ); - for( i = 0; i < num; i++ ) { - savefile->ReadString( damageGroups[ i ] ); - } - - savefile->ReadInt( num ); - damageScale.SetNum( num ); - for( i = 0; i < num; i++ ) { - savefile->ReadFloat( damageScale[ i ] ); - } - - savefile->ReadBool( use_combat_bbox ); - head.Restore( savefile ); - - savefile->ReadInt( num ); - copyJoints.SetNum( num ); - for( i = 0; i < num; i++ ) { - int val; - savefile->ReadInt( val ); - copyJoints[i].mod = static_cast( val ); - savefile->ReadJoint( copyJoints[i].from ); - savefile->ReadJoint( copyJoints[i].to ); - } - - savefile->ReadJoint( leftEyeJoint ); - savefile->ReadJoint( rightEyeJoint ); - savefile->ReadJoint( soundJoint ); - - walkIK.Restore( savefile ); - - savefile->ReadString( animPrefix ); - savefile->ReadString( painAnim ); - - savefile->ReadInt( blink_anim ); - savefile->ReadInt( blink_time ); - savefile->ReadInt( blink_min ); - savefile->ReadInt( blink_max ); - - savefile->ReadObject( reinterpret_cast( scriptThread ) ); - - savefile->ReadString( waitState ); - - headAnim.Restore( savefile ); - torsoAnim.Restore( savefile ); - legsAnim.Restore( savefile ); - - savefile->ReadBool( allowPain ); - savefile->ReadBool( allowEyeFocus ); - - savefile->ReadInt( painTime ); - - savefile->ReadInt( num ); - for ( i = 0; i < num; i++ ) { - idAttachInfo &attach = attachments.Alloc(); - attach.ent.Restore( savefile ); - savefile->ReadInt( attach.channel ); - } - - savefile->ReadBool( finalBoss ); - - idStr statename; - - savefile->ReadString( statename ); - if ( statename.Length() > 0 ) { - state = GetScriptFunction( statename ); - } - - savefile->ReadString( statename ); - if ( statename.Length() > 0 ) { - idealState = GetScriptFunction( statename ); - } - -#ifdef _D3XP - savefile->ReadInt(damageCap); -#endif -} - -/* -================ -idActor::Hide -================ -*/ -void idActor::Hide( void ) { - idEntity *ent; - idEntity *next; - - idAFEntity_Base::Hide(); - if ( head.GetEntity() ) { - head.GetEntity()->Hide(); - } - - for( ent = GetNextTeamEntity(); ent != NULL; ent = next ) { - next = ent->GetNextTeamEntity(); - if ( ent->GetBindMaster() == this ) { - ent->Hide(); - if ( ent->IsType( idLight::Type ) ) { - static_cast( ent )->Off(); - } - } - } - UnlinkCombat(); -} - -/* -================ -idActor::Show -================ -*/ -void idActor::Show( void ) { - idEntity *ent; - idEntity *next; - - idAFEntity_Base::Show(); - if ( head.GetEntity() ) { - head.GetEntity()->Show(); - } - for( ent = GetNextTeamEntity(); ent != NULL; ent = next ) { - next = ent->GetNextTeamEntity(); - if ( ent->GetBindMaster() == this ) { - ent->Show(); - if ( ent->IsType( idLight::Type ) ) { -#ifdef _D3XP - if(!spawnArgs.GetBool("lights_off", "0")) { - static_cast( ent )->On(); - } -#endif - - - } - } - } - LinkCombat(); -} - -/* -============== -idActor::GetDefaultSurfaceType -============== -*/ -int idActor::GetDefaultSurfaceType( void ) const { - return SURFTYPE_FLESH; -} - -/* -================ -idActor::ProjectOverlay -================ -*/ -void idActor::ProjectOverlay( const idVec3 &origin, const idVec3 &dir, float size, const char *material ) { - idEntity *ent; - idEntity *next; - - idEntity::ProjectOverlay( origin, dir, size, material ); - - for( ent = GetNextTeamEntity(); ent != NULL; ent = next ) { - next = ent->GetNextTeamEntity(); - if ( ent->GetBindMaster() == this ) { - if ( ent->fl.takedamage && ent->spawnArgs.GetBool( "bleed" ) ) { - ent->ProjectOverlay( origin, dir, size, material ); - } - } - } -} - -/* -================ -idActor::LoadAF -================ -*/ -bool idActor::LoadAF( void ) { - idStr fileName; - - if ( !spawnArgs.GetString( "ragdoll", "*unknown*", fileName ) || !fileName.Length() ) { - return false; - } - af.SetAnimator( GetAnimator() ); - return af.Load( this, fileName ); -} - -/* -===================== -idActor::SetupBody -===================== -*/ -void idActor::SetupBody( void ) { - const char *jointname; - - animator.ClearAllAnims( gameLocal.time, 0 ); - animator.ClearAllJoints(); - - idEntity *headEnt = head.GetEntity(); - if ( headEnt ) { - jointname = spawnArgs.GetString( "bone_leftEye" ); - leftEyeJoint = headEnt->GetAnimator()->GetJointHandle( jointname ); - - jointname = spawnArgs.GetString( "bone_rightEye" ); - rightEyeJoint = headEnt->GetAnimator()->GetJointHandle( jointname ); - - // set up the eye height. check if it's specified in the def. - if ( !spawnArgs.GetFloat( "eye_height", "0", eyeOffset.z ) ) { - // if not in the def, then try to base it off the idle animation - int anim = headEnt->GetAnimator()->GetAnim( "idle" ); - if ( anim && ( leftEyeJoint != INVALID_JOINT ) ) { - idVec3 pos; - idMat3 axis; - headEnt->GetAnimator()->PlayAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, 0 ); - headEnt->GetAnimator()->GetJointTransform( leftEyeJoint, gameLocal.time, pos, axis ); - headEnt->GetAnimator()->ClearAllAnims( gameLocal.time, 0 ); - headEnt->GetAnimator()->ForceUpdate(); - pos += headEnt->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin(); - eyeOffset = pos + modelOffset; - } else { - // just base it off the bounding box size - eyeOffset.z = GetPhysics()->GetBounds()[ 1 ].z - 6; - } - } - headAnim.Init( this, headEnt->GetAnimator(), ANIMCHANNEL_ALL ); - } else { - jointname = spawnArgs.GetString( "bone_leftEye" ); - leftEyeJoint = animator.GetJointHandle( jointname ); - - jointname = spawnArgs.GetString( "bone_rightEye" ); - rightEyeJoint = animator.GetJointHandle( jointname ); - - // set up the eye height. check if it's specified in the def. - if ( !spawnArgs.GetFloat( "eye_height", "0", eyeOffset.z ) ) { - // if not in the def, then try to base it off the idle animation - int anim = animator.GetAnim( "idle" ); - if ( anim && ( leftEyeJoint != INVALID_JOINT ) ) { - idVec3 pos; - idMat3 axis; - animator.PlayAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, 0 ); - animator.GetJointTransform( leftEyeJoint, gameLocal.time, pos, axis ); - animator.ClearAllAnims( gameLocal.time, 0 ); - animator.ForceUpdate(); - eyeOffset = pos + modelOffset; - } else { - // just base it off the bounding box size - eyeOffset.z = GetPhysics()->GetBounds()[ 1 ].z - 6; - } - } - headAnim.Init( this, &animator, ANIMCHANNEL_HEAD ); - } - - waitState = ""; - - torsoAnim.Init( this, &animator, ANIMCHANNEL_TORSO ); - legsAnim.Init( this, &animator, ANIMCHANNEL_LEGS ); -} - -/* -===================== -idActor::CheckBlink -===================== -*/ -void idActor::CheckBlink( void ) { - // check if it's time to blink - if ( !blink_anim || ( health <= 0 ) || !allowEyeFocus || ( blink_time > gameLocal.time ) ) { - return; - } - - idEntity *headEnt = head.GetEntity(); - if ( headEnt ) { - headEnt->GetAnimator()->PlayAnim( ANIMCHANNEL_EYELIDS, blink_anim, gameLocal.time, 1 ); - } else { - animator.PlayAnim( ANIMCHANNEL_EYELIDS, blink_anim, gameLocal.time, 1 ); - } - - // set the next blink time - blink_time = gameLocal.time + blink_min + gameLocal.random.RandomFloat() * ( blink_max - blink_min ); -} - -/* -================ -idActor::GetPhysicsToVisualTransform -================ -*/ -bool idActor::GetPhysicsToVisualTransform( idVec3 &origin, idMat3 &axis ) { - if ( af.IsActive() ) { - af.GetPhysicsToVisualTransform( origin, axis ); - return true; - } - origin = modelOffset; - axis = viewAxis; - return true; -} - -/* -================ -idActor::GetPhysicsToSoundTransform -================ -*/ -bool idActor::GetPhysicsToSoundTransform( idVec3 &origin, idMat3 &axis ) { - if ( soundJoint != INVALID_JOINT ) { - animator.GetJointTransform( soundJoint, gameLocal.time, origin, axis ); - origin += modelOffset; - axis = viewAxis; - } else { - origin = GetPhysics()->GetGravityNormal() * -eyeOffset.z; - axis.Identity(); - } - return true; -} - -/*********************************************************************** - - script state management - -***********************************************************************/ - -/* -================ -idActor::ShutdownThreads -================ -*/ -void idActor::ShutdownThreads( void ) { - headAnim.Shutdown(); - torsoAnim.Shutdown(); - legsAnim.Shutdown(); - - if ( scriptThread ) { - scriptThread->EndThread(); - scriptThread->PostEventMS( &EV_Remove, 0 ); - delete scriptThread; - scriptThread = NULL; - } -} - -/* -================ -idActor::ShouldConstructScriptObjectAtSpawn - -Called during idEntity::Spawn to see if it should construct the script object or not. -Overridden by subclasses that need to spawn the script object themselves. -================ -*/ -bool idActor::ShouldConstructScriptObjectAtSpawn( void ) const { - return false; -} - -/* -================ -idActor::ConstructScriptObject - -Called during idEntity::Spawn. Calls the constructor on the script object. -Can be overridden by subclasses when a thread doesn't need to be allocated. -================ -*/ -idThread *idActor::ConstructScriptObject( void ) { - const function_t *constructor; - - // make sure we have a scriptObject - if ( !scriptObject.HasObject() ) { - gameLocal.Error( "No scriptobject set on '%s'. Check the '%s' entityDef.", name.c_str(), GetEntityDefName() ); - } - - if ( !scriptThread ) { - // create script thread - scriptThread = new idThread(); - scriptThread->ManualDelete(); - scriptThread->ManualControl(); - scriptThread->SetThreadName( name.c_str() ); - } else { - scriptThread->EndThread(); - } - - // call script object's constructor - constructor = scriptObject.GetConstructor(); - if ( !constructor ) { - gameLocal.Error( "Missing constructor on '%s' for entity '%s'", scriptObject.GetTypeName(), name.c_str() ); - } - - // init the script object's data - scriptObject.ClearObject(); - - // just set the current function on the script. we'll execute in the subclasses. - scriptThread->CallFunction( this, constructor, true ); - - return scriptThread; -} - -/* -===================== -idActor::GetScriptFunction -===================== -*/ -const function_t *idActor::GetScriptFunction( const char *funcname ) { - const function_t *func; - - func = scriptObject.GetFunction( funcname ); - if ( !func ) { - scriptThread->Error( "Unknown function '%s' in '%s'", funcname, scriptObject.GetTypeName() ); - } - - return func; -} - -/* -===================== -idActor::SetState -===================== -*/ -void idActor::SetState( const function_t *newState ) { - if ( !newState ) { - gameLocal.Error( "idActor::SetState: Null state" ); - } - - if ( ai_debugScript.GetInteger() == entityNumber ) { - gameLocal.Printf( "%d: %s: State: %s\n", gameLocal.time, name.c_str(), newState->Name() ); - } - - state = newState; - idealState = state; - scriptThread->CallFunction( this, state, true ); -} - -/* -===================== -idActor::SetState -===================== -*/ -void idActor::SetState( const char *statename ) { - const function_t *newState; - - newState = GetScriptFunction( statename ); - SetState( newState ); -} - -/* -===================== -idActor::UpdateScript -===================== -*/ -void idActor::UpdateScript( void ) { - int i; - - if ( ai_debugScript.GetInteger() == entityNumber ) { - scriptThread->EnableDebugInfo(); - } else { - scriptThread->DisableDebugInfo(); - } - - // a series of state changes can happen in a single frame. - // this loop limits them in case we've entered an infinite loop. - for( i = 0; i < 20; i++ ) { - if ( idealState != state ) { - SetState( idealState ); - } - - // don't call script until it's done waiting - if ( scriptThread->IsWaiting() ) { - break; - } - - scriptThread->Execute(); - if ( idealState == state ) { - break; - } - } - - if ( i == 20 ) { - scriptThread->Warning( "idActor::UpdateScript: exited loop to prevent lockup" ); - } -} - -/*********************************************************************** - - vision - -***********************************************************************/ - -/* -===================== -idActor::setFov -===================== -*/ -void idActor::SetFOV( float fov ) { - fovDot = (float)cos( DEG2RAD( fov * 0.5f ) ); -} - -/* -===================== -idActor::SetEyeHeight -===================== -*/ -void idActor::SetEyeHeight( float height ) { - eyeOffset.z = height; -} - -/* -===================== -idActor::EyeHeight -===================== -*/ -float idActor::EyeHeight( void ) const { - return eyeOffset.z; -} - -/* -===================== -idActor::EyeOffset -===================== -*/ -idVec3 idActor::EyeOffset( void ) const { - return GetPhysics()->GetGravityNormal() * -eyeOffset.z; -} - -/* -===================== -idActor::GetEyePosition -===================== -*/ -idVec3 idActor::GetEyePosition( void ) const { - return GetPhysics()->GetOrigin() + ( GetPhysics()->GetGravityNormal() * -eyeOffset.z ); -} - -/* -===================== -idActor::GetViewPos -===================== -*/ -void idActor::GetViewPos( idVec3 &origin, idMat3 &axis ) const { - origin = GetEyePosition(); - axis = viewAxis; -} - -/* -===================== -idActor::CheckFOV -===================== -*/ -bool idActor::CheckFOV( const idVec3 &pos ) const { - if ( fovDot == 1.0f ) { - return true; - } - - float dot; - idVec3 delta; - - delta = pos - GetEyePosition(); - - // get our gravity normal - const idVec3 &gravityDir = GetPhysics()->GetGravityNormal(); - - // infinite vertical vision, so project it onto our orientation plane - delta -= gravityDir * ( gravityDir * delta ); - - delta.Normalize(); - dot = viewAxis[ 0 ] * delta; - - return ( dot >= fovDot ); -} - -/* -===================== -idActor::CanSee -===================== -*/ -bool idActor::CanSee( idEntity *ent, bool useFov ) const { - trace_t tr; - idVec3 eye; - idVec3 toPos; - - if ( ent->IsHidden() ) { - return false; - } - - if ( ent->IsType( idActor::Type ) ) { - toPos = ( ( idActor * )ent )->GetEyePosition(); - } else { - toPos = ent->GetPhysics()->GetOrigin(); - } - - if ( useFov && !CheckFOV( toPos ) ) { - return false; - } - - eye = GetEyePosition(); - - gameLocal.clip.TracePoint( tr, eye, toPos, MASK_OPAQUE, this ); - if ( tr.fraction >= 1.0f || ( gameLocal.GetTraceEntity( tr ) == ent ) ) { - return true; - } - - return false; -} - -/* -===================== -idActor::PointVisible -===================== -*/ -bool idActor::PointVisible( const idVec3 &point ) const { - trace_t results; - idVec3 start, end; - - start = GetEyePosition(); - end = point; - end[2] += 1.0f; - - gameLocal.clip.TracePoint( results, start, end, MASK_OPAQUE, this ); - return ( results.fraction >= 1.0f ); -} - -/* -===================== -idActor::GetAIAimTargets - -Returns positions for the AI to aim at. -===================== -*/ -void idActor::GetAIAimTargets( const idVec3 &lastSightPos, idVec3 &headPos, idVec3 &chestPos ) { - headPos = lastSightPos + EyeOffset(); - chestPos = ( headPos + lastSightPos + GetPhysics()->GetBounds().GetCenter() ) * 0.5f; -} - -/* -===================== -idActor::GetRenderView -===================== -*/ -renderView_t *idActor::GetRenderView() { - renderView_t *rv = idEntity::GetRenderView(); - rv->viewaxis = viewAxis; - rv->vieworg = GetEyePosition(); - return rv; -} - -/*********************************************************************** - - Model/Ragdoll - -***********************************************************************/ - -/* -================ -idActor::SetCombatModel -================ -*/ -void idActor::SetCombatModel( void ) { - idAFAttachment *headEnt; - - if ( !use_combat_bbox ) { - if ( combatModel ) { - combatModel->Unlink(); - combatModel->LoadModel( modelDefHandle ); - } else { - combatModel = new idClipModel( modelDefHandle ); - } - - headEnt = head.GetEntity(); - if ( headEnt ) { - headEnt->SetCombatModel(); - } - } -} - -/* -================ -idActor::GetCombatModel -================ -*/ -idClipModel *idActor::GetCombatModel( void ) const { - return combatModel; -} - -/* -================ -idActor::LinkCombat -================ -*/ -void idActor::LinkCombat( void ) { - idAFAttachment *headEnt; - - if ( fl.hidden || use_combat_bbox ) { - return; - } - - if ( combatModel ) { - combatModel->Link( gameLocal.clip, this, 0, renderEntity.origin, renderEntity.axis, modelDefHandle ); - } - headEnt = head.GetEntity(); - if ( headEnt ) { - headEnt->LinkCombat(); - } -} - -/* -================ -idActor::UnlinkCombat -================ -*/ -void idActor::UnlinkCombat( void ) { - idAFAttachment *headEnt; - - if ( combatModel ) { - combatModel->Unlink(); - } - headEnt = head.GetEntity(); - if ( headEnt ) { - headEnt->UnlinkCombat(); - } -} - -/* -================ -idActor::StartRagdoll -================ -*/ -bool idActor::StartRagdoll( void ) { - float slomoStart, slomoEnd; - float jointFrictionDent, jointFrictionDentStart, jointFrictionDentEnd; - float contactFrictionDent, contactFrictionDentStart, contactFrictionDentEnd; - - // if no AF loaded - if ( !af.IsLoaded() ) { - return false; - } - - // if the AF is already active - if ( af.IsActive() ) { - return true; - } - - // disable the monster bounding box - GetPhysics()->DisableClip(); - - // start using the AF - af.StartFromCurrentPose( spawnArgs.GetInt( "velocityTime", "0" ) ); - - slomoStart = MS2SEC( gameLocal.time ) + spawnArgs.GetFloat( "ragdoll_slomoStart", "-1.6" ); - slomoEnd = MS2SEC( gameLocal.time ) + spawnArgs.GetFloat( "ragdoll_slomoEnd", "0.8" ); - - // do the first part of the death in slow motion - af.GetPhysics()->SetTimeScaleRamp( slomoStart, slomoEnd ); - - jointFrictionDent = spawnArgs.GetFloat( "ragdoll_jointFrictionDent", "0.1" ); - jointFrictionDentStart = MS2SEC( gameLocal.time ) + spawnArgs.GetFloat( "ragdoll_jointFrictionStart", "0.2" ); - jointFrictionDentEnd = MS2SEC( gameLocal.time ) + spawnArgs.GetFloat( "ragdoll_jointFrictionEnd", "1.2" ); - - // set joint friction dent - af.GetPhysics()->SetJointFrictionDent( jointFrictionDent, jointFrictionDentStart, jointFrictionDentEnd ); - - contactFrictionDent = spawnArgs.GetFloat( "ragdoll_contactFrictionDent", "0.1" ); - contactFrictionDentStart = MS2SEC( gameLocal.time ) + spawnArgs.GetFloat( "ragdoll_contactFrictionStart", "1.0" ); - contactFrictionDentEnd = MS2SEC( gameLocal.time ) + spawnArgs.GetFloat( "ragdoll_contactFrictionEnd", "2.0" ); - - // set contact friction dent - af.GetPhysics()->SetContactFrictionDent( contactFrictionDent, contactFrictionDentStart, contactFrictionDentEnd ); - - // drop any items the actor is holding - idMoveableItem::DropItems( this, "death", NULL ); - - // drop any articulated figures the actor is holding - idAFEntity_Base::DropAFs( this, "death", NULL ); - - RemoveAttachments(); - - return true; -} - -/* -================ -idActor::StopRagdoll -================ -*/ -void idActor::StopRagdoll( void ) { - if ( af.IsActive() ) { - af.Stop(); - } -} - -/* -================ -idActor::UpdateAnimationControllers -================ -*/ -bool idActor::UpdateAnimationControllers( void ) { - - if ( af.IsActive() ) { - return idAFEntity_Base::UpdateAnimationControllers(); - } else { - animator.ClearAFPose(); - } - - if ( walkIK.IsInitialized() ) { - walkIK.Evaluate(); - return true; - } - - return false; -} - -/* -================ -idActor::RemoveAttachments -================ -*/ -void idActor::RemoveAttachments( void ) { - int i; - idEntity *ent; - - // remove any attached entities - for( i = 0; i < attachments.Num(); i++ ) { - ent = attachments[ i ].ent.GetEntity(); - if ( ent && ent->spawnArgs.GetBool( "remove" ) ) { - ent->PostEventMS( &EV_Remove, 0 ); - } - } -} - -/* -================ -idActor::Attach -================ -*/ -void idActor::Attach( idEntity *ent ) { - idVec3 origin; - idMat3 axis; - jointHandle_t joint; - idStr jointName; - idAttachInfo &attach = attachments.Alloc(); - idAngles angleOffset; - idVec3 originOffset; - - jointName = ent->spawnArgs.GetString( "joint" ); - joint = animator.GetJointHandle( jointName ); - if ( joint == INVALID_JOINT ) { - gameLocal.Error( "Joint '%s' not found for attaching '%s' on '%s'", jointName.c_str(), ent->GetClassname(), name.c_str() ); - } - - angleOffset = ent->spawnArgs.GetAngles( "angles" ); - originOffset = ent->spawnArgs.GetVector( "origin" ); - - attach.channel = animator.GetChannelForJoint( joint ); - GetJointWorldTransform( joint, gameLocal.time, origin, axis ); - attach.ent = ent; - - ent->SetOrigin( origin + originOffset * renderEntity.axis ); - idMat3 rotate = angleOffset.ToMat3(); - idMat3 newAxis = rotate * axis; - ent->SetAxis( newAxis ); - ent->BindToJoint( this, joint, true ); - ent->cinematic = cinematic; -} - -/* -================ -idActor::Teleport -================ -*/ -void idActor::Teleport( const idVec3 &origin, const idAngles &angles, idEntity *destination ) { - GetPhysics()->SetOrigin( origin + idVec3( 0, 0, CM_CLIP_EPSILON ) ); - GetPhysics()->SetLinearVelocity( vec3_origin ); - - viewAxis = angles.ToMat3(); - - UpdateVisuals(); - - if ( !IsHidden() ) { - // kill anything at the new position - gameLocal.KillBox( this ); - } -} - -/* -================ -idActor::GetDeltaViewAngles -================ -*/ -const idAngles &idActor::GetDeltaViewAngles( void ) const { - return deltaViewAngles; -} - -/* -================ -idActor::SetDeltaViewAngles -================ -*/ -void idActor::SetDeltaViewAngles( const idAngles &delta ) { - deltaViewAngles = delta; -} - -/* -================ -idActor::HasEnemies -================ -*/ -bool idActor::HasEnemies( void ) const { - idActor *ent; - - for( ent = enemyList.Next(); ent != NULL; ent = ent->enemyNode.Next() ) { - if ( !ent->fl.hidden ) { - return true; - } - } - - return false; -} - -/* -================ -idActor::ClosestEnemyToPoint -================ -*/ -idActor *idActor::ClosestEnemyToPoint( const idVec3 &pos ) { - idActor *ent; - idActor *bestEnt; - float bestDistSquared; - float distSquared; - idVec3 delta; - - bestDistSquared = idMath::INFINITY; - bestEnt = NULL; - for( ent = enemyList.Next(); ent != NULL; ent = ent->enemyNode.Next() ) { - if ( ent->fl.hidden ) { - continue; - } - delta = ent->GetPhysics()->GetOrigin() - pos; - distSquared = delta.LengthSqr(); - if ( distSquared < bestDistSquared ) { - bestEnt = ent; - bestDistSquared = distSquared; - } - } - - return bestEnt; -} - -/* -================ -idActor::EnemyWithMostHealth -================ -*/ -idActor *idActor::EnemyWithMostHealth() { - idActor *ent; - idActor *bestEnt; - - int most = -9999; - bestEnt = NULL; - for( ent = enemyList.Next(); ent != NULL; ent = ent->enemyNode.Next() ) { - if ( !ent->fl.hidden && ( ent->health > most ) ) { - bestEnt = ent; - most = ent->health; - } - } - return bestEnt; -} - -/* -================ -idActor::OnLadder -================ -*/ -bool idActor::OnLadder( void ) const { - return false; -} - -/* -============== -idActor::GetAASLocation -============== -*/ -void idActor::GetAASLocation( idAAS *aas, idVec3 &pos, int &areaNum ) const { - idVec3 size; - idBounds bounds; - - GetFloorPos( 64.0f, pos ); - if ( !aas ) { - areaNum = 0; - return; - } - - size = aas->GetSettings()->boundingBoxes[0][1]; - bounds[0] = -size; - size.z = 32.0f; - bounds[1] = size; - - areaNum = aas->PointReachableAreaNum( pos, bounds, AREA_REACHABLE_WALK ); - if ( areaNum ) { - aas->PushPointIntoAreaNum( areaNum, pos ); - } -} - -/*********************************************************************** - - animation state - -***********************************************************************/ - -/* -===================== -idActor::SetAnimState -===================== -*/ -void idActor::SetAnimState( int channel, const char *statename, int blendFrames ) { - const function_t *func; - - func = scriptObject.GetFunction( statename ); - if ( !func ) { - assert( 0 ); - gameLocal.Error( "Can't find function '%s' in object '%s'", statename, scriptObject.GetTypeName() ); - } - - switch( channel ) { - case ANIMCHANNEL_HEAD : - headAnim.SetState( statename, blendFrames ); - allowEyeFocus = true; - break; - - case ANIMCHANNEL_TORSO : - torsoAnim.SetState( statename, blendFrames ); - legsAnim.Enable( blendFrames ); - allowPain = true; - allowEyeFocus = true; - break; - - case ANIMCHANNEL_LEGS : - legsAnim.SetState( statename, blendFrames ); - torsoAnim.Enable( blendFrames ); - allowPain = true; - allowEyeFocus = true; - break; - - default: - gameLocal.Error( "idActor::SetAnimState: Unknown anim group" ); - break; - } -} - -/* -===================== -idActor::GetAnimState -===================== -*/ -const char *idActor::GetAnimState( int channel ) const { - switch( channel ) { - case ANIMCHANNEL_HEAD : - return headAnim.state; - break; - - case ANIMCHANNEL_TORSO : - return torsoAnim.state; - break; - - case ANIMCHANNEL_LEGS : - return legsAnim.state; - break; - - default: - gameLocal.Error( "idActor::GetAnimState: Unknown anim group" ); - return NULL; - break; - } -} - -/* -===================== -idActor::InAnimState -===================== -*/ -bool idActor::InAnimState( int channel, const char *statename ) const { - switch( channel ) { - case ANIMCHANNEL_HEAD : - if ( headAnim.state == statename ) { - return true; - } - break; - - case ANIMCHANNEL_TORSO : - if ( torsoAnim.state == statename ) { - return true; - } - break; - - case ANIMCHANNEL_LEGS : - if ( legsAnim.state == statename ) { - return true; - } - break; - - default: - gameLocal.Error( "idActor::InAnimState: Unknown anim group" ); - break; - } - - return false; -} - -/* -===================== -idActor::WaitState -===================== -*/ -const char *idActor::WaitState( void ) const { - if ( waitState.Length() ) { - return waitState; - } else { - return NULL; - } -} - -/* -===================== -idActor::SetWaitState -===================== -*/ -void idActor::SetWaitState( const char *_waitstate ) { - waitState = _waitstate; -} - -/* -===================== -idActor::UpdateAnimState -===================== -*/ -void idActor::UpdateAnimState( void ) { - headAnim.UpdateState(); - torsoAnim.UpdateState(); - legsAnim.UpdateState(); -} - -/* -===================== -idActor::GetAnim -===================== -*/ -int idActor::GetAnim( int channel, const char *animname ) { - int anim; - const char *temp; - idAnimator *animatorPtr; - - if ( channel == ANIMCHANNEL_HEAD ) { - if ( !head.GetEntity() ) { - return 0; - } - animatorPtr = head.GetEntity()->GetAnimator(); - } else { - animatorPtr = &animator; - } - - if ( animPrefix.Length() ) { - temp = va( "%s_%s", animPrefix.c_str(), animname ); - anim = animatorPtr->GetAnim( temp ); - if ( anim ) { - return anim; - } - } - - anim = animatorPtr->GetAnim( animname ); - - return anim; -} - -/* -=============== -idActor::SyncAnimChannels -=============== -*/ -void idActor::SyncAnimChannels( int channel, int syncToChannel, int blendFrames ) { - idAnimator *headAnimator; - idAFAttachment *headEnt; - int anim; - idAnimBlend *syncAnim; - int starttime; - int blendTime; - int cycle; - - blendTime = FRAME2MS( blendFrames ); - if ( channel == ANIMCHANNEL_HEAD ) { - headEnt = head.GetEntity(); - if ( headEnt ) { - headAnimator = headEnt->GetAnimator(); - syncAnim = animator.CurrentAnim( syncToChannel ); - if ( syncAnim ) { - anim = headAnimator->GetAnim( syncAnim->AnimFullName() ); - if ( !anim ) { - anim = headAnimator->GetAnim( syncAnim->AnimName() ); - } - if ( anim ) { - cycle = animator.CurrentAnim( syncToChannel )->GetCycleCount(); - starttime = animator.CurrentAnim( syncToChannel )->GetStartTime(); - headAnimator->PlayAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, blendTime ); - headAnimator->CurrentAnim( ANIMCHANNEL_ALL )->SetCycleCount( cycle ); - headAnimator->CurrentAnim( ANIMCHANNEL_ALL )->SetStartTime( starttime ); - } else { - headEnt->PlayIdleAnim( blendTime ); - } - } - } - } else if ( syncToChannel == ANIMCHANNEL_HEAD ) { - headEnt = head.GetEntity(); - if ( headEnt ) { - headAnimator = headEnt->GetAnimator(); - syncAnim = headAnimator->CurrentAnim( ANIMCHANNEL_ALL ); - if ( syncAnim ) { - anim = GetAnim( channel, syncAnim->AnimFullName() ); - if ( !anim ) { - anim = GetAnim( channel, syncAnim->AnimName() ); - } - if ( anim ) { - cycle = headAnimator->CurrentAnim( ANIMCHANNEL_ALL )->GetCycleCount(); - starttime = headAnimator->CurrentAnim( ANIMCHANNEL_ALL )->GetStartTime(); - animator.PlayAnim( channel, anim, gameLocal.time, blendTime ); - animator.CurrentAnim( channel )->SetCycleCount( cycle ); - animator.CurrentAnim( channel )->SetStartTime( starttime ); - } - } - } - } else { - animator.SyncAnimChannels( channel, syncToChannel, gameLocal.time, blendTime ); - } -} - -/*********************************************************************** - - Damage - -***********************************************************************/ - -/* -============ -idActor::Gib -============ -*/ -void idActor::Gib( const idVec3 &dir, const char *damageDefName ) { - // no gibbing in multiplayer - by self damage or by moving objects - if ( gameLocal.isMultiplayer ) { - return; - } - // only gib once - if ( gibbed ) { - return; - } - idAFEntity_Gibbable::Gib( dir, damageDefName ); - if ( head.GetEntity() ) { - head.GetEntity()->Hide(); - } - StopSound( SND_CHANNEL_VOICE, false ); -} - - -/* -============ -idActor::Damage - -this entity that is being damaged -inflictor entity that is causing the damage -attacker entity that caused the inflictor to damage targ - example: this=monster, inflictor=rocket, attacker=player - -dir direction of the attack for knockback in global space -point point at which the damage is being inflicted, used for headshots -damage amount of damage being inflicted - -inflictor, attacker, dir, and point can be NULL for environmental effects - -Bleeding wounds and surface overlays are applied in the collision code that -calls Damage() -============ -*/ -void idActor::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, - const char *damageDefName, const float damageScale, const int location ) { - if ( !fl.takedamage ) { - return; - } - - if ( !inflictor ) { - inflictor = gameLocal.world; - } - if ( !attacker ) { - attacker = gameLocal.world; - } - -#ifdef _D3XP - SetTimeState ts( timeGroup ); - - // Helltime boss is immune to all projectiles except the helltime killer - if ( finalBoss && idStr::Icmp(inflictor->GetEntityDefName(), "projectile_helltime_killer") ) { - return; - } - - // Maledict is immume to the falling asteroids - if ( !idStr::Icmp( GetEntityDefName(), "monster_boss_d3xp_maledict" ) && - (!idStr::Icmp( damageDefName, "damage_maledict_asteroid" ) || !idStr::Icmp( damageDefName, "damage_maledict_asteroid_splash" ) ) ) { - return; - } -#else - if ( finalBoss && !inflictor->IsType( idSoulCubeMissile::Type ) ) { - return; - } -#endif - - const idDict *damageDef = gameLocal.FindEntityDefDict( damageDefName ); - if ( !damageDef ) { - gameLocal.Error( "Unknown damageDef '%s'", damageDefName ); - } - - int damage = damageDef->GetInt( "damage" ) * damageScale; - damage = GetDamageForLocation( damage, location ); - - // inform the attacker that they hit someone - attacker->DamageFeedback( this, inflictor, damage ); - if ( damage > 0 ) { - health -= damage; - -#ifdef _D3XP - //Check the health against any damage cap that is currently set - if(damageCap >= 0 && health < damageCap) { - health = damageCap; - } -#endif - - if ( health <= 0 ) { - if ( health < -999 ) { - health = -999; - } - Killed( inflictor, attacker, damage, dir, location ); - if ( ( health < -20 ) && spawnArgs.GetBool( "gib" ) && damageDef->GetBool( "gib" ) ) { - Gib( dir, damageDefName ); - } - } else { - Pain( inflictor, attacker, damage, dir, location ); - } - } else { - // don't accumulate knockback - if ( af.IsLoaded() ) { - // clear impacts - af.Rest(); - - // physics is turned off by calling af.Rest() - BecomeActive( TH_PHYSICS ); - } - } -} - -/* -===================== -idActor::ClearPain -===================== -*/ -void idActor::ClearPain( void ) { - pain_debounce_time = 0; -} - -/* -===================== -idActor::Pain -===================== -*/ -bool idActor::Pain( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) { - if ( af.IsLoaded() ) { - // clear impacts - af.Rest(); - - // physics is turned off by calling af.Rest() - BecomeActive( TH_PHYSICS ); - } - - if ( gameLocal.time < pain_debounce_time ) { - return false; - } - - // don't play pain sounds more than necessary - pain_debounce_time = gameLocal.time + pain_delay; - - if ( health > 75 ) { - StartSound( "snd_pain_small", SND_CHANNEL_VOICE, 0, false, NULL ); - } else if ( health > 50 ) { - StartSound( "snd_pain_medium", SND_CHANNEL_VOICE, 0, false, NULL ); - } else if ( health > 25 ) { - StartSound( "snd_pain_large", SND_CHANNEL_VOICE, 0, false, NULL ); - } else { - StartSound( "snd_pain_huge", SND_CHANNEL_VOICE, 0, false, NULL ); - } - - if ( !allowPain || ( gameLocal.time < painTime ) ) { - // don't play a pain anim - return false; - } - - if ( pain_threshold && ( damage < pain_threshold ) ) { - return false; - } - - // set the pain anim - idStr damageGroup = GetDamageGroup( location ); - - painAnim = ""; - if ( animPrefix.Length() ) { - if ( damageGroup.Length() && ( damageGroup != "legs" ) ) { - sprintf( painAnim, "%s_pain_%s", animPrefix.c_str(), damageGroup.c_str() ); - if ( !animator.HasAnim( painAnim ) ) { - sprintf( painAnim, "pain_%s", damageGroup.c_str() ); - if ( !animator.HasAnim( painAnim ) ) { - painAnim = ""; - } - } - } - - if ( !painAnim.Length() ) { - sprintf( painAnim, "%s_pain", animPrefix.c_str() ); - if ( !animator.HasAnim( painAnim ) ) { - painAnim = ""; - } - } - } else if ( damageGroup.Length() && ( damageGroup != "legs" ) ) { - sprintf( painAnim, "pain_%s", damageGroup.c_str() ); - if ( !animator.HasAnim( painAnim ) ) { - sprintf( painAnim, "pain_%s", damageGroup.c_str() ); - if ( !animator.HasAnim( painAnim ) ) { - painAnim = ""; - } - } - } - - if ( !painAnim.Length() ) { - painAnim = "pain"; - } - - if ( g_debugDamage.GetBool() ) { - gameLocal.Printf( "Damage: joint: '%s', zone '%s', anim '%s'\n", animator.GetJointName( ( jointHandle_t )location ), - damageGroup.c_str(), painAnim.c_str() ); - } - - return true; -} - -/* -===================== -idActor::SpawnGibs -===================== -*/ -void idActor::SpawnGibs( const idVec3 &dir, const char *damageDefName ) { - idAFEntity_Gibbable::SpawnGibs( dir, damageDefName ); - RemoveAttachments(); -} - -/* -===================== -idActor::SetupDamageGroups - -FIXME: only store group names once and store an index for each joint -===================== -*/ -void idActor::SetupDamageGroups( void ) { - int i; - const idKeyValue *arg; - idStr groupname; - idList jointList; - int jointnum; - float scale; - - // create damage zones - damageGroups.SetNum( animator.NumJoints() ); - arg = spawnArgs.MatchPrefix( "damage_zone ", NULL ); - while ( arg ) { - groupname = arg->GetKey(); - groupname.Strip( "damage_zone " ); - animator.GetJointList( arg->GetValue(), jointList ); - for( i = 0; i < jointList.Num(); i++ ) { - jointnum = jointList[ i ]; - damageGroups[ jointnum ] = groupname; - } - jointList.Clear(); - arg = spawnArgs.MatchPrefix( "damage_zone ", arg ); - } - - // initilize the damage zones to normal damage - damageScale.SetNum( animator.NumJoints() ); - for( i = 0; i < damageScale.Num(); i++ ) { - damageScale[ i ] = 1.0f; - } - - // set the percentage on damage zones - arg = spawnArgs.MatchPrefix( "damage_scale ", NULL ); - while ( arg ) { - scale = atof( arg->GetValue() ); - groupname = arg->GetKey(); - groupname.Strip( "damage_scale " ); - for( i = 0; i < damageScale.Num(); i++ ) { - if ( damageGroups[ i ] == groupname ) { - damageScale[ i ] = scale; - } - } - arg = spawnArgs.MatchPrefix( "damage_scale ", arg ); - } -} - -/* -===================== -idActor::GetDamageForLocation -===================== -*/ -int idActor::GetDamageForLocation( int damage, int location ) { - if ( ( location < 0 ) || ( location >= damageScale.Num() ) ) { - return damage; - } - - return (int)ceil( damage * damageScale[ location ] ); -} - -/* -===================== -idActor::GetDamageGroup -===================== -*/ -const char *idActor::GetDamageGroup( int location ) { - if ( ( location < 0 ) || ( location >= damageGroups.Num() ) ) { - return ""; - } - - return damageGroups[ location ]; -} - - -/*********************************************************************** - - Events - -***********************************************************************/ - -/* -===================== -idActor::Event_EnableEyeFocus -===================== -*/ -void idActor::PlayFootStepSound( void ) { - const char *sound = NULL; - const idMaterial *material; - - if ( !GetPhysics()->HasGroundContacts() ) { - return; - } - - // start footstep sound based on material type - material = GetPhysics()->GetContact( 0 ).material; - if ( material != NULL ) { - sound = spawnArgs.GetString( va( "snd_footstep_%s", gameLocal.sufaceTypeNames[ material->GetSurfaceType() ] ) ); - } - if ( *sound == '\0' ) { - sound = spawnArgs.GetString( "snd_footstep" ); - } - if ( *sound != '\0' ) { - StartSoundShader( declManager->FindSound( sound ), SND_CHANNEL_BODY, 0, false, NULL ); - } -} - -/* -===================== -idActor::Event_EnableEyeFocus -===================== -*/ -void idActor::Event_EnableEyeFocus( void ) { - allowEyeFocus = true; - blink_time = gameLocal.time + blink_min + gameLocal.random.RandomFloat() * ( blink_max - blink_min ); -} - -/* -===================== -idActor::Event_DisableEyeFocus -===================== -*/ -void idActor::Event_DisableEyeFocus( void ) { - allowEyeFocus = false; - - idEntity *headEnt = head.GetEntity(); - if ( headEnt ) { - headEnt->GetAnimator()->Clear( ANIMCHANNEL_EYELIDS, gameLocal.time, FRAME2MS( 2 ) ); - } else { - animator.Clear( ANIMCHANNEL_EYELIDS, gameLocal.time, FRAME2MS( 2 ) ); - } -} - -/* -=============== -idActor::Event_Footstep -=============== -*/ -void idActor::Event_Footstep( void ) { - PlayFootStepSound(); -} - -/* -===================== -idActor::Event_EnableWalkIK -===================== -*/ -void idActor::Event_EnableWalkIK( void ) { - walkIK.EnableAll(); -} - -/* -===================== -idActor::Event_DisableWalkIK -===================== -*/ -void idActor::Event_DisableWalkIK( void ) { - walkIK.DisableAll(); -} - -/* -===================== -idActor::Event_EnableLegIK -===================== -*/ -void idActor::Event_EnableLegIK( int num ) { - walkIK.EnableLeg( num ); -} - -/* -===================== -idActor::Event_DisableLegIK -===================== -*/ -void idActor::Event_DisableLegIK( int num ) { - walkIK.DisableLeg( num ); -} - -/* -===================== -idActor::Event_PreventPain -===================== -*/ -void idActor::Event_PreventPain( float duration ) { - painTime = gameLocal.time + SEC2MS( duration ); -} - -/* -=============== -idActor::Event_DisablePain -=============== -*/ -void idActor::Event_DisablePain( void ) { - allowPain = false; -} - -/* -=============== -idActor::Event_EnablePain -=============== -*/ -void idActor::Event_EnablePain( void ) { - allowPain = true; -} - -/* -===================== -idActor::Event_GetPainAnim -===================== -*/ -void idActor::Event_GetPainAnim( void ) { - if ( !painAnim.Length() ) { - idThread::ReturnString( "pain" ); - } else { - idThread::ReturnString( painAnim ); - } -} - -/* -===================== -idActor::Event_SetAnimPrefix -===================== -*/ -void idActor::Event_SetAnimPrefix( const char *prefix ) { - animPrefix = prefix; -} - -/* -=============== -idActor::Event_StopAnim -=============== -*/ -void idActor::Event_StopAnim( int channel, int frames ) { - switch( channel ) { - case ANIMCHANNEL_HEAD : - headAnim.StopAnim( frames ); - break; - - case ANIMCHANNEL_TORSO : - torsoAnim.StopAnim( frames ); - break; - - case ANIMCHANNEL_LEGS : - legsAnim.StopAnim( frames ); - break; - - default: - gameLocal.Error( "Unknown anim group" ); - break; - } -} - -/* -=============== -idActor::Event_PlayAnim -=============== -*/ -void idActor::Event_PlayAnim( int channel, const char *animname ) { - animFlags_t flags; - idEntity *headEnt; - int anim; - - anim = GetAnim( channel, animname ); - if ( !anim ) { - if ( ( channel == ANIMCHANNEL_HEAD ) && head.GetEntity() ) { - gameLocal.DPrintf( "missing '%s' animation on '%s' (%s)\n", animname, name.c_str(), spawnArgs.GetString( "def_head", "" ) ); - } else { - gameLocal.DPrintf( "missing '%s' animation on '%s' (%s)\n", animname, name.c_str(), GetEntityDefName() ); - } - idThread::ReturnInt( 0 ); - return; - } - - switch( channel ) { - case ANIMCHANNEL_HEAD : - headEnt = head.GetEntity(); - if ( headEnt ) { - headAnim.idleAnim = false; - headAnim.PlayAnim( anim ); - flags = headAnim.GetAnimFlags(); - if ( !flags.prevent_idle_override ) { - if ( torsoAnim.IsIdle() ) { - torsoAnim.animBlendFrames = headAnim.lastAnimBlendFrames; - SyncAnimChannels( ANIMCHANNEL_TORSO, ANIMCHANNEL_HEAD, headAnim.lastAnimBlendFrames ); - if ( legsAnim.IsIdle() ) { - legsAnim.animBlendFrames = headAnim.lastAnimBlendFrames; - SyncAnimChannels( ANIMCHANNEL_LEGS, ANIMCHANNEL_HEAD, headAnim.lastAnimBlendFrames ); - } - } - } - } - break; - - case ANIMCHANNEL_TORSO : - torsoAnim.idleAnim = false; - torsoAnim.PlayAnim( anim ); - flags = torsoAnim.GetAnimFlags(); - if ( !flags.prevent_idle_override ) { - if ( headAnim.IsIdle() ) { - headAnim.animBlendFrames = torsoAnim.lastAnimBlendFrames; - SyncAnimChannels( ANIMCHANNEL_HEAD, ANIMCHANNEL_TORSO, torsoAnim.lastAnimBlendFrames ); - } - if ( legsAnim.IsIdle() ) { - legsAnim.animBlendFrames = torsoAnim.lastAnimBlendFrames; - SyncAnimChannels( ANIMCHANNEL_LEGS, ANIMCHANNEL_TORSO, torsoAnim.lastAnimBlendFrames ); - } - } - break; - - case ANIMCHANNEL_LEGS : - legsAnim.idleAnim = false; - legsAnim.PlayAnim( anim ); - flags = legsAnim.GetAnimFlags(); - if ( !flags.prevent_idle_override ) { - if ( torsoAnim.IsIdle() ) { - torsoAnim.animBlendFrames = legsAnim.lastAnimBlendFrames; - SyncAnimChannels( ANIMCHANNEL_TORSO, ANIMCHANNEL_LEGS, legsAnim.lastAnimBlendFrames ); - if ( headAnim.IsIdle() ) { - headAnim.animBlendFrames = legsAnim.lastAnimBlendFrames; - SyncAnimChannels( ANIMCHANNEL_HEAD, ANIMCHANNEL_LEGS, legsAnim.lastAnimBlendFrames ); - } - } - } - break; - - default : - gameLocal.Error( "Unknown anim group" ); - break; - } - idThread::ReturnInt( 1 ); -} - -/* -=============== -idActor::Event_PlayCycle -=============== -*/ -void idActor::Event_PlayCycle( int channel, const char *animname ) { - animFlags_t flags; - int anim; - - anim = GetAnim( channel, animname ); - if ( !anim ) { - if ( ( channel == ANIMCHANNEL_HEAD ) && head.GetEntity() ) { - gameLocal.DPrintf( "missing '%s' animation on '%s' (%s)\n", animname, name.c_str(), spawnArgs.GetString( "def_head", "" ) ); - } else { - gameLocal.DPrintf( "missing '%s' animation on '%s' (%s)\n", animname, name.c_str(), GetEntityDefName() ); - } - idThread::ReturnInt( false ); - return; - } - - switch( channel ) { - case ANIMCHANNEL_HEAD : - headAnim.idleAnim = false; - headAnim.CycleAnim( anim ); - flags = headAnim.GetAnimFlags(); - if ( !flags.prevent_idle_override ) { - if ( torsoAnim.IsIdle() && legsAnim.IsIdle() ) { - torsoAnim.animBlendFrames = headAnim.lastAnimBlendFrames; - SyncAnimChannels( ANIMCHANNEL_TORSO, ANIMCHANNEL_HEAD, headAnim.lastAnimBlendFrames ); - legsAnim.animBlendFrames = headAnim.lastAnimBlendFrames; - SyncAnimChannels( ANIMCHANNEL_LEGS, ANIMCHANNEL_HEAD, headAnim.lastAnimBlendFrames ); - } - } - break; - - case ANIMCHANNEL_TORSO : - torsoAnim.idleAnim = false; - torsoAnim.CycleAnim( anim ); - flags = torsoAnim.GetAnimFlags(); - if ( !flags.prevent_idle_override ) { - if ( headAnim.IsIdle() ) { - headAnim.animBlendFrames = torsoAnim.lastAnimBlendFrames; - SyncAnimChannels( ANIMCHANNEL_HEAD, ANIMCHANNEL_TORSO, torsoAnim.lastAnimBlendFrames ); - } - if ( legsAnim.IsIdle() ) { - legsAnim.animBlendFrames = torsoAnim.lastAnimBlendFrames; - SyncAnimChannels( ANIMCHANNEL_LEGS, ANIMCHANNEL_TORSO, torsoAnim.lastAnimBlendFrames ); - } - } - break; - - case ANIMCHANNEL_LEGS : - legsAnim.idleAnim = false; - legsAnim.CycleAnim( anim ); - flags = legsAnim.GetAnimFlags(); - if ( !flags.prevent_idle_override ) { - if ( torsoAnim.IsIdle() ) { - torsoAnim.animBlendFrames = legsAnim.lastAnimBlendFrames; - SyncAnimChannels( ANIMCHANNEL_TORSO, ANIMCHANNEL_LEGS, legsAnim.lastAnimBlendFrames ); - if ( headAnim.IsIdle() ) { - headAnim.animBlendFrames = legsAnim.lastAnimBlendFrames; - SyncAnimChannels( ANIMCHANNEL_HEAD, ANIMCHANNEL_LEGS, legsAnim.lastAnimBlendFrames ); - } - } - } - break; - - default: - gameLocal.Error( "Unknown anim group" ); - } - - idThread::ReturnInt( true ); -} - -/* -=============== -idActor::Event_IdleAnim -=============== -*/ -void idActor::Event_IdleAnim( int channel, const char *animname ) { - int anim; - - anim = GetAnim( channel, animname ); - if ( !anim ) { - if ( ( channel == ANIMCHANNEL_HEAD ) && head.GetEntity() ) { - gameLocal.DPrintf( "missing '%s' animation on '%s' (%s)\n", animname, name.c_str(), spawnArgs.GetString( "def_head", "" ) ); - } else { - gameLocal.DPrintf( "missing '%s' animation on '%s' (%s)\n", animname, name.c_str(), GetEntityDefName() ); - } - - switch( channel ) { - case ANIMCHANNEL_HEAD : - headAnim.BecomeIdle(); - break; - - case ANIMCHANNEL_TORSO : - torsoAnim.BecomeIdle(); - break; - - case ANIMCHANNEL_LEGS : - legsAnim.BecomeIdle(); - break; - - default: - gameLocal.Error( "Unknown anim group" ); - } - - idThread::ReturnInt( false ); - return; - } - - switch( channel ) { - case ANIMCHANNEL_HEAD : - headAnim.BecomeIdle(); - if ( torsoAnim.GetAnimFlags().prevent_idle_override ) { - // don't sync to torso body if it doesn't override idle anims - headAnim.CycleAnim( anim ); - } else if ( torsoAnim.IsIdle() && legsAnim.IsIdle() ) { - // everything is idle, so play the anim on the head and copy it to the torso and legs - headAnim.CycleAnim( anim ); - torsoAnim.animBlendFrames = headAnim.lastAnimBlendFrames; - SyncAnimChannels( ANIMCHANNEL_TORSO, ANIMCHANNEL_HEAD, headAnim.lastAnimBlendFrames ); - legsAnim.animBlendFrames = headAnim.lastAnimBlendFrames; - SyncAnimChannels( ANIMCHANNEL_LEGS, ANIMCHANNEL_HEAD, headAnim.lastAnimBlendFrames ); - } else if ( torsoAnim.IsIdle() ) { - // sync the head and torso to the legs - SyncAnimChannels( ANIMCHANNEL_HEAD, ANIMCHANNEL_LEGS, headAnim.animBlendFrames ); - torsoAnim.animBlendFrames = headAnim.lastAnimBlendFrames; - SyncAnimChannels( ANIMCHANNEL_TORSO, ANIMCHANNEL_LEGS, torsoAnim.animBlendFrames ); - } else { - // sync the head to the torso - SyncAnimChannels( ANIMCHANNEL_HEAD, ANIMCHANNEL_TORSO, headAnim.animBlendFrames ); - } - break; - - case ANIMCHANNEL_TORSO : - torsoAnim.BecomeIdle(); - if ( legsAnim.GetAnimFlags().prevent_idle_override ) { - // don't sync to legs if legs anim doesn't override idle anims - torsoAnim.CycleAnim( anim ); - } else if ( legsAnim.IsIdle() ) { - // play the anim in both legs and torso - torsoAnim.CycleAnim( anim ); - legsAnim.animBlendFrames = torsoAnim.lastAnimBlendFrames; - SyncAnimChannels( ANIMCHANNEL_LEGS, ANIMCHANNEL_TORSO, torsoAnim.lastAnimBlendFrames ); - } else { - // sync the anim to the legs - SyncAnimChannels( ANIMCHANNEL_TORSO, ANIMCHANNEL_LEGS, torsoAnim.animBlendFrames ); - } - - if ( headAnim.IsIdle() ) { - SyncAnimChannels( ANIMCHANNEL_HEAD, ANIMCHANNEL_TORSO, torsoAnim.lastAnimBlendFrames ); - } - break; - - case ANIMCHANNEL_LEGS : - legsAnim.BecomeIdle(); - if ( torsoAnim.GetAnimFlags().prevent_idle_override ) { - // don't sync to torso if torso anim doesn't override idle anims - legsAnim.CycleAnim( anim ); - } else if ( torsoAnim.IsIdle() ) { - // play the anim in both legs and torso - legsAnim.CycleAnim( anim ); - torsoAnim.animBlendFrames = legsAnim.lastAnimBlendFrames; - SyncAnimChannels( ANIMCHANNEL_TORSO, ANIMCHANNEL_LEGS, legsAnim.lastAnimBlendFrames ); - if ( headAnim.IsIdle() ) { - SyncAnimChannels( ANIMCHANNEL_HEAD, ANIMCHANNEL_LEGS, legsAnim.lastAnimBlendFrames ); - } - } else { - // sync the anim to the torso - SyncAnimChannels( ANIMCHANNEL_LEGS, ANIMCHANNEL_TORSO, legsAnim.animBlendFrames ); - } - break; - - default: - gameLocal.Error( "Unknown anim group" ); - } - - idThread::ReturnInt( true ); -} - -/* -================ -idActor::Event_SetSyncedAnimWeight -================ -*/ -void idActor::Event_SetSyncedAnimWeight( int channel, int anim, float weight ) { - idEntity *headEnt; - - headEnt = head.GetEntity(); - switch( channel ) { - case ANIMCHANNEL_HEAD : - if ( headEnt ) { - animator.CurrentAnim( ANIMCHANNEL_ALL )->SetSyncedAnimWeight( anim, weight ); - } else { - animator.CurrentAnim( ANIMCHANNEL_HEAD )->SetSyncedAnimWeight( anim, weight ); - } - if ( torsoAnim.IsIdle() ) { - animator.CurrentAnim( ANIMCHANNEL_TORSO )->SetSyncedAnimWeight( anim, weight ); - if ( legsAnim.IsIdle() ) { - animator.CurrentAnim( ANIMCHANNEL_LEGS )->SetSyncedAnimWeight( anim, weight ); - } - } - break; - - case ANIMCHANNEL_TORSO : - animator.CurrentAnim( ANIMCHANNEL_TORSO )->SetSyncedAnimWeight( anim, weight ); - if ( legsAnim.IsIdle() ) { - animator.CurrentAnim( ANIMCHANNEL_LEGS )->SetSyncedAnimWeight( anim, weight ); - } - if ( headEnt && headAnim.IsIdle() ) { - animator.CurrentAnim( ANIMCHANNEL_ALL )->SetSyncedAnimWeight( anim, weight ); - } - break; - - case ANIMCHANNEL_LEGS : - animator.CurrentAnim( ANIMCHANNEL_LEGS )->SetSyncedAnimWeight( anim, weight ); - if ( torsoAnim.IsIdle() ) { - animator.CurrentAnim( ANIMCHANNEL_TORSO )->SetSyncedAnimWeight( anim, weight ); - if ( headEnt && headAnim.IsIdle() ) { - animator.CurrentAnim( ANIMCHANNEL_ALL )->SetSyncedAnimWeight( anim, weight ); - } - } - break; - - default: - gameLocal.Error( "Unknown anim group" ); - } -} - -/* -=============== -idActor::Event_OverrideAnim -=============== -*/ -void idActor::Event_OverrideAnim( int channel ) { - switch( channel ) { - case ANIMCHANNEL_HEAD : - headAnim.Disable(); - if ( !torsoAnim.IsIdle() ) { - SyncAnimChannels( ANIMCHANNEL_HEAD, ANIMCHANNEL_TORSO, torsoAnim.lastAnimBlendFrames ); - } else { - SyncAnimChannels( ANIMCHANNEL_HEAD, ANIMCHANNEL_LEGS, legsAnim.lastAnimBlendFrames ); - } - break; - - case ANIMCHANNEL_TORSO : - torsoAnim.Disable(); - SyncAnimChannels( ANIMCHANNEL_TORSO, ANIMCHANNEL_LEGS, legsAnim.lastAnimBlendFrames ); - if ( headAnim.IsIdle() ) { - SyncAnimChannels( ANIMCHANNEL_HEAD, ANIMCHANNEL_TORSO, torsoAnim.lastAnimBlendFrames ); - } - break; - - case ANIMCHANNEL_LEGS : - legsAnim.Disable(); - SyncAnimChannels( ANIMCHANNEL_LEGS, ANIMCHANNEL_TORSO, torsoAnim.lastAnimBlendFrames ); - break; - - default: - gameLocal.Error( "Unknown anim group" ); - break; - } -} - -/* -=============== -idActor::Event_EnableAnim -=============== -*/ -void idActor::Event_EnableAnim( int channel, int blendFrames ) { - switch( channel ) { - case ANIMCHANNEL_HEAD : - headAnim.Enable( blendFrames ); - break; - - case ANIMCHANNEL_TORSO : - torsoAnim.Enable( blendFrames ); - break; - - case ANIMCHANNEL_LEGS : - legsAnim.Enable( blendFrames ); - break; - - default: - gameLocal.Error( "Unknown anim group" ); - break; - } -} - -/* -=============== -idActor::Event_SetBlendFrames -=============== -*/ -void idActor::Event_SetBlendFrames( int channel, int blendFrames ) { - switch( channel ) { - case ANIMCHANNEL_HEAD : - headAnim.animBlendFrames = blendFrames; - headAnim.lastAnimBlendFrames = blendFrames; - break; - - case ANIMCHANNEL_TORSO : - torsoAnim.animBlendFrames = blendFrames; - torsoAnim.lastAnimBlendFrames = blendFrames; - break; - - case ANIMCHANNEL_LEGS : - legsAnim.animBlendFrames = blendFrames; - legsAnim.lastAnimBlendFrames = blendFrames; - break; - - default: - gameLocal.Error( "Unknown anim group" ); - break; - } -} - -/* -=============== -idActor::Event_GetBlendFrames -=============== -*/ -void idActor::Event_GetBlendFrames( int channel ) { - switch( channel ) { - case ANIMCHANNEL_HEAD : - idThread::ReturnInt( headAnim.animBlendFrames ); - break; - - case ANIMCHANNEL_TORSO : - idThread::ReturnInt( torsoAnim.animBlendFrames ); - break; - - case ANIMCHANNEL_LEGS : - idThread::ReturnInt( legsAnim.animBlendFrames ); - break; - - default: - gameLocal.Error( "Unknown anim group" ); - break; - } -} - -/* -=============== -idActor::Event_AnimState -=============== -*/ -void idActor::Event_AnimState( int channel, const char *statename, int blendFrames ) { - SetAnimState( channel, statename, blendFrames ); -} - -/* -=============== -idActor::Event_GetAnimState -=============== -*/ -void idActor::Event_GetAnimState( int channel ) { - const char *state; - - state = GetAnimState( channel ); - idThread::ReturnString( state ); -} - -/* -=============== -idActor::Event_InAnimState -=============== -*/ -void idActor::Event_InAnimState( int channel, const char *statename ) { - bool instate; - - instate = InAnimState( channel, statename ); - idThread::ReturnInt( instate ); -} - -/* -=============== -idActor::Event_FinishAction -=============== -*/ -void idActor::Event_FinishAction( const char *actionname ) { - if ( waitState == actionname ) { - SetWaitState( "" ); - } -} - -/* -=============== -idActor::Event_AnimDone -=============== -*/ -void idActor::Event_AnimDone( int channel, int blendFrames ) { - bool result; - - switch( channel ) { - case ANIMCHANNEL_HEAD : - result = headAnim.AnimDone( blendFrames ); - idThread::ReturnInt( result ); - break; - - case ANIMCHANNEL_TORSO : - result = torsoAnim.AnimDone( blendFrames ); - idThread::ReturnInt( result ); - break; - - case ANIMCHANNEL_LEGS : - result = legsAnim.AnimDone( blendFrames ); - idThread::ReturnInt( result ); - break; - - default: - gameLocal.Error( "Unknown anim group" ); - } -} - -/* -================ -idActor::Event_HasAnim -================ -*/ -void idActor::Event_HasAnim( int channel, const char *animname ) { - if ( GetAnim( channel, animname ) != 0 ) { - idThread::ReturnFloat( 1.0f ); - } else { - idThread::ReturnFloat( 0.0f ); - } -} - -/* -================ -idActor::Event_CheckAnim -================ -*/ -void idActor::Event_CheckAnim( int channel, const char *animname ) { - if ( !GetAnim( channel, animname ) ) { - if ( animPrefix.Length() ) { - gameLocal.Error( "Can't find anim '%s_%s' for '%s'", animPrefix.c_str(), animname, name.c_str() ); - } else { - gameLocal.Error( "Can't find anim '%s' for '%s'", animname, name.c_str() ); - } - } -} - -/* -================ -idActor::Event_ChooseAnim -================ -*/ -void idActor::Event_ChooseAnim( int channel, const char *animname ) { - int anim; - - anim = GetAnim( channel, animname ); - if ( anim ) { - if ( channel == ANIMCHANNEL_HEAD ) { - if ( head.GetEntity() ) { - idThread::ReturnString( head.GetEntity()->GetAnimator()->AnimFullName( anim ) ); - return; - } - } else { - idThread::ReturnString( animator.AnimFullName( anim ) ); - return; - } - } - - idThread::ReturnString( "" ); -} - -/* -================ -idActor::Event_AnimLength -================ -*/ -void idActor::Event_AnimLength( int channel, const char *animname ) { - int anim; - - anim = GetAnim( channel, animname ); - if ( anim ) { - if ( channel == ANIMCHANNEL_HEAD ) { - if ( head.GetEntity() ) { - idThread::ReturnFloat( MS2SEC( head.GetEntity()->GetAnimator()->AnimLength( anim ) ) ); - return; - } - } else { - idThread::ReturnFloat( MS2SEC( animator.AnimLength( anim ) ) ); - return; - } - } - - idThread::ReturnFloat( 0.0f ); -} - -/* -================ -idActor::Event_AnimDistance -================ -*/ -void idActor::Event_AnimDistance( int channel, const char *animname ) { - int anim; - - anim = GetAnim( channel, animname ); - if ( anim ) { - if ( channel == ANIMCHANNEL_HEAD ) { - if ( head.GetEntity() ) { - idThread::ReturnFloat( head.GetEntity()->GetAnimator()->TotalMovementDelta( anim ).Length() ); - return; - } - } else { - idThread::ReturnFloat( animator.TotalMovementDelta( anim ).Length() ); - return; - } - } - - idThread::ReturnFloat( 0.0f ); -} - -/* -================ -idActor::Event_HasEnemies -================ -*/ -void idActor::Event_HasEnemies( void ) { - bool hasEnemy; - - hasEnemy = HasEnemies(); - idThread::ReturnInt( hasEnemy ); -} - -/* -================ -idActor::Event_NextEnemy -================ -*/ -void idActor::Event_NextEnemy( idEntity *ent ) { - idActor *actor; - - if ( !ent || ( ent == this ) ) { - actor = enemyList.Next(); - } else { - if ( !ent->IsType( idActor::Type ) ) { - gameLocal.Error( "'%s' cannot be an enemy", ent->name.c_str() ); - } - - actor = static_cast( ent ); - if ( actor->enemyNode.ListHead() != &enemyList ) { - gameLocal.Error( "'%s' is not in '%s' enemy list", actor->name.c_str(), name.c_str() ); - } - } - - for( ; actor != NULL; actor = actor->enemyNode.Next() ) { - if ( !actor->fl.hidden ) { - idThread::ReturnEntity( actor ); - return; - } - } - - idThread::ReturnEntity( NULL ); -} - -/* -================ -idActor::Event_ClosestEnemyToPoint -================ -*/ -void idActor::Event_ClosestEnemyToPoint( const idVec3 &pos ) { - idActor *bestEnt = ClosestEnemyToPoint( pos ); - idThread::ReturnEntity( bestEnt ); -} - -/* -================ -idActor::Event_StopSound -================ -*/ -void idActor::Event_StopSound( int channel, int netSync ) { - if ( channel == SND_CHANNEL_VOICE ) { - idEntity *headEnt = head.GetEntity(); - if ( headEnt ) { - headEnt->StopSound( channel, ( netSync != 0 ) ); - } - } - StopSound( channel, ( netSync != 0 ) ); -} - -/* -===================== -idActor::Event_SetNextState -===================== -*/ -void idActor::Event_SetNextState( const char *name ) { - idealState = GetScriptFunction( name ); - if ( idealState == state ) { - state = NULL; - } -} - -/* -===================== -idActor::Event_SetState -===================== -*/ -void idActor::Event_SetState( const char *name ) { - idealState = GetScriptFunction( name ); - if ( idealState == state ) { - state = NULL; - } - scriptThread->DoneProcessing(); -} - -/* -===================== -idActor::Event_GetState -===================== -*/ -void idActor::Event_GetState( void ) { - if ( state ) { - idThread::ReturnString( state->Name() ); - } else { - idThread::ReturnString( "" ); - } -} - -/* -===================== -idActor::Event_GetHead -===================== -*/ -void idActor::Event_GetHead( void ) { - idThread::ReturnEntity( head.GetEntity() ); -} - -#ifdef _D3XP -/* -================ -idActor::Event_SetDamageGroupScale -================ -*/ -void idActor::Event_SetDamageGroupScale( const char* groupName, float scale) { - - for( int i = 0; i < damageScale.Num(); i++ ) { - if ( damageGroups[ i ] == groupName ) { - damageScale[ i ] = scale; - } - } -} - -/* -================ -idActor::Event_SetDamageGroupScaleAll -================ -*/ -void idActor::Event_SetDamageGroupScaleAll( float scale ) { - - for( int i = 0; i < damageScale.Num(); i++ ) { - damageScale[ i ] = scale; - } -} - -void idActor::Event_GetDamageGroupScale( const char* groupName ) { - - for( int i = 0; i < damageScale.Num(); i++ ) { - if ( damageGroups[ i ] == groupName ) { - idThread::ReturnFloat(damageScale[i]); - return; - } - } - - idThread::ReturnFloat(0); -} - -void idActor::Event_SetDamageCap( float _damageCap ) { - damageCap = _damageCap; -} - -void idActor::Event_SetWaitState( const char* waitState) { - SetWaitState(waitState); -} - -void idActor::Event_GetWaitState() { - if(WaitState()) { - idThread::ReturnString(WaitState()); - } else { - idThread::ReturnString(""); - } -} -#endif diff --git a/d3xp/Actor.h b/d3xp/Actor.h deleted file mode 100644 index 5ecef15c..00000000 --- a/d3xp/Actor.h +++ /dev/null @@ -1,344 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __GAME_ACTOR_H__ -#define __GAME_ACTOR_H__ - -#include "AFEntity.h" -#include "IK.h" -#include "PlayerView.h" - -/* -=============================================================================== - - idActor - -=============================================================================== -*/ - -extern const idEventDef AI_EnableEyeFocus; -extern const idEventDef AI_DisableEyeFocus; -extern const idEventDef EV_Footstep; -extern const idEventDef EV_FootstepLeft; -extern const idEventDef EV_FootstepRight; -extern const idEventDef EV_EnableWalkIK; -extern const idEventDef EV_DisableWalkIK; -extern const idEventDef EV_EnableLegIK; -extern const idEventDef EV_DisableLegIK; -extern const idEventDef AI_SetAnimPrefix; -extern const idEventDef AI_PlayAnim; -extern const idEventDef AI_PlayCycle; -extern const idEventDef AI_AnimDone; -extern const idEventDef AI_SetBlendFrames; -extern const idEventDef AI_GetBlendFrames; - -#ifdef _D3XP -extern const idEventDef AI_SetState; -#endif - -class idDeclParticle; - -class idAnimState { -public: - bool idleAnim; - idStr state; - int animBlendFrames; - int lastAnimBlendFrames; // allows override anims to blend based on the last transition time - -public: - idAnimState(); - ~idAnimState(); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void Init( idActor *owner, idAnimator *_animator, int animchannel ); - void Shutdown( void ); - void SetState( const char *name, int blendFrames ); - void StopAnim( int frames ); - void PlayAnim( int anim ); - void CycleAnim( int anim ); - void BecomeIdle( void ); - bool UpdateState( void ); - bool Disabled( void ) const; - void Enable( int blendFrames ); - void Disable( void ); - bool AnimDone( int blendFrames ) const; - bool IsIdle( void ) const; - animFlags_t GetAnimFlags( void ) const; - -private: - idActor * self; - idAnimator * animator; - idThread * thread; - int channel; - bool disabled; -}; - -class idAttachInfo { -public: - idEntityPtr ent; - int channel; -}; - -typedef struct { - jointModTransform_t mod; - jointHandle_t from; - jointHandle_t to; -} copyJoints_t; - -class idActor : public idAFEntity_Gibbable { -public: - CLASS_PROTOTYPE( idActor ); - - int team; - int rank; // monsters don't fight back if the attacker's rank is higher - idMat3 viewAxis; // view axis of the actor - - idLinkList enemyNode; // node linked into an entity's enemy list for quick lookups of who is attacking him - idLinkList enemyList; // list of characters that have targeted the player as their enemy - -public: - idActor( void ); - virtual ~idActor( void ); - - void Spawn( void ); - virtual void Restart( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - virtual void Hide( void ); - virtual void Show( void ); - virtual int GetDefaultSurfaceType( void ) const; - virtual void ProjectOverlay( const idVec3 &origin, const idVec3 &dir, float size, const char *material ); - - virtual bool LoadAF( void ); - void SetupBody( void ); - - void CheckBlink( void ); - - virtual bool GetPhysicsToVisualTransform( idVec3 &origin, idMat3 &axis ); - virtual bool GetPhysicsToSoundTransform( idVec3 &origin, idMat3 &axis ); - - // script state management - void ShutdownThreads( void ); - virtual bool ShouldConstructScriptObjectAtSpawn( void ) const; - virtual idThread * ConstructScriptObject( void ); - void UpdateScript( void ); - const function_t *GetScriptFunction( const char *funcname ); - void SetState( const function_t *newState ); - void SetState( const char *statename ); - - // vision testing - void SetEyeHeight( float height ); - float EyeHeight( void ) const; - idVec3 EyeOffset( void ) const; - idVec3 GetEyePosition( void ) const; - virtual void GetViewPos( idVec3 &origin, idMat3 &axis ) const; - void SetFOV( float fov ); - bool CheckFOV( const idVec3 &pos ) const; - bool CanSee( idEntity *ent, bool useFOV ) const; - bool PointVisible( const idVec3 &point ) const; - virtual void GetAIAimTargets( const idVec3 &lastSightPos, idVec3 &headPos, idVec3 &chestPos ); - - // damage - void SetupDamageGroups( void ); - virtual void Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location ); - int GetDamageForLocation( int damage, int location ); - const char * GetDamageGroup( int location ); - void ClearPain( void ); - virtual bool Pain( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ); - - // model/combat model/ragdoll - void SetCombatModel( void ); - idClipModel * GetCombatModel( void ) const; - virtual void LinkCombat( void ); - virtual void UnlinkCombat( void ); - bool StartRagdoll( void ); - void StopRagdoll( void ); - virtual bool UpdateAnimationControllers( void ); - - // delta view angles to allow movers to rotate the view of the actor - const idAngles & GetDeltaViewAngles( void ) const; - void SetDeltaViewAngles( const idAngles &delta ); - - bool HasEnemies( void ) const; - idActor * ClosestEnemyToPoint( const idVec3 &pos ); - idActor * EnemyWithMostHealth(); - - virtual bool OnLadder( void ) const; - - virtual void GetAASLocation( idAAS *aas, idVec3 &pos, int &areaNum ) const; - - void Attach( idEntity *ent ); - - virtual void Teleport( const idVec3 &origin, const idAngles &angles, idEntity *destination ); - - virtual renderView_t * GetRenderView(); - - // animation state control - int GetAnim( int channel, const char *name ); - void UpdateAnimState( void ); - void SetAnimState( int channel, const char *name, int blendFrames ); - const char * GetAnimState( int channel ) const; - bool InAnimState( int channel, const char *name ) const; - const char * WaitState( void ) const; - void SetWaitState( const char *_waitstate ); - bool AnimDone( int channel, int blendFrames ) const; - virtual void SpawnGibs( const idVec3 &dir, const char *damageDefName ); - -#ifdef _D3XP - idEntity* GetHeadEntity() { return head.GetEntity(); }; -#endif - -protected: - friend class idAnimState; - - float fovDot; // cos( fovDegrees ) - idVec3 eyeOffset; // offset of eye relative to physics origin - idVec3 modelOffset; // offset of visual model relative to the physics origin - - idAngles deltaViewAngles; // delta angles relative to view input angles - - int pain_debounce_time; // next time the actor can show pain - int pain_delay; // time between playing pain sound - int pain_threshold; // how much damage monster can take at any one time before playing pain animation - - idStrList damageGroups; // body damage groups - idList damageScale; // damage scale per damage gruop - - bool use_combat_bbox; // whether to use the bounding box for combat collision - idEntityPtr head; - idList copyJoints; // copied from the body animation to the head model - - // state variables - const function_t *state; - const function_t *idealState; - - // joint handles - jointHandle_t leftEyeJoint; - jointHandle_t rightEyeJoint; - jointHandle_t soundJoint; - - idIK_Walk walkIK; - - idStr animPrefix; - idStr painAnim; - - // blinking - int blink_anim; - int blink_time; - int blink_min; - int blink_max; - - // script variables - idThread * scriptThread; - idStr waitState; - idAnimState headAnim; - idAnimState torsoAnim; - idAnimState legsAnim; - - bool allowPain; - bool allowEyeFocus; - bool finalBoss; - - int painTime; - - idList attachments; - -#ifdef _D3XP - int damageCap; -#endif - - virtual void Gib( const idVec3 &dir, const char *damageDefName ); - - // removes attachments with "remove" set for when character dies - void RemoveAttachments( void ); - - // copies animation from body to head joints - void CopyJointsFromBodyToHead( void ); - -private: - void SyncAnimChannels( int channel, int syncToChannel, int blendFrames ); - void FinishSetup( void ); - void SetupHead( void ); - void PlayFootStepSound( void ); - - void Event_EnableEyeFocus( void ); - void Event_DisableEyeFocus( void ); - void Event_Footstep( void ); - void Event_EnableWalkIK( void ); - void Event_DisableWalkIK( void ); - void Event_EnableLegIK( int num ); - void Event_DisableLegIK( int num ); - void Event_SetAnimPrefix( const char *name ); - void Event_LookAtEntity( idEntity *ent, float duration ); - void Event_PreventPain( float duration ); - void Event_DisablePain( void ); - void Event_EnablePain( void ); - void Event_GetPainAnim( void ); - void Event_StopAnim( int channel, int frames ); - void Event_PlayAnim( int channel, const char *name ); - void Event_PlayCycle( int channel, const char *name ); - void Event_IdleAnim( int channel, const char *name ); - void Event_SetSyncedAnimWeight( int channel, int anim, float weight ); - void Event_OverrideAnim( int channel ); - void Event_EnableAnim( int channel, int blendFrames ); - void Event_SetBlendFrames( int channel, int blendFrames ); - void Event_GetBlendFrames( int channel ); - void Event_AnimState( int channel, const char *name, int blendFrames ); - void Event_GetAnimState( int channel ); - void Event_InAnimState( int channel, const char *name ); - void Event_FinishAction( const char *name ); - void Event_AnimDone( int channel, int blendFrames ); - void Event_HasAnim( int channel, const char *name ); - void Event_CheckAnim( int channel, const char *animname ); - void Event_ChooseAnim( int channel, const char *animname ); - void Event_AnimLength( int channel, const char *animname ); - void Event_AnimDistance( int channel, const char *animname ); - void Event_HasEnemies( void ); - void Event_NextEnemy( idEntity *ent ); - void Event_ClosestEnemyToPoint( const idVec3 &pos ); - void Event_StopSound( int channel, int netsync ); - void Event_SetNextState( const char *name ); - void Event_SetState( const char *name ); - void Event_GetState( void ); - void Event_GetHead( void ); -#ifdef _D3XP - void Event_SetDamageGroupScale( const char* groupName, float scale); - void Event_SetDamageGroupScaleAll( float scale ); - void Event_GetDamageGroupScale( const char* groupName ); - void Event_SetDamageCap( float _damageCap ); - void Event_SetWaitState( const char* waitState); - void Event_GetWaitState(); - -#endif -}; - -#endif /* !__GAME_ACTOR_H__ */ diff --git a/d3xp/BrittleFracture.cpp b/d3xp/BrittleFracture.cpp deleted file mode 100644 index d05022a2..00000000 --- a/d3xp/BrittleFracture.cpp +++ /dev/null @@ -1,1382 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "framework/DeclEntityDef.h" -#include "renderer/ModelManager.h" - -#include "Fx.h" - -#include "BrittleFracture.h" - -CLASS_DECLARATION( idEntity, idBrittleFracture ) - EVENT( EV_Activate, idBrittleFracture::Event_Activate ) - EVENT( EV_Touch, idBrittleFracture::Event_Touch ) -END_CLASS - -const int SHARD_ALIVE_TIME = 5000; -const int SHARD_FADE_START = 2000; - -static const char *brittleFracture_SnapshotName = "_BrittleFracture_Snapshot_"; - -/* -================ -idBrittleFracture::idBrittleFracture -================ -*/ -idBrittleFracture::idBrittleFracture( void ) { - material = NULL; - decalMaterial = NULL; - decalSize = 0.0f; - maxShardArea = 0.0f; - maxShatterRadius = 0.0f; - minShatterRadius = 0.0f; - linearVelocityScale = 0.0f; - angularVelocityScale = 0.0f; - shardMass = 0.0f; - density = 0.0f; - friction = 0.0f; - bouncyness = 0.0f; - fxFracture.Clear(); - - bounds.Clear(); - disableFracture = false; - - lastRenderEntityUpdate = -1; - changed = false; - - fl.networkSync = true; - -#ifdef _D3XP - isXraySurface = false; -#endif -} - -/* -================ -idBrittleFracture::~idBrittleFracture -================ -*/ -idBrittleFracture::~idBrittleFracture( void ) { - int i; - - for ( i = 0; i < shards.Num(); i++ ) { - shards[i]->decals.DeleteContents( true ); - delete shards[i]; - } - - // make sure the render entity is freed before the model is freed - FreeModelDef(); - renderModelManager->FreeModel( renderEntity.hModel ); -} - -/* -================ -idBrittleFracture::Save -================ -*/ -void idBrittleFracture::Save( idSaveGame *savefile ) const { - int i, j; - - savefile->WriteInt( health ); - entityFlags_s flags = fl; - LittleBitField( &flags, sizeof( flags ) ); - savefile->Write( &flags, sizeof( flags ) ); - - // setttings - savefile->WriteMaterial( material ); - savefile->WriteMaterial( decalMaterial ); - savefile->WriteFloat( decalSize ); - savefile->WriteFloat( maxShardArea ); - savefile->WriteFloat( maxShatterRadius ); - savefile->WriteFloat( minShatterRadius ); - savefile->WriteFloat( linearVelocityScale ); - savefile->WriteFloat( angularVelocityScale ); - savefile->WriteFloat( shardMass ); - savefile->WriteFloat( density ); - savefile->WriteFloat( friction ); - savefile->WriteFloat( bouncyness ); - savefile->WriteString( fxFracture ); - - // state - savefile->WriteBounds( bounds ); - savefile->WriteBool( disableFracture ); - - savefile->WriteInt( lastRenderEntityUpdate ); - savefile->WriteBool( changed ); - - savefile->WriteStaticObject( physicsObj ); - - savefile->WriteInt( shards.Num() ); - for ( i = 0; i < shards.Num(); i++ ) { - savefile->WriteWinding( shards[i]->winding ); - - savefile->WriteInt( shards[i]->decals.Num() ); - for ( j = 0; j < shards[i]->decals.Num(); j++ ) { - savefile->WriteWinding( *shards[i]->decals[j] ); - } - - savefile->WriteInt( shards[i]->neighbours.Num() ); - for ( j = 0; j < shards[i]->neighbours.Num(); j++ ) { - int index = shards.FindIndex(shards[i]->neighbours[j]); - assert(index != -1); - savefile->WriteInt( index ); - } - - savefile->WriteInt( shards[i]->edgeHasNeighbour.Num() ); - for ( j = 0; j < shards[i]->edgeHasNeighbour.Num(); j++ ) { - savefile->WriteBool( shards[i]->edgeHasNeighbour[j] ); - } - - savefile->WriteInt( shards[i]->droppedTime ); - savefile->WriteInt( shards[i]->islandNum ); - savefile->WriteBool( shards[i]->atEdge ); - savefile->WriteStaticObject( shards[i]->physicsObj ); - } - -#ifdef _D3XP - savefile->WriteBool( isXraySurface ); -#endif -} - -/* -================ -idBrittleFracture::Restore -================ -*/ -void idBrittleFracture::Restore( idRestoreGame *savefile ) { - int i, j , num; - - renderEntity.hModel = renderModelManager->AllocModel(); - renderEntity.hModel->InitEmpty( brittleFracture_SnapshotName ); - renderEntity.callback = idBrittleFracture::ModelCallback; - renderEntity.noShadow = true; - renderEntity.noSelfShadow = true; - renderEntity.noDynamicInteractions = false; - - savefile->ReadInt( health ); - savefile->Read( &fl, sizeof( fl ) ); - LittleBitField( &fl, sizeof( fl ) ); - - // setttings - savefile->ReadMaterial( material ); - savefile->ReadMaterial( decalMaterial ); - savefile->ReadFloat( decalSize ); - savefile->ReadFloat( maxShardArea ); - savefile->ReadFloat( maxShatterRadius ); - savefile->ReadFloat( minShatterRadius ); - savefile->ReadFloat( linearVelocityScale ); - savefile->ReadFloat( angularVelocityScale ); - savefile->ReadFloat( shardMass ); - savefile->ReadFloat( density ); - savefile->ReadFloat( friction ); - savefile->ReadFloat( bouncyness ); - savefile->ReadString( fxFracture ); - - // state - savefile->ReadBounds(bounds); - savefile->ReadBool( disableFracture ); - - savefile->ReadInt( lastRenderEntityUpdate ); - savefile->ReadBool( changed ); - - savefile->ReadStaticObject( physicsObj ); - RestorePhysics( &physicsObj ); - - savefile->ReadInt( num ); - shards.SetNum( num ); - for ( i = 0; i < num; i++ ) { - shards[i] = new shard_t; - } - - for ( i = 0; i < num; i++ ) { - savefile->ReadWinding( shards[i]->winding ); - - savefile->ReadInt( j ); - shards[i]->decals.SetNum( j ); - for ( j = 0; j < shards[i]->decals.Num(); j++ ) { - shards[i]->decals[j] = new idFixedWinding; - savefile->ReadWinding( *shards[i]->decals[j] ); - } - - savefile->ReadInt( j ); - shards[i]->neighbours.SetNum( j ); - for ( j = 0; j < shards[i]->neighbours.Num(); j++ ) { - int index; - savefile->ReadInt( index ); - assert(index != -1); - shards[i]->neighbours[j] = shards[index]; - } - - savefile->ReadInt( j ); - shards[i]->edgeHasNeighbour.SetNum( j ); - for ( j = 0; j < shards[i]->edgeHasNeighbour.Num(); j++ ) { - savefile->ReadBool( shards[i]->edgeHasNeighbour[j] ); - } - - savefile->ReadInt( shards[i]->droppedTime ); - savefile->ReadInt( shards[i]->islandNum ); - savefile->ReadBool( shards[i]->atEdge ); - savefile->ReadStaticObject( shards[i]->physicsObj ); - if ( shards[i]->droppedTime < 0 ) { - shards[i]->clipModel = physicsObj.GetClipModel( i ); - } else { - shards[i]->clipModel = shards[i]->physicsObj.GetClipModel(); - } - } - -#ifdef _D3XP - savefile->ReadBool( isXraySurface ); -#endif -} - -/* -================ -idBrittleFracture::Spawn -================ -*/ -void idBrittleFracture::Spawn( void ) { - - // get shard properties - decalMaterial = declManager->FindMaterial( spawnArgs.GetString( "mtr_decal" ) ); - decalSize = spawnArgs.GetFloat( "decalSize", "40" ); - maxShardArea = spawnArgs.GetFloat( "maxShardArea", "200" ); - maxShardArea = idMath::ClampFloat( 100, 10000, maxShardArea ); - maxShatterRadius = spawnArgs.GetFloat( "maxShatterRadius", "40" ); - minShatterRadius = spawnArgs.GetFloat( "minShatterRadius", "10" ); - linearVelocityScale = spawnArgs.GetFloat( "linearVelocityScale", "0.1" ); - angularVelocityScale = spawnArgs.GetFloat( "angularVelocityScale", "40" ); - fxFracture = spawnArgs.GetString( "fx" ); - - // get rigid body properties - shardMass = spawnArgs.GetFloat( "shardMass", "20" ); - shardMass = idMath::ClampFloat( 0.001f, 1000.0f, shardMass ); - spawnArgs.GetFloat( "density", "0.1", density ); - density = idMath::ClampFloat( 0.001f, 1000.0f, density ); - spawnArgs.GetFloat( "friction", "0.4", friction ); - friction = idMath::ClampFloat( 0.0f, 1.0f, friction ); - spawnArgs.GetFloat( "bouncyness", "0.01", bouncyness ); - bouncyness = idMath::ClampFloat( 0.0f, 1.0f, bouncyness ); - - disableFracture = spawnArgs.GetBool( "disableFracture", "0" ); - health = spawnArgs.GetInt( "health", "40" ); - fl.takedamage = true; - - // FIXME: set "bleed" so idProjectile calls AddDamageEffect - spawnArgs.SetBool( "bleed", 1 ); - -#ifdef _D3XP - // check for xray surface - if ( 1 ) { - const idRenderModel *model = renderEntity.hModel; - - isXraySurface = false; - - for ( int i = 0; i < model->NumSurfaces(); i++ ) { - const modelSurface_t *surf = model->Surface( i ); - - if ( idStr( surf->shader->GetName() ) == "textures/smf/window_scratch" ) { - isXraySurface = true; - break; - } - } - } -#endif - - CreateFractures( renderEntity.hModel ); - - FindNeighbours(); - - renderEntity.hModel = renderModelManager->AllocModel(); - renderEntity.hModel->InitEmpty( brittleFracture_SnapshotName ); - renderEntity.callback = idBrittleFracture::ModelCallback; - renderEntity.noShadow = true; - renderEntity.noSelfShadow = true; - renderEntity.noDynamicInteractions = false; -} - -/* -================ -idBrittleFracture::AddShard -================ -*/ -void idBrittleFracture::AddShard( idClipModel *clipModel, idFixedWinding &w ) { - shard_t *shard = new shard_t; - shard->clipModel = clipModel; - shard->droppedTime = -1; - shard->winding = w; - shard->decals.Clear(); - shard->edgeHasNeighbour.AssureSize( w.GetNumPoints(), false ); - shard->neighbours.Clear(); - shard->atEdge = false; - shards.Append( shard ); -} - -/* -================ -idBrittleFracture::RemoveShard -================ -*/ -void idBrittleFracture::RemoveShard( int index ) { - int i; - - delete shards[index]; - shards.RemoveIndex( index ); - physicsObj.RemoveIndex( index ); - - for ( i = index; i < shards.Num(); i++ ) { - shards[i]->clipModel->SetId( i ); - } -} - -/* -================ -idBrittleFracture::UpdateRenderEntity -================ -*/ -bool idBrittleFracture::UpdateRenderEntity( renderEntity_s *renderEntity, const renderView_t *renderView ) const { - int i, j, k, n, msec, numTris, numDecalTris; - float fade; - dword packedColor; - srfTriangles_t *tris, *decalTris; - modelSurface_t surface; - idDrawVert *v; - idPlane plane; - idMat3 tangents; - - // this may be triggered by a model trace or other non-view related source, - // to which we should look like an empty model - if ( !renderView ) { - return false; - } - - // don't regenerate it if it is current - if ( lastRenderEntityUpdate == gameLocal.time || !changed ) { - return false; - } - - lastRenderEntityUpdate = gameLocal.time; - changed = false; - - numTris = 0; - numDecalTris = 0; - for ( i = 0; i < shards.Num(); i++ ) { - n = shards[i]->winding.GetNumPoints(); - if ( n > 2 ) { - numTris += n - 2; - } - for ( k = 0; k < shards[i]->decals.Num(); k++ ) { - n = shards[i]->decals[k]->GetNumPoints(); - if ( n > 2 ) { - numDecalTris += n - 2; - } - } - } - - // FIXME: re-use model surfaces - renderEntity->hModel->InitEmpty( brittleFracture_SnapshotName ); - - // allocate triangle surfaces for the fractures and decals - tris = renderEntity->hModel->AllocSurfaceTriangles( numTris * 3, material->ShouldCreateBackSides() ? numTris * 6 : numTris * 3 ); - decalTris = renderEntity->hModel->AllocSurfaceTriangles( numDecalTris * 3, decalMaterial->ShouldCreateBackSides() ? numDecalTris * 6 : numDecalTris * 3 ); - - for ( i = 0; i < shards.Num(); i++ ) { - const idVec3 &origin = shards[i]->clipModel->GetOrigin(); - const idMat3 &axis = shards[i]->clipModel->GetAxis(); - - fade = 1.0f; - if ( shards[i]->droppedTime >= 0 ) { - msec = gameLocal.time - shards[i]->droppedTime - SHARD_FADE_START; - if ( msec > 0 ) { - fade = 1.0f - (float) msec / ( SHARD_ALIVE_TIME - SHARD_FADE_START ); - } - } - packedColor = PackColor( idVec4( renderEntity->shaderParms[ SHADERPARM_RED ] * fade, - renderEntity->shaderParms[ SHADERPARM_GREEN ] * fade, - renderEntity->shaderParms[ SHADERPARM_BLUE ] * fade, - fade ) ); - - const idWinding &winding = shards[i]->winding; - - winding.GetPlane( plane ); - tangents = ( plane.Normal() * axis ).ToMat3(); - - for ( j = 2; j < winding.GetNumPoints(); j++ ) { - - v = &tris->verts[tris->numVerts++]; - v->Clear(); - v->xyz = origin + winding[0].ToVec3() * axis; - v->st[0] = winding[0].s; - v->st[1] = winding[0].t; - v->normal = tangents[0]; - v->tangents[0] = tangents[1]; - v->tangents[1] = tangents[2]; - v->SetColor( packedColor ); - - v = &tris->verts[tris->numVerts++]; - v->Clear(); - v->xyz = origin + winding[j-1].ToVec3() * axis; - v->st[0] = winding[j-1].s; - v->st[1] = winding[j-1].t; - v->normal = tangents[0]; - v->tangents[0] = tangents[1]; - v->tangents[1] = tangents[2]; - v->SetColor( packedColor ); - - v = &tris->verts[tris->numVerts++]; - v->Clear(); - v->xyz = origin + winding[j].ToVec3() * axis; - v->st[0] = winding[j].s; - v->st[1] = winding[j].t; - v->normal = tangents[0]; - v->tangents[0] = tangents[1]; - v->tangents[1] = tangents[2]; - v->SetColor( packedColor ); - - tris->indexes[tris->numIndexes++] = tris->numVerts - 3; - tris->indexes[tris->numIndexes++] = tris->numVerts - 2; - tris->indexes[tris->numIndexes++] = tris->numVerts - 1; - - if ( material->ShouldCreateBackSides() ) { - - tris->indexes[tris->numIndexes++] = tris->numVerts - 2; - tris->indexes[tris->numIndexes++] = tris->numVerts - 3; - tris->indexes[tris->numIndexes++] = tris->numVerts - 1; - } - } - - for ( k = 0; k < shards[i]->decals.Num(); k++ ) { - const idWinding &decalWinding = *shards[i]->decals[k]; - - for ( j = 2; j < decalWinding.GetNumPoints(); j++ ) { - - v = &decalTris->verts[decalTris->numVerts++]; - v->Clear(); - v->xyz = origin + decalWinding[0].ToVec3() * axis; - v->st[0] = decalWinding[0].s; - v->st[1] = decalWinding[0].t; - v->normal = tangents[0]; - v->tangents[0] = tangents[1]; - v->tangents[1] = tangents[2]; - v->SetColor( packedColor ); - - v = &decalTris->verts[decalTris->numVerts++]; - v->Clear(); - v->xyz = origin + decalWinding[j-1].ToVec3() * axis; - v->st[0] = decalWinding[j-1].s; - v->st[1] = decalWinding[j-1].t; - v->normal = tangents[0]; - v->tangents[0] = tangents[1]; - v->tangents[1] = tangents[2]; - v->SetColor( packedColor ); - - v = &decalTris->verts[decalTris->numVerts++]; - v->Clear(); - v->xyz = origin + decalWinding[j].ToVec3() * axis; - v->st[0] = decalWinding[j].s; - v->st[1] = decalWinding[j].t; - v->normal = tangents[0]; - v->tangents[0] = tangents[1]; - v->tangents[1] = tangents[2]; - v->SetColor( packedColor ); - - decalTris->indexes[decalTris->numIndexes++] = decalTris->numVerts - 3; - decalTris->indexes[decalTris->numIndexes++] = decalTris->numVerts - 2; - decalTris->indexes[decalTris->numIndexes++] = decalTris->numVerts - 1; - - if ( decalMaterial->ShouldCreateBackSides() ) { - - decalTris->indexes[decalTris->numIndexes++] = decalTris->numVerts - 2; - decalTris->indexes[decalTris->numIndexes++] = decalTris->numVerts - 3; - decalTris->indexes[decalTris->numIndexes++] = decalTris->numVerts - 1; - } - } - } - } - - tris->tangentsCalculated = true; - decalTris->tangentsCalculated = true; - - SIMDProcessor->MinMax( tris->bounds[0], tris->bounds[1], tris->verts, tris->numVerts ); - SIMDProcessor->MinMax( decalTris->bounds[0], decalTris->bounds[1], decalTris->verts, decalTris->numVerts ); - - memset( &surface, 0, sizeof( surface ) ); - surface.shader = material; - surface.id = 0; - surface.geometry = tris; - renderEntity->hModel->AddSurface( surface ); - - memset( &surface, 0, sizeof( surface ) ); - surface.shader = decalMaterial; - surface.id = 1; - surface.geometry = decalTris; - renderEntity->hModel->AddSurface( surface ); - - return true; -} - -/* -================ -idBrittleFracture::ModelCallback -================ -*/ -bool idBrittleFracture::ModelCallback( renderEntity_s *renderEntity, const renderView_t *renderView ) { - const idBrittleFracture *ent; - - ent = static_cast(gameLocal.entities[ renderEntity->entityNum ]); - if ( !ent ) { - gameLocal.Error( "idBrittleFracture::ModelCallback: callback with NULL game entity" ); - } - - return ent->UpdateRenderEntity( renderEntity, renderView ); -} - -/* -================ -idBrittleFracture::Present -================ -*/ -void idBrittleFracture::Present() { - - // don't present to the renderer if the entity hasn't changed - if ( !( thinkFlags & TH_UPDATEVISUALS ) ) { - return; - } - BecomeInactive( TH_UPDATEVISUALS ); - - renderEntity.bounds = bounds; - renderEntity.origin.Zero(); - renderEntity.axis.Identity(); - - // force an update because the bounds/origin/axis may stay the same while the model changes - renderEntity.forceUpdate = true; - - // add to refresh list - if ( modelDefHandle == -1 ) { - modelDefHandle = gameRenderWorld->AddEntityDef( &renderEntity ); - } else { - gameRenderWorld->UpdateEntityDef( modelDefHandle, &renderEntity ); - } - - changed = true; -} - -/* -================ -idBrittleFracture::Think -================ -*/ -void idBrittleFracture::Think( void ) { - int i, startTime, endTime, droppedTime; - shard_t *shard; - bool atRest = true, fading = false; - - // remove overdue shards - for ( i = 0; i < shards.Num(); i++ ) { - droppedTime = shards[i]->droppedTime; - if ( droppedTime != -1 ) { - if ( gameLocal.time - droppedTime > SHARD_ALIVE_TIME ) { - RemoveShard( i ); - i--; - } - fading = true; - } - } - - // remove the entity when nothing is visible - if ( !shards.Num() ) { - PostEventMS( &EV_Remove, 0 ); - return; - } - - if ( thinkFlags & TH_PHYSICS ) { - - startTime = gameLocal.previousTime; - endTime = gameLocal.time; - - // run physics on shards - for ( i = 0; i < shards.Num(); i++ ) { - shard = shards[i]; - - if ( shard->droppedTime == -1 ) { - continue; - } - - shard->physicsObj.Evaluate( endTime - startTime, endTime ); - - if ( !shard->physicsObj.IsAtRest() ) { - atRest = false; - } - } - - if ( atRest ) { - BecomeInactive( TH_PHYSICS ); - } else { - BecomeActive( TH_PHYSICS ); - } - } - - if ( !atRest || bounds.IsCleared() ) { - bounds.Clear(); - for ( i = 0; i < shards.Num(); i++ ) { - bounds.AddBounds( shards[i]->clipModel->GetAbsBounds() ); - } - } - - if ( fading ) { - BecomeActive( TH_UPDATEVISUALS | TH_THINK ); - } else { - BecomeInactive( TH_THINK ); - } - - RunPhysics(); - Present(); -} - -/* -================ -idBrittleFracture::ApplyImpulse -================ -*/ -void idBrittleFracture::ApplyImpulse( idEntity *ent, int id, const idVec3 &point, const idVec3 &impulse ) { - - if ( id < 0 || id >= shards.Num() ) { - return; - } - - if ( shards[id]->droppedTime != -1 ) { - shards[id]->physicsObj.ApplyImpulse( 0, point, impulse ); - } else if ( health <= 0 && !disableFracture ) { - Shatter( point, impulse, gameLocal.time ); - } -} - -/* -================ -idBrittleFracture::AddForce -================ -*/ -void idBrittleFracture::AddForce( idEntity *ent, int id, const idVec3 &point, const idVec3 &force ) { - - if ( id < 0 || id >= shards.Num() ) { - return; - } - - if ( shards[id]->droppedTime != -1 ) { - shards[id]->physicsObj.AddForce( 0, point, force ); - } else if ( health <= 0 && !disableFracture ) { - Shatter( point, force, gameLocal.time ); - } -} - -/* -================ -idBrittleFracture::ProjectDecal -================ -*/ -void idBrittleFracture::ProjectDecal( const idVec3 &point, const idVec3 &dir, const int time, const char *damageDefName ) { - int i, j, bits, clipBits; - float a, c, s; - idVec2 st[MAX_POINTS_ON_WINDING]; - idVec3 origin; - idMat3 axis, axistemp; - idPlane textureAxis[2]; - - if ( gameLocal.isServer ) { - idBitMsg msg; - byte msgBuf[MAX_EVENT_PARAM_SIZE]; - - msg.Init( msgBuf, sizeof( msgBuf ) ); - msg.BeginWriting(); - msg.WriteFloat( point[0] ); - msg.WriteFloat( point[1] ); - msg.WriteFloat( point[2] ); - msg.WriteFloat( dir[0] ); - msg.WriteFloat( dir[1] ); - msg.WriteFloat( dir[2] ); - ServerSendEvent( EVENT_PROJECT_DECAL, &msg, true, -1 ); - } - - if ( time >= gameLocal.time ) { - // try to get the sound from the damage def - const idDeclEntityDef *damageDef = NULL; - const idSoundShader *sndShader = NULL; - if ( damageDefName ) { - damageDef = gameLocal.FindEntityDef( damageDefName, false ); - if ( damageDef ) { - sndShader = declManager->FindSound( damageDef->dict.GetString( "snd_shatter", "" ) ); - } - } - - if ( sndShader ) { - StartSoundShader( sndShader, SND_CHANNEL_ANY, 0, false, NULL ); - } else { - StartSound( "snd_bullethole", SND_CHANNEL_ANY, 0, false, NULL ); - } - } - - a = gameLocal.random.RandomFloat() * idMath::TWO_PI; - c = cos( a ); - s = -sin( a ); - - axis[2] = -dir; - axis[2].Normalize(); - axis[2].NormalVectors( axistemp[0], axistemp[1] ); - axis[0] = axistemp[ 0 ] * c + axistemp[ 1 ] * s; - axis[1] = axistemp[ 0 ] * s + axistemp[ 1 ] * -c; - - textureAxis[0] = axis[0] * ( 1.0f / decalSize ); - textureAxis[0][3] = -( point * textureAxis[0].Normal() ) + 0.5f; - - textureAxis[1] = axis[1] * ( 1.0f / decalSize ); - textureAxis[1][3] = -( point * textureAxis[1].Normal() ) + 0.5f; - - for ( i = 0; i < shards.Num(); i++ ) { - idFixedWinding &winding = shards[i]->winding; - origin = shards[i]->clipModel->GetOrigin(); - axis = shards[i]->clipModel->GetAxis(); - float d0, d1; - - clipBits = -1; - for ( j = 0; j < winding.GetNumPoints(); j++ ) { - idVec3 p = origin + winding[j].ToVec3() * axis; - - st[j].x = d0 = textureAxis[0].Distance( p ); - st[j].y = d1 = textureAxis[1].Distance( p ); - - bits = FLOATSIGNBITSET( d0 ); - d0 = 1.0f - d0; - bits |= FLOATSIGNBITSET( d1 ) << 2; - d1 = 1.0f - d1; - bits |= FLOATSIGNBITSET( d0 ) << 1; - bits |= FLOATSIGNBITSET( d1 ) << 3; - - clipBits &= bits; - } - - if ( clipBits ) { - continue; - } - - idFixedWinding *decal = new idFixedWinding; - shards[i]->decals.Append( decal ); - - decal->SetNumPoints( winding.GetNumPoints() ); - for ( j = 0; j < winding.GetNumPoints(); j++ ) { - (*decal)[j].ToVec3() = winding[j].ToVec3(); - (*decal)[j].s = st[j].x; - (*decal)[j].t = st[j].y; - } - } - - BecomeActive( TH_UPDATEVISUALS ); -} - -/* -================ -idBrittleFracture::DropShard -================ -*/ -void idBrittleFracture::DropShard( shard_t *shard, const idVec3 &point, const idVec3 &dir, const float impulse, const int time ) { - int i, j, clipModelId; - float dist, f; - idVec3 dir2, origin; - idMat3 axis; - shard_t *neighbour; - - // don't display decals on dropped shards - shard->decals.DeleteContents( true ); - - // remove neighbour pointers of neighbours pointing to this shard - for ( i = 0; i < shard->neighbours.Num(); i++ ) { - neighbour = shard->neighbours[i]; - for ( j = 0; j < neighbour->neighbours.Num(); j++ ) { - if ( neighbour->neighbours[j] == shard ) { - neighbour->neighbours.RemoveIndex( j ); - break; - } - } - } - - // remove neighbour pointers - shard->neighbours.Clear(); - - // remove the clip model from the static physics object - clipModelId = shard->clipModel->GetId(); - physicsObj.SetClipModel( NULL, 1.0f, clipModelId, false ); - - origin = shard->clipModel->GetOrigin(); - axis = shard->clipModel->GetAxis(); - - // set the dropped time for fading - shard->droppedTime = time; - - dir2 = origin - point; - dist = dir2.Normalize(); - f = dist > maxShatterRadius ? 1.0f : idMath::Sqrt( dist - minShatterRadius ) * ( 1.0f / idMath::Sqrt( maxShatterRadius - minShatterRadius ) ); - - // setup the physics - shard->physicsObj.SetSelf( this ); - shard->physicsObj.SetClipModel( shard->clipModel, density ); - shard->physicsObj.SetMass( shardMass ); - shard->physicsObj.SetOrigin( origin ); - shard->physicsObj.SetAxis( axis ); - shard->physicsObj.SetBouncyness( bouncyness ); - shard->physicsObj.SetFriction( 0.6f, 0.6f, friction ); - shard->physicsObj.SetGravity( gameLocal.GetGravity() ); - shard->physicsObj.SetContents( CONTENTS_RENDERMODEL ); - shard->physicsObj.SetClipMask( MASK_SOLID | CONTENTS_MOVEABLECLIP ); - shard->physicsObj.ApplyImpulse( 0, origin, impulse * linearVelocityScale * dir ); - shard->physicsObj.SetAngularVelocity( dir.Cross( dir2 ) * ( f * angularVelocityScale ) ); - - shard->clipModel->SetId( clipModelId ); - - BecomeActive( TH_PHYSICS ); -} - -/* -================ -idBrittleFracture::Shatter -================ -*/ -void idBrittleFracture::Shatter( const idVec3 &point, const idVec3 &impulse, const int time ) { - int i; - idVec3 dir; - shard_t *shard; - float m; - - if ( gameLocal.isServer ) { - idBitMsg msg; - byte msgBuf[MAX_EVENT_PARAM_SIZE]; - - msg.Init( msgBuf, sizeof( msgBuf ) ); - msg.BeginWriting(); - msg.WriteFloat( point[0] ); - msg.WriteFloat( point[1] ); - msg.WriteFloat( point[2] ); - msg.WriteFloat( impulse[0] ); - msg.WriteFloat( impulse[1] ); - msg.WriteFloat( impulse[2] ); - ServerSendEvent( EVENT_SHATTER, &msg, true, -1 ); - } - - if ( time > ( gameLocal.time - SHARD_ALIVE_TIME ) ) { - StartSound( "snd_shatter", SND_CHANNEL_ANY, 0, false, NULL ); - } - - if ( !IsBroken() ) { - Break(); - } - - if ( fxFracture.Length() ) { - idEntityFx::StartFx( fxFracture, &point, &GetPhysics()->GetAxis(), this, true ); - } - - dir = impulse; - m = dir.Normalize(); - - for ( i = 0; i < shards.Num(); i++ ) { - shard = shards[i]; - - if ( shard->droppedTime != -1 ) { - continue; - } - - if ( ( shard->clipModel->GetOrigin() - point ).LengthSqr() > Square( maxShatterRadius ) ) { - continue; - } - - DropShard( shard, point, dir, m, time ); - } - - DropFloatingIslands( point, impulse, time ); -} - -/* -================ -idBrittleFracture::DropFloatingIslands -================ -*/ -void idBrittleFracture::DropFloatingIslands( const idVec3 &point, const idVec3 &impulse, const int time ) { - int i, j, numIslands; - int queueStart, queueEnd; - shard_t *curShard, *nextShard, **queue; - bool touchesEdge; - idVec3 dir; - - dir = impulse; - dir.Normalize(); - - numIslands = 0; - queue = (shard_t **) _alloca16( shards.Num() * sizeof(shard_t **) ); - for ( i = 0; i < shards.Num(); i++ ) { - shards[i]->islandNum = 0; - } - - for ( i = 0; i < shards.Num(); i++ ) { - - if ( shards[i]->droppedTime != -1 ) { - continue; - } - - if ( shards[i]->islandNum ) { - continue; - } - - queueStart = 0; - queueEnd = 1; - queue[0] = shards[i]; - shards[i]->islandNum = numIslands+1; - touchesEdge = false; - - if ( shards[i]->atEdge ) { - touchesEdge = true; - } - - for ( curShard = queue[queueStart]; queueStart < queueEnd; curShard = queue[++queueStart] ) { - - for ( j = 0; j < curShard->neighbours.Num(); j++ ) { - - nextShard = curShard->neighbours[j]; - - if ( nextShard->droppedTime != -1 ) { - continue; - } - - if ( nextShard->islandNum ) { - continue; - } - - queue[queueEnd++] = nextShard; - nextShard->islandNum = numIslands+1; - - if ( nextShard->atEdge ) { - touchesEdge = true; - } - } - } - numIslands++; - - // if the island is not connected to the world at any edges - if ( !touchesEdge ) { - for ( j = 0; j < queueEnd; j++ ) { - DropShard( queue[j], point, dir, 0.0f, time ); - } - } - } -} - -/* -================ -idBrittleFracture::Break -================ -*/ -void idBrittleFracture::Break( void ) { - fl.takedamage = false; - physicsObj.SetContents( CONTENTS_RENDERMODEL | CONTENTS_TRIGGER ); -} - -/* -================ -idBrittleFracture::IsBroken -================ -*/ -bool idBrittleFracture::IsBroken( void ) const { - return ( fl.takedamage == false ); -} - -/* -================ -idBrittleFracture::Killed -================ -*/ -void idBrittleFracture::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) { - if ( !disableFracture ) { - ActivateTargets( this ); - Break(); - } -} - -/* -================ -idBrittleFracture::AddDamageEffect -================ -*/ -void idBrittleFracture::AddDamageEffect( const trace_t &collision, const idVec3 &velocity, const char *damageDefName ) { - if ( !disableFracture ) { - ProjectDecal( collision.c.point, collision.c.normal, gameLocal.time, damageDefName ); - } -} - -/* -================ -idBrittleFracture::Fracture_r -================ -*/ -void idBrittleFracture::Fracture_r( idFixedWinding &w ) { - int i, j, bestPlane; - float a, c, s, dist, bestDist; - idVec3 origin; - idPlane windingPlane, splitPlanes[2]; - idMat3 axis, axistemp; - idFixedWinding back; - idTraceModel trm; - idClipModel *clipModel; - - while( 1 ) { - origin = w.GetCenter(); - w.GetPlane( windingPlane ); - - if ( w.GetArea() < maxShardArea ) { - break; - } - - // randomly create a split plane - axis[2] = windingPlane.Normal(); -#ifdef _D3XP - if ( isXraySurface ) { - a = idMath::TWO_PI / 2.f; - } - else { - a = gameLocal.random.RandomFloat() * idMath::TWO_PI; - } -#else - a = gameLocal.random.RandomFloat() * idMath::TWO_PI; -#endif - c = cos( a ); - s = -sin( a ); - axis[2].NormalVectors( axistemp[0], axistemp[1] ); - axis[0] = axistemp[ 0 ] * c + axistemp[ 1 ] * s; - axis[1] = axistemp[ 0 ] * s + axistemp[ 1 ] * -c; - - // get the best split plane - bestDist = 0.0f; - bestPlane = 0; - for ( i = 0; i < 2; i++ ) { - splitPlanes[i].SetNormal( axis[i] ); - splitPlanes[i].FitThroughPoint( origin ); - for ( j = 0; j < w.GetNumPoints(); j++ ) { - dist = splitPlanes[i].Distance( w[j].ToVec3() ); - if ( dist > bestDist ) { - bestDist = dist; - bestPlane = i; - } - } - } - - // split the winding - if ( !w.Split( &back, splitPlanes[bestPlane] ) ) { - break; - } - - // recursively create shards for the back winding - Fracture_r( back ); - } - - // translate the winding to it's center - origin = w.GetCenter(); - for ( j = 0; j < w.GetNumPoints(); j++ ) { - w[j].ToVec3() -= origin; - } - w.RemoveEqualPoints(); - - trm.SetupPolygon( w ); - trm.Shrink( CM_CLIP_EPSILON ); - clipModel = new idClipModel( trm ); - - physicsObj.SetClipModel( clipModel, 1.0f, shards.Num() ); - physicsObj.SetOrigin( GetPhysics()->GetOrigin() + origin, shards.Num() ); - physicsObj.SetAxis( GetPhysics()->GetAxis(), shards.Num() ); - - AddShard( clipModel, w ); -} - -/* -================ -idBrittleFracture::CreateFractures -================ -*/ -void idBrittleFracture::CreateFractures( const idRenderModel *renderModel ) { - int i, j, k; - const modelSurface_t *surf; - const idDrawVert *v; - idFixedWinding w; - - if ( !renderModel ) { - return; - } - - physicsObj.SetSelf( this ); - physicsObj.SetOrigin( GetPhysics()->GetOrigin(), 0 ); - physicsObj.SetAxis( GetPhysics()->GetAxis(), 0 ); - -#ifdef _D3XP - if ( isXraySurface ) { - for ( i = 0; i < 1 /*renderModel->NumSurfaces()*/; i++ ) { - surf = renderModel->Surface( i ); - material = surf->shader; - - w.Clear(); - - int k = 0; - v = &surf->geometry->verts[k]; - w.AddPoint( v->xyz ); - w[k].s = v->st[0]; - w[k].t = v->st[1]; - - k = 1; - v = &surf->geometry->verts[k]; - w.AddPoint( v->xyz ); - w[k].s = v->st[0]; - w[k].t = v->st[1]; - - k = 3; - v = &surf->geometry->verts[k]; - w.AddPoint( v->xyz ); - w[k].s = v->st[0]; - w[k].t = v->st[1]; - - k = 2; - v = &surf->geometry->verts[k]; - w.AddPoint( v->xyz ); - w[k].s = v->st[0]; - w[k].t = v->st[1]; - - Fracture_r( w ); - } - - } - else { - for ( i = 0; i < 1 /*renderModel->NumSurfaces()*/; i++ ) { - surf = renderModel->Surface( i ); - material = surf->shader; - - for ( j = 0; j < surf->geometry->numIndexes; j += 3 ) { - w.Clear(); - for ( k = 0; k < 3; k++ ) { - v = &surf->geometry->verts[ surf->geometry->indexes[ j + 2 - k ] ]; - w.AddPoint( v->xyz ); - w[k].s = v->st[0]; - w[k].t = v->st[1]; - } - Fracture_r( w ); - } - } - } -#else - for ( i = 0; i < 1 /*renderModel->NumSurfaces()*/; i++ ) { - surf = renderModel->Surface( i ); - material = surf->shader; - - for ( j = 0; j < surf->geometry->numIndexes; j += 3 ) { - w.Clear(); - for ( k = 0; k < 3; k++ ) { - v = &surf->geometry->verts[ surf->geometry->indexes[ j + 2 - k ] ]; - w.AddPoint( v->xyz ); - w[k].s = v->st[0]; - w[k].t = v->st[1]; - } - Fracture_r( w ); - } - } -#endif - - physicsObj.SetContents( material->GetContentFlags() ); - SetPhysics( &physicsObj ); -} - -/* -================ -idBrittleFracture::FindNeighbours -================ -*/ -void idBrittleFracture::FindNeighbours( void ) { - int i, j, k, l; - idVec3 p1, p2, dir; - idMat3 axis; - idPlane plane[4]; - - for ( i = 0; i < shards.Num(); i++ ) { - - shard_t *shard1 = shards[i]; - const idWinding &w1 = shard1->winding; - const idVec3 &origin1 = shard1->clipModel->GetOrigin(); - const idMat3 &axis1 = shard1->clipModel->GetAxis(); - - for ( k = 0; k < w1.GetNumPoints(); k++ ) { - - p1 = origin1 + w1[k].ToVec3() * axis1; - p2 = origin1 + w1[(k+1)%w1.GetNumPoints()].ToVec3() * axis1; - dir = p2 - p1; - dir.Normalize(); - axis = dir.ToMat3(); - - plane[0].SetNormal( dir ); - plane[0].FitThroughPoint( p1 ); - plane[1].SetNormal( -dir ); - plane[1].FitThroughPoint( p2 ); - plane[2].SetNormal( axis[1] ); - plane[2].FitThroughPoint( p1 ); - plane[3].SetNormal( axis[2] ); - plane[3].FitThroughPoint( p1 ); - - for ( j = 0; j < shards.Num(); j++ ) { - - if ( i == j ) { - continue; - } - - shard_t *shard2 = shards[j]; - - for ( l = 0; l < shard1->neighbours.Num(); l++ ) { - if ( shard1->neighbours[l] == shard2 ) { - break; - } - } - if ( l < shard1->neighbours.Num() ) { - continue; - } - - const idWinding &w2 = shard2->winding; - const idVec3 &origin2 = shard2->clipModel->GetOrigin(); - const idMat3 &axis2 = shard2->clipModel->GetAxis(); - - for ( l = w2.GetNumPoints()-1; l >= 0; l-- ) { - p1 = origin2 + w2[l].ToVec3() * axis2; - p2 = origin2 + w2[(l-1+w2.GetNumPoints())%w2.GetNumPoints()].ToVec3() * axis2; - if ( plane[0].Side( p2, 0.1f ) == SIDE_FRONT && plane[1].Side( p1, 0.1f ) == SIDE_FRONT ) { - if ( plane[2].Side( p1, 0.1f ) == SIDE_ON && plane[3].Side( p1, 0.1f ) == SIDE_ON ) { - if ( plane[2].Side( p2, 0.1f ) == SIDE_ON && plane[3].Side( p2, 0.1f ) == SIDE_ON ) { - shard1->neighbours.Append( shard2 ); - shard1->edgeHasNeighbour[k] = true; - shard2->neighbours.Append( shard1 ); - shard2->edgeHasNeighbour[(l-1+w2.GetNumPoints())%w2.GetNumPoints()] = true; - break; - } - } - } - } - } - } - - for ( k = 0; k < w1.GetNumPoints(); k++ ) { - if ( !shard1->edgeHasNeighbour[k] ) { - break; - } - } - if ( k < w1.GetNumPoints() ) { - shard1->atEdge = true; - } else { - shard1->atEdge = false; - } - } -} - -/* -================ -idBrittleFracture::Event_Activate -================ -*/ -void idBrittleFracture::Event_Activate( idEntity *activator ) { - disableFracture = false; - if ( health <= 0 ) { - Break(); - } -} - -/* -================ -idBrittleFracture::Event_Touch -================ -*/ -void idBrittleFracture::Event_Touch( idEntity *other, trace_t *trace ) { - idVec3 point, impulse; - - if ( !IsBroken() ) { - return; - } - - if ( trace->c.id < 0 || trace->c.id >= shards.Num() ) { - return; - } - - point = shards[trace->c.id]->clipModel->GetOrigin(); - impulse = other->GetPhysics()->GetLinearVelocity() * other->GetPhysics()->GetMass(); - - Shatter( point, impulse, gameLocal.time ); -} - -/* -================ -idBrittleFracture::ClientPredictionThink -================ -*/ -void idBrittleFracture::ClientPredictionThink( void ) { - // only think forward because the state is not synced through snapshots - if ( !gameLocal.isNewFrame ) { - return; - } - - Think(); -} - -/* -================ -idBrittleFracture::ClientReceiveEvent -================ -*/ -bool idBrittleFracture::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) { - idVec3 point, dir; - - switch( event ) { - case EVENT_PROJECT_DECAL: { - point[0] = msg.ReadFloat(); - point[1] = msg.ReadFloat(); - point[2] = msg.ReadFloat(); - dir[0] = msg.ReadFloat(); - dir[1] = msg.ReadFloat(); - dir[2] = msg.ReadFloat(); - ProjectDecal( point, dir, time, NULL ); - return true; - } - case EVENT_SHATTER: { - point[0] = msg.ReadFloat(); - point[1] = msg.ReadFloat(); - point[2] = msg.ReadFloat(); - dir[0] = msg.ReadFloat(); - dir[1] = msg.ReadFloat(); - dir[2] = msg.ReadFloat(); - Shatter( point, dir, time ); - return true; - } - default: - break; - } - - return idEntity::ClientReceiveEvent( event, time, msg ); -} diff --git a/d3xp/BrittleFracture.h b/d3xp/BrittleFracture.h deleted file mode 100644 index 0ccc1b0c..00000000 --- a/d3xp/BrittleFracture.h +++ /dev/null @@ -1,138 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __GAME_BRITTLEFRACTURE_H__ -#define __GAME_BRITTLEFRACTURE_H__ - -#include "physics/Physics_RigidBody.h" -#include "physics/Physics_StaticMulti.h" -#include "physics/Clip.h" -#include "Entity.h" - -/* -=============================================================================== - -B-rep Brittle Fracture - Static entity using the boundary representation -of the render model which can fracture. - -=============================================================================== -*/ - -typedef struct shard_s { - idClipModel * clipModel; - idFixedWinding winding; - idList decals; - idList edgeHasNeighbour; - idList neighbours; - idPhysics_RigidBody physicsObj; - int droppedTime; - bool atEdge; - int islandNum; -} shard_t; - - -class idBrittleFracture : public idEntity { - -public: - CLASS_PROTOTYPE( idBrittleFracture ); - - idBrittleFracture( void ); - virtual ~idBrittleFracture( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void Spawn( void ); - - virtual void Present( void ); - virtual void Think( void ); - virtual void ApplyImpulse( idEntity *ent, int id, const idVec3 &point, const idVec3 &impulse ); - virtual void AddForce( idEntity *ent, int id, const idVec3 &point, const idVec3 &force ); - virtual void AddDamageEffect( const trace_t &collision, const idVec3 &velocity, const char *damageDefName ); - virtual void Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ); - - void ProjectDecal( const idVec3 &point, const idVec3 &dir, const int time, const char *damageDefName ); - bool IsBroken( void ) const; - - enum { - EVENT_PROJECT_DECAL = idEntity::EVENT_MAXEVENTS, - EVENT_SHATTER, - EVENT_MAXEVENTS - }; - - virtual void ClientPredictionThink( void ); - virtual bool ClientReceiveEvent( int event, int time, const idBitMsg &msg ); - -private: - // setttings - const idMaterial * material; - const idMaterial * decalMaterial; - float decalSize; - float maxShardArea; - float maxShatterRadius; - float minShatterRadius; - float linearVelocityScale; - float angularVelocityScale; - float shardMass; - float density; - float friction; - float bouncyness; - idStr fxFracture; - -#ifdef _D3XP - bool isXraySurface; -#endif - - // state - idPhysics_StaticMulti physicsObj; - idList shards; - idBounds bounds; - bool disableFracture; - - // for rendering - mutable int lastRenderEntityUpdate; - mutable bool changed; - - bool UpdateRenderEntity( renderEntity_s *renderEntity, const renderView_t *renderView ) const; - static bool ModelCallback( renderEntity_s *renderEntity, const renderView_t *renderView ); - - void AddShard( idClipModel *clipModel, idFixedWinding &w ); - void RemoveShard( int index ); - void DropShard( shard_t *shard, const idVec3 &point, const idVec3 &dir, const float impulse, const int time ); - void Shatter( const idVec3 &point, const idVec3 &impulse, const int time ); - void DropFloatingIslands( const idVec3 &point, const idVec3 &impulse, const int time ); - void Break( void ); - void Fracture_r( idFixedWinding &w ); - void CreateFractures( const idRenderModel *renderModel ); - void FindNeighbours( void ); - - void Event_Activate( idEntity *activator ); - void Event_Touch( idEntity *other, trace_t *trace ); -}; - -#endif /* !__GAME_BRITTLEFRACTURE_H__ */ diff --git a/d3xp/Camera.cpp b/d3xp/Camera.cpp deleted file mode 100644 index dedba94f..00000000 --- a/d3xp/Camera.cpp +++ /dev/null @@ -1,725 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "gamesys/SysCvar.h" -#include "script/Script_Thread.h" -#include "Player.h" - -#include "Camera.h" - -/* -=============================================================================== - - idCamera - - Base class for cameras - -=============================================================================== -*/ - -ABSTRACT_DECLARATION( idEntity, idCamera ) -END_CLASS - -/* -===================== -idCamera::Spawn -===================== -*/ -void idCamera::Spawn( void ) { -} - -/* -===================== -idCamera::GetRenderView -===================== -*/ -renderView_t *idCamera::GetRenderView() { - renderView_t *rv = idEntity::GetRenderView(); - GetViewParms( rv ); - return rv; -} - -/*********************************************************************** - - idCameraView - -***********************************************************************/ -const idEventDef EV_Camera_SetAttachments( "", NULL ); - -CLASS_DECLARATION( idCamera, idCameraView ) - EVENT( EV_Activate, idCameraView::Event_Activate ) - EVENT( EV_Camera_SetAttachments, idCameraView::Event_SetAttachments ) -END_CLASS - - -/* -=============== -idCameraView::idCameraView -================ -*/ -idCameraView::idCameraView() { - fov = 90.0f; - attachedTo = NULL; - attachedView = NULL; -} - -/* -=============== -idCameraView::Save -================ -*/ -void idCameraView::Save( idSaveGame *savefile ) const { - savefile->WriteFloat( fov ); - savefile->WriteObject( attachedTo ); - savefile->WriteObject( attachedView ); -} - -/* -=============== -idCameraView::Restore -================ -*/ -void idCameraView::Restore( idRestoreGame *savefile ) { - savefile->ReadFloat( fov ); - savefile->ReadObject( reinterpret_cast( attachedTo ) ); - savefile->ReadObject( reinterpret_cast( attachedView ) ); -} - -/* -=============== -idCameraView::Event_SetAttachments -================ -*/ -void idCameraView::Event_SetAttachments( ) { - SetAttachment( &attachedTo, "attachedTo" ); - SetAttachment( &attachedView, "attachedView" ); -} - -/* -=============== -idCameraView::Event_Activate -================ -*/ -void idCameraView::Event_Activate( idEntity *activator ) { - if (spawnArgs.GetBool("trigger")) { - if (gameLocal.GetCamera() != this) { - if ( g_debugCinematic.GetBool() ) { - gameLocal.Printf( "%d: '%s' start\n", gameLocal.framenum, GetName() ); - } - - gameLocal.SetCamera(this); - } else { - if ( g_debugCinematic.GetBool() ) { - gameLocal.Printf( "%d: '%s' stop\n", gameLocal.framenum, GetName() ); - } - gameLocal.SetCamera(NULL); - } - } -} - -/* -===================== -idCameraView::Stop -===================== -*/ -void idCameraView::Stop( void ) { - if ( g_debugCinematic.GetBool() ) { - gameLocal.Printf( "%d: '%s' stop\n", gameLocal.framenum, GetName() ); - } - gameLocal.SetCamera(NULL); - ActivateTargets( gameLocal.GetLocalPlayer() ); -} - - -/* -===================== -idCameraView::Spawn -===================== -*/ -void idCameraView::SetAttachment( idEntity **e, const char *p ) { - const char *cam = spawnArgs.GetString( p ); - if ( strlen ( cam ) ) { - *e = gameLocal.FindEntity( cam ); - } -} - - -/* -===================== -idCameraView::Spawn -===================== -*/ -void idCameraView::Spawn( void ) { - // if no target specified use ourself - const char *cam = spawnArgs.GetString("cameraTarget"); - if ( strlen ( cam ) == 0) { - spawnArgs.Set("cameraTarget", spawnArgs.GetString("name")); - } - fov = spawnArgs.GetFloat("fov", "90"); - - PostEventMS( &EV_Camera_SetAttachments, 0 ); - - UpdateChangeableSpawnArgs(NULL); -} - -/* -===================== -idCameraView::GetViewParms -===================== -*/ -void idCameraView::GetViewParms( renderView_t *view ) { - assert( view ); - - if (view == NULL) { - return; - } - - idVec3 dir; - idEntity *ent; - - if ( attachedTo ) { - ent = attachedTo; - } else { - ent = this; - } - - view->vieworg = ent->GetPhysics()->GetOrigin(); - if ( attachedView ) { - dir = attachedView->GetPhysics()->GetOrigin() - view->vieworg; - dir.Normalize(); - view->viewaxis = dir.ToMat3(); - } else { - view->viewaxis = ent->GetPhysics()->GetAxis(); - } - - gameLocal.CalcFov( fov, view->fov_x, view->fov_y ); -} - -/* -=============================================================================== - - idCameraAnim - -=============================================================================== -*/ - -const idEventDef EV_Camera_Start( "start", NULL ); -const idEventDef EV_Camera_Stop( "stop", NULL ); - -CLASS_DECLARATION( idCamera, idCameraAnim ) - EVENT( EV_Thread_SetCallback, idCameraAnim::Event_SetCallback ) - EVENT( EV_Camera_Stop, idCameraAnim::Event_Stop ) - EVENT( EV_Camera_Start, idCameraAnim::Event_Start ) - EVENT( EV_Activate, idCameraAnim::Event_Activate ) -END_CLASS - - -/* -===================== -idCameraAnim::idCameraAnim -===================== -*/ -idCameraAnim::idCameraAnim() { - threadNum = 0; - offset.Zero(); - frameRate = 0; - cycle = 1; - starttime = 0; - activator = NULL; - -} - -/* -===================== -idCameraAnim::~idCameraAnim -===================== -*/ -idCameraAnim::~idCameraAnim() { - if ( gameLocal.GetCamera() == this ) { - gameLocal.SetCamera( NULL ); - } -} - -/* -=============== -idCameraAnim::Save -================ -*/ -void idCameraAnim::Save( idSaveGame *savefile ) const { - savefile->WriteInt( threadNum ); - savefile->WriteVec3( offset ); - savefile->WriteInt( frameRate ); - savefile->WriteInt( starttime ); - savefile->WriteInt( cycle ); - activator.Save( savefile ); -} - -/* -=============== -idCameraAnim::Restore -================ -*/ -void idCameraAnim::Restore( idRestoreGame *savefile ) { - savefile->ReadInt( threadNum ); - savefile->ReadVec3( offset ); - savefile->ReadInt( frameRate ); - savefile->ReadInt( starttime ); - savefile->ReadInt( cycle ); - activator.Restore( savefile ); - - LoadAnim(); -} - -/* -===================== -idCameraAnim::Spawn -===================== -*/ -void idCameraAnim::Spawn( void ) { - if ( spawnArgs.GetVector( "old_origin", "0 0 0", offset ) ) { - offset = GetPhysics()->GetOrigin() - offset; - } else { - offset.Zero(); - } - - // always think during cinematics - cinematic = true; - - LoadAnim(); -} - -/* -================ -idCameraAnim::Load -================ -*/ -void idCameraAnim::LoadAnim( void ) { - int version; - idLexer parser( LEXFL_ALLOWPATHNAMES | LEXFL_NOSTRINGESCAPECHARS | LEXFL_NOSTRINGCONCAT ); - idToken token; - int numFrames; - int numCuts; - int i; - idStr filename; - const char *key; - - key = spawnArgs.GetString( "anim" ); - if ( !key ) { - gameLocal.Error( "Missing 'anim' key on '%s'", name.c_str() ); - } - - filename = spawnArgs.GetString( va( "anim %s", key ) ); - if ( !filename.Length() ) { - gameLocal.Error( "Missing 'anim %s' key on '%s'", key, name.c_str() ); - } - - filename.SetFileExtension( MD5_CAMERA_EXT ); - if ( !parser.LoadFile( filename ) ) { - gameLocal.Error( "Unable to load '%s' on '%s'", filename.c_str(), name.c_str() ); - } - - cameraCuts.Clear(); - cameraCuts.SetGranularity( 1 ); - camera.Clear(); - camera.SetGranularity( 1 ); - - parser.ExpectTokenString( MD5_VERSION_STRING ); - version = parser.ParseInt(); - if ( version != MD5_VERSION ) { - parser.Error( "Invalid version %d. Should be version %d\n", version, MD5_VERSION ); - } - - // skip the commandline - parser.ExpectTokenString( "commandline" ); - parser.ReadToken( &token ); - - // parse num frames - parser.ExpectTokenString( "numFrames" ); - numFrames = parser.ParseInt(); - if ( numFrames <= 0 ) { - parser.Error( "Invalid number of frames: %d", numFrames ); - } - - // parse framerate - parser.ExpectTokenString( "frameRate" ); - frameRate = parser.ParseInt(); - if ( frameRate <= 0 ) { - parser.Error( "Invalid framerate: %d", frameRate ); - } - - // parse num cuts - parser.ExpectTokenString( "numCuts" ); - numCuts = parser.ParseInt(); - if ( ( numCuts < 0 ) || ( numCuts > numFrames ) ) { - parser.Error( "Invalid number of camera cuts: %d", numCuts ); - } - - // parse the camera cuts - parser.ExpectTokenString( "cuts" ); - parser.ExpectTokenString( "{" ); - cameraCuts.SetNum( numCuts ); - for( i = 0; i < numCuts; i++ ) { - cameraCuts[ i ] = parser.ParseInt(); - if ( ( cameraCuts[ i ] < 1 ) || ( cameraCuts[ i ] >= numFrames ) ) { - parser.Error( "Invalid camera cut" ); - } - } - parser.ExpectTokenString( "}" ); - - // parse the camera frames - parser.ExpectTokenString( "camera" ); - parser.ExpectTokenString( "{" ); - camera.SetNum( numFrames ); - for( i = 0; i < numFrames; i++ ) { - parser.Parse1DMatrix( 3, camera[ i ].t.ToFloatPtr() ); - parser.Parse1DMatrix( 3, camera[ i ].q.ToFloatPtr() ); - camera[ i ].fov = parser.ParseFloat(); - } - parser.ExpectTokenString( "}" ); - -#if 0 - if ( !gameLocal.GetLocalPlayer() ) { - return; - } - - idDebugGraph gGraph; - idDebugGraph tGraph; - idDebugGraph qGraph; - idDebugGraph dtGraph; - idDebugGraph dqGraph; - gGraph.SetNumSamples( numFrames ); - tGraph.SetNumSamples( numFrames ); - qGraph.SetNumSamples( numFrames ); - dtGraph.SetNumSamples( numFrames ); - dqGraph.SetNumSamples( numFrames ); - - gameLocal.Printf( "\n\ndelta vec:\n" ); - float diff_t, last_t, t; - float diff_q, last_q, q; - diff_t = last_t = 0.0f; - diff_q = last_q = 0.0f; - for( i = 1; i < numFrames; i++ ) { - t = ( camera[ i ].t - camera[ i - 1 ].t ).Length(); - q = ( camera[ i ].q.ToQuat() - camera[ i - 1 ].q.ToQuat() ).Length(); - diff_t = t - last_t; - diff_q = q - last_q; - gGraph.AddValue( ( i % 10 ) == 0 ); - tGraph.AddValue( t ); - qGraph.AddValue( q ); - dtGraph.AddValue( diff_t ); - dqGraph.AddValue( diff_q ); - - gameLocal.Printf( "%d: %.8f : %.8f, %.8f : %.8f\n", i, t, diff_t, q, diff_q ); - last_t = t; - last_q = q; - } - - gGraph.Draw( colorBlue, 300.0f ); - tGraph.Draw( colorOrange, 60.0f ); - dtGraph.Draw( colorYellow, 6000.0f ); - qGraph.Draw( colorGreen, 60.0f ); - dqGraph.Draw( colorCyan, 6000.0f ); -#endif -} - -/* -=============== -idCameraAnim::Start -================ -*/ -void idCameraAnim::Start( void ) { - cycle = spawnArgs.GetInt( "cycle" ); - if ( !cycle ) { - cycle = 1; - } - - if ( g_debugCinematic.GetBool() ) { - gameLocal.Printf( "%d: '%s' start\n", gameLocal.framenum, GetName() ); - } - - starttime = gameLocal.time; - gameLocal.SetCamera( this ); - BecomeActive( TH_THINK ); - - // if the player has already created the renderview for this frame, have him update it again so that the camera starts this frame - if ( gameLocal.GetLocalPlayer()->GetRenderView()->time == gameLocal.time ) { - gameLocal.GetLocalPlayer()->CalculateRenderView(); - } -} - -/* -===================== -idCameraAnim::Stop -===================== -*/ -void idCameraAnim::Stop( void ) { - if ( gameLocal.GetCamera() == this ) { - if ( g_debugCinematic.GetBool() ) { - gameLocal.Printf( "%d: '%s' stop\n", gameLocal.framenum, GetName() ); - } - - BecomeInactive( TH_THINK ); - gameLocal.SetCamera( NULL ); - if ( threadNum ) { - idThread::ObjectMoveDone( threadNum, this ); - threadNum = 0; - } - ActivateTargets( activator.GetEntity() ); - } -} - -/* -===================== -idCameraAnim::Think -===================== -*/ -void idCameraAnim::Think( void ) { - int frame; - int frameTime; - - if ( thinkFlags & TH_THINK ) { - // check if we're done in the Think function when the cinematic is being skipped (idCameraAnim::GetViewParms isn't called when skipping cinematics). - if ( !gameLocal.skipCinematic ) { - return; - } - - if ( camera.Num() < 2 ) { - // 1 frame anims never end - return; - } - - if ( frameRate == USERCMD_HZ ) { - frameTime = gameLocal.time - starttime; - frame = frameTime / gameLocal.msec; - } else { - frameTime = ( gameLocal.time - starttime ) * frameRate; - frame = frameTime / 1000; - } - - if ( frame > camera.Num() + cameraCuts.Num() - 2 ) { - if ( cycle > 0 ) { - cycle--; - } - - if ( cycle != 0 ) { - // advance start time so that we loop - starttime += ( ( camera.Num() - cameraCuts.Num() ) * 1000 ) / frameRate; - } else { - Stop(); - } - } - } -} - -/* -===================== -idCameraAnim::GetViewParms -===================== -*/ -void idCameraAnim::GetViewParms( renderView_t *view ) { - int realFrame; - int frame; - int frameTime; - float lerp; - float invlerp; - cameraFrame_t *camFrame; - int i; - int cut; - idQuat q1, q2, q3; - - assert( view ); - if ( !view ) { - return; - } - - if ( camera.Num() == 0 ) { - // we most likely are in the middle of a restore - // FIXME: it would be better to fix it so this doesn't get called during a restore - return; - } - -#ifdef _D3XP - SetTimeState ts( timeGroup ); -#endif - - if ( frameRate == USERCMD_HZ ) { - frameTime = gameLocal.time - starttime; - frame = frameTime / gameLocal.msec; - lerp = 0.0f; - } else { - frameTime = ( gameLocal.time - starttime ) * frameRate; - frame = frameTime / 1000; - lerp = ( frameTime % 1000 ) * 0.001f; - } - - // skip any frames where camera cuts occur - realFrame = frame; - cut = 0; - for( i = 0; i < cameraCuts.Num(); i++ ) { - if ( frame < cameraCuts[ i ] ) { - break; - } - frame++; - cut++; - } - - if ( g_debugCinematic.GetBool() ) { - int prevFrameTime = ( gameLocal.time - starttime - gameLocal.msec ) * frameRate; - int prevFrame = prevFrameTime / 1000; - int prevCut; - - prevCut = 0; - for( i = 0; i < cameraCuts.Num(); i++ ) { - if ( prevFrame < cameraCuts[ i ] ) { - break; - } - prevFrame++; - prevCut++; - } - - if ( prevCut != cut ) { - gameLocal.Printf( "%d: '%s' cut %d\n", gameLocal.framenum, GetName(), cut ); - } - } - - // clamp to the first frame. also check if this is a one frame anim. one frame anims would end immediately, - // but since they're mainly used for static cams anyway, just stay on it infinitely. - if ( ( frame < 0 ) || ( camera.Num() < 2 ) ) { - view->viewaxis = camera[ 0 ].q.ToQuat().ToMat3(); - view->vieworg = camera[ 0 ].t + offset; - view->fov_x = camera[ 0 ].fov; - } else if ( frame > camera.Num() - 2 ) { - if ( cycle > 0 ) { - cycle--; - } - - if ( cycle != 0 ) { - // advance start time so that we loop - starttime += ( ( camera.Num() - cameraCuts.Num() ) * 1000 ) / frameRate; - GetViewParms( view ); - return; - } - - Stop(); - if ( gameLocal.GetCamera() != NULL ) { - // we activated another camera when we stopped, so get it's viewparms instead - gameLocal.GetCamera()->GetViewParms( view ); - return; - } else { - // just use our last frame - camFrame = &camera[ camera.Num() - 1 ]; - view->viewaxis = camFrame->q.ToQuat().ToMat3(); - view->vieworg = camFrame->t + offset; - view->fov_x = camFrame->fov; - } - } else if ( lerp == 0.0f ) { - camFrame = &camera[ frame ]; - view->viewaxis = camFrame[ 0 ].q.ToMat3(); - view->vieworg = camFrame[ 0 ].t + offset; - view->fov_x = camFrame[ 0 ].fov; - } else { - camFrame = &camera[ frame ]; - invlerp = 1.0f - lerp; - q1 = camFrame[ 0 ].q.ToQuat(); - q2 = camFrame[ 1 ].q.ToQuat(); - q3.Slerp( q1, q2, lerp ); - view->viewaxis = q3.ToMat3(); - view->vieworg = camFrame[ 0 ].t * invlerp + camFrame[ 1 ].t * lerp + offset; - view->fov_x = camFrame[ 0 ].fov * invlerp + camFrame[ 1 ].fov * lerp; - } - - gameLocal.CalcFov( view->fov_x, view->fov_x, view->fov_y ); - - // setup the pvs for this frame - UpdatePVSAreas( view->vieworg ); - -#if 0 - static int lastFrame = 0; - static idVec3 lastFrameVec( 0.0f, 0.0f, 0.0f ); - if ( gameLocal.time != lastFrame ) { - gameRenderWorld->DebugBounds( colorCyan, idBounds( view->vieworg ).Expand( 16.0f ), vec3_origin, gameLocal.msec ); - gameRenderWorld->DebugLine( colorRed, view->vieworg, view->vieworg + idVec3( 0.0f, 0.0f, 2.0f ), 10000, false ); - gameRenderWorld->DebugLine( colorCyan, lastFrameVec, view->vieworg, 10000, false ); - gameRenderWorld->DebugLine( colorYellow, view->vieworg + view->viewaxis[ 0 ] * 64.0f, view->vieworg + view->viewaxis[ 0 ] * 66.0f, 10000, false ); - gameRenderWorld->DebugLine( colorOrange, view->vieworg + view->viewaxis[ 0 ] * 64.0f, view->vieworg + view->viewaxis[ 0 ] * 64.0f + idVec3( 0.0f, 0.0f, 2.0f ), 10000, false ); - lastFrameVec = view->vieworg; - lastFrame = gameLocal.time; - } -#endif - - if ( g_showcamerainfo.GetBool() ) { - gameLocal.Printf( "^5Frame: ^7%d/%d\n\n\n", realFrame + 1, camera.Num() - cameraCuts.Num() ); - } -} - -/* -=============== -idCameraAnim::Event_Activate -================ -*/ -void idCameraAnim::Event_Activate( idEntity *_activator ) { - activator = _activator; - if ( thinkFlags & TH_THINK ) { - Stop(); - } else { - Start(); - } -} - -/* -=============== -idCameraAnim::Event_Start -================ -*/ -void idCameraAnim::Event_Start( void ) { - Start(); -} - -/* -=============== -idCameraAnim::Event_Stop -================ -*/ -void idCameraAnim::Event_Stop( void ) { - Stop(); -} - -/* -================ -idCameraAnim::Event_SetCallback -================ -*/ -void idCameraAnim::Event_SetCallback( void ) { - if ( ( gameLocal.GetCamera() == this ) && !threadNum ) { - threadNum = idThread::CurrentThreadNum(); - idThread::ReturnInt( true ); - } else { - idThread::ReturnInt( false ); - } -} diff --git a/d3xp/Camera.h b/d3xp/Camera.h deleted file mode 100644 index ee5f5f53..00000000 --- a/d3xp/Camera.h +++ /dev/null @@ -1,135 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __GAME_CAMERA_H__ -#define __GAME_CAMERA_H__ - -#include "idlib/math/Quat.h" - -#include "Entity.h" - -/* -=============================================================================== - -Camera providing an alternative view of the level. - -=============================================================================== -*/ - -class idCamera : public idEntity { -public: - ABSTRACT_PROTOTYPE( idCamera ); - - void Spawn( void ); - virtual void GetViewParms( renderView_t *view ) = 0; - virtual renderView_t * GetRenderView(); - virtual void Stop( void ){} ; -}; - -/* -=============================================================================== - -idCameraView - -=============================================================================== -*/ - -class idCameraView : public idCamera { -public: - CLASS_PROTOTYPE( idCameraView ); - idCameraView(); - - // save games - void Save( idSaveGame *savefile ) const; // archives object for save game file - void Restore( idRestoreGame *savefile ); // unarchives object from save game file - - void Spawn( ); - virtual void GetViewParms( renderView_t *view ); - virtual void Stop( void ); - -protected: - void Event_Activate( idEntity *activator ); - void Event_SetAttachments(); - void SetAttachment( idEntity **e, const char *p ); - float fov; - idEntity *attachedTo; - idEntity *attachedView; -}; - - - -/* -=============================================================================== - -A camera which follows a path defined by an animation. - -=============================================================================== -*/ - -typedef struct { - idCQuat q; - idVec3 t; - float fov; -} cameraFrame_t; - -class idCameraAnim : public idCamera { -public: - CLASS_PROTOTYPE( idCameraAnim ); - - idCameraAnim(); - ~idCameraAnim(); - - // save games - void Save( idSaveGame *savefile ) const; // archives object for save game file - void Restore( idRestoreGame *savefile ); // unarchives object from save game file - - void Spawn( void ); - virtual void GetViewParms( renderView_t *view ); - -private: - int threadNum; - idVec3 offset; - int frameRate; - int starttime; - int cycle; - idList cameraCuts; - idList camera; - idEntityPtr activator; - - void Start( void ); - void Stop( void ); - void Think( void ); - - void LoadAnim( void ); - void Event_Start( void ); - void Event_Stop( void ); - void Event_SetCallback( void ); - void Event_Activate( idEntity *activator ); -}; - -#endif /* !__GAME_CAMERA_H__ */ diff --git a/d3xp/EndLevel.cpp b/d3xp/EndLevel.cpp deleted file mode 100644 index f6c03b99..00000000 --- a/d3xp/EndLevel.cpp +++ /dev/null @@ -1,187 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -// NOTE: even though this file is part of the Doom3 GPL source (and the original SDK in d3xp/), -// it has never been part of the build (=> not compiled into d3xp.dll) - -#include "sys/platform.h" - -#include "EndLevel.h" - -/* - - game_endlevel.cpp - - This entity is targeted to complete a level, and it also handles - running the stats and moving the camera. - -*/ - - -CLASS_DECLARATION( idEntity, idTarget_EndLevel ) - EVENT( EV_Activate, idTarget_EndLevel::Event_Trigger ) -END_CLASS - -/* -================ -idTarget_EndLevel::Spawn -================ -*/ -void idTarget_EndLevel::Spawn( void ) { - idStr guiName; - - gui = NULL; - noGui = spawnArgs.GetBool("noGui"); - if (!noGui) { - spawnArgs.GetString( "guiName", "guis/EndLevel.gui", guiName ); - - if (guiName.Length()) { - gui = idUserInterface::FindGui( guiName, true, false, true ); - } - } - - buttonsReleased = false; - readyToExit = false; - - exitCommand = ""; -} - -/* -================ -idTarget_EndLevel::~idTarget_EndLevel() -================ -*/ -idTarget_EndLevel::~idTarget_EndLevel() { - //FIXME: need to go to smart ptrs for gui allocs or the unique method - //delete gui; -} - -/* -================ -idTarget_EndLevel::Event_Trigger -================ -*/ -void idTarget_EndLevel::Event_Trigger( idEntity *activator ) { - if ( gameLocal.endLevel ) { - return; - } - - // mark the endLevel, which will modify some game actions - // and pass control to us for drawing the stats and camera position - gameLocal.endLevel = this; - - // grab the activating player view position - idPlayer *player = (idPlayer *)(activator); - - initialViewOrg = player->GetEyePosition(); - initialViewAngles = idVec3( player->viewAngles[0], player->viewAngles[1], player->viewAngles[2] ); - - // kill all the sounds - gameSoundWorld->StopAllSounds(); - - if ( noGui ) { - readyToExit = true; - } -} - -/* -================ -idTarget_EndLevel::Draw -================ -*/ -void idTarget_EndLevel::Draw() { - - if (noGui) { - return; - } - - renderView_t renderView; - - memset( &renderView, 0, sizeof( renderView ) ); - - renderView.width = SCREEN_WIDTH; - renderView.height = SCREEN_HEIGHT; - renderView.x = 0; - renderView.y = 0; - - renderView.fov_x = 90; - renderView.fov_y = gameLocal.CalcFovY( renderView.fov_x ); - renderView.time = gameLocal.time; - -#if 0 - renderView.vieworg = initialViewOrg; - renderView.viewaxis = idAngles(initialViewAngles).toMat3(); -#else - renderView.vieworg = renderEntity.origin; - renderView.viewaxis = renderEntity.axis; -#endif - - gameRenderWorld->RenderScene( &renderView ); - - // draw the gui on top of the 3D view - gui->Redraw(gameLocal.time); -} - -/* -================ -idTarget_EndLevel::PlayerCommand -================ -*/ -void idTarget_EndLevel::PlayerCommand( int buttons ) { - if ( !( buttons & BUTTON_ATTACK ) ) { - buttonsReleased = true; - return; - } - if ( !buttonsReleased ) { - return; - } - - // we will exit at the end of the next game frame - readyToExit = true; -} - -/* -================ -idTarget_EndLevel::ExitCommand -================ -*/ -const char *idTarget_EndLevel::ExitCommand() { - if ( !readyToExit ) { - return NULL; - } - - idStr nextMap; - - if (spawnArgs.GetString( "nextMap", "", nextMap )) { - sprintf( exitCommand, "map %s", nextMap.c_str() ); - } else { - exitCommand = ""; - } - - return exitCommand; -} diff --git a/d3xp/EndLevel.h b/d3xp/EndLevel.h deleted file mode 100644 index 2d830856..00000000 --- a/d3xp/EndLevel.h +++ /dev/null @@ -1,72 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __GAME_ENDLEVEL_H__ -#define __GAME_ENDLEVEL_H__ - -#include "Entity.h" - -class idTarget_EndLevel : public idEntity { -public: - CLASS_PROTOTYPE( idTarget_EndLevel ); - - void Spawn( void ); - ~idTarget_EndLevel(); - - void Draw(); - // the endLevel will be responsible for drawing the entire screen - // when it is active - - void PlayerCommand( int buttons ); - // when an endlevel is active, plauer buttons get sent here instead - // of doing anything to the player, which will allow moving to - // the next level - - const char *ExitCommand(); - // the game will check this each frame, and return it to the - // session when there is something to give - -private: - idStr exitCommand; - - idVec3 initialViewOrg; - idVec3 initialViewAngles; - // set when the player triggers the exit - - idUserInterface *gui; - - bool buttonsReleased; - // don't skip out until buttons are released, then pressed - - bool readyToExit; - bool noGui; - - void Event_Trigger( idEntity *activator ); -}; - -#endif diff --git a/d3xp/Entity.cpp b/d3xp/Entity.cpp deleted file mode 100644 index ec636a6a..00000000 --- a/d3xp/Entity.cpp +++ /dev/null @@ -1,5615 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "idlib/geometry/JointTransform.h" -#include "idlib/LangDict.h" -#include "framework/async/NetworkSystem.h" -#include "framework/DeclEntityDef.h" -#include "renderer/ModelManager.h" - -#include "gamesys/SysCvar.h" -#include "physics/Physics_Parametric.h" -#include "physics/Physics_Actor.h" -#include "script/Script_Thread.h" -#include "Fx.h" -#include "AFEntity.h" -#include "Player.h" -#include "Mover.h" -#include "WorldSpawn.h" -#include "SmokeParticles.h" - -#include "Entity.h" - -/* -=============================================================================== - - idEntity - -=============================================================================== -*/ - -// overridable events -const idEventDef EV_PostSpawn( "", NULL ); -const idEventDef EV_FindTargets( "", NULL ); -const idEventDef EV_Touch( "", "et" ); -const idEventDef EV_GetName( "getName", NULL, 's' ); -const idEventDef EV_SetName( "setName", "s" ); -const idEventDef EV_Activate( "activate", "e" ); -const idEventDef EV_ActivateTargets( "activateTargets", "e" ); -const idEventDef EV_NumTargets( "numTargets", NULL, 'f' ); -const idEventDef EV_GetTarget( "getTarget", "f", 'e' ); -const idEventDef EV_RandomTarget( "randomTarget", "s", 'e' ); -const idEventDef EV_Bind( "bind", "e" ); -const idEventDef EV_BindPosition( "bindPosition", "e" ); -const idEventDef EV_BindToJoint( "bindToJoint", "esf" ); -const idEventDef EV_Unbind( "unbind", NULL ); -const idEventDef EV_RemoveBinds( "removeBinds" ); -const idEventDef EV_SpawnBind( "", NULL ); -const idEventDef EV_SetOwner( "setOwner", "e" ); -const idEventDef EV_SetModel( "setModel", "s" ); -const idEventDef EV_SetSkin( "setSkin", "s" ); -const idEventDef EV_GetWorldOrigin( "getWorldOrigin", NULL, 'v' ); -const idEventDef EV_SetWorldOrigin( "setWorldOrigin", "v" ); -const idEventDef EV_GetOrigin( "getOrigin", NULL, 'v' ); -const idEventDef EV_SetOrigin( "setOrigin", "v" ); -const idEventDef EV_GetAngles( "getAngles", NULL, 'v' ); -const idEventDef EV_SetAngles( "setAngles", "v" ); -const idEventDef EV_GetLinearVelocity( "getLinearVelocity", NULL, 'v' ); -const idEventDef EV_SetLinearVelocity( "setLinearVelocity", "v" ); -const idEventDef EV_GetAngularVelocity( "getAngularVelocity", NULL, 'v' ); -const idEventDef EV_SetAngularVelocity( "setAngularVelocity", "v" ); -const idEventDef EV_GetSize( "getSize", NULL, 'v' ); -const idEventDef EV_SetSize( "setSize", "vv" ); -const idEventDef EV_GetMins( "getMins", NULL, 'v' ); -const idEventDef EV_GetMaxs( "getMaxs", NULL, 'v' ); -const idEventDef EV_IsHidden( "isHidden", NULL, 'd' ); -const idEventDef EV_Hide( "hide", NULL ); -const idEventDef EV_Show( "show", NULL ); -const idEventDef EV_Touches( "touches", "E", 'd' ); -const idEventDef EV_ClearSignal( "clearSignal", "d" ); -const idEventDef EV_GetShaderParm( "getShaderParm", "d", 'f' ); -const idEventDef EV_SetShaderParm( "setShaderParm", "df" ); -const idEventDef EV_SetShaderParms( "setShaderParms", "ffff" ); -const idEventDef EV_SetColor( "setColor", "fff" ); -const idEventDef EV_GetColor( "getColor", NULL, 'v' ); -const idEventDef EV_CacheSoundShader( "cacheSoundShader", "s" ); -const idEventDef EV_StartSoundShader( "startSoundShader", "sd", 'f' ); -const idEventDef EV_StartSound( "startSound", "sdd", 'f' ); -const idEventDef EV_StopSound( "stopSound", "dd" ); -const idEventDef EV_FadeSound( "fadeSound", "dff" ); -const idEventDef EV_SetGuiParm( "setGuiParm", "ss" ); -const idEventDef EV_SetGuiFloat( "setGuiFloat", "sf" ); -const idEventDef EV_GetNextKey( "getNextKey", "ss", 's' ); -const idEventDef EV_SetKey( "setKey", "ss" ); -const idEventDef EV_GetKey( "getKey", "s", 's' ); -const idEventDef EV_GetIntKey( "getIntKey", "s", 'f' ); -const idEventDef EV_GetFloatKey( "getFloatKey", "s", 'f' ); -const idEventDef EV_GetVectorKey( "getVectorKey", "s", 'v' ); -const idEventDef EV_GetEntityKey( "getEntityKey", "s", 'e' ); -const idEventDef EV_RestorePosition( "restorePosition" ); -const idEventDef EV_UpdateCameraTarget( "", NULL ); -const idEventDef EV_DistanceTo( "distanceTo", "E", 'f' ); -const idEventDef EV_DistanceToPoint( "distanceToPoint", "v", 'f' ); -const idEventDef EV_StartFx( "startFx", "s" ); -const idEventDef EV_HasFunction( "hasFunction", "s", 'd' ); -const idEventDef EV_CallFunction( "callFunction", "s" ); -const idEventDef EV_SetNeverDormant( "setNeverDormant", "d" ); -#ifdef _D3XP -const idEventDef EV_SetGui ( "setGui", "ds" ); -const idEventDef EV_PrecacheGui ( "precacheGui", "s" ); -const idEventDef EV_GetGuiParm ( "getGuiParm", "ds", 's' ); -const idEventDef EV_GetGuiParmFloat ( "getGuiParmFloat", "ds", 'f' ); -const idEventDef EV_MotionBlurOn( "motionBlurOn" ); -const idEventDef EV_MotionBlurOff( "motionBlurOff" ); -const idEventDef EV_GuiNamedEvent ( "guiNamedEvent", "ds" ); -#endif - -ABSTRACT_DECLARATION( idClass, idEntity ) - EVENT( EV_GetName, idEntity::Event_GetName ) - EVENT( EV_SetName, idEntity::Event_SetName ) - EVENT( EV_FindTargets, idEntity::Event_FindTargets ) - EVENT( EV_ActivateTargets, idEntity::Event_ActivateTargets ) - EVENT( EV_NumTargets, idEntity::Event_NumTargets ) - EVENT( EV_GetTarget, idEntity::Event_GetTarget ) - EVENT( EV_RandomTarget, idEntity::Event_RandomTarget ) - EVENT( EV_BindToJoint, idEntity::Event_BindToJoint ) - EVENT( EV_RemoveBinds, idEntity::Event_RemoveBinds ) - EVENT( EV_Bind, idEntity::Event_Bind ) - EVENT( EV_BindPosition, idEntity::Event_BindPosition ) - EVENT( EV_Unbind, idEntity::Event_Unbind ) - EVENT( EV_SpawnBind, idEntity::Event_SpawnBind ) - EVENT( EV_SetOwner, idEntity::Event_SetOwner ) - EVENT( EV_SetModel, idEntity::Event_SetModel ) - EVENT( EV_SetSkin, idEntity::Event_SetSkin ) - EVENT( EV_GetShaderParm, idEntity::Event_GetShaderParm ) - EVENT( EV_SetShaderParm, idEntity::Event_SetShaderParm ) - EVENT( EV_SetShaderParms, idEntity::Event_SetShaderParms ) - EVENT( EV_SetColor, idEntity::Event_SetColor ) - EVENT( EV_GetColor, idEntity::Event_GetColor ) - EVENT( EV_IsHidden, idEntity::Event_IsHidden ) - EVENT( EV_Hide, idEntity::Event_Hide ) - EVENT( EV_Show, idEntity::Event_Show ) - EVENT( EV_CacheSoundShader, idEntity::Event_CacheSoundShader ) - EVENT( EV_StartSoundShader, idEntity::Event_StartSoundShader ) - EVENT( EV_StartSound, idEntity::Event_StartSound ) - EVENT( EV_StopSound, idEntity::Event_StopSound ) - EVENT( EV_FadeSound, idEntity::Event_FadeSound ) - EVENT( EV_GetWorldOrigin, idEntity::Event_GetWorldOrigin ) - EVENT( EV_SetWorldOrigin, idEntity::Event_SetWorldOrigin ) - EVENT( EV_GetOrigin, idEntity::Event_GetOrigin ) - EVENT( EV_SetOrigin, idEntity::Event_SetOrigin ) - EVENT( EV_GetAngles, idEntity::Event_GetAngles ) - EVENT( EV_SetAngles, idEntity::Event_SetAngles ) - EVENT( EV_GetLinearVelocity, idEntity::Event_GetLinearVelocity ) - EVENT( EV_SetLinearVelocity, idEntity::Event_SetLinearVelocity ) - EVENT( EV_GetAngularVelocity, idEntity::Event_GetAngularVelocity ) - EVENT( EV_SetAngularVelocity, idEntity::Event_SetAngularVelocity ) - EVENT( EV_GetSize, idEntity::Event_GetSize ) - EVENT( EV_SetSize, idEntity::Event_SetSize ) - EVENT( EV_GetMins, idEntity::Event_GetMins) - EVENT( EV_GetMaxs, idEntity::Event_GetMaxs ) - EVENT( EV_Touches, idEntity::Event_Touches ) - EVENT( EV_SetGuiParm, idEntity::Event_SetGuiParm ) - EVENT( EV_SetGuiFloat, idEntity::Event_SetGuiFloat ) - EVENT( EV_GetNextKey, idEntity::Event_GetNextKey ) - EVENT( EV_SetKey, idEntity::Event_SetKey ) - EVENT( EV_GetKey, idEntity::Event_GetKey ) - EVENT( EV_GetIntKey, idEntity::Event_GetIntKey ) - EVENT( EV_GetFloatKey, idEntity::Event_GetFloatKey ) - EVENT( EV_GetVectorKey, idEntity::Event_GetVectorKey ) - EVENT( EV_GetEntityKey, idEntity::Event_GetEntityKey ) - EVENT( EV_RestorePosition, idEntity::Event_RestorePosition ) - EVENT( EV_UpdateCameraTarget, idEntity::Event_UpdateCameraTarget ) - EVENT( EV_DistanceTo, idEntity::Event_DistanceTo ) - EVENT( EV_DistanceToPoint, idEntity::Event_DistanceToPoint ) - EVENT( EV_StartFx, idEntity::Event_StartFx ) - EVENT( EV_Thread_WaitFrame, idEntity::Event_WaitFrame ) - EVENT( EV_Thread_Wait, idEntity::Event_Wait ) - EVENT( EV_HasFunction, idEntity::Event_HasFunction ) - EVENT( EV_CallFunction, idEntity::Event_CallFunction ) - EVENT( EV_SetNeverDormant, idEntity::Event_SetNeverDormant ) -#ifdef _D3XP - EVENT( EV_SetGui, idEntity::Event_SetGui ) - EVENT( EV_PrecacheGui, idEntity::Event_PrecacheGui ) - EVENT( EV_GetGuiParm, idEntity::Event_GetGuiParm ) - EVENT( EV_GetGuiParmFloat, idEntity::Event_GetGuiParmFloat ) - EVENT( EV_GuiNamedEvent, idEntity::Event_GuiNamedEvent ) -#endif -END_CLASS - -/* -================ -UpdateGuiParms -================ -*/ -void UpdateGuiParms( idUserInterface *gui, const idDict *args ) { - if ( gui == NULL || args == NULL ) { - return; - } - const idKeyValue *kv = args->MatchPrefix( "gui_parm", NULL ); - while( kv ) { - gui->SetStateString( kv->GetKey(), kv->GetValue() ); - kv = args->MatchPrefix( "gui_parm", kv ); - } - gui->SetStateBool( "noninteractive", args->GetBool( "gui_noninteractive" ) ) ; - gui->StateChanged( gameLocal.time ); -} - -/* -================ -AddRenderGui -================ -*/ -void AddRenderGui( const char *name, idUserInterface **gui, const idDict *args ) { - const idKeyValue *kv = args->MatchPrefix( "gui_parm", NULL ); - *gui = uiManager->FindGui( name, true, ( kv != NULL ) ); - UpdateGuiParms( *gui, args ); -} - -/* -================ -idGameEdit::ParseSpawnArgsToRenderEntity - -parse the static model parameters -this is the canonical renderEntity parm parsing, -which should be used by dmap and the editor -================ -*/ -void idGameEdit::ParseSpawnArgsToRenderEntity( const idDict *args, renderEntity_t *renderEntity ) { - int i; - const char *temp; - idVec3 color; - float angle; - const idDeclModelDef *modelDef; - - memset( renderEntity, 0, sizeof( *renderEntity ) ); - - temp = args->GetString( "model" ); - - modelDef = NULL; - if ( temp[0] != '\0' ) { - modelDef = static_cast( declManager->FindType( DECL_MODELDEF, temp, false ) ); - if ( modelDef ) { - renderEntity->hModel = modelDef->ModelHandle(); - } - if ( !renderEntity->hModel ) { - renderEntity->hModel = renderModelManager->FindModel( temp ); - } - } - if ( renderEntity->hModel ) { - renderEntity->bounds = renderEntity->hModel->Bounds( renderEntity ); - } else { - renderEntity->bounds.Zero(); - } - - temp = args->GetString( "skin" ); - if ( temp[0] != '\0' ) { - renderEntity->customSkin = declManager->FindSkin( temp ); - } else if ( modelDef ) { - renderEntity->customSkin = modelDef->GetDefaultSkin(); - } - - temp = args->GetString( "shader" ); - if ( temp[0] != '\0' ) { - renderEntity->customShader = declManager->FindMaterial( temp ); - } - - args->GetVector( "origin", "0 0 0", renderEntity->origin ); - - // get the rotation matrix in either full form, or single angle form - if ( !args->GetMatrix( "rotation", "1 0 0 0 1 0 0 0 1", renderEntity->axis ) ) { - angle = args->GetFloat( "angle" ); - if ( angle != 0.0f ) { - renderEntity->axis = idAngles( 0.0f, angle, 0.0f ).ToMat3(); - } else { - renderEntity->axis.Identity(); - } - } - - renderEntity->referenceSound = NULL; - - // get shader parms - args->GetVector( "_color", "1 1 1", color ); - renderEntity->shaderParms[ SHADERPARM_RED ] = color[0]; - renderEntity->shaderParms[ SHADERPARM_GREEN ] = color[1]; - renderEntity->shaderParms[ SHADERPARM_BLUE ] = color[2]; - renderEntity->shaderParms[ 3 ] = args->GetFloat( "shaderParm3", "1" ); - renderEntity->shaderParms[ 4 ] = args->GetFloat( "shaderParm4", "0" ); - renderEntity->shaderParms[ 5 ] = args->GetFloat( "shaderParm5", "0" ); - renderEntity->shaderParms[ 6 ] = args->GetFloat( "shaderParm6", "0" ); - renderEntity->shaderParms[ 7 ] = args->GetFloat( "shaderParm7", "0" ); - renderEntity->shaderParms[ 8 ] = args->GetFloat( "shaderParm8", "0" ); - renderEntity->shaderParms[ 9 ] = args->GetFloat( "shaderParm9", "0" ); - renderEntity->shaderParms[ 10 ] = args->GetFloat( "shaderParm10", "0" ); - renderEntity->shaderParms[ 11 ] = args->GetFloat( "shaderParm11", "0" ); - - // check noDynamicInteractions flag - renderEntity->noDynamicInteractions = args->GetBool( "noDynamicInteractions" ); - - // check noshadows flag - renderEntity->noShadow = args->GetBool( "noshadows" ); - - // check noselfshadows flag - renderEntity->noSelfShadow = args->GetBool( "noselfshadows" ); - - // init any guis, including entity-specific states - for( i = 0; i < MAX_RENDERENTITY_GUI; i++ ) { - temp = args->GetString( i == 0 ? "gui" : va( "gui%d", i + 1 ) ); - if ( temp[ 0 ] != '\0' ) { - AddRenderGui( temp, &renderEntity->gui[ i ], args ); - } - } -} - -/* -================ -idGameEdit::ParseSpawnArgsToRefSound - -parse the sound parameters -this is the canonical refSound parm parsing, -which should be used by dmap and the editor -================ -*/ -void idGameEdit::ParseSpawnArgsToRefSound( const idDict *args, refSound_t *refSound ) { - const char *temp; - - memset( refSound, 0, sizeof( *refSound ) ); - - refSound->parms.minDistance = args->GetFloat( "s_mindistance" ); - refSound->parms.maxDistance = args->GetFloat( "s_maxdistance" ); - refSound->parms.volume = args->GetFloat( "s_volume" ); - refSound->parms.shakes = args->GetFloat( "s_shakes" ); - - args->GetVector( "origin", "0 0 0", refSound->origin ); - - refSound->referenceSound = NULL; - - // if a diversity is not specified, every sound start will make - // a random one. Specifying diversity is usefull to make multiple - // lights all share the same buzz sound offset, for instance. - refSound->diversity = args->GetFloat( "s_diversity", "-1" ); - refSound->waitfortrigger = args->GetBool( "s_waitfortrigger" ); - - if ( args->GetBool( "s_omni" ) ) { - refSound->parms.soundShaderFlags |= SSF_OMNIDIRECTIONAL; - } - if ( args->GetBool( "s_looping" ) ) { - refSound->parms.soundShaderFlags |= SSF_LOOPING; - } - if ( args->GetBool( "s_occlusion" ) ) { - refSound->parms.soundShaderFlags |= SSF_NO_OCCLUSION; - } - if ( args->GetBool( "s_global" ) ) { - refSound->parms.soundShaderFlags |= SSF_GLOBAL; - } - if ( args->GetBool( "s_unclamped" ) ) { - refSound->parms.soundShaderFlags |= SSF_UNCLAMPED; - } - refSound->parms.soundClass = args->GetInt( "s_soundClass" ); - - temp = args->GetString( "s_shader" ); - if ( temp[0] != '\0' ) { - refSound->shader = declManager->FindSound( temp ); - } -} - -/* -=============== -idEntity::UpdateChangeableSpawnArgs - -Any key val pair that might change during the course of the game ( via a gui or whatever ) -should be initialize here so a gui or other trigger can change something and have it updated -properly. An optional source may be provided if the values reside in an outside dictionary and -first need copied over to spawnArgs -=============== -*/ -void idEntity::UpdateChangeableSpawnArgs( const idDict *source ) { - int i; - const char *target; - - if ( !source ) { - source = &spawnArgs; - } - cameraTarget = NULL; - target = source->GetString( "cameraTarget" ); - if ( target && target[0] ) { - // update the camera taget - PostEventMS( &EV_UpdateCameraTarget, 0 ); - } - - for ( i = 0; i < MAX_RENDERENTITY_GUI; i++ ) { - UpdateGuiParms( renderEntity.gui[ i ], source ); - } -} - -/* -================ -idEntity::idEntity -================ -*/ -idEntity::idEntity() { - - entityNumber = ENTITYNUM_NONE; - entityDefNumber = -1; - - spawnNode.SetOwner( this ); - activeNode.SetOwner( this ); - - snapshotNode.SetOwner( this ); - snapshotSequence = -1; - snapshotBits = 0; - - thinkFlags = 0; - dormantStart = 0; - cinematic = false; - renderView = NULL; - cameraTarget = NULL; - health = 0; - - physics = NULL; - bindMaster = NULL; - bindJoint = INVALID_JOINT; - bindBody = -1; - teamMaster = NULL; - teamChain = NULL; - signals = NULL; - - memset( PVSAreas, 0, sizeof( PVSAreas ) ); - numPVSAreas = -1; - - memset( &fl, 0, sizeof( fl ) ); - fl.neverDormant = true; // most entities never go dormant - - memset( &renderEntity, 0, sizeof( renderEntity ) ); - modelDefHandle = -1; - memset( &refSound, 0, sizeof( refSound ) ); - - mpGUIState = -1; - -#ifdef _D3XP - memset( &xrayEntity, 0, sizeof( xrayEntity ) ); - - timeGroup = TIME_GROUP1; - xrayEntityHandle = -1; - xraySkin = NULL; - - noGrab = false; -#endif -} - -/* -================ -idEntity::FixupLocalizedStrings -================ -*/ -void idEntity::FixupLocalizedStrings() { - for ( int i = 0; i < spawnArgs.GetNumKeyVals(); i++ ) { - const idKeyValue *kv = spawnArgs.GetKeyVal( i ); - if ( idStr::Cmpn( kv->GetValue(), STRTABLE_ID, STRTABLE_ID_LENGTH ) == 0 ){ - spawnArgs.Set( kv->GetKey(), common->GetLanguageDict()->GetString( kv->GetValue() ) ); - } - } -} - -/* -================ -idEntity::Spawn -================ -*/ -void idEntity::Spawn( void ) { - int i; - const char *temp; - idVec3 origin; - idMat3 axis; - const idKeyValue *networkSync; - const char *classname; - const char *scriptObjectName; - - gameLocal.RegisterEntity( this ); - - spawnArgs.GetString( "classname", NULL, &classname ); - const idDeclEntityDef *def = gameLocal.FindEntityDef( classname, false ); - if ( def ) { - entityDefNumber = def->Index(); - } - - FixupLocalizedStrings(); - - // parse static models the same way the editor display does - gameEdit->ParseSpawnArgsToRenderEntity( &spawnArgs, &renderEntity ); - - renderEntity.entityNum = entityNumber; - -#ifdef _D3XP - noGrab = spawnArgs.GetBool( "noGrab", "0" ); - - xraySkin = NULL; - renderEntity.xrayIndex = 1; - - idStr str; - if ( spawnArgs.GetString( "skin_xray", "", str ) ) { - xraySkin = declManager->FindSkin( str.c_str() ); - } -#endif - - // go dormant within 5 frames so that when the map starts most monsters are dormant - dormantStart = gameLocal.time - DELAY_DORMANT_TIME + gameLocal.msec * 5; - - origin = renderEntity.origin; - axis = renderEntity.axis; - - // do the audio parsing the same way dmap and the editor do - gameEdit->ParseSpawnArgsToRefSound( &spawnArgs, &refSound ); - - // only play SCHANNEL_PRIVATE when sndworld->PlaceListener() is called with this listenerId - // don't spatialize sounds from the same entity - refSound.listenerId = entityNumber + 1; - - cameraTarget = NULL; - temp = spawnArgs.GetString( "cameraTarget" ); - if ( temp && temp[0] ) { - // update the camera taget - PostEventMS( &EV_UpdateCameraTarget, 0 ); - } - - for ( i = 0; i < MAX_RENDERENTITY_GUI; i++ ) { - UpdateGuiParms( renderEntity.gui[ i ], &spawnArgs ); - } - - fl.solidForTeam = spawnArgs.GetBool( "solidForTeam", "0" ); - fl.neverDormant = spawnArgs.GetBool( "neverDormant", "0" ); - fl.hidden = spawnArgs.GetBool( "hide", "0" ); - if ( fl.hidden ) { - // make sure we're hidden, since a spawn function might not set it up right - PostEventMS( &EV_Hide, 0 ); - } - cinematic = spawnArgs.GetBool( "cinematic", "0" ); - - networkSync = spawnArgs.FindKey( "networkSync" ); - if ( networkSync ) { - fl.networkSync = ( atoi( networkSync->GetValue() ) != 0 ); - } - -#if 0 - if ( !gameLocal.isClient ) { - // common->DPrintf( "NET: DBG %s - %s is synced: %s\n", spawnArgs.GetString( "classname", "" ), GetType()->classname, fl.networkSync ? "true" : "false" ); - if ( spawnArgs.GetString( "classname", "" )[ 0 ] == '\0' && !fl.networkSync ) { - common->DPrintf( "NET: WRN %s entity, no classname, and no networkSync?\n", GetType()->classname ); - } - } -#endif - - // every object will have a unique name - temp = spawnArgs.GetString( "name", va( "%s_%s_%d", GetClassname(), spawnArgs.GetString( "classname" ), entityNumber ) ); - SetName( temp ); - - // if we have targets, wait until all entities are spawned to get them - if ( spawnArgs.MatchPrefix( "target" ) || spawnArgs.MatchPrefix( "guiTarget" ) ) { - if ( gameLocal.GameState() == GAMESTATE_STARTUP ) { - PostEventMS( &EV_FindTargets, 0 ); - } else { - // not during spawn, so it's ok to get the targets - FindTargets(); - } - } - - health = spawnArgs.GetInt( "health" ); - - InitDefaultPhysics( origin, axis ); - - SetOrigin( origin ); - SetAxis( axis ); - - temp = spawnArgs.GetString( "model" ); - if ( temp && *temp ) { - SetModel( temp ); - } - - if ( spawnArgs.GetString( "bind", "", &temp ) ) { - PostEventMS( &EV_SpawnBind, 0 ); - } - - // auto-start a sound on the entity - if ( refSound.shader && !refSound.waitfortrigger ) { - StartSoundShader( refSound.shader, SND_CHANNEL_ANY, 0, false, NULL ); - } - - // setup script object - if ( ShouldConstructScriptObjectAtSpawn() && spawnArgs.GetString( "scriptobject", NULL, &scriptObjectName ) ) { - if ( !scriptObject.SetType( scriptObjectName ) ) { - gameLocal.Error( "Script object '%s' not found on entity '%s'.", scriptObjectName, name.c_str() ); - } - - ConstructScriptObject(); - } - -#ifdef _D3XP - // determine time group - DetermineTimeGroup( spawnArgs.GetBool( "slowmo", "1" ) ); -#endif -} - -/* -================ -idEntity::~idEntity -================ -*/ -idEntity::~idEntity( void ) { - - if ( gameLocal.GameState() != GAMESTATE_SHUTDOWN && !gameLocal.isClient && fl.networkSync && entityNumber >= MAX_CLIENTS ) { - idBitMsg msg; - byte msgBuf[ MAX_GAME_MESSAGE_SIZE ]; - - msg.Init( msgBuf, sizeof( msgBuf ) ); - msg.WriteByte( GAME_RELIABLE_MESSAGE_DELETE_ENT ); - msg.WriteBits( gameLocal.GetSpawnId( this ), 32 ); - networkSystem->ServerSendReliableMessage( -1, msg ); - } - - DeconstructScriptObject(); - scriptObject.Free(); - - if ( thinkFlags ) { - BecomeInactive( thinkFlags ); - } - activeNode.Remove(); - - Signal( SIG_REMOVED ); - - // we have to set back the default physics object before unbinding because the entity - // specific physics object might be an entity variable and as such could already be destroyed. - SetPhysics( NULL ); - - // remove any entities that are bound to me - RemoveBinds(); - - // unbind from master - Unbind(); - QuitTeam(); - - gameLocal.RemoveEntityFromHash( name.c_str(), this ); - - delete renderView; - renderView = NULL; - - delete signals; - signals = NULL; - - FreeModelDef(); - FreeSoundEmitter( false ); - -#ifdef _D3XP - if ( xrayEntityHandle != -1) { - gameRenderWorld->FreeEntityDef( xrayEntityHandle ); - xrayEntityHandle = -1; - } -#endif - - gameLocal.UnregisterEntity( this ); -} - -/* -================ -idEntity::Save -================ -*/ -void idEntity::Save( idSaveGame *savefile ) const { - int i, j; - - savefile->WriteInt( entityNumber ); - savefile->WriteInt( entityDefNumber ); - - // spawnNode and activeNode are restored by gameLocal - - savefile->WriteInt( snapshotSequence ); - savefile->WriteInt( snapshotBits ); - - savefile->WriteDict( &spawnArgs ); - savefile->WriteString( name ); - scriptObject.Save( savefile ); - - savefile->WriteInt( thinkFlags ); - savefile->WriteInt( dormantStart ); - savefile->WriteBool( cinematic ); - - savefile->WriteObject( cameraTarget ); - - savefile->WriteInt( health ); - - savefile->WriteInt( targets.Num() ); - for( i = 0; i < targets.Num(); i++ ) { - targets[ i ].Save( savefile ); - } - - entityFlags_s flags = fl; - LittleBitField( &flags, sizeof( flags ) ); - savefile->Write( &flags, sizeof( flags ) ); - -#ifdef _D3XP - savefile->WriteInt( timeGroup ); - savefile->WriteBool( noGrab ); - savefile->WriteRenderEntity( xrayEntity ); - savefile->WriteInt( xrayEntityHandle ); - savefile->WriteSkin( xraySkin ); -#endif - - savefile->WriteRenderEntity( renderEntity ); - savefile->WriteInt( modelDefHandle ); - savefile->WriteRefSound( refSound ); - - savefile->WriteObject( bindMaster ); - savefile->WriteJoint( bindJoint ); - savefile->WriteInt( bindBody ); - savefile->WriteObject( teamMaster ); - savefile->WriteObject( teamChain ); - - savefile->WriteStaticObject( defaultPhysicsObj ); - - savefile->WriteInt( numPVSAreas ); - for( i = 0; i < MAX_PVS_AREAS; i++ ) { - savefile->WriteInt( PVSAreas[ i ] ); - } - - if ( !signals ) { - savefile->WriteBool( false ); - } else { - savefile->WriteBool( true ); - for( i = 0; i < NUM_SIGNALS; i++ ) { - savefile->WriteInt( signals->signal[ i ].Num() ); - for( j = 0; j < signals->signal[ i ].Num(); j++ ) { - savefile->WriteInt( signals->signal[ i ][ j ].threadnum ); - savefile->WriteString( signals->signal[ i ][ j ].function->Name() ); - } - } - } - - savefile->WriteInt( mpGUIState ); -} - -/* -================ -idEntity::Restore -================ -*/ -void idEntity::Restore( idRestoreGame *savefile ) { - int i, j; - int num; - idStr funcname; - - savefile->ReadInt( entityNumber ); - savefile->ReadInt( entityDefNumber ); - - // spawnNode and activeNode are restored by gameLocal - - savefile->ReadInt( snapshotSequence ); - savefile->ReadInt( snapshotBits ); - - savefile->ReadDict( &spawnArgs ); - savefile->ReadString( name ); - SetName( name ); - - scriptObject.Restore( savefile ); - - savefile->ReadInt( thinkFlags ); - savefile->ReadInt( dormantStart ); - savefile->ReadBool( cinematic ); - - savefile->ReadObject( reinterpret_cast( cameraTarget ) ); - - savefile->ReadInt( health ); - - targets.Clear(); - savefile->ReadInt( num ); - targets.SetNum( num ); - for( i = 0; i < num; i++ ) { - targets[ i ].Restore( savefile ); - } - - savefile->Read( &fl, sizeof( fl ) ); - LittleBitField( &fl, sizeof( fl ) ); - -#ifdef _D3XP - savefile->ReadInt( timeGroup ); - savefile->ReadBool( noGrab ); - savefile->ReadRenderEntity( xrayEntity ); - savefile->ReadInt( xrayEntityHandle ); - if ( xrayEntityHandle != -1 ) { - xrayEntityHandle = gameRenderWorld->AddEntityDef( &xrayEntity ); - } - savefile->ReadSkin( xraySkin ); -#endif - - savefile->ReadRenderEntity( renderEntity ); - savefile->ReadInt( modelDefHandle ); - savefile->ReadRefSound( refSound ); - - savefile->ReadObject( reinterpret_cast( bindMaster ) ); - savefile->ReadJoint( bindJoint ); - savefile->ReadInt( bindBody ); - savefile->ReadObject( reinterpret_cast( teamMaster ) ); - savefile->ReadObject( reinterpret_cast( teamChain ) ); - - savefile->ReadStaticObject( defaultPhysicsObj ); - RestorePhysics( &defaultPhysicsObj ); - - savefile->ReadInt( numPVSAreas ); - for( i = 0; i < MAX_PVS_AREAS; i++ ) { - savefile->ReadInt( PVSAreas[ i ] ); - } - - bool readsignals; - savefile->ReadBool( readsignals ); - if ( readsignals ) { - signals = new signalList_t; - for( i = 0; i < NUM_SIGNALS; i++ ) { - savefile->ReadInt( num ); - signals->signal[ i ].SetNum( num ); - for( j = 0; j < num; j++ ) { - savefile->ReadInt( signals->signal[ i ][ j ].threadnum ); - savefile->ReadString( funcname ); - signals->signal[ i ][ j ].function = gameLocal.program.FindFunction( funcname ); - if ( !signals->signal[ i ][ j ].function ) { - savefile->Error( "Function '%s' not found", funcname.c_str() ); - } - } - } - } - - savefile->ReadInt( mpGUIState ); - - // restore must retrieve modelDefHandle from the renderer - if ( modelDefHandle != -1 ) { - modelDefHandle = gameRenderWorld->AddEntityDef( &renderEntity ); - } -} - -/* -================ -idEntity::GetEntityDefName -================ -*/ -const char * idEntity::GetEntityDefName( void ) const { - if ( entityDefNumber < 0 ) { - return "*unknown*"; - } - return declManager->DeclByIndex( DECL_ENTITYDEF, entityDefNumber, false )->GetName(); -} - -/* -================ -idEntity::SetName -================ -*/ -void idEntity::SetName( const char *newname ) { - if ( name.Length() ) { - gameLocal.RemoveEntityFromHash( name.c_str(), this ); - gameLocal.program.SetEntity( name, NULL ); - } - - name = newname; - if ( name.Length() ) { - if ( ( name == "NULL" ) || ( name == "null_entity" ) ) { - gameLocal.Error( "Cannot name entity '%s'. '%s' is reserved for script.", name.c_str(), name.c_str() ); - } - gameLocal.AddEntityToHash( name.c_str(), this ); - gameLocal.program.SetEntity( name, this ); - } -} - -/* -================ -idEntity::GetName -================ -*/ -const char * idEntity::GetName( void ) const { - return name.c_str(); -} - - -/*********************************************************************** - - Thinking - -***********************************************************************/ - -/* -================ -idEntity::Think -================ -*/ -void idEntity::Think( void ) { - RunPhysics(); - Present(); -} - -/* -================ -idEntity::DoDormantTests - -Monsters and other expensive entities that are completely closed -off from the player can skip all of their work -================ -*/ -bool idEntity::DoDormantTests( void ) { - - if ( fl.neverDormant ) { - return false; - } - - // if the monster area is not topologically connected to a player - if ( !gameLocal.InPlayerConnectedArea( this ) ) { - if ( dormantStart == 0 ) { - dormantStart = gameLocal.time; - } - if ( gameLocal.time - dormantStart < DELAY_DORMANT_TIME ) { - // just got closed off, don't go dormant yet - return false; - } - return true; - } - - // the monster area is topologically connected to a player, but if - // the monster hasn't been woken up before, do the more precise PVS check - if ( !fl.hasAwakened ) { - if ( !gameLocal.InPlayerPVS( this ) ) { - return true; // stay dormant - } - } - - // wake up - dormantStart = 0; - fl.hasAwakened = true; // only go dormant when area closed off now, not just out of PVS - - return false; -} - -/* -================ -idEntity::CheckDormant - -Monsters and other expensive entities that are completely closed -off from the player can skip all of their work -================ -*/ -bool idEntity::CheckDormant( void ) { - bool dormant; - - dormant = DoDormantTests(); - if ( dormant && !fl.isDormant ) { - fl.isDormant = true; - DormantBegin(); - } else if ( !dormant && fl.isDormant ) { - fl.isDormant = false; - DormantEnd(); - } - - return dormant; -} - -/* -================ -idEntity::DormantBegin - -called when entity becomes dormant -================ -*/ -void idEntity::DormantBegin( void ) { -} - -/* -================ -idEntity::DormantEnd - -called when entity wakes from being dormant -================ -*/ -void idEntity::DormantEnd( void ) { -} - -/* -================ -idEntity::IsActive -================ -*/ -bool idEntity::IsActive( void ) const { - return activeNode.InList(); -} - -/* -================ -idEntity::BecomeActive -================ -*/ -void idEntity::BecomeActive( int flags ) { - if ( ( flags & TH_PHYSICS ) ) { - // enable the team master if this entity is part of a physics team - if ( teamMaster && teamMaster != this ) { - teamMaster->BecomeActive( TH_PHYSICS ); - } else if ( !( thinkFlags & TH_PHYSICS ) ) { - // if this is a pusher - if ( physics->IsType( idPhysics_Parametric::Type ) || physics->IsType( idPhysics_Actor::Type ) ) { - gameLocal.sortPushers = true; - } - } - } - - int oldFlags = thinkFlags; - thinkFlags |= flags; - if ( thinkFlags ) { - if ( !IsActive() ) { - activeNode.AddToEnd( gameLocal.activeEntities ); - } else if ( !oldFlags ) { - // we became inactive this frame, so we have to decrease the count of entities to deactivate - gameLocal.numEntitiesToDeactivate--; - } - } -} - -/* -================ -idEntity::BecomeInactive -================ -*/ -void idEntity::BecomeInactive( int flags ) { - if ( ( flags & TH_PHYSICS ) ) { - // may only disable physics on a team master if no team members are running physics or bound to a joints - if ( teamMaster == this ) { - for ( idEntity *ent = teamMaster->teamChain; ent; ent = ent->teamChain ) { - if ( ( ent->thinkFlags & TH_PHYSICS ) || ( ( ent->bindMaster == this ) && ( ent->bindJoint != INVALID_JOINT ) ) ) { - flags &= ~TH_PHYSICS; - break; - } - } - } - } - - if ( thinkFlags ) { - thinkFlags &= ~flags; - if ( !thinkFlags && IsActive() ) { - gameLocal.numEntitiesToDeactivate++; - } - } - - if ( ( flags & TH_PHYSICS ) ) { - // if this entity has a team master - if ( teamMaster && teamMaster != this ) { - // if the team master is at rest - if ( teamMaster->IsAtRest() ) { - teamMaster->BecomeInactive( TH_PHYSICS ); - } - } - } -} - -/*********************************************************************** - - Visuals - -***********************************************************************/ - -/* -================ -idEntity::SetShaderParm -================ -*/ -void idEntity::SetShaderParm( int parmnum, float value ) { - if ( ( parmnum < 0 ) || ( parmnum >= MAX_ENTITY_SHADER_PARMS ) ) { - gameLocal.Warning( "shader parm index (%d) out of range", parmnum ); - return; - } - - renderEntity.shaderParms[ parmnum ] = value; - UpdateVisuals(); -} - -/* -================ -idEntity::SetColor -================ -*/ -void idEntity::SetColor( float red, float green, float blue ) { - renderEntity.shaderParms[ SHADERPARM_RED ] = red; - renderEntity.shaderParms[ SHADERPARM_GREEN ] = green; - renderEntity.shaderParms[ SHADERPARM_BLUE ] = blue; - UpdateVisuals(); -} - -/* -================ -idEntity::SetColor -================ -*/ -void idEntity::SetColor( const idVec3 &color ) { - SetColor( color[ 0 ], color[ 1 ], color[ 2 ] ); - UpdateVisuals(); -} - -/* -================ -idEntity::GetColor -================ -*/ -void idEntity::GetColor( idVec3 &out ) const { - out[ 0 ] = renderEntity.shaderParms[ SHADERPARM_RED ]; - out[ 1 ] = renderEntity.shaderParms[ SHADERPARM_GREEN ]; - out[ 2 ] = renderEntity.shaderParms[ SHADERPARM_BLUE ]; -} - -/* -================ -idEntity::SetColor -================ -*/ -void idEntity::SetColor( const idVec4 &color ) { - renderEntity.shaderParms[ SHADERPARM_RED ] = color[ 0 ]; - renderEntity.shaderParms[ SHADERPARM_GREEN ] = color[ 1 ]; - renderEntity.shaderParms[ SHADERPARM_BLUE ] = color[ 2 ]; - renderEntity.shaderParms[ SHADERPARM_ALPHA ] = color[ 3 ]; - UpdateVisuals(); -} - -/* -================ -idEntity::GetColor -================ -*/ -void idEntity::GetColor( idVec4 &out ) const { - out[ 0 ] = renderEntity.shaderParms[ SHADERPARM_RED ]; - out[ 1 ] = renderEntity.shaderParms[ SHADERPARM_GREEN ]; - out[ 2 ] = renderEntity.shaderParms[ SHADERPARM_BLUE ]; - out[ 3 ] = renderEntity.shaderParms[ SHADERPARM_ALPHA ]; -} - -/* -================ -idEntity::UpdateAnimationControllers -================ -*/ -bool idEntity::UpdateAnimationControllers( void ) { - // any ragdoll and IK animation controllers should be updated here - return false; -} - -/* -================ -idEntity::SetModel -================ -*/ -void idEntity::SetModel( const char *modelname ) { - assert( modelname ); - - FreeModelDef(); - - renderEntity.hModel = renderModelManager->FindModel( modelname ); - - if ( renderEntity.hModel ) { - renderEntity.hModel->Reset(); - } - - renderEntity.callback = NULL; - renderEntity.numJoints = 0; - renderEntity.joints = NULL; - if ( renderEntity.hModel ) { - renderEntity.bounds = renderEntity.hModel->Bounds( &renderEntity ); - } else { - renderEntity.bounds.Zero(); - } - - UpdateVisuals(); -} - -/* -================ -idEntity::SetSkin -================ -*/ -void idEntity::SetSkin( const idDeclSkin *skin ) { - renderEntity.customSkin = skin; - UpdateVisuals(); -} - -/* -================ -idEntity::GetSkin -================ -*/ -const idDeclSkin *idEntity::GetSkin( void ) const { - return renderEntity.customSkin; -} - -/* -================ -idEntity::FreeModelDef -================ -*/ -void idEntity::FreeModelDef( void ) { - if ( modelDefHandle != -1 ) { - gameRenderWorld->FreeEntityDef( modelDefHandle ); - modelDefHandle = -1; - } -} - -/* -================ -idEntity::FreeLightDef -================ -*/ -void idEntity::FreeLightDef( void ) { -} - -/* -================ -idEntity::IsHidden -================ -*/ -bool idEntity::IsHidden( void ) const { - return fl.hidden; -} - -/* -================ -idEntity::Hide -================ -*/ -void idEntity::Hide( void ) { - if ( !IsHidden() ) { - fl.hidden = true; - FreeModelDef(); - UpdateVisuals(); - } -} - -/* -================ -idEntity::Show -================ -*/ -void idEntity::Show( void ) { - if ( IsHidden() ) { - fl.hidden = false; - UpdateVisuals(); - } -} - -/* -================ -idEntity::UpdateModelTransform -================ -*/ -void idEntity::UpdateModelTransform( void ) { - idVec3 origin; - idMat3 axis; - - if ( GetPhysicsToVisualTransform( origin, axis ) ) { - renderEntity.axis = axis * GetPhysics()->GetAxis(); - renderEntity.origin = GetPhysics()->GetOrigin() + origin * renderEntity.axis; - } else { - renderEntity.axis = GetPhysics()->GetAxis(); - renderEntity.origin = GetPhysics()->GetOrigin(); - } -} - -/* -================ -idEntity::UpdateModel -================ -*/ -void idEntity::UpdateModel( void ) { -#ifdef _D3XP - renderEntity.timeGroup = timeGroup; -#endif - - UpdateModelTransform(); - - // check if the entity has an MD5 model - idAnimator *animator = GetAnimator(); - if ( animator && animator->ModelHandle() ) { - // set the callback to update the joints - renderEntity.callback = idEntity::ModelCallback; - } - - // set to invalid number to force an update the next time the PVS areas are retrieved - ClearPVSAreas(); - - // ensure that we call Present this frame - BecomeActive( TH_UPDATEVISUALS ); - -#ifdef _D3XP - // If the entity has an xray skin, go ahead and add it - if ( xraySkin != NULL ) { - xrayEntity = renderEntity; - xrayEntity.xrayIndex = 2; - xrayEntity.customSkin = xraySkin; - - if ( xrayEntityHandle == -1 ) { - xrayEntityHandle = gameRenderWorld->AddEntityDef( &xrayEntity ); - } else { - gameRenderWorld->UpdateEntityDef( xrayEntityHandle, &xrayEntity ); - } - } -#endif -} - -/* -================ -idEntity::UpdateVisuals -================ -*/ -void idEntity::UpdateVisuals( void ) { - UpdateModel(); - UpdateSound(); -} - -/* -================ -idEntity::UpdatePVSAreas -================ -*/ -void idEntity::UpdatePVSAreas( void ) { - int localNumPVSAreas, localPVSAreas[32]; - idBounds modelAbsBounds; - int i; - - modelAbsBounds.FromTransformedBounds( renderEntity.bounds, renderEntity.origin, renderEntity.axis ); - localNumPVSAreas = gameLocal.pvs.GetPVSAreas( modelAbsBounds, localPVSAreas, sizeof( localPVSAreas ) / sizeof( localPVSAreas[0] ) ); - - // FIXME: some particle systems may have huge bounds and end up in many PVS areas - // the first MAX_PVS_AREAS may not be visible to a network client and as a result the particle system may not show up when it should - if ( localNumPVSAreas > MAX_PVS_AREAS ) { - localNumPVSAreas = gameLocal.pvs.GetPVSAreas( idBounds( renderEntity.origin ).Expand( 64.0f ), localPVSAreas, sizeof( localPVSAreas ) / sizeof( localPVSAreas[0] ) ); - } - - for ( numPVSAreas = 0; numPVSAreas < MAX_PVS_AREAS && numPVSAreas < localNumPVSAreas; numPVSAreas++ ) { - PVSAreas[numPVSAreas] = localPVSAreas[numPVSAreas]; - } - - for( i = numPVSAreas; i < MAX_PVS_AREAS; i++ ) { - PVSAreas[ i ] = 0; - } -} - -/* -================ -idEntity::UpdatePVSAreas -================ -*/ -void idEntity::UpdatePVSAreas( const idVec3 &pos ) { - int i; - - numPVSAreas = gameLocal.pvs.GetPVSAreas( idBounds( pos ), PVSAreas, MAX_PVS_AREAS ); - i = numPVSAreas; - while ( i < MAX_PVS_AREAS ) { - PVSAreas[ i++ ] = 0; - } -} - -/* -================ -idEntity::GetNumPVSAreas -================ -*/ -int idEntity::GetNumPVSAreas( void ) { - if ( numPVSAreas < 0 ) { - UpdatePVSAreas(); - } - return numPVSAreas; -} - -/* -================ -idEntity::GetPVSAreas -================ -*/ -const int *idEntity::GetPVSAreas( void ) { - if ( numPVSAreas < 0 ) { - UpdatePVSAreas(); - } - return PVSAreas; -} - -/* -================ -idEntity::ClearPVSAreas -================ -*/ -void idEntity::ClearPVSAreas( void ) { - numPVSAreas = -1; -} - -/* -================ -idEntity::PhysicsTeamInPVS - - FIXME: for networking also return true if any of the entity shadows is in the PVS -================ -*/ -bool idEntity::PhysicsTeamInPVS( pvsHandle_t pvsHandle ) { - idEntity *part; - - if ( teamMaster ) { - for ( part = teamMaster; part; part = part->teamChain ) { - if ( gameLocal.pvs.InCurrentPVS( pvsHandle, part->GetPVSAreas(), part->GetNumPVSAreas() ) ) { - return true; - } - } - } else { - return gameLocal.pvs.InCurrentPVS( pvsHandle, GetPVSAreas(), GetNumPVSAreas() ); - } - return false; -} - -/* -============== -idEntity::ProjectOverlay -============== -*/ -void idEntity::ProjectOverlay( const idVec3 &origin, const idVec3 &dir, float size, const char *material ) { - float s, c; - idMat3 axis, axistemp; - idVec3 localOrigin, localAxis[2]; - idPlane localPlane[2]; - - // make sure the entity has a valid model handle - if ( modelDefHandle < 0 ) { - return; - } - - // only do this on dynamic md5 models - if ( renderEntity.hModel->IsDynamicModel() != DM_CACHED ) { - return; - } - - idMath::SinCos16( gameLocal.random.RandomFloat() * idMath::TWO_PI, s, c ); - - axis[2] = -dir; - axis[2].NormalVectors( axistemp[0], axistemp[1] ); - axis[0] = axistemp[ 0 ] * c + axistemp[ 1 ] * -s; - axis[1] = axistemp[ 0 ] * -s + axistemp[ 1 ] * -c; - - renderEntity.axis.ProjectVector( origin - renderEntity.origin, localOrigin ); - renderEntity.axis.ProjectVector( axis[0], localAxis[0] ); - renderEntity.axis.ProjectVector( axis[1], localAxis[1] ); - - size = 1.0f / size; - localAxis[0] *= size; - localAxis[1] *= size; - - localPlane[0] = localAxis[0]; - localPlane[0][3] = -( localOrigin * localAxis[0] ) + 0.5f; - - localPlane[1] = localAxis[1]; - localPlane[1][3] = -( localOrigin * localAxis[1] ) + 0.5f; - - const idMaterial *mtr = declManager->FindMaterial( material ); - - // project an overlay onto the model - gameRenderWorld->ProjectOverlay( modelDefHandle, localPlane, mtr ); - - // make sure non-animating models update their overlay - UpdateVisuals(); -} - -/* -================ -idEntity::Present - -Present is called to allow entities to generate refEntities, lights, etc for the renderer. -================ -*/ -void idEntity::Present( void ) { - - if ( !gameLocal.isNewFrame ) { - return; - } - - // don't present to the renderer if the entity hasn't changed - if ( !( thinkFlags & TH_UPDATEVISUALS ) ) { - return; - } - BecomeInactive( TH_UPDATEVISUALS ); - - // camera target for remote render views - if ( cameraTarget && gameLocal.InPlayerPVS( this ) ) { - renderEntity.remoteRenderView = cameraTarget->GetRenderView(); - } - - // if set to invisible, skip - if ( !renderEntity.hModel || IsHidden() ) { - return; - } - - // add to refresh list - if ( modelDefHandle == -1 ) { - modelDefHandle = gameRenderWorld->AddEntityDef( &renderEntity ); - } else { - gameRenderWorld->UpdateEntityDef( modelDefHandle, &renderEntity ); - } -} - -/* -================ -idEntity::GetRenderEntity -================ -*/ -renderEntity_t *idEntity::GetRenderEntity( void ) { - return &renderEntity; -} - -/* -================ -idEntity::GetModelDefHandle -================ -*/ -int idEntity::GetModelDefHandle( void ) { - return modelDefHandle; -} - -/* -================ -idEntity::UpdateRenderEntity -================ -*/ -bool idEntity::UpdateRenderEntity( renderEntity_s *renderEntity, const renderView_t *renderView ) { - if ( gameLocal.inCinematic && gameLocal.skipCinematic ) { - return false; - } - - idAnimator *animator = GetAnimator(); - if ( animator ) { -#ifdef _D3XP - SetTimeState ts( timeGroup ); -#endif - - return animator->CreateFrame( gameLocal.time, false ); - } - - return false; -} - -/* -================ -idEntity::ModelCallback - - NOTE: may not change the game state whatsoever! -================ -*/ -bool idEntity::ModelCallback( renderEntity_s *renderEntity, const renderView_t *renderView ) { - idEntity *ent; - - ent = gameLocal.entities[ renderEntity->entityNum ]; - if ( !ent ) { - gameLocal.Error( "idEntity::ModelCallback: callback with NULL game entity" ); - } - - return ent->UpdateRenderEntity( renderEntity, renderView ); -} - -/* -================ -idEntity::GetAnimator - -Subclasses will be responsible for allocating animator. -================ -*/ -idAnimator *idEntity::GetAnimator( void ) { - return NULL; -} - -/* -============= -idEntity::GetRenderView - -This is used by remote camera views to look from an entity -============= -*/ -renderView_t *idEntity::GetRenderView( void ) { - if ( !renderView ) { - renderView = new renderView_t; - } - memset( renderView, 0, sizeof( *renderView ) ); - - renderView->vieworg = GetPhysics()->GetOrigin(); - renderView->fov_x = 120; - renderView->fov_y = 120; - renderView->viewaxis = GetPhysics()->GetAxis(); - - // copy global shader parms - for( int i = 0; i < MAX_GLOBAL_SHADER_PARMS; i++ ) { - renderView->shaderParms[ i ] = gameLocal.globalShaderParms[ i ]; - } - - renderView->globalMaterial = gameLocal.GetGlobalMaterial(); - - renderView->time = gameLocal.time; - - return renderView; -} - -/*********************************************************************** - - Sound - -***********************************************************************/ - -/* -================ -idEntity::CanPlayChatterSounds - -Used for playing chatter sounds on monsters. -================ -*/ -bool idEntity::CanPlayChatterSounds( void ) const { - return true; -} - -/* -================ -idEntity::StartSound -================ -*/ -bool idEntity::StartSound( const char *soundName, const s_channelType channel, int soundShaderFlags, bool broadcast, int *length ) { - const idSoundShader *shader; - const char *sound; - - if ( length ) { - *length = 0; - } - - // we should ALWAYS be playing sounds from the def. - // hardcoded sounds MUST be avoided at all times because they won't get precached. - assert( idStr::Icmpn( soundName, "snd_", 4 ) == 0 ); - - if ( !spawnArgs.GetString( soundName, "", &sound ) ) { - return false; - } - - if ( sound[0] == '\0' ) { - return false; - } - - if ( !gameLocal.isNewFrame ) { - // don't play the sound, but don't report an error - return true; - } - - shader = declManager->FindSound( sound ); - return StartSoundShader( shader, channel, soundShaderFlags, broadcast, length ); -} - -/* -================ -idEntity::StartSoundShader -================ -*/ -bool idEntity::StartSoundShader( const idSoundShader *shader, const s_channelType channel, int soundShaderFlags, bool broadcast, int *length ) { - float diversity; - int len; - - if ( length ) { - *length = 0; - } - - if ( !shader ) { - return false; - } - - if ( !gameLocal.isNewFrame ) { - return true; - } - - if ( gameLocal.isServer && broadcast ) { - idBitMsg msg; - byte msgBuf[MAX_EVENT_PARAM_SIZE]; - - msg.Init( msgBuf, sizeof( msgBuf ) ); - msg.BeginWriting(); - msg.WriteInt( gameLocal.ServerRemapDecl( -1, DECL_SOUND, shader->Index() ) ); - msg.WriteByte( channel ); - ServerSendEvent( EVENT_STARTSOUNDSHADER, &msg, false, -1 ); - } - - // set a random value for diversity unless one was parsed from the entity - if ( refSound.diversity < 0.0f ) { - diversity = gameLocal.random.RandomFloat(); - } else { - diversity = refSound.diversity; - } - - // if we don't have a soundEmitter allocated yet, get one now - if ( !refSound.referenceSound ) { - refSound.referenceSound = gameSoundWorld->AllocSoundEmitter(); - } - - UpdateSound(); - - len = refSound.referenceSound->StartSound( shader, channel, diversity, soundShaderFlags, !timeGroup /*_D3XP*/ ); - if ( length ) { - *length = len; - } - - // set reference to the sound for shader synced effects - renderEntity.referenceSound = refSound.referenceSound; - - return true; -} - -/* -================ -idEntity::StopSound -================ -*/ -void idEntity::StopSound( const s_channelType channel, bool broadcast ) { - if ( !gameLocal.isNewFrame ) { - return; - } - - if ( gameLocal.isServer && broadcast ) { - idBitMsg msg; - byte msgBuf[MAX_EVENT_PARAM_SIZE]; - - msg.Init( msgBuf, sizeof( msgBuf ) ); - msg.BeginWriting(); - msg.WriteByte( channel ); - ServerSendEvent( EVENT_STOPSOUNDSHADER, &msg, false, -1 ); - } - - if ( refSound.referenceSound ) { - refSound.referenceSound->StopSound( channel ); - } -} - -/* -================ -idEntity::SetSoundVolume - - Must be called before starting a new sound. -================ -*/ -void idEntity::SetSoundVolume( float volume ) { - refSound.parms.volume = volume; -} - -/* -================ -idEntity::UpdateSound -================ -*/ -void idEntity::UpdateSound( void ) { - if ( refSound.referenceSound ) { - idVec3 origin; - idMat3 axis; - - if ( GetPhysicsToSoundTransform( origin, axis ) ) { - refSound.origin = GetPhysics()->GetOrigin() + origin * axis; - } else { - refSound.origin = GetPhysics()->GetOrigin(); - } - - refSound.referenceSound->UpdateEmitter( refSound.origin, refSound.listenerId, &refSound.parms ); - } -} - -/* -================ -idEntity::GetListenerId -================ -*/ -int idEntity::GetListenerId( void ) const { - return refSound.listenerId; -} - -/* -================ -idEntity::GetSoundEmitter -================ -*/ -idSoundEmitter *idEntity::GetSoundEmitter( void ) const { - return refSound.referenceSound; -} - -/* -================ -idEntity::FreeSoundEmitter -================ -*/ -void idEntity::FreeSoundEmitter( bool immediate ) { - if ( refSound.referenceSound ) { - refSound.referenceSound->Free( immediate ); - refSound.referenceSound = NULL; - } -} - -/*********************************************************************** - - entity binding - -***********************************************************************/ - -/* -================ -idEntity::PreBind -================ -*/ -void idEntity::PreBind( void ) { -} - -/* -================ -idEntity::PostBind -================ -*/ -void idEntity::PostBind( void ) { -} - -/* -================ -idEntity::PreUnbind -================ -*/ -void idEntity::PreUnbind( void ) { -} - -/* -================ -idEntity::PostUnbind -================ -*/ -void idEntity::PostUnbind( void ) { -} - -/* -================ -idEntity::InitBind -================ -*/ -bool idEntity::InitBind( idEntity *master ) { - - if ( master == this ) { - gameLocal.Error( "Tried to bind an object to itself." ); - return false; - } - - if ( this == gameLocal.world ) { - gameLocal.Error( "Tried to bind world to another entity" ); - return false; - } - - // unbind myself from my master - Unbind(); - - // add any bind constraints to an articulated figure - if ( master && IsType( idAFEntity_Base::Type ) ) { - static_cast(this)->AddBindConstraints(); - } - - if ( !master || master == gameLocal.world ) { - // this can happen in scripts, so safely exit out. - return false; - } - - return true; -} - -/* -================ -idEntity::FinishBind -================ -*/ -void idEntity::FinishBind( void ) { - - // set the master on the physics object - physics->SetMaster( bindMaster, fl.bindOrientated ); - - // We are now separated from our previous team and are either - // an individual, or have a team of our own. Now we can join - // the new bindMaster's team. Bindmaster must be set before - // joining the team, or we will be placed in the wrong position - // on the team. - JoinTeam( bindMaster ); - - // if our bindMaster is enabled during a cinematic, we must be, too - cinematic = bindMaster->cinematic; - - // make sure the team master is active so that physics get run - teamMaster->BecomeActive( TH_PHYSICS ); -} - -/* -================ -idEntity::Bind - - bind relative to the visual position of the master -================ -*/ -void idEntity::Bind( idEntity *master, bool orientated ) { - - if ( !InitBind( master ) ) { - return; - } - - PreBind(); - - bindJoint = INVALID_JOINT; - bindBody = -1; - bindMaster = master; - fl.bindOrientated = orientated; - - FinishBind(); - - PostBind( ); -} - -/* -================ -idEntity::BindToJoint - - bind relative to a joint of the md5 model used by the master -================ -*/ -void idEntity::BindToJoint( idEntity *master, const char *jointname, bool orientated ) { - jointHandle_t jointnum; - idAnimator *masterAnimator; - - if ( !InitBind( master ) ) { - return; - } - - masterAnimator = master->GetAnimator(); - if ( !masterAnimator ) { - gameLocal.Warning( "idEntity::BindToJoint: entity '%s' cannot support skeletal models.", master->GetName() ); - return; - } - - jointnum = masterAnimator->GetJointHandle( jointname ); - if ( jointnum == INVALID_JOINT ) { - gameLocal.Warning( "idEntity::BindToJoint: joint '%s' not found on entity '%s'.", jointname, master->GetName() ); - } - - PreBind(); - - bindJoint = jointnum; - bindBody = -1; - bindMaster = master; - fl.bindOrientated = orientated; - - FinishBind(); - - PostBind(); -} - -/* -================ -idEntity::BindToJoint - - bind relative to a joint of the md5 model used by the master -================ -*/ -void idEntity::BindToJoint( idEntity *master, jointHandle_t jointnum, bool orientated ) { - - if ( !InitBind( master ) ) { - return; - } - - PreBind(); - - bindJoint = jointnum; - bindBody = -1; - bindMaster = master; - fl.bindOrientated = orientated; - - FinishBind(); - - PostBind(); -} - -/* -================ -idEntity::BindToBody - - bind relative to a collision model used by the physics of the master -================ -*/ -void idEntity::BindToBody( idEntity *master, int bodyId, bool orientated ) { - - if ( !InitBind( master ) ) { - return; - } - - if ( bodyId < 0 ) { - gameLocal.Warning( "idEntity::BindToBody: body '%d' not found.", bodyId ); - } - - PreBind(); - - bindJoint = INVALID_JOINT; - bindBody = bodyId; - bindMaster = master; - fl.bindOrientated = orientated; - - FinishBind(); - - PostBind(); -} - -/* -================ -idEntity::Unbind -================ -*/ -void idEntity::Unbind( void ) { - idEntity * prev; - idEntity * next; - idEntity * last; - idEntity * ent; - - // remove any bind constraints from an articulated figure - if ( IsType( idAFEntity_Base::Type ) ) { - static_cast(this)->RemoveBindConstraints(); - } - - if ( !bindMaster ) { - return; - } - - if ( !teamMaster ) { - // Teammaster already has been freed - bindMaster = NULL; - return; - } - - PreUnbind(); - - if ( physics ) { - physics->SetMaster( NULL, fl.bindOrientated ); - } - - // We're still part of a team, so that means I have to extricate myself - // and any entities that are bound to me from the old team. - // Find the node previous to me in the team - prev = teamMaster; - for( ent = teamMaster->teamChain; ent && ( ent != this ); ent = ent->teamChain ) { - prev = ent; - } - - assert( ent == this ); // If ent is not pointing to this, then something is very wrong. - - // Find the last node in my team that is bound to me. - // Also find the first node not bound to me, if one exists. - last = this; - for( next = teamChain; next != NULL; next = next->teamChain ) { - if ( !next->IsBoundTo( this ) ) { - break; - } - - // Tell them I'm now the teamMaster - next->teamMaster = this; - last = next; - } - - // disconnect the last member of our team from the old team - last->teamChain = NULL; - - // connect up the previous member of the old team to the node that - // follow the last node bound to me (if one exists). - if ( teamMaster != this ) { - prev->teamChain = next; - if ( !next && ( teamMaster == prev ) ) { - prev->teamMaster = NULL; - } - } else if ( next ) { - // If we were the teamMaster, then the nodes that were not bound to me are now - // a disconnected chain. Make them into their own team. - for( ent = next; ent->teamChain != NULL; ent = ent->teamChain ) { - ent->teamMaster = next; - } - next->teamMaster = next; - } - - // If we don't have anyone on our team, then clear the team variables. - if ( teamChain ) { - // make myself my own team - teamMaster = this; - } else { - // no longer a team - teamMaster = NULL; - } - - bindJoint = INVALID_JOINT; - bindBody = -1; - bindMaster = NULL; - - PostUnbind(); -} - -/* -================ -idEntity::RemoveBinds -================ -*/ -void idEntity::RemoveBinds( void ) { - idEntity *ent; - idEntity *next; - - for( ent = teamChain; ent != NULL; ent = next ) { - next = ent->teamChain; - if ( ent->bindMaster == this ) { - ent->Unbind(); - ent->PostEventMS( &EV_Remove, 0 ); - next = teamChain; - } - } -} - -/* -================ -idEntity::IsBound -================ -*/ -bool idEntity::IsBound( void ) const { - if ( bindMaster ) { - return true; - } - return false; -} - -/* -================ -idEntity::IsBoundTo -================ -*/ -bool idEntity::IsBoundTo( idEntity *master ) const { - idEntity *ent; - - if ( !bindMaster ) { - return false; - } - - for ( ent = bindMaster; ent != NULL; ent = ent->bindMaster ) { - if ( ent == master ) { - return true; - } - } - - return false; -} - -/* -================ -idEntity::GetBindMaster -================ -*/ -idEntity *idEntity::GetBindMaster( void ) const { - return bindMaster; -} - -/* -================ -idEntity::GetBindJoint -================ -*/ -jointHandle_t idEntity::GetBindJoint( void ) const { - return bindJoint; -} - -/* -================ -idEntity::GetBindBody -================ -*/ -int idEntity::GetBindBody( void ) const { - return bindBody; -} - -/* -================ -idEntity::GetTeamMaster -================ -*/ -idEntity *idEntity::GetTeamMaster( void ) const { - return teamMaster; -} - -/* -================ -idEntity::GetNextTeamEntity -================ -*/ -idEntity *idEntity::GetNextTeamEntity( void ) const { - return teamChain; -} - -/* -===================== -idEntity::ConvertLocalToWorldTransform -===================== -*/ -void idEntity::ConvertLocalToWorldTransform( idVec3 &offset, idMat3 &axis ) { - UpdateModelTransform(); - - offset = renderEntity.origin + offset * renderEntity.axis; - axis *= renderEntity.axis; -} - -/* -================ -idEntity::GetLocalVector - -Takes a vector in worldspace and transforms it into the parent -object's localspace. - -Note: Does not take origin into acount. Use getLocalCoordinate to -convert coordinates. -================ -*/ -idVec3 idEntity::GetLocalVector( const idVec3 &vec ) const { - idVec3 pos; - - if ( !bindMaster ) { - return vec; - } - - idVec3 masterOrigin; - idMat3 masterAxis; - - GetMasterPosition( masterOrigin, masterAxis ); - masterAxis.ProjectVector( vec, pos ); - - return pos; -} - -/* -================ -idEntity::GetLocalCoordinates - -Takes a vector in world coordinates and transforms it into the parent -object's local coordinates. -================ -*/ -idVec3 idEntity::GetLocalCoordinates( const idVec3 &vec ) const { - idVec3 pos; - - if ( !bindMaster ) { - return vec; - } - - idVec3 masterOrigin; - idMat3 masterAxis; - - GetMasterPosition( masterOrigin, masterAxis ); - masterAxis.ProjectVector( vec - masterOrigin, pos ); - - return pos; -} - -/* -================ -idEntity::GetWorldVector - -Takes a vector in the parent object's local coordinates and transforms -it into world coordinates. - -Note: Does not take origin into acount. Use getWorldCoordinate to -convert coordinates. -================ -*/ -idVec3 idEntity::GetWorldVector( const idVec3 &vec ) const { - idVec3 pos; - - if ( !bindMaster ) { - return vec; - } - - idVec3 masterOrigin; - idMat3 masterAxis; - - GetMasterPosition( masterOrigin, masterAxis ); - masterAxis.UnprojectVector( vec, pos ); - - return pos; -} - -/* -================ -idEntity::GetWorldCoordinates - -Takes a vector in the parent object's local coordinates and transforms -it into world coordinates. -================ -*/ -idVec3 idEntity::GetWorldCoordinates( const idVec3 &vec ) const { - idVec3 pos; - - if ( !bindMaster ) { - return vec; - } - - idVec3 masterOrigin; - idMat3 masterAxis; - - GetMasterPosition( masterOrigin, masterAxis ); - masterAxis.UnprojectVector( vec, pos ); - pos += masterOrigin; - - return pos; -} - -/* -================ -idEntity::GetMasterPosition -================ -*/ -bool idEntity::GetMasterPosition( idVec3 &masterOrigin, idMat3 &masterAxis ) const { - idVec3 localOrigin; - idMat3 localAxis; - idAnimator *masterAnimator; - - if ( bindMaster ) { - // if bound to a joint of an animated model - if ( bindJoint != INVALID_JOINT ) { - masterAnimator = bindMaster->GetAnimator(); - if ( !masterAnimator ) { - masterOrigin = vec3_origin; - masterAxis = mat3_identity; - return false; - } else { - masterAnimator->GetJointTransform( bindJoint, gameLocal.time, masterOrigin, masterAxis ); - masterAxis *= bindMaster->renderEntity.axis; - masterOrigin = bindMaster->renderEntity.origin + masterOrigin * bindMaster->renderEntity.axis; - } - } else if ( bindBody >= 0 && bindMaster->GetPhysics() ) { - masterOrigin = bindMaster->GetPhysics()->GetOrigin( bindBody ); - masterAxis = bindMaster->GetPhysics()->GetAxis( bindBody ); - } else { - masterOrigin = bindMaster->renderEntity.origin; - masterAxis = bindMaster->renderEntity.axis; - } - return true; - } else { - masterOrigin = vec3_origin; - masterAxis = mat3_identity; - return false; - } -} - -/* -================ -idEntity::GetWorldVelocities -================ -*/ -void idEntity::GetWorldVelocities( idVec3 &linearVelocity, idVec3 &angularVelocity ) const { - - linearVelocity = physics->GetLinearVelocity(); - angularVelocity = physics->GetAngularVelocity(); - - if ( bindMaster ) { - idVec3 masterOrigin, masterLinearVelocity, masterAngularVelocity; - idMat3 masterAxis; - - // get position of master - GetMasterPosition( masterOrigin, masterAxis ); - - // get master velocities - bindMaster->GetWorldVelocities( masterLinearVelocity, masterAngularVelocity ); - - // linear velocity relative to master plus master linear and angular velocity - linearVelocity = linearVelocity * masterAxis + masterLinearVelocity + - masterAngularVelocity.Cross( GetPhysics()->GetOrigin() - masterOrigin ); - } -} - -/* -================ -idEntity::JoinTeam -================ -*/ -void idEntity::JoinTeam( idEntity *teammember ) { - idEntity *ent; - idEntity *master; - idEntity *prev; - idEntity *next; - - // if we're already on a team, quit it so we can join this one - if ( teamMaster && ( teamMaster != this ) ) { - QuitTeam(); - } - - assert( teammember ); - - if ( teammember == this ) { - teamMaster = this; - return; - } - - // check if our new team mate is already on a team - master = teammember->teamMaster; - if ( !master ) { - // he's not on a team, so he's the new teamMaster - master = teammember; - teammember->teamMaster = teammember; - teammember->teamChain = this; - - // make anyone who's bound to me part of the new team - for( ent = teamChain; ent != NULL; ent = ent->teamChain ) { - ent->teamMaster = master; - } - } else { - // skip past the chain members bound to the entity we're teaming up with - prev = teammember; - next = teammember->teamChain; - if ( bindMaster ) { - // if we have a bindMaster, join after any entities bound to the entity - // we're joining - while( next && next->IsBoundTo( teammember ) ) { - prev = next; - next = next->teamChain; - } - } else { - // if we're not bound to someone, then put us at the end of the team - while( next ) { - prev = next; - next = next->teamChain; - } - } - - // make anyone who's bound to me part of the new team and - // also find the last member of my team - for( ent = this; ent->teamChain != NULL; ent = ent->teamChain ) { - ent->teamChain->teamMaster = master; - } - - prev->teamChain = this; - ent->teamChain = next; - } - - teamMaster = master; - - // reorder the active entity list - gameLocal.sortTeamMasters = true; -} - -/* -================ -idEntity::QuitTeam -================ -*/ -void idEntity::QuitTeam( void ) { - idEntity *ent; - - if ( !teamMaster ) { - return; - } - - // check if I'm the teamMaster - if ( teamMaster == this ) { - // do we have more than one teammate? - if ( !teamChain->teamChain ) { - // no, break up the team - teamChain->teamMaster = NULL; - } else { - // yes, so make the first teammate the teamMaster - for( ent = teamChain; ent; ent = ent->teamChain ) { - ent->teamMaster = teamChain; - } - } - } else { - assert( teamMaster ); - assert( teamMaster->teamChain ); - - // find the previous member of the teamChain - ent = teamMaster; - while( ent->teamChain != this ) { - assert( ent->teamChain ); // this should never happen - ent = ent->teamChain; - } - - // remove this from the teamChain - ent->teamChain = teamChain; - - // if no one is left on the team, break it up - if ( !teamMaster->teamChain ) { - teamMaster->teamMaster = NULL; - } - } - - teamMaster = NULL; - teamChain = NULL; -} - -/*********************************************************************** - - Physics. - -***********************************************************************/ - -/* -================ -idEntity::InitDefaultPhysics -================ -*/ -void idEntity::InitDefaultPhysics( const idVec3 &origin, const idMat3 &axis ) { - const char *temp; - idClipModel *clipModel = NULL; - - // check if a clipmodel key/value pair is set - if ( spawnArgs.GetString( "clipmodel", "", &temp ) ) { - if ( idClipModel::CheckModel( temp ) ) { - clipModel = new idClipModel( temp ); - } - } - - if ( !spawnArgs.GetBool( "noclipmodel", "0" ) ) { - - // check if mins/maxs or size key/value pairs are set - if ( !clipModel ) { - idVec3 size; - idBounds bounds; - bool setClipModel = false; - - if ( spawnArgs.GetVector( "mins", NULL, bounds[0] ) && - spawnArgs.GetVector( "maxs", NULL, bounds[1] ) ) { - setClipModel = true; - if ( bounds[0][0] > bounds[1][0] || bounds[0][1] > bounds[1][1] || bounds[0][2] > bounds[1][2] ) { - gameLocal.Error( "Invalid bounds '%s'-'%s' on entity '%s'", bounds[0].ToString(), bounds[1].ToString(), name.c_str() ); - } - } else if ( spawnArgs.GetVector( "size", NULL, size ) ) { - if ( ( size.x < 0.0f ) || ( size.y < 0.0f ) || ( size.z < 0.0f ) ) { - gameLocal.Error( "Invalid size '%s' on entity '%s'", size.ToString(), name.c_str() ); - } - bounds[0].Set( size.x * -0.5f, size.y * -0.5f, 0.0f ); - bounds[1].Set( size.x * 0.5f, size.y * 0.5f, size.z ); - setClipModel = true; - } - - if ( setClipModel ) { - int numSides; - idTraceModel trm; - - if ( spawnArgs.GetInt( "cylinder", "0", numSides ) && numSides > 0 ) { - trm.SetupCylinder( bounds, numSides < 3 ? 3 : numSides ); - } else if ( spawnArgs.GetInt( "cone", "0", numSides ) && numSides > 0 ) { - trm.SetupCone( bounds, numSides < 3 ? 3 : numSides ); - } else { - trm.SetupBox( bounds ); - } - clipModel = new idClipModel( trm ); - } - } - - // check if the visual model can be used as collision model - if ( !clipModel ) { - temp = spawnArgs.GetString( "model" ); - if ( ( temp != NULL ) && ( *temp != 0 ) ) { - if ( idClipModel::CheckModel( temp ) ) { - clipModel = new idClipModel( temp ); - } - } - } - } - - defaultPhysicsObj.SetSelf( this ); - defaultPhysicsObj.SetClipModel( clipModel, 1.0f ); - defaultPhysicsObj.SetOrigin( origin ); - defaultPhysicsObj.SetAxis( axis ); - - physics = &defaultPhysicsObj; -} - -/* -================ -idEntity::SetPhysics -================ -*/ -void idEntity::SetPhysics( idPhysics *phys ) { - // clear any contacts the current physics object has - if ( physics ) { - physics->ClearContacts(); - } - // set new physics object or set the default physics if NULL - if ( phys != NULL ) { - defaultPhysicsObj.SetClipModel( NULL, 1.0f ); - physics = phys; - physics->Activate(); - } else { - physics = &defaultPhysicsObj; - } - physics->UpdateTime( gameLocal.time ); - physics->SetMaster( bindMaster, fl.bindOrientated ); -} - -/* -================ -idEntity::RestorePhysics -================ -*/ -void idEntity::RestorePhysics( idPhysics *phys ) { - assert( phys != NULL ); - // restore physics pointer - physics = phys; -} - -/* -================ -idEntity::GetPhysics -================ -*/ -idPhysics *idEntity::GetPhysics( void ) const { - return physics; -} - -/* -================ -idEntity::RunPhysics -================ -*/ -bool idEntity::RunPhysics( void ) { - int i, reachedTime, startTime, endTime; - idEntity * part, *blockedPart, *blockingEntity; - bool moved; - - // don't run physics if not enabled - if ( !( thinkFlags & TH_PHYSICS ) ) { - // however do update any animation controllers - if ( UpdateAnimationControllers() ) { - BecomeActive( TH_ANIMATE ); - } - return false; - } - - // if this entity is a team slave don't do anything because the team master will handle everything - if ( teamMaster && teamMaster != this ) { - return false; - } - - startTime = gameLocal.previousTime; - endTime = gameLocal.time; - - gameLocal.push.InitSavingPushedEntityPositions(); - blockedPart = NULL; - - // save the physics state of the whole team and disable the team for collision detection - for ( part = this; part != NULL; part = part->teamChain ) { - if ( part->physics ) { - if ( !part->fl.solidForTeam ) { - part->physics->DisableClip(); - } - part->physics->SaveState(); - } - } - - // move the whole team - for ( part = this; part != NULL; part = part->teamChain ) { - - if ( part->physics ) { - - // run physics - moved = part->physics->Evaluate( endTime - startTime, endTime ); - - // check if the object is blocked - blockingEntity = part->physics->GetBlockingEntity(); - if ( blockingEntity ) { - blockedPart = part; - break; - } - - // if moved or forced to update the visual position and orientation from the physics - if ( moved || part->fl.forcePhysicsUpdate ) { - part->UpdateFromPhysics( false ); - } - - // update any animation controllers here so an entity bound - // to a joint of this entity gets the correct position - if ( part->UpdateAnimationControllers() ) { - part->BecomeActive( TH_ANIMATE ); - } - } - } - - // enable the whole team for collision detection - for ( part = this; part != NULL; part = part->teamChain ) { - if ( part->physics ) { - if ( !part->fl.solidForTeam ) { - part->physics->EnableClip(); - } - } - } - - // if one of the team entities is a pusher and blocked - if ( blockedPart ) { - // move the parts back to the previous position - for ( part = this; part != blockedPart; part = part->teamChain ) { - - if ( part->physics ) { - - // restore the physics state - part->physics->RestoreState(); - - // move back the visual position and orientation - part->UpdateFromPhysics( true ); - } - } - for ( part = this; part != NULL; part = part->teamChain ) { - if ( part->physics ) { - // update the physics time without moving - part->physics->UpdateTime( endTime ); - } - } - - // restore the positions of any pushed entities - gameLocal.push.RestorePushedEntityPositions(); - - if ( gameLocal.isClient ) { - return false; - } - - // if the master pusher has a "blocked" function, call it - Signal( SIG_BLOCKED ); - ProcessEvent( &EV_TeamBlocked, blockedPart, blockingEntity ); - // call the blocked function on the blocked part - blockedPart->ProcessEvent( &EV_PartBlocked, blockingEntity ); - return false; - } - - // set pushed - for ( i = 0; i < gameLocal.push.GetNumPushedEntities(); i++ ) { - idEntity *ent = gameLocal.push.GetPushedEntity( i ); - ent->physics->SetPushed( endTime - startTime ); - } - - if ( gameLocal.isClient ) { - return true; - } - - // post reached event if the current time is at or past the end point of the motion - for ( part = this; part != NULL; part = part->teamChain ) { - - if ( part->physics ) { - - reachedTime = part->physics->GetLinearEndTime(); - if ( startTime < reachedTime && endTime >= reachedTime ) { - part->ProcessEvent( &EV_ReachedPos ); - } - reachedTime = part->physics->GetAngularEndTime(); - if ( startTime < reachedTime && endTime >= reachedTime ) { - part->ProcessEvent( &EV_ReachedAng ); - } - } - } - - return true; -} - -/* -================ -idEntity::UpdateFromPhysics -================ -*/ -void idEntity::UpdateFromPhysics( bool moveBack ) { - - if ( IsType( idActor::Type ) ) { - idActor *actor = static_cast( this ); - - // set master delta angles for actors - if ( GetBindMaster() ) { - idAngles delta = actor->GetDeltaViewAngles(); - if ( moveBack ) { - delta.yaw -= static_cast(physics)->GetMasterDeltaYaw(); - } else { - delta.yaw += static_cast(physics)->GetMasterDeltaYaw(); - } - actor->SetDeltaViewAngles( delta ); - } - } - - UpdateVisuals(); -} - -/* -================ -idEntity::SetOrigin -================ -*/ -void idEntity::SetOrigin( const idVec3 &org ) { - - GetPhysics()->SetOrigin( org ); - - UpdateVisuals(); -} - -/* -================ -idEntity::SetAxis -================ -*/ -void idEntity::SetAxis( const idMat3 &axis ) { - - if ( GetPhysics()->IsType( idPhysics_Actor::Type ) ) { - static_cast(this)->viewAxis = axis; - } else { - GetPhysics()->SetAxis( axis ); - } - - UpdateVisuals(); -} - -/* -================ -idEntity::SetAngles -================ -*/ -void idEntity::SetAngles( const idAngles &ang ) { - SetAxis( ang.ToMat3() ); -} - -/* -================ -idEntity::GetFloorPos -================ -*/ -bool idEntity::GetFloorPos( float max_dist, idVec3 &floorpos ) const { - trace_t result; - - if ( !GetPhysics()->HasGroundContacts() ) { - GetPhysics()->ClipTranslation( result, GetPhysics()->GetGravityNormal() * max_dist, NULL ); - if ( result.fraction < 1.0f ) { - floorpos = result.endpos; - return true; - } else { - floorpos = GetPhysics()->GetOrigin(); - return false; - } - } else { - floorpos = GetPhysics()->GetOrigin(); - return true; - } -} - -/* -================ -idEntity::GetPhysicsToVisualTransform -================ -*/ -bool idEntity::GetPhysicsToVisualTransform( idVec3 &origin, idMat3 &axis ) { - return false; -} - -/* -================ -idEntity::GetPhysicsToSoundTransform -================ -*/ -bool idEntity::GetPhysicsToSoundTransform( idVec3 &origin, idMat3 &axis ) { - // by default play the sound at the center of the bounding box of the first clip model - if ( GetPhysics()->GetNumClipModels() > 0 ) { - origin = GetPhysics()->GetBounds().GetCenter(); - axis.Identity(); - return true; - } - return false; -} - -/* -================ -idEntity::Collide -================ -*/ -bool idEntity::Collide( const trace_t &collision, const idVec3 &velocity ) { - // this entity collides with collision.c.entityNum - return false; -} - -/* -================ -idEntity::GetImpactInfo -================ -*/ -void idEntity::GetImpactInfo( idEntity *ent, int id, const idVec3 &point, impactInfo_t *info ) { - GetPhysics()->GetImpactInfo( id, point, info ); -} - -/* -================ -idEntity::ApplyImpulse -================ -*/ -void idEntity::ApplyImpulse( idEntity *ent, int id, const idVec3 &point, const idVec3 &impulse ) { - GetPhysics()->ApplyImpulse( id, point, impulse ); -} - -/* -================ -idEntity::AddForce -================ -*/ -void idEntity::AddForce( idEntity *ent, int id, const idVec3 &point, const idVec3 &force ) { - GetPhysics()->AddForce( id, point, force ); -} - -/* -================ -idEntity::ActivatePhysics -================ -*/ -void idEntity::ActivatePhysics( idEntity *ent ) { - GetPhysics()->Activate(); -} - -/* -================ -idEntity::IsAtRest -================ -*/ -bool idEntity::IsAtRest( void ) const { - return GetPhysics()->IsAtRest(); -} - -/* -================ -idEntity::GetRestStartTime -================ -*/ -int idEntity::GetRestStartTime( void ) const { - return GetPhysics()->GetRestStartTime(); -} - -/* -================ -idEntity::AddContactEntity -================ -*/ -void idEntity::AddContactEntity( idEntity *ent ) { - GetPhysics()->AddContactEntity( ent ); -} - -/* -================ -idEntity::RemoveContactEntity -================ -*/ -void idEntity::RemoveContactEntity( idEntity *ent ) { - GetPhysics()->RemoveContactEntity( ent ); -} - - - -/*********************************************************************** - - Damage - -***********************************************************************/ - -/* -============ -idEntity::CanDamage - -Returns true if the inflictor can directly damage the target. Used for -explosions and melee attacks. -============ -*/ -bool idEntity::CanDamage( const idVec3 &origin, idVec3 &damagePoint ) const { - idVec3 dest; - trace_t tr; - idVec3 midpoint; - - // use the midpoint of the bounds instead of the origin, because - // bmodels may have their origin at 0,0,0 - midpoint = ( GetPhysics()->GetAbsBounds()[0] + GetPhysics()->GetAbsBounds()[1] ) * 0.5; - - dest = midpoint; - gameLocal.clip.TracePoint( tr, origin, dest, MASK_SOLID, NULL ); - if ( tr.fraction == 1.0 || ( gameLocal.GetTraceEntity( tr ) == this ) ) { - damagePoint = tr.endpos; - return true; - } - - // this should probably check in the plane of projection, rather than in world coordinate - dest = midpoint; - dest[0] += 15.0; - dest[1] += 15.0; - gameLocal.clip.TracePoint( tr, origin, dest, MASK_SOLID, NULL ); - if ( tr.fraction == 1.0 || ( gameLocal.GetTraceEntity( tr ) == this ) ) { - damagePoint = tr.endpos; - return true; - } - - dest = midpoint; - dest[0] += 15.0; - dest[1] -= 15.0; - gameLocal.clip.TracePoint( tr, origin, dest, MASK_SOLID, NULL ); - if ( tr.fraction == 1.0 || ( gameLocal.GetTraceEntity( tr ) == this ) ) { - damagePoint = tr.endpos; - return true; - } - - dest = midpoint; - dest[0] -= 15.0; - dest[1] += 15.0; - gameLocal.clip.TracePoint( tr, origin, dest, MASK_SOLID, NULL ); - if ( tr.fraction == 1.0 || ( gameLocal.GetTraceEntity( tr ) == this ) ) { - damagePoint = tr.endpos; - return true; - } - - dest = midpoint; - dest[0] -= 15.0; - dest[1] -= 15.0; - gameLocal.clip.TracePoint( tr, origin, dest, MASK_SOLID, NULL ); - if ( tr.fraction == 1.0 || ( gameLocal.GetTraceEntity( tr ) == this ) ) { - damagePoint = tr.endpos; - return true; - } - - dest = midpoint; - dest[2] += 15.0; - gameLocal.clip.TracePoint( tr, origin, dest, MASK_SOLID, NULL ); - if ( tr.fraction == 1.0 || ( gameLocal.GetTraceEntity( tr ) == this ) ) { - damagePoint = tr.endpos; - return true; - } - - dest = midpoint; - dest[2] -= 15.0; - gameLocal.clip.TracePoint( tr, origin, dest, MASK_SOLID, NULL ); - if ( tr.fraction == 1.0 || ( gameLocal.GetTraceEntity( tr ) == this ) ) { - damagePoint = tr.endpos; - return true; - } - - return false; -} - -/* -================ -idEntity::DamageFeedback - -callback function for when another entity received damage from this entity. damage can be adjusted and returned to the caller. -================ -*/ -void idEntity::DamageFeedback( idEntity *victim, idEntity *inflictor, int &damage ) { - // implemented in subclasses -} - -/* -============ -Damage - -this entity that is being damaged -inflictor entity that is causing the damage -attacker entity that caused the inflictor to damage targ - example: this=monster, inflictor=rocket, attacker=player - -dir direction of the attack for knockback in global space -point point at which the damage is being inflicted, used for headshots -damage amount of damage being inflicted - -inflictor, attacker, dir, and point can be NULL for environmental effects - -============ -*/ -void idEntity::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, - const char *damageDefName, const float damageScale, const int location ) { - if ( !fl.takedamage ) { - return; - } - -#ifdef _D3XP - SetTimeState ts( timeGroup ); -#endif - - if ( !inflictor ) { - inflictor = gameLocal.world; - } - - if ( !attacker ) { - attacker = gameLocal.world; - } - - const idDict *damageDef = gameLocal.FindEntityDefDict( damageDefName ); - if ( !damageDef ) { - gameLocal.Error( "Unknown damageDef '%s'\n", damageDefName ); - } - - int damage = damageDef->GetInt( "damage" ); - - // inform the attacker that they hit someone - attacker->DamageFeedback( this, inflictor, damage ); - if ( damage ) { - // do the damage - health -= damage; - if ( health <= 0 ) { - if ( health < -999 ) { - health = -999; - } - - Killed( inflictor, attacker, damage, dir, location ); - } else { - Pain( inflictor, attacker, damage, dir, location ); - } - } -} - -/* -================ -idEntity::AddDamageEffect -================ -*/ -void idEntity::AddDamageEffect( const trace_t &collision, const idVec3 &velocity, const char *damageDefName ) { - const char *sound, *decal, *key; - - const idDeclEntityDef *def = gameLocal.FindEntityDef( damageDefName, false ); - if ( def == NULL ) { - return; - } - - const char *materialType = gameLocal.sufaceTypeNames[ collision.c.material->GetSurfaceType() ]; - - // start impact sound based on material type - key = va( "snd_%s", materialType ); - sound = spawnArgs.GetString( key ); - if ( *sound == '\0' ) { - sound = def->dict.GetString( key ); - } - if ( *sound != '\0' ) { - StartSoundShader( declManager->FindSound( sound ), SND_CHANNEL_BODY, 0, false, NULL ); - } - - if ( g_decals.GetBool() ) { - // place a wound overlay on the model - key = va( "mtr_wound_%s", materialType ); - decal = spawnArgs.RandomPrefix( key, gameLocal.random ); - if ( *decal == '\0' ) { - decal = def->dict.RandomPrefix( key, gameLocal.random ); - } - if ( *decal != '\0' ) { - idVec3 dir = velocity; - dir.Normalize(); - ProjectOverlay( collision.c.point, dir, 20.0f, decal ); - } - } -} - -/* -============ -idEntity::Pain - -Called whenever an entity recieves damage. Returns whether the entity responds to the pain. -This is a virtual function that subclasses are expected to implement. -============ -*/ -bool idEntity::Pain( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) { - return false; -} - -/* -============ -idEntity::Killed - -Called whenever an entity's health is reduced to 0 or less. -This is a virtual function that subclasses are expected to implement. -============ -*/ -void idEntity::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) { -} - - -/*********************************************************************** - - Script functions - -***********************************************************************/ - -/* -================ -idEntity::ShouldConstructScriptObjectAtSpawn - -Called during idEntity::Spawn to see if it should construct the script object or not. -Overridden by subclasses that need to spawn the script object themselves. -================ -*/ -bool idEntity::ShouldConstructScriptObjectAtSpawn( void ) const { - return true; -} - -/* -================ -idEntity::ConstructScriptObject - -Called during idEntity::Spawn. Calls the constructor on the script object. -Can be overridden by subclasses when a thread doesn't need to be allocated. -================ -*/ -idThread *idEntity::ConstructScriptObject( void ) { - idThread *thread; - const function_t *constructor; - - // init the script object's data - scriptObject.ClearObject(); - - // call script object's constructor - constructor = scriptObject.GetConstructor(); - if ( constructor ) { - // start a thread that will initialize after Spawn is done being called - thread = new idThread(); - thread->SetThreadName( name.c_str() ); - thread->CallFunction( this, constructor, true ); - thread->DelayedStart( 0 ); - } else { - thread = NULL; - } - - // clear out the object's memory - scriptObject.ClearObject(); - - return thread; -} - -/* -================ -idEntity::DeconstructScriptObject - -Called during idEntity::~idEntity. Calls the destructor on the script object. -Can be overridden by subclasses when a thread doesn't need to be allocated. -Not called during idGameLocal::MapShutdown. -================ -*/ -void idEntity::DeconstructScriptObject( void ) { - idThread *thread; - const function_t *destructor; - - // don't bother calling the script object's destructor on map shutdown - if ( gameLocal.GameState() == GAMESTATE_SHUTDOWN ) { - return; - } - - // call script object's destructor - destructor = scriptObject.GetDestructor(); - if ( destructor ) { - // start a thread that will run immediately and be destroyed - thread = new idThread(); - thread->SetThreadName( name.c_str() ); - thread->CallFunction( this, destructor, true ); - thread->Execute(); - delete thread; - } -} - -/* -================ -idEntity::HasSignal -================ -*/ -bool idEntity::HasSignal( signalNum_t signalnum ) const { - if ( !signals ) { - return false; - } - assert( ( signalnum >= 0 ) && ( signalnum < NUM_SIGNALS ) ); - return ( signals->signal[ signalnum ].Num() > 0 ); -} - -/* -================ -idEntity::SetSignal -================ -*/ -void idEntity::SetSignal( signalNum_t signalnum, idThread *thread, const function_t *function ) { - int i; - int num; - signal_t sig; - int threadnum; - - assert( ( signalnum >= 0 ) && ( signalnum < NUM_SIGNALS ) ); - - if ( !signals ) { - signals = new signalList_t; - } - - assert( thread ); - threadnum = thread->GetThreadNum(); - - num = signals->signal[ signalnum ].Num(); - for( i = 0; i < num; i++ ) { - if ( signals->signal[ signalnum ][ i ].threadnum == threadnum ) { - signals->signal[ signalnum ][ i ].function = function; - return; - } - } - - if ( num >= MAX_SIGNAL_THREADS ) { - thread->Error( "Exceeded maximum number of signals per object" ); - } - - sig.threadnum = threadnum; - sig.function = function; - signals->signal[ signalnum ].Append( sig ); -} - -/* -================ -idEntity::ClearSignal -================ -*/ -void idEntity::ClearSignal( idThread *thread, signalNum_t signalnum ) { - assert( thread ); - if ( ( signalnum < 0 ) || ( signalnum >= NUM_SIGNALS ) ) { - gameLocal.Error( "Signal out of range" ); - } - - if ( !signals ) { - return; - } - - signals->signal[ signalnum ].Clear(); -} - -/* -================ -idEntity::ClearSignalThread -================ -*/ -void idEntity::ClearSignalThread( signalNum_t signalnum, idThread *thread ) { - int i; - int num; - int threadnum; - - assert( thread ); - - if ( ( signalnum < 0 ) || ( signalnum >= NUM_SIGNALS ) ) { - gameLocal.Error( "Signal out of range" ); - } - - if ( !signals ) { - return; - } - - threadnum = thread->GetThreadNum(); - - num = signals->signal[ signalnum ].Num(); - for( i = 0; i < num; i++ ) { - if ( signals->signal[ signalnum ][ i ].threadnum == threadnum ) { - signals->signal[ signalnum ].RemoveIndex( i ); - return; - } - } -} - -/* -================ -idEntity::Signal -================ -*/ -void idEntity::Signal( signalNum_t signalnum ) { - int i; - int num; - signal_t sigs[ MAX_SIGNAL_THREADS ]; - idThread *thread; - - assert( ( signalnum >= 0 ) && ( signalnum < NUM_SIGNALS ) ); - - if ( !signals ) { - return; - } - - // we copy the signal list since each thread has the potential - // to end any of the threads in the list. By copying the list - // we don't have to worry about the list changing as we're - // processing it. - num = signals->signal[ signalnum ].Num(); - for( i = 0; i < num; i++ ) { - sigs[ i ] = signals->signal[ signalnum ][ i ]; - } - - // clear out the signal list so that we don't get into an infinite loop - signals->signal[ signalnum ].Clear(); - - for( i = 0; i < num; i++ ) { - thread = idThread::GetThread( sigs[ i ].threadnum ); - if ( thread ) { - thread->CallFunction( this, sigs[ i ].function, true ); - thread->Execute(); - } - } -} - -/* -================ -idEntity::SignalEvent -================ -*/ -void idEntity::SignalEvent( idThread *thread, signalNum_t signalnum ) { - if ( ( signalnum < 0 ) || ( signalnum >= NUM_SIGNALS ) ) { - gameLocal.Error( "Signal out of range" ); - } - - if ( !signals ) { - return; - } - - Signal( signalnum ); -} - -/*********************************************************************** - - Guis. - -***********************************************************************/ - - -/* -================ -idEntity::TriggerGuis -================ -*/ -void idEntity::TriggerGuis( void ) { - int i; - for ( i = 0; i < MAX_RENDERENTITY_GUI; i++ ) { - if ( renderEntity.gui[ i ] ) { - renderEntity.gui[ i ]->Trigger( gameLocal.time ); - } - } -} - -/* -================ -idEntity::HandleGuiCommands -================ -*/ -bool idEntity::HandleGuiCommands( idEntity *entityGui, const char *cmds ) { - idEntity *targetEnt; - bool ret = false; - if ( entityGui && cmds && *cmds ) { - idLexer src; - idToken token, token2, token3, token4; - src.LoadMemory( cmds, strlen( cmds ), "guiCommands" ); - while( 1 ) { - - if ( !src.ReadToken( &token ) ) { - return ret; - } - - if ( token == ";" ) { - continue; - } - - if ( token.Icmp( "activate" ) == 0 ) { - bool targets = true; - if ( src.ReadToken( &token2 ) ) { - if ( token2 == ";" ) { - src.UnreadToken( &token2 ); - } else { - targets = false; - } - } - - if ( targets ) { - entityGui->ActivateTargets( this ); - } else { - idEntity *ent = gameLocal.FindEntity( token2 ); - if ( ent ) { - ent->Signal( SIG_TRIGGER ); - ent->PostEventMS( &EV_Activate, 0, this ); - } - } - - entityGui->renderEntity.shaderParms[ SHADERPARM_MODE ] = 1.0f; - continue; - } - - - if ( token.Icmp( "runScript" ) == 0 ) { - if ( src.ReadToken( &token2 ) ) { - while( src.CheckTokenString( "::" ) ) { - idToken token3; - if ( !src.ReadToken( &token3 ) ) { - gameLocal.Error( "Expecting function name following '::' in gui for entity '%s'", entityGui->name.c_str() ); - } - token2 += "::" + token3; - } - const function_t *func = gameLocal.program.FindFunction( token2 ); - if ( !func ) { - gameLocal.Error( "Can't find function '%s' for gui in entity '%s'", token2.c_str(), entityGui->name.c_str() ); - } else { - idThread *thread = new idThread( func ); - thread->DelayedStart( 0 ); - } - } - continue; - } - - if ( token.Icmp("play") == 0 ) { - if ( src.ReadToken( &token2 ) ) { - const idSoundShader *shader = declManager->FindSound(token2); - entityGui->StartSoundShader( shader, SND_CHANNEL_ANY, 0, false, NULL ); - } - continue; - } - - if ( token.Icmp( "setkeyval" ) == 0 ) { - if ( src.ReadToken( &token2 ) && src.ReadToken(&token3) && src.ReadToken( &token4 ) ) { - idEntity *ent = gameLocal.FindEntity( token2 ); - if ( ent ) { - ent->spawnArgs.Set( token3, token4 ); - ent->UpdateChangeableSpawnArgs( NULL ); - ent->UpdateVisuals(); - } - } - continue; - } - - if ( token.Icmp( "setshaderparm" ) == 0 ) { - if ( src.ReadToken( &token2 ) && src.ReadToken(&token3) ) { - entityGui->SetShaderParm( atoi( token2 ), atof( token3 ) ); - entityGui->UpdateVisuals(); - } - continue; - } - - if ( token.Icmp("close") == 0 ) { - ret = true; - continue; - } - - if ( !token.Icmp( "turkeyscore" ) ) { - if ( src.ReadToken( &token2 ) && entityGui->renderEntity.gui[0] ) { - int score = entityGui->renderEntity.gui[0]->State().GetInt( "score" ); - score += atoi( token2 ); - entityGui->renderEntity.gui[0]->SetStateInt( "score", score ); - if ( gameLocal.GetLocalPlayer() && score >= 25000 && !gameLocal.GetLocalPlayer()->inventory.turkeyScore ) { - gameLocal.GetLocalPlayer()->GiveEmail( "highScore" ); - gameLocal.GetLocalPlayer()->inventory.turkeyScore = true; - } - } - continue; - } - -#ifdef _D3XP - - if ( !token.Icmp( "martianbuddycomplete" ) ) { - gameLocal.GetLocalPlayer()->GiveEmail( "MartianBuddyGameComplete" ); - continue; - } - -#endif - - - // handy for debugging GUI stuff - if ( !token.Icmp( "print" ) ) { - idStr msg; - while ( src.ReadToken( &token2 ) ) { - if ( token2 == ";" ) { - src.UnreadToken( &token2 ); - break; - } - msg += token2.c_str(); - } - common->Printf( "ent gui 0x%x '%s': %s\n", entityNumber, name.c_str(), msg.c_str() ); - continue; - } - - // if we get to this point we don't know how to handle it - src.UnreadToken(&token); - if ( !HandleSingleGuiCommand( entityGui, &src ) ) { - // not handled there see if entity or any of its targets can handle it - // this will only work for one target atm - if ( entityGui->HandleSingleGuiCommand( entityGui, &src ) ) { - continue; - } - - int c = entityGui->targets.Num(); - int i; - for ( i = 0; i < c; i++) { - targetEnt = entityGui->targets[ i ].GetEntity(); - if ( targetEnt && targetEnt->HandleSingleGuiCommand( entityGui, &src ) ) { - break; - } - } - - if ( i == c ) { - // not handled - common->DPrintf( "idEntity::HandleGuiCommands: '%s' not handled\n", token.c_str() ); - src.ReadToken( &token ); - } - } - - } - } - return ret; -} - -/* -================ -idEntity::HandleSingleGuiCommand -================ -*/ -bool idEntity::HandleSingleGuiCommand( idEntity *entityGui, idLexer *src ) { - return false; -} - -/*********************************************************************** - - Targets - -***********************************************************************/ - -/* -=============== -idEntity::FindTargets - -We have to wait until all entities are spawned -Used to build lists of targets after the entity is spawned. Since not all entities -have been spawned when the entity is created at map load time, we have to wait -=============== -*/ -void idEntity::FindTargets( void ) { - int i; - - // targets can be a list of multiple names - gameLocal.GetTargets( spawnArgs, targets, "target" ); - - // ensure that we don't target ourselves since that could cause an infinite loop when activating entities - for( i = 0; i < targets.Num(); i++ ) { - if ( targets[ i ].GetEntity() == this ) { - gameLocal.Error( "Entity '%s' is targeting itself", name.c_str() ); - } - } -} - -/* -================ -idEntity::RemoveNullTargets -================ -*/ -void idEntity::RemoveNullTargets( void ) { - int i; - - for( i = targets.Num() - 1; i >= 0; i-- ) { - if ( !targets[ i ].GetEntity() ) { - targets.RemoveIndex( i ); - } - } -} - -/* -============================== -idEntity::ActivateTargets - -"activator" should be set to the entity that initiated the firing. -============================== -*/ -void idEntity::ActivateTargets( idEntity *activator ) const { - idEntity *ent; - int i, j; - - for( i = 0; i < targets.Num(); i++ ) { - ent = targets[ i ].GetEntity(); - if ( !ent ) { - continue; - } - if ( ent->RespondsTo( EV_Activate ) || ent->HasSignal( SIG_TRIGGER ) ) { - ent->Signal( SIG_TRIGGER ); - ent->ProcessEvent( &EV_Activate, activator ); - } - for ( j = 0; j < MAX_RENDERENTITY_GUI; j++ ) { - if ( ent->renderEntity.gui[ j ] ) { - ent->renderEntity.gui[ j ]->Trigger( gameLocal.time ); - } - } - } -} - -/*********************************************************************** - - Misc. - -***********************************************************************/ - -/* -================ -idEntity::Teleport -================ -*/ -void idEntity::Teleport( const idVec3 &origin, const idAngles &angles, idEntity *destination ) { - GetPhysics()->SetOrigin( origin ); - GetPhysics()->SetAxis( angles.ToMat3() ); - - UpdateVisuals(); -} - -/* -============ -idEntity::TouchTriggers - - Activate all trigger entities touched at the current position. -============ -*/ -bool idEntity::TouchTriggers( void ) const { - int i, numClipModels, numEntities; - idClipModel * cm; - idClipModel * clipModels[ MAX_GENTITIES ]; - idEntity * ent; - trace_t trace; - - memset( &trace, 0, sizeof( trace ) ); - trace.endpos = GetPhysics()->GetOrigin(); - trace.endAxis = GetPhysics()->GetAxis(); - - numClipModels = gameLocal.clip.ClipModelsTouchingBounds( GetPhysics()->GetAbsBounds(), CONTENTS_TRIGGER, clipModels, MAX_GENTITIES ); - numEntities = 0; - - for ( i = 0; i < numClipModels; i++ ) { - cm = clipModels[ i ]; - - // don't touch it if we're the owner - if ( cm->GetOwner() == this ) { - continue; - } - - ent = cm->GetEntity(); - - if ( !ent->RespondsTo( EV_Touch ) && !ent->HasSignal( SIG_TOUCH ) ) { - continue; - } - - if ( !GetPhysics()->ClipContents( cm ) ) { - continue; - } - -#ifdef _D3XP - SetTimeState ts( ent->timeGroup ); -#endif - - numEntities++; - - trace.c.contents = cm->GetContents(); - trace.c.entityNum = cm->GetEntity()->entityNumber; - trace.c.id = cm->GetId(); - - ent->Signal( SIG_TOUCH ); - ent->ProcessEvent( &EV_Touch, this, &trace ); - - if ( !gameLocal.entities[ entityNumber ] ) { - gameLocal.Printf( "entity was removed while touching triggers\n" ); - return true; - } - } - - return ( numEntities != 0 ); -} - -/* -================ -idEntity::GetSpline -================ -*/ -idCurve_Spline *idEntity::GetSpline( void ) const { - int i, numPoints, t; - const idKeyValue *kv; - idLexer lex; - idVec3 v; - idCurve_Spline *spline; - const char *curveTag = "curve_"; - - kv = spawnArgs.MatchPrefix( curveTag ); - if ( !kv ) { - return NULL; - } - - idStr str = kv->GetKey().Right( kv->GetKey().Length() - strlen( curveTag ) ); - if ( str.Icmp( "CatmullRomSpline" ) == 0 ) { - spline = new idCurve_CatmullRomSpline(); - } else if ( str.Icmp( "nubs" ) == 0 ) { - spline = new idCurve_NonUniformBSpline(); - } else if ( str.Icmp( "nurbs" ) == 0 ) { - spline = new idCurve_NURBS(); - } else { - spline = new idCurve_BSpline(); - } - - spline->SetBoundaryType( idCurve_Spline::BT_CLAMPED ); - - lex.LoadMemory( kv->GetValue(), kv->GetValue().Length(), curveTag ); - numPoints = lex.ParseInt(); - lex.ExpectTokenString( "(" ); - for ( t = i = 0; i < numPoints; i++, t += 100 ) { - v.x = lex.ParseFloat(); - v.y = lex.ParseFloat(); - v.z = lex.ParseFloat(); - spline->AddValue( t, v ); - } - lex.ExpectTokenString( ")" ); - - return spline; -} - -/* -=============== -idEntity::ShowEditingDialog -=============== -*/ -void idEntity::ShowEditingDialog( void ) { -} - -/*********************************************************************** - - Events - -***********************************************************************/ - -/* -================ -idEntity::Event_GetName -================ -*/ -void idEntity::Event_GetName( void ) { - idThread::ReturnString( name.c_str() ); -} - -/* -================ -idEntity::Event_SetName -================ -*/ -void idEntity::Event_SetName( const char *newname ) { - SetName( newname ); -} - -/* -=============== -idEntity::Event_FindTargets -=============== -*/ -void idEntity::Event_FindTargets( void ) { - FindTargets(); -} - -/* -============ -idEntity::Event_ActivateTargets - -Activates any entities targeted by this entity. Mainly used as an -event to delay activating targets. -============ -*/ -void idEntity::Event_ActivateTargets( idEntity *activator ) { - ActivateTargets( activator ); -} - -/* -================ -idEntity::Event_NumTargets -================ -*/ -void idEntity::Event_NumTargets( void ) { - idThread::ReturnFloat( targets.Num() ); -} - -/* -================ -idEntity::Event_GetTarget -================ -*/ -void idEntity::Event_GetTarget( float index ) { - int i; - - i = ( int )index; - if ( ( i < 0 ) || i >= targets.Num() ) { - idThread::ReturnEntity( NULL ); - } else { - idThread::ReturnEntity( targets[ i ].GetEntity() ); - } -} - -/* -================ -idEntity::Event_RandomTarget -================ -*/ -void idEntity::Event_RandomTarget( const char *ignore ) { - int num; - idEntity *ent; - int i; - int ignoreNum; - - RemoveNullTargets(); - if ( !targets.Num() ) { - idThread::ReturnEntity( NULL ); - return; - } - - ignoreNum = -1; - if ( ignore && ( ignore[ 0 ] != 0 ) && ( targets.Num() > 1 ) ) { - for( i = 0; i < targets.Num(); i++ ) { - ent = targets[ i ].GetEntity(); - if ( ent && ( ent->name == ignore ) ) { - ignoreNum = i; - break; - } - } - } - - if ( ignoreNum >= 0 ) { - num = gameLocal.random.RandomInt( targets.Num() - 1 ); - if ( num >= ignoreNum ) { - num++; - } - } else { - num = gameLocal.random.RandomInt( targets.Num() ); - } - - ent = targets[ num ].GetEntity(); - idThread::ReturnEntity( ent ); -} - -/* -================ -idEntity::Event_BindToJoint -================ -*/ -void idEntity::Event_BindToJoint( idEntity *master, const char *jointname, float orientated ) { - BindToJoint( master, jointname, ( orientated != 0.0f ) ); -} - -/* -================ -idEntity::Event_RemoveBinds -================ -*/ -void idEntity::Event_RemoveBinds( void ) { - RemoveBinds(); -} - -/* -================ -idEntity::Event_Bind -================ -*/ -void idEntity::Event_Bind( idEntity *master ) { - Bind( master, true ); -} - -/* -================ -idEntity::Event_BindPosition -================ -*/ -void idEntity::Event_BindPosition( idEntity *master ) { - Bind( master, false ); -} - -/* -================ -idEntity::Event_Unbind -================ -*/ -void idEntity::Event_Unbind( void ) { - Unbind(); -} - -/* -================ -idEntity::Event_SpawnBind -================ -*/ -void idEntity::Event_SpawnBind( void ) { - idEntity *parent; - const char *bind, *joint, *bindanim; - jointHandle_t bindJoint; - bool bindOrientated; - int id; - const idAnim *anim; - int animNum; - idAnimator *parentAnimator; - - if ( spawnArgs.GetString( "bind", "", &bind ) ) { - if ( idStr::Icmp( bind, "worldspawn" ) == 0 ) { - //FIXME: Completely unneccessary since the worldspawn is called "world" - parent = gameLocal.world; - } else { - parent = gameLocal.FindEntity( bind ); - } - bindOrientated = spawnArgs.GetBool( "bindOrientated", "1" ); - if ( parent ) { - // bind to a joint of the skeletal model of the parent - if ( spawnArgs.GetString( "bindToJoint", "", &joint ) && *joint ) { - parentAnimator = parent->GetAnimator(); - if ( !parentAnimator ) { - gameLocal.Error( "Cannot bind to joint '%s' on '%s'. Entity does not support skeletal models.", joint, name.c_str() ); - } - bindJoint = parentAnimator->GetJointHandle( joint ); - if ( bindJoint == INVALID_JOINT ) { - gameLocal.Error( "Joint '%s' not found for bind on '%s'", joint, name.c_str() ); - } - - // bind it relative to a specific anim - if ( ( parent->spawnArgs.GetString( "bindanim", "", &bindanim ) || parent->spawnArgs.GetString( "anim", "", &bindanim ) ) && *bindanim ) { - animNum = parentAnimator->GetAnim( bindanim ); - if ( !animNum ) { - gameLocal.Error( "Anim '%s' not found for bind on '%s'", bindanim, name.c_str() ); - } - anim = parentAnimator->GetAnim( animNum ); - if ( !anim ) { - gameLocal.Error( "Anim '%s' not found for bind on '%s'", bindanim, name.c_str() ); - } - - // make sure parent's render origin has been set - parent->UpdateModelTransform(); - - //FIXME: need a BindToJoint that accepts a joint position - parentAnimator->CreateFrame( gameLocal.time, true ); - idJointMat *frame = parent->renderEntity.joints; - gameEdit->ANIM_CreateAnimFrame( parentAnimator->ModelHandle(), anim->MD5Anim( 0 ), parent->renderEntity.numJoints, frame, 0, parentAnimator->ModelDef()->GetVisualOffset(), parentAnimator->RemoveOrigin() ); - BindToJoint( parent, joint, bindOrientated ); - parentAnimator->ForceUpdate(); - } else { - BindToJoint( parent, joint, bindOrientated ); - } - } - // bind to a body of the physics object of the parent - else if ( spawnArgs.GetInt( "bindToBody", "0", id ) ) { - BindToBody( parent, id, bindOrientated ); - } - // bind to the parent - else { - Bind( parent, bindOrientated ); - } - } - } -} - -/* -================ -idEntity::Event_SetOwner -================ -*/ -void idEntity::Event_SetOwner( idEntity *owner ) { - int i; - - for ( i = 0; i < GetPhysics()->GetNumClipModels(); i++ ) { - GetPhysics()->GetClipModel( i )->SetOwner( owner ); - } -} - -/* -================ -idEntity::Event_SetModel -================ -*/ -void idEntity::Event_SetModel( const char *modelname ) { - SetModel( modelname ); -} - -/* -================ -idEntity::Event_SetSkin -================ -*/ -void idEntity::Event_SetSkin( const char *skinname ) { - renderEntity.customSkin = declManager->FindSkin( skinname ); - UpdateVisuals(); -} - -/* -================ -idEntity::Event_GetShaderParm -================ -*/ -void idEntity::Event_GetShaderParm( int parmnum ) { - if ( ( parmnum < 0 ) || ( parmnum >= MAX_ENTITY_SHADER_PARMS ) ) { - gameLocal.Error( "shader parm index (%d) out of range", parmnum ); - } - - idThread::ReturnFloat( renderEntity.shaderParms[ parmnum ] ); -} - -/* -================ -idEntity::Event_SetShaderParm -================ -*/ -void idEntity::Event_SetShaderParm( int parmnum, float value ) { - SetShaderParm( parmnum, value ); -} - -/* -================ -idEntity::Event_SetShaderParms -================ -*/ -void idEntity::Event_SetShaderParms( float parm0, float parm1, float parm2, float parm3 ) { - renderEntity.shaderParms[ SHADERPARM_RED ] = parm0; - renderEntity.shaderParms[ SHADERPARM_GREEN ] = parm1; - renderEntity.shaderParms[ SHADERPARM_BLUE ] = parm2; - renderEntity.shaderParms[ SHADERPARM_ALPHA ] = parm3; - UpdateVisuals(); -} - - -/* -================ -idEntity::Event_SetColor -================ -*/ -void idEntity::Event_SetColor( float red, float green, float blue ) { - SetColor( red, green, blue ); -} - -/* -================ -idEntity::Event_GetColor -================ -*/ -void idEntity::Event_GetColor( void ) { - idVec3 out; - - GetColor( out ); - idThread::ReturnVector( out ); -} - -/* -================ -idEntity::Event_IsHidden -================ -*/ -void idEntity::Event_IsHidden( void ) { - idThread::ReturnInt( fl.hidden ); -} - -/* -================ -idEntity::Event_Hide -================ -*/ -void idEntity::Event_Hide( void ) { - Hide(); -} - -/* -================ -idEntity::Event_Show -================ -*/ -void idEntity::Event_Show( void ) { - Show(); -} - -/* -================ -idEntity::Event_CacheSoundShader -================ -*/ -void idEntity::Event_CacheSoundShader( const char *soundName ) { - declManager->FindSound( soundName ); -} - -/* -================ -idEntity::Event_StartSoundShader -================ -*/ -void idEntity::Event_StartSoundShader( const char *soundName, int channel ) { - int length; - - StartSoundShader( declManager->FindSound( soundName ), (s_channelType)channel, 0, false, &length ); - idThread::ReturnFloat( MS2SEC( length ) ); -} - -/* -================ -idEntity::Event_StopSound -================ -*/ -void idEntity::Event_StopSound( int channel, int netSync ) { - StopSound( channel, ( netSync != 0 ) ); -} - -/* -================ -idEntity::Event_StartSound -================ -*/ -void idEntity::Event_StartSound( const char *soundName, int channel, int netSync ) { - int time; - - StartSound( soundName, ( s_channelType )channel, 0, ( netSync != 0 ), &time ); - idThread::ReturnFloat( MS2SEC( time ) ); -} - -/* -================ -idEntity::Event_FadeSound -================ -*/ -void idEntity::Event_FadeSound( int channel, float to, float over ) { - if ( refSound.referenceSound ) { - refSound.referenceSound->FadeSound( channel, to, over ); - } -} - -/* -================ -idEntity::Event_GetWorldOrigin -================ -*/ -void idEntity::Event_GetWorldOrigin( void ) { - idThread::ReturnVector( GetPhysics()->GetOrigin() ); -} - -/* -================ -idEntity::Event_SetWorldOrigin -================ -*/ -void idEntity::Event_SetWorldOrigin( idVec3 const &org ) { - idVec3 neworg = GetLocalCoordinates( org ); - SetOrigin( neworg ); -} - -/* -================ -idEntity::Event_SetOrigin -================ -*/ -void idEntity::Event_SetOrigin( idVec3 const &org ) { - SetOrigin( org ); -} - -/* -================ -idEntity::Event_GetOrigin -================ -*/ -void idEntity::Event_GetOrigin( void ) { - idThread::ReturnVector( GetLocalCoordinates( GetPhysics()->GetOrigin() ) ); -} - -/* -================ -idEntity::Event_SetAngles -================ -*/ -void idEntity::Event_SetAngles( idAngles const &ang ) { - SetAngles( ang ); -} - -/* -================ -idEntity::Event_GetAngles -================ -*/ -void idEntity::Event_GetAngles( void ) { - idAngles ang = GetPhysics()->GetAxis().ToAngles(); - idThread::ReturnVector( idVec3( ang[0], ang[1], ang[2] ) ); -} - -/* -================ -idEntity::Event_SetLinearVelocity -================ -*/ -void idEntity::Event_SetLinearVelocity( const idVec3 &velocity ) { - GetPhysics()->SetLinearVelocity( velocity ); -} - -/* -================ -idEntity::Event_GetLinearVelocity -================ -*/ -void idEntity::Event_GetLinearVelocity( void ) { - idThread::ReturnVector( GetPhysics()->GetLinearVelocity() ); -} - -/* -================ -idEntity::Event_SetAngularVelocity -================ -*/ -void idEntity::Event_SetAngularVelocity( const idVec3 &velocity ) { - GetPhysics()->SetAngularVelocity( velocity ); -} - -/* -================ -idEntity::Event_GetAngularVelocity -================ -*/ -void idEntity::Event_GetAngularVelocity( void ) { - idThread::ReturnVector( GetPhysics()->GetAngularVelocity() ); -} - -/* -================ -idEntity::Event_SetSize -================ -*/ -void idEntity::Event_SetSize( idVec3 const &mins, idVec3 const &maxs ) { - GetPhysics()->SetClipBox( idBounds( mins, maxs ), 1.0f ); -} - -/* -================ -idEntity::Event_GetSize -================ -*/ -void idEntity::Event_GetSize( void ) { - idBounds bounds; - - bounds = GetPhysics()->GetBounds(); - idThread::ReturnVector( bounds[1] - bounds[0] ); -} - -/* -================ -idEntity::Event_GetMins -================ -*/ -void idEntity::Event_GetMins( void ) { - idThread::ReturnVector( GetPhysics()->GetBounds()[0] ); -} - -/* -================ -idEntity::Event_GetMaxs -================ -*/ -void idEntity::Event_GetMaxs( void ) { - idThread::ReturnVector( GetPhysics()->GetBounds()[1] ); -} - -/* -================ -idEntity::Event_Touches -================ -*/ -void idEntity::Event_Touches( idEntity *ent ) { - if ( !ent ) { - idThread::ReturnInt( false ); - return; - } - - const idBounds &myBounds = GetPhysics()->GetAbsBounds(); - const idBounds &entBounds = ent->GetPhysics()->GetAbsBounds(); - - idThread::ReturnInt( myBounds.IntersectsBounds( entBounds ) ); -} - -/* -================ -idEntity::Event_SetGuiParm -================ -*/ -void idEntity::Event_SetGuiParm( const char *key, const char *val ) { - for ( int i = 0; i < MAX_RENDERENTITY_GUI; i++ ) { - if ( renderEntity.gui[ i ] ) { - if ( idStr::Icmpn( key, "gui_", 4 ) == 0 ) { - spawnArgs.Set( key, val ); - } - renderEntity.gui[ i ]->SetStateString( key, val ); - renderEntity.gui[ i ]->StateChanged( gameLocal.time ); - } - } -} - -/* -================ -idEntity::Event_SetGuiParm -================ -*/ -void idEntity::Event_SetGuiFloat( const char *key, float f ) { - for ( int i = 0; i < MAX_RENDERENTITY_GUI; i++ ) { - if ( renderEntity.gui[ i ] ) { - renderEntity.gui[ i ]->SetStateString( key, va( "%f", f ) ); - renderEntity.gui[ i ]->StateChanged( gameLocal.time ); - } - } -} - -/* -================ -idEntity::Event_GetNextKey -================ -*/ -void idEntity::Event_GetNextKey( const char *prefix, const char *lastMatch ) { - const idKeyValue *kv; - const idKeyValue *previous; - - if ( *lastMatch ) { - previous = spawnArgs.FindKey( lastMatch ); - } else { - previous = NULL; - } - - kv = spawnArgs.MatchPrefix( prefix, previous ); - if ( !kv ) { - idThread::ReturnString( "" ); - } else { - idThread::ReturnString( kv->GetKey() ); - } -} - -/* -================ -idEntity::Event_SetKey -================ -*/ -void idEntity::Event_SetKey( const char *key, const char *value ) { - spawnArgs.Set( key, value ); -#ifdef _D3XP - UpdateChangeableSpawnArgs( NULL ); -#endif -} - -/* -================ -idEntity::Event_GetKey -================ -*/ -void idEntity::Event_GetKey( const char *key ) { - const char *value; - - spawnArgs.GetString( key, "", &value ); - idThread::ReturnString( value ); -} - -/* -================ -idEntity::Event_GetIntKey -================ -*/ -void idEntity::Event_GetIntKey( const char *key ) { - int value; - - spawnArgs.GetInt( key, "0", value ); - - // scripts only support floats - idThread::ReturnFloat( value ); -} - -/* -================ -idEntity::Event_GetFloatKey -================ -*/ -void idEntity::Event_GetFloatKey( const char *key ) { - float value; - - spawnArgs.GetFloat( key, "0", value ); - idThread::ReturnFloat( value ); -} - -/* -================ -idEntity::Event_GetVectorKey -================ -*/ -void idEntity::Event_GetVectorKey( const char *key ) { - idVec3 value; - - spawnArgs.GetVector( key, "0 0 0", value ); - idThread::ReturnVector( value ); -} - -/* -================ -idEntity::Event_GetEntityKey -================ -*/ -void idEntity::Event_GetEntityKey( const char *key ) { - idEntity *ent; - const char *entname; - - if ( !spawnArgs.GetString( key, NULL, &entname ) ) { - idThread::ReturnEntity( NULL ); - return; - } - - ent = gameLocal.FindEntity( entname ); - if ( !ent ) { - gameLocal.Warning( "Couldn't find entity '%s' specified in '%s' key in entity '%s'", entname, key, name.c_str() ); - } - - idThread::ReturnEntity( ent ); -} - -/* -================ -idEntity::Event_RestorePosition -================ -*/ -void idEntity::Event_RestorePosition( void ) { - idVec3 org; - idAngles angles; - idMat3 axis; - idEntity * part; - - spawnArgs.GetVector( "origin", "0 0 0", org ); - - // get the rotation matrix in either full form, or single angle form - if ( spawnArgs.GetMatrix( "rotation", "1 0 0 0 1 0 0 0 1", axis ) ) { - angles = axis.ToAngles(); - } else { - angles[ 0 ] = 0; - angles[ 1 ] = spawnArgs.GetFloat( "angle" ); - angles[ 2 ] = 0; - } - - Teleport( org, angles, NULL ); - - for ( part = teamChain; part != NULL; part = part->teamChain ) { - if ( part->bindMaster != this ) { - continue; - } - if ( part->GetPhysics()->IsType( idPhysics_Parametric::Type ) ) { - if ( static_cast(part->GetPhysics())->IsPusher() ) { - gameLocal.Warning( "teleported '%s' which has the pushing mover '%s' bound to it\n", GetName(), part->GetName() ); - } - } else if ( part->GetPhysics()->IsType( idPhysics_AF::Type ) ) { - gameLocal.Warning( "teleported '%s' which has the articulated figure '%s' bound to it\n", GetName(), part->GetName() ); - } - } -} - -/* -================ -idEntity::Event_UpdateCameraTarget -================ -*/ -void idEntity::Event_UpdateCameraTarget( void ) { - const char *target; - const idKeyValue *kv; - idVec3 dir; - - target = spawnArgs.GetString( "cameraTarget" ); - - cameraTarget = gameLocal.FindEntity( target ); - - if ( cameraTarget ) { - kv = cameraTarget->spawnArgs.MatchPrefix( "target", NULL ); - while( kv ) { - idEntity *ent = gameLocal.FindEntity( kv->GetValue() ); - if ( ent && idStr::Icmp( ent->GetEntityDefName(), "target_null" ) == 0) { - dir = ent->GetPhysics()->GetOrigin() - cameraTarget->GetPhysics()->GetOrigin(); - dir.Normalize(); - cameraTarget->SetAxis( dir.ToMat3() ); - SetAxis(dir.ToMat3()); - break; - } - kv = cameraTarget->spawnArgs.MatchPrefix( "target", kv ); - } - } - UpdateVisuals(); -} - -/* -================ -idEntity::Event_DistanceTo -================ -*/ -void idEntity::Event_DistanceTo( idEntity *ent ) { - if ( !ent ) { - // just say it's really far away - idThread::ReturnFloat( MAX_WORLD_SIZE ); - } else { - float dist = ( GetPhysics()->GetOrigin() - ent->GetPhysics()->GetOrigin() ).LengthFast(); - idThread::ReturnFloat( dist ); - } -} - -/* -================ -idEntity::Event_DistanceToPoint -================ -*/ -void idEntity::Event_DistanceToPoint( const idVec3 &point ) { - float dist = ( GetPhysics()->GetOrigin() - point ).LengthFast(); - idThread::ReturnFloat( dist ); -} - -/* -================ -idEntity::Event_StartFx -================ -*/ -void idEntity::Event_StartFx( const char *fx ) { - idEntityFx::StartFx( fx, NULL, NULL, this, true ); -} - -/* -================ -idEntity::Event_WaitFrame -================ -*/ -void idEntity::Event_WaitFrame( void ) { - idThread *thread; - - thread = idThread::CurrentThread(); - if ( thread ) { - thread->WaitFrame(); - } -} - -/* -===================== -idEntity::Event_Wait -===================== -*/ -void idEntity::Event_Wait( float time ) { - idThread *thread = idThread::CurrentThread(); - - if ( !thread ) { - gameLocal.Error( "Event 'wait' called from outside thread" ); - } - - thread->WaitSec( time ); -} - -/* -===================== -idEntity::Event_HasFunction -===================== -*/ -void idEntity::Event_HasFunction( const char *name ) { - const function_t *func; - - func = scriptObject.GetFunction( name ); - if ( func ) { - idThread::ReturnInt( true ); - } else { - idThread::ReturnInt( false ); - } -} - -/* -===================== -idEntity::Event_CallFunction -===================== -*/ -void idEntity::Event_CallFunction( const char *funcname ) { - const function_t *func; - idThread *thread; - - thread = idThread::CurrentThread(); - if ( !thread ) { - gameLocal.Error( "Event 'callFunction' called from outside thread" ); - } - - func = scriptObject.GetFunction( funcname ); - if ( !func ) { - gameLocal.Error( "Unknown function '%s' in '%s'", funcname, scriptObject.GetTypeName() ); - } - - if ( func->type->NumParameters() != 1 ) { - gameLocal.Error( "Function '%s' has the wrong number of parameters for 'callFunction'", funcname ); - } - if ( !scriptObject.GetTypeDef()->Inherits( func->type->GetParmType( 0 ) ) ) { - gameLocal.Error( "Function '%s' is the wrong type for 'callFunction'", funcname ); - } - - // function args will be invalid after this call - thread->CallFunction( this, func, false ); -} - -/* -================ -idEntity::Event_SetNeverDormant -================ -*/ -void idEntity::Event_SetNeverDormant( int enable ) { - fl.neverDormant = ( enable != 0 ); - dormantStart = 0; -} - -#ifdef _D3XP -/* -================ -idEntity::Event_SetGui -================ -* BSM Nerve: Allows guis to be changed at runtime. Guis that are -* loaded after the level loads should be precahced using PrecacheGui. -*/ -void idEntity::Event_SetGui( int guiNum, const char *guiName) { - idUserInterface** gui = NULL; - - if ( guiNum >= 1 && guiNum <= MAX_RENDERENTITY_GUI ) { - gui = &renderEntity.gui[ guiNum-1 ]; - } - - if( gui ) { - *gui = uiManager->FindGui( guiName, true, false ); - UpdateGuiParms( *gui, &spawnArgs ); - UpdateChangeableSpawnArgs( NULL ); - gameRenderWorld->UpdateEntityDef(modelDefHandle, &renderEntity); - - } else { - gameLocal.Error( "Entity '%s' doesn't have a GUI %d", name.c_str(), guiNum ); - } - -} - -/* -================ -idEntity::Event_PrecacheGui -================ -* BSM Nerve: Forces the engine to initialize a gui even if it is not specified as used in a level. -* This is useful for preventing load hitches when switching guis during the game using "setGui" -*/ -void idEntity::Event_PrecacheGui( const char *guiName ) { - uiManager->FindGui( guiName, true, true ); -} - -void idEntity::Event_GetGuiParm(int guiNum, const char *key) { - if(renderEntity.gui[guiNum-1]) { - idThread::ReturnString(renderEntity.gui[guiNum-1]->GetStateString(key)); - return; - } - idThread::ReturnString(""); -} - -void idEntity::Event_GetGuiParmFloat(int guiNum, const char *key) { - if(renderEntity.gui[guiNum-1]) { - idThread::ReturnFloat(renderEntity.gui[guiNum-1]->GetStateFloat(key)); - return; - } - idThread::ReturnFloat(0.0f); -} - -void idEntity::Event_GuiNamedEvent(int guiNum, const char *event) { - if(renderEntity.gui[guiNum-1]) { - renderEntity.gui[guiNum-1]->HandleNamedEvent(event); - } -} - -#endif - -/*********************************************************************** - - Network - -***********************************************************************/ - -/* -================ -idEntity::ClientPredictionThink -================ -*/ -void idEntity::ClientPredictionThink( void ) { - RunPhysics(); - Present(); -} - -/* -================ -idEntity::WriteBindToSnapshot -================ -*/ -void idEntity::WriteBindToSnapshot( idBitMsgDelta &msg ) const { - int bindInfo; - - if ( bindMaster ) { - bindInfo = bindMaster->entityNumber; - bindInfo |= ( fl.bindOrientated & 1 ) << GENTITYNUM_BITS; - if ( bindJoint != INVALID_JOINT ) { - bindInfo |= 1 << ( GENTITYNUM_BITS + 1 ); - bindInfo |= bindJoint << ( 3 + GENTITYNUM_BITS ); - } else if ( bindBody != -1 ) { - bindInfo |= 2 << ( GENTITYNUM_BITS + 1 ); - bindInfo |= bindBody << ( 3 + GENTITYNUM_BITS ); - } - } else { - bindInfo = ENTITYNUM_NONE; - } - msg.WriteBits( bindInfo, GENTITYNUM_BITS + 3 + 9 ); -} - -/* -================ -idEntity::ReadBindFromSnapshot -================ -*/ -void idEntity::ReadBindFromSnapshot( const idBitMsgDelta &msg ) { - int bindInfo, bindEntityNum, bindPos; - bool bindOrientated; - idEntity *master; - - bindInfo = msg.ReadBits( GENTITYNUM_BITS + 3 + 9 ); - bindEntityNum = bindInfo & ( ( 1 << GENTITYNUM_BITS ) - 1 ); - - if ( bindEntityNum != ENTITYNUM_NONE ) { - master = gameLocal.entities[ bindEntityNum ]; - - bindOrientated = ( bindInfo >> GENTITYNUM_BITS ) & 1; - bindPos = ( bindInfo >> ( GENTITYNUM_BITS + 3 ) ); - switch( ( bindInfo >> ( GENTITYNUM_BITS + 1 ) ) & 3 ) { - case 1: { - BindToJoint( master, (jointHandle_t) bindPos, bindOrientated ); - break; - } - case 2: { - BindToBody( master, bindPos, bindOrientated ); - break; - } - default: { - Bind( master, bindOrientated ); - break; - } - } - } else if ( bindMaster ) { - Unbind(); - } -} - -/* -================ -idEntity::WriteColorToSnapshot -================ -*/ -void idEntity::WriteColorToSnapshot( idBitMsgDelta &msg ) const { - idVec4 color; - - color[0] = renderEntity.shaderParms[ SHADERPARM_RED ]; - color[1] = renderEntity.shaderParms[ SHADERPARM_GREEN ]; - color[2] = renderEntity.shaderParms[ SHADERPARM_BLUE ]; - color[3] = renderEntity.shaderParms[ SHADERPARM_ALPHA ]; - msg.WriteInt( PackColor( color ) ); -} - -/* -================ -idEntity::ReadColorFromSnapshot -================ -*/ -void idEntity::ReadColorFromSnapshot( const idBitMsgDelta &msg ) { - idVec4 color; - - UnpackColor( msg.ReadInt(), color ); - renderEntity.shaderParms[ SHADERPARM_RED ] = color[0]; - renderEntity.shaderParms[ SHADERPARM_GREEN ] = color[1]; - renderEntity.shaderParms[ SHADERPARM_BLUE ] = color[2]; - renderEntity.shaderParms[ SHADERPARM_ALPHA ] = color[3]; -} - -/* -================ -idEntity::WriteGUIToSnapshot -================ -*/ -void idEntity::WriteGUIToSnapshot( idBitMsgDelta &msg ) const { - // no need to loop over MAX_RENDERENTITY_GUI at this time - if ( renderEntity.gui[ 0 ] ) { - msg.WriteByte( renderEntity.gui[ 0 ]->State().GetInt( "networkState" ) ); - } else { - msg.WriteByte( 0 ); - } -} - -/* -================ -idEntity::ReadGUIFromSnapshot -================ -*/ -void idEntity::ReadGUIFromSnapshot( const idBitMsgDelta &msg ) { - int state; - idUserInterface *gui; - state = msg.ReadByte( ); - gui = renderEntity.gui[ 0 ]; - if ( gui && state != mpGUIState ) { - mpGUIState = state; - gui->SetStateInt( "networkState", state ); - gui->HandleNamedEvent( "networkState" ); - } -} - -/* -================ -idEntity::WriteToSnapshot -================ -*/ -void idEntity::WriteToSnapshot( idBitMsgDelta &msg ) const { -} - -/* -================ -idEntity::ReadFromSnapshot -================ -*/ -void idEntity::ReadFromSnapshot( const idBitMsgDelta &msg ) { -} - -/* -================ -idEntity::ServerSendEvent - - Saved events are also sent to any client that connects late so all clients - always receive the events nomatter what time they join the game. -================ -*/ -void idEntity::ServerSendEvent( int eventId, const idBitMsg *msg, bool saveEvent, int excludeClient ) const { - idBitMsg outMsg; - byte msgBuf[MAX_GAME_MESSAGE_SIZE]; - - if ( !gameLocal.isServer ) { - return; - } - - // prevent dupe events caused by frame re-runs - if ( !gameLocal.isNewFrame ) { - return; - } - - outMsg.Init( msgBuf, sizeof( msgBuf ) ); - outMsg.BeginWriting(); - outMsg.WriteByte( GAME_RELIABLE_MESSAGE_EVENT ); - outMsg.WriteBits( gameLocal.GetSpawnId( this ), 32 ); - outMsg.WriteByte( eventId ); - outMsg.WriteInt( gameLocal.time ); - if ( msg ) { - outMsg.WriteBits( msg->GetSize(), idMath::BitsForInteger( MAX_EVENT_PARAM_SIZE ) ); - outMsg.WriteData( msg->GetData(), msg->GetSize() ); - } else { - outMsg.WriteBits( 0, idMath::BitsForInteger( MAX_EVENT_PARAM_SIZE ) ); - } - - if ( excludeClient != -1 ) { - networkSystem->ServerSendReliableMessageExcluding( excludeClient, outMsg ); - } else { - networkSystem->ServerSendReliableMessage( -1, outMsg ); - } - - if ( saveEvent ) { - gameLocal.SaveEntityNetworkEvent( this, eventId, msg ); - } -} - -/* -================ -idEntity::ClientSendEvent -================ -*/ -void idEntity::ClientSendEvent( int eventId, const idBitMsg *msg ) const { - idBitMsg outMsg; - byte msgBuf[MAX_GAME_MESSAGE_SIZE]; - - if ( !gameLocal.isClient ) { - return; - } - - // prevent dupe events caused by frame re-runs - if ( !gameLocal.isNewFrame ) { - return; - } - - outMsg.Init( msgBuf, sizeof( msgBuf ) ); - outMsg.BeginWriting(); - outMsg.WriteByte( GAME_RELIABLE_MESSAGE_EVENT ); - outMsg.WriteBits( gameLocal.GetSpawnId( this ), 32 ); - outMsg.WriteByte( eventId ); - outMsg.WriteInt( gameLocal.time ); - if ( msg ) { - outMsg.WriteBits( msg->GetSize(), idMath::BitsForInteger( MAX_EVENT_PARAM_SIZE ) ); - outMsg.WriteData( msg->GetData(), msg->GetSize() ); - } else { - outMsg.WriteBits( 0, idMath::BitsForInteger( MAX_EVENT_PARAM_SIZE ) ); - } - - networkSystem->ClientSendReliableMessage( outMsg ); -} - -/* -================ -idEntity::ServerReceiveEvent -================ -*/ -bool idEntity::ServerReceiveEvent( int event, int time, const idBitMsg &msg ) { - switch( event ) { - case 0: { - } - default: { - return false; - } - } -} - -/* -================ -idEntity::ClientReceiveEvent -================ -*/ -bool idEntity::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) { - int index; - const idSoundShader *shader; - s_channelType channel; - - switch( event ) { - case EVENT_STARTSOUNDSHADER: { - // the sound stuff would early out - assert( gameLocal.isNewFrame ); - if ( time < gameLocal.realClientTime - 1000 ) { - // too old, skip it ( reliable messages don't need to be parsed in full ) - common->DPrintf( "ent 0x%x: start sound shader too old (%d ms)\n", entityNumber, gameLocal.realClientTime - time ); - return true; - } - index = gameLocal.ClientRemapDecl( DECL_SOUND, msg.ReadInt() ); - if ( index >= 0 && index < declManager->GetNumDecls( DECL_SOUND ) ) { - shader = declManager->SoundByIndex( index, false ); - channel = (s_channelType)msg.ReadByte(); - StartSoundShader( shader, channel, 0, false, NULL ); - } - return true; - } - case EVENT_STOPSOUNDSHADER: { - // the sound stuff would early out - assert( gameLocal.isNewFrame ); - channel = (s_channelType)msg.ReadByte(); - StopSound( channel, false ); - return true; - } - default: - break; - } - - return false; -} - -#ifdef _D3XP -/* -================ -idEntity::DetermineTimeGroup -================ -*/ -void idEntity::DetermineTimeGroup( bool slowmo ) { - if ( slowmo || gameLocal.isMultiplayer ) { - timeGroup = TIME_GROUP1; - } - else { - timeGroup = TIME_GROUP2; - } -} - -/* -================ -idEntity::SetGrabbedState -================ -*/ -void idEntity::SetGrabbedState( bool grabbed ) { - fl.grabbed = grabbed; -} - -/* -================ -idEntity::IsGrabbed -================ -*/ -bool idEntity::IsGrabbed() { - return fl.grabbed; -} -#endif - -/* -=============================================================================== - - idAnimatedEntity - -=============================================================================== -*/ - -const idEventDef EV_GetJointHandle( "getJointHandle", "s", 'd' ); -const idEventDef EV_ClearAllJoints( "clearAllJoints" ); -const idEventDef EV_ClearJoint( "clearJoint", "d" ); -const idEventDef EV_SetJointPos( "setJointPos", "ddv" ); -const idEventDef EV_SetJointAngle( "setJointAngle", "ddv" ); -const idEventDef EV_GetJointPos( "getJointPos", "d", 'v' ); -const idEventDef EV_GetJointAngle( "getJointAngle", "d", 'v' ); - -CLASS_DECLARATION( idEntity, idAnimatedEntity ) - EVENT( EV_GetJointHandle, idAnimatedEntity::Event_GetJointHandle ) - EVENT( EV_ClearAllJoints, idAnimatedEntity::Event_ClearAllJoints ) - EVENT( EV_ClearJoint, idAnimatedEntity::Event_ClearJoint ) - EVENT( EV_SetJointPos, idAnimatedEntity::Event_SetJointPos ) - EVENT( EV_SetJointAngle, idAnimatedEntity::Event_SetJointAngle ) - EVENT( EV_GetJointPos, idAnimatedEntity::Event_GetJointPos ) - EVENT( EV_GetJointAngle, idAnimatedEntity::Event_GetJointAngle ) -END_CLASS - -/* -================ -idAnimatedEntity::idAnimatedEntity -================ -*/ -idAnimatedEntity::idAnimatedEntity() { - animator.SetEntity( this ); - damageEffects = NULL; -} - -/* -================ -idAnimatedEntity::~idAnimatedEntity -================ -*/ -idAnimatedEntity::~idAnimatedEntity() { - damageEffect_t *de; - - for ( de = damageEffects; de; de = damageEffects ) { - damageEffects = de->next; - delete de; - } -} - -/* -================ -idAnimatedEntity::Save - -archives object for save game file -================ -*/ -void idAnimatedEntity::Save( idSaveGame *savefile ) const { - animator.Save( savefile ); - - // Wounds are very temporary, ignored at this time - //damageEffect_t *damageEffects; -} - -/* -================ -idAnimatedEntity::Restore - -unarchives object from save game file -================ -*/ -void idAnimatedEntity::Restore( idRestoreGame *savefile ) { - animator.Restore( savefile ); - - // check if the entity has an MD5 model - if ( animator.ModelHandle() ) { - // set the callback to update the joints - renderEntity.callback = idEntity::ModelCallback; - animator.GetJoints( &renderEntity.numJoints, &renderEntity.joints ); - animator.GetBounds( gameLocal.time, renderEntity.bounds ); - if ( modelDefHandle != -1 ) { - gameRenderWorld->UpdateEntityDef( modelDefHandle, &renderEntity ); - } - } -} - -/* -================ -idAnimatedEntity::ClientPredictionThink -================ -*/ -void idAnimatedEntity::ClientPredictionThink( void ) { - RunPhysics(); - UpdateAnimation(); - Present(); -} - -/* -================ -idAnimatedEntity::Think -================ -*/ -void idAnimatedEntity::Think( void ) { - RunPhysics(); - UpdateAnimation(); - Present(); - UpdateDamageEffects(); -} - -/* -================ -idAnimatedEntity::UpdateAnimation -================ -*/ -void idAnimatedEntity::UpdateAnimation( void ) { - // don't do animations if they're not enabled - if ( !( thinkFlags & TH_ANIMATE ) ) { - return; - } - - // is the model an MD5? - if ( !animator.ModelHandle() ) { - // no, so nothing to do - return; - } - - // call any frame commands that have happened in the past frame - if ( !fl.hidden ) { - animator.ServiceAnims( gameLocal.previousTime, gameLocal.time ); - } - - // if the model is animating then we have to update it - if ( !animator.FrameHasChanged( gameLocal.time ) ) { - // still fine the way it was - return; - } - - // get the latest frame bounds - animator.GetBounds( gameLocal.time, renderEntity.bounds ); - if ( renderEntity.bounds.IsCleared() && !fl.hidden ) { - gameLocal.DPrintf( "%d: inside out bounds\n", gameLocal.time ); - } - - // update the renderEntity - UpdateVisuals(); - - // the animation is updated - animator.ClearForceUpdate(); -} - -/* -================ -idAnimatedEntity::GetAnimator -================ -*/ -idAnimator *idAnimatedEntity::GetAnimator( void ) { - return &animator; -} - -/* -================ -idAnimatedEntity::SetModel -================ -*/ -void idAnimatedEntity::SetModel( const char *modelname ) { - FreeModelDef(); - - renderEntity.hModel = animator.SetModel( modelname ); - if ( !renderEntity.hModel ) { - idEntity::SetModel( modelname ); - return; - } - - if ( !renderEntity.customSkin ) { - renderEntity.customSkin = animator.ModelDef()->GetDefaultSkin(); - } - - // set the callback to update the joints - renderEntity.callback = idEntity::ModelCallback; - animator.GetJoints( &renderEntity.numJoints, &renderEntity.joints ); - animator.GetBounds( gameLocal.time, renderEntity.bounds ); - - UpdateVisuals(); -} - -/* -===================== -idAnimatedEntity::GetJointWorldTransform -===================== -*/ -bool idAnimatedEntity::GetJointWorldTransform( jointHandle_t jointHandle, int currentTime, idVec3 &offset, idMat3 &axis ) { - if ( !animator.GetJointTransform( jointHandle, currentTime, offset, axis ) ) { - return false; - } - - ConvertLocalToWorldTransform( offset, axis ); - return true; -} - -/* -============== -idAnimatedEntity::GetJointTransformForAnim -============== -*/ -bool idAnimatedEntity::GetJointTransformForAnim( jointHandle_t jointHandle, int animNum, int frameTime, idVec3 &offset, idMat3 &axis ) const { - const idAnim *anim; - int numJoints; - idJointMat *frame; - - anim = animator.GetAnim( animNum ); - if ( !anim ) { - assert( 0 ); - return false; - } - - numJoints = animator.NumJoints(); - if ( ( jointHandle < 0 ) || ( jointHandle >= numJoints ) ) { - assert( 0 ); - return false; - } - - frame = ( idJointMat * )_alloca16( numJoints * sizeof( idJointMat ) ); - gameEdit->ANIM_CreateAnimFrame( animator.ModelHandle(), anim->MD5Anim( 0 ), renderEntity.numJoints, frame, frameTime, animator.ModelDef()->GetVisualOffset(), animator.RemoveOrigin() ); - - offset = frame[ jointHandle ].ToVec3(); - axis = frame[ jointHandle ].ToMat3(); - - return true; -} - -/* -============== -idAnimatedEntity::AddDamageEffect - - Dammage effects track the animating impact position, spitting out particles. -============== -*/ -void idAnimatedEntity::AddDamageEffect( const trace_t &collision, const idVec3 &velocity, const char *damageDefName ) { - jointHandle_t jointNum; - idVec3 origin, dir, localDir, localOrigin, localNormal; - idMat3 axis; - - if ( !g_bloodEffects.GetBool() || renderEntity.joints == NULL ) { - return; - } - - const idDeclEntityDef *def = gameLocal.FindEntityDef( damageDefName, false ); - if ( def == NULL ) { - return; - } - - jointNum = CLIPMODEL_ID_TO_JOINT_HANDLE( collision.c.id ); - if ( jointNum == INVALID_JOINT ) { - return; - } - - dir = velocity; - dir.Normalize(); - - axis = renderEntity.joints[jointNum].ToMat3() * renderEntity.axis; - origin = renderEntity.origin + renderEntity.joints[jointNum].ToVec3() * renderEntity.axis; - - localOrigin = ( collision.c.point - origin ) * axis.Transpose(); - localNormal = collision.c.normal * axis.Transpose(); - localDir = dir * axis.Transpose(); - - AddLocalDamageEffect( jointNum, localOrigin, localNormal, localDir, def, collision.c.material ); - - if ( gameLocal.isServer ) { - idBitMsg msg; - byte msgBuf[MAX_EVENT_PARAM_SIZE]; - - msg.Init( msgBuf, sizeof( msgBuf ) ); - msg.BeginWriting(); - msg.WriteShort( (int)jointNum ); - msg.WriteFloat( localOrigin[0] ); - msg.WriteFloat( localOrigin[1] ); - msg.WriteFloat( localOrigin[2] ); - msg.WriteDir( localNormal, 24 ); - msg.WriteDir( localDir, 24 ); - msg.WriteInt( gameLocal.ServerRemapDecl( -1, DECL_ENTITYDEF, def->Index() ) ); - msg.WriteInt( gameLocal.ServerRemapDecl( -1, DECL_MATERIAL, collision.c.material->Index() ) ); - ServerSendEvent( EVENT_ADD_DAMAGE_EFFECT, &msg, false, -1 ); - } -} - -/* -============== -idAnimatedEntity::GetDefaultSurfaceType -============== -*/ -int idAnimatedEntity::GetDefaultSurfaceType( void ) const { - return SURFTYPE_METAL; -} - -/* -============== -idAnimatedEntity::AddLocalDamageEffect -============== -*/ -void idAnimatedEntity::AddLocalDamageEffect( jointHandle_t jointNum, const idVec3 &localOrigin, const idVec3 &localNormal, const idVec3 &localDir, const idDeclEntityDef *def, const idMaterial *collisionMaterial ) { - const char *sound, *splat, *decal, *bleed, *key; - damageEffect_t *de; - idVec3 origin, dir; - idMat3 axis; - -#ifdef _D3XP - SetTimeState ts( timeGroup ); -#endif - - axis = renderEntity.joints[jointNum].ToMat3() * renderEntity.axis; - origin = renderEntity.origin + renderEntity.joints[jointNum].ToVec3() * renderEntity.axis; - - origin = origin + localOrigin * axis; - dir = localDir * axis; - - int type = collisionMaterial->GetSurfaceType(); - if ( type == SURFTYPE_NONE ) { - type = GetDefaultSurfaceType(); - } - - const char *materialType = gameLocal.sufaceTypeNames[ type ]; - - // start impact sound based on material type - key = va( "snd_%s", materialType ); - sound = spawnArgs.GetString( key ); - if ( *sound == '\0' ) { - sound = def->dict.GetString( key ); - } - if ( *sound != '\0' ) { - StartSoundShader( declManager->FindSound( sound ), SND_CHANNEL_BODY, 0, false, NULL ); - } - - // blood splats are thrown onto nearby surfaces - key = va( "mtr_splat_%s", materialType ); - splat = spawnArgs.RandomPrefix( key, gameLocal.random ); - if ( *splat == '\0' ) { - splat = def->dict.RandomPrefix( key, gameLocal.random ); - } - if ( *splat != '\0' ) { - gameLocal.BloodSplat( origin, dir, 64.0f, splat ); - } - - // can't see wounds on the player model in single player mode - if ( !( IsType( idPlayer::Type ) && !gameLocal.isMultiplayer ) ) { - // place a wound overlay on the model - key = va( "mtr_wound_%s", materialType ); - decal = spawnArgs.RandomPrefix( key, gameLocal.random ); - if ( *decal == '\0' ) { - decal = def->dict.RandomPrefix( key, gameLocal.random ); - } - if ( *decal != '\0' ) { - ProjectOverlay( origin, dir, 20.0f, decal ); - } - } - - // a blood spurting wound is added - key = va( "smoke_wound_%s", materialType ); - bleed = spawnArgs.GetString( key ); - if ( *bleed == '\0' ) { - bleed = def->dict.GetString( key ); - } - if ( *bleed != '\0' ) { - de = new damageEffect_t; - de->next = this->damageEffects; - this->damageEffects = de; - - de->jointNum = jointNum; - de->localOrigin = localOrigin; - de->localNormal = localNormal; - de->type = static_cast( declManager->FindType( DECL_PARTICLE, bleed ) ); - de->time = gameLocal.time; - } -} - -/* -============== -idAnimatedEntity::UpdateDamageEffects -============== -*/ -void idAnimatedEntity::UpdateDamageEffects( void ) { - damageEffect_t *de, **prev; - - // free any that have timed out - prev = &this->damageEffects; - while ( *prev ) { - de = *prev; - if ( de->time == 0 ) { // FIXME:SMOKE - *prev = de->next; - delete de; - } else { - prev = &de->next; - } - } - - if ( !g_bloodEffects.GetBool() ) { - return; - } - - // emit a particle for each bleeding wound - for ( de = this->damageEffects; de; de = de->next ) { - idVec3 origin, start; - idMat3 axis; - - animator.GetJointTransform( de->jointNum, gameLocal.time, origin, axis ); - axis *= renderEntity.axis; - origin = renderEntity.origin + origin * renderEntity.axis; - start = origin + de->localOrigin * axis; - if ( !gameLocal.smokeParticles->EmitSmoke( de->type, de->time, gameLocal.random.CRandomFloat(), start, axis, timeGroup /*_D3XP*/ ) ) { - de->time = 0; - } - } -} - -/* -================ -idAnimatedEntity::ClientReceiveEvent -================ -*/ -bool idAnimatedEntity::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) { - int damageDefIndex; - int materialIndex; - jointHandle_t jointNum; - idVec3 localOrigin, localNormal, localDir; - - switch( event ) { - case EVENT_ADD_DAMAGE_EFFECT: { - jointNum = (jointHandle_t) msg.ReadShort(); - localOrigin[0] = msg.ReadFloat(); - localOrigin[1] = msg.ReadFloat(); - localOrigin[2] = msg.ReadFloat(); - localNormal = msg.ReadDir( 24 ); - localDir = msg.ReadDir( 24 ); - damageDefIndex = gameLocal.ClientRemapDecl( DECL_ENTITYDEF, msg.ReadInt() ); - materialIndex = gameLocal.ClientRemapDecl( DECL_MATERIAL, msg.ReadInt() ); - const idDeclEntityDef *damageDef = static_cast( declManager->DeclByIndex( DECL_ENTITYDEF, damageDefIndex ) ); - const idMaterial *collisionMaterial = static_cast( declManager->DeclByIndex( DECL_MATERIAL, materialIndex ) ); - AddLocalDamageEffect( jointNum, localOrigin, localNormal, localDir, damageDef, collisionMaterial ); - return true; - } - default: - break; - } - - return idEntity::ClientReceiveEvent( event, time, msg ); -} - -/* -================ -idAnimatedEntity::Event_GetJointHandle - -looks up the number of the specified joint. returns INVALID_JOINT if the joint is not found. -================ -*/ -void idAnimatedEntity::Event_GetJointHandle( const char *jointname ) { - jointHandle_t joint; - - joint = animator.GetJointHandle( jointname ); - idThread::ReturnInt( joint ); -} - -/* -================ -idAnimatedEntity::Event_ClearAllJoints - -removes any custom transforms on all joints -================ -*/ -void idAnimatedEntity::Event_ClearAllJoints( void ) { - animator.ClearAllJoints(); -} - -/* -================ -idAnimatedEntity::Event_ClearJoint - -removes any custom transforms on the specified joint -================ -*/ -void idAnimatedEntity::Event_ClearJoint( jointHandle_t jointnum ) { - animator.ClearJoint( jointnum ); -} - -/* -================ -idAnimatedEntity::Event_SetJointPos - -modifies the position of the joint based on the transform type -================ -*/ -void idAnimatedEntity::Event_SetJointPos( jointHandle_t jointnum, jointModTransform_t transform_type, const idVec3 &pos ) { - animator.SetJointPos( jointnum, transform_type, pos ); -} - -/* -================ -idAnimatedEntity::Event_SetJointAngle - -modifies the orientation of the joint based on the transform type -================ -*/ -void idAnimatedEntity::Event_SetJointAngle( jointHandle_t jointnum, jointModTransform_t transform_type, const idAngles &angles ) { - idMat3 mat; - - mat = angles.ToMat3(); - animator.SetJointAxis( jointnum, transform_type, mat ); -} - -/* -================ -idAnimatedEntity::Event_GetJointPos - -returns the position of the joint in worldspace -================ -*/ -void idAnimatedEntity::Event_GetJointPos( jointHandle_t jointnum ) { - idVec3 offset; - idMat3 axis; - - if ( !GetJointWorldTransform( jointnum, gameLocal.time, offset, axis ) ) { - gameLocal.Warning( "Joint # %d out of range on entity '%s'", jointnum, name.c_str() ); - } - - idThread::ReturnVector( offset ); -} - -/* -================ -idAnimatedEntity::Event_GetJointAngle - -returns the orientation of the joint in worldspace -================ -*/ -void idAnimatedEntity::Event_GetJointAngle( jointHandle_t jointnum ) { - idVec3 offset; - idMat3 axis; - - if ( !GetJointWorldTransform( jointnum, gameLocal.time, offset, axis ) ) { - gameLocal.Warning( "Joint # %d out of range on entity '%s'", jointnum, name.c_str() ); - } - - idAngles ang = axis.ToAngles(); - idVec3 vec( ang[ 0 ], ang[ 1 ], ang[ 2 ] ); - idThread::ReturnVector( vec ); -} diff --git a/d3xp/Entity.h b/d3xp/Entity.h deleted file mode 100644 index 4413c303..00000000 --- a/d3xp/Entity.h +++ /dev/null @@ -1,629 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __GAME_ENTITY_H__ -#define __GAME_ENTITY_H__ - -#include "idlib/math/Curve.h" -#include "framework/DeclParticle.h" - -#include "physics/Physics_Static.h" -#include "physics/Physics.h" -#include "script/Script_Program.h" -#include "gamesys/Class.h" -#include "gamesys/Event.h" -#include "Game_local.h" - -/* -=============================================================================== - - Game entity base class. - -=============================================================================== -*/ - -static const int DELAY_DORMANT_TIME = 3000; - -extern const idEventDef EV_PostSpawn; -extern const idEventDef EV_FindTargets; -extern const idEventDef EV_Touch; -extern const idEventDef EV_Use; -extern const idEventDef EV_Activate; -extern const idEventDef EV_ActivateTargets; -extern const idEventDef EV_Hide; -extern const idEventDef EV_Show; -extern const idEventDef EV_GetShaderParm; -extern const idEventDef EV_SetShaderParm; -extern const idEventDef EV_SetOwner; -extern const idEventDef EV_GetAngles; -extern const idEventDef EV_SetAngles; -extern const idEventDef EV_SetLinearVelocity; -extern const idEventDef EV_SetAngularVelocity; -extern const idEventDef EV_SetSkin; -extern const idEventDef EV_StartSoundShader; -extern const idEventDef EV_StopSound; -extern const idEventDef EV_CacheSoundShader; - -// Think flags -enum { - TH_ALL = -1, - TH_THINK = 1, // run think function each frame - TH_PHYSICS = 2, // run physics each frame - TH_ANIMATE = 4, // update animation each frame - TH_UPDATEVISUALS = 8, // update renderEntity - TH_UPDATEPARTICLES = 16 -}; - -// -// Signals -// make sure to change script/doom_defs.script if you add any, or change their order -// -typedef enum { - SIG_TOUCH, // object was touched - SIG_USE, // object was used - SIG_TRIGGER, // object was activated - SIG_REMOVED, // object was removed from the game - SIG_DAMAGE, // object was damaged - SIG_BLOCKED, // object was blocked - - SIG_MOVER_POS1, // mover at position 1 (door closed) - SIG_MOVER_POS2, // mover at position 2 (door open) - SIG_MOVER_1TO2, // mover changing from position 1 to 2 - SIG_MOVER_2TO1, // mover changing from position 2 to 1 - - NUM_SIGNALS -} signalNum_t; - -// FIXME: At some point we may want to just limit it to one thread per signal, but -// for now, I'm allowing multiple threads. We should reevaluate this later in the project -#define MAX_SIGNAL_THREADS 16 // probably overkill, but idList uses a granularity of 16 - -struct signal_t { - int threadnum; - const function_t *function; -}; - -class signalList_t { -public: - idList signal[ NUM_SIGNALS ]; -}; - - -class idEntity : public idClass { -public: - static const int MAX_PVS_AREAS = 4; - - int entityNumber; // index into the entity list - int entityDefNumber; // index into the entity def list - - idLinkList spawnNode; // for being linked into spawnedEntities list - idLinkList activeNode; // for being linked into activeEntities list - - idLinkList snapshotNode; // for being linked into snapshotEntities list - int snapshotSequence; // last snapshot this entity was in - int snapshotBits; // number of bits this entity occupied in the last snapshot - - idStr name; // name of entity - idDict spawnArgs; // key/value pairs used to spawn and initialize entity - idScriptObject scriptObject; // contains all script defined data for this entity - - int thinkFlags; // TH_? flags - int dormantStart; // time that the entity was first closed off from player - bool cinematic; // during cinematics, entity will only think if cinematic is set - - renderView_t * renderView; // for camera views from this entity - idEntity * cameraTarget; // any remoteRenderMap shaders will use this - - idList< idEntityPtr > targets; // when this entity is activated these entities entity are activated - - int health; // FIXME: do all objects really need health? - - struct entityFlags_s { - bool notarget :1; // if true never attack or target this entity - bool noknockback :1; // if true no knockback from hits - bool takedamage :1; // if true this entity can be damaged - bool hidden :1; // if true this entity is not visible - bool bindOrientated :1; // if true both the master orientation is used for binding - bool solidForTeam :1; // if true this entity is considered solid when a physics team mate pushes entities - bool forcePhysicsUpdate :1; // if true always update from the physics whether the object moved or not - bool selected :1; // if true the entity is selected for editing - bool neverDormant :1; // if true the entity never goes dormant - bool isDormant :1; // if true the entity is dormant - bool hasAwakened :1; // before a monster has been awakened the first time, use full PVS for dormant instead of area-connected - bool networkSync :1; // if true the entity is synchronized over the network - bool grabbed :1; // if true object is currently being grabbed - } fl; - -#ifdef _D3XP - int timeGroup; - - bool noGrab; - - renderEntity_t xrayEntity; - qhandle_t xrayEntityHandle; - const idDeclSkin * xraySkin; - - void DetermineTimeGroup( bool slowmo ); - - void SetGrabbedState( bool grabbed ); - bool IsGrabbed(); -#endif - -public: - ABSTRACT_PROTOTYPE( idEntity ); - - idEntity(); - ~idEntity(); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - const char * GetEntityDefName( void ) const; - void SetName( const char *name ); - const char * GetName( void ) const; - virtual void UpdateChangeableSpawnArgs( const idDict *source ); - - // clients generate views based on all the player specific options, - // cameras have custom code, and everything else just uses the axis orientation - virtual renderView_t * GetRenderView(); - - // thinking - virtual void Think( void ); - bool CheckDormant( void ); // dormant == on the active list, but out of PVS - virtual void DormantBegin( void ); // called when entity becomes dormant - virtual void DormantEnd( void ); // called when entity wakes from being dormant - bool IsActive( void ) const; - void BecomeActive( int flags ); - void BecomeInactive( int flags ); - void UpdatePVSAreas( const idVec3 &pos ); - - // visuals - virtual void Present( void ); - virtual renderEntity_t *GetRenderEntity( void ); - virtual int GetModelDefHandle( void ); - virtual void SetModel( const char *modelname ); - void SetSkin( const idDeclSkin *skin ); - const idDeclSkin * GetSkin( void ) const; - void SetShaderParm( int parmnum, float value ); - virtual void SetColor( float red, float green, float blue ); - virtual void SetColor( const idVec3 &color ); - virtual void GetColor( idVec3 &out ) const; - virtual void SetColor( const idVec4 &color ); - virtual void GetColor( idVec4 &out ) const; - virtual void FreeModelDef( void ); - virtual void FreeLightDef( void ); - virtual void Hide( void ); - virtual void Show( void ); - bool IsHidden( void ) const; - void UpdateVisuals( void ); - void UpdateModel( void ); - void UpdateModelTransform( void ); - virtual void ProjectOverlay( const idVec3 &origin, const idVec3 &dir, float size, const char *material ); - int GetNumPVSAreas( void ); - const int * GetPVSAreas( void ); - void ClearPVSAreas( void ); - bool PhysicsTeamInPVS( pvsHandle_t pvsHandle ); - - // animation - virtual bool UpdateAnimationControllers( void ); - bool UpdateRenderEntity( renderEntity_s *renderEntity, const renderView_t *renderView ); - static bool ModelCallback( renderEntity_s *renderEntity, const renderView_t *renderView ); - virtual idAnimator * GetAnimator( void ); // returns animator object used by this entity - - // sound - virtual bool CanPlayChatterSounds( void ) const; - bool StartSound( const char *soundName, const s_channelType channel, int soundShaderFlags, bool broadcast, int *length ); - bool StartSoundShader( const idSoundShader *shader, const s_channelType channel, int soundShaderFlags, bool broadcast, int *length ); - void StopSound( const s_channelType channel, bool broadcast ); // pass SND_CHANNEL_ANY to stop all sounds - void SetSoundVolume( float volume ); - void UpdateSound( void ); - int GetListenerId( void ) const; - idSoundEmitter * GetSoundEmitter( void ) const; - void FreeSoundEmitter( bool immediate ); - - // entity binding - virtual void PreBind( void ); - virtual void PostBind( void ); - virtual void PreUnbind( void ); - virtual void PostUnbind( void ); - void JoinTeam( idEntity *teammember ); - void Bind( idEntity *master, bool orientated ); - void BindToJoint( idEntity *master, const char *jointname, bool orientated ); - void BindToJoint( idEntity *master, jointHandle_t jointnum, bool orientated ); - void BindToBody( idEntity *master, int bodyId, bool orientated ); - void Unbind( void ); - bool IsBound( void ) const; - bool IsBoundTo( idEntity *master ) const; - idEntity * GetBindMaster( void ) const; - jointHandle_t GetBindJoint( void ) const; - int GetBindBody( void ) const; - idEntity * GetTeamMaster( void ) const; - idEntity * GetNextTeamEntity( void ) const; - void ConvertLocalToWorldTransform( idVec3 &offset, idMat3 &axis ); - idVec3 GetLocalVector( const idVec3 &vec ) const; - idVec3 GetLocalCoordinates( const idVec3 &vec ) const; - idVec3 GetWorldVector( const idVec3 &vec ) const; - idVec3 GetWorldCoordinates( const idVec3 &vec ) const; - bool GetMasterPosition( idVec3 &masterOrigin, idMat3 &masterAxis ) const; - void GetWorldVelocities( idVec3 &linearVelocity, idVec3 &angularVelocity ) const; - - // physics - // set a new physics object to be used by this entity - void SetPhysics( idPhysics *phys ); - // get the physics object used by this entity - idPhysics * GetPhysics( void ) const; - // restore physics pointer for save games - void RestorePhysics( idPhysics *phys ); - // run the physics for this entity - bool RunPhysics( void ); - // set the origin of the physics object (relative to bindMaster if not NULL) - void SetOrigin( const idVec3 &org ); - // set the axis of the physics object (relative to bindMaster if not NULL) - void SetAxis( const idMat3 &axis ); - // use angles to set the axis of the physics object (relative to bindMaster if not NULL) - void SetAngles( const idAngles &ang ); - // get the floor position underneath the physics object - bool GetFloorPos( float max_dist, idVec3 &floorpos ) const; - // retrieves the transformation going from the physics origin/axis to the visual origin/axis - virtual bool GetPhysicsToVisualTransform( idVec3 &origin, idMat3 &axis ); - // retrieves the transformation going from the physics origin/axis to the sound origin/axis - virtual bool GetPhysicsToSoundTransform( idVec3 &origin, idMat3 &axis ); - // called from the physics object when colliding, should return true if the physics simulation should stop - virtual bool Collide( const trace_t &collision, const idVec3 &velocity ); - // retrieves impact information, 'ent' is the entity retrieving the info - virtual void GetImpactInfo( idEntity *ent, int id, const idVec3 &point, impactInfo_t *info ); - // apply an impulse to the physics object, 'ent' is the entity applying the impulse - virtual void ApplyImpulse( idEntity *ent, int id, const idVec3 &point, const idVec3 &impulse ); - // add a force to the physics object, 'ent' is the entity adding the force - virtual void AddForce( idEntity *ent, int id, const idVec3 &point, const idVec3 &force ); - // activate the physics object, 'ent' is the entity activating this entity - virtual void ActivatePhysics( idEntity *ent ); - // returns true if the physics object is at rest - virtual bool IsAtRest( void ) const; - // returns the time the physics object came to rest - virtual int GetRestStartTime( void ) const; - // add a contact entity - virtual void AddContactEntity( idEntity *ent ); - // remove a touching entity - virtual void RemoveContactEntity( idEntity *ent ); - - // damage - // returns true if this entity can be damaged from the given origin - virtual bool CanDamage( const idVec3 &origin, idVec3 &damagePoint ) const; - // applies damage to this entity - virtual void Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location ); - // adds a damage effect like overlays, blood, sparks, debris etc. - virtual void AddDamageEffect( const trace_t &collision, const idVec3 &velocity, const char *damageDefName ); - // callback function for when another entity received damage from this entity. damage can be adjusted and returned to the caller. - virtual void DamageFeedback( idEntity *victim, idEntity *inflictor, int &damage ); - // notifies this entity that it is in pain - virtual bool Pain( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ); - // notifies this entity that is has been killed - virtual void Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ); - - // scripting - virtual bool ShouldConstructScriptObjectAtSpawn( void ) const; - virtual idThread * ConstructScriptObject( void ); - virtual void DeconstructScriptObject( void ); - void SetSignal( signalNum_t signalnum, idThread *thread, const function_t *function ); - void ClearSignal( idThread *thread, signalNum_t signalnum ); - void ClearSignalThread( signalNum_t signalnum, idThread *thread ); - bool HasSignal( signalNum_t signalnum ) const; - void Signal( signalNum_t signalnum ); - void SignalEvent( idThread *thread, signalNum_t signalnum ); - - // gui - void TriggerGuis( void ); - bool HandleGuiCommands( idEntity *entityGui, const char *cmds ); - virtual bool HandleSingleGuiCommand( idEntity *entityGui, idLexer *src ); - - // targets - void FindTargets( void ); - void RemoveNullTargets( void ); - void ActivateTargets( idEntity *activator ) const; - - // misc - virtual void Teleport( const idVec3 &origin, const idAngles &angles, idEntity *destination ); - bool TouchTriggers( void ) const; - idCurve_Spline *GetSpline( void ) const; - virtual void ShowEditingDialog( void ); - - enum { - EVENT_STARTSOUNDSHADER, - EVENT_STOPSOUNDSHADER, - EVENT_MAXEVENTS - }; - - virtual void ClientPredictionThink( void ); - virtual void WriteToSnapshot( idBitMsgDelta &msg ) const; - virtual void ReadFromSnapshot( const idBitMsgDelta &msg ); - virtual bool ServerReceiveEvent( int event, int time, const idBitMsg &msg ); - virtual bool ClientReceiveEvent( int event, int time, const idBitMsg &msg ); - - void WriteBindToSnapshot( idBitMsgDelta &msg ) const; - void ReadBindFromSnapshot( const idBitMsgDelta &msg ); - void WriteColorToSnapshot( idBitMsgDelta &msg ) const; - void ReadColorFromSnapshot( const idBitMsgDelta &msg ); - void WriteGUIToSnapshot( idBitMsgDelta &msg ) const; - void ReadGUIFromSnapshot( const idBitMsgDelta &msg ); - - void ServerSendEvent( int eventId, const idBitMsg *msg, bool saveEvent, int excludeClient ) const; - void ClientSendEvent( int eventId, const idBitMsg *msg ) const; - -protected: - renderEntity_t renderEntity; // used to present a model to the renderer - int modelDefHandle; // handle to static renderer model - refSound_t refSound; // used to present sound to the audio engine - -private: - idPhysics_Static defaultPhysicsObj; // default physics object - idPhysics * physics; // physics used for this entity - idEntity * bindMaster; // entity bound to if unequal NULL - jointHandle_t bindJoint; // joint bound to if unequal INVALID_JOINT - int bindBody; // body bound to if unequal -1 - idEntity * teamMaster; // master of the physics team - idEntity * teamChain; // next entity in physics team - - int numPVSAreas; // number of renderer areas the entity covers - int PVSAreas[MAX_PVS_AREAS]; // numbers of the renderer areas the entity covers - - signalList_t * signals; - - int mpGUIState; // local cache to avoid systematic SetStateInt - -private: - void FixupLocalizedStrings(); - - bool DoDormantTests( void ); // dormant == on the active list, but out of PVS - - // physics - // initialize the default physics - void InitDefaultPhysics( const idVec3 &origin, const idMat3 &axis ); - // update visual position from the physics - void UpdateFromPhysics( bool moveBack ); - - // entity binding - bool InitBind( idEntity *master ); // initialize an entity binding - void FinishBind( void ); // finish an entity binding - void RemoveBinds( void ); // deletes any entities bound to this object - void QuitTeam( void ); // leave the current team - - void UpdatePVSAreas( void ); - - // events - void Event_GetName( void ); - void Event_SetName( const char *name ); - void Event_FindTargets( void ); - void Event_ActivateTargets( idEntity *activator ); - void Event_NumTargets( void ); - void Event_GetTarget( float index ); - void Event_RandomTarget( const char *ignore ); - void Event_Bind( idEntity *master ); - void Event_BindPosition( idEntity *master ); - void Event_BindToJoint( idEntity *master, const char *jointname, float orientated ); - void Event_Unbind( void ); - void Event_RemoveBinds( void ); - void Event_SpawnBind( void ); - void Event_SetOwner( idEntity *owner ); - void Event_SetModel( const char *modelname ); - void Event_SetSkin( const char *skinname ); - void Event_GetShaderParm( int parmnum ); - void Event_SetShaderParm( int parmnum, float value ); - void Event_SetShaderParms( float parm0, float parm1, float parm2, float parm3 ); - void Event_SetColor( float red, float green, float blue ); - void Event_GetColor( void ); - void Event_IsHidden( void ); - void Event_Hide( void ); - void Event_Show( void ); - void Event_CacheSoundShader( const char *soundName ); - void Event_StartSoundShader( const char *soundName, int channel ); - void Event_StopSound( int channel, int netSync ); - void Event_StartSound( const char *soundName, int channel, int netSync ); - void Event_FadeSound( int channel, float to, float over ); - void Event_GetWorldOrigin( void ); - void Event_SetWorldOrigin( idVec3 const &org ); - void Event_GetOrigin( void ); - void Event_SetOrigin( const idVec3 &org ); - void Event_GetAngles( void ); - void Event_SetAngles( const idAngles &ang ); - void Event_SetLinearVelocity( const idVec3 &velocity ); - void Event_GetLinearVelocity( void ); - void Event_SetAngularVelocity( const idVec3 &velocity ); - void Event_GetAngularVelocity( void ); - void Event_SetSize( const idVec3 &mins, const idVec3 &maxs ); - void Event_GetSize( void ); - void Event_GetMins( void ); - void Event_GetMaxs( void ); - void Event_Touches( idEntity *ent ); - void Event_SetGuiParm( const char *key, const char *val ); - void Event_SetGuiFloat( const char *key, float f ); - void Event_GetNextKey( const char *prefix, const char *lastMatch ); - void Event_SetKey( const char *key, const char *value ); - void Event_GetKey( const char *key ); - void Event_GetIntKey( const char *key ); - void Event_GetFloatKey( const char *key ); - void Event_GetVectorKey( const char *key ); - void Event_GetEntityKey( const char *key ); - void Event_RestorePosition( void ); - void Event_UpdateCameraTarget( void ); - void Event_DistanceTo( idEntity *ent ); - void Event_DistanceToPoint( const idVec3 &point ); - void Event_StartFx( const char *fx ); - void Event_WaitFrame( void ); - void Event_Wait( float time ); - void Event_HasFunction( const char *name ); - void Event_CallFunction( const char *name ); - void Event_SetNeverDormant( int enable ); -#ifdef _D3XP - void Event_SetGui( int guiNum, const char *guiName); - void Event_PrecacheGui( const char *guiName ); - void Event_GetGuiParm(int guiNum, const char *key); - void Event_GetGuiParmFloat(int guiNum, const char *key); - void Event_GuiNamedEvent(int guiNum, const char *event); -#endif -}; - -/* -=============================================================================== - - Animated entity base class. - -=============================================================================== -*/ - -typedef struct damageEffect_s { - jointHandle_t jointNum; - idVec3 localOrigin; - idVec3 localNormal; - int time; - const idDeclParticle* type; - struct damageEffect_s * next; -} damageEffect_t; - -class idAnimatedEntity : public idEntity { -public: - CLASS_PROTOTYPE( idAnimatedEntity ); - - idAnimatedEntity(); - ~idAnimatedEntity(); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - virtual void ClientPredictionThink( void ); - virtual void Think( void ); - - void UpdateAnimation( void ); - - virtual idAnimator * GetAnimator( void ); - virtual void SetModel( const char *modelname ); - - bool GetJointWorldTransform( jointHandle_t jointHandle, int currentTime, idVec3 &offset, idMat3 &axis ); - bool GetJointTransformForAnim( jointHandle_t jointHandle, int animNum, int currentTime, idVec3 &offset, idMat3 &axis ) const; - - virtual int GetDefaultSurfaceType( void ) const; - virtual void AddDamageEffect( const trace_t &collision, const idVec3 &velocity, const char *damageDefName ); - void AddLocalDamageEffect( jointHandle_t jointNum, const idVec3 &localPoint, const idVec3 &localNormal, const idVec3 &localDir, const idDeclEntityDef *def, const idMaterial *collisionMaterial ); - void UpdateDamageEffects( void ); - - virtual bool ClientReceiveEvent( int event, int time, const idBitMsg &msg ); - - enum { - EVENT_ADD_DAMAGE_EFFECT = idEntity::EVENT_MAXEVENTS, - EVENT_MAXEVENTS - }; - -protected: - idAnimator animator; - damageEffect_t * damageEffects; - -private: - void Event_GetJointHandle( const char *jointname ); - void Event_ClearAllJoints( void ); - void Event_ClearJoint( jointHandle_t jointnum ); - void Event_SetJointPos( jointHandle_t jointnum, jointModTransform_t transform_type, const idVec3 &pos ); - void Event_SetJointAngle( jointHandle_t jointnum, jointModTransform_t transform_type, const idAngles &angles ); - void Event_GetJointPos( jointHandle_t jointnum ); - void Event_GetJointAngle( jointHandle_t jointnum ); -}; - - -#ifdef _D3XP -class SetTimeState { - bool activated; - bool previousFast; - bool fast; - -public: - SetTimeState(); - SetTimeState( int timeGroup ); - ~SetTimeState(); - - void PushState( int timeGroup ); -}; - -ID_INLINE SetTimeState::SetTimeState() { - activated = false; - previousFast = false; -} - -ID_INLINE SetTimeState::SetTimeState( int timeGroup ) { - activated = false; - previousFast = false; - PushState( timeGroup ); -} - -ID_INLINE void SetTimeState::PushState( int timeGroup ) { - - // Don't mess with time in Multiplayer - if ( !gameLocal.isMultiplayer ) { - - activated = true; - - // determine previous fast setting - if ( gameLocal.time == gameLocal.slow.time ) { - previousFast = false; - } - else { - previousFast = true; - } - - // determine new fast setting - if ( timeGroup ) { - fast = true; - } - else { - fast = false; - } - - // set correct time - if ( fast ) { - gameLocal.fast.Get( gameLocal.time, gameLocal.previousTime, gameLocal.msec, gameLocal.framenum, gameLocal.realClientTime ); - } - else { - gameLocal.slow.Get( gameLocal.time, gameLocal.previousTime, gameLocal.msec, gameLocal.framenum, gameLocal.realClientTime ); - } - } -} - -ID_INLINE SetTimeState::~SetTimeState() { - if ( activated && !gameLocal.isMultiplayer ) { - // set previous correct time - if ( previousFast ) { - gameLocal.fast.Get( gameLocal.time, gameLocal.previousTime, gameLocal.msec, gameLocal.framenum, gameLocal.realClientTime ); - } - else { - gameLocal.slow.Get( gameLocal.time, gameLocal.previousTime, gameLocal.msec, gameLocal.framenum, gameLocal.realClientTime ); - } - } -} -#endif - -#endif /* !__GAME_ENTITY_H__ */ diff --git a/d3xp/Fx.cpp b/d3xp/Fx.cpp deleted file mode 100644 index ea8a09f5..00000000 --- a/d3xp/Fx.cpp +++ /dev/null @@ -1,824 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "renderer/ModelManager.h" - -#include "gamesys/SysCvar.h" -#include "Player.h" -#include "Projectile.h" -#include "WorldSpawn.h" - -#include "Fx.h" - -/* -=============================================================================== - - idEntityFx - -=============================================================================== -*/ - -const idEventDef EV_Fx_KillFx( "_killfx" ); -const idEventDef EV_Fx_Action( "_fxAction", "e" ); // implemented by subclasses - -CLASS_DECLARATION( idEntity, idEntityFx ) -EVENT( EV_Activate, idEntityFx::Event_Trigger ) -EVENT( EV_Fx_KillFx, idEntityFx::Event_ClearFx ) -END_CLASS - - -/* -================ -idEntityFx::Save -================ -*/ -void idEntityFx::Save( idSaveGame *savefile ) const { - int i; - - savefile->WriteInt( started ); - savefile->WriteInt( nextTriggerTime ); - savefile->WriteFX( fxEffect ); - savefile->WriteString( systemName ); - - savefile->WriteInt( actions.Num() ); - - for ( i = 0; i < actions.Num(); i++ ) { - - if ( actions[i].lightDefHandle >= 0 ) { - savefile->WriteBool( true ); - savefile->WriteRenderLight( actions[i].renderLight ); - } else { - savefile->WriteBool( false ); - } - - if ( actions[i].modelDefHandle >= 0 ) { - savefile->WriteBool( true ); - savefile->WriteRenderEntity( actions[i].renderEntity ); - } else { - savefile->WriteBool( false ); - } - - savefile->WriteFloat( actions[i].delay ); - savefile->WriteInt( actions[i].start ); - savefile->WriteBool( actions[i].soundStarted ); - savefile->WriteBool( actions[i].shakeStarted ); - savefile->WriteBool( actions[i].decalDropped ); - savefile->WriteBool( actions[i].launched ); - } -} - -/* -================ -idEntityFx::Restore -================ -*/ -void idEntityFx::Restore( idRestoreGame *savefile ) { - int i; - int num; - bool hasObject; - - savefile->ReadInt( started ); - savefile->ReadInt( nextTriggerTime ); - savefile->ReadFX( fxEffect ); - savefile->ReadString( systemName ); - - savefile->ReadInt( num ); - - actions.SetNum( num ); - for ( i = 0; i < num; i++ ) { - - savefile->ReadBool( hasObject ); - if ( hasObject ) { - savefile->ReadRenderLight( actions[i].renderLight ); - actions[i].lightDefHandle = gameRenderWorld->AddLightDef( &actions[i].renderLight ); - } else { - memset( &actions[i].renderLight, 0, sizeof( renderLight_t ) ); - actions[i].lightDefHandle = -1; - } - - savefile->ReadBool( hasObject ); - if ( hasObject ) { - savefile->ReadRenderEntity( actions[i].renderEntity ); - actions[i].modelDefHandle = gameRenderWorld->AddEntityDef( &actions[i].renderEntity ); - } else { - memset( &actions[i].renderEntity, 0, sizeof( renderEntity_t ) ); - actions[i].modelDefHandle = -1; - } - - savefile->ReadFloat( actions[i].delay ); - - // let the FX regenerate the particleSystem - actions[i].particleSystem = -1; - - savefile->ReadInt( actions[i].start ); - savefile->ReadBool( actions[i].soundStarted ); - savefile->ReadBool( actions[i].shakeStarted ); - savefile->ReadBool( actions[i].decalDropped ); - savefile->ReadBool( actions[i].launched ); - } -} - -/* -================ -idEntityFx::Setup -================ -*/ -void idEntityFx::Setup( const char *fx ) { - - if ( started >= 0 ) { - return; // already started - } - - // early during MP Spawn() with no information. wait till we ReadFromSnapshot for more - if ( gameLocal.isClient && ( !fx || fx[0] == '\0' ) ) { - return; - } - - systemName = fx; - started = 0; - - fxEffect = static_cast( declManager->FindType( DECL_FX, systemName.c_str() ) ); - - if ( fxEffect ) { - idFXLocalAction localAction; - - memset( &localAction, 0, sizeof( idFXLocalAction ) ); - - actions.AssureSize( fxEffect->events.Num(), localAction ); - - for( int i = 0; ievents.Num(); i++ ) { - const idFXSingleAction& fxaction = fxEffect->events[i]; - - idFXLocalAction& laction = actions[i]; - if ( fxaction.random1 || fxaction.random2 ) { - laction.delay = fxaction.random1 + gameLocal.random.RandomFloat() * ( fxaction.random2 - fxaction.random1 ); - } else { - laction.delay = fxaction.delay; - } - laction.start = -1; - laction.lightDefHandle = -1; - laction.modelDefHandle = -1; - laction.particleSystem = -1; - laction.shakeStarted = false; - laction.decalDropped = false; - laction.launched = false; - } - } -} - -/* -================ -idEntityFx::EffectName -================ -*/ -const char *idEntityFx::EffectName( void ) { - return fxEffect ? fxEffect->GetName() : NULL; -} - -/* -================ -idEntityFx::Joint -================ -*/ -const char *idEntityFx::Joint( void ) { - return fxEffect ? fxEffect->joint.c_str() : NULL; -} - -/* -================ -idEntityFx::CleanUp -================ -*/ -void idEntityFx::CleanUp( void ) { - if ( !fxEffect ) { - return; - } - for( int i = 0; i < fxEffect->events.Num(); i++ ) { - const idFXSingleAction& fxaction = fxEffect->events[i]; - idFXLocalAction& laction = actions[i]; - CleanUpSingleAction( fxaction, laction ); - } -} - -/* -================ -idEntityFx::CleanUpSingleAction -================ -*/ -void idEntityFx::CleanUpSingleAction( const idFXSingleAction& fxaction, idFXLocalAction& laction ) { - if ( laction.lightDefHandle != -1 && fxaction.sibling == -1 && fxaction.type != FX_ATTACHLIGHT ) { - gameRenderWorld->FreeLightDef( laction.lightDefHandle ); - laction.lightDefHandle = -1; - } - if ( laction.modelDefHandle != -1 && fxaction.sibling == -1 && fxaction.type != FX_ATTACHENTITY ) { - gameRenderWorld->FreeEntityDef( laction.modelDefHandle ); - laction.modelDefHandle = -1; - } - laction.start = -1; -} - -/* -================ -idEntityFx::Start -================ -*/ -void idEntityFx::Start( int time ) { - if ( !fxEffect ) { - return; - } - started = time; - for( int i = 0; i < fxEffect->events.Num(); i++ ) { - idFXLocalAction& laction = actions[i]; - laction.start = time; - laction.soundStarted = false; - laction.shakeStarted = false; - laction.particleSystem = -1; - laction.decalDropped = false; - laction.launched = false; - } -} - -/* -================ -idEntityFx::Stop -================ -*/ -void idEntityFx::Stop( void ) { - CleanUp(); - started = -1; -} - -/* -================ -idEntityFx::Duration -================ -*/ -const int idEntityFx::Duration( void ) { - int max = 0; - - if ( !fxEffect ) { - return max; - } - for( int i = 0; i < fxEffect->events.Num(); i++ ) { - const idFXSingleAction& fxaction = fxEffect->events[i]; - int d = ( fxaction.delay + fxaction.duration ) * 1000.0f; - if ( d > max ) { - max = d; - } - } - - return max; -} - - -/* -================ -idEntityFx::Done -================ -*/ -const bool idEntityFx::Done() { - if (started > 0 && gameLocal.time > started + Duration()) { - return true; - } - return false; -} - -/* -================ -idEntityFx::ApplyFade -================ -*/ -void idEntityFx::ApplyFade( const idFXSingleAction& fxaction, idFXLocalAction& laction, const int time, const int actualStart ) { - if ( fxaction.fadeInTime || fxaction.fadeOutTime ) { - float fadePct = (float)( time - actualStart ) / ( 1000.0f * ( ( fxaction.fadeInTime != 0 ) ? fxaction.fadeInTime : fxaction.fadeOutTime ) ); - if (fadePct > 1.0) { - fadePct = 1.0; - } - if ( laction.modelDefHandle != -1 ) { - laction.renderEntity.shaderParms[SHADERPARM_RED] = (fxaction.fadeInTime) ? fadePct : 1.0f - fadePct; - laction.renderEntity.shaderParms[SHADERPARM_GREEN] = (fxaction.fadeInTime) ? fadePct : 1.0f - fadePct; - laction.renderEntity.shaderParms[SHADERPARM_BLUE] = (fxaction.fadeInTime) ? fadePct : 1.0f - fadePct; - - gameRenderWorld->UpdateEntityDef( laction.modelDefHandle, &laction.renderEntity ); - } - if ( laction.lightDefHandle != -1 ) { - laction.renderLight.shaderParms[SHADERPARM_RED] = fxaction.lightColor.x * ( (fxaction.fadeInTime) ? fadePct : 1.0f - fadePct ); - laction.renderLight.shaderParms[SHADERPARM_GREEN] = fxaction.lightColor.y * ( (fxaction.fadeInTime) ? fadePct : 1.0f - fadePct ); - laction.renderLight.shaderParms[SHADERPARM_BLUE] = fxaction.lightColor.z * ( (fxaction.fadeInTime) ? fadePct : 1.0f - fadePct ); - - gameRenderWorld->UpdateLightDef( laction.lightDefHandle, &laction.renderLight ); - } - } -} - -/* -================ -idEntityFx::Run -================ -*/ -void idEntityFx::Run( int time ) { - int ieff, j; - idEntity *ent = NULL; - const idDict *projectileDef = NULL; - idProjectile *projectile = NULL; - - if ( !fxEffect ) { - return; - } - - for( ieff = 0; ieff < fxEffect->events.Num(); ieff++ ) { - const idFXSingleAction& fxaction = fxEffect->events[ieff]; - idFXLocalAction& laction = actions[ieff]; - - // - // if we're currently done with this one - // - if ( laction.start == -1 ) { - continue; - } - - // - // see if it's delayed - // - if ( laction.delay ) { - if ( laction.start + (time - laction.start) < laction.start + (laction.delay * 1000) ) { - continue; - } - } - - // - // each event can have it's own delay and restart - // - int actualStart = laction.delay ? laction.start + (int)( laction.delay * 1000 ) : laction.start; - float pct = (float)( time - actualStart ) / (1000 * fxaction.duration ); - if ( pct >= 1.0f ) { - laction.start = -1; - float totalDelay = 0.0f; - if ( fxaction.restart ) { - if ( fxaction.random1 || fxaction.random2 ) { - totalDelay = fxaction.random1 + gameLocal.random.RandomFloat() * (fxaction.random2 - fxaction.random1); - } else { - totalDelay = fxaction.delay; - } - laction.delay = totalDelay; - laction.start = time; - } - continue; - } - - if ( fxaction.fire.Length() ) { - for( j = 0; j < fxEffect->events.Num(); j++ ) { - if ( fxEffect->events[j].name.Icmp( fxaction.fire ) == 0 ) { - actions[j].delay = 0; - } - } - } - - idFXLocalAction *useAction; - if ( fxaction.sibling == -1 ) { - useAction = &laction; - } else { - useAction = &actions[fxaction.sibling]; - } - assert( useAction ); - - switch( fxaction.type ) { - case FX_ATTACHLIGHT: - case FX_LIGHT: { - if ( useAction->lightDefHandle == -1 ) { - if ( fxaction.type == FX_LIGHT ) { - memset( &useAction->renderLight, 0, sizeof( renderLight_t ) ); - useAction->renderLight.origin = GetPhysics()->GetOrigin() + fxaction.offset; - useAction->renderLight.axis = GetPhysics()->GetAxis(); - useAction->renderLight.lightRadius[0] = fxaction.lightRadius; - useAction->renderLight.lightRadius[1] = fxaction.lightRadius; - useAction->renderLight.lightRadius[2] = fxaction.lightRadius; - useAction->renderLight.shader = declManager->FindMaterial( fxaction.data, false ); - useAction->renderLight.shaderParms[ SHADERPARM_RED ] = fxaction.lightColor.x; - useAction->renderLight.shaderParms[ SHADERPARM_GREEN ] = fxaction.lightColor.y; - useAction->renderLight.shaderParms[ SHADERPARM_BLUE ] = fxaction.lightColor.z; - useAction->renderLight.shaderParms[ SHADERPARM_TIMESCALE ] = 1.0f; - useAction->renderLight.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( time ); - useAction->renderLight.referenceSound = refSound.referenceSound; - useAction->renderLight.pointLight = true; - if ( fxaction.noshadows ) { - useAction->renderLight.noShadows = true; - } - useAction->lightDefHandle = gameRenderWorld->AddLightDef( &useAction->renderLight ); - } - if ( fxaction.noshadows ) { - for( j = 0; j < fxEffect->events.Num(); j++ ) { - idFXLocalAction& laction2 = actions[j]; - if ( laction2.modelDefHandle != -1 ) { - laction2.renderEntity.noShadow = true; - } - } - } - } - ApplyFade( fxaction, *useAction, time, actualStart ); - break; - } - case FX_SOUND: { - if ( !useAction->soundStarted ) { - useAction->soundStarted = true; - const idSoundShader *shader = declManager->FindSound(fxaction.data); - StartSoundShader( shader, SND_CHANNEL_ANY, 0, false, NULL ); - for( j = 0; j < fxEffect->events.Num(); j++ ) { - idFXLocalAction& laction2 = actions[j]; - if ( laction2.lightDefHandle != -1 ) { - laction2.renderLight.referenceSound = refSound.referenceSound; - gameRenderWorld->UpdateLightDef( laction2.lightDefHandle, &laction2.renderLight ); - } - } - } - break; - } - case FX_DECAL: { - if ( !useAction->decalDropped ) { - useAction->decalDropped = true; - gameLocal.ProjectDecal( GetPhysics()->GetOrigin(), GetPhysics()->GetGravity(), 8.0f, true, fxaction.size, fxaction.data ); - } - break; - } - case FX_SHAKE: { - if ( !useAction->shakeStarted ) { - idDict args; - args.Clear(); - args.SetFloat( "kick_time", fxaction.shakeTime ); - args.SetFloat( "kick_amplitude", fxaction.shakeAmplitude ); - for ( j = 0; j < gameLocal.numClients; j++ ) { - idPlayer *player = gameLocal.GetClientByNum( j ); - if ( player && ( player->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin() ).LengthSqr() < Square( fxaction.shakeDistance ) ) { - if ( !gameLocal.isMultiplayer || !fxaction.shakeIgnoreMaster || GetBindMaster() != player ) { - player->playerView.DamageImpulse( fxaction.offset, &args ); - } - } - } - if ( fxaction.shakeImpulse != 0.0f && fxaction.shakeDistance != 0.0f ) { - idEntity *ignore_ent = NULL; - if ( gameLocal.isMultiplayer ) { - ignore_ent = this; - if ( fxaction.shakeIgnoreMaster ) { - ignore_ent = GetBindMaster(); - } - } - // lookup the ent we are bound to? - gameLocal.RadiusPush( GetPhysics()->GetOrigin(), fxaction.shakeDistance, fxaction.shakeImpulse, this, ignore_ent, 1.0f, true ); - } - useAction->shakeStarted = true; - } - break; - } - case FX_ATTACHENTITY: - case FX_PARTICLE: - case FX_MODEL: { - if ( useAction->modelDefHandle == -1 ) { - memset( &useAction->renderEntity, 0, sizeof( renderEntity_t ) ); - useAction->renderEntity.origin = GetPhysics()->GetOrigin() + fxaction.offset; - useAction->renderEntity.axis = (fxaction.explicitAxis) ? fxaction.axis : GetPhysics()->GetAxis(); - useAction->renderEntity.hModel = renderModelManager->FindModel( fxaction.data ); - useAction->renderEntity.shaderParms[ SHADERPARM_RED ] = 1.0f; - useAction->renderEntity.shaderParms[ SHADERPARM_GREEN ] = 1.0f; - useAction->renderEntity.shaderParms[ SHADERPARM_BLUE ] = 1.0f; - useAction->renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( time ); - useAction->renderEntity.shaderParms[3] = 1.0f; - useAction->renderEntity.shaderParms[5] = 0.0f; - if ( useAction->renderEntity.hModel ) { - useAction->renderEntity.bounds = useAction->renderEntity.hModel->Bounds( &useAction->renderEntity ); - } - useAction->modelDefHandle = gameRenderWorld->AddEntityDef( &useAction->renderEntity ); - } else if ( fxaction.trackOrigin ) { - useAction->renderEntity.origin = GetPhysics()->GetOrigin() + fxaction.offset; - useAction->renderEntity.axis = fxaction.explicitAxis ? fxaction.axis : GetPhysics()->GetAxis(); -#ifdef _D3XP - gameRenderWorld->UpdateEntityDef( useAction->modelDefHandle, &useAction->renderEntity ); -#endif - } - ApplyFade( fxaction, *useAction, time, actualStart ); - break; - } - case FX_LAUNCH: { - if ( gameLocal.isClient ) { - // client never spawns entities outside of ClientReadSnapshot - useAction->launched = true; - break; - } - if ( !useAction->launched ) { - useAction->launched = true; - projectile = NULL; - // FIXME: may need to cache this if it is slow - projectileDef = gameLocal.FindEntityDefDict( fxaction.data, false ); - if ( !projectileDef ) { - gameLocal.Warning( "projectile \'%s\' not found", fxaction.data.c_str() ); - } else { - gameLocal.SpawnEntityDef( *projectileDef, &ent, false ); - if ( ent && ent->IsType( idProjectile::Type ) ) { - projectile = ( idProjectile * )ent; - projectile->Create( this, GetPhysics()->GetOrigin(), GetPhysics()->GetAxis()[0] ); - projectile->Launch( GetPhysics()->GetOrigin(), GetPhysics()->GetAxis()[0], vec3_origin ); - } - } - } - break; - } -#ifdef _D3XP - case FX_SHOCKWAVE: { - if ( gameLocal.isClient ) { - useAction->shakeStarted = true; - break; - } - if ( !useAction->shakeStarted ) { - idStr shockDefName; - useAction->shakeStarted = true; - - shockDefName = fxaction.data; - if ( !shockDefName.Length() ) { - shockDefName = "func_shockwave"; - } - - projectileDef = gameLocal.FindEntityDefDict( shockDefName, false ); - if ( !projectileDef ) { - gameLocal.Warning( "shockwave \'%s\' not found", shockDefName.c_str() ); - } else { - gameLocal.SpawnEntityDef( *projectileDef, &ent ); - ent->SetOrigin( GetPhysics()->GetOrigin() + fxaction.offset ); - ent->PostEventMS( &EV_Remove, ent->spawnArgs.GetInt( "duration" ) ); - } - } - break; - } -#endif - } - } -} - -/* -================ -idEntityFx::idEntityFx -================ -*/ -idEntityFx::idEntityFx() { - fxEffect = NULL; - started = -1; - nextTriggerTime = -1; - fl.networkSync = true; -} - -/* -================ -idEntityFx::~idEntityFx -================ -*/ -idEntityFx::~idEntityFx() { - CleanUp(); - fxEffect = NULL; -} - -/* -================ -idEntityFx::Spawn -================ -*/ -void idEntityFx::Spawn( void ) { - - if ( g_skipFX.GetBool() ) { - return; - } - - const char *fx; - nextTriggerTime = 0; - fxEffect = NULL; - if ( spawnArgs.GetString( "fx", "", &fx ) ) { - systemName = fx; - } - if ( !spawnArgs.GetBool( "triggered" ) ) { - Setup( fx ); - if ( spawnArgs.GetBool( "test" ) || spawnArgs.GetBool( "start" ) || spawnArgs.GetFloat ( "restart" ) ) { - PostEventMS( &EV_Activate, 0, this ); - } - } -} - -/* -================ -idEntityFx::Think - - Clears any visual fx started when {item,mob,player} was spawned -================ -*/ -void idEntityFx::Think( void ) { - if ( g_skipFX.GetBool() ) { - return; - } - - if ( thinkFlags & TH_THINK ) { - Run( gameLocal.time ); - } - - RunPhysics(); - Present(); -} - -/* -================ -idEntityFx::Event_ClearFx - - Clears any visual fx started when item(mob) was spawned -================ -*/ -void idEntityFx::Event_ClearFx( void ) { - - if ( g_skipFX.GetBool() ) { - return; - } - - Stop(); - CleanUp(); - BecomeInactive( TH_THINK ); - - if ( spawnArgs.GetBool("test") ) { - PostEventMS( &EV_Activate, 0, this ); - } else { - if ( spawnArgs.GetFloat( "restart" ) || !spawnArgs.GetBool( "triggered")) { - float rest = spawnArgs.GetFloat( "restart", "0" ); - if ( rest == 0.0f ) { - PostEventSec( &EV_Remove, 0.1f ); - } else { - rest *= gameLocal.random.RandomFloat(); - PostEventSec( &EV_Activate, rest, this ); - } - } - } -} - -/* -================ -idEntityFx::Event_Trigger -================ -*/ -void idEntityFx::Event_Trigger( idEntity *activator ) { - - if ( g_skipFX.GetBool() ) { - return; - } - - float fxActionDelay; - const char *fx; - - if ( gameLocal.time < nextTriggerTime ) { - return; - } - - if ( spawnArgs.GetString( "fx", "", &fx) ) { - Setup( fx ); - Start( gameLocal.time ); - PostEventMS( &EV_Fx_KillFx, Duration() ); - BecomeActive( TH_THINK ); - } - - fxActionDelay = spawnArgs.GetFloat( "fxActionDelay" ); - if ( fxActionDelay != 0.0f ) { - nextTriggerTime = gameLocal.time + SEC2MS( fxActionDelay ); - } else { - // prevent multiple triggers on same frame - nextTriggerTime = gameLocal.time + 1; - } - PostEventSec( &EV_Fx_Action, fxActionDelay, activator ); -} - - -/* -================ -idEntityFx::StartFx -================ -*/ -idEntityFx *idEntityFx::StartFx( const char *fx, const idVec3 *useOrigin, const idMat3 *useAxis, idEntity *ent, bool bind ) { - - if ( g_skipFX.GetBool() || !fx || !*fx ) { - return NULL; - } - - idDict args; - args.SetBool( "start", true ); - args.Set( "fx", fx ); - idEntityFx *nfx = static_cast( gameLocal.SpawnEntityType( idEntityFx::Type, &args ) ); - if ( nfx->Joint() && *nfx->Joint() ) { - nfx->BindToJoint( ent, nfx->Joint(), true ); - nfx->SetOrigin( vec3_origin ); - } else { - nfx->SetOrigin( (useOrigin) ? *useOrigin : ent->GetPhysics()->GetOrigin() ); - nfx->SetAxis( (useAxis) ? *useAxis : ent->GetPhysics()->GetAxis() ); - } - - if ( bind ) { - // never bind to world spawn - if ( ent != gameLocal.world ) { - nfx->Bind( ent, true ); - } - } - nfx->Show(); - return nfx; -} - -/* -================= -idEntityFx::WriteToSnapshot -================= -*/ -void idEntityFx::WriteToSnapshot( idBitMsgDelta &msg ) const { - GetPhysics()->WriteToSnapshot( msg ); - WriteBindToSnapshot( msg ); - msg.WriteInt( ( fxEffect != NULL ) ? gameLocal.ServerRemapDecl( -1, DECL_FX, fxEffect->Index() ) : -1 ); - msg.WriteInt( started ); -} - -/* -================= -idEntityFx::ReadFromSnapshot -================= -*/ -void idEntityFx::ReadFromSnapshot( const idBitMsgDelta &msg ) { - int fx_index, start_time, max_lapse; - - GetPhysics()->ReadFromSnapshot( msg ); - ReadBindFromSnapshot( msg ); - fx_index = gameLocal.ClientRemapDecl( DECL_FX, msg.ReadInt() ); - start_time = msg.ReadInt(); - - if ( fx_index != -1 && start_time > 0 && !fxEffect && started < 0 ) { - spawnArgs.GetInt( "effect_lapse", "1000", max_lapse ); - if ( gameLocal.time - start_time > max_lapse ) { - // too late, skip the effect completely - started = 0; - return; - } - const idDeclFX *fx = static_cast( declManager->DeclByIndex( DECL_FX, fx_index ) ); - if ( !fx ) { - gameLocal.Error( "FX at index %d not found", fx_index ); - } - fxEffect = fx; - Setup( fx->GetName() ); - Start( start_time ); - } -} - -/* -================= -idEntityFx::ClientPredictionThink -================= -*/ -void idEntityFx::ClientPredictionThink( void ) { - if ( gameLocal.isNewFrame ) { - Run( gameLocal.time ); - } - RunPhysics(); - Present(); -} - -/* -=============================================================================== - - idTeleporter - -=============================================================================== -*/ - -CLASS_DECLARATION( idEntityFx, idTeleporter ) - EVENT( EV_Fx_Action, idTeleporter::Event_DoAction ) -END_CLASS - -/* -================ -idTeleporter::Event_DoAction -================ -*/ -void idTeleporter::Event_DoAction( idEntity *activator ) { - idAngles a( 0, spawnArgs.GetFloat( "angle" ), 0 ); - activator->Teleport( GetPhysics()->GetOrigin(), a, NULL ); -} diff --git a/d3xp/Fx.h b/d3xp/Fx.h deleted file mode 100644 index bb992254..00000000 --- a/d3xp/Fx.h +++ /dev/null @@ -1,110 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __GAME_FX_H__ -#define __GAME_FX_H__ - -#include "renderer/RenderWorld.h" - -#include "Entity.h" - -/* -=============================================================================== - - Special effects. - -=============================================================================== -*/ - -typedef struct { - renderLight_t renderLight; // light presented to the renderer - qhandle_t lightDefHandle; // handle to renderer light def - renderEntity_t renderEntity; // used to present a model to the renderer - int modelDefHandle; // handle to static renderer model - float delay; - int particleSystem; - int start; - bool soundStarted; - bool shakeStarted; - bool decalDropped; - bool launched; -} idFXLocalAction; - -class idEntityFx : public idEntity { -public: - CLASS_PROTOTYPE( idEntityFx ); - - idEntityFx(); - virtual ~idEntityFx(); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - virtual void Think(); - void Setup( const char *fx ); - void Run( int time ); - void Start( int time ); - void Stop( void ); - const int Duration( void ); - const char * EffectName( void ); - const char * Joint( void ); - const bool Done(); - - virtual void WriteToSnapshot( idBitMsgDelta &msg ) const; - virtual void ReadFromSnapshot( const idBitMsgDelta &msg ); - virtual void ClientPredictionThink( void ); - - static idEntityFx * StartFx( const char *fx, const idVec3 *useOrigin, const idMat3 *useAxis, idEntity *ent, bool bind ); - -protected: - void Event_Trigger( idEntity *activator ); - void Event_ClearFx( void ); - - void CleanUp( void ); - void CleanUpSingleAction( const idFXSingleAction& fxaction, idFXLocalAction& laction ); - void ApplyFade( const idFXSingleAction& fxaction, idFXLocalAction& laction, const int time, const int actualStart ); - - int started; - int nextTriggerTime; - const idDeclFX * fxEffect; // GetFX() should be called before using fxEffect as a pointer - idList actions; - idStr systemName; -}; - -class idTeleporter : public idEntityFx { -public: - CLASS_PROTOTYPE( idTeleporter ); - -private: - // teleporters to this location - void Event_DoAction( idEntity *activator ); -}; - -#endif /* !__GAME_FX_H__ */ diff --git a/d3xp/GameBase.h b/d3xp/GameBase.h deleted file mode 100644 index 9ff3a4ab..00000000 --- a/d3xp/GameBase.h +++ /dev/null @@ -1,81 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __GAMEBASE_H__ -#define __GAMEBASE_H__ - -// default scripts -#define SCRIPT_DEFAULTDEFS "script/doom_defs.script" -#define SCRIPT_DEFAULT "script/doom_main.script" -#define SCRIPT_DEFAULTFUNC "doom_main" - -#define TIME_GROUP1 0 -#define TIME_GROUP2 1 - -#define LAGO_IMG_WIDTH 64 -#define LAGO_IMG_HEIGHT 64 -#define LAGO_WIDTH 64 -#define LAGO_HEIGHT 44 -#define LAGO_MATERIAL "textures/sfx/lagometer" -#define LAGO_IMAGE "textures/sfx/lagometer.tga" - -// if set to 1 the server sends the client PVS with snapshots and the client compares against what it sees -#ifndef ASYNC_WRITE_PVS - #define ASYNC_WRITE_PVS 0 -#endif - -// the "gameversion" client command will print this plus compile date -#define GAME_VERSION "baseDOOM-1" - -#define MAX_CLIENTS 32 -#define GENTITYNUM_BITS 12 -#define MAX_GENTITIES (1<>5) - -// content masks -#define MASK_ALL (-1) -#define MASK_SOLID (CONTENTS_SOLID) -#define MASK_MONSTERSOLID (CONTENTS_SOLID|CONTENTS_MONSTERCLIP|CONTENTS_BODY) -#define MASK_PLAYERSOLID (CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_BODY) -#define MASK_DEADSOLID (CONTENTS_SOLID|CONTENTS_PLAYERCLIP) -#define MASK_WATER (CONTENTS_WATER) -#define MASK_OPAQUE (CONTENTS_OPAQUE) -#define MASK_SHOT_RENDERMODEL (CONTENTS_SOLID|CONTENTS_RENDERMODEL) -#define MASK_SHOT_BOUNDINGBOX (CONTENTS_SOLID|CONTENTS_BODY) - -#define DEFAULT_GRAVITY_STRING "1066" - -extern void gameError( const char *fmt, ... ); - -#endif diff --git a/d3xp/GameEdit.cpp b/d3xp/GameEdit.cpp deleted file mode 100644 index 0c637bdb..00000000 --- a/d3xp/GameEdit.cpp +++ /dev/null @@ -1,1148 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "gamesys/SysCvar.h" -#include "physics/Physics_Monster.h" -#include "ai/AI.h" -#include "Player.h" -#include "Light.h" -#include "WorldSpawn.h" -#include "Sound.h" -#include "Misc.h" - -#include "GameEdit.h" - -/* -=============================================================================== - - Ingame cursor. - -=============================================================================== -*/ - -CLASS_DECLARATION( idEntity, idCursor3D ) -END_CLASS - -/* -=============== -idCursor3D::idCursor3D -=============== -*/ -idCursor3D::idCursor3D( void ) { - draggedPosition.Zero(); -} - -/* -=============== -idCursor3D::~idCursor3D -=============== -*/ -idCursor3D::~idCursor3D( void ) { -} - -/* -=============== -idCursor3D::Spawn -=============== -*/ -void idCursor3D::Spawn( void ) { -} - -/* -=============== -idCursor3D::Present -=============== -*/ -void idCursor3D::Present( void ) { - // don't present to the renderer if the entity hasn't changed - if ( !( thinkFlags & TH_UPDATEVISUALS ) ) { - return; - } - BecomeInactive( TH_UPDATEVISUALS ); - - const idVec3 &origin = GetPhysics()->GetOrigin(); - const idMat3 &axis = GetPhysics()->GetAxis(); - gameRenderWorld->DebugArrow( colorYellow, origin + axis[1] * -5.0f + axis[2] * 5.0f, origin, 2 ); - gameRenderWorld->DebugArrow( colorRed, origin, draggedPosition, 2 ); -} - -/* -=============== -idCursor3D::Think -=============== -*/ -void idCursor3D::Think( void ) { - if ( thinkFlags & TH_THINK ) { - drag.Evaluate( gameLocal.time ); - } - Present(); -} - - -/* -=============================================================================== - - Allows entities to be dragged through the world with physics. - -=============================================================================== -*/ - -#define MAX_DRAG_TRACE_DISTANCE 2048.0f - -/* -============== -idDragEntity::idDragEntity -============== -*/ -idDragEntity::idDragEntity( void ) { - cursor = NULL; - Clear(); -} - -/* -============== -idDragEntity::~idDragEntity -============== -*/ -idDragEntity::~idDragEntity( void ) { - StopDrag(); - selected = NULL; - delete cursor; - cursor = NULL; -} - - -/* -============== -idDragEntity::Clear -============== -*/ -void idDragEntity::Clear() { - dragEnt = NULL; - joint = INVALID_JOINT; - id = 0; - localEntityPoint.Zero(); - localPlayerPoint.Zero(); - bodyName.Clear(); - selected = NULL; -} - -/* -============== -idDragEntity::StopDrag -============== -*/ -void idDragEntity::StopDrag( void ) { - dragEnt = NULL; - if ( cursor ) { - cursor->BecomeInactive( TH_THINK ); - } -} - -/* -============== -idDragEntity::Update -============== -*/ -void idDragEntity::Update( idPlayer *player ) { - idVec3 viewPoint, origin; - idMat3 viewAxis, axis; - trace_t trace; - idEntity *newEnt; - idAngles angles; - jointHandle_t newJoint; - idStr newBodyName; - - player->GetViewPos( viewPoint, viewAxis ); - - // if no entity selected for dragging - if ( !dragEnt.GetEntity() ) { - - if ( player->usercmd.buttons & BUTTON_ATTACK ) { - - gameLocal.clip.TracePoint( trace, viewPoint, viewPoint + viewAxis[0] * MAX_DRAG_TRACE_DISTANCE, (CONTENTS_SOLID|CONTENTS_RENDERMODEL|CONTENTS_BODY), player ); - if ( trace.fraction < 1.0f ) { - - newEnt = gameLocal.entities[ trace.c.entityNum ]; - if ( newEnt ) { - - if ( newEnt->GetBindMaster() ) { - if ( newEnt->GetBindJoint() ) { - trace.c.id = JOINT_HANDLE_TO_CLIPMODEL_ID( newEnt->GetBindJoint() ); - } else { - trace.c.id = newEnt->GetBindBody(); - } - newEnt = newEnt->GetBindMaster(); - } - - if ( newEnt->IsType( idAFEntity_Base::Type ) && static_cast(newEnt)->IsActiveAF() ) { - idAFEntity_Base *af = static_cast(newEnt); - - // joint being dragged - newJoint = CLIPMODEL_ID_TO_JOINT_HANDLE( trace.c.id ); - // get the body id from the trace model id which might be a joint handle - trace.c.id = af->BodyForClipModelId( trace.c.id ); - // get the name of the body being dragged - newBodyName = af->GetAFPhysics()->GetBody( trace.c.id )->GetName(); - - } else if ( !newEnt->IsType( idWorldspawn::Type ) ) { - - if ( trace.c.id < 0 ) { - newJoint = CLIPMODEL_ID_TO_JOINT_HANDLE( trace.c.id ); - } else { - newJoint = INVALID_JOINT; - } - newBodyName = ""; - - } else { - - newJoint = INVALID_JOINT; - newEnt = NULL; - } - } - if ( newEnt ) { - dragEnt = newEnt; - selected = newEnt; - joint = newJoint; - id = trace.c.id; - bodyName = newBodyName; - - if ( !cursor ) { - cursor = ( idCursor3D * )gameLocal.SpawnEntityType( idCursor3D::Type ); - } - - idPhysics *phys = dragEnt.GetEntity()->GetPhysics(); - localPlayerPoint = ( trace.c.point - viewPoint ) * viewAxis.Transpose(); - origin = phys->GetOrigin( id ); - axis = phys->GetAxis( id ); - localEntityPoint = ( trace.c.point - origin ) * axis.Transpose(); - - cursor->drag.Init( g_dragDamping.GetFloat() ); - cursor->drag.SetPhysics( phys, id, localEntityPoint ); - cursor->Show(); - - if ( phys->IsType( idPhysics_AF::Type ) || - phys->IsType( idPhysics_RigidBody::Type ) || - phys->IsType( idPhysics_Monster::Type ) ) { - cursor->BecomeActive( TH_THINK ); - } - } - } - } - } - - // if there is an entity selected for dragging - idEntity *drag = dragEnt.GetEntity(); - if ( drag ) { - - if ( !( player->usercmd.buttons & BUTTON_ATTACK ) ) { - StopDrag(); - return; - } - - cursor->SetOrigin( viewPoint + localPlayerPoint * viewAxis ); - cursor->SetAxis( viewAxis ); - - cursor->drag.SetDragPosition( cursor->GetPhysics()->GetOrigin() ); - - renderEntity_t *renderEntity = drag->GetRenderEntity(); - idAnimator *dragAnimator = drag->GetAnimator(); - - if ( joint != INVALID_JOINT && renderEntity && dragAnimator ) { - dragAnimator->GetJointTransform( joint, gameLocal.time, cursor->draggedPosition, axis ); - cursor->draggedPosition = renderEntity->origin + cursor->draggedPosition * renderEntity->axis; - gameRenderWorld->DrawText( va( "%s\n%s\n%s, %s", drag->GetName(), drag->GetType()->classname, dragAnimator->GetJointName( joint ), bodyName.c_str() ), cursor->GetPhysics()->GetOrigin(), 0.1f, colorWhite, viewAxis, 1 ); - } else { - cursor->draggedPosition = cursor->GetPhysics()->GetOrigin(); - gameRenderWorld->DrawText( va( "%s\n%s\n%s", drag->GetName(), drag->GetType()->classname, bodyName.c_str() ), cursor->GetPhysics()->GetOrigin(), 0.1f, colorWhite, viewAxis, 1 ); - } - } - - // if there is a selected entity - if ( selected.GetEntity() && g_dragShowSelection.GetBool() ) { - // draw the bbox of the selected entity - renderEntity_t *renderEntity = selected.GetEntity()->GetRenderEntity(); - if ( renderEntity ) { - gameRenderWorld->DebugBox( colorYellow, idBox( renderEntity->bounds, renderEntity->origin, renderEntity->axis ) ); - } - } -} - -/* -============== -idDragEntity::SetSelected -============== -*/ -void idDragEntity::SetSelected( idEntity *ent ) { - selected = ent; - StopDrag(); -} - -/* -============== -idDragEntity::DeleteSelected -============== -*/ -void idDragEntity::DeleteSelected( void ) { - delete selected.GetEntity(); - selected = NULL; - StopDrag(); -} - -/* -============== -idDragEntity::BindSelected -============== -*/ -void idDragEntity::BindSelected( void ) { - int num, largestNum; - idLexer lexer; - idToken type, bodyName; - idStr key, value, bindBodyName; - const idKeyValue *kv; - idAFEntity_Base *af; - - af = static_cast(dragEnt.GetEntity()); - - if ( !af || !af->IsType( idAFEntity_Base::Type ) || !af->IsActiveAF() ) { - return; - } - - bindBodyName = af->GetAFPhysics()->GetBody( id )->GetName(); - largestNum = 1; - - // parse all the bind constraints - kv = af->spawnArgs.MatchPrefix( "bindConstraint ", NULL ); - while ( kv ) { - key = kv->GetKey(); - key.Strip( "bindConstraint " ); - if ( sscanf( key, "bind%d", &num ) ) { - if ( num >= largestNum ) { - largestNum = num + 1; - } - } - - lexer.LoadMemory( kv->GetValue(), kv->GetValue().Length(), kv->GetKey() ); - lexer.ReadToken( &type ); - lexer.ReadToken( &bodyName ); - lexer.FreeSource(); - - // if there already exists a bind constraint for this body - if ( bodyName.Icmp( bindBodyName ) == 0 ) { - // delete the bind constraint - af->spawnArgs.Delete( kv->GetKey() ); - kv = NULL; - } - - kv = af->spawnArgs.MatchPrefix( "bindConstraint ", kv ); - } - - sprintf( key, "bindConstraint bind%d", largestNum ); - sprintf( value, "ballAndSocket %s %s", bindBodyName.c_str(), af->GetAnimator()->GetJointName( joint ) ); - - af->spawnArgs.Set( key, value ); - af->spawnArgs.Set( "bind", "worldspawn" ); - af->Bind( gameLocal.world, true ); -} - -/* -============== -idDragEntity::UnbindSelected -============== -*/ -void idDragEntity::UnbindSelected( void ) { - const idKeyValue *kv; - idAFEntity_Base *af; - - af = static_cast(selected.GetEntity()); - - if ( !af || !af->IsType( idAFEntity_Base::Type ) || !af->IsActiveAF() ) { - return; - } - - // unbind the selected entity - af->Unbind(); - - // delete all the bind constraints - kv = selected.GetEntity()->spawnArgs.MatchPrefix( "bindConstraint ", NULL ); - while ( kv ) { - selected.GetEntity()->spawnArgs.Delete( kv->GetKey() ); - kv = selected.GetEntity()->spawnArgs.MatchPrefix( "bindConstraint ", NULL ); - } - - // delete any bind information - af->spawnArgs.Delete( "bind" ); - af->spawnArgs.Delete( "bindToJoint" ); - af->spawnArgs.Delete( "bindToBody" ); -} - - -/* -=============================================================================== - - Handles ingame entity editing. - -=============================================================================== -*/ - -/* -============== -idEditEntities::idEditEntities -============== -*/ -idEditEntities::idEditEntities( void ) { - selectableEntityClasses.Clear(); - nextSelectTime = 0; -} - -/* -============= -idEditEntities::SelectEntity -============= -*/ -bool idEditEntities::SelectEntity( const idVec3 &origin, const idVec3 &dir, const idEntity *skip ) { - idVec3 end; - idEntity *ent; - - if ( !g_editEntityMode.GetInteger() || selectableEntityClasses.Num() == 0 ) { - return false; - } - - if ( gameLocal.time < nextSelectTime ) { - return true; - } - nextSelectTime = gameLocal.time + 300; - - end = origin + dir * 4096.0f; - - ent = NULL; - for ( int i = 0; i < selectableEntityClasses.Num(); i++ ) { - ent = gameLocal.FindTraceEntity( origin, end, *selectableEntityClasses[i].typeInfo, skip ); - if ( ent ) { - break; - } - } - if ( ent ) { - ClearSelectedEntities(); - if ( EntityIsSelectable( ent ) ) { - AddSelectedEntity( ent ); - gameLocal.Printf( "entity #%d: %s '%s'\n", ent->entityNumber, ent->GetClassname(), ent->name.c_str() ); - ent->ShowEditingDialog(); - return true; - } - } - return false; -} - -/* -============= -idEditEntities::AddSelectedEntity -============= -*/ -void idEditEntities::AddSelectedEntity(idEntity *ent) { - ent->fl.selected = true; - selectedEntities.AddUnique(ent); -} - -/* -============== -idEditEntities::RemoveSelectedEntity -============== -*/ -void idEditEntities::RemoveSelectedEntity( idEntity *ent ) { - if ( selectedEntities.Find( ent ) ) { - selectedEntities.Remove( ent ); - } -} - -/* -============= -idEditEntities::ClearSelectedEntities -============= -*/ -void idEditEntities::ClearSelectedEntities() { - int i, count; - - count = selectedEntities.Num(); - for ( i = 0; i < count; i++ ) { - selectedEntities[i]->fl.selected = false; - } - selectedEntities.Clear(); -} - - -/* -============= -idEditEntities::EntityIsSelectable -============= -*/ -bool idEditEntities::EntityIsSelectable( idEntity *ent, idVec4 *color, idStr *text ) { - for ( int i = 0; i < selectableEntityClasses.Num(); i++ ) { - if ( ent->GetType() == selectableEntityClasses[i].typeInfo ) { - if ( text ) { - *text = selectableEntityClasses[i].textKey; - } - if ( color ) { - if ( ent->fl.selected ) { - *color = colorRed; - } else { - switch( i ) { - case 1 : - *color = colorYellow; - break; - case 2 : - *color = colorBlue; - break; - default: - *color = colorGreen; - } - } - } - return true; - } - } - return false; -} - -/* -============= -idEditEntities::DisplayEntities -============= -*/ -void idEditEntities::DisplayEntities( void ) { - idEntity *ent; - - if ( !gameLocal.GetLocalPlayer() ) { - return; - } - - selectableEntityClasses.Clear(); - selectedTypeInfo_t sit; - - switch( g_editEntityMode.GetInteger() ) { - case 1: - sit.typeInfo = &idLight::Type; - sit.textKey = "texture"; - selectableEntityClasses.Append( sit ); - break; - case 2: - sit.typeInfo = &idSound::Type; - sit.textKey = "s_shader"; - selectableEntityClasses.Append( sit ); - sit.typeInfo = &idLight::Type; - sit.textKey = "texture"; - selectableEntityClasses.Append( sit ); - break; - case 3: - sit.typeInfo = &idAFEntity_Base::Type; - sit.textKey = "articulatedFigure"; - selectableEntityClasses.Append( sit ); - break; - case 4: - sit.typeInfo = &idFuncEmitter::Type; - sit.textKey = "model"; - selectableEntityClasses.Append( sit ); - break; - case 5: - sit.typeInfo = &idAI::Type; - sit.textKey = "name"; - selectableEntityClasses.Append( sit ); - break; - case 6: - sit.typeInfo = &idEntity::Type; - sit.textKey = "name"; - selectableEntityClasses.Append( sit ); - break; - case 7: - sit.typeInfo = &idEntity::Type; - sit.textKey = "model"; - selectableEntityClasses.Append( sit ); - break; - default: - return; - } - - idBounds viewBounds( gameLocal.GetLocalPlayer()->GetPhysics()->GetOrigin() ); - idBounds viewTextBounds( gameLocal.GetLocalPlayer()->GetPhysics()->GetOrigin() ); - idMat3 axis = gameLocal.GetLocalPlayer()->viewAngles.ToMat3(); - - viewBounds.ExpandSelf( 512 ); - viewTextBounds.ExpandSelf( 128 ); - - idStr textKey; - - for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) { - - idVec4 color; - - textKey = ""; - if ( !EntityIsSelectable( ent, &color, &textKey ) ) { - continue; - } - - bool drawArrows = false; - if ( ent->GetType() == &idAFEntity_Base::Type ) { - if ( !static_cast(ent)->IsActiveAF() ) { - continue; - } - } else if ( ent->GetType() == &idSound::Type ) { - if ( ent->fl.selected ) { - drawArrows = true; - } - const idSoundShader * ss = declManager->FindSound( ent->spawnArgs.GetString( textKey ) ); - if ( ss->HasDefaultSound() || ss->base->GetState() == DS_DEFAULTED ) { - color.Set( 1.0f, 0.0f, 1.0f, 1.0f ); - } - } else if ( ent->GetType() == &idFuncEmitter::Type ) { - if ( ent->fl.selected ) { - drawArrows = true; - } - } - - if ( !viewBounds.ContainsPoint( ent->GetPhysics()->GetOrigin() ) ) { - continue; - } - - gameRenderWorld->DebugBounds( color, idBounds( ent->GetPhysics()->GetOrigin() ).Expand( 8 ) ); - if ( drawArrows ) { - idVec3 start = ent->GetPhysics()->GetOrigin(); - idVec3 end = start + idVec3( 1, 0, 0 ) * 20.0f; - gameRenderWorld->DebugArrow( colorWhite, start, end, 2 ); - gameRenderWorld->DrawText( "x+", end + idVec3( 4, 0, 0 ), 0.15f, colorWhite, axis ); - end = start + idVec3( 1, 0, 0 ) * -20.0f; - gameRenderWorld->DebugArrow( colorWhite, start, end, 2 ); - gameRenderWorld->DrawText( "x-", end + idVec3( -4, 0, 0 ), 0.15f, colorWhite, axis ); - end = start + idVec3( 0, 1, 0 ) * +20.0f; - gameRenderWorld->DebugArrow( colorGreen, start, end, 2 ); - gameRenderWorld->DrawText( "y+", end + idVec3( 0, 4, 0 ), 0.15f, colorWhite, axis ); - end = start + idVec3( 0, 1, 0 ) * -20.0f; - gameRenderWorld->DebugArrow( colorGreen, start, end, 2 ); - gameRenderWorld->DrawText( "y-", end + idVec3( 0, -4, 0 ), 0.15f, colorWhite, axis ); - end = start + idVec3( 0, 0, 1 ) * +20.0f; - gameRenderWorld->DebugArrow( colorBlue, start, end, 2 ); - gameRenderWorld->DrawText( "z+", end + idVec3( 0, 0, 4 ), 0.15f, colorWhite, axis ); - end = start + idVec3( 0, 0, 1 ) * -20.0f; - gameRenderWorld->DebugArrow( colorBlue, start, end, 2 ); - gameRenderWorld->DrawText( "z-", end + idVec3( 0, 0, -4 ), 0.15f, colorWhite, axis ); - } - - if ( textKey.Length() ) { - const char *text = ent->spawnArgs.GetString( textKey ); - if ( viewTextBounds.ContainsPoint( ent->GetPhysics()->GetOrigin() ) ) { - gameRenderWorld->DrawText( text, ent->GetPhysics()->GetOrigin() + idVec3(0, 0, 12), 0.25, colorWhite, axis, 1 ); - } - } - } -} - - -/* -=============================================================================== - - idGameEdit - -=============================================================================== -*/ - -idGameEdit gameEditLocal; -idGameEdit * gameEdit = &gameEditLocal; - - -/* -============= -idGameEdit::GetSelectedEntities -============= -*/ -int idGameEdit::GetSelectedEntities( idEntity *list[], int max ) { - int num = 0; - idEntity *ent; - - for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) { - if ( ent->fl.selected ) { - list[num++] = ent; - if ( num >= max ) { - break; - } - } - } - return num; -} - -/* -============= -idGameEdit::TriggerSelected -============= -*/ -void idGameEdit::TriggerSelected() { - idEntity *ent; - for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) { - if ( ent->fl.selected ) { - ent->ProcessEvent( &EV_Activate, gameLocal.GetLocalPlayer() ); - } - } -} - -/* -================ -idGameEdit::ClearEntitySelection -================ -*/ -void idGameEdit::ClearEntitySelection() { - idEntity *ent; - - for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) { - ent->fl.selected = false; - } - gameLocal.editEntities->ClearSelectedEntities(); -} - -/* -================ -idGameEdit::AddSelectedEntity -================ -*/ -void idGameEdit::AddSelectedEntity( idEntity *ent ) { - if ( ent ) { - gameLocal.editEntities->AddSelectedEntity( ent ); - } -} - -/* -================ -idGameEdit::FindEntityDefDict -================ -*/ -const idDict *idGameEdit::FindEntityDefDict( const char *name, bool makeDefault ) const { - return gameLocal.FindEntityDefDict( name, makeDefault ); -} - -/* -================ -idGameEdit::SpawnEntityDef -================ -*/ -void idGameEdit::SpawnEntityDef( const idDict &args, idEntity **ent ) { - gameLocal.SpawnEntityDef( args, ent ); -} - -/* -================ -idGameEdit::FindEntity -================ -*/ -idEntity *idGameEdit::FindEntity( const char *name ) const { - return gameLocal.FindEntity( name ); -} - -/* -============= -idGameEdit::GetUniqueEntityName - -generates a unique name for a given classname -============= -*/ -const char *idGameEdit::GetUniqueEntityName( const char *classname ) const { - int id; - static char name[1024]; - - // can only have MAX_GENTITIES, so if we have a spot available, we're guaranteed to find one - for( id = 0; id < MAX_GENTITIES; id++ ) { - idStr::snPrintf( name, sizeof( name ), "%s_%d", classname, id ); - if ( !gameLocal.FindEntity( name ) ) { - return name; - } - } - - // id == MAX_GENTITIES + 1, which can't be in use if we get here - idStr::snPrintf( name, sizeof( name ), "%s_%d", classname, id ); - return name; -} - -/* -================ -idGameEdit::EntityGetOrigin -================ -*/ -void idGameEdit::EntityGetOrigin( idEntity *ent, idVec3 &org ) const { - if ( ent ) { - org = ent->GetPhysics()->GetOrigin(); - } -} - -/* -================ -idGameEdit::EntityGetAxis -================ -*/ -void idGameEdit::EntityGetAxis( idEntity *ent, idMat3 &axis ) const { - if ( ent ) { - axis = ent->GetPhysics()->GetAxis(); - } -} - -/* -================ -idGameEdit::EntitySetOrigin -================ -*/ -void idGameEdit::EntitySetOrigin( idEntity *ent, const idVec3 &org ) { - if ( ent ) { - ent->SetOrigin( org ); - } -} - -/* -================ -idGameEdit::EntitySetAxis -================ -*/ -void idGameEdit::EntitySetAxis( idEntity *ent, const idMat3 &axis ) { - if ( ent ) { - ent->SetAxis( axis ); - } -} - -/* -================ -idGameEdit::EntitySetColor -================ -*/ -void idGameEdit::EntitySetColor( idEntity *ent, const idVec3 color ) { - if ( ent ) { - ent->SetColor( color ); - } -} - -/* -================ -idGameEdit::EntityTranslate -================ -*/ -void idGameEdit::EntityTranslate( idEntity *ent, const idVec3 &org ) { - if ( ent ) { - ent->GetPhysics()->Translate( org ); - } -} - -/* -================ -idGameEdit::EntityGetSpawnArgs -================ -*/ -const idDict *idGameEdit::EntityGetSpawnArgs( idEntity *ent ) const { - if ( ent ) { - return &ent->spawnArgs; - } - return NULL; -} - -/* -================ -idGameEdit::EntityUpdateChangeableSpawnArgs -================ -*/ -void idGameEdit::EntityUpdateChangeableSpawnArgs( idEntity *ent, const idDict *dict ) { - if ( ent ) { - ent->UpdateChangeableSpawnArgs( dict ); - } -} - -/* -================ -idGameEdit::EntityChangeSpawnArgs -================ -*/ -void idGameEdit::EntityChangeSpawnArgs( idEntity *ent, const idDict *newArgs ) { - if ( ent ) { - for ( int i = 0 ; i < newArgs->GetNumKeyVals () ; i ++ ) { - const idKeyValue *kv = newArgs->GetKeyVal( i ); - - if ( kv->GetValue().Length() > 0 ) { - ent->spawnArgs.Set ( kv->GetKey() ,kv->GetValue() ); - } else { - ent->spawnArgs.Delete ( kv->GetKey() ); - } - } - } -} - -/* -================ -idGameEdit::EntityUpdateVisuals -================ -*/ -void idGameEdit::EntityUpdateVisuals( idEntity *ent ) { - if ( ent ) { - ent->UpdateVisuals(); - } -} - -/* -================ -idGameEdit::EntitySetModel -================ -*/ -void idGameEdit::EntitySetModel( idEntity *ent, const char *val ) { - if ( ent ) { - ent->spawnArgs.Set( "model", val ); - ent->SetModel( val ); - } -} - -/* -================ -idGameEdit::EntityStopSound -================ -*/ -void idGameEdit::EntityStopSound( idEntity *ent ) { - if ( ent ) { - ent->StopSound( SND_CHANNEL_ANY, false ); - } -} - -/* -================ -idGameEdit::EntityDelete -================ -*/ -void idGameEdit::EntityDelete( idEntity *ent ) { - delete ent; -} - -/* -================ -idGameEdit::PlayerIsValid -================ -*/ -bool idGameEdit::PlayerIsValid() const { - return ( gameLocal.GetLocalPlayer() != NULL ); -} - -/* -================ -idGameEdit::PlayerGetOrigin -================ -*/ -void idGameEdit::PlayerGetOrigin( idVec3 &org ) const { - org = gameLocal.GetLocalPlayer()->GetPhysics()->GetOrigin(); -} - -/* -================ -idGameEdit::PlayerGetAxis -================ -*/ -void idGameEdit::PlayerGetAxis( idMat3 &axis ) const { - axis = gameLocal.GetLocalPlayer()->GetPhysics()->GetAxis(); -} - -/* -================ -idGameEdit::PlayerGetViewAngles -================ -*/ -void idGameEdit::PlayerGetViewAngles( idAngles &angles ) const { - angles = gameLocal.GetLocalPlayer()->viewAngles; -} - -/* -================ -idGameEdit::PlayerGetEyePosition -================ -*/ -void idGameEdit::PlayerGetEyePosition( idVec3 &org ) const { - org = gameLocal.GetLocalPlayer()->GetEyePosition(); -} - - -/* -================ -idGameEdit::MapGetEntityDict -================ -*/ -const idDict *idGameEdit::MapGetEntityDict( const char *name ) const { - idMapFile *mapFile = gameLocal.GetLevelMap(); - if ( mapFile && name && *name ) { - idMapEntity *mapent = mapFile->FindEntity( name ); - if ( mapent ) { - return &mapent->epairs; - } - } - return NULL; -} - -/* -================ -idGameEdit::MapSave -================ -*/ -void idGameEdit::MapSave( const char *path ) const { - idMapFile *mapFile = gameLocal.GetLevelMap(); - if (mapFile) { - mapFile->Write( (path) ? path : mapFile->GetName(), ".map"); - } -} - -/* -================ -idGameEdit::MapSetEntityKeyVal -================ -*/ -void idGameEdit::MapSetEntityKeyVal( const char *name, const char *key, const char *val ) const { - idMapFile *mapFile = gameLocal.GetLevelMap(); - if ( mapFile && name && *name ) { - idMapEntity *mapent = mapFile->FindEntity( name ); - if ( mapent ) { - mapent->epairs.Set( key, val ); - } - } -} - -/* -================ -idGameEdit::MapCopyDictToEntity -================ -*/ -void idGameEdit::MapCopyDictToEntity( const char *name, const idDict *dict ) const { - idMapFile *mapFile = gameLocal.GetLevelMap(); - if ( mapFile && name && *name ) { - idMapEntity *mapent = mapFile->FindEntity( name ); - if ( mapent ) { - for ( int i = 0; i < dict->GetNumKeyVals(); i++ ) { - const idKeyValue *kv = dict->GetKeyVal( i ); - const char *key = kv->GetKey(); - const char *val = kv->GetValue(); - mapent->epairs.Set( key, val ); - } - } - } -} - - - -/* -================ -idGameEdit::MapGetUniqueMatchingKeyVals -================ -*/ -int idGameEdit::MapGetUniqueMatchingKeyVals( const char *key, const char *list[], int max ) const { - idMapFile *mapFile = gameLocal.GetLevelMap(); - int count = 0; - if ( mapFile ) { - for ( int i = 0; i < mapFile->GetNumEntities(); i++ ) { - idMapEntity *ent = mapFile->GetEntity( i ); - if ( ent ) { - const char *k = ent->epairs.GetString( key ); - if ( k && *k && count < max ) { - list[count++] = k; - } - } - } - } - return count; -} - -/* -================ -idGameEdit::MapAddEntity -================ -*/ -void idGameEdit::MapAddEntity( const idDict *dict ) const { - idMapFile *mapFile = gameLocal.GetLevelMap(); - if ( mapFile ) { - idMapEntity *ent = new idMapEntity(); - ent->epairs = *dict; - mapFile->AddEntity( ent ); - } -} - -/* -================ -idGameEdit::MapRemoveEntity -================ -*/ -void idGameEdit::MapRemoveEntity( const char *name ) const { - idMapFile *mapFile = gameLocal.GetLevelMap(); - if ( mapFile ) { - idMapEntity *ent = mapFile->FindEntity( name ); - if ( ent ) { - mapFile->RemoveEntity( ent ); - } - } -} - - -/* -================ -idGameEdit::MapGetEntitiesMatchignClassWithString -================ -*/ -int idGameEdit::MapGetEntitiesMatchingClassWithString( const char *classname, const char *match, const char *list[], const int max ) const { - idMapFile *mapFile = gameLocal.GetLevelMap(); - int count = 0; - if ( mapFile ) { - int entCount = mapFile->GetNumEntities(); - for ( int i = 0 ; i < entCount; i++ ) { - idMapEntity *ent = mapFile->GetEntity(i); - if (ent) { - idStr work = ent->epairs.GetString("classname"); - if ( work.Icmp( classname ) == 0 ) { - if ( match && *match ) { - work = ent->epairs.GetString( "soundgroup" ); - if ( count < max && work.Icmp( match ) == 0 ) { - list[count++] = ent->epairs.GetString( "name" ); - } - } else if ( count < max ) { - list[count++] = ent->epairs.GetString( "name" ); - } - } - } - } - } - return count; -} - - -/* -================ -idGameEdit::MapEntityTranslate -================ -*/ -void idGameEdit::MapEntityTranslate( const char *name, const idVec3 &v ) const { - idMapFile *mapFile = gameLocal.GetLevelMap(); - if ( mapFile && name && *name ) { - idMapEntity *mapent = mapFile->FindEntity( name ); - if ( mapent ) { - idVec3 origin; - mapent->epairs.GetVector( "origin", "", origin ); - origin += v; - mapent->epairs.SetVector( "origin", origin ); - } - } -} diff --git a/d3xp/GameEdit.h b/d3xp/GameEdit.h deleted file mode 100644 index bbc31ce5..00000000 --- a/d3xp/GameEdit.h +++ /dev/null @@ -1,125 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __GAME_EDIT_H__ -#define __GAME_EDIT_H__ - -#include "framework/DeclPDA.h" - -#include "physics/Force_Drag.h" -#include "Entity.h" - -class Player; - -/* -=============================================================================== - - Ingame cursor. - -=============================================================================== -*/ - -class idCursor3D : public idEntity { -public: - CLASS_PROTOTYPE( idCursor3D ); - - idCursor3D( void ); - ~idCursor3D( void ); - - void Spawn( void ); - void Present( void ); - void Think( void ); - - idForce_Drag drag; - idVec3 draggedPosition; -}; - - -/* -=============================================================================== - - Allows entities to be dragged through the world with physics. - -=============================================================================== -*/ - -class idDragEntity { -public: - idDragEntity( void ); - ~idDragEntity( void ); - - void Clear(); - void Update( idPlayer *player ); - void SetSelected( idEntity *ent ); - idEntity * GetSelected( void ) const { return selected.GetEntity(); } - void DeleteSelected( void ); - void BindSelected( void ); - void UnbindSelected( void ); - -private: - idEntityPtr dragEnt; // entity being dragged - jointHandle_t joint; // joint being dragged - int id; // id of body being dragged - idVec3 localEntityPoint; // dragged point in entity space - idVec3 localPlayerPoint; // dragged point in player space - idStr bodyName; // name of the body being dragged - idCursor3D * cursor; // cursor entity - idEntityPtr selected; // last dragged entity - - void StopDrag( void ); -}; - - -/* -=============================================================================== - - Handles ingame entity editing. - -=============================================================================== -*/ -typedef struct selectedTypeInfo_s { - idTypeInfo *typeInfo; - idStr textKey; -} selectedTypeInfo_t; - -class idEditEntities { -public: - idEditEntities( void ); - bool SelectEntity( const idVec3 &origin, const idVec3 &dir, const idEntity *skip ); - void AddSelectedEntity( idEntity *ent ); - void RemoveSelectedEntity( idEntity *ent ); - void ClearSelectedEntities( void ); - void DisplayEntities( void ); - bool EntityIsSelectable( idEntity *ent, idVec4 *color = NULL, idStr *text = NULL ); -private: - int nextSelectTime; - idList selectableEntityClasses; - idList selectedEntities; -}; - -#endif /* !__GAME_EDIT_H__ */ diff --git a/d3xp/Game_local.cpp b/d3xp/Game_local.cpp deleted file mode 100644 index 04891868..00000000 --- a/d3xp/Game_local.cpp +++ /dev/null @@ -1,5029 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/Stub_SDL_endian.h" -#include "sys/platform.h" -#include "idlib/LangDict.h" -#include "idlib/Timer.h" -#include "framework/async/NetworkSystem.h" -#include "framework/BuildVersion.h" -#include "framework/DeclEntityDef.h" -#include "framework/FileSystem.h" -#include "framework/Licensee.h" -#include "renderer/ModelManager.h" - -#include "gamesys/SysCvar.h" -#include "gamesys/SysCmds.h" -#include "script/Script_Thread.h" -#include "ai/AI.h" -#include "anim/Anim_Testmodel.h" -#include "Camera.h" -#include "SmokeParticles.h" -#include "Player.h" -#include "WorldSpawn.h" -#include "Misc.h" -#include "Trigger.h" - -#include "Game_local.h" - -const int NUM_RENDER_PORTAL_BITS = idMath::BitsForInteger( PS_BLOCK_ALL ); - -const float DEFAULT_GRAVITY = 1066.0f; -const idVec3 DEFAULT_GRAVITY_VEC3( 0, 0, -DEFAULT_GRAVITY ); - -const int CINEMATIC_SKIP_DELAY = SEC2MS( 2.0f ); - -#ifdef GAME_DLL - -idSys * sys = NULL; -idCommon * common = NULL; -idCmdSystem * cmdSystem = NULL; -idCVarSystem * cvarSystem = NULL; -idFileSystem * fileSystem = NULL; -idNetworkSystem * networkSystem = NULL; -idRenderSystem * renderSystem = NULL; -idSoundSystem * soundSystem = NULL; -idRenderModelManager * renderModelManager = NULL; -idUserInterfaceManager * uiManager = NULL; -idDeclManager * declManager = NULL; -idAASFileManager * AASFileManager = NULL; -idCollisionModelManager * collisionModelManager = NULL; -idCVar * idCVar::staticVars = NULL; - -idCVar com_forceGenericSIMD( "com_forceGenericSIMD", "0", CVAR_BOOL|CVAR_SYSTEM, "force generic platform independent SIMD" ); - -#endif - -idRenderWorld * gameRenderWorld = NULL; // all drawing is done to this world -idSoundWorld * gameSoundWorld = NULL; // all audio goes to this world - -static gameExport_t gameExport; - -// global animation lib -idAnimManager animationLib; - -// the rest of the engine will only reference the "game" variable, while all local aspects stay hidden -idGameLocal gameLocal; -idGame * game = &gameLocal; // statically pointed at an idGameLocal - -const char *idGameLocal::sufaceTypeNames[ MAX_SURFACE_TYPES ] = { - "none", "metal", "stone", "flesh", "wood", "cardboard", "liquid", "glass", "plastic", - "ricochet", "surftype10", "surftype11", "surftype12", "surftype13", "surftype14", "surftype15" -}; - -#ifdef _D3XP -// List of all defs used by the player that will stay on the fast timeline -static const char* fastEntityList[] = { - "player_doommarine", - "weapon_chainsaw", - "weapon_fists", - "weapon_flashlight", - "weapon_rocketlauncher", - "projectile_rocket", - "weapon_machinegun", - "projectile_bullet_machinegun", - "weapon_pistol", - "projectile_bullet_pistol", - "weapon_handgrenade", - "projectile_grenade", - "weapon_bfg", - "projectile_bfg", - "weapon_chaingun", - "projectile_chaingunbullet", - "weapon_pda", - "weapon_plasmagun", - "projectile_plasmablast", - "weapon_shotgun", - "projectile_bullet_shotgun", - "weapon_soulcube", - "projectile_soulblast", - "weapon_shotgun_double", - "projectile_shotgunbullet_double", - "weapon_grabber", - "weapon_bloodstone_active1", - "weapon_bloodstone_active2", - "weapon_bloodstone_active3", - "weapon_bloodstone_passive", - NULL }; -#endif -/* -=========== -GetGameAPI -============ -*/ -extern "C" ID_GAME_API gameExport_t *GetGameAPI( gameImport_t *import ) { - - if ( import->version == GAME_API_VERSION ) { - - // set interface pointers used by the game - sys = import->sys; - common = import->common; - cmdSystem = import->cmdSystem; - cvarSystem = import->cvarSystem; - fileSystem = import->fileSystem; - networkSystem = import->networkSystem; - renderSystem = import->renderSystem; - soundSystem = import->soundSystem; - renderModelManager = import->renderModelManager; - uiManager = import->uiManager; - declManager = import->declManager; - AASFileManager = import->AASFileManager; - collisionModelManager = import->collisionModelManager; - } - - // set interface pointers used by idLib - idLib::sys = sys; - idLib::common = common; - idLib::cvarSystem = cvarSystem; - idLib::fileSystem = fileSystem; - - // setup export interface - gameExport.version = GAME_API_VERSION; - gameExport.game = game; - gameExport.gameEdit = gameEdit; - - return &gameExport; -} - -/* -=========== -TestGameAPI -============ -*/ -void TestGameAPI( void ) { - gameImport_t testImport; - gameExport_t testExport; - - testImport.sys = ::sys; - testImport.common = ::common; - testImport.cmdSystem = ::cmdSystem; - testImport.cvarSystem = ::cvarSystem; - testImport.fileSystem = ::fileSystem; - testImport.networkSystem = ::networkSystem; - testImport.renderSystem = ::renderSystem; - testImport.soundSystem = ::soundSystem; - testImport.renderModelManager = ::renderModelManager; - testImport.uiManager = ::uiManager; - testImport.declManager = ::declManager; - testImport.AASFileManager = ::AASFileManager; - testImport.collisionModelManager = ::collisionModelManager; - - testExport = *GetGameAPI( &testImport ); -} - -/* -=========== -idGameLocal::idGameLocal -============ -*/ -idGameLocal::idGameLocal() { - Clear(); -} - -/* -=========== -idGameLocal::Clear -============ -*/ -void idGameLocal::Clear( void ) { - int i; - - serverInfo.Clear(); - numClients = 0; - for ( i = 0; i < MAX_CLIENTS; i++ ) { - userInfo[i].Clear(); - persistentPlayerInfo[i].Clear(); - } - memset( usercmds, 0, sizeof( usercmds ) ); - memset( entities, 0, sizeof( entities ) ); - memset( spawnIds, -1, sizeof( spawnIds ) ); - firstFreeIndex = 0; - num_entities = 0; - spawnedEntities.Clear(); - activeEntities.Clear(); - numEntitiesToDeactivate = 0; - sortPushers = false; - sortTeamMasters = false; - persistentLevelInfo.Clear(); - memset( globalShaderParms, 0, sizeof( globalShaderParms ) ); - random.SetSeed( 0 ); - world = NULL; - frameCommandThread = NULL; - testmodel = NULL; - testFx = NULL; - clip.Shutdown(); - pvs.Shutdown(); - sessionCommand.Clear(); - locationEntities = NULL; - smokeParticles = NULL; - editEntities = NULL; - entityHash.Clear( 1024, MAX_GENTITIES ); - inCinematic = false; - cinematicSkipTime = 0; - cinematicStopTime = 0; - cinematicMaxSkipTime = 0; - framenum = 0; - previousTime = 0; - time = 0; - vacuumAreaNum = 0; - mapFileName.Clear(); - mapFile = NULL; - spawnCount = INITIAL_SPAWN_COUNT; - mapSpawnCount = 0; - camera = NULL; - aasList.Clear(); - aasNames.Clear(); - lastAIAlertEntity = NULL; - lastAIAlertTime = 0; - spawnArgs.Clear(); - gravity.Set( 0, 0, -1 ); - playerPVS.h = -1; - playerConnectedAreas.h = -1; - gamestate = GAMESTATE_UNINITIALIZED; - skipCinematic = false; - influenceActive = false; - - localClientNum = 0; - isMultiplayer = false; - isServer = false; - isClient = false; - realClientTime = 0; - isNewFrame = true; - clientSmoothing = 0.1f; - entityDefBits = 0; - - nextGibTime = 0; - globalMaterial = NULL; - newInfo.Clear(); - lastGUIEnt = NULL; - lastGUI = 0; - - memset( clientEntityStates, 0, sizeof( clientEntityStates ) ); - memset( clientPVS, 0, sizeof( clientPVS ) ); - memset( clientSnapshots, 0, sizeof( clientSnapshots ) ); - - eventQueue.Init(); - savedEventQueue.Init(); - - memset( lagometer, 0, sizeof( lagometer ) ); - -#ifdef _D3XP - portalSkyEnt = NULL; - portalSkyActive = false; - - ResetSlowTimeVars(); -#endif -} - -/* -=========== -idGameLocal::Init - - initialize the game object, only happens once at startup, not each level load -============ -*/ -void idGameLocal::Init( void ) { - const idDict *dict; - idAAS *aas; - -#ifndef GAME_DLL - - TestGameAPI(); - -#else - - // initialize idLib - idLib::Init(); - - // register static cvars declared in the game - idCVar::RegisterStaticVars(); - - // initialize processor specific SIMD - idSIMD::InitProcessor( "game", com_forceGenericSIMD.GetBool() ); - -#endif - - Printf( "----- Initializing Game -----\n" ); - Printf( "gamename: %s\n", GAME_VERSION ); - Printf( "gamedate: %s\n", __DATE__ ); - - // register game specific decl types - declManager->RegisterDeclType( "model", DECL_MODELDEF, idDeclAllocator ); - declManager->RegisterDeclType( "export", DECL_MODELEXPORT, idDeclAllocator ); - - // register game specific decl folders - declManager->RegisterDeclFolder( "def", ".def", DECL_ENTITYDEF ); - declManager->RegisterDeclFolder( "fx", ".fx", DECL_FX ); - declManager->RegisterDeclFolder( "particles", ".prt", DECL_PARTICLE ); - declManager->RegisterDeclFolder( "af", ".af", DECL_AF ); - declManager->RegisterDeclFolder( "newpdas", ".pda", DECL_PDA ); - - cmdSystem->AddCommand( "listModelDefs", idListDecls_f, CMD_FL_SYSTEM|CMD_FL_GAME, "lists model defs" ); - cmdSystem->AddCommand( "printModelDefs", idPrintDecls_f, CMD_FL_SYSTEM|CMD_FL_GAME, "prints a model def", idCmdSystem::ArgCompletion_Decl ); - - Clear(); - - idEvent::Init(); - idClass::Init(); - - InitConsoleCommands(); - - -#ifdef _D3XP - if(!g_xp_bind_run_once.GetBool()) { - //The default config file contains remapped controls that support the XP weapons - //We want to run this once after the base doom config file has run so we can - //have the correct xp binds - cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "exec default.cfg\n" ); - cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "seta g_xp_bind_run_once 1\n" ); - cmdSystem->ExecuteCommandBuffer(); - } -#endif - - // load default scripts - program.Startup( SCRIPT_DEFAULT ); - -#ifdef _D3XP - //BSM Nerve: Loads a game specific main script file - idStr gamedir; - int i; - for ( i = 0; i < 2; i++ ) { - if ( i == 0 ) { - gamedir = cvarSystem->GetCVarString( "fs_game_base" ); - } else if ( i == 1 ) { - gamedir = cvarSystem->GetCVarString( "fs_game" ); - } - if( gamedir.Length() > 0 ) { - idStr scriptFile = va( "script/%s_main.script", gamedir.c_str() ); - if ( fileSystem->ReadFile( scriptFile.c_str(), NULL ) > 0 ) { - program.CompileFile( scriptFile.c_str() ); - program.FinishCompilation(); - } - } - } -#endif - - smokeParticles = new idSmokeParticles; - - // set up the aas - dict = FindEntityDefDict( "aas_types" ); - if ( !dict ) { - Error( "Unable to find entityDef for 'aas_types'" ); - } - - // allocate space for the aas - const idKeyValue *kv = dict->MatchPrefix( "type" ); - while( kv != NULL ) { - aas = idAAS::Alloc(); - aasList.Append( aas ); - aasNames.Append( kv->GetValue() ); - kv = dict->MatchPrefix( "type", kv ); - } - - gamestate = GAMESTATE_NOMAP; - - Printf( "...%d aas types\n", aasList.Num() ); -} - -/* -=========== -idGameLocal::Shutdown - - shut down the entire game -============ -*/ -void idGameLocal::Shutdown( void ) { - - if ( !common ) { - return; - } - - Printf( "----- Game Shutdown -----\n" ); - - mpGame.Shutdown(); - - MapShutdown(); - - aasList.DeleteContents( true ); - aasNames.Clear(); - - idAI::FreeObstacleAvoidanceNodes(); - - // shutdown the model exporter - idModelExport::Shutdown(); - - idEvent::Shutdown(); - - delete[] locationEntities; - locationEntities = NULL; - - delete smokeParticles; - smokeParticles = NULL; - - idClass::Shutdown(); - - // clear list with forces - idForce::ClearForceList(); - - // free the program data - program.FreeData(); - - // delete the .map file - delete mapFile; - mapFile = NULL; - - // free the collision map - collisionModelManager->FreeMap(); - - ShutdownConsoleCommands(); - - // free memory allocated by class objects - Clear(); - - // shut down the animation manager - animationLib.Shutdown(); - -#ifdef GAME_DLL - - // remove auto-completion function pointers pointing into this DLL - cvarSystem->RemoveFlaggedAutoCompletion( CVAR_GAME ); - - // enable leak test - Mem_EnableLeakTest( "game" ); - - // shutdown idLib - idLib::ShutDown(); - -#endif -} - -/* -=========== -idGameLocal::SaveGame - -save the current player state, level name, and level state -the session may have written some data to the file already -============ -*/ -void idGameLocal::SaveGame( idFile *f ) { - int i; - idEntity *ent; - idEntity *link; - - idSaveGame savegame( f ); - - if (g_flushSave.GetBool( ) == true ) { - // force flushing with each write... for tracking down - // save game bugs. - f->ForceFlush(); - } - - savegame.WriteBuildNumber( BUILD_NUMBER ); - - // DG: add some more information to savegame to make future quirks easier - savegame.WriteInt( INTERNAL_SAVEGAME_VERSION ); // to be independent of BUILD_NUMBER - savegame.WriteString( D3_OSTYPE ); // operating system - from CMake - savegame.WriteString( D3_ARCH ); // CPU architecture (e.g. "x86" or "x86_64") - from CMake - savegame.WriteString( ENGINE_VERSION ); - savegame.WriteShort( (short)sizeof(void*) ); // tells us if it's from a 32bit (4) or 64bit system (8) - savegame.WriteShort( SDL_BYTEORDER ) ; // SDL_LIL_ENDIAN or SDL_BIG_ENDIAN - // DG end - - // go through all entities and threads and add them to the object list - for( i = 0; i < MAX_GENTITIES; i++ ) { - ent = entities[i]; - - if ( ent ) { - if ( ent->GetTeamMaster() && ent->GetTeamMaster() != ent ) { - continue; - } - for ( link = ent; link != NULL; link = link->GetNextTeamEntity() ) { - savegame.AddObject( link ); - } - } - } - - idList threads; - threads = idThread::GetThreads(); - - for( i = 0; i < threads.Num(); i++ ) { - savegame.AddObject( threads[i] ); - } - - // write out complete object list - savegame.WriteObjectList(); - - program.Save( &savegame ); - - savegame.WriteInt( g_skill.GetInteger() ); - - savegame.WriteDict( &serverInfo ); - - savegame.WriteInt( numClients ); - for( i = 0; i < numClients; i++ ) { - savegame.WriteDict( &userInfo[ i ] ); - savegame.WriteUsercmd( usercmds[ i ] ); - savegame.WriteDict( &persistentPlayerInfo[ i ] ); - } - - for( i = 0; i < MAX_GENTITIES; i++ ) { - savegame.WriteObject( entities[ i ] ); - savegame.WriteInt( spawnIds[ i ] ); - } - - savegame.WriteInt( firstFreeIndex ); - savegame.WriteInt( num_entities ); - - // enityHash is restored by idEntity::Restore setting the entity name. - - savegame.WriteObject( world ); - - savegame.WriteInt( spawnedEntities.Num() ); - for( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) { - savegame.WriteObject( ent ); - } - - savegame.WriteInt( activeEntities.Num() ); - for( ent = activeEntities.Next(); ent != NULL; ent = ent->activeNode.Next() ) { - savegame.WriteObject( ent ); - } - - savegame.WriteInt( numEntitiesToDeactivate ); - savegame.WriteBool( sortPushers ); - savegame.WriteBool( sortTeamMasters ); - savegame.WriteDict( &persistentLevelInfo ); - - for( i = 0; i < MAX_GLOBAL_SHADER_PARMS; i++ ) { - savegame.WriteFloat( globalShaderParms[ i ] ); - } - - savegame.WriteInt( random.GetSeed() ); - savegame.WriteObject( frameCommandThread ); - - // clip - // push - // pvs - - testmodel = NULL; - testFx = NULL; - - savegame.WriteString( sessionCommand ); - - // FIXME: save smoke particles - - savegame.WriteInt( cinematicSkipTime ); - savegame.WriteInt( cinematicStopTime ); - savegame.WriteInt( cinematicMaxSkipTime ); - savegame.WriteBool( inCinematic ); - savegame.WriteBool( skipCinematic ); - - savegame.WriteBool( isMultiplayer ); - savegame.WriteInt( gameType ); - - savegame.WriteInt( framenum ); - savegame.WriteInt( previousTime ); - savegame.WriteInt( time ); - -#ifdef _D3XP - savegame.WriteInt( msec ); -#endif - - savegame.WriteInt( vacuumAreaNum ); - - savegame.WriteInt( entityDefBits ); - savegame.WriteBool( isServer ); - savegame.WriteBool( isClient ); - - savegame.WriteInt( localClientNum ); - - // snapshotEntities is used for multiplayer only - - savegame.WriteInt( realClientTime ); - savegame.WriteBool( isNewFrame ); - savegame.WriteFloat( clientSmoothing ); - -#ifdef _D3XP - portalSkyEnt.Save( &savegame ); - savegame.WriteBool( portalSkyActive ); - - fast.Save( &savegame ); - slow.Save( &savegame ); - - savegame.WriteInt( slowmoState ); - savegame.WriteFloat( slowmoMsec ); - savegame.WriteBool( quickSlowmoReset ); -#endif - - savegame.WriteBool( mapCycleLoaded ); - savegame.WriteInt( spawnCount ); - - if ( !locationEntities ) { - savegame.WriteInt( 0 ); - } else { - savegame.WriteInt( gameRenderWorld->NumAreas() ); - for( i = 0; i < gameRenderWorld->NumAreas(); i++ ) { - savegame.WriteObject( locationEntities[ i ] ); - } - } - - savegame.WriteObject( camera ); - - savegame.WriteMaterial( globalMaterial ); - - lastAIAlertEntity.Save( &savegame ); - savegame.WriteInt( lastAIAlertTime ); - - savegame.WriteDict( &spawnArgs ); - - savegame.WriteInt( playerPVS.i ); - savegame.WriteInt( playerPVS.h ); - savegame.WriteInt( playerConnectedAreas.i ); - savegame.WriteInt( playerConnectedAreas.h ); - - savegame.WriteVec3( gravity ); - - // gamestate - - savegame.WriteBool( influenceActive ); - savegame.WriteInt( nextGibTime ); - - // spawnSpots - // initialSpots - // currentInitialSpot - // newInfo - // makingBuild - // shakeSounds - - // write out pending events - idEvent::Save( &savegame ); - - savegame.Close(); -} - -/* -=========== -idGameLocal::GetPersistentPlayerInfo -============ -*/ -const idDict &idGameLocal::GetPersistentPlayerInfo( int clientNum ) { - idEntity *ent; - - persistentPlayerInfo[ clientNum ].Clear(); - ent = entities[ clientNum ]; - if ( ent && ent->IsType( idPlayer::Type ) ) { - static_cast(ent)->SavePersistantInfo(); - } - - return persistentPlayerInfo[ clientNum ]; -} - -/* -=========== -idGameLocal::SetPersistentPlayerInfo -============ -*/ -void idGameLocal::SetPersistentPlayerInfo( int clientNum, const idDict &playerInfo ) { - persistentPlayerInfo[ clientNum ] = playerInfo; -} - -/* -============ -idGameLocal::Printf -============ -*/ -void idGameLocal::Printf( const char *fmt, ... ) const { - va_list argptr; - char text[MAX_STRING_CHARS]; - - va_start( argptr, fmt ); - idStr::vsnPrintf( text, sizeof( text ), fmt, argptr ); - va_end( argptr ); - - common->Printf( "%s", text ); -} - -/* -============ -idGameLocal::DPrintf -============ -*/ -void idGameLocal::DPrintf( const char *fmt, ... ) const { - va_list argptr; - char text[MAX_STRING_CHARS]; - - if ( !developer.GetBool() ) { - return; - } - - va_start( argptr, fmt ); - idStr::vsnPrintf( text, sizeof( text ), fmt, argptr ); - va_end( argptr ); - - common->Printf( "%s", text ); -} - -/* -============ -idGameLocal::Warning -============ -*/ -void idGameLocal::Warning( const char *fmt, ... ) const { - va_list argptr; - char text[MAX_STRING_CHARS]; - idThread * thread; - - va_start( argptr, fmt ); - idStr::vsnPrintf( text, sizeof( text ), fmt, argptr ); - va_end( argptr ); - - thread = idThread::CurrentThread(); - if ( thread ) { - thread->Warning( "%s", text ); - } else { - common->Warning( "%s", text ); - } -} - -/* -============ -idGameLocal::DWarning -============ -*/ -void idGameLocal::DWarning( const char *fmt, ... ) const { - va_list argptr; - char text[MAX_STRING_CHARS]; - idThread * thread; - - if ( !developer.GetBool() ) { - return; - } - - va_start( argptr, fmt ); - idStr::vsnPrintf( text, sizeof( text ), fmt, argptr ); - va_end( argptr ); - - thread = idThread::CurrentThread(); - if ( thread ) { - thread->Warning( "%s", text ); - } else { - common->DWarning( "%s", text ); - } -} - -/* -============ -idGameLocal::Error -============ -*/ -void idGameLocal::Error( const char *fmt, ... ) const { - va_list argptr; - char text[MAX_STRING_CHARS]; - idThread * thread; - - va_start( argptr, fmt ); - idStr::vsnPrintf( text, sizeof( text ), fmt, argptr ); - va_end( argptr ); - - thread = idThread::CurrentThread(); - if ( thread ) { - thread->Error( "%s", text ); - } else { - common->Error( "%s", text ); - } -} - -/* -=============== -gameError -=============== -*/ -void gameError( const char *fmt, ... ) { - va_list argptr; - char text[MAX_STRING_CHARS]; - - va_start( argptr, fmt ); - idStr::vsnPrintf( text, sizeof( text ), fmt, argptr ); - va_end( argptr ); - - gameLocal.Error( "%s", text ); -} - -/* -=========== -idGameLocal::SetLocalClient -============ -*/ -void idGameLocal::SetLocalClient( int clientNum ) { - localClientNum = clientNum; -} - -/* -=========== -idGameLocal::SetUserInfo -============ -*/ -const idDict* idGameLocal::SetUserInfo( int clientNum, const idDict &userInfo, bool isClient, bool canModify ) { - int i; - bool modifiedInfo = false; - - this->isClient = isClient; - - if ( clientNum >= 0 && clientNum < MAX_CLIENTS ) { - idGameLocal::userInfo[ clientNum ] = userInfo; - - // server sanity - if ( canModify ) { - - // don't let numeric nicknames, it can be exploited to go around kick and ban commands from the server - if ( idStr::IsNumeric( this->userInfo[ clientNum ].GetString( "ui_name" ) ) ) { - idGameLocal::userInfo[ clientNum ].Set( "ui_name", va( "%s_", idGameLocal::userInfo[ clientNum ].GetString( "ui_name" ) ) ); - modifiedInfo = true; - } - - // don't allow dupe nicknames - for ( i = 0; i < numClients; i++ ) { - if ( i == clientNum ) { - continue; - } - if ( entities[ i ] && entities[ i ]->IsType( idPlayer::Type ) ) { - if ( !idStr::Icmp( idGameLocal::userInfo[ clientNum ].GetString( "ui_name" ), idGameLocal::userInfo[ i ].GetString( "ui_name" ) ) ) { - idGameLocal::userInfo[ clientNum ].Set( "ui_name", va( "%s_", idGameLocal::userInfo[ clientNum ].GetString( "ui_name" ) ) ); - modifiedInfo = true; - i = -1; // rescan - continue; - } - } - } - } - - if ( entities[ clientNum ] && entities[ clientNum ]->IsType( idPlayer::Type ) ) { - modifiedInfo |= static_cast( entities[ clientNum ] )->UserInfoChanged( canModify ); - } - - if ( !isClient ) { - // now mark this client in game - mpGame.EnterGame( clientNum ); - } - } - - if ( modifiedInfo ) { - assert( canModify ); - newInfo = idGameLocal::userInfo[ clientNum ]; - return &newInfo; - } - return NULL; -} - -/* -=========== -idGameLocal::GetUserInfo -============ -*/ -const idDict* idGameLocal::GetUserInfo( int clientNum ) { - if ( entities[ clientNum ] && entities[ clientNum ]->IsType( idPlayer::Type ) ) { - return &userInfo[ clientNum ]; - } - return NULL; -} - -/* -=========== -idGameLocal::SetServerInfo -============ -*/ -void idGameLocal::SetServerInfo( const idDict &_serverInfo ) { - idBitMsg outMsg; - byte msgBuf[MAX_GAME_MESSAGE_SIZE]; - - serverInfo = _serverInfo; - UpdateServerInfoFlags(); - - if ( !isClient ) { - // Let our clients know the server info changed - outMsg.Init( msgBuf, sizeof( msgBuf ) ); - outMsg.WriteByte( GAME_RELIABLE_MESSAGE_SERVERINFO ); - outMsg.WriteDeltaDict( gameLocal.serverInfo, NULL ); - networkSystem->ServerSendReliableMessage( -1, outMsg ); - } -} - - -/* -=================== -idGameLocal::LoadMap - -Initializes all map variables common to both save games and spawned games. -=================== -*/ -void idGameLocal::LoadMap( const char *mapName, int randseed ) { - int i; - bool sameMap = (mapFile && idStr::Icmp(mapFileName, mapName) == 0); - - // clear the sound system - gameSoundWorld->ClearAllSoundEmitters(); - -#ifdef _D3XP - // clear envirosuit sound fx - gameSoundWorld->SetEnviroSuit( false ); - gameSoundWorld->SetSlowmo( false ); -#endif - - InitAsyncNetwork(); - - if ( !sameMap || ( mapFile && mapFile->NeedsReload() ) ) { - // load the .map file - if ( mapFile ) { - delete mapFile; - } - mapFile = new idMapFile; - if ( !mapFile->Parse( idStr( mapName ) + ".map" ) ) { - delete mapFile; - mapFile = NULL; - Error( "Couldn't load %s", mapName ); - } - } - mapFileName = mapFile->GetName(); - - // load the collision map - collisionModelManager->LoadMap( mapFile ); - - numClients = 0; - - // initialize all entities for this game - memset( entities, 0, sizeof( entities ) ); - memset( usercmds, 0, sizeof( usercmds ) ); - memset( spawnIds, -1, sizeof( spawnIds ) ); - spawnCount = INITIAL_SPAWN_COUNT; - - spawnedEntities.Clear(); - activeEntities.Clear(); - numEntitiesToDeactivate = 0; - sortTeamMasters = false; - sortPushers = false; - lastGUIEnt = NULL; - lastGUI = 0; - - globalMaterial = NULL; - - memset( globalShaderParms, 0, sizeof( globalShaderParms ) ); - - // always leave room for the max number of clients, - // even if they aren't all used, so numbers inside that - // range are NEVER anything but clients - num_entities = MAX_CLIENTS; - firstFreeIndex = MAX_CLIENTS; - - // reset the random number generator. - random.SetSeed( isMultiplayer ? randseed : 0 ); - - camera = NULL; - world = NULL; - testmodel = NULL; - testFx = NULL; - - lastAIAlertEntity = NULL; - lastAIAlertTime = 0; - - previousTime = 0; - time = 0; - framenum = 0; - sessionCommand = ""; - nextGibTime = 0; - -#ifdef _D3XP - portalSkyEnt = NULL; - portalSkyActive = false; - - ResetSlowTimeVars(); -#endif - - vacuumAreaNum = -1; // if an info_vacuum is spawned, it will set this - - if ( !editEntities ) { - editEntities = new idEditEntities; - } - - gravity.Set( 0, 0, -g_gravity.GetFloat() ); - - spawnArgs.Clear(); - - skipCinematic = false; - inCinematic = false; - cinematicSkipTime = 0; - cinematicStopTime = 0; - cinematicMaxSkipTime = 0; - - clip.Init(); - pvs.Init(); - playerPVS.i = -1; - playerConnectedAreas.i = -1; - - // load navigation system for all the different monster sizes - for( i = 0; i < aasNames.Num(); i++ ) { - aasList[ i ]->Init( idStr( mapFileName ).SetFileExtension( aasNames[ i ] ).c_str(), mapFile->GetGeometryCRC() ); - } - - // clear the smoke particle free list - smokeParticles->Init(); - - // cache miscellanious media references - FindEntityDef( "preCacheExtras", false ); - - if ( !sameMap ) { - mapFile->RemovePrimitiveData(); - } -} - -/* -=================== -idGameLocal::LocalMapRestart -=================== -*/ -void idGameLocal::LocalMapRestart( ) { - int i, latchSpawnCount; - - Printf( "----- Game Map Restart -----\n" ); - - gamestate = GAMESTATE_SHUTDOWN; - - for ( i = 0; i < MAX_CLIENTS; i++ ) { - if ( entities[ i ] && entities[ i ]->IsType( idPlayer::Type ) ) { - static_cast< idPlayer * >( entities[ i ] )->PrepareForRestart(); - } - } - - eventQueue.Shutdown(); - savedEventQueue.Shutdown(); - - MapClear( false ); - - - - // clear the smoke particle free list - smokeParticles->Init(); - - // clear the sound system - if ( gameSoundWorld ) { - gameSoundWorld->ClearAllSoundEmitters(); -#ifdef _D3XP - // clear envirosuit sound fx - gameSoundWorld->SetEnviroSuit( false ); - gameSoundWorld->SetSlowmo( false ); -#endif - } - - // the spawnCount is reset to zero temporarily to spawn the map entities with the same spawnId - // if we don't do that, network clients are confused and don't show any map entities - latchSpawnCount = spawnCount; - spawnCount = INITIAL_SPAWN_COUNT; - - gamestate = GAMESTATE_STARTUP; - - program.Restart(); - - InitScriptForMap(); - - MapPopulate(); - - // once the map is populated, set the spawnCount back to where it was so we don't risk any collision - // (note that if there are no players in the game, we could just leave it at it's current value) - spawnCount = latchSpawnCount; - - // setup the client entities again - for ( i = 0; i < MAX_CLIENTS; i++ ) { - if ( entities[ i ] && entities[ i ]->IsType( idPlayer::Type ) ) { - static_cast< idPlayer * >( entities[ i ] )->Restart(); - } - } - - gamestate = GAMESTATE_ACTIVE; -} - -/* -=================== -idGameLocal::MapRestart -=================== -*/ -void idGameLocal::MapRestart( ) { - idBitMsg outMsg; - byte msgBuf[MAX_GAME_MESSAGE_SIZE]; - idDict newInfo; - int i; - const idKeyValue *keyval, *keyval2; - -#ifdef _D3XP - if ( isMultiplayer && isServer ) { - char buf[ MAX_STRING_CHARS ]; - idStr gametype; - GetBestGameType( si_map.GetString(), si_gameType.GetString(), buf ); - gametype = buf; - if ( gametype != si_gameType.GetString() ) { - cvarSystem->SetCVarString( "si_gameType", gametype ); - } - } -#endif - - - - if ( isClient ) { - LocalMapRestart(); - } else { - newInfo = *cvarSystem->MoveCVarsToDict( CVAR_SERVERINFO ); - for ( i = 0; i < newInfo.GetNumKeyVals(); i++ ) { - keyval = newInfo.GetKeyVal( i ); - keyval2 = serverInfo.FindKey( keyval->GetKey() ); - if ( !keyval2 ) { - break; - } - // a select set of si_ changes will cause a full restart of the server - if ( keyval->GetValue().Cmp( keyval2->GetValue() ) && - ( !keyval->GetKey().Cmp( "si_pure" ) || !keyval->GetKey().Cmp( "si_map" ) ) ) { - break; - } - } - cmdSystem->BufferCommandText( CMD_EXEC_NOW, "rescanSI" ); - - if ( i != newInfo.GetNumKeyVals() ) { - cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "nextMap" ); - } else { - outMsg.Init( msgBuf, sizeof( msgBuf ) ); - outMsg.WriteByte( GAME_RELIABLE_MESSAGE_RESTART ); - outMsg.WriteBits( 1, 1 ); - outMsg.WriteDeltaDict( serverInfo, NULL ); - networkSystem->ServerSendReliableMessage( -1, outMsg ); - - LocalMapRestart(); - mpGame.MapRestart(); - } - } - -#ifdef CTF - if ( isMultiplayer ) { - gameLocal.mpGame.ReloadScoreboard(); - // gameLocal.mpGame.Reset(); // force reconstruct the GUIs when reloading maps, different gametypes have different GUIs - // gameLocal.mpGame.UpdateMainGui(); - // gameLocal.mpGame.StartMenu(); - // gameLocal.mpGame.DisableMenu(); - // gameLocal.mpGame.Precache(); - } -#endif -} - -/* -=================== -idGameLocal::MapRestart_f -=================== -*/ -void idGameLocal::MapRestart_f( const idCmdArgs &args ) { - if ( !gameLocal.isMultiplayer || gameLocal.isClient ) { - common->Printf( "server is not running - use spawnServer\n" ); - cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "spawnServer\n" ); - return; - } - - gameLocal.MapRestart( ); -} - -/* -=================== -idGameLocal::NextMap -=================== -*/ -bool idGameLocal::NextMap( void ) { - const function_t *func; - idThread *thread; - idDict newInfo; - const idKeyValue *keyval, *keyval2; - int i; - - if ( !g_mapCycle.GetString()[0] ) { - Printf( common->GetLanguageDict()->GetString( "#str_04294" ) ); - return false; - } - if ( fileSystem->ReadFile( g_mapCycle.GetString(), NULL, NULL ) < 0 ) { - if ( fileSystem->ReadFile( va( "%s.scriptcfg", g_mapCycle.GetString() ), NULL, NULL ) < 0 ) { - Printf( "map cycle script '%s': not found\n", g_mapCycle.GetString() ); - return false; - } else { - g_mapCycle.SetString( va( "%s.scriptcfg", g_mapCycle.GetString() ) ); - } - } - - Printf( "map cycle script: '%s'\n", g_mapCycle.GetString() ); - func = program.FindFunction( "mapcycle::cycle" ); - if ( !func ) { - program.CompileFile( g_mapCycle.GetString() ); - func = program.FindFunction( "mapcycle::cycle" ); - } - if ( !func ) { - Printf( "Couldn't find mapcycle::cycle\n" ); - return false; - } - thread = new idThread( func ); - thread->Start(); - delete thread; - - newInfo = *cvarSystem->MoveCVarsToDict( CVAR_SERVERINFO ); - for ( i = 0; i < newInfo.GetNumKeyVals(); i++ ) { - keyval = newInfo.GetKeyVal( i ); - keyval2 = serverInfo.FindKey( keyval->GetKey() ); - if ( !keyval2 || keyval->GetValue().Cmp( keyval2->GetValue() ) ) { - break; - } - } - return ( i != newInfo.GetNumKeyVals() ); -} - -/* -=================== -idGameLocal::NextMap_f -=================== -*/ -void idGameLocal::NextMap_f( const idCmdArgs &args ) { - if ( !gameLocal.isMultiplayer || gameLocal.isClient ) { - common->Printf( "server is not running\n" ); - return; - } - - gameLocal.NextMap( ); - // next map was either voted for or triggered by a server command - always restart - gameLocal.MapRestart( ); -} - -/* -=================== -idGameLocal::MapPopulate -=================== -*/ -void idGameLocal::MapPopulate( void ) { - - if ( isMultiplayer ) { - cvarSystem->SetCVarBool( "r_skipSpecular", false ); - } - // parse the key/value pairs and spawn entities - SpawnMapEntities(); - - // mark location entities in all connected areas - SpreadLocations(); - - // prepare the list of randomized initial spawn spots - RandomizeInitialSpawns(); - - // spawnCount - 1 is the number of entities spawned into the map, their indexes started at MAX_CLIENTS (included) - // mapSpawnCount is used as the max index of map entities, it's the first index of non-map entities - mapSpawnCount = MAX_CLIENTS + spawnCount - 1; - - // execute pending events before the very first game frame - // this makes sure the map script main() function is called - // before the physics are run so entities can bind correctly - Printf( "==== Processing events ====\n" ); - idEvent::ServiceEvents(); -} - -/* -=================== -idGameLocal::InitFromNewMap -=================== -*/ -void idGameLocal::InitFromNewMap( const char *mapName, idRenderWorld *renderWorld, idSoundWorld *soundWorld, bool isServer, bool isClient, int randseed ) { - - this->isServer = isServer; - this->isClient = isClient; - this->isMultiplayer = isServer || isClient; - - if ( mapFileName.Length() ) { - MapShutdown(); - } - - Printf( "----- Game Map Init -----\n" ); - - gamestate = GAMESTATE_STARTUP; - - gameRenderWorld = renderWorld; - gameSoundWorld = soundWorld; - - LoadMap( mapName, randseed ); - - InitScriptForMap(); - - MapPopulate(); - - mpGame.Reset(); - - mpGame.Precache(); - - // free up any unused animations - animationLib.FlushUnusedAnims(); - - gamestate = GAMESTATE_ACTIVE; -} - -/* -================= -idGameLocal::InitFromSaveGame -================= -*/ -bool idGameLocal::InitFromSaveGame( const char *mapName, idRenderWorld *renderWorld, idSoundWorld *soundWorld, idFile *saveGameFile ) { - int i; - int num; - idEntity *ent; - idDict si; - - if ( mapFileName.Length() ) { - MapShutdown(); - } - - Printf( "----- Game Map Init SaveGame -----\n" ); - - gamestate = GAMESTATE_STARTUP; - - gameRenderWorld = renderWorld; - gameSoundWorld = soundWorld; - - idRestoreGame savegame( saveGameFile ); - - savegame.ReadBuildNumber(); - - // DG: I enhanced the information in savegames a bit for dhewm3 1.5.1 - // for which I bumped th BUILD_NUMBER to 1305 - if( savegame.GetBuildNumber() >= 1305 ) - { - savegame.ReadInternalSavegameVersion(); - if( savegame.GetInternalSavegameVersion() > INTERNAL_SAVEGAME_VERSION ) { - Warning( "Savegame from newer dhewm3 version, don't know how to load! (its version is %d, only up to %d supported)", - savegame.GetInternalSavegameVersion(), INTERNAL_SAVEGAME_VERSION ); - return false; - } - idStr osType; - idStr cpuArch; - idStr engineVersion; - short ptrSize = 0; - short byteorder = 0; - savegame.ReadString( osType ); // operating system the savegame was crated on (written from D3_OSTYPE) - savegame.ReadString( cpuArch ); // written from D3_ARCH (which is set in CMake), like "x86" or "x86_64" - savegame.ReadString( engineVersion ); // written from ENGINE_VERSION - savegame.ReadShort( ptrSize ); // sizeof(void*) of system that created the savegame, 4 on 32bit systems, 8 on 64bit systems - savegame.ReadShort( byteorder ); // SDL_LIL_ENDIAN or SDL_BIG_ENDIAN - - Printf( "Savegame was created by %s on %s %s. BuildNumber was %d, savegameversion %d\n", - engineVersion.c_str(), osType.c_str(), cpuArch.c_str(), savegame.GetBuildNumber(), - savegame.GetInternalSavegameVersion() ); - - // right now I have no further use for this information, but in the future - // it can be used for quirks for (then-) old savegames - } - // DG end - - // Create the list of all objects in the game - savegame.CreateObjects(); - - // Load the idProgram, also checking to make sure scripting hasn't changed since the savegame - if ( program.Restore( &savegame ) == false ) { - - // Abort the load process, and let the session know so that it can restart the level - // with the player persistent data. - savegame.DeleteObjects(); - program.Restart(); - - return false; - } - - // load the map needed for this savegame - LoadMap( mapName, 0 ); - - savegame.ReadInt( i ); - g_skill.SetInteger( i ); - - // precache the player - FindEntityDef( "player_doommarine", false ); - - // precache any media specified in the map - for ( i = 0; i < mapFile->GetNumEntities(); i++ ) { - idMapEntity *mapEnt = mapFile->GetEntity( i ); - - if ( !InhibitEntitySpawn( mapEnt->epairs ) ) { - CacheDictionaryMedia( &mapEnt->epairs ); - const char *classname; - if ( mapEnt->epairs.GetString( "classname", "", &classname ) ) { - FindEntityDef( classname, false ); - } - } - } - - savegame.ReadDict( &si ); - SetServerInfo( si ); - - savegame.ReadInt( numClients ); - for( i = 0; i < numClients; i++ ) { - savegame.ReadDict( &userInfo[ i ] ); - savegame.ReadUsercmd( usercmds[ i ] ); - savegame.ReadDict( &persistentPlayerInfo[ i ] ); - } - - for( i = 0; i < MAX_GENTITIES; i++ ) { - savegame.ReadObject( reinterpret_cast( entities[ i ] ) ); - savegame.ReadInt( spawnIds[ i ] ); - - // restore the entityNumber - if ( entities[ i ] != NULL ) { - entities[ i ]->entityNumber = i; - } - } - - savegame.ReadInt( firstFreeIndex ); - savegame.ReadInt( num_entities ); - - // enityHash is restored by idEntity::Restore setting the entity name. - - savegame.ReadObject( reinterpret_cast( world ) ); - - savegame.ReadInt( num ); - for( i = 0; i < num; i++ ) { - savegame.ReadObject( reinterpret_cast( ent ) ); - assert( ent ); - if ( ent ) { - ent->spawnNode.AddToEnd( spawnedEntities ); - } - } - - savegame.ReadInt( num ); - for( i = 0; i < num; i++ ) { - savegame.ReadObject( reinterpret_cast( ent ) ); - assert( ent ); - if ( ent ) { - ent->activeNode.AddToEnd( activeEntities ); - } - } - - savegame.ReadInt( numEntitiesToDeactivate ); - savegame.ReadBool( sortPushers ); - savegame.ReadBool( sortTeamMasters ); - savegame.ReadDict( &persistentLevelInfo ); - - for( i = 0; i < MAX_GLOBAL_SHADER_PARMS; i++ ) { - savegame.ReadFloat( globalShaderParms[ i ] ); - } - - savegame.ReadInt( i ); - random.SetSeed( i ); - - savegame.ReadObject( reinterpret_cast( frameCommandThread ) ); - - // clip - // push - // pvs - - // testmodel = "" - // testFx = "" - - savegame.ReadString( sessionCommand ); - - // FIXME: save smoke particles - - savegame.ReadInt( cinematicSkipTime ); - savegame.ReadInt( cinematicStopTime ); - savegame.ReadInt( cinematicMaxSkipTime ); - savegame.ReadBool( inCinematic ); - savegame.ReadBool( skipCinematic ); - - savegame.ReadBool( isMultiplayer ); - savegame.ReadInt( (int &)gameType ); - - savegame.ReadInt( framenum ); - savegame.ReadInt( previousTime ); - savegame.ReadInt( time ); - -#ifdef _D3XP - savegame.ReadInt( msec ); -#endif - - savegame.ReadInt( vacuumAreaNum ); - - savegame.ReadInt( entityDefBits ); - savegame.ReadBool( isServer ); - savegame.ReadBool( isClient ); - - savegame.ReadInt( localClientNum ); - - // snapshotEntities is used for multiplayer only - - savegame.ReadInt( realClientTime ); - savegame.ReadBool( isNewFrame ); - savegame.ReadFloat( clientSmoothing ); - -#ifdef _D3XP - portalSkyEnt.Restore( &savegame ); - savegame.ReadBool( portalSkyActive ); - - fast.Restore( &savegame ); - slow.Restore( &savegame ); - - int blah; - savegame.ReadInt( blah ); - slowmoState = (slowmoState_t)blah; - - savegame.ReadFloat( slowmoMsec ); - savegame.ReadBool( quickSlowmoReset ); - - if ( slowmoState == SLOWMO_STATE_OFF ) { - if ( gameSoundWorld ) { - gameSoundWorld->SetSlowmo( false ); - } - } - else { - if ( gameSoundWorld ) { - gameSoundWorld->SetSlowmo( true ); - } - } - if ( gameSoundWorld ) { - gameSoundWorld->SetSlowmoSpeed( slowmoMsec / (float)USERCMD_MSEC ); - } -#endif - - savegame.ReadBool( mapCycleLoaded ); - savegame.ReadInt( spawnCount ); - - savegame.ReadInt( num ); - if ( num ) { - if ( num != gameRenderWorld->NumAreas() ) { - savegame.Error( "idGameLocal::InitFromSaveGame: number of areas in map differs from save game." ); - } - - locationEntities = new idLocationEntity *[ num ]; - for( i = 0; i < num; i++ ) { - savegame.ReadObject( reinterpret_cast( locationEntities[ i ] ) ); - } - } - - savegame.ReadObject( reinterpret_cast( camera ) ); - - savegame.ReadMaterial( globalMaterial ); - - lastAIAlertEntity.Restore( &savegame ); - savegame.ReadInt( lastAIAlertTime ); - - savegame.ReadDict( &spawnArgs ); - - savegame.ReadInt( playerPVS.i ); - savegame.ReadInt( (int &)playerPVS.h ); - savegame.ReadInt( playerConnectedAreas.i ); - savegame.ReadInt( (int &)playerConnectedAreas.h ); - - savegame.ReadVec3( gravity ); - - // gamestate is restored after restoring everything else - - savegame.ReadBool( influenceActive ); - savegame.ReadInt( nextGibTime ); - - // spawnSpots - // initialSpots - // currentInitialSpot - // newInfo - // makingBuild - // shakeSounds - - // Read out pending events - idEvent::Restore( &savegame ); - - savegame.RestoreObjects(); - - mpGame.Reset(); - - mpGame.Precache(); - - // free up any unused animations - animationLib.FlushUnusedAnims(); - - gamestate = GAMESTATE_ACTIVE; - - return true; -} - -/* -=========== -idGameLocal::MapClear -=========== -*/ -void idGameLocal::MapClear( bool clearClients ) { - int i; - - for( i = ( clearClients ? 0 : MAX_CLIENTS ); i < MAX_GENTITIES; i++ ) { - delete entities[ i ]; - // ~idEntity is in charge of setting the pointer to NULL - // it will also clear pending events for this entity - assert( !entities[ i ] ); - spawnIds[ i ] = -1; - } - - entityHash.Clear( 1024, MAX_GENTITIES ); - - if ( !clearClients ) { - // add back the hashes of the clients - for ( i = 0; i < MAX_CLIENTS; i++ ) { - if ( !entities[ i ] ) { - continue; - } - entityHash.Add( entityHash.GenerateKey( entities[ i ]->name.c_str(), true ), i ); - } - } - - delete frameCommandThread; - frameCommandThread = NULL; - - if ( editEntities ) { - delete editEntities; - editEntities = NULL; - } - - delete[] locationEntities; - locationEntities = NULL; -} - -/* -=========== -idGameLocal::MapShutdown -============ -*/ -void idGameLocal::MapShutdown( void ) { - Printf( "----- Game Map Shutdown -----\n" ); - - gamestate = GAMESTATE_SHUTDOWN; - - if ( gameRenderWorld ) { - // clear any debug lines, text, and polygons - gameRenderWorld->DebugClearLines( 0 ); - gameRenderWorld->DebugClearPolygons( 0 ); - } - - // clear out camera if we're in a cinematic - if ( inCinematic ) { - camera = NULL; - inCinematic = false; - } - - MapClear( true ); - - // reset the script to the state it was before the map was started - program.Restart(); - - if ( smokeParticles ) { - smokeParticles->Shutdown(); - } - - pvs.Shutdown(); - - clip.Shutdown(); - idClipModel::ClearTraceModelCache(); - - ShutdownAsyncNetwork(); - - mapFileName.Clear(); - - gameRenderWorld = NULL; - gameSoundWorld = NULL; - - gamestate = GAMESTATE_NOMAP; -} - -/* -=================== -idGameLocal::DumpOggSounds -=================== -*/ -void idGameLocal::DumpOggSounds( void ) { - int i, j, k, size, totalSize; - idFile *file; - idStrList oggSounds, weaponSounds; - const idSoundShader *soundShader; - const soundShaderParms_t *parms; - idStr soundName; - - for ( i = 0; i < declManager->GetNumDecls( DECL_SOUND ); i++ ) { - soundShader = static_cast(declManager->DeclByIndex( DECL_SOUND, i, false )); - parms = soundShader->GetParms(); - - if ( soundShader->EverReferenced() && soundShader->GetState() != DS_DEFAULTED ) { - - const_cast(soundShader)->EnsureNotPurged(); - - for ( j = 0; j < soundShader->GetNumSounds(); j++ ) { - soundName = soundShader->GetSound( j ); - soundName.BackSlashesToSlashes(); - -#ifdef _D3XP - // D3XP :: don't add sounds that are in Doom 3's pak files - if ( fileSystem->FileIsInPAK( soundName ) ) { - continue; - } else { - // Also check for a pre-ogg'd version in the pak file - idStr testName = soundName; - - testName.SetFileExtension( ".ogg" ); - if ( fileSystem->FileIsInPAK( testName ) ) { - continue; - } - } -#endif - // don't OGG sounds that cause a shake because that would - // cause continuous seeking on the OGG file which is expensive - if ( parms->shakes != 0.0f ) { - shakeSounds.AddUnique( soundName ); - continue; - } - - // if not voice over or combat chatter - if ( soundName.Find( "/vo/", false ) == -1 && - soundName.Find( "/combat_chatter/", false ) == -1 && - soundName.Find( "/bfgcarnage/", false ) == -1 && - soundName.Find( "/enpro/", false ) == - 1 && - soundName.Find( "/soulcube/energize_01.wav", false ) == -1 ) { - // don't OGG weapon sounds - if ( soundName.Find( "weapon", false ) != -1 || - soundName.Find( "gun", false ) != -1 || - soundName.Find( "bullet", false ) != -1 || - soundName.Find( "bfg", false ) != -1 || - soundName.Find( "plasma", false ) != -1 ) { - weaponSounds.AddUnique( soundName ); - continue; - } - } - - for ( k = 0; k < shakeSounds.Num(); k++ ) { - if ( shakeSounds[k].IcmpPath( soundName ) == 0 ) { - break; - } - } - if ( k < shakeSounds.Num() ) { - continue; - } - - oggSounds.AddUnique( soundName ); - } - } - } - - file = fileSystem->OpenFileWrite( "makeogg.bat", "fs_savepath" ); - if ( file == NULL ) { - common->Warning( "Couldn't open makeogg.bat" ); - return; - } - - // list all the shake sounds - totalSize = 0; - for ( i = 0; i < shakeSounds.Num(); i++ ) { - size = fileSystem->ReadFile( shakeSounds[i], NULL, NULL ); - totalSize += size; - shakeSounds[i].Replace( "/", "\\" ); - file->Printf( "echo \"%s\" (%d kB)\n", shakeSounds[i].c_str(), size >> 10 ); - } - file->Printf( "echo %d kB in shake sounds\n\n\n", totalSize >> 10 ); - - // list all the weapon sounds - totalSize = 0; - for ( i = 0; i < weaponSounds.Num(); i++ ) { - size = fileSystem->ReadFile( weaponSounds[i], NULL, NULL ); - totalSize += size; - weaponSounds[i].Replace( "/", "\\" ); - file->Printf( "echo \"%s\" (%d kB)\n", weaponSounds[i].c_str(), size >> 10 ); - } - file->Printf( "echo %d kB in weapon sounds\n\n\n", totalSize >> 10 ); - - // list commands to convert all other sounds to ogg - totalSize = 0; - for ( i = 0; i < oggSounds.Num(); i++ ) { - size = fileSystem->ReadFile( oggSounds[i], NULL, NULL ); - totalSize += size; - oggSounds[i].Replace( "/", "\\" ); - file->Printf( "z:\\d3xp\\ogg\\oggenc -q 0 \"%s\\d3xp\\%s\"\n", cvarSystem->GetCVarString( "fs_basepath" ), oggSounds[i].c_str() ); - file->Printf( "del \"%s\\d3xp\\%s\"\n", cvarSystem->GetCVarString( "fs_basepath" ), oggSounds[i].c_str() ); - } - file->Printf( "\n\necho %d kB in OGG sounds\n\n\n", totalSize >> 10 ); - - fileSystem->CloseFile( file ); - - shakeSounds.Clear(); -} - -/* -=================== -idGameLocal::GetShakeSounds -=================== -*/ -void idGameLocal::GetShakeSounds( const idDict *dict ) { - const idSoundShader *soundShader; - const char *soundShaderName; - idStr soundName; - - if ( dict->GetString( "s_shader", "", &soundShaderName ) - && dict->GetFloat( "s_shakes" ) != 0.0f ) - { - soundShader = declManager->FindSound( soundShaderName ); - - for ( int i = 0; i < soundShader->GetNumSounds(); i++ ) { - soundName = soundShader->GetSound( i ); - soundName.BackSlashesToSlashes(); - - shakeSounds.AddUnique( soundName ); - } - } -} - -/* -=================== -idGameLocal::CacheDictionaryMedia - -This is called after parsing an EntityDef and for each entity spawnArgs before -merging the entitydef. It could be done post-merge, but that would -avoid the fast pre-cache check associated with each entityDef -=================== -*/ -void idGameLocal::CacheDictionaryMedia( const idDict *dict ) { - const idKeyValue *kv; - - if ( dict == NULL ) { - if ( cvarSystem->GetCVarBool( "com_makingBuild") ) { - DumpOggSounds(); - } - return; - } - - if ( cvarSystem->GetCVarBool( "com_makingBuild" ) ) { - GetShakeSounds( dict ); - } - - kv = dict->MatchPrefix( "model" ); - while( kv ) { - if ( kv->GetValue().Length() ) { - declManager->MediaPrint( "Precaching model %s\n", kv->GetValue().c_str() ); - // precache model/animations - if ( declManager->FindType( DECL_MODELDEF, kv->GetValue(), false ) == NULL ) { - // precache the render model - renderModelManager->FindModel( kv->GetValue() ); - // precache .cm files only - collisionModelManager->LoadModel( kv->GetValue(), true ); - } - } - kv = dict->MatchPrefix( "model", kv ); - } - - kv = dict->FindKey( "s_shader" ); - if ( kv && kv->GetValue().Length() ) { - declManager->FindType( DECL_SOUND, kv->GetValue() ); - } - - kv = dict->MatchPrefix( "snd", NULL ); - while( kv ) { - if ( kv->GetValue().Length() ) { - declManager->FindType( DECL_SOUND, kv->GetValue() ); - } - kv = dict->MatchPrefix( "snd", kv ); - } - - - kv = dict->MatchPrefix( "gui", NULL ); - while( kv ) { - if ( kv->GetValue().Length() ) { - if ( !idStr::Icmp( kv->GetKey(), "gui_noninteractive" ) - || !idStr::Icmpn( kv->GetKey(), "gui_parm", 8 ) - || !idStr::Icmp( kv->GetKey(), "gui_inventory" ) ) { - // unfortunate flag names, they aren't actually a gui - } else { - declManager->MediaPrint( "Precaching gui %s\n", kv->GetValue().c_str() ); - idUserInterface *gui = uiManager->Alloc(); - if ( gui ) { - gui->InitFromFile( kv->GetValue() ); - uiManager->DeAlloc( gui ); - } - } - } - kv = dict->MatchPrefix( "gui", kv ); - } - - kv = dict->FindKey( "texture" ); - if ( kv && kv->GetValue().Length() ) { - declManager->FindType( DECL_MATERIAL, kv->GetValue() ); - } - - kv = dict->MatchPrefix( "mtr", NULL ); - while( kv ) { - if ( kv->GetValue().Length() ) { - declManager->FindType( DECL_MATERIAL, kv->GetValue() ); - } - kv = dict->MatchPrefix( "mtr", kv ); - } - - // handles hud icons - kv = dict->MatchPrefix( "inv_icon", NULL ); - while ( kv ) { - if ( kv->GetValue().Length() ) { - declManager->FindType( DECL_MATERIAL, kv->GetValue() ); - } - kv = dict->MatchPrefix( "inv_icon", kv ); - } - - // handles teleport fx.. this is not ideal but the actual decision on which fx to use - // is handled by script code based on the teleport number - kv = dict->MatchPrefix( "teleport", NULL ); - if ( kv && kv->GetValue().Length() ) { - int teleportType = atoi( kv->GetValue() ); - const char *p = ( teleportType ) ? va( "fx/teleporter%i.fx", teleportType ) : "fx/teleporter.fx"; - declManager->FindType( DECL_FX, p ); - } - - kv = dict->MatchPrefix( "fx", NULL ); - while( kv ) { - if ( kv->GetValue().Length() ) { - declManager->MediaPrint( "Precaching fx %s\n", kv->GetValue().c_str() ); - declManager->FindType( DECL_FX, kv->GetValue() ); - } - kv = dict->MatchPrefix( "fx", kv ); - } - - kv = dict->MatchPrefix( "smoke", NULL ); - while( kv ) { - if ( kv->GetValue().Length() ) { - idStr prtName = kv->GetValue(); - int dash = prtName.Find('-'); - if ( dash > 0 ) { - prtName = prtName.Left( dash ); - } - declManager->FindType( DECL_PARTICLE, prtName ); - } - kv = dict->MatchPrefix( "smoke", kv ); - } - - kv = dict->MatchPrefix( "skin", NULL ); - while( kv ) { - if ( kv->GetValue().Length() ) { - declManager->MediaPrint( "Precaching skin %s\n", kv->GetValue().c_str() ); - declManager->FindType( DECL_SKIN, kv->GetValue() ); - } - kv = dict->MatchPrefix( "skin", kv ); - } - - kv = dict->MatchPrefix( "def", NULL ); - while( kv ) { - if ( kv->GetValue().Length() ) { - FindEntityDef( kv->GetValue().c_str(), false ); - } - kv = dict->MatchPrefix( "def", kv ); - } - - kv = dict->MatchPrefix( "pda_name", NULL ); - while( kv ) { - if ( kv->GetValue().Length() ) { - declManager->FindType( DECL_PDA, kv->GetValue().c_str(), false ); - } - kv = dict->MatchPrefix( "pda_name", kv ); - } - - kv = dict->MatchPrefix( "video", NULL ); - while( kv ) { - if ( kv->GetValue().Length() ) { - declManager->FindType( DECL_VIDEO, kv->GetValue().c_str(), false ); - } - kv = dict->MatchPrefix( "video", kv ); - } - - kv = dict->MatchPrefix( "audio", NULL ); - while( kv ) { - if ( kv->GetValue().Length() ) { - declManager->FindType( DECL_AUDIO, kv->GetValue().c_str(), false ); - } - kv = dict->MatchPrefix( "audio", kv ); - } -} - -/* -=========== -idGameLocal::InitScriptForMap -============ -*/ -void idGameLocal::InitScriptForMap( void ) { - // create a thread to run frame commands on - frameCommandThread = new idThread(); - frameCommandThread->ManualDelete(); - frameCommandThread->SetThreadName( "frameCommands" ); - - // run the main game script function (not the level specific main) - const function_t *func = program.FindFunction( SCRIPT_DEFAULTFUNC ); - if ( func != NULL ) { - idThread *thread = new idThread( func ); - if ( thread->Start() ) { - // thread has finished executing, so delete it - delete thread; - } - } -} - -/* -=========== -idGameLocal::SpawnPlayer -============ -*/ -void idGameLocal::SpawnPlayer( int clientNum ) { - idEntity *ent; - idDict args; - - // they can connect - Printf( "SpawnPlayer: %i\n", clientNum ); - - args.SetInt( "spawn_entnum", clientNum ); - args.Set( "name", va( "player%d", clientNum + 1 ) ); -#ifdef CTF - if ( isMultiplayer && gameType != GAME_CTF ) - args.Set( "classname", "player_doommarine_mp" ); - else if ( isMultiplayer && gameType == GAME_CTF ) - args.Set( "classname", "player_doommarine_ctf" ); - else - args.Set( "classname", "player_doommarine" ); -#else - args.Set( "classname", isMultiplayer ? "player_doommarine_mp" : "player_doommarine" ); -#endif - if ( !SpawnEntityDef( args, &ent ) || !entities[ clientNum ] ) { - Error( "Failed to spawn player as '%s'", args.GetString( "classname" ) ); - } - - // make sure it's a compatible class - if ( !ent->IsType( idPlayer::Type ) ) { - Error( "'%s' spawned the player as a '%s'. Player spawnclass must be a subclass of idPlayer.", args.GetString( "classname" ), ent->GetClassname() ); - } - - if ( clientNum >= numClients ) { - numClients = clientNum + 1; - } - - mpGame.SpawnPlayer( clientNum ); -} - -/* -================ -idGameLocal::GetClientByNum -================ -*/ -idPlayer *idGameLocal::GetClientByNum( int current ) const { - if ( current < 0 || current >= numClients ) { - current = 0; - } - if ( entities[current] ) { - return static_cast( entities[ current ] ); - } - return NULL; -} - -/* -================ -idGameLocal::GetClientByName -================ -*/ -idPlayer *idGameLocal::GetClientByName( const char *name ) const { - int i; - idEntity *ent; - for ( i = 0 ; i < numClients ; i++ ) { - ent = entities[ i ]; - if ( ent && ent->IsType( idPlayer::Type ) ) { - if ( idStr::IcmpNoColor( name, userInfo[ i ].GetString( "ui_name" ) ) == 0 ) { - return static_cast( ent ); - } - } - } - return NULL; -} - -/* -================ -idGameLocal::GetClientByCmdArgs -================ -*/ -idPlayer *idGameLocal::GetClientByCmdArgs( const idCmdArgs &args ) const { - idPlayer *player; - idStr client = args.Argv( 1 ); - if ( !client.Length() ) { - return NULL; - } - // we don't allow numeric ui_name so this can't go wrong - if ( client.IsNumeric() ) { - player = GetClientByNum( atoi( client.c_str() ) ); - } else { - player = GetClientByName( client.c_str() ); - } - if ( !player ) { - common->Printf( "Player '%s' not found\n", client.c_str() ); - } - return player; -} - -/* -================ -idGameLocal::GetNextClientNum -================ -*/ -int idGameLocal::GetNextClientNum( int _current ) const { - int i, current; - - current = 0; - for ( i = 0; i < numClients; i++) { - current = ( _current + i + 1 ) % numClients; - if ( entities[ current ] && entities[ current ]->IsType( idPlayer::Type ) ) { - return current; - } - } - - return current; -} - -/* -================ -idGameLocal::GetLocalPlayer - -Nothing in the game tic should EVER make a decision based on what the -local client number is, it shouldn't even be aware that there is a -draw phase even happening. This just returns client 0, which will -be correct for single player. -================ -*/ -idPlayer *idGameLocal::GetLocalPlayer() const { - if ( localClientNum < 0 ) { - return NULL; - } - - if ( !entities[ localClientNum ] || !entities[ localClientNum ]->IsType( idPlayer::Type ) ) { - // not fully in game yet - return NULL; - } - return static_cast( entities[ localClientNum ] ); -} - -/* -================ -idGameLocal::SetupClientPVS -================ -*/ -pvsHandle_t idGameLocal::GetClientPVS( idPlayer *player, pvsType_t type ) { - if ( player->GetPrivateCameraView() ) { - return pvs.SetupCurrentPVS( player->GetPrivateCameraView()->GetPVSAreas(), player->GetPrivateCameraView()->GetNumPVSAreas() ); - } else if ( camera ) { - return pvs.SetupCurrentPVS( camera->GetPVSAreas(), camera->GetNumPVSAreas() ); - } else { - return pvs.SetupCurrentPVS( player->GetPVSAreas(), player->GetNumPVSAreas() ); - } -} - -/* -================ -idGameLocal::SetupPlayerPVS -================ -*/ -void idGameLocal::SetupPlayerPVS( void ) { - int i; - idEntity * ent; - idPlayer * player; - pvsHandle_t otherPVS, newPVS; - - playerPVS.i = -1; - for ( i = 0; i < numClients; i++ ) { - ent = entities[i]; - if ( !ent || !ent->IsType( idPlayer::Type ) ) { - continue; - } - - player = static_cast(ent); - - if ( playerPVS.i == -1 ) { - playerPVS = GetClientPVS( player, PVS_NORMAL ); - } else { - otherPVS = GetClientPVS( player, PVS_NORMAL ); - newPVS = pvs.MergeCurrentPVS( playerPVS, otherPVS ); - pvs.FreeCurrentPVS( playerPVS ); - pvs.FreeCurrentPVS( otherPVS ); - playerPVS = newPVS; - } - - if ( playerConnectedAreas.i == -1 ) { - playerConnectedAreas = GetClientPVS( player, PVS_CONNECTED_AREAS ); - } else { - otherPVS = GetClientPVS( player, PVS_CONNECTED_AREAS ); - newPVS = pvs.MergeCurrentPVS( playerConnectedAreas, otherPVS ); - pvs.FreeCurrentPVS( playerConnectedAreas ); - pvs.FreeCurrentPVS( otherPVS ); - playerConnectedAreas = newPVS; - } - -#ifdef _D3XP - // if portalSky is preset, then merge into pvs so we get rotating brushes, etc - if ( portalSkyEnt.GetEntity() ) { - idEntity *skyEnt = portalSkyEnt.GetEntity(); - - otherPVS = pvs.SetupCurrentPVS( skyEnt->GetPVSAreas(), skyEnt->GetNumPVSAreas() ); - newPVS = pvs.MergeCurrentPVS( playerPVS, otherPVS ); - pvs.FreeCurrentPVS( playerPVS ); - pvs.FreeCurrentPVS( otherPVS ); - playerPVS = newPVS; - - otherPVS = pvs.SetupCurrentPVS( skyEnt->GetPVSAreas(), skyEnt->GetNumPVSAreas() ); - newPVS = pvs.MergeCurrentPVS( playerConnectedAreas, otherPVS ); - pvs.FreeCurrentPVS( playerConnectedAreas ); - pvs.FreeCurrentPVS( otherPVS ); - playerConnectedAreas = newPVS; - } -#endif - } -} - -/* -================ -idGameLocal::FreePlayerPVS -================ -*/ -void idGameLocal::FreePlayerPVS( void ) { - if ( playerPVS.i != -1 ) { - pvs.FreeCurrentPVS( playerPVS ); - playerPVS.i = -1; - } - if ( playerConnectedAreas.i != -1 ) { - pvs.FreeCurrentPVS( playerConnectedAreas ); - playerConnectedAreas.i = -1; - } -} - -/* -================ -idGameLocal::InPlayerPVS - - should only be called during entity thinking and event handling -================ -*/ -bool idGameLocal::InPlayerPVS( idEntity *ent ) const { - if ( playerPVS.i == -1 ) { - return false; - } - return pvs.InCurrentPVS( playerPVS, ent->GetPVSAreas(), ent->GetNumPVSAreas() ); -} - -/* -================ -idGameLocal::InPlayerConnectedArea - - should only be called during entity thinking and event handling -================ -*/ -bool idGameLocal::InPlayerConnectedArea( idEntity *ent ) const { - if ( playerConnectedAreas.i == -1 ) { - return false; - } - return pvs.InCurrentPVS( playerConnectedAreas, ent->GetPVSAreas(), ent->GetNumPVSAreas() ); -} - -/* -================ -idGameLocal::UpdateGravity -================ -*/ -void idGameLocal::UpdateGravity( void ) { - idEntity *ent; - - if ( g_gravity.IsModified() ) { - if ( g_gravity.GetFloat() == 0.0f ) { - g_gravity.SetFloat( 1.0f ); - } - gravity.Set( 0, 0, -g_gravity.GetFloat() ); - - // update all physics objects - for( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) { - if ( ent->IsType( idAFEntity_Generic::Type ) ) { - idPhysics *phys = ent->GetPhysics(); - if ( phys ) { - phys->SetGravity( gravity ); - } - } - } - g_gravity.ClearModified(); - } -} - -/* -================ -idGameLocal::GetGravity -================ -*/ -const idVec3 &idGameLocal::GetGravity( void ) const { - return gravity; -} - -/* -================ -idGameLocal::SortActiveEntityList - - Sorts the active entity list such that pushing entities come first, - actors come next and physics team slaves appear after their master. -================ -*/ -void idGameLocal::SortActiveEntityList( void ) { - idEntity *ent, *next_ent, *master, *part; - - // if the active entity list needs to be reordered to place physics team masters at the front - if ( sortTeamMasters ) { - for ( ent = activeEntities.Next(); ent != NULL; ent = next_ent ) { - next_ent = ent->activeNode.Next(); - master = ent->GetTeamMaster(); - if ( master && master == ent ) { - ent->activeNode.Remove(); - ent->activeNode.AddToFront( activeEntities ); - } - } - } - - // if the active entity list needs to be reordered to place pushers at the front - if ( sortPushers ) { - - for ( ent = activeEntities.Next(); ent != NULL; ent = next_ent ) { - next_ent = ent->activeNode.Next(); - master = ent->GetTeamMaster(); - if ( !master || master == ent ) { - // check if there is an actor on the team - for ( part = ent; part != NULL; part = part->GetNextTeamEntity() ) { - if ( part->GetPhysics()->IsType( idPhysics_Actor::Type ) ) { - break; - } - } - // if there is an actor on the team - if ( part ) { - ent->activeNode.Remove(); - ent->activeNode.AddToFront( activeEntities ); - } - } - } - - for ( ent = activeEntities.Next(); ent != NULL; ent = next_ent ) { - next_ent = ent->activeNode.Next(); - master = ent->GetTeamMaster(); - if ( !master || master == ent ) { - // check if there is an entity on the team using parametric physics - for ( part = ent; part != NULL; part = part->GetNextTeamEntity() ) { - if ( part->GetPhysics()->IsType( idPhysics_Parametric::Type ) ) { - break; - } - } - // if there is an entity on the team using parametric physics - if ( part ) { - ent->activeNode.Remove(); - ent->activeNode.AddToFront( activeEntities ); - } - } - } - } - - sortTeamMasters = false; - sortPushers = false; -} - -#ifdef _D3XP -/* -================ -idGameLocal::RunTimeGroup2 -================ -*/ -void idGameLocal::RunTimeGroup2() { - idEntity *ent; - int num = 0; - - fast.Increment(); - fast.Get( time, previousTime, msec, framenum, realClientTime ); - - for( ent = activeEntities.Next(); ent != NULL; ent = ent->activeNode.Next() ) { - if ( ent->timeGroup != TIME_GROUP2 ) { - continue; - } - - ent->Think(); - num++; - } - - slow.Get( time, previousTime, msec, framenum, realClientTime ); -} -#endif - -/* -================ -idGameLocal::RunFrame -================ -*/ -gameReturn_t idGameLocal::RunFrame( const usercmd_t *clientCmds ) { - idEntity * ent; - int num; - float ms; - idTimer timer_think, timer_events, timer_singlethink; - gameReturn_t ret; - idPlayer *player; - const renderView_t *view; - -#ifdef _DEBUG - if ( isMultiplayer ) { - assert( !isClient ); - } -#endif - - player = GetLocalPlayer(); - -#ifdef _D3XP - ComputeSlowMsec(); - - slow.Get( time, previousTime, msec, framenum, realClientTime ); - msec = slowmoMsec; -#endif - - if ( !isMultiplayer && g_stopTime.GetBool() ) { - // clear any debug lines from a previous frame - gameRenderWorld->DebugClearLines( time + 1 ); - - // set the user commands for this frame - memcpy( usercmds, clientCmds, numClients * sizeof( usercmds[ 0 ] ) ); - - if ( player ) { - player->Think(); - } - } else do { - // update the game time - framenum++; - previousTime = time; - time += msec; - realClientTime = time; - -#ifdef _D3XP - slow.Set( time, previousTime, msec, framenum, realClientTime ); -#endif - -#ifdef GAME_DLL - // allow changing SIMD usage on the fly - if ( com_forceGenericSIMD.IsModified() ) { - idSIMD::InitProcessor( "game", com_forceGenericSIMD.GetBool() ); - } -#endif - - // make sure the random number counter is used each frame so random events - // are influenced by the player's actions - random.RandomInt(); - - if ( player ) { - // update the renderview so that any gui videos play from the right frame - view = player->GetRenderView(); - if ( view ) { - gameRenderWorld->SetRenderView( view ); - } - } - - // clear any debug lines from a previous frame - gameRenderWorld->DebugClearLines( time ); - - // clear any debug polygons from a previous frame - gameRenderWorld->DebugClearPolygons( time ); - - // set the user commands for this frame - memcpy( usercmds, clientCmds, numClients * sizeof( usercmds[ 0 ] ) ); - - // free old smoke particles - smokeParticles->FreeSmokes(); - - // process events on the server - ServerProcessEntityNetworkEventQueue(); - - // update our gravity vector if needed. - UpdateGravity(); - - // create a merged pvs for all players - SetupPlayerPVS(); - - // sort the active entity list - SortActiveEntityList(); - - timer_think.Clear(); - timer_think.Start(); - - // let entities think - if ( g_timeentities.GetFloat() ) { - num = 0; - for( ent = activeEntities.Next(); ent != NULL; ent = ent->activeNode.Next() ) { - if ( g_cinematic.GetBool() && inCinematic && !ent->cinematic ) { - ent->GetPhysics()->UpdateTime( time ); - continue; - } - timer_singlethink.Clear(); - timer_singlethink.Start(); - ent->Think(); - timer_singlethink.Stop(); - ms = timer_singlethink.Milliseconds(); - if ( ms >= g_timeentities.GetFloat() ) { - Printf( "%d: entity '%s': %f ms\n", time, ent->name.c_str(), ms ); - } - num++; - } - } else { - if ( inCinematic ) { - num = 0; - for( ent = activeEntities.Next(); ent != NULL; ent = ent->activeNode.Next() ) { - if ( g_cinematic.GetBool() && !ent->cinematic ) { - ent->GetPhysics()->UpdateTime( time ); - continue; - } - ent->Think(); - num++; - } - } else { - num = 0; - for( ent = activeEntities.Next(); ent != NULL; ent = ent->activeNode.Next() ) { -#ifdef _D3XP - if ( ent->timeGroup != TIME_GROUP1 ) { - continue; - } -#endif - ent->Think(); - num++; - } - } - } - -#ifdef _D3XP - RunTimeGroup2(); -#endif - - // remove any entities that have stopped thinking - if ( numEntitiesToDeactivate ) { - idEntity *next_ent; - int c = 0; - for( ent = activeEntities.Next(); ent != NULL; ent = next_ent ) { - next_ent = ent->activeNode.Next(); - if ( !ent->thinkFlags ) { - ent->activeNode.Remove(); - c++; - } - } - //assert( numEntitiesToDeactivate == c ); - numEntitiesToDeactivate = 0; - } - - timer_think.Stop(); - timer_events.Clear(); - timer_events.Start(); - - // service any pending events - idEvent::ServiceEvents(); - -#ifdef _D3XP - // service pending fast events - fast.Get( time, previousTime, msec, framenum, realClientTime ); - idEvent::ServiceFastEvents(); - slow.Get( time, previousTime, msec, framenum, realClientTime ); -#endif - - timer_events.Stop(); - - // free the player pvs - FreePlayerPVS(); - - // do multiplayer related stuff - if ( isMultiplayer ) { - mpGame.Run(); - } - - // display how long it took to calculate the current game frame - if ( g_frametime.GetBool() ) { - Printf( "game %d: all:%u th:%u ev:%u %d ents \n", - time, timer_think.Milliseconds() + timer_events.Milliseconds(), - timer_think.Milliseconds(), timer_events.Milliseconds(), num ); - } - - // build the return value - ret.consistencyHash = 0; - ret.sessionCommand[0] = 0; - - if ( !isMultiplayer && player ) { - ret.health = player->health; - ret.heartRate = player->heartRate; - ret.stamina = idMath::FtoiFast( player->stamina ); - // combat is a 0-100 value based on lastHitTime and lastDmgTime - // each make up 50% of the time spread over 10 seconds - ret.combat = 0; - if ( player->lastDmgTime > 0 && time < player->lastDmgTime + 10000 ) { - ret.combat += 50.0f * (float) ( time - player->lastDmgTime ) / 10000; - } - if ( player->lastHitTime > 0 && time < player->lastHitTime + 10000 ) { - ret.combat += 50.0f * (float) ( time - player->lastHitTime ) / 10000; - } - } - - // see if a target_sessionCommand has forced a changelevel - if ( sessionCommand.Length() ) { - idStr::Copynz( ret.sessionCommand, sessionCommand, sizeof( ret.sessionCommand ) ); - break; - } - - // make sure we don't loop forever when skipping a cinematic - if ( skipCinematic && ( time > cinematicMaxSkipTime ) ) { - Warning( "Exceeded maximum cinematic skip length. Cinematic may be looping infinitely." ); - skipCinematic = false; - break; - } - } while( ( inCinematic || ( time < cinematicStopTime ) ) && skipCinematic ); - - ret.syncNextGameFrame = skipCinematic; - if ( skipCinematic ) { - soundSystem->SetMute( false ); - skipCinematic = false; - } - - // show any debug info for this frame - RunDebugInfo(); - D_DrawDebugLines(); - - return ret; -} - - -/* -====================================================================== - - Game view drawing - -====================================================================== -*/ - -/* -==================== -idGameLocal::CalcFov - -Calculates the horizontal and vertical field of view based on a horizontal field of view and custom aspect ratio -==================== -*/ -void idGameLocal::CalcFov( float base_fov, float &fov_x, float &fov_y ) const { - float x; - float y; - float ratio_x; - float ratio_y; - - // first, calculate the vertical fov based on a 640x480 view - x = 640.0f / tan( base_fov / 360.0f * idMath::PI ); - y = atan2( 480.0f, x ); - fov_y = y * 360.0f / idMath::PI; - - // FIXME: somehow, this is happening occasionally - assert( fov_y > 0 ); - if ( fov_y <= 0 ) { - Error( "idGameLocal::CalcFov: bad result, fov_y == %f, base_fov == %f", fov_y, base_fov ); - } - - switch( r_aspectRatio.GetInteger() ) { - default : - case -1 : - // auto mode => use aspect ratio from resolution, assuming screen's pixels are squares - ratio_x = renderSystem->GetScreenWidth(); - ratio_y = renderSystem->GetScreenHeight(); - if(ratio_x <= 0.0f || ratio_y <= 0.0f) - { - // for some reason (maybe this is a dedicated server?) GetScreenWidth()/Height() - // returned 0. Assume default 4:3 to avoid assert()/Error() below. - fov_x = base_fov; - return; - } - break; - case 0 : - // 4:3 - fov_x = base_fov; - return; - break; - - case 1 : - // 16:9 - ratio_x = 16.0f; - ratio_y = 9.0f; - break; - - case 2 : - // 16:10 - ratio_x = 16.0f; - ratio_y = 10.0f; - break; - } - - y = ratio_y / tan( fov_y / 360.0f * idMath::PI ); - fov_x = atan2( ratio_x, y ) * 360.0f / idMath::PI; - - if ( fov_x < base_fov ) { - fov_x = base_fov; - x = ratio_x / tan( fov_x / 360.0f * idMath::PI ); - fov_y = atan2( ratio_y, x ) * 360.0f / idMath::PI; - } - - // FIXME: somehow, this is happening occasionally - assert( ( fov_x > 0 ) && ( fov_y > 0 ) ); - if ( ( fov_y <= 0 ) || ( fov_x <= 0 ) ) { - Error( "idGameLocal::CalcFov: bad result" ); - } -} - -/* -================ -idGameLocal::Draw - -makes rendering and sound system calls -================ -*/ -bool idGameLocal::Draw( int clientNum ) { - if ( isMultiplayer ) { - return mpGame.Draw( clientNum ); - } - - idPlayer *player = static_cast(entities[ clientNum ]); - - if ( !player ) { - return false; - } - - // render the scene - player->playerView.RenderPlayerView( player->hud ); - - return true; -} - -/* -================ -idGameLocal::HandleESC -================ -*/ -escReply_t idGameLocal::HandleESC( idUserInterface **gui ) { - if ( isMultiplayer ) { - *gui = StartMenu(); - // we may set the gui back to NULL to hide it - return ESC_GUI; - } - idPlayer *player = GetLocalPlayer(); - if ( player ) { - if ( player->HandleESC() ) { - return ESC_IGNORE; - } else { - return ESC_MAIN; - } - } - return ESC_MAIN; -} - -/* -================ -idGameLocal::StartMenu -================ -*/ -idUserInterface* idGameLocal::StartMenu( void ) { - if ( !isMultiplayer ) { - return NULL; - } - return mpGame.StartMenu(); -} - -/* -================ -idGameLocal::HandleGuiCommands -================ -*/ -const char* idGameLocal::HandleGuiCommands( const char *menuCommand ) { - if ( !isMultiplayer ) { - return NULL; - } - return mpGame.HandleGuiCommands( menuCommand ); -} - -/* -================ -idGameLocal::HandleMainMenuCommands -================ -*/ -void idGameLocal::HandleMainMenuCommands( const char *menuCommand, idUserInterface *gui ) { } - -/* -================ -idGameLocal::GetLevelMap - - should only be used for in-game level editing -================ -*/ -idMapFile *idGameLocal::GetLevelMap( void ) { - if ( mapFile && mapFile->HasPrimitiveData()) { - return mapFile; - } - if ( !mapFileName.Length() ) { - return NULL; - } - - if ( mapFile ) { - delete mapFile; - } - - mapFile = new idMapFile; - if ( !mapFile->Parse( mapFileName ) ) { - delete mapFile; - mapFile = NULL; - } - - return mapFile; -} - -/* -================ -idGameLocal::GetMapName -================ -*/ -const char *idGameLocal::GetMapName( void ) const { - return mapFileName.c_str(); -} - -/* -================ -idGameLocal::CallFrameCommand -================ -*/ -void idGameLocal::CallFrameCommand( idEntity *ent, const function_t *frameCommand ) { - frameCommandThread->CallFunction( ent, frameCommand, true ); - frameCommandThread->Execute(); -} - -/* -================ -idGameLocal::CallObjectFrameCommand -================ -*/ -void idGameLocal::CallObjectFrameCommand( idEntity *ent, const char *frameCommand ) { - const function_t *func; - - func = ent->scriptObject.GetFunction( frameCommand ); - if ( !func ) { - if ( !ent->IsType( idTestModel::Type ) ) { - Error( "Unknown function '%s' called for frame command on entity '%s'", frameCommand, ent->name.c_str() ); - } - } else { - frameCommandThread->CallFunction( ent, func, true ); - frameCommandThread->Execute(); - } -} - -/* -================ -idGameLocal::ShowTargets -================ -*/ -void idGameLocal::ShowTargets( void ) { - idMat3 axis = GetLocalPlayer()->viewAngles.ToMat3(); - idVec3 up = axis[ 2 ] * 5.0f; - const idVec3 &viewPos = GetLocalPlayer()->GetPhysics()->GetOrigin(); - idBounds viewTextBounds( viewPos ); - idBounds viewBounds( viewPos ); - idBounds box( idVec3( -4.0f, -4.0f, -4.0f ), idVec3( 4.0f, 4.0f, 4.0f ) ); - idEntity *ent; - idEntity *target; - int i; - idBounds totalBounds; - - viewTextBounds.ExpandSelf( 128.0f ); - viewBounds.ExpandSelf( 512.0f ); - for( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) { - totalBounds = ent->GetPhysics()->GetAbsBounds(); - for( i = 0; i < ent->targets.Num(); i++ ) { - target = ent->targets[ i ].GetEntity(); - if ( target ) { - totalBounds.AddBounds( target->GetPhysics()->GetAbsBounds() ); - } - } - - if ( !viewBounds.IntersectsBounds( totalBounds ) ) { - continue; - } - - float dist; - idVec3 dir = totalBounds.GetCenter() - viewPos; - dir.NormalizeFast(); - totalBounds.RayIntersection( viewPos, dir, dist ); - float frac = ( 512.0f - dist ) / 512.0f; - if ( frac < 0.0f ) { - continue; - } - - gameRenderWorld->DebugBounds( ( ent->IsHidden() ? colorLtGrey : colorOrange ) * frac, ent->GetPhysics()->GetAbsBounds() ); - if ( viewTextBounds.IntersectsBounds( ent->GetPhysics()->GetAbsBounds() ) ) { - idVec3 center = ent->GetPhysics()->GetAbsBounds().GetCenter(); - gameRenderWorld->DrawText( ent->name.c_str(), center - up, 0.1f, colorWhite * frac, axis, 1 ); - gameRenderWorld->DrawText( ent->GetEntityDefName(), center, 0.1f, colorWhite * frac, axis, 1 ); - gameRenderWorld->DrawText( va( "#%d", ent->entityNumber ), center + up, 0.1f, colorWhite * frac, axis, 1 ); - } - - for( i = 0; i < ent->targets.Num(); i++ ) { - target = ent->targets[ i ].GetEntity(); - if ( target ) { - gameRenderWorld->DebugArrow( colorYellow * frac, ent->GetPhysics()->GetAbsBounds().GetCenter(), target->GetPhysics()->GetOrigin(), 10, 0 ); - gameRenderWorld->DebugBounds( colorGreen * frac, box, target->GetPhysics()->GetOrigin() ); - } - } - } -} - -/* -================ -idGameLocal::RunDebugInfo -================ -*/ -void idGameLocal::RunDebugInfo( void ) { - idEntity *ent; - idPlayer *player; - - player = GetLocalPlayer(); - if ( !player ) { - return; - } - - const idVec3 &origin = player->GetPhysics()->GetOrigin(); - - if ( g_showEntityInfo.GetBool() ) { - idMat3 axis = player->viewAngles.ToMat3(); - idVec3 up = axis[ 2 ] * 5.0f; - idBounds viewTextBounds( origin ); - idBounds viewBounds( origin ); - - viewTextBounds.ExpandSelf( 128.0f ); - viewBounds.ExpandSelf( 512.0f ); - for( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) { - // don't draw the worldspawn - if ( ent == world ) { - continue; - } - - // skip if the entity is very far away - if ( !viewBounds.IntersectsBounds( ent->GetPhysics()->GetAbsBounds() ) ) { - continue; - } - - const idBounds &entBounds = ent->GetPhysics()->GetAbsBounds(); - int contents = ent->GetPhysics()->GetContents(); - if ( contents & CONTENTS_BODY ) { - gameRenderWorld->DebugBounds( colorCyan, entBounds ); - } else if ( contents & CONTENTS_TRIGGER ) { - gameRenderWorld->DebugBounds( colorOrange, entBounds ); - } else if ( contents & CONTENTS_SOLID ) { - gameRenderWorld->DebugBounds( colorGreen, entBounds ); - } else { - if ( !entBounds.GetVolume() ) { - gameRenderWorld->DebugBounds( colorMdGrey, entBounds.Expand( 8.0f ) ); - } else { - gameRenderWorld->DebugBounds( colorMdGrey, entBounds ); - } - } - if ( viewTextBounds.IntersectsBounds( entBounds ) ) { - gameRenderWorld->DrawText( ent->name.c_str(), entBounds.GetCenter(), 0.1f, colorWhite, axis, 1 ); - gameRenderWorld->DrawText( va( "#%d", ent->entityNumber ), entBounds.GetCenter() + up, 0.1f, colorWhite, axis, 1 ); - } - } - } - - // debug tool to draw bounding boxes around active entities - if ( g_showActiveEntities.GetBool() ) { - for( ent = activeEntities.Next(); ent != NULL; ent = ent->activeNode.Next() ) { - idBounds b = ent->GetPhysics()->GetBounds(); - if ( b.GetVolume() <= 0 ) { - b[0][0] = b[0][1] = b[0][2] = -8; - b[1][0] = b[1][1] = b[1][2] = 8; - } - if ( ent->fl.isDormant ) { - gameRenderWorld->DebugBounds( colorYellow, b, ent->GetPhysics()->GetOrigin() ); - } else { - gameRenderWorld->DebugBounds( colorGreen, b, ent->GetPhysics()->GetOrigin() ); - } - } - } - - if ( g_showTargets.GetBool() ) { - ShowTargets(); - } - - if ( g_showTriggers.GetBool() ) { - idTrigger::DrawDebugInfo(); - } - - if ( ai_showCombatNodes.GetBool() ) { - idCombatNode::DrawDebugInfo(); - } - - if ( ai_showPaths.GetBool() ) { - idPathCorner::DrawDebugInfo(); - } - - if ( g_editEntityMode.GetBool() ) { - editEntities->DisplayEntities(); - } - - if ( g_showCollisionWorld.GetBool() ) { - collisionModelManager->DrawModel( 0, vec3_origin, mat3_identity, origin, 128.0f ); - } - - if ( g_showCollisionModels.GetBool() ) { - clip.DrawClipModels( player->GetEyePosition(), g_maxShowDistance.GetFloat(), pm_thirdPerson.GetBool() ? NULL : player ); - } - - if ( g_showCollisionTraces.GetBool() ) { - clip.PrintStatistics(); - } - - if ( g_showPVS.GetInteger() ) { - pvs.DrawPVS( origin, ( g_showPVS.GetInteger() == 2 ) ? PVS_ALL_PORTALS_OPEN : PVS_NORMAL ); - } - - if ( aas_test.GetInteger() >= 0 ) { - idAAS *aas = GetAAS( aas_test.GetInteger() ); - if ( aas ) { - aas->Test( origin ); - if ( ai_testPredictPath.GetBool() ) { - idVec3 velocity; - predictedPath_t path; - - velocity.x = cos( DEG2RAD( player->viewAngles.yaw ) ) * 100.0f; - velocity.y = sin( DEG2RAD( player->viewAngles.yaw ) ) * 100.0f; - velocity.z = 0.0f; - idAI::PredictPath( player, aas, origin, velocity, 1000, 100, SE_ENTER_OBSTACLE | SE_BLOCKED | SE_ENTER_LEDGE_AREA, path ); - } - } - } - - if ( ai_showObstacleAvoidance.GetInteger() == 2 ) { - idAAS *aas = GetAAS( 0 ); - if ( aas ) { - idVec3 seekPos; - obstaclePath_t path; - - seekPos = player->GetPhysics()->GetOrigin() + player->viewAxis[0] * 200.0f; - idAI::FindPathAroundObstacles( player->GetPhysics(), aas, NULL, player->GetPhysics()->GetOrigin(), seekPos, path ); - } - } - - // collision map debug output - collisionModelManager->DebugOutput( player->GetEyePosition() ); -} - -/* -================== -idGameLocal::NumAAS -================== -*/ -int idGameLocal::NumAAS( void ) const { - return aasList.Num(); -} - -/* -================== -idGameLocal::GetAAS -================== -*/ -idAAS *idGameLocal::GetAAS( int num ) const { - if ( ( num >= 0 ) && ( num < aasList.Num() ) ) { - if ( aasList[ num ] && aasList[ num ]->GetSettings() ) { - return aasList[ num ]; - } - } - return NULL; -} - -/* -================== -idGameLocal::GetAAS -================== -*/ -idAAS *idGameLocal::GetAAS( const char *name ) const { - int i; - - for ( i = 0; i < aasNames.Num(); i++ ) { - if ( aasNames[ i ] == name ) { - if ( !aasList[ i ]->GetSettings() ) { - return NULL; - } else { - return aasList[ i ]; - } - } - } - return NULL; -} - -/* -================== -idGameLocal::SetAASAreaState -================== -*/ -void idGameLocal::SetAASAreaState( const idBounds &bounds, const int areaContents, bool closed ) { - int i; - - for( i = 0; i < aasList.Num(); i++ ) { - aasList[ i ]->SetAreaState( bounds, areaContents, closed ); - } -} - -/* -================== -idGameLocal::AddAASObstacle -================== -*/ -aasHandle_t idGameLocal::AddAASObstacle( const idBounds &bounds ) { - int i; - aasHandle_t obstacle; - aasHandle_t check id_attribute((unused)); - - if ( !aasList.Num() ) { - return -1; - } - - obstacle = aasList[ 0 ]->AddObstacle( bounds ); - for( i = 1; i < aasList.Num(); i++ ) { - check = aasList[ i ]->AddObstacle( bounds ); - assert( check == obstacle ); - } - - return obstacle; -} - -/* -================== -idGameLocal::RemoveAASObstacle -================== -*/ -void idGameLocal::RemoveAASObstacle( const aasHandle_t handle ) { - int i; - - for( i = 0; i < aasList.Num(); i++ ) { - aasList[ i ]->RemoveObstacle( handle ); - } -} - -/* -================== -idGameLocal::RemoveAllAASObstacles -================== -*/ -void idGameLocal::RemoveAllAASObstacles( void ) { - int i; - - for( i = 0; i < aasList.Num(); i++ ) { - aasList[ i ]->RemoveAllObstacles(); - } -} - -/* -================== -idGameLocal::CheatsOk -================== -*/ -bool idGameLocal::CheatsOk( bool requirePlayer ) { - idPlayer *player; - - if ( isMultiplayer && !cvarSystem->GetCVarBool( "net_allowCheats" ) ) { - Printf( "Not allowed in multiplayer.\n" ); - return false; - } - - if ( developer.GetBool() ) { - return true; - } - - player = GetLocalPlayer(); - if ( !requirePlayer || ( player && ( player->health > 0 ) ) ) { - return true; - } - - Printf( "You must be alive to use this command.\n" ); - - return false; -} - -/* -=================== -idGameLocal::RegisterEntity -=================== -*/ -void idGameLocal::RegisterEntity( idEntity *ent ) { - int spawn_entnum; - - if ( spawnCount >= ( 1 << ( 32 - GENTITYNUM_BITS ) ) ) { - Error( "idGameLocal::RegisterEntity: spawn count overflow" ); - } - - if ( !spawnArgs.GetInt( "spawn_entnum", "0", spawn_entnum ) ) { - while( entities[firstFreeIndex] && firstFreeIndex < ENTITYNUM_MAX_NORMAL ) { - firstFreeIndex++; - } - if ( firstFreeIndex >= ENTITYNUM_MAX_NORMAL ) { - Error( "no free entities" ); - } - spawn_entnum = firstFreeIndex++; - } - - entities[ spawn_entnum ] = ent; - spawnIds[ spawn_entnum ] = spawnCount++; - ent->entityNumber = spawn_entnum; - ent->spawnNode.AddToEnd( spawnedEntities ); - ent->spawnArgs.TransferKeyValues( spawnArgs ); - - if ( spawn_entnum >= num_entities ) { - num_entities++; - } -} - -/* -=================== -idGameLocal::UnregisterEntity -=================== -*/ -void idGameLocal::UnregisterEntity( idEntity *ent ) { - assert( ent ); - - if ( editEntities ) { - editEntities->RemoveSelectedEntity( ent ); - } - - if ( ( ent->entityNumber != ENTITYNUM_NONE ) && ( entities[ ent->entityNumber ] == ent ) ) { - ent->spawnNode.Remove(); - entities[ ent->entityNumber ] = NULL; - spawnIds[ ent->entityNumber ] = -1; - if ( ent->entityNumber >= MAX_CLIENTS && ent->entityNumber < firstFreeIndex ) { - firstFreeIndex = ent->entityNumber; - } - ent->entityNumber = ENTITYNUM_NONE; - } -} - -/* -================ -idGameLocal::SpawnEntityType -================ -*/ -idEntity *idGameLocal::SpawnEntityType( const idTypeInfo &classdef, const idDict *args, bool bIsClientReadSnapshot ) { - idClass *obj; - -#if _DEBUG - if ( isClient ) { - assert( bIsClientReadSnapshot ); - } -#endif - - if ( !classdef.IsType( idEntity::Type ) ) { - Error( "Attempted to spawn non-entity class '%s'", classdef.classname ); - } - - try { - if ( args ) { - spawnArgs = *args; - } else { - spawnArgs.Clear(); - } - obj = classdef.CreateInstance(); - obj->CallSpawn(); - } - - catch( idAllocError & ) { - obj = NULL; - } - spawnArgs.Clear(); - - return static_cast(obj); -} - -/* -=================== -idGameLocal::SpawnEntityDef - -Finds the spawn function for the entity and calls it, -returning false if not found -=================== -*/ -bool idGameLocal::SpawnEntityDef( const idDict &args, idEntity **ent, bool setDefaults ) { - const char *classname; - const char *spawn; - idTypeInfo *cls; - idClass *obj; - idStr error; - const char *name; - - if ( ent ) { - *ent = NULL; - } - - spawnArgs = args; - - if ( spawnArgs.GetString( "name", "", &name ) ) { - sprintf( error, " on '%s'", name); - } - - spawnArgs.GetString( "classname", NULL, &classname ); - - const idDeclEntityDef *def = FindEntityDef( classname, false ); - - if ( !def ) { - Warning( "Unknown classname '%s'%s.", classname, error.c_str() ); - return false; - } - - spawnArgs.SetDefaults( &def->dict ); - -#ifdef _D3XP - if ( !spawnArgs.FindKey( "slowmo" ) ) { - bool slowmo = true; - - for ( int i = 0; fastEntityList[i]; i++ ) { - if ( !idStr::Cmp( classname, fastEntityList[i] ) ) { - slowmo = false; - break; - } - } - - if ( !slowmo ) { - spawnArgs.SetBool( "slowmo", slowmo ); - } - } -#endif - - // check if we should spawn a class object - spawnArgs.GetString( "spawnclass", NULL, &spawn ); - if ( spawn ) { - - cls = idClass::GetClass( spawn ); - if ( !cls ) { - Warning( "Could not spawn '%s'. Class '%s' not found %s.", classname, spawn, error.c_str() ); - return false; - } - - obj = cls->CreateInstance(); - if ( !obj ) { - Warning( "Could not spawn '%s'. Instance could not be created %s.", classname, error.c_str() ); - return false; - } - - obj->CallSpawn(); - - if ( ent && obj->IsType( idEntity::Type ) ) { - *ent = static_cast(obj); - } - - return true; - } - - // check if we should call a script function to spawn - spawnArgs.GetString( "spawnfunc", NULL, &spawn ); - if ( spawn ) { - const function_t *func = program.FindFunction( spawn ); - if ( !func ) { - Warning( "Could not spawn '%s'. Script function '%s' not found%s.", classname, spawn, error.c_str() ); - return false; - } - idThread *thread = new idThread( func ); - thread->DelayedStart( 0 ); - return true; - } - - Warning( "%s doesn't include a spawnfunc or spawnclass%s.", classname, error.c_str() ); - return false; -} - -/* -================ -idGameLocal::FindEntityDef -================ -*/ -const idDeclEntityDef *idGameLocal::FindEntityDef( const char *name, bool makeDefault ) const { - const idDecl *decl = NULL; - if ( isMultiplayer ) { - decl = declManager->FindType( DECL_ENTITYDEF, va( "%s_mp", name ), false ); - } - if ( !decl ) { - decl = declManager->FindType( DECL_ENTITYDEF, name, makeDefault ); - } - return static_cast( decl ); -} - -/* -================ -idGameLocal::FindEntityDefDict -================ -*/ -const idDict *idGameLocal::FindEntityDefDict( const char *name, bool makeDefault ) const { - const idDeclEntityDef *decl = FindEntityDef( name, makeDefault ); - return decl ? &decl->dict : NULL; -} - -/* -================ -idGameLocal::InhibitEntitySpawn -================ -*/ -bool idGameLocal::InhibitEntitySpawn( idDict &spawnArgs ) { - - bool result = false; - - if ( isMultiplayer ) { - spawnArgs.GetBool( "not_multiplayer", "0", result ); - } else if ( g_skill.GetInteger() == 0 ) { - spawnArgs.GetBool( "not_easy", "0", result ); - } else if ( g_skill.GetInteger() == 1 ) { - spawnArgs.GetBool( "not_medium", "0", result ); - } else { - spawnArgs.GetBool( "not_hard", "0", result ); -#ifdef _D3XP - if ( !result && g_skill.GetInteger() == 3 ) { - spawnArgs.GetBool( "not_nightmare", "0", result ); - } -#endif - } - - - const char *name; - if ( g_skill.GetInteger() == 3 ) { - name = spawnArgs.GetString( "classname" ); - // _D3XP :: remove moveable medkit packs also - if ( idStr::Icmp( name, "item_medkit" ) == 0 || idStr::Icmp( name, "item_medkit_small" ) == 0 || - idStr::Icmp( name, "moveable_item_medkit" ) == 0 || idStr::Icmp( name, "moveable_item_medkit_small" ) == 0 ) { - - result = true; - } - } - - if ( gameLocal.isMultiplayer ) { - name = spawnArgs.GetString( "classname" ); - if ( idStr::Icmp( name, "weapon_bfg" ) == 0 || idStr::Icmp( name, "weapon_soulcube" ) == 0 ) { - result = true; - } - } - - return result; -} - -/* -================ -idGameLocal::SetSkill -================ -*/ -void idGameLocal::SetSkill( int value ) { - int skill_level; - - if ( value < 0 ) { - skill_level = 0; - } else if ( value > 3 ) { - skill_level = 3; - } else { - skill_level = value; - } - - g_skill.SetInteger( skill_level ); -} - -/* -============== -idGameLocal::GameState - -Used to allow entities to know if they're being spawned during the initial spawn. -============== -*/ -gameState_t idGameLocal::GameState( void ) const { - return gamestate; -} - -/* -============== -idGameLocal::SpawnMapEntities - -Parses textual entity definitions out of an entstring and spawns gentities. -============== -*/ -void idGameLocal::SpawnMapEntities( void ) { - int i; - int num; - int inhibit; - idMapEntity *mapEnt; - int numEntities; - idDict args; - - Printf( "Spawning entities\n" ); - - if ( mapFile == NULL ) { - Printf("No mapfile present\n"); - return; - } - - SetSkill( g_skill.GetInteger() ); - - numEntities = mapFile->GetNumEntities(); - if ( numEntities == 0 ) { - Error( "...no entities" ); - } - - // the worldspawn is a special that performs any global setup - // needed by a level - mapEnt = mapFile->GetEntity( 0 ); - args = mapEnt->epairs; - args.SetInt( "spawn_entnum", ENTITYNUM_WORLD ); - if ( !SpawnEntityDef( args ) || !entities[ ENTITYNUM_WORLD ] || !entities[ ENTITYNUM_WORLD ]->IsType( idWorldspawn::Type ) ) { - Error( "Problem spawning world entity" ); - } - - num = 1; - inhibit = 0; - - for ( i = 1 ; i < numEntities ; i++ ) { - mapEnt = mapFile->GetEntity( i ); - args = mapEnt->epairs; - - if ( !InhibitEntitySpawn( args ) ) { - // precache any media specified in the map entity - CacheDictionaryMedia( &args ); - - SpawnEntityDef( args ); - num++; - } else { - inhibit++; - } - } - - Printf( "...%i entities spawned, %i inhibited\n\n", num, inhibit ); -} - -/* -================ -idGameLocal::AddEntityToHash -================ -*/ -void idGameLocal::AddEntityToHash( const char *name, idEntity *ent ) { - if ( FindEntity( name ) ) { - Error( "Multiple entities named '%s'", name ); - } - entityHash.Add( entityHash.GenerateKey( name, true ), ent->entityNumber ); -} - -/* -================ -idGameLocal::RemoveEntityFromHash -================ -*/ -bool idGameLocal::RemoveEntityFromHash( const char *name, idEntity *ent ) { - int hash, i; - - hash = entityHash.GenerateKey( name, true ); - for ( i = entityHash.First( hash ); i != -1; i = entityHash.Next( i ) ) { - if ( entities[i] && entities[i] == ent && entities[i]->name.Icmp( name ) == 0 ) { - entityHash.Remove( hash, i ); - return true; - } - } - return false; -} - -/* -================ -idGameLocal::GetTargets -================ -*/ -int idGameLocal::GetTargets( const idDict &args, idList< idEntityPtr > &list, const char *ref ) const { - int i, num, refLength; - const idKeyValue *arg; - idEntity *ent; - - list.Clear(); - - refLength = strlen( ref ); - num = args.GetNumKeyVals(); - for( i = 0; i < num; i++ ) { - - arg = args.GetKeyVal( i ); - if ( arg->GetKey().Icmpn( ref, refLength ) == 0 ) { - - ent = FindEntity( arg->GetValue() ); - if ( ent ) { - idEntityPtr &entityPtr = list.Alloc(); - entityPtr = ent; - } - } - } - - return list.Num(); -} - -/* -============= -idGameLocal::GetTraceEntity - -returns the master entity of a trace. for example, if the trace entity is the player's head, it will return the player. -============= -*/ -idEntity *idGameLocal::GetTraceEntity( const trace_t &trace ) const { - idEntity *master; - - if ( !entities[ trace.c.entityNum ] ) { - return NULL; - } - master = entities[ trace.c.entityNum ]->GetBindMaster(); - if ( master ) { - return master; - } - return entities[ trace.c.entityNum ]; -} - -/* -============= -idGameLocal::ArgCompletion_EntityName - -Argument completion for entity names -============= -*/ -void idGameLocal::ArgCompletion_EntityName( const idCmdArgs &args, void(*callback)( const char *s ) ) { - int i; - - for( i = 0; i < gameLocal.num_entities; i++ ) { - if ( gameLocal.entities[ i ] ) { - callback( va( "%s %s", args.Argv( 0 ), gameLocal.entities[ i ]->name.c_str() ) ); - } - } -} - -/* -============= -idGameLocal::FindEntity - -Returns the entity whose name matches the specified string. -============= -*/ -idEntity *idGameLocal::FindEntity( const char *name ) const { - int hash, i; - - hash = entityHash.GenerateKey( name, true ); - for ( i = entityHash.First( hash ); i != -1; i = entityHash.Next( i ) ) { - if ( entities[i] && entities[i]->name.Icmp( name ) == 0 ) { - return entities[i]; - } - } - - return NULL; -} - -/* -============= -idGameLocal::FindEntityUsingDef - -Searches all active entities for the next one using the specified entityDef. - -Searches beginning at the entity after from, or the beginning if NULL -NULL will be returned if the end of the list is reached. -============= -*/ -idEntity *idGameLocal::FindEntityUsingDef( idEntity *from, const char *match ) const { - idEntity *ent; - - if ( !from ) { - ent = spawnedEntities.Next(); - } else { - ent = from->spawnNode.Next(); - } - - for ( ; ent != NULL; ent = ent->spawnNode.Next() ) { - assert( ent ); - if ( idStr::Icmp( ent->GetEntityDefName(), match ) == 0 ) { - return ent; - } - } - - return NULL; -} - -/* -============= -idGameLocal::FindTraceEntity - -Searches all active entities for the closest ( to start ) match that intersects -the line start,end -============= -*/ -idEntity *idGameLocal::FindTraceEntity( idVec3 start, idVec3 end, const idTypeInfo &c, const idEntity *skip ) const { - idEntity *ent; - idEntity *bestEnt; - float scale; - float bestScale; - idBounds b; - - bestEnt = NULL; - bestScale = 1.0f; - for( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) { - if ( ent->IsType( c ) && ent != skip ) { - b = ent->GetPhysics()->GetAbsBounds().Expand( 16 ); - if ( b.RayIntersection( start, end-start, scale ) ) { - if ( scale >= 0.0f && scale < bestScale ) { - bestEnt = ent; - bestScale = scale; - } - } - } - } - - return bestEnt; -} - -/* -================ -idGameLocal::EntitiesWithinRadius -================ -*/ -int idGameLocal::EntitiesWithinRadius( const idVec3 org, float radius, idEntity **entityList, int maxCount ) const { - idEntity *ent; - idBounds bo( org ); - int entCount = 0; - - bo.ExpandSelf( radius ); - for( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) { - if ( ent->GetPhysics()->GetAbsBounds().IntersectsBounds( bo ) ) { - entityList[entCount++] = ent; - } - } - - return entCount; -} - -/* -================= -idGameLocal::KillBox - -Kills all entities that would touch the proposed new positioning of ent. The ent itself will not being killed. -Checks if player entities are in the teleporter, and marks them to die at teleport exit instead of immediately. -If catch_teleport, this only marks teleport players for death on exit -================= -*/ -void idGameLocal::KillBox( idEntity *ent, bool catch_teleport ) { - int i; - int num; - idEntity * hit; - idClipModel *cm; - idClipModel *clipModels[ MAX_GENTITIES ]; - idPhysics *phys; - - phys = ent->GetPhysics(); - if ( !phys->GetNumClipModels() ) { - return; - } - - num = clip.ClipModelsTouchingBounds( phys->GetAbsBounds(), phys->GetClipMask(), clipModels, MAX_GENTITIES ); - for ( i = 0; i < num; i++ ) { - cm = clipModels[ i ]; - - // don't check render entities - if ( cm->IsRenderModel() ) { - continue; - } - - hit = cm->GetEntity(); - if ( ( hit == ent ) || !hit->fl.takedamage ) { - continue; - } - - if ( !phys->ClipContents( cm ) ) { - continue; - } - - // nail it - if ( hit->IsType( idPlayer::Type ) && static_cast< idPlayer * >( hit )->IsInTeleport() ) { - static_cast< idPlayer * >( hit )->TeleportDeath( ent->entityNumber ); - } else if ( !catch_teleport ) { - hit->Damage( ent, ent, vec3_origin, "damage_telefrag", 1.0f, INVALID_JOINT ); - } - - if ( !gameLocal.isMultiplayer ) { - // let the mapper know about it - Warning( "'%s' telefragged '%s'", ent->name.c_str(), hit->name.c_str() ); - } - } -} - -/* -================ -idGameLocal::RequirementMet -================ -*/ -bool idGameLocal::RequirementMet( idEntity *activator, const idStr &requires, int removeItem ) { - if ( requires.Length() ) { - if ( activator->IsType( idPlayer::Type ) ) { - idPlayer *player = static_cast(activator); - idDict *item = player->FindInventoryItem( requires ); - if ( item ) { - if ( removeItem ) { - player->RemoveInventoryItem( item ); - } - return true; - } else { - return false; - } - } - } - - return true; -} - -/* -============ -idGameLocal::AlertAI -============ -*/ -void idGameLocal::AlertAI( idEntity *ent ) { - if ( ent && ent->IsType( idActor::Type ) ) { - // alert them for the next frame - lastAIAlertTime = time + msec; - lastAIAlertEntity = static_cast( ent ); - } -} - -/* -============ -idGameLocal::GetAlertEntity -============ -*/ -idActor *idGameLocal::GetAlertEntity( void ) { -#ifdef _D3XP - int timeGroup = 0; - if ( lastAIAlertTime && lastAIAlertEntity.GetEntity() ) { - timeGroup = lastAIAlertEntity.GetEntity()->timeGroup; - } - SetTimeState ts( timeGroup ); -#endif - - if ( lastAIAlertTime >= time ) { - return lastAIAlertEntity.GetEntity(); - } - - return NULL; -} - -/* -============ -idGameLocal::RadiusDamage -============ -*/ -void idGameLocal::RadiusDamage( const idVec3 &origin, idEntity *inflictor, idEntity *attacker, idEntity *ignoreDamage, idEntity *ignorePush, const char *damageDefName, float dmgPower ) { - float dist, damageScale, attackerDamageScale, attackerPushScale; - idEntity * ent; - idEntity * entityList[ MAX_GENTITIES ]; - int numListedEntities; - idBounds bounds; - idVec3 v, damagePoint, dir; - int i, e, damage, radius, push; - - const idDict *damageDef = FindEntityDefDict( damageDefName, false ); - if ( !damageDef ) { - Warning( "Unknown damageDef '%s'", damageDefName ); - return; - } - - damageDef->GetInt( "damage", "20", damage ); - damageDef->GetInt( "radius", "50", radius ); - damageDef->GetInt( "push", va( "%d", damage * 100 ), push ); - damageDef->GetFloat( "attackerDamageScale", "0.5", attackerDamageScale ); - damageDef->GetFloat( "attackerPushScale", "0", attackerPushScale ); - - if ( radius < 1 ) { - radius = 1; - } - - bounds = idBounds( origin ).Expand( radius ); - - // get all entities touching the bounds - numListedEntities = clip.EntitiesTouchingBounds( bounds, -1, entityList, MAX_GENTITIES ); - - if ( inflictor && inflictor->IsType( idAFAttachment::Type ) ) { - inflictor = static_cast(inflictor)->GetBody(); - } - if ( attacker && attacker->IsType( idAFAttachment::Type ) ) { - attacker = static_cast(attacker)->GetBody(); - } - if ( ignoreDamage && ignoreDamage->IsType( idAFAttachment::Type ) ) { - ignoreDamage = static_cast(ignoreDamage)->GetBody(); - } - - // apply damage to the entities - for ( e = 0; e < numListedEntities; e++ ) { - ent = entityList[ e ]; - assert( ent ); - - if ( !ent->fl.takedamage ) { - continue; - } - - if ( ent == inflictor || ( ent->IsType( idAFAttachment::Type ) && static_cast(ent)->GetBody() == inflictor ) ) { - continue; - } - - if ( ent == ignoreDamage || ( ent->IsType( idAFAttachment::Type ) && static_cast(ent)->GetBody() == ignoreDamage ) ) { - continue; - } - - // don't damage a dead player - if ( isMultiplayer && ent->entityNumber < MAX_CLIENTS && ent->IsType( idPlayer::Type ) && static_cast< idPlayer * >( ent )->health < 0 ) { - continue; - } - - // find the distance from the edge of the bounding box - for ( i = 0; i < 3; i++ ) { - if ( origin[ i ] < ent->GetPhysics()->GetAbsBounds()[0][ i ] ) { - v[ i ] = ent->GetPhysics()->GetAbsBounds()[0][ i ] - origin[ i ]; - } else if ( origin[ i ] > ent->GetPhysics()->GetAbsBounds()[1][ i ] ) { - v[ i ] = origin[ i ] - ent->GetPhysics()->GetAbsBounds()[1][ i ]; - } else { - v[ i ] = 0; - } - } - - dist = v.Length(); - if ( dist >= radius ) { - continue; - } - - if ( ent->CanDamage( origin, damagePoint ) ) { - // push the center of mass higher than the origin so players - // get knocked into the air more - dir = ent->GetPhysics()->GetOrigin() - origin; - dir[ 2 ] += 24; - - // get the damage scale - damageScale = dmgPower * ( 1.0f - dist / radius ); - if ( ent == attacker || ( ent->IsType( idAFAttachment::Type ) && static_cast(ent)->GetBody() == attacker ) ) { - damageScale *= attackerDamageScale; - } - - ent->Damage( inflictor, attacker, dir, damageDefName, damageScale, INVALID_JOINT ); - } - } - - // push physics objects - if ( push ) { - RadiusPush( origin, radius, push * dmgPower, attacker, ignorePush, attackerPushScale, false ); - } -} - -/* -============== -idGameLocal::RadiusPush -============== -*/ -void idGameLocal::RadiusPush( const idVec3 &origin, const float radius, const float push, const idEntity *inflictor, const idEntity *ignore, float inflictorScale, const bool quake ) { - int i, numListedClipModels; - idClipModel *clipModel; - idClipModel *clipModelList[ MAX_GENTITIES ]; - idVec3 dir; - idBounds bounds; - modelTrace_t result; - idEntity *ent; - float scale; - - dir.Set( 0.0f, 0.0f, 1.0f ); - - bounds = idBounds( origin ).Expand( radius ); - - // get all clip models touching the bounds - numListedClipModels = clip.ClipModelsTouchingBounds( bounds, -1, clipModelList, MAX_GENTITIES ); - - if ( inflictor && inflictor->IsType( idAFAttachment::Type ) ) { - inflictor = static_cast(inflictor)->GetBody(); - } - if ( ignore && ignore->IsType( idAFAttachment::Type ) ) { - ignore = static_cast(ignore)->GetBody(); - } - - // apply impact to all the clip models through their associated physics objects - for ( i = 0; i < numListedClipModels; i++ ) { - - clipModel = clipModelList[i]; - - // never push render models - if ( clipModel->IsRenderModel() ) { - continue; - } - - ent = clipModel->GetEntity(); - - // never push projectiles - if ( ent->IsType( idProjectile::Type ) ) { - continue; - } - - // players use "knockback" in idPlayer::Damage - if ( ent->IsType( idPlayer::Type ) && !quake ) { - continue; - } - - // don't push the ignore entity - if ( ent == ignore || ( ent->IsType( idAFAttachment::Type ) && static_cast(ent)->GetBody() == ignore ) ) { - continue; - } - - if ( gameRenderWorld->FastWorldTrace( result, origin, clipModel->GetOrigin() ) ) { - continue; - } - - // scale the push for the inflictor - if ( ent == inflictor || ( ent->IsType( idAFAttachment::Type ) && static_cast(ent)->GetBody() == inflictor ) ) { - scale = inflictorScale; - } else { - scale = 1.0f; - } - - if ( quake ) { - clipModel->GetEntity()->ApplyImpulse( world, clipModel->GetId(), clipModel->GetOrigin(), scale * push * dir ); - } else { - RadiusPushClipModel( origin, scale * push, clipModel ); - } - } -} - -/* -============== -idGameLocal::RadiusPushClipModel -============== -*/ -void idGameLocal::RadiusPushClipModel( const idVec3 &origin, const float push, const idClipModel *clipModel ) { - int i, j; - float dot, dist, area; - const idTraceModel *trm; - const traceModelPoly_t *poly; - idFixedWinding w; - idVec3 v, localOrigin, center, impulse; - - trm = clipModel->GetTraceModel(); - if ( !trm || 1 ) { - impulse = clipModel->GetAbsBounds().GetCenter() - origin; - impulse.Normalize(); - impulse.z += 1.0f; - clipModel->GetEntity()->ApplyImpulse( world, clipModel->GetId(), clipModel->GetOrigin(), push * impulse ); - return; - } - - localOrigin = ( origin - clipModel->GetOrigin() ) * clipModel->GetAxis().Transpose(); - for ( i = 0; i < trm->numPolys; i++ ) { - poly = &trm->polys[i]; - - center.Zero(); - for ( j = 0; j < poly->numEdges; j++ ) { - v = trm->verts[ trm->edges[ abs(poly->edges[j]) ].v[ INTSIGNBITSET( poly->edges[j] ) ] ]; - center += v; - v -= localOrigin; - v.NormalizeFast(); // project point on a unit sphere - w.AddPoint( v ); - } - center /= poly->numEdges; - v = center - localOrigin; - dist = v.NormalizeFast(); - dot = v * poly->normal; - if ( dot > 0.0f ) { - continue; - } - area = w.GetArea(); - // impulse in polygon normal direction - impulse = poly->normal * clipModel->GetAxis(); - // always push up for nicer effect - impulse.z -= 1.0f; - // scale impulse based on visible surface area and polygon angle - impulse *= push * ( dot * area * ( 1.0f / ( 4.0f * idMath::PI ) ) ); - // scale away distance for nicer effect - impulse *= ( dist * 2.0f ); - // impulse is applied to the center of the polygon - center = clipModel->GetOrigin() + center * clipModel->GetAxis(); - - clipModel->GetEntity()->ApplyImpulse( world, clipModel->GetId(), center, impulse ); - } -} - -/* -=============== -idGameLocal::ProjectDecal -=============== -*/ -void idGameLocal::ProjectDecal( const idVec3 &origin, const idVec3 &dir, float depth, bool parallel, float size, const char *material, float angle ) { - float s, c; - idMat3 axis, axistemp; - idFixedWinding winding; - idVec3 windingOrigin, projectionOrigin; - - static idVec3 decalWinding[4] = { - idVec3( 1.0f, 1.0f, 0.0f ), - idVec3( -1.0f, 1.0f, 0.0f ), - idVec3( -1.0f, -1.0f, 0.0f ), - idVec3( 1.0f, -1.0f, 0.0f ) - }; - - if ( !g_decals.GetBool() ) { - return; - } - - // randomly rotate the decal winding - idMath::SinCos16( ( angle ) ? angle : random.RandomFloat() * idMath::TWO_PI, s, c ); - - // winding orientation - axis[2] = dir; - axis[2].Normalize(); - axis[2].NormalVectors( axistemp[0], axistemp[1] ); - axis[0] = axistemp[ 0 ] * c + axistemp[ 1 ] * -s; - axis[1] = axistemp[ 0 ] * -s + axistemp[ 1 ] * -c; - - windingOrigin = origin + depth * axis[2]; - if ( parallel ) { - projectionOrigin = origin - depth * axis[2]; - } else { - projectionOrigin = origin; - } - - size *= 0.5f; - - winding.Clear(); - winding += idVec5( windingOrigin + ( axis * decalWinding[0] ) * size, idVec2( 1, 1 ) ); - winding += idVec5( windingOrigin + ( axis * decalWinding[1] ) * size, idVec2( 0, 1 ) ); - winding += idVec5( windingOrigin + ( axis * decalWinding[2] ) * size, idVec2( 0, 0 ) ); - winding += idVec5( windingOrigin + ( axis * decalWinding[3] ) * size, idVec2( 1, 0 ) ); - gameRenderWorld->ProjectDecalOntoWorld( winding, projectionOrigin, parallel, depth * 0.5f, declManager->FindMaterial( material ), gameLocal.slow.time /* _D3XP */ ); -} - -/* -============== -idGameLocal::BloodSplat -============== -*/ -void idGameLocal::BloodSplat( const idVec3 &origin, const idVec3 &dir, float size, const char *material ) { - float halfSize = size * 0.5f; - idVec3 verts[] = { idVec3( 0.0f, +halfSize, +halfSize ), - idVec3( 0.0f, +halfSize, -halfSize ), - idVec3( 0.0f, -halfSize, -halfSize ), - idVec3( 0.0f, -halfSize, +halfSize ) }; - idTraceModel trm; - idClipModel mdl; - trace_t results; - - // FIXME: get from damage def - if ( !g_bloodEffects.GetBool() ) { - return; - } - - size = halfSize + random.RandomFloat() * halfSize; - trm.SetupPolygon( verts, 4 ); - mdl.LoadModel( trm ); - clip.Translation( results, origin, origin + dir * 64.0f, &mdl, mat3_identity, CONTENTS_SOLID, NULL ); - ProjectDecal( results.endpos, dir, 2.0f * size, true, size, material ); -} - -/* -============= -idGameLocal::SetCamera -============= -*/ -void idGameLocal::SetCamera( idCamera *cam ) { - int i; - idEntity *ent; - idAI *ai; - - // this should fix going into a cinematic when dead.. rare but happens - idPlayer *client = GetLocalPlayer(); - if ( client->health <= 0 || client->AI_DEAD ) { - return; - } - - camera = cam; - if ( camera ) { - inCinematic = true; - - if ( skipCinematic && camera->spawnArgs.GetBool( "disconnect" ) ) { - camera->spawnArgs.SetBool( "disconnect", false ); - cvarSystem->SetCVarFloat( "r_znear", 3.0f ); - cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "disconnect\n" ); - skipCinematic = false; - return; - } - - if ( time > cinematicStopTime ) { - cinematicSkipTime = time + CINEMATIC_SKIP_DELAY; - } - - // set r_znear so that transitioning into/out of the player's head doesn't clip through the view - cvarSystem->SetCVarFloat( "r_znear", 1.0f ); - - // hide all the player models - for( i = 0; i < numClients; i++ ) { - if ( entities[ i ] ) { - client = static_cast< idPlayer* >( entities[ i ] ); - client->EnterCinematic(); - } - } - - if ( !cam->spawnArgs.GetBool( "ignore_enemies" ) ) { - // kill any active monsters that are enemies of the player - for ( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) { - if ( ent->cinematic || ent->fl.isDormant ) { - // only kill entities that aren't needed for cinematics and aren't dormant - continue; - } - - if ( ent->IsType( idAI::Type ) ) { - ai = static_cast( ent ); - if ( !ai->GetEnemy() || !ai->IsActive() ) { - // no enemy, or inactive, so probably safe to ignore - continue; - } - } else if ( ent->IsType( idProjectile::Type ) ) { - // remove all projectiles - } else if ( ent->spawnArgs.GetBool( "cinematic_remove" ) ) { - // remove anything marked to be removed during cinematics - } else { - // ignore everything else - continue; - } - - // remove it - DPrintf( "removing '%s' for cinematic\n", ent->GetName() ); - ent->PostEventMS( &EV_Remove, 0 ); - } - } - - } else { - inCinematic = false; - cinematicStopTime = time + msec; - - // restore r_znear - cvarSystem->SetCVarFloat( "r_znear", 3.0f ); - - // show all the player models - for( i = 0; i < numClients; i++ ) { - if ( entities[ i ] ) { - idPlayer *client = static_cast< idPlayer* >( entities[ i ] ); - client->ExitCinematic(); - } - } - } -} - -/* -============= -idGameLocal::GetCamera -============= -*/ -idCamera *idGameLocal::GetCamera( void ) const { - return camera; -} - -/* -============= -idGameLocal::SkipCinematic -============= -*/ -bool idGameLocal::SkipCinematic( void ) { - if ( camera ) { - if ( camera->spawnArgs.GetBool( "disconnect" ) ) { - camera->spawnArgs.SetBool( "disconnect", false ); - cvarSystem->SetCVarFloat( "r_znear", 3.0f ); - cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "disconnect\n" ); - skipCinematic = false; - return false; - } - - if ( camera->spawnArgs.GetBool( "instantSkip" ) ) { - camera->Stop(); - return false; - } - } - - soundSystem->SetMute( true ); - if ( !skipCinematic ) { - skipCinematic = true; - cinematicMaxSkipTime = gameLocal.time + SEC2MS( g_cinematicMaxSkipTime.GetFloat() ); - } - - return true; -} - - -/* -====================== -idGameLocal::SpreadLocations - -Now that everything has been spawned, associate areas with location entities -====================== -*/ -void idGameLocal::SpreadLocations() { - idEntity *ent; - - // allocate the area table - int numAreas = gameRenderWorld->NumAreas(); - locationEntities = new idLocationEntity *[ numAreas ]; - memset( locationEntities, 0, numAreas * sizeof( *locationEntities ) ); - - // for each location entity, make pointers from every area it touches - for( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) { - if ( !ent->IsType( idLocationEntity::Type ) ) { - continue; - } - idVec3 point = ent->spawnArgs.GetVector( "origin" ); - int areaNum = gameRenderWorld->PointInArea( point ); - if ( areaNum < 0 ) { - Printf( "SpreadLocations: location '%s' is not in a valid area\n", ent->spawnArgs.GetString( "name" ) ); - continue; - } - if ( areaNum >= numAreas ) { - Error( "idGameLocal::SpreadLocations: areaNum >= gameRenderWorld->NumAreas()" ); - } - if ( locationEntities[areaNum] ) { - Warning( "location entity '%s' overlaps '%s'", ent->spawnArgs.GetString( "name" ), - locationEntities[areaNum]->spawnArgs.GetString( "name" ) ); - continue; - } - locationEntities[areaNum] = static_cast(ent); - - // spread to all other connected areas - for ( int i = 0 ; i < numAreas ; i++ ) { - if ( i == areaNum ) { - continue; - } - if ( gameRenderWorld->AreasAreConnected( areaNum, i, PS_BLOCK_LOCATION ) ) { - locationEntities[i] = static_cast(ent); - } - } - } -} - -/* -=================== -idGameLocal::LocationForPoint - -The player checks the location each frame to update the HUD text display -May return NULL -=================== -*/ -idLocationEntity *idGameLocal::LocationForPoint( const idVec3 &point ) { - if ( !locationEntities ) { - // before SpreadLocations() has been called - return NULL; - } - - int areaNum = gameRenderWorld->PointInArea( point ); - if ( areaNum < 0 ) { - return NULL; - } - if ( areaNum >= gameRenderWorld->NumAreas() ) { - Error( "idGameLocal::LocationForPoint: areaNum >= gameRenderWorld->NumAreas()" ); - } - - return locationEntities[ areaNum ]; -} - -/* -============ -idGameLocal::SetPortalState -============ -*/ -void idGameLocal::SetPortalState( qhandle_t portal, int blockingBits ) { - idBitMsg outMsg; - byte msgBuf[ MAX_GAME_MESSAGE_SIZE ]; - - if ( !gameLocal.isClient ) { - outMsg.Init( msgBuf, sizeof( msgBuf ) ); - outMsg.WriteByte( GAME_RELIABLE_MESSAGE_PORTAL ); - outMsg.WriteInt( portal ); - outMsg.WriteBits( blockingBits, NUM_RENDER_PORTAL_BITS ); - networkSystem->ServerSendReliableMessage( -1, outMsg ); - } - gameRenderWorld->SetPortalState( portal, blockingBits ); -} - -/* -============ -idGameLocal::sortSpawnPoints -============ -*/ -int idGameLocal::sortSpawnPoints( const void *ptr1, const void *ptr2 ) { - const spawnSpot_t *spot1 = static_cast( ptr1 ); - const spawnSpot_t *spot2 = static_cast( ptr2 ); - float diff; - - diff = spot1->dist - spot2->dist; - if ( diff < 0.0f ) { - return 1; - } else if ( diff > 0.0f ) { - return -1; - } else { - return 0; - } -} - -/* -=========== -idGameLocal::RandomizeInitialSpawns -randomize the order of the initial spawns -prepare for a sequence of initial player spawns -============ -*/ -void idGameLocal::RandomizeInitialSpawns( void ) { - spawnSpot_t spot; - int i, j; -#ifdef CTF - int k; -#endif - - idEntity *ent; - - if ( !isMultiplayer || isClient ) { - return; - } - spawnSpots.Clear(); - initialSpots.Clear(); -#ifdef CTF - teamSpawnSpots[0].Clear(); - teamSpawnSpots[1].Clear(); - teamInitialSpots[0].Clear(); - teamInitialSpots[1].Clear(); -#endif - - spot.dist = 0; - spot.ent = FindEntityUsingDef( NULL, "info_player_deathmatch" ); - while( spot.ent ) { -#ifdef CTF - spot.ent->spawnArgs.GetInt( "team", "-1", spot.team ); - - if ( mpGame.IsGametypeFlagBased() ) /* CTF */ - { - if ( spot.team == 0 || spot.team == 1 ) - teamSpawnSpots[spot.team].Append( spot ); - else - common->Warning( "info_player_deathmatch : invalid or no team attached to spawn point\n"); - } -#endif - spawnSpots.Append( spot ); - if ( spot.ent->spawnArgs.GetBool( "initial" ) ) { -#ifdef CTF - if ( mpGame.IsGametypeFlagBased() ) /* CTF */ - { - assert( spot.team == 0 || spot.team == 1 ); - teamInitialSpots[ spot.team ].Append( spot.ent ); - } -#endif - - initialSpots.Append( spot.ent ); - } - spot.ent = FindEntityUsingDef( spot.ent, "info_player_deathmatch" ); - } - -#ifdef CTF - if ( mpGame.IsGametypeFlagBased() ) /* CTF */ - { - if ( !teamSpawnSpots[0].Num() ) - common->Warning( "red team : no info_player_deathmatch in map" ); - if ( !teamSpawnSpots[1].Num() ) - common->Warning( "blue team : no info_player_deathmatch in map" ); - - if ( !teamSpawnSpots[0].Num() || !teamSpawnSpots[1].Num() ) - return; - } -#endif - - if ( !spawnSpots.Num() ) { - common->Warning( "no info_player_deathmatch in map" ); - return; - } - -#ifdef CTF - if ( mpGame.IsGametypeFlagBased() ) /* CTF */ - { - common->Printf( "red team : %d spawns (%d initials)\n", teamSpawnSpots[ 0 ].Num(), teamInitialSpots[ 0 ].Num() ); - // if there are no initial spots in the map, consider they can all be used as initial - if ( !teamInitialSpots[ 0 ].Num() ) { - common->Warning( "red team : no info_player_deathmatch entities marked initial in map" ); - for ( i = 0; i < teamSpawnSpots[ 0 ].Num(); i++ ) { - teamInitialSpots[ 0 ].Append( teamSpawnSpots[ 0 ][ i ].ent ); - } - } - - common->Printf( "blue team : %d spawns (%d initials)\n", teamSpawnSpots[ 1 ].Num(), teamInitialSpots[ 1 ].Num() ); - // if there are no initial spots in the map, consider they can all be used as initial - if ( !teamInitialSpots[ 1 ].Num() ) { - common->Warning( "blue team : no info_player_deathmatch entities marked initial in map" ); - for ( i = 0; i < teamSpawnSpots[ 1 ].Num(); i++ ) { - teamInitialSpots[ 1 ].Append( teamSpawnSpots[ 1 ][ i ].ent ); - } - } - } -#endif - - - common->Printf( "%d spawns (%d initials)\n", spawnSpots.Num(), initialSpots.Num() ); - // if there are no initial spots in the map, consider they can all be used as initial - if ( !initialSpots.Num() ) { - common->Warning( "no info_player_deathmatch entities marked initial in map" ); - for ( i = 0; i < spawnSpots.Num(); i++ ) { - initialSpots.Append( spawnSpots[ i ].ent ); - } - } - -#ifdef CTF - for ( k = 0; k < 2; k++ ) - for ( i = 0; i < teamInitialSpots[ k ].Num(); i++ ) { - j = random.RandomInt( teamInitialSpots[ k ].Num() ); - ent = teamInitialSpots[ k ][ i ]; - teamInitialSpots[ k ][ i ] = teamInitialSpots[ k ][ j ]; - teamInitialSpots[ k ][ j ] = ent; - } -#endif - - for ( i = 0; i < initialSpots.Num(); i++ ) { - j = random.RandomInt( initialSpots.Num() ); - ent = initialSpots[ i ]; - initialSpots[ i ] = initialSpots[ j ]; - initialSpots[ j ] = ent; - } - // reset the counter - currentInitialSpot = 0; - -#ifdef CTF - teamCurrentInitialSpot[0] = 0; - teamCurrentInitialSpot[1] = 0; -#endif -} - -/* -=========== -idGameLocal::SelectInitialSpawnPoint -spectators are spawned randomly anywhere -in-game clients are spawned based on distance to active players (randomized on the first half) -upon map restart, initial spawns are used (randomized ordered list of spawns flagged "initial") - if there are more players than initial spots, overflow to regular spawning -============ -*/ -idEntity *idGameLocal::SelectInitialSpawnPoint( idPlayer *player ) { - int i, j, which; - spawnSpot_t spot; - idVec3 pos; - float dist; - bool alone; - -#ifdef CTF - if ( !isMultiplayer || !spawnSpots.Num() || ( mpGame.IsGametypeFlagBased() && ( !teamSpawnSpots[0].Num() || !teamSpawnSpots[1].Num() ) ) ) { /* CTF */ -#else - if ( !isMultiplayer || !spawnSpots.Num() ) { -#endif - spot.ent = FindEntityUsingDef( NULL, "info_player_start" ); - if ( !spot.ent ) { - Error( "No info_player_start on map.\n" ); - } - return spot.ent; - } - -#ifdef CTF - bool useInitialSpots = false; - if ( mpGame.IsGametypeFlagBased() ) { /* CTF */ - assert( player->team == 0 || player->team == 1 ); - useInitialSpots = player->useInitialSpawns && teamCurrentInitialSpot[ player->team ] < teamInitialSpots[ player->team ].Num(); - } else { - useInitialSpots = player->useInitialSpawns && currentInitialSpot < initialSpots.Num(); - } -#endif - - if ( player->spectating ) { - // plain random spot, don't bother - return spawnSpots[ random.RandomInt( spawnSpots.Num() ) ].ent; -#ifdef CTF - } else if ( useInitialSpots ) { - if ( mpGame.IsGametypeFlagBased() ) { /* CTF */ - assert( player->team == 0 || player->team == 1 ); - player->useInitialSpawns = false; // only use the initial spawn once - return teamInitialSpots[ player->team ][ teamCurrentInitialSpot[ player->team ]++ ]; - } - return initialSpots[ currentInitialSpot++ ]; -#else - } else if ( player->useInitialSpawns && currentInitialSpot < initialSpots.Num() ) { - return initialSpots[ currentInitialSpot++ ]; -#endif - } else { - // check if we are alone in map - alone = true; - for ( j = 0; j < MAX_CLIENTS; j++ ) { - if ( entities[ j ] && entities[ j ] != player ) { - alone = false; - break; - } - } - if ( alone ) { -#ifdef CTF - if ( mpGame.IsGametypeFlagBased() ) /* CTF */ - { - assert( player->team == 0 || player->team == 1 ); - return teamSpawnSpots[ player->team ][ random.RandomInt( teamSpawnSpots[ player->team ].Num() ) ].ent; - } -#endif - // don't do distance-based - return spawnSpots[ random.RandomInt( spawnSpots.Num() ) ].ent; - } - -#ifdef CTF - if ( mpGame.IsGametypeFlagBased() ) /* CTF */ - { - // TODO : make as reusable method, same code as below - int team = player->team; - assert( team == 0 || team == 1 ); - - // find the distance to the closest active player for each spawn spot - for( i = 0; i < teamSpawnSpots[ team ].Num(); i++ ) { - pos = teamSpawnSpots[ team ][ i ].ent->GetPhysics()->GetOrigin(); - - // skip initial spawn points for CTF - if ( teamSpawnSpots[ team ][ i ].ent->spawnArgs.GetBool("initial") ) { - teamSpawnSpots[ team ][ i ].dist = 0x0; - continue; - } - - teamSpawnSpots[ team ][ i ].dist = 0x7fffffff; - - for( j = 0; j < MAX_CLIENTS; j++ ) { - if ( !entities[ j ] || !entities[ j ]->IsType( idPlayer::Type ) - || entities[ j ] == player - || static_cast< idPlayer * >( entities[ j ] )->spectating ) { - continue; - } - - dist = ( pos - entities[ j ]->GetPhysics()->GetOrigin() ).LengthSqr(); - if ( dist < teamSpawnSpots[ team ][ i ].dist ) { - teamSpawnSpots[ team ][ i ].dist = dist; - } - } - } - - // sort the list - qsort( ( void * )teamSpawnSpots[ team ].Ptr(), teamSpawnSpots[ team ].Num(), sizeof( spawnSpot_t ), ( int (*)(const void *, const void *) )sortSpawnPoints ); - - // choose a random one in the top half - which = random.RandomInt( teamSpawnSpots[ team ].Num() / 2 ); - spot = teamSpawnSpots[ team ][ which ]; -// assert( teamSpawnSpots[ team ][ which ].dist != 0 ); - - return spot.ent; - } -#endif - - // find the distance to the closest active player for each spawn spot - for( i = 0; i < spawnSpots.Num(); i++ ) { - pos = spawnSpots[ i ].ent->GetPhysics()->GetOrigin(); - spawnSpots[ i ].dist = 0x7fffffff; - for( j = 0; j < MAX_CLIENTS; j++ ) { - if ( !entities[ j ] || !entities[ j ]->IsType( idPlayer::Type ) - || entities[ j ] == player - || static_cast< idPlayer * >( entities[ j ] )->spectating ) { - continue; - } - - dist = ( pos - entities[ j ]->GetPhysics()->GetOrigin() ).LengthSqr(); - if ( dist < spawnSpots[ i ].dist ) { - spawnSpots[ i ].dist = dist; - } - } - } - - // sort the list - qsort( ( void * )spawnSpots.Ptr(), spawnSpots.Num(), sizeof( spawnSpot_t ), ( int (*)(const void *, const void *) )sortSpawnPoints ); - - // choose a random one in the top half - which = random.RandomInt( spawnSpots.Num() / 2 ); - spot = spawnSpots[ which ]; - } - return spot.ent; -} - -/* -================ -idGameLocal::UpdateServerInfoFlags -================ -*/ -void idGameLocal::UpdateServerInfoFlags() { - gameType = GAME_SP; - if ( ( idStr::Icmp( serverInfo.GetString( "si_gameType" ), "deathmatch" ) == 0 ) ) { - gameType = GAME_DM; - } else if ( ( idStr::Icmp( serverInfo.GetString( "si_gameType" ), "Tourney" ) == 0 ) ) { - gameType = GAME_TOURNEY; - } else if ( ( idStr::Icmp( serverInfo.GetString( "si_gameType" ), "Team DM" ) == 0 ) ) { - gameType = GAME_TDM; - } else if ( ( idStr::Icmp( serverInfo.GetString( "si_gameType" ), "Last Man" ) == 0 ) ) { - gameType = GAME_LASTMAN; - } -#ifdef CTF - else if ( ( idStr::Icmp( serverInfo.GetString( "si_gameType" ), "CTF" ) == 0 ) ) { - gameType = GAME_CTF; - } -#endif - - if ( gameType == GAME_LASTMAN ) { - if ( !serverInfo.GetInt( "si_warmup" ) ) { - common->Warning( "Last Man Standing - forcing warmup on" ); - serverInfo.SetInt( "si_warmup", 1 ); - } - if ( serverInfo.GetInt( "si_fraglimit" ) <= 0 ) { - common->Warning( "Last Man Standing - setting fraglimit 1" ); - serverInfo.SetInt( "si_fraglimit", 1 ); - } - } -} - - -/* -================ -idGameLocal::SetGlobalMaterial -================ -*/ -void idGameLocal::SetGlobalMaterial( const idMaterial *mat ) { - globalMaterial = mat; -} - -/* -================ -idGameLocal::GetGlobalMaterial -================ -*/ -const idMaterial *idGameLocal::GetGlobalMaterial() { - return globalMaterial; -} - -/* -================ -idGameLocal::GetSpawnId -================ -*/ -int idGameLocal::GetSpawnId( const idEntity* ent ) const { - return ( gameLocal.spawnIds[ ent->entityNumber ] << GENTITYNUM_BITS ) | ent->entityNumber; -} - -/* -================ -idGameLocal::ThrottleUserInfo -================ -*/ -void idGameLocal::ThrottleUserInfo( void ) { - mpGame.ThrottleUserInfo(); -} - -#ifdef _D3XP -/* -================= -idPlayer::SetPortalSkyEnt -================= -*/ -void idGameLocal::SetPortalSkyEnt( idEntity *ent ) { - portalSkyEnt = ent; -} - -/* -================= -idPlayer::IsPortalSkyAcive -================= -*/ -bool idGameLocal::IsPortalSkyAcive() { - return portalSkyActive; -} - -/* -=========== -idGameLocal::SelectTimeGroup -============ -*/ -void idGameLocal::SelectTimeGroup( int timeGroup ) { - if ( timeGroup ) { - fast.Get( time, previousTime, msec, framenum, realClientTime ); - } else { - slow.Get( time, previousTime, msec, framenum, realClientTime ); - } -} - -/* -=========== -idGameLocal::GetTimeGroupTime -============ -*/ -int idGameLocal::GetTimeGroupTime( int timeGroup ) { - if ( timeGroup ) { - return fast.time; - } else { - return slow.time; - } -} - -/* -=============== -idGameLocal::GetBestGameType -=============== -*/ -void idGameLocal::GetBestGameType( const char* map, const char* gametype, char buf[ MAX_STRING_CHARS ] ) { - idStr aux = mpGame.GetBestGametype( map, gametype ); - idStr::Copynz( buf, aux.c_str(), MAX_STRING_CHARS ); - buf[ MAX_STRING_CHARS - 1 ] = '\0'; -} - -/* -=========== -idGameLocal::ComputeSlowMsec -============ -*/ -void idGameLocal::ComputeSlowMsec() { - idPlayer *player; - bool powerupOn; - float delta; - - // check if we need to do a quick reset - if ( quickSlowmoReset ) { - quickSlowmoReset = false; - - // stop the sounds - if ( gameSoundWorld ) { - gameSoundWorld->SetSlowmo( false ); - gameSoundWorld->SetSlowmoSpeed( 1 ); - } - - // stop the state - slowmoState = SLOWMO_STATE_OFF; - slowmoMsec = USERCMD_MSEC; - } - - // check the player state - player = GetLocalPlayer(); - powerupOn = false; - - if ( player && player->PowerUpActive( HELLTIME ) ) { - powerupOn = true; - } - else if ( g_enableSlowmo.GetBool() ) { - powerupOn = true; - } - - // determine proper slowmo state - if ( powerupOn && slowmoState == SLOWMO_STATE_OFF ) { - slowmoState = SLOWMO_STATE_RAMPUP; - - slowmoMsec = msec; - if ( gameSoundWorld ) { - gameSoundWorld->SetSlowmo( true ); - gameSoundWorld->SetSlowmoSpeed( slowmoMsec / (float)USERCMD_MSEC ); - } - } - else if ( !powerupOn && slowmoState == SLOWMO_STATE_ON ) { - slowmoState = SLOWMO_STATE_RAMPDOWN; - - // play the stop sound - if ( player ) { - player->PlayHelltimeStopSound(); - } - } - - // do any necessary ramping - if ( slowmoState == SLOWMO_STATE_RAMPUP ) { - delta = 4 - slowmoMsec; - - if ( fabs( delta ) < g_slowmoStepRate.GetFloat() ) { - slowmoMsec = 4; - slowmoState = SLOWMO_STATE_ON; - } - else { - slowmoMsec += delta * g_slowmoStepRate.GetFloat(); - } - - if ( gameSoundWorld ) { - gameSoundWorld->SetSlowmoSpeed( slowmoMsec / (float)USERCMD_MSEC ); - } - } - else if ( slowmoState == SLOWMO_STATE_RAMPDOWN ) { - delta = 16 - slowmoMsec; - - if ( fabs( delta ) < g_slowmoStepRate.GetFloat() ) { - slowmoMsec = 16; - slowmoState = SLOWMO_STATE_OFF; - if ( gameSoundWorld ) { - gameSoundWorld->SetSlowmo( false ); - } - } - else { - slowmoMsec += delta * g_slowmoStepRate.GetFloat(); - } - - if ( gameSoundWorld ) { - gameSoundWorld->SetSlowmoSpeed( slowmoMsec / (float)USERCMD_MSEC ); - } - } -} - -/* -=========== -idGameLocal::ResetSlowTimeVars -============ -*/ -void idGameLocal::ResetSlowTimeVars() { - msec = USERCMD_MSEC; - slowmoMsec = USERCMD_MSEC; - slowmoState = SLOWMO_STATE_OFF; - - fast.framenum = 0; - fast.previousTime = 0; - fast.time = 0; - fast.msec = USERCMD_MSEC; - - slow.framenum = 0; - slow.previousTime = 0; - slow.time = 0; - slow.msec = USERCMD_MSEC; -} - -/* -=========== -idGameLocal::QuickSlowmoReset -============ -*/ -void idGameLocal::QuickSlowmoReset() { - quickSlowmoReset = true; -} - -/* -=============== -idGameLocal::NeedRestart -=============== -*/ -bool idGameLocal::NeedRestart() { - - idDict newInfo; - const idKeyValue *keyval, *keyval2; - - newInfo = *cvarSystem->MoveCVarsToDict( CVAR_SERVERINFO ); - - for ( int i = 0; i < newInfo.GetNumKeyVals(); i++ ) { - keyval = newInfo.GetKeyVal( i ); - keyval2 = serverInfo.FindKey( keyval->GetKey() ); - if ( !keyval2 ) { - return true; - } - // a select set of si_ changes will cause a full restart of the server - if ( keyval->GetValue().Cmp( keyval2->GetValue() ) && ( !keyval->GetKey().Cmp( "si_pure" ) || !keyval->GetKey().Cmp( "si_map" ) ) ) { - return true; - } - } - return false; -} - -#endif - -/* -================ -idGameLocal::GetClientStats -================ -*/ -void idGameLocal::GetClientStats( int clientNum, char *data, const int len ) { - mpGame.PlayerStats( clientNum, data, len ); -} - - -/* -================ -idGameLocal::SwitchTeam -================ -*/ -void idGameLocal::SwitchTeam( int clientNum, int team ) { - - idPlayer * player; - player = static_cast< idPlayer * >( entities[ clientNum ] ); - int oldTeam = player->team ; - - // Put in spectator mode - if ( team == -1 ) { - static_cast< idPlayer * >( entities[ clientNum ] )->Spectate( true ); - } - // Switch to a team - else { - mpGame.SwitchToTeam ( clientNum, oldTeam, team ); - } - player->forceRespawn = true ; -} - -/* -=============== -idGameLocal::GetMapLoadingGUI -=============== -*/ -void idGameLocal::GetMapLoadingGUI( char gui[ MAX_STRING_CHARS ] ) { } diff --git a/d3xp/Game_local.h b/d3xp/Game_local.h deleted file mode 100644 index acd4fff0..00000000 --- a/d3xp/Game_local.h +++ /dev/null @@ -1,719 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __GAME_LOCAL_H__ -#define __GAME_LOCAL_H__ - -#include "GameBase.h" - -#include "idlib/containers/StrList.h" -#include "idlib/containers/LinkList.h" -#include "idlib/BitMsg.h" -#include "framework/Game.h" - -#include "gamesys/SaveGame.h" -#include "physics/Clip.h" -#include "physics/Push.h" -#include "script/Script_Program.h" -#include "ai/AAS.h" -#include "anim/Anim.h" -#include "Pvs.h" -#include "MultiplayerGame.h" - -#ifdef ID_DEBUG_UNINITIALIZED_MEMORY -// This is real evil but allows the code to inspect arbitrary class variables. -#define private public -#define protected public -#endif - -/* -=============================================================================== - - Local implementation of the public game interface. - -=============================================================================== -*/ -class idDeclEntityDef; -class idRenderWorld; -class idSoundWorld; -class idUserInterface; - -extern idRenderWorld * gameRenderWorld; -extern idSoundWorld * gameSoundWorld; - -// classes used by idGameLocal -class idEntity; -class idActor; -class idPlayer; -class idCamera; -class idWorldspawn; -class idTestModel; -class idSmokeParticles; -class idEntityFx; -class idTypeInfo; -class idThread; -class idEditEntities; -class idLocationEntity; - -//============================================================================ -extern const int NUM_RENDER_PORTAL_BITS; - -void gameError( const char *fmt, ... ); - -extern idRenderWorld * gameRenderWorld; -extern idSoundWorld * gameSoundWorld; - -extern const int NUM_RENDER_PORTAL_BITS; -/* -=============================================================================== - - Local implementation of the public game interface. - -=============================================================================== -*/ -typedef struct entityState_s { - int entityNumber; - idBitMsg state; - byte stateBuf[MAX_ENTITY_STATE_SIZE]; - struct entityState_s * next; -} entityState_t; - -typedef struct snapshot_s { - int sequence; - entityState_t * firstEntityState; - int pvs[ENTITY_PVS_SIZE]; - struct snapshot_s * next; -} snapshot_t; - -const int MAX_EVENT_PARAM_SIZE = 128; - -typedef struct entityNetEvent_s { - int spawnId; - int event; - int time; - int paramsSize; - byte paramsBuf[MAX_EVENT_PARAM_SIZE]; - struct entityNetEvent_s *next; - struct entityNetEvent_s *prev; -} entityNetEvent_t; - -enum { - GAME_RELIABLE_MESSAGE_INIT_DECL_REMAP, - GAME_RELIABLE_MESSAGE_REMAP_DECL, - GAME_RELIABLE_MESSAGE_SPAWN_PLAYER, - GAME_RELIABLE_MESSAGE_DELETE_ENT, - GAME_RELIABLE_MESSAGE_CHAT, - GAME_RELIABLE_MESSAGE_TCHAT, - GAME_RELIABLE_MESSAGE_SOUND_EVENT, - GAME_RELIABLE_MESSAGE_SOUND_INDEX, - GAME_RELIABLE_MESSAGE_DB, - GAME_RELIABLE_MESSAGE_KILL, - GAME_RELIABLE_MESSAGE_DROPWEAPON, - GAME_RELIABLE_MESSAGE_RESTART, - GAME_RELIABLE_MESSAGE_SERVERINFO, - GAME_RELIABLE_MESSAGE_TOURNEYLINE, - GAME_RELIABLE_MESSAGE_CALLVOTE, - GAME_RELIABLE_MESSAGE_CASTVOTE, - GAME_RELIABLE_MESSAGE_STARTVOTE, - GAME_RELIABLE_MESSAGE_UPDATEVOTE, - GAME_RELIABLE_MESSAGE_PORTALSTATES, - GAME_RELIABLE_MESSAGE_PORTAL, - GAME_RELIABLE_MESSAGE_VCHAT, - GAME_RELIABLE_MESSAGE_STARTSTATE, - GAME_RELIABLE_MESSAGE_MENU, - GAME_RELIABLE_MESSAGE_WARMUPTIME, - GAME_RELIABLE_MESSAGE_EVENT -}; - -typedef enum { - GAMESTATE_UNINITIALIZED, // prior to Init being called - GAMESTATE_NOMAP, // no map loaded - GAMESTATE_STARTUP, // inside InitFromNewMap(). spawning map entities. - GAMESTATE_ACTIVE, // normal gameplay - GAMESTATE_SHUTDOWN // inside MapShutdown(). clearing memory. -} gameState_t; - -typedef struct { - idEntity *ent; - int dist; -#ifdef CTF - int team; -#endif -} spawnSpot_t; - -//============================================================================ - -class idEventQueue { -public: - typedef enum { - OUTOFORDER_IGNORE, - OUTOFORDER_DROP, - OUTOFORDER_SORT - } outOfOrderBehaviour_t; - - idEventQueue() : start( NULL ), end( NULL ) {} - - entityNetEvent_t * Alloc(); - void Free( entityNetEvent_t *event ); - void Shutdown(); - - void Init(); - void Enqueue( entityNetEvent_t* event, outOfOrderBehaviour_t oooBehaviour ); - entityNetEvent_t * Dequeue( void ); - entityNetEvent_t * RemoveLast( void ); - - entityNetEvent_t * Start( void ) { return start; } - -private: - entityNetEvent_t * start; - entityNetEvent_t * end; - idBlockAlloc eventAllocator; -}; - -//============================================================================ - -template< class type > -class idEntityPtr { -public: - idEntityPtr(); - - // save games - void Save( idSaveGame *savefile ) const; // archives object for save game file - void Restore( idRestoreGame *savefile ); // unarchives object from save game file - - idEntityPtr & operator=( type *ent ); - - // synchronize entity pointers over the network - int GetSpawnId( void ) const { return spawnId; } - bool SetSpawnId( int id ); - bool UpdateSpawnId( void ); - - bool IsValid( void ) const; - type * GetEntity( void ) const; - int GetEntityNum( void ) const; - -private: - int spawnId; -}; - -#ifdef _D3XP -struct timeState_t { - int time; - int previousTime; - int msec; - int framenum; - int realClientTime; - - void Set( int t, int pt, int ms, int f, int rct ) { time = t; previousTime = pt; msec = ms; framenum = f; realClientTime = rct; }; - void Get( int& t, int& pt, int& ms, int& f, int& rct ) { t = time; pt = previousTime; ms = msec; f = framenum; rct = realClientTime; }; - void Save( idSaveGame *savefile ) const { savefile->WriteInt( time ); savefile->WriteInt( previousTime ); savefile->WriteInt( msec ); savefile->WriteInt( framenum ); savefile->WriteInt( realClientTime ); } - void Restore( idRestoreGame *savefile ) { savefile->ReadInt( time ); savefile->ReadInt( previousTime ); savefile->ReadInt( msec ); savefile->ReadInt( framenum ); savefile->ReadInt( realClientTime ); } - void Increment() { framenum++; previousTime = time; time += msec; realClientTime = time; }; -}; - -enum slowmoState_t { - SLOWMO_STATE_OFF, - SLOWMO_STATE_RAMPUP, - SLOWMO_STATE_ON, - SLOWMO_STATE_RAMPDOWN -}; -#endif - -//============================================================================ - -class idGameLocal : public idGame { -public: - idDict serverInfo; // all the tunable parameters, like numclients, etc - int numClients; // pulled from serverInfo and verified - idDict userInfo[MAX_CLIENTS]; // client specific settings - usercmd_t usercmds[MAX_CLIENTS]; // client input commands - idDict persistentPlayerInfo[MAX_CLIENTS]; - idEntity * entities[MAX_GENTITIES];// index to entities - int spawnIds[MAX_GENTITIES];// for use in idEntityPtr - int firstFreeIndex; // first free index in the entities array - int num_entities; // current number <= MAX_GENTITIES - idHashIndex entityHash; // hash table to quickly find entities by name - idWorldspawn * world; // world entity - idLinkList spawnedEntities; // all spawned entities - idLinkList activeEntities; // all thinking entities (idEntity::thinkFlags != 0) - int numEntitiesToDeactivate;// number of entities that became inactive in current frame - bool sortPushers; // true if active lists needs to be reordered to place pushers at the front - bool sortTeamMasters; // true if active lists needs to be reordered to place physics team masters before their slaves - idDict persistentLevelInfo; // contains args that are kept around between levels - - // can be used to automatically effect every material in the world that references globalParms - float globalShaderParms[ MAX_GLOBAL_SHADER_PARMS ]; - - idRandom random; // random number generator used throughout the game - - idProgram program; // currently loaded script and data space - idThread * frameCommandThread; - - idClip clip; // collision detection - idPush push; // geometric pushing - idPVS pvs; // potential visible set - - idTestModel * testmodel; // for development testing of models - idEntityFx * testFx; // for development testing of fx - - idStr sessionCommand; // a target_sessionCommand can set this to return something to the session - - idMultiplayerGame mpGame; // handles rules for standard dm - - idSmokeParticles * smokeParticles; // global smoke trails - idEditEntities * editEntities; // in game editing - - int cinematicSkipTime; // don't allow skipping cinemetics until this time has passed so player doesn't skip out accidently from a firefight - int cinematicStopTime; // cinematics have several camera changes, so keep track of when we stop them so that we don't reset cinematicSkipTime unnecessarily - int cinematicMaxSkipTime; // time to end cinematic when skipping. there's a possibility of an infinite loop if the map isn't set up right. - bool inCinematic; // game is playing cinematic (player controls frozen) - bool skipCinematic; - - // are kept up to date with changes to serverInfo - int framenum; - int previousTime; // time in msec of last frame - int time; // in msec - int msec; // time since last update in milliseconds - - int vacuumAreaNum; // -1 if level doesn't have any outside areas - - gameType_t gameType; - bool isMultiplayer; // set if the game is run in multiplayer mode - bool isServer; // set if the game is run for a dedicated or listen server - bool isClient; // set if the game is run for a client - // discriminates between the RunFrame path and the ClientPrediction path - // NOTE: on a listen server, isClient is false - int localClientNum; // number of the local client. MP: -1 on a dedicated - idLinkList snapshotEntities; // entities from the last snapshot - int realClientTime; // real client time - bool isNewFrame; // true if this is a new game frame, not a rerun due to prediction - float clientSmoothing; // smoothing of other clients in the view - int entityDefBits; // bits required to store an entity def number - - static const char * sufaceTypeNames[ MAX_SURFACE_TYPES ]; // text names for surface types - - idEntityPtr lastGUIEnt; // last entity with a GUI, used by Cmd_NextGUI_f - int lastGUI; // last GUI on the lastGUIEnt - -#ifdef _D3XP - idEntityPtr portalSkyEnt; - bool portalSkyActive; - - void SetPortalSkyEnt( idEntity *ent ); - bool IsPortalSkyAcive(); - - timeState_t fast; - timeState_t slow; - - slowmoState_t slowmoState; - float slowmoMsec; - - bool quickSlowmoReset; - - virtual void SelectTimeGroup( int timeGroup ); - virtual int GetTimeGroupTime( int timeGroup ); - - virtual void GetBestGameType( const char* map, const char* gametype, char buf[ MAX_STRING_CHARS ] ); - - void ComputeSlowMsec(); - void RunTimeGroup2(); - - void ResetSlowTimeVars(); - void QuickSlowmoReset(); - - bool NeedRestart(); -#endif - - void Tokenize( idStrList &out, const char *in ); - - // ---------------------- Public idGame Interface ------------------- - - idGameLocal(); - - virtual void Init( void ); - virtual void Shutdown( void ); - virtual void SetLocalClient( int clientNum ); - virtual void ThrottleUserInfo( void ); - virtual const idDict * SetUserInfo( int clientNum, const idDict &userInfo, bool isClient, bool canModify ); - virtual const idDict * GetUserInfo( int clientNum ); - virtual void SetServerInfo( const idDict &serverInfo ); - - virtual const idDict & GetPersistentPlayerInfo( int clientNum ); - virtual void SetPersistentPlayerInfo( int clientNum, const idDict &playerInfo ); - virtual void InitFromNewMap( const char *mapName, idRenderWorld *renderWorld, idSoundWorld *soundWorld, bool isServer, bool isClient, int randSeed ); - virtual bool InitFromSaveGame( const char *mapName, idRenderWorld *renderWorld, idSoundWorld *soundWorld, idFile *saveGameFile ); - virtual void SaveGame( idFile *saveGameFile ); - virtual void MapShutdown( void ); - virtual void CacheDictionaryMedia( const idDict *dict ); - virtual void SpawnPlayer( int clientNum ); - virtual gameReturn_t RunFrame( const usercmd_t *clientCmds ); - virtual bool Draw( int clientNum ); - virtual escReply_t HandleESC( idUserInterface **gui ); - virtual idUserInterface *StartMenu( void ); - virtual const char * HandleGuiCommands( const char *menuCommand ); - virtual void HandleMainMenuCommands( const char *menuCommand, idUserInterface *gui ); - virtual allowReply_t ServerAllowClient( int numClients, const char *IP, const char *guid, const char *password, char reason[MAX_STRING_CHARS] ); - virtual void ServerClientConnect( int clientNum, const char *guid ); - virtual void ServerClientBegin( int clientNum ); - virtual void ServerClientDisconnect( int clientNum ); - virtual void ServerWriteInitialReliableMessages( int clientNum ); - virtual void ServerWriteSnapshot( int clientNum, int sequence, idBitMsg &msg, byte *clientInPVS, int numPVSClients ); - virtual bool ServerApplySnapshot( int clientNum, int sequence ); - virtual void ServerProcessReliableMessage( int clientNum, const idBitMsg &msg ); - virtual void ClientReadSnapshot( int clientNum, int sequence, const int gameFrame, const int gameTime, const int dupeUsercmds, const int aheadOfServer, const idBitMsg &msg ); - virtual bool ClientApplySnapshot( int clientNum, int sequence ); - virtual void ClientProcessReliableMessage( int clientNum, const idBitMsg &msg ); - virtual gameReturn_t ClientPrediction( int clientNum, const usercmd_t *clientCmds, bool lastPredictFrame ); - - virtual void GetClientStats( int clientNum, char *data, const int len ); - virtual void SwitchTeam( int clientNum, int team ); - - virtual bool DownloadRequest( const char *IP, const char *guid, const char *paks, char urls[ MAX_STRING_CHARS ] ); - - virtual void GetMapLoadingGUI( char gui[ MAX_STRING_CHARS ] ); - - // ---------------------- Public idGameLocal Interface ------------------- - - void Printf( const char *fmt, ... ) const id_attribute((format(printf,2,3))); - void DPrintf( const char *fmt, ... ) const id_attribute((format(printf,2,3))); - void Warning( const char *fmt, ... ) const id_attribute((format(printf,2,3))); - void DWarning( const char *fmt, ... ) const id_attribute((format(printf,2,3))); - void Error( const char *fmt, ... ) const id_attribute((format(printf,2,3))); - - // Initializes all map variables common to both save games and spawned games - void LoadMap( const char *mapName, int randseed ); - - void LocalMapRestart( void ); - void MapRestart( void ); - static void MapRestart_f( const idCmdArgs &args ); - bool NextMap( void ); // returns wether serverinfo settings have been modified - static void NextMap_f( const idCmdArgs &args ); - - idMapFile * GetLevelMap( void ); - const char * GetMapName( void ) const; - - int NumAAS( void ) const; - idAAS * GetAAS( int num ) const; - idAAS * GetAAS( const char *name ) const; - void SetAASAreaState( const idBounds &bounds, const int areaContents, bool closed ); - aasHandle_t AddAASObstacle( const idBounds &bounds ); - void RemoveAASObstacle( const aasHandle_t handle ); - void RemoveAllAASObstacles( void ); - - bool CheatsOk( bool requirePlayer = true ); - void SetSkill( int value ); - gameState_t GameState( void ) const; - idEntity * SpawnEntityType( const idTypeInfo &classdef, const idDict *args = NULL, bool bIsClientReadSnapshot = false ); - bool SpawnEntityDef( const idDict &args, idEntity **ent = NULL, bool setDefaults = true ); - int GetSpawnId( const idEntity *ent ) const; - - const idDeclEntityDef * FindEntityDef( const char *name, bool makeDefault = true ) const; - const idDict * FindEntityDefDict( const char *name, bool makeDefault = true ) const; - - void RegisterEntity( idEntity *ent ); - void UnregisterEntity( idEntity *ent ); - - bool RequirementMet( idEntity *activator, const idStr &requires, int removeItem ); - - void AlertAI( idEntity *ent ); - idActor * GetAlertEntity( void ); - - bool InPlayerPVS( idEntity *ent ) const; - bool InPlayerConnectedArea( idEntity *ent ) const; -#ifdef _D3XP - pvsHandle_t GetPlayerPVS() { return playerPVS; }; -#endif - - void SetCamera( idCamera *cam ); - idCamera * GetCamera( void ) const; - bool SkipCinematic( void ); - void CalcFov( float base_fov, float &fov_x, float &fov_y ) const; - - void AddEntityToHash( const char *name, idEntity *ent ); - bool RemoveEntityFromHash( const char *name, idEntity *ent ); - int GetTargets( const idDict &args, idList< idEntityPtr > &list, const char *ref ) const; - - // returns the master entity of a trace. for example, if the trace entity is the player's head, it will return the player. - idEntity * GetTraceEntity( const trace_t &trace ) const; - - static void ArgCompletion_EntityName( const idCmdArgs &args, void(*callback)( const char *s ) ); - idEntity * FindTraceEntity( idVec3 start, idVec3 end, const idTypeInfo &c, const idEntity *skip ) const; - idEntity * FindEntity( const char *name ) const; - idEntity * FindEntityUsingDef( idEntity *from, const char *match ) const; - int EntitiesWithinRadius( const idVec3 org, float radius, idEntity **entityList, int maxCount ) const; - - void KillBox( idEntity *ent, bool catch_teleport = false ); - void RadiusDamage( const idVec3 &origin, idEntity *inflictor, idEntity *attacker, idEntity *ignoreDamage, idEntity *ignorePush, const char *damageDefName, float dmgPower = 1.0f ); - void RadiusPush( const idVec3 &origin, const float radius, const float push, const idEntity *inflictor, const idEntity *ignore, float inflictorScale, const bool quake ); - void RadiusPushClipModel( const idVec3 &origin, const float push, const idClipModel *clipModel ); - - void ProjectDecal( const idVec3 &origin, const idVec3 &dir, float depth, bool parallel, float size, const char *material, float angle = 0 ); - void BloodSplat( const idVec3 &origin, const idVec3 &dir, float size, const char *material ); - - void CallFrameCommand( idEntity *ent, const function_t *frameCommand ); - void CallObjectFrameCommand( idEntity *ent, const char *frameCommand ); - - const idVec3 & GetGravity( void ) const; - - // added the following to assist licensees with merge issues - int GetFrameNum() const { return framenum; }; - int GetTime() const { return time; }; - int GetMSec() const { return msec; }; - - int GetNextClientNum( int current ) const; - idPlayer * GetClientByNum( int current ) const; - idPlayer * GetClientByName( const char *name ) const; - idPlayer * GetClientByCmdArgs( const idCmdArgs &args ) const; - - idPlayer * GetLocalPlayer() const; - - void SpreadLocations(); - idLocationEntity * LocationForPoint( const idVec3 &point ); // May return NULL - idEntity * SelectInitialSpawnPoint( idPlayer *player ); - - void SetPortalState( qhandle_t portal, int blockingBits ); - void SaveEntityNetworkEvent( const idEntity *ent, int event, const idBitMsg *msg ); - void ServerSendChatMessage( int to, const char *name, const char *text ); - int ServerRemapDecl( int clientNum, declType_t type, int index ); - int ClientRemapDecl( declType_t type, int index ); - - void SetGlobalMaterial( const idMaterial *mat ); - const idMaterial * GetGlobalMaterial(); - - void SetGibTime( int _time ) { nextGibTime = _time; }; - int GetGibTime() { return nextGibTime; }; - - - -private: - const static int INITIAL_SPAWN_COUNT = 1; - const static int INTERNAL_SAVEGAME_VERSION = 1; // DG: added this for >= 1305 savegames - - idStr mapFileName; // name of the map, empty string if no map loaded - idMapFile * mapFile; // will be NULL during the game unless in-game editing is used - bool mapCycleLoaded; - - int spawnCount; - int mapSpawnCount; // it's handy to know which entities are part of the map - - idLocationEntity ** locationEntities; // for location names, etc - - idCamera * camera; - const idMaterial * globalMaterial; // for overriding everything - - idList aasList; // area system - idStrList aasNames; - - idEntityPtr lastAIAlertEntity; - int lastAIAlertTime; - - idDict spawnArgs; // spawn args used during entity spawning FIXME: shouldn't be necessary anymore - - pvsHandle_t playerPVS; // merged pvs of all players - pvsHandle_t playerConnectedAreas; // all areas connected to any player area - - idVec3 gravity; // global gravity vector - gameState_t gamestate; // keeps track of whether we're spawning, shutting down, or normal gameplay - bool influenceActive; // true when a phantasm is happening - int nextGibTime; - - idList clientDeclRemap[MAX_CLIENTS][DECL_MAX_TYPES]; - - entityState_t * clientEntityStates[MAX_CLIENTS][MAX_GENTITIES]; - int clientPVS[MAX_CLIENTS][ENTITY_PVS_SIZE]; - snapshot_t * clientSnapshots[MAX_CLIENTS]; - idBlockAllocentityStateAllocator; - idBlockAllocsnapshotAllocator; - - idEventQueue eventQueue; - idEventQueue savedEventQueue; - - idStaticList spawnSpots; - idStaticList initialSpots; - int currentInitialSpot; - -#ifdef CTF - idStaticList teamSpawnSpots[2]; - idStaticList teamInitialSpots[2]; - int teamCurrentInitialSpot[2]; -#endif - - idDict newInfo; - - idStrList shakeSounds; - - byte lagometer[ LAGO_IMG_HEIGHT ][ LAGO_IMG_WIDTH ][ 4 ]; - - void Clear( void ); - // returns true if the entity shouldn't be spawned at all in this game type or difficulty level - bool InhibitEntitySpawn( idDict &spawnArgs ); - // spawn entities from the map file - void SpawnMapEntities( void ); - // commons used by init, shutdown, and restart - void MapPopulate( void ); - void MapClear( bool clearClients ); - - pvsHandle_t GetClientPVS( idPlayer *player, pvsType_t type ); - void SetupPlayerPVS( void ); - void FreePlayerPVS( void ); - void UpdateGravity( void ); - void SortActiveEntityList( void ); - void ShowTargets( void ); - void RunDebugInfo( void ); - - void InitScriptForMap( void ); - - void InitConsoleCommands( void ); - void ShutdownConsoleCommands( void ); - - void InitAsyncNetwork( void ); - void ShutdownAsyncNetwork( void ); - void InitLocalClient( int clientNum ); - void InitClientDeclRemap( int clientNum ); - void ServerSendDeclRemapToClient( int clientNum, declType_t type, int index ); - void FreeSnapshotsOlderThanSequence( int clientNum, int sequence ); - bool ApplySnapshot( int clientNum, int sequence ); - void WriteGameStateToSnapshot( idBitMsgDelta &msg ) const; - void ReadGameStateFromSnapshot( const idBitMsgDelta &msg ); - void NetworkEventWarning( const entityNetEvent_t *event, const char *fmt, ... ) id_attribute((format(printf,3,4))); - void ServerProcessEntityNetworkEventQueue( void ); - void ClientProcessEntityNetworkEventQueue( void ); - void ClientShowSnapshot( int clientNum ) const; - // call after any change to serverInfo. Will update various quick-access flags - void UpdateServerInfoFlags( void ); - void RandomizeInitialSpawns( void ); - static int sortSpawnPoints( const void *ptr1, const void *ptr2 ); - - void DumpOggSounds( void ); - void GetShakeSounds( const idDict *dict ); - - void UpdateLagometer( int aheadOfServer, int dupeUsercmds ); -}; - -//============================================================================ - -extern idGameLocal gameLocal; -extern idAnimManager animationLib; - -//============================================================================ - -class idGameError : public idException { -public: - idGameError( const char *text ) : idException( text ) {} -}; - -//============================================================================ - -template< class type > -ID_INLINE idEntityPtr::idEntityPtr() { - spawnId = 0; -} - -template< class type > -ID_INLINE void idEntityPtr::Save( idSaveGame *savefile ) const { - savefile->WriteInt( spawnId ); -} - -template< class type > -ID_INLINE void idEntityPtr::Restore( idRestoreGame *savefile ) { - savefile->ReadInt( spawnId ); -} - -template< class type > -ID_INLINE idEntityPtr &idEntityPtr::operator=( type *ent ) { - if ( ent == NULL ) { - spawnId = 0; - } else { - spawnId = ( gameLocal.spawnIds[ent->entityNumber] << GENTITYNUM_BITS ) | ent->entityNumber; - } - return *this; -} - -template< class type > -ID_INLINE bool idEntityPtr::SetSpawnId( int id ) { - // the reason for this first check is unclear: - // the function returning false may mean the spawnId is already set right, or the entity is missing - if ( id == spawnId ) { - return false; - } - if ( ( id >> GENTITYNUM_BITS ) == gameLocal.spawnIds[ id & ( ( 1 << GENTITYNUM_BITS ) - 1 ) ] ) { - spawnId = id; - return true; - } - return false; -} - -template< class type > -ID_INLINE bool idEntityPtr::IsValid( void ) const { - return ( gameLocal.spawnIds[ spawnId & ( ( 1 << GENTITYNUM_BITS ) - 1 ) ] == ( spawnId >> GENTITYNUM_BITS ) ); -} - -template< class type > -ID_INLINE type *idEntityPtr::GetEntity( void ) const { - int entityNum = spawnId & ( ( 1 << GENTITYNUM_BITS ) - 1 ); - if ( gameLocal.spawnIds[ entityNum ] == ( spawnId >> GENTITYNUM_BITS ) ) { - return static_cast( gameLocal.entities[ entityNum ] ); - } - return NULL; -} - -template< class type > -ID_INLINE int idEntityPtr::GetEntityNum( void ) const { - return ( spawnId & ( ( 1 << GENTITYNUM_BITS ) - 1 ) ); -} - -// =========================================================================== - -// -// these defines work for all startsounds from all entity types -// make sure to change script/doom_defs.script if you add any channels, or change their order -// -typedef enum { - SND_CHANNEL_ANY = SCHANNEL_ANY, - SND_CHANNEL_VOICE = SCHANNEL_ONE, - SND_CHANNEL_VOICE2, - SND_CHANNEL_BODY, - SND_CHANNEL_BODY2, - SND_CHANNEL_BODY3, - SND_CHANNEL_WEAPON, - SND_CHANNEL_ITEM, - SND_CHANNEL_HEART, - SND_CHANNEL_PDA, - SND_CHANNEL_DEMONIC, - SND_CHANNEL_RADIO, - - // internal use only. not exposed to script or framecommands. - SND_CHANNEL_AMBIENT, - SND_CHANNEL_DAMAGE -} gameSoundChannel_t; - -extern const float DEFAULT_GRAVITY; -extern const idVec3 DEFAULT_GRAVITY_VEC3; -extern const int CINEMATIC_SKIP_DELAY; - -#endif /* !__GAME_LOCAL_H__ */ diff --git a/d3xp/Game_network.cpp b/d3xp/Game_network.cpp deleted file mode 100644 index 7c3bb140..00000000 --- a/d3xp/Game_network.cpp +++ /dev/null @@ -1,1803 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "framework/FileSystem.h" -#include "framework/async/NetworkSystem.h" -#include "renderer/RenderSystem.h" - -#include "gamesys/SysCmds.h" -#include "Entity.h" -#include "Player.h" - -#include "Game_local.h" - -/* -=============================================================================== - - Client running game code: - - entity events don't work and should not be issued - - entities should never be spawned outside idGameLocal::ClientReadSnapshot - -=============================================================================== -*/ - -// adds tags to the network protocol to detect when things go bad ( internal consistency ) -// NOTE: this changes the network protocol -#ifndef ASYNC_WRITE_TAGS - #define ASYNC_WRITE_TAGS 0 -#endif - -idCVar net_clientShowSnapshot( "net_clientShowSnapshot", "0", CVAR_GAME | CVAR_INTEGER, "", 0, 3, idCmdSystem::ArgCompletion_Integer<0,3> ); -idCVar net_clientShowSnapshotRadius( "net_clientShowSnapshotRadius", "128", CVAR_GAME | CVAR_FLOAT, "" ); -idCVar net_clientSmoothing( "net_clientSmoothing", "0.8", CVAR_GAME | CVAR_FLOAT, "smooth other clients angles and position.", 0.0f, 0.95f ); -idCVar net_clientSelfSmoothing( "net_clientSelfSmoothing", "0.6", CVAR_GAME | CVAR_FLOAT, "smooth self position if network causes prediction error.", 0.0f, 0.95f ); -idCVar net_clientMaxPrediction( "net_clientMaxPrediction", "1000", CVAR_SYSTEM | CVAR_INTEGER | CVAR_NOCHEAT, "maximum number of milliseconds a client can predict ahead of server." ); -idCVar net_clientLagOMeter( "net_clientLagOMeter", "1", CVAR_GAME | CVAR_BOOL | CVAR_NOCHEAT | CVAR_ARCHIVE, "draw prediction graph" ); - -/* -================ -idGameLocal::InitAsyncNetwork -================ -*/ -void idGameLocal::InitAsyncNetwork( void ) { - int i, type; - - for ( i = 0; i < MAX_CLIENTS; i++ ) { - for ( type = 0; type < declManager->GetNumDeclTypes(); type++ ) { - clientDeclRemap[i][type].Clear(); - } - } - - memset( clientEntityStates, 0, sizeof( clientEntityStates ) ); - memset( clientPVS, 0, sizeof( clientPVS ) ); - memset( clientSnapshots, 0, sizeof( clientSnapshots ) ); - - eventQueue.Init(); - savedEventQueue.Init(); - - entityDefBits = -( idMath::BitsForInteger( declManager->GetNumDecls( DECL_ENTITYDEF ) ) + 1 ); - localClientNum = 0; // on a listen server SetLocalUser will set this right - realClientTime = 0; - isNewFrame = true; - clientSmoothing = net_clientSmoothing.GetFloat(); -} - -/* -================ -idGameLocal::ShutdownAsyncNetwork -================ -*/ -void idGameLocal::ShutdownAsyncNetwork( void ) { - entityStateAllocator.Shutdown(); - snapshotAllocator.Shutdown(); - eventQueue.Shutdown(); - savedEventQueue.Shutdown(); - memset( clientEntityStates, 0, sizeof( clientEntityStates ) ); - memset( clientPVS, 0, sizeof( clientPVS ) ); - memset( clientSnapshots, 0, sizeof( clientSnapshots ) ); -} - -/* -================ -idGameLocal::InitLocalClient -================ -*/ -void idGameLocal::InitLocalClient( int clientNum ) { - isServer = false; - isClient = true; - localClientNum = clientNum; - clientSmoothing = net_clientSmoothing.GetFloat(); -} - -/* -================ -idGameLocal::InitClientDeclRemap -================ -*/ -void idGameLocal::InitClientDeclRemap( int clientNum ) { - int type, i, num; - - for ( type = 0; type < declManager->GetNumDeclTypes(); type++ ) { - - // only implicit materials and sound shaders decls are used - if ( type != DECL_MATERIAL && type != DECL_SOUND ) { - continue; - } - - num = declManager->GetNumDecls( (declType_t) type ); - clientDeclRemap[clientNum][type].Clear(); - clientDeclRemap[clientNum][type].AssureSize( num, -1 ); - - // pre-initialize the remap with non-implicit decls, all non-implicit decls are always going - // to be in order and in sync between server and client because of the decl manager checksum - for ( i = 0; i < num; i++ ) { - const idDecl *decl = declManager->DeclByIndex( (declType_t) type, i, false ); - if ( decl->IsImplicit() ) { - // once the first implicit decl is found all remaining decls are considered implicit as well - break; - } - clientDeclRemap[clientNum][type][i] = i; - } - } -} - -/* -================ -idGameLocal::ServerSendDeclRemapToClient -================ -*/ -void idGameLocal::ServerSendDeclRemapToClient( int clientNum, declType_t type, int index ) { - idBitMsg outMsg; - byte msgBuf[MAX_GAME_MESSAGE_SIZE]; - - // if no client connected for this spot - if ( entities[clientNum] == NULL ) { - return; - } - // increase size of list if required - if ( index >= clientDeclRemap[clientNum][type].Num() ) { - clientDeclRemap[clientNum][(int)type].AssureSize( index + 1, -1 ); - } - // if already remapped - if ( clientDeclRemap[clientNum][(int)type][index] != -1 ) { - return; - } - - const idDecl *decl = declManager->DeclByIndex( type, index, false ); - if ( decl == NULL ) { - gameLocal.Error( "server tried to remap bad %s decl index %d", declManager->GetDeclNameFromType( type ), index ); - return; - } - - // set the index at the server - clientDeclRemap[clientNum][(int)type][index] = index; - - // write update to client - outMsg.Init( msgBuf, sizeof( msgBuf ) ); - outMsg.BeginWriting(); - outMsg.WriteByte( GAME_RELIABLE_MESSAGE_REMAP_DECL ); - outMsg.WriteByte( type ); - outMsg.WriteInt( index ); - outMsg.WriteString( decl->GetName() ); - networkSystem->ServerSendReliableMessage( clientNum, outMsg ); -} - -/* -================ -idGameLocal::ServerRemapDecl -================ -*/ -int idGameLocal::ServerRemapDecl( int clientNum, declType_t type, int index ) { - - // only implicit materials and sound shaders decls are used - if ( type != DECL_MATERIAL && type != DECL_SOUND ) { - return index; - } - - if ( clientNum == -1 ) { - for ( int i = 0; i < MAX_CLIENTS; i++ ) { - ServerSendDeclRemapToClient( i, type, index ); - } - } else { - ServerSendDeclRemapToClient( clientNum, type, index ); - } - return index; -} - -/* -================ -idGameLocal::ClientRemapDecl -================ -*/ -int idGameLocal::ClientRemapDecl( declType_t type, int index ) { - - // only implicit materials and sound shaders decls are used - if ( type != DECL_MATERIAL && type != DECL_SOUND ) { - return index; - } - - // negative indexes are sometimes used for NULL decls - if ( index < 0 ) { - return index; - } - - // make sure the index is valid - if ( clientDeclRemap[localClientNum][(int)type].Num() == 0 ) { - gameLocal.Error( "client received decl index %d before %s decl remap was initialized", index, declManager->GetDeclNameFromType( type ) ); - return -1; - } - if ( index >= clientDeclRemap[localClientNum][(int)type].Num() ) { - gameLocal.Error( "client received unmapped %s decl index %d from server", declManager->GetDeclNameFromType( type ), index ); - return -1; - } - if ( clientDeclRemap[localClientNum][(int)type][index] == -1 ) { - gameLocal.Error( "client received unmapped %s decl index %d from server", declManager->GetDeclNameFromType( type ), index ); - return -1; - } - return clientDeclRemap[localClientNum][type][index]; -} - -/* -================ -idGameLocal::ServerAllowClient -================ -*/ -allowReply_t idGameLocal::ServerAllowClient( int numClients, const char *IP, const char *guid, const char *password, char reason[ MAX_STRING_CHARS ] ) { - reason[0] = '\0'; - - if ( serverInfo.GetInt( "si_pure" ) && !mpGame.IsPureReady() ) { - idStr::snPrintf( reason, MAX_STRING_CHARS, "#str_07139" ); - return ALLOW_NOTYET; - } - - if ( !serverInfo.GetInt( "si_maxPlayers" ) ) { - idStr::snPrintf( reason, MAX_STRING_CHARS, "#str_07140" ); - return ALLOW_NOTYET; - } - - if ( numClients >= serverInfo.GetInt( "si_maxPlayers" ) ) { - idStr::snPrintf( reason, MAX_STRING_CHARS, "#str_07141" ); - return ALLOW_NOTYET; - } - - if ( !cvarSystem->GetCVarBool( "si_usepass" ) ) { - return ALLOW_YES; - } - - const char *pass = cvarSystem->GetCVarString( "g_password" ); - if ( pass[ 0 ] == '\0' ) { - common->Warning( "si_usepass is set but g_password is empty" ); - cmdSystem->BufferCommandText( CMD_EXEC_NOW, "say si_usepass is set but g_password is empty" ); - // avoids silent misconfigured state - idStr::snPrintf( reason, MAX_STRING_CHARS, "#str_07142" ); - return ALLOW_NOTYET; - } - - if ( !idStr::Cmp( pass, password ) ) { - return ALLOW_YES; - } - - idStr::snPrintf( reason, MAX_STRING_CHARS, "#str_07143" ); - Printf( "Rejecting client %s from IP %s: invalid password\n", guid, IP ); - return ALLOW_BADPASS; -} - -/* -================ -idGameLocal::ServerClientConnect -================ -*/ -void idGameLocal::ServerClientConnect( int clientNum, const char *guid ) { - // make sure no parasite entity is left - if ( entities[ clientNum ] ) { - common->DPrintf( "ServerClientConnect: remove old player entity\n" ); - delete entities[ clientNum ]; - } - userInfo[ clientNum ].Clear(); - mpGame.ServerClientConnect( clientNum ); - Printf( "client %d connected.\n", clientNum ); -} - -/* -================ -idGameLocal::ServerClientBegin -================ -*/ -void idGameLocal::ServerClientBegin( int clientNum ) { - idBitMsg outMsg; - byte msgBuf[MAX_GAME_MESSAGE_SIZE]; - - // initialize the decl remap - InitClientDeclRemap( clientNum ); - - // send message to initialize decl remap at the client (this is always the very first reliable game message) - outMsg.Init( msgBuf, sizeof( msgBuf ) ); - outMsg.BeginWriting(); - outMsg.WriteByte( GAME_RELIABLE_MESSAGE_INIT_DECL_REMAP ); - networkSystem->ServerSendReliableMessage( clientNum, outMsg ); - - // spawn the player - SpawnPlayer( clientNum ); - if ( clientNum == localClientNum ) { - mpGame.EnterGame( clientNum ); - } - - // send message to spawn the player at the clients - outMsg.Init( msgBuf, sizeof( msgBuf ) ); - outMsg.BeginWriting(); - outMsg.WriteByte( GAME_RELIABLE_MESSAGE_SPAWN_PLAYER ); - outMsg.WriteByte( clientNum ); - outMsg.WriteInt( spawnIds[ clientNum ] ); - networkSystem->ServerSendReliableMessage( -1, outMsg ); -} - -/* -================ -idGameLocal::ServerClientDisconnect -================ -*/ -void idGameLocal::ServerClientDisconnect( int clientNum ) { - int i; - idBitMsg outMsg; - byte msgBuf[MAX_GAME_MESSAGE_SIZE]; - - outMsg.Init( msgBuf, sizeof( msgBuf ) ); - outMsg.BeginWriting(); - outMsg.WriteByte( GAME_RELIABLE_MESSAGE_DELETE_ENT ); - outMsg.WriteBits( ( spawnIds[ clientNum ] << GENTITYNUM_BITS ) | clientNum, 32 ); // see GetSpawnId - networkSystem->ServerSendReliableMessage( -1, outMsg ); - - // free snapshots stored for this client - FreeSnapshotsOlderThanSequence( clientNum, 0x7FFFFFFF ); - - // free entity states stored for this client - for ( i = 0; i < MAX_GENTITIES; i++ ) { - if ( clientEntityStates[ clientNum ][ i ] ) { - entityStateAllocator.Free( clientEntityStates[ clientNum ][ i ] ); - clientEntityStates[ clientNum ][ i ] = NULL; - } - } - - // clear the client PVS - memset( clientPVS[ clientNum ], 0, sizeof( clientPVS[ clientNum ] ) ); - - // delete the player entity - delete entities[ clientNum ]; - - mpGame.DisconnectClient( clientNum ); - -} - -/* -================ -idGameLocal::ServerWriteInitialReliableMessages - - Send reliable messages to initialize the client game up to a certain initial state. -================ -*/ -void idGameLocal::ServerWriteInitialReliableMessages( int clientNum ) { - int i; - idBitMsg outMsg; - byte msgBuf[MAX_GAME_MESSAGE_SIZE]; - entityNetEvent_t *event; - - // spawn players - for ( i = 0; i < MAX_CLIENTS; i++ ) { - if ( entities[i] == NULL || i == clientNum ) { - continue; - } - outMsg.Init( msgBuf, sizeof( msgBuf ) ); - outMsg.BeginWriting( ); - outMsg.WriteByte( GAME_RELIABLE_MESSAGE_SPAWN_PLAYER ); - outMsg.WriteByte( i ); - outMsg.WriteInt( spawnIds[ i ] ); - networkSystem->ServerSendReliableMessage( clientNum, outMsg ); - } - - // send all saved events - for ( event = savedEventQueue.Start(); event; event = event->next ) { - outMsg.Init( msgBuf, sizeof( msgBuf ) ); - outMsg.BeginWriting(); - outMsg.WriteByte( GAME_RELIABLE_MESSAGE_EVENT ); - outMsg.WriteBits( event->spawnId, 32 ); - outMsg.WriteByte( event->event ); - outMsg.WriteInt( event->time ); - outMsg.WriteBits( event->paramsSize, idMath::BitsForInteger( MAX_EVENT_PARAM_SIZE ) ); - if ( event->paramsSize ) { - outMsg.WriteData( event->paramsBuf, event->paramsSize ); - } - - networkSystem->ServerSendReliableMessage( clientNum, outMsg ); - } - - // update portals for opened doors - int numPortals = gameRenderWorld->NumPortals(); - outMsg.Init( msgBuf, sizeof( msgBuf ) ); - outMsg.BeginWriting(); - outMsg.WriteByte( GAME_RELIABLE_MESSAGE_PORTALSTATES ); - outMsg.WriteInt( numPortals ); - for ( i = 0; i < numPortals; i++ ) { - outMsg.WriteBits( gameRenderWorld->GetPortalState( (qhandle_t) (i+1) ) , NUM_RENDER_PORTAL_BITS ); - } - networkSystem->ServerSendReliableMessage( clientNum, outMsg ); - - mpGame.ServerWriteInitialReliableMessages( clientNum ); -} - -/* -================ -idGameLocal::SaveEntityNetworkEvent -================ -*/ -void idGameLocal::SaveEntityNetworkEvent( const idEntity *ent, int eventId, const idBitMsg *msg ) { - entityNetEvent_t *event; - - event = savedEventQueue.Alloc(); - event->spawnId = GetSpawnId( ent ); - event->event = eventId; - event->time = time; - if ( msg ) { - event->paramsSize = msg->GetSize(); - memcpy( event->paramsBuf, msg->GetData(), msg->GetSize() ); - } else { - event->paramsSize = 0; - } - - savedEventQueue.Enqueue( event, idEventQueue::OUTOFORDER_IGNORE ); -} - -/* -================ -idGameLocal::FreeSnapshotsOlderThanSequence -================ -*/ -void idGameLocal::FreeSnapshotsOlderThanSequence( int clientNum, int sequence ) { - snapshot_t *snapshot, *lastSnapshot, *nextSnapshot; - entityState_t *state; - - for ( lastSnapshot = NULL, snapshot = clientSnapshots[clientNum]; snapshot; snapshot = nextSnapshot ) { - nextSnapshot = snapshot->next; - if ( snapshot->sequence < sequence ) { - for ( state = snapshot->firstEntityState; state; state = snapshot->firstEntityState ) { - snapshot->firstEntityState = snapshot->firstEntityState->next; - entityStateAllocator.Free( state ); - } - if ( lastSnapshot ) { - lastSnapshot->next = snapshot->next; - } else { - clientSnapshots[clientNum] = snapshot->next; - } - snapshotAllocator.Free( snapshot ); - } else { - lastSnapshot = snapshot; - } - } -} - -/* -================ -idGameLocal::ApplySnapshot -================ -*/ -bool idGameLocal::ApplySnapshot( int clientNum, int sequence ) { - snapshot_t *snapshot, *lastSnapshot, *nextSnapshot; - entityState_t *state; - - FreeSnapshotsOlderThanSequence( clientNum, sequence ); - - for ( lastSnapshot = NULL, snapshot = clientSnapshots[clientNum]; snapshot; snapshot = nextSnapshot ) { - nextSnapshot = snapshot->next; - if ( snapshot->sequence == sequence ) { - for ( state = snapshot->firstEntityState; state; state = state->next ) { - if ( clientEntityStates[clientNum][state->entityNumber] ) { - entityStateAllocator.Free( clientEntityStates[clientNum][state->entityNumber] ); - } - clientEntityStates[clientNum][state->entityNumber] = state; - } - memcpy( clientPVS[clientNum], snapshot->pvs, sizeof( snapshot->pvs ) ); - if ( lastSnapshot ) { - lastSnapshot->next = nextSnapshot; - } else { - clientSnapshots[clientNum] = nextSnapshot; - } - snapshotAllocator.Free( snapshot ); - return true; - } else { - lastSnapshot = snapshot; - } - } - - return false; -} - -/* -================ -idGameLocal::WriteGameStateToSnapshot -================ -*/ -void idGameLocal::WriteGameStateToSnapshot( idBitMsgDelta &msg ) const { - int i; - - for( i = 0; i < MAX_GLOBAL_SHADER_PARMS; i++ ) { - msg.WriteFloat( globalShaderParms[i] ); - } - - mpGame.WriteToSnapshot( msg ); -} - -/* -================ -idGameLocal::ReadGameStateFromSnapshot -================ -*/ -void idGameLocal::ReadGameStateFromSnapshot( const idBitMsgDelta &msg ) { - int i; - - for( i = 0; i < MAX_GLOBAL_SHADER_PARMS; i++ ) { - globalShaderParms[i] = msg.ReadFloat(); - } - - mpGame.ReadFromSnapshot( msg ); -} - -/* -================ -idGameLocal::ServerWriteSnapshot - - Write a snapshot of the current game state for the given client. -================ -*/ -void idGameLocal::ServerWriteSnapshot( int clientNum, int sequence, idBitMsg &msg, byte *clientInPVS, int numPVSClients ) { - int i, msgSize, msgWriteBit; - idPlayer *player, *spectated = NULL; - idEntity *ent; - pvsHandle_t pvsHandle; - idBitMsgDelta deltaMsg; - snapshot_t *snapshot; - entityState_t *base, *newBase; - int numSourceAreas, sourceAreas[ idEntity::MAX_PVS_AREAS ]; - - player = static_cast( entities[ clientNum ] ); - if ( !player ) { - return; - } - if ( player->spectating && player->spectator != clientNum && entities[ player->spectator ] ) { - spectated = static_cast< idPlayer * >( entities[ player->spectator ] ); - } else { - spectated = player; - } - - // free too old snapshots - FreeSnapshotsOlderThanSequence( clientNum, sequence - 64 ); - - // allocate new snapshot - snapshot = snapshotAllocator.Alloc(); - snapshot->sequence = sequence; - snapshot->firstEntityState = NULL; - snapshot->next = clientSnapshots[clientNum]; - clientSnapshots[clientNum] = snapshot; - memset( snapshot->pvs, 0, sizeof( snapshot->pvs ) ); - - // get PVS for this player - // don't use PVSAreas for networking - PVSAreas depends on animations (and md5 bounds), which are not synchronized - numSourceAreas = gameRenderWorld->BoundsInAreas( spectated->GetPlayerPhysics()->GetAbsBounds(), sourceAreas, idEntity::MAX_PVS_AREAS ); - pvsHandle = gameLocal.pvs.SetupCurrentPVS( sourceAreas, numSourceAreas, PVS_NORMAL ); - -#ifdef _D3XP - // Add portalSky areas to PVS - if ( portalSkyEnt.GetEntity() ) { - pvsHandle_t otherPVS, newPVS; - idEntity *skyEnt = portalSkyEnt.GetEntity(); - - otherPVS = gameLocal.pvs.SetupCurrentPVS( skyEnt->GetPVSAreas(), skyEnt->GetNumPVSAreas() ); - newPVS = gameLocal.pvs.MergeCurrentPVS( pvsHandle, otherPVS ); - pvs.FreeCurrentPVS( pvsHandle ); - pvs.FreeCurrentPVS( otherPVS ); - pvsHandle = newPVS; - } -#endif - -#if ASYNC_WRITE_TAGS - idRandom tagRandom; - tagRandom.SetSeed( random.RandomInt() ); - msg.WriteInt( tagRandom.GetSeed() ); -#endif - - // create the snapshot - for( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) { - - // if the entity is not in the player PVS - if ( !ent->PhysicsTeamInPVS( pvsHandle ) && ent->entityNumber != clientNum ) { - continue; - } - - // add the entity to the snapshot pvs - snapshot->pvs[ ent->entityNumber >> 5 ] |= 1 << ( ent->entityNumber & 31 ); - - // if that entity is not marked for network synchronization - if ( !ent->fl.networkSync ) { - continue; - } - - // save the write state to which we can revert when the entity didn't change at all - msg.SaveWriteState( msgSize, msgWriteBit ); - - // write the entity to the snapshot - msg.WriteBits( ent->entityNumber, GENTITYNUM_BITS ); - - base = clientEntityStates[clientNum][ent->entityNumber]; - if ( base ) { - base->state.BeginReading(); - } - newBase = entityStateAllocator.Alloc(); - newBase->entityNumber = ent->entityNumber; - newBase->state.Init( newBase->stateBuf, sizeof( newBase->stateBuf ) ); - newBase->state.BeginWriting(); - - deltaMsg.Init( base ? &base->state : NULL, &newBase->state, &msg ); - - deltaMsg.WriteBits( spawnIds[ ent->entityNumber ], 32 - GENTITYNUM_BITS ); - deltaMsg.WriteBits( ent->GetType()->typeNum, idClass::GetTypeNumBits() ); - deltaMsg.WriteBits( ServerRemapDecl( -1, DECL_ENTITYDEF, ent->entityDefNumber ), entityDefBits ); - - // write the class specific data to the snapshot - ent->WriteToSnapshot( deltaMsg ); - - if ( !deltaMsg.HasChanged() ) { - msg.RestoreWriteState( msgSize, msgWriteBit ); - entityStateAllocator.Free( newBase ); - } else { - newBase->next = snapshot->firstEntityState; - snapshot->firstEntityState = newBase; - -#if ASYNC_WRITE_TAGS - msg.WriteInt( tagRandom.RandomInt() ); -#endif - } - } - - msg.WriteBits( ENTITYNUM_NONE, GENTITYNUM_BITS ); - - // write the PVS to the snapshot -#if ASYNC_WRITE_PVS - for ( i = 0; i < idEntity::MAX_PVS_AREAS; i++ ) { - if ( i < numSourceAreas ) { - msg.WriteInt( sourceAreas[ i ] ); - } else { - msg.WriteInt( 0 ); - } - } - gameLocal.pvs.WritePVS( pvsHandle, msg ); -#endif - for ( i = 0; i < ENTITY_PVS_SIZE; i++ ) { - msg.WriteDeltaInt( clientPVS[clientNum][i], snapshot->pvs[i] ); - } - - // free the PVS - pvs.FreeCurrentPVS( pvsHandle ); - - // write the game and player state to the snapshot - base = clientEntityStates[clientNum][ENTITYNUM_NONE]; // ENTITYNUM_NONE is used for the game and player state - if ( base ) { - base->state.BeginReading(); - } - newBase = entityStateAllocator.Alloc(); - newBase->entityNumber = ENTITYNUM_NONE; - newBase->next = snapshot->firstEntityState; - snapshot->firstEntityState = newBase; - newBase->state.Init( newBase->stateBuf, sizeof( newBase->stateBuf ) ); - newBase->state.BeginWriting(); - deltaMsg.Init( base ? &base->state : NULL, &newBase->state, &msg ); - if ( player->spectating && player->spectator != player->entityNumber && gameLocal.entities[ player->spectator ] && gameLocal.entities[ player->spectator ]->IsType( idPlayer::Type ) ) { - static_cast< idPlayer * >( gameLocal.entities[ player->spectator ] )->WritePlayerStateToSnapshot( deltaMsg ); - } else { - player->WritePlayerStateToSnapshot( deltaMsg ); - } - WriteGameStateToSnapshot( deltaMsg ); - - // copy the client PVS string - memcpy( clientInPVS, snapshot->pvs, ( numPVSClients + 7 ) >> 3 ); - LittleRevBytes( clientInPVS, sizeof( int ), sizeof( clientInPVS ) / sizeof ( int ) ); -} - -/* -================ -idGameLocal::ServerApplySnapshot -================ -*/ -bool idGameLocal::ServerApplySnapshot( int clientNum, int sequence ) { - return ApplySnapshot( clientNum, sequence ); -} - -/* -================ -idGameLocal::NetworkEventWarning -================ -*/ -void idGameLocal::NetworkEventWarning( const entityNetEvent_t *event, const char *fmt, ... ) { - char buf[1024]; - int length = 0; - va_list argptr; - - int entityNum = event->spawnId & ( ( 1 << GENTITYNUM_BITS ) - 1 ); - int id = event->spawnId >> GENTITYNUM_BITS; - - length += idStr::snPrintf( buf+length, sizeof(buf)-1-length, "event %d for entity %d %d: ", event->event, entityNum, id ); - va_start( argptr, fmt ); - length = idStr::vsnPrintf( buf+length, sizeof(buf)-1-length, fmt, argptr ); - va_end( argptr ); - idStr::Append( buf, sizeof(buf), "\n" ); - - common->DWarning( buf ); -} - -/* -================ -idGameLocal::ServerProcessEntityNetworkEventQueue -================ -*/ -void idGameLocal::ServerProcessEntityNetworkEventQueue( void ) { - idEntity *ent; - entityNetEvent_t *event; - idBitMsg eventMsg; - - while ( eventQueue.Start() ) { - event = eventQueue.Start(); - - if ( event->time > time ) { - break; - } - - idEntityPtr< idEntity > entPtr; - - if( !entPtr.SetSpawnId( event->spawnId ) ) { - NetworkEventWarning( event, "Entity does not exist any longer, or has not been spawned yet." ); - } else { - ent = entPtr.GetEntity(); - assert( ent ); - - eventMsg.Init( event->paramsBuf, sizeof( event->paramsBuf ) ); - eventMsg.SetSize( event->paramsSize ); - eventMsg.BeginReading(); - if ( !ent->ServerReceiveEvent( event->event, event->time, eventMsg ) ) { - NetworkEventWarning( event, "unknown event" ); - } - } - - entityNetEvent_t* freedEvent id_attribute((unused)) = eventQueue.Dequeue(); - assert( freedEvent == event ); - eventQueue.Free( event ); - } -} - -/* -================ -idGameLocal::ServerSendChatMessage -================ -*/ -void idGameLocal::ServerSendChatMessage( int to, const char *name, const char *text ) { - idBitMsg outMsg; - byte msgBuf[ MAX_GAME_MESSAGE_SIZE ]; - - outMsg.Init( msgBuf, sizeof( msgBuf ) ); - outMsg.BeginWriting(); - outMsg.WriteByte( GAME_RELIABLE_MESSAGE_CHAT ); - outMsg.WriteString( name ); - outMsg.WriteString( text, -1, false ); - networkSystem->ServerSendReliableMessage( to, outMsg ); - - if ( to == -1 || to == localClientNum ) { - mpGame.AddChatLine( "%s^0: %s\n", name, text ); - } -} - -/* -================ -idGameLocal::ServerProcessReliableMessage -================ -*/ -void idGameLocal::ServerProcessReliableMessage( int clientNum, const idBitMsg &msg ) { - int id; - - id = msg.ReadByte(); - switch( id ) { - case GAME_RELIABLE_MESSAGE_CHAT: - case GAME_RELIABLE_MESSAGE_TCHAT: { - char name[128]; - char text[128]; - - msg.ReadString( name, sizeof( name ) ); - msg.ReadString( text, sizeof( text ) ); - - mpGame.ProcessChatMessage( clientNum, id == GAME_RELIABLE_MESSAGE_TCHAT, name, text, NULL ); - - break; - } - case GAME_RELIABLE_MESSAGE_VCHAT: { - int index = msg.ReadInt(); - bool team = msg.ReadBits( 1 ) != 0; - mpGame.ProcessVoiceChat( clientNum, team, index ); - break; - } - case GAME_RELIABLE_MESSAGE_KILL: { - mpGame.WantKilled( clientNum ); - break; - } - case GAME_RELIABLE_MESSAGE_DROPWEAPON: { - mpGame.DropWeapon( clientNum ); - break; - } - case GAME_RELIABLE_MESSAGE_CALLVOTE: { - mpGame.ServerCallVote( clientNum, msg ); - break; - } - case GAME_RELIABLE_MESSAGE_CASTVOTE: { - bool vote = ( msg.ReadByte() != 0 ); - mpGame.CastVote( clientNum, vote ); - break; - } -#if 0 - // uncomment this if you want to track when players are in a menu - case GAME_RELIABLE_MESSAGE_MENU: { - bool menuUp = ( msg.ReadBits( 1 ) != 0 ); - break; - } -#endif - case GAME_RELIABLE_MESSAGE_EVENT: { - entityNetEvent_t *event; - - // allocate new event - event = eventQueue.Alloc(); - eventQueue.Enqueue( event, idEventQueue::OUTOFORDER_DROP ); - - event->spawnId = msg.ReadBits( 32 ); - event->event = msg.ReadByte(); - event->time = msg.ReadInt(); - - event->paramsSize = msg.ReadBits( idMath::BitsForInteger( MAX_EVENT_PARAM_SIZE ) ); - if ( event->paramsSize ) { - if ( event->paramsSize > MAX_EVENT_PARAM_SIZE ) { - NetworkEventWarning( event, "invalid param size" ); - return; - } - msg.ReadByteAlign(); - msg.ReadData( event->paramsBuf, event->paramsSize ); - } - break; - } - default: { - Warning( "Unknown client->server reliable message: %d", id ); - break; - } - } -} - -/* -================ -idGameLocal::ClientShowSnapshot -================ -*/ -void idGameLocal::ClientShowSnapshot( int clientNum ) const { - int baseBits; - idEntity *ent; - idPlayer *player; - idMat3 viewAxis; - idBounds viewBounds; - entityState_t *base; - - if ( !net_clientShowSnapshot.GetInteger() ) { - return; - } - - player = static_cast( entities[clientNum] ); - if ( !player ) { - return; - } - - viewAxis = player->viewAngles.ToMat3(); - viewBounds = player->GetPhysics()->GetAbsBounds().Expand( net_clientShowSnapshotRadius.GetFloat() ); - - for( ent = snapshotEntities.Next(); ent != NULL; ent = ent->snapshotNode.Next() ) { - - if ( net_clientShowSnapshot.GetInteger() == 1 && ent->snapshotBits == 0 ) { - continue; - } - - const idBounds &entBounds = ent->GetPhysics()->GetAbsBounds(); - - if ( !entBounds.IntersectsBounds( viewBounds ) ) { - continue; - } - - base = clientEntityStates[clientNum][ent->entityNumber]; - if ( base ) { - baseBits = base->state.GetNumBitsWritten(); - } else { - baseBits = 0; - } - - if ( net_clientShowSnapshot.GetInteger() == 2 && baseBits == 0 ) { - continue; - } - - gameRenderWorld->DebugBounds( colorGreen, entBounds ); - gameRenderWorld->DrawText( va( "%d: %s (%d,%d bytes of %d,%d)\n", ent->entityNumber, - ent->name.c_str(), ent->snapshotBits >> 3, ent->snapshotBits & 7, baseBits >> 3, baseBits & 7 ), - entBounds.GetCenter(), 0.1f, colorWhite, viewAxis, 1 ); - } -} - -/* -================ -idGameLocal::UpdateLagometer -================ -*/ -void idGameLocal::UpdateLagometer( int aheadOfServer, int dupeUsercmds ) { - int i, j, ahead; - for ( i = 0; i < LAGO_HEIGHT; i++ ) { - memmove( (byte *)lagometer + LAGO_WIDTH * 4 * i, (byte *)lagometer + LAGO_WIDTH * 4 * i + 4, ( LAGO_WIDTH - 1 ) * 4 ); - } - j = LAGO_WIDTH - 1; - for ( i = 0; i < LAGO_HEIGHT; i++ ) { - lagometer[i][j][0] = lagometer[i][j][1] = lagometer[i][j][2] = lagometer[i][j][3] = 0; - } - ahead = idMath::Rint( (float)aheadOfServer / 16.0f ); - if ( ahead >= 0 ) { - for ( i = 2 * Max( 0, 5 - ahead ); i < 2 * 5; i++ ) { - lagometer[i][j][1] = 255; - lagometer[i][j][3] = 255; - } - } else { - for ( i = 2 * 5; i < 2 * ( 5 + Min( 10, -ahead ) ); i++ ) { - lagometer[i][j][0] = 255; - lagometer[i][j][1] = 255; - lagometer[i][j][3] = 255; - } - } - for ( i = LAGO_HEIGHT - 2 * Min( 6, dupeUsercmds ); i < LAGO_HEIGHT; i++ ) { - lagometer[i][j][0] = 255; - if ( dupeUsercmds <= 2 ) { - lagometer[i][j][1] = 255; - } - lagometer[i][j][3] = 255; - } -} - -/* -================ -idGameLocal::ClientReadSnapshot -================ -*/ -void idGameLocal::ClientReadSnapshot( int clientNum, int sequence, const int gameFrame, const int gameTime, const int dupeUsercmds, const int aheadOfServer, const idBitMsg &msg ) { - int i, typeNum, entityDefNumber, numBitsRead; - idTypeInfo *typeInfo; - idEntity *ent; - idPlayer *player, *spectated; - pvsHandle_t pvsHandle; - idDict args; - const char *classname; - idBitMsgDelta deltaMsg; - snapshot_t *snapshot; - entityState_t *base, *newBase; - int spawnId; - int numSourceAreas, sourceAreas[ idEntity::MAX_PVS_AREAS ]; - idWeapon *weap; - - if ( net_clientLagOMeter.GetBool() && renderSystem ) { - UpdateLagometer( aheadOfServer, dupeUsercmds ); - if ( !renderSystem->UploadImage( LAGO_IMAGE, (byte *)lagometer, LAGO_IMG_WIDTH, LAGO_IMG_HEIGHT ) ) { - common->Printf( "lagometer: UploadImage failed. turning off net_clientLagOMeter\n" ); - net_clientLagOMeter.SetBool( false ); - } - } - - InitLocalClient( clientNum ); - - // clear any debug lines from a previous frame - gameRenderWorld->DebugClearLines( time ); - - // clear any debug polygons from a previous frame - gameRenderWorld->DebugClearPolygons( time ); - - // update the game time - framenum = gameFrame; - time = gameTime; - previousTime = time - msec; - - // so that StartSound/StopSound doesn't risk skipping - isNewFrame = true; - - // clear the snapshot entity list - snapshotEntities.Clear(); - - // allocate new snapshot - snapshot = snapshotAllocator.Alloc(); - snapshot->sequence = sequence; - snapshot->firstEntityState = NULL; - snapshot->next = clientSnapshots[clientNum]; - clientSnapshots[clientNum] = snapshot; - -#if ASYNC_WRITE_TAGS - idRandom tagRandom; - tagRandom.SetSeed( msg.ReadInt() ); -#endif - - // read all entities from the snapshot - for ( i = msg.ReadBits( GENTITYNUM_BITS ); i != ENTITYNUM_NONE; i = msg.ReadBits( GENTITYNUM_BITS ) ) { - - base = clientEntityStates[clientNum][i]; - if ( base ) { - base->state.BeginReading(); - } - newBase = entityStateAllocator.Alloc(); - newBase->entityNumber = i; - newBase->next = snapshot->firstEntityState; - snapshot->firstEntityState = newBase; - newBase->state.Init( newBase->stateBuf, sizeof( newBase->stateBuf ) ); - newBase->state.BeginWriting(); - - numBitsRead = msg.GetNumBitsRead(); - - deltaMsg.Init( base ? &base->state : NULL, &newBase->state, &msg ); - - spawnId = deltaMsg.ReadBits( 32 - GENTITYNUM_BITS ); - typeNum = deltaMsg.ReadBits( idClass::GetTypeNumBits() ); - entityDefNumber = ClientRemapDecl( DECL_ENTITYDEF, deltaMsg.ReadBits( entityDefBits ) ); - - typeInfo = idClass::GetType( typeNum ); - if ( !typeInfo ) { - Error( "Unknown type number %d for entity %d with class number %d", typeNum, i, entityDefNumber ); - } - - ent = entities[i]; - - // if there is no entity or an entity of the wrong type - if ( !ent || ent->GetType()->typeNum != typeNum || ent->entityDefNumber != entityDefNumber || spawnId != spawnIds[ i ] ) { - - if ( i < MAX_CLIENTS && ent ) { - // SPAWN_PLAYER should be taking care of spawning the entity with the right spawnId - common->Warning( "ClientReadSnapshot: recycling client entity %d\n", i ); - } - - delete ent; - - spawnCount = spawnId; - - args.Clear(); - args.SetInt( "spawn_entnum", i ); - args.Set( "name", va( "entity%d", i ) ); - - if ( entityDefNumber >= 0 ) { - if ( entityDefNumber >= declManager->GetNumDecls( DECL_ENTITYDEF ) ) { - Error( "server has %d entityDefs instead of %d", entityDefNumber, declManager->GetNumDecls( DECL_ENTITYDEF ) ); - } - classname = declManager->DeclByIndex( DECL_ENTITYDEF, entityDefNumber, false )->GetName(); - args.Set( "classname", classname ); - if ( !SpawnEntityDef( args, &ent ) || !entities[i] || entities[i]->GetType()->typeNum != typeNum ) { - Error( "Failed to spawn entity with classname '%s' of type '%s'", classname, typeInfo->classname ); - } - } else { - ent = SpawnEntityType( *typeInfo, &args, true ); - if ( !entities[i] || entities[i]->GetType()->typeNum != typeNum ) { - Error( "Failed to spawn entity of type '%s'", typeInfo->classname ); - } - } - if ( i < MAX_CLIENTS && i >= numClients ) { - numClients = i + 1; - } - } - - // add the entity to the snapshot list - ent->snapshotNode.AddToEnd( snapshotEntities ); - ent->snapshotSequence = sequence; - - // read the class specific data from the snapshot - ent->ReadFromSnapshot( deltaMsg ); - - ent->snapshotBits = msg.GetNumBitsRead() - numBitsRead; - -#if ASYNC_WRITE_TAGS - if ( msg.ReadInt() != tagRandom.RandomInt() ) { - cmdSystem->BufferCommandText( CMD_EXEC_NOW, "writeGameState" ); - if ( entityDefNumber >= 0 && entityDefNumber < declManager->GetNumDecls( DECL_ENTITYDEF ) ) { - classname = declManager->DeclByIndex( DECL_ENTITYDEF, entityDefNumber, false )->GetName(); - Error( "write to and read from snapshot out of sync for classname '%s' of type '%s'", classname, typeInfo->classname ); - } else { - Error( "write to and read from snapshot out of sync for type '%s'", typeInfo->classname ); - } - } -#endif - } - - player = static_cast( entities[clientNum] ); - if ( !player ) { - return; - } - - // if prediction is off, enable local client smoothing - player->SetSelfSmooth( dupeUsercmds > 2 ); - - if ( player->spectating && player->spectator != clientNum && entities[ player->spectator ] ) { - spectated = static_cast< idPlayer * >( entities[ player->spectator ] ); - } else { - spectated = player; - } - - // get PVS for this player - // don't use PVSAreas for networking - PVSAreas depends on animations (and md5 bounds), which are not synchronized - numSourceAreas = gameRenderWorld->BoundsInAreas( spectated->GetPlayerPhysics()->GetAbsBounds(), sourceAreas, idEntity::MAX_PVS_AREAS ); - pvsHandle = gameLocal.pvs.SetupCurrentPVS( sourceAreas, numSourceAreas, PVS_NORMAL ); - -#ifdef _D3XP - // Add portalSky areas to PVS - if ( portalSkyEnt.GetEntity() ) { - pvsHandle_t otherPVS, newPVS; - idEntity *skyEnt = portalSkyEnt.GetEntity(); - - otherPVS = gameLocal.pvs.SetupCurrentPVS( skyEnt->GetPVSAreas(), skyEnt->GetNumPVSAreas() ); - newPVS = gameLocal.pvs.MergeCurrentPVS( pvsHandle, otherPVS ); - pvs.FreeCurrentPVS( pvsHandle ); - pvs.FreeCurrentPVS( otherPVS ); - pvsHandle = newPVS; - } -#endif - - // read the PVS from the snapshot -#if ASYNC_WRITE_PVS - int serverPVS[idEntity::MAX_PVS_AREAS]; - i = numSourceAreas; - while ( i < idEntity::MAX_PVS_AREAS ) { - sourceAreas[ i++ ] = 0; - } - for ( i = 0; i < idEntity::MAX_PVS_AREAS; i++ ) { - serverPVS[ i ] = msg.ReadInt(); - } - if ( memcmp( sourceAreas, serverPVS, idEntity::MAX_PVS_AREAS * sizeof( int ) ) ) { - common->Warning( "client PVS areas != server PVS areas, sequence 0x%x", sequence ); - for ( i = 0; i < idEntity::MAX_PVS_AREAS; i++ ) { - common->DPrintf( "%3d ", sourceAreas[ i ] ); - } - common->DPrintf( "\n" ); - for ( i = 0; i < idEntity::MAX_PVS_AREAS; i++ ) { - common->DPrintf( "%3d ", serverPVS[ i ] ); - } - common->DPrintf( "\n" ); - } - gameLocal.pvs.ReadPVS( pvsHandle, msg ); -#endif - for ( i = 0; i < ENTITY_PVS_SIZE; i++ ) { - snapshot->pvs[i] = msg.ReadDeltaInt( clientPVS[clientNum][i] ); - } - - // add entities in the PVS that haven't changed since the last applied snapshot - for( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) { - - // if the entity is already in the snapshot - if ( ent->snapshotSequence == sequence ) { - continue; - } - - // if the entity is not in the snapshot PVS - if ( !( snapshot->pvs[ent->entityNumber >> 5] & ( 1 << ( ent->entityNumber & 31 ) ) ) ) { - if ( ent->PhysicsTeamInPVS( pvsHandle ) ) { - if ( ent->entityNumber >= MAX_CLIENTS && ent->entityNumber < mapSpawnCount && !ent->spawnArgs.GetBool("net_dynamic", "0")) { //_D3XP - // server says it's not in PVS, client says it's in PVS - // if that happens on map entities, most likely something is wrong - // I can see that moving pieces along several PVS could be a legit situation though - // this is a band aid, which means something is not done right elsewhere - common->DWarning( "client thinks map entity 0x%x (%s) is stale, sequence 0x%x", ent->entityNumber, ent->name.c_str(), sequence ); - } else { - ent->FreeModelDef(); -#ifdef CTF - // possible fix for left over lights on CTF flag - ent->FreeLightDef(); -#endif - ent->UpdateVisuals(); - ent->GetPhysics()->UnlinkClip(); - } - } - continue; - } - - // add the entity to the snapshot list - ent->snapshotNode.AddToEnd( snapshotEntities ); - ent->snapshotSequence = sequence; - ent->snapshotBits = 0; - - base = clientEntityStates[clientNum][ent->entityNumber]; - if ( !base ) { - // entity has probably fl.networkSync set to false - continue; - } - - base->state.BeginReading(); - - deltaMsg.Init( &base->state, NULL, (const idBitMsg *)NULL ); - - spawnId = deltaMsg.ReadBits( 32 - GENTITYNUM_BITS ); - typeNum = deltaMsg.ReadBits( idClass::GetTypeNumBits() ); - entityDefNumber = deltaMsg.ReadBits( entityDefBits ); - - typeInfo = idClass::GetType( typeNum ); - - // if the entity is not the right type - if ( !typeInfo || ent->GetType()->typeNum != typeNum || ent->entityDefNumber != entityDefNumber ) { - // should never happen - it does though. with != entityDefNumber only? - common->DWarning( "entity '%s' is not the right type %p 0x%d 0x%x 0x%x 0x%x", ent->GetName(), typeInfo, ent->GetType()->typeNum, typeNum, ent->entityDefNumber, entityDefNumber ); - continue; - } - - // read the class specific data from the base state - ent->ReadFromSnapshot( deltaMsg ); - } - - // free the PVS - pvs.FreeCurrentPVS( pvsHandle ); - - // read the game and player state from the snapshot - base = clientEntityStates[clientNum][ENTITYNUM_NONE]; // ENTITYNUM_NONE is used for the game and player state - if ( base ) { - base->state.BeginReading(); - } - newBase = entityStateAllocator.Alloc(); - newBase->entityNumber = ENTITYNUM_NONE; - newBase->next = snapshot->firstEntityState; - snapshot->firstEntityState = newBase; - newBase->state.Init( newBase->stateBuf, sizeof( newBase->stateBuf ) ); - newBase->state.BeginWriting(); - deltaMsg.Init( base ? &base->state : NULL, &newBase->state, &msg ); - if ( player->spectating && player->spectator != player->entityNumber && gameLocal.entities[ player->spectator ] && gameLocal.entities[ player->spectator ]->IsType( idPlayer::Type ) ) { - static_cast< idPlayer * >( gameLocal.entities[ player->spectator ] )->ReadPlayerStateFromSnapshot( deltaMsg ); - weap = static_cast< idPlayer * >( gameLocal.entities[ player->spectator ] )->weapon.GetEntity(); - if ( weap && ( weap->GetRenderEntity()->bounds[0] == weap->GetRenderEntity()->bounds[1] ) ) { - // update the weapon's viewmodel bounds so that the model doesn't flicker in the spectator's view - weap->GetAnimator()->GetBounds( gameLocal.time, weap->GetRenderEntity()->bounds ); - weap->UpdateVisuals(); - } - } else { - player->ReadPlayerStateFromSnapshot( deltaMsg ); - } - ReadGameStateFromSnapshot( deltaMsg ); - - // visualize the snapshot - ClientShowSnapshot( clientNum ); - - // process entity events - ClientProcessEntityNetworkEventQueue(); -} - -/* -================ -idGameLocal::ClientApplySnapshot -================ -*/ -bool idGameLocal::ClientApplySnapshot( int clientNum, int sequence ) { - return ApplySnapshot( clientNum, sequence ); -} - -/* -================ -idGameLocal::ClientProcessEntityNetworkEventQueue -================ -*/ -void idGameLocal::ClientProcessEntityNetworkEventQueue( void ) { - idEntity *ent; - entityNetEvent_t *event; - idBitMsg eventMsg; - - while( eventQueue.Start() ) { - event = eventQueue.Start(); - - // only process forward, in order - if ( event->time > time ) { - break; - } - - idEntityPtr< idEntity > entPtr; - - if( !entPtr.SetSpawnId( event->spawnId ) ) { - if( !gameLocal.entities[ event->spawnId & ( ( 1 << GENTITYNUM_BITS ) - 1 ) ] ) { - // if new entity exists in this position, silently ignore - NetworkEventWarning( event, "Entity does not exist any longer, or has not been spawned yet." ); - } - } else { - ent = entPtr.GetEntity(); - assert( ent ); - - eventMsg.Init( event->paramsBuf, sizeof( event->paramsBuf ) ); - eventMsg.SetSize( event->paramsSize ); - eventMsg.BeginReading(); - if ( !ent->ClientReceiveEvent( event->event, event->time, eventMsg ) ) { - NetworkEventWarning( event, "unknown event" ); - } - } - - entityNetEvent_t* freedEvent id_attribute((unused)) = eventQueue.Dequeue(); - assert( freedEvent == event ); - eventQueue.Free( event ); - } -} - -/* -================ -idGameLocal::ClientProcessReliableMessage -================ -*/ -void idGameLocal::ClientProcessReliableMessage( int clientNum, const idBitMsg &msg ) { - int id, line; - idPlayer *p; - idDict backupSI; - - InitLocalClient( clientNum ); - - id = msg.ReadByte(); - switch( id ) { - case GAME_RELIABLE_MESSAGE_INIT_DECL_REMAP: { - InitClientDeclRemap( clientNum ); - break; - } - case GAME_RELIABLE_MESSAGE_REMAP_DECL: { - int type, index; - char name[MAX_STRING_CHARS]; - - type = msg.ReadByte(); - index = msg.ReadInt(); - msg.ReadString( name, sizeof( name ) ); - - const idDecl *decl = declManager->FindType( (declType_t)type, name, false ); - if ( decl != NULL ) { - if ( index >= clientDeclRemap[clientNum][type].Num() ) { - clientDeclRemap[clientNum][type].AssureSize( index + 1, -1 ); - } - clientDeclRemap[clientNum][type][index] = decl->Index(); - } - break; - } - case GAME_RELIABLE_MESSAGE_SPAWN_PLAYER: { - int client = msg.ReadByte(); - int spawnId = msg.ReadInt(); - if ( !entities[ client ] ) { - SpawnPlayer( client ); - entities[ client ]->FreeModelDef(); - } - // fix up the spawnId to match what the server says - // otherwise there is going to be a bogus delete/new of the client entity in the first ClientReadFromSnapshot - spawnIds[ client ] = spawnId; - break; - } - case GAME_RELIABLE_MESSAGE_DELETE_ENT: { - int spawnId = msg.ReadBits( 32 ); - idEntityPtr< idEntity > entPtr; - if( !entPtr.SetSpawnId( spawnId ) ) { - break; - } - delete entPtr.GetEntity(); - break; - } - case GAME_RELIABLE_MESSAGE_CHAT: - case GAME_RELIABLE_MESSAGE_TCHAT: { // (client should never get a TCHAT though) - char name[128]; - char text[128]; - msg.ReadString( name, sizeof( name ) ); - msg.ReadString( text, sizeof( text ) ); - mpGame.AddChatLine( "%s^0: %s\n", name, text ); - break; - } - case GAME_RELIABLE_MESSAGE_SOUND_EVENT: { - snd_evt_t snd_evt = (snd_evt_t)msg.ReadByte(); - mpGame.PlayGlobalSound( -1, snd_evt ); - break; - } - case GAME_RELIABLE_MESSAGE_SOUND_INDEX: { - int index = gameLocal.ClientRemapDecl( DECL_SOUND, msg.ReadInt() ); - if ( index >= 0 && index < declManager->GetNumDecls( DECL_SOUND ) ) { - const idSoundShader *shader = declManager->SoundByIndex( index ); - mpGame.PlayGlobalSound( -1, SND_COUNT, shader->GetName() ); - } - break; - } - case GAME_RELIABLE_MESSAGE_DB: { - idMultiplayerGame::msg_evt_t msg_evt = (idMultiplayerGame::msg_evt_t)msg.ReadByte(); - int parm1, parm2; - parm1 = msg.ReadByte( ); - parm2 = msg.ReadByte( ); - mpGame.PrintMessageEvent( -1, msg_evt, parm1, parm2 ); - break; - } - case GAME_RELIABLE_MESSAGE_EVENT: { - entityNetEvent_t *event; - - // allocate new event - event = eventQueue.Alloc(); - eventQueue.Enqueue( event, idEventQueue::OUTOFORDER_IGNORE ); - - event->spawnId = msg.ReadBits( 32 ); - event->event = msg.ReadByte(); - event->time = msg.ReadInt(); - - event->paramsSize = msg.ReadBits( idMath::BitsForInteger( MAX_EVENT_PARAM_SIZE ) ); - if ( event->paramsSize ) { - if ( event->paramsSize > MAX_EVENT_PARAM_SIZE ) { - NetworkEventWarning( event, "invalid param size" ); - return; - } - msg.ReadByteAlign(); - msg.ReadData( event->paramsBuf, event->paramsSize ); - } - break; - } - case GAME_RELIABLE_MESSAGE_SERVERINFO: { - idDict info; - msg.ReadDeltaDict( info, NULL ); - gameLocal.SetServerInfo( info ); - break; - } - case GAME_RELIABLE_MESSAGE_RESTART: { -#ifdef _D3XP - int newServerInfo = msg.ReadBits(1); - if(newServerInfo) { - idDict info; - msg.ReadDeltaDict( info, NULL ); - gameLocal.SetServerInfo( info ); - } -#endif - MapRestart(); - break; - } - case GAME_RELIABLE_MESSAGE_TOURNEYLINE: { - line = msg.ReadByte( ); - p = static_cast< idPlayer * >( entities[ clientNum ] ); - if ( !p ) { - break; - } - p->tourneyLine = line; - break; - } - case GAME_RELIABLE_MESSAGE_STARTVOTE: { - char voteString[ MAX_STRING_CHARS ]; - int clientNum = msg.ReadByte( ); - msg.ReadString( voteString, sizeof( voteString ) ); - mpGame.ClientStartVote( clientNum, voteString ); - break; - } - case GAME_RELIABLE_MESSAGE_UPDATEVOTE: { - int result = msg.ReadByte( ); - int yesCount = msg.ReadByte( ); - int noCount = msg.ReadByte( ); - mpGame.ClientUpdateVote( (idMultiplayerGame::vote_result_t)result, yesCount, noCount ); - break; - } - case GAME_RELIABLE_MESSAGE_PORTALSTATES: { - int numPortals = msg.ReadInt(); - assert( numPortals == gameRenderWorld->NumPortals() ); - for ( int i = 0; i < numPortals; i++ ) { - gameRenderWorld->SetPortalState( (qhandle_t) (i+1), msg.ReadBits( NUM_RENDER_PORTAL_BITS ) ); - } - break; - } - case GAME_RELIABLE_MESSAGE_PORTAL: { - qhandle_t portal = msg.ReadInt(); - int blockingBits = msg.ReadBits( NUM_RENDER_PORTAL_BITS ); - assert( portal > 0 && portal <= gameRenderWorld->NumPortals() ); - gameRenderWorld->SetPortalState( portal, blockingBits ); - break; - } - case GAME_RELIABLE_MESSAGE_STARTSTATE: { - mpGame.ClientReadStartState( msg ); - break; - } - case GAME_RELIABLE_MESSAGE_WARMUPTIME: { - mpGame.ClientReadWarmupTime( msg ); - break; - } - default: { - Error( "Unknown server->client reliable message: %d", id ); - break; - } - } -} - -/* -================ -idGameLocal::ClientPrediction -================ -*/ -gameReturn_t idGameLocal::ClientPrediction( int clientNum, const usercmd_t *clientCmds, bool lastPredictFrame ) { - idEntity *ent; - idPlayer *player; - gameReturn_t ret; - - ret.sessionCommand[ 0 ] = '\0'; - - player = static_cast( entities[clientNum] ); - if ( !player ) { - return ret; - } - - // check for local client lag - if ( networkSystem->ClientGetTimeSinceLastPacket() >= net_clientMaxPrediction.GetInteger() ) { - player->isLagged = true; - } else { - player->isLagged = false; - } - - InitLocalClient( clientNum ); - - // update the game time - framenum++; - previousTime = time; - time += msec; - - // update the real client time and the new frame flag - if ( time > realClientTime ) { - realClientTime = time; - isNewFrame = true; - } else { - isNewFrame = false; - } - -#ifdef _D3XP - slow.Set( time, previousTime, msec, framenum, realClientTime ); - fast.Set( time, previousTime, msec, framenum, realClientTime ); -#endif - - // set the user commands for this frame - memcpy( usercmds, clientCmds, numClients * sizeof( usercmds[ 0 ] ) ); - - // run prediction on all entities from the last snapshot - for( ent = snapshotEntities.Next(); ent != NULL; ent = ent->snapshotNode.Next() ) { - ent->thinkFlags |= TH_PHYSICS; - ent->ClientPredictionThink(); - } - - // service any pending events - idEvent::ServiceEvents(); - - // show any debug info for this frame - if ( isNewFrame ) { - RunDebugInfo(); - D_DrawDebugLines(); - } - - if ( sessionCommand.Length() ) { - idStr::Copynz( ret.sessionCommand, sessionCommand, sizeof( ret.sessionCommand ) ); - } - return ret; -} - -/* -=============== -idGameLocal::Tokenize -=============== -*/ -void idGameLocal::Tokenize( idStrList &out, const char *in ) { - char buf[ MAX_STRING_CHARS ]; - char *token, *next; - - idStr::Copynz( buf, in, MAX_STRING_CHARS ); - token = buf; - next = strchr( token, ';' ); - while ( token ) { - if ( next ) { - *next = '\0'; - } - idStr::ToLower( token ); - out.Append( token ); - if ( next ) { - token = next + 1; - next = strchr( token, ';' ); - } else { - token = NULL; - } - } -} - -/* -=============== -idGameLocal::DownloadRequest -=============== -*/ -bool idGameLocal::DownloadRequest( const char *IP, const char *guid, const char *paks, char urls[ MAX_STRING_CHARS ] ) { - if ( !cvarSystem->GetCVarInteger( "net_serverDownload" ) ) { - return false; - } - if ( cvarSystem->GetCVarInteger( "net_serverDownload" ) == 1 ) { - // 1: single URL redirect - if ( !strlen( cvarSystem->GetCVarString( "si_serverURL" ) ) ) { - common->Warning( "si_serverURL not set" ); - return false; - } - idStr::snPrintf( urls, MAX_STRING_CHARS, "1;%s", cvarSystem->GetCVarString( "si_serverURL" ) ); - return true; - } - - // 2: table of pak URLs - // first token is the game pak if request, empty if not requested by the client - // there may be empty tokens for paks the server couldn't pinpoint - the order matters - idStr reply = "2;"; - idStrList dlTable, pakList; - int i, j; - - Tokenize( dlTable, cvarSystem->GetCVarString( "net_serverDlTable" ) ); - Tokenize( pakList, paks ); - - for ( i = 0; i < pakList.Num(); i++ ) { - if ( i > 0 ) { - reply += ";"; - } - if ( pakList[ i ][ 0 ] == '\0' ) { - if ( i == 0 ) { - // pak 0 will always miss when client doesn't ask for game bin - common->DPrintf( "no game pak request\n" ); - } else { - common->DPrintf( "no pak %d\n", i ); - } - continue; - } - for ( j = 0; j < dlTable.Num(); j++ ) { - if ( !fileSystem->FilenameCompare( pakList[ i ], dlTable[ j ] ) ) { - break; - } - } - if ( j == dlTable.Num() ) { - common->Printf( "download for %s: pak not matched: %s\n", IP, pakList[ i ].c_str() ); - } else { - idStr url = cvarSystem->GetCVarString( "net_serverDlBaseURL" ); - url.AppendPath( dlTable[ j ] ); - reply += url; - common->DPrintf( "download for %s: %s\n", IP, url.c_str() ); - } - } - - idStr::Copynz( urls, reply, MAX_STRING_CHARS ); - return true; -} - -/* -=============== -idEventQueue::Alloc -=============== -*/ -entityNetEvent_t* idEventQueue::Alloc() { - entityNetEvent_t* event = eventAllocator.Alloc(); - event->prev = NULL; - event->next = NULL; - return event; -} - -/* -=============== -idEventQueue::Free -=============== -*/ -void idEventQueue::Free( entityNetEvent_t *event ) { - // should only be called on an unlinked event! - assert( !event->next && !event->prev ); - eventAllocator.Free( event ); -} - -/* -=============== -idEventQueue::Shutdown -=============== -*/ -void idEventQueue::Shutdown() { - eventAllocator.Shutdown(); - this->Init(); -} - -/* -=============== -idEventQueue::Init -=============== -*/ -void idEventQueue::Init( void ) { - start = NULL; - end = NULL; -} - -/* -=============== -idEventQueue::Dequeue -=============== -*/ -entityNetEvent_t* idEventQueue::Dequeue( void ) { - entityNetEvent_t* event = start; - if ( !event ) { - return NULL; - } - - start = start->next; - - if ( !start ) { - end = NULL; - } else { - start->prev = NULL; - } - - event->next = NULL; - event->prev = NULL; - - return event; -} - -/* -=============== -idEventQueue::RemoveLast -=============== -*/ -entityNetEvent_t* idEventQueue::RemoveLast( void ) { - entityNetEvent_t *event = end; - if ( !event ) { - return NULL; - } - - end = event->prev; - - if ( !end ) { - start = NULL; - } else { - end->next = NULL; - } - - event->next = NULL; - event->prev = NULL; - - return event; -} - -/* -=============== -idEventQueue::Enqueue -=============== -*/ -void idEventQueue::Enqueue( entityNetEvent_t *event, outOfOrderBehaviour_t behaviour ) { - if ( behaviour == OUTOFORDER_DROP ) { - // go backwards through the queue and determine if there are - // any out-of-order events - while ( end && end->time > event->time ) { - entityNetEvent_t *outOfOrder = RemoveLast(); - common->DPrintf( "WARNING: new event with id %d ( time %d ) caused removal of event with id %d ( time %d ), game time = %d.\n", event->event, event->time, outOfOrder->event, outOfOrder->time, gameLocal.time ); - Free( outOfOrder ); - } - } else if ( behaviour == OUTOFORDER_SORT && end ) { - // NOT TESTED -- sorting out of order packets hasn't been - // tested yet... wasn't strictly necessary for - // the patch fix. - entityNetEvent_t *cur = end; - // iterate until we find a time < the new event's - while ( cur && cur->time > event->time ) { - cur = cur->prev; - } - if ( !cur ) { - // add to start - event->next = start; - event->prev = NULL; - start = event; - } else { - // insert - event->prev = cur; - event->next = cur->next; - cur->next = event; - } - return; - } - - // add the new event - event->next = NULL; - event->prev = NULL; - - if ( end ) { - end->next = event; - event->prev = end; - } else { - start = event; - } - end = event; -} diff --git a/d3xp/IK.cpp b/d3xp/IK.cpp deleted file mode 100644 index 6bd54d6b..00000000 --- a/d3xp/IK.cpp +++ /dev/null @@ -1,1130 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "idlib/geometry/JointTransform.h" - -#include "gamesys/SysCvar.h" -#include "Mover.h" - -#include "IK.h" - -/* -=============================================================================== - - idIK - -=============================================================================== -*/ - -/* -================ -idIK::idIK -================ -*/ -idIK::idIK( void ) { - ik_activate = false; - initialized = false; - self = NULL; - animator = NULL; - modifiedAnim = 0; - modelOffset.Zero(); -} - -/* -================ -idIK::~idIK -================ -*/ -idIK::~idIK( void ) { -} - -/* -================ -idIK::Save -================ -*/ -void idIK::Save( idSaveGame *savefile ) const { - savefile->WriteBool( initialized ); - savefile->WriteBool( ik_activate ); - savefile->WriteObject( self ); - savefile->WriteString( animator != NULL && animator->GetAnim( modifiedAnim ) ? animator->GetAnim( modifiedAnim )->Name() : "" ); - savefile->WriteVec3( modelOffset ); -} - -/* -================ -idIK::Restore -================ -*/ -void idIK::Restore( idRestoreGame *savefile ) { - idStr anim; - - savefile->ReadBool( initialized ); - savefile->ReadBool( ik_activate ); - savefile->ReadObject( reinterpret_cast( self ) ); - savefile->ReadString( anim ); - savefile->ReadVec3( modelOffset ); - - if ( self ) { - animator = self->GetAnimator(); - if ( animator == NULL || animator->ModelDef() == NULL ) { - gameLocal.Warning( "idIK::Restore: IK for entity '%s' at (%s) has no model set.", - self->name.c_str(), self->GetPhysics()->GetOrigin().ToString(0) ); - } - modifiedAnim = animator->GetAnim( anim ); - if ( modifiedAnim == 0 ) { - gameLocal.Warning( "idIK::Restore: IK for entity '%s' at (%s) has no modified animation.", - self->name.c_str(), self->GetPhysics()->GetOrigin().ToString(0) ); - } - } else { - animator = NULL; - modifiedAnim = 0; - } -} - -/* -================ -idIK::IsInitialized -================ -*/ -bool idIK::IsInitialized( void ) const { - return initialized && ik_enable.GetBool(); -} - -/* -================ -idIK::Init -================ -*/ -bool idIK::Init( idEntity *self, const char *anim, const idVec3 &modelOffset ) { - idRenderModel *model; - - if ( self == NULL ) { - return false; - } - - this->self = self; - - animator = self->GetAnimator(); - if ( animator == NULL || animator->ModelDef() == NULL ) { - gameLocal.Warning( "idIK::Init: IK for entity '%s' at (%s) has no model set.", - self->name.c_str(), self->GetPhysics()->GetOrigin().ToString(0) ); - return false; - } - if ( animator->ModelDef()->ModelHandle() == NULL ) { - gameLocal.Warning( "idIK::Init: IK for entity '%s' at (%s) uses default model.", - self->name.c_str(), self->GetPhysics()->GetOrigin().ToString(0) ); - return false; - } - model = animator->ModelHandle(); - if ( model == NULL ) { - gameLocal.Warning( "idIK::Init: IK for entity '%s' at (%s) has no model set.", - self->name.c_str(), self->GetPhysics()->GetOrigin().ToString(0) ); - return false; - } - modifiedAnim = animator->GetAnim( anim ); - if ( modifiedAnim == 0 ) { - gameLocal.Warning( "idIK::Init: IK for entity '%s' at (%s) has no modified animation.", - self->name.c_str(), self->GetPhysics()->GetOrigin().ToString(0) ); - return false; - } - - this->modelOffset = modelOffset; - - return true; -} - -/* -================ -idIK::Evaluate -================ -*/ -void idIK::Evaluate( void ) { -} - -/* -================ -idIK::ClearJointMods -================ -*/ -void idIK::ClearJointMods( void ) { - ik_activate = false; -} - -/* -================ -idIK::SolveTwoBones -================ -*/ -bool idIK::SolveTwoBones( const idVec3 &startPos, const idVec3 &endPos, const idVec3 &dir, float len0, float len1, idVec3 &jointPos ) { - float length, lengthSqr, lengthInv, x, y; - idVec3 vec0, vec1; - - vec0 = endPos - startPos; - lengthSqr = vec0.LengthSqr(); - lengthInv = idMath::InvSqrt( lengthSqr ); - length = lengthInv * lengthSqr; - - // if the start and end position are too far out or too close to each other - if ( length > len0 + len1 || length < idMath::Fabs( len0 - len1 ) ) { - jointPos = startPos + 0.5f * vec0; - return false; - } - - vec0 *= lengthInv; - vec1 = dir - vec0 * dir * vec0; - vec1.Normalize(); - - x = ( length * length + len0 * len0 - len1 * len1 ) * ( 0.5f * lengthInv ); - y = idMath::Sqrt( len0 * len0 - x * x ); - - jointPos = startPos + x * vec0 + y * vec1; - - return true; -} - -/* -================ -idIK::GetBoneAxis -================ -*/ -float idIK::GetBoneAxis( const idVec3 &startPos, const idVec3 &endPos, const idVec3 &dir, idMat3 &axis ) { - float length; - axis[0] = endPos - startPos; - length = axis[0].Normalize(); - axis[1] = dir - axis[0] * dir * axis[0]; - axis[1].Normalize(); - axis[2].Cross( axis[1], axis[0] ); - return length; -} - - -/* -=============================================================================== - - idIK_Walk - -=============================================================================== -*/ - -/* -================ -idIK_Walk::idIK_Walk -================ -*/ -idIK_Walk::idIK_Walk() { - int i; - - initialized = false; - footModel = NULL; - numLegs = 0; - enabledLegs = 0; - for ( i = 0; i < MAX_LEGS; i++ ) { - footJoints[i] = INVALID_JOINT; - ankleJoints[i] = INVALID_JOINT; - kneeJoints[i] = INVALID_JOINT; - hipJoints[i] = INVALID_JOINT; - dirJoints[i] = INVALID_JOINT; - hipForward[i].Zero(); - kneeForward[i].Zero(); - upperLegLength[i] = 0.0f; - lowerLegLength[i] = 0.0f; - upperLegToHipJoint[i].Identity(); - lowerLegToKneeJoint[i].Identity(); - oldAnkleHeights[i] = 0.0f; - } - waistJoint = INVALID_JOINT; - - smoothing = 0.75f; - waistSmoothing = 0.5f; - footShift = 0.0f; - waistShift = 0.0f; - minWaistFloorDist = 0.0f; - minWaistAnkleDist = 0.0f; - footUpTrace = 32.0f; - footDownTrace = 32.0f; - tiltWaist = false; - usePivot = false; - - pivotFoot = -1; - pivotYaw = 0.0f; - pivotPos.Zero(); - - oldHeightsValid = false; - oldWaistHeight = 0.0f; - waistOffset.Zero(); -} - -/* -================ -idIK_Walk::~idIK_Walk -================ -*/ -idIK_Walk::~idIK_Walk() { - if ( footModel ) { - delete footModel; - } -} - -/* -================ -idIK_Walk::Save -================ -*/ -void idIK_Walk::Save( idSaveGame *savefile ) const { - int i; - - idIK::Save( savefile ); - - savefile->WriteClipModel( footModel ); - - savefile->WriteInt( numLegs ); - savefile->WriteInt( enabledLegs ); - for ( i = 0; i < MAX_LEGS; i++ ) - savefile->WriteInt( footJoints[i] ); - for ( i = 0; i < MAX_LEGS; i++ ) - savefile->WriteInt( ankleJoints[i] ); - for ( i = 0; i < MAX_LEGS; i++ ) - savefile->WriteInt( kneeJoints[i] ); - for ( i = 0; i < MAX_LEGS; i++ ) - savefile->WriteInt( hipJoints[i] ); - for ( i = 0; i < MAX_LEGS; i++ ) - savefile->WriteInt( dirJoints[i] ); - savefile->WriteInt( waistJoint ); - - for ( i = 0; i < MAX_LEGS; i++ ) - savefile->WriteVec3( hipForward[i] ); - for ( i = 0; i < MAX_LEGS; i++ ) - savefile->WriteVec3( kneeForward[i] ); - - for ( i = 0; i < MAX_LEGS; i++ ) - savefile->WriteFloat( upperLegLength[i] ); - for ( i = 0; i < MAX_LEGS; i++ ) - savefile->WriteFloat( lowerLegLength[i] ); - - for ( i = 0; i < MAX_LEGS; i++ ) - savefile->WriteMat3( upperLegToHipJoint[i] ); - for ( i = 0; i < MAX_LEGS; i++ ) - savefile->WriteMat3( lowerLegToKneeJoint[i] ); - - savefile->WriteFloat( smoothing ); - savefile->WriteFloat( waistSmoothing ); - savefile->WriteFloat( footShift ); - savefile->WriteFloat( waistShift ); - savefile->WriteFloat( minWaistFloorDist ); - savefile->WriteFloat( minWaistAnkleDist ); - savefile->WriteFloat( footUpTrace ); - savefile->WriteFloat( footDownTrace ); - savefile->WriteBool( tiltWaist ); - savefile->WriteBool( usePivot ); - - savefile->WriteInt( pivotFoot ); - savefile->WriteFloat( pivotYaw ); - savefile->WriteVec3( pivotPos ); - savefile->WriteBool( oldHeightsValid ); - savefile->WriteFloat( oldWaistHeight ); - for ( i = 0; i < MAX_LEGS; i++ ) { - savefile->WriteFloat( oldAnkleHeights[i] ); - } - savefile->WriteVec3( waistOffset ); -} - -/* -================ -idIK_Walk::Restore -================ -*/ -void idIK_Walk::Restore( idRestoreGame *savefile ) { - int i; - - idIK::Restore( savefile ); - - savefile->ReadClipModel( footModel ); - - savefile->ReadInt( numLegs ); - savefile->ReadInt( enabledLegs ); - for ( i = 0; i < MAX_LEGS; i++ ) - savefile->ReadInt( (int&)footJoints[i] ); - for ( i = 0; i < MAX_LEGS; i++ ) - savefile->ReadInt( (int&)ankleJoints[i] ); - for ( i = 0; i < MAX_LEGS; i++ ) - savefile->ReadInt( (int&)kneeJoints[i] ); - for ( i = 0; i < MAX_LEGS; i++ ) - savefile->ReadInt( (int&)hipJoints[i] ); - for ( i = 0; i < MAX_LEGS; i++ ) - savefile->ReadInt( (int&)dirJoints[i] ); - savefile->ReadInt( (int&)waistJoint ); - - for ( i = 0; i < MAX_LEGS; i++ ) - savefile->ReadVec3( hipForward[i] ); - for ( i = 0; i < MAX_LEGS; i++ ) - savefile->ReadVec3( kneeForward[i] ); - - for ( i = 0; i < MAX_LEGS; i++ ) - savefile->ReadFloat( upperLegLength[i] ); - for ( i = 0; i < MAX_LEGS; i++ ) - savefile->ReadFloat( lowerLegLength[i] ); - - for ( i = 0; i < MAX_LEGS; i++ ) - savefile->ReadMat3( upperLegToHipJoint[i] ); - for ( i = 0; i < MAX_LEGS; i++ ) - savefile->ReadMat3( lowerLegToKneeJoint[i] ); - - savefile->ReadFloat( smoothing ); - savefile->ReadFloat( waistSmoothing ); - savefile->ReadFloat( footShift ); - savefile->ReadFloat( waistShift ); - savefile->ReadFloat( minWaistFloorDist ); - savefile->ReadFloat( minWaistAnkleDist ); - savefile->ReadFloat( footUpTrace ); - savefile->ReadFloat( footDownTrace ); - savefile->ReadBool( tiltWaist ); - savefile->ReadBool( usePivot ); - - savefile->ReadInt( pivotFoot ); - savefile->ReadFloat( pivotYaw ); - savefile->ReadVec3( pivotPos ); - savefile->ReadBool( oldHeightsValid ); - savefile->ReadFloat( oldWaistHeight ); - for ( i = 0; i < MAX_LEGS; i++ ) { - savefile->ReadFloat( oldAnkleHeights[i] ); - } - savefile->ReadVec3( waistOffset ); -} - -/* -================ -idIK_Walk::Init -================ -*/ -bool idIK_Walk::Init( idEntity *self, const char *anim, const idVec3 &modelOffset ) { - int i; - float footSize; - idVec3 verts[4]; - idTraceModel trm; - const char *jointName; - idVec3 dir, ankleOrigin, kneeOrigin, hipOrigin, dirOrigin; - idMat3 axis, ankleAxis, kneeAxis, hipAxis; - - static idVec3 footWinding[4] = { - idVec3( 1.0f, 1.0f, 0.0f ), - idVec3( -1.0f, 1.0f, 0.0f ), - idVec3( -1.0f, -1.0f, 0.0f ), - idVec3( 1.0f, -1.0f, 0.0f ) - }; - - if ( !self ) { - return false; - } - - numLegs = Min( self->spawnArgs.GetInt( "ik_numLegs", "0" ), MAX_LEGS ); - if ( numLegs == 0 ) { - return true; - } - - if ( !idIK::Init( self, anim, modelOffset ) ) { - return false; - } - - int numJoints = animator->NumJoints(); - idJointMat *joints = ( idJointMat * )_alloca16( numJoints * sizeof( joints[0] ) ); - - // create the animation frame used to setup the IK - gameEdit->ANIM_CreateAnimFrame( animator->ModelHandle(), animator->GetAnim( modifiedAnim )->MD5Anim( 0 ), numJoints, joints, 1, animator->ModelDef()->GetVisualOffset() + modelOffset, animator->RemoveOrigin() ); - - enabledLegs = 0; - - // get all the joints - for ( i = 0; i < numLegs; i++ ) { - - jointName = self->spawnArgs.GetString( va( "ik_foot%d", i+1 ) ); - footJoints[i] = animator->GetJointHandle( jointName ); - if ( footJoints[i] == INVALID_JOINT ) { - gameLocal.Error( "idIK_Walk::Init: invalid foot joint '%s'", jointName ); - } - - jointName = self->spawnArgs.GetString( va( "ik_ankle%d", i+1 ) ); - ankleJoints[i] = animator->GetJointHandle( jointName ); - if ( ankleJoints[i] == INVALID_JOINT ) { - gameLocal.Error( "idIK_Walk::Init: invalid ankle joint '%s'", jointName ); - } - - jointName = self->spawnArgs.GetString( va( "ik_knee%d", i+1 ) ); - kneeJoints[i] = animator->GetJointHandle( jointName ); - if ( kneeJoints[i] == INVALID_JOINT ) { - gameLocal.Error( "idIK_Walk::Init: invalid knee joint '%s'\n", jointName ); - } - - jointName = self->spawnArgs.GetString( va( "ik_hip%d", i+1 ) ); - hipJoints[i] = animator->GetJointHandle( jointName ); - if ( hipJoints[i] == INVALID_JOINT ) { - gameLocal.Error( "idIK_Walk::Init: invalid hip joint '%s'\n", jointName ); - } - - jointName = self->spawnArgs.GetString( va( "ik_dir%d", i+1 ) ); - dirJoints[i] = animator->GetJointHandle( jointName ); - - enabledLegs |= 1 << i; - } - - jointName = self->spawnArgs.GetString( "ik_waist" ); - waistJoint = animator->GetJointHandle( jointName ); - if ( waistJoint == INVALID_JOINT ) { - gameLocal.Error( "idIK_Walk::Init: invalid waist joint '%s'\n", jointName ); - } - - // get the leg bone lengths and rotation matrices - for ( i = 0; i < numLegs; i++ ) { - oldAnkleHeights[i] = 0.0f; - - ankleAxis = joints[ ankleJoints[ i ] ].ToMat3(); - ankleOrigin = joints[ ankleJoints[ i ] ].ToVec3(); - - kneeAxis = joints[ kneeJoints[ i ] ].ToMat3(); - kneeOrigin = joints[ kneeJoints[ i ] ].ToVec3(); - - hipAxis = joints[ hipJoints[ i ] ].ToMat3(); - hipOrigin = joints[ hipJoints[ i ] ].ToVec3(); - - // get the IK direction - if ( dirJoints[i] != INVALID_JOINT ) { - dirOrigin = joints[ dirJoints[ i ] ].ToVec3(); - dir = dirOrigin - kneeOrigin; - } else { - dir.Set( 1.0f, 0.0f, 0.0f ); - } - - hipForward[i] = dir * hipAxis.Transpose(); - kneeForward[i] = dir * kneeAxis.Transpose(); - - // conversion from upper leg bone axis to hip joint axis - upperLegLength[i] = GetBoneAxis( hipOrigin, kneeOrigin, dir, axis ); - upperLegToHipJoint[i] = hipAxis * axis.Transpose(); - - // conversion from lower leg bone axis to knee joint axis - lowerLegLength[i] = GetBoneAxis( kneeOrigin, ankleOrigin, dir, axis ); - lowerLegToKneeJoint[i] = kneeAxis * axis.Transpose(); - } - - smoothing = self->spawnArgs.GetFloat( "ik_smoothing", "0.75" ); - waistSmoothing = self->spawnArgs.GetFloat( "ik_waistSmoothing", "0.75" ); - footShift = self->spawnArgs.GetFloat( "ik_footShift", "0" ); - waistShift = self->spawnArgs.GetFloat( "ik_waistShift", "0" ); - minWaistFloorDist = self->spawnArgs.GetFloat( "ik_minWaistFloorDist", "0" ); - minWaistAnkleDist = self->spawnArgs.GetFloat( "ik_minWaistAnkleDist", "0" ); - footUpTrace = self->spawnArgs.GetFloat( "ik_footUpTrace", "32" ); - footDownTrace = self->spawnArgs.GetFloat( "ik_footDownTrace", "32" ); - tiltWaist = self->spawnArgs.GetBool( "ik_tiltWaist", "0" ); - usePivot = self->spawnArgs.GetBool( "ik_usePivot", "0" ); - - // setup a clip model for the feet - footSize = self->spawnArgs.GetFloat( "ik_footSize", "4" ) * 0.5f; - if ( footSize > 0.0f ) { - for ( i = 0; i < 4; i++ ) { - verts[i] = footWinding[i] * footSize; - } - trm.SetupPolygon( verts, 4 ); - footModel = new idClipModel( trm ); - } - - initialized = true; - - return true; -} - -/* -================ -idIK_Walk::Evaluate -================ -*/ -void idIK_Walk::Evaluate( void ) { - int i, newPivotFoot = 0; - float modelHeight, jointHeight, lowestHeight, floorHeights[MAX_LEGS]; - float shift, smallestShift, newHeight, step, newPivotYaw, height, largestAnkleHeight; - idVec3 modelOrigin, normal, hipDir, kneeDir, start, end, jointOrigins[MAX_LEGS]; - idVec3 footOrigin, ankleOrigin, kneeOrigin, hipOrigin, waistOrigin; - idMat3 modelAxis, waistAxis, axis; - idMat3 hipAxis[MAX_LEGS], kneeAxis[MAX_LEGS], ankleAxis[MAX_LEGS]; - trace_t results; - - if ( !self || !gameLocal.isNewFrame ) { - return; - } - - // if no IK enabled on any legs - if ( !enabledLegs ) { - return; - } - - normal = - self->GetPhysics()->GetGravityNormal(); - modelOrigin = self->GetPhysics()->GetOrigin(); - modelAxis = self->GetRenderEntity()->axis; - modelHeight = modelOrigin * normal; - - modelOrigin += modelOffset * modelAxis; - - // create frame without joint mods - animator->CreateFrame( gameLocal.time, false ); - - // get the joint positions for the feet - lowestHeight = idMath::INFINITY; - for ( i = 0; i < numLegs; i++ ) { - animator->GetJointTransform( footJoints[i], gameLocal.time, footOrigin, axis ); - jointOrigins[i] = modelOrigin + footOrigin * modelAxis; - jointHeight = jointOrigins[i] * normal; - if ( jointHeight < lowestHeight ) { - lowestHeight = jointHeight; - newPivotFoot = i; - } - } - - if ( usePivot ) { - - newPivotYaw = modelAxis[0].ToYaw(); - - // change pivot foot - if ( newPivotFoot != pivotFoot || idMath::Fabs( idMath::AngleNormalize180( newPivotYaw - pivotYaw ) ) > 30.0f ) { - pivotFoot = newPivotFoot; - pivotYaw = newPivotYaw; - animator->GetJointTransform( footJoints[pivotFoot], gameLocal.time, footOrigin, axis ); - pivotPos = modelOrigin + footOrigin * modelAxis; - } - - // keep pivot foot in place - jointOrigins[pivotFoot] = pivotPos; - } - - // get the floor heights for the feet - for ( i = 0; i < numLegs; i++ ) { - - if ( !( enabledLegs & ( 1 << i ) ) ) { - continue; - } - - start = jointOrigins[i] + normal * footUpTrace; - end = jointOrigins[i] - normal * footDownTrace; - gameLocal.clip.Translation( results, start, end, footModel, mat3_identity, CONTENTS_SOLID|CONTENTS_IKCLIP, self ); - floorHeights[i] = results.endpos * normal; - - if ( ik_debug.GetBool() && footModel ) { - idFixedWinding w; - for ( int j = 0; j < footModel->GetTraceModel()->numVerts; j++ ) { - w += footModel->GetTraceModel()->verts[j]; - } - gameRenderWorld->DebugWinding( colorRed, w, results.endpos, results.endAxis ); - } - } - - const idPhysics *phys = self->GetPhysics(); - - // test whether or not the character standing on the ground - bool onGround = phys->HasGroundContacts(); - - // test whether or not the character is standing on a plat - bool onPlat = false; - for ( i = 0; i < phys->GetNumContacts(); i++ ) { - idEntity *ent = gameLocal.entities[ phys->GetContact( i ).entityNum ]; - if ( ent != NULL && ent->IsType( idPlat::Type ) ) { - onPlat = true; - break; - } - } - - // adjust heights of the ankles - smallestShift = idMath::INFINITY; - largestAnkleHeight = -idMath::INFINITY; - for ( i = 0; i < numLegs; i++ ) { - - if ( onGround && ( enabledLegs & ( 1 << i ) ) ) { - shift = floorHeights[i] - modelHeight + footShift; - } else { - shift = 0.0f; - } - - if ( shift < smallestShift ) { - smallestShift = shift; - } - - animator->GetJointTransform( ankleJoints[i], gameLocal.time, ankleOrigin, ankleAxis[i] ); - jointOrigins[i] = modelOrigin + ankleOrigin * modelAxis; - - height = jointOrigins[i] * normal; - - if ( oldHeightsValid && !onPlat ) { - step = height + shift - oldAnkleHeights[i]; - shift -= smoothing * step; - } - - newHeight = height + shift; - if ( newHeight > largestAnkleHeight ) { - largestAnkleHeight = newHeight; - } - - oldAnkleHeights[i] = newHeight; - - jointOrigins[i] += shift * normal; - } - - animator->GetJointTransform( waistJoint, gameLocal.time, waistOrigin, waistAxis ); - waistOrigin = modelOrigin + waistOrigin * modelAxis; - - // adjust position of the waist - waistOffset = ( smallestShift + waistShift ) * normal; - - // if the waist should be at least a certain distance above the floor - if ( minWaistFloorDist > 0.0f && waistOffset * normal < 0.0f ) { - start = waistOrigin; - end = waistOrigin + waistOffset - normal * minWaistFloorDist; - gameLocal.clip.Translation( results, start, end, footModel, modelAxis, CONTENTS_SOLID|CONTENTS_IKCLIP, self ); - height = ( waistOrigin + waistOffset - results.endpos ) * normal; - if ( height < minWaistFloorDist ) { - waistOffset += ( minWaistFloorDist - height ) * normal; - } - } - - // if the waist should be at least a certain distance above the ankles - if ( minWaistAnkleDist > 0.0f ) { - height = ( waistOrigin + waistOffset ) * normal; - if ( height - largestAnkleHeight < minWaistAnkleDist ) { - waistOffset += ( minWaistAnkleDist - ( height - largestAnkleHeight ) ) * normal; - } - } - - if ( oldHeightsValid ) { - // smoothly adjust height of waist - newHeight = ( waistOrigin + waistOffset ) * normal; - step = newHeight - oldWaistHeight; - waistOffset -= waistSmoothing * step * normal; - } - - // save height of waist for smoothing - oldWaistHeight = ( waistOrigin + waistOffset ) * normal; - - if ( !oldHeightsValid ) { - oldHeightsValid = true; - return; - } - - // solve IK - for ( i = 0; i < numLegs; i++ ) { - - // get the position of the hip in world space - animator->GetJointTransform( hipJoints[i], gameLocal.time, hipOrigin, axis ); - hipOrigin = modelOrigin + waistOffset + hipOrigin * modelAxis; - hipDir = hipForward[i] * axis * modelAxis; - - // get the IK bend direction - animator->GetJointTransform( kneeJoints[i], gameLocal.time, kneeOrigin, axis ); - kneeDir = kneeForward[i] * axis * modelAxis; - - // solve IK and calculate knee position - SolveTwoBones( hipOrigin, jointOrigins[i], kneeDir, upperLegLength[i], lowerLegLength[i], kneeOrigin ); - - if ( ik_debug.GetBool() ) { - gameRenderWorld->DebugLine( colorCyan, hipOrigin, kneeOrigin ); - gameRenderWorld->DebugLine( colorRed, kneeOrigin, jointOrigins[i] ); - gameRenderWorld->DebugLine( colorYellow, kneeOrigin, kneeOrigin + hipDir ); - gameRenderWorld->DebugLine( colorGreen, kneeOrigin, kneeOrigin + kneeDir ); - } - - // get the axis for the hip joint - GetBoneAxis( hipOrigin, kneeOrigin, hipDir, axis ); - hipAxis[i] = upperLegToHipJoint[i] * ( axis * modelAxis.Transpose() ); - - // get the axis for the knee joint - GetBoneAxis( kneeOrigin, jointOrigins[i], kneeDir, axis ); - kneeAxis[i] = lowerLegToKneeJoint[i] * ( axis * modelAxis.Transpose() ); - } - - // set the joint mods - animator->SetJointAxis( waistJoint, JOINTMOD_WORLD_OVERRIDE, waistAxis ); - animator->SetJointPos( waistJoint, JOINTMOD_WORLD_OVERRIDE, ( waistOrigin + waistOffset - modelOrigin ) * modelAxis.Transpose() ); - for ( i = 0; i < numLegs; i++ ) { - animator->SetJointAxis( hipJoints[i], JOINTMOD_WORLD_OVERRIDE, hipAxis[i] ); - animator->SetJointAxis( kneeJoints[i], JOINTMOD_WORLD_OVERRIDE, kneeAxis[i] ); - animator->SetJointAxis( ankleJoints[i], JOINTMOD_WORLD_OVERRIDE, ankleAxis[i] ); - } - - ik_activate = true; -} - -/* -================ -idIK_Walk::ClearJointMods -================ -*/ -void idIK_Walk::ClearJointMods( void ) { - int i; - - if ( !self || !ik_activate ) { - return; - } - - animator->SetJointAxis( waistJoint, JOINTMOD_NONE, mat3_identity ); - animator->SetJointPos( waistJoint, JOINTMOD_NONE, vec3_origin ); - for ( i = 0; i < numLegs; i++ ) { - animator->SetJointAxis( hipJoints[i], JOINTMOD_NONE, mat3_identity ); - animator->SetJointAxis( kneeJoints[i], JOINTMOD_NONE, mat3_identity ); - animator->SetJointAxis( ankleJoints[i], JOINTMOD_NONE, mat3_identity ); - } - - ik_activate = false; -} - -/* -================ -idIK_Walk::EnableAll -================ -*/ -void idIK_Walk::EnableAll( void ) { - enabledLegs = ( 1 << numLegs ) - 1; - oldHeightsValid = false; -} - -/* -================ -idIK_Walk::DisableAll -================ -*/ -void idIK_Walk::DisableAll( void ) { - enabledLegs = 0; - oldHeightsValid = false; -} - -/* -================ -idIK_Walk::EnableLeg -================ -*/ -void idIK_Walk::EnableLeg( int num ) { - enabledLegs |= 1 << num; -} - -/* -================ -idIK_Walk::DisableLeg -================ -*/ -void idIK_Walk::DisableLeg( int num ) { - enabledLegs &= ~( 1 << num ); -} - - -/* -=============================================================================== - - idIK_Reach - -=============================================================================== -*/ - -/* -================ -idIK_Reach::idIK_Reach -================ -*/ -idIK_Reach::idIK_Reach() { - int i; - - initialized = false; - numArms = 0; - enabledArms = 0; - for ( i = 0; i < MAX_ARMS; i++ ) { - handJoints[i] = INVALID_JOINT; - elbowJoints[i] = INVALID_JOINT; - shoulderJoints[i] = INVALID_JOINT; - dirJoints[i] = INVALID_JOINT; - shoulderForward[i].Zero(); - elbowForward[i].Zero(); - upperArmLength[i] = 0.0f; - lowerArmLength[i] = 0.0f; - upperArmToShoulderJoint[i].Identity(); - lowerArmToElbowJoint[i].Identity(); - } -} - -/* -================ -idIK_Reach::~idIK_Reach -================ -*/ -idIK_Reach::~idIK_Reach() { -} - -/* -================ -idIK_Reach::Save -================ -*/ -void idIK_Reach::Save( idSaveGame *savefile ) const { - int i; - idIK::Save( savefile ); - - savefile->WriteInt( numArms ); - savefile->WriteInt( enabledArms ); - for ( i = 0; i < MAX_ARMS; i++ ) - savefile->WriteInt( handJoints[i] ); - for ( i = 0; i < MAX_ARMS; i++ ) - savefile->WriteInt( elbowJoints[i] ); - for ( i = 0; i < MAX_ARMS; i++ ) - savefile->WriteInt( shoulderJoints[i] ); - for ( i = 0; i < MAX_ARMS; i++ ) - savefile->WriteInt( dirJoints[i] ); - - for ( i = 0; i < MAX_ARMS; i++ ) - savefile->WriteVec3( shoulderForward[i] ); - for ( i = 0; i < MAX_ARMS; i++ ) - savefile->WriteVec3( elbowForward[i] ); - - for ( i = 0; i < MAX_ARMS; i++ ) - savefile->WriteFloat( upperArmLength[i] ); - for ( i = 0; i < MAX_ARMS; i++ ) - savefile->WriteFloat( lowerArmLength[i] ); - - for ( i = 0; i < MAX_ARMS; i++ ) - savefile->WriteMat3( upperArmToShoulderJoint[i] ); - for ( i = 0; i < MAX_ARMS; i++ ) - savefile->WriteMat3( lowerArmToElbowJoint[i] ); -} - -/* -================ -idIK_Reach::Restore -================ -*/ -void idIK_Reach::Restore( idRestoreGame *savefile ) { - int i; - idIK::Restore( savefile ); - - savefile->ReadInt( numArms ); - savefile->ReadInt( enabledArms ); - for ( i = 0; i < MAX_ARMS; i++ ) - savefile->ReadInt( (int&)handJoints[i] ); - for ( i = 0; i < MAX_ARMS; i++ ) - savefile->ReadInt( (int&)elbowJoints[i] ); - for ( i = 0; i < MAX_ARMS; i++ ) - savefile->ReadInt( (int&)shoulderJoints[i] ); - for ( i = 0; i < MAX_ARMS; i++ ) - savefile->ReadInt( (int&)dirJoints[i] ); - - for ( i = 0; i < MAX_ARMS; i++ ) - savefile->ReadVec3( shoulderForward[i] ); - for ( i = 0; i < MAX_ARMS; i++ ) - savefile->ReadVec3( elbowForward[i] ); - - for ( i = 0; i < MAX_ARMS; i++ ) - savefile->ReadFloat( upperArmLength[i] ); - for ( i = 0; i < MAX_ARMS; i++ ) - savefile->ReadFloat( lowerArmLength[i] ); - - for ( i = 0; i < MAX_ARMS; i++ ) - savefile->ReadMat3( upperArmToShoulderJoint[i] ); - for ( i = 0; i < MAX_ARMS; i++ ) - savefile->ReadMat3( lowerArmToElbowJoint[i] ); -} - -/* -================ -idIK_Reach::Init -================ -*/ -bool idIK_Reach::Init( idEntity *self, const char *anim, const idVec3 &modelOffset ) { - int i; - const char *jointName; - idTraceModel trm; - idVec3 dir, handOrigin, elbowOrigin, shoulderOrigin, dirOrigin; - idMat3 axis, handAxis, elbowAxis, shoulderAxis; - - if ( !self ) { - return false; - } - - numArms = Min( self->spawnArgs.GetInt( "ik_numArms", "0" ), MAX_ARMS ); - if ( numArms == 0 ) { - return true; - } - - if ( !idIK::Init( self, anim, modelOffset ) ) { - return false; - } - - int numJoints = animator->NumJoints(); - idJointMat *joints = ( idJointMat * )_alloca16( numJoints * sizeof( joints[0] ) ); - - // create the animation frame used to setup the IK - gameEdit->ANIM_CreateAnimFrame( animator->ModelHandle(), animator->GetAnim( modifiedAnim )->MD5Anim( 0 ), numJoints, joints, 1, animator->ModelDef()->GetVisualOffset() + modelOffset, animator->RemoveOrigin() ); - - enabledArms = 0; - - // get all the joints - for ( i = 0; i < numArms; i++ ) { - - jointName = self->spawnArgs.GetString( va( "ik_hand%d", i+1 ) ); - handJoints[i] = animator->GetJointHandle( jointName ); - if ( handJoints[i] == INVALID_JOINT ) { - gameLocal.Error( "idIK_Reach::Init: invalid hand joint '%s'", jointName ); - } - - jointName = self->spawnArgs.GetString( va( "ik_elbow%d", i+1 ) ); - elbowJoints[i] = animator->GetJointHandle( jointName ); - if ( elbowJoints[i] == INVALID_JOINT ) { - gameLocal.Error( "idIK_Reach::Init: invalid elbow joint '%s'\n", jointName ); - } - - jointName = self->spawnArgs.GetString( va( "ik_shoulder%d", i+1 ) ); - shoulderJoints[i] = animator->GetJointHandle( jointName ); - if ( shoulderJoints[i] == INVALID_JOINT ) { - gameLocal.Error( "idIK_Reach::Init: invalid shoulder joint '%s'\n", jointName ); - } - - jointName = self->spawnArgs.GetString( va( "ik_elbowDir%d", i+1 ) ); - dirJoints[i] = animator->GetJointHandle( jointName ); - - enabledArms |= 1 << i; - } - - // get the arm bone lengths and rotation matrices - for ( i = 0; i < numArms; i++ ) { - - handAxis = joints[ handJoints[ i ] ].ToMat3(); - handOrigin = joints[ handJoints[ i ] ].ToVec3(); - - elbowAxis = joints[ elbowJoints[ i ] ].ToMat3(); - elbowOrigin = joints[ elbowJoints[ i ] ].ToVec3(); - - shoulderAxis = joints[ shoulderJoints[ i ] ].ToMat3(); - shoulderOrigin = joints[ shoulderJoints[ i ] ].ToVec3(); - - // get the IK direction - if ( dirJoints[i] != INVALID_JOINT ) { - dirOrigin = joints[ dirJoints[ i ] ].ToVec3(); - dir = dirOrigin - elbowOrigin; - } else { - dir.Set( -1.0f, 0.0f, 0.0f ); - } - - shoulderForward[i] = dir * shoulderAxis.Transpose(); - elbowForward[i] = dir * elbowAxis.Transpose(); - - // conversion from upper arm bone axis to should joint axis - upperArmLength[i] = GetBoneAxis( shoulderOrigin, elbowOrigin, dir, axis ); - upperArmToShoulderJoint[i] = shoulderAxis * axis.Transpose(); - - // conversion from lower arm bone axis to elbow joint axis - lowerArmLength[i] = GetBoneAxis( elbowOrigin, handOrigin, dir, axis ); - lowerArmToElbowJoint[i] = elbowAxis * axis.Transpose(); - } - - initialized = true; - - return true; -} - -/* -================ -idIK_Reach::Evaluate -================ -*/ -void idIK_Reach::Evaluate( void ) { - int i; - idVec3 modelOrigin, shoulderOrigin, elbowOrigin, handOrigin, shoulderDir, elbowDir; - idMat3 modelAxis, axis; - idMat3 shoulderAxis[MAX_ARMS], elbowAxis[MAX_ARMS]; - trace_t trace; - - modelOrigin = self->GetRenderEntity()->origin; - modelAxis = self->GetRenderEntity()->axis; - - // solve IK - for ( i = 0; i < numArms; i++ ) { - - // get the position of the shoulder in world space - animator->GetJointTransform( shoulderJoints[i], gameLocal.time, shoulderOrigin, axis ); - shoulderOrigin = modelOrigin + shoulderOrigin * modelAxis; - shoulderDir = shoulderForward[i] * axis * modelAxis; - - // get the position of the hand in world space - animator->GetJointTransform( handJoints[i], gameLocal.time, handOrigin, axis ); - handOrigin = modelOrigin + handOrigin * modelAxis; - - // get first collision going from shoulder to hand - gameLocal.clip.TracePoint( trace, shoulderOrigin, handOrigin, CONTENTS_SOLID, self ); - handOrigin = trace.endpos; - - // get the IK bend direction - animator->GetJointTransform( elbowJoints[i], gameLocal.time, elbowOrigin, axis ); - elbowDir = elbowForward[i] * axis * modelAxis; - - // solve IK and calculate elbow position - SolveTwoBones( shoulderOrigin, handOrigin, elbowDir, upperArmLength[i], lowerArmLength[i], elbowOrigin ); - - if ( ik_debug.GetBool() ) { - gameRenderWorld->DebugLine( colorCyan, shoulderOrigin, elbowOrigin ); - gameRenderWorld->DebugLine( colorRed, elbowOrigin, handOrigin ); - gameRenderWorld->DebugLine( colorYellow, elbowOrigin, elbowOrigin + elbowDir ); - gameRenderWorld->DebugLine( colorGreen, elbowOrigin, elbowOrigin + shoulderDir ); - } - - // get the axis for the shoulder joint - GetBoneAxis( shoulderOrigin, elbowOrigin, shoulderDir, axis ); - shoulderAxis[i] = upperArmToShoulderJoint[i] * ( axis * modelAxis.Transpose() ); - - // get the axis for the elbow joint - GetBoneAxis( elbowOrigin, handOrigin, elbowDir, axis ); - elbowAxis[i] = lowerArmToElbowJoint[i] * ( axis * modelAxis.Transpose() ); - } - - for ( i = 0; i < numArms; i++ ) { - animator->SetJointAxis( shoulderJoints[i], JOINTMOD_WORLD_OVERRIDE, shoulderAxis[i] ); - animator->SetJointAxis( elbowJoints[i], JOINTMOD_WORLD_OVERRIDE, elbowAxis[i] ); - } - - ik_activate = true; -} - -/* -================ -idIK_Reach::ClearJointMods -================ -*/ -void idIK_Reach::ClearJointMods( void ) { - int i; - - if ( !self || !ik_activate ) { - return; - } - - for ( i = 0; i < numArms; i++ ) { - animator->SetJointAxis( shoulderJoints[i], JOINTMOD_NONE, mat3_identity ); - animator->SetJointAxis( elbowJoints[i], JOINTMOD_NONE, mat3_identity ); - animator->SetJointAxis( handJoints[i], JOINTMOD_NONE, mat3_identity ); - } - - ik_activate = false; -} diff --git a/d3xp/IK.h b/d3xp/IK.h deleted file mode 100644 index a2a9f837..00000000 --- a/d3xp/IK.h +++ /dev/null @@ -1,187 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __GAME_IK_H__ -#define __GAME_IK_H__ - -#include "Entity.h" - -class idSaveGame; -class idRestoreGame; - -/* -=============================================================================== - - IK base class with a simple fast two bone solver. - -=============================================================================== -*/ - -#define IK_ANIM "ik_pose" - -class idIK { -public: - idIK( void ); - virtual ~idIK( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - bool IsInitialized( void ) const; - - virtual bool Init( idEntity *self, const char *anim, const idVec3 &modelOffset ); - virtual void Evaluate( void ); - virtual void ClearJointMods( void ); - - bool SolveTwoBones( const idVec3 &startPos, const idVec3 &endPos, const idVec3 &dir, float len0, float len1, idVec3 &jointPos ); - float GetBoneAxis( const idVec3 &startPos, const idVec3 &endPos, const idVec3 &dir, idMat3 &axis ); - -protected: - bool initialized; - bool ik_activate; - idEntity * self; // entity using the animated model - idAnimator * animator; // animator on entity - int modifiedAnim; // animation modified by the IK - idVec3 modelOffset; -}; - - -/* -=============================================================================== - - IK controller for a walking character with an arbitrary number of legs. - -=============================================================================== -*/ - -class idIK_Walk : public idIK { -public: - - idIK_Walk( void ); - virtual ~idIK_Walk( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - virtual bool Init( idEntity *self, const char *anim, const idVec3 &modelOffset ); - virtual void Evaluate( void ); - virtual void ClearJointMods( void ); - - void EnableAll( void ); - void DisableAll( void ); - void EnableLeg( int num ); - void DisableLeg( int num ); - -private: - static const int MAX_LEGS = 8; - - idClipModel * footModel; - - int numLegs; - int enabledLegs; - jointHandle_t footJoints[MAX_LEGS]; - jointHandle_t ankleJoints[MAX_LEGS]; - jointHandle_t kneeJoints[MAX_LEGS]; - jointHandle_t hipJoints[MAX_LEGS]; - jointHandle_t dirJoints[MAX_LEGS]; - jointHandle_t waistJoint; - - idVec3 hipForward[MAX_LEGS]; - idVec3 kneeForward[MAX_LEGS]; - - float upperLegLength[MAX_LEGS]; - float lowerLegLength[MAX_LEGS]; - - idMat3 upperLegToHipJoint[MAX_LEGS]; - idMat3 lowerLegToKneeJoint[MAX_LEGS]; - - float smoothing; - float waistSmoothing; - float footShift; - float waistShift; - float minWaistFloorDist; - float minWaistAnkleDist; - float footUpTrace; - float footDownTrace; - bool tiltWaist; - bool usePivot; - - // state - int pivotFoot; - float pivotYaw; - idVec3 pivotPos; - bool oldHeightsValid; - float oldWaistHeight; - float oldAnkleHeights[MAX_LEGS]; - idVec3 waistOffset; -}; - - -/* -=============================================================================== - - IK controller for reaching a position with an arm or leg. - -=============================================================================== -*/ - -class idIK_Reach : public idIK { -public: - - idIK_Reach( void ); - virtual ~idIK_Reach( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - virtual bool Init( idEntity *self, const char *anim, const idVec3 &modelOffset ); - virtual void Evaluate( void ); - virtual void ClearJointMods( void ); - -private: - - static const int MAX_ARMS = 2; - - int numArms; - int enabledArms; - jointHandle_t handJoints[MAX_ARMS]; - jointHandle_t elbowJoints[MAX_ARMS]; - jointHandle_t shoulderJoints[MAX_ARMS]; - jointHandle_t dirJoints[MAX_ARMS]; - - idVec3 shoulderForward[MAX_ARMS]; - idVec3 elbowForward[MAX_ARMS]; - - float upperArmLength[MAX_ARMS]; - float lowerArmLength[MAX_ARMS]; - - idMat3 upperArmToShoulderJoint[MAX_ARMS]; - idMat3 lowerArmToElbowJoint[MAX_ARMS]; -}; - -#endif /* !__GAME_IK_H__ */ diff --git a/d3xp/Item.cpp b/d3xp/Item.cpp deleted file mode 100644 index 0c1356d8..00000000 --- a/d3xp/Item.cpp +++ /dev/null @@ -1,2168 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "renderer/RenderSystem.h" - -#include "gamesys/SysCvar.h" -#include "Player.h" -#include "Fx.h" -#include "SmokeParticles.h" - -#include "Item.h" - -/* -=============================================================================== - - idItem - -=============================================================================== -*/ - -const idEventDef EV_DropToFloor( "" ); -const idEventDef EV_RespawnItem( "respawn" ); -const idEventDef EV_RespawnFx( "" ); -const idEventDef EV_GetPlayerPos( "" ); -const idEventDef EV_HideObjective( "", "e" ); -const idEventDef EV_CamShot( "" ); - -CLASS_DECLARATION( idEntity, idItem ) - EVENT( EV_DropToFloor, idItem::Event_DropToFloor ) - EVENT( EV_Touch, idItem::Event_Touch ) - EVENT( EV_Activate, idItem::Event_Trigger ) - EVENT( EV_RespawnItem, idItem::Event_Respawn ) - EVENT( EV_RespawnFx, idItem::Event_RespawnFx ) -END_CLASS - - -/* -================ -idItem::idItem -================ -*/ -idItem::idItem() { - spin = false; - inView = false; - inViewTime = 0; - lastCycle = 0; - lastRenderViewTime = -1; - itemShellHandle = -1; - shellMaterial = NULL; - orgOrigin.Zero(); - canPickUp = true; - fl.networkSync = true; -} - -/* -================ -idItem::~idItem -================ -*/ -idItem::~idItem() { - // remove the highlight shell - if ( itemShellHandle != -1 ) { - gameRenderWorld->FreeEntityDef( itemShellHandle ); - } -} - -/* -================ -idItem::Save -================ -*/ -void idItem::Save( idSaveGame *savefile ) const { - - savefile->WriteVec3( orgOrigin ); - savefile->WriteBool( spin ); - savefile->WriteBool( pulse ); - savefile->WriteBool( canPickUp ); - - savefile->WriteMaterial( shellMaterial ); - - savefile->WriteBool( inView ); - savefile->WriteInt( inViewTime ); - savefile->WriteInt( lastCycle ); - savefile->WriteInt( lastRenderViewTime ); -} - -/* -================ -idItem::Restore -================ -*/ -void idItem::Restore( idRestoreGame *savefile ) { - - savefile->ReadVec3( orgOrigin ); - savefile->ReadBool( spin ); - savefile->ReadBool( pulse ); - savefile->ReadBool( canPickUp ); - - savefile->ReadMaterial( shellMaterial ); - - savefile->ReadBool( inView ); - savefile->ReadInt( inViewTime ); - savefile->ReadInt( lastCycle ); - savefile->ReadInt( lastRenderViewTime ); - - itemShellHandle = -1; -} - -/* -================ -idItem::UpdateRenderEntity -================ -*/ -bool idItem::UpdateRenderEntity( renderEntity_s *renderEntity, const renderView_t *renderView ) const { - - if ( lastRenderViewTime == renderView->time ) { - return false; - } - - lastRenderViewTime = renderView->time; - - // check for glow highlighting if near the center of the view - idVec3 dir = renderEntity->origin - renderView->vieworg; - dir.Normalize(); - float d = dir * renderView->viewaxis[0]; - - // two second pulse cycle - float cycle = ( renderView->time - inViewTime ) / 2000.0f; - - if ( d > 0.94f ) { - if ( !inView ) { - inView = true; - if ( cycle > lastCycle ) { - // restart at the beginning - inViewTime = renderView->time; - cycle = 0.0f; - } - } - } else { - if ( inView ) { - inView = false; - lastCycle = ceil( cycle ); - } - } - - // fade down after the last pulse finishes - if ( !inView && cycle > lastCycle ) { - renderEntity->shaderParms[4] = 0.0f; - } else { - // pulse up in 1/4 second - cycle -= (int)cycle; - if ( cycle < 0.1f ) { - renderEntity->shaderParms[4] = cycle * 10.0f; - } else if ( cycle < 0.2f ) { - renderEntity->shaderParms[4] = 1.0f; - } else if ( cycle < 0.3f ) { - renderEntity->shaderParms[4] = 1.0f - ( cycle - 0.2f ) * 10.0f; - } else { - // stay off between pulses - renderEntity->shaderParms[4] = 0.0f; - } - } - - // update every single time this is in view - return true; -} - -/* -================ -idItem::ModelCallback -================ -*/ -bool idItem::ModelCallback( renderEntity_t *renderEntity, const renderView_t *renderView ) { - const idItem *ent; - - // this may be triggered by a model trace or other non-view related source - if ( !renderView ) { - return false; - } - - ent = static_cast(gameLocal.entities[ renderEntity->entityNum ]); - if ( !ent ) { - gameLocal.Error( "idItem::ModelCallback: callback with NULL game entity" ); - } - - return ent->UpdateRenderEntity( renderEntity, renderView ); -} - -/* -================ -idItem::Think -================ -*/ -void idItem::Think( void ) { - if ( thinkFlags & TH_THINK ) { - if ( spin ) { - idAngles ang; - idVec3 org; - - ang.pitch = ang.roll = 0.0f; - ang.yaw = ( gameLocal.time & 4095 ) * 360.0f / -4096.0f; - SetAngles( ang ); - - float scale = 0.005f + entityNumber * 0.00001f; - - org = orgOrigin; - org.z += 4.0f + cos( ( gameLocal.time + 2000 ) * scale ) * 4.0f; - SetOrigin( org ); - } - } - - Present(); -} - -/* -================ -idItem::Present -================ -*/ -void idItem::Present( void ) { - idEntity::Present(); - - if ( !fl.hidden && pulse ) { - // also add a highlight shell model - renderEntity_t shell; - - shell = renderEntity; - - // we will mess with shader parms when the item is in view - // to give the "item pulse" effect - shell.callback = idItem::ModelCallback; - shell.entityNum = entityNumber; - shell.customShader = shellMaterial; - if ( itemShellHandle == -1 ) { - itemShellHandle = gameRenderWorld->AddEntityDef( &shell ); - } else { - gameRenderWorld->UpdateEntityDef( itemShellHandle, &shell ); - } - - } -} - -/* -================ -idItem::Spawn -================ -*/ -void idItem::Spawn( void ) { - idStr giveTo; - idEntity * ent; - float tsize; - - if ( spawnArgs.GetBool( "dropToFloor" ) ) { - PostEventMS( &EV_DropToFloor, 0 ); - } - - if ( spawnArgs.GetFloat( "triggersize", "0", tsize ) ) { - GetPhysics()->GetClipModel()->LoadModel( idTraceModel( idBounds( vec3_origin ).Expand( tsize ) ) ); - GetPhysics()->GetClipModel()->Link( gameLocal.clip ); - } - - if ( spawnArgs.GetBool( "start_off" ) ) { - GetPhysics()->SetContents( 0 ); - Hide(); - } else { - GetPhysics()->SetContents( CONTENTS_TRIGGER ); - } - - giveTo = spawnArgs.GetString( "owner" ); - if ( giveTo.Length() ) { - ent = gameLocal.FindEntity( giveTo ); - if ( !ent ) { - gameLocal.Error( "Item couldn't find owner '%s'", giveTo.c_str() ); - } - PostEventMS( &EV_Touch, 0, ent, 0 ); - } - -#ifdef CTF - // idItemTeam does not rotate and bob - if ( spawnArgs.GetBool( "spin" ) || (gameLocal.isMultiplayer && !this->IsType( idItemTeam::Type ) ) ) { - spin = true; - BecomeActive( TH_THINK ); - } -#else - if ( spawnArgs.GetBool( "spin" ) || gameLocal.isMultiplayer ) { - spin = true; - BecomeActive( TH_THINK ); - } -#endif - - //pulse = !spawnArgs.GetBool( "nopulse" ); - //temp hack for tim - pulse = false; - orgOrigin = GetPhysics()->GetOrigin(); - - canPickUp = !( spawnArgs.GetBool( "triggerFirst" ) || spawnArgs.GetBool( "no_touch" ) ); - - inViewTime = -1000; - lastCycle = -1; - itemShellHandle = -1; - shellMaterial = declManager->FindMaterial( "itemHighlightShell" ); -} - -/* -================ -idItem::GetAttributes -================ -*/ -void idItem::GetAttributes( idDict &attributes ) { - int i; - const idKeyValue *arg; - - for( i = 0; i < spawnArgs.GetNumKeyVals(); i++ ) { - arg = spawnArgs.GetKeyVal( i ); - if ( arg->GetKey().Left( 4 ) == "inv_" ) { - attributes.Set( arg->GetKey().Right( arg->GetKey().Length() - 4 ), arg->GetValue() ); - } - } -} - -/* -================ -idItem::GiveToPlayer -================ -*/ -bool idItem::GiveToPlayer( idPlayer *player ) { - if ( player == NULL ) { - return false; - } - - if ( spawnArgs.GetBool( "inv_carry" ) ) { - return player->GiveInventoryItem( &spawnArgs ); - } - - return player->GiveItem( this ); -} - -/* -================ -idItem::Pickup -================ -*/ -bool idItem::Pickup( idPlayer *player ) { - - if ( !GiveToPlayer( player ) ) { - return false; - } - - if ( gameLocal.isServer ) { - ServerSendEvent( EVENT_PICKUP, NULL, false, -1 ); - } - - // play pickup sound - StartSound( "snd_acquire", SND_CHANNEL_ITEM, 0, false, NULL ); - - // trigger our targets - ActivateTargets( player ); - - // clear our contents so the object isn't picked up twice - GetPhysics()->SetContents( 0 ); - - // hide the model - Hide(); - - // add the highlight shell - if ( itemShellHandle != -1 ) { - gameRenderWorld->FreeEntityDef( itemShellHandle ); - itemShellHandle = -1; - } - - float respawn = spawnArgs.GetFloat( "respawn" ); - bool dropped = spawnArgs.GetBool( "dropped" ); - bool no_respawn = spawnArgs.GetBool( "no_respawn" ); - - if ( gameLocal.isMultiplayer && respawn == 0.0f ) { - respawn = 20.0f; - } - - if ( respawn && !dropped && !no_respawn ) { - const char *sfx = spawnArgs.GetString( "fxRespawn" ); - if ( sfx && *sfx ) { - PostEventSec( &EV_RespawnFx, respawn - 0.5f ); - } - PostEventSec( &EV_RespawnItem, respawn ); - } else if ( !spawnArgs.GetBool( "inv_objective" ) && !no_respawn ) { - // give some time for the pickup sound to play - // FIXME: Play on the owner - if ( !spawnArgs.GetBool( "inv_carry" ) ) { - PostEventMS( &EV_Remove, 5000 ); - } - } - - BecomeInactive( TH_THINK ); - return true; -} - -/* -================ -idItem::ClientPredictionThink -================ -*/ -void idItem::ClientPredictionThink( void ) { - // only think forward because the state is not synced through snapshots - if ( !gameLocal.isNewFrame ) { - return; - } - Think(); -} - -/* -================ -idItem::WriteFromSnapshot -================ -*/ -void idItem::WriteToSnapshot( idBitMsgDelta &msg ) const { - msg.WriteBits( IsHidden(), 1 ); -} - -/* -================ -idItem::ReadFromSnapshot -================ -*/ -void idItem::ReadFromSnapshot( const idBitMsgDelta &msg ) { - if ( msg.ReadBits( 1 ) ) { - Hide(); - } else { - Show(); - } -} - -/* -================ -idItem::ClientReceiveEvent -================ -*/ -bool idItem::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) { - - switch( event ) { - case EVENT_PICKUP: { - - // play pickup sound - StartSound( "snd_acquire", SND_CHANNEL_ITEM, 0, false, NULL ); - - // hide the model - Hide(); - - // remove the highlight shell - if ( itemShellHandle != -1 ) { - gameRenderWorld->FreeEntityDef( itemShellHandle ); - itemShellHandle = -1; - } - return true; - } - case EVENT_RESPAWN: { - Event_Respawn(); - return true; - } - case EVENT_RESPAWNFX: { - Event_RespawnFx(); - return true; - } - default: - break; - } - - return idEntity::ClientReceiveEvent( event, time, msg ); -} - -/* -================ -idItem::Event_DropToFloor -================ -*/ -void idItem::Event_DropToFloor( void ) { - trace_t trace; - - // don't drop the floor if bound to another entity - if ( GetBindMaster() != NULL && GetBindMaster() != this ) { - return; - } - - gameLocal.clip.TraceBounds( trace, renderEntity.origin, renderEntity.origin - idVec3( 0, 0, 64 ), renderEntity.bounds, MASK_SOLID | CONTENTS_CORPSE, this ); - SetOrigin( trace.endpos ); -} - -/* -================ -idItem::Event_Touch -================ -*/ -void idItem::Event_Touch( idEntity *other, trace_t *trace ) { - if ( !other->IsType( idPlayer::Type ) ) { - return; - } - - if ( !canPickUp ) { - return; - } - - Pickup( static_cast(other) ); -} - -/* -================ -idItem::Event_Trigger -================ -*/ -void idItem::Event_Trigger( idEntity *activator ) { - - if ( !canPickUp && spawnArgs.GetBool( "triggerFirst" ) ) { - canPickUp = true; - return; - } - - if ( activator && activator->IsType( idPlayer::Type ) ) { - Pickup( static_cast( activator ) ); - } -} - -/* -================ -idItem::Event_Respawn -================ -*/ -void idItem::Event_Respawn( void ) { - if ( gameLocal.isServer ) { - ServerSendEvent( EVENT_RESPAWN, NULL, false, -1 ); - } - BecomeActive( TH_THINK ); - Show(); - inViewTime = -1000; - lastCycle = -1; - GetPhysics()->SetContents( CONTENTS_TRIGGER ); - SetOrigin( orgOrigin ); - StartSound( "snd_respawn", SND_CHANNEL_ITEM, 0, false, NULL ); - CancelEvents( &EV_RespawnItem ); // don't double respawn -} - -/* -================ -idItem::Event_RespawnFx -================ -*/ -void idItem::Event_RespawnFx( void ) { - if ( gameLocal.isServer ) { - ServerSendEvent( EVENT_RESPAWNFX, NULL, false, -1 ); - } - const char *sfx = spawnArgs.GetString( "fxRespawn" ); - if ( sfx && *sfx ) { - idEntityFx::StartFx( sfx, NULL, NULL, this, true ); - } -} - -/* -=============================================================================== - - idItemPowerup - -=============================================================================== -*/ - -/* -=============== -idItemPowerup -=============== -*/ - -CLASS_DECLARATION( idItem, idItemPowerup ) -END_CLASS - -/* -================ -idItemPowerup::idItemPowerup -================ -*/ -idItemPowerup::idItemPowerup() { - time = 0; - type = 0; -} - -/* -================ -idItemPowerup::Save -================ -*/ -void idItemPowerup::Save( idSaveGame *savefile ) const { - savefile->WriteInt( time ); - savefile->WriteInt( type ); -} - -/* -================ -idItemPowerup::Restore -================ -*/ -void idItemPowerup::Restore( idRestoreGame *savefile ) { - savefile->ReadInt( time ); - savefile->ReadInt( type ); -} - -/* -================ -idItemPowerup::Spawn -================ -*/ -void idItemPowerup::Spawn( void ) { - time = spawnArgs.GetInt( "time", "30" ); - type = spawnArgs.GetInt( "type", "0" ); -} - -/* -================ -idItemPowerup::GiveToPlayer -================ -*/ -bool idItemPowerup::GiveToPlayer( idPlayer *player ) { - if ( player->spectating ) { - return false; - } - player->GivePowerUp( type, time * 1000 ); - return true; -} - -#ifdef CTF - - -/* -=============================================================================== - - idItemTeam - - Used for flags in Capture the Flag - -=============================================================================== -*/ - -// temporarely removed these events - -const idEventDef EV_FlagReturn( "flagreturn", "e" ); -const idEventDef EV_TakeFlag( "takeflag", "e" ); -const idEventDef EV_DropFlag( "dropflag", "d" ); -const idEventDef EV_FlagCapture( "flagcapture" ); - -CLASS_DECLARATION( idItem, idItemTeam ) - EVENT( EV_FlagReturn, idItemTeam::Event_FlagReturn ) - EVENT( EV_TakeFlag, idItemTeam::Event_TakeFlag ) - EVENT( EV_DropFlag, idItemTeam::Event_DropFlag ) - EVENT( EV_FlagCapture, idItemTeam::Event_FlagCapture ) -END_CLASS - -/* -=============== -idItemTeam::idItemTeam -=============== -*/ -idItemTeam::idItemTeam() { - team = -1; - carried = false; - dropped = false; - lastDrop = 0; - - itemGlowHandle = -1; - - skinDefault = NULL; - skinCarried = NULL; - - scriptTaken = NULL; - scriptDropped = NULL; - scriptReturned = NULL; - scriptCaptured = NULL; - - lastNuggetDrop = 0; - nuggetName = 0; -} - -/* -=============== -idItemTeam::~idItemTeam -=============== -*/ -idItemTeam::~idItemTeam() { - FreeLightDef(); -} -/* -=============== -idItemTeam::Spawn -=============== -*/ -void idItemTeam::Spawn( void ) { - team = spawnArgs.GetInt( "team" ); - returnOrigin = GetPhysics()->GetOrigin() + idVec3( 0, 0, 20 ); - returnAxis = GetPhysics()->GetAxis(); - - BecomeActive( TH_THINK ); - - const char * skinName; - skinName = spawnArgs.GetString( "skin", "" ); - if ( skinName[0] ) - skinDefault = declManager->FindSkin( skinName ); - - skinName = spawnArgs.GetString( "skin_carried", "" ); - if ( skinName[0] ) - skinCarried = declManager->FindSkin( skinName ); - - nuggetName = spawnArgs.GetString( "nugget_name", "" ); - if ( !nuggetName[0] ) { - nuggetName = NULL; - } - - scriptTaken = LoadScript( "script_taken" ); - scriptDropped = LoadScript( "script_dropped" ); - scriptReturned = LoadScript( "script_returned" ); - scriptCaptured = LoadScript( "script_captured" ); - - /* Spawn attached dlight */ - /* - idDict args; - idVec3 lightOffset( 0.0f, 20.0f, 0.0f ); - - // Set up the flag's dynamic light - memset( &itemGlow, 0, sizeof( itemGlow ) ); - itemGlow.axis = mat3_identity; - itemGlow.lightRadius.x = 128.0f; - itemGlow.lightRadius.y = itemGlow.lightRadius.z = itemGlow.lightRadius.x; - itemGlow.noShadows = true; - itemGlow.pointLight = true; - itemGlow.shaderParms[ SHADERPARM_RED ] = 0.0f; - itemGlow.shaderParms[ SHADERPARM_GREEN ] = 0.0f; - itemGlow.shaderParms[ SHADERPARM_BLUE ] = 0.0f; - itemGlow.shaderParms[ SHADERPARM_ALPHA ] = 0.0f; - - // Select a shader based on the team - if ( team == 0 ) - itemGlow.shader = declManager->FindMaterial( "lights/redflag" ); - else - itemGlow.shader = declManager->FindMaterial( "lights/blueflag" ); - */ - - idMoveableItem::Spawn(); - - physicsObj.SetContents( 0 ); - physicsObj.SetClipMask( MASK_SOLID | CONTENTS_MOVEABLECLIP ); - physicsObj.SetGravity( idVec3( 0, 0, spawnArgs.GetInt("gravity", "-30" ) ) ); -} - - -/* -=============== -idItemTeam::LoadScript -=============== -*/ -function_t * idItemTeam::LoadScript( const char * script ) { - function_t * function = NULL; - idStr funcname = spawnArgs.GetString( script, "" ); - if ( funcname.Length() ) { - function = gameLocal.program.FindFunction( funcname ); - if ( function == NULL ) { -#ifdef _DEBUG - gameLocal.Warning( "idItemTeam '%s' at (%s) calls unknown function '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), funcname.c_str() ); -#endif - } - } - return function; -} - - -/* -=============== -idItemTeam::Think -=============== -*/ -void idItemTeam::Think( void ) { - idMoveableItem::Think(); - - TouchTriggers(); - - // TODO : only update on updatevisuals - /*idVec3 offset( 0.0f, 0.0f, 20.0f ); - itemGlow.origin = GetPhysics()->GetOrigin() + offset; - if ( itemGlowHandle == -1 ) { - itemGlowHandle = gameRenderWorld->AddLightDef( &itemGlow ); - } else { - gameRenderWorld->UpdateLightDef( itemGlowHandle, &itemGlow ); - }*/ - -#if 1 - // should only the server do this? - if ( gameLocal.isServer && nuggetName && carried && ( !lastNuggetDrop || (gameLocal.time - lastNuggetDrop) > spawnArgs.GetInt("nugget_frequency") ) ) { - - SpawnNugget( GetPhysics()->GetOrigin() ); - lastNuggetDrop = gameLocal.time; - } -#endif - - // return dropped flag after si_flagDropTimeLimit seconds - if ( dropped && !carried && lastDrop != 0 && (gameLocal.time - lastDrop) > ( si_flagDropTimeLimit.GetInteger()*1000 ) ) { - - Return(); // return flag after 30 seconds on ground - return; - } -} - -/* -=============== -idItemTeam::Pickup -=============== -*/ -bool idItemTeam::Pickup( idPlayer *player ) { - if ( !gameLocal.mpGame.IsGametypeFlagBased() ) /* CTF */ - return false; - - if ( gameLocal.mpGame.GetGameState() == idMultiplayerGame::WARMUP || - gameLocal.mpGame.GetGameState() == idMultiplayerGame::COUNTDOWN ) - return false; - - // wait 2 seconds after drop before beeing picked up again - if ( lastDrop != 0 && (gameLocal.time - lastDrop) < spawnArgs.GetInt("pickupDelay", "500") ) - return false; - - if ( carried == false && player->team != this->team ) { - - PostEventMS( &EV_TakeFlag, 0, player ); - - return true; - } else if ( carried == false && dropped == true && player->team == this->team ) { - - gameLocal.mpGame.PlayerScoreCTF( player->entityNumber, 5 ); - - // return flag - PostEventMS( &EV_FlagReturn, 0, player ); - - return false; - } - - return false; -} - -/* -=============== -idItemTeam::ClientReceiveEvent -=============== -*/ -bool idItemTeam::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) { - gameLocal.DPrintf("ClientRecieveEvent: %i\n", event ); - - switch ( event ) { - case EVENT_TAKEFLAG: { - idPlayer * player = static_cast(gameLocal.entities[ msg.ReadBits( GENTITYNUM_BITS ) ]); - if ( player == NULL ) { - gameLocal.Warning( "NULL player takes flag?\n" ); - return false; - } - - Event_TakeFlag( player ); - } - return true; - - case EVENT_DROPFLAG : { - bool death = bool( msg.ReadBits( 1 ) == 1 ); - Event_DropFlag( death ); - } - return true; - - case EVENT_FLAGRETURN : { - Hide(); - - FreeModelDef(); - FreeLightDef(); - - Event_FlagReturn(); - } - return true; - - case EVENT_FLAGCAPTURE : { - Hide(); - - FreeModelDef(); - FreeLightDef(); - - Event_FlagCapture(); - } - return true; - }; - - return false; -} - -/* -================ -idItemTeam::Drop -================ -*/ -void idItemTeam::Drop( bool death ) -{ -// PostEventMS( &EV_DropFlag, 0, int(death == true) ); -// had to remove the delayed drop because of drop flag on disconnect - Event_DropFlag( death ); -} - -/* -================ -idItemTeam::Return -================ -*/ -void idItemTeam::Return( idPlayer * player ) -{ - if ( team != 0 && team != 1 ) - return; - -// PostEventMS( &EV_FlagReturn, 0 ); - Event_FlagReturn(); -} - -/* -================ -idItemTeam::Capture -================ -*/ -void idItemTeam::Capture( void ) -{ - if ( team != 0 && team != 1 ) - return; - - PostEventMS( &EV_FlagCapture, 0 ); -} - -/* -================ -idItemTeam::PrivateReturn -================ -*/ -void idItemTeam::PrivateReturn( void ) -{ - Unbind(); - - if ( gameLocal.isServer && carried && !dropped ) { - int playerIdx = gameLocal.mpGame.GetFlagCarrier( 1-team ); - if ( playerIdx != -1 ) { - idPlayer * player = static_cast( gameLocal.entities[ playerIdx ] ); - player->carryingFlag = false; - } else { - gameLocal.Warning( "BUG: carried flag has no carrier before return" ); - } - } - - dropped = false; - carried = false; - - SetOrigin( returnOrigin ); - SetAxis( returnAxis ); - - trigger->Link( gameLocal.clip, this, 0, GetPhysics()->GetOrigin(), mat3_identity ); - - SetSkin( skinDefault ); - - // Turn off the light - /*itemGlow.shaderParms[ SHADERPARM_RED ] = 0.0f; - itemGlow.shaderParms[ SHADERPARM_GREEN ] = 0.0f; - itemGlow.shaderParms[ SHADERPARM_BLUE ] = 0.0f; - itemGlow.shaderParms[ SHADERPARM_ALPHA ] = 0.0f; - - if ( itemGlowHandle != -1 ) - gameRenderWorld->UpdateLightDef( itemGlowHandle, &itemGlow );*/ - - GetPhysics()->SetLinearVelocity( idVec3(0, 0, 0) ); - GetPhysics()->SetAngularVelocity( idVec3(0, 0, 0) ); -} - -/* -================ -idItemTeam::Event_TakeFlag -================ -*/ -void idItemTeam::Event_TakeFlag( idPlayer * player ) { - gameLocal.DPrintf("Event_TakeFlag()!\n"); - - if ( gameLocal.isServer ) { - idBitMsg msg; - byte msgBuf[MAX_EVENT_PARAM_SIZE]; - // Send the event - msg.Init( msgBuf, sizeof( msgBuf ) ); - msg.BeginWriting(); - msg.WriteBits( player->entityNumber, GENTITYNUM_BITS ); - ServerSendEvent( EVENT_TAKEFLAG, &msg, false, -1 ); - - gameLocal.mpGame.PlayTeamSound( player->team, SND_FLAG_TAKEN_THEIRS ); - gameLocal.mpGame.PlayTeamSound( team, SND_FLAG_TAKEN_YOURS ); - - gameLocal.mpGame.PrintMessageEvent( -1, idMultiplayerGame::MSG_FLAGTAKEN, team, player->entityNumber ); - - // dont drop a nugget RIGHT away - lastNuggetDrop = gameLocal.time - gameLocal.random.RandomInt( 1000 ); - - } - - BindToJoint( player, g_flagAttachJoint.GetString(), true ); - idVec3 origin( g_flagAttachOffsetX.GetFloat(), g_flagAttachOffsetY.GetFloat(), g_flagAttachOffsetZ.GetFloat() ); - idAngles angle( g_flagAttachAngleX.GetFloat(), g_flagAttachAngleY.GetFloat(), g_flagAttachAngleZ.GetFloat() ); - SetAngles( angle ); - SetOrigin( origin ); - - // Turn the light on - /*itemGlow.shaderParms[ SHADERPARM_RED ] = 1.0f; - itemGlow.shaderParms[ SHADERPARM_GREEN ] = 1.0f; - itemGlow.shaderParms[ SHADERPARM_BLUE ] = 1.0f; - itemGlow.shaderParms[ SHADERPARM_ALPHA ] = 1.0f; - - if ( itemGlowHandle != -1 ) - gameRenderWorld->UpdateLightDef( itemGlowHandle, &itemGlow );*/ - - if ( scriptTaken ) { - idThread *thread = new idThread(); - thread->CallFunction( scriptTaken, false ); - thread->DelayedStart( 0 ); - } - - dropped = false; - carried = true; - player->carryingFlag = true; - - SetSkin( skinCarried ); - - UpdateVisuals(); - UpdateGuis(); - - if ( gameLocal.isServer ) { - if ( team == 0 ) - gameLocal.mpGame.player_red_flag = player->entityNumber; - else - gameLocal.mpGame.player_blue_flag = player->entityNumber; - } -} - -/* -================ -idItemTeam::Event_DropFlag -================ -*/ -void idItemTeam::Event_DropFlag( bool death ) { - gameLocal.DPrintf("Event_DropFlag()!\n"); - - if ( gameLocal.isServer ) { - idBitMsg msg; - byte msgBuf[MAX_EVENT_PARAM_SIZE]; - // Send the event - msg.Init( msgBuf, sizeof( msgBuf ) ); - msg.BeginWriting(); - msg.WriteBits( death, 1 ); - ServerSendEvent( EVENT_DROPFLAG, &msg, false, -1 ); - - if ( gameLocal.mpGame.IsFlagMsgOn() ) { - gameLocal.mpGame.PlayTeamSound( 1-team, SND_FLAG_DROPPED_THEIRS ); - gameLocal.mpGame.PlayTeamSound( team, SND_FLAG_DROPPED_YOURS ); - - gameLocal.mpGame.PrintMessageEvent( -1, idMultiplayerGame::MSG_FLAGDROP, team ); - } - } - - lastDrop = gameLocal.time; - - BecomeActive( TH_THINK ); - Show(); - - if ( death ) - GetPhysics()->SetLinearVelocity( idVec3(0, 0, 0) ); - else - GetPhysics()->SetLinearVelocity( idVec3(0, 0, 20) ); - - GetPhysics()->SetAngularVelocity( idVec3(0, 0, 0) ); - -// GetPhysics()->SetLinearVelocity( ( GetPhysics()->GetLinearVelocity() * GetBindMaster()->GetPhysics()->GetAxis() ) + GetBindMaster()->GetPhysics()->GetLinearVelocity() ); - - if ( GetBindMaster() ) { - const idBounds bounds = GetPhysics()->GetBounds(); - idVec3 origin = GetBindMaster()->GetPhysics()->GetOrigin() + idVec3(0, 0, ( bounds[1].z-bounds[0].z )*0.6f ); - - Unbind(); - - SetOrigin( origin ); - } - - idAngles angle = GetPhysics()->GetAxis().ToAngles(); - angle.roll = 0; - angle.pitch = 0; - SetAxis( angle.ToMat3() ); - - dropped = true; - carried = false; - - if ( scriptDropped ) { - idThread *thread = new idThread(); - thread->CallFunction( scriptDropped, false ); - thread->DelayedStart( 0 ); - } - - SetSkin( skinDefault ); - UpdateVisuals(); - UpdateGuis(); - - - if ( gameLocal.isServer ) { - if ( team == 0 ) - gameLocal.mpGame.player_red_flag = -1; - else - gameLocal.mpGame.player_blue_flag = -1; - - } -} - -/* -================ -idItemTeam::Event_FlagReturn -================ -*/ -void idItemTeam::Event_FlagReturn( idPlayer * player ) { - gameLocal.DPrintf("Event_FlagReturn()!\n"); - - if ( gameLocal.isServer ) { - ServerSendEvent( EVENT_FLAGRETURN, NULL, false, -1 ); - - if ( gameLocal.mpGame.IsFlagMsgOn() ) { - gameLocal.mpGame.PlayTeamSound( 1-team, SND_FLAG_RETURN ); - gameLocal.mpGame.PlayTeamSound( team, SND_FLAG_RETURN ); - - int entitynum = 255; - if ( player ) { - entitynum = player->entityNumber; - } - - gameLocal.mpGame.PrintMessageEvent( -1, idMultiplayerGame::MSG_FLAGRETURN, team, entitynum ); - } - } - - BecomeActive( TH_THINK ); - Show(); - - PrivateReturn(); - - if ( scriptReturned ) { - idThread *thread = new idThread(); - thread->CallFunction( scriptReturned, false ); - thread->DelayedStart( 0 ); - } - - UpdateVisuals(); - UpdateGuis(); -// Present(); - - if ( gameLocal.isServer ) { - if ( team == 0 ) - gameLocal.mpGame.player_red_flag = -1; - else - gameLocal.mpGame.player_blue_flag = -1; - } -} - -/* -================ -idItemTeam::Event_FlagCapture -================ -*/ -void idItemTeam::Event_FlagCapture( void ) { - gameLocal.DPrintf("Event_FlagCapture()!\n"); - - if ( gameLocal.isServer ) { - ServerSendEvent( EVENT_FLAGCAPTURE, NULL, false, -1 ); - - gameLocal.mpGame.PlayTeamSound( 1-team, SND_FLAG_CAPTURED_THEIRS ); - gameLocal.mpGame.PlayTeamSound( team, SND_FLAG_CAPTURED_YOURS ); - - gameLocal.mpGame.TeamScoreCTF( 1-team, 1 ); - - int playerIdx = gameLocal.mpGame.GetFlagCarrier( 1-team ); - if ( playerIdx != -1 ) { - gameLocal.mpGame.PlayerScoreCTF( playerIdx, 10 ); - } else { - playerIdx = 255; - } - - gameLocal.mpGame.PrintMessageEvent( -1, idMultiplayerGame::MSG_FLAGCAPTURE, team, playerIdx ); - } - - BecomeActive( TH_THINK ); - Show(); - - PrivateReturn(); - - if ( scriptCaptured ) { - idThread *thread = new idThread(); - thread->CallFunction( scriptCaptured, false ); - thread->DelayedStart( 0 ); - } - - UpdateVisuals(); - UpdateGuis(); - - - if ( gameLocal.isServer ) { - if ( team == 0 ) - gameLocal.mpGame.player_red_flag = -1; - else - gameLocal.mpGame.player_blue_flag = -1; - } - -} - -/* -================ -idItemTeam::FreeLightDef -================ -*/ -void idItemTeam::FreeLightDef( void ) { - if ( itemGlowHandle != -1 ) { - gameRenderWorld->FreeLightDef( itemGlowHandle ); - itemGlowHandle = -1; - } -} - -/* -================ -idItemTeam::SpawnNugget -================ -*/ -void idItemTeam::SpawnNugget( idVec3 pos ) { - - idAngles angle( gameLocal.random.RandomInt(spawnArgs.GetInt("nugget_pitch", "30")), gameLocal.random.RandomInt(spawnArgs.GetInt("nugget_yaw", "360" )), 0 ); - float velocity = float(gameLocal.random.RandomInt( 40 )+15); - - velocity *= spawnArgs.GetFloat("nugget_velocity", "1" ); - - idEntity * ent = idMoveableItem::DropItem( nuggetName, pos, GetPhysics()->GetAxis(), angle.ToMat3()*idVec3(velocity, velocity, velocity), 0, spawnArgs.GetInt("nugget_removedelay") ); - idPhysics_RigidBody * physics = static_cast( ent->GetPhysics() ); - - if ( physics && physics->IsType( idPhysics_RigidBody::Type ) ) { - physics->DisableImpact(); - } -} - - - -/* -================ -idItemTeam::Event_FlagCapture -================ -*/ -void idItemTeam::WriteToSnapshot( idBitMsgDelta &msg ) const { - msg.WriteBits( carried, 1 ); - msg.WriteBits( dropped, 1 ); - - WriteBindToSnapshot( msg ); - - idMoveableItem::WriteToSnapshot( msg ); -} - - -/* -================ -idItemTeam::ReadFromSnapshot -================ -*/ -void idItemTeam::ReadFromSnapshot( const idBitMsgDelta &msg ) { - carried = msg.ReadBits( 1 ) == 1; - dropped = msg.ReadBits( 1 ) == 1; - - ReadBindFromSnapshot( msg ); - - if ( msg.HasChanged() ) - { - UpdateGuis(); - - if ( carried == true ) - SetSkin( skinCarried ); - else - SetSkin( skinDefault ); - } - - idMoveableItem::ReadFromSnapshot( msg ); -} - -/* -================ -idItemTeam::UpdateGuis - -Update all client's huds wrt the flag status. -================ -*/ -void idItemTeam::UpdateGuis( void ) { - idPlayer *player; - - for ( int i = 0; i < gameLocal.numClients; i++ ) { - player = static_cast( gameLocal.entities[ i ] ); - - if ( player == NULL || player->hud == NULL ) - continue; - - player->hud->SetStateInt( "red_flagstatus", gameLocal.mpGame.GetFlagStatus( 0 ) ); - player->hud->SetStateInt( "blue_flagstatus", gameLocal.mpGame.GetFlagStatus( 1 ) ); - - player->hud->SetStateInt( "red_team_score", gameLocal.mpGame.GetFlagPoints( 0 ) ); - player->hud->SetStateInt( "blue_team_score", gameLocal.mpGame.GetFlagPoints( 1 ) ); - - } - -} - -/* -================ -idItemTeam::Present -================ -*/ -void idItemTeam::Present( void ) { - // hide the flag for localplayer if in first person - if ( carried && GetBindMaster() ) { - idPlayer * player = static_cast( GetBindMaster() ); - if ( player == gameLocal.GetLocalPlayer() && !pm_thirdPerson.GetBool() ) { - FreeModelDef(); - BecomeActive( TH_UPDATEVISUALS ); - return; - } - } - - idEntity::Present(); -} - -#endif - -/* -=============================================================================== - - idObjective - -=============================================================================== -*/ - -CLASS_DECLARATION( idItem, idObjective ) - EVENT( EV_Activate, idObjective::Event_Trigger ) - EVENT( EV_HideObjective, idObjective::Event_HideObjective ) - EVENT( EV_GetPlayerPos, idObjective::Event_GetPlayerPos ) - EVENT( EV_CamShot, idObjective::Event_CamShot ) -END_CLASS - -/* -================ -idObjective::idObjective -================ -*/ -idObjective::idObjective() { - playerPos.Zero(); -} - -/* -================ -idObjective::Save -================ -*/ -void idObjective::Save( idSaveGame *savefile ) const { - savefile->WriteVec3( playerPos ); -} - -/* -================ -idObjective::Restore -================ -*/ -void idObjective::Restore( idRestoreGame *savefile ) { - savefile->ReadVec3( playerPos ); -} - -/* -================ -idObjective::Spawn -================ -*/ -void idObjective::Spawn( void ) { - Hide(); - if ( cvarSystem->GetCVarBool( "com_makingBuild") ) { - PostEventMS( &EV_CamShot, 250 ); - } -} - -/* -================ -idObjective::Event_Screenshot -================ -*/ -void idObjective::Event_CamShot( ) { - const char *camName; - idStr shotName = gameLocal.GetMapName(); - shotName.StripFileExtension(); - shotName += "/"; - shotName += spawnArgs.GetString( "screenshot" ); - shotName.SetFileExtension( ".tga" ); - if ( spawnArgs.GetString( "camShot", "", &camName ) ) { - idEntity *ent = gameLocal.FindEntity( camName ); - if ( ent && ent->cameraTarget ) { - const renderView_t *view = ent->cameraTarget->GetRenderView(); - renderView_t fullView = *view; - fullView.width = SCREEN_WIDTH; - fullView.height = SCREEN_HEIGHT; - -#ifdef _D3XP - // HACK : always draw sky-portal view if there is one in the map, this isn't real-time - if ( gameLocal.portalSkyEnt.GetEntity() && g_enablePortalSky.GetBool() ) { - renderView_t portalView = fullView; - portalView.vieworg = gameLocal.portalSkyEnt.GetEntity()->GetPhysics()->GetOrigin(); - - // setup global fixup projection vars - if ( 1 ) { - int vidWidth, vidHeight; - idVec2 shiftScale; - - renderSystem->GetGLSettings( vidWidth, vidHeight ); - - float pot; - int temp; - - int w = vidWidth; - for (temp = 1 ; temp < w ; temp<<=1) { - } - pot = (float)temp; - shiftScale.x = (float)w / pot; - - int h = vidHeight; - for (temp = 1 ; temp < h ; temp<<=1) { - } - pot = (float)temp; - shiftScale.y = (float)h / pot; - - fullView.shaderParms[4] = shiftScale.x; - fullView.shaderParms[5] = shiftScale.y; - } - - gameRenderWorld->RenderScene( &portalView ); - renderSystem->CaptureRenderToImage( "_currentRender" ); - } -#endif - - // draw a view to a texture - renderSystem->CropRenderSize( 256, 256, true ); - gameRenderWorld->RenderScene( &fullView ); - renderSystem->CaptureRenderToFile( shotName ); - renderSystem->UnCrop(); - } - } -} - -/* -================ -idObjective::Event_Trigger -================ -*/ -void idObjective::Event_Trigger( idEntity *activator ) { - idPlayer *player = gameLocal.GetLocalPlayer(); - if ( player ) { - - //Pickup( player ); - - if ( spawnArgs.GetString( "inv_objective", NULL ) ) { - if ( player && player->hud ) { - idStr shotName = gameLocal.GetMapName(); - shotName.StripFileExtension(); - shotName += "/"; - shotName += spawnArgs.GetString( "screenshot" ); - shotName.SetFileExtension( ".tga" ); - player->hud->SetStateString( "screenshot", shotName ); - player->hud->SetStateString( "objective", "1" ); - player->hud->SetStateString( "objectivetext", spawnArgs.GetString( "objectivetext" ) ); - player->hud->SetStateString( "objectivetitle", spawnArgs.GetString( "objectivetitle" ) ); - player->GiveObjective( spawnArgs.GetString( "objectivetitle" ), spawnArgs.GetString( "objectivetext" ), shotName ); - - // a tad slow but keeps from having to update all objectives in all maps with a name ptr - for( int i = 0; i < gameLocal.num_entities; i++ ) { - if ( gameLocal.entities[ i ] && gameLocal.entities[ i ]->IsType( idObjectiveComplete::Type ) ) { - if ( idStr::Icmp( spawnArgs.GetString( "objectivetitle" ), gameLocal.entities[ i ]->spawnArgs.GetString( "objectivetitle" ) ) == 0 ){ - gameLocal.entities[ i ]->spawnArgs.SetBool( "objEnabled", true ); - break; - } - } - } - - PostEventMS( &EV_GetPlayerPos, 2000 ); - } - } - } -} - -/* -================ -idObjective::Event_GetPlayerPos -================ -*/ -void idObjective::Event_GetPlayerPos() { - idPlayer *player = gameLocal.GetLocalPlayer(); - if ( player ) { - playerPos = player->GetPhysics()->GetOrigin(); - PostEventMS( &EV_HideObjective, 100, player ); - } -} - -/* -================ -idObjective::Event_HideObjective -================ -*/ -void idObjective::Event_HideObjective(idEntity *e) { - idPlayer *player = gameLocal.GetLocalPlayer(); - if ( player ) { - idVec3 v = player->GetPhysics()->GetOrigin() - playerPos; - if ( v.Length() > 64.0f ) { - player->HideObjective(); - PostEventMS( &EV_Remove, 0 ); - } else { - PostEventMS( &EV_HideObjective, 100, player ); - } - } -} - -/* -=============================================================================== - - idVideoCDItem - -=============================================================================== -*/ - -CLASS_DECLARATION( idItem, idVideoCDItem ) -END_CLASS - -/* -================ -idVideoCDItem::Spawn -================ -*/ -void idVideoCDItem::Spawn( void ) { -} - -/* -================ -idVideoCDItem::GiveToPlayer -================ -*/ -bool idVideoCDItem::GiveToPlayer( idPlayer *player ) { - idStr str = spawnArgs.GetString( "video" ); - if ( player && str.Length() ) { - player->GiveVideo( str, &spawnArgs ); - } - return true; -} - -/* -=============================================================================== - - idPDAItem - -=============================================================================== -*/ - -CLASS_DECLARATION( idItem, idPDAItem ) -END_CLASS - -/* -================ -idPDAItem::GiveToPlayer -================ -*/ -bool idPDAItem::GiveToPlayer(idPlayer *player) { - const char *str = spawnArgs.GetString( "pda_name" ); - if ( player ) { - player->GivePDA( str, &spawnArgs ); - } - return true; -} - -/* -=============================================================================== - - idMoveableItem - -=============================================================================== -*/ - -CLASS_DECLARATION( idItem, idMoveableItem ) - EVENT( EV_DropToFloor, idMoveableItem::Event_DropToFloor ) - EVENT( EV_Gib, idMoveableItem::Event_Gib ) -END_CLASS - -/* -================ -idMoveableItem::idMoveableItem -================ -*/ -idMoveableItem::idMoveableItem() { - trigger = NULL; - smoke = NULL; - smokeTime = 0; -#ifdef _D3XP - nextSoundTime = 0; -#endif -#ifdef CTF - repeatSmoke = false; -#endif -} - -/* -================ -idMoveableItem::~idMoveableItem -================ -*/ -idMoveableItem::~idMoveableItem() { - if ( trigger ) { - delete trigger; - } -} - -/* -================ -idMoveableItem::Save -================ -*/ -void idMoveableItem::Save( idSaveGame *savefile ) const { - savefile->WriteStaticObject( physicsObj ); - - savefile->WriteClipModel( trigger ); - - savefile->WriteParticle( smoke ); - savefile->WriteInt( smokeTime ); -#ifdef _D3XP - savefile->WriteInt( nextSoundTime ); -#endif -} - -/* -================ -idMoveableItem::Restore -================ -*/ -void idMoveableItem::Restore( idRestoreGame *savefile ) { - savefile->ReadStaticObject( physicsObj ); - RestorePhysics( &physicsObj ); - - savefile->ReadClipModel( trigger ); - - savefile->ReadParticle( smoke ); - savefile->ReadInt( smokeTime ); -#ifdef _D3XP - savefile->ReadInt( nextSoundTime ); -#endif -} - -/* -================ -idMoveableItem::Spawn -================ -*/ -void idMoveableItem::Spawn( void ) { - idTraceModel trm; - float density, friction, bouncyness, tsize; - idStr clipModelName; - idBounds bounds; -#ifdef _D3XP - SetTimeState ts( timeGroup ); -#endif - - // create a trigger for item pickup - spawnArgs.GetFloat( "triggersize", "16.0", tsize ); - trigger = new idClipModel( idTraceModel( idBounds( vec3_origin ).Expand( tsize ) ) ); - trigger->Link( gameLocal.clip, this, 0, GetPhysics()->GetOrigin(), GetPhysics()->GetAxis() ); - trigger->SetContents( CONTENTS_TRIGGER ); - - // check if a clip model is set - spawnArgs.GetString( "clipmodel", "", clipModelName ); - if ( !clipModelName[0] ) { - clipModelName = spawnArgs.GetString( "model" ); // use the visual model - } - - // load the trace model - if ( !collisionModelManager->TrmFromModel( clipModelName, trm ) ) { - gameLocal.Error( "idMoveableItem '%s': cannot load collision model %s", name.c_str(), clipModelName.c_str() ); - return; - } - - // if the model should be shrinked - if ( spawnArgs.GetBool( "clipshrink" ) ) { - trm.Shrink( CM_CLIP_EPSILON ); - } - - // get rigid body properties - spawnArgs.GetFloat( "density", "0.5", density ); - density = idMath::ClampFloat( 0.001f, 1000.0f, density ); - spawnArgs.GetFloat( "friction", "0.05", friction ); - friction = idMath::ClampFloat( 0.0f, 1.0f, friction ); - spawnArgs.GetFloat( "bouncyness", "0.6", bouncyness ); - bouncyness = idMath::ClampFloat( 0.0f, 1.0f, bouncyness ); - - // setup the physics - physicsObj.SetSelf( this ); - physicsObj.SetClipModel( new idClipModel( trm ), density ); - physicsObj.SetOrigin( GetPhysics()->GetOrigin() ); - physicsObj.SetAxis( GetPhysics()->GetAxis() ); - physicsObj.SetBouncyness( bouncyness ); - physicsObj.SetFriction( 0.6f, 0.6f, friction ); - physicsObj.SetGravity( gameLocal.GetGravity() ); - physicsObj.SetContents( CONTENTS_RENDERMODEL ); - physicsObj.SetClipMask( MASK_SOLID | CONTENTS_MOVEABLECLIP ); - SetPhysics( &physicsObj ); - - smoke = NULL; - smokeTime = 0; -#ifdef _D3XP - nextSoundTime = 0; -#endif - const char *smokeName = spawnArgs.GetString( "smoke_trail" ); - if ( *smokeName != '\0' ) { - smoke = static_cast( declManager->FindType( DECL_PARTICLE, smokeName ) ); - smokeTime = gameLocal.time; - BecomeActive( TH_UPDATEPARTICLES ); - } - -#ifdef CTF - repeatSmoke = spawnArgs.GetBool( "repeatSmoke", "0" ); -#endif -} - -/* -================ -idMoveableItem::Think -================ -*/ -void idMoveableItem::Think( void ) { - - RunPhysics(); - - if ( thinkFlags & TH_PHYSICS ) { - // update trigger position - trigger->Link( gameLocal.clip, this, 0, GetPhysics()->GetOrigin(), mat3_identity ); - } - - if ( thinkFlags & TH_UPDATEPARTICLES ) { - if ( !gameLocal.smokeParticles->EmitSmoke( smoke, smokeTime, gameLocal.random.CRandomFloat(), GetPhysics()->GetOrigin(), GetPhysics()->GetAxis(), timeGroup /*_D3XP*/ ) ) { -#ifdef CTF - if ( !repeatSmoke ) { - smokeTime = 0; - BecomeInactive( TH_UPDATEPARTICLES ); - } else { - smokeTime = gameLocal.time; - } -#else - smokeTime = 0; - BecomeInactive( TH_UPDATEPARTICLES ); -#endif - } - } - - Present(); -} - -#ifdef _D3XP -/* -================= -idMoveableItem::Collide -================= -*/ -bool idMoveableItem::Collide( const trace_t &collision, const idVec3 &velocity ) { - float v, f; - - v = -( velocity * collision.c.normal ); - if ( v > 80 && gameLocal.time > nextSoundTime ) { - f = v > 200 ? 1.0f : idMath::Sqrt( v - 80 ) * 0.091f; - if ( StartSound( "snd_bounce", SND_CHANNEL_ANY, 0, false, NULL ) ) { - // don't set the volume unless there is a bounce sound as it overrides the entire channel - // which causes footsteps on ai's to not honor their shader parms - SetSoundVolume( f ); - } - nextSoundTime = gameLocal.time + 500; - } - - return false; -} -#endif - -/* -================ -idMoveableItem::Pickup -================ -*/ -bool idMoveableItem::Pickup( idPlayer *player ) { - bool ret = idItem::Pickup( player ); - if ( ret ) { - trigger->SetContents( 0 ); - } - return ret; -} - -/* -================ -idMoveableItem::DropItem -================ -*/ -idEntity *idMoveableItem::DropItem( const char *classname, const idVec3 &origin, const idMat3 &axis, const idVec3 &velocity, int activateDelay, int removeDelay ) { - idDict args; - idEntity *item; - - args.Set( "classname", classname ); - args.Set( "dropped", "1" ); - - // we sometimes drop idMoveables here, so set 'nodrop' to 1 so that it doesn't get put on the floor - args.Set( "nodrop", "1" ); - - if ( activateDelay ) { - args.SetBool( "triggerFirst", true ); - } - - gameLocal.SpawnEntityDef( args, &item ); - if ( item ) { - // set item position - item->GetPhysics()->SetOrigin( origin ); - item->GetPhysics()->SetAxis( axis ); - item->GetPhysics()->SetLinearVelocity( velocity ); - item->UpdateVisuals(); - if ( activateDelay ) { - item->PostEventMS( &EV_Activate, activateDelay, item ); - } - if ( !removeDelay ) { - removeDelay = 5 * 60 * 1000; - } - // always remove a dropped item after 5 minutes in case it dropped to an unreachable location - item->PostEventMS( &EV_Remove, removeDelay ); - } - return item; -} - -/* -================ -idMoveableItem::DropItems - - The entity should have the following key/value pairs set: - "def_dropItem" "item def" - "dropItemJoint" "joint name" - "dropItemRotation" "pitch yaw roll" - "dropItemOffset" "x y z" - "skin_drop" "skin name" - To drop multiple items the following key/value pairs can be used: - "def_dropItem" "item def" - "dropItemJoint" "joint name" - "dropItemRotation" "pitch yaw roll" - "dropItemOffset" "x y z" - where is an aribtrary string. -================ -*/ -void idMoveableItem::DropItems( idAnimatedEntity *ent, const char *type, idList *list ) { - const idKeyValue *kv; - const char *skinName, *c, *jointName; - idStr key, key2; - idVec3 origin; - idMat3 axis; - idAngles angles; - const idDeclSkin *skin; - jointHandle_t joint; - idEntity *item; - - // drop all items - kv = ent->spawnArgs.MatchPrefix( va( "def_drop%sItem", type ), NULL ); - while ( kv ) { - - c = kv->GetKey().c_str() + kv->GetKey().Length(); - if ( idStr::Icmp( c - 5, "Joint" ) != 0 && idStr::Icmp( c - 8, "Rotation" ) != 0 ) { - - key = kv->GetKey().c_str() + 4; - key2 = key; - key += "Joint"; - key2 += "Offset"; - jointName = ent->spawnArgs.GetString( key ); - joint = ent->GetAnimator()->GetJointHandle( jointName ); - if ( !ent->GetJointWorldTransform( joint, gameLocal.time, origin, axis ) ) { - gameLocal.Warning( "%s refers to invalid joint '%s' on entity '%s'\n", key.c_str(), jointName, ent->name.c_str() ); - origin = ent->GetPhysics()->GetOrigin(); - axis = ent->GetPhysics()->GetAxis(); - } - if ( g_dropItemRotation.GetString()[0] ) { - angles.Zero(); - sscanf( g_dropItemRotation.GetString(), "%f %f %f", &angles.pitch, &angles.yaw, &angles.roll ); - } else { - key = kv->GetKey().c_str() + 4; - key += "Rotation"; - ent->spawnArgs.GetAngles( key, "0 0 0", angles ); - } - axis = angles.ToMat3() * axis; - - origin += ent->spawnArgs.GetVector( key2, "0 0 0" ); - - item = DropItem( kv->GetValue(), origin, axis, vec3_origin, 0, 0 ); - if ( list && item ) { - list->Append( item ); - } - } - - kv = ent->spawnArgs.MatchPrefix( va( "def_drop%sItem", type ), kv ); - } - - // change the skin to hide all items - skinName = ent->spawnArgs.GetString( va( "skin_drop%s", type ) ); - if ( skinName[0] ) { - skin = declManager->FindSkin( skinName ); - ent->SetSkin( skin ); - } -} - -/* -====================== -idMoveableItem::WriteToSnapshot -====================== -*/ -void idMoveableItem::WriteToSnapshot( idBitMsgDelta &msg ) const { - physicsObj.WriteToSnapshot( msg ); -} - -/* -====================== -idMoveableItem::ReadFromSnapshot -====================== -*/ -void idMoveableItem::ReadFromSnapshot( const idBitMsgDelta &msg ) { - physicsObj.ReadFromSnapshot( msg ); - if ( msg.HasChanged() ) { - UpdateVisuals(); - } -} - -/* -============ -idMoveableItem::Gib -============ -*/ -void idMoveableItem::Gib( const idVec3 &dir, const char *damageDefName ) { - // spawn smoke puff - const char *smokeName = spawnArgs.GetString( "smoke_gib" ); - if ( *smokeName != '\0' ) { - const idDeclParticle *smoke = static_cast( declManager->FindType( DECL_PARTICLE, smokeName ) ); - gameLocal.smokeParticles->EmitSmoke( smoke, gameLocal.time, gameLocal.random.CRandomFloat(), renderEntity.origin, renderEntity.axis, timeGroup /*_D3XP*/ ); - } - // remove the entity - PostEventMS( &EV_Remove, 0 ); -} - -/* -================ -idMoveableItem::Event_DropToFloor -================ -*/ -void idMoveableItem::Event_DropToFloor( void ) { - // the physics will drop the moveable to the floor -} - -/* -============ -idMoveableItem::Event_Gib -============ -*/ -void idMoveableItem::Event_Gib( const char *damageDefName ) { - Gib( idVec3( 0, 0, 1 ), damageDefName ); -} - -/* -=============================================================================== - - idMoveablePDAItem - -=============================================================================== -*/ - -CLASS_DECLARATION( idMoveableItem, idMoveablePDAItem ) -END_CLASS - -/* -================ -idMoveablePDAItem::GiveToPlayer -================ -*/ -bool idMoveablePDAItem::GiveToPlayer(idPlayer *player) { - const char *str = spawnArgs.GetString( "pda_name" ); - if ( player ) { - player->GivePDA( str, &spawnArgs ); - } - return true; -} - -/* -=============================================================================== - - idItemRemover - -=============================================================================== -*/ - -CLASS_DECLARATION( idEntity, idItemRemover ) - EVENT( EV_Activate, idItemRemover::Event_Trigger ) -END_CLASS - -/* -================ -idItemRemover::Spawn -================ -*/ -void idItemRemover::Spawn( void ) { -} - -/* -================ -idItemRemover::RemoveItem -================ -*/ -void idItemRemover::RemoveItem( idPlayer *player ) { - const char *remove; - - remove = spawnArgs.GetString( "remove" ); - player->RemoveInventoryItem( remove ); -} - -/* -================ -idItemRemover::Event_Trigger -================ -*/ -void idItemRemover::Event_Trigger( idEntity *activator ) { - if ( activator->IsType( idPlayer::Type ) ) { - RemoveItem( static_cast(activator) ); - } -} - -/* -=============================================================================== - - idObjectiveComplete - -=============================================================================== -*/ - -CLASS_DECLARATION( idItemRemover, idObjectiveComplete ) - EVENT( EV_Activate, idObjectiveComplete::Event_Trigger ) - EVENT( EV_HideObjective, idObjectiveComplete::Event_HideObjective ) - EVENT( EV_GetPlayerPos, idObjectiveComplete::Event_GetPlayerPos ) -END_CLASS - -/* -================ -idObjectiveComplete::idObjectiveComplete -================ -*/ -idObjectiveComplete::idObjectiveComplete() { - playerPos.Zero(); -} - -/* -================ -idObjectiveComplete::Save -================ -*/ -void idObjectiveComplete::Save( idSaveGame *savefile ) const { - savefile->WriteVec3( playerPos ); -} - -/* -================ -idObjectiveComplete::Restore -================ -*/ -void idObjectiveComplete::Restore( idRestoreGame *savefile ) { - savefile->ReadVec3( playerPos ); -} - -/* -================ -idObjectiveComplete::Spawn -================ -*/ -void idObjectiveComplete::Spawn( void ) { - spawnArgs.SetBool( "objEnabled", false ); - Hide(); -} - -/* -================ -idObjectiveComplete::Event_Trigger -================ -*/ -void idObjectiveComplete::Event_Trigger( idEntity *activator ) { - if ( !spawnArgs.GetBool( "objEnabled" ) ) { - return; - } - idPlayer *player = gameLocal.GetLocalPlayer(); - if ( player ) { - RemoveItem( player ); - - if ( spawnArgs.GetString( "inv_objective", NULL ) ) { - if ( player->hud ) { - player->hud->SetStateString( "objective", "2"); - - player->hud->SetStateString( "objectivetext", spawnArgs.GetString( "objectivetext" ) ); -#ifdef _D3XP - player->hud->SetStateString( "objectivecompletetitle", spawnArgs.GetString( "objectivetitle" ) ); -#else - player->hud->SetStateString( "objectivetitle", spawnArgs.GetString( "objectivetitle" ) ); -#endif - player->CompleteObjective( spawnArgs.GetString( "objectivetitle" ) ); - PostEventMS( &EV_GetPlayerPos, 2000 ); - } - } - } -} - -/* -================ -idObjectiveComplete::Event_GetPlayerPos -================ -*/ -void idObjectiveComplete::Event_GetPlayerPos() { - idPlayer *player = gameLocal.GetLocalPlayer(); - if ( player ) { - playerPos = player->GetPhysics()->GetOrigin(); - PostEventMS( &EV_HideObjective, 100, player ); - } -} - -/* -================ -idObjectiveComplete::Event_HideObjective -================ -*/ -void idObjectiveComplete::Event_HideObjective( idEntity *e ) { - idPlayer *player = gameLocal.GetLocalPlayer(); - if ( player ) { - idVec3 v = player->GetPhysics()->GetOrigin(); - v -= playerPos; - if ( v.Length() > 64.0f ) { - player->hud->HandleNamedEvent( "closeObjective" ); - PostEventMS( &EV_Remove, 0 ); - } else { - PostEventMS( &EV_HideObjective, 100, player ); - } - } -} diff --git a/d3xp/Item.h b/d3xp/Item.h deleted file mode 100644 index d02b7b26..00000000 --- a/d3xp/Item.h +++ /dev/null @@ -1,316 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __GAME_ITEM_H__ -#define __GAME_ITEM_H__ - -#include "physics/Physics_RigidBody.h" -#include "Entity.h" - -/* -=============================================================================== - - Items the player can pick up or use. - -=============================================================================== -*/ - -class idItem : public idEntity { -public: - CLASS_PROTOTYPE( idItem ); - - idItem(); - virtual ~idItem(); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void Spawn( void ); - void GetAttributes( idDict &attributes ); - virtual bool GiveToPlayer( idPlayer *player ); - virtual bool Pickup( idPlayer *player ); - virtual void Think( void ); - virtual void Present(); - - enum { - EVENT_PICKUP = idEntity::EVENT_MAXEVENTS, - EVENT_RESPAWN, - EVENT_RESPAWNFX, -#ifdef CTF - EVENT_TAKEFLAG, - EVENT_DROPFLAG, - EVENT_FLAGRETURN, - EVENT_FLAGCAPTURE, -#endif - EVENT_MAXEVENTS - }; - - virtual void ClientPredictionThink( void ); - virtual bool ClientReceiveEvent( int event, int time, const idBitMsg &msg ); - - // networking - virtual void WriteToSnapshot( idBitMsgDelta &msg ) const; - virtual void ReadFromSnapshot( const idBitMsgDelta &msg ); - -private: - idVec3 orgOrigin; - bool spin; - bool pulse; - bool canPickUp; - - // for item pulse effect - int itemShellHandle; - const idMaterial * shellMaterial; - - // used to update the item pulse effect - mutable bool inView; - mutable int inViewTime; - mutable int lastCycle; - mutable int lastRenderViewTime; - - bool UpdateRenderEntity( renderEntity_s *renderEntity, const renderView_t *renderView ) const; - static bool ModelCallback( renderEntity_s *renderEntity, const renderView_t *renderView ); - - void Event_DropToFloor( void ); - void Event_Touch( idEntity *other, trace_t *trace ); - void Event_Trigger( idEntity *activator ); - void Event_Respawn( void ); - void Event_RespawnFx( void ); -}; - -class idItemPowerup : public idItem { -public: - CLASS_PROTOTYPE( idItemPowerup ); - - idItemPowerup(); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void Spawn(); - virtual bool GiveToPlayer( idPlayer *player ); - -private: - int time; - int type; -}; - -class idObjective : public idItem { -public: - CLASS_PROTOTYPE( idObjective ); - - idObjective(); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void Spawn(); - -private: - idVec3 playerPos; - - void Event_Trigger( idEntity *activator ); - void Event_HideObjective( idEntity *e ); - void Event_GetPlayerPos(); - void Event_CamShot(); -}; - -class idVideoCDItem : public idItem { -public: - CLASS_PROTOTYPE( idVideoCDItem ); - - void Spawn(); - virtual bool GiveToPlayer( idPlayer *player ); -}; - -class idPDAItem : public idItem { -public: - CLASS_PROTOTYPE( idPDAItem ); - - virtual bool GiveToPlayer( idPlayer *player ); -}; - -class idMoveableItem : public idItem { -public: - CLASS_PROTOTYPE( idMoveableItem ); - - idMoveableItem(); - virtual ~idMoveableItem(); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void Spawn( void ); - virtual void Think( void ); -#ifdef _D3XP - virtual bool Collide( const trace_t &collision, const idVec3 &velocity ); -#endif - virtual bool Pickup( idPlayer *player ); - - static void DropItems( idAnimatedEntity *ent, const char *type, idList *list ); - static idEntity * DropItem( const char *classname, const idVec3 &origin, const idMat3 &axis, const idVec3 &velocity, int activateDelay, int removeDelay ); - - virtual void WriteToSnapshot( idBitMsgDelta &msg ) const; - virtual void ReadFromSnapshot( const idBitMsgDelta &msg ); - -#ifdef CTF -protected: -#else -private: -#endif - idPhysics_RigidBody physicsObj; - idClipModel * trigger; - const idDeclParticle * smoke; - int smokeTime; - -#ifdef _D3XP - int nextSoundTime; -#endif -#ifdef CTF - bool repeatSmoke; // never stop updating the particles -#endif - - void Gib( const idVec3 &dir, const char *damageDefName ); - - void Event_DropToFloor( void ); - void Event_Gib( const char *damageDefName ); -}; - -#ifdef CTF - -class idItemTeam : public idMoveableItem { -public: - CLASS_PROTOTYPE( idItemTeam ); - - idItemTeam(); - virtual ~idItemTeam(); - - void Spawn(); - virtual bool Pickup( idPlayer *player ); - virtual bool ClientReceiveEvent( int event, int time, const idBitMsg &msg ); - virtual void Think(void ); - - void Drop( bool death = false ); // was the drop caused by death of carrier? - void Return( idPlayer * player = NULL ); - void Capture( void ); - - virtual void FreeLightDef( void ); - virtual void Present( void ); - - // networking - virtual void WriteToSnapshot( idBitMsgDelta &msg ) const; - virtual void ReadFromSnapshot( const idBitMsgDelta &msg ); - -public: - int team; - // TODO : turn this into a state : - bool carried; // is it beeing carried by a player? - bool dropped; // was it dropped? - -private: - idVec3 returnOrigin; - idMat3 returnAxis; - int lastDrop; - - const idDeclSkin * skinDefault; - const idDeclSkin * skinCarried; - - const function_t * scriptTaken; - const function_t * scriptDropped; - const function_t * scriptReturned; - const function_t * scriptCaptured; - - renderLight_t itemGlow; // Used by flags when they are picked up - int itemGlowHandle; - - int lastNuggetDrop; - const char * nuggetName; - -private: - - void Event_TakeFlag( idPlayer * player ); - void Event_DropFlag( bool death ); - void Event_FlagReturn( idPlayer * player = NULL ); - void Event_FlagCapture( void ); - - void PrivateReturn( void ); - function_t * LoadScript( const char * script ); - - void SpawnNugget( idVec3 pos ); - void UpdateGuis( void ); -}; - -#endif - - -class idMoveablePDAItem : public idMoveableItem { -public: - CLASS_PROTOTYPE( idMoveablePDAItem ); - - virtual bool GiveToPlayer( idPlayer *player ); -}; - -/* -=============================================================================== - - Item removers. - -=============================================================================== -*/ - -class idItemRemover : public idEntity { -public: - CLASS_PROTOTYPE( idItemRemover ); - - void Spawn(); - void RemoveItem( idPlayer *player ); - -private: - void Event_Trigger( idEntity *activator ); -}; - -class idObjectiveComplete : public idItemRemover { -public: - CLASS_PROTOTYPE( idObjectiveComplete ); - - idObjectiveComplete(); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void Spawn(); - -private: - idVec3 playerPos; - - void Event_Trigger( idEntity *activator ); - void Event_HideObjective( idEntity *e ); - void Event_GetPlayerPos(); -}; - -#endif /* !__GAME_ITEM_H__ */ diff --git a/d3xp/Light.cpp b/d3xp/Light.cpp deleted file mode 100644 index 8db6eb3d..00000000 --- a/d3xp/Light.cpp +++ /dev/null @@ -1,1165 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "renderer/ModelManager.h" - -#include "gamesys/SysCvar.h" -#include "script/Script_Thread.h" - -#include "Light.h" - -/* -=============================================================================== - - idLight - -=============================================================================== -*/ - -const idEventDef EV_Light_SetShader( "setShader", "s" ); -const idEventDef EV_Light_GetLightParm( "getLightParm", "d", 'f' ); -const idEventDef EV_Light_SetLightParm( "setLightParm", "df" ); -const idEventDef EV_Light_SetLightParms( "setLightParms", "ffff" ); -const idEventDef EV_Light_SetRadiusXYZ( "setRadiusXYZ", "fff" ); -const idEventDef EV_Light_SetRadius( "setRadius", "f" ); -const idEventDef EV_Light_On( "On", NULL ); -const idEventDef EV_Light_Off( "Off", NULL ); -const idEventDef EV_Light_FadeOut( "fadeOutLight", "f" ); -const idEventDef EV_Light_FadeIn( "fadeInLight", "f" ); - -CLASS_DECLARATION( idEntity, idLight ) - EVENT( EV_Light_SetShader, idLight::Event_SetShader ) - EVENT( EV_Light_GetLightParm, idLight::Event_GetLightParm ) - EVENT( EV_Light_SetLightParm, idLight::Event_SetLightParm ) - EVENT( EV_Light_SetLightParms, idLight::Event_SetLightParms ) - EVENT( EV_Light_SetRadiusXYZ, idLight::Event_SetRadiusXYZ ) - EVENT( EV_Light_SetRadius, idLight::Event_SetRadius ) - EVENT( EV_Hide, idLight::Event_Hide ) - EVENT( EV_Show, idLight::Event_Show ) - EVENT( EV_Light_On, idLight::Event_On ) - EVENT( EV_Light_Off, idLight::Event_Off ) - EVENT( EV_Activate, idLight::Event_ToggleOnOff ) - EVENT( EV_PostSpawn, idLight::Event_SetSoundHandles ) - EVENT( EV_Light_FadeOut, idLight::Event_FadeOut ) - EVENT( EV_Light_FadeIn, idLight::Event_FadeIn ) -END_CLASS - - -/* -================ -idGameEdit::ParseSpawnArgsToRenderLight - -parse the light parameters -this is the canonical renderLight parm parsing, -which should be used by dmap and the editor -================ -*/ -void idGameEdit::ParseSpawnArgsToRenderLight( const idDict *args, renderLight_t *renderLight ) { - bool gotTarget, gotUp, gotRight; - const char *texture; - idVec3 color; - - memset( renderLight, 0, sizeof( *renderLight ) ); - - if (!args->GetVector("light_origin", "", renderLight->origin)) { - args->GetVector( "origin", "", renderLight->origin ); - } - - gotTarget = args->GetVector( "light_target", "", renderLight->target ); - gotUp = args->GetVector( "light_up", "", renderLight->up ); - gotRight = args->GetVector( "light_right", "", renderLight->right ); - args->GetVector( "light_start", "0 0 0", renderLight->start ); - if ( !args->GetVector( "light_end", "", renderLight->end ) ) { - renderLight->end = renderLight->target; - } - - // we should have all of the target/right/up or none of them - if ( ( gotTarget || gotUp || gotRight ) != ( gotTarget && gotUp && gotRight ) ) { - gameLocal.Printf( "Light at (%f,%f,%f) has bad target info\n", - renderLight->origin[0], renderLight->origin[1], renderLight->origin[2] ); - return; - } - - if ( !gotTarget ) { - renderLight->pointLight = true; - - // allow an optional relative center of light and shadow offset - args->GetVector( "light_center", "0 0 0", renderLight->lightCenter ); - - // create a point light - if (!args->GetVector( "light_radius", "300 300 300", renderLight->lightRadius ) ) { - float radius; - - args->GetFloat( "light", "300", radius ); - renderLight->lightRadius[0] = renderLight->lightRadius[1] = renderLight->lightRadius[2] = radius; - } - } - - // get the rotation matrix in either full form, or single angle form - idAngles angles; - idMat3 mat; - if ( !args->GetMatrix( "light_rotation", "1 0 0 0 1 0 0 0 1", mat ) ) { - if ( !args->GetMatrix( "rotation", "1 0 0 0 1 0 0 0 1", mat ) ) { - args->GetFloat( "angle", "0", angles[ 1 ] ); - angles[ 0 ] = 0; - angles[ 1 ] = idMath::AngleNormalize360( angles[ 1 ] ); - angles[ 2 ] = 0; - mat = angles.ToMat3(); - } - } - - // fix degenerate identity matrices - mat[0].FixDegenerateNormal(); - mat[1].FixDegenerateNormal(); - mat[2].FixDegenerateNormal(); - - renderLight->axis = mat; - - // check for other attributes - args->GetVector( "_color", "1 1 1", color ); - renderLight->shaderParms[ SHADERPARM_RED ] = color[0]; - renderLight->shaderParms[ SHADERPARM_GREEN ] = color[1]; - renderLight->shaderParms[ SHADERPARM_BLUE ] = color[2]; - args->GetFloat( "shaderParm3", "1", renderLight->shaderParms[ SHADERPARM_TIMESCALE ] ); - if ( !args->GetFloat( "shaderParm4", "0", renderLight->shaderParms[ SHADERPARM_TIMEOFFSET ] ) ) { - // offset the start time of the shader to sync it to the game time - renderLight->shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time ); - } - - args->GetFloat( "shaderParm5", "0", renderLight->shaderParms[5] ); - args->GetFloat( "shaderParm6", "0", renderLight->shaderParms[6] ); - args->GetFloat( "shaderParm7", "0", renderLight->shaderParms[ SHADERPARM_MODE ] ); - args->GetBool( "noshadows", "0", renderLight->noShadows ); - args->GetBool( "nospecular", "0", renderLight->noSpecular ); - args->GetBool( "parallel", "0", renderLight->parallel ); - - args->GetString( "texture", "lights/squarelight1", &texture ); - // allow this to be NULL - renderLight->shader = declManager->FindMaterial( texture, false ); -} - -/* -================ -idLight::UpdateChangeableSpawnArgs -================ -*/ -void idLight::UpdateChangeableSpawnArgs( const idDict *source ) { - - idEntity::UpdateChangeableSpawnArgs( source ); - - if ( source ) { - source->Print(); - } - FreeSoundEmitter( true ); - gameEdit->ParseSpawnArgsToRefSound( source ? source : &spawnArgs, &refSound ); - if ( refSound.shader && !refSound.waitfortrigger ) { - StartSoundShader( refSound.shader, SND_CHANNEL_ANY, 0, false, NULL ); - } - - gameEdit->ParseSpawnArgsToRenderLight( source ? source : &spawnArgs, &renderLight ); - - UpdateVisuals(); -} - -/* -================ -idLight::idLight -================ -*/ -idLight::idLight() { - memset( &renderLight, 0, sizeof( renderLight ) ); - localLightOrigin = vec3_zero; - localLightAxis = mat3_identity; - lightDefHandle = -1; - levels = 0; - currentLevel = 0; - baseColor = vec3_zero; - breakOnTrigger = false; - count = 0; - triggercount = 0; - lightParent = NULL; - fadeFrom.Set( 1, 1, 1, 1 ); - fadeTo.Set( 1, 1, 1, 1 ); - fadeStart = 0; - fadeEnd = 0; - soundWasPlaying = false; -} - -/* -================ -idLight::~idLight -================ -*/ -idLight::~idLight() { - if ( lightDefHandle != -1 ) { - gameRenderWorld->FreeLightDef( lightDefHandle ); - } -} - -/* -================ -idLight::Save - -archives object for save game file -================ -*/ -void idLight::Save( idSaveGame *savefile ) const { - savefile->WriteRenderLight( renderLight ); - - savefile->WriteBool( renderLight.prelightModel != NULL ); - - savefile->WriteVec3( localLightOrigin ); - savefile->WriteMat3( localLightAxis ); - - savefile->WriteString( brokenModel ); - savefile->WriteInt( levels ); - savefile->WriteInt( currentLevel ); - - savefile->WriteVec3( baseColor ); - savefile->WriteBool( breakOnTrigger ); - savefile->WriteInt( count ); - savefile->WriteInt( triggercount ); - savefile->WriteObject( lightParent ); - - savefile->WriteVec4( fadeFrom ); - savefile->WriteVec4( fadeTo ); - savefile->WriteInt( fadeStart ); - savefile->WriteInt( fadeEnd ); - savefile->WriteBool( soundWasPlaying ); -} - -/* -================ -idLight::Restore - -unarchives object from save game file -================ -*/ -void idLight::Restore( idRestoreGame *savefile ) { - bool hadPrelightModel; - - savefile->ReadRenderLight( renderLight ); - - savefile->ReadBool( hadPrelightModel ); - renderLight.prelightModel = renderModelManager->CheckModel( va( "_prelight_%s", name.c_str() ) ); - if ( ( renderLight.prelightModel == NULL ) && hadPrelightModel ) { - assert( 0 ); - if ( developer.GetBool() ) { - // we really want to know if this happens - gameLocal.Error( "idLight::Restore: prelightModel '_prelight_%s' not found", name.c_str() ); - } else { - // but let it slide after release - gameLocal.Warning( "idLight::Restore: prelightModel '_prelight_%s' not found", name.c_str() ); - } - } - - savefile->ReadVec3( localLightOrigin ); - savefile->ReadMat3( localLightAxis ); - - savefile->ReadString( brokenModel ); - savefile->ReadInt( levels ); - savefile->ReadInt( currentLevel ); - - savefile->ReadVec3( baseColor ); - savefile->ReadBool( breakOnTrigger ); - savefile->ReadInt( count ); - savefile->ReadInt( triggercount ); - savefile->ReadObject( reinterpret_cast( lightParent ) ); - - savefile->ReadVec4( fadeFrom ); - savefile->ReadVec4( fadeTo ); - savefile->ReadInt( fadeStart ); - savefile->ReadInt( fadeEnd ); - savefile->ReadBool( soundWasPlaying ); - - lightDefHandle = -1; - - SetLightLevel(); -} - -/* -================ -idLight::Spawn -================ -*/ -void idLight::Spawn( void ) { - bool start_off; - bool needBroken; - const char *demonic_shader; - - // do the parsing the same way dmap and the editor do - gameEdit->ParseSpawnArgsToRenderLight( &spawnArgs, &renderLight ); - - // we need the origin and axis relative to the physics origin/axis - localLightOrigin = ( renderLight.origin - GetPhysics()->GetOrigin() ) * GetPhysics()->GetAxis().Transpose(); - localLightAxis = renderLight.axis * GetPhysics()->GetAxis().Transpose(); - - // set the base color from the shader parms - baseColor.Set( renderLight.shaderParms[ SHADERPARM_RED ], renderLight.shaderParms[ SHADERPARM_GREEN ], renderLight.shaderParms[ SHADERPARM_BLUE ] ); - - // set the number of light levels - spawnArgs.GetInt( "levels", "1", levels ); - currentLevel = levels; - if ( levels <= 0 ) { - gameLocal.Error( "Invalid light level set on entity #%d(%s)", entityNumber, name.c_str() ); - } - - // make sure the demonic shader is cached - if ( spawnArgs.GetString( "mat_demonic", NULL, &demonic_shader ) ) { - declManager->FindType( DECL_MATERIAL, demonic_shader ); - } - - // game specific functionality, not mirrored in - // editor or dmap light parsing - - // also put the light texture on the model, so light flares - // can get the current intensity of the light - renderEntity.referenceShader = renderLight.shader; - - lightDefHandle = -1; // no static version yet - - // see if an optimized shadow volume exists - // the renderer will ignore this value after a light has been moved, - // but there may still be a chance to get it wrong if the game moves - // a light before the first present, and doesn't clear the prelight - renderLight.prelightModel = 0; - if ( name[ 0 ] ) { - // this will return 0 if not found - renderLight.prelightModel = renderModelManager->CheckModel( va( "_prelight_%s", name.c_str() ) ); - } - - spawnArgs.GetBool( "start_off", "0", start_off ); - if ( start_off ) { - Off(); - } - -#ifdef CTF - // Midnight CTF - if ( gameLocal.mpGame.IsGametypeFlagBased() && gameLocal.serverInfo.GetBool("si_midnight") && !spawnArgs.GetBool("midnight_override") ) { - Off(); - } -#endif - - health = spawnArgs.GetInt( "health", "0" ); - spawnArgs.GetString( "broken", "", brokenModel ); - spawnArgs.GetBool( "break", "0", breakOnTrigger ); - spawnArgs.GetInt( "count", "1", count ); - - triggercount = 0; - - fadeFrom.Set( 1, 1, 1, 1 ); - fadeTo.Set( 1, 1, 1, 1 ); - fadeStart = 0; - fadeEnd = 0; - - // if we have a health make light breakable - if ( health ) { - idStr model = spawnArgs.GetString( "model" ); // get the visual model - if ( !model.Length() ) { - gameLocal.Error( "Breakable light without a model set on entity #%d(%s)", entityNumber, name.c_str() ); - } - - fl.takedamage = true; - - // see if we need to create a broken model name - needBroken = true; - if ( model.Length() && !brokenModel.Length() ) { - int pos; - - needBroken = false; - - pos = model.Find( "." ); - if ( pos < 0 ) { - pos = model.Length(); - } - if ( pos > 0 ) { - model.Left( pos, brokenModel ); - } - brokenModel += "_broken"; - if ( pos > 0 ) { - brokenModel += &model[ pos ]; - } - } - - // make sure the model gets cached - if ( !renderModelManager->CheckModel( brokenModel ) ) { - if ( needBroken ) { - gameLocal.Error( "Model '%s' not found for entity %d(%s)", brokenModel.c_str(), entityNumber, name.c_str() ); - } else { - brokenModel = ""; - } - } - - GetPhysics()->SetContents( spawnArgs.GetBool( "nonsolid" ) ? 0 : CONTENTS_SOLID ); - - // make sure the collision model gets cached - idClipModel::CheckModel( brokenModel ); - } - - PostEventMS( &EV_PostSpawn, 0 ); - - UpdateVisuals(); -} - -/* -================ -idLight::SetLightLevel -================ -*/ -void idLight::SetLightLevel( void ) { - idVec3 color; - float intensity; - - intensity = ( float )currentLevel / ( float )levels; - color = baseColor * intensity; - renderLight.shaderParms[ SHADERPARM_RED ] = color[ 0 ]; - renderLight.shaderParms[ SHADERPARM_GREEN ] = color[ 1 ]; - renderLight.shaderParms[ SHADERPARM_BLUE ] = color[ 2 ]; - renderEntity.shaderParms[ SHADERPARM_RED ] = color[ 0 ]; - renderEntity.shaderParms[ SHADERPARM_GREEN ]= color[ 1 ]; - renderEntity.shaderParms[ SHADERPARM_BLUE ] = color[ 2 ]; - PresentLightDefChange(); - PresentModelDefChange(); -} - -/* -================ -idLight::GetColor -================ -*/ -void idLight::GetColor( idVec3 &out ) const { - out[ 0 ] = renderLight.shaderParms[ SHADERPARM_RED ]; - out[ 1 ] = renderLight.shaderParms[ SHADERPARM_GREEN ]; - out[ 2 ] = renderLight.shaderParms[ SHADERPARM_BLUE ]; -} - -/* -================ -idLight::GetColor -================ -*/ -void idLight::GetColor( idVec4 &out ) const { - out[ 0 ] = renderLight.shaderParms[ SHADERPARM_RED ]; - out[ 1 ] = renderLight.shaderParms[ SHADERPARM_GREEN ]; - out[ 2 ] = renderLight.shaderParms[ SHADERPARM_BLUE ]; - out[ 3 ] = renderLight.shaderParms[ SHADERPARM_ALPHA ]; -} - -/* -================ -idLight::SetColor -================ -*/ -void idLight::SetColor( float red, float green, float blue ) { - baseColor.Set( red, green, blue ); - SetLightLevel(); -} - -/* -================ -idLight::SetColor -================ -*/ -void idLight::SetColor( const idVec3 &color ) { - baseColor = color; - SetLightLevel(); -} - -/* -================ -idLight::SetColor -================ -*/ -void idLight::SetColor( const idVec4 &color ) { - baseColor = color.ToVec3(); - renderLight.shaderParms[ SHADERPARM_ALPHA ] = color[ 3 ]; - renderEntity.shaderParms[ SHADERPARM_ALPHA ] = color[ 3 ]; - SetLightLevel(); -} - -/* -================ -idLight::SetShader -================ -*/ -void idLight::SetShader( const char *shadername ) { - // allow this to be NULL - renderLight.shader = declManager->FindMaterial( shadername, false ); - PresentLightDefChange(); -} - -/* -================ -idLight::SetLightParm -================ -*/ -void idLight::SetLightParm( int parmnum, float value ) { - if ( ( parmnum < 0 ) || ( parmnum >= MAX_ENTITY_SHADER_PARMS ) ) { - gameLocal.Error( "shader parm index (%d) out of range", parmnum ); - } - - renderLight.shaderParms[ parmnum ] = value; - PresentLightDefChange(); -} - -/* -================ -idLight::SetLightParms -================ -*/ -void idLight::SetLightParms( float parm0, float parm1, float parm2, float parm3 ) { - renderLight.shaderParms[ SHADERPARM_RED ] = parm0; - renderLight.shaderParms[ SHADERPARM_GREEN ] = parm1; - renderLight.shaderParms[ SHADERPARM_BLUE ] = parm2; - renderLight.shaderParms[ SHADERPARM_ALPHA ] = parm3; - renderEntity.shaderParms[ SHADERPARM_RED ] = parm0; - renderEntity.shaderParms[ SHADERPARM_GREEN ] = parm1; - renderEntity.shaderParms[ SHADERPARM_BLUE ] = parm2; - renderEntity.shaderParms[ SHADERPARM_ALPHA ] = parm3; - PresentLightDefChange(); - PresentModelDefChange(); -} - -/* -================ -idLight::SetRadiusXYZ -================ -*/ -void idLight::SetRadiusXYZ( float x, float y, float z ) { - renderLight.lightRadius[0] = x; - renderLight.lightRadius[1] = y; - renderLight.lightRadius[2] = z; - PresentLightDefChange(); -} - -/* -================ -idLight::SetRadius -================ -*/ -void idLight::SetRadius( float radius ) { - renderLight.lightRadius[0] = renderLight.lightRadius[1] = renderLight.lightRadius[2] = radius; - PresentLightDefChange(); -} - -/* -================ -idLight::On -================ -*/ -void idLight::On( void ) { - currentLevel = levels; - // offset the start time of the shader to sync it to the game time - renderLight.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time ); - if ( ( soundWasPlaying || refSound.waitfortrigger ) && refSound.shader ) { - StartSoundShader( refSound.shader, SND_CHANNEL_ANY, 0, false, NULL ); - soundWasPlaying = false; - } - SetLightLevel(); - BecomeActive( TH_UPDATEVISUALS ); -} - -/* -================ -idLight::Off -================ -*/ -void idLight::Off( void ) { - currentLevel = 0; - // kill any sound it was making - if ( refSound.referenceSound && refSound.referenceSound->CurrentlyPlaying() ) { - StopSound( SND_CHANNEL_ANY, false ); - soundWasPlaying = true; - } - SetLightLevel(); - BecomeActive( TH_UPDATEVISUALS ); -} - -/* -================ -idLight::Fade -================ -*/ -void idLight::Fade( const idVec4 &to, float fadeTime ) { - GetColor( fadeFrom ); - fadeTo = to; - fadeStart = gameLocal.time; - fadeEnd = gameLocal.time + SEC2MS( fadeTime ); - BecomeActive( TH_THINK ); -} - -/* -================ -idLight::FadeOut -================ -*/ -void idLight::FadeOut( float time ) { - Fade( colorBlack, time ); -} - -/* -================ -idLight::FadeIn -================ -*/ -void idLight::FadeIn( float time ) { - idVec3 color; - idVec4 color4; - - currentLevel = levels; - spawnArgs.GetVector( "_color", "1 1 1", color ); - color4.Set( color.x, color.y, color.z, 1.0f ); - Fade( color4, time ); -} - -/* -================ -idLight::Killed -================ -*/ -void idLight::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) { - BecomeBroken( attacker ); -} - -/* -================ -idLight::BecomeBroken -================ -*/ -void idLight::BecomeBroken( idEntity *activator ) { - const char *damageDefName; - - fl.takedamage = false; - - if ( brokenModel.Length() ) { - SetModel( brokenModel ); - - if ( !spawnArgs.GetBool( "nonsolid" ) ) { - GetPhysics()->SetClipModel( new idClipModel( brokenModel.c_str() ), 1.0f ); - GetPhysics()->SetContents( CONTENTS_SOLID ); - } - } else if ( spawnArgs.GetBool( "hideModelOnBreak" ) ) { - SetModel( "" ); - GetPhysics()->SetContents( 0 ); - } - - if ( gameLocal.isServer ) { - - ServerSendEvent( EVENT_BECOMEBROKEN, NULL, true, -1 ); - - if ( spawnArgs.GetString( "def_damage", "", &damageDefName ) ) { - idVec3 origin = renderEntity.origin + renderEntity.bounds.GetCenter() * renderEntity.axis; - gameLocal.RadiusDamage( origin, activator, activator, this, this, damageDefName ); - } - - } - - ActivateTargets( activator ); - - // offset the start time of the shader to sync it to the game time - renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time ); - renderLight.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time ); - - // set the state parm - renderEntity.shaderParms[ SHADERPARM_MODE ] = 1; - renderLight.shaderParms[ SHADERPARM_MODE ] = 1; - - // if the light has a sound, either start the alternate (broken) sound, or stop the sound - const char *parm = spawnArgs.GetString( "snd_broken" ); - if ( refSound.shader || ( parm && *parm ) ) { - StopSound( SND_CHANNEL_ANY, false ); - const idSoundShader *alternate = refSound.shader ? refSound.shader->GetAltSound() : declManager->FindSound( parm ); - if ( alternate ) { - // start it with no diversity, so the leadin break sound plays - refSound.referenceSound->StartSound( alternate, SND_CHANNEL_ANY, 0.0, 0 ); - } - } - - parm = spawnArgs.GetString( "mtr_broken" ); - if ( parm && *parm ) { - SetShader( parm ); - } - - UpdateVisuals(); -} - -/* -================ -idLight::PresentLightDefChange -================ -*/ -void idLight::PresentLightDefChange( void ) { - // let the renderer apply it to the world - if ( ( lightDefHandle != -1 ) ) { - gameRenderWorld->UpdateLightDef( lightDefHandle, &renderLight ); - } else { - lightDefHandle = gameRenderWorld->AddLightDef( &renderLight ); - } -} - -/* -================ -idLight::PresentModelDefChange -================ -*/ -void idLight::PresentModelDefChange( void ) { - - if ( !renderEntity.hModel || IsHidden() ) { - return; - } - - // add to refresh list - if ( modelDefHandle == -1 ) { - modelDefHandle = gameRenderWorld->AddEntityDef( &renderEntity ); - } else { - gameRenderWorld->UpdateEntityDef( modelDefHandle, &renderEntity ); - } -} - -/* -================ -idLight::Present -================ -*/ -void idLight::Present( void ) { - // don't present to the renderer if the entity hasn't changed - if ( !( thinkFlags & TH_UPDATEVISUALS ) ) { - return; - } - - // add the model - idEntity::Present(); - - // current transformation - renderLight.axis = localLightAxis * GetPhysics()->GetAxis(); - renderLight.origin = GetPhysics()->GetOrigin() + GetPhysics()->GetAxis() * localLightOrigin; - - // reference the sound for shader synced effects - if ( lightParent ) { - renderLight.referenceSound = lightParent->GetSoundEmitter(); - renderEntity.referenceSound = lightParent->GetSoundEmitter(); - } - else { - renderLight.referenceSound = refSound.referenceSound; - renderEntity.referenceSound = refSound.referenceSound; - } - - // update the renderLight and renderEntity to render the light and flare - PresentLightDefChange(); - PresentModelDefChange(); -} - -/* -================ -idLight::Think -================ -*/ -void idLight::Think( void ) { - idVec4 color; - - if ( thinkFlags & TH_THINK ) { - if ( fadeEnd > 0 ) { - if ( gameLocal.time < fadeEnd ) { - color.Lerp( fadeFrom, fadeTo, ( float )( gameLocal.time - fadeStart ) / ( float )( fadeEnd - fadeStart ) ); - } else { - color = fadeTo; - fadeEnd = 0; - BecomeInactive( TH_THINK ); - } - SetColor( color ); - } - } - - RunPhysics(); - Present(); -} - -/* -================ -idLight::GetPhysicsToSoundTransform -================ -*/ -bool idLight::GetPhysicsToSoundTransform( idVec3 &origin, idMat3 &axis ) { - origin = localLightOrigin + renderLight.lightCenter; - axis = localLightAxis * GetPhysics()->GetAxis(); - return true; -} - -/* -================ -idLight::FreeLightDef -================ -*/ -void idLight::FreeLightDef( void ) { - if ( lightDefHandle != -1 ) { - gameRenderWorld->FreeLightDef( lightDefHandle ); - lightDefHandle = -1; - } -} - -/* -================ -idLight::SaveState -================ -*/ -void idLight::SaveState( idDict *args ) { - int i, c = spawnArgs.GetNumKeyVals(); - for ( i = 0; i < c; i++ ) { - const idKeyValue *pv = spawnArgs.GetKeyVal(i); - if ( pv->GetKey().Find( "editor_", false ) >= 0 || pv->GetKey().Find( "parse_", false ) >= 0 ) { - continue; - } - args->Set( pv->GetKey(), pv->GetValue() ); - } -} - -/* -=============== -idLight::ShowEditingDialog -=============== -*/ -void idLight::ShowEditingDialog( void ) { - if ( g_editEntityMode.GetInteger() == 1 ) { - common->InitTool( EDITOR_LIGHT, &spawnArgs ); - } else { - common->InitTool( EDITOR_SOUND, &spawnArgs ); - } -} - -/* -================ -idLight::Event_SetShader -================ -*/ -void idLight::Event_SetShader( const char *shadername ) { - SetShader( shadername ); -} - -/* -================ -idLight::Event_GetLightParm -================ -*/ -void idLight::Event_GetLightParm( int parmnum ) { - if ( ( parmnum < 0 ) || ( parmnum >= MAX_ENTITY_SHADER_PARMS ) ) { - gameLocal.Error( "shader parm index (%d) out of range", parmnum ); - } - - idThread::ReturnFloat( renderLight.shaderParms[ parmnum ] ); -} - -/* -================ -idLight::Event_SetLightParm -================ -*/ -void idLight::Event_SetLightParm( int parmnum, float value ) { - SetLightParm( parmnum, value ); -} - -/* -================ -idLight::Event_SetLightParms -================ -*/ -void idLight::Event_SetLightParms( float parm0, float parm1, float parm2, float parm3 ) { - SetLightParms( parm0, parm1, parm2, parm3 ); -} - -/* -================ -idLight::Event_SetRadiusXYZ -================ -*/ -void idLight::Event_SetRadiusXYZ( float x, float y, float z ) { - SetRadiusXYZ( x, y, z ); -} - -/* -================ -idLight::Event_SetRadius -================ -*/ -void idLight::Event_SetRadius( float radius ) { - SetRadius( radius ); -} - -/* -================ -idLight::Event_Hide -================ -*/ -void idLight::Event_Hide( void ) { - Hide(); - PresentModelDefChange(); - Off(); -} - -/* -================ -idLight::Event_Show -================ -*/ -void idLight::Event_Show( void ) { - Show(); - PresentModelDefChange(); - On(); -} - -/* -================ -idLight::Event_On -================ -*/ -void idLight::Event_On( void ) { - On(); -} - -/* -================ -idLight::Event_Off -================ -*/ -void idLight::Event_Off( void ) { - Off(); -} - -/* -================ -idLight::Event_ToggleOnOff -================ -*/ -void idLight::Event_ToggleOnOff( idEntity *activator ) { - triggercount++; - if ( triggercount < count ) { - return; - } - - // reset trigger count - triggercount = 0; - - if ( breakOnTrigger ) { - BecomeBroken( activator ); - breakOnTrigger = false; - return; - } - - if ( !currentLevel ) { - On(); - } - else { - currentLevel--; - if ( !currentLevel ) { - Off(); - } - else { - SetLightLevel(); - } - } -} - -/* -================ -idLight::Event_SetSoundHandles - - set the same sound def handle on all targeted lights -================ -*/ -void idLight::Event_SetSoundHandles( void ) { - int i; - idEntity *targetEnt; - - if ( !refSound.referenceSound ) { - return; - } - - for ( i = 0; i < targets.Num(); i++ ) { - targetEnt = targets[ i ].GetEntity(); - if ( targetEnt && targetEnt->IsType( idLight::Type ) ) { - idLight *light = static_cast(targetEnt); - light->lightParent = this; - - // explicitly delete any sounds on the entity - light->FreeSoundEmitter( true ); - - // manually set the refSound to this light's refSound - light->renderEntity.referenceSound = renderEntity.referenceSound; - - // update the renderEntity to the renderer - light->UpdateVisuals(); - } - } -} - -/* -================ -idLight::Event_FadeOut -================ -*/ -void idLight::Event_FadeOut( float time ) { - FadeOut( time ); -} - -/* -================ -idLight::Event_FadeIn -================ -*/ -void idLight::Event_FadeIn( float time ) { - FadeIn( time ); -} - -/* -================ -idLight::ClientPredictionThink -================ -*/ -void idLight::ClientPredictionThink( void ) { - Think(); -} - -/* -================ -idLight::WriteToSnapshot -================ -*/ -void idLight::WriteToSnapshot( idBitMsgDelta &msg ) const { - - GetPhysics()->WriteToSnapshot( msg ); - WriteBindToSnapshot( msg ); - - msg.WriteByte( currentLevel ); - msg.WriteInt( PackColor( baseColor ) ); - // msg.WriteBits( lightParent.GetEntityNum(), GENTITYNUM_BITS ); - -/* // only helps prediction - msg.WriteInt( PackColor( fadeFrom ) ); - msg.WriteInt( PackColor( fadeTo ) ); - msg.WriteInt( fadeStart ); - msg.WriteInt( fadeEnd ); -*/ - - // FIXME: send renderLight.shader - msg.WriteFloat( renderLight.lightRadius[0], 5, 10 ); - msg.WriteFloat( renderLight.lightRadius[1], 5, 10 ); - msg.WriteFloat( renderLight.lightRadius[2], 5, 10 ); - - msg.WriteInt( PackColor( idVec4( renderLight.shaderParms[SHADERPARM_RED], - renderLight.shaderParms[SHADERPARM_GREEN], - renderLight.shaderParms[SHADERPARM_BLUE], - renderLight.shaderParms[SHADERPARM_ALPHA] ) ) ); - - msg.WriteFloat( renderLight.shaderParms[SHADERPARM_TIMESCALE], 5, 10 ); - msg.WriteInt( renderLight.shaderParms[SHADERPARM_TIMEOFFSET] ); - //msg.WriteByte( renderLight.shaderParms[SHADERPARM_DIVERSITY] ); - msg.WriteShort( renderLight.shaderParms[SHADERPARM_MODE] ); - - WriteColorToSnapshot( msg ); -} - -/* -================ -idLight::ReadFromSnapshot -================ -*/ -void idLight::ReadFromSnapshot( const idBitMsgDelta &msg ) { - idVec4 shaderColor; - int oldCurrentLevel = currentLevel; - idVec3 oldBaseColor = baseColor; - - GetPhysics()->ReadFromSnapshot( msg ); - ReadBindFromSnapshot( msg ); - - currentLevel = msg.ReadByte(); - if ( currentLevel != oldCurrentLevel ) { - // need to call On/Off for flickering lights to start/stop the sound - // while doing it this way rather than through events, the flickering is out of sync between clients - // but at least there is no question about saving the event and having them happening globally in the world - if ( currentLevel ) { - On(); - } else { - Off(); - } - } - UnpackColor( msg.ReadInt(), baseColor ); - // lightParentEntityNum = msg.ReadBits( GENTITYNUM_BITS ); - -/* // only helps prediction - UnpackColor( msg.ReadInt(), fadeFrom ); - UnpackColor( msg.ReadInt(), fadeTo ); - fadeStart = msg.ReadInt(); - fadeEnd = msg.ReadInt(); -*/ - - // FIXME: read renderLight.shader - renderLight.lightRadius[0] = msg.ReadFloat( 5, 10 ); - renderLight.lightRadius[1] = msg.ReadFloat( 5, 10 ); - renderLight.lightRadius[2] = msg.ReadFloat( 5, 10 ); - - UnpackColor( msg.ReadInt(), shaderColor ); - renderLight.shaderParms[SHADERPARM_RED] = shaderColor[0]; - renderLight.shaderParms[SHADERPARM_GREEN] = shaderColor[1]; - renderLight.shaderParms[SHADERPARM_BLUE] = shaderColor[2]; - renderLight.shaderParms[SHADERPARM_ALPHA] = shaderColor[3]; - - renderLight.shaderParms[SHADERPARM_TIMESCALE] = msg.ReadFloat( 5, 10 ); - renderLight.shaderParms[SHADERPARM_TIMEOFFSET] = msg.ReadInt(); - //renderLight.shaderParms[SHADERPARM_DIVERSITY] = msg.ReadFloat(); - renderLight.shaderParms[SHADERPARM_MODE] = msg.ReadShort(); - - ReadColorFromSnapshot( msg ); - - if ( msg.HasChanged() ) { - if ( ( currentLevel != oldCurrentLevel ) || ( baseColor != oldBaseColor ) ) { - SetLightLevel(); - } else { - PresentLightDefChange(); - PresentModelDefChange(); - } - } -} - -/* -================ -idLight::ClientReceiveEvent -================ -*/ -bool idLight::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) { - - switch( event ) { - case EVENT_BECOMEBROKEN: { - BecomeBroken( NULL ); - return true; - } - default: - break; - } - - return idEntity::ClientReceiveEvent( event, time, msg ); -} diff --git a/d3xp/Light.h b/d3xp/Light.h deleted file mode 100644 index 340a0b9a..00000000 --- a/d3xp/Light.h +++ /dev/null @@ -1,139 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __GAME_LIGHT_H__ -#define __GAME_LIGHT_H__ - -#include "gamesys/Event.h" -#include "Entity.h" - -/* -=============================================================================== - - Generic light. - -=============================================================================== -*/ - -extern const idEventDef EV_Light_GetLightParm; -extern const idEventDef EV_Light_SetLightParm; -extern const idEventDef EV_Light_SetLightParms; - -class idLight : public idEntity { -public: - CLASS_PROTOTYPE( idLight ); - - idLight(); - ~idLight(); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; // archives object for save game file - void Restore( idRestoreGame *savefile ); // unarchives object from save game file - - virtual void UpdateChangeableSpawnArgs( const idDict *source ); - virtual void Think( void ); - virtual void FreeLightDef( void ); - virtual bool GetPhysicsToSoundTransform( idVec3 &origin, idMat3 &axis ); - void Present( void ); - - void SaveState( idDict *args ); - virtual void SetColor( float red, float green, float blue ); - virtual void SetColor( const idVec3 &color ); - virtual void SetColor( const idVec4 &color ); - virtual void GetColor( idVec3 &out ) const; - virtual void GetColor( idVec4 &out ) const; - const idVec3 & GetBaseColor( void ) const { return baseColor; } - void SetShader( const char *shadername ); - void SetLightParm( int parmnum, float value ); - void SetLightParms( float parm0, float parm1, float parm2, float parm3 ); - void SetRadiusXYZ( float x, float y, float z ); - void SetRadius( float radius ); - void On( void ); - void Off( void ); - void Fade( const idVec4 &to, float fadeTime ); - void FadeOut( float time ); - void FadeIn( float time ); - void Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ); - void BecomeBroken( idEntity *activator ); - qhandle_t GetLightDefHandle( void ) const { return lightDefHandle; } - void SetLightParent( idEntity *lparent ) { lightParent = lparent; } - void SetLightLevel( void ); - - virtual void ShowEditingDialog( void ); - - enum { - EVENT_BECOMEBROKEN = idEntity::EVENT_MAXEVENTS, - EVENT_MAXEVENTS - }; - - virtual void ClientPredictionThink( void ); - virtual void WriteToSnapshot( idBitMsgDelta &msg ) const; - virtual void ReadFromSnapshot( const idBitMsgDelta &msg ); - virtual bool ClientReceiveEvent( int event, int time, const idBitMsg &msg ); - -private: - renderLight_t renderLight; // light presented to the renderer - idVec3 localLightOrigin; // light origin relative to the physics origin - idMat3 localLightAxis; // light axis relative to physics axis - qhandle_t lightDefHandle; // handle to renderer light def - idStr brokenModel; - int levels; - int currentLevel; - idVec3 baseColor; - bool breakOnTrigger; - int count; - int triggercount; - idEntity * lightParent; - idVec4 fadeFrom; - idVec4 fadeTo; - int fadeStart; - int fadeEnd; - bool soundWasPlaying; - -private: - void PresentLightDefChange( void ); - void PresentModelDefChange( void ); - - void Event_SetShader( const char *shadername ); - void Event_GetLightParm( int parmnum ); - void Event_SetLightParm( int parmnum, float value ); - void Event_SetLightParms( float parm0, float parm1, float parm2, float parm3 ); - void Event_SetRadiusXYZ( float x, float y, float z ); - void Event_SetRadius( float radius ); - void Event_Hide( void ); - void Event_Show( void ); - void Event_On( void ); - void Event_Off( void ); - void Event_ToggleOnOff( idEntity *activator ); - void Event_SetSoundHandles( void ); - void Event_FadeOut( float time ); - void Event_FadeIn( float time ); -}; - -#endif /* !__GAME_LIGHT_H__ */ diff --git a/d3xp/Misc.cpp b/d3xp/Misc.cpp deleted file mode 100644 index f87342d5..00000000 --- a/d3xp/Misc.cpp +++ /dev/null @@ -1,3762 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ -/* - -Various utility objects and functions. - -*/ - -#include "sys/platform.h" -#include "renderer/ModelManager.h" - -#include "gamesys/SysCvar.h" -#include "script/Script_Thread.h" -#include "ai/AI.h" -#include "Player.h" -#include "Camera.h" -#include "WorldSpawn.h" -#include "Moveable.h" -#include "SmokeParticles.h" - -#include "Misc.h" - -/* -=============================================================================== - -idSpawnableEntity - -A simple, spawnable entity with a model and no functionable ability of it's own. -For example, it can be used as a placeholder during development, for marking -locations on maps for script, or for simple placed models without any behavior -that can be bound to other entities. Should not be subclassed. -=============================================================================== -*/ - -CLASS_DECLARATION( idEntity, idSpawnableEntity ) -END_CLASS - -/* -====================== -idSpawnableEntity::Spawn -====================== -*/ -void idSpawnableEntity::Spawn() { - // this just holds dict information -} - -/* -=============================================================================== - - idPlayerStart - -=============================================================================== -*/ - -const idEventDef EV_TeleportStage( "", "e" ); - -CLASS_DECLARATION( idEntity, idPlayerStart ) - EVENT( EV_Activate, idPlayerStart::Event_TeleportPlayer ) - EVENT( EV_TeleportStage, idPlayerStart::Event_TeleportStage ) -END_CLASS - -/* -=============== -idPlayerStart::idPlayerStart -================ -*/ -idPlayerStart::idPlayerStart( void ) { - teleportStage = 0; -} - -/* -=============== -idPlayerStart::Spawn -================ -*/ -void idPlayerStart::Spawn( void ) { - teleportStage = 0; -} - -/* -================ -idPlayerStart::Save -================ -*/ -void idPlayerStart::Save( idSaveGame *savefile ) const { - savefile->WriteInt( teleportStage ); -} - -/* -================ -idPlayerStart::Restore -================ -*/ -void idPlayerStart::Restore( idRestoreGame *savefile ) { - savefile->ReadInt( teleportStage ); -} - -/* -================ -idPlayerStart::ClientReceiveEvent -================ -*/ -bool idPlayerStart::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) { - int entityNumber; - - switch( event ) { - case EVENT_TELEPORTPLAYER: { - entityNumber = msg.ReadBits( GENTITYNUM_BITS ); - idPlayer *player = static_cast( gameLocal.entities[entityNumber] ); - if ( player != NULL && player->IsType( idPlayer::Type ) ) { - Event_TeleportPlayer( player ); - } - return true; - } - default: - break; - } - - return idEntity::ClientReceiveEvent( event, time, msg ); -} - -/* -=============== -idPlayerStart::Event_TeleportStage - -FIXME: add functionality to fx system ( could be done with player scripting too ) -================ -*/ -void idPlayerStart::Event_TeleportStage( idEntity *_player ) { - idPlayer *player; - if ( !_player->IsType( idPlayer::Type ) ) { - common->Warning( "idPlayerStart::Event_TeleportStage: entity is not an idPlayer\n" ); - return; - } - player = static_cast(_player); - float teleportDelay = spawnArgs.GetFloat( "teleportDelay" ); - switch ( teleportStage ) { - case 0: - player->playerView.Flash( colorWhite, 125 ); - player->SetInfluenceLevel( INFLUENCE_LEVEL3 ); - player->SetInfluenceView( spawnArgs.GetString( "mtr_teleportFx" ), NULL, 0.0f, NULL ); - gameSoundWorld->FadeSoundClasses( 0, -20.0f, teleportDelay ); - player->StartSound( "snd_teleport_start", SND_CHANNEL_BODY2, 0, false, NULL ); - teleportStage++; - PostEventSec( &EV_TeleportStage, teleportDelay, player ); - break; - case 1: - gameSoundWorld->FadeSoundClasses( 0, 0.0f, 0.25f ); - teleportStage++; - PostEventSec( &EV_TeleportStage, 0.25f, player ); - break; - case 2: - player->SetInfluenceView( NULL, NULL, 0.0f, NULL ); - TeleportPlayer( player ); - player->StopSound( SND_CHANNEL_BODY2, false ); - player->SetInfluenceLevel( INFLUENCE_NONE ); - teleportStage = 0; - break; - default: - break; - } -} - -/* -=============== -idPlayerStart::TeleportPlayer -================ -*/ -void idPlayerStart::TeleportPlayer( idPlayer *player ) { - float pushVel = spawnArgs.GetFloat( "push", "300" ); - float f = spawnArgs.GetFloat( "visualEffect", "0" ); - const char *viewName = spawnArgs.GetString( "visualView", "" ); - idEntity *ent = viewName ? gameLocal.FindEntity( viewName ) : NULL; - -#ifdef _D3XP - SetTimeState ts( player->timeGroup ); -#endif - - if ( f && ent ) { - // place in private camera view for some time - // the entity needs to teleport to where the camera view is to have the PVS right - player->Teleport( ent->GetPhysics()->GetOrigin(), ang_zero, this ); - player->StartSound( "snd_teleport_enter", SND_CHANNEL_ANY, 0, false, NULL ); - player->SetPrivateCameraView( static_cast(ent) ); - // the player entity knows where to spawn from the previous Teleport call - if ( !gameLocal.isClient ) { - player->PostEventSec( &EV_Player_ExitTeleporter, f ); - } - } else { - // direct to exit, Teleport will take care of the killbox - player->Teleport( GetPhysics()->GetOrigin(), GetPhysics()->GetAxis().ToAngles(), NULL ); - - // multiplayer hijacked this entity, so only push the player in multiplayer - if ( gameLocal.isMultiplayer ) { - player->GetPhysics()->SetLinearVelocity( GetPhysics()->GetAxis()[0] * pushVel ); - } - } -} - -/* -=============== -idPlayerStart::Event_TeleportPlayer -================ -*/ -void idPlayerStart::Event_TeleportPlayer( idEntity *activator ) { - idPlayer *player; - - if ( activator->IsType( idPlayer::Type ) ) { - player = static_cast( activator ); - } else { - player = gameLocal.GetLocalPlayer(); - } - if ( player ) { - if ( spawnArgs.GetBool( "visualFx" ) ) { - - teleportStage = 0; - Event_TeleportStage( player ); - - } else { - - if ( gameLocal.isServer ) { - idBitMsg msg; - byte msgBuf[MAX_EVENT_PARAM_SIZE]; - - msg.Init( msgBuf, sizeof( msgBuf ) ); - msg.BeginWriting(); - msg.WriteBits( player->entityNumber, GENTITYNUM_BITS ); - ServerSendEvent( EVENT_TELEPORTPLAYER, &msg, false, -1 ); - } - - TeleportPlayer( player ); - } - } -} - -/* -=============================================================================== - - idActivator - -=============================================================================== -*/ - -CLASS_DECLARATION( idEntity, idActivator ) - EVENT( EV_Activate, idActivator::Event_Activate ) -END_CLASS - -/* -=============== -idActivator::Save -================ -*/ -void idActivator::Save( idSaveGame *savefile ) const { - savefile->WriteBool( stay_on ); -} - -/* -=============== -idActivator::Restore -================ -*/ -void idActivator::Restore( idRestoreGame *savefile ) { - savefile->ReadBool( stay_on ); - - if ( stay_on ) { - BecomeActive( TH_THINK ); - } -} - -/* -=============== -idActivator::Spawn -================ -*/ -void idActivator::Spawn( void ) { - bool start_off; - - spawnArgs.GetBool( "stay_on", "0", stay_on ); - spawnArgs.GetBool( "start_off", "0", start_off ); - - GetPhysics()->SetClipBox( idBounds( vec3_origin ).Expand( 4 ), 1.0f ); - GetPhysics()->SetContents( 0 ); - - if ( !start_off ) { - BecomeActive( TH_THINK ); - } -} - -/* -=============== -idActivator::Think -================ -*/ -void idActivator::Think( void ) { - RunPhysics(); - if ( thinkFlags & TH_THINK ) { - if ( TouchTriggers() ) { - if ( !stay_on ) { - BecomeInactive( TH_THINK ); - } - } - } - Present(); -} - -/* -=============== -idActivator::Activate -================ -*/ -void idActivator::Event_Activate( idEntity *activator ) { - if ( thinkFlags & TH_THINK ) { - BecomeInactive( TH_THINK ); - } else { - BecomeActive( TH_THINK ); - } -} - - -/* -=============================================================================== - -idPathCorner - -=============================================================================== -*/ - -CLASS_DECLARATION( idEntity, idPathCorner ) - EVENT( AI_RandomPath, idPathCorner::Event_RandomPath ) -END_CLASS - -/* -===================== -idPathCorner::Spawn -===================== -*/ -void idPathCorner::Spawn( void ) { -} - -/* -===================== -idPathCorner::DrawDebugInfo -===================== -*/ -void idPathCorner::DrawDebugInfo( void ) { - idEntity *ent; - idBounds bnds( idVec3( -4.0, -4.0f, -8.0f ), idVec3( 4.0, 4.0f, 64.0f ) ); - - for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) { - if ( !ent->IsType( idPathCorner::Type ) ) { - continue; - } - - idVec3 org = ent->GetPhysics()->GetOrigin(); - gameRenderWorld->DebugBounds( colorRed, bnds, org, 0 ); - } -} - -/* -============ -idPathCorner::RandomPath -============ -*/ -idPathCorner *idPathCorner::RandomPath( const idEntity *source, const idEntity *ignore ) { - int i; - int num; - int which; - idEntity *ent; - idPathCorner *path[ MAX_GENTITIES ]; - - num = 0; - for( i = 0; i < source->targets.Num(); i++ ) { - ent = source->targets[ i ].GetEntity(); - if ( ent && ( ent != ignore ) && ent->IsType( idPathCorner::Type ) ) { - path[ num++ ] = static_cast( ent ); - if ( num >= MAX_GENTITIES ) { - break; - } - } - } - - if ( !num ) { - return NULL; - } - - which = gameLocal.random.RandomInt( num ); - return path[ which ]; -} - -/* -===================== -idPathCorner::Event_RandomPath -===================== -*/ -void idPathCorner::Event_RandomPath( void ) { - idPathCorner *path; - - path = RandomPath( this, NULL ); - idThread::ReturnEntity( path ); -} - -/* -=============================================================================== - - idDamagable - -=============================================================================== -*/ - -const idEventDef EV_RestoreDamagable( "" ); - -CLASS_DECLARATION( idEntity, idDamagable ) - EVENT( EV_Activate, idDamagable::Event_BecomeBroken ) - EVENT( EV_RestoreDamagable, idDamagable::Event_RestoreDamagable ) -END_CLASS - -/* -================ -idDamagable::idDamagable -================ -*/ -idDamagable::idDamagable( void ) { - count = 0; - nextTriggerTime = 0; -} - -/* -================ -idDamagable::Save -================ -*/ -void idDamagable::Save( idSaveGame *savefile ) const { - savefile->WriteInt( count ); - savefile->WriteInt( nextTriggerTime ); -} - -/* -================ -idDamagable::Restore -================ -*/ -void idDamagable::Restore( idRestoreGame *savefile ) { - savefile->ReadInt( count ); - savefile->ReadInt( nextTriggerTime ); -} - -/* -================ -idDamagable::Spawn -================ -*/ -void idDamagable::Spawn( void ) { - idStr broken; - - health = spawnArgs.GetInt( "health", "5" ); - spawnArgs.GetInt( "count", "1", count ); - nextTriggerTime = 0; - - // make sure the model gets cached - spawnArgs.GetString( "broken", "", broken ); - if ( broken.Length() && !renderModelManager->CheckModel( broken ) ) { - gameLocal.Error( "idDamagable '%s' at (%s): cannot load broken model '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), broken.c_str() ); - } - - fl.takedamage = true; - GetPhysics()->SetContents( CONTENTS_SOLID ); -} - -/* -================ -idDamagable::BecomeBroken -================ -*/ -void idDamagable::BecomeBroken( idEntity *activator ) { - float forceState; - int numStates; - int cycle; - float wait; - - if ( gameLocal.time < nextTriggerTime ) { - return; - } - - spawnArgs.GetFloat( "wait", "0.1", wait ); - nextTriggerTime = gameLocal.time + SEC2MS( wait ); - if ( count > 0 ) { - count--; - if ( !count ) { - fl.takedamage = false; - } else { - health = spawnArgs.GetInt( "health", "5" ); - } - } - - idStr broken; - - spawnArgs.GetString( "broken", "", broken ); - if ( broken.Length() ) { - SetModel( broken ); - } - - // offset the start time of the shader to sync it to the gameLocal time - renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time ); - - spawnArgs.GetInt( "numstates", "1", numStates ); - spawnArgs.GetInt( "cycle", "0", cycle ); - spawnArgs.GetFloat( "forcestate", "0", forceState ); - - // set the state parm - if ( cycle ) { - renderEntity.shaderParms[ SHADERPARM_MODE ]++; - if ( renderEntity.shaderParms[ SHADERPARM_MODE ] > numStates ) { - renderEntity.shaderParms[ SHADERPARM_MODE ] = 0; - } - } else if ( forceState ) { - renderEntity.shaderParms[ SHADERPARM_MODE ] = forceState; - } else { - renderEntity.shaderParms[ SHADERPARM_MODE ] = gameLocal.random.RandomInt( numStates ) + 1; - } - - renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time ); - - ActivateTargets( activator ); - - if ( spawnArgs.GetBool( "hideWhenBroken" ) ) { - Hide(); - PostEventMS( &EV_RestoreDamagable, nextTriggerTime - gameLocal.time ); - BecomeActive( TH_THINK ); - } -} - -/* -================ -idDamagable::Killed -================ -*/ -void idDamagable::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) { - if ( gameLocal.time < nextTriggerTime ) { - health += damage; - return; - } - - BecomeBroken( attacker ); -} - -#ifdef _D3XP -/* -================ -idDamagable::Hide -================ -*/ -void idDamagable::Hide( void ) { - idEntity::Hide(); - GetPhysics()->SetContents( 0 ); -} - -/* -================ -idDamagable::Show -================ -*/ -void idDamagable::Show( void ) { - idEntity::Show(); - GetPhysics()->SetContents( CONTENTS_SOLID ); -} -#endif - -/* -================ -idDamagable::Event_BecomeBroken -================ -*/ -void idDamagable::Event_BecomeBroken( idEntity *activator ) { - BecomeBroken( activator ); -} - -/* -================ -idDamagable::Event_RestoreDamagable -================ -*/ -void idDamagable::Event_RestoreDamagable( void ) { - health = spawnArgs.GetInt( "health", "5" ); - Show(); -} - - -/* -=============================================================================== - - idExplodable - -=============================================================================== -*/ - -CLASS_DECLARATION( idEntity, idExplodable ) - EVENT( EV_Activate, idExplodable::Event_Explode ) -END_CLASS - -/* -================ -idExplodable::Spawn -================ -*/ -void idExplodable::Spawn( void ) { - Hide(); -} - -/* -================ -idExplodable::Event_Explode -================ -*/ -void idExplodable::Event_Explode( idEntity *activator ) { - const char *temp; - - if ( spawnArgs.GetString( "def_damage", "damage_explosion", &temp ) ) { - gameLocal.RadiusDamage( GetPhysics()->GetOrigin(), activator, activator, this, this, temp ); - } - - StartSound( "snd_explode", SND_CHANNEL_ANY, 0, false, NULL ); - - // Show() calls UpdateVisuals, so we don't need to call it ourselves after setting the shaderParms - renderEntity.shaderParms[SHADERPARM_RED] = 1.0f; - renderEntity.shaderParms[SHADERPARM_GREEN] = 1.0f; - renderEntity.shaderParms[SHADERPARM_BLUE] = 1.0f; - renderEntity.shaderParms[SHADERPARM_ALPHA] = 1.0f; - renderEntity.shaderParms[SHADERPARM_TIMEOFFSET] = -MS2SEC( gameLocal.time ); - renderEntity.shaderParms[SHADERPARM_DIVERSITY] = 0.0f; - Show(); - - PostEventMS( &EV_Remove, 2000 ); - - ActivateTargets( activator ); -} - - -/* -=============================================================================== - - idSpring - -=============================================================================== -*/ - -CLASS_DECLARATION( idEntity, idSpring ) - EVENT( EV_PostSpawn, idSpring::Event_LinkSpring ) -END_CLASS - -/* -================ -idSpring::Think -================ -*/ -void idSpring::Think( void ) { - idVec3 start, end, origin; - idMat3 axis; - - // run physics - RunPhysics(); - - if ( thinkFlags & TH_THINK ) { - // evaluate force - spring.Evaluate( gameLocal.time ); - - start = p1; - if ( ent1->GetPhysics() ) { - axis = ent1->GetPhysics()->GetAxis(); - origin = ent1->GetPhysics()->GetOrigin(); - start = origin + start * axis; - } - - end = p2; - if ( ent2->GetPhysics() ) { - axis = ent2->GetPhysics()->GetAxis(); - origin = ent2->GetPhysics()->GetOrigin(); - end = origin + p2 * axis; - } - - gameRenderWorld->DebugLine( idVec4(1, 1, 0, 1), start, end, 0, true ); - } - - Present(); -} - -/* -================ -idSpring::Event_LinkSpring -================ -*/ -void idSpring::Event_LinkSpring( void ) { - idStr name1, name2; - - spawnArgs.GetString( "ent1", "", name1 ); - spawnArgs.GetString( "ent2", "", name2 ); - - if ( name1.Length() ) { - ent1 = gameLocal.FindEntity( name1 ); - if ( !ent1 ) { - gameLocal.Error( "idSpring '%s' at (%s): cannot find first entity '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), name1.c_str() ); - } - } - else { - ent1 = gameLocal.entities[ENTITYNUM_WORLD]; - } - - if ( name2.Length() ) { - ent2 = gameLocal.FindEntity( name2 ); - if ( !ent2 ) { - gameLocal.Error( "idSpring '%s' at (%s): cannot find second entity '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), name2.c_str() ); - } - } - else { - ent2 = gameLocal.entities[ENTITYNUM_WORLD]; - } - spring.SetPosition( ent1->GetPhysics(), id1, p1, ent2->GetPhysics(), id2, p2 ); - BecomeActive( TH_THINK ); -} - -/* -================ -idSpring::Spawn -================ -*/ -void idSpring::Spawn( void ) { - float Kstretch, damping, restLength; - - spawnArgs.GetInt( "id1", "0", id1 ); - spawnArgs.GetInt( "id2", "0", id2 ); - spawnArgs.GetVector( "point1", "0 0 0", p1 ); - spawnArgs.GetVector( "point2", "0 0 0", p2 ); - spawnArgs.GetFloat( "constant", "100.0f", Kstretch ); - spawnArgs.GetFloat( "damping", "10.0f", damping ); - spawnArgs.GetFloat( "restlength", "0.0f", restLength ); - - spring.InitSpring( Kstretch, 0.0f, damping, restLength ); - - ent1 = ent2 = NULL; - - PostEventMS( &EV_PostSpawn, 0 ); -} - -/* -=============================================================================== - - idForceField - -=============================================================================== -*/ - -const idEventDef EV_Toggle( "Toggle", NULL ); - -CLASS_DECLARATION( idEntity, idForceField ) - EVENT( EV_Activate, idForceField::Event_Activate ) - EVENT( EV_Toggle, idForceField::Event_Toggle ) - EVENT( EV_FindTargets, idForceField::Event_FindTargets ) -END_CLASS - -/* -=============== -idForceField::Toggle -================ -*/ -void idForceField::Toggle( void ) { - if ( thinkFlags & TH_THINK ) { - BecomeInactive( TH_THINK ); - } else { - BecomeActive( TH_THINK ); - } -} - -/* -================ -idForceField::Think -================ -*/ -void idForceField::Think( void ) { - if ( thinkFlags & TH_THINK ) { - // evaluate force - forceField.Evaluate( gameLocal.time ); - } - Present(); -} - -/* -================ -idForceField::Save -================ -*/ -void idForceField::Save( idSaveGame *savefile ) const { - savefile->WriteStaticObject( forceField ); -} - -/* -================ -idForceField::Restore -================ -*/ -void idForceField::Restore( idRestoreGame *savefile ) { - savefile->ReadStaticObject( forceField ); -} - -/* -================ -idForceField::Spawn -================ -*/ -void idForceField::Spawn( void ) { - idVec3 uniform; - float explosion, implosion, randomTorque; - - if ( spawnArgs.GetVector( "uniform", "0 0 0", uniform ) ) { - forceField.Uniform( uniform ); - } else if ( spawnArgs.GetFloat( "explosion", "0", explosion ) ) { - forceField.Explosion( explosion ); - } else if ( spawnArgs.GetFloat( "implosion", "0", implosion ) ) { - forceField.Implosion( implosion ); - } - - if ( spawnArgs.GetFloat( "randomTorque", "0", randomTorque ) ) { - forceField.RandomTorque( randomTorque ); - } - - if ( spawnArgs.GetBool( "applyForce", "0" ) ) { - forceField.SetApplyType( FORCEFIELD_APPLY_FORCE ); - } else if ( spawnArgs.GetBool( "applyImpulse", "0" ) ) { - forceField.SetApplyType( FORCEFIELD_APPLY_IMPULSE ); - } else { - forceField.SetApplyType( FORCEFIELD_APPLY_VELOCITY ); - } - - forceField.SetPlayerOnly( spawnArgs.GetBool( "playerOnly", "0" ) ); - forceField.SetMonsterOnly( spawnArgs.GetBool( "monsterOnly", "0" ) ); - - // set the collision model on the force field - forceField.SetClipModel( new idClipModel( GetPhysics()->GetClipModel() ) ); - - // remove the collision model from the physics object - GetPhysics()->SetClipModel( NULL, 1.0f ); - - if ( spawnArgs.GetBool( "start_on" ) ) { - BecomeActive( TH_THINK ); - } -} - -/* -=============== -idForceField::Event_Toggle -================ -*/ -void idForceField::Event_Toggle( void ) { - Toggle(); -} - -/* -================ -idForceField::Event_Activate -================ -*/ -void idForceField::Event_Activate( idEntity *activator ) { - float wait; - - Toggle(); - if ( spawnArgs.GetFloat( "wait", "0.01", wait ) ) { - PostEventSec( &EV_Toggle, wait ); - } -} - -/* -================ -idForceField::Event_FindTargets -================ -*/ -void idForceField::Event_FindTargets( void ) { - FindTargets(); - RemoveNullTargets(); - if ( targets.Num() ) { - forceField.Uniform( targets[0].GetEntity()->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin() ); - } -} - - -/* -=============================================================================== - - idAnimated - -=============================================================================== -*/ - -const idEventDef EV_Animated_Start( "" ); -const idEventDef EV_LaunchMissiles( "launchMissiles", "ssssdf" ); -const idEventDef EV_LaunchMissilesUpdate( "", "dddd" ); -const idEventDef EV_AnimDone( "", "d" ); -const idEventDef EV_StartRagdoll( "startRagdoll" ); -#ifdef _D3XP -const idEventDef EV_SetAnimation( "setAnimation", "s" ); -const idEventDef EV_GetAnimationLength( "getAnimationLength", NULL, 'f' ); -#endif - -CLASS_DECLARATION( idAFEntity_Gibbable, idAnimated ) - EVENT( EV_Activate, idAnimated::Event_Activate ) - EVENT( EV_Animated_Start, idAnimated::Event_Start ) - EVENT( EV_StartRagdoll, idAnimated::Event_StartRagdoll ) - EVENT( EV_AnimDone, idAnimated::Event_AnimDone ) - EVENT( EV_Footstep, idAnimated::Event_Footstep ) - EVENT( EV_FootstepLeft, idAnimated::Event_Footstep ) - EVENT( EV_FootstepRight, idAnimated::Event_Footstep ) - EVENT( EV_LaunchMissiles, idAnimated::Event_LaunchMissiles ) - EVENT( EV_LaunchMissilesUpdate, idAnimated::Event_LaunchMissilesUpdate ) -#ifdef _D3XP - EVENT( EV_SetAnimation, idAnimated::Event_SetAnimation ) - EVENT( EV_GetAnimationLength, idAnimated::Event_GetAnimationLength ) -#endif -END_CLASS - -/* -=============== -idAnimated::idAnimated -================ -*/ -idAnimated::idAnimated() { - anim = 0; - blendFrames = 0; - soundJoint = INVALID_JOINT; - activated = false; - combatModel = NULL; - activator = NULL; - current_anim_index = 0; - num_anims = 0; - -} - -/* -=============== -idAnimated::idAnimated -================ -*/ -idAnimated::~idAnimated() { - delete combatModel; - combatModel = NULL; -} - -/* -=============== -idAnimated::Save -================ -*/ -void idAnimated::Save( idSaveGame *savefile ) const { - savefile->WriteInt( current_anim_index ); - savefile->WriteInt( num_anims ); - savefile->WriteInt( anim ); - savefile->WriteInt( blendFrames ); - savefile->WriteJoint( soundJoint ); - activator.Save( savefile ); - savefile->WriteBool( activated ); -} - -/* -=============== -idAnimated::Restore -================ -*/ -void idAnimated::Restore( idRestoreGame *savefile ) { - savefile->ReadInt( current_anim_index ); - savefile->ReadInt( num_anims ); - savefile->ReadInt( anim ); - savefile->ReadInt( blendFrames ); - savefile->ReadJoint( soundJoint ); - activator.Restore( savefile ); - savefile->ReadBool( activated ); -} - -/* -=============== -idAnimated::Spawn -================ -*/ -void idAnimated::Spawn( void ) { - idStr animname; - int anim2; - float wait; - const char *joint; - - joint = spawnArgs.GetString( "sound_bone", "origin" ); - soundJoint = animator.GetJointHandle( joint ); - if ( soundJoint == INVALID_JOINT ) { - gameLocal.Warning( "idAnimated '%s' at (%s): cannot find joint '%s' for sound playback", name.c_str(), GetPhysics()->GetOrigin().ToString(0), joint ); - } - - LoadAF(); - - // allow bullets to collide with a combat model - if ( spawnArgs.GetBool( "combatModel", "0" ) ) { - combatModel = new idClipModel( modelDefHandle ); - } - - // allow the entity to take damage - if ( spawnArgs.GetBool( "takeDamage", "0" ) ) { - fl.takedamage = true; - } - - blendFrames = 0; - - current_anim_index = 0; - spawnArgs.GetInt( "num_anims", "0", num_anims ); - - blendFrames = spawnArgs.GetInt( "blend_in" ); - - animname = spawnArgs.GetString( num_anims ? "anim1" : "anim" ); - if ( !animname.Length() ) { - anim = 0; - } else { - anim = animator.GetAnim( animname ); - if ( !anim ) { - gameLocal.Error( "idAnimated '%s' at (%s): cannot find anim '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), animname.c_str() ); - } - } - - if ( spawnArgs.GetBool( "hide" ) ) { - Hide(); - - if ( !num_anims ) { - blendFrames = 0; - } - } else if ( spawnArgs.GetString( "start_anim", "", animname ) ) { - anim2 = animator.GetAnim( animname ); - if ( !anim2 ) { - gameLocal.Error( "idAnimated '%s' at (%s): cannot find anim '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), animname.c_str() ); - } - animator.CycleAnim( ANIMCHANNEL_ALL, anim2, gameLocal.time, 0 ); - } else if ( anim ) { - // init joints to the first frame of the animation - animator.SetFrame( ANIMCHANNEL_ALL, anim, 1, gameLocal.time, 0 ); - - if ( !num_anims ) { - blendFrames = 0; - } - } - - spawnArgs.GetFloat( "wait", "-1", wait ); - - if ( wait >= 0 ) { - PostEventSec( &EV_Activate, wait, this ); - } -} - -/* -=============== -idAnimated::LoadAF -=============== -*/ -bool idAnimated::LoadAF( void ) { - idStr fileName; - - if ( !spawnArgs.GetString( "ragdoll", "*unknown*", fileName ) ) { - return false; - } - af.SetAnimator( GetAnimator() ); - return af.Load( this, fileName ); -} - -/* -=============== -idAnimated::GetPhysicsToSoundTransform -=============== -*/ -bool idAnimated::GetPhysicsToSoundTransform( idVec3 &origin, idMat3 &axis ) { - animator.GetJointTransform( soundJoint, gameLocal.time, origin, axis ); - axis = renderEntity.axis; - return true; -} - -/* -================ -idAnimated::StartRagdoll -================ -*/ -bool idAnimated::StartRagdoll( void ) { - // if no AF loaded - if ( !af.IsLoaded() ) { - return false; - } - - // if the AF is already active - if ( af.IsActive() ) { - return true; - } - - // disable any collision model used - GetPhysics()->DisableClip(); - - // start using the AF - af.StartFromCurrentPose( spawnArgs.GetInt( "velocityTime", "0" ) ); - - return true; -} - -/* -===================== -idAnimated::PlayNextAnim -===================== -*/ -void idAnimated::PlayNextAnim( void ) { - const char *animname; - int len; - int cycle; - - if ( current_anim_index >= num_anims ) { - Hide(); - if ( spawnArgs.GetBool( "remove" ) ) { - PostEventMS( &EV_Remove, 0 ); - } else { - current_anim_index = 0; - } - return; - } - - Show(); - current_anim_index++; - - spawnArgs.GetString( va( "anim%d", current_anim_index ), NULL, &animname ); - if ( !animname ) { - anim = 0; - animator.Clear( ANIMCHANNEL_ALL, gameLocal.time, FRAME2MS( blendFrames ) ); - return; - } - - anim = animator.GetAnim( animname ); - if ( !anim ) { - gameLocal.Warning( "missing anim '%s' on %s", animname, name.c_str() ); - return; - } - - if ( g_debugCinematic.GetBool() ) { - gameLocal.Printf( "%d: '%s' start anim '%s'\n", gameLocal.framenum, GetName(), animname ); - } - - spawnArgs.GetInt( "cycle", "1", cycle ); - if ( ( current_anim_index == num_anims ) && spawnArgs.GetBool( "loop_last_anim" ) ) { - cycle = -1; - } - - animator.CycleAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS( blendFrames ) ); - animator.CurrentAnim( ANIMCHANNEL_ALL )->SetCycleCount( cycle ); - - len = animator.CurrentAnim( ANIMCHANNEL_ALL )->PlayLength(); - if ( len >= 0 ) { - PostEventMS( &EV_AnimDone, len, current_anim_index ); - } - - // offset the start time of the shader to sync it to the game time - renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time ); - - animator.ForceUpdate(); - UpdateAnimation(); - UpdateVisuals(); - Present(); -} - -/* -=============== -idAnimated::Event_StartRagdoll -================ -*/ -void idAnimated::Event_StartRagdoll( void ) { - StartRagdoll(); -} - -/* -=============== -idAnimated::Event_AnimDone -================ -*/ -void idAnimated::Event_AnimDone( int animindex ) { - if ( g_debugCinematic.GetBool() ) { - const idAnim *animPtr = animator.GetAnim( anim ); - gameLocal.Printf( "%d: '%s' end anim '%s'\n", gameLocal.framenum, GetName(), animPtr ? animPtr->Name() : "" ); - } - - if ( ( animindex >= num_anims ) && spawnArgs.GetBool( "remove" ) ) { - Hide(); - PostEventMS( &EV_Remove, 0 ); - } else if ( spawnArgs.GetBool( "auto_advance" ) ) { - PlayNextAnim(); - } else { - activated = false; - } - - ActivateTargets( activator.GetEntity() ); -} - -/* -=============== -idAnimated::Event_Activate -================ -*/ -void idAnimated::Event_Activate( idEntity *_activator ) { - if ( num_anims ) { - PlayNextAnim(); - activator = _activator; - return; - } - - if ( activated ) { - // already activated - return; - } - - activated = true; - activator = _activator; - ProcessEvent( &EV_Animated_Start ); -} - -/* -=============== -idAnimated::Event_Start -================ -*/ -void idAnimated::Event_Start( void ) { - int cycle; - int len; - - Show(); - - if ( num_anims ) { - PlayNextAnim(); - return; - } - - if ( anim ) { - if ( g_debugCinematic.GetBool() ) { - const idAnim *animPtr = animator.GetAnim( anim ); - gameLocal.Printf( "%d: '%s' start anim '%s'\n", gameLocal.framenum, GetName(), animPtr ? animPtr->Name() : "" ); - } - spawnArgs.GetInt( "cycle", "1", cycle ); - animator.CycleAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS( blendFrames ) ); - animator.CurrentAnim( ANIMCHANNEL_ALL )->SetCycleCount( cycle ); - - len = animator.CurrentAnim( ANIMCHANNEL_ALL )->PlayLength(); - if ( len >= 0 ) { - PostEventMS( &EV_AnimDone, len, 1 ); - } - } - - // offset the start time of the shader to sync it to the game time - renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time ); - - animator.ForceUpdate(); - UpdateAnimation(); - UpdateVisuals(); - Present(); -} - -/* -=============== -idAnimated::Event_Footstep -=============== -*/ -void idAnimated::Event_Footstep( void ) { - StartSound( "snd_footstep", SND_CHANNEL_BODY, 0, false, NULL ); -} - -/* -===================== -idAnimated::Event_LaunchMissilesUpdate -===================== -*/ -void idAnimated::Event_LaunchMissilesUpdate( int launchjoint, int targetjoint, int numshots, int framedelay ) { - idVec3 launchPos; - idVec3 targetPos; - idMat3 axis; - idVec3 dir; - idEntity * ent; - idProjectile * projectile; - const idDict * projectileDef; - const char * projectilename; - - projectilename = spawnArgs.GetString( "projectilename" ); - projectileDef = gameLocal.FindEntityDefDict( projectilename, false ); - if ( !projectileDef ) { - gameLocal.Warning( "idAnimated '%s' at (%s): 'launchMissiles' called with unknown projectile '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), projectilename ); - return; - } - - StartSound( "snd_missile", SND_CHANNEL_WEAPON, 0, false, NULL ); - - animator.GetJointTransform( ( jointHandle_t )launchjoint, gameLocal.time, launchPos, axis ); - launchPos = renderEntity.origin + launchPos * renderEntity.axis; - - animator.GetJointTransform( ( jointHandle_t )targetjoint, gameLocal.time, targetPos, axis ); - targetPos = renderEntity.origin + targetPos * renderEntity.axis; - - dir = targetPos - launchPos; - dir.Normalize(); - - gameLocal.SpawnEntityDef( *projectileDef, &ent, false ); - if ( !ent || !ent->IsType( idProjectile::Type ) ) { - gameLocal.Error( "idAnimated '%s' at (%s): in 'launchMissiles' call '%s' is not an idProjectile", name.c_str(), GetPhysics()->GetOrigin().ToString(0), projectilename ); - } - projectile = ( idProjectile * )ent; - projectile->Create( this, launchPos, dir ); - projectile->Launch( launchPos, dir, vec3_origin ); - - if ( numshots > 0 ) { - PostEventMS( &EV_LaunchMissilesUpdate, FRAME2MS( framedelay ), launchjoint, targetjoint, numshots - 1, framedelay ); - } -} - -/* -===================== -idAnimated::Event_LaunchMissiles -===================== -*/ -void idAnimated::Event_LaunchMissiles( const char *projectilename, const char *sound, const char *launchjoint, const char *targetjoint, int numshots, int framedelay ) { - const idDict * projectileDef; - jointHandle_t launch; - jointHandle_t target; - - projectileDef = gameLocal.FindEntityDefDict( projectilename, false ); - if ( !projectileDef ) { - gameLocal.Warning( "idAnimated '%s' at (%s): unknown projectile '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), projectilename ); - return; - } - - launch = animator.GetJointHandle( launchjoint ); - if ( launch == INVALID_JOINT ) { - gameLocal.Warning( "idAnimated '%s' at (%s): unknown launch joint '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), launchjoint ); - gameLocal.Error( "Unknown joint '%s'", launchjoint ); - } - - target = animator.GetJointHandle( targetjoint ); - if ( target == INVALID_JOINT ) { - gameLocal.Warning( "idAnimated '%s' at (%s): unknown target joint '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), targetjoint ); - } - - spawnArgs.Set( "projectilename", projectilename ); - spawnArgs.Set( "missilesound", sound ); - - CancelEvents( &EV_LaunchMissilesUpdate ); - ProcessEvent( &EV_LaunchMissilesUpdate, launch, target, numshots - 1, framedelay ); -} - -#ifdef _D3XP -/* -===================== -idAnimated::Event_SetAnimation -===================== -*/ -void idAnimated::Event_SetAnimation( const char *animName ) { - - //BSM Nerve: Need to add some error checking so we don't change the animation - //in the middle of the existing animation - anim = animator.GetAnim( animName ); - if ( !anim ) { - gameLocal.Error( "idAnimated '%s' at (%s): cannot find anim '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), animName ); - } - -} - -/* -===================== -idAnimated::Event_GetAnimationLength -===================== -*/ -void idAnimated::Event_GetAnimationLength() { - float length = 0; - - if(anim) { - length = (float)(animator.AnimLength( anim )) / 1000.f; - } - - idThread::ReturnFloat(length); -} -#endif - -/* -=============================================================================== - - idStaticEntity - - Some static entities may be optimized into inline geometry by dmap - -=============================================================================== -*/ - -CLASS_DECLARATION( idEntity, idStaticEntity ) - EVENT( EV_Activate, idStaticEntity::Event_Activate ) -END_CLASS - -/* -=============== -idStaticEntity::idStaticEntity -=============== -*/ -idStaticEntity::idStaticEntity( void ) { - spawnTime = 0; - active = false; - fadeFrom.Set( 1, 1, 1, 1 ); - fadeTo.Set( 1, 1, 1, 1 ); - fadeStart = 0; - fadeEnd = 0; - runGui = false; -} - -/* -=============== -idStaticEntity::Save -=============== -*/ -void idStaticEntity::Save( idSaveGame *savefile ) const { - savefile->WriteInt( spawnTime ); - savefile->WriteBool( active ); - savefile->WriteVec4( fadeFrom ); - savefile->WriteVec4( fadeTo ); - savefile->WriteInt( fadeStart ); - savefile->WriteInt( fadeEnd ); - savefile->WriteBool( runGui ); -} - -/* -=============== -idStaticEntity::Restore -=============== -*/ -void idStaticEntity::Restore( idRestoreGame *savefile ) { - savefile->ReadInt( spawnTime ); - savefile->ReadBool( active ); - savefile->ReadVec4( fadeFrom ); - savefile->ReadVec4( fadeTo ); - savefile->ReadInt( fadeStart ); - savefile->ReadInt( fadeEnd ); - savefile->ReadBool( runGui ); -} - -/* -=============== -idStaticEntity::Spawn -=============== -*/ -void idStaticEntity::Spawn( void ) { - bool solid; - bool hidden; - - // an inline static model will not do anything at all - if ( spawnArgs.GetBool( "inline" ) || gameLocal.world->spawnArgs.GetBool( "inlineAllStatics" ) ) { - Hide(); - return; - } - - solid = spawnArgs.GetBool( "solid" ); - hidden = spawnArgs.GetBool( "hide" ); - - if ( solid && !hidden ) { - GetPhysics()->SetContents( CONTENTS_SOLID ); - } else { - GetPhysics()->SetContents( 0 ); - } - - spawnTime = gameLocal.time; - active = false; - - idStr model = spawnArgs.GetString( "model" ); - if ( model.Find( ".prt" ) >= 0 ) { - // we want the parametric particles out of sync with each other - renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = gameLocal.random.RandomInt( 32767 ); - } - - fadeFrom.Set( 1, 1, 1, 1 ); - fadeTo.Set( 1, 1, 1, 1 ); - fadeStart = 0; - fadeEnd = 0; - - // NOTE: this should be used very rarely because it is expensive - runGui = spawnArgs.GetBool( "runGui" ); - if ( runGui ) { - BecomeActive( TH_THINK ); - } -} - -/* -================ -idStaticEntity::ShowEditingDialog -================ -*/ -void idStaticEntity::ShowEditingDialog( void ) { - common->InitTool( EDITOR_PARTICLE, &spawnArgs ); -} -/* -================ -idStaticEntity::Think -================ -*/ -void idStaticEntity::Think( void ) { - idEntity::Think(); - if ( thinkFlags & TH_THINK ) { - if ( runGui && renderEntity.gui[0] ) { - idPlayer *player = gameLocal.GetLocalPlayer(); - if ( player ) { - if ( !player->objectiveSystemOpen ) { - renderEntity.gui[0]->StateChanged( gameLocal.time, true ); - if ( renderEntity.gui[1] ) { - renderEntity.gui[1]->StateChanged( gameLocal.time, true ); - } - if ( renderEntity.gui[2] ) { - renderEntity.gui[2]->StateChanged( gameLocal.time, true ); - } - } - } - } - if ( fadeEnd > 0 ) { - idVec4 color; - if ( gameLocal.time < fadeEnd ) { - color.Lerp( fadeFrom, fadeTo, ( float )( gameLocal.time - fadeStart ) / ( float )( fadeEnd - fadeStart ) ); - } else { - color = fadeTo; - fadeEnd = 0; - BecomeInactive( TH_THINK ); - } - SetColor( color ); - } - } -} - -/* -================ -idStaticEntity::Fade -================ -*/ -void idStaticEntity::Fade( const idVec4 &to, float fadeTime ) { - GetColor( fadeFrom ); - fadeTo = to; - fadeStart = gameLocal.time; - fadeEnd = gameLocal.time + SEC2MS( fadeTime ); - BecomeActive( TH_THINK ); -} - -/* -================ -idStaticEntity::Hide -================ -*/ -void idStaticEntity::Hide( void ) { - idEntity::Hide(); - GetPhysics()->SetContents( 0 ); -} - -/* -================ -idStaticEntity::Show -================ -*/ -void idStaticEntity::Show( void ) { - idEntity::Show(); - if ( spawnArgs.GetBool( "solid" ) ) { - GetPhysics()->SetContents( CONTENTS_SOLID ); - } -} - -/* -================ -idStaticEntity::Event_Activate -================ -*/ -void idStaticEntity::Event_Activate( idEntity *activator ) { - idStr activateGui; - - spawnTime = gameLocal.time; - active = !active; - - const idKeyValue *kv = spawnArgs.FindKey( "hide" ); - if ( kv ) { - if ( IsHidden() ) { - Show(); - } else { - Hide(); - } - } - - renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( spawnTime ); - renderEntity.shaderParms[5] = active; - // this change should be a good thing, it will automatically turn on - // lights etc.. when triggered so that does not have to be specifically done - // with trigger parms.. it MIGHT break things so need to keep an eye on it - renderEntity.shaderParms[ SHADERPARM_MODE ] = ( renderEntity.shaderParms[ SHADERPARM_MODE ] ) ? 0.0f : 1.0f; - BecomeActive( TH_UPDATEVISUALS ); -} - -/* -================ -idStaticEntity::WriteToSnapshot -================ -*/ -void idStaticEntity::WriteToSnapshot( idBitMsgDelta &msg ) const { - GetPhysics()->WriteToSnapshot( msg ); - WriteBindToSnapshot( msg ); - WriteColorToSnapshot( msg ); - WriteGUIToSnapshot( msg ); - msg.WriteBits( IsHidden()?1:0, 1 ); -} - -/* -================ -idStaticEntity::ReadFromSnapshot -================ -*/ -void idStaticEntity::ReadFromSnapshot( const idBitMsgDelta &msg ) { - bool hidden; - - GetPhysics()->ReadFromSnapshot( msg ); - ReadBindFromSnapshot( msg ); - ReadColorFromSnapshot( msg ); - ReadGUIFromSnapshot( msg ); - hidden = msg.ReadBits( 1 ) == 1; - if ( hidden != IsHidden() ) { - if ( hidden ) { - Hide(); - } else { - Show(); - } - } - if ( msg.HasChanged() ) { - UpdateVisuals(); - } -} - - -/* -=============================================================================== - -idFuncEmitter - -=============================================================================== -*/ - - -CLASS_DECLARATION( idStaticEntity, idFuncEmitter ) -EVENT( EV_Activate, idFuncEmitter::Event_Activate ) -END_CLASS - -/* -=============== -idFuncEmitter::idFuncEmitter -=============== -*/ -idFuncEmitter::idFuncEmitter( void ) { - hidden = false; -} - -/* -=============== -idFuncEmitter::Spawn -=============== -*/ -void idFuncEmitter::Spawn( void ) { - if ( spawnArgs.GetBool( "start_off" ) ) { - hidden = true; - renderEntity.shaderParms[SHADERPARM_PARTICLE_STOPTIME] = MS2SEC( 1 ); - UpdateVisuals(); - } else { - hidden = false; - } -} - -/* -=============== -idFuncEmitter::Save -=============== -*/ -void idFuncEmitter::Save( idSaveGame *savefile ) const { - savefile->WriteBool( hidden ); -} - -/* -=============== -idFuncEmitter::Restore -=============== -*/ -void idFuncEmitter::Restore( idRestoreGame *savefile ) { - savefile->ReadBool( hidden ); -} - -/* -================ -idFuncEmitter::Event_Activate -================ -*/ -void idFuncEmitter::Event_Activate( idEntity *activator ) { - if ( hidden || spawnArgs.GetBool( "cycleTrigger" ) ) { - renderEntity.shaderParms[SHADERPARM_PARTICLE_STOPTIME] = 0; - renderEntity.shaderParms[SHADERPARM_TIMEOFFSET] = -MS2SEC( gameLocal.time ); - hidden = false; - } else { - renderEntity.shaderParms[SHADERPARM_PARTICLE_STOPTIME] = MS2SEC( gameLocal.time ); - hidden = true; - } - UpdateVisuals(); -} - -/* -================ -idFuncEmitter::WriteToSnapshot -================ -*/ -void idFuncEmitter::WriteToSnapshot( idBitMsgDelta &msg ) const { - msg.WriteBits( hidden ? 1 : 0, 1 ); - msg.WriteFloat( renderEntity.shaderParms[ SHADERPARM_PARTICLE_STOPTIME ] ); - msg.WriteFloat( renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] ); -} - -/* -================ -idFuncEmitter::ReadFromSnapshot -================ -*/ -void idFuncEmitter::ReadFromSnapshot( const idBitMsgDelta &msg ) { - hidden = msg.ReadBits( 1 ) != 0; - renderEntity.shaderParms[ SHADERPARM_PARTICLE_STOPTIME ] = msg.ReadFloat(); - renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = msg.ReadFloat(); - if ( msg.HasChanged() ) { - UpdateVisuals(); - } -} - - -/* -=============================================================================== - -idFuncSplat - -=============================================================================== -*/ - - -const idEventDef EV_Splat( "" ); -CLASS_DECLARATION( idFuncEmitter, idFuncSplat ) -EVENT( EV_Activate, idFuncSplat::Event_Activate ) -EVENT( EV_Splat, idFuncSplat::Event_Splat ) -END_CLASS - -/* -=============== -idFuncSplat::idFuncSplat -=============== -*/ -idFuncSplat::idFuncSplat( void ) { -} - -/* -=============== -idFuncSplat::Spawn -=============== -*/ -void idFuncSplat::Spawn( void ) { -} - -/* -================ -idFuncSplat::Event_Splat -================ -*/ -void idFuncSplat::Event_Splat( void ) { - const char *splat = NULL; - int count = spawnArgs.GetInt( "splatCount", "1" ); - for ( int i = 0; i < count; i++ ) { - splat = spawnArgs.RandomPrefix( "mtr_splat", gameLocal.random ); - if ( splat && *splat ) { - float size = spawnArgs.GetFloat( "splatSize", "128" ); - float dist = spawnArgs.GetFloat( "splatDistance", "128" ); - float angle = spawnArgs.GetFloat( "splatAngle", "0" ); - gameLocal.ProjectDecal( GetPhysics()->GetOrigin(), GetPhysics()->GetAxis()[2], dist, true, size, splat, angle ); - } - } - StartSound( "snd_splat", SND_CHANNEL_ANY, 0, false, NULL ); -} - -/* -================ -idFuncSplat::Event_Activate -================ -*/ -void idFuncSplat::Event_Activate( idEntity *activator ) { - idFuncEmitter::Event_Activate( activator ); - PostEventSec( &EV_Splat, spawnArgs.GetFloat( "splatDelay", "0.25" ) ); - StartSound( "snd_spurt", SND_CHANNEL_ANY, 0, false, NULL ); -} - -/* -=============================================================================== - -idFuncSmoke - -=============================================================================== -*/ - -CLASS_DECLARATION( idEntity, idFuncSmoke ) -EVENT( EV_Activate, idFuncSmoke::Event_Activate ) -END_CLASS - -/* -=============== -idFuncSmoke::idFuncSmoke -=============== -*/ -idFuncSmoke::idFuncSmoke() { - smokeTime = 0; - smoke = NULL; - restart = false; -} - -/* -=============== -idFuncSmoke::Save -=============== -*/ -void idFuncSmoke::Save( idSaveGame *savefile ) const { - savefile->WriteInt( smokeTime ); - savefile->WriteParticle( smoke ); - savefile->WriteBool( restart ); -} - -/* -=============== -idFuncSmoke::Restore -=============== -*/ -void idFuncSmoke::Restore( idRestoreGame *savefile ) { - savefile->ReadInt( smokeTime ); - savefile->ReadParticle( smoke ); - savefile->ReadBool( restart ); -} - -/* -=============== -idFuncSmoke::Spawn -=============== -*/ -void idFuncSmoke::Spawn( void ) { - const char *smokeName = spawnArgs.GetString( "smoke" ); - if ( *smokeName != '\0' ) { - smoke = static_cast( declManager->FindType( DECL_PARTICLE, smokeName ) ); - } else { - smoke = NULL; - } - if ( spawnArgs.GetBool( "start_off" ) ) { - smokeTime = 0; - restart = false; - } else if ( smoke ) { - smokeTime = gameLocal.time; - BecomeActive( TH_UPDATEPARTICLES ); - restart = true; - } - GetPhysics()->SetContents( 0 ); -} - -/* -================ -idFuncSmoke::Event_Activate -================ -*/ -void idFuncSmoke::Event_Activate( idEntity *activator ) { - if ( thinkFlags & TH_UPDATEPARTICLES ) { - restart = false; - return; - } else { - BecomeActive( TH_UPDATEPARTICLES ); - restart = true; - smokeTime = gameLocal.time; - } -} - -/* -=============== -idFuncSmoke::Think -================ -*/ -void idFuncSmoke::Think( void ) { - - // if we are completely closed off from the player, don't do anything at all - if ( CheckDormant() || smoke == NULL || smokeTime == -1 ) { - return; - } - - if ( ( thinkFlags & TH_UPDATEPARTICLES) && !IsHidden() ) { - if ( !gameLocal.smokeParticles->EmitSmoke( smoke, smokeTime, gameLocal.random.CRandomFloat(), GetPhysics()->GetOrigin(), GetPhysics()->GetAxis(), timeGroup /*_D3XP*/ ) ) { - if ( restart ) { - smokeTime = gameLocal.time; - } else { - smokeTime = 0; - BecomeInactive( TH_UPDATEPARTICLES ); - } - } - } - -} - - -/* -=============================================================================== - - idTextEntity - -=============================================================================== -*/ - -CLASS_DECLARATION( idEntity, idTextEntity ) -END_CLASS - -/* -================ -idTextEntity::Spawn -================ -*/ -void idTextEntity::Spawn( void ) { - // these are cached as the are used each frame - text = spawnArgs.GetString( "text" ); - playerOriented = spawnArgs.GetBool( "playerOriented" ); - bool force = spawnArgs.GetBool( "force" ); - if ( developer.GetBool() || force ) { - BecomeActive(TH_THINK); - } -} - -/* -================ -idTextEntity::Save -================ -*/ -void idTextEntity::Save( idSaveGame *savefile ) const { - savefile->WriteString( text ); - savefile->WriteBool( playerOriented ); -} - -/* -================ -idTextEntity::Restore -================ -*/ -void idTextEntity::Restore( idRestoreGame *savefile ) { - savefile->ReadString( text ); - savefile->ReadBool( playerOriented ); -} - -/* -================ -idTextEntity::Think -================ -*/ -void idTextEntity::Think( void ) { - if ( thinkFlags & TH_THINK ) { - gameRenderWorld->DrawText( text, GetPhysics()->GetOrigin(), 0.25, colorWhite, playerOriented ? gameLocal.GetLocalPlayer()->viewAngles.ToMat3() : GetPhysics()->GetAxis().Transpose(), 1 ); - for ( int i = 0; i < targets.Num(); i++ ) { - if ( targets[i].GetEntity() ) { - gameRenderWorld->DebugArrow( colorBlue, GetPhysics()->GetOrigin(), targets[i].GetEntity()->GetPhysics()->GetOrigin(), 1 ); - } - } - } else { - BecomeInactive( TH_ALL ); - } -} - - -/* -=============================================================================== - - idVacuumSeperatorEntity - - Can be triggered to let vacuum through a portal (blown out window) - -=============================================================================== -*/ - -CLASS_DECLARATION( idEntity, idVacuumSeparatorEntity ) - EVENT( EV_Activate, idVacuumSeparatorEntity::Event_Activate ) -END_CLASS - - -/* -================ -idVacuumSeparatorEntity::idVacuumSeparatorEntity -================ -*/ -idVacuumSeparatorEntity::idVacuumSeparatorEntity( void ) { - portal = 0; -} - -/* -================ -idVacuumSeparatorEntity::Save -================ -*/ -void idVacuumSeparatorEntity::Save( idSaveGame *savefile ) const { - savefile->WriteInt( (int)portal ); - savefile->WriteInt( gameRenderWorld->GetPortalState( portal ) ); -} - -/* -================ -idVacuumSeparatorEntity::Restore -================ -*/ -void idVacuumSeparatorEntity::Restore( idRestoreGame *savefile ) { - int state; - - savefile->ReadInt( (int &)portal ); - savefile->ReadInt( state ); - - gameLocal.SetPortalState( portal, state ); -} - -/* -================ -idVacuumSeparatorEntity::Spawn -================ -*/ -void idVacuumSeparatorEntity::Spawn() { - idBounds b; - - b = idBounds( spawnArgs.GetVector( "origin" ) ).Expand( 16 ); - portal = gameRenderWorld->FindPortal( b ); - if ( !portal ) { - gameLocal.Warning( "VacuumSeparator '%s' didn't contact a portal", spawnArgs.GetString( "name" ) ); - return; - } - gameLocal.SetPortalState( portal, PS_BLOCK_AIR | PS_BLOCK_LOCATION ); -} - -/* -================ -idVacuumSeparatorEntity::Event_Activate -================ -*/ -void idVacuumSeparatorEntity::Event_Activate( idEntity *activator ) { - if ( !portal ) { - return; - } - gameLocal.SetPortalState( portal, PS_BLOCK_NONE ); -} - - -/* -=============================================================================== - -idLocationSeparatorEntity - -=============================================================================== -*/ - -CLASS_DECLARATION( idEntity, idLocationSeparatorEntity ) -END_CLASS - -/* -================ -idLocationSeparatorEntity::Spawn -================ -*/ -void idLocationSeparatorEntity::Spawn() { - idBounds b; - - b = idBounds( spawnArgs.GetVector( "origin" ) ).Expand( 16 ); - qhandle_t portal = gameRenderWorld->FindPortal( b ); - if ( !portal ) { - gameLocal.Warning( "LocationSeparator '%s' didn't contact a portal", spawnArgs.GetString( "name" ) ); - } - gameLocal.SetPortalState( portal, PS_BLOCK_LOCATION ); -} - - -/* -=============================================================================== - - idVacuumEntity - - Levels should only have a single vacuum entity. - -=============================================================================== -*/ - -CLASS_DECLARATION( idEntity, idVacuumEntity ) -END_CLASS - -/* -================ -idVacuumEntity::Spawn -================ -*/ -void idVacuumEntity::Spawn() { - if ( gameLocal.vacuumAreaNum != -1 ) { - gameLocal.Warning( "idVacuumEntity::Spawn: multiple idVacuumEntity in level" ); - return; - } - - idVec3 org = spawnArgs.GetVector( "origin" ); - - gameLocal.vacuumAreaNum = gameRenderWorld->PointInArea( org ); -} - - -/* -=============================================================================== - -idLocationEntity - -=============================================================================== -*/ - -CLASS_DECLARATION( idEntity, idLocationEntity ) -END_CLASS - -/* -====================== -idLocationEntity::Spawn -====================== -*/ -void idLocationEntity::Spawn() { - idStr realName; - - // this just holds dict information - - // if "location" not already set, use the entity name. - if ( !spawnArgs.GetString( "location", "", realName ) ) { - spawnArgs.Set( "location", name ); - } -} - -/* -====================== -idLocationEntity::GetLocation -====================== -*/ -const char *idLocationEntity::GetLocation( void ) const { - return spawnArgs.GetString( "location" ); -} - -/* -=============================================================================== - - idBeam - -=============================================================================== -*/ - -CLASS_DECLARATION( idEntity, idBeam ) - EVENT( EV_PostSpawn, idBeam::Event_MatchTarget ) - EVENT( EV_Activate, idBeam::Event_Activate ) -END_CLASS - -/* -=============== -idBeam::idBeam -=============== -*/ -idBeam::idBeam() { - target = NULL; - master = NULL; -} - -/* -=============== -idBeam::Save -=============== -*/ -void idBeam::Save( idSaveGame *savefile ) const { - target.Save( savefile ); - master.Save( savefile ); -} - -/* -=============== -idBeam::Restore -=============== -*/ -void idBeam::Restore( idRestoreGame *savefile ) { - target.Restore( savefile ); - master.Restore( savefile ); -} - -/* -=============== -idBeam::Spawn -=============== -*/ -void idBeam::Spawn( void ) { - float width; - - if ( spawnArgs.GetFloat( "width", "0", width ) ) { - renderEntity.shaderParms[ SHADERPARM_BEAM_WIDTH ] = width; - } - - SetModel( "_BEAM" ); - Hide(); - PostEventMS( &EV_PostSpawn, 0 ); -} - -/* -================ -idBeam::Think -================ -*/ -void idBeam::Think( void ) { - idBeam *masterEnt; - - if ( !IsHidden() && !target.GetEntity() ) { - // hide if our target is removed - Hide(); - } - - RunPhysics(); - - masterEnt = master.GetEntity(); - if ( masterEnt ) { - const idVec3 &origin = GetPhysics()->GetOrigin(); - masterEnt->SetBeamTarget( origin ); - } - Present(); -} - -/* -================ -idBeam::SetMaster -================ -*/ -void idBeam::SetMaster( idBeam *masterbeam ) { - master = masterbeam; -} - -/* -================ -idBeam::SetBeamTarget -================ -*/ -void idBeam::SetBeamTarget( const idVec3 &origin ) { - if ( ( renderEntity.shaderParms[ SHADERPARM_BEAM_END_X ] != origin.x ) || ( renderEntity.shaderParms[ SHADERPARM_BEAM_END_Y ] != origin.y ) || ( renderEntity.shaderParms[ SHADERPARM_BEAM_END_Z ] != origin.z ) ) { - renderEntity.shaderParms[ SHADERPARM_BEAM_END_X ] = origin.x; - renderEntity.shaderParms[ SHADERPARM_BEAM_END_Y ] = origin.y; - renderEntity.shaderParms[ SHADERPARM_BEAM_END_Z ] = origin.z; - UpdateVisuals(); - } -} - -/* -================ -idBeam::Show -================ -*/ -void idBeam::Show( void ) { - idBeam *targetEnt; - - idEntity::Show(); - - targetEnt = target.GetEntity(); - if ( targetEnt ) { - const idVec3 &origin = targetEnt->GetPhysics()->GetOrigin(); - SetBeamTarget( origin ); - } -} - -/* -================ -idBeam::Event_MatchTarget -================ -*/ -void idBeam::Event_MatchTarget( void ) { - int i; - idEntity *targetEnt; - idBeam *targetBeam; - - if ( !targets.Num() ) { - return; - } - - targetBeam = NULL; - for( i = 0; i < targets.Num(); i++ ) { - targetEnt = targets[ i ].GetEntity(); - if ( targetEnt && targetEnt->IsType( idBeam::Type ) ) { - targetBeam = static_cast( targetEnt ); - break; - } - } - - if ( !targetBeam ) { - gameLocal.Error( "Could not find valid beam target for '%s'", name.c_str() ); - } - - target = targetBeam; - targetBeam->SetMaster( this ); - if ( !spawnArgs.GetBool( "start_off" ) ) { - Show(); - } -} - -/* -================ -idBeam::Event_Activate -================ -*/ -void idBeam::Event_Activate( idEntity *activator ) { - if ( IsHidden() ) { - Show(); - } else { - Hide(); - } -} - -/* -================ -idBeam::WriteToSnapshot -================ -*/ -void idBeam::WriteToSnapshot( idBitMsgDelta &msg ) const { - GetPhysics()->WriteToSnapshot( msg ); - WriteBindToSnapshot( msg ); - WriteColorToSnapshot( msg ); - msg.WriteFloat( renderEntity.shaderParms[SHADERPARM_BEAM_END_X] ); - msg.WriteFloat( renderEntity.shaderParms[SHADERPARM_BEAM_END_Y] ); - msg.WriteFloat( renderEntity.shaderParms[SHADERPARM_BEAM_END_Z] ); -} - -/* -================ -idBeam::ReadFromSnapshot -================ -*/ -void idBeam::ReadFromSnapshot( const idBitMsgDelta &msg ) { - GetPhysics()->ReadFromSnapshot( msg ); - ReadBindFromSnapshot( msg ); - ReadColorFromSnapshot( msg ); - renderEntity.shaderParms[SHADERPARM_BEAM_END_X] = msg.ReadFloat(); - renderEntity.shaderParms[SHADERPARM_BEAM_END_Y] = msg.ReadFloat(); - renderEntity.shaderParms[SHADERPARM_BEAM_END_Z] = msg.ReadFloat(); - if ( msg.HasChanged() ) { - UpdateVisuals(); - } -} - - -/* -=============================================================================== - - idLiquid - -=============================================================================== -*/ - -CLASS_DECLARATION( idEntity, idLiquid ) - EVENT( EV_Touch, idLiquid::Event_Touch ) -END_CLASS - -/* -================ -idLiquid::Save -================ -*/ -void idLiquid::Save( idSaveGame *savefile ) const { - // Nothing to save -} - -/* -================ -idLiquid::Restore -================ -*/ -void idLiquid::Restore( idRestoreGame *savefile ) { - //FIXME: NO! - Spawn(); -} - -/* -================ -idLiquid::Spawn -================ -*/ -void idLiquid::Spawn() { -/* - model = dynamic_cast( renderEntity.hModel ); - if ( !model ) { - gameLocal.Error( "Entity '%s' must have liquid model", name.c_str() ); - } - model->Reset(); - GetPhysics()->SetContents( CONTENTS_TRIGGER ); -*/ -} - -/* -================ -idLiquid::Event_Touch -================ -*/ -void idLiquid::Event_Touch( idEntity *other, trace_t *trace ) { - // FIXME: for QuakeCon -/* - idVec3 pos; - - pos = other->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin(); - model->IntersectBounds( other->GetPhysics()->GetBounds().Translate( pos ), -10.0f ); -*/ -} - - -/* -=============================================================================== - - idShaking - -=============================================================================== -*/ - -CLASS_DECLARATION( idEntity, idShaking ) - EVENT( EV_Activate, idShaking::Event_Activate ) -END_CLASS - -/* -=============== -idShaking::idShaking -=============== -*/ -idShaking::idShaking() { - active = false; -} - -/* -=============== -idShaking::Save -=============== -*/ -void idShaking::Save( idSaveGame *savefile ) const { - savefile->WriteBool( active ); - savefile->WriteStaticObject( physicsObj ); -} - -/* -=============== -idShaking::Restore -=============== -*/ -void idShaking::Restore( idRestoreGame *savefile ) { - savefile->ReadBool( active ); - savefile->ReadStaticObject( physicsObj ); - RestorePhysics( &physicsObj ); -} - -/* -=============== -idShaking::Spawn -=============== -*/ -void idShaking::Spawn( void ) { - physicsObj.SetSelf( this ); - physicsObj.SetClipModel( new idClipModel( GetPhysics()->GetClipModel() ), 1.0f ); - physicsObj.SetOrigin( GetPhysics()->GetOrigin() ); - physicsObj.SetAxis( GetPhysics()->GetAxis() ); - physicsObj.SetClipMask( MASK_SOLID ); - SetPhysics( &physicsObj ); - - active = false; - if ( !spawnArgs.GetBool( "start_off" ) ) { - BeginShaking(); - } -} - -/* -================ -idShaking::BeginShaking -================ -*/ -void idShaking::BeginShaking( void ) { - int phase; - idAngles shake; - int period; - - active = true; - phase = gameLocal.random.RandomInt( 1000 ); - shake = spawnArgs.GetAngles( "shake", "0.5 0.5 0.5" ); - period = spawnArgs.GetFloat( "period", "0.05" ) * 1000; - physicsObj.SetAngularExtrapolation( extrapolation_t(EXTRAPOLATION_DECELSINE|EXTRAPOLATION_NOSTOP), phase, period * 0.25f, GetPhysics()->GetAxis().ToAngles(), shake, ang_zero ); -} - -/* -================ -idShaking::Event_Activate -================ -*/ -void idShaking::Event_Activate( idEntity *activator ) { - if ( !active ) { - BeginShaking(); - } else { - active = false; - physicsObj.SetAngularExtrapolation( EXTRAPOLATION_NONE, 0, 0, physicsObj.GetAxis().ToAngles(), ang_zero, ang_zero ); - } -} - -/* -=============================================================================== - - idEarthQuake - -=============================================================================== -*/ - -CLASS_DECLARATION( idEntity, idEarthQuake ) - EVENT( EV_Activate, idEarthQuake::Event_Activate ) -END_CLASS - -/* -=============== -idEarthQuake::idEarthQuake -=============== -*/ -idEarthQuake::idEarthQuake() { - wait = 0.0f; - random = 0.0f; - nextTriggerTime = 0; - shakeStopTime = 0; - triggered = false; - playerOriented = false; - disabled = false; - shakeTime = 0.0f; -} - -/* -=============== -idEarthQuake::Save -=============== -*/ -void idEarthQuake::Save( idSaveGame *savefile ) const { - savefile->WriteInt( nextTriggerTime ); - savefile->WriteInt( shakeStopTime ); - savefile->WriteFloat( wait ); - savefile->WriteFloat( random ); - savefile->WriteBool( triggered ); - savefile->WriteBool( playerOriented ); - savefile->WriteBool( disabled ); - savefile->WriteFloat( shakeTime ); -} - -/* -=============== -idEarthQuake::Restore -=============== -*/ -void idEarthQuake::Restore( idRestoreGame *savefile ) { - savefile->ReadInt( nextTriggerTime ); - savefile->ReadInt( shakeStopTime ); - savefile->ReadFloat( wait ); - savefile->ReadFloat( random ); - savefile->ReadBool( triggered ); - savefile->ReadBool( playerOriented ); - savefile->ReadBool( disabled ); - savefile->ReadFloat( shakeTime ); - - if ( shakeStopTime > gameLocal.time ) { - BecomeActive( TH_THINK ); - } -} - -/* -=============== -idEarthQuake::Spawn -=============== -*/ -void idEarthQuake::Spawn( void ) { - nextTriggerTime = 0; - shakeStopTime = 0; - wait = spawnArgs.GetFloat( "wait", "15" ); - random = spawnArgs.GetFloat( "random", "5" ); - triggered = spawnArgs.GetBool( "triggered" ); - playerOriented = spawnArgs.GetBool( "playerOriented" ); - disabled = false; - shakeTime = spawnArgs.GetFloat( "shakeTime", "0" ); - - if ( !triggered ){ - PostEventSec( &EV_Activate, spawnArgs.GetFloat( "wait" ), this ); - } - BecomeInactive( TH_THINK ); -} - -/* -================ -idEarthQuake::Event_Activate -================ -*/ -void idEarthQuake::Event_Activate( idEntity *activator ) { - - if ( nextTriggerTime > gameLocal.time ) { - return; - } - - if ( disabled && activator == this ) { - return; - } - - idPlayer *player = gameLocal.GetLocalPlayer(); - if ( player == NULL ) { - return; - } - - nextTriggerTime = 0; - - if ( !triggered && activator != this ){ - // if we are not triggered ( i.e. random ), disable or enable - disabled ^= 1; - if (disabled) { - return; - } else { - PostEventSec( &EV_Activate, wait + random * gameLocal.random.CRandomFloat(), this ); - } - } - - ActivateTargets( activator ); - - const idSoundShader *shader = declManager->FindSound( spawnArgs.GetString( "snd_quake" ) ); - if ( playerOriented ) { - player->StartSoundShader( shader, SND_CHANNEL_ANY, SSF_GLOBAL, false, NULL ); - } else { - StartSoundShader( shader, SND_CHANNEL_ANY, SSF_GLOBAL, false, NULL ); - } - - if ( shakeTime > 0.0f ) { - shakeStopTime = gameLocal.time + SEC2MS( shakeTime ); - BecomeActive( TH_THINK ); - } - - if ( wait > 0.0f ) { - if ( !triggered ) { - PostEventSec( &EV_Activate, wait + random * gameLocal.random.CRandomFloat(), this ); - } else { - nextTriggerTime = gameLocal.time + SEC2MS( wait + random * gameLocal.random.CRandomFloat() ); - } - } else if ( shakeTime == 0.0f ) { - PostEventMS( &EV_Remove, 0 ); - } -} - - -/* -=============== -idEarthQuake::Think -================ -*/ -void idEarthQuake::Think( void ) { - if ( thinkFlags & TH_THINK ) { - if ( gameLocal.time > shakeStopTime ) { - BecomeInactive( TH_THINK ); - if ( wait <= 0.0f ) { - PostEventMS( &EV_Remove, 0 ); - } - return; - } - float shakeVolume = gameSoundWorld->CurrentShakeAmplitudeForPosition( gameLocal.time, gameLocal.GetLocalPlayer()->firstPersonViewOrigin ); - gameLocal.RadiusPush( GetPhysics()->GetOrigin(), 256, 1500 * shakeVolume, this, this, 1.0f, true ); - } - BecomeInactive( TH_UPDATEVISUALS ); -} - -/* -=============================================================================== - - idFuncPortal - -=============================================================================== -*/ - -CLASS_DECLARATION( idEntity, idFuncPortal ) - EVENT( EV_Activate, idFuncPortal::Event_Activate ) -END_CLASS - -/* -=============== -idFuncPortal::idFuncPortal -=============== -*/ -idFuncPortal::idFuncPortal() { - portal = 0; - state = false; -} - -/* -=============== -idFuncPortal::Save -=============== -*/ -void idFuncPortal::Save( idSaveGame *savefile ) const { - savefile->WriteInt( (int)portal ); - savefile->WriteBool( state ); -} - -/* -=============== -idFuncPortal::Restore -=============== -*/ -void idFuncPortal::Restore( idRestoreGame *savefile ) { - savefile->ReadInt( (int &)portal ); - savefile->ReadBool( state ); - gameLocal.SetPortalState( portal, state ? PS_BLOCK_ALL : PS_BLOCK_NONE ); -} - -/* -=============== -idFuncPortal::Spawn -=============== -*/ -void idFuncPortal::Spawn( void ) { - portal = gameRenderWorld->FindPortal( GetPhysics()->GetAbsBounds().Expand( 32.0f ) ); - if ( portal > 0 ) { - state = spawnArgs.GetBool( "start_on" ); - gameLocal.SetPortalState( portal, state ? PS_BLOCK_ALL : PS_BLOCK_NONE ); - } -} - -/* -================ -idFuncPortal::Event_Activate -================ -*/ -void idFuncPortal::Event_Activate( idEntity *activator ) { - if ( portal > 0 ) { - state = !state; - gameLocal.SetPortalState( portal, state ? PS_BLOCK_ALL : PS_BLOCK_NONE ); - } -} - -/* -=============================================================================== - - idFuncAASPortal - -=============================================================================== -*/ - -CLASS_DECLARATION( idEntity, idFuncAASPortal ) - EVENT( EV_Activate, idFuncAASPortal::Event_Activate ) -END_CLASS - -/* -=============== -idFuncAASPortal::idFuncAASPortal -=============== -*/ -idFuncAASPortal::idFuncAASPortal() { - state = false; -} - -/* -=============== -idFuncAASPortal::Save -=============== -*/ -void idFuncAASPortal::Save( idSaveGame *savefile ) const { - savefile->WriteBool( state ); -} - -/* -=============== -idFuncAASPortal::Restore -=============== -*/ -void idFuncAASPortal::Restore( idRestoreGame *savefile ) { - savefile->ReadBool( state ); - gameLocal.SetAASAreaState( GetPhysics()->GetAbsBounds(), AREACONTENTS_CLUSTERPORTAL, state ); -} - -/* -=============== -idFuncAASPortal::Spawn -=============== -*/ -void idFuncAASPortal::Spawn( void ) { - state = spawnArgs.GetBool( "start_on" ); - gameLocal.SetAASAreaState( GetPhysics()->GetAbsBounds(), AREACONTENTS_CLUSTERPORTAL, state ); -} - -/* -================ -idFuncAASPortal::Event_Activate -================ -*/ -void idFuncAASPortal::Event_Activate( idEntity *activator ) { - state ^= 1; - gameLocal.SetAASAreaState( GetPhysics()->GetAbsBounds(), AREACONTENTS_CLUSTERPORTAL, state ); -} - -/* -=============================================================================== - - idFuncAASObstacle - -=============================================================================== -*/ - -CLASS_DECLARATION( idEntity, idFuncAASObstacle ) - EVENT( EV_Activate, idFuncAASObstacle::Event_Activate ) -END_CLASS - -/* -=============== -idFuncAASObstacle::idFuncAASObstacle -=============== -*/ -idFuncAASObstacle::idFuncAASObstacle() { - state = false; -} - -/* -=============== -idFuncAASObstacle::Save -=============== -*/ -void idFuncAASObstacle::Save( idSaveGame *savefile ) const { - savefile->WriteBool( state ); -} - -/* -=============== -idFuncAASObstacle::Restore -=============== -*/ -void idFuncAASObstacle::Restore( idRestoreGame *savefile ) { - savefile->ReadBool( state ); - gameLocal.SetAASAreaState( GetPhysics()->GetAbsBounds(), AREACONTENTS_OBSTACLE, state ); -} - -/* -=============== -idFuncAASObstacle::Spawn -=============== -*/ -void idFuncAASObstacle::Spawn( void ) { - state = spawnArgs.GetBool( "start_on" ); - gameLocal.SetAASAreaState( GetPhysics()->GetAbsBounds(), AREACONTENTS_OBSTACLE, state ); -} - -/* -================ -idFuncAASObstacle::Event_Activate -================ -*/ -void idFuncAASObstacle::Event_Activate( idEntity *activator ) { - state ^= 1; - gameLocal.SetAASAreaState( GetPhysics()->GetAbsBounds(), AREACONTENTS_OBSTACLE, state ); -} - - - -/* -=============================================================================== - -idFuncRadioChatter - -=============================================================================== -*/ - -const idEventDef EV_ResetRadioHud( "", "e" ); - - -CLASS_DECLARATION( idEntity, idFuncRadioChatter ) -EVENT( EV_Activate, idFuncRadioChatter::Event_Activate ) -EVENT( EV_ResetRadioHud, idFuncRadioChatter::Event_ResetRadioHud ) -END_CLASS - -/* -=============== -idFuncRadioChatter::idFuncRadioChatter -=============== -*/ -idFuncRadioChatter::idFuncRadioChatter() { - time = 0.0; -} - -/* -=============== -idFuncRadioChatter::Save -=============== -*/ -void idFuncRadioChatter::Save( idSaveGame *savefile ) const { - savefile->WriteFloat( time ); -} - -/* -=============== -idFuncRadioChatter::Restore -=============== -*/ -void idFuncRadioChatter::Restore( idRestoreGame *savefile ) { - savefile->ReadFloat( time ); -} - -/* -=============== -idFuncRadioChatter::Spawn -=============== -*/ -void idFuncRadioChatter::Spawn( void ) { - time = spawnArgs.GetFloat( "time", "5.0" ); -} - -/* -================ -idFuncRadioChatter::Event_Activate -================ -*/ -void idFuncRadioChatter::Event_Activate( idEntity *activator ) { - idPlayer *player; - const char *sound; - const idSoundShader *shader; - int length; - - if ( activator->IsType( idPlayer::Type ) ) { - player = static_cast( activator ); - } else { - player = gameLocal.GetLocalPlayer(); - } - - player->hud->HandleNamedEvent( "radioChatterUp" ); - - sound = spawnArgs.GetString( "snd_radiochatter", "" ); - if ( sound && *sound ) { - shader = declManager->FindSound( sound ); - player->StartSoundShader( shader, SND_CHANNEL_RADIO, SSF_GLOBAL, false, &length ); - time = MS2SEC( length + 150 ); - } - // we still put the hud up because this is used with no sound on - // certain frame commands when the chatter is triggered - PostEventSec( &EV_ResetRadioHud, time, player ); - -} - -/* -================ -idFuncRadioChatter::Event_ResetRadioHud -================ -*/ -void idFuncRadioChatter::Event_ResetRadioHud( idEntity *activator ) { - idPlayer *player = ( activator->IsType( idPlayer::Type ) ) ? static_cast( activator ) : gameLocal.GetLocalPlayer(); - player->hud->HandleNamedEvent( "radioChatterDown" ); - ActivateTargets( activator ); -} - - -/* -=============================================================================== - - idPhantomObjects - -=============================================================================== -*/ - -CLASS_DECLARATION( idEntity, idPhantomObjects ) - EVENT( EV_Activate, idPhantomObjects::Event_Activate ) -END_CLASS - -/* -=============== -idPhantomObjects::idPhantomObjects -=============== -*/ -idPhantomObjects::idPhantomObjects() { - target = NULL; - end_time = 0; - throw_time = 0.0f; - shake_time = 0.0f; - shake_ang.Zero(); - speed = 0.0f; - min_wait = 0; - max_wait = 0; - fl.neverDormant = false; -} - -/* -=============== -idPhantomObjects::Save -=============== -*/ -void idPhantomObjects::Save( idSaveGame *savefile ) const { - int i; - - savefile->WriteInt( end_time ); - savefile->WriteFloat( throw_time ); - savefile->WriteFloat( shake_time ); - savefile->WriteVec3( shake_ang ); - savefile->WriteFloat( speed ); - savefile->WriteInt( min_wait ); - savefile->WriteInt( max_wait ); - target.Save( savefile ); - - savefile->WriteInt( targetTime.Num() ); - for( i = 0; i < targetTime.Num(); i++ ) { - savefile->WriteInt( targetTime[ i ] ); - } - for( i = 0; i < lastTargetPos.Num(); i++ ) { - savefile->WriteVec3( lastTargetPos[ i ] ); - } -} - -/* -=============== -idPhantomObjects::Restore -=============== -*/ -void idPhantomObjects::Restore( idRestoreGame *savefile ) { - int num; - int i; - - savefile->ReadInt( end_time ); - savefile->ReadFloat( throw_time ); - savefile->ReadFloat( shake_time ); - savefile->ReadVec3( shake_ang ); - savefile->ReadFloat( speed ); - savefile->ReadInt( min_wait ); - savefile->ReadInt( max_wait ); - target.Restore( savefile ); - - savefile->ReadInt( num ); - targetTime.SetGranularity( 1 ); - targetTime.SetNum( num ); - lastTargetPos.SetGranularity( 1 ); - lastTargetPos.SetNum( num ); - - for( i = 0; i < num; i++ ) { - savefile->ReadInt( targetTime[ i ] ); - } - for( i = 0; i < num; i++ ) { - savefile->ReadVec3( lastTargetPos[ i ] ); - } -} - -/* -=============== -idPhantomObjects::Spawn -=============== -*/ -void idPhantomObjects::Spawn( void ) { - throw_time = spawnArgs.GetFloat( "time", "5" ); - speed = spawnArgs.GetFloat( "speed", "1200" ); - shake_time = spawnArgs.GetFloat( "shake_time", "1" ); - throw_time -= shake_time; - if ( throw_time < 0.0f ) { - throw_time = 0.0f; - } - min_wait = SEC2MS( spawnArgs.GetFloat( "min_wait", "1" ) ); - max_wait = SEC2MS( spawnArgs.GetFloat( "max_wait", "3" ) ); - - shake_ang = spawnArgs.GetVector( "shake_ang", "65 65 65" ); - Hide(); - GetPhysics()->SetContents( 0 ); -} - -/* -================ -idPhantomObjects::Event_Activate -================ -*/ -void idPhantomObjects::Event_Activate( idEntity *activator ) { - int i; - float time; - float frac; - float scale; - - if ( thinkFlags & TH_THINK ) { - BecomeInactive( TH_THINK ); - return; - } - - RemoveNullTargets(); - if ( !targets.Num() ) { - return; - } - - if ( !activator || !activator->IsType( idActor::Type ) ) { - target = gameLocal.GetLocalPlayer(); - } else { - target = static_cast( activator ); - } - - end_time = gameLocal.time + SEC2MS( spawnArgs.GetFloat( "end_time", "0" ) ); - - targetTime.SetNum( targets.Num() ); - lastTargetPos.SetNum( targets.Num() ); - - const idVec3 &toPos = target.GetEntity()->GetEyePosition(); - - // calculate the relative times of all the objects - time = 0.0f; - for( i = 0; i < targetTime.Num(); i++ ) { - targetTime[ i ] = SEC2MS( time ); - lastTargetPos[ i ] = toPos; - - frac = 1.0f - ( float )i / ( float )targetTime.Num(); - time += ( gameLocal.random.RandomFloat() + 1.0f ) * 0.5f * frac + 0.1f; - } - - // scale up the times to fit within throw_time - scale = throw_time / time; - for( i = 0; i < targetTime.Num(); i++ ) { - targetTime[ i ] = gameLocal.time + SEC2MS( shake_time )+ targetTime[ i ] * scale; - } - - BecomeActive( TH_THINK ); -} - -/* -=============== -idPhantomObjects::Think -================ -*/ -void idPhantomObjects::Think( void ) { - int i; - int num; - float time; - idVec3 vel; - idVec3 ang; - idEntity *ent; - idActor *targetEnt; - idPhysics *entPhys; - trace_t tr; - - // if we are completely closed off from the player, don't do anything at all - if ( CheckDormant() ) { - return; - } - - if ( !( thinkFlags & TH_THINK ) ) { - BecomeInactive( thinkFlags & ~TH_THINK ); - return; - } - - targetEnt = target.GetEntity(); - if ( !targetEnt || ( targetEnt->health <= 0 ) || ( end_time && ( gameLocal.time > end_time ) ) || gameLocal.inCinematic ) { - BecomeInactive( TH_THINK ); - } - - const idVec3 &toPos = targetEnt->GetEyePosition(); - - num = 0; - for ( i = 0; i < targets.Num(); i++ ) { - ent = targets[ i ].GetEntity(); - if ( !ent ) { - continue; - } - - if ( ent->fl.hidden ) { - // don't throw hidden objects - continue; - } - - if ( !targetTime[ i ] ) { - // already threw this object - continue; - } - - num++; - - time = MS2SEC( targetTime[ i ] - gameLocal.time ); - if ( time > shake_time ) { - continue; - } - - entPhys = ent->GetPhysics(); - const idVec3 &entOrg = entPhys->GetOrigin(); - - gameLocal.clip.TracePoint( tr, entOrg, toPos, MASK_OPAQUE, ent ); - if ( tr.fraction >= 1.0f || ( gameLocal.GetTraceEntity( tr ) == targetEnt ) ) { - lastTargetPos[ i ] = toPos; - } - - if ( time < 0.0f ) { - idAI::PredictTrajectory( entPhys->GetOrigin(), lastTargetPos[ i ], speed, entPhys->GetGravity(), - entPhys->GetClipModel(), entPhys->GetClipMask(), 256.0f, ent, targetEnt, ai_debugTrajectory.GetBool() ? 1 : 0, vel ); - vel *= speed; - entPhys->SetLinearVelocity( vel ); - if ( !end_time ) { - targetTime[ i ] = 0; - } else { - targetTime[ i ] = gameLocal.time + gameLocal.random.RandomInt( max_wait - min_wait ) + min_wait; - } - if ( ent->IsType( idMoveable::Type ) ) { - idMoveable *ment = static_cast( ent ); - ment->EnableDamage( true, 2.5f ); - } - } else { - // this is not the right way to set the angular velocity, but the effect is nice, so I'm keeping it. :) - ang.Set( gameLocal.random.CRandomFloat() * shake_ang.x, gameLocal.random.CRandomFloat() * shake_ang.y, gameLocal.random.CRandomFloat() * shake_ang.z ); - ang *= ( 1.0f - time / shake_time ); - entPhys->SetAngularVelocity( ang ); - } - } - - if ( !num ) { - BecomeInactive( TH_THINK ); - } -} - -#ifdef _D3XP -/* -=============================================================================== - -idShockwave - -=============================================================================== -*/ -CLASS_DECLARATION( idEntity, idShockwave ) -EVENT( EV_Activate, idShockwave::Event_Activate ) -END_CLASS - -/* -=============== -idShockwave::idShockwave -=============== -*/ -idShockwave::idShockwave() { - isActive = false; - startTime = 0; - duration = 0; - startSize = 0.f; - endSize = 0.f; - currentSize = 0.f; - magnitude = 0.f; - - height = 0.0f; - playerDamaged = false; - playerDamageSize = 0.0f; -} - -/* -=============== -idShockwave::~idShockwave -=============== -*/ -idShockwave::~idShockwave() { -} - -/* -=============== -idShockwave::Save -=============== -*/ -void idShockwave::Save( idSaveGame *savefile ) const { - savefile->WriteBool( isActive ); - savefile->WriteInt( startTime ); - savefile->WriteInt( duration ); - - savefile->WriteFloat( startSize ); - savefile->WriteFloat( endSize ); - savefile->WriteFloat( currentSize ); - - savefile->WriteFloat( magnitude ); - - savefile->WriteFloat( height ); - savefile->WriteBool( playerDamaged ); - savefile->WriteFloat( playerDamageSize ); -} - -/* -=============== -idShockwave::Restore -=============== -*/ -void idShockwave::Restore( idRestoreGame *savefile ) { - savefile->ReadBool( isActive ); - savefile->ReadInt( startTime ); - savefile->ReadInt( duration ); - - savefile->ReadFloat( startSize ); - savefile->ReadFloat( endSize ); - savefile->ReadFloat( currentSize ); - - savefile->ReadFloat( magnitude ); - - savefile->ReadFloat( height ); - savefile->ReadBool( playerDamaged ); - savefile->ReadFloat( playerDamageSize ); - -} - -/* -=============== -idShockwave::Spawn -=============== -*/ -void idShockwave::Spawn() { - - spawnArgs.GetInt( "duration", "1000", duration ); - spawnArgs.GetFloat( "startsize", "8", startSize ); - spawnArgs.GetFloat( "endsize", "512", endSize ); - spawnArgs.GetFloat( "magnitude", "100", magnitude ); - - spawnArgs.GetFloat( "height", "0", height); - spawnArgs.GetFloat( "player_damage_size", "20", playerDamageSize); - - if ( spawnArgs.GetBool( "start_on" ) ) { - ProcessEvent( &EV_Activate, this ); - } -} - -/* -=============== -idShockwave::Think -=============== -*/ -void idShockwave::Think() { - int endTime; - - if ( !isActive ) { - BecomeInactive( TH_THINK ); - return; - } - - endTime = startTime + duration; - - if ( gameLocal.time < endTime ) { - float u; - float newSize; - - // Expand shockwave - u = (float)(gameLocal.time - startTime) / (float)duration; - newSize = startSize + u * (endSize - startSize); - - // Find all clipmodels between currentSize and newSize - idVec3 pos, end; - idClipModel *clipModelList[ MAX_GENTITIES ]; - idClipModel *clip; - idEntity *ent; - int i, listedClipModels; - - // Set bounds - pos = GetPhysics()->GetOrigin(); - - float zVal; - if(!height) { - zVal = newSize; - } else { - zVal = height/2.0f; - } - - //Expand in a sphere - end = pos + idVec3( newSize, newSize, zVal ); - idBounds bounds( end ); - end = pos + idVec3( -newSize, -newSize, -zVal ); - bounds.AddPoint( end ); - - if(g_debugShockwave.GetBool()) { - gameRenderWorld->DebugBounds(colorRed, bounds, vec3_origin); - } - - listedClipModels = gameLocal.clip.ClipModelsTouchingBounds( bounds, -1, clipModelList, MAX_GENTITIES ); - - for ( i = 0; i < listedClipModels; i++ ) { - clip = clipModelList[ i ]; - ent = clip->GetEntity(); - - if ( ent->IsHidden() ) { - continue; - } - - if ( !ent->IsType( idMoveable::Type ) && !ent->IsType( idAFEntity_Base::Type ) && !ent->IsType( idPlayer::Type )) { - continue; - } - - idVec3 point = ent->GetPhysics()->GetOrigin(); - idVec3 force = point - pos; - - float dist = force.Normalize(); - - if(ent->IsType( idPlayer::Type )) { - - if(ent->GetPhysics()->GetAbsBounds().IntersectsBounds(bounds)) { - - //For player damage we check the current radius and a specified player damage ring size - if ( dist <= newSize && dist > newSize-playerDamageSize ) { - - idStr damageDef = spawnArgs.GetString("def_player_damage", ""); - if(damageDef.Length() > 0 && !playerDamaged) { - - playerDamaged = true; //Only damage once per shockwave - idPlayer* player = static_cast< idPlayer* >( ent ); - idVec3 dir = ent->GetPhysics()->GetOrigin() - pos; - dir.NormalizeFast(); - player->Damage(NULL, NULL, dir, damageDef, 1.0f, INVALID_JOINT); - } - } - } - - } else { - - // If the object is inside the current expansion... - if ( dist <= newSize && dist > currentSize ) { - force.z += 4.f; - force.NormalizeFast(); - - if ( ent->IsType( idAFEntity_Base::Type ) ) { - force = force * (ent->GetPhysics()->GetMass() * magnitude * 0.01f); - } else { - force = force * ent->GetPhysics()->GetMass() * magnitude; - } - - // Kick it up, move force point off object origin - float rad = ent->GetPhysics()->GetBounds().GetRadius(); - point.x += gameLocal.random.CRandomFloat() * rad; - point.y += gameLocal.random.CRandomFloat() * rad; - - int j; - for( j=0; j < ent->GetPhysics()->GetNumClipModels(); j++ ) { - ent->GetPhysics()->AddForce( j, point, force ); - } - } - } - } - - // Update currentSize for next frame - currentSize = newSize; - - } else { - - // turn off - isActive = false; - } -} - -/* -=============== -idShockwave::Event_Activate -=============== -*/ -void idShockwave::Event_Activate( idEntity *activator ) { - - isActive = true; - startTime = gameLocal.time; - playerDamaged = false; - - BecomeActive( TH_THINK ); -} - - -/* -=============================================================================== - -idFuncMountedObject - -=============================================================================== -*/ - -CLASS_DECLARATION( idEntity, idFuncMountedObject ) -EVENT( EV_Touch, idFuncMountedObject::Event_Touch ) -EVENT( EV_Activate, idFuncMountedObject::Event_Activate ) -END_CLASS - -/* -=============== -idFuncMountedObject::idFuncMountedObject -=============== -*/ -idFuncMountedObject::idFuncMountedObject() { - isMounted = false; - scriptFunction = NULL; - mountedPlayer = NULL; - harc = 0; - varc = 0; -} - -/* -=============== -idFuncMountedObject::idFuncMountedObject -=============== -*/ -idFuncMountedObject::~idFuncMountedObject() { -} - -/* -=============== -idFuncMountedObject::Spawn -=============== -*/ -void idFuncMountedObject::Spawn( void ) { - // Get viewOffset - spawnArgs.GetInt( "harc", "45", harc ); - spawnArgs.GetInt( "varc", "30", varc ); - - // Get script function - idStr funcName = spawnArgs.GetString( "call", "" ); - if ( funcName.Length() ) { - scriptFunction = gameLocal.program.FindFunction( funcName ); - if ( scriptFunction == NULL ) { - gameLocal.Warning( "idFuncMountedObject '%s' at (%s) calls unknown function '%s'\n", name.c_str(), GetPhysics()->GetOrigin().ToString(0), funcName.c_str() ); - } - } - - BecomeActive( TH_THINK ); -} - -/* -================ -idFuncMountedObject::Think -================ -*/ -void idFuncMountedObject::Think( void ) { - - idEntity::Think(); -} - -/* -================ -idFuncMountedObject::GetViewInfo -================ -*/ -void idFuncMountedObject::GetAngleRestrictions( int &yaw_min, int &yaw_max, int &pitch ) { - idMat3 axis; - idAngles angs; - - axis = GetPhysics()->GetAxis(); - angs = axis.ToAngles(); - - yaw_min = angs.yaw - harc; - yaw_min = idMath::AngleNormalize180( yaw_min ); - - yaw_max = angs.yaw + harc; - yaw_max = idMath::AngleNormalize180( yaw_max ); - - pitch = varc; -} - -/* -================ -idFuncMountedObject::Event_Touch -================ -*/ -void idFuncMountedObject::Event_Touch( idEntity *other, trace_t *trace ) { - - ProcessEvent( &EV_Activate, other ); -} - -/* -================ -idFuncMountedObject::Event_Activate -================ -*/ -void idFuncMountedObject::Event_Activate( idEntity *activator ) { - if ( !isMounted && activator->IsType( idPlayer::Type ) ) { - idPlayer *client = (idPlayer *)activator; - - mountedPlayer = client; - - /* - // Place player at path_corner targeted by mounted object - int i; - idPathCorner *spot; - - for ( i = 0; i < targets.Num(); i++ ) { - if ( targets[i]->IsType( idPathCorner::Type ) ) { - spot = (idPathCorner*)targets[i]; - break; - } - } - - mountedPlayer->GetPhysics()->SetOrigin( spot->GetPhysics()->GetOrigin() ); - mountedPlayer->GetPhysics()->SetAxis( spot->GetPhysics()->GetAxis() ); - */ - - mountedPlayer->Bind( this, true ); - mountedPlayer->mountedObject = this; - - // Call a script function - idThread *mountthread; - if ( scriptFunction ) { - mountthread = new idThread( scriptFunction ); - mountthread->DelayedStart( 0 ); - } - - isMounted = true; - } -} - -/* -=============================================================================== - -idFuncMountedWeapon - -=============================================================================== -*/ -CLASS_DECLARATION( idFuncMountedObject, idFuncMountedWeapon ) -EVENT( EV_PostSpawn, idFuncMountedWeapon::Event_PostSpawn ) -END_CLASS - -idFuncMountedWeapon::idFuncMountedWeapon() { - turret = NULL; - weaponLastFireTime = 0; - weaponFireDelay = 0; - projectile = NULL; -} - -idFuncMountedWeapon::~idFuncMountedWeapon() { -} - - -void idFuncMountedWeapon::Spawn( void ) { - - // Get projectile info - projectile = gameLocal.FindEntityDefDict( spawnArgs.GetString( "def_projectile" ), false ); - if ( !projectile ) { - gameLocal.Warning( "Invalid projectile on func_mountedweapon." ); - } - - float firerate; - spawnArgs.GetFloat( "firerate", "3", firerate ); - weaponFireDelay = 1000.f / firerate; - - // Get the firing sound - idStr fireSound; - spawnArgs.GetString( "snd_fire", "", fireSound ); - soundFireWeapon = declManager->FindSound( fireSound ); - - PostEventMS( &EV_PostSpawn, 0 ); -} - -void idFuncMountedWeapon::Think( void ) { - - if ( isMounted && turret ) { - idVec3 vec = mountedPlayer->viewAngles.ToForward(); - idAngles ang = mountedPlayer->GetLocalVector( vec ).ToAngles(); - - turret->GetPhysics()->SetAxis( ang.ToMat3() ); - turret->UpdateVisuals(); - - // Check for firing - if ( mountedPlayer->usercmd.buttons & BUTTON_ATTACK && ( gameLocal.time > weaponLastFireTime + weaponFireDelay ) ) { - // FIRE! - idEntity *ent; - idProjectile *proj; - idBounds projBounds; - idVec3 dir; - - gameLocal.SpawnEntityDef( *projectile, &ent ); - if ( !ent || !ent->IsType( idProjectile::Type ) ) { - const char *projectileName = spawnArgs.GetString( "def_projectile" ); - gameLocal.Error( "'%s' is not an idProjectile", projectileName ); - } - - mountedPlayer->GetViewPos( muzzleOrigin, muzzleAxis ); - - muzzleOrigin += ( muzzleAxis[0] * 128 ); - muzzleOrigin -= ( muzzleAxis[2] * 20 ); - - dir = muzzleAxis[0]; - - proj = static_cast(ent); - proj->Create( this, muzzleOrigin, dir ); - - projBounds = proj->GetPhysics()->GetBounds().Rotate( proj->GetPhysics()->GetAxis() ); - - proj->Launch( muzzleOrigin, dir, vec3_origin ); - StartSoundShader( soundFireWeapon, SND_CHANNEL_WEAPON, SSF_GLOBAL, false, NULL ); - - weaponLastFireTime = gameLocal.time; - } - } - - idFuncMountedObject::Think(); -} - -void idFuncMountedWeapon::Event_PostSpawn( void ) { - - if ( targets.Num() >= 1 ) { - for ( int i=0; i < targets.Num(); i++ ) { - if ( targets[i].GetEntity()->IsType( idStaticEntity::Type ) ) { - turret = targets[i].GetEntity(); - break; - } - } - } else { - gameLocal.Warning( "idFuncMountedWeapon::Spawn: Please target one model for a turret\n" ); - } -} - - - - - - -/* -=============================================================================== - -idPortalSky - -=============================================================================== -*/ - -CLASS_DECLARATION( idEntity, idPortalSky ) - EVENT( EV_PostSpawn, idPortalSky::Event_PostSpawn ) - EVENT( EV_Activate, idPortalSky::Event_Activate ) -END_CLASS - -/* -=============== -idPortalSky::idPortalSky -=============== -*/ -idPortalSky::idPortalSky( void ) { - -} - -/* -=============== -idPortalSky::~idPortalSky -=============== -*/ -idPortalSky::~idPortalSky( void ) { - -} - -/* -=============== -idPortalSky::Spawn -=============== -*/ -void idPortalSky::Spawn( void ) { - if ( !spawnArgs.GetBool( "triggered" ) ) { - PostEventMS( &EV_PostSpawn, 1 ); - } -} - -/* -================ -idPortalSky::Event_PostSpawn -================ -*/ -void idPortalSky::Event_PostSpawn() { - gameLocal.SetPortalSkyEnt( this ); -} - -/* -================ -idPortalSky::Event_Activate -================ -*/ -void idPortalSky::Event_Activate( idEntity *activator ) { - gameLocal.SetPortalSkyEnt( this ); -} -#endif /* _D3XP */ diff --git a/d3xp/Misc.h b/d3xp/Misc.h deleted file mode 100644 index a3254096..00000000 --- a/d3xp/Misc.h +++ /dev/null @@ -1,900 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __GAME_MISC_H__ -#define __GAME_MISC_H__ - -#include "physics/Physics_Parametric.h" -#include "physics/Force_Field.h" -#include "physics/Force_Spring.h" - -/* -=============================================================================== - -idSpawnableEntity - -A simple, spawnable entity with a model and no functionable ability of it's own. -For example, it can be used as a placeholder during development, for marking -locations on maps for script, or for simple placed models without any behavior -that can be bound to other entities. Should not be subclassed. -=============================================================================== -*/ - -class idSpawnableEntity : public idEntity { -public: - CLASS_PROTOTYPE( idSpawnableEntity ); - - void Spawn( void ); - -private: -}; - -/* -=============================================================================== - - Potential spawning position for players. - The first time a player enters the game, they will be at an 'initial' spot. - Targets will be fired when someone spawns in on them. - - When triggered, will cause player to be teleported to spawn spot. - -=============================================================================== -*/ - -class idPlayerStart : public idEntity { -public: - CLASS_PROTOTYPE( idPlayerStart ); - - enum { - EVENT_TELEPORTPLAYER = idEntity::EVENT_MAXEVENTS, - EVENT_MAXEVENTS - }; - - idPlayerStart( void ); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - virtual bool ClientReceiveEvent( int event, int time, const idBitMsg &msg ); - -private: - int teleportStage; - - void Event_TeleportPlayer( idEntity *activator ); - void Event_TeleportStage( idEntity *player ); - void TeleportPlayer( idPlayer *player ); -}; - - -/* -=============================================================================== - - Non-displayed entity used to activate triggers when it touches them. - Bind to a mover to have the mover activate a trigger as it moves. - When target by triggers, activating the trigger will toggle the - activator on and off. Check "start_off" to have it spawn disabled. - -=============================================================================== -*/ - -class idActivator : public idEntity { -public: - CLASS_PROTOTYPE( idActivator ); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - virtual void Think( void ); - -private: - bool stay_on; - - void Event_Activate( idEntity *activator ); -}; - - -/* -=============================================================================== - - Path entities for monsters to follow. - -=============================================================================== -*/ -class idPathCorner : public idEntity { -public: - CLASS_PROTOTYPE( idPathCorner ); - - void Spawn( void ); - - static void DrawDebugInfo( void ); - - static idPathCorner *RandomPath( const idEntity *source, const idEntity *ignore ); - -private: - void Event_RandomPath( void ); -}; - - -/* -=============================================================================== - - Object that fires targets and changes shader parms when damaged. - -=============================================================================== -*/ - -class idDamagable : public idEntity { -public: - CLASS_PROTOTYPE( idDamagable ); - - idDamagable( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void Spawn( void ); - void Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ); - -#ifdef _D3XP - virtual void Hide( void ); - virtual void Show( void ); -#endif - -private: - int count; - int nextTriggerTime; - - void BecomeBroken( idEntity *activator ); - void Event_BecomeBroken( idEntity *activator ); - void Event_RestoreDamagable( void ); -}; - - -/* -=============================================================================== - - Hidden object that explodes when activated - -=============================================================================== -*/ - -class idExplodable : public idEntity { -public: - CLASS_PROTOTYPE( idExplodable ); - - void Spawn( void ); - -private: - void Event_Explode( idEntity *activator ); -}; - - -/* -=============================================================================== - - idSpring - -=============================================================================== -*/ - -class idSpring : public idEntity { -public: - CLASS_PROTOTYPE( idSpring ); - - void Spawn( void ); - - virtual void Think( void ); - -private: - idEntity * ent1; - idEntity * ent2; - int id1; - int id2; - idVec3 p1; - idVec3 p2; - idForce_Spring spring; - - void Event_LinkSpring( void ); -}; - - -/* -=============================================================================== - - idForceField - -=============================================================================== -*/ - -class idForceField : public idEntity { -public: - CLASS_PROTOTYPE( idForceField ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void Spawn( void ); - - virtual void Think( void ); - -private: - idForce_Field forceField; - - void Toggle( void ); - - void Event_Activate( idEntity *activator ); - void Event_Toggle( void ); - void Event_FindTargets( void ); -}; - - -/* -=============================================================================== - - idAnimated - -=============================================================================== -*/ - -class idAnimated : public idAFEntity_Gibbable { -public: - CLASS_PROTOTYPE( idAnimated ); - - idAnimated(); - ~idAnimated(); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void Spawn( void ); - virtual bool LoadAF( void ); - bool StartRagdoll( void ); - virtual bool GetPhysicsToSoundTransform( idVec3 &origin, idMat3 &axis ); - -private: - int num_anims; - int current_anim_index; - int anim; - int blendFrames; - jointHandle_t soundJoint; - idEntityPtr activator; - bool activated; - - void PlayNextAnim( void ); - - void Event_Activate( idEntity *activator ); - void Event_Start( void ); - void Event_StartRagdoll( void ); - void Event_AnimDone( int animIndex ); - void Event_Footstep( void ); - void Event_LaunchMissiles( const char *projectilename, const char *sound, const char *launchjoint, const char *targetjoint, int numshots, int framedelay ); - void Event_LaunchMissilesUpdate( int launchjoint, int targetjoint, int numshots, int framedelay ); -#ifdef _D3XP - void Event_SetAnimation( const char *animName ); - void Event_GetAnimationLength(); -#endif -}; - - -/* -=============================================================================== - - idStaticEntity - -=============================================================================== -*/ - -class idStaticEntity : public idEntity { -public: - CLASS_PROTOTYPE( idStaticEntity ); - - idStaticEntity( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void Spawn( void ); - void ShowEditingDialog( void ); - virtual void Hide( void ); - virtual void Show( void ); - void Fade( const idVec4 &to, float fadeTime ); - virtual void Think( void ); - - virtual void WriteToSnapshot( idBitMsgDelta &msg ) const; - virtual void ReadFromSnapshot( const idBitMsgDelta &msg ); - -private: - void Event_Activate( idEntity *activator ); - - int spawnTime; - bool active; - idVec4 fadeFrom; - idVec4 fadeTo; - int fadeStart; - int fadeEnd; - bool runGui; -}; - - -/* -=============================================================================== - -idFuncEmitter - -=============================================================================== -*/ - -class idFuncEmitter : public idStaticEntity { -public: - CLASS_PROTOTYPE( idFuncEmitter ); - - idFuncEmitter( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void Spawn( void ); - void Event_Activate( idEntity *activator ); - - virtual void WriteToSnapshot( idBitMsgDelta &msg ) const; - virtual void ReadFromSnapshot( const idBitMsgDelta &msg ); - -private: - bool hidden; - -}; - - -/* -=============================================================================== - -idFuncSmoke - -=============================================================================== -*/ - -class idFuncSmoke : public idEntity { -public: - CLASS_PROTOTYPE( idFuncSmoke ); - - idFuncSmoke(); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - virtual void Think( void ); - void Event_Activate( idEntity *activator ); - -private: - int smokeTime; - const idDeclParticle * smoke; - bool restart; -}; - - -/* -=============================================================================== - -idFuncSplat - -=============================================================================== -*/ - -class idFuncSplat : public idFuncEmitter { -public: - CLASS_PROTOTYPE( idFuncSplat ); - - idFuncSplat( void ); - - void Spawn( void ); - -private: - void Event_Activate( idEntity *activator ); - void Event_Splat(); -}; - - -/* -=============================================================================== - -idTextEntity - -=============================================================================== -*/ - -class idTextEntity : public idEntity { -public: - CLASS_PROTOTYPE( idTextEntity ); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - virtual void Think( void ); - -private: - idStr text; - bool playerOriented; -}; - - -/* -=============================================================================== - -idLocationEntity - -=============================================================================== -*/ - -class idLocationEntity : public idEntity { -public: - CLASS_PROTOTYPE( idLocationEntity ); - - void Spawn( void ); - - const char * GetLocation( void ) const; - -private: -}; - -class idLocationSeparatorEntity : public idEntity { -public: - CLASS_PROTOTYPE( idLocationSeparatorEntity ); - - void Spawn( void ); - -private: -}; - -class idVacuumSeparatorEntity : public idEntity { -public: - CLASS_PROTOTYPE( idVacuumSeparatorEntity ); - - idVacuumSeparatorEntity( void ); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void Event_Activate( idEntity *activator ); - -private: - qhandle_t portal; -}; - -class idVacuumEntity : public idEntity { -public: - CLASS_PROTOTYPE( idVacuumEntity ); - - void Spawn( void ); - -private: -}; - - -/* -=============================================================================== - - idBeam - -=============================================================================== -*/ - -class idBeam : public idEntity { -public: - CLASS_PROTOTYPE( idBeam ); - - idBeam(); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - virtual void Think( void ); - - void SetMaster( idBeam *masterbeam ); - void SetBeamTarget( const idVec3 &origin ); - - virtual void Show( void ); - - virtual void WriteToSnapshot( idBitMsgDelta &msg ) const; - virtual void ReadFromSnapshot( const idBitMsgDelta &msg ); - -private: - void Event_MatchTarget( void ); - void Event_Activate( idEntity *activator ); - - idEntityPtr target; - idEntityPtr master; -}; - - -/* -=============================================================================== - - idLiquid - -=============================================================================== -*/ - -class idRenderModelLiquid; - -class idLiquid : public idEntity { -public: - CLASS_PROTOTYPE( idLiquid ); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - -private: - void Event_Touch( idEntity *other, trace_t *trace ); - - - idRenderModelLiquid *model; -}; - - -/* -=============================================================================== - - idShaking - -=============================================================================== -*/ - -class idShaking : public idEntity { -public: - CLASS_PROTOTYPE( idShaking ); - - idShaking(); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - -private: - idPhysics_Parametric physicsObj; - bool active; - - void BeginShaking( void ); - void Event_Activate( idEntity *activator ); -}; - - -/* -=============================================================================== - - idEarthQuake - -=============================================================================== -*/ - -class idEarthQuake : public idEntity { -public: - CLASS_PROTOTYPE( idEarthQuake ); - - idEarthQuake(); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - virtual void Think( void ); - -private: - int nextTriggerTime; - int shakeStopTime; - float wait; - float random; - bool triggered; - bool playerOriented; - bool disabled; - float shakeTime; - - void Event_Activate( idEntity *activator ); -}; - - -/* -=============================================================================== - - idFuncPortal - -=============================================================================== -*/ - -class idFuncPortal : public idEntity { -public: - CLASS_PROTOTYPE( idFuncPortal ); - - idFuncPortal(); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - -private: - qhandle_t portal; - bool state; - - void Event_Activate( idEntity *activator ); -}; - -/* -=============================================================================== - - idFuncAASPortal - -=============================================================================== -*/ - -class idFuncAASPortal : public idEntity { -public: - CLASS_PROTOTYPE( idFuncAASPortal ); - - idFuncAASPortal(); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - -private: - bool state; - - void Event_Activate( idEntity *activator ); -}; - -/* -=============================================================================== - - idFuncAASObstacle - -=============================================================================== -*/ - -class idFuncAASObstacle : public idEntity { -public: - CLASS_PROTOTYPE( idFuncAASObstacle ); - - idFuncAASObstacle(); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - -private: - bool state; - - void Event_Activate( idEntity *activator ); -}; - - -/* -=============================================================================== - -idFuncRadioChatter - -=============================================================================== -*/ - -class idFuncRadioChatter : public idEntity { -public: - CLASS_PROTOTYPE( idFuncRadioChatter ); - - idFuncRadioChatter(); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - -private: - float time; - void Event_Activate( idEntity *activator ); - void Event_ResetRadioHud( idEntity *activator ); -}; - - -/* -=============================================================================== - - idPhantomObjects - -=============================================================================== -*/ - -class idPhantomObjects : public idEntity { -public: - CLASS_PROTOTYPE( idPhantomObjects ); - - idPhantomObjects(); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - virtual void Think( void ); - -private: - void Event_Activate( idEntity *activator ); - void Event_Throw( void ); - void Event_ShakeObject( idEntity *object, int starttime ); - - int end_time; - float throw_time; - float shake_time; - idVec3 shake_ang; - float speed; - int min_wait; - int max_wait; - idEntityPtrtarget; - idList targetTime; - idList lastTargetPos; -}; - -#ifdef _D3XP -/* -=============================================================================== - -idShockwave - -=============================================================================== -*/ -class idShockwave : public idEntity { -public: - CLASS_PROTOTYPE( idShockwave ); - - idShockwave(); - ~idShockwave(); - - void Spawn( void ); - void Think( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - -private: - void Event_Activate( idEntity *activator ); - - bool isActive; - int startTime; - int duration; - - float startSize; - float endSize; - float currentSize; - - float magnitude; - - float height; - bool playerDamaged; - float playerDamageSize; - -}; - -/* -=============================================================================== - -idFuncMountedObject - -=============================================================================== -*/ -class idFuncMountedObject : public idEntity { -public: - CLASS_PROTOTYPE( idFuncMountedObject ); - - idFuncMountedObject(); - ~idFuncMountedObject(); - - void Spawn( void ); - void Think( void ); - - void GetAngleRestrictions( int &yaw_min, int &yaw_max, int &pitch ); - -private: - int harc; - int varc; - - void Event_Touch( idEntity *other, trace_t *trace ); - void Event_Activate( idEntity *activator ); - -public: - bool isMounted; - function_t * scriptFunction; - idPlayer * mountedPlayer; -}; - - -class idFuncMountedWeapon : public idFuncMountedObject { -public: - CLASS_PROTOTYPE( idFuncMountedWeapon ); - - idFuncMountedWeapon(); - ~idFuncMountedWeapon(); - - void Spawn( void ); - void Think( void ); - -private: - - // The actual turret that moves with the player's view - idEntity * turret; - - // the muzzle bone's position, used for launching projectiles and trailing smoke - idVec3 muzzleOrigin; - idMat3 muzzleAxis; - - float weaponLastFireTime; - float weaponFireDelay; - - const idDict * projectile; - - const idSoundShader *soundFireWeapon; - - void Event_PostSpawn( void ); -}; - -/* -=============================================================================== - -idPortalSky - -=============================================================================== -*/ -class idPortalSky : public idEntity { -public: - CLASS_PROTOTYPE( idPortalSky ); - - idPortalSky(); - ~idPortalSky(); - - void Spawn( void ); - void Event_PostSpawn(); - void Event_Activate( idEntity *activator ); -}; - -#endif /* _D3XP */ - -#endif /* !__GAME_MISC_H__ */ diff --git a/d3xp/Moveable.cpp b/d3xp/Moveable.cpp deleted file mode 100644 index 0ba26a85..00000000 --- a/d3xp/Moveable.cpp +++ /dev/null @@ -1,1358 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "renderer/ModelManager.h" - -#include "gamesys/SysCvar.h" -#include "ai/AI.h" -#include "Fx.h" - -#include "Moveable.h" - -/* -=============================================================================== - - idMoveable - -=============================================================================== -*/ - -const idEventDef EV_BecomeNonSolid( "becomeNonSolid" ); -const idEventDef EV_SetOwnerFromSpawnArgs( "" ); -const idEventDef EV_IsAtRest( "isAtRest", NULL, 'd' ); -const idEventDef EV_EnableDamage( "enableDamage", "f" ); - -CLASS_DECLARATION( idEntity, idMoveable ) - EVENT( EV_Activate, idMoveable::Event_Activate ) - EVENT( EV_BecomeNonSolid, idMoveable::Event_BecomeNonSolid ) - EVENT( EV_SetOwnerFromSpawnArgs, idMoveable::Event_SetOwnerFromSpawnArgs ) - EVENT( EV_IsAtRest, idMoveable::Event_IsAtRest ) - EVENT( EV_EnableDamage, idMoveable::Event_EnableDamage ) -END_CLASS - - -static const float BOUNCE_SOUND_MIN_VELOCITY = 80.0f; -static const float BOUNCE_SOUND_MAX_VELOCITY = 200.0f; - -/* -================ -idMoveable::idMoveable -================ -*/ -idMoveable::idMoveable( void ) { - minDamageVelocity = 100.0f; - maxDamageVelocity = 200.0f; - nextCollideFxTime = 0; - nextDamageTime = 0; - nextSoundTime = 0; - initialSpline = NULL; - initialSplineDir = vec3_zero; - explode = false; - unbindOnDeath = false; - allowStep = false; - canDamage = false; -#ifdef _D3XP - attacker = NULL; -#endif -} - -/* -================ -idMoveable::~idMoveable -================ -*/ -idMoveable::~idMoveable( void ) { - delete initialSpline; - initialSpline = NULL; -} - -/* -================ -idMoveable::Spawn -================ -*/ -void idMoveable::Spawn( void ) { - idTraceModel trm; - float density, friction, bouncyness, mass; - int clipShrink; - idStr clipModelName; - - // check if a clip model is set - spawnArgs.GetString( "clipmodel", "", clipModelName ); - if ( !clipModelName[0] ) { - clipModelName = spawnArgs.GetString( "model" ); // use the visual model - } - - if ( !collisionModelManager->TrmFromModel( clipModelName, trm ) ) { - gameLocal.Error( "idMoveable '%s': cannot load collision model %s", name.c_str(), clipModelName.c_str() ); - return; - } - - // if the model should be shrinked - clipShrink = spawnArgs.GetInt( "clipshrink" ); - if ( clipShrink != 0 ) { - trm.Shrink( clipShrink * CM_CLIP_EPSILON ); - } - - // get rigid body properties - spawnArgs.GetFloat( "density", "0.5", density ); - density = idMath::ClampFloat( 0.001f, 1000.0f, density ); - spawnArgs.GetFloat( "friction", "0.05", friction ); - friction = idMath::ClampFloat( 0.0f, 1.0f, friction ); - spawnArgs.GetFloat( "bouncyness", "0.6", bouncyness ); - bouncyness = idMath::ClampFloat( 0.0f, 1.0f, bouncyness ); - explode = spawnArgs.GetBool( "explode" ); - unbindOnDeath = spawnArgs.GetBool( "unbindondeath" ); - - fxCollide = spawnArgs.GetString( "fx_collide" ); - nextCollideFxTime = 0; - - fl.takedamage = true; - damage = spawnArgs.GetString( "def_damage", "" ); -#ifdef _D3XP - monsterDamage = spawnArgs.GetString( "monster_damage", "" ); - fl.networkSync = true; - attacker = NULL; -#endif - canDamage = spawnArgs.GetBool( "damageWhenActive" ) ? false : true; - minDamageVelocity = spawnArgs.GetFloat( "minDamageVelocity", "300" ); // _D3XP - maxDamageVelocity = spawnArgs.GetFloat( "maxDamageVelocity", "700" ); // _D3XP - nextDamageTime = 0; - nextSoundTime = 0; - - health = spawnArgs.GetInt( "health", "0" ); - spawnArgs.GetString( "broken", "", brokenModel ); - - if ( health ) { - if ( brokenModel != "" && !renderModelManager->CheckModel( brokenModel ) ) { - gameLocal.Error( "idMoveable '%s' at (%s): cannot load broken model '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), brokenModel.c_str() ); - } - } - - // setup the physics - physicsObj.SetSelf( this ); - physicsObj.SetClipModel( new idClipModel( trm ), density ); - physicsObj.GetClipModel()->SetMaterial( GetRenderModelMaterial() ); - physicsObj.SetOrigin( GetPhysics()->GetOrigin() ); - physicsObj.SetAxis( GetPhysics()->GetAxis() ); - physicsObj.SetBouncyness( bouncyness ); - physicsObj.SetFriction( 0.6f, 0.6f, friction ); - physicsObj.SetGravity( gameLocal.GetGravity() ); - physicsObj.SetContents( CONTENTS_SOLID ); - physicsObj.SetClipMask( MASK_SOLID | CONTENTS_BODY | CONTENTS_CORPSE | CONTENTS_MOVEABLECLIP ); - SetPhysics( &physicsObj ); - - if ( spawnArgs.GetFloat( "mass", "10", mass ) ) { - physicsObj.SetMass( mass ); - } - - if ( spawnArgs.GetBool( "nodrop" ) ) { - physicsObj.PutToRest(); - } else { - physicsObj.DropToFloor(); - } - - if ( spawnArgs.GetBool( "noimpact" ) || spawnArgs.GetBool( "notPushable" ) ) { - physicsObj.DisableImpact(); - } - - if ( spawnArgs.GetBool( "nonsolid" ) ) { - BecomeNonSolid(); - } - - allowStep = spawnArgs.GetBool( "allowStep", "1" ); - - PostEventMS( &EV_SetOwnerFromSpawnArgs, 0 ); -} - -/* -================ -idMoveable::Save -================ -*/ -void idMoveable::Save( idSaveGame *savefile ) const { - - savefile->WriteString( brokenModel ); - savefile->WriteString( damage ); -#ifdef _D3XP - savefile->WriteString( monsterDamage ); - savefile->WriteObject( attacker ); -#endif - savefile->WriteString( fxCollide ); - savefile->WriteInt( nextCollideFxTime ); - savefile->WriteFloat( minDamageVelocity ); - savefile->WriteFloat( maxDamageVelocity ); - savefile->WriteBool( explode ); - savefile->WriteBool( unbindOnDeath ); - savefile->WriteBool( allowStep ); - savefile->WriteBool( canDamage ); - savefile->WriteInt( nextDamageTime ); - savefile->WriteInt( nextSoundTime ); - savefile->WriteInt( initialSpline != NULL ? initialSpline->GetTime( 0 ) : -1 ); - savefile->WriteVec3( initialSplineDir ); - - savefile->WriteStaticObject( physicsObj ); -} - -/* -================ -idMoveable::Restore -================ -*/ -void idMoveable::Restore( idRestoreGame *savefile ) { - int initialSplineTime; - - savefile->ReadString( brokenModel ); - savefile->ReadString( damage ); -#ifdef _D3XP - savefile->ReadString( monsterDamage ); - savefile->ReadObject( reinterpret_cast( attacker ) ); -#endif - savefile->ReadString( fxCollide ); - savefile->ReadInt( nextCollideFxTime ); - savefile->ReadFloat( minDamageVelocity ); - savefile->ReadFloat( maxDamageVelocity ); - savefile->ReadBool( explode ); - savefile->ReadBool( unbindOnDeath ); - savefile->ReadBool( allowStep ); - savefile->ReadBool( canDamage ); - savefile->ReadInt( nextDamageTime ); - savefile->ReadInt( nextSoundTime ); - savefile->ReadInt( initialSplineTime ); - savefile->ReadVec3( initialSplineDir ); - - if ( initialSplineTime != -1 ) { - InitInitialSpline( initialSplineTime ); - } else { - initialSpline = NULL; - } - - savefile->ReadStaticObject( physicsObj ); - RestorePhysics( &physicsObj ); -} - -/* -================ -idMoveable::Hide -================ -*/ -void idMoveable::Hide( void ) { - idEntity::Hide(); - physicsObj.SetContents( 0 ); -} - -/* -================ -idMoveable::Show -================ -*/ -void idMoveable::Show( void ) { - idEntity::Show(); - if ( !spawnArgs.GetBool( "nonsolid" ) ) { - physicsObj.SetContents( CONTENTS_SOLID ); - } -} - -/* -================= -idMoveable::Collide -================= -*/ -bool idMoveable::Collide( const trace_t &collision, const idVec3 &velocity ) { - float v, f; - idVec3 dir; - idEntity *ent; - - v = -( velocity * collision.c.normal ); - if ( v > BOUNCE_SOUND_MIN_VELOCITY && gameLocal.time > nextSoundTime ) { - f = v > BOUNCE_SOUND_MAX_VELOCITY ? 1.0f : idMath::Sqrt( v - BOUNCE_SOUND_MIN_VELOCITY ) * ( 1.0f / idMath::Sqrt( BOUNCE_SOUND_MAX_VELOCITY - BOUNCE_SOUND_MIN_VELOCITY ) ); - if ( StartSound( "snd_bounce", SND_CHANNEL_ANY, 0, false, NULL ) ) { - // don't set the volume unless there is a bounce sound as it overrides the entire channel - // which causes footsteps on ai's to not honor their shader parms - SetSoundVolume( f ); - } - nextSoundTime = gameLocal.time + 500; - } - - // _D3XP :: changes relating to the addition of monsterDamage - if ( !gameLocal.isClient && canDamage && gameLocal.time > nextDamageTime ) { - bool hasDamage = damage.Length() > 0; - bool hasMonsterDamage = monsterDamage.Length() > 0; - - if ( hasDamage || hasMonsterDamage ) { - ent = gameLocal.entities[ collision.c.entityNum ]; - if ( ent && v > minDamageVelocity ) { - f = v > maxDamageVelocity ? 1.0f : idMath::Sqrt( v - minDamageVelocity ) * ( 1.0f / idMath::Sqrt( maxDamageVelocity - minDamageVelocity ) ); - dir = velocity; - dir.NormalizeFast(); - if ( ent->IsType( idAI::Type ) && hasMonsterDamage ) { -#ifdef _D3XP - if ( attacker ) { - ent->Damage( this, attacker, dir, monsterDamage, f, INVALID_JOINT ); - } - else { - ent->Damage( this, GetPhysics()->GetClipModel()->GetOwner(), dir, monsterDamage, f, INVALID_JOINT ); - } -#else - ent->Damage( this, GetPhysics()->GetClipModel()->GetOwner(), dir, monsterDamage, f, INVALID_JOINT ); -#endif - } else if ( hasDamage ) { -#ifdef _D3XP - // in multiplayer, scale damage wrt mass of object - if ( gameLocal.isMultiplayer ) { - f *= GetPhysics()->GetMass() * g_moveableDamageScale.GetFloat(); - } - - if ( attacker ) { - ent->Damage( this, attacker, dir, damage, f, INVALID_JOINT ); - } - else { - ent->Damage( this, GetPhysics()->GetClipModel()->GetOwner(), dir, damage, f, INVALID_JOINT ); - } -#else - ent->Damage( this, GetPhysics()->GetClipModel()->GetOwner(), dir, damage, f, INVALID_JOINT ); -#endif - } - - nextDamageTime = gameLocal.time + 1000; - } - } - } - -#ifdef _D3XP - if ( this->IsType( idExplodingBarrel::Type ) ) { - idExplodingBarrel *ebarrel = static_cast(this); - - if ( !ebarrel->IsStable() ) { - PostEventSec( &EV_Explode, 0.04f ); - } - } -#endif - - if ( fxCollide.Length() && gameLocal.time > nextCollideFxTime ) { - idEntityFx::StartFx( fxCollide, &collision.c.point, NULL, this, false ); - nextCollideFxTime = gameLocal.time + 3500; - } - - return false; -} - -/* -============ -idMoveable::Killed -============ -*/ -void idMoveable::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) { - if ( unbindOnDeath ) { - Unbind(); - } - - if ( brokenModel != "" ) { - SetModel( brokenModel ); - } - - if ( explode ) { - if ( brokenModel == "" ) { - PostEventMS( &EV_Remove, 1000 ); - } - } - - if ( renderEntity.gui[ 0 ] ) { - renderEntity.gui[ 0 ] = NULL; - } - - ActivateTargets( this ); - - fl.takedamage = false; -} - -/* -================ -idMoveable::AllowStep -================ -*/ -bool idMoveable::AllowStep( void ) const { - return allowStep; -} - -/* -================ -idMoveable::BecomeNonSolid -================ -*/ -void idMoveable::BecomeNonSolid( void ) { - // set CONTENTS_RENDERMODEL so bullets still collide with the moveable - physicsObj.SetContents( CONTENTS_CORPSE | CONTENTS_RENDERMODEL ); - physicsObj.SetClipMask( MASK_SOLID | CONTENTS_CORPSE | CONTENTS_MOVEABLECLIP ); -} - -/* -================ -idMoveable::EnableDamage -================ -*/ -void idMoveable::EnableDamage( bool enable, float duration ) { -#ifdef _D3XP - if ( canDamage == enable ) { - return; - } -#endif - - canDamage = enable; - if ( duration ) { - PostEventSec( &EV_EnableDamage, duration, ( /*_D3XP*/enable ) ? 0.0f : 1.0f ); - } -} - -/* -================ -idMoveable::InitInitialSpline -================ -*/ -void idMoveable::InitInitialSpline( int startTime ) { - int initialSplineTime; - - initialSpline = GetSpline(); - initialSplineTime = spawnArgs.GetInt( "initialSplineTime", "300" ); - - if ( initialSpline != NULL ) { - initialSpline->MakeUniform( initialSplineTime ); - initialSpline->ShiftTime( startTime - initialSpline->GetTime( 0 ) ); - initialSplineDir = initialSpline->GetCurrentFirstDerivative( startTime ); - initialSplineDir *= physicsObj.GetAxis().Transpose(); - initialSplineDir.Normalize(); - BecomeActive( TH_THINK ); - } -} - -/* -================ -idMoveable::FollowInitialSplinePath -================ -*/ -bool idMoveable::FollowInitialSplinePath( void ) { - if ( initialSpline != NULL ) { - if ( gameLocal.time < initialSpline->GetTime( initialSpline->GetNumValues() - 1 ) ) { - idVec3 splinePos = initialSpline->GetCurrentValue( gameLocal.time ); - idVec3 linearVelocity = ( splinePos - physicsObj.GetOrigin() ) * USERCMD_HZ; - physicsObj.SetLinearVelocity( linearVelocity ); - - idVec3 splineDir = initialSpline->GetCurrentFirstDerivative( gameLocal.time ); - idVec3 dir = initialSplineDir * physicsObj.GetAxis(); - idVec3 angularVelocity = dir.Cross( splineDir ); - angularVelocity.Normalize(); - angularVelocity *= idMath::ACos16( dir * splineDir / splineDir.Length() ) * USERCMD_HZ; - physicsObj.SetAngularVelocity( angularVelocity ); - return true; - } else { - delete initialSpline; - initialSpline = NULL; - } - } - return false; -} - -/* -================ -idMoveable::Think -================ -*/ -void idMoveable::Think( void ) { - if ( thinkFlags & TH_THINK ) { - if ( !FollowInitialSplinePath() ) { - BecomeInactive( TH_THINK ); - } - } - idEntity::Think(); -} - -/* -================ -idMoveable::GetRenderModelMaterial -================ -*/ -const idMaterial *idMoveable::GetRenderModelMaterial( void ) const { - if ( renderEntity.customShader ) { - return renderEntity.customShader; - } - if ( renderEntity.hModel && renderEntity.hModel->NumSurfaces() ) { - return renderEntity.hModel->Surface( 0 )->shader; - } - return NULL; -} - -/* -================ -idMoveable::WriteToSnapshot -================ -*/ -void idMoveable::WriteToSnapshot( idBitMsgDelta &msg ) const { - physicsObj.WriteToSnapshot( msg ); -} - -/* -================ -idMoveable::ReadFromSnapshot -================ -*/ -void idMoveable::ReadFromSnapshot( const idBitMsgDelta &msg ) { - physicsObj.ReadFromSnapshot( msg ); - if ( msg.HasChanged() ) { - UpdateVisuals(); - } -} - -/* -================ -idMoveable::Event_BecomeNonSolid -================ -*/ -void idMoveable::Event_BecomeNonSolid( void ) { - BecomeNonSolid(); -} - -#ifdef _D3XP -/* -================ -idMoveable::SetAttacker -================ -*/ -void idMoveable::SetAttacker( idEntity *ent ) { - attacker = ent; -} -#endif - -/* -================ -idMoveable::Event_Activate -================ -*/ -void idMoveable::Event_Activate( idEntity *activator ) { - float delay; - idVec3 init_velocity, init_avelocity; - - Show(); - - if ( !spawnArgs.GetInt( "notPushable" ) ) { - physicsObj.EnableImpact(); - } - - physicsObj.Activate(); - - spawnArgs.GetVector( "init_velocity", "0 0 0", init_velocity ); - spawnArgs.GetVector( "init_avelocity", "0 0 0", init_avelocity ); - - delay = spawnArgs.GetFloat( "init_velocityDelay", "0" ); - if ( delay == 0.0f ) { - physicsObj.SetLinearVelocity( init_velocity ); - } else { - PostEventSec( &EV_SetLinearVelocity, delay, init_velocity ); - } - - delay = spawnArgs.GetFloat( "init_avelocityDelay", "0" ); - if ( delay == 0.0f ) { - physicsObj.SetAngularVelocity( init_avelocity ); - } else { - PostEventSec( &EV_SetAngularVelocity, delay, init_avelocity ); - } - - InitInitialSpline( gameLocal.time ); -} - -/* -================ -idMoveable::Event_SetOwnerFromSpawnArgs -================ -*/ -void idMoveable::Event_SetOwnerFromSpawnArgs( void ) { - idStr owner; - - if ( spawnArgs.GetString( "owner", "", owner ) ) { - ProcessEvent( &EV_SetOwner, gameLocal.FindEntity( owner ) ); - } -} - -/* -================ -idMoveable::Event_IsAtRest -================ -*/ -void idMoveable::Event_IsAtRest( void ) { - idThread::ReturnInt( physicsObj.IsAtRest() ); -} - -/* -================ -idMoveable::Event_EnableDamage -================ -*/ -void idMoveable::Event_EnableDamage( float enable ) { -#ifdef _D3XP - // clear out attacker - attacker = NULL; -#endif - - canDamage = ( enable != 0.0f ); -} - - -/* -=============================================================================== - - idBarrel - -=============================================================================== -*/ - -CLASS_DECLARATION( idMoveable, idBarrel ) -END_CLASS - -/* -================ -idBarrel::idBarrel -================ -*/ -idBarrel::idBarrel() { - radius = 1.0f; - barrelAxis = 0; - lastOrigin.Zero(); - lastAxis.Identity(); - additionalRotation = 0.0f; - additionalAxis.Identity(); - fl.networkSync = true; -} - -/* -================ -idBarrel::Save -================ -*/ -void idBarrel::Save( idSaveGame *savefile ) const { - savefile->WriteFloat( radius ); - savefile->WriteInt( barrelAxis ); - savefile->WriteVec3( lastOrigin ); - savefile->WriteMat3( lastAxis ); - savefile->WriteFloat( additionalRotation ); - savefile->WriteMat3( additionalAxis ); -} - -/* -================ -idBarrel::Restore -================ -*/ -void idBarrel::Restore( idRestoreGame *savefile ) { - savefile->ReadFloat( radius ); - savefile->ReadInt( barrelAxis ); - savefile->ReadVec3( lastOrigin ); - savefile->ReadMat3( lastAxis ); - savefile->ReadFloat( additionalRotation ); - savefile->ReadMat3( additionalAxis ); -} - -/* -================ -idBarrel::BarrelThink -================ -*/ -void idBarrel::BarrelThink( void ) { - bool wasAtRest, onGround; - float movedDistance, rotatedDistance, angle; - idVec3 curOrigin, gravityNormal, dir; - idMat3 curAxis, axis; - - wasAtRest = IsAtRest(); - - // run physics - RunPhysics(); - - // only need to give the visual model an additional rotation if the physics were run - if ( !wasAtRest ) { - - // current physics state - onGround = GetPhysics()->HasGroundContacts(); - curOrigin = GetPhysics()->GetOrigin(); - curAxis = GetPhysics()->GetAxis(); - - // if the barrel is on the ground - if ( onGround ) { - gravityNormal = GetPhysics()->GetGravityNormal(); - - dir = curOrigin - lastOrigin; - dir -= gravityNormal * dir * gravityNormal; - movedDistance = dir.LengthSqr(); - - // if the barrel moved and the barrel is not aligned with the gravity direction - if ( movedDistance > 0.0f && idMath::Fabs( gravityNormal * curAxis[barrelAxis] ) < 0.7f ) { - - // barrel movement since last think frame orthogonal to the barrel axis - movedDistance = idMath::Sqrt( movedDistance ); - dir *= 1.0f / movedDistance; - movedDistance = ( 1.0f - idMath::Fabs( dir * curAxis[barrelAxis] ) ) * movedDistance; - - // get rotation about barrel axis since last think frame - angle = lastAxis[(barrelAxis+1)%3] * curAxis[(barrelAxis+1)%3]; - angle = idMath::ACos( angle ); - // distance along cylinder hull - rotatedDistance = angle * radius; - - // if the barrel moved further than it rotated about it's axis - if ( movedDistance > rotatedDistance ) { - - // additional rotation of the visual model to make it look - // like the barrel rolls instead of slides - angle = 180.0f * (movedDistance - rotatedDistance) / (radius * idMath::PI); - if ( gravityNormal.Cross( curAxis[barrelAxis] ) * dir < 0.0f ) { - additionalRotation += angle; - } else { - additionalRotation -= angle; - } - dir = vec3_origin; - dir[barrelAxis] = 1.0f; - additionalAxis = idRotation( vec3_origin, dir, additionalRotation ).ToMat3(); - } - } - } - - // save state for next think - lastOrigin = curOrigin; - lastAxis = curAxis; - } - - Present(); -} - -/* -================ -idBarrel::Think -================ -*/ -void idBarrel::Think( void ) { - if ( thinkFlags & TH_THINK ) { - if ( !FollowInitialSplinePath() ) { - BecomeInactive( TH_THINK ); - } - } - - BarrelThink(); -} - -/* -================ -idBarrel::GetPhysicsToVisualTransform -================ -*/ -bool idBarrel::GetPhysicsToVisualTransform( idVec3 &origin, idMat3 &axis ) { - origin = vec3_origin; - axis = additionalAxis; - return true; -} - -/* -================ -idBarrel::Spawn -================ -*/ -void idBarrel::Spawn( void ) { - const idBounds &bounds = GetPhysics()->GetBounds(); - - // radius of the barrel cylinder - radius = ( bounds[1][0] - bounds[0][0] ) * 0.5f; - - // always a vertical barrel with cylinder axis parallel to the z-axis - barrelAxis = 2; - - lastOrigin = GetPhysics()->GetOrigin(); - lastAxis = GetPhysics()->GetAxis(); - - additionalRotation = 0.0f; - additionalAxis.Identity(); - -#ifdef _D3XP - fl.networkSync = true; -#endif -} - -/* -================ -idBarrel::ClientPredictionThink -================ -*/ -void idBarrel::ClientPredictionThink( void ) { - Think(); -} - - -/* -=============================================================================== - -idExplodingBarrel - -=============================================================================== -*/ -const idEventDef EV_Respawn( "" ); -const idEventDef EV_TriggerTargets( "" ); - -CLASS_DECLARATION( idBarrel, idExplodingBarrel ) - EVENT( EV_Activate, idExplodingBarrel::Event_Activate ) - EVENT( EV_Respawn, idExplodingBarrel::Event_Respawn ) - EVENT( EV_Explode, idExplodingBarrel::Event_Explode ) - EVENT( EV_TriggerTargets, idExplodingBarrel::Event_TriggerTargets ) -END_CLASS - -/* -================ -idExplodingBarrel::idExplodingBarrel -================ -*/ -idExplodingBarrel::idExplodingBarrel() { - spawnOrigin.Zero(); - spawnAxis.Zero(); - state = NORMAL; -#ifdef _D3XP - isStable = true; -#endif - particleModelDefHandle = -1; - lightDefHandle = -1; - memset( &particleRenderEntity, 0, sizeof( particleRenderEntity ) ); - memset( &light, 0, sizeof( light ) ); - particleTime = 0; - lightTime = 0; - time = 0.0f; -} - -/* -================ -idExplodingBarrel::~idExplodingBarrel -================ -*/ -idExplodingBarrel::~idExplodingBarrel() { - if ( particleModelDefHandle >= 0 ){ - gameRenderWorld->FreeEntityDef( particleModelDefHandle ); - } - if ( lightDefHandle >= 0 ) { - gameRenderWorld->FreeLightDef( lightDefHandle ); - } -} - -/* -================ -idExplodingBarrel::Save -================ -*/ -void idExplodingBarrel::Save( idSaveGame *savefile ) const { - savefile->WriteVec3( spawnOrigin ); - savefile->WriteMat3( spawnAxis ); - - savefile->WriteInt( state ); - savefile->WriteInt( particleModelDefHandle ); - savefile->WriteInt( lightDefHandle ); - - savefile->WriteRenderEntity( particleRenderEntity ); - savefile->WriteRenderLight( light ); - - savefile->WriteInt( particleTime ); - savefile->WriteInt( lightTime ); - savefile->WriteFloat( time ); - -#ifdef _D3XP - savefile->WriteBool( isStable ); -#endif -} - -/* -================ -idExplodingBarrel::Restore -================ -*/ -void idExplodingBarrel::Restore( idRestoreGame *savefile ) { - savefile->ReadVec3( spawnOrigin ); - savefile->ReadMat3( spawnAxis ); - - savefile->ReadInt( (int &)state ); - savefile->ReadInt( (int &)particleModelDefHandle ); - savefile->ReadInt( (int &)lightDefHandle ); - - savefile->ReadRenderEntity( particleRenderEntity ); - savefile->ReadRenderLight( light ); - - savefile->ReadInt( particleTime ); - savefile->ReadInt( lightTime ); - savefile->ReadFloat( time ); - -#ifdef _D3XP - savefile->ReadBool( isStable ); - - if ( lightDefHandle != -1 ) { - lightDefHandle = gameRenderWorld->AddLightDef( &light ); - } - if ( particleModelDefHandle != -1 ) { - particleModelDefHandle = gameRenderWorld->AddEntityDef( &particleRenderEntity ); - } -#endif -} - -/* -================ -idExplodingBarrel::Spawn -================ -*/ -void idExplodingBarrel::Spawn( void ) { - health = spawnArgs.GetInt( "health", "5" ); - fl.takedamage = true; -#ifdef _D3XP - isStable = true; - fl.networkSync = true; -#endif - spawnOrigin = GetPhysics()->GetOrigin(); - spawnAxis = GetPhysics()->GetAxis(); - state = NORMAL; - particleModelDefHandle = -1; - lightDefHandle = -1; - lightTime = 0; - particleTime = 0; - time = spawnArgs.GetFloat( "time" ); - memset( &particleRenderEntity, 0, sizeof( particleRenderEntity ) ); - memset( &light, 0, sizeof( light ) ); -} - -/* -================ -idExplodingBarrel::Think -================ -*/ -void idExplodingBarrel::Think( void ) { - idBarrel::BarrelThink(); - - if ( lightDefHandle >= 0 ){ - if ( state == BURNING ) { - // ramp the color up over 250 ms - float pct = (gameLocal.time - lightTime) / 250.f; - if ( pct > 1.0f ) { - pct = 1.0f; - } - light.origin = physicsObj.GetAbsBounds().GetCenter(); - light.axis = mat3_identity; - light.shaderParms[ SHADERPARM_RED ] = pct; - light.shaderParms[ SHADERPARM_GREEN ] = pct; - light.shaderParms[ SHADERPARM_BLUE ] = pct; - light.shaderParms[ SHADERPARM_ALPHA ] = pct; - gameRenderWorld->UpdateLightDef( lightDefHandle, &light ); - } else { - if ( gameLocal.time - lightTime > 250 ) { - gameRenderWorld->FreeLightDef( lightDefHandle ); - lightDefHandle = -1; - } - return; - } - } - - if ( !gameLocal.isClient && state != BURNING && state != EXPLODING ) { - BecomeInactive( TH_THINK ); - return; - } - - if ( particleModelDefHandle >= 0 ){ - particleRenderEntity.origin = physicsObj.GetAbsBounds().GetCenter(); - particleRenderEntity.axis = mat3_identity; - gameRenderWorld->UpdateEntityDef( particleModelDefHandle, &particleRenderEntity ); - } -} - -#ifdef _D3XP -/* -================ -idExplodingBarrel::SetStability -================ -*/ -void idExplodingBarrel::SetStability( bool stability ) { - isStable = stability; -} - -/* -================ -idExplodingBarrel::IsStable -================ -*/ -bool idExplodingBarrel::IsStable( void ) { - return isStable; -} - -/* -================ -idExplodingBarrel::StartBurning -================ -*/ -void idExplodingBarrel::StartBurning( void ) { - state = BURNING; - AddParticles( "barrelfire.prt", true ); -} - -/* -================ -idExplodingBarrel::StartBurning -================ -*/ -void idExplodingBarrel::StopBurning( void ) { - state = NORMAL; - - if ( particleModelDefHandle >= 0 ){ - gameRenderWorld->FreeEntityDef( particleModelDefHandle ); - particleModelDefHandle = -1; - - particleTime = 0; - memset( &particleRenderEntity, 0, sizeof( particleRenderEntity ) ); - } -} -#endif - -/* -================ -idExplodingBarrel::AddParticles -================ -*/ -void idExplodingBarrel::AddParticles( const char *name, bool burn ) { - if ( name && *name ) { -#ifdef _D3XP - int explicitTimeGroup = timeGroup; - SetTimeState explicitTS( explicitTimeGroup ); -#endif - if ( particleModelDefHandle >= 0 ){ - gameRenderWorld->FreeEntityDef( particleModelDefHandle ); - } - memset( &particleRenderEntity, 0, sizeof ( particleRenderEntity ) ); - const idDeclModelDef *modelDef = static_cast( declManager->FindType( DECL_MODELDEF, name ) ); - if ( modelDef ) { - particleRenderEntity.origin = physicsObj.GetAbsBounds().GetCenter(); - particleRenderEntity.axis = mat3_identity; - particleRenderEntity.hModel = modelDef->ModelHandle(); - float rgb = ( burn ) ? 0.0f : 1.0f; - particleRenderEntity.shaderParms[ SHADERPARM_RED ] = rgb; - particleRenderEntity.shaderParms[ SHADERPARM_GREEN ] = rgb; - particleRenderEntity.shaderParms[ SHADERPARM_BLUE ] = rgb; - particleRenderEntity.shaderParms[ SHADERPARM_ALPHA ] = rgb; - particleRenderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.realClientTime ); - particleRenderEntity.shaderParms[ SHADERPARM_DIVERSITY ] = ( burn ) ? 1.0f : gameLocal.random.RandomInt( 90 ); -#ifdef _D3XP - particleRenderEntity.timeGroup = explicitTimeGroup; -#endif - if ( !particleRenderEntity.hModel ) { - particleRenderEntity.hModel = renderModelManager->FindModel( name ); - } - particleModelDefHandle = gameRenderWorld->AddEntityDef( &particleRenderEntity ); - if ( burn ) { - BecomeActive( TH_THINK ); - } - particleTime = gameLocal.realClientTime; - } - } -} - -/* -================ -idExplodingBarrel::AddLight -================ -*/ -void idExplodingBarrel::AddLight( const char *name, bool burn ) { - if ( lightDefHandle >= 0 ){ - gameRenderWorld->FreeLightDef( lightDefHandle ); - } - memset( &light, 0, sizeof ( light ) ); - light.axis = mat3_identity; - light.lightRadius.x = spawnArgs.GetFloat( "light_radius" ); - light.lightRadius.y = light.lightRadius.z = light.lightRadius.x; - light.origin = physicsObj.GetOrigin(); - light.origin.z += 128; - light.pointLight = true; - light.shader = declManager->FindMaterial( name ); - light.shaderParms[ SHADERPARM_RED ] = 2.0f; - light.shaderParms[ SHADERPARM_GREEN ] = 2.0f; - light.shaderParms[ SHADERPARM_BLUE ] = 2.0f; - light.shaderParms[ SHADERPARM_ALPHA ] = 2.0f; - lightDefHandle = gameRenderWorld->AddLightDef( &light ); - lightTime = gameLocal.realClientTime; - BecomeActive( TH_THINK ); -} - -/* -================ -idExplodingBarrel::ExplodingEffects -================ -*/ -void idExplodingBarrel::ExplodingEffects( void ) { - const char *temp; - - StartSound( "snd_explode", SND_CHANNEL_ANY, 0, false, NULL ); - - temp = spawnArgs.GetString( "model_damage" ); - if ( *temp != '\0' ) { - SetModel( temp ); - Show(); - } - - temp = spawnArgs.GetString( "model_detonate" ); - if ( *temp != '\0' ) { - AddParticles( temp, false ); - } - - temp = spawnArgs.GetString( "mtr_lightexplode" ); - if ( *temp != '\0' ) { - AddLight( temp, false ); - } - - temp = spawnArgs.GetString( "mtr_burnmark" ); - if ( *temp != '\0' ) { - gameLocal.ProjectDecal( GetPhysics()->GetOrigin(), GetPhysics()->GetGravity(), 128.0f, true, 96.0f, temp ); - } -} - -/* -================ -idExplodingBarrel::Killed -================ -*/ -void idExplodingBarrel::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) { - - if ( IsHidden() || state == EXPLODING || state == BURNING ) { - return; - } - - float f = spawnArgs.GetFloat( "burn" ); - if ( f > 0.0f && state == NORMAL ) { - state = BURNING; - PostEventSec( &EV_Explode, f ); - StartSound( "snd_burn", SND_CHANNEL_ANY, 0, false, NULL ); - AddParticles( spawnArgs.GetString ( "model_burn", "" ), true ); - return; - } else { - state = EXPLODING; - if ( gameLocal.isServer ) { - idBitMsg msg; - byte msgBuf[MAX_EVENT_PARAM_SIZE]; - - msg.Init( msgBuf, sizeof( msgBuf ) ); - msg.WriteInt( gameLocal.time ); - ServerSendEvent( EVENT_EXPLODE, &msg, false, -1 ); - } - } - - // do this before applying radius damage so the ent can trace to any damagable ents nearby - Hide(); - physicsObj.SetContents( 0 ); - - const char *splash = spawnArgs.GetString( "def_splash_damage", "damage_explosion" ); - if ( splash && *splash ) { - gameLocal.RadiusDamage( GetPhysics()->GetOrigin(), this, attacker, this, this, splash ); - } - - ExplodingEffects( ); - - //FIXME: need to precache all the debris stuff here and in the projectiles - const idKeyValue *kv = spawnArgs.MatchPrefix( "def_debris" ); - // bool first = true; - while ( kv ) { - const idDict *debris_args = gameLocal.FindEntityDefDict( kv->GetValue(), false ); - if ( debris_args ) { - idEntity *ent; - idVec3 dir; - idDebris *debris; - //if ( first ) { - dir = physicsObj.GetAxis()[1]; - // first = false; - //} else { - dir.x += gameLocal.random.CRandomFloat() * 4.0f; - dir.y += gameLocal.random.CRandomFloat() * 4.0f; - //dir.z = gameLocal.random.RandomFloat() * 8.0f; - //} - dir.Normalize(); - - gameLocal.SpawnEntityDef( *debris_args, &ent, false ); - if ( !ent || !ent->IsType( idDebris::Type ) ) { - gameLocal.Error( "'projectile_debris' is not an idDebris" ); - } - - debris = static_cast(ent); - debris->Create( this, physicsObj.GetOrigin(), dir.ToMat3() ); - debris->Launch(); - debris->GetRenderEntity()->shaderParms[ SHADERPARM_TIME_OF_DEATH ] = ( gameLocal.time + 1500 ) * 0.001f; - debris->UpdateVisuals(); - - } - kv = spawnArgs.MatchPrefix( "def_debris", kv ); - } - - physicsObj.PutToRest(); - CancelEvents( &EV_Explode ); - CancelEvents( &EV_Activate ); - - f = spawnArgs.GetFloat( "respawn" ); - if ( f > 0.0f ) { - PostEventSec( &EV_Respawn, f ); - } else { - PostEventMS( &EV_Remove, 5000 ); - } - - if ( spawnArgs.GetBool( "triggerTargets" ) ) { - ActivateTargets( this ); - } -} - -/* -================ -idExplodingBarrel::Damage -================ -*/ -void idExplodingBarrel::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, - const char *damageDefName, const float damageScale, const int location ) { - - const idDict *damageDef = gameLocal.FindEntityDefDict( damageDefName ); - if ( !damageDef ) { - gameLocal.Error( "Unknown damageDef '%s'\n", damageDefName ); - } - if ( damageDef->FindKey( "radius" ) && GetPhysics()->GetContents() != 0 && GetBindMaster() == NULL ) { - PostEventMS( &EV_Explode, 400 ); - } else { - idEntity::Damage( inflictor, attacker, dir, damageDefName, damageScale, location ); - } -} - -/* -================ -idExplodingBarrel::Event_TriggerTargets -================ -*/ -void idExplodingBarrel::Event_TriggerTargets() { - ActivateTargets( this ); -} - -/* -================ -idExplodingBarrel::Event_Explode -================ -*/ -void idExplodingBarrel::Event_Explode() { - if ( state == NORMAL || state == BURNING ) { - state = BURNEXPIRED; - Killed( NULL, NULL, 0, vec3_zero, 0 ); - } -} - -/* -================ -idExplodingBarrel::Event_Respawn -================ -*/ -void idExplodingBarrel::Event_Respawn() { - int i; - int minRespawnDist = spawnArgs.GetInt( "respawn_range", "256" ); - if ( minRespawnDist ) { - float minDist = -1; - for ( i = 0; i < gameLocal.numClients; i++ ) { - if ( !gameLocal.entities[ i ] || !gameLocal.entities[ i ]->IsType( idPlayer::Type ) ) { - continue; - } - idVec3 v = gameLocal.entities[ i ]->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin(); - float dist = v.Length(); - if ( minDist < 0 || dist < minDist ) { - minDist = dist; - } - } - if ( minDist < minRespawnDist ) { - PostEventSec( &EV_Respawn, spawnArgs.GetInt( "respawn_again", "10" ) ); - return; - } - } - const char *temp = spawnArgs.GetString( "model" ); - if ( temp && *temp ) { - SetModel( temp ); - } - health = spawnArgs.GetInt( "health", "5" ); - fl.takedamage = true; - physicsObj.SetOrigin( spawnOrigin ); - physicsObj.SetAxis( spawnAxis ); - physicsObj.SetContents( CONTENTS_SOLID ); - physicsObj.DropToFloor(); - state = NORMAL; - Show(); - UpdateVisuals(); -} - -/* -================ -idMoveable::Event_Activate -================ -*/ -void idExplodingBarrel::Event_Activate( idEntity *activator ) { - Killed( activator, activator, 0, vec3_origin, 0 ); -} - -/* -================ -idMoveable::WriteToSnapshot -================ -*/ -void idExplodingBarrel::WriteToSnapshot( idBitMsgDelta &msg ) const { - idMoveable::WriteToSnapshot( msg ); - msg.WriteBits( IsHidden(), 1 ); -} - -/* -================ -idMoveable::ReadFromSnapshot -================ -*/ -void idExplodingBarrel::ReadFromSnapshot( const idBitMsgDelta &msg ) { - - idMoveable::ReadFromSnapshot( msg ); - if ( msg.ReadBits( 1 ) ) { - Hide(); - } else { - Show(); - } -} - -/* -================ -idExplodingBarrel::ClientReceiveEvent -================ -*/ -bool idExplodingBarrel::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) { - - switch( event ) { - case EVENT_EXPLODE: - if ( gameLocal.realClientTime - msg.ReadInt() < spawnArgs.GetInt( "explode_lapse", "1000" ) ) { - ExplodingEffects( ); - } - return true; - default: - break; - } - - return idBarrel::ClientReceiveEvent( event, time, msg ); -} diff --git a/d3xp/Moveable.h b/d3xp/Moveable.h deleted file mode 100644 index 53f27514..00000000 --- a/d3xp/Moveable.h +++ /dev/null @@ -1,222 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __GAME_MOVEABLE_H__ -#define __GAME_MOVEABLE_H__ - -#include "physics/Physics_RigidBody.h" -#include "script/Script_Thread.h" -#include "gamesys/Event.h" -#include "Entity.h" -#include "Player.h" -#include "Projectile.h" - -/* -=============================================================================== - - Entity using rigid body physics. - -=============================================================================== -*/ - -extern const idEventDef EV_BecomeNonSolid; -extern const idEventDef EV_IsAtRest; - -class idMoveable : public idEntity { -public: - CLASS_PROTOTYPE( idMoveable ); - - idMoveable( void ); - ~idMoveable( void ); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - virtual void Think( void ); - - virtual void Hide( void ); - virtual void Show( void ); - - bool AllowStep( void ) const; - void EnableDamage( bool enable, float duration ); - virtual bool Collide( const trace_t &collision, const idVec3 &velocity ); - virtual void Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ); - virtual void WriteToSnapshot( idBitMsgDelta &msg ) const; - virtual void ReadFromSnapshot( const idBitMsgDelta &msg ); - -#ifdef _D3XP - void SetAttacker( idEntity *ent ); -#endif - -protected: - idPhysics_RigidBody physicsObj; // physics object - idStr brokenModel; // model set when health drops down to or below zero - idStr damage; // if > 0 apply damage to hit entities -#ifdef _D3XP - idStr monsterDamage; - idEntity *attacker; -#endif - idStr fxCollide; // fx system to start when collides with something - int nextCollideFxTime; // next time it is ok to spawn collision fx - float minDamageVelocity; // minimum velocity before moveable applies damage - float maxDamageVelocity; // velocity at which the maximum damage is applied - idCurve_Spline *initialSpline; // initial spline path the moveable follows - idVec3 initialSplineDir; // initial relative direction along the spline path - bool explode; // entity explodes when health drops down to or below zero - bool unbindOnDeath; // unbind from master when health drops down to or below zero - bool allowStep; // allow monsters to step on the object - bool canDamage; // only apply damage when this is set - int nextDamageTime; // next time the movable can hurt the player - int nextSoundTime; // next time the moveable can make a sound - - const idMaterial * GetRenderModelMaterial( void ) const; - void BecomeNonSolid( void ); - void InitInitialSpline( int startTime ); - bool FollowInitialSplinePath( void ); - - void Event_Activate( idEntity *activator ); - void Event_BecomeNonSolid( void ); - void Event_SetOwnerFromSpawnArgs( void ); - void Event_IsAtRest( void ); - void Event_EnableDamage( float enable ); -}; - - -/* -=============================================================================== - - A barrel using rigid body physics. The barrel has special handling of - the view model orientation to make it look like it rolls instead of slides. - -=============================================================================== -*/ - -class idBarrel : public idMoveable { - -public: - CLASS_PROTOTYPE( idBarrel ); - idBarrel(); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void BarrelThink( void ); - virtual void Think( void ); - virtual bool GetPhysicsToVisualTransform( idVec3 &origin, idMat3 &axis ); - virtual void ClientPredictionThink( void ); - -private: - float radius; // radius of barrel - int barrelAxis; // one of the coordinate axes the barrel cylinder is parallel to - idVec3 lastOrigin; // origin of the barrel the last think frame - idMat3 lastAxis; // axis of the barrel the last think frame - float additionalRotation; // additional rotation of the barrel about it's axis - idMat3 additionalAxis; // additional rotation axis -}; - - -/* -=============================================================================== - - A barrel using rigid body physics and special handling of the view model - orientation to make it look like it rolls instead of slides. The barrel - can burn and explode when damaged. - -=============================================================================== -*/ - -class idExplodingBarrel : public idBarrel { -public: - CLASS_PROTOTYPE( idExplodingBarrel ); - - idExplodingBarrel(); - ~idExplodingBarrel(); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - -#ifdef _D3XP - bool IsStable( void ); - void SetStability( bool stability ); - void StartBurning( void ); - void StopBurning( void ); -#endif - - virtual void Think( void ); - virtual void Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, - const char *damageDefName, const float damageScale, const int location ); - virtual void Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ); - - virtual void WriteToSnapshot( idBitMsgDelta &msg ) const; - virtual void ReadFromSnapshot( const idBitMsgDelta &msg ); - virtual bool ClientReceiveEvent( int event, int time, const idBitMsg &msg ); - - enum { - EVENT_EXPLODE = idEntity::EVENT_MAXEVENTS, - EVENT_MAXEVENTS - }; - -private: - typedef enum { - NORMAL = 0, - BURNING, - BURNEXPIRED, - EXPLODING - } explode_state_t; - explode_state_t state; - - idVec3 spawnOrigin; - idMat3 spawnAxis; - qhandle_t particleModelDefHandle; - qhandle_t lightDefHandle; - renderEntity_t particleRenderEntity; - renderLight_t light; - int particleTime; - int lightTime; - float time; -#ifdef _D3XP - bool isStable; -#endif - - void AddParticles( const char *name, bool burn ); - void AddLight( const char *name , bool burn ); - void ExplodingEffects( void ); - - void Event_Activate( idEntity *activator ); - void Event_Respawn(); - void Event_Explode(); - void Event_TriggerTargets(); -}; - -#endif /* !__GAME_MOVEABLE_H__ */ diff --git a/d3xp/Mover.cpp b/d3xp/Mover.cpp deleted file mode 100644 index 4e4160fb..00000000 --- a/d3xp/Mover.cpp +++ /dev/null @@ -1,4695 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "gamesys/SysCvar.h" -#include "script/Script_Thread.h" -#include "Player.h" - -#include "Mover.h" - -// _D3XP : rename all gameLocal.time to gameLocal.slow.time for merge! - -// a mover will update any gui entities in it's target list with -// a key/val pair of "mover" "state" from below.. guis can represent -// realtime info like this -// binary only -static const char *guiBinaryMoverStates[] = { - "1", // pos 1 - "2", // pos 2 - "3", // moving 1 to 2 - "4" // moving 2 to 1 -}; - - -/* -=============================================================================== - -idMover - -=============================================================================== -*/ - -const idEventDef EV_FindGuiTargets( "", NULL ); -const idEventDef EV_TeamBlocked( "", "ee" ); -const idEventDef EV_PartBlocked( "", "e" ); -const idEventDef EV_ReachedPos( "", NULL ); -const idEventDef EV_ReachedAng( "", NULL ); -const idEventDef EV_PostRestore( "", "ddddd" ); -const idEventDef EV_StopMoving( "stopMoving", NULL ); -const idEventDef EV_StopRotating( "stopRotating", NULL ); -const idEventDef EV_Speed( "speed", "f" ); -const idEventDef EV_Time( "time", "f" ); -const idEventDef EV_AccelTime( "accelTime", "f" ); -const idEventDef EV_DecelTime( "decelTime", "f" ); -const idEventDef EV_MoveTo( "moveTo", "e" ); -const idEventDef EV_MoveToPos( "moveToPos", "v" ); -const idEventDef EV_Move( "move", "ff" ); -const idEventDef EV_MoveAccelerateTo( "accelTo", "ff" ); -const idEventDef EV_MoveDecelerateTo( "decelTo", "ff" ); -const idEventDef EV_RotateDownTo( "rotateDownTo", "df" ); -const idEventDef EV_RotateUpTo( "rotateUpTo", "df" ); -const idEventDef EV_RotateTo( "rotateTo", "v" ); -const idEventDef EV_Rotate( "rotate", "v" ); -const idEventDef EV_RotateOnce( "rotateOnce", "v" ); -const idEventDef EV_Bob( "bob", "ffv" ); -const idEventDef EV_Sway( "sway", "ffv" ); -const idEventDef EV_Mover_OpenPortal( "openPortal" ); -const idEventDef EV_Mover_ClosePortal( "closePortal" ); -const idEventDef EV_AccelSound( "accelSound", "s" ); -const idEventDef EV_DecelSound( "decelSound", "s" ); -const idEventDef EV_MoveSound( "moveSound", "s" ); -const idEventDef EV_Mover_InitGuiTargets( "", NULL ); -const idEventDef EV_EnableSplineAngles( "enableSplineAngles", NULL ); -const idEventDef EV_DisableSplineAngles( "disableSplineAngles", NULL ); -const idEventDef EV_RemoveInitialSplineAngles( "removeInitialSplineAngles", NULL ); -const idEventDef EV_StartSpline( "startSpline", "e" ); -const idEventDef EV_StopSpline( "stopSpline", NULL ); -const idEventDef EV_IsMoving( "isMoving", NULL, 'd' ); -const idEventDef EV_IsRotating( "isRotating", NULL, 'd' ); - -CLASS_DECLARATION( idEntity, idMover ) - EVENT( EV_FindGuiTargets, idMover::Event_FindGuiTargets ) - EVENT( EV_Thread_SetCallback, idMover::Event_SetCallback ) - EVENT( EV_TeamBlocked, idMover::Event_TeamBlocked ) - EVENT( EV_PartBlocked, idMover::Event_PartBlocked ) - EVENT( EV_ReachedPos, idMover::Event_UpdateMove ) - EVENT( EV_ReachedAng, idMover::Event_UpdateRotation ) - EVENT( EV_PostRestore, idMover::Event_PostRestore ) - EVENT( EV_StopMoving, idMover::Event_StopMoving ) - EVENT( EV_StopRotating, idMover::Event_StopRotating ) - EVENT( EV_Speed, idMover::Event_SetMoveSpeed ) - EVENT( EV_Time, idMover::Event_SetMoveTime ) - EVENT( EV_AccelTime, idMover::Event_SetAccellerationTime ) - EVENT( EV_DecelTime, idMover::Event_SetDecelerationTime ) - EVENT( EV_MoveTo, idMover::Event_MoveTo ) - EVENT( EV_MoveToPos, idMover::Event_MoveToPos ) - EVENT( EV_Move, idMover::Event_MoveDir ) - EVENT( EV_MoveAccelerateTo, idMover::Event_MoveAccelerateTo ) - EVENT( EV_MoveDecelerateTo, idMover::Event_MoveDecelerateTo ) - EVENT( EV_RotateDownTo, idMover::Event_RotateDownTo ) - EVENT( EV_RotateUpTo, idMover::Event_RotateUpTo ) - EVENT( EV_RotateTo, idMover::Event_RotateTo ) - EVENT( EV_Rotate, idMover::Event_Rotate ) - EVENT( EV_RotateOnce, idMover::Event_RotateOnce ) - EVENT( EV_Bob, idMover::Event_Bob ) - EVENT( EV_Sway, idMover::Event_Sway ) - EVENT( EV_Mover_OpenPortal, idMover::Event_OpenPortal ) - EVENT( EV_Mover_ClosePortal, idMover::Event_ClosePortal ) - EVENT( EV_AccelSound, idMover::Event_SetAccelSound ) - EVENT( EV_DecelSound, idMover::Event_SetDecelSound ) - EVENT( EV_MoveSound, idMover::Event_SetMoveSound ) - EVENT( EV_Mover_InitGuiTargets, idMover::Event_InitGuiTargets ) - EVENT( EV_EnableSplineAngles, idMover::Event_EnableSplineAngles ) - EVENT( EV_DisableSplineAngles, idMover::Event_DisableSplineAngles ) - EVENT( EV_RemoveInitialSplineAngles, idMover::Event_RemoveInitialSplineAngles ) - EVENT( EV_StartSpline, idMover::Event_StartSpline ) - EVENT( EV_StopSpline, idMover::Event_StopSpline ) - EVENT( EV_Activate, idMover::Event_Activate ) - EVENT( EV_IsMoving, idMover::Event_IsMoving ) - EVENT( EV_IsRotating, idMover::Event_IsRotating ) -END_CLASS - -/* -================ -idMover::idMover -================ -*/ -idMover::idMover( void ) { - memset( &move, 0, sizeof( move ) ); - memset( &rot, 0, sizeof( rot ) ); - move_thread = 0; - rotate_thread = 0; - dest_angles.Zero(); - angle_delta.Zero(); - dest_position.Zero(); - move_delta.Zero(); - move_speed = 0.0f; - move_time = 0; - deceltime = 0; - acceltime = 0; - stopRotation = false; - useSplineAngles = true; - lastCommand = MOVER_NONE; - damage = 0.0f; - areaPortal = 0; - fl.networkSync = true; -} - -/* -================ -idMover::Save -================ -*/ -void idMover::Save( idSaveGame *savefile ) const { - int i; - - savefile->WriteStaticObject( physicsObj ); - - savefile->WriteInt( move.stage ); - savefile->WriteInt( move.acceleration ); - savefile->WriteInt( move.movetime ); - savefile->WriteInt( move.deceleration ); - savefile->WriteVec3( move.dir ); - - savefile->WriteInt( rot.stage ); - savefile->WriteInt( rot.acceleration ); - savefile->WriteInt( rot.movetime ); - savefile->WriteInt( rot.deceleration ); - savefile->WriteFloat( rot.rot.pitch ); - savefile->WriteFloat( rot.rot.yaw ); - savefile->WriteFloat( rot.rot.roll ); - - savefile->WriteInt( move_thread ); - savefile->WriteInt( rotate_thread ); - - savefile->WriteAngles( dest_angles ); - savefile->WriteAngles( angle_delta ); - savefile->WriteVec3( dest_position ); - savefile->WriteVec3( move_delta ); - - savefile->WriteFloat( move_speed ); - savefile->WriteInt( move_time ); - savefile->WriteInt( deceltime ); - savefile->WriteInt( acceltime ); - savefile->WriteBool( stopRotation ); - savefile->WriteBool( useSplineAngles ); - savefile->WriteInt( lastCommand ); - savefile->WriteFloat( damage ); - - savefile->WriteInt( areaPortal ); - if ( areaPortal > 0 ) { - savefile->WriteInt( gameRenderWorld->GetPortalState( areaPortal ) ); - } - - savefile->WriteInt( guiTargets.Num() ); - for( i = 0; i < guiTargets.Num(); i++ ) { - guiTargets[ i ].Save( savefile ); - } - - if ( splineEnt.GetEntity() && splineEnt.GetEntity()->GetSpline() ) { - idCurve_Spline *spline = physicsObj.GetSpline(); - - savefile->WriteBool( true ); - splineEnt.Save( savefile ); - savefile->WriteInt( spline->GetTime( 0 ) ); - savefile->WriteInt( spline->GetTime( spline->GetNumValues() - 1 ) - spline->GetTime( 0 ) ); - savefile->WriteInt( physicsObj.GetSplineAcceleration() ); - savefile->WriteInt( physicsObj.GetSplineDeceleration() ); - savefile->WriteInt( (int)physicsObj.UsingSplineAngles() ); - - } else { - savefile->WriteBool( false ); - } -} - -/* -================ -idMover::Restore -================ -*/ -void idMover::Restore( idRestoreGame *savefile ) { - int i, num; - bool hasSpline = false; - - savefile->ReadStaticObject( physicsObj ); - RestorePhysics( &physicsObj ); - - savefile->ReadInt( (int&)move.stage ); - savefile->ReadInt( move.acceleration ); - savefile->ReadInt( move.movetime ); - savefile->ReadInt( move.deceleration ); - savefile->ReadVec3( move.dir ); - - savefile->ReadInt( (int&)rot.stage ); - savefile->ReadInt( rot.acceleration ); - savefile->ReadInt( rot.movetime ); - savefile->ReadInt( rot.deceleration ); - savefile->ReadFloat( rot.rot.pitch ); - savefile->ReadFloat( rot.rot.yaw ); - savefile->ReadFloat( rot.rot.roll ); - - savefile->ReadInt( move_thread ); - savefile->ReadInt( rotate_thread ); - - savefile->ReadAngles( dest_angles ); - savefile->ReadAngles( angle_delta ); - savefile->ReadVec3( dest_position ); - savefile->ReadVec3( move_delta ); - - savefile->ReadFloat( move_speed ); - savefile->ReadInt( move_time ); - savefile->ReadInt( deceltime ); - savefile->ReadInt( acceltime ); - savefile->ReadBool( stopRotation ); - savefile->ReadBool( useSplineAngles ); - savefile->ReadInt( (int &)lastCommand ); - savefile->ReadFloat( damage ); - - savefile->ReadInt( areaPortal ); - if ( areaPortal > 0 ) { - int portalState = 0; - savefile->ReadInt( portalState ); - gameLocal.SetPortalState( areaPortal, portalState ); - } - - guiTargets.Clear(); - savefile->ReadInt( num ); - guiTargets.SetNum( num ); - for( i = 0; i < num; i++ ) { - guiTargets[ i ].Restore( savefile ); - } - - savefile->ReadBool( hasSpline ); - if ( hasSpline ) { - int starttime; - int totaltime; - int accel; - int decel; - int useAngles; - - splineEnt.Restore( savefile ); - savefile->ReadInt( starttime ); - savefile->ReadInt( totaltime ); - savefile->ReadInt( accel ); - savefile->ReadInt( decel ); - savefile->ReadInt( useAngles ); - - PostEventMS( &EV_PostRestore, 0, starttime, totaltime, accel, decel, useAngles ); - } -} - -/* -================ -idMover::Event_PostRestore -================ -*/ -void idMover::Event_PostRestore( int start, int total, int accel, int decel, int useSplineAng ) { - idCurve_Spline *spline; - - idEntity *splineEntity = splineEnt.GetEntity(); - if ( !splineEntity ) { - // We should never get this event if splineEnt is invalid - common->Warning( "Invalid spline entity during restore\n" ); - return; - } - - spline = splineEntity->GetSpline(); - - spline->MakeUniform( total ); - spline->ShiftTime( start - spline->GetTime( 0 ) ); - - physicsObj.SetSpline( spline, accel, decel, ( useSplineAng != 0 ) ); - physicsObj.SetLinearExtrapolation( EXTRAPOLATION_NONE, 0, 0, dest_position, vec3_origin, vec3_origin ); -} - -/* -================ -idMover::Spawn -================ -*/ -void idMover::Spawn( void ) { - move_thread = 0; - rotate_thread = 0; - stopRotation = false; - lastCommand = MOVER_NONE; - - acceltime = 1000.0f * spawnArgs.GetFloat( "accel_time", "0" ); - deceltime = 1000.0f * spawnArgs.GetFloat( "decel_time", "0" ); - move_time = 1000.0f * spawnArgs.GetFloat( "move_time", "1" ); // safe default value - move_speed = spawnArgs.GetFloat( "move_speed", "0" ); - - spawnArgs.GetFloat( "damage" , "0", damage ); - - dest_position = GetPhysics()->GetOrigin(); - dest_angles = GetPhysics()->GetAxis().ToAngles(); - - physicsObj.SetSelf( this ); - physicsObj.SetClipModel( new idClipModel( GetPhysics()->GetClipModel() ), 1.0f ); - physicsObj.SetOrigin( GetPhysics()->GetOrigin() ); - physicsObj.SetAxis( GetPhysics()->GetAxis() ); - physicsObj.SetClipMask( MASK_SOLID ); - if ( !spawnArgs.GetBool( "solid", "1" ) ) { - physicsObj.SetContents( 0 ); - } - if ( !renderEntity.hModel || !spawnArgs.GetBool( "nopush" ) ) { - physicsObj.SetPusher( 0 ); - } - physicsObj.SetLinearExtrapolation( EXTRAPOLATION_NONE, 0, 0, dest_position, vec3_origin, vec3_origin ); - physicsObj.SetAngularExtrapolation( EXTRAPOLATION_NONE, 0, 0, dest_angles, ang_zero, ang_zero ); - SetPhysics( &physicsObj ); - - // see if we are on an areaportal - areaPortal = gameRenderWorld->FindPortal( GetPhysics()->GetAbsBounds() ); - - if ( spawnArgs.MatchPrefix( "guiTarget" ) ) { - if ( gameLocal.GameState() == GAMESTATE_STARTUP ) { - PostEventMS( &EV_FindGuiTargets, 0 ); - } else { - // not during spawn, so it's ok to get the targets - FindGuiTargets(); - } - } - - health = spawnArgs.GetInt( "health" ); - if ( health ) { - fl.takedamage = true; - } - -} - -/* -================ -idMover::Hide -================ -*/ -void idMover::Hide( void ) { - idEntity::Hide(); - physicsObj.SetContents( 0 ); -} - -/* -================ -idMover::Show -================ -*/ -void idMover::Show( void ) { - idEntity::Show(); - if ( spawnArgs.GetBool( "solid", "1" ) ) { - physicsObj.SetContents( CONTENTS_SOLID ); - } - SetPhysics( &physicsObj ); -} - -/* -============ -idMover::Killed -============ -*/ -void idMover::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) { - fl.takedamage = false; - ActivateTargets( this ); -} - - -/* -================ -idMover::Event_SetCallback -================ -*/ -void idMover::Event_SetCallback( void ) { - if ( ( lastCommand == MOVER_ROTATING ) && !rotate_thread ) { - lastCommand = MOVER_NONE; - rotate_thread = idThread::CurrentThreadNum(); - idThread::ReturnInt( true ); - } else if ( ( lastCommand == MOVER_MOVING || lastCommand == MOVER_SPLINE ) && !move_thread ) { - lastCommand = MOVER_NONE; - move_thread = idThread::CurrentThreadNum(); - idThread::ReturnInt( true ); - } else { - idThread::ReturnInt( false ); - } -} - -/* -================ -idMover::VectorForDir -================ -*/ -void idMover::VectorForDir( float angle, idVec3 &vec ) { - idAngles ang; - - switch( ( int )angle ) { - case DIR_UP : - vec.Set( 0, 0, 1 ); - break; - - case DIR_DOWN : - vec.Set( 0, 0, -1 ); - break; - - case DIR_LEFT : - physicsObj.GetLocalAngles( ang ); - ang.pitch = 0; - ang.roll = 0; - ang.yaw += 90; - vec = ang.ToForward(); - break; - - case DIR_RIGHT : - physicsObj.GetLocalAngles( ang ); - ang.pitch = 0; - ang.roll = 0; - ang.yaw -= 90; - vec = ang.ToForward(); - break; - - case DIR_FORWARD : - physicsObj.GetLocalAngles( ang ); - ang.pitch = 0; - ang.roll = 0; - vec = ang.ToForward(); - break; - - case DIR_BACK : - physicsObj.GetLocalAngles( ang ); - ang.pitch = 0; - ang.roll = 0; - ang.yaw += 180; - vec = ang.ToForward(); - break; - - case DIR_REL_UP : - vec.Set( 0, 0, 1 ); - break; - - case DIR_REL_DOWN : - vec.Set( 0, 0, -1 ); - break; - - case DIR_REL_LEFT : - physicsObj.GetLocalAngles( ang ); - ang.ToVectors( NULL, &vec ); - vec *= -1; - break; - - case DIR_REL_RIGHT : - physicsObj.GetLocalAngles( ang ); - ang.ToVectors( NULL, &vec ); - break; - - case DIR_REL_FORWARD : - physicsObj.GetLocalAngles( ang ); - vec = ang.ToForward(); - break; - - case DIR_REL_BACK : - physicsObj.GetLocalAngles( ang ); - vec = ang.ToForward() * -1; - break; - - default: - ang.Set( 0, angle, 0 ); - vec = GetWorldVector( ang.ToForward() ); - break; - } -} - -/* -================ -idMover::FindGuiTargets -================ -*/ -void idMover::FindGuiTargets( void ) { - gameLocal.GetTargets( spawnArgs, guiTargets, "guiTarget" ); -} - -/* -============================== -idMover::SetGuiState - -key/val will be set to any renderEntity->gui's on the list -============================== -*/ -void idMover::SetGuiState( const char *key, const char *val ) const { - gameLocal.Printf( "Setting %s to %s\n", key, val ); - for( int i = 0; i < guiTargets.Num(); i++ ) { - idEntity *ent = guiTargets[ i ].GetEntity(); - if ( ent ) { - for ( int j = 0; j < MAX_RENDERENTITY_GUI; j++ ) { - if ( ent->GetRenderEntity() && ent->GetRenderEntity()->gui[ j ] ) { - ent->GetRenderEntity()->gui[ j ]->SetStateString( key, val ); - ent->GetRenderEntity()->gui[ j ]->StateChanged( gameLocal.slow.time, true ); - } - } - ent->UpdateVisuals(); - } - } -} - -/* -================ -idMover::Event_InitGuiTargets -================ -*/ -void idMover::Event_FindGuiTargets( void ) { - FindGuiTargets(); -} - -/* -================ -idMover::SetGuiStates -================ -*/ -void idMover::SetGuiStates( const char *state ) { - int i; - if ( guiTargets.Num() ) { - SetGuiState( "movestate", state ); - } - for ( i = 0; i < MAX_RENDERENTITY_GUI; i++ ) { - if ( renderEntity.gui[ i ] ) { - renderEntity.gui[ i ]->SetStateString( "movestate", state ); - renderEntity.gui[ i ]->StateChanged( gameLocal.slow.time, true ); - } - } -} - -/* -================ -idMover::Event_InitGuiTargets -================ -*/ -void idMover::Event_InitGuiTargets( void ) { - SetGuiStates( guiBinaryMoverStates[MOVER_POS1] ); -} - -/*********************************************************************** - - Translation control functions - -***********************************************************************/ - -/* -================ -idMover::Event_StopMoving -================ -*/ -void idMover::Event_StopMoving( void ) { - physicsObj.GetLocalOrigin( dest_position ); - DoneMoving(); -} - -/* -================ -idMover::DoneMoving -================ -*/ -void idMover::DoneMoving( void ) { - - if ( lastCommand != MOVER_SPLINE ) { - // set our final position so that we get rid of any numerical inaccuracy - physicsObj.SetLinearExtrapolation( EXTRAPOLATION_NONE, 0, 0, dest_position, vec3_origin, vec3_origin ); - } - - lastCommand = MOVER_NONE; - idThread::ObjectMoveDone( move_thread, this ); - move_thread = 0; - - StopSound( SND_CHANNEL_BODY, false ); -} - -/* -================ -idMover::UpdateMoveSound -================ -*/ -void idMover::UpdateMoveSound( moveStage_t stage ) { - switch( stage ) { - case ACCELERATION_STAGE: { - StartSound( "snd_accel", SND_CHANNEL_BODY2, 0, false, NULL ); - StartSound( "snd_move", SND_CHANNEL_BODY, 0, false, NULL ); - break; - } - case LINEAR_STAGE: { - StartSound( "snd_move", SND_CHANNEL_BODY, 0, false, NULL ); - break; - } - case DECELERATION_STAGE: { - StopSound( SND_CHANNEL_BODY, false ); - StartSound( "snd_decel", SND_CHANNEL_BODY2, 0, false, NULL ); - break; - } - case FINISHED_STAGE: { - StopSound( SND_CHANNEL_BODY, false ); - break; - } - } -} - -/* -================ -idMover::Event_UpdateMove -================ -*/ -void idMover::Event_UpdateMove( void ) { - idVec3 org; - - physicsObj.GetLocalOrigin( org ); - - UpdateMoveSound( move.stage ); - - switch( move.stage ) { - case ACCELERATION_STAGE: { - physicsObj.SetLinearExtrapolation( EXTRAPOLATION_ACCELLINEAR, gameLocal.slow.time, move.acceleration, org, move.dir, vec3_origin ); - if ( move.movetime > 0 ) { - move.stage = LINEAR_STAGE; - } else if ( move.deceleration > 0 ) { - move.stage = DECELERATION_STAGE; - } else { - move.stage = FINISHED_STAGE; - } - break; - } - case LINEAR_STAGE: { - physicsObj.SetLinearExtrapolation( EXTRAPOLATION_LINEAR, gameLocal.slow.time, move.movetime, org, move.dir, vec3_origin ); - if ( move.deceleration ) { - move.stage = DECELERATION_STAGE; - } else { - move.stage = FINISHED_STAGE; - } - break; - } - case DECELERATION_STAGE: { - physicsObj.SetLinearExtrapolation( EXTRAPOLATION_DECELLINEAR, gameLocal.slow.time, move.deceleration, org, move.dir, vec3_origin ); - move.stage = FINISHED_STAGE; - break; - } - case FINISHED_STAGE: { - if ( g_debugMover.GetBool() ) { - gameLocal.Printf( "%d: '%s' move done\n", gameLocal.slow.time, name.c_str() ); - } - DoneMoving(); - break; - } - } -} - -/* -================ -idMover::BeginMove -================ -*/ -void idMover::BeginMove( idThread *thread ) { - moveStage_t stage; - idVec3 org; - float dist; - float acceldist; - int totalacceltime; - int at; - int dt; - - lastCommand = MOVER_MOVING; - move_thread = 0; - - physicsObj.GetLocalOrigin( org ); - - move_delta = dest_position - org; - if ( move_delta.Compare( vec3_zero ) ) { - DoneMoving(); - return; - } - - // scale times up to whole physics frames - at = idPhysics::SnapTimeToPhysicsFrame( acceltime ); - move_time += at - acceltime; - acceltime = at; - dt = idPhysics::SnapTimeToPhysicsFrame( deceltime ); - move_time += dt - deceltime; - deceltime = dt; - - // if we're moving at a specific speed, we need to calculate the move time - if ( move_speed ) { - dist = move_delta.Length(); - - totalacceltime = acceltime + deceltime; - - // calculate the distance we'll move during acceleration and deceleration - acceldist = totalacceltime * 0.5f * 0.001f * move_speed; - if ( acceldist >= dist ) { - // going too slow for this distance to move at a constant speed - move_time = totalacceltime; - } else { - // calculate move time taking acceleration into account - move_time = totalacceltime + 1000.0f * ( dist - acceldist ) / move_speed; - } - } - - // scale time up to a whole physics frames - move_time = idPhysics::SnapTimeToPhysicsFrame( move_time ); - - if ( acceltime ) { - stage = ACCELERATION_STAGE; - } else if ( move_time <= deceltime ) { - stage = DECELERATION_STAGE; - } else { - stage = LINEAR_STAGE; - } - - at = acceltime; - dt = deceltime; - - if ( at + dt > move_time ) { - // there's no real correct way to handle this, so we just scale - // the times to fit into the move time in the same proportions - at = idPhysics::SnapTimeToPhysicsFrame( at * move_time / ( at + dt ) ); - dt = move_time - at; - } - - move_delta = move_delta * ( 1000.0f / ( (float) move_time - ( at + dt ) * 0.5f ) ); - - move.stage = stage; - move.acceleration = at; - move.movetime = move_time - at - dt; - move.deceleration = dt; - move.dir = move_delta; - - ProcessEvent( &EV_ReachedPos ); -} - -/*********************************************************************** - - Rotation control functions - -***********************************************************************/ - -/* -================ -idMover::Event_StopRotating -================ -*/ -void idMover::Event_StopRotating( void ) { - physicsObj.GetLocalAngles( dest_angles ); - physicsObj.SetAngularExtrapolation( EXTRAPOLATION_NONE, 0, 0, dest_angles, ang_zero, ang_zero ); - DoneRotating(); -} - -/* -================ -idMover::DoneRotating -================ -*/ -void idMover::DoneRotating( void ) { - lastCommand = MOVER_NONE; - idThread::ObjectMoveDone( rotate_thread, this ); - rotate_thread = 0; - - StopSound( SND_CHANNEL_BODY, false ); -} - -/* -================ -idMover::UpdateRotationSound -================ -*/ -void idMover::UpdateRotationSound( moveStage_t stage ) { - switch( stage ) { - case ACCELERATION_STAGE: { - StartSound( "snd_accel", SND_CHANNEL_BODY2, 0, false, NULL ); - StartSound( "snd_move", SND_CHANNEL_BODY, 0, false, NULL ); - break; - } - case LINEAR_STAGE: { - StartSound( "snd_move", SND_CHANNEL_BODY, 0, false, NULL ); - break; - } - case DECELERATION_STAGE: { - StopSound( SND_CHANNEL_BODY, false ); - StartSound( "snd_decel", SND_CHANNEL_BODY2, 0, false, NULL ); - break; - } - case FINISHED_STAGE: { - StopSound( SND_CHANNEL_BODY, false ); - break; - } - } -} - -/* -================ -idMover::Event_UpdateRotation -================ -*/ -void idMover::Event_UpdateRotation( void ) { - idAngles ang; - - physicsObj.GetLocalAngles( ang ); - - UpdateRotationSound( rot.stage ); - - switch( rot.stage ) { - case ACCELERATION_STAGE: { - physicsObj.SetAngularExtrapolation( EXTRAPOLATION_ACCELLINEAR, gameLocal.slow.time, rot.acceleration, ang, rot.rot, ang_zero ); - if ( rot.movetime > 0 ) { - rot.stage = LINEAR_STAGE; - } else if ( rot.deceleration > 0 ) { - rot.stage = DECELERATION_STAGE; - } else { - rot.stage = FINISHED_STAGE; - } - break; - } - case LINEAR_STAGE: { - if ( !stopRotation && !rot.deceleration ) { - physicsObj.SetAngularExtrapolation( extrapolation_t(EXTRAPOLATION_LINEAR|EXTRAPOLATION_NOSTOP), gameLocal.slow.time, rot.movetime, ang, rot.rot, ang_zero ); - } else { - physicsObj.SetAngularExtrapolation( EXTRAPOLATION_LINEAR, gameLocal.slow.time, rot.movetime, ang, rot.rot, ang_zero ); - } - - if ( rot.deceleration ) { - rot.stage = DECELERATION_STAGE; - } else { - rot.stage = FINISHED_STAGE; - } - break; - } - case DECELERATION_STAGE: { - physicsObj.SetAngularExtrapolation( EXTRAPOLATION_DECELLINEAR, gameLocal.slow.time, rot.deceleration, ang, rot.rot, ang_zero ); - rot.stage = FINISHED_STAGE; - break; - } - case FINISHED_STAGE: { - lastCommand = MOVER_NONE; - if ( stopRotation ) { - // set our final angles so that we get rid of any numerical inaccuracy - dest_angles.Normalize360(); - physicsObj.SetAngularExtrapolation( EXTRAPOLATION_NONE, 0, 0, dest_angles, ang_zero, ang_zero ); - stopRotation = false; - } else if ( physicsObj.GetAngularExtrapolationType() == EXTRAPOLATION_ACCELLINEAR ) { - // keep our angular velocity constant - physicsObj.SetAngularExtrapolation( extrapolation_t(EXTRAPOLATION_LINEAR|EXTRAPOLATION_NOSTOP), gameLocal.slow.time, 0, ang, rot.rot, ang_zero ); - } - - if ( g_debugMover.GetBool() ) { - gameLocal.Printf( "%d: '%s' rotation done\n", gameLocal.slow.time, name.c_str() ); - } - - DoneRotating(); - break; - } - } -} - -/* -================ -idMover::BeginRotation -================ -*/ -void idMover::BeginRotation( idThread *thread, bool stopwhendone ) { - moveStage_t stage; - idAngles ang; - int at; - int dt; - - lastCommand = MOVER_ROTATING; - rotate_thread = 0; - - // rotation always uses move_time so that if a move was started before the rotation, - // the rotation will take the same amount of time as the move. If no move has been - // started and no time is set, the rotation takes 1 second. - if ( !move_time ) { - move_time = 1; - } - - physicsObj.GetLocalAngles( ang ); - angle_delta = dest_angles - ang; - if ( angle_delta == ang_zero ) { - // set our final angles so that we get rid of any numerical inaccuracy - dest_angles.Normalize360(); - physicsObj.SetAngularExtrapolation( EXTRAPOLATION_NONE, 0, 0, dest_angles, ang_zero, ang_zero ); - stopRotation = false; - DoneRotating(); - return; - } - - // scale times up to whole physics frames - at = idPhysics::SnapTimeToPhysicsFrame( acceltime ); - move_time += at - acceltime; - acceltime = at; - dt = idPhysics::SnapTimeToPhysicsFrame( deceltime ); - move_time += dt - deceltime; - deceltime = dt; - move_time = idPhysics::SnapTimeToPhysicsFrame( move_time ); - - if ( acceltime ) { - stage = ACCELERATION_STAGE; - } else if ( move_time <= deceltime ) { - stage = DECELERATION_STAGE; - } else { - stage = LINEAR_STAGE; - } - - at = acceltime; - dt = deceltime; - - if ( at + dt > move_time ) { - // there's no real correct way to handle this, so we just scale - // the times to fit into the move time in the same proportions - at = idPhysics::SnapTimeToPhysicsFrame( at * move_time / ( at + dt ) ); - dt = move_time - at; - } - - angle_delta = angle_delta * ( 1000.0f / ( (float) move_time - ( at + dt ) * 0.5f ) ); - - stopRotation = stopwhendone || ( dt != 0 ); - - rot.stage = stage; - rot.acceleration = at; - rot.movetime = move_time - at - dt; - rot.deceleration = dt; - rot.rot = angle_delta; - - ProcessEvent( &EV_ReachedAng ); -} - - -/*********************************************************************** - - Script callable routines - -***********************************************************************/ - -/* -=============== -idMover::Event_TeamBlocked -=============== -*/ -void idMover::Event_TeamBlocked( idEntity *blockedEntity, idEntity *blockingEntity ) { - if ( g_debugMover.GetBool() ) { - gameLocal.Printf( "%d: '%s' stopped due to team member '%s' blocked by '%s'\n", gameLocal.slow.time, name.c_str(), blockedEntity->name.c_str(), blockingEntity->name.c_str() ); - } -} - -/* -=============== -idMover::Event_PartBlocked -=============== -*/ -void idMover::Event_PartBlocked( idEntity *blockingEntity ) { - if ( damage > 0.0f ) { - blockingEntity->Damage( this, this, vec3_origin, "damage_moverCrush", damage, INVALID_JOINT ); - } - if ( g_debugMover.GetBool() ) { - gameLocal.Printf( "%d: '%s' blocked by '%s'\n", gameLocal.slow.time, name.c_str(), blockingEntity->name.c_str() ); - } -} - -/* -================ -idMover::Event_SetMoveSpeed -================ -*/ -void idMover::Event_SetMoveSpeed( float speed ) { - if ( speed <= 0 ) { - gameLocal.Error( "Cannot set speed less than or equal to 0." ); - } - - move_speed = speed; - move_time = 0; // move_time is calculated for each move when move_speed is non-0 -} - -/* -================ -idMover::Event_SetMoveTime -================ -*/ -void idMover::Event_SetMoveTime( float time ) { - if ( time <= 0 ) { - gameLocal.Error( "Cannot set time less than or equal to 0." ); - } - - move_speed = 0; - move_time = SEC2MS( time ); -} - -/* -================ -idMover::Event_SetAccellerationTime -================ -*/ -void idMover::Event_SetAccellerationTime( float time ) { - if ( time < 0 ) { - gameLocal.Error( "Cannot set acceleration time less than 0." ); - } - - acceltime = SEC2MS( time ); -} - -/* -================ -idMover::Event_SetDecelerationTime -================ -*/ -void idMover::Event_SetDecelerationTime( float time ) { - if ( time < 0 ) { - gameLocal.Error( "Cannot set deceleration time less than 0." ); - } - - deceltime = SEC2MS( time ); -} - -/* -================ -idMover::Event_MoveTo -================ -*/ -void idMover::Event_MoveTo( idEntity *ent ) { - if ( !ent ) { - gameLocal.Warning( "Entity not found" ); - } - - dest_position = GetLocalCoordinates( ent->GetPhysics()->GetOrigin() ); - BeginMove( idThread::CurrentThread() ); -} - -/* -================ -idMover::MoveToPos -================ -*/ -void idMover::MoveToPos( const idVec3 &pos ) { - dest_position = GetLocalCoordinates( pos ); - BeginMove( NULL ); -} - -/* -================ -idMover::Event_MoveToPos -================ -*/ -void idMover::Event_MoveToPos( idVec3 &pos ) { - MoveToPos( pos ); -} - -/* -================ -idMover::Event_MoveDir -================ -*/ -void idMover::Event_MoveDir( float angle, float distance ) { - idVec3 dir; - idVec3 org; - - physicsObj.GetLocalOrigin( org ); - VectorForDir( angle, dir ); - dest_position = org + dir * distance; - - BeginMove( idThread::CurrentThread() ); -} - -/* -================ -idMover::Event_MoveAccelerateTo -================ -*/ -void idMover::Event_MoveAccelerateTo( float speed, float time ) { - float v; - idVec3 org, dir; - int at; - - if ( time < 0 ) { - gameLocal.Error( "idMover::Event_MoveAccelerateTo: cannot set acceleration time less than 0." ); - } - - dir = physicsObj.GetLinearVelocity(); - v = dir.Normalize(); - - // if not moving already - if ( v == 0.0f ) { - gameLocal.Error( "idMover::Event_MoveAccelerateTo: not moving." ); - } - - // if already moving faster than the desired speed - if ( v >= speed ) { - return; - } - - at = idPhysics::SnapTimeToPhysicsFrame( SEC2MS( time ) ); - - lastCommand = MOVER_MOVING; - - physicsObj.GetLocalOrigin( org ); - - move.stage = ACCELERATION_STAGE; - move.acceleration = at; - move.movetime = 0; - move.deceleration = 0; - - StartSound( "snd_accel", SND_CHANNEL_BODY2, 0, false, NULL ); - StartSound( "snd_move", SND_CHANNEL_BODY, 0, false, NULL ); - physicsObj.SetLinearExtrapolation( EXTRAPOLATION_ACCELLINEAR, gameLocal.slow.time, move.acceleration, org, dir * ( speed - v ), dir * v ); -} - -/* -================ -idMover::Event_MoveDecelerateTo -================ -*/ -void idMover::Event_MoveDecelerateTo( float speed, float time ) { - float v; - idVec3 org, dir; - int dt; - - if ( time < 0 ) { - gameLocal.Error( "idMover::Event_MoveDecelerateTo: cannot set deceleration time less than 0." ); - } - - dir = physicsObj.GetLinearVelocity(); - v = dir.Normalize(); - - // if not moving already - if ( v == 0.0f ) { - gameLocal.Error( "idMover::Event_MoveDecelerateTo: not moving." ); - } - - // if already moving slower than the desired speed - if ( v <= speed ) { - return; - } - - dt = idPhysics::SnapTimeToPhysicsFrame( SEC2MS( time ) ); - - lastCommand = MOVER_MOVING; - - physicsObj.GetLocalOrigin( org ); - - move.stage = DECELERATION_STAGE; - move.acceleration = 0; - move.movetime = 0; - move.deceleration = dt; - - StartSound( "snd_decel", SND_CHANNEL_BODY2, 0, false, NULL ); - StartSound( "snd_move", SND_CHANNEL_BODY, 0, false, NULL ); - physicsObj.SetLinearExtrapolation( EXTRAPOLATION_DECELLINEAR, gameLocal.slow.time, move.deceleration, org, dir * ( v - speed ), dir * speed ); -} - -/* -================ -idMover::Event_RotateDownTo -================ -*/ -void idMover::Event_RotateDownTo( int axis, float angle ) { - idAngles ang; - - if ( ( axis < 0 ) || ( axis > 2 ) ) { - gameLocal.Error( "Invalid axis" ); - } - - physicsObj.GetLocalAngles( ang ); - - dest_angles[ axis ] = angle; - if ( dest_angles[ axis ] > ang[ axis ] ) { - dest_angles[ axis ] -= 360; - } - - BeginRotation( idThread::CurrentThread(), true ); -} - -/* -================ -idMover::Event_RotateUpTo -================ -*/ -void idMover::Event_RotateUpTo( int axis, float angle ) { - idAngles ang; - - if ( ( axis < 0 ) || ( axis > 2 ) ) { - gameLocal.Error( "Invalid axis" ); - } - - physicsObj.GetLocalAngles( ang ); - - dest_angles[ axis ] = angle; - if ( dest_angles[ axis ] < ang[ axis ] ) { - dest_angles[ axis ] += 360; - } - - BeginRotation( idThread::CurrentThread(), true ); -} - -/* -================ -idMover::Event_RotateTo -================ -*/ -void idMover::Event_RotateTo( idAngles &angles ) { - dest_angles = angles; - BeginRotation( idThread::CurrentThread(), true ); -} - -/* -================ -idMover::Event_Rotate -================ -*/ -void idMover::Event_Rotate( idAngles &angles ) { - idAngles ang; - - if ( rotate_thread ) { - DoneRotating(); - } - - physicsObj.GetLocalAngles( ang ); - dest_angles = ang + angles * ( move_time - ( acceltime + deceltime ) / 2 ) * 0.001f; - - BeginRotation( idThread::CurrentThread(), false ); -} - -/* -================ -idMover::Event_RotateOnce -================ -*/ -void idMover::Event_RotateOnce( idAngles &angles ) { - idAngles ang; - - if ( rotate_thread ) { - DoneRotating(); - } - - physicsObj.GetLocalAngles( ang ); - dest_angles = ang + angles; - - BeginRotation( idThread::CurrentThread(), true ); -} - -/* -================ -idMover::Event_Bob -================ -*/ -void idMover::Event_Bob( float speed, float phase, idVec3 &depth ) { - idVec3 org; - - physicsObj.GetLocalOrigin( org ); - physicsObj.SetLinearExtrapolation( extrapolation_t(EXTRAPOLATION_DECELSINE|EXTRAPOLATION_NOSTOP), speed * 1000 * phase, speed * 500, org, depth * 2.0f, vec3_origin ); -} - -/* -================ -idMover::Event_Sway -================ -*/ -void idMover::Event_Sway( float speed, float phase, idAngles &depth ) { - idAngles ang, angSpeed; - float duration; - - physicsObj.GetLocalAngles( ang ); - assert ( speed > 0.0f ); - duration = idMath::Sqrt( depth[0] * depth[0] + depth[1] * depth[1] + depth[2] * depth[2] ) / speed; - angSpeed = depth / ( duration * idMath::SQRT_1OVER2 ); - physicsObj.SetAngularExtrapolation( extrapolation_t(EXTRAPOLATION_DECELSINE|EXTRAPOLATION_NOSTOP), duration * 1000.0f * phase, duration * 1000.0f, ang, angSpeed, ang_zero ); -} - -/* -================ -idMover::Event_OpenPortal - -Sets the portal associtated with this mover to be open -================ -*/ -void idMover::Event_OpenPortal( void ) { - if ( areaPortal ) { - SetPortalState( true ); - } -} - -/* -================ -idMover::Event_ClosePortal - -Sets the portal associtated with this mover to be closed -================ -*/ -void idMover::Event_ClosePortal( void ) { - if ( areaPortal ) { - SetPortalState( false ); - } -} - -/* -================ -idMover::Event_SetAccelSound -================ -*/ -void idMover::Event_SetAccelSound( const char *sound ) { -// refSound.SetSound( "accel", sound ); -} - -/* -================ -idMover::Event_SetDecelSound -================ -*/ -void idMover::Event_SetDecelSound( const char *sound ) { -// refSound.SetSound( "decel", sound ); -} - -/* -================ -idMover::Event_SetMoveSound -================ -*/ -void idMover::Event_SetMoveSound( const char *sound ) { -// refSound.SetSound( "move", sound ); -} - -/* -================ -idMover::Event_EnableSplineAngles -================ -*/ -void idMover::Event_EnableSplineAngles( void ) { - useSplineAngles = true; -} - -/* -================ -idMover::Event_DisableSplineAngles -================ -*/ -void idMover::Event_DisableSplineAngles( void ) { - useSplineAngles = false; -} - -/* -================ -idMover::Event_RemoveInitialSplineAngles -================ -*/ -void idMover::Event_RemoveInitialSplineAngles( void ) { - idCurve_Spline *spline; - idAngles ang; - - spline = physicsObj.GetSpline(); - if ( !spline ) { - return; - } - ang = spline->GetCurrentFirstDerivative( 0 ).ToAngles(); - physicsObj.SetAngularExtrapolation( EXTRAPOLATION_NONE, 0, 0, -ang, ang_zero, ang_zero ); -} - -/* -================ -idMover::Event_StartSpline -================ -*/ -void idMover::Event_StartSpline( idEntity *splineEntity ) { - idCurve_Spline *spline; - - if ( !splineEntity ) { - return; - } - - // Needed for savegames - splineEnt = splineEntity; - - spline = splineEntity->GetSpline(); - if ( !spline ) { - return; - } - - lastCommand = MOVER_SPLINE; - move_thread = 0; - - if ( acceltime + deceltime > move_time ) { - acceltime = move_time / 2; - deceltime = move_time - acceltime; - } - move.stage = FINISHED_STAGE; - move.acceleration = acceltime; - move.movetime = move_time; - move.deceleration = deceltime; - - spline->MakeUniform( move_time ); - spline->ShiftTime( gameLocal.slow.time - spline->GetTime( 0 ) ); - - physicsObj.SetSpline( spline, move.acceleration, move.deceleration, useSplineAngles ); - physicsObj.SetLinearExtrapolation( EXTRAPOLATION_NONE, 0, 0, dest_position, vec3_origin, vec3_origin ); -} - -/* -================ -idMover::Event_StopSpline -================ -*/ -void idMover::Event_StopSpline( void ) { - physicsObj.SetSpline( NULL, 0, 0, useSplineAngles ); - splineEnt = NULL; -} - -/* -================ -idMover::Event_Activate -================ -*/ -void idMover::Event_Activate( idEntity *activator ) { - Show(); - Event_StartSpline( this ); -} - -/* -================ -idMover::Event_IsMoving -================ -*/ -void idMover::Event_IsMoving( void ) { - if ( physicsObj.GetLinearExtrapolationType() == EXTRAPOLATION_NONE ) { - idThread::ReturnInt( false ); - } else { - idThread::ReturnInt( true ); - } -} - -/* -================ -idMover::Event_IsRotating -================ -*/ -void idMover::Event_IsRotating( void ) { - if ( physicsObj.GetAngularExtrapolationType() == EXTRAPOLATION_NONE ) { - idThread::ReturnInt( false ); - } else { - idThread::ReturnInt( true ); - } -} - -/* -================ -idMover::WriteToSnapshot -================ -*/ -void idMover::WriteToSnapshot( idBitMsgDelta &msg ) const { - physicsObj.WriteToSnapshot( msg ); - msg.WriteBits( move.stage, 3 ); - msg.WriteBits( rot.stage, 3 ); - WriteBindToSnapshot( msg ); - WriteGUIToSnapshot( msg ); -} - -/* -================ -idMover::ReadFromSnapshot -================ -*/ -void idMover::ReadFromSnapshot( const idBitMsgDelta &msg ) { - moveStage_t oldMoveStage = move.stage; - moveStage_t oldRotStage = rot.stage; - - physicsObj.ReadFromSnapshot( msg ); - move.stage = (moveStage_t) msg.ReadBits( 3 ); - rot.stage = (moveStage_t) msg.ReadBits( 3 ); - ReadBindFromSnapshot( msg ); - ReadGUIFromSnapshot( msg ); - - if ( msg.HasChanged() ) { - if ( move.stage != oldMoveStage ) { - UpdateMoveSound( oldMoveStage ); - } - if ( rot.stage != oldRotStage ) { - UpdateRotationSound( oldRotStage ); - } - UpdateVisuals(); - } -} - -/* -================ -idMover::SetPortalState -================ -*/ -void idMover::SetPortalState( bool open ) { - assert( areaPortal ); - gameLocal.SetPortalState( areaPortal, open ? PS_BLOCK_NONE : PS_BLOCK_ALL ); -} - -/* -=============================================================================== - - idSplinePath, holds a spline path to be used by an idMover - -=============================================================================== -*/ - -CLASS_DECLARATION( idEntity, idSplinePath ) -END_CLASS - -/* -================ -idSplinePath::idSplinePath -================ -*/ -idSplinePath::idSplinePath() { -} - -/* -================ -idSplinePath::Spawn -================ -*/ -void idSplinePath::Spawn( void ) { -} - - -/* -=============================================================================== - -idElevator - -=============================================================================== -*/ -const idEventDef EV_PostArrival( "postArrival", NULL ); -const idEventDef EV_GotoFloor( "gotoFloor", "d" ); -#ifdef _D3XP -const idEventDef EV_SetGuiStates( "setGuiStates" ); -#endif - -CLASS_DECLARATION( idMover, idElevator ) - EVENT( EV_Activate, idElevator::Event_Activate ) - EVENT( EV_TeamBlocked, idElevator::Event_TeamBlocked ) - EVENT( EV_PartBlocked, idElevator::Event_PartBlocked ) - EVENT( EV_PostArrival, idElevator::Event_PostFloorArrival ) - EVENT( EV_GotoFloor, idElevator::Event_GotoFloor ) - EVENT( EV_Touch, idElevator::Event_Touch ) -#ifdef _D3XP - EVENT( EV_SetGuiStates, idElevator::Event_SetGuiStates ) -#endif -END_CLASS - -/* -================ -idElevator::idElevator -================ -*/ -idElevator::idElevator( void ) { - state = INIT; - floorInfo.Clear(); - currentFloor = 0; - pendingFloor = 0; - lastFloor = 0; - controlsDisabled = false; - lastTouchTime = 0; - returnFloor = 0; - returnTime = 0; -} - -/* -================ -idElevator::Save -================ -*/ -void idElevator::Save( idSaveGame *savefile ) const { - int i; - - savefile->WriteInt( (int)state ); - - savefile->WriteInt( floorInfo.Num() ); - for ( i = 0; i < floorInfo.Num(); i++ ) { - savefile->WriteVec3( floorInfo[ i ].pos ); - savefile->WriteString( floorInfo[ i ].door ); - savefile->WriteInt( floorInfo[ i ].floor ); - } - - savefile->WriteInt( currentFloor ); - savefile->WriteInt( pendingFloor ); - savefile->WriteInt( lastFloor ); - savefile->WriteBool( controlsDisabled ); - savefile->WriteFloat( returnTime ); - savefile->WriteInt( returnFloor ); - savefile->WriteInt( lastTouchTime ); -} - -/* -================ -idElevator::Restore -================ -*/ -void idElevator::Restore( idRestoreGame *savefile ) { - int i, num; - - savefile->ReadInt( (int &)state ); - - savefile->ReadInt( num ); - for ( i = 0; i < num; i++ ) { - floorInfo_s floor; - - savefile->ReadVec3( floor.pos ); - savefile->ReadString( floor.door ); - savefile->ReadInt( floor.floor ); - - floorInfo.Append( floor ); - } - - savefile->ReadInt( currentFloor ); - savefile->ReadInt( pendingFloor ); - savefile->ReadInt( lastFloor ); - savefile->ReadBool( controlsDisabled ); - savefile->ReadFloat( returnTime ); - savefile->ReadInt( returnFloor ); - savefile->ReadInt( lastTouchTime ); -} - -/* -================ -idElevator::Spawn -================ -*/ -void idElevator::Spawn( void ) { - idStr str; - int len1; - - lastFloor = 0; - currentFloor = 0; - pendingFloor = spawnArgs.GetInt( "floor", "1" ); - SetGuiStates( ( pendingFloor == 1 ) ? guiBinaryMoverStates[0] : guiBinaryMoverStates[1]); - - returnTime = spawnArgs.GetFloat( "returnTime" ); - returnFloor = spawnArgs.GetInt( "returnFloor" ); - - len1 = strlen( "floorPos_" ); - const idKeyValue *kv = spawnArgs.MatchPrefix( "floorPos_", NULL ); - while( kv ) { - str = kv->GetKey().Right( kv->GetKey().Length() - len1 ); - floorInfo_s fi; - fi.floor = atoi( str ); - fi.door = spawnArgs.GetString( va( "floorDoor_%i", fi.floor ) ); - fi.pos = spawnArgs.GetVector( kv->GetKey() ); - floorInfo.Append( fi ); - kv = spawnArgs.MatchPrefix( "floorPos_", kv ); - } - lastTouchTime = 0; - state = INIT; - BecomeActive( TH_THINK | TH_PHYSICS ); - PostEventMS( &EV_Mover_InitGuiTargets, 0 ); - controlsDisabled = false; -} - -/* -============== -idElevator::Event_Touch -=============== -*/ -void idElevator::Event_Touch( idEntity *other, trace_t *trace ) { - - if ( gameLocal.slow.time < lastTouchTime + 2000 ) { - return; - } - - if ( !other->IsType( idPlayer::Type ) ) { - return; - } - - lastTouchTime = gameLocal.slow.time; - - if ( thinkFlags & TH_PHYSICS ) { - return; - } - - int triggerFloor = spawnArgs.GetInt( "triggerFloor" ); - if ( spawnArgs.GetBool( "trigger" ) && triggerFloor != currentFloor ) { - PostEventSec( &EV_GotoFloor, 0.25f, triggerFloor ); - } -} - -/* -================ -idElevator::Think -================ -*/ -void idElevator::Think( void ) { - idVec3 masterOrigin; - idMat3 masterAxis; - idDoor *doorent = GetDoor( spawnArgs.GetString( "innerdoor" ) ); - if ( state == INIT ) { - state = IDLE; - if ( doorent ) { - doorent->BindTeam( this ); - doorent->spawnArgs.Set( "snd_open", "" ); - doorent->spawnArgs.Set( "snd_close", "" ); - doorent->spawnArgs.Set( "snd_opened", "" ); - } - for ( int i = 0; i < floorInfo.Num(); i++ ) { - idDoor *door = GetDoor( floorInfo[i].door ); - if ( door ) { - door->SetCompanion( doorent ); - } - } - - Event_GotoFloor( pendingFloor ); - DisableAllDoors(); - SetGuiStates( ( pendingFloor == 1 ) ? guiBinaryMoverStates[0] : guiBinaryMoverStates[1] ); - } else if ( state == WAITING_ON_DOORS ) { - if ( doorent ) { - state = doorent->IsOpen() ? WAITING_ON_DOORS : IDLE; - } else { - state = IDLE; - } - if ( state == IDLE ) { - lastFloor = currentFloor; - currentFloor = pendingFloor; - floorInfo_s *fi = GetFloorInfo( currentFloor ); - if ( fi ) { - MoveToPos( fi->pos ); - } - } - } - RunPhysics(); - Present(); -} - -/* -================ -idElevator::Event_Activate -================ -*/ -void idElevator::Event_Activate( idEntity *activator ) { - int triggerFloor = spawnArgs.GetInt( "triggerFloor" ); - if ( spawnArgs.GetBool( "trigger" ) && triggerFloor != currentFloor ) { - Event_GotoFloor( triggerFloor ); - } -} - -/* -================ -idElevator::Event_TeamBlocked -================ -*/ -void idElevator::Event_TeamBlocked( idEntity *blockedEntity, idEntity *blockingEntity ) { - if ( blockedEntity == this ) { - Event_GotoFloor( lastFloor ); - } else if ( blockedEntity && blockedEntity->IsType( idDoor::Type ) ) { - // open the inner doors if one is blocked - idDoor *blocked = static_cast( blockedEntity ); - idDoor *door = GetDoor( spawnArgs.GetString( "innerdoor" ) ); - if ( door && blocked->GetMoveMaster() == door->GetMoveMaster() ) { - door->SetBlocked(true); - OpenInnerDoor(); - OpenFloorDoor( currentFloor ); - } - } -} - -/* -=============== -idElevator::HandleSingleGuiCommand -=============== -*/ -bool idElevator::HandleSingleGuiCommand( idEntity *entityGui, idLexer *src ) { - idToken token; - - if ( controlsDisabled ) { - return false; - } - - if ( !src->ReadToken( &token ) ) { - return false; - } - - if ( token == ";" ) { - return false; - } - - if ( token.Icmp( "changefloor" ) == 0 ) { - if ( src->ReadToken( &token ) ) { - int newFloor = atoi( token ); - if ( newFloor == currentFloor ) { - // open currentFloor and interior doors - OpenInnerDoor(); - OpenFloorDoor( currentFloor ); - } else { - idDoor *door = GetDoor( spawnArgs.GetString( "innerdoor" ) ); - if ( door && door->IsOpen() ) { - PostEventSec( &EV_GotoFloor, 0.5f, newFloor ); - } else { - ProcessEvent( &EV_GotoFloor, newFloor ); - } - } - return true; - } - } - - src->UnreadToken( &token ); - return false; -} - -/* -================ -idElevator::OpenFloorDoor -================ -*/ -void idElevator::OpenFloorDoor( int floor ) { - floorInfo_s *fi = GetFloorInfo( floor ); - if ( fi ) { - idDoor *door = GetDoor( fi->door ); - if ( door ) { - door->Open(); - } - } -} - -/* -================ -idElevator::OpenInnerDoor -================ -*/ -void idElevator::OpenInnerDoor( void ) { - idDoor *door = GetDoor( spawnArgs.GetString( "innerdoor" ) ); - if ( door ) { - door->Open(); - } -} - -/* -================ -idElevator::GetFloorInfo -================ -*/ -floorInfo_s *idElevator::GetFloorInfo( int floor ) { - for ( int i = 0; i < floorInfo.Num(); i++ ) { - if ( floorInfo[i].floor == floor ) { - return &floorInfo[i]; - } - } - return NULL; -} - -/* -================ -idElevator::Event_GotoFloor -================ -*/ -void idElevator::Event_GotoFloor( int floor ) { - floorInfo_s *fi = GetFloorInfo( floor ); - if ( fi ) { - idDoor *door = GetDoor( spawnArgs.GetString( "innerdoor" ) ); - if ( door ) { - if ( door->IsBlocked() || door->IsOpen() ) { - PostEventSec( &EV_GotoFloor, 0.5f, floor ); - return; - } - } - DisableAllDoors(); - CloseAllDoors(); - state = WAITING_ON_DOORS; - pendingFloor = floor; - } -} - -/* -================ -idElevator::BeginMove -================ -*/ -void idElevator::BeginMove( idThread *thread ) { - controlsDisabled = true; - CloseAllDoors(); - DisableAllDoors(); - const idKeyValue *kv = spawnArgs.MatchPrefix( "statusGui" ); - while( kv ) { - idEntity *ent = gameLocal.FindEntity( kv->GetValue() ); - if ( ent ) { - for ( int j = 0; j < MAX_RENDERENTITY_GUI; j++ ) { - if ( ent->GetRenderEntity() && ent->GetRenderEntity()->gui[ j ] ) { - ent->GetRenderEntity()->gui[ j ]->SetStateString( "floor", "" ); - ent->GetRenderEntity()->gui[ j ]->StateChanged( gameLocal.slow.time, true ); - } - } - ent->UpdateVisuals(); - } - kv = spawnArgs.MatchPrefix( "statusGui", kv ); - } - SetGuiStates( ( pendingFloor == 1 ) ? guiBinaryMoverStates[3] : guiBinaryMoverStates[2] ); - idMover::BeginMove( thread ); -} - -/* -================ -idElevator::GetDoor -================ -*/ -idDoor *idElevator::GetDoor( const char *name ) { - idEntity *ent; - idEntity *master; - idDoor *doorEnt; - - doorEnt = NULL; - if ( name && *name ) { - ent = gameLocal.FindEntity( name ); - if ( ent && ent->IsType( idDoor::Type ) ) { - doorEnt = static_cast( ent ); - master = doorEnt->GetMoveMaster(); - if ( master != doorEnt ) { - if ( master->IsType( idDoor::Type ) ) { - doorEnt = static_cast( master ); - } else { - doorEnt = NULL; - } - } - } - } - - return doorEnt; -} - -/* -================ -idElevator::Event_PostFloorArrival -================ -*/ -void idElevator::Event_PostFloorArrival() { - OpenFloorDoor( currentFloor ); - OpenInnerDoor(); - SetGuiStates( ( currentFloor == 1 ) ? guiBinaryMoverStates[0] : guiBinaryMoverStates[1] ); - controlsDisabled = false; - if ( returnTime > 0.0f && returnFloor != currentFloor ) { - PostEventSec( &EV_GotoFloor, returnTime, returnFloor ); - } -} - -#ifdef _D3XP -void idElevator::Event_SetGuiStates() { - SetGuiStates( ( currentFloor == 1 ) ? guiBinaryMoverStates[0] : guiBinaryMoverStates[1] ); -} -#endif - -/* -================ -idElevator::DoneMoving -================ -*/ -void idElevator::DoneMoving( void ) { - idMover::DoneMoving(); - EnableProperDoors(); - const idKeyValue *kv = spawnArgs.MatchPrefix( "statusGui" ); - while( kv ) { - idEntity *ent = gameLocal.FindEntity( kv->GetValue() ); - if ( ent ) { - for ( int j = 0; j < MAX_RENDERENTITY_GUI; j++ ) { - if ( ent->GetRenderEntity() && ent->GetRenderEntity()->gui[ j ] ) { - ent->GetRenderEntity()->gui[ j ]->SetStateString( "floor", va( "%i", currentFloor ) ); - ent->GetRenderEntity()->gui[ j ]->StateChanged( gameLocal.slow.time, true ); - } - } - ent->UpdateVisuals(); - } - kv = spawnArgs.MatchPrefix( "statusGui", kv ); - } - if ( spawnArgs.GetInt( "pauseOnFloor", "-1" ) == currentFloor ) { - PostEventSec( &EV_PostArrival, spawnArgs.GetFloat( "pauseTime" ) ); - } else { - Event_PostFloorArrival(); - } -} - -/* -================ -idElevator::CloseAllDoors -================ -*/ -void idElevator::CloseAllDoors( void ) { - idDoor *door = GetDoor( spawnArgs.GetString( "innerdoor" ) ); - if ( door ) { - door->Close(); - } - for ( int i = 0; i < floorInfo.Num(); i++ ) { - door = GetDoor( floorInfo[i].door ); - if ( door ) { - door->Close(); - } - } -} - -/* -================ -idElevator::DisableAllDoors -================ -*/ -void idElevator::DisableAllDoors( void ) { - idDoor *door = GetDoor( spawnArgs.GetString( "innerdoor" ) ); - if ( door ) { - door->Enable( false ); - } - for ( int i = 0; i < floorInfo.Num(); i++ ) { - door = GetDoor( floorInfo[i].door ); - if ( door ) { - door->Enable( false ); - } - } -} - -/* -================ -idElevator::EnableProperDoors -================ -*/ -void idElevator::EnableProperDoors( void ) { - idDoor *door = GetDoor( spawnArgs.GetString( "innerdoor" ) ); - if ( door ) { - door->Enable( true ); - } - for ( int i = 0; i < floorInfo.Num(); i++ ) { - if ( floorInfo[i].floor == currentFloor ) { - door = GetDoor( floorInfo[i].door ); - if ( door ) { - door->Enable( true ); - break; - } - } - } -} - - -/* -=============================================================================== - -idMover_Binary - -Doors, plats, and buttons are all binary (two position) movers -Pos1 is "at rest", pos2 is "activated" - -=============================================================================== -*/ - -const idEventDef EV_Mover_ReturnToPos1( "", NULL ); -const idEventDef EV_Mover_MatchTeam( "", "dd" ); -const idEventDef EV_Mover_Enable( "enable", NULL ); -const idEventDef EV_Mover_Disable( "disable", NULL ); - -CLASS_DECLARATION( idEntity, idMover_Binary ) - EVENT( EV_FindGuiTargets, idMover_Binary::Event_FindGuiTargets ) - EVENT( EV_Thread_SetCallback, idMover_Binary::Event_SetCallback ) - EVENT( EV_Mover_ReturnToPos1, idMover_Binary::Event_ReturnToPos1 ) - EVENT( EV_Activate, idMover_Binary::Event_Use_BinaryMover ) - EVENT( EV_ReachedPos, idMover_Binary::Event_Reached_BinaryMover ) - EVENT( EV_Mover_MatchTeam, idMover_Binary::Event_MatchActivateTeam ) - EVENT( EV_Mover_Enable, idMover_Binary::Event_Enable ) - EVENT( EV_Mover_Disable, idMover_Binary::Event_Disable ) - EVENT( EV_Mover_OpenPortal, idMover_Binary::Event_OpenPortal ) - EVENT( EV_Mover_ClosePortal, idMover_Binary::Event_ClosePortal ) - EVENT( EV_Mover_InitGuiTargets, idMover_Binary::Event_InitGuiTargets ) -END_CLASS - -/* -================ -idMover_Binary::idMover_Binary() -================ -*/ -idMover_Binary::idMover_Binary() { - pos1.Zero(); - pos2.Zero(); - moverState = MOVER_POS1; - moveMaster = NULL; - activateChain = NULL; - soundPos1 = 0; - sound1to2 = 0; - sound2to1 = 0; - soundPos2 = 0; - soundLoop = 0; - wait = 0.0f; - damage = 0.0f; - duration = 0; - accelTime = 0; - decelTime = 0; - activatedBy = this; - stateStartTime = 0; - team.Clear(); - enabled = false; - move_thread = 0; - updateStatus = 0; - areaPortal = 0; - blocked = false; -#ifdef _D3XP - playerOnly = false; -#endif - fl.networkSync = true; -} - -/* -================ -idMover_Binary::~idMover_Binary -================ -*/ -idMover_Binary::~idMover_Binary() { - idMover_Binary *mover; - - // if this is the mover master - if ( this == moveMaster ) { - // make the next mover in the chain the move master - for ( mover = moveMaster; mover; mover = mover->activateChain ) { - mover->moveMaster = this->activateChain; - } - } - else { - // remove mover from the activate chain - for ( mover = moveMaster; mover; mover = mover->activateChain ) { - if ( mover->activateChain == this ) { - mover->activateChain = this->activateChain; - break; - } - } - } -} - -/* -================ -idMover_Binary::Save -================ -*/ -void idMover_Binary::Save( idSaveGame *savefile ) const { - int i; - - savefile->WriteVec3( pos1 ); - savefile->WriteVec3( pos2 ); - savefile->WriteInt( (moverState_t)moverState ); - - savefile->WriteObject( moveMaster ); - savefile->WriteObject( activateChain ); - - savefile->WriteInt( soundPos1 ); - savefile->WriteInt( sound1to2 ); - savefile->WriteInt( sound2to1 ); - savefile->WriteInt( soundPos2 ); - savefile->WriteInt( soundLoop ); - - savefile->WriteFloat( wait ); - savefile->WriteFloat( damage ); - - savefile->WriteInt( duration ); - savefile->WriteInt( accelTime ); - savefile->WriteInt( decelTime ); - - activatedBy.Save( savefile ); - - savefile->WriteInt( stateStartTime ); - savefile->WriteString( team ); - savefile->WriteBool( enabled ); - - savefile->WriteInt( move_thread ); - savefile->WriteInt( updateStatus ); - - savefile->WriteInt( buddies.Num() ); - for ( i = 0; i < buddies.Num(); i++ ) { - savefile->WriteString( buddies[ i ] ); - } - - savefile->WriteStaticObject( physicsObj ); - - savefile->WriteInt( areaPortal ); - if ( areaPortal ) { - savefile->WriteInt( gameRenderWorld->GetPortalState( areaPortal ) ); - } - savefile->WriteBool( blocked ); -#ifdef _D3XP - savefile->WriteBool( playerOnly ); -#endif - - savefile->WriteInt( guiTargets.Num() ); - for( i = 0; i < guiTargets.Num(); i++ ) { - guiTargets[ i ].Save( savefile ); - } -} - -/* -================ -idMover_Binary::Restore -================ -*/ -void idMover_Binary::Restore( idRestoreGame *savefile ) { - int i, num, portalState; - idStr temp; - - savefile->ReadVec3( pos1 ); - savefile->ReadVec3( pos2 ); - savefile->ReadInt( (int &)moverState ); - - savefile->ReadObject( reinterpret_cast( moveMaster ) ); - savefile->ReadObject( reinterpret_cast( activateChain ) ); - - savefile->ReadInt( soundPos1 ); - savefile->ReadInt( sound1to2 ); - savefile->ReadInt( sound2to1 ); - savefile->ReadInt( soundPos2 ); - savefile->ReadInt( soundLoop ); - - savefile->ReadFloat( wait ); - savefile->ReadFloat( damage ); - - savefile->ReadInt( duration ); - savefile->ReadInt( accelTime ); - savefile->ReadInt( decelTime ); - - activatedBy.Restore( savefile ); - - savefile->ReadInt( stateStartTime ); - - savefile->ReadString( team ); - savefile->ReadBool( enabled ); - - savefile->ReadInt( move_thread ); - savefile->ReadInt( updateStatus ); - - savefile->ReadInt( num ); - for ( i = 0; i < num; i++ ) { - savefile->ReadString( temp ); - buddies.Append( temp ); - } - - savefile->ReadStaticObject( physicsObj ); - RestorePhysics( &physicsObj ); - - savefile->ReadInt( areaPortal ); - if ( areaPortal ) { - savefile->ReadInt( portalState ); - gameLocal.SetPortalState( areaPortal, portalState ); - } - savefile->ReadBool( blocked ); -#ifdef _D3XP - savefile->ReadBool( playerOnly ); -#endif - - guiTargets.Clear(); - savefile->ReadInt( num ); - guiTargets.SetNum( num ); - for( i = 0; i < num; i++ ) { - guiTargets[ i ].Restore( savefile ); - } -} - -/* -================ -idMover_Binary::Spawn - -Base class for all movers. - -"wait" wait before returning (3 default, -1 = never return) -"speed" movement speed -================ -*/ -void idMover_Binary::Spawn( void ) { - idEntity *ent; - const char *temp; - - move_thread = 0; - enabled = true; - areaPortal = 0; - - activateChain = NULL; - - spawnArgs.GetFloat( "wait", "0", wait ); - - spawnArgs.GetInt( "updateStatus", "0", updateStatus ); - - const idKeyValue *kv = spawnArgs.MatchPrefix( "buddy", NULL ); - while( kv ) { - buddies.Append( kv->GetValue() ); - kv = spawnArgs.MatchPrefix( "buddy", kv ); - } - - spawnArgs.GetString( "team", "", &temp ); - team = temp; - - if ( !team.Length() ) { - ent = this; - } else { - // find the first entity spawned on this team (which could be us) - for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) { - if ( ent->IsType( idMover_Binary::Type ) && !idStr::Icmp( static_cast(ent)->team.c_str(), temp ) ) { - break; - } - } - if ( !ent ) { - ent = this; - } - } - moveMaster = static_cast(ent); - - // create a physics team for the binary mover parts - if ( ent != this ) { - JoinTeam( ent ); - } - - physicsObj.SetSelf( this ); - physicsObj.SetClipModel( new idClipModel( GetPhysics()->GetClipModel() ), 1.0f ); - physicsObj.SetOrigin( GetPhysics()->GetOrigin() ); - physicsObj.SetAxis( GetPhysics()->GetAxis() ); - physicsObj.SetClipMask( MASK_SOLID ); - if ( !spawnArgs.GetBool( "solid", "1" ) ) { - physicsObj.SetContents( 0 ); - } - if ( !spawnArgs.GetBool( "nopush" ) ) { - physicsObj.SetPusher( 0 ); - } - physicsObj.SetLinearExtrapolation( EXTRAPOLATION_NONE, 0, 0, GetPhysics()->GetOrigin(), vec3_origin, vec3_origin ); - physicsObj.SetAngularExtrapolation( EXTRAPOLATION_NONE, 0, 0, GetPhysics()->GetAxis().ToAngles(), ang_zero, ang_zero ); - SetPhysics( &physicsObj ); - - if ( moveMaster != this ) { - JoinActivateTeam( moveMaster ); - } - - idBounds soundOrigin; - idMover_Binary *slave; - - soundOrigin.Clear(); - for ( slave = moveMaster; slave != NULL; slave = slave->activateChain ) { - soundOrigin += slave->GetPhysics()->GetAbsBounds(); - } - moveMaster->refSound.origin = soundOrigin.GetCenter(); - - if ( spawnArgs.MatchPrefix( "guiTarget" ) ) { - if ( gameLocal.GameState() == GAMESTATE_STARTUP ) { - PostEventMS( &EV_FindGuiTargets, 0 ); - } else { - // not during spawn, so it's ok to get the targets - FindGuiTargets(); - } - } -} - -/* -=============== -idMover_Binary::GetMovedir - -The editor only specifies a single value for angles (yaw), -but we have special constants to generate an up or down direction. -Angles will be cleared, because it is being used to represent a direction -instead of an orientation. -=============== -*/ -void idMover_Binary::GetMovedir( float angle, idVec3 &movedir ) { - if ( angle == -1 ) { - movedir.Set( 0, 0, 1 ); - } else if ( angle == -2 ) { - movedir.Set( 0, 0, -1 ); - } else { - movedir = idAngles( 0, angle, 0 ).ToForward(); - } -} - -/* -================ -idMover_Binary::Event_SetCallback -================ -*/ -void idMover_Binary::Event_SetCallback( void ) { - if ( ( moverState == MOVER_1TO2 ) || ( moverState == MOVER_2TO1 ) ) { - move_thread = idThread::CurrentThreadNum(); - idThread::ReturnInt( true ); - } else { - idThread::ReturnInt( false ); - } -} - -/* -=============== -idMover_Binary::UpdateMoverSound -=============== -*/ -void idMover_Binary::UpdateMoverSound( moverState_t state ) { - if ( moveMaster == this ) { - switch( state ) { - case MOVER_POS1: - break; - case MOVER_POS2: - break; - case MOVER_1TO2: - StartSound( "snd_open", SND_CHANNEL_ANY, 0, false, NULL ); - break; - case MOVER_2TO1: - StartSound( "snd_close", SND_CHANNEL_ANY, 0, false, NULL ); - break; - } - } -} - -/* -=============== -idMover_Binary::SetMoverState -=============== -*/ -void idMover_Binary::SetMoverState( moverState_t newstate, int time ) { - idVec3 delta; - - moverState = newstate; - move_thread = 0; - - UpdateMoverSound( newstate ); - - stateStartTime = time; - switch( moverState ) { - case MOVER_POS1: { - Signal( SIG_MOVER_POS1 ); - physicsObj.SetLinearExtrapolation( EXTRAPOLATION_NONE, time, 0, pos1, vec3_origin, vec3_origin ); - break; - } - case MOVER_POS2: { - Signal( SIG_MOVER_POS2 ); - physicsObj.SetLinearExtrapolation( EXTRAPOLATION_NONE, time, 0, pos2, vec3_origin, vec3_origin ); - break; - } - case MOVER_1TO2: { - Signal( SIG_MOVER_1TO2 ); - physicsObj.SetLinearExtrapolation( EXTRAPOLATION_LINEAR, time, duration, pos1, ( pos2 - pos1 ) * 1000.0f / duration, vec3_origin ); - if ( accelTime != 0 || decelTime != 0 ) { - physicsObj.SetLinearInterpolation( time, accelTime, decelTime, duration, pos1, pos2 ); - } else { - physicsObj.SetLinearInterpolation( 0, 0, 0, 0, pos1, pos2 ); - } - break; - } - case MOVER_2TO1: { - Signal( SIG_MOVER_2TO1 ); - physicsObj.SetLinearExtrapolation( EXTRAPOLATION_LINEAR, time, duration, pos2, ( pos1 - pos2 ) * 1000.0f / duration, vec3_origin ); - if ( accelTime != 0 || decelTime != 0 ) { - physicsObj.SetLinearInterpolation( time, accelTime, decelTime, duration, pos2, pos1 ); - } else { - physicsObj.SetLinearInterpolation( 0, 0, 0, 0, pos1, pos2 ); - } - break; - } - } -} - -/* -================ -idMover_Binary::MatchActivateTeam - -All entities in a mover team will move from pos1 to pos2 -in the same amount of time -================ -*/ -void idMover_Binary::MatchActivateTeam( moverState_t newstate, int time ) { - idMover_Binary *slave; - - for ( slave = this; slave != NULL; slave = slave->activateChain ) { - slave->SetMoverState( newstate, time ); - } -} - -/* -================ -idMover_Binary::Enable -================ -*/ -void idMover_Binary::Enable( bool b ) { - enabled = b; -} - -/* -================ -idMover_Binary::Event_MatchActivateTeam -================ -*/ -void idMover_Binary::Event_MatchActivateTeam( moverState_t newstate, int time ) { - MatchActivateTeam( newstate, time ); -} - -/* -================ -idMover_Binary::BindTeam - -All entities in a mover team will be bound -================ -*/ -void idMover_Binary::BindTeam( idEntity *bindTo ) { - idMover_Binary *slave; - - for ( slave = this; slave != NULL; slave = slave->activateChain ) { - slave->Bind( bindTo, true ); - } -} - -/* -================ -idMover_Binary::JoinActivateTeam - -Set all entities in a mover team to be enabled -================ -*/ -void idMover_Binary::JoinActivateTeam( idMover_Binary *master ) { - this->activateChain = master->activateChain; - master->activateChain = this; -} - -/* -================ -idMover_Binary::Event_Enable - -Set all entities in a mover team to be enabled -================ -*/ -void idMover_Binary::Event_Enable( void ) { - idMover_Binary *slave; - - for ( slave = moveMaster; slave != NULL; slave = slave->activateChain ) { - slave->Enable( false ); - } -} - -/* -================ -idMover_Binary::Event_Disable - -Set all entities in a mover team to be disabled -================ -*/ -void idMover_Binary::Event_Disable( void ) { - idMover_Binary *slave; - - for ( slave = moveMaster; slave != NULL; slave = slave->activateChain ) { - slave->Enable( false ); - } -} - -/* -================ -idMover_Binary::Event_OpenPortal - -Sets the portal associtated with this mover to be open -================ -*/ -void idMover_Binary::Event_OpenPortal( void ) { - idMover_Binary *slave; - - for ( slave = moveMaster; slave != NULL; slave = slave->activateChain ) { - if ( slave->areaPortal ) { - slave->SetPortalState( true ); - } -#ifdef _D3XP - if ( slave->playerOnly ) { - gameLocal.SetAASAreaState( slave->GetPhysics()->GetAbsBounds(), AREACONTENTS_CLUSTERPORTAL, false ); - } -#endif - } -} - -/* -================ -idMover_Binary::Event_ClosePortal - -Sets the portal associtated with this mover to be closed -================ -*/ -void idMover_Binary::Event_ClosePortal( void ) { - idMover_Binary *slave; - - for ( slave = moveMaster; slave != NULL; slave = slave->activateChain ) { - if ( !slave->IsHidden() ) { - if ( slave->areaPortal ) { - slave->SetPortalState( false ); - } -#ifdef _D3XP - if ( slave->playerOnly ) { - gameLocal.SetAASAreaState( slave->GetPhysics()->GetAbsBounds(), AREACONTENTS_CLUSTERPORTAL, true ); - } -#endif - } - } -} - -/* -================ -idMover_Binary::Event_ReturnToPos1 -================ -*/ -void idMover_Binary::Event_ReturnToPos1( void ) { - MatchActivateTeam( MOVER_2TO1, gameLocal.slow.time ); -} - -/* -================ -idMover_Binary::Event_Reached_BinaryMover -================ -*/ -void idMover_Binary::Event_Reached_BinaryMover( void ) { - - if ( moverState == MOVER_1TO2 ) { - // reached pos2 - idThread::ObjectMoveDone( move_thread, this ); - move_thread = 0; - - if ( moveMaster == this ) { - StartSound( "snd_opened", SND_CHANNEL_ANY, 0, false, NULL ); - } - - SetMoverState( MOVER_POS2, gameLocal.slow.time ); - - SetGuiStates( guiBinaryMoverStates[MOVER_POS2] ); - - UpdateBuddies( 1 ); - - if ( enabled && wait >= 0 && !spawnArgs.GetBool( "toggle" ) ) { - // return to pos1 after a delay - PostEventSec( &EV_Mover_ReturnToPos1, wait ); - } - - // fire targets - ActivateTargets( moveMaster->GetActivator() ); - - SetBlocked(false); - } else if ( moverState == MOVER_2TO1 ) { - // reached pos1 - idThread::ObjectMoveDone( move_thread, this ); - move_thread = 0; - - SetMoverState( MOVER_POS1, gameLocal.slow.time ); - - SetGuiStates( guiBinaryMoverStates[MOVER_POS1] ); - - UpdateBuddies( 0 ); - - // close areaportals - if ( moveMaster == this ) { - ProcessEvent( &EV_Mover_ClosePortal ); - } - - if ( enabled && wait >= 0 && spawnArgs.GetBool( "continuous" ) ) { - PostEventSec( &EV_Activate, wait, this ); - } - SetBlocked(false); - } else { - gameLocal.Error( "Event_Reached_BinaryMover: bad moverState" ); - } -} - -/* -================ -idMover_Binary::GotoPosition1 -================ -*/ -void idMover_Binary::GotoPosition1( void ) { - idMover_Binary *slave; - int partial; - - // only the master should control this - if ( moveMaster != this ) { - moveMaster->GotoPosition1(); - return; - } - - SetGuiStates( guiBinaryMoverStates[MOVER_2TO1] ); - - if ( ( moverState == MOVER_POS1 ) || ( moverState == MOVER_2TO1 ) ) { - // already there, or on the way - return; - } - - if ( moverState == MOVER_POS2 ) { - for ( slave = this; slave != NULL; slave = slave->activateChain ) { - slave->CancelEvents( &EV_Mover_ReturnToPos1 ); - } - if ( !spawnArgs.GetBool( "toggle" ) ) { - ProcessEvent( &EV_Mover_ReturnToPos1 ); - } - return; - } - - // only partway up before reversing - if ( moverState == MOVER_1TO2 ) { - // use the physics times because this might be executed during the physics simulation - partial = physicsObj.GetLinearEndTime() - physicsObj.GetTime(); - assert( partial >= 0 ); - if ( partial < 0 ) { - partial = 0; - } - MatchActivateTeam( MOVER_2TO1, physicsObj.GetTime() - partial ); - // if already at at position 1 (partial == duration) execute the reached event - if ( partial >= duration ) { - Event_Reached_BinaryMover(); - } - } -} - -/* -================ -idMover_Binary::GotoPosition2 -================ -*/ -void idMover_Binary::GotoPosition2( void ) { - int partial; - - // only the master should control this - if ( moveMaster != this ) { - moveMaster->GotoPosition2(); - return; - } - - SetGuiStates( guiBinaryMoverStates[MOVER_1TO2] ); - - if ( ( moverState == MOVER_POS2 ) || ( moverState == MOVER_1TO2 ) ) { - // already there, or on the way - return; - } - - if ( moverState == MOVER_POS1 ) { - MatchActivateTeam( MOVER_1TO2, gameLocal.slow.time ); - - // open areaportal - ProcessEvent( &EV_Mover_OpenPortal ); - return; - } - - - // only partway up before reversing - if ( moverState == MOVER_2TO1 ) { - // use the physics times because this might be executed during the physics simulation - partial = physicsObj.GetLinearEndTime() - physicsObj.GetTime(); - assert( partial >= 0 ); - if ( partial < 0 ) { - partial = 0; - } - MatchActivateTeam( MOVER_1TO2, physicsObj.GetTime() - partial ); - // if already at at position 2 (partial == duration) execute the reached event - if ( partial >= duration ) { - Event_Reached_BinaryMover(); - } - } -} - -/* -================ -idMover_Binary::UpdateBuddies -================ -*/ -void idMover_Binary::UpdateBuddies( int val ) { - int i, c; - - if ( updateStatus == 2 ) { - c = buddies.Num(); - for ( i = 0; i < c; i++ ) { - idEntity *buddy = gameLocal.FindEntity( buddies[i] ); - if ( buddy ) { - buddy->SetShaderParm( SHADERPARM_MODE, val ); - buddy->UpdateVisuals(); - } - } - } -} - -/* -================ -idMover_Binary::SetGuiStates -================ -*/ -void idMover_Binary::SetGuiStates( const char *state ) { - if ( guiTargets.Num() ) { - SetGuiState( "movestate", state ); - } - - idMover_Binary *mb = activateChain; - while( mb ) { - if ( mb->guiTargets.Num() ) { - mb->SetGuiState( "movestate", state ); - } - mb = mb->activateChain; - } -} - -/* -================ -idMover_Binary::Use_BinaryMover -================ -*/ -void idMover_Binary::Use_BinaryMover( idEntity *activator ) { - // only the master should be used - if ( moveMaster != this ) { - moveMaster->Use_BinaryMover( activator ); - return; - } - - if ( !enabled ) { - return; - } - - activatedBy = activator; - - if ( moverState == MOVER_POS1 ) { - // FIXME: start moving USERCMD_MSEC later, because if this was player - // triggered, gameLocal.time hasn't been advanced yet - MatchActivateTeam( MOVER_1TO2, gameLocal.slow.time + USERCMD_MSEC ); - - SetGuiStates( guiBinaryMoverStates[MOVER_1TO2] ); - // open areaportal - ProcessEvent( &EV_Mover_OpenPortal ); - return; - } - - // if all the way up, just delay before coming down - if ( moverState == MOVER_POS2 ) { - idMover_Binary *slave; - - if ( wait == -1 ) { - return; - } - - SetGuiStates( guiBinaryMoverStates[MOVER_2TO1] ); - - for ( slave = this; slave != NULL; slave = slave->activateChain ) { - slave->CancelEvents( &EV_Mover_ReturnToPos1 ); - slave->PostEventSec( &EV_Mover_ReturnToPos1, spawnArgs.GetBool( "toggle" ) ? 0 : wait ); - } - return; - } - - // only partway down before reversing - if ( moverState == MOVER_2TO1 ) { - GotoPosition2(); - return; - } - - // only partway up before reversing - if ( moverState == MOVER_1TO2 ) { - GotoPosition1(); - return; - } -} - -/* -================ -idMover_Binary::Event_Use_BinaryMover -================ -*/ -void idMover_Binary::Event_Use_BinaryMover( idEntity *activator ) { - Use_BinaryMover( activator ); -} - -/* -================ -idMover_Binary::PreBind -================ -*/ -void idMover_Binary::PreBind( void ) { - pos1 = GetWorldCoordinates( pos1 ); - pos2 = GetWorldCoordinates( pos2 ); -} - -/* -================ -idMover_Binary::PostBind -================ -*/ -void idMover_Binary::PostBind( void ) { - pos1 = GetLocalCoordinates( pos1 ); - pos2 = GetLocalCoordinates( pos2 ); -} - -/* -================ -idMover_Binary::FindGuiTargets -================ -*/ -void idMover_Binary::FindGuiTargets( void ) { - gameLocal.GetTargets( spawnArgs, guiTargets, "guiTarget" ); -} - -/* -============================== -idMover_Binary::SetGuiState - -key/val will be set to any renderEntity->gui's on the list -============================== -*/ -void idMover_Binary::SetGuiState( const char *key, const char *val ) const { - int i; - - for( i = 0; i < guiTargets.Num(); i++ ) { - idEntity *ent = guiTargets[ i ].GetEntity(); - if ( ent ) { - for ( int j = 0; j < MAX_RENDERENTITY_GUI; j++ ) { - if ( ent->GetRenderEntity() && ent->GetRenderEntity()->gui[ j ] ) { - ent->GetRenderEntity()->gui[ j ]->SetStateString( key, val ); - ent->GetRenderEntity()->gui[ j ]->StateChanged( gameLocal.slow.time, true ); - } - } - ent->UpdateVisuals(); - } - } -} - -/* -================ -idMover_Binary::Event_InitGuiTargets -================ -*/ -void idMover_Binary::Event_FindGuiTargets( void ) { - FindGuiTargets(); -} - -/* -================ -idMover_Binary::Event_InitGuiTargets -================ -*/ -void idMover_Binary::Event_InitGuiTargets( void ) { - if ( guiTargets.Num() ) { - SetGuiState( "movestate", guiBinaryMoverStates[MOVER_POS1] ); - } -} - -/* -================ -idMover_Binary::InitSpeed - -pos1, pos2, and speed are passed in so the movement delta can be calculated -================ -*/ -void idMover_Binary::InitSpeed( idVec3 &mpos1, idVec3 &mpos2, float mspeed, float maccelTime, float mdecelTime ) { - idVec3 move; - float distance; - float speed; - - pos1 = mpos1; - pos2 = mpos2; - - accelTime = idPhysics::SnapTimeToPhysicsFrame( SEC2MS( maccelTime ) ); - decelTime = idPhysics::SnapTimeToPhysicsFrame( SEC2MS( mdecelTime ) ); - - speed = mspeed ? mspeed : 100; - - // calculate time to reach second position from speed - move = pos2 - pos1; - distance = move.Length(); - duration = idPhysics::SnapTimeToPhysicsFrame( distance * 1000 / speed ); - if ( duration <= 0 ) { - duration = 1; - } - - moverState = MOVER_POS1; - - physicsObj.SetLinearExtrapolation( EXTRAPOLATION_NONE, 0, 0, pos1, vec3_origin, vec3_origin ); - physicsObj.SetLinearInterpolation( 0, 0, 0, 0, vec3_origin, vec3_origin ); - SetOrigin( pos1 ); - - PostEventMS( &EV_Mover_InitGuiTargets, 0 ); -} - -/* -================ -idMover_Binary::InitTime - -pos1, pos2, and time are passed in so the movement delta can be calculated -================ -*/ -void idMover_Binary::InitTime( idVec3 &mpos1, idVec3 &mpos2, float mtime, float maccelTime, float mdecelTime ) { - - pos1 = mpos1; - pos2 = mpos2; - - accelTime = idPhysics::SnapTimeToPhysicsFrame( SEC2MS( maccelTime ) ); - decelTime = idPhysics::SnapTimeToPhysicsFrame( SEC2MS( mdecelTime ) ); - - duration = idPhysics::SnapTimeToPhysicsFrame( SEC2MS( mtime ) ); - if ( duration <= 0 ) { - duration = 1; - } - - moverState = MOVER_POS1; - - physicsObj.SetLinearExtrapolation( EXTRAPOLATION_NONE, 0, 0, pos1, vec3_origin, vec3_origin ); - physicsObj.SetLinearInterpolation( 0, 0, 0, 0, vec3_origin, vec3_origin ); - SetOrigin( pos1 ); - - PostEventMS( &EV_Mover_InitGuiTargets, 0 ); -} - -/* -================ -idMover_Binary::SetBlocked -================ -*/ -void idMover_Binary::SetBlocked( bool b ) { - for ( idMover_Binary *slave = moveMaster; slave != NULL; slave = slave->activateChain ) { - slave->blocked = b; - if ( b ) { - const idKeyValue *kv = slave->spawnArgs.MatchPrefix( "triggerBlocked" ); - while( kv ) { - idEntity *ent = gameLocal.FindEntity( kv->GetValue() ); - if ( ent ) { - ent->PostEventMS( &EV_Activate, 0, moveMaster->GetActivator() ); - } - kv = slave->spawnArgs.MatchPrefix( "triggerBlocked", kv ); - } - } - } -} - -/* -================ -idMover_Binary::IsBlocked -================ -*/ -bool idMover_Binary::IsBlocked( void ) { - return blocked; -} - -/* -================ -idMover_Binary::GetActivator -================ -*/ -idEntity *idMover_Binary::GetActivator( void ) const { - return activatedBy.GetEntity(); -} - -/* -================ -idMover_Binary::WriteToSnapshot -================ -*/ -void idMover_Binary::WriteToSnapshot( idBitMsgDelta &msg ) const { - physicsObj.WriteToSnapshot( msg ); - msg.WriteBits( moverState, 3 ); - WriteBindToSnapshot( msg ); -} - -/* -================ -idMover_Binary::ReadFromSnapshot -================ -*/ -void idMover_Binary::ReadFromSnapshot( const idBitMsgDelta &msg ) { - moverState_t oldMoverState = moverState; - - physicsObj.ReadFromSnapshot( msg ); - moverState = (moverState_t) msg.ReadBits( 3 ); - ReadBindFromSnapshot( msg ); - - if ( msg.HasChanged() ) { - if ( moverState != oldMoverState ) { - UpdateMoverSound( moverState ); - } - UpdateVisuals(); - } -} - -/* -================ -idMover_Binary::SetPortalState -================ -*/ -void idMover_Binary::SetPortalState( bool open ) { - assert( areaPortal ); - gameLocal.SetPortalState( areaPortal, open ? PS_BLOCK_NONE : PS_BLOCK_ALL ); -} - -/* -=============================================================================== - -idDoor - -A use can be triggered either by a touch function, by being shot, or by being -targeted by another entity. - -=============================================================================== -*/ - -const idEventDef EV_Door_StartOpen( "", NULL ); -const idEventDef EV_Door_SpawnDoorTrigger( "", NULL ); -const idEventDef EV_Door_SpawnSoundTrigger( "", NULL ); -const idEventDef EV_Door_Open( "open", NULL ); -const idEventDef EV_Door_Close( "close", NULL ); -const idEventDef EV_Door_Lock( "lock", "d" ); -const idEventDef EV_Door_IsOpen( "isOpen", NULL, 'f' ); -const idEventDef EV_Door_IsLocked( "isLocked", NULL, 'f' ); - -CLASS_DECLARATION( idMover_Binary, idDoor ) - EVENT( EV_TeamBlocked, idDoor::Event_TeamBlocked ) - EVENT( EV_PartBlocked, idDoor::Event_PartBlocked ) - EVENT( EV_Touch, idDoor::Event_Touch ) - EVENT( EV_Activate, idDoor::Event_Activate ) - EVENT( EV_Door_StartOpen, idDoor::Event_StartOpen ) - EVENT( EV_Door_SpawnDoorTrigger, idDoor::Event_SpawnDoorTrigger ) - EVENT( EV_Door_SpawnSoundTrigger, idDoor::Event_SpawnSoundTrigger ) - EVENT( EV_Door_Open, idDoor::Event_Open ) - EVENT( EV_Door_Close, idDoor::Event_Close ) - EVENT( EV_Door_Lock, idDoor::Event_Lock ) - EVENT( EV_Door_IsOpen, idDoor::Event_IsOpen ) - EVENT( EV_Door_IsLocked, idDoor::Event_Locked ) - EVENT( EV_ReachedPos, idDoor::Event_Reached_BinaryMover ) - EVENT( EV_SpectatorTouch, idDoor::Event_SpectatorTouch ) - EVENT( EV_Mover_OpenPortal, idDoor::Event_OpenPortal ) - EVENT( EV_Mover_ClosePortal, idDoor::Event_ClosePortal ) -END_CLASS - -/* -================ -idDoor::idDoor -================ -*/ -idDoor::idDoor( void ) { - triggersize = 1.0f; - crusher = false; - noTouch = false; - aas_area_closed = false; - buddyStr.Clear(); - trigger = NULL; - sndTrigger = NULL; - nextSndTriggerTime = 0; - localTriggerOrigin.Zero(); - localTriggerAxis.Identity(); - requires.Clear(); - removeItem = 0; - syncLock.Clear(); - companionDoor = NULL; - normalAxisIndex = 0; -} - -/* -================ -idDoor::~idDoor -================ -*/ -idDoor::~idDoor( void ) { - if ( trigger ) { - delete trigger; - } - if ( sndTrigger ) { - delete sndTrigger; - } -} - -/* -================ -idDoor::Save -================ -*/ -void idDoor::Save( idSaveGame *savefile ) const { - - savefile->WriteFloat( triggersize ); - savefile->WriteBool( crusher ); - savefile->WriteBool( noTouch ); - savefile->WriteBool( aas_area_closed ); - savefile->WriteString( buddyStr ); - savefile->WriteInt( nextSndTriggerTime ); - - savefile->WriteVec3( localTriggerOrigin ); - savefile->WriteMat3( localTriggerAxis ); - - savefile->WriteString( requires ); - savefile->WriteInt( removeItem ); - savefile->WriteString( syncLock ); - savefile->WriteInt( normalAxisIndex ); - - savefile->WriteClipModel( trigger ); - savefile->WriteClipModel( sndTrigger ); - - savefile->WriteObject( companionDoor ); -} - -/* -================ -idDoor::Restore -================ -*/ -void idDoor::Restore( idRestoreGame *savefile ) { - - savefile->ReadFloat( triggersize ); - savefile->ReadBool( crusher ); - savefile->ReadBool( noTouch ); - savefile->ReadBool( aas_area_closed ); - SetAASAreaState( aas_area_closed ); - savefile->ReadString( buddyStr ); - savefile->ReadInt( nextSndTriggerTime ); - - savefile->ReadVec3( localTriggerOrigin ); - savefile->ReadMat3( localTriggerAxis ); - - savefile->ReadString( requires ); - savefile->ReadInt( removeItem ); - savefile->ReadString( syncLock ); - savefile->ReadInt( normalAxisIndex ); - - savefile->ReadClipModel( trigger ); - savefile->ReadClipModel( sndTrigger ); - - savefile->ReadObject( reinterpret_cast( companionDoor ) ); -} - -/* -================ -idDoor::Spawn -================ -*/ -void idDoor::Spawn( void ) { - idVec3 abs_movedir; - float distance; - idVec3 size; - idVec3 movedir; - float dir; - float lip; - bool start_open; - float time; - float speed; - - // get the direction to move - if ( !spawnArgs.GetFloat( "movedir", "0", dir ) ) { - // no movedir, so angle defines movement direction and not orientation, - // a la oldschool Quake - SetAngles( ang_zero ); - spawnArgs.GetFloat( "angle", "0", dir ); - } - GetMovedir( dir, movedir ); - - // default speed of 400 - spawnArgs.GetFloat( "speed", "400", speed ); - - // default wait of 2 seconds - spawnArgs.GetFloat( "wait", "3", wait ); - - // default lip of 8 units - spawnArgs.GetFloat( "lip", "8", lip ); - - // by default no damage - spawnArgs.GetFloat( "damage", "0", damage ); - - // trigger size - spawnArgs.GetFloat( "triggersize", "120", triggersize ); - - spawnArgs.GetBool( "crusher", "0", crusher ); - spawnArgs.GetBool( "start_open", "0", start_open ); - spawnArgs.GetBool( "no_touch", "0", noTouch ); -#ifdef _D3XP - spawnArgs.GetBool( "player_only", "0", playerOnly ); -#endif - - // expects syncLock to be a door that must be closed before this door will open - spawnArgs.GetString( "syncLock", "", syncLock ); - - spawnArgs.GetString( "buddy", "", buddyStr ); - - spawnArgs.GetString( "requires", "", requires ); - spawnArgs.GetInt( "removeItem", "0", removeItem ); - - // ever separate piece of a door is considered solid when other team mates push entities - fl.solidForTeam = true; - - // first position at start - pos1 = GetPhysics()->GetOrigin(); - - // calculate second position - abs_movedir[0] = idMath::Fabs( movedir[ 0 ] ); - abs_movedir[1] = idMath::Fabs( movedir[ 1 ] ); - abs_movedir[2] = idMath::Fabs( movedir[ 2 ] ); - size = GetPhysics()->GetAbsBounds()[1] - GetPhysics()->GetAbsBounds()[0]; - distance = ( abs_movedir * size ) - lip; - pos2 = pos1 + distance * movedir; - - // if "start_open", reverse position 1 and 2 - if ( start_open ) { - // post it after EV_SpawnBind - PostEventMS( &EV_Door_StartOpen, 1 ); - } - - if ( spawnArgs.GetFloat( "time", "1", time ) ) { - InitTime( pos1, pos2, time, 0, 0 ); - } else { - InitSpeed( pos1, pos2, speed, 0, 0 ); - } - - if ( moveMaster == this ) { - if ( health ) { - fl.takedamage = true; - } - if ( noTouch || health ) { - // non touch/shoot doors - PostEventMS( &EV_Mover_MatchTeam, 0, moverState, gameLocal.slow.time ); - - const char *sndtemp = spawnArgs.GetString( "snd_locked" ); - if ( spawnArgs.GetInt( "locked" ) && sndtemp && *sndtemp ) { - PostEventMS( &EV_Door_SpawnSoundTrigger, 0 ); - } - } else { - // spawn trigger - PostEventMS( &EV_Door_SpawnDoorTrigger, 0 ); - } - } - - // see if we are on an areaportal - areaPortal = gameRenderWorld->FindPortal( GetPhysics()->GetAbsBounds() ); - if ( !start_open ) { - // start closed - ProcessEvent( &EV_Mover_ClosePortal ); - -#ifdef _D3XP - if ( playerOnly ) { - gameLocal.SetAASAreaState( GetPhysics()->GetAbsBounds(), AREACONTENTS_CLUSTERPORTAL, true ); - } -#endif - } - - int locked = spawnArgs.GetInt( "locked" ); - if ( locked ) { - // make sure all members of the team get locked - PostEventMS( &EV_Door_Lock, 0, locked ); - } - - if ( spawnArgs.GetBool( "continuous" ) ) { - PostEventSec( &EV_Activate, spawnArgs.GetFloat( "delay" ), this ); - } - - // sounds have a habit of stuttering when portals close, so make them unoccluded - refSound.parms.soundShaderFlags |= SSF_NO_OCCLUSION; - - companionDoor = NULL; - - enabled = true; - blocked = false; -} - -/* -================ -idDoor::Think -================ -*/ -void idDoor::Think( void ) { - idVec3 masterOrigin; - idMat3 masterAxis; - - idMover_Binary::Think(); - - if ( thinkFlags & TH_PHYSICS ) { - // update trigger position - if ( GetMasterPosition( masterOrigin, masterAxis ) ) { - if ( trigger ) { - trigger->Link( gameLocal.clip, this, 0, masterOrigin + localTriggerOrigin * masterAxis, localTriggerAxis * masterAxis ); - } - if ( sndTrigger ) { - sndTrigger->Link( gameLocal.clip, this, 0, masterOrigin + localTriggerOrigin * masterAxis, localTriggerAxis * masterAxis ); - } - } - } -} - -/* -================ -idDoor::PreBind -================ -*/ -void idDoor::PreBind( void ) { - idMover_Binary::PreBind(); -} - -/* -================ -idDoor::PostBind -================ -*/ -void idDoor::PostBind( void ) { - idMover_Binary::PostBind(); - GetLocalTriggerPosition( trigger ? trigger : sndTrigger ); -} - -/* -================ -idDoor::SetAASAreaState -================ -*/ -void idDoor::SetAASAreaState( bool closed ) { - aas_area_closed = closed; - gameLocal.SetAASAreaState( physicsObj.GetAbsBounds(), AREACONTENTS_CLUSTERPORTAL|AREACONTENTS_OBSTACLE, closed ); -} - -/* -================ -idDoor::Hide -================ -*/ -void idDoor::Hide( void ) { - idMover_Binary *slave; - idMover_Binary *master; - idDoor *slaveDoor; - idDoor *companion; - - master = GetMoveMaster(); - if ( this != master ) { - master->Hide(); - } else { - for ( slave = this; slave != NULL; slave = slave->GetActivateChain() ) { - if ( slave->IsType( idDoor::Type ) ) { - slaveDoor = static_cast( slave ); - companion = slaveDoor->companionDoor; - if ( companion && ( companion != master ) && ( companion->GetMoveMaster() != master ) ) { - companion->Hide(); - } - if ( slaveDoor->trigger ) { - slaveDoor->trigger->Disable(); - } - if ( slaveDoor->sndTrigger ) { - slaveDoor->sndTrigger->Disable(); - } - if ( slaveDoor->areaPortal ) { - slaveDoor->SetPortalState( true ); - } - slaveDoor->SetAASAreaState( false ); - } - slave->GetPhysics()->GetClipModel()->Disable(); - slave->idMover_Binary::Hide(); - } - } -} - -/* -================ -idDoor::Show -================ -*/ -void idDoor::Show( void ) { - idMover_Binary *slave; - idMover_Binary *master; - idDoor *slaveDoor; - idDoor *companion; - - master = GetMoveMaster(); - if ( this != master ) { - master->Show(); - } else { - for ( slave = this; slave != NULL; slave = slave->GetActivateChain() ) { - if ( slave->IsType( idDoor::Type ) ) { - slaveDoor = static_cast( slave ); - companion = slaveDoor->companionDoor; - if ( companion && ( companion != master ) && ( companion->GetMoveMaster() != master ) ) { - companion->Show(); - } - if ( slaveDoor->trigger ) { - slaveDoor->trigger->Enable(); - } - if ( slaveDoor->sndTrigger ) { - slaveDoor->sndTrigger->Enable(); - } - if ( slaveDoor->areaPortal && ( slaveDoor->moverState == MOVER_POS1 ) ) { - slaveDoor->SetPortalState( false ); - } - slaveDoor->SetAASAreaState( IsLocked() || IsNoTouch() ); - } - slave->GetPhysics()->GetClipModel()->Enable(); - slave->idMover_Binary::Show(); - } - } -} - -/* -================ -idDoor::GetLocalTriggerPosition -================ -*/ -void idDoor::GetLocalTriggerPosition( const idClipModel *trigger ) { - idVec3 origin; - idMat3 axis; - - if ( !trigger ) { - return; - } - - GetMasterPosition( origin, axis ); - localTriggerOrigin = ( trigger->GetOrigin() - origin ) * axis.Transpose(); - localTriggerAxis = trigger->GetAxis() * axis.Transpose(); -} - -/* -================ -idDoor::Use -================ -*/ -void idDoor::Use( idEntity *other, idEntity *activator ) { - if ( gameLocal.RequirementMet( activator, requires, removeItem ) ) { - if ( syncLock.Length() ) { - idEntity *sync = gameLocal.FindEntity( syncLock ); - if ( sync && sync->IsType( idDoor::Type ) ) { - if ( static_cast( sync )->IsOpen() ) { - return; - } - } - } - ActivateTargets( activator ); - Use_BinaryMover( activator ); - } -} - -/* -================ -idDoor::Open -================ -*/ -void idDoor::Open( void ) { - GotoPosition2(); -} - -/* -================ -idDoor::Close -================ -*/ -void idDoor::Close( void ) { - GotoPosition1(); -} - -/* -================ -idDoor::Lock -================ -*/ -void idDoor::Lock( int f ) { - idMover_Binary *other; - - // lock all the doors on the team - for( other = moveMaster; other != NULL; other = other->GetActivateChain() ) { - if ( other->IsType( idDoor::Type ) ) { - idDoor *door = static_cast( other ); - if ( other == moveMaster ) { - if ( door->sndTrigger == NULL ) { - // in this case the sound trigger never got spawned - const char *sndtemp = door->spawnArgs.GetString( "snd_locked" ); - if ( sndtemp && *sndtemp ) { - door->PostEventMS( &EV_Door_SpawnSoundTrigger, 0 ); - } - } - if ( !f && ( door->spawnArgs.GetInt( "locked" ) != 0 ) ) { - door->StartSound( "snd_unlocked", SND_CHANNEL_ANY, 0, false, NULL ); - } - } - door->spawnArgs.SetInt( "locked", f ); - if ( ( f == 0 ) || ( !IsHidden() && ( door->moverState == MOVER_POS1 ) ) ) { - door->SetAASAreaState( f != 0 ); - } - } - } - - if ( f ) { - Close(); - } -} - -/* -================ -idDoor::IsLocked -================ -*/ -int idDoor::IsLocked( void ) { - return spawnArgs.GetInt( "locked" ); -} - -/* -================ -idDoor::IsOpen -================ -*/ -bool idDoor::IsOpen( void ) { - return ( moverState != MOVER_POS1 ); -} - -/* -================ -idDoor::IsNoTouch -================ -*/ -bool idDoor::IsNoTouch( void ) { - return noTouch; -} - -#ifdef _D3XP -/* -================ -idDoor::AllowPlayerOnly -================ -*/ -bool idDoor::AllowPlayerOnly( idEntity *ent ) { - if ( playerOnly && !ent->IsType(idPlayer::Type) ) { - return false; - } - - return true; -} -#endif - -/* -====================== -idDoor::CalcTriggerBounds - -Calcs bounds for a trigger. -====================== -*/ -void idDoor::CalcTriggerBounds( float size, idBounds &bounds ) { - idMover_Binary *other; - int i; - int best; - - // find the bounds of everything on the team - bounds = GetPhysics()->GetAbsBounds(); - - fl.takedamage = true; - for( other = activateChain; other != NULL; other = other->GetActivateChain() ) { - if ( other->IsType( idDoor::Type ) ) { - // find the bounds of everything on the team - bounds.AddBounds( other->GetPhysics()->GetAbsBounds() ); - - // set all of the slaves as shootable - other->fl.takedamage = true; - } - } - - // find the thinnest axis, which will be the one we expand - best = 0; - for ( i = 1 ; i < 3 ; i++ ) { - if ( bounds[1][ i ] - bounds[0][ i ] < bounds[1][ best ] - bounds[0][ best ] ) { - best = i; - } - } - normalAxisIndex = best; - bounds[0][ best ] -= size; - bounds[1][ best ] += size; - bounds[0] -= GetPhysics()->GetOrigin(); - bounds[1] -= GetPhysics()->GetOrigin(); -} - -/* -====================== -idDoor::Event_StartOpen - -if "start_open", reverse position 1 and 2 -====================== -*/ -void idDoor::Event_StartOpen( void ) { - float time; - float speed; - - // if "start_open", reverse position 1 and 2 - pos1 = pos2; - pos2 = GetPhysics()->GetOrigin(); - - spawnArgs.GetFloat( "speed", "400", speed ); - - if ( spawnArgs.GetFloat( "time", "1", time ) ) { - InitTime( pos1, pos2, time, 0, 0 ); - } else { - InitSpeed( pos1, pos2, speed, 0, 0 ); - } -} - -/* -====================== -idDoor::Event_SpawnDoorTrigger - -All of the parts of a door have been spawned, so create -a trigger that encloses all of them. -====================== -*/ -void idDoor::Event_SpawnDoorTrigger( void ) { - idBounds bounds; - idMover_Binary *other; - bool toggle; - - if ( trigger ) { - // already have a trigger, so don't spawn a new one. - return; - } - - // check if any of the doors are marked as toggled - toggle = false; - for( other = moveMaster; other != NULL; other = other->GetActivateChain() ) { - if ( other->IsType( idDoor::Type ) && other->spawnArgs.GetBool( "toggle" ) ) { - toggle = true; - break; - } - } - - if ( toggle ) { - // mark them all as toggled - for( other = moveMaster; other != NULL; other = other->GetActivateChain() ) { - if ( other->IsType( idDoor::Type ) ) { - other->spawnArgs.Set( "toggle", "1" ); - } - } - // don't spawn trigger - return; - } - - const char *sndtemp = spawnArgs.GetString( "snd_locked" ); - if ( spawnArgs.GetInt( "locked" ) && sndtemp && *sndtemp ) { - PostEventMS( &EV_Door_SpawnSoundTrigger, 0 ); - } - - CalcTriggerBounds( triggersize, bounds ); - - // create a trigger clip model - trigger = new idClipModel( idTraceModel( bounds ) ); - trigger->Link( gameLocal.clip, this, 255, GetPhysics()->GetOrigin(), mat3_identity ); - trigger->SetContents( CONTENTS_TRIGGER ); - - GetLocalTriggerPosition( trigger ); - - MatchActivateTeam( moverState, gameLocal.slow.time ); -} - -/* -====================== -idDoor::Event_SpawnSoundTrigger - -Spawn a sound trigger to activate locked sound if it exists. -====================== -*/ -void idDoor::Event_SpawnSoundTrigger( void ) { - idBounds bounds; - - if ( sndTrigger ) { - return; - } - - CalcTriggerBounds( triggersize * 0.5f, bounds ); - - // create a trigger clip model - sndTrigger = new idClipModel( idTraceModel( bounds ) ); - sndTrigger->Link( gameLocal.clip, this, 254, GetPhysics()->GetOrigin(), mat3_identity ); - sndTrigger->SetContents( CONTENTS_TRIGGER ); - - GetLocalTriggerPosition( sndTrigger ); -} - -/* -================ -idDoor::Event_Reached_BinaryMover -================ -*/ -void idDoor::Event_Reached_BinaryMover( void ) { - if ( moverState == MOVER_2TO1 ) { - SetBlocked( false ); - const idKeyValue *kv = spawnArgs.MatchPrefix( "triggerClosed" ); - while( kv ) { - idEntity *ent = gameLocal.FindEntity( kv->GetValue() ); - if ( ent ) { - ent->PostEventMS( &EV_Activate, 0, moveMaster->GetActivator() ); - } - kv = spawnArgs.MatchPrefix( "triggerClosed", kv ); - } - } else if ( moverState == MOVER_1TO2 ) { - const idKeyValue *kv = spawnArgs.MatchPrefix( "triggerOpened" ); - while( kv ) { - idEntity *ent = gameLocal.FindEntity( kv->GetValue() ); - if ( ent ) { - ent->PostEventMS( &EV_Activate, 0, moveMaster->GetActivator() ); - } - kv = spawnArgs.MatchPrefix( "triggerOpened", kv ); - } - } - idMover_Binary::Event_Reached_BinaryMover(); -} - -/* -================ -idDoor::Blocked_Door -================ -*/ -void idDoor::Event_TeamBlocked( idEntity *blockedEntity, idEntity *blockingEntity ) { - SetBlocked( true ); - - if ( crusher ) { - return; // crushers don't reverse - } - - // reverse direction - Use_BinaryMover( moveMaster->GetActivator() ); - - if ( companionDoor ) { - companionDoor->ProcessEvent( &EV_TeamBlocked, blockedEntity, blockingEntity ); - } -} - -/* -=============== -idDoor::SetCompanion -=============== -*/ -void idDoor::SetCompanion( idDoor *door ) { - companionDoor = door; -} - -/* -=============== -idDoor::Event_PartBlocked -=============== -*/ -void idDoor::Event_PartBlocked( idEntity *blockingEntity ) { - if ( damage > 0.0f ) { - blockingEntity->Damage( this, this, vec3_origin, "damage_moverCrush", damage, INVALID_JOINT ); - } -} - -/* -================ -idDoor::Event_Touch -================ -*/ -void idDoor::Event_Touch( idEntity *other, trace_t *trace ) { - idVec3 contact, translate; - idVec3 planeaxis1, planeaxis2, normal; - idBounds bounds; - - if ( !enabled ) { - return; - } - - if ( trigger && trace->c.id == trigger->GetId() ) { - if ( !IsNoTouch() && !IsLocked() && GetMoverState() != MOVER_1TO2 ) { -#ifdef _D3XP - if ( AllowPlayerOnly( other ) ) { -#endif - Use( this, other ); -#ifdef _D3XP - } -#endif - } - } else if ( sndTrigger && trace->c.id == sndTrigger->GetId() ) { - if ( other && other->IsType( idPlayer::Type ) && IsLocked() && gameLocal.slow.time > nextSndTriggerTime ) { - StartSound( "snd_locked", SND_CHANNEL_ANY, 0, false, NULL ); - nextSndTriggerTime = gameLocal.slow.time + 10000; - } - } -} - -/* -================ -idDoor::Event_SpectatorTouch -================ -*/ -void idDoor::Event_SpectatorTouch( idEntity *other, trace_t *trace ) { - idVec3 contact, translate, normal; - idBounds bounds; - idPlayer *p; - - assert( other && other->IsType( idPlayer::Type ) && static_cast< idPlayer * >( other )->spectating ); - - p = static_cast< idPlayer * >( other ); - // avoid flicker when stopping right at clip box boundaries - if ( p->lastSpectateTeleport > gameLocal.slow.time - 1000 ) { - return; - } - if ( trigger && !IsOpen() ) { - // teleport to the other side, center to the middle of the trigger brush - bounds = trigger->GetAbsBounds(); - contact = trace->endpos - bounds.GetCenter(); - translate = bounds.GetCenter(); - normal.Zero(); - normal[ normalAxisIndex ] = 1.0f; - if ( normal * contact > 0 ) { - translate[ normalAxisIndex ] += ( bounds[ 0 ][ normalAxisIndex ] - translate[ normalAxisIndex ] ) * 0.5f; - } else { - translate[ normalAxisIndex ] += ( bounds[ 1 ][ normalAxisIndex ] - translate[ normalAxisIndex ] ) * 0.5f; - } - p->SetOrigin( translate ); - p->lastSpectateTeleport = gameLocal.slow.time; - } -} - -/* -================ -idDoor::Event_Activate -================ -*/ -void idDoor::Event_Activate( idEntity *activator ) { - int old_lock; - - if ( spawnArgs.GetInt( "locked" ) ) { - if ( !trigger ) { - PostEventMS( &EV_Door_SpawnDoorTrigger, 0 ); - } - if ( buddyStr.Length() ) { - idEntity *buddy = gameLocal.FindEntity( buddyStr ); - if ( buddy ) { - buddy->SetShaderParm( SHADERPARM_MODE, 1 ); - buddy->UpdateVisuals(); - } - } - - old_lock = spawnArgs.GetInt( "locked" ); - Lock( 0 ); - if ( old_lock == 2 ) { - return; - } - } - - if ( syncLock.Length() ) { - idEntity *sync = gameLocal.FindEntity( syncLock ); - if ( sync && sync->IsType( idDoor::Type ) ) { - if ( static_cast( sync )->IsOpen() ) { - return; - } - } - } - - ActivateTargets( activator ); - - renderEntity.shaderParms[ SHADERPARM_MODE ] = 1; - UpdateVisuals(); - - Use_BinaryMover( activator ); -} - -/* -================ -idDoor::Event_Open -================ -*/ -void idDoor::Event_Open( void ) { - Open(); -} - -/* -================ -idDoor::Event_Close -================ -*/ -void idDoor::Event_Close( void ) { - Close(); -} - -/* -================ -idDoor::Event_Lock -================ -*/ -void idDoor::Event_Lock( int f ) { - Lock( f ); -} - -/* -================ -idDoor::Event_IsOpen -================ -*/ -void idDoor::Event_IsOpen( void ) { - bool state; - - state = IsOpen(); - idThread::ReturnFloat( state ); -} - -/* -================ -idDoor::Event_Locked -================ -*/ -void idDoor::Event_Locked( void ) { - idThread::ReturnFloat( spawnArgs.GetInt("locked") ); -} - -/* -================ -idDoor::Event_OpenPortal - -Sets the portal associtated with this door to be open -================ -*/ -void idDoor::Event_OpenPortal( void ) { - idMover_Binary *slave; - idDoor *slaveDoor; - - for ( slave = this; slave != NULL; slave = slave->GetActivateChain() ) { - if ( slave->IsType( idDoor::Type ) ) { - slaveDoor = static_cast( slave ); - if ( slaveDoor->areaPortal ) { - slaveDoor->SetPortalState( true ); - } - slaveDoor->SetAASAreaState( false ); - } - } -} - -/* -================ -idDoor::Event_ClosePortal - -Sets the portal associtated with this door to be closed -================ -*/ -void idDoor::Event_ClosePortal( void ) { - idMover_Binary *slave; - idDoor *slaveDoor; - - for ( slave = this; slave != NULL; slave = slave->GetActivateChain() ) { - if ( !slave->IsHidden() ) { - if ( slave->IsType( idDoor::Type ) ) { - slaveDoor = static_cast( slave ); - if ( slaveDoor->areaPortal ) { - slaveDoor->SetPortalState( false ); - } - slaveDoor->SetAASAreaState( IsLocked() || IsNoTouch() ); - } - } - } -} - - -/* -=============================================================================== - -idPlat - -=============================================================================== -*/ - -CLASS_DECLARATION( idMover_Binary, idPlat ) - EVENT( EV_Touch, idPlat::Event_Touch ) - EVENT( EV_TeamBlocked, idPlat::Event_TeamBlocked ) - EVENT( EV_PartBlocked, idPlat::Event_PartBlocked ) -END_CLASS - -/* -=============== -idPlat::idPlat -=============== -*/ -idPlat::idPlat( void ) { - trigger = NULL; - localTriggerOrigin.Zero(); - localTriggerAxis.Identity(); -} - -/* -=============== -idPlat::~idPlat -=============== -*/ -idPlat::~idPlat( void ) { - if ( trigger ) { - delete trigger; - } -} - -/* -=============== -idPlat::Save -=============== -*/ -void idPlat::Save( idSaveGame *savefile ) const { - savefile->WriteClipModel( trigger ); - savefile->WriteVec3( localTriggerOrigin ); - savefile->WriteMat3( localTriggerAxis ); -} - -/* -=============== -idPlat::Restore -=============== -*/ -void idPlat::Restore( idRestoreGame *savefile ) { - savefile->ReadClipModel( trigger ); - savefile->ReadVec3( localTriggerOrigin ); - savefile->ReadMat3( localTriggerAxis ); -} - -/* -=============== -idPlat::Spawn -=============== -*/ -void idPlat::Spawn( void ) { - float lip; - float height; - float time; - float speed; - float accel; - float decel; - bool noTouch; - - spawnArgs.GetFloat( "speed", "100", speed ); - spawnArgs.GetFloat( "damage", "0", damage ); - spawnArgs.GetFloat( "wait", "1", wait ); - spawnArgs.GetFloat( "lip", "8", lip ); - spawnArgs.GetFloat( "accel_time", "0.25", accel ); - spawnArgs.GetFloat( "decel_time", "0.25", decel ); - - // create second position - if ( !spawnArgs.GetFloat( "height", "0", height ) ) { - height = ( GetPhysics()->GetBounds()[1][2] - GetPhysics()->GetBounds()[0][2] ) - lip; - } - - spawnArgs.GetBool( "no_touch", "0", noTouch ); - - // pos1 is the rest (bottom) position, pos2 is the top - pos2 = GetPhysics()->GetOrigin(); - pos1 = pos2; - pos1[2] -= height; - - if ( spawnArgs.GetFloat( "time", "1", time ) ) { - InitTime( pos1, pos2, time, accel, decel ); - } else { - InitSpeed( pos1, pos2, speed, accel, decel ); - } - - SetMoverState( MOVER_POS1, gameLocal.slow.time ); - UpdateVisuals(); - - // spawn the trigger if one hasn't been custom made - if ( !noTouch ) { - // spawn trigger - SpawnPlatTrigger( pos1 ); - } -} - -/* -================ -idPlat::Think -================ -*/ -void idPlat::Think( void ) { - idVec3 masterOrigin; - idMat3 masterAxis; - - idMover_Binary::Think(); - - if ( thinkFlags & TH_PHYSICS ) { - // update trigger position - if ( GetMasterPosition( masterOrigin, masterAxis ) ) { - if ( trigger ) { - trigger->Link( gameLocal.clip, this, 0, masterOrigin + localTriggerOrigin * masterAxis, localTriggerAxis * masterAxis ); - } - } - } -} - -/* -================ -idPlat::PreBind -================ -*/ -void idPlat::PreBind( void ) { - idMover_Binary::PreBind(); -} - -/* -================ -idPlat::PostBind -================ -*/ -void idPlat::PostBind( void ) { - idMover_Binary::PostBind(); - GetLocalTriggerPosition( trigger ); -} - -/* -================ -idPlat::GetLocalTriggerPosition -================ -*/ -void idPlat::GetLocalTriggerPosition( const idClipModel *trigger ) { - idVec3 origin; - idMat3 axis; - - if ( !trigger ) { - return; - } - - GetMasterPosition( origin, axis ); - localTriggerOrigin = ( trigger->GetOrigin() - origin ) * axis.Transpose(); - localTriggerAxis = trigger->GetAxis() * axis.Transpose(); -} - -/* -============== -idPlat::SpawnPlatTrigger -=============== -*/ -void idPlat::SpawnPlatTrigger( idVec3 &pos ) { - idBounds bounds; - idVec3 tmin; - idVec3 tmax; - - // the middle trigger will be a thin trigger just - // above the starting position - - bounds = GetPhysics()->GetBounds(); - - tmin[0] = bounds[0][0] + 33; - tmin[1] = bounds[0][1] + 33; - tmin[2] = bounds[0][2]; - - tmax[0] = bounds[1][0] - 33; - tmax[1] = bounds[1][1] - 33; - tmax[2] = bounds[1][2] + 8; - - if ( tmax[0] <= tmin[0] ) { - tmin[0] = ( bounds[0][0] + bounds[1][0] ) * 0.5f; - tmax[0] = tmin[0] + 1; - } - if ( tmax[1] <= tmin[1] ) { - tmin[1] = ( bounds[0][1] + bounds[1][1] ) * 0.5f; - tmax[1] = tmin[1] + 1; - } - - trigger = new idClipModel( idTraceModel( idBounds( tmin, tmax ) ) ); - trigger->Link( gameLocal.clip, this, 255, GetPhysics()->GetOrigin(), mat3_identity ); - trigger->SetContents( CONTENTS_TRIGGER ); -} - -/* -============== -idPlat::Event_Touch -=============== -*/ -void idPlat::Event_Touch( idEntity *other, trace_t *trace ) { - if ( !other->IsType( idPlayer::Type ) ) { - return; - } - - if ( ( GetMoverState() == MOVER_POS1 ) && trigger && ( trace->c.id == trigger->GetId() ) && ( other->health > 0 ) ) { - Use_BinaryMover( other ); - } -} - -/* -================ -idPlat::Event_TeamBlocked -================ -*/ -void idPlat::Event_TeamBlocked( idEntity *blockedEntity, idEntity *blockingEntity ) { - // reverse direction - Use_BinaryMover( activatedBy.GetEntity() ); -} - -/* -=============== -idPlat::Event_PartBlocked -=============== -*/ -void idPlat::Event_PartBlocked( idEntity *blockingEntity ) { - if ( damage > 0.0f ) { - blockingEntity->Damage( this, this, vec3_origin, "damage_moverCrush", damage, INVALID_JOINT ); - } -} - - -/* -=============================================================================== - -idMover_Periodic - -=============================================================================== -*/ - -CLASS_DECLARATION( idEntity, idMover_Periodic ) - EVENT( EV_TeamBlocked, idMover_Periodic::Event_TeamBlocked ) - EVENT( EV_PartBlocked, idMover_Periodic::Event_PartBlocked ) -END_CLASS - -/* -=============== -idMover_Periodic::idMover_Periodic -=============== -*/ -idMover_Periodic::idMover_Periodic( void ) { - damage = 0.0f; - fl.neverDormant = false; -} - -/* -=============== -idMover_Periodic::Spawn -=============== -*/ -void idMover_Periodic::Spawn( void ) { - spawnArgs.GetFloat( "damage", "0", damage ); - if ( !spawnArgs.GetBool( "solid", "1" ) ) { - GetPhysics()->SetContents( 0 ); - } -} - -/* -=============== -idMover_Periodic::Save -=============== -*/ -void idMover_Periodic::Save( idSaveGame *savefile ) const { - savefile->WriteFloat( damage ); - savefile->WriteStaticObject( physicsObj ); -} - -/* -=============== -idMover_Periodic::Restore -=============== -*/ -void idMover_Periodic::Restore( idRestoreGame *savefile ) { - savefile->ReadFloat( damage ); - savefile->ReadStaticObject( physicsObj ); - RestorePhysics( &physicsObj ); -} - -/* -================ -idMover_Periodic::Think -================ -*/ -void idMover_Periodic::Think( void ) { - // if we are completely closed off from the player, don't do anything at all - if ( CheckDormant() ) { - return; - } - - RunPhysics(); - Present(); -} - -/* -=============== -idMover_Periodic::Event_TeamBlocked -=============== -*/ -void idMover_Periodic::Event_TeamBlocked( idEntity *blockedEntity, idEntity *blockingEntity ) { -} - -/* -=============== -idMover_Periodic::Event_PartBlocked -=============== -*/ -void idMover_Periodic::Event_PartBlocked( idEntity *blockingEntity ) { - if ( damage > 0.0f ) { - blockingEntity->Damage( this, this, vec3_origin, "damage_moverCrush", damage, INVALID_JOINT ); - } -} - -/* -================ -idMover_Periodic::WriteToSnapshot -================ -*/ -void idMover_Periodic::WriteToSnapshot( idBitMsgDelta &msg ) const { - physicsObj.WriteToSnapshot( msg ); - WriteBindToSnapshot( msg ); -} - -/* -================ -idMover_Periodic::ReadFromSnapshot -================ -*/ -void idMover_Periodic::ReadFromSnapshot( const idBitMsgDelta &msg ) { - physicsObj.ReadFromSnapshot( msg ); - ReadBindFromSnapshot( msg ); - - if ( msg.HasChanged() ) { - UpdateVisuals(); - } -} - - -/* -=============================================================================== - -idRotater - -=============================================================================== -*/ - -CLASS_DECLARATION( idMover_Periodic, idRotater ) - EVENT( EV_Activate, idRotater::Event_Activate ) -END_CLASS - -/* -=============== -idRotater::idRotater -=============== -*/ -idRotater::idRotater( void ) { - activatedBy = this; -} - -/* -=============== -idRotater::Spawn -=============== -*/ -void idRotater::Spawn( void ) { - physicsObj.SetSelf( this ); - physicsObj.SetClipModel( new idClipModel( GetPhysics()->GetClipModel() ), 1.0f ); - physicsObj.SetOrigin( GetPhysics()->GetOrigin() ); - physicsObj.SetAxis( GetPhysics()->GetAxis() ); - physicsObj.SetClipMask( MASK_SOLID ); - if ( !spawnArgs.GetBool( "nopush" ) ) { - physicsObj.SetPusher( 0 ); - } - physicsObj.SetLinearExtrapolation( EXTRAPOLATION_NONE, gameLocal.slow.time, 0, GetPhysics()->GetOrigin(), vec3_origin, vec3_origin ); - physicsObj.SetAngularExtrapolation( extrapolation_t(EXTRAPOLATION_LINEAR|EXTRAPOLATION_NOSTOP), gameLocal.slow.time, 0, GetPhysics()->GetAxis().ToAngles(), ang_zero, ang_zero ); - SetPhysics( &physicsObj ); - - if ( spawnArgs.GetBool( "start_on" ) ) { - ProcessEvent( &EV_Activate, this ); - } -} - -/* -=============== -idRotater::Save -=============== -*/ -void idRotater::Save( idSaveGame *savefile ) const { - activatedBy.Save( savefile ); -} - -/* -=============== -idRotater::Restore -=============== -*/ -void idRotater::Restore( idRestoreGame *savefile ) { - activatedBy.Restore( savefile ); -} - -/* -=============== -idRotater::Event_Activate -=============== -*/ -void idRotater::Event_Activate( idEntity *activator ) { - float speed; - bool x_axis; - bool y_axis; - idAngles delta; - - activatedBy = activator; - - delta.Zero(); - - if ( !spawnArgs.GetBool( "rotate" ) ) { - spawnArgs.Set( "rotate", "1" ); - spawnArgs.GetFloat( "speed", "100", speed ); - spawnArgs.GetBool( "x_axis", "0", x_axis ); - spawnArgs.GetBool( "y_axis", "0", y_axis ); - - // set the axis of rotation - if ( x_axis ) { - delta[2] = speed; - } else if ( y_axis ) { - delta[0] = speed; - } else { - delta[1] = speed; - } - } else { - spawnArgs.Set( "rotate", "0" ); - } - - physicsObj.SetAngularExtrapolation( extrapolation_t(EXTRAPOLATION_LINEAR|EXTRAPOLATION_NOSTOP), gameLocal.slow.time, 0, physicsObj.GetAxis().ToAngles(), delta, ang_zero ); -} - - -/* -=============================================================================== - -idBobber - -=============================================================================== -*/ - -CLASS_DECLARATION( idMover_Periodic, idBobber ) -END_CLASS - -/* -=============== -idBobber::idBobber -=============== -*/ -idBobber::idBobber( void ) { -} - -/* -=============== -idBobber::Spawn -=============== -*/ -void idBobber::Spawn( void ) { - float speed; - float height; - float phase; - bool x_axis; - bool y_axis; - idVec3 delta; - - spawnArgs.GetFloat( "speed", "4", speed ); - spawnArgs.GetFloat( "height", "32", height ); - spawnArgs.GetFloat( "phase", "0", phase ); - spawnArgs.GetBool( "x_axis", "0", x_axis ); - spawnArgs.GetBool( "y_axis", "0", y_axis ); - - // set the axis of bobbing - delta = vec3_origin; - if ( x_axis ) { - delta[ 0 ] = height; - } else if ( y_axis ) { - delta[ 1 ] = height; - } else { - delta[ 2 ] = height; - } - - physicsObj.SetSelf( this ); - physicsObj.SetClipModel( new idClipModel( GetPhysics()->GetClipModel() ), 1.0f ); - physicsObj.SetOrigin( GetPhysics()->GetOrigin() ); - physicsObj.SetAxis( GetPhysics()->GetAxis() ); - physicsObj.SetClipMask( MASK_SOLID ); - if ( !spawnArgs.GetBool( "nopush" ) ) { - physicsObj.SetPusher( 0 ); - } - physicsObj.SetLinearExtrapolation( extrapolation_t(EXTRAPOLATION_DECELSINE|EXTRAPOLATION_NOSTOP), phase * 1000, speed * 500, GetPhysics()->GetOrigin(), delta * 2.0f, vec3_origin ); - SetPhysics( &physicsObj ); -} - - -/* -=============================================================================== - -idPendulum - -=============================================================================== -*/ - -CLASS_DECLARATION( idMover_Periodic, idPendulum ) -END_CLASS - -/* -=============== -idPendulum::idPendulum -=============== -*/ -idPendulum::idPendulum( void ) { -} - -/* -=============== -idPendulum::Spawn -=============== -*/ -void idPendulum::Spawn( void ) { - float speed; - float freq; - float length; - float phase; - - spawnArgs.GetFloat( "speed", "30", speed ); - spawnArgs.GetFloat( "phase", "0", phase ); - - if ( spawnArgs.GetFloat( "freq", "", freq ) ) { - if ( freq <= 0.0f ) { - gameLocal.Error( "Invalid frequency on entity '%s'", GetName() ); - } - } else { - // find pendulum length - length = idMath::Fabs( GetPhysics()->GetBounds()[0][2] ); - if ( length < 8 ) { - length = 8; - } - - freq = 1 / ( idMath::TWO_PI ) * idMath::Sqrt( g_gravity.GetFloat() / ( 3 * length ) ); - } - - physicsObj.SetSelf( this ); - physicsObj.SetClipModel( new idClipModel( GetPhysics()->GetClipModel() ), 1.0f ); - physicsObj.SetOrigin( GetPhysics()->GetOrigin() ); - physicsObj.SetAxis( GetPhysics()->GetAxis() ); - physicsObj.SetClipMask( MASK_SOLID ); - if ( !spawnArgs.GetBool( "nopush" ) ) { - physicsObj.SetPusher( 0 ); - } - physicsObj.SetLinearExtrapolation( EXTRAPOLATION_NONE, 0, 0, GetPhysics()->GetOrigin(), vec3_origin, vec3_origin ); - physicsObj.SetAngularExtrapolation( extrapolation_t(EXTRAPOLATION_DECELSINE|EXTRAPOLATION_NOSTOP), phase * 1000, 500/freq, GetPhysics()->GetAxis().ToAngles(), idAngles( 0, 0, speed * 2.0f ), ang_zero ); - SetPhysics( &physicsObj ); -} - - -/* -=============================================================================== - -idBobber - -=============================================================================== -*/ - -CLASS_DECLARATION( idMover_Periodic, idRiser ) -EVENT( EV_Activate, idRiser::Event_Activate ) -END_CLASS - -/* -=============== -idRiser::idRiser -=============== -*/ -idRiser::idRiser( void ) { -} - -/* -=============== -idRiser::Spawn -=============== -*/ -void idRiser::Spawn( void ) { - physicsObj.SetSelf( this ); - physicsObj.SetClipModel( new idClipModel( GetPhysics()->GetClipModel() ), 1.0f ); - physicsObj.SetOrigin( GetPhysics()->GetOrigin() ); - physicsObj.SetAxis( GetPhysics()->GetAxis() ); - - physicsObj.SetClipMask( MASK_SOLID ); - if ( !spawnArgs.GetBool( "solid", "1" ) ) { - physicsObj.SetContents( 0 ); - } - if ( !spawnArgs.GetBool( "nopush" ) ) { - physicsObj.SetPusher( 0 ); - } - physicsObj.SetLinearExtrapolation( EXTRAPOLATION_NONE, 0, 0, GetPhysics()->GetOrigin(), vec3_origin, vec3_origin ); - SetPhysics( &physicsObj ); -} - -/* -================ -idRiser::Event_Activate -================ -*/ -void idRiser::Event_Activate( idEntity *activator ) { - - if ( !IsHidden() && spawnArgs.GetBool("hide") ) { - Hide(); - } else { - Show(); - float time; - float height; - idVec3 delta; - - spawnArgs.GetFloat( "time", "4", time ); - spawnArgs.GetFloat( "height", "32", height ); - - delta = vec3_origin; - delta[ 2 ] = height; - - physicsObj.SetLinearExtrapolation( EXTRAPOLATION_LINEAR, gameLocal.slow.time, time * 1000, physicsObj.GetOrigin(), delta, vec3_origin ); - } -} diff --git a/d3xp/Mover.h b/d3xp/Mover.h deleted file mode 100644 index dc660da1..00000000 --- a/d3xp/Mover.h +++ /dev/null @@ -1,563 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __GAME_MOVER_H__ -#define __GAME_MOVER_H__ - -#include "physics/Physics_Parametric.h" -#include "Entity.h" - -extern const idEventDef EV_TeamBlocked; -extern const idEventDef EV_PartBlocked; -extern const idEventDef EV_ReachedPos; -extern const idEventDef EV_ReachedAng; - -/* -=============================================================================== - - General movers. - -=============================================================================== -*/ - -class idMover : public idEntity { -public: - CLASS_PROTOTYPE( idMover ); - - idMover( void ); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - virtual void Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ); - - virtual void WriteToSnapshot( idBitMsgDelta &msg ) const; - virtual void ReadFromSnapshot( const idBitMsgDelta &msg ); - - virtual void Hide( void ); - virtual void Show( void ); - - void SetPortalState( bool open ); - -protected: - typedef enum { - ACCELERATION_STAGE, - LINEAR_STAGE, - DECELERATION_STAGE, - FINISHED_STAGE - } moveStage_t; - - typedef enum { - MOVER_NONE, - MOVER_ROTATING, - MOVER_MOVING, - MOVER_SPLINE - } moverCommand_t; - - // - // mover directions. make sure to change script/doom_defs.script if you add any, or change their order - // - typedef enum { - DIR_UP = -1, - DIR_DOWN = -2, - DIR_LEFT = -3, - DIR_RIGHT = -4, - DIR_FORWARD = -5, - DIR_BACK = -6, - DIR_REL_UP = -7, - DIR_REL_DOWN = -8, - DIR_REL_LEFT = -9, - DIR_REL_RIGHT = -10, - DIR_REL_FORWARD = -11, - DIR_REL_BACK = -12 - } moverDir_t; - - typedef struct { - moveStage_t stage; - int acceleration; - int movetime; - int deceleration; - idVec3 dir; - } moveState_t; - - typedef struct { - moveStage_t stage; - int acceleration; - int movetime; - int deceleration; - idAngles rot; - } rotationState_t; - - idPhysics_Parametric physicsObj; - - void Event_OpenPortal( void ); - void Event_ClosePortal( void ); - void Event_PartBlocked( idEntity *blockingEntity ); - - void MoveToPos( const idVec3 &pos); - void UpdateMoveSound( moveStage_t stage ); - void UpdateRotationSound( moveStage_t stage ); - void SetGuiStates( const char *state ); - void FindGuiTargets( void ); - void SetGuiState( const char *key, const char *val ) const; - - virtual void DoneMoving( void ); - virtual void DoneRotating( void ); - virtual void BeginMove( idThread *thread = NULL ); - virtual void BeginRotation( idThread *thread, bool stopwhendone ); - moveState_t move; - -private: - rotationState_t rot; - - int move_thread; - int rotate_thread; - idAngles dest_angles; - idAngles angle_delta; - idVec3 dest_position; - idVec3 move_delta; - float move_speed; - int move_time; - int deceltime; - int acceltime; - bool stopRotation; - bool useSplineAngles; - idEntityPtr splineEnt; - moverCommand_t lastCommand; - float damage; - - qhandle_t areaPortal; // 0 = no portal - - idList< idEntityPtr > guiTargets; - - void VectorForDir( float dir, idVec3 &vec ); - idCurve_Spline *GetSpline( idEntity *splineEntity ) const; - - void Event_SetCallback( void ); - void Event_TeamBlocked( idEntity *blockedPart, idEntity *blockingEntity ); - void Event_StopMoving( void ); - void Event_StopRotating( void ); - void Event_UpdateMove( void ); - void Event_UpdateRotation( void ); - void Event_SetMoveSpeed( float speed ); - void Event_SetMoveTime( float time ); - void Event_SetDecelerationTime( float time ); - void Event_SetAccellerationTime( float time ); - void Event_MoveTo( idEntity *ent ); - void Event_MoveToPos( idVec3 &pos ); - void Event_MoveDir( float angle, float distance ); - void Event_MoveAccelerateTo( float speed, float time ); - void Event_MoveDecelerateTo( float speed, float time ); - void Event_RotateDownTo( int axis, float angle ); - void Event_RotateUpTo( int axis, float angle ); - void Event_RotateTo( idAngles &angles ); - void Event_Rotate( idAngles &angles ); - void Event_RotateOnce( idAngles &angles ); - void Event_Bob( float speed, float phase, idVec3 &depth ); - void Event_Sway( float speed, float phase, idAngles &depth ); - void Event_SetAccelSound( const char *sound ); - void Event_SetDecelSound( const char *sound ); - void Event_SetMoveSound( const char *sound ); - void Event_FindGuiTargets( void ); - void Event_InitGuiTargets( void ); - void Event_EnableSplineAngles( void ); - void Event_DisableSplineAngles( void ); - void Event_RemoveInitialSplineAngles( void ); - void Event_StartSpline( idEntity *splineEntity ); - void Event_StopSpline( void ); - void Event_Activate( idEntity *activator ); - void Event_PostRestore( int start, int total, int accel, int decel, int useSplineAng ); - void Event_IsMoving( void ); - void Event_IsRotating( void ); -}; - -class idSplinePath : public idEntity { -public: - CLASS_PROTOTYPE( idSplinePath ); - - idSplinePath(); - - void Spawn( void ); -}; - - -struct floorInfo_s { - idVec3 pos; - idStr door; - int floor; -}; - -class idElevator : public idMover { -public: - CLASS_PROTOTYPE( idElevator ); - - idElevator( void ); - - void Spawn(); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - virtual bool HandleSingleGuiCommand( idEntity *entityGui, idLexer *src ); - void Event_GotoFloor( int floor ); - floorInfo_s * GetFloorInfo( int floor ); - -protected: - virtual void DoneMoving( void ); - virtual void BeginMove( idThread *thread = NULL ); - void SpawnTrigger( const idVec3 &pos ); - void GetLocalTriggerPosition(); - void Event_Touch( idEntity *other, trace_t *trace ); - -private: - typedef enum { - INIT, - IDLE, - WAITING_ON_DOORS - } elevatorState_t; - - elevatorState_t state; - idList floorInfo; - int currentFloor; - int pendingFloor; - int lastFloor; - bool controlsDisabled; - float returnTime; - int returnFloor; - int lastTouchTime; - - class idDoor * GetDoor( const char *name ); - void Think( void ); - void OpenInnerDoor( void ); - void OpenFloorDoor( int floor ); - void CloseAllDoors( void ); - void DisableAllDoors( void ); - void EnableProperDoors( void ); - - void Event_TeamBlocked( idEntity *blockedEntity, idEntity *blockingEntity ); - void Event_Activate( idEntity *activator ); - void Event_PostFloorArrival(); - -#ifdef _D3XP - void Event_SetGuiStates(); -#endif - -}; - - -/* -=============================================================================== - - Binary movers. - -=============================================================================== -*/ - -typedef enum { - MOVER_POS1, - MOVER_POS2, - MOVER_1TO2, - MOVER_2TO1 -} moverState_t; - -class idMover_Binary : public idEntity { -public: - CLASS_PROTOTYPE( idMover_Binary ); - - idMover_Binary(); - ~idMover_Binary(); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - virtual void PreBind( void ); - virtual void PostBind( void ); - - void Enable( bool b ); - void InitSpeed( idVec3 &mpos1, idVec3 &mpos2, float mspeed, float maccelTime, float mdecelTime ); - void InitTime( idVec3 &mpos1, idVec3 &mpos2, float mtime, float maccelTime, float mdecelTime ); - void GotoPosition1( void ); - void GotoPosition2( void ); - void Use_BinaryMover( idEntity *activator ); - void SetGuiStates( const char *state ); - void UpdateBuddies( int val ); - idMover_Binary * GetActivateChain( void ) const { return activateChain; } - idMover_Binary * GetMoveMaster( void ) const { return moveMaster; } - void BindTeam( idEntity *bindTo ); - void SetBlocked( bool b ); - bool IsBlocked( void ); - idEntity * GetActivator( void ) const; - - virtual void WriteToSnapshot( idBitMsgDelta &msg ) const; - virtual void ReadFromSnapshot( const idBitMsgDelta &msg ); - - void SetPortalState( bool open ); - -protected: - idVec3 pos1; - idVec3 pos2; - moverState_t moverState; - idMover_Binary * moveMaster; - idMover_Binary * activateChain; - int soundPos1; - int sound1to2; - int sound2to1; - int soundPos2; - int soundLoop; - float wait; - float damage; - int duration; - int accelTime; - int decelTime; - idEntityPtr activatedBy; - int stateStartTime; - idStr team; - bool enabled; - int move_thread; - int updateStatus; // 1 = lock behaviour, 2 = open close status - idStrList buddies; - idPhysics_Parametric physicsObj; - qhandle_t areaPortal; // 0 = no portal - bool blocked; -#ifdef _D3XP - bool playerOnly; -#endif - idList< idEntityPtr > guiTargets; - - void MatchActivateTeam( moverState_t newstate, int time ); - void JoinActivateTeam( idMover_Binary *master ); - - void UpdateMoverSound( moverState_t state ); - void SetMoverState( moverState_t newstate, int time ); - moverState_t GetMoverState( void ) const { return moverState; } - void FindGuiTargets( void ); - void SetGuiState( const char *key, const char *val ) const; - - void Event_SetCallback( void ); - void Event_ReturnToPos1( void ); - void Event_Use_BinaryMover( idEntity *activator ); - void Event_Reached_BinaryMover( void ); - void Event_MatchActivateTeam( moverState_t newstate, int time ); - void Event_Enable( void ); - void Event_Disable( void ); - void Event_OpenPortal( void ); - void Event_ClosePortal( void ); - void Event_FindGuiTargets( void ); - void Event_InitGuiTargets( void ); - - static void GetMovedir( float dir, idVec3 &movedir ); -}; - -class idDoor : public idMover_Binary { -public: - CLASS_PROTOTYPE( idDoor ); - - idDoor( void ); - ~idDoor( void ); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - virtual void Think( void ); - virtual void PreBind( void ); - virtual void PostBind( void ); - virtual void Hide( void ); - virtual void Show( void ); - - bool IsOpen( void ); - bool IsNoTouch( void ); -#ifdef _D3XP - bool AllowPlayerOnly( idEntity *ent ); -#endif - int IsLocked( void ); - void Lock( int f ); - void Use( idEntity *other, idEntity *activator ); - void Close( void ); - void Open( void ); - void SetCompanion( idDoor *door ); - -private: - float triggersize; - bool crusher; - bool noTouch; - bool aas_area_closed; - idStr buddyStr; - idClipModel * trigger; - idClipModel * sndTrigger; - int nextSndTriggerTime; - idVec3 localTriggerOrigin; - idMat3 localTriggerAxis; - idStr requires; - int removeItem; - idStr syncLock; - int normalAxisIndex; // door faces X or Y for spectator teleports - idDoor * companionDoor; - - void SetAASAreaState( bool closed ); - - void GetLocalTriggerPosition( const idClipModel *trigger ); - void CalcTriggerBounds( float size, idBounds &bounds ); - - void Event_Reached_BinaryMover( void ); - void Event_TeamBlocked( idEntity *blockedEntity, idEntity *blockingEntity ); - void Event_PartBlocked( idEntity *blockingEntity ); - void Event_Touch( idEntity *other, trace_t *trace ); - void Event_Activate( idEntity *activator ); - void Event_StartOpen( void ); - void Event_SpawnDoorTrigger( void ); - void Event_SpawnSoundTrigger( void ); - void Event_Close( void ); - void Event_Open( void ); - void Event_Lock( int f ); - void Event_IsOpen( void ); - void Event_Locked( void ); - void Event_SpectatorTouch( idEntity *other, trace_t *trace ); - void Event_OpenPortal( void ); - void Event_ClosePortal( void ); -}; - -class idPlat : public idMover_Binary { -public: - CLASS_PROTOTYPE( idPlat ); - - idPlat( void ); - ~idPlat( void ); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - virtual void Think( void ); - virtual void PreBind( void ); - virtual void PostBind( void ); - -private: - idClipModel * trigger; - idVec3 localTriggerOrigin; - idMat3 localTriggerAxis; - - void GetLocalTriggerPosition( const idClipModel *trigger ); - void SpawnPlatTrigger( idVec3 &pos ); - - void Event_TeamBlocked( idEntity *blockedEntity, idEntity *blockingEntity ); - void Event_PartBlocked( idEntity *blockingEntity ); - void Event_Touch( idEntity *other, trace_t *trace ); -}; - - -/* -=============================================================================== - - Special periodic movers. - -=============================================================================== -*/ - -class idMover_Periodic : public idEntity { -public: - CLASS_PROTOTYPE( idMover_Periodic ); - - idMover_Periodic( void ); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - virtual void Think( void ); - - virtual void WriteToSnapshot( idBitMsgDelta &msg ) const; - virtual void ReadFromSnapshot( const idBitMsgDelta &msg ); - -protected: - idPhysics_Parametric physicsObj; - float damage; - - void Event_TeamBlocked( idEntity *blockedEntity, idEntity *blockingEntity ); - void Event_PartBlocked( idEntity *blockingEntity ); -}; - -class idRotater : public idMover_Periodic { -public: - CLASS_PROTOTYPE( idRotater ); - - idRotater( void ); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - -private: - idEntityPtr activatedBy; - - void Event_Activate( idEntity *activator ); -}; - -class idBobber : public idMover_Periodic { -public: - CLASS_PROTOTYPE( idBobber ); - - idBobber( void ); - - void Spawn( void ); - -private: -}; - -class idPendulum : public idMover_Periodic { -public: - CLASS_PROTOTYPE( idPendulum ); - - idPendulum( void ); - - void Spawn( void ); - -private: -}; - -class idRiser : public idMover_Periodic { -public: - CLASS_PROTOTYPE( idRiser ); - - idRiser( void ); - - void Spawn( void ); - -private: - void Event_Activate( idEntity *activator ); -}; - -#endif /* !__GAME_MOVER_H__ */ diff --git a/d3xp/MultiplayerGame.cpp b/d3xp/MultiplayerGame.cpp deleted file mode 100644 index ec9dfa85..00000000 --- a/d3xp/MultiplayerGame.cpp +++ /dev/null @@ -1,4390 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "idlib/BitMsg.h" -#include "idlib/Str.h" -#include "idlib/LangDict.h" -#include "framework/async/NetworkSystem.h" -#include "framework/FileSystem.h" -#include "framework/DeclEntityDef.h" -#include "ui/UserInterface.h" - -#include "gamesys/SysCvar.h" -#include "Player.h" -#include "Game_local.h" - -#include "MultiplayerGame.h" - -// could be a problem if players manage to go down sudden deaths till this .. oh well -#define LASTMAN_NOLIVES -20 - -idCVar g_spectatorChat( "g_spectatorChat", "0", CVAR_GAME | CVAR_ARCHIVE | CVAR_BOOL, "let spectators talk to everyone during game" ); - -// global sounds transmitted by index - 0 .. SND_COUNT -// sounds in this list get precached on MP start -const char *idMultiplayerGame::GlobalSoundStrings[] = { - "sound/feedback/voc_youwin.wav", - "sound/feedback/voc_youlose.wav", - "sound/feedback/fight.wav", - "sound/feedback/vote_now.wav", - "sound/feedback/vote_passed.wav", - "sound/feedback/vote_failed.wav", - "sound/feedback/three.wav", - "sound/feedback/two.wav", - "sound/feedback/one.wav", - "sound/feedback/sudden_death.wav", -#ifdef CTF - "sound/ctf/flag_capped_yours.wav", - "sound/ctf/flag_capped_theirs.wav", - "sound/ctf/flag_return.wav", - "sound/ctf/flag_taken_yours.wav", - "sound/ctf/flag_taken_theirs.wav", - "sound/ctf/flag_dropped_yours.wav", - "sound/ctf/flag_dropped_theirs.wav" -#endif -}; - -// handy verbose -const char *idMultiplayerGame::GameStateStrings[] = { - "INACTIVE", - "WARMUP", - "COUNTDOWN", - "GAMEON", - "SUDDENDEATH", - "GAMEREVIEW", - "NEXTGAME" -}; - -const char *idMultiplayerGame::MPGuis[] = { - "guis/mphud.gui", - "guis/mpmain.gui", - "guis/mpmsgmode.gui", - "guis/netmenu.gui", - NULL -}; - -const char *idMultiplayerGame::ThrottleVars[] = { - "ui_spectate", - "ui_ready", - "ui_team", - NULL -}; - -const char *idMultiplayerGame::ThrottleVarsInEnglish[] = { - "#str_06738", - "#str_06737", - "#str_01991", - NULL -}; - -const int idMultiplayerGame::ThrottleDelay[] = { - 8, - 5, - 5 -}; - -/* -================ -idMultiplayerGame::idMultiplayerGame -================ -*/ -idMultiplayerGame::idMultiplayerGame() { - scoreBoard = NULL; - spectateGui = NULL; - guiChat = NULL; - mainGui = NULL; - mapList = NULL; - msgmodeGui = NULL; - lastGameType = GAME_SP; - -#ifdef CTF - teamFlags[0] = NULL; - teamFlags[1] = NULL; - - teamPoints[0] = 0; - teamPoints[1] = 0; - - flagMsgOn = true; - - player_blue_flag = -1; - player_red_flag = -1; -#endif - - Clear(); -} - -/* -================ -idMultiplayerGame::Shutdown -================ -*/ -void idMultiplayerGame::Shutdown( void ) { - Clear(); -} - -/* -================ -idMultiplayerGame::SetMenuSkin -================ -*/ -void idMultiplayerGame::SetMenuSkin( void ) { - // skins - idStr str = cvarSystem->GetCVarString( "mod_validSkins" ); - idStr uiSkin = cvarSystem->GetCVarString( "ui_skin" ); - idStr skin; - int skinId = 1; - int count = 1; - while ( str.Length() ) { - int n = str.Find( ";" ); - if ( n >= 0 ) { - skin = str.Left( n ); - str = str.Right( str.Length() - n - 1 ); - } else { - skin = str; - str = ""; - } - if ( skin.Icmp( uiSkin ) == 0 ) { - skinId = count; - } - count++; - } - - for ( int i = 0; i < count; i++ ) { - mainGui->SetStateInt( va( "skin%i", i+1 ), 0 ); - } - mainGui->SetStateInt( va( "skin%i", skinId ), 1 ); -} - -/* -================ -idMultiplayerGame::Reset -================ -*/ -void idMultiplayerGame::Reset() { - Clear(); - assert( !scoreBoard && !spectateGui && !guiChat && !mainGui && !mapList ); - -#ifdef CTF - // CTF uses its own scoreboard - if ( IsGametypeFlagBased() ) - scoreBoard = uiManager->FindGui( "guis/ctfscoreboard.gui", true, false, true ); - else -#endif - scoreBoard = uiManager->FindGui( "guis/scoreboard.gui", true, false, true ); - - spectateGui = uiManager->FindGui( "guis/spectate.gui", true, false, true ); - guiChat = uiManager->FindGui( "guis/chat.gui", true, false, true ); - mainGui = uiManager->FindGui( "guis/mpmain.gui", true, false, true ); - mapList = uiManager->AllocListGUI( ); - mapList->Config( mainGui, "mapList" ); - // set this GUI so that our Draw function is still called when it becomes the active/fullscreen GUI - mainGui->SetStateBool( "gameDraw", true ); - mainGui->SetKeyBindingNames(); - mainGui->SetStateInt( "com_machineSpec", cvarSystem->GetCVarInteger( "com_machineSpec" ) ); - SetMenuSkin(); - msgmodeGui = uiManager->FindGui( "guis/mpmsgmode.gui", true, false, true ); - msgmodeGui->SetStateBool( "gameDraw", true ); - ClearGuis(); - ClearChatData(); - warmupEndTime = 0; -} - -/* -================ -idMultiplayerGame::ServerClientConnect -================ -*/ -void idMultiplayerGame::ServerClientConnect( int clientNum ) { - memset( &playerState[ clientNum ], 0, sizeof( playerState[ clientNum ] ) ); -} - -/* -================ -idMultiplayerGame::SpawnPlayer -================ -*/ -void idMultiplayerGame::SpawnPlayer( int clientNum ) { - - bool ingame = playerState[ clientNum ].ingame; - - memset( &playerState[ clientNum ], 0, sizeof( playerState[ clientNum ] ) ); - if ( !gameLocal.isClient ) { - idPlayer *p = static_cast< idPlayer * >( gameLocal.entities[ clientNum ] ); - p->spawnedTime = gameLocal.time; - - if ( IsGametypeTeamBased() ) { /* CTF */ - SwitchToTeam( clientNum, -1, p->team ); - } - p->tourneyRank = 0; - if ( gameLocal.gameType == GAME_TOURNEY && gameState == GAMEON ) { - p->tourneyRank++; - } - playerState[ clientNum ].ingame = ingame; - } -} - -/* -================ -idMultiplayerGame::Clear -================ -*/ -void idMultiplayerGame::Clear() { - int i; - - gameState = INACTIVE; - nextState = INACTIVE; - pingUpdateTime = 0; - vote = VOTE_NONE; - voteTimeOut = 0; - voteExecTime = 0; - nextStateSwitch = 0; - matchStartedTime = 0; - currentTourneyPlayer[ 0 ] = -1; - currentTourneyPlayer[ 1 ] = -1; - one = two = three = false; - memset( &playerState, 0 , sizeof( playerState ) ); - lastWinner = -1; - currentMenu = 0; - bCurrentMenuMsg = false; - nextMenu = 0; - pureReady = false; - scoreBoard = NULL; - spectateGui = NULL; - guiChat = NULL; - mainGui = NULL; - msgmodeGui = NULL; - if ( mapList ) { - uiManager->FreeListGUI( mapList ); - mapList = NULL; - } - fragLimitTimeout = 0; - memset( &switchThrottle, 0, sizeof( switchThrottle ) ); - voiceChatThrottle = 0; - for ( i = 0; i < NUM_CHAT_NOTIFY; i++ ) { - chatHistory[ i ].line.Clear(); - } - warmupText.Clear(); - voteValue.Clear(); - voteString.Clear(); - startFragLimit = -1; -} - -/* -================ -idMultiplayerGame::ClearGuis -================ -*/ -void idMultiplayerGame::ClearGuis() { - int i; - - for ( i = 0; i < MAX_CLIENTS; i++ ) { - scoreBoard->SetStateString( va( "player%i",i+1 ), "" ); - scoreBoard->SetStateString( va( "player%i_score", i+1 ), "" ); - scoreBoard->SetStateString( va( "player%i_tdm_tscore", i+1 ), "" ); - scoreBoard->SetStateString( va( "player%i_tdm_score", i+1 ), "" ); - scoreBoard->SetStateString( va( "player%i_wins", i+1 ), "" ); - scoreBoard->SetStateString( va( "player%i_status", i+1 ), "" ); - scoreBoard->SetStateInt( va( "rank%i", i+1 ), 0 ); - scoreBoard->SetStateInt( "rank_self", 0 ); - - idPlayer *player = static_cast( gameLocal.entities[ i ] ); - if ( !player || !player->hud ) { - continue; - } - player->hud->SetStateString( va( "player%i",i+1 ), "" ); - player->hud->SetStateString( va( "player%i_score", i+1 ), "" ); - player->hud->SetStateString( va( "player%i_ready", i+1 ), "" ); - scoreBoard->SetStateInt( va( "rank%i", i+1 ), 0 ); - player->hud->SetStateInt( "rank_self", 0 ); - - } - -#ifdef CTF - ClearHUDStatus(); -#endif -} - -#ifdef CTF -/* -================ -idMultiplayerGame::ClearHUDStatus -================ -*/ -void idMultiplayerGame::ClearHUDStatus( void ) { - int i; - - for ( i = 0; i < MAX_CLIENTS; i++ ) { - - idPlayer *player = static_cast( gameLocal.entities[ i ] ); - if ( !player || !player->hud ) { - continue; - } - - player->hud->SetStateInt( "red_flagstatus", 0 ); - player->hud->SetStateInt( "blue_flagstatus", 0 ); - if ( IsGametypeFlagBased()) - player->hud->SetStateInt( "self_team", player->team ); - else - player->hud->SetStateInt( "self_team", -1 ); // Invisible. - } - -} - -/* -================ -idMultiplayerGame::GetFlagPoints - -Gets number of captures in CTF game. - -0 = red team -1 = blue team -================ -*/ -int idMultiplayerGame::GetFlagPoints( int team ) -{ - assert( team <= 1 ); - - return teamPoints[ team ]; -} -#endif - -/* -================ -idMultiplayerGame::UpdatePlayerRanks -================ -*/ -void idMultiplayerGame::UpdatePlayerRanks() { - int i, j, k; - idPlayer *players[MAX_CLIENTS]; - idEntity *ent; - idPlayer *player; - - memset( players, 0, sizeof( players ) ); - numRankedPlayers = 0; - - for ( i = 0; i < gameLocal.numClients; i++ ) { - ent = gameLocal.entities[ i ]; - if ( !ent || !ent->IsType( idPlayer::Type ) ) { - continue; - } - player = static_cast< idPlayer * >( ent ); - if ( !CanPlay( player ) ) { - continue; - } - if ( gameLocal.gameType == GAME_TOURNEY ) { - if ( i != currentTourneyPlayer[ 0 ] && i != currentTourneyPlayer[ 1 ] ) { - continue; - } - } - if ( gameLocal.gameType == GAME_LASTMAN && playerState[ i ].fragCount == LASTMAN_NOLIVES ) { - continue; - } - for ( j = 0; j < numRankedPlayers; j++ ) { - bool insert = false; - - if ( IsGametypeTeamBased() ) { /* CTF */ - if ( player->team != players[ j ]->team ) { - if ( playerState[ i ].teamFragCount > playerState[ players[ j ]->entityNumber ].teamFragCount ) { - // team scores - insert = true; - } else if ( playerState[ i ].teamFragCount == playerState[ players[ j ]->entityNumber ].teamFragCount && player->team < players[ j ]->team ) { - // at equal scores, sort by team number - insert = true; - } - } else if ( playerState[ i ].fragCount > playerState[ players[ j ]->entityNumber ].fragCount ) { - // in the same team, sort by frag count - insert = true; - } - } else { - insert = ( playerState[ i ].fragCount > playerState[ players[ j ]->entityNumber ].fragCount ); - } - if ( insert ) { - for ( k = numRankedPlayers; k > j; k-- ) { - players[ k ] = players[ k-1 ]; - } - players[ j ] = player; - break; - } - } - if ( j == numRankedPlayers ) { - players[ numRankedPlayers ] = player; - } - numRankedPlayers++; - } - - memcpy( rankedPlayers, players, sizeof( players ) ); -} - - -/* -================ -idMultiplayerGame::UpdateRankColor -================ -*/ -void idMultiplayerGame::UpdateRankColor( idUserInterface *gui, const char *mask, int i, const idVec3 &vec ) { - for ( int j = 1; j < 4; j++ ) { - gui->SetStateFloat( va( mask, i, j ), vec[ j - 1 ] ); - } -} - -/* -================ -idMultiplayerGame::UpdateScoreboard -================ -*/ -void idMultiplayerGame::UpdateScoreboard( idUserInterface *scoreBoard, idPlayer *player ) { - int i, j, iline, k; - idStr gameinfo; -#ifdef _D3XP - idStr livesinfo; - idStr timeinfo; -#endif - - idEntity *ent; - idPlayer *p; - int value; - - scoreBoard->SetStateString( "scoretext", gameLocal.gameType == GAME_LASTMAN ? common->GetLanguageDict()->GetString( "#str_04242" ) : common->GetLanguageDict()->GetString( "#str_04243" ) ); - - iline = 0; // the display lines - if ( gameState != WARMUP ) { - for ( i = 0; i < numRankedPlayers; i++ ) { - // ranked player - iline++; - scoreBoard->SetStateString( va( "player%i", iline ), rankedPlayers[ i ]->GetUserInfo()->GetString( "ui_name" ) ); - if ( IsGametypeTeamBased() ) { /* CTF */ - value = idMath::ClampInt( MP_PLAYER_MINFRAGS, MP_PLAYER_MAXFRAGS, playerState[ rankedPlayers[ i ]->entityNumber ].fragCount ); - scoreBoard->SetStateInt( va( "player%i_tdm_score", iline ), value ); - value = idMath::ClampInt( MP_PLAYER_MINFRAGS, MP_PLAYER_MAXFRAGS, playerState[ rankedPlayers[ i ]->entityNumber ].teamFragCount ); - scoreBoard->SetStateString( va( "player%i_tdm_tscore", iline ), va( "/ %i", value ) ); - scoreBoard->SetStateString( va( "player%i_score", iline ), "" ); - } else { - value = idMath::ClampInt( MP_PLAYER_MINFRAGS, MP_PLAYER_MAXFRAGS, playerState[ rankedPlayers[ i ]->entityNumber ].fragCount ); - scoreBoard->SetStateInt( va( "player%i_score", iline ), value ); - scoreBoard->SetStateString( va( "player%i_tdm_tscore", iline ), "" ); - scoreBoard->SetStateString( va( "player%i_tdm_score", iline ), "" ); - } - - value = idMath::ClampInt( 0, MP_PLAYER_MAXWINS, playerState[ rankedPlayers[ i ]->entityNumber ].wins ); - scoreBoard->SetStateInt( va( "player%i_wins", iline ), value ); - scoreBoard->SetStateInt( va( "player%i_ping", iline ), playerState[ rankedPlayers[ i ]->entityNumber ].ping ); - // set the color band - scoreBoard->SetStateInt( va( "rank%i", iline ), 1 ); - UpdateRankColor( scoreBoard, "rank%i_color%i", iline, rankedPlayers[ i ]->colorBar ); - if ( rankedPlayers[ i ] == player ) { - // highlight who we are - scoreBoard->SetStateInt( "rank_self", iline ); - } - } - } - - // if warmup, this draws everyone, otherwise it goes over spectators only - // when doing warmup we loop twice to draw ready/not ready first *then* spectators - // NOTE: in tourney, shows spectators according to their playing rank order? - for ( k = 0; k < ( gameState == WARMUP ? 2 : 1 ); k++ ) { - for ( i = 0; i < MAX_CLIENTS; i++ ) { - ent = gameLocal.entities[ i ]; - if ( !ent || !ent->IsType( idPlayer::Type ) ) { - continue; - } - if ( gameState != WARMUP ) { - // check he's not covered by ranks already - for ( j = 0; j < numRankedPlayers; j++ ) { - if ( ent == rankedPlayers[ j ] ) { - break; - } - } - if ( j != numRankedPlayers ) { - continue; - } - } - p = static_cast< idPlayer * >( ent ); - if ( gameState == WARMUP ) { - if ( k == 0 && p->spectating ) { - continue; - } - if ( k == 1 && !p->spectating ) { - continue; - } - } - - iline++; - if ( !playerState[ i ].ingame ) { - scoreBoard->SetStateString( va( "player%i", iline ), common->GetLanguageDict()->GetString( "#str_04244" ) ); - scoreBoard->SetStateString( va( "player%i_score", iline ), common->GetLanguageDict()->GetString( "#str_04245" ) ); - // no color band - scoreBoard->SetStateInt( va( "rank%i", iline ), 0 ); - } else { - scoreBoard->SetStateString( va( "player%i", iline ), gameLocal.userInfo[ i ].GetString( "ui_name" ) ); - if ( gameState == WARMUP ) { - if ( p->spectating ) { - scoreBoard->SetStateString( va( "player%i_score", iline ), common->GetLanguageDict()->GetString( "#str_04246" ) ); - // no color band - scoreBoard->SetStateInt( va( "rank%i", iline ), 0 ); - } else { - scoreBoard->SetStateString( va( "player%i_score", iline ), p->IsReady() ? common->GetLanguageDict()->GetString( "#str_04247" ) : common->GetLanguageDict()->GetString( "#str_04248" ) ); - // set the color band - scoreBoard->SetStateInt( va( "rank%i", iline ), 1 ); - UpdateRankColor( scoreBoard, "rank%i_color%i", iline, p->colorBar ); - } - } else { - if ( gameLocal.gameType == GAME_LASTMAN && playerState[ i ].fragCount == LASTMAN_NOLIVES ) { - scoreBoard->SetStateString( va( "player%i_score", iline ), common->GetLanguageDict()->GetString( "#str_06736" ) ); - // set the color band - scoreBoard->SetStateInt( va( "rank%i", iline ), 1 ); - UpdateRankColor( scoreBoard, "rank%i_color%i", iline, p->colorBar ); - } else { - scoreBoard->SetStateString( va( "player%i_score", iline ), common->GetLanguageDict()->GetString( "#str_04246" ) ); - // no color band - scoreBoard->SetStateInt( va( "rank%i", iline ), 0 ); - } - } - } - scoreBoard->SetStateString( va( "player%i_tdm_tscore", iline ), "" ); - scoreBoard->SetStateString( va( "player%i_tdm_score", iline ), "" ); - scoreBoard->SetStateString( va( "player%i_wins", iline ), "" ); - scoreBoard->SetStateInt( va( "player%i_ping", iline ), playerState[ i ].ping ); - if ( i == player->entityNumber ) { - // highlight who we are - scoreBoard->SetStateInt( "rank_self", iline ); - } - } - } - - // clear remaining lines (empty slots) - iline++; -#ifdef _D3XP - while ( iline < MAX_CLIENTS ) { //Max players is now 8 -#else - while ( iline < 5 ) { -#endif - scoreBoard->SetStateString( va( "player%i", iline ), "" ); - scoreBoard->SetStateString( va( "player%i_score", iline ), "" ); - scoreBoard->SetStateString( va( "player%i_tdm_tscore", iline ), "" ); - scoreBoard->SetStateString( va( "player%i_tdm_score", iline ), "" ); - scoreBoard->SetStateString( va( "player%i_wins", iline ), "" ); - scoreBoard->SetStateString( va( "player%i_ping", iline ), "" ); - scoreBoard->SetStateInt( va( "rank%i", iline ), 0 ); - iline++; - } - - gameinfo = va( "%s: %s", common->GetLanguageDict()->GetString( "#str_02376" ), gameLocal.serverInfo.GetString( "si_gameType" ) ); - if ( gameLocal.gameType == GAME_LASTMAN ) { - if ( gameState == GAMEON || gameState == SUDDENDEATH ) { - livesinfo = va( "%s: %i", common->GetLanguageDict()->GetString( "#str_04264" ), startFragLimit ); - } else { - livesinfo = va( "%s: %i", common->GetLanguageDict()->GetString( "#str_04264" ), gameLocal.serverInfo.GetInt( "si_fragLimit" ) ); - } -#ifdef CTF - } else if ( gameLocal.gameType != GAME_CTF ) { -#else - } else { -#endif - livesinfo = va( "%s: %i", common->GetLanguageDict()->GetString( "#str_01982" ), gameLocal.serverInfo.GetInt( "si_fragLimit" ) ); - } - if ( gameLocal.serverInfo.GetInt( "si_timeLimit" ) > 0 ) { - timeinfo = va( "%s: %i", common->GetLanguageDict()->GetString( "#str_01983" ), gameLocal.serverInfo.GetInt( "si_timeLimit" ) ); - } else { - timeinfo = va("%s", common->GetLanguageDict()->GetString( "#str_07209" )); - } - scoreBoard->SetStateString( "gameinfo", gameinfo ); - scoreBoard->SetStateString( "livesinfo", livesinfo ); - scoreBoard->SetStateString( "timeinfo", timeinfo ); - - scoreBoard->Redraw( gameLocal.time ); -} - -#ifdef CTF -/* -================ -idMultiplayerGame::UpdateCTFScoreboard -================ -*/ -void idMultiplayerGame::UpdateCTFScoreboard( idUserInterface *scoreBoard, idPlayer *player ) { - int i, j; - idStr gameinfo; - idEntity *ent; - int value; - - // The display lines - int ilines[2] = {0,0}; - - // The team strings - char redTeam[] = "red"; - char blueTeam[] = "blue"; - char *curTeam = NULL; - - /* Word "frags" */ - scoreBoard->SetStateString( "scoretext", gameLocal.gameType == GAME_LASTMAN ? common->GetLanguageDict()->GetString( "#str_04242" ) : common->GetLanguageDict()->GetString( "#str_04243" ) ); - - // Blank the flag carrier on the scoreboard. We update these in the loop below if necessary. - if ( this->player_blue_flag == -1 ) - scoreBoard->SetStateInt( "player_blue_flag", 0 ); - - if ( this->player_red_flag == -1 ) - scoreBoard->SetStateInt( "player_red_flag", 0 ); - - if ( gameState != WARMUP ) { - for ( i = 0; i < numRankedPlayers; i++ ) { - - idPlayer *player = rankedPlayers[ i ]; - assert( player ); - - if ( player->team == 0 ) - curTeam = redTeam; - else - curTeam = blueTeam; - - // Increase the appropriate iline - assert( player->team <= 1 ); - ilines[ player->team ]++; - - - // Update the flag status - if ( this->player_blue_flag == player->entityNumber ) - scoreBoard->SetStateInt( "player_blue_flag", ilines[ player->team ] ); - - if ( player->team == 1 && this->player_red_flag == player->entityNumber ) - scoreBoard->SetStateInt( "player_red_flag", ilines[ player->team ] ); - - - - /* Player Name */ - scoreBoard->SetStateString( va( "player%i_%s", ilines[ player->team ], curTeam ), player->GetUserInfo()->GetString( "ui_name" ) ); - - if ( IsGametypeTeamBased() ) { - - value = idMath::ClampInt( MP_PLAYER_MINFRAGS, MP_PLAYER_MAXFRAGS, playerState[ rankedPlayers[ i ]->entityNumber ].fragCount ); - scoreBoard->SetStateInt( va( "player%i_%s_score", ilines[ player->team ], curTeam ), value ); - - /* Team score and score, blanked */ - scoreBoard->SetStateString( va( "player%i_%s_tscore", ilines[ player->team ], curTeam ), "" ); - //scoreBoard->SetStateString( va( "player%i_%s_score", ilines[ player->team ], curTeam ), "" ); - } - - /* Wins */ - value = idMath::ClampInt( 0, MP_PLAYER_MAXWINS, playerState[ rankedPlayers[ i ]->entityNumber ].wins ); - scoreBoard->SetStateInt( va( "player%i_%s_wins", ilines[ player->team ], curTeam ), value ); - - /* Ping */ - scoreBoard->SetStateInt( va( "player%i_%s_ping", ilines[ player->team ], curTeam ), playerState[ rankedPlayers[ i ]->entityNumber ].ping ); - } - } - - for ( i = 0; i < MAX_CLIENTS; i++ ) { - - ent = gameLocal.entities[ i ]; - if ( !ent || !ent->IsType( idPlayer::Type ) ) { - continue; - } - - if ( gameState != WARMUP ) { - // check he's not covered by ranks already - for ( j = 0; j < numRankedPlayers; j++ ) { - if ( ent == rankedPlayers[ j ] ) { - break; - } - } - - if ( j != numRankedPlayers ) { - continue; - } - - } - player = static_cast< idPlayer * >( ent ); - - if ( player->spectating ) - continue; - - if ( player->team == 0 ) - curTeam = redTeam; - else - curTeam = blueTeam; - - ilines[ player->team ]++; - - - - - - if ( !playerState[ i ].ingame ) { - - /* "New Player" on player's name location */ - scoreBoard->SetStateString( va( "player%i_%s", ilines[ player->team ], curTeam ), common->GetLanguageDict()->GetString( "#str_04244" ) ); - - /* "Connecting" on player's score location */ - scoreBoard->SetStateString( va( "player%i_%s_score", ilines[ player->team ], curTeam ), common->GetLanguageDict()->GetString( "#str_04245" ) ); - - - } else { - - /* Player's name in player's name location */ - if ( !player->spectating ) - scoreBoard->SetStateString( va( "player%i_%s", ilines[ player->team ], curTeam ), gameLocal.userInfo[ i ].GetString( "ui_name" ) ); - - if ( gameState == WARMUP ) { - - if ( player->spectating ) { - - /* "Spectating" on player's score location */ - scoreBoard->SetStateString( va( "player%i_%s_score", ilines[ player->team ], curTeam ), common->GetLanguageDict()->GetString( "#str_04246" ) ); - - } else { - - /* Display "ready" in player's score location if they're ready. Display nothing if not. No room for 'not ready'. */ - scoreBoard->SetStateString( va( "player%i_%s_score", ilines[ player->team ], curTeam ), player->IsReady() ? common->GetLanguageDict()->GetString( "#str_04247" ) : "" ); - - } - } - } - - } - - // Clear remaining slots - for ( i = 0; i < 2; i++ ) - { - if ( i ) - curTeam = blueTeam; - else - curTeam = redTeam; - - for ( j = ilines[ i ]+1; j <= 8; j++ ) - { - scoreBoard->SetStateString( va( "player%i_%s", j, curTeam ), "" ); - scoreBoard->SetStateString( va( "player%i_%s_score", j, curTeam ), "" ); - scoreBoard->SetStateString( va( "player%i_%s_wins", j, curTeam ), "" ); - scoreBoard->SetStateString( va( "player%i_%s_ping", j, curTeam ), "" ); - scoreBoard->SetStateInt( "rank_self", 0 ); - } - } - - - // Don't display "CTF" -- if this scoreboard comes up, it should be apparent. - - if ( gameLocal.gameType == GAME_CTF ) { - - int captureLimit = gameLocal.serverInfo.GetInt( "si_fragLimit" ); - - if ( captureLimit > MP_CTF_MAXPOINTS ) - captureLimit = MP_CTF_MAXPOINTS; - - int timeLimit = gameLocal.serverInfo.GetInt( "si_timeLimit" ); - - /* Prints "Capture Limit: %i" at the bottom of the scoreboard, left */ - if ( captureLimit ) - scoreBoard->SetStateString( "gameinfo_red", va( common->GetLanguageDict()->GetString( "#str_11108" ), captureLimit) ); - else - scoreBoard->SetStateString( "gameinfo_red", "" ); - - /* Prints "Time Limit: %i" at the bottom of the scoreboard, right */ - if ( timeLimit ) - scoreBoard->SetStateString( "gameinfo_blue", va( common->GetLanguageDict()->GetString( "#str_11109" ), timeLimit) ); - else - scoreBoard->SetStateString( "gameinfo_blue", "" ); - } - - - - // Set team scores - scoreBoard->SetStateInt( "red_team_score", GetFlagPoints( 0 ) ); - scoreBoard->SetStateInt( "blue_team_score", GetFlagPoints( 1 ) ); - - // Handle flag status changed event - scoreBoard->HandleNamedEvent( "BlueFlagStatusChange" ); - scoreBoard->HandleNamedEvent( "RedFlagStatusChange" ); - - scoreBoard->Redraw( gameLocal.time ); - - - - -} -#endif - -/* -================ -idMultiplayerGame::GameTime -================ -*/ -const char *idMultiplayerGame::GameTime() { - static char buff[16]; - int m, s, t, ms; - - if ( gameState == COUNTDOWN ) { - ms = warmupEndTime - gameLocal.realClientTime; - s = ms / 1000 + 1; - if ( ms <= 0 ) { - strcpy( buff, "WMP --" ); - } else { - sprintf( buff, "WMP %i", s ); - } - } else { - int timeLimit = gameLocal.serverInfo.GetInt( "si_timeLimit" ); - if ( timeLimit ) { - ms = ( timeLimit * 60000 ) - ( gameLocal.time - matchStartedTime ); - } else { - ms = gameLocal.time - matchStartedTime; - } - if ( ms < 0 ) { - ms = 0; - } - - s = ms / 1000; - m = s / 60; - s -= m * 60; - t = s / 10; - s -= t * 10; - - sprintf( buff, "%i:%i%i", m, t, s ); - } - return &buff[0]; -} - -/* -================ -idMultiplayerGame::NumActualClients -================ -*/ -int idMultiplayerGame::NumActualClients( bool countSpectators, int *teamcounts ) { - idPlayer *p; - int c = 0; - - if ( teamcounts ) { - teamcounts[ 0 ] = teamcounts[ 1 ] = 0; - } - for( int i = 0 ; i < gameLocal.numClients ; i++ ) { - idEntity *ent = gameLocal.entities[ i ]; - if ( !ent || !ent->IsType( idPlayer::Type ) ) { - continue; - } - p = static_cast< idPlayer * >( ent ); - if ( countSpectators || CanPlay( p ) ) { - c++; - } - if ( teamcounts && CanPlay( p ) ) { - teamcounts[ p->team ]++; - } - } - return c; -} - -/* -================ -idMultiplayerGame::EnoughClientsToPlay -================ -*/ -bool idMultiplayerGame::EnoughClientsToPlay() { - int team[ 2 ]; - int clients = NumActualClients( false, &team[ 0 ] ); - if ( IsGametypeTeamBased() ) { /* CTF */ - return clients >= 2 && team[ 0 ] && team[ 1 ]; - } else { - return clients >= 2; - } -} - -/* -================ -idMultiplayerGame::AllPlayersReady -================ -*/ -bool idMultiplayerGame::AllPlayersReady() { - int i; - idEntity *ent; - idPlayer *p; - int team[ 2 ]; - - if ( NumActualClients( false, &team[ 0 ] ) <= 1 ) { - return false; - } - - if ( IsGametypeTeamBased() ) { /* CTF */ - if ( !team[ 0 ] || !team[ 1 ] ) { - return false; - } - } - - if ( !gameLocal.serverInfo.GetBool( "si_warmup" ) ) { - return true; - } - - for( i = 0; i < gameLocal.numClients; i++ ) { - if ( gameLocal.gameType == GAME_TOURNEY && i != currentTourneyPlayer[ 0 ] && i != currentTourneyPlayer[ 1 ] ) { - continue; - } - ent = gameLocal.entities[ i ]; - if ( !ent || !ent->IsType( idPlayer::Type ) ) { - continue; - } - p = static_cast< idPlayer * >( ent ); - if ( CanPlay( p ) && !p->IsReady() ) { - return false; - } - team[ p->team ]++; - } - - return true; -} - -/* -================ -idMultiplayerGame::FragLimitHit -return the winning player (team player) -if there is no FragLeader(), the game is tied and we return NULL -================ -*/ -idPlayer *idMultiplayerGame::FragLimitHit() { - int i; - int fragLimit = gameLocal.serverInfo.GetInt( "si_fragLimit" ); - idPlayer *leader; - -#ifdef CTF - if ( IsGametypeFlagBased() ) /* CTF */ - return NULL; -#endif - - leader = FragLeader(); - if ( !leader ) { - return NULL; - } - - if ( fragLimit <= 0 ) { - fragLimit = MP_PLAYER_MAXFRAGS; - } - - if ( gameLocal.gameType == GAME_LASTMAN ) { - // we have a leader, check if any other players have frags left - assert( !static_cast< idPlayer * >( leader )->lastManOver ); - for( i = 0 ; i < gameLocal.numClients ; i++ ) { - idEntity *ent = gameLocal.entities[ i ]; - if ( !ent || !ent->IsType( idPlayer::Type ) ) { - continue; - } - if ( !CanPlay( static_cast< idPlayer * >( ent ) ) ) { - continue; - } - if ( ent == leader ) { - continue; - } - if ( playerState[ ent->entityNumber ].fragCount > 0 ) { - return NULL; - } - } - // there is a leader, his score may even be negative, but no one else has frags left or is !lastManOver - return leader; - } else if ( IsGametypeTeamBased() ) { /* CTF */ - if ( playerState[ leader->entityNumber ].teamFragCount >= fragLimit ) { - return leader; - } - } else { - if ( playerState[ leader->entityNumber ].fragCount >= fragLimit ) { - return leader; - } - } - - return NULL; -} - -/* -================ -idMultiplayerGame::TimeLimitHit -================ -*/ -bool idMultiplayerGame::TimeLimitHit() { - int timeLimit = gameLocal.serverInfo.GetInt( "si_timeLimit" ); - if ( timeLimit ) { - if ( gameLocal.time >= matchStartedTime + timeLimit * 60000 ) { - return true; - } - } - return false; -} - -#ifdef CTF - -/* -================ -idMultiplayerGame::WinningTeam -return winning team --1 if tied or no players -================ -*/ -int idMultiplayerGame::WinningTeam( void ) { - if ( teamPoints[0] > teamPoints[1] ) - return 0; - if ( teamPoints[0] < teamPoints[1] ) - return 1; - return -1; -} - -/* -================ -idMultiplayerGame::PointLimitHit -================ -*/ -bool idMultiplayerGame::PointLimitHit( void ) { - int pointLimit = gameLocal.serverInfo.GetInt( "si_fragLimit" ); - - // default to MP_CTF_MAXPOINTS if needed - if ( pointLimit > MP_CTF_MAXPOINTS ) - pointLimit = MP_CTF_MAXPOINTS; - else if ( pointLimit <= 0 ) - pointLimit = MP_CTF_MAXPOINTS; - - if ( teamPoints[0] == teamPoints[1] ) - return false; - - if ( teamPoints[0] >= pointLimit || - teamPoints[1] >= pointLimit ) - return true; - - return false; -} -#endif - -/* -================ -idMultiplayerGame::FragLeader -return the current winner ( or a player from the winning team ) -NULL if even -================ -*/ -idPlayer *idMultiplayerGame::FragLeader( void ) { - int i; - int frags[ MAX_CLIENTS ]; - idPlayer *leader = NULL; - idEntity *ent; - idPlayer *p; - int high = -9999; - int count = 0; - bool teamLead[ 2 ] = { false, false }; - - for ( i = 0 ; i < gameLocal.numClients ; i++ ) { - ent = gameLocal.entities[ i ]; - if ( !ent || !ent->IsType( idPlayer::Type ) ) { - continue; - } - if ( !CanPlay( static_cast< idPlayer * >( ent ) ) ) { - continue; - } - if ( gameLocal.gameType == GAME_TOURNEY && ent->entityNumber != currentTourneyPlayer[ 0 ] && ent->entityNumber != currentTourneyPlayer[ 1 ] ) { - continue; - } - if ( static_cast< idPlayer * >( ent )->lastManOver ) { - continue; - } - - int fragc = ( IsGametypeTeamBased() ) ? playerState[i].teamFragCount : playerState[i].fragCount; /* CTF */ - if ( fragc > high ) { - high = fragc; - } - - frags[ i ] = fragc; - } - - for ( i = 0; i < gameLocal.numClients; i++ ) { - ent = gameLocal.entities[ i ]; - if ( !ent || !ent->IsType( idPlayer::Type ) ) { - continue; - } - p = static_cast< idPlayer * >( ent ); - p->SetLeader( false ); - - if ( !CanPlay( p ) ) { - continue; - } - if ( gameLocal.gameType == GAME_TOURNEY && ent->entityNumber != currentTourneyPlayer[ 0 ] && ent->entityNumber != currentTourneyPlayer[ 1 ] ) { - continue; - } - if ( p->lastManOver ) { - continue; - } - if ( p->spectating ) { - continue; - } - - if ( frags[ i ] >= high ) { - leader = p; - count++; - p->SetLeader( true ); - if ( IsGametypeTeamBased() ) { /* CTF */ - teamLead[ p->team ] = true; - } - } - } - - if ( !IsGametypeTeamBased() ) { /* CTF */ - // more than one player at the highest frags - if ( count > 1 ) { - return NULL; - } else { - return leader; - } - } else { - if ( teamLead[ 0 ] && teamLead[ 1 ] ) { - // even game in team play - return NULL; - } - return leader; - } -} - -/* -================ -idGameLocal::UpdateWinsLosses -================ -*/ -void idMultiplayerGame::UpdateWinsLosses( idPlayer *winner ) { - if ( winner ) { - // run back through and update win/loss count - for( int i = 0; i < gameLocal.numClients; i++ ) { - idEntity *ent = gameLocal.entities[ i ]; - if ( !ent || !ent->IsType( idPlayer::Type ) ) { - continue; - } - idPlayer *player = static_cast(ent); - if ( IsGametypeTeamBased() ) { /* CTF */ - if ( player == winner || ( player != winner && player->team == winner->team ) ) { - playerState[ i ].wins++; - PlayGlobalSound( player->entityNumber, SND_YOUWIN ); - } else { - PlayGlobalSound( player->entityNumber, SND_YOULOSE ); - } - } else if ( gameLocal.gameType == GAME_LASTMAN ) { - if ( player == winner ) { - playerState[ i ].wins++; - PlayGlobalSound( player->entityNumber, SND_YOUWIN ); - } else if ( !player->wantSpectate ) { - PlayGlobalSound( player->entityNumber, SND_YOULOSE ); - } - } else if ( gameLocal.gameType == GAME_TOURNEY ) { - if ( player == winner ) { - playerState[ i ].wins++; - PlayGlobalSound( player->entityNumber, SND_YOUWIN ); - } else if ( i == currentTourneyPlayer[ 0 ] || i == currentTourneyPlayer[ 1 ] ) { - PlayGlobalSound( player->entityNumber, SND_YOULOSE ); - } - } else { - if ( player == winner ) { - playerState[i].wins++; - PlayGlobalSound( player->entityNumber, SND_YOUWIN ); - } else if ( !player->wantSpectate ) { - PlayGlobalSound( player->entityNumber, SND_YOULOSE ); - } - } - } - } -#ifdef CTF - else if ( IsGametypeFlagBased() ) { /* CTF */ - int winteam = WinningTeam(); - - if ( winteam != -1 ) // TODO : print a message telling it why the hell the game ended with no winning team? - for( int i = 0; i < gameLocal.numClients; i++ ) { - idEntity *ent = gameLocal.entities[ i ]; - if ( !ent || !ent->IsType( idPlayer::Type ) ) { - continue; - } - idPlayer *player = static_cast(ent); - - if ( player->team == winteam ) { - PlayGlobalSound( player->entityNumber, SND_YOUWIN ); - } else { - PlayGlobalSound( player->entityNumber, SND_YOULOSE ); - } - } - } -#endif - - if ( winner ) { - lastWinner = winner->entityNumber; - } else { - lastWinner = -1; - } -} - -#ifdef CTF -/* -================ -idMultiplayerGame::TeamScoreCTF -================ -*/ -void idMultiplayerGame::TeamScoreCTF( int team, int delta ) { - if ( team < 0 || team > 1 ) - return; - - teamPoints[team] += delta; - - if ( gameState == GAMEON || gameState == SUDDENDEATH ) - PrintMessageEvent( -1, MSG_SCOREUPDATE, teamPoints[0], teamPoints[1] ); -} - -/* -================ -idMultiplayerGame::PlayerScoreCTF -================ -*/ -void idMultiplayerGame::PlayerScoreCTF( int playerIdx, int delta ) { - if ( playerIdx < 0 || playerIdx >= MAX_CLIENTS ) - return; - - playerState[ playerIdx ].fragCount += delta; -} - -/* -================ -idMultiplayerGame::GetFlagCarrier -================ -*/ -int idMultiplayerGame::GetFlagCarrier( int team ) { - int iFlagCarrier = -1; - - for ( int i = 0; i < gameLocal.numClients; i++ ) { - idEntity * ent = gameLocal.entities[ i ]; - if ( !ent || !ent->IsType( idPlayer::Type ) ) { - continue; - } - - idPlayer * player = static_cast( ent ); - if ( player->team != team ) - continue; - - if ( player->carryingFlag ) { - if ( iFlagCarrier != -1 ) - gameLocal.Warning( "BUG: more than one flag carrier on %s team", team == 0 ? "red" : "blue" ); - iFlagCarrier = i; - } - } - - return iFlagCarrier; -} - - - -#endif - -/* -================ -idMultiplayerGame::TeamScore -================ -*/ -void idMultiplayerGame::TeamScore( int entityNumber, int team, int delta ) { - playerState[ entityNumber ].fragCount += delta; - for( int i = 0 ; i < gameLocal.numClients ; i++ ) { - idEntity *ent = gameLocal.entities[ i ]; - if ( !ent || !ent->IsType( idPlayer::Type ) ) { - continue; - } - idPlayer *player = static_cast(ent); - if ( player->team == team ) { - playerState[ player->entityNumber ].teamFragCount += delta; - } - } -} - -/* -================ -idMultiplayerGame::PlayerDeath -================ -*/ -void idMultiplayerGame::PlayerDeath( idPlayer *dead, idPlayer *killer, bool telefrag ) { - - // don't do PrintMessageEvent and shit - assert( !gameLocal.isClient ); - - if ( killer ) { - if ( gameLocal.gameType == GAME_LASTMAN ) { - playerState[ dead->entityNumber ].fragCount--; - - } else if ( IsGametypeTeamBased() ) { /* CTF */ - if ( killer == dead || killer->team == dead->team ) { - // suicide or teamkill - TeamScore( killer->entityNumber, killer->team, -1 ); - } else { - TeamScore( killer->entityNumber, killer->team, +1 ); - } - } else { - playerState[ killer->entityNumber ].fragCount += ( killer == dead ) ? -1 : 1; - } - } - - if ( killer && killer == dead ) { - PrintMessageEvent( -1, MSG_SUICIDE, dead->entityNumber ); - } else if ( killer ) { - if ( telefrag ) { - PrintMessageEvent( -1, MSG_TELEFRAGGED, dead->entityNumber, killer->entityNumber ); - } else if ( IsGametypeTeamBased() && dead->team == killer->team ) { /* CTF */ - PrintMessageEvent( -1, MSG_KILLEDTEAM, dead->entityNumber, killer->entityNumber ); - } else { - PrintMessageEvent( -1, MSG_KILLED, dead->entityNumber, killer->entityNumber ); - } - } else { - PrintMessageEvent( -1, MSG_DIED, dead->entityNumber ); - playerState[ dead->entityNumber ].fragCount--; - } -} - -/* -================ -idMultiplayerGame::PlayerStats -================ -*/ -void idMultiplayerGame::PlayerStats( int clientNum, char *data, const int len ) { - - idEntity *ent; - int team; - - *data = 0; - - // make sure we don't exceed the client list - if ( clientNum < 0 || clientNum > gameLocal.numClients ) { - return; - } - - // find which team this player is on - ent = gameLocal.entities[ clientNum ]; - if ( ent && ent->IsType( idPlayer::Type ) ) { - team = static_cast< idPlayer * >(ent)->team; - } else { - return; - } - - idStr::snPrintf( data, len, "team=%d score=%d tks=%d", team, playerState[ clientNum ].fragCount, playerState[ clientNum ].teamFragCount ); - - return; - -} - -/* -================ -idMultiplayerGame::PlayerVote -================ -*/ -void idMultiplayerGame::PlayerVote( int clientNum, playerVote_t vote ) { - playerState[ clientNum ].vote = vote; -} - -/* -================ -idMultiplayerGame::DumpTourneyLine -================ -*/ -void idMultiplayerGame::DumpTourneyLine( void ) { - int i; - for ( i = 0; i < gameLocal.numClients; i++ ) { - if ( gameLocal.entities[ i ] && gameLocal.entities[ i ]->IsType( idPlayer::Type ) ) { - common->Printf( "client %d: rank %d\n", i, static_cast< idPlayer * >( gameLocal.entities[ i ] )->tourneyRank ); - } - } -} - -/* -================ -idMultiplayerGame::NewState -================ -*/ -void idMultiplayerGame::NewState( gameState_t news, idPlayer *player ) { - idBitMsg outMsg; - byte msgBuf[MAX_GAME_MESSAGE_SIZE]; - int i; - - assert( news != gameState ); - assert( !gameLocal.isClient ); - gameLocal.DPrintf( "%s -> %s\n", GameStateStrings[ gameState ], GameStateStrings[ news ] ); - switch( news ) { - case GAMEON: { - gameLocal.LocalMapRestart(); - outMsg.Init( msgBuf, sizeof( msgBuf ) ); - outMsg.WriteByte( GAME_RELIABLE_MESSAGE_RESTART ); - outMsg.WriteBits( 0, 1 ); - networkSystem->ServerSendReliableMessage( -1, outMsg ); - -#ifdef CTF - teamPoints[0] = 0; - teamPoints[1] = 0; - - ClearHUDStatus(); -#endif - - PlayGlobalSound( -1, SND_FIGHT ); - matchStartedTime = gameLocal.time; - fragLimitTimeout = 0; - for( i = 0; i < gameLocal.numClients; i++ ) { - idEntity *ent = gameLocal.entities[ i ]; - if ( !ent || !ent->IsType( idPlayer::Type ) ) { - continue; - } - idPlayer *p = static_cast( ent ); - p->SetLeader( false ); // don't carry the flag from previous games - if ( gameLocal.gameType == GAME_TOURNEY && currentTourneyPlayer[ 0 ] != i && currentTourneyPlayer[ 1 ] != i ) { - p->ServerSpectate( true ); - p->tourneyRank++; - } else { - int fragLimit = gameLocal.serverInfo.GetInt( "si_fragLimit" ); - int startingCount = ( gameLocal.gameType == GAME_LASTMAN ) ? fragLimit : 0; - playerState[ i ].fragCount = startingCount; - playerState[ i ].teamFragCount = startingCount; - if ( !static_cast(ent)->wantSpectate ) { - static_cast(ent)->ServerSpectate( false ); - if ( gameLocal.gameType == GAME_TOURNEY ) { - p->tourneyRank = 0; - } - } - } - if ( CanPlay( p ) ) { - p->lastManPresent = true; - } else { - p->lastManPresent = false; - } - } - cvarSystem->SetCVarString( "ui_ready", "Not Ready" ); - switchThrottle[ 1 ] = 0; // passby the throttle - startFragLimit = gameLocal.serverInfo.GetInt( "si_fragLimit" ); - break; - } - case GAMEREVIEW: { -#ifdef CTF - SetFlagMsg( false ); -#endif - nextState = INACTIVE; // used to abort a game. cancel out any upcoming state change - // set all players not ready and spectating - for( i = 0; i < gameLocal.numClients; i++ ) { - idEntity *ent = gameLocal.entities[ i ]; - if ( !ent || !ent->IsType( idPlayer::Type ) ) { - continue; - } - static_cast< idPlayer *>( ent )->forcedReady = false; - static_cast(ent)->ServerSpectate( true ); - } - UpdateWinsLosses( player ); -#ifdef CTF - SetFlagMsg( true ); -#endif - break; - } - case SUDDENDEATH: { - PrintMessageEvent( -1, MSG_SUDDENDEATH ); - PlayGlobalSound( -1, SND_SUDDENDEATH ); - break; - } - case COUNTDOWN: { - idBitMsg outMsg; - byte msgBuf[ 128 ]; - - warmupEndTime = gameLocal.time + 1000*cvarSystem->GetCVarInteger( "g_countDown" ); - - outMsg.Init( msgBuf, sizeof( msgBuf ) ); - outMsg.WriteByte( GAME_RELIABLE_MESSAGE_WARMUPTIME ); - outMsg.WriteInt( warmupEndTime ); - networkSystem->ServerSendReliableMessage( -1, outMsg ); - - break; - } -#ifdef CTF - case WARMUP: { - teamPoints[0] = 0; - teamPoints[1] = 0; - - if ( IsGametypeFlagBased() ) { - // reset player scores to zero, only required for CTF - for( i = 0; i < gameLocal.numClients; i++ ) { - idEntity *ent = gameLocal.entities[ i ]; - if ( !ent || !ent->IsType( idPlayer::Type ) ) { - continue; - } - playerState[ i ].fragCount = 0; - } - } - } -#endif - default: - break; - } - - gameState = news; -} - -/* -================ -idMultiplayerGame::FillTourneySlots -NOTE: called each frame during warmup to keep the tourney slots filled -================ -*/ -void idMultiplayerGame::FillTourneySlots( ) { - int i, j, rankmax, rankmaxindex; - idEntity *ent; - idPlayer *p; - - // fill up the slots based on tourney ranks - for ( i = 0; i < 2; i++ ) { - if ( currentTourneyPlayer[ i ] != -1 ) { - continue; - } - rankmax = -1; - rankmaxindex = -1; - for ( j = 0; j < gameLocal.numClients; j++ ) { - ent = gameLocal.entities[ j ]; - if ( !ent || !ent->IsType( idPlayer::Type ) ) { - continue; - } - if ( currentTourneyPlayer[ 0 ] == j || currentTourneyPlayer[ 1 ] == j ) { - continue; - } - p = static_cast< idPlayer * >( ent ); - if ( p->wantSpectate ) { - continue; - } - if ( p->tourneyRank >= rankmax ) { - // when ranks are equal, use time in game - if ( p->tourneyRank == rankmax ) { - assert( rankmaxindex >= 0 ); - if ( p->spawnedTime > static_cast< idPlayer * >( gameLocal.entities[ rankmaxindex ] )->spawnedTime ) { - continue; - } - } - rankmax = static_cast< idPlayer * >( ent )->tourneyRank; - rankmaxindex = j; - } - } - currentTourneyPlayer[ i ] = rankmaxindex; // may be -1 if we found nothing - } -} - -/* -================ -idMultiplayerGame::UpdateTourneyLine -we manipulate tourneyRank on player entities for internal ranking. it's easier to deal with. -but we need a real wait list to be synced down to clients for GUI -ignore current players, ignore wantSpectate -================ -*/ -void idMultiplayerGame::UpdateTourneyLine( void ) { - int i, j, imax, max, globalmax = -1; - idPlayer *p; - - assert( !gameLocal.isClient ); - if ( gameLocal.gameType != GAME_TOURNEY ) { - return; - } - - for ( j = 1; j <= gameLocal.numClients; j++ ) { - max = -1; imax = -1; - for ( i = 0; i < gameLocal.numClients; i++ ) { - if ( currentTourneyPlayer[ 0 ] == i || currentTourneyPlayer[ 1 ] == i ) { - continue; - } - p = static_cast< idPlayer * >( gameLocal.entities[ i ] ); - if ( !p || p->wantSpectate ) { - continue; - } - if ( p->tourneyRank > max && ( globalmax == -1 || p->tourneyRank < globalmax ) ) { - imax = i; - max = p->tourneyRank; - } - } - if ( imax == -1 ) { - break; - } - - idBitMsg outMsg; - byte msgBuf[1024]; - outMsg.Init( msgBuf, sizeof( msgBuf ) ); - outMsg.WriteByte( GAME_RELIABLE_MESSAGE_TOURNEYLINE ); - outMsg.WriteByte( j ); - networkSystem->ServerSendReliableMessage( imax, outMsg ); - - globalmax = max; - } -} - -/* -================ -idMultiplayerGame::CycleTourneyPlayers -================ -*/ -void idMultiplayerGame::CycleTourneyPlayers( ) { - int i; - idEntity *ent; - idPlayer *player; - - currentTourneyPlayer[ 0 ] = -1; - currentTourneyPlayer[ 1 ] = -1; - // if any, winner from last round will play again - if ( lastWinner != -1 ) { - idEntity *ent = gameLocal.entities[ lastWinner ]; - if ( ent && ent->IsType( idPlayer::Type ) ) { - currentTourneyPlayer[ 0 ] = lastWinner; - } - } - FillTourneySlots( ); - // force selected players in/out of the game and update the ranks - for ( i = 0 ; i < gameLocal.numClients ; i++ ) { - if ( currentTourneyPlayer[ 0 ] == i || currentTourneyPlayer[ 1 ] == i ) { - player = static_cast( gameLocal.entities[ i ] ); - player->ServerSpectate( false ); - } else { - ent = gameLocal.entities[ i ]; - if ( ent && ent->IsType( idPlayer::Type ) ) { - player = static_cast( gameLocal.entities[ i ] ); - player->ServerSpectate( true ); - } - } - } - UpdateTourneyLine(); -} - -/* -================ -idMultiplayerGame::ExecuteVote -the votes are checked for validity/relevance before they are started -we assume that they are still legit when reaching here -================ -*/ -void idMultiplayerGame::ExecuteVote( void ) { - bool needRestart; - switch ( vote ) { - case VOTE_RESTART: - gameLocal.MapRestart(); - break; - case VOTE_TIMELIMIT: - si_timeLimit.SetInteger( atoi( voteValue ) ); -#ifdef _D3XP - needRestart = gameLocal.NeedRestart(); - cmdSystem->BufferCommandText( CMD_EXEC_NOW, "rescanSI" ); - if ( needRestart ) { - cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "nextMap" ); - } -#endif - break; - case VOTE_FRAGLIMIT: - si_fragLimit.SetInteger( atoi( voteValue ) ); -#ifdef _D3XP - needRestart = gameLocal.NeedRestart(); - cmdSystem->BufferCommandText( CMD_EXEC_NOW, "rescanSI" ); - if ( needRestart ) { - cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "nextMap" ); - } -#endif - break; - case VOTE_GAMETYPE: - si_gameType.SetString( voteValue ); - gameLocal.MapRestart(); - break; - case VOTE_KICK: - cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "kick %s", voteValue.c_str() ) ); - break; - case VOTE_MAP: - si_map.SetString( voteValue ); - gameLocal.MapRestart(); - break; - case VOTE_SPECTATORS: - si_spectators.SetBool( !si_spectators.GetBool() ); -#ifdef _D3XP - needRestart = gameLocal.NeedRestart(); - cmdSystem->BufferCommandText( CMD_EXEC_NOW, "rescanSI" ); - if ( needRestart ) { - cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "nextMap" ); - } -#endif - break; - case VOTE_NEXTMAP: - cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "serverNextMap\n" ); - break; - } -} - -/* -================ -idMultiplayerGame::CheckVote -================ -*/ -void idMultiplayerGame::CheckVote( void ) { - int numVoters, i; - - if ( vote == VOTE_NONE ) { - return; - } - - if ( voteExecTime ) { - if ( gameLocal.time > voteExecTime ) { - voteExecTime = 0; - ClientUpdateVote( VOTE_RESET, 0, 0 ); - ExecuteVote(); - vote = VOTE_NONE; - } - return; - } - - // count voting players - numVoters = 0; - for ( i = 0; i < gameLocal.numClients; i++ ) { - idEntity *ent = gameLocal.entities[ i ]; - if ( !ent || !ent->IsType( idPlayer::Type ) ) { - continue; - } - if ( playerState[ i ].vote != PLAYER_VOTE_NONE ) { - numVoters++; - } - } - if ( !numVoters ) { - // abort - vote = VOTE_NONE; - ClientUpdateVote( VOTE_ABORTED, yesVotes, noVotes ); - return; - } - if ( yesVotes / numVoters > 0.5f ) { - ClientUpdateVote( VOTE_PASSED, yesVotes, noVotes ); - voteExecTime = gameLocal.time + 2000; - return; - } - if ( gameLocal.time > voteTimeOut || noVotes / numVoters >= 0.5f ) { - ClientUpdateVote( VOTE_FAILED, yesVotes, noVotes ); - vote = VOTE_NONE; - return; - } -} - -/* -================ -idMultiplayerGame::Warmup -================ -*/ -bool idMultiplayerGame::Warmup() { - return ( gameState == WARMUP ); -} - -/* -================ -idMultiplayerGame::Run -================ -*/ -void idMultiplayerGame::Run() { - int i, timeLeft; - idPlayer *player; - int gameReviewPause; - - assert( gameLocal.isMultiplayer ); - assert( !gameLocal.isClient ); - - pureReady = true; - - if ( gameState == INACTIVE ) { - lastGameType = gameLocal.gameType; - NewState( WARMUP ); - } - - CheckVote(); - - CheckRespawns(); - - if ( nextState != INACTIVE && gameLocal.time > nextStateSwitch ) { - NewState( nextState ); - nextState = INACTIVE; - } - - // don't update the ping every frame to save bandwidth - if ( gameLocal.time > pingUpdateTime ) { - for ( i = 0; i < gameLocal.numClients; i++ ) { - playerState[i].ping = networkSystem->ServerGetClientPing( i ); - } - pingUpdateTime = gameLocal.time + 1000; - } - - warmupText = ""; - - switch( gameState ) { - case GAMEREVIEW: { - if ( nextState == INACTIVE ) { - gameReviewPause = cvarSystem->GetCVarInteger( "g_gameReviewPause" ); - nextState = NEXTGAME; - nextStateSwitch = gameLocal.time + 1000 * gameReviewPause; - } - break; - } - case NEXTGAME: { - if ( nextState == INACTIVE ) { - // game rotation, new map, gametype etc. - if ( gameLocal.NextMap() ) { - cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "serverMapRestart\n" ); - return; - } -#ifdef CTF - // make sure flags are returned - if ( IsGametypeFlagBased() ) { - idItemTeam * flag; - flag = GetTeamFlag( 0 ); - if ( flag ) { - flag->Return(); - } - flag = GetTeamFlag( 1 ); - if ( flag ) { - flag->Return(); - } - } -#endif - NewState( WARMUP ); - if ( gameLocal.gameType == GAME_TOURNEY ) { - CycleTourneyPlayers(); - } - // put everyone back in from endgame spectate - for ( i = 0; i < gameLocal.numClients; i++ ) { - idEntity *ent = gameLocal.entities[ i ]; - if ( ent && ent->IsType( idPlayer::Type ) ) { - if ( !static_cast< idPlayer * >( ent )->wantSpectate ) { - CheckRespawns( static_cast( ent ) ); - } - } - } - } - break; - } - case WARMUP: { - if ( AllPlayersReady() ) { - NewState( COUNTDOWN ); - nextState = GAMEON; - nextStateSwitch = gameLocal.time + 1000 * cvarSystem->GetCVarInteger( "g_countDown" ); - } - warmupText = "Warming up.. waiting for players to get ready"; - one = two = three = false; - break; - } - case COUNTDOWN: { - timeLeft = ( nextStateSwitch - gameLocal.time ) / 1000 + 1; - if ( timeLeft == 3 && !three ) { - PlayGlobalSound( -1, SND_THREE ); - three = true; - } else if ( timeLeft == 2 && !two ) { - PlayGlobalSound( -1, SND_TWO ); - two = true; - } else if ( timeLeft == 1 && !one ) { - PlayGlobalSound( -1, SND_ONE ); - one = true; - } - warmupText = va( "Match starts in %i", timeLeft ); - break; - } - case GAMEON: { -#ifdef CTF - if ( IsGametypeFlagBased() ) { /* CTF */ - // totally different logic branch for CTF - if ( PointLimitHit() ) { - int team = WinningTeam(); - assert( team != -1 ); - - NewState( GAMEREVIEW, NULL ); - PrintMessageEvent( -1, MSG_POINTLIMIT, team ); - } else if ( TimeLimitHit() ) { - int team = WinningTeam(); - if ( EnoughClientsToPlay() && team == -1 ) { - NewState( SUDDENDEATH ); - } else { - NewState( GAMEREVIEW, NULL ); - PrintMessageEvent( -1, MSG_TIMELIMIT ); - } - } - break; - } -#endif - - player = FragLimitHit(); - if ( player ) { - // delay between detecting frag limit and ending game. let the death anims play - if ( !fragLimitTimeout ) { - common->DPrintf( "enter FragLimit timeout, player %d is leader\n", player->entityNumber ); - fragLimitTimeout = gameLocal.time + FRAGLIMIT_DELAY; - } - if ( gameLocal.time > fragLimitTimeout ) { - NewState( GAMEREVIEW, player ); - PrintMessageEvent( -1, MSG_FRAGLIMIT, player->entityNumber ); - } - } else { - if ( fragLimitTimeout ) { - // frag limit was hit and cancelled. means the two teams got even during FRAGLIMIT_DELAY - // enter sudden death, the next frag leader will win - SuddenRespawn(); - PrintMessageEvent( -1, MSG_HOLYSHIT ); - fragLimitTimeout = 0; - NewState( SUDDENDEATH ); - } else if ( TimeLimitHit() ) { - player = FragLeader(); - if ( !player ) { - NewState( SUDDENDEATH ); - } else { - NewState( GAMEREVIEW, player ); - PrintMessageEvent( -1, MSG_TIMELIMIT ); - } - } - } - break; - } - case SUDDENDEATH: { -#ifdef CTF - if ( IsGametypeFlagBased() ) { /* CTF */ - int team = WinningTeam(); - if ( team != -1 ) { - // TODO : implement pointLimitTimeout - NewState( GAMEREVIEW, NULL ); - PrintMessageEvent( -1, MSG_POINTLIMIT, team ); - } - break; - } -#endif - - player = FragLeader(); - if ( player ) { - if ( !fragLimitTimeout ) { - common->DPrintf( "enter sudden death FragLeader timeout, player %d is leader\n", player->entityNumber ); - fragLimitTimeout = gameLocal.time + FRAGLIMIT_DELAY; - } - if ( gameLocal.time > fragLimitTimeout ) { - NewState( GAMEREVIEW, player ); - PrintMessageEvent( -1, MSG_FRAGLIMIT, player->entityNumber ); - } - } else if ( fragLimitTimeout ) { - SuddenRespawn(); - PrintMessageEvent( -1, MSG_HOLYSHIT ); - fragLimitTimeout = 0; - } - break; - } - } -} - -/* -================ -idMultiplayerGame::UpdateMainGui -================ -*/ -void idMultiplayerGame::UpdateMainGui( void ) { - int i; - mainGui->SetStateInt( "readyon", gameState == WARMUP ? 1 : 0 ); - mainGui->SetStateInt( "readyoff", gameState != WARMUP ? 1 : 0 ); - idStr strReady = cvarSystem->GetCVarString( "ui_ready" ); - if ( strReady.Icmp( "ready") == 0 ){ - strReady = common->GetLanguageDict()->GetString( "#str_04248" ); - } else { - strReady = common->GetLanguageDict()->GetString( "#str_04247" ); - } - mainGui->SetStateString( "ui_ready", strReady ); - mainGui->SetStateInt( "teamon", IsGametypeTeamBased() ? 1 : 0 ); /* CTF */ - mainGui->SetStateInt( "teamoff", (!IsGametypeTeamBased()) ? 1 : 0 ); /* CTF */ - if ( IsGametypeTeamBased() ) { - idPlayer *p = gameLocal.GetClientByNum( gameLocal.localClientNum ); - if ( p ) { - mainGui->SetStateInt( "team", p->team ); - } - else { - mainGui->SetStateInt( "team", 0 ); - } - } - // setup vote - mainGui->SetStateInt( "voteon", ( vote != VOTE_NONE && !voted ) ? 1 : 0 ); - mainGui->SetStateInt( "voteoff", ( vote != VOTE_NONE && !voted ) ? 0 : 1 ); - // last man hack - mainGui->SetStateInt( "isLastMan", gameLocal.gameType == GAME_LASTMAN ? 1 : 0 ); - // send the current serverinfo values - for ( i = 0; i < gameLocal.serverInfo.GetNumKeyVals(); i++ ) { - const idKeyValue *keyval = gameLocal.serverInfo.GetKeyVal( i ); - mainGui->SetStateString( keyval->GetKey(), keyval->GetValue() ); - } - mainGui->StateChanged( gameLocal.time ); - mainGui->SetStateString( "driver_prompt", "0" ); -} - -/* -================ -idMultiplayerGame::StartMenu -================ -*/ -idUserInterface* idMultiplayerGame::StartMenu( void ) { - - if ( mainGui == NULL ) { - return NULL; - } - - int i, j; - if ( currentMenu ) { - currentMenu = 0; - cvarSystem->SetCVarBool( "ui_chat", false ); - } else { - if ( nextMenu >= 2 ) { - currentMenu = nextMenu; - } else { - // for default and explicit - currentMenu = 1; - } - cvarSystem->SetCVarBool( "ui_chat", true ); - } - nextMenu = 0; - gameLocal.sessionCommand = ""; // in case we used "game_startMenu" to trigger the menu - if ( currentMenu == 1 ) { - UpdateMainGui(); - - // UpdateMainGui sets most things, but it doesn't set these because - // it'd be pointless and/or harmful to set them every frame (for various reasons) - // Currenty the gui doesn't update properly if they change anyway, so we'll leave it like this. - - // setup callvote - if ( vote == VOTE_NONE ) { - bool callvote_ok = false; - for ( i = 0; i < VOTE_COUNT; i++ ) { - // flag on means vote is denied, so default value 0 means all votes and -1 disables - mainGui->SetStateInt( va( "vote%d", i ), g_voteFlags.GetInteger() & ( 1 << i ) ? 0 : 1 ); - if ( !( g_voteFlags.GetInteger() & ( 1 << i ) ) ) { - callvote_ok = true; - } - } - mainGui->SetStateInt( "callvote", callvote_ok ); - } else { - mainGui->SetStateInt( "callvote", 2 ); - } - - // player kick data - idStr kickList; - j = 0; - for ( i = 0; i < gameLocal.numClients; i++ ) { - if ( gameLocal.entities[ i ] && gameLocal.entities[ i ]->IsType( idPlayer::Type ) ) { - if ( kickList.Length() ) { - kickList += ";"; - } - kickList += va( "\"%d - %s\"", i, gameLocal.userInfo[ i ].GetString( "ui_name" ) ); - kickVoteMap[ j ] = i; - j++; - } - } - mainGui->SetStateString( "kickChoices", kickList ); - -#ifdef CTF - const char *gametype = gameLocal.serverInfo.GetString( "si_gameType" ); - const char *map = gameLocal.serverInfo.GetString( "si_map" ); // what if server changes this strings while user in UI? - int num = declManager->GetNumDecls( DECL_MAPDEF ); - - for ( i = 0; i < num; i++ ) { - const idDeclEntityDef *mapDef = static_cast( declManager->DeclByIndex( DECL_MAPDEF, i ) ); - - if ( mapDef && idStr::Icmp( mapDef->GetName(), map ) == 0 && mapDef->dict.GetBool( gametype ) ) { - int k = 0; - - idStr gametypeList; - - for ( j = 0; si_gameTypeArgs[ j ]; j++ ) { - if ( mapDef->dict.GetBool( si_gameTypeArgs[ j ] ) ) { - if ( gametypeList.Length() ) { - gametypeList += ";"; - } - gametypeList += va( "%s", si_gameTypeArgs[ j ] ); - gameTypeVoteMap[ k ] = si_gameTypeArgs[ j ]; - k++; - } - } - - mainGui->SetStateString( "gametypeChoices", gametypeList ); - - break; - } - } -#endif - - mainGui->SetStateString( "chattext", "" ); - mainGui->Activate( true, gameLocal.time ); - return mainGui; - } else if ( currentMenu == 2 ) { - // the setup is done in MessageMode - msgmodeGui->Activate( true, gameLocal.time ); - cvarSystem->SetCVarBool( "ui_chat", true ); - return msgmodeGui; - } - return NULL; -} - -/* -================ -idMultiplayerGame::DisableMenu -================ -*/ -void idMultiplayerGame::DisableMenu( void ) { - gameLocal.sessionCommand = ""; // in case we used "game_startMenu" to trigger the menu - if ( currentMenu == 1 ) { - mainGui->Activate( false, gameLocal.time ); - } else if ( currentMenu == 2 ) { - msgmodeGui->Activate( false, gameLocal.time ); - } - currentMenu = 0; - nextMenu = 0; - cvarSystem->SetCVarBool( "ui_chat", false ); -} - -/* -================ -idMultiplayerGame::SetMapShot -================ -*/ -void idMultiplayerGame::SetMapShot( void ) { - char screenshot[ MAX_STRING_CHARS ]; - int mapNum = mapList->GetSelection( NULL, 0 ); - const idDict *dict = NULL; - if ( mapNum >= 0 ) { - dict = fileSystem->GetMapDecl( mapNum ); - } - fileSystem->FindMapScreenshot( dict ? dict->GetString( "path" ) : "", screenshot, MAX_STRING_CHARS ); - mainGui->SetStateString( "current_levelshot", screenshot ); -} - -/* -================ -idMultiplayerGame::HandleGuiCommands -================ -*/ -const char* idMultiplayerGame::HandleGuiCommands( const char *_menuCommand ) { - idUserInterface *currentGui; - const char *voteValue; - int vote_clientNum; - int icmd; - idCmdArgs args; - - if ( !_menuCommand[ 0 ] ) { - common->Printf( "idMultiplayerGame::HandleGuiCommands: empty command\n" ); - return "continue"; - } - assert( currentMenu ); - if ( currentMenu == 1 ) { - currentGui = mainGui; - } else { - currentGui = msgmodeGui; - } - - args.TokenizeString( _menuCommand, false ); - - for( icmd = 0; icmd < args.Argc(); ) { - const char *cmd = args.Argv( icmd++ ); - - if ( !idStr::Icmp( cmd, ";" ) ) { - continue; - } else if ( !idStr::Icmp( cmd, "video" ) ) { - idStr vcmd; - if ( args.Argc() - icmd >= 1 ) { - vcmd = args.Argv( icmd++ ); - } - - int oldSpec = cvarSystem->GetCVarInteger( "com_machineSpec" ); - - if ( idStr::Icmp( vcmd, "low" ) == 0 ) { - cvarSystem->SetCVarInteger( "com_machineSpec", 0 ); - } else if ( idStr::Icmp( vcmd, "medium" ) == 0 ) { - cvarSystem->SetCVarInteger( "com_machineSpec", 1 ); - } else if ( idStr::Icmp( vcmd, "high" ) == 0 ) { - cvarSystem->SetCVarInteger( "com_machineSpec", 2 ); - } else if ( idStr::Icmp( vcmd, "ultra" ) == 0 ) { - cvarSystem->SetCVarInteger( "com_machineSpec", 3 ); - } else if ( idStr::Icmp( vcmd, "recommended" ) == 0 ) { - cmdSystem->BufferCommandText( CMD_EXEC_NOW, "setMachineSpec\n" ); - } - - if ( oldSpec != cvarSystem->GetCVarInteger( "com_machineSpec" ) ) { - currentGui->SetStateInt( "com_machineSpec", cvarSystem->GetCVarInteger( "com_machineSpec" ) ); - currentGui->StateChanged( gameLocal.realClientTime ); - cmdSystem->BufferCommandText( CMD_EXEC_NOW, "execMachineSpec\n" ); - } - - if ( idStr::Icmp( vcmd, "restart" ) == 0) { - cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "vid_restart\n" ); - } - - continue; - } else if ( !idStr::Icmp( cmd, "play" ) ) { - if ( args.Argc() - icmd >= 1 ) { - idStr snd = args.Argv( icmd++ ); - int channel = 1; - if ( snd.Length() == 1 ) { - channel = atoi( snd ); - snd = args.Argv( icmd++ ); - } - gameSoundWorld->PlayShaderDirectly( snd, channel ); - } - continue; - } else if ( !idStr::Icmp( cmd, "mpSkin" ) ) { - idStr skin; - if ( args.Argc() - icmd >= 1 ) { - skin = args.Argv( icmd++ ); - cvarSystem->SetCVarString( "ui_skin", skin ); - } - SetMenuSkin(); - continue; - } else if ( !idStr::Icmp( cmd, "quit" ) ) { - cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "quit\n" ); - return NULL; - } else if ( !idStr::Icmp( cmd, "disconnect" ) ) { - cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "disconnect\n" ); - return NULL; - } else if ( !idStr::Icmp( cmd, "close" ) ) { - DisableMenu( ); - return NULL; - } else if ( !idStr::Icmp( cmd, "spectate" ) ) { - ToggleSpectate(); - DisableMenu( ); - return NULL; - } else if ( !idStr::Icmp( cmd, "chatmessage" ) ) { - int mode = currentGui->State().GetInt( "messagemode" ); - if ( mode ) { - cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "sayTeam \"%s\"", currentGui->State().GetString( "chattext" ) ) ); - } else { - cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "say \"%s\"", currentGui->State().GetString( "chattext" ) ) ); - } - currentGui->SetStateString( "chattext", "" ); - if ( currentMenu == 1 ) { - return "continue"; - } else { - DisableMenu(); - return NULL; - } - } else if ( !idStr::Icmp( cmd, "readytoggle" ) ) { - ToggleReady( ); - DisableMenu( ); - return NULL; - } else if ( !idStr::Icmp( cmd, "teamtoggle" ) ) { - ToggleTeam( ); - DisableMenu( ); - return NULL; - } else if ( !idStr::Icmp( cmd, "callVote" ) ) { - vote_flags_t voteIndex = (vote_flags_t)mainGui->State().GetInt( "voteIndex" ); - if ( voteIndex == VOTE_MAP ) { - int mapNum = mapList->GetSelection( NULL, 0 ); - if ( mapNum >= 0 ) { - const idDict *dict = fileSystem->GetMapDecl( mapNum ); - if ( dict ) { - ClientCallVote( VOTE_MAP, dict->GetString( "path" ) ); - } - } - } else { - voteValue = mainGui->State().GetString( "str_voteValue" ); - if ( voteIndex == VOTE_KICK ) { - vote_clientNum = kickVoteMap[ atoi( voteValue ) ]; - ClientCallVote( voteIndex, va( "%d", vote_clientNum ) ); -#ifdef CTF - } else if ( voteIndex == VOTE_GAMETYPE ) { - // send the actual gametype index, not an index in the choice list - int i; - for ( i = 0; si_gameTypeArgs[i]; i++ ) { - if ( !idStr::Icmp( gameTypeVoteMap[ atoi( voteValue ) ], si_gameTypeArgs[i] ) ) { - ClientCallVote( voteIndex, va( "%d", i ) ); - break; - } - } -#endif - } else { - ClientCallVote( voteIndex, voteValue ); - } - } - DisableMenu(); - return NULL; - } else if ( !idStr::Icmp( cmd, "voteyes" ) ) { - CastVote( gameLocal.localClientNum, true ); - DisableMenu(); - return NULL; - } else if ( !idStr::Icmp( cmd, "voteno" ) ) { - CastVote( gameLocal.localClientNum, false ); - DisableMenu(); - return NULL; - } else if ( !idStr::Icmp( cmd, "bind" ) ) { - if ( args.Argc() - icmd >= 2 ) { - idStr key = args.Argv( icmd++ ); - idStr bind = args.Argv( icmd++ ); - cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "bindunbindtwo \"%s\" \"%s\"", key.c_str(), bind.c_str() ) ); - mainGui->SetKeyBindingNames(); - } - continue; - } else if ( !idStr::Icmp( cmd, "clearbind" ) ) { - if ( args.Argc() - icmd >= 1 ) { - idStr bind = args.Argv( icmd++ ); - cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "unbind \"%s\"", bind.c_str() ) ); - mainGui->SetKeyBindingNames(); - } - continue; - } else if ( !idStr::Icmp( cmd, "MAPScan" ) ) { - const char *gametype = gameLocal.serverInfo.GetString( "si_gameType" ); - if ( gametype == NULL || *gametype == 0 || idStr::Icmp( gametype, "singleplayer" ) == 0 ) { - gametype = "Deathmatch"; - } - - int i, num; - idStr si_map = gameLocal.serverInfo.GetString("si_map"); - const idDict *dict; - - mapList->Clear(); - mapList->SetSelection( -1 ); - num = fileSystem->GetNumMaps(); - for ( i = 0; i < num; i++ ) { - dict = fileSystem->GetMapDecl( i ); - if ( dict ) { - // any MP gametype supported - bool isMP = false; - int igt = GAME_SP + 1; - while ( si_gameTypeArgs[ igt ] ) { - if ( dict->GetBool( si_gameTypeArgs[ igt ] ) ) { - isMP = true; - break; - } - igt++; - } - if ( isMP ) { - const char *mapName = dict->GetString( "name" ); - if ( mapName[0] == '\0' ) { - mapName = dict->GetString( "path" ); - } - mapName = common->GetLanguageDict()->GetString( mapName ); - mapList->Add( i, mapName ); - if ( !si_map.Icmp( dict->GetString( "path" ) ) ) { - mapList->SetSelection( mapList->Num() - 1 ); - } - } - } - } - // set the current level shot - SetMapShot( ); - return "continue"; - } else if ( !idStr::Icmp( cmd, "click_maplist" ) ) { - SetMapShot( ); - return "continue"; - } else if ( strstr( cmd, "sound" ) == cmd ) { - // pass that back to the core, will know what to do with it - return _menuCommand; - } - common->Printf( "idMultiplayerGame::HandleGuiCommands: '%s' unknown\n", cmd ); - - } - return "continue"; -} - -/* -================ -idMultiplayerGame::Draw -================ -*/ -bool idMultiplayerGame::Draw( int clientNum ) { - idPlayer *player, *viewPlayer; - - // clear the render entities for any players that don't need - // icons and which might not be thinking because they weren't in - // the last snapshot. - for ( int i = 0; i < gameLocal.numClients; i++ ) { - player = static_cast( gameLocal.entities[ i ] ); - if ( player && !player->NeedsIcon() ) { - player->HidePlayerIcons(); - } - } - - player = viewPlayer = static_cast( gameLocal.entities[ clientNum ] ); - - if ( player == NULL ) { - return false; - } - - if ( player->spectating ) { - viewPlayer = static_cast( gameLocal.entities[ player->spectator ] ); - if ( viewPlayer == NULL ) { - return false; - } - } - - UpdatePlayerRanks(); - UpdateHud( viewPlayer, player->hud ); - // use the hud of the local player - viewPlayer->playerView.RenderPlayerView( player->hud ); - - if ( currentMenu ) { -#if 0 - // uncomment this if you want to track when players are in a menu - if ( !bCurrentMenuMsg ) { - idBitMsg outMsg; - byte msgBuf[ 128 ]; - - outMsg.Init( msgBuf, sizeof( msgBuf ) ); - outMsg.WriteByte( GAME_RELIABLE_MESSAGE_MENU ); - outMsg.WriteBits( 1, 1 ); - networkSystem->ClientSendReliableMessage( outMsg ); - - bCurrentMenuMsg = true; - } -#endif - if ( player->wantSpectate ) { - mainGui->SetStateString( "spectext", common->GetLanguageDict()->GetString( "#str_04249" ) ); - } else { - mainGui->SetStateString( "spectext", common->GetLanguageDict()->GetString( "#str_04250" ) ); - } - DrawChat(); - if ( currentMenu == 1 ) { - UpdateMainGui(); - mainGui->Redraw( gameLocal.time ); - } else { - msgmodeGui->Redraw( gameLocal.time ); - } - } else { -#if 0 - // uncomment this if you want to track when players are in a menu - if ( bCurrentMenuMsg ) { - idBitMsg outMsg; - byte msgBuf[ 128 ]; - - outMsg.Init( msgBuf, sizeof( msgBuf ) ); - outMsg.WriteByte( GAME_RELIABLE_MESSAGE_MENU ); - outMsg.WriteBits( 0, 1 ); - networkSystem->ClientSendReliableMessage( outMsg ); - - bCurrentMenuMsg = false; - } -#endif - if ( player->spectating ) { - idStr spectatetext[ 2 ]; - int ispecline = 0; - if ( gameLocal.gameType == GAME_TOURNEY ) { - if ( !player->wantSpectate ) { - spectatetext[ 0 ] = common->GetLanguageDict()->GetString( "#str_04246" ); - switch ( player->tourneyLine ) { - case 0: - spectatetext[ 0 ] += common->GetLanguageDict()->GetString( "#str_07003" ); - break; - case 1: - spectatetext[ 0 ] += common->GetLanguageDict()->GetString( "#str_07004" ); - break; - case 2: - spectatetext[ 0 ] += common->GetLanguageDict()->GetString( "#str_07005" ); - break; - default: - spectatetext[ 0 ] += va( common->GetLanguageDict()->GetString( "#str_07006" ), player->tourneyLine ); - break; - } - ispecline++; - } - } else if ( gameLocal.gameType == GAME_LASTMAN ) { - if ( !player->wantSpectate ) { - spectatetext[ 0 ] = common->GetLanguageDict()->GetString( "#str_07007" ); - ispecline++; - } - } - if ( player->spectator != player->entityNumber ) { - spectatetext[ ispecline ] = va( common->GetLanguageDict()->GetString( "#str_07008" ), viewPlayer->GetUserInfo()->GetString( "ui_name" ) ); - } else if ( !ispecline ) { - spectatetext[ 0 ] = common->GetLanguageDict()->GetString( "#str_04246" ); - } - spectateGui->SetStateString( "spectatetext0", spectatetext[0].c_str() ); - spectateGui->SetStateString( "spectatetext1", spectatetext[1].c_str() ); - if ( vote != VOTE_NONE ) { - spectateGui->SetStateString( "vote", va( "%s (y: %d n: %d)", voteString.c_str(), (int)yesVotes, (int)noVotes ) ); - } else { - spectateGui->SetStateString( "vote", "" ); - } - spectateGui->Redraw( gameLocal.time ); - } - DrawChat(); - DrawScoreBoard( player ); - } - - return true; -} - -/* -================ -idMultiplayerGame::UpdateHud -================ -*/ -void idMultiplayerGame::UpdateHud( idPlayer *player, idUserInterface *hud ) { - int i; - - if ( !hud ) { - return; - } - - hud->SetStateBool( "warmup", Warmup() ); - - if ( gameState == WARMUP ) { - if ( player->IsReady() ) { - hud->SetStateString( "warmuptext", common->GetLanguageDict()->GetString( "#str_04251" ) ); - } else { - hud->SetStateString( "warmuptext", common->GetLanguageDict()->GetString( "#str_07002" ) ); - } - } - - hud->SetStateString( "timer", ( Warmup() ) ? common->GetLanguageDict()->GetString( "#str_04251" ) : ( gameState == SUDDENDEATH ) ? common->GetLanguageDict()->GetString( "#str_04252" ) : GameTime() ); - if ( vote != VOTE_NONE ) { - hud->SetStateString( "vote", va( "%s (y: %d n: %d)", voteString.c_str(), (int)yesVotes, (int)noVotes ) ); - } else { - hud->SetStateString( "vote", "" ); - } - - hud->SetStateInt( "rank_self", 0 ); - if ( gameState == GAMEON ) { - for ( i = 0; i < numRankedPlayers; i++ ) { - if ( IsGametypeTeamBased() ) { /* CTF */ - hud->SetStateInt( va( "player%i_score", i+1 ), playerState[ rankedPlayers[ i ]->entityNumber ].teamFragCount ); - } else { - hud->SetStateInt( va( "player%i_score", i+1 ), playerState[ rankedPlayers[ i ]->entityNumber ].fragCount ); - } - hud->SetStateInt( va( "rank%i", i+1 ), 1 ); - UpdateRankColor( hud, "rank%i_color%i", i+1, rankedPlayers[ i ]->colorBar ); - if ( rankedPlayers[ i ] == player ) { - hud->SetStateInt( "rank_self", i+1 ); - } - } - } -#ifdef _D3XP - for ( i = ( gameState == GAMEON ? numRankedPlayers : 0 ) ; i < MAX_CLIENTS; i++ ) { -#else - for ( i = ( gameState == GAMEON ? numRankedPlayers : 0 ) ; i < 5; i++ ) { -#endif - hud->SetStateString( va( "player%i", i+1 ), "" ); - hud->SetStateString( va( "player%i_score", i+1 ), "" ); - hud->SetStateInt( va( "rank%i", i+1 ), 0 ); - } - -#ifdef CTF - if ( IsGametypeFlagBased() ) - hud->SetStateInt( "self_team", player->team ); - else - hud->SetStateInt( "self_team", -1 ); /* Disable */ -#endif - -} - -/* -================ -idMultiplayerGame::DrawScoreBoard -================ -*/ -void idMultiplayerGame::DrawScoreBoard( idPlayer *player ) { - if ( player->scoreBoardOpen || gameState == GAMEREVIEW ) { - if ( !playerState[ player->entityNumber ].scoreBoardUp ) { - scoreBoard->Activate( true, gameLocal.time ); - playerState[ player->entityNumber ].scoreBoardUp = true; - } - -#ifdef CTF - if ( IsGametypeFlagBased() ) - UpdateCTFScoreboard( scoreBoard, player ); - else -#endif - UpdateScoreboard( scoreBoard, player ); - - } else { - if ( playerState[ player->entityNumber ].scoreBoardUp ) { - scoreBoard->Activate( false, gameLocal.time ); - playerState[ player->entityNumber ].scoreBoardUp = false; - } - } -} - -/* -=============== -idMultiplayerGame::ClearChatData -=============== -*/ -void idMultiplayerGame::ClearChatData() { - chatHistoryIndex = 0; - chatHistorySize = 0; - chatDataUpdated = true; -} - -/* -=============== -idMultiplayerGame::AddChatLine -=============== -*/ -void idMultiplayerGame::AddChatLine( const char *fmt, ... ) { - idStr temp; - va_list argptr; - - va_start( argptr, fmt ); - vsprintf( temp, fmt, argptr ); - va_end( argptr ); - - gameLocal.Printf( "%s\n", temp.c_str() ); - - chatHistory[ chatHistoryIndex % NUM_CHAT_NOTIFY ].line = temp; - chatHistory[ chatHistoryIndex % NUM_CHAT_NOTIFY ].fade = 6; - - chatHistoryIndex++; - if ( chatHistorySize < NUM_CHAT_NOTIFY ) { - chatHistorySize++; - } - chatDataUpdated = true; - lastChatLineTime = gameLocal.time; -} - -/* -=============== -idMultiplayerGame::DrawChat -=============== -*/ -void idMultiplayerGame::DrawChat() { - int i, j; - if ( guiChat ) { - if ( gameLocal.time - lastChatLineTime > CHAT_FADE_TIME ) { - if ( chatHistorySize > 0 ) { - for ( i = chatHistoryIndex - chatHistorySize; i < chatHistoryIndex; i++ ) { - chatHistory[ i % NUM_CHAT_NOTIFY ].fade--; - if ( chatHistory[ i % NUM_CHAT_NOTIFY ].fade < 0 ) { - chatHistorySize--; // this assumes the removals are always at the beginning - } - } - chatDataUpdated = true; - } - lastChatLineTime = gameLocal.time; - } - if ( chatDataUpdated ) { - j = 0; - i = chatHistoryIndex - chatHistorySize; - while ( i < chatHistoryIndex ) { - guiChat->SetStateString( va( "chat%i", j ), chatHistory[ i % NUM_CHAT_NOTIFY ].line ); - // don't set alpha above 4, the gui only knows that - guiChat->SetStateInt( va( "alpha%i", j ), Min( 4, (int)chatHistory[ i % NUM_CHAT_NOTIFY ].fade ) ); - j++; i++; - } - while ( j < NUM_CHAT_NOTIFY ) { - guiChat->SetStateString( va( "chat%i", j ), "" ); - j++; - } - guiChat->Activate( true, gameLocal.time ); - chatDataUpdated = false; - } - guiChat->Redraw( gameLocal.time ); - } -} - -#ifdef _D3XP -//D3XP: Adding one to frag count to allow for the negative flag in numbers greater than 255 -const int ASYNC_PLAYER_FRAG_BITS = -(idMath::BitsForInteger( MP_PLAYER_MAXFRAGS - MP_PLAYER_MINFRAGS )+1); // player can have negative frags -#else -const int ASYNC_PLAYER_FRAG_BITS = -idMath::BitsForInteger( MP_PLAYER_MAXFRAGS - MP_PLAYER_MINFRAGS ); // player can have negative frags -#endif -const int ASYNC_PLAYER_WINS_BITS = idMath::BitsForInteger( MP_PLAYER_MAXWINS ); -const int ASYNC_PLAYER_PING_BITS = idMath::BitsForInteger( MP_PLAYER_MAXPING ); - -/* -================ -idMultiplayerGame::WriteToSnapshot -================ -*/ -void idMultiplayerGame::WriteToSnapshot( idBitMsgDelta &msg ) const { - int i; - int value; - - msg.WriteByte( gameState ); - msg.WriteShort( currentTourneyPlayer[ 0 ] ); - msg.WriteShort( currentTourneyPlayer[ 1 ] ); - for ( i = 0; i < MAX_CLIENTS; i++ ) { - // clamp all values to min/max possible value that we can send over - value = idMath::ClampInt( MP_PLAYER_MINFRAGS, MP_PLAYER_MAXFRAGS, playerState[i].fragCount ); - msg.WriteBits( value, ASYNC_PLAYER_FRAG_BITS ); - value = idMath::ClampInt( MP_PLAYER_MINFRAGS, MP_PLAYER_MAXFRAGS, playerState[i].teamFragCount ); - msg.WriteBits( value, ASYNC_PLAYER_FRAG_BITS ); - value = idMath::ClampInt( 0, MP_PLAYER_MAXWINS, playerState[i].wins ); - msg.WriteBits( value, ASYNC_PLAYER_WINS_BITS ); - value = idMath::ClampInt( 0, MP_PLAYER_MAXPING, playerState[i].ping ); - msg.WriteBits( value, ASYNC_PLAYER_PING_BITS ); - msg.WriteBits( playerState[i].ingame, 1 ); - } - -#ifdef CTF - msg.WriteShort( teamPoints[0] ); - msg.WriteShort( teamPoints[1] ); - msg.WriteShort( player_red_flag ); - msg.WriteShort( player_blue_flag ); -#endif -} - -/* -================ -idMultiplayerGame::ReadFromSnapshot -================ -*/ -void idMultiplayerGame::ReadFromSnapshot( const idBitMsgDelta &msg ) { - int i; - gameState_t newState; - - newState = (idMultiplayerGame::gameState_t)msg.ReadByte(); - if ( newState != gameState ) { - gameLocal.DPrintf( "%s -> %s\n", GameStateStrings[ gameState ], GameStateStrings[ newState ] ); - gameState = newState; - // these could be gathered in a BGNewState() kind of thing, as we have to do them in NewState as well - if ( gameState == GAMEON ) { - matchStartedTime = gameLocal.time; - cvarSystem->SetCVarString( "ui_ready", "Not Ready" ); - switchThrottle[ 1 ] = 0; // passby the throttle - startFragLimit = gameLocal.serverInfo.GetInt( "si_fragLimit" ); - } - } - currentTourneyPlayer[ 0 ] = msg.ReadShort(); - currentTourneyPlayer[ 1 ] = msg.ReadShort(); - for ( i = 0; i < MAX_CLIENTS; i++ ) { - playerState[i].fragCount = msg.ReadBits( ASYNC_PLAYER_FRAG_BITS ); - playerState[i].teamFragCount = msg.ReadBits( ASYNC_PLAYER_FRAG_BITS ); - playerState[i].wins = msg.ReadBits( ASYNC_PLAYER_WINS_BITS ); - playerState[i].ping = msg.ReadBits( ASYNC_PLAYER_PING_BITS ); - playerState[i].ingame = msg.ReadBits( 1 ) != 0; - } - -#ifdef CTF - teamPoints[0] = msg.ReadShort(); - teamPoints[1] = msg.ReadShort(); - - player_red_flag = msg.ReadShort(); - player_blue_flag = msg.ReadShort(); - -#endif - -} - -/* -================ -idMultiplayerGame::PlayGlobalSound -================ -*/ -void idMultiplayerGame::PlayGlobalSound( int to, snd_evt_t evt, const char *shader ) { - const idSoundShader *shaderDecl; - - if ( to == -1 || to == gameLocal.localClientNum ) { - if ( shader ) { - if ( gameSoundWorld ) { - gameSoundWorld->PlayShaderDirectly( shader ); - } - } else { - if ( gameSoundWorld ) { - gameSoundWorld->PlayShaderDirectly( GlobalSoundStrings[ evt ] ); - } - } - } - - if ( !gameLocal.isClient ) { - idBitMsg outMsg; - byte msgBuf[1024]; - outMsg.Init( msgBuf, sizeof( msgBuf ) ); - - if ( shader ) { - shaderDecl = declManager->FindSound( shader ); - if ( !shaderDecl ) { - return; - } - outMsg.WriteByte( GAME_RELIABLE_MESSAGE_SOUND_INDEX ); - outMsg.WriteInt( gameLocal.ServerRemapDecl( to, DECL_SOUND, shaderDecl->Index() ) ); - } else { - outMsg.WriteByte( GAME_RELIABLE_MESSAGE_SOUND_EVENT ); - outMsg.WriteByte( evt ); - } - - networkSystem->ServerSendReliableMessage( to, outMsg ); - } -} - -#ifdef CTF -/* -================ -idMultiplayerGame::PlayTeamSound -================ -*/ -void idMultiplayerGame::PlayTeamSound( int toTeam, snd_evt_t evt, const char *shader ) { - for( int i = 0; i < gameLocal.numClients; i++ ) { - idEntity *ent = gameLocal.entities[ i ]; - if ( !ent || !ent->IsType( idPlayer::Type ) ) { - continue; - } - idPlayer * player = static_cast(ent); - if ( player->team != toTeam ) - continue; - PlayGlobalSound( i, evt, shader ); - } -} -#endif - -/* -================ -idMultiplayerGame::PrintMessageEvent -================ -*/ -void idMultiplayerGame::PrintMessageEvent( int to, msg_evt_t evt, int parm1, int parm2 ) { - switch ( evt ) { - case MSG_SUICIDE: - assert( parm1 >= 0 ); - AddChatLine( common->GetLanguageDict()->GetString( "#str_04293" ), gameLocal.userInfo[ parm1 ].GetString( "ui_name" ) ); - break; - case MSG_KILLED: - assert( parm1 >= 0 && parm2 >= 0 ); - AddChatLine( common->GetLanguageDict()->GetString( "#str_04292" ), gameLocal.userInfo[ parm1 ].GetString( "ui_name" ), gameLocal.userInfo[ parm2 ].GetString( "ui_name" ) ); - break; - case MSG_KILLEDTEAM: - assert( parm1 >= 0 && parm2 >= 0 ); - AddChatLine( common->GetLanguageDict()->GetString( "#str_04291" ), gameLocal.userInfo[ parm1 ].GetString( "ui_name" ), gameLocal.userInfo[ parm2 ].GetString( "ui_name" ) ); - break; - case MSG_TELEFRAGGED: - assert( parm1 >= 0 && parm2 >= 0 ); - AddChatLine( common->GetLanguageDict()->GetString( "#str_04290" ), gameLocal.userInfo[ parm1 ].GetString( "ui_name" ), gameLocal.userInfo[ parm2 ].GetString( "ui_name" ) ); - break; - case MSG_DIED: - assert( parm1 >= 0 ); - AddChatLine( common->GetLanguageDict()->GetString( "#str_04289" ), gameLocal.userInfo[ parm1 ].GetString( "ui_name" ) ); - break; - case MSG_VOTE: - AddChatLine( common->GetLanguageDict()->GetString( "#str_04288" ) ); - break; - case MSG_SUDDENDEATH: - AddChatLine( common->GetLanguageDict()->GetString( "#str_04287" ) ); - break; - case MSG_FORCEREADY: - AddChatLine( common->GetLanguageDict()->GetString( "#str_04286" ), gameLocal.userInfo[ parm1 ].GetString( "ui_name" ) ); - if ( gameLocal.entities[ parm1 ] && gameLocal.entities[ parm1 ]->IsType( idPlayer::Type ) ) { - static_cast< idPlayer * >( gameLocal.entities[ parm1 ] )->forcedReady = true; - } - break; - case MSG_JOINEDSPEC: - AddChatLine( common->GetLanguageDict()->GetString( "#str_04285" ), gameLocal.userInfo[ parm1 ].GetString( "ui_name" ) ); - break; - case MSG_TIMELIMIT: - AddChatLine( common->GetLanguageDict()->GetString( "#str_04284" ) ); - break; - case MSG_FRAGLIMIT: - if ( gameLocal.gameType == GAME_LASTMAN ) { - AddChatLine( common->GetLanguageDict()->GetString( "#str_04283" ), gameLocal.userInfo[ parm1 ].GetString( "ui_name" ) ); - } else if ( IsGametypeTeamBased() ) { /* CTF */ - AddChatLine( common->GetLanguageDict()->GetString( "#str_04282" ), gameLocal.userInfo[ parm1 ].GetString( "ui_team" ) ); - } else { - AddChatLine( common->GetLanguageDict()->GetString( "#str_04281" ), gameLocal.userInfo[ parm1 ].GetString( "ui_name" ) ); - } - break; - case MSG_JOINTEAM: - AddChatLine( common->GetLanguageDict()->GetString( "#str_04280" ), gameLocal.userInfo[ parm1 ].GetString( "ui_name" ), parm2 ? common->GetLanguageDict()->GetString( "#str_02500" ) : common->GetLanguageDict()->GetString( "#str_02499" ) ); - break; - case MSG_HOLYSHIT: - AddChatLine( common->GetLanguageDict()->GetString( "#str_06732" ) ); - break; -#ifdef CTF - case MSG_POINTLIMIT: - AddChatLine( common->GetLanguageDict()->GetString( "#str_11100" ), parm1 ? common->GetLanguageDict()->GetString( "#str_11110" ) : common->GetLanguageDict()->GetString( "#str_11111" ) ); - break; - - case MSG_FLAGTAKEN : - if ( gameLocal.GetLocalPlayer() == NULL ) - break; - - if ( parm2 < 0 || parm2 >= MAX_CLIENTS ) - break; - - if ( gameLocal.GetLocalPlayer()->team != parm1 ) { - AddChatLine( common->GetLanguageDict()->GetString( "#str_11101" ), gameLocal.userInfo[ parm2 ].GetString( "ui_name" ) ); // your team - } else { - AddChatLine( common->GetLanguageDict()->GetString( "#str_11102" ), gameLocal.userInfo[ parm2 ].GetString( "ui_name" ) ); // enemy - } - break; - - case MSG_FLAGDROP : - if ( gameLocal.GetLocalPlayer() == NULL ) - break; - - if ( gameLocal.GetLocalPlayer()->team != parm1 ) { - AddChatLine( common->GetLanguageDict()->GetString( "#str_11103" ) ); // your team - } else { - AddChatLine( common->GetLanguageDict()->GetString( "#str_11104" ) ); // enemy - } - break; - - case MSG_FLAGRETURN : - if ( gameLocal.GetLocalPlayer() == NULL ) - break; - - if ( parm2 >= 0 && parm2 < MAX_CLIENTS ) { - if ( gameLocal.GetLocalPlayer()->team != parm1 ) { - AddChatLine( common->GetLanguageDict()->GetString( "#str_11120" ), gameLocal.userInfo[ parm2 ].GetString( "ui_name" ) ); // your team - } else { - AddChatLine( common->GetLanguageDict()->GetString( "#str_11121" ), gameLocal.userInfo[ parm2 ].GetString( "ui_name" ) ); // enemy - } - } else { - AddChatLine( common->GetLanguageDict()->GetString( "#str_11105" ), parm1 ? common->GetLanguageDict()->GetString( "#str_11110" ) : common->GetLanguageDict()->GetString( "#str_11111" ) ); - } - break; - - case MSG_FLAGCAPTURE : - if ( gameLocal.GetLocalPlayer() == NULL ) - break; - - if ( parm2 < 0 || parm2 >= MAX_CLIENTS ) - break; - - if ( gameLocal.GetLocalPlayer()->team != parm1 ) { - AddChatLine( common->GetLanguageDict()->GetString( "#str_11122" ), gameLocal.userInfo[ parm2 ].GetString( "ui_name" ) ); // your team - } else { - AddChatLine( common->GetLanguageDict()->GetString( "#str_11123" ), gameLocal.userInfo[ parm2 ].GetString( "ui_name" ) ); // enemy - } - -// AddChatLine( common->GetLanguageDict()->GetString( "#str_11106" ), parm1 ? common->GetLanguageDict()->GetString( "#str_11110" ) : common->GetLanguageDict()->GetString( "#str_11111" ) ); - break; - - case MSG_SCOREUPDATE: - AddChatLine( common->GetLanguageDict()->GetString( "#str_11107" ), parm1, parm2 ); - break; -#endif - default: - gameLocal.DPrintf( "PrintMessageEvent: unknown message type %d\n", evt ); - return; - } - if ( !gameLocal.isClient ) { - idBitMsg outMsg; - byte msgBuf[1024]; - outMsg.Init( msgBuf, sizeof( msgBuf ) ); - outMsg.WriteByte( GAME_RELIABLE_MESSAGE_DB ); - outMsg.WriteByte( evt ); - outMsg.WriteByte( parm1 ); - outMsg.WriteByte( parm2 ); - networkSystem->ServerSendReliableMessage( to, outMsg ); - } -} - -/* -================ -idMultiplayerGame::SuddenRespawns -solely for LMN if an end game ( fragLimitTimeout ) was entered and aborted before expiration -LMN players which still have lives left need to be respawned without being marked lastManOver -================ -*/ -void idMultiplayerGame::SuddenRespawn( void ) { - int i; - - if ( gameLocal.gameType != GAME_LASTMAN ) { - return; - } - - for ( i = 0; i < gameLocal.numClients; i++ ) { - if ( !gameLocal.entities[ i ] || !gameLocal.entities[ i ]->IsType( idPlayer::Type ) ) { - continue; - } - if ( !CanPlay( static_cast< idPlayer * >( gameLocal.entities[ i ] ) ) ) { - continue; - } - if ( static_cast< idPlayer * >( gameLocal.entities[ i ] )->lastManOver ) { - continue; - } - static_cast< idPlayer * >( gameLocal.entities[ i ] )->lastManPlayAgain = true; - } -} - -/* -================ -idMultiplayerGame::CheckSpawns -================ -*/ -void idMultiplayerGame::CheckRespawns( idPlayer *spectator ) { - for( int i = 0 ; i < gameLocal.numClients ; i++ ) { - idEntity *ent = gameLocal.entities[ i ]; - if ( !ent || !ent->IsType( idPlayer::Type ) ) { - continue; - } - idPlayer *p = static_cast(ent); - // once we hit sudden death, nobody respawns till game has ended - if ( WantRespawn( p ) || p == spectator ) { - if ( gameState == SUDDENDEATH && gameLocal.gameType != GAME_LASTMAN ) { - // respawn rules while sudden death are different - // sudden death may trigger while a player is dead, so there are still cases where we need to respawn - // don't do any respawns while we are in end game delay though - if ( !fragLimitTimeout ) { - if ( IsGametypeTeamBased() || p->IsLeader() ) { /* CTF */ -#ifdef _DEBUG - if ( gameLocal.gameType == GAME_TOURNEY ) { - assert( p->entityNumber == currentTourneyPlayer[ 0 ] || p->entityNumber == currentTourneyPlayer[ 1 ] ); - } -#endif - p->ServerSpectate( false ); - } else if ( !p->IsLeader() ) { - // sudden death is rolling, this player is not a leader, have him spectate - p->ServerSpectate( true ); - CheckAbortGame(); - } - } - } else { - if ( gameLocal.gameType == GAME_DM || // CTF : 3wave sboily, was DM really included before? - IsGametypeTeamBased() ) - { - if ( gameState == WARMUP || gameState == COUNTDOWN || gameState == GAMEON ) { - p->ServerSpectate( false ); - } - } else if ( gameLocal.gameType == GAME_TOURNEY ) { - if ( i == currentTourneyPlayer[ 0 ] || i == currentTourneyPlayer[ 1 ] ) { - if ( gameState == WARMUP || gameState == COUNTDOWN || gameState == GAMEON ) { - p->ServerSpectate( false ); - } - } else if ( gameState == WARMUP ) { - // make sure empty tourney slots get filled first - FillTourneySlots( ); - if ( i == currentTourneyPlayer[ 0 ] || i == currentTourneyPlayer[ 1 ] ) { - p->ServerSpectate( false ); - } - } - } else if ( gameLocal.gameType == GAME_LASTMAN ) { - if ( gameState == WARMUP || gameState == COUNTDOWN ) { - p->ServerSpectate( false ); - } else if ( gameState == GAMEON || gameState == SUDDENDEATH ) { - if ( gameState == GAMEON && playerState[ i ].fragCount > 0 && p->lastManPresent ) { - assert( !p->lastManOver ); - p->ServerSpectate( false ); - } else if ( p->lastManPlayAgain && p->lastManPresent ) { - assert( gameState == SUDDENDEATH ); - p->ServerSpectate( false ); - } else { - // if a fragLimitTimeout was engaged, do NOT mark lastManOver as that could mean - // everyone ends up spectator and game is stalled with no end - // if the frag limit delay is engaged and cancels out before expiring, LMN players are - // respawned to play the tie again ( through SuddenRespawn and lastManPlayAgain ) - if ( !fragLimitTimeout && !p->lastManOver ) { - common->DPrintf( "client %d has lost all last man lives\n", i ); - // end of the game for this guy, send him to spectators - p->lastManOver = true; - // clients don't have access to lastManOver - // so set the fragCount to something silly ( used in scoreboard and player ranking ) - playerState[ i ].fragCount = LASTMAN_NOLIVES; - p->ServerSpectate( true ); - - //Check for a situation where the last two player dies at the same time and don't - //try to respawn manually...This was causing all players to go into spectate mode - //and the server got stuck - { - int j; - for ( j = 0; j < gameLocal.numClients; j++ ) { - if ( !gameLocal.entities[ j ] ) { - continue; - } - if ( !CanPlay( static_cast< idPlayer * >( gameLocal.entities[ j ] ) ) ) { - continue; - } - if ( !static_cast< idPlayer * >( gameLocal.entities[ j ] )->lastManOver ) { - break; - } - } - if( j == gameLocal.numClients) { - //Everyone is dead so don't allow this player to spectate - //so the match will end - p->ServerSpectate( false ); - } - } - } - } - } - } - } - } else if ( p->wantSpectate && !p->spectating ) { - playerState[ i ].fragCount = 0; // whenever you willingly go spectate during game, your score resets - p->ServerSpectate( true ); - UpdateTourneyLine(); - CheckAbortGame(); - } - } -} - -/* -================ -idMultiplayerGame::ForceReady -================ -*/ -void idMultiplayerGame::ForceReady( ) { - - for( int i = 0 ; i < gameLocal.numClients ; i++ ) { - idEntity *ent = gameLocal.entities[ i ]; - if ( !ent || !ent->IsType( idPlayer::Type ) ) { - continue; - } - idPlayer *p = static_cast( ent ); - if ( !p->IsReady() ) { - PrintMessageEvent( -1, MSG_FORCEREADY, i ); - p->forcedReady = true; - } - } -} - -/* -================ -idMultiplayerGame::ForceReady_f -================ -*/ -void idMultiplayerGame::ForceReady_f( const idCmdArgs &args ) { - if ( !gameLocal.isMultiplayer || gameLocal.isClient ) { - common->Printf( "forceReady: multiplayer server only\n" ); - return; - } - gameLocal.mpGame.ForceReady(); -} - -/* -================ -idMultiplayerGame::DropWeapon -================ -*/ -void idMultiplayerGame::DropWeapon( int clientNum ) { - assert( !gameLocal.isClient ); - idEntity *ent = gameLocal.entities[ clientNum ]; - if ( !ent || !ent->IsType( idPlayer::Type ) ) { - return; - } - static_cast< idPlayer* >( ent )->DropWeapon( false ); -} - -/* -================ -idMultiplayerGame::DropWeapon_f -================ -*/ -void idMultiplayerGame::DropWeapon_f( const idCmdArgs &args ) { - if ( !gameLocal.isMultiplayer ) { - common->Printf( "clientDropWeapon: only valid in multiplayer\n" ); - return; - } - idBitMsg outMsg; - byte msgBuf[128]; - outMsg.Init( msgBuf, sizeof( msgBuf ) ); - outMsg.WriteByte( GAME_RELIABLE_MESSAGE_DROPWEAPON ); - networkSystem->ClientSendReliableMessage( outMsg ); -} - -/* -================ -idMultiplayerGame::MessageMode_f -================ -*/ -void idMultiplayerGame::MessageMode_f( const idCmdArgs &args ) { - gameLocal.mpGame.MessageMode( args ); -} - -/* -================ -idMultiplayerGame::MessageMode -================ -*/ -void idMultiplayerGame::MessageMode( const idCmdArgs &args ) { - const char *mode; - int imode; - - if ( !gameLocal.isMultiplayer ) { - common->Printf( "clientMessageMode: only valid in multiplayer\n" ); - return; - } - if ( !mainGui ) { - common->Printf( "no local client\n" ); - return; - } - mode = args.Argv( 1 ); - if ( !mode[ 0 ] ) { - imode = 0; - } else { - imode = atoi( mode ); - } - msgmodeGui->SetStateString( "messagemode", imode ? "1" : "0" ); - msgmodeGui->SetStateString( "chattext", "" ); - nextMenu = 2; - // let the session know that we want our ingame main menu opened - gameLocal.sessionCommand = "game_startmenu"; -} - -/* -================ -idMultiplayerGame::Vote_f -FIXME: voting from console -================ -*/ -void idMultiplayerGame::Vote_f( const idCmdArgs &args ) { } - -/* -================ -idMultiplayerGame::CallVote_f -FIXME: voting from console -================ -*/ -void idMultiplayerGame::CallVote_f( const idCmdArgs &args ) { } - -/* -================ -idMultiplayerGame::ServerStartVote -================ -*/ -void idMultiplayerGame::ServerStartVote( int clientNum, vote_flags_t voteIndex, const char *value ) { - int i; - - assert( vote == VOTE_NONE ); - - // setup - yesVotes = 1; - noVotes = 0; - vote = voteIndex; - voteValue = value; - voteTimeOut = gameLocal.time + 20000; - // mark players allowed to vote - only current ingame players, players joining during vote will be ignored - for ( i = 0; i < gameLocal.numClients; i++ ) { - if ( gameLocal.entities[ i ] && gameLocal.entities[ i ]->IsType( idPlayer::Type ) ) { - playerState[ i ].vote = ( i == clientNum ) ? PLAYER_VOTE_YES : PLAYER_VOTE_WAIT; - } else { - playerState[i].vote = PLAYER_VOTE_NONE; - } - } -} - -/* -================ -idMultiplayerGame::ClientStartVote -================ -*/ -void idMultiplayerGame::ClientStartVote( int clientNum, const char *_voteString ) { - idBitMsg outMsg; - byte msgBuf[ MAX_GAME_MESSAGE_SIZE ]; - - if ( !gameLocal.isClient ) { - outMsg.Init( msgBuf, sizeof( msgBuf ) ); - outMsg.WriteByte( GAME_RELIABLE_MESSAGE_STARTVOTE ); - outMsg.WriteByte( clientNum ); - outMsg.WriteString( _voteString ); - networkSystem->ServerSendReliableMessage( -1, outMsg ); - } - - voteString = _voteString; - AddChatLine( va( common->GetLanguageDict()->GetString( "#str_04279" ), gameLocal.userInfo[ clientNum ].GetString( "ui_name" ) ) ); - gameSoundWorld->PlayShaderDirectly( GlobalSoundStrings[ SND_VOTE ] ); - if ( clientNum == gameLocal.localClientNum ) { - voted = true; - } else { - voted = false; - } - if ( gameLocal.isClient ) { - // the the vote value to something so the vote line is displayed - vote = VOTE_RESTART; - yesVotes = 1; - noVotes = 0; - } -} - -/* -================ -idMultiplayerGame::ClientUpdateVote -================ -*/ -void idMultiplayerGame::ClientUpdateVote( vote_result_t status, int yesCount, int noCount ) { - idBitMsg outMsg; - byte msgBuf[ MAX_GAME_MESSAGE_SIZE ]; - - if ( !gameLocal.isClient ) { - outMsg.Init( msgBuf, sizeof( msgBuf ) ); - outMsg.WriteByte( GAME_RELIABLE_MESSAGE_UPDATEVOTE ); - outMsg.WriteByte( status ); - outMsg.WriteByte( yesCount ); - outMsg.WriteByte( noCount ); - networkSystem->ServerSendReliableMessage( -1, outMsg ); - } - - if ( vote == VOTE_NONE ) { - // clients coming in late don't get the vote start and are not allowed to vote - return; - } - - switch ( status ) { - case VOTE_FAILED: - AddChatLine( common->GetLanguageDict()->GetString( "#str_04278" ) ); - gameSoundWorld->PlayShaderDirectly( GlobalSoundStrings[ SND_VOTE_FAILED ] ); - if ( gameLocal.isClient ) { - vote = VOTE_NONE; - } - break; - case VOTE_PASSED: - AddChatLine( common->GetLanguageDict()->GetString( "#str_04277" ) ); - gameSoundWorld->PlayShaderDirectly( GlobalSoundStrings[ SND_VOTE_PASSED ] ); - break; - case VOTE_RESET: - if ( gameLocal.isClient ) { - vote = VOTE_NONE; - } - break; - case VOTE_ABORTED: - AddChatLine( common->GetLanguageDict()->GetString( "#str_04276" ) ); - if ( gameLocal.isClient ) { - vote = VOTE_NONE; - } - break; - default: - break; - } - if ( gameLocal.isClient ) { - yesVotes = yesCount; - noVotes = noCount; - } -} - -/* -================ -idMultiplayerGame::ClientCallVote -================ -*/ -void idMultiplayerGame::ClientCallVote( vote_flags_t voteIndex, const char *voteValue ) { - idBitMsg outMsg; - byte msgBuf[ MAX_GAME_MESSAGE_SIZE ]; - - // send - outMsg.Init( msgBuf, sizeof( msgBuf ) ); - outMsg.WriteByte( GAME_RELIABLE_MESSAGE_CALLVOTE ); - outMsg.WriteByte( voteIndex ); - outMsg.WriteString( voteValue ); - networkSystem->ClientSendReliableMessage( outMsg ); -} - -/* -================ -idMultiplayerGame::CastVote -================ -*/ -void idMultiplayerGame::CastVote( int clientNum, bool castVote ) { - idBitMsg outMsg; - byte msgBuf[ 128 ]; - - if ( clientNum == gameLocal.localClientNum ) { - voted = true; - } - - if ( gameLocal.isClient ) { - outMsg.Init( msgBuf, sizeof( msgBuf ) ); - outMsg.WriteByte( GAME_RELIABLE_MESSAGE_CASTVOTE ); - outMsg.WriteByte( castVote ); - networkSystem->ClientSendReliableMessage( outMsg ); - return; - } - - // sanity - if ( vote == VOTE_NONE ) { - gameLocal.ServerSendChatMessage( clientNum, "server", common->GetLanguageDict()->GetString( "#str_04275" ) ); - common->DPrintf( "client %d: cast vote while no vote in progress\n", clientNum ); - return; - } - if ( playerState[ clientNum ].vote != PLAYER_VOTE_WAIT ) { - gameLocal.ServerSendChatMessage( clientNum, "server", common->GetLanguageDict()->GetString( "#str_04274" ) ); - common->DPrintf( "client %d: cast vote - vote %d != PLAYER_VOTE_WAIT\n", clientNum, playerState[ clientNum ].vote ); - return; - } - - if ( castVote ) { - playerState[ clientNum ].vote = PLAYER_VOTE_YES; - yesVotes++; - } else { - playerState[ clientNum ].vote = PLAYER_VOTE_NO; - noVotes++; - } - - ClientUpdateVote( VOTE_UPDATE, yesVotes, noVotes ); -} - -/* -================ -idMultiplayerGame::ServerCallVote -================ -*/ -void idMultiplayerGame::ServerCallVote( int clientNum, const idBitMsg &msg ) { - vote_flags_t voteIndex; - int vote_timeLimit, vote_fragLimit, vote_clientNum, vote_gameTypeIndex; //, vote_kickIndex; - char value[ MAX_STRING_CHARS ]; - - assert( clientNum != -1 ); - assert( !gameLocal.isClient ); - - voteIndex = (vote_flags_t)msg.ReadByte( ); - msg.ReadString( value, sizeof( value ) ); - - // sanity checks - setup the vote - if ( vote != VOTE_NONE ) { - gameLocal.ServerSendChatMessage( clientNum, "server", common->GetLanguageDict()->GetString( "#str_04273" ) ); - common->DPrintf( "client %d: called vote while voting already in progress - ignored\n", clientNum ); - return; - } - switch ( voteIndex ) { - case VOTE_RESTART: - ServerStartVote( clientNum, voteIndex, "" ); - ClientStartVote( clientNum, common->GetLanguageDict()->GetString( "#str_04271" ) ); - break; - case VOTE_NEXTMAP: - ServerStartVote( clientNum, voteIndex, "" ); - ClientStartVote( clientNum, common->GetLanguageDict()->GetString( "#str_04272" ) ); - break; - case VOTE_TIMELIMIT: - vote_timeLimit = strtol( value, NULL, 10 ); - if ( vote_timeLimit == gameLocal.serverInfo.GetInt( "si_timeLimit" ) ) { - gameLocal.ServerSendChatMessage( clientNum, "server", common->GetLanguageDict()->GetString( "#str_04270" ) ); - common->DPrintf( "client %d: already at the voted Time Limit\n", clientNum ); - return; - } - if ( vote_timeLimit < si_timeLimit.GetMinValue() || vote_timeLimit > si_timeLimit.GetMaxValue() ) { - gameLocal.ServerSendChatMessage( clientNum, "server", common->GetLanguageDict()->GetString( "#str_04269" ) ); - common->DPrintf( "client %d: timelimit value out of range for vote: %s\n", clientNum, value ); - return; - } - ServerStartVote( clientNum, voteIndex, value ); - ClientStartVote( clientNum, va( common->GetLanguageDict()->GetString( "#str_04268" ), vote_timeLimit ) ); - break; - case VOTE_FRAGLIMIT: - vote_fragLimit = strtol( value, NULL, 10 ); - if ( vote_fragLimit == gameLocal.serverInfo.GetInt( "si_fragLimit" ) ) { - gameLocal.ServerSendChatMessage( clientNum, "server", common->GetLanguageDict()->GetString( "#str_04267" ) ); - common->DPrintf( "client %d: already at the voted Frag Limit\n", clientNum ); - return; - } - if ( vote_fragLimit < si_fragLimit.GetMinValue() || vote_fragLimit > si_fragLimit.GetMaxValue() ) { - gameLocal.ServerSendChatMessage( clientNum, "server", common->GetLanguageDict()->GetString( "#str_04266" ) ); - common->DPrintf( "client %d: fraglimit value out of range for vote: %s\n", clientNum, value ); - return; - } - ServerStartVote( clientNum, voteIndex, value ); - ClientStartVote( clientNum, va( common->GetLanguageDict()->GetString( "#str_04303" ), gameLocal.gameType == GAME_LASTMAN ? common->GetLanguageDict()->GetString( "#str_04264" ) : common->GetLanguageDict()->GetString( "#str_04265" ), vote_fragLimit ) ); - break; - case VOTE_GAMETYPE: - vote_gameTypeIndex = strtol( value, NULL, 10 ); -#ifdef CTF - assert( vote_gameTypeIndex > 0 && vote_gameTypeIndex < GAME_COUNT ); - strcpy( value, si_gameTypeArgs[ vote_gameTypeIndex ] ); -#endif - -/*#ifdef CTF - assert( vote_gameTypeIndex >= 0 && vote_gameTypeIndex <= 4 ); -#else - assert( vote_gameTypeIndex >= 0 && vote_gameTypeIndex <= 3 ); -#endif - switch ( vote_gameTypeIndex ) { - case 0: - strcpy( value, "Deathmatch" ); - break; - case 1: - strcpy( value, "Tourney" ); - break; - case 2: - strcpy( value, "Team DM" ); - break; - case 3: - strcpy( value, "Last Man" ); - break; -#ifdef CTF - case 4: - strcpy( value, "CTF" ); - break; -#endif - }*/ - if ( !idStr::Icmp( value, gameLocal.serverInfo.GetString( "si_gameType" ) ) ) { - gameLocal.ServerSendChatMessage( clientNum, "server", common->GetLanguageDict()->GetString( "#str_04259" ) ); - common->DPrintf( "client %d: already at the voted Game Type\n", clientNum ); - return; - } - ServerStartVote( clientNum, voteIndex, value ); - ClientStartVote( clientNum, va( common->GetLanguageDict()->GetString( "#str_04258" ), value ) ); - break; - case VOTE_KICK: - vote_clientNum = strtol( value, NULL, 10 ); - if ( vote_clientNum == gameLocal.localClientNum ) { - gameLocal.ServerSendChatMessage( clientNum, "server", common->GetLanguageDict()->GetString( "#str_04257" ) ); - common->DPrintf( "client %d: called kick for the server host\n", clientNum ); - return; - } - ServerStartVote( clientNum, voteIndex, va( "%d", vote_clientNum ) ); - ClientStartVote( clientNum, va( common->GetLanguageDict()->GetString( "#str_04302" ), vote_clientNum, gameLocal.userInfo[ vote_clientNum ].GetString( "ui_name" ) ) ); - break; - case VOTE_MAP: { - if ( idStr::FindText( gameLocal.serverInfo.GetString( "si_map" ), value ) != -1 ) { - gameLocal.ServerSendChatMessage( clientNum, "server", va( common->GetLanguageDict()->GetString( "#str_04295" ), value ) ); - common->DPrintf( "client %d: already running the voted map: %s\n", clientNum, value ); - return; - } - int num = fileSystem->GetNumMaps(); - int i; - const idDict *dict; - bool haveMap = false; - for ( i = 0; i < num; i++ ) { - dict = fileSystem->GetMapDecl( i ); - if ( dict && !idStr::Icmp( dict->GetString( "path" ), value ) ) { - haveMap = true; - break; - } - } - if ( !haveMap ) { - gameLocal.ServerSendChatMessage( clientNum, "server", va( common->GetLanguageDict()->GetString( "#str_04296" ), value ) ); - common->Printf( "client %d: map not found: %s\n", clientNum, value ); - return; - } - ServerStartVote( clientNum, voteIndex, value ); - ClientStartVote( clientNum, va( common->GetLanguageDict()->GetString( "#str_04256" ), common->GetLanguageDict()->GetString( dict ? dict->GetString( "name" ) : value ) ) ); - break; - } - case VOTE_SPECTATORS: - if ( gameLocal.serverInfo.GetBool( "si_spectators" ) ) { - ServerStartVote( clientNum, voteIndex, "" ); - ClientStartVote( clientNum, common->GetLanguageDict()->GetString( "#str_04255" ) ); - } else { - ServerStartVote( clientNum, voteIndex, "" ); - ClientStartVote( clientNum, common->GetLanguageDict()->GetString( "#str_04254" ) ); - } - break; - default: - gameLocal.ServerSendChatMessage( clientNum, "server", va( common->GetLanguageDict()->GetString( "#str_04297" ), (int)voteIndex ) ); - common->DPrintf( "client %d: unknown vote index %d\n", clientNum, voteIndex ); - } -} - -/* -================ -idMultiplayerGame::DisconnectClient -================ -*/ -void idMultiplayerGame::DisconnectClient( int clientNum ) { - if ( lastWinner == clientNum ) { - lastWinner = -1; - } - UpdatePlayerRanks(); - CheckAbortGame(); -} - -/* -================ -idMultiplayerGame::CheckAbortGame -================ -*/ -void idMultiplayerGame::CheckAbortGame( void ) { - int i; - if ( gameLocal.gameType == GAME_TOURNEY && gameState == WARMUP ) { - // if a tourney player joined spectators, let someone else have his spot - for ( i = 0; i < 2; i++ ) { - if ( !gameLocal.entities[ currentTourneyPlayer[ i ] ] || static_cast< idPlayer * >( gameLocal.entities[ currentTourneyPlayer[ i ] ] )->spectating ) { - currentTourneyPlayer[ i ] = -1; - } - } - } - // only checks for aborts -> game review below - if ( gameState != COUNTDOWN && gameState != GAMEON && gameState != SUDDENDEATH ) { - return; - } - switch ( gameLocal.gameType ) { - case GAME_TOURNEY: - for ( i = 0; i < 2; i++ ) { - if ( !gameLocal.entities[ currentTourneyPlayer[ i ] ] || static_cast< idPlayer * >( gameLocal.entities[ currentTourneyPlayer[ i ] ] )->spectating ) { - NewState( GAMEREVIEW ); - return; - } - } - break; - default: - if ( !EnoughClientsToPlay() ) { - NewState( GAMEREVIEW ); - } - break; - } -} - -/* -================ -idMultiplayerGame::WantKilled -================ -*/ -void idMultiplayerGame::WantKilled( int clientNum ) { - idEntity *ent = gameLocal.entities[ clientNum ]; - if ( ent && ent->IsType( idPlayer::Type ) ) { - static_cast( ent )->Kill( false, false ); - } -} - -/* -================ -idMultiplayerGame::MapRestart -================ -*/ -void idMultiplayerGame::MapRestart( void ) { - int clientNum; - - assert( !gameLocal.isClient ); - if ( gameState != WARMUP ) { - NewState( WARMUP ); - nextState = INACTIVE; - nextStateSwitch = 0; - } - -#ifdef CTF - teamPoints[0] = 0; - teamPoints[1] = 0; - - ClearHUDStatus(); -#endif - -#ifdef CTF - // still balance teams in CTF - if ( g_balanceTDM.GetBool() && lastGameType != GAME_TDM && lastGameType != GAME_CTF && gameLocal.mpGame.IsGametypeTeamBased() ) { -#else - if ( g_balanceTDM.GetBool() && lastGameType != GAME_TDM && gameLocal.gameType == GAME_TDM ) { -#endif - for ( clientNum = 0; clientNum < gameLocal.numClients; clientNum++ ) { - if ( gameLocal.entities[ clientNum ] && gameLocal.entities[ clientNum ]->IsType( idPlayer::Type ) ) { - if ( static_cast< idPlayer* >( gameLocal.entities[ clientNum ] )->BalanceTDM() ) { - // core is in charge of syncing down userinfo changes - // it will also call back game through SetUserInfo with the current info for update - cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "updateUI %d\n", clientNum ) ); - } - } - } - } - lastGameType = gameLocal.gameType; -} - -/* -================ -idMultiplayerGame::SwitchToTeam -================ -*/ -void idMultiplayerGame::SwitchToTeam( int clientNum, int oldteam, int newteam ) { - idEntity *ent; - int i; - - assert( IsGametypeTeamBased() ); /* CTF */ - assert( oldteam != newteam ); - assert( !gameLocal.isClient ); - - if ( !gameLocal.isClient && newteam >= 0 && IsInGame( clientNum ) ) { - PrintMessageEvent( -1, MSG_JOINTEAM, clientNum, newteam ); - } - // assign the right teamFragCount - for( i = 0; i < gameLocal.numClients; i++ ) { - if ( i == clientNum ) { - continue; - } - ent = gameLocal.entities[ i ]; - if ( ent && ent->IsType( idPlayer::Type ) && static_cast< idPlayer * >(ent)->team == newteam ) { - playerState[ clientNum ].teamFragCount = playerState[ i ].teamFragCount; - break; - } - } - if ( i == gameLocal.numClients ) { - // alone on this team - playerState[ clientNum ].teamFragCount = 0; - - } -#ifdef CTF - if ( ( gameState == GAMEON || ( IsGametypeFlagBased() && gameState == SUDDENDEATH ) ) && oldteam != -1 ) { -#else - if ( gameState == GAMEON && oldteam != -1 ) { -#endif - // when changing teams during game, kill and respawn - idPlayer *p = static_cast( gameLocal.entities[ clientNum ] ); - if ( p->IsInTeleport() ) { - p->ServerSendEvent( idPlayer::EVENT_ABORT_TELEPORTER, NULL, false, -1 ); - p->SetPrivateCameraView( NULL ); - } - p->Kill( true, true ); -#ifdef CTF - if ( IsGametypeFlagBased() ) - p->DropFlag(); -#endif - CheckAbortGame(); - } -#ifdef CTF - else if ( IsGametypeFlagBased() && oldteam != -1 ) { - idPlayer *p = static_cast( gameLocal.entities[ clientNum ] ); - p->DropFlag(); - } -#endif -} - -/* -================ -idMultiplayerGame::ProcessChatMessage -================ -*/ -void idMultiplayerGame::ProcessChatMessage( int clientNum, bool team, const char *name, const char *text, const char *sound ) { - idBitMsg outMsg; - byte msgBuf[ 256 ]; - const char *prefix = NULL; - int send_to; // 0 - all, 1 - specs, 2 - team - int i; - idEntity *ent; - idPlayer *p; - idStr prefixed_name; - - assert( !gameLocal.isClient ); - - if ( clientNum >= 0 ) { - p = static_cast< idPlayer * >( gameLocal.entities[ clientNum ] ); - if ( !( p && p->IsType( idPlayer::Type ) ) ) { - return; - } - - if ( p->spectating ) { - prefix = "spectating"; - if ( team || ( !g_spectatorChat.GetBool() && ( gameState == GAMEON || gameState == SUDDENDEATH ) ) ) { - // to specs - send_to = 1; - } else { - // to all - send_to = 0; - } - } else if ( team ) { - prefix = "team"; - // to team - send_to = 2; - } else { - // to all - send_to = 0; - } - } else { - p = NULL; - send_to = 0; - } - // put the message together - outMsg.Init( msgBuf, sizeof( msgBuf ) ); - outMsg.WriteByte( GAME_RELIABLE_MESSAGE_CHAT ); - if ( prefix ) { - prefixed_name = va( "(%s) %s", prefix, name ); - } else { - prefixed_name = name; - } - outMsg.WriteString( prefixed_name ); - outMsg.WriteString( text, -1, false ); - if ( !send_to ) { - AddChatLine( "%s^0: %s\n", prefixed_name.c_str(), text ); - networkSystem->ServerSendReliableMessage( -1, outMsg ); - if ( sound ) { - PlayGlobalSound( -1, SND_COUNT, sound ); - } - } else { - for ( i = 0; i < gameLocal.numClients; i++ ) { - ent = gameLocal.entities[ i ]; - if ( !ent || !ent->IsType( idPlayer::Type ) ) { - continue; - } - if ( send_to == 1 && static_cast< idPlayer * >( ent )->spectating ) { - if ( sound ) { - PlayGlobalSound( i, SND_COUNT, sound ); - } - if ( i == gameLocal.localClientNum ) { - AddChatLine( "%s^0: %s\n", prefixed_name.c_str(), text ); - } else { - networkSystem->ServerSendReliableMessage( i, outMsg ); - } - } else if ( send_to == 2 && static_cast< idPlayer * >( ent )->team == p->team ) { - if ( sound ) { - PlayGlobalSound( i, SND_COUNT, sound ); - } - if ( i == gameLocal.localClientNum ) { - AddChatLine( "%s^0: %s\n", prefixed_name.c_str(), text ); - } else { - networkSystem->ServerSendReliableMessage( i, outMsg ); - } - } - } - } -} - -/* -================ -idMultiplayerGame::Precache -================ -*/ -void idMultiplayerGame::Precache( void ) { - int i; - idFile *f; - - if ( !gameLocal.isMultiplayer ) { - return; - } - gameLocal.FindEntityDefDict( "player_doommarine", false );; - - // skins - idStr str = cvarSystem->GetCVarString( "mod_validSkins" ); - idStr skin; - while ( str.Length() ) { - int n = str.Find( ";" ); - if ( n >= 0 ) { - skin = str.Left( n ); - str = str.Right( str.Length() - n - 1 ); - } else { - skin = str; - str = ""; - } - declManager->FindSkin( skin, false ); - } - - for ( i = 0; ui_skinArgs[ i ]; i++ ) { - declManager->FindSkin( ui_skinArgs[ i ], false ); - } - // MP game sounds - for ( i = 0; i < SND_COUNT; i++ ) { - f = fileSystem->OpenFileRead( GlobalSoundStrings[ i ] ); - fileSystem->CloseFile( f ); - } - // MP guis. just make sure we hit all of them - i = 0; - while ( MPGuis[ i ] ) { - uiManager->FindGui( MPGuis[ i ], true ); - i++; - } -} - -/* -================ -idMultiplayerGame::ToggleSpectate -================ -*/ -void idMultiplayerGame::ToggleSpectate( void ) { - bool spectating; - assert( gameLocal.isClient || gameLocal.localClientNum == 0 ); - - spectating = ( idStr::Icmp( cvarSystem->GetCVarString( "ui_spectate" ), "Spectate" ) == 0 ); - if ( spectating ) { - // always allow toggling to play - cvarSystem->SetCVarString( "ui_spectate", "Play" ); - } else { - // only allow toggling to spectate if spectators are enabled. - if ( gameLocal.serverInfo.GetBool( "si_spectators" ) ) { - cvarSystem->SetCVarString( "ui_spectate", "Spectate" ); - } else { - gameLocal.mpGame.AddChatLine( common->GetLanguageDict()->GetString( "#str_06747" ) ); - } - } -} - -/* -================ -idMultiplayerGame::ToggleReady -================ -*/ -void idMultiplayerGame::ToggleReady( void ) { - bool ready; - assert( gameLocal.isClient || gameLocal.localClientNum == 0 ); - - ready = ( idStr::Icmp( cvarSystem->GetCVarString( "ui_ready" ), "Ready" ) == 0 ); - if ( ready ) { - cvarSystem->SetCVarString( "ui_ready", "Not Ready" ); - } else { - cvarSystem->SetCVarString( "ui_ready", "Ready" ); - } -} - -/* -================ -idMultiplayerGame::ToggleTeam -================ -*/ -void idMultiplayerGame::ToggleTeam( void ) { - bool team; - assert( gameLocal.isClient || gameLocal.localClientNum == 0 ); - - team = ( idStr::Icmp( cvarSystem->GetCVarString( "ui_team" ), "Red" ) == 0 ); - if ( team ) { - cvarSystem->SetCVarString( "ui_team", "Blue" ); - } else { - cvarSystem->SetCVarString( "ui_team", "Red" ); - } -} - -/* -================ -idMultiplayerGame::ToggleUserInfo -================ -*/ -void idMultiplayerGame::ThrottleUserInfo( void ) { - int i; - - assert( gameLocal.localClientNum >= 0 ); - - i = 0; - while ( ThrottleVars[ i ] ) { - if ( idStr::Icmp( gameLocal.userInfo[ gameLocal.localClientNum ].GetString( ThrottleVars[ i ] ), - cvarSystem->GetCVarString( ThrottleVars[ i ] ) ) ) { - if ( gameLocal.realClientTime < switchThrottle[ i ] ) { - AddChatLine( common->GetLanguageDict()->GetString( "#str_04299" ), common->GetLanguageDict()->GetString( ThrottleVarsInEnglish[ i ] ), ( switchThrottle[ i ] - gameLocal.time ) / 1000 + 1 ); - cvarSystem->SetCVarString( ThrottleVars[ i ], gameLocal.userInfo[ gameLocal.localClientNum ].GetString( ThrottleVars[ i ] ) ); - } else { - switchThrottle[ i ] = gameLocal.time + ThrottleDelay[ i ] * 1000; - } - } - i++; - } -} - -/* -================ -idMultiplayerGame::CanPlay -================ -*/ -bool idMultiplayerGame::CanPlay( idPlayer *p ) { - return !p->wantSpectate && playerState[ p->entityNumber ].ingame; -} - -/* -================ -idMultiplayerGame::EnterGame -================ -*/ -void idMultiplayerGame::EnterGame( int clientNum ) { - assert( !gameLocal.isClient ); - - if ( !playerState[ clientNum ].ingame ) { - playerState[ clientNum ].ingame = true; - if ( gameLocal.isMultiplayer ) { - // can't use PrintMessageEvent as clients don't know the nickname yet - gameLocal.ServerSendChatMessage( -1, common->GetLanguageDict()->GetString( "#str_02047" ), va( common->GetLanguageDict()->GetString( "#str_07177" ), gameLocal.userInfo[ clientNum ].GetString( "ui_name" ) ) ); - } - } -} - -/* -================ -idMultiplayerGame::WantRespawn -================ -*/ -bool idMultiplayerGame::WantRespawn( idPlayer *p ) { - return p->forceRespawn && !p->wantSpectate && playerState[ p->entityNumber ].ingame; -} - -/* -================ -idMultiplayerGame::VoiceChat -================ -*/ -void idMultiplayerGame::VoiceChat_f( const idCmdArgs &args ) { - gameLocal.mpGame.VoiceChat( args, false ); -} - -/* -================ -idMultiplayerGame::VoiceChatTeam -================ -*/ -void idMultiplayerGame::VoiceChatTeam_f( const idCmdArgs &args ) { - gameLocal.mpGame.VoiceChat( args, true ); -} - -/* -================ -idMultiplayerGame::VoiceChat -================ -*/ -void idMultiplayerGame::VoiceChat( const idCmdArgs &args, bool team ) { - idBitMsg outMsg; - byte msgBuf[128]; - const char *voc; - const idDict *spawnArgs; - const idKeyValue *keyval; - int index; - - if ( !gameLocal.isMultiplayer ) { - common->Printf( "clientVoiceChat: only valid in multiplayer\n" ); - return; - } - if ( args.Argc() != 2 ) { - common->Printf( "clientVoiceChat: bad args\n" ); - return; - } - // throttle - if ( gameLocal.realClientTime < voiceChatThrottle ) { - return; - } - - voc = args.Argv( 1 ); - spawnArgs = gameLocal.FindEntityDefDict( "player_doommarine", false ); - keyval = spawnArgs->MatchPrefix( "snd_voc_", NULL ); - index = 0; - while ( keyval ) { - if ( !keyval->GetValue().Icmp( voc ) ) { - break; - } - keyval = spawnArgs->MatchPrefix( "snd_voc_", keyval ); - index++; - } - if ( !keyval ) { - common->Printf( "Voice command not found: %s\n", voc ); - return; - } - voiceChatThrottle = gameLocal.realClientTime + 1000; - - outMsg.Init( msgBuf, sizeof( msgBuf ) ); - outMsg.WriteByte( GAME_RELIABLE_MESSAGE_VCHAT ); - outMsg.WriteInt( index ); - outMsg.WriteBits( team ? 1 : 0, 1 ); - networkSystem->ClientSendReliableMessage( outMsg ); -} - -/* -================ -idMultiplayerGame::ProcessVoiceChat -================ -*/ -void idMultiplayerGame::ProcessVoiceChat( int clientNum, bool team, int index ) { - const idDict *spawnArgs; - const idKeyValue *keyval; - idStr name; - idStr snd_key; - idStr text_key; - idPlayer *p; - - p = static_cast< idPlayer * >( gameLocal.entities[ clientNum ] ); - if ( !( p && p->IsType( idPlayer::Type ) ) ) { - return; - } - - if ( p->spectating ) { - return; - } - - // lookup the sound def - spawnArgs = gameLocal.FindEntityDefDict( "player_doommarine", false ); - keyval = spawnArgs->MatchPrefix( "snd_voc_", NULL ); - while ( index > 0 && keyval ) { - keyval = spawnArgs->MatchPrefix( "snd_voc_", keyval ); - index--; - } - if ( !keyval ) { - common->DPrintf( "ProcessVoiceChat: unknown chat index %d\n", index ); - return; - } - snd_key = keyval->GetKey(); - name = gameLocal.userInfo[ clientNum ].GetString( "ui_name" ); - sprintf( text_key, "txt_%s", snd_key.Right( snd_key.Length() - 4 ).c_str() ); - if ( team || gameState == COUNTDOWN || gameState == GAMEREVIEW ) { - ProcessChatMessage( clientNum, team, name, spawnArgs->GetString( text_key ), spawnArgs->GetString( snd_key ) ); - } else { - p->StartSound( snd_key, SND_CHANNEL_ANY, 0, true, NULL ); - ProcessChatMessage( clientNum, team, name, spawnArgs->GetString( text_key ), NULL ); - } -} - -/* -================ -idMultiplayerGame::ServerWriteInitialReliableMessages -================ -*/ -void idMultiplayerGame::ServerWriteInitialReliableMessages( int clientNum ) { - idBitMsg outMsg; - byte msgBuf[ MAX_GAME_MESSAGE_SIZE ]; - int i; - idEntity *ent; - - outMsg.Init( msgBuf, sizeof( msgBuf ) ); - outMsg.BeginWriting(); - outMsg.WriteByte( GAME_RELIABLE_MESSAGE_STARTSTATE ); - // send the game state and start time - outMsg.WriteByte( gameState ); - outMsg.WriteInt( matchStartedTime ); - outMsg.WriteShort( startFragLimit ); - // send the powerup states and the spectate states - for( i = 0; i < gameLocal.numClients; i++ ) { - ent = gameLocal.entities[ i ]; - if ( i != clientNum && ent && ent->IsType( idPlayer::Type ) ) { - outMsg.WriteShort( i ); - outMsg.WriteShort( static_cast< idPlayer * >( ent )->inventory.powerups ); - outMsg.WriteBits( static_cast< idPlayer * >( ent )->spectating, 1 ); - } - } - outMsg.WriteShort( MAX_CLIENTS ); - networkSystem->ServerSendReliableMessage( clientNum, outMsg ); - - // we send SI in connectResponse messages, but it may have been modified already - outMsg.BeginWriting( ); - outMsg.WriteByte( GAME_RELIABLE_MESSAGE_SERVERINFO ); - outMsg.WriteDeltaDict( gameLocal.serverInfo, NULL ); - networkSystem->ServerSendReliableMessage( clientNum, outMsg ); - - // warmup time - if ( gameState == COUNTDOWN ) { - outMsg.BeginWriting(); - outMsg.WriteByte( GAME_RELIABLE_MESSAGE_WARMUPTIME ); - outMsg.WriteInt( warmupEndTime ); - networkSystem->ServerSendReliableMessage( clientNum, outMsg ); - } -} - -/* -================ -idMultiplayerGame::ClientReadStartState -================ -*/ -void idMultiplayerGame::ClientReadStartState( const idBitMsg &msg ) { - int i, client, powerup; - - // read the state in preparation for reading snapshot updates - gameState = (idMultiplayerGame::gameState_t)msg.ReadByte(); - matchStartedTime = msg.ReadInt( ); - startFragLimit = msg.ReadShort( ); - while ( ( client = msg.ReadShort() ) != MAX_CLIENTS ) { - assert( gameLocal.entities[ client ] && gameLocal.entities[ client ]->IsType( idPlayer::Type ) ); - powerup = msg.ReadShort(); - for ( i = 0; i < MAX_POWERUPS; i++ ) { - if ( powerup & ( 1 << i ) ) { - static_cast< idPlayer * >( gameLocal.entities[ client ] )->GivePowerUp( i, 0 ); - } - } - bool spectate = ( msg.ReadBits( 1 ) != 0 ); - static_cast< idPlayer * >( gameLocal.entities[ client ] )->Spectate( spectate ); - } -} - -/* -================ -idMultiplayerGame::ClientReadWarmupTime -================ -*/ -void idMultiplayerGame::ClientReadWarmupTime( const idBitMsg &msg ) { - warmupEndTime = msg.ReadInt(); -} - -/* -#ifdef CTF - - Threewave note: - The below IsGametype...() functions were implemented for CTF, - but we did not #ifdef CTF them, because doing so would clutter - the codebase substantially. Please consider them part of the merged - CTF code. -*/ - -/* -================ -idMultiplayerGame::IsGametypeTeamBased -================ -*/ -bool idMultiplayerGame::IsGametypeTeamBased( void ) /* CTF */ -{ - switch ( gameLocal.gameType ) - { - case GAME_SP: - case GAME_DM: - case GAME_TOURNEY: - case GAME_LASTMAN: - return false; -#ifdef CTF - case GAME_CTF: -#endif - case GAME_TDM: - return true; - - default: - assert( !"Add support for your new gametype here." ); - } - - return false; -} - -/* -================ -idMultiplayerGame::IsGametypeFlagBased -================ -*/ -bool idMultiplayerGame::IsGametypeFlagBased( void ) { - switch ( gameLocal.gameType ) - { - case GAME_SP: - case GAME_DM: - case GAME_TOURNEY: - case GAME_LASTMAN: - case GAME_TDM: - return false; - -#ifdef CTF - case GAME_CTF: - return true; -#endif - - default: - assert( !"Add support for your new gametype here." ); - } - - return false; - -} -#ifdef CTF - -/* -================ -idMultiplayerGame::GetTeamFlag -================ -*/ -idItemTeam * idMultiplayerGame::GetTeamFlag( int team ) { - assert( team == 0 || team == 1 ); - - if ( !IsGametypeFlagBased() || ( team != 0 && team != 1 ) ) /* CTF */ - return NULL; - - // TODO : just call on map start - FindTeamFlags(); - - return teamFlags[team]; -} - -/* -================ -idMultiplayerGame::GetTeamFlag -================ -*/ -void idMultiplayerGame::FindTeamFlags( void ) { - const char * flagDefs[2] = - { - "team_CTF_redflag", - "team_CTF_blueflag" - }; - - for ( int i = 0; i < 2; i++) - { - idEntity * entity = gameLocal.FindEntityUsingDef( NULL, flagDefs[i] ); - do - { - if ( entity == NULL ) - return; - - idItemTeam * flag = static_cast(entity); - - if ( flag->team == i ) - { - teamFlags[i] = flag; - break; - } - - entity = gameLocal.FindEntityUsingDef( entity, flagDefs[i] ); - } while( entity ); - } -} - -/* -================ -idMultiplayerGame::GetFlagStatus -================ -*/ -flagStatus_t idMultiplayerGame::GetFlagStatus( int team ) { - //assert( IsGametypeFlagBased() ); - - idItemTeam *teamFlag = GetTeamFlag( team ); - //assert( teamFlag != NULL ); - - if ( teamFlag != NULL ) { - if ( teamFlag->carried == false && teamFlag->dropped == false ) - return FLAGSTATUS_INBASE; - - if ( teamFlag->carried == true ) - return FLAGSTATUS_TAKEN; - - if ( teamFlag->carried == false && teamFlag->dropped == true ) - return FLAGSTATUS_STRAY; - } - - //assert( !"Invalid flag state." ); - return FLAGSTATUS_NONE; -} - -/* -================ -idMultiplayerGame::SetFlagMsgs -================ -*/ -void idMultiplayerGame::SetFlagMsg( bool b ) { - flagMsgOn = b; -} - -/* -================ -idMultiplayerGame::IsFlagMsgOn -================ -*/ -bool idMultiplayerGame::IsFlagMsgOn( void ) { - return ( GetGameState() == WARMUP || GetGameState() == GAMEON || GetGameState() == SUDDENDEATH ) && flagMsgOn; -} - - -/* -================ -idMultiplayerGame::SetBestGametype -================ -*/ -void idMultiplayerGame::SetBestGametype( const char * map ) { - const char *gametype = gameLocal.serverInfo.GetString( "si_gameType" ); - // const char *map = gameLocal.serverInfo.GetString( "si_map" ); - int num = declManager->GetNumDecls( DECL_MAPDEF ); - int i, j; - - for ( i = 0; i < num; i++ ) { - const idDeclEntityDef *mapDef = static_cast( declManager->DeclByIndex( DECL_MAPDEF, i ) ); - - if ( mapDef && idStr::Icmp( mapDef->GetName(), map ) == 0 ) { - if ( mapDef->dict.GetBool( gametype ) ) { - // dont change gametype - return; - } - - for ( j = 1; si_gameTypeArgs[ j ]; j++ ) { - if ( mapDef->dict.GetBool( si_gameTypeArgs[ j ] ) ) { - si_gameType.SetString( si_gameTypeArgs[ j ] ); - return; - } - } - - // error out, no valid gametype - return; - } - } -} - -/* -================ -idMultiplayerGame::ReloadScoreboard -================ -*/ -void idMultiplayerGame::ReloadScoreboard() { - // CTF uses its own scoreboard - if ( IsGametypeFlagBased() ) - scoreBoard = uiManager->FindGui( "guis/ctfscoreboard.gui", true, false, true ); - else - scoreBoard = uiManager->FindGui( "guis/scoreboard.gui", true, false, true ); - - Precache(); -} - - -#endif - -#ifdef _D3XP -idStr idMultiplayerGame::GetBestGametype( const char* map, const char* gametype ) { - - int num = declManager->GetNumDecls( DECL_MAPDEF ); - int i, j; - - for ( i = 0; i < num; i++ ) { - const idDeclEntityDef *mapDef = static_cast( declManager->DeclByIndex( DECL_MAPDEF, i ) ); - - if ( mapDef && idStr::Icmp( mapDef->GetName(), map ) == 0 ) { - if ( mapDef->dict.GetBool( gametype ) ) { - // dont change gametype - return gametype; - } - - for ( j = 1; si_gameTypeArgs[ j ]; j++ ) { - if ( mapDef->dict.GetBool( si_gameTypeArgs[ j ] ) ) { - return si_gameTypeArgs[ j ]; - } - } - - // error out, no valid gametype - return "deathmatch"; - } - } - - //For testing a new map let it play any gametpye - return gametype; -} -#endif diff --git a/d3xp/MultiplayerGame.h b/d3xp/MultiplayerGame.h deleted file mode 100644 index 100f9878..00000000 --- a/d3xp/MultiplayerGame.h +++ /dev/null @@ -1,488 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __MULTIPLAYERGAME_H__ -#define __MULTIPLAYERGAME_H__ - -#include "idlib/BitMsg.h" -#include "idlib/Str.h" -#include "ui/UserInterface.h" - -#include "GameBase.h" - -/* -=============================================================================== - - Basic DOOM multiplayer - -=============================================================================== -*/ - -class idPlayer; - -#ifdef CTF -class idItemTeam; -#endif - - -typedef enum { - GAME_SP = 0, - GAME_DM, - GAME_TOURNEY, - GAME_TDM, - GAME_LASTMAN, -#ifdef CTF - GAME_CTF, - GAME_COUNT, -#endif -} gameType_t; - -#ifdef CTF - -// Used by the UI -typedef enum { - FLAGSTATUS_INBASE = 0, - FLAGSTATUS_TAKEN = 1, - FLAGSTATUS_STRAY = 2, - FLAGSTATUS_NONE = 3 -} flagStatus_t; - -#endif - - -typedef enum { - PLAYER_VOTE_NONE, - PLAYER_VOTE_NO, - PLAYER_VOTE_YES, - PLAYER_VOTE_WAIT // mark a player allowed to vote -} playerVote_t; - -typedef struct mpPlayerState_s { - int ping; // player ping - int fragCount; // kills - int teamFragCount; // team kills - int wins; // wins - playerVote_t vote; // player's vote - bool scoreBoardUp; // toggle based on player scoreboard button, used to activate de-activate the scoreboard gui - bool ingame; -} mpPlayerState_t; - -const int NUM_CHAT_NOTIFY = 5; -const int CHAT_FADE_TIME = 400; -const int FRAGLIMIT_DELAY = 2000; - -const int MP_PLAYER_MINFRAGS = -100; -#ifdef CTF -const int MP_PLAYER_MAXFRAGS = 400; // in CTF frags are player points -#else -const int MP_PLAYER_MAXFRAGS = 100; -#endif -const int MP_PLAYER_MAXWINS = 100; -const int MP_PLAYER_MAXPING = 999; - -#ifdef CTF -const int MP_CTF_MAXPOINTS = 25; -#endif - -typedef struct mpChatLine_s { - idStr line; - short fade; // starts high and decreases, line is removed once reached 0 -} mpChatLine_t; - -typedef enum { - SND_YOUWIN = 0, - SND_YOULOSE, - SND_FIGHT, - SND_VOTE, - SND_VOTE_PASSED, - SND_VOTE_FAILED, - SND_THREE, - SND_TWO, - SND_ONE, - SND_SUDDENDEATH, -#ifdef CTF - SND_FLAG_CAPTURED_YOURS, - SND_FLAG_CAPTURED_THEIRS, - SND_FLAG_RETURN, - SND_FLAG_TAKEN_YOURS, - SND_FLAG_TAKEN_THEIRS, - SND_FLAG_DROPPED_YOURS, - SND_FLAG_DROPPED_THEIRS, -#endif - SND_COUNT -} snd_evt_t; - -class idMultiplayerGame { -public: - - idMultiplayerGame(); - - void Shutdown( void ); - - // resets everything and prepares for a match - void Reset( void ); - - // setup local data for a new player - void SpawnPlayer( int clientNum ); - - // checks rules and updates state of the mp game - void Run( void ); - - // draws mp hud, scoredboard, etc.. - bool Draw( int clientNum ); - - // updates a player vote - void PlayerVote( int clientNum, playerVote_t vote ); - - // updates frag counts and potentially ends the match in sudden death - void PlayerDeath( idPlayer *dead, idPlayer *killer, bool telefrag ); - - void AddChatLine( const char *fmt, ... ) id_attribute((format(printf,2,3))); - - void UpdateMainGui( void ); - idUserInterface*StartMenu( void ); - const char* HandleGuiCommands( const char *menuCommand ); - void SetMenuSkin( void ); - - void WriteToSnapshot( idBitMsgDelta &msg ) const; - void ReadFromSnapshot( const idBitMsgDelta &msg ); - - // game state - typedef enum { - INACTIVE = 0, // not running - WARMUP, // warming up - COUNTDOWN, // post warmup pre-game - GAMEON, // game is on - SUDDENDEATH, // game is on but in sudden death, first frag wins - GAMEREVIEW, // game is over, scoreboard is up. we wait si_gameReviewPause seconds (which has a min value) - NEXTGAME, - STATE_COUNT - } gameState_t; - static const char *GameStateStrings[ STATE_COUNT ]; - idMultiplayerGame::gameState_t GetGameState( void ) const; - - static const char *GlobalSoundStrings[ SND_COUNT ]; - void PlayGlobalSound( int to, snd_evt_t evt, const char *shader = NULL ); -#ifdef CTF - void PlayTeamSound( int toTeam, snd_evt_t evt, const char *shader = NULL ); // sound that's sent only to member of toTeam team -#endif - - // more compact than a chat line - typedef enum { - MSG_SUICIDE = 0, - MSG_KILLED, - MSG_KILLEDTEAM, - MSG_DIED, - MSG_VOTE, - MSG_VOTEPASSED, - MSG_VOTEFAILED, - MSG_SUDDENDEATH, - MSG_FORCEREADY, - MSG_JOINEDSPEC, - MSG_TIMELIMIT, - MSG_FRAGLIMIT, - MSG_TELEFRAGGED, - MSG_JOINTEAM, - MSG_HOLYSHIT, -#ifdef CTF - MSG_POINTLIMIT, - - MSG_FLAGTAKEN, - MSG_FLAGDROP, - MSG_FLAGRETURN, - MSG_FLAGCAPTURE, - MSG_SCOREUPDATE, - -#endif - MSG_COUNT - } msg_evt_t; - void PrintMessageEvent( int to, msg_evt_t evt, int parm1 = -1, int parm2 = -1 ); - - void DisconnectClient( int clientNum ); - static void ForceReady_f( const idCmdArgs &args ); - static void DropWeapon_f( const idCmdArgs &args ); - static void MessageMode_f( const idCmdArgs &args ); - static void VoiceChat_f( const idCmdArgs &args ); - static void VoiceChatTeam_f( const idCmdArgs &args ); - - typedef enum { - VOTE_RESTART = 0, - VOTE_TIMELIMIT, - VOTE_FRAGLIMIT, - VOTE_GAMETYPE, - VOTE_KICK, - VOTE_MAP, - VOTE_SPECTATORS, - VOTE_NEXTMAP, - VOTE_COUNT, - VOTE_NONE - } vote_flags_t; - - typedef enum { - VOTE_UPDATE, - VOTE_FAILED, - VOTE_PASSED, // passed, but no reset yet - VOTE_ABORTED, - VOTE_RESET // tell clients to reset vote state - } vote_result_t; - - static void Vote_f( const idCmdArgs &args ); - static void CallVote_f( const idCmdArgs &args ); - void ClientCallVote( vote_flags_t voteIndex, const char *voteValue ); - void ServerCallVote( int clientNum, const idBitMsg &msg ); - void ClientStartVote( int clientNum, const char *voteString ); - void ServerStartVote( int clientNum, vote_flags_t voteIndex, const char *voteValue ); - void ClientUpdateVote( vote_result_t result, int yesCount, int noCount ); - void CastVote( int clientNum, bool vote ); - void ExecuteVote( void ); - - void WantKilled( int clientNum ); - int NumActualClients( bool countSpectators, int *teamcount = NULL ); - void DropWeapon( int clientNum ); - void MapRestart( void ); - // called by idPlayer whenever it detects a team change (init or switch) - void SwitchToTeam( int clientNum, int oldteam, int newteam ); - bool IsPureReady( void ) const; - void ProcessChatMessage( int clientNum, bool team, const char *name, const char *text, const char *sound ); - void ProcessVoiceChat( int clientNum, bool team, int index ); - - void Precache( void ); - - // throttle UI switch rates - void ThrottleUserInfo( void ); - void ToggleSpectate( void ); - void ToggleReady( void ); - void ToggleTeam( void ); - - void ClearFrags( int clientNum ); - - void EnterGame( int clientNum ); - bool CanPlay( idPlayer *p ); - bool IsInGame( int clientNum ); - bool WantRespawn( idPlayer *p ); - - void ServerWriteInitialReliableMessages( int clientNum ); - void ClientReadStartState( const idBitMsg &msg ); - void ClientReadWarmupTime( const idBitMsg &msg ); - - void ServerClientConnect( int clientNum ); -#ifdef CTF - void ClearHUDStatus( void ); - int GetFlagPoints( int team ); // Team points in CTF - void SetFlagMsg( bool b ); // allow flag event messages to be sent - bool IsFlagMsgOn( void ); // should flag event messages go through? - void ClearGuis( void ); - - int player_red_flag; // Ent num of red flag carrier for HUD - int player_blue_flag; // Ent num of blue flag carrier for HUD - -#endif - void PlayerStats( int clientNum, char *data, const int len ); - -private: - static const char *MPGuis[]; - static const char *ThrottleVars[]; - static const char *ThrottleVarsInEnglish[]; - static const int ThrottleDelay[]; - - // state vars - gameState_t gameState; // what state the current game is in - gameState_t nextState; // state to switch to when nextStateSwitch is hit - int pingUpdateTime; // time to update ping - - mpPlayerState_t playerState[ MAX_CLIENTS ]; - - // keep track of clients which are willingly in spectator mode - - // vote vars - vote_flags_t vote; // active vote or VOTE_NONE - int voteTimeOut; // when the current vote expires - int voteExecTime; // delay between vote passed msg and execute - float yesVotes; // counter for yes votes - float noVotes; // and for no votes - idStr voteValue; // the data voted upon ( server ) - idStr voteString; // the vote string ( client ) - bool voted; // hide vote box ( client ) - int kickVoteMap[ MAX_CLIENTS ]; - - // time related - int nextStateSwitch; // time next state switch - int warmupEndTime; // warmup till.. - int matchStartedTime; // time current match started - - // tourney - int currentTourneyPlayer[2];// our current set of players - int lastWinner; // plays again - - // warmup - idStr warmupText; // text shown in warmup area of screen - bool one, two, three; // keeps count down voice from repeating - - // guis - idUserInterface *scoreBoard; // scoreboard - idUserInterface *spectateGui; // spectate info - idUserInterface *guiChat; // chat text - idUserInterface *mainGui; // ready / nick / votes etc. - idListGUI *mapList; - idUserInterface *msgmodeGui; // message mode - int currentMenu; // 0 - none, 1 - mainGui, 2 - msgmodeGui - int nextMenu; // if 0, will do mainGui - bool bCurrentMenuMsg; // send menu state updates to server - - // chat data - mpChatLine_t chatHistory[ NUM_CHAT_NOTIFY ]; - int chatHistoryIndex; - int chatHistorySize; // 0 <= x < NUM_CHAT_NOTIFY - bool chatDataUpdated; - int lastChatLineTime; - - // rankings are used by UpdateScoreboard and UpdateHud - int numRankedPlayers; // ranked players, others may be empty slots or spectators - idPlayer * rankedPlayers[MAX_CLIENTS]; - - bool pureReady; // defaults to false, set to true once server game is running with pure checksums - int fragLimitTimeout; - - int switchThrottle[ 3 ]; - int voiceChatThrottle; - - gameType_t lastGameType; // for restarts - int startFragLimit; // synchronize to clients in initial state, set on -> GAMEON - -#ifdef CTF - idItemTeam * teamFlags[ 2 ]; - int teamPoints[ 2 ]; - - bool flagMsgOn; - - const char * gameTypeVoteMap[ GAME_COUNT ]; -#endif - -private: - void UpdatePlayerRanks(); - - // updates the passed gui with current score information - void UpdateRankColor( idUserInterface *gui, const char *mask, int i, const idVec3 &vec ); - void UpdateScoreboard( idUserInterface *scoreBoard, idPlayer *player ); -#ifdef CTF - void UpdateCTFScoreboard( idUserInterface *scoreBoard, idPlayer *player ); -#endif - -#ifndef CTF - // We declare this publically above so we can call it during a map restart. - void ClearGuis( void ); -#endif - - void DrawScoreBoard( idPlayer *player ); - void UpdateHud( idPlayer *player, idUserInterface *hud ); - bool Warmup( void ); - void CheckVote( void ); - bool AllPlayersReady( void ); - idPlayer * FragLimitHit( void ); - idPlayer * FragLeader( void ); - bool TimeLimitHit( void ); -#ifdef CTF - bool PointLimitHit( void ); - // return team with most points - int WinningTeam( void ); -#endif - void NewState( gameState_t news, idPlayer *player = NULL ); - void UpdateWinsLosses( idPlayer *winner ); - // fill any empty tourney slots based on the current tourney ranks - void FillTourneySlots( void ); - void CycleTourneyPlayers( void ); - // walk through the tourneyRank to build a wait list for the clients - void UpdateTourneyLine( void ); - const char * GameTime( void ); - void Clear( void ); - bool EnoughClientsToPlay( void ); - void ClearChatData( void ); - void DrawChat( void ); - // go through the clients, and see if they want to be respawned, and if the game allows it - // called during normal gameplay for death -> respawn cycles - // and for a spectator who want back in the game (see param) - void CheckRespawns( idPlayer *spectator = NULL ); - void ForceReady(); - // when clients disconnect or join spectate during game, check if we need to end the game - void CheckAbortGame( void ); - void MessageMode( const idCmdArgs &args ); - void DisableMenu( void ); - void SetMapShot( void ); - // scores in TDM - void TeamScore( int entityNumber, int team, int delta ); - void VoiceChat( const idCmdArgs &args, bool team ); - void DumpTourneyLine( void ); - void SuddenRespawn( void ); - -#ifdef CTF - void FindTeamFlags( void ); -#endif - -public: - -#ifdef CTF - idItemTeam * GetTeamFlag( int team ); - flagStatus_t GetFlagStatus( int team ); - void TeamScoreCTF( int team, int delta ); - void PlayerScoreCTF( int playerIdx, int delta ); - // returns entityNum to team flag carrier, -1 if no flag carrier - int GetFlagCarrier( int team ); - void UpdateScoreboardFlagStatus( void ); - - void SetBestGametype( const char * map ); - void ReloadScoreboard(); -#endif - -#ifdef _D3XP - idStr GetBestGametype( const char* map, const char* gametype ); -#endif - -/* #ifdef CTF ... merge the below IsGametypeFlagBased */ -bool IsGametypeFlagBased( void ); -bool IsGametypeTeamBased( void ); -/* #endif CTF */ - -}; - -ID_INLINE idMultiplayerGame::gameState_t idMultiplayerGame::GetGameState( void ) const { - return gameState; -} - -ID_INLINE bool idMultiplayerGame::IsPureReady( void ) const { - return pureReady; -} - -ID_INLINE void idMultiplayerGame::ClearFrags( int clientNum ) { - playerState[ clientNum ].fragCount = 0; -} - -ID_INLINE bool idMultiplayerGame::IsInGame( int clientNum ) { - return playerState[ clientNum ].ingame; -} - -#endif /* !__MULTIPLAYERGAME_H__ */ diff --git a/d3xp/Player.cpp b/d3xp/Player.cpp deleted file mode 100644 index 718a8cc7..00000000 --- a/d3xp/Player.cpp +++ /dev/null @@ -1,10125 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "idlib/LangDict.h" -#include "framework/async/NetworkSystem.h" -#include "framework/DeclEntityDef.h" -#include "renderer/RenderSystem.h" - -#include "gamesys/SysCvar.h" -#include "script/Script_Thread.h" -#include "ai/AI.h" -#include "WorldSpawn.h" -#include "Player.h" -#include "Camera.h" -#include "Fx.h" -#include "Misc.h" - -const int ASYNC_PLAYER_INV_AMMO_BITS = idMath::BitsForInteger( 999 ); // 9 bits to cover the range [0, 999] -const int ASYNC_PLAYER_INV_CLIP_BITS = -7; // -7 bits to cover the range [-1, 60] -/* -=============================================================================== - - Player control of the Doom Marine. - This object handles all player movement and world interaction. - -=============================================================================== -*/ - -// distance between ladder rungs (actually is half that distance, but this sounds better) -const int LADDER_RUNG_DISTANCE = 32; - -// amount of health per dose from the health station -const int HEALTH_PER_DOSE = 10; - -// time before a weapon dropped to the floor disappears -const int WEAPON_DROP_TIME = 20 * 1000; - -// time before a next or prev weapon switch happens -const int WEAPON_SWITCH_DELAY = 150; - -// how many units to raise spectator above default view height so it's in the head of someone -const int SPECTATE_RAISE = 25; - -const int HEALTHPULSE_TIME = 333; - -// minimum speed to bob and play run/walk animations at -const float MIN_BOB_SPEED = 5.0f; - -const idEventDef EV_Player_GetButtons( "getButtons", NULL, 'd' ); -const idEventDef EV_Player_GetMove( "getMove", NULL, 'v' ); -const idEventDef EV_Player_GetViewAngles( "getViewAngles", NULL, 'v' ); -const idEventDef EV_Player_StopFxFov( "stopFxFov" ); -const idEventDef EV_Player_EnableWeapon( "enableWeapon" ); -const idEventDef EV_Player_DisableWeapon( "disableWeapon" ); -const idEventDef EV_Player_GetCurrentWeapon( "getCurrentWeapon", NULL, 's' ); -const idEventDef EV_Player_GetPreviousWeapon( "getPreviousWeapon", NULL, 's' ); -const idEventDef EV_Player_SelectWeapon( "selectWeapon", "s" ); -const idEventDef EV_Player_GetWeaponEntity( "getWeaponEntity", NULL, 'e' ); -const idEventDef EV_Player_OpenPDA( "openPDA" ); -const idEventDef EV_Player_InPDA( "inPDA", NULL, 'd' ); -const idEventDef EV_Player_ExitTeleporter( "exitTeleporter" ); -const idEventDef EV_Player_StopAudioLog( "stopAudioLog" ); -const idEventDef EV_Player_HideTip( "hideTip" ); -const idEventDef EV_Player_LevelTrigger( "levelTrigger" ); -const idEventDef EV_SpectatorTouch( "spectatorTouch", "et" ); -#ifdef _D3XP -const idEventDef EV_Player_GiveInventoryItem( "giveInventoryItem", "s" ); -const idEventDef EV_Player_RemoveInventoryItem( "removeInventoryItem", "s" ); -const idEventDef EV_Player_GetIdealWeapon( "getIdealWeapon", NULL, 's' ); -const idEventDef EV_Player_SetPowerupTime( "setPowerupTime", "dd" ); -const idEventDef EV_Player_IsPowerupActive( "isPowerupActive", "d", 'd' ); -const idEventDef EV_Player_WeaponAvailable( "weaponAvailable", "s", 'd'); -const idEventDef EV_Player_StartWarp( "startWarp" ); -const idEventDef EV_Player_StopHelltime( "stopHelltime", "d" ); -const idEventDef EV_Player_ToggleBloom( "toggleBloom", "d" ); -const idEventDef EV_Player_SetBloomParms( "setBloomParms", "ff" ); -#endif - -CLASS_DECLARATION( idActor, idPlayer ) - EVENT( EV_Player_GetButtons, idPlayer::Event_GetButtons ) - EVENT( EV_Player_GetMove, idPlayer::Event_GetMove ) - EVENT( EV_Player_GetViewAngles, idPlayer::Event_GetViewAngles ) - EVENT( EV_Player_StopFxFov, idPlayer::Event_StopFxFov ) - EVENT( EV_Player_EnableWeapon, idPlayer::Event_EnableWeapon ) - EVENT( EV_Player_DisableWeapon, idPlayer::Event_DisableWeapon ) - EVENT( EV_Player_GetCurrentWeapon, idPlayer::Event_GetCurrentWeapon ) - EVENT( EV_Player_GetPreviousWeapon, idPlayer::Event_GetPreviousWeapon ) - EVENT( EV_Player_SelectWeapon, idPlayer::Event_SelectWeapon ) - EVENT( EV_Player_GetWeaponEntity, idPlayer::Event_GetWeaponEntity ) - EVENT( EV_Player_OpenPDA, idPlayer::Event_OpenPDA ) - EVENT( EV_Player_InPDA, idPlayer::Event_InPDA ) - EVENT( EV_Player_ExitTeleporter, idPlayer::Event_ExitTeleporter ) - EVENT( EV_Player_StopAudioLog, idPlayer::Event_StopAudioLog ) - EVENT( EV_Player_HideTip, idPlayer::Event_HideTip ) - EVENT( EV_Player_LevelTrigger, idPlayer::Event_LevelTrigger ) - EVENT( EV_Gibbed, idPlayer::Event_Gibbed ) -#ifdef _D3XP - EVENT( EV_Player_GiveInventoryItem, idPlayer::Event_GiveInventoryItem ) - EVENT( EV_Player_RemoveInventoryItem, idPlayer::Event_RemoveInventoryItem ) - EVENT( EV_Player_GetIdealWeapon, idPlayer::Event_GetIdealWeapon ) - EVENT( EV_Player_WeaponAvailable, idPlayer::Event_WeaponAvailable ) - EVENT( EV_Player_SetPowerupTime, idPlayer::Event_SetPowerupTime ) - EVENT( EV_Player_IsPowerupActive, idPlayer::Event_IsPowerupActive ) - EVENT( EV_Player_StartWarp, idPlayer::Event_StartWarp ) - EVENT( EV_Player_StopHelltime, idPlayer::Event_StopHelltime ) - EVENT( EV_Player_ToggleBloom, idPlayer::Event_ToggleBloom ) - EVENT( EV_Player_SetBloomParms, idPlayer::Event_SetBloomParms ) -#endif -END_CLASS - -const int MAX_RESPAWN_TIME = 10000; -const int RAGDOLL_DEATH_TIME = 3000; -const int MAX_PDAS = 64; -const int MAX_PDA_ITEMS = 128; -const int STEPUP_TIME = 200; -const int MAX_INVENTORY_ITEMS = 20; - - -#ifdef _D3XP -idVec3 idPlayer::colorBarTable[ 8 ] = { -#else -idVec3 idPlayer::colorBarTable[ 5 ] = { -#endif - idVec3( 0.25f, 0.25f, 0.25f ), - idVec3( 1.00f, 0.00f, 0.00f ), - idVec3( 0.00f, 0.80f, 0.10f ), - idVec3( 0.20f, 0.50f, 0.80f ), - idVec3( 1.00f, 0.80f, 0.10f ) -#ifdef _D3XP - ,idVec3( 0.425f, 0.484f, 0.445f ), - idVec3( 0.39f, 0.199f, 0.3f ), - idVec3( 0.484f, 0.312f, 0.074f) -#endif -}; - -/* -============== -idInventory::Clear -============== -*/ -void idInventory::Clear( void ) { - maxHealth = 0; - weapons = 0; - powerups = 0; - armor = 0; - maxarmor = 0; - deplete_armor = 0; - deplete_rate = 0.0f; - deplete_ammount = 0; - nextArmorDepleteTime = 0; - - memset( ammo, 0, sizeof( ammo ) ); - - ClearPowerUps(); - - // set to -1 so that the gun knows to have a full clip the first time we get it and at the start of the level - memset( clip, -1, sizeof( clip ) ); - - items.DeleteContents( true ); - memset(pdasViewed, 0, 4 * sizeof( pdasViewed[0] ) ); - pdas.Clear(); - videos.Clear(); - emails.Clear(); - selVideo = 0; - selEMail = 0; - selPDA = 0; - selAudio = 0; - pdaOpened = false; - turkeyScore = false; - - levelTriggers.Clear(); - - nextItemPickup = 0; - nextItemNum = 1; - onePickupTime = 0; - pickupItemNames.Clear(); - objectiveNames.Clear(); - - ammoPredictTime = 0; - - lastGiveTime = 0; - - ammoPulse = false; - weaponPulse = false; - armorPulse = false; -} - -/* -============== -idInventory::GivePowerUp -============== -*/ -void idInventory::GivePowerUp( idPlayer *player, int powerup, int msec ) { - if ( !msec ) { - // get the duration from the .def files - const idDeclEntityDef *def = NULL; - switch ( powerup ) { - case BERSERK: - def = gameLocal.FindEntityDef( "powerup_berserk", false ); - break; - case INVISIBILITY: - def = gameLocal.FindEntityDef( "powerup_invisibility", false ); - break; - case MEGAHEALTH: - def = gameLocal.FindEntityDef( "powerup_megahealth", false ); - break; - case ADRENALINE: - def = gameLocal.FindEntityDef( "powerup_adrenaline", false ); - break; -#ifdef _D3XP - case INVULNERABILITY: - def = gameLocal.FindEntityDef( "powerup_invulnerability", false ); - break; - /*case HASTE: - def = gameLocal.FindEntityDef( "powerup_haste", false ); - break;*/ -#endif - } - assert( def ); - msec = def->dict.GetInt( "time" ) * 1000; - } - powerups |= 1 << powerup; - powerupEndTime[ powerup ] = gameLocal.time + msec; -} - -/* -============== -idInventory::ClearPowerUps -============== -*/ -void idInventory::ClearPowerUps( void ) { - int i; - for ( i = 0; i < MAX_POWERUPS; i++ ) { - powerupEndTime[ i ] = 0; - } - powerups = 0; -} - -/* -============== -idInventory::GetPersistantData -============== -*/ -void idInventory::GetPersistantData( idDict &dict ) { - int i; - int num; - idDict *item; - idStr key; - const idKeyValue *kv; - const char *name; - - // armor - dict.SetInt( "armor", armor ); - - // don't bother with powerups, maxhealth, maxarmor, or the clip - - // ammo - for( i = 0; i < AMMO_NUMTYPES; i++ ) { - name = idWeapon::GetAmmoNameForNum( ( ammo_t )i ); - if ( name ) { - dict.SetInt( name, ammo[ i ] ); - } - } - -#ifdef _D3XP - //Save the clip data - for( i = 0; i < MAX_WEAPONS; i++ ) { - dict.SetInt( va("clip%i", i), clip[ i ] ); - } -#endif - - // items - num = 0; - for( i = 0; i < items.Num(); i++ ) { - item = items[ i ]; - - // copy all keys with "inv_" - kv = item->MatchPrefix( "inv_" ); - if ( kv ) { - while( kv ) { - sprintf( key, "item_%i %s", num, kv->GetKey().c_str() ); - dict.Set( key, kv->GetValue() ); - kv = item->MatchPrefix( "inv_", kv ); - } - num++; - } - } - dict.SetInt( "items", num ); - - // pdas viewed - for ( i = 0; i < 4; i++ ) { - dict.SetInt( va("pdasViewed_%i", i), pdasViewed[i] ); - } - - dict.SetInt( "selPDA", selPDA ); - dict.SetInt( "selVideo", selVideo ); - dict.SetInt( "selEmail", selEMail ); - dict.SetInt( "selAudio", selAudio ); - dict.SetInt( "pdaOpened", pdaOpened ); - dict.SetInt( "turkeyScore", turkeyScore ); - - // pdas - for ( i = 0; i < pdas.Num(); i++ ) { - sprintf( key, "pda_%i", i ); - dict.Set( key, pdas[ i ] ); - } - dict.SetInt( "pdas", pdas.Num() ); - - // video cds - for ( i = 0; i < videos.Num(); i++ ) { - sprintf( key, "video_%i", i ); - dict.Set( key, videos[ i ].c_str() ); - } - dict.SetInt( "videos", videos.Num() ); - - // emails - for ( i = 0; i < emails.Num(); i++ ) { - sprintf( key, "email_%i", i ); - dict.Set( key, emails[ i ].c_str() ); - } - dict.SetInt( "emails", emails.Num() ); - - // weapons - dict.SetInt( "weapon_bits", weapons ); - - dict.SetInt( "levelTriggers", levelTriggers.Num() ); - for ( i = 0; i < levelTriggers.Num(); i++ ) { - sprintf( key, "levelTrigger_Level_%i", i ); - dict.Set( key, levelTriggers[i].levelName ); - sprintf( key, "levelTrigger_Trigger_%i", i ); - dict.Set( key, levelTriggers[i].triggerName ); - } -} - -/* -============== -idInventory::RestoreInventory -============== -*/ -void idInventory::RestoreInventory( idPlayer *owner, const idDict &dict ) { - int i; - int num; - idDict *item; - idStr key; - idStr itemname; - const idKeyValue *kv; - const char *name; - - Clear(); - - // health/armor - maxHealth = dict.GetInt( "maxhealth", "100" ); - armor = dict.GetInt( "armor", "50" ); - maxarmor = dict.GetInt( "maxarmor", "100" ); - deplete_armor = dict.GetInt( "deplete_armor", "0" ); - deplete_rate = dict.GetFloat( "deplete_rate", "2.0" ); - deplete_ammount = dict.GetInt( "deplete_ammount", "1" ); - - // the clip and powerups aren't restored - - // ammo - for( i = 0; i < AMMO_NUMTYPES; i++ ) { - name = idWeapon::GetAmmoNameForNum( ( ammo_t )i ); - if ( name ) { - ammo[ i ] = dict.GetInt( name ); - } - } - -#ifdef _D3XP - //Restore the clip data - for( i = 0; i < MAX_WEAPONS; i++ ) { - clip[i] = dict.GetInt(va("clip%i", i), "-1"); - } -#endif - - // items - num = dict.GetInt( "items" ); - items.SetNum( num ); - for( i = 0; i < num; i++ ) { - item = new idDict(); - items[ i ] = item; - sprintf( itemname, "item_%i ", i ); - kv = dict.MatchPrefix( itemname ); - while( kv ) { - key = kv->GetKey(); - key.Strip( itemname ); - item->Set( key, kv->GetValue() ); - kv = dict.MatchPrefix( itemname, kv ); - } - } - - // pdas viewed - for ( i = 0; i < 4; i++ ) { - pdasViewed[i] = dict.GetInt(va("pdasViewed_%i", i)); - } - - selPDA = dict.GetInt( "selPDA" ); - selEMail = dict.GetInt( "selEmail" ); - selVideo = dict.GetInt( "selVideo" ); - selAudio = dict.GetInt( "selAudio" ); - pdaOpened = dict.GetBool( "pdaOpened" ); - turkeyScore = dict.GetBool( "turkeyScore" ); - - // pdas - num = dict.GetInt( "pdas" ); - pdas.SetNum( num ); - for ( i = 0; i < num; i++ ) { - sprintf( itemname, "pda_%i", i ); - pdas[i] = dict.GetString( itemname, "default" ); - } - - // videos - num = dict.GetInt( "videos" ); - videos.SetNum( num ); - for ( i = 0; i < num; i++ ) { - sprintf( itemname, "video_%i", i ); - videos[i] = dict.GetString( itemname, "default" ); - } - - // emails - num = dict.GetInt( "emails" ); - emails.SetNum( num ); - for ( i = 0; i < num; i++ ) { - sprintf( itemname, "email_%i", i ); - emails[i] = dict.GetString( itemname, "default" ); - } - - // weapons are stored as a number for persistant data, but as strings in the entityDef - weapons = dict.GetInt( "weapon_bits", "0" ); - - if ( g_skill.GetInteger() >= 3 ) { - Give( owner, dict, "weapon", dict.GetString( "weapon_nightmare" ), NULL, false ); - } else { - Give( owner, dict, "weapon", dict.GetString( "weapon" ), NULL, false ); - } - - num = dict.GetInt( "levelTriggers" ); - for ( i = 0; i < num; i++ ) { - sprintf( itemname, "levelTrigger_Level_%i", i ); - idLevelTriggerInfo lti; - lti.levelName = dict.GetString( itemname ); - sprintf( itemname, "levelTrigger_Trigger_%i", i ); - lti.triggerName = dict.GetString( itemname ); - levelTriggers.Append( lti ); - } - -} - -/* -============== -idInventory::Save -============== -*/ -void idInventory::Save( idSaveGame *savefile ) const { - int i; - - savefile->WriteInt( maxHealth ); - savefile->WriteInt( weapons ); - savefile->WriteInt( powerups ); - savefile->WriteInt( armor ); - savefile->WriteInt( maxarmor ); - savefile->WriteInt( ammoPredictTime ); - savefile->WriteInt( deplete_armor ); - savefile->WriteFloat( deplete_rate ); - savefile->WriteInt( deplete_ammount ); - savefile->WriteInt( nextArmorDepleteTime ); - - for( i = 0; i < AMMO_NUMTYPES; i++ ) { - savefile->WriteInt( ammo[ i ] ); - } - for( i = 0; i < MAX_WEAPONS; i++ ) { - savefile->WriteInt( clip[ i ] ); - } - for( i = 0; i < MAX_POWERUPS; i++ ) { - savefile->WriteInt( powerupEndTime[ i ] ); - } - - savefile->WriteInt( items.Num() ); - for( i = 0; i < items.Num(); i++ ) { - savefile->WriteDict( items[ i ] ); - } - - savefile->WriteInt( pdasViewed[0] ); - savefile->WriteInt( pdasViewed[1] ); - savefile->WriteInt( pdasViewed[2] ); - savefile->WriteInt( pdasViewed[3] ); - - savefile->WriteInt( selPDA ); - savefile->WriteInt( selVideo ); - savefile->WriteInt( selEMail ); - savefile->WriteInt( selAudio ); - savefile->WriteBool( pdaOpened ); - savefile->WriteBool( turkeyScore ); - - savefile->WriteInt( pdas.Num() ); - for( i = 0; i < pdas.Num(); i++ ) { - savefile->WriteString( pdas[ i ] ); - } - - savefile->WriteInt( pdaSecurity.Num() ); - for( i=0; i < pdaSecurity.Num(); i++ ) { - savefile->WriteString( pdaSecurity[ i ] ); - } - - savefile->WriteInt( videos.Num() ); - for( i = 0; i < videos.Num(); i++ ) { - savefile->WriteString( videos[ i ] ); - } - - savefile->WriteInt( emails.Num() ); - for ( i = 0; i < emails.Num(); i++ ) { - savefile->WriteString( emails[ i ] ); - } - - savefile->WriteInt( nextItemPickup ); - savefile->WriteInt( nextItemNum ); - savefile->WriteInt( onePickupTime ); - - savefile->WriteInt( pickupItemNames.Num() ); - for( i = 0; i < pickupItemNames.Num(); i++ ) { - savefile->WriteString( pickupItemNames[i].icon ); - savefile->WriteString( pickupItemNames[i].name ); - } - - savefile->WriteInt( objectiveNames.Num() ); - for( i = 0; i < objectiveNames.Num(); i++ ) { - savefile->WriteString( objectiveNames[i].screenshot ); - savefile->WriteString( objectiveNames[i].text ); - savefile->WriteString( objectiveNames[i].title ); - } - - savefile->WriteInt( levelTriggers.Num() ); - for ( i = 0; i < levelTriggers.Num(); i++ ) { - savefile->WriteString( levelTriggers[i].levelName ); - savefile->WriteString( levelTriggers[i].triggerName ); - } - - savefile->WriteBool( ammoPulse ); - savefile->WriteBool( weaponPulse ); - savefile->WriteBool( armorPulse ); - - savefile->WriteInt( lastGiveTime ); - -#ifdef _D3XP - for(i = 0; i < AMMO_NUMTYPES; i++) { - savefile->WriteInt(rechargeAmmo[i].ammo); - savefile->WriteInt(rechargeAmmo[i].rechargeTime); - savefile->WriteString(rechargeAmmo[i].ammoName); - } -#endif -} - -/* -============== -idInventory::Restore -============== -*/ -void idInventory::Restore( idRestoreGame *savefile ) { - int i, num; - - savefile->ReadInt( maxHealth ); - savefile->ReadInt( weapons ); - savefile->ReadInt( powerups ); - savefile->ReadInt( armor ); - savefile->ReadInt( maxarmor ); - savefile->ReadInt( ammoPredictTime ); - savefile->ReadInt( deplete_armor ); - savefile->ReadFloat( deplete_rate ); - savefile->ReadInt( deplete_ammount ); - savefile->ReadInt( nextArmorDepleteTime ); - - for( i = 0; i < AMMO_NUMTYPES; i++ ) { - savefile->ReadInt( ammo[ i ] ); - } - for( i = 0; i < MAX_WEAPONS; i++ ) { - savefile->ReadInt( clip[ i ] ); - } - for( i = 0; i < MAX_POWERUPS; i++ ) { - savefile->ReadInt( powerupEndTime[ i ] ); - } - - savefile->ReadInt( num ); - for( i = 0; i < num; i++ ) { - idDict *itemdict = new idDict; - - savefile->ReadDict( itemdict ); - items.Append( itemdict ); - } - - // pdas - savefile->ReadInt( pdasViewed[0] ); - savefile->ReadInt( pdasViewed[1] ); - savefile->ReadInt( pdasViewed[2] ); - savefile->ReadInt( pdasViewed[3] ); - - savefile->ReadInt( selPDA ); - savefile->ReadInt( selVideo ); - savefile->ReadInt( selEMail ); - savefile->ReadInt( selAudio ); - savefile->ReadBool( pdaOpened ); - savefile->ReadBool( turkeyScore ); - - savefile->ReadInt( num ); - for( i = 0; i < num; i++ ) { - idStr strPda; - savefile->ReadString( strPda ); - pdas.Append( strPda ); - } - - // pda security clearances - savefile->ReadInt( num ); - for ( i = 0; i < num; i++ ) { - idStr invName; - savefile->ReadString( invName ); - pdaSecurity.Append( invName ); - } - - // videos - savefile->ReadInt( num ); - for( i = 0; i < num; i++ ) { - idStr strVideo; - savefile->ReadString( strVideo ); - videos.Append( strVideo ); - } - - // email - savefile->ReadInt( num ); - for( i = 0; i < num; i++ ) { - idStr strEmail; - savefile->ReadString( strEmail ); - emails.Append( strEmail ); - } - - savefile->ReadInt( nextItemPickup ); - savefile->ReadInt( nextItemNum ); - savefile->ReadInt( onePickupTime ); - savefile->ReadInt( num ); - for( i = 0; i < num; i++ ) { - idItemInfo info; - - savefile->ReadString( info.icon ); - savefile->ReadString( info.name ); - - pickupItemNames.Append( info ); - } - - savefile->ReadInt( num ); - for( i = 0; i < num; i++ ) { - idObjectiveInfo obj; - - savefile->ReadString( obj.screenshot ); - savefile->ReadString( obj.text ); - savefile->ReadString( obj.title ); - - objectiveNames.Append( obj ); - } - - savefile->ReadInt( num ); - for ( i = 0; i < num; i++ ) { - idLevelTriggerInfo lti; - savefile->ReadString( lti.levelName ); - savefile->ReadString( lti.triggerName ); - levelTriggers.Append( lti ); - } - - savefile->ReadBool( ammoPulse ); - savefile->ReadBool( weaponPulse ); - savefile->ReadBool( armorPulse ); - - savefile->ReadInt( lastGiveTime ); - -#ifdef _D3XP - for(i = 0; i < AMMO_NUMTYPES; i++) { - savefile->ReadInt(rechargeAmmo[i].ammo); - savefile->ReadInt(rechargeAmmo[i].rechargeTime); - - idStr name; - savefile->ReadString(name); - strcpy(rechargeAmmo[i].ammoName, name); - } -#endif -} - -/* -============== -idInventory::AmmoIndexForAmmoClass -============== -*/ -ammo_t idInventory::AmmoIndexForAmmoClass( const char *ammo_classname ) const { - return idWeapon::GetAmmoNumForName( ammo_classname ); -} - -/* -============== -idInventory::AmmoIndexForAmmoClass -============== -*/ -int idInventory::MaxAmmoForAmmoClass( idPlayer *owner, const char *ammo_classname ) const { - return owner->spawnArgs.GetInt( va( "max_%s", ammo_classname ), "0" ); -} - -/* -============== -idInventory::AmmoPickupNameForIndex -============== -*/ -const char *idInventory::AmmoPickupNameForIndex( ammo_t ammonum ) const { - return idWeapon::GetAmmoPickupNameForNum( ammonum ); -} - -/* -============== -idInventory::WeaponIndexForAmmoClass -mapping could be prepared in the constructor -============== -*/ -int idInventory::WeaponIndexForAmmoClass( const idDict & spawnArgs, const char *ammo_classname ) const { - int i; - const char *weapon_classname; - for( i = 0; i < MAX_WEAPONS; i++ ) { - weapon_classname = spawnArgs.GetString( va( "def_weapon%d", i ) ); - if ( !weapon_classname ) { - continue; - } - const idDeclEntityDef *decl = gameLocal.FindEntityDef( weapon_classname, false ); - if ( !decl ) { - continue; - } - if ( !idStr::Icmp( ammo_classname, decl->dict.GetString( "ammoType" ) ) ) { - return i; - } - } - return -1; -} - -/* -============== -idInventory::AmmoIndexForWeaponClass -============== -*/ -ammo_t idInventory::AmmoIndexForWeaponClass( const char *weapon_classname, int *ammoRequired ) { - const idDeclEntityDef *decl = gameLocal.FindEntityDef( weapon_classname, false ); - if ( !decl ) { - gameLocal.Error( "Unknown weapon in decl '%s'", weapon_classname ); - } - if ( ammoRequired ) { - *ammoRequired = decl->dict.GetInt( "ammoRequired" ); - } - ammo_t ammo_i = AmmoIndexForAmmoClass( decl->dict.GetString( "ammoType" ) ); - return ammo_i; -} - -/* -============== -idInventory::AddPickupName -============== -*/ -void idInventory::AddPickupName( const char *name, const char *icon, idPlayer* owner ) { //_D3XP - int num; - - num = pickupItemNames.Num(); - if ( ( num == 0 ) || ( pickupItemNames[ num - 1 ].name.Icmp( name ) != 0 ) ) { - idItemInfo &info = pickupItemNames.Alloc(); - - if ( idStr::Cmpn( name, STRTABLE_ID, STRTABLE_ID_LENGTH ) == 0 ) { - info.name = common->GetLanguageDict()->GetString( name ); - } else { - info.name = name; - } - info.icon = icon; - -#ifdef _D3XP - if ( gameLocal.isServer ) { - idBitMsg msg; - byte msgBuf[MAX_EVENT_PARAM_SIZE]; - - msg.Init( msgBuf, sizeof( msgBuf ) ); - msg.WriteString( name, MAX_EVENT_PARAM_SIZE ); - owner->ServerSendEvent( idPlayer::EVENT_PICKUPNAME, &msg, false, -1 ); - } - } -#endif -} - -/* -============== -idInventory::Give -============== -*/ -bool idInventory::Give( idPlayer *owner, const idDict &spawnArgs, const char *statname, const char *value, int *idealWeapon, bool updateHud ) { - int i; - const char *pos; - const char *end; - int len; - idStr weaponString; - int max; - const idDeclEntityDef *weaponDecl; - bool tookWeapon; - int amount; - idItemInfo info; - const char *name; - -#ifdef _D3XP - if ( !idStr::Icmp( statname, "ammo_bloodstone" ) ) { - i = AmmoIndexForAmmoClass( statname ); - max = MaxAmmoForAmmoClass( owner, statname ); - - if(max <= 0) { - //No Max - ammo[ i ] += atoi( value ); - } else { - //Already at or above the max so don't allow the give - if(ammo[ i ] >= max) { - ammo[ i ] = max; - return false; - } - //We were below the max so accept the give but cap it at the max - ammo[ i ] += atoi( value ); - if(ammo[ i ] > max) { - ammo[ i ] = max; - } - } - } else -#endif - - if ( !idStr::Icmpn( statname, "ammo_", 5 ) ) { - i = AmmoIndexForAmmoClass( statname ); - max = MaxAmmoForAmmoClass( owner, statname ); - if ( ammo[ i ] >= max ) { - return false; - } - amount = atoi( value ); - if ( amount ) { - ammo[ i ] += amount; - if ( ( max > 0 ) && ( ammo[ i ] > max ) ) { - ammo[ i ] = max; - } - ammoPulse = true; - - name = AmmoPickupNameForIndex( i ); - if ( idStr::Length( name ) ) { - AddPickupName( name, "", owner ); //_D3XP - } - } - } else if ( !idStr::Icmp( statname, "armor" ) ) { - if ( armor >= maxarmor ) { - return false; // can't hold any more, so leave the item - } - amount = atoi( value ); - if ( amount ) { - armor += amount; - if ( armor > maxarmor ) { - armor = maxarmor; - } - nextArmorDepleteTime = 0; - armorPulse = true; - } - } else if ( idStr::FindText( statname, "inclip_" ) == 0 ) { -#ifdef _D3XP - idStr temp = statname; - i = atoi(temp.Mid(7, 2)); -#else - i = WeaponIndexForAmmoClass( spawnArgs, statname + 7 ); -#endif - if ( i != -1 ) { - // set, don't add. not going over the clip size limit. -#ifndef _D3XP - clip[ i ] = atoi( value ); -#endif - } -#ifdef _D3XP - } else if ( !idStr::Icmp( statname, "invulnerability" ) ) { - owner->GivePowerUp( INVULNERABILITY, SEC2MS( atof( value ) ) ); - } else if ( !idStr::Icmp( statname, "helltime" ) ) { - owner->GivePowerUp( HELLTIME, SEC2MS( atof( value ) ) ); - } else if ( !idStr::Icmp( statname, "envirosuit" ) ) { - owner->GivePowerUp( ENVIROSUIT, SEC2MS( atof( value ) ) ); - owner->GivePowerUp( ENVIROTIME, SEC2MS( atof( value ) ) ); - } else if ( !idStr::Icmp( statname, "berserk" ) ) { - owner->GivePowerUp( BERSERK, SEC2MS( atof( value ) ) ); - //} else if ( !idStr::Icmp( statname, "haste" ) ) { - // owner->GivePowerUp( HASTE, SEC2MS( atof( value ) ) ); -#else - } else if ( !idStr::Icmp( statname, "berserk" ) ) { - GivePowerUp( owner, BERSERK, SEC2MS( atof( value ) ) ); -#endif - } else if ( !idStr::Icmp( statname, "mega" ) ) { - GivePowerUp( owner, MEGAHEALTH, SEC2MS( atof( value ) ) ); - } else if ( !idStr::Icmp( statname, "weapon" ) ) { - tookWeapon = false; - for( pos = value; pos != NULL; pos = end ) { - end = strchr( pos, ',' ); - if ( end ) { - len = end - pos; - end++; - } else { - len = strlen( pos ); - } - - idStr weaponName( pos, 0, len ); - - // find the number of the matching weapon name - for( i = 0; i < MAX_WEAPONS; i++ ) { - if ( weaponName == spawnArgs.GetString( va( "def_weapon%d", i ) ) ) { - break; - } - } - - if ( i >= MAX_WEAPONS ) { -#ifdef _D3XP - gameLocal.Warning( "Unknown weapon '%s'", weaponName.c_str() ); - continue; -#else - gameLocal.Error( "Unknown weapon '%s'", weaponName.c_str() ); -#endif - } - - // cache the media for this weapon - weaponDecl = gameLocal.FindEntityDef( weaponName, false ); - - // don't pickup "no ammo" weapon types twice - // not for D3 SP .. there is only one case in the game where you can get a no ammo - // weapon when you might already have it, in that case it is more conistent to pick it up - if ( gameLocal.isMultiplayer && weaponDecl && ( weapons & ( 1 << i ) ) && !weaponDecl->dict.GetInt( "ammoRequired" ) ) { - continue; - } - - if ( !gameLocal.world->spawnArgs.GetBool( "no_Weapons" ) || ( weaponName == "weapon_fists" ) || ( weaponName == "weapon_soulcube" ) ) { - if ( ( weapons & ( 1 << i ) ) == 0 || gameLocal.isMultiplayer ) { - if ( owner->GetUserInfo()->GetBool( "ui_autoSwitch" ) && idealWeapon && i != owner->weapon_bloodstone_active1 && i != owner->weapon_bloodstone_active2 && i != owner->weapon_bloodstone_active3) { - assert( !gameLocal.isClient ); - *idealWeapon = i; - } - if ( owner->hud && updateHud && lastGiveTime + 1000 < gameLocal.time ) { - owner->hud->SetStateInt( "newWeapon", i ); - owner->hud->HandleNamedEvent( "newWeapon" ); - lastGiveTime = gameLocal.time; - } - weaponPulse = true; - weapons |= ( 1 << i ); - tookWeapon = true; - } - } - } - return tookWeapon; - } else if ( !idStr::Icmp( statname, "item" ) || !idStr::Icmp( statname, "icon" ) || !idStr::Icmp( statname, "name" ) ) { - // ignore these as they're handled elsewhere - return false; - } else { - // unknown item - gameLocal.Warning( "Unknown stat '%s' added to player's inventory", statname ); - return false; - } - - return true; -} - -/* -=============== -idInventoy::Drop -=============== -*/ -void idInventory::Drop( const idDict &spawnArgs, const char *weapon_classname, int weapon_index ) { - // remove the weapon bit - // also remove the ammo associated with the weapon as we pushed it in the item - assert( weapon_index != -1 || weapon_classname ); - if ( weapon_index == -1 ) { - for( weapon_index = 0; weapon_index < MAX_WEAPONS; weapon_index++ ) { - if ( !idStr::Icmp( weapon_classname, spawnArgs.GetString( va( "def_weapon%d", weapon_index ) ) ) ) { - break; - } - } - if ( weapon_index >= MAX_WEAPONS ) { - gameLocal.Error( "Unknown weapon '%s'", weapon_classname ); - } - } else if ( !weapon_classname ) { - weapon_classname = spawnArgs.GetString( va( "def_weapon%d", weapon_index ) ); - } - weapons &= ( 0xffffffff ^ ( 1 << weapon_index ) ); - ammo_t ammo_i = AmmoIndexForWeaponClass( weapon_classname, NULL ); - if ( ammo_i ) { - clip[ weapon_index ] = -1; - ammo[ ammo_i ] = 0; - } -} - -/* -=============== -idInventory::HasAmmo -=============== -*/ -int idInventory::HasAmmo( ammo_t type, int amount ) { - if ( ( type == 0 ) || !amount ) { - // always allow weapons that don't use ammo to fire - return -1; - } - - // check if we have infinite ammo - if ( ammo[ type ] < 0 ) { - return -1; - } - - // return how many shots we can fire - return ammo[ type ] / amount; - -} - -/* -=============== -idInventory::HasAmmo -=============== -*/ -int idInventory::HasAmmo( const char *weapon_classname, bool includeClip, idPlayer* owner ) { //_D3XP - int ammoRequired; - ammo_t ammo_i = AmmoIndexForWeaponClass( weapon_classname, &ammoRequired ); - -#ifdef _D3XP - int ammoCount = HasAmmo( ammo_i, ammoRequired ); - if(includeClip && owner) { - ammoCount += clip[owner->SlotForWeapon(weapon_classname)]; - } - return ammoCount; -#else - return HasAmmo( ammo_i, ammoRequired ); -#endif - -} - -#ifdef _D3XP -/* -=============== -idInventory::HasEmptyClipCannotRefill -=============== -*/ -bool idInventory::HasEmptyClipCannotRefill(const char *weapon_classname, idPlayer* owner) { - - int clipSize = clip[owner->SlotForWeapon(weapon_classname)]; - if(clipSize) { - return false; - } - - const idDeclEntityDef *decl = gameLocal.FindEntityDef( weapon_classname, false ); - if ( !decl ) { - gameLocal.Error( "Unknown weapon in decl '%s'", weapon_classname ); - } - int minclip = decl->dict.GetInt("minclipsize"); - if(!minclip) { - return false; - } - - ammo_t ammo_i = AmmoIndexForAmmoClass( decl->dict.GetString( "ammoType" ) ); - int ammoRequired = decl->dict.GetInt( "ammoRequired" ); - int ammoCount = HasAmmo( ammo_i, ammoRequired ); - if(ammoCount < minclip) { - return true; - } - return false; -} -#endif - -/* -=============== -idInventory::UseAmmo -=============== -*/ -bool idInventory::UseAmmo( ammo_t type, int amount ) { - if ( !HasAmmo( type, amount ) ) { - return false; - } - - // take an ammo away if not infinite - if ( ammo[ type ] >= 0 ) { - ammo[ type ] -= amount; - ammoPredictTime = gameLocal.time; // mp client: we predict this. mark time so we're not confused by snapshots - } - - return true; -} - -/* -=============== -idInventory::UpdateArmor -=============== -*/ -void idInventory::UpdateArmor( void ) { - if ( deplete_armor != 0.0f && deplete_armor < armor ) { - if ( !nextArmorDepleteTime ) { - nextArmorDepleteTime = gameLocal.time + deplete_rate * 1000; - } else if ( gameLocal.time > nextArmorDepleteTime ) { - armor -= deplete_ammount; - if ( armor < deplete_armor ) { - armor = deplete_armor; - } - nextArmorDepleteTime = gameLocal.time + deplete_rate * 1000; - } - } -} - -#ifdef _D3XP -/* -=============== -idInventory::InitRechargeAmmo -=============== -* Loads any recharge ammo definitions from the ammo_types entity definitions. -*/ -void idInventory::InitRechargeAmmo(idPlayer *owner) { - - memset (rechargeAmmo, 0, sizeof(rechargeAmmo)); - - const idKeyValue *kv = owner->spawnArgs.MatchPrefix( "ammorecharge_" ); - while( kv ) { - idStr key = kv->GetKey(); - idStr ammoname = key.Right(key.Length()- strlen("ammorecharge_")); - int ammoType = AmmoIndexForAmmoClass(ammoname); - rechargeAmmo[ammoType].ammo = (atof(kv->GetValue().c_str())*1000); - strcpy(rechargeAmmo[ammoType].ammoName, ammoname); - kv = owner->spawnArgs.MatchPrefix( "ammorecharge_", kv ); - } -} - -/* -=============== -idInventory::RechargeAmmo -=============== -* Called once per frame to update any ammo amount for ammo types that recharge. -*/ -void idInventory::RechargeAmmo(idPlayer *owner) { - - for(int i = 0; i < AMMO_NUMTYPES; i++) { - if(rechargeAmmo[i].ammo > 0) { - if(!rechargeAmmo[i].rechargeTime) { - //Initialize the recharge timer. - rechargeAmmo[i].rechargeTime = gameLocal.time; - } - int elapsed = gameLocal.time - rechargeAmmo[i].rechargeTime; - if(elapsed >= rechargeAmmo[i].ammo) { - int intervals = (gameLocal.time - rechargeAmmo[i].rechargeTime)/rechargeAmmo[i].ammo; - ammo[i] += intervals; - - int max = MaxAmmoForAmmoClass(owner, rechargeAmmo[i].ammoName); - if(max > 0) { - if(ammo[i] > max) { - ammo[i] = max; - } - } - rechargeAmmo[i].rechargeTime += intervals*rechargeAmmo[i].ammo; - } - } - } -} - -/* -=============== -idInventory::CanGive -=============== -*/ -bool idInventory::CanGive( idPlayer *owner, const idDict &spawnArgs, const char *statname, const char *value, int *idealWeapon ) { - - if ( !idStr::Icmp( statname, "ammo_bloodstone" ) ) { - int max = MaxAmmoForAmmoClass(owner, statname); - int i = AmmoIndexForAmmoClass(statname); - - if(max <= 0) { - //No Max - return true; - } else { - //Already at or above the max so don't allow the give - if(ammo[ i ] >= max) { - ammo[ i ] = max; - return false; - } - return true; - } - } else if ( !idStr::Icmp( statname, "item" ) || !idStr::Icmp( statname, "icon" ) || !idStr::Icmp( statname, "name" ) ) { - // ignore these as they're handled elsewhere - //These items should not be considered as succesful gives because it messes up the max ammo items - return false; - } - return true; -} -#endif - -/* -============== -idPlayer::idPlayer -============== -*/ -idPlayer::idPlayer() { - memset( &usercmd, 0, sizeof( usercmd ) ); - - noclip = false; - godmode = false; - - spawnAnglesSet = false; - spawnAngles = ang_zero; - viewAngles = ang_zero; - cmdAngles = ang_zero; - - oldButtons = 0; - buttonMask = 0; - oldFlags = 0; - - lastHitTime = 0; - lastSndHitTime = 0; - lastSavingThrowTime = 0; - - weapon = NULL; - - hud = NULL; - objectiveSystem = NULL; - objectiveSystemOpen = false; - -#ifdef _D3XP - mountedObject = NULL; - enviroSuitLight = NULL; -#endif - - heartRate = BASE_HEARTRATE; - heartInfo.Init( 0, 0, 0, 0 ); - lastHeartAdjust = 0; - lastHeartBeat = 0; - lastDmgTime = 0; - deathClearContentsTime = 0; - lastArmorPulse = -10000; - stamina = 0.0f; - healthPool = 0.0f; - nextHealthPulse = 0; - healthPulse = false; - nextHealthTake = 0; - healthTake = false; - - scoreBoardOpen = false; - forceScoreBoard = false; - forceRespawn = false; - spectating = false; - spectator = 0; - colorBar = vec3_zero; - colorBarIndex = 0; - forcedReady = false; - wantSpectate = false; - -#ifdef CTF - carryingFlag = false; -#endif - - lastHitToggle = false; - - minRespawnTime = 0; - maxRespawnTime = 0; - - firstPersonViewOrigin = vec3_zero; - firstPersonViewAxis = mat3_identity; - - hipJoint = INVALID_JOINT; - chestJoint = INVALID_JOINT; - headJoint = INVALID_JOINT; - - bobFoot = 0; - bobFrac = 0.0f; - bobfracsin = 0.0f; - bobCycle = 0; - xyspeed = 0.0f; - stepUpTime = 0; - stepUpDelta = 0.0f; - idealLegsYaw = 0.0f; - legsYaw = 0.0f; - legsForward = true; - oldViewYaw = 0.0f; - viewBobAngles = ang_zero; - viewBob = vec3_zero; - landChange = 0; - landTime = 0; - - currentWeapon = -1; - idealWeapon = -1; - previousWeapon = -1; - weaponSwitchTime = 0; - weaponEnabled = true; - weapon_soulcube = -1; - weapon_pda = -1; - weapon_fists = -1; -#ifdef _D3XP - weapon_bloodstone = -1; - weapon_bloodstone_active1 = -1; - weapon_bloodstone_active2 = -1; - weapon_bloodstone_active3 = -1; - harvest_lock = false; - - hudPowerup = -1; - lastHudPowerup = -1; - hudPowerupDuration = 0; -#endif - showWeaponViewModel = true; - - skin = NULL; - powerUpSkin = NULL; - baseSkinName = ""; - - numProjectilesFired = 0; - numProjectileHits = 0; - - airless = false; - airTics = 0; - lastAirDamage = 0; - - gibDeath = false; - gibsLaunched = false; - gibsDir = vec3_zero; - - zoomFov.Init( 0, 0, 0, 0 ); - centerView.Init( 0, 0, 0, 0 ); - fxFov = false; - - influenceFov = 0; - influenceActive = 0; - influenceRadius = 0.0f; - influenceEntity = NULL; - influenceMaterial = NULL; - influenceSkin = NULL; - - privateCameraView = NULL; - - memset( loggedViewAngles, 0, sizeof( loggedViewAngles ) ); - memset( loggedAccel, 0, sizeof( loggedAccel ) ); - currentLoggedAccel = 0; - - focusTime = 0; - focusGUIent = NULL; - focusUI = NULL; - focusCharacter = NULL; - talkCursor = 0; - focusVehicle = NULL; - cursor = NULL; - - oldMouseX = 0; - oldMouseY = 0; - - pdaAudio = ""; - pdaVideo = ""; - pdaVideoWave = ""; - - lastDamageDef = 0; - lastDamageDir = vec3_zero; - lastDamageLocation = 0; - smoothedFrame = 0; - smoothedOriginUpdated = false; - smoothedOrigin = vec3_zero; - smoothedAngles = ang_zero; - - fl.networkSync = true; - - latchedTeam = -1; - doingDeathSkin = false; - weaponGone = false; - useInitialSpawns = false; - tourneyRank = 0; - lastSpectateTeleport = 0; - tourneyLine = 0; - hiddenWeapon = false; - tipUp = false; - objectiveUp = false; - teleportEntity = NULL; - teleportKiller = -1; - respawning = false; - ready = false; - leader = false; - lastSpectateChange = 0; - lastTeleFX = -9999; - weaponCatchup = false; - lastSnapshotSequence = 0; - - MPAim = -1; - lastMPAim = -1; - lastMPAimTime = 0; - MPAimFadeTime = 0; - MPAimHighlight = false; - - spawnedTime = 0; - lastManOver = false; - lastManPlayAgain = false; - lastManPresent = false; - - isTelefragged = false; - - isLagged = false; - isChatting = false; - - selfSmooth = false; -} - -/* -============== -idPlayer::LinkScriptVariables - -set up conditions for animation -============== -*/ -void idPlayer::LinkScriptVariables( void ) { - AI_FORWARD.LinkTo( scriptObject, "AI_FORWARD" ); - AI_BACKWARD.LinkTo( scriptObject, "AI_BACKWARD" ); - AI_STRAFE_LEFT.LinkTo( scriptObject, "AI_STRAFE_LEFT" ); - AI_STRAFE_RIGHT.LinkTo( scriptObject, "AI_STRAFE_RIGHT" ); - AI_ATTACK_HELD.LinkTo( scriptObject, "AI_ATTACK_HELD" ); - AI_WEAPON_FIRED.LinkTo( scriptObject, "AI_WEAPON_FIRED" ); - AI_JUMP.LinkTo( scriptObject, "AI_JUMP" ); - AI_DEAD.LinkTo( scriptObject, "AI_DEAD" ); - AI_CROUCH.LinkTo( scriptObject, "AI_CROUCH" ); - AI_ONGROUND.LinkTo( scriptObject, "AI_ONGROUND" ); - AI_ONLADDER.LinkTo( scriptObject, "AI_ONLADDER" ); - AI_HARDLANDING.LinkTo( scriptObject, "AI_HARDLANDING" ); - AI_SOFTLANDING.LinkTo( scriptObject, "AI_SOFTLANDING" ); - AI_RUN.LinkTo( scriptObject, "AI_RUN" ); - AI_PAIN.LinkTo( scriptObject, "AI_PAIN" ); - AI_RELOAD.LinkTo( scriptObject, "AI_RELOAD" ); - AI_TELEPORT.LinkTo( scriptObject, "AI_TELEPORT" ); - AI_TURN_LEFT.LinkTo( scriptObject, "AI_TURN_LEFT" ); - AI_TURN_RIGHT.LinkTo( scriptObject, "AI_TURN_RIGHT" ); -} - -/* -============== -idPlayer::SetupWeaponEntity -============== -*/ -void idPlayer::SetupWeaponEntity( void ) { - int w; - const char *weap; - - if ( weapon.GetEntity() ) { - // get rid of old weapon - weapon.GetEntity()->Clear(); - currentWeapon = -1; - } else if ( !gameLocal.isClient ) { - weapon = static_cast( gameLocal.SpawnEntityType( idWeapon::Type, NULL ) ); - weapon.GetEntity()->SetOwner( this ); - currentWeapon = -1; - } - - for( w = 0; w < MAX_WEAPONS; w++ ) { - weap = spawnArgs.GetString( va( "def_weapon%d", w ) ); - if ( weap && *weap ) { - idWeapon::CacheWeapon( weap ); - } - } -} - -/* -============== -idPlayer::Init -============== -*/ -void idPlayer::Init( void ) { - const char *value; - const idKeyValue *kv; - - noclip = false; - godmode = false; - - oldButtons = 0; - oldFlags = 0; - - currentWeapon = -1; - idealWeapon = -1; - previousWeapon = -1; - weaponSwitchTime = 0; - weaponEnabled = true; - weapon_soulcube = SlotForWeapon( "weapon_soulcube" ); - weapon_pda = SlotForWeapon( "weapon_pda" ); - weapon_fists = SlotForWeapon( "weapon_fists" ); -#ifdef _D3XP - weapon_bloodstone = SlotForWeapon( "weapon_bloodstone_passive" ); - weapon_bloodstone_active1 = SlotForWeapon( "weapon_bloodstone_active1" ); - weapon_bloodstone_active2 = SlotForWeapon( "weapon_bloodstone_active2" ); - weapon_bloodstone_active3 = SlotForWeapon( "weapon_bloodstone_active3" ); - harvest_lock = false; -#endif - showWeaponViewModel = GetUserInfo()->GetBool( "ui_showGun" ); - - - lastDmgTime = 0; - lastArmorPulse = -10000; - lastHeartAdjust = 0; - lastHeartBeat = 0; - heartInfo.Init( 0, 0, 0, 0 ); - - bobCycle = 0; - bobFrac = 0.0f; - landChange = 0; - landTime = 0; - zoomFov.Init( 0, 0, 0, 0 ); - centerView.Init( 0, 0, 0, 0 ); - fxFov = false; - - influenceFov = 0; - influenceActive = 0; - influenceRadius = 0.0f; - influenceEntity = NULL; - influenceMaterial = NULL; - influenceSkin = NULL; - -#ifdef _D3XP - mountedObject = NULL; - if( enviroSuitLight.IsValid() ) { - enviroSuitLight.GetEntity()->PostEventMS( &EV_Remove, 0 ); - } - enviroSuitLight = NULL; - healthRecharge = false; - lastHealthRechargeTime = 0; - rechargeSpeed = 500; - new_g_damageScale = 1.f; - bloomEnabled = false; - bloomSpeed = 1.f; - bloomIntensity = -0.01f; - inventory.InitRechargeAmmo(this); - hudPowerup = -1; - lastHudPowerup = -1; - hudPowerupDuration = 0; -#endif - - currentLoggedAccel = 0; - - focusTime = 0; - focusGUIent = NULL; - focusUI = NULL; - focusCharacter = NULL; - talkCursor = 0; - focusVehicle = NULL; - - // remove any damage effects - playerView.ClearEffects(); - - // damage values - fl.takedamage = true; - ClearPain(); - - // restore persistent data - RestorePersistantInfo(); - - bobCycle = 0; - stamina = 0.0f; - healthPool = 0.0f; - nextHealthPulse = 0; - healthPulse = false; - nextHealthTake = 0; - healthTake = false; - - SetupWeaponEntity(); - currentWeapon = -1; - previousWeapon = -1; - - heartRate = BASE_HEARTRATE; - AdjustHeartRate( BASE_HEARTRATE, 0.0f, 0.0f, true ); - - idealLegsYaw = 0.0f; - legsYaw = 0.0f; - legsForward = true; - oldViewYaw = 0.0f; - - // set the pm_ cvars - if ( !gameLocal.isMultiplayer || gameLocal.isServer ) { - kv = spawnArgs.MatchPrefix( "pm_", NULL ); - while( kv ) { - cvarSystem->SetCVarString( kv->GetKey(), kv->GetValue() ); - kv = spawnArgs.MatchPrefix( "pm_", kv ); - } - } - - // disable stamina on hell levels - if ( gameLocal.world && gameLocal.world->spawnArgs.GetBool( "no_stamina" ) ) { - pm_stamina.SetFloat( 0.0f ); - } - - // stamina always initialized to maximum - stamina = pm_stamina.GetFloat(); - - // air always initialized to maximum too - airTics = pm_airTics.GetFloat(); - airless = false; - - gibDeath = false; - gibsLaunched = false; - gibsDir.Zero(); - - // set the gravity - physicsObj.SetGravity( gameLocal.GetGravity() ); - - // start out standing - SetEyeHeight( pm_normalviewheight.GetFloat() ); - - stepUpTime = 0; - stepUpDelta = 0.0f; - viewBobAngles.Zero(); - viewBob.Zero(); - - value = spawnArgs.GetString( "model" ); - if ( value && ( *value != 0 ) ) { - SetModel( value ); - } - - if ( cursor ) { - cursor->SetStateInt( "talkcursor", 0 ); - cursor->SetStateString( "combatcursor", "1" ); - cursor->SetStateString( "itemcursor", "0" ); - cursor->SetStateString( "guicursor", "0" ); -#ifdef _D3XP - cursor->SetStateString( "grabbercursor", "0" ); -#endif - } - - if ( ( gameLocal.isMultiplayer || g_testDeath.GetBool() ) && skin ) { - SetSkin( skin ); - renderEntity.shaderParms[6] = 0.0f; - } else if ( spawnArgs.GetString( "spawn_skin", NULL, &value ) ) { - skin = declManager->FindSkin( value ); - SetSkin( skin ); - renderEntity.shaderParms[6] = 0.0f; - } - - value = spawnArgs.GetString( "bone_hips", "" ); - hipJoint = animator.GetJointHandle( value ); - if ( hipJoint == INVALID_JOINT ) { - gameLocal.Error( "Joint '%s' not found for 'bone_hips' on '%s'", value, name.c_str() ); - } - - value = spawnArgs.GetString( "bone_chest", "" ); - chestJoint = animator.GetJointHandle( value ); - if ( chestJoint == INVALID_JOINT ) { - gameLocal.Error( "Joint '%s' not found for 'bone_chest' on '%s'", value, name.c_str() ); - } - - value = spawnArgs.GetString( "bone_head", "" ); - headJoint = animator.GetJointHandle( value ); - if ( headJoint == INVALID_JOINT ) { - gameLocal.Error( "Joint '%s' not found for 'bone_head' on '%s'", value, name.c_str() ); - } - - // initialize the script variables - AI_FORWARD = false; - AI_BACKWARD = false; - AI_STRAFE_LEFT = false; - AI_STRAFE_RIGHT = false; - AI_ATTACK_HELD = false; - AI_WEAPON_FIRED = false; - AI_JUMP = false; - AI_DEAD = false; - AI_CROUCH = false; - AI_ONGROUND = true; - AI_ONLADDER = false; - AI_HARDLANDING = false; - AI_SOFTLANDING = false; - AI_RUN = false; - AI_PAIN = false; - AI_RELOAD = false; - AI_TELEPORT = false; - AI_TURN_LEFT = false; - AI_TURN_RIGHT = false; - - // reset the script object - ConstructScriptObject(); - - // execute the script so the script object's constructor takes effect immediately - scriptThread->Execute(); - - forceScoreBoard = false; - forcedReady = false; - - privateCameraView = NULL; - - lastSpectateChange = 0; - lastTeleFX = -9999; - - hiddenWeapon = false; - tipUp = false; - objectiveUp = false; - teleportEntity = NULL; - teleportKiller = -1; - leader = false; - - SetPrivateCameraView( NULL ); - - lastSnapshotSequence = 0; - - MPAim = -1; - lastMPAim = -1; - lastMPAimTime = 0; - MPAimFadeTime = 0; - MPAimHighlight = false; - - if ( hud ) { - hud->HandleNamedEvent( "aim_clear" ); - } - - //isChatting = false; - cvarSystem->SetCVarBool("ui_chat", false); -} - -/* -============== -idPlayer::Spawn - -Prepare any resources used by the player. -============== -*/ -void idPlayer::Spawn( void ) { - idStr temp; - idBounds bounds; - - if ( entityNumber >= MAX_CLIENTS ) { - gameLocal.Error( "entityNum > MAX_CLIENTS for player. Player may only be spawned with a client." ); - } - - // allow thinking during cinematics - cinematic = true; - - if ( gameLocal.isMultiplayer ) { - // always start in spectating state waiting to be spawned in - // do this before SetClipModel to get the right bounding box - spectating = true; - } - - // set our collision model - physicsObj.SetSelf( this ); - SetClipModel(); - physicsObj.SetMass( spawnArgs.GetFloat( "mass", "100" ) ); - physicsObj.SetContents( CONTENTS_BODY ); - physicsObj.SetClipMask( MASK_PLAYERSOLID ); - SetPhysics( &physicsObj ); - InitAASLocation(); - - skin = renderEntity.customSkin; - - // only the local player needs guis - if ( !gameLocal.isMultiplayer || entityNumber == gameLocal.localClientNum ) { - - // load HUD - if ( gameLocal.isMultiplayer ) { - hud = uiManager->FindGui( "guis/mphud.gui", true, false, true ); - } else if ( spawnArgs.GetString( "hud", "", temp ) ) { - hud = uiManager->FindGui( temp, true, false, true ); - } - if ( hud ) { - hud->Activate( true, gameLocal.time ); -#ifdef CTF - if ( gameLocal.mpGame.IsGametypeFlagBased() ) { - hud->SetStateInt( "red_team_score", gameLocal.mpGame.GetFlagPoints(0) ); - hud->SetStateInt( "blue_team_score", gameLocal.mpGame.GetFlagPoints(1) ); - } -#endif - } - - // load cursor - if ( spawnArgs.GetString( "cursor", "", temp ) ) { - cursor = uiManager->FindGui( temp, true, gameLocal.isMultiplayer, gameLocal.isMultiplayer ); - } - if ( cursor ) { - cursor->Activate( true, gameLocal.time ); - } - - objectiveSystem = uiManager->FindGui( "guis/pda.gui", true, false, true ); - objectiveSystemOpen = false; - } - - SetLastHitTime( 0 ); - - // load the armor sound feedback - declManager->FindSound( "player_sounds_hitArmor" ); - - // set up conditions for animation - LinkScriptVariables(); - - animator.RemoveOriginOffset( true ); - - // initialize user info related settings - // on server, we wait for the userinfo broadcast, as this controls when the player is initially spawned in game - if ( gameLocal.isClient || entityNumber == gameLocal.localClientNum ) { - UserInfoChanged( false ); - } - - // create combat collision hull for exact collision detection - SetCombatModel(); - - // init the damage effects - playerView.SetPlayerEntity( this ); - - // supress model in non-player views, but allow it in mirrors and remote views - renderEntity.suppressSurfaceInViewID = entityNumber+1; - - // don't project shadow on self or weapon - renderEntity.noSelfShadow = true; - - idAFAttachment *headEnt = head.GetEntity(); - if ( headEnt ) { - headEnt->GetRenderEntity()->suppressSurfaceInViewID = entityNumber+1; - headEnt->GetRenderEntity()->noSelfShadow = true; - } - - if ( gameLocal.isMultiplayer ) { - Init(); - Hide(); // properly hidden if starting as a spectator - if ( !gameLocal.isClient ) { - // set yourself ready to spawn. idMultiplayerGame will decide when/if appropriate and call SpawnFromSpawnSpot - SetupWeaponEntity(); - SpawnFromSpawnSpot(); - forceRespawn = true; - assert( spectating ); - } - } else { - SetupWeaponEntity(); - SpawnFromSpawnSpot(); - } - - // trigger playtesting item gives, if we didn't get here from a previous level - // the devmap key will be set on the first devmap, but cleared on any level - // transitions - if ( !gameLocal.isMultiplayer && gameLocal.serverInfo.FindKey( "devmap" ) ) { - // fire a trigger with the name "devmap" - idEntity *ent = gameLocal.FindEntity( "devmap" ); - if ( ent ) { - ent->ActivateTargets( this ); - } - } - if ( hud ) { - // We can spawn with a full soul cube, so we need to make sure the hud knows this -#ifndef _D3XP - if ( weapon_soulcube > 0 && ( inventory.weapons & ( 1 << weapon_soulcube ) ) ) { - int max_souls = inventory.MaxAmmoForAmmoClass( this, "ammo_souls" ); - if ( inventory.ammo[ idWeapon::GetAmmoNumForName( "ammo_souls" ) ] >= max_souls ) { - hud->HandleNamedEvent( "soulCubeReady" ); - } - } -#endif -#ifdef _D3XP - //We can spawn with a full bloodstone, so make sure the hud knows - if ( weapon_bloodstone > 0 && ( inventory.weapons & ( 1 << weapon_bloodstone ) ) ) { - //int max_blood = inventory.MaxAmmoForAmmoClass( this, "ammo_bloodstone" ); - //if ( inventory.ammo[ idWeapon::GetAmmoNumForName( "ammo_bloodstone" ) ] >= max_blood ) { - hud->HandleNamedEvent( "bloodstoneReady" ); - //} - } -#endif - hud->HandleNamedEvent( "itemPickup" ); - } - - if ( GetPDA() ) { - // Add any emails from the inventory - for ( int i = 0; i < inventory.emails.Num(); i++ ) { - GetPDA()->AddEmail( inventory.emails[i] ); - } - GetPDA()->SetSecurity( common->GetLanguageDict()->GetString( "#str_00066" ) ); - } - - if ( gameLocal.world->spawnArgs.GetBool( "no_Weapons" ) ) { - hiddenWeapon = true; - if ( weapon.GetEntity() ) { - weapon.GetEntity()->LowerWeapon(); - } - idealWeapon = 0; - } else { - hiddenWeapon = false; - } - - if ( hud ) { - UpdateHudWeapon(); - hud->StateChanged( gameLocal.time ); - } - - tipUp = false; - objectiveUp = false; - - if ( inventory.levelTriggers.Num() ) { - PostEventMS( &EV_Player_LevelTrigger, 0 ); - } - - inventory.pdaOpened = false; - inventory.selPDA = 0; - - if ( !gameLocal.isMultiplayer ) { - if ( g_skill.GetInteger() < 2 ) { - if ( health < 25 ) { - health = 25; - } - if ( g_useDynamicProtection.GetBool() ) { -#ifdef _D3XP - new_g_damageScale = 1.0f; -#else - g_damageScale.SetFloat( 1.0f ); -#endif - } - } else { -#ifdef _D3XP - new_g_damageScale = 1.0f; -#else - g_damageScale.SetFloat( 1.0f ); -#endif - g_armorProtection.SetFloat( ( g_skill.GetInteger() < 2 ) ? 0.4f : 0.2f ); - - if ( g_skill.GetInteger() == 3 ) { - healthTake = true; - nextHealthTake = gameLocal.time + g_healthTakeTime.GetInteger() * 1000; - } - } - } - -#ifdef _D3XP - //Setup the weapon toggle lists - const idKeyValue *kv; - kv = spawnArgs.MatchPrefix( "weapontoggle", NULL ); - while( kv ) { - WeaponToggle_t newToggle; - strcpy(newToggle.name, kv->GetKey().c_str()); - - idStr toggleData = kv->GetValue(); - - idLexer src; - idToken token; - src.LoadMemory(toggleData, toggleData.Length(), "toggleData"); - while(1) { - if(!src.ReadToken(&token)) { - break; - } - int index = atoi(token.c_str()); - newToggle.toggleList.Append(index); - - //Skip the , - src.ReadToken(&token); - } - weaponToggles.Set(newToggle.name, newToggle); - - kv = spawnArgs.MatchPrefix( "weapontoggle", kv ); - } -#endif - -#ifdef _D3XP - if(g_skill.GetInteger() >= 3) { - if(!WeaponAvailable("weapon_bloodstone_passive")) { - GiveInventoryItem("weapon_bloodstone_passive"); - } - if(!WeaponAvailable("weapon_bloodstone_active1")) { - GiveInventoryItem("weapon_bloodstone_active1"); - } - if(!WeaponAvailable("weapon_bloodstone_active2")) { - GiveInventoryItem("weapon_bloodstone_active2"); - } - if(!WeaponAvailable("weapon_bloodstone_active3")) { - GiveInventoryItem("weapon_bloodstone_active3"); - } - } - - bloomEnabled = false; - bloomSpeed = 1; - bloomIntensity = -0.01f; -#endif -} - -/* -============== -idPlayer::~idPlayer() - -Release any resources used by the player. -============== -*/ -idPlayer::~idPlayer() { - delete weapon.GetEntity(); - weapon = NULL; -#ifdef CTF - if ( enviroSuitLight.IsValid() ) { - enviroSuitLight.GetEntity()->ProcessEvent( &EV_Remove ); - } - // have to do this here, idMultiplayerGame::DisconnectClient() is too late - if ( gameLocal.isMultiplayer && gameLocal.mpGame.IsGametypeFlagBased() ) { - ReturnFlag(); - } -#endif -} - -/* -=========== -idPlayer::Save -=========== -*/ -void idPlayer::Save( idSaveGame *savefile ) const { - int i; - - savefile->WriteUsercmd( usercmd ); - playerView.Save( savefile ); - - savefile->WriteBool( noclip ); - savefile->WriteBool( godmode ); - - // don't save spawnAnglesSet, since we'll have to reset them after loading the savegame - savefile->WriteAngles( spawnAngles ); - savefile->WriteAngles( viewAngles ); - savefile->WriteAngles( cmdAngles ); - - savefile->WriteInt( buttonMask ); - savefile->WriteInt( oldButtons ); - savefile->WriteInt( oldFlags ); - - savefile->WriteInt( lastHitTime ); - savefile->WriteInt( lastSndHitTime ); - savefile->WriteInt( lastSavingThrowTime ); - - // idBoolFields don't need to be saved, just re-linked in Restore - - inventory.Save( savefile ); - weapon.Save( savefile ); - - savefile->WriteUserInterface( hud, false ); - savefile->WriteUserInterface( objectiveSystem, false ); - savefile->WriteBool( objectiveSystemOpen ); - - savefile->WriteInt( weapon_soulcube ); - savefile->WriteInt( weapon_pda ); - savefile->WriteInt( weapon_fists ); -#ifdef _D3XP - savefile->WriteInt( weapon_bloodstone ); - savefile->WriteInt( weapon_bloodstone_active1 ); - savefile->WriteInt( weapon_bloodstone_active2 ); - savefile->WriteInt( weapon_bloodstone_active3 ); - savefile->WriteBool( harvest_lock ); - savefile->WriteInt( hudPowerup ); - savefile->WriteInt( lastHudPowerup ); - savefile->WriteInt( hudPowerupDuration ); - - -#endif - - savefile->WriteInt( heartRate ); - - savefile->WriteFloat( heartInfo.GetStartTime() ); - savefile->WriteFloat( heartInfo.GetDuration() ); - savefile->WriteFloat( heartInfo.GetStartValue() ); - savefile->WriteFloat( heartInfo.GetEndValue() ); - - savefile->WriteInt( lastHeartAdjust ); - savefile->WriteInt( lastHeartBeat ); - savefile->WriteInt( lastDmgTime ); - savefile->WriteInt( deathClearContentsTime ); - savefile->WriteBool( doingDeathSkin ); - savefile->WriteInt( lastArmorPulse ); - savefile->WriteFloat( stamina ); - savefile->WriteFloat( healthPool ); - savefile->WriteInt( nextHealthPulse ); - savefile->WriteBool( healthPulse ); - savefile->WriteInt( nextHealthTake ); - savefile->WriteBool( healthTake ); - - savefile->WriteBool( hiddenWeapon ); - soulCubeProjectile.Save( savefile ); - - savefile->WriteInt( spectator ); - savefile->WriteVec3( colorBar ); - savefile->WriteInt( colorBarIndex ); - savefile->WriteBool( scoreBoardOpen ); - savefile->WriteBool( forceScoreBoard ); - savefile->WriteBool( forceRespawn ); - savefile->WriteBool( spectating ); - savefile->WriteInt( lastSpectateTeleport ); - savefile->WriteBool( lastHitToggle ); - savefile->WriteBool( forcedReady ); - savefile->WriteBool( wantSpectate ); - savefile->WriteBool( weaponGone ); - savefile->WriteBool( useInitialSpawns ); - savefile->WriteInt( latchedTeam ); - savefile->WriteInt( tourneyRank ); - savefile->WriteInt( tourneyLine ); - - teleportEntity.Save( savefile ); - savefile->WriteInt( teleportKiller ); - - savefile->WriteInt( minRespawnTime ); - savefile->WriteInt( maxRespawnTime ); - - savefile->WriteVec3( firstPersonViewOrigin ); - savefile->WriteMat3( firstPersonViewAxis ); - - // don't bother saving dragEntity since it's a dev tool - - savefile->WriteJoint( hipJoint ); - savefile->WriteJoint( chestJoint ); - savefile->WriteJoint( headJoint ); - - savefile->WriteStaticObject( physicsObj ); - - savefile->WriteInt( aasLocation.Num() ); - for( i = 0; i < aasLocation.Num(); i++ ) { - savefile->WriteInt( aasLocation[ i ].areaNum ); - savefile->WriteVec3( aasLocation[ i ].pos ); - } - - savefile->WriteInt( bobFoot ); - savefile->WriteFloat( bobFrac ); - savefile->WriteFloat( bobfracsin ); - savefile->WriteInt( bobCycle ); - savefile->WriteFloat( xyspeed ); - savefile->WriteInt( stepUpTime ); - savefile->WriteFloat( stepUpDelta ); - savefile->WriteFloat( idealLegsYaw ); - savefile->WriteFloat( legsYaw ); - savefile->WriteBool( legsForward ); - savefile->WriteFloat( oldViewYaw ); - savefile->WriteAngles( viewBobAngles ); - savefile->WriteVec3( viewBob ); - savefile->WriteInt( landChange ); - savefile->WriteInt( landTime ); - - savefile->WriteInt( currentWeapon ); - savefile->WriteInt( idealWeapon ); - savefile->WriteInt( previousWeapon ); - savefile->WriteInt( weaponSwitchTime ); - savefile->WriteBool( weaponEnabled ); - savefile->WriteBool( showWeaponViewModel ); - - savefile->WriteSkin( skin ); - savefile->WriteSkin( powerUpSkin ); - savefile->WriteString( baseSkinName ); - - savefile->WriteInt( numProjectilesFired ); - savefile->WriteInt( numProjectileHits ); - - savefile->WriteBool( airless ); - savefile->WriteInt( airTics ); - savefile->WriteInt( lastAirDamage ); - - savefile->WriteBool( gibDeath ); - savefile->WriteBool( gibsLaunched ); - savefile->WriteVec3( gibsDir ); - - savefile->WriteFloat( zoomFov.GetStartTime() ); - savefile->WriteFloat( zoomFov.GetDuration() ); - savefile->WriteFloat( zoomFov.GetStartValue() ); - savefile->WriteFloat( zoomFov.GetEndValue() ); - - savefile->WriteFloat( centerView.GetStartTime() ); - savefile->WriteFloat( centerView.GetDuration() ); - savefile->WriteFloat( centerView.GetStartValue() ); - savefile->WriteFloat( centerView.GetEndValue() ); - - savefile->WriteBool( fxFov ); - - savefile->WriteFloat( influenceFov ); - savefile->WriteInt( influenceActive ); - savefile->WriteFloat( influenceRadius ); - savefile->WriteObject( influenceEntity ); - savefile->WriteMaterial( influenceMaterial ); - savefile->WriteSkin( influenceSkin ); - - savefile->WriteObject( privateCameraView ); - - for( i = 0; i < NUM_LOGGED_VIEW_ANGLES; i++ ) { - savefile->WriteAngles( loggedViewAngles[ i ] ); - } - for( i = 0; i < NUM_LOGGED_ACCELS; i++ ) { - savefile->WriteInt( loggedAccel[ i ].time ); - savefile->WriteVec3( loggedAccel[ i ].dir ); - } - savefile->WriteInt( currentLoggedAccel ); - - savefile->WriteObject( focusGUIent ); - // can't save focusUI - savefile->WriteObject( focusCharacter ); - savefile->WriteInt( talkCursor ); - savefile->WriteInt( focusTime ); - savefile->WriteObject( focusVehicle ); - savefile->WriteUserInterface( cursor, false ); - - savefile->WriteInt( oldMouseX ); - savefile->WriteInt( oldMouseY ); - - savefile->WriteString( pdaAudio ); - savefile->WriteString( pdaVideo ); - savefile->WriteString( pdaVideoWave ); - - savefile->WriteBool( tipUp ); - savefile->WriteBool( objectiveUp ); - - savefile->WriteInt( lastDamageDef ); - savefile->WriteVec3( lastDamageDir ); - savefile->WriteInt( lastDamageLocation ); - savefile->WriteInt( smoothedFrame ); - savefile->WriteBool( smoothedOriginUpdated ); - savefile->WriteVec3( smoothedOrigin ); - savefile->WriteAngles( smoothedAngles ); - - savefile->WriteBool( ready ); - savefile->WriteBool( respawning ); - savefile->WriteBool( leader ); - savefile->WriteInt( lastSpectateChange ); - savefile->WriteInt( lastTeleFX ); - - savefile->WriteFloat( pm_stamina.GetFloat() ); - - if ( hud ) { - hud->SetStateString( "message", common->GetLanguageDict()->GetString( "#str_02916" ) ); - hud->HandleNamedEvent( "Message" ); - } - -#ifdef _D3XP - savefile->WriteInt(weaponToggles.Num()); - for(i = 0; i < weaponToggles.Num(); i++) { - WeaponToggle_t* weaponToggle = weaponToggles.GetIndex(i); - savefile->WriteString(weaponToggle->name); - savefile->WriteInt(weaponToggle->toggleList.Num()); - for(int j = 0; j < weaponToggle->toggleList.Num(); j++) { - savefile->WriteInt(weaponToggle->toggleList[j]); - } - } - savefile->WriteObject( mountedObject ); - enviroSuitLight.Save( savefile ); - savefile->WriteBool( healthRecharge ); - savefile->WriteInt( lastHealthRechargeTime ); - savefile->WriteInt( rechargeSpeed ); - savefile->WriteFloat( new_g_damageScale ); - - savefile->WriteBool( bloomEnabled ); - savefile->WriteFloat( bloomSpeed ); - savefile->WriteFloat( bloomIntensity ); - -#endif -} - -/* -=========== -idPlayer::Restore -=========== -*/ -void idPlayer::Restore( idRestoreGame *savefile ) { - int i; - int num; - float set; - - savefile->ReadUsercmd( usercmd ); - playerView.Restore( savefile ); - - savefile->ReadBool( noclip ); - savefile->ReadBool( godmode ); - - savefile->ReadAngles( spawnAngles ); - savefile->ReadAngles( viewAngles ); - savefile->ReadAngles( cmdAngles ); - - memset( usercmd.angles, 0, sizeof( usercmd.angles ) ); - SetViewAngles( viewAngles ); - spawnAnglesSet = true; - - savefile->ReadInt( buttonMask ); - savefile->ReadInt( oldButtons ); - savefile->ReadInt( oldFlags ); - - usercmd.flags = 0; - oldFlags = 0; - - savefile->ReadInt( lastHitTime ); - savefile->ReadInt( lastSndHitTime ); - savefile->ReadInt( lastSavingThrowTime ); - - // Re-link idBoolFields to the scriptObject, values will be restored in scriptObject's restore - LinkScriptVariables(); - - inventory.Restore( savefile ); - weapon.Restore( savefile ); - - for ( i = 0; i < inventory.emails.Num(); i++ ) { - GetPDA()->AddEmail( inventory.emails[i] ); - } - - savefile->ReadUserInterface( hud ); - savefile->ReadUserInterface( objectiveSystem ); - savefile->ReadBool( objectiveSystemOpen ); - - savefile->ReadInt( weapon_soulcube ); - savefile->ReadInt( weapon_pda ); - savefile->ReadInt( weapon_fists ); -#ifdef _D3XP - savefile->ReadInt( weapon_bloodstone ); - savefile->ReadInt( weapon_bloodstone_active1 ); - savefile->ReadInt( weapon_bloodstone_active2 ); - savefile->ReadInt( weapon_bloodstone_active3 ); - - savefile->ReadBool( harvest_lock ); - savefile->ReadInt( hudPowerup ); - savefile->ReadInt( lastHudPowerup ); - savefile->ReadInt( hudPowerupDuration ); - - -#endif - - savefile->ReadInt( heartRate ); - - savefile->ReadFloat( set ); - heartInfo.SetStartTime( set ); - savefile->ReadFloat( set ); - heartInfo.SetDuration( set ); - savefile->ReadFloat( set ); - heartInfo.SetStartValue( set ); - savefile->ReadFloat( set ); - heartInfo.SetEndValue( set ); - - savefile->ReadInt( lastHeartAdjust ); - savefile->ReadInt( lastHeartBeat ); - savefile->ReadInt( lastDmgTime ); - savefile->ReadInt( deathClearContentsTime ); - savefile->ReadBool( doingDeathSkin ); - savefile->ReadInt( lastArmorPulse ); - savefile->ReadFloat( stamina ); - savefile->ReadFloat( healthPool ); - savefile->ReadInt( nextHealthPulse ); - savefile->ReadBool( healthPulse ); - savefile->ReadInt( nextHealthTake ); - savefile->ReadBool( healthTake ); - - savefile->ReadBool( hiddenWeapon ); - soulCubeProjectile.Restore( savefile ); - - savefile->ReadInt( spectator ); - savefile->ReadVec3( colorBar ); - savefile->ReadInt( colorBarIndex ); - savefile->ReadBool( scoreBoardOpen ); - savefile->ReadBool( forceScoreBoard ); - savefile->ReadBool( forceRespawn ); - savefile->ReadBool( spectating ); - savefile->ReadInt( lastSpectateTeleport ); - savefile->ReadBool( lastHitToggle ); - savefile->ReadBool( forcedReady ); - savefile->ReadBool( wantSpectate ); - savefile->ReadBool( weaponGone ); - savefile->ReadBool( useInitialSpawns ); - savefile->ReadInt( latchedTeam ); - savefile->ReadInt( tourneyRank ); - savefile->ReadInt( tourneyLine ); - - teleportEntity.Restore( savefile ); - savefile->ReadInt( teleportKiller ); - - savefile->ReadInt( minRespawnTime ); - savefile->ReadInt( maxRespawnTime ); - - savefile->ReadVec3( firstPersonViewOrigin ); - savefile->ReadMat3( firstPersonViewAxis ); - - // don't bother saving dragEntity since it's a dev tool - dragEntity.Clear(); - - savefile->ReadJoint( hipJoint ); - savefile->ReadJoint( chestJoint ); - savefile->ReadJoint( headJoint ); - - savefile->ReadStaticObject( physicsObj ); - RestorePhysics( &physicsObj ); - - savefile->ReadInt( num ); - aasLocation.SetGranularity( 1 ); - aasLocation.SetNum( num ); - for( i = 0; i < num; i++ ) { - savefile->ReadInt( aasLocation[ i ].areaNum ); - savefile->ReadVec3( aasLocation[ i ].pos ); - } - - savefile->ReadInt( bobFoot ); - savefile->ReadFloat( bobFrac ); - savefile->ReadFloat( bobfracsin ); - savefile->ReadInt( bobCycle ); - savefile->ReadFloat( xyspeed ); - savefile->ReadInt( stepUpTime ); - savefile->ReadFloat( stepUpDelta ); - savefile->ReadFloat( idealLegsYaw ); - savefile->ReadFloat( legsYaw ); - savefile->ReadBool( legsForward ); - savefile->ReadFloat( oldViewYaw ); - savefile->ReadAngles( viewBobAngles ); - savefile->ReadVec3( viewBob ); - savefile->ReadInt( landChange ); - savefile->ReadInt( landTime ); - - savefile->ReadInt( currentWeapon ); - savefile->ReadInt( idealWeapon ); - savefile->ReadInt( previousWeapon ); - savefile->ReadInt( weaponSwitchTime ); - savefile->ReadBool( weaponEnabled ); - savefile->ReadBool( showWeaponViewModel ); - - savefile->ReadSkin( skin ); - savefile->ReadSkin( powerUpSkin ); - savefile->ReadString( baseSkinName ); - - savefile->ReadInt( numProjectilesFired ); - savefile->ReadInt( numProjectileHits ); - - savefile->ReadBool( airless ); - savefile->ReadInt( airTics ); - savefile->ReadInt( lastAirDamage ); - - savefile->ReadBool( gibDeath ); - savefile->ReadBool( gibsLaunched ); - savefile->ReadVec3( gibsDir ); - - savefile->ReadFloat( set ); - zoomFov.SetStartTime( set ); - savefile->ReadFloat( set ); - zoomFov.SetDuration( set ); - savefile->ReadFloat( set ); - zoomFov.SetStartValue( set ); - savefile->ReadFloat( set ); - zoomFov.SetEndValue( set ); - - savefile->ReadFloat( set ); - centerView.SetStartTime( set ); - savefile->ReadFloat( set ); - centerView.SetDuration( set ); - savefile->ReadFloat( set ); - centerView.SetStartValue( set ); - savefile->ReadFloat( set ); - centerView.SetEndValue( set ); - - savefile->ReadBool( fxFov ); - - savefile->ReadFloat( influenceFov ); - savefile->ReadInt( influenceActive ); - savefile->ReadFloat( influenceRadius ); - savefile->ReadObject( reinterpret_cast( influenceEntity ) ); - savefile->ReadMaterial( influenceMaterial ); - savefile->ReadSkin( influenceSkin ); - - savefile->ReadObject( reinterpret_cast( privateCameraView ) ); - - for( i = 0; i < NUM_LOGGED_VIEW_ANGLES; i++ ) { - savefile->ReadAngles( loggedViewAngles[ i ] ); - } - for( i = 0; i < NUM_LOGGED_ACCELS; i++ ) { - savefile->ReadInt( loggedAccel[ i ].time ); - savefile->ReadVec3( loggedAccel[ i ].dir ); - } - savefile->ReadInt( currentLoggedAccel ); - - savefile->ReadObject( reinterpret_cast( focusGUIent ) ); - // can't save focusUI - focusUI = NULL; - savefile->ReadObject( reinterpret_cast( focusCharacter ) ); - savefile->ReadInt( talkCursor ); - savefile->ReadInt( focusTime ); - savefile->ReadObject( reinterpret_cast( focusVehicle ) ); - savefile->ReadUserInterface( cursor ); - - savefile->ReadInt( oldMouseX ); - savefile->ReadInt( oldMouseY ); - - savefile->ReadString( pdaAudio ); - savefile->ReadString( pdaVideo ); - savefile->ReadString( pdaVideoWave ); - - savefile->ReadBool( tipUp ); - savefile->ReadBool( objectiveUp ); - - savefile->ReadInt( lastDamageDef ); - savefile->ReadVec3( lastDamageDir ); - savefile->ReadInt( lastDamageLocation ); - savefile->ReadInt( smoothedFrame ); - savefile->ReadBool( smoothedOriginUpdated ); - savefile->ReadVec3( smoothedOrigin ); - savefile->ReadAngles( smoothedAngles ); - - savefile->ReadBool( ready ); - savefile->ReadBool( respawning ); - savefile->ReadBool( leader ); - savefile->ReadInt( lastSpectateChange ); - savefile->ReadInt( lastTeleFX ); - - // set the pm_ cvars - const idKeyValue *kv; - kv = spawnArgs.MatchPrefix( "pm_", NULL ); - while( kv ) { - cvarSystem->SetCVarString( kv->GetKey(), kv->GetValue() ); - kv = spawnArgs.MatchPrefix( "pm_", kv ); - } - - savefile->ReadFloat( set ); - pm_stamina.SetFloat( set ); - - // create combat collision hull for exact collision detection - SetCombatModel(); - -#ifdef _D3XP - int weaponToggleCount; - savefile->ReadInt(weaponToggleCount); - for(i = 0; i < weaponToggleCount; i++) { - WeaponToggle_t newToggle; - memset(&newToggle, 0, sizeof(newToggle)); - - idStr name; - savefile->ReadString(name); - strcpy(newToggle.name, name.c_str()); - - int indexCount; - savefile->ReadInt(indexCount); - for(int j = 0; j < indexCount; j++) { - int temp; - savefile->ReadInt(temp); - newToggle.toggleList.Append(temp); - } - weaponToggles.Set(newToggle.name, newToggle); - } - savefile->ReadObject(reinterpret_cast(mountedObject)); - enviroSuitLight.Restore( savefile ); - savefile->ReadBool( healthRecharge ); - savefile->ReadInt( lastHealthRechargeTime ); - savefile->ReadInt( rechargeSpeed ); - savefile->ReadFloat( new_g_damageScale ); - - savefile->ReadBool( bloomEnabled ); - savefile->ReadFloat( bloomSpeed ); - savefile->ReadFloat( bloomIntensity ); -#endif - - // DG: workaround for lingering messages that are shown forever after loading a savegame - // (one way to get them is saving again, while the message from first save is still - // shown, and then load) - if ( hud ) { - hud->SetStateString( "message", "" ); - } -} - -/* -=============== -idPlayer::PrepareForRestart -================ -*/ -void idPlayer::PrepareForRestart( void ) { - ClearPowerUps(); - Spectate( true ); - forceRespawn = true; - -#ifdef CTF - // Confirm reset hud states - DropFlag(); - - if ( hud ) { - hud->SetStateInt( "red_flagstatus", 0 ); - hud->SetStateInt( "blue_flagstatus", 0 ); - } -#endif - - // we will be restarting program, clear the client entities from program-related things first - ShutdownThreads(); - - // the sound world is going to be cleared, don't keep references to emitters - FreeSoundEmitter( false ); -} - -/* -=============== -idPlayer::Restart -================ -*/ -void idPlayer::Restart( void ) { - idActor::Restart(); - - // client needs to setup the animation script object again - if ( gameLocal.isClient ) { - Init(); - } else { - // choose a random spot and prepare the point of view in case player is left spectating - assert( spectating ); - SpawnFromSpawnSpot(); - } - - useInitialSpawns = true; - UpdateSkinSetup( true ); -} - -/* -=============== -idPlayer::ServerSpectate -================ -*/ -void idPlayer::ServerSpectate( bool spectate ) { - assert( !gameLocal.isClient ); - - if ( spectating != spectate ) { - Spectate( spectate ); - if ( spectate ) { - SetSpectateOrigin(); - } else { - if ( gameLocal.gameType == GAME_DM ) { - // make sure the scores are reset so you can't exploit by spectating and entering the game back - // other game types don't matter, as you either can't join back, or it's team scores - gameLocal.mpGame.ClearFrags( entityNumber ); - } - } - } - if ( !spectate ) { - SpawnFromSpawnSpot(); - } -#ifdef CTF - // drop the flag if player was carrying it - if ( spectate && gameLocal.isMultiplayer && gameLocal.mpGame.IsGametypeFlagBased() && - carryingFlag ) - { - DropFlag(); - } -#endif -} - -/* -=========== -idPlayer::SelectInitialSpawnPoint - -Try to find a spawn point marked 'initial', otherwise -use normal spawn selection. -============ -*/ -void idPlayer::SelectInitialSpawnPoint( idVec3 &origin, idAngles &angles ) { - idEntity *spot; - idStr skin; - - spot = gameLocal.SelectInitialSpawnPoint( this ); - - // set the player skin from the spawn location - if ( spot->spawnArgs.GetString( "skin", NULL, skin ) ) { - spawnArgs.Set( "spawn_skin", skin ); - } - - // activate the spawn locations targets - spot->PostEventMS( &EV_ActivateTargets, 0, this ); - - origin = spot->GetPhysics()->GetOrigin(); - origin[2] += 4.0f + CM_BOX_EPSILON; // move up to make sure the player is at least an epsilon above the floor - angles = spot->GetPhysics()->GetAxis().ToAngles(); -} - -/* -=========== -idPlayer::SpawnFromSpawnSpot - -Chooses a spawn location and spawns the player -============ -*/ -void idPlayer::SpawnFromSpawnSpot( void ) { - idVec3 spawn_origin; - idAngles spawn_angles; - - SelectInitialSpawnPoint( spawn_origin, spawn_angles ); - SpawnToPoint( spawn_origin, spawn_angles ); -} - -/* -=========== -idPlayer::SpawnToPoint - -Called every time a client is placed fresh in the world: -after the first ClientBegin, and after each respawn -Initializes all non-persistant parts of playerState - -when called here with spectating set to true, just place yourself and init -============ -*/ -void idPlayer::SpawnToPoint( const idVec3 &spawn_origin, const idAngles &spawn_angles ) { - idVec3 spec_origin; - - assert( !gameLocal.isClient ); - - respawning = true; - - Init(); - - fl.noknockback = false; - - // stop any ragdolls being used - StopRagdoll(); - - // set back the player physics - SetPhysics( &physicsObj ); - - physicsObj.SetClipModelAxis(); - physicsObj.EnableClip(); - - if ( !spectating ) { - SetCombatContents( true ); - } - - physicsObj.SetLinearVelocity( vec3_origin ); - - // setup our initial view - if ( !spectating ) { - SetOrigin( spawn_origin ); - } else { - spec_origin = spawn_origin; - spec_origin[ 2 ] += pm_normalheight.GetFloat(); - spec_origin[ 2 ] += SPECTATE_RAISE; - SetOrigin( spec_origin ); - } - - // if this is the first spawn of the map, we don't have a usercmd yet, - // so the delta angles won't be correct. This will be fixed on the first think. - viewAngles = ang_zero; - SetDeltaViewAngles( ang_zero ); - SetViewAngles( spawn_angles ); - spawnAngles = spawn_angles; - spawnAnglesSet = false; - - legsForward = true; - legsYaw = 0.0f; - idealLegsYaw = 0.0f; - oldViewYaw = viewAngles.yaw; - - if ( spectating ) { - Hide(); - } else { - Show(); - } - - if ( gameLocal.isMultiplayer ) { - if ( !spectating ) { - // we may be called twice in a row in some situations. avoid a double fx and 'fly to the roof' - if ( lastTeleFX < gameLocal.time - 1000 ) { - idEntityFx::StartFx( spawnArgs.GetString( "fx_spawn" ), &spawn_origin, NULL, this, true ); - lastTeleFX = gameLocal.time; - } - } - AI_TELEPORT = true; - } else { - AI_TELEPORT = false; - } - - // kill anything at the new position - if ( !spectating ) { - physicsObj.SetClipMask( MASK_PLAYERSOLID ); // the clip mask is usually maintained in Move(), but KillBox requires it - gameLocal.KillBox( this ); - } - - // don't allow full run speed for a bit - physicsObj.SetKnockBack( 100 ); - - // set our respawn time and buttons so that if we're killed we don't respawn immediately - minRespawnTime = gameLocal.time; - maxRespawnTime = gameLocal.time; - if ( !spectating ) { - forceRespawn = false; - } - - privateCameraView = NULL; - - BecomeActive( TH_THINK ); - - // run a client frame to drop exactly to the floor, - // initialize animations and other things - Think(); - - respawning = false; - lastManOver = false; - lastManPlayAgain = false; - isTelefragged = false; -} - -/* -=============== -idPlayer::SavePersistantInfo - -Saves any inventory and player stats when changing levels. -=============== -*/ -void idPlayer::SavePersistantInfo( void ) { - idDict &playerInfo = gameLocal.persistentPlayerInfo[entityNumber]; - - playerInfo.Clear(); - inventory.GetPersistantData( playerInfo ); - playerInfo.SetInt( "health", health ); - playerInfo.SetInt( "current_weapon", currentWeapon ); -} - -/* -=============== -idPlayer::RestorePersistantInfo - -Restores any inventory and player stats when changing levels. -=============== -*/ -void idPlayer::RestorePersistantInfo( void ) { - if ( gameLocal.isMultiplayer ) { - gameLocal.persistentPlayerInfo[entityNumber].Clear(); - } - - spawnArgs.Copy( gameLocal.persistentPlayerInfo[entityNumber] ); - - inventory.RestoreInventory( this, spawnArgs ); - health = spawnArgs.GetInt( "health", "100" ); - if ( !gameLocal.isClient ) { - idealWeapon = spawnArgs.GetInt( "current_weapon", "1" ); - } -} - -/* -================ -idPlayer::GetUserInfo -================ -*/ -idDict *idPlayer::GetUserInfo( void ) { - return &gameLocal.userInfo[ entityNumber ]; -} - -/* -============== -idPlayer::UpdateSkinSetup -============== -*/ -void idPlayer::UpdateSkinSetup( bool restart ) { - if ( restart ) { - team = ( idStr::Icmp( GetUserInfo()->GetString( "ui_team" ), "Blue" ) == 0 ); - } - if ( gameLocal.mpGame.IsGametypeTeamBased() ) { /* CTF */ - if ( team ) { - baseSkinName = "skins/characters/player/marine_mp_blue"; - } else { - baseSkinName = "skins/characters/player/marine_mp_red"; - } - if ( !gameLocal.isClient && team != latchedTeam ) { - gameLocal.mpGame.SwitchToTeam( entityNumber, latchedTeam, team ); - } - latchedTeam = team; - } else { - baseSkinName = GetUserInfo()->GetString( "ui_skin" ); - } - if ( !baseSkinName.Length() ) { - baseSkinName = "skins/characters/player/marine_mp"; - } - skin = declManager->FindSkin( baseSkinName, false ); - assert( skin ); - // match the skin to a color band for scoreboard - if ( baseSkinName.Find( "red" ) != -1 ) { - colorBarIndex = 1; - } else if ( baseSkinName.Find( "green" ) != -1 ) { - colorBarIndex = 2; - } else if ( baseSkinName.Find( "blue" ) != -1 ) { - colorBarIndex = 3; - } else if ( baseSkinName.Find( "yellow" ) != -1 ) { - colorBarIndex = 4; - } else if ( baseSkinName.Find( "grey" ) != -1 ) { - colorBarIndex = 5; - } else if ( baseSkinName.Find( "purple" ) != -1 ) { - colorBarIndex = 6; - } else if ( baseSkinName.Find( "orange" ) != -1 ) { - colorBarIndex = 7; - } else { - colorBarIndex = 0; - } - colorBar = colorBarTable[ colorBarIndex ]; - if ( PowerUpActive( BERSERK ) ) { - powerUpSkin = declManager->FindSkin( baseSkinName + "_berserk" ); - } -#ifdef _D3XP - else if ( PowerUpActive( INVULNERABILITY ) ) { - powerUpSkin = declManager->FindSkin( baseSkinName + "_invuln" ); - //} else if ( PowerUpActive( HASTE ) ) { - // powerUpSkin = declManager->FindSkin( baseSkinName + "_haste" ); - } -#endif -} - -/* -============== -idPlayer::BalanceTDM -============== -*/ -bool idPlayer::BalanceTDM( void ) { - int i, balanceTeam, teamCount[2]; - idEntity *ent; - - teamCount[ 0 ] = teamCount[ 1 ] = 0; - for( i = 0; i < gameLocal.numClients; i++ ) { - ent = gameLocal.entities[ i ]; - if ( ent && ent->IsType( idPlayer::Type ) ) { - teamCount[ static_cast< idPlayer * >( ent )->team ]++; - } - } - balanceTeam = -1; - if ( teamCount[ 0 ] < teamCount[ 1 ] ) { - balanceTeam = 0; - } else if ( teamCount[ 0 ] > teamCount[ 1 ] ) { - balanceTeam = 1; - } - if ( balanceTeam != -1 && team != balanceTeam ) { - common->DPrintf( "team balance: forcing player %d to %s team\n", entityNumber, balanceTeam ? "blue" : "red" ); - team = balanceTeam; - GetUserInfo()->Set( "ui_team", team ? "Blue" : "Red" ); - return true; - } - return false; -} - -/* -============== -idPlayer::UserInfoChanged -============== -*/ -bool idPlayer::UserInfoChanged( bool canModify ) { - idDict *userInfo; - bool modifiedInfo; - bool spec; - bool newready; - - userInfo = GetUserInfo(); - showWeaponViewModel = userInfo->GetBool( "ui_showGun" ); - - if ( !gameLocal.isMultiplayer ) { - return false; - } - - modifiedInfo = false; - - spec = ( idStr::Icmp( userInfo->GetString( "ui_spectate" ), "Spectate" ) == 0 ); - if ( gameLocal.serverInfo.GetBool( "si_spectators" ) ) { - // never let spectators go back to game while sudden death is on - if ( canModify && gameLocal.mpGame.GetGameState() == idMultiplayerGame::SUDDENDEATH && !spec && wantSpectate == true ) { - userInfo->Set( "ui_spectate", "Spectate" ); - modifiedInfo |= true; - } else { - if ( spec != wantSpectate && !spec ) { - // returning from spectate, set forceRespawn so we don't get stuck in spectate forever - forceRespawn = true; - } - wantSpectate = spec; - } - } else { - if ( canModify && spec ) { - userInfo->Set( "ui_spectate", "Play" ); - modifiedInfo |= true; - } else if ( spectating ) { - // allow player to leaving spectator mode if they were in it when si_spectators got turned off - forceRespawn = true; - } - wantSpectate = false; - } - - newready = ( idStr::Icmp( userInfo->GetString( "ui_ready" ), "Ready" ) == 0 ); - if ( ready != newready && gameLocal.mpGame.GetGameState() == idMultiplayerGame::WARMUP && !wantSpectate ) { - gameLocal.mpGame.AddChatLine( common->GetLanguageDict()->GetString( "#str_07180" ), userInfo->GetString( "ui_name" ), newready ? common->GetLanguageDict()->GetString( "#str_04300" ) : common->GetLanguageDict()->GetString( "#str_04301" ) ); - } - ready = newready; - team = ( idStr::Icmp( userInfo->GetString( "ui_team" ), "Blue" ) == 0 ); - // server maintains TDM balance - if ( canModify && gameLocal.mpGame.IsGametypeTeamBased() && !gameLocal.mpGame.IsInGame( entityNumber ) && g_balanceTDM.GetBool() ) { /* CTF */ - modifiedInfo |= BalanceTDM( ); - } - UpdateSkinSetup( false ); - - isChatting = userInfo->GetBool( "ui_chat", "0" ); - if ( canModify && isChatting && AI_DEAD ) { - // if dead, always force chat icon off. - isChatting = false; - userInfo->SetBool( "ui_chat", false ); - modifiedInfo |= true; - } - - return modifiedInfo; -} - -/* -=============== -idPlayer::UpdateHudAmmo -=============== -*/ -void idPlayer::UpdateHudAmmo( idUserInterface *_hud ) { - int inclip; - int ammoamount; - - assert( weapon.GetEntity() ); - assert( _hud ); - - inclip = weapon.GetEntity()->AmmoInClip(); - ammoamount = weapon.GetEntity()->AmmoAvailable(); - -#ifdef _D3XP - //Hack to stop the bloodstone ammo to display when it is being activated - if ( ammoamount < 0 || !weapon.GetEntity()->IsReady() || currentWeapon == weapon_bloodstone) { -#else - if ( ammoamount < 0 || !weapon.GetEntity()->IsReady() ) { -#endif - // show infinite ammo - _hud->SetStateString( "player_ammo", "" ); - _hud->SetStateString( "player_totalammo", "" ); - } else { - // show remaining ammo -#ifdef _D3XP - _hud->SetStateString( "player_totalammo", va( "%i", ammoamount ) ); -#else - _hud->SetStateString( "player_totalammo", va( "%i", ammoamount - inclip ) ); -#endif - _hud->SetStateString( "player_ammo", weapon.GetEntity()->ClipSize() ? va( "%i", inclip ) : "--" ); // how much in the current clip - _hud->SetStateString( "player_clips", weapon.GetEntity()->ClipSize() ? va( "%i", ammoamount / weapon.GetEntity()->ClipSize() ) : "--" ); - -#ifdef _D3XP - _hud->SetStateString( "player_allammo", va( "%i/%i", inclip, ammoamount ) ); -#else - _hud->SetStateString( "player_allammo", va( "%i/%i", inclip, ammoamount - inclip ) ); -#endif - } - - _hud->SetStateBool( "player_ammo_empty", ( ammoamount == 0 ) ); - _hud->SetStateBool( "player_clip_empty", ( weapon.GetEntity()->ClipSize() ? inclip == 0 : false ) ); - _hud->SetStateBool( "player_clip_low", ( weapon.GetEntity()->ClipSize() ? inclip <= weapon.GetEntity()->LowAmmo() : false ) ); - -#ifdef _D3XP - //Hack to stop the bloodstone ammo to display when it is being activated - if(currentWeapon == weapon_bloodstone) { - _hud->SetStateBool( "player_ammo_empty", false ); - _hud->SetStateBool( "player_clip_empty", false ); - _hud->SetStateBool( "player_clip_low", false ); - } -#endif - -#ifdef _D3XP - //Let the HUD know the total amount of ammo regardless of the ammo required value - _hud->SetStateString( "player_ammo_count", va("%i", weapon.GetEntity()->AmmoCount())); -#endif - -#ifdef _D3XP - //Make sure the hud always knows how many bloodstone charges there are - int ammoRequired; - ammo_t ammo_i = inventory.AmmoIndexForWeaponClass( "weapon_bloodstone_passive", &ammoRequired ); - int bloodstoneAmmo = inventory.HasAmmo( ammo_i, ammoRequired ); - _hud->SetStateString("player_bloodstone_ammo", va("%i", bloodstoneAmmo)); - _hud->HandleNamedEvent( "bloodstoneAmmoUpdate" ); -#endif - - _hud->HandleNamedEvent( "updateAmmo" ); -} - -/* -=============== -idPlayer::UpdateHudStats -=============== -*/ -void idPlayer::UpdateHudStats( idUserInterface *_hud ) { - int staminapercentage; - float max_stamina; - - assert( _hud ); - - max_stamina = pm_stamina.GetFloat(); - if ( !max_stamina ) { - // stamina disabled, so show full stamina bar - staminapercentage = 100.0f; - } else { - staminapercentage = idMath::FtoiFast( 100.0f * stamina / max_stamina ); - } - - _hud->SetStateInt( "player_health", health ); - _hud->SetStateInt( "player_stamina", staminapercentage ); - _hud->SetStateInt( "player_armor", inventory.armor ); - _hud->SetStateInt( "player_hr", heartRate ); - - _hud->SetStateInt( "player_nostamina", ( max_stamina == 0 ) ? 1 : 0 ); - - _hud->HandleNamedEvent( "updateArmorHealthAir" ); - -#ifdef _D3XP - _hud->HandleNamedEvent( "updatePowerup" ); -#endif - - if ( healthPulse ) { - _hud->HandleNamedEvent( "healthPulse" ); - StartSound( "snd_healthpulse", SND_CHANNEL_ITEM, 0, false, NULL ); - healthPulse = false; - } - - if ( healthTake ) { - _hud->HandleNamedEvent( "healthPulse" ); - StartSound( "snd_healthtake", SND_CHANNEL_ITEM, 0, false, NULL ); - healthTake = false; - } - - if ( inventory.ammoPulse ) { - _hud->HandleNamedEvent( "ammoPulse" ); - inventory.ammoPulse = false; - } - if ( inventory.weaponPulse ) { - // We need to update the weapon hud manually, but not - // the armor/ammo/health because they are updated every - // frame no matter what - UpdateHudWeapon(); - _hud->HandleNamedEvent( "weaponPulse" ); - inventory.weaponPulse = false; - } - if ( inventory.armorPulse ) { - _hud->HandleNamedEvent( "armorPulse" ); - inventory.armorPulse = false; - } - -#ifdef CTF - if ( gameLocal.mpGame.IsGametypeFlagBased() && _hud ) - { - _hud->SetStateInt( "red_flagstatus", gameLocal.mpGame.GetFlagStatus( 0 ) ); - _hud->SetStateInt( "blue_flagstatus", gameLocal.mpGame.GetFlagStatus( 1 ) ); - - _hud->SetStateInt( "red_team_score", gameLocal.mpGame.GetFlagPoints( 0 ) ); - _hud->SetStateInt( "blue_team_score", gameLocal.mpGame.GetFlagPoints( 1 ) ); - - _hud->HandleNamedEvent( "RedFlagStatusChange" ); - _hud->HandleNamedEvent( "BlueFlagStatusChange" ); - } - - _hud->HandleNamedEvent( "selfTeam" ); - -#endif - - - UpdateHudAmmo( _hud ); -} - -/* -=============== -idPlayer::UpdateHudWeapon -=============== -*/ -void idPlayer::UpdateHudWeapon( bool flashWeapon ) { - idUserInterface *hud = idPlayer::hud; - - // if updating the hud of a followed client - if ( gameLocal.localClientNum >= 0 && gameLocal.entities[ gameLocal.localClientNum ] && gameLocal.entities[ gameLocal.localClientNum ]->IsType( idPlayer::Type ) ) { - idPlayer *p = static_cast< idPlayer * >( gameLocal.entities[ gameLocal.localClientNum ] ); - if ( p->spectating && p->spectator == entityNumber ) { - assert( p->hud ); - hud = p->hud; - } - } - - if ( !hud ) { - return; - } - - for ( int i = 0; i < MAX_WEAPONS; i++ ) { - const char *weapnum = va( "def_weapon%d", i ); - const char *hudWeap = va( "weapon%d", i ); - int weapstate = 0; - if ( inventory.weapons & ( 1 << i ) ) { - const char *weap = spawnArgs.GetString( weapnum ); - if ( weap && *weap ) { - weapstate++; - } - if ( idealWeapon == i ) { - weapstate++; - } - } - hud->SetStateInt( hudWeap, weapstate ); - } - if ( flashWeapon ) { - -/*#ifdef _D3XP - //Clear all hud weapon varaibles for the weapon change - hud->SetStateString( "player_ammo", "" ); - hud->SetStateString( "player_totalammo", "" ); - hud->SetStateString( "player_clips", "" ); - hud->SetStateString( "player_allammo", "" ); - hud->SetStateBool( "player_ammo_empty", false ); - hud->SetStateBool( "player_clip_empty", false ); - hud->SetStateBool( "player_clip_low", false ); - hud->SetStateString( "player_ammo_count", ""); -#endif*/ - - hud->HandleNamedEvent( "weaponChange" ); - } -} - -/* -=============== -idPlayer::DrawHUD -=============== -*/ -void idPlayer::DrawHUD( idUserInterface *_hud ) { - - if ( !weapon.GetEntity() || influenceActive != INFLUENCE_NONE || privateCameraView || gameLocal.GetCamera() || !_hud || !g_showHud.GetBool() ) { - return; - } - - UpdateHudStats( _hud ); - - _hud->SetStateString( "weapicon", weapon.GetEntity()->Icon() ); - - // FIXME: this is temp to allow the sound meter to show up in the hud - // it should be commented out before shipping but the code can remain - // for mod developers to enable for the same functionality - _hud->SetStateInt( "s_debug", cvarSystem->GetCVarInteger( "s_showLevelMeter" ) ); - - weapon.GetEntity()->UpdateGUI(); - - _hud->Redraw( gameLocal.realClientTime ); - - // weapon targeting crosshair - if ( !GuiActive() ) { - if ( cursor && weapon.GetEntity()->ShowCrosshair() ) { - -#ifdef _D3XP - if ( weapon.GetEntity()->GetGrabberState() == 1 || weapon.GetEntity()->GetGrabberState() == 2 ) { - cursor->SetStateString( "grabbercursor", "1" ); - cursor->SetStateString( "combatcursor", "0" ); - } else { - cursor->SetStateString( "grabbercursor", "0" ); - cursor->SetStateString( "combatcursor", "1" ); - } -#endif - - cursor->Redraw( gameLocal.realClientTime ); - } - } -} - -/* -=============== -idPlayer::EnterCinematic -=============== -*/ -void idPlayer::EnterCinematic( void ) { -#ifdef _D3XP - if ( PowerUpActive( HELLTIME ) ) { - StopHelltime(); - } -#endif - - Hide(); - StopAudioLog(); - StopSound( SND_CHANNEL_PDA, false ); - if ( hud ) { - hud->HandleNamedEvent( "radioChatterDown" ); - } - - physicsObj.SetLinearVelocity( vec3_origin ); - - SetState( "EnterCinematic" ); - UpdateScript(); - - if ( weaponEnabled && weapon.GetEntity() ) { - weapon.GetEntity()->EnterCinematic(); - } - - AI_FORWARD = false; - AI_BACKWARD = false; - AI_STRAFE_LEFT = false; - AI_STRAFE_RIGHT = false; - AI_RUN = false; - AI_ATTACK_HELD = false; - AI_WEAPON_FIRED = false; - AI_JUMP = false; - AI_CROUCH = false; - AI_ONGROUND = true; - AI_ONLADDER = false; - AI_DEAD = ( health <= 0 ); - AI_RUN = false; - AI_PAIN = false; - AI_HARDLANDING = false; - AI_SOFTLANDING = false; - AI_RELOAD = false; - AI_TELEPORT = false; - AI_TURN_LEFT = false; - AI_TURN_RIGHT = false; -} - -/* -=============== -idPlayer::ExitCinematic -=============== -*/ -void idPlayer::ExitCinematic( void ) { - Show(); - - if ( weaponEnabled && weapon.GetEntity() ) { - weapon.GetEntity()->ExitCinematic(); - } - - SetState( "ExitCinematic" ); - UpdateScript(); -} - -/* -===================== -idPlayer::UpdateConditions -===================== -*/ -void idPlayer::UpdateConditions( void ) { - idVec3 velocity; - float forwardspeed; - float sidespeed; - - // minus the push velocity to avoid playing the walking animation and sounds when riding a mover - velocity = physicsObj.GetLinearVelocity() - physicsObj.GetPushedLinearVelocity(); - - if ( influenceActive ) { - AI_FORWARD = false; - AI_BACKWARD = false; - AI_STRAFE_LEFT = false; - AI_STRAFE_RIGHT = false; - } else if ( gameLocal.time - lastDmgTime < 500 ) { - forwardspeed = velocity * viewAxis[ 0 ]; - sidespeed = velocity * viewAxis[ 1 ]; - AI_FORWARD = AI_ONGROUND && ( forwardspeed > 20.01f ); - AI_BACKWARD = AI_ONGROUND && ( forwardspeed < -20.01f ); - AI_STRAFE_LEFT = AI_ONGROUND && ( sidespeed > 20.01f ); - AI_STRAFE_RIGHT = AI_ONGROUND && ( sidespeed < -20.01f ); - } else if ( xyspeed > MIN_BOB_SPEED ) { - AI_FORWARD = AI_ONGROUND && ( usercmd.forwardmove > 0 ); - AI_BACKWARD = AI_ONGROUND && ( usercmd.forwardmove < 0 ); - AI_STRAFE_LEFT = AI_ONGROUND && ( usercmd.rightmove < 0 ); - AI_STRAFE_RIGHT = AI_ONGROUND && ( usercmd.rightmove > 0 ); - } else { - AI_FORWARD = false; - AI_BACKWARD = false; - AI_STRAFE_LEFT = false; - AI_STRAFE_RIGHT = false; - } - - AI_RUN = ( usercmd.buttons & BUTTON_RUN ) && ( ( !pm_stamina.GetFloat() ) || ( stamina > pm_staminathreshold.GetFloat() ) ); - AI_DEAD = ( health <= 0 ); -} - -/* -================== -WeaponFireFeedback - -Called when a weapon fires, generates head twitches, etc -================== -*/ -void idPlayer::WeaponFireFeedback( const idDict *weaponDef ) { - // force a blink - blink_time = 0; - - // play the fire animation - AI_WEAPON_FIRED = true; - - // update view feedback - playerView.WeaponFireFeedback( weaponDef ); -} - -/* -=============== -idPlayer::StopFiring -=============== -*/ -void idPlayer::StopFiring( void ) { - AI_ATTACK_HELD = false; - AI_WEAPON_FIRED = false; - AI_RELOAD = false; - if ( weapon.GetEntity() ) { - weapon.GetEntity()->EndAttack(); - } -} - -/* -=============== -idPlayer::FireWeapon -=============== -*/ -void idPlayer::FireWeapon( void ) { - idMat3 axis; - idVec3 muzzle; - - if ( privateCameraView ) { - return; - } - - if ( g_editEntityMode.GetInteger() ) { - GetViewPos( muzzle, axis ); - if ( gameLocal.editEntities->SelectEntity( muzzle, axis[0], this ) ) { - return; - } - } - - if ( !hiddenWeapon && weapon.GetEntity()->IsReady() ) { - if ( weapon.GetEntity()->AmmoInClip() || weapon.GetEntity()->AmmoAvailable() ) { - AI_ATTACK_HELD = true; - weapon.GetEntity()->BeginAttack(); - if ( ( weapon_soulcube >= 0 ) && ( currentWeapon == weapon_soulcube ) ) { - if ( hud ) { - hud->HandleNamedEvent( "soulCubeNotReady" ); - } - SelectWeapon( previousWeapon, false ); - } -#ifdef _D3XP - if( (weapon_bloodstone >= 0) && (currentWeapon == weapon_bloodstone) && inventory.weapons & ( 1 << weapon_bloodstone_active1 ) && weapon.GetEntity()->GetStatus() == WP_READY) { - // tell it to switch to the previous weapon. Only do this once to prevent - // weapon toggling messing up the previous weapon - if(idealWeapon == weapon_bloodstone) { - if(previousWeapon == weapon_bloodstone || previousWeapon == -1) { - NextBestWeapon(); - } else { - //Since this is a toggle weapon just select itself and it will toggle to the last weapon - SelectWeapon( weapon_bloodstone, false ); - } - } - } -#endif - } else { - NextBestWeapon(); - } - } - - if ( hud ) { - if ( tipUp ) { - HideTip(); - } - // may want to track with with a bool as well - // keep from looking up named events so often - if ( objectiveUp ) { - HideObjective(); - } - } -} - -/* -=============== -idPlayer::CacheWeapons -=============== -*/ -void idPlayer::CacheWeapons( void ) { - idStr weap; - int w; - - // check if we have any weapons - if ( !inventory.weapons ) { - return; - } - - for( w = 0; w < MAX_WEAPONS; w++ ) { - if ( inventory.weapons & ( 1 << w ) ) { - weap = spawnArgs.GetString( va( "def_weapon%d", w ) ); - if ( weap != "" ) { - idWeapon::CacheWeapon( weap ); - } else { - inventory.weapons &= ~( 1 << w ); - } - } - } -} - -/* -=============== -idPlayer::Give -=============== -*/ -bool idPlayer::Give( const char *statname, const char *value ) { - int amount; - - if ( AI_DEAD ) { - return false; - } - - if ( !idStr::Icmp( statname, "health" ) ) { - if ( health >= inventory.maxHealth ) { - return false; - } - amount = atoi( value ); - if ( amount ) { - health += amount; - if ( health > inventory.maxHealth ) { - health = inventory.maxHealth; - } - if ( hud ) { - hud->HandleNamedEvent( "healthPulse" ); - } - } - - } else if ( !idStr::Icmp( statname, "stamina" ) ) { - if ( stamina >= 100 ) { - return false; - } - stamina += atof( value ); - if ( stamina > 100 ) { - stamina = 100; - } - - } else if ( !idStr::Icmp( statname, "heartRate" ) ) { - heartRate += atoi( value ); - if ( heartRate > MAX_HEARTRATE ) { - heartRate = MAX_HEARTRATE; - } - - } else if ( !idStr::Icmp( statname, "air" ) ) { - if ( airTics >= pm_airTics.GetInteger() ) { - return false; - } - airTics += atoi( value ) / 100.0 * pm_airTics.GetInteger(); - if ( airTics > pm_airTics.GetInteger() ) { - airTics = pm_airTics.GetInteger(); - } -#ifdef _D3XP - } else if ( !idStr::Icmp( statname, "enviroTime" ) ) { - if ( PowerUpActive( ENVIROTIME ) ) { - inventory.powerupEndTime[ ENVIROTIME ] += (atof(value) * 1000); - } else { - GivePowerUp( ENVIROTIME, atoi(value)*1000 ); - } - } else { - bool ret = inventory.Give( this, spawnArgs, statname, value, &idealWeapon, true ); - if(!idStr::Icmp( statname, "ammo_bloodstone" ) ) { - //int i = inventory.AmmoIndexForAmmoClass( statname ); - //int max = inventory.MaxAmmoForAmmoClass( this, statname ); - //if(hud && inventory.ammo[ i ] >= max) { - if(hud) { - - //Force an update of the bloodstone ammount - int ammoRequired; - ammo_t ammo_i = inventory.AmmoIndexForWeaponClass( "weapon_bloodstone_passive", &ammoRequired ); - int bloodstoneAmmo = inventory.HasAmmo( ammo_i, ammoRequired ); - hud->SetStateString("player_bloodstone_ammo", va("%i", bloodstoneAmmo)); - - hud->HandleNamedEvent("bloodstoneReady"); - //Make sure we unlock the ability to harvest - harvest_lock = false; - } - } - return ret; -#else - return inventory.Give( this, spawnArgs, statname, value, &idealWeapon, true ); -#endif - } - return true; -} - - -/* -=============== -idPlayer::GiveHealthPool - -adds health to the player health pool -=============== -*/ -void idPlayer::GiveHealthPool( float amt ) { - - if ( AI_DEAD ) { - return; - } - - if ( health > 0 ) { - healthPool += amt; - if ( healthPool > inventory.maxHealth - health ) { - healthPool = inventory.maxHealth - health; - } - nextHealthPulse = gameLocal.time; - } -} - -/* -=============== -idPlayer::GiveItem - -Returns false if the item shouldn't be picked up -=============== -*/ -bool idPlayer::GiveItem( idItem *item ) { - int i; - const idKeyValue *arg; - idDict attr; - bool gave; - int numPickup; - - if ( gameLocal.isMultiplayer && spectating ) { - return false; - } - - item->GetAttributes( attr ); - - gave = false; - numPickup = inventory.pickupItemNames.Num(); - for( i = 0; i < attr.GetNumKeyVals(); i++ ) { - arg = attr.GetKeyVal( i ); - if ( Give( arg->GetKey(), arg->GetValue() ) ) { - gave = true; - } - } - - arg = item->spawnArgs.MatchPrefix( "inv_weapon", NULL ); - if ( arg && hud ) { - // We need to update the weapon hud manually, but not - // the armor/ammo/health because they are updated every - // frame no matter what - UpdateHudWeapon( false ); - hud->HandleNamedEvent( "weaponPulse" ); - } - - // display the pickup feedback on the hud - if ( gave && ( numPickup == inventory.pickupItemNames.Num() ) ) { - inventory.AddPickupName( item->spawnArgs.GetString( "inv_name" ), item->spawnArgs.GetString( "inv_icon" ), this ); //_D3XP - } - - return gave; -} - -/* -=============== -idPlayer::PowerUpModifier -=============== -*/ -float idPlayer::PowerUpModifier( int type ) { - float mod = 1.0f; - - if ( PowerUpActive( BERSERK ) ) { - switch( type ) { - case SPEED: { - mod *= 1.7f; - break; - } - case PROJECTILE_DAMAGE: { - mod *= 2.0f; - break; - } - case MELEE_DAMAGE: { - mod *= 30.0f; - break; - } - case MELEE_DISTANCE: { - mod *= 2.0f; - break; - } - } - } - - if ( gameLocal.isMultiplayer && !gameLocal.isClient ) { - if ( PowerUpActive( MEGAHEALTH ) ) { - if ( healthPool <= 0 ) { - GiveHealthPool( 100 ); - } - } else { - healthPool = 0; - } - -#ifdef _D3XP - /*if( PowerUpActive( HASTE ) ) { - switch( type ) { - case SPEED: { - mod = 1.7f; - break; - } - } - }*/ -#endif - } - - return mod; -} - -/* -=============== -idPlayer::PowerUpActive -=============== -*/ -bool idPlayer::PowerUpActive( int powerup ) const { - return ( inventory.powerups & ( 1 << powerup ) ) != 0; -} - -/* -=============== -idPlayer::GivePowerUp -=============== -*/ -bool idPlayer::GivePowerUp( int powerup, int time ) { - const char *sound; - const char *skin; - - if ( powerup >= 0 && powerup < MAX_POWERUPS ) { - - if ( gameLocal.isServer ) { - idBitMsg msg; - byte msgBuf[MAX_EVENT_PARAM_SIZE]; - - msg.Init( msgBuf, sizeof( msgBuf ) ); - msg.WriteShort( powerup ); - msg.WriteBits( 1, 1 ); - ServerSendEvent( EVENT_POWERUP, &msg, false, -1 ); - } - - if ( powerup != MEGAHEALTH ) { - inventory.GivePowerUp( this, powerup, time ); - } - - const idDeclEntityDef *def = NULL; - - switch( powerup ) { - case BERSERK: { - if(gameLocal.isMultiplayer && !gameLocal.isClient) { - inventory.AddPickupName("#str_00100627", "", this); - } - - if(gameLocal.isMultiplayer) { - if ( spawnArgs.GetString( "snd_berserk_third", "", &sound ) ) { - StartSoundShader( declManager->FindSound( sound ), SND_CHANNEL_DEMONIC, 0, false, NULL ); - } - } - - - if ( baseSkinName.Length() ) { - powerUpSkin = declManager->FindSkin( baseSkinName + "_berserk" ); - } - if ( !gameLocal.isClient ) { -#ifdef _D3XP - if( !gameLocal.isMultiplayer ) { - // Trying it out without the health boost (1/3/05) - // Give the player full health in single-player - // health = 100; - } else { - // Switch to fists in multiplayer - idealWeapon = 1; - } -#else - idealWeapon = 0; -#endif - } - break; - } - case INVISIBILITY: { - if(gameLocal.isMultiplayer && !gameLocal.isClient) { - inventory.AddPickupName("#str_00100628", "", this); - } - spawnArgs.GetString( "skin_invisibility", "", &skin ); - powerUpSkin = declManager->FindSkin( skin ); - // remove any decals from the model - if ( modelDefHandle != -1 ) { - gameRenderWorld->RemoveDecals( modelDefHandle ); - } - if ( weapon.GetEntity() ) { - weapon.GetEntity()->UpdateSkin(); - } -/* if ( spawnArgs.GetString( "snd_invisibility", "", &sound ) ) { - StartSoundShader( declManager->FindSound( sound ), SND_CHANNEL_ANY, 0, false, NULL ); - } */ - break; - } - case ADRENALINE: { -#ifdef _D3XP - inventory.AddPickupName("#str_00100799", "", this); -#endif - stamina = 100.0f; - break; - } - case MEGAHEALTH: { - if(gameLocal.isMultiplayer && !gameLocal.isClient) { - inventory.AddPickupName("#str_00100629", "", this); - } - if ( spawnArgs.GetString( "snd_megahealth", "", &sound ) ) { - StartSoundShader( declManager->FindSound( sound ), SND_CHANNEL_ANY, 0, false, NULL ); - } - def = gameLocal.FindEntityDef( "powerup_megahealth", false ); - if ( def ) { - health = def->dict.GetInt( "inv_health" ); - } - break; - } -#ifdef _D3XP - case HELLTIME: { - if ( spawnArgs.GetString( "snd_helltime_start", "", &sound ) ) { - PostEventMS( &EV_StartSoundShader, 0, sound, SND_CHANNEL_ANY ); - } - if ( spawnArgs.GetString( "snd_helltime_loop", "", &sound ) ) { - PostEventMS( &EV_StartSoundShader, 0, sound, SND_CHANNEL_DEMONIC ); - } - break; - } - case ENVIROSUIT: { - // Turn on the envirosuit sound - if ( gameSoundWorld ) { - gameSoundWorld->SetEnviroSuit( true ); - } - - // Put the helmet and lights on the player - idDict args; - - // Light - const idDict *lightDef = gameLocal.FindEntityDefDict( "envirosuit_light", false ); - if ( lightDef ) { - idEntity *temp; - gameLocal.SpawnEntityDef( *lightDef, &temp, false ); - - idLight *eLight = static_cast(temp); - eLight->GetPhysics()->SetOrigin( firstPersonViewOrigin ); - eLight->UpdateVisuals(); - eLight->Present(); - - enviroSuitLight = eLight; - } - break; - } - case ENVIROTIME: { - hudPowerup = ENVIROTIME; - // The HUD display bar is fixed at 60 seconds - hudPowerupDuration = 60000; - break; - } - case INVULNERABILITY: { - if(gameLocal.isMultiplayer && !gameLocal.isClient) { - inventory.AddPickupName("#str_00100630", "", this); - } - if(gameLocal.isMultiplayer) { - /*if ( spawnArgs.GetString( "snd_invulnerable", "", &sound ) ) { - StartSoundShader( declManager->FindSound( sound ), SND_CHANNEL_DEMONIC, 0, false, NULL ); - }*/ - if ( baseSkinName.Length() ) { - powerUpSkin = declManager->FindSkin( baseSkinName + "_invuln" ); - } - } - break; - } - /*case HASTE: { - if(gameLocal.isMultiplayer && !gameLocal.isClient) { - inventory.AddPickupName("#str_00100631", "", this); - } - - if ( baseSkinName.Length() ) { - powerUpSkin = declManager->FindSkin( baseSkinName + "_haste" ); - } - break; - }*/ -#endif - } - - if ( hud ) { - hud->HandleNamedEvent( "itemPickup" ); - } - - return true; - } else { - gameLocal.Warning( "Player given power up %i\n which is out of range", powerup ); - } - return false; -} - -/* -============== -idPlayer::ClearPowerup -============== -*/ -void idPlayer::ClearPowerup( int i ) { - - if ( gameLocal.isServer ) { - idBitMsg msg; - byte msgBuf[MAX_EVENT_PARAM_SIZE]; - - msg.Init( msgBuf, sizeof( msgBuf ) ); - msg.WriteShort( i ); - msg.WriteBits( 0, 1 ); - ServerSendEvent( EVENT_POWERUP, &msg, false, -1 ); - } - - powerUpSkin = NULL; - inventory.powerups &= ~( 1 << i ); - inventory.powerupEndTime[ i ] = 0; - switch( i ) { - case BERSERK: { - if(gameLocal.isMultiplayer) { - StopSound( SND_CHANNEL_DEMONIC, false ); - } -#ifdef _D3XP - if(!gameLocal.isMultiplayer) { - StopHealthRecharge(); - } -#endif - break; - } - case INVISIBILITY: { - if ( weapon.GetEntity() ) { - weapon.GetEntity()->UpdateSkin(); - } - break; - } -#ifdef _D3XP - case HELLTIME: { - StopSound( SND_CHANNEL_DEMONIC, false ); - break; - } - case ENVIROSUIT: { - - hudPowerup = -1; - - // Turn off the envirosuit sound - if ( gameSoundWorld ) { - gameSoundWorld->SetEnviroSuit( false ); - } - - // Take off the helmet and lights - if ( enviroSuitLight.IsValid() ) { - enviroSuitLight.GetEntity()->PostEventMS( &EV_Remove, 0 ); - } - enviroSuitLight = NULL; - break; - } - case INVULNERABILITY: { - if(gameLocal.isMultiplayer) { - StopSound( SND_CHANNEL_DEMONIC, false ); - } - } - /*case HASTE: { - if(gameLocal.isMultiplayer) { - StopSound( SND_CHANNEL_DEMONIC, false ); - } - }*/ -#endif - } -} - -/* -============== -idPlayer::UpdatePowerUps -============== -*/ -void idPlayer::UpdatePowerUps( void ) { - int i; - - if ( !gameLocal.isClient ) { - for ( i = 0; i < MAX_POWERUPS; i++ ) { -#ifdef _D3XP - if ( ( inventory.powerups & ( 1 << i ) ) && inventory.powerupEndTime[i] > gameLocal.time ) { - switch( i ) { - case ENVIROSUIT: { - if ( enviroSuitLight.IsValid() ) { - idAngles lightAng = firstPersonViewAxis.ToAngles(); - idVec3 lightOrg = firstPersonViewOrigin; - const idDict *lightDef = gameLocal.FindEntityDefDict( "envirosuit_light", false ); - - idVec3 enviroOffset = lightDef->GetVector( "enviro_offset" ); - idVec3 enviroAngleOffset = lightDef->GetVector( "enviro_angle_offset" ); - - lightOrg += (enviroOffset.x * firstPersonViewAxis[0]); - lightOrg += (enviroOffset.y * firstPersonViewAxis[1]); - lightOrg += (enviroOffset.z * firstPersonViewAxis[2]); - lightAng.pitch += enviroAngleOffset.x; - lightAng.yaw += enviroAngleOffset.y; - lightAng.roll += enviroAngleOffset.z; - - enviroSuitLight.GetEntity()->GetPhysics()->SetOrigin( lightOrg ); - enviroSuitLight.GetEntity()->GetPhysics()->SetAxis( lightAng.ToMat3() ); - enviroSuitLight.GetEntity()->UpdateVisuals(); - enviroSuitLight.GetEntity()->Present(); - } - break; - } - default: { - break; - } - } - } -#endif - if ( PowerUpActive( i ) && inventory.powerupEndTime[i] <= gameLocal.time ) { - ClearPowerup( i ); - } - } - } - - if ( health > 0 ) { - if ( powerUpSkin ) { - renderEntity.customSkin = powerUpSkin; - } else { - renderEntity.customSkin = skin; - } - } - - if ( healthPool && gameLocal.time > nextHealthPulse && !AI_DEAD && health > 0 ) { - assert( !gameLocal.isClient ); // healthPool never be set on client - int amt = ( healthPool > 5 ) ? 5 : healthPool; - health += amt; - if ( health > inventory.maxHealth ) { - health = inventory.maxHealth; - healthPool = 0; - } else { - healthPool -= amt; - } - nextHealthPulse = gameLocal.time + HEALTHPULSE_TIME; - healthPulse = true; - } - - if ( !gameLocal.inCinematic && influenceActive == 0 && g_skill.GetInteger() == 3 && gameLocal.time > nextHealthTake && !AI_DEAD && health > g_healthTakeLimit.GetInteger() ) { - assert( !gameLocal.isClient ); // healthPool never be set on client - -#ifdef _D3XP - if(!PowerUpActive(INVULNERABILITY)) { -#endif - health -= g_healthTakeAmt.GetInteger(); - if ( health < g_healthTakeLimit.GetInteger() ) { - health = g_healthTakeLimit.GetInteger(); - } -#ifdef _D3XP - } -#endif - nextHealthTake = gameLocal.time + g_healthTakeTime.GetInteger() * 1000; - healthTake = true; - } -} - -/* -=============== -idPlayer::ClearPowerUps -=============== -*/ -void idPlayer::ClearPowerUps( void ) { - int i; - for ( i = 0; i < MAX_POWERUPS; i++ ) { - if ( PowerUpActive( i ) ) { - ClearPowerup( i ); - } - } - inventory.ClearPowerUps(); - -#ifdef _D3XP - if ( gameLocal.isMultiplayer ) { - if ( enviroSuitLight.IsValid() ) { - enviroSuitLight.GetEntity()->PostEventMS( &EV_Remove, 0 ); - } - } -#endif -} - -/* -=============== -idPlayer::GiveInventoryItem -=============== -*/ -bool idPlayer::GiveInventoryItem( idDict *item ) { - if ( gameLocal.isMultiplayer && spectating ) { - return false; - } - inventory.items.Append( new idDict( *item ) ); - idItemInfo info; - const char* itemName = item->GetString( "inv_name" ); - if ( idStr::Cmpn( itemName, STRTABLE_ID, STRTABLE_ID_LENGTH ) == 0 ) { - info.name = common->GetLanguageDict()->GetString( itemName ); - } else { - info.name = itemName; - } - info.icon = item->GetString( "inv_icon" ); - inventory.pickupItemNames.Append( info ); - if ( hud ) { - hud->SetStateString( "itemicon", info.icon ); - hud->HandleNamedEvent( "invPickup" ); - } - -#ifdef _D3XP //Added to support powercells - if(item->GetInt("inv_powercell") && focusUI) { - //Reset the powercell count - int powerCellCount = 0; - for ( int j = 0; j < inventory.items.Num(); j++ ) { - idDict *item = inventory.items[ j ]; - if(item->GetInt("inv_powercell")) { - powerCellCount++; - } - } - focusUI->SetStateInt( "powercell_count", powerCellCount ); - } -#endif - - return true; -} - -#ifdef _D3XP //BSM: Implementing this defined function for scripted give inventory items -/* -============== -idPlayer::GiveInventoryItem -============== -*/ -bool idPlayer::GiveInventoryItem( const char *name ) { - idDict args; - - args.Set( "classname", name ); - args.Set( "owner", this->name.c_str() ); - gameLocal.SpawnEntityDef( args); - return true; -} -#endif - -/* -============== -idPlayer::UpdateObjectiveInfo -============== - */ -void idPlayer::UpdateObjectiveInfo( void ) { - if ( objectiveSystem == NULL ) { - return; - } - objectiveSystem->SetStateString( "objective1", "" ); - objectiveSystem->SetStateString( "objective2", "" ); - objectiveSystem->SetStateString( "objective3", "" ); - for ( int i = 0; i < inventory.objectiveNames.Num(); i++ ) { - objectiveSystem->SetStateString( va( "objective%i", i+1 ), "1" ); - objectiveSystem->SetStateString( va( "objectivetitle%i", i+1 ), inventory.objectiveNames[i].title.c_str() ); - objectiveSystem->SetStateString( va( "objectivetext%i", i+1 ), inventory.objectiveNames[i].text.c_str() ); - objectiveSystem->SetStateString( va( "objectiveshot%i", i+1 ), inventory.objectiveNames[i].screenshot.c_str() ); - } - objectiveSystem->StateChanged( gameLocal.time ); -} - -/* -=============== -idPlayer::GiveObjective -=============== -*/ -void idPlayer::GiveObjective( const char *title, const char *text, const char *screenshot ) { - idObjectiveInfo info; - info.title = title; - info.text = text; - info.screenshot = screenshot; - inventory.objectiveNames.Append( info ); - ShowObjective( "newObjective" ); - if ( hud ) { - hud->HandleNamedEvent( "newObjective" ); - } -} - -/* -=============== -idPlayer::CompleteObjective -=============== -*/ -void idPlayer::CompleteObjective( const char *title ) { - int c = inventory.objectiveNames.Num(); - for ( int i = 0; i < c; i++ ) { - if ( idStr::Icmp(inventory.objectiveNames[i].title, title) == 0 ) { - inventory.objectiveNames.RemoveIndex( i ); - break; - } - } - ShowObjective( "newObjectiveComplete" ); - - if ( hud ) { - hud->HandleNamedEvent( "newObjectiveComplete" ); - } -} - -/* -=============== -idPlayer::GiveVideo -=============== -*/ -void idPlayer::GiveVideo( const char *videoName, idDict *item ) { - - if ( videoName == NULL || *videoName == 0 ) { - return; - } - - inventory.videos.AddUnique( videoName ); - - if ( item ) { - idItemInfo info; - info.name = item->GetString( "inv_name" ); - info.icon = item->GetString( "inv_icon" ); - inventory.pickupItemNames.Append( info ); - } - if ( hud ) { - hud->HandleNamedEvent( "videoPickup" ); - } -} - -/* -=============== -idPlayer::GiveSecurity -=============== -*/ -void idPlayer::GiveSecurity( const char *security ) { - GetPDA()->SetSecurity( security ); - if ( hud ) { - hud->SetStateString( "pda_security", "1" ); - hud->HandleNamedEvent( "securityPickup" ); - } -} - -/* -=============== -idPlayer::GiveEmail -=============== -*/ -void idPlayer::GiveEmail( const char *emailName ) { - - if ( emailName == NULL || *emailName == 0 ) { - return; - } - - inventory.emails.AddUnique( emailName ); - GetPDA()->AddEmail( emailName ); - - if ( hud ) { - hud->HandleNamedEvent( "emailPickup" ); - } -} - -/* -=============== -idPlayer::GivePDA -=============== -*/ -void idPlayer::GivePDA( const char *pdaName, idDict *item ) -{ - if ( gameLocal.isMultiplayer && spectating ) { - return; - } - - if ( item ) { - inventory.pdaSecurity.AddUnique( item->GetString( "inv_name" ) ); - } - - if ( pdaName == NULL || *pdaName == 0 ) { - pdaName = "personal"; - } - - const idDeclPDA *pda = static_cast< const idDeclPDA* >( declManager->FindType( DECL_PDA, pdaName ) ); - - inventory.pdas.AddUnique( pdaName ); - - // Copy any videos over - for ( int i = 0; i < pda->GetNumVideos(); i++ ) { - const idDeclVideo *video = pda->GetVideoByIndex( i ); - if ( video ) { - inventory.videos.AddUnique( video->GetName() ); - } - } - - // This is kind of a hack, but it works nicely - // We don't want to display the 'you got a new pda' message during a map load - if ( gameLocal.GetFrameNum() > 10 ) { - if ( pda && hud ) { - idStr pdaName = pda->GetPdaName(); - pdaName.RemoveColors(); - hud->SetStateString( "pda", "1" ); - hud->SetStateString( "pda_text", pdaName ); - const char *sec = pda->GetSecurity(); - hud->SetStateString( "pda_security", ( sec && *sec ) ? "1" : "0" ); - hud->HandleNamedEvent( "pdaPickup" ); - } - - if ( inventory.pdas.Num() == 1 ) { - GetPDA()->RemoveAddedEmailsAndVideos(); - if ( !objectiveSystemOpen ) { - TogglePDA(); - } - objectiveSystem->HandleNamedEvent( "showPDATip" ); - //ShowTip( spawnArgs.GetString( "text_infoTitle" ), spawnArgs.GetString( "text_firstPDA" ), true ); - } - - if ( inventory.pdas.Num() > 1 && pda->GetNumVideos() > 0 && hud ) { - hud->HandleNamedEvent( "videoPickup" ); - } - } -} - -/* -=============== -idPlayer::FindInventoryItem -=============== -*/ -idDict *idPlayer::FindInventoryItem( const char *name ) { - for ( int i = 0; i < inventory.items.Num(); i++ ) { - const char *iname = inventory.items[i]->GetString( "inv_name" ); - if ( iname && *iname ) { - if ( idStr::Icmp( name, iname ) == 0 ) { - return inventory.items[i]; - } - } - } - return NULL; -} - -/* -=============== -idPlayer::RemoveInventoryItem -=============== -*/ -void idPlayer::RemoveInventoryItem( const char *name ) { - //Hack for localization - if(!idStr::Icmp(name, "Pwr Cell")) { - name = common->GetLanguageDict()->GetString( "#str_00101056" ); - } - idDict *item = FindInventoryItem(name); - if ( item ) { - RemoveInventoryItem( item ); - } -} - -/* -=============== -idPlayer::RemoveInventoryItem -=============== -*/ -void idPlayer::RemoveInventoryItem( idDict *item ) { - inventory.items.Remove( item ); - -#ifdef _D3XP //Added to support powercells - if(item->GetInt("inv_powercell") && focusUI) { - //Reset the powercell count - int powerCellCount = 0; - for ( int j = 0; j < inventory.items.Num(); j++ ) { - idDict *item = inventory.items[ j ]; - if(item->GetInt("inv_powercell")) { - powerCellCount++; - } - } - focusUI->SetStateInt( "powercell_count", powerCellCount ); - } -#endif - - delete item; -} - -/* -=============== -idPlayer::GiveItem -=============== -*/ -void idPlayer::GiveItem( const char *itemname ) { - idDict args; - - args.Set( "classname", itemname ); - args.Set( "owner", name.c_str() ); - gameLocal.SpawnEntityDef( args ); - if ( hud ) { - hud->HandleNamedEvent( "itemPickup" ); - } -} - -/* -================== -idPlayer::SlotForWeapon -================== -*/ -int idPlayer::SlotForWeapon( const char *weaponName ) { - int i; - - for( i = 0; i < MAX_WEAPONS; i++ ) { - const char *weap = spawnArgs.GetString( va( "def_weapon%d", i ) ); - if ( !idStr::Cmp( weap, weaponName ) ) { - return i; - } - } - - // not found - return -1; -} - -/* -=============== -idPlayer::Reload -=============== -*/ -void idPlayer::Reload( void ) { - if ( gameLocal.isClient ) { - return; - } - - if ( spectating || gameLocal.inCinematic || influenceActive ) { - return; - } - - if ( weapon.GetEntity() && weapon.GetEntity()->IsLinked() ) { - weapon.GetEntity()->Reload(); - } -} - -/* -=============== -idPlayer::NextBestWeapon -=============== -*/ -void idPlayer::NextBestWeapon( void ) { - const char *weap; - int w = MAX_WEAPONS; - - if ( gameLocal.isClient || !weaponEnabled ) { - return; - } - - while ( w > 0 ) { - w--; - weap = spawnArgs.GetString( va( "def_weapon%d", w ) ); -#ifdef _D3XP - if ( !weap[ 0 ] || ( ( inventory.weapons & ( 1 << w ) ) == 0 ) || ( !inventory.HasAmmo( weap, true, this ) ) ) { -#else - if ( !weap[ 0 ] || ( ( inventory.weapons & ( 1 << w ) ) == 0 ) || ( !(inventory.HasAmmo( weap )) ) ) { -#endif - continue; - } - if ( !spawnArgs.GetBool( va( "weapon%d_best", w ) ) ) { - continue; - } - -#ifdef _D3XP - //Some weapons will report having ammo but the clip is empty and - //will not have enough to fill the clip (i.e. Double Barrel Shotgun with 1 round left) - //We need to skip these weapons because they cannot be used - if(inventory.HasEmptyClipCannotRefill(weap, this)) { - continue; - } -#endif - - break; - } - idealWeapon = w; - weaponSwitchTime = gameLocal.time + WEAPON_SWITCH_DELAY; - UpdateHudWeapon(); -} - -/* -=============== -idPlayer::NextWeapon -=============== -*/ -void idPlayer::NextWeapon( void ) { - - const char *weap; - int w; - - if ( !weaponEnabled || spectating || hiddenWeapon || gameLocal.inCinematic || gameLocal.world->spawnArgs.GetBool( "no_Weapons" ) || health < 0 ) { - return; - } - - if ( gameLocal.isClient ) { - return; - } - - // check if we have any weapons - if ( !inventory.weapons ) { - return; - } - - w = idealWeapon; - while( 1 ) { - w++; - if ( w >= MAX_WEAPONS ) { - w = 0; - } - weap = spawnArgs.GetString( va( "def_weapon%d", w ) ); - if ( !spawnArgs.GetBool( va( "weapon%d_cycle", w ) ) ) { - continue; - } - if ( !weap[ 0 ] ) { - continue; - } - if ( ( inventory.weapons & ( 1 << w ) ) == 0 ) { - continue; - } - -#ifdef _D3XP - if ( inventory.HasAmmo( weap, true, this ) || w == weapon_bloodstone ) { -#else - if ( inventory.HasAmmo( weap ) ) { -#endif - break; - } - } - - if ( ( w != currentWeapon ) && ( w != idealWeapon ) ) { - idealWeapon = w; - weaponSwitchTime = gameLocal.time + WEAPON_SWITCH_DELAY; - UpdateHudWeapon(); - } -} - -/* -=============== -idPlayer::PrevWeapon -=============== -*/ -void idPlayer::PrevWeapon( void ) { - - const char *weap; - int w; - - if ( !weaponEnabled || spectating || hiddenWeapon || gameLocal.inCinematic || gameLocal.world->spawnArgs.GetBool( "no_Weapons" ) || health < 0 ) { - return; - } - - if ( gameLocal.isClient ) { - return; - } - - // check if we have any weapons - if ( !inventory.weapons ) { - return; - } - - w = idealWeapon; - while( 1 ) { - w--; - if ( w < 0 ) { - w = MAX_WEAPONS - 1; - } - weap = spawnArgs.GetString( va( "def_weapon%d", w ) ); - if ( !spawnArgs.GetBool( va( "weapon%d_cycle", w ) ) ) { - continue; - } - if ( !weap[ 0 ] ) { - continue; - } - if ( ( inventory.weapons & ( 1 << w ) ) == 0 ) { - continue; - } -#ifdef _D3XP - if ( inventory.HasAmmo( weap, true, this ) || w == weapon_bloodstone ) { -#else - if ( inventory.HasAmmo( weap ) ) { -#endif - break; - } - } - - if ( ( w != currentWeapon ) && ( w != idealWeapon ) ) { - idealWeapon = w; - weaponSwitchTime = gameLocal.time + WEAPON_SWITCH_DELAY; - UpdateHudWeapon(); - } -} - -/* -=============== -idPlayer::SelectWeapon -=============== -*/ -void idPlayer::SelectWeapon( int num, bool force ) { - const char *weap; - - if ( !weaponEnabled || spectating || gameLocal.inCinematic || health < 0 ) { - return; - } - - if ( ( num < 0 ) || ( num >= MAX_WEAPONS ) ) { - return; - } - - if ( gameLocal.isClient ) { - return; - } - - if ( ( num != weapon_pda ) && gameLocal.world->spawnArgs.GetBool( "no_Weapons" ) ) { - num = weapon_fists; - hiddenWeapon ^= 1; - if ( hiddenWeapon && weapon.GetEntity() ) { - weapon.GetEntity()->LowerWeapon(); - } else { - weapon.GetEntity()->RaiseWeapon(); - } - } - - weap = spawnArgs.GetString( va( "def_weapon%d", num ) ); - if ( !weap[ 0 ] ) { - gameLocal.Printf( "Invalid weapon\n" ); - return; - } - -#ifdef _D3XP - //Is the weapon a toggle weapon - WeaponToggle_t* weaponToggle; - if(weaponToggles.Get(va("weapontoggle%d", num), &weaponToggle)) { - - int weaponToggleIndex = 0; - - //Find the current Weapon in the list - int currentIndex = -1; - for(int i = 0; i < weaponToggle->toggleList.Num(); i++) { - if(weaponToggle->toggleList[i] == idealWeapon) { - currentIndex = i; - break; - } - } - if(currentIndex == -1) { - //Didn't find the current weapon so select the first item - weaponToggleIndex = 0; - } else { - //Roll to the next available item in the list - weaponToggleIndex = currentIndex; - weaponToggleIndex++; - if(weaponToggleIndex >= weaponToggle->toggleList.Num()) { - weaponToggleIndex = 0; - } - } - - for(int i = 0; i < weaponToggle->toggleList.Num(); i++) { - - //Is it available - if(inventory.weapons & ( 1 << weaponToggle->toggleList[weaponToggleIndex])) { - break; - } - - weaponToggleIndex++; - if(weaponToggleIndex >= weaponToggle->toggleList.Num()) { - weaponToggleIndex = 0; - } - } - - num = weaponToggle->toggleList[weaponToggleIndex]; - } -#endif - - if ( force || ( inventory.weapons & ( 1 << num ) ) ) { -#ifdef _D3XP - if ( !inventory.HasAmmo( weap, true, this ) && !spawnArgs.GetBool( va( "weapon%d_allowempty", num ) ) ) { -#else - if ( !inventory.HasAmmo( weap ) && !spawnArgs.GetBool( va( "weapon%d_allowempty", num ) ) ) { -#endif - return; - } - if ( ( previousWeapon >= 0 ) && ( idealWeapon == num ) && ( spawnArgs.GetBool( va( "weapon%d_toggle", num ) ) ) ) { - weap = spawnArgs.GetString( va( "def_weapon%d", previousWeapon ) ); -#ifdef _D3XP - if ( !inventory.HasAmmo( weap, true, this ) && !spawnArgs.GetBool( va( "weapon%d_allowempty", previousWeapon ) ) ) { -#else - if ( !inventory.HasAmmo( weap ) && !spawnArgs.GetBool( va( "weapon%d_allowempty", previousWeapon ) ) ) { -#endif - return; - } - idealWeapon = previousWeapon; - } else if ( ( weapon_pda >= 0 ) && ( num == weapon_pda ) && ( inventory.pdas.Num() == 0 ) ) { - ShowTip( spawnArgs.GetString( "text_infoTitle" ), spawnArgs.GetString( "text_noPDA" ), true ); - return; - } else { - idealWeapon = num; - } - UpdateHudWeapon(); - } -} - -/* -================= -idPlayer::DropWeapon -================= -*/ -void idPlayer::DropWeapon( bool died ) { - idVec3 forward, up; - int inclip, ammoavailable; - - assert( !gameLocal.isClient ); - - if ( spectating || weaponGone || weapon.GetEntity() == NULL ) { - return; - } - - if ( ( !died && !weapon.GetEntity()->IsReady() ) || weapon.GetEntity()->IsReloading() ) { - return; - } - // ammoavailable is how many shots we can fire - // inclip is which amount is in clip right now - ammoavailable = weapon.GetEntity()->AmmoAvailable(); - inclip = weapon.GetEntity()->AmmoInClip(); - - // don't drop a grenade if we have none left - if ( !idStr::Icmp( idWeapon::GetAmmoNameForNum( weapon.GetEntity()->GetAmmoType() ), "ammo_grenades" ) && ( ammoavailable - inclip <= 0 ) ) { - return; - } - -#ifdef _D3XP - ammoavailable += inclip; -#endif - - // expect an ammo setup that makes sense before doing any dropping - // ammoavailable is -1 for infinite ammo, and weapons like chainsaw - // a bad ammo config usually indicates a bad weapon state, so we should not drop - // used to be an assertion check, but it still happens in edge cases - - if ( ( ammoavailable != -1 ) && ( ammoavailable < 0 ) ) { - common->DPrintf( "idPlayer::DropWeapon: bad ammo setup\n" ); - return; - } - idEntity *item = NULL; - if ( died ) { - // ain't gonna throw you no weapon if I'm dead - item = weapon.GetEntity()->DropItem( vec3_origin, 0, WEAPON_DROP_TIME, died ); - } else { - viewAngles.ToVectors( &forward, NULL, &up ); - item = weapon.GetEntity()->DropItem( 250.0f * forward + 150.0f * up, 500, WEAPON_DROP_TIME, died ); - } - if ( !item ) { - return; - } - // set the appropriate ammo in the dropped object - const idKeyValue * keyval = item->spawnArgs.MatchPrefix( "inv_ammo_" ); - if ( keyval ) { - item->spawnArgs.SetInt( keyval->GetKey(), ammoavailable ); - idStr inclipKey = keyval->GetKey(); - inclipKey.Insert( "inclip_", 4 ); -#ifdef _D3XP - inclipKey.Insert( va("%.2d", currentWeapon), 11); -#endif - item->spawnArgs.SetInt( inclipKey, inclip ); - } - if ( !died ) { - // remove from our local inventory completely - inventory.Drop( spawnArgs, item->spawnArgs.GetString( "inv_weapon" ), -1 ); - weapon.GetEntity()->ResetAmmoClip(); - NextWeapon(); - weapon.GetEntity()->WeaponStolen(); - weaponGone = true; - } -} - -/* -================= -idPlayer::StealWeapon -steal the target player's current weapon -================= -*/ -void idPlayer::StealWeapon( idPlayer *player ) { - assert( !gameLocal.isClient ); - - // make sure there's something to steal - idWeapon *player_weapon = static_cast< idWeapon * >( player->weapon.GetEntity() ); - if ( !player_weapon || !player_weapon->CanDrop() || weaponGone ) { - return; - } - // steal - we need to effectively force the other player to abandon his weapon - int newweap = player->currentWeapon; - if ( newweap == -1 ) { - return; - } - // might be just dropped - check inventory - if ( ! ( player->inventory.weapons & ( 1 << newweap ) ) ) { - return; - } - const char *weapon_classname = spawnArgs.GetString( va( "def_weapon%d", newweap ) ); - assert( weapon_classname ); - int ammoavailable = player->weapon.GetEntity()->AmmoAvailable(); - int inclip = player->weapon.GetEntity()->AmmoInClip(); - -#ifdef _D3XP - ammoavailable += inclip; -#endif - - if ( ( ammoavailable != -1 ) && ( ammoavailable < 0 ) ) { - // see DropWeapon - common->DPrintf( "idPlayer::StealWeapon: bad ammo setup\n" ); - // we still steal the weapon, so let's use the default ammo levels - inclip = -1; - const idDeclEntityDef *decl = gameLocal.FindEntityDef( weapon_classname ); - assert( decl ); - const idKeyValue *keypair = decl->dict.MatchPrefix( "inv_ammo_" ); - assert( keypair ); - ammoavailable = atoi( keypair->GetValue() ); - } - - player->weapon.GetEntity()->WeaponStolen(); - player->inventory.Drop( player->spawnArgs, NULL, newweap ); - player->SelectWeapon( weapon_fists, false ); - // in case the robbed player is firing rounds with a continuous fire weapon like the chaingun/plasma etc. - // this will ensure the firing actually stops - player->weaponGone = true; - - // give weapon, setup the ammo count - Give( "weapon", weapon_classname ); - ammo_t ammo_i = player->inventory.AmmoIndexForWeaponClass( weapon_classname, NULL ); - idealWeapon = newweap; - inventory.ammo[ ammo_i ] += ammoavailable; - -#ifndef _D3XP - inventory.clip[ newweap ] = inclip; -#endif -} - -/* -=============== -idPlayer::ActiveGui -=============== -*/ -idUserInterface *idPlayer::ActiveGui( void ) { - if ( objectiveSystemOpen ) { - return objectiveSystem; - } - - return focusUI; -} - -/* -=============== -idPlayer::Weapon_Combat -=============== -*/ -void idPlayer::Weapon_Combat( void ) { - if ( influenceActive || !weaponEnabled || gameLocal.inCinematic || privateCameraView ) { - return; - } - - weapon.GetEntity()->RaiseWeapon(); - if ( weapon.GetEntity()->IsReloading() ) { - if ( !AI_RELOAD ) { - AI_RELOAD = true; - SetState( "ReloadWeapon" ); - UpdateScript(); - } - } else { - AI_RELOAD = false; - } - - if ( idealWeapon == weapon_soulcube && soulCubeProjectile.GetEntity() != NULL ) { - idealWeapon = currentWeapon; - } - - if ( idealWeapon != currentWeapon ) { - if ( weaponCatchup ) { - assert( gameLocal.isClient ); - - currentWeapon = idealWeapon; - weaponGone = false; - animPrefix = spawnArgs.GetString( va( "def_weapon%d", currentWeapon ) ); - weapon.GetEntity()->GetWeaponDef( animPrefix, inventory.clip[ currentWeapon ] ); - animPrefix.Strip( "weapon_" ); - - weapon.GetEntity()->NetCatchup(); - const function_t *newstate = GetScriptFunction( "NetCatchup" ); - if ( newstate ) { - SetState( newstate ); - UpdateScript(); - } - weaponCatchup = false; - } else { - if ( weapon.GetEntity()->IsReady() ) { - weapon.GetEntity()->PutAway(); - } - - if ( weapon.GetEntity()->IsHolstered() ) { - assert( idealWeapon >= 0 ); - assert( idealWeapon < MAX_WEAPONS ); - - if ( currentWeapon != weapon_pda && !spawnArgs.GetBool( va( "weapon%d_toggle", currentWeapon ) ) ) { - previousWeapon = currentWeapon; - } - currentWeapon = idealWeapon; - weaponGone = false; - animPrefix = spawnArgs.GetString( va( "def_weapon%d", currentWeapon ) ); - weapon.GetEntity()->GetWeaponDef( animPrefix, inventory.clip[ currentWeapon ] ); - animPrefix.Strip( "weapon_" ); - - weapon.GetEntity()->Raise(); - } - } - } else { - weaponGone = false; // if you drop and re-get weap, you may miss the = false above - if ( weapon.GetEntity()->IsHolstered() ) { - if ( !weapon.GetEntity()->AmmoAvailable() ) { - // weapons can switch automatically if they have no more ammo - NextBestWeapon(); - } else { - weapon.GetEntity()->Raise(); - state = GetScriptFunction( "RaiseWeapon" ); - if ( state ) { - SetState( state ); - } - } - } - } - - // check for attack - AI_WEAPON_FIRED = false; - if ( !influenceActive ) { - if ( ( usercmd.buttons & BUTTON_ATTACK ) && !weaponGone ) { - FireWeapon(); - } else if ( oldButtons & BUTTON_ATTACK ) { - AI_ATTACK_HELD = false; - weapon.GetEntity()->EndAttack(); - } - } - - // update our ammo clip in our inventory - if ( ( currentWeapon >= 0 ) && ( currentWeapon < MAX_WEAPONS ) ) { - inventory.clip[ currentWeapon ] = weapon.GetEntity()->AmmoInClip(); - if ( hud && ( currentWeapon == idealWeapon ) ) { - UpdateHudAmmo( hud ); - } - } -} - -/* -=============== -idPlayer::Weapon_NPC -=============== -*/ -void idPlayer::Weapon_NPC( void ) { - if ( idealWeapon != currentWeapon ) { - Weapon_Combat(); - } - StopFiring(); - weapon.GetEntity()->LowerWeapon(); - - if ( ( usercmd.buttons & BUTTON_ATTACK ) && !( oldButtons & BUTTON_ATTACK ) ) { - buttonMask |= BUTTON_ATTACK; - focusCharacter->TalkTo( this ); - } -} - -/* -=============== -idPlayer::LowerWeapon -=============== -*/ -void idPlayer::LowerWeapon( void ) { - if ( weapon.GetEntity() && !weapon.GetEntity()->IsHidden() ) { - weapon.GetEntity()->LowerWeapon(); - } -} - -/* -=============== -idPlayer::RaiseWeapon -=============== -*/ -void idPlayer::RaiseWeapon( void ) { - if ( weapon.GetEntity() && weapon.GetEntity()->IsHidden() ) { - weapon.GetEntity()->RaiseWeapon(); - } -} - -/* -=============== -idPlayer::WeaponLoweringCallback -=============== -*/ -void idPlayer::WeaponLoweringCallback( void ) { - SetState( "LowerWeapon" ); - UpdateScript(); -} - -/* -=============== -idPlayer::WeaponRisingCallback -=============== -*/ -void idPlayer::WeaponRisingCallback( void ) { - SetState( "RaiseWeapon" ); - UpdateScript(); -} - -/* -=============== -idPlayer::Weapon_GUI -=============== -*/ -void idPlayer::Weapon_GUI( void ) { - - if ( !objectiveSystemOpen ) { - if ( idealWeapon != currentWeapon ) { - Weapon_Combat(); - } - StopFiring(); - weapon.GetEntity()->LowerWeapon(); - } - - // disable click prediction for the GUIs. handy to check the state sync does the right thing - if ( gameLocal.isClient && !net_clientPredictGUI.GetBool() ) { - return; - } - - if ( ( oldButtons ^ usercmd.buttons ) & BUTTON_ATTACK ) { - sysEvent_t ev; - const char *command = NULL; - bool updateVisuals = false; - - idUserInterface *ui = ActiveGui(); - if ( ui ) { - ev = sys->GenerateMouseButtonEvent( 1, ( usercmd.buttons & BUTTON_ATTACK ) != 0 ); - command = ui->HandleEvent( &ev, gameLocal.time, &updateVisuals ); - if ( updateVisuals && focusGUIent && ui == focusUI ) { - focusGUIent->UpdateVisuals(); - } - } - if ( gameLocal.isClient ) { - // we predict enough, but don't want to execute commands - return; - } - if ( focusGUIent ) { - HandleGuiCommands( focusGUIent, command ); - } else { - HandleGuiCommands( this, command ); - } - } -} - -/* -=============== -idPlayer::UpdateWeapon -=============== -*/ -void idPlayer::UpdateWeapon( void ) { - if ( health <= 0 ) { - return; - } - - assert( !spectating ); - - if ( gameLocal.isClient ) { - // clients need to wait till the weapon and it's world model entity - // are present and synchronized ( weapon.worldModel idEntityPtr to idAnimatedEntity ) - if ( !weapon.GetEntity()->IsWorldModelReady() ) { - return; - } - } - - // always make sure the weapon is correctly setup before accessing it - if ( !weapon.GetEntity()->IsLinked() ) { - if ( idealWeapon != -1 ) { - animPrefix = spawnArgs.GetString( va( "def_weapon%d", idealWeapon ) ); - weapon.GetEntity()->GetWeaponDef( animPrefix, inventory.clip[ idealWeapon ] ); - assert( weapon.GetEntity()->IsLinked() ); - } else { - return; - } - } - - if ( hiddenWeapon && tipUp && usercmd.buttons & BUTTON_ATTACK ) { - HideTip(); - } - - if ( g_dragEntity.GetBool() ) { - StopFiring(); - weapon.GetEntity()->LowerWeapon(); - dragEntity.Update( this ); - } else if ( ActiveGui() ) { - // gui handling overrides weapon use - Weapon_GUI(); - } else if ( focusCharacter && ( focusCharacter->health > 0 ) ) { - Weapon_NPC(); - } else { - Weapon_Combat(); - } - - if ( hiddenWeapon ) { - weapon.GetEntity()->LowerWeapon(); - } - - // update weapon state, particles, dlights, etc - weapon.GetEntity()->PresentWeapon( showWeaponViewModel ); -} - -/* -=============== -idPlayer::SpectateFreeFly -=============== -*/ -void idPlayer::SpectateFreeFly( bool force ) { - idPlayer *player; - idVec3 newOrig; - idVec3 spawn_origin; - idAngles spawn_angles; - - player = gameLocal.GetClientByNum( spectator ); - if ( force || gameLocal.time > lastSpectateChange ) { - spectator = entityNumber; - if ( player && player != this && !player->spectating && !player->IsInTeleport() ) { - newOrig = player->GetPhysics()->GetOrigin(); - if ( player->physicsObj.IsCrouching() ) { - newOrig[ 2 ] += pm_crouchviewheight.GetFloat(); - } else { - newOrig[ 2 ] += pm_normalviewheight.GetFloat(); - } - newOrig[ 2 ] += SPECTATE_RAISE; - idBounds b = idBounds( vec3_origin ).Expand( pm_spectatebbox.GetFloat() * 0.5f ); - idVec3 start = player->GetPhysics()->GetOrigin(); - start[2] += pm_spectatebbox.GetFloat() * 0.5f; - trace_t t; - // assuming spectate bbox is inside stand or crouch box - gameLocal.clip.TraceBounds( t, start, newOrig, b, MASK_PLAYERSOLID, player ); - newOrig.Lerp( start, newOrig, t.fraction ); - SetOrigin( newOrig ); - idAngles angle = player->viewAngles; - angle[ 2 ] = 0; - SetViewAngles( angle ); - } else { - SelectInitialSpawnPoint( spawn_origin, spawn_angles ); - spawn_origin[ 2 ] += pm_normalviewheight.GetFloat(); - spawn_origin[ 2 ] += SPECTATE_RAISE; - SetOrigin( spawn_origin ); - SetViewAngles( spawn_angles ); - } - lastSpectateChange = gameLocal.time + 500; - } -} - -/* -=============== -idPlayer::SpectateCycle -=============== -*/ -void idPlayer::SpectateCycle( void ) { - idPlayer *player; - - if ( gameLocal.time > lastSpectateChange ) { - int latchedSpectator = spectator; - spectator = gameLocal.GetNextClientNum( spectator ); - player = gameLocal.GetClientByNum( spectator ); - assert( player ); // never call here when the current spectator is wrong - // ignore other spectators - while ( latchedSpectator != spectator && player->spectating ) { - spectator = gameLocal.GetNextClientNum( spectator ); - player = gameLocal.GetClientByNum( spectator ); - } - lastSpectateChange = gameLocal.time + 500; - } -} - -/* -=============== -idPlayer::UpdateSpectating -=============== -*/ -void idPlayer::UpdateSpectating( void ) { - assert( spectating ); - assert( !gameLocal.isClient ); - assert( IsHidden() ); - idPlayer *player; - if ( !gameLocal.isMultiplayer ) { - return; - } - player = gameLocal.GetClientByNum( spectator ); - if ( !player || ( player->spectating && player != this ) ) { - SpectateFreeFly( true ); - } else if ( usercmd.upmove > 0 ) { - SpectateFreeFly( false ); - } else if ( usercmd.buttons & BUTTON_ATTACK ) { - SpectateCycle(); - } -} - -/* -=============== -idPlayer::HandleSingleGuiCommand -=============== -*/ -bool idPlayer::HandleSingleGuiCommand( idEntity *entityGui, idLexer *src ) { - idToken token; - - if ( !src->ReadToken( &token ) ) { - return false; - } - - if ( token == ";" ) { - return false; - } - - if ( token.Icmp( "addhealth" ) == 0 ) { - if ( entityGui && health < 100 ) { - int _health = entityGui->spawnArgs.GetInt( "gui_parm1" ); - int amt = ( _health >= HEALTH_PER_DOSE ) ? HEALTH_PER_DOSE : _health; - _health -= amt; - entityGui->spawnArgs.SetInt( "gui_parm1", _health ); - if ( entityGui->GetRenderEntity() && entityGui->GetRenderEntity()->gui[ 0 ] ) { - entityGui->GetRenderEntity()->gui[ 0 ]->SetStateInt( "gui_parm1", _health ); - } - health += amt; - if ( health > 100 ) { - health = 100; - } - } - return true; - } - - if ( token.Icmp( "ready" ) == 0 ) { - PerformImpulse( IMPULSE_17 ); - return true; - } - - if ( token.Icmp( "updatepda" ) == 0 ) { - UpdatePDAInfo( true ); - return true; - } - - if ( token.Icmp( "updatepda2" ) == 0 ) { - UpdatePDAInfo( false ); - return true; - } - - if ( token.Icmp( "stoppdavideo" ) == 0 ) { - if ( objectiveSystem && objectiveSystemOpen && pdaVideoWave.Length() > 0 ) { - StopSound( SND_CHANNEL_PDA, false ); - } - return true; - } - - if ( token.Icmp( "close" ) == 0 ) { - if ( objectiveSystem && objectiveSystemOpen ) { - TogglePDA(); - } - } - - if ( token.Icmp( "playpdavideo" ) == 0 ) { - if ( objectiveSystem && objectiveSystemOpen && pdaVideo.Length() > 0 ) { - const idMaterial *mat = declManager->FindMaterial( pdaVideo ); - if ( mat ) { - int c = mat->GetNumStages(); - for ( int i = 0; i < c; i++ ) { - const shaderStage_t *stage = mat->GetStage(i); - if ( stage && stage->texture.cinematic ) { - stage->texture.cinematic->ResetTime( gameLocal.time ); - } - } - if ( pdaVideoWave.Length() ) { - const idSoundShader *shader = declManager->FindSound( pdaVideoWave ); - StartSoundShader( shader, SND_CHANNEL_PDA, 0, false, NULL ); - } - } - } - } - - if ( token.Icmp( "playpdaaudio" ) == 0 ) { - if ( objectiveSystem && objectiveSystemOpen && pdaAudio.Length() > 0 ) { - const idSoundShader *shader = declManager->FindSound( pdaAudio ); - int ms; - StartSoundShader( shader, SND_CHANNEL_PDA, 0, false, &ms ); - StartAudioLog(); - CancelEvents( &EV_Player_StopAudioLog ); - PostEventMS( &EV_Player_StopAudioLog, ms + 150 ); - } - return true; - } - - if ( token.Icmp( "stoppdaaudio" ) == 0 ) { - if ( objectiveSystem && objectiveSystemOpen && pdaAudio.Length() > 0 ) { - // idSoundShader *shader = declManager->FindSound( pdaAudio ); - StopAudioLog(); - StopSound( SND_CHANNEL_PDA, false ); - } - return true; - } - - src->UnreadToken( &token ); - return false; -} - -/* -============== -idPlayer::Collide -============== -*/ -bool idPlayer::Collide( const trace_t &collision, const idVec3 &velocity ) { - idEntity *other; - - if ( gameLocal.isClient ) { - return false; - } - - other = gameLocal.entities[ collision.c.entityNum ]; - if ( other ) { - other->Signal( SIG_TOUCH ); - if ( !spectating ) { - if ( other->RespondsTo( EV_Touch ) ) { - other->ProcessEvent( &EV_Touch, this, &collision ); - } - } else { - if ( other->RespondsTo( EV_SpectatorTouch ) ) { - other->ProcessEvent( &EV_SpectatorTouch, this, &collision ); - } - } - } - return false; -} - - -/* -================ -idPlayer::UpdateLocation - -Searches nearby locations -================ -*/ -void idPlayer::UpdateLocation( void ) { - if ( hud ) { - idLocationEntity *locationEntity = gameLocal.LocationForPoint( GetEyePosition() ); - if ( locationEntity ) { - hud->SetStateString( "location", locationEntity->GetLocation() ); - } else { - hud->SetStateString( "location", common->GetLanguageDict()->GetString( "#str_02911" ) ); - } - } -} - -/* -================ -idPlayer::ClearFocus - -Clears the focus cursor -================ -*/ -void idPlayer::ClearFocus( void ) { - focusCharacter = NULL; - focusGUIent = NULL; - focusUI = NULL; - focusVehicle = NULL; - talkCursor = 0; -} - -/* -================ -idPlayer::UpdateFocus - -Searches nearby entities for interactive guis, possibly making one of them -the focus and sending it a mouse move event -================ -*/ -void idPlayer::UpdateFocus( void ) { - idClipModel *clipModelList[ MAX_GENTITIES ]; - idClipModel *clip; - int listedClipModels; - idEntity *oldFocus; - idEntity *ent; - idUserInterface *oldUI; - idAI *oldChar; - int oldTalkCursor; - int i, j; - idVec3 start, end; - bool allowFocus; - const char *command; - trace_t trace; - guiPoint_t pt; - const idKeyValue *kv; - sysEvent_t ev; - idUserInterface *ui; - - if ( gameLocal.inCinematic ) { - return; - } - - // only update the focus character when attack button isn't pressed so players - // can still chainsaw NPC's - if ( gameLocal.isMultiplayer || ( !focusCharacter && ( usercmd.buttons & BUTTON_ATTACK ) ) ) { - allowFocus = false; - } else { - allowFocus = true; - } - - oldFocus = focusGUIent; - oldUI = focusUI; - oldChar = focusCharacter; - oldTalkCursor = talkCursor; - - if ( focusTime <= gameLocal.time ) { - ClearFocus(); - } - - // don't let spectators interact with GUIs - if ( spectating ) { - return; - } - - start = GetEyePosition(); - end = start + viewAngles.ToForward() * 80.0f; - - // player identification -> names to the hud - if ( gameLocal.isMultiplayer && entityNumber == gameLocal.localClientNum ) { - idVec3 end = start + viewAngles.ToForward() * 768.0f; - gameLocal.clip.TracePoint( trace, start, end, MASK_SHOT_BOUNDINGBOX, this ); - int iclient = -1; - if ( ( trace.fraction < 1.0f ) && ( trace.c.entityNum < MAX_CLIENTS ) ) { - iclient = trace.c.entityNum; - } - if ( MPAim != iclient ) { - lastMPAim = MPAim; - MPAim = iclient; - lastMPAimTime = gameLocal.realClientTime; - } - } - - idBounds bounds( start ); - bounds.AddPoint( end ); - - listedClipModels = gameLocal.clip.ClipModelsTouchingBounds( bounds, -1, clipModelList, MAX_GENTITIES ); - - // no pretense at sorting here, just assume that there will only be one active - // gui within range along the trace - for ( i = 0; i < listedClipModels; i++ ) { - clip = clipModelList[ i ]; - ent = clip->GetEntity(); - - if ( ent->IsHidden() ) { - continue; - } - - if ( allowFocus ) { - if ( ent->IsType( idAFAttachment::Type ) ) { - idEntity *body = static_cast( ent )->GetBody(); - if ( body && body->IsType( idAI::Type ) && ( static_cast( body )->GetTalkState() >= TALK_OK ) ) { - gameLocal.clip.TracePoint( trace, start, end, MASK_SHOT_RENDERMODEL, this ); - if ( ( trace.fraction < 1.0f ) && ( trace.c.entityNum == ent->entityNumber ) ) { - ClearFocus(); - focusCharacter = static_cast( body ); - talkCursor = 1; - focusTime = gameLocal.time + FOCUS_TIME; - break; - } - } - continue; - } - - if ( ent->IsType( idAI::Type ) ) { - if ( static_cast( ent )->GetTalkState() >= TALK_OK ) { - gameLocal.clip.TracePoint( trace, start, end, MASK_SHOT_RENDERMODEL, this ); - if ( ( trace.fraction < 1.0f ) && ( trace.c.entityNum == ent->entityNumber ) ) { - ClearFocus(); - focusCharacter = static_cast( ent ); - talkCursor = 1; - focusTime = gameLocal.time + FOCUS_TIME; - break; - } - } - continue; - } - - if ( ent->IsType( idAFEntity_Vehicle::Type ) ) { - gameLocal.clip.TracePoint( trace, start, end, MASK_SHOT_RENDERMODEL, this ); - if ( ( trace.fraction < 1.0f ) && ( trace.c.entityNum == ent->entityNumber ) ) { - ClearFocus(); - focusVehicle = static_cast( ent ); - focusTime = gameLocal.time + FOCUS_TIME; - break; - } - continue; - } - } - - if ( !ent->GetRenderEntity() || !ent->GetRenderEntity()->gui[ 0 ] || !ent->GetRenderEntity()->gui[ 0 ]->IsInteractive() ) { - continue; - } - - if ( ent->spawnArgs.GetBool( "inv_item" ) ) { - // don't allow guis on pickup items focus - continue; - } - - pt = gameRenderWorld->GuiTrace( ent->GetModelDefHandle(), start, end ); - if ( pt.x != -1 ) { - // we have a hit - renderEntity_t *focusGUIrenderEntity = ent->GetRenderEntity(); - if ( !focusGUIrenderEntity ) { - continue; - } - - if ( pt.guiId == 1 ) { - ui = focusGUIrenderEntity->gui[ 0 ]; - } else if ( pt.guiId == 2 ) { - ui = focusGUIrenderEntity->gui[ 1 ]; - } else { - ui = focusGUIrenderEntity->gui[ 2 ]; - } - - if ( ui == NULL ) { - continue; - } - - ClearFocus(); - focusGUIent = ent; - focusUI = ui; - - if ( oldFocus != ent ) { - // new activation - // going to see if we have anything in inventory a gui might be interested in - // need to enumerate inventory items - focusUI->SetStateInt( "inv_count", inventory.items.Num() ); - for ( j = 0; j < inventory.items.Num(); j++ ) { - idDict *item = inventory.items[ j ]; - const char *iname = item->GetString( "inv_name" ); - const char *iicon = item->GetString( "inv_icon" ); - const char *itext = item->GetString( "inv_text" ); - - focusUI->SetStateString( va( "inv_name_%i", j), iname ); - focusUI->SetStateString( va( "inv_icon_%i", j), iicon ); - focusUI->SetStateString( va( "inv_text_%i", j), itext ); - kv = item->MatchPrefix("inv_id", NULL); - if ( kv ) { - focusUI->SetStateString( va( "inv_id_%i", j ), kv->GetValue() ); - } - focusUI->SetStateInt( iname, 1 ); - } - - - for( j = 0; j < inventory.pdaSecurity.Num(); j++ ) { - const char *p = inventory.pdaSecurity[ j ]; - if ( p && *p ) { - focusUI->SetStateInt( p, 1 ); - } - } - -#ifdef _D3XP //BSM: Added for powercells - int powerCellCount = 0; - for ( j = 0; j < inventory.items.Num(); j++ ) { - idDict *item = inventory.items[ j ]; - if(item->GetInt("inv_powercell")) { - powerCellCount++; - } - } - focusUI->SetStateInt( "powercell_count", powerCellCount ); -#endif - - int staminapercentage = ( int )( 100.0f * stamina / pm_stamina.GetFloat() ); - focusUI->SetStateString( "player_health", va("%i", health ) ); - focusUI->SetStateString( "player_stamina", va( "%i%%", staminapercentage ) ); - focusUI->SetStateString( "player_armor", va( "%i%%", inventory.armor ) ); - - kv = focusGUIent->spawnArgs.MatchPrefix( "gui_parm", NULL ); - while ( kv ) { - focusUI->SetStateString( kv->GetKey(), kv->GetValue() ); - kv = focusGUIent->spawnArgs.MatchPrefix( "gui_parm", kv ); - } - } - - // clamp the mouse to the corner - ev = sys->GenerateMouseMoveEvent( -2000, -2000 ); - command = focusUI->HandleEvent( &ev, gameLocal.time ); - HandleGuiCommands( focusGUIent, command ); - - // move to an absolute position - ev = sys->GenerateMouseMoveEvent( pt.x * SCREEN_WIDTH, pt.y * SCREEN_HEIGHT ); - command = focusUI->HandleEvent( &ev, gameLocal.time ); - HandleGuiCommands( focusGUIent, command ); - focusTime = gameLocal.time + FOCUS_GUI_TIME; - break; - } - } - - if ( focusGUIent && focusUI ) { - if ( !oldFocus || oldFocus != focusGUIent ) { - command = focusUI->Activate( true, gameLocal.time ); - HandleGuiCommands( focusGUIent, command ); - StartSound( "snd_guienter", SND_CHANNEL_ANY, 0, false, NULL ); - // HideTip(); - // HideObjective(); - } - } else if ( oldFocus && oldUI ) { - command = oldUI->Activate( false, gameLocal.time ); - HandleGuiCommands( oldFocus, command ); - StartSound( "snd_guiexit", SND_CHANNEL_ANY, 0, false, NULL ); - } - - if ( cursor && ( oldTalkCursor != talkCursor ) ) { - cursor->SetStateInt( "talkcursor", talkCursor ); - } - - if ( oldChar != focusCharacter && hud ) { - if ( focusCharacter ) { - hud->SetStateString( "npc", focusCharacter->spawnArgs.GetString( "npc_name", "Joe" ) ); -#ifdef _D3XP - //Use to code to update the npc action string to fix bug 1159 - hud->SetStateString( "npc_action", common->GetLanguageDict()->GetString( "#str_02036" )); -#endif - hud->HandleNamedEvent( "showNPC" ); - // HideTip(); - // HideObjective(); - } else { - hud->SetStateString( "npc", "" ); -#ifdef _D3XP - hud->SetStateString( "npc_action", "" ); -#endif - hud->HandleNamedEvent( "hideNPC" ); - } - } -} - -/* -================= -idPlayer::CrashLand - -Check for hard landings that generate sound events -================= -*/ -void idPlayer::CrashLand( const idVec3 &oldOrigin, const idVec3 &oldVelocity ) { - idVec3 origin, velocity; - idVec3 gravityVector, gravityNormal; - float delta; - float hardDelta, fatalDelta; - float dist; - float vel, acc; - float t; - float a, b, c, den; - waterLevel_t waterLevel; - bool noDamage; - - AI_SOFTLANDING = false; - AI_HARDLANDING = false; - - // if the player is not on the ground - if ( !physicsObj.HasGroundContacts() ) { - return; - } - - gravityNormal = physicsObj.GetGravityNormal(); - - // if the player wasn't going down - if ( ( oldVelocity * -gravityNormal ) >= 0.0f ) { - return; - } - - waterLevel = physicsObj.GetWaterLevel(); - - // never take falling damage if completely underwater - if ( waterLevel == WATERLEVEL_HEAD ) { - return; - } - - // no falling damage if touching a nodamage surface - noDamage = false; - for ( int i = 0; i < physicsObj.GetNumContacts(); i++ ) { - const contactInfo_t &contact = physicsObj.GetContact( i ); - if ( contact.material->GetSurfaceFlags() & SURF_NODAMAGE ) { - noDamage = true; - StartSound( "snd_land_hard", SND_CHANNEL_ANY, 0, false, NULL ); - break; - } - } - - origin = GetPhysics()->GetOrigin(); - gravityVector = physicsObj.GetGravity(); - - // calculate the exact velocity on landing - dist = ( origin - oldOrigin ) * -gravityNormal; - vel = oldVelocity * -gravityNormal; - acc = -gravityVector.Length(); - - a = acc / 2.0f; - b = vel; - c = -dist; - - den = b * b - 4.0f * a * c; - if ( den < 0 ) { - return; - } - t = ( -b - idMath::Sqrt( den ) ) / ( 2.0f * a ); - - delta = vel + t * acc; - delta = delta * delta * 0.0001; - - // reduce falling damage if there is standing water - if ( waterLevel == WATERLEVEL_WAIST ) { - delta *= 0.25f; - } - if ( waterLevel == WATERLEVEL_FEET ) { - delta *= 0.5f; - } - - if ( delta < 1.0f ) { - return; - } - - // allow falling a bit further for multiplayer - if ( gameLocal.isMultiplayer ) { - fatalDelta = 75.0f; - hardDelta = 50.0f; - } else { - fatalDelta = 65.0f; - hardDelta = 45.0f; - } - - if ( delta > fatalDelta ) { - AI_HARDLANDING = true; - landChange = -32; - landTime = gameLocal.time; - if ( !noDamage ) { - pain_debounce_time = gameLocal.time + pain_delay + 1; // ignore pain since we'll play our landing anim - Damage( NULL, NULL, idVec3( 0, 0, -1 ), "damage_fatalfall", 1.0f, 0 ); - } - } else if ( delta > hardDelta ) { - AI_HARDLANDING = true; - landChange = -24; - landTime = gameLocal.time; - if ( !noDamage ) { - pain_debounce_time = gameLocal.time + pain_delay + 1; // ignore pain since we'll play our landing anim - Damage( NULL, NULL, idVec3( 0, 0, -1 ), "damage_hardfall", 1.0f, 0 ); - } - } else if ( delta > 30 ) { - AI_HARDLANDING = true; - landChange = -16; - landTime = gameLocal.time; - if ( !noDamage ) { - pain_debounce_time = gameLocal.time + pain_delay + 1; // ignore pain since we'll play our landing anim - Damage( NULL, NULL, idVec3( 0, 0, -1 ), "damage_softfall", 1.0f, 0 ); - } - } else if ( delta > 7 ) { - AI_SOFTLANDING = true; - landChange = -8; - landTime = gameLocal.time; - } else if ( delta > 3 ) { - // just walk on - } -} - -/* -=============== -idPlayer::BobCycle -=============== -*/ -void idPlayer::BobCycle( const idVec3 &pushVelocity ) { - float bobmove; - int old, deltaTime; - idVec3 vel, gravityDir, velocity; - idMat3 viewaxis; - float bob; - float delta; - float speed; - float f; - - // - // calculate speed and cycle to be used for - // all cyclic walking effects - // - velocity = physicsObj.GetLinearVelocity() - pushVelocity; - - gravityDir = physicsObj.GetGravityNormal(); - vel = velocity - ( velocity * gravityDir ) * gravityDir; - xyspeed = vel.LengthFast(); - - // do not evaluate the bob for other clients - // when doing a spectate follow, don't do any weapon bobbing - if ( gameLocal.isClient && entityNumber != gameLocal.localClientNum ) { - viewBobAngles.Zero(); - viewBob.Zero(); - return; - } - - if ( !physicsObj.HasGroundContacts() || influenceActive == INFLUENCE_LEVEL2 || ( gameLocal.isMultiplayer && spectating ) ) { - // airborne - bobCycle = 0; - bobFoot = 0; - bobfracsin = 0; - } else if ( ( !usercmd.forwardmove && !usercmd.rightmove ) || ( xyspeed <= MIN_BOB_SPEED ) ) { - // start at beginning of cycle again - bobCycle = 0; - bobFoot = 0; - bobfracsin = 0; - } else { - if ( physicsObj.IsCrouching() ) { - bobmove = pm_crouchbob.GetFloat(); - // ducked characters never play footsteps - } else { - // vary the bobbing based on the speed of the player - bobmove = pm_walkbob.GetFloat() * ( 1.0f - bobFrac ) + pm_runbob.GetFloat() * bobFrac; - } - - // check for footstep / splash sounds - old = bobCycle; - bobCycle = (int)( old + bobmove * gameLocal.msec ) & 255; - bobFoot = ( bobCycle & 128 ) >> 7; - bobfracsin = idMath::Fabs( sin( ( bobCycle & 127 ) / 127.0 * idMath::PI ) ); - } - - // calculate angles for view bobbing - viewBobAngles.Zero(); - - viewaxis = viewAngles.ToMat3() * physicsObj.GetGravityAxis(); - - // add angles based on velocity - delta = velocity * viewaxis[0]; - viewBobAngles.pitch += delta * pm_runpitch.GetFloat(); - - delta = velocity * viewaxis[1]; - viewBobAngles.roll -= delta * pm_runroll.GetFloat(); - - // add angles based on bob - // make sure the bob is visible even at low speeds - speed = xyspeed > 200 ? xyspeed : 200; - - delta = bobfracsin * pm_bobpitch.GetFloat() * speed; - if ( physicsObj.IsCrouching() ) { - delta *= 3; // crouching - } - viewBobAngles.pitch += delta; - delta = bobfracsin * pm_bobroll.GetFloat() * speed; - if ( physicsObj.IsCrouching() ) { - delta *= 3; // crouching accentuates roll - } - if ( bobFoot & 1 ) { - delta = -delta; - } - viewBobAngles.roll += delta; - - // calculate position for view bobbing - viewBob.Zero(); - - if ( physicsObj.HasSteppedUp() ) { - - // check for stepping up before a previous step is completed - deltaTime = gameLocal.time - stepUpTime; - if ( deltaTime < STEPUP_TIME ) { - stepUpDelta = stepUpDelta * ( STEPUP_TIME - deltaTime ) / STEPUP_TIME + physicsObj.GetStepUp(); - } else { - stepUpDelta = physicsObj.GetStepUp(); - } - if ( stepUpDelta > 2.0f * pm_stepsize.GetFloat() ) { - stepUpDelta = 2.0f * pm_stepsize.GetFloat(); - } - stepUpTime = gameLocal.time; - } - - idVec3 gravity = physicsObj.GetGravityNormal(); - - // if the player stepped up recently - deltaTime = gameLocal.time - stepUpTime; - if ( deltaTime < STEPUP_TIME ) { - viewBob += gravity * ( stepUpDelta * ( STEPUP_TIME - deltaTime ) / STEPUP_TIME ); - } - - // add bob height after any movement smoothing - bob = bobfracsin * xyspeed * pm_bobup.GetFloat(); - if ( bob > 6 ) { - bob = 6; - } - viewBob[2] += bob; - - // add fall height - delta = gameLocal.time - landTime; - if ( delta < LAND_DEFLECT_TIME ) { - f = delta / LAND_DEFLECT_TIME; - viewBob -= gravity * ( landChange * f ); - } else if ( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) { - delta -= LAND_DEFLECT_TIME; - f = 1.0 - ( delta / LAND_RETURN_TIME ); - viewBob -= gravity * ( landChange * f ); - } -} - -/* -================ -idPlayer::UpdateDeltaViewAngles -================ -*/ -void idPlayer::UpdateDeltaViewAngles( const idAngles &angles ) { - // set the delta angle - idAngles delta; - for( int i = 0; i < 3; i++ ) { - delta[ i ] = angles[ i ] - SHORT2ANGLE( usercmd.angles[ i ] ); - } - SetDeltaViewAngles( delta ); -} - -/* -================ -idPlayer::SetViewAngles -================ -*/ -void idPlayer::SetViewAngles( const idAngles &angles ) { - UpdateDeltaViewAngles( angles ); - viewAngles = angles; -} - -/* -================ -idPlayer::UpdateViewAngles -================ -*/ -void idPlayer::UpdateViewAngles( void ) { - int i; - idAngles delta; - - if ( !noclip && ( gameLocal.inCinematic || privateCameraView || gameLocal.GetCamera() || influenceActive == INFLUENCE_LEVEL2 || objectiveSystemOpen ) ) { - // no view changes at all, but we still want to update the deltas or else when - // we get out of this mode, our view will snap to a kind of random angle - UpdateDeltaViewAngles( viewAngles ); - return; - } - - // if dead - if ( health <= 0 ) { - if ( pm_thirdPersonDeath.GetBool() ) { - viewAngles.roll = 0.0f; - viewAngles.pitch = 30.0f; - } else { - viewAngles.roll = 40.0f; - viewAngles.pitch = -15.0f; - } - return; - } - - // circularly clamp the angles with deltas - for ( i = 0; i < 3; i++ ) { - cmdAngles[i] = SHORT2ANGLE( usercmd.angles[i] ); - if ( influenceActive == INFLUENCE_LEVEL3 ) { - viewAngles[i] += idMath::ClampFloat( -1.0f, 1.0f, idMath::AngleDelta( idMath::AngleNormalize180( SHORT2ANGLE( usercmd.angles[i]) + deltaViewAngles[i] ) , viewAngles[i] ) ); - } else { - viewAngles[i] = idMath::AngleNormalize180( SHORT2ANGLE( usercmd.angles[i]) + deltaViewAngles[i] ); - } - } - if ( !centerView.IsDone( gameLocal.time ) ) { - viewAngles.pitch = centerView.GetCurrentValue(gameLocal.time); - } - - // clamp the pitch - if ( noclip ) { - if ( viewAngles.pitch > 89.0f ) { - // don't let the player look down more than 89 degrees while noclipping - viewAngles.pitch = 89.0f; - } else if ( viewAngles.pitch < -89.0f ) { - // don't let the player look up more than 89 degrees while noclipping - viewAngles.pitch = -89.0f; - } -#ifdef _D3XP - } else if ( mountedObject ) { - int yaw_min, yaw_max, varc; - - mountedObject->GetAngleRestrictions( yaw_min, yaw_max, varc ); - - if ( yaw_min < yaw_max ) { - viewAngles.yaw = idMath::ClampFloat( yaw_min, yaw_max, viewAngles.yaw ); - } else { - if ( viewAngles.yaw < 0 ) { - viewAngles.yaw = idMath::ClampFloat( -180.f, yaw_max, viewAngles.yaw ); - } else { - viewAngles.yaw = idMath::ClampFloat( yaw_min, 180.f, viewAngles.yaw ); - } - } - viewAngles.pitch = idMath::ClampFloat( -varc, varc, viewAngles.pitch ); -#endif - } else { - if ( viewAngles.pitch > pm_maxviewpitch.GetFloat() ) { - // don't let the player look down enough to see the shadow of his (non-existant) feet - viewAngles.pitch = pm_maxviewpitch.GetFloat(); - } else if ( viewAngles.pitch < pm_minviewpitch.GetFloat() ) { - // don't let the player look up more than 89 degrees - viewAngles.pitch = pm_minviewpitch.GetFloat(); - } - } - - UpdateDeltaViewAngles( viewAngles ); - - // orient the model towards the direction we're looking - SetAngles( idAngles( 0, viewAngles.yaw, 0 ) ); - - // save in the log for analyzing weapon angle offsets - loggedViewAngles[ gameLocal.framenum & (NUM_LOGGED_VIEW_ANGLES-1) ] = viewAngles; -} - -/* -============== -idPlayer::AdjustHeartRate - -Player heartrate works as follows - -DEF_HEARTRATE is resting heartrate - -Taking damage when health is above 75 adjusts heart rate by 1 beat per second -Taking damage when health is below 75 adjusts heart rate by 5 beats per second -Maximum heartrate from damage is MAX_HEARTRATE - -Firing a weapon adds 1 beat per second up to a maximum of COMBAT_HEARTRATE - -Being at less than 25% stamina adds 5 beats per second up to ZEROSTAMINA_HEARTRATE - -All heartrates are target rates.. the heart rate will start falling as soon as there have been no adjustments for 5 seconds -Once it starts falling it always tries to get to DEF_HEARTRATE - -The exception to the above rule is upon death at which point the rate is set to DYING_HEARTRATE and starts falling -immediately to zero - -Heart rate volumes go from zero ( -40 db for DEF_HEARTRATE to 5 db for MAX_HEARTRATE ) the volume is -scaled linearly based on the actual rate - -Exception to the above rule is once the player is dead, the dying heart rate starts at either the current volume if -it is audible or -10db and scales to 8db on the last few beats -============== -*/ -void idPlayer::AdjustHeartRate( int target, float timeInSecs, float delay, bool force ) { - - if ( heartInfo.GetEndValue() == target ) { - return; - } - - if ( AI_DEAD && !force ) { - return; - } - - lastHeartAdjust = gameLocal.time; - - heartInfo.Init( gameLocal.time + delay * 1000, timeInSecs * 1000, heartRate, target ); -} - -/* -============== -idPlayer::GetBaseHeartRate -============== -*/ -int idPlayer::GetBaseHeartRate( void ) { - int base = idMath::FtoiFast( ( BASE_HEARTRATE + LOWHEALTH_HEARTRATE_ADJ ) - ( (float)health / 100.0f ) * LOWHEALTH_HEARTRATE_ADJ ); - int rate = idMath::FtoiFast( base + ( ZEROSTAMINA_HEARTRATE - base ) * ( 1.0f - stamina / pm_stamina.GetFloat() ) ); - int diff = ( lastDmgTime ) ? gameLocal.time - lastDmgTime : 99999; - rate += ( diff < 5000 ) ? ( diff < 2500 ) ? ( diff < 1000 ) ? 15 : 10 : 5 : 0; - return rate; -} - -/* -============== -idPlayer::SetCurrentHeartRate -============== -*/ -void idPlayer::SetCurrentHeartRate( void ) { - - int base = idMath::FtoiFast( ( BASE_HEARTRATE + LOWHEALTH_HEARTRATE_ADJ ) - ( (float) health / 100.0f ) * LOWHEALTH_HEARTRATE_ADJ ); - - if ( PowerUpActive( ADRENALINE )) { - heartRate = 135; - } else { - heartRate = idMath::FtoiFast( heartInfo.GetCurrentValue( gameLocal.time ) ); - int currentRate = GetBaseHeartRate(); - if ( health >= 0 && gameLocal.time > lastHeartAdjust + 2500 ) { - AdjustHeartRate( currentRate, 2.5f, 0.0f, false ); - } - } - - int bps = idMath::FtoiFast( 60.0f / heartRate * 1000.0f ); - if ( gameLocal.time - lastHeartBeat > bps ) { - int dmgVol = DMG_VOLUME; - int deathVol = DEATH_VOLUME; - int zeroVol = ZERO_VOLUME; - float pct = 0.0; - if ( heartRate > BASE_HEARTRATE && health > 0 ) { - pct = (float)(heartRate - base) / (MAX_HEARTRATE - base); - pct *= ((float)dmgVol - (float)zeroVol); - } else if ( health <= 0 ) { - pct = (float)(heartRate - DYING_HEARTRATE) / (BASE_HEARTRATE - DYING_HEARTRATE); - if ( pct > 1.0f ) { - pct = 1.0f; - } else if (pct < 0.0f) { - pct = 0.0f; - } - pct *= ((float)deathVol - (float)zeroVol); - } - - pct += (float)zeroVol; - - if ( pct != zeroVol ) { - StartSound( "snd_heartbeat", SND_CHANNEL_HEART, SSF_PRIVATE_SOUND, false, NULL ); - // modify just this channel to a custom volume - soundShaderParms_t parms; - memset( &parms, 0, sizeof( parms ) ); - parms.volume = pct; - refSound.referenceSound->ModifySound( SND_CHANNEL_HEART, &parms ); - } - - lastHeartBeat = gameLocal.time; - } -} - -/* -============== -idPlayer::UpdateAir -============== -*/ -void idPlayer::UpdateAir( void ) { - if ( health <= 0 ) { - return; - } - - // see if the player is connected to the info_vacuum - bool newAirless = false; - - if ( gameLocal.vacuumAreaNum != -1 ) { - int num = GetNumPVSAreas(); - if ( num > 0 ) { - int areaNum; - - // if the player box spans multiple areas, get the area from the origin point instead, - // otherwise a rotating player box may poke into an outside area - if ( num == 1 ) { - const int *pvsAreas = GetPVSAreas(); - areaNum = pvsAreas[0]; - } else { - areaNum = gameRenderWorld->PointInArea( this->GetPhysics()->GetOrigin() ); - } - newAirless = gameRenderWorld->AreasAreConnected( gameLocal.vacuumAreaNum, areaNum, PS_BLOCK_AIR ); - } - } - -#ifdef _D3XP - if ( PowerUpActive( ENVIROTIME ) ) { - newAirless = false; - } -#endif - - if ( newAirless ) { - if ( !airless ) { - StartSound( "snd_decompress", SND_CHANNEL_ANY, SSF_GLOBAL, false, NULL ); - StartSound( "snd_noAir", SND_CHANNEL_BODY2, 0, false, NULL ); - if ( hud ) { - hud->HandleNamedEvent( "noAir" ); - } - } - airTics--; - if ( airTics < 0 ) { - airTics = 0; - // check for damage - const idDict *damageDef = gameLocal.FindEntityDefDict( "damage_noair", false ); - int dmgTiming = 1000 * ((damageDef) ? damageDef->GetFloat( "delay", "3.0" ) : 3.0f ); - if ( gameLocal.time > lastAirDamage + dmgTiming ) { - Damage( NULL, NULL, vec3_origin, "damage_noair", 1.0f, 0 ); - lastAirDamage = gameLocal.time; - } - } - - } else { - if ( airless ) { - StartSound( "snd_recompress", SND_CHANNEL_ANY, SSF_GLOBAL, false, NULL ); - StopSound( SND_CHANNEL_BODY2, false ); - if ( hud ) { - hud->HandleNamedEvent( "Air" ); - } - } - airTics+=2; // regain twice as fast as lose - if ( airTics > pm_airTics.GetInteger() ) { - airTics = pm_airTics.GetInteger(); - } - } - - airless = newAirless; - - if ( hud ) { - hud->SetStateInt( "player_air", 100 * airTics / pm_airTics.GetInteger() ); - } -} - -void idPlayer::UpdatePowerupHud() { - - if ( health <= 0 ) { - return; - } - - if(lastHudPowerup != hudPowerup) { - - if(hudPowerup == -1) { - //The powerup hud should be turned off - if ( hud ) { - hud->HandleNamedEvent( "noPowerup" ); - } - } else { - //Turn the pwoerup hud on - if ( hud ) { - hud->HandleNamedEvent( "Powerup" ); - } - } - - lastHudPowerup = hudPowerup; - } - - if(hudPowerup != -1) { - if(PowerUpActive(hudPowerup)) { - int remaining = inventory.powerupEndTime[ hudPowerup ] - gameLocal.time; - int filledbar = idMath::ClampInt( 0, hudPowerupDuration, remaining ); - - if ( hud ) { - hud->SetStateInt( "player_powerup", 100 * filledbar / hudPowerupDuration ); - hud->SetStateInt( "player_poweruptime", remaining / 1000 ); - } - } - } -} - -/* -============== -idPlayer::AddGuiPDAData -============== - */ -int idPlayer::AddGuiPDAData( const declType_t dataType, const char *listName, const idDeclPDA *src, idUserInterface *gui ) { - int c, i; - idStr work; - if ( dataType == DECL_EMAIL ) { - c = src->GetNumEmails(); - for ( i = 0; i < c; i++ ) { - const idDeclEmail *email = src->GetEmailByIndex( i ); - if ( email == NULL ) { - work = va( "-\tEmail %d not found\t-", i ); - } else { - work = email->GetFrom(); - work += "\t"; - work += email->GetSubject(); - work += "\t"; - work += email->GetDate(); - } - gui->SetStateString( va( "%s_item_%i", listName, i ), work ); - } - return c; - } else if ( dataType == DECL_AUDIO ) { - c = src->GetNumAudios(); - for ( i = 0; i < c; i++ ) { - const idDeclAudio *audio = src->GetAudioByIndex( i ); - if ( audio == NULL ) { - work = va( "Audio Log %d not found", i ); - } else { - work = audio->GetAudioName(); - } - gui->SetStateString( va( "%s_item_%i", listName, i ), work ); - } - return c; - } else if ( dataType == DECL_VIDEO ) { - c = inventory.videos.Num(); - for ( i = 0; i < c; i++ ) { - const idDeclVideo *video = GetVideo( i ); - if ( video == NULL ) { - work = va( "Video CD %s not found", inventory.videos[i].c_str() ); - } else { - work = video->GetVideoName(); - } - gui->SetStateString( va( "%s_item_%i", listName, i ), work ); - } - return c; - } - return 0; -} - -/* -============== -idPlayer::GetPDA -============== - */ -const idDeclPDA *idPlayer::GetPDA( void ) const { - if ( inventory.pdas.Num() ) { - return static_cast< const idDeclPDA* >( declManager->FindType( DECL_PDA, inventory.pdas[ 0 ] ) ); - } else { - return NULL; - } -} - - -/* -============== -idPlayer::GetVideo -============== -*/ -const idDeclVideo *idPlayer::GetVideo( int index ) { - if ( index >= 0 && index < inventory.videos.Num() ) { - return static_cast< const idDeclVideo* >( declManager->FindType( DECL_VIDEO, inventory.videos[index], false ) ); - } - return NULL; -} - - -/* -============== -idPlayer::UpdatePDAInfo -============== -*/ -void idPlayer::UpdatePDAInfo( bool updatePDASel ) { - int j, sel; - - if ( objectiveSystem == NULL ) { - return; - } - - assert( hud ); - - int currentPDA = objectiveSystem->State().GetInt( "listPDA_sel_0", "0" ); - if ( currentPDA == -1 ) { - currentPDA = 0; - } - - if ( updatePDASel ) { - objectiveSystem->SetStateInt( "listPDAVideo_sel_0", 0 ); - objectiveSystem->SetStateInt( "listPDAEmail_sel_0", 0 ); - objectiveSystem->SetStateInt( "listPDAAudio_sel_0", 0 ); - } - - if ( currentPDA > 0 ) { - currentPDA = inventory.pdas.Num() - currentPDA; - } - - // Mark in the bit array that this pda has been read - if ( currentPDA < 128 ) { - inventory.pdasViewed[currentPDA >> 5] |= 1 << (currentPDA & 31); - } - - pdaAudio = ""; - pdaVideo = ""; - pdaVideoWave = ""; - idStr name, data, preview, info, wave; - for ( j = 0; j < MAX_PDAS; j++ ) { - objectiveSystem->SetStateString( va( "listPDA_item_%i", j ), "" ); - } - for ( j = 0; j < MAX_PDA_ITEMS; j++ ) { - objectiveSystem->SetStateString( va( "listPDAVideo_item_%i", j ), "" ); - objectiveSystem->SetStateString( va( "listPDAAudio_item_%i", j ), "" ); - objectiveSystem->SetStateString( va( "listPDAEmail_item_%i", j ), "" ); - objectiveSystem->SetStateString( va( "listPDASecurity_item_%i", j ), "" ); - } - for ( j = 0; j < inventory.pdas.Num(); j++ ) { - - const idDeclPDA *pda = static_cast< const idDeclPDA* >( declManager->FindType( DECL_PDA, inventory.pdas[j], false ) ); - - if ( pda == NULL ) { - continue; - } - - int index = inventory.pdas.Num() - j; - if ( j == 0 ) { - // Special case for the first PDA - index = 0; - } - - if ( j != currentPDA && j < 128 && inventory.pdasViewed[j >> 5] & (1 << (j & 31)) ) { - // This pda has been read already, mark in gray - objectiveSystem->SetStateString( va( "listPDA_item_%i", index), va(S_COLOR_GRAY "%s", pda->GetPdaName()) ); - } else { - // This pda has not been read yet - objectiveSystem->SetStateString( va( "listPDA_item_%i", index), pda->GetPdaName() ); - } - - const char *security = pda->GetSecurity(); - if ( j == currentPDA || (currentPDA == 0 && security && *security ) ) { - if ( *security == 0 ) { - security = common->GetLanguageDict()->GetString( "#str_00066" ); - } - objectiveSystem->SetStateString( "PDASecurityClearance", security ); - } - - if ( j == currentPDA ) { - - objectiveSystem->SetStateString( "pda_icon", pda->GetIcon() ); - objectiveSystem->SetStateString( "pda_id", pda->GetID() ); - objectiveSystem->SetStateString( "pda_title", pda->GetTitle() ); - - if ( j == 0 ) { - // Selected, personal pda - // Add videos - if ( updatePDASel || !inventory.pdaOpened ) { - objectiveSystem->HandleNamedEvent( "playerPDAActive" ); - objectiveSystem->SetStateString( "pda_personal", "1" ); - inventory.pdaOpened = true; - } - objectiveSystem->SetStateString( "pda_location", hud->State().GetString("location") ); - objectiveSystem->SetStateString( "pda_name", cvarSystem->GetCVarString( "ui_name") ); - AddGuiPDAData( DECL_VIDEO, "listPDAVideo", pda, objectiveSystem ); - sel = objectiveSystem->State().GetInt( "listPDAVideo_sel_0", "0" ); - const idDeclVideo *vid = NULL; - if ( sel >= 0 && sel < inventory.videos.Num() ) { - vid = static_cast< const idDeclVideo * >( declManager->FindType( DECL_VIDEO, inventory.videos[ sel ], false ) ); - } - if ( vid ) { - pdaVideo = vid->GetRoq(); - pdaVideoWave = vid->GetWave(); - objectiveSystem->SetStateString( "PDAVideoTitle", vid->GetVideoName() ); - objectiveSystem->SetStateString( "PDAVideoVid", vid->GetRoq() ); - objectiveSystem->SetStateString( "PDAVideoIcon", vid->GetPreview() ); - objectiveSystem->SetStateString( "PDAVideoInfo", vid->GetInfo() ); - } else { - //FIXME: need to precache these in the player def - objectiveSystem->SetStateString( "PDAVideoVid", "sound/vo/video/welcome.tga" ); - objectiveSystem->SetStateString( "PDAVideoIcon", "sound/vo/video/welcome.tga" ); - objectiveSystem->SetStateString( "PDAVideoTitle", "" ); - objectiveSystem->SetStateString( "PDAVideoInfo", "" ); - } - } else { - // Selected, non-personal pda - // Add audio logs - if ( updatePDASel ) { - objectiveSystem->HandleNamedEvent( "playerPDANotActive" ); - objectiveSystem->SetStateString( "pda_personal", "0" ); - inventory.pdaOpened = true; - } - objectiveSystem->SetStateString( "pda_location", pda->GetPost() ); - objectiveSystem->SetStateString( "pda_name", pda->GetFullName() ); - int audioCount = AddGuiPDAData( DECL_AUDIO, "listPDAAudio", pda, objectiveSystem ); - objectiveSystem->SetStateInt( "audioLogCount", audioCount ); - sel = objectiveSystem->State().GetInt( "listPDAAudio_sel_0", "0" ); - const idDeclAudio *aud = NULL; - if ( sel >= 0 ) { - aud = pda->GetAudioByIndex( sel ); - } - if ( aud ) { - pdaAudio = aud->GetWave(); - objectiveSystem->SetStateString( "PDAAudioTitle", aud->GetAudioName() ); - objectiveSystem->SetStateString( "PDAAudioIcon", aud->GetPreview() ); - objectiveSystem->SetStateString( "PDAAudioInfo", aud->GetInfo() ); - } else { - objectiveSystem->SetStateString( "PDAAudioIcon", "sound/vo/video/welcome.tga" ); - objectiveSystem->SetStateString( "PDAAutioTitle", "" ); - objectiveSystem->SetStateString( "PDAAudioInfo", "" ); - } - } - // add emails - name = ""; - data = ""; - int numEmails = pda->GetNumEmails(); - if ( numEmails > 0 ) { - AddGuiPDAData( DECL_EMAIL, "listPDAEmail", pda, objectiveSystem ); - sel = objectiveSystem->State().GetInt( "listPDAEmail_sel_0", "-1" ); - if ( sel >= 0 && sel < numEmails ) { - const idDeclEmail *email = pda->GetEmailByIndex( sel ); - name = email->GetSubject(); - data = email->GetBody(); - } - } - objectiveSystem->SetStateString( "PDAEmailTitle", name ); - objectiveSystem->SetStateString( "PDAEmailText", data ); - } - } - if ( objectiveSystem->State().GetInt( "listPDA_sel_0", "-1" ) == -1 ) { - objectiveSystem->SetStateInt( "listPDA_sel_0", 0 ); - } - objectiveSystem->StateChanged( gameLocal.time ); -} - -/* -============== -idPlayer::TogglePDA -============== -*/ -void idPlayer::TogglePDA( void ) { - if ( objectiveSystem == NULL ) { - return; - } - - if ( inventory.pdas.Num() == 0 ) { - ShowTip( spawnArgs.GetString( "text_infoTitle" ), spawnArgs.GetString( "text_noPDA" ), true ); - return; - } - - assert( hud ); - - if ( !objectiveSystemOpen ) { - int j, c = inventory.items.Num(); - objectiveSystem->SetStateInt( "inv_count", c ); - for ( j = 0; j < MAX_INVENTORY_ITEMS; j++ ) { - objectiveSystem->SetStateString( va( "inv_name_%i", j ), "" ); - objectiveSystem->SetStateString( va( "inv_icon_%i", j ), "" ); - objectiveSystem->SetStateString( va( "inv_text_%i", j ), "" ); - } - for ( j = 0; j < c; j++ ) { - idDict *item = inventory.items[j]; - if ( !item->GetBool( "inv_pda" ) ) { - const char *iname = item->GetString( "inv_name" ); - const char *iicon = item->GetString( "inv_icon" ); - const char *itext = item->GetString( "inv_text" ); - objectiveSystem->SetStateString( va( "inv_name_%i", j ), iname ); - objectiveSystem->SetStateString( va( "inv_icon_%i", j ), iicon ); - objectiveSystem->SetStateString( va( "inv_text_%i", j ), itext ); - const idKeyValue *kv = item->MatchPrefix( "inv_id", NULL ); - if ( kv ) { - objectiveSystem->SetStateString( va( "inv_id_%i", j ), kv->GetValue() ); - } - } - } - - for ( j = 0; j < MAX_WEAPONS; j++ ) { - const char *weapnum = va( "def_weapon%d", j ); - const char *hudWeap = va( "weapon%d", j ); - int weapstate = 0; - if ( inventory.weapons & ( 1 << j ) ) { - const char *weap = spawnArgs.GetString( weapnum ); - if ( weap && *weap ) { - weapstate++; - } - } - objectiveSystem->SetStateInt( hudWeap, weapstate ); - } - - objectiveSystem->SetStateInt( "listPDA_sel_0", inventory.selPDA ); - objectiveSystem->SetStateInt( "listPDAVideo_sel_0", inventory.selVideo ); - objectiveSystem->SetStateInt( "listPDAAudio_sel_0", inventory.selAudio ); - objectiveSystem->SetStateInt( "listPDAEmail_sel_0", inventory.selEMail ); - UpdatePDAInfo( false ); - UpdateObjectiveInfo(); - objectiveSystem->Activate( true, gameLocal.time ); - hud->HandleNamedEvent( "pdaPickupHide" ); - hud->HandleNamedEvent( "videoPickupHide" ); - } else { - inventory.selPDA = objectiveSystem->State().GetInt( "listPDA_sel_0" ); - inventory.selVideo = objectiveSystem->State().GetInt( "listPDAVideo_sel_0" ); - inventory.selAudio = objectiveSystem->State().GetInt( "listPDAAudio_sel_0" ); - inventory.selEMail = objectiveSystem->State().GetInt( "listPDAEmail_sel_0" ); - objectiveSystem->Activate( false, gameLocal.time ); - } - objectiveSystemOpen ^= 1; -} - -/* -============== -idPlayer::ToggleScoreboard -============== -*/ -void idPlayer::ToggleScoreboard( void ) { - scoreBoardOpen ^= 1; -} - -/* -============== -idPlayer::Spectate -============== -*/ -void idPlayer::Spectate( bool spectate ) { - idBitMsg msg; - byte msgBuf[MAX_EVENT_PARAM_SIZE]; - - // track invisible player bug - // all hiding and showing should be performed through Spectate calls - // except for the private camera view, which is used for teleports - assert( ( teleportEntity.GetEntity() != NULL ) || ( IsHidden() == spectating ) ); - - if ( spectating == spectate ) { - return; - } - - spectating = spectate; - - if ( gameLocal.isServer ) { - msg.Init( msgBuf, sizeof( msgBuf ) ); - msg.WriteBits( spectating, 1 ); - ServerSendEvent( EVENT_SPECTATE, &msg, false, -1 ); - } - - if ( spectating ) { - // join the spectators - ClearPowerUps(); - spectator = this->entityNumber; - Init(); - StopRagdoll(); - SetPhysics( &physicsObj ); - physicsObj.DisableClip(); - Hide(); - Event_DisableWeapon(); - if ( hud ) { - hud->HandleNamedEvent( "aim_clear" ); - MPAimFadeTime = 0; - } - } else { - // put everything back together again - currentWeapon = -1; // to make sure the def will be loaded if necessary - Show(); - Event_EnableWeapon(); - } - SetClipModel(); -} - -/* -============== -idPlayer::SetClipModel -============== -*/ -void idPlayer::SetClipModel( void ) { - idBounds bounds; - - if ( spectating ) { - bounds = idBounds( vec3_origin ).Expand( pm_spectatebbox.GetFloat() * 0.5f ); - } else { - bounds[0].Set( -pm_bboxwidth.GetFloat() * 0.5f, -pm_bboxwidth.GetFloat() * 0.5f, 0 ); - bounds[1].Set( pm_bboxwidth.GetFloat() * 0.5f, pm_bboxwidth.GetFloat() * 0.5f, pm_normalheight.GetFloat() ); - } - // the origin of the clip model needs to be set before calling SetClipModel - // otherwise our physics object's current origin value gets reset to 0 - idClipModel *newClip; - if ( pm_usecylinder.GetBool() ) { - newClip = new idClipModel( idTraceModel( bounds, 8 ) ); - newClip->Translate( physicsObj.PlayerGetOrigin() ); - physicsObj.SetClipModel( newClip, 1.0f ); - } else { - newClip = new idClipModel( idTraceModel( bounds ) ); - newClip->Translate( physicsObj.PlayerGetOrigin() ); - physicsObj.SetClipModel( newClip, 1.0f ); - } -} - -/* -============== -idPlayer::UseVehicle -============== -*/ -void idPlayer::UseVehicle( void ) { - trace_t trace; - idVec3 start, end; - idEntity *ent; - - if ( GetBindMaster() && GetBindMaster()->IsType( idAFEntity_Vehicle::Type ) ) { - Show(); - static_cast(GetBindMaster())->Use( this ); - } else { - start = GetEyePosition(); - end = start + viewAngles.ToForward() * 80.0f; - gameLocal.clip.TracePoint( trace, start, end, MASK_SHOT_RENDERMODEL, this ); - if ( trace.fraction < 1.0f ) { - ent = gameLocal.entities[ trace.c.entityNum ]; - if ( ent && ent->IsType( idAFEntity_Vehicle::Type ) ) { - Hide(); - static_cast(ent)->Use( this ); - } - } - } -} - -/* -============== -idPlayer::PerformImpulse -============== -*/ -void idPlayer::PerformImpulse( int impulse ) { - - if ( gameLocal.isClient ) { - idBitMsg msg; - byte msgBuf[MAX_EVENT_PARAM_SIZE]; - - assert( entityNumber == gameLocal.localClientNum ); - msg.Init( msgBuf, sizeof( msgBuf ) ); - msg.BeginWriting(); - msg.WriteBits( impulse, 6 ); - ClientSendEvent( EVENT_IMPULSE, &msg ); - } - - if ( impulse >= IMPULSE_0 && impulse <= IMPULSE_12 ) { - SelectWeapon( impulse, false ); - return; - } - - switch( impulse ) { - case IMPULSE_13: { - Reload(); - break; - } - case IMPULSE_14: { - NextWeapon(); - break; - } - case IMPULSE_15: { - PrevWeapon(); - break; - } - case IMPULSE_17: { - if ( gameLocal.isClient || entityNumber == gameLocal.localClientNum ) { - gameLocal.mpGame.ToggleReady(); - } - break; - } - case IMPULSE_18: { - centerView.Init(gameLocal.time, 200, viewAngles.pitch, 0); - break; - } - case IMPULSE_19: { - // when we're not in single player, IMPULSE_19 is used for showScores - // otherwise it opens the pda - if ( !gameLocal.isMultiplayer ) { - if ( objectiveSystemOpen ) { - TogglePDA(); - } else if ( weapon_pda >= 0 ) { - SelectWeapon( weapon_pda, true ); - } - } - break; - } - case IMPULSE_20: { - if ( gameLocal.isClient || entityNumber == gameLocal.localClientNum ) { - gameLocal.mpGame.ToggleTeam(); - } - break; - } - case IMPULSE_22: { - if ( gameLocal.isClient || entityNumber == gameLocal.localClientNum ) { - gameLocal.mpGame.ToggleSpectate(); - } - break; - } - - case IMPULSE_25: { - if ( gameLocal.isServer && gameLocal.mpGame.IsGametypeFlagBased() && (gameLocal.serverInfo.GetInt( "si_midnight" ) == 2) ) { - if ( enviroSuitLight.IsValid() ) { - enviroSuitLight.GetEntity()->PostEventMS( &EV_Remove, 0 ); - enviroSuitLight = NULL; - } else { - const idDict *lightDef = gameLocal.FindEntityDefDict( "envirosuit_light", false ); - if ( lightDef ) { - idEntity *temp = static_cast(enviroSuitLight.GetEntity()); - idAngles lightAng = firstPersonViewAxis.ToAngles(); - idVec3 lightOrg = firstPersonViewOrigin; - - idVec3 enviroOffset = lightDef->GetVector( "enviro_offset" ); - idVec3 enviroAngleOffset = lightDef->GetVector( "enviro_angle_offset" ); - - gameLocal.SpawnEntityDef( *lightDef, &temp, false ); - enviroSuitLight = static_cast(temp); - - enviroSuitLight.GetEntity()->fl.networkSync = true; - - lightOrg += (enviroOffset.x * firstPersonViewAxis[0]); - lightOrg += (enviroOffset.y * firstPersonViewAxis[1]); - lightOrg += (enviroOffset.z * firstPersonViewAxis[2]); - lightAng.pitch += enviroAngleOffset.x; - lightAng.yaw += enviroAngleOffset.y; - lightAng.roll += enviroAngleOffset.z; - - enviroSuitLight.GetEntity()->GetPhysics()->SetOrigin( lightOrg ); - enviroSuitLight.GetEntity()->GetPhysics()->SetAxis( lightAng.ToMat3() ); - - enviroSuitLight.GetEntity()->UpdateVisuals(); - enviroSuitLight.GetEntity()->Present(); - } - } - } - break; - } - - case IMPULSE_28: { - if ( gameLocal.isClient || entityNumber == gameLocal.localClientNum ) { - gameLocal.mpGame.CastVote( gameLocal.localClientNum, true ); - } - break; - } - case IMPULSE_29: { - if ( gameLocal.isClient || entityNumber == gameLocal.localClientNum ) { - gameLocal.mpGame.CastVote( gameLocal.localClientNum, false ); - } - break; - } - case IMPULSE_40: { - UseVehicle(); - break; - } -#ifdef _D3XP - //Hack so the chainsaw will work in MP - case IMPULSE_27: { - SelectWeapon(18, false); - break; - } -#endif - } -} - -bool idPlayer::HandleESC( void ) { - if ( gameLocal.inCinematic ) { - return SkipCinematic(); - } - - if ( objectiveSystemOpen ) { - TogglePDA(); - return true; - } - - return false; -} - -bool idPlayer::SkipCinematic( void ) { - StartSound( "snd_skipcinematic", SND_CHANNEL_ANY, 0, false, NULL ); - return gameLocal.SkipCinematic(); -} - -/* -============== -idPlayer::EvaluateControls -============== -*/ -void idPlayer::EvaluateControls( void ) { - // check for respawning - if ( health <= 0 ) { - if ( ( gameLocal.time > minRespawnTime ) && ( usercmd.buttons & BUTTON_ATTACK ) ) { - forceRespawn = true; - } else if ( gameLocal.time > maxRespawnTime ) { - forceRespawn = true; - } - } - - // in MP, idMultiplayerGame decides spawns - if ( forceRespawn && !gameLocal.isMultiplayer && !g_testDeath.GetBool() ) { - // in single player, we let the session handle restarting the level or loading a game - gameLocal.sessionCommand = "died"; - } - - if ( ( usercmd.flags & UCF_IMPULSE_SEQUENCE ) != ( oldFlags & UCF_IMPULSE_SEQUENCE ) ) { - PerformImpulse( usercmd.impulse ); - } - - scoreBoardOpen = ( ( usercmd.buttons & BUTTON_SCORES ) != 0 || forceScoreBoard ); - - oldFlags = usercmd.flags; - - AdjustSpeed(); - - // update the viewangles - UpdateViewAngles(); -} - -/* -============== -idPlayer::AdjustSpeed -============== -*/ -void idPlayer::AdjustSpeed( void ) { - float speed; - float rate; - - if ( spectating ) { - speed = pm_spectatespeed.GetFloat(); - bobFrac = 0.0f; - } else if ( noclip ) { - speed = pm_noclipspeed.GetFloat(); - bobFrac = 0.0f; - } else if ( !physicsObj.OnLadder() && ( usercmd.buttons & BUTTON_RUN ) && ( usercmd.forwardmove || usercmd.rightmove ) && ( usercmd.upmove >= 0 ) ) { - if ( !gameLocal.isMultiplayer && !physicsObj.IsCrouching() && !PowerUpActive( ADRENALINE ) ) { - stamina -= MS2SEC( gameLocal.msec ); - } - if ( stamina < 0 ) { - stamina = 0; - } - if ( ( !pm_stamina.GetFloat() ) || ( stamina > pm_staminathreshold.GetFloat() ) ) { - bobFrac = 1.0f; - } else if ( pm_staminathreshold.GetFloat() <= 0.0001f ) { - bobFrac = 0.0f; - } else { - bobFrac = stamina / pm_staminathreshold.GetFloat(); - } - speed = pm_walkspeed.GetFloat() * ( 1.0f - bobFrac ) + pm_runspeed.GetFloat() * bobFrac; - } else { - rate = pm_staminarate.GetFloat(); - - // increase 25% faster when not moving - if ( ( usercmd.forwardmove == 0 ) && ( usercmd.rightmove == 0 ) && ( !physicsObj.OnLadder() || ( usercmd.upmove == 0 ) ) ) { - rate *= 1.25f; - } - - stamina += rate * MS2SEC( gameLocal.msec ); - if ( stamina > pm_stamina.GetFloat() ) { - stamina = pm_stamina.GetFloat(); - } - speed = pm_walkspeed.GetFloat(); - bobFrac = 0.0f; - } - - speed *= PowerUpModifier(SPEED); - - if ( influenceActive == INFLUENCE_LEVEL3 ) { - speed *= 0.33f; - } - - physicsObj.SetSpeed( speed, pm_crouchspeed.GetFloat() ); -} - -/* -============== -idPlayer::AdjustBodyAngles -============== -*/ -void idPlayer::AdjustBodyAngles( void ) { - idMat3 lookAxis; - idMat3 legsAxis; - bool blend; - float diff; - float frac; - float upBlend; - float forwardBlend; - float downBlend; - - if ( health < 0 ) { - return; - } - - blend = true; - - if ( !physicsObj.HasGroundContacts() ) { - idealLegsYaw = 0.0f; - legsForward = true; - } else if ( usercmd.forwardmove < 0 ) { - idealLegsYaw = idMath::AngleNormalize180( idVec3( -usercmd.forwardmove, usercmd.rightmove, 0.0f ).ToYaw() ); - legsForward = false; - } else if ( usercmd.forwardmove > 0 ) { - idealLegsYaw = idMath::AngleNormalize180( idVec3( usercmd.forwardmove, -usercmd.rightmove, 0.0f ).ToYaw() ); - legsForward = true; - } else if ( ( usercmd.rightmove != 0 ) && physicsObj.IsCrouching() ) { - if ( !legsForward ) { - idealLegsYaw = idMath::AngleNormalize180( idVec3( idMath::Abs( usercmd.rightmove ), usercmd.rightmove, 0.0f ).ToYaw() ); - } else { - idealLegsYaw = idMath::AngleNormalize180( idVec3( idMath::Abs( usercmd.rightmove ), -usercmd.rightmove, 0.0f ).ToYaw() ); - } - } else if ( usercmd.rightmove != 0 ) { - idealLegsYaw = 0.0f; - legsForward = true; - } else { - legsForward = true; - diff = idMath::Fabs( idealLegsYaw - legsYaw ); - idealLegsYaw = idealLegsYaw - idMath::AngleNormalize180( viewAngles.yaw - oldViewYaw ); - if ( diff < 0.1f ) { - legsYaw = idealLegsYaw; - blend = false; - } - } - - if ( !physicsObj.IsCrouching() ) { - legsForward = true; - } - - oldViewYaw = viewAngles.yaw; - - AI_TURN_LEFT = false; - AI_TURN_RIGHT = false; - if ( idealLegsYaw < -45.0f ) { - idealLegsYaw = 0; - AI_TURN_RIGHT = true; - blend = true; - } else if ( idealLegsYaw > 45.0f ) { - idealLegsYaw = 0; - AI_TURN_LEFT = true; - blend = true; - } - - if ( blend ) { - legsYaw = legsYaw * 0.9f + idealLegsYaw * 0.1f; - } - legsAxis = idAngles( 0.0f, legsYaw, 0.0f ).ToMat3(); - animator.SetJointAxis( hipJoint, JOINTMOD_WORLD, legsAxis ); - - // calculate the blending between down, straight, and up - frac = viewAngles.pitch / 90.0f; - if ( frac > 0.0f ) { - downBlend = frac; - forwardBlend = 1.0f - frac; - upBlend = 0.0f; - } else { - downBlend = 0.0f; - forwardBlend = 1.0f + frac; - upBlend = -frac; - } - - animator.CurrentAnim( ANIMCHANNEL_TORSO )->SetSyncedAnimWeight( 0, downBlend ); - animator.CurrentAnim( ANIMCHANNEL_TORSO )->SetSyncedAnimWeight( 1, forwardBlend ); - animator.CurrentAnim( ANIMCHANNEL_TORSO )->SetSyncedAnimWeight( 2, upBlend ); - - animator.CurrentAnim( ANIMCHANNEL_LEGS )->SetSyncedAnimWeight( 0, downBlend ); - animator.CurrentAnim( ANIMCHANNEL_LEGS )->SetSyncedAnimWeight( 1, forwardBlend ); - animator.CurrentAnim( ANIMCHANNEL_LEGS )->SetSyncedAnimWeight( 2, upBlend ); -} - -/* -============== -idPlayer::InitAASLocation -============== -*/ -void idPlayer::InitAASLocation( void ) { - int i; - int num; - idVec3 size; - idBounds bounds; - idAAS *aas; - idVec3 origin; - - GetFloorPos( 64.0f, origin ); - - num = gameLocal.NumAAS(); - aasLocation.SetGranularity( 1 ); - aasLocation.SetNum( num ); - for( i = 0; i < aasLocation.Num(); i++ ) { - aasLocation[ i ].areaNum = 0; - aasLocation[ i ].pos = origin; - aas = gameLocal.GetAAS( i ); - if ( aas && aas->GetSettings() ) { - size = aas->GetSettings()->boundingBoxes[0][1]; - bounds[0] = -size; - size.z = 32.0f; - bounds[1] = size; - - aasLocation[ i ].areaNum = aas->PointReachableAreaNum( origin, bounds, AREA_REACHABLE_WALK ); - } - } -} - -/* -============== -idPlayer::SetAASLocation -============== -*/ -void idPlayer::SetAASLocation( void ) { - int i; - int areaNum; - idVec3 size; - idBounds bounds; - idAAS *aas; - idVec3 origin; - - if ( !GetFloorPos( 64.0f, origin ) ) { - return; - } - - for( i = 0; i < aasLocation.Num(); i++ ) { - aas = gameLocal.GetAAS( i ); - if ( !aas ) { - continue; - } - - size = aas->GetSettings()->boundingBoxes[0][1]; - bounds[0] = -size; - size.z = 32.0f; - bounds[1] = size; - - areaNum = aas->PointReachableAreaNum( origin, bounds, AREA_REACHABLE_WALK ); - if ( areaNum ) { - aasLocation[ i ].pos = origin; - aasLocation[ i ].areaNum = areaNum; - } - } -} - -/* -============== -idPlayer::GetAASLocation -============== -*/ -void idPlayer::GetAASLocation( idAAS *aas, idVec3 &pos, int &areaNum ) const { - int i; - - if ( aas != NULL ) { - for( i = 0; i < aasLocation.Num(); i++ ) { - if ( aas == gameLocal.GetAAS( i ) ) { - areaNum = aasLocation[ i ].areaNum; - pos = aasLocation[ i ].pos; - return; - } - } - } - - areaNum = 0; - pos = physicsObj.GetOrigin(); -} - -/* -============== -idPlayer::Move -============== -*/ -void idPlayer::Move( void ) { - float newEyeOffset; - idVec3 oldOrigin; - idVec3 oldVelocity; - idVec3 pushVelocity; - - // save old origin and velocity for crashlanding - oldOrigin = physicsObj.GetOrigin(); - oldVelocity = physicsObj.GetLinearVelocity(); - pushVelocity = physicsObj.GetPushedLinearVelocity(); - - // set physics variables - physicsObj.SetMaxStepHeight( pm_stepsize.GetFloat() ); - physicsObj.SetMaxJumpHeight( pm_jumpheight.GetFloat() ); - - if ( noclip ) { - physicsObj.SetContents( 0 ); - physicsObj.SetMovementType( PM_NOCLIP ); - } else if ( spectating ) { - physicsObj.SetContents( 0 ); - physicsObj.SetMovementType( PM_SPECTATOR ); - } else if ( health <= 0 ) { - physicsObj.SetContents( CONTENTS_CORPSE | CONTENTS_MONSTERCLIP ); - physicsObj.SetMovementType( PM_DEAD ); - } else if ( gameLocal.inCinematic || gameLocal.GetCamera() || privateCameraView || ( influenceActive == INFLUENCE_LEVEL2 ) ) { - physicsObj.SetContents( CONTENTS_BODY ); - physicsObj.SetMovementType( PM_FREEZE ); -#ifdef _D3XP - } else if ( mountedObject ) { - physicsObj.SetContents( 0 ); - physicsObj.SetMovementType( PM_FREEZE ); -#endif - } else { - physicsObj.SetContents( CONTENTS_BODY ); - physicsObj.SetMovementType( PM_NORMAL ); - } - - if ( spectating ) { - physicsObj.SetClipMask( MASK_DEADSOLID ); - } else if ( health <= 0 ) { - physicsObj.SetClipMask( MASK_DEADSOLID ); - } else { - physicsObj.SetClipMask( MASK_PLAYERSOLID ); - } - - physicsObj.SetDebugLevel( g_debugMove.GetBool() ); - physicsObj.SetPlayerInput( usercmd, viewAngles ); - - // FIXME: physics gets disabled somehow - BecomeActive( TH_PHYSICS ); - RunPhysics(); - - // update our last valid AAS location for the AI - SetAASLocation(); - - if ( spectating ) { - newEyeOffset = 0.0f; - } else if ( health <= 0 ) { - newEyeOffset = pm_deadviewheight.GetFloat(); - } else if ( physicsObj.IsCrouching() ) { - newEyeOffset = pm_crouchviewheight.GetFloat(); - } else if ( GetBindMaster() && GetBindMaster()->IsType( idAFEntity_Vehicle::Type ) ) { - newEyeOffset = 0.0f; - } else { - newEyeOffset = pm_normalviewheight.GetFloat(); - } - - if ( EyeHeight() != newEyeOffset ) { - if ( spectating ) { - SetEyeHeight( newEyeOffset ); - } else { - // smooth out duck height changes - SetEyeHeight( EyeHeight() * pm_crouchrate.GetFloat() + newEyeOffset * ( 1.0f - pm_crouchrate.GetFloat() ) ); - } - } - - if ( noclip || gameLocal.inCinematic || ( influenceActive == INFLUENCE_LEVEL2 ) ) { - AI_CROUCH = false; - AI_ONGROUND = ( influenceActive == INFLUENCE_LEVEL2 ); - AI_ONLADDER = false; - AI_JUMP = false; - } else { - AI_CROUCH = physicsObj.IsCrouching(); - AI_ONGROUND = physicsObj.HasGroundContacts(); - AI_ONLADDER = physicsObj.OnLadder(); - AI_JUMP = physicsObj.HasJumped(); - - // check if we're standing on top of a monster and give a push if we are - idEntity *groundEnt = physicsObj.GetGroundEntity(); - if ( groundEnt && groundEnt->IsType( idAI::Type ) ) { - idVec3 vel = physicsObj.GetLinearVelocity(); - if ( vel.ToVec2().LengthSqr() < 0.1f ) { - vel.ToVec2() = physicsObj.GetOrigin().ToVec2() - groundEnt->GetPhysics()->GetAbsBounds().GetCenter().ToVec2(); - vel.ToVec2().NormalizeFast(); - vel.ToVec2() *= pm_walkspeed.GetFloat(); - } else { - // give em a push in the direction they're going - vel *= 1.1f; - } - physicsObj.SetLinearVelocity( vel ); - } - } - - if ( AI_JUMP ) { - // bounce the view weapon - loggedAccel_t *acc = &loggedAccel[currentLoggedAccel&(NUM_LOGGED_ACCELS-1)]; - currentLoggedAccel++; - acc->time = gameLocal.time; - acc->dir[2] = 200; - acc->dir[0] = acc->dir[1] = 0; - } - - if ( AI_ONLADDER ) { - int old_rung = oldOrigin.z / LADDER_RUNG_DISTANCE; - int new_rung = physicsObj.GetOrigin().z / LADDER_RUNG_DISTANCE; - - if ( old_rung != new_rung ) { - StartSound( "snd_stepladder", SND_CHANNEL_ANY, 0, false, NULL ); - } - } - - BobCycle( pushVelocity ); - CrashLand( oldOrigin, oldVelocity ); -} - -/* -============== -idPlayer::UpdateHud -============== -*/ -void idPlayer::UpdateHud( void ) { - idPlayer *aimed; - - if ( !hud ) { - return; - } - - if ( entityNumber != gameLocal.localClientNum ) { - return; - } - - int c = inventory.pickupItemNames.Num(); - if ( c > 0 ) { - if ( gameLocal.time > inventory.nextItemPickup ) { - if ( inventory.nextItemPickup && gameLocal.time - inventory.nextItemPickup > 2000 ) { - inventory.nextItemNum = 1; - } - int i, count = 5; -#ifdef _D3XP - if(gameLocal.isMultiplayer) { - count = 3; - } - - if (count < c) - c = count; -#endif - for ( i = 0; i < c; i++ ) { //_D3XP - hud->SetStateString( va( "itemtext%i", inventory.nextItemNum ), inventory.pickupItemNames[0].name ); - hud->SetStateString( va( "itemicon%i", inventory.nextItemNum ), inventory.pickupItemNames[0].icon ); - hud->HandleNamedEvent( va( "itemPickup%i", inventory.nextItemNum++ ) ); - inventory.pickupItemNames.RemoveIndex( 0 ); - if (inventory.nextItemNum == 1 ) { - inventory.onePickupTime = gameLocal.time; - } else if ( inventory.nextItemNum > count ) { //_D3XP - inventory.nextItemNum = 1; - inventory.nextItemPickup = inventory.onePickupTime + 2000; - } else { - inventory.nextItemPickup = gameLocal.time + 400; - } - } - } - } - - if ( gameLocal.realClientTime == lastMPAimTime ) { - if ( MPAim != -1 && gameLocal.mpGame.IsGametypeTeamBased() /* CTF */ - && gameLocal.entities[ MPAim ] && gameLocal.entities[ MPAim ]->IsType( idPlayer::Type ) - && static_cast< idPlayer * >( gameLocal.entities[ MPAim ] )->team == team ) { - aimed = static_cast< idPlayer * >( gameLocal.entities[ MPAim ] ); - hud->SetStateString( "aim_text", gameLocal.userInfo[ MPAim ].GetString( "ui_name" ) ); - hud->SetStateFloat( "aim_color", aimed->colorBarIndex ); - hud->HandleNamedEvent( "aim_flash" ); - MPAimHighlight = true; - MPAimFadeTime = 0; // no fade till loosing focus - } else if ( MPAimHighlight ) { - hud->HandleNamedEvent( "aim_fade" ); - MPAimFadeTime = gameLocal.realClientTime; - MPAimHighlight = false; - } - } - if ( MPAimFadeTime ) { - assert( !MPAimHighlight ); - if ( gameLocal.realClientTime - MPAimFadeTime > 2000 ) { - MPAimFadeTime = 0; - } - } - - hud->SetStateInt( "g_showProjectilePct", g_showProjectilePct.GetInteger() ); - if ( numProjectilesFired ) { - hud->SetStateString( "projectilepct", va( "Hit %% %.1f", ( (float) numProjectileHits / numProjectilesFired ) * 100 ) ); - } else { - hud->SetStateString( "projectilepct", "Hit % 0.0" ); - } - - if ( isLagged && gameLocal.isMultiplayer && gameLocal.localClientNum == entityNumber ) { - hud->SetStateString( "hudLag", "1" ); - } else { - hud->SetStateString( "hudLag", "0" ); - } -} - -/* -============== -idPlayer::UpdateDeathSkin -============== -*/ -void idPlayer::UpdateDeathSkin( bool state_hitch ) { - if ( !( gameLocal.isMultiplayer || g_testDeath.GetBool() ) ) { - return; - } - if ( health <= 0 ) { - if ( !doingDeathSkin ) { - deathClearContentsTime = spawnArgs.GetInt( "deathSkinTime" ); - doingDeathSkin = true; - renderEntity.noShadow = true; - if ( state_hitch ) { - renderEntity.shaderParms[ SHADERPARM_TIME_OF_DEATH ] = gameLocal.time * 0.001f - 2.0f; - } else { - renderEntity.shaderParms[ SHADERPARM_TIME_OF_DEATH ] = gameLocal.time * 0.001f; - } - UpdateVisuals(); - } - - // wait a bit before switching off the content - if ( deathClearContentsTime && gameLocal.time > deathClearContentsTime ) { - SetCombatContents( false ); - deathClearContentsTime = 0; - } - } else { - renderEntity.noShadow = false; - renderEntity.shaderParms[ SHADERPARM_TIME_OF_DEATH ] = 0.0f; - UpdateVisuals(); - doingDeathSkin = false; - } -} - -/* -============== -idPlayer::StartFxOnBone -============== -*/ -void idPlayer::StartFxOnBone( const char *fx, const char *bone ) { - idVec3 offset; - idMat3 axis; - jointHandle_t jointHandle = GetAnimator()->GetJointHandle( bone ); - - if ( jointHandle == INVALID_JOINT ) { - gameLocal.Printf( "Cannot find bone %s\n", bone ); - return; - } - - if ( GetAnimator()->GetJointTransform( jointHandle, gameLocal.time, offset, axis ) ) { - offset = GetPhysics()->GetOrigin() + offset * GetPhysics()->GetAxis(); - axis = axis * GetPhysics()->GetAxis(); - } - - idEntityFx::StartFx( fx, &offset, &axis, this, true ); -} - -/* -============== -idPlayer::Think - -Called every tic for each player -============== -*/ -void idPlayer::Think( void ) { - renderEntity_t *headRenderEnt; - - UpdatePlayerIcons(); - - // latch button actions - oldButtons = usercmd.buttons; - - // grab out usercmd - usercmd_t oldCmd = usercmd; - usercmd = gameLocal.usercmds[ entityNumber ]; - buttonMask &= usercmd.buttons; - usercmd.buttons &= ~buttonMask; - - if ( gameLocal.inCinematic && gameLocal.skipCinematic ) { - return; - } - - // clear the ik before we do anything else so the skeleton doesn't get updated twice - walkIK.ClearJointMods(); - - // if this is the very first frame of the map, set the delta view angles - // based on the usercmd angles - if ( !spawnAnglesSet && ( gameLocal.GameState() != GAMESTATE_STARTUP ) ) { - spawnAnglesSet = true; - SetViewAngles( spawnAngles ); - oldFlags = usercmd.flags; - } - -#ifdef _D3XP - if ( mountedObject ) { - usercmd.forwardmove = 0; - usercmd.rightmove = 0; - usercmd.upmove = 0; - } -#endif - - if ( objectiveSystemOpen || gameLocal.inCinematic || influenceActive ) { - if ( objectiveSystemOpen && AI_PAIN ) { - TogglePDA(); - } - usercmd.forwardmove = 0; - usercmd.rightmove = 0; - usercmd.upmove = 0; - } - - // log movement changes for weapon bobbing effects - if ( usercmd.forwardmove != oldCmd.forwardmove ) { - loggedAccel_t *acc = &loggedAccel[currentLoggedAccel&(NUM_LOGGED_ACCELS-1)]; - currentLoggedAccel++; - acc->time = gameLocal.time; - acc->dir[0] = usercmd.forwardmove - oldCmd.forwardmove; - acc->dir[1] = acc->dir[2] = 0; - } - - if ( usercmd.rightmove != oldCmd.rightmove ) { - loggedAccel_t *acc = &loggedAccel[currentLoggedAccel&(NUM_LOGGED_ACCELS-1)]; - currentLoggedAccel++; - acc->time = gameLocal.time; - acc->dir[1] = usercmd.rightmove - oldCmd.rightmove; - acc->dir[0] = acc->dir[2] = 0; - } - - // freelook centering - if ( ( usercmd.buttons ^ oldCmd.buttons ) & BUTTON_MLOOK ) { - centerView.Init( gameLocal.time, 200, viewAngles.pitch, 0 ); - } - - // zooming - if ( ( usercmd.buttons ^ oldCmd.buttons ) & BUTTON_ZOOM ) { - if ( ( usercmd.buttons & BUTTON_ZOOM ) && weapon.GetEntity() ) { - zoomFov.Init( gameLocal.time, 200.0f, CalcFov( false ), weapon.GetEntity()->GetZoomFov() ); - } else { - zoomFov.Init( gameLocal.time, 200.0f, zoomFov.GetCurrentValue( gameLocal.time ), DefaultFov() ); - } - } - - // if we have an active gui, we will unrotate the view angles as - // we turn the mouse movements into gui events - idUserInterface *gui = ActiveGui(); - if ( gui && gui != focusUI ) { - RouteGuiMouse( gui ); - } - - // set the push velocity on the weapon before running the physics - if ( weapon.GetEntity() ) { - weapon.GetEntity()->SetPushVelocity( physicsObj.GetPushedLinearVelocity() ); - } - - EvaluateControls(); - - if ( !af.IsActive() ) { - AdjustBodyAngles(); - CopyJointsFromBodyToHead(); - } - - Move(); - - if ( !g_stopTime.GetBool() ) { - - if ( !noclip && !spectating && ( health > 0 ) && !IsHidden() ) { - TouchTriggers(); - } - - // not done on clients for various reasons. don't do it on server and save the sound channel for other things - if ( !gameLocal.isMultiplayer ) { - SetCurrentHeartRate(); -#ifdef _D3XP - float scale = new_g_damageScale; -#else - float scale = g_damageScale.GetFloat(); -#endif - if ( g_useDynamicProtection.GetBool() && scale < 1.0f && gameLocal.time - lastDmgTime > 500 ) { - if ( scale < 1.0f ) { - scale += 0.05f; - } - if ( scale > 1.0f ) { - scale = 1.0f; - } -#ifdef _D3XP - new_g_damageScale = scale; -#else - g_damageScale.SetFloat( scale ); -#endif - } - } - - // update GUIs, Items, and character interactions - UpdateFocus(); - - UpdateLocation(); - - // update player script - UpdateScript(); - - // service animations - if ( !spectating && !af.IsActive() && !gameLocal.inCinematic ) { - UpdateConditions(); - UpdateAnimState(); - CheckBlink(); - } - - // clear out our pain flag so we can tell if we recieve any damage between now and the next time we think - AI_PAIN = false; - } - - // calculate the exact bobbed view position, which is used to - // position the view weapon, among other things - CalculateFirstPersonView(); - - // this may use firstPersonView, or a thirdPeroson / camera view - CalculateRenderView(); - - inventory.UpdateArmor(); - - if ( spectating ) { - UpdateSpectating(); - } else if ( health > 0 ) { - UpdateWeapon(); - } - - UpdateAir(); - -#ifdef _D3XP - UpdatePowerupHud(); -#endif - - UpdateHud(); - - UpdatePowerUps(); - - UpdateDeathSkin( false ); - - if ( gameLocal.isMultiplayer ) { - DrawPlayerIcons(); - -#ifdef _D3XP - if ( enviroSuitLight.IsValid() ) { - idAngles lightAng = firstPersonViewAxis.ToAngles(); - idVec3 lightOrg = firstPersonViewOrigin; - const idDict *lightDef = gameLocal.FindEntityDefDict( "envirosuit_light", false ); - - idVec3 enviroOffset = lightDef->GetVector( "enviro_offset" ); - idVec3 enviroAngleOffset = lightDef->GetVector( "enviro_angle_offset" ); - - lightOrg += (enviroOffset.x * firstPersonViewAxis[0]); - lightOrg += (enviroOffset.y * firstPersonViewAxis[1]); - lightOrg += (enviroOffset.z * firstPersonViewAxis[2]); - lightAng.pitch += enviroAngleOffset.x; - lightAng.yaw += enviroAngleOffset.y; - lightAng.roll += enviroAngleOffset.z; - - enviroSuitLight.GetEntity()->GetPhysics()->SetOrigin( lightOrg ); - enviroSuitLight.GetEntity()->GetPhysics()->SetAxis( lightAng.ToMat3() ); - enviroSuitLight.GetEntity()->UpdateVisuals(); - enviroSuitLight.GetEntity()->Present(); - } -#endif - } - - if ( head.GetEntity() ) { - headRenderEnt = head.GetEntity()->GetRenderEntity(); - } else { - headRenderEnt = NULL; - } - - if ( headRenderEnt ) { - if ( influenceSkin ) { - headRenderEnt->customSkin = influenceSkin; - } else { - headRenderEnt->customSkin = NULL; - } - } - - if ( gameLocal.isMultiplayer || g_showPlayerShadow.GetBool() ) { - renderEntity.suppressShadowInViewID = 0; - if ( headRenderEnt ) { - headRenderEnt->suppressShadowInViewID = 0; - } - } else { - renderEntity.suppressShadowInViewID = entityNumber+1; - if ( headRenderEnt ) { - headRenderEnt->suppressShadowInViewID = entityNumber+1; - } - } - // never cast shadows from our first-person muzzle flashes - renderEntity.suppressShadowInLightID = LIGHTID_VIEW_MUZZLE_FLASH + entityNumber; - if ( headRenderEnt ) { - headRenderEnt->suppressShadowInLightID = LIGHTID_VIEW_MUZZLE_FLASH + entityNumber; - } - - if ( !g_stopTime.GetBool() ) { - UpdateAnimation(); - - Present(); - - UpdateDamageEffects(); - - LinkCombat(); - - playerView.CalculateShake(); - } - - if ( !( thinkFlags & TH_THINK ) ) { - gameLocal.Printf( "player %d not thinking?\n", entityNumber ); - } - - if ( g_showEnemies.GetBool() ) { - idActor *ent; - int num = 0; - for( ent = enemyList.Next(); ent != NULL; ent = ent->enemyNode.Next() ) { - gameLocal.Printf( "enemy (%d)'%s'\n", ent->entityNumber, ent->name.c_str() ); - gameRenderWorld->DebugBounds( colorRed, ent->GetPhysics()->GetBounds().Expand( 2 ), ent->GetPhysics()->GetOrigin() ); - num++; - } - gameLocal.Printf( "%d: enemies\n", num ); - } - -#ifdef _D3XP - inventory.RechargeAmmo(this); - - if(healthRecharge) { - int elapsed = gameLocal.time - lastHealthRechargeTime; - if(elapsed >= rechargeSpeed) { - int intervals = (gameLocal.time - lastHealthRechargeTime)/rechargeSpeed; - Give("health", va("%d", intervals)); - lastHealthRechargeTime += intervals*rechargeSpeed; - } - } - - // determine if portal sky is in pvs - gameLocal.portalSkyActive = gameLocal.pvs.CheckAreasForPortalSky( gameLocal.GetPlayerPVS(), GetPhysics()->GetOrigin() ); -#endif -} - -#ifdef _D3XP -/* -================= -idPlayer::StartHealthRecharge -================= -*/ -void idPlayer::StartHealthRecharge(int speed) { - lastHealthRechargeTime = gameLocal.time; - healthRecharge = true; - rechargeSpeed = speed; -} - -/* -================= -idPlayer::StopHealthRecharge -================= -*/ -void idPlayer::StopHealthRecharge() { - healthRecharge = false; -} - -/* -================= -idPlayer::GetCurrentWeapon -================= -*/ -idStr idPlayer::GetCurrentWeapon() { - const char *weapon; - - if ( currentWeapon >= 0 ) { - weapon = spawnArgs.GetString( va( "def_weapon%d", currentWeapon ) ); - return weapon; - } else { - return ""; - } -} - -/* -================= -idPlayer::CanGive -================= -*/ -bool idPlayer::CanGive( const char *statname, const char *value ) { - if ( AI_DEAD ) { - return false; - } - - if ( !idStr::Icmp( statname, "health" ) ) { - if ( health >= inventory.maxHealth ) { - return false; - } - return true; - } else if ( !idStr::Icmp( statname, "stamina" ) ) { - if ( stamina >= 100 ) { - return false; - } - return true; - - } else if ( !idStr::Icmp( statname, "heartRate" ) ) { - return true; - - } else if ( !idStr::Icmp( statname, "air" ) ) { - if ( airTics >= pm_airTics.GetInteger() ) { - return false; - } - return true; - } - - return inventory.CanGive( this, spawnArgs, statname, value, &idealWeapon ); -} - -/* -================= -idPlayer::StopHelltime - -provides a quick non-ramping way of stopping helltime -================= -*/ -void idPlayer::StopHelltime( bool quick ) { - if ( !PowerUpActive( HELLTIME ) ) { - return; - } - - // take away the powerups - if ( PowerUpActive( INVULNERABILITY ) ) { - ClearPowerup( INVULNERABILITY ); - } - - if ( PowerUpActive( BERSERK ) ) { - ClearPowerup( BERSERK ); - } - - if ( PowerUpActive( HELLTIME ) ) { - ClearPowerup( HELLTIME ); - } - - // stop the looping sound - StopSound( SND_CHANNEL_DEMONIC, false ); - - // reset the game vars - if ( quick ) { - gameLocal.QuickSlowmoReset(); - } -} - -/* -================= -idPlayer::Event_ToggleBloom -================= -*/ -void idPlayer::Event_ToggleBloom( int on ) { - if ( on ) { - bloomEnabled = true; - } - else { - bloomEnabled = false; - } -} - -/* -================= -idPlayer::Event_SetBloomParms -================= -*/ -void idPlayer::Event_SetBloomParms( float speed, float intensity ) { - bloomSpeed = speed; - bloomIntensity = intensity; -} - -/* -================= -idPlayer::PlayHelltimeStopSound -================= -*/ -void idPlayer::PlayHelltimeStopSound() { - const char* sound; - - if ( spawnArgs.GetString( "snd_helltime_stop", "", &sound ) ) { - PostEventMS( &EV_StartSoundShader, 0, sound, SND_CHANNEL_ANY ); - } -} -#endif - -/* -================= -idPlayer::RouteGuiMouse -================= -*/ -void idPlayer::RouteGuiMouse( idUserInterface *gui ) { - sysEvent_t ev; - - if ( usercmd.mx != oldMouseX || usercmd.my != oldMouseY ) { - ev = sys->GenerateMouseMoveEvent( usercmd.mx - oldMouseX, usercmd.my - oldMouseY ); - gui->HandleEvent( &ev, gameLocal.time ); - oldMouseX = usercmd.mx; - oldMouseY = usercmd.my; - } -} - -/* -================== -idPlayer::LookAtKiller -================== -*/ -void idPlayer::LookAtKiller( idEntity *inflictor, idEntity *attacker ) { - idVec3 dir; - - if ( attacker && attacker != this ) { - dir = attacker->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin(); - } else if ( inflictor && inflictor != this ) { - dir = inflictor->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin(); - } else { - dir = viewAxis[ 0 ]; - } - - idAngles ang( 0, dir.ToYaw(), 0 ); - SetViewAngles( ang ); -} - -/* -============== -idPlayer::Kill -============== -*/ -void idPlayer::Kill( bool delayRespawn, bool nodamage ) { - if ( spectating ) { - SpectateFreeFly( false ); - } else if ( health > 0 ) { - godmode = false; - if ( nodamage ) { - ServerSpectate( true ); - forceRespawn = true; - } else { - Damage( this, this, vec3_origin, "damage_suicide", 1.0f, INVALID_JOINT ); - if ( delayRespawn ) { - forceRespawn = false; - int delay = spawnArgs.GetFloat( "respawn_delay" ); - minRespawnTime = gameLocal.time + SEC2MS( delay ); - maxRespawnTime = minRespawnTime + MAX_RESPAWN_TIME; - } - } - } -} - -/* -================== -idPlayer::Killed -================== -*/ -void idPlayer::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) { - float delay; - - assert( !gameLocal.isClient ); - - // stop taking knockback once dead - fl.noknockback = true; - if ( health < -999 ) { - health = -999; - } - - if ( AI_DEAD ) { - AI_PAIN = true; - return; - } - - heartInfo.Init( 0, 0, 0, BASE_HEARTRATE ); - AdjustHeartRate( DEAD_HEARTRATE, 10.0f, 0.0f, true ); - - if ( !g_testDeath.GetBool() ) { - playerView.Fade( colorBlack, 12000 ); - } - - AI_DEAD = true; - SetAnimState( ANIMCHANNEL_LEGS, "Legs_Death", 4 ); - SetAnimState( ANIMCHANNEL_TORSO, "Torso_Death", 4 ); - SetWaitState( "" ); - - animator.ClearAllJoints(); - - if ( StartRagdoll() ) { - pm_modelView.SetInteger( 0 ); - minRespawnTime = gameLocal.time + RAGDOLL_DEATH_TIME; - maxRespawnTime = minRespawnTime + MAX_RESPAWN_TIME; - } else { - // don't allow respawn until the death anim is done - // g_forcerespawn may force spawning at some later time - delay = spawnArgs.GetFloat( "respawn_delay" ); - minRespawnTime = gameLocal.time + SEC2MS( delay ); - maxRespawnTime = minRespawnTime + MAX_RESPAWN_TIME; - } - - physicsObj.SetMovementType( PM_DEAD ); - StartSound( "snd_death", SND_CHANNEL_VOICE, 0, false, NULL ); - StopSound( SND_CHANNEL_BODY2, false ); - - fl.takedamage = true; // can still be gibbed - - // get rid of weapon - weapon.GetEntity()->OwnerDied(); - - // drop the weapon as an item - DropWeapon( true ); - -#ifdef CTF - // drop the flag if player was carrying it - if ( gameLocal.isMultiplayer && gameLocal.mpGame.IsGametypeFlagBased() && - carryingFlag ) - { - DropFlag(); - } -#endif - - if ( !g_testDeath.GetBool() ) { - LookAtKiller( inflictor, attacker ); - } - - if ( gameLocal.isMultiplayer || g_testDeath.GetBool() ) { - idPlayer *killer = NULL; - // no gibbing in MP. Event_Gib will early out in MP - if ( attacker->IsType( idPlayer::Type ) ) { - killer = static_cast(attacker); - if ( health < -20 || killer->PowerUpActive( BERSERK ) ) { - gibDeath = true; - gibsDir = dir; - gibsLaunched = false; - } - } - gameLocal.mpGame.PlayerDeath( this, killer, isTelefragged ); - } else { - physicsObj.SetContents( CONTENTS_CORPSE | CONTENTS_MONSTERCLIP ); - } - - ClearPowerUps(); - - UpdateVisuals(); - - isChatting = false; -} - -/* -===================== -idPlayer::GetAIAimTargets - -Returns positions for the AI to aim at. -===================== -*/ -void idPlayer::GetAIAimTargets( const idVec3 &lastSightPos, idVec3 &headPos, idVec3 &chestPos ) { - idVec3 offset; - idMat3 axis; - idVec3 origin; - - origin = lastSightPos - physicsObj.GetOrigin(); - - GetJointWorldTransform( chestJoint, gameLocal.time, offset, axis ); - headPos = offset + origin; - - GetJointWorldTransform( headJoint, gameLocal.time, offset, axis ); - chestPos = offset + origin; -} - -/* -================ -idPlayer::DamageFeedback - -callback function for when another entity received damage from this entity. damage can be adjusted and returned to the caller. -================ -*/ -void idPlayer::DamageFeedback( idEntity *victim, idEntity *inflictor, int &damage ) { - assert( !gameLocal.isClient ); - damage *= PowerUpModifier( BERSERK ); - if ( damage && ( victim != this ) && ( victim->IsType( idActor::Type ) || victim->IsType( idDamagable::Type ) ) ) { - - idPlayer *victimPlayer = NULL; - - /* No damage feedback sound for hitting friendlies in CTF */ - if ( victim->IsType( idPlayer::Type ) ) { - victimPlayer = static_cast(victim); - } - - if ( gameLocal.mpGame.IsGametypeFlagBased() && victimPlayer && this->team == victimPlayer->team ) { - /* Do nothing ... */ - } - else { - SetLastHitTime( gameLocal.time ); - } - } -} - -/* -================= -idPlayer::CalcDamagePoints - -Calculates how many health and armor points will be inflicted, but -doesn't actually do anything with them. This is used to tell when an attack -would have killed the player, possibly allowing a "saving throw" -================= -*/ -void idPlayer::CalcDamagePoints( idEntity *inflictor, idEntity *attacker, const idDict *damageDef, - const float damageScale, const int location, int *health, int *armor ) { - int damage; - int armorSave; - - damageDef->GetInt( "damage", "20", damage ); - damage = GetDamageForLocation( damage, location ); - - idPlayer *player = attacker->IsType( idPlayer::Type ) ? static_cast(attacker) : NULL; - if ( !gameLocal.isMultiplayer ) { - if ( inflictor != gameLocal.world ) { - switch ( g_skill.GetInteger() ) { - case 0: - damage *= 0.80f; - if ( damage < 1 ) { - damage = 1; - } - break; - case 2: - damage *= 1.70f; - break; - case 3: - damage *= 3.5f; - break; - default: - break; - } - } - } - - damage *= damageScale; - - // always give half damage if hurting self - if ( attacker == this ) { - if ( gameLocal.isMultiplayer ) { - // only do this in mp so single player plasma and rocket splash is very dangerous in close quarters - damage *= damageDef->GetFloat( "selfDamageScale", "0.5" ); - } else { - damage *= damageDef->GetFloat( "selfDamageScale", "1" ); - } - } - - // check for completely getting out of the damage - if ( !damageDef->GetBool( "noGod" ) ) { - // check for godmode - if ( godmode ) { - damage = 0; - } -#ifdef _D3XP - //Invulnerability is just like god mode - if( PowerUpActive( INVULNERABILITY ) ) { - damage = 0; - } -#endif - } - - // inform the attacker that they hit someone - attacker->DamageFeedback( this, inflictor, damage ); - - // save some from armor - if ( !damageDef->GetBool( "noArmor" ) ) { - float armor_protection; - - armor_protection = ( gameLocal.isMultiplayer ) ? g_armorProtectionMP.GetFloat() : g_armorProtection.GetFloat(); - - armorSave = ceil( damage * armor_protection ); - if ( armorSave >= inventory.armor ) { - armorSave = inventory.armor; - } - - if ( !damage ) { - armorSave = 0; - } else if ( armorSave >= damage ) { - armorSave = damage - 1; - damage = 1; - } else { - damage -= armorSave; - } - } else { - armorSave = 0; - } - - // check for team damage - if ( gameLocal.mpGame.IsGametypeTeamBased() /* CTF */ - && !gameLocal.serverInfo.GetBool( "si_teamDamage" ) - && !damageDef->GetBool( "noTeam" ) - && player - && player != this // you get self damage no matter what - && player->team == team ) { - damage = 0; - } - - *health = damage; - *armor = armorSave; -} - -/* -============ -Damage - -this entity that is being damaged -inflictor entity that is causing the damage -attacker entity that caused the inflictor to damage targ - example: this=monster, inflictor=rocket, attacker=player - -dir direction of the attack for knockback in global space - -damageDef an idDict with all the options for damage effects - -inflictor, attacker, dir, and point can be NULL for environmental effects -============ -*/ -void idPlayer::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, - const char *damageDefName, const float damageScale, const int location ) { - idVec3 kick; - int damage; - int armorSave; - int knockback; - idVec3 damage_from; - idVec3 localDamageVector; - float attackerPushScale; -#ifdef _D3XP - SetTimeState ts( timeGroup ); -#endif - - // damage is only processed on server - if ( gameLocal.isClient ) { - return; - } - - if ( !fl.takedamage || noclip || spectating || gameLocal.inCinematic ) { - return; - } - - if ( !inflictor ) { - inflictor = gameLocal.world; - } - if ( !attacker ) { - attacker = gameLocal.world; - } - - if ( attacker->IsType( idAI::Type ) ) { -#ifndef _D3XP - if ( PowerUpActive( BERSERK ) ) { - return; - } -#endif - // don't take damage from monsters during influences - if ( influenceActive != 0 ) { - return; - } - } - - const idDeclEntityDef *damageDef = gameLocal.FindEntityDef( damageDefName, false ); - if ( !damageDef ) { - gameLocal.Warning( "Unknown damageDef '%s'", damageDefName ); - return; - } - - if ( damageDef->dict.GetBool( "ignore_player" ) ) { - return; - } - - CalcDamagePoints( inflictor, attacker, &damageDef->dict, damageScale, location, &damage, &armorSave ); - - // determine knockback - damageDef->dict.GetInt( "knockback", "20", knockback ); - -/*#ifdef _D3XP - idPlayer *player = attacker->IsType( idPlayer::Type ) ? static_cast(attacker) : NULL; - - if ( gameLocal.mpGame.IsGametypeTeamBased() - && !gameLocal.serverInfo.GetBool( "si_teamDamage" ) - && !damageDef->dict.GetBool( "noTeam" ) - && player - && player != this // you get self damage no matter what - && player->team == team ) { - knockback = 0; - } -#endif*/ - - if ( knockback != 0 && !fl.noknockback ) { - if ( attacker == this ) { - damageDef->dict.GetFloat( "attackerPushScale", "0", attackerPushScale ); - } else { - attackerPushScale = 1.0f; - } - - kick = dir; - kick.Normalize(); - kick *= g_knockback.GetFloat() * knockback * attackerPushScale / 200.0f; - physicsObj.SetLinearVelocity( physicsObj.GetLinearVelocity() + kick ); - - // set the timer so that the player can't cancel out the movement immediately - physicsObj.SetKnockBack( idMath::ClampInt( 50, 200, knockback * 2 ) ); - } - - - // give feedback on the player view and audibly when armor is helping - if ( armorSave ) { - inventory.armor -= armorSave; - - if ( gameLocal.time > lastArmorPulse + 200 ) { - StartSound( "snd_hitArmor", SND_CHANNEL_ITEM, 0, false, NULL ); - } - lastArmorPulse = gameLocal.time; - } - - if ( damageDef->dict.GetBool( "burn" ) ) { - StartSound( "snd_burn", SND_CHANNEL_BODY3, 0, false, NULL ); - } else if ( damageDef->dict.GetBool( "no_air" ) ) { - if ( !armorSave && health > 0 ) { - StartSound( "snd_airGasp", SND_CHANNEL_ITEM, 0, false, NULL ); - } - } - - if ( g_debugDamage.GetInteger() ) { - gameLocal.Printf( "client:%i health:%i damage:%i armor:%i\n", - entityNumber, health, damage, armorSave ); - } - - // move the world direction vector to local coordinates - damage_from = dir; - damage_from.Normalize(); - - viewAxis.ProjectVector( damage_from, localDamageVector ); - - // add to the damage inflicted on a player this frame - // the total will be turned into screen blends and view angle kicks - // at the end of the frame - if ( health > 0 ) { - playerView.DamageImpulse( localDamageVector, &damageDef->dict ); - } - - // do the damage - if ( damage > 0 ) { - - if ( !gameLocal.isMultiplayer ) { -#ifdef _D3XP - float scale = new_g_damageScale; -#else - float scale = g_damageScale.GetFloat(); -#endif - if ( g_useDynamicProtection.GetBool() && g_skill.GetInteger() < 2 ) { - if ( gameLocal.time > lastDmgTime + 500 && scale > 0.25f ) { - scale -= 0.05f; -#ifdef _D3XP - new_g_damageScale = scale; -#else - g_damageScale.SetFloat( scale ); -#endif - } - } - - if ( scale > 0.0f ) { - damage *= scale; - } - } - - if ( damage < 1 ) { - damage = 1; - } - - health -= damage; - - if ( health <= 0 ) { - - if ( health < -999 ) { - health = -999; - } - - isTelefragged = damageDef->dict.GetBool( "telefrag" ); - - lastDmgTime = gameLocal.time; - Killed( inflictor, attacker, damage, dir, location ); - - } else { - // force a blink - blink_time = 0; - - // let the anim script know we took damage - AI_PAIN = Pain( inflictor, attacker, damage, dir, location ); - if ( !g_testDeath.GetBool() ) { - lastDmgTime = gameLocal.time; - } - } - } else { - // don't accumulate impulses - if ( af.IsLoaded() ) { - // clear impacts - af.Rest(); - - // physics is turned off by calling af.Rest() - BecomeActive( TH_PHYSICS ); - } - } - - lastDamageDef = damageDef->Index(); - lastDamageDir = damage_from; - lastDamageLocation = location; -} - -/* -=========== -idPlayer::Teleport -============ -*/ -void idPlayer::Teleport( const idVec3 &origin, const idAngles &angles, idEntity *destination ) { - idVec3 org; - - if ( weapon.GetEntity() ) { - weapon.GetEntity()->LowerWeapon(); - } - - SetOrigin( origin + idVec3( 0, 0, CM_CLIP_EPSILON ) ); - if ( !gameLocal.isMultiplayer && GetFloorPos( 16.0f, org ) ) { - SetOrigin( org ); - } - - // clear the ik heights so model doesn't appear in the wrong place - walkIK.EnableAll(); - - GetPhysics()->SetLinearVelocity( vec3_origin ); - - SetViewAngles( angles ); - - legsYaw = 0.0f; - idealLegsYaw = 0.0f; - oldViewYaw = viewAngles.yaw; - - if ( gameLocal.isMultiplayer ) { - playerView.Flash( colorWhite, 140 ); - } - - UpdateVisuals(); - - teleportEntity = destination; - - if ( !gameLocal.isClient && !noclip ) { - if ( gameLocal.isMultiplayer ) { - // kill anything at the new position or mark for kill depending on immediate or delayed teleport - gameLocal.KillBox( this, destination != NULL ); - } else { - // kill anything at the new position - gameLocal.KillBox( this, true ); - } - } - -#ifdef _D3XP - if ( PowerUpActive( HELLTIME ) ) { - StopHelltime(); - } -#endif -} - -/* -==================== -idPlayer::SetPrivateCameraView -==================== -*/ -void idPlayer::SetPrivateCameraView( idCamera *camView ) { - privateCameraView = camView; - if ( camView ) { - StopFiring(); - Hide(); - } else { - if ( !spectating ) { - Show(); - } - } -} - -/* -==================== -idPlayer::DefaultFov - -Returns the base FOV -==================== -*/ -float idPlayer::DefaultFov( void ) const { - float fov; - - fov = g_fov.GetFloat(); - if ( gameLocal.isMultiplayer ) { - if ( fov < 90.0f ) { - return 90.0f; - } else if ( fov > 110.0f ) { - return 110.0f; - } - } - - return fov; -} - -/* -==================== -idPlayer::CalcFov - -Fixed fov at intermissions, otherwise account for fov variable and zooms. -==================== -*/ -float idPlayer::CalcFov( bool honorZoom ) { - float fov; - - if ( fxFov ) { - return DefaultFov() + 10.0f + cos( ( gameLocal.time + 2000 ) * 0.01 ) * 10.0f; - } - - if ( influenceFov ) { - return influenceFov; - } - - if ( zoomFov.IsDone( gameLocal.time ) ) { - fov = ( honorZoom && usercmd.buttons & BUTTON_ZOOM ) && weapon.GetEntity() ? weapon.GetEntity()->GetZoomFov() : DefaultFov(); - } else { - fov = zoomFov.GetCurrentValue( gameLocal.time ); - } - - // bound normal viewsize - if ( fov < 1 ) { - fov = 1; - } else if ( fov > 179 ) { - fov = 179; - } - - return fov; -} - -/* -============== -idPlayer::GunTurningOffset - -generate a rotational offset for the gun based on the view angle -history in loggedViewAngles -============== -*/ -idAngles idPlayer::GunTurningOffset( void ) { - idAngles a; - - a.Zero(); - - if ( gameLocal.framenum < NUM_LOGGED_VIEW_ANGLES ) { - return a; - } - - idAngles current = loggedViewAngles[ gameLocal.framenum & (NUM_LOGGED_VIEW_ANGLES-1) ]; - - idAngles av, base; - int weaponAngleOffsetAverages; - float weaponAngleOffsetScale, weaponAngleOffsetMax; - - weapon.GetEntity()->GetWeaponAngleOffsets( &weaponAngleOffsetAverages, &weaponAngleOffsetScale, &weaponAngleOffsetMax ); - - av = current; - - // calcualte this so the wrap arounds work properly - for ( int j = 1 ; j < weaponAngleOffsetAverages ; j++ ) { - idAngles a2 = loggedViewAngles[ ( gameLocal.framenum - j ) & (NUM_LOGGED_VIEW_ANGLES-1) ]; - - idAngles delta = a2 - current; - - if ( delta[1] > 180 ) { - delta[1] -= 360; - } else if ( delta[1] < -180 ) { - delta[1] += 360; - } - - av += delta * ( 1.0f / weaponAngleOffsetAverages ); - } - - a = ( av - current ) * weaponAngleOffsetScale; - - for ( int i = 0 ; i < 3 ; i++ ) { - if ( a[i] < -weaponAngleOffsetMax ) { - a[i] = -weaponAngleOffsetMax; - } else if ( a[i] > weaponAngleOffsetMax ) { - a[i] = weaponAngleOffsetMax; - } - } - - return a; -} - -/* -============== -idPlayer::GunAcceleratingOffset - -generate a positional offset for the gun based on the movement -history in loggedAccelerations -============== -*/ -idVec3 idPlayer::GunAcceleratingOffset( void ) { - idVec3 ofs; - - float weaponOffsetTime, weaponOffsetScale; - - ofs.Zero(); - - weapon.GetEntity()->GetWeaponTimeOffsets( &weaponOffsetTime, &weaponOffsetScale ); - - int stop = currentLoggedAccel - NUM_LOGGED_ACCELS; - if ( stop < 0 ) { - stop = 0; - } - for ( int i = currentLoggedAccel-1 ; i > stop ; i-- ) { - loggedAccel_t *acc = &loggedAccel[i&(NUM_LOGGED_ACCELS-1)]; - - float f; - float t = gameLocal.time - acc->time; - if ( t >= weaponOffsetTime ) { - break; // remainder are too old to care about - } - - f = t / weaponOffsetTime; - f = ( cos( f * 2.0f * idMath::PI ) - 1.0f ) * 0.5f; - ofs += f * weaponOffsetScale * acc->dir; - } - - return ofs; -} - -/* -============== -idPlayer::CalculateViewWeaponPos - -Calculate the bobbing position of the view weapon -============== -*/ -void idPlayer::CalculateViewWeaponPos( idVec3 &origin, idMat3 &axis ) { - float scale; - float fracsin; - idAngles angles; - int delta; - - // CalculateRenderView must have been called first - const idVec3 &viewOrigin = firstPersonViewOrigin; - const idMat3 &viewAxis = firstPersonViewAxis; - - // these cvars are just for hand tweaking before moving a value to the weapon def - idVec3 gunpos( g_gun_x.GetFloat(), g_gun_y.GetFloat(), g_gun_z.GetFloat() ); - - // as the player changes direction, the gun will take a small lag - idVec3 gunOfs = GunAcceleratingOffset(); - origin = viewOrigin + ( gunpos + gunOfs ) * viewAxis; - - // on odd legs, invert some angles - if ( bobCycle & 128 ) { - scale = -xyspeed; - } else { - scale = xyspeed; - } - - // gun angles from bobbing - angles.roll = scale * bobfracsin * 0.005f; - angles.yaw = scale * bobfracsin * 0.01f; - angles.pitch = xyspeed * bobfracsin * 0.005f; - - // gun angles from turning - if ( gameLocal.isMultiplayer ) { - idAngles offset = GunTurningOffset(); - offset *= g_mpWeaponAngleScale.GetFloat(); - angles += offset; - } else { - angles += GunTurningOffset(); - } - - idVec3 gravity = physicsObj.GetGravityNormal(); - - // drop the weapon when landing after a jump / fall - delta = gameLocal.time - landTime; - if ( delta < LAND_DEFLECT_TIME ) { - origin -= gravity * ( landChange*0.25f * delta / LAND_DEFLECT_TIME ); - } else if ( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) { - origin -= gravity * ( landChange*0.25f * (LAND_DEFLECT_TIME + LAND_RETURN_TIME - delta) / LAND_RETURN_TIME ); - } - - // speed sensitive idle drift - scale = xyspeed + 40.0f; - fracsin = scale * sin( MS2SEC( gameLocal.time ) ) * 0.01f; - angles.roll += fracsin; - angles.yaw += fracsin; - angles.pitch += fracsin; - - axis = angles.ToMat3() * viewAxis; -} - -/* -=============== -idPlayer::OffsetThirdPersonView -=============== -*/ -void idPlayer::OffsetThirdPersonView( float angle, float range, float height, bool clip ) { - idVec3 view; - idVec3 focusAngles; - trace_t trace; - idVec3 focusPoint; - float focusDist; - float forwardScale, sideScale; - idVec3 origin; - idAngles angles; - idMat3 axis; - idBounds bounds; - - angles = viewAngles; - GetViewPos( origin, axis ); - - if ( angle ) { - angles.pitch = 0.0f; - } - - if ( angles.pitch > 45.0f ) { - angles.pitch = 45.0f; // don't go too far overhead - } - - focusPoint = origin + angles.ToForward() * THIRD_PERSON_FOCUS_DISTANCE; - focusPoint.z += height; - view = origin; - view.z += 8 + height; - - angles.pitch *= 0.5f; - renderView->viewaxis = angles.ToMat3() * physicsObj.GetGravityAxis(); - - idMath::SinCos( DEG2RAD( angle ), sideScale, forwardScale ); - view -= range * forwardScale * renderView->viewaxis[ 0 ]; - view += range * sideScale * renderView->viewaxis[ 1 ]; - - if ( clip ) { - // trace a ray from the origin to the viewpoint to make sure the view isn't - // in a solid block. Use an 8 by 8 block to prevent the view from near clipping anything - bounds = idBounds( idVec3( -4, -4, -4 ), idVec3( 4, 4, 4 ) ); - gameLocal.clip.TraceBounds( trace, origin, view, bounds, MASK_SOLID, this ); - if ( trace.fraction != 1.0f ) { - view = trace.endpos; - view.z += ( 1.0f - trace.fraction ) * 32.0f; - - // try another trace to this position, because a tunnel may have the ceiling - // close enough that this is poking out - gameLocal.clip.TraceBounds( trace, origin, view, bounds, MASK_SOLID, this ); - view = trace.endpos; - } - } - - // select pitch to look at focus point from vieword - focusPoint -= view; - focusDist = idMath::Sqrt( focusPoint[0] * focusPoint[0] + focusPoint[1] * focusPoint[1] ); - if ( focusDist < 1.0f ) { - focusDist = 1.0f; // should never happen - } - - angles.pitch = - RAD2DEG( atan2( focusPoint.z, focusDist ) ); - angles.yaw -= angle; - - renderView->vieworg = view; - renderView->viewaxis = angles.ToMat3() * physicsObj.GetGravityAxis(); - renderView->viewID = 0; -} - -/* -=============== -idPlayer::GetEyePosition -=============== -*/ -idVec3 idPlayer::GetEyePosition( void ) const { - idVec3 org; - - // use the smoothed origin if spectating another player in multiplayer - if ( gameLocal.isClient && entityNumber != gameLocal.localClientNum ) { - org = smoothedOrigin; - } else { - org = GetPhysics()->GetOrigin(); - } - return org + ( GetPhysics()->GetGravityNormal() * -eyeOffset.z ); -} - -/* -=============== -idPlayer::GetViewPos -=============== -*/ -void idPlayer::GetViewPos( idVec3 &origin, idMat3 &axis ) const { - idAngles angles; - - // if dead, fix the angle and don't add any kick - if ( health <= 0 ) { - angles.yaw = viewAngles.yaw; - angles.roll = 40; - angles.pitch = -15; - axis = angles.ToMat3(); - origin = GetEyePosition(); - } else { - origin = GetEyePosition() + viewBob; - angles = viewAngles + viewBobAngles + playerView.AngleOffset(); - - axis = angles.ToMat3() * physicsObj.GetGravityAxis(); - - // adjust the origin based on the camera nodal distance (eye distance from neck) - origin += physicsObj.GetGravityNormal() * g_viewNodalZ.GetFloat(); - origin += axis[0] * g_viewNodalX.GetFloat() + axis[2] * g_viewNodalZ.GetFloat(); - } -} - -/* -=============== -idPlayer::CalculateFirstPersonView -=============== -*/ -void idPlayer::CalculateFirstPersonView( void ) { - if ( ( pm_modelView.GetInteger() == 1 ) || ( ( pm_modelView.GetInteger() == 2 ) && ( health <= 0 ) ) ) { - // Displays the view from the point of view of the "camera" joint in the player model - - idMat3 axis; - idVec3 origin; - idAngles ang; - - ang = viewBobAngles + playerView.AngleOffset(); - ang.yaw += viewAxis[ 0 ].ToYaw(); - - jointHandle_t joint = animator.GetJointHandle( "camera" ); - animator.GetJointTransform( joint, gameLocal.time, origin, axis ); - firstPersonViewOrigin = ( origin + modelOffset ) * ( viewAxis * physicsObj.GetGravityAxis() ) + physicsObj.GetOrigin() + viewBob; - firstPersonViewAxis = axis * ang.ToMat3() * physicsObj.GetGravityAxis(); - } else { - // offset for local bobbing and kicks - GetViewPos( firstPersonViewOrigin, firstPersonViewAxis ); -#if 0 - // shakefrom sound stuff only happens in first person - firstPersonViewAxis = firstPersonViewAxis * playerView.ShakeAxis(); -#endif - } -} - -/* -================== -idPlayer::GetRenderView - -Returns the renderView that was calculated for this tic -================== -*/ -renderView_t *idPlayer::GetRenderView( void ) { - return renderView; -} - -/* -================== -idPlayer::CalculateRenderView - -create the renderView for the current tic -================== -*/ -void idPlayer::CalculateRenderView( void ) { - int i; - float range; - - if ( !renderView ) { - renderView = new renderView_t; - } - memset( renderView, 0, sizeof( *renderView ) ); - - // copy global shader parms - for( i = 0; i < MAX_GLOBAL_SHADER_PARMS; i++ ) { - renderView->shaderParms[ i ] = gameLocal.globalShaderParms[ i ]; - } - renderView->globalMaterial = gameLocal.GetGlobalMaterial(); - -#ifdef _D3XP - renderView->time = gameLocal.slow.time; -#endif - - // calculate size of 3D view - renderView->x = 0; - renderView->y = 0; - renderView->width = SCREEN_WIDTH; - renderView->height = SCREEN_HEIGHT; - renderView->viewID = 0; - - // check if we should be drawing from a camera's POV - if ( !noclip && (gameLocal.GetCamera() || privateCameraView) ) { - // get origin, axis, and fov - if ( privateCameraView ) { - privateCameraView->GetViewParms( renderView ); - } else { - gameLocal.GetCamera()->GetViewParms( renderView ); - } - } else { - if ( g_stopTime.GetBool() ) { - renderView->vieworg = firstPersonViewOrigin; - renderView->viewaxis = firstPersonViewAxis; - - if ( !pm_thirdPerson.GetBool() ) { - // set the viewID to the clientNum + 1, so we can suppress the right player bodies and - // allow the right player view weapons - renderView->viewID = entityNumber + 1; - } - } else if ( pm_thirdPerson.GetBool() ) { - OffsetThirdPersonView( pm_thirdPersonAngle.GetFloat(), pm_thirdPersonRange.GetFloat(), pm_thirdPersonHeight.GetFloat(), pm_thirdPersonClip.GetBool() ); - } else if ( pm_thirdPersonDeath.GetBool() ) { - range = gameLocal.time < minRespawnTime ? ( gameLocal.time + RAGDOLL_DEATH_TIME - minRespawnTime ) * ( 120.0f / RAGDOLL_DEATH_TIME ) : 120.0f; - OffsetThirdPersonView( 0.0f, 20.0f + range, 0.0f, false ); - } else { - renderView->vieworg = firstPersonViewOrigin; - renderView->viewaxis = firstPersonViewAxis; - - // set the viewID to the clientNum + 1, so we can suppress the right player bodies and - // allow the right player view weapons - renderView->viewID = entityNumber + 1; - } - - // field of view - gameLocal.CalcFov( CalcFov( true ), renderView->fov_x, renderView->fov_y ); - } - - if ( renderView->fov_y == 0 ) { - common->Error( "renderView->fov_y == 0" ); - } - - if ( g_showviewpos.GetBool() ) { - gameLocal.Printf( "%s : %s\n", renderView->vieworg.ToString(), renderView->viewaxis.ToAngles().ToString() ); - } -} - -/* -============= -idPlayer::AddAIKill -============= -*/ -void idPlayer::AddAIKill( void ) { - -#ifndef _D3XP - - int max_souls; - int ammo_souls; - - if ( ( weapon_soulcube < 0 ) || ( inventory.weapons & ( 1 << weapon_soulcube ) ) == 0 ) { - return; - } - - assert( hud ); - - - ammo_souls = idWeapon::GetAmmoNumForName( "ammo_souls" ); - max_souls = inventory.MaxAmmoForAmmoClass( this, "ammo_souls" ); - if ( inventory.ammo[ ammo_souls ] < max_souls ) { - inventory.ammo[ ammo_souls ]++; - if ( inventory.ammo[ ammo_souls ] >= max_souls ) { - hud->HandleNamedEvent( "soulCubeReady" ); - StartSound( "snd_soulcube_ready", SND_CHANNEL_ANY, 0, false, NULL ); - } - } -#endif -} - -/* -============= -idPlayer::SetSoulCubeProjectile -============= -*/ -void idPlayer::SetSoulCubeProjectile( idProjectile *projectile ) { - soulCubeProjectile = projectile; -} - -/* -============= -idPlayer::AddProjectilesFired -============= -*/ -void idPlayer::AddProjectilesFired( int count ) { - numProjectilesFired += count; -} - -/* -============= -idPlayer::AddProjectileHites -============= -*/ -void idPlayer::AddProjectileHits( int count ) { - numProjectileHits += count; -} - -/* -============= -idPlayer::SetLastHitTime -============= -*/ -void idPlayer::SetLastHitTime( int time ) { - idPlayer *aimed = NULL; - - if ( time && lastHitTime != time ) { - lastHitToggle ^= 1; - } - lastHitTime = time; - if ( !time ) { - // level start and inits - return; - } - if ( gameLocal.isMultiplayer && ( time - lastSndHitTime ) > 10 ) { - lastSndHitTime = time; - StartSound( "snd_hit_feedback", SND_CHANNEL_ANY, SSF_PRIVATE_SOUND, false, NULL ); - } - if ( cursor ) { - cursor->HandleNamedEvent( "hitTime" ); - } - if ( hud ) { - if ( MPAim != -1 ) { - if ( gameLocal.entities[ MPAim ] && gameLocal.entities[ MPAim ]->IsType( idPlayer::Type ) ) { - aimed = static_cast< idPlayer * >( gameLocal.entities[ MPAim ] ); - } - assert( aimed ); - // full highlight, no fade till loosing aim - hud->SetStateString( "aim_text", gameLocal.userInfo[ MPAim ].GetString( "ui_name" ) ); - if ( aimed ) { - hud->SetStateFloat( "aim_color", aimed->colorBarIndex ); - } - hud->HandleNamedEvent( "aim_flash" ); - MPAimHighlight = true; - MPAimFadeTime = 0; - } else if ( lastMPAim != -1 ) { - if ( gameLocal.entities[ lastMPAim ] && gameLocal.entities[ lastMPAim ]->IsType( idPlayer::Type ) ) { - aimed = static_cast< idPlayer * >( gameLocal.entities[ lastMPAim ] ); - } - assert( aimed ); - // start fading right away - hud->SetStateString( "aim_text", gameLocal.userInfo[ lastMPAim ].GetString( "ui_name" ) ); - if ( aimed ) { - hud->SetStateFloat( "aim_color", aimed->colorBarIndex ); - } - hud->HandleNamedEvent( "aim_flash" ); - hud->HandleNamedEvent( "aim_fade" ); - MPAimHighlight = false; - MPAimFadeTime = gameLocal.realClientTime; - } - } -} - -/* -============= -idPlayer::SetInfluenceLevel -============= -*/ -void idPlayer::SetInfluenceLevel( int level ) { - if ( level != influenceActive ) { - if ( level ) { - for ( idEntity *ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) { - if ( ent->IsType( idProjectile::Type ) ) { - // remove all projectiles - ent->PostEventMS( &EV_Remove, 0 ); - } - } - if ( weaponEnabled && weapon.GetEntity() ) { - weapon.GetEntity()->EnterCinematic(); - } - } else { - physicsObj.SetLinearVelocity( vec3_origin ); - if ( weaponEnabled && weapon.GetEntity() ) { - weapon.GetEntity()->ExitCinematic(); - } - } - influenceActive = level; - } -} - -/* -============= -idPlayer::SetInfluenceView -============= -*/ -void idPlayer::SetInfluenceView( const char *mtr, const char *skinname, float radius, idEntity *ent ) { - influenceMaterial = NULL; - influenceEntity = NULL; - influenceSkin = NULL; - if ( mtr && *mtr ) { - influenceMaterial = declManager->FindMaterial( mtr ); - } - if ( skinname && *skinname ) { - influenceSkin = declManager->FindSkin( skinname ); - if ( head.GetEntity() ) { - head.GetEntity()->GetRenderEntity()->shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time ); - } - UpdateVisuals(); - } - influenceRadius = radius; - if ( radius > 0.0f ) { - influenceEntity = ent; - } -} - -/* -============= -idPlayer::SetInfluenceFov -============= -*/ -void idPlayer::SetInfluenceFov( float fov ) { - influenceFov = fov; -} - -/* -================ -idPlayer::OnLadder -================ -*/ -bool idPlayer::OnLadder( void ) const { - return physicsObj.OnLadder(); -} - -/* -================== -idPlayer::Event_GetButtons -================== -*/ -void idPlayer::Event_GetButtons( void ) { - idThread::ReturnInt( usercmd.buttons ); -} - -/* -================== -idPlayer::Event_GetMove -================== -*/ -void idPlayer::Event_GetMove( void ) { - idVec3 move( usercmd.forwardmove, usercmd.rightmove, usercmd.upmove ); - idThread::ReturnVector( move ); -} - -/* -================ -idPlayer::Event_GetViewAngles -================ -*/ -void idPlayer::Event_GetViewAngles( void ) { - idThread::ReturnVector( idVec3( viewAngles[0], viewAngles[1], viewAngles[2] ) ); -} - -/* -================== -idPlayer::Event_StopFxFov -================== -*/ -void idPlayer::Event_StopFxFov( void ) { - fxFov = false; -} - -/* -================== -idPlayer::StartFxFov -================== -*/ -void idPlayer::StartFxFov( float duration ) { - fxFov = true; - PostEventSec( &EV_Player_StopFxFov, duration ); -} - -/* -================== -idPlayer::Event_EnableWeapon -================== -*/ -void idPlayer::Event_EnableWeapon( void ) { - hiddenWeapon = gameLocal.world->spawnArgs.GetBool( "no_Weapons" ); - weaponEnabled = true; - if ( weapon.GetEntity() ) { - weapon.GetEntity()->ExitCinematic(); - } -} - -/* -================== -idPlayer::Event_DisableWeapon -================== -*/ -void idPlayer::Event_DisableWeapon( void ) { - hiddenWeapon = gameLocal.world->spawnArgs.GetBool( "no_Weapons" ); - weaponEnabled = false; - if ( weapon.GetEntity() ) { - weapon.GetEntity()->EnterCinematic(); - } -} - -#ifdef _D3XP -/* -================== -idPlayer::Event_GiveInventoryItem -================== -*/ -void idPlayer::Event_GiveInventoryItem( const char* name ) { - GiveInventoryItem(name); -} - -/* -================== -idPlayer::Event_RemoveInventoryItem -================== -*/ -void idPlayer::Event_RemoveInventoryItem( const char* name ) { - RemoveInventoryItem(name); -} - -/* -================== -idPlayer::Event_GetIdealWeapon -================== -*/ -void idPlayer::Event_GetIdealWeapon( void ) { - const char *weapon; - - if ( idealWeapon >= 0 ) { - weapon = spawnArgs.GetString( va( "def_weapon%d", idealWeapon ) ); - idThread::ReturnString( weapon ); - } else { - idThread::ReturnString( "" ); - } -} - -/* -================== -idPlayer::Event_SetPowerupTime -================== -*/ -void idPlayer::Event_SetPowerupTime( int powerup, int time ) { - if ( time > 0 ) { - GivePowerUp( powerup, time ); - } else { - ClearPowerup( powerup ); - } -} - -/* -================== -idPlayer::Event_IsPowerupActive -================== -*/ -void idPlayer::Event_IsPowerupActive( int powerup ) { - idThread::ReturnInt(this->PowerUpActive(powerup) ? 1 : 0); -} - -/* -================== -idPlayer::Event_StartWarp -================== -*/ -void idPlayer::Event_StartWarp() { - playerView.AddWarp( idVec3( 0, 0, 0 ), SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, 100, 1000 ); -} - -/* -================== -idPlayer::Event_StopHelltime -================== -*/ -void idPlayer::Event_StopHelltime( int mode ) { - if ( mode == 1 ) { - StopHelltime( true ); - } - else { - StopHelltime( false ); - } -} - -/* -================== -idPlayer::Event_WeaponAvailable -================== -*/ -void idPlayer::Event_WeaponAvailable( const char* name ) { - - idThread::ReturnInt( WeaponAvailable(name) ? 1 : 0 ); -} - -bool idPlayer::WeaponAvailable( const char* name ) { - for( int i = 0; i < MAX_WEAPONS; i++ ) { - if ( inventory.weapons & ( 1 << i ) ) { - const char *weap = spawnArgs.GetString( va( "def_weapon%d", i ) ); - if ( !idStr::Cmp( weap, name ) ) { - return true; - } - } - } - return false; -} - -#endif - -/* -================== -idPlayer::Event_GetCurrentWeapon -================== -*/ -void idPlayer::Event_GetCurrentWeapon( void ) { - const char *weapon; - - if ( currentWeapon >= 0 ) { - weapon = spawnArgs.GetString( va( "def_weapon%d", currentWeapon ) ); - idThread::ReturnString( weapon ); - } else { - idThread::ReturnString( "" ); - } -} - -/* -================== -idPlayer::Event_GetPreviousWeapon -================== -*/ -void idPlayer::Event_GetPreviousWeapon( void ) { - const char *weapon; - - if ( previousWeapon >= 0 ) { - int pw = ( gameLocal.world->spawnArgs.GetBool( "no_Weapons" ) ) ? 0 : previousWeapon; - weapon = spawnArgs.GetString( va( "def_weapon%d", pw) ); - idThread::ReturnString( weapon ); - } else { - idThread::ReturnString( spawnArgs.GetString( "def_weapon0" ) ); - } -} - -/* -================== -idPlayer::Event_SelectWeapon -================== -*/ -void idPlayer::Event_SelectWeapon( const char *weaponName ) { - int i; - int weaponNum; - - if ( gameLocal.isClient ) { - gameLocal.Warning( "Cannot switch weapons from script in multiplayer" ); - return; - } - - if ( hiddenWeapon && gameLocal.world->spawnArgs.GetBool( "no_Weapons" ) ) { - idealWeapon = weapon_fists; - weapon.GetEntity()->HideWeapon(); - return; - } - - weaponNum = -1; - for( i = 0; i < MAX_WEAPONS; i++ ) { - if ( inventory.weapons & ( 1 << i ) ) { - const char *weap = spawnArgs.GetString( va( "def_weapon%d", i ) ); - if ( !idStr::Cmp( weap, weaponName ) ) { - weaponNum = i; - break; - } - } - } - - if ( weaponNum < 0 ) { - gameLocal.Warning( "%s is not carrying weapon '%s'", name.c_str(), weaponName ); - return; - } - - hiddenWeapon = false; - idealWeapon = weaponNum; - - UpdateHudWeapon(); -} - -/* -================== -idPlayer::Event_GetWeaponEntity -================== -*/ -void idPlayer::Event_GetWeaponEntity( void ) { - idThread::ReturnEntity( weapon.GetEntity() ); -} - -/* -================== -idPlayer::Event_OpenPDA -================== -*/ -void idPlayer::Event_OpenPDA( void ) { - if ( !gameLocal.isMultiplayer ) { - TogglePDA(); - } -} - -/* -================== -idPlayer::Event_InPDA -================== -*/ -void idPlayer::Event_InPDA( void ) { - idThread::ReturnInt( objectiveSystemOpen ); -} - -/* -================== -idPlayer::TeleportDeath -================== -*/ -void idPlayer::TeleportDeath( int killer ) { - teleportKiller = killer; -} - -/* -================== -idPlayer::Event_ExitTeleporter -================== -*/ -void idPlayer::Event_ExitTeleporter( void ) { - idEntity *exitEnt; - float pushVel; - - // verify and setup - exitEnt = teleportEntity.GetEntity(); - if ( !exitEnt ) { - common->DPrintf( "Event_ExitTeleporter player %d while not being teleported\n", entityNumber ); - return; - } - - pushVel = exitEnt->spawnArgs.GetFloat( "push", "300" ); - - if ( gameLocal.isServer ) { - ServerSendEvent( EVENT_EXIT_TELEPORTER, NULL, false, -1 ); - } - - SetPrivateCameraView( NULL ); - // setup origin and push according to the exit target - SetOrigin( exitEnt->GetPhysics()->GetOrigin() + idVec3( 0, 0, CM_CLIP_EPSILON ) ); - SetViewAngles( exitEnt->GetPhysics()->GetAxis().ToAngles() ); - physicsObj.SetLinearVelocity( exitEnt->GetPhysics()->GetAxis()[ 0 ] * pushVel ); - physicsObj.ClearPushedVelocity(); - // teleport fx - playerView.Flash( colorWhite, 120 ); - - // clear the ik heights so model doesn't appear in the wrong place - walkIK.EnableAll(); - - UpdateVisuals(); - - StartSound( "snd_teleport_exit", SND_CHANNEL_ANY, 0, false, NULL ); - - if ( teleportKiller != -1 ) { - // we got killed while being teleported - Damage( gameLocal.entities[ teleportKiller ], gameLocal.entities[ teleportKiller ], vec3_origin, "damage_telefrag", 1.0f, INVALID_JOINT ); - teleportKiller = -1; - } else { - // kill anything that would have waited at teleport exit - gameLocal.KillBox( this ); - } - teleportEntity = NULL; -} - -/* -================ -idPlayer::ClientPredictionThink -================ -*/ -void idPlayer::ClientPredictionThink( void ) { - renderEntity_t *headRenderEnt; - - oldFlags = usercmd.flags; - oldButtons = usercmd.buttons; - - usercmd = gameLocal.usercmds[ entityNumber ]; - - if ( entityNumber != gameLocal.localClientNum ) { - // ignore attack button of other clients. that's no good for predictions - usercmd.buttons &= ~BUTTON_ATTACK; - } - - buttonMask &= usercmd.buttons; - usercmd.buttons &= ~buttonMask; - -#ifdef _D3XP - if ( mountedObject ) { - usercmd.forwardmove = 0; - usercmd.rightmove = 0; - usercmd.upmove = 0; - } -#endif - - if ( objectiveSystemOpen ) { - usercmd.forwardmove = 0; - usercmd.rightmove = 0; - usercmd.upmove = 0; - } - - // clear the ik before we do anything else so the skeleton doesn't get updated twice - walkIK.ClearJointMods(); - - if ( gameLocal.isNewFrame ) { - if ( ( usercmd.flags & UCF_IMPULSE_SEQUENCE ) != ( oldFlags & UCF_IMPULSE_SEQUENCE ) ) { - PerformImpulse( usercmd.impulse ); - } - } - - scoreBoardOpen = ( ( usercmd.buttons & BUTTON_SCORES ) != 0 || forceScoreBoard ); - - AdjustSpeed(); - - UpdateViewAngles(); - - // update the smoothed view angles - if ( gameLocal.framenum >= smoothedFrame && entityNumber != gameLocal.localClientNum ) { - idAngles anglesDiff = viewAngles - smoothedAngles; - anglesDiff.Normalize180(); - if ( idMath::Fabs( anglesDiff.yaw ) < 90.0f && idMath::Fabs( anglesDiff.pitch ) < 90.0f ) { - // smoothen by pushing back to the previous angles - viewAngles -= gameLocal.clientSmoothing * anglesDiff; - viewAngles.Normalize180(); - } - smoothedAngles = viewAngles; - } - smoothedOriginUpdated = false; - - if ( !af.IsActive() ) { - AdjustBodyAngles(); - } - - if ( !isLagged ) { - // don't allow client to move when lagged - Move(); - } - - // update GUIs, Items, and character interactions - UpdateFocus(); - - // service animations - if ( !spectating && !af.IsActive() ) { - UpdateConditions(); - UpdateAnimState(); - CheckBlink(); - } - - // clear out our pain flag so we can tell if we recieve any damage between now and the next time we think - AI_PAIN = false; - - // calculate the exact bobbed view position, which is used to - // position the view weapon, among other things - CalculateFirstPersonView(); - - // this may use firstPersonView, or a thirdPerson / camera view - CalculateRenderView(); - - if ( !gameLocal.inCinematic && weapon.GetEntity() && ( health > 0 ) && !( gameLocal.isMultiplayer && spectating ) ) { - UpdateWeapon(); - } - - UpdateHud(); - - if ( gameLocal.isNewFrame ) { - UpdatePowerUps(); - } - - UpdateDeathSkin( false ); - - if ( head.GetEntity() ) { - headRenderEnt = head.GetEntity()->GetRenderEntity(); - } else { - headRenderEnt = NULL; - } - - if ( headRenderEnt ) { - if ( influenceSkin ) { - headRenderEnt->customSkin = influenceSkin; - } else { - headRenderEnt->customSkin = NULL; - } - } - - if ( gameLocal.isMultiplayer || g_showPlayerShadow.GetBool() ) { - renderEntity.suppressShadowInViewID = 0; - if ( headRenderEnt ) { - headRenderEnt->suppressShadowInViewID = 0; - } - } else { - renderEntity.suppressShadowInViewID = entityNumber+1; - if ( headRenderEnt ) { - headRenderEnt->suppressShadowInViewID = entityNumber+1; - } - } - // never cast shadows from our first-person muzzle flashes - renderEntity.suppressShadowInLightID = LIGHTID_VIEW_MUZZLE_FLASH + entityNumber; - if ( headRenderEnt ) { - headRenderEnt->suppressShadowInLightID = LIGHTID_VIEW_MUZZLE_FLASH + entityNumber; - } - - if ( !gameLocal.inCinematic ) { - UpdateAnimation(); - } - -#ifdef _D3XP - if ( enviroSuitLight.IsValid() ) { - idAngles lightAng = firstPersonViewAxis.ToAngles(); - idVec3 lightOrg = firstPersonViewOrigin; - const idDict *lightDef = gameLocal.FindEntityDefDict( "envirosuit_light", false ); - - idVec3 enviroOffset = lightDef->GetVector( "enviro_offset" ); - idVec3 enviroAngleOffset = lightDef->GetVector( "enviro_angle_offset" ); - - lightOrg += (enviroOffset.x * firstPersonViewAxis[0]); - lightOrg += (enviroOffset.y * firstPersonViewAxis[1]); - lightOrg += (enviroOffset.z * firstPersonViewAxis[2]); - lightAng.pitch += enviroAngleOffset.x; - lightAng.yaw += enviroAngleOffset.y; - lightAng.roll += enviroAngleOffset.z; - - enviroSuitLight.GetEntity()->GetPhysics()->SetOrigin( lightOrg ); - enviroSuitLight.GetEntity()->GetPhysics()->SetAxis( lightAng.ToMat3() ); - enviroSuitLight.GetEntity()->UpdateVisuals(); - enviroSuitLight.GetEntity()->Present(); - } -#endif - - if ( gameLocal.isMultiplayer ) { - DrawPlayerIcons(); - } - - Present(); - - UpdateDamageEffects(); - - LinkCombat(); - - if ( gameLocal.isNewFrame && entityNumber == gameLocal.localClientNum ) { - playerView.CalculateShake(); - } - -#ifdef _D3XP - // determine if portal sky is in pvs - pvsHandle_t clientPVS = gameLocal.pvs.SetupCurrentPVS( GetPVSAreas(), GetNumPVSAreas() ); - gameLocal.portalSkyActive = gameLocal.pvs.CheckAreasForPortalSky( clientPVS, GetPhysics()->GetOrigin() ); - gameLocal.pvs.FreeCurrentPVS( clientPVS ); -#endif -} - -/* -================ -idPlayer::GetPhysicsToVisualTransform -================ -*/ -bool idPlayer::GetPhysicsToVisualTransform( idVec3 &origin, idMat3 &axis ) { - if ( af.IsActive() ) { - af.GetPhysicsToVisualTransform( origin, axis ); - return true; - } - - // smoothen the rendered origin and angles of other clients - // smooth self origin if snapshots are telling us prediction is off - if ( gameLocal.isClient && gameLocal.framenum >= smoothedFrame && ( entityNumber != gameLocal.localClientNum || selfSmooth ) ) { - // render origin and axis - idMat3 renderAxis = viewAxis * GetPhysics()->GetAxis(); - idVec3 renderOrigin = GetPhysics()->GetOrigin() + modelOffset * renderAxis; - - // update the smoothed origin - if ( !smoothedOriginUpdated ) { - idVec2 originDiff = renderOrigin.ToVec2() - smoothedOrigin.ToVec2(); - if ( originDiff.LengthSqr() < Square( 100.0f ) ) { - // smoothen by pushing back to the previous position - if ( selfSmooth ) { - assert( entityNumber == gameLocal.localClientNum ); - renderOrigin.ToVec2() -= net_clientSelfSmoothing.GetFloat() * originDiff; - } else { - renderOrigin.ToVec2() -= gameLocal.clientSmoothing * originDiff; - } - } - smoothedOrigin = renderOrigin; - - smoothedFrame = gameLocal.framenum; - smoothedOriginUpdated = true; - } - - axis = idAngles( 0.0f, smoothedAngles.yaw, 0.0f ).ToMat3(); - origin = ( smoothedOrigin - GetPhysics()->GetOrigin() ) * axis.Transpose(); - - } else { - - axis = viewAxis; - origin = modelOffset; - } - return true; -} - -/* -================ -idPlayer::GetPhysicsToSoundTransform -================ -*/ -bool idPlayer::GetPhysicsToSoundTransform( idVec3 &origin, idMat3 &axis ) { - idCamera *camera; - - if ( privateCameraView ) { - camera = privateCameraView; - } else { - camera = gameLocal.GetCamera(); - } - - if ( camera ) { - renderView_t view; - - memset( &view, 0, sizeof( view ) ); - camera->GetViewParms( &view ); - origin = view.vieworg; - axis = view.viewaxis; - return true; - } else { - return idActor::GetPhysicsToSoundTransform( origin, axis ); - } -} - -/* -================ -idPlayer::WriteToSnapshot -================ -*/ -void idPlayer::WriteToSnapshot( idBitMsgDelta &msg ) const { - physicsObj.WriteToSnapshot( msg ); - WriteBindToSnapshot( msg ); - msg.WriteDeltaFloat( 0.0f, deltaViewAngles[0] ); - msg.WriteDeltaFloat( 0.0f, deltaViewAngles[1] ); - msg.WriteDeltaFloat( 0.0f, deltaViewAngles[2] ); - msg.WriteShort( health ); - msg.WriteBits( gameLocal.ServerRemapDecl( -1, DECL_ENTITYDEF, lastDamageDef ), gameLocal.entityDefBits ); - msg.WriteDir( lastDamageDir, 9 ); - msg.WriteShort( lastDamageLocation ); - msg.WriteBits( idealWeapon, idMath::BitsForInteger( MAX_WEAPONS ) ); - msg.WriteBits( inventory.weapons, MAX_WEAPONS ); - msg.WriteBits( weapon.GetSpawnId(), 32 ); - msg.WriteBits( spectator, idMath::BitsForInteger( MAX_CLIENTS ) ); - msg.WriteBits( lastHitToggle, 1 ); - msg.WriteBits( weaponGone, 1 ); - msg.WriteBits( isLagged, 1 ); - msg.WriteBits( isChatting, 1 ); -#ifdef CTF - /* Needed for the scoreboard */ - msg.WriteBits( carryingFlag, 1 ); -#endif -#ifdef _D3XP - msg.WriteBits( enviroSuitLight.GetSpawnId(), 32 ); -#endif -} - -/* -================ -idPlayer::ReadFromSnapshot -================ -*/ -void idPlayer::ReadFromSnapshot( const idBitMsgDelta &msg ) { - int i, oldHealth, newIdealWeapon, weaponSpawnId; - bool newHitToggle, stateHitch; - - if ( snapshotSequence - lastSnapshotSequence > 1 ) { - stateHitch = true; - } else { - stateHitch = false; - } - lastSnapshotSequence = snapshotSequence; - - oldHealth = health; - - physicsObj.ReadFromSnapshot( msg ); - ReadBindFromSnapshot( msg ); - deltaViewAngles[0] = msg.ReadDeltaFloat( 0.0f ); - deltaViewAngles[1] = msg.ReadDeltaFloat( 0.0f ); - deltaViewAngles[2] = msg.ReadDeltaFloat( 0.0f ); - health = msg.ReadShort(); - lastDamageDef = gameLocal.ClientRemapDecl( DECL_ENTITYDEF, msg.ReadBits( gameLocal.entityDefBits ) ); - lastDamageDir = msg.ReadDir( 9 ); - lastDamageLocation = msg.ReadShort(); - newIdealWeapon = msg.ReadBits( idMath::BitsForInteger( MAX_WEAPONS ) ); - inventory.weapons = msg.ReadBits( MAX_WEAPONS ); - weaponSpawnId = msg.ReadBits( 32 ); - spectator = msg.ReadBits( idMath::BitsForInteger( MAX_CLIENTS ) ); - newHitToggle = msg.ReadBits( 1 ) != 0; - weaponGone = msg.ReadBits( 1 ) != 0; - isLagged = msg.ReadBits( 1 ) != 0; - isChatting = msg.ReadBits( 1 ) != 0; -#ifdef CTF - carryingFlag = msg.ReadBits( 1 ) != 0; -#endif -#ifdef _D3XP - int enviroSpawnId; - enviroSpawnId = msg.ReadBits( 32 ); - enviroSuitLight.SetSpawnId( enviroSpawnId ); -#endif - - // no msg reading below this - - if ( weapon.SetSpawnId( weaponSpawnId ) ) { - if ( weapon.GetEntity() ) { - // maintain ownership locally - weapon.GetEntity()->SetOwner( this ); - } - currentWeapon = -1; - } - // if not a local client assume the client has all ammo types - if ( entityNumber != gameLocal.localClientNum ) { - for( i = 0; i < AMMO_NUMTYPES; i++ ) { - inventory.ammo[ i ] = 999; - } - } - - if ( oldHealth > 0 && health <= 0 ) { - if ( stateHitch ) { - // so we just hide and don't show a death skin - UpdateDeathSkin( true ); - } - // die - AI_DEAD = true; - ClearPowerUps(); - SetAnimState( ANIMCHANNEL_LEGS, "Legs_Death", 4 ); - SetAnimState( ANIMCHANNEL_TORSO, "Torso_Death", 4 ); - SetWaitState( "" ); - animator.ClearAllJoints(); - if ( entityNumber == gameLocal.localClientNum ) { - playerView.Fade( colorBlack, 12000 ); - } - StartRagdoll(); - physicsObj.SetMovementType( PM_DEAD ); - if ( !stateHitch ) { - StartSound( "snd_death", SND_CHANNEL_VOICE, 0, false, NULL ); - } - if ( weapon.GetEntity() ) { - weapon.GetEntity()->OwnerDied(); - } - } else if ( oldHealth <= 0 && health > 0 ) { - // respawn - Init(); - StopRagdoll(); - SetPhysics( &physicsObj ); - physicsObj.EnableClip(); - SetCombatContents( true ); - } else if ( health < oldHealth && health > 0 ) { - if ( stateHitch ) { - lastDmgTime = gameLocal.time; - } else { - // damage feedback - const idDeclEntityDef *def = static_cast( declManager->DeclByIndex( DECL_ENTITYDEF, lastDamageDef, false ) ); - if ( def ) { - playerView.DamageImpulse( lastDamageDir * viewAxis.Transpose(), &def->dict ); - AI_PAIN = Pain( NULL, NULL, oldHealth - health, lastDamageDir, lastDamageLocation ); - lastDmgTime = gameLocal.time; - } else { - common->Warning( "NET: no damage def for damage feedback '%d'\n", lastDamageDef ); - } - } - } else if ( health > oldHealth && PowerUpActive( MEGAHEALTH ) && !stateHitch ) { - // just pulse, for any health raise - healthPulse = true; - } - -#ifdef _D3XP - // If the player is alive, restore proper physics object - if ( health > 0 && IsActiveAF() ) { - StopRagdoll(); - SetPhysics( &physicsObj ); - physicsObj.EnableClip(); - SetCombatContents( true ); - } -#endif - - if ( idealWeapon != newIdealWeapon ) { - if ( stateHitch ) { - weaponCatchup = true; - } - idealWeapon = newIdealWeapon; - UpdateHudWeapon(); - } - - if ( lastHitToggle != newHitToggle ) { - SetLastHitTime( gameLocal.realClientTime ); - } - - if ( msg.HasChanged() ) { - UpdateVisuals(); - } -} - -/* -================ -idPlayer::WritePlayerStateToSnapshot -================ -*/ -void idPlayer::WritePlayerStateToSnapshot( idBitMsgDelta &msg ) const { - int i; - - msg.WriteByte( bobCycle ); - msg.WriteInt( stepUpTime ); - msg.WriteFloat( stepUpDelta ); -#ifdef _D3XP - msg.WriteInt( inventory.weapons ); -#else - msg.WriteShort( inventory.weapons ); -#endif - msg.WriteByte( inventory.armor ); - - for( i = 0; i < AMMO_NUMTYPES; i++ ) { - msg.WriteBits( inventory.ammo[i], ASYNC_PLAYER_INV_AMMO_BITS ); - } - for( i = 0; i < MAX_WEAPONS; i++ ) { - msg.WriteBits( inventory.clip[i], ASYNC_PLAYER_INV_CLIP_BITS ); - } -} - -/* -================ -idPlayer::ReadPlayerStateFromSnapshot -================ -*/ -void idPlayer::ReadPlayerStateFromSnapshot( const idBitMsgDelta &msg ) { - int i, ammo; - - bobCycle = msg.ReadByte(); - stepUpTime = msg.ReadInt(); - stepUpDelta = msg.ReadFloat(); -#ifdef _D3XP - inventory.weapons = msg.ReadInt(); -#else - inventory.weapons = msg.ReadShort(); -#endif - inventory.armor = msg.ReadByte(); - - for( i = 0; i < AMMO_NUMTYPES; i++ ) { - ammo = msg.ReadBits( ASYNC_PLAYER_INV_AMMO_BITS ); - if ( gameLocal.time >= inventory.ammoPredictTime ) { - inventory.ammo[ i ] = ammo; - } - } - for( i = 0; i < MAX_WEAPONS; i++ ) { - inventory.clip[i] = msg.ReadBits( ASYNC_PLAYER_INV_CLIP_BITS ); - } -} - -/* -================ -idPlayer::ServerReceiveEvent -================ -*/ -bool idPlayer::ServerReceiveEvent( int event, int time, const idBitMsg &msg ) { - - if ( idEntity::ServerReceiveEvent( event, time, msg ) ) { - return true; - } - - // client->server events - switch( event ) { - case EVENT_IMPULSE: { - PerformImpulse( msg.ReadBits( 6 ) ); - return true; - } - default: { - return false; - } - } -} - -/* -================ -idPlayer::ClientReceiveEvent -================ -*/ -bool idPlayer::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) { - int powerup; - bool start; - - switch ( event ) { - case EVENT_EXIT_TELEPORTER: - Event_ExitTeleporter(); - return true; - case EVENT_ABORT_TELEPORTER: - SetPrivateCameraView( NULL ); - return true; - case EVENT_POWERUP: { - powerup = msg.ReadShort(); - start = msg.ReadBits( 1 ) != 0; - if ( start ) { - GivePowerUp( powerup, 0 ); - } else { - ClearPowerup( powerup ); - } - return true; - } -#ifdef _D3XP - case EVENT_PICKUPNAME: { - char buf[MAX_EVENT_PARAM_SIZE]; - msg.ReadString(buf, MAX_EVENT_PARAM_SIZE); - inventory.AddPickupName(buf, "", this); //_D3XP - return true; - } -#endif - case EVENT_SPECTATE: { - bool spectate = ( msg.ReadBits( 1 ) != 0 ); - Spectate( spectate ); - return true; - } - case EVENT_ADD_DAMAGE_EFFECT: { - if ( spectating ) { - // if we're spectating, ignore - // happens if the event and the spectate change are written on the server during the same frame (fraglimit) - return true; - } - break; - } - default: - break; - } - - return idActor::ClientReceiveEvent( event, time, msg ); -} - -/* -================ -idPlayer::Hide -================ -*/ -void idPlayer::Hide( void ) { - idWeapon *weap; - - idActor::Hide(); - weap = weapon.GetEntity(); - if ( weap ) { - weap->HideWorldModel(); - } -} - -/* -================ -idPlayer::Show -================ -*/ -void idPlayer::Show( void ) { - idWeapon *weap; - - idActor::Show(); - weap = weapon.GetEntity(); - if ( weap ) { - weap->ShowWorldModel(); - } -} - -/* -=============== -idPlayer::StartAudioLog -=============== -*/ -void idPlayer::StartAudioLog( void ) { - if ( hud ) { - hud->HandleNamedEvent( "audioLogUp" ); - } -} - -/* -=============== -idPlayer::StopAudioLog -=============== -*/ -void idPlayer::StopAudioLog( void ) { - if ( hud ) { - hud->HandleNamedEvent( "audioLogDown" ); - } -} - -/* -=============== -idPlayer::ShowTip -=============== -*/ -void idPlayer::ShowTip( const char *title, const char *tip, bool autoHide ) { - if ( tipUp ) { - return; - } - hud->SetStateString( "tip", tip ); - hud->SetStateString( "tiptitle", title ); - hud->HandleNamedEvent( "tipWindowUp" ); - if ( autoHide ) { - PostEventSec( &EV_Player_HideTip, 5.0f ); - } - tipUp = true; -} - -/* -=============== -idPlayer::HideTip -=============== -*/ -void idPlayer::HideTip( void ) { - hud->HandleNamedEvent( "tipWindowDown" ); - tipUp = false; -} - -/* -=============== -idPlayer::Event_HideTip -=============== -*/ -void idPlayer::Event_HideTip( void ) { - HideTip(); -} - -/* -=============== -idPlayer::ShowObjective -=============== -*/ -void idPlayer::ShowObjective( const char *obj ) { - hud->HandleNamedEvent( obj ); - objectiveUp = true; -} - -/* -=============== -idPlayer::HideObjective -=============== -*/ -void idPlayer::HideObjective( void ) { - hud->HandleNamedEvent( "closeObjective" ); - objectiveUp = false; -} - -/* -=============== -idPlayer::Event_StopAudioLog -=============== -*/ -void idPlayer::Event_StopAudioLog( void ) { - StopAudioLog(); -} - -/* -=============== -idPlayer::SetSpectateOrigin -=============== -*/ -void idPlayer::SetSpectateOrigin( void ) { - idVec3 neworig; - - neworig = GetPhysics()->GetOrigin(); - neworig[ 2 ] += EyeHeight(); - neworig[ 2 ] += 25; - SetOrigin( neworig ); -} - -/* -=============== -idPlayer::RemoveWeapon -=============== -*/ -void idPlayer::RemoveWeapon( const char *weap ) { - if ( weap && *weap ) { - inventory.Drop( spawnArgs, spawnArgs.GetString( weap ), -1 ); - } -} - -/* -=============== -idPlayer::CanShowWeaponViewmodel -=============== -*/ -bool idPlayer::CanShowWeaponViewmodel( void ) const { - return showWeaponViewModel; -} - -/* -=============== -idPlayer::SetLevelTrigger -=============== -*/ -void idPlayer::SetLevelTrigger( const char *levelName, const char *triggerName ) { - if ( levelName && *levelName && triggerName && *triggerName ) { - idLevelTriggerInfo lti; - lti.levelName = levelName; - lti.triggerName = triggerName; - inventory.levelTriggers.Append( lti ); - } -} - -/* -=============== -idPlayer::Event_LevelTrigger -=============== -*/ -void idPlayer::Event_LevelTrigger( void ) { - idStr mapName = gameLocal.GetMapName(); - mapName.StripPath(); - mapName.StripFileExtension(); - for ( int i = inventory.levelTriggers.Num() - 1; i >= 0; i-- ) { - if ( idStr::Icmp( mapName, inventory.levelTriggers[i].levelName) == 0 ){ - idEntity *ent = gameLocal.FindEntity( inventory.levelTriggers[i].triggerName ); - if ( ent ) { - ent->PostEventMS( &EV_Activate, 1, this ); - } - } - } -} - -/* -=============== -idPlayer::Event_Gibbed -=============== -*/ -void idPlayer::Event_Gibbed( void ) { - // do nothing -} - -/* -=============== -idPlayer::UpdatePlayerIcons -=============== -*/ -void idPlayer::UpdatePlayerIcons( void ) { - int time = networkSystem->ServerGetClientTimeSinceLastPacket( entityNumber ); - if ( time > cvarSystem->GetCVarInteger( "net_clientMaxPrediction" ) ) { - isLagged = true; - } else { - isLagged = false; - } - // TODO: chatting, PDA, etc? -} - -/* -=============== -idPlayer::DrawPlayerIcons -=============== -*/ -void idPlayer::DrawPlayerIcons( void ) { - if ( !NeedsIcon() ) { - playerIcon.FreeIcon(); - return; - } - -#ifdef CTF - // Never draw icons for hidden players. - if ( this->IsHidden() ) - return; -#endif - - playerIcon.Draw( this, headJoint ); -} - -/* -=============== -idPlayer::HidePlayerIcons -=============== -*/ -void idPlayer::HidePlayerIcons( void ) { - playerIcon.FreeIcon(); -} - -/* -=============== -idPlayer::NeedsIcon -============== -*/ -bool idPlayer::NeedsIcon( void ) { - // local clients don't render their own icons... they're only info for other clients -#ifdef CTF - // always draw icons in CTF games - return entityNumber != gameLocal.localClientNum && ( ( g_CTFArrows.GetBool() && gameLocal.mpGame.IsGametypeFlagBased() && !IsHidden() && !AI_DEAD ) || ( isLagged || isChatting ) ); -#else - return entityNumber != gameLocal.localClientNum && ( isLagged || isChatting ); -#endif -} - -#ifdef CTF -/* -=============== -idPlayer::DropFlag() -============== -*/ -void idPlayer::DropFlag( void ) { - if ( !carryingFlag || !gameLocal.isMultiplayer || !gameLocal.mpGame.IsGametypeFlagBased() ) /* CTF */ - return; - - idEntity * entity = gameLocal.mpGame.GetTeamFlag( 1 - this->latchedTeam ); - if ( entity ) { - idItemTeam * item = static_cast(entity); - - if ( item->carried && !item->dropped ) { - item->Drop( health <= 0 ); - carryingFlag = false; - } - } - -} - -void idPlayer::ReturnFlag() { - - if ( !carryingFlag || !gameLocal.isMultiplayer || !gameLocal.mpGame.IsGametypeFlagBased() ) /* CTF */ - return; - - idEntity * entity = gameLocal.mpGame.GetTeamFlag( 1 - this->latchedTeam ); - if ( entity ) { - idItemTeam * item = static_cast(entity); - - if ( item->carried && !item->dropped ) { - item->Return(); - carryingFlag = false; - } - } -} - -void idPlayer::FreeModelDef( void ) { - idAFEntity_Base::FreeModelDef(); - if ( gameLocal.isMultiplayer && gameLocal.mpGame.IsGametypeFlagBased() ) - playerIcon.FreeIcon(); -} - -#endif diff --git a/d3xp/Player.h b/d3xp/Player.h deleted file mode 100644 index aadf8550..00000000 --- a/d3xp/Player.h +++ /dev/null @@ -1,852 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __GAME_PLAYER_H__ -#define __GAME_PLAYER_H__ - -#include "idlib/math/Interpolate.h" - -#include "physics/Physics_Player.h" -#include "Item.h" -#include "Actor.h" -#include "Weapon.h" -#include "Projectile.h" -#include "PlayerIcon.h" -#include "GameEdit.h" - -class idAI; -class idFuncMountedObject; - -/* -=============================================================================== - - Player entity. - -=============================================================================== -*/ - -extern const idEventDef EV_Player_GetButtons; -extern const idEventDef EV_Player_GetMove; -extern const idEventDef EV_Player_GetViewAngles; -extern const idEventDef EV_Player_EnableWeapon; -extern const idEventDef EV_Player_DisableWeapon; -extern const idEventDef EV_Player_ExitTeleporter; -extern const idEventDef EV_Player_SelectWeapon; -extern const idEventDef EV_SpectatorTouch; - -const float THIRD_PERSON_FOCUS_DISTANCE = 512.0f; -const int LAND_DEFLECT_TIME = 150; -const int LAND_RETURN_TIME = 300; -const int FOCUS_TIME = 300; -const int FOCUS_GUI_TIME = 500; - -#ifdef _D3XP -const int MAX_WEAPONS = 32; -#else -const int MAX_WEAPONS = 16; -#endif - -const int DEAD_HEARTRATE = 0; // fall to as you die -const int LOWHEALTH_HEARTRATE_ADJ = 20; // -const int DYING_HEARTRATE = 30; // used for volumen calc when dying/dead -const int BASE_HEARTRATE = 70; // default -const int ZEROSTAMINA_HEARTRATE = 115; // no stamina -const int MAX_HEARTRATE = 130; // maximum -const int ZERO_VOLUME = -40; // volume at zero -const int DMG_VOLUME = 5; // volume when taking damage -const int DEATH_VOLUME = 15; // volume at death - -const int SAVING_THROW_TIME = 5000; // maximum one "saving throw" every five seconds - -extern const int ASYNC_PLAYER_INV_AMMO_BITS; -extern const int ASYNC_PLAYER_INV_CLIP_BITS; - -struct idItemInfo { - idStr name; - idStr icon; -}; - -struct idObjectiveInfo { - idStr title; - idStr text; - idStr screenshot; -}; - -struct idLevelTriggerInfo { - idStr levelName; - idStr triggerName; -}; - -// powerups - the "type" in item .def must match -enum { - BERSERK = 0, - INVISIBILITY, - MEGAHEALTH, - ADRENALINE, -#ifdef _D3XP - INVULNERABILITY, - HELLTIME, - ENVIROSUIT, - //HASTE, - ENVIROTIME, -#endif - MAX_POWERUPS -}; - -// powerup modifiers -enum { - SPEED = 0, - PROJECTILE_DAMAGE, - MELEE_DAMAGE, - MELEE_DISTANCE -}; - -// influence levels -enum { - INFLUENCE_NONE = 0, // none - INFLUENCE_LEVEL1, // no gun or hud - INFLUENCE_LEVEL2, // no gun, hud, movement - INFLUENCE_LEVEL3, // slow player movement -}; - -#ifdef _D3XP -typedef struct { - int ammo; - int rechargeTime; - char ammoName[128]; -} RechargeAmmo_t; - -typedef struct { - char name[64]; - idList toggleList; -} WeaponToggle_t; -#endif - -class idInventory { -public: - int maxHealth; - int weapons; - int powerups; - int armor; - int maxarmor; - int ammo[ AMMO_NUMTYPES ]; - int clip[ MAX_WEAPONS ]; - int powerupEndTime[ MAX_POWERUPS ]; - -#ifdef _D3XP - RechargeAmmo_t rechargeAmmo[ AMMO_NUMTYPES ]; -#endif - - // mp - int ammoPredictTime; - - int deplete_armor; - float deplete_rate; - int deplete_ammount; - int nextArmorDepleteTime; - - int pdasViewed[4]; // 128 bit flags for indicating if a pda has been viewed - - int selPDA; - int selEMail; - int selVideo; - int selAudio; - bool pdaOpened; - bool turkeyScore; - idList items; - idStrList pdas; - idStrList pdaSecurity; - idStrList videos; - idStrList emails; - - bool ammoPulse; - bool weaponPulse; - bool armorPulse; - int lastGiveTime; - - idList levelTriggers; - - idInventory() { Clear(); } - ~idInventory() { Clear(); } - - // save games - void Save( idSaveGame *savefile ) const; // archives object for save game file - void Restore( idRestoreGame *savefile ); // unarchives object from save game file - - void Clear( void ); - void GivePowerUp( idPlayer *player, int powerup, int msec ); - void ClearPowerUps( void ); - void GetPersistantData( idDict &dict ); - void RestoreInventory( idPlayer *owner, const idDict &dict ); - bool Give( idPlayer *owner, const idDict &spawnArgs, const char *statname, const char *value, int *idealWeapon, bool updateHud ); - void Drop( const idDict &spawnArgs, const char *weapon_classname, int weapon_index ); - ammo_t AmmoIndexForAmmoClass( const char *ammo_classname ) const; - int MaxAmmoForAmmoClass( idPlayer *owner, const char *ammo_classname ) const; - int WeaponIndexForAmmoClass( const idDict & spawnArgs, const char *ammo_classname ) const; - ammo_t AmmoIndexForWeaponClass( const char *weapon_classname, int *ammoRequired ); - const char * AmmoPickupNameForIndex( ammo_t ammonum ) const; - void AddPickupName( const char *name, const char *icon, idPlayer* owner ); //_D3XP - - int HasAmmo( ammo_t type, int amount ); - bool UseAmmo( ammo_t type, int amount ); - int HasAmmo( const char *weapon_classname, bool includeClip = false, idPlayer* owner = NULL ); // _D3XP - -#ifdef _D3XP - bool HasEmptyClipCannotRefill(const char *weapon_classname, idPlayer* owner); -#endif - - void UpdateArmor( void ); - - int nextItemPickup; - int nextItemNum; - int onePickupTime; - idList pickupItemNames; - idList objectiveNames; - -#ifdef _D3XP - void InitRechargeAmmo(idPlayer *owner); - void RechargeAmmo(idPlayer *owner); - bool CanGive( idPlayer *owner, const idDict &spawnArgs, const char *statname, const char *value, int *idealWeapon ); -#endif -}; - -typedef struct { - int time; - idVec3 dir; // scaled larger for running -} loggedAccel_t; - -typedef struct { - int areaNum; - idVec3 pos; -} aasLocation_t; - -class idPlayer : public idActor { -public: - enum { - EVENT_IMPULSE = idEntity::EVENT_MAXEVENTS, - EVENT_EXIT_TELEPORTER, - EVENT_ABORT_TELEPORTER, - EVENT_POWERUP, - EVENT_SPECTATE, -#ifdef _D3XP - EVENT_PICKUPNAME, -#endif - EVENT_MAXEVENTS - }; - - usercmd_t usercmd; - - class idPlayerView playerView; // handles damage kicks and effects - - bool noclip; - bool godmode; - - bool spawnAnglesSet; // on first usercmd, we must set deltaAngles - idAngles spawnAngles; - idAngles viewAngles; // player view angles - idAngles cmdAngles; // player cmd angles - - int buttonMask; - int oldButtons; - int oldFlags; - - int lastHitTime; // last time projectile fired by player hit target - int lastSndHitTime; // MP hit sound - != lastHitTime because we throttle - int lastSavingThrowTime; // for the "free miss" effect - - idScriptBool AI_FORWARD; - idScriptBool AI_BACKWARD; - idScriptBool AI_STRAFE_LEFT; - idScriptBool AI_STRAFE_RIGHT; - idScriptBool AI_ATTACK_HELD; - idScriptBool AI_WEAPON_FIRED; - idScriptBool AI_JUMP; - idScriptBool AI_CROUCH; - idScriptBool AI_ONGROUND; - idScriptBool AI_ONLADDER; - idScriptBool AI_DEAD; - idScriptBool AI_RUN; - idScriptBool AI_PAIN; - idScriptBool AI_HARDLANDING; - idScriptBool AI_SOFTLANDING; - idScriptBool AI_RELOAD; - idScriptBool AI_TELEPORT; - idScriptBool AI_TURN_LEFT; - idScriptBool AI_TURN_RIGHT; - - // inventory - idInventory inventory; - - idEntityPtr weapon; - idUserInterface * hud; // MP: is NULL if not local player - idUserInterface * objectiveSystem; - bool objectiveSystemOpen; - - int weapon_soulcube; - int weapon_pda; - int weapon_fists; -#ifdef _D3XP - int weapon_bloodstone; - int weapon_bloodstone_active1; - int weapon_bloodstone_active2; - int weapon_bloodstone_active3; - bool harvest_lock; -#endif - - int heartRate; - idInterpolate heartInfo; - int lastHeartAdjust; - int lastHeartBeat; - int lastDmgTime; - int deathClearContentsTime; - bool doingDeathSkin; - int lastArmorPulse; // lastDmgTime if we had armor at time of hit - float stamina; - float healthPool; // amount of health to give over time - int nextHealthPulse; - bool healthPulse; - bool healthTake; - int nextHealthTake; - - - bool hiddenWeapon; // if the weapon is hidden ( in noWeapons maps ) - idEntityPtr soulCubeProjectile; - - // mp stuff -#ifdef _D3XP - static idVec3 colorBarTable[ 8 ]; -#else - static idVec3 colorBarTable[ 5 ]; -#endif - - int spectator; - idVec3 colorBar; // used for scoreboard and hud display - int colorBarIndex; - bool scoreBoardOpen; - bool forceScoreBoard; - bool forceRespawn; - bool spectating; - int lastSpectateTeleport; - bool lastHitToggle; - bool forcedReady; - bool wantSpectate; // from userInfo - bool weaponGone; // force stop firing - bool useInitialSpawns; // toggled by a map restart to be active for the first game spawn - int latchedTeam; // need to track when team gets changed - int tourneyRank; // for tourney cycling - the higher, the more likely to play next - server - int tourneyLine; // client side - our spot in the wait line. 0 means no info. - int spawnedTime; // when client first enters the game - -#ifdef CTF - bool carryingFlag; // is the player carrying the flag? -#endif - - idEntityPtr teleportEntity; // while being teleported, this is set to the entity we'll use for exit - int teleportKiller; // entity number of an entity killing us at teleporter exit - bool lastManOver; // can't respawn in last man anymore (srv only) - bool lastManPlayAgain; // play again when end game delay is cancelled out before expiring (srv only) - bool lastManPresent; // true when player was in when game started (spectators can't join a running LMS) - bool isLagged; // replicated from server, true if packets haven't been received from client. - bool isChatting; // replicated from server, true if the player is chatting. - - // timers - int minRespawnTime; // can respawn when time > this, force after g_forcerespawn - int maxRespawnTime; // force respawn after this time - - // the first person view values are always calculated, even - // if a third person view is used - idVec3 firstPersonViewOrigin; - idMat3 firstPersonViewAxis; - - idDragEntity dragEntity; - -#ifdef _D3XP - idFuncMountedObject * mountedObject; - idEntityPtr enviroSuitLight; - - bool healthRecharge; - int lastHealthRechargeTime; - int rechargeSpeed; - - float new_g_damageScale; - - bool bloomEnabled; - float bloomSpeed; - float bloomIntensity; -#endif - -public: - CLASS_PROTOTYPE( idPlayer ); - - idPlayer(); - virtual ~idPlayer(); - - void Spawn( void ); - void Think( void ); - - // save games - void Save( idSaveGame *savefile ) const; // archives object for save game file - void Restore( idRestoreGame *savefile ); // unarchives object from save game file - - virtual void Hide( void ); - virtual void Show( void ); - - void Init( void ); - void PrepareForRestart( void ); - virtual void Restart( void ); - void LinkScriptVariables( void ); - void SetupWeaponEntity( void ); - void SelectInitialSpawnPoint( idVec3 &origin, idAngles &angles ); - void SpawnFromSpawnSpot( void ); - void SpawnToPoint( const idVec3 &spawn_origin, const idAngles &spawn_angles ); - void SetClipModel( void ); // spectator mode uses a different bbox size - - void SavePersistantInfo( void ); - void RestorePersistantInfo( void ); - void SetLevelTrigger( const char *levelName, const char *triggerName ); - - bool UserInfoChanged( bool canModify ); - idDict * GetUserInfo( void ); - bool BalanceTDM( void ); - - void CacheWeapons( void ); - - void EnterCinematic( void ); - void ExitCinematic( void ); - bool HandleESC( void ); - bool SkipCinematic( void ); - - void UpdateConditions( void ); - void SetViewAngles( const idAngles &angles ); - - // delta view angles to allow movers to rotate the view of the player - void UpdateDeltaViewAngles( const idAngles &angles ); - - virtual bool Collide( const trace_t &collision, const idVec3 &velocity ); - - virtual void GetAASLocation( idAAS *aas, idVec3 &pos, int &areaNum ) const; - virtual void GetAIAimTargets( const idVec3 &lastSightPos, idVec3 &headPos, idVec3 &chestPos ); - virtual void DamageFeedback( idEntity *victim, idEntity *inflictor, int &damage ); - void CalcDamagePoints( idEntity *inflictor, idEntity *attacker, const idDict *damageDef, - const float damageScale, const int location, int *health, int *armor ); - virtual void Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location ); - - // use exitEntityNum to specify a teleport with private camera view and delayed exit - virtual void Teleport( const idVec3 &origin, const idAngles &angles, idEntity *destination ); - - void Kill( bool delayRespawn, bool nodamage ); - virtual void Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ); - void StartFxOnBone(const char *fx, const char *bone); - - renderView_t * GetRenderView( void ); - void CalculateRenderView( void ); // called every tic by player code - void CalculateFirstPersonView( void ); - - void DrawHUD( idUserInterface *hud ); - - void WeaponFireFeedback( const idDict *weaponDef ); - - float DefaultFov( void ) const; - float CalcFov( bool honorZoom ); - void CalculateViewWeaponPos( idVec3 &origin, idMat3 &axis ); - idVec3 GetEyePosition( void ) const; - void GetViewPos( idVec3 &origin, idMat3 &axis ) const; - void OffsetThirdPersonView( float angle, float range, float height, bool clip ); - - bool Give( const char *statname, const char *value ); - bool GiveItem( idItem *item ); - void GiveItem( const char *name ); - void GiveHealthPool( float amt ); - - bool GiveInventoryItem( idDict *item ); - void RemoveInventoryItem( idDict *item ); - bool GiveInventoryItem( const char *name ); - void RemoveInventoryItem( const char *name ); - idDict * FindInventoryItem( const char *name ); - - void GivePDA( const char *pdaName, idDict *item ); - void GiveVideo( const char *videoName, idDict *item ); - void GiveEmail( const char *emailName ); - void GiveSecurity( const char *security ); - void GiveObjective( const char *title, const char *text, const char *screenshot ); - void CompleteObjective( const char *title ); - - bool GivePowerUp( int powerup, int time ); - void ClearPowerUps( void ); - bool PowerUpActive( int powerup ) const; - float PowerUpModifier( int type ); - - int SlotForWeapon( const char *weaponName ); - void Reload( void ); - void NextWeapon( void ); - void NextBestWeapon( void ); - void PrevWeapon( void ); - void SelectWeapon( int num, bool force ); - void DropWeapon( bool died ) ; - void StealWeapon( idPlayer *player ); - void AddProjectilesFired( int count ); - void AddProjectileHits( int count ); - void SetLastHitTime( int time ); - void LowerWeapon( void ); - void RaiseWeapon( void ); - void WeaponLoweringCallback( void ); - void WeaponRisingCallback( void ); - void RemoveWeapon( const char *weap ); - bool CanShowWeaponViewmodel( void ) const; - - void AddAIKill( void ); - void SetSoulCubeProjectile( idProjectile *projectile ); - - void AdjustHeartRate( int target, float timeInSecs, float delay, bool force ); - void SetCurrentHeartRate( void ); - int GetBaseHeartRate( void ); - void UpdateAir( void ); - -#ifdef _D3XP - void UpdatePowerupHud(); -#endif - - virtual bool HandleSingleGuiCommand( idEntity *entityGui, idLexer *src ); - bool GuiActive( void ) { return focusGUIent != NULL; } - - void PerformImpulse( int impulse ); - void Spectate( bool spectate ); - void TogglePDA( void ); - void ToggleScoreboard( void ); - void RouteGuiMouse( idUserInterface *gui ); - void UpdateHud( void ); - const idDeclPDA * GetPDA( void ) const; - const idDeclVideo * GetVideo( int index ); - void SetInfluenceFov( float fov ); - void SetInfluenceView( const char *mtr, const char *skinname, float radius, idEntity *ent ); - void SetInfluenceLevel( int level ); - int GetInfluenceLevel( void ) { return influenceActive; }; - void SetPrivateCameraView( idCamera *camView ); - idCamera * GetPrivateCameraView( void ) const { return privateCameraView; } - void StartFxFov( float duration ); - void UpdateHudWeapon( bool flashWeapon = true ); - void UpdateHudStats( idUserInterface *hud ); - void UpdateHudAmmo( idUserInterface *hud ); - void Event_StopAudioLog( void ); - void StartAudioLog( void ); - void StopAudioLog( void ); - void ShowTip( const char *title, const char *tip, bool autoHide ); - void HideTip( void ); - bool IsTipVisible( void ) { return tipUp; }; - void ShowObjective( const char *obj ); - void HideObjective( void ); - - virtual void ClientPredictionThink( void ); - virtual void WriteToSnapshot( idBitMsgDelta &msg ) const; - virtual void ReadFromSnapshot( const idBitMsgDelta &msg ); - void WritePlayerStateToSnapshot( idBitMsgDelta &msg ) const; - void ReadPlayerStateFromSnapshot( const idBitMsgDelta &msg ); - - virtual bool ServerReceiveEvent( int event, int time, const idBitMsg &msg ); - - virtual bool GetPhysicsToVisualTransform( idVec3 &origin, idMat3 &axis ); - virtual bool GetPhysicsToSoundTransform( idVec3 &origin, idMat3 &axis ); - - virtual bool ClientReceiveEvent( int event, int time, const idBitMsg &msg ); - bool IsReady( void ); - bool IsRespawning( void ); - bool IsInTeleport( void ); - - idEntity *GetInfluenceEntity( void ) { return influenceEntity; }; - const idMaterial *GetInfluenceMaterial( void ) { return influenceMaterial; }; - float GetInfluenceRadius( void ) { return influenceRadius; }; - - // server side work for in/out of spectate. takes care of spawning it into the world as well - void ServerSpectate( bool spectate ); - // for very specific usage. != GetPhysics() - idPhysics *GetPlayerPhysics( void ); - void TeleportDeath( int killer ); - void SetLeader( bool lead ); - bool IsLeader( void ); - - void UpdateSkinSetup( bool restart ); - - bool OnLadder( void ) const; - - virtual void UpdatePlayerIcons( void ); - virtual void DrawPlayerIcons( void ); - virtual void HidePlayerIcons( void ); - bool NeedsIcon( void ); - -#ifdef _D3XP - void StartHealthRecharge(int speed); - void StopHealthRecharge(); - - idStr GetCurrentWeapon(); - - bool CanGive( const char *statname, const char *value ); - - void StopHelltime( bool quick = true ); - void PlayHelltimeStopSound(); -#endif - -#ifdef CTF - void DropFlag( void ); // drop CTF item - void ReturnFlag(); - virtual void FreeModelDef( void ); -#endif - - bool SelfSmooth( void ); - void SetSelfSmooth( bool b ); - -private: - jointHandle_t hipJoint; - jointHandle_t chestJoint; - jointHandle_t headJoint; - - idPhysics_Player physicsObj; // player physics - - idList aasLocation; // for AI tracking the player - - int bobFoot; - float bobFrac; - float bobfracsin; - int bobCycle; // for view bobbing and footstep generation - float xyspeed; - int stepUpTime; - float stepUpDelta; - float idealLegsYaw; - float legsYaw; - bool legsForward; - float oldViewYaw; - idAngles viewBobAngles; - idVec3 viewBob; - int landChange; - int landTime; - - int currentWeapon; - int idealWeapon; - int previousWeapon; - int weaponSwitchTime; - bool weaponEnabled; - bool showWeaponViewModel; - - const idDeclSkin * skin; - const idDeclSkin * powerUpSkin; - idStr baseSkinName; - - int numProjectilesFired; // number of projectiles fired - int numProjectileHits; // number of hits on mobs - - bool airless; - int airTics; // set to pm_airTics at start, drops in vacuum - int lastAirDamage; - - bool gibDeath; - bool gibsLaunched; - idVec3 gibsDir; - - idInterpolate zoomFov; - idInterpolate centerView; - bool fxFov; - - float influenceFov; - int influenceActive; // level of influence.. 1 == no gun or hud .. 2 == 1 + no movement - idEntity * influenceEntity; - const idMaterial * influenceMaterial; - float influenceRadius; - const idDeclSkin * influenceSkin; - - idCamera * privateCameraView; - - static const int NUM_LOGGED_VIEW_ANGLES = 64; // for weapon turning angle offsets - idAngles loggedViewAngles[NUM_LOGGED_VIEW_ANGLES]; // [gameLocal.framenum&(LOGGED_VIEW_ANGLES-1)] - static const int NUM_LOGGED_ACCELS = 16; // for weapon turning angle offsets - loggedAccel_t loggedAccel[NUM_LOGGED_ACCELS]; // [currentLoggedAccel & (NUM_LOGGED_ACCELS-1)] - int currentLoggedAccel; - - // if there is a focusGUIent, the attack button will be changed into mouse clicks - idEntity * focusGUIent; - idUserInterface * focusUI; // focusGUIent->renderEntity.gui, gui2, or gui3 - idAI * focusCharacter; - int talkCursor; // show the state of the focusCharacter (0 == can't talk/dead, 1 == ready to talk, 2 == busy talking) - int focusTime; - idAFEntity_Vehicle * focusVehicle; - idUserInterface * cursor; - - // full screen guis track mouse movements directly - int oldMouseX; - int oldMouseY; - - idStr pdaAudio; - idStr pdaVideo; - idStr pdaVideoWave; - - bool tipUp; - bool objectiveUp; - - int lastDamageDef; - idVec3 lastDamageDir; - int lastDamageLocation; - int smoothedFrame; - bool smoothedOriginUpdated; - idVec3 smoothedOrigin; - idAngles smoothedAngles; - -#ifdef _D3XP - idHashTable weaponToggles; - - int hudPowerup; - int lastHudPowerup; - int hudPowerupDuration; -#endif - - // mp - bool ready; // from userInfo - bool respawning; // set to true while in SpawnToPoint for telefrag checks - bool leader; // for sudden death situations - int lastSpectateChange; - int lastTeleFX; - unsigned int lastSnapshotSequence; // track state hitches on clients - bool weaponCatchup; // raise up the weapon silently ( state catchups ) - int MPAim; // player num in aim - int lastMPAim; - int lastMPAimTime; // last time the aim changed - int MPAimFadeTime; // for GUI fade - bool MPAimHighlight; - bool isTelefragged; // proper obituaries - - idPlayerIcon playerIcon; - - bool selfSmooth; - - void LookAtKiller( idEntity *inflictor, idEntity *attacker ); - - void StopFiring( void ); - void FireWeapon( void ); - void Weapon_Combat( void ); - void Weapon_NPC( void ); - void Weapon_GUI( void ); - void UpdateWeapon( void ); - void UpdateSpectating( void ); - void SpectateFreeFly( bool force ); // ignore the timeout to force when followed spec is no longer valid - void SpectateCycle( void ); - idAngles GunTurningOffset( void ); - idVec3 GunAcceleratingOffset( void ); - - void UseObjects( void ); - void CrashLand( const idVec3 &oldOrigin, const idVec3 &oldVelocity ); - void BobCycle( const idVec3 &pushVelocity ); - void UpdateViewAngles( void ); - void EvaluateControls( void ); - void AdjustSpeed( void ); - void AdjustBodyAngles( void ); - void InitAASLocation( void ); - void SetAASLocation( void ); - void Move( void ); - void UpdatePowerUps( void ); - void UpdateDeathSkin( bool state_hitch ); - void ClearPowerup( int i ); - void SetSpectateOrigin( void ); - - void ClearFocus( void ); - void UpdateFocus( void ); - void UpdateLocation( void ); - idUserInterface * ActiveGui( void ); - void UpdatePDAInfo( bool updatePDASel ); - int AddGuiPDAData( const declType_t dataType, const char *listName, const idDeclPDA *src, idUserInterface *gui ); - void ExtractEmailInfo( const idStr &email, const char *scan, idStr &out ); - void UpdateObjectiveInfo( void ); - -#ifdef _D3XP - bool WeaponAvailable( const char* name ); -#endif - - void UseVehicle( void ); - - void Event_GetButtons( void ); - void Event_GetMove( void ); - void Event_GetViewAngles( void ); - void Event_StopFxFov( void ); - void Event_EnableWeapon( void ); - void Event_DisableWeapon( void ); - void Event_GetCurrentWeapon( void ); - void Event_GetPreviousWeapon( void ); - void Event_SelectWeapon( const char *weaponName ); - void Event_GetWeaponEntity( void ); - void Event_OpenPDA( void ); - void Event_PDAAvailable( void ); - void Event_InPDA( void ); - void Event_ExitTeleporter( void ); - void Event_HideTip( void ); - void Event_LevelTrigger( void ); - void Event_Gibbed( void ); - -#ifdef _D3XP //BSM: Event to remove inventory items. Useful with powercells. - void Event_GiveInventoryItem( const char* name ); - void Event_RemoveInventoryItem( const char* name ); - - void Event_GetIdealWeapon( void ); - void Event_WeaponAvailable( const char* name ); - void Event_SetPowerupTime( int powerup, int time ); - void Event_IsPowerupActive( int powerup ); - void Event_StartWarp(); - void Event_StopHelltime( int mode ); - void Event_ToggleBloom( int on ); - void Event_SetBloomParms( float speed, float intensity ); -#endif -}; - -ID_INLINE bool idPlayer::IsReady( void ) { - return ready || forcedReady; -} - -ID_INLINE bool idPlayer::IsRespawning( void ) { - return respawning; -} - -ID_INLINE idPhysics* idPlayer::GetPlayerPhysics( void ) { - return &physicsObj; -} - -ID_INLINE bool idPlayer::IsInTeleport( void ) { - return ( teleportEntity.GetEntity() != NULL ); -} - -ID_INLINE void idPlayer::SetLeader( bool lead ) { - leader = lead; -} - -ID_INLINE bool idPlayer::IsLeader( void ) { - return leader; -} - -ID_INLINE bool idPlayer::SelfSmooth( void ) { - return selfSmooth; -} - -ID_INLINE void idPlayer::SetSelfSmooth( bool b ) { - selfSmooth = b; -} - -#endif /* !__GAME_PLAYER_H__ */ diff --git a/d3xp/PlayerIcon.cpp b/d3xp/PlayerIcon.cpp deleted file mode 100644 index 3fd58efa..00000000 --- a/d3xp/PlayerIcon.cpp +++ /dev/null @@ -1,199 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "renderer/ModelManager.h" - -#include "gamesys/SysCvar.h" -#include "Player.h" - -#include "PlayerIcon.h" - -static const char * iconKeys[ ICON_NONE ] = { - "mtr_icon_lag", - "mtr_icon_chat" -#ifdef CTF - ,"mtr_icon_redteam", - "mtr_icon_blueteam" -#endif -}; - -/* -=============== -idPlayerIcon::idPlayerIcon -=============== -*/ -idPlayerIcon::idPlayerIcon() { - iconHandle = -1; - iconType = ICON_NONE; -} - -/* -=============== -idPlayerIcon::~idPlayerIcon -=============== -*/ -idPlayerIcon::~idPlayerIcon() { - FreeIcon(); -} - -/* -=============== -idPlayerIcon::Draw -=============== -*/ -void idPlayerIcon::Draw( idPlayer *player, jointHandle_t joint ) { - idVec3 origin; - idMat3 axis; - - if ( joint == INVALID_JOINT ) { - FreeIcon(); - return; - } - - player->GetJointWorldTransform( joint, gameLocal.time, origin, axis ); - origin.z += 16.0f; - - Draw( player, origin ); -} - -/* -=============== -idPlayerIcon::Draw -=============== -*/ -void idPlayerIcon::Draw( idPlayer *player, const idVec3 &origin ) { - idPlayer *localPlayer = gameLocal.GetLocalPlayer(); - if ( !localPlayer || !localPlayer->GetRenderView() ) { - FreeIcon(); - return; - } - - idMat3 axis = localPlayer->GetRenderView()->viewaxis; - - if ( player->isLagged && !player->spectating ) { - // create the icon if necessary, or update if already created - if ( !CreateIcon( player, ICON_LAG, origin, axis ) ) { - UpdateIcon( player, origin, axis ); - } - } else if ( player->isChatting && !player->spectating ) { - if ( !CreateIcon( player, ICON_CHAT, origin, axis ) ) { - UpdateIcon( player, origin, axis ); - } -#ifdef CTF - } else if ( g_CTFArrows.GetBool() && gameLocal.mpGame.IsGametypeFlagBased() && gameLocal.GetLocalPlayer() && player->team == gameLocal.GetLocalPlayer()->team && !player->IsHidden() && !player->AI_DEAD ) { - int icon = ICON_TEAM_RED + player->team; - - if ( icon != ICON_TEAM_RED && icon != ICON_TEAM_BLUE ) - return; - - if ( !CreateIcon( player, ( playerIconType_t )icon, origin, axis ) ) { - UpdateIcon( player, origin, axis ); - } -#endif - } else { - FreeIcon(); - } -} - -/* -=============== -idPlayerIcon::FreeIcon -=============== -*/ -void idPlayerIcon::FreeIcon( void ) { - if ( iconHandle != - 1 ) { - gameRenderWorld->FreeEntityDef( iconHandle ); - iconHandle = -1; - } - iconType = ICON_NONE; -} - -/* -=============== -idPlayerIcon::CreateIcon -=============== -*/ -bool idPlayerIcon::CreateIcon( idPlayer *player, playerIconType_t type, const idVec3 &origin, const idMat3 &axis ) { - assert( type != ICON_NONE ); - const char *mtr = player->spawnArgs.GetString( iconKeys[ type ], "_default" ); - return CreateIcon( player, type, mtr, origin, axis ); -} - -/* -=============== -idPlayerIcon::CreateIcon -=============== -*/ -bool idPlayerIcon::CreateIcon( idPlayer *player, playerIconType_t type, const char *mtr, const idVec3 &origin, const idMat3 &axis ) { - assert( type != ICON_NONE ); - - if ( type == iconType ) { - return false; - } - - FreeIcon(); - - memset( &renderEnt, 0, sizeof( renderEnt ) ); - renderEnt.origin = origin; - renderEnt.axis = axis; - renderEnt.shaderParms[ SHADERPARM_RED ] = 1.0f; - renderEnt.shaderParms[ SHADERPARM_GREEN ] = 1.0f; - renderEnt.shaderParms[ SHADERPARM_BLUE ] = 1.0f; - renderEnt.shaderParms[ SHADERPARM_ALPHA ] = 1.0f; - renderEnt.shaderParms[ SHADERPARM_SPRITE_WIDTH ] = 16.0f; - renderEnt.shaderParms[ SHADERPARM_SPRITE_HEIGHT ] = 16.0f; - renderEnt.hModel = renderModelManager->FindModel( "_sprite" ); - renderEnt.callback = NULL; - renderEnt.numJoints = 0; - renderEnt.joints = NULL; - renderEnt.customSkin = 0; - renderEnt.noShadow = true; - renderEnt.noSelfShadow = true; - renderEnt.customShader = declManager->FindMaterial( mtr ); - renderEnt.referenceShader = 0; - renderEnt.bounds = renderEnt.hModel->Bounds( &renderEnt ); - - iconHandle = gameRenderWorld->AddEntityDef( &renderEnt ); - iconType = type; - - return true; -} - -/* -=============== -idPlayerIcon::UpdateIcon -=============== -*/ -void idPlayerIcon::UpdateIcon( idPlayer *player, const idVec3 &origin, const idMat3 &axis ) { - assert( iconHandle >= 0 ); - - renderEnt.origin = origin; - renderEnt.axis = axis; - gameRenderWorld->UpdateEntityDef( iconHandle, &renderEnt ); -} diff --git a/d3xp/PlayerIcon.h b/d3xp/PlayerIcon.h deleted file mode 100644 index cbf582d4..00000000 --- a/d3xp/PlayerIcon.h +++ /dev/null @@ -1,66 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __PLAYERICON_H__ -#define __PLAYERICON_H__ - -typedef enum { - ICON_LAG, - ICON_CHAT, -#ifdef CTF - ICON_TEAM_RED, - ICON_TEAM_BLUE, -#endif - ICON_NONE -} playerIconType_t; - -class idPlayerIcon { -public: - -public: - idPlayerIcon(); - ~idPlayerIcon(); - - void Draw( idPlayer *player, jointHandle_t joint ); - void Draw( idPlayer *player, const idVec3 &origin ); - -public: - playerIconType_t iconType; - renderEntity_t renderEnt; - qhandle_t iconHandle; - -public: - void FreeIcon( void ); - bool CreateIcon( idPlayer* player, playerIconType_t type, const char *mtr, const idVec3 &origin, const idMat3 &axis ); - bool CreateIcon( idPlayer* player, playerIconType_t type, const idVec3 &origin, const idMat3 &axis ); - void UpdateIcon( idPlayer* player, const idVec3 &origin, const idMat3 &axis ); - -}; - - -#endif /* !_PLAYERICON_H_ */ diff --git a/d3xp/PlayerView.cpp b/d3xp/PlayerView.cpp deleted file mode 100644 index 00a5d21c..00000000 --- a/d3xp/PlayerView.cpp +++ /dev/null @@ -1,1855 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "renderer/RenderWorld.h" - -#include "gamesys/SysCvar.h" -#include "gamesys/SaveGame.h" -#include "GameBase.h" -#include "Player.h" - -#include "PlayerView.h" - -// _D3XP : rename all gameLocal.time to gameLocal.slow.time for merge! - -#ifdef _D3XP -static int MakePowerOfTwo( int num ) { - int pot; - for (pot = 1 ; pot < num ; pot<<=1) { - } - return pot; -} -#endif - -const int IMPULSE_DELAY = 150; -/* -============== -idPlayerView::idPlayerView -============== -*/ -idPlayerView::idPlayerView() { - memset( screenBlobs, 0, sizeof( screenBlobs ) ); - memset( &view, 0, sizeof( view ) ); - player = NULL; - dvMaterial = declManager->FindMaterial( "_scratch" ); - tunnelMaterial = declManager->FindMaterial( "textures/decals/tunnel" ); - armorMaterial = declManager->FindMaterial( "armorViewEffect" ); - berserkMaterial = declManager->FindMaterial( "textures/decals/berserk" ); - irGogglesMaterial = declManager->FindMaterial( "textures/decals/irblend" ); - bloodSprayMaterial = declManager->FindMaterial( "textures/decals/bloodspray" ); - bfgMaterial = declManager->FindMaterial( "textures/decals/bfgvision" ); - lagoMaterial = declManager->FindMaterial( LAGO_MATERIAL, false ); - bfgVision = false; - dvFinishTime = 0; - kickFinishTime = 0; - kickAngles.Zero(); - lastDamageTime = 0.0f; - fadeTime = 0; - fadeRate = 0.0; - fadeFromColor.Zero(); - fadeToColor.Zero(); - fadeColor.Zero(); - shakeAng.Zero(); -#ifdef _D3XP - fxManager = NULL; - - if ( !fxManager ) { - fxManager = new FullscreenFXManager; - fxManager->Initialize( this ); - } -#endif - - ClearEffects(); -} - -/* -============== -idPlayerView::Save -============== -*/ -void idPlayerView::Save( idSaveGame *savefile ) const { - int i; - const screenBlob_t *blob; - - blob = &screenBlobs[ 0 ]; - for( i = 0; i < MAX_SCREEN_BLOBS; i++, blob++ ) { - savefile->WriteMaterial( blob->material ); - savefile->WriteFloat( blob->x ); - savefile->WriteFloat( blob->y ); - savefile->WriteFloat( blob->w ); - savefile->WriteFloat( blob->h ); - savefile->WriteFloat( blob->s1 ); - savefile->WriteFloat( blob->t1 ); - savefile->WriteFloat( blob->s2 ); - savefile->WriteFloat( blob->t2 ); - savefile->WriteInt( blob->finishTime ); - savefile->WriteInt( blob->startFadeTime ); - savefile->WriteFloat( blob->driftAmount ); - } - - savefile->WriteInt( dvFinishTime ); - savefile->WriteMaterial( dvMaterial ); - savefile->WriteInt( kickFinishTime ); - savefile->WriteAngles( kickAngles ); - savefile->WriteBool( bfgVision ); - - savefile->WriteMaterial( tunnelMaterial ); - savefile->WriteMaterial( armorMaterial ); - savefile->WriteMaterial( berserkMaterial ); - savefile->WriteMaterial( irGogglesMaterial ); - savefile->WriteMaterial( bloodSprayMaterial ); - savefile->WriteMaterial( bfgMaterial ); - savefile->WriteFloat( lastDamageTime ); - - savefile->WriteVec4( fadeColor ); - savefile->WriteVec4( fadeToColor ); - savefile->WriteVec4( fadeFromColor ); - savefile->WriteFloat( fadeRate ); - savefile->WriteInt( fadeTime ); - - savefile->WriteAngles( shakeAng ); - - savefile->WriteObject( player ); - savefile->WriteRenderView( view ); - -#ifdef _D3XP - if ( fxManager ) { - fxManager->Save( savefile ); - } -#endif -} - -/* -============== -idPlayerView::Restore -============== -*/ -void idPlayerView::Restore( idRestoreGame *savefile ) { - int i; - screenBlob_t *blob; - - blob = &screenBlobs[ 0 ]; - for( i = 0; i < MAX_SCREEN_BLOBS; i++, blob++ ) { - savefile->ReadMaterial( blob->material ); - savefile->ReadFloat( blob->x ); - savefile->ReadFloat( blob->y ); - savefile->ReadFloat( blob->w ); - savefile->ReadFloat( blob->h ); - savefile->ReadFloat( blob->s1 ); - savefile->ReadFloat( blob->t1 ); - savefile->ReadFloat( blob->s2 ); - savefile->ReadFloat( blob->t2 ); - savefile->ReadInt( blob->finishTime ); - savefile->ReadInt( blob->startFadeTime ); - savefile->ReadFloat( blob->driftAmount ); - } - - savefile->ReadInt( dvFinishTime ); - savefile->ReadMaterial( dvMaterial ); - savefile->ReadInt( kickFinishTime ); - savefile->ReadAngles( kickAngles ); - savefile->ReadBool( bfgVision ); - - savefile->ReadMaterial( tunnelMaterial ); - savefile->ReadMaterial( armorMaterial ); - savefile->ReadMaterial( berserkMaterial ); - savefile->ReadMaterial( irGogglesMaterial ); - savefile->ReadMaterial( bloodSprayMaterial ); - savefile->ReadMaterial( bfgMaterial ); - savefile->ReadFloat( lastDamageTime ); - - savefile->ReadVec4( fadeColor ); - savefile->ReadVec4( fadeToColor ); - savefile->ReadVec4( fadeFromColor ); - savefile->ReadFloat( fadeRate ); - savefile->ReadInt( fadeTime ); - - savefile->ReadAngles( shakeAng ); - - savefile->ReadObject( reinterpret_cast( player ) ); - savefile->ReadRenderView( view ); - -#ifdef _D3XP - if ( fxManager ) { - fxManager->Restore( savefile ); - } -#endif -} - -/* -============== -idPlayerView::SetPlayerEntity -============== -*/ -void idPlayerView::SetPlayerEntity( idPlayer *playerEnt ) { - player = playerEnt; -} - -/* -============== -idPlayerView::ClearEffects -============== -*/ -void idPlayerView::ClearEffects() { - lastDamageTime = MS2SEC( gameLocal.slow.time - 99999 ); - - dvFinishTime = ( gameLocal.fast.time - 99999 ); - kickFinishTime = ( gameLocal.slow.time - 99999 ); - - for ( int i = 0 ; i < MAX_SCREEN_BLOBS ; i++ ) { - screenBlobs[i].finishTime = gameLocal.slow.time; - } - - fadeTime = 0; - bfgVision = false; -} - -/* -============== -idPlayerView::GetScreenBlob -============== -*/ -screenBlob_t *idPlayerView::GetScreenBlob() { - screenBlob_t *oldest = &screenBlobs[0]; - - for ( int i = 1 ; i < MAX_SCREEN_BLOBS ; i++ ) { - if ( screenBlobs[i].finishTime < oldest->finishTime ) { - oldest = &screenBlobs[i]; - } - } - return oldest; -} - -/* -============== -idPlayerView::DamageImpulse - -LocalKickDir is the direction of force in the player's coordinate system, -which will determine the head kick direction -============== -*/ -void idPlayerView::DamageImpulse( idVec3 localKickDir, const idDict *damageDef ) { - // - // double vision effect - // - if ( lastDamageTime > 0.0f && SEC2MS( lastDamageTime ) + IMPULSE_DELAY > gameLocal.slow.time ) { - // keep shotgun from obliterating the view - return; - } - - float dvTime = damageDef->GetFloat( "dv_time" ); - if ( dvTime ) { - if ( dvFinishTime < gameLocal.fast.time ) { - dvFinishTime = gameLocal.fast.time; - } - dvFinishTime += g_dvTime.GetFloat() * dvTime; - // don't let it add up too much in god mode - if ( dvFinishTime > gameLocal.fast.time + 5000 ) { - dvFinishTime = gameLocal.fast.time + 5000; - } - } - - // - // head angle kick - // - float kickTime = damageDef->GetFloat( "kick_time" ); - if ( kickTime ) { - kickFinishTime = gameLocal.slow.time + g_kickTime.GetFloat() * kickTime; - - // forward / back kick will pitch view - kickAngles[0] = localKickDir[0]; - - // side kick will yaw view - kickAngles[1] = localKickDir[1]*0.5f; - - // up / down kick will pitch view - kickAngles[0] += localKickDir[2]; - - // roll will come from side - kickAngles[2] = localKickDir[1]; - - float kickAmplitude = damageDef->GetFloat( "kick_amplitude" ); - if ( kickAmplitude ) { - kickAngles *= kickAmplitude; - } - } - - // - // screen blob - // - float blobTime = damageDef->GetFloat( "blob_time" ); - if ( blobTime ) { - screenBlob_t *blob = GetScreenBlob(); - blob->startFadeTime = gameLocal.slow.time; - blob->finishTime = gameLocal.slow.time + blobTime * g_blobTime.GetFloat() * ((float)gameLocal.msec / USERCMD_MSEC); - - const char *materialName = damageDef->GetString( "mtr_blob" ); - blob->material = declManager->FindMaterial( materialName ); - blob->x = damageDef->GetFloat( "blob_x" ); - blob->x += ( gameLocal.random.RandomInt()&63 ) - 32; - blob->y = damageDef->GetFloat( "blob_y" ); - blob->y += ( gameLocal.random.RandomInt()&63 ) - 32; - - float scale = ( 256 + ( ( gameLocal.random.RandomInt()&63 ) - 32 ) ) / 256.0f; - blob->w = damageDef->GetFloat( "blob_width" ) * g_blobSize.GetFloat() * scale; - blob->h = damageDef->GetFloat( "blob_height" ) * g_blobSize.GetFloat() * scale; - blob->s1 = 0; - blob->t1 = 0; - blob->s2 = 1; - blob->t2 = 1; - } - - // - // save lastDamageTime for tunnel vision accentuation - // - lastDamageTime = MS2SEC( gameLocal.slow.time ); - -} - -/* -================== -idPlayerView::AddBloodSpray - -If we need a more generic way to add blobs then we can do that -but having it localized here lets the material be pre-looked up etc. -================== -*/ -void idPlayerView::AddBloodSpray( float duration ) { -/* - if ( duration <= 0 || bloodSprayMaterial == NULL || g_skipViewEffects.GetBool() ) { - return; - } - // visit this for chainsaw - screenBlob_t *blob = GetScreenBlob(); - blob->startFadeTime = gameLocal.slow.time; - blob->finishTime = gameLocal.slow.time + ( duration * 1000 ); - blob->material = bloodSprayMaterial; - blob->x = ( gameLocal.random.RandomInt() & 63 ) - 32; - blob->y = ( gameLocal.random.RandomInt() & 63 ) - 32; - blob->driftAmount = 0.5f + gameLocal.random.CRandomFloat() * 0.5; - float scale = ( 256 + ( ( gameLocal.random.RandomInt()&63 ) - 32 ) ) / 256.0f; - blob->w = 600 * g_blobSize.GetFloat() * scale; - blob->h = 480 * g_blobSize.GetFloat() * scale; - float s1 = 0.0f; - float t1 = 0.0f; - float s2 = 1.0f; - float t2 = 1.0f; - if ( blob->driftAmount < 0.6 ) { - s1 = 1.0f; - s2 = 0.0f; - } else if ( blob->driftAmount < 0.75 ) { - t1 = 1.0f; - t2 = 0.0f; - } else if ( blob->driftAmount < 0.85 ) { - s1 = 1.0f; - s2 = 0.0f; - t1 = 1.0f; - t2 = 0.0f; - } - blob->s1 = s1; - blob->t1 = t1; - blob->s2 = s2; - blob->t2 = t2; -*/ -} - -/* -================== -idPlayerView::WeaponFireFeedback - -Called when a weapon fires, generates head twitches, etc -================== -*/ -void idPlayerView::WeaponFireFeedback( const idDict *weaponDef ) { - int recoilTime; - - recoilTime = weaponDef->GetInt( "recoilTime" ); - // don't shorten a damage kick in progress - if ( recoilTime && kickFinishTime < gameLocal.slow.time ) { - idAngles angles; - weaponDef->GetAngles( "recoilAngles", "5 0 0", angles ); - kickAngles = angles; - int finish = gameLocal.slow.time + g_kickTime.GetFloat() * recoilTime; - kickFinishTime = finish; - } - -} - -/* -=================== -idPlayerView::CalculateShake -=================== -*/ -void idPlayerView::CalculateShake() { - idVec3 origin, matrix; - - float shakeVolume = gameSoundWorld->CurrentShakeAmplitudeForPosition( gameLocal.slow.time, player->firstPersonViewOrigin ); - // - // shakeVolume should somehow be molded into an angle here - // it should be thought of as being in the range 0.0 -> 1.0, although - // since CurrentShakeAmplitudeForPosition() returns all the shake sounds - // the player can hear, it can go over 1.0 too. - // - shakeAng[0] = gameLocal.random.CRandomFloat() * shakeVolume; - shakeAng[1] = gameLocal.random.CRandomFloat() * shakeVolume; - shakeAng[2] = gameLocal.random.CRandomFloat() * shakeVolume; -} - -/* -=================== -idPlayerView::ShakeAxis -=================== -*/ -idMat3 idPlayerView::ShakeAxis() const { - return shakeAng.ToMat3(); -} - -/* -=================== -idPlayerView::AngleOffset - - kickVector, a world space direction that the attack should -=================== -*/ -idAngles idPlayerView::AngleOffset() const { - idAngles ang; - - ang.Zero(); - - if ( gameLocal.slow.time < kickFinishTime ) { - float offset = kickFinishTime - gameLocal.slow.time; - - ang = kickAngles * offset * offset * g_kickAmplitude.GetFloat(); - - for ( int i = 0 ; i < 3 ; i++ ) { - if ( ang[i] > 70.0f ) { - ang[i] = 70.0f; - } else if ( ang[i] < -70.0f ) { - ang[i] = -70.0f; - } - } - } - return ang; -} - -/* -================== -idPlayerView::SingleView -================== -*/ -void idPlayerView::SingleView( idUserInterface *hud, const renderView_t *view ) { - - // normal rendering - if ( !view ) { - return; - } - - // place the sound origin for the player - gameSoundWorld->PlaceListener( view->vieworg, view->viewaxis, player->entityNumber + 1, gameLocal.slow.time, hud ? hud->State().GetString( "location" ) : "Undefined" ); - - // if the objective system is up, don't do normal drawing - if ( player->objectiveSystemOpen ) { - player->objectiveSystem->Redraw( gameLocal.fast.time ); - return; - } - - // hack the shake in at the very last moment, so it can't cause any consistency problems - renderView_t hackedView = *view; - hackedView.viewaxis = hackedView.viewaxis * ShakeAxis(); - -#ifdef _D3XP - if ( gameLocal.portalSkyEnt.GetEntity() && gameLocal.IsPortalSkyAcive() && g_enablePortalSky.GetBool() ) { - renderView_t portalView = hackedView; - portalView.vieworg = gameLocal.portalSkyEnt.GetEntity()->GetPhysics()->GetOrigin(); - - // setup global fixup projection vars - if ( 1 ) { - int vidWidth, vidHeight; - idVec2 shiftScale; - - renderSystem->GetGLSettings( vidWidth, vidHeight ); - - float pot; - int w = vidWidth; - pot = MakePowerOfTwo( w ); - shiftScale.x = (float)w / pot; - - int h = vidHeight; - pot = MakePowerOfTwo( h ); - shiftScale.y = (float)h / pot; - - hackedView.shaderParms[4] = shiftScale.x; - hackedView.shaderParms[5] = shiftScale.y; - } - - gameRenderWorld->RenderScene( &portalView ); - renderSystem->CaptureRenderToImage( "_currentRender" ); - - hackedView.forceUpdate = true; // FIX: for smoke particles not drawing when portalSky present - } - - // process the frame - fxManager->Process( &hackedView ); -#endif - - if ( player->spectating ) { - return; - } - -#ifdef _D3XP - if ( !hud ) { - return; - } -#endif - - // draw screen blobs - if ( !pm_thirdPerson.GetBool() && !g_skipViewEffects.GetBool() ) { - for ( int i = 0 ; i < MAX_SCREEN_BLOBS ; i++ ) { - screenBlob_t *blob = &screenBlobs[i]; - if ( blob->finishTime <= gameLocal.slow.time ) { - continue; - } - - blob->y += blob->driftAmount; - - float fade = (float)( blob->finishTime - gameLocal.slow.time ) / ( blob->finishTime - blob->startFadeTime ); - if ( fade > 1.0f ) { - fade = 1.0f; - } - if ( fade ) { - renderSystem->SetColor4( 1,1,1,fade ); - renderSystem->DrawStretchPic( blob->x, blob->y, blob->w, blob->h,blob->s1, blob->t1, blob->s2, blob->t2, blob->material ); - } - } - player->DrawHUD( hud ); - - // armor impulse feedback - float armorPulse = ( gameLocal.fast.time - player->lastArmorPulse ) / 250.0f; - - if ( armorPulse > 0.0f && armorPulse < 1.0f ) { - renderSystem->SetColor4( 1, 1, 1, 1.0 - armorPulse ); - renderSystem->DrawStretchPic( 0, 0, 640, 480, 0, 0, 1, 1, armorMaterial ); - } - - - // tunnel vision - float health = 0.0f; - if ( g_testHealthVision.GetFloat() != 0.0f ) { - health = g_testHealthVision.GetFloat(); - } else { - health = player->health; - } - float alpha = health / 100.0f; - if ( alpha < 0.0f ) { - alpha = 0.0f; - } - if ( alpha > 1.0f ) { - alpha = 1.0f; - } - - if ( alpha < 1.0f ) { - renderSystem->SetColor4( ( player->health <= 0.0f ) ? MS2SEC( gameLocal.slow.time ) : lastDamageTime, 1.0f, 1.0f, ( player->health <= 0.0f ) ? 0.0f : alpha ); - renderSystem->DrawStretchPic( 0.0f, 0.0f, 640.0f, 480.0f, 0.0f, 0.0f, 1.0f, 1.0f, tunnelMaterial ); - } - - if ( bfgVision ) { - renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, 1.0f ); - renderSystem->DrawStretchPic( 0.0f, 0.0f, 640.0f, 480.0f, 0.0f, 0.0f, 1.0f, 1.0f, bfgMaterial ); - } - - } - - // test a single material drawn over everything - if ( g_testPostProcess.GetString()[0] ) { - const idMaterial *mtr = declManager->FindMaterial( g_testPostProcess.GetString(), false ); - if ( !mtr ) { - common->Printf( "Material not found.\n" ); - g_testPostProcess.SetString( "" ); - } else { - renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, 1.0f ); - renderSystem->DrawStretchPic( 0.0f, 0.0f, 640.0f, 480.0f, 0.0f, 0.0f, 1.0f, 1.0f, mtr ); - } - } -} - - -/* -================= -idPlayerView::Flash - -flashes the player view with the given color -================= -*/ -void idPlayerView::Flash(idVec4 color, int time ) { - Fade(idVec4(0, 0, 0, 0), time); - fadeFromColor = colorWhite; -} - -/* -================= -idPlayerView::Fade - -used for level transition fades -assumes: color.w is 0 or 1 -================= -*/ -void idPlayerView::Fade( idVec4 color, int time ) { -#ifdef _D3XP - SetTimeState ts( player->timeGroup ); -#endif - - if ( !fadeTime ) { - fadeFromColor.Set( 0.0f, 0.0f, 0.0f, 1.0f - color[ 3 ] ); - } else { - fadeFromColor = fadeColor; - } - fadeToColor = color; - - if ( time <= 0 ) { - fadeRate = 0; - time = 0; - fadeColor = fadeToColor; - } else { - fadeRate = 1.0f / ( float )time; - } - - if ( gameLocal.realClientTime == 0 && time == 0 ) { - fadeTime = 1; - } else { - fadeTime = gameLocal.realClientTime + time; - } -} - -/* -================= -idPlayerView::ScreenFade -================= -*/ -void idPlayerView::ScreenFade() { - int msec; - float t; - - if ( !fadeTime ) { - return; - } - -#ifdef _D3XP - SetTimeState ts( player->timeGroup ); -#endif - - msec = fadeTime - gameLocal.realClientTime; - - if ( msec <= 0 ) { - fadeColor = fadeToColor; - if ( fadeColor[ 3 ] == 0.0f ) { - fadeTime = 0; - } - } else { - t = ( float )msec * fadeRate; - fadeColor = fadeFromColor * t + fadeToColor * ( 1.0f - t ); - } - - if ( fadeColor[ 3 ] != 0.0f ) { - renderSystem->SetColor4( fadeColor[ 0 ], fadeColor[ 1 ], fadeColor[ 2 ], fadeColor[ 3 ] ); - renderSystem->DrawStretchPic( 0, 0, 640, 480, 0, 0, 1, 1, declManager->FindMaterial( "_white" ) ); - } -} - -/* -=================== -idPlayerView::RenderPlayerView -=================== -*/ -void idPlayerView::RenderPlayerView( idUserInterface *hud ) { - const renderView_t *view = player->GetRenderView(); - - SingleView( hud, view ); - ScreenFade(); - - if ( net_clientLagOMeter.GetBool() && lagoMaterial && gameLocal.isClient ) { - renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, 1.0f ); - renderSystem->DrawStretchPic( 10.0f, 380.0f, 64.0f, 64.0f, 0.0f, 0.0f, 1.0f, 1.0f, lagoMaterial ); - } -} - -#ifdef _D3XP -/* -=================== -idPlayerView::WarpVision -=================== -*/ -int idPlayerView::AddWarp( idVec3 worldOrigin, float centerx, float centery, float initialRadius, float durationMsec ) { - FullscreenFX_Warp *fx = (FullscreenFX_Warp*)( fxManager->FindFX( "warp" ) ); - - if ( fx ) { - fx->EnableGrabber( true ); - return 1; - } - - return 1; -} - -void idPlayerView::FreeWarp( int id ) { - FullscreenFX_Warp *fx = (FullscreenFX_Warp*)( fxManager->FindFX( "warp" ) ); - - if ( fx ) { - fx->EnableGrabber( false ); - return; - } -} - - - - - -/* -================== -FxFader::FxFader -================== -*/ -FxFader::FxFader() { - time = 0; - state = FX_STATE_OFF; - alpha = 0; - msec = 1000; -} - -/* -================== -FxFader::SetTriggerState -================== -*/ -bool FxFader::SetTriggerState( bool active ) { - - // handle on/off states - if ( active && state == FX_STATE_OFF ) { - state = FX_STATE_RAMPUP; - time = gameLocal.slow.time + msec; - } - else if ( !active && state == FX_STATE_ON ) { - state = FX_STATE_RAMPDOWN; - time = gameLocal.slow.time + msec; - } - - // handle rampup/rampdown states - if ( state == FX_STATE_RAMPUP ) { - if ( gameLocal.slow.time >= time ) { - state = FX_STATE_ON; - } - } - else if ( state == FX_STATE_RAMPDOWN ) { - if ( gameLocal.slow.time >= time ) { - state = FX_STATE_OFF; - } - } - - // compute alpha - switch ( state ) { - case FX_STATE_ON: alpha = 1; break; - case FX_STATE_OFF: alpha = 0; break; - case FX_STATE_RAMPUP: alpha = 1 - (float)( time - gameLocal.slow.time ) / msec; break; - case FX_STATE_RAMPDOWN: alpha = (float)( time - gameLocal.slow.time ) / msec; break; - } - - if ( alpha > 0 ) { - return true; - } - else { - return false; - } -} - -/* -================== -FxFader::Save -================== -*/ -void FxFader::Save( idSaveGame *savefile ) { - savefile->WriteInt( time ); - savefile->WriteInt( state ); - savefile->WriteFloat( alpha ); - savefile->WriteInt( msec ); -} - -/* -================== -FxFader::Restore -================== -*/ -void FxFader::Restore( idRestoreGame *savefile ) { - savefile->ReadInt( time ); - savefile->ReadInt( state ); - savefile->ReadFloat( alpha ); - savefile->ReadInt( msec ); -} - - - - - -/* -================== -FullscreenFX_Helltime::Save -================== -*/ -void FullscreenFX::Save( idSaveGame *savefile ) { - fader.Save( savefile ); -} - -/* -================== -FullscreenFX_Helltime::Restore -================== -*/ -void FullscreenFX::Restore( idRestoreGame *savefile ) { - fader.Restore( savefile ); -} - - -/* -================== -FullscreenFX_Helltime::Initialize -================== -*/ -void FullscreenFX_Helltime::Initialize() { - acInitMaterials[0] = declManager->FindMaterial( "textures/smf/bloodorb1/ac_init" ); - acInitMaterials[1] = declManager->FindMaterial( "textures/smf/bloodorb2/ac_init" ); - acInitMaterials[2] = declManager->FindMaterial( "textures/smf/bloodorb3/ac_init" ); - - acCaptureMaterials[0] = declManager->FindMaterial( "textures/smf/bloodorb1/ac_capture" ); - acCaptureMaterials[1] = declManager->FindMaterial( "textures/smf/bloodorb2/ac_capture" ); - acCaptureMaterials[2] = declManager->FindMaterial( "textures/smf/bloodorb3/ac_capture" ); - - acDrawMaterials[0] = declManager->FindMaterial( "textures/smf/bloodorb1/ac_draw" ); - acDrawMaterials[1] = declManager->FindMaterial( "textures/smf/bloodorb2/ac_draw" ); - acDrawMaterials[2] = declManager->FindMaterial( "textures/smf/bloodorb3/ac_draw" ); - - crCaptureMaterials[0] = declManager->FindMaterial( "textures/smf/bloodorb1/cr_capture" ); - crCaptureMaterials[1] = declManager->FindMaterial( "textures/smf/bloodorb2/cr_capture" ); - crCaptureMaterials[2] = declManager->FindMaterial( "textures/smf/bloodorb3/cr_capture" ); - - crDrawMaterials[0] = declManager->FindMaterial( "textures/smf/bloodorb1/cr_draw" ); - crDrawMaterials[1] = declManager->FindMaterial( "textures/smf/bloodorb2/cr_draw" ); - crDrawMaterials[2] = declManager->FindMaterial( "textures/smf/bloodorb3/cr_draw" ); - - clearAccumBuffer = true; -} - -/* -================== -FullscreenFX_Helltime::DetermineLevel -================== -*/ -int FullscreenFX_Helltime::DetermineLevel() { - idPlayer *player; - int testfx = g_testHelltimeFX.GetInteger(); - - // for testing purposes - if ( testfx >= 0 && testfx < 3 ) { - return testfx; - } - - player = fxman->GetPlayer(); - - if ( player->PowerUpActive( INVULNERABILITY ) ) { - return 2; - } - else if ( player->PowerUpActive( BERSERK ) ) { - return 1; - } - else if ( player->PowerUpActive( HELLTIME ) ) { - return 0; - } - - return -1; -} - -/* -================== -FullscreenFX_Helltime::Active -================== -*/ -bool FullscreenFX_Helltime::Active() { - - if ( gameLocal.inCinematic || gameLocal.isMultiplayer ) { - return false; - } - - if ( DetermineLevel() >= 0 ) { - return true; - } - else { - // latch the clear flag - if ( fader.GetAlpha() == 0 ) { - clearAccumBuffer = true; - } - } - - return false; -} - -/* -================== -FullscreenFX_Helltime::AccumPass -================== -*/ -void FullscreenFX_Helltime::AccumPass( const renderView_t *view ) { - idVec2 shiftScale; - int level = DetermineLevel(); - - // for testing - if ( level < 0 || level > 2 ) { - level = 0; - } - - shiftScale = fxman->GetShiftScale(); - renderSystem->SetColor4( 1, 1, 1, 1 ); - - // capture pass - if ( clearAccumBuffer ) { - clearAccumBuffer = false; - renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 1, 1, 0, acInitMaterials[level] ); - } - else { - renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 1, 1, 0, acCaptureMaterials[level] ); - renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, shiftScale.y, shiftScale.x, 0, crCaptureMaterials[level] ); - } - - renderSystem->CaptureRenderToImage( "_accum" ); -} - -/* -================== -FullscreenFX_Helltime::HighQuality -================== -*/ -void FullscreenFX_Helltime::HighQuality() { - idVec2 shiftScale; - int level = DetermineLevel(); - - // for testing - if ( level < 0 || level > 2 ) { - level = 0; - } - - shiftScale = fxman->GetShiftScale(); - renderSystem->SetColor4( 1, 1, 1, 1 ); - - // draw pass - renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 1, 1, 0, acDrawMaterials[level] ); - renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, shiftScale.y, shiftScale.x, 0, crDrawMaterials[level] ); -} - -/* -================== -FullscreenFX_Helltime::Restore -================== -*/ -void FullscreenFX_Helltime::Restore( idRestoreGame *savefile ) { - FullscreenFX::Restore( savefile ); - - // latch the clear flag - clearAccumBuffer = true; -} - - - - - -/* -================== -FullscreenFX_Multiplayer::Initialize -================== -*/ -void FullscreenFX_Multiplayer::Initialize() { - acInitMaterials = declManager->FindMaterial( "textures/smf/multiplayer1/ac_init" ); - acCaptureMaterials = declManager->FindMaterial( "textures/smf/multiplayer1/ac_capture" ); - acDrawMaterials = declManager->FindMaterial( "textures/smf/multiplayer1/ac_draw" ); - crCaptureMaterials = declManager->FindMaterial( "textures/smf/multiplayer1/cr_capture" ); - crDrawMaterials = declManager->FindMaterial( "textures/smf/multiplayer1/cr_draw" ); - clearAccumBuffer = true; -} - -/* -================== -FullscreenFX_Multiplayer::DetermineLevel -================== -*/ -int FullscreenFX_Multiplayer::DetermineLevel() { - idPlayer *player; - int testfx = g_testMultiplayerFX.GetInteger(); - - // for testing purposes - if ( testfx >= 0 && testfx < 3 ) { - return testfx; - } - - player = fxman->GetPlayer(); - - if ( player->PowerUpActive( INVULNERABILITY ) ) { - return 2; - } - //else if ( player->PowerUpActive( HASTE ) ) { - // return 1; - //} - else if ( player->PowerUpActive( BERSERK ) ) { - return 0; - } - - return -1; -} - -/* -================== -FullscreenFX_Multiplayer::Active -================== -*/ -bool FullscreenFX_Multiplayer::Active() { - - if ( !gameLocal.isMultiplayer && g_testMultiplayerFX.GetInteger() == -1 ) { - return false; - } - - if ( DetermineLevel() >= 0 ) { - return true; - } - else { - // latch the clear flag - if ( fader.GetAlpha() == 0 ) { - clearAccumBuffer = true; - } - } - - return false; -} - -/* -================== -FullscreenFX_Multiplayer::AccumPass -================== -*/ -void FullscreenFX_Multiplayer::AccumPass( const renderView_t *view ) { - idVec2 shiftScale; - int level = DetermineLevel(); - - // for testing - if ( level < 0 || level > 2 ) { - level = 0; - } - - shiftScale = fxman->GetShiftScale(); - renderSystem->SetColor4( 1, 1, 1, 1 ); - - // capture pass - if ( clearAccumBuffer ) { - clearAccumBuffer = false; - renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 1, 1, 0, acInitMaterials ); - } - else { - renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 1, 1, 0, acCaptureMaterials ); - renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, shiftScale.y, shiftScale.x, 0, crCaptureMaterials ); - } - - renderSystem->CaptureRenderToImage( "_accum" ); -} - -/* -================== -FullscreenFX_Multiplayer::HighQuality -================== -*/ -void FullscreenFX_Multiplayer::HighQuality() { - idVec2 shiftScale; - int level = DetermineLevel(); - - // for testing - if ( level < 0 || level > 2 ) { - level = 0; - } - - shiftScale = fxman->GetShiftScale(); - renderSystem->SetColor4( 1, 1, 1, 1 ); - - // draw pass - renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 1, 1, 0, acDrawMaterials ); - renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, shiftScale.y, shiftScale.x, 0, crDrawMaterials ); -} - -/* -================== -FullscreenFX_Multiplayer::Restore -================== -*/ -void FullscreenFX_Multiplayer::Restore( idRestoreGame *savefile ) { - FullscreenFX::Restore( savefile ); - - // latch the clear flag - clearAccumBuffer = true; -} - - - - - -/* -================== -FullscreenFX_Warp::Initialize -================== -*/ -void FullscreenFX_Warp::Initialize() { - material = declManager->FindMaterial( "textures/smf/warp" ); - grabberEnabled = false; - startWarpTime = 0; -} - -/* -================== -FullscreenFX_Warp::Active -================== -*/ -bool FullscreenFX_Warp::Active() { - if ( grabberEnabled ) { - return true; - } - - return false; -} - -/* -================== -FullscreenFX_Warp::Save -================== -*/ -void FullscreenFX_Warp::Save( idSaveGame *savefile ) { - FullscreenFX::Save( savefile ); - - savefile->WriteBool( grabberEnabled ); - savefile->WriteInt( startWarpTime ); -} - -/* -================== -FullscreenFX_Warp::Restore -================== -*/ -void FullscreenFX_Warp::Restore( idRestoreGame *savefile ) { - FullscreenFX::Restore( savefile ); - - savefile->ReadBool( grabberEnabled ); - savefile->ReadInt( startWarpTime ); -} - -/* -================== -FullscreenFX_Warp::DrawWarp -================== -*/ -void FullscreenFX_Warp::DrawWarp( WarpPolygon_t wp, float interp ) { - idVec4 mid1_uv, mid2_uv; - idVec4 mid1, mid2; - idVec2 drawPts[6], shiftScale; - WarpPolygon_t trans; - - trans = wp; - shiftScale = fxman->GetShiftScale(); - - // compute mid points - mid1 = trans.outer1 * ( interp ) + trans.center * ( 1 - interp ); - mid2 = trans.outer2 * ( interp ) + trans.center * ( 1 - interp ); - mid1_uv = trans.outer1 * ( 0.5 ) + trans.center * ( 1 - 0.5 ); - mid2_uv = trans.outer2 * ( 0.5 ) + trans.center * ( 1 - 0.5 ); - - // draw [outer1, mid2, mid1] - drawPts[0].Set( trans.outer1.x, trans.outer1.y ); - drawPts[1].Set( mid2.x, mid2.y ); - drawPts[2].Set( mid1.x, mid1.y ); - drawPts[3].Set( trans.outer1.z, trans.outer1.w ); - drawPts[4].Set( mid2_uv.z, mid2_uv.w ); - drawPts[5].Set( mid1_uv.z, mid1_uv.w ); - for ( int j = 0; j < 3; j++ ) { - drawPts[j+3].x *= shiftScale.x; - drawPts[j+3].y *= shiftScale.y; - } - renderSystem->DrawStretchTri( drawPts[0], drawPts[1], drawPts[2], drawPts[3], drawPts[4], drawPts[5], material ); - - // draw [outer1, outer2, mid2] - drawPts[0].Set( trans.outer1.x, trans.outer1.y ); - drawPts[1].Set( trans.outer2.x, trans.outer2.y ); - drawPts[2].Set( mid2.x, mid2.y ); - drawPts[3].Set( trans.outer1.z, trans.outer1.w ); - drawPts[4].Set( trans.outer2.z, trans.outer2.w ); - drawPts[5].Set( mid2_uv.z, mid2_uv.w ); - for ( int j = 0; j < 3; j++ ) { - drawPts[j+3].x *= shiftScale.x; - drawPts[j+3].y *= shiftScale.y; - } - renderSystem->DrawStretchTri( drawPts[0], drawPts[1], drawPts[2], drawPts[3], drawPts[4], drawPts[5], material ); - - // draw [mid1, mid2, center] - drawPts[0].Set( mid1.x, mid1.y ); - drawPts[1].Set( mid2.x, mid2.y ); - drawPts[2].Set( trans.center.x, trans.center.y ); - drawPts[3].Set( mid1_uv.z, mid1_uv.w ); - drawPts[4].Set( mid2_uv.z, mid2_uv.w ); - drawPts[5].Set( trans.center.z, trans.center.w ); - for ( int j = 0; j < 3; j++ ) { - drawPts[j+3].x *= shiftScale.x; - drawPts[j+3].y *= shiftScale.y; - } - renderSystem->DrawStretchTri( drawPts[0], drawPts[1], drawPts[2], drawPts[3], drawPts[4], drawPts[5], material ); -} - -/* -================== -FullscreenFX_Warp::HighQuality -================== -*/ -void FullscreenFX_Warp::HighQuality() { - float x1, y1, x2, y2, radius, interp; - idVec2 center; - int STEP = 9; - - interp = ( idMath::Sin( (float)( gameLocal.slow.time - startWarpTime ) / 1000 ) + 1 ) / 2.f; - interp = 0.7 * ( 1 - interp ) + 0.3 * ( interp ); - - // draw the warps - center.x = 320; - center.y = 240; - radius = 200; - - for ( float i = 0; i < 360; i += STEP ) { - // compute the values - x1 = idMath::Sin( DEG2RAD( i ) ); - y1 = idMath::Cos( DEG2RAD( i ) ); - - x2 = idMath::Sin( DEG2RAD( i + STEP ) ); - y2 = idMath::Cos( DEG2RAD( i + STEP ) ); - - // add warp polygon - WarpPolygon_t p; - - p.outer1.x = center.x + x1 * radius; - p.outer1.y = center.y + y1 * radius; - p.outer1.z = p.outer1.x / 640.f; - p.outer1.w = 1 - ( p.outer1.y / 480.f ); - - p.outer2.x = center.x + x2 * radius; - p.outer2.y = center.y + y2 * radius; - p.outer2.z = p.outer2.x / 640.f; - p.outer2.w = 1 - ( p.outer2.y / 480.f ); - - p.center.x = center.x; - p.center.y = center.y; - p.center.z = p.center.x / 640.f; - p.center.w = 1 - ( p.center.y / 480.f ); - - // draw it - DrawWarp( p, interp ); - } -} - - - - - -/* -================== -FullscreenFX_EnviroSuit::Initialize -================== -*/ -void FullscreenFX_EnviroSuit::Initialize() { - material = declManager->FindMaterial( "textures/smf/enviro_suit" ); -} - -/* -================== -FullscreenFX_EnviroSuit::Active -================== -*/ -bool FullscreenFX_EnviroSuit::Active() { - idPlayer *player; - - player = fxman->GetPlayer(); - - if ( player->PowerUpActive( ENVIROSUIT ) ) { - return true; - } - - return false; -} - -/* -================== -FullscreenFX_EnviroSuit::HighQuality -================== -*/ -void FullscreenFX_EnviroSuit::HighQuality() { - renderSystem->SetColor4( 1, 1, 1, 1 ); - renderSystem->DrawStretchPic( 0.0f, 0.0f, 640.0f, 480.0f, 0.0f, 0.0f, 1.0f, 1.0f, material ); -} - - - - - -/* -================== -FullscreenFX_DoubleVision::Initialize -================== -*/ -void FullscreenFX_DoubleVision::Initialize() { - material = declManager->FindMaterial( "textures/smf/doubleVision" ); -} - -/* -================== -FullscreenFX_DoubleVision::Active -================== -*/ -bool FullscreenFX_DoubleVision::Active() { - - if ( gameLocal.fast.time < fxman->GetPlayerView()->dvFinishTime ) { - return true; - } - - return false; -} - -/* -================== -FullscreenFX_DoubleVision::HighQuality -================== -*/ -void FullscreenFX_DoubleVision::HighQuality() { - int offset = fxman->GetPlayerView()->dvFinishTime - gameLocal.fast.time; - float scale = offset * g_dvAmplitude.GetFloat(); - idPlayer *player; - idVec2 shiftScale; - - // for testing purposes - if ( !Active() ) { - static int test = 0; - if ( test > 312 ) { - test = 0; - } - - offset = test++; - scale = offset * g_dvAmplitude.GetFloat(); - } - - player = fxman->GetPlayer(); - shiftScale = fxman->GetShiftScale(); - - offset *= 2; // crutch up for higher res - - // set the scale and shift - if ( scale > 0.5f ) { - scale = 0.5f; - } - float shift = scale * sin( sqrtf( (float)offset ) * g_dvFrequency.GetFloat() ); - shift = fabs( shift ); - - // carry red tint if in berserk mode - idVec4 color(1, 1, 1, 1); - if ( gameLocal.fast.time < player->inventory.powerupEndTime[ BERSERK ] ) { - color.y = 0; - color.z = 0; - } - - if ( !gameLocal.isMultiplayer && (gameLocal.fast.time < player->inventory.powerupEndTime[ HELLTIME ] || gameLocal.fast.time < player->inventory.powerupEndTime[ INVULNERABILITY ])) { - color.y = 0; - color.z = 0; - } - - renderSystem->SetColor4( color.x, color.y, color.z, 1.0f ); - renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, shift, shiftScale.y, shiftScale.x, 0, material ); - renderSystem->SetColor4( color.x, color.y, color.z, 0.5f ); - renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, shiftScale.y, (1-shift) * shiftScale.x, 0, material ); -} - - - - -/* -================== -FullscreenFX_InfluenceVision::Initialize -================== -*/ -void FullscreenFX_InfluenceVision::Initialize() { - -} - -/* -================== -FullscreenFX_InfluenceVision::Active -================== -*/ -bool FullscreenFX_InfluenceVision::Active() { - idPlayer *player; - - player = fxman->GetPlayer(); - - if ( player->GetInfluenceMaterial() || player->GetInfluenceEntity() ) { - return true; - } - - return false; -} - -/* -================== -FullscreenFX_InfluenceVision::HighQuality -================== -*/ -void FullscreenFX_InfluenceVision::HighQuality() { - float distance = 0.0f; - float pct = 1.0f; - idPlayer *player; - idVec2 shiftScale; - - shiftScale = fxman->GetShiftScale(); - player = fxman->GetPlayer(); - - if ( player->GetInfluenceEntity() ) { - distance = ( player->GetInfluenceEntity()->GetPhysics()->GetOrigin() - player->GetPhysics()->GetOrigin() ).Length(); - if ( player->GetInfluenceRadius() != 0.0f && distance < player->GetInfluenceRadius() ) { - pct = distance / player->GetInfluenceRadius(); - pct = 1.0f - idMath::ClampFloat( 0.0f, 1.0f, pct ); - } - } - - if ( player->GetInfluenceMaterial() ) { - renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, pct ); - renderSystem->DrawStretchPic( 0.0f, 0.0f, 640.0f, 480.0f, 0.0f, 0.0f, 1.0f, 1.0f, player->GetInfluenceMaterial() ); - } else if ( player->GetInfluenceEntity() == NULL ) { - return; - } else { -// int offset = 25 + sinf( gameLocal.slow.time ); -// DoubleVision( hud, view, pct * offset ); - } -} - - - - -/* -================== -FullscreenFX_Bloom::Initialize -================== -*/ -void FullscreenFX_Bloom::Initialize() { - drawMaterial = declManager->FindMaterial( "textures/smf/bloom2/draw" ); - initMaterial = declManager->FindMaterial( "textures/smf/bloom2/init" ); - currentMaterial = declManager->FindMaterial( "textures/smf/bloom2/currentMaterial" ); - - currentIntensity = 0; - targetIntensity = 0; -} - -/* -================== -FullscreenFX_Bloom::Active -================== -*/ -bool FullscreenFX_Bloom::Active() { - idPlayer *player; - - player = fxman->GetPlayer(); - - if ( player && player->bloomEnabled ) { - return true; - } - - return false; -} - -/* -================== -FullscreenFX_Bloom::HighQuality -================== -*/ -void FullscreenFX_Bloom::HighQuality() { - float shift, delta; - idVec2 shiftScale; - idPlayer *player; - int num; - - shift = 1; - player = fxman->GetPlayer(); - shiftScale = fxman->GetShiftScale(); - renderSystem->SetColor4( 1, 1, 1, 1 ); - - // if intensity value is different, start the blend - targetIntensity = g_testBloomIntensity.GetFloat(); - - if ( player && player->bloomEnabled ) { - targetIntensity = player->bloomIntensity; - } - - delta = targetIntensity - currentIntensity; - float step = 0.001f; - - if ( step < fabs( delta ) ) { - if ( delta < 0 ) { - step = -step; - } - - currentIntensity += step; - } - - // draw the blends - num = g_testBloomNumPasses.GetInteger(); - - for ( int i = 0; i < num; i++ ) { - float s1 = 0, t1 = 0, s2 = 1, t2 = 1; - float alpha; - - // do the center scale - s1 -= 0.5; - s1 *= shift; - s1 += 0.5; - s1 *= shiftScale.x; - - t1 -= 0.5; - t1 *= shift; - t1 += 0.5; - t1 *= shiftScale.y; - - s2 -= 0.5; - s2 *= shift; - s2 += 0.5; - s2 *= shiftScale.x; - - t2 -= 0.5; - t2 *= shift; - t2 += 0.5; - t2 *= shiftScale.y; - - // draw it - if ( num == 1 ) { - alpha = 1; - } - else { - alpha = 1 - (float)i / ( num - 1 ); - } - - renderSystem->SetColor4( alpha, alpha, alpha, 1 ); - renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, s1, t2, s2, t1, drawMaterial ); - - shift += currentIntensity; - } -} - -/* -================== -FullscreenFX_Bloom::Save -================== -*/ -void FullscreenFX_Bloom::Save( idSaveGame *savefile ) { - FullscreenFX::Save( savefile ); - savefile->WriteFloat( currentIntensity ); - savefile->WriteFloat( targetIntensity ); -} - -/* -================== -FullscreenFX_Bloom::Restore -================== -*/ -void FullscreenFX_Bloom::Restore( idRestoreGame *savefile ) { - FullscreenFX::Restore( savefile ); - savefile->ReadFloat( currentIntensity ); - savefile->ReadFloat( targetIntensity ); -} - - - - - - -/* -================== -FullscreenFXManager::FullscreenFXManager -================== -*/ -FullscreenFXManager::FullscreenFXManager() { - highQualityMode = false; - playerView = NULL; - blendBackMaterial = NULL; - shiftScale.Set( 0, 0 ); -} - -/* -================== -FullscreenFXManager::~FullscreenFXManager -================== -*/ -FullscreenFXManager::~FullscreenFXManager() { - -} - -/* -================== -FullscreenFXManager::FindFX -================== -*/ -FullscreenFX* FullscreenFXManager::FindFX( idStr name ) { - for ( int i = 0; i < fx.Num(); i++ ) { - if ( fx[i]->GetName() == name ) { - return fx[i]; - } - } - - return NULL; -} - -/* -================== -FullscreenFXManager::CreateFX -================== -*/ -void FullscreenFXManager::CreateFX( idStr name, idStr fxtype, int fade ) { - FullscreenFX *pfx = NULL; - - if ( fxtype == "helltime" ) { - pfx = new FullscreenFX_Helltime; - } - else if ( fxtype == "warp" ) { - pfx = new FullscreenFX_Warp; - } - else if ( fxtype == "envirosuit" ) { - pfx = new FullscreenFX_EnviroSuit; - } - else if ( fxtype == "doublevision" ) { - pfx = new FullscreenFX_DoubleVision; - } - else if ( fxtype == "multiplayer" ) { - pfx = new FullscreenFX_Multiplayer; - } - else if ( fxtype == "influencevision" ) { - pfx = new FullscreenFX_InfluenceVision; - } - else if ( fxtype == "bloom" ) { - pfx = new FullscreenFX_Bloom; - } - else { - assert( 0 ); - } - - if ( pfx ) { - pfx->Initialize(); - pfx->SetFXManager( this ); - pfx->SetName( name ); - pfx->SetFadeSpeed( fade ); - fx.Append( pfx ); - } -} - -/* -================== -FullscreenFXManager::Initialize -================== -*/ -void FullscreenFXManager::Initialize( idPlayerView *pv ) { - // set the playerview - playerView = pv; - blendBackMaterial = declManager->FindMaterial( "textures/smf/blendBack" ); - - // allocate the fx - CreateFX( "helltime", "helltime", 1000 ); - CreateFX( "warp", "warp", 0 ); - CreateFX( "envirosuit", "envirosuit", 500 ); - CreateFX( "doublevision", "doublevision", 0 ); - CreateFX( "multiplayer", "multiplayer", 1000 ); - CreateFX( "influencevision", "influencevision", 1000 ); - CreateFX( "bloom", "bloom", 0 ); - - // pre-cache the texture grab so we dont hitch - renderSystem->CropRenderSize( 512, 512, true ); - renderSystem->CaptureRenderToImage( "_accum" ); - renderSystem->UnCrop(); - - renderSystem->CropRenderSize( 512, 256, true ); - renderSystem->CaptureRenderToImage( "_scratch" ); - renderSystem->UnCrop(); - - renderSystem->CaptureRenderToImage( "_currentRender" ); -} - -/* -================== -FullscreenFXManager::Blendback -================== -*/ -void FullscreenFXManager::Blendback( float alpha ) { - // alpha fade - if ( alpha < 1.f ) { - renderSystem->SetColor4( 1, 1, 1, 1 - alpha ); - renderSystem->DrawStretchPic( 0.0f, 0.0f, 640.0f, 480.0f, 0.0f, shiftScale.y, shiftScale.x, 0.f, blendBackMaterial ); - } -} - -/* -================== -FullscreenFXManager::Save -================== -*/ -void FullscreenFXManager::Save( idSaveGame *savefile ) { - savefile->WriteBool( highQualityMode ); - savefile->WriteVec2( shiftScale ); - - for ( int i = 0; i < fx.Num(); i++ ) { - FullscreenFX *pfx = fx[i]; - pfx->Save( savefile ); - } -} - -/* -================== -FullscreenFXManager::Restore -================== -*/ -void FullscreenFXManager::Restore( idRestoreGame *savefile ) { - savefile->ReadBool( highQualityMode ); - savefile->ReadVec2( shiftScale ); - - for ( int i = 0; i < fx.Num(); i++ ) { - FullscreenFX *pfx = fx[i]; - pfx->Restore( savefile ); - } -} - -/* -================== -FullscreenFXManager::CaptureCurrentRender -================== -*/ -void FullscreenFXManager::CaptureCurrentRender() { - renderSystem->CaptureRenderToImage( "_currentRender" ); -} - -/* -================== -FullscreenFXManager::Process -================== -*/ -void FullscreenFXManager::Process( const renderView_t *view ) { - bool allpass = false; - - if ( g_testFullscreenFX.GetInteger() == -2 ) { - allpass = true; - } - - if ( g_lowresFullscreenFX.GetBool() ) { - highQualityMode = false; - } - else { - highQualityMode = true; - } - - // compute the shift scale - if ( highQualityMode ) { - int vidWidth, vidHeight; - renderSystem->GetGLSettings( vidWidth, vidHeight ); - - float pot; - int w = vidWidth; - pot = MakePowerOfTwo( w ); - shiftScale.x = (float)w / pot; - - int h = vidHeight; - pot = MakePowerOfTwo( h ); - shiftScale.y = (float)h / pot; - } - else { - // if we're in low-res mode, shrink view down - shiftScale.x = 1; - shiftScale.y = 1; - renderSystem->CropRenderSize( 512, 512, true ); - } - - // do the first render - gameRenderWorld->RenderScene( view ); - - // do the process - for ( int i = 0; i < fx.Num(); i++ ) { - FullscreenFX *pfx = fx[i]; - bool drawIt = false; - - // determine if we need to draw - if ( pfx->Active() || g_testFullscreenFX.GetInteger() == i || allpass ) { - drawIt = pfx->SetTriggerState( true ); - } - else { - drawIt = pfx->SetTriggerState( false ); - } - - // do the actual drawing - if ( drawIt ) { - // we need to dump to _currentRender - CaptureCurrentRender(); - - // handle the accum pass if we have one - if ( pfx->HasAccum() ) { - - // if we're in high quality mode, we need to crop the accum pass - if ( highQualityMode ) { - renderSystem->CropRenderSize( 512, 512, true ); - pfx->AccumPass( view ); - renderSystem->UnCrop(); - } - else { - pfx->AccumPass( view ); - } - } - - // do the high quality pass - pfx->HighQuality(); - - // do the blendback - Blendback( pfx->GetFadeAlpha() ); - } - } - - if ( !highQualityMode ) { - // we need to dump to _currentRender - CaptureCurrentRender(); - - // uncrop view - renderSystem->UnCrop(); - - // draw the final full-screen image - renderSystem->SetColor4( 1, 1, 1, 1 ); - renderSystem->DrawStretchPic( 0.0f, 0.0f, 640.0f, 480.0f, 0.0f, 1, 1, 0.f, blendBackMaterial ); - } -} - - - -#endif diff --git a/d3xp/PlayerView.h b/d3xp/PlayerView.h deleted file mode 100644 index 502abb87..00000000 --- a/d3xp/PlayerView.h +++ /dev/null @@ -1,437 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __GAME_PLAYERVIEW_H__ -#define __GAME_PLAYERVIEW_H__ - -#include "idlib/math/Vector.h" -#include "idlib/Dict.h" -#include "renderer/Material.h" -#include "renderer/RenderWorld.h" - -class idSaveGame; -class idRestoreGame; - -/* -=============================================================================== - - Player view. - -=============================================================================== -*/ - -// screenBlob_t are for the on-screen damage claw marks, etc -typedef struct { - const idMaterial * material; - float x, y, w, h; - float s1, t1, s2, t2; - int finishTime; - int startFadeTime; - float driftAmount; -} screenBlob_t; - -#define MAX_SCREEN_BLOBS 8 - - - - - -#ifdef _D3XP -class WarpPolygon_t { -public: - idVec4 outer1; - idVec4 outer2; - idVec4 center; -}; - -class Warp_t { -public: - int id; - bool active; - - int startTime; - float initialRadius; - - idVec3 worldOrigin; - idVec2 screenOrigin; - - int durationMsec; - - idList polys; -}; -#endif - - - - - - - -#ifdef _D3XP - -class idPlayerView; -class FullscreenFXManager; - - -/* -================== -FxFader -================== -*/ -class FxFader { - enum { - FX_STATE_OFF, - FX_STATE_RAMPUP, - FX_STATE_RAMPDOWN, - FX_STATE_ON - }; - - int time; - int state; - float alpha; - int msec; - -public: - FxFader(); - - // primary functions - bool SetTriggerState( bool active ); - - virtual void Save( idSaveGame *savefile ); - virtual void Restore( idRestoreGame *savefile ); - - // fader functions - void SetFadeTime( int t ) { msec = t; }; - int GetFadeTime() { return msec; }; - - // misc functions - float GetAlpha() { return alpha; }; -}; - - -/* -================== -FullscreenFX -================== -*/ -class FullscreenFX { -protected: - idStr name; - FxFader fader; - FullscreenFXManager *fxman; - -public: - FullscreenFX() { fxman = NULL; }; - virtual ~FullscreenFX() { }; - - virtual void Initialize() = 0; - virtual bool Active() = 0; - virtual void HighQuality() = 0; - virtual void LowQuality() { }; - virtual void AccumPass( const renderView_t *view ) { }; - virtual bool HasAccum() { return false; }; - - void SetName( idStr n ) { name = n; }; - idStr GetName() { return name; }; - - void SetFXManager( FullscreenFXManager *fx ) { fxman = fx; }; - - bool SetTriggerState( bool state ) { return fader.SetTriggerState( state ); }; - void SetFadeSpeed( int msec ) { fader.SetFadeTime( msec ); }; - float GetFadeAlpha() { return fader.GetAlpha(); }; - - virtual void Save( idSaveGame *savefile ); - virtual void Restore( idRestoreGame *savefile ); -}; - -/* -================== -FullscreenFX_Helltime -================== -*/ -class FullscreenFX_Helltime : public FullscreenFX { - const idMaterial* acInitMaterials[3]; - const idMaterial* acCaptureMaterials[3]; - const idMaterial* acDrawMaterials[3]; - const idMaterial* crCaptureMaterials[3]; - const idMaterial* crDrawMaterials[3]; - bool clearAccumBuffer; - - int DetermineLevel(); - -public: - virtual void Initialize(); - virtual bool Active(); - virtual void HighQuality(); - virtual void AccumPass( const renderView_t *view ); - virtual bool HasAccum() { return true; }; - - virtual void Restore( idRestoreGame *savefile ); -}; - -/* -================== -FullscreenFX_Multiplayer -================== -*/ -class FullscreenFX_Multiplayer : public FullscreenFX { - const idMaterial* acInitMaterials; - const idMaterial* acCaptureMaterials; - const idMaterial* acDrawMaterials; - const idMaterial* crCaptureMaterials; - const idMaterial* crDrawMaterials; - bool clearAccumBuffer; - - int DetermineLevel(); - -public: - virtual void Initialize(); - virtual bool Active(); - virtual void HighQuality(); - virtual void AccumPass( const renderView_t *view ); - virtual bool HasAccum() { return true; }; - - virtual void Restore( idRestoreGame *savefile ); -}; - -/* -================== -FullscreenFX_Warp -================== -*/ -class FullscreenFX_Warp : public FullscreenFX { - const idMaterial* material; - bool grabberEnabled; - int startWarpTime; - - void DrawWarp( WarpPolygon_t wp, float interp ); - -public: - virtual void Initialize(); - virtual bool Active(); - virtual void HighQuality(); - - void EnableGrabber( bool active ) { grabberEnabled = active; startWarpTime = gameLocal.slow.time; }; - - virtual void Save( idSaveGame *savefile ); - virtual void Restore( idRestoreGame *savefile ); -}; - -/* -================== -FullscreenFX_EnviroSuit -================== -*/ -class FullscreenFX_EnviroSuit : public FullscreenFX { - const idMaterial* material; - -public: - virtual void Initialize(); - virtual bool Active(); - virtual void HighQuality(); -}; - -/* -================== -FullscreenFX_DoubleVision -================== -*/ -class FullscreenFX_DoubleVision : public FullscreenFX { - const idMaterial* material; - -public: - virtual void Initialize(); - virtual bool Active(); - virtual void HighQuality(); -}; - -/* -================== -FullscreenFX_InfluenceVision -================== -*/ -class FullscreenFX_InfluenceVision : public FullscreenFX { - -public: - virtual void Initialize(); - virtual bool Active(); - virtual void HighQuality(); -}; - -/* -================== -FullscreenFX_Bloom -================== -*/ -class FullscreenFX_Bloom : public FullscreenFX { - const idMaterial* drawMaterial; - const idMaterial* initMaterial; - const idMaterial* currentMaterial; - - float currentIntensity; - float targetIntensity; - -public: - virtual void Initialize(); - virtual bool Active(); - virtual void HighQuality(); - - virtual void Save( idSaveGame *savefile ); - virtual void Restore( idRestoreGame *savefile ); -}; - - - -/* -================== -FullscreenFXManager -================== -*/ -class FullscreenFXManager { - idList fx; - bool highQualityMode; - idVec2 shiftScale; - - idPlayerView *playerView; - const idMaterial* blendBackMaterial; - - void CreateFX( idStr name, idStr fxtype, int fade ); - -public: - FullscreenFXManager(); - virtual ~FullscreenFXManager(); - - void Initialize( idPlayerView *pv ); - - void Process( const renderView_t *view ); - void CaptureCurrentRender(); - void Blendback( float alpha ); - - idVec2 GetShiftScale() { return shiftScale; }; - idPlayerView* GetPlayerView() { return playerView; }; - idPlayer* GetPlayer() { return gameLocal.GetLocalPlayer(); }; - - int GetNum() { return fx.Num(); }; - FullscreenFX* GetFX( int index ) { return fx[index]; }; - FullscreenFX* FindFX( idStr name ); - - void Save( idSaveGame *savefile ); - void Restore( idRestoreGame *savefile ); -}; - -#endif - - - - - - - - - -class idPlayerView { -public: - idPlayerView(); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void SetPlayerEntity( class idPlayer *playerEnt ); - - void ClearEffects( void ); - - void DamageImpulse( idVec3 localKickDir, const idDict *damageDef ); - - void WeaponFireFeedback( const idDict *weaponDef ); - - idAngles AngleOffset( void ) const; // returns the current kick angle - - idMat3 ShakeAxis( void ) const; // returns the current shake angle - - void CalculateShake( void ); - - // this may involve rendering to a texture and displaying - // that with a warp model or in double vision mode - void RenderPlayerView( idUserInterface *hud ); - - void Fade( idVec4 color, int time ); - - void Flash( idVec4 color, int time ); - - void AddBloodSpray( float duration ); - - // temp for view testing - void EnableBFGVision( bool b ) { bfgVision = b; }; - -private: - void SingleView( idUserInterface *hud, const renderView_t *view ); - void ScreenFade(); - - screenBlob_t * GetScreenBlob(); - - screenBlob_t screenBlobs[MAX_SCREEN_BLOBS]; - -public: - int dvFinishTime; // double vision will be stopped at this time - const idMaterial * dvMaterial; // material to take the double vision screen shot - - int kickFinishTime; // view kick will be stopped at this time - idAngles kickAngles; - - bool bfgVision; // - - const idMaterial * tunnelMaterial; // health tunnel vision - const idMaterial * armorMaterial; // armor damage view effect - const idMaterial * berserkMaterial; // berserk effect - const idMaterial * irGogglesMaterial; // ir effect - const idMaterial * bloodSprayMaterial; // blood spray - const idMaterial * bfgMaterial; // when targeted with BFG - const idMaterial * lagoMaterial; // lagometer drawing - float lastDamageTime; // accentuate the tunnel effect for a while - - idVec4 fadeColor; // fade color - idVec4 fadeToColor; // color to fade to - idVec4 fadeFromColor; // color to fade from - float fadeRate; // fade rate - int fadeTime; // fade time - - idAngles shakeAng; // from the sound sources - - idPlayer * player; - renderView_t view; - -#ifdef _D3XP - FullscreenFXManager *fxManager; - -public: - int AddWarp( idVec3 worldOrigin, float centerx, float centery, float initialRadius, float durationMsec ); - void FreeWarp( int id ); -#endif -}; - -#endif /* !__GAME_PLAYERVIEW_H__ */ diff --git a/d3xp/Projectile.cpp b/d3xp/Projectile.cpp deleted file mode 100644 index 51023b6d..00000000 --- a/d3xp/Projectile.cpp +++ /dev/null @@ -1,2656 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "renderer/ModelManager.h" - -#include "gamesys/SysCvar.h" -#include "script/Script_Thread.h" -#include "ai/AI.h" -#include "Player.h" -#include "Mover.h" -#include "SmokeParticles.h" -#include "Misc.h" - -#include "Projectile.h" - -/* -=============================================================================== - - idProjectile - -=============================================================================== -*/ - - -static const int BFG_DAMAGE_FREQUENCY = 333; -static const float BOUNCE_SOUND_MIN_VELOCITY = 200.0f; -static const float BOUNCE_SOUND_MAX_VELOCITY = 400.0f; - -const idEventDef EV_Explode( "", NULL ); -const idEventDef EV_Fizzle( "", NULL ); -const idEventDef EV_RadiusDamage( "", "e" ); -const idEventDef EV_GetProjectileState( "getProjectileState", NULL, 'd' ); - -#ifdef _D3XP -const idEventDef EV_CreateProjectile( "projectileCreateProjectile", "evv" ); -const idEventDef EV_LaunchProjectile( "projectileLaunchProjectile", "vvv" ); -const idEventDef EV_SetGravity( "setGravity", "f" ); -#endif - -CLASS_DECLARATION( idEntity, idProjectile ) - EVENT( EV_Explode, idProjectile::Event_Explode ) - EVENT( EV_Fizzle, idProjectile::Event_Fizzle ) - EVENT( EV_Touch, idProjectile::Event_Touch ) - EVENT( EV_RadiusDamage, idProjectile::Event_RadiusDamage ) - EVENT( EV_GetProjectileState, idProjectile::Event_GetProjectileState ) -#ifdef _D3XP - EVENT( EV_CreateProjectile, idProjectile::Event_CreateProjectile ) - EVENT( EV_LaunchProjectile, idProjectile::Event_LaunchProjectile ) - EVENT( EV_SetGravity, idProjectile::Event_SetGravity ) -#endif -END_CLASS - -/* -================ -idProjectile::idProjectile -================ -*/ -idProjectile::idProjectile( void ) { - owner = NULL; - lightDefHandle = -1; - thrust = 0.0f; - thrust_end = 0; - smokeFly = NULL; - smokeFlyTime = 0; - state = SPAWNED; - lightOffset = vec3_zero; - lightStartTime = 0; - lightEndTime = 0; - lightColor = vec3_zero; - state = SPAWNED; - damagePower = 1.0f; - memset( &projectileFlags, 0, sizeof( projectileFlags ) ); - memset( &renderLight, 0, sizeof( renderLight ) ); - - // note: for net_instanthit projectiles, we will force this back to false at spawn time - fl.networkSync = true; - - netSyncPhysics = false; -} - -/* -================ -idProjectile::Spawn -================ -*/ -void idProjectile::Spawn( void ) { - physicsObj.SetSelf( this ); - physicsObj.SetClipModel( new idClipModel( GetPhysics()->GetClipModel() ), 1.0f ); - physicsObj.SetContents( 0 ); - physicsObj.SetClipMask( 0 ); - physicsObj.PutToRest(); - SetPhysics( &physicsObj ); -} - -/* -================ -idProjectile::Save -================ -*/ -void idProjectile::Save( idSaveGame *savefile ) const { - - owner.Save( savefile ); - - projectileFlags_s flags = projectileFlags; - LittleBitField( &flags, sizeof( flags ) ); - savefile->Write( &flags, sizeof( flags ) ); - - savefile->WriteFloat( thrust ); - savefile->WriteInt( thrust_end ); - - savefile->WriteRenderLight( renderLight ); - savefile->WriteInt( (int)lightDefHandle ); - savefile->WriteVec3( lightOffset ); - savefile->WriteInt( lightStartTime ); - savefile->WriteInt( lightEndTime ); - savefile->WriteVec3( lightColor ); - - savefile->WriteParticle( smokeFly ); - savefile->WriteInt( smokeFlyTime ); - -#ifdef _D3XP - savefile->WriteInt( originalTimeGroup ); -#endif - - savefile->WriteInt( (int)state ); - - savefile->WriteFloat( damagePower ); - - savefile->WriteStaticObject( physicsObj ); - savefile->WriteStaticObject( thruster ); -} - -/* -================ -idProjectile::Restore -================ -*/ -void idProjectile::Restore( idRestoreGame *savefile ) { - - owner.Restore( savefile ); - - savefile->Read( &projectileFlags, sizeof( projectileFlags ) ); - LittleBitField( &projectileFlags, sizeof( projectileFlags ) ); - - savefile->ReadFloat( thrust ); - savefile->ReadInt( thrust_end ); - - savefile->ReadRenderLight( renderLight ); - savefile->ReadInt( (int &)lightDefHandle ); - savefile->ReadVec3( lightOffset ); - savefile->ReadInt( lightStartTime ); - savefile->ReadInt( lightEndTime ); - savefile->ReadVec3( lightColor ); - - savefile->ReadParticle( smokeFly ); - savefile->ReadInt( smokeFlyTime ); - -#ifdef _D3XP - savefile->ReadInt( originalTimeGroup ); -#endif - - savefile->ReadInt( (int &)state ); - - savefile->ReadFloat( damagePower ); - - savefile->ReadStaticObject( physicsObj ); - RestorePhysics( &physicsObj ); - - savefile->ReadStaticObject( thruster ); - thruster.SetPhysics( &physicsObj ); - - if ( smokeFly != NULL ) { - idVec3 dir; - dir = physicsObj.GetLinearVelocity(); - dir.NormalizeFast(); - gameLocal.smokeParticles->EmitSmoke( smokeFly, gameLocal.time, gameLocal.random.RandomFloat(), GetPhysics()->GetOrigin(), GetPhysics()->GetAxis(), timeGroup /*_D3XP*/ ); - } - -#ifdef _D3XP - if ( lightDefHandle >= 0 ) { - lightDefHandle = gameRenderWorld->AddLightDef( &renderLight ); - } -#endif -} - -/* -================ -idProjectile::GetOwner -================ -*/ -idEntity *idProjectile::GetOwner( void ) const { - return owner.GetEntity(); -} - -/* -================ -idProjectile::Create -================ -*/ -void idProjectile::Create( idEntity *owner, const idVec3 &start, const idVec3 &dir ) { - idDict args; - idStr shaderName; - idVec3 light_color; - idVec3 light_offset; - idVec3 tmp; - idMat3 axis; - - Unbind(); - - // align z-axis of model with the direction - axis = dir.ToMat3(); - tmp = axis[2]; - axis[2] = axis[0]; - axis[0] = -tmp; - - physicsObj.SetOrigin( start ); - physicsObj.SetAxis( axis ); - - physicsObj.GetClipModel()->SetOwner( owner ); - - this->owner = owner; - - memset( &renderLight, 0, sizeof( renderLight ) ); - shaderName = spawnArgs.GetString( "mtr_light_shader" ); - if ( *(const char *)shaderName ) { - renderLight.shader = declManager->FindMaterial( shaderName, false ); - renderLight.pointLight = true; - renderLight.lightRadius[0] = - renderLight.lightRadius[1] = - renderLight.lightRadius[2] = spawnArgs.GetFloat( "light_radius" ); - spawnArgs.GetVector( "light_color", "1 1 1", light_color ); - renderLight.shaderParms[0] = light_color[0]; - renderLight.shaderParms[1] = light_color[1]; - renderLight.shaderParms[2] = light_color[2]; - renderLight.shaderParms[3] = 1.0f; - } - - spawnArgs.GetVector( "light_offset", "0 0 0", lightOffset ); - - lightStartTime = 0; - lightEndTime = 0; - smokeFlyTime = 0; - - damagePower = 1.0f; - -#ifdef _D3XP - if(spawnArgs.GetBool("reset_time_offset", "0")) { - renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time ); - } -#endif - - UpdateVisuals(); - - state = CREATED; - - if ( spawnArgs.GetBool( "net_fullphysics" ) ) { - netSyncPhysics = true; - } -} - -/* -================= -idProjectile::~idProjectile -================= -*/ -idProjectile::~idProjectile() { - StopSound( SND_CHANNEL_ANY, false ); - FreeLightDef(); -} - -/* -================= -idProjectile::FreeLightDef -================= -*/ -void idProjectile::FreeLightDef( void ) { - if ( lightDefHandle != -1 ) { - gameRenderWorld->FreeLightDef( lightDefHandle ); - lightDefHandle = -1; - } -} - -/* -================= -idProjectile::Launch -================= -*/ -void idProjectile::Launch( const idVec3 &start, const idVec3 &dir, const idVec3 &pushVelocity, const float timeSinceFire, const float launchPower, const float dmgPower ) { - float fuse; - float endthrust; - idVec3 velocity; - idAngles angular_velocity; - float linear_friction; - float angular_friction; - float contact_friction; - float bounce; - float mass; - float speed; - float gravity; - idVec3 gravVec; - idVec3 tmp; - idMat3 axis; - int contents; - int clipMask; - - // allow characters to throw projectiles during cinematics, but not the player - if ( owner.GetEntity() && !owner.GetEntity()->IsType( idPlayer::Type ) ) { - cinematic = owner.GetEntity()->cinematic; - } else { - cinematic = false; - } - - thrust = spawnArgs.GetFloat( "thrust" ); - endthrust = spawnArgs.GetFloat( "thrust_end" ); - - spawnArgs.GetVector( "velocity", "0 0 0", velocity ); - - speed = velocity.Length() * launchPower; - - damagePower = dmgPower; - - spawnArgs.GetAngles( "angular_velocity", "0 0 0", angular_velocity ); - - linear_friction = spawnArgs.GetFloat( "linear_friction" ); - angular_friction = spawnArgs.GetFloat( "angular_friction" ); - contact_friction = spawnArgs.GetFloat( "contact_friction" ); - bounce = spawnArgs.GetFloat( "bounce" ); - mass = spawnArgs.GetFloat( "mass" ); - gravity = spawnArgs.GetFloat( "gravity" ); - fuse = spawnArgs.GetFloat( "fuse" ); - - projectileFlags.detonate_on_world = spawnArgs.GetBool( "detonate_on_world" ); - projectileFlags.detonate_on_actor = spawnArgs.GetBool( "detonate_on_actor" ); - projectileFlags.randomShaderSpin = spawnArgs.GetBool( "random_shader_spin" ); - - if ( mass <= 0 ) { - gameLocal.Error( "Invalid mass on '%s'\n", GetEntityDefName() ); - } - - thrust *= mass; - thrust_end = SEC2MS( endthrust ) + gameLocal.time; - - lightStartTime = 0; - lightEndTime = 0; - - if ( health ) { - fl.takedamage = true; - } - - gravVec = gameLocal.GetGravity(); - gravVec.NormalizeFast(); - - Unbind(); - - // align z-axis of model with the direction - axis = dir.ToMat3(); - tmp = axis[2]; - axis[2] = axis[0]; - axis[0] = -tmp; - - contents = 0; - clipMask = MASK_SHOT_RENDERMODEL; - if ( spawnArgs.GetBool( "detonate_on_trigger" ) ) { - contents |= CONTENTS_TRIGGER; - } - if ( !spawnArgs.GetBool( "no_contents" ) ) { - contents |= CONTENTS_PROJECTILE; - clipMask |= CONTENTS_PROJECTILE; - } - -#ifdef _D3XP - if ( !idStr::Cmp( this->GetEntityDefName(), "projectile_helltime_killer" ) ) { - contents = CONTENTS_MOVEABLECLIP; - clipMask = CONTENTS_MOVEABLECLIP; - } -#endif - - // don't do tracers on client, we don't know origin and direction - if ( spawnArgs.GetBool( "tracers" ) && gameLocal.random.RandomFloat() > 0.5f ) { - SetModel( spawnArgs.GetString( "model_tracer" ) ); - projectileFlags.isTracer = true; - } - - physicsObj.SetMass( mass ); - physicsObj.SetFriction( linear_friction, angular_friction, contact_friction ); - if ( contact_friction == 0.0f ) { - physicsObj.NoContact(); - } - physicsObj.SetBouncyness( bounce ); - physicsObj.SetGravity( gravVec * gravity ); - physicsObj.SetContents( contents ); - physicsObj.SetClipMask( clipMask ); - physicsObj.SetLinearVelocity( axis[ 2 ] * speed + pushVelocity ); - physicsObj.SetAngularVelocity( angular_velocity.ToAngularVelocity() * axis ); - physicsObj.SetOrigin( start ); - physicsObj.SetAxis( axis ); - - thruster.SetPosition( &physicsObj, 0, idVec3( GetPhysics()->GetBounds()[ 0 ].x, 0, 0 ) ); - - if ( !gameLocal.isClient ) { - if ( fuse <= 0 ) { - // run physics for 1 second - RunPhysics(); - PostEventMS( &EV_Remove, spawnArgs.GetInt( "remove_time", "1500" ) ); - } else if ( spawnArgs.GetBool( "detonate_on_fuse" ) ) { - fuse -= timeSinceFire; - if ( fuse < 0.0f ) { - fuse = 0.0f; - } - PostEventSec( &EV_Explode, fuse ); - } else { - fuse -= timeSinceFire; - if ( fuse < 0.0f ) { - fuse = 0.0f; - } - PostEventSec( &EV_Fizzle, fuse ); - } - } - - if ( projectileFlags.isTracer ) { - StartSound( "snd_tracer", SND_CHANNEL_BODY, 0, false, NULL ); - } else { - StartSound( "snd_fly", SND_CHANNEL_BODY, 0, false, NULL ); - } - - smokeFlyTime = 0; - const char *smokeName = spawnArgs.GetString( "smoke_fly" ); - if ( *smokeName != '\0' ) { - smokeFly = static_cast( declManager->FindType( DECL_PARTICLE, smokeName ) ); - smokeFlyTime = gameLocal.time; - } - -#ifdef _D3XP - originalTimeGroup = timeGroup; -#endif - - // used for the plasma bolts but may have other uses as well - if ( projectileFlags.randomShaderSpin ) { - float f = gameLocal.random.RandomFloat(); - f *= 0.5f; - renderEntity.shaderParms[SHADERPARM_DIVERSITY] = f; - } - - UpdateVisuals(); - - state = LAUNCHED; -} - -/* -================ -idProjectile::Think -================ -*/ -void idProjectile::Think( void ) { - - if ( thinkFlags & TH_THINK ) { - if ( thrust && ( gameLocal.time < thrust_end ) ) { - // evaluate force - thruster.SetForce( GetPhysics()->GetAxis()[ 0 ] * thrust ); - thruster.Evaluate( gameLocal.time ); - } - } - - // run physics - RunPhysics(); - - Present(); - - // add the particles - if ( smokeFly != NULL && smokeFlyTime && !IsHidden() ) { - idVec3 dir = -GetPhysics()->GetLinearVelocity(); - dir.Normalize(); -#ifdef _D3XP - SetTimeState ts(originalTimeGroup); -#endif - if ( !gameLocal.smokeParticles->EmitSmoke( smokeFly, smokeFlyTime, gameLocal.random.RandomFloat(), GetPhysics()->GetOrigin(), dir.ToMat3(), timeGroup /*_D3XP*/ ) ) { - smokeFlyTime = gameLocal.time; - } - } - - // add the light - if ( renderLight.lightRadius.x > 0.0f && g_projectileLights.GetBool() ) { - renderLight.origin = GetPhysics()->GetOrigin() + GetPhysics()->GetAxis() * lightOffset; - renderLight.axis = GetPhysics()->GetAxis(); - if ( ( lightDefHandle != -1 ) ) { - if ( lightEndTime > 0 && gameLocal.time <= lightEndTime + gameLocal.GetMSec() ) { - idVec3 color( 0, 0, 0 ); - if ( gameLocal.time < lightEndTime ) { - float frac = ( float )( gameLocal.time - lightStartTime ) / ( float )( lightEndTime - lightStartTime ); - color.Lerp( lightColor, color, frac ); - } - renderLight.shaderParms[SHADERPARM_RED] = color.x; - renderLight.shaderParms[SHADERPARM_GREEN] = color.y; - renderLight.shaderParms[SHADERPARM_BLUE] = color.z; - } - gameRenderWorld->UpdateLightDef( lightDefHandle, &renderLight ); - } else { - lightDefHandle = gameRenderWorld->AddLightDef( &renderLight ); - } - } -} - -/* -================= -idProjectile::Collide -================= -*/ -bool idProjectile::Collide( const trace_t &collision, const idVec3 &velocity ) { - idEntity *ent; - idEntity *ignore; - const char *damageDefName; - idVec3 dir; - float push; - float damageScale; - - if ( state == EXPLODED || state == FIZZLED ) { - return true; - } - - // predict the explosion - if ( gameLocal.isClient ) { - if ( ClientPredictionCollide( this, spawnArgs, collision, velocity, !spawnArgs.GetBool( "net_instanthit" ) ) ) { - Explode( collision, NULL ); - return true; - } - return false; - } - - // remove projectile when a 'noimpact' surface is hit - if ( ( collision.c.material != NULL ) && ( collision.c.material->GetSurfaceFlags() & SURF_NOIMPACT ) ) { - PostEventMS( &EV_Remove, 0 ); - common->DPrintf( "Projectile collision no impact\n" ); - return true; - } - - // get the entity the projectile collided with - ent = gameLocal.entities[ collision.c.entityNum ]; - if ( ent == owner.GetEntity() ) { - assert( 0 ); - return true; - } - - // just get rid of the projectile when it hits a player in noclip - if ( ent->IsType( idPlayer::Type ) && static_cast( ent )->noclip ) { - PostEventMS( &EV_Remove, 0 ); - return true; - } - - // direction of projectile - dir = velocity; - dir.Normalize(); - - // projectiles can apply an additional impulse next to the rigid body physics impulse - if ( spawnArgs.GetFloat( "push", "0", push ) && push > 0.0f ) { - ent->ApplyImpulse( this, collision.c.id, collision.c.point, push * dir ); - } - - // MP: projectiles open doors - if ( gameLocal.isMultiplayer && ent->IsType( idDoor::Type ) && !static_cast< idDoor * >(ent)->IsOpen() && !ent->spawnArgs.GetBool( "no_touch" ) ) { - ent->ProcessEvent( &EV_Activate , this ); - } - - if ( ent->IsType( idActor::Type ) || ( ent->IsType( idAFAttachment::Type ) && static_cast(ent)->GetBody()->IsType( idActor::Type ) ) ) { - if ( !projectileFlags.detonate_on_actor ) { - return false; - } - } else { - if ( !projectileFlags.detonate_on_world ) { - if ( !StartSound( "snd_ricochet", SND_CHANNEL_ITEM, 0, true, NULL ) ) { - float len = velocity.Length(); - if ( len > BOUNCE_SOUND_MIN_VELOCITY ) { - SetSoundVolume( len > BOUNCE_SOUND_MAX_VELOCITY ? 1.0f : idMath::Sqrt( len - BOUNCE_SOUND_MIN_VELOCITY ) * ( 1.0f / idMath::Sqrt( BOUNCE_SOUND_MAX_VELOCITY - BOUNCE_SOUND_MIN_VELOCITY ) ) ); - StartSound( "snd_bounce", SND_CHANNEL_ANY, 0, true, NULL ); - } - } - return false; - } - } - - SetOrigin( collision.endpos ); - SetAxis( collision.endAxis ); - - // unlink the clip model because we no longer need it - GetPhysics()->UnlinkClip(); - - damageDefName = spawnArgs.GetString( "def_damage" ); - - ignore = NULL; - - // if the hit entity takes damage - if ( ent->fl.takedamage ) { - if ( damagePower ) { - damageScale = damagePower; - } else { - damageScale = 1.0f; - } - - // if the projectile owner is a player - if ( owner.GetEntity() && owner.GetEntity()->IsType( idPlayer::Type ) ) { - // if the projectile hit an actor - if ( ent->IsType( idActor::Type ) ) { - idPlayer *player = static_cast( owner.GetEntity() ); - player->AddProjectileHits( 1 ); - damageScale *= player->PowerUpModifier( PROJECTILE_DAMAGE ); - } - } - - if ( damageDefName[0] != '\0' ) { - ent->Damage( this, owner.GetEntity(), dir, damageDefName, damageScale, CLIPMODEL_ID_TO_JOINT_HANDLE( collision.c.id ) ); - ignore = ent; - } - } - - // if the projectile causes a damage effect - if ( spawnArgs.GetBool( "impact_damage_effect" ) ) { - // if the hit entity has a special damage effect - if ( ent->spawnArgs.GetBool( "bleed" ) ) { - ent->AddDamageEffect( collision, velocity, damageDefName ); - } else { - AddDefaultDamageEffect( collision, velocity ); - } - } - - Explode( collision, ignore ); - - return true; -} - -/* -================= -idProjectile::DefaultDamageEffect -================= -*/ -void idProjectile::DefaultDamageEffect( idEntity *soundEnt, const idDict &projectileDef, const trace_t &collision, const idVec3 &velocity ) { - const char *decal, *sound, *typeName; - surfTypes_t materialType; - - if ( collision.c.material != NULL ) { - materialType = collision.c.material->GetSurfaceType(); - } else { - materialType = SURFTYPE_METAL; - } - - // get material type name - typeName = gameLocal.sufaceTypeNames[ materialType ]; - - // play impact sound - sound = projectileDef.GetString( va( "snd_%s", typeName ) ); - if ( *sound == '\0' ) { - sound = projectileDef.GetString( "snd_metal" ); - } - if ( *sound == '\0' ) { - sound = projectileDef.GetString( "snd_impact" ); - } - if ( *sound != '\0' ) { - soundEnt->StartSoundShader( declManager->FindSound( sound ), SND_CHANNEL_BODY, 0, false, NULL ); - } - - // project decal - decal = projectileDef.GetString( va( "mtr_detonate_%s", typeName ) ); - if ( *decal == '\0' ) { - decal = projectileDef.GetString( "mtr_detonate" ); - } - if ( *decal != '\0' ) { - gameLocal.ProjectDecal( collision.c.point, -collision.c.normal, 8.0f, true, projectileDef.GetFloat( "decal_size", "6.0" ), decal ); - } -} - -/* -================= -idProjectile::AddDefaultDamageEffect -================= -*/ -void idProjectile::AddDefaultDamageEffect( const trace_t &collision, const idVec3 &velocity ) { - - DefaultDamageEffect( this, spawnArgs, collision, velocity ); - - if ( gameLocal.isServer && fl.networkSync ) { - idBitMsg msg; - byte msgBuf[MAX_EVENT_PARAM_SIZE]; - int excludeClient; - - if ( spawnArgs.GetBool( "net_instanthit" ) ) { - excludeClient = owner.GetEntityNum(); - } else { - excludeClient = -1; - } - - msg.Init( msgBuf, sizeof( msgBuf ) ); - msg.BeginWriting(); - msg.WriteFloat( collision.c.point[0] ); - msg.WriteFloat( collision.c.point[1] ); - msg.WriteFloat( collision.c.point[2] ); - msg.WriteDir( collision.c.normal, 24 ); - msg.WriteInt( ( collision.c.material != NULL ) ? gameLocal.ServerRemapDecl( -1, DECL_MATERIAL, collision.c.material->Index() ) : -1 ); - msg.WriteFloat( velocity[0], 5, 10 ); - msg.WriteFloat( velocity[1], 5, 10 ); - msg.WriteFloat( velocity[2], 5, 10 ); - ServerSendEvent( EVENT_DAMAGE_EFFECT, &msg, false, excludeClient ); - } -} - -/* -================ -idProjectile::Killed -================ -*/ -void idProjectile::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) { - if ( spawnArgs.GetBool( "detonate_on_death" ) ) { - trace_t collision; - - memset( &collision, 0, sizeof( collision ) ); - collision.endAxis = GetPhysics()->GetAxis(); - collision.endpos = GetPhysics()->GetOrigin(); - collision.c.point = GetPhysics()->GetOrigin(); - collision.c.normal.Set( 0, 0, 1 ); - Explode( collision, NULL ); - physicsObj.ClearContacts(); - physicsObj.PutToRest(); - } else { - Fizzle(); - } -} - -/* -================ -idProjectile::Fizzle -================ -*/ -void idProjectile::Fizzle( void ) { - - if ( state == EXPLODED || state == FIZZLED ) { - return; - } - - StopSound( SND_CHANNEL_BODY, false ); - StartSound( "snd_fizzle", SND_CHANNEL_BODY, 0, false, NULL ); - - // fizzle FX - const char *psystem = spawnArgs.GetString( "smoke_fuse" ); - if ( psystem && *psystem ) { -//FIXME:SMOKE gameLocal.particles->SpawnParticles( GetPhysics()->GetOrigin(), vec3_origin, psystem ); - } - - // we need to work out how long the effects last and then remove them at that time - // for example, bullets have no real effects - if ( smokeFly && smokeFlyTime ) { - smokeFlyTime = 0; - } - - fl.takedamage = false; - physicsObj.SetContents( 0 ); - physicsObj.GetClipModel()->Unlink(); - physicsObj.PutToRest(); - - Hide(); - FreeLightDef(); - - state = FIZZLED; - - if ( gameLocal.isClient ) { - return; - } - - CancelEvents( &EV_Fizzle ); - PostEventMS( &EV_Remove, spawnArgs.GetInt( "remove_time", "1500" ) ); -} - -/* -================ -idProjectile::Event_RadiusDamage -================ -*/ -void idProjectile::Event_RadiusDamage( idEntity *ignore ) { - const char *splash_damage = spawnArgs.GetString( "def_splash_damage" ); - if ( splash_damage[0] != '\0' ) { - gameLocal.RadiusDamage( physicsObj.GetOrigin(), this, owner.GetEntity(), ignore, this, splash_damage, damagePower ); - } -} - -/* -================ -idProjectile::Event_RadiusDamage -================ -*/ -void idProjectile::Event_GetProjectileState( void ) { - idThread::ReturnInt( state ); -} - -/* -================ -idProjectile::Explode -================ -*/ -void idProjectile::Explode( const trace_t &collision, idEntity *ignore ) { - const char *fxname, *light_shader, *sndExplode; - float light_fadetime; - idVec3 normal; - int removeTime; - - if ( state == EXPLODED || state == FIZZLED ) { - return; - } - - // stop sound - StopSound( SND_CHANNEL_BODY2, false ); - - // play explode sound - switch ( ( int ) damagePower ) { - case 2: sndExplode = "snd_explode2"; break; - case 3: sndExplode = "snd_explode3"; break; - case 4: sndExplode = "snd_explode4"; break; - default: sndExplode = "snd_explode"; break; - } - StartSound( sndExplode, SND_CHANNEL_BODY, 0, true, NULL ); - - // we need to work out how long the effects last and then remove them at that time - // for example, bullets have no real effects - if ( smokeFly && smokeFlyTime ) { - smokeFlyTime = 0; - } - - Hide(); - FreeLightDef(); - - if ( spawnArgs.GetVector( "detonation_axis", "", normal ) ) { - GetPhysics()->SetAxis( normal.ToMat3() ); - } - GetPhysics()->SetOrigin( collision.endpos + 2.0f * collision.c.normal ); - - // default remove time - removeTime = spawnArgs.GetInt( "remove_time", "1500" ); - - // change the model, usually to a PRT - fxname = NULL; - if ( g_testParticle.GetInteger() == TEST_PARTICLE_IMPACT ) { - fxname = g_testParticleName.GetString(); - } else { - fxname = spawnArgs.GetString( "model_detonate" ); - } - - int surfaceType = collision.c.material != NULL ? collision.c.material->GetSurfaceType() : SURFTYPE_METAL; - if ( !( fxname && *fxname ) ) { - if ( ( surfaceType == SURFTYPE_NONE ) || ( surfaceType == SURFTYPE_METAL ) || ( surfaceType == SURFTYPE_STONE ) ) { - fxname = spawnArgs.GetString( "model_smokespark" ); - } else if ( surfaceType == SURFTYPE_RICOCHET ) { - fxname = spawnArgs.GetString( "model_ricochet" ); - } else { - fxname = spawnArgs.GetString( "model_smoke" ); - } - } - -#ifdef _D3XP - // If the explosion is in liquid, spawn a particle splash - idVec3 testOrg = GetPhysics()->GetOrigin(); - int testC = gameLocal.clip.Contents( testOrg, NULL, mat3_identity, CONTENTS_WATER, this ); - if ( testC & CONTENTS_WATER ) { - idFuncEmitter *splashEnt; - idDict splashArgs; - - splashArgs.Set( "model", "sludgebulletimpact.prt" ); - splashArgs.Set( "start_off", "1" ); - splashEnt = static_cast( gameLocal.SpawnEntityType( idFuncEmitter::Type, &splashArgs ) ); - - splashEnt->GetPhysics()->SetOrigin( testOrg ); - splashEnt->PostEventMS( &EV_Activate, 0, this ); - splashEnt->PostEventMS( &EV_Remove, 1500 ); - - // HACK - if this is a chaingun bullet, don't do the normal effect - if ( !idStr::Cmp( spawnArgs.GetString( "def_damage" ), "damage_bullet_chaingun" ) ) { - fxname = NULL; - } - } -#endif - - if ( fxname && *fxname ) { - SetModel( fxname ); - renderEntity.shaderParms[SHADERPARM_RED] = - renderEntity.shaderParms[SHADERPARM_GREEN] = - renderEntity.shaderParms[SHADERPARM_BLUE] = - renderEntity.shaderParms[SHADERPARM_ALPHA] = 1.0f; - renderEntity.shaderParms[SHADERPARM_TIMEOFFSET] = -MS2SEC( gameLocal.time ); - renderEntity.shaderParms[SHADERPARM_DIVERSITY] = gameLocal.random.CRandomFloat(); - Show(); - removeTime = ( removeTime > 3000 ) ? removeTime : 3000; - } - - // explosion light - light_shader = spawnArgs.GetString( "mtr_explode_light_shader" ); - -#ifdef CTF - if ( gameLocal.mpGame.IsGametypeFlagBased() && gameLocal.serverInfo.GetBool("si_midnight") ) - { - light_shader = "lights/midnight_grenade"; - } -#endif - - if ( *light_shader ) { - renderLight.shader = declManager->FindMaterial( light_shader, false ); - renderLight.pointLight = true; - renderLight.lightRadius[0] = - renderLight.lightRadius[1] = - renderLight.lightRadius[2] = spawnArgs.GetFloat( "explode_light_radius" ); - -#ifdef CTF - // Midnight ctf - if ( gameLocal.mpGame.IsGametypeFlagBased() && gameLocal.serverInfo.GetBool("si_midnight") ) - { - renderLight.lightRadius[0] = - renderLight.lightRadius[1] = - renderLight.lightRadius[2] = spawnArgs.GetFloat( "explode_light_radius" ) * 2; - } - -#endif - - spawnArgs.GetVector( "explode_light_color", "1 1 1", lightColor ); - renderLight.shaderParms[SHADERPARM_RED] = lightColor.x; - renderLight.shaderParms[SHADERPARM_GREEN] = lightColor.y; - renderLight.shaderParms[SHADERPARM_BLUE] = lightColor.z; - renderLight.shaderParms[SHADERPARM_ALPHA] = 1.0f; - renderLight.shaderParms[SHADERPARM_TIMEOFFSET] = -MS2SEC( gameLocal.time ); - -#ifdef CTF - // Midnight ctf - if ( gameLocal.mpGame.IsGametypeFlagBased() && gameLocal.serverInfo.GetBool("si_midnight") ) - { - light_fadetime = 3.0f; - } - else -#endif - light_fadetime = spawnArgs.GetFloat( "explode_light_fadetime", "0.5" ); - lightStartTime = gameLocal.time; - lightEndTime = gameLocal.time + SEC2MS( light_fadetime ); - BecomeActive( TH_THINK ); - } - - fl.takedamage = false; - physicsObj.SetContents( 0 ); - physicsObj.PutToRest(); - - state = EXPLODED; - - if ( gameLocal.isClient ) { - return; - } - - // alert the ai - gameLocal.AlertAI( owner.GetEntity() ); - - // bind the projectile to the impact entity if necesary - if ( gameLocal.entities[collision.c.entityNum] && spawnArgs.GetBool( "bindOnImpact" ) ) { - Bind( gameLocal.entities[collision.c.entityNum], true ); - } - - // splash damage - if ( !projectileFlags.noSplashDamage ) { - float delay = spawnArgs.GetFloat( "delay_splash" ); - if ( delay ) { - if ( removeTime < delay * 1000 ) { - removeTime = ( delay + 0.10 ) * 1000; - } - PostEventSec( &EV_RadiusDamage, delay, ignore ); - } else { - Event_RadiusDamage( ignore ); - } - } - - // spawn debris entities - int fxdebris = spawnArgs.GetInt( "debris_count" ); - if ( fxdebris ) { - const idDict *debris = gameLocal.FindEntityDefDict( "projectile_debris", false ); - if ( debris ) { - int amount = gameLocal.random.RandomInt( fxdebris ); - for ( int i = 0; i < amount; i++ ) { - idEntity *ent; - idVec3 dir; - dir.x = gameLocal.random.CRandomFloat() * 4.0f; - dir.y = gameLocal.random.CRandomFloat() * 4.0f; - dir.z = gameLocal.random.RandomFloat() * 8.0f; - dir.Normalize(); - - gameLocal.SpawnEntityDef( *debris, &ent, false ); - if ( !ent || !ent->IsType( idDebris::Type ) ) { - gameLocal.Error( "'projectile_debris' is not an idDebris" ); - } - - idDebris *debris = static_cast(ent); - debris->Create( owner.GetEntity(), physicsObj.GetOrigin(), dir.ToMat3() ); - debris->Launch(); - } - } - debris = gameLocal.FindEntityDefDict( "projectile_shrapnel", false ); - if ( debris ) { - int amount = gameLocal.random.RandomInt( fxdebris ); - for ( int i = 0; i < amount; i++ ) { - idEntity *ent; - idVec3 dir; - dir.x = gameLocal.random.CRandomFloat() * 8.0f; - dir.y = gameLocal.random.CRandomFloat() * 8.0f; - dir.z = gameLocal.random.RandomFloat() * 8.0f + 8.0f; - dir.Normalize(); - - gameLocal.SpawnEntityDef( *debris, &ent, false ); - if ( !ent || !ent->IsType( idDebris::Type ) ) { - gameLocal.Error( "'projectile_shrapnel' is not an idDebris" ); - } - - idDebris *debris = static_cast(ent); - debris->Create( owner.GetEntity(), physicsObj.GetOrigin(), dir.ToMat3() ); - debris->Launch(); - } - } - } - - CancelEvents( &EV_Explode ); - PostEventMS( &EV_Remove, removeTime ); -} - -/* -================ -idProjectile::GetVelocity -================ -*/ -idVec3 idProjectile::GetVelocity( const idDict *projectile ) { - idVec3 velocity; - - projectile->GetVector( "velocity", "0 0 0", velocity ); - return velocity; -} - -/* -================ -idProjectile::GetGravity -================ -*/ -idVec3 idProjectile::GetGravity( const idDict *projectile ) { - float gravity; - - gravity = projectile->GetFloat( "gravity" ); - return idVec3( 0, 0, -gravity ); -} - -/* -================ -idProjectile::Event_Explode -================ -*/ -void idProjectile::Event_Explode( void ) { - trace_t collision; - - memset( &collision, 0, sizeof( collision ) ); - collision.endAxis = GetPhysics()->GetAxis(); - collision.endpos = GetPhysics()->GetOrigin(); - collision.c.point = GetPhysics()->GetOrigin(); - collision.c.normal.Set( 0, 0, 1 ); - AddDefaultDamageEffect( collision, collision.c.normal ); - Explode( collision, NULL ); -} - -/* -================ -idProjectile::Event_Fizzle -================ -*/ -void idProjectile::Event_Fizzle( void ) { - Fizzle(); -} - -/* -================ -idProjectile::Event_Touch -================ -*/ -void idProjectile::Event_Touch( idEntity *other, trace_t *trace ) { - - if ( IsHidden() ) { - return; - } - -#ifdef CTF - // Projectiles do not collide with flags - if ( other->IsType( idItemTeam::Type ) ) - return; -#endif - - if ( other != owner.GetEntity() ) { - trace_t collision; - - memset( &collision, 0, sizeof( collision ) ); - collision.endAxis = GetPhysics()->GetAxis(); - collision.endpos = GetPhysics()->GetOrigin(); - collision.c.point = GetPhysics()->GetOrigin(); - collision.c.normal.Set( 0, 0, 1 ); - AddDefaultDamageEffect( collision, collision.c.normal ); - Explode( collision, NULL ); - } -} - -#ifdef _D3XP -/* -================ -idProjectile::CatchProjectile -================ -*/ -void idProjectile::CatchProjectile( idEntity* o, const char* reflectName ) { - idEntity *prevowner = owner.GetEntity(); - - owner = o; - physicsObj.GetClipModel()->SetOwner( o ); - - if ( this->IsType( idGuidedProjectile::Type ) ) { - idGuidedProjectile *proj = static_cast(this); - - proj->SetEnemy( prevowner ); - } - - idStr s = spawnArgs.GetString( "def_damage" ); - s += reflectName; - - const idDict *damageDef = gameLocal.FindEntityDefDict( s, false ); - if ( damageDef ) { - spawnArgs.Set( "def_damage", s ); - } -} - -/* -================ -idProjectile::GetProjectileState -================ -*/ -int idProjectile::GetProjectileState( void ) { - - return (int)state; -} - -/* -================ -idProjectile::Event_CreateProjectile -================ -*/ -void idProjectile::Event_CreateProjectile( idEntity *owner, const idVec3 &start, const idVec3 &dir ) { - Create(owner, start, dir); -} - -/* -================ -idProjectile::Event_LaunchProjectile -================ -*/ -void idProjectile::Event_LaunchProjectile( const idVec3 &start, const idVec3 &dir, const idVec3 &pushVelocity ) { - Launch(start, dir, pushVelocity); -} - -/* -================ -idProjectile::Event_SetGravity -================ -*/ -void idProjectile::Event_SetGravity( float gravity ) { - idVec3 gravVec; - - gravVec = gameLocal.GetGravity(); - gravVec.NormalizeFast(); - physicsObj.SetGravity(gravVec * gravity); -} -#endif - -/* -================= -idProjectile::ClientPredictionCollide -================= -*/ -bool idProjectile::ClientPredictionCollide( idEntity *soundEnt, const idDict &projectileDef, const trace_t &collision, const idVec3 &velocity, bool addDamageEffect ) { - idEntity *ent; - - // remove projectile when a 'noimpact' surface is hit - if ( collision.c.material && ( collision.c.material->GetSurfaceFlags() & SURF_NOIMPACT ) ) { - return false; - } - - // get the entity the projectile collided with - ent = gameLocal.entities[ collision.c.entityNum ]; - if ( ent == NULL ) { - return false; - } - - // don't do anything if hitting a noclip player - if ( ent->IsType( idPlayer::Type ) && static_cast( ent )->noclip ) { - return false; - } - - if ( ent->IsType( idActor::Type ) || ( ent->IsType( idAFAttachment::Type ) && static_cast(ent)->GetBody()->IsType( idActor::Type ) ) ) { - if ( !projectileDef.GetBool( "detonate_on_actor" ) ) { - return false; - } - } else { - if ( !projectileDef.GetBool( "detonate_on_world" ) ) { - return false; - } - } - - // if the projectile causes a damage effect - if ( addDamageEffect && projectileDef.GetBool( "impact_damage_effect" ) ) { - // if the hit entity does not have a special damage effect - if ( !ent->spawnArgs.GetBool( "bleed" ) ) { - // predict damage effect - DefaultDamageEffect( soundEnt, projectileDef, collision, velocity ); - } - } - return true; -} - -/* -================ -idProjectile::ClientPredictionThink -================ -*/ -void idProjectile::ClientPredictionThink( void ) { - if ( !renderEntity.hModel ) { - return; - } - Think(); -} - -/* -================ -idProjectile::WriteToSnapshot -================ -*/ -void idProjectile::WriteToSnapshot( idBitMsgDelta &msg ) const { - msg.WriteBits( owner.GetSpawnId(), 32 ); - msg.WriteBits( state, 3 ); - msg.WriteBits( fl.hidden, 1 ); - if ( netSyncPhysics ) { - msg.WriteBits( 1, 1 ); - physicsObj.WriteToSnapshot( msg ); - } else { - msg.WriteBits( 0, 1 ); - const idVec3 &origin = physicsObj.GetOrigin(); - const idVec3 &velocity = physicsObj.GetLinearVelocity(); - - msg.WriteFloat( origin.x ); - msg.WriteFloat( origin.y ); - msg.WriteFloat( origin.z ); - - msg.WriteDeltaFloat( 0.0f, velocity[0], RB_VELOCITY_EXPONENT_BITS, RB_VELOCITY_MANTISSA_BITS ); - msg.WriteDeltaFloat( 0.0f, velocity[1], RB_VELOCITY_EXPONENT_BITS, RB_VELOCITY_MANTISSA_BITS ); - msg.WriteDeltaFloat( 0.0f, velocity[2], RB_VELOCITY_EXPONENT_BITS, RB_VELOCITY_MANTISSA_BITS ); - } -} - -/* -================ -idProjectile::ReadFromSnapshot -================ -*/ -void idProjectile::ReadFromSnapshot( const idBitMsgDelta &msg ) { - projectileState_t newState; - - owner.SetSpawnId( msg.ReadBits( 32 ) ); - newState = (projectileState_t) msg.ReadBits( 3 ); - if ( msg.ReadBits( 1 ) ) { - Hide(); - } else { - Show(); - } - - while( state != newState ) { - switch( state ) { - case SPAWNED: { - Create( owner.GetEntity(), vec3_origin, idVec3( 1, 0, 0 ) ); - break; - } - case CREATED: { - // the right origin and direction are required if you want bullet traces - Launch( vec3_origin, idVec3( 1, 0, 0 ), vec3_origin ); - break; - } - case LAUNCHED: { - if ( newState == FIZZLED ) { - Fizzle(); - } else { - trace_t collision; - memset( &collision, 0, sizeof( collision ) ); - collision.endAxis = GetPhysics()->GetAxis(); - collision.endpos = GetPhysics()->GetOrigin(); - collision.c.point = GetPhysics()->GetOrigin(); - collision.c.normal.Set( 0, 0, 1 ); - Explode( collision, NULL ); - } - break; - } - case FIZZLED: - case EXPLODED: { - StopSound( SND_CHANNEL_BODY2, false ); - gameEdit->ParseSpawnArgsToRenderEntity( &spawnArgs, &renderEntity ); - state = SPAWNED; - break; - } - } - } - - if ( msg.ReadBits( 1 ) ) { - physicsObj.ReadFromSnapshot( msg ); - } else { - idVec3 origin; - idVec3 velocity; - idVec3 tmp; - idMat3 axis; - - origin.x = msg.ReadFloat(); - origin.y = msg.ReadFloat(); - origin.z = msg.ReadFloat(); - - velocity.x = msg.ReadDeltaFloat( 0.0f, RB_VELOCITY_EXPONENT_BITS, RB_VELOCITY_MANTISSA_BITS ); - velocity.y = msg.ReadDeltaFloat( 0.0f, RB_VELOCITY_EXPONENT_BITS, RB_VELOCITY_MANTISSA_BITS ); - velocity.z = msg.ReadDeltaFloat( 0.0f, RB_VELOCITY_EXPONENT_BITS, RB_VELOCITY_MANTISSA_BITS ); - - physicsObj.SetOrigin( origin ); - physicsObj.SetLinearVelocity( velocity ); - - // align z-axis of model with the direction - velocity.NormalizeFast(); - axis = velocity.ToMat3(); - tmp = axis[2]; - axis[2] = axis[0]; - axis[0] = -tmp; - physicsObj.SetAxis( axis ); - } - - if ( msg.HasChanged() ) { - UpdateVisuals(); - } -} - -/* -================ -idProjectile::ClientReceiveEvent -================ -*/ -bool idProjectile::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) { - trace_t collision; - idVec3 velocity; - - switch( event ) { - case EVENT_DAMAGE_EFFECT: { - memset( &collision, 0, sizeof( collision ) ); - collision.c.point[0] = msg.ReadFloat(); - collision.c.point[1] = msg.ReadFloat(); - collision.c.point[2] = msg.ReadFloat(); - collision.c.normal = msg.ReadDir( 24 ); - int index = gameLocal.ClientRemapDecl( DECL_MATERIAL, msg.ReadInt() ); - collision.c.material = ( index != -1 ) ? static_cast( declManager->DeclByIndex( DECL_MATERIAL, index ) ) : NULL; - velocity[0] = msg.ReadFloat( 5, 10 ); - velocity[1] = msg.ReadFloat( 5, 10 ); - velocity[2] = msg.ReadFloat( 5, 10 ); - DefaultDamageEffect( this, spawnArgs, collision, velocity ); - return true; - } - default: - break; - } - - return idEntity::ClientReceiveEvent( event, time, msg ); -} - -/* -=============================================================================== - - idGuidedProjectile - -=============================================================================== -*/ - -#ifdef _D3XP -const idEventDef EV_SetEnemy( "setEnemy", "E" ); -#endif - -CLASS_DECLARATION( idProjectile, idGuidedProjectile ) -#ifdef _D3XP - EVENT( EV_SetEnemy, idGuidedProjectile::Event_SetEnemy ) -#endif -END_CLASS - -/* -================ -idGuidedProjectile::idGuidedProjectile -================ -*/ -idGuidedProjectile::idGuidedProjectile( void ) { - enemy = NULL; - speed = 0.0f; - turn_max = 0.0f; - clamp_dist = 0.0f; - rndScale = ang_zero; - rndAng = ang_zero; - rndUpdateTime = 0; - angles = ang_zero; - burstMode = false; - burstDist = 0; - burstVelocity = 0.0f; - unGuided = false; -} - -/* -================= -idGuidedProjectile::~idGuidedProjectile -================= -*/ -idGuidedProjectile::~idGuidedProjectile( void ) { -} - -/* -================ -idGuidedProjectile::Spawn -================ -*/ -void idGuidedProjectile::Spawn( void ) { -} - -/* -================ -idGuidedProjectile::Save -================ -*/ -void idGuidedProjectile::Save( idSaveGame *savefile ) const { - enemy.Save( savefile ); - savefile->WriteFloat( speed ); - savefile->WriteAngles( rndScale ); - savefile->WriteAngles( rndAng ); - savefile->WriteInt( rndUpdateTime ); - savefile->WriteFloat( turn_max ); - savefile->WriteFloat( clamp_dist ); - savefile->WriteAngles( angles ); - savefile->WriteBool( burstMode ); - savefile->WriteBool( unGuided ); - savefile->WriteFloat( burstDist ); - savefile->WriteFloat( burstVelocity ); -} - -/* -================ -idGuidedProjectile::Restore -================ -*/ -void idGuidedProjectile::Restore( idRestoreGame *savefile ) { - enemy.Restore( savefile ); - savefile->ReadFloat( speed ); - savefile->ReadAngles( rndScale ); - savefile->ReadAngles( rndAng ); - savefile->ReadInt( rndUpdateTime ); - savefile->ReadFloat( turn_max ); - savefile->ReadFloat( clamp_dist ); - savefile->ReadAngles( angles ); - savefile->ReadBool( burstMode ); - savefile->ReadBool( unGuided ); - savefile->ReadFloat( burstDist ); - savefile->ReadFloat( burstVelocity ); -} - - -/* -================ -idGuidedProjectile::GetSeekPos -================ -*/ -void idGuidedProjectile::GetSeekPos( idVec3 &out ) { - idEntity *enemyEnt = enemy.GetEntity(); - if ( enemyEnt ) { - if ( enemyEnt->IsType( idActor::Type ) ) { - out = static_cast(enemyEnt)->GetEyePosition(); - out.z -= 12.0f; - } else { - out = enemyEnt->GetPhysics()->GetOrigin(); - } - } else { - out = GetPhysics()->GetOrigin() + physicsObj.GetLinearVelocity() * 2.0f; - } -} - -/* -================ -idGuidedProjectile::Think -================ -*/ -void idGuidedProjectile::Think( void ) { - idVec3 dir; - idVec3 seekPos; - idVec3 velocity; - idVec3 nose; - idVec3 tmp; - idMat3 axis; - idAngles dirAng; - idAngles diff; - float dist; - float frac; - int i; - - if ( state == LAUNCHED && !unGuided ) { - - GetSeekPos( seekPos ); - - if ( rndUpdateTime < gameLocal.time ) { - rndAng[ 0 ] = rndScale[ 0 ] * gameLocal.random.CRandomFloat(); - rndAng[ 1 ] = rndScale[ 1 ] * gameLocal.random.CRandomFloat(); - rndAng[ 2 ] = rndScale[ 2 ] * gameLocal.random.CRandomFloat(); - rndUpdateTime = gameLocal.time + 200; - } - - nose = physicsObj.GetOrigin() + 10.0f * physicsObj.GetAxis()[0]; - - dir = seekPos - nose; - dist = dir.Normalize(); - dirAng = dir.ToAngles(); - - // make it more accurate as it gets closer - frac = dist / clamp_dist; - if ( frac > 1.0f ) { - frac = 1.0f; - } - - diff = dirAng - angles + rndAng * frac; - - // clamp the to the max turn rate - diff.Normalize180(); - for( i = 0; i < 3; i++ ) { - if ( diff[ i ] > turn_max ) { - diff[ i ] = turn_max; - } else if ( diff[ i ] < -turn_max ) { - diff[ i ] = -turn_max; - } - } - angles += diff; - - // make the visual model always points the dir we're traveling - dir = angles.ToForward(); - velocity = dir * speed; - - if ( burstMode && dist < burstDist ) { - unGuided = true; - velocity *= burstVelocity; - } - - physicsObj.SetLinearVelocity( velocity ); - - // align z-axis of model with the direction - axis = dir.ToMat3(); - tmp = axis[2]; - axis[2] = axis[0]; - axis[0] = -tmp; - - GetPhysics()->SetAxis( axis ); - } - - idProjectile::Think(); -} - -/* -================= -idGuidedProjectile::Launch -================= -*/ -void idGuidedProjectile::Launch( const idVec3 &start, const idVec3 &dir, const idVec3 &pushVelocity, const float timeSinceFire, const float launchPower, float dmgPower ) { - idProjectile::Launch( start, dir, pushVelocity, timeSinceFire, launchPower, dmgPower ); - if ( owner.GetEntity() ) { - if ( owner.GetEntity()->IsType( idAI::Type ) ) { - enemy = static_cast( owner.GetEntity() )->GetEnemy(); - } else if ( owner.GetEntity()->IsType( idPlayer::Type ) ) { - trace_t tr; - idPlayer *player = static_cast( owner.GetEntity() ); - idVec3 start = player->GetEyePosition(); - idVec3 end = start + player->viewAxis[0] * 1000.0f; - gameLocal.clip.TracePoint( tr, start, end, MASK_SHOT_RENDERMODEL | CONTENTS_BODY, owner.GetEntity() ); - if ( tr.fraction < 1.0f ) { - enemy = gameLocal.GetTraceEntity( tr ); - } - // ignore actors on the player's team - if ( enemy.GetEntity() == NULL || !enemy.GetEntity()->IsType( idActor::Type ) || ( static_cast( enemy.GetEntity() )->team == player->team ) ) { - enemy = player->EnemyWithMostHealth(); - } - } - } - const idVec3 &vel = physicsObj.GetLinearVelocity(); - angles = vel.ToAngles(); - speed = vel.Length(); - rndScale = spawnArgs.GetAngles( "random", "15 15 0" ); - turn_max = spawnArgs.GetFloat( "turn_max", "180" ) / ( float )USERCMD_HZ; - clamp_dist = spawnArgs.GetFloat( "clamp_dist", "256" ); - burstMode = spawnArgs.GetBool( "burstMode" ); - unGuided = false; - burstDist = spawnArgs.GetFloat( "burstDist", "64" ); - burstVelocity = spawnArgs.GetFloat( "burstVelocity", "1.25" ); - UpdateVisuals(); -} - -#ifdef _D3XP -void idGuidedProjectile::SetEnemy( idEntity *ent ) { - enemy = ent; -} -void idGuidedProjectile::Event_SetEnemy(idEntity *ent) { - SetEnemy(ent); -} -#endif - -/* -=============================================================================== - -idSoulCubeMissile - -=============================================================================== -*/ - -CLASS_DECLARATION( idGuidedProjectile, idSoulCubeMissile ) -END_CLASS - -/* -================ -idSoulCubeMissile::Spawn( void ) -================ -*/ -void idSoulCubeMissile::Spawn( void ) { - startingVelocity.Zero(); - endingVelocity.Zero(); - accelTime = 0.0f; - launchTime = 0; - killPhase = false; - returnPhase = false; - smokeKillTime = 0; - smokeKill = NULL; -} - -/* -================= -idSoulCubeMissile::~idSoulCubeMissile -================= -*/ -idSoulCubeMissile::~idSoulCubeMissile() { -} - -/* -================ -idSoulCubeMissile::Save -================ -*/ -void idSoulCubeMissile::Save( idSaveGame *savefile ) const { - savefile->WriteVec3( startingVelocity ); - savefile->WriteVec3( endingVelocity ); - savefile->WriteFloat( accelTime ); - savefile->WriteInt( launchTime ); - savefile->WriteBool( killPhase ); - savefile->WriteBool( returnPhase ); - savefile->WriteVec3( destOrg); - savefile->WriteInt( orbitTime ); - savefile->WriteVec3( orbitOrg ); - savefile->WriteInt( smokeKillTime ); - savefile->WriteParticle( smokeKill ); -} - -/* -================ -idSoulCubeMissile::Restore -================ -*/ -void idSoulCubeMissile::Restore( idRestoreGame *savefile ) { - savefile->ReadVec3( startingVelocity ); - savefile->ReadVec3( endingVelocity ); - savefile->ReadFloat( accelTime ); - savefile->ReadInt( launchTime ); - savefile->ReadBool( killPhase ); - savefile->ReadBool( returnPhase ); - savefile->ReadVec3( destOrg); - savefile->ReadInt( orbitTime ); - savefile->ReadVec3( orbitOrg ); - savefile->ReadInt( smokeKillTime ); - savefile->ReadParticle( smokeKill ); -} - -/* -================ -idSoulCubeMissile::KillTarget -================ -*/ -void idSoulCubeMissile::KillTarget( const idVec3 &dir ) { - idEntity *ownerEnt; - const char *smokeName; - idActor *act; - - ReturnToOwner(); - if ( enemy.GetEntity() && enemy.GetEntity()->IsType( idActor::Type ) ) { - act = static_cast( enemy.GetEntity() ); - killPhase = true; - orbitOrg = act->GetPhysics()->GetAbsBounds().GetCenter(); - orbitTime = gameLocal.time; - smokeKillTime = 0; - smokeName = spawnArgs.GetString( "smoke_kill" ); - if ( *smokeName != '\0' ) { - smokeKill = static_cast( declManager->FindType( DECL_PARTICLE, smokeName ) ); - smokeKillTime = gameLocal.time; - } - ownerEnt = owner.GetEntity(); - if ( ( act->health > 0 ) && ownerEnt && ownerEnt->IsType( idPlayer::Type ) && ( ownerEnt->health > 0 ) && !act->spawnArgs.GetBool( "boss" ) ) { - static_cast( ownerEnt )->GiveHealthPool( act->health ); - } - act->Damage( this, owner.GetEntity(), dir, spawnArgs.GetString( "def_damage" ), 1.0f, INVALID_JOINT ); - act->GetAFPhysics()->SetTimeScale( 0.25 ); - StartSound( "snd_explode", SND_CHANNEL_BODY, 0, false, NULL ); - } -} - -/* -================ -idSoulCubeMissile::Think -================ -*/ -void idSoulCubeMissile::Think( void ) { - float pct; - idVec3 seekPos; - idEntity *ownerEnt; - - if ( state == LAUNCHED ) { - if ( killPhase ) { - // orbit the mob, cascading down - if ( gameLocal.time < orbitTime + 1500 ) { - if ( !gameLocal.smokeParticles->EmitSmoke( smokeKill, smokeKillTime, gameLocal.random.CRandomFloat(), orbitOrg, mat3_identity, timeGroup /*_D3XP*/ ) ) { - smokeKillTime = gameLocal.time; - } - } - } else { - if ( accelTime && gameLocal.time < launchTime + accelTime * 1000 ) { - pct = ( gameLocal.time - launchTime ) / ( accelTime * 1000 ); - speed = ( startingVelocity + ( startingVelocity + endingVelocity ) * pct ).Length(); - } - } - idGuidedProjectile::Think(); - GetSeekPos( seekPos ); - if ( ( seekPos - physicsObj.GetOrigin() ).Length() < 32.0f ) { - if ( returnPhase ) { - StopSound( SND_CHANNEL_ANY, false ); - StartSound( "snd_return", SND_CHANNEL_BODY2, 0, false, NULL ); - Hide(); - PostEventSec( &EV_Remove, 2.0f ); - - ownerEnt = owner.GetEntity(); - if ( ownerEnt && ownerEnt->IsType( idPlayer::Type ) ) { - static_cast( ownerEnt )->SetSoulCubeProjectile( NULL ); - } - - state = FIZZLED; - } else if ( !killPhase ){ - KillTarget( physicsObj.GetAxis()[0] ); - } - } - } -} - -/* -================ -idSoulCubeMissile::GetSeekPos -================ -*/ -void idSoulCubeMissile::GetSeekPos( idVec3 &out ) { - if ( returnPhase && owner.GetEntity() && owner.GetEntity()->IsType( idActor::Type ) ) { - idActor *act = static_cast( owner.GetEntity() ); - out = act->GetEyePosition(); - return; - } - if ( destOrg != vec3_zero ) { - out = destOrg; - return; - } - idGuidedProjectile::GetSeekPos( out ); -} - - -/* -================ -idSoulCubeMissile::Event_ReturnToOwner -================ -*/ -void idSoulCubeMissile::ReturnToOwner() { - speed *= 0.65f; - killPhase = false; - returnPhase = true; - smokeFlyTime = 0; -} - - -/* -================= -idSoulCubeMissile::Launch -================= -*/ -void idSoulCubeMissile::Launch( const idVec3 &start, const idVec3 &dir, const idVec3 &pushVelocity, const float timeSinceFire, const float launchPower, float dmgPower ) { - idVec3 newStart; - idVec3 offs; - idEntity *ownerEnt; - - // push it out a little - newStart = start + dir * spawnArgs.GetFloat( "launchDist" ); - offs = spawnArgs.GetVector( "launchOffset", "0 0 -4" ); - newStart += offs; - idGuidedProjectile::Launch( newStart, dir, pushVelocity, timeSinceFire, launchPower, dmgPower ); - if ( enemy.GetEntity() == NULL || !enemy.GetEntity()->IsType( idActor::Type ) ) { - destOrg = start + dir * 256.0f; - } else { - destOrg.Zero(); - } - physicsObj.SetClipMask( 0 ); // never collide.. think routine will decide when to detonate - startingVelocity = spawnArgs.GetVector( "startingVelocity", "15 0 0" ); - endingVelocity = spawnArgs.GetVector( "endingVelocity", "1500 0 0" ); - accelTime = spawnArgs.GetFloat( "accelTime", "5" ); - physicsObj.SetLinearVelocity( startingVelocity.Length() * physicsObj.GetAxis()[2] ); - launchTime = gameLocal.time; - killPhase = false; - UpdateVisuals(); - - ownerEnt = owner.GetEntity(); - if ( ownerEnt && ownerEnt->IsType( idPlayer::Type ) ) { - static_cast( ownerEnt )->SetSoulCubeProjectile( this ); - } - -} - - -/* -=============================================================================== - -idBFGProjectile - -=============================================================================== -*/ -const idEventDef EV_RemoveBeams( "", NULL ); - -CLASS_DECLARATION( idProjectile, idBFGProjectile ) - EVENT( EV_RemoveBeams, idBFGProjectile::Event_RemoveBeams ) -END_CLASS - - -/* -================= -idBFGProjectile::idBFGProjectile -================= -*/ -idBFGProjectile::idBFGProjectile() { - memset( &secondModel, 0, sizeof( secondModel ) ); - secondModelDefHandle = -1; - nextDamageTime = 0; -} - -/* -================= -idBFGProjectile::~idBFGProjectile -================= -*/ -idBFGProjectile::~idBFGProjectile() { - FreeBeams(); - - if ( secondModelDefHandle >= 0 ) { - gameRenderWorld->FreeEntityDef( secondModelDefHandle ); - secondModelDefHandle = -1; - } -} - -/* -================ -idBFGProjectile::Spawn -================ -*/ -void idBFGProjectile::Spawn( void ) { - beamTargets.Clear(); - memset( &secondModel, 0, sizeof( secondModel ) ); - secondModelDefHandle = -1; - const char *temp = spawnArgs.GetString( "model_two" ); - if ( temp && *temp ) { - secondModel.hModel = renderModelManager->FindModel( temp ); - secondModel.bounds = secondModel.hModel->Bounds( &secondModel ); - secondModel.shaderParms[ SHADERPARM_RED ] = - secondModel.shaderParms[ SHADERPARM_GREEN ] = - secondModel.shaderParms[ SHADERPARM_BLUE ] = - secondModel.shaderParms[ SHADERPARM_ALPHA ] = 1.0f; - secondModel.noSelfShadow = true; - secondModel.noShadow = true; - } - nextDamageTime = 0; - damageFreq = NULL; -} - -/* -================ -idBFGProjectile::Save -================ -*/ -void idBFGProjectile::Save( idSaveGame *savefile ) const { - int i; - - savefile->WriteInt( beamTargets.Num() ); - for ( i = 0; i < beamTargets.Num(); i++ ) { - beamTargets[i].target.Save( savefile ); - savefile->WriteRenderEntity( beamTargets[i].renderEntity ); - savefile->WriteInt( beamTargets[i].modelDefHandle ); - } - - savefile->WriteRenderEntity( secondModel ); - savefile->WriteInt( secondModelDefHandle ); - savefile->WriteInt( nextDamageTime ); - savefile->WriteString( damageFreq ); -} - -/* -================ -idBFGProjectile::Restore -================ -*/ -void idBFGProjectile::Restore( idRestoreGame *savefile ) { - int i, num; - - savefile->ReadInt( num ); - beamTargets.SetNum( num ); - for ( i = 0; i < num; i++ ) { - beamTargets[i].target.Restore( savefile ); - savefile->ReadRenderEntity( beamTargets[i].renderEntity ); - savefile->ReadInt( beamTargets[i].modelDefHandle ); - - if ( beamTargets[i].modelDefHandle >= 0 ) { - beamTargets[i].modelDefHandle = gameRenderWorld->AddEntityDef( &beamTargets[i].renderEntity ); - } - } - - savefile->ReadRenderEntity( secondModel ); - savefile->ReadInt( secondModelDefHandle ); - savefile->ReadInt( nextDamageTime ); - savefile->ReadString( damageFreq ); - - if ( secondModelDefHandle >= 0 ) { - secondModelDefHandle = gameRenderWorld->AddEntityDef( &secondModel ); - } -} - -/* -================= -idBFGProjectile::FreeBeams -================= -*/ -void idBFGProjectile::FreeBeams() { - for ( int i = 0; i < beamTargets.Num(); i++ ) { - if ( beamTargets[i].modelDefHandle >= 0 ) { - gameRenderWorld->FreeEntityDef( beamTargets[i].modelDefHandle ); - beamTargets[i].modelDefHandle = -1; - } - } - - idPlayer *player = gameLocal.GetLocalPlayer(); - if ( player ) { - player->playerView.EnableBFGVision( false ); - } -} - -/* -================ -idBFGProjectile::Think -================ -*/ -void idBFGProjectile::Think( void ) { - if ( state == LAUNCHED ) { - - // update beam targets - for ( int i = 0; i < beamTargets.Num(); i++ ) { - if ( beamTargets[i].target.GetEntity() == NULL ) { - continue; - } - idPlayer *player = ( beamTargets[i].target.GetEntity()->IsType( idPlayer::Type ) ) ? static_cast( beamTargets[i].target.GetEntity() ) : NULL; -#ifdef _D3XP - // Major hack for end boss. :( - idAnimatedEntity *beamEnt; - idVec3 org; - bool forceDamage = false; - - beamEnt = static_cast(beamTargets[i].target.GetEntity()); - if ( !idStr::Cmp( beamEnt->GetEntityDefName(), "monster_boss_d3xp_maledict" ) ) { - SetTimeState ts( beamEnt->timeGroup ); - idMat3 temp; - jointHandle_t bodyJoint; - - bodyJoint = beamEnt->GetAnimator()->GetJointHandle( "Chest1" ); - beamEnt->GetJointWorldTransform( bodyJoint, gameLocal.time, org, temp ); - - forceDamage = true; - } else { - org = beamEnt->GetPhysics()->GetAbsBounds().GetCenter(); - } -#else - idVec3 org = beamTargets[i].target.GetEntity()->GetPhysics()->GetAbsBounds().GetCenter(); -#endif - beamTargets[i].renderEntity.origin = GetPhysics()->GetOrigin(); - beamTargets[i].renderEntity.shaderParms[ SHADERPARM_BEAM_END_X ] = org.x; - beamTargets[i].renderEntity.shaderParms[ SHADERPARM_BEAM_END_Y ] = org.y; - beamTargets[i].renderEntity.shaderParms[ SHADERPARM_BEAM_END_Z ] = org.z; - beamTargets[i].renderEntity.shaderParms[ SHADERPARM_RED ] = - beamTargets[i].renderEntity.shaderParms[ SHADERPARM_GREEN ] = - beamTargets[i].renderEntity.shaderParms[ SHADERPARM_BLUE ] = - beamTargets[i].renderEntity.shaderParms[ SHADERPARM_ALPHA ] = 1.0f; - if ( gameLocal.time > nextDamageTime ) { - bool bfgVision = true; -#ifdef _D3XP - if ( damageFreq && *(const char *)damageFreq && beamTargets[i].target.GetEntity() && ( forceDamage || beamTargets[i].target.GetEntity()->CanDamage( GetPhysics()->GetOrigin(), org ) ) ) { -#else - if ( damageFreq && *(const char *)damageFreq && beamTargets[i].target.GetEntity() && beamTargets[i].target.GetEntity()->CanDamage( GetPhysics()->GetOrigin(), org ) ) { -#endif - org = beamTargets[i].target.GetEntity()->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin(); - org.Normalize(); - beamTargets[i].target.GetEntity()->Damage( this, owner.GetEntity(), org, damageFreq, ( damagePower ) ? damagePower : 1.0f, INVALID_JOINT ); - } else { - beamTargets[i].renderEntity.shaderParms[ SHADERPARM_RED ] = - beamTargets[i].renderEntity.shaderParms[ SHADERPARM_GREEN ] = - beamTargets[i].renderEntity.shaderParms[ SHADERPARM_BLUE ] = - beamTargets[i].renderEntity.shaderParms[ SHADERPARM_ALPHA ] = 0.0f; - bfgVision = false; - } - if ( player ) { - player->playerView.EnableBFGVision( bfgVision ); - } - nextDamageTime = gameLocal.time + BFG_DAMAGE_FREQUENCY; - } - gameRenderWorld->UpdateEntityDef( beamTargets[i].modelDefHandle, &beamTargets[i].renderEntity ); - } - - if ( secondModelDefHandle >= 0 ) { - secondModel.origin = GetPhysics()->GetOrigin(); - gameRenderWorld->UpdateEntityDef( secondModelDefHandle, &secondModel ); - } - - idAngles ang; - - ang.pitch = ( gameLocal.time & 4095 ) * 360.0f / -4096.0f; - ang.yaw = ang.pitch; - ang.roll = 0.0f; - SetAngles( ang ); - - ang.pitch = ( gameLocal.time & 2047 ) * 360.0f / -2048.0f; - ang.yaw = ang.pitch; - ang.roll = 0.0f; - secondModel.axis = ang.ToMat3(); - - UpdateVisuals(); - } - - idProjectile::Think(); -} - -/* -================= -idBFGProjectile::Launch -================= -*/ -void idBFGProjectile::Launch( const idVec3 &start, const idVec3 &dir, const idVec3 &pushVelocity, const float timeSinceFire, const float power, const float dmgPower ) { - idProjectile::Launch( start, dir, pushVelocity, 0.0f, power, dmgPower ); - - // dmgPower * radius is the target acquisition area - // acquisition should make sure that monsters are not dormant - // which will cut down on hitting monsters not actively fighting - // but saves on the traces making sure they are visible - // damage is not applied until the projectile explodes - - idEntity * ent; - idEntity * entityList[ MAX_GENTITIES ]; - int numListedEntities; - idBounds bounds; - idVec3 damagePoint; - - float radius; - spawnArgs.GetFloat( "damageRadius", "512", radius ); - bounds = idBounds( GetPhysics()->GetOrigin() ).Expand( radius ); - - float beamWidth = spawnArgs.GetFloat( "beam_WidthFly" ); - const char *skin = spawnArgs.GetString( "skin_beam" ); - - memset( &secondModel, 0, sizeof( secondModel ) ); - secondModelDefHandle = -1; - const char *temp = spawnArgs.GetString( "model_two" ); - if ( temp && *temp ) { - secondModel.hModel = renderModelManager->FindModel( temp ); - secondModel.bounds = secondModel.hModel->Bounds( &secondModel ); - secondModel.shaderParms[ SHADERPARM_RED ] = - secondModel.shaderParms[ SHADERPARM_GREEN ] = - secondModel.shaderParms[ SHADERPARM_BLUE ] = - secondModel.shaderParms[ SHADERPARM_ALPHA ] = 1.0f; - secondModel.noSelfShadow = true; - secondModel.noShadow = true; - secondModel.origin = GetPhysics()->GetOrigin(); - secondModel.axis = GetPhysics()->GetAxis(); - secondModelDefHandle = gameRenderWorld->AddEntityDef( &secondModel ); - } - - idVec3 delta( 15.0f, 15.0f, 15.0f ); - //physicsObj.SetAngularExtrapolation( extrapolation_t(EXTRAPOLATION_LINEAR|EXTRAPOLATION_NOSTOP), gameLocal.time, 0, physicsObj.GetAxis().ToAngles(), delta, ang_zero ); - - // get all entities touching the bounds - numListedEntities = gameLocal.clip.EntitiesTouchingBounds( bounds, CONTENTS_BODY, entityList, MAX_GENTITIES ); - for ( int e = 0; e < numListedEntities; e++ ) { - ent = entityList[ e ]; - assert( ent ); - - if ( ent == this || ent == owner.GetEntity() || ent->IsHidden() || !ent->IsActive() || !ent->fl.takedamage || ent->health <= 0 || !ent->IsType( idActor::Type ) ) { - continue; - } - - if ( !ent->CanDamage( GetPhysics()->GetOrigin(), damagePoint ) ) { - continue; - } - - if ( ent->IsType( idPlayer::Type ) ) { - idPlayer *player = static_cast( ent ); - player->playerView.EnableBFGVision( true ); - } - - beamTarget_t bt; - memset( &bt.renderEntity, 0, sizeof( renderEntity_t ) ); - bt.renderEntity.origin = GetPhysics()->GetOrigin(); - bt.renderEntity.axis = GetPhysics()->GetAxis(); - bt.renderEntity.shaderParms[ SHADERPARM_BEAM_WIDTH ] = beamWidth; - bt.renderEntity.shaderParms[ SHADERPARM_RED ] = 1.0f; - bt.renderEntity.shaderParms[ SHADERPARM_GREEN ] = 1.0f; - bt.renderEntity.shaderParms[ SHADERPARM_BLUE ] = 1.0f; - bt.renderEntity.shaderParms[ SHADERPARM_ALPHA ] = 1.0f; - bt.renderEntity.shaderParms[ SHADERPARM_DIVERSITY] = gameLocal.random.CRandomFloat() * 0.75; - bt.renderEntity.hModel = renderModelManager->FindModel( "_beam" ); - bt.renderEntity.callback = NULL; - bt.renderEntity.numJoints = 0; - bt.renderEntity.joints = NULL; - bt.renderEntity.bounds.Clear(); - bt.renderEntity.customSkin = declManager->FindSkin( skin ); - bt.target = ent; - bt.modelDefHandle = gameRenderWorld->AddEntityDef( &bt.renderEntity ); - beamTargets.Append( bt ); - } - -#ifdef _D3XP - // Major hack for end boss. :( - idAnimatedEntity *maledict = static_cast(gameLocal.FindEntity( "monster_boss_d3xp_maledict_1" )); - - if ( maledict ) { - SetTimeState ts( maledict->timeGroup ); - - idVec3 realPoint; - idMat3 temp; - float dist; - jointHandle_t bodyJoint; - - bodyJoint = maledict->GetAnimator()->GetJointHandle( "Chest1" ); - maledict->GetJointWorldTransform( bodyJoint, gameLocal.time, realPoint, temp ); - - dist = idVec3( realPoint - GetPhysics()->GetOrigin() ).Length(); - - if ( dist < radius ) { - beamTarget_t bt; - memset( &bt.renderEntity, 0, sizeof( renderEntity_t ) ); - bt.renderEntity.origin = GetPhysics()->GetOrigin(); - bt.renderEntity.axis = GetPhysics()->GetAxis(); - bt.renderEntity.shaderParms[ SHADERPARM_BEAM_WIDTH ] = beamWidth; - bt.renderEntity.shaderParms[ SHADERPARM_RED ] = 1.0f; - bt.renderEntity.shaderParms[ SHADERPARM_GREEN ] = 1.0f; - bt.renderEntity.shaderParms[ SHADERPARM_BLUE ] = 1.0f; - bt.renderEntity.shaderParms[ SHADERPARM_ALPHA ] = 1.0f; - bt.renderEntity.shaderParms[ SHADERPARM_DIVERSITY] = gameLocal.random.CRandomFloat() * 0.75; - bt.renderEntity.hModel = renderModelManager->FindModel( "_beam" ); - bt.renderEntity.callback = NULL; - bt.renderEntity.numJoints = 0; - bt.renderEntity.joints = NULL; - bt.renderEntity.bounds.Clear(); - bt.renderEntity.customSkin = declManager->FindSkin( skin ); - bt.target = maledict; - bt.modelDefHandle = gameRenderWorld->AddEntityDef( &bt.renderEntity ); - beamTargets.Append( bt ); - - numListedEntities++; - } - } -#endif - - if ( numListedEntities ) { - StartSound( "snd_beam", SND_CHANNEL_BODY2, 0, false, NULL ); - } - damageFreq = spawnArgs.GetString( "def_damageFreq" ); - nextDamageTime = gameLocal.time + BFG_DAMAGE_FREQUENCY; - UpdateVisuals(); -} - -/* -================ -idProjectile::Event_RemoveBeams -================ -*/ -void idBFGProjectile::Event_RemoveBeams() { - FreeBeams(); - UpdateVisuals(); -} - -/* -================ -idProjectile::Explode -================ -*/ -void idBFGProjectile::Explode( const trace_t &collision, idEntity *ignore ) { - int i; - idVec3 dmgPoint; - idVec3 dir; - float beamWidth; - float damageScale; - const char *damage; - idPlayer * player; - idEntity * ownerEnt; - - ownerEnt = owner.GetEntity(); - if ( ownerEnt && ownerEnt->IsType( idPlayer::Type ) ) { - player = static_cast< idPlayer * >( ownerEnt ); - } else { - player = NULL; - } - - beamWidth = spawnArgs.GetFloat( "beam_WidthExplode" ); - damage = spawnArgs.GetString( "def_damage" ); - - for ( i = 0; i < beamTargets.Num(); i++ ) { - if ( ( beamTargets[i].target.GetEntity() == NULL ) || ( ownerEnt == NULL ) ) { - continue; - } - - if ( !beamTargets[i].target.GetEntity()->CanDamage( GetPhysics()->GetOrigin(), dmgPoint ) ) { - continue; - } - - beamTargets[i].renderEntity.shaderParms[SHADERPARM_BEAM_WIDTH] = beamWidth; - - // if the hit entity takes damage - if ( damagePower ) { - damageScale = damagePower; - } else { - damageScale = 1.0f; - } - - // if the projectile owner is a player - if ( player ) { - // if the projectile hit an actor - if ( beamTargets[i].target.GetEntity()->IsType( idActor::Type ) ) { - player->SetLastHitTime( gameLocal.time ); - player->AddProjectileHits( 1 ); - damageScale *= player->PowerUpModifier( PROJECTILE_DAMAGE ); - } - } - - if ( damage[0] && ( beamTargets[i].target.GetEntity()->entityNumber > gameLocal.numClients - 1 ) ) { - dir = beamTargets[i].target.GetEntity()->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin(); - dir.Normalize(); - beamTargets[i].target.GetEntity()->Damage( this, ownerEnt, dir, damage, damageScale, ( collision.c.id < 0 ) ? CLIPMODEL_ID_TO_JOINT_HANDLE( collision.c.id ) : INVALID_JOINT ); - } - } - - if ( secondModelDefHandle >= 0 ) { - gameRenderWorld->FreeEntityDef( secondModelDefHandle ); - secondModelDefHandle = -1; - } - - if ( ignore == NULL ) { - projectileFlags.noSplashDamage = true; - } - - if ( !gameLocal.isClient ) { - if ( ignore != NULL ) { - PostEventMS( &EV_RemoveBeams, 750 ); - } else { - PostEventMS( &EV_RemoveBeams, 0 ); - } - } - - return idProjectile::Explode( collision, ignore ); -} - - -/* -=============================================================================== - - idDebris - -=============================================================================== -*/ - -CLASS_DECLARATION( idEntity, idDebris ) -EVENT( EV_Explode, idDebris::Event_Explode ) -EVENT( EV_Fizzle, idDebris::Event_Fizzle ) -END_CLASS - -/* -================ -idDebris::Spawn -================ -*/ -void idDebris::Spawn( void ) { - owner = NULL; - smokeFly = NULL; - smokeFlyTime = 0; -} - -/* -================ -idDebris::Create -================ -*/ -void idDebris::Create( idEntity *owner, const idVec3 &start, const idMat3 &axis ) { - Unbind(); - GetPhysics()->SetOrigin( start ); - GetPhysics()->SetAxis( axis ); - GetPhysics()->SetContents( 0 ); - this->owner = owner; - smokeFly = NULL; - smokeFlyTime = 0; - sndBounce = NULL; -#ifdef _D3XP - noGrab = true; -#endif - UpdateVisuals(); -} - -/* -================= -idDebris::idDebris -================= -*/ -idDebris::idDebris( void ) { - owner = NULL; - smokeFly = NULL; - smokeFlyTime = 0; - sndBounce = NULL; -} - -/* -================= -idDebris::~idDebris -================= -*/ -idDebris::~idDebris( void ) { -} - -/* -================= -idDebris::Save -================= -*/ -void idDebris::Save( idSaveGame *savefile ) const { - owner.Save( savefile ); - - savefile->WriteStaticObject( physicsObj ); - - savefile->WriteParticle( smokeFly ); - savefile->WriteInt( smokeFlyTime ); - savefile->WriteSoundShader( sndBounce ); -} - -/* -================= -idDebris::Restore -================= -*/ -void idDebris::Restore( idRestoreGame *savefile ) { - owner.Restore( savefile ); - - savefile->ReadStaticObject( physicsObj ); - RestorePhysics( &physicsObj ); - - savefile->ReadParticle( smokeFly ); - savefile->ReadInt( smokeFlyTime ); - savefile->ReadSoundShader( sndBounce ); -} - -/* -================= -idDebris::Launch -================= -*/ -void idDebris::Launch( void ) { - float fuse; - idVec3 velocity; - idAngles angular_velocity; - float linear_friction; - float angular_friction; - float contact_friction; - float bounce; - float mass; - float gravity; - idVec3 gravVec; - bool randomVelocity; - idMat3 axis; - - renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time ); - - spawnArgs.GetVector( "velocity", "0 0 0", velocity ); - spawnArgs.GetAngles( "angular_velocity", "0 0 0", angular_velocity ); - - linear_friction = spawnArgs.GetFloat( "linear_friction" ); - angular_friction = spawnArgs.GetFloat( "angular_friction" ); - contact_friction = spawnArgs.GetFloat( "contact_friction" ); - bounce = spawnArgs.GetFloat( "bounce" ); - mass = spawnArgs.GetFloat( "mass" ); - gravity = spawnArgs.GetFloat( "gravity" ); - fuse = spawnArgs.GetFloat( "fuse" ); - randomVelocity = spawnArgs.GetBool ( "random_velocity" ); - - if ( mass <= 0 ) { - gameLocal.Error( "Invalid mass on '%s'\n", GetEntityDefName() ); - } - - if ( randomVelocity ) { - velocity.x *= gameLocal.random.RandomFloat() + 0.5f; - velocity.y *= gameLocal.random.RandomFloat() + 0.5f; - velocity.z *= gameLocal.random.RandomFloat() + 0.5f; - } - - if ( health ) { - fl.takedamage = true; - } - - gravVec = gameLocal.GetGravity(); - gravVec.NormalizeFast(); - axis = GetPhysics()->GetAxis(); - - Unbind(); - - physicsObj.SetSelf( this ); - - // check if a clip model is set - const char *clipModelName; - idTraceModel trm; - spawnArgs.GetString( "clipmodel", "", &clipModelName ); - if ( !clipModelName[0] ) { - clipModelName = spawnArgs.GetString( "model" ); // use the visual model - } - - // load the trace model - if ( !collisionModelManager->TrmFromModel( clipModelName, trm ) ) { - // default to a box - physicsObj.SetClipBox( renderEntity.bounds, 1.0f ); - } else { - physicsObj.SetClipModel( new idClipModel( trm ), 1.0f ); - } - - physicsObj.GetClipModel()->SetOwner( owner.GetEntity() ); - physicsObj.SetMass( mass ); - physicsObj.SetFriction( linear_friction, angular_friction, contact_friction ); - if ( contact_friction == 0.0f ) { - physicsObj.NoContact(); - } - physicsObj.SetBouncyness( bounce ); - physicsObj.SetGravity( gravVec * gravity ); - physicsObj.SetContents( 0 ); - physicsObj.SetClipMask( MASK_SOLID | CONTENTS_MOVEABLECLIP ); - physicsObj.SetLinearVelocity( axis[ 0 ] * velocity[ 0 ] + axis[ 1 ] * velocity[ 1 ] + axis[ 2 ] * velocity[ 2 ] ); - physicsObj.SetAngularVelocity( angular_velocity.ToAngularVelocity() * axis ); - physicsObj.SetOrigin( GetPhysics()->GetOrigin() ); - physicsObj.SetAxis( axis ); - SetPhysics( &physicsObj ); - - if ( !gameLocal.isClient ) { - if ( fuse <= 0 ) { - // run physics for 1 second - RunPhysics(); - PostEventMS( &EV_Remove, 0 ); - } else if ( spawnArgs.GetBool( "detonate_on_fuse" ) ) { - if ( fuse < 0.0f ) { - fuse = 0.0f; - } - RunPhysics(); - PostEventSec( &EV_Explode, fuse ); - } else { - if ( fuse < 0.0f ) { - fuse = 0.0f; - } - PostEventSec( &EV_Fizzle, fuse ); - } - } - - StartSound( "snd_fly", SND_CHANNEL_BODY, 0, false, NULL ); - - smokeFly = NULL; - smokeFlyTime = 0; - const char *smokeName = spawnArgs.GetString( "smoke_fly" ); - if ( *smokeName != '\0' ) { - smokeFly = static_cast( declManager->FindType( DECL_PARTICLE, smokeName ) ); - smokeFlyTime = gameLocal.time; - gameLocal.smokeParticles->EmitSmoke( smokeFly, smokeFlyTime, gameLocal.random.CRandomFloat(), GetPhysics()->GetOrigin(), GetPhysics()->GetAxis(), timeGroup /*_D3XP*/ ); - } - - const char *sndName = spawnArgs.GetString( "snd_bounce" ); - if ( *sndName != '\0' ) { - sndBounce = declManager->FindSound( sndName ); - } - - UpdateVisuals(); -} - -/* -================ -idDebris::Think -================ -*/ -void idDebris::Think( void ) { - - // run physics - RunPhysics(); - Present(); - - if ( smokeFly && smokeFlyTime ) { - if ( !gameLocal.smokeParticles->EmitSmoke( smokeFly, smokeFlyTime, gameLocal.random.CRandomFloat(), GetPhysics()->GetOrigin(), GetPhysics()->GetAxis(), timeGroup /*_D3XP*/ ) ) { - smokeFlyTime = 0; - } - } -} - -/* -================ -idDebris::Killed -================ -*/ -void idDebris::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) { - if ( spawnArgs.GetBool( "detonate_on_death" ) ) { - Explode(); - } else { - Fizzle(); - } -} - -/* -================= -idDebris::Collide -================= -*/ -bool idDebris::Collide( const trace_t &collision, const idVec3 &velocity ) { - if ( sndBounce != NULL ) { - StartSoundShader( sndBounce, SND_CHANNEL_BODY, 0, false, NULL ); - } - sndBounce = NULL; - return false; -} - - -/* -================ -idDebris::Fizzle -================ -*/ -void idDebris::Fizzle( void ) { - if ( IsHidden() ) { - // already exploded - return; - } - - StopSound( SND_CHANNEL_ANY, false ); - StartSound( "snd_fizzle", SND_CHANNEL_BODY, 0, false, NULL ); - - // fizzle FX - const char *smokeName = spawnArgs.GetString( "smoke_fuse" ); - if ( *smokeName != '\0' ) { - smokeFly = static_cast( declManager->FindType( DECL_PARTICLE, smokeName ) ); - smokeFlyTime = gameLocal.time; - gameLocal.smokeParticles->EmitSmoke( smokeFly, smokeFlyTime, gameLocal.random.CRandomFloat(), GetPhysics()->GetOrigin(), GetPhysics()->GetAxis(), timeGroup /*_D3XP*/ ); - } - - fl.takedamage = false; - physicsObj.SetContents( 0 ); - physicsObj.PutToRest(); - - Hide(); - - if ( gameLocal.isClient ) { - return; - } - - CancelEvents( &EV_Fizzle ); - PostEventMS( &EV_Remove, 0 ); -} - -/* -================ -idDebris::Explode -================ -*/ -void idDebris::Explode( void ) { - if ( IsHidden() ) { - // already exploded - return; - } - - StopSound( SND_CHANNEL_ANY, false ); - StartSound( "snd_explode", SND_CHANNEL_BODY, 0, false, NULL ); - - Hide(); - - // these must not be "live forever" particle systems - smokeFly = NULL; - smokeFlyTime = 0; - const char *smokeName = spawnArgs.GetString( "smoke_detonate" ); - if ( *smokeName != '\0' ) { - smokeFly = static_cast( declManager->FindType( DECL_PARTICLE, smokeName ) ); - smokeFlyTime = gameLocal.time; - gameLocal.smokeParticles->EmitSmoke( smokeFly, smokeFlyTime, gameLocal.random.CRandomFloat(), GetPhysics()->GetOrigin(), GetPhysics()->GetAxis(), timeGroup /*_D3XP*/ ); - } - - fl.takedamage = false; - physicsObj.SetContents( 0 ); - physicsObj.PutToRest(); - - CancelEvents( &EV_Explode ); - PostEventMS( &EV_Remove, 0 ); -} - -/* -================ -idDebris::Event_Explode -================ -*/ -void idDebris::Event_Explode( void ) { - Explode(); -} - -/* -================ -idDebris::Event_Fizzle -================ -*/ -void idDebris::Event_Fizzle( void ) { - Fizzle(); -} diff --git a/d3xp/Projectile.h b/d3xp/Projectile.h deleted file mode 100644 index ed2433a0..00000000 --- a/d3xp/Projectile.h +++ /dev/null @@ -1,288 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __GAME_PROJECTILE_H__ -#define __GAME_PROJECTILE_H__ - -#include "physics/Physics_RigidBody.h" -#include "physics/Force_Constant.h" -#include "Entity.h" - -/* -=============================================================================== - - idProjectile - -=============================================================================== -*/ - -extern const idEventDef EV_Explode; - -class idProjectile : public idEntity { -public : - CLASS_PROTOTYPE( idProjectile ); - - idProjectile(); - virtual ~idProjectile(); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void Create( idEntity *owner, const idVec3 &start, const idVec3 &dir ); - virtual void Launch( const idVec3 &start, const idVec3 &dir, const idVec3 &pushVelocity, const float timeSinceFire = 0.0f, const float launchPower = 1.0f, const float dmgPower = 1.0f ); - virtual void FreeLightDef( void ); - - idEntity * GetOwner( void ) const; -#ifdef _D3XP - void CatchProjectile( idEntity* o, const char* reflectName ); - int GetProjectileState( void ); - void Event_CreateProjectile( idEntity *owner, const idVec3 &start, const idVec3 &dir ); - void Event_LaunchProjectile( const idVec3 &start, const idVec3 &dir, const idVec3 &pushVelocity ); - void Event_SetGravity( float gravity ); -#endif - - virtual void Think( void ); - virtual void Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ); - virtual bool Collide( const trace_t &collision, const idVec3 &velocity ); - virtual void Explode( const trace_t &collision, idEntity *ignore ); - void Fizzle( void ); - - static idVec3 GetVelocity( const idDict *projectile ); - static idVec3 GetGravity( const idDict *projectile ); - - enum { - EVENT_DAMAGE_EFFECT = idEntity::EVENT_MAXEVENTS, - EVENT_MAXEVENTS - }; - - static void DefaultDamageEffect( idEntity *soundEnt, const idDict &projectileDef, const trace_t &collision, const idVec3 &velocity ); - static bool ClientPredictionCollide( idEntity *soundEnt, const idDict &projectileDef, const trace_t &collision, const idVec3 &velocity, bool addDamageEffect ); - virtual void ClientPredictionThink( void ); - virtual void WriteToSnapshot( idBitMsgDelta &msg ) const; - virtual void ReadFromSnapshot( const idBitMsgDelta &msg ); - virtual bool ClientReceiveEvent( int event, int time, const idBitMsg &msg ); - -protected: - idEntityPtr owner; - - struct projectileFlags_s { - bool detonate_on_world : 1; - bool detonate_on_actor : 1; - bool randomShaderSpin : 1; - bool isTracer : 1; - bool noSplashDamage : 1; - } projectileFlags; - - float thrust; - int thrust_end; - float damagePower; - - renderLight_t renderLight; - qhandle_t lightDefHandle; // handle to renderer light def - idVec3 lightOffset; - int lightStartTime; - int lightEndTime; - idVec3 lightColor; - - idForce_Constant thruster; - idPhysics_RigidBody physicsObj; - - const idDeclParticle * smokeFly; - int smokeFlyTime; - -#ifdef _D3XP - int originalTimeGroup; -#endif - - typedef enum { - // must update these in script/doom_defs.script if changed - SPAWNED = 0, - CREATED = 1, - LAUNCHED = 2, - FIZZLED = 3, - EXPLODED = 4 - } projectileState_t; - - projectileState_t state; - -private: - bool netSyncPhysics; - - void AddDefaultDamageEffect( const trace_t &collision, const idVec3 &velocity ); - - void Event_Explode( void ); - void Event_Fizzle( void ); - void Event_RadiusDamage( idEntity *ignore ); - void Event_Touch( idEntity *other, trace_t *trace ); - void Event_GetProjectileState( void ); -}; - -class idGuidedProjectile : public idProjectile { -public : - CLASS_PROTOTYPE( idGuidedProjectile ); - - idGuidedProjectile( void ); - ~idGuidedProjectile( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void Spawn( void ); - virtual void Think( void ); - virtual void Launch( const idVec3 &start, const idVec3 &dir, const idVec3 &pushVelocity, const float timeSinceFire = 0.0f, const float launchPower = 1.0f, const float dmgPower = 1.0f ); -#ifdef _D3XP - void SetEnemy( idEntity *ent ); - void Event_SetEnemy(idEntity *ent); -#endif - -protected: - float speed; - idEntityPtr enemy; - virtual void GetSeekPos( idVec3 &out ); - -private: - idAngles rndScale; - idAngles rndAng; - idAngles angles; - int rndUpdateTime; - float turn_max; - float clamp_dist; - bool burstMode; - bool unGuided; - float burstDist; - float burstVelocity; -}; - -class idSoulCubeMissile : public idGuidedProjectile { -public: - CLASS_PROTOTYPE ( idSoulCubeMissile ); - ~idSoulCubeMissile(); - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void Spawn( void ); - virtual void Think( void ); - virtual void Launch( const idVec3 &start, const idVec3 &dir, const idVec3 &pushVelocity, const float timeSinceFire = 0.0f, const float power = 1.0f, const float dmgPower = 1.0f ); - -protected: - virtual void GetSeekPos( idVec3 &out ); - void ReturnToOwner( void ); - void KillTarget( const idVec3 &dir ); - -private: - idVec3 startingVelocity; - idVec3 endingVelocity; - float accelTime; - int launchTime; - bool killPhase; - bool returnPhase; - idVec3 destOrg; - idVec3 orbitOrg; - int orbitTime; - int smokeKillTime; - const idDeclParticle * smokeKill; -}; - -struct beamTarget_t { - idEntityPtr target; - renderEntity_t renderEntity; - qhandle_t modelDefHandle; -}; - -class idBFGProjectile : public idProjectile { -public : - CLASS_PROTOTYPE( idBFGProjectile ); - - idBFGProjectile(); - ~idBFGProjectile(); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void Spawn( void ); - virtual void Think( void ); - virtual void Launch( const idVec3 &start, const idVec3 &dir, const idVec3 &pushVelocity, const float timeSinceFire = 0.0f, const float launchPower = 1.0f, const float dmgPower = 1.0f ); - virtual void Explode( const trace_t &collision, idEntity *ignore ); - -private: - idList beamTargets; - renderEntity_t secondModel; - qhandle_t secondModelDefHandle; - int nextDamageTime; - idStr damageFreq; - - void FreeBeams(); - void Event_RemoveBeams(); - void ApplyDamage(); -}; - -/* -=============================================================================== - - idDebris - -=============================================================================== -*/ - -class idDebris : public idEntity { -public : - CLASS_PROTOTYPE( idDebris ); - - idDebris(); - ~idDebris(); - - // save games - void Save( idSaveGame *savefile ) const; // archives object for save game file - void Restore( idRestoreGame *savefile ); // unarchives object from save game file - - void Spawn( void ); - - void Create( idEntity *owner, const idVec3 &start, const idMat3 &axis ); - void Launch( void ); - void Think( void ); - void Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ); - void Explode( void ); - void Fizzle( void ); - virtual bool Collide( const trace_t &collision, const idVec3 &velocity ); - - -private: - idEntityPtr owner; - idPhysics_RigidBody physicsObj; - const idDeclParticle * smokeFly; - int smokeFlyTime; - const idSoundShader * sndBounce; - - - void Event_Explode( void ); - void Event_Fizzle( void ); -}; - -#endif /* !__GAME_PROJECTILE_H__ */ diff --git a/d3xp/Pvs.cpp b/d3xp/Pvs.cpp deleted file mode 100644 index 46e16f11..00000000 --- a/d3xp/Pvs.cpp +++ /dev/null @@ -1,1457 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "idlib/Timer.h" - -#include "Game_local.h" - -#include "Pvs.h" - -#define MAX_BOUNDS_AREAS 16 - -typedef struct pvsPassage_s { - byte * canSee; // bit set for all portals that can be seen through this passage -} pvsPassage_t; - - -typedef struct pvsPortal_s { - int areaNum; // area this portal leads to - idWinding * w; // winding goes counter clockwise seen from the area this portal is part of - idBounds bounds; // winding bounds - idPlane plane; // winding plane, normal points towards the area this portal leads to - pvsPassage_t * passages; // passages to portals in the area this portal leads to - bool done; // true if pvs is calculated for this portal - byte * vis; // PVS for this portal - byte * mightSee; // used during construction -} pvsPortal_t; - - -typedef struct pvsArea_s { - int numPortals; // number of portals in this area - idBounds bounds; // bounds of the whole area - pvsPortal_t ** portals; // array with pointers to the portals of this area -} pvsArea_t; - - -typedef struct pvsStack_s { - struct pvsStack_s * next; // next stack entry - byte * mightSee; // bit set for all portals that might be visible through this passage/portal stack -} pvsStack_t; - - -/* -================ -idPVS::idPVS -================ -*/ -idPVS::idPVS( void ) { - int i; - - numAreas = 0; - numPortals = 0; - - connectedAreas = NULL; - areaQueue = NULL; - areaPVS = NULL; - - for ( i = 0; i < MAX_CURRENT_PVS; i++ ) { - currentPVS[i].handle.i = -1; - currentPVS[i].handle.h = 0; - currentPVS[i].pvs = NULL; - } - - pvsAreas = NULL; - pvsPortals = NULL; -} - -/* -================ -idPVS::~idPVS -================ -*/ -idPVS::~idPVS( void ) { - Shutdown(); -} - -/* -================ -idPVS::GetPortalCount -================ -*/ -int idPVS::GetPortalCount( void ) const { - int i, na, np; - - na = gameRenderWorld->NumAreas(); - np = 0; - for ( i = 0; i < na; i++ ) { - np += gameRenderWorld->NumPortalsInArea( i ); - } - return np; -} - -/* -================ -idPVS::CreatePVSData -================ -*/ -void idPVS::CreatePVSData( void ) { - int i, j, n, cp; - exitPortal_t portal; - pvsArea_t *area; - pvsPortal_t *p, **portalPtrs; - - if ( !numPortals ) { - return; - } - - pvsPortals = new pvsPortal_t[numPortals]; - pvsAreas = new pvsArea_t[numAreas]; - memset( pvsAreas, 0, numAreas * sizeof( *pvsAreas ) ); - - cp = 0; - portalPtrs = new pvsPortal_t*[numPortals]; - - for ( i = 0; i < numAreas; i++ ) { - - area = &pvsAreas[i]; - area->bounds.Clear(); - area->portals = portalPtrs + cp; - - n = gameRenderWorld->NumPortalsInArea( i ); - - for ( j = 0; j < n; j++ ) { - - portal = gameRenderWorld->GetPortal( i, j ); - - p = &pvsPortals[cp++]; - // the winding goes counter clockwise seen from this area - p->w = portal.w->Copy(); - p->areaNum = portal.areas[1]; // area[1] is always the area the portal leads to - - p->vis = new byte[portalVisBytes]; - memset( p->vis, 0, portalVisBytes ); - p->mightSee = new byte[portalVisBytes]; - memset( p->mightSee, 0, portalVisBytes ); - p->w->GetBounds( p->bounds ); - p->w->GetPlane( p->plane ); - // plane normal points to outside the area - p->plane = -p->plane; - // no PVS calculated for this portal yet - p->done = false; - - area->portals[area->numPortals] = p; - area->numPortals++; - - area->bounds += p->bounds; - } - } -} - -/* -================ -idPVS::DestroyPVSData -================ -*/ -void idPVS::DestroyPVSData( void ) { - int i; - - if ( !pvsAreas ) { - return; - } - - // delete portal pointer array - delete[] pvsAreas[0].portals; - - // delete all areas - delete[] pvsAreas; - pvsAreas = NULL; - - // delete portal data - for ( i = 0; i < numPortals; i++ ) { - delete[] pvsPortals[i].vis; - delete[] pvsPortals[i].mightSee; - delete pvsPortals[i].w; - } - - // delete portals - delete[] pvsPortals; - pvsPortals = NULL; -} - -/* -================ -idPVS::FloodFrontPortalPVS_r -================ -*/ -void idPVS::FloodFrontPortalPVS_r( pvsPortal_t *portal, int areaNum ) const { - int i, n; - pvsArea_t *area; - pvsPortal_t *p; - - area = &pvsAreas[ areaNum ]; - - for ( i = 0; i < area->numPortals; i++ ) { - p = area->portals[i]; - n = p - pvsPortals; - // don't flood through if this portal is not at the front - if ( !( portal->mightSee[ n>>3 ] & (1 << (n&7)) ) ) { - continue; - } - // don't flood through if already visited this portal - if ( portal->vis[ n>>3 ] & (1 << (n&7)) ) { - continue; - } - // this portal might be visible - portal->vis[ n>>3 ] |= (1 << (n&7)); - // flood through the portal - FloodFrontPortalPVS_r( portal, p->areaNum ); - } -} - -/* -================ -idPVS::FrontPortalPVS -================ -*/ -void idPVS::FrontPortalPVS( void ) const { - int i, j, k, n, p, side1, side2, areaSide; - pvsPortal_t *p1, *p2; - pvsArea_t *area; - - for ( i = 0; i < numPortals; i++ ) { - p1 = &pvsPortals[i]; - - for ( j = 0; j < numAreas; j++ ) { - - area = &pvsAreas[j]; - - areaSide = side1 = area->bounds.PlaneSide( p1->plane ); - - // if the whole area is at the back side of the portal - if ( areaSide == PLANESIDE_BACK ) { - continue; - } - - for ( p = 0; p < area->numPortals; p++ ) { - - p2 = area->portals[p]; - - // if we the whole area is not at the front we need to check - if ( areaSide != PLANESIDE_FRONT ) { - // if the second portal is completely at the back side of the first portal - side1 = p2->bounds.PlaneSide( p1->plane ); - if ( side1 == PLANESIDE_BACK ) { - continue; - } - } - - // if the first portal is completely at the front of the second portal - side2 = p1->bounds.PlaneSide( p2->plane ); - if ( side2 == PLANESIDE_FRONT ) { - continue; - } - - // if the second portal is not completely at the front of the first portal - if ( side1 != PLANESIDE_FRONT ) { - // more accurate check - for ( k = 0; k < p2->w->GetNumPoints(); k++ ) { - // if more than an epsilon at the front side - if ( p1->plane.Side( (*p2->w)[k].ToVec3(), ON_EPSILON ) == PLANESIDE_FRONT ) { - break; - } - } - if ( k >= p2->w->GetNumPoints() ) { - continue; // second portal is at the back of the first portal - } - } - - // if the first portal is not completely at the back side of the second portal - if ( side2 != PLANESIDE_BACK ) { - // more accurate check - for ( k = 0; k < p1->w->GetNumPoints(); k++ ) { - // if more than an epsilon at the back side - if ( p2->plane.Side( (*p1->w)[k].ToVec3(), ON_EPSILON ) == PLANESIDE_BACK ) { - break; - } - } - if ( k >= p1->w->GetNumPoints() ) { - continue; // first portal is at the front of the second portal - } - } - - // the portal might be visible at the front - n = p2 - pvsPortals; - p1->mightSee[ n >> 3 ] |= 1 << (n&7); - } - } - } - - // flood the front portal pvs for all portals - for ( i = 0; i < numPortals; i++ ) { - p1 = &pvsPortals[i]; - FloodFrontPortalPVS_r( p1, p1->areaNum ); - } -} - -/* -=============== -idPVS::FloodPassagePVS_r -=============== -*/ -pvsStack_t *idPVS::FloodPassagePVS_r( pvsPortal_t *source, const pvsPortal_t *portal, pvsStack_t *prevStack ) const { - int i, j, n, m; - pvsPortal_t *p; - pvsArea_t *area; - pvsStack_t *stack; - pvsPassage_t *passage; - int *sourceVis, *passageVis, *portalVis, *mightSee, *prevMightSee, more; - - area = &pvsAreas[portal->areaNum]; - - stack = prevStack->next; - // if no next stack entry allocated - if ( !stack ) { - stack = reinterpret_cast(new byte[sizeof(pvsStack_t) + portalVisBytes]); - stack->mightSee = (reinterpret_cast(stack)) + sizeof(pvsStack_t); - stack->next = NULL; - prevStack->next = stack; - } - - // check all portals for flooding into other areas - for ( i = 0; i < area->numPortals; i++ ) { - - passage = &portal->passages[i]; - - // if this passage is completely empty - if ( !passage->canSee ) { - continue; - } - - p = area->portals[i]; - n = p - pvsPortals; - - // if this portal cannot be seen through our current portal/passage stack - if ( !( prevStack->mightSee[n >> 3] & (1 << (n & 7)) ) ) { - continue; - } - - // mark the portal as visible - source->vis[n >> 3] |= (1 << (n & 7)); - - // get pointers to vis data - prevMightSee = reinterpret_cast(prevStack->mightSee); - passageVis = reinterpret_cast(passage->canSee); - sourceVis = reinterpret_cast(source->vis); - mightSee = reinterpret_cast(stack->mightSee); - - more = 0; - // use the portal PVS if it has been calculated - if ( p->done ) { - portalVis = reinterpret_cast(p->vis); - for ( j = 0; j < portalVisInts; j++ ) { - // get new PVS which is decreased by going through this passage - m = *prevMightSee++ & *passageVis++ & *portalVis++; - // check if anything might be visible through this passage that wasn't yet visible - more |= (m & ~(*sourceVis++)); - // store new PVS - *mightSee++ = m; - } - } - else { - // the p->mightSee is implicitely stored in the passageVis - for ( j = 0; j < portalVisInts; j++ ) { - // get new PVS which is decreased by going through this passage - m = *prevMightSee++ & *passageVis++; - // check if anything might be visible through this passage that wasn't yet visible - more |= (m & ~(*sourceVis++)); - // store new PVS - *mightSee++ = m; - } - } - - // if nothing more can be seen - if ( !more ) { - continue; - } - - // go through the portal - stack->next = FloodPassagePVS_r( source, p, stack ); - } - - return stack; -} - -/* -=============== -idPVS::PassagePVS -=============== -*/ -void idPVS::PassagePVS( void ) const { - int i; - pvsPortal_t *source; - pvsStack_t *stack, *s; - - // create the passages - CreatePassages(); - - // allocate first stack entry - stack = reinterpret_cast(new byte[sizeof(pvsStack_t) + portalVisBytes]); - stack->mightSee = (reinterpret_cast(stack)) + sizeof(pvsStack_t); - stack->next = NULL; - - // calculate portal PVS by flooding through the passages - for ( i = 0; i < numPortals; i++ ) { - source = &pvsPortals[i]; - memset( source->vis, 0, portalVisBytes ); - memcpy( stack->mightSee, source->mightSee, portalVisBytes ); - FloodPassagePVS_r( source, source, stack ); - source->done = true; - } - - // free the allocated stack - for ( s = stack; s; s = stack ) { - stack = stack->next; - delete[] s; - } - - // destroy the passages - DestroyPassages(); -} - -/* -=============== -idPVS::AddPassageBoundaries -=============== -*/ -void idPVS::AddPassageBoundaries( const idWinding &source, const idWinding &pass, bool flipClip, idPlane *bounds, int &numBounds, int maxBounds ) const { - int i, j, k, l; - idVec3 v1, v2, normal; - float d, dist; - bool flipTest, front; - idPlane plane; - - - // check all combinations - for ( i = 0; i < source.GetNumPoints(); i++ ) { - - l = (i + 1) % source.GetNumPoints(); - v1 = source[l].ToVec3() - source[i].ToVec3(); - - // find a vertex of pass that makes a plane that puts all of the - // vertices of pass on the front side and all of the vertices of - // source on the back side - for ( j = 0; j < pass.GetNumPoints(); j++ ) { - - v2 = pass[j].ToVec3() - source[i].ToVec3(); - - normal = v1.Cross( v2 ); - if ( normal.Normalize() < 0.01f ) { - continue; - } - dist = normal * pass[j].ToVec3(); - - // - // find out which side of the generated seperating plane has the - // source portal - // - flipTest = false; - for ( k = 0; k < source.GetNumPoints(); k++ ) { - if ( k == i || k == l ) { - continue; - } - d = source[k].ToVec3() * normal - dist; - if ( d < -ON_EPSILON ) { - // source is on the negative side, so we want all - // pass and target on the positive side - flipTest = false; - break; - } - else if ( d > ON_EPSILON ) { - // source is on the positive side, so we want all - // pass and target on the negative side - flipTest = true; - break; - } - } - if ( k == source.GetNumPoints() ) { - continue; // planar with source portal - } - - // flip the normal if the source portal is backwards - if (flipTest) { - normal = -normal; - dist = -dist; - } - - // if all of the pass portal points are now on the positive side, - // this is the seperating plane - front = false; - for ( k = 0; k < pass.GetNumPoints(); k++ ) { - if ( k == j ) { - continue; - } - d = pass[k].ToVec3() * normal - dist; - if ( d < -ON_EPSILON ) { - break; - } - else if ( d > ON_EPSILON ) { - front = true; - } - } - if ( k < pass.GetNumPoints() ) { - continue; // points on negative side, not a seperating plane - } - if ( !front ) { - continue; // planar with seperating plane - } - - // flip the normal if we want the back side - if ( flipClip ) { - plane.SetNormal( -normal ); - plane.SetDist( -dist ); - } - else { - plane.SetNormal( normal ); - plane.SetDist( dist ); - } - - // check if the plane is already a passage boundary - for ( k = 0; k < numBounds; k++ ) { - if ( plane.Compare( bounds[k], 0.001f, 0.01f ) ) { - break; - } - } - if ( k < numBounds ) { - break; - } - - if ( numBounds >= maxBounds ) { - gameLocal.Warning( "max passage boundaries." ); - break; - } - bounds[numBounds] = plane; - numBounds++; - break; - } - } -} - -/* -================ -idPVS::CreatePassages -================ -*/ -#define MAX_PASSAGE_BOUNDS 128 - -void idPVS::CreatePassages( void ) const { - int i, j, l, n, numBounds, front, passageMemory, byteNum, bitNum; - int sides[MAX_PASSAGE_BOUNDS]; - idPlane passageBounds[MAX_PASSAGE_BOUNDS]; - pvsPortal_t *source, *target, *p; - pvsArea_t *area; - pvsPassage_t *passage; - idFixedWinding winding; - byte canSee, mightSee, bit; - - passageMemory = 0; - for ( i = 0; i < numPortals; i++ ) { - source = &pvsPortals[i]; - area = &pvsAreas[source->areaNum]; - - source->passages = new pvsPassage_t[area->numPortals]; - - for ( j = 0; j < area->numPortals; j++ ) { - target = area->portals[j]; - n = target - pvsPortals; - - passage = &source->passages[j]; - - // if the source portal cannot see this portal - if ( !( source->mightSee[ n>>3 ] & (1 << (n&7)) ) ) { - // not all portals in the area have to be visible because areas are not necesarily convex - // also no passage has to be created for the portal which is the opposite of the source - passage->canSee = NULL; - continue; - } - - passage->canSee = new byte[portalVisBytes]; - passageMemory += portalVisBytes; - - // boundary plane normals point inwards - numBounds = 0; - AddPassageBoundaries( *(source->w), *(target->w), false, passageBounds, numBounds, MAX_PASSAGE_BOUNDS ); - AddPassageBoundaries( *(target->w), *(source->w), true, passageBounds, numBounds, MAX_PASSAGE_BOUNDS ); - - // get all portals visible through this passage - for ( byteNum = 0; byteNum < portalVisBytes; byteNum++) { - - canSee = 0; - mightSee = source->mightSee[byteNum] & target->mightSee[byteNum]; - - // go through eight portals at a time to speed things up - for ( bitNum = 0; bitNum < 8; bitNum++ ) { - - bit = 1 << bitNum; - - if ( !( mightSee & bit ) ) { - continue; - } - - p = &pvsPortals[(byteNum << 3) + bitNum]; - - if ( p->areaNum == source->areaNum ) { - continue; - } - - for ( front = 0, l = 0; l < numBounds; l++ ) { - sides[l] = p->bounds.PlaneSide( passageBounds[l] ); - // if completely at the back of the passage bounding plane - if ( sides[l] == PLANESIDE_BACK ) { - break; - } - // if completely at the front - if ( sides[l] == PLANESIDE_FRONT ) { - front++; - } - } - // if completely outside the passage - if ( l < numBounds ) { - continue; - } - - // if not at the front of all bounding planes and thus not completely inside the passage - if ( front != numBounds ) { - - winding = *p->w; - - for ( l = 0; l < numBounds; l++ ) { - // only clip if the winding possibly crosses this plane - if ( sides[l] != PLANESIDE_CROSS ) { - continue; - } - // clip away the part at the back of the bounding plane - winding.ClipInPlace( passageBounds[l] ); - // if completely clipped away - if ( !winding.GetNumPoints() ) { - break; - } - } - // if completely outside the passage - if ( l < numBounds ) { - continue; - } - } - - canSee |= bit; - } - - // store results of all eight portals - passage->canSee[byteNum] = canSee; - } - - // can always see the target portal - passage->canSee[n >> 3] |= (1 << (n&7)); - } - } - if ( passageMemory < 1024 ) { - gameLocal.Printf( "%5d bytes passage memory used to build PVS\n", passageMemory ); - } - else { - gameLocal.Printf( "%5d KB passage memory used to build PVS\n", passageMemory>>10 ); - } -} - -/* -================ -idPVS::DestroyPassages -================ -*/ -void idPVS::DestroyPassages( void ) const { - int i, j; - pvsPortal_t *p; - pvsArea_t *area; - - for ( i = 0; i < numPortals; i++ ) { - p = &pvsPortals[i]; - area = &pvsAreas[p->areaNum]; - for ( j = 0; j < area->numPortals; j++ ) { - if ( p->passages[j].canSee ) { - delete[] p->passages[j].canSee; - } - } - delete[] p->passages; - } -} - -/* -================ -idPVS::CopyPortalPVSToMightSee -================ -*/ -void idPVS::CopyPortalPVSToMightSee( void ) const { - int i; - pvsPortal_t *p; - - for ( i = 0; i < numPortals; i++ ) { - p = &pvsPortals[i]; - memcpy( p->mightSee, p->vis, portalVisBytes ); - } -} - -/* -================ -idPVS::AreaPVSFromPortalPVS -================ -*/ -int idPVS::AreaPVSFromPortalPVS( void ) const { - int i, j, k, areaNum, totalVisibleAreas; - int *p1, *p2; - byte *pvs, *portalPVS; - pvsArea_t *area; - - totalVisibleAreas = 0; - - if ( !numPortals ) { - return totalVisibleAreas; - } - - memset( areaPVS, 0, numAreas * areaVisBytes ); - - for ( i = 0; i < numAreas; i++ ) { - area = &pvsAreas[i]; - pvs = areaPVS + i * areaVisBytes; - - // the area is visible to itself - pvs[ i >> 3 ] |= 1 << (i & 7); - - if ( !area->numPortals ) { - continue; - } - - // store the PVS of all portals in this area at the first portal - for ( j = 1; j < area->numPortals; j++ ) { - p1 = reinterpret_cast(area->portals[0]->vis); - p2 = reinterpret_cast(area->portals[j]->vis); - for ( k = 0; k < portalVisInts; k++ ) { - *p1++ |= *p2++; - } - } - - // the portals of this area are always visible - for ( j = 0; j < area->numPortals; j++ ) { - k = area->portals[j] - pvsPortals; - area->portals[0]->vis[ k >> 3 ] |= 1 << (k & 7); - } - - // set all areas to visible that can be seen from the portals of this area - portalPVS = area->portals[0]->vis; - for ( j = 0; j < numPortals; j++ ) { - // if this portal is visible - if ( portalPVS[j>>3] & (1 << (j&7)) ) { - areaNum = pvsPortals[j].areaNum; - pvs[ areaNum >> 3 ] |= 1 << (areaNum & 7); - } - } - - // count the number of visible areas - for ( j = 0; j < numAreas; j++ ) { - if ( pvs[j>>3] & (1 << (j&7)) ) { - totalVisibleAreas++; - } - } - } - return totalVisibleAreas; -} - -/* -================ -idPVS::Init -================ -*/ -void idPVS::Init( void ) { - int totalVisibleAreas; - - Shutdown(); - - numAreas = gameRenderWorld->NumAreas(); - if ( numAreas <= 0 ) { - return; - } - - connectedAreas = new bool[numAreas]; - areaQueue = new int[numAreas]; - - areaVisBytes = ( ((numAreas+31)&~31) >> 3); - areaVisInts = areaVisBytes/sizeof(int); - - areaPVS = new byte[numAreas * areaVisBytes]; - memset( areaPVS, 0xFF, numAreas * areaVisBytes ); - - numPortals = GetPortalCount(); - - portalVisBytes = ( ((numPortals+31)&~31) >> 3); - portalVisInts = portalVisBytes/sizeof(int); - - for ( int i = 0; i < MAX_CURRENT_PVS; i++ ) { - currentPVS[i].handle.i = -1; - currentPVS[i].handle.h = 0; - currentPVS[i].pvs = new byte[areaVisBytes]; - memset( currentPVS[i].pvs, 0, areaVisBytes ); - } - - idTimer timer; - timer.Start(); - - CreatePVSData(); - - FrontPortalPVS(); - - CopyPortalPVSToMightSee(); - - PassagePVS(); - - totalVisibleAreas = AreaPVSFromPortalPVS(); - - DestroyPVSData(); - - timer.Stop(); - - gameLocal.Printf( "%5u msec to calculate PVS\n", timer.Milliseconds() ); - gameLocal.Printf( "%5d areas\n", numAreas ); - gameLocal.Printf( "%5d portals\n", numPortals ); - gameLocal.Printf( "%5d areas visible on average\n", totalVisibleAreas / numAreas ); - if ( numAreas * areaVisBytes < 1024 ) { - gameLocal.Printf( "%5d bytes PVS data\n", numAreas * areaVisBytes ); - } - else { - gameLocal.Printf( "%5d KB PVS data\n", (numAreas * areaVisBytes) >> 10 ); - } -} - -/* -================ -idPVS::Shutdown -================ -*/ -void idPVS::Shutdown( void ) { - if ( connectedAreas ) { - delete[] connectedAreas; - connectedAreas = NULL; - } - if ( areaQueue ) { - delete[] areaQueue; - areaQueue = NULL; - } - if ( areaPVS ) { - delete[] areaPVS; - areaPVS = NULL; - } - if ( currentPVS ) { - for ( int i = 0; i < MAX_CURRENT_PVS; i++ ) { - delete[] currentPVS[i].pvs; - currentPVS[i].pvs = NULL; - } - } -} - -/* -================ -idPVS::GetConnectedAreas - - assumes the 'areas' array is initialized to false -================ -*/ -void idPVS::GetConnectedAreas( int srcArea, bool *areas ) const { - int curArea, nextArea; - int queueStart, queueEnd; - int i, n; - exitPortal_t portal; - - queueStart = -1; - queueEnd = 0; - areas[srcArea] = true; - - for ( curArea = srcArea; queueStart < queueEnd; curArea = areaQueue[++queueStart] ) { - - n = gameRenderWorld->NumPortalsInArea( curArea ); - - for ( i = 0; i < n; i++ ) { - portal = gameRenderWorld->GetPortal( curArea, i ); - - if ( portal.blockingBits & PS_BLOCK_VIEW ) { - continue; - } - - // area[1] is always the area the portal leads to - nextArea = portal.areas[1]; - - // if already visited this area - if ( areas[nextArea] ) { - continue; - } - - // add area to queue - areaQueue[queueEnd++] = nextArea; - areas[nextArea] = true; - } - } -} - -/* -================ -idPVS::GetPVSArea -================ -*/ -int idPVS::GetPVSArea( const idVec3 &point ) const { - return gameRenderWorld->PointInArea( point ); -} - -/* -================ -idPVS::GetPVSAreas -================ -*/ -int idPVS::GetPVSAreas( const idBounds &bounds, int *areas, int maxAreas ) const { - return gameRenderWorld->BoundsInAreas( bounds, areas, maxAreas ); -} - -/* -================ -idPVS::SetupCurrentPVS -================ -*/ -pvsHandle_t idPVS::SetupCurrentPVS( const idVec3 &source, const pvsType_t type ) const { - int sourceArea; - - sourceArea = gameRenderWorld->PointInArea( source ); - - return SetupCurrentPVS( sourceArea, type ); -} - -/* -================ -idPVS::SetupCurrentPVS -================ -*/ -pvsHandle_t idPVS::SetupCurrentPVS( const idBounds &source, const pvsType_t type ) const { - int numSourceAreas, sourceAreas[MAX_BOUNDS_AREAS]; - - numSourceAreas = gameRenderWorld->BoundsInAreas( source, sourceAreas, MAX_BOUNDS_AREAS ); - - return SetupCurrentPVS( sourceAreas, numSourceAreas, type ); -} - -/* -================ -idPVS::SetupCurrentPVS -================ -*/ -pvsHandle_t idPVS::SetupCurrentPVS( const int sourceArea, const pvsType_t type ) const { - int i; - pvsHandle_t handle; - - handle = AllocCurrentPVS( *reinterpret_cast(&sourceArea) ); - - if ( sourceArea < 0 || sourceArea >= numAreas ) { - memset( currentPVS[handle.i].pvs, 0, areaVisBytes ); - return handle; - } - - if ( type != PVS_CONNECTED_AREAS ) { - memcpy( currentPVS[handle.i].pvs, areaPVS + sourceArea * areaVisBytes, areaVisBytes ); - } else { - memset( currentPVS[handle.i].pvs, -1, areaVisBytes ); - } - - if ( type == PVS_ALL_PORTALS_OPEN ) { - return handle; - } - - memset( connectedAreas, 0, numAreas * sizeof( *connectedAreas ) ); - - GetConnectedAreas( sourceArea, connectedAreas ); - - for ( i = 0; i < numAreas; i++ ) { - if ( !connectedAreas[i] ) { - currentPVS[handle.i].pvs[i>>3] &= ~(1 << (i&7)); - } - } - - return handle; -} - -/* -================ -idPVS::SetupCurrentPVS -================ -*/ -pvsHandle_t idPVS::SetupCurrentPVS( const int *sourceAreas, const int numSourceAreas, const pvsType_t type ) const { - int i, j; - unsigned int h; - int *vis, *pvs; - pvsHandle_t handle; - - h = 0; - for ( i = 0; i < numSourceAreas; i++ ) { - h ^= *reinterpret_cast(&sourceAreas[i]); - } - handle = AllocCurrentPVS( h ); - - if ( !numSourceAreas || sourceAreas[0] < 0 || sourceAreas[0] >= numAreas) { - memset( currentPVS[handle.i].pvs, 0, areaVisBytes ); - return handle; - } - - if ( type != PVS_CONNECTED_AREAS ) { - // merge PVS of all areas the source is in - memcpy( currentPVS[handle.i].pvs, areaPVS + sourceAreas[0] * areaVisBytes, areaVisBytes ); - for ( i = 1; i < numSourceAreas; i++ ) { - - assert( sourceAreas[i] >= 0 && sourceAreas[i] < numAreas ); - - vis = reinterpret_cast(areaPVS + sourceAreas[i] * areaVisBytes); - pvs = reinterpret_cast(currentPVS[handle.i].pvs); - for ( j = 0; j < areaVisInts; j++ ) { - *pvs++ |= *vis++; - } - } - } else { - memset( currentPVS[handle.i].pvs, -1, areaVisBytes ); - } - - if ( type == PVS_ALL_PORTALS_OPEN ) { - return handle; - } - - memset( connectedAreas, 0, numAreas * sizeof( *connectedAreas ) ); - - // get all areas connected to any of the source areas - for ( i = 0; i < numSourceAreas; i++ ) { - if ( !connectedAreas[sourceAreas[i]] ) { - GetConnectedAreas( sourceAreas[i], connectedAreas ); - } - } - - // remove unconnected areas from the PVS - for ( i = 0; i < numAreas; i++ ) { - if ( !connectedAreas[i] ) { - currentPVS[handle.i].pvs[i>>3] &= ~(1 << (i&7)); - } - } - - return handle; -} - -/* -================ -idPVS::MergeCurrentPVS -================ -*/ -pvsHandle_t idPVS::MergeCurrentPVS( pvsHandle_t pvs1, pvsHandle_t pvs2 ) const { - int i; - int *pvs1Ptr, *pvs2Ptr, *ptr; - pvsHandle_t handle; - - if ( pvs1.i < 0 || pvs1.i >= MAX_CURRENT_PVS || pvs1.h != currentPVS[pvs1.i].handle.h || - pvs2.i < 0 || pvs2.i >= MAX_CURRENT_PVS || pvs2.h != currentPVS[pvs2.i].handle.h ) { - gameLocal.Error( "idPVS::MergeCurrentPVS: invalid handle" ); - } - - handle = AllocCurrentPVS( pvs1.h ^ pvs2.h ); - - ptr = reinterpret_cast(currentPVS[handle.i].pvs); - pvs1Ptr = reinterpret_cast(currentPVS[pvs1.i].pvs); - pvs2Ptr = reinterpret_cast(currentPVS[pvs2.i].pvs); - - for ( i = 0; i < areaVisInts; i++ ) { - *ptr++ = *pvs1Ptr++ | *pvs2Ptr++; - } - - return handle; -} - -/* -================ -idPVS::AllocCurrentPVS -================ -*/ -pvsHandle_t idPVS::AllocCurrentPVS( unsigned int h ) const { - int i; - pvsHandle_t handle; - - for ( i = 0; i < MAX_CURRENT_PVS; i++ ) { - if ( currentPVS[i].handle.i == -1 ) { - currentPVS[i].handle.i = i; - currentPVS[i].handle.h = h; - return currentPVS[i].handle; - } - } - - gameLocal.Error( "idPVS::AllocCurrentPVS: no free PVS left" ); - - handle.i = -1; - handle.h = 0; - return handle; -} - -/* -================ -idPVS::FreeCurrentPVS -================ -*/ -void idPVS::FreeCurrentPVS( pvsHandle_t handle ) const { - if ( handle.i < 0 || handle.i >= MAX_CURRENT_PVS || handle.h != currentPVS[handle.i].handle.h ) { - gameLocal.Error( "idPVS::FreeCurrentPVS: invalid handle" ); - } - currentPVS[handle.i].handle.i = -1; -} - -/* -================ -idPVS::InCurrentPVS -================ -*/ -bool idPVS::InCurrentPVS( const pvsHandle_t handle, const idVec3 &target ) const { - int targetArea; - - if ( handle.i < 0 || handle.i >= MAX_CURRENT_PVS || - handle.h != currentPVS[handle.i].handle.h ) { - gameLocal.Error( "idPVS::InCurrentPVS: invalid handle" ); - } - - targetArea = gameRenderWorld->PointInArea( target ); - - if ( targetArea == -1 ) { - return false; - } - - return ( ( currentPVS[handle.i].pvs[targetArea>>3] & (1 << (targetArea&7)) ) != 0 ); -} - -/* -================ -idPVS::InCurrentPVS -================ -*/ -bool idPVS::InCurrentPVS( const pvsHandle_t handle, const idBounds &target ) const { - int i, numTargetAreas, targetAreas[MAX_BOUNDS_AREAS]; - - if ( handle.i < 0 || handle.i >= MAX_CURRENT_PVS || - handle.h != currentPVS[handle.i].handle.h ) { - gameLocal.Error( "idPVS::InCurrentPVS: invalid handle" ); - } - - numTargetAreas = gameRenderWorld->BoundsInAreas( target, targetAreas, MAX_BOUNDS_AREAS ); - - for ( i = 0; i < numTargetAreas; i++ ) { - if ( currentPVS[handle.i].pvs[targetAreas[i]>>3] & (1 << (targetAreas[i]&7)) ) { - return true; - } - } - return false; -} - -/* -================ -idPVS::InCurrentPVS -================ -*/ -bool idPVS::InCurrentPVS( const pvsHandle_t handle, const int targetArea ) const { - - if ( handle.i < 0 || handle.i >= MAX_CURRENT_PVS || - handle.h != currentPVS[handle.i].handle.h ) { - gameLocal.Error( "idPVS::InCurrentPVS: invalid handle" ); - } - - if ( targetArea < 0 || targetArea >= numAreas ) { - return false; - } - - return ( ( currentPVS[handle.i].pvs[targetArea>>3] & (1 << (targetArea&7)) ) != 0 ); -} - -/* -================ -idPVS::InCurrentPVS -================ -*/ -bool idPVS::InCurrentPVS( const pvsHandle_t handle, const int *targetAreas, int numTargetAreas ) const { - int i; - - if ( handle.i < 0 || handle.i >= MAX_CURRENT_PVS || - handle.h != currentPVS[handle.i].handle.h ) { - gameLocal.Error( "idPVS::InCurrentPVS: invalid handle" ); - } - - for ( i = 0; i < numTargetAreas; i++ ) { - if ( targetAreas[i] < 0 || targetAreas[i] >= numAreas ) { - continue; - } - if ( currentPVS[handle.i].pvs[targetAreas[i]>>3] & (1 << (targetAreas[i]&7)) ) { - return true; - } - } - return false; -} - -/* -================ -idPVS::DrawPVS -================ -*/ -void idPVS::DrawPVS( const idVec3 &source, const pvsType_t type ) const { - int i, j, k, numPoints, n, sourceArea; - exitPortal_t portal; - idPlane plane; - idVec3 offset; - idVec4 *color; - pvsHandle_t handle; - - sourceArea = gameRenderWorld->PointInArea( source ); - - if ( sourceArea == -1 ) { - return; - } - - handle = SetupCurrentPVS( source, type ); - - for ( j = 0; j < numAreas; j++ ) { - - if ( !( currentPVS[handle.i].pvs[j>>3] & (1 << (j&7)) ) ) { - continue; - } - - if ( j == sourceArea ) { - color = &colorRed; - } - else { - color = &colorCyan; - } - - n = gameRenderWorld->NumPortalsInArea( j ); - - // draw all the portals of the area - for ( i = 0; i < n; i++ ) { - portal = gameRenderWorld->GetPortal( j, i ); - - numPoints = portal.w->GetNumPoints(); - - portal.w->GetPlane( plane ); - offset = plane.Normal() * 4.0f; - for ( k = 0; k < numPoints; k++ ) { - gameRenderWorld->DebugLine( *color, (*portal.w)[k].ToVec3() + offset, (*portal.w)[(k+1)%numPoints].ToVec3() + offset ); - } - } - } - - FreeCurrentPVS( handle ); -} - -/* -================ -idPVS::DrawPVS -================ -*/ -void idPVS::DrawPVS( const idBounds &source, const pvsType_t type ) const { - int i, j, k, numPoints, n, num, areas[MAX_BOUNDS_AREAS]; - exitPortal_t portal; - idPlane plane; - idVec3 offset; - idVec4 *color; - pvsHandle_t handle; - - num = gameRenderWorld->BoundsInAreas( source, areas, MAX_BOUNDS_AREAS ); - - if ( !num ) { - return; - } - - handle = SetupCurrentPVS( source, type ); - - for ( j = 0; j < numAreas; j++ ) { - - if ( !( currentPVS[handle.i].pvs[j>>3] & (1 << (j&7)) ) ) { - continue; - } - - for ( i = 0; i < num; i++ ) { - if ( j == areas[i] ) { - break; - } - } - if ( i < num ) { - color = &colorRed; - } - else { - color = &colorCyan; - } - - n = gameRenderWorld->NumPortalsInArea( j ); - - // draw all the portals of the area - for ( i = 0; i < n; i++ ) { - portal = gameRenderWorld->GetPortal( j, i ); - - numPoints = portal.w->GetNumPoints(); - - portal.w->GetPlane( plane ); - offset = plane.Normal() * 4.0f; - for ( k = 0; k < numPoints; k++ ) { - gameRenderWorld->DebugLine( *color, (*portal.w)[k].ToVec3() + offset, (*portal.w)[(k+1)%numPoints].ToVec3() + offset ); - } - } - } - - FreeCurrentPVS( handle ); -} - -/* -================ -idPVS::DrawPVS -================ -*/ -void idPVS::DrawCurrentPVS( const pvsHandle_t handle, const idVec3 &source ) const { - int i, j, k, numPoints, n, sourceArea; - exitPortal_t portal; - idPlane plane; - idVec3 offset; - idVec4 *color; - - if ( handle.i < 0 || handle.i >= MAX_CURRENT_PVS || - handle.h != currentPVS[handle.i].handle.h ) { - gameLocal.Error( "idPVS::DrawCurrentPVS: invalid handle" ); - } - - sourceArea = gameRenderWorld->PointInArea( source ); - - if ( sourceArea == -1 ) { - return; - } - - for ( j = 0; j < numAreas; j++ ) { - - if ( !( currentPVS[handle.i].pvs[j>>3] & (1 << (j&7)) ) ) { - continue; - } - - if ( j == sourceArea ) { - color = &colorRed; - } - else { - color = &colorCyan; - } - - n = gameRenderWorld->NumPortalsInArea( j ); - - // draw all the portals of the area - for ( i = 0; i < n; i++ ) { - portal = gameRenderWorld->GetPortal( j, i ); - - numPoints = portal.w->GetNumPoints(); - - portal.w->GetPlane( plane ); - offset = plane.Normal() * 4.0f; - for ( k = 0; k < numPoints; k++ ) { - gameRenderWorld->DebugLine( *color, (*portal.w)[k].ToVec3() + offset, (*portal.w)[(k+1)%numPoints].ToVec3() + offset ); - } - } - } -} - -#if ASYNC_WRITE_PVS - -/* -=================== -idPVS::WritePVS -=================== -*/ -void idPVS::WritePVS( const pvsHandle_t handle, idBitMsg &msg ) { - msg.WriteData( currentPVS[ handle.i ].pvs, areaVisBytes ); -} - -/* -=================== -idPVS::ReadPVS -=================== -*/ -void idPVS::ReadPVS( const pvsHandle_t handle, const idBitMsg &msg ) { - byte l_pvs[ 256 ]; - int i; - - assert( areaVisBytes <= 256 ); - msg.ReadData( l_pvs, areaVisBytes ); - if ( memcmp( l_pvs, currentPVS[ handle.i ].pvs, areaVisBytes ) ) { - common->Printf( "PVS not matching ( %d areaVisBytes ) - server then client:\n", areaVisBytes ); - for ( i = 0; i < areaVisBytes; i++ ) { - common->Printf( "%x ", l_pvs[ i ] ); - } - common->Printf( "\n" ); - for ( i = 0; i < areaVisBytes; i++ ) { - common->Printf( "%x ", currentPVS[ handle.i ].pvs[ i ] ); - } - common->Printf( "\n" ); - } -} - -#endif - - -#ifdef _D3XP -/* -================ -idPVS::CheckAreasForPortalSky -================ -*/ -bool idPVS::CheckAreasForPortalSky( const pvsHandle_t handle, const idVec3 &origin ) { - int j, sourceArea; - - if ( handle.i < 0 || handle.i >= MAX_CURRENT_PVS || handle.h != currentPVS[handle.i].handle.h ) { - return false; - } - - sourceArea = gameRenderWorld->PointInArea( origin ); - - if ( sourceArea == -1 ) { - return false; - } - - for ( j = 0; j < numAreas; j++ ) { - - if ( !( currentPVS[handle.i].pvs[j>>3] & (1 << (j&7)) ) ) { - continue; - } - - if ( gameRenderWorld->CheckAreaForPortalSky( j ) ) { - return true; - } - } - - return false; -} -#endif diff --git a/d3xp/Pvs.h b/d3xp/Pvs.h deleted file mode 100644 index f97d6cfe..00000000 --- a/d3xp/Pvs.h +++ /dev/null @@ -1,137 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __GAME_PVS_H__ -#define __GAME_PVS_H__ - -#include "idlib/geometry/Winding.h" -#include "idlib/math/Vector.h" -#include "idlib/bv/Bounds.h" - -/* -=================================================================================== - - PVS - - Note: mirrors and other special view portals are not taken into account - -=================================================================================== -*/ - - -typedef struct pvsHandle_s { - int i; // index to current pvs - unsigned int h; // handle for current pvs -} pvsHandle_t; - - -typedef struct pvsCurrent_s { - pvsHandle_t handle; // current pvs handle - byte * pvs; // current pvs bit string -} pvsCurrent_t; - -#define MAX_CURRENT_PVS 8 // must be a power of 2 - -typedef enum { - PVS_NORMAL = 0, // PVS through portals taking portal states into account - PVS_ALL_PORTALS_OPEN = 1, // PVS through portals assuming all portals are open - PVS_CONNECTED_AREAS = 2 // PVS considering all topologically connected areas visible -} pvsType_t; - - -class idPVS { -public: - idPVS( void ); - ~idPVS( void ); - // setup for the current map - void Init( void ); - void Shutdown( void ); - // get the area(s) the source is in - int GetPVSArea( const idVec3 &point ) const; // returns the area number - int GetPVSAreas( const idBounds &bounds, int *areas, int maxAreas ) const; // returns number of areas - // setup current PVS for the source - pvsHandle_t SetupCurrentPVS( const idVec3 &source, const pvsType_t type = PVS_NORMAL ) const; - pvsHandle_t SetupCurrentPVS( const idBounds &source, const pvsType_t type = PVS_NORMAL ) const; - pvsHandle_t SetupCurrentPVS( const int sourceArea, const pvsType_t type = PVS_NORMAL ) const; - pvsHandle_t SetupCurrentPVS( const int *sourceAreas, const int numSourceAreas, const pvsType_t type = PVS_NORMAL ) const; - pvsHandle_t MergeCurrentPVS( pvsHandle_t pvs1, pvsHandle_t pvs2 ) const; - void FreeCurrentPVS( pvsHandle_t handle ) const; - // returns true if the target is within the current PVS - bool InCurrentPVS( const pvsHandle_t handle, const idVec3 &target ) const; - bool InCurrentPVS( const pvsHandle_t handle, const idBounds &target ) const; - bool InCurrentPVS( const pvsHandle_t handle, const int targetArea ) const; - bool InCurrentPVS( const pvsHandle_t handle, const int *targetAreas, int numTargetAreas ) const; - // draw all portals that are within the PVS of the source - void DrawPVS( const idVec3 &source, const pvsType_t type = PVS_NORMAL ) const; - void DrawPVS( const idBounds &source, const pvsType_t type = PVS_NORMAL ) const; - // visualize the PVS the handle points to - void DrawCurrentPVS( const pvsHandle_t handle, const idVec3 &source ) const; - -#if ASYNC_WRITE_PVS - void WritePVS( const pvsHandle_t handle, idBitMsg &msg ); - void ReadPVS( const pvsHandle_t handle, const idBitMsg &msg ); -#endif - -#ifdef _D3XP - bool CheckAreasForPortalSky( const pvsHandle_t handle, const idVec3 &origin ); -#endif - -private: - int numAreas; - int numPortals; - bool * connectedAreas; - int * areaQueue; - byte * areaPVS; - // current PVS for a specific source possibly taking portal states (open/closed) into account - mutable pvsCurrent_t currentPVS[MAX_CURRENT_PVS]; - // used to create PVS - int portalVisBytes; - int portalVisInts; - int areaVisBytes; - int areaVisInts; - struct pvsPortal_s *pvsPortals; - struct pvsArea_s * pvsAreas; - -private: - int GetPortalCount( void ) const; - void CreatePVSData( void ); - void DestroyPVSData( void ); - void CopyPortalPVSToMightSee( void ) const; - void FloodFrontPortalPVS_r( struct pvsPortal_s *portal, int areaNum ) const; - void FrontPortalPVS( void ) const; - struct pvsStack_s * FloodPassagePVS_r( struct pvsPortal_s *source, const struct pvsPortal_s *portal, struct pvsStack_s *prevStack ) const; - void PassagePVS( void ) const; - void AddPassageBoundaries( const idWinding &source, const idWinding &pass, bool flipClip, idPlane *bounds, int &numBounds, int maxBounds ) const; - void CreatePassages( void ) const; - void DestroyPassages( void ) const; - int AreaPVSFromPortalPVS( void ) const; - void GetConnectedAreas( int srcArea, bool *connectedAreas ) const; - pvsHandle_t AllocCurrentPVS( unsigned int h ) const; -}; - -#endif /* !__GAME_PVS_H__ */ diff --git a/d3xp/SecurityCamera.cpp b/d3xp/SecurityCamera.cpp deleted file mode 100644 index 36a0cbe0..00000000 --- a/d3xp/SecurityCamera.cpp +++ /dev/null @@ -1,586 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "gamesys/SysCvar.h" -#include "physics/Physics_RigidBody.h" -#include "Entity.h" -#include "Light.h" -#include "Player.h" -#include "Fx.h" - -#include "SecurityCamera.h" - -/*********************************************************************** - - idSecurityCamera - - Security camera that triggers targets when player is in view - -***********************************************************************/ - -const idEventDef EV_SecurityCam_ReverseSweep( "" ); -const idEventDef EV_SecurityCam_ContinueSweep( "" ); -const idEventDef EV_SecurityCam_Pause( "" ); -const idEventDef EV_SecurityCam_Alert( "" ); -const idEventDef EV_SecurityCam_AddLight( "" ); - -CLASS_DECLARATION( idEntity, idSecurityCamera ) - EVENT( EV_SecurityCam_ReverseSweep, idSecurityCamera::Event_ReverseSweep ) - EVENT( EV_SecurityCam_ContinueSweep, idSecurityCamera::Event_ContinueSweep ) - EVENT( EV_SecurityCam_Pause, idSecurityCamera::Event_Pause ) - EVENT( EV_SecurityCam_Alert, idSecurityCamera::Event_Alert ) - EVENT( EV_SecurityCam_AddLight, idSecurityCamera::Event_AddLight ) -END_CLASS - -/* -================ -idSecurityCamera::Save -================ -*/ -void idSecurityCamera::Save( idSaveGame *savefile ) const { - savefile->WriteFloat( angle ); - savefile->WriteFloat( sweepAngle ); - savefile->WriteInt( modelAxis ); - savefile->WriteBool( flipAxis ); - savefile->WriteFloat( scanDist ); - savefile->WriteFloat( scanFov ); - - savefile->WriteFloat( sweepStart ); - savefile->WriteFloat( sweepEnd ); - savefile->WriteBool( negativeSweep ); - savefile->WriteBool( sweeping ); - savefile->WriteInt( alertMode ); - savefile->WriteFloat( stopSweeping ); - savefile->WriteFloat( scanFovCos ); - - savefile->WriteVec3( viewOffset ); - - savefile->WriteInt( pvsArea ); - savefile->WriteStaticObject( physicsObj ); - savefile->WriteTraceModel( trm ); -} - -/* -================ -idSecurityCamera::Restore -================ -*/ -void idSecurityCamera::Restore( idRestoreGame *savefile ) { - savefile->ReadFloat( angle ); - savefile->ReadFloat( sweepAngle ); - savefile->ReadInt( modelAxis ); - savefile->ReadBool( flipAxis ); - savefile->ReadFloat( scanDist ); - savefile->ReadFloat( scanFov ); - - savefile->ReadFloat( sweepStart ); - savefile->ReadFloat( sweepEnd ); - savefile->ReadBool( negativeSweep ); - savefile->ReadBool( sweeping ); - savefile->ReadInt( alertMode ); - savefile->ReadFloat( stopSweeping ); - savefile->ReadFloat( scanFovCos ); - - savefile->ReadVec3( viewOffset ); - - savefile->ReadInt( pvsArea ); - savefile->ReadStaticObject( physicsObj ); - savefile->ReadTraceModel( trm ); -} - -/* -================ -idSecurityCamera::Spawn -================ -*/ -void idSecurityCamera::Spawn( void ) { - idStr str; - - sweepAngle = spawnArgs.GetFloat( "sweepAngle", "90" ); - health = spawnArgs.GetInt( "health", "100" ); - scanFov = spawnArgs.GetFloat( "scanFov", "90" ); - scanDist = spawnArgs.GetFloat( "scanDist", "200" ); - flipAxis = spawnArgs.GetBool( "flipAxis" ); - - modelAxis = spawnArgs.GetInt( "modelAxis" ); - if ( modelAxis < 0 || modelAxis > 2 ) { - modelAxis = 0; - } - - spawnArgs.GetVector( "viewOffset", "0 0 0", viewOffset ); - - if ( spawnArgs.GetBool( "spotLight" ) ) { - PostEventMS( &EV_SecurityCam_AddLight, 0 ); - } - - negativeSweep = ( sweepAngle < 0 ) ? true : false; - sweepAngle = idMath::Fabs( sweepAngle ); - - scanFovCos = cos( scanFov * idMath::PI / 360.0f ); - - angle = GetPhysics()->GetAxis().ToAngles().yaw; - StartSweep(); - SetAlertMode( SCANNING ); - BecomeActive( TH_THINK ); - - if ( health ) { - fl.takedamage = true; - } - - pvsArea = gameLocal.pvs.GetPVSArea( GetPhysics()->GetOrigin() ); - // if no target specified use ourself - str = spawnArgs.GetString( "cameraTarget" ); - if ( str.Length() == 0 ) { - spawnArgs.Set( "cameraTarget", spawnArgs.GetString( "name" ) ); - } - - // check if a clip model is set - spawnArgs.GetString( "clipmodel", "", str ); - if ( !str[0] ) { - str = spawnArgs.GetString( "model" ); // use the visual model - } - - if ( !collisionModelManager->TrmFromModel( str, trm ) ) { - gameLocal.Error( "idSecurityCamera '%s': cannot load collision model %s", name.c_str(), str.c_str() ); - return; - } - - GetPhysics()->SetContents( CONTENTS_SOLID ); - GetPhysics()->SetClipMask( MASK_SOLID | CONTENTS_BODY | CONTENTS_CORPSE | CONTENTS_MOVEABLECLIP ); - // setup the physics - UpdateChangeableSpawnArgs( NULL ); -} - -/* -================ -idSecurityCamera::Event_AddLight -================ -*/ -void idSecurityCamera::Event_AddLight( void ) { - idDict args; - idVec3 right, up, target, temp; - idVec3 dir; - float radius; - idVec3 lightOffset; - idLight *spotLight; - - dir = GetAxis(); - dir.NormalVectors( right, up ); - target = GetPhysics()->GetOrigin() + dir * scanDist; - - radius = tan( scanFov * idMath::PI / 360.0f ); - up = dir + up * radius; - up.Normalize(); - up = GetPhysics()->GetOrigin() + up * scanDist; - up -= target; - - right = dir + right * radius; - right.Normalize(); - right = GetPhysics()->GetOrigin() + right * scanDist; - right -= target; - - spawnArgs.GetVector( "lightOffset", "0 0 0", lightOffset ); - - args.Set( "origin", ( GetPhysics()->GetOrigin() + lightOffset ).ToString() ); - args.Set( "light_target", target.ToString() ); - args.Set( "light_right", right.ToString() ); - args.Set( "light_up", up.ToString() ); - args.SetFloat( "angle", GetPhysics()->GetAxis()[0].ToYaw() ); - - spotLight = static_cast( gameLocal.SpawnEntityType( idLight::Type, &args ) ); - spotLight->Bind( this, true ); - spotLight->UpdateVisuals(); -} - -/* -================ -idSecurityCamera::DrawFov -================ -*/ -void idSecurityCamera::DrawFov( void ) { - int i; - float radius, a, s, c, halfRadius; - idVec3 right, up; - idVec4 color(1, 0, 0, 1), color2(0, 0, 1, 1); - idVec3 lastPoint, point, lastHalfPoint, halfPoint, center; - - idVec3 dir = GetAxis(); - dir.NormalVectors( right, up ); - - radius = tan( scanFov * idMath::PI / 360.0f ); - halfRadius = radius * 0.5f; - lastPoint = dir + up * radius; - lastPoint.Normalize(); - lastPoint = GetPhysics()->GetOrigin() + lastPoint * scanDist; - lastHalfPoint = dir + up * halfRadius; - lastHalfPoint.Normalize(); - lastHalfPoint = GetPhysics()->GetOrigin() + lastHalfPoint * scanDist; - center = GetPhysics()->GetOrigin() + dir * scanDist; - for ( i = 1; i < 12; i++ ) { - a = idMath::TWO_PI * i / 12.0f; - idMath::SinCos( a, s, c ); - point = dir + right * s * radius + up * c * radius; - point.Normalize(); - point = GetPhysics()->GetOrigin() + point * scanDist; - gameRenderWorld->DebugLine( color, lastPoint, point ); - gameRenderWorld->DebugLine( color, GetPhysics()->GetOrigin(), point ); - lastPoint = point; - - halfPoint = dir + right * s * halfRadius + up * c * halfRadius; - halfPoint.Normalize(); - halfPoint = GetPhysics()->GetOrigin() + halfPoint * scanDist; - gameRenderWorld->DebugLine( color2, point, halfPoint ); - gameRenderWorld->DebugLine( color2, lastHalfPoint, halfPoint ); - lastHalfPoint = halfPoint; - - gameRenderWorld->DebugLine( color2, halfPoint, center ); - } -} - -/* -================ -idSecurityCamera::GetRenderView -================ -*/ -renderView_t *idSecurityCamera::GetRenderView() { - renderView_t *rv = idEntity::GetRenderView(); - rv->fov_x = scanFov; - rv->fov_y = scanFov; - rv->viewaxis = GetAxis().ToAngles().ToMat3(); - rv->vieworg = GetPhysics()->GetOrigin() + viewOffset; - return rv; -} - -/* -================ -idSecurityCamera::CanSeePlayer -================ -*/ -bool idSecurityCamera::CanSeePlayer( void ) { - int i; - float dist; - idPlayer *ent; - trace_t tr; - idVec3 dir; - pvsHandle_t handle; - - handle = gameLocal.pvs.SetupCurrentPVS( pvsArea ); - - for ( i = 0; i < gameLocal.numClients; i++ ) { - ent = static_cast(gameLocal.entities[ i ]); - - if ( !ent || ( ent->fl.notarget ) ) { - continue; - } - - // if there is no way we can see this player - if ( !gameLocal.pvs.InCurrentPVS( handle, ent->GetPVSAreas(), ent->GetNumPVSAreas() ) ) { - continue; - } - - dir = ent->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin(); - dist = dir.Normalize(); - - if ( dist > scanDist ) { - continue; - } - - if ( dir * GetAxis() < scanFovCos ) { - continue; - } - - idVec3 eye; - - eye = ent->EyeOffset(); - - gameLocal.clip.TracePoint( tr, GetPhysics()->GetOrigin(), ent->GetPhysics()->GetOrigin() + eye, MASK_OPAQUE, this ); - if ( tr.fraction == 1.0 || ( gameLocal.GetTraceEntity( tr ) == ent ) ) { - gameLocal.pvs.FreeCurrentPVS( handle ); - return true; - } - } - - gameLocal.pvs.FreeCurrentPVS( handle ); - - return false; -} - -/* -================ -idSecurityCamera::SetAlertMode -================ -*/ -void idSecurityCamera::SetAlertMode( int alert ) { - if (alert >= SCANNING && alert <= ACTIVATED) { - alertMode = alert; - } - renderEntity.shaderParms[ SHADERPARM_MODE ] = alertMode; - UpdateVisuals(); -} - -/* -================ -idSecurityCamera::Think -================ -*/ -void idSecurityCamera::Think( void ) { - float pct; - float travel; - - if ( thinkFlags & TH_THINK ) { - if ( g_showEntityInfo.GetBool() ) { - DrawFov(); - } - - if (health <= 0) { - BecomeInactive( TH_THINK ); - return; - } - } - - // run physics - RunPhysics(); - - if ( thinkFlags & TH_THINK ) { - if (CanSeePlayer()) { - if (alertMode == SCANNING) { - float sightTime; - - SetAlertMode(ALERT); - stopSweeping = gameLocal.time; - if (sweeping) { - CancelEvents( &EV_SecurityCam_Pause ); - } else { - CancelEvents( &EV_SecurityCam_ReverseSweep ); - } - sweeping = false; - StopSound( SND_CHANNEL_ANY, false ); - StartSound( "snd_sight", SND_CHANNEL_BODY, 0, false, NULL ); - - sightTime = spawnArgs.GetFloat( "sightTime", "5" ); - PostEventSec(&EV_SecurityCam_Alert, sightTime); - } - } else { - if (alertMode == ALERT) { - float sightResume; - - SetAlertMode(LOSINGINTEREST); - CancelEvents( &EV_SecurityCam_Alert ); - - sightResume = spawnArgs.GetFloat( "sightResume", "1.5" ); - PostEventSec( &EV_SecurityCam_ContinueSweep, sightResume ); - } - - if ( sweeping ) { - idAngles a = GetPhysics()->GetAxis().ToAngles(); - - pct = ( gameLocal.time - sweepStart ) / ( sweepEnd - sweepStart ); - travel = pct * sweepAngle; - if ( negativeSweep ) { - a.yaw = angle + travel; - } else { - a.yaw = angle - travel; - } - - SetAngles( a ); - } - } - } - Present(); -} - -/* -================ -idSecurityCamera::GetAxis -================ -*/ -const idVec3 idSecurityCamera::GetAxis( void ) const { - return (flipAxis) ? -GetPhysics()->GetAxis()[modelAxis] : GetPhysics()->GetAxis()[modelAxis]; -}; - -/* -================ -idSecurityCamera::SweepSpeed -================ -*/ -float idSecurityCamera::SweepSpeed( void ) const { - return spawnArgs.GetFloat( "sweepSpeed", "5" ); -} - -/* -================ -idSecurityCamera::StartSweep -================ -*/ -void idSecurityCamera::StartSweep( void ) { - int speed; - - sweeping = true; - sweepStart = gameLocal.time; - speed = SEC2MS( SweepSpeed() ); - sweepEnd = sweepStart + speed; - PostEventMS( &EV_SecurityCam_Pause, speed ); - StartSound( "snd_moving", SND_CHANNEL_BODY, 0, false, NULL ); -} - -/* -================ -idSecurityCamera::Event_ContinueSweep -================ -*/ -void idSecurityCamera::Event_ContinueSweep( void ) { - float pct = (stopSweeping - sweepStart) / (sweepEnd - sweepStart); - float f = gameLocal.time - (sweepEnd - sweepStart) * pct; - int speed; - - sweepStart = f; - speed = MS2SEC( SweepSpeed() ); - sweepEnd = sweepStart + speed; - PostEventMS( &EV_SecurityCam_Pause, speed * (1.0 - pct)); - StartSound( "snd_moving", SND_CHANNEL_BODY, 0, false, NULL ); - SetAlertMode(SCANNING); - sweeping = true; -} - -/* -================ -idSecurityCamera::Event_Alert -================ -*/ -void idSecurityCamera::Event_Alert( void ) { - float wait; - - SetAlertMode(ACTIVATED); - StopSound( SND_CHANNEL_ANY, false ); - StartSound( "snd_activate", SND_CHANNEL_BODY, 0, false, NULL ); - ActivateTargets(this); - CancelEvents( &EV_SecurityCam_ContinueSweep ); - - wait = spawnArgs.GetFloat( "wait", "20" ); - PostEventSec( &EV_SecurityCam_ContinueSweep, wait ); -} - -/* -================ -idSecurityCamera::Event_ReverseSweep -================ -*/ -void idSecurityCamera::Event_ReverseSweep( void ) { - angle = GetPhysics()->GetAxis().ToAngles().yaw; - negativeSweep = !negativeSweep; - StartSweep(); -} - -/* -================ -idSecurityCamera::Event_Pause -================ -*/ -void idSecurityCamera::Event_Pause( void ) { - float sweepWait; - - sweepWait = spawnArgs.GetFloat( "sweepWait", "0.5" ); - sweeping = false; - StopSound( SND_CHANNEL_ANY, false ); - StartSound( "snd_stop", SND_CHANNEL_BODY, 0, false, NULL ); - PostEventSec( &EV_SecurityCam_ReverseSweep, sweepWait ); -} - -/* -============ -idSecurityCamera::Killed -============ -*/ -void idSecurityCamera::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) { - sweeping = false; - StopSound( SND_CHANNEL_ANY, false ); - const char *fx = spawnArgs.GetString( "fx_destroyed" ); - if ( fx[0] != '\0' ) { - idEntityFx::StartFx( fx, NULL, NULL, this, true ); - } - - physicsObj.SetSelf( this ); - physicsObj.SetClipModel( new idClipModel( trm ), 0.02f ); - physicsObj.SetOrigin( GetPhysics()->GetOrigin() ); - physicsObj.SetAxis( GetPhysics()->GetAxis() ); - physicsObj.SetBouncyness( 0.2f ); - physicsObj.SetFriction( 0.6f, 0.6f, 0.2f ); - physicsObj.SetGravity( gameLocal.GetGravity() ); - physicsObj.SetContents( CONTENTS_SOLID ); - physicsObj.SetClipMask( MASK_SOLID | CONTENTS_BODY | CONTENTS_CORPSE | CONTENTS_MOVEABLECLIP ); - SetPhysics( &physicsObj ); - physicsObj.DropToFloor(); -} - - -/* -============ -idSecurityCamera::Pain -============ -*/ -bool idSecurityCamera::Pain( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) { - const char *fx = spawnArgs.GetString( "fx_damage" ); - if ( fx[0] != '\0' ) { - idEntityFx::StartFx( fx, NULL, NULL, this, true ); - } - return true; -} - - -/* -================ -idSecurityCamera::Present - -Present is called to allow entities to generate refEntities, lights, etc for the renderer. -================ -*/ -void idSecurityCamera::Present( void ) { - // don't present to the renderer if the entity hasn't changed - if ( !( thinkFlags & TH_UPDATEVISUALS ) ) { - return; - } - BecomeInactive( TH_UPDATEVISUALS ); - - // camera target for remote render views - if ( cameraTarget ) { - renderEntity.remoteRenderView = cameraTarget->GetRenderView(); - } - - // if set to invisible, skip - if ( !renderEntity.hModel || IsHidden() ) { - return; - } - - // add to refresh list - if ( modelDefHandle == -1 ) { - modelDefHandle = gameRenderWorld->AddEntityDef( &renderEntity ); - } else { - gameRenderWorld->UpdateEntityDef( modelDefHandle, &renderEntity ); - } -} diff --git a/d3xp/SecurityCamera.h b/d3xp/SecurityCamera.h deleted file mode 100644 index 6e54dfd1..00000000 --- a/d3xp/SecurityCamera.h +++ /dev/null @@ -1,99 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __GAME_SECURITYCAMERA_H__ -#define __GAME_SECURITYCAMERA_H__ - -#include "Entity.h" - -/* -=================================================================================== - - Security camera - -=================================================================================== -*/ - - -class idSecurityCamera : public idEntity { -public: - CLASS_PROTOTYPE( idSecurityCamera ); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - virtual void Think( void ); - - virtual renderView_t * GetRenderView(); - virtual void Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ); - virtual bool Pain( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ); - virtual void Present( void ); - - -private: - - enum { SCANNING, LOSINGINTEREST, ALERT, ACTIVATED }; - - float angle; - float sweepAngle; - int modelAxis; - bool flipAxis; - float scanDist; - float scanFov; - - float sweepStart; - float sweepEnd; - bool negativeSweep; - bool sweeping; - int alertMode; - float stopSweeping; - float scanFovCos; - - idVec3 viewOffset; - - int pvsArea; - idPhysics_RigidBody physicsObj; - idTraceModel trm; - - void StartSweep( void ); - bool CanSeePlayer( void ); - void SetAlertMode( int status ); - void DrawFov( void ); - const idVec3 GetAxis( void ) const; - float SweepSpeed( void ) const; - - void Event_ReverseSweep( void ); - void Event_ContinueSweep( void ); - void Event_Pause( void ); - void Event_Alert( void ); - void Event_AddLight( void ); -}; - -#endif /* !__GAME_SECURITYCAMERA_H__ */ diff --git a/d3xp/SmokeParticles.cpp b/d3xp/SmokeParticles.cpp deleted file mode 100644 index 710baecf..00000000 --- a/d3xp/SmokeParticles.cpp +++ /dev/null @@ -1,449 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "renderer/ModelManager.h" -#include "Entity.h" -#include "Game_local.h" - -#include "SmokeParticles.h" - -static const char *smokeParticle_SnapshotName = "_SmokeParticle_Snapshot_"; - -/* -================ -idSmokeParticles::idSmokeParticles -================ -*/ -idSmokeParticles::idSmokeParticles( void ) { - initialized = false; - memset( &renderEntity, 0, sizeof( renderEntity ) ); - renderEntityHandle = -1; - memset( smokes, 0, sizeof( smokes ) ); - freeSmokes = NULL; - numActiveSmokes = 0; - currentParticleTime = -1; -} - -/* -================ -idSmokeParticles::Init -================ -*/ -void idSmokeParticles::Init( void ) { - if ( initialized ) { - Shutdown(); - } - - // set up the free list - for ( int i = 0; i < MAX_SMOKE_PARTICLES-1; i++ ) { - smokes[i].next = &smokes[i+1]; - } - smokes[MAX_SMOKE_PARTICLES-1].next = NULL; - freeSmokes = &smokes[0]; - numActiveSmokes = 0; - - activeStages.Clear(); - - memset( &renderEntity, 0, sizeof( renderEntity ) ); - - renderEntity.bounds.Clear(); - renderEntity.axis = mat3_identity; - renderEntity.shaderParms[ SHADERPARM_RED ] = 1; - renderEntity.shaderParms[ SHADERPARM_GREEN ] = 1; - renderEntity.shaderParms[ SHADERPARM_BLUE ] = 1; - renderEntity.shaderParms[3] = 1; - - renderEntity.hModel = renderModelManager->AllocModel(); - renderEntity.hModel->InitEmpty( smokeParticle_SnapshotName ); - - // we certainly don't want particle shadows - renderEntity.noShadow = 1; - - // huge bounds, so it will be present in every world area - renderEntity.bounds.AddPoint( idVec3(-100000, -100000, -100000) ); - renderEntity.bounds.AddPoint( idVec3( 100000, 100000, 100000) ); - - renderEntity.callback = idSmokeParticles::ModelCallback; - // add to renderer list - renderEntityHandle = gameRenderWorld->AddEntityDef( &renderEntity ); - - currentParticleTime = -1; - - initialized = true; -} - -/* -================ -idSmokeParticles::Shutdown -================ -*/ -void idSmokeParticles::Shutdown( void ) { - // make sure the render entity is freed before the model is freed - if ( renderEntityHandle != -1 ) { - gameRenderWorld->FreeEntityDef( renderEntityHandle ); - renderEntityHandle = -1; - } - if ( renderEntity.hModel != NULL ) { - renderModelManager->FreeModel( renderEntity.hModel ); - renderEntity.hModel = NULL; - } - initialized = false; -} - -/* -================ -idSmokeParticles::FreeSmokes -================ -*/ -void idSmokeParticles::FreeSmokes( void ) { - for ( int activeStageNum = 0; activeStageNum < activeStages.Num(); activeStageNum++ ) { - singleSmoke_t *smoke, *next, *last; - - activeSmokeStage_t *active = &activeStages[activeStageNum]; - const idParticleStage *stage = active->stage; - - for ( last = NULL, smoke = active->smokes; smoke; smoke = next ) { - next = smoke->next; - -#ifdef _D3XP - float frac; - - if ( smoke->timeGroup ) { - frac = (float)( gameLocal.fast.time - smoke->privateStartTime ) / ( stage->particleLife * 1000 ); - } - else { - frac = (float)( gameLocal.slow.time - smoke->privateStartTime ) / ( stage->particleLife * 1000 ); - } -#else - float frac = (float)( gameLocal.time - smoke->privateStartTime ) / ( stage->particleLife * 1000 ); -#endif - if ( frac >= 1.0f ) { - // remove the particle from the stage list - if ( last != NULL ) { - last->next = smoke->next; - } else { - active->smokes = smoke->next; - } - // put the particle on the free list - smoke->next = freeSmokes; - freeSmokes = smoke; - numActiveSmokes--; - continue; - } - - last = smoke; - } - - if ( !active->smokes ) { - // remove this from the activeStages list - activeStages.RemoveIndex( activeStageNum ); - activeStageNum--; - } - } -} - -/* -================ -idSmokeParticles::EmitSmoke - -Called by game code to drop another particle into the list -================ -*/ -bool idSmokeParticles::EmitSmoke( const idDeclParticle *smoke, const int systemStartTime, const float diversity, const idVec3 &origin, const idMat3 &axis, int timeGroup /*_D3XP*/ ) { - bool continues = false; -#ifdef _D3XP - SetTimeState ts( timeGroup ); -#endif - - if ( !smoke ) { - return false; - } - - if ( !gameLocal.isNewFrame ) { - return false; - } - - // dedicated doesn't smoke. No UpdateRenderEntity, so they would not be freed - if ( gameLocal.localClientNum < 0 ) { - return false; - } - - assert( gameLocal.time == 0 || systemStartTime <= gameLocal.time ); - if ( systemStartTime > gameLocal.time ) { - return false; - } - - idRandom steppingRandom( 0xffff * diversity ); - - // for each stage in the smoke that is still emitting particles, emit a new singleSmoke_t - for ( int stageNum = 0; stageNum < smoke->stages.Num(); stageNum++ ) { - const idParticleStage *stage = smoke->stages[stageNum]; - - if ( !stage->cycleMsec ) { - continue; - } - - if ( !stage->material ) { - continue; - } - - if ( stage->particleLife <= 0 ) { - continue; - } - - // see how many particles we should emit this tic - // FIXME: smoke.privateStartTime += stage->timeOffset; - int finalParticleTime = stage->cycleMsec * stage->spawnBunching; - int deltaMsec = gameLocal.time - systemStartTime; - - int nowCount, prevCount; - if ( finalParticleTime == 0 ) { - // if spawnBunching is 0, they will all come out at once - if ( gameLocal.time == systemStartTime ) { - prevCount = -1; - nowCount = stage->totalParticles-1; - } else { - prevCount = stage->totalParticles; - } - } else { - nowCount = floor( ( (float)deltaMsec / finalParticleTime ) * stage->totalParticles ); - if ( nowCount >= stage->totalParticles ) { - nowCount = stage->totalParticles-1; - } - prevCount = floor( ((float)( deltaMsec - gameLocal.msec /*_D3XP - FIX - was USERCMD_MSEC*/ ) / finalParticleTime) * stage->totalParticles ); - if ( prevCount < -1 ) { - prevCount = -1; - } - } - - if ( prevCount >= stage->totalParticles ) { - // no more particles from this stage - continue; - } - - if ( nowCount < stage->totalParticles-1 ) { - // the system will need to emit particles next frame as well - continues = true; - } - - // find an activeSmokeStage that matches this - activeSmokeStage_t *active = NULL; - int i; - for ( i = 0 ; i < activeStages.Num() ; i++ ) { - active = &activeStages[i]; - if ( active->stage == stage ) { - break; - } - } - if ( i == activeStages.Num() ) { - // add a new one - activeSmokeStage_t newActive; - - newActive.smokes = NULL; - newActive.stage = stage; - i = activeStages.Append( newActive ); - active = &activeStages[i]; - } - - // add all the required particles - for ( prevCount++ ; prevCount <= nowCount ; prevCount++ ) { - if ( !freeSmokes ) { - gameLocal.Printf( "idSmokeParticles::EmitSmoke: no free smokes with %d active stages\n", activeStages.Num() ); - return true; - } - singleSmoke_t *newSmoke = freeSmokes; - freeSmokes = freeSmokes->next; - numActiveSmokes++; - -#ifdef _D3XP - newSmoke->timeGroup = timeGroup; -#endif - newSmoke->index = prevCount; - newSmoke->axis = axis; - newSmoke->origin = origin; - newSmoke->random = steppingRandom; - newSmoke->privateStartTime = systemStartTime + prevCount * finalParticleTime / stage->totalParticles; - newSmoke->next = active->smokes; - active->smokes = newSmoke; - - steppingRandom.RandomInt(); // advance the random - } - } - - return continues; -} - -/* -================ -idSmokeParticles::UpdateRenderEntity -================ -*/ -bool idSmokeParticles::UpdateRenderEntity( renderEntity_s *renderEntity, const renderView_t *renderView ) { - - // FIXME: re-use model surfaces - renderEntity->hModel->InitEmpty( smokeParticle_SnapshotName ); - - // this may be triggered by a model trace or other non-view related source, - // to which we should look like an empty model - if ( !renderView ) { - return false; - } - - // don't regenerate it if it is current - if ( renderView->time == currentParticleTime && !renderView->forceUpdate ) { - return false; - } - currentParticleTime = renderView->time; - - particleGen_t g; - - g.renderEnt = renderEntity; - g.renderView = renderView; - - for ( int activeStageNum = 0; activeStageNum < activeStages.Num(); activeStageNum++ ) { - singleSmoke_t *smoke, *next, *last; - - activeSmokeStage_t *active = &activeStages[activeStageNum]; - const idParticleStage *stage = active->stage; - - if ( !stage->material ) { - continue; - } - - // allocate a srfTriangles that can hold all the particles - int count = 0; - for ( smoke = active->smokes; smoke; smoke = smoke->next ) { - count++; - } - int quads = count * stage->NumQuadsPerParticle(); - srfTriangles_t *tri = renderEntity->hModel->AllocSurfaceTriangles( quads * 4, quads * 6 ); - tri->numIndexes = quads * 6; - tri->numVerts = quads * 4; - - // just always draw the particles - tri->bounds[0][0] = - tri->bounds[0][1] = - tri->bounds[0][2] = -99999; - tri->bounds[1][0] = - tri->bounds[1][1] = - tri->bounds[1][2] = 99999; - - tri->numVerts = 0; - for ( last = NULL, smoke = active->smokes; smoke; smoke = next ) { - next = smoke->next; - -#ifdef _D3XP - if ( smoke->timeGroup ) { - g.frac = (float)( gameLocal.fast.time - smoke->privateStartTime ) / (stage->particleLife * 1000); - } - else { - g.frac = (float)( gameLocal.time - smoke->privateStartTime ) / (stage->particleLife * 1000); - } -#else - g.frac = (float)( gameLocal.time - smoke->privateStartTime ) / (stage->particleLife * 1000); -#endif - if ( g.frac >= 1.0f ) { - // remove the particle from the stage list - if ( last != NULL ) { - last->next = smoke->next; - } else { - active->smokes = smoke->next; - } - // put the particle on the free list - smoke->next = freeSmokes; - freeSmokes = smoke; - numActiveSmokes--; - continue; - } - - g.index = smoke->index; - g.random = smoke->random; - - g.origin = smoke->origin; - g.axis = smoke->axis; - - g.originalRandom = g.random; - g.age = g.frac * stage->particleLife; - - tri->numVerts += stage->CreateParticle( &g, tri->verts + tri->numVerts ); - - last = smoke; - } - if ( tri->numVerts > quads * 4 ) { - gameLocal.Error( "idSmokeParticles::UpdateRenderEntity: miscounted verts" ); - } - - if ( tri->numVerts == 0 ) { - - // they were all removed - renderEntity->hModel->FreeSurfaceTriangles( tri ); - - if ( !active->smokes ) { - // remove this from the activeStages list - activeStages.RemoveIndex( activeStageNum ); - activeStageNum--; - } - } else { - // build the index list - int indexes = 0; - for ( int i = 0 ; i < tri->numVerts ; i += 4 ) { - tri->indexes[indexes+0] = i; - tri->indexes[indexes+1] = i+2; - tri->indexes[indexes+2] = i+3; - tri->indexes[indexes+3] = i; - tri->indexes[indexes+4] = i+3; - tri->indexes[indexes+5] = i+1; - indexes += 6; - } - tri->numIndexes = indexes; - - modelSurface_t surf; - surf.geometry = tri; - surf.shader = stage->material; - surf.id = 0; - - renderEntity->hModel->AddSurface( surf ); - } - } - return true; -} - -/* -================ -idSmokeParticles::ModelCallback -================ -*/ -bool idSmokeParticles::ModelCallback( renderEntity_s *renderEntity, const renderView_t *renderView ) { - // update the particles - if ( gameLocal.smokeParticles ) { - return gameLocal.smokeParticles->UpdateRenderEntity( renderEntity, renderView ); - } - - return true; -} diff --git a/d3xp/SmokeParticles.h b/d3xp/SmokeParticles.h deleted file mode 100644 index 0f2700ce..00000000 --- a/d3xp/SmokeParticles.h +++ /dev/null @@ -1,111 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __SMOKEPARTICLES_H__ -#define __SMOKEPARTICLES_H__ - -#include "idlib/math/Random.h" -#include "idlib/math/Vector.h" -#include "idlib/math/Matrix.h" -#include "framework/DeclParticle.h" -#include "renderer/RenderWorld.h" - -/* -=============================================================================== - - Smoke systems are for particles that are emitted off of things that are - constantly changing position and orientation, like muzzle smoke coming - from a bone on a weapon, blood spurting from a wound, or particles - trailing from a monster limb. - - The smoke particles are always evaluated and rendered each tic, so there - is a performance cost with using them for continuous effects. The general - particle systems are completely parametric, and have no performance - overhead when not in view. - - All smoke systems share the same shaderparms, so any coloration must be - done in the particle definition. - - Each particle model has its own shaderparms, which can be used by the - particle materials. - -=============================================================================== -*/ - -typedef struct singleSmoke_s { - struct singleSmoke_s * next; - int privateStartTime; // start time for this particular particle - int index; // particle index in system, 0 <= index < stage->totalParticles - idRandom random; - idVec3 origin; - idMat3 axis; -#ifdef _D3XP - int timeGroup; -#endif -} singleSmoke_t; - -typedef struct { - const idParticleStage * stage; - singleSmoke_t * smokes; -} activeSmokeStage_t; - - -class idSmokeParticles { -public: - idSmokeParticles( void ); - - // creats an entity covering the entire world that will call back each rendering - void Init( void ); - void Shutdown( void ); - - // spits out a particle, returning false if the system will not emit any more particles in the future - bool EmitSmoke( const idDeclParticle *smoke, const int startTime, const float diversity, - const idVec3 &origin, const idMat3 &axis, int timeGroup /*_D3XP*/ ); - - // free old smokes - void FreeSmokes( void ); - -private: - bool initialized; - - renderEntity_t renderEntity; // used to present a model to the renderer - int renderEntityHandle; // handle to static renderer model - - static const int MAX_SMOKE_PARTICLES = 10000; - singleSmoke_t smokes[MAX_SMOKE_PARTICLES]; - - idList activeStages; - singleSmoke_t * freeSmokes; - int numActiveSmokes; - int currentParticleTime; // don't need to recalculate if == view time - - bool UpdateRenderEntity( renderEntity_s *renderEntity, const renderView_t *renderView ); - static bool ModelCallback( renderEntity_s *renderEntity, const renderView_t *renderView ); -}; - -#endif /* !__SMOKEPARTICLES_H__ */ diff --git a/d3xp/Sound.cpp b/d3xp/Sound.cpp deleted file mode 100644 index d5a1f3e5..00000000 --- a/d3xp/Sound.cpp +++ /dev/null @@ -1,304 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "Entity.h" - -#include "Sound.h" - -/* -=============================================================================== - - SOUND - -=============================================================================== -*/ - -const idEventDef EV_Speaker_On( "On", NULL ); -const idEventDef EV_Speaker_Off( "Off", NULL ); -const idEventDef EV_Speaker_Timer( "", NULL ); - -CLASS_DECLARATION( idEntity, idSound ) - EVENT( EV_Activate, idSound::Event_Trigger ) - EVENT( EV_Speaker_On, idSound::Event_On ) - EVENT( EV_Speaker_Off, idSound::Event_Off ) - EVENT( EV_Speaker_Timer, idSound::Event_Timer ) -END_CLASS - - -/* -================ -idSound::idSound -================ -*/ -idSound::idSound( void ) { - lastSoundVol = 0.0f; - soundVol = 0.0f; - shakeTranslate.Zero(); - shakeRotate.Zero(); - random = 0.0f; - wait = 0.0f; - timerOn = false; - playingUntilTime = 0; -} - -/* -================ -idSound::Save -================ -*/ -void idSound::Save( idSaveGame *savefile ) const { - savefile->WriteFloat( lastSoundVol ); - savefile->WriteFloat( soundVol ); - savefile->WriteFloat( random ); - savefile->WriteFloat( wait ); - savefile->WriteBool( timerOn ); - savefile->WriteVec3( shakeTranslate ); - savefile->WriteAngles( shakeRotate ); - savefile->WriteInt( playingUntilTime ); -} - -/* -================ -idSound::Restore -================ -*/ -void idSound::Restore( idRestoreGame *savefile ) { - savefile->ReadFloat( lastSoundVol ); - savefile->ReadFloat( soundVol ); - savefile->ReadFloat( random ); - savefile->ReadFloat( wait ); - savefile->ReadBool( timerOn ); - savefile->ReadVec3( shakeTranslate ); - savefile->ReadAngles( shakeRotate ); - savefile->ReadInt( playingUntilTime ); -} - -/* -================ -idSound::Spawn -================ -*/ -void idSound::Spawn( void ) { - spawnArgs.GetVector( "move", "0 0 0", shakeTranslate ); - spawnArgs.GetAngles( "rotate", "0 0 0", shakeRotate ); - spawnArgs.GetFloat( "random", "0", random ); - spawnArgs.GetFloat( "wait", "0", wait ); - - if ( ( wait > 0.0f ) && ( random >= wait ) ) { - random = wait - 0.001; - gameLocal.Warning( "speaker '%s' at (%s) has random >= wait", name.c_str(), GetPhysics()->GetOrigin().ToString(0) ); - } - - soundVol = 0.0f; - lastSoundVol = 0.0f; - - if ( ( shakeRotate != ang_zero ) || ( shakeTranslate != vec3_zero ) ) { - BecomeActive( TH_THINK ); - } - - if ( !refSound.waitfortrigger && ( wait > 0.0f ) ) { - timerOn = true; - PostEventSec( &EV_Speaker_Timer, wait + gameLocal.random.CRandomFloat() * random ); - } else { - timerOn = false; - } -} - -/* -================ -idSound::Event_Trigger - -this will toggle the idle idSound on and off -================ -*/ -void idSound::Event_Trigger( idEntity *activator ) { - if ( wait > 0.0f ) { - if ( timerOn ) { - timerOn = false; - CancelEvents( &EV_Speaker_Timer ); - } else { - timerOn = true; - DoSound( true ); - PostEventSec( &EV_Speaker_Timer, wait + gameLocal.random.CRandomFloat() * random ); - } - } else { - if ( gameLocal.isMultiplayer ) { - if ( refSound.referenceSound && ( gameLocal.time < playingUntilTime ) ) { - DoSound( false ); - } else { - DoSound( true ); - } - } else { - if ( refSound.referenceSound && refSound.referenceSound->CurrentlyPlaying() ) { - DoSound( false ); - } else { - DoSound( true ); - } - } - } -} - -/* -================ -idSound::Event_Timer -================ -*/ -void idSound::Event_Timer( void ) { - DoSound( true ); - PostEventSec( &EV_Speaker_Timer, wait + gameLocal.random.CRandomFloat() * random ); -} - -/* -================ -idSound::Think -================ -*/ -void idSound::Think( void ) { - idAngles ang; - - // run physics - RunPhysics(); - - // clear out our update visuals think flag since we never call Present - BecomeInactive( TH_UPDATEVISUALS ); -} - -/* -=============== -idSound::UpdateChangableSpawnArgs -=============== -*/ -void idSound::UpdateChangeableSpawnArgs( const idDict *source ) { - - idEntity::UpdateChangeableSpawnArgs( source ); - - if ( source ) { - FreeSoundEmitter( true ); - spawnArgs.Copy( *source ); - idSoundEmitter *saveRef = refSound.referenceSound; - gameEdit->ParseSpawnArgsToRefSound( &spawnArgs, &refSound ); - refSound.referenceSound = saveRef; - - idVec3 origin; - idMat3 axis; - - if ( GetPhysicsToSoundTransform( origin, axis ) ) { - refSound.origin = GetPhysics()->GetOrigin() + origin * axis; - } else { - refSound.origin = GetPhysics()->GetOrigin(); - } - - spawnArgs.GetFloat( "random", "0", random ); - spawnArgs.GetFloat( "wait", "0", wait ); - - if ( ( wait > 0.0f ) && ( random >= wait ) ) { - random = wait - 0.001; - gameLocal.Warning( "speaker '%s' at (%s) has random >= wait", name.c_str(), GetPhysics()->GetOrigin().ToString(0) ); - } - - if ( !refSound.waitfortrigger && ( wait > 0.0f ) ) { - timerOn = true; - DoSound( false ); - CancelEvents( &EV_Speaker_Timer ); - PostEventSec( &EV_Speaker_Timer, wait + gameLocal.random.CRandomFloat() * random ); - } else if ( !refSound.waitfortrigger && !(refSound.referenceSound && refSound.referenceSound->CurrentlyPlaying() ) ) { - // start it if it isn't already playing, and we aren't waitForTrigger - DoSound( true ); - timerOn = false; - } - } -} - -/* -=============== -idSound::SetSound -=============== -*/ -void idSound::SetSound( const char *sound, int channel ) { - const idSoundShader *shader = declManager->FindSound( sound ); - if ( shader != refSound.shader ) { - FreeSoundEmitter( true ); - } - gameEdit->ParseSpawnArgsToRefSound(&spawnArgs, &refSound); - refSound.shader = shader; - // start it if it isn't already playing, and we aren't waitForTrigger - if ( !refSound.waitfortrigger && !(refSound.referenceSound && refSound.referenceSound->CurrentlyPlaying() ) ) { - DoSound( true ); - } -} - -/* -================ -idSound::DoSound -================ -*/ -void idSound::DoSound( bool play ) { - if ( play ) { - StartSoundShader( refSound.shader, SND_CHANNEL_ANY, refSound.parms.soundShaderFlags, true, &playingUntilTime ); - playingUntilTime += gameLocal.time; - } else { - StopSound( SND_CHANNEL_ANY, true ); - playingUntilTime = 0; - } -} - -/* -================ -idSound::Event_On -================ -*/ -void idSound::Event_On( void ) { - if ( wait > 0.0f ) { - timerOn = true; - PostEventSec( &EV_Speaker_Timer, wait + gameLocal.random.CRandomFloat() * random ); - } - DoSound( true ); -} - -/* -================ -idSound::Event_Off -================ -*/ -void idSound::Event_Off( void ) { - if ( timerOn ) { - timerOn = false; - CancelEvents( &EV_Speaker_Timer ); - } - DoSound( false ); -} - -/* -=============== -idSound::ShowEditingDialog -=============== -*/ -void idSound::ShowEditingDialog( void ) { - common->InitTool( EDITOR_SOUND, &spawnArgs ); -} diff --git a/d3xp/Sound.h b/d3xp/Sound.h deleted file mode 100644 index 7992f22e..00000000 --- a/d3xp/Sound.h +++ /dev/null @@ -1,78 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __GAME_SOUND_H__ -#define __GAME_SOUND_H__ - -#include "Entity.h" - -/* -=============================================================================== - - Generic sound emitter. - -=============================================================================== -*/ - -class idSound : public idEntity { -public: - CLASS_PROTOTYPE( idSound ); - - idSound( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - virtual void UpdateChangeableSpawnArgs( const idDict *source ); - - void Spawn( void ); - - void ToggleOnOff( idEntity *other, idEntity *activator ); - void Think( void ); - void SetSound( const char *sound, int channel = SND_CHANNEL_ANY ); - - virtual void ShowEditingDialog( void ); - -private: - float lastSoundVol; - float soundVol; - float random; - float wait; - bool timerOn; - idVec3 shakeTranslate; - idAngles shakeRotate; - int playingUntilTime; - - void Event_Trigger( idEntity *activator ); - void Event_Timer( void ); - void Event_On( void ); - void Event_Off( void ); - void DoSound( bool play ); -}; - -#endif /* !__GAME_SOUND_H__ */ diff --git a/d3xp/Target.cpp b/d3xp/Target.cpp deleted file mode 100644 index 3a3f74cd..00000000 --- a/d3xp/Target.cpp +++ /dev/null @@ -1,1798 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "idlib/LangDict.h" -#include "renderer/ModelManager.h" - -#include "gamesys/SysCvar.h" -#include "script/Script_Thread.h" -#include "Light.h" -#include "Player.h" -#include "Mover.h" -#include "Misc.h" -#include "WorldSpawn.h" -#include "Sound.h" - -#include "Target.h" - -/* -=============================================================================== - -idTarget - -Invisible entities that affect other entities or the world when activated. - -=============================================================================== -*/ - -CLASS_DECLARATION( idEntity, idTarget ) -END_CLASS - - -/* -=============================================================================== - -idTarget_Remove - -=============================================================================== -*/ - -CLASS_DECLARATION( idTarget, idTarget_Remove ) - EVENT( EV_Activate, idTarget_Remove::Event_Activate ) -END_CLASS - -/* -================ -idTarget_Remove::Event_Activate -================ -*/ -void idTarget_Remove::Event_Activate( idEntity *activator ) { - int i; - idEntity *ent; - - for( i = 0; i < targets.Num(); i++ ) { - ent = targets[ i ].GetEntity(); - if ( ent ) { - ent->PostEventMS( &EV_Remove, 0 ); - } - } - - // delete our self when done - PostEventMS( &EV_Remove, 0 ); -} - - -/* -=============================================================================== - -idTarget_Show - -=============================================================================== -*/ - -CLASS_DECLARATION( idTarget, idTarget_Show ) - EVENT( EV_Activate, idTarget_Show::Event_Activate ) -END_CLASS - -/* -================ -idTarget_Show::Event_Activate -================ -*/ -void idTarget_Show::Event_Activate( idEntity *activator ) { - int i; - idEntity *ent; - - for( i = 0; i < targets.Num(); i++ ) { - ent = targets[ i ].GetEntity(); - if ( ent ) { - ent->Show(); - } - } - - // delete our self when done - PostEventMS( &EV_Remove, 0 ); -} - - -/* -=============================================================================== - -idTarget_Damage - -=============================================================================== -*/ - -CLASS_DECLARATION( idTarget, idTarget_Damage ) - EVENT( EV_Activate, idTarget_Damage::Event_Activate ) -END_CLASS - -/* -================ -idTarget_Damage::Event_Activate -================ -*/ -void idTarget_Damage::Event_Activate( idEntity *activator ) { - int i; - const char *damage; - idEntity * ent; - - damage = spawnArgs.GetString( "def_damage", "damage_generic" ); - for( i = 0; i < targets.Num(); i++ ) { - ent = targets[ i ].GetEntity(); - if ( ent ) { - ent->Damage( this, this, vec3_origin, damage, 1.0f, INVALID_JOINT ); - } - } -} - - -/* -=============================================================================== - -idTarget_SessionCommand - -=============================================================================== -*/ - -CLASS_DECLARATION( idTarget, idTarget_SessionCommand ) - EVENT( EV_Activate, idTarget_SessionCommand::Event_Activate ) -END_CLASS - -/* -================ -idTarget_SessionCommand::Event_Activate -================ -*/ -void idTarget_SessionCommand::Event_Activate( idEntity *activator ) { - gameLocal.sessionCommand = spawnArgs.GetString( "command" ); -} - - -/* -=============================================================================== - -idTarget_EndLevel - -Just a modified form of idTarget_SessionCommand -=============================================================================== -*/ - -CLASS_DECLARATION( idTarget, idTarget_EndLevel ) - EVENT( EV_Activate, idTarget_EndLevel::Event_Activate ) -END_CLASS - -/* -================ -idTarget_EndLevel::Event_Activate -================ -*/ -void idTarget_EndLevel::Event_Activate( idEntity *activator ) { - idStr nextMap; - - if ( spawnArgs.GetBool( "endOfGame" ) ) { - cvarSystem->SetCVarBool( "g_nightmare", true ); - gameLocal.sessionCommand = "disconnect"; - return; - } - - if ( !spawnArgs.GetString( "nextMap", "", nextMap ) ) { - gameLocal.Printf( "idTarget_SessionCommand::Event_Activate: no nextMap key\n" ); - return; - } - - if ( spawnArgs.GetInt( "devmap", "0" ) ) { - gameLocal.sessionCommand = "devmap "; // only for special demos - } else { - gameLocal.sessionCommand = "map "; - } - - gameLocal.sessionCommand += nextMap; -} - - -/* -=============================================================================== - -idTarget_WaitForButton - -=============================================================================== -*/ - -CLASS_DECLARATION( idTarget, idTarget_WaitForButton ) - EVENT( EV_Activate, idTarget_WaitForButton::Event_Activate ) -END_CLASS - -/* -================ -idTarget_WaitForButton::Event_Activate -================ -*/ -void idTarget_WaitForButton::Event_Activate( idEntity *activator ) { - if ( thinkFlags & TH_THINK ) { - BecomeInactive( TH_THINK ); - } else { - // always allow during cinematics - cinematic = true; - BecomeActive( TH_THINK ); - } -} - -/* -================ -idTarget_WaitForButton::Think -================ -*/ -void idTarget_WaitForButton::Think( void ) { - idPlayer *player; - - if ( thinkFlags & TH_THINK ) { - player = gameLocal.GetLocalPlayer(); - if ( player && !( player->oldButtons & BUTTON_ATTACK ) && ( player->usercmd.buttons & BUTTON_ATTACK ) ) { - player->usercmd.buttons &= ~BUTTON_ATTACK; - BecomeInactive( TH_THINK ); - ActivateTargets( player ); - } - } else { - BecomeInactive( TH_ALL ); - } -} - - -/* -=============================================================================== - -idTarget_SetGlobalShaderParm - -=============================================================================== -*/ - -CLASS_DECLARATION( idTarget, idTarget_SetGlobalShaderTime ) -EVENT( EV_Activate, idTarget_SetGlobalShaderTime::Event_Activate ) -END_CLASS - -/* -================ -idTarget_SetGlobalShaderTime::Event_Activate -================ -*/ -void idTarget_SetGlobalShaderTime::Event_Activate( idEntity *activator ) { - int parm = spawnArgs.GetInt( "globalParm" ); - float time = -MS2SEC( gameLocal.time ); - if ( parm >= 0 && parm < MAX_GLOBAL_SHADER_PARMS ) { - gameLocal.globalShaderParms[parm] = time; - } -} - -/* -=============================================================================== - -idTarget_SetShaderParm - -=============================================================================== -*/ - -CLASS_DECLARATION( idTarget, idTarget_SetShaderParm ) - EVENT( EV_Activate, idTarget_SetShaderParm::Event_Activate ) -END_CLASS - -/* -================ -idTarget_SetShaderParm::Event_Activate -================ -*/ -void idTarget_SetShaderParm::Event_Activate( idEntity *activator ) { - int i; - idEntity * ent; - float value; - idVec3 color; - int parmnum; - - // set the color on the targets - if ( spawnArgs.GetVector( "_color", "1 1 1", color ) ) { - for( i = 0; i < targets.Num(); i++ ) { - ent = targets[ i ].GetEntity(); - if ( ent ) { - ent->SetColor( color[ 0 ], color[ 1 ], color[ 2 ] ); - } - } - } - - // set any shader parms on the targets - for( parmnum = 0; parmnum < MAX_ENTITY_SHADER_PARMS; parmnum++ ) { - if ( spawnArgs.GetFloat( va( "shaderParm%d", parmnum ), "0", value ) ) { - for( i = 0; i < targets.Num(); i++ ) { - ent = targets[ i ].GetEntity(); - if ( ent ) { - ent->SetShaderParm( parmnum, value ); - } - } - if (spawnArgs.GetBool("toggle") && (value == 0 || value == 1)) { - int val = value; - val ^= 1; - value = val; - spawnArgs.SetFloat(va("shaderParm%d", parmnum), value); - } - } - } -} - - -/* -=============================================================================== - -idTarget_SetShaderTime - -=============================================================================== -*/ - -CLASS_DECLARATION( idTarget, idTarget_SetShaderTime ) - EVENT( EV_Activate, idTarget_SetShaderTime::Event_Activate ) -END_CLASS - -/* -================ -idTarget_SetShaderTime::Event_Activate -================ -*/ -void idTarget_SetShaderTime::Event_Activate( idEntity *activator ) { - int i; - idEntity * ent; - float time; - - time = -MS2SEC( gameLocal.time ); - for( i = 0; i < targets.Num(); i++ ) { - ent = targets[ i ].GetEntity(); - if ( ent ) { - ent->SetShaderParm( SHADERPARM_TIMEOFFSET, time ); - if ( ent->IsType( idLight::Type ) ) { - static_cast(ent)->SetLightParm( SHADERPARM_TIMEOFFSET, time ); - } - } - } -} - -/* -=============================================================================== - -idTarget_FadeEntity - -=============================================================================== -*/ - -CLASS_DECLARATION( idTarget, idTarget_FadeEntity ) - EVENT( EV_Activate, idTarget_FadeEntity::Event_Activate ) -END_CLASS - -/* -================ -idTarget_FadeEntity::idTarget_FadeEntity -================ -*/ -idTarget_FadeEntity::idTarget_FadeEntity( void ) { - fadeFrom.Zero(); - fadeStart = 0; - fadeEnd = 0; -} - -/* -================ -idTarget_FadeEntity::Save -================ -*/ -void idTarget_FadeEntity::Save( idSaveGame *savefile ) const { - savefile->WriteVec4( fadeFrom ); - savefile->WriteInt( fadeStart ); - savefile->WriteInt( fadeEnd ); -} - -/* -================ -idTarget_FadeEntity::Restore -================ -*/ -void idTarget_FadeEntity::Restore( idRestoreGame *savefile ) { - savefile->ReadVec4( fadeFrom ); - savefile->ReadInt( fadeStart ); - savefile->ReadInt( fadeEnd ); -} - -/* -================ -idTarget_FadeEntity::Event_Activate -================ -*/ -void idTarget_FadeEntity::Event_Activate( idEntity *activator ) { - idEntity *ent; - int i; - - if ( !targets.Num() ) { - return; - } - - // always allow during cinematics - cinematic = true; - BecomeActive( TH_THINK ); - - ent = this; - for( i = 0; i < targets.Num(); i++ ) { - ent = targets[ i ].GetEntity(); - if ( ent ) { - ent->GetColor( fadeFrom ); - break; - } - } - - fadeStart = gameLocal.time; - fadeEnd = gameLocal.time + SEC2MS( spawnArgs.GetFloat( "fadetime" ) ); -} - -/* -================ -idTarget_FadeEntity::Think -================ -*/ -void idTarget_FadeEntity::Think( void ) { - int i; - idEntity *ent; - idVec4 color; - idVec4 fadeTo; - float frac; - - if ( thinkFlags & TH_THINK ) { - GetColor( fadeTo ); - if ( gameLocal.time >= fadeEnd ) { - color = fadeTo; - BecomeInactive( TH_THINK ); - } else { - frac = ( float )( gameLocal.time - fadeStart ) / ( float )( fadeEnd - fadeStart ); - color.Lerp( fadeFrom, fadeTo, frac ); - } - - // set the color on the targets - for( i = 0; i < targets.Num(); i++ ) { - ent = targets[ i ].GetEntity(); - if ( ent ) { - ent->SetColor( color ); - } - } - } else { - BecomeInactive( TH_ALL ); - } -} - -/* -=============================================================================== - -idTarget_LightFadeIn - -=============================================================================== -*/ - -CLASS_DECLARATION( idTarget, idTarget_LightFadeIn ) - EVENT( EV_Activate, idTarget_LightFadeIn::Event_Activate ) -END_CLASS - -/* -================ -idTarget_LightFadeIn::Event_Activate -================ -*/ -void idTarget_LightFadeIn::Event_Activate( idEntity *activator ) { - idEntity *ent; - idLight *light; - int i; - float time; - - if ( !targets.Num() ) { - return; - } - - time = spawnArgs.GetFloat( "fadetime" ); - ent = this; - for( i = 0; i < targets.Num(); i++ ) { - ent = targets[ i ].GetEntity(); - if ( !ent ) { - continue; - } - if ( ent->IsType( idLight::Type ) ) { - light = static_cast( ent ); - light->FadeIn( time ); - } else { - gameLocal.Printf( "'%s' targets non-light '%s'", name.c_str(), ent->GetName() ); - } - } -} - -/* -=============================================================================== - -idTarget_LightFadeOut - -=============================================================================== -*/ - -CLASS_DECLARATION( idTarget, idTarget_LightFadeOut ) - EVENT( EV_Activate, idTarget_LightFadeOut::Event_Activate ) -END_CLASS - -/* -================ -idTarget_LightFadeOut::Event_Activate -================ -*/ -void idTarget_LightFadeOut::Event_Activate( idEntity *activator ) { - idEntity *ent; - idLight *light; - int i; - float time; - - if ( !targets.Num() ) { - return; - } - - time = spawnArgs.GetFloat( "fadetime" ); - ent = this; - for( i = 0; i < targets.Num(); i++ ) { - ent = targets[ i ].GetEntity(); - if ( !ent ) { - continue; - } - if ( ent->IsType( idLight::Type ) ) { - light = static_cast( ent ); - light->FadeOut( time ); - } else { - gameLocal.Printf( "'%s' targets non-light '%s'", name.c_str(), ent->GetName() ); - } - } -} - -/* -=============================================================================== - -idTarget_Give - -=============================================================================== -*/ - -CLASS_DECLARATION( idTarget, idTarget_Give ) - EVENT( EV_Activate, idTarget_Give::Event_Activate ) -END_CLASS - -/* -================ -idTarget_Give::Spawn -================ -*/ -void idTarget_Give::Spawn( void ) { - if ( spawnArgs.GetBool( "onSpawn" ) ) { - PostEventMS( &EV_Activate, 50 ); - } -} - -/* -================ -idTarget_Give::Event_Activate -================ -*/ -void idTarget_Give::Event_Activate( idEntity *activator ) { - - if ( spawnArgs.GetBool( "development" ) && developer.GetInteger() == 0 ) { - return; - } - - static int giveNum = 0; - idPlayer *player = gameLocal.GetLocalPlayer(); - if ( player ) { - const idKeyValue *kv = spawnArgs.MatchPrefix( "item", NULL ); - while ( kv ) { - const idDict *dict = gameLocal.FindEntityDefDict( kv->GetValue(), false ); - if ( dict ) { - idDict d2; - d2.Copy( *dict ); - d2.Set( "name", va( "givenitem_%i", giveNum++ ) ); - idEntity *ent = NULL; - if ( gameLocal.SpawnEntityDef( d2, &ent ) && ent && ent->IsType( idItem::Type ) ) { - idItem *item = static_cast(ent); - item->GiveToPlayer( gameLocal.GetLocalPlayer() ); - } - } - kv = spawnArgs.MatchPrefix( "item", kv ); - } - } -} - -/* -=============================================================================== - -idTarget_GiveEmail - -=============================================================================== -*/ - -CLASS_DECLARATION( idTarget, idTarget_GiveEmail ) -EVENT( EV_Activate, idTarget_GiveEmail::Event_Activate ) -END_CLASS - -/* -================ -idTarget_GiveEmail::Spawn -================ -*/ -void idTarget_GiveEmail::Spawn( void ) { -} - -/* -================ -idTarget_GiveEmail::Event_Activate -================ -*/ -void idTarget_GiveEmail::Event_Activate( idEntity *activator ) { - idPlayer *player = gameLocal.GetLocalPlayer(); - const idDeclPDA *pda = player->GetPDA(); - if ( pda ) { - player->GiveEmail( spawnArgs.GetString( "email" ) ); - } else { - player->ShowTip( spawnArgs.GetString( "text_infoTitle" ), spawnArgs.GetString( "text_PDANeeded" ), true ); - } -} - - -/* -=============================================================================== - -idTarget_SetModel - -=============================================================================== -*/ - -CLASS_DECLARATION( idTarget, idTarget_SetModel ) - EVENT( EV_Activate, idTarget_SetModel::Event_Activate ) -END_CLASS - -/* -================ -idTarget_SetModel::Spawn -================ -*/ -void idTarget_SetModel::Spawn( void ) { - const char *model; - - model = spawnArgs.GetString( "newmodel" ); - if ( declManager->FindType( DECL_MODELDEF, model, false ) == NULL ) { - // precache the render model - renderModelManager->FindModel( model ); - // precache .cm files only - collisionModelManager->LoadModel( model, true ); - } -} - -/* -================ -idTarget_SetModel::Event_Activate -================ -*/ -void idTarget_SetModel::Event_Activate( idEntity *activator ) { - for( int i = 0; i < targets.Num(); i++ ) { - idEntity *ent = targets[ i ].GetEntity(); - if ( ent ) { - ent->SetModel( spawnArgs.GetString( "newmodel" ) ); - } - } -} - - -/* -=============================================================================== - -idTarget_SetInfluence - -=============================================================================== -*/ - -const idEventDef EV_RestoreInfluence( "" ); -const idEventDef EV_GatherEntities( "" ); -const idEventDef EV_Flash( "", "fd" ); -const idEventDef EV_ClearFlash( "", "f" ); - -CLASS_DECLARATION( idTarget, idTarget_SetInfluence ) - EVENT( EV_Activate, idTarget_SetInfluence::Event_Activate ) - EVENT( EV_RestoreInfluence, idTarget_SetInfluence::Event_RestoreInfluence ) - EVENT( EV_GatherEntities, idTarget_SetInfluence::Event_GatherEntities ) - EVENT( EV_Flash, idTarget_SetInfluence::Event_Flash ) - EVENT( EV_ClearFlash, idTarget_SetInfluence::Event_ClearFlash ) -END_CLASS - -/* -================ -idTarget_SetInfluence::idTarget_SetInfluence -================ -*/ -idTarget_SetInfluence::idTarget_SetInfluence( void ) { - flashIn = 0.0f; - flashOut = 0.0f; - delay = 0.0f; - switchToCamera = NULL; - soundFaded = false; - restoreOnTrigger = false; -} - -/* -================ -idTarget_SetInfluence::Save -================ -*/ -void idTarget_SetInfluence::Save( idSaveGame *savefile ) const { - int i; - - savefile->WriteInt( lightList.Num() ); - for( i = 0; i < lightList.Num(); i++ ) { - savefile->WriteInt( lightList[ i ] ); - } - - savefile->WriteInt( guiList.Num() ); - for( i = 0; i < guiList.Num(); i++ ) { - savefile->WriteInt( guiList[ i ] ); - } - - savefile->WriteInt( soundList.Num() ); - for( i = 0; i < soundList.Num(); i++ ) { - savefile->WriteInt( soundList[ i ] ); - } - - savefile->WriteInt( genericList.Num() ); - for( i = 0; i < genericList.Num(); i++ ) { - savefile->WriteInt( genericList[ i ] ); - } - - savefile->WriteFloat( flashIn ); - savefile->WriteFloat( flashOut ); - - savefile->WriteFloat( delay ); - - savefile->WriteString( flashInSound ); - savefile->WriteString( flashOutSound ); - - savefile->WriteObject( switchToCamera ); - - savefile->WriteFloat( fovSetting.GetStartTime() ); - savefile->WriteFloat( fovSetting.GetDuration() ); - savefile->WriteFloat( fovSetting.GetStartValue() ); - savefile->WriteFloat( fovSetting.GetEndValue() ); - - savefile->WriteBool( soundFaded ); - savefile->WriteBool( restoreOnTrigger ); - -#ifdef _D3XP - savefile->WriteInt( savedGuiList.Num() ); - for( i = 0; i < savedGuiList.Num(); i++ ) { - for(int j = 0; j < MAX_RENDERENTITY_GUI; j++) { - savefile->WriteUserInterface(savedGuiList[i].gui[j], savedGuiList[i].gui[j] ? savedGuiList[i].gui[j]->IsUniqued() : false); - } - } -#endif -} - -/* -================ -idTarget_SetInfluence::Restore -================ -*/ -void idTarget_SetInfluence::Restore( idRestoreGame *savefile ) { - int i, num; - int itemNum; - float set; - - savefile->ReadInt( num ); - for( i = 0; i < num; i++ ) { - savefile->ReadInt( itemNum ); - lightList.Append( itemNum ); - } - - savefile->ReadInt( num ); - for( i = 0; i < num; i++ ) { - savefile->ReadInt( itemNum ); - guiList.Append( itemNum ); - } - - savefile->ReadInt( num ); - for( i = 0; i < num; i++ ) { - savefile->ReadInt( itemNum ); - soundList.Append( itemNum ); - } - - savefile->ReadInt( num ); - for ( i = 0; i < num; i++ ) { - savefile->ReadInt( itemNum ); - genericList.Append( itemNum ); - } - - savefile->ReadFloat( flashIn ); - savefile->ReadFloat( flashOut ); - - savefile->ReadFloat( delay ); - - savefile->ReadString( flashInSound ); - savefile->ReadString( flashOutSound ); - - savefile->ReadObject( reinterpret_cast( switchToCamera ) ); - - savefile->ReadFloat( set ); - fovSetting.SetStartTime( set ); - savefile->ReadFloat( set ); - fovSetting.SetDuration( set ); - savefile->ReadFloat( set ); - fovSetting.SetStartValue( set ); - savefile->ReadFloat( set ); - fovSetting.SetEndValue( set ); - - savefile->ReadBool( soundFaded ); - savefile->ReadBool( restoreOnTrigger ); - -#ifdef _D3XP - savefile->ReadInt( num ); - for( i = 0; i < num; i++ ) { - SavedGui_t temp; - for(int j = 0; j < MAX_RENDERENTITY_GUI; j++) { - savefile->ReadUserInterface(temp.gui[j]); - } - savedGuiList.Append( temp ); - } -#endif -} - -/* -================ -idTarget_SetInfluence::Spawn -================ -*/ -void idTarget_SetInfluence::Spawn() { - PostEventMS( &EV_GatherEntities, 0 ); - flashIn = spawnArgs.GetFloat( "flashIn", "0" ); - flashOut = spawnArgs.GetFloat( "flashOut", "0" ); - flashInSound = spawnArgs.GetString( "snd_flashin" ); - flashOutSound = spawnArgs.GetString( "snd_flashout" ); - delay = spawnArgs.GetFloat( "delay" ); - soundFaded = false; - restoreOnTrigger = false; - - // always allow during cinematics - cinematic = true; -} - -/* -================ -idTarget_SetInfluence::Event_Flash -================ -*/ -void idTarget_SetInfluence::Event_Flash( float flash, int out ) { - idPlayer *player = gameLocal.GetLocalPlayer(); - player->playerView.Fade( idVec4( 1, 1, 1, 1 ), flash ); - const idSoundShader *shader = NULL; - if ( !out && flashInSound.Length() ){ - shader = declManager->FindSound( flashInSound ); - player->StartSoundShader( shader, SND_CHANNEL_VOICE, 0, false, NULL ); - } else if ( out && ( flashOutSound.Length() || flashInSound.Length() ) ) { - shader = declManager->FindSound( flashOutSound.Length() ? flashOutSound : flashInSound ); - player->StartSoundShader( shader, SND_CHANNEL_VOICE, 0, false, NULL ); - } - PostEventSec( &EV_ClearFlash, flash, flash ); -} - - -/* -================ -idTarget_SetInfluence::Event_ClearFlash -================ -*/ -void idTarget_SetInfluence::Event_ClearFlash( float flash ) { - idPlayer *player = gameLocal.GetLocalPlayer(); - player->playerView.Fade( vec4_zero , flash ); -} -/* -================ -idTarget_SetInfluence::Event_GatherEntities -================ -*/ -void idTarget_SetInfluence::Event_GatherEntities() { - int i, listedEntities; - idEntity *entityList[ MAX_GENTITIES ]; - - bool lights = spawnArgs.GetBool( "effect_lights" ); - bool sounds = spawnArgs.GetBool( "effect_sounds" ); - bool guis = spawnArgs.GetBool( "effect_guis" ); - bool models = spawnArgs.GetBool( "effect_models" ); - bool vision = spawnArgs.GetBool( "effect_vision" ); - bool targetsOnly = spawnArgs.GetBool( "targetsOnly" ); - - lightList.Clear(); - guiList.Clear(); - soundList.Clear(); -#ifdef _D3XP - savedGuiList.Clear(); -#endif - - if ( spawnArgs.GetBool( "effect_all" ) ) { - lights = sounds = guis = models = vision = true; - } - - if ( targetsOnly ) { - listedEntities = targets.Num(); - for ( i = 0; i < listedEntities; i++ ) { - entityList[i] = targets[i].GetEntity(); - } - } else { - float radius = spawnArgs.GetFloat( "radius" ); - listedEntities = gameLocal.EntitiesWithinRadius( GetPhysics()->GetOrigin(), radius, entityList, MAX_GENTITIES ); - } - - for( i = 0; i < listedEntities; i++ ) { - idEntity *ent = entityList[ i ]; - if ( ent ) { - if ( lights && ent->IsType( idLight::Type ) && ent->spawnArgs.FindKey( "color_demonic" ) ) { - lightList.Append( ent->entityNumber ); - continue; - } - if ( sounds && ent->IsType( idSound::Type ) && ent->spawnArgs.FindKey( "snd_demonic" ) ) { - soundList.Append( ent->entityNumber ); - continue; - } - if ( guis && ent->GetRenderEntity() && ent->GetRenderEntity()->gui[ 0 ] && ent->spawnArgs.FindKey( "gui_demonic" ) ) { - guiList.Append( ent->entityNumber ); -#ifdef _D3XP - SavedGui_t temp; - savedGuiList.Append(temp); -#endif - continue; - } - if ( ent->IsType( idStaticEntity::Type ) && ent->spawnArgs.FindKey( "color_demonic" ) ) { - genericList.Append( ent->entityNumber ); - continue; - } - } - } - idStr temp; - temp = spawnArgs.GetString( "switchToView" ); - switchToCamera = ( temp.Length() ) ? gameLocal.FindEntity( temp ) : NULL; - -} - -/* -================ -idTarget_SetInfluence::Event_Activate -================ -*/ -void idTarget_SetInfluence::Event_Activate( idEntity *activator ) { - int i, j; - idEntity *ent; - idLight *light; - idSound *sound; - idStaticEntity *generic; - const char *parm; - const char *skin; - bool update; - idVec3 color; - idVec4 colorTo; - idPlayer *player; - - player = gameLocal.GetLocalPlayer(); - - if ( spawnArgs.GetBool( "triggerActivate" ) ) { - if ( restoreOnTrigger ) { - ProcessEvent( &EV_RestoreInfluence ); - restoreOnTrigger = false; - return; - } - restoreOnTrigger = true; - } - - float fadeTime = spawnArgs.GetFloat( "fadeWorldSounds" ); - - if ( delay > 0.0f ) { - PostEventSec( &EV_Activate, delay, activator ); - delay = 0.0f; - // start any sound fading now - if ( fadeTime ) { - gameSoundWorld->FadeSoundClasses( 0, -40.0f, fadeTime ); - soundFaded = true; - } - return; - } else if ( fadeTime && !soundFaded ) { - gameSoundWorld->FadeSoundClasses( 0, -40.0f, fadeTime ); - soundFaded = true; - } - - if ( spawnArgs.GetBool( "triggerTargets" ) ) { - ActivateTargets( activator ); - } - - if ( flashIn ) { - PostEventSec( &EV_Flash, 0.0f, flashIn, 0 ); - } - - parm = spawnArgs.GetString( "snd_influence" ); - if ( parm && *parm ) { - PostEventSec( &EV_StartSoundShader, flashIn, parm, SND_CHANNEL_ANY ); - } - - if ( switchToCamera ) { - switchToCamera->PostEventSec( &EV_Activate, flashIn + 0.05f, this ); - } - - int fov = spawnArgs.GetInt( "fov" ); - if ( fov ) { - fovSetting.Init( gameLocal.time, SEC2MS( spawnArgs.GetFloat( "fovTime" ) ), player->DefaultFov(), fov ); - BecomeActive( TH_THINK ); - } - - for ( i = 0; i < genericList.Num(); i++ ) { - ent = gameLocal.entities[genericList[i]]; - if ( ent == NULL ) { - continue; - } - generic = static_cast( ent ); - color = generic->spawnArgs.GetVector( "color_demonic" ); - colorTo.Set( color.x, color.y, color.z, 1.0f ); - generic->Fade( colorTo, spawnArgs.GetFloat( "fade_time", "0.25" ) ); - } - - for ( i = 0; i < lightList.Num(); i++ ) { - ent = gameLocal.entities[lightList[i]]; - if ( ent == NULL || !ent->IsType( idLight::Type ) ) { - continue; - } - light = static_cast(ent); - parm = light->spawnArgs.GetString( "mat_demonic" ); - if ( parm && *parm ) { - light->SetShader( parm ); - } - - color = light->spawnArgs.GetVector( "_color" ); - color = light->spawnArgs.GetVector( "color_demonic", color.ToString() ); - colorTo.Set( color.x, color.y, color.z, 1.0f ); - light->Fade( colorTo, spawnArgs.GetFloat( "fade_time", "0.25" ) ); - } - - for ( i = 0; i < soundList.Num(); i++ ) { - ent = gameLocal.entities[soundList[i]]; - if ( ent == NULL || !ent->IsType( idSound::Type ) ) { - continue; - } - sound = static_cast(ent); - parm = sound->spawnArgs.GetString( "snd_demonic" ); - if ( parm && *parm ) { - if ( sound->spawnArgs.GetBool( "overlayDemonic" ) ) { - sound->StartSound( "snd_demonic", SND_CHANNEL_DEMONIC, 0, false, NULL ); - } else { - sound->StopSound( SND_CHANNEL_ANY, false ); - sound->SetSound( parm ); - } - } - } - - for ( i = 0; i < guiList.Num(); i++ ) { - ent = gameLocal.entities[guiList[i]]; - if ( ent == NULL || ent->GetRenderEntity() == NULL ) { - continue; - } - update = false; - - for ( j = 0; j < MAX_RENDERENTITY_GUI; j++ ) { - if ( ent->GetRenderEntity()->gui[ j ] && ent->spawnArgs.FindKey( j == 0 ? "gui_demonic" : va( "gui_demonic%d", j+1 ) ) ) { -#ifdef _D3XP - //Backup the old one - savedGuiList[i].gui[j] = ent->GetRenderEntity()->gui[ j ]; -#endif - ent->GetRenderEntity()->gui[ j ] = uiManager->FindGui( ent->spawnArgs.GetString( j == 0 ? "gui_demonic" : va( "gui_demonic%d", j+1 ) ), true ); - update = true; - } - } - - if ( update ) { - ent->UpdateVisuals(); - ent->Present(); - } - } - - player->SetInfluenceLevel( spawnArgs.GetInt( "influenceLevel" ) ); - - int snapAngle = spawnArgs.GetInt( "snapAngle" ); - if ( snapAngle ) { - idAngles ang( 0, snapAngle, 0 ); - player->SetViewAngles( ang ); - player->SetAngles( ang ); - } - - if ( spawnArgs.GetBool( "effect_vision" ) ) { - parm = spawnArgs.GetString( "mtrVision" ); - skin = spawnArgs.GetString( "skinVision" ); - player->SetInfluenceView( parm, skin, spawnArgs.GetInt( "visionRadius" ), this ); - } - - parm = spawnArgs.GetString( "mtrWorld" ); - if ( parm && *parm ) { - gameLocal.SetGlobalMaterial( declManager->FindMaterial( parm ) ); - } - - if ( !restoreOnTrigger ) { - PostEventMS( &EV_RestoreInfluence, SEC2MS( spawnArgs.GetFloat( "time" ) ) ); - } -} - -/* -================ -idTarget_SetInfluence::Think -================ -*/ -void idTarget_SetInfluence::Think( void ) { - if ( thinkFlags & TH_THINK ) { - idPlayer *player = gameLocal.GetLocalPlayer(); - player->SetInfluenceFov( fovSetting.GetCurrentValue( gameLocal.time ) ); - if ( fovSetting.IsDone( gameLocal.time ) ) { - if ( !spawnArgs.GetBool( "leaveFOV" ) ) { - player->SetInfluenceFov( 0 ); - } - BecomeInactive( TH_THINK ); - } - } else { - BecomeInactive( TH_ALL ); - } -} - - -/* -================ -idTarget_SetInfluence::Event_RestoreInfluence -================ -*/ -void idTarget_SetInfluence::Event_RestoreInfluence() { - int i, j; - idEntity *ent; - idLight *light; - idSound *sound; - idStaticEntity *generic; - bool update; - idVec3 color; - idVec4 colorTo; - - if ( flashOut ) { - PostEventSec( &EV_Flash, 0.0f, flashOut, 1 ); - } - - if ( switchToCamera ) { - switchToCamera->PostEventMS( &EV_Activate, 0.0f, this ); - } - - for ( i = 0; i < genericList.Num(); i++ ) { - ent = gameLocal.entities[genericList[i]]; - if ( ent == NULL ) { - continue; - } - generic = static_cast( ent ); - colorTo.Set( 1.0f, 1.0f, 1.0f, 1.0f ); - generic->Fade( colorTo, spawnArgs.GetFloat( "fade_time", "0.25" ) ); - } - - for ( i = 0; i < lightList.Num(); i++ ) { - ent = gameLocal.entities[lightList[i]]; - if ( ent == NULL || !ent->IsType( idLight::Type ) ) { - continue; - } - light = static_cast(ent); - if ( !light->spawnArgs.GetBool( "leave_demonic_mat" ) ) { - const char *texture = light->spawnArgs.GetString( "texture", "lights/squarelight1" ); - light->SetShader( texture ); - } - color = light->spawnArgs.GetVector( "_color" ); - colorTo.Set( color.x, color.y, color.z, 1.0f ); - light->Fade( colorTo, spawnArgs.GetFloat( "fade_time", "0.25" ) ); - } - - for ( i = 0; i < soundList.Num(); i++ ) { - ent = gameLocal.entities[soundList[i]]; - if ( ent == NULL || !ent->IsType( idSound::Type ) ) { - continue; - } - sound = static_cast(ent); - sound->StopSound( SND_CHANNEL_ANY, false ); - sound->SetSound( sound->spawnArgs.GetString( "s_shader" ) ); - } - - for ( i = 0; i < guiList.Num(); i++ ) { - ent = gameLocal.entities[guiList[i]]; - if ( ent == NULL || GetRenderEntity() == NULL ) { - continue; - } - update = false; - for( j = 0; j < MAX_RENDERENTITY_GUI; j++ ) { - if ( ent->GetRenderEntity()->gui[ j ] ) { -#ifdef _D3XP - ent->GetRenderEntity()->gui[ j ] = savedGuiList[i].gui[j]; -#else - ent->GetRenderEntity()->gui[ j ] = uiManager->FindGui( ent->spawnArgs.GetString( j == 0 ? "gui" : va( "gui%d", j+1 ) ) ); -#endif - update = true; - } - } - if ( update ) { - ent->UpdateVisuals(); - ent->Present(); - } - } - - idPlayer *player = gameLocal.GetLocalPlayer(); - player->SetInfluenceLevel( 0 ); - player->SetInfluenceView( NULL, NULL, 0.0f, NULL ); - player->SetInfluenceFov( 0 ); - gameLocal.SetGlobalMaterial( NULL ); - float fadeTime = spawnArgs.GetFloat( "fadeWorldSounds" ); - if ( fadeTime ) { - gameSoundWorld->FadeSoundClasses( 0, 0.0f, fadeTime / 2.0f ); - } - -} - -/* -=============================================================================== - -idTarget_SetKeyVal - -=============================================================================== -*/ - -CLASS_DECLARATION( idTarget, idTarget_SetKeyVal ) - EVENT( EV_Activate, idTarget_SetKeyVal::Event_Activate ) -END_CLASS - -/* -================ -idTarget_SetKeyVal::Event_Activate -================ -*/ -void idTarget_SetKeyVal::Event_Activate( idEntity *activator ) { - int i; - idStr key, val; - idEntity *ent; - const idKeyValue *kv; - int n; - - for( i = 0; i < targets.Num(); i++ ) { - ent = targets[ i ].GetEntity(); - if ( ent ) { - kv = spawnArgs.MatchPrefix("keyval"); - while ( kv ) { - n = kv->GetValue().Find( ";" ); - if ( n > 0 ) { - key = kv->GetValue().Left( n ); - val = kv->GetValue().Right( kv->GetValue().Length() - n - 1 ); - ent->spawnArgs.Set( key, val ); - for ( int j = 0; j < MAX_RENDERENTITY_GUI; j++ ) { - if ( ent->GetRenderEntity()->gui[ j ] ) { - if ( idStr::Icmpn( key, "gui_", 4 ) == 0 ) { - ent->GetRenderEntity()->gui[ j ]->SetStateString( key, val ); - ent->GetRenderEntity()->gui[ j ]->StateChanged( gameLocal.time ); - } - } - } - } - kv = spawnArgs.MatchPrefix( "keyval", kv ); - } - ent->UpdateChangeableSpawnArgs( NULL ); - ent->UpdateVisuals(); - ent->Present(); - } - } -} - -/* -=============================================================================== - -idTarget_SetFov - -=============================================================================== -*/ - -CLASS_DECLARATION( idTarget, idTarget_SetFov ) - EVENT( EV_Activate, idTarget_SetFov::Event_Activate ) -END_CLASS - - -/* -================ -idTarget_SetFov::Save -================ -*/ -void idTarget_SetFov::Save( idSaveGame *savefile ) const { - - savefile->WriteFloat( fovSetting.GetStartTime() ); - savefile->WriteFloat( fovSetting.GetDuration() ); - savefile->WriteFloat( fovSetting.GetStartValue() ); - savefile->WriteFloat( fovSetting.GetEndValue() ); -} - -/* -================ -idTarget_SetFov::Restore -================ -*/ -void idTarget_SetFov::Restore( idRestoreGame *savefile ) { - float setting; - - savefile->ReadFloat( setting ); - fovSetting.SetStartTime( setting ); - savefile->ReadFloat( setting ); - fovSetting.SetDuration( setting ); - savefile->ReadFloat( setting ); - fovSetting.SetStartValue( setting ); - savefile->ReadFloat( setting ); - fovSetting.SetEndValue( setting ); - - fovSetting.GetCurrentValue( gameLocal.time ); -} - -/* -================ -idTarget_SetFov::Event_Activate -================ -*/ -void idTarget_SetFov::Event_Activate( idEntity *activator ) { - // always allow during cinematics - cinematic = true; - - idPlayer *player = gameLocal.GetLocalPlayer(); - fovSetting.Init( gameLocal.time, SEC2MS( spawnArgs.GetFloat( "time" ) ), player ? player->DefaultFov() : g_fov.GetFloat(), spawnArgs.GetFloat( "fov" ) ); - BecomeActive( TH_THINK ); -} - -/* -================ -idTarget_SetFov::Think -================ -*/ -void idTarget_SetFov::Think( void ) { - if ( thinkFlags & TH_THINK ) { - idPlayer *player = gameLocal.GetLocalPlayer(); - player->SetInfluenceFov( fovSetting.GetCurrentValue( gameLocal.time ) ); - if ( fovSetting.IsDone( gameLocal.time ) ) { - player->SetInfluenceFov( 0.0f ); - BecomeInactive( TH_THINK ); - } - } else { - BecomeInactive( TH_ALL ); - } -} - - -/* -=============================================================================== - -idTarget_SetPrimaryObjective - -=============================================================================== -*/ - -CLASS_DECLARATION( idTarget, idTarget_SetPrimaryObjective ) - EVENT( EV_Activate, idTarget_SetPrimaryObjective::Event_Activate ) -END_CLASS - -/* -================ -idTarget_SetPrimaryObjective::Event_Activate -================ -*/ -void idTarget_SetPrimaryObjective::Event_Activate( idEntity *activator ) { - idPlayer *player = gameLocal.GetLocalPlayer(); - if ( player && player->objectiveSystem ) { - player->objectiveSystem->SetStateString( "missionobjective", spawnArgs.GetString( "text", common->GetLanguageDict()->GetString( "#str_04253" ) ) ); - } -} - -/* -=============================================================================== - -idTarget_LockDoor - -=============================================================================== -*/ - -CLASS_DECLARATION( idTarget, idTarget_LockDoor ) - EVENT( EV_Activate, idTarget_LockDoor::Event_Activate ) -END_CLASS - -/* -================ -idTarget_LockDoor::Event_Activate -================ -*/ -void idTarget_LockDoor::Event_Activate( idEntity *activator ) { - int i; - idEntity *ent; - int lock; - - lock = spawnArgs.GetInt( "locked", "1" ); - for( i = 0; i < targets.Num(); i++ ) { - ent = targets[ i ].GetEntity(); - if ( ent && ent->IsType( idDoor::Type ) ) { - if ( static_cast( ent )->IsLocked() ) { - static_cast( ent )->Lock( 0 ); - } else { - static_cast( ent )->Lock( lock ); - } - } - } -} - -/* -=============================================================================== - -idTarget_CallObjectFunction - -=============================================================================== -*/ - -CLASS_DECLARATION( idTarget, idTarget_CallObjectFunction ) - EVENT( EV_Activate, idTarget_CallObjectFunction::Event_Activate ) -END_CLASS - -/* -================ -idTarget_CallObjectFunction::Event_Activate -================ -*/ -void idTarget_CallObjectFunction::Event_Activate( idEntity *activator ) { - int i; - idEntity *ent; - const function_t *func; - const char *funcName; - idThread *thread; - - funcName = spawnArgs.GetString( "call" ); - for( i = 0; i < targets.Num(); i++ ) { - ent = targets[ i ].GetEntity(); - if ( ent && ent->scriptObject.HasObject() ) { - func = ent->scriptObject.GetFunction( funcName ); - if ( !func ) { - gameLocal.Error( "Function '%s' not found on entity '%s' for function call from '%s'", funcName, ent->name.c_str(), name.c_str() ); - } - if ( func->type->NumParameters() != 1 ) { - gameLocal.Error( "Function '%s' on entity '%s' has the wrong number of parameters for function call from '%s'", funcName, ent->name.c_str(), name.c_str() ); - } - if ( !ent->scriptObject.GetTypeDef()->Inherits( func->type->GetParmType( 0 ) ) ) { - gameLocal.Error( "Function '%s' on entity '%s' is the wrong type for function call from '%s'", funcName, ent->name.c_str(), name.c_str() ); - } - // create a thread and call the function - thread = new idThread(); - thread->CallFunction( ent, func, true ); - thread->Start(); - } - } -} - - -/* -=============================================================================== - -idTarget_EnableLevelWeapons - -=============================================================================== -*/ - -CLASS_DECLARATION( idTarget, idTarget_EnableLevelWeapons ) - EVENT( EV_Activate, idTarget_EnableLevelWeapons::Event_Activate ) -END_CLASS - -/* -================ -idTarget_EnableLevelWeapons::Event_Activate -================ -*/ -void idTarget_EnableLevelWeapons::Event_Activate( idEntity *activator ) { - int i; - const char *weap; - - gameLocal.world->spawnArgs.SetBool( "no_Weapons", spawnArgs.GetBool( "disable" ) ); - - if ( spawnArgs.GetBool( "disable" ) ) { - for( i = 0; i < gameLocal.numClients; i++ ) { - if ( gameLocal.entities[ i ] ) { - gameLocal.entities[ i ]->ProcessEvent( &EV_Player_DisableWeapon ); - } - } - } else { - weap = spawnArgs.GetString( "weapon" ); - for( i = 0; i < gameLocal.numClients; i++ ) { - if ( gameLocal.entities[ i ] ) { - gameLocal.entities[ i ]->ProcessEvent( &EV_Player_EnableWeapon ); - if ( weap && weap[ 0 ] ) { - gameLocal.entities[ i ]->PostEventSec( &EV_Player_SelectWeapon, 0.5f, weap ); - } - } - } - } -} - -/* -=============================================================================== - -idTarget_Tip - -=============================================================================== -*/ - -const idEventDef EV_TipOff( "" ); -extern const idEventDef EV_GetPlayerPos( "" ); - -CLASS_DECLARATION( idTarget, idTarget_Tip ) - EVENT( EV_Activate, idTarget_Tip::Event_Activate ) - EVENT( EV_TipOff, idTarget_Tip::Event_TipOff ) - EVENT( EV_GetPlayerPos, idTarget_Tip::Event_GetPlayerPos ) -END_CLASS - - -/* -================ -idTarget_Tip::idTarget_Tip -================ -*/ -idTarget_Tip::idTarget_Tip( void ) { - playerPos.Zero(); -} - -/* -================ -idTarget_Tip::Spawn -================ -*/ -void idTarget_Tip::Spawn( void ) { -} - -/* -================ -idTarget_Tip::Save -================ -*/ -void idTarget_Tip::Save( idSaveGame *savefile ) const { - savefile->WriteVec3( playerPos ); -} - -/* -================ -idTarget_Tip::Restore -================ -*/ -void idTarget_Tip::Restore( idRestoreGame *savefile ) { - savefile->ReadVec3( playerPos ); -} - -/* -================ -idTarget_Tip::Event_Activate -================ -*/ -void idTarget_Tip::Event_GetPlayerPos( void ) { - idPlayer *player = gameLocal.GetLocalPlayer(); - if ( player ) { - playerPos = player->GetPhysics()->GetOrigin(); - PostEventMS( &EV_TipOff, 100 ); - } -} - -/* -================ -idTarget_Tip::Event_Activate -================ -*/ -void idTarget_Tip::Event_Activate( idEntity *activator ) { - idPlayer *player = gameLocal.GetLocalPlayer(); - if ( player ) { - if ( player->IsTipVisible() ) { - PostEventSec( &EV_Activate, 5.1f, activator ); - return; - } - player->ShowTip( spawnArgs.GetString( "text_title" ), spawnArgs.GetString( "text_tip" ), false ); - PostEventMS( &EV_GetPlayerPos, 2000 ); - } -} - -/* -================ -idTarget_Tip::Event_TipOff -================ -*/ -void idTarget_Tip::Event_TipOff( void ) { - idPlayer *player = gameLocal.GetLocalPlayer(); - if ( player ) { - idVec3 v = player->GetPhysics()->GetOrigin() - playerPos; - if ( v.Length() > 96.0f ) { - player->HideTip(); - } else { - PostEventMS( &EV_TipOff, 100 ); - } - } -} - - -/* -=============================================================================== - -idTarget_GiveSecurity - -=============================================================================== -*/ - -CLASS_DECLARATION( idTarget, idTarget_GiveSecurity ) -EVENT( EV_Activate, idTarget_GiveSecurity::Event_Activate ) -END_CLASS - -/* -================ -idTarget_GiveEmail::Event_Activate -================ -*/ -void idTarget_GiveSecurity::Event_Activate( idEntity *activator ) { - idPlayer *player = gameLocal.GetLocalPlayer(); - if ( player ) { - player->GiveSecurity( spawnArgs.GetString( "text_security" ) ); - } -} - - -/* -=============================================================================== - -idTarget_RemoveWeapons - -=============================================================================== -*/ - -CLASS_DECLARATION( idTarget, idTarget_RemoveWeapons ) -EVENT( EV_Activate, idTarget_RemoveWeapons::Event_Activate ) -END_CLASS - -/* -================ -idTarget_RemoveWeapons::Event_Activate -================ -*/ -void idTarget_RemoveWeapons::Event_Activate( idEntity *activator ) { - for( int i = 0; i < gameLocal.numClients; i++ ) { - if ( gameLocal.entities[ i ] ) { - idPlayer *player = static_cast< idPlayer* >( gameLocal.entities[i] ); - const idKeyValue *kv = spawnArgs.MatchPrefix( "weapon", NULL ); - while ( kv ) { - player->RemoveWeapon( kv->GetValue() ); - kv = spawnArgs.MatchPrefix( "weapon", kv ); - } - player->SelectWeapon( player->weapon_fists, true ); - } - } -} - - -/* -=============================================================================== - -idTarget_LevelTrigger - -=============================================================================== -*/ - -CLASS_DECLARATION( idTarget, idTarget_LevelTrigger ) -EVENT( EV_Activate, idTarget_LevelTrigger::Event_Activate ) -END_CLASS - -/* -================ -idTarget_LevelTrigger::Event_Activate -================ -*/ -void idTarget_LevelTrigger::Event_Activate( idEntity *activator ) { - for( int i = 0; i < gameLocal.numClients; i++ ) { - if ( gameLocal.entities[ i ] ) { - idPlayer *player = static_cast< idPlayer* >( gameLocal.entities[i] ); - player->SetLevelTrigger( spawnArgs.GetString( "levelName" ), spawnArgs.GetString( "triggerName" ) ); - } - } -} - - -/* -=============================================================================== - -idTarget_EnableStamina - -=============================================================================== -*/ - -CLASS_DECLARATION( idTarget, idTarget_EnableStamina ) -EVENT( EV_Activate, idTarget_EnableStamina::Event_Activate ) -END_CLASS - -/* -================ -idTarget_EnableStamina::Event_Activate -================ -*/ -void idTarget_EnableStamina::Event_Activate( idEntity *activator ) { - for( int i = 0; i < gameLocal.numClients; i++ ) { - if ( gameLocal.entities[ i ] ) { - idPlayer *player = static_cast< idPlayer* >( gameLocal.entities[i] ); - if ( spawnArgs.GetBool( "enable" ) ) { - pm_stamina.SetFloat( player->spawnArgs.GetFloat( "pm_stamina" ) ); - } else { - pm_stamina.SetFloat( 0.0f ); - } - } - } -} - -/* -=============================================================================== - -idTarget_FadeSoundClass - -=============================================================================== -*/ - -const idEventDef EV_RestoreVolume( "" ); -CLASS_DECLARATION( idTarget, idTarget_FadeSoundClass ) -EVENT( EV_Activate, idTarget_FadeSoundClass::Event_Activate ) -EVENT( EV_RestoreVolume, idTarget_FadeSoundClass::Event_RestoreVolume ) -END_CLASS - -/* -================ -idTarget_FadeSoundClass::Event_Activate -================ -*/ -void idTarget_FadeSoundClass::Event_Activate( idEntity *activator ) { - float fadeTime = spawnArgs.GetFloat( "fadeTime" ); - float fadeDB = spawnArgs.GetFloat( "fadeDB" ); - float fadeDuration = spawnArgs.GetFloat( "fadeDuration" ); - int fadeClass = spawnArgs.GetInt( "fadeClass" ); - // start any sound fading now - if ( fadeTime ) { - gameSoundWorld->FadeSoundClasses( fadeClass, spawnArgs.GetBool( "fadeIn" ) ? fadeDB : 0.0f - fadeDB, fadeTime ); - if ( fadeDuration ) { - PostEventSec( &EV_RestoreVolume, fadeDuration ); - } - } -} - -/* -================ -idTarget_FadeSoundClass::Event_RestoreVolume -================ -*/ -void idTarget_FadeSoundClass::Event_RestoreVolume() { - float fadeTime = spawnArgs.GetFloat( "fadeTime" ); - float fadeDB = spawnArgs.GetFloat( "fadeDB" ); - // restore volume - gameSoundWorld->FadeSoundClasses( 0, fadeDB, fadeTime ); -} diff --git a/d3xp/Target.h b/d3xp/Target.h deleted file mode 100644 index 9c2c0a80..00000000 --- a/d3xp/Target.h +++ /dev/null @@ -1,581 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __GAME_TARGET_H__ -#define __GAME_TARGET_H__ - -#include "idlib/math/Interpolate.h" - -#include "Entity.h" - -/* -=============================================================================== - -idTarget - -=============================================================================== -*/ - -class idTarget : public idEntity { -public: - CLASS_PROTOTYPE( idTarget ); -}; - - -/* -=============================================================================== - -idTarget_Remove - -=============================================================================== -*/ - -class idTarget_Remove : public idTarget { -public: - CLASS_PROTOTYPE( idTarget_Remove ); - -private: - void Event_Activate( idEntity *activator ); -}; - - -/* -=============================================================================== - -idTarget_Show - -=============================================================================== -*/ - -class idTarget_Show : public idTarget { -public: - CLASS_PROTOTYPE( idTarget_Show ); - -private: - void Event_Activate( idEntity *activator ); -}; - - -/* -=============================================================================== - -idTarget_Damage - -=============================================================================== -*/ - -class idTarget_Damage : public idTarget { -public: - CLASS_PROTOTYPE( idTarget_Damage ); - -private: - void Event_Activate( idEntity *activator ); -}; - - -/* -=============================================================================== - -idTarget_SessionCommand - -=============================================================================== -*/ - -class idTarget_SessionCommand : public idTarget { -public: - CLASS_PROTOTYPE( idTarget_SessionCommand ); - -private: - void Event_Activate( idEntity *activator ); -}; - - -/* -=============================================================================== - -idTarget_EndLevel - -=============================================================================== -*/ - -class idTarget_EndLevel : public idTarget { -public: - CLASS_PROTOTYPE( idTarget_EndLevel ); - -private: - void Event_Activate( idEntity *activator ); - -}; - - -/* -=============================================================================== - -idTarget_WaitForButton - -=============================================================================== -*/ - -class idTarget_WaitForButton : public idTarget { -public: - CLASS_PROTOTYPE( idTarget_WaitForButton ); - - void Think( void ); - -private: - void Event_Activate( idEntity *activator ); -}; - -/* -=============================================================================== - -idTarget_SetGlobalShaderTime - -=============================================================================== -*/ - -class idTarget_SetGlobalShaderTime : public idTarget { -public: - CLASS_PROTOTYPE( idTarget_SetGlobalShaderTime ); - -private: - void Event_Activate( idEntity *activator ); -}; - - -/* -=============================================================================== - -idTarget_SetShaderParm - -=============================================================================== -*/ - -class idTarget_SetShaderParm : public idTarget { -public: - CLASS_PROTOTYPE( idTarget_SetShaderParm ); - -private: - void Event_Activate( idEntity *activator ); -}; - - -/* -=============================================================================== - -idTarget_SetShaderTime - -=============================================================================== -*/ - -class idTarget_SetShaderTime : public idTarget { -public: - CLASS_PROTOTYPE( idTarget_SetShaderTime ); - -private: - void Event_Activate( idEntity *activator ); -}; - -/* -=============================================================================== - -idTarget_FadeEntity - -=============================================================================== -*/ - -class idTarget_FadeEntity : public idTarget { -public: - CLASS_PROTOTYPE( idTarget_FadeEntity ); - - idTarget_FadeEntity( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void Think( void ); - -private: - idVec4 fadeFrom; - int fadeStart; - int fadeEnd; - - void Event_Activate( idEntity *activator ); -}; - -/* -=============================================================================== - -idTarget_LightFadeIn - -=============================================================================== -*/ - -class idTarget_LightFadeIn : public idTarget { -public: - CLASS_PROTOTYPE( idTarget_LightFadeIn ); - -private: - void Event_Activate( idEntity *activator ); -}; - -/* -=============================================================================== - -idTarget_LightFadeOut - -=============================================================================== -*/ - -class idTarget_LightFadeOut : public idTarget { -public: - CLASS_PROTOTYPE( idTarget_LightFadeOut ); - -private: - void Event_Activate( idEntity *activator ); -}; - -/* -=============================================================================== - -idTarget_Give - -=============================================================================== -*/ - -class idTarget_Give : public idTarget { -public: - CLASS_PROTOTYPE( idTarget_Give ); - - void Spawn( void ); - -private: - void Event_Activate( idEntity *activator ); -}; - - -/* -=============================================================================== - -idTarget_GiveEmail - -=============================================================================== -*/ - -class idTarget_GiveEmail : public idTarget { -public: - CLASS_PROTOTYPE( idTarget_GiveEmail ); - - void Spawn( void ); - -private: - void Event_Activate( idEntity *activator ); -}; - -/* -=============================================================================== - -idTarget_SetModel - -=============================================================================== -*/ - -class idTarget_SetModel : public idTarget { -public: - CLASS_PROTOTYPE( idTarget_SetModel ); - - void Spawn( void ); - -private: - void Event_Activate( idEntity *activator ); -}; - - -/* -=============================================================================== - -idTarget_SetInfluence - -=============================================================================== -*/ - -#ifdef _D3XP -typedef struct SavedGui_s { - SavedGui_s() {memset(gui, 0, sizeof(idUserInterface*)*MAX_RENDERENTITY_GUI); }; - idUserInterface* gui[MAX_RENDERENTITY_GUI]; -} SavedGui_t; -#endif - -class idTarget_SetInfluence : public idTarget { -public: - CLASS_PROTOTYPE( idTarget_SetInfluence ); - - idTarget_SetInfluence( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void Spawn( void ); - -private: - void Event_Activate( idEntity *activator ); - void Event_RestoreInfluence(); - void Event_GatherEntities(); - void Event_Flash( float flash, int out ); - void Event_ClearFlash( float flash ); - void Think( void ); - - idList lightList; - idList guiList; - idList soundList; - idList genericList; - float flashIn; - float flashOut; - float delay; - idStr flashInSound; - idStr flashOutSound; - idEntity * switchToCamera; - idInterpolatefovSetting; - bool soundFaded; - bool restoreOnTrigger; - -#ifdef _D3XP - idList savedGuiList; -#endif -}; - - -/* -=============================================================================== - -idTarget_SetKeyVal - -=============================================================================== -*/ - -class idTarget_SetKeyVal : public idTarget { -public: - CLASS_PROTOTYPE( idTarget_SetKeyVal ); - -private: - void Event_Activate( idEntity *activator ); -}; - - -/* -=============================================================================== - -idTarget_SetFov - -=============================================================================== -*/ - -class idTarget_SetFov : public idTarget { -public: - CLASS_PROTOTYPE( idTarget_SetFov ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void Think( void ); - -private: - idInterpolate fovSetting; - - void Event_Activate( idEntity *activator ); -}; - - -/* -=============================================================================== - -idTarget_SetPrimaryObjective - -=============================================================================== -*/ - -class idTarget_SetPrimaryObjective : public idTarget { -public: - CLASS_PROTOTYPE( idTarget_SetPrimaryObjective ); - -private: - void Event_Activate( idEntity *activator ); -}; - -/* -=============================================================================== - -idTarget_LockDoor - -=============================================================================== -*/ - -class idTarget_LockDoor: public idTarget { -public: - CLASS_PROTOTYPE( idTarget_LockDoor ); - -private: - void Event_Activate( idEntity *activator ); -}; - -/* -=============================================================================== - -idTarget_CallObjectFunction - -=============================================================================== -*/ - -class idTarget_CallObjectFunction : public idTarget { -public: - CLASS_PROTOTYPE( idTarget_CallObjectFunction ); - -private: - void Event_Activate( idEntity *activator ); -}; - - -/* -=============================================================================== - -idTarget_LockDoor - -=============================================================================== -*/ - -class idTarget_EnableLevelWeapons : public idTarget { -public: - CLASS_PROTOTYPE( idTarget_EnableLevelWeapons ); - -private: - void Event_Activate( idEntity *activator ); -}; - - -/* -=============================================================================== - -idTarget_Tip - -=============================================================================== -*/ - -class idTarget_Tip : public idTarget { -public: - CLASS_PROTOTYPE( idTarget_Tip ); - - idTarget_Tip( void ); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - -private: - idVec3 playerPos; - - void Event_Activate( idEntity *activator ); - void Event_TipOff( void ); - void Event_GetPlayerPos( void ); -}; - -/* -=============================================================================== - -idTarget_GiveSecurity - -=============================================================================== -*/ -class idTarget_GiveSecurity : public idTarget { -public: - CLASS_PROTOTYPE( idTarget_GiveSecurity ); -private: - void Event_Activate( idEntity *activator ); -}; - - -/* -=============================================================================== - -idTarget_RemoveWeapons - -=============================================================================== -*/ -class idTarget_RemoveWeapons : public idTarget { -public: - CLASS_PROTOTYPE( idTarget_RemoveWeapons ); -private: - void Event_Activate( idEntity *activator ); -}; - - -/* -=============================================================================== - -idTarget_LevelTrigger - -=============================================================================== -*/ -class idTarget_LevelTrigger : public idTarget { -public: - CLASS_PROTOTYPE( idTarget_LevelTrigger ); -private: - void Event_Activate( idEntity *activator ); -}; - -/* -=============================================================================== - -idTarget_EnableStamina - -=============================================================================== -*/ -class idTarget_EnableStamina : public idTarget { -public: - CLASS_PROTOTYPE( idTarget_EnableStamina ); -private: - void Event_Activate( idEntity *activator ); -}; - -/* -=============================================================================== - -idTarget_FadeSoundClass - -=============================================================================== -*/ -class idTarget_FadeSoundClass : public idTarget { -public: - CLASS_PROTOTYPE( idTarget_FadeSoundClass ); -private: - void Event_Activate( idEntity *activator ); - void Event_RestoreVolume(); -}; - - -#endif /* !__GAME_TARGET_H__ */ diff --git a/d3xp/Trigger.cpp b/d3xp/Trigger.cpp deleted file mode 100644 index c3943440..00000000 --- a/d3xp/Trigger.cpp +++ /dev/null @@ -1,1326 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "script/Script_Thread.h" -#include "Player.h" - -#include "Trigger.h" - -/* -=============================================================================== - - idTrigger - -=============================================================================== -*/ - -const idEventDef EV_Enable( "enable", NULL ); -const idEventDef EV_Disable( "disable", NULL ); - -CLASS_DECLARATION( idEntity, idTrigger ) - EVENT( EV_Enable, idTrigger::Event_Enable ) - EVENT( EV_Disable, idTrigger::Event_Disable ) -END_CLASS - -/* -================ -idTrigger::DrawDebugInfo -================ -*/ -void idTrigger::DrawDebugInfo( void ) { - idMat3 axis = gameLocal.GetLocalPlayer()->viewAngles.ToMat3(); - idVec3 up = axis[ 2 ] * 5.0f; - idBounds viewTextBounds( gameLocal.GetLocalPlayer()->GetPhysics()->GetOrigin() ); - idBounds viewBounds( gameLocal.GetLocalPlayer()->GetPhysics()->GetOrigin() ); - idBounds box( idVec3( -4.0f, -4.0f, -4.0f ), idVec3( 4.0f, 4.0f, 4.0f ) ); - idEntity *ent; - idEntity *target; - int i; - bool show; - const function_t *func; - - viewTextBounds.ExpandSelf( 128.0f ); - viewBounds.ExpandSelf( 512.0f ); - for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) { - if ( ent->GetPhysics()->GetContents() & ( CONTENTS_TRIGGER | CONTENTS_FLASHLIGHT_TRIGGER ) ) { - show = viewBounds.IntersectsBounds( ent->GetPhysics()->GetAbsBounds() ); - if ( !show ) { - for( i = 0; i < ent->targets.Num(); i++ ) { - target = ent->targets[ i ].GetEntity(); - if ( target && viewBounds.IntersectsBounds( target->GetPhysics()->GetAbsBounds() ) ) { - show = true; - break; - } - } - } - - if ( !show ) { - continue; - } - - gameRenderWorld->DebugBounds( colorOrange, ent->GetPhysics()->GetAbsBounds() ); - if ( viewTextBounds.IntersectsBounds( ent->GetPhysics()->GetAbsBounds() ) ) { - gameRenderWorld->DrawText( ent->name.c_str(), ent->GetPhysics()->GetAbsBounds().GetCenter(), 0.1f, colorWhite, axis, 1 ); - gameRenderWorld->DrawText( ent->GetEntityDefName(), ent->GetPhysics()->GetAbsBounds().GetCenter() + up, 0.1f, colorWhite, axis, 1 ); - if ( ent->IsType( idTrigger::Type ) ) { - func = static_cast( ent )->GetScriptFunction(); - } else { - func = NULL; - } - - if ( func ) { - gameRenderWorld->DrawText( va( "call script '%s'", func->Name() ), ent->GetPhysics()->GetAbsBounds().GetCenter() - up, 0.1f, colorWhite, axis, 1 ); - } - } - - for( i = 0; i < ent->targets.Num(); i++ ) { - target = ent->targets[ i ].GetEntity(); - if ( target ) { - gameRenderWorld->DebugArrow( colorYellow, ent->GetPhysics()->GetAbsBounds().GetCenter(), target->GetPhysics()->GetOrigin(), 10, 0 ); - gameRenderWorld->DebugBounds( colorGreen, box, target->GetPhysics()->GetOrigin() ); - if ( viewTextBounds.IntersectsBounds( target->GetPhysics()->GetAbsBounds() ) ) { - gameRenderWorld->DrawText( target->name.c_str(), target->GetPhysics()->GetAbsBounds().GetCenter(), 0.1f, colorWhite, axis, 1 ); - } - } - } - } - } -} - -/* -================ -idTrigger::Enable -================ -*/ -void idTrigger::Enable( void ) { - GetPhysics()->SetContents( CONTENTS_TRIGGER ); - GetPhysics()->EnableClip(); -} - -/* -================ -idTrigger::Disable -================ -*/ -void idTrigger::Disable( void ) { - // we may be relinked if we're bound to another object, so clear the contents as well - GetPhysics()->SetContents( 0 ); - GetPhysics()->DisableClip(); -} - -/* -================ -idTrigger::CallScript -================ -*/ -void idTrigger::CallScript( void ) const { - idThread *thread; - - if ( scriptFunction ) { - thread = new idThread( scriptFunction ); - thread->DelayedStart( 0 ); - } -} - -/* -================ -idTrigger::GetScriptFunction -================ -*/ -const function_t *idTrigger::GetScriptFunction( void ) const { - return scriptFunction; -} - -/* -================ -idTrigger::Save -================ -*/ -void idTrigger::Save( idSaveGame *savefile ) const { - if ( scriptFunction ) { - savefile->WriteString( scriptFunction->Name() ); - } else { - savefile->WriteString( "" ); - } -} - -/* -================ -idTrigger::Restore -================ -*/ -void idTrigger::Restore( idRestoreGame *savefile ) { - idStr funcname; - savefile->ReadString( funcname ); - if ( funcname.Length() ) { - scriptFunction = gameLocal.program.FindFunction( funcname ); - if ( scriptFunction == NULL ) { - gameLocal.Warning( "idTrigger_Multi '%s' at (%s) calls unknown function '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), funcname.c_str() ); - } - } else { - scriptFunction = NULL; - } -} - -/* -================ -idTrigger::Event_Enable -================ -*/ -void idTrigger::Event_Enable( void ) { - Enable(); -} - -/* -================ -idTrigger::Event_Disable -================ -*/ -void idTrigger::Event_Disable( void ) { - Disable(); -} - -/* -================ -idTrigger::idTrigger -================ -*/ -idTrigger::idTrigger() { - scriptFunction = NULL; -} - -/* -================ -idTrigger::Spawn -================ -*/ -void idTrigger::Spawn( void ) { - GetPhysics()->SetContents( CONTENTS_TRIGGER ); - - idStr funcname = spawnArgs.GetString( "call", "" ); - if ( funcname.Length() ) { - scriptFunction = gameLocal.program.FindFunction( funcname ); - if ( scriptFunction == NULL ) { - gameLocal.Warning( "trigger '%s' at (%s) calls unknown function '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), funcname.c_str() ); - } - } else { - scriptFunction = NULL; - } -} - - -/* -=============================================================================== - - idTrigger_Multi - -=============================================================================== -*/ - -const idEventDef EV_TriggerAction( "", "e" ); - -CLASS_DECLARATION( idTrigger, idTrigger_Multi ) - EVENT( EV_Touch, idTrigger_Multi::Event_Touch ) - EVENT( EV_Activate, idTrigger_Multi::Event_Trigger ) - EVENT( EV_TriggerAction, idTrigger_Multi::Event_TriggerAction ) -END_CLASS - - -/* -================ -idTrigger_Multi::idTrigger_Multi -================ -*/ -idTrigger_Multi::idTrigger_Multi( void ) { - wait = 0.0f; - random = 0.0f; - delay = 0.0f; - random_delay = 0.0f; - nextTriggerTime = 0; - removeItem = 0; - touchClient = false; - touchOther = false; - triggerFirst = false; - triggerWithSelf = false; -} - -/* -================ -idTrigger_Multi::Save -================ -*/ -void idTrigger_Multi::Save( idSaveGame *savefile ) const { - savefile->WriteFloat( wait ); - savefile->WriteFloat( random ); - savefile->WriteFloat( delay ); - savefile->WriteFloat( random_delay ); - savefile->WriteInt( nextTriggerTime ); - savefile->WriteString( requires ); - savefile->WriteInt( removeItem ); - savefile->WriteBool( touchClient ); - savefile->WriteBool( touchOther ); - savefile->WriteBool( triggerFirst ); - savefile->WriteBool( triggerWithSelf ); -} - -/* -================ -idTrigger_Multi::Restore -================ -*/ -void idTrigger_Multi::Restore( idRestoreGame *savefile ) { - savefile->ReadFloat( wait ); - savefile->ReadFloat( random ); - savefile->ReadFloat( delay ); - savefile->ReadFloat( random_delay ); - savefile->ReadInt( nextTriggerTime ); - savefile->ReadString( requires ); - savefile->ReadInt( removeItem ); - savefile->ReadBool( touchClient ); - savefile->ReadBool( touchOther ); - savefile->ReadBool( triggerFirst ); - savefile->ReadBool( triggerWithSelf ); -} - -/* -================ -idTrigger_Multi::Spawn - -"wait" : Seconds between triggerings, 0.5 default, -1 = one time only. -"call" : Script function to call when triggered -"random" wait variance, default is 0 -Variable sized repeatable trigger. Must be targeted at one or more entities. -so, the basic time between firing is a random time between -(wait - random) and (wait + random) -================ -*/ -void idTrigger_Multi::Spawn( void ) { - spawnArgs.GetFloat( "wait", "0.5", wait ); - spawnArgs.GetFloat( "random", "0", random ); - spawnArgs.GetFloat( "delay", "0", delay ); - spawnArgs.GetFloat( "random_delay", "0", random_delay ); - - if ( random && ( random >= wait ) && ( wait >= 0 ) ) { - random = wait - 1; - gameLocal.Warning( "idTrigger_Multi '%s' at (%s) has random >= wait", name.c_str(), GetPhysics()->GetOrigin().ToString(0) ); - } - - if ( random_delay && ( random_delay >= delay ) && ( delay >= 0 ) ) { - random_delay = delay - 1; - gameLocal.Warning( "idTrigger_Multi '%s' at (%s) has random_delay >= delay", name.c_str(), GetPhysics()->GetOrigin().ToString(0) ); - } - - spawnArgs.GetString( "requires", "", requires ); - spawnArgs.GetInt( "removeItem", "0", removeItem ); - spawnArgs.GetBool( "triggerFirst", "0", triggerFirst ); - spawnArgs.GetBool( "triggerWithSelf", "0", triggerWithSelf ); - - if ( spawnArgs.GetBool( "anyTouch" ) ) { - touchClient = true; - touchOther = true; - } else if ( spawnArgs.GetBool( "noTouch" ) ) { - touchClient = false; - touchOther = false; - } else if ( spawnArgs.GetBool( "noClient" ) ) { - touchClient = false; - touchOther = true; - } else { - touchClient = true; - touchOther = false; - } - - nextTriggerTime = 0; - - if ( spawnArgs.GetBool( "flashlight_trigger" ) ) { - GetPhysics()->SetContents( CONTENTS_FLASHLIGHT_TRIGGER ); - } else { - GetPhysics()->SetContents( CONTENTS_TRIGGER ); - } -} - -/* -================ -idTrigger_Multi::CheckFacing -================ -*/ -bool idTrigger_Multi::CheckFacing( idEntity *activator ) { - if ( spawnArgs.GetBool( "facing" ) ) { - if ( !activator->IsType( idPlayer::Type ) ) { - return true; - } - idPlayer *player = static_cast< idPlayer* >( activator ); - float dot = player->viewAngles.ToForward() * GetPhysics()->GetAxis()[0]; - float angle = RAD2DEG( idMath::ACos( dot ) ); - if ( angle > spawnArgs.GetFloat( "angleLimit", "30" ) ) { - return false; - } - } - return true; -} - - -/* -================ -idTrigger_Multi::TriggerAction -================ -*/ -void idTrigger_Multi::TriggerAction( idEntity *activator ) { - ActivateTargets( triggerWithSelf ? this : activator ); - CallScript(); - - if ( wait >= 0 ) { - nextTriggerTime = gameLocal.time + SEC2MS( wait + random * gameLocal.random.CRandomFloat() ); - } else { - // we can't just remove (this) here, because this is a touch function - // called while looping through area links... -#ifdef _D3XP - // If the player spawned inside the trigger, the player Spawn function called Think directly, - // allowing for multiple triggers on a trigger_once. Increasing the nextTriggerTime prevents it. - nextTriggerTime = gameLocal.time + 99999; -#else - nextTriggerTime = gameLocal.time + 1; -#endif - PostEventMS( &EV_Remove, 0 ); - } -} - -/* -================ -idTrigger_Multi::Event_TriggerAction -================ -*/ -void idTrigger_Multi::Event_TriggerAction( idEntity *activator ) { - TriggerAction( activator ); -} - -/* -================ -idTrigger_Multi::Event_Trigger - -the trigger was just activated -activated should be the entity that originated the activation sequence (ie. the original target) -activator should be set to the activator so it can be held through a delay -so wait for the delay time before firing -================ -*/ -void idTrigger_Multi::Event_Trigger( idEntity *activator ) { - if ( nextTriggerTime > gameLocal.time ) { - // can't retrigger until the wait is over - return; - } - - // see if this trigger requires an item - if ( !gameLocal.RequirementMet( activator, requires, removeItem ) ) { - return; - } - - if ( !CheckFacing( activator ) ) { - return; - } - - if ( triggerFirst ) { - triggerFirst = false; - return; - } - - // don't allow it to trigger twice in a single frame - nextTriggerTime = gameLocal.time + 1; - - if ( delay > 0 ) { - // don't allow it to trigger again until our delay has passed - nextTriggerTime += SEC2MS( delay + random_delay * gameLocal.random.CRandomFloat() ); - PostEventSec( &EV_TriggerAction, delay, activator ); - } else { - TriggerAction( activator ); - } -} - -/* -================ -idTrigger_Multi::Event_Touch -================ -*/ -void idTrigger_Multi::Event_Touch( idEntity *other, trace_t *trace ) { - if( triggerFirst ) { - return; - } - - bool player = other->IsType( idPlayer::Type ); - if ( player ) { - if ( !touchClient ) { - return; - } - if ( static_cast< idPlayer * >( other )->spectating ) { - return; - } - } else if ( !touchOther ) { - return; - } - - if ( nextTriggerTime > gameLocal.time ) { - // can't retrigger until the wait is over - return; - } - - // see if this trigger requires an item - if ( !gameLocal.RequirementMet( other, requires, removeItem ) ) { - return; - } - - if ( !CheckFacing( other ) ) { - return; - } - - if ( spawnArgs.GetBool( "toggleTriggerFirst" ) ) { - triggerFirst = true; - } - - nextTriggerTime = gameLocal.time + 1; - if ( delay > 0 ) { - // don't allow it to trigger again until our delay has passed - nextTriggerTime += SEC2MS( delay + random_delay * gameLocal.random.CRandomFloat() ); - PostEventSec( &EV_TriggerAction, delay, other ); - } else { - TriggerAction( other ); - } -} - -/* -=============================================================================== - - idTrigger_EntityName - -=============================================================================== -*/ - -CLASS_DECLARATION( idTrigger, idTrigger_EntityName ) - EVENT( EV_Touch, idTrigger_EntityName::Event_Touch ) - EVENT( EV_Activate, idTrigger_EntityName::Event_Trigger ) - EVENT( EV_TriggerAction, idTrigger_EntityName::Event_TriggerAction ) -END_CLASS - -/* -================ -idTrigger_EntityName::idTrigger_EntityName -================ -*/ -idTrigger_EntityName::idTrigger_EntityName( void ) { - wait = 0.0f; - random = 0.0f; - delay = 0.0f; - random_delay = 0.0f; - nextTriggerTime = 0; - triggerFirst = false; -} - -/* -================ -idTrigger_EntityName::Save -================ -*/ -void idTrigger_EntityName::Save( idSaveGame *savefile ) const { - savefile->WriteFloat( wait ); - savefile->WriteFloat( random ); - savefile->WriteFloat( delay ); - savefile->WriteFloat( random_delay ); - savefile->WriteInt( nextTriggerTime ); - savefile->WriteBool( triggerFirst ); - savefile->WriteString( entityName ); -} - -/* -================ -idTrigger_EntityName::Restore -================ -*/ -void idTrigger_EntityName::Restore( idRestoreGame *savefile ) { - savefile->ReadFloat( wait ); - savefile->ReadFloat( random ); - savefile->ReadFloat( delay ); - savefile->ReadFloat( random_delay ); - savefile->ReadInt( nextTriggerTime ); - savefile->ReadBool( triggerFirst ); - savefile->ReadString( entityName ); -} - -/* -================ -idTrigger_EntityName::Spawn -================ -*/ -void idTrigger_EntityName::Spawn( void ) { - spawnArgs.GetFloat( "wait", "0.5", wait ); - spawnArgs.GetFloat( "random", "0", random ); - spawnArgs.GetFloat( "delay", "0", delay ); - spawnArgs.GetFloat( "random_delay", "0", random_delay ); - - if ( random && ( random >= wait ) && ( wait >= 0 ) ) { - random = wait - 1; - gameLocal.Warning( "idTrigger_EntityName '%s' at (%s) has random >= wait", name.c_str(), GetPhysics()->GetOrigin().ToString(0) ); - } - - if ( random_delay && ( random_delay >= delay ) && ( delay >= 0 ) ) { - random_delay = delay - 1; - gameLocal.Warning( "idTrigger_EntityName '%s' at (%s) has random_delay >= delay", name.c_str(), GetPhysics()->GetOrigin().ToString(0) ); - } - - spawnArgs.GetBool( "triggerFirst", "0", triggerFirst ); - - entityName = spawnArgs.GetString( "entityname" ); - if ( !entityName.Length() ) { - gameLocal.Error( "idTrigger_EntityName '%s' at (%s) doesn't have 'entityname' key specified", name.c_str(), GetPhysics()->GetOrigin().ToString(0) ); - } - - nextTriggerTime = 0; - - if ( !spawnArgs.GetBool( "noTouch" ) ) { - GetPhysics()->SetContents( CONTENTS_TRIGGER ); - } -} - -/* -================ -idTrigger_EntityName::TriggerAction -================ -*/ -void idTrigger_EntityName::TriggerAction( idEntity *activator ) { - ActivateTargets( activator ); - CallScript(); - - if ( wait >= 0 ) { - nextTriggerTime = gameLocal.time + SEC2MS( wait + random * gameLocal.random.CRandomFloat() ); - } else { - // we can't just remove (this) here, because this is a touch function - // called while looping through area links... - nextTriggerTime = gameLocal.time + 1; - PostEventMS( &EV_Remove, 0 ); - } -} - -/* -================ -idTrigger_EntityName::Event_TriggerAction -================ -*/ -void idTrigger_EntityName::Event_TriggerAction( idEntity *activator ) { - TriggerAction( activator ); -} - -/* -================ -idTrigger_EntityName::Event_Trigger - -the trigger was just activated -activated should be the entity that originated the activation sequence (ie. the original target) -activator should be set to the activator so it can be held through a delay -so wait for the delay time before firing -================ -*/ -void idTrigger_EntityName::Event_Trigger( idEntity *activator ) { - if ( nextTriggerTime > gameLocal.time ) { - // can't retrigger until the wait is over - return; - } - - if ( !activator || ( activator->name != entityName ) ) { - return; - } - - if ( triggerFirst ) { - triggerFirst = false; - return; - } - - // don't allow it to trigger twice in a single frame - nextTriggerTime = gameLocal.time + 1; - - if ( delay > 0 ) { - // don't allow it to trigger again until our delay has passed - nextTriggerTime += SEC2MS( delay + random_delay * gameLocal.random.CRandomFloat() ); - PostEventSec( &EV_TriggerAction, delay, activator ); - } else { - TriggerAction( activator ); - } -} - -/* -================ -idTrigger_EntityName::Event_Touch -================ -*/ -void idTrigger_EntityName::Event_Touch( idEntity *other, trace_t *trace ) { - if( triggerFirst ) { - return; - } - - if ( nextTriggerTime > gameLocal.time ) { - // can't retrigger until the wait is over - return; - } - - if ( !other || ( other->name != entityName ) ) { - return; - } - - nextTriggerTime = gameLocal.time + 1; - if ( delay > 0 ) { - // don't allow it to trigger again until our delay has passed - nextTriggerTime += SEC2MS( delay + random_delay * gameLocal.random.CRandomFloat() ); - PostEventSec( &EV_TriggerAction, delay, other ); - } else { - TriggerAction( other ); - } -} - -/* -=============================================================================== - - idTrigger_Timer - -=============================================================================== -*/ - -const idEventDef EV_Timer( "", NULL ); - -CLASS_DECLARATION( idTrigger, idTrigger_Timer ) - EVENT( EV_Timer, idTrigger_Timer::Event_Timer ) - EVENT( EV_Activate, idTrigger_Timer::Event_Use ) -END_CLASS - -/* -================ -idTrigger_Timer::idTrigger_Timer -================ -*/ -idTrigger_Timer::idTrigger_Timer( void ) { - random = 0.0f; - wait = 0.0f; - on = false; - delay = 0.0f; -} - -/* -================ -idTrigger_Timer::Save -================ -*/ -void idTrigger_Timer::Save( idSaveGame *savefile ) const { - savefile->WriteFloat( random ); - savefile->WriteFloat( wait ); - savefile->WriteBool( on ); - savefile->WriteFloat( delay ); - savefile->WriteString( onName ); - savefile->WriteString( offName ); -} - -/* -================ -idTrigger_Timer::Restore -================ -*/ -void idTrigger_Timer::Restore( idRestoreGame *savefile ) { - savefile->ReadFloat( random ); - savefile->ReadFloat( wait ); - savefile->ReadBool( on ); - savefile->ReadFloat( delay ); - savefile->ReadString( onName ); - savefile->ReadString( offName ); -} - -/* -================ -idTrigger_Timer::Spawn - -Repeatedly fires its targets. -Can be turned on or off by using. -================ -*/ -void idTrigger_Timer::Spawn( void ) { - spawnArgs.GetFloat( "random", "1", random ); - spawnArgs.GetFloat( "wait", "1", wait ); - spawnArgs.GetBool( "start_on", "0", on ); - spawnArgs.GetFloat( "delay", "0", delay ); - onName = spawnArgs.GetString( "onName" ); - offName = spawnArgs.GetString( "offName" ); - - if ( random >= wait && wait >= 0 ) { - random = wait - 0.001; - gameLocal.Warning( "idTrigger_Timer '%s' at (%s) has random >= wait", name.c_str(), GetPhysics()->GetOrigin().ToString(0) ); - } - - if ( on ) { - PostEventSec( &EV_Timer, delay ); - } -} - -/* -================ -idTrigger_Timer::Enable -================ -*/ -void idTrigger_Timer::Enable( void ) { - // if off, turn it on - if ( !on ) { - on = true; - PostEventSec( &EV_Timer, delay ); - } -} - -/* -================ -idTrigger_Timer::Disable -================ -*/ -void idTrigger_Timer::Disable( void ) { - // if on, turn it off - if ( on ) { - on = false; - CancelEvents( &EV_Timer ); - } -} - -/* -================ -idTrigger_Timer::Event_Timer -================ -*/ -void idTrigger_Timer::Event_Timer( void ) { - ActivateTargets( this ); - - // set time before next firing - if ( wait >= 0.0f ) { - PostEventSec( &EV_Timer, wait + gameLocal.random.CRandomFloat() * random ); - } -} - -/* -================ -idTrigger_Timer::Event_Use -================ -*/ -void idTrigger_Timer::Event_Use( idEntity *activator ) { - // if on, turn it off - if ( on ) { - if ( offName.Length() && offName.Icmp( activator->GetName() ) ) { - return; - } - on = false; - CancelEvents( &EV_Timer ); - } else { - // turn it on - if ( onName.Length() && onName.Icmp( activator->GetName() ) ) { - return; - } - on = true; - PostEventSec( &EV_Timer, delay ); - } -} - -/* -=============================================================================== - - idTrigger_Count - -=============================================================================== -*/ - -CLASS_DECLARATION( idTrigger, idTrigger_Count ) - EVENT( EV_Activate, idTrigger_Count::Event_Trigger ) - EVENT( EV_TriggerAction, idTrigger_Count::Event_TriggerAction ) -END_CLASS - -/* -================ -idTrigger_Count::idTrigger_Count -================ -*/ -idTrigger_Count::idTrigger_Count( void ) { - goal = 0; - count = 0; - delay = 0.0f; -} - -/* -================ -idTrigger_Count::Save -================ -*/ -void idTrigger_Count::Save( idSaveGame *savefile ) const { - savefile->WriteInt( goal ); - savefile->WriteInt( count ); - savefile->WriteFloat( delay ); -} - -/* -================ -idTrigger_Count::Restore -================ -*/ -void idTrigger_Count::Restore( idRestoreGame *savefile ) { - savefile->ReadInt( goal ); - savefile->ReadInt( count ); - savefile->ReadFloat( delay ); -} - -/* -================ -idTrigger_Count::Spawn -================ -*/ -void idTrigger_Count::Spawn( void ) { - spawnArgs.GetInt( "count", "1", goal ); - spawnArgs.GetFloat( "delay", "0", delay ); - count = 0; -} - -/* -================ -idTrigger_Count::Event_Trigger -================ -*/ -void idTrigger_Count::Event_Trigger( idEntity *activator ) { - // goal of -1 means trigger has been exhausted - if (goal >= 0) { - count++; - if ( count >= goal ) { - if (spawnArgs.GetBool("repeat")) { - count = 0; - } else { - goal = -1; - } - PostEventSec( &EV_TriggerAction, delay, activator ); - } - } -} - -/* -================ -idTrigger_Count::Event_TriggerAction -================ -*/ -void idTrigger_Count::Event_TriggerAction( idEntity *activator ) { - ActivateTargets( activator ); - CallScript(); - if ( goal == -1 ) { - PostEventMS( &EV_Remove, 0 ); - } -} - -/* -=============================================================================== - - idTrigger_Hurt - -=============================================================================== -*/ - -CLASS_DECLARATION( idTrigger, idTrigger_Hurt ) - EVENT( EV_Touch, idTrigger_Hurt::Event_Touch ) - EVENT( EV_Activate, idTrigger_Hurt::Event_Toggle ) -END_CLASS - - -/* -================ -idTrigger_Hurt::idTrigger_Hurt -================ -*/ -idTrigger_Hurt::idTrigger_Hurt( void ) { - on = false; - delay = 0.0f; - nextTime = 0; -} - -/* -================ -idTrigger_Hurt::Save -================ -*/ -void idTrigger_Hurt::Save( idSaveGame *savefile ) const { - savefile->WriteBool( on ); - savefile->WriteFloat( delay ); - savefile->WriteInt( nextTime ); -} - -/* -================ -idTrigger_Hurt::Restore -================ -*/ -void idTrigger_Hurt::Restore( idRestoreGame *savefile ) { - savefile->ReadBool( on ); - savefile->ReadFloat( delay ); - savefile->ReadInt( nextTime ); -} - -/* -================ -idTrigger_Hurt::Spawn - - Damages activator - Can be turned on or off by using. -================ -*/ -void idTrigger_Hurt::Spawn( void ) { - spawnArgs.GetBool( "on", "1", on ); - spawnArgs.GetFloat( "delay", "1.0", delay ); - nextTime = gameLocal.time; - Enable(); -} - -/* -================ -idTrigger_Hurt::Event_Touch -================ -*/ -void idTrigger_Hurt::Event_Touch( idEntity *other, trace_t *trace ) { - const char *damage; - - if ( on && other && gameLocal.time >= nextTime ) { -#ifdef _D3XP - bool playerOnly = spawnArgs.GetBool( "playerOnly" ); - if ( playerOnly ) { - if ( !other->IsType( idPlayer::Type ) ) { - return; - } - } -#endif - damage = spawnArgs.GetString( "def_damage", "damage_painTrigger" ); - -#ifdef _D3XP - idVec3 dir = vec3_origin; - if(spawnArgs.GetBool("kick_from_center", "0")) { - dir = other->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin(); - dir.Normalize(); - } - other->Damage( NULL, NULL, dir, damage, 1.0f, INVALID_JOINT ); -#else - other->Damage( NULL, NULL, vec3_origin, damage, 1.0f, INVALID_JOINT ); -#endif - - ActivateTargets( other ); - CallScript(); - - nextTime = gameLocal.time + SEC2MS( delay ); - } -} - -/* -================ -idTrigger_Hurt::Event_Toggle -================ -*/ -void idTrigger_Hurt::Event_Toggle( idEntity *activator ) { - on = !on; -} - - -/* -=============================================================================== - - idTrigger_Fade - -=============================================================================== -*/ - -CLASS_DECLARATION( idTrigger, idTrigger_Fade ) - EVENT( EV_Activate, idTrigger_Fade::Event_Trigger ) -END_CLASS - -/* -================ -idTrigger_Fade::Event_Trigger -================ -*/ -void idTrigger_Fade::Event_Trigger( idEntity *activator ) { - idVec4 fadeColor; - int fadeTime; - idPlayer *player; - - player = gameLocal.GetLocalPlayer(); - if ( player ) { - fadeColor = spawnArgs.GetVec4( "fadeColor", "0, 0, 0, 1" ); - fadeTime = SEC2MS( spawnArgs.GetFloat( "fadeTime", "0.5" ) ); - player->playerView.Fade( fadeColor, fadeTime ); - PostEventMS( &EV_ActivateTargets, fadeTime, activator ); - } -} - -/* -=============================================================================== - - idTrigger_Touch - -=============================================================================== -*/ - -CLASS_DECLARATION( idTrigger, idTrigger_Touch ) - EVENT( EV_Activate, idTrigger_Touch::Event_Trigger ) -END_CLASS - - -/* -================ -idTrigger_Touch::idTrigger_Touch -================ -*/ -idTrigger_Touch::idTrigger_Touch( void ) { - clipModel = NULL; -} - -/* -================ -idTrigger_Touch::Spawn -================ -*/ -void idTrigger_Touch::Spawn( void ) { - // get the clip model - clipModel = new idClipModel( GetPhysics()->GetClipModel() ); - - // remove the collision model from the physics object - GetPhysics()->SetClipModel( NULL, 1.0f ); - - if ( spawnArgs.GetBool( "start_on" ) ) { - BecomeActive( TH_THINK ); - } -} - -/* -================ -idTrigger_Touch::Save -================ -*/ -void idTrigger_Touch::Save( idSaveGame *savefile ) { - savefile->WriteClipModel( clipModel ); -} - -/* -================ -idTrigger_Touch::Restore -================ -*/ -void idTrigger_Touch::Restore( idRestoreGame *savefile ) { - savefile->ReadClipModel( clipModel ); -} - -/* -================ -idTrigger_Touch::TouchEntities -================ -*/ -void idTrigger_Touch::TouchEntities( void ) { - int numClipModels, i; - idBounds bounds; - idClipModel *cm, *clipModelList[ MAX_GENTITIES ]; - - if ( clipModel == NULL || scriptFunction == NULL ) { - return; - } - - bounds.FromTransformedBounds( clipModel->GetBounds(), clipModel->GetOrigin(), clipModel->GetAxis() ); - numClipModels = gameLocal.clip.ClipModelsTouchingBounds( bounds, -1, clipModelList, MAX_GENTITIES ); - - for ( i = 0; i < numClipModels; i++ ) { - cm = clipModelList[ i ]; - - if ( !cm->IsTraceModel() ) { - continue; - } - - idEntity *entity = cm->GetEntity(); - - if ( !entity ) { - continue; - } - - if ( !gameLocal.clip.ContentsModel( cm->GetOrigin(), cm, cm->GetAxis(), -1, - clipModel->Handle(), clipModel->GetOrigin(), clipModel->GetAxis() ) ) { - continue; - } - - ActivateTargets( entity ); - - idThread *thread = new idThread(); - thread->CallFunction( entity, scriptFunction, false ); - thread->DelayedStart( 0 ); - } -} - -/* -================ -idTrigger_Touch::Think -================ -*/ -void idTrigger_Touch::Think( void ) { - if ( thinkFlags & TH_THINK ) { - TouchEntities(); - } - idEntity::Think(); -} - -/* -================ -idTrigger_Touch::Event_Trigger -================ -*/ -void idTrigger_Touch::Event_Trigger( idEntity *activator ) { - if ( thinkFlags & TH_THINK ) { - BecomeInactive( TH_THINK ); - } else { - BecomeActive( TH_THINK ); - } -} - -/* -================ -idTrigger_Touch::Enable -================ -*/ -void idTrigger_Touch::Enable( void ) { - BecomeActive( TH_THINK ); -} - -/* -================ -idTrigger_Touch::Disable -================ -*/ -void idTrigger_Touch::Disable( void ) { - BecomeInactive( TH_THINK ); -} - -#ifdef CTF -/* -=============================================================================== - - idTrigger_Flag - -=============================================================================== -*/ - -CLASS_DECLARATION( idTrigger_Multi, idTrigger_Flag ) - EVENT( EV_Touch, idTrigger_Flag::Event_Touch ) -END_CLASS - -idTrigger_Flag::idTrigger_Flag( void ) { - team = -1; - player = false; - eventFlag = NULL; -} - -void idTrigger_Flag::Spawn( void ) { - team = spawnArgs.GetInt( "team", "0" ); - player = spawnArgs.GetBool( "player", "0" ); - - idStr funcname = spawnArgs.GetString( "eventflag", "" ); - if ( funcname.Length() ) { - eventFlag = idEventDef::FindEvent( funcname );// gameLocal.program.FindFunction( funcname );//, &idItemTeam::Type ); - if ( eventFlag == NULL ) { - gameLocal.Warning( "trigger '%s' at (%s) event unknown '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), funcname.c_str() ); - } - } else { - eventFlag = NULL; - } - - idTrigger_Multi::Spawn(); -} - -void idTrigger_Flag::Event_Touch( idEntity *other, trace_t *trace ) { - - idItemTeam * flag = NULL; - - if ( player ) { - if ( !other->IsType( idPlayer::Type ) ) - return; - - idPlayer * player = static_cast(other); - if ( player->carryingFlag == false ) - return; - - if ( team != -1 && ( player->team != team || (player->team != 0 && player->team != 1)) ) - return; - - idItemTeam * flags[2]; - - flags[0] = gameLocal.mpGame.GetTeamFlag( 0 ); - flags[1] = gameLocal.mpGame.GetTeamFlag( 1 ); - - int iFriend = 1 - player->team; // index to the flag player team wants - int iOpp = player->team; // index to the flag opp team wants - - // flag is captured if : - // 1)flag is truely bound to the player - // 2)opponent flag has been return - if ( flags[iFriend]->carried && !flags[iFriend]->dropped && //flags[iFriend]->IsBoundTo( player ) && - !flags[iOpp]->carried && !flags[iOpp]->dropped ) - flag = flags[iFriend]; - else - return; - } else { - if ( !other->IsType( idItemTeam::Type ) ) - return; - - idItemTeam * item = static_cast( other ); - - if ( item->team == team || team == -1 ) { - flag = item; - } - else - return; - } - - if ( flag ) { - switch ( eventFlag->GetNumArgs() ) { - default : - case 0 : - flag->PostEventMS( eventFlag, 0 ); - break; - case 1 : - flag->PostEventMS( eventFlag, 0, 0 ); - break; - case 2 : - flag->PostEventMS( eventFlag, 0, 0, 0 ); - break; - } - -/* - ServerSendEvent( eventFlag->GetEventNum(), NULL, true, false ); - - idThread *thread; - if ( scriptFlag ) { - thread = new idThread(); - thread->CallFunction( flag, scriptFlag, false ); - thread->DelayedStart( 0 ); - } -*/ - idTrigger_Multi::Event_Touch( other, trace ); - } -} - -#endif diff --git a/d3xp/Trigger.h b/d3xp/Trigger.h deleted file mode 100644 index 7e4e348a..00000000 --- a/d3xp/Trigger.h +++ /dev/null @@ -1,321 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __GAME_TRIGGER_H__ -#define __GAME_TRIGGER_H__ - -#include "gamesys/Event.h" -#include "Entity.h" - -extern const idEventDef EV_Enable; -extern const idEventDef EV_Disable; - -/* -=============================================================================== - - Trigger base. - -=============================================================================== -*/ - -class idTrigger : public idEntity { -public: - CLASS_PROTOTYPE( idTrigger ); - - static void DrawDebugInfo( void ); - - idTrigger(); - void Spawn( void ); - - const function_t * GetScriptFunction( void ) const; - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - virtual void Enable( void ); - virtual void Disable( void ); - -protected: - void CallScript( void ) const; - - void Event_Enable( void ); - void Event_Disable( void ); - - const function_t * scriptFunction; -}; - - -/* -=============================================================================== - - Trigger which can be activated multiple times. - -=============================================================================== -*/ - -class idTrigger_Multi : public idTrigger { -public: - CLASS_PROTOTYPE( idTrigger_Multi ); - - idTrigger_Multi( void ); - - void Spawn( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - -#ifdef CTF -protected: -#else -private: -#endif - - float wait; - float random; - float delay; - float random_delay; - int nextTriggerTime; - idStr requires; - int removeItem; - bool touchClient; - bool touchOther; - bool triggerFirst; - bool triggerWithSelf; - - bool CheckFacing( idEntity *activator ); - void TriggerAction( idEntity *activator ); - void Event_TriggerAction( idEntity *activator ); - void Event_Trigger( idEntity *activator ); - void Event_Touch( idEntity *other, trace_t *trace ); -}; - - -/* -=============================================================================== - - Trigger which can only be activated by an entity with a specific name. - -=============================================================================== -*/ - -class idTrigger_EntityName : public idTrigger { -public: - CLASS_PROTOTYPE( idTrigger_EntityName ); - - idTrigger_EntityName( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void Spawn( void ); - -private: - float wait; - float random; - float delay; - float random_delay; - int nextTriggerTime; - bool triggerFirst; - idStr entityName; - - void TriggerAction( idEntity *activator ); - void Event_TriggerAction( idEntity *activator ); - void Event_Trigger( idEntity *activator ); - void Event_Touch( idEntity *other, trace_t *trace ); -}; - -/* -=============================================================================== - - Trigger which repeatedly fires targets. - -=============================================================================== -*/ - -class idTrigger_Timer : public idTrigger { -public: - CLASS_PROTOTYPE( idTrigger_Timer ); - - idTrigger_Timer( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void Spawn( void ); - - virtual void Enable( void ); - virtual void Disable( void ); - -private: - float random; - float wait; - bool on; - float delay; - idStr onName; - idStr offName; - - void Event_Timer( void ); - void Event_Use( idEntity *activator ); -}; - - -/* -=============================================================================== - - Trigger which fires targets after being activated a specific number of times. - -=============================================================================== -*/ - -class idTrigger_Count : public idTrigger { -public: - CLASS_PROTOTYPE( idTrigger_Count ); - - idTrigger_Count( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void Spawn( void ); - -private: - int goal; - int count; - float delay; - - void Event_Trigger( idEntity *activator ); - void Event_TriggerAction( idEntity *activator ); -}; - - -/* -=============================================================================== - - Trigger which hurts touching entities. - -=============================================================================== -*/ - -class idTrigger_Hurt : public idTrigger { -public: - CLASS_PROTOTYPE( idTrigger_Hurt ); - - idTrigger_Hurt( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void Spawn( void ); - -private: - bool on; - float delay; - int nextTime; - - void Event_Touch( idEntity *other, trace_t *trace ); - void Event_Toggle( idEntity *activator ); -}; - - -/* -=============================================================================== - - Trigger which fades the player view. - -=============================================================================== -*/ - -class idTrigger_Fade : public idTrigger { -public: - - CLASS_PROTOTYPE( idTrigger_Fade ); - -private: - void Event_Trigger( idEntity *activator ); -}; - - -/* -=============================================================================== - - Trigger which continuously tests whether other entities are touching it. - -=============================================================================== -*/ - -class idTrigger_Touch : public idTrigger { -public: - - CLASS_PROTOTYPE( idTrigger_Touch ); - - idTrigger_Touch( void ); - - void Spawn( void ); - virtual void Think( void ); - - void Save( idSaveGame *savefile ); - void Restore( idRestoreGame *savefile ); - - virtual void Enable( void ); - virtual void Disable( void ); - - void TouchEntities( void ); - -private: - idClipModel * clipModel; - - void Event_Trigger( idEntity *activator ); -}; - -#ifdef CTF -/* -=============================================================================== - - Trigger that responces to CTF flags - -=============================================================================== -*/ -class idTrigger_Flag : public idTrigger_Multi { -public: - CLASS_PROTOTYPE( idTrigger_Flag ); - - idTrigger_Flag( void ); - void Spawn( void ); - -private: - int team; - bool player; // flag must be attached/carried by player - - const idEventDef * eventFlag; - - void Event_Touch( idEntity *other, trace_t *trace ); -}; - -#endif /* CTF */ - -#endif /* !__GAME_TRIGGER_H__ */ diff --git a/d3xp/Weapon.cpp b/d3xp/Weapon.cpp deleted file mode 100644 index 30f8882b..00000000 --- a/d3xp/Weapon.cpp +++ /dev/null @@ -1,3952 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "framework/DeclEntityDef.h" -#include "framework/DeclSkin.h" - -#include "gamesys/SysCvar.h" -#include "ai/AI.h" -#include "Player.h" -#include "Trigger.h" -#include "SmokeParticles.h" -#include "WorldSpawn.h" -#include "Misc.h" - -#include "Weapon.h" - -/*********************************************************************** - - idWeapon - -***********************************************************************/ - -// -// event defs -// -const idEventDef EV_Weapon_Clear( "" ); -const idEventDef EV_Weapon_GetOwner( "getOwner", NULL, 'e' ); -const idEventDef EV_Weapon_Next( "nextWeapon" ); -const idEventDef EV_Weapon_State( "weaponState", "sd" ); -const idEventDef EV_Weapon_UseAmmo( "useAmmo", "d" ); -const idEventDef EV_Weapon_AddToClip( "addToClip", "d" ); -const idEventDef EV_Weapon_AmmoInClip( "ammoInClip", NULL, 'f' ); -const idEventDef EV_Weapon_AmmoAvailable( "ammoAvailable", NULL, 'f' ); -const idEventDef EV_Weapon_TotalAmmoCount( "totalAmmoCount", NULL, 'f' ); -const idEventDef EV_Weapon_ClipSize( "clipSize", NULL, 'f' ); -const idEventDef EV_Weapon_WeaponOutOfAmmo( "weaponOutOfAmmo" ); -const idEventDef EV_Weapon_WeaponReady( "weaponReady" ); -const idEventDef EV_Weapon_WeaponReloading( "weaponReloading" ); -const idEventDef EV_Weapon_WeaponHolstered( "weaponHolstered" ); -const idEventDef EV_Weapon_WeaponRising( "weaponRising" ); -const idEventDef EV_Weapon_WeaponLowering( "weaponLowering" ); -const idEventDef EV_Weapon_Flashlight( "flashlight", "d" ); -const idEventDef EV_Weapon_LaunchProjectiles( "launchProjectiles", "dffff" ); -const idEventDef EV_Weapon_CreateProjectile( "createProjectile", NULL, 'e' ); -const idEventDef EV_Weapon_EjectBrass( "ejectBrass" ); -const idEventDef EV_Weapon_Melee( "melee", NULL, 'd' ); -const idEventDef EV_Weapon_GetWorldModel( "getWorldModel", NULL, 'e' ); -const idEventDef EV_Weapon_AllowDrop( "allowDrop", "d" ); -const idEventDef EV_Weapon_AutoReload( "autoReload", NULL, 'f' ); -const idEventDef EV_Weapon_NetReload( "netReload" ); -const idEventDef EV_Weapon_IsInvisible( "isInvisible", NULL, 'f' ); -const idEventDef EV_Weapon_NetEndReload( "netEndReload" ); -#ifdef _D3XP -const idEventDef EV_Weapon_GrabberHasTarget( "grabberHasTarget", NULL, 'd' ); -const idEventDef EV_Weapon_Grabber( "grabber", "d" ); -const idEventDef EV_Weapon_Grabber_SetGrabDistance( "grabberGrabDistance", "f" ); -const idEventDef EV_Weapon_LaunchProjectilesEllipse( "launchProjectilesEllipse", "dffff" ); -const idEventDef EV_Weapon_LaunchPowerup( "launchPowerup", "sfd" ); -const idEventDef EV_Weapon_StartWeaponSmoke( "startWeaponSmoke" ); -const idEventDef EV_Weapon_StopWeaponSmoke( "stopWeaponSmoke" ); -const idEventDef EV_Weapon_StartWeaponParticle( "startWeaponParticle", "s" ); -const idEventDef EV_Weapon_StopWeaponParticle( "stopWeaponParticle", "s" ); -const idEventDef EV_Weapon_StartWeaponLight( "startWeaponLight", "s" ); -const idEventDef EV_Weapon_StopWeaponLight( "stopWeaponLight", "s" ); -#endif - -// -// class def -// -CLASS_DECLARATION( idAnimatedEntity, idWeapon ) - EVENT( EV_Weapon_Clear, idWeapon::Event_Clear ) - EVENT( EV_Weapon_GetOwner, idWeapon::Event_GetOwner ) - EVENT( EV_Weapon_State, idWeapon::Event_WeaponState ) - EVENT( EV_Weapon_WeaponReady, idWeapon::Event_WeaponReady ) - EVENT( EV_Weapon_WeaponOutOfAmmo, idWeapon::Event_WeaponOutOfAmmo ) - EVENT( EV_Weapon_WeaponReloading, idWeapon::Event_WeaponReloading ) - EVENT( EV_Weapon_WeaponHolstered, idWeapon::Event_WeaponHolstered ) - EVENT( EV_Weapon_WeaponRising, idWeapon::Event_WeaponRising ) - EVENT( EV_Weapon_WeaponLowering, idWeapon::Event_WeaponLowering ) - EVENT( EV_Weapon_UseAmmo, idWeapon::Event_UseAmmo ) - EVENT( EV_Weapon_AddToClip, idWeapon::Event_AddToClip ) - EVENT( EV_Weapon_AmmoInClip, idWeapon::Event_AmmoInClip ) - EVENT( EV_Weapon_AmmoAvailable, idWeapon::Event_AmmoAvailable ) - EVENT( EV_Weapon_TotalAmmoCount, idWeapon::Event_TotalAmmoCount ) - EVENT( EV_Weapon_ClipSize, idWeapon::Event_ClipSize ) - EVENT( AI_PlayAnim, idWeapon::Event_PlayAnim ) - EVENT( AI_PlayCycle, idWeapon::Event_PlayCycle ) - EVENT( AI_SetBlendFrames, idWeapon::Event_SetBlendFrames ) - EVENT( AI_GetBlendFrames, idWeapon::Event_GetBlendFrames ) - EVENT( AI_AnimDone, idWeapon::Event_AnimDone ) - EVENT( EV_Weapon_Next, idWeapon::Event_Next ) - EVENT( EV_SetSkin, idWeapon::Event_SetSkin ) - EVENT( EV_Weapon_Flashlight, idWeapon::Event_Flashlight ) - EVENT( EV_Light_GetLightParm, idWeapon::Event_GetLightParm ) - EVENT( EV_Light_SetLightParm, idWeapon::Event_SetLightParm ) - EVENT( EV_Light_SetLightParms, idWeapon::Event_SetLightParms ) - EVENT( EV_Weapon_LaunchProjectiles, idWeapon::Event_LaunchProjectiles ) - EVENT( EV_Weapon_CreateProjectile, idWeapon::Event_CreateProjectile ) - EVENT( EV_Weapon_EjectBrass, idWeapon::Event_EjectBrass ) - EVENT( EV_Weapon_Melee, idWeapon::Event_Melee ) - EVENT( EV_Weapon_GetWorldModel, idWeapon::Event_GetWorldModel ) - EVENT( EV_Weapon_AllowDrop, idWeapon::Event_AllowDrop ) - EVENT( EV_Weapon_AutoReload, idWeapon::Event_AutoReload ) - EVENT( EV_Weapon_NetReload, idWeapon::Event_NetReload ) - EVENT( EV_Weapon_IsInvisible, idWeapon::Event_IsInvisible ) - EVENT( EV_Weapon_NetEndReload, idWeapon::Event_NetEndReload ) -#ifdef _D3XP - EVENT( EV_Weapon_Grabber, idWeapon::Event_Grabber ) - EVENT( EV_Weapon_GrabberHasTarget, idWeapon::Event_GrabberHasTarget ) - EVENT( EV_Weapon_Grabber_SetGrabDistance, idWeapon::Event_GrabberSetGrabDistance ) - EVENT( EV_Weapon_LaunchProjectilesEllipse, idWeapon::Event_LaunchProjectilesEllipse ) - EVENT( EV_Weapon_LaunchPowerup, idWeapon::Event_LaunchPowerup ) - EVENT( EV_Weapon_StartWeaponSmoke, idWeapon::Event_StartWeaponSmoke ) - EVENT( EV_Weapon_StopWeaponSmoke, idWeapon::Event_StopWeaponSmoke ) - EVENT( EV_Weapon_StartWeaponParticle, idWeapon::Event_StartWeaponParticle ) - EVENT( EV_Weapon_StopWeaponParticle, idWeapon::Event_StopWeaponParticle ) - EVENT( EV_Weapon_StartWeaponLight, idWeapon::Event_StartWeaponLight ) - EVENT( EV_Weapon_StopWeaponLight, idWeapon::Event_StopWeaponLight ) -#endif -END_CLASS - -/*********************************************************************** - - init - -***********************************************************************/ - -/* -================ -idWeapon::idWeapon() -================ -*/ -idWeapon::idWeapon() { - owner = NULL; - worldModel = NULL; - weaponDef = NULL; - thread = NULL; - - memset( &guiLight, 0, sizeof( guiLight ) ); - memset( &muzzleFlash, 0, sizeof( muzzleFlash ) ); - memset( &worldMuzzleFlash, 0, sizeof( worldMuzzleFlash ) ); - memset( &nozzleGlow, 0, sizeof( nozzleGlow ) ); - - muzzleFlashEnd = 0; - flashColor = vec3_origin; - muzzleFlashHandle = -1; - worldMuzzleFlashHandle = -1; - guiLightHandle = -1; - nozzleGlowHandle = -1; - modelDefHandle = -1; -#ifdef _D3XP - grabberState = -1; -#endif - - berserk = 2; - brassDelay = 0; - - allowDrop = true; - - Clear(); - - fl.networkSync = true; -} - -/* -================ -idWeapon::~idWeapon() -================ -*/ -idWeapon::~idWeapon() { - Clear(); - delete worldModel.GetEntity(); -} - - -/* -================ -idWeapon::Spawn -================ -*/ -void idWeapon::Spawn( void ) { - if ( !gameLocal.isClient ) { - // setup the world model - worldModel = static_cast< idAnimatedEntity * >( gameLocal.SpawnEntityType( idAnimatedEntity::Type, NULL ) ); - worldModel.GetEntity()->fl.networkSync = true; - } - -#ifdef _D3XP - if ( 1 /*!gameLocal.isMultiplayer*/ ) { - grabber.Initialize(); - } -#endif - - thread = new idThread(); - thread->ManualDelete(); - thread->ManualControl(); -} - -/* -================ -idWeapon::SetOwner - -Only called at player spawn time, not each weapon switch -================ -*/ -void idWeapon::SetOwner( idPlayer *_owner ) { - assert( !owner ); - owner = _owner; - SetName( va( "%s_weapon", owner->name.c_str() ) ); - - if ( worldModel.GetEntity() ) { - worldModel.GetEntity()->SetName( va( "%s_weapon_worldmodel", owner->name.c_str() ) ); - } -} - -/* -================ -idWeapon::ShouldConstructScriptObjectAtSpawn - -Called during idEntity::Spawn to see if it should construct the script object or not. -Overridden by subclasses that need to spawn the script object themselves. -================ -*/ -bool idWeapon::ShouldConstructScriptObjectAtSpawn( void ) const { - return false; -} - -/* -================ -idWeapon::CacheWeapon -================ -*/ -void idWeapon::CacheWeapon( const char *weaponName ) { - const idDeclEntityDef *weaponDef; - const char *brassDefName; - const char *clipModelName; - idTraceModel trm; - const char *guiName; - - weaponDef = gameLocal.FindEntityDef( weaponName, false ); - if ( !weaponDef ) { - return; - } - - // precache the brass collision model - brassDefName = weaponDef->dict.GetString( "def_ejectBrass" ); - if ( brassDefName[0] ) { - const idDeclEntityDef *brassDef = gameLocal.FindEntityDef( brassDefName, false ); - if ( brassDef ) { - brassDef->dict.GetString( "clipmodel", "", &clipModelName ); - if ( !clipModelName[0] ) { - clipModelName = brassDef->dict.GetString( "model" ); // use the visual model - } - // load the trace model - collisionModelManager->TrmFromModel( clipModelName, trm ); - } - } - - guiName = weaponDef->dict.GetString( "gui" ); - if ( guiName[0] ) { - uiManager->FindGui( guiName, true, false, true ); - } -} - -/* -================ -idWeapon::Save -================ -*/ -void idWeapon::Save( idSaveGame *savefile ) const { - - savefile->WriteInt( status ); - savefile->WriteObject( thread ); - savefile->WriteString( state ); - savefile->WriteString( idealState ); - savefile->WriteInt( animBlendFrames ); - savefile->WriteInt( animDoneTime ); - savefile->WriteBool( isLinked ); - - savefile->WriteObject( owner ); - worldModel.Save( savefile ); - - savefile->WriteInt( hideTime ); - savefile->WriteFloat( hideDistance ); - savefile->WriteInt( hideStartTime ); - savefile->WriteFloat( hideStart ); - savefile->WriteFloat( hideEnd ); - savefile->WriteFloat( hideOffset ); - savefile->WriteBool( hide ); - savefile->WriteBool( disabled ); - - savefile->WriteInt( berserk ); - - savefile->WriteVec3( playerViewOrigin ); - savefile->WriteMat3( playerViewAxis ); - - savefile->WriteVec3( viewWeaponOrigin ); - savefile->WriteMat3( viewWeaponAxis ); - - savefile->WriteVec3( muzzleOrigin ); - savefile->WriteMat3( muzzleAxis ); - - savefile->WriteVec3( pushVelocity ); - - savefile->WriteString( weaponDef->GetName() ); - savefile->WriteFloat( meleeDistance ); - savefile->WriteString( meleeDefName ); - savefile->WriteInt( brassDelay ); - savefile->WriteString( icon ); - - savefile->WriteInt( guiLightHandle ); - savefile->WriteRenderLight( guiLight ); - - savefile->WriteInt( muzzleFlashHandle ); - savefile->WriteRenderLight( muzzleFlash ); - - savefile->WriteInt( worldMuzzleFlashHandle ); - savefile->WriteRenderLight( worldMuzzleFlash ); - - savefile->WriteVec3( flashColor ); - savefile->WriteInt( muzzleFlashEnd ); - savefile->WriteInt( flashTime ); - - savefile->WriteBool( lightOn ); - savefile->WriteBool( silent_fire ); - - savefile->WriteInt( kick_endtime ); - savefile->WriteInt( muzzle_kick_time ); - savefile->WriteInt( muzzle_kick_maxtime ); - savefile->WriteAngles( muzzle_kick_angles ); - savefile->WriteVec3( muzzle_kick_offset ); - - savefile->WriteInt( ammoType ); - savefile->WriteInt( ammoRequired ); - savefile->WriteInt( clipSize ); - savefile->WriteInt( ammoClip ); - savefile->WriteInt( lowAmmo ); - savefile->WriteBool( powerAmmo ); - - // savegames <= 17 - savefile->WriteInt( 0 ); - - savefile->WriteInt( zoomFov ); - - savefile->WriteJoint( barrelJointView ); - savefile->WriteJoint( flashJointView ); - savefile->WriteJoint( ejectJointView ); - savefile->WriteJoint( guiLightJointView ); - savefile->WriteJoint( ventLightJointView ); - - savefile->WriteJoint( flashJointWorld ); - savefile->WriteJoint( barrelJointWorld ); - savefile->WriteJoint( ejectJointWorld ); - - savefile->WriteBool( hasBloodSplat ); - - savefile->WriteSoundShader( sndHum ); - - savefile->WriteParticle( weaponSmoke ); - savefile->WriteInt( weaponSmokeStartTime ); - savefile->WriteBool( continuousSmoke ); - savefile->WriteParticle( strikeSmoke ); - savefile->WriteInt( strikeSmokeStartTime ); - savefile->WriteVec3( strikePos ); - savefile->WriteMat3( strikeAxis ); - savefile->WriteInt( nextStrikeFx ); - - savefile->WriteBool( nozzleFx ); - savefile->WriteInt( nozzleFxFade ); - - savefile->WriteInt( lastAttack ); - - savefile->WriteInt( nozzleGlowHandle ); - savefile->WriteRenderLight( nozzleGlow ); - - savefile->WriteVec3( nozzleGlowColor ); - savefile->WriteMaterial( nozzleGlowShader ); - savefile->WriteFloat( nozzleGlowRadius ); - - savefile->WriteInt( weaponAngleOffsetAverages ); - savefile->WriteFloat( weaponAngleOffsetScale ); - savefile->WriteFloat( weaponAngleOffsetMax ); - savefile->WriteFloat( weaponOffsetTime ); - savefile->WriteFloat( weaponOffsetScale ); - - savefile->WriteBool( allowDrop ); - savefile->WriteObject( projectileEnt ); - -#ifdef _D3XP - savefile->WriteStaticObject( grabber ); - savefile->WriteInt( grabberState ); - - savefile->WriteJoint ( smokeJointView ); - - savefile->WriteInt(weaponParticles.Num()); - for(int i = 0; i < weaponParticles.Num(); i++) { - WeaponParticle_t* part = weaponParticles.GetIndex(i); - savefile->WriteString( part->name ); - savefile->WriteString( part->particlename ); - savefile->WriteBool( part->active ); - savefile->WriteInt( part->startTime ); - savefile->WriteJoint( part->joint ); - savefile->WriteBool( part->smoke ); - if(!part->smoke) { - savefile->WriteObject(part->emitter); - } - } - savefile->WriteInt(weaponLights.Num()); - for(int i = 0; i < weaponLights.Num(); i++) { - WeaponLight_t* light = weaponLights.GetIndex(i); - savefile->WriteString( light->name ); - savefile->WriteBool( light->active ); - savefile->WriteInt( light->startTime ); - savefile->WriteJoint( light->joint ); - savefile->WriteInt( light->lightHandle ); - savefile->WriteRenderLight( light->light ); - } -#endif - -} - -/* -================ -idWeapon::Restore -================ -*/ -void idWeapon::Restore( idRestoreGame *savefile ) { - - savefile->ReadInt( (int &)status ); - savefile->ReadObject( reinterpret_cast( thread ) ); - savefile->ReadString( state ); - savefile->ReadString( idealState ); - savefile->ReadInt( animBlendFrames ); - savefile->ReadInt( animDoneTime ); - savefile->ReadBool( isLinked ); - - // Re-link script fields - WEAPON_ATTACK.LinkTo( scriptObject, "WEAPON_ATTACK" ); - WEAPON_RELOAD.LinkTo( scriptObject, "WEAPON_RELOAD" ); - WEAPON_NETRELOAD.LinkTo( scriptObject, "WEAPON_NETRELOAD" ); - WEAPON_NETENDRELOAD.LinkTo( scriptObject, "WEAPON_NETENDRELOAD" ); - WEAPON_NETFIRING.LinkTo( scriptObject, "WEAPON_NETFIRING" ); - WEAPON_RAISEWEAPON.LinkTo( scriptObject, "WEAPON_RAISEWEAPON" ); - WEAPON_LOWERWEAPON.LinkTo( scriptObject, "WEAPON_LOWERWEAPON" ); - - savefile->ReadObject( reinterpret_cast( owner ) ); - worldModel.Restore( savefile ); - - savefile->ReadInt( hideTime ); - savefile->ReadFloat( hideDistance ); - savefile->ReadInt( hideStartTime ); - savefile->ReadFloat( hideStart ); - savefile->ReadFloat( hideEnd ); - savefile->ReadFloat( hideOffset ); - savefile->ReadBool( hide ); - savefile->ReadBool( disabled ); - - savefile->ReadInt( berserk ); - - savefile->ReadVec3( playerViewOrigin ); - savefile->ReadMat3( playerViewAxis ); - - savefile->ReadVec3( viewWeaponOrigin ); - savefile->ReadMat3( viewWeaponAxis ); - - savefile->ReadVec3( muzzleOrigin ); - savefile->ReadMat3( muzzleAxis ); - - savefile->ReadVec3( pushVelocity ); - - idStr objectname; - savefile->ReadString( objectname ); - weaponDef = gameLocal.FindEntityDef( objectname ); - meleeDef = gameLocal.FindEntityDef( weaponDef->dict.GetString( "def_melee" ), false ); - - const idDeclEntityDef *projectileDef = gameLocal.FindEntityDef( weaponDef->dict.GetString( "def_projectile" ), false ); - if ( projectileDef ) { - projectileDict = projectileDef->dict; - } else { - projectileDict.Clear(); - } - - const idDeclEntityDef *brassDef = gameLocal.FindEntityDef( weaponDef->dict.GetString( "def_ejectBrass" ), false ); - if ( brassDef ) { - brassDict = brassDef->dict; - } else { - brassDict.Clear(); - } - - savefile->ReadFloat( meleeDistance ); - savefile->ReadString( meleeDefName ); - savefile->ReadInt( brassDelay ); - savefile->ReadString( icon ); - - savefile->ReadInt( guiLightHandle ); - savefile->ReadRenderLight( guiLight ); -#ifdef _D3XP - if ( guiLightHandle >= 0 ) { - guiLightHandle = gameRenderWorld->AddLightDef( &guiLight ); - } -#endif - - savefile->ReadInt( muzzleFlashHandle ); - savefile->ReadRenderLight( muzzleFlash ); -#ifdef _D3XP - if ( muzzleFlashHandle >= 0 ) { - muzzleFlashHandle = gameRenderWorld->AddLightDef( &muzzleFlash ); - } -#endif - - savefile->ReadInt( worldMuzzleFlashHandle ); - savefile->ReadRenderLight( worldMuzzleFlash ); -#ifdef _D3XP - if ( worldMuzzleFlashHandle >= 0 ) { - worldMuzzleFlashHandle = gameRenderWorld->AddLightDef( &worldMuzzleFlash ); - } -#endif - - savefile->ReadVec3( flashColor ); - savefile->ReadInt( muzzleFlashEnd ); - savefile->ReadInt( flashTime ); - - savefile->ReadBool( lightOn ); - savefile->ReadBool( silent_fire ); - - savefile->ReadInt( kick_endtime ); - savefile->ReadInt( muzzle_kick_time ); - savefile->ReadInt( muzzle_kick_maxtime ); - savefile->ReadAngles( muzzle_kick_angles ); - savefile->ReadVec3( muzzle_kick_offset ); - - savefile->ReadInt( (int &)ammoType ); - savefile->ReadInt( ammoRequired ); - savefile->ReadInt( clipSize ); - savefile->ReadInt( ammoClip ); - savefile->ReadInt( lowAmmo ); - savefile->ReadBool( powerAmmo ); - - // savegame versions <= 17 - int foo; - savefile->ReadInt( foo ); - - savefile->ReadInt( zoomFov ); - - savefile->ReadJoint( barrelJointView ); - savefile->ReadJoint( flashJointView ); - savefile->ReadJoint( ejectJointView ); - savefile->ReadJoint( guiLightJointView ); - savefile->ReadJoint( ventLightJointView ); - - savefile->ReadJoint( flashJointWorld ); - savefile->ReadJoint( barrelJointWorld ); - savefile->ReadJoint( ejectJointWorld ); - - savefile->ReadBool( hasBloodSplat ); - - savefile->ReadSoundShader( sndHum ); - - savefile->ReadParticle( weaponSmoke ); - savefile->ReadInt( weaponSmokeStartTime ); - savefile->ReadBool( continuousSmoke ); - savefile->ReadParticle( strikeSmoke ); - savefile->ReadInt( strikeSmokeStartTime ); - savefile->ReadVec3( strikePos ); - savefile->ReadMat3( strikeAxis ); - savefile->ReadInt( nextStrikeFx ); - - savefile->ReadBool( nozzleFx ); - savefile->ReadInt( nozzleFxFade ); - - savefile->ReadInt( lastAttack ); - - savefile->ReadInt( nozzleGlowHandle ); - savefile->ReadRenderLight( nozzleGlow ); -#ifdef _D3XP - if ( nozzleGlowHandle >= 0 ) { - nozzleGlowHandle = gameRenderWorld->AddLightDef( &nozzleGlow ); - } -#endif - - savefile->ReadVec3( nozzleGlowColor ); - savefile->ReadMaterial( nozzleGlowShader ); - savefile->ReadFloat( nozzleGlowRadius ); - - savefile->ReadInt( weaponAngleOffsetAverages ); - savefile->ReadFloat( weaponAngleOffsetScale ); - savefile->ReadFloat( weaponAngleOffsetMax ); - savefile->ReadFloat( weaponOffsetTime ); - savefile->ReadFloat( weaponOffsetScale ); - - savefile->ReadBool( allowDrop ); - savefile->ReadObject( reinterpret_cast( projectileEnt ) ); - -#ifdef _D3XP - savefile->ReadStaticObject( grabber ); - savefile->ReadInt( grabberState ); - - savefile->ReadJoint ( smokeJointView ); - - int particleCount; - savefile->ReadInt( particleCount ); - for(int i = 0; i < particleCount; i++) { - WeaponParticle_t newParticle; - memset(&newParticle, 0, sizeof(newParticle)); - - idStr name, particlename; - savefile->ReadString( name ); - savefile->ReadString( particlename ); - - strcpy( newParticle.name, name.c_str() ); - strcpy( newParticle.particlename, particlename.c_str() ); - - savefile->ReadBool( newParticle.active ); - savefile->ReadInt( newParticle.startTime ); - savefile->ReadJoint( newParticle.joint ); - savefile->ReadBool( newParticle.smoke ); - if(newParticle.smoke) { - newParticle.particle = static_cast( declManager->FindType( DECL_PARTICLE, particlename, false ) ); - } else { - savefile->ReadObject(reinterpret_cast(newParticle.emitter)); - } - - weaponParticles.Set(newParticle.name, newParticle); - } - - int lightCount; - savefile->ReadInt( lightCount ); - for(int i = 0; i < lightCount; i++) { - WeaponLight_t newLight; - memset(&newLight, 0, sizeof(newLight)); - - idStr name; - savefile->ReadString( name ); - strcpy( newLight.name, name.c_str() ); - - savefile->ReadBool( newLight.active ); - savefile->ReadInt( newLight.startTime ); - savefile->ReadJoint( newLight.joint ); - savefile->ReadInt( newLight.lightHandle ); - savefile->ReadRenderLight( newLight.light ); - if ( newLight.lightHandle >= 0 ) { - newLight.lightHandle = gameRenderWorld->AddLightDef( &newLight.light ); - } - weaponLights.Set(newLight.name, newLight); - } -#endif -} - -/*********************************************************************** - - Weapon definition management - -***********************************************************************/ - -/* -================ -idWeapon::Clear -================ -*/ -void idWeapon::Clear( void ) { - CancelEvents( &EV_Weapon_Clear ); - - DeconstructScriptObject(); - scriptObject.Free(); - - WEAPON_ATTACK.Unlink(); - WEAPON_RELOAD.Unlink(); - WEAPON_NETRELOAD.Unlink(); - WEAPON_NETENDRELOAD.Unlink(); - WEAPON_NETFIRING.Unlink(); - WEAPON_RAISEWEAPON.Unlink(); - WEAPON_LOWERWEAPON.Unlink(); - - if ( muzzleFlashHandle != -1 ) { - gameRenderWorld->FreeLightDef( muzzleFlashHandle ); - muzzleFlashHandle = -1; - } - if ( muzzleFlashHandle != -1 ) { - gameRenderWorld->FreeLightDef( muzzleFlashHandle ); - muzzleFlashHandle = -1; - } - if ( worldMuzzleFlashHandle != -1 ) { - gameRenderWorld->FreeLightDef( worldMuzzleFlashHandle ); - worldMuzzleFlashHandle = -1; - } - if ( guiLightHandle != -1 ) { - gameRenderWorld->FreeLightDef( guiLightHandle ); - guiLightHandle = -1; - } - if ( nozzleGlowHandle != -1 ) { - gameRenderWorld->FreeLightDef( nozzleGlowHandle ); - nozzleGlowHandle = -1; - } - - memset( &renderEntity, 0, sizeof( renderEntity ) ); - renderEntity.entityNum = entityNumber; - - renderEntity.noShadow = true; - renderEntity.noSelfShadow = true; - renderEntity.customSkin = NULL; - - // set default shader parms - renderEntity.shaderParms[ SHADERPARM_RED ] = 1.0f; - renderEntity.shaderParms[ SHADERPARM_GREEN ]= 1.0f; - renderEntity.shaderParms[ SHADERPARM_BLUE ] = 1.0f; - renderEntity.shaderParms[3] = 1.0f; - renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = 0.0f; - renderEntity.shaderParms[5] = 0.0f; - renderEntity.shaderParms[6] = 0.0f; - renderEntity.shaderParms[7] = 0.0f; - - if ( refSound.referenceSound ) { - refSound.referenceSound->Free( true ); - } - memset( &refSound, 0, sizeof( refSound_t ) ); - - // setting diversity to 0 results in no random sound. -1 indicates random. - refSound.diversity = -1.0f; - - if ( owner ) { - // don't spatialize the weapon sounds - refSound.listenerId = owner->GetListenerId(); - } - - // clear out the sounds from our spawnargs since we'll copy them from the weapon def - const idKeyValue *kv = spawnArgs.MatchPrefix( "snd_" ); - while( kv ) { - spawnArgs.Delete( kv->GetKey() ); - kv = spawnArgs.MatchPrefix( "snd_" ); - } - - hideTime = 300; - hideDistance = -15.0f; - hideStartTime = gameLocal.time - hideTime; - hideStart = 0.0f; - hideEnd = 0.0f; - hideOffset = 0.0f; - hide = false; - disabled = false; - - weaponSmoke = NULL; - weaponSmokeStartTime = 0; - continuousSmoke = false; - strikeSmoke = NULL; - strikeSmokeStartTime = 0; - strikePos.Zero(); - strikeAxis = mat3_identity; - nextStrikeFx = 0; - - icon = ""; - - playerViewAxis.Identity(); - playerViewOrigin.Zero(); - viewWeaponAxis.Identity(); - viewWeaponOrigin.Zero(); - muzzleAxis.Identity(); - muzzleOrigin.Zero(); - pushVelocity.Zero(); - - status = WP_HOLSTERED; - state = ""; - idealState = ""; - animBlendFrames = 0; - animDoneTime = 0; - - projectileDict.Clear(); - meleeDef = NULL; - meleeDefName = ""; - meleeDistance = 0.0f; - brassDict.Clear(); - - flashTime = 250; - lightOn = false; - silent_fire = false; - -#ifdef _D3XP - grabberState = -1; - grabber.Update( owner, true ); -#endif - - ammoType = 0; - ammoRequired = 0; - ammoClip = 0; - clipSize = 0; - lowAmmo = 0; - powerAmmo = false; - - kick_endtime = 0; - muzzle_kick_time = 0; - muzzle_kick_maxtime = 0; - muzzle_kick_angles.Zero(); - muzzle_kick_offset.Zero(); - - zoomFov = 90; - - barrelJointView = INVALID_JOINT; - flashJointView = INVALID_JOINT; - ejectJointView = INVALID_JOINT; - guiLightJointView = INVALID_JOINT; - ventLightJointView = INVALID_JOINT; - - barrelJointWorld = INVALID_JOINT; - flashJointWorld = INVALID_JOINT; - ejectJointWorld = INVALID_JOINT; - -#ifdef _D3XP - smokeJointView = INVALID_JOINT; - - //Clean up the weapon particles - for(int i = 0; i < weaponParticles.Num(); i++) { - WeaponParticle_t* part = weaponParticles.GetIndex(i); - if(!part->smoke) { - //Destroy the emitters - part->emitter->PostEventMS(&EV_Remove, 0 ); - } - } - weaponParticles.Clear(); - - //Clean up the weapon lights - for(int i = 0; i < weaponLights.Num(); i++) { - WeaponLight_t* light = weaponLights.GetIndex(i); - if ( light->lightHandle != -1 ) { - gameRenderWorld->FreeLightDef( light->lightHandle ); - } - } - weaponLights.Clear(); -#endif - - hasBloodSplat = false; - nozzleFx = false; - nozzleFxFade = 1500; - lastAttack = 0; - nozzleGlowHandle = -1; - nozzleGlowShader = NULL; - nozzleGlowRadius = 10; - nozzleGlowColor.Zero(); - - weaponAngleOffsetAverages = 0; - weaponAngleOffsetScale = 0.0f; - weaponAngleOffsetMax = 0.0f; - weaponOffsetTime = 0.0f; - weaponOffsetScale = 0.0f; - - allowDrop = true; - - animator.ClearAllAnims( gameLocal.time, 0 ); - FreeModelDef(); - - sndHum = NULL; - - isLinked = false; - projectileEnt = NULL; - - isFiring = false; -} - -/* -================ -idWeapon::InitWorldModel -================ -*/ -void idWeapon::InitWorldModel( const idDeclEntityDef *def ) { - idEntity *ent; - - ent = worldModel.GetEntity(); - - assert( ent ); - assert( def ); - - const char *model = def->dict.GetString( "model_world" ); - const char *attach = def->dict.GetString( "joint_attach" ); - - ent->SetSkin( NULL ); - if ( model[0] && attach[0] ) { - ent->Show(); - ent->SetModel( model ); - if ( ent->GetAnimator()->ModelDef() ) { - ent->SetSkin( ent->GetAnimator()->ModelDef()->GetDefaultSkin() ); - } - ent->GetPhysics()->SetContents( 0 ); - ent->GetPhysics()->SetClipModel( NULL, 1.0f ); - ent->BindToJoint( owner, attach, true ); - ent->GetPhysics()->SetOrigin( vec3_origin ); - ent->GetPhysics()->SetAxis( mat3_identity ); - - // supress model in player views, but allow it in mirrors and remote views - renderEntity_t *worldModelRenderEntity = ent->GetRenderEntity(); - if ( worldModelRenderEntity ) { - worldModelRenderEntity->suppressSurfaceInViewID = owner->entityNumber+1; - worldModelRenderEntity->suppressShadowInViewID = owner->entityNumber+1; - worldModelRenderEntity->suppressShadowInLightID = LIGHTID_VIEW_MUZZLE_FLASH + owner->entityNumber; - } - } else { - ent->SetModel( "" ); - ent->Hide(); - } - - flashJointWorld = ent->GetAnimator()->GetJointHandle( "flash" ); - barrelJointWorld = ent->GetAnimator()->GetJointHandle( "muzzle" ); - ejectJointWorld = ent->GetAnimator()->GetJointHandle( "eject" ); -} - -/* -================ -idWeapon::GetWeaponDef -================ -*/ -void idWeapon::GetWeaponDef( const char *objectname, int ammoinclip ) { - const char *shader; - const char *objectType; - const char *vmodel; - const char *guiName; - const char *projectileName; - const char *brassDefName; - const char *smokeName; - int ammoAvail; - - Clear(); - - if ( !objectname || !objectname[ 0 ] ) { - return; - } - - assert( owner ); - - weaponDef = gameLocal.FindEntityDef( objectname ); - - ammoType = GetAmmoNumForName( weaponDef->dict.GetString( "ammoType" ) ); - ammoRequired = weaponDef->dict.GetInt( "ammoRequired" ); - clipSize = weaponDef->dict.GetInt( "clipSize" ); - lowAmmo = weaponDef->dict.GetInt( "lowAmmo" ); - - icon = weaponDef->dict.GetString( "icon" ); - silent_fire = weaponDef->dict.GetBool( "silent_fire" ); - powerAmmo = weaponDef->dict.GetBool( "powerAmmo" ); - - muzzle_kick_time = SEC2MS( weaponDef->dict.GetFloat( "muzzle_kick_time" ) ); - muzzle_kick_maxtime = SEC2MS( weaponDef->dict.GetFloat( "muzzle_kick_maxtime" ) ); - muzzle_kick_angles = weaponDef->dict.GetAngles( "muzzle_kick_angles" ); - muzzle_kick_offset = weaponDef->dict.GetVector( "muzzle_kick_offset" ); - - hideTime = SEC2MS( weaponDef->dict.GetFloat( "hide_time", "0.3" ) ); - hideDistance = weaponDef->dict.GetFloat( "hide_distance", "-15" ); - - // muzzle smoke - smokeName = weaponDef->dict.GetString( "smoke_muzzle" ); - if ( *smokeName != '\0' ) { - weaponSmoke = static_cast( declManager->FindType( DECL_PARTICLE, smokeName ) ); - } else { - weaponSmoke = NULL; - } - continuousSmoke = weaponDef->dict.GetBool( "continuousSmoke" ); - weaponSmokeStartTime = ( continuousSmoke ) ? gameLocal.time : 0; - - smokeName = weaponDef->dict.GetString( "smoke_strike" ); - if ( *smokeName != '\0' ) { - strikeSmoke = static_cast( declManager->FindType( DECL_PARTICLE, smokeName ) ); - } else { - strikeSmoke = NULL; - } - strikeSmokeStartTime = 0; - strikePos.Zero(); - strikeAxis = mat3_identity; - nextStrikeFx = 0; - - // setup gui light - memset( &guiLight, 0, sizeof( guiLight ) ); - const char *guiLightShader = weaponDef->dict.GetString( "mtr_guiLightShader" ); - if ( *guiLightShader != '\0' ) { - guiLight.shader = declManager->FindMaterial( guiLightShader, false ); - guiLight.lightRadius[0] = guiLight.lightRadius[1] = guiLight.lightRadius[2] = 3; - guiLight.pointLight = true; - } - - // setup the view model - vmodel = weaponDef->dict.GetString( "model_view" ); - SetModel( vmodel ); - - // setup the world model - InitWorldModel( weaponDef ); - - // copy the sounds from the weapon view model def into out spawnargs - const idKeyValue *kv = weaponDef->dict.MatchPrefix( "snd_" ); - while( kv ) { - spawnArgs.Set( kv->GetKey(), kv->GetValue() ); - kv = weaponDef->dict.MatchPrefix( "snd_", kv ); - } - - // find some joints in the model for locating effects - barrelJointView = animator.GetJointHandle( "barrel" ); - flashJointView = animator.GetJointHandle( "flash" ); - ejectJointView = animator.GetJointHandle( "eject" ); - guiLightJointView = animator.GetJointHandle( "guiLight" ); - ventLightJointView = animator.GetJointHandle( "ventLight" ); - -#ifdef _D3XP - idStr smokeJoint = weaponDef->dict.GetString("smoke_joint"); - if(smokeJoint.Length() > 0) { - smokeJointView = animator.GetJointHandle( smokeJoint ); - } else { - smokeJointView = INVALID_JOINT; - } -#endif - - // get the projectile - projectileDict.Clear(); - - projectileName = weaponDef->dict.GetString( "def_projectile" ); - if ( projectileName[0] != '\0' ) { - const idDeclEntityDef *projectileDef = gameLocal.FindEntityDef( projectileName, false ); - if ( !projectileDef ) { - gameLocal.Warning( "Unknown projectile '%s' in weapon '%s'", projectileName, objectname ); - } else { - const char *spawnclass = projectileDef->dict.GetString( "spawnclass" ); - idTypeInfo *cls = idClass::GetClass( spawnclass ); - if ( !cls || !cls->IsType( idProjectile::Type ) ) { - gameLocal.Warning( "Invalid spawnclass '%s' on projectile '%s' (used by weapon '%s')", spawnclass, projectileName, objectname ); - } else { - projectileDict = projectileDef->dict; - } - } - } - - // set up muzzleflash render light - const idMaterial*flashShader; - idVec3 flashTarget; - idVec3 flashUp; - idVec3 flashRight; - float flashRadius; - bool flashPointLight; - - weaponDef->dict.GetString( "mtr_flashShader", "", &shader ); - flashShader = declManager->FindMaterial( shader, false ); - flashPointLight = weaponDef->dict.GetBool( "flashPointLight", "1" ); - weaponDef->dict.GetVector( "flashColor", "0 0 0", flashColor ); - flashRadius = (float)weaponDef->dict.GetInt( "flashRadius" ); // if 0, no light will spawn - flashTime = SEC2MS( weaponDef->dict.GetFloat( "flashTime", "0.25" ) ); - flashTarget = weaponDef->dict.GetVector( "flashTarget" ); - flashUp = weaponDef->dict.GetVector( "flashUp" ); - flashRight = weaponDef->dict.GetVector( "flashRight" ); - - memset( &muzzleFlash, 0, sizeof( muzzleFlash ) ); - muzzleFlash.lightId = LIGHTID_VIEW_MUZZLE_FLASH + owner->entityNumber; - muzzleFlash.allowLightInViewID = owner->entityNumber+1; - - // the weapon lights will only be in first person - guiLight.allowLightInViewID = owner->entityNumber+1; - nozzleGlow.allowLightInViewID = owner->entityNumber+1; - - muzzleFlash.pointLight = flashPointLight; - muzzleFlash.shader = flashShader; - muzzleFlash.shaderParms[ SHADERPARM_RED ] = flashColor[0]; - muzzleFlash.shaderParms[ SHADERPARM_GREEN ] = flashColor[1]; - muzzleFlash.shaderParms[ SHADERPARM_BLUE ] = flashColor[2]; - muzzleFlash.shaderParms[ SHADERPARM_TIMESCALE ] = 1.0f; - - muzzleFlash.lightRadius[0] = flashRadius; - muzzleFlash.lightRadius[1] = flashRadius; - muzzleFlash.lightRadius[2] = flashRadius; - - if ( !flashPointLight ) { - muzzleFlash.target = flashTarget; - muzzleFlash.up = flashUp; - muzzleFlash.right = flashRight; - muzzleFlash.end = flashTarget; - } - - // the world muzzle flash is the same, just positioned differently - worldMuzzleFlash = muzzleFlash; - worldMuzzleFlash.suppressLightInViewID = owner->entityNumber+1; - worldMuzzleFlash.allowLightInViewID = 0; - worldMuzzleFlash.lightId = LIGHTID_WORLD_MUZZLE_FLASH + owner->entityNumber; - - //----------------------------------- - - nozzleFx = weaponDef->dict.GetBool("nozzleFx"); - nozzleFxFade = weaponDef->dict.GetInt("nozzleFxFade", "1500"); - nozzleGlowColor = weaponDef->dict.GetVector("nozzleGlowColor", "1 1 1"); - nozzleGlowRadius = weaponDef->dict.GetFloat("nozzleGlowRadius", "10"); - weaponDef->dict.GetString( "mtr_nozzleGlowShader", "", &shader ); - nozzleGlowShader = declManager->FindMaterial( shader, false ); - - // get the melee damage def - meleeDistance = weaponDef->dict.GetFloat( "melee_distance" ); - meleeDefName = weaponDef->dict.GetString( "def_melee" ); - if ( meleeDefName.Length() ) { - meleeDef = gameLocal.FindEntityDef( meleeDefName, false ); - if ( !meleeDef ) { - gameLocal.Error( "Unknown melee '%s'", meleeDefName.c_str() ); - } - } - - // get the brass def - brassDict.Clear(); - brassDelay = weaponDef->dict.GetInt( "ejectBrassDelay", "0" ); - brassDefName = weaponDef->dict.GetString( "def_ejectBrass" ); - - if ( brassDefName[0] ) { - const idDeclEntityDef *brassDef = gameLocal.FindEntityDef( brassDefName, false ); - if ( !brassDef ) { - gameLocal.Warning( "Unknown brass '%s'", brassDefName ); - } else { - brassDict = brassDef->dict; - } - } - - if ( ( ammoType < 0 ) || ( ammoType >= AMMO_NUMTYPES ) ) { - gameLocal.Warning( "Unknown ammotype in object '%s'", objectname ); - } - - ammoClip = ammoinclip; - if ( ( ammoClip < 0 ) || ( ammoClip > clipSize ) ) { - // first time using this weapon so have it fully loaded to start - ammoClip = clipSize; - ammoAvail = owner->inventory.HasAmmo( ammoType, ammoRequired ); - if ( ammoClip > ammoAvail ) { - ammoClip = ammoAvail; - } -#ifdef _D3XP - //In D3XP we use ammo as soon as it is moved into the clip. This allows for weapons that share ammo - owner->inventory.UseAmmo(ammoType, ammoClip); -#endif - } - - renderEntity.gui[ 0 ] = NULL; - guiName = weaponDef->dict.GetString( "gui" ); - if ( guiName[0] ) { - renderEntity.gui[ 0 ] = uiManager->FindGui( guiName, true, false, true ); - } - - zoomFov = weaponDef->dict.GetInt( "zoomFov", "70" ); - berserk = weaponDef->dict.GetInt( "berserk", "2" ); - - weaponAngleOffsetAverages = weaponDef->dict.GetInt( "weaponAngleOffsetAverages", "10" ); - weaponAngleOffsetScale = weaponDef->dict.GetFloat( "weaponAngleOffsetScale", "0.25" ); - weaponAngleOffsetMax = weaponDef->dict.GetFloat( "weaponAngleOffsetMax", "10" ); - - weaponOffsetTime = weaponDef->dict.GetFloat( "weaponOffsetTime", "400" ); - weaponOffsetScale = weaponDef->dict.GetFloat( "weaponOffsetScale", "0.005" ); - - if ( !weaponDef->dict.GetString( "weapon_scriptobject", NULL, &objectType ) ) { - gameLocal.Error( "No 'weapon_scriptobject' set on '%s'.", objectname ); - } - - // setup script object - if ( !scriptObject.SetType( objectType ) ) { - gameLocal.Error( "Script object '%s' not found on weapon '%s'.", objectType, objectname ); - } - - WEAPON_ATTACK.LinkTo( scriptObject, "WEAPON_ATTACK" ); - WEAPON_RELOAD.LinkTo( scriptObject, "WEAPON_RELOAD" ); - WEAPON_NETRELOAD.LinkTo( scriptObject, "WEAPON_NETRELOAD" ); - WEAPON_NETENDRELOAD.LinkTo( scriptObject, "WEAPON_NETENDRELOAD" ); - WEAPON_NETFIRING.LinkTo( scriptObject, "WEAPON_NETFIRING" ); - WEAPON_RAISEWEAPON.LinkTo( scriptObject, "WEAPON_RAISEWEAPON" ); - WEAPON_LOWERWEAPON.LinkTo( scriptObject, "WEAPON_LOWERWEAPON" ); - - spawnArgs = weaponDef->dict; - - shader = spawnArgs.GetString( "snd_hum" ); - if ( shader && *shader ) { - sndHum = declManager->FindSound( shader ); - StartSoundShader( sndHum, SND_CHANNEL_BODY, 0, false, NULL ); - } - - isLinked = true; - - // call script object's constructor - ConstructScriptObject(); - - // make sure we have the correct skin - UpdateSkin(); - -#ifdef _D3XP - idEntity *ent = worldModel.GetEntity(); - DetermineTimeGroup( weaponDef->dict.GetBool( "slowmo", "0" ) ); - if ( ent ) { - ent->DetermineTimeGroup( weaponDef->dict.GetBool( "slowmo", "0" ) ); - } - - //Initialize the particles - if ( !gameLocal.isMultiplayer ) { - - const idKeyValue *pkv = weaponDef->dict.MatchPrefix( "weapon_particle", NULL ); - while( pkv ) { - WeaponParticle_t newParticle; - memset( &newParticle, 0, sizeof( newParticle ) ); - - idStr name = pkv->GetValue(); - - strcpy(newParticle.name, name.c_str()); - - idStr jointName = weaponDef->dict.GetString(va("%s_joint", name.c_str())); - newParticle.joint = animator.GetJointHandle(jointName.c_str()); - newParticle.smoke = weaponDef->dict.GetBool(va("%s_smoke", name.c_str())); - newParticle.active = false; - newParticle.startTime = 0; - - idStr particle = weaponDef->dict.GetString(va("%s_particle", name.c_str())); - strcpy(newParticle.particlename, particle.c_str()); - - if(newParticle.smoke) { - newParticle.particle = static_cast( declManager->FindType( DECL_PARTICLE, particle, false ) ); - } else { - idDict args; - - const idDeclEntityDef *emitterDef = gameLocal.FindEntityDef( "func_emitter", false ); - args = emitterDef->dict; - args.Set("model", particle.c_str()); - args.SetBool("start_off", true); - - idEntity* ent; - gameLocal.SpawnEntityDef(args, &ent, false); - newParticle.emitter = (idFuncEmitter*)ent; - - newParticle.emitter->BecomeActive(TH_THINK); - } - - weaponParticles.Set(name.c_str(), newParticle); - - pkv = weaponDef->dict.MatchPrefix( "weapon_particle", pkv ); - } - - const idKeyValue *lkv = weaponDef->dict.MatchPrefix( "weapon_light", NULL ); - while( lkv ) { - WeaponLight_t newLight; - memset( &newLight, 0, sizeof( newLight ) ); - - newLight.lightHandle = -1; - newLight.active = false; - newLight.startTime = 0; - - idStr name = lkv->GetValue(); - strcpy(newLight.name, name.c_str()); - - idStr jointName = weaponDef->dict.GetString(va("%s_joint", name.c_str())); - newLight.joint = animator.GetJointHandle(jointName.c_str()); - - idStr shader = weaponDef->dict.GetString(va("%s_shader", name.c_str())); - newLight.light.shader = declManager->FindMaterial( shader, false ); - - float radius = weaponDef->dict.GetFloat(va("%s_radius", name.c_str())); - newLight.light.lightRadius[0] = newLight.light.lightRadius[1] = newLight.light.lightRadius[2] = radius; - newLight.light.pointLight = true; - newLight.light.noShadows = true; - - newLight.light.allowLightInViewID = owner->entityNumber+1; - - weaponLights.Set(name.c_str(), newLight); - - lkv = weaponDef->dict.MatchPrefix( "weapon_light", lkv ); - } - } -#endif -} - -/*********************************************************************** - - GUIs - -***********************************************************************/ - -/* -================ -idWeapon::Icon -================ -*/ -const char *idWeapon::Icon( void ) const { - return icon; -} - -/* -================ -idWeapon::UpdateGUI -================ -*/ -void idWeapon::UpdateGUI( void ) { - if ( !renderEntity.gui[ 0 ] ) { - return; - } - - if ( status == WP_HOLSTERED ) { - return; - } - - if ( owner->weaponGone ) { - // dropping weapons was implemented wierd, so we have to not update the gui when it happens or we'll get a negative ammo count - return; - } - - if ( gameLocal.localClientNum != owner->entityNumber ) { - // if updating the hud for a followed client - if ( gameLocal.localClientNum >= 0 && gameLocal.entities[ gameLocal.localClientNum ] && gameLocal.entities[ gameLocal.localClientNum ]->IsType( idPlayer::Type ) ) { - idPlayer *p = static_cast< idPlayer * >( gameLocal.entities[ gameLocal.localClientNum ] ); - if ( !p->spectating || p->spectator != owner->entityNumber ) { - return; - } - } else { - return; - } - } - - int inclip = AmmoInClip(); - int ammoamount = AmmoAvailable(); - - if ( ammoamount < 0 ) { - // show infinite ammo - renderEntity.gui[ 0 ]->SetStateString( "player_ammo", "" ); - } else { - // show remaining ammo -#ifdef _D3XP - renderEntity.gui[ 0 ]->SetStateString( "player_totalammo", va( "%i", ammoamount) ); -#else - renderEntity.gui[ 0 ]->SetStateString( "player_totalammo", va( "%i", ammoamount - inclip) ); -#endif - renderEntity.gui[ 0 ]->SetStateString( "player_ammo", ClipSize() ? va( "%i", inclip ) : "--" ); - renderEntity.gui[ 0 ]->SetStateString( "player_clips", ClipSize() ? va("%i", ammoamount / ClipSize()) : "--" ); - -#ifdef _D3XP - renderEntity.gui[ 0 ]->SetStateString( "player_allammo", va( "%i/%i", inclip, ammoamount ) ); -#else - renderEntity.gui[ 0 ]->SetStateString( "player_allammo", va( "%i/%i", inclip, ammoamount - inclip ) ); -#endif - } - renderEntity.gui[ 0 ]->SetStateBool( "player_ammo_empty", ( ammoamount == 0 ) ); - renderEntity.gui[ 0 ]->SetStateBool( "player_clip_empty", ( inclip == 0 ) ); - renderEntity.gui[ 0 ]->SetStateBool( "player_clip_low", ( inclip <= lowAmmo ) ); - -#ifdef _D3XP - //Let the HUD know the total amount of ammo regardless of the ammo required value - renderEntity.gui[ 0 ]->SetStateString( "player_ammo_count", va("%i", AmmoCount())); - - //Grabber Gui Info - renderEntity.gui[ 0 ]->SetStateString( "grabber_state", va("%i", grabberState)); -#endif -} - -/*********************************************************************** - - Model and muzzleflash - -***********************************************************************/ - -/* -================ -idWeapon::UpdateFlashPosition -================ -*/ -void idWeapon::UpdateFlashPosition( void ) { - // the flash has an explicit joint for locating it - GetGlobalJointTransform( true, flashJointView, muzzleFlash.origin, muzzleFlash.axis ); - - // if the desired point is inside or very close to a wall, back it up until it is clear - idVec3 start = muzzleFlash.origin - playerViewAxis[0] * 16; - idVec3 end = muzzleFlash.origin + playerViewAxis[0] * 8; - trace_t tr; - gameLocal.clip.TracePoint( tr, start, end, MASK_SHOT_RENDERMODEL, owner ); - // be at least 8 units away from a solid - muzzleFlash.origin = tr.endpos - playerViewAxis[0] * 8; - - // put the world muzzle flash on the end of the joint, no matter what - GetGlobalJointTransform( false, flashJointWorld, worldMuzzleFlash.origin, worldMuzzleFlash.axis ); -} - -/* -================ -idWeapon::MuzzleFlashLight -================ -*/ -void idWeapon::MuzzleFlashLight( void ) { - - if ( !lightOn && ( !g_muzzleFlash.GetBool() || !muzzleFlash.lightRadius[0] ) ) { - return; - } - - if ( flashJointView == INVALID_JOINT ) { - return; - } - - UpdateFlashPosition(); - - // these will be different each fire - muzzleFlash.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time ); - muzzleFlash.shaderParms[ SHADERPARM_DIVERSITY ] = renderEntity.shaderParms[ SHADERPARM_DIVERSITY ]; - - worldMuzzleFlash.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time ); - worldMuzzleFlash.shaderParms[ SHADERPARM_DIVERSITY ] = renderEntity.shaderParms[ SHADERPARM_DIVERSITY ]; - - // the light will be removed at this time - muzzleFlashEnd = gameLocal.time + flashTime; - - if ( muzzleFlashHandle != -1 ) { - gameRenderWorld->UpdateLightDef( muzzleFlashHandle, &muzzleFlash ); - gameRenderWorld->UpdateLightDef( worldMuzzleFlashHandle, &worldMuzzleFlash ); - } else { - muzzleFlashHandle = gameRenderWorld->AddLightDef( &muzzleFlash ); - worldMuzzleFlashHandle = gameRenderWorld->AddLightDef( &worldMuzzleFlash ); - } -} - -/* -================ -idWeapon::UpdateSkin -================ -*/ -bool idWeapon::UpdateSkin( void ) { - const function_t *func; - - if ( !isLinked ) { - return false; - } - - func = scriptObject.GetFunction( "UpdateSkin" ); - if ( !func ) { - common->Warning( "Can't find function 'UpdateSkin' in object '%s'", scriptObject.GetTypeName() ); - return false; - } - - // use the frameCommandThread since it's safe to use outside of framecommands - gameLocal.frameCommandThread->CallFunction( this, func, true ); - gameLocal.frameCommandThread->Execute(); - - return true; -} - -/* -================ -idWeapon::SetModel -================ -*/ -void idWeapon::SetModel( const char *modelname ) { - assert( modelname ); - - if ( modelDefHandle >= 0 ) { - gameRenderWorld->RemoveDecals( modelDefHandle ); - } - - renderEntity.hModel = animator.SetModel( modelname ); - if ( renderEntity.hModel ) { - renderEntity.customSkin = animator.ModelDef()->GetDefaultSkin(); - animator.GetJoints( &renderEntity.numJoints, &renderEntity.joints ); - } else { - renderEntity.customSkin = NULL; - renderEntity.callback = NULL; - renderEntity.numJoints = 0; - renderEntity.joints = NULL; - } - - // hide the model until an animation is played - Hide(); -} - -/* -================ -idWeapon::GetGlobalJointTransform - -This returns the offset and axis of a weapon bone in world space, suitable for attaching models or lights -================ -*/ -bool idWeapon::GetGlobalJointTransform( bool viewModel, const jointHandle_t jointHandle, idVec3 &offset, idMat3 &axis ) { - if ( viewModel ) { - // view model - if ( animator.GetJointTransform( jointHandle, gameLocal.time, offset, axis ) ) { - offset = offset * viewWeaponAxis + viewWeaponOrigin; - axis = axis * viewWeaponAxis; - return true; - } - } else { - // world model - if ( worldModel.GetEntity() && worldModel.GetEntity()->GetAnimator()->GetJointTransform( jointHandle, gameLocal.time, offset, axis ) ) { - offset = worldModel.GetEntity()->GetPhysics()->GetOrigin() + offset * worldModel.GetEntity()->GetPhysics()->GetAxis(); - axis = axis * worldModel.GetEntity()->GetPhysics()->GetAxis(); - return true; - } - } - offset = viewWeaponOrigin; - axis = viewWeaponAxis; - return false; -} - -/* -================ -idWeapon::SetPushVelocity -================ -*/ -void idWeapon::SetPushVelocity( const idVec3 &pushVelocity ) { - this->pushVelocity = pushVelocity; -} - - -/*********************************************************************** - - State control/player interface - -***********************************************************************/ - -/* -================ -idWeapon::Think -================ -*/ -void idWeapon::Think( void ) { - // do nothing because the present is called from the player through PresentWeapon -} - -/* -================ -idWeapon::Raise -================ -*/ -void idWeapon::Raise( void ) { - if ( isLinked ) { - WEAPON_RAISEWEAPON = true; - } -} - -/* -================ -idWeapon::PutAway -================ -*/ -void idWeapon::PutAway( void ) { - hasBloodSplat = false; - if ( isLinked ) { - WEAPON_LOWERWEAPON = true; - } -} - -/* -================ -idWeapon::Reload -NOTE: this is only for impulse-triggered reload, auto reload is scripted -================ -*/ -void idWeapon::Reload( void ) { - if ( isLinked ) { - WEAPON_RELOAD = true; - } -} - -/* -================ -idWeapon::LowerWeapon -================ -*/ -void idWeapon::LowerWeapon( void ) { - if ( !hide ) { - hideStart = 0.0f; - hideEnd = hideDistance; - if ( gameLocal.time - hideStartTime < hideTime ) { - hideStartTime = gameLocal.time - ( hideTime - ( gameLocal.time - hideStartTime ) ); - } else { - hideStartTime = gameLocal.time; - } - hide = true; - } -} - -/* -================ -idWeapon::RaiseWeapon -================ -*/ -void idWeapon::RaiseWeapon( void ) { - Show(); - - if ( hide ) { - hideStart = hideDistance; - hideEnd = 0.0f; - if ( gameLocal.time - hideStartTime < hideTime ) { - hideStartTime = gameLocal.time - ( hideTime - ( gameLocal.time - hideStartTime ) ); - } else { - hideStartTime = gameLocal.time; - } - hide = false; - } -} - -/* -================ -idWeapon::HideWeapon -================ -*/ -void idWeapon::HideWeapon( void ) { - Hide(); - if ( worldModel.GetEntity() ) { - worldModel.GetEntity()->Hide(); - } - muzzleFlashEnd = 0; -} - -/* -================ -idWeapon::ShowWeapon -================ -*/ -void idWeapon::ShowWeapon( void ) { - Show(); - if ( worldModel.GetEntity() ) { - worldModel.GetEntity()->Show(); - } - if ( lightOn ) { - MuzzleFlashLight(); - } -} - -/* -================ -idWeapon::HideWorldModel -================ -*/ -void idWeapon::HideWorldModel( void ) { - if ( worldModel.GetEntity() ) { - worldModel.GetEntity()->Hide(); - } -} - -/* -================ -idWeapon::ShowWorldModel -================ -*/ -void idWeapon::ShowWorldModel( void ) { - if ( worldModel.GetEntity() ) { - worldModel.GetEntity()->Show(); - } -} - -/* -================ -idWeapon::OwnerDied -================ -*/ -void idWeapon::OwnerDied( void ) { - if ( isLinked ) { - SetState( "OwnerDied", 0 ); - thread->Execute(); - -#ifdef _D3XP - // Update the grabber effects - if ( /*!gameLocal.isMultiplayer &&*/ grabberState != -1 ) { - grabber.Update( owner, hide ); - } -#endif - } - - Hide(); - if ( worldModel.GetEntity() ) { - worldModel.GetEntity()->Hide(); - } - - // don't clear the weapon immediately since the owner might have killed himself by firing the weapon - // within the current stack frame - PostEventMS( &EV_Weapon_Clear, 0 ); -} - -/* -================ -idWeapon::BeginAttack -================ -*/ -void idWeapon::BeginAttack( void ) { - if ( status != WP_OUTOFAMMO ) { - lastAttack = gameLocal.time; - } - - if ( !isLinked ) { - return; - } - - if ( !WEAPON_ATTACK ) { - if ( sndHum && grabberState == -1 ) { // _D3XP :: don't stop grabber hum - StopSound( SND_CHANNEL_BODY, false ); - } - } - WEAPON_ATTACK = true; -} - -/* -================ -idWeapon::EndAttack -================ -*/ -void idWeapon::EndAttack( void ) { - if ( !WEAPON_ATTACK.IsLinked() ) { - return; - } - if ( WEAPON_ATTACK ) { - WEAPON_ATTACK = false; - if ( sndHum && grabberState == -1 ) { // _D3XP :: don't stop grabber hum - StartSoundShader( sndHum, SND_CHANNEL_BODY, 0, false, NULL ); - } - } -} - -/* -================ -idWeapon::isReady -================ -*/ -bool idWeapon::IsReady( void ) const { - return !hide && !IsHidden() && ( ( status == WP_RELOAD ) || ( status == WP_READY ) || ( status == WP_OUTOFAMMO ) ); -} - -/* -================ -idWeapon::IsReloading -================ -*/ -bool idWeapon::IsReloading( void ) const { - return ( status == WP_RELOAD ); -} - -/* -================ -idWeapon::IsHolstered -================ -*/ -bool idWeapon::IsHolstered( void ) const { - return ( status == WP_HOLSTERED ); -} - -/* -================ -idWeapon::ShowCrosshair -================ -*/ -bool idWeapon::ShowCrosshair( void ) const { - return !( state == idStr( WP_RISING ) || state == idStr( WP_LOWERING ) || state == idStr( WP_HOLSTERED ) ); -} - -/* -===================== -idWeapon::CanDrop -===================== -*/ -bool idWeapon::CanDrop( void ) const { - if ( !weaponDef || !worldModel.GetEntity() ) { - return false; - } - const char *classname = weaponDef->dict.GetString( "def_dropItem" ); - if ( !classname[ 0 ] ) { - return false; - } - return true; -} - -/* -================ -idWeapon::WeaponStolen -================ -*/ -void idWeapon::WeaponStolen( void ) { - assert( !gameLocal.isClient ); - if ( projectileEnt ) { - if ( isLinked ) { - SetState( "WeaponStolen", 0 ); - thread->Execute(); - } - projectileEnt = NULL; - } - - // set to holstered so we can switch weapons right away - status = WP_HOLSTERED; - - HideWeapon(); -} - -/* -===================== -idWeapon::DropItem -===================== -*/ -idEntity * idWeapon::DropItem( const idVec3 &velocity, int activateDelay, int removeDelay, bool died ) { - if ( !weaponDef || !worldModel.GetEntity() ) { - return NULL; - } - if ( !allowDrop ) { - return NULL; - } - const char *classname = weaponDef->dict.GetString( "def_dropItem" ); - if ( !classname[0] ) { - return NULL; - } - StopSound( SND_CHANNEL_BODY, true ); - StopSound( SND_CHANNEL_BODY3, true ); - - return idMoveableItem::DropItem( classname, worldModel.GetEntity()->GetPhysics()->GetOrigin(), worldModel.GetEntity()->GetPhysics()->GetAxis(), velocity, activateDelay, removeDelay ); -} - -/*********************************************************************** - - Script state management - -***********************************************************************/ - -/* -===================== -idWeapon::SetState -===================== -*/ -void idWeapon::SetState( const char *statename, int blendFrames ) { - const function_t *func; - - if ( !isLinked ) { - return; - } - - func = scriptObject.GetFunction( statename ); - if ( !func ) { - assert( 0 ); - gameLocal.Error( "Can't find function '%s' in object '%s'", statename, scriptObject.GetTypeName() ); - } - - thread->CallFunction( this, func, true ); - state = statename; - - animBlendFrames = blendFrames; - if ( g_debugWeapon.GetBool() ) { - gameLocal.Printf( "%d: weapon state : %s\n", gameLocal.time, statename ); - } - - idealState = ""; -} - - -/*********************************************************************** - - Particles/Effects - -***********************************************************************/ - -/* -================ -idWeapon::UpdateNozzelFx -================ -*/ -void idWeapon::UpdateNozzleFx( void ) { - if ( !nozzleFx ) { - return; - } - - // - // shader parms - // - int la = gameLocal.time - lastAttack + 1; - float s = 1.0f; - float l = 0.0f; - if ( la < nozzleFxFade ) { - s = ((float)la / nozzleFxFade); - l = 1.0f - s; - } - renderEntity.shaderParms[5] = s; - renderEntity.shaderParms[6] = l; - - if ( ventLightJointView == INVALID_JOINT ) { - return; - } - - // - // vent light - // - if ( nozzleGlowHandle == -1 ) { - memset(&nozzleGlow, 0, sizeof(nozzleGlow)); - if ( owner ) { - nozzleGlow.allowLightInViewID = owner->entityNumber+1; - } - nozzleGlow.pointLight = true; - nozzleGlow.noShadows = true; - nozzleGlow.lightRadius.x = nozzleGlowRadius; - nozzleGlow.lightRadius.y = nozzleGlowRadius; - nozzleGlow.lightRadius.z = nozzleGlowRadius; - nozzleGlow.shader = nozzleGlowShader; - nozzleGlow.shaderParms[ SHADERPARM_TIMESCALE ] = 1.0f; - nozzleGlow.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time ); - GetGlobalJointTransform( true, ventLightJointView, nozzleGlow.origin, nozzleGlow.axis ); - nozzleGlowHandle = gameRenderWorld->AddLightDef(&nozzleGlow); - } - - GetGlobalJointTransform( true, ventLightJointView, nozzleGlow.origin, nozzleGlow.axis ); - - nozzleGlow.shaderParms[ SHADERPARM_RED ] = nozzleGlowColor.x * s; - nozzleGlow.shaderParms[ SHADERPARM_GREEN ] = nozzleGlowColor.y * s; - nozzleGlow.shaderParms[ SHADERPARM_BLUE ] = nozzleGlowColor.z * s; - gameRenderWorld->UpdateLightDef(nozzleGlowHandle, &nozzleGlow); -} - - -/* -================ -idWeapon::BloodSplat -================ -*/ -bool idWeapon::BloodSplat( float size ) { - float s, c; - idMat3 localAxis, axistemp; - idVec3 localOrigin, normal; - - if ( hasBloodSplat ) { - return true; - } - - hasBloodSplat = true; - - if ( modelDefHandle < 0 ) { - return false; - } - - if ( !GetGlobalJointTransform( true, ejectJointView, localOrigin, localAxis ) ) { - return false; - } - - localOrigin[0] += gameLocal.random.RandomFloat() * -10.0f; - localOrigin[1] += gameLocal.random.RandomFloat() * 1.0f; - localOrigin[2] += gameLocal.random.RandomFloat() * -2.0f; - - normal = idVec3( gameLocal.random.CRandomFloat(), -gameLocal.random.RandomFloat(), -1 ); - normal.Normalize(); - - idMath::SinCos16( gameLocal.random.RandomFloat() * idMath::TWO_PI, s, c ); - - localAxis[2] = -normal; - localAxis[2].NormalVectors( axistemp[0], axistemp[1] ); - localAxis[0] = axistemp[ 0 ] * c + axistemp[ 1 ] * -s; - localAxis[1] = axistemp[ 0 ] * -s + axistemp[ 1 ] * -c; - - localAxis[0] *= 1.0f / size; - localAxis[1] *= 1.0f / size; - - idPlane localPlane[2]; - - localPlane[0] = localAxis[0]; - localPlane[0][3] = -(localOrigin * localAxis[0]) + 0.5f; - - localPlane[1] = localAxis[1]; - localPlane[1][3] = -(localOrigin * localAxis[1]) + 0.5f; - - const idMaterial *mtr = declManager->FindMaterial( "textures/decals/duffysplatgun" ); - - gameRenderWorld->ProjectOverlay( modelDefHandle, localPlane, mtr ); - - return true; -} - - -/*********************************************************************** - - Visual presentation - -***********************************************************************/ - -/* -================ -idWeapon::MuzzleRise - -The machinegun and chaingun will incrementally back up as they are being fired -================ -*/ -void idWeapon::MuzzleRise( idVec3 &origin, idMat3 &axis ) { - int time; - float amount; - idAngles ang; - idVec3 offset; - - time = kick_endtime - gameLocal.time; - if ( time <= 0 ) { - return; - } - - if ( muzzle_kick_maxtime <= 0 ) { - return; - } - - if ( time > muzzle_kick_maxtime ) { - time = muzzle_kick_maxtime; - } - - amount = ( float )time / ( float )muzzle_kick_maxtime; - ang = muzzle_kick_angles * amount; - offset = muzzle_kick_offset * amount; - - origin = origin - axis * offset; - axis = ang.ToMat3() * axis; -} - -/* -================ -idWeapon::ConstructScriptObject - -Called during idEntity::Spawn. Calls the constructor on the script object. -Can be overridden by subclasses when a thread doesn't need to be allocated. -================ -*/ -idThread *idWeapon::ConstructScriptObject( void ) { - const function_t *constructor; - - thread->EndThread(); - - // call script object's constructor - constructor = scriptObject.GetConstructor(); - if ( !constructor ) { - gameLocal.Error( "Missing constructor on '%s' for weapon", scriptObject.GetTypeName() ); - } - - // init the script object's data - scriptObject.ClearObject(); - thread->CallFunction( this, constructor, true ); - thread->Execute(); - - return thread; -} - -/* -================ -idWeapon::DeconstructScriptObject - -Called during idEntity::~idEntity. Calls the destructor on the script object. -Can be overridden by subclasses when a thread doesn't need to be allocated. -Not called during idGameLocal::MapShutdown. -================ -*/ -void idWeapon::DeconstructScriptObject( void ) { - const function_t *destructor; - - if ( !thread ) { - return; - } - - // don't bother calling the script object's destructor on map shutdown - if ( gameLocal.GameState() == GAMESTATE_SHUTDOWN ) { - return; - } - - thread->EndThread(); - - // call script object's destructor - destructor = scriptObject.GetDestructor(); - if ( destructor ) { - // start a thread that will run immediately and end - thread->CallFunction( this, destructor, true ); - thread->Execute(); - thread->EndThread(); - } - - // clear out the object's memory - scriptObject.ClearObject(); -} - -/* -================ -idWeapon::UpdateScript -================ -*/ -void idWeapon::UpdateScript( void ) { - int count; - - if ( !isLinked ) { - return; - } - - // only update the script on new frames - if ( !gameLocal.isNewFrame ) { - return; - } - - if ( idealState.Length() ) { - SetState( idealState, animBlendFrames ); - } - - // update script state, which may call Event_LaunchProjectiles, among other things - count = 10; - while( ( thread->Execute() || idealState.Length() ) && count-- ) { - // happens for weapons with no clip (like grenades) - if ( idealState.Length() ) { - SetState( idealState, animBlendFrames ); - } - } - - WEAPON_RELOAD = false; -} - -/* -================ -idWeapon::AlertMonsters -================ -*/ -void idWeapon::AlertMonsters( void ) { - trace_t tr; - idEntity *ent; - idVec3 end = muzzleFlash.origin + muzzleFlash.axis * muzzleFlash.target; - - gameLocal.clip.TracePoint( tr, muzzleFlash.origin, end, CONTENTS_OPAQUE | MASK_SHOT_RENDERMODEL | CONTENTS_FLASHLIGHT_TRIGGER, owner ); - if ( g_debugWeapon.GetBool() ) { - gameRenderWorld->DebugLine( colorYellow, muzzleFlash.origin, end, 0 ); - gameRenderWorld->DebugArrow( colorGreen, muzzleFlash.origin, tr.endpos, 2, 0 ); - } - - if ( tr.fraction < 1.0f ) { - ent = gameLocal.GetTraceEntity( tr ); - if ( ent->IsType( idAI::Type ) ) { - static_cast( ent )->TouchedByFlashlight( owner ); - } else if ( ent->IsType( idTrigger::Type ) ) { - ent->Signal( SIG_TOUCH ); - ent->ProcessEvent( &EV_Touch, owner, &tr ); - } - } - - // jitter the trace to try to catch cases where a trace down the center doesn't hit the monster - end += muzzleFlash.axis * muzzleFlash.right * idMath::Sin16( MS2SEC( gameLocal.time ) * 31.34f ); - end += muzzleFlash.axis * muzzleFlash.up * idMath::Sin16( MS2SEC( gameLocal.time ) * 12.17f ); - gameLocal.clip.TracePoint( tr, muzzleFlash.origin, end, CONTENTS_OPAQUE | MASK_SHOT_RENDERMODEL | CONTENTS_FLASHLIGHT_TRIGGER, owner ); - if ( g_debugWeapon.GetBool() ) { - gameRenderWorld->DebugLine( colorYellow, muzzleFlash.origin, end, 0 ); - gameRenderWorld->DebugArrow( colorGreen, muzzleFlash.origin, tr.endpos, 2, 0 ); - } - - if ( tr.fraction < 1.0f ) { - ent = gameLocal.GetTraceEntity( tr ); - if ( ent->IsType( idAI::Type ) ) { - static_cast( ent )->TouchedByFlashlight( owner ); - } else if ( ent->IsType( idTrigger::Type ) ) { - ent->Signal( SIG_TOUCH ); - ent->ProcessEvent( &EV_Touch, owner, &tr ); - } - } -} - -/* -================ -idWeapon::PresentWeapon -================ -*/ -void idWeapon::PresentWeapon( bool showViewModel ) { - playerViewOrigin = owner->firstPersonViewOrigin; - playerViewAxis = owner->firstPersonViewAxis; - - // calculate weapon position based on player movement bobbing - owner->CalculateViewWeaponPos( viewWeaponOrigin, viewWeaponAxis ); - - // hide offset is for dropping the gun when approaching a GUI or NPC - // This is simpler to manage than doing the weapon put-away animation - if ( gameLocal.time - hideStartTime < hideTime ) { - float frac = ( float )( gameLocal.time - hideStartTime ) / ( float )hideTime; - if ( hideStart < hideEnd ) { - frac = 1.0f - frac; - frac = 1.0f - frac * frac; - } else { - frac = frac * frac; - } - hideOffset = hideStart + ( hideEnd - hideStart ) * frac; - } else { - hideOffset = hideEnd; - if ( hide && disabled ) { - Hide(); - } - } - viewWeaponOrigin += hideOffset * viewWeaponAxis[ 2 ]; - - // kick up based on repeat firing - MuzzleRise( viewWeaponOrigin, viewWeaponAxis ); - - // set the physics position and orientation - GetPhysics()->SetOrigin( viewWeaponOrigin ); - GetPhysics()->SetAxis( viewWeaponAxis ); - UpdateVisuals(); - - // update the weapon script - UpdateScript(); - - UpdateGUI(); - - // update animation - UpdateAnimation(); - - // only show the surface in player view - renderEntity.allowSurfaceInViewID = owner->entityNumber+1; - - // crunch the depth range so it never pokes into walls this breaks the machine gun gui - renderEntity.weaponDepthHack = true; - - // present the model - if ( showViewModel ) { - Present(); - } else { - FreeModelDef(); - } - - if ( worldModel.GetEntity() && worldModel.GetEntity()->GetRenderEntity() ) { - // deal with the third-person visible world model - // don't show shadows of the world model in first person - if ( gameLocal.isMultiplayer || g_showPlayerShadow.GetBool() || pm_thirdPerson.GetBool() ) { - worldModel.GetEntity()->GetRenderEntity()->suppressShadowInViewID = 0; - } else { - worldModel.GetEntity()->GetRenderEntity()->suppressShadowInViewID = owner->entityNumber+1; - worldModel.GetEntity()->GetRenderEntity()->suppressShadowInLightID = LIGHTID_VIEW_MUZZLE_FLASH + owner->entityNumber; - } - } - - if ( nozzleFx ) { - UpdateNozzleFx(); - } - - // muzzle smoke - if ( showViewModel && !disabled && weaponSmoke && ( weaponSmokeStartTime != 0 ) ) { - // use the barrel joint if available - -#ifdef _D3XP - if(smokeJointView != INVALID_JOINT) { - GetGlobalJointTransform( true, smokeJointView, muzzleOrigin, muzzleAxis ); - } else if (barrelJointView != INVALID_JOINT) { - GetGlobalJointTransform( true, barrelJointView, muzzleOrigin, muzzleAxis ); -#else - if ( barrelJointView ) { - GetGlobalJointTransform( true, barrelJointView, muzzleOrigin, muzzleAxis ); -#endif - } else { - // default to going straight out the view - muzzleOrigin = playerViewOrigin; - muzzleAxis = playerViewAxis; - } - // spit out a particle - if ( !gameLocal.smokeParticles->EmitSmoke( weaponSmoke, weaponSmokeStartTime, gameLocal.random.RandomFloat(), muzzleOrigin, muzzleAxis, timeGroup /*_D3XP*/ ) ) { - weaponSmokeStartTime = ( continuousSmoke ) ? gameLocal.time : 0; - } - } - - if ( showViewModel && strikeSmoke && strikeSmokeStartTime != 0 ) { - // spit out a particle - if ( !gameLocal.smokeParticles->EmitSmoke( strikeSmoke, strikeSmokeStartTime, gameLocal.random.RandomFloat(), strikePos, strikeAxis, timeGroup /*_D3XP*/ ) ) { - strikeSmokeStartTime = 0; - } - } - -#ifdef _D3XP - if ( showViewModel && !hide ) { - - for( int i = 0; i < weaponParticles.Num(); i++ ) { - WeaponParticle_t* part = weaponParticles.GetIndex(i); - - if(part->active) { - if(part->smoke) { - if(part->joint != INVALID_JOINT) { - GetGlobalJointTransform( true, part->joint, muzzleOrigin, muzzleAxis ); - } else { - // default to going straight out the view - muzzleOrigin = playerViewOrigin; - muzzleAxis = playerViewAxis; - } - if ( !gameLocal.smokeParticles->EmitSmoke( part->particle, part->startTime, gameLocal.random.RandomFloat(), muzzleOrigin, muzzleAxis, timeGroup /*_D3XP*/ ) ) { - part->active = false; // all done - part->startTime = 0; - } - } else { - //Manually update the position of the emitter so it follows the weapon - renderEntity_t* rendEnt = part->emitter->GetRenderEntity(); - GetGlobalJointTransform( true, part->joint, rendEnt->origin, rendEnt->axis ); - - if ( part->emitter->GetModelDefHandle() != -1 ) { - gameRenderWorld->UpdateEntityDef( part->emitter->GetModelDefHandle(), rendEnt ); - } - } - } - } - - for(int i = 0; i < weaponLights.Num(); i++) { - WeaponLight_t* light = weaponLights.GetIndex(i); - - if(light->active) { - - GetGlobalJointTransform( true, light->joint, light->light.origin, light->light.axis ); - if ( ( light->lightHandle != -1 ) ) { - gameRenderWorld->UpdateLightDef( light->lightHandle, &light->light ); - } else { - light->lightHandle = gameRenderWorld->AddLightDef( &light->light ); - } - } - } - } - - // Update the grabber effects - if ( grabberState != -1 ) { - grabberState = grabber.Update( owner, hide ); - } -#endif - - // remove the muzzle flash light when it's done - if ( ( !lightOn && ( gameLocal.time >= muzzleFlashEnd ) ) || IsHidden() ) { - if ( muzzleFlashHandle != -1 ) { - gameRenderWorld->FreeLightDef( muzzleFlashHandle ); - muzzleFlashHandle = -1; - } - if ( worldMuzzleFlashHandle != -1 ) { - gameRenderWorld->FreeLightDef( worldMuzzleFlashHandle ); - worldMuzzleFlashHandle = -1; - } - } - - // update the muzzle flash light, so it moves with the gun - if ( muzzleFlashHandle != -1 ) { - UpdateFlashPosition(); - gameRenderWorld->UpdateLightDef( muzzleFlashHandle, &muzzleFlash ); - gameRenderWorld->UpdateLightDef( worldMuzzleFlashHandle, &worldMuzzleFlash ); - - // wake up monsters with the flashlight - if ( !gameLocal.isMultiplayer && lightOn && !owner->fl.notarget ) { - AlertMonsters(); - } - } - - // update the gui light - if ( guiLight.lightRadius[0] && guiLightJointView != INVALID_JOINT ) { - GetGlobalJointTransform( true, guiLightJointView, guiLight.origin, guiLight.axis ); - - if ( ( guiLightHandle != -1 ) ) { - gameRenderWorld->UpdateLightDef( guiLightHandle, &guiLight ); - } else { - guiLightHandle = gameRenderWorld->AddLightDef( &guiLight ); - } - } - - if ( status != WP_READY && sndHum ) { - StopSound( SND_CHANNEL_BODY, false ); - } - - UpdateSound(); -} - -/* -================ -idWeapon::EnterCinematic -================ -*/ -void idWeapon::EnterCinematic( void ) { - StopSound( SND_CHANNEL_ANY, false ); - - if ( isLinked ) { - SetState( "EnterCinematic", 0 ); - thread->Execute(); - - WEAPON_ATTACK = false; - WEAPON_RELOAD = false; - WEAPON_NETRELOAD = false; - WEAPON_NETENDRELOAD = false; - WEAPON_NETFIRING = false; - WEAPON_RAISEWEAPON = false; - WEAPON_LOWERWEAPON = false; - -#ifdef _D3XP - grabber.Update( this->GetOwner(), true ); -#endif - } - - disabled = true; - - LowerWeapon(); -} - -/* -================ -idWeapon::ExitCinematic -================ -*/ -void idWeapon::ExitCinematic( void ) { - disabled = false; - - if ( isLinked ) { - SetState( "ExitCinematic", 0 ); - thread->Execute(); - } - - RaiseWeapon(); -} - -/* -================ -idWeapon::NetCatchup -================ -*/ -void idWeapon::NetCatchup( void ) { - if ( isLinked ) { - SetState( "NetCatchup", 0 ); - thread->Execute(); - } -} - -/* -================ -idWeapon::GetZoomFov -================ -*/ -int idWeapon::GetZoomFov( void ) { - return zoomFov; -} - -/* -================ -idWeapon::GetWeaponAngleOffsets -================ -*/ -void idWeapon::GetWeaponAngleOffsets( int *average, float *scale, float *max ) { - *average = weaponAngleOffsetAverages; - *scale = weaponAngleOffsetScale; - *max = weaponAngleOffsetMax; -} - -/* -================ -idWeapon::GetWeaponTimeOffsets -================ -*/ -void idWeapon::GetWeaponTimeOffsets( float *time, float *scale ) { - *time = weaponOffsetTime; - *scale = weaponOffsetScale; -} - - -/*********************************************************************** - - Ammo - -***********************************************************************/ - -/* -================ -idWeapon::GetAmmoNumForName -================ -*/ -ammo_t idWeapon::GetAmmoNumForName( const char *ammoname ) { - int num; - const idDict *ammoDict; - - assert( ammoname ); - - ammoDict = gameLocal.FindEntityDefDict( "ammo_types", false ); - if ( !ammoDict ) { - gameLocal.Error( "Could not find entity definition for 'ammo_types'\n" ); - } - - if ( !ammoname[ 0 ] ) { - return 0; - } - - if ( !ammoDict->GetInt( ammoname, "-1", num ) ) { -#ifdef _D3XP - //Lets look in a game specific ammo type definition for the weapon - idStr gamedir; - int i; - for ( i = 0; i < 2; i++ ) { - if ( i == 0 ) { - gamedir = cvarSystem->GetCVarString( "fs_game_base" ); - } else if ( i == 1 ) { - gamedir = cvarSystem->GetCVarString( "fs_game" ); - } - if ( gamedir.Length() > 0 ) { - ammoDict = gameLocal.FindEntityDefDict( va("ammo_types_%s", gamedir.c_str()), false ); - if ( ammoDict ) { - if ( ammoDict->GetInt( ammoname, "-1", num ) ) { - break; - } - } - } - } - if ( i == 2 ) { - gameLocal.Error( "Unknown ammo type '%s'", ammoname ); - } -#endif - } - - if ( ( num < 0 ) || ( num >= AMMO_NUMTYPES ) ) { - gameLocal.Error( "Ammo type '%s' value out of range. Maximum ammo types is %d.\n", ammoname, AMMO_NUMTYPES ); - } - - return ( ammo_t )num; -} - -/* -================ -idWeapon::GetAmmoNameForNum -================ -*/ -const char *idWeapon::GetAmmoNameForNum( ammo_t ammonum ) { - int i, j; - int num; - const idDict *ammoDict; - const idKeyValue *kv; - char text[ 32 ]; - - ammoDict = gameLocal.FindEntityDefDict( "ammo_types", false ); - if ( !ammoDict ) { - gameLocal.Error( "Could not find entity definition for 'ammo_types'\n" ); - } - - sprintf( text, "%d", ammonum ); - - num = ammoDict->GetNumKeyVals(); - for( i = 0; i < num; i++ ) { - kv = ammoDict->GetKeyVal( i ); - if ( kv->GetValue() == text ) { - return kv->GetKey(); - } - } - -#ifdef _D3XP - // Look in the game specific ammo types - idStr gamedir; - for ( i = 0; i < 2; i++ ) { - if ( i == 0 ) { - gamedir = cvarSystem->GetCVarString( "fs_game_base" ); - } else if ( i == 1 ) { - gamedir = cvarSystem->GetCVarString( "fs_game" ); - } - if ( gamedir.Length() > 0 ) { - ammoDict = gameLocal.FindEntityDefDict( va("ammo_types_%s", gamedir.c_str()), false ); - if ( ammoDict ) { - num = ammoDict->GetNumKeyVals(); - for( j = 0; j < num; j++ ) { - kv = ammoDict->GetKeyVal( j ); - if ( kv->GetValue() == text ) { - return kv->GetKey(); - } - } - } - } - } -#endif - - return NULL; -} - -/* -================ -idWeapon::GetAmmoPickupNameForNum -================ -*/ -const char *idWeapon::GetAmmoPickupNameForNum( ammo_t ammonum ) { - int i; - int num; - const idDict *ammoDict; - const idKeyValue *kv; - - ammoDict = gameLocal.FindEntityDefDict( "ammo_names", false ); - if ( !ammoDict ) { - gameLocal.Error( "Could not find entity definition for 'ammo_names'\n" ); - } - - const char *name = GetAmmoNameForNum( ammonum ); - - if ( name && *name ) { - num = ammoDict->GetNumKeyVals(); - for( i = 0; i < num; i++ ) { - kv = ammoDict->GetKeyVal( i ); - if ( idStr::Icmp( kv->GetKey(), name) == 0 ) { - return kv->GetValue(); - } - } - } - - return ""; -} - -/* -================ -idWeapon::AmmoAvailable -================ -*/ -int idWeapon::AmmoAvailable( void ) const { - if ( owner ) { - return owner->inventory.HasAmmo( ammoType, ammoRequired ); - } else { - return 0; - } -} - -/* -================ -idWeapon::AmmoInClip -================ -*/ -int idWeapon::AmmoInClip( void ) const { - return ammoClip; -} - -/* -================ -idWeapon::ResetAmmoClip -================ -*/ -void idWeapon::ResetAmmoClip( void ) { - ammoClip = -1; -} - -/* -================ -idWeapon::GetAmmoType -================ -*/ -ammo_t idWeapon::GetAmmoType( void ) const { - return ammoType; -} - -/* -================ -idWeapon::ClipSize -================ -*/ -int idWeapon::ClipSize( void ) const { - return clipSize; -} - -/* -================ -idWeapon::LowAmmo -================ -*/ -int idWeapon::LowAmmo() const { - return lowAmmo; -} - -/* -================ -idWeapon::AmmoRequired -================ -*/ -int idWeapon::AmmoRequired( void ) const { - return ammoRequired; -} - -#ifdef _D3XP -/* -================ -idWeapon::GetGrabberState - -Returns the current grabberState -================ -*/ -int idWeapon::GetGrabberState() const { - - return grabberState; -} - -/* -================ -idWeapon::AmmoCount - -Returns the total number of rounds regardless of the required ammo -================ -*/ -int idWeapon::AmmoCount() const { - - if ( owner ) { - return owner->inventory.HasAmmo( ammoType, 1 ); - } else { - return 0; - } -} -#endif - -/* -================ -idWeapon::WriteToSnapshot -================ -*/ -void idWeapon::WriteToSnapshot( idBitMsgDelta &msg ) const { - msg.WriteBits( ammoClip, ASYNC_PLAYER_INV_CLIP_BITS ); - msg.WriteBits( worldModel.GetSpawnId(), 32 ); - msg.WriteBits( lightOn, 1 ); - msg.WriteBits( isFiring ? 1 : 0, 1 ); -} - -/* -================ -idWeapon::ReadFromSnapshot -================ -*/ -void idWeapon::ReadFromSnapshot( const idBitMsgDelta &msg ) { - ammoClip = msg.ReadBits( ASYNC_PLAYER_INV_CLIP_BITS ); - worldModel.SetSpawnId( msg.ReadBits( 32 ) ); - bool snapLight = msg.ReadBits( 1 ) != 0; - isFiring = msg.ReadBits( 1 ) != 0; - - // WEAPON_NETFIRING is only turned on for other clients we're predicting. not for local client - if ( owner && gameLocal.localClientNum != owner->entityNumber && WEAPON_NETFIRING.IsLinked() ) { - - // immediately go to the firing state so we don't skip fire animations - if ( !WEAPON_NETFIRING && isFiring ) { - idealState = "Fire"; - } - - // immediately switch back to idle - if ( WEAPON_NETFIRING && !isFiring ) { - idealState = "Idle"; - } - - WEAPON_NETFIRING = isFiring; - } - - if ( snapLight != lightOn ) { - Reload(); - } -} - -/* -================ -idWeapon::ClientReceiveEvent -================ -*/ -bool idWeapon::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) { - - switch( event ) { - case EVENT_RELOAD: { - if ( gameLocal.time - time < 1000 ) { - if ( WEAPON_NETRELOAD.IsLinked() ) { - WEAPON_NETRELOAD = true; - WEAPON_NETENDRELOAD = false; - } - } - return true; - } - case EVENT_ENDRELOAD: { - if ( WEAPON_NETENDRELOAD.IsLinked() ) { - WEAPON_NETENDRELOAD = true; - } - return true; - } - case EVENT_CHANGESKIN: { - int index = gameLocal.ClientRemapDecl( DECL_SKIN, msg.ReadInt() ); - renderEntity.customSkin = ( index != -1 ) ? static_cast( declManager->DeclByIndex( DECL_SKIN, index ) ) : NULL; - UpdateVisuals(); - if ( worldModel.GetEntity() ) { - worldModel.GetEntity()->SetSkin( renderEntity.customSkin ); - } - return true; - } - default: - break; - } - - return idEntity::ClientReceiveEvent( event, time, msg ); -} - -/*********************************************************************** - - Script events - -***********************************************************************/ - -/* -=============== -idWeapon::Event_Clear -=============== -*/ -void idWeapon::Event_Clear( void ) { - Clear(); -} - -/* -=============== -idWeapon::Event_GetOwner -=============== -*/ -void idWeapon::Event_GetOwner( void ) { - idThread::ReturnEntity( owner ); -} - -/* -=============== -idWeapon::Event_WeaponState -=============== -*/ -void idWeapon::Event_WeaponState( const char *statename, int blendFrames ) { - const function_t *func; - - func = scriptObject.GetFunction( statename ); - if ( !func ) { - assert( 0 ); - gameLocal.Error( "Can't find function '%s' in object '%s'", statename, scriptObject.GetTypeName() ); - } - - idealState = statename; - - if ( !idealState.Icmp( "Fire" ) ) { - isFiring = true; - } else { - isFiring = false; - } - - animBlendFrames = blendFrames; - thread->DoneProcessing(); -} - -/* -=============== -idWeapon::Event_WeaponReady -=============== -*/ -void idWeapon::Event_WeaponReady( void ) { - status = WP_READY; - if ( isLinked ) { - WEAPON_RAISEWEAPON = false; - } - if ( sndHum ) { - StartSoundShader( sndHum, SND_CHANNEL_BODY, 0, false, NULL ); - } - -} - -/* -=============== -idWeapon::Event_WeaponOutOfAmmo -=============== -*/ -void idWeapon::Event_WeaponOutOfAmmo( void ) { - status = WP_OUTOFAMMO; - if ( isLinked ) { - WEAPON_RAISEWEAPON = false; - } -} - -/* -=============== -idWeapon::Event_WeaponReloading -=============== -*/ -void idWeapon::Event_WeaponReloading( void ) { - status = WP_RELOAD; -} - -/* -=============== -idWeapon::Event_WeaponHolstered -=============== -*/ -void idWeapon::Event_WeaponHolstered( void ) { - status = WP_HOLSTERED; - if ( isLinked ) { - WEAPON_LOWERWEAPON = false; - } -} - -/* -=============== -idWeapon::Event_WeaponRising -=============== -*/ -void idWeapon::Event_WeaponRising( void ) { - status = WP_RISING; - if ( isLinked ) { - WEAPON_LOWERWEAPON = false; - } - owner->WeaponRisingCallback(); -} - -/* -=============== -idWeapon::Event_WeaponLowering -=============== -*/ -void idWeapon::Event_WeaponLowering( void ) { - status = WP_LOWERING; - if ( isLinked ) { - WEAPON_RAISEWEAPON = false; - } - owner->WeaponLoweringCallback(); -} - -/* -=============== -idWeapon::Event_UseAmmo -=============== -*/ -void idWeapon::Event_UseAmmo( int amount ) { - if ( gameLocal.isClient ) { - return; - } - - owner->inventory.UseAmmo( ammoType, ( powerAmmo ) ? amount : ( amount * ammoRequired ) ); - if ( clipSize && ammoRequired ) { - ammoClip -= powerAmmo ? amount : ( amount * ammoRequired ); - if ( ammoClip < 0 ) { - ammoClip = 0; - } - } -} - -/* -=============== -idWeapon::Event_AddToClip -=============== -*/ -void idWeapon::Event_AddToClip( int amount ) { - int ammoAvail; - - if ( gameLocal.isClient ) { - return; - } - -#ifdef _D3XP - int oldAmmo = ammoClip; - ammoAvail = owner->inventory.HasAmmo( ammoType, ammoRequired ) + AmmoInClip(); -#endif - - ammoClip += amount; - if ( ammoClip > clipSize ) { - ammoClip = clipSize; - } - -#ifdef _D3XP -#else - ammoAvail = owner->inventory.HasAmmo( ammoType, ammoRequired ); -#endif - - if ( ammoClip > ammoAvail ) { - ammoClip = ammoAvail; - } - -#ifdef _D3XP - // for shared ammo we need to use the ammo when it is moved into the clip - int usedAmmo = ammoClip - oldAmmo; - owner->inventory.UseAmmo(ammoType, usedAmmo); -#endif -} - -/* -=============== -idWeapon::Event_AmmoInClip -=============== -*/ -void idWeapon::Event_AmmoInClip( void ) { - int ammo = AmmoInClip(); - idThread::ReturnFloat( ammo ); -} - -/* -=============== -idWeapon::Event_AmmoAvailable -=============== -*/ -void idWeapon::Event_AmmoAvailable( void ) { -#ifdef _D3XP - int ammoAvail = owner->inventory.HasAmmo( ammoType, ammoRequired ); - ammoAvail += AmmoInClip(); -#else - int ammoAvail = owner->inventory.HasAmmo( ammoType, ammoRequired ); -#endif - - idThread::ReturnFloat( ammoAvail ); -} - -/* -=============== -idWeapon::Event_TotalAmmoCount -=============== -*/ -void idWeapon::Event_TotalAmmoCount( void ) { - int ammoAvail = owner->inventory.HasAmmo( ammoType, 1 ); - idThread::ReturnFloat( ammoAvail ); -} - -/* -=============== -idWeapon::Event_ClipSize -=============== -*/ -void idWeapon::Event_ClipSize( void ) { - idThread::ReturnFloat( clipSize ); -} - -/* -=============== -idWeapon::Event_AutoReload -=============== -*/ -void idWeapon::Event_AutoReload( void ) { - assert( owner ); - if ( gameLocal.isClient ) { - idThread::ReturnFloat( 0.0f ); - return; - } - idThread::ReturnFloat( gameLocal.userInfo[ owner->entityNumber ].GetBool( "ui_autoReload" ) ); -} - -/* -=============== -idWeapon::Event_NetReload -=============== -*/ -void idWeapon::Event_NetReload( void ) { - assert( owner ); - if ( gameLocal.isServer ) { - ServerSendEvent( EVENT_RELOAD, NULL, false, -1 ); - } -} - -/* -=============== -idWeapon::Event_NetEndReload -=============== -*/ -void idWeapon::Event_NetEndReload( void ) { - assert( owner ); - if ( gameLocal.isServer ) { - ServerSendEvent( EVENT_ENDRELOAD, NULL, false, -1 ); - } -} - -/* -=============== -idWeapon::Event_PlayAnim -=============== -*/ -void idWeapon::Event_PlayAnim( int channel, const char *animname ) { - int anim; - - anim = animator.GetAnim( animname ); - if ( !anim ) { - gameLocal.Warning( "missing '%s' animation on '%s' (%s)", animname, name.c_str(), GetEntityDefName() ); - animator.Clear( channel, gameLocal.time, FRAME2MS( animBlendFrames ) ); - animDoneTime = 0; - } else { - if ( !( owner && owner->GetInfluenceLevel() ) ) { - Show(); - } - animator.PlayAnim( channel, anim, gameLocal.time, FRAME2MS( animBlendFrames ) ); - animDoneTime = animator.CurrentAnim( channel )->GetEndTime(); - if ( worldModel.GetEntity() ) { - anim = worldModel.GetEntity()->GetAnimator()->GetAnim( animname ); - if ( anim ) { - worldModel.GetEntity()->GetAnimator()->PlayAnim( channel, anim, gameLocal.time, FRAME2MS( animBlendFrames ) ); - } - } - } - animBlendFrames = 0; - idThread::ReturnInt( 0 ); -} - -/* -=============== -idWeapon::Event_PlayCycle -=============== -*/ -void idWeapon::Event_PlayCycle( int channel, const char *animname ) { - int anim; - - anim = animator.GetAnim( animname ); - if ( !anim ) { - gameLocal.Warning( "missing '%s' animation on '%s' (%s)", animname, name.c_str(), GetEntityDefName() ); - animator.Clear( channel, gameLocal.time, FRAME2MS( animBlendFrames ) ); - animDoneTime = 0; - } else { - if ( !( owner && owner->GetInfluenceLevel() ) ) { - Show(); - } - animator.CycleAnim( channel, anim, gameLocal.time, FRAME2MS( animBlendFrames ) ); - animDoneTime = animator.CurrentAnim( channel )->GetEndTime(); - if ( worldModel.GetEntity() ) { - anim = worldModel.GetEntity()->GetAnimator()->GetAnim( animname ); - worldModel.GetEntity()->GetAnimator()->CycleAnim( channel, anim, gameLocal.time, FRAME2MS( animBlendFrames ) ); - } - } - animBlendFrames = 0; - idThread::ReturnInt( 0 ); -} - -/* -=============== -idWeapon::Event_AnimDone -=============== -*/ -void idWeapon::Event_AnimDone( int channel, int blendFrames ) { - if ( animDoneTime - FRAME2MS( blendFrames ) <= gameLocal.time ) { - idThread::ReturnInt( true ); - } else { - idThread::ReturnInt( false ); - } -} - -/* -=============== -idWeapon::Event_SetBlendFrames -=============== -*/ -void idWeapon::Event_SetBlendFrames( int channel, int blendFrames ) { - animBlendFrames = blendFrames; -} - -/* -=============== -idWeapon::Event_GetBlendFrames -=============== -*/ -void idWeapon::Event_GetBlendFrames( int channel ) { - idThread::ReturnInt( animBlendFrames ); -} - -/* -================ -idWeapon::Event_Next -================ -*/ -void idWeapon::Event_Next( void ) { - // change to another weapon if possible - owner->NextBestWeapon(); -} - -/* -================ -idWeapon::Event_SetSkin -================ -*/ -void idWeapon::Event_SetSkin( const char *skinname ) { - const idDeclSkin *skinDecl; - - if ( !skinname || !skinname[ 0 ] ) { - skinDecl = NULL; - } else { - skinDecl = declManager->FindSkin( skinname ); - } - - renderEntity.customSkin = skinDecl; - UpdateVisuals(); - - if ( worldModel.GetEntity() ) { - worldModel.GetEntity()->SetSkin( skinDecl ); - } - - if ( gameLocal.isServer ) { - idBitMsg msg; - byte msgBuf[MAX_EVENT_PARAM_SIZE]; - - msg.Init( msgBuf, sizeof( msgBuf ) ); - msg.WriteInt( ( skinDecl != NULL ) ? gameLocal.ServerRemapDecl( -1, DECL_SKIN, skinDecl->Index() ) : -1 ); - ServerSendEvent( EVENT_CHANGESKIN, &msg, false, -1 ); - } -} - -/* -================ -idWeapon::Event_Flashlight -================ -*/ -void idWeapon::Event_Flashlight( int enable ) { - if ( enable ) { - lightOn = true; - MuzzleFlashLight(); - } else { - lightOn = false; - muzzleFlashEnd = 0; - } -} - -/* -================ -idWeapon::Event_GetLightParm -================ -*/ -void idWeapon::Event_GetLightParm( int parmnum ) { - if ( ( parmnum < 0 ) || ( parmnum >= MAX_ENTITY_SHADER_PARMS ) ) { - gameLocal.Error( "shader parm index (%d) out of range", parmnum ); - } - - idThread::ReturnFloat( muzzleFlash.shaderParms[ parmnum ] ); -} - -/* -================ -idWeapon::Event_SetLightParm -================ -*/ -void idWeapon::Event_SetLightParm( int parmnum, float value ) { - if ( ( parmnum < 0 ) || ( parmnum >= MAX_ENTITY_SHADER_PARMS ) ) { - gameLocal.Error( "shader parm index (%d) out of range", parmnum ); - } - - muzzleFlash.shaderParms[ parmnum ] = value; - worldMuzzleFlash.shaderParms[ parmnum ] = value; - UpdateVisuals(); -} - -/* -================ -idWeapon::Event_SetLightParms -================ -*/ -void idWeapon::Event_SetLightParms( float parm0, float parm1, float parm2, float parm3 ) { - muzzleFlash.shaderParms[ SHADERPARM_RED ] = parm0; - muzzleFlash.shaderParms[ SHADERPARM_GREEN ] = parm1; - muzzleFlash.shaderParms[ SHADERPARM_BLUE ] = parm2; - muzzleFlash.shaderParms[ SHADERPARM_ALPHA ] = parm3; - - worldMuzzleFlash.shaderParms[ SHADERPARM_RED ] = parm0; - worldMuzzleFlash.shaderParms[ SHADERPARM_GREEN ] = parm1; - worldMuzzleFlash.shaderParms[ SHADERPARM_BLUE ] = parm2; - worldMuzzleFlash.shaderParms[ SHADERPARM_ALPHA ] = parm3; - - UpdateVisuals(); -} - -#ifdef _D3XP -/* -================ -idWeapon::Event_Grabber -================ -*/ -void idWeapon::Event_Grabber( int enable ) { - if ( enable ) { - grabberState = 0; - } else { - grabberState = -1; - } -} - -/* -================ -idWeapon::Event_GrabberHasTarget -================ -*/ -void idWeapon::Event_GrabberHasTarget() { - idThread::ReturnInt( grabberState ); -} - -/* -================ -idWeapon::Event_GrabberSetGrabDistance -================ -*/ -void idWeapon::Event_GrabberSetGrabDistance( float dist ) { - - grabber.SetDragDistance( dist ); -} -#endif - -/* -================ -idWeapon::Event_CreateProjectile -================ -*/ -void idWeapon::Event_CreateProjectile( void ) { - if ( !gameLocal.isClient ) { - projectileEnt = NULL; - gameLocal.SpawnEntityDef( projectileDict, &projectileEnt, false ); - if ( projectileEnt ) { - projectileEnt->SetOrigin( GetPhysics()->GetOrigin() ); - projectileEnt->Bind( owner, false ); - projectileEnt->Hide(); - } - idThread::ReturnEntity( projectileEnt ); - } else { - idThread::ReturnEntity( NULL ); - } -} - -/* -================ -idWeapon::Event_LaunchProjectiles -================ -*/ -void idWeapon::Event_LaunchProjectiles( int num_projectiles, float spread, float fuseOffset, float launchPower, float dmgPower ) { - idProjectile *proj; - idEntity *ent; - int i; - idVec3 dir; - float ang; - float spin; - float distance; - trace_t tr; - idVec3 start; - idVec3 muzzle_pos; - idBounds ownerBounds, projBounds; - - if ( IsHidden() ) { - return; - } - - if ( !projectileDict.GetNumKeyVals() ) { - const char *classname = weaponDef->dict.GetString( "classname" ); - gameLocal.Warning( "No projectile defined on '%s'", classname ); - return; - } - - // avoid all ammo considerations on an MP client - if ( !gameLocal.isClient ) { - -#ifdef _D3XP - - if ( ( clipSize != 0 ) && ( ammoClip <= 0 ) ) { - return; - } - -#else - // check if we're out of ammo or the clip is empty - int ammoAvail = owner->inventory.HasAmmo( ammoType, ammoRequired ); - if ( !ammoAvail || ( ( clipSize != 0 ) && ( ammoClip <= 0 ) ) ) { - return; - } -#endif - // if this is a power ammo weapon ( currently only the bfg ) then make sure - // we only fire as much power as available in each clip - if ( powerAmmo ) { - // power comes in as a float from zero to max - // if we use this on more than the bfg will need to define the max - // in the .def as opposed to just in the script so proper calcs - // can be done here. - dmgPower = ( int )dmgPower + 1; - if ( dmgPower > ammoClip ) { - dmgPower = ammoClip; - } - } - -#ifdef _D3XP - if(clipSize == 0) { - //Weapons with a clip size of 0 launch strait from inventory without moving to a clip -#endif - //In D3XP we used the ammo when the ammo was moved into the clip so we don't want to - //use it now. - owner->inventory.UseAmmo( ammoType, ( powerAmmo ) ? dmgPower : ammoRequired ); - -#ifdef _D3XP - } -#endif - - if ( clipSize && ammoRequired ) { -#ifdef _D3XP - ammoClip -= powerAmmo ? dmgPower : ammoRequired; -#else - ammoClip -= powerAmmo ? dmgPower : 1; -#endif - } - - } - - if ( !silent_fire ) { - // wake up nearby monsters - gameLocal.AlertAI( owner ); - } - - // set the shader parm to the time of last projectile firing, - // which the gun material shaders can reference for single shot barrel glows, etc - renderEntity.shaderParms[ SHADERPARM_DIVERSITY ] = gameLocal.random.CRandomFloat(); - renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.realClientTime ); - - if ( worldModel.GetEntity() ) { - worldModel.GetEntity()->SetShaderParm( SHADERPARM_DIVERSITY, renderEntity.shaderParms[ SHADERPARM_DIVERSITY ] ); - worldModel.GetEntity()->SetShaderParm( SHADERPARM_TIMEOFFSET, renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] ); - } - - // calculate the muzzle position - if ( barrelJointView != INVALID_JOINT && projectileDict.GetBool( "launchFromBarrel" ) ) { - // there is an explicit joint for the muzzle - GetGlobalJointTransform( true, barrelJointView, muzzleOrigin, muzzleAxis ); - } else { - // go straight out of the view - muzzleOrigin = playerViewOrigin; - muzzleAxis = playerViewAxis; - } - - // add some to the kick time, incrementally moving repeat firing weapons back - if ( kick_endtime < gameLocal.realClientTime ) { - kick_endtime = gameLocal.realClientTime; - } - kick_endtime += muzzle_kick_time; - if ( kick_endtime > gameLocal.realClientTime + muzzle_kick_maxtime ) { - kick_endtime = gameLocal.realClientTime + muzzle_kick_maxtime; - } - - if ( gameLocal.isClient ) { - - // predict instant hit projectiles - if ( projectileDict.GetBool( "net_instanthit" ) ) { - float spreadRad = DEG2RAD( spread ); - muzzle_pos = muzzleOrigin + playerViewAxis[ 0 ] * 2.0f; - for( i = 0; i < num_projectiles; i++ ) { - ang = idMath::Sin( spreadRad * gameLocal.random.RandomFloat() ); - spin = (float)DEG2RAD( 360.0f ) * gameLocal.random.RandomFloat(); - dir = playerViewAxis[ 0 ] + playerViewAxis[ 2 ] * ( ang * idMath::Sin( spin ) ) - playerViewAxis[ 1 ] * ( ang * idMath::Cos( spin ) ); - dir.Normalize(); - gameLocal.clip.Translation( tr, muzzle_pos, muzzle_pos + dir * 4096.0f, NULL, mat3_identity, MASK_SHOT_RENDERMODEL, owner ); - if ( tr.fraction < 1.0f ) { - idProjectile::ClientPredictionCollide( this, projectileDict, tr, vec3_origin, true ); - } - } - } - - } else { - - ownerBounds = owner->GetPhysics()->GetAbsBounds(); - - owner->AddProjectilesFired( num_projectiles ); - - float spreadRad = DEG2RAD( spread ); - for( i = 0; i < num_projectiles; i++ ) { - ang = idMath::Sin( spreadRad * gameLocal.random.RandomFloat() ); - spin = (float)DEG2RAD( 360.0f ) * gameLocal.random.RandomFloat(); - dir = playerViewAxis[ 0 ] + playerViewAxis[ 2 ] * ( ang * idMath::Sin( spin ) ) - playerViewAxis[ 1 ] * ( ang * idMath::Cos( spin ) ); - dir.Normalize(); - - if ( projectileEnt ) { - ent = projectileEnt; - ent->Show(); - ent->Unbind(); - projectileEnt = NULL; - } else { - gameLocal.SpawnEntityDef( projectileDict, &ent, false ); - } - - if ( !ent || !ent->IsType( idProjectile::Type ) ) { - const char *projectileName = weaponDef->dict.GetString( "def_projectile" ); - gameLocal.Error( "'%s' is not an idProjectile", projectileName ); - } - - if ( projectileDict.GetBool( "net_instanthit" ) ) { - // don't synchronize this on top of the already predicted effect - ent->fl.networkSync = false; - } - - proj = static_cast(ent); - proj->Create( owner, muzzleOrigin, dir ); - - projBounds = proj->GetPhysics()->GetBounds().Rotate( proj->GetPhysics()->GetAxis() ); - - // make sure the projectile starts inside the bounding box of the owner - if ( i == 0 ) { - muzzle_pos = muzzleOrigin + playerViewAxis[ 0 ] * 2.0f; - - // DG: sometimes the assertion in idBounds::operator-(const idBounds&) triggers - // (would get bounding box with negative volume) - // => check that before doing ownerBounds - projBounds (equivalent to the check in the assertion) - idVec3 obDiff = ownerBounds[1] - ownerBounds[0]; - idVec3 pbDiff = projBounds[1] - projBounds[0]; - bool boundsSubLegal = obDiff.x > pbDiff.x && obDiff.y > pbDiff.y && obDiff.z > pbDiff.z; - if ( boundsSubLegal && ( ownerBounds - projBounds ).RayIntersection( muzzle_pos, playerViewAxis[0], distance ) ) { - start = muzzle_pos + distance * playerViewAxis[0]; - } else { - start = ownerBounds.GetCenter(); - } - gameLocal.clip.Translation( tr, start, muzzle_pos, proj->GetPhysics()->GetClipModel(), proj->GetPhysics()->GetClipModel()->GetAxis(), MASK_SHOT_RENDERMODEL, owner ); - muzzle_pos = tr.endpos; - } - - proj->Launch( muzzle_pos, dir, pushVelocity, fuseOffset, launchPower, dmgPower ); - } - - // toss the brass -#ifdef _D3XP - if(brassDelay >= 0) -#endif - PostEventMS( &EV_Weapon_EjectBrass, brassDelay ); - } - - // add the light for the muzzleflash - if ( !lightOn ) { - MuzzleFlashLight(); - } - - owner->WeaponFireFeedback( &weaponDef->dict ); - - // reset muzzle smoke - weaponSmokeStartTime = gameLocal.realClientTime; -} - -#ifdef _D3XP -/* -================ -idWeapon::Event_LaunchProjectilesEllipse -================ -*/ -void idWeapon::Event_LaunchProjectilesEllipse( int num_projectiles, float spreada, float spreadb, float fuseOffset, float power ) { - idProjectile *proj; - idEntity *ent; - int i; - idVec3 dir; - float anga, angb; - float spin; - float distance; - trace_t tr; - idVec3 start; - idVec3 muzzle_pos; - idBounds ownerBounds, projBounds; - - if ( IsHidden() ) { - return; - } - - if ( !projectileDict.GetNumKeyVals() ) { - const char *classname = weaponDef->dict.GetString( "classname" ); - gameLocal.Warning( "No projectile defined on '%s'", classname ); - return; - } - - // avoid all ammo considerations on a client - if ( !gameLocal.isClient ) { - - if ( ( clipSize != 0 ) && ( ammoClip <= 0 ) ) { - return; - } - - if( clipSize == 0 ) { - //Weapons with a clip size of 0 launch strait from inventory without moving to a clip - owner->inventory.UseAmmo( ammoType, ammoRequired ); - } - - if ( clipSize && ammoRequired ) { - ammoClip -= ammoRequired; - } - - if ( !silent_fire ) { - // wake up nearby monsters - gameLocal.AlertAI( owner ); - } - - } - - // set the shader parm to the time of last projectile firing, - // which the gun material shaders can reference for single shot barrel glows, etc - renderEntity.shaderParms[ SHADERPARM_DIVERSITY ] = gameLocal.random.CRandomFloat(); - renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time ); - - if ( worldModel.GetEntity() ) { - worldModel.GetEntity()->SetShaderParm( SHADERPARM_DIVERSITY, renderEntity.shaderParms[ SHADERPARM_DIVERSITY ] ); - worldModel.GetEntity()->SetShaderParm( SHADERPARM_TIMEOFFSET, renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] ); - } - - // calculate the muzzle position - if ( barrelJointView != INVALID_JOINT && projectileDict.GetBool( "launchFromBarrel" ) ) { - // there is an explicit joint for the muzzle - GetGlobalJointTransform( true, barrelJointView, muzzleOrigin, muzzleAxis ); - } else { - // go straight out of the view - muzzleOrigin = playerViewOrigin; - muzzleAxis = playerViewAxis; - } - - // add some to the kick time, incrementally moving repeat firing weapons back - if ( kick_endtime < gameLocal.time ) { - kick_endtime = gameLocal.time; - } - kick_endtime += muzzle_kick_time; - if ( kick_endtime > gameLocal.time + muzzle_kick_maxtime ) { - kick_endtime = gameLocal.time + muzzle_kick_maxtime; - } - - if ( !gameLocal.isClient ) { - ownerBounds = owner->GetPhysics()->GetAbsBounds(); - - owner->AddProjectilesFired( num_projectiles ); - - float spreadRadA = DEG2RAD( spreada ); - float spreadRadB = DEG2RAD( spreadb ); - - for( i = 0; i < num_projectiles; i++ ) { - //Ellipse Form - spin = (float)DEG2RAD( 360.0f ) * gameLocal.random.RandomFloat(); - anga = idMath::Sin(spreadRadA * gameLocal.random.RandomFloat()); - angb = idMath::Sin(spreadRadB * gameLocal.random.RandomFloat()); - dir = playerViewAxis[ 0 ] + playerViewAxis[ 2 ] * ( angb*idMath::Sin( spin ) ) - playerViewAxis[ 1 ] * ( anga*idMath::Cos( spin ) ); - dir.Normalize(); - - gameLocal.SpawnEntityDef( projectileDict, &ent ); - if ( !ent || !ent->IsType( idProjectile::Type ) ) { - const char *projectileName = weaponDef->dict.GetString( "def_projectile" ); - gameLocal.Error( "'%s' is not an idProjectile", projectileName ); - } - - proj = static_cast(ent); - proj->Create( owner, muzzleOrigin, dir ); - - projBounds = proj->GetPhysics()->GetBounds().Rotate( proj->GetPhysics()->GetAxis() ); - - // make sure the projectile starts inside the bounding box of the owner - if ( i == 0 ) { - muzzle_pos = muzzleOrigin + playerViewAxis[ 0 ] * 2.0f; - if ( ( ownerBounds - projBounds).RayIntersection( muzzle_pos, playerViewAxis[0], distance ) ) { - start = muzzle_pos + distance * playerViewAxis[0]; - } - else { - start = ownerBounds.GetCenter(); - } - gameLocal.clip.Translation( tr, start, muzzle_pos, proj->GetPhysics()->GetClipModel(), proj->GetPhysics()->GetClipModel()->GetAxis(), MASK_SHOT_RENDERMODEL, owner ); - muzzle_pos = tr.endpos; - } - - proj->Launch( muzzle_pos, dir, pushVelocity, fuseOffset, power ); - } - - // toss the brass - if( brassDelay >= 0 ) { - PostEventMS( &EV_Weapon_EjectBrass, brassDelay ); - } - } - - // add the light for the muzzleflash - if ( !lightOn ) { - MuzzleFlashLight(); - } - - owner->WeaponFireFeedback( &weaponDef->dict ); - - // reset muzzle smoke - weaponSmokeStartTime = gameLocal.time; - -} - -/** -* Gives the player a powerup as if it were a weapon shot. It will use the ammo amount specified -* as ammoRequired. -*/ -void idWeapon::Event_LaunchPowerup( const char* powerup, float duration, int useAmmo ) { - - if ( IsHidden() ) { - return; - } - - // check if we're out of ammo - if(useAmmo) { - int ammoAvail = owner->inventory.HasAmmo( ammoType, ammoRequired ); - if ( !ammoAvail ) { - return; - } - owner->inventory.UseAmmo( ammoType, ammoRequired ); - } - - // set the shader parm to the time of last projectile firing, - // which the gun material shaders can reference for single shot barrel glows, etc - renderEntity.shaderParms[ SHADERPARM_DIVERSITY ] = gameLocal.random.CRandomFloat(); - renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time ); - - if ( worldModel.GetEntity() ) { - worldModel.GetEntity()->SetShaderParm( SHADERPARM_DIVERSITY, renderEntity.shaderParms[ SHADERPARM_DIVERSITY ] ); - worldModel.GetEntity()->SetShaderParm( SHADERPARM_TIMEOFFSET, renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] ); - } - - // add the light for the muzzleflash - if ( !lightOn ) { - MuzzleFlashLight(); - } - - owner->Give(powerup, va("%f", duration)); - - -} - -void idWeapon::Event_StartWeaponSmoke() { - - // reset muzzle smoke - weaponSmokeStartTime = gameLocal.time; -} - -void idWeapon::Event_StopWeaponSmoke() { - - // reset muzzle smoke - weaponSmokeStartTime = 0; -} - -void idWeapon::Event_StartWeaponParticle( const char* name) { - WeaponParticle_t* part; - weaponParticles.Get(name, &part); - if(part) { - part->active = true; - part->startTime = gameLocal.time; - - //Toggle the emitter - if(!part->smoke) { - part->emitter->Show(); - part->emitter->PostEventMS(&EV_Activate, 0, this); - } - } -} - -void idWeapon::Event_StopWeaponParticle( const char* name) { - WeaponParticle_t* part; - weaponParticles.Get(name, &part); - if(part) { - part->active = false; - part->startTime = 0; - - //Toggle the emitter - if(!part->smoke) { - part->emitter->Hide(); - part->emitter->PostEventMS(&EV_Activate, 0, this); - } - } -} - -void idWeapon::Event_StartWeaponLight( const char* name) { - WeaponLight_t* light; - weaponLights.Get(name, &light); - if(light) { - light->active = true; - light->startTime = gameLocal.time; - } -} - -void idWeapon::Event_StopWeaponLight( const char* name) { - WeaponLight_t* light; - weaponLights.Get(name, &light); - if(light) { - light->active = false; - light->startTime = 0; - if(light->lightHandle != -1) { - gameRenderWorld->FreeLightDef( light->lightHandle ); - light->lightHandle = -1; - } - } -} -#endif -/* -===================== -idWeapon::Event_Melee -===================== -*/ -void idWeapon::Event_Melee( void ) { - idEntity *ent; - trace_t tr; - - if ( !meleeDef ) { - gameLocal.Error( "No meleeDef on '%s'", weaponDef->dict.GetString( "classname" ) ); - } - - if ( !gameLocal.isClient ) { - idVec3 start = playerViewOrigin; - idVec3 end = start + playerViewAxis[0] * ( meleeDistance * owner->PowerUpModifier( MELEE_DISTANCE ) ); - gameLocal.clip.TracePoint( tr, start, end, MASK_SHOT_RENDERMODEL, owner ); - if ( tr.fraction < 1.0f ) { - ent = gameLocal.GetTraceEntity( tr ); - } else { - ent = NULL; - } - - if ( g_debugWeapon.GetBool() ) { - gameRenderWorld->DebugLine( colorYellow, start, end, 100 ); - if ( ent ) { - gameRenderWorld->DebugBounds( colorRed, ent->GetPhysics()->GetBounds(), ent->GetPhysics()->GetOrigin(), 100 ); - } - } - - bool hit = false; - const char *hitSound = meleeDef->dict.GetString( "snd_miss" ); - - if ( ent ) { - - float push = meleeDef->dict.GetFloat( "push" ); - idVec3 impulse = -push * owner->PowerUpModifier( SPEED ) * tr.c.normal; - - if ( gameLocal.world->spawnArgs.GetBool( "no_Weapons" ) && ( ent->IsType( idActor::Type ) || ent->IsType( idAFAttachment::Type) ) ) { - idThread::ReturnInt( 0 ); - return; - } - - ent->ApplyImpulse( this, tr.c.id, tr.c.point, impulse ); - - // weapon stealing - do this before damaging so weapons are not dropped twice - if ( gameLocal.isMultiplayer - && weaponDef && weaponDef->dict.GetBool( "stealing" ) - && ent->IsType( idPlayer::Type ) - && !owner->PowerUpActive( BERSERK ) - && ( (gameLocal.gameType != GAME_TDM ) || gameLocal.serverInfo.GetBool( "si_teamDamage" ) || ( owner->team != static_cast< idPlayer * >( ent )->team ) ) - ) { - -#ifdef CTF /* Code is formed oddly for easy merge */ - - if ( gameLocal.mpGame.IsGametypeFlagBased() ) - { /* Do nothing ... */ } - else -#endif - owner->StealWeapon( static_cast< idPlayer * >( ent ) ); - } - - if ( ent->fl.takedamage ) { - idVec3 kickDir, globalKickDir; - meleeDef->dict.GetVector( "kickDir", "0 0 0", kickDir ); - globalKickDir = muzzleAxis * kickDir; -#ifdef _D3XP - //Adjust the melee powerup modifier for the invulnerability boss fight - float mod = owner->PowerUpModifier( MELEE_DAMAGE ); - if(!strcmp(ent->GetEntityDefName(), "monster_hunter_invul")) { - //Only do a quater of the damage mod - mod *= 0.25f; - } - ent->Damage( owner, owner, globalKickDir, meleeDefName, mod, tr.c.id ); -#else - ent->Damage( owner, owner, globalKickDir, meleeDefName, owner->PowerUpModifier( MELEE_DAMAGE ), tr.c.id ); -#endif - hit = true; - } - - if ( weaponDef->dict.GetBool( "impact_damage_effect" ) ) { - - if ( ent->spawnArgs.GetBool( "bleed" ) ) { - - hitSound = meleeDef->dict.GetString( owner->PowerUpActive( BERSERK ) ? "snd_hit_berserk" : "snd_hit" ); - - ent->AddDamageEffect( tr, impulse, meleeDef->dict.GetString( "classname" ) ); - - } else { - - int type = tr.c.material->GetSurfaceType(); - if ( type == SURFTYPE_NONE ) { - type = GetDefaultSurfaceType(); - } - - const char *materialType = gameLocal.sufaceTypeNames[ type ]; - - // start impact sound based on material type - hitSound = meleeDef->dict.GetString( va( "snd_%s", materialType ) ); - if ( *hitSound == '\0' ) { - hitSound = meleeDef->dict.GetString( "snd_metal" ); - } - - if ( gameLocal.time > nextStrikeFx ) { - const char *decal; - // project decal - decal = weaponDef->dict.GetString( "mtr_strike" ); - if ( decal && *decal ) { - gameLocal.ProjectDecal( tr.c.point, -tr.c.normal, 8.0f, true, 6.0, decal ); - } - nextStrikeFx = gameLocal.time + 200; - } else { - hitSound = ""; - } - - strikeSmokeStartTime = gameLocal.time; - strikePos = tr.c.point; - strikeAxis = -tr.endAxis; - } - } - } - - if ( *hitSound != '\0' ) { - const idSoundShader *snd = declManager->FindSound( hitSound ); - StartSoundShader( snd, SND_CHANNEL_BODY2, 0, true, NULL ); - } - - idThread::ReturnInt( hit ); - owner->WeaponFireFeedback( &weaponDef->dict ); - return; - } - - idThread::ReturnInt( 0 ); - owner->WeaponFireFeedback( &weaponDef->dict ); -} - -/* -===================== -idWeapon::Event_GetWorldModel -===================== -*/ -void idWeapon::Event_GetWorldModel( void ) { - idThread::ReturnEntity( worldModel.GetEntity() ); -} - -/* -===================== -idWeapon::Event_AllowDrop -===================== -*/ -void idWeapon::Event_AllowDrop( int allow ) { - if ( allow ) { - allowDrop = true; - } else { - allowDrop = false; - } -} - -/* -================ -idWeapon::Event_EjectBrass - -Toss a shell model out from the breach if the bone is present -================ -*/ -void idWeapon::Event_EjectBrass( void ) { - if ( !g_showBrass.GetBool() || !owner->CanShowWeaponViewmodel() ) { - return; - } - - if ( ejectJointView == INVALID_JOINT || !brassDict.GetNumKeyVals() ) { - return; - } - - if ( gameLocal.isClient ) { - return; - } - - idMat3 axis; - idVec3 origin, linear_velocity, angular_velocity; - idEntity *ent; - - if ( !GetGlobalJointTransform( true, ejectJointView, origin, axis ) ) { - return; - } - - gameLocal.SpawnEntityDef( brassDict, &ent, false ); - if ( !ent || !ent->IsType( idDebris::Type ) ) { - gameLocal.Error( "'%s' is not an idDebris", weaponDef ? weaponDef->dict.GetString( "def_ejectBrass" ) : "def_ejectBrass" ); - } - idDebris *debris = static_cast(ent); - debris->Create( owner, origin, axis ); - debris->Launch(); - - linear_velocity = 40 * ( playerViewAxis[0] + playerViewAxis[1] + playerViewAxis[2] ); - angular_velocity.Set( 10 * gameLocal.random.CRandomFloat(), 10 * gameLocal.random.CRandomFloat(), 10 * gameLocal.random.CRandomFloat() ); - - debris->GetPhysics()->SetLinearVelocity( linear_velocity ); - debris->GetPhysics()->SetAngularVelocity( angular_velocity ); -} - -/* -=============== -idWeapon::Event_IsInvisible -=============== -*/ -void idWeapon::Event_IsInvisible( void ) { - if ( !owner ) { - idThread::ReturnFloat( 0 ); - return; - } - idThread::ReturnFloat( owner->PowerUpActive( INVISIBILITY ) ? 1 : 0 ); -} - -/* -=============== -idWeapon::ClientPredictionThink -=============== -*/ -void idWeapon::ClientPredictionThink( void ) { - UpdateAnimation(); -} diff --git a/d3xp/Weapon.h b/d3xp/Weapon.h deleted file mode 100644 index 8e7a1d0e..00000000 --- a/d3xp/Weapon.h +++ /dev/null @@ -1,435 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __GAME_WEAPON_H__ -#define __GAME_WEAPON_H__ - -#include "script/Script_Thread.h" -#include "Entity.h" -#include "Light.h" -#include "Grabber.h" -#include "Actor.h" - -class idFuncEmitter; - -/* -=============================================================================== - - Player Weapon - -=============================================================================== -*/ - -#ifdef _D3XP -extern const idEventDef EV_Weapon_State; -#endif - -typedef enum { - WP_READY, - WP_OUTOFAMMO, - WP_RELOAD, - WP_HOLSTERED, - WP_RISING, - WP_LOWERING -} weaponStatus_t; - -typedef int ammo_t; -static const int AMMO_NUMTYPES = 16; - -class idPlayer; - -static const int LIGHTID_WORLD_MUZZLE_FLASH = 1; -static const int LIGHTID_VIEW_MUZZLE_FLASH = 100; - -class idMoveableItem; - -#ifdef _D3XP -typedef struct { - char name[64]; - char particlename[128]; - bool active; - int startTime; - jointHandle_t joint; //The joint on which to attach the particle - bool smoke; //Is this a smoke particle - const idDeclParticle* particle; //Used for smoke particles - idFuncEmitter* emitter; //Used for non-smoke particles -} WeaponParticle_t; - -typedef struct { - char name[64]; - bool active; - int startTime; - jointHandle_t joint; - int lightHandle; - renderLight_t light; -} WeaponLight_t; -#endif - -class idWeapon : public idAnimatedEntity { -public: - CLASS_PROTOTYPE( idWeapon ); - - idWeapon(); - virtual ~idWeapon(); - - // Init - void Spawn( void ); - void SetOwner( idPlayer *owner ); - idPlayer* GetOwner( void ); - virtual bool ShouldConstructScriptObjectAtSpawn( void ) const; - - static void CacheWeapon( const char *weaponName ); - - // save games - void Save( idSaveGame *savefile ) const; // archives object for save game file - void Restore( idRestoreGame *savefile ); // unarchives object from save game file - - // Weapon definition management - void Clear( void ); - void GetWeaponDef( const char *objectname, int ammoinclip ); - bool IsLinked( void ); - bool IsWorldModelReady( void ); - - // GUIs - const char * Icon( void ) const; - void UpdateGUI( void ); - - virtual void SetModel( const char *modelname ); - bool GetGlobalJointTransform( bool viewModel, const jointHandle_t jointHandle, idVec3 &offset, idMat3 &axis ); - void SetPushVelocity( const idVec3 &pushVelocity ); - bool UpdateSkin( void ); - - // State control/player interface - void Think( void ); - void Raise( void ); - void PutAway( void ); - void Reload( void ); - void LowerWeapon( void ); - void RaiseWeapon( void ); - void HideWeapon( void ); - void ShowWeapon( void ); - void HideWorldModel( void ); - void ShowWorldModel( void ); - void OwnerDied( void ); - void BeginAttack( void ); - void EndAttack( void ); - bool IsReady( void ) const; - bool IsReloading( void ) const; - bool IsHolstered( void ) const; - bool ShowCrosshair( void ) const; - idEntity * DropItem( const idVec3 &velocity, int activateDelay, int removeDelay, bool died ); - bool CanDrop( void ) const; - void WeaponStolen( void ); - -#ifdef _D3XP - weaponStatus_t GetStatus() { return status; }; - -#endif - - // Script state management - virtual idThread * ConstructScriptObject( void ); - virtual void DeconstructScriptObject( void ); - void SetState( const char *statename, int blendFrames ); - void UpdateScript( void ); - void EnterCinematic( void ); - void ExitCinematic( void ); - void NetCatchup( void ); - - // Visual presentation - void PresentWeapon( bool showViewModel ); - int GetZoomFov( void ); - void GetWeaponAngleOffsets( int *average, float *scale, float *max ); - void GetWeaponTimeOffsets( float *time, float *scale ); - bool BloodSplat( float size ); - - // Ammo - static ammo_t GetAmmoNumForName( const char *ammoname ); - static const char *GetAmmoNameForNum( ammo_t ammonum ); - static const char *GetAmmoPickupNameForNum( ammo_t ammonum ); - ammo_t GetAmmoType( void ) const; - int AmmoAvailable( void ) const; - int AmmoInClip( void ) const; - void ResetAmmoClip( void ); - int ClipSize( void ) const; - int LowAmmo( void ) const; - int AmmoRequired( void ) const; -#ifdef _D3XP - int AmmoCount() const; - int GetGrabberState() const; -#endif - - virtual void WriteToSnapshot( idBitMsgDelta &msg ) const; - virtual void ReadFromSnapshot( const idBitMsgDelta &msg ); - - enum { - EVENT_RELOAD = idEntity::EVENT_MAXEVENTS, - EVENT_ENDRELOAD, - EVENT_CHANGESKIN, - EVENT_MAXEVENTS - }; - virtual bool ClientReceiveEvent( int event, int time, const idBitMsg &msg ); - - virtual void ClientPredictionThink( void ); - -private: - // script control - idScriptBool WEAPON_ATTACK; - idScriptBool WEAPON_RELOAD; - idScriptBool WEAPON_NETRELOAD; - idScriptBool WEAPON_NETENDRELOAD; - idScriptBool WEAPON_NETFIRING; - idScriptBool WEAPON_RAISEWEAPON; - idScriptBool WEAPON_LOWERWEAPON; - weaponStatus_t status; - idThread * thread; - idStr state; - idStr idealState; - int animBlendFrames; - int animDoneTime; - bool isLinked; - - // precreated projectile - idEntity *projectileEnt; - - idPlayer * owner; - idEntityPtr worldModel; - - // hiding (for GUIs and NPCs) - int hideTime; - float hideDistance; - int hideStartTime; - float hideStart; - float hideEnd; - float hideOffset; - bool hide; - bool disabled; - - // berserk - int berserk; - - // these are the player render view parms, which include bobbing - idVec3 playerViewOrigin; - idMat3 playerViewAxis; - - // the view weapon render entity parms - idVec3 viewWeaponOrigin; - idMat3 viewWeaponAxis; - - // the muzzle bone's position, used for launching projectiles and trailing smoke - idVec3 muzzleOrigin; - idMat3 muzzleAxis; - - idVec3 pushVelocity; - - // weapon definition - // we maintain local copies of the projectile and brass dictionaries so they - // do not have to be copied across the DLL boundary when entities are spawned - const idDeclEntityDef * weaponDef; - const idDeclEntityDef * meleeDef; - idDict projectileDict; - float meleeDistance; - idStr meleeDefName; - idDict brassDict; - int brassDelay; - idStr icon; - - // view weapon gui light - renderLight_t guiLight; - int guiLightHandle; - - // muzzle flash - renderLight_t muzzleFlash; // positioned on view weapon bone - int muzzleFlashHandle; - - renderLight_t worldMuzzleFlash; // positioned on world weapon bone - int worldMuzzleFlashHandle; - - idVec3 flashColor; - int muzzleFlashEnd; - int flashTime; - bool lightOn; - bool silent_fire; - bool allowDrop; - - // effects - bool hasBloodSplat; - - // weapon kick - int kick_endtime; - int muzzle_kick_time; - int muzzle_kick_maxtime; - idAngles muzzle_kick_angles; - idVec3 muzzle_kick_offset; - - // ammo management - ammo_t ammoType; - int ammoRequired; // amount of ammo to use each shot. 0 means weapon doesn't need ammo. - int clipSize; // 0 means no reload - int ammoClip; - int lowAmmo; // if ammo in clip hits this threshold, snd_ - bool powerAmmo; // true if the clip reduction is a factor of the power setting when - // a projectile is launched - // mp client - bool isFiring; - - // zoom - int zoomFov; // variable zoom fov per weapon - - // joints from models - jointHandle_t barrelJointView; - jointHandle_t flashJointView; - jointHandle_t ejectJointView; - jointHandle_t guiLightJointView; - jointHandle_t ventLightJointView; - - jointHandle_t flashJointWorld; - jointHandle_t barrelJointWorld; - jointHandle_t ejectJointWorld; - -#ifdef _D3XP - jointHandle_t smokeJointView; - - idHashTable weaponParticles; - idHashTable weaponLights; -#endif - - // sound - const idSoundShader * sndHum; - - // new style muzzle smokes - const idDeclParticle * weaponSmoke; // null if it doesn't smoke - int weaponSmokeStartTime; // set to gameLocal.time every weapon fire - bool continuousSmoke; // if smoke is continuous ( chainsaw ) - const idDeclParticle * strikeSmoke; // striking something in melee - int strikeSmokeStartTime; // timing - idVec3 strikePos; // position of last melee strike - idMat3 strikeAxis; // axis of last melee strike - int nextStrikeFx; // used for sound and decal ( may use for strike smoke too ) - - // nozzle effects - bool nozzleFx; // does this use nozzle effects ( parm5 at rest, parm6 firing ) - // this also assumes a nozzle light atm - int nozzleFxFade; // time it takes to fade between the effects - int lastAttack; // last time an attack occured - renderLight_t nozzleGlow; // nozzle light - int nozzleGlowHandle; // handle for nozzle light - - idVec3 nozzleGlowColor; // color of the nozzle glow - const idMaterial * nozzleGlowShader; // shader for glow light - float nozzleGlowRadius; // radius of glow light - - // weighting for viewmodel angles - int weaponAngleOffsetAverages; - float weaponAngleOffsetScale; - float weaponAngleOffsetMax; - float weaponOffsetTime; - float weaponOffsetScale; - - // flashlight - void AlertMonsters( void ); - - // Visual presentation - void InitWorldModel( const idDeclEntityDef *def ); - void MuzzleFlashLight( void ); - void MuzzleRise( idVec3 &origin, idMat3 &axis ); - void UpdateNozzleFx( void ); - void UpdateFlashPosition( void ); - - // script events - void Event_Clear( void ); - void Event_GetOwner( void ); - void Event_WeaponState( const char *statename, int blendFrames ); - void Event_SetWeaponStatus( float newStatus ); - void Event_WeaponReady( void ); - void Event_WeaponOutOfAmmo( void ); - void Event_WeaponReloading( void ); - void Event_WeaponHolstered( void ); - void Event_WeaponRising( void ); - void Event_WeaponLowering( void ); - void Event_UseAmmo( int amount ); - void Event_AddToClip( int amount ); - void Event_AmmoInClip( void ); - void Event_AmmoAvailable( void ); - void Event_TotalAmmoCount( void ); - void Event_ClipSize( void ); - void Event_PlayAnim( int channel, const char *animname ); - void Event_PlayCycle( int channel, const char *animname ); - void Event_AnimDone( int channel, int blendFrames ); - void Event_SetBlendFrames( int channel, int blendFrames ); - void Event_GetBlendFrames( int channel ); - void Event_Next( void ); - void Event_SetSkin( const char *skinname ); - void Event_Flashlight( int enable ); - void Event_GetLightParm( int parmnum ); - void Event_SetLightParm( int parmnum, float value ); - void Event_SetLightParms( float parm0, float parm1, float parm2, float parm3 ); - void Event_LaunchProjectiles( int num_projectiles, float spread, float fuseOffset, float launchPower, float dmgPower ); - void Event_CreateProjectile( void ); - void Event_EjectBrass( void ); - void Event_Melee( void ); - void Event_GetWorldModel( void ); - void Event_AllowDrop( int allow ); - void Event_AutoReload( void ); - void Event_NetReload( void ); - void Event_IsInvisible( void ); - void Event_NetEndReload( void ); - -#ifdef _D3XP - idGrabber grabber; - int grabberState; - - void Event_Grabber( int enable ); - void Event_GrabberHasTarget( void ); - void Event_GrabberSetGrabDistance( float dist ); - void Event_LaunchProjectilesEllipse( int num_projectiles, float spreada, float spreadb, float fuseOffset, float power ); - void Event_LaunchPowerup( const char* powerup, float duration, int useAmmo ); - - void Event_StartWeaponSmoke(); - void Event_StopWeaponSmoke(); - - void Event_StartWeaponParticle( const char* name); - void Event_StopWeaponParticle( const char* name); - - void Event_StartWeaponLight( const char* name); - void Event_StopWeaponLight( const char* name); -#endif -}; - -ID_INLINE bool idWeapon::IsLinked( void ) { - return isLinked; -} - -ID_INLINE bool idWeapon::IsWorldModelReady( void ) { - return ( worldModel.GetEntity() != NULL ); -} - -ID_INLINE idPlayer* idWeapon::GetOwner( void ) { - return owner; -} - -#endif /* !__GAME_WEAPON_H__ */ diff --git a/d3xp/WorldSpawn.cpp b/d3xp/WorldSpawn.cpp deleted file mode 100644 index 1f97aad9..00000000 --- a/d3xp/WorldSpawn.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "framework/FileSystem.h" - -#include "gamesys/SysCvar.h" -#include "script/Script_Thread.h" - -#include "WorldSpawn.h" - -/* -================ -idWorldspawn - -Worldspawn class. Each map has one worldspawn which handles global spawnargs. -Every map should have exactly one worldspawn. -================ -*/ -CLASS_DECLARATION( idEntity, idWorldspawn ) - EVENT( EV_Remove, idWorldspawn::Event_Remove ) - EVENT( EV_SafeRemove, idWorldspawn::Event_Remove ) -END_CLASS - -/* -================ -idWorldspawn::Spawn -================ -*/ -void idWorldspawn::Spawn( void ) { - idStr scriptname; - idThread *thread; - const function_t *func; - const idKeyValue *kv; - - assert( gameLocal.world == NULL ); - gameLocal.world = this; - - g_gravity.SetFloat( spawnArgs.GetFloat( "gravity", va( "%f", DEFAULT_GRAVITY ) ) ); - - // disable stamina on hell levels - if ( spawnArgs.GetBool( "no_stamina" ) ) { - pm_stamina.SetFloat( 0.0f ); - } - - // load script - scriptname = gameLocal.GetMapName(); - scriptname.SetFileExtension( ".script" ); - if ( fileSystem->ReadFile( scriptname, NULL, NULL ) > 0 ) { - gameLocal.program.CompileFile( scriptname ); - - // call the main function by default - func = gameLocal.program.FindFunction( "main" ); - if ( func != NULL ) { - thread = new idThread( func ); - thread->DelayedStart( 0 ); - } - } - - // call any functions specified in worldspawn - kv = spawnArgs.MatchPrefix( "call" ); - while( kv != NULL ) { - func = gameLocal.program.FindFunction( kv->GetValue() ); - if ( func == NULL ) { - gameLocal.Error( "Function '%s' not found in script for '%s' key on worldspawn", kv->GetValue().c_str(), kv->GetKey().c_str() ); - } - - thread = new idThread( func ); - thread->DelayedStart( 0 ); - kv = spawnArgs.MatchPrefix( "call", kv ); - } -} - -/* -================= -idWorldspawn::Save -================= -*/ -void idWorldspawn::Save( idRestoreGame *savefile ) { -} - -/* -================= -idWorldspawn::Restore -================= -*/ -void idWorldspawn::Restore( idRestoreGame *savefile ) { - assert( gameLocal.world == this ); - - g_gravity.SetFloat( spawnArgs.GetFloat( "gravity", va( "%f", DEFAULT_GRAVITY ) ) ); - - // disable stamina on hell levels - if ( spawnArgs.GetBool( "no_stamina" ) ) { - pm_stamina.SetFloat( 0.0f ); - } -} - -/* -================ -idWorldspawn::~idWorldspawn -================ -*/ -idWorldspawn::~idWorldspawn() { - if ( gameLocal.world == this ) { - gameLocal.world = NULL; - } -} - -/* -================ -idWorldspawn::Event_Remove -================ -*/ -void idWorldspawn::Event_Remove( void ) { - gameLocal.Error( "Tried to remove world" ); -} diff --git a/d3xp/WorldSpawn.h b/d3xp/WorldSpawn.h deleted file mode 100644 index b8bb4e02..00000000 --- a/d3xp/WorldSpawn.h +++ /dev/null @@ -1,57 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __GAME_WORLDSPAWN_H__ -#define __GAME_WORLDSPAWN_H__ - -#include "Entity.h" - -/* -=============================================================================== - - World entity. - -=============================================================================== -*/ - -class idWorldspawn : public idEntity { -public: - CLASS_PROTOTYPE( idWorldspawn ); - - ~idWorldspawn(); - - void Spawn( void ); - - void Save( idRestoreGame *savefile ); - void Restore( idRestoreGame *savefile ); - -private: - void Event_Remove( void ); -}; - -#endif /* !__GAME_WORLDSPAWN_H__ */ diff --git a/d3xp/ai/AAS.cpp b/d3xp/ai/AAS.cpp deleted file mode 100644 index 10ab9c25..00000000 --- a/d3xp/ai/AAS.cpp +++ /dev/null @@ -1,276 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "framework/Common.h" -#include "tools/compilers/aas/AASFileManager.h" - -#include "ai/AAS_local.h" - -/* -============ -idAAS::Alloc -============ -*/ -idAAS *idAAS::Alloc( void ) { - return new idAASLocal; -} - -/* -============ -idAAS::idAAS -============ -*/ -idAAS::~idAAS( void ) { -} - -/* -============ -idAASLocal::idAASLocal -============ -*/ -idAASLocal::idAASLocal( void ) { - file = NULL; -} - -/* -============ -idAASLocal::~idAASLocal -============ -*/ -idAASLocal::~idAASLocal( void ) { - Shutdown(); -} - -/* -============ -idAASLocal::Init -============ -*/ -bool idAASLocal::Init( const idStr &mapName, unsigned int mapFileCRC ) { - if ( file && mapName.Icmp( file->GetName() ) == 0 && mapFileCRC == file->GetCRC() ) { - common->Printf( "Keeping %s\n", file->GetName() ); - RemoveAllObstacles(); - } - else { - Shutdown(); - - file = AASFileManager->LoadAAS( mapName, mapFileCRC ); - if ( !file ) { - common->DWarning( "Couldn't load AAS file: '%s'", mapName.c_str() ); - return false; - } - SetupRouting(); - } - return true; -} - -/* -============ -idAASLocal::Shutdown -============ -*/ -void idAASLocal::Shutdown( void ) { - if ( file ) { - ShutdownRouting(); - RemoveAllObstacles(); - AASFileManager->FreeAAS( file ); - file = NULL; - } -} - -/* -============ -idAASLocal::Stats -============ -*/ -void idAASLocal::Stats( void ) const { - if ( !file ) { - return; - } - common->Printf( "[%s]\n", file->GetName() ); - file->PrintInfo(); - RoutingStats(); -} - -/* -============ -idAASLocal::GetSettings -============ -*/ -const idAASSettings *idAASLocal::GetSettings( void ) const { - if ( !file ) { - return NULL; - } - return &file->GetSettings(); -} - -/* -============ -idAASLocal::PointAreaNum -============ -*/ -int idAASLocal::PointAreaNum( const idVec3 &origin ) const { - if ( !file ) { - return 0; - } - return file->PointAreaNum( origin ); -} - -/* -============ -idAASLocal::PointReachableAreaNum -============ -*/ -int idAASLocal::PointReachableAreaNum( const idVec3 &origin, const idBounds &searchBounds, const int areaFlags ) const { - if ( !file ) { - return 0; - } - - return file->PointReachableAreaNum( origin, searchBounds, areaFlags, TFL_INVALID ); -} - -/* -============ -idAASLocal::BoundsReachableAreaNum -============ -*/ -int idAASLocal::BoundsReachableAreaNum( const idBounds &bounds, const int areaFlags ) const { - if ( !file ) { - return 0; - } - - return file->BoundsReachableAreaNum( bounds, areaFlags, TFL_INVALID ); -} - -/* -============ -idAASLocal::PushPointIntoAreaNum -============ -*/ -void idAASLocal::PushPointIntoAreaNum( int areaNum, idVec3 &origin ) const { - if ( !file ) { - return; - } - file->PushPointIntoAreaNum( areaNum, origin ); -} - -/* -============ -idAASLocal::AreaCenter -============ -*/ -idVec3 idAASLocal::AreaCenter( int areaNum ) const { - if ( !file ) { - return vec3_origin; - } - return file->GetArea( areaNum ).center; -} - -/* -============ -idAASLocal::AreaFlags -============ -*/ -int idAASLocal::AreaFlags( int areaNum ) const { - if ( !file ) { - return 0; - } - return file->GetArea( areaNum ).flags; -} - -/* -============ -idAASLocal::AreaTravelFlags -============ -*/ -int idAASLocal::AreaTravelFlags( int areaNum ) const { - if ( !file ) { - return 0; - } - return file->GetArea( areaNum ).travelFlags; -} - -/* -============ -idAASLocal::Trace -============ -*/ -bool idAASLocal::Trace( aasTrace_t &trace, const idVec3 &start, const idVec3 &end ) const { - if ( !file ) { - trace.fraction = 0.0f; - trace.lastAreaNum = 0; - trace.numAreas = 0; - return true; - } - return file->Trace( trace, start, end ); -} - -/* -============ -idAASLocal::GetPlane -============ -*/ -const idPlane &idAASLocal::GetPlane( int planeNum ) const { - if ( !file ) { - static idPlane dummy; - return dummy; - } - return file->GetPlane( planeNum ); -} - -/* -============ -idAASLocal::GetEdgeVertexNumbers -============ -*/ -void idAASLocal::GetEdgeVertexNumbers( int edgeNum, int verts[2] ) const { - if ( !file ) { - verts[0] = verts[1] = 0; - return; - } - const int *v = file->GetEdge( abs(edgeNum) ).vertexNum; - verts[0] = v[INTSIGNBITSET(edgeNum)]; - verts[1] = v[INTSIGNBITNOTSET(edgeNum)]; -} - -/* -============ -idAASLocal::GetEdge -============ -*/ -void idAASLocal::GetEdge( int edgeNum, idVec3 &start, idVec3 &end ) const { - if ( !file ) { - start.Zero(); - end.Zero(); - return; - } - const int *v = file->GetEdge( abs(edgeNum) ).vertexNum; - start = file->GetVertex( v[INTSIGNBITSET(edgeNum)] ); - end = file->GetVertex( v[INTSIGNBITNOTSET(edgeNum)] ); -} diff --git a/d3xp/ai/AAS.h b/d3xp/ai/AAS.h deleted file mode 100644 index 08ab9c09..00000000 --- a/d3xp/ai/AAS.h +++ /dev/null @@ -1,143 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __AAS_H__ -#define __AAS_H__ - -#include "tools/compilers/aas/AASFile.h" - -/* -=============================================================================== - - Area Awareness System - -=============================================================================== -*/ - -enum { - PATHTYPE_WALK, - PATHTYPE_WALKOFFLEDGE, - PATHTYPE_BARRIERJUMP, - PATHTYPE_JUMP -}; - -typedef struct aasPath_s { - int type; // path type - idVec3 moveGoal; // point the AI should move towards - int moveAreaNum; // number of the area the AI should move towards - idVec3 secondaryGoal; // secondary move goal for complex navigation - const idReachability * reachability; // reachability used for navigation -} aasPath_t; - - -typedef struct aasGoal_s { - int areaNum; // area the goal is in - idVec3 origin; // position of goal -} aasGoal_t; - - -typedef struct aasObstacle_s { - idBounds absBounds; // absolute bounds of obstacle - idBounds expAbsBounds; // expanded absolute bounds of obstacle -} aasObstacle_t; - -class idAASCallback { -public: - virtual ~idAASCallback() {}; - virtual bool TestArea( const class idAAS *aas, int areaNum ) = 0; -}; - -typedef int aasHandle_t; - -class idAAS { -public: - static idAAS * Alloc( void ); - virtual ~idAAS( void ) = 0; - // Initialize for the given map. - virtual bool Init( const idStr &mapName, unsigned int mapFileCRC ) = 0; - // Print AAS stats. - virtual void Stats( void ) const = 0; - // Test from the given origin. - virtual void Test( const idVec3 &origin ) = 0; - // Get the AAS settings. - virtual const idAASSettings *GetSettings( void ) const = 0; - // Returns the number of the area the origin is in. - virtual int PointAreaNum( const idVec3 &origin ) const = 0; - // Returns the number of the nearest reachable area for the given point. - virtual int PointReachableAreaNum( const idVec3 &origin, const idBounds &bounds, const int areaFlags ) const = 0; - // Returns the number of the first reachable area in or touching the bounds. - virtual int BoundsReachableAreaNum( const idBounds &bounds, const int areaFlags ) const = 0; - // Push the point into the area. - virtual void PushPointIntoAreaNum( int areaNum, idVec3 &origin ) const = 0; - // Returns a reachable point inside the given area. - virtual idVec3 AreaCenter( int areaNum ) const = 0; - // Returns the area flags. - virtual int AreaFlags( int areaNum ) const = 0; - // Returns the travel flags for traveling through the area. - virtual int AreaTravelFlags( int areaNum ) const = 0; - // Trace through the areas and report the first collision. - virtual bool Trace( aasTrace_t &trace, const idVec3 &start, const idVec3 &end ) const = 0; - // Get a plane for a trace. - virtual const idPlane & GetPlane( int planeNum ) const = 0; - // Get wall edges. - virtual int GetWallEdges( int areaNum, const idBounds &bounds, int travelFlags, int *edges, int maxEdges ) const = 0; - // Sort the wall edges to create continuous sequences of walls. - virtual void SortWallEdges( int *edges, int numEdges ) const = 0; - // Get the vertex numbers for an edge. - virtual void GetEdgeVertexNumbers( int edgeNum, int verts[2] ) const = 0; - // Get an edge. - virtual void GetEdge( int edgeNum, idVec3 &start, idVec3 &end ) const = 0; - // Find all areas within or touching the bounds with the given contents and disable/enable them for routing. - virtual bool SetAreaState( const idBounds &bounds, const int areaContents, bool disabled ) = 0; - // Add an obstacle to the routing system. - virtual aasHandle_t AddObstacle( const idBounds &bounds ) = 0; - // Remove an obstacle from the routing system. - virtual void RemoveObstacle( const aasHandle_t handle ) = 0; - // Remove all obstacles from the routing system. - virtual void RemoveAllObstacles( void ) = 0; - // Returns the travel time towards the goal area in 100th of a second. - virtual int TravelTimeToGoalArea( int areaNum, const idVec3 &origin, int goalAreaNum, int travelFlags ) const = 0; - // Get the travel time and first reachability to be used towards the goal, returns true if there is a path. - virtual bool RouteToGoalArea( int areaNum, const idVec3 origin, int goalAreaNum, int travelFlags, int &travelTime, idReachability **reach ) const = 0; - // Creates a walk path towards the goal. - virtual bool WalkPathToGoal( aasPath_t &path, int areaNum, const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin, int travelFlags ) const = 0; - // Returns true if one can walk along a straight line from the origin to the goal origin. - virtual bool WalkPathValid( int areaNum, const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin, int travelFlags, idVec3 &endPos, int &endAreaNum ) const = 0; - // Creates a fly path towards the goal. - virtual bool FlyPathToGoal( aasPath_t &path, int areaNum, const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin, int travelFlags ) const = 0; - // Returns true if one can fly along a straight line from the origin to the goal origin. - virtual bool FlyPathValid( int areaNum, const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin, int travelFlags, idVec3 &endPos, int &endAreaNum ) const = 0; - // Show the walk path from the origin towards the area. - virtual void ShowWalkPath( const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin ) const = 0; - // Show the fly path from the origin towards the area. - virtual void ShowFlyPath( const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin ) const = 0; - // Find the nearest goal which satisfies the callback. - virtual bool FindNearestGoal( aasGoal_t &goal, int areaNum, const idVec3 origin, const idVec3 &target, int travelFlags, aasObstacle_t *obstacles, int numObstacles, idAASCallback &callback ) const = 0; -}; - -#endif /* !__AAS_H__ */ diff --git a/d3xp/ai/AAS_debug.cpp b/d3xp/ai/AAS_debug.cpp deleted file mode 100644 index ad9d8c6c..00000000 --- a/d3xp/ai/AAS_debug.cpp +++ /dev/null @@ -1,499 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "gamesys/SysCvar.h" -#include "ai/AI.h" -#include "Player.h" -#include "Game_local.h" - -#include "ai/AAS_local.h" - -/* -============ -idAASLocal::DrawCone -============ -*/ -void idAASLocal::DrawCone( const idVec3 &origin, const idVec3 &dir, float radius, const idVec4 &color ) const { - int i; - idMat3 axis; - idVec3 center, top, p, lastp; - - axis[2] = dir; - axis[2].NormalVectors( axis[0], axis[1] ); - axis[1] = -axis[1]; - - center = origin + dir; - top = center + dir * (3.0f * radius); - lastp = center + radius * axis[1]; - - for ( i = 20; i <= 360; i += 20 ) { - p = center + sin( DEG2RAD(i) ) * radius * axis[0] + cos( DEG2RAD(i) ) * radius * axis[1]; - gameRenderWorld->DebugLine( color, lastp, p, 0 ); - gameRenderWorld->DebugLine( color, p, top, 0 ); - lastp = p; - } -} - -/* -============ -idAASLocal::DrawReachability -============ -*/ -void idAASLocal::DrawReachability( const idReachability *reach ) const { - gameRenderWorld->DebugArrow( colorCyan, reach->start, reach->end, 2 ); - - if ( gameLocal.GetLocalPlayer() ) { - gameRenderWorld->DrawText( va( "%d", reach->edgeNum ), ( reach->start + reach->end ) * 0.5f, 0.1f, colorWhite, gameLocal.GetLocalPlayer()->viewAxis ); - } -} - -/* -============ -idAASLocal::DrawEdge -============ -*/ -void idAASLocal::DrawEdge( int edgeNum, bool arrow ) const { - const aasEdge_t *edge; - idVec4 *color; - - if ( !file ) { - return; - } - - edge = &file->GetEdge( edgeNum ); - color = &colorRed; - if ( arrow ) { - gameRenderWorld->DebugArrow( *color, file->GetVertex( edge->vertexNum[0] ), file->GetVertex( edge->vertexNum[1] ), 1 ); - } else { - gameRenderWorld->DebugLine( *color, file->GetVertex( edge->vertexNum[0] ), file->GetVertex( edge->vertexNum[1] ) ); - } - - if ( gameLocal.GetLocalPlayer() ) { - gameRenderWorld->DrawText( va( "%d", edgeNum ), ( file->GetVertex( edge->vertexNum[0] ) + file->GetVertex( edge->vertexNum[1] ) ) * 0.5f + idVec3(0,0,4), 0.1f, colorRed, gameLocal.GetLocalPlayer()->viewAxis ); - } -} - -/* -============ -idAASLocal::DrawFace -============ -*/ -void idAASLocal::DrawFace( int faceNum, bool side ) const { - int i, j, numEdges, firstEdge; - const aasFace_t *face; - idVec3 mid, end; - - if ( !file ) { - return; - } - - face = &file->GetFace( faceNum ); - numEdges = face->numEdges; - firstEdge = face->firstEdge; - - mid = vec3_origin; - for ( i = 0; i < numEdges; i++ ) { - DrawEdge( abs( file->GetEdgeIndex( firstEdge + i ) ), ( face->flags & FACE_FLOOR ) != 0 ); - j = file->GetEdgeIndex( firstEdge + i ); - mid += file->GetVertex( file->GetEdge( abs( j ) ).vertexNum[ j < 0 ] ); - } - - mid /= numEdges; - if ( side ) { - end = mid - 5.0f * file->GetPlane( file->GetFace( faceNum ).planeNum ).Normal(); - } else { - end = mid + 5.0f * file->GetPlane( file->GetFace( faceNum ).planeNum ).Normal(); - } - gameRenderWorld->DebugArrow( colorGreen, mid, end, 1 ); -} - -/* -============ -idAASLocal::DrawArea -============ -*/ -void idAASLocal::DrawArea( int areaNum ) const { - int i, numFaces, firstFace; - const aasArea_t *area; - idReachability *reach; - - if ( !file ) { - return; - } - - area = &file->GetArea( areaNum ); - numFaces = area->numFaces; - firstFace = area->firstFace; - - for ( i = 0; i < numFaces; i++ ) { - DrawFace( abs( file->GetFaceIndex( firstFace + i ) ), file->GetFaceIndex( firstFace + i ) < 0 ); - } - - for ( reach = area->reach; reach; reach = reach->next ) { - DrawReachability( reach ); - } -} - -/* -============ -idAASLocal::DefaultSearchBounds -============ -*/ -const idBounds &idAASLocal::DefaultSearchBounds( void ) const { - return file->GetSettings().boundingBoxes[0]; -} - -/* -============ -idAASLocal::ShowArea -============ -*/ -void idAASLocal::ShowArea( const idVec3 &origin ) const { - static int lastAreaNum; - int areaNum; - const aasArea_t *area; - idVec3 org; - - areaNum = PointReachableAreaNum( origin, DefaultSearchBounds(), (AREA_REACHABLE_WALK|AREA_REACHABLE_FLY) ); - org = origin; - PushPointIntoAreaNum( areaNum, org ); - - if ( aas_goalArea.GetInteger() ) { - int travelTime; - idReachability *reach; - - RouteToGoalArea( areaNum, org, aas_goalArea.GetInteger(), TFL_WALK|TFL_AIR, travelTime, &reach ); - gameLocal.Printf( "\rtt = %4d", travelTime ); - if ( reach ) { - gameLocal.Printf( " to area %4d", reach->toAreaNum ); - DrawArea( reach->toAreaNum ); - } - } - - if ( areaNum != lastAreaNum ) { - area = &file->GetArea( areaNum ); - gameLocal.Printf( "area %d: ", areaNum ); - if ( area->flags & AREA_LEDGE ) { - gameLocal.Printf( "AREA_LEDGE " ); - } - if ( area->flags & AREA_REACHABLE_WALK ) { - gameLocal.Printf( "AREA_REACHABLE_WALK " ); - } - if ( area->flags & AREA_REACHABLE_FLY ) { - gameLocal.Printf( "AREA_REACHABLE_FLY " ); - } - if ( area->contents & AREACONTENTS_CLUSTERPORTAL ) { - gameLocal.Printf( "AREACONTENTS_CLUSTERPORTAL " ); - } - if ( area->contents & AREACONTENTS_OBSTACLE ) { - gameLocal.Printf( "AREACONTENTS_OBSTACLE " ); - } - gameLocal.Printf( "\n" ); - lastAreaNum = areaNum; - } - - if ( org != origin ) { - idBounds bnds = file->GetSettings().boundingBoxes[ 0 ]; - bnds[ 1 ].z = bnds[ 0 ].z; - gameRenderWorld->DebugBounds( colorYellow, bnds, org ); - } - - DrawArea( areaNum ); -} - -/* -============ -idAASLocal::ShowWalkPath -============ -*/ -void idAASLocal::ShowWalkPath( const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin ) const { - int i, areaNum, curAreaNum, travelTime; - idReachability *reach; - idVec3 org, areaCenter; - aasPath_t path; - - if ( !file ) { - return; - } - - org = origin; - areaNum = PointReachableAreaNum( org, DefaultSearchBounds(), AREA_REACHABLE_WALK ); - PushPointIntoAreaNum( areaNum, org ); - curAreaNum = areaNum; - - for ( i = 0; i < 100; i++ ) { - - if ( !RouteToGoalArea( curAreaNum, org, goalAreaNum, TFL_WALK|TFL_AIR, travelTime, &reach ) ) { - break; - } - - if ( !reach ) { - break; - } - - gameRenderWorld->DebugArrow( colorGreen, org, reach->start, 2 ); - DrawReachability( reach ); - - if ( reach->toAreaNum == goalAreaNum ) { - break; - } - - curAreaNum = reach->toAreaNum; - org = reach->end; - } - - if ( WalkPathToGoal( path, areaNum, origin, goalAreaNum, goalOrigin, TFL_WALK|TFL_AIR ) ) { - gameRenderWorld->DebugArrow( colorBlue, origin, path.moveGoal, 2 ); - } -} - -/* -============ -idAASLocal::ShowFlyPath -============ -*/ -void idAASLocal::ShowFlyPath( const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin ) const { - int i, areaNum, curAreaNum, travelTime; - idReachability *reach; - idVec3 org, areaCenter; - aasPath_t path; - - if ( !file ) { - return; - } - - org = origin; - areaNum = PointReachableAreaNum( org, DefaultSearchBounds(), AREA_REACHABLE_FLY ); - PushPointIntoAreaNum( areaNum, org ); - curAreaNum = areaNum; - - for ( i = 0; i < 100; i++ ) { - - if ( !RouteToGoalArea( curAreaNum, org, goalAreaNum, TFL_WALK|TFL_FLY|TFL_AIR, travelTime, &reach ) ) { - break; - } - - if ( !reach ) { - break; - } - - gameRenderWorld->DebugArrow( colorPurple, org, reach->start, 2 ); - DrawReachability( reach ); - - if ( reach->toAreaNum == goalAreaNum ) { - break; - } - - curAreaNum = reach->toAreaNum; - org = reach->end; - } - - if ( FlyPathToGoal( path, areaNum, origin, goalAreaNum, goalOrigin, TFL_WALK|TFL_FLY|TFL_AIR ) ) { - gameRenderWorld->DebugArrow( colorBlue, origin, path.moveGoal, 2 ); - } -} - -/* -============ -idAASLocal::ShowWallEdges -============ -*/ -void idAASLocal::ShowWallEdges( const idVec3 &origin ) const { - int i, areaNum, numEdges, edges[1024]; - idVec3 start, end; - idPlayer *player; - - player = gameLocal.GetLocalPlayer(); - if ( !player ) { - return; - } - - areaNum = PointReachableAreaNum( origin, DefaultSearchBounds(), (AREA_REACHABLE_WALK|AREA_REACHABLE_FLY) ); - numEdges = GetWallEdges( areaNum, idBounds( origin ).Expand( 256.0f ), TFL_WALK, edges, 1024 ); - for ( i = 0; i < numEdges; i++ ) { - GetEdge( edges[i], start, end ); - gameRenderWorld->DebugLine( colorRed, start, end ); - gameRenderWorld->DrawText( va( "%d", edges[i] ), ( start + end ) * 0.5f, 0.1f, colorWhite, player->viewAxis ); - } -} - -/* -============ -idAASLocal::ShowHideArea -============ -*/ -void idAASLocal::ShowHideArea( const idVec3 &origin, int targetAreaNum ) const { - int areaNum, numObstacles; - idVec3 target; - aasGoal_t goal; - aasObstacle_t obstacles[10]; - - areaNum = PointReachableAreaNum( origin, DefaultSearchBounds(), (AREA_REACHABLE_WALK|AREA_REACHABLE_FLY) ); - target = AreaCenter( targetAreaNum ); - - // consider the target an obstacle - obstacles[0].absBounds = idBounds( target ).Expand( 16 ); - numObstacles = 1; - - DrawCone( target, idVec3(0,0,1), 16.0f, colorYellow ); - - idAASFindCover findCover( target ); - if ( FindNearestGoal( goal, areaNum, origin, target, TFL_WALK|TFL_AIR, obstacles, numObstacles, findCover ) ) { - DrawArea( goal.areaNum ); - ShowWalkPath( origin, goal.areaNum, goal.origin ); - DrawCone( goal.origin, idVec3(0,0,1), 16.0f, colorWhite ); - } -} - -/* -============ -idAASLocal::PullPlayer -============ -*/ -bool idAASLocal::PullPlayer( const idVec3 &origin, int toAreaNum ) const { - int areaNum; - idVec3 areaCenter, dir, vel; - idAngles delta; - aasPath_t path; - idPlayer *player; - - player = gameLocal.GetLocalPlayer(); - if ( !player ) { - return true; - } - - idPhysics *physics = player->GetPhysics(); - if ( !physics ) { - return true; - } - - if ( !toAreaNum ) { - return false; - } - - areaNum = PointReachableAreaNum( origin, DefaultSearchBounds(), (AREA_REACHABLE_WALK|AREA_REACHABLE_FLY) ); - areaCenter = AreaCenter( toAreaNum ); - if ( player->GetPhysics()->GetAbsBounds().Expand( 8 ).ContainsPoint( areaCenter ) ) { - return false; - } - if ( WalkPathToGoal( path, areaNum, origin, toAreaNum, areaCenter, TFL_WALK|TFL_AIR ) ) { - dir = path.moveGoal - origin; - dir[2] *= 0.5f; - dir.Normalize(); - delta = dir.ToAngles() - player->cmdAngles - player->GetDeltaViewAngles(); - delta.Normalize180(); - player->SetDeltaViewAngles( player->GetDeltaViewAngles() + delta * 0.1f ); - dir[2] = 0.0f; - dir.Normalize(); - dir *= 100.0f; - vel = physics->GetLinearVelocity(); - dir[2] = vel[2]; - physics->SetLinearVelocity( dir ); - return true; - } - else { - return false; - } -} - -/* -============ -idAASLocal::RandomPullPlayer -============ -*/ -void idAASLocal::RandomPullPlayer( const idVec3 &origin ) const { - int rnd, i, n; - - if ( !PullPlayer( origin, aas_pullPlayer.GetInteger() ) ) { - - rnd = gameLocal.random.RandomFloat() * file->GetNumAreas(); - - for ( i = 0; i < file->GetNumAreas(); i++ ) { - n = (rnd + i) % file->GetNumAreas(); - if ( file->GetArea( n ).flags & (AREA_REACHABLE_WALK|AREA_REACHABLE_FLY) ) { - aas_pullPlayer.SetInteger( n ); - } - } - } else { - ShowWalkPath( origin, aas_pullPlayer.GetInteger(), AreaCenter( aas_pullPlayer.GetInteger() ) ); - } -} - -/* -============ -idAASLocal::ShowPushIntoArea -============ -*/ -void idAASLocal::ShowPushIntoArea( const idVec3 &origin ) const { - int areaNum; - idVec3 target; - - target = origin; - areaNum = PointReachableAreaNum( target, DefaultSearchBounds(), (AREA_REACHABLE_WALK|AREA_REACHABLE_FLY) ); - PushPointIntoAreaNum( areaNum, target ); - gameRenderWorld->DebugArrow( colorGreen, origin, target, 1 ); -} - -/* -============ -idAASLocal::Test -============ -*/ -void idAASLocal::Test( const idVec3 &origin ) { - - if ( !file ) { - return; - } - - if ( aas_randomPullPlayer.GetBool() ) { - RandomPullPlayer( origin ); - } - if ( ( aas_pullPlayer.GetInteger() > 0 ) && ( aas_pullPlayer.GetInteger() < file->GetNumAreas() ) ) { - ShowWalkPath( origin, aas_pullPlayer.GetInteger(), AreaCenter( aas_pullPlayer.GetInteger() ) ); - PullPlayer( origin, aas_pullPlayer.GetInteger() ); - } - if ( ( aas_showPath.GetInteger() > 0 ) && ( aas_showPath.GetInteger() < file->GetNumAreas() ) ) { - ShowWalkPath( origin, aas_showPath.GetInteger(), AreaCenter( aas_showPath.GetInteger() ) ); - } - if ( ( aas_showFlyPath.GetInteger() > 0 ) && ( aas_showFlyPath.GetInteger() < file->GetNumAreas() ) ) { - ShowFlyPath( origin, aas_showFlyPath.GetInteger(), AreaCenter( aas_showFlyPath.GetInteger() ) ); - } - if ( ( aas_showHideArea.GetInteger() > 0 ) && ( aas_showHideArea.GetInteger() < file->GetNumAreas() ) ) { - ShowHideArea( origin, aas_showHideArea.GetInteger() ); - } - if ( aas_showAreas.GetBool() ) { - ShowArea( origin ); - } - if ( aas_showWallEdges.GetBool() ) { - ShowWallEdges( origin ); - } - if ( aas_showPushIntoArea.GetBool() ) { - ShowPushIntoArea( origin ); - } -} diff --git a/d3xp/ai/AAS_local.h b/d3xp/ai/AAS_local.h deleted file mode 100644 index 6d32c2ed..00000000 --- a/d3xp/ai/AAS_local.h +++ /dev/null @@ -1,188 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __AAS_LOCAL_H__ -#define __AAS_LOCAL_H__ - -#include "ai/AAS.h" -#include "Pvs.h" - -class idRoutingCache { - friend class idAASLocal; - -public: - idRoutingCache( int size ); - ~idRoutingCache( void ); - - int Size( void ) const; - -private: - int type; // portal or area cache - int size; // size of cache - int cluster; // cluster of the cache - int areaNum; // area of the cache - int travelFlags; // combinations of the travel flags - idRoutingCache * next; // next in list - idRoutingCache * prev; // previous in list - idRoutingCache * time_next; // next in time based list - idRoutingCache * time_prev; // previous in time based list - unsigned short startTravelTime; // travel time to start with - unsigned char * reachabilities; // reachabilities used for routing - unsigned short * travelTimes; // travel time for every area -}; - - -class idRoutingUpdate { - friend class idAASLocal; - -private: - int cluster; // cluster number of this update - int areaNum; // area number of this update - unsigned short tmpTravelTime; // temporary travel time - unsigned short * areaTravelTimes; // travel times within the area - idVec3 start; // start point into area - idRoutingUpdate * next; // next in list - idRoutingUpdate * prev; // prev in list - bool isInList; // true if the update is in the list -}; - - -class idRoutingObstacle { - friend class idAASLocal; - idRoutingObstacle( void ) { } - -private: - idBounds bounds; // obstacle bounds - idList areas; // areas the bounds are in -}; - - -class idAASLocal : public idAAS { -public: - idAASLocal( void ); - virtual ~idAASLocal( void ); - virtual bool Init( const idStr &mapName, unsigned int mapFileCRC ); - virtual void Shutdown( void ); - virtual void Stats( void ) const; - virtual void Test( const idVec3 &origin ); - virtual const idAASSettings *GetSettings( void ) const; - virtual int PointAreaNum( const idVec3 &origin ) const; - virtual int PointReachableAreaNum( const idVec3 &origin, const idBounds &searchBounds, const int areaFlags ) const; - virtual int BoundsReachableAreaNum( const idBounds &bounds, const int areaFlags ) const; - virtual void PushPointIntoAreaNum( int areaNum, idVec3 &origin ) const; - virtual idVec3 AreaCenter( int areaNum ) const; - virtual int AreaFlags( int areaNum ) const; - virtual int AreaTravelFlags( int areaNum ) const; - virtual bool Trace( aasTrace_t &trace, const idVec3 &start, const idVec3 &end ) const; - virtual const idPlane & GetPlane( int planeNum ) const; - virtual int GetWallEdges( int areaNum, const idBounds &bounds, int travelFlags, int *edges, int maxEdges ) const; - virtual void SortWallEdges( int *edges, int numEdges ) const; - virtual void GetEdgeVertexNumbers( int edgeNum, int verts[2] ) const; - virtual void GetEdge( int edgeNum, idVec3 &start, idVec3 &end ) const; - virtual bool SetAreaState( const idBounds &bounds, const int areaContents, bool disabled ); - virtual aasHandle_t AddObstacle( const idBounds &bounds ); - virtual void RemoveObstacle( const aasHandle_t handle ); - virtual void RemoveAllObstacles( void ); - virtual int TravelTimeToGoalArea( int areaNum, const idVec3 &origin, int goalAreaNum, int travelFlags ) const; - virtual bool RouteToGoalArea( int areaNum, const idVec3 origin, int goalAreaNum, int travelFlags, int &travelTime, idReachability **reach ) const; - virtual bool WalkPathToGoal( aasPath_t &path, int areaNum, const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin, int travelFlags ) const; - virtual bool WalkPathValid( int areaNum, const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin, int travelFlags, idVec3 &endPos, int &endAreaNum ) const; - virtual bool FlyPathToGoal( aasPath_t &path, int areaNum, const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin, int travelFlags ) const; - virtual bool FlyPathValid( int areaNum, const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin, int travelFlags, idVec3 &endPos, int &endAreaNum ) const; - virtual void ShowWalkPath( const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin ) const; - virtual void ShowFlyPath( const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin ) const; - virtual bool FindNearestGoal( aasGoal_t &goal, int areaNum, const idVec3 origin, const idVec3 &target, int travelFlags, aasObstacle_t *obstacles, int numObstacles, idAASCallback &callback ) const; - -private: - idAASFile * file; - idStr name; - -private: // routing data - idRoutingCache *** areaCacheIndex; // for each area in each cluster the travel times to all other areas in the cluster - int areaCacheIndexSize; // number of area cache entries - idRoutingCache ** portalCacheIndex; // for each area in the world the travel times from each portal - int portalCacheIndexSize; // number of portal cache entries - idRoutingUpdate * areaUpdate; // memory used to update the area routing cache - idRoutingUpdate * portalUpdate; // memory used to update the portal routing cache - unsigned short * goalAreaTravelTimes; // travel times to goal areas - unsigned short * areaTravelTimes; // travel times through the areas - int numAreaTravelTimes; // number of area travel times - mutable idRoutingCache * cacheListStart; // start of list with cache sorted from oldest to newest - mutable idRoutingCache * cacheListEnd; // end of list with cache sorted from oldest to newest - mutable int totalCacheMemory; // total cache memory used - idList obstacleList; // list with obstacles - -private: // routing - bool SetupRouting( void ); - void ShutdownRouting( void ); - unsigned short AreaTravelTime( int areaNum, const idVec3 &start, const idVec3 &end ) const; - void CalculateAreaTravelTimes( void ); - void DeleteAreaTravelTimes( void ); - void SetupRoutingCache( void ); - void DeleteClusterCache( int clusterNum ); - void DeletePortalCache( void ); - void ShutdownRoutingCache( void ); - void RoutingStats( void ) const; - void LinkCache( idRoutingCache *cache ) const; - void UnlinkCache( idRoutingCache *cache ) const; - void DeleteOldestCache( void ) const; - idReachability * GetAreaReachability( int areaNum, int reachabilityNum ) const; - int ClusterAreaNum( int clusterNum, int areaNum ) const; - void UpdateAreaRoutingCache( idRoutingCache *areaCache ) const; - idRoutingCache * GetAreaRoutingCache( int clusterNum, int areaNum, int travelFlags ) const; - void UpdatePortalRoutingCache( idRoutingCache *portalCache ) const; - idRoutingCache * GetPortalRoutingCache( int clusterNum, int areaNum, int travelFlags ) const; - void RemoveRoutingCacheUsingArea( int areaNum ); - void DisableArea( int areaNum ); - void EnableArea( int areaNum ); - bool SetAreaState_r( int nodeNum, const idBounds &bounds, const int areaContents, bool disabled ); - void GetBoundsAreas_r( int nodeNum, const idBounds &bounds, idList &areas ) const; - void SetObstacleState( const idRoutingObstacle *obstacle, bool enable ); - -private: // pathing - bool EdgeSplitPoint( idVec3 &split, int edgeNum, const idPlane &plane ) const; - bool FloorEdgeSplitPoint( idVec3 &split, int areaNum, const idPlane &splitPlane, const idPlane &frontPlane, bool closest ) const; - idVec3 SubSampleWalkPath( int areaNum, const idVec3 &origin, const idVec3 &start, const idVec3 &end, int travelFlags, int &endAreaNum ) const; - idVec3 SubSampleFlyPath( int areaNum, const idVec3 &origin, const idVec3 &start, const idVec3 &end, int travelFlags, int &endAreaNum ) const; - -private: // debug - const idBounds & DefaultSearchBounds( void ) const; - void DrawCone( const idVec3 &origin, const idVec3 &dir, float radius, const idVec4 &color ) const; - void DrawArea( int areaNum ) const; - void DrawFace( int faceNum, bool side ) const; - void DrawEdge( int edgeNum, bool arrow ) const; - void DrawReachability( const idReachability *reach ) const; - void ShowArea( const idVec3 &origin ) const; - void ShowWallEdges( const idVec3 &origin ) const; - void ShowHideArea( const idVec3 &origin, int targerAreaNum ) const; - bool PullPlayer( const idVec3 &origin, int toAreaNum ) const; - void RandomPullPlayer( const idVec3 &origin ) const; - void ShowPushIntoArea( const idVec3 &origin ) const; -}; - -#endif /* !__AAS_LOCAL_H__ */ diff --git a/d3xp/ai/AAS_pathing.cpp b/d3xp/ai/AAS_pathing.cpp deleted file mode 100644 index 916b5b6f..00000000 --- a/d3xp/ai/AAS_pathing.cpp +++ /dev/null @@ -1,715 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "framework/Common.h" - -#include "ai/AAS_local.h" - -#define SUBSAMPLE_WALK_PATH 1 -#define SUBSAMPLE_FLY_PATH 0 - -const int maxWalkPathIterations = 10; -const float maxWalkPathDistance = 500.0f; -const float walkPathSampleDistance = 8.0f; - -const int maxFlyPathIterations = 10; -const float maxFlyPathDistance = 500.0f; -const float flyPathSampleDistance = 8.0f; - - -/* -============ -idAASLocal::EdgeSplitPoint - - calculates split point of the edge with the plane - returns true if the split point is between the edge vertices -============ -*/ -bool idAASLocal::EdgeSplitPoint( idVec3 &split, int edgeNum, const idPlane &plane ) const { - const aasEdge_t *edge; - idVec3 v1, v2; - float d1, d2; - - edge = &file->GetEdge( edgeNum ); - v1 = file->GetVertex( edge->vertexNum[0] ); - v2 = file->GetVertex( edge->vertexNum[1] ); - d1 = v1 * plane.Normal() - plane.Dist(); - d2 = v2 * plane.Normal() - plane.Dist(); - - //if ( (d1 < CM_CLIP_EPSILON && d2 < CM_CLIP_EPSILON) || (d1 > -CM_CLIP_EPSILON && d2 > -CM_CLIP_EPSILON) ) { - if ( FLOATSIGNBITSET( d1 ) == FLOATSIGNBITSET( d2 ) ) { - return false; - } - split = v1 + (d1 / (d1 - d2)) * (v2 - v1); - return true; -} - -/* -============ -idAASLocal::FloorEdgeSplitPoint - - calculates either the closest or furthest point on the floor of the area which also lies on the pathPlane - the point has to be on the front side of the frontPlane to be valid -============ -*/ -bool idAASLocal::FloorEdgeSplitPoint( idVec3 &bestSplit, int areaNum, const idPlane &pathPlane, const idPlane &frontPlane, bool closest ) const { - int i, j, faceNum, edgeNum; - const aasArea_t *area; - const aasFace_t *face; - idVec3 split; - float dist, bestDist; - - if ( closest ) { - bestDist = maxWalkPathDistance; - } else { - bestDist = -0.1f; - } - - area = &file->GetArea( areaNum ); - - for ( i = 0; i < area->numFaces; i++ ) { - faceNum = file->GetFaceIndex( area->firstFace + i ); - face = &file->GetFace( abs(faceNum) ); - - if ( !(face->flags & FACE_FLOOR ) ) { - continue; - } - - for ( j = 0; j < face->numEdges; j++ ) { - edgeNum = file->GetEdgeIndex( face->firstEdge + j ); - - if ( !EdgeSplitPoint( split, abs( edgeNum ), pathPlane ) ) { - continue; - } - dist = frontPlane.Distance( split ); - if ( closest ) { - if ( dist >= -0.1f && dist < bestDist ) { - bestDist = dist; - bestSplit = split; - } - } else { - if ( dist > bestDist ) { - bestDist = dist; - bestSplit = split; - } - } - } - } - - if ( closest ) { - return ( bestDist < maxWalkPathDistance ); - } else { - return ( bestDist > -0.1f ); - } -} - -/* -============ -idAASLocal::WalkPathValid - - returns true if one can walk in a straight line between origin and goalOrigin -============ -*/ -bool idAASLocal::WalkPathValid( int areaNum, const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin, int travelFlags, idVec3 &endPos, int &endAreaNum ) const { - int curAreaNum, lastAreas[4], lastAreaIndex; - idPlane pathPlane, frontPlane, farPlane; - idReachability *reach; - const aasArea_t *area; - idVec3 p, dir; - - if ( file == NULL ) { - endPos = goalOrigin; - endAreaNum = 0; - return true; - } - - lastAreas[0] = lastAreas[1] = lastAreas[2] = lastAreas[3] = areaNum; - lastAreaIndex = 0; - - pathPlane.SetNormal( (goalOrigin - origin).Cross( file->GetSettings().gravityDir ) ); - pathPlane.Normalize(); - pathPlane.FitThroughPoint( origin ); - - frontPlane.SetNormal( goalOrigin - origin ); - frontPlane.Normalize(); - frontPlane.FitThroughPoint( origin ); - - farPlane.SetNormal( frontPlane.Normal() ); - farPlane.FitThroughPoint( goalOrigin ); - - curAreaNum = areaNum; - - while ( 1 ) { - - // find the furthest floor face split point on the path - if ( !FloorEdgeSplitPoint( endPos, curAreaNum, pathPlane, frontPlane, false ) ) { - endPos = origin; - } - - // if we found a point near or further than the goal we're done - if ( farPlane.Distance( endPos ) > -0.5f ) { - break; - } - - // if we reached the goal area we're done - if ( curAreaNum == goalAreaNum ) { - break; - } - - frontPlane.SetDist( frontPlane.Normal() * endPos ); - - area = &file->GetArea( curAreaNum ); - - for ( reach = area->reach; reach; reach = reach->next ) { - if ( reach->travelType != TFL_WALK ) { - continue; - } - - // if the reachability goes back to a previous area - if ( reach->toAreaNum == lastAreas[0] || reach->toAreaNum == lastAreas[1] || - reach->toAreaNum == lastAreas[2] || reach->toAreaNum == lastAreas[3] ) { - continue; - } - - // if undesired travel flags are required to travel through the area - if ( file->GetArea( reach->toAreaNum ).travelFlags & ~travelFlags ) { - continue; - } - - // don't optimize through an area near a ledge - if ( file->GetArea( reach->toAreaNum ).flags & AREA_LEDGE ) { - continue; - } - - // find the closest floor face split point on the path - if ( !FloorEdgeSplitPoint( p, reach->toAreaNum, pathPlane, frontPlane, true ) ) { - continue; - } - - // direction parallel to gravity - dir = ( file->GetSettings().gravityDir * endPos * file->GetSettings().gravityDir ) - - ( file->GetSettings().gravityDir * p * file->GetSettings().gravityDir ); - if ( dir.LengthSqr() > Square( file->GetSettings().maxStepHeight ) ) { - continue; - } - - // direction orthogonal to gravity - dir = endPos - p - dir; - if ( dir.LengthSqr() > Square( 0.2f ) ) { - continue; - } - - break; - } - - if ( !reach ) { - return false; - } - - lastAreas[lastAreaIndex] = curAreaNum; - lastAreaIndex = ( lastAreaIndex + 1 ) & 3; - - curAreaNum = reach->toAreaNum; - } - - endAreaNum = curAreaNum; - - return true; -} - -/* -============ -idAASLocal::SubSampleWalkPath -============ -*/ -idVec3 idAASLocal::SubSampleWalkPath( int areaNum, const idVec3 &origin, const idVec3 &start, const idVec3 &end, int travelFlags, int &endAreaNum ) const { - int i, numSamples, curAreaNum; - idVec3 dir, point, nextPoint, endPos; - - dir = end - start; - numSamples = (int) (dir.Length() / walkPathSampleDistance) + 1; - - point = start; - for ( i = 1; i < numSamples; i++ ) { - nextPoint = start + dir * ((float) i / numSamples); - if ( (point - nextPoint).LengthSqr() > Square( maxWalkPathDistance ) ) { - return point; - } - if ( !idAASLocal::WalkPathValid( areaNum, origin, 0, nextPoint, travelFlags, endPos, curAreaNum ) ) { - return point; - } - point = nextPoint; - endAreaNum = curAreaNum; - } - return point; -} - -/* -============ -idAASLocal::WalkPathToGoal - - FIXME: don't stop optimizing on first failure ? -============ -*/ -bool idAASLocal::WalkPathToGoal( aasPath_t &path, int areaNum, const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin, int travelFlags ) const { - int i, travelTime, curAreaNum, lastAreas[4], lastAreaIndex, endAreaNum; - idReachability *reach; - idVec3 endPos; - - path.type = PATHTYPE_WALK; - path.moveGoal = origin; - path.moveAreaNum = areaNum; - path.secondaryGoal = origin; - path.reachability = NULL; - - if ( file == NULL || areaNum == goalAreaNum ) { - path.moveGoal = goalOrigin; - return true; - } - - lastAreas[0] = lastAreas[1] = lastAreas[2] = lastAreas[3] = areaNum; - lastAreaIndex = 0; - - curAreaNum = areaNum; - - for ( i = 0; i < maxWalkPathIterations; i++ ) { - - if ( !idAASLocal::RouteToGoalArea( curAreaNum, path.moveGoal, goalAreaNum, travelFlags, travelTime, &reach ) ) { - break; - } - - if ( !reach ) { - return false; - } - - // no need to check through the first area - if ( areaNum != curAreaNum ) { - // only optimize a limited distance ahead - if ( (reach->start - origin).LengthSqr() > Square( maxWalkPathDistance ) ) { -#if SUBSAMPLE_WALK_PATH - path.moveGoal = SubSampleWalkPath( areaNum, origin, path.moveGoal, reach->start, travelFlags, path.moveAreaNum ); -#endif - return true; - } - - if ( !idAASLocal::WalkPathValid( areaNum, origin, 0, reach->start, travelFlags, endPos, endAreaNum ) ) { -#if SUBSAMPLE_WALK_PATH - path.moveGoal = SubSampleWalkPath( areaNum, origin, path.moveGoal, reach->start, travelFlags, path.moveAreaNum ); -#endif - return true; - } - } - - path.moveGoal = reach->start; - path.moveAreaNum = curAreaNum; - - if ( reach->travelType != TFL_WALK ) { - break; - } - - if ( !idAASLocal::WalkPathValid( areaNum, origin, 0, reach->end, travelFlags, endPos, endAreaNum ) ) { - return true; - } - - path.moveGoal = reach->end; - path.moveAreaNum = reach->toAreaNum; - - if ( reach->toAreaNum == goalAreaNum ) { - if ( !idAASLocal::WalkPathValid( areaNum, origin, 0, goalOrigin, travelFlags, endPos, endAreaNum ) ) { -#if SUBSAMPLE_WALK_PATH - path.moveGoal = SubSampleWalkPath( areaNum, origin, path.moveGoal, goalOrigin, travelFlags, path.moveAreaNum ); -#endif - return true; - } - path.moveGoal = goalOrigin; - path.moveAreaNum = goalAreaNum; - return true; - } - - lastAreas[lastAreaIndex] = curAreaNum; - lastAreaIndex = ( lastAreaIndex + 1 ) & 3; - - curAreaNum = reach->toAreaNum; - - if ( curAreaNum == lastAreas[0] || curAreaNum == lastAreas[1] || - curAreaNum == lastAreas[2] || curAreaNum == lastAreas[3] ) { - common->Warning( "idAASLocal::WalkPathToGoal: local routing minimum going from area %d to area %d", areaNum, goalAreaNum ); - break; - } - } - - if ( !reach ) { - return false; - } - - switch( reach->travelType ) { - case TFL_WALKOFFLEDGE: - path.type = PATHTYPE_WALKOFFLEDGE; - path.secondaryGoal = reach->end; - path.reachability = reach; - break; - case TFL_BARRIERJUMP: - path.type |= PATHTYPE_BARRIERJUMP; - path.secondaryGoal = reach->end; - path.reachability = reach; - break; - case TFL_JUMP: - path.type |= PATHTYPE_JUMP; - path.secondaryGoal = reach->end; - path.reachability = reach; - break; - default: - break; - } - - return true; -} - -/* -============ -idAASLocal::FlyPathValid - - returns true if one can fly in a straight line between origin and goalOrigin -============ -*/ -bool idAASLocal::FlyPathValid( int areaNum, const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin, int travelFlags, idVec3 &endPos, int &endAreaNum ) const { - aasTrace_t trace; - - if ( file == NULL ) { - endPos = goalOrigin; - endAreaNum = 0; - return true; - } - - file->Trace( trace, origin, goalOrigin ); - - endPos = trace.endpos; - endAreaNum = trace.lastAreaNum; - - if ( trace.fraction >= 1.0f ) { - return true; - } - - return false; -} - -/* -============ -idAASLocal::SubSampleFlyPath -============ -*/ -idVec3 idAASLocal::SubSampleFlyPath( int areaNum, const idVec3 &origin, const idVec3 &start, const idVec3 &end, int travelFlags, int &endAreaNum ) const { - int i, numSamples, curAreaNum; - idVec3 dir, point, nextPoint, endPos; - - dir = end - start; - numSamples = (int) (dir.Length() / flyPathSampleDistance) + 1; - - point = start; - for ( i = 1; i < numSamples; i++ ) { - nextPoint = start + dir * ((float) i / numSamples); - if ( (point - nextPoint).LengthSqr() > Square( maxFlyPathDistance ) ) { - return point; - } - if ( !idAASLocal::FlyPathValid( areaNum, origin, 0, nextPoint, travelFlags, endPos, curAreaNum ) ) { - return point; - } - point = nextPoint; - endAreaNum = curAreaNum; - } - return point; -} - -/* -============ -idAASLocal::FlyPathToGoal - - FIXME: don't stop optimizing on first failure ? -============ -*/ -bool idAASLocal::FlyPathToGoal( aasPath_t &path, int areaNum, const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin, int travelFlags ) const { - int i, travelTime, curAreaNum, lastAreas[4], lastAreaIndex, endAreaNum; - idReachability *reach; - idVec3 endPos; - - path.type = PATHTYPE_WALK; - path.moveGoal = origin; - path.moveAreaNum = areaNum; - path.secondaryGoal = origin; - path.reachability = NULL; - - if ( file == NULL || areaNum == goalAreaNum ) { - path.moveGoal = goalOrigin; - return true; - } - - lastAreas[0] = lastAreas[1] = lastAreas[2] = lastAreas[3] = areaNum; - lastAreaIndex = 0; - - curAreaNum = areaNum; - - for ( i = 0; i < maxFlyPathIterations; i++ ) { - - if ( !idAASLocal::RouteToGoalArea( curAreaNum, path.moveGoal, goalAreaNum, travelFlags, travelTime, &reach ) ) { - break; - } - - if ( !reach ) { - return false; - } - - // no need to check through the first area - if ( areaNum != curAreaNum ) { - if ( (reach->start - origin).LengthSqr() > Square( maxFlyPathDistance ) ) { -#if SUBSAMPLE_FLY_PATH - path.moveGoal = SubSampleFlyPath( areaNum, origin, path.moveGoal, reach->start, travelFlags, path.moveAreaNum ); -#endif - return true; - } - - if ( !idAASLocal::FlyPathValid( areaNum, origin, 0, reach->start, travelFlags, endPos, endAreaNum ) ) { -#if SUBSAMPLE_FLY_PATH - path.moveGoal = SubSampleFlyPath( areaNum, origin, path.moveGoal, reach->start, travelFlags, path.moveAreaNum ); -#endif - return true; - } - } - - path.moveGoal = reach->start; - path.moveAreaNum = curAreaNum; - - if ( !idAASLocal::FlyPathValid( areaNum, origin, 0, reach->end, travelFlags, endPos, endAreaNum ) ) { - return true; - } - - path.moveGoal = reach->end; - path.moveAreaNum = reach->toAreaNum; - - if ( reach->toAreaNum == goalAreaNum ) { - if ( !idAASLocal::FlyPathValid( areaNum, origin, 0, goalOrigin, travelFlags, endPos, endAreaNum ) ) { -#if SUBSAMPLE_FLY_PATH - path.moveGoal = SubSampleFlyPath( areaNum, origin, path.moveGoal, goalOrigin, travelFlags, path.moveAreaNum ); -#endif - return true; - } - path.moveGoal = goalOrigin; - path.moveAreaNum = goalAreaNum; - return true; - } - - lastAreas[lastAreaIndex] = curAreaNum; - lastAreaIndex = ( lastAreaIndex + 1 ) & 3; - - curAreaNum = reach->toAreaNum; - - if ( curAreaNum == lastAreas[0] || curAreaNum == lastAreas[1] || - curAreaNum == lastAreas[2] || curAreaNum == lastAreas[3] ) { - common->Warning( "idAASLocal::FlyPathToGoal: local routing minimum going from area %d to area %d", areaNum, goalAreaNum ); - break; - } - } - - if ( !reach ) { - return false; - } - - return true; -} - -typedef struct wallEdge_s { - int edgeNum; - int verts[2]; - struct wallEdge_s * next; -} wallEdge_t; - -/* -============ -idAASLocal::SortWallEdges -============ -*/ -void idAASLocal::SortWallEdges( int *edges, int numEdges ) const { - int i, j, k, numSequences; - wallEdge_t **sequenceFirst, **sequenceLast, *wallEdges, *wallEdge; - - wallEdges = (wallEdge_t *) _alloca16( numEdges * sizeof( wallEdge_t ) ); - sequenceFirst = (wallEdge_t **)_alloca16( numEdges * sizeof( wallEdge_t * ) ); - sequenceLast = (wallEdge_t **)_alloca16( numEdges * sizeof( wallEdge_t * ) ); - - for ( i = 0; i < numEdges; i++ ) { - wallEdges[i].edgeNum = edges[i]; - GetEdgeVertexNumbers( edges[i], wallEdges[i].verts ); - wallEdges[i].next = NULL; - sequenceFirst[i] = &wallEdges[i]; - sequenceLast[i] = &wallEdges[i]; - } - numSequences = numEdges; - - for ( i = 0; i < numSequences; i++ ) { - for ( j = i+1; j < numSequences; j++ ) { - if ( sequenceFirst[i]->verts[0] == sequenceLast[j]->verts[1] ) { - sequenceLast[j]->next = sequenceFirst[i]; - sequenceFirst[i] = sequenceFirst[j]; - break; - } - if ( sequenceLast[i]->verts[1] == sequenceFirst[j]->verts[0] ) { - sequenceLast[i]->next = sequenceFirst[j]; - break; - } - } - if ( j < numSequences ) { - numSequences--; - for ( k = j; k < numSequences; k++ ) { - sequenceFirst[k] = sequenceFirst[k+1]; - sequenceLast[k] = sequenceLast[k+1]; - } - i = -1; - } - } - - k = 0; - for ( i = 0; i < numSequences; i++ ) { - for ( wallEdge = sequenceFirst[i]; wallEdge; wallEdge = wallEdge->next ) { - edges[k++] = wallEdge->edgeNum; - } - } -} - -/* -============ -idAASLocal::GetWallEdges -============ -*/ -int idAASLocal::GetWallEdges( int areaNum, const idBounds &bounds, int travelFlags, int *edges, int maxEdges ) const { - int i, j, k, l, face1Num, face2Num, edge1Num, edge2Num, numEdges, absEdge1Num; - int *areaQueue, curArea, queueStart, queueEnd; - byte *areasVisited; - const aasArea_t *area; - const aasFace_t *face1, *face2; - idReachability *reach; - - if ( !file ) { - return 0; - } - - numEdges = 0; - - areasVisited = (byte *) _alloca16( file->GetNumAreas() ); - memset( areasVisited, 0, file->GetNumAreas() * sizeof( byte ) ); - areaQueue = (int *) _alloca16( file->GetNumAreas() * sizeof( int ) ); - - queueStart = -1; - queueEnd = 0; - areaQueue[0] = areaNum; - areasVisited[areaNum] = true; - - for ( curArea = areaNum; queueStart < queueEnd; curArea = areaQueue[++queueStart] ) { - - area = &file->GetArea( curArea ); - - for ( i = 0; i < area->numFaces; i++ ) { - face1Num = file->GetFaceIndex( area->firstFace + i ); - face1 = &file->GetFace( abs(face1Num) ); - - if ( !(face1->flags & FACE_FLOOR ) ) { - continue; - } - - for ( j = 0; j < face1->numEdges; j++ ) { - edge1Num = file->GetEdgeIndex( face1->firstEdge + j ); - absEdge1Num = abs( edge1Num ); - - // test if the edge is shared by another floor face of this area - for ( k = 0; k < area->numFaces; k++ ) { - if ( k == i ) { - continue; - } - face2Num = file->GetFaceIndex( area->firstFace + k ); - face2 = &file->GetFace( abs(face2Num) ); - - if ( !(face2->flags & FACE_FLOOR ) ) { - continue; - } - - for ( l = 0; l < face2->numEdges; l++ ) { - edge2Num = abs( file->GetEdgeIndex( face2->firstEdge + l ) ); - if ( edge2Num == absEdge1Num ) { - break; - } - } - if ( l < face2->numEdges ) { - break; - } - } - if ( k < area->numFaces ) { - continue; - } - - // test if the edge is used by a reachability - for ( reach = area->reach; reach; reach = reach->next ) { - if ( reach->travelType & travelFlags ) { - if ( reach->edgeNum == absEdge1Num ) { - break; - } - } - } - if ( reach ) { - continue; - } - - // test if the edge is already in the list - for ( k = 0; k < numEdges; k++ ) { - if ( edge1Num == edges[k] ) { - break; - } - } - if ( k < numEdges ) { - continue; - } - - // add the edge to the list - edges[numEdges++] = edge1Num; - if ( numEdges >= maxEdges ) { - return numEdges; - } - } - } - - // add new areas to the queue - for ( reach = area->reach; reach; reach = reach->next ) { - if ( reach->travelType & travelFlags ) { - // if the area the reachability leads to hasn't been visited yet and the area bounds touch the search bounds - if ( !areasVisited[reach->toAreaNum] && bounds.IntersectsBounds( file->GetArea( reach->toAreaNum ).bounds ) ) { - areaQueue[queueEnd++] = reach->toAreaNum; - areasVisited[reach->toAreaNum] = true; - } - } - } - } - return numEdges; -} diff --git a/d3xp/ai/AAS_routing.cpp b/d3xp/ai/AAS_routing.cpp deleted file mode 100644 index e82ca4eb..00000000 --- a/d3xp/ai/AAS_routing.cpp +++ /dev/null @@ -1,1348 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "Game_local.h" - -#include "ai/AAS_local.h" - -#define CACHETYPE_AREA 1 -#define CACHETYPE_PORTAL 2 - -#define MAX_ROUTING_CACHE_MEMORY (2*1024*1024) - -#define LEDGE_TRAVELTIME_PANALTY 250 - -/* -============ -idRoutingCache::idRoutingCache -============ -*/ -idRoutingCache::idRoutingCache( int size ) { - areaNum = 0; - cluster = 0; - next = prev = NULL; - time_next = time_prev = NULL; - travelFlags = 0; - startTravelTime = 0; - type = 0; - this->size = size; - reachabilities = new byte[size]; - memset( reachabilities, 0, size * sizeof( reachabilities[0] ) ); - travelTimes = new unsigned short[size]; - memset( travelTimes, 0, size * sizeof( travelTimes[0] ) ); -} - -/* -============ -idRoutingCache::~idRoutingCache -============ -*/ -idRoutingCache::~idRoutingCache( void ) { - delete [] reachabilities; - delete [] travelTimes; -} - -/* -============ -idRoutingCache::Size -============ -*/ -int idRoutingCache::Size( void ) const { - return sizeof( idRoutingCache ) + size * sizeof( reachabilities[0] ) + size * sizeof( travelTimes[0] ); -} - -/* -============ -idAASLocal::AreaTravelTime -============ -*/ -unsigned short idAASLocal::AreaTravelTime( int areaNum, const idVec3 &start, const idVec3 &end ) const { - float dist; - - dist = ( end - start ).Length(); - - if ( file->GetArea( areaNum ).travelFlags & TFL_CROUCH ) { - dist *= 100.0f / 100.0f; - } else if ( file->GetArea( areaNum ).travelFlags & TFL_WATER ) { - dist *= 100.0f / 150.0f; - } else { - dist *= 100.0f / 300.0f; - } - if ( dist < 1.0f ) { - return 1; - } - return (unsigned short) idMath::FtoiFast( dist ); -} - -/* -============ -idAASLocal::CalculateAreaTravelTimes -============ -*/ -void idAASLocal::CalculateAreaTravelTimes(void) { - int n, i, j, numReach, numRevReach, t, maxt; - byte *bytePtr; - idReachability *reach, *rev_reach; - - // get total memory for all area travel times - numAreaTravelTimes = 0; - for ( n = 0; n < file->GetNumAreas(); n++ ) { - - if ( !(file->GetArea( n ).flags & (AREA_REACHABLE_WALK|AREA_REACHABLE_FLY)) ) { - continue; - } - - numReach = 0; - for ( reach = file->GetArea( n ).reach; reach; reach = reach->next ) { - numReach++; - } - - numRevReach = 0; - for ( rev_reach = file->GetArea( n ).rev_reach; rev_reach; rev_reach = rev_reach->rev_next ) { - numRevReach++; - } - numAreaTravelTimes += numReach * numRevReach; - } - - areaTravelTimes = (unsigned short *) Mem_Alloc( numAreaTravelTimes * sizeof( unsigned short ) ); - bytePtr = (byte *) areaTravelTimes; - - for ( n = 0; n < file->GetNumAreas(); n++ ) { - - if ( !(file->GetArea( n ).flags & (AREA_REACHABLE_WALK|AREA_REACHABLE_FLY)) ) { - continue; - } - - // for each reachability that starts in this area calculate the travel time - // towards all the reachabilities that lead towards this area - for ( maxt = i = 0, reach = file->GetArea( n ).reach; reach; reach = reach->next, i++ ) { - assert( i < MAX_REACH_PER_AREA ); - if ( i >= MAX_REACH_PER_AREA ) { - gameLocal.Error( "i >= MAX_REACH_PER_AREA" ); - } - reach->number = i; - reach->disableCount = 0; - reach->areaTravelTimes = (unsigned short *) bytePtr; - for ( j = 0, rev_reach = file->GetArea( n ).rev_reach; rev_reach; rev_reach = rev_reach->rev_next, j++ ) { - t = AreaTravelTime( n, reach->start, rev_reach->end ); - reach->areaTravelTimes[j] = t; - if ( t > maxt ) { - maxt = t; - } - } - bytePtr += j * sizeof( unsigned short ); - } - - // if this area is a portal - if ( file->GetArea( n ).cluster < 0 ) { - // set the maximum travel time through this portal - file->SetPortalMaxTravelTime( -file->GetArea( n ).cluster, maxt ); - } - } - - assert( ( ( ptrdiff_t ) bytePtr - ( ptrdiff_t ) areaTravelTimes ) <= numAreaTravelTimes * sizeof( unsigned short ) ); -} - -/* -============ -idAASLocal::DeleteAreaTravelTimes -============ -*/ -void idAASLocal::DeleteAreaTravelTimes( void ) { - Mem_Free( areaTravelTimes ); - areaTravelTimes = NULL; - numAreaTravelTimes = 0; -} - -/* -============ -idAASLocal::SetupRoutingCache -============ -*/ -void idAASLocal::SetupRoutingCache( void ) { - int i; - byte *bytePtr; - - areaCacheIndexSize = 0; - for ( i = 0; i < file->GetNumClusters(); i++ ) { - areaCacheIndexSize += file->GetCluster( i ).numReachableAreas; - } - areaCacheIndex = (idRoutingCache ***) Mem_ClearedAlloc( file->GetNumClusters() * sizeof( idRoutingCache ** ) + - areaCacheIndexSize * sizeof( idRoutingCache *) ); - bytePtr = ((byte *)areaCacheIndex) + file->GetNumClusters() * sizeof( idRoutingCache ** ); - for ( i = 0; i < file->GetNumClusters(); i++ ) { - areaCacheIndex[i] = ( idRoutingCache ** ) bytePtr; - bytePtr += file->GetCluster( i ).numReachableAreas * sizeof( idRoutingCache * ); - } - - portalCacheIndexSize = file->GetNumAreas(); - portalCacheIndex = (idRoutingCache **) Mem_ClearedAlloc( portalCacheIndexSize * sizeof( idRoutingCache * ) ); - - areaUpdate = (idRoutingUpdate *) Mem_ClearedAlloc( file->GetNumAreas() * sizeof( idRoutingUpdate ) ); - portalUpdate = (idRoutingUpdate *) Mem_ClearedAlloc( (file->GetNumPortals()+1) * sizeof( idRoutingUpdate ) ); - - goalAreaTravelTimes = (unsigned short *) Mem_ClearedAlloc( file->GetNumAreas() * sizeof( unsigned short ) ); - - cacheListStart = cacheListEnd = NULL; - totalCacheMemory = 0; -} - -/* -============ -idAASLocal::DeleteClusterCache -============ -*/ -void idAASLocal::DeleteClusterCache( int clusterNum ) { - int i; - idRoutingCache *cache; - - for ( i = 0; i < file->GetCluster( clusterNum ).numReachableAreas; i++ ) { - for ( cache = areaCacheIndex[clusterNum][i]; cache; cache = areaCacheIndex[clusterNum][i] ) { - areaCacheIndex[clusterNum][i] = cache->next; - UnlinkCache( cache ); - delete cache; - } - } -} - -/* -============ -idAASLocal::DeletePortalCache -============ -*/ -void idAASLocal::DeletePortalCache( void ) { - int i; - idRoutingCache *cache; - - for ( i = 0; i < file->GetNumAreas(); i++ ) { - for ( cache = portalCacheIndex[i]; cache; cache = portalCacheIndex[i] ) { - portalCacheIndex[i] = cache->next; - UnlinkCache( cache ); - delete cache; - } - } -} - -/* -============ -idAASLocal::ShutdownRoutingCache -============ -*/ -void idAASLocal::ShutdownRoutingCache( void ) { - int i; - - for ( i = 0; i < file->GetNumClusters(); i++ ) { - DeleteClusterCache( i ); - } - - DeletePortalCache(); - - Mem_Free( areaCacheIndex ); - areaCacheIndex = NULL; - areaCacheIndexSize = 0; - Mem_Free( portalCacheIndex ); - portalCacheIndex = NULL; - portalCacheIndexSize = 0; - Mem_Free( areaUpdate ); - areaUpdate = NULL; - Mem_Free( portalUpdate ); - portalUpdate = NULL; - Mem_Free( goalAreaTravelTimes ); - goalAreaTravelTimes = NULL; - - cacheListStart = cacheListEnd = NULL; - totalCacheMemory = 0; -} - -/* -============ -idAASLocal::SetupRouting -============ -*/ -bool idAASLocal::SetupRouting( void ) { - CalculateAreaTravelTimes(); - SetupRoutingCache(); - return true; -} - -/* -============ -idAASLocal::ShutdownRouting -============ -*/ -void idAASLocal::ShutdownRouting( void ) { - DeleteAreaTravelTimes(); - ShutdownRoutingCache(); -} - -/* -============ -idAASLocal::RoutingStats -============ -*/ -void idAASLocal::RoutingStats( void ) const { - idRoutingCache *cache; - int numAreaCache, numPortalCache; - int totalAreaCacheMemory, totalPortalCacheMemory; - - numAreaCache = numPortalCache = 0; - totalAreaCacheMemory = totalPortalCacheMemory = 0; - for ( cache = cacheListStart; cache; cache = cache->time_next ) { - if ( cache->type == CACHETYPE_AREA ) { - numAreaCache++; - totalAreaCacheMemory += sizeof( idRoutingCache ) + cache->size * (sizeof( unsigned short ) + sizeof( byte )); - } else { - numPortalCache++; - totalPortalCacheMemory += sizeof( idRoutingCache ) + cache->size * (sizeof( unsigned short ) + sizeof( byte )); - } - } - - gameLocal.Printf( "%6d area cache (%d KB)\n", numAreaCache, totalAreaCacheMemory >> 10 ); - gameLocal.Printf( "%6d portal cache (%d KB)\n", numPortalCache, totalPortalCacheMemory >> 10 ); - gameLocal.Printf( "%6d total cache (%d KB)\n", numAreaCache + numPortalCache, totalCacheMemory >> 10 ); - gameLocal.Printf( "%6d area travel times (%zd KB)\n", numAreaTravelTimes, ( numAreaTravelTimes * sizeof( unsigned short ) ) >> 10 ); - gameLocal.Printf( "%6d area cache entries (%zd KB)\n", areaCacheIndexSize, ( areaCacheIndexSize * sizeof( idRoutingCache * ) ) >> 10 ); - gameLocal.Printf( "%6d portal cache entries (%zd KB)\n", portalCacheIndexSize, ( portalCacheIndexSize * sizeof( idRoutingCache * ) ) >> 10 ); -} - -/* -============ -idAASLocal::RemoveRoutingCacheUsingArea -============ -*/ -void idAASLocal::RemoveRoutingCacheUsingArea( int areaNum ) { - int clusterNum; - - clusterNum = file->GetArea( areaNum ).cluster; - if ( clusterNum > 0 ) { - // remove all the cache in the cluster the area is in - DeleteClusterCache( clusterNum ); - } - else { - // if this is a portal remove all cache in both the front and back cluster - DeleteClusterCache( file->GetPortal( -clusterNum ).clusters[0] ); - DeleteClusterCache( file->GetPortal( -clusterNum ).clusters[1] ); - } - DeletePortalCache(); -} - -/* -============ -idAASLocal::DisableArea -============ -*/ -void idAASLocal::DisableArea( int areaNum ) { - assert( areaNum > 0 && areaNum < file->GetNumAreas() ); - - if ( file->GetArea( areaNum ).travelFlags & TFL_INVALID ) { - return; - } - - file->SetAreaTravelFlag( areaNum, TFL_INVALID ); - - RemoveRoutingCacheUsingArea( areaNum ); -} - -/* -============ -idAASLocal::EnableArea -============ -*/ -void idAASLocal::EnableArea( int areaNum ) { - assert( areaNum > 0 && areaNum < file->GetNumAreas() ); - - if ( !( file->GetArea( areaNum ).travelFlags & TFL_INVALID ) ) { - return; - } - - file->RemoveAreaTravelFlag( areaNum, TFL_INVALID ); - - RemoveRoutingCacheUsingArea( areaNum ); -} - -/* -============ -idAASLocal::SetAreaState_r -============ -*/ -bool idAASLocal::SetAreaState_r( int nodeNum, const idBounds &bounds, const int areaContents, bool disabled ) { - int res; - const aasNode_t *node; - bool foundClusterPortal = false; - - while( nodeNum != 0 ) { - if ( nodeNum < 0 ) { - // if this area is a cluster portal - if ( file->GetArea( -nodeNum ).contents & areaContents ) { - if ( disabled ) { - DisableArea( -nodeNum ); - } else { - EnableArea( -nodeNum ); - } - foundClusterPortal |= true; - } - break; - } - node = &file->GetNode( nodeNum ); - res = bounds.PlaneSide( file->GetPlane( node->planeNum ) ); - if ( res == PLANESIDE_BACK ) { - nodeNum = node->children[1]; - } - else if ( res == PLANESIDE_FRONT ) { - nodeNum = node->children[0]; - } - else { - foundClusterPortal |= SetAreaState_r( node->children[1], bounds, areaContents, disabled ); - nodeNum = node->children[0]; - } - } - - return foundClusterPortal; -} - -/* -============ -idAASLocal::SetAreaState -============ -*/ -bool idAASLocal::SetAreaState( const idBounds &bounds, const int areaContents, bool disabled ) { - idBounds expBounds; - - if ( !file ) { - return false; - } - - expBounds[0] = bounds[0] - file->GetSettings().boundingBoxes[0][1]; - expBounds[1] = bounds[1] - file->GetSettings().boundingBoxes[0][0]; - - // find all areas within or touching the bounds with the given contents and disable/enable them for routing - return SetAreaState_r( 1, expBounds, areaContents, disabled ); -} - -/* -============ -idAASLocal::GetBoundsAreas_r -============ -*/ -void idAASLocal::GetBoundsAreas_r( int nodeNum, const idBounds &bounds, idList &areas ) const { - int res; - const aasNode_t *node; - - while( nodeNum != 0 ) { - if ( nodeNum < 0 ) { - areas.Append( -nodeNum ); - break; - } - node = &file->GetNode( nodeNum ); - res = bounds.PlaneSide( file->GetPlane( node->planeNum ) ); - if ( res == PLANESIDE_BACK ) { - nodeNum = node->children[1]; - } - else if ( res == PLANESIDE_FRONT ) { - nodeNum = node->children[0]; - } - else { - GetBoundsAreas_r( node->children[1], bounds, areas ); - nodeNum = node->children[0]; - } - } -} - -/* -============ -idAASLocal::SetObstacleState -============ -*/ -void idAASLocal::SetObstacleState( const idRoutingObstacle *obstacle, bool enable ) { - int i; - const aasArea_t *area; - idReachability *reach, *rev_reach; - bool inside; - - for ( i = 0; i < obstacle->areas.Num(); i++ ) { - - RemoveRoutingCacheUsingArea( obstacle->areas[i] ); - - area = &file->GetArea( obstacle->areas[i] ); - - for ( rev_reach = area->rev_reach; rev_reach; rev_reach = rev_reach->rev_next ) { - - if ( rev_reach->travelType & TFL_INVALID ) { - continue; - } - - inside = false; - - if ( obstacle->bounds.ContainsPoint( rev_reach->end ) ) { - inside = true; - } - else { - for ( reach = area->reach; reach; reach = reach->next ) { - if ( obstacle->bounds.LineIntersection( rev_reach->end, reach->start ) ) { - inside = true; - break; - } - } - } - - if ( inside ) { - if ( enable ) { - rev_reach->disableCount--; - if ( rev_reach->disableCount <= 0 ) { - rev_reach->travelType &= ~TFL_INVALID; - rev_reach->disableCount = 0; - } - } - else { - rev_reach->travelType |= TFL_INVALID; - rev_reach->disableCount++; - } - } - } - } -} - -/* -============ -idAASLocal::AddObstacle -============ -*/ -aasHandle_t idAASLocal::AddObstacle( const idBounds &bounds ) { - idRoutingObstacle *obstacle; - - if ( !file ) { - return -1; - } - - obstacle = new idRoutingObstacle; - obstacle->bounds[0] = bounds[0] - file->GetSettings().boundingBoxes[0][1]; - obstacle->bounds[1] = bounds[1] - file->GetSettings().boundingBoxes[0][0]; - GetBoundsAreas_r( 1, obstacle->bounds, obstacle->areas ); - SetObstacleState( obstacle, true ); - - obstacleList.Append( obstacle ); - return obstacleList.Num() - 1; -} - -/* -============ -idAASLocal::RemoveObstacle -============ -*/ -void idAASLocal::RemoveObstacle( const aasHandle_t handle ) { - if ( !file ) { - return; - } - if ( ( handle >= 0 ) && ( handle < obstacleList.Num() ) ) { - SetObstacleState( obstacleList[handle], false ); - - delete obstacleList[handle]; - obstacleList.RemoveIndex( handle ); - } -} - -/* -============ -idAASLocal::RemoveAllObstacles -============ -*/ -void idAASLocal::RemoveAllObstacles( void ) { - int i; - - if ( !file ) { - return; - } - - for ( i = 0; i < obstacleList.Num(); i++ ) { - SetObstacleState( obstacleList[i], false ); - delete obstacleList[i]; - } - obstacleList.Clear(); -} - -/* -============ -idAASLocal::LinkCache - - link the cache in the cache list sorted from oldest to newest cache -============ -*/ -void idAASLocal::LinkCache( idRoutingCache *cache ) const { - - // if the cache is already linked - if ( cache->time_next || cache->time_prev || cacheListStart == cache ) { - UnlinkCache( cache ); - } - - totalCacheMemory += cache->Size(); - - // add cache to the end of the list - cache->time_next = NULL; - cache->time_prev = cacheListEnd; - if ( cacheListEnd ) { - cacheListEnd->time_next = cache; - } - cacheListEnd = cache; - if ( !cacheListStart ) { - cacheListStart = cache; - } -} - -/* -============ -idAASLocal::UnlinkCache -============ -*/ -void idAASLocal::UnlinkCache( idRoutingCache *cache ) const { - - totalCacheMemory -= cache->Size(); - - // unlink the cache - if ( cache->time_next ) { - cache->time_next->time_prev = cache->time_prev; - } else { - cacheListEnd = cache->time_prev; - } - if ( cache->time_prev ) { - cache->time_prev->time_next = cache->time_next; - } else { - cacheListStart = cache->time_next; - } - cache->time_next = cache->time_prev = NULL; -} - -/* -============ -idAASLocal::DeleteOldestCache -============ -*/ -void idAASLocal::DeleteOldestCache( void ) const { - idRoutingCache *cache; - - assert( cacheListStart ); - - // unlink the oldest cache - cache = cacheListStart; - UnlinkCache( cache ); - - // unlink the oldest cache from the area or portal cache index - if ( cache->next ) { - cache->next->prev = cache->prev; - } - if ( cache->prev ) { - cache->prev->next = cache->next; - } - else if ( cache->type == CACHETYPE_AREA ) { - areaCacheIndex[cache->cluster][ClusterAreaNum( cache->cluster, cache->areaNum )] = cache->next; - } - else if ( cache->type == CACHETYPE_PORTAL ) { - portalCacheIndex[cache->areaNum] = cache->next; - } - - delete cache; -} - -/* -============ -idAASLocal::GetAreaReachability -============ -*/ -idReachability *idAASLocal::GetAreaReachability( int areaNum, int reachabilityNum ) const { - idReachability *reach; - - for ( reach = file->GetArea( areaNum ).reach; reach; reach = reach->next ) { - if ( --reachabilityNum < 0 ) { - return reach; - } - } - return NULL; -} - -/* -============ -idAASLocal::ClusterAreaNum -============ -*/ -ID_INLINE int idAASLocal::ClusterAreaNum( int clusterNum, int areaNum ) const { - int side, areaCluster; - - areaCluster = file->GetArea( areaNum ).cluster; - if ( areaCluster > 0 ) { - return file->GetArea( areaNum ).clusterAreaNum; - } - else { - side = file->GetPortal( -areaCluster ).clusters[0] != clusterNum; - return file->GetPortal( -areaCluster ).clusterAreaNum[side]; - } -} - -/* -============ -idAASLocal::UpdateAreaRoutingCache -============ -*/ -void idAASLocal::UpdateAreaRoutingCache( idRoutingCache *areaCache ) const { - int i, nextAreaNum, cluster, badTravelFlags, clusterAreaNum, numReachableAreas; - unsigned short t, startAreaTravelTimes[MAX_REACH_PER_AREA]; - idRoutingUpdate *updateListStart, *updateListEnd, *curUpdate, *nextUpdate; - idReachability *reach; - const aasArea_t *nextArea; - - // number of reachability areas within this cluster - numReachableAreas = file->GetCluster( areaCache->cluster ).numReachableAreas; - - // number of the start area within the cluster - clusterAreaNum = ClusterAreaNum( areaCache->cluster, areaCache->areaNum ); - if ( clusterAreaNum >= numReachableAreas ) { - return; - } - - areaCache->travelTimes[clusterAreaNum] = areaCache->startTravelTime; - badTravelFlags = ~areaCache->travelFlags; - memset( startAreaTravelTimes, 0, sizeof( startAreaTravelTimes ) ); - - // initialize first update - curUpdate = &areaUpdate[clusterAreaNum]; - curUpdate->areaNum = areaCache->areaNum; - curUpdate->areaTravelTimes = startAreaTravelTimes; - curUpdate->tmpTravelTime = areaCache->startTravelTime; - curUpdate->next = NULL; - curUpdate->prev = NULL; - updateListStart = curUpdate; - updateListEnd = curUpdate; - - // while there are updates in the list - while( updateListStart ) { - - curUpdate = updateListStart; - if ( curUpdate->next ) { - curUpdate->next->prev = NULL; - } - else { - updateListEnd = NULL; - } - updateListStart = curUpdate->next; - - curUpdate->isInList = false; - - for ( i = 0, reach = file->GetArea( curUpdate->areaNum ).rev_reach; reach; reach = reach->rev_next, i++ ) { - - // if the reachability uses an undesired travel type - if ( reach->travelType & badTravelFlags ) { - continue; - } - - // next area the reversed reachability leads to - nextAreaNum = reach->fromAreaNum; - nextArea = &file->GetArea( nextAreaNum ); - - // if traveling through the next area requires an undesired travel flag - if ( nextArea->travelFlags & badTravelFlags ) { - continue; - } - - // get the cluster number of the area - cluster = nextArea->cluster; - // don't leave the cluster, however do flood into cluster portals - if ( cluster > 0 && cluster != areaCache->cluster ) { - continue; - } - - // get the number of the area in the cluster - clusterAreaNum = ClusterAreaNum( areaCache->cluster, nextAreaNum ); - if ( clusterAreaNum >= numReachableAreas ) { - continue; // should never happen - } - - assert( clusterAreaNum < areaCache->size ); - - // time already travelled plus the traveltime through the current area - // plus the travel time of the reachability towards the next area - t = curUpdate->tmpTravelTime + curUpdate->areaTravelTimes[i] + reach->travelTime; - - if ( !areaCache->travelTimes[clusterAreaNum] || t < areaCache->travelTimes[clusterAreaNum] ) { - - areaCache->travelTimes[clusterAreaNum] = t; - areaCache->reachabilities[clusterAreaNum] = reach->number; // reversed reachability used to get into this area - nextUpdate = &areaUpdate[clusterAreaNum]; - nextUpdate->areaNum = nextAreaNum; - nextUpdate->tmpTravelTime = t; - nextUpdate->areaTravelTimes = reach->areaTravelTimes; - - // if we are not allowed to fly - if ( badTravelFlags & TFL_FLY ) { - // avoid areas near ledges - if ( file->GetArea( nextAreaNum ).flags & AREA_LEDGE ) { - nextUpdate->tmpTravelTime += LEDGE_TRAVELTIME_PANALTY; - } - } - - if ( !nextUpdate->isInList ) { - nextUpdate->next = NULL; - nextUpdate->prev = updateListEnd; - if ( updateListEnd ) { - updateListEnd->next = nextUpdate; - } - else { - updateListStart = nextUpdate; - } - updateListEnd = nextUpdate; - nextUpdate->isInList = true; - } - } - } - } -} - -/* -============ -idAASLocal::GetAreaRoutingCache -============ -*/ -idRoutingCache *idAASLocal::GetAreaRoutingCache( int clusterNum, int areaNum, int travelFlags ) const { - int clusterAreaNum; - idRoutingCache *cache, *clusterCache; - - // number of the area in the cluster - clusterAreaNum = ClusterAreaNum( clusterNum, areaNum ); - // pointer to the cache for the area in the cluster - clusterCache = areaCacheIndex[clusterNum][clusterAreaNum]; - // check if cache without undesired travel flags already exists - for ( cache = clusterCache; cache; cache = cache->next ) { - if ( cache->travelFlags == travelFlags ) { - break; - } - } - // if no cache found - if ( !cache ) { - cache = new idRoutingCache( file->GetCluster( clusterNum ).numReachableAreas ); - cache->type = CACHETYPE_AREA; - cache->cluster = clusterNum; - cache->areaNum = areaNum; - cache->startTravelTime = 1; - cache->travelFlags = travelFlags; - cache->prev = NULL; - cache->next = clusterCache; - if ( clusterCache ) { - clusterCache->prev = cache; - } - areaCacheIndex[clusterNum][clusterAreaNum] = cache; - UpdateAreaRoutingCache( cache ); - } - LinkCache( cache ); - return cache; -} - -/* -============ -idAASLocal::UpdatePortalRoutingCache -============ -*/ -void idAASLocal::UpdatePortalRoutingCache( idRoutingCache *portalCache ) const { - int i, portalNum, clusterAreaNum; - unsigned short t; - const aasPortal_t *portal; - const aasCluster_t *cluster; - idRoutingCache *cache; - idRoutingUpdate *updateListStart, *updateListEnd, *curUpdate, *nextUpdate; - - curUpdate = &portalUpdate[ file->GetNumPortals() ]; - curUpdate->cluster = portalCache->cluster; - curUpdate->areaNum = portalCache->areaNum; - curUpdate->tmpTravelTime = portalCache->startTravelTime; - - //put the area to start with in the current read list - curUpdate->next = NULL; - curUpdate->prev = NULL; - updateListStart = curUpdate; - updateListEnd = curUpdate; - - // while there are updates in the current list - while( updateListStart ) { - - curUpdate = updateListStart; - // remove the current update from the list - if ( curUpdate->next ) { - curUpdate->next->prev = NULL; - } - else { - updateListEnd = NULL; - } - updateListStart = curUpdate->next; - // current update is removed from the list - curUpdate->isInList = false; - - cluster = &file->GetCluster( curUpdate->cluster ); - cache = GetAreaRoutingCache( curUpdate->cluster, curUpdate->areaNum, portalCache->travelFlags ); - - // take all portals of the cluster - for ( i = 0; i < cluster->numPortals; i++ ) { - portalNum = file->GetPortalIndex( cluster->firstPortal + i ); - assert( portalNum < portalCache->size ); - portal = &file->GetPortal( portalNum ); - - clusterAreaNum = ClusterAreaNum( curUpdate->cluster, portal->areaNum ); - if ( clusterAreaNum >= cluster->numReachableAreas ) { - continue; - } - - t = cache->travelTimes[clusterAreaNum]; - if ( t == 0 ) { - continue; - } - t += curUpdate->tmpTravelTime; - - if ( !portalCache->travelTimes[portalNum] || t < portalCache->travelTimes[portalNum] ) { - - portalCache->travelTimes[portalNum] = t; - portalCache->reachabilities[portalNum] = cache->reachabilities[clusterAreaNum]; - nextUpdate = &portalUpdate[portalNum]; - if ( portal->clusters[0] == curUpdate->cluster ) { - nextUpdate->cluster = portal->clusters[1]; - } - else { - nextUpdate->cluster = portal->clusters[0]; - } - nextUpdate->areaNum = portal->areaNum; - // add travel time through the actual portal area for the next update - nextUpdate->tmpTravelTime = t + portal->maxAreaTravelTime; - - if ( !nextUpdate->isInList ) { - - nextUpdate->next = NULL; - nextUpdate->prev = updateListEnd; - if ( updateListEnd ) { - updateListEnd->next = nextUpdate; - } - else { - updateListStart = nextUpdate; - } - updateListEnd = nextUpdate; - nextUpdate->isInList = true; - } - } - } - } -} - -/* -============ -idAASLocal::GetPortalRoutingCache -============ -*/ -idRoutingCache *idAASLocal::GetPortalRoutingCache( int clusterNum, int areaNum, int travelFlags ) const { - idRoutingCache *cache; - - // check if cache without undesired travel flags already exists - for ( cache = portalCacheIndex[areaNum]; cache; cache = cache->next ) { - if ( cache->travelFlags == travelFlags ) { - break; - } - } - // if no cache found - if ( !cache ) { - cache = new idRoutingCache( file->GetNumPortals() ); - cache->type = CACHETYPE_PORTAL; - cache->cluster = clusterNum; - cache->areaNum = areaNum; - cache->startTravelTime = 1; - cache->travelFlags = travelFlags; - cache->prev = NULL; - cache->next = portalCacheIndex[areaNum]; - if ( portalCacheIndex[areaNum] ) { - portalCacheIndex[areaNum]->prev = cache; - } - portalCacheIndex[areaNum] = cache; - UpdatePortalRoutingCache( cache ); - } - LinkCache( cache ); - return cache; -} - -/* -============ -idAASLocal::RouteToGoalArea -============ -*/ -bool idAASLocal::RouteToGoalArea( int areaNum, const idVec3 origin, int goalAreaNum, int travelFlags, int &travelTime, idReachability **reach ) const { - int clusterNum, goalClusterNum, portalNum, i, clusterAreaNum; - unsigned short int t, bestTime; - const aasPortal_t *portal; - const aasCluster_t *cluster; - idRoutingCache *areaCache, *portalCache, *clusterCache; - idReachability *bestReach, *r, *nextr; - - travelTime = 0; - *reach = NULL; - - if ( !file ) { - return false; - } - - if ( areaNum == goalAreaNum ) { - return true; - } - - if ( areaNum <= 0 || areaNum >= file->GetNumAreas() ) { - gameLocal.Printf( "RouteToGoalArea: areaNum %d out of range\n", areaNum ); - return false; - } - if ( goalAreaNum <= 0 || goalAreaNum >= file->GetNumAreas() ) { - gameLocal.Printf( "RouteToGoalArea: goalAreaNum %d out of range\n", goalAreaNum ); - return false; - } - - while( totalCacheMemory > MAX_ROUTING_CACHE_MEMORY ) { - DeleteOldestCache(); - } - - clusterNum = file->GetArea( areaNum ).cluster; - goalClusterNum = file->GetArea( goalAreaNum ).cluster; - - // if the source area is a cluster portal, read directly from the portal cache - if ( clusterNum < 0 ) { - // if the goal area is a portal - if ( goalClusterNum < 0 ) { - // just assume the goal area is part of the front cluster - portal = &file->GetPortal( -goalClusterNum ); - goalClusterNum = portal->clusters[0]; - } - // get the portal routing cache - portalCache = GetPortalRoutingCache( goalClusterNum, goalAreaNum, travelFlags ); - *reach = GetAreaReachability( areaNum, portalCache->reachabilities[-clusterNum] ); - travelTime = portalCache->travelTimes[-clusterNum] + AreaTravelTime( areaNum, origin, (*reach)->start ); - return true; - } - - bestTime = 0; - bestReach = NULL; - - // check if the goal area is a portal of the source area cluster - if ( goalClusterNum < 0 ) { - portal = &file->GetPortal( -goalClusterNum ); - if ( portal->clusters[0] == clusterNum || portal->clusters[1] == clusterNum) { - goalClusterNum = clusterNum; - } - } - - // if both areas are in the same cluster - if ( clusterNum > 0 && goalClusterNum > 0 && clusterNum == goalClusterNum ) { - clusterCache = GetAreaRoutingCache( clusterNum, goalAreaNum, travelFlags ); - clusterAreaNum = ClusterAreaNum( clusterNum, areaNum ); - if ( clusterCache->travelTimes[clusterAreaNum] ) { - bestReach = GetAreaReachability( areaNum, clusterCache->reachabilities[clusterAreaNum] ); - bestTime = clusterCache->travelTimes[clusterAreaNum] + AreaTravelTime( areaNum, origin, bestReach->start ); - } - else { - clusterCache = NULL; - } - } - else { - clusterCache = NULL; - } - - clusterNum = file->GetArea( areaNum ).cluster; - goalClusterNum = file->GetArea( goalAreaNum ).cluster; - - // if the goal area is a portal - if ( goalClusterNum < 0 ) { - // just assume the goal area is part of the front cluster - portal = &file->GetPortal( -goalClusterNum ); - goalClusterNum = portal->clusters[0]; - } - // get the portal routing cache - portalCache = GetPortalRoutingCache( goalClusterNum, goalAreaNum, travelFlags ); - - // the cluster the area is in - cluster = &file->GetCluster( clusterNum ); - // current area inside the current cluster - clusterAreaNum = ClusterAreaNum( clusterNum, areaNum ); - // if the area is not a reachable area - if ( clusterAreaNum >= cluster->numReachableAreas) { - return false; - } - - // find the portal of the source area cluster leading towards the goal area - for ( i = 0; i < cluster->numPortals; i++ ) { - portalNum = file->GetPortalIndex( cluster->firstPortal + i ); - - // if the goal area isn't reachable from the portal - if ( !portalCache->travelTimes[portalNum] ) { - continue; - } - - portal = &file->GetPortal( portalNum ); - // get the cache of the portal area - areaCache = GetAreaRoutingCache( clusterNum, portal->areaNum, travelFlags ); - // if the portal is not reachable from this area - if ( !areaCache->travelTimes[clusterAreaNum] ) { - continue; - } - - r = GetAreaReachability( areaNum, areaCache->reachabilities[clusterAreaNum] ); - - if ( clusterCache ) { - // if the next reachability from the portal leads back into the cluster - nextr = GetAreaReachability( portal->areaNum, portalCache->reachabilities[portalNum] ); - if ( file->GetArea( nextr->toAreaNum ).cluster < 0 || file->GetArea( nextr->toAreaNum ).cluster == clusterNum ) { - continue; - } - } - - // the total travel time is the travel time from the portal area to the goal area - // plus the travel time from the source area towards the portal area - t = portalCache->travelTimes[portalNum] + areaCache->travelTimes[clusterAreaNum]; - // NOTE: Should add the exact travel time through the portal area. - // However we add the largest travel time through the portal area. - // We cannot directly calculate the exact travel time through the portal area - // because the reachability used to travel into the portal area is not known. - t += portal->maxAreaTravelTime; - - // if the time is better than the one already found - if ( !bestTime || t < bestTime ) { - bestReach = r; - bestTime = t; - } - } - - if ( !bestReach ) { - return false; - } - - *reach = bestReach; - travelTime = bestTime; - - return true; -} - -/* -============ -idAASLocal::TravelTimeToGoalArea -============ -*/ -int idAASLocal::TravelTimeToGoalArea( int areaNum, const idVec3 &origin, int goalAreaNum, int travelFlags ) const { - int travelTime; - idReachability *reach; - - if ( !file ) { - return 0; - } - - if ( !RouteToGoalArea( areaNum, origin, goalAreaNum, travelFlags, travelTime, &reach ) ) { - return 0; - } - return travelTime; -} - -/* -============ -idAASLocal::FindNearestGoal -============ -*/ -bool idAASLocal::FindNearestGoal( aasGoal_t &goal, int areaNum, const idVec3 origin, const idVec3 &target, int travelFlags, aasObstacle_t *obstacles, int numObstacles, idAASCallback &callback ) const { - int i, j, k, badTravelFlags, nextAreaNum, bestAreaNum; - unsigned short t, bestTravelTime; - idRoutingUpdate *updateListStart, *updateListEnd, *curUpdate, *nextUpdate; - idReachability *reach; - const aasArea_t *nextArea; - idVec3 v1, v2, p; - float targetDist, dist; - - if ( file == NULL || areaNum <= 0 ) { - goal.areaNum = areaNum; - goal.origin = origin; - return false; - } - - // if the first area is valid goal, just return the origin - if ( callback.TestArea( this, areaNum ) ) { - goal.areaNum = areaNum; - goal.origin = origin; - return true; - } - - // setup obstacles - for ( k = 0; k < numObstacles; k++ ) { - obstacles[k].expAbsBounds[0] = obstacles[k].absBounds[0] - file->GetSettings().boundingBoxes[0][1]; - obstacles[k].expAbsBounds[1] = obstacles[k].absBounds[1] - file->GetSettings().boundingBoxes[0][0]; - } - - badTravelFlags = ~travelFlags; - SIMDProcessor->Memset( goalAreaTravelTimes, 0, file->GetNumAreas() * sizeof( unsigned short ) ); - - targetDist = (target - origin).Length(); - - // initialize first update - curUpdate = &areaUpdate[areaNum]; - curUpdate->areaNum = areaNum; - curUpdate->tmpTravelTime = 0; - curUpdate->start = origin; - curUpdate->next = NULL; - curUpdate->prev = NULL; - updateListStart = curUpdate; - updateListEnd = curUpdate; - - bestTravelTime = 0; - bestAreaNum = 0; - - // while there are updates in the list - while ( updateListStart ) { - - curUpdate = updateListStart; - if ( curUpdate->next ) { - curUpdate->next->prev = NULL; - } - else { - updateListEnd = NULL; - } - updateListStart = curUpdate->next; - - curUpdate->isInList = false; - - // if we already found a closer location - if ( bestTravelTime && curUpdate->tmpTravelTime >= bestTravelTime ) { - continue; - } - - for ( i = 0, reach = file->GetArea( curUpdate->areaNum ).reach; reach; reach = reach->next, i++ ) { - - // if the reachability uses an undesired travel type - if ( reach->travelType & badTravelFlags ) { - continue; - } - - // next area the reversed reachability leads to - nextAreaNum = reach->toAreaNum; - nextArea = &file->GetArea( nextAreaNum ); - - // if traveling through the next area requires an undesired travel flag - if ( nextArea->travelFlags & badTravelFlags ) { - continue; - } - - t = curUpdate->tmpTravelTime + - AreaTravelTime( curUpdate->areaNum, curUpdate->start, reach->start ) + - reach->travelTime; - - // project target origin onto movement vector through the area - v1 = reach->end - curUpdate->start; - v1.Normalize(); - v2 = target - curUpdate->start; - p = curUpdate->start + (v2 * v1) * v1; - - // get the point on the path closest to the target - for ( j = 0; j < 3; j++ ) { - if ( (p[j] > curUpdate->start[j] + 0.1f && p[j] > reach->end[j] + 0.1f) || - (p[j] < curUpdate->start[j] - 0.1f && p[j] < reach->end[j] - 0.1f) ) { - break; - } - } - if ( j >= 3 ) { - dist = (target - p).Length(); - } else { - dist = (target - reach->end).Length(); - } - - // avoid moving closer to the target - if ( dist < targetDist ) { - t += ( targetDist - dist ) * 10; - } - - // if we already found a closer location - if ( bestTravelTime && t >= bestTravelTime ) { - continue; - } - - // if this is not the best path towards the next area - if ( goalAreaTravelTimes[nextAreaNum] && t >= goalAreaTravelTimes[nextAreaNum] ) { - continue; - } - - // path may not go through any obstacles - for ( k = 0; k < numObstacles; k++ ) { - // if the movement vector intersects the expanded obstacle bounds - if ( obstacles[k].expAbsBounds.LineIntersection( curUpdate->start, reach->end ) ) { - break; - } - } - if ( k < numObstacles ) { - continue; - } - - goalAreaTravelTimes[nextAreaNum] = t; - nextUpdate = &areaUpdate[nextAreaNum]; - nextUpdate->areaNum = nextAreaNum; - nextUpdate->tmpTravelTime = t; - nextUpdate->start = reach->end; - - // if we are not allowed to fly - if ( badTravelFlags & TFL_FLY ) { - // avoid areas near ledges - if ( file->GetArea( nextAreaNum ).flags & AREA_LEDGE ) { - nextUpdate->tmpTravelTime += LEDGE_TRAVELTIME_PANALTY; - } - } - - if ( !nextUpdate->isInList ) { - nextUpdate->next = NULL; - nextUpdate->prev = updateListEnd; - if ( updateListEnd ) { - updateListEnd->next = nextUpdate; - } else { - updateListStart = nextUpdate; - } - updateListEnd = nextUpdate; - nextUpdate->isInList = true; - } - - // don't put goal near a ledge - if ( !( nextArea->flags & AREA_LEDGE ) ) { - - // add travel time through the area - t += AreaTravelTime( reach->toAreaNum, reach->end, nextArea->center ); - - if ( !bestTravelTime || t < bestTravelTime ) { - // if the area is not visible to the target - if ( callback.TestArea( this, reach->toAreaNum ) ) { - bestTravelTime = t; - bestAreaNum = reach->toAreaNum; - } - } - } - } - } - - if ( bestAreaNum ) { - goal.areaNum = bestAreaNum; - goal.origin = AreaCenter( bestAreaNum ); - return true; - } - - return false; -} diff --git a/d3xp/ai/AI.cpp b/d3xp/ai/AI.cpp deleted file mode 100644 index 887594b6..00000000 --- a/d3xp/ai/AI.cpp +++ /dev/null @@ -1,5350 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "idlib/math/Quat.h" -#include "framework/DeclEntityDef.h" - -#include "gamesys/SysCvar.h" -#include "Moveable.h" -#include "Fx.h" -#include "SmokeParticles.h" -#include "Misc.h" - -#include "ai/AI.h" - -static const char *moveCommandString[ NUM_MOVE_COMMANDS ] = { - "MOVE_NONE", - "MOVE_FACE_ENEMY", - "MOVE_FACE_ENTITY", - "MOVE_TO_ENEMY", - "MOVE_TO_ENEMYHEIGHT", - "MOVE_TO_ENTITY", - "MOVE_OUT_OF_RANGE", - "MOVE_TO_ATTACK_POSITION", - "MOVE_TO_COVER", - "MOVE_TO_POSITION", - "MOVE_TO_POSITION_DIRECT", - "MOVE_SLIDE_TO_POSITION", - "MOVE_WANDER" -}; - -/* -===================== -idMoveState::idMoveState -===================== -*/ -idMoveState::idMoveState() { - moveType = MOVETYPE_ANIM; - moveCommand = MOVE_NONE; - moveStatus = MOVE_STATUS_DONE; - moveDest.Zero(); - moveDir.Set( 1.0f, 0.0f, 0.0f ); - goalEntity = NULL; - goalEntityOrigin.Zero(); - toAreaNum = 0; - startTime = 0; - duration = 0; - speed = 0.0f; - range = 0.0f; - wanderYaw = 0; - nextWanderTime = 0; - blockTime = 0; - obstacle = NULL; - lastMoveOrigin = vec3_origin; - lastMoveTime = 0; - anim = 0; -} - -/* -===================== -idMoveState::Save -===================== -*/ -void idMoveState::Save( idSaveGame *savefile ) const { - savefile->WriteInt( (int)moveType ); - savefile->WriteInt( (int)moveCommand ); - savefile->WriteInt( (int)moveStatus ); - savefile->WriteVec3( moveDest ); - savefile->WriteVec3( moveDir ); - goalEntity.Save( savefile ); - savefile->WriteVec3( goalEntityOrigin ); - savefile->WriteInt( toAreaNum ); - savefile->WriteInt( startTime ); - savefile->WriteInt( duration ); - savefile->WriteFloat( speed ); - savefile->WriteFloat( range ); - savefile->WriteFloat( wanderYaw ); - savefile->WriteInt( nextWanderTime ); - savefile->WriteInt( blockTime ); - obstacle.Save( savefile ); - savefile->WriteVec3( lastMoveOrigin ); - savefile->WriteInt( lastMoveTime ); - savefile->WriteInt( anim ); -} - -/* -===================== -idMoveState::Restore -===================== -*/ -void idMoveState::Restore( idRestoreGame *savefile ) { - savefile->ReadInt( (int &)moveType ); - savefile->ReadInt( (int &)moveCommand ); - savefile->ReadInt( (int &)moveStatus ); - savefile->ReadVec3( moveDest ); - savefile->ReadVec3( moveDir ); - goalEntity.Restore( savefile ); - savefile->ReadVec3( goalEntityOrigin ); - savefile->ReadInt( toAreaNum ); - savefile->ReadInt( startTime ); - savefile->ReadInt( duration ); - savefile->ReadFloat( speed ); - savefile->ReadFloat( range ); - savefile->ReadFloat( wanderYaw ); - savefile->ReadInt( nextWanderTime ); - savefile->ReadInt( blockTime ); - obstacle.Restore( savefile ); - savefile->ReadVec3( lastMoveOrigin ); - savefile->ReadInt( lastMoveTime ); - savefile->ReadInt( anim ); -} - -/* -============ -idAASFindCover::idAASFindCover -============ -*/ -idAASFindCover::idAASFindCover( const idVec3 &hideFromPos ) { - int numPVSAreas; - idBounds bounds( hideFromPos - idVec3( 16, 16, 0 ), hideFromPos + idVec3( 16, 16, 64 ) ); - - // setup PVS - numPVSAreas = gameLocal.pvs.GetPVSAreas( bounds, PVSAreas, idEntity::MAX_PVS_AREAS ); - hidePVS = gameLocal.pvs.SetupCurrentPVS( PVSAreas, numPVSAreas ); -} - -/* -============ -idAASFindCover::~idAASFindCover -============ -*/ -idAASFindCover::~idAASFindCover() { - gameLocal.pvs.FreeCurrentPVS( hidePVS ); -} - -/* -============ -idAASFindCover::TestArea -============ -*/ -bool idAASFindCover::TestArea( const idAAS *aas, int areaNum ) { - idVec3 areaCenter; - int numPVSAreas; - int PVSAreas[ idEntity::MAX_PVS_AREAS ]; - - areaCenter = aas->AreaCenter( areaNum ); - areaCenter[ 2 ] += 1.0f; - - numPVSAreas = gameLocal.pvs.GetPVSAreas( idBounds( areaCenter ).Expand( 16.0f ), PVSAreas, idEntity::MAX_PVS_AREAS ); - if ( !gameLocal.pvs.InCurrentPVS( hidePVS, PVSAreas, numPVSAreas ) ) { - return true; - } - - return false; -} - -/* -============ -idAASFindAreaOutOfRange::idAASFindAreaOutOfRange -============ -*/ -idAASFindAreaOutOfRange::idAASFindAreaOutOfRange( const idVec3 &targetPos, float maxDist ) { - this->targetPos = targetPos; - this->maxDistSqr = maxDist * maxDist; -} - -/* -============ -idAASFindAreaOutOfRange::TestArea -============ -*/ -bool idAASFindAreaOutOfRange::TestArea( const idAAS *aas, int areaNum ) { - const idVec3 &areaCenter = aas->AreaCenter( areaNum ); - trace_t trace; - float dist; - - dist = ( targetPos.ToVec2() - areaCenter.ToVec2() ).LengthSqr(); - - if ( ( maxDistSqr > 0.0f ) && ( dist < maxDistSqr ) ) { - return false; - } - - gameLocal.clip.TracePoint( trace, targetPos, areaCenter + idVec3( 0.0f, 0.0f, 1.0f ), MASK_OPAQUE, NULL ); - if ( trace.fraction < 1.0f ) { - return false; - } - - return true; -} - -/* -============ -idAASFindAttackPosition::idAASFindAttackPosition -============ -*/ -idAASFindAttackPosition::idAASFindAttackPosition( const idAI *self, const idMat3 &gravityAxis, idEntity *target, const idVec3 &targetPos, const idVec3 &fireOffset ) { - int numPVSAreas; - - this->target = target; - this->targetPos = targetPos; - this->fireOffset = fireOffset; - this->self = self; - this->gravityAxis = gravityAxis; - - excludeBounds = idBounds( idVec3( -64.0, -64.0f, -8.0f ), idVec3( 64.0, 64.0f, 64.0f ) ); - excludeBounds.TranslateSelf( self->GetPhysics()->GetOrigin() ); - - // setup PVS - idBounds bounds( targetPos - idVec3( 16, 16, 0 ), targetPos + idVec3( 16, 16, 64 ) ); - numPVSAreas = gameLocal.pvs.GetPVSAreas( bounds, PVSAreas, idEntity::MAX_PVS_AREAS ); - targetPVS = gameLocal.pvs.SetupCurrentPVS( PVSAreas, numPVSAreas ); -} - -/* -============ -idAASFindAttackPosition::~idAASFindAttackPosition -============ -*/ -idAASFindAttackPosition::~idAASFindAttackPosition() { - gameLocal.pvs.FreeCurrentPVS( targetPVS ); -} - -/* -============ -idAASFindAttackPosition::TestArea -============ -*/ -bool idAASFindAttackPosition::TestArea( const idAAS *aas, int areaNum ) { - idVec3 dir; - idVec3 local_dir; - idVec3 fromPos; - idMat3 axis; - idVec3 areaCenter; - int numPVSAreas; - int PVSAreas[ idEntity::MAX_PVS_AREAS ]; - - areaCenter = aas->AreaCenter( areaNum ); - areaCenter[ 2 ] += 1.0f; - - if ( excludeBounds.ContainsPoint( areaCenter ) ) { - // too close to where we already are - return false; - } - - numPVSAreas = gameLocal.pvs.GetPVSAreas( idBounds( areaCenter ).Expand( 16.0f ), PVSAreas, idEntity::MAX_PVS_AREAS ); - if ( !gameLocal.pvs.InCurrentPVS( targetPVS, PVSAreas, numPVSAreas ) ) { - return false; - } - - // calculate the world transform of the launch position - dir = targetPos - areaCenter; - gravityAxis.ProjectVector( dir, local_dir ); - local_dir.z = 0.0f; - local_dir.ToVec2().Normalize(); - axis = local_dir.ToMat3(); - fromPos = areaCenter + fireOffset * axis; - - return self->GetAimDir( fromPos, target, self, dir ); -} - -/* -===================== -idAI::idAI -===================== -*/ -idAI::idAI() { - aas = NULL; - travelFlags = TFL_WALK|TFL_AIR; - - kickForce = 2048.0f; - ignore_obstacles = false; - blockedRadius = 0.0f; - blockedMoveTime = 750; - blockedAttackTime = 750; - turnRate = 360.0f; - turnVel = 0.0f; - anim_turn_yaw = 0.0f; - anim_turn_amount = 0.0f; - anim_turn_angles = 0.0f; - fly_offset = 0; - fly_seek_scale = 1.0f; - fly_roll_scale = 0.0f; - fly_roll_max = 0.0f; - fly_roll = 0.0f; - fly_pitch_scale = 0.0f; - fly_pitch_max = 0.0f; - fly_pitch = 0.0f; - allowMove = false; - allowHiddenMovement = false; - fly_speed = 0.0f; - fly_bob_strength = 0.0f; - fly_bob_vert = 0.0f; - fly_bob_horz = 0.0f; - lastHitCheckResult = false; - lastHitCheckTime = 0; - lastAttackTime = 0; - melee_range = 0.0f; - projectile_height_to_distance_ratio = 1.0f; - projectileDef = NULL; - projectile = NULL; - projectileClipModel = NULL; - projectileRadius = 0.0f; - projectileVelocity = vec3_origin; - projectileGravity = vec3_origin; - projectileSpeed = 0.0f; - chat_snd = NULL; - chat_min = 0; - chat_max = 0; - chat_time = 0; - talk_state = TALK_NEVER; - talkTarget = NULL; - - particles.Clear(); - restartParticles = true; - useBoneAxis = false; - - wakeOnFlashlight = false; - memset( &worldMuzzleFlash, 0, sizeof ( worldMuzzleFlash ) ); - worldMuzzleFlashHandle = -1; - - enemy = NULL; - lastVisibleEnemyPos.Zero(); - lastVisibleEnemyEyeOffset.Zero(); - lastVisibleReachableEnemyPos.Zero(); - lastReachableEnemyPos.Zero(); - shrivel_rate = 0.0f; - shrivel_start = 0; - fl.neverDormant = false; // AI's can go dormant - current_yaw = 0.0f; - ideal_yaw = 0.0f; - -#ifdef _D3XP - spawnClearMoveables = false; - harvestEnt = NULL; -#endif - - num_cinematics = 0; - current_cinematic = 0; - - allowEyeFocus = true; - allowPain = true; - allowJointMod = true; - focusEntity = NULL; - focusTime = 0; - alignHeadTime = 0; - forceAlignHeadTime = 0; - - currentFocusPos.Zero(); - eyeAng.Zero(); - lookAng.Zero(); - destLookAng.Zero(); - lookMin.Zero(); - lookMax.Zero(); - - eyeMin.Zero(); - eyeMax.Zero(); - muzzleFlashEnd = 0; - flashTime = 0; - flashJointWorld = INVALID_JOINT; - - focusJoint = INVALID_JOINT; - orientationJoint = INVALID_JOINT; - flyTiltJoint = INVALID_JOINT; - - eyeVerticalOffset = 0.0f; - eyeHorizontalOffset = 0.0f; - eyeFocusRate = 0.0f; - headFocusRate = 0.0f; - focusAlignTime = 0; -} - -/* -===================== -idAI::~idAI -===================== -*/ -idAI::~idAI() { - delete projectileClipModel; - DeconstructScriptObject(); - scriptObject.Free(); - if ( worldMuzzleFlashHandle != -1 ) { - gameRenderWorld->FreeLightDef( worldMuzzleFlashHandle ); - worldMuzzleFlashHandle = -1; - } - -#ifdef _D3XP - if ( harvestEnt.GetEntity() ) { - harvestEnt.GetEntity()->PostEventMS( &EV_Remove, 0 ); - } -#endif -} - -/* -===================== -idAI::Save -===================== -*/ -void idAI::Save( idSaveGame *savefile ) const { - int i; - - savefile->WriteInt( travelFlags ); - move.Save( savefile ); - savedMove.Save( savefile ); - savefile->WriteFloat( kickForce ); - savefile->WriteBool( ignore_obstacles ); - savefile->WriteFloat( blockedRadius ); - savefile->WriteInt( blockedMoveTime ); - savefile->WriteInt( blockedAttackTime ); - - savefile->WriteFloat( ideal_yaw ); - savefile->WriteFloat( current_yaw ); - savefile->WriteFloat( turnRate ); - savefile->WriteFloat( turnVel ); - savefile->WriteFloat( anim_turn_yaw ); - savefile->WriteFloat( anim_turn_amount ); - savefile->WriteFloat( anim_turn_angles ); - - savefile->WriteStaticObject( physicsObj ); - - savefile->WriteFloat( fly_speed ); - savefile->WriteFloat( fly_bob_strength ); - savefile->WriteFloat( fly_bob_vert ); - savefile->WriteFloat( fly_bob_horz ); - savefile->WriteInt( fly_offset ); - savefile->WriteFloat( fly_seek_scale ); - savefile->WriteFloat( fly_roll_scale ); - savefile->WriteFloat( fly_roll_max ); - savefile->WriteFloat( fly_roll ); - savefile->WriteFloat( fly_pitch_scale ); - savefile->WriteFloat( fly_pitch_max ); - savefile->WriteFloat( fly_pitch ); - - savefile->WriteBool( allowMove ); - savefile->WriteBool( allowHiddenMovement ); - savefile->WriteBool( disableGravity ); - savefile->WriteBool( af_push_moveables ); - - savefile->WriteBool( lastHitCheckResult ); - savefile->WriteInt( lastHitCheckTime ); - savefile->WriteInt( lastAttackTime ); - savefile->WriteFloat( melee_range ); - savefile->WriteFloat( projectile_height_to_distance_ratio ); - - savefile->WriteInt( missileLaunchOffset.Num() ); - for( i = 0; i < missileLaunchOffset.Num(); i++ ) { - savefile->WriteVec3( missileLaunchOffset[ i ] ); - } - - idStr projectileName; - spawnArgs.GetString( "def_projectile", "", projectileName ); - savefile->WriteString( projectileName ); - savefile->WriteFloat( projectileRadius ); - savefile->WriteFloat( projectileSpeed ); - savefile->WriteVec3( projectileVelocity ); - savefile->WriteVec3( projectileGravity ); - projectile.Save( savefile ); - savefile->WriteString( attack ); - - savefile->WriteSoundShader( chat_snd ); - savefile->WriteInt( chat_min ); - savefile->WriteInt( chat_max ); - savefile->WriteInt( chat_time ); - savefile->WriteInt( talk_state ); - talkTarget.Save( savefile ); - - savefile->WriteInt( num_cinematics ); - savefile->WriteInt( current_cinematic ); - - savefile->WriteBool( allowJointMod ); - focusEntity.Save( savefile ); - savefile->WriteVec3( currentFocusPos ); - savefile->WriteInt( focusTime ); - savefile->WriteInt( alignHeadTime ); - savefile->WriteInt( forceAlignHeadTime ); - savefile->WriteAngles( eyeAng ); - savefile->WriteAngles( lookAng ); - savefile->WriteAngles( destLookAng ); - savefile->WriteAngles( lookMin ); - savefile->WriteAngles( lookMax ); - - savefile->WriteInt( lookJoints.Num() ); - for( i = 0; i < lookJoints.Num(); i++ ) { - savefile->WriteJoint( lookJoints[ i ] ); - savefile->WriteAngles( lookJointAngles[ i ] ); - } - - savefile->WriteFloat( shrivel_rate ); - savefile->WriteInt( shrivel_start ); - - savefile->WriteInt( particles.Num() ); - for ( i = 0; i < particles.Num(); i++ ) { - savefile->WriteParticle( particles[i].particle ); - savefile->WriteInt( particles[i].time ); - savefile->WriteJoint( particles[i].joint ); - } - savefile->WriteBool( restartParticles ); - savefile->WriteBool( useBoneAxis ); - - enemy.Save( savefile ); - savefile->WriteVec3( lastVisibleEnemyPos ); - savefile->WriteVec3( lastVisibleEnemyEyeOffset ); - savefile->WriteVec3( lastVisibleReachableEnemyPos ); - savefile->WriteVec3( lastReachableEnemyPos ); - savefile->WriteBool( wakeOnFlashlight ); - - savefile->WriteAngles( eyeMin ); - savefile->WriteAngles( eyeMax ); - - savefile->WriteFloat( eyeVerticalOffset ); - savefile->WriteFloat( eyeHorizontalOffset ); - savefile->WriteFloat( eyeFocusRate ); - savefile->WriteFloat( headFocusRate ); - savefile->WriteInt( focusAlignTime ); - - savefile->WriteJoint( flashJointWorld ); - savefile->WriteInt( muzzleFlashEnd ); - - savefile->WriteJoint( focusJoint ); - savefile->WriteJoint( orientationJoint ); - savefile->WriteJoint( flyTiltJoint ); - - savefile->WriteBool( GetPhysics() == static_cast(&physicsObj) ); - -#ifdef _D3XP - savefile->WriteInt(funcEmitters.Num()); - for(int i = 0; i < funcEmitters.Num(); i++) { - funcEmitter_t* emitter = funcEmitters.GetIndex(i); - savefile->WriteString(emitter->name); - savefile->WriteJoint(emitter->joint); - savefile->WriteObject(emitter->particle); - } - - harvestEnt.Save( savefile); -#endif -} - -/* -===================== -idAI::Restore -===================== -*/ -void idAI::Restore( idRestoreGame *savefile ) { - bool restorePhysics; - int i; - int num; - idBounds bounds; - - savefile->ReadInt( travelFlags ); - move.Restore( savefile ); - savedMove.Restore( savefile ); - savefile->ReadFloat( kickForce ); - savefile->ReadBool( ignore_obstacles ); - savefile->ReadFloat( blockedRadius ); - savefile->ReadInt( blockedMoveTime ); - savefile->ReadInt( blockedAttackTime ); - - savefile->ReadFloat( ideal_yaw ); - savefile->ReadFloat( current_yaw ); - savefile->ReadFloat( turnRate ); - savefile->ReadFloat( turnVel ); - savefile->ReadFloat( anim_turn_yaw ); - savefile->ReadFloat( anim_turn_amount ); - savefile->ReadFloat( anim_turn_angles ); - - savefile->ReadStaticObject( physicsObj ); - - savefile->ReadFloat( fly_speed ); - savefile->ReadFloat( fly_bob_strength ); - savefile->ReadFloat( fly_bob_vert ); - savefile->ReadFloat( fly_bob_horz ); - savefile->ReadInt( fly_offset ); - savefile->ReadFloat( fly_seek_scale ); - savefile->ReadFloat( fly_roll_scale ); - savefile->ReadFloat( fly_roll_max ); - savefile->ReadFloat( fly_roll ); - savefile->ReadFloat( fly_pitch_scale ); - savefile->ReadFloat( fly_pitch_max ); - savefile->ReadFloat( fly_pitch ); - - savefile->ReadBool( allowMove ); - savefile->ReadBool( allowHiddenMovement ); - savefile->ReadBool( disableGravity ); - savefile->ReadBool( af_push_moveables ); - - savefile->ReadBool( lastHitCheckResult ); - savefile->ReadInt( lastHitCheckTime ); - savefile->ReadInt( lastAttackTime ); - savefile->ReadFloat( melee_range ); - savefile->ReadFloat( projectile_height_to_distance_ratio ); - - savefile->ReadInt( num ); - missileLaunchOffset.SetGranularity( 1 ); - missileLaunchOffset.SetNum( num ); - for( i = 0; i < num; i++ ) { - savefile->ReadVec3( missileLaunchOffset[ i ] ); - } - - idStr projectileName; - savefile->ReadString( projectileName ); - if ( projectileName.Length() ) { - projectileDef = gameLocal.FindEntityDefDict( projectileName ); - } else { - projectileDef = NULL; - } - savefile->ReadFloat( projectileRadius ); - savefile->ReadFloat( projectileSpeed ); - savefile->ReadVec3( projectileVelocity ); - savefile->ReadVec3( projectileGravity ); - projectile.Restore( savefile ); - savefile->ReadString( attack ); - - savefile->ReadSoundShader( chat_snd ); - savefile->ReadInt( chat_min ); - savefile->ReadInt( chat_max ); - savefile->ReadInt( chat_time ); - savefile->ReadInt( i ); - talk_state = static_cast( i ); - talkTarget.Restore( savefile ); - - savefile->ReadInt( num_cinematics ); - savefile->ReadInt( current_cinematic ); - - savefile->ReadBool( allowJointMod ); - focusEntity.Restore( savefile ); - savefile->ReadVec3( currentFocusPos ); - savefile->ReadInt( focusTime ); - savefile->ReadInt( alignHeadTime ); - savefile->ReadInt( forceAlignHeadTime ); - savefile->ReadAngles( eyeAng ); - savefile->ReadAngles( lookAng ); - savefile->ReadAngles( destLookAng ); - savefile->ReadAngles( lookMin ); - savefile->ReadAngles( lookMax ); - - savefile->ReadInt( num ); - lookJoints.SetGranularity( 1 ); - lookJoints.SetNum( num ); - lookJointAngles.SetGranularity( 1 ); - lookJointAngles.SetNum( num ); - for( i = 0; i < num; i++ ) { - savefile->ReadJoint( lookJoints[ i ] ); - savefile->ReadAngles( lookJointAngles[ i ] ); - } - - savefile->ReadFloat( shrivel_rate ); - savefile->ReadInt( shrivel_start ); - - savefile->ReadInt( num ); - particles.SetNum( num ); - for ( i = 0; i < particles.Num(); i++ ) { - savefile->ReadParticle( particles[i].particle ); - savefile->ReadInt( particles[i].time ); - savefile->ReadJoint( particles[i].joint ); - } - savefile->ReadBool( restartParticles ); - savefile->ReadBool( useBoneAxis ); - - enemy.Restore( savefile ); - savefile->ReadVec3( lastVisibleEnemyPos ); - savefile->ReadVec3( lastVisibleEnemyEyeOffset ); - savefile->ReadVec3( lastVisibleReachableEnemyPos ); - savefile->ReadVec3( lastReachableEnemyPos ); - - savefile->ReadBool( wakeOnFlashlight ); - - savefile->ReadAngles( eyeMin ); - savefile->ReadAngles( eyeMax ); - - savefile->ReadFloat( eyeVerticalOffset ); - savefile->ReadFloat( eyeHorizontalOffset ); - savefile->ReadFloat( eyeFocusRate ); - savefile->ReadFloat( headFocusRate ); - savefile->ReadInt( focusAlignTime ); - - savefile->ReadJoint( flashJointWorld ); - savefile->ReadInt( muzzleFlashEnd ); - - savefile->ReadJoint( focusJoint ); - savefile->ReadJoint( orientationJoint ); - savefile->ReadJoint( flyTiltJoint ); - - savefile->ReadBool( restorePhysics ); - - // Set the AAS if the character has the correct gravity vector - idVec3 gravity = spawnArgs.GetVector( "gravityDir", "0 0 -1" ); - gravity *= g_gravity.GetFloat(); - if ( gravity == gameLocal.GetGravity() ) { - SetAAS(); - } - - SetCombatModel(); - LinkCombat(); - - InitMuzzleFlash(); - - // Link the script variables back to the scriptobject - LinkScriptVariables(); - - if ( restorePhysics ) { - RestorePhysics( &physicsObj ); - } - -#ifdef _D3XP - - //Clean up the emitters - for(int i = 0; i < funcEmitters.Num(); i++) { - funcEmitter_t* emitter = funcEmitters.GetIndex(i); - if(emitter->particle) { - //Destroy the emitters - emitter->particle->PostEventMS(&EV_Remove, 0 ); - } - } - funcEmitters.Clear(); - - int emitterCount; - savefile->ReadInt( emitterCount ); - for(int i = 0; i < emitterCount; i++) { - funcEmitter_t newEmitter; - memset(&newEmitter, 0, sizeof(newEmitter)); - - idStr name; - savefile->ReadString( name ); - - strcpy( newEmitter.name, name.c_str() ); - - savefile->ReadJoint( newEmitter.joint ); - savefile->ReadObject(reinterpret_cast(newEmitter.particle)); - - funcEmitters.Set(newEmitter.name, newEmitter); - } - - harvestEnt.Restore(savefile); - //if(harvestEnt.GetEntity()) { - // harvestEnt.GetEntity()->SetParent(this); - //} - -#endif -} - -/* -===================== -idAI::Spawn -===================== -*/ -void idAI::Spawn( void ) { - const char *jointname; - const idKeyValue *kv; - idStr jointName; - idAngles jointScale; - jointHandle_t joint; - idVec3 local_dir; - bool talks; - - if ( !g_monsters.GetBool() ) { - PostEventMS( &EV_Remove, 0 ); - return; - } - - spawnArgs.GetInt( "team", "1", team ); - spawnArgs.GetInt( "rank", "0", rank ); - spawnArgs.GetInt( "fly_offset", "0", fly_offset ); - spawnArgs.GetFloat( "fly_speed", "100", fly_speed ); - spawnArgs.GetFloat( "fly_bob_strength", "50", fly_bob_strength ); - spawnArgs.GetFloat( "fly_bob_vert", "2", fly_bob_horz ); - spawnArgs.GetFloat( "fly_bob_horz", "2.7", fly_bob_vert ); - spawnArgs.GetFloat( "fly_seek_scale", "4", fly_seek_scale ); - spawnArgs.GetFloat( "fly_roll_scale", "90", fly_roll_scale ); - spawnArgs.GetFloat( "fly_roll_max", "60", fly_roll_max ); - spawnArgs.GetFloat( "fly_pitch_scale", "45", fly_pitch_scale ); - spawnArgs.GetFloat( "fly_pitch_max", "30", fly_pitch_max ); - - spawnArgs.GetFloat( "melee_range", "64", melee_range ); - spawnArgs.GetFloat( "projectile_height_to_distance_ratio", "1", projectile_height_to_distance_ratio ); - - spawnArgs.GetFloat( "turn_rate", "360", turnRate ); - - spawnArgs.GetBool( "talks", "0", talks ); - if ( spawnArgs.GetString( "npc_name", NULL ) != NULL ) { - if ( talks ) { - talk_state = TALK_OK; - } else { - talk_state = TALK_BUSY; - } - } else { - talk_state = TALK_NEVER; - } - - spawnArgs.GetBool( "animate_z", "0", disableGravity ); - spawnArgs.GetBool( "af_push_moveables", "0", af_push_moveables ); - spawnArgs.GetFloat( "kick_force", "4096", kickForce ); - spawnArgs.GetBool( "ignore_obstacles", "0", ignore_obstacles ); - spawnArgs.GetFloat( "blockedRadius", "-1", blockedRadius ); - spawnArgs.GetInt( "blockedMoveTime", "750", blockedMoveTime ); - spawnArgs.GetInt( "blockedAttackTime", "750", blockedAttackTime ); - - spawnArgs.GetInt( "num_cinematics", "0", num_cinematics ); - current_cinematic = 0; - - LinkScriptVariables(); - - fl.takedamage = !spawnArgs.GetBool( "noDamage" ); - enemy = NULL; - allowMove = true; - allowHiddenMovement = false; - - animator.RemoveOriginOffset( true ); - - // create combat collision hull for exact collision detection - SetCombatModel(); - - lookMin = spawnArgs.GetAngles( "look_min", "-80 -75 0" ); - lookMax = spawnArgs.GetAngles( "look_max", "80 75 0" ); - - lookJoints.SetGranularity( 1 ); - lookJointAngles.SetGranularity( 1 ); - kv = spawnArgs.MatchPrefix( "look_joint", NULL ); - while( kv ) { - jointName = kv->GetKey(); - jointName.StripLeadingOnce( "look_joint " ); - joint = animator.GetJointHandle( jointName ); - if ( joint == INVALID_JOINT ) { - gameLocal.Warning( "Unknown look_joint '%s' on entity %s", jointName.c_str(), name.c_str() ); - } else { - jointScale = spawnArgs.GetAngles( kv->GetKey(), "0 0 0" ); - jointScale.roll = 0.0f; - - // if no scale on any component, then don't bother adding it. this may be done to - // zero out rotation from an inherited entitydef. - if ( jointScale != ang_zero ) { - lookJoints.Append( joint ); - lookJointAngles.Append( jointScale ); - } - } - kv = spawnArgs.MatchPrefix( "look_joint", kv ); - } - - // calculate joint positions on attack frames so we can do proper "can hit" tests - CalculateAttackOffsets(); - - eyeMin = spawnArgs.GetAngles( "eye_turn_min", "-10 -30 0" ); - eyeMax = spawnArgs.GetAngles( "eye_turn_max", "10 30 0" ); - eyeVerticalOffset = spawnArgs.GetFloat( "eye_verticle_offset", "5" ); - eyeHorizontalOffset = spawnArgs.GetFloat( "eye_horizontal_offset", "-8" ); - eyeFocusRate = spawnArgs.GetFloat( "eye_focus_rate", "0.5" ); - headFocusRate = spawnArgs.GetFloat( "head_focus_rate", "0.1" ); - focusAlignTime = SEC2MS( spawnArgs.GetFloat( "focus_align_time", "1" ) ); - - flashJointWorld = animator.GetJointHandle( "flash" ); - - if ( head.GetEntity() ) { - idAnimator *headAnimator = head.GetEntity()->GetAnimator(); - - jointname = spawnArgs.GetString( "bone_focus" ); - if ( *jointname ) { - focusJoint = headAnimator->GetJointHandle( jointname ); - if ( focusJoint == INVALID_JOINT ) { - gameLocal.Warning( "Joint '%s' not found on head on '%s'", jointname, name.c_str() ); - } - } - } else { - jointname = spawnArgs.GetString( "bone_focus" ); - if ( *jointname ) { - focusJoint = animator.GetJointHandle( jointname ); - if ( focusJoint == INVALID_JOINT ) { - gameLocal.Warning( "Joint '%s' not found on '%s'", jointname, name.c_str() ); - } - } - } - - jointname = spawnArgs.GetString( "bone_orientation" ); - if ( *jointname ) { - orientationJoint = animator.GetJointHandle( jointname ); - if ( orientationJoint == INVALID_JOINT ) { - gameLocal.Warning( "Joint '%s' not found on '%s'", jointname, name.c_str() ); - } - } - - jointname = spawnArgs.GetString( "bone_flytilt" ); - if ( *jointname ) { - flyTiltJoint = animator.GetJointHandle( jointname ); - if ( flyTiltJoint == INVALID_JOINT ) { - gameLocal.Warning( "Joint '%s' not found on '%s'", jointname, name.c_str() ); - } - } - - InitMuzzleFlash(); - - physicsObj.SetSelf( this ); - physicsObj.SetClipModel( new idClipModel( GetPhysics()->GetClipModel() ), 1.0f ); - physicsObj.SetMass( spawnArgs.GetFloat( "mass", "100" ) ); - - if ( spawnArgs.GetBool( "big_monster" ) ) { - physicsObj.SetContents( 0 ); - physicsObj.SetClipMask( MASK_MONSTERSOLID & ~CONTENTS_BODY ); - } else { - if ( use_combat_bbox ) { - physicsObj.SetContents( CONTENTS_BODY|CONTENTS_SOLID ); - } else { - physicsObj.SetContents( CONTENTS_BODY ); - } - physicsObj.SetClipMask( MASK_MONSTERSOLID ); - } - - // move up to make sure the monster is at least an epsilon above the floor - physicsObj.SetOrigin( GetPhysics()->GetOrigin() + idVec3( 0, 0, CM_CLIP_EPSILON ) ); - - if ( num_cinematics ) { - physicsObj.SetGravity( vec3_origin ); - } else { - idVec3 gravity = spawnArgs.GetVector( "gravityDir", "0 0 -1" ); - gravity *= g_gravity.GetFloat(); - physicsObj.SetGravity( gravity ); - } - - SetPhysics( &physicsObj ); - - physicsObj.GetGravityAxis().ProjectVector( viewAxis[ 0 ], local_dir ); - current_yaw = local_dir.ToYaw(); - ideal_yaw = idMath::AngleNormalize180( current_yaw ); - - move.blockTime = 0; - - SetAAS(); - - projectile = NULL; - projectileDef = NULL; - projectileClipModel = NULL; - idStr projectileName; - if ( spawnArgs.GetString( "def_projectile", "", projectileName ) && projectileName.Length() ) { - projectileDef = gameLocal.FindEntityDefDict( projectileName ); - CreateProjectile( vec3_origin, viewAxis[ 0 ] ); - projectileRadius = projectile.GetEntity()->GetPhysics()->GetClipModel()->GetBounds().GetRadius(); - projectileVelocity = idProjectile::GetVelocity( projectileDef ); - projectileGravity = idProjectile::GetGravity( projectileDef ); - projectileSpeed = projectileVelocity.Length(); - delete projectile.GetEntity(); - projectile = NULL; - } - - particles.Clear(); - restartParticles = true; - useBoneAxis = spawnArgs.GetBool( "useBoneAxis" ); - SpawnParticles( "smokeParticleSystem" ); - - if ( num_cinematics || spawnArgs.GetBool( "hide" ) || spawnArgs.GetBool( "teleport" ) || spawnArgs.GetBool( "trigger_anim" ) ) { - fl.takedamage = false; - physicsObj.SetContents( 0 ); - physicsObj.GetClipModel()->Unlink(); - Hide(); - } else { - // play a looping ambient sound if we have one - StartSound( "snd_ambient", SND_CHANNEL_AMBIENT, 0, false, NULL ); - } - - if ( health <= 0 ) { - gameLocal.Warning( "entity '%s' doesn't have health set", name.c_str() ); - health = 1; - } - - // set up monster chatter - SetChatSound(); - - BecomeActive( TH_THINK ); - - if ( af_push_moveables ) { - af.SetupPose( this, gameLocal.time ); - af.GetPhysics()->EnableClip(); - } - - // init the move variables - StopMove( MOVE_STATUS_DONE ); - - -#ifdef _D3XP - spawnArgs.GetBool( "spawnClearMoveables", "0", spawnClearMoveables ); -#endif -} - - -#ifdef _D3XP -void idAI::Gib( const idVec3 &dir, const char *damageDefName ) { - if(harvestEnt.GetEntity()) { - //Let the harvest ent know that we gibbed - harvestEnt.GetEntity()->Gib(); - } - idActor::Gib(dir, damageDefName); -} -#endif - -/* -=================== -idAI::InitMuzzleFlash -=================== -*/ -void idAI::InitMuzzleFlash( void ) { - const char *shader; - idVec3 flashColor; - - spawnArgs.GetString( "mtr_flashShader", "muzzleflash", &shader ); - spawnArgs.GetVector( "flashColor", "0 0 0", flashColor ); - float flashRadius = spawnArgs.GetFloat( "flashRadius" ); - flashTime = SEC2MS( spawnArgs.GetFloat( "flashTime", "0.25" ) ); - - memset( &worldMuzzleFlash, 0, sizeof ( worldMuzzleFlash ) ); - - worldMuzzleFlash.pointLight = true; - worldMuzzleFlash.shader = declManager->FindMaterial( shader, false ); - worldMuzzleFlash.shaderParms[ SHADERPARM_RED ] = flashColor[0]; - worldMuzzleFlash.shaderParms[ SHADERPARM_GREEN ] = flashColor[1]; - worldMuzzleFlash.shaderParms[ SHADERPARM_BLUE ] = flashColor[2]; - worldMuzzleFlash.shaderParms[ SHADERPARM_ALPHA ] = 1.0f; - worldMuzzleFlash.shaderParms[ SHADERPARM_TIMESCALE ] = 1.0f; - worldMuzzleFlash.lightRadius[0] = flashRadius; - worldMuzzleFlash.lightRadius[1] = flashRadius; - worldMuzzleFlash.lightRadius[2] = flashRadius; - - worldMuzzleFlashHandle = -1; -} - -/* -=================== -idAI::List_f -=================== -*/ -void idAI::List_f( const idCmdArgs &args ) { - int e; - idAI *check; - int count; - const char *statename; - - count = 0; - - gameLocal.Printf( "%-4s %-20s %s\n", " Num", "EntityDef", "Name" ); - gameLocal.Printf( "------------------------------------------------\n" ); - for( e = 0; e < MAX_GENTITIES; e++ ) { - check = static_cast(gameLocal.entities[ e ]); - if ( !check || !check->IsType( idAI::Type ) ) { - continue; - } - - if ( check->state ) { - statename = check->state->Name(); - } else { - statename = "NULL state"; - } - - gameLocal.Printf( "%4i: %-20s %-20s %s move: %d\n", e, check->GetEntityDefName(), check->name.c_str(), statename, check->allowMove ); - count++; - } - - gameLocal.Printf( "...%d monsters\n", count ); -} - -/* -================ -idAI::DormantBegin - -called when entity becomes dormant -================ -*/ -void idAI::DormantBegin( void ) { - // since dormant happens on a timer, we wont get to update particles to - // hidden through the think loop, but we need to hide them though. - if ( particles.Num() ) { - for ( int i = 0; i < particles.Num(); i++ ) { - particles[i].time = 0; - } - } - - if ( enemyNode.InList() ) { - // remove ourselves from the enemy's enemylist - enemyNode.Remove(); - } - idActor::DormantBegin(); -} - -/* -================ -idAI::DormantEnd - -called when entity wakes from being dormant -================ -*/ -void idAI::DormantEnd( void ) { - if ( enemy.GetEntity() && !enemyNode.InList() ) { - // let our enemy know we're back on the trail - enemyNode.AddToEnd( enemy.GetEntity()->enemyList ); - } - - if ( particles.Num() ) { - for ( int i = 0; i < particles.Num(); i++ ) { - particles[i].time = gameLocal.time; - } - } - - idActor::DormantEnd(); -} - -/* -===================== -idAI::Think -===================== -*/ -void idAI::Think( void ) { - // if we are completely closed off from the player, don't do anything at all - if ( CheckDormant() ) { - return; - } - - if ( thinkFlags & TH_THINK ) { - // clear out the enemy when he dies or is hidden - idActor *enemyEnt = enemy.GetEntity(); - if ( enemyEnt ) { - if ( enemyEnt->health <= 0 ) { - EnemyDead(); - } - } - - current_yaw += deltaViewAngles.yaw; - ideal_yaw = idMath::AngleNormalize180( ideal_yaw + deltaViewAngles.yaw ); - deltaViewAngles.Zero(); - viewAxis = idAngles( 0, current_yaw, 0 ).ToMat3(); - - if ( num_cinematics ) { - if ( !IsHidden() && torsoAnim.AnimDone( 0 ) ) { - PlayCinematic(); - } - RunPhysics(); - } else if ( !allowHiddenMovement && IsHidden() ) { - // hidden monsters - UpdateAIScript(); - } else { - // clear the ik before we do anything else so the skeleton doesn't get updated twice - walkIK.ClearJointMods(); - - switch( move.moveType ) { - case MOVETYPE_DEAD : - // dead monsters - UpdateAIScript(); - DeadMove(); - break; - - case MOVETYPE_FLY : - // flying monsters - UpdateEnemyPosition(); - UpdateAIScript(); - FlyMove(); - PlayChatter(); - CheckBlink(); - break; - - case MOVETYPE_STATIC : - // static monsters - UpdateEnemyPosition(); - UpdateAIScript(); - StaticMove(); - PlayChatter(); - CheckBlink(); - break; - - case MOVETYPE_ANIM : - // animation based movement - UpdateEnemyPosition(); - UpdateAIScript(); - AnimMove(); - PlayChatter(); - CheckBlink(); - break; - - case MOVETYPE_SLIDE : - // velocity based movement - UpdateEnemyPosition(); - UpdateAIScript(); - SlideMove(); - PlayChatter(); - CheckBlink(); - break; - } - } - - // clear pain flag so that we recieve any damage between now and the next time we run the script - AI_PAIN = false; - AI_SPECIAL_DAMAGE = 0; - AI_PUSHED = false; - } else if ( thinkFlags & TH_PHYSICS ) { - RunPhysics(); - } - - if ( af_push_moveables ) { - PushWithAF(); - } - - if ( fl.hidden && allowHiddenMovement ) { - // UpdateAnimation won't call frame commands when hidden, so call them here when we allow hidden movement - animator.ServiceAnims( gameLocal.previousTime, gameLocal.time ); - } -/* this still draws in retail builds.. not sure why.. don't care at this point. - if ( !aas && developer.GetBool() && !fl.hidden && !num_cinematics ) { - gameRenderWorld->DrawText( "No AAS", physicsObj.GetAbsBounds().GetCenter(), 0.1f, colorWhite, gameLocal.GetLocalPlayer()->viewAngles.ToMat3(), 1, gameLocal.msec ); - } -*/ - - UpdateMuzzleFlash(); - UpdateAnimation(); - UpdateParticles(); - Present(); - UpdateDamageEffects(); - LinkCombat(); - -#ifdef _D3XP - if(ai_showHealth.GetBool()) { - idVec3 aboveHead(0,0,20); - gameRenderWorld->DrawText( va( "%d", ( int )health), this->GetEyePosition()+aboveHead, 0.5f, colorWhite, gameLocal.GetLocalPlayer()->viewAngles.ToMat3() ); - } -#endif -} - -/*********************************************************************** - - AI script state management - -***********************************************************************/ - -/* -===================== -idAI::LinkScriptVariables -===================== -*/ -void idAI::LinkScriptVariables( void ) { - AI_TALK.LinkTo( scriptObject, "AI_TALK" ); - AI_DAMAGE.LinkTo( scriptObject, "AI_DAMAGE" ); - AI_PAIN.LinkTo( scriptObject, "AI_PAIN" ); - AI_SPECIAL_DAMAGE.LinkTo( scriptObject, "AI_SPECIAL_DAMAGE" ); - AI_DEAD.LinkTo( scriptObject, "AI_DEAD" ); - AI_ENEMY_VISIBLE.LinkTo( scriptObject, "AI_ENEMY_VISIBLE" ); - AI_ENEMY_IN_FOV.LinkTo( scriptObject, "AI_ENEMY_IN_FOV" ); - AI_ENEMY_DEAD.LinkTo( scriptObject, "AI_ENEMY_DEAD" ); - AI_MOVE_DONE.LinkTo( scriptObject, "AI_MOVE_DONE" ); - AI_ONGROUND.LinkTo( scriptObject, "AI_ONGROUND" ); - AI_ACTIVATED.LinkTo( scriptObject, "AI_ACTIVATED" ); - AI_FORWARD.LinkTo( scriptObject, "AI_FORWARD" ); - AI_JUMP.LinkTo( scriptObject, "AI_JUMP" ); - AI_BLOCKED.LinkTo( scriptObject, "AI_BLOCKED" ); - AI_DEST_UNREACHABLE.LinkTo( scriptObject, "AI_DEST_UNREACHABLE" ); - AI_HIT_ENEMY.LinkTo( scriptObject, "AI_HIT_ENEMY" ); - AI_OBSTACLE_IN_PATH.LinkTo( scriptObject, "AI_OBSTACLE_IN_PATH" ); - AI_PUSHED.LinkTo( scriptObject, "AI_PUSHED" ); -} - -/* -===================== -idAI::UpdateAIScript -===================== -*/ -void idAI::UpdateAIScript( void ) { - UpdateScript(); - - // clear the hit enemy flag so we catch the next time we hit someone - AI_HIT_ENEMY = false; - - if ( allowHiddenMovement || !IsHidden() ) { - // update the animstate if we're not hidden - UpdateAnimState(); - } -} - -/*********************************************************************** - - navigation - -***********************************************************************/ - -/* -============ -idAI::KickObstacles -============ -*/ -void idAI::KickObstacles( const idVec3 &dir, float force, idEntity *alwaysKick ) { - int i, numListedClipModels; - idBounds clipBounds; - idEntity *obEnt; - idClipModel *clipModel; - idClipModel *clipModelList[ MAX_GENTITIES ]; - int clipmask; - idVec3 org; - idVec3 forceVec; - idVec3 delta; - idVec2 perpendicular; - - org = physicsObj.GetOrigin(); - - // find all possible obstacles - clipBounds = physicsObj.GetAbsBounds(); - clipBounds.TranslateSelf( dir * 32.0f ); - clipBounds.ExpandSelf( 8.0f ); - clipBounds.AddPoint( org ); - clipmask = physicsObj.GetClipMask(); - numListedClipModels = gameLocal.clip.ClipModelsTouchingBounds( clipBounds, clipmask, clipModelList, MAX_GENTITIES ); - for ( i = 0; i < numListedClipModels; i++ ) { - clipModel = clipModelList[i]; - obEnt = clipModel->GetEntity(); - if ( obEnt == alwaysKick ) { - // we'll kick this one outside the loop - continue; - } - - if ( !clipModel->IsTraceModel() ) { - continue; - } - - if ( obEnt->IsType( idMoveable::Type ) && obEnt->GetPhysics()->IsPushable() ) { - delta = obEnt->GetPhysics()->GetOrigin() - org; - delta.NormalizeFast(); - perpendicular.x = -delta.y; - perpendicular.y = delta.x; - delta.z += 0.5f; - delta.ToVec2() += perpendicular * gameLocal.random.CRandomFloat() * 0.5f; - forceVec = delta * force * obEnt->GetPhysics()->GetMass(); - obEnt->ApplyImpulse( this, 0, obEnt->GetPhysics()->GetOrigin(), forceVec ); - } - } - - if ( alwaysKick ) { - delta = alwaysKick->GetPhysics()->GetOrigin() - org; - delta.NormalizeFast(); - perpendicular.x = -delta.y; - perpendicular.y = delta.x; - delta.z += 0.5f; - delta.ToVec2() += perpendicular * gameLocal.random.CRandomFloat() * 0.5f; - forceVec = delta * force * alwaysKick->GetPhysics()->GetMass(); - alwaysKick->ApplyImpulse( this, 0, alwaysKick->GetPhysics()->GetOrigin(), forceVec ); - } -} - -/* -============ -ValidForBounds -============ -*/ -bool ValidForBounds( const idAASSettings *settings, const idBounds &bounds ) { - int i; - - for ( i = 0; i < 3; i++ ) { - if ( bounds[0][i] < settings->boundingBoxes[0][0][i] ) { - return false; - } - if ( bounds[1][i] > settings->boundingBoxes[0][1][i] ) { - return false; - } - } - return true; -} - -/* -===================== -idAI::SetAAS -===================== -*/ -void idAI::SetAAS( void ) { - idStr use_aas; - - spawnArgs.GetString( "use_aas", NULL, use_aas ); - aas = gameLocal.GetAAS( use_aas ); - if ( aas ) { - const idAASSettings *settings = aas->GetSettings(); - if ( settings ) { - if ( !ValidForBounds( settings, physicsObj.GetBounds() ) ) { - gameLocal.Error( "%s cannot use use_aas %s\n", name.c_str(), use_aas.c_str() ); - } - float height = settings->maxStepHeight; - physicsObj.SetMaxStepHeight( height ); - return; - } else { - aas = NULL; - } - } - gameLocal.Printf( "WARNING: %s has no AAS file\n", name.c_str() ); -} - -/* -===================== -idAI::DrawRoute -===================== -*/ -void idAI::DrawRoute( void ) const { - if ( aas && move.toAreaNum && move.moveCommand != MOVE_NONE && move.moveCommand != MOVE_WANDER && move.moveCommand != MOVE_FACE_ENEMY && move.moveCommand != MOVE_FACE_ENTITY && move.moveCommand != MOVE_TO_POSITION_DIRECT ) { - if ( move.moveType == MOVETYPE_FLY ) { - aas->ShowFlyPath( physicsObj.GetOrigin(), move.toAreaNum, move.moveDest ); - } else { - aas->ShowWalkPath( physicsObj.GetOrigin(), move.toAreaNum, move.moveDest ); - } - } -} - -/* -===================== -idAI::ReachedPos -===================== -*/ -bool idAI::ReachedPos( const idVec3 &pos, const moveCommand_t moveCommand ) const { - if ( move.moveType == MOVETYPE_SLIDE ) { - idBounds bnds( idVec3( -4, -4.0f, -8.0f ), idVec3( 4.0f, 4.0f, 64.0f ) ); - bnds.TranslateSelf( physicsObj.GetOrigin() ); - if ( bnds.ContainsPoint( pos ) ) { - return true; - } - } else { - if ( ( moveCommand == MOVE_TO_ENEMY ) || ( moveCommand == MOVE_TO_ENTITY ) ) { - if ( physicsObj.GetAbsBounds().IntersectsBounds( idBounds( pos ).Expand( 8.0f ) ) ) { - return true; - } - } else { - idBounds bnds( idVec3( -16.0, -16.0f, -8.0f ), idVec3( 16.0, 16.0f, 64.0f ) ); - bnds.TranslateSelf( physicsObj.GetOrigin() ); - if ( bnds.ContainsPoint( pos ) ) { - return true; - } - } - } - return false; -} - -/* -===================== -idAI::PointReachableAreaNum -===================== -*/ -int idAI::PointReachableAreaNum( const idVec3 &pos, const float boundsScale ) const { - int areaNum; - idVec3 size; - idBounds bounds; - - if ( !aas ) { - return 0; - } - - size = aas->GetSettings()->boundingBoxes[0][1] * boundsScale; - bounds[0] = -size; - size.z = 32.0f; - bounds[1] = size; - - if ( move.moveType == MOVETYPE_FLY ) { - areaNum = aas->PointReachableAreaNum( pos, bounds, AREA_REACHABLE_WALK | AREA_REACHABLE_FLY ); - } else { - areaNum = aas->PointReachableAreaNum( pos, bounds, AREA_REACHABLE_WALK ); - } - - return areaNum; -} - -/* -===================== -idAI::PathToGoal -===================== -*/ -bool idAI::PathToGoal( aasPath_t &path, int areaNum, const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin ) const { - idVec3 org; - idVec3 goal; - - if ( !aas ) { - return false; - } - - org = origin; - aas->PushPointIntoAreaNum( areaNum, org ); - if ( !areaNum ) { - return false; - } - - goal = goalOrigin; - aas->PushPointIntoAreaNum( goalAreaNum, goal ); - if ( !goalAreaNum ) { - return false; - } - - if ( move.moveType == MOVETYPE_FLY ) { - return aas->FlyPathToGoal( path, areaNum, org, goalAreaNum, goal, travelFlags ); - } else { - return aas->WalkPathToGoal( path, areaNum, org, goalAreaNum, goal, travelFlags ); - } -} - -/* -===================== -idAI::TravelDistance - -Returns the approximate travel distance from one position to the goal, or if no AAS, the straight line distance. - -This is feakin' slow, so it's not good to do it too many times per frame. It also is slower the further you -are from the goal, so try to break the goals up into shorter distances. -===================== -*/ -float idAI::TravelDistance( const idVec3 &start, const idVec3 &end ) const { - int fromArea; - int toArea; - float dist; - idVec2 delta; - - if ( !aas ) { - // no aas, so just take the straight line distance - delta = end.ToVec2() - start.ToVec2(); - dist = delta.LengthFast(); - - if ( ai_debugMove.GetBool() ) { - gameRenderWorld->DebugLine( colorBlue, start, end, gameLocal.msec, false ); - gameRenderWorld->DrawText( va( "%d", ( int )dist ), ( start + end ) * 0.5f, 0.1f, colorWhite, gameLocal.GetLocalPlayer()->viewAngles.ToMat3() ); - } - - return dist; - } - - fromArea = PointReachableAreaNum( start ); - toArea = PointReachableAreaNum( end ); - - if ( !fromArea || !toArea ) { - // can't seem to get there - return -1; - } - - if ( fromArea == toArea ) { - // same area, so just take the straight line distance - delta = end.ToVec2() - start.ToVec2(); - dist = delta.LengthFast(); - - if ( ai_debugMove.GetBool() ) { - gameRenderWorld->DebugLine( colorBlue, start, end, gameLocal.msec, false ); - gameRenderWorld->DrawText( va( "%d", ( int )dist ), ( start + end ) * 0.5f, 0.1f, colorWhite, gameLocal.GetLocalPlayer()->viewAngles.ToMat3() ); - } - - return dist; - } - - idReachability *reach; - int travelTime; - if ( !aas->RouteToGoalArea( fromArea, start, toArea, travelFlags, travelTime, &reach ) ) { - return -1; - } - - if ( ai_debugMove.GetBool() ) { - if ( move.moveType == MOVETYPE_FLY ) { - aas->ShowFlyPath( start, toArea, end ); - } else { - aas->ShowWalkPath( start, toArea, end ); - } - } - - return travelTime; -} - -/* -===================== -idAI::StopMove -===================== -*/ -void idAI::StopMove( moveStatus_t status ) { - AI_MOVE_DONE = true; - AI_FORWARD = false; - move.moveCommand = MOVE_NONE; - move.moveStatus = status; - move.toAreaNum = 0; - move.goalEntity = NULL; - move.moveDest = physicsObj.GetOrigin(); - AI_DEST_UNREACHABLE = false; - AI_OBSTACLE_IN_PATH = false; - AI_BLOCKED = false; - move.startTime = gameLocal.time; - move.duration = 0; - move.range = 0.0f; - move.speed = 0.0f; - move.anim = 0; - move.moveDir.Zero(); - move.lastMoveOrigin.Zero(); - move.lastMoveTime = gameLocal.time; -} - -/* -===================== -idAI::FaceEnemy - -Continually face the enemy's last known position. MoveDone is always true in this case. -===================== -*/ -bool idAI::FaceEnemy( void ) { - idActor *enemyEnt = enemy.GetEntity(); - if ( !enemyEnt ) { - StopMove( MOVE_STATUS_DEST_NOT_FOUND ); - return false; - } - - TurnToward( lastVisibleEnemyPos ); - move.goalEntity = enemyEnt; - move.moveDest = physicsObj.GetOrigin(); - move.moveCommand = MOVE_FACE_ENEMY; - move.moveStatus = MOVE_STATUS_WAITING; - move.startTime = gameLocal.time; - move.speed = 0.0f; - AI_MOVE_DONE = true; - AI_FORWARD = false; - AI_DEST_UNREACHABLE = false; - - return true; -} - -/* -===================== -idAI::FaceEntity - -Continually face the entity position. MoveDone is always true in this case. -===================== -*/ -bool idAI::FaceEntity( idEntity *ent ) { - if ( !ent ) { - StopMove( MOVE_STATUS_DEST_NOT_FOUND ); - return false; - } - - idVec3 entityOrg = ent->GetPhysics()->GetOrigin(); - TurnToward( entityOrg ); - move.goalEntity = ent; - move.moveDest = physicsObj.GetOrigin(); - move.moveCommand = MOVE_FACE_ENTITY; - move.moveStatus = MOVE_STATUS_WAITING; - move.startTime = gameLocal.time; - move.speed = 0.0f; - AI_MOVE_DONE = true; - AI_FORWARD = false; - AI_DEST_UNREACHABLE = false; - - return true; -} - -/* -===================== -idAI::DirectMoveToPosition -===================== -*/ -bool idAI::DirectMoveToPosition( const idVec3 &pos ) { - if ( ReachedPos( pos, move.moveCommand ) ) { - StopMove( MOVE_STATUS_DONE ); - return true; - } - - move.moveDest = pos; - move.goalEntity = NULL; - move.moveCommand = MOVE_TO_POSITION_DIRECT; - move.moveStatus = MOVE_STATUS_MOVING; - move.startTime = gameLocal.time; - move.speed = fly_speed; - AI_MOVE_DONE = false; - AI_DEST_UNREACHABLE = false; - AI_FORWARD = true; - - if ( move.moveType == MOVETYPE_FLY ) { - idVec3 dir = pos - physicsObj.GetOrigin(); - dir.Normalize(); - dir *= fly_speed; - physicsObj.SetLinearVelocity( dir ); - } - - return true; -} - -/* -===================== -idAI::MoveToEnemyHeight -===================== -*/ -bool idAI::MoveToEnemyHeight( void ) { - idActor *enemyEnt = enemy.GetEntity(); - - if ( !enemyEnt || ( move.moveType != MOVETYPE_FLY ) ) { - StopMove( MOVE_STATUS_DEST_NOT_FOUND ); - return false; - } - - move.moveDest.z = lastVisibleEnemyPos.z + enemyEnt->EyeOffset().z + fly_offset; - move.goalEntity = enemyEnt; - move.moveCommand = MOVE_TO_ENEMYHEIGHT; - move.moveStatus = MOVE_STATUS_MOVING; - move.startTime = gameLocal.time; - move.speed = 0.0f; - AI_MOVE_DONE = false; - AI_DEST_UNREACHABLE = false; - AI_FORWARD = false; - - return true; -} - -/* -===================== -idAI::MoveToEnemy -===================== -*/ -bool idAI::MoveToEnemy( void ) { - int areaNum; - aasPath_t path; - idActor *enemyEnt = enemy.GetEntity(); - - if ( !enemyEnt ) { - StopMove( MOVE_STATUS_DEST_NOT_FOUND ); - return false; - } - - if ( ReachedPos( lastVisibleReachableEnemyPos, MOVE_TO_ENEMY ) ) { - if ( !ReachedPos( lastVisibleEnemyPos, MOVE_TO_ENEMY ) || !AI_ENEMY_VISIBLE ) { - StopMove( MOVE_STATUS_DEST_UNREACHABLE ); - AI_DEST_UNREACHABLE = true; - return false; - } - StopMove( MOVE_STATUS_DONE ); - return true; - } - - idVec3 pos = lastVisibleReachableEnemyPos; - - move.toAreaNum = 0; - if ( aas ) { - move.toAreaNum = PointReachableAreaNum( pos ); - aas->PushPointIntoAreaNum( move.toAreaNum, pos ); - - areaNum = PointReachableAreaNum( physicsObj.GetOrigin() ); - if ( !PathToGoal( path, areaNum, physicsObj.GetOrigin(), move.toAreaNum, pos ) ) { - AI_DEST_UNREACHABLE = true; - return false; - } - } - - if ( !move.toAreaNum ) { - // if only trying to update the enemy position - if ( move.moveCommand == MOVE_TO_ENEMY ) { - if ( !aas ) { - // keep the move destination up to date for wandering - move.moveDest = pos; - } - return false; - } - - if ( !NewWanderDir( pos ) ) { - StopMove( MOVE_STATUS_DEST_UNREACHABLE ); - AI_DEST_UNREACHABLE = true; - return false; - } - } - - if ( move.moveCommand != MOVE_TO_ENEMY ) { - move.moveCommand = MOVE_TO_ENEMY; - move.startTime = gameLocal.time; - } - - move.moveDest = pos; - move.goalEntity = enemyEnt; - move.speed = fly_speed; - move.moveStatus = MOVE_STATUS_MOVING; - AI_MOVE_DONE = false; - AI_DEST_UNREACHABLE = false; - AI_FORWARD = true; - - return true; -} - -/* -===================== -idAI::MoveToEntity -===================== -*/ -bool idAI::MoveToEntity( idEntity *ent ) { - int areaNum; - aasPath_t path; - idVec3 pos; - - if ( !ent ) { - StopMove( MOVE_STATUS_DEST_NOT_FOUND ); - return false; - } - - pos = ent->GetPhysics()->GetOrigin(); - if ( ( move.moveType != MOVETYPE_FLY ) && ( ( move.moveCommand != MOVE_TO_ENTITY ) || ( move.goalEntityOrigin != pos ) ) ) { - ent->GetFloorPos( 64.0f, pos ); - } - - if ( ReachedPos( pos, MOVE_TO_ENTITY ) ) { - StopMove( MOVE_STATUS_DONE ); - return true; - } - - move.toAreaNum = 0; - if ( aas ) { - move.toAreaNum = PointReachableAreaNum( pos ); - aas->PushPointIntoAreaNum( move.toAreaNum, pos ); - - areaNum = PointReachableAreaNum( physicsObj.GetOrigin() ); - if ( !PathToGoal( path, areaNum, physicsObj.GetOrigin(), move.toAreaNum, pos ) ) { - AI_DEST_UNREACHABLE = true; - return false; - } - } - - if ( !move.toAreaNum ) { - // if only trying to update the entity position - if ( move.moveCommand == MOVE_TO_ENTITY ) { - if ( !aas ) { - // keep the move destination up to date for wandering - move.moveDest = pos; - } - return false; - } - - if ( !NewWanderDir( pos ) ) { - StopMove( MOVE_STATUS_DEST_UNREACHABLE ); - AI_DEST_UNREACHABLE = true; - return false; - } - } - - if ( ( move.moveCommand != MOVE_TO_ENTITY ) || ( move.goalEntity.GetEntity() != ent ) ) { - move.startTime = gameLocal.time; - move.goalEntity = ent; - move.moveCommand = MOVE_TO_ENTITY; - } - - move.moveDest = pos; - move.goalEntityOrigin = ent->GetPhysics()->GetOrigin(); - move.moveStatus = MOVE_STATUS_MOVING; - move.speed = fly_speed; - AI_MOVE_DONE = false; - AI_DEST_UNREACHABLE = false; - AI_FORWARD = true; - - return true; -} - -/* -===================== -idAI::MoveOutOfRange -===================== -*/ -bool idAI::MoveOutOfRange( idEntity *ent, float range ) { - int areaNum; - aasObstacle_t obstacle; - aasGoal_t goal; - idBounds bounds; - idVec3 pos; - - if ( !aas || !ent ) { - StopMove( MOVE_STATUS_DEST_UNREACHABLE ); - AI_DEST_UNREACHABLE = true; - return false; - } - - const idVec3 &org = physicsObj.GetOrigin(); - areaNum = PointReachableAreaNum( org ); - - // consider the entity the monster is getting close to as an obstacle - obstacle.absBounds = ent->GetPhysics()->GetAbsBounds(); - - if ( ent == enemy.GetEntity() ) { - pos = lastVisibleEnemyPos; - } else { - pos = ent->GetPhysics()->GetOrigin(); - } - - idAASFindAreaOutOfRange findGoal( pos, range ); - if ( !aas->FindNearestGoal( goal, areaNum, org, pos, travelFlags, &obstacle, 1, findGoal ) ) { - StopMove( MOVE_STATUS_DEST_UNREACHABLE ); - AI_DEST_UNREACHABLE = true; - return false; - } - - if ( ReachedPos( goal.origin, move.moveCommand ) ) { - StopMove( MOVE_STATUS_DONE ); - return true; - } - - move.moveDest = goal.origin; - move.toAreaNum = goal.areaNum; - move.goalEntity = ent; - move.moveCommand = MOVE_OUT_OF_RANGE; - move.moveStatus = MOVE_STATUS_MOVING; - move.range = range; - move.speed = fly_speed; - move.startTime = gameLocal.time; - AI_MOVE_DONE = false; - AI_DEST_UNREACHABLE = false; - AI_FORWARD = true; - - return true; -} - -/* -===================== -idAI::MoveToAttackPosition -===================== -*/ -bool idAI::MoveToAttackPosition( idEntity *ent, int attack_anim ) { - int areaNum; - aasObstacle_t obstacle; - aasGoal_t goal; - idBounds bounds; - idVec3 pos; - - if ( !aas || !ent ) { - StopMove( MOVE_STATUS_DEST_UNREACHABLE ); - AI_DEST_UNREACHABLE = true; - return false; - } - - const idVec3 &org = physicsObj.GetOrigin(); - areaNum = PointReachableAreaNum( org ); - - // consider the entity the monster is getting close to as an obstacle - obstacle.absBounds = ent->GetPhysics()->GetAbsBounds(); - - if ( ent == enemy.GetEntity() ) { - pos = lastVisibleEnemyPos; - } else { - pos = ent->GetPhysics()->GetOrigin(); - } - - idAASFindAttackPosition findGoal( this, physicsObj.GetGravityAxis(), ent, pos, missileLaunchOffset[ attack_anim ] ); - if ( !aas->FindNearestGoal( goal, areaNum, org, pos, travelFlags, &obstacle, 1, findGoal ) ) { - StopMove( MOVE_STATUS_DEST_UNREACHABLE ); - AI_DEST_UNREACHABLE = true; - return false; - } - - move.moveDest = goal.origin; - move.toAreaNum = goal.areaNum; - move.goalEntity = ent; - move.moveCommand = MOVE_TO_ATTACK_POSITION; - move.moveStatus = MOVE_STATUS_MOVING; - move.speed = fly_speed; - move.startTime = gameLocal.time; - move.anim = attack_anim; - AI_MOVE_DONE = false; - AI_DEST_UNREACHABLE = false; - AI_FORWARD = true; - - return true; -} - -/* -===================== -idAI::MoveToPosition -===================== -*/ -bool idAI::MoveToPosition( const idVec3 &pos ) { - idVec3 org; - int areaNum; - aasPath_t path; - - if ( ReachedPos( pos, move.moveCommand ) ) { - StopMove( MOVE_STATUS_DONE ); - return true; - } - - org = pos; - move.toAreaNum = 0; - if ( aas ) { - move.toAreaNum = PointReachableAreaNum( org ); - aas->PushPointIntoAreaNum( move.toAreaNum, org ); - - areaNum = PointReachableAreaNum( physicsObj.GetOrigin() ); - if ( !PathToGoal( path, areaNum, physicsObj.GetOrigin(), move.toAreaNum, org ) ) { - StopMove( MOVE_STATUS_DEST_UNREACHABLE ); - AI_DEST_UNREACHABLE = true; - return false; - } - } - - if ( !move.toAreaNum && !NewWanderDir( org ) ) { - StopMove( MOVE_STATUS_DEST_UNREACHABLE ); - AI_DEST_UNREACHABLE = true; - return false; - } - - move.moveDest = org; - move.goalEntity = NULL; - move.moveCommand = MOVE_TO_POSITION; - move.moveStatus = MOVE_STATUS_MOVING; - move.startTime = gameLocal.time; - move.speed = fly_speed; - AI_MOVE_DONE = false; - AI_DEST_UNREACHABLE = false; - AI_FORWARD = true; - - return true; -} - -/* -===================== -idAI::MoveToCover -===================== -*/ -bool idAI::MoveToCover( idEntity *entity, const idVec3 &hideFromPos ) { - int areaNum; - aasObstacle_t obstacle; - aasGoal_t hideGoal; - idBounds bounds; - - if ( !aas || !entity ) { - StopMove( MOVE_STATUS_DEST_UNREACHABLE ); - AI_DEST_UNREACHABLE = true; - return false; - } - - const idVec3 &org = physicsObj.GetOrigin(); - areaNum = PointReachableAreaNum( org ); - - // consider the entity the monster tries to hide from as an obstacle - obstacle.absBounds = entity->GetPhysics()->GetAbsBounds(); - - idAASFindCover findCover( hideFromPos ); - if ( !aas->FindNearestGoal( hideGoal, areaNum, org, hideFromPos, travelFlags, &obstacle, 1, findCover ) ) { - StopMove( MOVE_STATUS_DEST_UNREACHABLE ); - AI_DEST_UNREACHABLE = true; - return false; - } - - if ( ReachedPos( hideGoal.origin, move.moveCommand ) ) { - StopMove( MOVE_STATUS_DONE ); - return true; - } - - move.moveDest = hideGoal.origin; - move.toAreaNum = hideGoal.areaNum; - move.goalEntity = entity; - move.moveCommand = MOVE_TO_COVER; - move.moveStatus = MOVE_STATUS_MOVING; - move.startTime = gameLocal.time; - move.speed = fly_speed; - AI_MOVE_DONE = false; - AI_DEST_UNREACHABLE = false; - AI_FORWARD = true; - - return true; -} - -/* -===================== -idAI::SlideToPosition -===================== -*/ -bool idAI::SlideToPosition( const idVec3 &pos, float time ) { - StopMove( MOVE_STATUS_DONE ); - - move.moveDest = pos; - move.goalEntity = NULL; - move.moveCommand = MOVE_SLIDE_TO_POSITION; - move.moveStatus = MOVE_STATUS_MOVING; - move.startTime = gameLocal.time; - move.duration = idPhysics::SnapTimeToPhysicsFrame( SEC2MS( time ) ); - AI_MOVE_DONE = false; - AI_DEST_UNREACHABLE = false; - AI_FORWARD = false; - - if ( move.duration > 0 ) { - move.moveDir = ( pos - physicsObj.GetOrigin() ) / MS2SEC( move.duration ); - if ( move.moveType != MOVETYPE_FLY ) { - move.moveDir.z = 0.0f; - } - move.speed = move.moveDir.LengthFast(); - } - - return true; -} - -/* -===================== -idAI::WanderAround -===================== -*/ -bool idAI::WanderAround( void ) { - StopMove( MOVE_STATUS_DONE ); - - move.moveDest = physicsObj.GetOrigin() + viewAxis[ 0 ] * physicsObj.GetGravityAxis() * 256.0f; - if ( !NewWanderDir( move.moveDest ) ) { - StopMove( MOVE_STATUS_DEST_UNREACHABLE ); - AI_DEST_UNREACHABLE = true; - return false; - } - - move.moveCommand = MOVE_WANDER; - move.moveStatus = MOVE_STATUS_MOVING; - move.startTime = gameLocal.time; - move.speed = fly_speed; - AI_MOVE_DONE = false; - AI_FORWARD = true; - - return true; -} - -/* -===================== -idAI::MoveDone -===================== -*/ -bool idAI::MoveDone( void ) const { - return ( move.moveCommand == MOVE_NONE ); -} - -/* -================ -idAI::StepDirection -================ -*/ -bool idAI::StepDirection( float dir ) { - predictedPath_t path; - idVec3 org; - - move.wanderYaw = dir; - move.moveDir = idAngles( 0, move.wanderYaw, 0 ).ToForward(); - - org = physicsObj.GetOrigin(); - - idAI::PredictPath( this, aas, org, move.moveDir * 48.0f, 1000, 1000, ( move.moveType == MOVETYPE_FLY ) ? SE_BLOCKED : ( SE_ENTER_OBSTACLE | SE_BLOCKED | SE_ENTER_LEDGE_AREA ), path ); - - if ( path.blockingEntity && ( ( move.moveCommand == MOVE_TO_ENEMY ) || ( move.moveCommand == MOVE_TO_ENTITY ) ) && ( path.blockingEntity == move.goalEntity.GetEntity() ) ) { - // don't report being blocked if we ran into our goal entity - return true; - } - - if ( ( move.moveType == MOVETYPE_FLY ) && ( path.endEvent == SE_BLOCKED ) ) { - float z; - - move.moveDir = path.endVelocity * 1.0f / 48.0f; - - // trace down to the floor and see if we can go forward - idAI::PredictPath( this, aas, org, idVec3( 0.0f, 0.0f, -1024.0f ), 1000, 1000, SE_BLOCKED, path ); - - idVec3 floorPos = path.endPos; - idAI::PredictPath( this, aas, floorPos, move.moveDir * 48.0f, 1000, 1000, SE_BLOCKED, path ); - if ( !path.endEvent ) { - move.moveDir.z = -1.0f; - return true; - } - - // trace up to see if we can go over something and go forward - idAI::PredictPath( this, aas, org, idVec3( 0.0f, 0.0f, 256.0f ), 1000, 1000, SE_BLOCKED, path ); - - idVec3 ceilingPos = path.endPos; - - for( z = org.z; z <= ceilingPos.z + 64.0f; z += 64.0f ) { - idVec3 start; - if ( z <= ceilingPos.z ) { - start.x = org.x; - start.y = org.y; - start.z = z; - } else { - start = ceilingPos; - } - idAI::PredictPath( this, aas, start, move.moveDir * 48.0f, 1000, 1000, SE_BLOCKED, path ); - if ( !path.endEvent ) { - move.moveDir.z = 1.0f; - return true; - } - } - return false; - } - - return ( path.endEvent == 0 ); -} - -/* -================ -idAI::NewWanderDir -================ -*/ -bool idAI::NewWanderDir( const idVec3 &dest ) { - float deltax, deltay; - float d[ 3 ]; - float tdir, olddir, turnaround; - - move.nextWanderTime = gameLocal.time + ( gameLocal.random.RandomFloat() * 500 + 500 ); - - olddir = idMath::AngleNormalize360( ( int )( current_yaw / 45 ) * 45 ); - turnaround = idMath::AngleNormalize360( olddir - 180 ); - - idVec3 org = physicsObj.GetOrigin(); - deltax = dest.x - org.x; - deltay = dest.y - org.y; - if ( deltax > 10 ) { - d[ 1 ]= 0; - } else if ( deltax < -10 ) { - d[ 1 ] = 180; - } else { - d[ 1 ] = DI_NODIR; - } - - if ( deltay < -10 ) { - d[ 2 ] = 270; - } else if ( deltay > 10 ) { - d[ 2 ] = 90; - } else { - d[ 2 ] = DI_NODIR; - } - - // try direct route - if ( d[ 1 ] != DI_NODIR && d[ 2 ] != DI_NODIR ) { - if ( d[ 1 ] == 0 ) { - tdir = d[ 2 ] == 90 ? 45 : 315; - } else { - tdir = d[ 2 ] == 90 ? 135 : 215; - } - - if ( tdir != turnaround && StepDirection( tdir ) ) { - return true; - } - } - - // try other directions - if ( ( gameLocal.random.RandomInt() & 1 ) || idMath::Fabs( deltay ) > idMath::Fabs( deltax ) ) { - tdir = d[ 1 ]; - d[ 1 ] = d[ 2 ]; - d[ 2 ] = tdir; - } - - if ( d[ 1 ] != DI_NODIR && d[ 1 ] != turnaround && StepDirection( d[1] ) ) { - return true; - } - - if ( d[ 2 ] != DI_NODIR && d[ 2 ] != turnaround && StepDirection( d[ 2 ] ) ) { - return true; - } - - // there is no direct path to the player, so pick another direction - if ( olddir != DI_NODIR && StepDirection( olddir ) ) { - return true; - } - - // randomly determine direction of search - if ( gameLocal.random.RandomInt() & 1 ) { - for( tdir = 0; tdir <= 315; tdir += 45 ) { - if ( tdir != turnaround && StepDirection( tdir ) ) { - return true; - } - } - } else { - for ( tdir = 315; tdir >= 0; tdir -= 45 ) { - if ( tdir != turnaround && StepDirection( tdir ) ) { - return true; - } - } - } - - if ( turnaround != DI_NODIR && StepDirection( turnaround ) ) { - return true; - } - - // can't move - StopMove( MOVE_STATUS_DEST_UNREACHABLE ); - return false; -} - -/* -===================== -idAI::GetMovePos -===================== -*/ -bool idAI::GetMovePos( idVec3 &seekPos ) { - int areaNum; - aasPath_t path; - bool result; - idVec3 org; - - org = physicsObj.GetOrigin(); - seekPos = org; - - switch( move.moveCommand ) { - case MOVE_NONE : - seekPos = move.moveDest; - return false; - break; - - case MOVE_FACE_ENEMY : - case MOVE_FACE_ENTITY : - seekPos = move.moveDest; - return false; - break; - - case MOVE_TO_POSITION_DIRECT : - seekPos = move.moveDest; - if ( ReachedPos( move.moveDest, move.moveCommand ) ) { - StopMove( MOVE_STATUS_DONE ); - } - return false; - break; - - case MOVE_SLIDE_TO_POSITION : - seekPos = org; - return false; - break; - } - - if ( move.moveCommand == MOVE_TO_ENTITY ) { - MoveToEntity( move.goalEntity.GetEntity() ); - } - - move.moveStatus = MOVE_STATUS_MOVING; - result = false; - if ( gameLocal.time > move.blockTime ) { - if ( move.moveCommand == MOVE_WANDER ) { - move.moveDest = org + viewAxis[ 0 ] * physicsObj.GetGravityAxis() * 256.0f; - } else { - if ( ReachedPos( move.moveDest, move.moveCommand ) ) { - StopMove( MOVE_STATUS_DONE ); - seekPos = org; - return false; - } - } - - if ( aas && move.toAreaNum ) { - areaNum = PointReachableAreaNum( org ); - if ( PathToGoal( path, areaNum, org, move.toAreaNum, move.moveDest ) ) { - seekPos = path.moveGoal; - result = true; - move.nextWanderTime = 0; - } else { - AI_DEST_UNREACHABLE = true; - } - } - } - - if ( !result ) { - // wander around - if ( ( gameLocal.time > move.nextWanderTime ) || !StepDirection( move.wanderYaw ) ) { - result = NewWanderDir( move.moveDest ); - if ( !result ) { - StopMove( MOVE_STATUS_DEST_UNREACHABLE ); - AI_DEST_UNREACHABLE = true; - seekPos = org; - return false; - } - } else { - result = true; - } - - seekPos = org + move.moveDir * 2048.0f; - if ( ai_debugMove.GetBool() ) { - gameRenderWorld->DebugLine( colorYellow, org, seekPos, gameLocal.msec, true ); - } - } else { - AI_DEST_UNREACHABLE = false; - } - - if ( result && ( ai_debugMove.GetBool() ) ) { - gameRenderWorld->DebugLine( colorCyan, physicsObj.GetOrigin(), seekPos ); - } - - return result; -} - -/* -===================== -idAI::EntityCanSeePos -===================== -*/ -bool idAI::EntityCanSeePos( idActor *actor, const idVec3 &actorOrigin, const idVec3 &pos ) { - idVec3 eye, point; - trace_t results; - pvsHandle_t handle; - - handle = gameLocal.pvs.SetupCurrentPVS( actor->GetPVSAreas(), actor->GetNumPVSAreas() ); - - if ( !gameLocal.pvs.InCurrentPVS( handle, GetPVSAreas(), GetNumPVSAreas() ) ) { - gameLocal.pvs.FreeCurrentPVS( handle ); - return false; - } - - gameLocal.pvs.FreeCurrentPVS( handle ); - - eye = actorOrigin + actor->EyeOffset(); - - point = pos; - point[2] += 1.0f; - - physicsObj.DisableClip(); - - gameLocal.clip.TracePoint( results, eye, point, MASK_SOLID, actor ); - if ( results.fraction >= 1.0f || ( gameLocal.GetTraceEntity( results ) == this ) ) { - physicsObj.EnableClip(); - return true; - } - - const idBounds &bounds = physicsObj.GetBounds(); - point[2] += bounds[1][2] - bounds[0][2]; - - gameLocal.clip.TracePoint( results, eye, point, MASK_SOLID, actor ); - physicsObj.EnableClip(); - if ( results.fraction >= 1.0f || ( gameLocal.GetTraceEntity( results ) == this ) ) { - return true; - } - return false; -} - -/* -===================== -idAI::BlockedFailSafe -===================== -*/ -void idAI::BlockedFailSafe( void ) { - if ( !ai_blockedFailSafe.GetBool() || blockedRadius < 0.0f ) { - return; - } - if ( !physicsObj.OnGround() || enemy.GetEntity() == NULL || - ( physicsObj.GetOrigin() - move.lastMoveOrigin ).LengthSqr() > Square( blockedRadius ) ) { - move.lastMoveOrigin = physicsObj.GetOrigin(); - move.lastMoveTime = gameLocal.time; - } - if ( move.lastMoveTime < gameLocal.time - blockedMoveTime ) { - if ( lastAttackTime < gameLocal.time - blockedAttackTime ) { - AI_BLOCKED = true; - move.lastMoveTime = gameLocal.time; - } - } -} - -/*********************************************************************** - - turning - -***********************************************************************/ - -/* -===================== -idAI::Turn -===================== -*/ -void idAI::Turn( void ) { - float diff; - float diff2; - float turnAmount; - animFlags_t animflags; - - if ( !turnRate ) { - return; - } - - // check if the animator has marker this anim as non-turning - if ( !legsAnim.Disabled() && !legsAnim.AnimDone( 0 ) ) { - animflags = legsAnim.GetAnimFlags(); - } else { - animflags = torsoAnim.GetAnimFlags(); - } - if ( animflags.ai_no_turn ) { - return; - } - - if ( anim_turn_angles && animflags.anim_turn ) { - idMat3 rotateAxis; - - // set the blend between no turn and full turn - float frac = anim_turn_amount / anim_turn_angles; - animator.CurrentAnim( ANIMCHANNEL_LEGS )->SetSyncedAnimWeight( 0, 1.0f - frac ); - animator.CurrentAnim( ANIMCHANNEL_LEGS )->SetSyncedAnimWeight( 1, frac ); - animator.CurrentAnim( ANIMCHANNEL_TORSO )->SetSyncedAnimWeight( 0, 1.0f - frac ); - animator.CurrentAnim( ANIMCHANNEL_TORSO )->SetSyncedAnimWeight( 1, frac ); - - // get the total rotation from the start of the anim - animator.GetDeltaRotation( 0, gameLocal.time, rotateAxis ); - current_yaw = idMath::AngleNormalize180( anim_turn_yaw + rotateAxis[ 0 ].ToYaw() ); - } else { - diff = idMath::AngleNormalize180( ideal_yaw - current_yaw ); - turnVel += AI_TURN_SCALE * diff * MS2SEC( gameLocal.msec ); - if ( turnVel > turnRate ) { - turnVel = turnRate; - } else if ( turnVel < -turnRate ) { - turnVel = -turnRate; - } - turnAmount = turnVel * MS2SEC( gameLocal.msec ); - if ( ( diff >= 0.0f ) && ( turnAmount >= diff ) ) { - turnVel = diff / MS2SEC( gameLocal.msec ); - turnAmount = diff; - } else if ( ( diff <= 0.0f ) && ( turnAmount <= diff ) ) { - turnVel = diff / MS2SEC( gameLocal.msec ); - turnAmount = diff; - } - current_yaw += turnAmount; - current_yaw = idMath::AngleNormalize180( current_yaw ); - diff2 = idMath::AngleNormalize180( ideal_yaw - current_yaw ); - if ( idMath::Fabs( diff2 ) < 0.1f ) { - current_yaw = ideal_yaw; - } - } - - viewAxis = idAngles( 0, current_yaw, 0 ).ToMat3(); - - if ( ai_debugMove.GetBool() ) { - const idVec3 &org = physicsObj.GetOrigin(); - gameRenderWorld->DebugLine( colorRed, org, org + idAngles( 0, ideal_yaw, 0 ).ToForward() * 64, gameLocal.msec ); - gameRenderWorld->DebugLine( colorGreen, org, org + idAngles( 0, current_yaw, 0 ).ToForward() * 48, gameLocal.msec ); - gameRenderWorld->DebugLine( colorYellow, org, org + idAngles( 0, current_yaw + turnVel, 0 ).ToForward() * 32, gameLocal.msec ); - } -} - -/* -===================== -idAI::FacingIdeal -===================== -*/ -bool idAI::FacingIdeal( void ) { - float diff; - - if ( !turnRate ) { - return true; - } - - diff = idMath::AngleNormalize180( current_yaw - ideal_yaw ); - if ( idMath::Fabs( diff ) < 0.01f ) { - // force it to be exact - current_yaw = ideal_yaw; - return true; - } - - return false; -} - -/* -===================== -idAI::TurnToward -===================== -*/ -bool idAI::TurnToward( float yaw ) { - ideal_yaw = idMath::AngleNormalize180( yaw ); - bool result = FacingIdeal(); - return result; -} - -/* -===================== -idAI::TurnToward -===================== -*/ -bool idAI::TurnToward( const idVec3 &pos ) { - idVec3 dir; - idVec3 local_dir; - float lengthSqr; - - dir = pos - physicsObj.GetOrigin(); - physicsObj.GetGravityAxis().ProjectVector( dir, local_dir ); - local_dir.z = 0.0f; - lengthSqr = local_dir.LengthSqr(); - if ( lengthSqr > Square( 2.0f ) || ( lengthSqr > Square( 0.1f ) && enemy.GetEntity() == NULL ) ) { - ideal_yaw = idMath::AngleNormalize180( local_dir.ToYaw() ); - } - - bool result = FacingIdeal(); - return result; -} - -/*********************************************************************** - - Movement - -***********************************************************************/ - -/* -================ -idAI::ApplyImpulse -================ -*/ -void idAI::ApplyImpulse( idEntity *ent, int id, const idVec3 &point, const idVec3 &impulse ) { - // FIXME: Jim take a look at this and see if this is a reasonable thing to do - // instead of a spawnArg flag.. Sabaoth is the only slide monster ( and should be the only one for D3 ) - // and we don't want him taking physics impulses as it can knock him off the path - if ( move.moveType != MOVETYPE_STATIC && move.moveType != MOVETYPE_SLIDE ) { - idActor::ApplyImpulse( ent, id, point, impulse ); - } -} - -/* -===================== -idAI::GetMoveDelta -===================== -*/ -void idAI::GetMoveDelta( const idMat3 &oldaxis, const idMat3 &axis, idVec3 &delta ) { - idVec3 oldModelOrigin; - idVec3 modelOrigin; - - animator.GetDelta( gameLocal.time - gameLocal.msec, gameLocal.time, delta ); - delta = axis * delta; - - if ( modelOffset != vec3_zero ) { - // the pivot of the monster's model is around its origin, and not around the bounding - // box's origin, so we have to compensate for this when the model is offset so that - // the monster still appears to rotate around it's origin. - oldModelOrigin = modelOffset * oldaxis; - modelOrigin = modelOffset * axis; - delta += oldModelOrigin - modelOrigin; - } - - delta *= physicsObj.GetGravityAxis(); -} - -/* -===================== -idAI::CheckObstacleAvoidance -===================== -*/ -void idAI::CheckObstacleAvoidance( const idVec3 &goalPos, idVec3 &newPos ) { - idEntity *obstacle; - obstaclePath_t path; - idVec3 dir; - float dist; - bool foundPath; - - if ( ignore_obstacles ) { - newPos = goalPos; - move.obstacle = NULL; - return; - } - - const idVec3 &origin = physicsObj.GetOrigin(); - - obstacle = NULL; - AI_OBSTACLE_IN_PATH = false; - foundPath = FindPathAroundObstacles( &physicsObj, aas, enemy.GetEntity(), origin, goalPos, path ); - if ( ai_showObstacleAvoidance.GetBool() ) { - gameRenderWorld->DebugLine( colorBlue, goalPos + idVec3( 1.0f, 1.0f, 0.0f ), goalPos + idVec3( 1.0f, 1.0f, 64.0f ), gameLocal.msec ); - gameRenderWorld->DebugLine( foundPath ? colorYellow : colorRed, path.seekPos, path.seekPos + idVec3( 0.0f, 0.0f, 64.0f ), gameLocal.msec ); - } - - if ( !foundPath ) { - // couldn't get around obstacles - if ( path.firstObstacle ) { - AI_OBSTACLE_IN_PATH = true; - if ( physicsObj.GetAbsBounds().Expand( 2.0f ).IntersectsBounds( path.firstObstacle->GetPhysics()->GetAbsBounds() ) ) { - obstacle = path.firstObstacle; - } - } else if ( path.startPosObstacle ) { - AI_OBSTACLE_IN_PATH = true; - if ( physicsObj.GetAbsBounds().Expand( 2.0f ).IntersectsBounds( path.startPosObstacle->GetPhysics()->GetAbsBounds() ) ) { - obstacle = path.startPosObstacle; - } - } else { - // Blocked by wall - move.moveStatus = MOVE_STATUS_BLOCKED_BY_WALL; - } -#if 0 - } else if ( path.startPosObstacle ) { - // check if we're past where the our origin was pushed out of the obstacle - dir = goalPos - origin; - dir.Normalize(); - dist = ( path.seekPos - origin ) * dir; - if ( dist < 1.0f ) { - AI_OBSTACLE_IN_PATH = true; - obstacle = path.startPosObstacle; - } -#endif - } else if ( path.seekPosObstacle ) { - // if the AI is very close to the path.seekPos already and path.seekPosObstacle != NULL - // then we want to push the path.seekPosObstacle entity out of the way - AI_OBSTACLE_IN_PATH = true; - - // check if we're past where the goalPos was pushed out of the obstacle - dir = goalPos - origin; - dir.Normalize(); - dist = ( path.seekPos - origin ) * dir; - if ( dist < 1.0f ) { - obstacle = path.seekPosObstacle; - } - } - - // if we had an obstacle, set our move status based on the type, and kick it out of the way if it's a moveable - if ( obstacle ) { - if ( obstacle->IsType( idActor::Type ) ) { - // monsters aren't kickable - if ( obstacle == enemy.GetEntity() ) { - move.moveStatus = MOVE_STATUS_BLOCKED_BY_ENEMY; - } else { - move.moveStatus = MOVE_STATUS_BLOCKED_BY_MONSTER; - } - } else { - // try kicking the object out of the way - move.moveStatus = MOVE_STATUS_BLOCKED_BY_OBJECT; - } - newPos = obstacle->GetPhysics()->GetOrigin(); - //newPos = path.seekPos; - move.obstacle = obstacle; - } else { - newPos = path.seekPos; - move.obstacle = NULL; - } -} - -/* -===================== -idAI::DeadMove -===================== -*/ -void idAI::DeadMove( void ) { - idVec3 delta; - - GetMoveDelta( viewAxis, viewAxis, delta ); - physicsObj.SetDelta( delta ); - - RunPhysics(); - - AI_ONGROUND = physicsObj.OnGround(); -} - -/* -===================== -idAI::AnimMove -===================== -*/ -void idAI::AnimMove( void ) { - idVec3 goalPos; - idVec3 delta; - idVec3 goalDelta; - float goalDist; - idVec3 newDest; - - idVec3 oldorigin = physicsObj.GetOrigin(); - idMat3 oldaxis = viewAxis; - - AI_BLOCKED = false; - - if ( move.moveCommand < NUM_NONMOVING_COMMANDS ){ - move.lastMoveOrigin.Zero(); - move.lastMoveTime = gameLocal.time; - } - - move.obstacle = NULL; - if ( ( move.moveCommand == MOVE_FACE_ENEMY ) && enemy.GetEntity() ) { - TurnToward( lastVisibleEnemyPos ); - goalPos = oldorigin; - } else if ( ( move.moveCommand == MOVE_FACE_ENTITY ) && move.goalEntity.GetEntity() ) { - TurnToward( move.goalEntity.GetEntity()->GetPhysics()->GetOrigin() ); - goalPos = oldorigin; - } else if ( GetMovePos( goalPos ) ) { - if ( move.moveCommand != MOVE_WANDER ) { - CheckObstacleAvoidance( goalPos, newDest ); - TurnToward( newDest ); - } else { - TurnToward( goalPos ); - } - } - - Turn(); - - if ( move.moveCommand == MOVE_SLIDE_TO_POSITION ) { - if ( gameLocal.time < move.startTime + move.duration ) { - goalPos = move.moveDest - move.moveDir * MS2SEC( move.startTime + move.duration - gameLocal.time ); - delta = goalPos - oldorigin; - delta.z = 0.0f; - } else { - delta = move.moveDest - oldorigin; - delta.z = 0.0f; - StopMove( MOVE_STATUS_DONE ); - } - } else if ( allowMove ) { - GetMoveDelta( oldaxis, viewAxis, delta ); - } else { - delta.Zero(); - } - - if ( move.moveCommand == MOVE_TO_POSITION ) { - goalDelta = move.moveDest - oldorigin; - goalDist = goalDelta.LengthFast(); - if ( goalDist < delta.LengthFast() ) { - delta = goalDelta; - } - } - -#ifdef _D3XP - physicsObj.UseFlyMove( false ); -#endif - physicsObj.SetDelta( delta ); - physicsObj.ForceDeltaMove( disableGravity ); - - RunPhysics(); - - if ( ai_debugMove.GetBool() ) { - gameRenderWorld->DebugLine( colorCyan, oldorigin, physicsObj.GetOrigin(), 5000 ); - } - - if ( !af_push_moveables && attack.Length() && TestMelee() ) { - DirectDamage( attack, enemy.GetEntity() ); - } else { - idEntity *blockEnt = physicsObj.GetSlideMoveEntity(); - if ( blockEnt && blockEnt->IsType( idMoveable::Type ) && blockEnt->GetPhysics()->IsPushable() ) { - KickObstacles( viewAxis[ 0 ], kickForce, blockEnt ); - } - } - - BlockedFailSafe(); - - AI_ONGROUND = physicsObj.OnGround(); - - idVec3 org = physicsObj.GetOrigin(); - if ( oldorigin != org ) { - TouchTriggers(); - } - - if ( ai_debugMove.GetBool() ) { - gameRenderWorld->DebugBounds( colorMagenta, physicsObj.GetBounds(), org, gameLocal.msec ); - gameRenderWorld->DebugBounds( colorMagenta, physicsObj.GetBounds(), move.moveDest, gameLocal.msec ); - gameRenderWorld->DebugLine( colorYellow, org + EyeOffset(), org + EyeOffset() + viewAxis[ 0 ] * physicsObj.GetGravityAxis() * 16.0f, gameLocal.msec, true ); - DrawRoute(); - } -} - -/* -===================== -Seek -===================== -*/ -idVec3 Seek( idVec3 &vel, const idVec3 &org, const idVec3 &goal, float prediction ) { - idVec3 predictedPos; - idVec3 goalDelta; - idVec3 seekVel; - - // predict our position - predictedPos = org + vel * prediction; - goalDelta = goal - predictedPos; - seekVel = goalDelta * MS2SEC( gameLocal.msec ); - - return seekVel; -} - -/* -===================== -idAI::SlideMove -===================== -*/ -void idAI::SlideMove( void ) { - idVec3 goalPos; - idVec3 delta; - idVec3 goalDelta; - float goalDist; - idVec3 newDest; - - idVec3 oldorigin = physicsObj.GetOrigin(); - - AI_BLOCKED = false; - - if ( move.moveCommand < NUM_NONMOVING_COMMANDS ){ - move.lastMoveOrigin.Zero(); - move.lastMoveTime = gameLocal.time; - } - - move.obstacle = NULL; - if ( ( move.moveCommand == MOVE_FACE_ENEMY ) && enemy.GetEntity() ) { - TurnToward( lastVisibleEnemyPos ); - goalPos = move.moveDest; - } else if ( ( move.moveCommand == MOVE_FACE_ENTITY ) && move.goalEntity.GetEntity() ) { - TurnToward( move.goalEntity.GetEntity()->GetPhysics()->GetOrigin() ); - goalPos = move.moveDest; - } else if ( GetMovePos( goalPos ) ) { - CheckObstacleAvoidance( goalPos, newDest ); - TurnToward( newDest ); - goalPos = newDest; - } - - if ( move.moveCommand == MOVE_SLIDE_TO_POSITION ) { - if ( gameLocal.time < move.startTime + move.duration ) { - goalPos = move.moveDest - move.moveDir * MS2SEC( move.startTime + move.duration - gameLocal.time ); - } else { - goalPos = move.moveDest; - StopMove( MOVE_STATUS_DONE ); - } - } - - if ( move.moveCommand == MOVE_TO_POSITION ) { - goalDelta = move.moveDest - oldorigin; - goalDist = goalDelta.LengthFast(); - if ( goalDist < delta.LengthFast() ) { - delta = goalDelta; - } - } - - idVec3 vel = physicsObj.GetLinearVelocity(); - float z = vel.z; - idVec3 predictedPos = oldorigin + vel * AI_SEEK_PREDICTION; - - // seek the goal position - goalDelta = goalPos - predictedPos; - vel -= vel * AI_FLY_DAMPENING * MS2SEC( gameLocal.msec ); - vel += goalDelta * MS2SEC( gameLocal.msec ); - - // cap our speed - vel.Truncate( fly_speed ); - vel.z = z; - physicsObj.SetLinearVelocity( vel ); - physicsObj.UseVelocityMove( true ); - RunPhysics(); - - if ( ( move.moveCommand == MOVE_FACE_ENEMY ) && enemy.GetEntity() ) { - TurnToward( lastVisibleEnemyPos ); - } else if ( ( move.moveCommand == MOVE_FACE_ENTITY ) && move.goalEntity.GetEntity() ) { - TurnToward( move.goalEntity.GetEntity()->GetPhysics()->GetOrigin() ); - } else if ( move.moveCommand != MOVE_NONE ) { - if ( vel.ToVec2().LengthSqr() > 0.1f ) { - TurnToward( vel.ToYaw() ); - } - } - Turn(); - - if ( ai_debugMove.GetBool() ) { - gameRenderWorld->DebugLine( colorCyan, oldorigin, physicsObj.GetOrigin(), 5000 ); - } - - if ( !af_push_moveables && attack.Length() && TestMelee() ) { - DirectDamage( attack, enemy.GetEntity() ); - } else { - idEntity *blockEnt = physicsObj.GetSlideMoveEntity(); - if ( blockEnt && blockEnt->IsType( idMoveable::Type ) && blockEnt->GetPhysics()->IsPushable() ) { - KickObstacles( viewAxis[ 0 ], kickForce, blockEnt ); - } - } - - BlockedFailSafe(); - - AI_ONGROUND = physicsObj.OnGround(); - - idVec3 org = physicsObj.GetOrigin(); - if ( oldorigin != org ) { - TouchTriggers(); - } - - if ( ai_debugMove.GetBool() ) { - gameRenderWorld->DebugBounds( colorMagenta, physicsObj.GetBounds(), org, gameLocal.msec ); - gameRenderWorld->DebugBounds( colorMagenta, physicsObj.GetBounds(), move.moveDest, gameLocal.msec ); - gameRenderWorld->DebugLine( colorYellow, org + EyeOffset(), org + EyeOffset() + viewAxis[ 0 ] * physicsObj.GetGravityAxis() * 16.0f, gameLocal.msec, true ); - DrawRoute(); - } -} - -/* -===================== -idAI::AdjustFlyingAngles -===================== -*/ -void idAI::AdjustFlyingAngles( void ) { - idVec3 vel; - float speed; - float roll; - float pitch; - - vel = physicsObj.GetLinearVelocity(); - - speed = vel.Length(); - if ( speed < 5.0f ) { - roll = 0.0f; - pitch = 0.0f; - } else { - roll = vel * viewAxis[ 1 ] * -fly_roll_scale / fly_speed; - if ( roll > fly_roll_max ) { - roll = fly_roll_max; - } else if ( roll < -fly_roll_max ) { - roll = -fly_roll_max; - } - - pitch = vel * viewAxis[ 2 ] * -fly_pitch_scale / fly_speed; - if ( pitch > fly_pitch_max ) { - pitch = fly_pitch_max; - } else if ( pitch < -fly_pitch_max ) { - pitch = -fly_pitch_max; - } - } - - fly_roll = fly_roll * 0.95f + roll * 0.05f; - fly_pitch = fly_pitch * 0.95f + pitch * 0.05f; - - if ( flyTiltJoint != INVALID_JOINT ) { - animator.SetJointAxis( flyTiltJoint, JOINTMOD_WORLD, idAngles( fly_pitch, 0.0f, fly_roll ).ToMat3() ); - } else { - viewAxis = idAngles( fly_pitch, current_yaw, fly_roll ).ToMat3(); - } -} - -/* -===================== -idAI::AddFlyBob -===================== -*/ -void idAI::AddFlyBob( idVec3 &vel ) { - idVec3 fly_bob_add; - float t; - - if ( fly_bob_strength ) { - t = MS2SEC( gameLocal.time + entityNumber * 497 ); - fly_bob_add = ( viewAxis[ 1 ] * idMath::Sin16( t * fly_bob_horz ) + viewAxis[ 2 ] * idMath::Sin16( t * fly_bob_vert ) ) * fly_bob_strength; - vel += fly_bob_add * MS2SEC( gameLocal.msec ); - if ( ai_debugMove.GetBool() ) { - const idVec3 &origin = physicsObj.GetOrigin(); - gameRenderWorld->DebugArrow( colorOrange, origin, origin + fly_bob_add, 0 ); - } - } -} - -/* -===================== -idAI::AdjustFlyHeight -===================== -*/ -void idAI::AdjustFlyHeight( idVec3 &vel, const idVec3 &goalPos ) { - const idVec3 &origin = physicsObj.GetOrigin(); - predictedPath_t path; - idVec3 end; - idVec3 dest; - trace_t trace; - idActor *enemyEnt; - bool goLower; - - // make sure we're not flying too high to get through doors - goLower = false; - if ( origin.z > goalPos.z ) { - dest = goalPos; - dest.z = origin.z + 128.0f; - idAI::PredictPath( this, aas, goalPos, dest - origin, 1000, 1000, SE_BLOCKED, path ); - if ( path.endPos.z < origin.z ) { - idVec3 addVel = Seek( vel, origin, path.endPos, AI_SEEK_PREDICTION ); - vel.z += addVel.z; - goLower = true; - } - - if ( ai_debugMove.GetBool() ) { - gameRenderWorld->DebugBounds( goLower ? colorRed : colorGreen, physicsObj.GetBounds(), path.endPos, gameLocal.msec ); - } - } - - if ( !goLower ) { - // make sure we don't fly too low - end = origin; - - enemyEnt = enemy.GetEntity(); - if ( enemyEnt ) { - end.z = lastVisibleEnemyPos.z + lastVisibleEnemyEyeOffset.z + fly_offset; - } else { - // just use the default eye height for the player - end.z = goalPos.z + DEFAULT_FLY_OFFSET + fly_offset; - } - - gameLocal.clip.Translation( trace, origin, end, physicsObj.GetClipModel(), mat3_identity, MASK_MONSTERSOLID, this ); - vel += Seek( vel, origin, trace.endpos, AI_SEEK_PREDICTION ); - } -} - -/* -===================== -idAI::FlySeekGoal -===================== -*/ -void idAI::FlySeekGoal( idVec3 &vel, idVec3 &goalPos ) { - idVec3 seekVel; - - // seek the goal position - seekVel = Seek( vel, physicsObj.GetOrigin(), goalPos, AI_SEEK_PREDICTION ); - seekVel *= fly_seek_scale; - vel += seekVel; -} - -/* -===================== -idAI::AdjustFlySpeed -===================== -*/ -void idAI::AdjustFlySpeed( idVec3 &vel ) { - float speed; - - // apply dampening - vel -= vel * AI_FLY_DAMPENING * MS2SEC( gameLocal.msec ); - - // gradually speed up/slow down to desired speed - speed = vel.Normalize(); - speed += ( move.speed - speed ) * MS2SEC( gameLocal.msec ); - if ( speed < 0.0f ) { - speed = 0.0f; - } else if ( move.speed && ( speed > move.speed ) ) { - speed = move.speed; - } - - vel *= speed; -} - -/* -===================== -idAI::FlyTurn -===================== -*/ -void idAI::FlyTurn( void ) { - if ( move.moveCommand == MOVE_FACE_ENEMY ) { - TurnToward( lastVisibleEnemyPos ); - } else if ( ( move.moveCommand == MOVE_FACE_ENTITY ) && move.goalEntity.GetEntity() ) { - TurnToward( move.goalEntity.GetEntity()->GetPhysics()->GetOrigin() ); - } else if ( move.speed > 0.0f ) { - const idVec3 &vel = physicsObj.GetLinearVelocity(); - if ( vel.ToVec2().LengthSqr() > 0.1f ) { - TurnToward( vel.ToYaw() ); - } - } - Turn(); -} - -/* -===================== -idAI::FlyMove -===================== -*/ -void idAI::FlyMove( void ) { - idVec3 goalPos; - idVec3 oldorigin; - idVec3 newDest; - - AI_BLOCKED = false; - if ( ( move.moveCommand != MOVE_NONE ) && ReachedPos( move.moveDest, move.moveCommand ) ) { - StopMove( MOVE_STATUS_DONE ); - } - - if ( ai_debugMove.GetBool() ) { - gameLocal.Printf( "%d: %s: %s, vel = %.2f, sp = %.2f, maxsp = %.2f\n", gameLocal.time, name.c_str(), moveCommandString[ move.moveCommand ], physicsObj.GetLinearVelocity().Length(), move.speed, fly_speed ); - } - - if ( move.moveCommand != MOVE_TO_POSITION_DIRECT ) { - idVec3 vel = physicsObj.GetLinearVelocity(); - - if ( GetMovePos( goalPos ) ) { - CheckObstacleAvoidance( goalPos, newDest ); - goalPos = newDest; - } - - if ( move.speed ) { - FlySeekGoal( vel, goalPos ); - } - - // add in bobbing - AddFlyBob( vel ); - - if ( enemy.GetEntity() && ( move.moveCommand != MOVE_TO_POSITION ) ) { - AdjustFlyHeight( vel, goalPos ); - } - - AdjustFlySpeed( vel ); - - physicsObj.SetLinearVelocity( vel ); - } - - // turn - FlyTurn(); - - // run the physics for this frame - oldorigin = physicsObj.GetOrigin(); - physicsObj.UseFlyMove( true ); - physicsObj.UseVelocityMove( false ); - physicsObj.SetDelta( vec3_zero ); - physicsObj.ForceDeltaMove( disableGravity ); - RunPhysics(); - - monsterMoveResult_t moveResult = physicsObj.GetMoveResult(); - if ( !af_push_moveables && attack.Length() && TestMelee() ) { - DirectDamage( attack, enemy.GetEntity() ); - } else { - idEntity *blockEnt = physicsObj.GetSlideMoveEntity(); - if ( blockEnt && blockEnt->IsType( idMoveable::Type ) && blockEnt->GetPhysics()->IsPushable() ) { - KickObstacles( viewAxis[ 0 ], kickForce, blockEnt ); - } else if ( moveResult == MM_BLOCKED ) { - move.blockTime = gameLocal.time + 500; - AI_BLOCKED = true; - } - } - - idVec3 org = physicsObj.GetOrigin(); - if ( oldorigin != org ) { - TouchTriggers(); - } - - if ( ai_debugMove.GetBool() ) { - gameRenderWorld->DebugLine( colorCyan, oldorigin, physicsObj.GetOrigin(), 4000 ); - gameRenderWorld->DebugBounds( colorOrange, physicsObj.GetBounds(), org, gameLocal.msec ); - gameRenderWorld->DebugBounds( colorMagenta, physicsObj.GetBounds(), move.moveDest, gameLocal.msec ); - gameRenderWorld->DebugLine( colorRed, org, org + physicsObj.GetLinearVelocity(), gameLocal.msec, true ); - gameRenderWorld->DebugLine( colorBlue, org, goalPos, gameLocal.msec, true ); - gameRenderWorld->DebugLine( colorYellow, org + EyeOffset(), org + EyeOffset() + viewAxis[ 0 ] * physicsObj.GetGravityAxis() * 16.0f, gameLocal.msec, true ); - DrawRoute(); - } -} - -/* -===================== -idAI::StaticMove -===================== -*/ -void idAI::StaticMove( void ) { - idActor *enemyEnt = enemy.GetEntity(); - - if ( AI_DEAD ) { - return; - } - - if ( ( move.moveCommand == MOVE_FACE_ENEMY ) && enemyEnt ) { - TurnToward( lastVisibleEnemyPos ); - } else if ( ( move.moveCommand == MOVE_FACE_ENTITY ) && move.goalEntity.GetEntity() ) { - TurnToward( move.goalEntity.GetEntity()->GetPhysics()->GetOrigin() ); - } else if ( move.moveCommand != MOVE_NONE ) { - TurnToward( move.moveDest ); - } - Turn(); - - physicsObj.ForceDeltaMove( true ); // disable gravity - RunPhysics(); - - AI_ONGROUND = false; - - if ( !af_push_moveables && attack.Length() && TestMelee() ) { - DirectDamage( attack, enemyEnt ); - } - - if ( ai_debugMove.GetBool() ) { - const idVec3 &org = physicsObj.GetOrigin(); - gameRenderWorld->DebugBounds( colorMagenta, physicsObj.GetBounds(), org, gameLocal.msec ); - gameRenderWorld->DebugLine( colorBlue, org, move.moveDest, gameLocal.msec, true ); - gameRenderWorld->DebugLine( colorYellow, org + EyeOffset(), org + EyeOffset() + viewAxis[ 0 ] * physicsObj.GetGravityAxis() * 16.0f, gameLocal.msec, true ); - } -} - -/*********************************************************************** - - Damage - -***********************************************************************/ - -/* -===================== -idAI::ReactionTo -===================== -*/ -int idAI::ReactionTo( const idEntity *ent ) { - - if ( ent->fl.hidden ) { - // ignore hidden entities - return ATTACK_IGNORE; - } - - if ( !ent->IsType( idActor::Type ) ) { - return ATTACK_IGNORE; - } - - const idActor *actor = static_cast( ent ); - if ( actor->IsType( idPlayer::Type ) && static_cast(actor)->noclip ) { - // ignore players in noclip mode - return ATTACK_IGNORE; - } - - // actors on different teams will always fight each other - if ( actor->team != team ) { - if ( actor->fl.notarget ) { - // don't attack on sight when attacker is notargeted - return ATTACK_ON_DAMAGE | ATTACK_ON_ACTIVATE; - } - return ATTACK_ON_SIGHT | ATTACK_ON_DAMAGE | ATTACK_ON_ACTIVATE; - } - - // monsters will fight when attacked by lower ranked monsters. rank 0 never fights back. - if ( rank && ( actor->rank < rank ) ) { - return ATTACK_ON_DAMAGE; - } - - // don't fight back - return ATTACK_IGNORE; -} - - -/* -===================== -idAI::Pain -===================== -*/ -bool idAI::Pain( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) { - idActor *actor; - - AI_PAIN = idActor::Pain( inflictor, attacker, damage, dir, location ); - AI_DAMAGE = true; - - // force a blink - blink_time = 0; - - // ignore damage from self - if ( attacker != this ) { - if ( inflictor ) { - AI_SPECIAL_DAMAGE = inflictor->spawnArgs.GetInt( "special_damage" ); - } else { - AI_SPECIAL_DAMAGE = 0; - } - - if ( enemy.GetEntity() != attacker && attacker->IsType( idActor::Type ) ) { - actor = ( idActor * )attacker; - if ( ReactionTo( actor ) & ATTACK_ON_DAMAGE ) { - gameLocal.AlertAI( actor ); - SetEnemy( actor ); - } - } - } - - return ( AI_PAIN != 0 ); -} - - -/* -===================== -idAI::SpawnParticles -===================== -*/ -void idAI::SpawnParticles( const char *keyName ) { - const idKeyValue *kv = spawnArgs.MatchPrefix( keyName, NULL ); - while ( kv ) { - particleEmitter_t pe; - - idStr particleName = kv->GetValue(); - - if ( particleName.Length() ) { - - idStr jointName = kv->GetValue(); - int dash = jointName.Find('-'); - if ( dash > 0 ) { - particleName = particleName.Left( dash ); - jointName = jointName.Right( jointName.Length() - dash - 1 ); - } - - SpawnParticlesOnJoint( pe, particleName, jointName ); - particles.Append( pe ); - } - - kv = spawnArgs.MatchPrefix( keyName, kv ); - } -} - -/* -===================== -idAI::SpawnParticlesOnJoint -===================== -*/ -const idDeclParticle *idAI::SpawnParticlesOnJoint( particleEmitter_t &pe, const char *particleName, const char *jointName ) { - idVec3 origin; - idMat3 axis; - - if ( *particleName == '\0' ) { - memset( &pe, 0, sizeof( pe ) ); - return pe.particle; - } - - pe.joint = animator.GetJointHandle( jointName ); - if ( pe.joint == INVALID_JOINT ) { - gameLocal.Warning( "Unknown particleJoint '%s' on '%s'", jointName, name.c_str() ); - pe.time = 0; - pe.particle = NULL; - } else { - animator.GetJointTransform( pe.joint, gameLocal.time, origin, axis ); - origin = renderEntity.origin + origin * renderEntity.axis; - - BecomeActive( TH_UPDATEPARTICLES ); - if ( !gameLocal.time ) { - // particles with time of 0 don't show, so set the time differently on the first frame - pe.time = 1; - } else { - pe.time = gameLocal.time; - } - pe.particle = static_cast( declManager->FindType( DECL_PARTICLE, particleName ) ); - gameLocal.smokeParticles->EmitSmoke( pe.particle, pe.time, gameLocal.random.CRandomFloat(), origin, axis, timeGroup /*_D3XP*/ ); - } - - return pe.particle; -} - -/* -===================== -idAI::Killed -===================== -*/ -void idAI::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) { - idAngles ang; - const char *modelDeath; - - // make sure the monster is activated - EndAttack(); - - if ( g_debugDamage.GetBool() ) { - gameLocal.Printf( "Damage: joint: '%s', zone '%s'\n", animator.GetJointName( ( jointHandle_t )location ), - GetDamageGroup( location ) ); - } - - if ( inflictor ) { - AI_SPECIAL_DAMAGE = inflictor->spawnArgs.GetInt( "special_damage" ); - } else { - AI_SPECIAL_DAMAGE = 0; - } - - if ( AI_DEAD ) { - AI_PAIN = true; - AI_DAMAGE = true; - return; - } - - // stop all voice sounds - StopSound( SND_CHANNEL_VOICE, false ); - if ( head.GetEntity() ) { - head.GetEntity()->StopSound( SND_CHANNEL_VOICE, false ); - head.GetEntity()->GetAnimator()->ClearAllAnims( gameLocal.time, 100 ); - } - - disableGravity = false; - move.moveType = MOVETYPE_DEAD; - af_push_moveables = false; - - physicsObj.UseFlyMove( false ); - physicsObj.ForceDeltaMove( false ); - - // end our looping ambient sound - StopSound( SND_CHANNEL_AMBIENT, false ); - - if ( attacker && attacker->IsType( idActor::Type ) ) { - gameLocal.AlertAI( ( idActor * )attacker ); - } - - // activate targets - ActivateTargets( attacker ); - - RemoveAttachments(); - RemoveProjectile(); - StopMove( MOVE_STATUS_DONE ); - - ClearEnemy(); - AI_DEAD = true; - - // make monster nonsolid - physicsObj.SetContents( 0 ); - physicsObj.GetClipModel()->Unlink(); - - Unbind(); - - if ( StartRagdoll() ) { - StartSound( "snd_death", SND_CHANNEL_VOICE, 0, false, NULL ); - } - - if ( spawnArgs.GetString( "model_death", "", &modelDeath ) ) { - // lost soul is only case that does not use a ragdoll and has a model_death so get the death sound in here - StartSound( "snd_death", SND_CHANNEL_VOICE, 0, false, NULL ); - renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time ); - SetModel( modelDeath ); - physicsObj.SetLinearVelocity( vec3_zero ); - physicsObj.PutToRest(); - physicsObj.DisableImpact(); -#ifdef _D3XP - // No grabbing if "model_death" - noGrab = true; -#endif - } - - restartParticles = false; - - state = GetScriptFunction( "state_Killed" ); - SetState( state ); - SetWaitState( "" ); - - const idKeyValue *kv = spawnArgs.MatchPrefix( "def_drops", NULL ); - while( kv ) { - idDict args; - - args.Set( "classname", kv->GetValue() ); - args.Set( "origin", physicsObj.GetOrigin().ToString() ); - gameLocal.SpawnEntityDef( args ); - kv = spawnArgs.MatchPrefix( "def_drops", kv ); - } - -#ifndef _D3XP - if ( ( attacker && attacker->IsType( idPlayer::Type ) ) && ( inflictor && !inflictor->IsType( idSoulCubeMissile::Type ) ) ) { - static_cast< idPlayer* >( attacker )->AddAIKill(); - } -#endif - -#ifdef _D3XP - if(spawnArgs.GetBool("harvest_on_death")) { - const idDict *harvestDef = gameLocal.FindEntityDefDict( spawnArgs.GetString("def_harvest_type"), false ); - if ( harvestDef ) { - idEntity *temp; - gameLocal.SpawnEntityDef( *harvestDef, &temp, false ); - harvestEnt = static_cast(temp); - - } - - if(harvestEnt.GetEntity()) { - //Let the harvest entity set itself up - harvestEnt.GetEntity()->Init(this); - harvestEnt.GetEntity()->BecomeActive( TH_THINK ); - } - } -#endif -} - -/*********************************************************************** - - Targeting/Combat - -***********************************************************************/ - -/* -===================== -idAI::PlayCinematic -===================== -*/ -void idAI::PlayCinematic( void ) { - const char *animname; - - if ( current_cinematic >= num_cinematics ) { - if ( g_debugCinematic.GetBool() ) { - gameLocal.Printf( "%d: '%s' stop\n", gameLocal.framenum, GetName() ); - } - if ( !spawnArgs.GetBool( "cinematic_no_hide" ) ) { - Hide(); - } - current_cinematic = 0; - ActivateTargets( gameLocal.GetLocalPlayer() ); - fl.neverDormant = false; - return; - } - - Show(); - current_cinematic++; - - allowJointMod = false; - allowEyeFocus = false; - - spawnArgs.GetString( va( "anim%d", current_cinematic ), NULL, &animname ); - if ( !animname ) { - gameLocal.Warning( "missing 'anim%d' key on %s", current_cinematic, name.c_str() ); - return; - } - - if ( g_debugCinematic.GetBool() ) { - gameLocal.Printf( "%d: '%s' start '%s'\n", gameLocal.framenum, GetName(), animname ); - } - - headAnim.animBlendFrames = 0; - headAnim.lastAnimBlendFrames = 0; - headAnim.BecomeIdle(); - - legsAnim.animBlendFrames = 0; - legsAnim.lastAnimBlendFrames = 0; - legsAnim.BecomeIdle(); - - torsoAnim.animBlendFrames = 0; - torsoAnim.lastAnimBlendFrames = 0; - ProcessEvent( &AI_PlayAnim, ANIMCHANNEL_TORSO, animname ); - - // make sure our model gets updated - animator.ForceUpdate(); - - // update the anim bounds - UpdateAnimation(); - UpdateVisuals(); - Present(); - - if ( head.GetEntity() ) { - // since the body anim was updated, we need to run physics to update the position of the head - RunPhysics(); - - // make sure our model gets updated - head.GetEntity()->GetAnimator()->ForceUpdate(); - - // update the anim bounds - head.GetEntity()->UpdateAnimation(); - head.GetEntity()->UpdateVisuals(); - head.GetEntity()->Present(); - } - - fl.neverDormant = true; -} - -/* -===================== -idAI::Activate - -Notifies the script that a monster has been activated by a trigger or flashlight -===================== -*/ -void idAI::Activate( idEntity *activator ) { - idPlayer *player; - - if ( AI_DEAD ) { - // ignore it when they're dead - return; - } - - // make sure he's not dormant - dormantStart = 0; - - if ( num_cinematics ) { - PlayCinematic(); - } else { - AI_ACTIVATED = true; - if ( !activator || !activator->IsType( idPlayer::Type ) ) { - player = gameLocal.GetLocalPlayer(); - } else { - player = static_cast( activator ); - } - - if ( ReactionTo( player ) & ATTACK_ON_ACTIVATE ) { - SetEnemy( player ); - } - - // update the script in cinematics so that entities don't start anims or show themselves a frame late. - if ( cinematic ) { - UpdateAIScript(); - - // make sure our model gets updated - animator.ForceUpdate(); - - // update the anim bounds - UpdateAnimation(); - UpdateVisuals(); - Present(); - - if ( head.GetEntity() ) { - // since the body anim was updated, we need to run physics to update the position of the head - RunPhysics(); - - // make sure our model gets updated - head.GetEntity()->GetAnimator()->ForceUpdate(); - - // update the anim bounds - head.GetEntity()->UpdateAnimation(); - head.GetEntity()->UpdateVisuals(); - head.GetEntity()->Present(); - } - } - } -} - -/* -===================== -idAI::EnemyDead -===================== -*/ -void idAI::EnemyDead( void ) { - ClearEnemy(); - AI_ENEMY_DEAD = true; -} - -/* -===================== -idAI::TalkTo -===================== -*/ -void idAI::TalkTo( idActor *actor ) { - if ( talk_state != TALK_OK ) { - return; - } - -#ifdef _D3XP - // Wake up monsters that are pretending to be NPC's - if ( team == 1 && actor->team != team ) { - ProcessEvent( &EV_Activate, actor ); - } -#endif - - talkTarget = actor; - if ( actor ) { - AI_TALK = true; - } else { - AI_TALK = false; - } -} - -/* -===================== -idAI::GetEnemy -===================== -*/ -idActor *idAI::GetEnemy( void ) const { - return enemy.GetEntity(); -} - -/* -===================== -idAI::GetTalkState -===================== -*/ -talkState_t idAI::GetTalkState( void ) const { - if ( ( talk_state != TALK_NEVER ) && AI_DEAD ) { - return TALK_DEAD; - } - if ( IsHidden() ) { - return TALK_NEVER; - } - return talk_state; -} - -/* -===================== -idAI::TouchedByFlashlight -===================== -*/ -void idAI::TouchedByFlashlight( idActor *flashlight_owner ) { - if ( wakeOnFlashlight ) { - Activate( flashlight_owner ); - } -} - -/* -===================== -idAI::ClearEnemy -===================== -*/ -void idAI::ClearEnemy( void ) { - if ( move.moveCommand == MOVE_TO_ENEMY ) { - StopMove( MOVE_STATUS_DEST_NOT_FOUND ); - } - - enemyNode.Remove(); - enemy = NULL; - AI_ENEMY_IN_FOV = false; - AI_ENEMY_VISIBLE = false; - AI_ENEMY_DEAD = true; - - SetChatSound(); -} - -/* -===================== -idAI::EnemyPositionValid -===================== -*/ -bool idAI::EnemyPositionValid( void ) const { - trace_t tr; - idVec3 muzzle; - idMat3 axis; - - if ( !enemy.GetEntity() ) { - return false; - } - - if ( AI_ENEMY_VISIBLE ) { - return true; - } - - gameLocal.clip.TracePoint( tr, GetEyePosition(), lastVisibleEnemyPos + lastVisibleEnemyEyeOffset, MASK_OPAQUE, this ); - if ( tr.fraction < 1.0f ) { - // can't see the area yet, so don't know if he's there or not - return true; - } - - return false; -} - -/* -===================== -idAI::SetEnemyPosition -===================== -*/ -void idAI::SetEnemyPosition( void ) { - idActor *enemyEnt = enemy.GetEntity(); - int enemyAreaNum; - int areaNum; - int lastVisibleReachableEnemyAreaNum; - aasPath_t path; - idVec3 pos; - bool onGround; - - if ( !enemyEnt ) { - return; - } - - lastVisibleReachableEnemyPos = lastReachableEnemyPos; - lastVisibleEnemyEyeOffset = enemyEnt->EyeOffset(); - lastVisibleEnemyPos = enemyEnt->GetPhysics()->GetOrigin(); - if ( move.moveType == MOVETYPE_FLY ) { - pos = lastVisibleEnemyPos; - onGround = true; - } else { - onGround = enemyEnt->GetFloorPos( 64.0f, pos ); - if ( enemyEnt->OnLadder() ) { - onGround = false; - } - } - - if ( !onGround ) { - if ( move.moveCommand == MOVE_TO_ENEMY ) { - AI_DEST_UNREACHABLE = true; - } - return; - } - - // when we don't have an AAS, we can't tell if an enemy is reachable or not, - // so just assume that he is. - if ( !aas ) { - lastVisibleReachableEnemyPos = lastVisibleEnemyPos; - if ( move.moveCommand == MOVE_TO_ENEMY ) { - AI_DEST_UNREACHABLE = false; - } - enemyAreaNum = 0; - areaNum = 0; - } else { - lastVisibleReachableEnemyAreaNum = move.toAreaNum; - enemyAreaNum = PointReachableAreaNum( lastVisibleEnemyPos, 1.0f ); - if ( !enemyAreaNum ) { - enemyAreaNum = PointReachableAreaNum( lastReachableEnemyPos, 1.0f ); - pos = lastReachableEnemyPos; - } - if ( !enemyAreaNum ) { - if ( move.moveCommand == MOVE_TO_ENEMY ) { - AI_DEST_UNREACHABLE = true; - } - areaNum = 0; - } else { - const idVec3 &org = physicsObj.GetOrigin(); - areaNum = PointReachableAreaNum( org ); - if ( PathToGoal( path, areaNum, org, enemyAreaNum, pos ) ) { - lastVisibleReachableEnemyPos = pos; - lastVisibleReachableEnemyAreaNum = enemyAreaNum; - if ( move.moveCommand == MOVE_TO_ENEMY ) { - AI_DEST_UNREACHABLE = false; - } - } else if ( move.moveCommand == MOVE_TO_ENEMY ) { - AI_DEST_UNREACHABLE = true; - } - } - } - - if ( move.moveCommand == MOVE_TO_ENEMY ) { - if ( !aas ) { - // keep the move destination up to date for wandering - move.moveDest = lastVisibleReachableEnemyPos; - } else if ( enemyAreaNum ) { - move.toAreaNum = lastVisibleReachableEnemyAreaNum; - move.moveDest = lastVisibleReachableEnemyPos; - } - - if ( move.moveType == MOVETYPE_FLY ) { - predictedPath_t path; - idVec3 end = move.moveDest; - end.z += enemyEnt->EyeOffset().z + fly_offset; - idAI::PredictPath( this, aas, move.moveDest, end - move.moveDest, 1000, 1000, SE_BLOCKED, path ); - move.moveDest = path.endPos; - move.toAreaNum = PointReachableAreaNum( move.moveDest, 1.0f ); - } - } -} - -/* -===================== -idAI::UpdateEnemyPosition -===================== -*/ -void idAI::UpdateEnemyPosition( void ) { - idActor *enemyEnt = enemy.GetEntity(); - int enemyAreaNum; - int areaNum; - aasPath_t path; - idVec3 enemyPos; - bool onGround; - - if ( !enemyEnt ) { - return; - } - - const idVec3 &org = physicsObj.GetOrigin(); - - if ( move.moveType == MOVETYPE_FLY ) { - enemyPos = enemyEnt->GetPhysics()->GetOrigin(); - onGround = true; - } else { - onGround = enemyEnt->GetFloorPos( 64.0f, enemyPos ); - if ( enemyEnt->OnLadder() ) { - onGround = false; - } - } - - if ( onGround ) { - // when we don't have an AAS, we can't tell if an enemy is reachable or not, - // so just assume that he is. - if ( !aas ) { - enemyAreaNum = 0; - lastReachableEnemyPos = enemyPos; - } else { - enemyAreaNum = PointReachableAreaNum( enemyPos, 1.0f ); - if ( enemyAreaNum ) { - areaNum = PointReachableAreaNum( org ); - if ( PathToGoal( path, areaNum, org, enemyAreaNum, enemyPos ) ) { - lastReachableEnemyPos = enemyPos; - } - } - } - } - - AI_ENEMY_IN_FOV = false; - AI_ENEMY_VISIBLE = false; - - if ( CanSee( enemyEnt, false ) ) { - AI_ENEMY_VISIBLE = true; - if ( CheckFOV( enemyEnt->GetPhysics()->GetOrigin() ) ) { - AI_ENEMY_IN_FOV = true; - } - - SetEnemyPosition(); - } else { - // check if we heard any sounds in the last frame - if ( enemyEnt == gameLocal.GetAlertEntity() ) { - float dist = ( enemyEnt->GetPhysics()->GetOrigin() - org ).LengthSqr(); - if ( dist < Square( AI_HEARING_RANGE ) ) { - SetEnemyPosition(); - } - } - } - - if ( ai_debugMove.GetBool() ) { - gameRenderWorld->DebugBounds( colorLtGrey, enemyEnt->GetPhysics()->GetBounds(), lastReachableEnemyPos, gameLocal.msec ); - gameRenderWorld->DebugBounds( colorWhite, enemyEnt->GetPhysics()->GetBounds(), lastVisibleReachableEnemyPos, gameLocal.msec ); - } -} - -/* -===================== -idAI::SetEnemy -===================== -*/ -void idAI::SetEnemy( idActor *newEnemy ) { - int enemyAreaNum; - - if ( AI_DEAD ) { - ClearEnemy(); - return; - } - - AI_ENEMY_DEAD = false; - if ( !newEnemy ) { - ClearEnemy(); - } else if ( enemy.GetEntity() != newEnemy ) { - enemy = newEnemy; - enemyNode.AddToEnd( newEnemy->enemyList ); - if ( newEnemy->health <= 0 ) { - EnemyDead(); - return; - } - // let the monster know where the enemy is - newEnemy->GetAASLocation( aas, lastReachableEnemyPos, enemyAreaNum ); - SetEnemyPosition(); - SetChatSound(); - - lastReachableEnemyPos = lastVisibleEnemyPos; - lastVisibleReachableEnemyPos = lastReachableEnemyPos; - enemyAreaNum = PointReachableAreaNum( lastReachableEnemyPos, 1.0f ); - if ( aas && enemyAreaNum ) { - aas->PushPointIntoAreaNum( enemyAreaNum, lastReachableEnemyPos ); - lastVisibleReachableEnemyPos = lastReachableEnemyPos; - } - } -} - -/* -============ -idAI::FirstVisiblePointOnPath -============ -*/ -idVec3 idAI::FirstVisiblePointOnPath( const idVec3 origin, const idVec3 &target, int travelFlags ) const { - int i, areaNum, targetAreaNum, curAreaNum, travelTime; - idVec3 curOrigin; - idReachability *reach; - - if ( !aas ) { - return origin; - } - - areaNum = PointReachableAreaNum( origin ); - targetAreaNum = PointReachableAreaNum( target ); - - if ( !areaNum || !targetAreaNum ) { - return origin; - } - - if ( ( areaNum == targetAreaNum ) || PointVisible( origin ) ) { - return origin; - } - - curAreaNum = areaNum; - curOrigin = origin; - - for( i = 0; i < 10; i++ ) { - - if ( !aas->RouteToGoalArea( curAreaNum, curOrigin, targetAreaNum, travelFlags, travelTime, &reach ) ) { - break; - } - - if ( !reach ) { - return target; - } - - curAreaNum = reach->toAreaNum; - curOrigin = reach->end; - - if ( PointVisible( curOrigin ) ) { - return curOrigin; - } - } - - return origin; -} - -/* -=================== -idAI::CalculateAttackOffsets - -calculate joint positions on attack frames so we can do proper "can hit" tests -=================== -*/ -void idAI::CalculateAttackOffsets( void ) { - const idDeclModelDef *modelDef; - int num; - int i; - int frame; - const frameCommand_t *command; - idMat3 axis; - const idAnim *anim; - jointHandle_t joint; - - modelDef = animator.ModelDef(); - if ( !modelDef ) { - return; - } - num = modelDef->NumAnims(); - - // needs to be off while getting the offsets so that we account for the distance the monster moves in the attack anim - animator.RemoveOriginOffset( false ); - - // anim number 0 is reserved for non-existant anims. to avoid off by one issues, just allocate an extra spot for - // launch offsets so that anim number can be used without subtracting 1. - missileLaunchOffset.SetGranularity( 1 ); - missileLaunchOffset.SetNum( num + 1 ); - missileLaunchOffset[ 0 ].Zero(); - - for( i = 1; i <= num; i++ ) { - missileLaunchOffset[ i ].Zero(); - anim = modelDef->GetAnim( i ); - if ( anim ) { - frame = anim->FindFrameForFrameCommand( FC_LAUNCHMISSILE, &command ); - if ( frame >= 0 ) { - joint = animator.GetJointHandle( command->string->c_str() ); - if ( joint == INVALID_JOINT ) { - gameLocal.Error( "Invalid joint '%s' on 'launch_missile' frame command on frame %d of model '%s'", command->string->c_str(), frame, modelDef->GetName() ); - } - GetJointTransformForAnim( joint, i, FRAME2MS( frame ), missileLaunchOffset[ i ], axis ); - } - } - } - - animator.RemoveOriginOffset( true ); -} - -/* -===================== -idAI::CreateProjectileClipModel -===================== -*/ -void idAI::CreateProjectileClipModel( void ) const { - if ( projectileClipModel == NULL ) { - idBounds projectileBounds( vec3_origin ); - projectileBounds.ExpandSelf( projectileRadius ); - projectileClipModel = new idClipModel( idTraceModel( projectileBounds ) ); - } -} - -/* -===================== -idAI::GetAimDir -===================== -*/ -bool idAI::GetAimDir( const idVec3 &firePos, idEntity *aimAtEnt, const idEntity *ignore, idVec3 &aimDir ) const { - idVec3 targetPos1; - idVec3 targetPos2; - idVec3 delta; - float max_height; - bool result; - - // if no aimAtEnt or projectile set - if ( !aimAtEnt || !projectileDef ) { - aimDir = viewAxis[ 0 ] * physicsObj.GetGravityAxis(); - return false; - } - - if ( projectileClipModel == NULL ) { - CreateProjectileClipModel(); - } - - if ( aimAtEnt == enemy.GetEntity() ) { - static_cast( aimAtEnt )->GetAIAimTargets( lastVisibleEnemyPos, targetPos1, targetPos2 ); - } else if ( aimAtEnt->IsType( idActor::Type ) ) { - static_cast( aimAtEnt )->GetAIAimTargets( aimAtEnt->GetPhysics()->GetOrigin(), targetPos1, targetPos2 ); - } else { - targetPos1 = aimAtEnt->GetPhysics()->GetAbsBounds().GetCenter(); - targetPos2 = targetPos1; - } - -#ifdef _D3XP - if ( this->team == 0 && !idStr::Cmp( aimAtEnt->GetEntityDefName(), "monster_demon_vulgar" ) ) { - targetPos1.z -= 28.f; - targetPos2.z -= 12.f; - } -#endif - - // try aiming for chest - delta = firePos - targetPos1; - max_height = delta.LengthFast() * projectile_height_to_distance_ratio; - result = PredictTrajectory( firePos, targetPos1, projectileSpeed, projectileGravity, projectileClipModel, MASK_SHOT_RENDERMODEL, max_height, ignore, aimAtEnt, ai_debugTrajectory.GetBool() ? 1000 : 0, aimDir ); - if ( result || !aimAtEnt->IsType( idActor::Type ) ) { - return result; - } - - // try aiming for head - delta = firePos - targetPos2; - max_height = delta.LengthFast() * projectile_height_to_distance_ratio; - result = PredictTrajectory( firePos, targetPos2, projectileSpeed, projectileGravity, projectileClipModel, MASK_SHOT_RENDERMODEL, max_height, ignore, aimAtEnt, ai_debugTrajectory.GetBool() ? 1000 : 0, aimDir ); - - return result; -} - -/* -===================== -idAI::BeginAttack -===================== -*/ -void idAI::BeginAttack( const char *name ) { - attack = name; - lastAttackTime = gameLocal.time; -} - -/* -===================== -idAI::EndAttack -===================== -*/ -void idAI::EndAttack( void ) { - attack = ""; -} - -/* -===================== -idAI::CreateProjectile -===================== -*/ -idProjectile *idAI::CreateProjectile( const idVec3 &pos, const idVec3 &dir ) { - idEntity *ent; - const char *clsname; - - if ( !projectile.GetEntity() ) { - gameLocal.SpawnEntityDef( *projectileDef, &ent, false ); - if ( !ent ) { - clsname = projectileDef->GetString( "classname" ); - gameLocal.Error( "Could not spawn entityDef '%s'", clsname ); - } - - if ( !ent->IsType( idProjectile::Type ) ) { - clsname = ent->GetClassname(); - gameLocal.Error( "'%s' is not an idProjectile", clsname ); - } - projectile = ( idProjectile * )ent; - } - - projectile.GetEntity()->Create( this, pos, dir ); - - return projectile.GetEntity(); -} - -/* -===================== -idAI::RemoveProjectile -===================== -*/ -void idAI::RemoveProjectile( void ) { - if ( projectile.GetEntity() ) { - projectile.GetEntity()->PostEventMS( &EV_Remove, 0 ); - projectile = NULL; - } -} - -/* -===================== -idAI::LaunchProjectile -===================== -*/ -idProjectile *idAI::LaunchProjectile( const char *jointname, idEntity *target, bool clampToAttackCone ) { - idVec3 muzzle; - idVec3 dir; - idVec3 start; - trace_t tr; - idBounds projBounds; - float distance; - const idClipModel *projClip; - float attack_accuracy; - float attack_cone; - float projectile_spread; - float diff; - float angle; - float spin; - idAngles ang; - int num_projectiles; - int i; - idMat3 axis; -#ifdef _D3XP - idMat3 proj_axis; - bool forceMuzzle; -#endif - idVec3 tmp; - idProjectile *lastProjectile; - - if ( !projectileDef ) { - gameLocal.Warning( "%s (%s) doesn't have a projectile specified", name.c_str(), GetEntityDefName() ); - return NULL; - } - - attack_accuracy = spawnArgs.GetFloat( "attack_accuracy", "7" ); - attack_cone = spawnArgs.GetFloat( "attack_cone", "70" ); - projectile_spread = spawnArgs.GetFloat( "projectile_spread", "0" ); - num_projectiles = spawnArgs.GetInt( "num_projectiles", "1" ); -#ifdef _D3XP - forceMuzzle = spawnArgs.GetBool( "forceMuzzle", "0" ); -#endif - - GetMuzzle( jointname, muzzle, axis ); - - if ( !projectile.GetEntity() ) { - CreateProjectile( muzzle, axis[ 0 ] ); - } - - lastProjectile = projectile.GetEntity(); - - if ( target != NULL ) { - tmp = target->GetPhysics()->GetAbsBounds().GetCenter() - muzzle; - tmp.Normalize(); - axis = tmp.ToMat3(); - } else { - axis = viewAxis; - } - - // rotate it because the cone points up by default - tmp = axis[2]; - axis[2] = axis[0]; - axis[0] = -tmp; - -#ifdef _D3XP - proj_axis = axis; -#endif - - if ( !forceMuzzle ) { // _D3XP - // make sure the projectile starts inside the monster bounding box - const idBounds &ownerBounds = physicsObj.GetAbsBounds(); - projClip = lastProjectile->GetPhysics()->GetClipModel(); - projBounds = projClip->GetBounds().Rotate( axis ); - - // check if the owner bounds is bigger than the projectile bounds - if ( ( ( ownerBounds[1][0] - ownerBounds[0][0] ) > ( projBounds[1][0] - projBounds[0][0] ) ) && - ( ( ownerBounds[1][1] - ownerBounds[0][1] ) > ( projBounds[1][1] - projBounds[0][1] ) ) && - ( ( ownerBounds[1][2] - ownerBounds[0][2] ) > ( projBounds[1][2] - projBounds[0][2] ) ) ) { - if ( (ownerBounds - projBounds).RayIntersection( muzzle, viewAxis[ 0 ], distance ) ) { - start = muzzle + distance * viewAxis[ 0 ]; - } else { - start = ownerBounds.GetCenter(); - } - } else { - // projectile bounds bigger than the owner bounds, so just start it from the center - start = ownerBounds.GetCenter(); - } - - gameLocal.clip.Translation( tr, start, muzzle, projClip, axis, MASK_SHOT_RENDERMODEL, this ); - muzzle = tr.endpos; - } - - // set aiming direction - GetAimDir( muzzle, target, this, dir ); - ang = dir.ToAngles(); - - // adjust his aim so it's not perfect. uses sine based movement so the tracers appear less random in their spread. - float t = MS2SEC( gameLocal.time + entityNumber * 497 ); - ang.pitch += idMath::Sin16( t * 5.1 ) * attack_accuracy; - ang.yaw += idMath::Sin16( t * 6.7 ) * attack_accuracy; - - if ( clampToAttackCone ) { - // clamp the attack direction to be within monster's attack cone so he doesn't do - // things like throw the missile backwards if you're behind him - diff = idMath::AngleDelta( ang.yaw, current_yaw ); - if ( diff > attack_cone ) { - ang.yaw = current_yaw + attack_cone; - } else if ( diff < -attack_cone ) { - ang.yaw = current_yaw - attack_cone; - } - } - - axis = ang.ToMat3(); - - float spreadRad = DEG2RAD( projectile_spread ); - for( i = 0; i < num_projectiles; i++ ) { - // spread the projectiles out - angle = idMath::Sin( spreadRad * gameLocal.random.RandomFloat() ); - spin = (float)DEG2RAD( 360.0f ) * gameLocal.random.RandomFloat(); - dir = axis[ 0 ] + axis[ 2 ] * ( angle * idMath::Sin( spin ) ) - axis[ 1 ] * ( angle * idMath::Cos( spin ) ); - dir.Normalize(); - - // launch the projectile - if ( !projectile.GetEntity() ) { - CreateProjectile( muzzle, dir ); - } - lastProjectile = projectile.GetEntity(); - lastProjectile->Launch( muzzle, dir, vec3_origin ); - projectile = NULL; - } - - TriggerWeaponEffects( muzzle ); - - lastAttackTime = gameLocal.time; - - return lastProjectile; -} - -/* -================ -idAI::DamageFeedback - -callback function for when another entity received damage from this entity. damage can be adjusted and returned to the caller. - -FIXME: This gets called when we call idPlayer::CalcDamagePoints from idAI::AttackMelee, which then checks for a saving throw, -possibly forcing a miss. This is harmless behavior ATM, but is not intuitive. -================ -*/ -void idAI::DamageFeedback( idEntity *victim, idEntity *inflictor, int &damage ) { - if ( ( victim == this ) && inflictor->IsType( idProjectile::Type ) ) { - // monsters only get half damage from their own projectiles - damage = ( damage + 1 ) / 2; // round up so we don't do 0 damage - - } else if ( victim == enemy.GetEntity() ) { - AI_HIT_ENEMY = true; - } -} - -/* -===================== -idAI::DirectDamage - -Causes direct damage to an entity - -kickDir is specified in the monster's coordinate system, and gives the direction -that the view kick and knockback should go -===================== -*/ -void idAI::DirectDamage( const char *meleeDefName, idEntity *ent ) { - const idDict *meleeDef; - const char *p; - const idSoundShader *shader; - - meleeDef = gameLocal.FindEntityDefDict( meleeDefName, false ); - if ( !meleeDef ) { - gameLocal.Error( "Unknown damage def '%s' on '%s'", meleeDefName, name.c_str() ); - } - - if ( !ent->fl.takedamage ) { - const idSoundShader *shader = declManager->FindSound(meleeDef->GetString( "snd_miss" )); - StartSoundShader( shader, SND_CHANNEL_DAMAGE, 0, false, NULL ); - return; - } - - // - // do the damage - // - p = meleeDef->GetString( "snd_hit" ); - if ( p && *p ) { - shader = declManager->FindSound( p ); - StartSoundShader( shader, SND_CHANNEL_DAMAGE, 0, false, NULL ); - } - - idVec3 kickDir; - meleeDef->GetVector( "kickDir", "0 0 0", kickDir ); - - idVec3 globalKickDir; - globalKickDir = ( viewAxis * physicsObj.GetGravityAxis() ) * kickDir; - - ent->Damage( this, this, globalKickDir, meleeDefName, 1.0f, INVALID_JOINT ); - - // end the attack if we're a multiframe attack - EndAttack(); -} - -/* -===================== -idAI::TestMelee -===================== -*/ -bool idAI::TestMelee( void ) const { - trace_t trace; - idActor *enemyEnt = enemy.GetEntity(); - - if ( !enemyEnt || !melee_range ) { - return false; - } - - //FIXME: make work with gravity vector - idVec3 org = physicsObj.GetOrigin(); - const idBounds &myBounds = physicsObj.GetBounds(); - idBounds bounds; - - // expand the bounds out by our melee range - bounds[0][0] = -melee_range; - bounds[0][1] = -melee_range; - bounds[0][2] = myBounds[0][2] - 4.0f; - bounds[1][0] = melee_range; - bounds[1][1] = melee_range; - bounds[1][2] = myBounds[1][2] + 4.0f; - bounds.TranslateSelf( org ); - - idVec3 enemyOrg = enemyEnt->GetPhysics()->GetOrigin(); - idBounds enemyBounds = enemyEnt->GetPhysics()->GetBounds(); - enemyBounds.TranslateSelf( enemyOrg ); - - if ( ai_debugMove.GetBool() ) { - gameRenderWorld->DebugBounds( colorYellow, bounds, vec3_zero, gameLocal.msec ); - } - - if ( !bounds.IntersectsBounds( enemyBounds ) ) { - return false; - } - - idVec3 start = GetEyePosition(); - idVec3 end = enemyEnt->GetEyePosition(); - - gameLocal.clip.TracePoint( trace, start, end, MASK_SHOT_BOUNDINGBOX, this ); - if ( ( trace.fraction == 1.0f ) || ( gameLocal.GetTraceEntity( trace ) == enemyEnt ) ) { - return true; - } - - return false; -} - -/* -===================== -idAI::AttackMelee - -jointname allows the endpoint to be exactly specified in the model, -as for the commando tentacle. If not specified, it will be set to -the facing direction + melee_range. - -kickDir is specified in the monster's coordinate system, and gives the direction -that the view kick and knockback should go -===================== -*/ -bool idAI::AttackMelee( const char *meleeDefName ) { - const idDict *meleeDef; - idActor *enemyEnt = enemy.GetEntity(); - const char *p; - const idSoundShader *shader; - - meleeDef = gameLocal.FindEntityDefDict( meleeDefName, false ); - if ( !meleeDef ) { - gameLocal.Error( "Unknown melee '%s'", meleeDefName ); - } - - if ( !enemyEnt ) { - p = meleeDef->GetString( "snd_miss" ); - if ( p && *p ) { - shader = declManager->FindSound( p ); - StartSoundShader( shader, SND_CHANNEL_DAMAGE, 0, false, NULL ); - } - return false; - } - - // check for the "saving throw" automatic melee miss on lethal blow - // stupid place for this. - bool forceMiss = false; - if ( enemyEnt->IsType( idPlayer::Type ) && g_skill.GetInteger() < 2 ) { - int damage, armor; - idPlayer *player = static_cast( enemyEnt ); - player->CalcDamagePoints( this, this, meleeDef, 1.0f, INVALID_JOINT, &damage, &armor ); - - if ( enemyEnt->health <= damage ) { - int t = gameLocal.time - player->lastSavingThrowTime; - if ( t > SAVING_THROW_TIME ) { - player->lastSavingThrowTime = gameLocal.time; - t = 0; - } - if ( t < 1000 ) { - gameLocal.Printf( "Saving throw.\n" ); - forceMiss = true; - } - } - } - - // make sure the trace can actually hit the enemy - if ( forceMiss || !TestMelee() ) { - // missed - p = meleeDef->GetString( "snd_miss" ); - if ( p && *p ) { - shader = declManager->FindSound( p ); - StartSoundShader( shader, SND_CHANNEL_DAMAGE, 0, false, NULL ); - } - return false; - } - - // - // do the damage - // - p = meleeDef->GetString( "snd_hit" ); - if ( p && *p ) { - shader = declManager->FindSound( p ); - StartSoundShader( shader, SND_CHANNEL_DAMAGE, 0, false, NULL ); - } - - idVec3 kickDir; - meleeDef->GetVector( "kickDir", "0 0 0", kickDir ); - - idVec3 globalKickDir; - globalKickDir = ( viewAxis * physicsObj.GetGravityAxis() ) * kickDir; - - enemyEnt->Damage( this, this, globalKickDir, meleeDefName, 1.0f, INVALID_JOINT ); - - lastAttackTime = gameLocal.time; - - return true; -} - -/* -================ -idAI::PushWithAF -================ -*/ -void idAI::PushWithAF( void ) { - int i, j; - afTouch_t touchList[ MAX_GENTITIES ]; - idEntity *pushed_ents[ MAX_GENTITIES ]; - idEntity *ent; - idVec3 vel; - int num_pushed; - - num_pushed = 0; - af.ChangePose( this, gameLocal.time ); - int num = af.EntitiesTouchingAF( touchList ); - for( i = 0; i < num; i++ ) { - if ( touchList[ i ].touchedEnt->IsType( idProjectile::Type ) ) { - // skip projectiles - continue; - } - - // make sure we havent pushed this entity already. this avoids causing double damage - for( j = 0; j < num_pushed; j++ ) { - if ( pushed_ents[ j ] == touchList[ i ].touchedEnt ) { - break; - } - } - if ( j >= num_pushed ) { - ent = touchList[ i ].touchedEnt; - pushed_ents[num_pushed++] = ent; - vel = ent->GetPhysics()->GetAbsBounds().GetCenter() - touchList[ i ].touchedByBody->GetWorldOrigin(); - vel.Normalize(); - if ( attack.Length() && ent->IsType( idActor::Type ) ) { - ent->Damage( this, this, vel, attack, 1.0f, INVALID_JOINT ); - } else { - ent->GetPhysics()->SetLinearVelocity( 100.0f * vel, touchList[ i ].touchedClipModel->GetId() ); - } - } - } -} - -/*********************************************************************** - - Misc - -***********************************************************************/ - -/* -================ -idAI::GetMuzzle -================ -*/ -void idAI::GetMuzzle( const char *jointname, idVec3 &muzzle, idMat3 &axis ) { - jointHandle_t joint; - - if ( !jointname || !jointname[ 0 ] ) { - muzzle = physicsObj.GetOrigin() + viewAxis[ 0 ] * physicsObj.GetGravityAxis() * 14; - muzzle -= physicsObj.GetGravityNormal() * physicsObj.GetBounds()[ 1 ].z * 0.5f; - } else { - joint = animator.GetJointHandle( jointname ); - if ( joint == INVALID_JOINT ) { - gameLocal.Error( "Unknown joint '%s' on %s", jointname, GetEntityDefName() ); - } - GetJointWorldTransform( joint, gameLocal.time, muzzle, axis ); - } -} - -/* -================ -idAI::TriggerWeaponEffects -================ -*/ -void idAI::TriggerWeaponEffects( const idVec3 &muzzle ) { - idVec3 org; - idMat3 axis; - - if ( !g_muzzleFlash.GetBool() ) { - return; - } - - // muzzle flash - // offset the shader parms so muzzle flashes show up - renderEntity.shaderParms[SHADERPARM_TIMEOFFSET] = -MS2SEC( gameLocal.time ); - renderEntity.shaderParms[ SHADERPARM_DIVERSITY ] = gameLocal.random.CRandomFloat(); - - if ( flashJointWorld != INVALID_JOINT ) { - GetJointWorldTransform( flashJointWorld, gameLocal.time, org, axis ); - - if ( worldMuzzleFlash.lightRadius.x > 0.0f ) { - worldMuzzleFlash.axis = axis; - worldMuzzleFlash.shaderParms[SHADERPARM_TIMEOFFSET] = -MS2SEC( gameLocal.time ); - if ( worldMuzzleFlashHandle != - 1 ) { - gameRenderWorld->UpdateLightDef( worldMuzzleFlashHandle, &worldMuzzleFlash ); - } else { - worldMuzzleFlashHandle = gameRenderWorld->AddLightDef( &worldMuzzleFlash ); - } - muzzleFlashEnd = gameLocal.time + flashTime; - UpdateVisuals(); - } - } -} - -/* -================ -idAI::UpdateMuzzleFlash -================ -*/ -void idAI::UpdateMuzzleFlash( void ) { - if ( worldMuzzleFlashHandle != -1 ) { - if ( gameLocal.time >= muzzleFlashEnd ) { - gameRenderWorld->FreeLightDef( worldMuzzleFlashHandle ); - worldMuzzleFlashHandle = -1; - } else { - idVec3 muzzle; - animator.GetJointTransform( flashJointWorld, gameLocal.time, muzzle, worldMuzzleFlash.axis ); - animator.GetJointTransform( flashJointWorld, gameLocal.time, muzzle, worldMuzzleFlash.axis ); - muzzle = physicsObj.GetOrigin() + ( muzzle + modelOffset ) * viewAxis * physicsObj.GetGravityAxis(); - worldMuzzleFlash.origin = muzzle; - gameRenderWorld->UpdateLightDef( worldMuzzleFlashHandle, &worldMuzzleFlash ); - } - } -} - -/* -================ -idAI::Hide -================ -*/ -void idAI::Hide( void ) { - idActor::Hide(); - fl.takedamage = false; - physicsObj.SetContents( 0 ); - physicsObj.GetClipModel()->Unlink(); - StopSound( SND_CHANNEL_AMBIENT, false ); - SetChatSound(); - - AI_ENEMY_IN_FOV = false; - AI_ENEMY_VISIBLE = false; - StopMove( MOVE_STATUS_DONE ); -} - -/* -================ -idAI::Show -================ -*/ -void idAI::Show( void ) { - idActor::Show(); - if ( spawnArgs.GetBool( "big_monster" ) ) { - physicsObj.SetContents( 0 ); - } else if ( use_combat_bbox ) { - physicsObj.SetContents( CONTENTS_BODY|CONTENTS_SOLID ); - } else { - physicsObj.SetContents( CONTENTS_BODY ); - } - physicsObj.GetClipModel()->Link( gameLocal.clip ); - fl.takedamage = !spawnArgs.GetBool( "noDamage" ); - SetChatSound(); - StartSound( "snd_ambient", SND_CHANNEL_AMBIENT, 0, false, NULL ); -} - -/* -===================== -idAI::SetChatSound -===================== -*/ -void idAI::SetChatSound( void ) { - const char *snd; - - if ( IsHidden() ) { - snd = NULL; - } else if ( enemy.GetEntity() ) { - snd = spawnArgs.GetString( "snd_chatter_combat", NULL ); - chat_min = SEC2MS( spawnArgs.GetFloat( "chatter_combat_min", "5" ) ); - chat_max = SEC2MS( spawnArgs.GetFloat( "chatter_combat_max", "10" ) ); - } else if ( !spawnArgs.GetBool( "no_idle_chatter" ) ) { - snd = spawnArgs.GetString( "snd_chatter", NULL ); - chat_min = SEC2MS( spawnArgs.GetFloat( "chatter_min", "5" ) ); - chat_max = SEC2MS( spawnArgs.GetFloat( "chatter_max", "10" ) ); - } else { - snd = NULL; - } - - if ( snd && *snd ) { - chat_snd = declManager->FindSound( snd ); - - // set the next chat time - chat_time = gameLocal.time + chat_min + gameLocal.random.RandomFloat() * ( chat_max - chat_min ); - } else { - chat_snd = NULL; - } -} - -/* -================ -idAI::CanPlayChatterSounds - -Used for playing chatter sounds on monsters. -================ -*/ -bool idAI::CanPlayChatterSounds( void ) const { - if ( AI_DEAD ) { - return false; - } - - if ( IsHidden() ) { - return false; - } - - if ( enemy.GetEntity() ) { - return true; - } - - if ( spawnArgs.GetBool( "no_idle_chatter" ) ) { - return false; - } - - return true; -} - -/* -===================== -idAI::PlayChatter -===================== -*/ -void idAI::PlayChatter( void ) { - // check if it's time to play a chat sound - if ( AI_DEAD || !chat_snd || ( chat_time > gameLocal.time ) ) { - return; - } - - StartSoundShader( chat_snd, SND_CHANNEL_VOICE, 0, false, NULL ); - - // set the next chat time - chat_time = gameLocal.time + chat_min + gameLocal.random.RandomFloat() * ( chat_max - chat_min ); -} - -/* -===================== -idAI::UpdateParticles -===================== -*/ -void idAI::UpdateParticles( void ) { - if ( ( thinkFlags & TH_UPDATEPARTICLES) && !IsHidden() ) { - idVec3 realVector; - idMat3 realAxis; - - int particlesAlive = 0; - for ( int i = 0; i < particles.Num(); i++ ) { -#ifdef _D3XP - // Smoke particles on AI characters will always be "slow", even when held by grabber - SetTimeState ts(TIME_GROUP1); -#endif - if ( particles[i].particle && particles[i].time ) { - particlesAlive++; - if (af.IsActive()) { - realAxis = mat3_identity; - realVector = GetPhysics()->GetOrigin(); - } else { - animator.GetJointTransform( particles[i].joint, gameLocal.time, realVector, realAxis ); - realAxis *= renderEntity.axis; - realVector = physicsObj.GetOrigin() + ( realVector + modelOffset ) * ( viewAxis * physicsObj.GetGravityAxis() ); - } - - if ( !gameLocal.smokeParticles->EmitSmoke( particles[i].particle, particles[i].time, gameLocal.random.CRandomFloat(), realVector, realAxis, timeGroup /*_D3XP*/ )) { - if ( restartParticles ) { - particles[i].time = gameLocal.time; - } else { - particles[i].time = 0; - particlesAlive--; - } - } - } - } - if ( particlesAlive == 0 ) { - BecomeInactive( TH_UPDATEPARTICLES ); - } - } -} - -/* -===================== -idAI::TriggerParticles -===================== -*/ -void idAI::TriggerParticles( const char *jointName ) { - jointHandle_t jointNum; - - jointNum = animator.GetJointHandle( jointName ); - for ( int i = 0; i < particles.Num(); i++ ) { - if ( particles[i].joint == jointNum ) { - particles[i].time = gameLocal.time; - BecomeActive( TH_UPDATEPARTICLES ); - } - } -} - -#ifdef _D3XP -void idAI::TriggerFX( const char* joint, const char* fx ) { - - if( !strcmp(joint, "origin") ) { - idEntityFx::StartFx( fx, NULL, NULL, this, true ); - } else { - idVec3 joint_origin; - idMat3 joint_axis; - jointHandle_t jointNum; - jointNum = animator.GetJointHandle( joint ); - - if ( jointNum == INVALID_JOINT ) { - gameLocal.Warning( "Unknown fx joint '%s' on entity %s", joint, name.c_str() ); - return; - } - - GetJointWorldTransform( jointNum, gameLocal.time, joint_origin, joint_axis ); - idEntityFx::StartFx( fx, &joint_origin, &joint_axis, this, true ); - } -} - -idEntity* idAI::StartEmitter( const char* name, const char* joint, const char* particle ) { - - idEntity* existing = GetEmitter(name); - if(existing) { - return existing; - } - - jointHandle_t jointNum; - jointNum = animator.GetJointHandle( joint ); - - idVec3 offset; - idMat3 axis; - - GetJointWorldTransform( jointNum, gameLocal.time, offset, axis ); - - /*animator.GetJointTransform( jointNum, gameLocal.time, offset, axis ); - offset = GetPhysics()->GetOrigin() + offset * GetPhysics()->GetAxis(); - axis = axis * GetPhysics()->GetAxis();*/ - - - - idDict args; - - const idDeclEntityDef *emitterDef = gameLocal.FindEntityDef( "func_emitter", false ); - args = emitterDef->dict; - args.Set("model", particle); - args.Set( "origin", offset.ToString() ); - args.SetBool("start_off", true); - - idEntity* ent; - gameLocal.SpawnEntityDef(args, &ent, false); - - ent->GetPhysics()->SetOrigin(offset); - //ent->GetPhysics()->SetAxis(axis); - - // align z-axis of model with the direction - /*idVec3 tmp; - axis = (viewAxis[ 0 ] * physicsObj.GetGravityAxis()).ToMat3(); - tmp = axis[2]; - axis[2] = axis[0]; - axis[0] = -tmp; - - ent->GetPhysics()->SetAxis(axis);*/ - - axis = physicsObj.GetGravityAxis(); - ent->GetPhysics()->SetAxis(axis); - - - ent->GetPhysics()->GetClipModel()->SetOwner( this ); - - - //Keep a reference to the emitter so we can track it - funcEmitter_t newEmitter; - strcpy(newEmitter.name, name); - newEmitter.particle = (idFuncEmitter*)ent; - newEmitter.joint = jointNum; - funcEmitters.Set(newEmitter.name, newEmitter); - - //Bind it to the joint and make it active - newEmitter.particle->BindToJoint(this, jointNum, true); - newEmitter.particle->BecomeActive(TH_THINK); - newEmitter.particle->Show(); - newEmitter.particle->PostEventMS(&EV_Activate, 0, this); - return newEmitter.particle; -} - -idEntity* idAI::GetEmitter( const char* name ) { - funcEmitter_t* emitter; - funcEmitters.Get(name, &emitter); - if(emitter) { - return emitter->particle; - } - return NULL; -} - -void idAI::StopEmitter( const char* name ) { - funcEmitter_t* emitter; - funcEmitters.Get(name, &emitter); - if(emitter) { - emitter->particle->Unbind(); - emitter->particle->PostEventMS( &EV_Remove, 0 ); - funcEmitters.Remove(name); - } -} - -#endif - - -/*********************************************************************** - - Head & torso aiming - -***********************************************************************/ - -/* -================ -idAI::UpdateAnimationControllers -================ -*/ -bool idAI::UpdateAnimationControllers( void ) { - idVec3 local; - idVec3 focusPos; - idQuat jawQuat; - idVec3 left; - idVec3 dir; - idVec3 orientationJointPos; - idVec3 localDir; - idAngles newLookAng; - idAngles diff; - idMat3 mat; - idMat3 axis; - idMat3 orientationJointAxis; - idAFAttachment *headEnt = head.GetEntity(); - idVec3 eyepos; - idVec3 pos; - int i; - idAngles jointAng; - float orientationJointYaw; - - if ( AI_DEAD ) { - return idActor::UpdateAnimationControllers(); - } - - if ( orientationJoint == INVALID_JOINT ) { - orientationJointAxis = viewAxis; - orientationJointPos = physicsObj.GetOrigin(); - orientationJointYaw = current_yaw; - } else { - GetJointWorldTransform( orientationJoint, gameLocal.time, orientationJointPos, orientationJointAxis ); - orientationJointYaw = orientationJointAxis[ 2 ].ToYaw(); - orientationJointAxis = idAngles( 0.0f, orientationJointYaw, 0.0f ).ToMat3(); - } - - if ( focusJoint != INVALID_JOINT ) { - if ( headEnt ) { - headEnt->GetJointWorldTransform( focusJoint, gameLocal.time, eyepos, axis ); - } else { - GetJointWorldTransform( focusJoint, gameLocal.time, eyepos, axis ); - } - eyeOffset.z = eyepos.z - physicsObj.GetOrigin().z; - if ( ai_debugMove.GetBool() ) { - gameRenderWorld->DebugLine( colorRed, eyepos, eyepos + orientationJointAxis[ 0 ] * 32.0f, gameLocal.msec ); - } - } else { - eyepos = GetEyePosition(); - } - - if ( headEnt ) { - CopyJointsFromBodyToHead(); - } - - // Update the IK after we've gotten all the joint positions we need, but before we set any joint positions. - // Getting the joint positions causes the joints to be updated. The IK gets joint positions itself (which - // are already up to date because of getting the joints in this function) and then sets their positions, which - // forces the heirarchy to be updated again next time we get a joint or present the model. If IK is enabled, - // or if we have a seperate head, we end up transforming the joints twice per frame. Characters with no - // head entity and no ik will only transform their joints once. Set g_debuganim to the current entity number - // in order to see how many times an entity transforms the joints per frame. - idActor::UpdateAnimationControllers(); - - idEntity *focusEnt = focusEntity.GetEntity(); - if ( !allowJointMod || !allowEyeFocus || ( gameLocal.time >= focusTime ) ) { - focusPos = GetEyePosition() + orientationJointAxis[ 0 ] * 512.0f; - } else if ( focusEnt == NULL ) { - // keep looking at last position until focusTime is up - focusPos = currentFocusPos; - } else if ( focusEnt == enemy.GetEntity() ) { - focusPos = lastVisibleEnemyPos + lastVisibleEnemyEyeOffset - eyeVerticalOffset * enemy.GetEntity()->GetPhysics()->GetGravityNormal(); - } else if ( focusEnt->IsType( idActor::Type ) ) { - focusPos = static_cast( focusEnt )->GetEyePosition() - eyeVerticalOffset * focusEnt->GetPhysics()->GetGravityNormal(); - } else { - focusPos = focusEnt->GetPhysics()->GetOrigin(); - } - - currentFocusPos = currentFocusPos + ( focusPos - currentFocusPos ) * eyeFocusRate; - - // determine yaw from origin instead of from focus joint since joint may be offset, which can cause us to bounce between two angles - dir = focusPos - orientationJointPos; - newLookAng.yaw = idMath::AngleNormalize180( dir.ToYaw() - orientationJointYaw ); - newLookAng.roll = 0.0f; - newLookAng.pitch = 0.0f; - -#if 0 - gameRenderWorld->DebugLine( colorRed, orientationJointPos, focusPos, gameLocal.msec ); - gameRenderWorld->DebugLine( colorYellow, orientationJointPos, orientationJointPos + orientationJointAxis[ 0 ] * 32.0f, gameLocal.msec ); - gameRenderWorld->DebugLine( colorGreen, orientationJointPos, orientationJointPos + newLookAng.ToForward() * 48.0f, gameLocal.msec ); -#endif - - // determine pitch from joint position - dir = focusPos - eyepos; - dir.NormalizeFast(); - orientationJointAxis.ProjectVector( dir, localDir ); - newLookAng.pitch = -idMath::AngleNormalize180( localDir.ToPitch() ); - newLookAng.roll = 0.0f; - - diff = newLookAng - lookAng; - - if ( eyeAng != diff ) { - eyeAng = diff; - eyeAng.Clamp( eyeMin, eyeMax ); - idAngles angDelta = diff - eyeAng; - if ( !angDelta.Compare( ang_zero, 0.1f ) ) { - alignHeadTime = gameLocal.time; - } else { - alignHeadTime = gameLocal.time + ( 0.5f + 0.5f * gameLocal.random.RandomFloat() ) * focusAlignTime; - } - } - - if ( idMath::Fabs( newLookAng.yaw ) < 0.1f ) { - alignHeadTime = gameLocal.time; - } - - if ( ( gameLocal.time >= alignHeadTime ) || ( gameLocal.time < forceAlignHeadTime ) ) { - alignHeadTime = gameLocal.time + ( 0.5f + 0.5f * gameLocal.random.RandomFloat() ) * focusAlignTime; - destLookAng = newLookAng; - destLookAng.Clamp( lookMin, lookMax ); - } - - diff = destLookAng - lookAng; - if ( ( lookMin.pitch == -180.0f ) && ( lookMax.pitch == 180.0f ) ) { - if ( ( diff.pitch > 180.0f ) || ( diff.pitch <= -180.0f ) ) { - diff.pitch = 360.0f - diff.pitch; - } - } - if ( ( lookMin.yaw == -180.0f ) && ( lookMax.yaw == 180.0f ) ) { - if ( diff.yaw > 180.0f ) { - diff.yaw -= 360.0f; - } else if ( diff.yaw <= -180.0f ) { - diff.yaw += 360.0f; - } - } - lookAng = lookAng + diff * headFocusRate; - lookAng.Normalize180(); - - jointAng.roll = 0.0f; - for( i = 0; i < lookJoints.Num(); i++ ) { - jointAng.pitch = lookAng.pitch * lookJointAngles[ i ].pitch; - jointAng.yaw = lookAng.yaw * lookJointAngles[ i ].yaw; - animator.SetJointAxis( lookJoints[ i ], JOINTMOD_WORLD, jointAng.ToMat3() ); - } - - if ( move.moveType == MOVETYPE_FLY ) { - // lean into turns - AdjustFlyingAngles(); - } - - if ( headEnt ) { - idAnimator *headAnimator = headEnt->GetAnimator(); - - if ( allowEyeFocus ) { - idMat3 eyeAxis = ( lookAng + eyeAng ).ToMat3(); idMat3 headTranspose = headEnt->GetPhysics()->GetAxis().Transpose(); - axis = eyeAxis * orientationJointAxis; - left = axis[ 1 ] * eyeHorizontalOffset; - eyepos -= headEnt->GetPhysics()->GetOrigin(); - headAnimator->SetJointPos( leftEyeJoint, JOINTMOD_WORLD_OVERRIDE, eyepos + ( axis[ 0 ] * 64.0f + left ) * headTranspose ); - headAnimator->SetJointPos( rightEyeJoint, JOINTMOD_WORLD_OVERRIDE, eyepos + ( axis[ 0 ] * 64.0f - left ) * headTranspose ); - } else { - headAnimator->ClearJoint( leftEyeJoint ); - headAnimator->ClearJoint( rightEyeJoint ); - } - } else { - if ( allowEyeFocus ) { - idMat3 eyeAxis = ( lookAng + eyeAng ).ToMat3(); - axis = eyeAxis * orientationJointAxis; - left = axis[ 1 ] * eyeHorizontalOffset; - eyepos += axis[ 0 ] * 64.0f - physicsObj.GetOrigin(); - animator.SetJointPos( leftEyeJoint, JOINTMOD_WORLD_OVERRIDE, eyepos + left ); - animator.SetJointPos( rightEyeJoint, JOINTMOD_WORLD_OVERRIDE, eyepos - left ); - } else { - animator.ClearJoint( leftEyeJoint ); - animator.ClearJoint( rightEyeJoint ); - } - } - - return true; -} - -/*********************************************************************** - -idCombatNode - -***********************************************************************/ - -const idEventDef EV_CombatNode_MarkUsed( "markUsed" ); - -CLASS_DECLARATION( idEntity, idCombatNode ) - EVENT( EV_CombatNode_MarkUsed, idCombatNode::Event_MarkUsed ) - EVENT( EV_Activate, idCombatNode::Event_Activate ) -END_CLASS - -/* -===================== -idCombatNode::idCombatNode -===================== -*/ -idCombatNode::idCombatNode( void ) { - min_dist = 0.0f; - max_dist = 0.0f; - cone_dist = 0.0f; - min_height = 0.0f; - max_height = 0.0f; - cone_left.Zero(); - cone_right.Zero(); - offset.Zero(); - disabled = false; -} - -/* -===================== -idCombatNode::Save -===================== -*/ -void idCombatNode::Save( idSaveGame *savefile ) const { - savefile->WriteFloat( min_dist ); - savefile->WriteFloat( max_dist ); - savefile->WriteFloat( cone_dist ); - savefile->WriteFloat( min_height ); - savefile->WriteFloat( max_height ); - savefile->WriteVec3( cone_left ); - savefile->WriteVec3( cone_right ); - savefile->WriteVec3( offset ); - savefile->WriteBool( disabled ); -} - -/* -===================== -idCombatNode::Restore -===================== -*/ -void idCombatNode::Restore( idRestoreGame *savefile ) { - savefile->ReadFloat( min_dist ); - savefile->ReadFloat( max_dist ); - savefile->ReadFloat( cone_dist ); - savefile->ReadFloat( min_height ); - savefile->ReadFloat( max_height ); - savefile->ReadVec3( cone_left ); - savefile->ReadVec3( cone_right ); - savefile->ReadVec3( offset ); - savefile->ReadBool( disabled ); -} - -/* -===================== -idCombatNode::Spawn -===================== -*/ -void idCombatNode::Spawn( void ) { - float fov; - float yaw; - float height; - - min_dist = spawnArgs.GetFloat( "min" ); - max_dist = spawnArgs.GetFloat( "max" ); - height = spawnArgs.GetFloat( "height" ); - fov = spawnArgs.GetFloat( "fov", "60" ); - offset = spawnArgs.GetVector( "offset" ); - - const idVec3 &org = GetPhysics()->GetOrigin() + offset; - min_height = org.z - height * 0.5f; - max_height = min_height + height; - - const idMat3 &axis = GetPhysics()->GetAxis(); - yaw = axis[ 0 ].ToYaw(); - - idAngles leftang( 0.0f, yaw + fov * 0.5f - 90.0f, 0.0f ); - cone_left = leftang.ToForward(); - - idAngles rightang( 0.0f, yaw - fov * 0.5f + 90.0f, 0.0f ); - cone_right = rightang.ToForward(); - - disabled = spawnArgs.GetBool( "start_off" ); -} - -/* -===================== -idCombatNode::IsDisabled -===================== -*/ -bool idCombatNode::IsDisabled( void ) const { - return disabled; -} - -/* -===================== -idCombatNode::DrawDebugInfo -===================== -*/ -void idCombatNode::DrawDebugInfo( void ) { - idEntity *ent; - idCombatNode *node; - idPlayer *player = gameLocal.GetLocalPlayer(); - idVec4 color; - idBounds bounds( idVec3( -16, -16, 0 ), idVec3( 16, 16, 0 ) ); - - for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) { - if ( !ent->IsType( idCombatNode::Type ) ) { - continue; - } - - node = static_cast( ent ); - if ( node->disabled ) { - color = colorMdGrey; - } else if ( player && node->EntityInView( player, player->GetPhysics()->GetOrigin() ) ) { - color = colorYellow; - } else { - color = colorRed; - } - - idVec3 leftDir( -node->cone_left.y, node->cone_left.x, 0.0f ); - idVec3 rightDir( node->cone_right.y, -node->cone_right.x, 0.0f ); - idVec3 org = node->GetPhysics()->GetOrigin() + node->offset; - - bounds[ 1 ].z = node->max_height; - - leftDir.NormalizeFast(); - rightDir.NormalizeFast(); - - const idMat3 &axis = node->GetPhysics()->GetAxis(); - float cone_dot = node->cone_right * axis[ 1 ]; - if ( idMath::Fabs( cone_dot ) > 0.1 ) { - float cone_dist = node->max_dist / cone_dot; - idVec3 pos1 = org + leftDir * node->min_dist; - idVec3 pos2 = org + leftDir * cone_dist; - idVec3 pos3 = org + rightDir * node->min_dist; - idVec3 pos4 = org + rightDir * cone_dist; - - gameRenderWorld->DebugLine( color, node->GetPhysics()->GetOrigin(), ( pos1 + pos3 ) * 0.5f, gameLocal.msec ); - gameRenderWorld->DebugLine( color, pos1, pos2, gameLocal.msec ); - gameRenderWorld->DebugLine( color, pos1, pos3, gameLocal.msec ); - gameRenderWorld->DebugLine( color, pos3, pos4, gameLocal.msec ); - gameRenderWorld->DebugLine( color, pos2, pos4, gameLocal.msec ); - gameRenderWorld->DebugBounds( color, bounds, org, gameLocal.msec ); - } - } -} - -/* -===================== -idCombatNode::EntityInView -===================== -*/ -bool idCombatNode::EntityInView( idActor *actor, const idVec3 &pos ) { - if ( !actor || ( actor->health <= 0 ) ) { - return false; - } - - const idBounds &bounds = actor->GetPhysics()->GetBounds(); - if ( ( pos.z + bounds[ 1 ].z < min_height ) || ( pos.z + bounds[ 0 ].z >= max_height ) ) { - return false; - } - - const idVec3 &org = GetPhysics()->GetOrigin() + offset; - const idMat3 &axis = GetPhysics()->GetAxis(); - idVec3 dir = pos - org; - float dist = dir * axis[ 0 ]; - - if ( ( dist < min_dist ) || ( dist > max_dist ) ) { - return false; - } - - float left_dot = dir * cone_left; - if ( left_dot < 0.0f ) { - return false; - } - - float right_dot = dir * cone_right; - if ( right_dot < 0.0f ) { - return false; - } - - return true; -} - -/* -===================== -idCombatNode::Event_Activate -===================== -*/ -void idCombatNode::Event_Activate( idEntity *activator ) { - disabled = !disabled; -} - -/* -===================== -idCombatNode::Event_MarkUsed -===================== -*/ -void idCombatNode::Event_MarkUsed( void ) { - if ( spawnArgs.GetBool( "use_once" ) ) { - disabled = true; - } -} diff --git a/d3xp/ai/AI.h b/d3xp/ai/AI.h deleted file mode 100644 index 7264869a..00000000 --- a/d3xp/ai/AI.h +++ /dev/null @@ -1,745 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __AI_H__ -#define __AI_H__ - -#include "physics/Physics_Monster.h" -#include "Entity.h" -#include "Actor.h" -#include "Projectile.h" - -class idFuncEmitter; - -/* -=============================================================================== - - idAI - -=============================================================================== -*/ - -const float SQUARE_ROOT_OF_2 = 1.414213562f; -const float AI_TURN_PREDICTION = 0.2f; -const float AI_TURN_SCALE = 60.0f; -const float AI_SEEK_PREDICTION = 0.3f; -const float AI_FLY_DAMPENING = 0.15f; -const float AI_HEARING_RANGE = 2048.0f; -const int DEFAULT_FLY_OFFSET = 68; - -#define ATTACK_IGNORE 0 -#define ATTACK_ON_DAMAGE 1 -#define ATTACK_ON_ACTIVATE 2 -#define ATTACK_ON_SIGHT 4 - -// defined in script/ai_base.script. please keep them up to date. -typedef enum { - MOVETYPE_DEAD, - MOVETYPE_ANIM, - MOVETYPE_SLIDE, - MOVETYPE_FLY, - MOVETYPE_STATIC, - NUM_MOVETYPES -} moveType_t; - -typedef enum { - MOVE_NONE, - MOVE_FACE_ENEMY, - MOVE_FACE_ENTITY, - - // commands < NUM_NONMOVING_COMMANDS don't cause a change in position - NUM_NONMOVING_COMMANDS, - - MOVE_TO_ENEMY = NUM_NONMOVING_COMMANDS, - MOVE_TO_ENEMYHEIGHT, - MOVE_TO_ENTITY, - MOVE_OUT_OF_RANGE, - MOVE_TO_ATTACK_POSITION, - MOVE_TO_COVER, - MOVE_TO_POSITION, - MOVE_TO_POSITION_DIRECT, - MOVE_SLIDE_TO_POSITION, - MOVE_WANDER, - NUM_MOVE_COMMANDS -} moveCommand_t; - -typedef enum { - TALK_NEVER, - TALK_DEAD, - TALK_OK, - TALK_BUSY, - NUM_TALK_STATES -} talkState_t; - -// -// status results from move commands -// make sure to change script/doom_defs.script if you add any, or change their order -// -typedef enum { - MOVE_STATUS_DONE, - MOVE_STATUS_MOVING, - MOVE_STATUS_WAITING, - MOVE_STATUS_DEST_NOT_FOUND, - MOVE_STATUS_DEST_UNREACHABLE, - MOVE_STATUS_BLOCKED_BY_WALL, - MOVE_STATUS_BLOCKED_BY_OBJECT, - MOVE_STATUS_BLOCKED_BY_ENEMY, - MOVE_STATUS_BLOCKED_BY_MONSTER -} moveStatus_t; - -#define DI_NODIR -1 - -// obstacle avoidance -typedef struct obstaclePath_s { - idVec3 seekPos; // seek position avoiding obstacles - idEntity * firstObstacle; // if != NULL the first obstacle along the path - idVec3 startPosOutsideObstacles; // start position outside obstacles - idEntity * startPosObstacle; // if != NULL the obstacle containing the start position - idVec3 seekPosOutsideObstacles; // seek position outside obstacles - idEntity * seekPosObstacle; // if != NULL the obstacle containing the seek position -} obstaclePath_t; - -// path prediction -typedef enum { - SE_BLOCKED = BIT(0), - SE_ENTER_LEDGE_AREA = BIT(1), - SE_ENTER_OBSTACLE = BIT(2), - SE_FALL = BIT(3), - SE_LAND = BIT(4) -} stopEvent_t; - -typedef struct predictedPath_s { - idVec3 endPos; // final position - idVec3 endVelocity; // velocity at end position - idVec3 endNormal; // normal of blocking surface - int endTime; // time predicted - int endEvent; // event that stopped the prediction - const idEntity * blockingEntity; // entity that blocks the movement -} predictedPath_t; - -// -// events -// -extern const idEventDef AI_BeginAttack; -extern const idEventDef AI_EndAttack; -extern const idEventDef AI_MuzzleFlash; -extern const idEventDef AI_CreateMissile; -extern const idEventDef AI_AttackMissile; -extern const idEventDef AI_FireMissileAtTarget; -#ifdef _D3XP -extern const idEventDef AI_LaunchProjectile; -extern const idEventDef AI_TriggerFX; -extern const idEventDef AI_StartEmitter; -extern const idEventDef AI_StopEmitter; -#endif -extern const idEventDef AI_AttackMelee; -extern const idEventDef AI_DirectDamage; -extern const idEventDef AI_JumpFrame; -extern const idEventDef AI_EnableClip; -extern const idEventDef AI_DisableClip; -extern const idEventDef AI_EnableGravity; -extern const idEventDef AI_DisableGravity; -extern const idEventDef AI_TriggerParticles; -extern const idEventDef AI_RandomPath; - -class idPathCorner; - -typedef struct particleEmitter_s { - particleEmitter_s() { - particle = NULL; - time = 0; - joint = INVALID_JOINT; - }; - const idDeclParticle *particle; - int time; - jointHandle_t joint; -} particleEmitter_t; - -#ifdef _D3XP -typedef struct funcEmitter_s { - char name[64]; - idFuncEmitter* particle; - jointHandle_t joint; -} funcEmitter_t; -#endif - -class idMoveState { -public: - idMoveState(); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - moveType_t moveType; - moveCommand_t moveCommand; - moveStatus_t moveStatus; - idVec3 moveDest; - idVec3 moveDir; // used for wandering and slide moves - idEntityPtr goalEntity; - idVec3 goalEntityOrigin; // move to entity uses this to avoid checking the floor position every frame - int toAreaNum; - int startTime; - int duration; - float speed; // only used by flying creatures - float range; - float wanderYaw; - int nextWanderTime; - int blockTime; - idEntityPtr obstacle; - idVec3 lastMoveOrigin; - int lastMoveTime; - int anim; -}; - -class idAASFindCover : public idAASCallback { -public: - idAASFindCover( const idVec3 &hideFromPos ); - ~idAASFindCover(); - - virtual bool TestArea( const idAAS *aas, int areaNum ); - -private: - pvsHandle_t hidePVS; - int PVSAreas[ idEntity::MAX_PVS_AREAS ]; -}; - -class idAASFindAreaOutOfRange : public idAASCallback { -public: - idAASFindAreaOutOfRange( const idVec3 &targetPos, float maxDist ); - - virtual bool TestArea( const idAAS *aas, int areaNum ); - -private: - idVec3 targetPos; - float maxDistSqr; -}; - -class idAI; - -class idAASFindAttackPosition : public idAASCallback { -public: - idAASFindAttackPosition( const idAI *self, const idMat3 &gravityAxis, idEntity *target, const idVec3 &targetPos, const idVec3 &fireOffset ); - ~idAASFindAttackPosition(); - - virtual bool TestArea( const idAAS *aas, int areaNum ); - -private: - const idAI *self; - idEntity *target; - idBounds excludeBounds; - idVec3 targetPos; - idVec3 fireOffset; - idMat3 gravityAxis; - pvsHandle_t targetPVS; - int PVSAreas[ idEntity::MAX_PVS_AREAS ]; -}; - -class idAI : public idActor { -public: - CLASS_PROTOTYPE( idAI ); - - idAI(); - ~idAI(); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void Spawn( void ); - void HeardSound( idEntity *ent, const char *action ); - idActor *GetEnemy( void ) const; - void TalkTo( idActor *actor ); - talkState_t GetTalkState( void ) const; - - bool GetAimDir( const idVec3 &firePos, idEntity *aimAtEnt, const idEntity *ignore, idVec3 &aimDir ) const; - - void TouchedByFlashlight( idActor *flashlight_owner ); - - // Outputs a list of all monsters to the console. - static void List_f( const idCmdArgs &args ); - - // Finds a path around dynamic obstacles. - static bool FindPathAroundObstacles( const idPhysics *physics, const idAAS *aas, const idEntity *ignore, const idVec3 &startPos, const idVec3 &seekPos, obstaclePath_t &path ); - // Frees any nodes used for the dynamic obstacle avoidance. - static void FreeObstacleAvoidanceNodes( void ); - // Predicts movement, returns true if a stop event was triggered. - static bool PredictPath( const idEntity *ent, const idAAS *aas, const idVec3 &start, const idVec3 &velocity, int totalTime, int frameTime, int stopEvent, predictedPath_t &path ); - // Return true if the trajectory of the clip model is collision free. - static bool TestTrajectory( const idVec3 &start, const idVec3 &end, float zVel, float gravity, float time, float max_height, const idClipModel *clip, int clipmask, const idEntity *ignore, const idEntity *targetEntity, int drawtime ); - // Finds the best collision free trajectory for a clip model. - static bool PredictTrajectory( const idVec3 &firePos, const idVec3 &target, float projectileSpeed, const idVec3 &projGravity, const idClipModel *clip, int clipmask, float max_height, const idEntity *ignore, const idEntity *targetEntity, int drawtime, idVec3 &aimDir ); - -#ifdef _D3XP - virtual void Gib( const idVec3 &dir, const char *damageDefName ); -#endif - -protected: - // navigation - idAAS * aas; - int travelFlags; - - idMoveState move; - idMoveState savedMove; - - float kickForce; - bool ignore_obstacles; - float blockedRadius; - int blockedMoveTime; - int blockedAttackTime; - - // turning - float ideal_yaw; - float current_yaw; - float turnRate; - float turnVel; - float anim_turn_yaw; - float anim_turn_amount; - float anim_turn_angles; - - // physics - idPhysics_Monster physicsObj; - - // flying - jointHandle_t flyTiltJoint; - float fly_speed; - float fly_bob_strength; - float fly_bob_vert; - float fly_bob_horz; - int fly_offset; // prefered offset from player's view - float fly_seek_scale; - float fly_roll_scale; - float fly_roll_max; - float fly_roll; - float fly_pitch_scale; - float fly_pitch_max; - float fly_pitch; - - bool allowMove; // disables any animation movement - bool allowHiddenMovement; // allows character to still move around while hidden - bool disableGravity; // disables gravity and allows vertical movement by the animation - bool af_push_moveables; // allow the articulated figure to push moveable objects - - // weapon/attack vars - bool lastHitCheckResult; - int lastHitCheckTime; - int lastAttackTime; - float melee_range; - float projectile_height_to_distance_ratio; // calculates the maximum height a projectile can be thrown - idList missileLaunchOffset; - - const idDict * projectileDef; - mutable idClipModel *projectileClipModel; - float projectileRadius; - float projectileSpeed; - idVec3 projectileVelocity; - idVec3 projectileGravity; - idEntityPtr projectile; - idStr attack; - - // chatter/talking - const idSoundShader *chat_snd; - int chat_min; - int chat_max; - int chat_time; - talkState_t talk_state; - idEntityPtr talkTarget; - - // cinematics - int num_cinematics; - int current_cinematic; - - bool allowJointMod; - idEntityPtr focusEntity; - idVec3 currentFocusPos; - int focusTime; - int alignHeadTime; - int forceAlignHeadTime; - idAngles eyeAng; - idAngles lookAng; - idAngles destLookAng; - idAngles lookMin; - idAngles lookMax; - idList lookJoints; - idList lookJointAngles; - float eyeVerticalOffset; - float eyeHorizontalOffset; - float eyeFocusRate; - float headFocusRate; - int focusAlignTime; - - // special fx - float shrivel_rate; - int shrivel_start; - - bool restartParticles; // should smoke emissions restart - bool useBoneAxis; // use the bone vs the model axis - idList particles; // particle data - - renderLight_t worldMuzzleFlash; // positioned on world weapon bone - int worldMuzzleFlashHandle; - jointHandle_t flashJointWorld; - int muzzleFlashEnd; - int flashTime; - - // joint controllers - idAngles eyeMin; - idAngles eyeMax; - jointHandle_t focusJoint; - jointHandle_t orientationJoint; - - // enemy variables - idEntityPtr enemy; - idVec3 lastVisibleEnemyPos; - idVec3 lastVisibleEnemyEyeOffset; - idVec3 lastVisibleReachableEnemyPos; - idVec3 lastReachableEnemyPos; - bool wakeOnFlashlight; - -#ifdef _D3XP - bool spawnClearMoveables; - - idHashTable funcEmitters; - - idEntityPtr harvestEnt; -#endif - - // script variables - idScriptBool AI_TALK; - idScriptBool AI_DAMAGE; - idScriptBool AI_PAIN; - idScriptFloat AI_SPECIAL_DAMAGE; - idScriptBool AI_DEAD; - idScriptBool AI_ENEMY_VISIBLE; - idScriptBool AI_ENEMY_IN_FOV; - idScriptBool AI_ENEMY_DEAD; - idScriptBool AI_MOVE_DONE; - idScriptBool AI_ONGROUND; - idScriptBool AI_ACTIVATED; - idScriptBool AI_FORWARD; - idScriptBool AI_JUMP; - idScriptBool AI_ENEMY_REACHABLE; - idScriptBool AI_BLOCKED; - idScriptBool AI_OBSTACLE_IN_PATH; - idScriptBool AI_DEST_UNREACHABLE; - idScriptBool AI_HIT_ENEMY; - idScriptBool AI_PUSHED; - - // - // ai/ai.cpp - // - void SetAAS( void ); - virtual void DormantBegin( void ); // called when entity becomes dormant - virtual void DormantEnd( void ); // called when entity wakes from being dormant - void Think( void ); - void Activate( idEntity *activator ); - int ReactionTo( const idEntity *ent ); - bool CheckForEnemy( void ); - void EnemyDead( void ); - virtual bool CanPlayChatterSounds( void ) const; - void SetChatSound( void ); - void PlayChatter( void ); - virtual void Hide( void ); - virtual void Show( void ); - idVec3 FirstVisiblePointOnPath( const idVec3 origin, const idVec3 &target, int travelFlags ) const; - void CalculateAttackOffsets( void ); - void PlayCinematic( void ); - - // movement - virtual void ApplyImpulse( idEntity *ent, int id, const idVec3 &point, const idVec3 &impulse ); - void GetMoveDelta( const idMat3 &oldaxis, const idMat3 &axis, idVec3 &delta ); - void CheckObstacleAvoidance( const idVec3 &goalPos, idVec3 &newPos ); - void DeadMove( void ); - void AnimMove( void ); - void SlideMove( void ); - void AdjustFlyingAngles( void ); - void AddFlyBob( idVec3 &vel ); - void AdjustFlyHeight( idVec3 &vel, const idVec3 &goalPos ); - void FlySeekGoal( idVec3 &vel, idVec3 &goalPos ); - void AdjustFlySpeed( idVec3 &vel ); - void FlyTurn( void ); - void FlyMove( void ); - void StaticMove( void ); - - // damage - virtual bool Pain( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ); - virtual void Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ); - - // navigation - void KickObstacles( const idVec3 &dir, float force, idEntity *alwaysKick ); - bool ReachedPos( const idVec3 &pos, const moveCommand_t moveCommand ) const; - float TravelDistance( const idVec3 &start, const idVec3 &end ) const; - int PointReachableAreaNum( const idVec3 &pos, const float boundsScale = 2.0f ) const; - bool PathToGoal( aasPath_t &path, int areaNum, const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin ) const; - void DrawRoute( void ) const; - bool GetMovePos( idVec3 &seekPos ); - bool MoveDone( void ) const; - bool EntityCanSeePos( idActor *actor, const idVec3 &actorOrigin, const idVec3 &pos ); - void BlockedFailSafe( void ); - - // movement control - void StopMove( moveStatus_t status ); - bool FaceEnemy( void ); - bool FaceEntity( idEntity *ent ); - bool DirectMoveToPosition( const idVec3 &pos ); - bool MoveToEnemyHeight( void ); - bool MoveOutOfRange( idEntity *entity, float range ); - bool MoveToAttackPosition( idEntity *ent, int attack_anim ); - bool MoveToEnemy( void ); - bool MoveToEntity( idEntity *ent ); - bool MoveToPosition( const idVec3 &pos ); - bool MoveToCover( idEntity *entity, const idVec3 &pos ); - bool SlideToPosition( const idVec3 &pos, float time ); - bool WanderAround( void ); - bool StepDirection( float dir ); - bool NewWanderDir( const idVec3 &dest ); - - // effects - const idDeclParticle *SpawnParticlesOnJoint( particleEmitter_t &pe, const char *particleName, const char *jointName ); - void SpawnParticles( const char *keyName ); - bool ParticlesActive( void ); - - // turning - bool FacingIdeal( void ); - void Turn( void ); - bool TurnToward( float yaw ); - bool TurnToward( const idVec3 &pos ); - - // enemy management - void ClearEnemy( void ); - bool EnemyPositionValid( void ) const; - void SetEnemyPosition( void ); - void UpdateEnemyPosition( void ); - void SetEnemy( idActor *newEnemy ); - - // attacks - void CreateProjectileClipModel( void ) const; - idProjectile *CreateProjectile( const idVec3 &pos, const idVec3 &dir ); - void RemoveProjectile( void ); - idProjectile *LaunchProjectile( const char *jointname, idEntity *target, bool clampToAttackCone ); - virtual void DamageFeedback( idEntity *victim, idEntity *inflictor, int &damage ); - void DirectDamage( const char *meleeDefName, idEntity *ent ); - bool TestMelee( void ) const; - bool AttackMelee( const char *meleeDefName ); - void BeginAttack( const char *name ); - void EndAttack( void ); - void PushWithAF( void ); - - // special effects - void GetMuzzle( const char *jointname, idVec3 &muzzle, idMat3 &axis ); - void InitMuzzleFlash( void ); - void TriggerWeaponEffects( const idVec3 &muzzle ); - void UpdateMuzzleFlash( void ); - virtual bool UpdateAnimationControllers( void ); - void UpdateParticles( void ); - void TriggerParticles( const char *jointName ); - -#ifdef _D3XP - void TriggerFX( const char* joint, const char* fx ); - idEntity* StartEmitter( const char* name, const char* joint, const char* particle ); - idEntity* GetEmitter( const char* name ); - void StopEmitter( const char* name ); -#endif - - // AI script state management - void LinkScriptVariables( void ); - void UpdateAIScript( void ); - - // - // ai/ai_events.cpp - // - void Event_Activate( idEntity *activator ); - void Event_Touch( idEntity *other, trace_t *trace ); - void Event_FindEnemy( int useFOV ); - void Event_FindEnemyAI( int useFOV ); - void Event_FindEnemyInCombatNodes( void ); - void Event_ClosestReachableEnemyOfEntity( idEntity *team_mate ); - void Event_HeardSound( int ignore_team ); - void Event_SetEnemy( idEntity *ent ); - void Event_ClearEnemy( void ); - void Event_MuzzleFlash( const char *jointname ); - void Event_CreateMissile( const char *jointname ); - void Event_AttackMissile( const char *jointname ); - void Event_FireMissileAtTarget( const char *jointname, const char *targetname ); - void Event_LaunchMissile( const idVec3 &muzzle, const idAngles &ang ); -#ifdef _D3XP - void Event_LaunchProjectile( const char *entityDefName ); -#endif - void Event_AttackMelee( const char *meleeDefName ); - void Event_DirectDamage( idEntity *damageTarget, const char *damageDefName ); - void Event_RadiusDamageFromJoint( const char *jointname, const char *damageDefName ); - void Event_BeginAttack( const char *name ); - void Event_EndAttack( void ); - void Event_MeleeAttackToJoint( const char *jointname, const char *meleeDefName ); - void Event_RandomPath( void ); - void Event_CanBecomeSolid( void ); - void Event_BecomeSolid( void ); - void Event_BecomeNonSolid( void ); - void Event_BecomeRagdoll( void ); - void Event_StopRagdoll( void ); - void Event_SetHealth( float newHealth ); - void Event_GetHealth( void ); - void Event_AllowDamage( void ); - void Event_IgnoreDamage( void ); - void Event_GetCurrentYaw( void ); - void Event_TurnTo( float angle ); - void Event_TurnToPos( const idVec3 &pos ); - void Event_TurnToEntity( idEntity *ent ); - void Event_MoveStatus( void ); - void Event_StopMove( void ); - void Event_MoveToCover( void ); - void Event_MoveToEnemy( void ); - void Event_MoveToEnemyHeight( void ); - void Event_MoveOutOfRange( idEntity *entity, float range ); - void Event_MoveToAttackPosition( idEntity *entity, const char *attack_anim ); - void Event_MoveToEntity( idEntity *ent ); - void Event_MoveToPosition( const idVec3 &pos ); - void Event_SlideTo( const idVec3 &pos, float time ); - void Event_Wander( void ); - void Event_FacingIdeal( void ); - void Event_FaceEnemy( void ); - void Event_FaceEntity( idEntity *ent ); - void Event_WaitAction( const char *waitForState ); - void Event_GetCombatNode( void ); - void Event_EnemyInCombatCone( idEntity *ent, int use_current_enemy_location ); - void Event_WaitMove( void ); - void Event_GetJumpVelocity( const idVec3 &pos, float speed, float max_height ); - void Event_EntityInAttackCone( idEntity *ent ); - void Event_CanSeeEntity( idEntity *ent ); - void Event_SetTalkTarget( idEntity *target ); - void Event_GetTalkTarget( void ); - void Event_SetTalkState( int state ); - void Event_EnemyRange( void ); - void Event_EnemyRange2D( void ); - void Event_GetEnemy( void ); - void Event_GetEnemyPos( void ); - void Event_GetEnemyEyePos( void ); - void Event_PredictEnemyPos( float time ); - void Event_CanHitEnemy( void ); - void Event_CanHitEnemyFromAnim( const char *animname ); - void Event_CanHitEnemyFromJoint( const char *jointname ); - void Event_EnemyPositionValid( void ); - void Event_ChargeAttack( const char *damageDef ); - void Event_TestChargeAttack( void ); - void Event_TestAnimMoveTowardEnemy( const char *animname ); - void Event_TestAnimMove( const char *animname ); - void Event_TestMoveToPosition( const idVec3 &position ); - void Event_TestMeleeAttack( void ); - void Event_TestAnimAttack( const char *animname ); - void Event_Shrivel( float shirvel_time ); - void Event_Burn( void ); - void Event_PreBurn( void ); - void Event_ClearBurn( void ); - void Event_SetSmokeVisibility( int num, int on ); - void Event_NumSmokeEmitters( void ); - void Event_StopThinking( void ); - void Event_GetTurnDelta( void ); - void Event_GetMoveType( void ); - void Event_SetMoveType( int moveType ); - void Event_SaveMove( void ); - void Event_RestoreMove( void ); - void Event_AllowMovement( float flag ); - void Event_JumpFrame( void ); - void Event_EnableClip( void ); - void Event_DisableClip( void ); - void Event_EnableGravity( void ); - void Event_DisableGravity( void ); - void Event_EnableAFPush( void ); - void Event_DisableAFPush( void ); - void Event_SetFlySpeed( float speed ); - void Event_SetFlyOffset( int offset ); - void Event_ClearFlyOffset( void ); - void Event_GetClosestHiddenTarget( const char *type ); - void Event_GetRandomTarget( const char *type ); - void Event_TravelDistanceToPoint( const idVec3 &pos ); - void Event_TravelDistanceToEntity( idEntity *ent ); - void Event_TravelDistanceBetweenPoints( const idVec3 &source, const idVec3 &dest ); - void Event_TravelDistanceBetweenEntities( idEntity *source, idEntity *dest ); - void Event_LookAtEntity( idEntity *ent, float duration ); - void Event_LookAtEnemy( float duration ); - void Event_SetJointMod( int allowJointMod ); - void Event_ThrowMoveable( void ); - void Event_ThrowAF( void ); - void Event_SetAngles( idAngles const &ang ); - void Event_GetAngles( void ); - void Event_RealKill( void ); - void Event_Kill( void ); - void Event_WakeOnFlashlight( int enable ); - void Event_LocateEnemy( void ); - void Event_KickObstacles( idEntity *kickEnt, float force ); - void Event_GetObstacle( void ); - void Event_PushPointIntoAAS( const idVec3 &pos ); - void Event_GetTurnRate( void ); - void Event_SetTurnRate( float rate ); - void Event_AnimTurn( float angles ); - void Event_AllowHiddenMovement( int enable ); - void Event_TriggerParticles( const char *jointName ); - void Event_FindActorsInBounds( const idVec3 &mins, const idVec3 &maxs ); - void Event_CanReachPosition( const idVec3 &pos ); - void Event_CanReachEntity( idEntity *ent ); - void Event_CanReachEnemy( void ); - void Event_GetReachableEntityPosition( idEntity *ent ); -#ifdef _D3XP - void Event_MoveToPositionDirect( const idVec3 &pos ); - void Event_AvoidObstacles( int ignore); - void Event_TriggerFX( const char* joint, const char* fx ); - - void Event_StartEmitter( const char* name, const char* joint, const char* particle ); - void Event_GetEmitter( const char* name ); - void Event_StopEmitter( const char* name ); -#endif -}; - -class idCombatNode : public idEntity { -public: - CLASS_PROTOTYPE( idCombatNode ); - - idCombatNode(); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void Spawn( void ); - bool IsDisabled( void ) const; - bool EntityInView( idActor *actor, const idVec3 &pos ); - static void DrawDebugInfo( void ); - -private: - float min_dist; - float max_dist; - float cone_dist; - float min_height; - float max_height; - idVec3 cone_left; - idVec3 cone_right; - idVec3 offset; - bool disabled; - - void Event_Activate( idEntity *activator ); - void Event_MarkUsed( void ); -}; - -#endif /* !__AI_H__ */ diff --git a/d3xp/ai/AI_Vagary.cpp b/d3xp/ai/AI_Vagary.cpp deleted file mode 100644 index 6d8463b4..00000000 --- a/d3xp/ai/AI_Vagary.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ -/*********************************************************************** - -game/ai/AI_Vagary.cpp - -Vagary specific AI code - -***********************************************************************/ - -#include "sys/platform.h" -#include "script/Script_Thread.h" - -#include "gamesys/SysCvar.h" -#include "Moveable.h" - -#include "ai/AI.h" - -class idAI_Vagary : public idAI { -public: - CLASS_PROTOTYPE( idAI_Vagary ); - -private: - void Event_ChooseObjectToThrow( const idVec3 &mins, const idVec3 &maxs, float speed, float minDist, float offset ); - void Event_ThrowObjectAtEnemy( idEntity *ent, float speed ); -}; - -const idEventDef AI_Vagary_ChooseObjectToThrow( "vagary_ChooseObjectToThrow", "vvfff", 'e' ); -const idEventDef AI_Vagary_ThrowObjectAtEnemy( "vagary_ThrowObjectAtEnemy", "ef" ); - -CLASS_DECLARATION( idAI, idAI_Vagary ) - EVENT( AI_Vagary_ChooseObjectToThrow, idAI_Vagary::Event_ChooseObjectToThrow ) - EVENT( AI_Vagary_ThrowObjectAtEnemy, idAI_Vagary::Event_ThrowObjectAtEnemy ) -END_CLASS - -/* -================ -idAI_Vagary::Event_ChooseObjectToThrow -================ -*/ -void idAI_Vagary::Event_ChooseObjectToThrow( const idVec3 &mins, const idVec3 &maxs, float speed, float minDist, float offset ) { - idEntity * ent; - idEntity * entityList[ MAX_GENTITIES ]; - int numListedEntities; - int i, index; - float dist; - idVec3 vel; - idVec3 offsetVec( 0, 0, offset ); - idEntity *enemyEnt = enemy.GetEntity(); - - if ( !enemyEnt ) { - idThread::ReturnEntity( NULL ); - } - - idVec3 enemyEyePos = lastVisibleEnemyPos + lastVisibleEnemyEyeOffset; - const idBounds &myBounds = physicsObj.GetAbsBounds(); - idBounds checkBounds( mins, maxs ); - checkBounds.TranslateSelf( physicsObj.GetOrigin() ); - numListedEntities = gameLocal.clip.EntitiesTouchingBounds( checkBounds, -1, entityList, MAX_GENTITIES ); - - index = gameLocal.random.RandomInt( numListedEntities ); - for ( i = 0; i < numListedEntities; i++, index++ ) { - if ( index >= numListedEntities ) { - index = 0; - } - ent = entityList[ index ]; - if ( !ent->IsType( idMoveable::Type ) ) { - continue; - } - - if ( ent->fl.hidden ) { - // don't throw hidden objects - continue; - } - - idPhysics *entPhys = ent->GetPhysics(); - const idVec3 &entOrg = entPhys->GetOrigin(); - dist = ( entOrg - enemyEyePos ).LengthFast(); - if ( dist < minDist ) { - continue; - } - - idBounds expandedBounds = myBounds.Expand( entPhys->GetBounds().GetRadius() ); - if ( expandedBounds.LineIntersection( entOrg, enemyEyePos ) ) { - // ignore objects that are behind us - continue; - } - - if ( PredictTrajectory( entPhys->GetOrigin() + offsetVec, enemyEyePos, speed, entPhys->GetGravity(), - entPhys->GetClipModel(), entPhys->GetClipMask(), MAX_WORLD_SIZE, NULL, enemyEnt, ai_debugTrajectory.GetBool() ? 4000 : 0, vel ) ) { - idThread::ReturnEntity( ent ); - return; - } - } - - idThread::ReturnEntity( NULL ); -} - -/* -================ -idAI_Vagary::Event_ThrowObjectAtEnemy -================ -*/ -void idAI_Vagary::Event_ThrowObjectAtEnemy( idEntity *ent, float speed ) { - idVec3 vel; - idEntity *enemyEnt; - idPhysics *entPhys; - - entPhys = ent->GetPhysics(); - enemyEnt = enemy.GetEntity(); - if ( !enemyEnt ) { - vel = ( viewAxis[ 0 ] * physicsObj.GetGravityAxis() ) * speed; - } else { - PredictTrajectory( entPhys->GetOrigin(), lastVisibleEnemyPos + lastVisibleEnemyEyeOffset, speed, entPhys->GetGravity(), - entPhys->GetClipModel(), entPhys->GetClipMask(), MAX_WORLD_SIZE, NULL, enemyEnt, ai_debugTrajectory.GetBool() ? 4000 : 0, vel ); - vel *= speed; - } - - entPhys->SetLinearVelocity( vel ); - - if ( ent->IsType( idMoveable::Type ) ) { - idMoveable *ment = static_cast( ent ); - ment->EnableDamage( true, 2.5f ); - } -} diff --git a/d3xp/ai/AI_events.cpp b/d3xp/ai/AI_events.cpp deleted file mode 100644 index 15bbced2..00000000 --- a/d3xp/ai/AI_events.cpp +++ /dev/null @@ -1,2906 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "Moveable.h" -#include "Misc.h" - -#include "gamesys/SysCvar.h" -#include "ai/AI.h" - -/*********************************************************************** - - AI Events - -***********************************************************************/ - -const idEventDef AI_FindEnemy( "findEnemy", "d", 'e' ); -const idEventDef AI_FindEnemyAI( "findEnemyAI", "d", 'e' ); -const idEventDef AI_FindEnemyInCombatNodes( "findEnemyInCombatNodes", NULL, 'e' ); -const idEventDef AI_ClosestReachableEnemyOfEntity( "closestReachableEnemyOfEntity", "E", 'e' ); -const idEventDef AI_HeardSound( "heardSound", "d", 'e' ); -const idEventDef AI_SetEnemy( "setEnemy", "E" ); -const idEventDef AI_ClearEnemy( "clearEnemy" ); -const idEventDef AI_MuzzleFlash( "muzzleFlash", "s" ); -const idEventDef AI_CreateMissile( "createMissile", "s", 'e' ); -const idEventDef AI_AttackMissile( "attackMissile", "s", 'e' ); -const idEventDef AI_FireMissileAtTarget( "fireMissileAtTarget", "ss", 'e' ); -const idEventDef AI_LaunchMissile( "launchMissile", "vv", 'e' ); -#ifdef _D3XP -const idEventDef AI_LaunchProjectile( "launchProjectile", "s" ); -#endif -const idEventDef AI_AttackMelee( "attackMelee", "s", 'd' ); -const idEventDef AI_DirectDamage( "directDamage", "es" ); -const idEventDef AI_RadiusDamageFromJoint( "radiusDamageFromJoint", "ss" ); -const idEventDef AI_BeginAttack( "attackBegin", "s" ); -const idEventDef AI_EndAttack( "attackEnd" ); -const idEventDef AI_MeleeAttackToJoint( "meleeAttackToJoint", "ss", 'd' ); -const idEventDef AI_RandomPath( "randomPath", NULL, 'e' ); -const idEventDef AI_CanBecomeSolid( "canBecomeSolid", NULL, 'f' ); -const idEventDef AI_BecomeSolid( "becomeSolid" ); -const idEventDef AI_BecomeRagdoll( "becomeRagdoll", NULL, 'd' ); -const idEventDef AI_StopRagdoll( "stopRagdoll" ); -const idEventDef AI_SetHealth( "setHealth", "f" ); -const idEventDef AI_GetHealth( "getHealth", NULL, 'f' ); -const idEventDef AI_AllowDamage( "allowDamage" ); -const idEventDef AI_IgnoreDamage( "ignoreDamage" ); -const idEventDef AI_GetCurrentYaw( "getCurrentYaw", NULL, 'f' ); -const idEventDef AI_TurnTo( "turnTo", "f" ); -const idEventDef AI_TurnToPos( "turnToPos", "v" ); -const idEventDef AI_TurnToEntity( "turnToEntity", "E" ); -const idEventDef AI_MoveStatus( "moveStatus", NULL, 'd' ); -const idEventDef AI_StopMove( "stopMove" ); -const idEventDef AI_MoveToCover( "moveToCover" ); -const idEventDef AI_MoveToEnemy( "moveToEnemy" ); -const idEventDef AI_MoveToEnemyHeight( "moveToEnemyHeight" ); -const idEventDef AI_MoveOutOfRange( "moveOutOfRange", "ef" ); -const idEventDef AI_MoveToAttackPosition( "moveToAttackPosition", "es" ); -const idEventDef AI_Wander( "wander" ); -const idEventDef AI_MoveToEntity( "moveToEntity", "e" ); -const idEventDef AI_MoveToPosition( "moveToPosition", "v" ); -const idEventDef AI_SlideTo( "slideTo", "vf" ); -const idEventDef AI_FacingIdeal( "facingIdeal", NULL, 'd' ); -const idEventDef AI_FaceEnemy( "faceEnemy" ); -const idEventDef AI_FaceEntity( "faceEntity", "E" ); -const idEventDef AI_GetCombatNode( "getCombatNode", NULL, 'e' ); -const idEventDef AI_EnemyInCombatCone( "enemyInCombatCone", "Ed", 'd' ); -const idEventDef AI_WaitMove( "waitMove" ); -const idEventDef AI_GetJumpVelocity( "getJumpVelocity", "vff", 'v' ); -const idEventDef AI_EntityInAttackCone( "entityInAttackCone", "E", 'd' ); -const idEventDef AI_CanSeeEntity( "canSee", "E", 'd' ); -const idEventDef AI_SetTalkTarget( "setTalkTarget", "E" ); -const idEventDef AI_GetTalkTarget( "getTalkTarget", NULL, 'e' ); -const idEventDef AI_SetTalkState( "setTalkState", "d" ); -const idEventDef AI_EnemyRange( "enemyRange", NULL, 'f' ); -const idEventDef AI_EnemyRange2D( "enemyRange2D", NULL, 'f' ); -const idEventDef AI_GetEnemy( "getEnemy", NULL, 'e' ); -const idEventDef AI_GetEnemyPos( "getEnemyPos", NULL, 'v' ); -const idEventDef AI_GetEnemyEyePos( "getEnemyEyePos", NULL, 'v' ); -const idEventDef AI_PredictEnemyPos( "predictEnemyPos", "f", 'v' ); -const idEventDef AI_CanHitEnemy( "canHitEnemy", NULL, 'd' ); -const idEventDef AI_CanHitEnemyFromAnim( "canHitEnemyFromAnim", "s", 'd' ); -const idEventDef AI_CanHitEnemyFromJoint( "canHitEnemyFromJoint", "s", 'd' ); -const idEventDef AI_EnemyPositionValid( "enemyPositionValid", NULL, 'd' ); -const idEventDef AI_ChargeAttack( "chargeAttack", "s" ); -const idEventDef AI_TestChargeAttack( "testChargeAttack", NULL, 'f' ); -const idEventDef AI_TestMoveToPosition( "testMoveToPosition", "v", 'd' ); -const idEventDef AI_TestAnimMoveTowardEnemy( "testAnimMoveTowardEnemy", "s", 'd' ); -const idEventDef AI_TestAnimMove( "testAnimMove", "s", 'd' ); -const idEventDef AI_TestMeleeAttack( "testMeleeAttack", NULL, 'd' ); -const idEventDef AI_TestAnimAttack( "testAnimAttack", "s", 'd' ); -const idEventDef AI_Shrivel( "shrivel", "f" ); -const idEventDef AI_Burn( "burn" ); -const idEventDef AI_ClearBurn( "clearBurn" ); -const idEventDef AI_PreBurn( "preBurn" ); -const idEventDef AI_SetSmokeVisibility( "setSmokeVisibility", "dd" ); -const idEventDef AI_NumSmokeEmitters( "numSmokeEmitters", NULL, 'd' ); -const idEventDef AI_WaitAction( "waitAction", "s" ); -const idEventDef AI_StopThinking( "stopThinking" ); -const idEventDef AI_GetTurnDelta( "getTurnDelta", NULL, 'f' ); -const idEventDef AI_GetMoveType( "getMoveType", NULL, 'd' ); -const idEventDef AI_SetMoveType( "setMoveType", "d" ); -const idEventDef AI_SaveMove( "saveMove" ); -const idEventDef AI_RestoreMove( "restoreMove" ); -const idEventDef AI_AllowMovement( "allowMovement", "f" ); -const idEventDef AI_JumpFrame( "" ); -const idEventDef AI_EnableClip( "enableClip" ); -const idEventDef AI_DisableClip( "disableClip" ); -const idEventDef AI_EnableGravity( "enableGravity" ); -const idEventDef AI_DisableGravity( "disableGravity" ); -const idEventDef AI_EnableAFPush( "enableAFPush" ); -const idEventDef AI_DisableAFPush( "disableAFPush" ); -const idEventDef AI_SetFlySpeed( "setFlySpeed", "f" ); -const idEventDef AI_SetFlyOffset( "setFlyOffset", "d" ); -const idEventDef AI_ClearFlyOffset( "clearFlyOffset" ); -const idEventDef AI_GetClosestHiddenTarget( "getClosestHiddenTarget", "s", 'e' ); -const idEventDef AI_GetRandomTarget( "getRandomTarget", "s", 'e' ); -const idEventDef AI_TravelDistanceToPoint( "travelDistanceToPoint", "v", 'f' ); -const idEventDef AI_TravelDistanceToEntity( "travelDistanceToEntity", "e", 'f' ); -const idEventDef AI_TravelDistanceBetweenPoints( "travelDistanceBetweenPoints", "vv", 'f' ); -const idEventDef AI_TravelDistanceBetweenEntities( "travelDistanceBetweenEntities", "ee", 'f' ); -const idEventDef AI_LookAtEntity( "lookAt", "Ef" ); -const idEventDef AI_LookAtEnemy( "lookAtEnemy", "f" ); -const idEventDef AI_SetJointMod( "setBoneMod", "d" ); -const idEventDef AI_ThrowMoveable( "throwMoveable" ); -const idEventDef AI_ThrowAF( "throwAF" ); -const idEventDef AI_RealKill( "" ); -const idEventDef AI_Kill( "kill" ); -const idEventDef AI_WakeOnFlashlight( "wakeOnFlashlight", "d" ); -const idEventDef AI_LocateEnemy( "locateEnemy" ); -const idEventDef AI_KickObstacles( "kickObstacles", "Ef" ); -const idEventDef AI_GetObstacle( "getObstacle", NULL, 'e' ); -const idEventDef AI_PushPointIntoAAS( "pushPointIntoAAS", "v", 'v' ); -const idEventDef AI_GetTurnRate( "getTurnRate", NULL, 'f' ); -const idEventDef AI_SetTurnRate( "setTurnRate", "f" ); -const idEventDef AI_AnimTurn( "animTurn", "f" ); -const idEventDef AI_AllowHiddenMovement( "allowHiddenMovement", "d" ); -const idEventDef AI_TriggerParticles( "triggerParticles", "s" ); -const idEventDef AI_FindActorsInBounds( "findActorsInBounds", "vv", 'e' ); -const idEventDef AI_CanReachPosition( "canReachPosition", "v", 'd' ); -const idEventDef AI_CanReachEntity( "canReachEntity", "E", 'd' ); -const idEventDef AI_CanReachEnemy( "canReachEnemy", NULL, 'd' ); -const idEventDef AI_GetReachableEntityPosition( "getReachableEntityPosition", "e", 'v' ); -#ifdef _D3XP -const idEventDef AI_MoveToPositionDirect( "moveToPositionDirect", "v" ); -const idEventDef AI_AvoidObstacles( "avoidObstacles", "d" ); -const idEventDef AI_TriggerFX( "triggerFX", "ss" ); -const idEventDef AI_StartEmitter( "startEmitter", "sss", 'e' ); -const idEventDef AI_GetEmitter( "getEmitter", "s", 'e' ); -const idEventDef AI_StopEmitter( "stopEmitter", "s" ); - - -#endif - -CLASS_DECLARATION( idActor, idAI ) - EVENT( EV_Activate, idAI::Event_Activate ) - EVENT( EV_Touch, idAI::Event_Touch ) - EVENT( AI_FindEnemy, idAI::Event_FindEnemy ) - EVENT( AI_FindEnemyAI, idAI::Event_FindEnemyAI ) - EVENT( AI_FindEnemyInCombatNodes, idAI::Event_FindEnemyInCombatNodes ) - EVENT( AI_ClosestReachableEnemyOfEntity, idAI::Event_ClosestReachableEnemyOfEntity ) - EVENT( AI_HeardSound, idAI::Event_HeardSound ) - EVENT( AI_SetEnemy, idAI::Event_SetEnemy ) - EVENT( AI_ClearEnemy, idAI::Event_ClearEnemy ) - EVENT( AI_MuzzleFlash, idAI::Event_MuzzleFlash ) - EVENT( AI_CreateMissile, idAI::Event_CreateMissile ) - EVENT( AI_AttackMissile, idAI::Event_AttackMissile ) - EVENT( AI_FireMissileAtTarget, idAI::Event_FireMissileAtTarget ) - EVENT( AI_LaunchMissile, idAI::Event_LaunchMissile ) -#ifdef _D3XP - EVENT( AI_LaunchProjectile, idAI::Event_LaunchProjectile ) -#endif - EVENT( AI_AttackMelee, idAI::Event_AttackMelee ) - EVENT( AI_DirectDamage, idAI::Event_DirectDamage ) - EVENT( AI_RadiusDamageFromJoint, idAI::Event_RadiusDamageFromJoint ) - EVENT( AI_BeginAttack, idAI::Event_BeginAttack ) - EVENT( AI_EndAttack, idAI::Event_EndAttack ) - EVENT( AI_MeleeAttackToJoint, idAI::Event_MeleeAttackToJoint ) - EVENT( AI_RandomPath, idAI::Event_RandomPath ) - EVENT( AI_CanBecomeSolid, idAI::Event_CanBecomeSolid ) - EVENT( AI_BecomeSolid, idAI::Event_BecomeSolid ) - EVENT( EV_BecomeNonSolid, idAI::Event_BecomeNonSolid ) - EVENT( AI_BecomeRagdoll, idAI::Event_BecomeRagdoll ) - EVENT( AI_StopRagdoll, idAI::Event_StopRagdoll ) - EVENT( AI_SetHealth, idAI::Event_SetHealth ) - EVENT( AI_GetHealth, idAI::Event_GetHealth ) - EVENT( AI_AllowDamage, idAI::Event_AllowDamage ) - EVENT( AI_IgnoreDamage, idAI::Event_IgnoreDamage ) - EVENT( AI_GetCurrentYaw, idAI::Event_GetCurrentYaw ) - EVENT( AI_TurnTo, idAI::Event_TurnTo ) - EVENT( AI_TurnToPos, idAI::Event_TurnToPos ) - EVENT( AI_TurnToEntity, idAI::Event_TurnToEntity ) - EVENT( AI_MoveStatus, idAI::Event_MoveStatus ) - EVENT( AI_StopMove, idAI::Event_StopMove ) - EVENT( AI_MoveToCover, idAI::Event_MoveToCover ) - EVENT( AI_MoveToEnemy, idAI::Event_MoveToEnemy ) - EVENT( AI_MoveToEnemyHeight, idAI::Event_MoveToEnemyHeight ) - EVENT( AI_MoveOutOfRange, idAI::Event_MoveOutOfRange ) - EVENT( AI_MoveToAttackPosition, idAI::Event_MoveToAttackPosition ) - EVENT( AI_Wander, idAI::Event_Wander ) - EVENT( AI_MoveToEntity, idAI::Event_MoveToEntity ) - EVENT( AI_MoveToPosition, idAI::Event_MoveToPosition ) - EVENT( AI_SlideTo, idAI::Event_SlideTo ) - EVENT( AI_FacingIdeal, idAI::Event_FacingIdeal ) - EVENT( AI_FaceEnemy, idAI::Event_FaceEnemy ) - EVENT( AI_FaceEntity, idAI::Event_FaceEntity ) - EVENT( AI_WaitAction, idAI::Event_WaitAction ) - EVENT( AI_GetCombatNode, idAI::Event_GetCombatNode ) - EVENT( AI_EnemyInCombatCone, idAI::Event_EnemyInCombatCone ) - EVENT( AI_WaitMove, idAI::Event_WaitMove ) - EVENT( AI_GetJumpVelocity, idAI::Event_GetJumpVelocity ) - EVENT( AI_EntityInAttackCone, idAI::Event_EntityInAttackCone ) - EVENT( AI_CanSeeEntity, idAI::Event_CanSeeEntity ) - EVENT( AI_SetTalkTarget, idAI::Event_SetTalkTarget ) - EVENT( AI_GetTalkTarget, idAI::Event_GetTalkTarget ) - EVENT( AI_SetTalkState, idAI::Event_SetTalkState ) - EVENT( AI_EnemyRange, idAI::Event_EnemyRange ) - EVENT( AI_EnemyRange2D, idAI::Event_EnemyRange2D ) - EVENT( AI_GetEnemy, idAI::Event_GetEnemy ) - EVENT( AI_GetEnemyPos, idAI::Event_GetEnemyPos ) - EVENT( AI_GetEnemyEyePos, idAI::Event_GetEnemyEyePos ) - EVENT( AI_PredictEnemyPos, idAI::Event_PredictEnemyPos ) - EVENT( AI_CanHitEnemy, idAI::Event_CanHitEnemy ) - EVENT( AI_CanHitEnemyFromAnim, idAI::Event_CanHitEnemyFromAnim ) - EVENT( AI_CanHitEnemyFromJoint, idAI::Event_CanHitEnemyFromJoint ) - EVENT( AI_EnemyPositionValid, idAI::Event_EnemyPositionValid ) - EVENT( AI_ChargeAttack, idAI::Event_ChargeAttack ) - EVENT( AI_TestChargeAttack, idAI::Event_TestChargeAttack ) - EVENT( AI_TestAnimMoveTowardEnemy, idAI::Event_TestAnimMoveTowardEnemy ) - EVENT( AI_TestAnimMove, idAI::Event_TestAnimMove ) - EVENT( AI_TestMoveToPosition, idAI::Event_TestMoveToPosition ) - EVENT( AI_TestMeleeAttack, idAI::Event_TestMeleeAttack ) - EVENT( AI_TestAnimAttack, idAI::Event_TestAnimAttack ) - EVENT( AI_Shrivel, idAI::Event_Shrivel ) - EVENT( AI_Burn, idAI::Event_Burn ) - EVENT( AI_PreBurn, idAI::Event_PreBurn ) - EVENT( AI_SetSmokeVisibility, idAI::Event_SetSmokeVisibility ) - EVENT( AI_NumSmokeEmitters, idAI::Event_NumSmokeEmitters ) - EVENT( AI_ClearBurn, idAI::Event_ClearBurn ) - EVENT( AI_StopThinking, idAI::Event_StopThinking ) - EVENT( AI_GetTurnDelta, idAI::Event_GetTurnDelta ) - EVENT( AI_GetMoveType, idAI::Event_GetMoveType ) - EVENT( AI_SetMoveType, idAI::Event_SetMoveType ) - EVENT( AI_SaveMove, idAI::Event_SaveMove ) - EVENT( AI_RestoreMove, idAI::Event_RestoreMove ) - EVENT( AI_AllowMovement, idAI::Event_AllowMovement ) - EVENT( AI_JumpFrame, idAI::Event_JumpFrame ) - EVENT( AI_EnableClip, idAI::Event_EnableClip ) - EVENT( AI_DisableClip, idAI::Event_DisableClip ) - EVENT( AI_EnableGravity, idAI::Event_EnableGravity ) - EVENT( AI_DisableGravity, idAI::Event_DisableGravity ) - EVENT( AI_EnableAFPush, idAI::Event_EnableAFPush ) - EVENT( AI_DisableAFPush, idAI::Event_DisableAFPush ) - EVENT( AI_SetFlySpeed, idAI::Event_SetFlySpeed ) - EVENT( AI_SetFlyOffset, idAI::Event_SetFlyOffset ) - EVENT( AI_ClearFlyOffset, idAI::Event_ClearFlyOffset ) - EVENT( AI_GetClosestHiddenTarget, idAI::Event_GetClosestHiddenTarget ) - EVENT( AI_GetRandomTarget, idAI::Event_GetRandomTarget ) - EVENT( AI_TravelDistanceToPoint, idAI::Event_TravelDistanceToPoint ) - EVENT( AI_TravelDistanceToEntity, idAI::Event_TravelDistanceToEntity ) - EVENT( AI_TravelDistanceBetweenPoints, idAI::Event_TravelDistanceBetweenPoints ) - EVENT( AI_TravelDistanceBetweenEntities, idAI::Event_TravelDistanceBetweenEntities ) - EVENT( AI_LookAtEntity, idAI::Event_LookAtEntity ) - EVENT( AI_LookAtEnemy, idAI::Event_LookAtEnemy ) - EVENT( AI_SetJointMod, idAI::Event_SetJointMod ) - EVENT( AI_ThrowMoveable, idAI::Event_ThrowMoveable ) - EVENT( AI_ThrowAF, idAI::Event_ThrowAF ) - EVENT( EV_GetAngles, idAI::Event_GetAngles ) - EVENT( EV_SetAngles, idAI::Event_SetAngles ) - EVENT( AI_RealKill, idAI::Event_RealKill ) - EVENT( AI_Kill, idAI::Event_Kill ) - EVENT( AI_WakeOnFlashlight, idAI::Event_WakeOnFlashlight ) - EVENT( AI_LocateEnemy, idAI::Event_LocateEnemy ) - EVENT( AI_KickObstacles, idAI::Event_KickObstacles ) - EVENT( AI_GetObstacle, idAI::Event_GetObstacle ) - EVENT( AI_PushPointIntoAAS, idAI::Event_PushPointIntoAAS ) - EVENT( AI_GetTurnRate, idAI::Event_GetTurnRate ) - EVENT( AI_SetTurnRate, idAI::Event_SetTurnRate ) - EVENT( AI_AnimTurn, idAI::Event_AnimTurn ) - EVENT( AI_AllowHiddenMovement, idAI::Event_AllowHiddenMovement ) - EVENT( AI_TriggerParticles, idAI::Event_TriggerParticles ) - EVENT( AI_FindActorsInBounds, idAI::Event_FindActorsInBounds ) - EVENT( AI_CanReachPosition, idAI::Event_CanReachPosition ) - EVENT( AI_CanReachEntity, idAI::Event_CanReachEntity ) - EVENT( AI_CanReachEnemy, idAI::Event_CanReachEnemy ) - EVENT( AI_GetReachableEntityPosition, idAI::Event_GetReachableEntityPosition ) -#ifdef _D3XP - EVENT( AI_MoveToPositionDirect, idAI::Event_MoveToPositionDirect ) - EVENT( AI_AvoidObstacles, idAI::Event_AvoidObstacles ) - EVENT( AI_TriggerFX, idAI::Event_TriggerFX ) - EVENT( AI_StartEmitter, idAI::Event_StartEmitter ) - EVENT( AI_GetEmitter, idAI::Event_GetEmitter ) - EVENT( AI_StopEmitter, idAI::Event_StopEmitter ) -#endif -END_CLASS - -/* -===================== -idAI::Event_Activate -===================== -*/ -void idAI::Event_Activate( idEntity *activator ) { - Activate( activator ); -} - -/* -===================== -idAI::Event_Touch -===================== -*/ -void idAI::Event_Touch( idEntity *other, trace_t *trace ) { - if ( !enemy.GetEntity() && !other->fl.notarget && ( ReactionTo( other ) & ATTACK_ON_ACTIVATE ) ) { - Activate( other ); - } - AI_PUSHED = true; -} - -/* -===================== -idAI::Event_FindEnemy -===================== -*/ -void idAI::Event_FindEnemy( int useFOV ) { - int i; - idEntity *ent; - idActor *actor; - - if ( gameLocal.InPlayerPVS( this ) ) { - for ( i = 0; i < gameLocal.numClients ; i++ ) { - ent = gameLocal.entities[ i ]; - - if ( !ent || !ent->IsType( idActor::Type ) ) { - continue; - } - - actor = static_cast( ent ); - if ( ( actor->health <= 0 ) || !( ReactionTo( actor ) & ATTACK_ON_SIGHT ) ) { - continue; - } - - if ( CanSee( actor, useFOV != 0 ) ) { - idThread::ReturnEntity( actor ); - return; - } - } - } - - idThread::ReturnEntity( NULL ); -} - -/* -===================== -idAI::Event_FindEnemyAI -===================== -*/ -void idAI::Event_FindEnemyAI( int useFOV ) { - idEntity *ent; - idActor *actor; - idActor *bestEnemy; - float bestDist; - float dist; - idVec3 delta; - pvsHandle_t pvs; - - pvs = gameLocal.pvs.SetupCurrentPVS( GetPVSAreas(), GetNumPVSAreas() ); - - bestDist = idMath::INFINITY; - bestEnemy = NULL; - for ( ent = gameLocal.activeEntities.Next(); ent != NULL; ent = ent->activeNode.Next() ) { - if ( ent->fl.hidden || ent->fl.isDormant || !ent->IsType( idActor::Type ) ) { - continue; - } - - actor = static_cast( ent ); - if ( ( actor->health <= 0 ) || !( ReactionTo( actor ) & ATTACK_ON_SIGHT ) ) { - continue; - } - - if ( !gameLocal.pvs.InCurrentPVS( pvs, actor->GetPVSAreas(), actor->GetNumPVSAreas() ) ) { - continue; - } - - delta = physicsObj.GetOrigin() - actor->GetPhysics()->GetOrigin(); - dist = delta.LengthSqr(); - if ( ( dist < bestDist ) && CanSee( actor, useFOV != 0 ) ) { - bestDist = dist; - bestEnemy = actor; - } - } - - gameLocal.pvs.FreeCurrentPVS( pvs ); - idThread::ReturnEntity( bestEnemy ); -} - -/* -===================== -idAI::Event_FindEnemyInCombatNodes -===================== -*/ -void idAI::Event_FindEnemyInCombatNodes( void ) { - int i, j; - idCombatNode *node; - idEntity *ent; - idEntity *targetEnt; - idActor *actor; - - if ( !gameLocal.InPlayerPVS( this ) ) { - // don't locate the player when we're not in his PVS - idThread::ReturnEntity( NULL ); - return; - } - - for ( i = 0; i < gameLocal.numClients ; i++ ) { - ent = gameLocal.entities[ i ]; - - if ( !ent || !ent->IsType( idActor::Type ) ) { - continue; - } - - actor = static_cast( ent ); - if ( ( actor->health <= 0 ) || !( ReactionTo( actor ) & ATTACK_ON_SIGHT ) ) { - continue; - } - - for( j = 0; j < targets.Num(); j++ ) { - targetEnt = targets[ j ].GetEntity(); - if ( !targetEnt || !targetEnt->IsType( idCombatNode::Type ) ) { - continue; - } - - node = static_cast( targetEnt ); - if ( !node->IsDisabled() && node->EntityInView( actor, actor->GetPhysics()->GetOrigin() ) ) { - idThread::ReturnEntity( actor ); - return; - } - } - } - - idThread::ReturnEntity( NULL ); -} - -/* -===================== -idAI::Event_ClosestReachableEnemyOfEntity -===================== -*/ -void idAI::Event_ClosestReachableEnemyOfEntity( idEntity *team_mate ) { - idActor *actor; - idActor *ent; - idActor *bestEnt; - float bestDistSquared; - float distSquared; - idVec3 delta; - int areaNum; - int enemyAreaNum; - aasPath_t path; - - if ( !team_mate->IsType( idActor::Type ) ) { - gameLocal.Error( "Entity '%s' is not an AI character or player", team_mate->GetName() ); - } - - actor = static_cast( team_mate ); - - const idVec3 &origin = physicsObj.GetOrigin(); - areaNum = PointReachableAreaNum( origin ); - - bestDistSquared = idMath::INFINITY; - bestEnt = NULL; - for( ent = actor->enemyList.Next(); ent != NULL; ent = ent->enemyNode.Next() ) { - if ( ent->fl.hidden ) { - continue; - } - delta = ent->GetPhysics()->GetOrigin() - origin; - distSquared = delta.LengthSqr(); - if ( distSquared < bestDistSquared ) { - const idVec3 &enemyPos = ent->GetPhysics()->GetOrigin(); - enemyAreaNum = PointReachableAreaNum( enemyPos ); - if ( ( areaNum != 0 ) && PathToGoal( path, areaNum, origin, enemyAreaNum, enemyPos ) ) { - bestEnt = ent; - bestDistSquared = distSquared; - } - } - } - - idThread::ReturnEntity( bestEnt ); -} - -/* -===================== -idAI::Event_HeardSound -===================== -*/ -void idAI::Event_HeardSound( int ignore_team ) { - // check if we heard any sounds in the last frame - idActor *actor = gameLocal.GetAlertEntity(); - if ( actor && ( !ignore_team || ( ReactionTo( actor ) & ATTACK_ON_SIGHT ) ) && gameLocal.InPlayerPVS( this ) ) { - idVec3 pos = actor->GetPhysics()->GetOrigin(); - idVec3 org = physicsObj.GetOrigin(); - float dist = ( pos - org ).LengthSqr(); - if ( dist < Square( AI_HEARING_RANGE ) ) { - idThread::ReturnEntity( actor ); - return; - } - } - - idThread::ReturnEntity( NULL ); -} - -/* -===================== -idAI::Event_SetEnemy -===================== -*/ -void idAI::Event_SetEnemy( idEntity *ent ) { - if ( !ent ) { - ClearEnemy(); - } else if ( !ent->IsType( idActor::Type ) ) { - gameLocal.Error( "'%s' is not an idActor (player or ai controlled character)", ent->name.c_str() ); - } else { - SetEnemy( static_cast( ent ) ); - } -} - -/* -===================== -idAI::Event_ClearEnemy -===================== -*/ -void idAI::Event_ClearEnemy( void ) { - ClearEnemy(); -} - -/* -===================== -idAI::Event_MuzzleFlash -===================== -*/ -void idAI::Event_MuzzleFlash( const char *jointname ) { - idVec3 muzzle; - idMat3 axis; - - GetMuzzle( jointname, muzzle, axis ); - TriggerWeaponEffects( muzzle ); -} - -/* -===================== -idAI::Event_CreateMissile -===================== -*/ -void idAI::Event_CreateMissile( const char *jointname ) { - idVec3 muzzle; - idMat3 axis; - - if ( !projectileDef ) { - gameLocal.Warning( "%s (%s) doesn't have a projectile specified", name.c_str(), GetEntityDefName() ); - return idThread::ReturnEntity( NULL ); - } - - GetMuzzle( jointname, muzzle, axis ); - CreateProjectile( muzzle, viewAxis[ 0 ] * physicsObj.GetGravityAxis() ); - if ( projectile.GetEntity() ) { - if ( !jointname || !jointname[ 0 ] ) { - projectile.GetEntity()->Bind( this, true ); - } else { - projectile.GetEntity()->BindToJoint( this, jointname, true ); - } - } - idThread::ReturnEntity( projectile.GetEntity() ); -} - -/* -===================== -idAI::Event_AttackMissile -===================== -*/ -void idAI::Event_AttackMissile( const char *jointname ) { - idProjectile *proj; - - proj = LaunchProjectile( jointname, enemy.GetEntity(), true ); - idThread::ReturnEntity( proj ); -} - -/* -===================== -idAI::Event_FireMissileAtTarget -===================== -*/ -void idAI::Event_FireMissileAtTarget( const char *jointname, const char *targetname ) { - idEntity *aent; - idProjectile *proj; - - aent = gameLocal.FindEntity( targetname ); - if ( !aent ) { - gameLocal.Warning( "Entity '%s' not found for 'fireMissileAtTarget'", targetname ); - } - - proj = LaunchProjectile( jointname, aent, false ); - idThread::ReturnEntity( proj ); -} - -/* -===================== -idAI::Event_LaunchMissile -===================== -*/ -void idAI::Event_LaunchMissile( const idVec3 &org, const idAngles &ang ) { - idVec3 start; - trace_t tr; - idBounds projBounds; - const idClipModel *projClip; - idMat3 axis; - float distance; - - if ( !projectileDef ) { - gameLocal.Warning( "%s (%s) doesn't have a projectile specified", name.c_str(), GetEntityDefName() ); - idThread::ReturnEntity( NULL ); - return; - } - - axis = ang.ToMat3(); - if ( !projectile.GetEntity() ) { - CreateProjectile( org, axis[ 0 ] ); - } - - // make sure the projectile starts inside the monster bounding box - const idBounds &ownerBounds = physicsObj.GetAbsBounds(); - projClip = projectile.GetEntity()->GetPhysics()->GetClipModel(); - projBounds = projClip->GetBounds().Rotate( projClip->GetAxis() ); - - // check if the owner bounds is bigger than the projectile bounds - if ( ( ( ownerBounds[1][0] - ownerBounds[0][0] ) > ( projBounds[1][0] - projBounds[0][0] ) ) && - ( ( ownerBounds[1][1] - ownerBounds[0][1] ) > ( projBounds[1][1] - projBounds[0][1] ) ) && - ( ( ownerBounds[1][2] - ownerBounds[0][2] ) > ( projBounds[1][2] - projBounds[0][2] ) ) ) { - if ( (ownerBounds - projBounds).RayIntersection( org, viewAxis[ 0 ], distance ) ) { - start = org + distance * viewAxis[ 0 ]; - } else { - start = ownerBounds.GetCenter(); - } - } else { - // projectile bounds bigger than the owner bounds, so just start it from the center - start = ownerBounds.GetCenter(); - } - - gameLocal.clip.Translation( tr, start, org, projClip, projClip->GetAxis(), MASK_SHOT_RENDERMODEL, this ); - - // launch the projectile - idThread::ReturnEntity( projectile.GetEntity() ); - projectile.GetEntity()->Launch( tr.endpos, axis[ 0 ], vec3_origin ); - projectile = NULL; - - TriggerWeaponEffects( tr.endpos ); - - lastAttackTime = gameLocal.time; -} - - -#ifdef _D3XP -/* -===================== -idAI::Event_LaunchProjectile -===================== -*/ -void idAI::Event_LaunchProjectile( const char *entityDefName ) { - idVec3 muzzle, start, dir; - const idDict *projDef; - idMat3 axis; - const idClipModel *projClip; - idBounds projBounds; - trace_t tr; - idEntity *ent; - const char *clsname; - float distance; - idProjectile *proj = NULL; - - projDef = gameLocal.FindEntityDefDict( entityDefName ); - - gameLocal.SpawnEntityDef( *projDef, &ent, false ); - if ( !ent ) { - clsname = projectileDef->GetString( "classname" ); - gameLocal.Error( "Could not spawn entityDef '%s'", clsname ); - } - - if ( !ent->IsType( idProjectile::Type ) ) { - clsname = ent->GetClassname(); - gameLocal.Error( "'%s' is not an idProjectile", clsname ); - } - proj = ( idProjectile * )ent; - - GetMuzzle( "pistol", muzzle, axis ); - proj->Create( this, muzzle, axis[0] ); - - // make sure the projectile starts inside the monster bounding box - const idBounds &ownerBounds = physicsObj.GetAbsBounds(); - projClip = proj->GetPhysics()->GetClipModel(); - projBounds = projClip->GetBounds().Rotate( projClip->GetAxis() ); - if ( (ownerBounds - projBounds).RayIntersection( muzzle, viewAxis[ 0 ], distance ) ) { - start = muzzle + distance * viewAxis[ 0 ]; - } else { - start = ownerBounds.GetCenter(); - } - gameLocal.clip.Translation( tr, start, muzzle, projClip, projClip->GetAxis(), MASK_SHOT_RENDERMODEL, this ); - muzzle = tr.endpos; - - GetAimDir( muzzle, enemy.GetEntity(), this, dir ); - - proj->Launch( muzzle, dir, vec3_origin ); - - TriggerWeaponEffects( muzzle ); -} - -#endif - - -/* -===================== -idAI::Event_AttackMelee -===================== -*/ -void idAI::Event_AttackMelee( const char *meleeDefName ) { - bool hit; - - hit = AttackMelee( meleeDefName ); - idThread::ReturnInt( hit ); -} - -/* -===================== -idAI::Event_DirectDamage -===================== -*/ -void idAI::Event_DirectDamage( idEntity *damageTarget, const char *damageDefName ) { - DirectDamage( damageDefName, damageTarget ); -} - -/* -===================== -idAI::Event_RadiusDamageFromJoint -===================== -*/ -void idAI::Event_RadiusDamageFromJoint( const char *jointname, const char *damageDefName ) { - jointHandle_t joint; - idVec3 org; - idMat3 axis; - - if ( !jointname || !jointname[ 0 ] ) { - org = physicsObj.GetOrigin(); - } else { - joint = animator.GetJointHandle( jointname ); - if ( joint == INVALID_JOINT ) { - gameLocal.Error( "Unknown joint '%s' on %s", jointname, GetEntityDefName() ); - } - GetJointWorldTransform( joint, gameLocal.time, org, axis ); - } - - gameLocal.RadiusDamage( org, this, this, this, this, damageDefName ); -} - -/* -===================== -idAI::Event_RandomPath -===================== -*/ -void idAI::Event_RandomPath( void ) { - idPathCorner *path; - - path = idPathCorner::RandomPath( this, NULL ); - idThread::ReturnEntity( path ); -} - -/* -===================== -idAI::Event_BeginAttack -===================== -*/ -void idAI::Event_BeginAttack( const char *name ) { - BeginAttack( name ); -} - -/* -===================== -idAI::Event_EndAttack -===================== -*/ -void idAI::Event_EndAttack( void ) { - EndAttack(); -} - -/* -===================== -idAI::Event_MeleeAttackToJoint -===================== -*/ -void idAI::Event_MeleeAttackToJoint( const char *jointname, const char *meleeDefName ) { - jointHandle_t joint; - idVec3 start; - idVec3 end; - idMat3 axis; - trace_t trace; - idEntity *hitEnt; - - joint = animator.GetJointHandle( jointname ); - if ( joint == INVALID_JOINT ) { - gameLocal.Error( "Unknown joint '%s' on %s", jointname, GetEntityDefName() ); - } - animator.GetJointTransform( joint, gameLocal.time, end, axis ); - end = physicsObj.GetOrigin() + ( end + modelOffset ) * viewAxis * physicsObj.GetGravityAxis(); - start = GetEyePosition(); - - if ( ai_debugMove.GetBool() ) { - gameRenderWorld->DebugLine( colorYellow, start, end, gameLocal.msec ); - } - - gameLocal.clip.TranslationEntities( trace, start, end, NULL, mat3_identity, MASK_SHOT_BOUNDINGBOX, this ); - if ( trace.fraction < 1.0f ) { - hitEnt = gameLocal.GetTraceEntity( trace ); - if ( hitEnt && hitEnt->IsType( idActor::Type ) ) { - DirectDamage( meleeDefName, hitEnt ); - idThread::ReturnInt( true ); - return; - } - } - - idThread::ReturnInt( false ); -} - -/* -===================== -idAI::Event_CanBecomeSolid -===================== -*/ -void idAI::Event_CanBecomeSolid( void ) { - int i; - int num; -#ifdef _D3XP - bool returnValue = true; -#endif - idEntity * hit; - idClipModel *cm; - idClipModel *clipModels[ MAX_GENTITIES ]; - - num = gameLocal.clip.ClipModelsTouchingBounds( physicsObj.GetAbsBounds(), MASK_MONSTERSOLID, clipModels, MAX_GENTITIES ); - for ( i = 0; i < num; i++ ) { - cm = clipModels[ i ]; - - // don't check render entities - if ( cm->IsRenderModel() ) { - continue; - } - - hit = cm->GetEntity(); - if ( ( hit == this ) || !hit->fl.takedamage ) { - continue; - } - -#ifdef _D3XP - if ( (spawnClearMoveables && hit->IsType( idMoveable::Type )) || (hit->IsType( idBarrel::Type ) || hit->IsType( idExplodingBarrel::Type) ) ) { - idVec3 push; - push = hit->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin(); - push.z = 30.f; - push.NormalizeFast(); - if ( (idMath::Fabs(push.x) < 0.15f) && (idMath::Fabs(push.y) < 0.15f) ) { - push.x = 10.f; push.y = 10.f; push.z = 15.f; - push.NormalizeFast(); - } - push *= 300.f; - hit->GetPhysics()->SetLinearVelocity( push ); - } -#endif - - if ( physicsObj.ClipContents( cm ) ) { -#ifdef _D3XP - returnValue = false; -#else - idThread::ReturnFloat( false ); - return; -#endif - } - } - -#ifdef _D3XP - idThread::ReturnFloat( returnValue ); -#else - idThread::ReturnFloat( true ); -#endif -} - -/* -===================== -idAI::Event_BecomeSolid -===================== -*/ -void idAI::Event_BecomeSolid( void ) { - physicsObj.EnableClip(); - if ( spawnArgs.GetBool( "big_monster" ) ) { - physicsObj.SetContents( 0 ); - } else if ( use_combat_bbox ) { - physicsObj.SetContents( CONTENTS_BODY|CONTENTS_SOLID ); - } else { - physicsObj.SetContents( CONTENTS_BODY ); - } - physicsObj.GetClipModel()->Link( gameLocal.clip ); - fl.takedamage = !spawnArgs.GetBool( "noDamage" ); -} - -/* -===================== -idAI::Event_BecomeNonSolid -===================== -*/ -void idAI::Event_BecomeNonSolid( void ) { - fl.takedamage = false; - physicsObj.SetContents( 0 ); - physicsObj.GetClipModel()->Unlink(); -} - -/* -===================== -idAI::Event_BecomeRagdoll -===================== -*/ -void idAI::Event_BecomeRagdoll( void ) { - bool result; - - result = StartRagdoll(); - idThread::ReturnInt( result ); -} - -/* -===================== -idAI::Event_StopRagdoll -===================== -*/ -void idAI::Event_StopRagdoll( void ) { - StopRagdoll(); - - // set back the monster physics - SetPhysics( &physicsObj ); -} - -/* -===================== -idAI::Event_SetHealth -===================== -*/ -void idAI::Event_SetHealth( float newHealth ) { - health = newHealth; - fl.takedamage = true; - if ( health > 0 ) { - AI_DEAD = false; - } else { - AI_DEAD = true; - } -} - -/* -===================== -idAI::Event_GetHealth -===================== -*/ -void idAI::Event_GetHealth( void ) { - idThread::ReturnFloat( health ); -} - -/* -===================== -idAI::Event_AllowDamage -===================== -*/ -void idAI::Event_AllowDamage( void ) { - fl.takedamage = true; -} - -/* -===================== -idAI::Event_IgnoreDamage -===================== -*/ -void idAI::Event_IgnoreDamage( void ) { - fl.takedamage = false; -} - -/* -===================== -idAI::Event_GetCurrentYaw -===================== -*/ -void idAI::Event_GetCurrentYaw( void ) { - idThread::ReturnFloat( current_yaw ); -} - -/* -===================== -idAI::Event_TurnTo -===================== -*/ -void idAI::Event_TurnTo( float angle ) { - TurnToward( angle ); -} - -/* -===================== -idAI::Event_TurnToPos -===================== -*/ -void idAI::Event_TurnToPos( const idVec3 &pos ) { - TurnToward( pos ); -} - -/* -===================== -idAI::Event_TurnToEntity -===================== -*/ -void idAI::Event_TurnToEntity( idEntity *ent ) { - if ( ent ) { - TurnToward( ent->GetPhysics()->GetOrigin() ); - } -} - -/* -===================== -idAI::Event_MoveStatus -===================== -*/ -void idAI::Event_MoveStatus( void ) { - idThread::ReturnInt( move.moveStatus ); -} - -/* -===================== -idAI::Event_StopMove -===================== -*/ -void idAI::Event_StopMove( void ) { - StopMove( MOVE_STATUS_DONE ); -} - -/* -===================== -idAI::Event_MoveToCover -===================== -*/ -void idAI::Event_MoveToCover( void ) { - idActor *enemyEnt = enemy.GetEntity(); - - StopMove( MOVE_STATUS_DEST_NOT_FOUND ); - if ( !enemyEnt || !MoveToCover( enemyEnt, lastVisibleEnemyPos ) ) { - return; - } -} - -/* -===================== -idAI::Event_MoveToEnemy -===================== -*/ -void idAI::Event_MoveToEnemy( void ) { - StopMove( MOVE_STATUS_DEST_NOT_FOUND ); - if ( !enemy.GetEntity() || !MoveToEnemy() ) { - return; - } -} - -/* -===================== -idAI::Event_MoveToEnemyHeight -===================== -*/ -void idAI::Event_MoveToEnemyHeight( void ) { - StopMove( MOVE_STATUS_DEST_NOT_FOUND ); - MoveToEnemyHeight(); -} - -/* -===================== -idAI::Event_MoveOutOfRange -===================== -*/ -void idAI::Event_MoveOutOfRange( idEntity *entity, float range ) { - StopMove( MOVE_STATUS_DEST_NOT_FOUND ); - MoveOutOfRange( entity, range ); -} - -/* -===================== -idAI::Event_MoveToAttackPosition -===================== -*/ -void idAI::Event_MoveToAttackPosition( idEntity *entity, const char *attack_anim ) { - int anim; - - StopMove( MOVE_STATUS_DEST_NOT_FOUND ); - - anim = GetAnim( ANIMCHANNEL_LEGS, attack_anim ); - if ( !anim ) { - gameLocal.Error( "Unknown anim '%s'", attack_anim ); - } - - MoveToAttackPosition( entity, anim ); -} - -/* -===================== -idAI::Event_MoveToEntity -===================== -*/ -void idAI::Event_MoveToEntity( idEntity *ent ) { - StopMove( MOVE_STATUS_DEST_NOT_FOUND ); - if ( ent ) { - MoveToEntity( ent ); - } -} - -/* -===================== -idAI::Event_MoveToPosition -===================== -*/ -void idAI::Event_MoveToPosition( const idVec3 &pos ) { - StopMove( MOVE_STATUS_DONE ); - MoveToPosition( pos ); -} - -/* -===================== -idAI::Event_SlideTo -===================== -*/ -void idAI::Event_SlideTo( const idVec3 &pos, float time ) { - SlideToPosition( pos, time ); -} -/* -===================== -idAI::Event_Wander -===================== -*/ -void idAI::Event_Wander( void ) { - WanderAround(); -} - -/* -===================== -idAI::Event_FacingIdeal -===================== -*/ -void idAI::Event_FacingIdeal( void ) { - bool facing = FacingIdeal(); - idThread::ReturnInt( facing ); -} - -/* -===================== -idAI::Event_FaceEnemy -===================== -*/ -void idAI::Event_FaceEnemy( void ) { - FaceEnemy(); -} - -/* -===================== -idAI::Event_FaceEntity -===================== -*/ -void idAI::Event_FaceEntity( idEntity *ent ) { - FaceEntity( ent ); -} - -/* -===================== -idAI::Event_WaitAction -===================== -*/ -void idAI::Event_WaitAction( const char *waitForState ) { - if ( idThread::BeginMultiFrameEvent( this, &AI_WaitAction ) ) { - SetWaitState( waitForState ); - } - - if ( !WaitState() ) { - idThread::EndMultiFrameEvent( this, &AI_WaitAction ); - } -} - -/* -===================== -idAI::Event_GetCombatNode -===================== -*/ -void idAI::Event_GetCombatNode( void ) { - int i; - float dist; - idEntity *targetEnt; - idCombatNode *node; - float bestDist; - idCombatNode *bestNode; - idActor *enemyEnt = enemy.GetEntity(); - - if ( !targets.Num() ) { - // no combat nodes - idThread::ReturnEntity( NULL ); - return; - } - - if ( !enemyEnt || !EnemyPositionValid() ) { - // don't return a combat node if we don't have an enemy or - // if we can see he's not in the last place we saw him - -#ifdef _D3XP - if ( team == 0 ) { - // find the closest attack node to the player - bestNode = NULL; - const idVec3 &myPos = physicsObj.GetOrigin(); - const idVec3 &playerPos = gameLocal.GetLocalPlayer()->GetPhysics()->GetOrigin(); - - bestDist = ( myPos - playerPos ).LengthSqr(); - - for( i = 0; i < targets.Num(); i++ ) { - targetEnt = targets[ i ].GetEntity(); - if ( !targetEnt || !targetEnt->IsType( idCombatNode::Type ) ) { - continue; - } - - node = static_cast( targetEnt ); - if ( !node->IsDisabled() ) { - idVec3 org = node->GetPhysics()->GetOrigin(); - dist = ( playerPos - org ).LengthSqr(); - if ( dist < bestDist ) { - bestNode = node; - bestDist = dist; - } - } - } - - idThread::ReturnEntity( bestNode ); - return; - } -#endif - - idThread::ReturnEntity( NULL ); - return; - } - - // find the closest attack node that can see our enemy and is closer than our enemy - bestNode = NULL; - const idVec3 &myPos = physicsObj.GetOrigin(); - bestDist = ( myPos - lastVisibleEnemyPos ).LengthSqr(); - for( i = 0; i < targets.Num(); i++ ) { - targetEnt = targets[ i ].GetEntity(); - if ( !targetEnt || !targetEnt->IsType( idCombatNode::Type ) ) { - continue; - } - - node = static_cast( targetEnt ); - if ( !node->IsDisabled() && node->EntityInView( enemyEnt, lastVisibleEnemyPos ) ) { - idVec3 org = node->GetPhysics()->GetOrigin(); - dist = ( myPos - org ).LengthSqr(); - if ( dist < bestDist ) { - bestNode = node; - bestDist = dist; - } - } - } - - idThread::ReturnEntity( bestNode ); -} - -/* -===================== -idAI::Event_EnemyInCombatCone -===================== -*/ -void idAI::Event_EnemyInCombatCone( idEntity *ent, int use_current_enemy_location ) { - idCombatNode *node; - bool result; - idActor *enemyEnt = enemy.GetEntity(); - - if ( !targets.Num() ) { - // no combat nodes - idThread::ReturnInt( false ); - return; - } - - if ( !enemyEnt ) { - // have to have an enemy - idThread::ReturnInt( false ); - return; - } - - if ( !ent || !ent->IsType( idCombatNode::Type ) ) { - // not a combat node - idThread::ReturnInt( false ); - return; - } - -#ifdef _D3XP - //Allow the level designers define attack nodes that the enemy should never leave. - //This is different that the turrent type combat nodes because they can play an animation - if(ent->spawnArgs.GetBool("neverLeave", "0")) { - idThread::ReturnInt( true ); - return; - } -#endif - - node = static_cast( ent ); - if ( use_current_enemy_location ) { - const idVec3 &pos = enemyEnt->GetPhysics()->GetOrigin(); - result = node->EntityInView( enemyEnt, pos ); - } else { - result = node->EntityInView( enemyEnt, lastVisibleEnemyPos ); - } - - idThread::ReturnInt( result ); -} - -/* -===================== -idAI::Event_WaitMove -===================== -*/ -void idAI::Event_WaitMove( void ) { - idThread::BeginMultiFrameEvent( this, &AI_WaitMove ); - - if ( MoveDone() ) { - idThread::EndMultiFrameEvent( this, &AI_WaitMove ); - } -} - -/* -===================== -idAI::Event_GetJumpVelocity -===================== -*/ -void idAI::Event_GetJumpVelocity( const idVec3 &pos, float speed, float max_height ) { - idVec3 start; - idVec3 end; - idVec3 dir; - float dist; - bool result; - idEntity *enemyEnt = enemy.GetEntity(); - - if ( !enemyEnt ) { - idThread::ReturnVector( vec3_zero ); - return; - } - - if ( speed <= 0.0f ) { - gameLocal.Error( "Invalid speed. speed must be > 0." ); - } - - start = physicsObj.GetOrigin(); - end = pos; - dir = end - start; - dist = dir.Normalize(); - if ( dist > 16.0f ) { - dist -= 16.0f; - end -= dir * 16.0f; - } - - result = PredictTrajectory( start, end, speed, physicsObj.GetGravity(), physicsObj.GetClipModel(), MASK_MONSTERSOLID, max_height, this, enemyEnt, ai_debugMove.GetBool() ? 4000 : 0, dir ); - if ( result ) { - idThread::ReturnVector( dir * speed ); - } else { - idThread::ReturnVector( vec3_zero ); - } -} - -/* -===================== -idAI::Event_EntityInAttackCone -===================== -*/ -void idAI::Event_EntityInAttackCone( idEntity *ent ) { - float attack_cone; - idVec3 delta; - float yaw; - float relYaw; - - if ( !ent ) { - idThread::ReturnInt( false ); - return; - } - - delta = ent->GetPhysics()->GetOrigin() - GetEyePosition(); - - // get our gravity normal - const idVec3 &gravityDir = GetPhysics()->GetGravityNormal(); - - // infinite vertical vision, so project it onto our orientation plane - delta -= gravityDir * ( gravityDir * delta ); - - delta.Normalize(); - yaw = delta.ToYaw(); - - attack_cone = spawnArgs.GetFloat( "attack_cone", "70" ); - relYaw = idMath::AngleNormalize180( ideal_yaw - yaw ); - if ( idMath::Fabs( relYaw ) < ( attack_cone * 0.5f ) ) { - idThread::ReturnInt( true ); - } else { - idThread::ReturnInt( false ); - } -} - -/* -===================== -idAI::Event_CanSeeEntity -===================== -*/ -void idAI::Event_CanSeeEntity( idEntity *ent ) { - if ( !ent ) { - idThread::ReturnInt( false ); - return; - } - - bool cansee = CanSee( ent, false ); - idThread::ReturnInt( cansee ); -} - -/* -===================== -idAI::Event_SetTalkTarget -===================== -*/ -void idAI::Event_SetTalkTarget( idEntity *target ) { - if ( target && !target->IsType( idActor::Type ) ) { - gameLocal.Error( "Cannot set talk target to '%s'. Not a character or player.", target->GetName() ); - } - talkTarget = static_cast( target ); - if ( target ) { - AI_TALK = true; - } else { - AI_TALK = false; - } -} - -/* -===================== -idAI::Event_GetTalkTarget -===================== -*/ -void idAI::Event_GetTalkTarget( void ) { - idThread::ReturnEntity( talkTarget.GetEntity() ); -} - -/* -================ -idAI::Event_SetTalkState -================ -*/ -void idAI::Event_SetTalkState( int state ) { - if ( ( state < 0 ) || ( state >= NUM_TALK_STATES ) ) { - gameLocal.Error( "Invalid talk state (%d)", state ); - } - - talk_state = static_cast( state ); -} - -/* -===================== -idAI::Event_EnemyRange -===================== -*/ -void idAI::Event_EnemyRange( void ) { - float dist; - idActor *enemyEnt = enemy.GetEntity(); - - if ( enemyEnt ) { - dist = ( enemyEnt->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin() ).Length(); - } else { - // Just some really high number - dist = idMath::INFINITY; - } - - idThread::ReturnFloat( dist ); -} - -/* -===================== -idAI::Event_EnemyRange2D -===================== -*/ -void idAI::Event_EnemyRange2D( void ) { - float dist; - idActor *enemyEnt = enemy.GetEntity(); - - if ( enemyEnt ) { - dist = ( enemyEnt->GetPhysics()->GetOrigin().ToVec2() - GetPhysics()->GetOrigin().ToVec2() ).Length(); - } else { - // Just some really high number - dist = idMath::INFINITY; - } - - idThread::ReturnFloat( dist ); -} - -/* -===================== -idAI::Event_GetEnemy -===================== -*/ -void idAI::Event_GetEnemy( void ) { - idThread::ReturnEntity( enemy.GetEntity() ); -} - -/* -===================== -idAI::Event_GetEnemyPos -===================== -*/ -void idAI::Event_GetEnemyPos( void ) { - idThread::ReturnVector( lastVisibleEnemyPos ); -} - -/* -===================== -idAI::Event_GetEnemyEyePos -===================== -*/ -void idAI::Event_GetEnemyEyePos( void ) { - idThread::ReturnVector( lastVisibleEnemyPos + lastVisibleEnemyEyeOffset ); -} - -/* -===================== -idAI::Event_PredictEnemyPos -===================== -*/ -void idAI::Event_PredictEnemyPos( float time ) { - predictedPath_t path; - idActor *enemyEnt = enemy.GetEntity(); - - // if no enemy set - if ( !enemyEnt ) { - idThread::ReturnVector( physicsObj.GetOrigin() ); - return; - } - - // predict the enemy movement - idAI::PredictPath( enemyEnt, aas, lastVisibleEnemyPos, enemyEnt->GetPhysics()->GetLinearVelocity(), SEC2MS( time ), SEC2MS( time ), ( move.moveType == MOVETYPE_FLY ) ? SE_BLOCKED : ( SE_BLOCKED | SE_ENTER_LEDGE_AREA ), path ); - - idThread::ReturnVector( path.endPos ); -} - -/* -===================== -idAI::Event_CanHitEnemy -===================== -*/ -void idAI::Event_CanHitEnemy( void ) { - trace_t tr; - idEntity *hit; - - idActor *enemyEnt = enemy.GetEntity(); - if ( !AI_ENEMY_VISIBLE || !enemyEnt ) { - idThread::ReturnInt( false ); - return; - } - - // don't check twice per frame - if ( gameLocal.time == lastHitCheckTime ) { - idThread::ReturnInt( lastHitCheckResult ); - return; - } - - lastHitCheckTime = gameLocal.time; - - idVec3 toPos = enemyEnt->GetEyePosition(); - idVec3 eye = GetEyePosition(); - idVec3 dir; - - // expand the ray out as far as possible so we can detect anything behind the enemy - dir = toPos - eye; - dir.Normalize(); - toPos = eye + dir * MAX_WORLD_SIZE; - gameLocal.clip.TracePoint( tr, eye, toPos, MASK_SHOT_BOUNDINGBOX, this ); - hit = gameLocal.GetTraceEntity( tr ); - if ( tr.fraction >= 1.0f || ( hit == enemyEnt ) ) { - lastHitCheckResult = true; - } else if ( ( tr.fraction < 1.0f ) && ( hit->IsType( idAI::Type ) ) && - ( static_cast( hit )->team != team ) ) { - lastHitCheckResult = true; - } else { - lastHitCheckResult = false; - } - - idThread::ReturnInt( lastHitCheckResult ); -} - -/* -===================== -idAI::Event_CanHitEnemyFromAnim -===================== -*/ -void idAI::Event_CanHitEnemyFromAnim( const char *animname ) { - int anim; - idVec3 dir; - idVec3 local_dir; - idVec3 fromPos; - idMat3 axis; - idVec3 start; - trace_t tr; - float distance; - - idActor *enemyEnt = enemy.GetEntity(); - if ( !AI_ENEMY_VISIBLE || !enemyEnt ) { - idThread::ReturnInt( false ); - return; - } - - anim = GetAnim( ANIMCHANNEL_LEGS, animname ); - if ( !anim ) { - idThread::ReturnInt( false ); - return; - } - - // just do a ray test if close enough - if ( enemyEnt->GetPhysics()->GetAbsBounds().IntersectsBounds( physicsObj.GetAbsBounds().Expand( 16.0f ) ) ) { - Event_CanHitEnemy(); - return; - } - - // calculate the world transform of the launch position - const idVec3 &org = physicsObj.GetOrigin(); - dir = lastVisibleEnemyPos - org; - physicsObj.GetGravityAxis().ProjectVector( dir, local_dir ); - local_dir.z = 0.0f; - local_dir.ToVec2().Normalize(); - axis = local_dir.ToMat3(); - fromPos = physicsObj.GetOrigin() + missileLaunchOffset[ anim ] * axis; - - if ( projectileClipModel == NULL ) { - CreateProjectileClipModel(); - } - - // check if the owner bounds is bigger than the projectile bounds - const idBounds &ownerBounds = physicsObj.GetAbsBounds(); - const idBounds &projBounds = projectileClipModel->GetBounds(); - if ( ( ( ownerBounds[1][0] - ownerBounds[0][0] ) > ( projBounds[1][0] - projBounds[0][0] ) ) && - ( ( ownerBounds[1][1] - ownerBounds[0][1] ) > ( projBounds[1][1] - projBounds[0][1] ) ) && - ( ( ownerBounds[1][2] - ownerBounds[0][2] ) > ( projBounds[1][2] - projBounds[0][2] ) ) ) { - if ( (ownerBounds - projBounds).RayIntersection( org, viewAxis[ 0 ], distance ) ) { - start = org + distance * viewAxis[ 0 ]; - } else { - start = ownerBounds.GetCenter(); - } - } else { - // projectile bounds bigger than the owner bounds, so just start it from the center - start = ownerBounds.GetCenter(); - } - - gameLocal.clip.Translation( tr, start, fromPos, projectileClipModel, mat3_identity, MASK_SHOT_RENDERMODEL, this ); - fromPos = tr.endpos; - - if ( GetAimDir( fromPos, enemy.GetEntity(), this, dir ) ) { - idThread::ReturnInt( true ); - } else { - idThread::ReturnInt( false ); - } -} - -/* -===================== -idAI::Event_CanHitEnemyFromJoint -===================== -*/ -void idAI::Event_CanHitEnemyFromJoint( const char *jointname ) { - trace_t tr; - idVec3 muzzle; - idMat3 axis; - idVec3 start; - float distance; - - idActor *enemyEnt = enemy.GetEntity(); - if ( !AI_ENEMY_VISIBLE || !enemyEnt ) { - idThread::ReturnInt( false ); - return; - } - - // don't check twice per frame - if ( gameLocal.time == lastHitCheckTime ) { - idThread::ReturnInt( lastHitCheckResult ); - return; - } - - lastHitCheckTime = gameLocal.time; - - const idVec3 &org = physicsObj.GetOrigin(); - idVec3 toPos = enemyEnt->GetEyePosition(); - jointHandle_t joint = animator.GetJointHandle( jointname ); - if ( joint == INVALID_JOINT ) { - gameLocal.Error( "Unknown joint '%s' on %s", jointname, GetEntityDefName() ); - } - animator.GetJointTransform( joint, gameLocal.time, muzzle, axis ); - muzzle = org + ( muzzle + modelOffset ) * viewAxis * physicsObj.GetGravityAxis(); - - if ( projectileClipModel == NULL ) { - CreateProjectileClipModel(); - } - - // check if the owner bounds is bigger than the projectile bounds - const idBounds &ownerBounds = physicsObj.GetAbsBounds(); - const idBounds &projBounds = projectileClipModel->GetBounds(); - if ( ( ( ownerBounds[1][0] - ownerBounds[0][0] ) > ( projBounds[1][0] - projBounds[0][0] ) ) && - ( ( ownerBounds[1][1] - ownerBounds[0][1] ) > ( projBounds[1][1] - projBounds[0][1] ) ) && - ( ( ownerBounds[1][2] - ownerBounds[0][2] ) > ( projBounds[1][2] - projBounds[0][2] ) ) ) { - if ( (ownerBounds - projBounds).RayIntersection( org, viewAxis[ 0 ], distance ) ) { - start = org + distance * viewAxis[ 0 ]; - } else { - start = ownerBounds.GetCenter(); - } - } else { - // projectile bounds bigger than the owner bounds, so just start it from the center - start = ownerBounds.GetCenter(); - } - - gameLocal.clip.Translation( tr, start, muzzle, projectileClipModel, mat3_identity, MASK_SHOT_BOUNDINGBOX, this ); - muzzle = tr.endpos; - - gameLocal.clip.Translation( tr, muzzle, toPos, projectileClipModel, mat3_identity, MASK_SHOT_BOUNDINGBOX, this ); - if ( tr.fraction >= 1.0f || ( gameLocal.GetTraceEntity( tr ) == enemyEnt ) ) { - lastHitCheckResult = true; - } else { - lastHitCheckResult = false; - } - - idThread::ReturnInt( lastHitCheckResult ); -} - -/* -===================== -idAI::Event_EnemyPositionValid -===================== -*/ -void idAI::Event_EnemyPositionValid( void ) { - bool result; - - result = EnemyPositionValid(); - idThread::ReturnInt( result ); -} - -/* -===================== -idAI::Event_ChargeAttack -===================== -*/ -void idAI::Event_ChargeAttack( const char *damageDef ) { - idActor *enemyEnt = enemy.GetEntity(); - - StopMove( MOVE_STATUS_DEST_NOT_FOUND ); - if ( enemyEnt ) { - idVec3 enemyOrg; - - if ( move.moveType == MOVETYPE_FLY ) { - // position destination so that we're in the enemy's view - enemyOrg = enemyEnt->GetEyePosition(); - enemyOrg -= enemyEnt->GetPhysics()->GetGravityNormal() * fly_offset; - } else { - enemyOrg = enemyEnt->GetPhysics()->GetOrigin(); - } - - BeginAttack( damageDef ); - DirectMoveToPosition( enemyOrg ); - TurnToward( enemyOrg ); - } -} - -/* -===================== -idAI::Event_TestChargeAttack -===================== -*/ -void idAI::Event_TestChargeAttack( void ) { - idActor *enemyEnt = enemy.GetEntity(); - predictedPath_t path; - idVec3 end; - - if ( !enemyEnt ) { - idThread::ReturnFloat( 0.0f ); - return; - } - - if ( move.moveType == MOVETYPE_FLY ) { - // position destination so that we're in the enemy's view - end = enemyEnt->GetEyePosition(); - end -= enemyEnt->GetPhysics()->GetGravityNormal() * fly_offset; - } else { - end = enemyEnt->GetPhysics()->GetOrigin(); - } - - idAI::PredictPath( this, aas, physicsObj.GetOrigin(), end - physicsObj.GetOrigin(), 1000, 1000, ( move.moveType == MOVETYPE_FLY ) ? SE_BLOCKED : ( SE_ENTER_OBSTACLE | SE_BLOCKED | SE_ENTER_LEDGE_AREA ), path ); - - if ( ai_debugMove.GetBool() ) { - gameRenderWorld->DebugLine( colorGreen, physicsObj.GetOrigin(), end, gameLocal.msec ); - gameRenderWorld->DebugBounds( path.endEvent == 0 ? colorYellow : colorRed, physicsObj.GetBounds(), end, gameLocal.msec ); - } - - if ( ( path.endEvent == 0 ) || ( path.blockingEntity == enemyEnt ) ) { - idVec3 delta = end - physicsObj.GetOrigin(); - float time = delta.LengthFast(); - idThread::ReturnFloat( time ); - } else { - idThread::ReturnFloat( 0.0f ); - } -} - -/* -===================== -idAI::Event_TestAnimMoveTowardEnemy -===================== -*/ -void idAI::Event_TestAnimMoveTowardEnemy( const char *animname ) { - int anim; - predictedPath_t path; - idVec3 moveVec; - float yaw; - idVec3 delta; - idActor *enemyEnt; - - enemyEnt = enemy.GetEntity(); - if ( !enemyEnt ) { - idThread::ReturnInt( false ); - return; - } - - anim = GetAnim( ANIMCHANNEL_LEGS, animname ); - if ( !anim ) { - gameLocal.DWarning( "missing '%s' animation on '%s' (%s)", animname, name.c_str(), GetEntityDefName() ); - idThread::ReturnInt( false ); - return; - } - - delta = enemyEnt->GetPhysics()->GetOrigin() - physicsObj.GetOrigin(); - yaw = delta.ToYaw(); - - moveVec = animator.TotalMovementDelta( anim ) * idAngles( 0.0f, yaw, 0.0f ).ToMat3() * physicsObj.GetGravityAxis(); - idAI::PredictPath( this, aas, physicsObj.GetOrigin(), moveVec, 1000, 1000, ( move.moveType == MOVETYPE_FLY ) ? SE_BLOCKED : ( SE_ENTER_OBSTACLE | SE_BLOCKED | SE_ENTER_LEDGE_AREA ), path ); - - if ( ai_debugMove.GetBool() ) { - gameRenderWorld->DebugLine( colorGreen, physicsObj.GetOrigin(), physicsObj.GetOrigin() + moveVec, gameLocal.msec ); - gameRenderWorld->DebugBounds( path.endEvent == 0 ? colorYellow : colorRed, physicsObj.GetBounds(), physicsObj.GetOrigin() + moveVec, gameLocal.msec ); - } - - idThread::ReturnInt( path.endEvent == 0 ); -} - -/* -===================== -idAI::Event_TestAnimMove -===================== -*/ -void idAI::Event_TestAnimMove( const char *animname ) { - int anim; - predictedPath_t path; - idVec3 moveVec; - - anim = GetAnim( ANIMCHANNEL_LEGS, animname ); - if ( !anim ) { - gameLocal.DWarning( "missing '%s' animation on '%s' (%s)", animname, name.c_str(), GetEntityDefName() ); - idThread::ReturnInt( false ); - return; - } - - moveVec = animator.TotalMovementDelta( anim ) * idAngles( 0.0f, ideal_yaw, 0.0f ).ToMat3() * physicsObj.GetGravityAxis(); - idAI::PredictPath( this, aas, physicsObj.GetOrigin(), moveVec, 1000, 1000, ( move.moveType == MOVETYPE_FLY ) ? SE_BLOCKED : ( SE_ENTER_OBSTACLE | SE_BLOCKED | SE_ENTER_LEDGE_AREA ), path ); - - if ( ai_debugMove.GetBool() ) { - gameRenderWorld->DebugLine( colorGreen, physicsObj.GetOrigin(), physicsObj.GetOrigin() + moveVec, gameLocal.msec ); - gameRenderWorld->DebugBounds( path.endEvent == 0 ? colorYellow : colorRed, physicsObj.GetBounds(), physicsObj.GetOrigin() + moveVec, gameLocal.msec ); - } - - idThread::ReturnInt( path.endEvent == 0 ); -} - -/* -===================== -idAI::Event_TestMoveToPosition -===================== -*/ -void idAI::Event_TestMoveToPosition( const idVec3 &position ) { - predictedPath_t path; - - idAI::PredictPath( this, aas, physicsObj.GetOrigin(), position - physicsObj.GetOrigin(), 1000, 1000, ( move.moveType == MOVETYPE_FLY ) ? SE_BLOCKED : ( SE_ENTER_OBSTACLE | SE_BLOCKED | SE_ENTER_LEDGE_AREA ), path ); - - if ( ai_debugMove.GetBool() ) { - gameRenderWorld->DebugLine( colorGreen, physicsObj.GetOrigin(), position, gameLocal.msec ); - gameRenderWorld->DebugBounds( colorYellow, physicsObj.GetBounds(), position, gameLocal.msec ); - if ( path.endEvent ) { - gameRenderWorld->DebugBounds( colorRed, physicsObj.GetBounds(), path.endPos, gameLocal.msec ); - } - } - - idThread::ReturnInt( path.endEvent == 0 ); -} - -/* -===================== -idAI::Event_TestMeleeAttack -===================== -*/ -void idAI::Event_TestMeleeAttack( void ) { - bool result = TestMelee(); - idThread::ReturnInt( result ); -} - -/* -===================== -idAI::Event_TestAnimAttack -===================== -*/ -void idAI::Event_TestAnimAttack( const char *animname ) { - int anim; - predictedPath_t path; - - anim = GetAnim( ANIMCHANNEL_LEGS, animname ); - if ( !anim ) { - gameLocal.DWarning( "missing '%s' animation on '%s' (%s)", animname, name.c_str(), GetEntityDefName() ); - idThread::ReturnInt( false ); - return; - } - - idAI::PredictPath( this, aas, physicsObj.GetOrigin(), animator.TotalMovementDelta( anim ), 1000, 1000, ( move.moveType == MOVETYPE_FLY ) ? SE_BLOCKED : ( SE_ENTER_OBSTACLE | SE_BLOCKED | SE_ENTER_LEDGE_AREA ), path ); - - idThread::ReturnInt( path.blockingEntity && ( path.blockingEntity == enemy.GetEntity() ) ); -} - -/* -===================== -idAI::Event_Shrivel -===================== -*/ -void idAI::Event_Shrivel( float shrivel_time ) { - float t; - - if ( idThread::BeginMultiFrameEvent( this, &AI_Shrivel ) ) { - if ( shrivel_time <= 0.0f ) { - idThread::EndMultiFrameEvent( this, &AI_Shrivel ); - return; - } - - shrivel_rate = 0.001f / shrivel_time; - shrivel_start = gameLocal.time; - } - - t = ( gameLocal.time - shrivel_start ) * shrivel_rate; - if ( t > 0.25f ) { - renderEntity.noShadow = true; - } - if ( t > 1.0f ) { - t = 1.0f; - idThread::EndMultiFrameEvent( this, &AI_Shrivel ); - } - - renderEntity.shaderParms[ SHADERPARM_MD5_SKINSCALE ] = 1.0f - t * 0.5f; - UpdateVisuals(); -} - -/* -===================== -idAI::Event_PreBurn -===================== -*/ -void idAI::Event_PreBurn( void ) { -#ifdef _D3XP - // No grabbing after the burn has started! - noGrab = true; -#endif - - // for now this just turns shadows off - renderEntity.noShadow = true; -} - -/* -===================== -idAI::Event_Burn -===================== -*/ -void idAI::Event_Burn( void ) { - renderEntity.shaderParms[ SHADERPARM_TIME_OF_DEATH ] = gameLocal.time * 0.001f; - SpawnParticles( "smoke_burnParticleSystem" ); - UpdateVisuals(); -} - -/* -===================== -idAI::Event_ClearBurn -===================== -*/ -void idAI::Event_ClearBurn( void ) { - renderEntity.noShadow = spawnArgs.GetBool( "noshadows" ); - renderEntity.shaderParms[ SHADERPARM_TIME_OF_DEATH ] = 0.0f; - UpdateVisuals(); -} - -/* -===================== -idAI::Event_SetSmokeVisibility -===================== -*/ -void idAI::Event_SetSmokeVisibility( int num, int on ) { - int i; - int time; - - if ( num >= particles.Num() ) { - gameLocal.Warning( "Particle #%d out of range (%d particles) on entity '%s'", num, particles.Num(), name.c_str() ); - return; - } - - if ( on != 0 ) { - time = gameLocal.time; - BecomeActive( TH_UPDATEPARTICLES ); - } else { - time = 0; - } - - if ( num >= 0 ) { - particles[ num ].time = time; - } else { - for ( i = 0; i < particles.Num(); i++ ) { - particles[ i ].time = time; - } - } - - UpdateVisuals(); -} - -/* -===================== -idAI::Event_NumSmokeEmitters -===================== -*/ -void idAI::Event_NumSmokeEmitters( void ) { - idThread::ReturnInt( particles.Num() ); -} - -/* -===================== -idAI::Event_StopThinking -===================== -*/ -void idAI::Event_StopThinking( void ) { - BecomeInactive( TH_THINK ); - idThread *thread = idThread::CurrentThread(); - if ( thread ) { - thread->DoneProcessing(); - } -} - -/* -===================== -idAI::Event_GetTurnDelta -===================== -*/ -void idAI::Event_GetTurnDelta( void ) { - float amount; - - if ( turnRate ) { - amount = idMath::AngleNormalize180( ideal_yaw - current_yaw ); - idThread::ReturnFloat( amount ); - } else { - idThread::ReturnFloat( 0.0f ); - } -} - -/* -===================== -idAI::Event_GetMoveType -===================== -*/ -void idAI::Event_GetMoveType( void ) { - idThread::ReturnInt( move.moveType ); -} - -/* -===================== -idAI::Event_SetMoveTypes -===================== -*/ -void idAI::Event_SetMoveType( int moveType ) { - if ( ( moveType < 0 ) || ( moveType >= NUM_MOVETYPES ) ) { - gameLocal.Error( "Invalid movetype %d", moveType ); - } - - move.moveType = static_cast( moveType ); - if ( move.moveType == MOVETYPE_FLY ) { - travelFlags = TFL_WALK|TFL_AIR|TFL_FLY; - } else { - travelFlags = TFL_WALK|TFL_AIR; - } -} - -/* -===================== -idAI::Event_SaveMove -===================== -*/ -void idAI::Event_SaveMove( void ) { - savedMove = move; -} - -/* -===================== -idAI::Event_RestoreMove -===================== -*/ -void idAI::Event_RestoreMove( void ) { - idVec3 goalPos; - idVec3 dest; - - switch( savedMove.moveCommand ) { - case MOVE_NONE : - StopMove( savedMove.moveStatus ); - break; - - case MOVE_FACE_ENEMY : - FaceEnemy(); - break; - - case MOVE_FACE_ENTITY : - FaceEntity( savedMove.goalEntity.GetEntity() ); - break; - - case MOVE_TO_ENEMY : - MoveToEnemy(); - break; - - case MOVE_TO_ENEMYHEIGHT : - MoveToEnemyHeight(); - break; - - case MOVE_TO_ENTITY : - MoveToEntity( savedMove.goalEntity.GetEntity() ); - break; - - case MOVE_OUT_OF_RANGE : - MoveOutOfRange( savedMove.goalEntity.GetEntity(), savedMove.range ); - break; - - case MOVE_TO_ATTACK_POSITION : - MoveToAttackPosition( savedMove.goalEntity.GetEntity(), savedMove.anim ); - break; - - case MOVE_TO_COVER : - MoveToCover( savedMove.goalEntity.GetEntity(), lastVisibleEnemyPos ); - break; - - case MOVE_TO_POSITION : - MoveToPosition( savedMove.moveDest ); - break; - - case MOVE_TO_POSITION_DIRECT : - DirectMoveToPosition( savedMove.moveDest ); - break; - - case MOVE_SLIDE_TO_POSITION : - SlideToPosition( savedMove.moveDest, savedMove.duration ); - break; - - case MOVE_WANDER : - WanderAround(); - break; - } - - if ( GetMovePos( goalPos ) ) { - CheckObstacleAvoidance( goalPos, dest ); - } -} - -/* -===================== -idAI::Event_AllowMovement -===================== -*/ -void idAI::Event_AllowMovement( float flag ) { - allowMove = ( flag != 0.0f ); -} - -/* -===================== -idAI::Event_JumpFrame -===================== -*/ -void idAI::Event_JumpFrame( void ) { - AI_JUMP = true; -} - -/* -===================== -idAI::Event_EnableClip -===================== -*/ -void idAI::Event_EnableClip( void ) { - physicsObj.SetClipMask( MASK_MONSTERSOLID ); - disableGravity = false; -} - -/* -===================== -idAI::Event_DisableClip -===================== -*/ -void idAI::Event_DisableClip( void ) { - physicsObj.SetClipMask( 0 ); - disableGravity = true; -} - -/* -===================== -idAI::Event_EnableGravity -===================== -*/ -void idAI::Event_EnableGravity( void ) { - disableGravity = false; -} - -/* -===================== -idAI::Event_DisableGravity -===================== -*/ -void idAI::Event_DisableGravity( void ) { - disableGravity = true; -} - -/* -===================== -idAI::Event_EnableAFPush -===================== -*/ -void idAI::Event_EnableAFPush( void ) { - af_push_moveables = true; -} - -/* -===================== -idAI::Event_DisableAFPush -===================== -*/ -void idAI::Event_DisableAFPush( void ) { - af_push_moveables = false; -} - -/* -===================== -idAI::Event_SetFlySpeed -===================== -*/ -void idAI::Event_SetFlySpeed( float speed ) { - if ( move.speed == fly_speed ) { - move.speed = speed; - } - fly_speed = speed; -} - -/* -================ -idAI::Event_SetFlyOffset -================ -*/ -void idAI::Event_SetFlyOffset( int offset ) { - fly_offset = offset; -} - -/* -================ -idAI::Event_ClearFlyOffset -================ -*/ -void idAI::Event_ClearFlyOffset( void ) { - spawnArgs.GetInt( "fly_offset", "0", fly_offset ); -} - -/* -===================== -idAI::Event_GetClosestHiddenTarget -===================== -*/ -void idAI::Event_GetClosestHiddenTarget( const char *type ) { - int i; - idEntity *ent; - idEntity *bestEnt; - float time; - float bestTime; - const idVec3 &org = physicsObj.GetOrigin(); - idActor *enemyEnt = enemy.GetEntity(); - - if ( !enemyEnt ) { - // no enemy to hide from - idThread::ReturnEntity( NULL ); - return; - } - - if ( targets.Num() == 1 ) { - ent = targets[ 0 ].GetEntity(); - if ( ent && idStr::Cmp( ent->GetEntityDefName(), type ) == 0 ) { - if ( !EntityCanSeePos( enemyEnt, lastVisibleEnemyPos, ent->GetPhysics()->GetOrigin() ) ) { - idThread::ReturnEntity( ent ); - return; - } - } - idThread::ReturnEntity( NULL ); - return; - } - - bestEnt = NULL; - bestTime = idMath::INFINITY; - for( i = 0; i < targets.Num(); i++ ) { - ent = targets[ i ].GetEntity(); - if ( ent && idStr::Cmp( ent->GetEntityDefName(), type ) == 0 ) { - const idVec3 &destOrg = ent->GetPhysics()->GetOrigin(); - time = TravelDistance( org, destOrg ); - if ( ( time >= 0.0f ) && ( time < bestTime ) ) { - if ( !EntityCanSeePos( enemyEnt, lastVisibleEnemyPos, destOrg ) ) { - bestEnt = ent; - bestTime = time; - } - } - } - } - idThread::ReturnEntity( bestEnt ); -} - -/* -===================== -idAI::Event_GetRandomTarget -===================== -*/ -void idAI::Event_GetRandomTarget( const char *type ) { - int i; - int num; - int which; - idEntity *ent; - idEntity *ents[ MAX_GENTITIES ]; - - num = 0; - for( i = 0; i < targets.Num(); i++ ) { - ent = targets[ i ].GetEntity(); - if ( ent && idStr::Cmp( ent->GetEntityDefName(), type ) == 0 ) { - ents[ num++ ] = ent; - if ( num >= MAX_GENTITIES ) { - break; - } - } - } - - if ( !num ) { - idThread::ReturnEntity( NULL ); - return; - } - - which = gameLocal.random.RandomInt( num ); - idThread::ReturnEntity( ents[ which ] ); -} - -/* -================ -idAI::Event_TravelDistanceToPoint -================ -*/ -void idAI::Event_TravelDistanceToPoint( const idVec3 &pos ) { - float time; - - time = TravelDistance( physicsObj.GetOrigin(), pos ); - idThread::ReturnFloat( time ); -} - -/* -================ -idAI::Event_TravelDistanceToEntity -================ -*/ -void idAI::Event_TravelDistanceToEntity( idEntity *ent ) { - float time; - - time = TravelDistance( physicsObj.GetOrigin(), ent->GetPhysics()->GetOrigin() ); - idThread::ReturnFloat( time ); -} - -/* -================ -idAI::Event_TravelDistanceBetweenPoints -================ -*/ -void idAI::Event_TravelDistanceBetweenPoints( const idVec3 &source, const idVec3 &dest ) { - float time; - - time = TravelDistance( source, dest ); - idThread::ReturnFloat( time ); -} - -/* -================ -idAI::Event_TravelDistanceBetweenEntities -================ -*/ -void idAI::Event_TravelDistanceBetweenEntities( idEntity *source, idEntity *dest ) { - float time; - - assert( source ); - assert( dest ); - time = TravelDistance( source->GetPhysics()->GetOrigin(), dest->GetPhysics()->GetOrigin() ); - idThread::ReturnFloat( time ); -} - -/* -===================== -idAI::Event_LookAtEntity -===================== -*/ -void idAI::Event_LookAtEntity( idEntity *ent, float duration ) { - if ( ent == this ) { - ent = NULL; - } - - if ( ( ent != focusEntity.GetEntity() ) || ( focusTime < gameLocal.time ) ) { - focusEntity = ent; - alignHeadTime = gameLocal.time; - forceAlignHeadTime = gameLocal.time + SEC2MS( 1 ); - blink_time = 0; - } - - focusTime = gameLocal.time + SEC2MS( duration ); -} - -/* -===================== -idAI::Event_LookAtEnemy -===================== -*/ -void idAI::Event_LookAtEnemy( float duration ) { - idActor *enemyEnt; - - enemyEnt = enemy.GetEntity(); - if ( ( enemyEnt != focusEntity.GetEntity() ) || ( focusTime < gameLocal.time ) ) { - focusEntity = enemyEnt; - alignHeadTime = gameLocal.time; - forceAlignHeadTime = gameLocal.time + SEC2MS( 1 ); - blink_time = 0; - } - - focusTime = gameLocal.time + SEC2MS( duration ); -} - -/* -=============== -idAI::Event_SetJointMod -=============== -*/ -void idAI::Event_SetJointMod( int allow ) { - allowJointMod = ( allow != 0 ); -} - -/* -================ -idAI::Event_ThrowMoveable -================ -*/ -void idAI::Event_ThrowMoveable( void ) { - idEntity *ent; - idEntity *moveable = NULL; - - for ( ent = GetNextTeamEntity(); ent != NULL; ent = ent->GetNextTeamEntity() ) { - if ( ent->GetBindMaster() == this && ent->IsType( idMoveable::Type ) ) { - moveable = ent; - break; - } - } - if ( moveable ) { - moveable->Unbind(); - moveable->PostEventMS( &EV_SetOwner, 200, 0 ); - } -} - -/* -================ -idAI::Event_ThrowAF -================ -*/ -void idAI::Event_ThrowAF( void ) { - idEntity *ent; - idEntity *af = NULL; - - for ( ent = GetNextTeamEntity(); ent != NULL; ent = ent->GetNextTeamEntity() ) { - if ( ent->GetBindMaster() == this && ent->IsType( idAFEntity_Base::Type ) ) { - af = ent; - break; - } - } - if ( af ) { - af->Unbind(); - af->PostEventMS( &EV_SetOwner, 200, 0 ); - } -} - -/* -================ -idAI::Event_SetAngles -================ -*/ -void idAI::Event_SetAngles( idAngles const &ang ) { - current_yaw = ang.yaw; - viewAxis = idAngles( 0, current_yaw, 0 ).ToMat3(); -} - -/* -================ -idAI::Event_GetAngles -================ -*/ -void idAI::Event_GetAngles( void ) { - idThread::ReturnVector( idVec3( 0.0f, current_yaw, 0.0f ) ); -} - -/* -================ -idAI::Event_RealKill -================ -*/ -void idAI::Event_RealKill( void ) { - health = 0; - - if ( af.IsLoaded() ) { - // clear impacts - af.Rest(); - - // physics is turned off by calling af.Rest() - BecomeActive( TH_PHYSICS ); - } - - Killed( this, this, 0, vec3_zero, INVALID_JOINT ); -} - -/* -================ -idAI::Event_Kill -================ -*/ -void idAI::Event_Kill( void ) { - PostEventMS( &AI_RealKill, 0 ); -} - -/* -================ -idAI::Event_WakeOnFlashlight -================ -*/ -void idAI::Event_WakeOnFlashlight( int enable ) { - wakeOnFlashlight = ( enable != 0 ); -} - -/* -================ -idAI::Event_LocateEnemy -================ -*/ -void idAI::Event_LocateEnemy( void ) { - idActor *enemyEnt; - int areaNum; - - enemyEnt = enemy.GetEntity(); - if ( !enemyEnt ) { - return; - } - - enemyEnt->GetAASLocation( aas, lastReachableEnemyPos, areaNum ); - SetEnemyPosition(); - UpdateEnemyPosition(); -} - -/* -================ -idAI::Event_KickObstacles -================ -*/ -void idAI::Event_KickObstacles( idEntity *kickEnt, float force ) { - idVec3 dir; - idEntity *obEnt; - - if ( kickEnt ) { - obEnt = kickEnt; - } else { - obEnt = move.obstacle.GetEntity(); - } - - if ( obEnt ) { - dir = obEnt->GetPhysics()->GetOrigin() - physicsObj.GetOrigin(); - dir.Normalize(); - } else { - dir = viewAxis[ 0 ]; - } - KickObstacles( dir, force, obEnt ); -} - -/* -================ -idAI::Event_GetObstacle -================ -*/ -void idAI::Event_GetObstacle( void ) { - idThread::ReturnEntity( move.obstacle.GetEntity() ); -} - -/* -================ -idAI::Event_PushPointIntoAAS -================ -*/ -void idAI::Event_PushPointIntoAAS( const idVec3 &pos ) { - int areaNum; - idVec3 newPos; - - areaNum = PointReachableAreaNum( pos ); - if ( areaNum ) { - newPos = pos; - aas->PushPointIntoAreaNum( areaNum, newPos ); - idThread::ReturnVector( newPos ); - } else { - idThread::ReturnVector( pos ); - } -} - - -/* -================ -idAI::Event_GetTurnRate -================ -*/ -void idAI::Event_GetTurnRate( void ) { - idThread::ReturnFloat( turnRate ); -} - -/* -================ -idAI::Event_SetTurnRate -================ -*/ -void idAI::Event_SetTurnRate( float rate ) { - turnRate = rate; -} - -/* -================ -idAI::Event_AnimTurn -================ -*/ -void idAI::Event_AnimTurn( float angles ) { - turnVel = 0.0f; - anim_turn_angles = angles; - if ( angles ) { - anim_turn_yaw = current_yaw; - anim_turn_amount = idMath::Fabs( idMath::AngleNormalize180( current_yaw - ideal_yaw ) ); - if ( anim_turn_amount > anim_turn_angles ) { - anim_turn_amount = anim_turn_angles; - } - } else { - anim_turn_amount = 0.0f; - animator.CurrentAnim( ANIMCHANNEL_LEGS )->SetSyncedAnimWeight( 0, 1.0f ); - animator.CurrentAnim( ANIMCHANNEL_LEGS )->SetSyncedAnimWeight( 1, 0.0f ); - animator.CurrentAnim( ANIMCHANNEL_TORSO )->SetSyncedAnimWeight( 0, 1.0f ); - animator.CurrentAnim( ANIMCHANNEL_TORSO )->SetSyncedAnimWeight( 1, 0.0f ); - } -} - -/* -================ -idAI::Event_AllowHiddenMovement -================ -*/ -void idAI::Event_AllowHiddenMovement( int enable ) { - allowHiddenMovement = ( enable != 0 ); -} - -/* -================ -idAI::Event_TriggerParticles -================ -*/ -void idAI::Event_TriggerParticles( const char *jointName ) { - TriggerParticles( jointName ); -} - -/* -===================== -idAI::Event_FindActorsInBounds -===================== -*/ -void idAI::Event_FindActorsInBounds( const idVec3 &mins, const idVec3 &maxs ) { - idEntity * ent; - idEntity * entityList[ MAX_GENTITIES ]; - int numListedEntities; - int i; - - numListedEntities = gameLocal.clip.EntitiesTouchingBounds( idBounds( mins, maxs ), CONTENTS_BODY, entityList, MAX_GENTITIES ); - for( i = 0; i < numListedEntities; i++ ) { - ent = entityList[ i ]; - if ( ent != this && !ent->IsHidden() && ( ent->health > 0 ) && ent->IsType( idActor::Type ) ) { - idThread::ReturnEntity( ent ); - return; - } - } - - idThread::ReturnEntity( NULL ); -} - -/* -================ -idAI::Event_CanReachPosition -================ -*/ -void idAI::Event_CanReachPosition( const idVec3 &pos ) { - aasPath_t path; - int toAreaNum; - int areaNum; - - toAreaNum = PointReachableAreaNum( pos ); - areaNum = PointReachableAreaNum( physicsObj.GetOrigin() ); - if ( !toAreaNum || !PathToGoal( path, areaNum, physicsObj.GetOrigin(), toAreaNum, pos ) ) { - idThread::ReturnInt( false ); - } else { - idThread::ReturnInt( true ); - } -} - -/* -================ -idAI::Event_CanReachEntity -================ -*/ -void idAI::Event_CanReachEntity( idEntity *ent ) { - aasPath_t path; - int toAreaNum; - int areaNum; - idVec3 pos; - - if ( !ent ) { - idThread::ReturnInt( false ); - return; - } - - if ( move.moveType != MOVETYPE_FLY ) { - if ( !ent->GetFloorPos( 64.0f, pos ) ) { - idThread::ReturnInt( false ); - return; - } - if ( ent->IsType( idActor::Type ) && static_cast( ent )->OnLadder() ) { - idThread::ReturnInt( false ); - return; - } - } else { - pos = ent->GetPhysics()->GetOrigin(); - } - - toAreaNum = PointReachableAreaNum( pos ); - if ( !toAreaNum ) { - idThread::ReturnInt( false ); - return; - } - - const idVec3 &org = physicsObj.GetOrigin(); - areaNum = PointReachableAreaNum( org ); - if ( !toAreaNum || !PathToGoal( path, areaNum, org, toAreaNum, pos ) ) { - idThread::ReturnInt( false ); - } else { - idThread::ReturnInt( true ); - } -} - -/* -================ -idAI::Event_CanReachEnemy -================ -*/ -void idAI::Event_CanReachEnemy( void ) { - aasPath_t path; - int toAreaNum; - int areaNum; - idVec3 pos; - idActor *enemyEnt; - - enemyEnt = enemy.GetEntity(); - if ( !enemyEnt ) { - idThread::ReturnInt( false ); - return; - } - - if ( move.moveType != MOVETYPE_FLY ) { - if ( enemyEnt->OnLadder() ) { - idThread::ReturnInt( false ); - return; - } - enemyEnt->GetAASLocation( aas, pos, toAreaNum ); - } else { - pos = enemyEnt->GetPhysics()->GetOrigin(); - toAreaNum = PointReachableAreaNum( pos ); - } - - if ( !toAreaNum ) { - idThread::ReturnInt( false ); - return; - } - - const idVec3 &org = physicsObj.GetOrigin(); - areaNum = PointReachableAreaNum( org ); - if ( !PathToGoal( path, areaNum, org, toAreaNum, pos ) ) { - idThread::ReturnInt( false ); - } else { - idThread::ReturnInt( true ); - } -} - -/* -================ -idAI::Event_GetReachableEntityPosition -================ -*/ -void idAI::Event_GetReachableEntityPosition( idEntity *ent ) { - int toAreaNum; - idVec3 pos; - - if ( move.moveType != MOVETYPE_FLY ) { - if ( !ent->GetFloorPos( 64.0f, pos ) ) { - // NOTE: not a good way to return 'false' - return idThread::ReturnVector( vec3_zero ); - } - if ( ent->IsType( idActor::Type ) && static_cast( ent )->OnLadder() ) { - // NOTE: not a good way to return 'false' - return idThread::ReturnVector( vec3_zero ); - } - } else { - pos = ent->GetPhysics()->GetOrigin(); - } - - if ( aas ) { - toAreaNum = PointReachableAreaNum( pos ); - aas->PushPointIntoAreaNum( toAreaNum, pos ); - } - - idThread::ReturnVector( pos ); -} - -#ifdef _D3XP -/* -================ -idAI::Event_MoveToPositionDirect -================ -*/ -void idAI::Event_MoveToPositionDirect( const idVec3 &pos ) { - StopMove( MOVE_STATUS_DONE ); - DirectMoveToPosition( pos ); -} - -/* -================ -idAI::Event_AvoidObstacles -================ -*/ -void idAI::Event_AvoidObstacles( int ignore) { - ignore_obstacles = (ignore == 1) ? false : true; -} - -/* -================ -idAI::Event_TriggerFX -================ -*/ -void idAI::Event_TriggerFX( const char* joint, const char* fx ) { - TriggerFX(joint, fx); -} - -void idAI::Event_StartEmitter( const char* name, const char* joint, const char* particle ) { - idEntity *ent = StartEmitter(name, joint, particle); - idThread::ReturnEntity(ent); -} - -void idAI::Event_GetEmitter( const char* name ) { - idThread::ReturnEntity(GetEmitter(name)); -} - -void idAI::Event_StopEmitter( const char* name ) { - StopEmitter(name); -} - -#endif diff --git a/d3xp/ai/AI_pathing.cpp b/d3xp/ai/AI_pathing.cpp deleted file mode 100644 index 4b043dc5..00000000 --- a/d3xp/ai/AI_pathing.cpp +++ /dev/null @@ -1,1536 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "idlib/containers/Queue.h" -#include "idlib/geometry/Winding2D.h" - -#include "gamesys/SysCvar.h" -#include "Moveable.h" -#include "WorldSpawn.h" - -#include "ai/AI.h" - -/* -=============================================================================== - - Dynamic Obstacle Avoidance - - - assumes the AI lives inside a bounding box aligned with the gravity direction - - obstacles in proximity of the AI are gathered - - if obstacles are found the AAS walls are also considered as obstacles - - every obstacle is represented by an oriented bounding box (OBB) - - an OBB is projected onto a 2D plane orthogonal to AI's gravity direction - - the 2D windings of the projections are expanded for the AI bbox - - a path tree is build using clockwise and counter clockwise edge walks along the winding edges - - the path tree is pruned and optimized - - the shortest path is chosen for navigation - -=============================================================================== -*/ - -const float MAX_OBSTACLE_RADIUS = 256.0f; -const float PUSH_OUTSIDE_OBSTACLES = 0.5f; -const float CLIP_BOUNDS_EPSILON = 10.0f; -const int MAX_AAS_WALL_EDGES = 256; -const int MAX_OBSTACLES = 256; -const int MAX_PATH_NODES = 256; -const int MAX_OBSTACLE_PATH = 64; - -typedef struct obstacle_s { - idVec2 bounds[2]; - idWinding2D winding; - idEntity * entity; -} obstacle_t; - -typedef struct pathNode_s { - int dir; - idVec2 pos; - idVec2 delta; - float dist; - int obstacle; - int edgeNum; - int numNodes; - struct pathNode_s * parent; - struct pathNode_s * children[2]; - struct pathNode_s * next; - void Init(); -} pathNode_t; - -void pathNode_s::Init() { - dir = 0; - pos.Zero(); - delta.Zero(); - obstacle = -1; - edgeNum = -1; - numNodes = 0; - parent = children[0] = children[1] = next = NULL; -} - -idBlockAlloc pathNodeAllocator; - - -/* -============ -LineIntersectsPath -============ -*/ -bool LineIntersectsPath( const idVec2 &start, const idVec2 &end, const pathNode_t *node ) { - float d0, d1, d2, d3; - idVec3 plane1, plane2; - - plane1 = idWinding2D::Plane2DFromPoints( start, end ); - d0 = plane1.x * node->pos.x + plane1.y * node->pos.y + plane1.z; - while( node->parent ) { - d1 = plane1.x * node->parent->pos.x + plane1.y * node->parent->pos.y + plane1.z; - if ( FLOATSIGNBITSET( d0 ) ^ FLOATSIGNBITSET( d1 ) ) { - plane2 = idWinding2D::Plane2DFromPoints( node->pos, node->parent->pos ); - d2 = plane2.x * start.x + plane2.y * start.y + plane2.z; - d3 = plane2.x * end.x + plane2.y * end.y + plane2.z; - if ( FLOATSIGNBITSET( d2 ) ^ FLOATSIGNBITSET( d3 ) ) { - return true; - } - } - d0 = d1; - node = node->parent; - } - return false; -} - -/* -============ -PointInsideObstacle -============ -*/ -int PointInsideObstacle( const obstacle_t *obstacles, const int numObstacles, const idVec2 &point ) { - int i; - - for ( i = 0; i < numObstacles; i++ ) { - - const idVec2 *bounds = obstacles[i].bounds; - if ( point.x < bounds[0].x || point.y < bounds[0].y || point.x > bounds[1].x || point.y > bounds[1].y ) { - continue; - } - - if ( !obstacles[i].winding.PointInside( point, 0.1f ) ) { - continue; - } - - return i; - } - - return -1; -} - -/* -============ -GetPointOutsideObstacles -============ -*/ -void GetPointOutsideObstacles( const obstacle_t *obstacles, const int numObstacles, idVec2 &point, int *obstacle, int *edgeNum ) { - int i, j, k, n, bestObstacle, bestEdgeNum, queueStart, queueEnd, edgeNums[2]; - float d, bestd, scale[2]; - idVec3 plane, bestPlane; - idVec2 newPoint, dir, bestPoint; - int *queue; - bool *obstacleVisited; - idWinding2D w1, w2; - - if ( obstacle ) { - *obstacle = -1; - } - if ( edgeNum ) { - *edgeNum = -1; - } - - bestObstacle = PointInsideObstacle( obstacles, numObstacles, point ); - if ( bestObstacle == -1 ) { - return; - } - - const idWinding2D &w = obstacles[bestObstacle].winding; - bestd = idMath::INFINITY; - bestEdgeNum = 0; - for ( i = 0; i < w.GetNumPoints(); i++ ) { - plane = idWinding2D::Plane2DFromPoints( w[(i+1)%w.GetNumPoints()], w[i], true ); - d = plane.x * point.x + plane.y * point.y + plane.z; - if ( d < bestd ) { - bestd = d; - bestPlane = plane; - bestEdgeNum = i; - } - // if this is a wall always try to pop out at the first edge - if ( obstacles[bestObstacle].entity == NULL ) { - break; - } - } - - if (i == 0) - return; - - newPoint = point - ( bestd + PUSH_OUTSIDE_OBSTACLES ) * bestPlane.ToVec2(); - if ( PointInsideObstacle( obstacles, numObstacles, newPoint ) == -1 ) { - point = newPoint; - if ( obstacle ) { - *obstacle = bestObstacle; - } - if ( edgeNum ) { - *edgeNum = bestEdgeNum; - } - return; - } - - queue = (int *) _alloca( numObstacles * sizeof( queue[0] ) ); - obstacleVisited = (bool *) _alloca( numObstacles * sizeof( obstacleVisited[0] ) ); - - queueStart = 0; - queueEnd = 1; - queue[0] = bestObstacle; - - memset( obstacleVisited, 0, numObstacles * sizeof( obstacleVisited[0] ) ); - obstacleVisited[bestObstacle] = true; - - bestd = idMath::INFINITY; - for ( i = queue[0]; queueStart < queueEnd; i = queue[++queueStart] ) { - w1 = obstacles[i].winding; - w1.Expand( PUSH_OUTSIDE_OBSTACLES ); - - for ( j = 0; j < numObstacles; j++ ) { - // if the obstacle has been visited already - if ( obstacleVisited[j] ) { - continue; - } - // if the bounds do not intersect - if ( obstacles[j].bounds[0].x > obstacles[i].bounds[1].x || obstacles[j].bounds[0].y > obstacles[i].bounds[1].y || - obstacles[j].bounds[1].x < obstacles[i].bounds[0].x || obstacles[j].bounds[1].y < obstacles[i].bounds[0].y ) { - continue; - } - - queue[queueEnd++] = j; - obstacleVisited[j] = true; - - w2 = obstacles[j].winding; - w2.Expand( 0.2f ); - - for ( k = 0; k < w1.GetNumPoints(); k++ ) { - dir = w1[(k+1)%w1.GetNumPoints()] - w1[k]; - if ( !w2.RayIntersection( w1[k], dir, scale[0], scale[1], edgeNums ) ) { - continue; - } - for ( n = 0; n < 2; n++ ) { - newPoint = w1[k] + scale[n] * dir; - if ( PointInsideObstacle( obstacles, numObstacles, newPoint ) == -1 ) { - d = ( newPoint - point ).LengthSqr(); - if ( d < bestd ) { - bestd = d; - bestPoint = newPoint; - bestEdgeNum = edgeNums[n]; - bestObstacle = j; - } - } - } - } - } - - if ( bestd < idMath::INFINITY ) { - point = bestPoint; - if ( obstacle ) { - *obstacle = bestObstacle; - } - if ( edgeNum ) { - *edgeNum = bestEdgeNum; - } - return; - } - } - gameLocal.Warning( "GetPointOutsideObstacles: no valid point found" ); -} - -/* -============ -GetFirstBlockingObstacle -============ -*/ -bool GetFirstBlockingObstacle( const obstacle_t *obstacles, int numObstacles, int skipObstacle, const idVec2 &startPos, const idVec2 &delta, float &blockingScale, int &blockingObstacle, int &blockingEdgeNum ) { - int i, edgeNums[2]; - float dist, scale1, scale2; - idVec2 bounds[2]; - - // get bounds for the current movement delta - bounds[0] = startPos - idVec2( CM_BOX_EPSILON, CM_BOX_EPSILON ); - bounds[1] = startPos + idVec2( CM_BOX_EPSILON, CM_BOX_EPSILON ); - bounds[FLOATSIGNBITNOTSET(delta.x)].x += delta.x; - bounds[FLOATSIGNBITNOTSET(delta.y)].y += delta.y; - - // test for obstacles blocking the path - blockingScale = idMath::INFINITY; - dist = delta.Length(); - for ( i = 0; i < numObstacles; i++ ) { - if ( i == skipObstacle ) { - continue; - } - if ( bounds[0].x > obstacles[i].bounds[1].x || bounds[0].y > obstacles[i].bounds[1].y || - bounds[1].x < obstacles[i].bounds[0].x || bounds[1].y < obstacles[i].bounds[0].y ) { - continue; - } - if ( obstacles[i].winding.RayIntersection( startPos, delta, scale1, scale2, edgeNums ) ) { - if ( scale1 < blockingScale && scale1 * dist > -0.01f && scale2 * dist > 0.01f ) { - blockingScale = scale1; - blockingObstacle = i; - blockingEdgeNum = edgeNums[0]; - } - } - } - return ( blockingScale < 1.0f ); -} - -/* -============ -GetObstacles -============ -*/ -int GetObstacles( const idPhysics *physics, const idAAS *aas, const idEntity *ignore, int areaNum, const idVec3 &startPos, const idVec3 &seekPos, obstacle_t *obstacles, int maxObstacles, idBounds &clipBounds ) { - int i, j, numListedClipModels, numObstacles, numVerts, clipMask, blockingObstacle, blockingEdgeNum; - int wallEdges[MAX_AAS_WALL_EDGES], numWallEdges, verts[2], lastVerts[2], nextVerts[2]; - float stepHeight, headHeight, blockingScale, min, max; - idVec3 seekDelta, silVerts[32], start, end, nextStart, nextEnd; - idVec2 expBounds[2], edgeDir, edgeNormal, nextEdgeDir, nextEdgeNormal, lastEdgeNormal; - idVec2 obDelta; - idPhysics *obPhys; - idBox box; - idEntity *obEnt; - idClipModel *clipModel; - idClipModel *clipModelList[ MAX_GENTITIES ]; - - numObstacles = 0; - - seekDelta = seekPos - startPos; - expBounds[0] = physics->GetBounds()[0].ToVec2() - idVec2( CM_BOX_EPSILON, CM_BOX_EPSILON ); - expBounds[1] = physics->GetBounds()[1].ToVec2() + idVec2( CM_BOX_EPSILON, CM_BOX_EPSILON ); - - physics->GetAbsBounds().AxisProjection( -physics->GetGravityNormal(), stepHeight, headHeight ); - stepHeight += aas->GetSettings()->maxStepHeight; - - // clip bounds for the obstacle search space - clipBounds[0] = clipBounds[1] = startPos; - clipBounds.AddPoint( seekPos ); - clipBounds.ExpandSelf( MAX_OBSTACLE_RADIUS ); - clipMask = physics->GetClipMask(); - - // find all obstacles touching the clip bounds - numListedClipModels = gameLocal.clip.ClipModelsTouchingBounds( clipBounds, clipMask, clipModelList, MAX_GENTITIES ); - - for ( i = 0; i < numListedClipModels && numObstacles < MAX_OBSTACLES; i++ ) { - clipModel = clipModelList[i]; - obEnt = clipModel->GetEntity(); - - if ( !clipModel->IsTraceModel() ) { - continue; - } - - if ( obEnt->IsType( idActor::Type ) ) { - obPhys = obEnt->GetPhysics(); - // ignore myself, my enemy, and dead bodies - if ( ( obPhys == physics ) || ( obEnt == ignore ) || ( obEnt->health <= 0 ) ) { - continue; - } - // if the actor is moving - idVec3 v1 = obPhys->GetLinearVelocity(); - if ( v1.LengthSqr() > Square( 10.0f ) ) { - idVec3 v2 = physics->GetLinearVelocity(); - if ( v2.LengthSqr() > Square( 10.0f ) ) { - // if moving in about the same direction - if ( v1 * v2 > 0.0f ) { - continue; - } - } - } - } else if ( obEnt->IsType( idMoveable::Type ) ) { - // moveables are considered obstacles - } else { - // ignore everything else - continue; - } - - // check if we can step over the object - clipModel->GetAbsBounds().AxisProjection( -physics->GetGravityNormal(), min, max ); - if ( max < stepHeight || min > headHeight ) { - // can step over this one - continue; - } - - // project a box containing the obstacle onto the floor plane - box = idBox( clipModel->GetBounds(), clipModel->GetOrigin(), clipModel->GetAxis() ); - numVerts = box.GetParallelProjectionSilhouetteVerts( physics->GetGravityNormal(), silVerts ); - - // create a 2D winding for the obstacle; - obstacle_t &obstacle = obstacles[numObstacles++]; - obstacle.winding.Clear(); - for ( j = 0; j < numVerts; j++ ) { - obstacle.winding.AddPoint( silVerts[j].ToVec2() ); - } - - if ( ai_showObstacleAvoidance.GetBool() ) { - for ( j = 0; j < numVerts; j++ ) { - silVerts[j].z = startPos.z; - } - for ( j = 0; j < numVerts; j++ ) { - gameRenderWorld->DebugArrow( colorWhite, silVerts[j], silVerts[(j+1)%numVerts], 4 ); - } - } - - // expand the 2D winding for collision with a 2D box - obstacle.winding.ExpandForAxialBox( expBounds ); - obstacle.winding.GetBounds( obstacle.bounds ); - obstacle.entity = obEnt; - } - - // if there are no dynamic obstacles the path should be through valid AAS space - if ( numObstacles == 0 ) { - return 0; - } - - // if the current path doesn't intersect any dynamic obstacles the path should be through valid AAS space - if ( PointInsideObstacle( obstacles, numObstacles, startPos.ToVec2() ) == -1 ) { - if ( !GetFirstBlockingObstacle( obstacles, numObstacles, -1, startPos.ToVec2(), seekDelta.ToVec2(), blockingScale, blockingObstacle, blockingEdgeNum ) ) { - return 0; - } - } - - // create obstacles for AAS walls - if ( aas ) { - float halfBoundsSize = ( expBounds[ 1 ].x - expBounds[ 0 ].x ) * 0.5f; - - numWallEdges = aas->GetWallEdges( areaNum, clipBounds, TFL_WALK, wallEdges, MAX_AAS_WALL_EDGES ); - aas->SortWallEdges( wallEdges, numWallEdges ); - - lastVerts[0] = lastVerts[1] = 0; - lastEdgeNormal.Zero(); - nextEdgeNormal.Zero(); - nextVerts[0] = nextVerts[1] = 0; - for ( i = 0; i < numWallEdges && numObstacles < MAX_OBSTACLES; i++ ) { - aas->GetEdge( wallEdges[i], start, end ); - aas->GetEdgeVertexNumbers( wallEdges[i], verts ); - edgeDir = end.ToVec2() - start.ToVec2(); - edgeDir.Normalize(); - edgeNormal.x = edgeDir.y; - edgeNormal.y = -edgeDir.x; - if ( i < numWallEdges-1 ) { - aas->GetEdge( wallEdges[i+1], nextStart, nextEnd ); - aas->GetEdgeVertexNumbers( wallEdges[i+1], nextVerts ); - nextEdgeDir = nextEnd.ToVec2() - nextStart.ToVec2(); - nextEdgeDir.Normalize(); - nextEdgeNormal.x = nextEdgeDir.y; - nextEdgeNormal.y = -nextEdgeDir.x; - } - - obstacle_t &obstacle = obstacles[numObstacles++]; - obstacle.winding.Clear(); - obstacle.winding.AddPoint( end.ToVec2() ); - obstacle.winding.AddPoint( start.ToVec2() ); - obstacle.winding.AddPoint( start.ToVec2() - edgeDir - edgeNormal * halfBoundsSize ); - obstacle.winding.AddPoint( end.ToVec2() + edgeDir - edgeNormal * halfBoundsSize ); - if ( lastVerts[1] == verts[0] ) { - obstacle.winding[2] -= lastEdgeNormal * halfBoundsSize; - } else { - obstacle.winding[1] -= edgeDir; - } - if ( verts[1] == nextVerts[0] ) { - obstacle.winding[3] -= nextEdgeNormal * halfBoundsSize; - } else { - obstacle.winding[0] += edgeDir; - } - obstacle.winding.GetBounds( obstacle.bounds ); - obstacle.entity = NULL; - - memcpy( lastVerts, verts, sizeof( lastVerts ) ); - lastEdgeNormal = edgeNormal; - } - } - - // show obstacles - if ( ai_showObstacleAvoidance.GetBool() ) { - for ( i = 0; i < numObstacles; i++ ) { - obstacle_t &obstacle = obstacles[i]; - for ( j = 0; j < obstacle.winding.GetNumPoints(); j++ ) { - silVerts[j].ToVec2() = obstacle.winding[j]; - silVerts[j].z = startPos.z; - } - for ( j = 0; j < obstacle.winding.GetNumPoints(); j++ ) { - gameRenderWorld->DebugArrow( colorGreen, silVerts[j], silVerts[(j+1)%obstacle.winding.GetNumPoints()], 4 ); - } - } - } - - return numObstacles; -} - -/* -============ -FreePathTree_r -============ -*/ -void FreePathTree_r( pathNode_t *node ) { - if ( node->children[0] ) { - FreePathTree_r( node->children[0] ); - } - if ( node->children[1] ) { - FreePathTree_r( node->children[1] ); - } - pathNodeAllocator.Free( node ); -} - -/* -============ -DrawPathTree -============ -*/ -void DrawPathTree( const pathNode_t *root, const float height ) { - int i; - idVec3 start, end; - const pathNode_t *node; - - for ( node = root; node; node = node->next ) { - for ( i = 0; i < 2; i++ ) { - if ( node->children[i] ) { - start.ToVec2() = node->pos; - start.z = height; - end.ToVec2() = node->children[i]->pos; - end.z = height; - gameRenderWorld->DebugArrow( node->edgeNum == -1 ? colorYellow : i ? colorBlue : colorRed, start, end, 1 ); - break; - } - } - } -} - -/* -============ -GetPathNodeDelta -============ -*/ -bool GetPathNodeDelta( pathNode_t *node, const obstacle_t *obstacles, const idVec2 &seekPos, bool blocked ) { - int numPoints, edgeNum; - bool facing; - idVec2 seekDelta, dir; - pathNode_t *n; - - numPoints = obstacles[node->obstacle].winding.GetNumPoints(); - - // get delta along the current edge - while( 1 ) { - edgeNum = ( node->edgeNum + node->dir ) % numPoints; - node->delta = obstacles[node->obstacle].winding[edgeNum] - node->pos; - if ( node->delta.LengthSqr() > 0.01f ) { - break; - } - node->edgeNum = ( node->edgeNum + numPoints + ( 2 * node->dir - 1 ) ) % numPoints; - } - - // if not blocked - if ( !blocked ) { - - // test if the current edge faces the goal - seekDelta = seekPos - node->pos; - facing = ( ( 2 * node->dir - 1 ) * ( node->delta.x * seekDelta.y - node->delta.y * seekDelta.x ) ) >= 0.0f; - - // if the current edge faces goal and the line from the current - // position to the goal does not intersect the current path - if ( facing && !LineIntersectsPath( node->pos, seekPos, node->parent ) ) { - node->delta = seekPos - node->pos; - node->edgeNum = -1; - } - } - - // if the delta is along the obstacle edge - if ( node->edgeNum != -1 ) { - // if the edge is found going from this node to the root node - for ( n = node->parent; n; n = n->parent ) { - - if ( node->obstacle != n->obstacle || node->edgeNum != n->edgeNum ) { - continue; - } - - // test whether or not the edge segments actually overlap - if ( n->pos * node->delta > ( node->pos + node->delta ) * node->delta ) { - continue; - } - if ( node->pos * node->delta > ( n->pos + n->delta ) * node->delta ) { - continue; - } - - break; - } - if ( n ) { - return false; - } - } - return true; -} - -/* -============ -BuildPathTree -============ -*/ -pathNode_t *BuildPathTree( const obstacle_t *obstacles, int numObstacles, const idBounds &clipBounds, const idVec2 &startPos, const idVec2 &seekPos, obstaclePath_t &path ) { - int blockingEdgeNum, blockingObstacle, obstaclePoints, bestNumNodes = MAX_OBSTACLE_PATH; - float blockingScale; - pathNode_t *root, *node, *child; - // gcc 4.0 - idQueueTemplate pathNodeQueue, treeQueue; - - root = pathNodeAllocator.Alloc(); - root->Init(); - root->pos = startPos; - - root->delta = seekPos - root->pos; - root->numNodes = 0; - pathNodeQueue.Add( root ); - - for ( node = pathNodeQueue.Get(); node && pathNodeAllocator.GetAllocCount() < MAX_PATH_NODES; node = pathNodeQueue.Get() ) { - - treeQueue.Add( node ); - - // if this path has more than twice the number of nodes than the best path so far - if ( node->numNodes > bestNumNodes * 2 ) { - continue; - } - - // don't move outside of the clip bounds - idVec2 endPos = node->pos + node->delta; - if ( endPos.x - CLIP_BOUNDS_EPSILON < clipBounds[0].x || endPos.x + CLIP_BOUNDS_EPSILON > clipBounds[1].x || - endPos.y - CLIP_BOUNDS_EPSILON < clipBounds[0].y || endPos.y + CLIP_BOUNDS_EPSILON > clipBounds[1].y ) { - continue; - } - - // if an obstacle is blocking the path - if ( GetFirstBlockingObstacle( obstacles, numObstacles, node->obstacle, node->pos, node->delta, blockingScale, blockingObstacle, blockingEdgeNum ) ) { - - if ( path.firstObstacle == NULL ) { - path.firstObstacle = obstacles[blockingObstacle].entity; - } - - node->delta *= blockingScale; - - if ( node->edgeNum == -1 ) { - node->children[0] = pathNodeAllocator.Alloc(); - node->children[0]->Init(); - node->children[1] = pathNodeAllocator.Alloc(); - node->children[1]->Init(); - node->children[0]->dir = 0; - node->children[1]->dir = 1; - node->children[0]->parent = node->children[1]->parent = node; - node->children[0]->pos = node->children[1]->pos = node->pos + node->delta; - node->children[0]->obstacle = node->children[1]->obstacle = blockingObstacle; - node->children[0]->edgeNum = node->children[1]->edgeNum = blockingEdgeNum; - node->children[0]->numNodes = node->children[1]->numNodes = node->numNodes + 1; - if ( GetPathNodeDelta( node->children[0], obstacles, seekPos, true ) ) { - pathNodeQueue.Add( node->children[0] ); - } - if ( GetPathNodeDelta( node->children[1], obstacles, seekPos, true ) ) { - pathNodeQueue.Add( node->children[1] ); - } - } else { - node->children[node->dir] = child = pathNodeAllocator.Alloc(); - child->Init(); - child->dir = node->dir; - child->parent = node; - child->pos = node->pos + node->delta; - child->obstacle = blockingObstacle; - child->edgeNum = blockingEdgeNum; - child->numNodes = node->numNodes + 1; - if ( GetPathNodeDelta( child, obstacles, seekPos, true ) ) { - pathNodeQueue.Add( child ); - } - } - } else { - node->children[node->dir] = child = pathNodeAllocator.Alloc(); - child->Init(); - child->dir = node->dir; - child->parent = node; - child->pos = node->pos + node->delta; - child->numNodes = node->numNodes + 1; - - // there is a free path towards goal - if ( node->edgeNum == -1 ) { - if ( node->numNodes < bestNumNodes ) { - bestNumNodes = node->numNodes; - } - continue; - } - - child->obstacle = node->obstacle; - obstaclePoints = obstacles[node->obstacle].winding.GetNumPoints(); - child->edgeNum = ( node->edgeNum + obstaclePoints + ( 2 * node->dir - 1 ) ) % obstaclePoints; - - if ( GetPathNodeDelta( child, obstacles, seekPos, false ) ) { - pathNodeQueue.Add( child ); - } - } - } - - return root; -} - -/* -============ -PrunePathTree -============ -*/ -void PrunePathTree( pathNode_t *root, const idVec2 &seekPos ) { - int i; - float bestDist; - pathNode_t *node, *lastNode, *n, *bestNode; - - node = root; - while( node ) { - - node->dist = ( seekPos - node->pos ).LengthSqr(); - - if ( node->children[0] ) { - node = node->children[0]; - } else if ( node->children[1] ) { - node = node->children[1]; - } else { - - // find the node closest to the goal along this path - bestDist = idMath::INFINITY; - bestNode = node; - for ( n = node; n; n = n->parent ) { - if ( n->children[0] && n->children[1] ) { - break; - } - if ( n->dist < bestDist ) { - bestDist = n->dist; - bestNode = n; - } - } - - // free tree down from the best node - for ( i = 0; i < 2; i++ ) { - if ( bestNode->children[i] ) { - FreePathTree_r( bestNode->children[i] ); - bestNode->children[i] = NULL; - } - } - - for ( lastNode = bestNode, node = bestNode->parent; node; lastNode = node, node = node->parent ) { - if ( node->children[1] && ( node->children[1] != lastNode ) ) { - node = node->children[1]; - break; - } - } - } - } -} - -/* -============ -OptimizePath -============ -*/ -int OptimizePath( const pathNode_t *root, const pathNode_t *leafNode, const obstacle_t *obstacles, int numObstacles, idVec2 optimizedPath[MAX_OBSTACLE_PATH] ) { - int i, numPathPoints, edgeNums[2]; - const pathNode_t *curNode, *nextNode; - idVec2 curPos, curDelta, bounds[2]; - float scale1, scale2, curLength; - - optimizedPath[0] = root->pos; - numPathPoints = 1; - - for ( nextNode = curNode = root; curNode != leafNode; curNode = nextNode ) { - - for ( nextNode = leafNode; nextNode->parent != curNode; nextNode = nextNode->parent ) { - - // can only take shortcuts when going from one object to another - if ( nextNode->obstacle == curNode->obstacle ) { - continue; - } - - curPos = curNode->pos; - curDelta = nextNode->pos - curPos; - curLength = curDelta.Length(); - - // get bounds for the current movement delta - bounds[0] = curPos - idVec2( CM_BOX_EPSILON, CM_BOX_EPSILON ); - bounds[1] = curPos + idVec2( CM_BOX_EPSILON, CM_BOX_EPSILON ); - bounds[FLOATSIGNBITNOTSET(curDelta.x)].x += curDelta.x; - bounds[FLOATSIGNBITNOTSET(curDelta.y)].y += curDelta.y; - - // test if the shortcut intersects with any obstacles - for ( i = 0; i < numObstacles; i++ ) { - if ( bounds[0].x > obstacles[i].bounds[1].x || bounds[0].y > obstacles[i].bounds[1].y || - bounds[1].x < obstacles[i].bounds[0].x || bounds[1].y < obstacles[i].bounds[0].y ) { - continue; - } - if ( obstacles[i].winding.RayIntersection( curPos, curDelta, scale1, scale2, edgeNums ) ) { - if ( scale1 >= 0.0f && scale1 <= 1.0f && ( i != nextNode->obstacle || scale1 * curLength < curLength - 0.5f ) ) { - break; - } - if ( scale2 >= 0.0f && scale2 <= 1.0f && ( i != nextNode->obstacle || scale2 * curLength < curLength - 0.5f ) ) { - break; - } - } - } - if ( i >= numObstacles ) { - break; - } - } - - // store the next position along the optimized path - optimizedPath[numPathPoints++] = nextNode->pos; - } - - return numPathPoints; -} - -/* -============ -PathLength -============ -*/ -float PathLength( idVec2 optimizedPath[MAX_OBSTACLE_PATH], int numPathPoints, const idVec2 &curDir ) { - int i; - float pathLength; - - // calculate the path length - pathLength = 0.0f; - for ( i = 0; i < numPathPoints-1; i++ ) { - pathLength += ( optimizedPath[i+1] - optimizedPath[i] ).LengthFast(); - } - - // add penalty if this path does not go in the current direction - if ( curDir * ( optimizedPath[1] - optimizedPath[0] ) < 0.0f ) { - pathLength += 100.0f; - } - return pathLength; -} - -/* -============ -FindOptimalPath - - Returns true if there is a path all the way to the goal. -============ -*/ -bool FindOptimalPath( const pathNode_t *root, const obstacle_t *obstacles, int numObstacles, const float height, const idVec3 &curDir, idVec3 &seekPos ) { - int i, numPathPoints, bestNumPathPoints; - const pathNode_t *node, *lastNode, *bestNode; - idVec2 optimizedPath[MAX_OBSTACLE_PATH]; - float pathLength, bestPathLength; - bool pathToGoalExists, optimizedPathCalculated; - - seekPos.Zero(); - seekPos.z = height; - - pathToGoalExists = false; - optimizedPathCalculated = false; - - bestNode = root; - bestNumPathPoints = 0; - bestPathLength = idMath::INFINITY; - - node = root; - while( node ) { - - pathToGoalExists |= ( node->dist < 0.1f ); - - if ( node->dist <= bestNode->dist ) { - - if ( idMath::Fabs( node->dist - bestNode->dist ) < 0.1f ) { - - if ( !optimizedPathCalculated ) { - bestNumPathPoints = OptimizePath( root, bestNode, obstacles, numObstacles, optimizedPath ); - bestPathLength = PathLength( optimizedPath, bestNumPathPoints, curDir.ToVec2() ); - seekPos.ToVec2() = optimizedPath[1]; - } - - numPathPoints = OptimizePath( root, node, obstacles, numObstacles, optimizedPath ); - pathLength = PathLength( optimizedPath, numPathPoints, curDir.ToVec2() ); - - if ( pathLength < bestPathLength ) { - bestNode = node; - bestNumPathPoints = numPathPoints; - bestPathLength = pathLength; - seekPos.ToVec2() = optimizedPath[1]; - } - optimizedPathCalculated = true; - - } else { - - bestNode = node; - optimizedPathCalculated = false; - } - } - - if ( node->children[0] ) { - node = node->children[0]; - } else if ( node->children[1] ) { - node = node->children[1]; - } else { - for ( lastNode = node, node = node->parent; node; lastNode = node, node = node->parent ) { - if ( node->children[1] && node->children[1] != lastNode ) { - node = node->children[1]; - break; - } - } - } - } - - if ( !pathToGoalExists ) { - seekPos.ToVec2() = root->children[0]->pos; - } else if ( !optimizedPathCalculated ) { - OptimizePath( root, bestNode, obstacles, numObstacles, optimizedPath ); - seekPos.ToVec2() = optimizedPath[1]; - } - - if ( ai_showObstacleAvoidance.GetBool() ) { - idVec3 start, end; - start.z = end.z = height + 4.0f; - numPathPoints = OptimizePath( root, bestNode, obstacles, numObstacles, optimizedPath ); - for ( i = 0; i < numPathPoints-1; i++ ) { - start.ToVec2() = optimizedPath[i]; - end.ToVec2() = optimizedPath[i+1]; - gameRenderWorld->DebugArrow( colorCyan, start, end, 1 ); - } - } - - return pathToGoalExists; -} - -/* -============ -idAI::FindPathAroundObstacles - - Finds a path around dynamic obstacles using a path tree with clockwise and counter clockwise edge walks. -============ -*/ -bool idAI::FindPathAroundObstacles( const idPhysics *physics, const idAAS *aas, const idEntity *ignore, const idVec3 &startPos, const idVec3 &seekPos, obstaclePath_t &path ) { - int numObstacles, areaNum, insideObstacle; - obstacle_t obstacles[MAX_OBSTACLES]; - idBounds clipBounds; - idBounds bounds; - pathNode_t *root; - bool pathToGoalExists; - - path.seekPos = seekPos; - path.firstObstacle = NULL; - path.startPosOutsideObstacles = startPos; - path.startPosObstacle = NULL; - path.seekPosOutsideObstacles = seekPos; - path.seekPosObstacle = NULL; - - if ( !aas ) { - return true; - } - - bounds[1] = aas->GetSettings()->boundingBoxes[0][1]; - bounds[0] = -bounds[1]; - bounds[1].z = 32.0f; - - // get the AAS area number and a valid point inside that area - areaNum = aas->PointReachableAreaNum( path.startPosOutsideObstacles, bounds, (AREA_REACHABLE_WALK|AREA_REACHABLE_FLY) ); - aas->PushPointIntoAreaNum( areaNum, path.startPosOutsideObstacles ); - - // get all the nearby obstacles - numObstacles = GetObstacles( physics, aas, ignore, areaNum, path.startPosOutsideObstacles, path.seekPosOutsideObstacles, obstacles, MAX_OBSTACLES, clipBounds ); - - // get a source position outside the obstacles - GetPointOutsideObstacles( obstacles, numObstacles, path.startPosOutsideObstacles.ToVec2(), &insideObstacle, NULL ); - if ( insideObstacle != -1 ) { - path.startPosObstacle = obstacles[insideObstacle].entity; - } - - // get a goal position outside the obstacles - GetPointOutsideObstacles( obstacles, numObstacles, path.seekPosOutsideObstacles.ToVec2(), &insideObstacle, NULL ); - if ( insideObstacle != -1 ) { - path.seekPosObstacle = obstacles[insideObstacle].entity; - } - - // if start and destination are pushed to the same point, we don't have a path around the obstacle - if ( ( path.seekPosOutsideObstacles.ToVec2() - path.startPosOutsideObstacles.ToVec2() ).LengthSqr() < Square( 1.0f ) ) { - if ( ( seekPos.ToVec2() - startPos.ToVec2() ).LengthSqr() > Square( 2.0f ) ) { - return false; - } - } - - // build a path tree - root = BuildPathTree( obstacles, numObstacles, clipBounds, path.startPosOutsideObstacles.ToVec2(), path.seekPosOutsideObstacles.ToVec2(), path ); - - // draw the path tree - if ( ai_showObstacleAvoidance.GetBool() ) { - DrawPathTree( root, physics->GetOrigin().z ); - } - - // prune the tree - PrunePathTree( root, path.seekPosOutsideObstacles.ToVec2() ); - - // find the optimal path - pathToGoalExists = FindOptimalPath( root, obstacles, numObstacles, physics->GetOrigin().z, physics->GetLinearVelocity(), path.seekPos ); - - // free the tree - FreePathTree_r( root ); - - return pathToGoalExists; -} - -/* -============ -idAI::FreeObstacleAvoidanceNodes -============ -*/ -void idAI::FreeObstacleAvoidanceNodes( void ) { - pathNodeAllocator.Shutdown(); -} - - -/* -=============================================================================== - - Path Prediction - - Uses the AAS to quickly and accurately predict a path for a certain - period of time based on an initial position and velocity. - -=============================================================================== -*/ - -const float OVERCLIP = 1.001f; -const int MAX_FRAME_SLIDE = 5; - -typedef struct pathTrace_s { - float fraction; - idVec3 endPos; - idVec3 normal; - const idEntity * blockingEntity; -} pathTrace_t; - -/* -============ -PathTrace - - Returns true if a stop event was triggered. -============ -*/ -bool PathTrace( const idEntity *ent, const idAAS *aas, const idVec3 &start, const idVec3 &end, int stopEvent, struct pathTrace_s &trace, predictedPath_t &path ) { - trace_t clipTrace; - aasTrace_t aasTrace; - - memset( &trace, 0, sizeof( trace ) ); - - if ( !aas || !aas->GetSettings() ) { - - gameLocal.clip.Translation( clipTrace, start, end, ent->GetPhysics()->GetClipModel(), - ent->GetPhysics()->GetClipModel()->GetAxis(), MASK_MONSTERSOLID, ent ); - - // NOTE: could do (expensive) ledge detection here for when there is no AAS file - - trace.fraction = clipTrace.fraction; - trace.endPos = clipTrace.endpos; - trace.normal = clipTrace.c.normal; - trace.blockingEntity = gameLocal.entities[ clipTrace.c.entityNum ]; - } else { - aasTrace.getOutOfSolid = true; - if ( stopEvent & SE_ENTER_LEDGE_AREA ) { - aasTrace.flags |= AREA_LEDGE; - } - if ( stopEvent & SE_ENTER_OBSTACLE ) { - aasTrace.travelFlags |= TFL_INVALID; - } - - aas->Trace( aasTrace, start, end ); - - gameLocal.clip.TranslationEntities( clipTrace, start, aasTrace.endpos, ent->GetPhysics()->GetClipModel(), - ent->GetPhysics()->GetClipModel()->GetAxis(), MASK_MONSTERSOLID, ent ); - - if ( clipTrace.fraction >= 1.0f ) { - - trace.fraction = aasTrace.fraction; - trace.endPos = aasTrace.endpos; - trace.normal = aas->GetPlane( aasTrace.planeNum ).Normal(); - trace.blockingEntity = gameLocal.world; - - if ( aasTrace.fraction < 1.0f ) { - if ( stopEvent & SE_ENTER_LEDGE_AREA ) { - if ( aas->AreaFlags( aasTrace.blockingAreaNum ) & AREA_LEDGE ) { - path.endPos = trace.endPos; - path.endNormal = trace.normal; - path.endEvent = SE_ENTER_LEDGE_AREA; - path.blockingEntity = trace.blockingEntity; - - if ( ai_debugMove.GetBool() ) { - gameRenderWorld->DebugLine( colorRed, start, aasTrace.endpos ); - } - return true; - } - } - if ( stopEvent & SE_ENTER_OBSTACLE ) { - if ( aas->AreaTravelFlags( aasTrace.blockingAreaNum ) & TFL_INVALID ) { - path.endPos = trace.endPos; - path.endNormal = trace.normal; - path.endEvent = SE_ENTER_OBSTACLE; - path.blockingEntity = trace.blockingEntity; - - if ( ai_debugMove.GetBool() ) { - gameRenderWorld->DebugLine( colorRed, start, aasTrace.endpos ); - } - return true; - } - } - } - } else { - trace.fraction = clipTrace.fraction; - trace.endPos = clipTrace.endpos; - trace.normal = clipTrace.c.normal; - trace.blockingEntity = gameLocal.entities[ clipTrace.c.entityNum ]; - } - } - - if ( trace.fraction >= 1.0f ) { - trace.blockingEntity = NULL; - } - - return false; -} - -/* -============ -idAI::PredictPath - - Can also be used when there is no AAS file available however ledges are not detected. -============ -*/ -bool idAI::PredictPath( const idEntity *ent, const idAAS *aas, const idVec3 &start, const idVec3 &velocity, int totalTime, int frameTime, int stopEvent, predictedPath_t &path ) { - int i, j, step, numFrames, curFrameTime; - idVec3 delta, curStart, curEnd, curVelocity, lastEnd, stepUp, tmpStart; - idVec3 gravity, gravityDir, invGravityDir; - float maxStepHeight, minFloorCos; - pathTrace_t trace; - - if ( aas && aas->GetSettings() ) { - gravity = aas->GetSettings()->gravity; - gravityDir = aas->GetSettings()->gravityDir; - invGravityDir = aas->GetSettings()->invGravityDir; - maxStepHeight = aas->GetSettings()->maxStepHeight; - minFloorCos = aas->GetSettings()->minFloorCos; - } else { - gravity = DEFAULT_GRAVITY_VEC3; - gravityDir = idVec3( 0, 0, -1 ); - invGravityDir = idVec3( 0, 0, 1 ); - maxStepHeight = 14.0f; - minFloorCos = 0.7f; - } - - path.endPos = start; - path.endVelocity = velocity; - path.endNormal.Zero(); - path.endEvent = 0; - path.endTime = 0; - path.blockingEntity = NULL; - - curStart = start; - curVelocity = velocity; - - numFrames = ( totalTime + frameTime - 1 ) / frameTime; - curFrameTime = frameTime; - for ( i = 0; i < numFrames; i++ ) { - - if ( i == numFrames-1 ) { - curFrameTime = totalTime - i * curFrameTime; - } - - delta = curVelocity * curFrameTime * 0.001f; - - path.endVelocity = curVelocity; - path.endTime = i * frameTime; - - // allow sliding along a few surfaces per frame - for ( j = 0; j < MAX_FRAME_SLIDE; j++ ) { - - idVec3 lineStart = curStart; - - // allow stepping up three times per frame - for ( step = 0; step < 3; step++ ) { - - curEnd = curStart + delta; - if ( PathTrace( ent, aas, curStart, curEnd, stopEvent, trace, path ) ) { - return true; - } - - if ( step ) { - - // step down at end point - tmpStart = trace.endPos; - curEnd = tmpStart - stepUp; - if ( PathTrace( ent, aas, tmpStart, curEnd, stopEvent, trace, path ) ) { - return true; - } - - // if not moved any further than without stepping up, or if not on a floor surface - if ( (lastEnd - start).LengthSqr() > (trace.endPos - start).LengthSqr() - 0.1f || - ( trace.normal * invGravityDir ) < minFloorCos ) { - if ( stopEvent & SE_BLOCKED ) { - path.endPos = lastEnd; - path.endEvent = SE_BLOCKED; - - if ( ai_debugMove.GetBool() ) { - gameRenderWorld->DebugLine( colorRed, lineStart, lastEnd ); - } - - return true; - } - - curStart = lastEnd; - break; - } - } - - path.endNormal = trace.normal; - path.blockingEntity = trace.blockingEntity; - - // if the trace is not blocked or blocked by a floor surface - if ( trace.fraction >= 1.0f || ( trace.normal * invGravityDir ) > minFloorCos ) { - curStart = trace.endPos; - break; - } - - // save last result - lastEnd = trace.endPos; - - // step up - stepUp = invGravityDir * maxStepHeight; - if ( PathTrace( ent, aas, curStart, curStart + stepUp, stopEvent, trace, path ) ) { - return true; - } - stepUp *= trace.fraction; - curStart = trace.endPos; - } - - if ( ai_debugMove.GetBool() ) { - gameRenderWorld->DebugLine( colorRed, lineStart, curStart ); - } - - if ( trace.fraction >= 1.0f ) { - break; - } - - delta.ProjectOntoPlane( trace.normal, OVERCLIP ); - curVelocity.ProjectOntoPlane( trace.normal, OVERCLIP ); - - if ( stopEvent & SE_BLOCKED ) { - // if going backwards - if ( (curVelocity - gravityDir * curVelocity * gravityDir ) * - (velocity - gravityDir * velocity * gravityDir) < 0.0f ) { - path.endPos = curStart; - path.endEvent = SE_BLOCKED; - - return true; - } - } - } - - if ( j >= MAX_FRAME_SLIDE ) { - if ( stopEvent & SE_BLOCKED ) { - path.endPos = curStart; - path.endEvent = SE_BLOCKED; - return true; - } - } - - // add gravity - curVelocity += gravity * frameTime * 0.001f; - } - - path.endTime = totalTime; - path.endVelocity = curVelocity; - path.endPos = curStart; - path.endEvent = 0; - - return false; -} - - -/* -=============================================================================== - - Trajectory Prediction - - Finds the best collision free trajectory for a clip model based on an - initial position, target position and speed. - -=============================================================================== -*/ - -/* -===================== -Ballistics - - get the ideal aim pitch angle in order to hit the target - also get the time it takes for the projectile to arrive at the target -===================== -*/ -typedef struct ballistics_s { - float angle; // angle in degrees in the range [-180, 180] - float time; // time it takes before the projectile arrives -} ballistics_t; - -static int Ballistics( const idVec3 &start, const idVec3 &end, float speed, float gravity, ballistics_t bal[2] ) { - int n, i; - float x, y, a, b, c, d, sqrtd, inva, p[2]; - - x = ( end.ToVec2() - start.ToVec2() ).Length(); - y = end[2] - start[2]; - - a = 4.0f * y * y + 4.0f * x * x; - b = -4.0f * speed * speed - 4.0f * y * gravity; - c = gravity * gravity; - - d = b * b - 4.0f * a * c; - if ( d <= 0.0f || a == 0.0f ) { - return 0; - } - sqrtd = idMath::Sqrt( d ); - inva = 0.5f / a; - p[0] = ( - b + sqrtd ) * inva; - p[1] = ( - b - sqrtd ) * inva; - n = 0; - for ( i = 0; i < 2; i++ ) { - if ( p[i] <= 0.0f ) { - continue; - } - d = idMath::Sqrt( p[i] ); - bal[n].angle = atan2( 0.5f * ( 2.0f * y * p[i] - gravity ) / d, d * x ); - bal[n].time = x / ( cos( bal[n].angle ) * speed ); - bal[n].angle = idMath::AngleNormalize180( RAD2DEG( bal[n].angle ) ); - n++; - } - - return n; -} - -/* -===================== -HeightForTrajectory - -Returns the maximum hieght of a given trajectory -===================== -*/ -#if 0 -static float HeightForTrajectory( const idVec3 &start, float zVel, float gravity ) { - float maxHeight, t; - - t = zVel / gravity; - // maximum height of projectile - maxHeight = start.z - 0.5f * gravity * ( t * t ); - - return maxHeight; -} -#endif - -/* -===================== -idAI::TestTrajectory -===================== -*/ -bool idAI::TestTrajectory( const idVec3 &start, const idVec3 &end, float zVel, float gravity, float time, float max_height, const idClipModel *clip, int clipmask, const idEntity *ignore, const idEntity *targetEntity, int drawtime ) { - int i, numSegments; - float maxHeight, t, t2; - idVec3 points[5]; - trace_t trace; - bool result; - - t = zVel / gravity; - // maximum height of projectile - maxHeight = start.z - 0.5f * gravity * ( t * t ); - // time it takes to fall from the top to the end height - t = idMath::Sqrt( ( maxHeight - end.z ) / ( 0.5f * -gravity ) ); - - // start of parabolic - points[0] = start; - - if ( t < time ) { - numSegments = 4; - // point in the middle between top and start - t2 = ( time - t ) * 0.5f; - points[1].ToVec2() = start.ToVec2() + (end.ToVec2() - start.ToVec2()) * ( t2 / time ); - points[1].z = start.z + t2 * zVel + 0.5f * gravity * t2 * t2; - // top of parabolic - t2 = time - t; - points[2].ToVec2() = start.ToVec2() + (end.ToVec2() - start.ToVec2()) * ( t2 / time ); - points[2].z = start.z + t2 * zVel + 0.5f * gravity * t2 * t2; - // point in the middel between top and end - t2 = time - t * 0.5f; - points[3].ToVec2() = start.ToVec2() + (end.ToVec2() - start.ToVec2()) * ( t2 / time ); - points[3].z = start.z + t2 * zVel + 0.5f * gravity * t2 * t2; - } else { - numSegments = 2; - // point halfway through - t2 = time * 0.5f; - points[1].ToVec2() = start.ToVec2() + ( end.ToVec2() - start.ToVec2() ) * 0.5f; - points[1].z = start.z + t2 * zVel + 0.5f * gravity * t2 * t2; - } - - // end of parabolic - points[numSegments] = end; - - if ( drawtime ) { - for ( i = 0; i < numSegments; i++ ) { - gameRenderWorld->DebugLine( colorRed, points[i], points[i+1], drawtime ); - } - } - - // make sure projectile doesn't go higher than we want it to go - for ( i = 0; i < numSegments; i++ ) { - if ( points[i].z > max_height ) { - // goes higher than we want to allow - return false; - } - } - - result = true; - for ( i = 0; i < numSegments; i++ ) { - gameLocal.clip.Translation( trace, points[i], points[i+1], clip, mat3_identity, clipmask, ignore ); - if ( trace.fraction < 1.0f ) { - if ( gameLocal.GetTraceEntity( trace ) == targetEntity ) { - result = true; - } else { - result = false; - } - break; - } - } - - if ( drawtime ) { - if ( clip ) { - gameRenderWorld->DebugBounds( result ? colorGreen : colorYellow, clip->GetBounds().Expand( 1.0f ), trace.endpos, drawtime ); - } else { - idBounds bnds( trace.endpos ); - bnds.ExpandSelf( 1.0f ); - gameRenderWorld->DebugBounds( result ? colorGreen : colorYellow, bnds, vec3_zero, drawtime ); - } - } - - return result; -} - -/* -===================== -idAI::PredictTrajectory - - returns true if there is a collision free trajectory for the clip model - aimDir is set to the ideal aim direction in order to hit the target -===================== -*/ -bool idAI::PredictTrajectory( const idVec3 &firePos, const idVec3 &target, float projectileSpeed, const idVec3 &projGravity, const idClipModel *clip, int clipmask, float max_height, const idEntity *ignore, const idEntity *targetEntity, int drawtime, idVec3 &aimDir ) { - int n, i, j; - float zVel, a, t, pitch, s, c; - trace_t trace; - ballistics_t ballistics[2]; - idVec3 dir[2]; - idVec3 velocity; - idVec3 lastPos, pos; - - assert( targetEntity ); - - // check if the projectile starts inside the target - if ( targetEntity->GetPhysics()->GetAbsBounds().IntersectsBounds( clip->GetBounds().Translate( firePos ) ) ) { - aimDir = target - firePos; - aimDir.Normalize(); - return true; - } - - // if no velocity or the projectile is not affected by gravity - if ( projectileSpeed <= 0.0f || projGravity == vec3_origin ) { - - aimDir = target - firePos; - aimDir.Normalize(); - - gameLocal.clip.Translation( trace, firePos, target, clip, mat3_identity, clipmask, ignore ); - - if ( drawtime ) { - gameRenderWorld->DebugLine( colorRed, firePos, target, drawtime ); - idBounds bnds( trace.endpos ); - bnds.ExpandSelf( 1.0f ); - gameRenderWorld->DebugBounds( ( trace.fraction >= 1.0f || ( gameLocal.GetTraceEntity( trace ) == targetEntity ) ) ? colorGreen : colorYellow, bnds, vec3_zero, drawtime ); - } - - return ( trace.fraction >= 1.0f || ( gameLocal.GetTraceEntity( trace ) == targetEntity ) ); - } - - n = Ballistics( firePos, target, projectileSpeed, projGravity[2], ballistics ); - if ( n == 0 ) { - // there is no valid trajectory - aimDir = target - firePos; - aimDir.Normalize(); - return false; - } - - // make sure the first angle is the smallest - if ( n == 2 ) { - if ( ballistics[1].angle < ballistics[0].angle ) { - a = ballistics[0].angle; ballistics[0].angle = ballistics[1].angle; ballistics[1].angle = a; - t = ballistics[0].time; ballistics[0].time = ballistics[1].time; ballistics[1].time = t; - } - } - - // test if there is a collision free trajectory - for ( i = 0; i < n; i++ ) { - pitch = DEG2RAD( ballistics[i].angle ); - idMath::SinCos( pitch, s, c ); - dir[i] = target - firePos; - dir[i].z = 0.0f; - dir[i] *= c * idMath::InvSqrt( dir[i].LengthSqr() ); - dir[i].z = s; - - zVel = projectileSpeed * dir[i].z; - - if ( ai_debugTrajectory.GetBool() ) { - t = ballistics[i].time / 100.0f; - velocity = dir[i] * projectileSpeed; - lastPos = firePos; - pos = firePos; - for ( j = 1; j < 100; j++ ) { - pos += velocity * t; - velocity += projGravity * t; - gameRenderWorld->DebugLine( colorCyan, lastPos, pos ); - lastPos = pos; - } - } - - if ( TestTrajectory( firePos, target, zVel, projGravity[2], ballistics[i].time, firePos.z + max_height, clip, clipmask, ignore, targetEntity, drawtime ) ) { - aimDir = dir[i]; - return true; - } - } - - aimDir = dir[0]; - - // there is no collision free trajectory - return false; -} diff --git a/d3xp/anim/Anim.cpp b/d3xp/anim/Anim.cpp deleted file mode 100644 index a9f6252d..00000000 --- a/d3xp/anim/Anim.cpp +++ /dev/null @@ -1,1090 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "idlib/geometry/JointTransform.h" -#include "idlib/math/Quat.h" - -#include "Game_local.h" - -#include "anim/Anim.h" - -bool idAnimManager::forceExport = false; - -/*********************************************************************** - - idMD5Anim - -***********************************************************************/ - -/* -==================== -idMD5Anim::idMD5Anim -==================== -*/ -idMD5Anim::idMD5Anim() { - ref_count = 0; - numFrames = 0; - numJoints = 0; - frameRate = 24; - animLength = 0; - totaldelta.Zero(); -} - -/* -==================== -idMD5Anim::idMD5Anim -==================== -*/ -idMD5Anim::~idMD5Anim() { - Free(); -} - -/* -==================== -idMD5Anim::Free -==================== -*/ -void idMD5Anim::Free( void ) { - numFrames = 0; - numJoints = 0; - frameRate = 24; - animLength = 0; - name = ""; - - totaldelta.Zero(); - - jointInfo.Clear(); - bounds.Clear(); - componentFrames.Clear(); -} - -/* -==================== -idMD5Anim::NumFrames -==================== -*/ -int idMD5Anim::NumFrames( void ) const { - return numFrames; -} - -/* -==================== -idMD5Anim::NumJoints -==================== -*/ -int idMD5Anim::NumJoints( void ) const { - return numJoints; -} - -/* -==================== -idMD5Anim::Length -==================== -*/ -int idMD5Anim::Length( void ) const { - return animLength; -} - -/* -===================== -idMD5Anim::TotalMovementDelta -===================== -*/ -const idVec3 &idMD5Anim::TotalMovementDelta( void ) const { - return totaldelta; -} - -/* -===================== -idMD5Anim::TotalMovementDelta -===================== -*/ -const char *idMD5Anim::Name( void ) const { - return name; -} - -/* -==================== -idMD5Anim::Reload -==================== -*/ -bool idMD5Anim::Reload( void ) { - idStr filename; - - filename = name; - Free(); - - return LoadAnim( filename ); -} - -/* -==================== -idMD5Anim::Allocated -==================== -*/ -size_t idMD5Anim::Allocated( void ) const { - size_t size = bounds.Allocated() + jointInfo.Allocated() + componentFrames.Allocated() + name.Allocated(); - return size; -} - -/* -==================== -idMD5Anim::LoadAnim -==================== -*/ -bool idMD5Anim::LoadAnim( const char *filename ) { - int version; - idLexer parser( LEXFL_ALLOWPATHNAMES | LEXFL_NOSTRINGESCAPECHARS | LEXFL_NOSTRINGCONCAT ); - idToken token; - int i, j; - int num; - - if ( !parser.LoadFile( filename ) ) { - return false; - } - - Free(); - - name = filename; - - parser.ExpectTokenString( MD5_VERSION_STRING ); - version = parser.ParseInt(); - if ( version != MD5_VERSION ) { - parser.Error( "Invalid version %d. Should be version %d\n", version, MD5_VERSION ); - } - - // skip the commandline - parser.ExpectTokenString( "commandline" ); - parser.ReadToken( &token ); - - // parse num frames - parser.ExpectTokenString( "numFrames" ); - numFrames = parser.ParseInt(); - if ( numFrames <= 0 ) { - parser.Error( "Invalid number of frames: %d", numFrames ); - } - - // parse num joints - parser.ExpectTokenString( "numJoints" ); - numJoints = parser.ParseInt(); - if ( numJoints <= 0 ) { - parser.Error( "Invalid number of joints: %d", numJoints ); - } - - // parse frame rate - parser.ExpectTokenString( "frameRate" ); - frameRate = parser.ParseInt(); - if ( frameRate < 0 ) { - parser.Error( "Invalid frame rate: %d", frameRate ); - } - - // parse number of animated components - parser.ExpectTokenString( "numAnimatedComponents" ); - numAnimatedComponents = parser.ParseInt(); - if ( ( numAnimatedComponents < 0 ) || ( numAnimatedComponents > numJoints * 6 ) ) { - parser.Error( "Invalid number of animated components: %d", numAnimatedComponents ); - } - - // parse the hierarchy - jointInfo.SetGranularity( 1 ); - jointInfo.SetNum( numJoints ); - parser.ExpectTokenString( "hierarchy" ); - parser.ExpectTokenString( "{" ); - for( i = 0; i < numJoints; i++ ) { - parser.ReadToken( &token ); - jointInfo[ i ].nameIndex = animationLib.JointIndex( token ); - - // parse parent num - jointInfo[ i ].parentNum = parser.ParseInt(); - if ( jointInfo[ i ].parentNum >= i ) { - parser.Error( "Invalid parent num: %d", jointInfo[ i ].parentNum ); - } - - if ( ( i != 0 ) && ( jointInfo[ i ].parentNum < 0 ) ) { - parser.Error( "Animations may have only one root joint" ); - } - - // parse anim bits - jointInfo[ i ].animBits = parser.ParseInt(); - if ( jointInfo[ i ].animBits & ~63 ) { - parser.Error( "Invalid anim bits: %d", jointInfo[ i ].animBits ); - } - - // parse first component - jointInfo[ i ].firstComponent = parser.ParseInt(); - if ( ( numAnimatedComponents > 0 ) && ( ( jointInfo[ i ].firstComponent < 0 ) || ( jointInfo[ i ].firstComponent >= numAnimatedComponents ) ) ) { - parser.Error( "Invalid first component: %d", jointInfo[ i ].firstComponent ); - } - } - - parser.ExpectTokenString( "}" ); - - // parse bounds - parser.ExpectTokenString( "bounds" ); - parser.ExpectTokenString( "{" ); - bounds.SetGranularity( 1 ); - bounds.SetNum( numFrames ); - for( i = 0; i < numFrames; i++ ) { - parser.Parse1DMatrix( 3, bounds[ i ][ 0 ].ToFloatPtr() ); - parser.Parse1DMatrix( 3, bounds[ i ][ 1 ].ToFloatPtr() ); - } - parser.ExpectTokenString( "}" ); - - // parse base frame - baseFrame.SetGranularity( 1 ); - baseFrame.SetNum( numJoints ); - parser.ExpectTokenString( "baseframe" ); - parser.ExpectTokenString( "{" ); - for( i = 0; i < numJoints; i++ ) { - idCQuat q; - parser.Parse1DMatrix( 3, baseFrame[ i ].t.ToFloatPtr() ); - parser.Parse1DMatrix( 3, q.ToFloatPtr() );//baseFrame[ i ].q.ToFloatPtr() ); - baseFrame[ i ].q = q.ToQuat();//.w = baseFrame[ i ].q.CalcW(); - } - parser.ExpectTokenString( "}" ); - - // parse frames - componentFrames.SetGranularity( 1 ); - componentFrames.SetNum( numAnimatedComponents * numFrames ); - - float *componentPtr = componentFrames.Ptr(); - for( i = 0; i < numFrames; i++ ) { - parser.ExpectTokenString( "frame" ); - num = parser.ParseInt(); - if ( num != i ) { - parser.Error( "Expected frame number %d", i ); - } - parser.ExpectTokenString( "{" ); - - for( j = 0; j < numAnimatedComponents; j++, componentPtr++ ) { - *componentPtr = parser.ParseFloat(); - } - - parser.ExpectTokenString( "}" ); - } - - // get total move delta - if ( !numAnimatedComponents ) { - totaldelta.Zero(); - } else { - componentPtr = &componentFrames[ jointInfo[ 0 ].firstComponent ]; - if ( jointInfo[ 0 ].animBits & ANIM_TX ) { - for( i = 0; i < numFrames; i++ ) { - componentPtr[ numAnimatedComponents * i ] -= baseFrame[ 0 ].t.x; - } - totaldelta.x = componentPtr[ numAnimatedComponents * ( numFrames - 1 ) ]; - componentPtr++; - } else { - totaldelta.x = 0.0f; - } - if ( jointInfo[ 0 ].animBits & ANIM_TY ) { - for( i = 0; i < numFrames; i++ ) { - componentPtr[ numAnimatedComponents * i ] -= baseFrame[ 0 ].t.y; - } - totaldelta.y = componentPtr[ numAnimatedComponents * ( numFrames - 1 ) ]; - componentPtr++; - } else { - totaldelta.y = 0.0f; - } - if ( jointInfo[ 0 ].animBits & ANIM_TZ ) { - for( i = 0; i < numFrames; i++ ) { - componentPtr[ numAnimatedComponents * i ] -= baseFrame[ 0 ].t.z; - } - totaldelta.z = componentPtr[ numAnimatedComponents * ( numFrames - 1 ) ]; - } else { - totaldelta.z = 0.0f; - } - } - baseFrame[ 0 ].t.Zero(); - - // we don't count last frame because it would cause a 1 frame pause at the end - animLength = ( ( numFrames - 1 ) * 1000 + frameRate - 1 ) / frameRate; - - // done - return true; -} - -/* -==================== -idMD5Anim::IncreaseRefs -==================== -*/ -void idMD5Anim::IncreaseRefs( void ) const { - ref_count++; -} - -/* -==================== -idMD5Anim::DecreaseRefs -==================== -*/ -void idMD5Anim::DecreaseRefs( void ) const { - ref_count--; -} - -/* -==================== -idMD5Anim::NumRefs -==================== -*/ -int idMD5Anim::NumRefs( void ) const { - return ref_count; -} - -/* -==================== -idMD5Anim::GetFrameBlend -==================== -*/ -void idMD5Anim::GetFrameBlend( int framenum, frameBlend_t &frame ) const { - frame.cycleCount = 0; - frame.backlerp = 0.0f; - frame.frontlerp = 1.0f; - - // frame 1 is first frame - framenum--; - if ( framenum < 0 ) { - framenum = 0; - } else if ( framenum >= numFrames ) { - framenum = numFrames - 1; - } - - frame.frame1 = framenum; - frame.frame2 = framenum; -} - -/* -==================== -idMD5Anim::ConvertTimeToFrame -==================== -*/ -void idMD5Anim::ConvertTimeToFrame( int time, int cyclecount, frameBlend_t &frame ) const { - int frameTime; - int frameNum; - - if ( numFrames <= 1 ) { - frame.frame1 = 0; - frame.frame2 = 0; - frame.backlerp = 0.0f; - frame.frontlerp = 1.0f; - frame.cycleCount = 0; - return; - } - - if ( time <= 0 ) { - frame.frame1 = 0; - frame.frame2 = 1; - frame.backlerp = 0.0f; - frame.frontlerp = 1.0f; - frame.cycleCount = 0; - return; - } - - frameTime = time * frameRate; - frameNum = frameTime / 1000; - frame.cycleCount = frameNum / ( numFrames - 1 ); - - if ( ( cyclecount > 0 ) && ( frame.cycleCount >= cyclecount ) ) { - frame.cycleCount = cyclecount - 1; - frame.frame1 = numFrames - 1; - frame.frame2 = frame.frame1; - frame.backlerp = 0.0f; - frame.frontlerp = 1.0f; - return; - } - - frame.frame1 = frameNum % ( numFrames - 1 ); - frame.frame2 = frame.frame1 + 1; - if ( frame.frame2 >= numFrames ) { - frame.frame2 = 0; - } - - frame.backlerp = ( frameTime % 1000 ) * 0.001f; - frame.frontlerp = 1.0f - frame.backlerp; -} - -/* -==================== -idMD5Anim::GetOrigin -==================== -*/ -void idMD5Anim::GetOrigin( idVec3 &offset, int time, int cyclecount ) const { - frameBlend_t frame; - - offset = baseFrame[ 0 ].t; - if ( !( jointInfo[ 0 ].animBits & ( ANIM_TX | ANIM_TY | ANIM_TZ ) ) ) { - // just use the baseframe - return; - } - - ConvertTimeToFrame( time, cyclecount, frame ); - - const float *componentPtr1 = &componentFrames[ numAnimatedComponents * frame.frame1 + jointInfo[ 0 ].firstComponent ]; - const float *componentPtr2 = &componentFrames[ numAnimatedComponents * frame.frame2 + jointInfo[ 0 ].firstComponent ]; - - if ( jointInfo[ 0 ].animBits & ANIM_TX ) { - offset.x = *componentPtr1 * frame.frontlerp + *componentPtr2 * frame.backlerp; - componentPtr1++; - componentPtr2++; - } - - if ( jointInfo[ 0 ].animBits & ANIM_TY ) { - offset.y = *componentPtr1 * frame.frontlerp + *componentPtr2 * frame.backlerp; - componentPtr1++; - componentPtr2++; - } - - if ( jointInfo[ 0 ].animBits & ANIM_TZ ) { - offset.z = *componentPtr1 * frame.frontlerp + *componentPtr2 * frame.backlerp; - } - - if ( frame.cycleCount ) { - offset += totaldelta * ( float )frame.cycleCount; - } -} - -/* -==================== -idMD5Anim::GetOriginRotation -==================== -*/ -void idMD5Anim::GetOriginRotation( idQuat &rotation, int time, int cyclecount ) const { - frameBlend_t frame; - int animBits; - - animBits = jointInfo[ 0 ].animBits; - if ( !( animBits & ( ANIM_QX | ANIM_QY | ANIM_QZ ) ) ) { - // just use the baseframe - rotation = baseFrame[ 0 ].q; - return; - } - - ConvertTimeToFrame( time, cyclecount, frame ); - - const float *jointframe1 = &componentFrames[ numAnimatedComponents * frame.frame1 + jointInfo[ 0 ].firstComponent ]; - const float *jointframe2 = &componentFrames[ numAnimatedComponents * frame.frame2 + jointInfo[ 0 ].firstComponent ]; - - if ( animBits & ANIM_TX ) { - jointframe1++; - jointframe2++; - } - - if ( animBits & ANIM_TY ) { - jointframe1++; - jointframe2++; - } - - if ( animBits & ANIM_TZ ) { - jointframe1++; - jointframe2++; - } - - idQuat q1; - idQuat q2; - - switch( animBits & (ANIM_QX|ANIM_QY|ANIM_QZ) ) { - case ANIM_QX: - q1.x = jointframe1[0]; - q2.x = jointframe2[0]; - q1.y = baseFrame[ 0 ].q.y; - q2.y = q1.y; - q1.z = baseFrame[ 0 ].q.z; - q2.z = q1.z; - q1.w = q1.CalcW(); - q2.w = q2.CalcW(); - break; - case ANIM_QY: - q1.y = jointframe1[0]; - q2.y = jointframe2[0]; - q1.x = baseFrame[ 0 ].q.x; - q2.x = q1.x; - q1.z = baseFrame[ 0 ].q.z; - q2.z = q1.z; - q1.w = q1.CalcW(); - q2.w = q2.CalcW(); - break; - case ANIM_QZ: - q1.z = jointframe1[0]; - q2.z = jointframe2[0]; - q1.x = baseFrame[ 0 ].q.x; - q2.x = q1.x; - q1.y = baseFrame[ 0 ].q.y; - q2.y = q1.y; - q1.w = q1.CalcW(); - q2.w = q2.CalcW(); - break; - case ANIM_QX|ANIM_QY: - q1.x = jointframe1[0]; - q1.y = jointframe1[1]; - q2.x = jointframe2[0]; - q2.y = jointframe2[1]; - q1.z = baseFrame[ 0 ].q.z; - q2.z = q1.z; - q1.w = q1.CalcW(); - q2.w = q2.CalcW(); - break; - case ANIM_QX|ANIM_QZ: - q1.x = jointframe1[0]; - q1.z = jointframe1[1]; - q2.x = jointframe2[0]; - q2.z = jointframe2[1]; - q1.y = baseFrame[ 0 ].q.y; - q2.y = q1.y; - q1.w = q1.CalcW(); - q2.w = q2.CalcW(); - break; - case ANIM_QY|ANIM_QZ: - q1.y = jointframe1[0]; - q1.z = jointframe1[1]; - q2.y = jointframe2[0]; - q2.z = jointframe2[1]; - q1.x = baseFrame[ 0 ].q.x; - q2.x = q1.x; - q1.w = q1.CalcW(); - q2.w = q2.CalcW(); - break; - case ANIM_QX|ANIM_QY|ANIM_QZ: - q1.x = jointframe1[0]; - q1.y = jointframe1[1]; - q1.z = jointframe1[2]; - q2.x = jointframe2[0]; - q2.y = jointframe2[1]; - q2.z = jointframe2[2]; - q1.w = q1.CalcW(); - q2.w = q2.CalcW(); - break; - } - - rotation.Slerp( q1, q2, frame.backlerp ); -} - -/* -==================== -idMD5Anim::GetBounds -==================== -*/ -void idMD5Anim::GetBounds( idBounds &bnds, int time, int cyclecount ) const { - frameBlend_t frame; - idVec3 offset; - - ConvertTimeToFrame( time, cyclecount, frame ); - - bnds = bounds[ frame.frame1 ]; - bnds.AddBounds( bounds[ frame.frame2 ] ); - - // origin position - offset = baseFrame[ 0 ].t; - if ( jointInfo[ 0 ].animBits & ( ANIM_TX | ANIM_TY | ANIM_TZ ) ) { - const float *componentPtr1 = &componentFrames[ numAnimatedComponents * frame.frame1 + jointInfo[ 0 ].firstComponent ]; - const float *componentPtr2 = &componentFrames[ numAnimatedComponents * frame.frame2 + jointInfo[ 0 ].firstComponent ]; - - if ( jointInfo[ 0 ].animBits & ANIM_TX ) { - offset.x = *componentPtr1 * frame.frontlerp + *componentPtr2 * frame.backlerp; - componentPtr1++; - componentPtr2++; - } - - if ( jointInfo[ 0 ].animBits & ANIM_TY ) { - offset.y = *componentPtr1 * frame.frontlerp + *componentPtr2 * frame.backlerp; - componentPtr1++; - componentPtr2++; - } - - if ( jointInfo[ 0 ].animBits & ANIM_TZ ) { - offset.z = *componentPtr1 * frame.frontlerp + *componentPtr2 * frame.backlerp; - } - } - - bnds[ 0 ] -= offset; - bnds[ 1 ] -= offset; -} - -/* -==================== -idMD5Anim::GetInterpolatedFrame -==================== -*/ -void idMD5Anim::GetInterpolatedFrame( frameBlend_t &frame, idJointQuat *joints, const int *index, int numIndexes ) const { - int i, numLerpJoints; - const float *frame1; - const float *frame2; - const float *jointframe1; - const float *jointframe2; - const jointAnimInfo_t *infoPtr; - int animBits; - idJointQuat *blendJoints; - idJointQuat *jointPtr; - idJointQuat *blendPtr; - int *lerpIndex; - - // copy the baseframe - SIMDProcessor->Memcpy( joints, baseFrame.Ptr(), baseFrame.Num() * sizeof( baseFrame[ 0 ] ) ); - - if ( !numAnimatedComponents ) { - // just use the base frame - return; - } - - blendJoints = (idJointQuat *)_alloca16( baseFrame.Num() * sizeof( blendPtr[ 0 ] ) ); - lerpIndex = (int *)_alloca16( baseFrame.Num() * sizeof( lerpIndex[ 0 ] ) ); - numLerpJoints = 0; - - frame1 = &componentFrames[ frame.frame1 * numAnimatedComponents ]; - frame2 = &componentFrames[ frame.frame2 * numAnimatedComponents ]; - - for ( i = 0; i < numIndexes; i++ ) { - int j = index[i]; - jointPtr = &joints[j]; - blendPtr = &blendJoints[j]; - infoPtr = &jointInfo[j]; - - animBits = infoPtr->animBits; - if ( animBits ) { - - lerpIndex[numLerpJoints++] = j; - - jointframe1 = frame1 + infoPtr->firstComponent; - jointframe2 = frame2 + infoPtr->firstComponent; - - switch( animBits & (ANIM_TX|ANIM_TY|ANIM_TZ) ) { - case 0: - blendPtr->t = jointPtr->t; - break; - case ANIM_TX: - jointPtr->t.x = jointframe1[0]; - blendPtr->t.x = jointframe2[0]; - blendPtr->t.y = jointPtr->t.y; - blendPtr->t.z = jointPtr->t.z; - jointframe1++; - jointframe2++; - break; - case ANIM_TY: - jointPtr->t.y = jointframe1[0]; - blendPtr->t.y = jointframe2[0]; - blendPtr->t.x = jointPtr->t.x; - blendPtr->t.z = jointPtr->t.z; - jointframe1++; - jointframe2++; - break; - case ANIM_TZ: - jointPtr->t.z = jointframe1[0]; - blendPtr->t.z = jointframe2[0]; - blendPtr->t.x = jointPtr->t.x; - blendPtr->t.y = jointPtr->t.y; - jointframe1++; - jointframe2++; - break; - case ANIM_TX|ANIM_TY: - jointPtr->t.x = jointframe1[0]; - jointPtr->t.y = jointframe1[1]; - blendPtr->t.x = jointframe2[0]; - blendPtr->t.y = jointframe2[1]; - blendPtr->t.z = jointPtr->t.z; - jointframe1 += 2; - jointframe2 += 2; - break; - case ANIM_TX|ANIM_TZ: - jointPtr->t.x = jointframe1[0]; - jointPtr->t.z = jointframe1[1]; - blendPtr->t.x = jointframe2[0]; - blendPtr->t.z = jointframe2[1]; - blendPtr->t.y = jointPtr->t.y; - jointframe1 += 2; - jointframe2 += 2; - break; - case ANIM_TY|ANIM_TZ: - jointPtr->t.y = jointframe1[0]; - jointPtr->t.z = jointframe1[1]; - blendPtr->t.y = jointframe2[0]; - blendPtr->t.z = jointframe2[1]; - blendPtr->t.x = jointPtr->t.x; - jointframe1 += 2; - jointframe2 += 2; - break; - case ANIM_TX|ANIM_TY|ANIM_TZ: - jointPtr->t.x = jointframe1[0]; - jointPtr->t.y = jointframe1[1]; - jointPtr->t.z = jointframe1[2]; - blendPtr->t.x = jointframe2[0]; - blendPtr->t.y = jointframe2[1]; - blendPtr->t.z = jointframe2[2]; - jointframe1 += 3; - jointframe2 += 3; - break; - } - - switch( animBits & (ANIM_QX|ANIM_QY|ANIM_QZ) ) { - case 0: - blendPtr->q = jointPtr->q; - break; - case ANIM_QX: - jointPtr->q.x = jointframe1[0]; - blendPtr->q.x = jointframe2[0]; - blendPtr->q.y = jointPtr->q.y; - blendPtr->q.z = jointPtr->q.z; - jointPtr->q.w = jointPtr->q.CalcW(); - blendPtr->q.w = blendPtr->q.CalcW(); - break; - case ANIM_QY: - jointPtr->q.y = jointframe1[0]; - blendPtr->q.y = jointframe2[0]; - blendPtr->q.x = jointPtr->q.x; - blendPtr->q.z = jointPtr->q.z; - jointPtr->q.w = jointPtr->q.CalcW(); - blendPtr->q.w = blendPtr->q.CalcW(); - break; - case ANIM_QZ: - jointPtr->q.z = jointframe1[0]; - blendPtr->q.z = jointframe2[0]; - blendPtr->q.x = jointPtr->q.x; - blendPtr->q.y = jointPtr->q.y; - jointPtr->q.w = jointPtr->q.CalcW(); - blendPtr->q.w = blendPtr->q.CalcW(); - break; - case ANIM_QX|ANIM_QY: - jointPtr->q.x = jointframe1[0]; - jointPtr->q.y = jointframe1[1]; - blendPtr->q.x = jointframe2[0]; - blendPtr->q.y = jointframe2[1]; - blendPtr->q.z = jointPtr->q.z; - jointPtr->q.w = jointPtr->q.CalcW(); - blendPtr->q.w = blendPtr->q.CalcW(); - break; - case ANIM_QX|ANIM_QZ: - jointPtr->q.x = jointframe1[0]; - jointPtr->q.z = jointframe1[1]; - blendPtr->q.x = jointframe2[0]; - blendPtr->q.z = jointframe2[1]; - blendPtr->q.y = jointPtr->q.y; - jointPtr->q.w = jointPtr->q.CalcW(); - blendPtr->q.w = blendPtr->q.CalcW(); - break; - case ANIM_QY|ANIM_QZ: - jointPtr->q.y = jointframe1[0]; - jointPtr->q.z = jointframe1[1]; - blendPtr->q.y = jointframe2[0]; - blendPtr->q.z = jointframe2[1]; - blendPtr->q.x = jointPtr->q.x; - jointPtr->q.w = jointPtr->q.CalcW(); - blendPtr->q.w = blendPtr->q.CalcW(); - break; - case ANIM_QX|ANIM_QY|ANIM_QZ: - jointPtr->q.x = jointframe1[0]; - jointPtr->q.y = jointframe1[1]; - jointPtr->q.z = jointframe1[2]; - blendPtr->q.x = jointframe2[0]; - blendPtr->q.y = jointframe2[1]; - blendPtr->q.z = jointframe2[2]; - jointPtr->q.w = jointPtr->q.CalcW(); - blendPtr->q.w = blendPtr->q.CalcW(); - break; - } - } - } - - SIMDProcessor->BlendJoints( joints, blendJoints, frame.backlerp, lerpIndex, numLerpJoints ); - - if ( frame.cycleCount ) { - joints[ 0 ].t += totaldelta * ( float )frame.cycleCount; - } -} - -/* -==================== -idMD5Anim::GetSingleFrame -==================== -*/ -void idMD5Anim::GetSingleFrame( int framenum, idJointQuat *joints, const int *index, int numIndexes ) const { - int i; - const float *frame; - const float *jointframe; - int animBits; - idJointQuat *jointPtr; - const jointAnimInfo_t *infoPtr; - - // copy the baseframe - SIMDProcessor->Memcpy( joints, baseFrame.Ptr(), baseFrame.Num() * sizeof( baseFrame[ 0 ] ) ); - - if ( ( framenum == 0 ) || !numAnimatedComponents ) { - // just use the base frame - return; - } - - frame = &componentFrames[ framenum * numAnimatedComponents ]; - - for ( i = 0; i < numIndexes; i++ ) { - int j = index[i]; - jointPtr = &joints[j]; - infoPtr = &jointInfo[j]; - - animBits = infoPtr->animBits; - if ( animBits ) { - - jointframe = frame + infoPtr->firstComponent; - - if ( animBits & (ANIM_TX|ANIM_TY|ANIM_TZ) ) { - - if ( animBits & ANIM_TX ) { - jointPtr->t.x = *jointframe++; - } - - if ( animBits & ANIM_TY ) { - jointPtr->t.y = *jointframe++; - } - - if ( animBits & ANIM_TZ ) { - jointPtr->t.z = *jointframe++; - } - } - - if ( animBits & (ANIM_QX|ANIM_QY|ANIM_QZ) ) { - - if ( animBits & ANIM_QX ) { - jointPtr->q.x = *jointframe++; - } - - if ( animBits & ANIM_QY ) { - jointPtr->q.y = *jointframe++; - } - - if ( animBits & ANIM_QZ ) { - jointPtr->q.z = *jointframe; - } - - jointPtr->q.w = jointPtr->q.CalcW(); - } - } - } -} - -/* -==================== -idMD5Anim::CheckModelHierarchy -==================== -*/ -void idMD5Anim::CheckModelHierarchy( const idRenderModel *model ) const { - int i; - int jointNum; - int parent; - - if ( jointInfo.Num() != model->NumJoints() ) { - gameLocal.Error( "Model '%s' has different # of joints than anim '%s'", model->Name(), name.c_str() ); - } - - const idMD5Joint *modelJoints = model->GetJoints(); - for( i = 0; i < jointInfo.Num(); i++ ) { - jointNum = jointInfo[ i ].nameIndex; - if ( modelJoints[ i ].name != animationLib.JointName( jointNum ) ) { - gameLocal.Error( "Model '%s''s joint names don't match anim '%s''s", model->Name(), name.c_str() ); - } - if ( modelJoints[ i ].parent ) { - parent = modelJoints[ i ].parent - modelJoints; - } else { - parent = -1; - } - if ( parent != jointInfo[ i ].parentNum ) { - gameLocal.Error( "Model '%s' has different joint hierarchy than anim '%s'", model->Name(), name.c_str() ); - } - } -} - -/*********************************************************************** - - idAnimManager - -***********************************************************************/ - -/* -==================== -idAnimManager::idAnimManager -==================== -*/ -idAnimManager::idAnimManager() { -} - -/* -==================== -idAnimManager::~idAnimManager -==================== -*/ -idAnimManager::~idAnimManager() { - Shutdown(); -} - -/* -==================== -idAnimManager::Shutdown -==================== -*/ -void idAnimManager::Shutdown( void ) { - animations.DeleteContents(); - jointnames.Clear(); - jointnamesHash.Free(); -} - -/* -==================== -idAnimManager::GetAnim -==================== -*/ -idMD5Anim *idAnimManager::GetAnim( const char *name ) { - idMD5Anim **animptrptr; - idMD5Anim *anim; - - // see if it has been asked for before - animptrptr = NULL; - if ( animations.Get( name, &animptrptr ) ) { - anim = *animptrptr; - } else { - idStr extension; - idStr filename = name; - - filename.ExtractFileExtension( extension ); - if ( extension != MD5_ANIM_EXT ) { - return NULL; - } - - anim = new idMD5Anim(); - if ( !anim->LoadAnim( filename ) ) { - gameLocal.Warning( "Couldn't load anim: '%s'", filename.c_str() ); - delete anim; - anim = NULL; - } - animations.Set( filename, anim ); - } - - return anim; -} - -/* -================ -idAnimManager::ReloadAnims -================ -*/ -void idAnimManager::ReloadAnims( void ) { - int i; - idMD5Anim **animptr; - - for( i = 0; i < animations.Num(); i++ ) { - animptr = animations.GetIndex( i ); - if ( animptr && *animptr ) { - ( *animptr )->Reload(); - } - } -} - -/* -================ -idAnimManager::JointIndex -================ -*/ -int idAnimManager::JointIndex( const char *name ) { - int i, hash; - - hash = jointnamesHash.GenerateKey( name ); - for ( i = jointnamesHash.First( hash ); i != -1; i = jointnamesHash.Next( i ) ) { - if ( jointnames[i].Cmp( name ) == 0 ) { - return i; - } - } - - i = jointnames.Append( name ); - jointnamesHash.Add( hash, i ); - return i; -} - -/* -================ -idAnimManager::JointName -================ -*/ -const char *idAnimManager::JointName( int index ) const { - return jointnames[ index ]; -} - -/* -================ -idAnimManager::ListAnims -================ -*/ -void idAnimManager::ListAnims( void ) const { - int i; - idMD5Anim **animptr; - idMD5Anim *anim; - size_t size; - size_t s; - size_t namesize; - int num; - - num = 0; - size = 0; - for( i = 0; i < animations.Num(); i++ ) { - animptr = animations.GetIndex( i ); - if ( animptr && *animptr ) { - anim = *animptr; - s = anim->Size(); - gameLocal.Printf( "%8zd bytes : %2d refs : %s\n", s, anim->NumRefs(), anim->Name() ); - size += s; - num++; - } - } - - namesize = jointnames.Size() + jointnamesHash.Size(); - for( i = 0; i < jointnames.Num(); i++ ) { - namesize += jointnames[ i ].Size(); - } - - gameLocal.Printf( "\n%zd memory used in %d anims\n", size, num ); - gameLocal.Printf( "%zd memory used in %d joint names\n", namesize, jointnames.Num() ); -} - -/* -================ -idAnimManager::FlushUnusedAnims -================ -*/ -void idAnimManager::FlushUnusedAnims( void ) { - int i; - idMD5Anim **animptr; - idList removeAnims; - - for( i = 0; i < animations.Num(); i++ ) { - animptr = animations.GetIndex( i ); - if ( animptr && *animptr ) { - if ( ( *animptr )->NumRefs() <= 0 ) { - removeAnims.Append( *animptr ); - } - } - } - - for( i = 0; i < removeAnims.Num(); i++ ) { - animations.Remove( removeAnims[ i ]->Name() ); - delete removeAnims[ i ]; - } -} diff --git a/d3xp/anim/Anim.h b/d3xp/anim/Anim.h deleted file mode 100644 index b37b2096..00000000 --- a/d3xp/anim/Anim.h +++ /dev/null @@ -1,634 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ -#ifndef __ANIM_H__ -#define __ANIM_H__ - -#include "idlib/containers/StrList.h" -#include "idlib/containers/HashTable.h" -#include "idlib/Dict.h" -#include "renderer/Model.h" - -#include "physics/Clip.h" - -// -// animation channels -// these can be changed by modmakers and licensees to be whatever they need. -const int ANIM_NumAnimChannels = 5; -const int ANIM_MaxAnimsPerChannel = 3; -const int ANIM_MaxSyncedAnims = 3; - -// -// animation channels. make sure to change script/doom_defs.script if you add any channels, or change their order -// -const int ANIMCHANNEL_ALL = 0; -const int ANIMCHANNEL_TORSO = 1; -const int ANIMCHANNEL_LEGS = 2; -const int ANIMCHANNEL_HEAD = 3; -const int ANIMCHANNEL_EYELIDS = 4; - -// for converting from 24 frames per second to milliseconds -ID_INLINE int FRAME2MS( int framenum ) { - return ( framenum * 1000 ) / 24; -} - -class idRenderModel; -class idAnimator; -class idAnimBlend; -class function_t; -class idEntity; -class idSaveGame; -class idRestoreGame; - -typedef struct { - int cycleCount; // how many times the anim has wrapped to the begining (0 for clamped anims) - int frame1; - int frame2; - float frontlerp; - float backlerp; -} frameBlend_t; - -typedef struct { - int nameIndex; - int parentNum; - int animBits; - int firstComponent; -} jointAnimInfo_t; - -typedef struct { - jointHandle_t num; - jointHandle_t parentNum; - int channel; -} jointInfo_t; - -// -// joint modifier modes. make sure to change script/doom_defs.script if you add any, or change their order. -// -typedef enum { - JOINTMOD_NONE, // no modification - JOINTMOD_LOCAL, // modifies the joint's position or orientation in joint local space - JOINTMOD_LOCAL_OVERRIDE, // sets the joint's position or orientation in joint local space - JOINTMOD_WORLD, // modifies joint's position or orientation in model space - JOINTMOD_WORLD_OVERRIDE // sets the joint's position or orientation in model space -} jointModTransform_t; - -typedef struct { - jointHandle_t jointnum; - idMat3 mat; - idVec3 pos; - jointModTransform_t transform_pos; - jointModTransform_t transform_axis; -} jointMod_t; - -#define ANIM_TX BIT( 0 ) -#define ANIM_TY BIT( 1 ) -#define ANIM_TZ BIT( 2 ) -#define ANIM_QX BIT( 3 ) -#define ANIM_QY BIT( 4 ) -#define ANIM_QZ BIT( 5 ) - -typedef enum { - FC_SCRIPTFUNCTION, - FC_SCRIPTFUNCTIONOBJECT, - FC_EVENTFUNCTION, - FC_SOUND, - FC_SOUND_VOICE, - FC_SOUND_VOICE2, - FC_SOUND_BODY, - FC_SOUND_BODY2, - FC_SOUND_BODY3, - FC_SOUND_WEAPON, - FC_SOUND_ITEM, - FC_SOUND_GLOBAL, - FC_SOUND_CHATTER, - FC_SKIN, - FC_TRIGGER, - FC_TRIGGER_SMOKE_PARTICLE, - FC_MELEE, - FC_DIRECTDAMAGE, - FC_BEGINATTACK, - FC_ENDATTACK, - FC_MUZZLEFLASH, - FC_CREATEMISSILE, - FC_LAUNCHMISSILE, - FC_FIREMISSILEATTARGET, - FC_FOOTSTEP, - FC_LEFTFOOT, - FC_RIGHTFOOT, - FC_ENABLE_EYE_FOCUS, - FC_DISABLE_EYE_FOCUS, - FC_FX, - FC_DISABLE_GRAVITY, - FC_ENABLE_GRAVITY, - FC_JUMP, - FC_ENABLE_CLIP, - FC_DISABLE_CLIP, - FC_ENABLE_WALK_IK, - FC_DISABLE_WALK_IK, - FC_ENABLE_LEG_IK, - FC_DISABLE_LEG_IK, - FC_RECORDDEMO, - FC_AVIGAME -#ifdef _D3XP - , FC_LAUNCH_PROJECTILE, - FC_TRIGGER_FX, - FC_START_EMITTER, - FC_STOP_EMITTER, -#endif -} frameCommandType_t; - -typedef struct { - int num; - int firstCommand; -} frameLookup_t; - -typedef struct { - frameCommandType_t type; - idStr *string; - - union { - const idSoundShader *soundShader; - const function_t *function; - const idDeclSkin *skin; - int index; - }; -} frameCommand_t; - -typedef struct { - bool prevent_idle_override : 1; - bool random_cycle_start : 1; - bool ai_no_turn : 1; - bool anim_turn : 1; -} animFlags_t; - - -/* -============================================================================================== - - idModelExport - -============================================================================================== -*/ - -class idModelExport { -private: - void Reset( void ); - bool ParseOptions( idLexer &lex ); - int ParseExportSection( idParser &parser ); - - static bool CheckMayaInstall( void ); - static void LoadMayaDll( void ); - - bool ConvertMayaToMD5( void ); - static bool initialized; - -public: - idStr commandLine; - idStr src; - idStr dest; - bool force; - - idModelExport(); - - static void Shutdown( void ); - - int ExportDefFile( const char *filename ); - bool ExportModel( const char *model ); - bool ExportAnim( const char *anim ); - int ExportModels( const char *pathname, const char *extension ); -}; - -/* -============================================================================================== - - idMD5Anim - -============================================================================================== -*/ - -class idMD5Anim { -private: - int numFrames; - int frameRate; - int animLength; - int numJoints; - int numAnimatedComponents; - idList bounds; - idList jointInfo; - idList baseFrame; - idList componentFrames; - idStr name; - idVec3 totaldelta; - mutable int ref_count; - -public: - idMD5Anim(); - ~idMD5Anim(); - - void Free( void ); - bool Reload( void ); - size_t Allocated( void ) const; - size_t Size( void ) const { return sizeof( *this ) + Allocated(); }; - bool LoadAnim( const char *filename ); - - void IncreaseRefs( void ) const; - void DecreaseRefs( void ) const; - int NumRefs( void ) const; - - void CheckModelHierarchy( const idRenderModel *model ) const; - void GetInterpolatedFrame( frameBlend_t &frame, idJointQuat *joints, const int *index, int numIndexes ) const; - void GetSingleFrame( int framenum, idJointQuat *joints, const int *index, int numIndexes ) const; - int Length( void ) const; - int NumFrames( void ) const; - int NumJoints( void ) const; - const idVec3 &TotalMovementDelta( void ) const; - const char *Name( void ) const; - - void GetFrameBlend( int framenum, frameBlend_t &frame ) const; // frame 1 is first frame - void ConvertTimeToFrame( int time, int cyclecount, frameBlend_t &frame ) const; - - void GetOrigin( idVec3 &offset, int currentTime, int cyclecount ) const; - void GetOriginRotation( idQuat &rotation, int time, int cyclecount ) const; - void GetBounds( idBounds &bounds, int currentTime, int cyclecount ) const; -}; - -/* -============================================================================================== - - idAnim - -============================================================================================== -*/ - -class idAnim { -private: - const class idDeclModelDef *modelDef; - const idMD5Anim *anims[ ANIM_MaxSyncedAnims ]; - int numAnims; - idStr name; - idStr realname; - idList frameLookup; - idList frameCommands; - animFlags_t flags; - -public: - idAnim(); - idAnim( const idDeclModelDef *modelDef, const idAnim *anim ); - ~idAnim(); - - void SetAnim( const idDeclModelDef *modelDef, const char *sourcename, const char *animname, int num, const idMD5Anim *md5anims[ ANIM_MaxSyncedAnims ] ); - const char *Name( void ) const; - const char *FullName( void ) const; - const idMD5Anim *MD5Anim( int num ) const; - const idDeclModelDef *ModelDef( void ) const; - int Length( void ) const; - int NumFrames( void ) const; - int NumAnims( void ) const; - const idVec3 &TotalMovementDelta( void ) const; - bool GetOrigin( idVec3 &offset, int animNum, int time, int cyclecount ) const; - bool GetOriginRotation( idQuat &rotation, int animNum, int currentTime, int cyclecount ) const; - bool GetBounds( idBounds &bounds, int animNum, int time, int cyclecount ) const; - const char *AddFrameCommand( const class idDeclModelDef *modelDef, int framenum, idLexer &src, const idDict *def ); - void CallFrameCommands( idEntity *ent, int from, int to ) const; - bool HasFrameCommands( void ) const; - - // returns first frame (zero based) that command occurs. returns -1 if not found. - int FindFrameForFrameCommand( frameCommandType_t framecommand, const frameCommand_t **command ) const; - void SetAnimFlags( const animFlags_t &animflags ); - const animFlags_t &GetAnimFlags( void ) const; -}; - -/* -============================================================================================== - - idDeclModelDef - -============================================================================================== -*/ - -class idDeclModelDef : public idDecl { -public: - idDeclModelDef(); - ~idDeclModelDef(); - - virtual size_t Size( void ) const; - virtual const char * DefaultDefinition( void ) const; - virtual bool Parse( const char *text, const int textLength ); - virtual void FreeData( void ); - - void Touch( void ) const; - - const idDeclSkin * GetDefaultSkin( void ) const; - const idJointQuat * GetDefaultPose( void ) const; - void SetupJoints( int *numJoints, idJointMat **jointList, idBounds &frameBounds, bool removeOriginOffset ) const; - idRenderModel * ModelHandle( void ) const; - void GetJointList( const char *jointnames, idList &jointList ) const; - const jointInfo_t * FindJoint( const char *name ) const; - - int NumAnims( void ) const; - const idAnim * GetAnim( int index ) const; - int GetSpecificAnim( const char *name ) const; - int GetAnim( const char *name ) const; - bool HasAnim( const char *name ) const; - const idDeclSkin * GetSkin( void ) const; - const char * GetModelName( void ) const; - const idList & Joints( void ) const; - const int * JointParents( void ) const; - int NumJoints( void ) const; - const jointInfo_t * GetJoint( int jointHandle ) const; - const char * GetJointName( int jointHandle ) const; - int NumJointsOnChannel( int channel ) const; - const int * GetChannelJoints( int channel ) const; - - const idVec3 & GetVisualOffset( void ) const; - -private: - void CopyDecl( const idDeclModelDef *decl ); - bool ParseAnim( idLexer &src, int numDefaultAnims ); - -private: - idVec3 offset; - idList joints; - idList jointParents; - idList channelJoints[ ANIM_NumAnimChannels ]; - idRenderModel * modelHandle; - idList anims; - const idDeclSkin * skin; -}; - -/* -============================================================================================== - - idAnimBlend - -============================================================================================== -*/ - -class idAnimBlend { -private: - const class idDeclModelDef *modelDef; - int starttime; - int endtime; - int timeOffset; - float rate; - - int blendStartTime; - int blendDuration; - float blendStartValue; - float blendEndValue; - - float animWeights[ ANIM_MaxSyncedAnims ]; - short cycle; - short frame; - short animNum; - bool allowMove; - bool allowFrameCommands; - - friend class idAnimator; - - void Reset( const idDeclModelDef *_modelDef ); - void CallFrameCommands( idEntity *ent, int fromtime, int totime ) const; - void SetFrame( const idDeclModelDef *modelDef, int animnum, int frame, int currenttime, int blendtime ); - void CycleAnim( const idDeclModelDef *modelDef, int animnum, int currenttime, int blendtime ); - void PlayAnim( const idDeclModelDef *modelDef, int animnum, int currenttime, int blendtime ); - bool BlendAnim( int currentTime, int channel, int numJoints, idJointQuat *blendFrame, float &blendWeight, bool removeOrigin, bool overrideBlend, bool printInfo ) const; - void BlendOrigin( int currentTime, idVec3 &blendPos, float &blendWeight, bool removeOriginOffset ) const; - void BlendDelta( int fromtime, int totime, idVec3 &blendDelta, float &blendWeight ) const; - void BlendDeltaRotation( int fromtime, int totime, idQuat &blendDelta, float &blendWeight ) const; - bool AddBounds( int currentTime, idBounds &bounds, bool removeOriginOffset ) const; - -public: - idAnimBlend(); - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile, const idDeclModelDef *modelDef ); - const char *AnimName( void ) const; - const char *AnimFullName( void ) const; - float GetWeight( int currenttime ) const; - float GetFinalWeight( void ) const; - void SetWeight( float newweight, int currenttime, int blendtime ); - int NumSyncedAnims( void ) const; - bool SetSyncedAnimWeight( int num, float weight ); - void Clear( int currentTime, int clearTime ); - bool IsDone( int currentTime ) const; - bool FrameHasChanged( int currentTime ) const; - int GetCycleCount( void ) const; - void SetCycleCount( int count ); - void SetPlaybackRate( int currentTime, float newRate ); - float GetPlaybackRate( void ) const; - void SetStartTime( int startTime ); - int GetStartTime( void ) const; - int GetEndTime( void ) const; - int GetFrameNumber( int currenttime ) const; - int AnimTime( int currenttime ) const; - int NumFrames( void ) const; - int Length( void ) const; - int PlayLength( void ) const; - void AllowMovement( bool allow ); - void AllowFrameCommands( bool allow ); - const idAnim *Anim( void ) const; - int AnimNum( void ) const; -}; - -/* -============================================================================================== - - idAFPoseJointMod - -============================================================================================== -*/ - -typedef enum { - AF_JOINTMOD_AXIS, - AF_JOINTMOD_ORIGIN, - AF_JOINTMOD_BOTH -} AFJointModType_t; - -class idAFPoseJointMod { -public: - idAFPoseJointMod( void ); - - AFJointModType_t mod; - idMat3 axis; - idVec3 origin; -}; - -ID_INLINE idAFPoseJointMod::idAFPoseJointMod( void ) { - mod = AF_JOINTMOD_AXIS; - axis.Identity(); - origin.Zero(); -} - -/* -============================================================================================== - - idAnimator - -============================================================================================== -*/ - -class idAnimator { -public: - idAnimator(); - ~idAnimator(); - - size_t Allocated( void ) const; - size_t Size( void ) const; - - void Save( idSaveGame *savefile ) const; // archives object for save game file - void Restore( idRestoreGame *savefile ); // unarchives object from save game file - - void SetEntity( idEntity *ent ); - idEntity *GetEntity( void ) const ; - void RemoveOriginOffset( bool remove ); - bool RemoveOrigin( void ) const; - - void GetJointList( const char *jointnames, idList &jointList ) const; - - int NumAnims( void ) const; - const idAnim *GetAnim( int index ) const; - int GetAnim( const char *name ) const; - bool HasAnim( const char *name ) const; - - void ServiceAnims( int fromtime, int totime ); - bool IsAnimating( int currentTime ) const; - - void GetJoints( int *numJoints, idJointMat **jointsPtr ); - int NumJoints( void ) const; - jointHandle_t GetFirstChild( jointHandle_t jointnum ) const; - jointHandle_t GetFirstChild( const char *name ) const; - - idRenderModel *SetModel( const char *modelname ); - idRenderModel *ModelHandle( void ) const; - const idDeclModelDef *ModelDef( void ) const; - - void ForceUpdate( void ); - void ClearForceUpdate( void ); - bool CreateFrame( int animtime, bool force ); - bool FrameHasChanged( int animtime ) const; - void GetDelta( int fromtime, int totime, idVec3 &delta ) const; - bool GetDeltaRotation( int fromtime, int totime, idMat3 &delta ) const; - void GetOrigin( int currentTime, idVec3 &pos ) const; - bool GetBounds( int currentTime, idBounds &bounds ); - - idAnimBlend *CurrentAnim( int channelNum ); - void Clear( int channelNum, int currentTime, int cleartime ); - void SetFrame( int channelNum, int animnum, int frame, int currenttime, int blendtime ); - void CycleAnim( int channelNum, int animnum, int currenttime, int blendtime ); - void PlayAnim( int channelNum, int animnum, int currenttime, int blendTime ); - - // copies the current anim from fromChannelNum to channelNum. - // the copied anim will have frame commands disabled to avoid executing them twice. - void SyncAnimChannels( int channelNum, int fromChannelNum, int currenttime, int blendTime ); - - void SetJointPos( jointHandle_t jointnum, jointModTransform_t transform_type, const idVec3 &pos ); - void SetJointAxis( jointHandle_t jointnum, jointModTransform_t transform_type, const idMat3 &mat ); - void ClearJoint( jointHandle_t jointnum ); - void ClearAllJoints( void ); - - void InitAFPose( void ); - void SetAFPoseJointMod( const jointHandle_t jointNum, const AFJointModType_t mod, const idMat3 &axis, const idVec3 &origin ); - void FinishAFPose( int animnum, const idBounds &bounds, const int time ); - void SetAFPoseBlendWeight( float blendWeight ); - bool BlendAFPose( idJointQuat *blendFrame ) const; - void ClearAFPose( void ); - - void ClearAllAnims( int currentTime, int cleartime ); - - jointHandle_t GetJointHandle( const char *name ) const; - const char * GetJointName( jointHandle_t handle ) const; - int GetChannelForJoint( jointHandle_t joint ) const; - bool GetJointTransform( jointHandle_t jointHandle, int currenttime, idVec3 &offset, idMat3 &axis ); - bool GetJointLocalTransform( jointHandle_t jointHandle, int currentTime, idVec3 &offset, idMat3 &axis ); - - const animFlags_t GetAnimFlags( int animnum ) const; - int NumFrames( int animnum ) const; - int NumSyncedAnims( int animnum ) const; - const char *AnimName( int animnum ) const; - const char *AnimFullName( int animnum ) const; - int AnimLength( int animnum ) const; - const idVec3 &TotalMovementDelta( int animnum ) const; - -private: - void FreeData( void ); - void PushAnims( int channel, int currentTime, int blendTime ); - -private: - const idDeclModelDef * modelDef; - idEntity * entity; - - idAnimBlend channels[ ANIM_NumAnimChannels ][ ANIM_MaxAnimsPerChannel ]; - idList jointMods; - int numJoints; - idJointMat * joints; - - mutable int lastTransformTime; // mutable because the value is updated in CreateFrame - mutable bool stoppedAnimatingUpdate; - bool removeOriginOffset; - bool forceUpdate; - - idBounds frameBounds; - - float AFPoseBlendWeight; - idList AFPoseJoints; - idList AFPoseJointMods; - idList AFPoseJointFrame; - idBounds AFPoseBounds; - int AFPoseTime; -}; - -/* -============================================================================================== - - idAnimManager - -============================================================================================== -*/ - -class idAnimManager { -public: - idAnimManager(); - ~idAnimManager(); - - static bool forceExport; - - void Shutdown( void ); - idMD5Anim * GetAnim( const char *name ); - void ReloadAnims( void ); - void ListAnims( void ) const; - int JointIndex( const char *name ); - const char * JointName( int index ) const; - - void ClearAnimsInUse( void ); - void FlushUnusedAnims( void ); - -private: - idHashTable animations; - idStrList jointnames; - idHashIndex jointnamesHash; -}; - -#endif /* !__ANIM_H__ */ diff --git a/d3xp/anim/Anim_Blend.cpp b/d3xp/anim/Anim_Blend.cpp deleted file mode 100644 index da1249a6..00000000 --- a/d3xp/anim/Anim_Blend.cpp +++ /dev/null @@ -1,5119 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "idlib/containers/BinSearch.h" -#include "idlib/geometry/JointTransform.h" -#include "idlib/math/Quat.h" -#include "renderer/ModelManager.h" - -#include "gamesys/SysCvar.h" -#include "ai/AI.h" -#include "Entity.h" -#include "Fx.h" -#include "Game_local.h" - -#include "anim/Anim.h" - -static const char *channelNames[ ANIM_NumAnimChannels ] = { - "all", "torso", "legs", "head", "eyelids" -}; - -/*********************************************************************** - - idAnim - -***********************************************************************/ - -/* -===================== -idAnim::idAnim -===================== -*/ -idAnim::idAnim() { - modelDef = NULL; - numAnims = 0; - memset( anims, 0, sizeof( anims ) ); - memset( &flags, 0, sizeof( flags ) ); -} - -/* -===================== -idAnim::idAnim -===================== -*/ -idAnim::idAnim( const idDeclModelDef *modelDef, const idAnim *anim ) { - int i; - - this->modelDef = modelDef; - numAnims = anim->numAnims; - name = anim->name; - realname = anim->realname; - flags = anim->flags; - - memset( anims, 0, sizeof( anims ) ); - for( i = 0; i < numAnims; i++ ) { - anims[ i ] = anim->anims[ i ]; - anims[ i ]->IncreaseRefs(); - } - - frameLookup.SetNum( anim->frameLookup.Num() ); - memcpy( frameLookup.Ptr(), anim->frameLookup.Ptr(), frameLookup.MemoryUsed() ); - - frameCommands.SetNum( anim->frameCommands.Num() ); - for( i = 0; i < frameCommands.Num(); i++ ) { - frameCommands[ i ] = anim->frameCommands[ i ]; - if ( anim->frameCommands[ i ].string ) { - frameCommands[ i ].string = new idStr( *anim->frameCommands[ i ].string ); - } - } -} - -/* -===================== -idAnim::~idAnim -===================== -*/ -idAnim::~idAnim() { - int i; - - for( i = 0; i < numAnims; i++ ) { - anims[ i ]->DecreaseRefs(); - } - - for( i = 0; i < frameCommands.Num(); i++ ) { - delete frameCommands[ i ].string; - } -} - -/* -===================== -idAnim::SetAnim -===================== -*/ -void idAnim::SetAnim( const idDeclModelDef *modelDef, const char *sourcename, const char *animname, int num, const idMD5Anim *md5anims[ ANIM_MaxSyncedAnims ] ) { - int i; - - this->modelDef = modelDef; - - for( i = 0; i < numAnims; i++ ) { - anims[ i ]->DecreaseRefs(); - anims[ i ] = NULL; - } - - assert( ( num > 0 ) && ( num <= ANIM_MaxSyncedAnims ) ); - numAnims = num; - realname = sourcename; - name = animname; - - for( i = 0; i < num; i++ ) { - anims[ i ] = md5anims[ i ]; - anims[ i ]->IncreaseRefs(); - } - - memset( &flags, 0, sizeof( flags ) ); - - for( i = 0; i < frameCommands.Num(); i++ ) { - delete frameCommands[ i ].string; - } - - frameLookup.Clear(); - frameCommands.Clear(); -} - -/* -===================== -idAnim::Name -===================== -*/ -const char *idAnim::Name( void ) const { - return name; -} - -/* -===================== -idAnim::FullName -===================== -*/ -const char *idAnim::FullName( void ) const { - return realname; -} - -/* -===================== -idAnim::MD5Anim - -index 0 will never be NULL. Any anim >= NumAnims will return NULL. -===================== -*/ -const idMD5Anim *idAnim::MD5Anim( int num ) const { - if ( anims == NULL || anims[0] == NULL ) { - return NULL; - } - return anims[ num ]; -} - -/* -===================== -idAnim::ModelDef -===================== -*/ -const idDeclModelDef *idAnim::ModelDef( void ) const { - return modelDef; -} - -/* -===================== -idAnim::Length -===================== -*/ -int idAnim::Length( void ) const { - if ( !anims[ 0 ] ) { - return 0; - } - - return anims[ 0 ]->Length(); -} - -/* -===================== -idAnim::NumFrames -===================== -*/ -int idAnim::NumFrames( void ) const { - if ( !anims[ 0 ] ) { - return 0; - } - - return anims[ 0 ]->NumFrames(); -} - -/* -===================== -idAnim::NumAnims -===================== -*/ -int idAnim::NumAnims( void ) const { - return numAnims; -} - -/* -===================== -idAnim::TotalMovementDelta -===================== -*/ -const idVec3 &idAnim::TotalMovementDelta( void ) const { - if ( !anims[ 0 ] ) { - return vec3_zero; - } - - return anims[ 0 ]->TotalMovementDelta(); -} - -/* -===================== -idAnim::GetOrigin -===================== -*/ -bool idAnim::GetOrigin( idVec3 &offset, int animNum, int currentTime, int cyclecount ) const { - if ( !anims[ animNum ] ) { - offset.Zero(); - return false; - } - - anims[ animNum ]->GetOrigin( offset, currentTime, cyclecount ); - return true; -} - -/* -===================== -idAnim::GetOriginRotation -===================== -*/ -bool idAnim::GetOriginRotation( idQuat &rotation, int animNum, int currentTime, int cyclecount ) const { - if ( !anims[ animNum ] ) { - rotation.Set( 0.0f, 0.0f, 0.0f, 1.0f ); - return false; - } - - anims[ animNum ]->GetOriginRotation( rotation, currentTime, cyclecount ); - return true; -} - -/* -===================== -idAnim::GetBounds -===================== -*/ -ID_INLINE bool idAnim::GetBounds( idBounds &bounds, int animNum, int currentTime, int cyclecount ) const { - if ( !anims[ animNum ] ) { - return false; - } - - anims[ animNum ]->GetBounds( bounds, currentTime, cyclecount ); - return true; -} - - -/* -===================== -idAnim::AddFrameCommand - -Returns NULL if no error. -===================== -*/ -const char *idAnim::AddFrameCommand( const idDeclModelDef *modelDef, int framenum, idLexer &src, const idDict *def ) { - int i; - int index; - idStr text; - idStr funcname; - frameCommand_t fc; - idToken token; - const jointInfo_t *jointInfo; - - // make sure we're within bounds - if ( ( framenum < 1 ) || ( framenum > anims[ 0 ]->NumFrames() ) ) { - return va( "Frame %d out of range", framenum ); - } - - // frame numbers are 1 based in .def files, but 0 based internally - framenum--; - - memset( &fc, 0, sizeof( fc ) ); - - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - if ( token == "call" ) { - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - fc.type = FC_SCRIPTFUNCTION; - fc.function = gameLocal.program.FindFunction( token ); - if ( !fc.function ) { - return va( "Function '%s' not found", token.c_str() ); - } - } else if ( token == "object_call" ) { - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - fc.type = FC_SCRIPTFUNCTIONOBJECT; - fc.string = new idStr( token ); - } else if ( token == "event" ) { - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - fc.type = FC_EVENTFUNCTION; - const idEventDef *ev = idEventDef::FindEvent( token ); - if ( !ev ) { - return va( "Event '%s' not found", token.c_str() ); - } - if ( ev->GetNumArgs() != 0 ) { - return va( "Event '%s' has arguments", token.c_str() ); - } - fc.string = new idStr( token ); - } else if ( token == "sound" ) { - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - fc.type = FC_SOUND; - if ( !token.Cmpn( "snd_", 4 ) ) { - fc.string = new idStr( token ); - } else { - fc.soundShader = declManager->FindSound( token ); - if ( fc.soundShader->GetState() == DS_DEFAULTED ) { - gameLocal.Warning( "Sound '%s' not found", token.c_str() ); - } - } - } else if ( token == "sound_voice" ) { - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - fc.type = FC_SOUND_VOICE; - if ( !token.Cmpn( "snd_", 4 ) ) { - fc.string = new idStr( token ); - } else { - fc.soundShader = declManager->FindSound( token ); - if ( fc.soundShader->GetState() == DS_DEFAULTED ) { - gameLocal.Warning( "Sound '%s' not found", token.c_str() ); - } - } - } else if ( token == "sound_voice2" ) { - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - fc.type = FC_SOUND_VOICE2; - if ( !token.Cmpn( "snd_", 4 ) ) { - fc.string = new idStr( token ); - } else { - fc.soundShader = declManager->FindSound( token ); - if ( fc.soundShader->GetState() == DS_DEFAULTED ) { - gameLocal.Warning( "Sound '%s' not found", token.c_str() ); - } - } - } else if ( token == "sound_body" ) { - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - fc.type = FC_SOUND_BODY; - if ( !token.Cmpn( "snd_", 4 ) ) { - fc.string = new idStr( token ); - } else { - fc.soundShader = declManager->FindSound( token ); - if ( fc.soundShader->GetState() == DS_DEFAULTED ) { - gameLocal.Warning( "Sound '%s' not found", token.c_str() ); - } - } - } else if ( token == "sound_body2" ) { - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - fc.type = FC_SOUND_BODY2; - if ( !token.Cmpn( "snd_", 4 ) ) { - fc.string = new idStr( token ); - } else { - fc.soundShader = declManager->FindSound( token ); - if ( fc.soundShader->GetState() == DS_DEFAULTED ) { - gameLocal.Warning( "Sound '%s' not found", token.c_str() ); - } - } - } else if ( token == "sound_body3" ) { - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - fc.type = FC_SOUND_BODY3; - if ( !token.Cmpn( "snd_", 4 ) ) { - fc.string = new idStr( token ); - } else { - fc.soundShader = declManager->FindSound( token ); - if ( fc.soundShader->GetState() == DS_DEFAULTED ) { - gameLocal.Warning( "Sound '%s' not found", token.c_str() ); - } - } - } else if ( token == "sound_weapon" ) { - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - fc.type = FC_SOUND_WEAPON; - if ( !token.Cmpn( "snd_", 4 ) ) { - fc.string = new idStr( token ); - } else { - fc.soundShader = declManager->FindSound( token ); - if ( fc.soundShader->GetState() == DS_DEFAULTED ) { - gameLocal.Warning( "Sound '%s' not found", token.c_str() ); - } - } - } else if ( token == "sound_global" ) { - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - fc.type = FC_SOUND_GLOBAL; - if ( !token.Cmpn( "snd_", 4 ) ) { - fc.string = new idStr( token ); - } else { - fc.soundShader = declManager->FindSound( token ); - if ( fc.soundShader->GetState() == DS_DEFAULTED ) { - gameLocal.Warning( "Sound '%s' not found", token.c_str() ); - } - } - } else if ( token == "sound_item" ) { - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - fc.type = FC_SOUND_ITEM; - if ( !token.Cmpn( "snd_", 4 ) ) { - fc.string = new idStr( token ); - } else { - fc.soundShader = declManager->FindSound( token ); - if ( fc.soundShader->GetState() == DS_DEFAULTED ) { - gameLocal.Warning( "Sound '%s' not found", token.c_str() ); - } - } - } else if ( token == "sound_chatter" ) { - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - fc.type = FC_SOUND_CHATTER; - if ( !token.Cmpn( "snd_", 4 ) ) { - fc.string = new idStr( token ); - } else { - fc.soundShader = declManager->FindSound( token ); - if ( fc.soundShader->GetState() == DS_DEFAULTED ) { - gameLocal.Warning( "Sound '%s' not found", token.c_str() ); - } - } - } else if ( token == "skin" ) { - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - fc.type = FC_SKIN; - if ( token == "none" ) { - fc.skin = NULL; - } else { - fc.skin = declManager->FindSkin( token ); - if ( !fc.skin ) { - return va( "Skin '%s' not found", token.c_str() ); - } - } - } else if ( token == "fx" ) { - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - fc.type = FC_FX; - if ( !declManager->FindType( DECL_FX, token.c_str() ) ) { - return va( "fx '%s' not found", token.c_str() ); - } - fc.string = new idStr( token ); - } else if ( token == "trigger" ) { - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - fc.type = FC_TRIGGER; - fc.string = new idStr( token ); - } else if ( token == "triggerSmokeParticle" ) { - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - fc.type = FC_TRIGGER_SMOKE_PARTICLE; - fc.string = new idStr( token ); - } else if ( token == "melee" ) { - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - fc.type = FC_MELEE; - if ( !gameLocal.FindEntityDef( token.c_str(), false ) ) { - return va( "Unknown entityDef '%s'", token.c_str() ); - } - fc.string = new idStr( token ); - } else if ( token == "direct_damage" ) { - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - fc.type = FC_DIRECTDAMAGE; - if ( !gameLocal.FindEntityDef( token.c_str(), false ) ) { - return va( "Unknown entityDef '%s'", token.c_str() ); - } - fc.string = new idStr( token ); - } else if ( token == "attack_begin" ) { - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - fc.type = FC_BEGINATTACK; - if ( !gameLocal.FindEntityDef( token.c_str(), false ) ) { - return va( "Unknown entityDef '%s'", token.c_str() ); - } - fc.string = new idStr( token ); - } else if ( token == "attack_end" ) { - fc.type = FC_ENDATTACK; - } else if ( token == "muzzle_flash" ) { - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - if ( ( token != "" ) && !modelDef->FindJoint( token ) ) { - return va( "Joint '%s' not found", token.c_str() ); - } - fc.type = FC_MUZZLEFLASH; - fc.string = new idStr( token ); - } else if ( token == "muzzle_flash" ) { - fc.type = FC_MUZZLEFLASH; - fc.string = new idStr( "" ); - } else if ( token == "create_missile" ) { - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - if ( !modelDef->FindJoint( token ) ) { - return va( "Joint '%s' not found", token.c_str() ); - } - fc.type = FC_CREATEMISSILE; - fc.string = new idStr( token ); - } else if ( token == "launch_missile" ) { - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - if ( !modelDef->FindJoint( token ) ) { - return va( "Joint '%s' not found", token.c_str() ); - } - fc.type = FC_LAUNCHMISSILE; - fc.string = new idStr( token ); - } else if ( token == "fire_missile_at_target" ) { - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - jointInfo = modelDef->FindJoint( token ); - if ( !jointInfo ) { - return va( "Joint '%s' not found", token.c_str() ); - } - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - fc.type = FC_FIREMISSILEATTARGET; - fc.string = new idStr( token ); - fc.index = jointInfo->num; -#ifdef _D3XP - } else if ( token == "launch_projectile" ) { - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - if ( !declManager->FindDeclWithoutParsing( DECL_ENTITYDEF, token, false ) ) { - return "Unknown projectile def"; - } - fc.type = FC_LAUNCH_PROJECTILE; - fc.string = new idStr( token ); - } else if ( token == "trigger_fx" ) { - - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - jointInfo = modelDef->FindJoint( token ); - if ( !jointInfo ) { - return va( "Joint '%s' not found", token.c_str() ); - } - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - if ( !declManager->FindType( DECL_FX, token, false ) ) { - return "Unknown FX def"; - } - - fc.type = FC_TRIGGER_FX; - fc.string = new idStr( token ); - fc.index = jointInfo->num; - - } else if ( token == "start_emitter" ) { - - idStr str; - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - str = token + " "; - - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - jointInfo = modelDef->FindJoint( token ); - if ( !jointInfo ) { - return va( "Joint '%s' not found", token.c_str() ); - } - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - str += token; - fc.type = FC_START_EMITTER; - fc.string = new idStr( str ); - fc.index = jointInfo->num; - - } else if ( token == "stop_emitter" ) { - - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - fc.type = FC_STOP_EMITTER; - fc.string = new idStr( token ); -#endif - } else if ( token == "footstep" ) { - fc.type = FC_FOOTSTEP; - } else if ( token == "leftfoot" ) { - fc.type = FC_LEFTFOOT; - } else if ( token == "rightfoot" ) { - fc.type = FC_RIGHTFOOT; - } else if ( token == "enableEyeFocus" ) { - fc.type = FC_ENABLE_EYE_FOCUS; - } else if ( token == "disableEyeFocus" ) { - fc.type = FC_DISABLE_EYE_FOCUS; - } else if ( token == "disableGravity" ) { - fc.type = FC_DISABLE_GRAVITY; - } else if ( token == "enableGravity" ) { - fc.type = FC_ENABLE_GRAVITY; - } else if ( token == "jump" ) { - fc.type = FC_JUMP; - } else if ( token == "enableClip" ) { - fc.type = FC_ENABLE_CLIP; - } else if ( token == "disableClip" ) { - fc.type = FC_DISABLE_CLIP; - } else if ( token == "enableWalkIK" ) { - fc.type = FC_ENABLE_WALK_IK; - } else if ( token == "disableWalkIK" ) { - fc.type = FC_DISABLE_WALK_IK; - } else if ( token == "enableLegIK" ) { - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - fc.type = FC_ENABLE_LEG_IK; - fc.index = atoi( token ); - } else if ( token == "disableLegIK" ) { - if( !src.ReadTokenOnLine( &token ) ) { - return "Unexpected end of line"; - } - fc.type = FC_DISABLE_LEG_IK; - fc.index = atoi( token ); - } else if ( token == "recordDemo" ) { - fc.type = FC_RECORDDEMO; - if( src.ReadTokenOnLine( &token ) ) { - fc.string = new idStr( token ); - } - } else if ( token == "aviGame" ) { - fc.type = FC_AVIGAME; - if( src.ReadTokenOnLine( &token ) ) { - fc.string = new idStr( token ); - } - } else { - return va( "Unknown command '%s'", token.c_str() ); - } - - // check if we've initialized the frame loopup table - if ( !frameLookup.Num() ) { - // we haven't, so allocate the table and initialize it - frameLookup.SetGranularity( 1 ); - frameLookup.SetNum( anims[ 0 ]->NumFrames() ); - for( i = 0; i < frameLookup.Num(); i++ ) { - frameLookup[ i ].num = 0; - frameLookup[ i ].firstCommand = 0; - } - } - - // allocate space for a new command - frameCommands.Alloc(); - - // calculate the index of the new command - index = frameLookup[ framenum ].firstCommand + frameLookup[ framenum ].num; - - // move all commands from our index onward up one to give us space for our new command - for( i = frameCommands.Num() - 1; i > index; i-- ) { - frameCommands[ i ] = frameCommands[ i - 1 ]; - } - - // fix the indices of any later frames to account for the inserted command - for( i = framenum + 1; i < frameLookup.Num(); i++ ) { - frameLookup[ i ].firstCommand++; - } - - // store the new command - frameCommands[ index ] = fc; - - // increase the number of commands on this frame - frameLookup[ framenum ].num++; - - // return with no error - return NULL; -} - -/* -===================== -idAnim::CallFrameCommands -===================== -*/ -void idAnim::CallFrameCommands( idEntity *ent, int from, int to ) const { - int index; - int end; - int frame; - int numframes; - - numframes = anims[ 0 ]->NumFrames(); - - frame = from; - while( frame != to ) { - frame++; - if ( frame >= numframes ) { - frame = 0; - } - - index = frameLookup[ frame ].firstCommand; - end = index + frameLookup[ frame ].num; - while( index < end ) { - const frameCommand_t &command = frameCommands[ index++ ]; - switch( command.type ) { - case FC_SCRIPTFUNCTION: { - gameLocal.CallFrameCommand( ent, command.function ); - break; - } - case FC_SCRIPTFUNCTIONOBJECT: { - gameLocal.CallObjectFrameCommand( ent, command.string->c_str() ); - break; - } - case FC_EVENTFUNCTION: { - const idEventDef *ev = idEventDef::FindEvent( command.string->c_str() ); - ent->ProcessEvent( ev ); - break; - } - case FC_SOUND: { - if ( !command.soundShader ) { - if ( !ent->StartSound( command.string->c_str(), SND_CHANNEL_ANY, 0, false, NULL ) ) { - gameLocal.Warning( "Framecommand 'sound' on entity '%s', anim '%s', frame %d: Could not find sound '%s'", - ent->name.c_str(), FullName(), frame + 1, command.string->c_str() ); - } - } else { - ent->StartSoundShader( command.soundShader, SND_CHANNEL_ANY, 0, false, NULL ); - } - break; - } - case FC_SOUND_VOICE: { - if ( !command.soundShader ) { - if ( !ent->StartSound( command.string->c_str(), SND_CHANNEL_VOICE, 0, false, NULL ) ) { - gameLocal.Warning( "Framecommand 'sound_voice' on entity '%s', anim '%s', frame %d: Could not find sound '%s'", - ent->name.c_str(), FullName(), frame + 1, command.string->c_str() ); - } - } else { - ent->StartSoundShader( command.soundShader, SND_CHANNEL_VOICE, 0, false, NULL ); - } - break; - } - case FC_SOUND_VOICE2: { - if ( !command.soundShader ) { - if ( !ent->StartSound( command.string->c_str(), SND_CHANNEL_VOICE2, 0, false, NULL ) ) { - gameLocal.Warning( "Framecommand 'sound_voice2' on entity '%s', anim '%s', frame %d: Could not find sound '%s'", - ent->name.c_str(), FullName(), frame + 1, command.string->c_str() ); - } - } else { - ent->StartSoundShader( command.soundShader, SND_CHANNEL_VOICE2, 0, false, NULL ); - } - break; - } - case FC_SOUND_BODY: { - if ( !command.soundShader ) { - if ( !ent->StartSound( command.string->c_str(), SND_CHANNEL_BODY, 0, false, NULL ) ) { - gameLocal.Warning( "Framecommand 'sound_body' on entity '%s', anim '%s', frame %d: Could not find sound '%s'", - ent->name.c_str(), FullName(), frame + 1, command.string->c_str() ); - } - } else { - ent->StartSoundShader( command.soundShader, SND_CHANNEL_BODY, 0, false, NULL ); - } - break; - } - case FC_SOUND_BODY2: { - if ( !command.soundShader ) { - if ( !ent->StartSound( command.string->c_str(), SND_CHANNEL_BODY2, 0, false, NULL ) ) { - gameLocal.Warning( "Framecommand 'sound_body2' on entity '%s', anim '%s', frame %d: Could not find sound '%s'", - ent->name.c_str(), FullName(), frame + 1, command.string->c_str() ); - } - } else { - ent->StartSoundShader( command.soundShader, SND_CHANNEL_BODY2, 0, false, NULL ); - } - break; - } - case FC_SOUND_BODY3: { - if ( !command.soundShader ) { - if ( !ent->StartSound( command.string->c_str(), SND_CHANNEL_BODY3, 0, false, NULL ) ) { - gameLocal.Warning( "Framecommand 'sound_body3' on entity '%s', anim '%s', frame %d: Could not find sound '%s'", - ent->name.c_str(), FullName(), frame + 1, command.string->c_str() ); - } - } else { - ent->StartSoundShader( command.soundShader, SND_CHANNEL_BODY3, 0, false, NULL ); - } - break; - } - case FC_SOUND_WEAPON: { - if ( !command.soundShader ) { - if ( !ent->StartSound( command.string->c_str(), SND_CHANNEL_WEAPON, 0, false, NULL ) ) { - gameLocal.Warning( "Framecommand 'sound_weapon' on entity '%s', anim '%s', frame %d: Could not find sound '%s'", - ent->name.c_str(), FullName(), frame + 1, command.string->c_str() ); - } - } else { - ent->StartSoundShader( command.soundShader, SND_CHANNEL_WEAPON, 0, false, NULL ); - } - break; - } - case FC_SOUND_GLOBAL: { - if ( !command.soundShader ) { - if ( !ent->StartSound( command.string->c_str(), SND_CHANNEL_ANY, SSF_GLOBAL, false, NULL ) ) { - gameLocal.Warning( "Framecommand 'sound_global' on entity '%s', anim '%s', frame %d: Could not find sound '%s'", - ent->name.c_str(), FullName(), frame + 1, command.string->c_str() ); - } - } else { - ent->StartSoundShader( command.soundShader, SND_CHANNEL_ANY, SSF_GLOBAL, false, NULL ); - } - break; - } - case FC_SOUND_ITEM: { - if ( !command.soundShader ) { - if ( !ent->StartSound( command.string->c_str(), SND_CHANNEL_ITEM, 0, false, NULL ) ) { - gameLocal.Warning( "Framecommand 'sound_item' on entity '%s', anim '%s', frame %d: Could not find sound '%s'", - ent->name.c_str(), FullName(), frame + 1, command.string->c_str() ); - } - } else { - ent->StartSoundShader( command.soundShader, SND_CHANNEL_ITEM, 0, false, NULL ); - } - break; - } - case FC_SOUND_CHATTER: { - if ( ent->CanPlayChatterSounds() ) { - if ( !command.soundShader ) { - if ( !ent->StartSound( command.string->c_str(), SND_CHANNEL_VOICE, 0, false, NULL ) ) { - gameLocal.Warning( "Framecommand 'sound_chatter' on entity '%s', anim '%s', frame %d: Could not find sound '%s'", - ent->name.c_str(), FullName(), frame + 1, command.string->c_str() ); - } - } else { - ent->StartSoundShader( command.soundShader, SND_CHANNEL_VOICE, 0, false, NULL ); - } - } - break; - } - case FC_FX: { - idEntityFx::StartFx( command.string->c_str(), NULL, NULL, ent, true ); - break; - } - case FC_SKIN: { - ent->SetSkin( command.skin ); - break; - } - case FC_TRIGGER: { - idEntity *target; - - target = gameLocal.FindEntity( command.string->c_str() ); - if ( target ) { -#ifdef _D3XP - SetTimeState ts(target->timeGroup); -#endif - target->Signal( SIG_TRIGGER ); - target->ProcessEvent( &EV_Activate, ent ); - target->TriggerGuis(); - } else { - gameLocal.Warning( "Framecommand 'trigger' on entity '%s', anim '%s', frame %d: Could not find entity '%s'", - ent->name.c_str(), FullName(), frame + 1, command.string->c_str() ); - } - break; - } - case FC_TRIGGER_SMOKE_PARTICLE: { - ent->ProcessEvent( &AI_TriggerParticles, command.string->c_str() ); - break; - } - case FC_MELEE: { - ent->ProcessEvent( &AI_AttackMelee, command.string->c_str() ); - break; - } - case FC_DIRECTDAMAGE: { - ent->ProcessEvent( &AI_DirectDamage, command.string->c_str() ); - break; - } - case FC_BEGINATTACK: { - ent->ProcessEvent( &AI_BeginAttack, command.string->c_str() ); - break; - } - case FC_ENDATTACK: { - ent->ProcessEvent( &AI_EndAttack ); - break; - } - case FC_MUZZLEFLASH: { - ent->ProcessEvent( &AI_MuzzleFlash, command.string->c_str() ); - break; - } - case FC_CREATEMISSILE: { - ent->ProcessEvent( &AI_CreateMissile, command.string->c_str() ); - break; - } - case FC_LAUNCHMISSILE: { - ent->ProcessEvent( &AI_AttackMissile, command.string->c_str() ); - break; - } - case FC_FIREMISSILEATTARGET: { - ent->ProcessEvent( &AI_FireMissileAtTarget, modelDef->GetJointName( command.index ), command.string->c_str() ); - break; - } -#ifdef _D3XP - case FC_LAUNCH_PROJECTILE: { - ent->ProcessEvent( &AI_LaunchProjectile, command.string->c_str() ); - break; - } - case FC_TRIGGER_FX: { - ent->ProcessEvent( &AI_TriggerFX, modelDef->GetJointName( command.index ), command.string->c_str() ); - break; - } - case FC_START_EMITTER: { - int index = command.string->Find(" "); - if(index >= 0) { - idStr name = command.string->Left(index); - idStr particle = command.string->Right(command.string->Length() - index - 1); - ent->ProcessEvent( &AI_StartEmitter, name.c_str(), modelDef->GetJointName( command.index ), particle.c_str() ); - } - } - - case FC_STOP_EMITTER: { - ent->ProcessEvent( &AI_StopEmitter, command.string->c_str() ); - } -#endif - case FC_FOOTSTEP : { - ent->ProcessEvent( &EV_Footstep ); - break; - } - case FC_LEFTFOOT: { - ent->ProcessEvent( &EV_FootstepLeft ); - break; - } - case FC_RIGHTFOOT: { - ent->ProcessEvent( &EV_FootstepRight ); - break; - } - case FC_ENABLE_EYE_FOCUS: { - ent->ProcessEvent( &AI_EnableEyeFocus ); - break; - } - case FC_DISABLE_EYE_FOCUS: { - ent->ProcessEvent( &AI_DisableEyeFocus ); - break; - } - case FC_DISABLE_GRAVITY: { - ent->ProcessEvent( &AI_DisableGravity ); - break; - } - case FC_ENABLE_GRAVITY: { - ent->ProcessEvent( &AI_EnableGravity ); - break; - } - case FC_JUMP: { - ent->ProcessEvent( &AI_JumpFrame ); - break; - } - case FC_ENABLE_CLIP: { - ent->ProcessEvent( &AI_EnableClip ); - break; - } - case FC_DISABLE_CLIP: { - ent->ProcessEvent( &AI_DisableClip ); - break; - } - case FC_ENABLE_WALK_IK: { - ent->ProcessEvent( &EV_EnableWalkIK ); - break; - } - case FC_DISABLE_WALK_IK: { - ent->ProcessEvent( &EV_DisableWalkIK ); - break; - } - case FC_ENABLE_LEG_IK: { - ent->ProcessEvent( &EV_EnableLegIK, command.index ); - break; - } - case FC_DISABLE_LEG_IK: { - ent->ProcessEvent( &EV_DisableLegIK, command.index ); - break; - } - case FC_RECORDDEMO: { - if ( command.string ) { - cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "recordDemo %s", command.string->c_str() ) ); - } else { - cmdSystem->BufferCommandText( CMD_EXEC_NOW, "stoprecording" ); - } - break; - } - case FC_AVIGAME: { - if ( command.string ) { - cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "aviGame %s", command.string->c_str() ) ); - } else { - cmdSystem->BufferCommandText( CMD_EXEC_NOW, "aviGame" ); - } - break; - } - } - } - } -} - -/* -===================== -idAnim::FindFrameForFrameCommand -===================== -*/ -int idAnim::FindFrameForFrameCommand( frameCommandType_t framecommand, const frameCommand_t **command ) const { - int frame; - int index; - int numframes; - int end; - - if ( !frameCommands.Num() ) { - return -1; - } - - numframes = anims[ 0 ]->NumFrames(); - for( frame = 0; frame < numframes; frame++ ) { - end = frameLookup[ frame ].firstCommand + frameLookup[ frame ].num; - for( index = frameLookup[ frame ].firstCommand; index < end; index++ ) { - if ( frameCommands[ index ].type == framecommand ) { - if ( command ) { - *command = &frameCommands[ index ]; - } - return frame; - } - } - } - - if ( command ) { - *command = NULL; - } - - return -1; -} - -/* -===================== -idAnim::HasFrameCommands -===================== -*/ -bool idAnim::HasFrameCommands( void ) const { - if ( !frameCommands.Num() ) { - return false; - } - return true; -} - -/* -===================== -idAnim::SetAnimFlags -===================== -*/ -void idAnim::SetAnimFlags( const animFlags_t &animflags ) { - flags = animflags; -} - -/* -===================== -idAnim::GetAnimFlags -===================== -*/ -const animFlags_t &idAnim::GetAnimFlags( void ) const { - return flags; -} - -/*********************************************************************** - - idAnimBlend - -***********************************************************************/ - -/* -===================== -idAnimBlend::idAnimBlend -===================== -*/ -idAnimBlend::idAnimBlend( void ) { - Reset( NULL ); -} - -/* -===================== -idAnimBlend::Save - -archives object for save game file -===================== -*/ -void idAnimBlend::Save( idSaveGame *savefile ) const { - int i; - - savefile->WriteInt( starttime ); - savefile->WriteInt( endtime ); - savefile->WriteInt( timeOffset ); - savefile->WriteFloat( rate ); - - savefile->WriteInt( blendStartTime ); - savefile->WriteInt( blendDuration ); - savefile->WriteFloat( blendStartValue ); - savefile->WriteFloat( blendEndValue ); - - for( i = 0; i < ANIM_MaxSyncedAnims; i++ ) { - savefile->WriteFloat( animWeights[ i ] ); - } - savefile->WriteShort( cycle ); - savefile->WriteShort( frame ); - savefile->WriteShort( animNum ); - savefile->WriteBool( allowMove ); - savefile->WriteBool( allowFrameCommands ); -} - -/* -===================== -idAnimBlend::Restore - -unarchives object from save game file -===================== -*/ -void idAnimBlend::Restore( idRestoreGame *savefile, const idDeclModelDef *modelDef ) { - int i; - - this->modelDef = modelDef; - - savefile->ReadInt( starttime ); - savefile->ReadInt( endtime ); - savefile->ReadInt( timeOffset ); - savefile->ReadFloat( rate ); - - savefile->ReadInt( blendStartTime ); - savefile->ReadInt( blendDuration ); - savefile->ReadFloat( blendStartValue ); - savefile->ReadFloat( blendEndValue ); - - for( i = 0; i < ANIM_MaxSyncedAnims; i++ ) { - savefile->ReadFloat( animWeights[ i ] ); - } - savefile->ReadShort( cycle ); - savefile->ReadShort( frame ); - savefile->ReadShort( animNum ); - if ( !modelDef ) { - animNum = 0; - } else if ( ( animNum < 0 ) || ( animNum > modelDef->NumAnims() ) ) { - gameLocal.Warning( "Anim number %d out of range for model '%s' during save game", animNum, modelDef->GetModelName() ); - animNum = 0; - } - savefile->ReadBool( allowMove ); - savefile->ReadBool( allowFrameCommands ); -} - -/* -===================== -idAnimBlend::Reset -===================== -*/ -void idAnimBlend::Reset( const idDeclModelDef *_modelDef ) { - modelDef = _modelDef; - cycle = 1; - starttime = 0; - endtime = 0; - timeOffset = 0; - rate = 1.0f; - frame = 0; - allowMove = true; - allowFrameCommands = true; - animNum = 0; - - memset( animWeights, 0, sizeof( animWeights ) ); - - blendStartValue = 0.0f; - blendEndValue = 0.0f; - blendStartTime = 0; - blendDuration = 0; -} - -/* -===================== -idAnimBlend::FullName -===================== -*/ -const char *idAnimBlend::AnimFullName( void ) const { - const idAnim *anim = Anim(); - if ( !anim ) { - return ""; - } - - return anim->FullName(); -} - -/* -===================== -idAnimBlend::AnimName -===================== -*/ -const char *idAnimBlend::AnimName( void ) const { - const idAnim *anim = Anim(); - if ( !anim ) { - return ""; - } - - return anim->Name(); -} - -/* -===================== -idAnimBlend::NumFrames -===================== -*/ -int idAnimBlend::NumFrames( void ) const { - const idAnim *anim = Anim(); - if ( !anim ) { - return 0; - } - - return anim->NumFrames(); -} - -/* -===================== -idAnimBlend::Length -===================== -*/ -int idAnimBlend::Length( void ) const { - const idAnim *anim = Anim(); - if ( !anim ) { - return 0; - } - - return anim->Length(); -} - -/* -===================== -idAnimBlend::GetWeight -===================== -*/ -float idAnimBlend::GetWeight( int currentTime ) const { - int timeDelta; - float frac; - float w; - - timeDelta = currentTime - blendStartTime; - if ( timeDelta <= 0 ) { - w = blendStartValue; - } else if ( timeDelta >= blendDuration ) { - w = blendEndValue; - } else { - frac = ( float )timeDelta / ( float )blendDuration; - w = blendStartValue + ( blendEndValue - blendStartValue ) * frac; - } - - return w; -} - -/* -===================== -idAnimBlend::GetFinalWeight -===================== -*/ -float idAnimBlend::GetFinalWeight( void ) const { - return blendEndValue; -} - -/* -===================== -idAnimBlend::SetWeight -===================== -*/ -void idAnimBlend::SetWeight( float newweight, int currentTime, int blendTime ) { - blendStartValue = GetWeight( currentTime ); - blendEndValue = newweight; - blendStartTime = currentTime - 1; - blendDuration = blendTime; - - if ( !newweight ) { - endtime = currentTime + blendTime; - } -} - -/* -===================== -idAnimBlend::NumSyncedAnims -===================== -*/ -int idAnimBlend::NumSyncedAnims( void ) const { - const idAnim *anim = Anim(); - if ( !anim ) { - return 0; - } - - return anim->NumAnims(); -} - -/* -===================== -idAnimBlend::SetSyncedAnimWeight -===================== -*/ -bool idAnimBlend::SetSyncedAnimWeight( int num, float weight ) { - const idAnim *anim = Anim(); - if ( !anim ) { - return false; - } - - if ( ( num < 0 ) || ( num > anim->NumAnims() ) ) { - return false; - } - - animWeights[ num ] = weight; - return true; -} - -/* -===================== -idAnimBlend::SetFrame -===================== -*/ -void idAnimBlend::SetFrame( const idDeclModelDef *modelDef, int _animNum, int _frame, int currentTime, int blendTime ) { - Reset( modelDef ); - if ( !modelDef ) { - return; - } - - const idAnim *_anim = modelDef->GetAnim( _animNum ); - if ( !_anim ) { - return; - } - - const idMD5Anim *md5anim = _anim->MD5Anim( 0 ); - if ( modelDef->Joints().Num() != md5anim->NumJoints() ) { - gameLocal.Warning( "Model '%s' has different # of joints than anim '%s'", modelDef->GetModelName(), md5anim->Name() ); - return; - } - - animNum = _animNum; - starttime = currentTime; - endtime = -1; - cycle = -1; - animWeights[ 0 ] = 1.0f; - frame = _frame; - - // a frame of 0 means it's not a single frame blend, so we set it to frame + 1 - if ( frame <= 0 ) { - frame = 1; - } else if ( frame > _anim->NumFrames() ) { - frame = _anim->NumFrames(); - } - - // set up blend - blendEndValue = 1.0f; - blendStartTime = currentTime - 1; - blendDuration = blendTime; - blendStartValue = 0.0f; -} - -/* -===================== -idAnimBlend::CycleAnim -===================== -*/ -void idAnimBlend::CycleAnim( const idDeclModelDef *modelDef, int _animNum, int currentTime, int blendTime ) { - Reset( modelDef ); - if ( !modelDef ) { - return; - } - - const idAnim *_anim = modelDef->GetAnim( _animNum ); - if ( !_anim ) { - return; - } - - const idMD5Anim *md5anim = _anim->MD5Anim( 0 ); - if ( modelDef->Joints().Num() != md5anim->NumJoints() ) { - gameLocal.Warning( "Model '%s' has different # of joints than anim '%s'", modelDef->GetModelName(), md5anim->Name() ); - return; - } - - animNum = _animNum; - animWeights[ 0 ] = 1.0f; - endtime = -1; - cycle = -1; - if ( _anim->GetAnimFlags().random_cycle_start ) { - // start the animation at a random time so that characters don't walk in sync - starttime = currentTime - gameLocal.random.RandomFloat() * _anim->Length(); - } else { - starttime = currentTime; - } - - // set up blend - blendEndValue = 1.0f; - blendStartTime = currentTime - 1; - blendDuration = blendTime; - blendStartValue = 0.0f; -} - -/* -===================== -idAnimBlend::PlayAnim -===================== -*/ -void idAnimBlend::PlayAnim( const idDeclModelDef *modelDef, int _animNum, int currentTime, int blendTime ) { - Reset( modelDef ); - if ( !modelDef ) { - return; - } - - const idAnim *_anim = modelDef->GetAnim( _animNum ); - if ( !_anim ) { - return; - } - - const idMD5Anim *md5anim = _anim->MD5Anim( 0 ); - if ( modelDef->Joints().Num() != md5anim->NumJoints() ) { - gameLocal.Warning( "Model '%s' has different # of joints than anim '%s'", modelDef->GetModelName(), md5anim->Name() ); - return; - } - - animNum = _animNum; - starttime = currentTime; - endtime = starttime + _anim->Length(); - cycle = 1; - animWeights[ 0 ] = 1.0f; - - // set up blend - blendEndValue = 1.0f; - blendStartTime = currentTime - 1; - blendDuration = blendTime; - blendStartValue = 0.0f; -} - -/* -===================== -idAnimBlend::Clear -===================== -*/ -void idAnimBlend::Clear( int currentTime, int clearTime ) { - if ( !clearTime ) { - Reset( modelDef ); - } else { - SetWeight( 0.0f, currentTime, clearTime ); - } -} - -/* -===================== -idAnimBlend::IsDone -===================== -*/ -bool idAnimBlend::IsDone( int currentTime ) const { - if ( !frame && ( endtime > 0 ) && ( currentTime >= endtime ) ) { - return true; - } - - if ( ( blendEndValue <= 0.0f ) && ( currentTime >= ( blendStartTime + blendDuration ) ) ) { - return true; - } - - return false; -} - -/* -===================== -idAnimBlend::FrameHasChanged -===================== -*/ -bool idAnimBlend::FrameHasChanged( int currentTime ) const { - // if we don't have an anim, no change - if ( !animNum ) { - return false; - } - - // if anim is done playing, no change - if ( ( endtime > 0 ) && ( currentTime > endtime ) ) { - return false; - } - - // if our blend weight changes, we need to update - if ( ( currentTime < ( blendStartTime + blendDuration ) && ( blendStartValue != blendEndValue ) ) ) { - return true; - } - - // if we're a single frame anim and this isn't the frame we started on, we don't need to update - if ( ( frame || ( NumFrames() == 1 ) ) && ( currentTime != starttime ) ) { - return false; - } - - return true; -} - -/* -===================== -idAnimBlend::GetCycleCount -===================== -*/ -int idAnimBlend::GetCycleCount( void ) const { - return cycle; -} - -/* -===================== -idAnimBlend::SetCycleCount -===================== -*/ -void idAnimBlend::SetCycleCount( int count ) { - const idAnim *anim = Anim(); - - if ( !anim ) { - cycle = -1; - endtime = 0; - } else { - cycle = count; - if ( cycle < 0 ) { - cycle = -1; - endtime = -1; - } else if ( cycle == 0 ) { - cycle = 1; - - // most of the time we're running at the original frame rate, so avoid the int-to-float-to-int conversion - if ( rate == 1.0f ) { - endtime = starttime - timeOffset + anim->Length(); - } else if ( rate != 0.0f ) { - endtime = starttime - timeOffset + anim->Length() / rate; - } else { - endtime = -1; - } - } else { - // most of the time we're running at the original frame rate, so avoid the int-to-float-to-int conversion - if ( rate == 1.0f ) { - endtime = starttime - timeOffset + anim->Length() * cycle; - } else if ( rate != 0.0f ) { - endtime = starttime - timeOffset + ( anim->Length() * cycle ) / rate; - } else { - endtime = -1; - } - } - } -} - -/* -===================== -idAnimBlend::SetPlaybackRate -===================== -*/ -void idAnimBlend::SetPlaybackRate( int currentTime, float newRate ) { - int animTime; - - if ( rate == newRate ) { - return; - } - - animTime = AnimTime( currentTime ); - if ( newRate == 1.0f ) { - timeOffset = animTime - ( currentTime - starttime ); - } else { - timeOffset = animTime - ( currentTime - starttime ) * newRate; - } - - rate = newRate; - - // update the anim endtime - SetCycleCount( cycle ); -} - -/* -===================== -idAnimBlend::GetPlaybackRate -===================== -*/ -float idAnimBlend::GetPlaybackRate( void ) const { - return rate; -} - -/* -===================== -idAnimBlend::SetStartTime -===================== -*/ -void idAnimBlend::SetStartTime( int _startTime ) { - starttime = _startTime; - - // update the anim endtime - SetCycleCount( cycle ); -} - -/* -===================== -idAnimBlend::GetStartTime -===================== -*/ -int idAnimBlend::GetStartTime( void ) const { - if ( !animNum ) { - return 0; - } - - return starttime; -} - -/* -===================== -idAnimBlend::GetEndTime -===================== -*/ -int idAnimBlend::GetEndTime( void ) const { - if ( !animNum ) { - return 0; - } - - return endtime; -} - -/* -===================== -idAnimBlend::PlayLength -===================== -*/ -int idAnimBlend::PlayLength( void ) const { - if ( !animNum ) { - return 0; - } - - if ( endtime < 0 ) { - return -1; - } - - return endtime - starttime + timeOffset; -} - -/* -===================== -idAnimBlend::AllowMovement -===================== -*/ -void idAnimBlend::AllowMovement( bool allow ) { - allowMove = allow; -} - -/* -===================== -idAnimBlend::AllowFrameCommands -===================== -*/ -void idAnimBlend::AllowFrameCommands( bool allow ) { - allowFrameCommands = allow; -} - - -/* -===================== -idAnimBlend::Anim -===================== -*/ -const idAnim *idAnimBlend::Anim( void ) const { - if ( !modelDef ) { - return NULL; - } - - const idAnim *anim = modelDef->GetAnim( animNum ); - return anim; -} - -/* -===================== -idAnimBlend::AnimNum -===================== -*/ -int idAnimBlend::AnimNum( void ) const { - return animNum; -} - -/* -===================== -idAnimBlend::AnimTime -===================== -*/ -int idAnimBlend::AnimTime( int currentTime ) const { - int time; - int length; - const idAnim *anim = Anim(); - - if ( anim ) { - if ( frame ) { - return FRAME2MS( frame - 1 ); - } - - // most of the time we're running at the original frame rate, so avoid the int-to-float-to-int conversion - if ( rate == 1.0f ) { - time = currentTime - starttime + timeOffset; - } else { - time = static_cast( ( currentTime - starttime ) * rate ) + timeOffset; - } - - // given enough time, we can easily wrap time around in our frame calculations, so - // keep cycling animations' time within the length of the anim. - length = anim->Length(); - if ( ( cycle < 0 ) && ( length > 0 ) ) { - time %= length; - - // time will wrap after 24 days (oh no!), resulting in negative results for the %. - // adding the length gives us the proper result. - if ( time < 0 ) { - time += length; - } - } - return time; - } else { - return 0; - } -} - -/* -===================== -idAnimBlend::GetFrameNumber -===================== -*/ -int idAnimBlend::GetFrameNumber( int currentTime ) const { - const idMD5Anim *md5anim; - frameBlend_t frameinfo; - int animTime; - - const idAnim *anim = Anim(); - if ( !anim ) { - return 1; - } - - if ( frame ) { - return frame; - } - - md5anim = anim->MD5Anim( 0 ); - animTime = AnimTime( currentTime ); - md5anim->ConvertTimeToFrame( animTime, cycle, frameinfo ); - - return frameinfo.frame1 + 1; -} - -/* -===================== -idAnimBlend::CallFrameCommands -===================== -*/ -void idAnimBlend::CallFrameCommands( idEntity *ent, int fromtime, int totime ) const { - const idMD5Anim *md5anim; - frameBlend_t frame1; - frameBlend_t frame2; - int fromFrameTime; - int toFrameTime; - - if ( !allowFrameCommands || !ent || frame || ( ( endtime > 0 ) && ( fromtime > endtime ) ) ) { - return; - } - - const idAnim *anim = Anim(); - if ( !anim || !anim->HasFrameCommands() ) { - return; - } - - if ( totime <= starttime ) { - // don't play until next frame or we'll play commands twice. - // this happens on the player sometimes. - return; - } - - fromFrameTime = AnimTime( fromtime ); - toFrameTime = AnimTime( totime ); - if ( toFrameTime < fromFrameTime ) { - toFrameTime += anim->Length(); - } - - md5anim = anim->MD5Anim( 0 ); - md5anim->ConvertTimeToFrame( fromFrameTime, cycle, frame1 ); - md5anim->ConvertTimeToFrame( toFrameTime, cycle, frame2 ); - - if ( fromFrameTime <= 0 ) { - // make sure first frame is called - anim->CallFrameCommands( ent, -1, frame2.frame1 ); - } else { - anim->CallFrameCommands( ent, frame1.frame1, frame2.frame1 ); - } -} - -/* -===================== -idAnimBlend::BlendAnim -===================== -*/ -bool idAnimBlend::BlendAnim( int currentTime, int channel, int numJoints, idJointQuat *blendFrame, float &blendWeight, bool removeOriginOffset, bool overrideBlend, bool printInfo ) const { - int i; - float lerp; - float mixWeight; - const idMD5Anim *md5anim; - idJointQuat *ptr; - frameBlend_t frametime; - idJointQuat *jointFrame; - idJointQuat *mixFrame; - int numAnims; - int time; - - const idAnim *anim = Anim(); - if ( !anim ) { - return false; - } - - float weight = GetWeight( currentTime ); - if ( blendWeight > 0.0f ) { - if ( ( endtime >= 0 ) && ( currentTime >= endtime ) ) { - return false; - } - if ( !weight ) { - return false; - } - if ( overrideBlend ) { - blendWeight = 1.0f - weight; - } - } - - if ( ( channel == ANIMCHANNEL_ALL ) && !blendWeight ) { - // we don't need a temporary buffer, so just store it directly in the blend frame - jointFrame = blendFrame; - } else { - // allocate a temporary buffer to copy the joints from - jointFrame = ( idJointQuat * )_alloca16( numJoints * sizeof( *jointFrame ) ); - } - - time = AnimTime( currentTime ); - - numAnims = anim->NumAnims(); - if ( numAnims == 1 ) { - md5anim = anim->MD5Anim( 0 ); - if ( frame ) { - md5anim->GetSingleFrame( frame - 1, jointFrame, modelDef->GetChannelJoints( channel ), modelDef->NumJointsOnChannel( channel ) ); - } else { - md5anim->ConvertTimeToFrame( time, cycle, frametime ); - md5anim->GetInterpolatedFrame( frametime, jointFrame, modelDef->GetChannelJoints( channel ), modelDef->NumJointsOnChannel( channel ) ); - } - } else { - // - // need to mix the multipoint anim together first - // - // allocate a temporary buffer to copy the joints to - mixFrame = ( idJointQuat * )_alloca16( numJoints * sizeof( *jointFrame ) ); - - if ( !frame ) { - anim->MD5Anim( 0 )->ConvertTimeToFrame( time, cycle, frametime ); - } - - ptr = jointFrame; - mixWeight = 0.0f; - for( i = 0; i < numAnims; i++ ) { - if ( animWeights[ i ] > 0.0f ) { - mixWeight += animWeights[ i ]; - lerp = animWeights[ i ] / mixWeight; - md5anim = anim->MD5Anim( i ); - if ( frame ) { - md5anim->GetSingleFrame( frame - 1, ptr, modelDef->GetChannelJoints( channel ), modelDef->NumJointsOnChannel( channel ) ); - } else { - md5anim->GetInterpolatedFrame( frametime, ptr, modelDef->GetChannelJoints( channel ), modelDef->NumJointsOnChannel( channel ) ); - } - - // only blend after the first anim is mixed in - if ( ptr != jointFrame ) { - SIMDProcessor->BlendJoints( jointFrame, ptr, lerp, modelDef->GetChannelJoints( channel ), modelDef->NumJointsOnChannel( channel ) ); - } - - ptr = mixFrame; - } - } - - if ( !mixWeight ) { - return false; - } - } - - if ( removeOriginOffset ) { - if ( allowMove ) { -#ifdef VELOCITY_MOVE - jointFrame[ 0 ].t.x = 0.0f; -#else - jointFrame[ 0 ].t.Zero(); -#endif - } - - if ( anim->GetAnimFlags().anim_turn ) { - jointFrame[ 0 ].q.Set( -0.70710677f, 0.0f, 0.0f, 0.70710677f ); - } - } - - if ( !blendWeight ) { - blendWeight = weight; - if ( channel != ANIMCHANNEL_ALL ) { - const int *index = modelDef->GetChannelJoints( channel ); - const int num = modelDef->NumJointsOnChannel( channel ); - for( i = 0; i < num; i++ ) { - int j = index[i]; - blendFrame[j].t = jointFrame[j].t; - blendFrame[j].q = jointFrame[j].q; - } - } - } else { - blendWeight += weight; - lerp = weight / blendWeight; - SIMDProcessor->BlendJoints( blendFrame, jointFrame, lerp, modelDef->GetChannelJoints( channel ), modelDef->NumJointsOnChannel( channel ) ); - } - - if ( printInfo ) { - if ( frame ) { - gameLocal.Printf( " %s: '%s', %d, %.2f%%\n", channelNames[ channel ], anim->FullName(), frame, weight * 100.0f ); - } else { - gameLocal.Printf( " %s: '%s', %.3f, %.2f%%\n", channelNames[ channel ], anim->FullName(), ( float )frametime.frame1 + frametime.backlerp, weight * 100.0f ); - } - } - - return true; -} - -/* -===================== -idAnimBlend::BlendOrigin -===================== -*/ -void idAnimBlend::BlendOrigin( int currentTime, idVec3 &blendPos, float &blendWeight, bool removeOriginOffset ) const { - float lerp; - idVec3 animpos; - idVec3 pos; - int time; - int num; - int i; - - if ( frame || ( ( endtime > 0 ) && ( currentTime > endtime ) ) ) { - return; - } - - const idAnim *anim = Anim(); - if ( !anim ) { - return; - } - - if ( allowMove && removeOriginOffset ) { - return; - } - - float weight = GetWeight( currentTime ); - if ( !weight ) { - return; - } - - time = AnimTime( currentTime ); - - pos.Zero(); - num = anim->NumAnims(); - for( i = 0; i < num; i++ ) { - anim->GetOrigin( animpos, i, time, cycle ); - pos += animpos * animWeights[ i ]; - } - - if ( !blendWeight ) { - blendPos = pos; - blendWeight = weight; - } else { - lerp = weight / ( blendWeight + weight ); - blendPos += lerp * ( pos - blendPos ); - blendWeight += weight; - } -} - -/* -===================== -idAnimBlend::BlendDelta -===================== -*/ -void idAnimBlend::BlendDelta( int fromtime, int totime, idVec3 &blendDelta, float &blendWeight ) const { - idVec3 pos1; - idVec3 pos2; - idVec3 animpos; - idVec3 delta; - int time1; - int time2; - float lerp; - int num; - int i; - - if ( frame || !allowMove || ( ( endtime > 0 ) && ( fromtime > endtime ) ) ) { - return; - } - - const idAnim *anim = Anim(); - if ( !anim ) { - return; - } - - float weight = GetWeight( totime ); - if ( !weight ) { - return; - } - - time1 = AnimTime( fromtime ); - time2 = AnimTime( totime ); - if ( time2 < time1 ) { - time2 += anim->Length(); - } - - num = anim->NumAnims(); - - pos1.Zero(); - pos2.Zero(); - for( i = 0; i < num; i++ ) { - anim->GetOrigin( animpos, i, time1, cycle ); - pos1 += animpos * animWeights[ i ]; - - anim->GetOrigin( animpos, i, time2, cycle ); - pos2 += animpos * animWeights[ i ]; - } - - delta = pos2 - pos1; - if ( !blendWeight ) { - blendDelta = delta; - blendWeight = weight; - } else { - lerp = weight / ( blendWeight + weight ); - blendDelta += lerp * ( delta - blendDelta ); - blendWeight += weight; - } -} - -/* -===================== -idAnimBlend::BlendDeltaRotation -===================== -*/ -void idAnimBlend::BlendDeltaRotation( int fromtime, int totime, idQuat &blendDelta, float &blendWeight ) const { - idQuat q1; - idQuat q2; - idQuat q3; - int time1; - int time2; - float lerp; - float mixWeight; - int num; - int i; - - if ( frame || !allowMove || ( ( endtime > 0 ) && ( fromtime > endtime ) ) ) { - return; - } - - const idAnim *anim = Anim(); - if ( !anim || !anim->GetAnimFlags().anim_turn ) { - return; - } - - float weight = GetWeight( totime ); - if ( !weight ) { - return; - } - - time1 = AnimTime( fromtime ); - time2 = AnimTime( totime ); - if ( time2 < time1 ) { - time2 += anim->Length(); - } - - q1.Set( 0.0f, 0.0f, 0.0f, 1.0f ); - q2.Set( 0.0f, 0.0f, 0.0f, 1.0f ); - - mixWeight = 0.0f; - num = anim->NumAnims(); - for( i = 0; i < num; i++ ) { - if ( animWeights[ i ] > 0.0f ) { - mixWeight += animWeights[ i ]; - if ( animWeights[ i ] == mixWeight ) { - anim->GetOriginRotation( q1, i, time1, cycle ); - anim->GetOriginRotation( q2, i, time2, cycle ); - } else { - lerp = animWeights[ i ] / mixWeight; - anim->GetOriginRotation( q3, i, time1, cycle ); - q1.Slerp( q1, q3, lerp ); - - anim->GetOriginRotation( q3, i, time2, cycle ); - q2.Slerp( q1, q3, lerp ); - } - } - } - - q3 = q1.Inverse() * q2; - if ( !blendWeight ) { - blendDelta = q3; - blendWeight = weight; - } else { - lerp = weight / ( blendWeight + weight ); - blendDelta.Slerp( blendDelta, q3, lerp ); - blendWeight += weight; - } -} - -/* -===================== -idAnimBlend::AddBounds -===================== -*/ -bool idAnimBlend::AddBounds( int currentTime, idBounds &bounds, bool removeOriginOffset ) const { - int i; - int num; - idBounds b; - int time; - idVec3 pos; - bool addorigin; - - if ( ( endtime > 0 ) && ( currentTime > endtime ) ) { - return false; - } - - const idAnim *anim = Anim(); - if ( !anim ) { - return false; - } - - float weight = GetWeight( currentTime ); - if ( !weight ) { - return false; - } - - time = AnimTime( currentTime ); - num = anim->NumAnims(); - - addorigin = !allowMove || !removeOriginOffset; - for( i = 0; i < num; i++ ) { - if ( anim->GetBounds( b, i, time, cycle ) ) { - if ( addorigin ) { - anim->GetOrigin( pos, i, time, cycle ); - b.TranslateSelf( pos ); - } - bounds.AddBounds( b ); - } - } - - return true; -} - -/*********************************************************************** - - idDeclModelDef - -***********************************************************************/ - -/* -===================== -idDeclModelDef::idDeclModelDef -===================== -*/ -idDeclModelDef::idDeclModelDef() { - modelHandle = NULL; - skin = NULL; - offset.Zero(); - for ( int i = 0; i < ANIM_NumAnimChannels; i++ ) { - channelJoints[i].Clear(); - } -} - -/* -===================== -idDeclModelDef::~idDeclModelDef -===================== -*/ -idDeclModelDef::~idDeclModelDef() { - FreeData(); -} - -/* -================= -idDeclModelDef::Size -================= -*/ -size_t idDeclModelDef::Size( void ) const { - return sizeof( idDeclModelDef ); -} - -/* -===================== -idDeclModelDef::CopyDecl -===================== -*/ -void idDeclModelDef::CopyDecl( const idDeclModelDef *decl ) { - int i; - - FreeData(); - - offset = decl->offset; - modelHandle = decl->modelHandle; - skin = decl->skin; - - anims.SetNum( decl->anims.Num() ); - for( i = 0; i < anims.Num(); i++ ) { - anims[ i ] = new idAnim( this, decl->anims[ i ] ); - } - - joints.SetNum( decl->joints.Num() ); - memcpy( joints.Ptr(), decl->joints.Ptr(), decl->joints.Num() * sizeof( joints[0] ) ); - jointParents.SetNum( decl->jointParents.Num() ); - memcpy( jointParents.Ptr(), decl->jointParents.Ptr(), decl->jointParents.Num() * sizeof( jointParents[0] ) ); - for ( i = 0; i < ANIM_NumAnimChannels; i++ ) { - channelJoints[i] = decl->channelJoints[i]; - } -} - -/* -===================== -idDeclModelDef::FreeData -===================== -*/ -void idDeclModelDef::FreeData( void ) { - anims.DeleteContents( true ); - joints.Clear(); - jointParents.Clear(); - modelHandle = NULL; - skin = NULL; - offset.Zero(); - for ( int i = 0; i < ANIM_NumAnimChannels; i++ ) { - channelJoints[i].Clear(); - } -} - -/* -================ -idDeclModelDef::DefaultDefinition -================ -*/ -const char *idDeclModelDef::DefaultDefinition( void ) const { - return "{ }"; -} - -/* -==================== -idDeclModelDef::FindJoint -==================== -*/ -const jointInfo_t *idDeclModelDef::FindJoint( const char *name ) const { - int i; - const idMD5Joint *joint; - - if ( !modelHandle ) { - return NULL; - } - - joint = modelHandle->GetJoints(); - for( i = 0; i < joints.Num(); i++, joint++ ) { - if ( !joint->name.Icmp( name ) ) { - return &joints[ i ]; - } - } - - return NULL; -} - -/* -===================== -idDeclModelDef::ModelHandle -===================== -*/ -idRenderModel *idDeclModelDef::ModelHandle( void ) const { - return ( idRenderModel * )modelHandle; -} - -/* -===================== -idDeclModelDef::GetJointList -===================== -*/ -void idDeclModelDef::GetJointList( const char *jointnames, idList &jointList ) const { - const char *pos; - idStr jointname; - const jointInfo_t *joint; - const jointInfo_t *child; - int i; - int num; - bool getChildren; - bool subtract; - - if ( !modelHandle ) { - return; - } - - jointList.Clear(); - - num = modelHandle->NumJoints(); - - // scan through list of joints and add each to the joint list - pos = jointnames; - while( *pos ) { - // skip over whitespace - while( ( *pos != 0 ) && isspace( *pos ) ) { - pos++; - } - - if ( !*pos ) { - // no more names - break; - } - - // copy joint name - jointname = ""; - - if ( *pos == '-' ) { - subtract = true; - pos++; - } else { - subtract = false; - } - - if ( *pos == '*' ) { - getChildren = true; - pos++; - } else { - getChildren = false; - } - - while( ( *pos != 0 ) && !isspace( *pos ) ) { - jointname += *pos; - pos++; - } - - joint = FindJoint( jointname ); - if ( !joint ) { - gameLocal.Warning( "Unknown joint '%s' in '%s' for model '%s'", jointname.c_str(), jointnames, GetName() ); - continue; - } - - if ( !subtract ) { - jointList.AddUnique( joint->num ); - } else { - jointList.Remove( joint->num ); - } - - if ( getChildren ) { - // include all joint's children - child = joint + 1; - for( i = joint->num + 1; i < num; i++, child++ ) { - // all children of the joint should follow it in the list. - // once we reach a joint without a parent or with a parent - // who is earlier in the list than the specified joint, then - // we've gone through all it's children. - if ( child->parentNum < joint->num ) { - break; - } - - if ( !subtract ) { - jointList.AddUnique( child->num ); - } else { - jointList.Remove( child->num ); - } - } - } - } -} - -/* -===================== -idDeclModelDef::Touch -===================== -*/ -void idDeclModelDef::Touch( void ) const { - if ( modelHandle ) { - renderModelManager->FindModel( modelHandle->Name() ); - } -} - -/* -===================== -idDeclModelDef::GetDefaultSkin -===================== -*/ -const idDeclSkin *idDeclModelDef::GetDefaultSkin( void ) const { - return skin; -} - -/* -===================== -idDeclModelDef::GetDefaultPose -===================== -*/ -const idJointQuat *idDeclModelDef::GetDefaultPose( void ) const { - return modelHandle->GetDefaultPose(); -} - -/* -===================== -idDeclModelDef::SetupJoints -===================== -*/ -void idDeclModelDef::SetupJoints( int *numJoints, idJointMat **jointList, idBounds &frameBounds, bool removeOriginOffset ) const { - int num; - const idJointQuat *pose; - idJointMat *list; - - if ( !modelHandle || modelHandle->IsDefaultModel() ) { - Mem_Free16( (*jointList) ); - (*jointList) = NULL; - frameBounds.Clear(); - return; - } - - // get the number of joints - num = modelHandle->NumJoints(); - - if ( !num ) { - gameLocal.Error( "model '%s' has no joints", modelHandle->Name() ); - } - - // set up initial pose for model (with no pose, model is just a jumbled mess) - list = (idJointMat *) Mem_Alloc16( num * sizeof( list[0] ) ); - pose = GetDefaultPose(); - - // convert the joint quaternions to joint matrices - SIMDProcessor->ConvertJointQuatsToJointMats( list, pose, joints.Num() ); - - // check if we offset the model by the origin joint - if ( removeOriginOffset ) { -#ifdef VELOCITY_MOVE - list[ 0 ].SetTranslation( idVec3( offset.x, offset.y + pose[0].t.y, offset.z + pose[0].t.z ) ); -#else - list[ 0 ].SetTranslation( offset ); -#endif - } else { - list[ 0 ].SetTranslation( pose[0].t + offset ); - } - - // transform the joint hierarchy - SIMDProcessor->TransformJoints( list, jointParents.Ptr(), 1, joints.Num() - 1 ); - - *numJoints = num; - *jointList = list; - - // get the bounds of the default pose - frameBounds = modelHandle->Bounds( NULL ); -} - -/* -===================== -idDeclModelDef::ParseAnim -===================== -*/ -bool idDeclModelDef::ParseAnim( idLexer &src, int numDefaultAnims ) { - int i; - int len; - idAnim *anim; - const idMD5Anim *md5anims[ ANIM_MaxSyncedAnims ]; - const idMD5Anim *md5anim; - idStr alias; - idToken realname; - idToken token; - int numAnims; - animFlags_t flags; - - numAnims = 0; - memset( md5anims, 0, sizeof( md5anims ) ); - - if( !src.ReadToken( &realname ) ) { - src.Warning( "Unexpected end of file" ); - MakeDefault(); - return false; - } - alias = realname; - - for( i = 0; i < anims.Num(); i++ ) { - if ( !strcmp( anims[ i ]->FullName(), realname ) ) { - break; - } - } - - if ( ( i < anims.Num() ) && ( i >= numDefaultAnims ) ) { - src.Warning( "Duplicate anim '%s'", realname.c_str() ); - MakeDefault(); - return false; - } - - if ( i < numDefaultAnims ) { - anim = anims[ i ]; - } else { - // create the alias associated with this animation - anim = new idAnim(); - anims.Append( anim ); - } - - // random anims end with a number. find the numeric suffix of the animation. - len = alias.Length(); - for( i = len - 1; i > 0; i-- ) { - if ( !isdigit( alias[ i ] ) ) { - break; - } - } - - // check for zero length name, or a purely numeric name - if ( i <= 0 ) { - src.Warning( "Invalid animation name '%s'", alias.c_str() ); - MakeDefault(); - return false; - } - - // remove the numeric suffix - alias.CapLength( i + 1 ); - - // parse the anims from the string - do { - if( !src.ReadToken( &token ) ) { - src.Warning( "Unexpected end of file" ); - MakeDefault(); - return false; - } - - // lookup the animation - md5anim = animationLib.GetAnim( token ); - if ( !md5anim ) { - src.Warning( "Couldn't load anim '%s'", token.c_str() ); - MakeDefault(); - return false; - } - - md5anim->CheckModelHierarchy( modelHandle ); - - if ( numAnims > 0 ) { - // make sure it's the same length as the other anims - if ( md5anim->Length() != md5anims[ 0 ]->Length() ) { - src.Warning( "Anim '%s' does not match length of anim '%s'", md5anim->Name(), md5anims[ 0 ]->Name() ); - MakeDefault(); - return false; - } - } - - if ( numAnims >= ANIM_MaxSyncedAnims ) { - src.Warning( "Exceeded max synced anims (%d)", ANIM_MaxSyncedAnims ); - MakeDefault(); - return false; - } - - // add it to our list - md5anims[ numAnims ] = md5anim; - numAnims++; - } while ( src.CheckTokenString( "," ) ); - - if ( !numAnims ) { - src.Warning( "No animation specified" ); - MakeDefault(); - return false; - } - - anim->SetAnim( this, realname, alias, numAnims, md5anims ); - memset( &flags, 0, sizeof( flags ) ); - - // parse any frame commands or animflags - if ( src.CheckTokenString( "{" ) ) { - while( 1 ) { - if( !src.ReadToken( &token ) ) { - src.Warning( "Unexpected end of file" ); - MakeDefault(); - return false; - } - if ( token == "}" ) { - break; - }else if ( token == "prevent_idle_override" ) { - flags.prevent_idle_override = true; - } else if ( token == "random_cycle_start" ) { - flags.random_cycle_start = true; - } else if ( token == "ai_no_turn" ) { - flags.ai_no_turn = true; - } else if ( token == "anim_turn" ) { - flags.anim_turn = true; - } else if ( token == "frame" ) { - // create a frame command - int framenum; - const char *err; - - // make sure we don't have any line breaks while reading the frame command so the error line # will be correct - if ( !src.ReadTokenOnLine( &token ) ) { - src.Warning( "Missing frame # after 'frame'" ); - MakeDefault(); - return false; - } - if ( token.type == TT_PUNCTUATION && token == "-" ) { - src.Warning( "Invalid frame # after 'frame'" ); - MakeDefault(); - return false; - } else if ( token.type != TT_NUMBER || token.subtype == TT_FLOAT ) { - src.Error( "expected integer value, found '%s'", token.c_str() ); - } - - // get the frame number - framenum = token.GetIntValue(); - - // put the command on the specified frame of the animation - err = anim->AddFrameCommand( this, framenum, src, NULL ); - if ( err ) { - src.Warning( "%s", err ); - MakeDefault(); - return false; - } - } else { - src.Warning( "Unknown command '%s'", token.c_str() ); - MakeDefault(); - return false; - } - } - } - - // set the flags - anim->SetAnimFlags( flags ); - return true; -} - -/* -================ -idDeclModelDef::Parse -================ -*/ -bool idDeclModelDef::Parse( const char *text, const int textLength ) { - int i; - int num; - idStr filename; - idStr extension; - const idMD5Joint *md5joint; - const idMD5Joint *md5joints; - idLexer src; - idToken token; - idToken token2; - idStr jointnames; - int channel; - jointHandle_t jointnum; - idList jointList; - int numDefaultAnims; - - src.LoadMemory( text, textLength, GetFileName(), GetLineNum() ); - src.SetFlags( DECL_LEXER_FLAGS ); - src.SkipUntilString( "{" ); - - numDefaultAnims = 0; - while( 1 ) { - if ( !src.ReadToken( &token ) ) { - break; - } - - if ( !token.Icmp( "}" ) ) { - break; - } - - if ( token == "inherit" ) { - if( !src.ReadToken( &token2 ) ) { - src.Warning( "Unexpected end of file" ); - MakeDefault(); - return false; - } - - const idDeclModelDef *copy = static_cast( declManager->FindType( DECL_MODELDEF, token2, false ) ); - if ( !copy ) { - common->Warning( "Unknown model definition '%s'", token2.c_str() ); - } else if ( copy->GetState() == DS_DEFAULTED ) { - common->Warning( "inherited model definition '%s' defaulted", token2.c_str() ); - MakeDefault(); - return false; - } else { - CopyDecl( copy ); - numDefaultAnims = anims.Num(); - } - } else if ( token == "skin" ) { - if( !src.ReadToken( &token2 ) ) { - src.Warning( "Unexpected end of file" ); - MakeDefault(); - return false; - } - skin = declManager->FindSkin( token2 ); - if ( !skin ) { - src.Warning( "Skin '%s' not found", token2.c_str() ); - MakeDefault(); - return false; - } - } else if ( token == "mesh" ) { - if( !src.ReadToken( &token2 ) ) { - src.Warning( "Unexpected end of file" ); - MakeDefault(); - return false; - } - filename = token2; - filename.ExtractFileExtension( extension ); - if ( extension != MD5_MESH_EXT ) { - src.Warning( "Invalid model for MD5 mesh" ); - MakeDefault(); - return false; - } - modelHandle = renderModelManager->FindModel( filename ); - if ( !modelHandle ) { - src.Warning( "Model '%s' not found", filename.c_str() ); - MakeDefault(); - return false; - } - - if ( modelHandle->IsDefaultModel() ) { - src.Warning( "Model '%s' defaulted", filename.c_str() ); - MakeDefault(); - return false; - } - - // get the number of joints - num = modelHandle->NumJoints(); - if ( !num ) { - src.Warning( "Model '%s' has no joints", filename.c_str() ); - } - - // set up the joint hierarchy - joints.SetGranularity( 1 ); - joints.SetNum( num ); - jointParents.SetNum( num ); - channelJoints[0].SetNum( num ); - md5joints = modelHandle->GetJoints(); - md5joint = md5joints; - for( i = 0; i < num; i++, md5joint++ ) { - joints[i].channel = ANIMCHANNEL_ALL; - joints[i].num = static_cast( i ); - if ( md5joint->parent ) { - joints[i].parentNum = static_cast( md5joint->parent - md5joints ); - } else { - joints[i].parentNum = INVALID_JOINT; - } - jointParents[i] = joints[i].parentNum; - channelJoints[0][i] = i; - } - } else if ( token == "remove" ) { - // removes any anims whos name matches - if( !src.ReadToken( &token2 ) ) { - src.Warning( "Unexpected end of file" ); - MakeDefault(); - return false; - } - num = 0; - for( i = 0; i < anims.Num(); i++ ) { - if ( ( token2 == anims[ i ]->Name() ) || ( token2 == anims[ i ]->FullName() ) ) { - delete anims[ i ]; - anims.RemoveIndex( i ); - if ( i >= numDefaultAnims ) { - src.Warning( "Anim '%s' was not inherited. Anim should be removed from the model def.", token2.c_str() ); - MakeDefault(); - return false; - } - i--; - numDefaultAnims--; - num++; - continue; - } - } - if ( !num ) { - src.Warning( "Couldn't find anim '%s' to remove", token2.c_str() ); - MakeDefault(); - return false; - } - } else if ( token == "anim" ) { - if ( !modelHandle ) { - src.Warning( "Must specify mesh before defining anims" ); - MakeDefault(); - return false; - } - if ( !ParseAnim( src, numDefaultAnims ) ) { - MakeDefault(); - return false; - } - } else if ( token == "offset" ) { - if ( !src.Parse1DMatrix( 3, offset.ToFloatPtr() ) ) { - src.Warning( "Expected vector following 'offset'" ); - MakeDefault(); - return false; - } - } else if ( token == "channel" ) { - if ( !modelHandle ) { - src.Warning( "Must specify mesh before defining channels" ); - MakeDefault(); - return false; - } - - // set the channel for a group of joints - if( !src.ReadToken( &token2 ) ) { - src.Warning( "Unexpected end of file" ); - MakeDefault(); - return false; - } - if ( !src.CheckTokenString( "(" ) ) { - src.Warning( "Expected { after '%s'\n", token2.c_str() ); - MakeDefault(); - return false; - } - - for( i = ANIMCHANNEL_ALL + 1; i < ANIM_NumAnimChannels; i++ ) { - if ( !idStr::Icmp( channelNames[ i ], token2 ) ) { - break; - } - } - - if ( i >= ANIM_NumAnimChannels ) { - src.Warning( "Unknown channel '%s'", token2.c_str() ); - MakeDefault(); - return false; - } - - channel = i; - jointnames = ""; - - while( !src.CheckTokenString( ")" ) ) { - if( !src.ReadToken( &token2 ) ) { - src.Warning( "Unexpected end of file" ); - MakeDefault(); - return false; - } - jointnames += token2; - if ( ( token2 != "*" ) && ( token2 != "-" ) ) { - jointnames += " "; - } - } - - GetJointList( jointnames, jointList ); - - channelJoints[ channel ].SetNum( jointList.Num() ); - for( num = i = 0; i < jointList.Num(); i++ ) { - jointnum = jointList[ i ]; - if ( joints[ jointnum ].channel != ANIMCHANNEL_ALL ) { - src.Warning( "Joint '%s' assigned to multiple channels", modelHandle->GetJointName( jointnum ) ); - continue; - } - joints[ jointnum ].channel = channel; - channelJoints[ channel ][ num++ ] = jointnum; - } - channelJoints[ channel ].SetNum( num ); - } else { - src.Warning( "unknown token '%s'", token.c_str() ); - MakeDefault(); - return false; - } - } - - // shrink the anim list down to save space - anims.SetGranularity( 1 ); - anims.SetNum( anims.Num() ); - - return true; -} - -/* -===================== -idDeclModelDef::HasAnim -===================== -*/ -bool idDeclModelDef::HasAnim( const char *name ) const { - int i; - - // find any animations with same name - for( i = 0; i < anims.Num(); i++ ) { - if ( !strcmp( anims[ i ]->Name(), name ) ) { - return true; - } - } - - return false; -} - -/* -===================== -idDeclModelDef::NumAnims -===================== -*/ -int idDeclModelDef::NumAnims( void ) const { - return anims.Num() + 1; -} - -/* -===================== -idDeclModelDef::GetSpecificAnim - -Gets the exact anim for the name, without randomization. -===================== -*/ -int idDeclModelDef::GetSpecificAnim( const char *name ) const { - int i; - - // find a specific animation - for( i = 0; i < anims.Num(); i++ ) { - if ( !strcmp( anims[ i ]->FullName(), name ) ) { - return i + 1; - } - } - - // didn't find it - return 0; -} - -/* -===================== -idDeclModelDef::GetAnim -===================== -*/ -const idAnim *idDeclModelDef::GetAnim( int index ) const { - if ( ( index < 1 ) || ( index > anims.Num() ) ) { - return NULL; - } - - return anims[ index - 1 ]; -} - -/* -===================== -idDeclModelDef::GetAnim -===================== -*/ -int idDeclModelDef::GetAnim( const char *name ) const { - int i; - int which; - const int MAX_ANIMS = 64; - int animList[ MAX_ANIMS ]; - int numAnims; - int len; - - len = strlen( name ); - if ( len && idStr::CharIsNumeric( name[ len - 1 ] ) ) { - // find a specific animation - return GetSpecificAnim( name ); - } - - // find all animations with same name - numAnims = 0; - for( i = 0; i < anims.Num(); i++ ) { - if ( !strcmp( anims[ i ]->Name(), name ) ) { - animList[ numAnims++ ] = i; - if ( numAnims >= MAX_ANIMS ) { - break; - } - } - } - - if ( !numAnims ) { - return 0; - } - - // get a random anim - //FIXME: don't access gameLocal here? - which = gameLocal.random.RandomInt( numAnims ); - return animList[ which ] + 1; -} - -/* -===================== -idDeclModelDef::GetSkin -===================== -*/ -const idDeclSkin *idDeclModelDef::GetSkin( void ) const { - return skin; -} - -/* -===================== -idDeclModelDef::GetModelName -===================== -*/ -const char *idDeclModelDef::GetModelName( void ) const { - if ( modelHandle ) { - return modelHandle->Name(); - } else { - return ""; - } -} - -/* -===================== -idDeclModelDef::Joints -===================== -*/ -const idList &idDeclModelDef::Joints( void ) const { - return joints; -} - -/* -===================== -idDeclModelDef::JointParents -===================== -*/ -const int * idDeclModelDef::JointParents( void ) const { - return jointParents.Ptr(); -} - -/* -===================== -idDeclModelDef::NumJoints -===================== -*/ -int idDeclModelDef::NumJoints( void ) const { - return joints.Num(); -} - -/* -===================== -idDeclModelDef::GetJoint -===================== -*/ -const jointInfo_t *idDeclModelDef::GetJoint( int jointHandle ) const { - if ( ( jointHandle < 0 ) || ( jointHandle > joints.Num() ) ) { - gameLocal.Error( "idDeclModelDef::GetJoint : joint handle out of range" ); - } - return &joints[ jointHandle ]; -} - -/* -==================== -idDeclModelDef::GetJointName -==================== -*/ -const char *idDeclModelDef::GetJointName( int jointHandle ) const { - const idMD5Joint *joint; - - if ( !modelHandle ) { - return NULL; - } - - if ( ( jointHandle < 0 ) || ( jointHandle > joints.Num() ) ) { - gameLocal.Error( "idDeclModelDef::GetJointName : joint handle out of range" ); - } - - joint = modelHandle->GetJoints(); - return joint[ jointHandle ].name.c_str(); -} - -/* -===================== -idDeclModelDef::NumJointsOnChannel -===================== -*/ -int idDeclModelDef::NumJointsOnChannel( int channel ) const { - if ( ( channel < 0 ) || ( channel >= ANIM_NumAnimChannels ) ) { - gameLocal.Error( "idDeclModelDef::NumJointsOnChannel : channel out of range" ); - } - return channelJoints[ channel ].Num(); -} - -/* -===================== -idDeclModelDef::GetChannelJoints -===================== -*/ -const int * idDeclModelDef::GetChannelJoints( int channel ) const { - if ( ( channel < 0 ) || ( channel >= ANIM_NumAnimChannels ) ) { - gameLocal.Error( "idDeclModelDef::GetChannelJoints : channel out of range" ); - } - return channelJoints[ channel ].Ptr(); -} - -/* -===================== -idDeclModelDef::GetVisualOffset -===================== -*/ -const idVec3 &idDeclModelDef::GetVisualOffset( void ) const { - return offset; -} - -/*********************************************************************** - - idAnimator - -***********************************************************************/ - -/* -===================== -idAnimator::idAnimator -===================== -*/ -idAnimator::idAnimator() { - int i, j; - - modelDef = NULL; - entity = NULL; - numJoints = 0; - joints = NULL; - lastTransformTime = -1; - stoppedAnimatingUpdate = false; - removeOriginOffset = false; - forceUpdate = false; - - frameBounds.Clear(); - - AFPoseJoints.SetGranularity( 1 ); - AFPoseJointMods.SetGranularity( 1 ); - AFPoseJointFrame.SetGranularity( 1 ); - - ClearAFPose(); - - for( i = ANIMCHANNEL_ALL; i < ANIM_NumAnimChannels; i++ ) { - for( j = 0; j < ANIM_MaxAnimsPerChannel; j++ ) { - channels[ i ][ j ].Reset( NULL ); - } - } -} - -/* -===================== -idAnimator::~idAnimator -===================== -*/ -idAnimator::~idAnimator() { - FreeData(); -} - -/* -===================== -idAnimator::Allocated -===================== -*/ -size_t idAnimator::Allocated( void ) const { - size_t size; - - size = jointMods.Allocated() + numJoints * sizeof( joints[0] ) + jointMods.Num() * sizeof( jointMods[ 0 ] ) + AFPoseJointMods.Allocated() + AFPoseJointFrame.Allocated() + AFPoseJoints.Allocated(); - - return size; -} - -/* -===================== -idAnimator::Save - -archives object for save game file -===================== -*/ -void idAnimator::Save( idSaveGame *savefile ) const { - int i; - int j; - - savefile->WriteModelDef( modelDef ); - savefile->WriteObject( entity ); - - savefile->WriteInt( jointMods.Num() ); - for( i = 0; i < jointMods.Num(); i++ ) { - savefile->WriteInt( jointMods[ i ]->jointnum ); - savefile->WriteMat3( jointMods[ i ]->mat ); - savefile->WriteVec3( jointMods[ i ]->pos ); - savefile->WriteInt( (int&)jointMods[ i ]->transform_pos ); - savefile->WriteInt( (int&)jointMods[ i ]->transform_axis ); - } - - savefile->WriteInt( numJoints ); - for ( i = 0; i < numJoints; i++ ) { - float *data = joints[i].ToFloatPtr(); - for ( j = 0; j < 12; j++ ) { - savefile->WriteFloat( data[j] ); - } - } - - savefile->WriteInt( lastTransformTime ); - savefile->WriteBool( stoppedAnimatingUpdate ); - savefile->WriteBool( forceUpdate ); - savefile->WriteBounds( frameBounds ); - - savefile->WriteFloat( AFPoseBlendWeight ); - - savefile->WriteInt( AFPoseJoints.Num() ); - for ( i = 0; i < AFPoseJoints.Num(); i++ ) { - savefile->WriteInt( AFPoseJoints[i] ); - } - - savefile->WriteInt( AFPoseJointMods.Num() ); - for ( i = 0; i < AFPoseJointMods.Num(); i++ ) { - savefile->WriteInt( (int&)AFPoseJointMods[i].mod ); - savefile->WriteMat3( AFPoseJointMods[i].axis ); - savefile->WriteVec3( AFPoseJointMods[i].origin ); - } - - savefile->WriteInt( AFPoseJointFrame.Num() ); - for ( i = 0; i < AFPoseJointFrame.Num(); i++ ) { - savefile->WriteFloat( AFPoseJointFrame[i].q.x ); - savefile->WriteFloat( AFPoseJointFrame[i].q.y ); - savefile->WriteFloat( AFPoseJointFrame[i].q.z ); - savefile->WriteFloat( AFPoseJointFrame[i].q.w ); - savefile->WriteVec3( AFPoseJointFrame[i].t ); - } - - savefile->WriteBounds( AFPoseBounds ); - savefile->WriteInt( AFPoseTime ); - - savefile->WriteBool( removeOriginOffset ); - - for( i = ANIMCHANNEL_ALL; i < ANIM_NumAnimChannels; i++ ) { - for( j = 0; j < ANIM_MaxAnimsPerChannel; j++ ) { - channels[ i ][ j ].Save( savefile ); - } - } -} - -/* -===================== -idAnimator::Restore - -unarchives object from save game file -===================== -*/ -void idAnimator::Restore( idRestoreGame *savefile ) { - int i; - int j; - int num; - - savefile->ReadModelDef( modelDef ); - savefile->ReadObject( reinterpret_cast( entity ) ); - - savefile->ReadInt( num ); - jointMods.SetNum( num ); - for( i = 0; i < num; i++ ) { - jointMods[ i ] = new jointMod_t; - savefile->ReadInt( (int&)jointMods[ i ]->jointnum ); - savefile->ReadMat3( jointMods[ i ]->mat ); - savefile->ReadVec3( jointMods[ i ]->pos ); - savefile->ReadInt( (int&)jointMods[ i ]->transform_pos ); - savefile->ReadInt( (int&)jointMods[ i ]->transform_axis ); - } - - savefile->ReadInt( numJoints ); - joints = (idJointMat *) Mem_Alloc16( numJoints * sizeof( joints[0] ) ); - for ( i = 0; i < numJoints; i++ ) { - float *data = joints[i].ToFloatPtr(); - for ( j = 0; j < 12; j++ ) { - savefile->ReadFloat( data[j] ); - } - } - - savefile->ReadInt( lastTransformTime ); - savefile->ReadBool( stoppedAnimatingUpdate ); - savefile->ReadBool( forceUpdate ); - savefile->ReadBounds( frameBounds ); - - savefile->ReadFloat( AFPoseBlendWeight ); - - savefile->ReadInt( num ); - AFPoseJoints.SetGranularity( 1 ); - AFPoseJoints.SetNum( num ); - for ( i = 0; i < AFPoseJoints.Num(); i++ ) { - savefile->ReadInt( AFPoseJoints[i] ); - } - - savefile->ReadInt( num ); - AFPoseJointMods.SetGranularity( 1 ); - AFPoseJointMods.SetNum( num ); - for ( i = 0; i < AFPoseJointMods.Num(); i++ ) { - savefile->ReadInt( (int&)AFPoseJointMods[i].mod ); - savefile->ReadMat3( AFPoseJointMods[i].axis ); - savefile->ReadVec3( AFPoseJointMods[i].origin ); - } - - savefile->ReadInt( num ); - AFPoseJointFrame.SetGranularity( 1 ); - AFPoseJointFrame.SetNum( num ); - for ( i = 0; i < AFPoseJointFrame.Num(); i++ ) { - savefile->ReadFloat( AFPoseJointFrame[i].q.x ); - savefile->ReadFloat( AFPoseJointFrame[i].q.y ); - savefile->ReadFloat( AFPoseJointFrame[i].q.z ); - savefile->ReadFloat( AFPoseJointFrame[i].q.w ); - savefile->ReadVec3( AFPoseJointFrame[i].t ); - } - - savefile->ReadBounds( AFPoseBounds ); - savefile->ReadInt( AFPoseTime ); - - savefile->ReadBool( removeOriginOffset ); - - for( i = ANIMCHANNEL_ALL; i < ANIM_NumAnimChannels; i++ ) { - for( j = 0; j < ANIM_MaxAnimsPerChannel; j++ ) { - channels[ i ][ j ].Restore( savefile, modelDef ); - } - } -} - -/* -===================== -idAnimator::FreeData -===================== -*/ -void idAnimator::FreeData( void ) { - int i, j; - - if ( entity ) { - entity->BecomeInactive( TH_ANIMATE ); - } - - for( i = ANIMCHANNEL_ALL; i < ANIM_NumAnimChannels; i++ ) { - for( j = 0; j < ANIM_MaxAnimsPerChannel; j++ ) { - channels[ i ][ j ].Reset( NULL ); - } - } - - jointMods.DeleteContents( true ); - - Mem_Free16( joints ); - joints = NULL; - numJoints = 0; - - modelDef = NULL; - - ForceUpdate(); -} - -/* -===================== -idAnimator::PushAnims -===================== -*/ -void idAnimator::PushAnims( int channelNum, int currentTime, int blendTime ) { - int i; - idAnimBlend *channel; - - channel = channels[ channelNum ]; - if ( !channel[ 0 ].GetWeight( currentTime ) || ( channel[ 0 ].starttime == currentTime ) ) { - return; - } - - for( i = ANIM_MaxAnimsPerChannel - 1; i > 0; i-- ) { - channel[ i ] = channel[ i - 1 ]; - } - - channel[ 0 ].Reset( modelDef ); - channel[ 1 ].Clear( currentTime, blendTime ); - ForceUpdate(); -} - -/* -===================== -idAnimator::SetModel -===================== -*/ -idRenderModel *idAnimator::SetModel( const char *modelname ) { - int i, j; - - FreeData(); - - // check if we're just clearing the model - if ( !modelname || !*modelname ) { - return NULL; - } - - modelDef = static_cast( declManager->FindType( DECL_MODELDEF, modelname, false ) ); - if ( !modelDef ) { - return NULL; - } - - idRenderModel *renderModel = modelDef->ModelHandle(); - if ( !renderModel ) { - modelDef = NULL; - return NULL; - } - - // make sure model hasn't been purged - modelDef->Touch(); - - modelDef->SetupJoints( &numJoints, &joints, frameBounds, removeOriginOffset ); - modelDef->ModelHandle()->Reset(); - - // set the modelDef on all channels - for( i = ANIMCHANNEL_ALL; i < ANIM_NumAnimChannels; i++ ) { - for( j = 0; j < ANIM_MaxAnimsPerChannel; j++ ) { - channels[ i ][ j ].Reset( modelDef ); - } - } - - return modelDef->ModelHandle(); -} - -/* -===================== -idAnimator::Size -===================== -*/ -size_t idAnimator::Size( void ) const { - return sizeof( *this ) + Allocated(); -} - -/* -===================== -idAnimator::SetEntity -===================== -*/ -void idAnimator::SetEntity( idEntity *ent ) { - entity = ent; -} - -/* -===================== -idAnimator::GetEntity -===================== -*/ -idEntity *idAnimator::GetEntity( void ) const { - return entity; -} - -/* -===================== -idAnimator::RemoveOriginOffset -===================== -*/ -void idAnimator::RemoveOriginOffset( bool remove ) { - removeOriginOffset = remove; -} - -/* -===================== -idAnimator::RemoveOrigin -===================== -*/ -bool idAnimator::RemoveOrigin( void ) const { - return removeOriginOffset; -} - -/* -===================== -idAnimator::GetJointList -===================== -*/ -void idAnimator::GetJointList( const char *jointnames, idList &jointList ) const { - if ( modelDef ) { - modelDef->GetJointList( jointnames, jointList ); - } -} - -/* -===================== -idAnimator::NumAnims -===================== -*/ -int idAnimator::NumAnims( void ) const { - if ( !modelDef ) { - return 0; - } - - return modelDef->NumAnims(); -} - -/* -===================== -idAnimator::GetAnim -===================== -*/ -const idAnim *idAnimator::GetAnim( int index ) const { - if ( !modelDef ) { - return NULL; - } - - return modelDef->GetAnim( index ); -} - -/* -===================== -idAnimator::GetAnim -===================== -*/ -int idAnimator::GetAnim( const char *name ) const { - if ( !modelDef ) { - return 0; - } - - return modelDef->GetAnim( name ); -} - -/* -===================== -idAnimator::HasAnim -===================== -*/ -bool idAnimator::HasAnim( const char *name ) const { - if ( !modelDef ) { - return false; - } - - return modelDef->HasAnim( name ); -} - -/* -===================== -idAnimator::NumJoints -===================== -*/ -int idAnimator::NumJoints( void ) const { - return numJoints; -} - -/* -===================== -idAnimator::ModelHandle -===================== -*/ -idRenderModel *idAnimator::ModelHandle( void ) const { - if ( !modelDef ) { - return NULL; - } - - return modelDef->ModelHandle(); -} - -/* -===================== -idAnimator::ModelDef -===================== -*/ -const idDeclModelDef *idAnimator::ModelDef( void ) const { - return modelDef; -} - -/* -===================== -idAnimator::CurrentAnim -===================== -*/ -idAnimBlend *idAnimator::CurrentAnim( int channelNum ) { - if ( ( channelNum < 0 ) || ( channelNum >= ANIM_NumAnimChannels ) ) { - gameLocal.Error( "idAnimator::CurrentAnim : channel out of range" ); - } - - return &channels[ channelNum ][ 0 ]; -} - -/* -===================== -idAnimator::Clear -===================== -*/ -void idAnimator::Clear( int channelNum, int currentTime, int cleartime ) { - int i; - idAnimBlend *blend; - - if ( ( channelNum < 0 ) || ( channelNum >= ANIM_NumAnimChannels ) ) { - gameLocal.Error( "idAnimator::Clear : channel out of range" ); - } - - blend = channels[ channelNum ]; - for( i = 0; i < ANIM_MaxAnimsPerChannel; i++, blend++ ) { - blend->Clear( currentTime, cleartime ); - } - ForceUpdate(); -} - -/* -===================== -idAnimator::SetFrame -===================== -*/ -void idAnimator::SetFrame( int channelNum, int animNum, int frame, int currentTime, int blendTime ) { - if ( ( channelNum < 0 ) || ( channelNum >= ANIM_NumAnimChannels ) ) { - gameLocal.Error( "idAnimator::SetFrame : channel out of range" ); - } - - if ( !modelDef || !modelDef->GetAnim( animNum ) ) { - return; - } - - PushAnims( channelNum, currentTime, blendTime ); - channels[ channelNum ][ 0 ].SetFrame( modelDef, animNum, frame, currentTime, blendTime ); - if ( entity ) { - entity->BecomeActive( TH_ANIMATE ); - } -} - -/* -===================== -idAnimator::CycleAnim -===================== -*/ -void idAnimator::CycleAnim( int channelNum, int animNum, int currentTime, int blendTime ) { - if ( ( channelNum < 0 ) || ( channelNum >= ANIM_NumAnimChannels ) ) { - gameLocal.Error( "idAnimator::CycleAnim : channel out of range" ); - } - - if ( !modelDef || !modelDef->GetAnim( animNum ) ) { - return; - } - - PushAnims( channelNum, currentTime, blendTime ); - channels[ channelNum ][ 0 ].CycleAnim( modelDef, animNum, currentTime, blendTime ); - if ( entity ) { - entity->BecomeActive( TH_ANIMATE ); - } -} - -/* -===================== -idAnimator::PlayAnim -===================== -*/ -void idAnimator::PlayAnim( int channelNum, int animNum, int currentTime, int blendTime ) { - if ( ( channelNum < 0 ) || ( channelNum >= ANIM_NumAnimChannels ) ) { - gameLocal.Error( "idAnimator::PlayAnim : channel out of range" ); - } - - if ( !modelDef || !modelDef->GetAnim( animNum ) ) { - return; - } - - PushAnims( channelNum, currentTime, blendTime ); - channels[ channelNum ][ 0 ].PlayAnim( modelDef, animNum, currentTime, blendTime ); - if ( entity ) { - entity->BecomeActive( TH_ANIMATE ); - } -} - -/* -===================== -idAnimator::SyncAnimChannels -===================== -*/ -void idAnimator::SyncAnimChannels( int channelNum, int fromChannelNum, int currentTime, int blendTime ) { - if ( ( channelNum < 0 ) || ( channelNum >= ANIM_NumAnimChannels ) || ( fromChannelNum < 0 ) || ( fromChannelNum >= ANIM_NumAnimChannels ) ) { - gameLocal.Error( "idAnimator::SyncToChannel : channel out of range" ); - } - - idAnimBlend &fromBlend = channels[ fromChannelNum ][ 0 ]; - idAnimBlend &toBlend = channels[ channelNum ][ 0 ]; - - float weight = fromBlend.blendEndValue; - if ( ( fromBlend.Anim() != toBlend.Anim() ) || ( fromBlend.GetStartTime() != toBlend.GetStartTime() ) || ( fromBlend.GetEndTime() != toBlend.GetEndTime() ) ) { - PushAnims( channelNum, currentTime, blendTime ); - toBlend = fromBlend; - toBlend.blendStartValue = 0.0f; - toBlend.blendEndValue = 0.0f; - } - toBlend.SetWeight( weight, currentTime - 1, blendTime ); - - // disable framecommands on the current channel so that commands aren't called twice - toBlend.AllowFrameCommands( false ); - - if ( entity ) { - entity->BecomeActive( TH_ANIMATE ); - } -} - -/* -===================== -idAnimator::SetJointPos -===================== -*/ -void idAnimator::SetJointPos( jointHandle_t jointnum, jointModTransform_t transform_type, const idVec3 &pos ) { - int i; - jointMod_t *jointMod; - - if ( !modelDef || !modelDef->ModelHandle() || ( jointnum < 0 ) || ( jointnum >= numJoints ) ) { - return; - } - - jointMod = NULL; - for( i = 0; i < jointMods.Num(); i++ ) { - if ( jointMods[ i ]->jointnum == jointnum ) { - jointMod = jointMods[ i ]; - break; - } else if ( jointMods[ i ]->jointnum > jointnum ) { - break; - } - } - - if ( !jointMod ) { - jointMod = new jointMod_t; - jointMod->jointnum = jointnum; - jointMod->mat.Identity(); - jointMod->transform_axis = JOINTMOD_NONE; - jointMods.Insert( jointMod, i ); - } - - jointMod->pos = pos; - jointMod->transform_pos = transform_type; - - if ( entity ) { - entity->BecomeActive( TH_ANIMATE ); - } - ForceUpdate(); -} - -/* -===================== -idAnimator::SetJointAxis -===================== -*/ -void idAnimator::SetJointAxis( jointHandle_t jointnum, jointModTransform_t transform_type, const idMat3 &mat ) { - int i; - jointMod_t *jointMod; - - if ( !modelDef || !modelDef->ModelHandle() || ( jointnum < 0 ) || ( jointnum >= numJoints ) ) { - return; - } - - jointMod = NULL; - for( i = 0; i < jointMods.Num(); i++ ) { - if ( jointMods[ i ]->jointnum == jointnum ) { - jointMod = jointMods[ i ]; - break; - } else if ( jointMods[ i ]->jointnum > jointnum ) { - break; - } - } - - if ( !jointMod ) { - jointMod = new jointMod_t; - jointMod->jointnum = jointnum; - jointMod->pos.Zero(); - jointMod->transform_pos = JOINTMOD_NONE; - jointMods.Insert( jointMod, i ); - } - - jointMod->mat = mat; - jointMod->transform_axis = transform_type; - - if ( entity ) { - entity->BecomeActive( TH_ANIMATE ); - } - ForceUpdate(); -} - -/* -===================== -idAnimator::ClearJoint -===================== -*/ -void idAnimator::ClearJoint( jointHandle_t jointnum ) { - int i; - - if ( !modelDef || !modelDef->ModelHandle() || ( jointnum < 0 ) || ( jointnum >= numJoints ) ) { - return; - } - - for( i = 0; i < jointMods.Num(); i++ ) { - if ( jointMods[ i ]->jointnum == jointnum ) { - delete jointMods[ i ]; - jointMods.RemoveIndex( i ); - ForceUpdate(); - break; - } else if ( jointMods[ i ]->jointnum > jointnum ) { - break; - } - } -} - -/* -===================== -idAnimator::ClearAllJoints -===================== -*/ -void idAnimator::ClearAllJoints( void ) { - if ( jointMods.Num() ) { - ForceUpdate(); - } - jointMods.DeleteContents( true ); -} - -/* -===================== -idAnimator::ClearAllAnims -===================== -*/ -void idAnimator::ClearAllAnims( int currentTime, int cleartime ) { - int i; - - for( i = 0; i < ANIM_NumAnimChannels; i++ ) { - Clear( i, currentTime, cleartime ); - } - - ClearAFPose(); - ForceUpdate(); -} - -/* -==================== -idAnimator::GetDelta -==================== -*/ -void idAnimator::GetDelta( int fromtime, int totime, idVec3 &delta ) const { - int i; - const idAnimBlend *blend; - float blendWeight; - - if ( !modelDef || !modelDef->ModelHandle() || ( fromtime == totime ) ) { - delta.Zero(); - return; - } - - delta.Zero(); - blendWeight = 0.0f; - - blend = channels[ ANIMCHANNEL_ALL ]; - for( i = 0; i < ANIM_MaxAnimsPerChannel; i++, blend++ ) { - blend->BlendDelta( fromtime, totime, delta, blendWeight ); - } - - if ( modelDef->Joints()[ 0 ].channel ) { - blend = channels[ modelDef->Joints()[ 0 ].channel ]; - for( i = 0; i < ANIM_MaxAnimsPerChannel; i++, blend++ ) { - blend->BlendDelta( fromtime, totime, delta, blendWeight ); - } - } -} - -/* -==================== -idAnimator::GetDeltaRotation -==================== -*/ -bool idAnimator::GetDeltaRotation( int fromtime, int totime, idMat3 &delta ) const { - int i; - const idAnimBlend *blend; - float blendWeight; - idQuat q; - - if ( !modelDef || !modelDef->ModelHandle() || ( fromtime == totime ) ) { - delta.Identity(); - return false; - } - - q.Set( 0.0f, 0.0f, 0.0f, 1.0f ); - blendWeight = 0.0f; - - blend = channels[ ANIMCHANNEL_ALL ]; - for( i = 0; i < ANIM_MaxAnimsPerChannel; i++, blend++ ) { - blend->BlendDeltaRotation( fromtime, totime, q, blendWeight ); - } - - if ( modelDef->Joints()[ 0 ].channel ) { - blend = channels[ modelDef->Joints()[ 0 ].channel ]; - for( i = 0; i < ANIM_MaxAnimsPerChannel; i++, blend++ ) { - blend->BlendDeltaRotation( fromtime, totime, q, blendWeight ); - } - } - - if ( blendWeight > 0.0f ) { - delta = q.ToMat3(); - return true; - } else { - delta.Identity(); - return false; - } -} - -/* -==================== -idAnimator::GetOrigin -==================== -*/ -void idAnimator::GetOrigin( int currentTime, idVec3 &pos ) const { - int i; - const idAnimBlend *blend; - float blendWeight; - - if ( !modelDef || !modelDef->ModelHandle() ) { - pos.Zero(); - return; - } - - pos.Zero(); - blendWeight = 0.0f; - - blend = channels[ ANIMCHANNEL_ALL ]; - for( i = 0; i < ANIM_MaxAnimsPerChannel; i++, blend++ ) { - blend->BlendOrigin( currentTime, pos, blendWeight, removeOriginOffset ); - } - - if ( modelDef->Joints()[ 0 ].channel ) { - blend = channels[ modelDef->Joints()[ 0 ].channel ]; - for( i = 0; i < ANIM_MaxAnimsPerChannel; i++, blend++ ) { - blend->BlendOrigin( currentTime, pos, blendWeight, removeOriginOffset ); - } - } - - pos += modelDef->GetVisualOffset(); -} - -/* -==================== -idAnimator::GetBounds -==================== -*/ -bool idAnimator::GetBounds( int currentTime, idBounds &bounds ) { - int i, j; - const idAnimBlend *blend; - int count; - - if ( !modelDef || !modelDef->ModelHandle() ) { - return false; - } - - if ( AFPoseJoints.Num() ) { - bounds = AFPoseBounds; - count = 1; - } else { - bounds.Clear(); - count = 0; - } - - blend = channels[ 0 ]; - for( i = ANIMCHANNEL_ALL; i < ANIM_NumAnimChannels; i++ ) { - for( j = 0; j < ANIM_MaxAnimsPerChannel; j++, blend++ ) { - if ( blend->AddBounds( currentTime, bounds, removeOriginOffset ) ) { - count++; - } - } - } - - if ( !count ) { - if ( !frameBounds.IsCleared() ) { - bounds = frameBounds; - return true; - } else { - bounds.Zero(); - return false; - } - } - - bounds.TranslateSelf( modelDef->GetVisualOffset() ); - - if ( g_debugBounds.GetBool() ) { - if ( bounds[1][0] - bounds[0][0] > 2048 || bounds[1][1] - bounds[0][1] > 2048 ) { - if ( entity ) { - gameLocal.Warning( "big frameBounds on entity '%s' with model '%s': %f,%f", entity->name.c_str(), modelDef->ModelHandle()->Name(), bounds[1][0] - bounds[0][0], bounds[1][1] - bounds[0][1] ); - } else { - gameLocal.Warning( "big frameBounds on model '%s': %f,%f", modelDef->ModelHandle()->Name(), bounds[1][0] - bounds[0][0], bounds[1][1] - bounds[0][1] ); - } - } - } - - frameBounds = bounds; - - return true; -} - -/* -===================== -idAnimator::InitAFPose -===================== -*/ -void idAnimator::InitAFPose( void ) { - - if ( !modelDef ) { - return; - } - - AFPoseJoints.SetNum( modelDef->Joints().Num(), false ); - AFPoseJoints.SetNum( 0, false ); - AFPoseJointMods.SetNum( modelDef->Joints().Num(), false ); - AFPoseJointFrame.SetNum( modelDef->Joints().Num(), false ); -} - -/* -===================== -idAnimator::SetAFPoseJointMod -===================== -*/ -void idAnimator::SetAFPoseJointMod( const jointHandle_t jointNum, const AFJointModType_t mod, const idMat3 &axis, const idVec3 &origin ) { - AFPoseJointMods[jointNum].mod = mod; - AFPoseJointMods[jointNum].axis = axis; - AFPoseJointMods[jointNum].origin = origin; - - int index = idBinSearch_GreaterEqual( AFPoseJoints.Ptr(), AFPoseJoints.Num(), jointNum ); - if ( index >= AFPoseJoints.Num() || jointNum != AFPoseJoints[index] ) { - AFPoseJoints.Insert( jointNum, index ); - } -} - -/* -===================== -idAnimator::FinishAFPose -===================== -*/ -void idAnimator::FinishAFPose( int animNum, const idBounds &bounds, const int time ) { - int i, j; - int numJoints; - int parentNum; - int jointMod; - int jointNum; - const int * jointParent; - - if ( !modelDef ) { - return; - } - - const idAnim *anim = modelDef->GetAnim( animNum ); - if ( !anim ) { - return; - } - - numJoints = modelDef->Joints().Num(); - if ( !numJoints ) { - return; - } - - idRenderModel *md5 = modelDef->ModelHandle(); - const idMD5Anim *md5anim = anim->MD5Anim( 0 ); - - if ( numJoints != md5anim->NumJoints() ) { - gameLocal.Warning( "Model '%s' has different # of joints than anim '%s'", md5->Name(), md5anim->Name() ); - return; - } - - idJointQuat *jointFrame = ( idJointQuat * )_alloca16( numJoints * sizeof( *jointFrame ) ); - md5anim->GetSingleFrame( 0, jointFrame, modelDef->GetChannelJoints( ANIMCHANNEL_ALL ), modelDef->NumJointsOnChannel( ANIMCHANNEL_ALL ) ); - - if ( removeOriginOffset ) { -#ifdef VELOCITY_MOVE - jointFrame[ 0 ].t.x = 0.0f; -#else - jointFrame[ 0 ].t.Zero(); -#endif - } - - idJointMat *joints = ( idJointMat * )_alloca16( numJoints * sizeof( *joints ) ); - - // convert the joint quaternions to joint matrices - SIMDProcessor->ConvertJointQuatsToJointMats( joints, jointFrame, numJoints ); - - // first joint is always root of entire hierarchy - if ( AFPoseJoints.Num() && AFPoseJoints[0] == 0 ) { - switch( AFPoseJointMods[0].mod ) { - case AF_JOINTMOD_AXIS: { - joints[0].SetRotation( AFPoseJointMods[0].axis ); - break; - } - case AF_JOINTMOD_ORIGIN: { - joints[0].SetTranslation( AFPoseJointMods[0].origin ); - break; - } - case AF_JOINTMOD_BOTH: { - joints[0].SetRotation( AFPoseJointMods[0].axis ); - joints[0].SetTranslation( AFPoseJointMods[0].origin ); - break; - } - } - j = 1; - } else { - j = 0; - } - - // pointer to joint info - jointParent = modelDef->JointParents(); - - // transform the child joints - for( i = 1; j < AFPoseJoints.Num(); j++, i++ ) { - jointMod = AFPoseJoints[j]; - - // transform any joints preceding the joint modifier - SIMDProcessor->TransformJoints( joints, jointParent, i, jointMod - 1 ); - i = jointMod; - - parentNum = jointParent[i]; - - switch( AFPoseJointMods[jointMod].mod ) { - case AF_JOINTMOD_AXIS: { - joints[i].SetRotation( AFPoseJointMods[jointMod].axis ); - joints[i].SetTranslation( joints[parentNum].ToVec3() + joints[i].ToVec3() * joints[parentNum].ToMat3() ); - break; - } - case AF_JOINTMOD_ORIGIN: { - joints[i].SetRotation( joints[i].ToMat3() * joints[parentNum].ToMat3() ); - joints[i].SetTranslation( AFPoseJointMods[jointMod].origin ); - break; - } - case AF_JOINTMOD_BOTH: { - joints[i].SetRotation( AFPoseJointMods[jointMod].axis ); - joints[i].SetTranslation( AFPoseJointMods[jointMod].origin ); - break; - } - } - } - - // transform the rest of the hierarchy - SIMDProcessor->TransformJoints( joints, jointParent, i, numJoints - 1 ); - - // untransform hierarchy - SIMDProcessor->UntransformJoints( joints, jointParent, 1, numJoints - 1 ); - - // convert joint matrices back to joint quaternions - SIMDProcessor->ConvertJointMatsToJointQuats( AFPoseJointFrame.Ptr(), joints, numJoints ); - - // find all modified joints and their parents - bool *blendJoints = (bool *) _alloca16( numJoints * sizeof( bool ) ); - memset( blendJoints, 0, numJoints * sizeof( bool ) ); - - // mark all modified joints and their parents - for( i = 0; i < AFPoseJoints.Num(); i++ ) { - for( jointNum = AFPoseJoints[i]; jointNum != INVALID_JOINT; jointNum = jointParent[jointNum] ) { - blendJoints[jointNum] = true; - } - } - - // lock all parents of modified joints - AFPoseJoints.SetNum( 0, false ); - for ( i = 0; i < numJoints; i++ ) { - if ( blendJoints[i] ) { - AFPoseJoints.Append( i ); - } - } - - AFPoseBounds = bounds; - AFPoseTime = time; - - ForceUpdate(); -} - -/* -===================== -idAnimator::SetAFPoseBlendWeight -===================== -*/ -void idAnimator::SetAFPoseBlendWeight( float blendWeight ) { - AFPoseBlendWeight = blendWeight; -} - -/* -===================== -idAnimator::BlendAFPose -===================== -*/ -bool idAnimator::BlendAFPose( idJointQuat *blendFrame ) const { - - if ( !AFPoseJoints.Num() ) { - return false; - } - - SIMDProcessor->BlendJoints( blendFrame, AFPoseJointFrame.Ptr(), AFPoseBlendWeight, AFPoseJoints.Ptr(), AFPoseJoints.Num() ); - - return true; -} - -/* -===================== -idAnimator::ClearAFPose -===================== -*/ -void idAnimator::ClearAFPose( void ) { - if ( AFPoseJoints.Num() ) { - ForceUpdate(); - } - AFPoseBlendWeight = 1.0f; - AFPoseJoints.SetNum( 0, false ); - AFPoseBounds.Clear(); - AFPoseTime = 0; -} - -/* -===================== -idAnimator::ServiceAnims -===================== -*/ -void idAnimator::ServiceAnims( int fromtime, int totime ) { - int i, j; - idAnimBlend *blend; - - if ( !modelDef ) { - return; - } - - if ( modelDef->ModelHandle() ) { - blend = channels[ 0 ]; - for( i = 0; i < ANIM_NumAnimChannels; i++ ) { - for( j = 0; j < ANIM_MaxAnimsPerChannel; j++, blend++ ) { - blend->CallFrameCommands( entity, fromtime, totime ); - } - } - } - - if ( !IsAnimating( totime ) ) { - stoppedAnimatingUpdate = true; - if ( entity ) { - entity->BecomeInactive( TH_ANIMATE ); - - // present one more time with stopped animations so the renderer can properly recreate interactions - entity->BecomeActive( TH_UPDATEVISUALS ); - } - } -} - -/* -===================== -idAnimator::IsAnimating -===================== -*/ -bool idAnimator::IsAnimating( int currentTime ) const { - int i, j; - const idAnimBlend *blend; - - if ( !modelDef || !modelDef->ModelHandle() ) { - return false; - } - - // if animating with an articulated figure - if ( AFPoseJoints.Num() && currentTime <= AFPoseTime ) { - return true; - } - - blend = channels[ 0 ]; - for( i = 0; i < ANIM_NumAnimChannels; i++ ) { - for( j = 0; j < ANIM_MaxAnimsPerChannel; j++, blend++ ) { - if ( !blend->IsDone( currentTime ) ) { - return true; - } - } - } - - return false; -} - -/* -===================== -idAnimator::FrameHasChanged -===================== -*/ -bool idAnimator::FrameHasChanged( int currentTime ) const { - int i, j; - const idAnimBlend *blend; - - if ( !modelDef || !modelDef->ModelHandle() ) { - return false; - } - - // if animating with an articulated figure - if ( AFPoseJoints.Num() && currentTime <= AFPoseTime ) { - return true; - } - - blend = channels[ 0 ]; - for( i = 0; i < ANIM_NumAnimChannels; i++ ) { - for( j = 0; j < ANIM_MaxAnimsPerChannel; j++, blend++ ) { - if ( blend->FrameHasChanged( currentTime ) ) { - return true; - } - } - } - - if ( forceUpdate && IsAnimating( currentTime ) ) { - return true; - } - - return false; -} - -/* -===================== -idAnimator::CreateFrame -===================== -*/ -bool idAnimator::CreateFrame( int currentTime, bool force ) { - int i, j; - int numJoints; - int parentNum; - bool hasAnim; - bool debugInfo; - float baseBlend; - float blendWeight; - const idAnimBlend * blend; - const int * jointParent; - const jointMod_t * jointMod; - const idJointQuat * defaultPose; - - static idCVar r_showSkel( "r_showSkel", "0", CVAR_RENDERER | CVAR_INTEGER, "", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> ); - - if ( gameLocal.inCinematic && gameLocal.skipCinematic ) { - return false; - } - - if ( !modelDef || !modelDef->ModelHandle() ) { - return false; - } - - if ( !force && !r_showSkel.GetInteger() ) { - if ( lastTransformTime == currentTime ) { - return false; - } - if ( lastTransformTime != -1 && !stoppedAnimatingUpdate && !IsAnimating( currentTime ) ) { - return false; - } - } - - lastTransformTime = currentTime; - stoppedAnimatingUpdate = false; - - if ( entity && ( ( g_debugAnim.GetInteger() == entity->entityNumber ) || ( g_debugAnim.GetInteger() == -2 ) ) ) { - debugInfo = true; - gameLocal.Printf( "---------------\n%d: entity '%s':\n", gameLocal.time, entity->GetName() ); - gameLocal.Printf( "model '%s':\n", modelDef->GetModelName() ); - } else { - debugInfo = false; - } - - // init the joint buffer - if ( AFPoseJoints.Num() ) { - // initialize with AF pose anim for the case where there are no other animations and no AF pose joint modifications - defaultPose = AFPoseJointFrame.Ptr(); - } else { - defaultPose = modelDef->GetDefaultPose(); - } - - if ( !defaultPose ) { - //gameLocal.Warning( "idAnimator::CreateFrame: no defaultPose on '%s'", modelDef->Name() ); - return false; - } - - numJoints = modelDef->Joints().Num(); - idJointQuat *jointFrame = ( idJointQuat * )_alloca16( numJoints * sizeof( jointFrame[0] ) ); - SIMDProcessor->Memcpy( jointFrame, defaultPose, numJoints * sizeof( jointFrame[0] ) ); - - hasAnim = false; - - // blend the all channel - baseBlend = 0.0f; - blend = channels[ ANIMCHANNEL_ALL ]; - for( j = 0; j < ANIM_MaxAnimsPerChannel; j++, blend++ ) { - if ( blend->BlendAnim( currentTime, ANIMCHANNEL_ALL, numJoints, jointFrame, baseBlend, removeOriginOffset, false, debugInfo ) ) { - hasAnim = true; - if ( baseBlend >= 1.0f ) { - break; - } - } - } - - // only blend other channels if there's enough space to blend into - if ( baseBlend < 1.0f ) { - for( i = ANIMCHANNEL_ALL + 1; i < ANIM_NumAnimChannels; i++ ) { - if ( !modelDef->NumJointsOnChannel( i ) ) { - continue; - } - if ( i == ANIMCHANNEL_EYELIDS ) { - // eyelids blend over any previous anims, so skip it and blend it later - continue; - } - blendWeight = baseBlend; - blend = channels[ i ]; - for( j = 0; j < ANIM_MaxAnimsPerChannel; j++, blend++ ) { - if ( blend->BlendAnim( currentTime, i, numJoints, jointFrame, blendWeight, removeOriginOffset, false, debugInfo ) ) { - hasAnim = true; - if ( blendWeight >= 1.0f ) { - // fully blended - break; - } - } - } - - if ( debugInfo && !AFPoseJoints.Num() && !blendWeight ) { - gameLocal.Printf( "%d: %s using default pose in model '%s'\n", gameLocal.time, channelNames[ i ], modelDef->GetModelName() ); - } - } - } - - // blend in the eyelids - if ( modelDef->NumJointsOnChannel( ANIMCHANNEL_EYELIDS ) ) { - blend = channels[ ANIMCHANNEL_EYELIDS ]; - blendWeight = baseBlend; - for( j = 0; j < ANIM_MaxAnimsPerChannel; j++, blend++ ) { - if ( blend->BlendAnim( currentTime, ANIMCHANNEL_EYELIDS, numJoints, jointFrame, blendWeight, removeOriginOffset, true, debugInfo ) ) { - hasAnim = true; - if ( blendWeight >= 1.0f ) { - // fully blended - break; - } - } - } - } - - // blend the articulated figure pose - if ( BlendAFPose( jointFrame ) ) { - hasAnim = true; - } - - if ( !hasAnim && !jointMods.Num() ) { - // no animations were updated - return false; - } - - // convert the joint quaternions to rotation matrices - SIMDProcessor->ConvertJointQuatsToJointMats( joints, jointFrame, numJoints ); - - // check if we need to modify the origin - if ( jointMods.Num() && ( jointMods[0]->jointnum == 0 ) ) { - jointMod = jointMods[0]; - - switch( jointMod->transform_axis ) { - case JOINTMOD_NONE: - break; - - case JOINTMOD_LOCAL: - joints[0].SetRotation( jointMod->mat * joints[0].ToMat3() ); - break; - - case JOINTMOD_WORLD: - joints[0].SetRotation( joints[0].ToMat3() * jointMod->mat ); - break; - - case JOINTMOD_LOCAL_OVERRIDE: - case JOINTMOD_WORLD_OVERRIDE: - joints[0].SetRotation( jointMod->mat ); - break; - } - - switch( jointMod->transform_pos ) { - case JOINTMOD_NONE: - break; - - case JOINTMOD_LOCAL: - joints[0].SetTranslation( joints[0].ToVec3() + jointMod->pos ); - break; - - case JOINTMOD_LOCAL_OVERRIDE: - case JOINTMOD_WORLD: - case JOINTMOD_WORLD_OVERRIDE: - joints[0].SetTranslation( jointMod->pos ); - break; - } - j = 1; - } else { - j = 0; - } - - // add in the model offset - joints[0].SetTranslation( joints[0].ToVec3() + modelDef->GetVisualOffset() ); - - // pointer to joint info - jointParent = modelDef->JointParents(); - - // add in any joint modifications - for( i = 1; j < jointMods.Num(); j++, i++ ) { - jointMod = jointMods[j]; - - // transform any joints preceding the joint modifier - SIMDProcessor->TransformJoints( joints, jointParent, i, jointMod->jointnum - 1 ); - i = jointMod->jointnum; - - parentNum = jointParent[i]; - - // modify the axis - switch( jointMod->transform_axis ) { - case JOINTMOD_NONE: - joints[i].SetRotation( joints[i].ToMat3() * joints[ parentNum ].ToMat3() ); - break; - - case JOINTMOD_LOCAL: - joints[i].SetRotation( jointMod->mat * ( joints[i].ToMat3() * joints[parentNum].ToMat3() ) ); - break; - - case JOINTMOD_LOCAL_OVERRIDE: - joints[i].SetRotation( jointMod->mat * joints[parentNum].ToMat3() ); - break; - - case JOINTMOD_WORLD: - joints[i].SetRotation( ( joints[i].ToMat3() * joints[parentNum].ToMat3() ) * jointMod->mat ); - break; - - case JOINTMOD_WORLD_OVERRIDE: - joints[i].SetRotation( jointMod->mat ); - break; - } - - // modify the position - switch( jointMod->transform_pos ) { - case JOINTMOD_NONE: - joints[i].SetTranslation( joints[parentNum].ToVec3() + joints[i].ToVec3() * joints[parentNum].ToMat3() ); - break; - - case JOINTMOD_LOCAL: - joints[i].SetTranslation( joints[parentNum].ToVec3() + ( joints[i].ToVec3() + jointMod->pos ) * joints[parentNum].ToMat3() ); - break; - - case JOINTMOD_LOCAL_OVERRIDE: - joints[i].SetTranslation( joints[parentNum].ToVec3() + jointMod->pos * joints[parentNum].ToMat3() ); - break; - - case JOINTMOD_WORLD: - joints[i].SetTranslation( joints[parentNum].ToVec3() + joints[i].ToVec3() * joints[parentNum].ToMat3() + jointMod->pos ); - break; - - case JOINTMOD_WORLD_OVERRIDE: - joints[i].SetTranslation( jointMod->pos ); - break; - } - } - - // transform the rest of the hierarchy - SIMDProcessor->TransformJoints( joints, jointParent, i, numJoints - 1 ); - - return true; -} - -/* -===================== -idAnimator::ForceUpdate -===================== -*/ -void idAnimator::ForceUpdate( void ) { - lastTransformTime = -1; - forceUpdate = true; -} - -/* -===================== -idAnimator::ClearForceUpdate -===================== -*/ -void idAnimator::ClearForceUpdate( void ) { - forceUpdate = false; -} - -/* -===================== -idAnimator::GetJointTransform> gamex86.dll!idAnimator::ForceUpdate() Line 4268 C++ - -===================== -*/ -bool idAnimator::GetJointTransform( jointHandle_t jointHandle, int currentTime, idVec3 &offset, idMat3 &axis ) { - if ( !modelDef || ( jointHandle < 0 ) || ( jointHandle >= modelDef->NumJoints() ) ) { - return false; - } - - CreateFrame( currentTime, false ); - - offset = joints[ jointHandle ].ToVec3(); - axis = joints[ jointHandle ].ToMat3(); - - return true; -} - -/* -===================== -idAnimator::GetJointLocalTransform -===================== -*/ -bool idAnimator::GetJointLocalTransform( jointHandle_t jointHandle, int currentTime, idVec3 &offset, idMat3 &axis ) { - if ( !modelDef ) { - return false; - } - - const idList &modelJoints = modelDef->Joints(); - - if ( ( jointHandle < 0 ) || ( jointHandle >= modelJoints.Num() ) ) { - return false; - } - - // FIXME: overkill - CreateFrame( currentTime, false ); - - if ( jointHandle == 0 ) { - offset = joints[ jointHandle ].ToVec3(); - axis = joints[ jointHandle ].ToMat3(); - - return true; - } - - idJointMat m = joints[ jointHandle ]; - m /= joints[ modelJoints[ jointHandle ].parentNum ]; - offset = m.ToVec3(); - axis = m.ToMat3(); - - return true; -} - -/* -===================== -idAnimator::GetJointHandle -===================== -*/ -jointHandle_t idAnimator::GetJointHandle( const char *name ) const { - if ( !modelDef || !modelDef->ModelHandle() ) { - return INVALID_JOINT; - } - - return modelDef->ModelHandle()->GetJointHandle( name ); -} - -/* -===================== -idAnimator::GetJointName -===================== -*/ -const char *idAnimator::GetJointName( jointHandle_t handle ) const { - if ( !modelDef || !modelDef->ModelHandle() ) { - return ""; - } - - return modelDef->ModelHandle()->GetJointName( handle ); -} - -/* -===================== -idAnimator::GetChannelForJoint -===================== -*/ -int idAnimator::GetChannelForJoint( jointHandle_t joint ) const { - if ( !modelDef ) { - gameLocal.Error( "idAnimator::GetChannelForJoint: NULL model" ); - } - - if ( ( joint < 0 ) || ( joint >= numJoints ) ) { - gameLocal.Error( "idAnimator::GetChannelForJoint: invalid joint num (%d)", joint ); - } - - return modelDef->GetJoint( joint )->channel; -} - -/* -===================== -idAnimator::GetFirstChild -===================== -*/ -jointHandle_t idAnimator::GetFirstChild( const char *name ) const { - return GetFirstChild( GetJointHandle( name ) ); -} - -/* -===================== -idAnimator::GetFirstChild -===================== -*/ -jointHandle_t idAnimator::GetFirstChild( jointHandle_t jointnum ) const { - int i; - int num; - const jointInfo_t *joint; - - if ( !modelDef ) { - return INVALID_JOINT; - } - - num = modelDef->NumJoints(); - if ( !num ) { - return jointnum; - } - joint = modelDef->GetJoint( 0 ); - for( i = 0; i < num; i++, joint++ ) { - if ( joint->parentNum == jointnum ) { - return ( jointHandle_t )joint->num; - } - } - return jointnum; -} - -/* -===================== -idAnimator::GetJoints -===================== -*/ -void idAnimator::GetJoints( int *numJoints, idJointMat **jointsPtr ) { - *numJoints = this->numJoints; - *jointsPtr = this->joints; -} - -/* -===================== -idAnimator::GetAnimFlags -===================== -*/ -const animFlags_t idAnimator::GetAnimFlags( int animNum ) const { - animFlags_t result; - - const idAnim *anim = GetAnim( animNum ); - if ( anim ) { - return anim->GetAnimFlags(); - } - - memset( &result, 0, sizeof( result ) ); - return result; -} - -/* -===================== -idAnimator::NumFrames -===================== -*/ -int idAnimator::NumFrames( int animNum ) const { - const idAnim *anim = GetAnim( animNum ); - if ( anim ) { - return anim->NumFrames(); - } else { - return 0; - } -} - -/* -===================== -idAnimator::NumSyncedAnims -===================== -*/ -int idAnimator::NumSyncedAnims( int animNum ) const { - const idAnim *anim = GetAnim( animNum ); - if ( anim ) { - return anim->NumAnims(); - } else { - return 0; - } -} - -/* -===================== -idAnimator::AnimName -===================== -*/ -const char *idAnimator::AnimName( int animNum ) const { - const idAnim *anim = GetAnim( animNum ); - if ( anim ) { - return anim->Name(); - } else { - return ""; - } -} - -/* -===================== -idAnimator::AnimFullName -===================== -*/ -const char *idAnimator::AnimFullName( int animNum ) const { - const idAnim *anim = GetAnim( animNum ); - if ( anim ) { - return anim->FullName(); - } else { - return ""; - } -} - -/* -===================== -idAnimator::AnimLength -===================== -*/ -int idAnimator::AnimLength( int animNum ) const { - const idAnim *anim = GetAnim( animNum ); - if ( anim ) { - return anim->Length(); - } else { - return 0; - } -} - -/* -===================== -idAnimator::TotalMovementDelta -===================== -*/ -const idVec3 &idAnimator::TotalMovementDelta( int animNum ) const { - const idAnim *anim = GetAnim( animNum ); - if ( anim ) { - return anim->TotalMovementDelta(); - } else { - return vec3_origin; - } -} - -/*********************************************************************** - - Util functions - -***********************************************************************/ - -/* -===================== -ANIM_GetModelDefFromEntityDef -===================== -*/ -const idDeclModelDef *ANIM_GetModelDefFromEntityDef( const idDict *args ) { - const idDeclModelDef *modelDef; - - idStr name = args->GetString( "model" ); - modelDef = static_cast( declManager->FindType( DECL_MODELDEF, name, false ) ); - if ( modelDef && modelDef->ModelHandle() ) { - return modelDef; - } - - return NULL; -} - -/* -===================== -idGameEdit::ANIM_GetModelFromEntityDef -===================== -*/ -idRenderModel *idGameEdit::ANIM_GetModelFromEntityDef( const idDict *args ) { - idRenderModel *model; - const idDeclModelDef *modelDef; - - model = NULL; - - idStr name = args->GetString( "model" ); - modelDef = static_cast( declManager->FindType( DECL_MODELDEF, name, false ) ); - if ( modelDef ) { - model = modelDef->ModelHandle(); - } - - if ( !model ) { - model = renderModelManager->FindModel( name ); - } - - if ( model && model->IsDefaultModel() ) { - return NULL; - } - - return model; -} - -/* -===================== -idGameEdit::ANIM_GetModelFromEntityDef -===================== -*/ -idRenderModel *idGameEdit::ANIM_GetModelFromEntityDef( const char *classname ) { - const idDict *args; - - args = gameLocal.FindEntityDefDict( classname, false ); - if ( !args ) { - return NULL; - } - - return ANIM_GetModelFromEntityDef( args ); -} - -/* -===================== -idGameEdit::ANIM_GetModelOffsetFromEntityDef -===================== -*/ -const idVec3 &idGameEdit::ANIM_GetModelOffsetFromEntityDef( const char *classname ) { - const idDict *args; - const idDeclModelDef *modelDef; - - args = gameLocal.FindEntityDefDict( classname, false ); - if ( !args ) { - return vec3_origin; - } - - modelDef = ANIM_GetModelDefFromEntityDef( args ); - if ( !modelDef ) { - return vec3_origin; - } - - return modelDef->GetVisualOffset(); -} - -/* -===================== -idGameEdit::ANIM_GetModelFromName -===================== -*/ -idRenderModel *idGameEdit::ANIM_GetModelFromName( const char *modelName ) { - const idDeclModelDef *modelDef; - idRenderModel *model; - - model = NULL; - modelDef = static_cast( declManager->FindType( DECL_MODELDEF, modelName, false ) ); - if ( modelDef ) { - model = modelDef->ModelHandle(); - } - if ( !model ) { - model = renderModelManager->FindModel( modelName ); - } - return model; -} - -/* -===================== -idGameEdit::ANIM_GetAnimFromEntityDef -===================== -*/ -const idMD5Anim *idGameEdit::ANIM_GetAnimFromEntityDef( const char *classname, const char *animname ) { - const idDict *args; - const idMD5Anim *md5anim; - const idAnim *anim; - int animNum; - const char *modelname; - const idDeclModelDef *modelDef; - - args = gameLocal.FindEntityDefDict( classname, false ); - if ( !args ) { - return NULL; - } - - md5anim = NULL; - modelname = args->GetString( "model" ); - modelDef = static_cast( declManager->FindType( DECL_MODELDEF, modelname, false ) ); - if ( modelDef ) { - animNum = modelDef->GetAnim( animname ); - if ( animNum ) { - anim = modelDef->GetAnim( animNum ); - if ( anim ) { - md5anim = anim->MD5Anim( 0 ); - } - } - } - return md5anim; -} - -/* -===================== -idGameEdit::ANIM_GetNumAnimsFromEntityDef -===================== -*/ -int idGameEdit::ANIM_GetNumAnimsFromEntityDef( const idDict *args ) { - const char *modelname; - const idDeclModelDef *modelDef; - - modelname = args->GetString( "model" ); - modelDef = static_cast( declManager->FindType( DECL_MODELDEF, modelname, false ) ); - if ( modelDef ) { - return modelDef->NumAnims(); - } - return 0; -} - -/* -===================== -idGameEdit::ANIM_GetAnimNameFromEntityDef -===================== -*/ -const char *idGameEdit::ANIM_GetAnimNameFromEntityDef( const idDict *args, int animNum ) { - const char *modelname; - const idDeclModelDef *modelDef; - - modelname = args->GetString( "model" ); - modelDef = static_cast( declManager->FindType( DECL_MODELDEF, modelname, false ) ); - if ( modelDef ) { - const idAnim* anim = modelDef->GetAnim( animNum ); - if ( anim ) { - return anim->FullName(); - } - } - return ""; -} - -/* -===================== -idGameEdit::ANIM_GetAnim -===================== -*/ -const idMD5Anim *idGameEdit::ANIM_GetAnim( const char *fileName ) { - return animationLib.GetAnim( fileName ); -} - -/* -===================== -idGameEdit::ANIM_GetLength -===================== -*/ -int idGameEdit::ANIM_GetLength( const idMD5Anim *anim ) { - if ( !anim ) { - return 0; - } - return anim->Length(); -} - -/* -===================== -idGameEdit::ANIM_GetNumFrames -===================== -*/ -int idGameEdit::ANIM_GetNumFrames( const idMD5Anim *anim ) { - if ( !anim ) { - return 0; - } - return anim->NumFrames(); -} - -/* -===================== -idGameEdit::ANIM_CreateAnimFrame -===================== -*/ -void idGameEdit::ANIM_CreateAnimFrame( const idRenderModel *model, const idMD5Anim *anim, int numJoints, idJointMat *joints, int time, const idVec3 &offset, bool remove_origin_offset ) { - int i; - frameBlend_t frame; - const idMD5Joint *md5joints; - int *index; - - if ( !model || model->IsDefaultModel() || !anim ) { - return; - } - - if ( numJoints != model->NumJoints() ) { - gameLocal.Error( "ANIM_CreateAnimFrame: different # of joints in renderEntity_t than in model (%s)", model->Name() ); - } - - if ( !model->NumJoints() ) { - // FIXME: Print out a warning? - return; - } - - if ( !joints ) { - gameLocal.Error( "ANIM_CreateAnimFrame: NULL joint frame pointer on model (%s)", model->Name() ); - } - - if ( numJoints != anim->NumJoints() ) { - gameLocal.Warning( "Model '%s' has different # of joints than anim '%s'", model->Name(), anim->Name() ); - for( i = 0; i < numJoints; i++ ) { - joints[i].SetRotation( mat3_identity ); - joints[i].SetTranslation( offset ); - } - return; - } - - // create index for all joints - index = ( int * )_alloca16( numJoints * sizeof( int ) ); - for ( i = 0; i < numJoints; i++ ) { - index[i] = i; - } - - // create the frame - anim->ConvertTimeToFrame( time, 1, frame ); - idJointQuat *jointFrame = ( idJointQuat * )_alloca16( numJoints * sizeof( *jointFrame ) ); - anim->GetInterpolatedFrame( frame, jointFrame, index, numJoints ); - - // convert joint quaternions to joint matrices - SIMDProcessor->ConvertJointQuatsToJointMats( joints, jointFrame, numJoints ); - - // first joint is always root of entire hierarchy - if ( remove_origin_offset ) { - joints[0].SetTranslation( offset ); - } else { - joints[0].SetTranslation( joints[0].ToVec3() + offset ); - } - - // transform the children - md5joints = model->GetJoints(); - for( i = 1; i < numJoints; i++ ) { - joints[i] *= joints[ md5joints[i].parent - md5joints ]; - } -} - -/* -===================== -idGameEdit::ANIM_CreateMeshForAnim -===================== -*/ -idRenderModel *idGameEdit::ANIM_CreateMeshForAnim( idRenderModel *model, const char *classname, const char *animname, int frame, bool remove_origin_offset ) { - renderEntity_t ent; - const idDict *args; - const char *temp; - idRenderModel *newmodel; - const idMD5Anim *md5anim; - idStr filename; - idStr extension; - const idAnim *anim; - int animNum; - idVec3 offset; - const idDeclModelDef *modelDef; - - if ( !model || model->IsDefaultModel() ) { - return NULL; - } - - args = gameLocal.FindEntityDefDict( classname, false ); - if ( !args ) { - return NULL; - } - - memset( &ent, 0, sizeof( ent ) ); - - ent.bounds.Clear(); - ent.suppressSurfaceInViewID = 0; - - modelDef = ANIM_GetModelDefFromEntityDef( args ); - if ( modelDef ) { - animNum = modelDef->GetAnim( animname ); - if ( !animNum ) { - return NULL; - } - anim = modelDef->GetAnim( animNum ); - if ( !anim ) { - return NULL; - } - md5anim = anim->MD5Anim( 0 ); - ent.customSkin = modelDef->GetDefaultSkin(); - offset = modelDef->GetVisualOffset(); - } else { - filename = animname; - filename.ExtractFileExtension( extension ); - if ( !extension.Length() ) { - animname = args->GetString( va( "anim %s", animname ) ); - } - - md5anim = animationLib.GetAnim( animname ); - offset.Zero(); - } - - if ( !md5anim ) { - return NULL; - } - - temp = args->GetString( "skin", "" ); - if ( temp[ 0 ] ) { - ent.customSkin = declManager->FindSkin( temp ); - } - - ent.numJoints = model->NumJoints(); - ent.joints = ( idJointMat * )Mem_Alloc16( ent.numJoints * sizeof( *ent.joints ) ); - - ANIM_CreateAnimFrame( model, md5anim, ent.numJoints, ent.joints, FRAME2MS( frame ), offset, remove_origin_offset ); - - newmodel = model->InstantiateDynamicModel( &ent, NULL, NULL ); - - Mem_Free16( ent.joints ); - ent.joints = NULL; - - return newmodel; -} diff --git a/d3xp/anim/Anim_Import.cpp b/d3xp/anim/Anim_Import.cpp deleted file mode 100644 index 035f5884..00000000 --- a/d3xp/anim/Anim_Import.cpp +++ /dev/null @@ -1,570 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "framework/Licensee.h" -#include "MayaImport/maya_main.h" - -#include "gamesys/SysCvar.h" -#include "Game_local.h" - -#include "anim/Anim.h" - -/*********************************************************************** - - Maya conversion functions - -***********************************************************************/ - -static idStr Maya_Error; - -static exporterInterface_t Maya_ConvertModel = NULL; -static exporterShutdown_t Maya_Shutdown = NULL; -static uintptr_t importDLL = 0; - -bool idModelExport::initialized = false; - -/* -==================== -idModelExport::idModelExport -==================== -*/ -idModelExport::idModelExport() { - Reset(); -} - -/* -==================== -idModelExport::Shutdown -==================== -*/ -void idModelExport::Shutdown( void ) { - if ( Maya_Shutdown ) { - Maya_Shutdown(); - } - - if ( importDLL ) { - sys->DLL_Unload( importDLL ); - } - - importDLL = 0; - Maya_Shutdown = NULL; - Maya_ConvertModel = NULL; - Maya_Error.Clear(); - initialized = false; -} - -/* -===================== -idModelExport::CheckMayaInstall - -Determines if Maya is installed on the user's machine -===================== -*/ -bool idModelExport::CheckMayaInstall( void ) { -#ifndef _WIN32 - return false; -#elif 0 - HKEY hKey; - long lres, lType; - - lres = RegOpenKey( HKEY_LOCAL_MACHINE, "SOFTWARE\\Alias|Wavefront\\Maya\\4.5\\Setup\\InstallPath", &hKey ); - - if ( lres != ERROR_SUCCESS ) { - return false; - } - - lres = RegQueryValueEx( hKey, "MAYA_INSTALL_LOCATION", NULL, (unsigned long*)&lType, (unsigned char*)NULL, (unsigned long*)NULL ); - - RegCloseKey( hKey ); - - if ( lres != ERROR_SUCCESS ) { - return false; - } - return true; -#else - HKEY hKey; - long lres; - - // only check the non-version specific key so that we only have to update the maya dll when new versions are released - lres = RegOpenKey( HKEY_LOCAL_MACHINE, "SOFTWARE\\Alias|Wavefront\\Maya", &hKey ); - RegCloseKey( hKey ); - - if ( lres != ERROR_SUCCESS ) { - return false; - } - return true; -#endif -} - -/* -===================== -idModelExport::LoadMayaDll - -Checks to see if we can load the Maya export dll -===================== -*/ -void idModelExport::LoadMayaDll( void ) { - exporterDLLEntry_t dllEntry; - char dllPath[ MAX_OSPATH ]; - - fileSystem->FindDLL( "MayaImport", dllPath ); - if ( !dllPath[ 0 ] ) { - return; - } - importDLL = sys->DLL_Load( dllPath ); - if ( !importDLL ) { - return; - } - - // look up the dll interface functions - dllEntry = ( exporterDLLEntry_t )sys->DLL_GetProcAddress( importDLL, "dllEntry" ); - Maya_ConvertModel = ( exporterInterface_t )sys->DLL_GetProcAddress( importDLL, "Maya_ConvertModel" ); - Maya_Shutdown = ( exporterShutdown_t )sys->DLL_GetProcAddress( importDLL, "Maya_Shutdown" ); - if ( !Maya_ConvertModel || !dllEntry || !Maya_Shutdown ) { - Maya_ConvertModel = NULL; - Maya_Shutdown = NULL; - sys->DLL_Unload( importDLL ); - importDLL = 0; - gameLocal.Error( "Invalid interface on export DLL." ); - return; - } - - // initialize the DLL - if ( !dllEntry( MD5_VERSION, common, sys ) ) { - // init failed - Maya_ConvertModel = NULL; - Maya_Shutdown = NULL; - sys->DLL_Unload( importDLL ); - importDLL = 0; - gameLocal.Error( "Export DLL init failed." ); - return; - } -} - -/* -===================== -idModelExport::ConvertMayaToMD5 - -Checks if a Maya model should be converted to an MD5, and converts if if the time/date or -version number has changed. -===================== -*/ -bool idModelExport::ConvertMayaToMD5( void ) { - ID_TIME_T sourceTime; - ID_TIME_T destTime; - int version; - idToken cmdLine; - idStr path; - - // check if our DLL got loaded - if ( initialized && !Maya_ConvertModel ) { - Maya_Error = "MayaImport dll not loaded."; - return false; - } - - // if idAnimManager::forceExport is set then we always reexport Maya models - if ( idAnimManager::forceExport ) { - force = true; - } - - // get the source file's time - if ( fileSystem->ReadFile( src, NULL, &sourceTime ) < 0 ) { - // source file doesn't exist - return true; - } - - // get the destination file's time - if ( !force && ( fileSystem->ReadFile( dest, NULL, &destTime ) >= 0 ) ) { - idParser parser( LEXFL_ALLOWPATHNAMES | LEXFL_NOSTRINGESCAPECHARS ); - - parser.LoadFile( dest ); - - // read the file version - if ( parser.CheckTokenString( MD5_VERSION_STRING ) ) { - version = parser.ParseInt(); - - // check the command line - if ( parser.CheckTokenString( "commandline" ) ) { - parser.ReadToken( &cmdLine ); - - // check the file time, scale, and version - if ( ( destTime >= sourceTime ) && ( version == MD5_VERSION ) && ( cmdLine == commandLine ) ) { - // don't convert it - return true; - } - } - } - } - - // if this is the first time we've been run, check if Maya is installed and load our DLL - if ( !initialized ) { - initialized = true; - - if ( !CheckMayaInstall() ) { - Maya_Error = "Maya not installed in registry."; - return false; - } - - LoadMayaDll(); - - // check if our DLL got loaded - if ( !Maya_ConvertModel ) { - Maya_Error = "Could not load MayaImport dll."; - return false; - } - } - - // we need to make sure we have a full path, so convert the filename to an OS path - // _D3XP :: we work out of the cdpath, at least until we get Alienbrain - src = fileSystem->RelativePathToOSPath( src, "fs_cdpath" ); - dest = fileSystem->RelativePathToOSPath( dest, "fs_cdpath" ); - - dest.ExtractFilePath( path ); - if ( path.Length() ) { - fileSystem->CreateOSPath( path ); - } - - // get the os path in case it needs to create one - path = fileSystem->RelativePathToOSPath( "", "fs_cdpath" /* _D3XP */ ); - - common->SetRefreshOnPrint( true ); - Maya_Error = Maya_ConvertModel( path, commandLine ); - common->SetRefreshOnPrint( false ); - if ( Maya_Error != "Ok" ) { - return false; - } - - // conversion succeded - return true; -} - -/* -==================== -idModelExport::Reset -==================== -*/ -void idModelExport::Reset( void ) { - force = false; - commandLine = ""; - src = ""; - dest = ""; -} - -/* -==================== -idModelExport::ExportModel -==================== -*/ -bool idModelExport::ExportModel( const char *model ) { - const char *game = cvarSystem->GetCVarString( "fs_game" ); - if ( strlen(game) == 0 ) { - game = BASE_GAMEDIR; - } - - Reset(); - src = model; - dest = model; - dest.SetFileExtension( MD5_MESH_EXT ); - - sprintf( commandLine, "mesh %s -dest %s -game %s", src.c_str(), dest.c_str(), game ); - if ( !ConvertMayaToMD5() ) { - gameLocal.Printf( "Failed to export '%s' : %s", src.c_str(), Maya_Error.c_str() ); - return false; - } - - return true; -} - -/* -==================== -idModelExport::ExportAnim -==================== -*/ -bool idModelExport::ExportAnim( const char *anim ) { - const char *game = cvarSystem->GetCVarString( "fs_game" ); - if ( strlen(game) == 0 ) { - game = BASE_GAMEDIR; - } - - Reset(); - src = anim; - dest = anim; - dest.SetFileExtension( MD5_ANIM_EXT ); - - sprintf( commandLine, "anim %s -dest %s -game %s", src.c_str(), dest.c_str(), game ); - if ( !ConvertMayaToMD5() ) { - gameLocal.Printf( "Failed to export '%s' : %s", src.c_str(), Maya_Error.c_str() ); - return false; - } - - return true; -} - -/* -==================== -idModelExport::ParseOptions -==================== -*/ -bool idModelExport::ParseOptions( idLexer &lex ) { - idToken token; - idStr destdir; - idStr sourcedir; - - if ( !lex.ReadToken( &token ) ) { - lex.Error( "Expected filename" ); - return false; - } - - src = token; - dest = token; - - while( lex.ReadToken( &token ) ) { - if ( token == "-" ) { - if ( !lex.ReadToken( &token ) ) { - lex.Error( "Expecting option" ); - return false; - } - if ( token == "sourcedir" ) { - if ( !lex.ReadToken( &token ) ) { - lex.Error( "Missing pathname after -sourcedir" ); - return false; - } - sourcedir = token; - } else if ( token == "destdir" ) { - if ( !lex.ReadToken( &token ) ) { - lex.Error( "Missing pathname after -destdir" ); - return false; - } - destdir = token; - } else if ( token == "dest" ) { - if ( !lex.ReadToken( &token ) ) { - lex.Error( "Missing filename after -dest" ); - return false; - } - dest = token; - } else { - commandLine += va( " -%s", token.c_str() ); - } - } else { - commandLine += va( " %s", token.c_str() ); - } - } - - if ( sourcedir.Length() ) { - src.StripPath(); - sourcedir.BackSlashesToSlashes(); - sprintf( src, "%s/%s", sourcedir.c_str(), src.c_str() ); - } - - if ( destdir.Length() ) { - dest.StripPath(); - destdir.BackSlashesToSlashes(); - sprintf( dest, "%s/%s", destdir.c_str(), dest.c_str() ); - } - - return true; -} - -/* -==================== -idModelExport::ParseExportSection -==================== -*/ -int idModelExport::ParseExportSection( idParser &parser ) { - idToken command; - idToken token; - idStr defaultCommands; - idLexer lex; - idStr temp; - idStr parms; - int count; - - const char *game = cvarSystem->GetCVarString( "fs_game" ); - - if ( strlen(game) == 0 ) { - game = BASE_GAMEDIR; - } - - // only export sections that match our export mask - if ( g_exportMask.GetString()[ 0 ] ) { - if ( parser.CheckTokenString( "{" ) ) { - parser.SkipBracedSection( false ); - return 0; - } - - parser.ReadToken( &token ); - if ( token.Icmp( g_exportMask.GetString() ) ) { - parser.SkipBracedSection(); - return 0; - } - parser.ExpectTokenString( "{" ); - } else if ( !parser.CheckTokenString( "{" ) ) { - // skip the export mask - parser.ReadToken( &token ); - parser.ExpectTokenString( "{" ); - } - - count = 0; - - lex.SetFlags( LEXFL_NOSTRINGCONCAT | LEXFL_ALLOWPATHNAMES | LEXFL_ALLOWMULTICHARLITERALS | LEXFL_ALLOWBACKSLASHSTRINGCONCAT ); - - while( 1 ) { - - if ( !parser.ReadToken( &command ) ) { - parser.Error( "Unexpoected end-of-file" ); - break; - } - - if ( command == "}" ) { - break; - } - - if ( command == "options" ) { - parser.ParseRestOfLine( defaultCommands ); - } else if ( command == "addoptions" ) { - parser.ParseRestOfLine( temp ); - defaultCommands += " "; - defaultCommands += temp; - } else if ( ( command == "mesh" ) || ( command == "anim" ) || ( command == "camera" ) ) { - if ( !parser.ReadToken( &token ) ) { - parser.Error( "Expected filename" ); - } - - temp = token; - parser.ParseRestOfLine( parms ); - - if ( defaultCommands.Length() ) { - sprintf( temp, "%s %s", temp.c_str(), defaultCommands.c_str() ); - } - - if ( parms.Length() ) { - sprintf( temp, "%s %s", temp.c_str(), parms.c_str() ); - } - - lex.LoadMemory( temp, temp.Length(), parser.GetFileName() ); - - Reset(); - if ( ParseOptions( lex ) ) { - const char *game = cvarSystem->GetCVarString( "fs_game" ); - if ( strlen(game) == 0 ) { - game = BASE_GAMEDIR; - } - - if ( command == "mesh" ) { - dest.SetFileExtension( MD5_MESH_EXT ); - } else if ( command == "anim" ) { - dest.SetFileExtension( MD5_ANIM_EXT ); - } else if ( command == "camera" ) { - dest.SetFileExtension( MD5_CAMERA_EXT ); - } else { - dest.SetFileExtension( command ); - } - idStr back = commandLine; - sprintf( commandLine, "%s %s -dest %s -game %s%s", command.c_str(), src.c_str(), dest.c_str(), game, commandLine.c_str() ); - if ( ConvertMayaToMD5() ) { - count++; - } else { - parser.Warning( "Failed to export '%s' : %s", src.c_str(), Maya_Error.c_str() ); - } - } - lex.FreeSource(); - } else { - parser.Error( "Unknown token: %s", command.c_str() ); - parser.SkipBracedSection( false ); - break; - } - } - - return count; -} - -/* -================ -idModelExport::ExportDefFile -================ -*/ -int idModelExport::ExportDefFile( const char *filename ) { - idParser parser( LEXFL_NOSTRINGCONCAT | LEXFL_ALLOWPATHNAMES | LEXFL_ALLOWMULTICHARLITERALS | LEXFL_ALLOWBACKSLASHSTRINGCONCAT ); - idToken token; - int count; - - count = 0; - - if ( !parser.LoadFile( filename ) ) { - gameLocal.Printf( "Could not load '%s'\n", filename ); - return 0; - } - - while( parser.ReadToken( &token ) ) { - if ( token == "export" ) { - count += ParseExportSection( parser ); - } else { - parser.ReadToken( &token ); - parser.SkipBracedSection(); - } - } - - return count; -} - -/* -================ -idModelExport::ExportModels -================ -*/ -int idModelExport::ExportModels( const char *pathname, const char *extension ) { - int count; - - count = 0; - - idFileList *files; - int i; - - if ( !CheckMayaInstall() ) { - // if Maya isn't installed, don't bother checking if we have anims to export - return 0; - } - - gameLocal.Printf( "----- Exporting models -----\n" ); - if ( !g_exportMask.GetString()[ 0 ] ) { - gameLocal.Printf( " Export mask: '%s'\n", g_exportMask.GetString() ); - } - - count = 0; - - files = fileSystem->ListFiles( pathname, extension ); - for( i = 0; i < files->GetNumFiles(); i++ ) { - count += ExportDefFile( va( "%s/%s", pathname, files->GetFile( i ) ) ); - } - fileSystem->FreeFileList( files ); - - gameLocal.Printf( "...%d models exported.\n", count ); - - return count; -} diff --git a/d3xp/anim/Anim_Testmodel.cpp b/d3xp/anim/Anim_Testmodel.cpp deleted file mode 100644 index d4cbc4cc..00000000 --- a/d3xp/anim/Anim_Testmodel.cpp +++ /dev/null @@ -1,931 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "renderer/ModelManager.h" - -#include "gamesys/SysCvar.h" -#include "Player.h" - -#include "anim/Anim_Testmodel.h" - -/* -============================================================================= - - MODEL TESTING - -Model viewing can begin with either "testmodel " - -The names must be the full pathname after the basedir, like -"models/weapons/v_launch/tris.md3" or "players/male/tris.md3" - -Extension will default to ".ase" if not specified. - -Testmodel will create a fake entity 100 units in front of the current view -position, directly facing the viewer. It will remain immobile, so you can -move around it to view it from different angles. - - g_testModelRotate - g_testModelAnimate - g_testModelBlend - -============================================================================= -*/ - -CLASS_DECLARATION( idAnimatedEntity, idTestModel ) - EVENT( EV_FootstepLeft, idTestModel::Event_Footstep ) - EVENT( EV_FootstepRight, idTestModel::Event_Footstep ) -END_CLASS - -/* -================ -idTestModel::idTestModel -================ -*/ -idTestModel::idTestModel() { - head = NULL; - headAnimator = NULL; - anim = 0; - headAnim = 0; - starttime = 0; - animtime = 0; - mode = 0; - frame = 0; -} - -/* -================ -idTestModel::Save -================ -*/ -void idTestModel::Save( idSaveGame *savefile ) { -} - -/* -================ -idTestModel::Restore -================ -*/ -void idTestModel::Restore( idRestoreGame *savefile ) { - // FIXME: one day we may actually want to save/restore test models, but for now we'll just delete them - delete this; -} - -/* -================ -idTestModel::Spawn -================ -*/ -void idTestModel::Spawn( void ) { - idVec3 size; - idBounds bounds; - const char *headModel; - jointHandle_t joint; - idStr jointName; - idVec3 origin, modelOffset; - idMat3 axis; - const idKeyValue *kv; - copyJoints_t copyJoint; - - if ( renderEntity.hModel && renderEntity.hModel->IsDefaultModel() && !animator.ModelDef() ) { - gameLocal.Warning( "Unable to create testmodel for '%s' : model defaulted", spawnArgs.GetString( "model" ) ); - PostEventMS( &EV_Remove, 0 ); - return; - } - - mode = g_testModelAnimate.GetInteger(); - animator.RemoveOriginOffset( g_testModelAnimate.GetInteger() == 1 ); - - physicsObj.SetSelf( this ); - physicsObj.SetOrigin( GetPhysics()->GetOrigin() ); - physicsObj.SetAxis( GetPhysics()->GetAxis() ); - - if ( spawnArgs.GetVector( "mins", NULL, bounds[0] ) ) { - spawnArgs.GetVector( "maxs", NULL, bounds[1] ); - physicsObj.SetClipBox( bounds, 1.0f ); - physicsObj.SetContents( 0 ); - } else if ( spawnArgs.GetVector( "size", NULL, size ) ) { - bounds[ 0 ].Set( size.x * -0.5f, size.y * -0.5f, 0.0f ); - bounds[ 1 ].Set( size.x * 0.5f, size.y * 0.5f, size.z ); - physicsObj.SetClipBox( bounds, 1.0f ); - physicsObj.SetContents( 0 ); - } - - spawnArgs.GetVector( "offsetModel", "0 0 0", modelOffset ); - - // add the head model if it has one - headModel = spawnArgs.GetString( "def_head", "" ); - if ( headModel[ 0 ] ) { - jointName = spawnArgs.GetString( "head_joint" ); - joint = animator.GetJointHandle( jointName ); - if ( joint == INVALID_JOINT ) { - gameLocal.Warning( "Joint '%s' not found for 'head_joint'", jointName.c_str() ); - } else { - // copy any sounds in case we have frame commands on the head - idDict args; - const idKeyValue *sndKV = spawnArgs.MatchPrefix( "snd_", NULL ); - while( sndKV ) { - args.Set( sndKV->GetKey(), sndKV->GetValue() ); - sndKV = spawnArgs.MatchPrefix( "snd_", sndKV ); - } - - head = gameLocal.SpawnEntityType( idAnimatedEntity::Type, &args ); - animator.GetJointTransform( joint, gameLocal.time, origin, axis ); - origin = GetPhysics()->GetOrigin() + ( origin + modelOffset ) * GetPhysics()->GetAxis(); - head.GetEntity()->SetModel( headModel ); - head.GetEntity()->SetOrigin( origin ); - head.GetEntity()->SetAxis( GetPhysics()->GetAxis() ); - head.GetEntity()->BindToJoint( this, animator.GetJointName( joint ), true ); - - headAnimator = head.GetEntity()->GetAnimator(); - - // set up the list of joints to copy to the head - for( kv = spawnArgs.MatchPrefix( "copy_joint", NULL ); kv != NULL; kv = spawnArgs.MatchPrefix( "copy_joint", kv ) ) { - jointName = kv->GetKey(); - - if ( jointName.StripLeadingOnce( "copy_joint_world " ) ) { - copyJoint.mod = JOINTMOD_WORLD_OVERRIDE; - } else { - jointName.StripLeadingOnce( "copy_joint " ); - copyJoint.mod = JOINTMOD_LOCAL_OVERRIDE; - } - - copyJoint.from = animator.GetJointHandle( jointName ); - if ( copyJoint.from == INVALID_JOINT ) { - gameLocal.Warning( "Unknown copy_joint '%s'", jointName.c_str() ); - continue; - } - - copyJoint.to = headAnimator->GetJointHandle( jointName ); - if ( copyJoint.to == INVALID_JOINT ) { - gameLocal.Warning( "Unknown copy_joint '%s' on head", jointName.c_str() ); - continue; - } - - copyJoints.Append( copyJoint ); - } - } - } - - // start any shader effects based off of the spawn time - renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time ); - - SetPhysics( &physicsObj ); - - gameLocal.Printf( "Added testmodel at origin = '%s', angles = '%s'\n", GetPhysics()->GetOrigin().ToString(), GetPhysics()->GetAxis().ToAngles().ToString() ); - BecomeActive( TH_THINK ); -} - -/* -================ -idTestModel::~idTestModel -================ -*/ -idTestModel::~idTestModel() { - StopSound( SND_CHANNEL_ANY, false ); - if ( renderEntity.hModel ) { - gameLocal.Printf( "Removing testmodel %s\n", renderEntity.hModel->Name() ); - } else { - gameLocal.Printf( "Removing testmodel\n" ); - } - if ( gameLocal.testmodel == this ) { - gameLocal.testmodel = NULL; - } - if ( head.GetEntity() ) { - head.GetEntity()->StopSound( SND_CHANNEL_ANY, false ); - head.GetEntity()->PostEventMS( &EV_Remove, 0 ); - } -} - -/* -=============== -idTestModel::Event_Footstep -=============== -*/ -void idTestModel::Event_Footstep( void ) { - StartSound( "snd_footstep", SND_CHANNEL_BODY, 0, false, NULL ); -} - -/* -================ -idTestModel::ShouldConstructScriptObjectAtSpawn - -Called during idEntity::Spawn to see if it should construct the script object or not. -Overridden by subclasses that need to spawn the script object themselves. -================ -*/ -bool idTestModel::ShouldConstructScriptObjectAtSpawn( void ) const { - return false; -} - -/* -================ -idTestModel::Think -================ -*/ -void idTestModel::Think( void ) { - idVec3 pos; - idMat3 axis; - idAngles ang; - int i; - - if ( thinkFlags & TH_THINK ) { - if ( anim && ( gameLocal.testmodel == this ) && ( mode != g_testModelAnimate.GetInteger() ) ) { - StopSound( SND_CHANNEL_ANY, false ); - if ( head.GetEntity() ) { - head.GetEntity()->StopSound( SND_CHANNEL_ANY, false ); - } - switch( g_testModelAnimate.GetInteger() ) { - default: - case 0: - // cycle anim with origin reset - if ( animator.NumFrames( anim ) <= 1 ) { - // single frame animations end immediately, so just cycle it since it's the same result - animator.CycleAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) ); - if ( headAnim ) { - headAnimator->CycleAnim( ANIMCHANNEL_ALL, headAnim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) ); - } - } else { - animator.PlayAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) ); - if ( headAnim ) { - headAnimator->PlayAnim( ANIMCHANNEL_ALL, headAnim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) ); - if ( headAnimator->AnimLength( headAnim ) > animator.AnimLength( anim ) ) { - // loop the body anim when the head anim is longer - animator.CurrentAnim( ANIMCHANNEL_ALL )->SetCycleCount( -1 ); - } - } - } - animator.RemoveOriginOffset( false ); - break; - - case 1: - // cycle anim with fixed origin - animator.CycleAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) ); - animator.RemoveOriginOffset( true ); - if ( headAnim ) { - headAnimator->CycleAnim( ANIMCHANNEL_ALL, headAnim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) ); - } - break; - - case 2: - // cycle anim with continuous origin - animator.CycleAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) ); - animator.RemoveOriginOffset( false ); - if ( headAnim ) { - headAnimator->CycleAnim( ANIMCHANNEL_ALL, headAnim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) ); - } - break; - - case 3: - // frame by frame with continuous origin - animator.SetFrame( ANIMCHANNEL_ALL, anim, frame, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) ); - animator.RemoveOriginOffset( false ); - if ( headAnim ) { - headAnimator->SetFrame( ANIMCHANNEL_ALL, headAnim, frame, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) ); - } - break; - - case 4: - // play anim once - animator.PlayAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) ); - animator.RemoveOriginOffset( false ); - if ( headAnim ) { - headAnimator->PlayAnim( ANIMCHANNEL_ALL, headAnim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) ); - } - break; - - case 5: - // frame by frame with fixed origin - animator.SetFrame( ANIMCHANNEL_ALL, anim, frame, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) ); - animator.RemoveOriginOffset( true ); - if ( headAnim ) { - headAnimator->SetFrame( ANIMCHANNEL_ALL, headAnim, frame, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) ); - } - break; - } - - mode = g_testModelAnimate.GetInteger(); - } - - if ( ( mode == 0 ) && ( gameLocal.time >= starttime + animtime ) ) { - starttime = gameLocal.time; - StopSound( SND_CHANNEL_ANY, false ); - animator.PlayAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) ); - if ( headAnim ) { - headAnimator->PlayAnim( ANIMCHANNEL_ALL, headAnim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) ); - if ( headAnimator->AnimLength( headAnim ) > animator.AnimLength( anim ) ) { - // loop the body anim when the head anim is longer - animator.CurrentAnim( ANIMCHANNEL_ALL )->SetCycleCount( -1 ); - } - } - } - - if ( headAnimator ) { - // copy the animation from the body to the head - for( i = 0; i < copyJoints.Num(); i++ ) { - if ( copyJoints[ i ].mod == JOINTMOD_WORLD_OVERRIDE ) { - idMat3 mat = head.GetEntity()->GetPhysics()->GetAxis().Transpose(); - GetJointWorldTransform( copyJoints[ i ].from, gameLocal.time, pos, axis ); - pos -= head.GetEntity()->GetPhysics()->GetOrigin(); - headAnimator->SetJointPos( copyJoints[ i ].to, copyJoints[ i ].mod, pos * mat ); - headAnimator->SetJointAxis( copyJoints[ i ].to, copyJoints[ i ].mod, axis * mat ); - } else { - animator.GetJointLocalTransform( copyJoints[ i ].from, gameLocal.time, pos, axis ); - headAnimator->SetJointPos( copyJoints[ i ].to, copyJoints[ i ].mod, pos ); - headAnimator->SetJointAxis( copyJoints[ i ].to, copyJoints[ i ].mod, axis ); - } - } - } - - // update rotation - RunPhysics(); - - physicsObj.GetAngles( ang ); - physicsObj.SetAngularExtrapolation( extrapolation_t(EXTRAPOLATION_LINEAR|EXTRAPOLATION_NOSTOP), gameLocal.time, 0, ang, idAngles( 0, g_testModelRotate.GetFloat() * 360.0f / 60.0f, 0 ), ang_zero ); - - idClipModel *clip = physicsObj.GetClipModel(); - if ( clip && animator.ModelDef() ) { - idVec3 neworigin; - idMat3 axis; - jointHandle_t joint; - - joint = animator.GetJointHandle( "origin" ); - animator.GetJointTransform( joint, gameLocal.time, neworigin, axis ); - neworigin = ( ( neworigin - animator.ModelDef()->GetVisualOffset() ) * physicsObj.GetAxis() ) + GetPhysics()->GetOrigin(); - clip->Link( gameLocal.clip, this, 0, neworigin, clip->GetAxis() ); - } - } - - UpdateAnimation(); - Present(); - - if ( ( gameLocal.testmodel == this ) && g_showTestModelFrame.GetInteger() && anim ) { - gameLocal.Printf( "^5 Anim: ^7%s ^5Frame: ^7%d/%d Time: %.3f\n", animator.AnimFullName( anim ), animator.CurrentAnim( ANIMCHANNEL_ALL )->GetFrameNumber( gameLocal.time ), - animator.CurrentAnim( ANIMCHANNEL_ALL )->NumFrames(), MS2SEC( gameLocal.time - animator.CurrentAnim( ANIMCHANNEL_ALL )->GetStartTime() ) ); - if ( headAnim ) { - gameLocal.Printf( "^5 Head: ^7%s ^5Frame: ^7%d/%d Time: %.3f\n\n", headAnimator->AnimFullName( headAnim ), headAnimator->CurrentAnim( ANIMCHANNEL_ALL )->GetFrameNumber( gameLocal.time ), - headAnimator->CurrentAnim( ANIMCHANNEL_ALL )->NumFrames(), MS2SEC( gameLocal.time - headAnimator->CurrentAnim( ANIMCHANNEL_ALL )->GetStartTime() ) ); - } else { - gameLocal.Printf( "\n\n" ); - } - } -} - -/* -================ -idTestModel::NextAnim -================ -*/ -void idTestModel::NextAnim( const idCmdArgs &args ) { - if ( !animator.NumAnims() ) { - return; - } - - anim++; - if ( anim >= animator.NumAnims() ) { - // anim 0 is no anim - anim = 1; - } - - starttime = gameLocal.time; - animtime = animator.AnimLength( anim ); - animname = animator.AnimFullName( anim ); - headAnim = 0; - if ( headAnimator ) { - headAnimator->ClearAllAnims( gameLocal.time, 0 ); - headAnim = headAnimator->GetAnim( animname ); - if ( !headAnim ) { - headAnim = headAnimator->GetAnim( "idle" ); - } - - if ( headAnim && ( headAnimator->AnimLength( headAnim ) > animtime ) ) { - animtime = headAnimator->AnimLength( headAnim ); - } - } - - gameLocal.Printf( "anim '%s', %d.%03d seconds, %d frames\n", animname.c_str(), animator.AnimLength( anim ) / 1000, animator.AnimLength( anim ) % 1000, animator.NumFrames( anim ) ); - if ( headAnim ) { - gameLocal.Printf( "head '%s', %d.%03d seconds, %d frames\n", headAnimator->AnimFullName( headAnim ), headAnimator->AnimLength( headAnim ) / 1000, headAnimator->AnimLength( headAnim ) % 1000, headAnimator->NumFrames( headAnim ) ); - } - - // reset the anim - mode = -1; - frame = 1; -} - -/* -================ -idTestModel::PrevAnim -================ -*/ -void idTestModel::PrevAnim( const idCmdArgs &args ) { - if ( !animator.NumAnims() ) { - return; - } - - headAnim = 0; - anim--; - if ( anim < 0 ) { - anim = animator.NumAnims() - 1; - } - - starttime = gameLocal.time; - animtime = animator.AnimLength( anim ); - animname = animator.AnimFullName( anim ); - headAnim = 0; - if ( headAnimator ) { - headAnimator->ClearAllAnims( gameLocal.time, 0 ); - headAnim = headAnimator->GetAnim( animname ); - if ( !headAnim ) { - headAnim = headAnimator->GetAnim( "idle" ); - } - - if ( headAnim && ( headAnimator->AnimLength( headAnim ) > animtime ) ) { - animtime = headAnimator->AnimLength( headAnim ); - } - } - - gameLocal.Printf( "anim '%s', %d.%03d seconds, %d frames\n", animname.c_str(), animator.AnimLength( anim ) / 1000, animator.AnimLength( anim ) % 1000, animator.NumFrames( anim ) ); - if ( headAnim ) { - gameLocal.Printf( "head '%s', %d.%03d seconds, %d frames\n", headAnimator->AnimFullName( headAnim ), headAnimator->AnimLength( headAnim ) / 1000, headAnimator->AnimLength( headAnim ) % 1000, headAnimator->NumFrames( headAnim ) ); - } - - // reset the anim - mode = -1; - frame = 1; -} - -/* -================ -idTestModel::NextFrame -================ -*/ -void idTestModel::NextFrame( const idCmdArgs &args ) { - if ( !anim || ( ( g_testModelAnimate.GetInteger() != 3 ) && ( g_testModelAnimate.GetInteger() != 5 ) ) ) { - return; - } - - frame++; - if ( frame > animator.NumFrames( anim ) ) { - frame = 1; - } - - gameLocal.Printf( "^5 Anim: ^7%s\n^5Frame: ^7%d/%d\n\n", animator.AnimFullName( anim ), frame, animator.NumFrames( anim ) ); - - // reset the anim - mode = -1; -} - -/* -================ -idTestModel::PrevFrame -================ -*/ -void idTestModel::PrevFrame( const idCmdArgs &args ) { - if ( !anim || ( ( g_testModelAnimate.GetInteger() != 3 ) && ( g_testModelAnimate.GetInteger() != 5 ) ) ) { - return; - } - - frame--; - if ( frame < 1 ) { - frame = animator.NumFrames( anim ); - } - - gameLocal.Printf( "^5 Anim: ^7%s\n^5Frame: ^7%d/%d\n\n", animator.AnimFullName( anim ), frame, animator.NumFrames( anim ) ); - - // reset the anim - mode = -1; -} - -/* -================ -idTestModel::TestAnim -================ -*/ -void idTestModel::TestAnim( const idCmdArgs &args ) { - idStr name; - int animNum; - //const idAnim *newanim; - - if ( args.Argc() < 2 ) { - gameLocal.Printf( "usage: testanim \n" ); - return; - } - - //newanim = NULL; - - name = args.Argv( 1 ); -#if 0 - if ( strstr( name, ".ma" ) || strstr( name, ".mb" ) ) { - const idMD5Anim *md5anims[ ANIM_MaxSyncedAnims ]; - idModelExport exporter; - exporter.ExportAnim( name ); - name.SetFileExtension( MD5_ANIM_EXT ); - md5anims[ 0 ] = animationLib.GetAnim( name ); - if ( md5anims[ 0 ] ) { - customAnim.SetAnim( animator.ModelDef(), name, name, 1, md5anims ); - newanim = &customAnim; - } - } else { - animNum = animator.GetAnim( name ); - } -#else - animNum = animator.GetAnim( name ); -#endif - - if ( !animNum ) { - gameLocal.Printf( "Animation '%s' not found.\n", name.c_str() ); - return; - } - - anim = animNum; - starttime = gameLocal.time; - animtime = animator.AnimLength( anim ); - headAnim = 0; - if ( headAnimator ) { - headAnimator->ClearAllAnims( gameLocal.time, 0 ); - headAnim = headAnimator->GetAnim( animname ); - if ( !headAnim ) { - headAnim = headAnimator->GetAnim( "idle" ); - if ( !headAnim ) { - gameLocal.Printf( "Missing 'idle' anim for head.\n" ); - } - } - - if ( headAnim && ( headAnimator->AnimLength( headAnim ) > animtime ) ) { - animtime = headAnimator->AnimLength( headAnim ); - } - } - - animname = name; - gameLocal.Printf( "anim '%s', %d.%03d seconds, %d frames\n", animname.c_str(), animator.AnimLength( anim ) / 1000, animator.AnimLength( anim ) % 1000, animator.NumFrames( anim ) ); - - // reset the anim - mode = -1; -} - -/* -===================== -idTestModel::BlendAnim -===================== -*/ -void idTestModel::BlendAnim( const idCmdArgs &args ) { - int anim1; - int anim2; - - if ( args.Argc() < 4 ) { - gameLocal.Printf( "usage: testblend \n" ); - return; - } - - anim1 = gameLocal.testmodel->animator.GetAnim( args.Argv( 1 ) ); - if ( !anim1 ) { - gameLocal.Printf( "Animation '%s' not found.\n", args.Argv( 1 ) ); - return; - } - - anim2 = gameLocal.testmodel->animator.GetAnim( args.Argv( 2 ) ); - if ( !anim2 ) { - gameLocal.Printf( "Animation '%s' not found.\n", args.Argv( 2 ) ); - return; - } - - animname = args.Argv( 2 ); - animator.CycleAnim( ANIMCHANNEL_ALL, anim1, gameLocal.time, 0 ); - animator.CycleAnim( ANIMCHANNEL_ALL, anim2, gameLocal.time, FRAME2MS( atoi( args.Argv( 3 ) ) ) ); - - anim = anim2; - headAnim = 0; -} - -/*********************************************************************** - - Testmodel console commands - -***********************************************************************/ - -/* -================= -idTestModel::KeepTestModel_f - -Makes the current test model permanent, allowing you to place -multiple test models -================= -*/ -void idTestModel::KeepTestModel_f( const idCmdArgs &args ) { - if ( !gameLocal.testmodel ) { - gameLocal.Printf( "No active testModel.\n" ); - return; - } - - gameLocal.Printf( "modelDef %p kept\n", gameLocal.testmodel->renderEntity.hModel ); - - gameLocal.testmodel = NULL; -} - -/* -================= -idTestModel::TestSkin_f - -Sets a skin on an existing testModel -================= -*/ -void idTestModel::TestSkin_f( const idCmdArgs &args ) { - idVec3 offset; - idStr name; - idPlayer * player; - idDict dict; - - player = gameLocal.GetLocalPlayer(); - if ( !player || !gameLocal.CheatsOk() ) { - return; - } - - // delete the testModel if active - if ( !gameLocal.testmodel ) { - common->Printf( "No active testModel\n" ); - return; - } - - if ( args.Argc() < 2 ) { - common->Printf( "removing testSkin.\n" ); - gameLocal.testmodel->SetSkin( NULL ); - return; - } - - name = args.Argv( 1 ); - gameLocal.testmodel->SetSkin( declManager->FindSkin( name ) ); -} - -/* -================= -idTestModel::TestShaderParm_f - -Sets a shaderParm on an existing testModel -================= -*/ -void idTestModel::TestShaderParm_f( const idCmdArgs &args ) { - idVec3 offset; - idStr name; - idPlayer * player; - idDict dict; - - player = gameLocal.GetLocalPlayer(); - if ( !player || !gameLocal.CheatsOk() ) { - return; - } - - // delete the testModel if active - if ( !gameLocal.testmodel ) { - common->Printf( "No active testModel\n" ); - return; - } - - if ( args.Argc() != 3 ) { - common->Printf( "USAGE: testShaderParm \n" ); - return; - } - - int parm = atoi( args.Argv( 1 ) ); - if ( parm < 0 || parm >= MAX_ENTITY_SHADER_PARMS ) { - common->Printf( "parmNum %i out of range\n", parm ); - return; - } - - float value; - if ( !idStr::Icmp( args.Argv( 2 ), "time" ) ) { - value = gameLocal.time * -0.001; - } else { - value = atof( args.Argv( 2 ) ); - } - - gameLocal.testmodel->SetShaderParm( parm, value ); -} - -/* -================= -idTestModel::TestModel_f - -Creates a static modelDef in front of the current position, which -can then be moved around -================= -*/ -void idTestModel::TestModel_f( const idCmdArgs &args ) { - idVec3 offset; - idStr name; - idPlayer * player; - const idDict * entityDef; - idDict dict; - - player = gameLocal.GetLocalPlayer(); - if ( !player || !gameLocal.CheatsOk() ) { - return; - } - - // delete the testModel if active - if ( gameLocal.testmodel ) { - delete gameLocal.testmodel; - gameLocal.testmodel = NULL; - } - - if ( args.Argc() < 2 ) { - return; - } - - name = args.Argv( 1 ); - - entityDef = gameLocal.FindEntityDefDict( name, false ); - if ( entityDef ) { - dict = *entityDef; - } else { - if ( declManager->FindType( DECL_MODELDEF, name, false ) ) { - dict.Set( "model", name ); - } else { - // allow map models with underscore prefixes to be tested during development - // without appending an ase - if ( name[ 0 ] != '_' ) { - name.DefaultFileExtension( ".ase" ); - } - -#ifndef _D3XP - // Maya ascii format is supported natively now - if ( strstr( name, ".ma" ) || strstr( name, ".mb" ) ) { - idModelExport exporter; - exporter.ExportModel( name ); - name.SetFileExtension( MD5_MESH_EXT ); - } -#endif - - if ( !renderModelManager->CheckModel( name ) ) { - gameLocal.Printf( "Can't register model\n" ); - return; - } - dict.Set( "model", name ); - } - } - - offset = player->GetPhysics()->GetOrigin() + player->viewAngles.ToForward() * 100.0f; - - dict.Set( "origin", offset.ToString() ); - dict.Set( "angle", va( "%f", player->viewAngles.yaw + 180.0f ) ); - gameLocal.testmodel = ( idTestModel * )gameLocal.SpawnEntityType( idTestModel::Type, &dict ); - gameLocal.testmodel->renderEntity.shaderParms[SHADERPARM_TIMEOFFSET] = -MS2SEC( gameLocal.time ); -} - -/* -===================== -idTestModel::ArgCompletion_TestModel -===================== -*/ -void idTestModel::ArgCompletion_TestModel( const idCmdArgs &args, void(*callback)( const char *s ) ) { - int i, num; - - num = declManager->GetNumDecls( DECL_ENTITYDEF ); - for ( i = 0; i < num; i++ ) { - callback( idStr( args.Argv( 0 ) ) + " " + declManager->DeclByIndex( DECL_ENTITYDEF, i , false )->GetName() ); - } - num = declManager->GetNumDecls( DECL_MODELDEF ); - for ( i = 0; i < num; i++ ) { - callback( idStr( args.Argv( 0 ) ) + " " + declManager->DeclByIndex( DECL_MODELDEF, i , false )->GetName() ); - } - cmdSystem->ArgCompletion_FolderExtension( args, callback, "models/", false, ".lwo", ".ase", ".md5mesh", ".ma", ".mb", NULL ); -} - -/* -===================== -idTestModel::TestParticleStopTime_f -===================== -*/ -void idTestModel::TestParticleStopTime_f( const idCmdArgs &args ) { - if ( !gameLocal.testmodel ) { - gameLocal.Printf( "No testModel active.\n" ); - return; - } - - gameLocal.testmodel->renderEntity.shaderParms[SHADERPARM_PARTICLE_STOPTIME] = MS2SEC( gameLocal.time ); - gameLocal.testmodel->UpdateVisuals(); -} - -/* -===================== -idTestModel::TestAnim_f -===================== -*/ -void idTestModel::TestAnim_f( const idCmdArgs &args ) { - if ( !gameLocal.testmodel ) { - gameLocal.Printf( "No testModel active.\n" ); - return; - } - - gameLocal.testmodel->TestAnim( args ); -} - - -/* -===================== -idTestModel::ArgCompletion_TestAnim -===================== -*/ -void idTestModel::ArgCompletion_TestAnim( const idCmdArgs &args, void(*callback)( const char *s ) ) { - if ( gameLocal.testmodel ) { - idAnimator *animator = gameLocal.testmodel->GetAnimator(); - for( int i = 0; i < animator->NumAnims(); i++ ) { - callback( va( "%s %s", args.Argv( 0 ), animator->AnimFullName( i ) ) ); - } - } -} - -/* -===================== -idTestModel::TestBlend_f -===================== -*/ -void idTestModel::TestBlend_f( const idCmdArgs &args ) { - if ( !gameLocal.testmodel ) { - gameLocal.Printf( "No testModel active.\n" ); - return; - } - - gameLocal.testmodel->BlendAnim( args ); -} - -/* -===================== -idTestModel::TestModelNextAnim_f -===================== -*/ -void idTestModel::TestModelNextAnim_f( const idCmdArgs &args ) { - if ( !gameLocal.testmodel ) { - gameLocal.Printf( "No testModel active.\n" ); - return; - } - - gameLocal.testmodel->NextAnim( args ); -} - -/* -===================== -idTestModel::TestModelPrevAnim_f -===================== -*/ -void idTestModel::TestModelPrevAnim_f( const idCmdArgs &args ) { - if ( !gameLocal.testmodel ) { - gameLocal.Printf( "No testModel active.\n" ); - return; - } - - gameLocal.testmodel->PrevAnim( args ); -} - -/* -===================== -idTestModel::TestModelNextFrame_f -===================== -*/ -void idTestModel::TestModelNextFrame_f( const idCmdArgs &args ) { - if ( !gameLocal.testmodel ) { - gameLocal.Printf( "No testModel active.\n" ); - return; - } - - gameLocal.testmodel->NextFrame( args ); -} - -/* -===================== -idTestModel::TestModelPrevFrame_f -===================== -*/ -void idTestModel::TestModelPrevFrame_f( const idCmdArgs &args ) { - if ( !gameLocal.testmodel ) { - gameLocal.Printf( "No testModel active.\n" ); - return; - } - - gameLocal.testmodel->PrevFrame( args ); -} diff --git a/d3xp/anim/Anim_Testmodel.h b/d3xp/anim/Anim_Testmodel.h deleted file mode 100644 index 398b7b59..00000000 --- a/d3xp/anim/Anim_Testmodel.h +++ /dev/null @@ -1,99 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __ANIM_TESTMODEL_H__ -#define __ANIM_TESTMODEL_H__ - -#include "physics/Physics_Parametric.h" -#include "Entity.h" -#include "Actor.h" - -/* -============================================================================================== - - idTestModel - -============================================================================================== -*/ - -class idTestModel : public idAnimatedEntity { -public: - CLASS_PROTOTYPE( idTestModel ); - - idTestModel(); - ~idTestModel(); - - void Save( idSaveGame *savefile ); - void Restore( idRestoreGame *savefile ); - - void Spawn( void ); - - virtual bool ShouldConstructScriptObjectAtSpawn( void ) const; - - void NextAnim( const idCmdArgs &args ); - void PrevAnim( const idCmdArgs &args ); - void NextFrame( const idCmdArgs &args ); - void PrevFrame( const idCmdArgs &args ); - void TestAnim( const idCmdArgs &args ); - void BlendAnim( const idCmdArgs &args ); - - static void KeepTestModel_f( const idCmdArgs &args ); - static void TestModel_f( const idCmdArgs &args ); - static void ArgCompletion_TestModel( const idCmdArgs &args, void(*callback)( const char *s ) ); - static void TestSkin_f( const idCmdArgs &args ); - static void TestShaderParm_f( const idCmdArgs &args ); - static void TestParticleStopTime_f( const idCmdArgs &args ); - static void TestAnim_f( const idCmdArgs &args ); - static void ArgCompletion_TestAnim( const idCmdArgs &args, void(*callback)( const char *s ) ); - static void TestBlend_f( const idCmdArgs &args ); - static void TestModelNextAnim_f( const idCmdArgs &args ); - static void TestModelPrevAnim_f( const idCmdArgs &args ); - static void TestModelNextFrame_f( const idCmdArgs &args ); - static void TestModelPrevFrame_f( const idCmdArgs &args ); - -private: - idEntityPtr head; - idAnimator *headAnimator; - idAnim customAnim; - idPhysics_Parametric physicsObj; - idStr animname; - int anim; - int headAnim; - int mode; - int frame; - int starttime; - int animtime; - - idList copyJoints; - - virtual void Think( void ); - - void Event_Footstep( void ); -}; - -#endif /* !__ANIM_TESTMODEL_H__*/ diff --git a/d3xp/gamesys/Callbacks.cpp b/d3xp/gamesys/Callbacks.cpp deleted file mode 100644 index 1757dcd3..00000000 --- a/d3xp/gamesys/Callbacks.cpp +++ /dev/null @@ -1,2626 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ -// generated file - see CREATE_EVENT_CODE - - /******************************************************* - - 1 args - - *******************************************************/ - - case 512 : - typedef void ( idClass::*eventCallback_i_t )( const intptr_t ); - ( this->*( eventCallback_i_t )callback )( data[ 0 ] ); - break; - - case 513 : - typedef void ( idClass::*eventCallback_f_t )( const float ); - ( this->*( eventCallback_f_t )callback )( *( float * )&data[ 0 ] ); - break; - - /******************************************************* - - 2 args - - *******************************************************/ - - case 1024 : - typedef void ( idClass::*eventCallback_ii_t )( const intptr_t, const intptr_t ); - ( this->*( eventCallback_ii_t )callback )( data[ 0 ], data[ 1 ] ); - break; - - case 1025 : - typedef void ( idClass::*eventCallback_fi_t )( const float, const intptr_t ); - ( this->*( eventCallback_fi_t )callback )( *( float * )&data[ 0 ], data[ 1 ] ); - break; - - case 1026 : - typedef void ( idClass::*eventCallback_if_t )( const intptr_t, const float ); - ( this->*( eventCallback_if_t )callback )( data[ 0 ], *( float * )&data[ 1 ] ); - break; - - case 1027 : - typedef void ( idClass::*eventCallback_ff_t )( const float, const float ); - ( this->*( eventCallback_ff_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ] ); - break; - - /******************************************************* - - 3 args - - *******************************************************/ - - case 2048 : - typedef void ( idClass::*eventCallback_iii_t )( const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iii_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ] ); - break; - - case 2049 : - typedef void ( idClass::*eventCallback_fii_t )( const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fii_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ] ); - break; - - case 2050 : - typedef void ( idClass::*eventCallback_ifi_t )( const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_ifi_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ] ); - break; - - case 2051 : - typedef void ( idClass::*eventCallback_ffi_t )( const float, const float, const intptr_t ); - ( this->*( eventCallback_ffi_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ] ); - break; - - case 2052 : - typedef void ( idClass::*eventCallback_iif_t )( const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_iif_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ] ); - break; - - case 2053 : - typedef void ( idClass::*eventCallback_fif_t )( const float, const intptr_t, const float ); - ( this->*( eventCallback_fif_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ] ); - break; - - case 2054 : - typedef void ( idClass::*eventCallback_iff_t )( const intptr_t, const float, const float ); - ( this->*( eventCallback_iff_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ] ); - break; - - case 2055 : - typedef void ( idClass::*eventCallback_fff_t )( const float, const float, const float ); - ( this->*( eventCallback_fff_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ] ); - break; - - /******************************************************* - - 4 args - - *******************************************************/ - - case 4096 : - typedef void ( idClass::*eventCallback_iiii_t )( const intptr_t, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iiii_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ] ); - break; - - case 4097 : - typedef void ( idClass::*eventCallback_fiii_t )( const float, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fiii_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ] ); - break; - - case 4098 : - typedef void ( idClass::*eventCallback_ifii_t )( const intptr_t, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ifii_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ] ); - break; - - case 4099 : - typedef void ( idClass::*eventCallback_ffii_t )( const float, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ffii_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ] ); - break; - - case 4100 : - typedef void ( idClass::*eventCallback_iifi_t )( const intptr_t, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_iifi_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ] ); - break; - - case 4101 : - typedef void ( idClass::*eventCallback_fifi_t )( const float, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_fifi_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ] ); - break; - - case 4102 : - typedef void ( idClass::*eventCallback_iffi_t )( const intptr_t, const float, const float, const intptr_t ); - ( this->*( eventCallback_iffi_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ] ); - break; - - case 4103 : - typedef void ( idClass::*eventCallback_fffi_t )( const float, const float, const float, const intptr_t ); - ( this->*( eventCallback_fffi_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ] ); - break; - - case 4104 : - typedef void ( idClass::*eventCallback_iiif_t )( const intptr_t, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_iiif_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ] ); - break; - - case 4105 : - typedef void ( idClass::*eventCallback_fiif_t )( const float, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_fiif_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ] ); - break; - - case 4106 : - typedef void ( idClass::*eventCallback_ifif_t )( const intptr_t, const float, const intptr_t, const float ); - ( this->*( eventCallback_ifif_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ] ); - break; - - case 4107 : - typedef void ( idClass::*eventCallback_ffif_t )( const float, const float, const intptr_t, const float ); - ( this->*( eventCallback_ffif_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ] ); - break; - - case 4108 : - typedef void ( idClass::*eventCallback_iiff_t )( const intptr_t, const intptr_t, const float, const float ); - ( this->*( eventCallback_iiff_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ] ); - break; - - case 4109 : - typedef void ( idClass::*eventCallback_fiff_t )( const float, const intptr_t, const float, const float ); - ( this->*( eventCallback_fiff_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ] ); - break; - - case 4110 : - typedef void ( idClass::*eventCallback_ifff_t )( const intptr_t, const float, const float, const float ); - ( this->*( eventCallback_ifff_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ] ); - break; - - case 4111 : - typedef void ( idClass::*eventCallback_ffff_t )( const float, const float, const float, const float ); - ( this->*( eventCallback_ffff_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ] ); - break; - - /******************************************************* - - 5 args - - *******************************************************/ - - case 8192 : - typedef void ( idClass::*eventCallback_iiiii_t )( const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iiiii_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ] ); - break; - - case 8193 : - typedef void ( idClass::*eventCallback_fiiii_t )( const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fiiii_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ] ); - break; - - case 8194 : - typedef void ( idClass::*eventCallback_ifiii_t )( const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ifiii_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ] ); - break; - - case 8195 : - typedef void ( idClass::*eventCallback_ffiii_t )( const float, const float, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ffiii_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ] ); - break; - - case 8196 : - typedef void ( idClass::*eventCallback_iifii_t )( const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iifii_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ] ); - break; - - case 8197 : - typedef void ( idClass::*eventCallback_fifii_t )( const float, const intptr_t, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fifii_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ] ); - break; - - case 8198 : - typedef void ( idClass::*eventCallback_iffii_t )( const intptr_t, const float, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iffii_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ] ); - break; - - case 8199 : - typedef void ( idClass::*eventCallback_fffii_t )( const float, const float, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fffii_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ] ); - break; - - case 8200 : - typedef void ( idClass::*eventCallback_iiifi_t )( const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_iiifi_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ] ); - break; - - case 8201 : - typedef void ( idClass::*eventCallback_fiifi_t )( const float, const intptr_t, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_fiifi_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ] ); - break; - - case 8202 : - typedef void ( idClass::*eventCallback_ififi_t )( const intptr_t, const float, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_ififi_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ] ); - break; - - case 8203 : - typedef void ( idClass::*eventCallback_ffifi_t )( const float, const float, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_ffifi_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ] ); - break; - - case 8204 : - typedef void ( idClass::*eventCallback_iiffi_t )( const intptr_t, const intptr_t, const float, const float, const intptr_t ); - ( this->*( eventCallback_iiffi_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ] ); - break; - - case 8205 : - typedef void ( idClass::*eventCallback_fiffi_t )( const float, const intptr_t, const float, const float, const intptr_t ); - ( this->*( eventCallback_fiffi_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ] ); - break; - - case 8206 : - typedef void ( idClass::*eventCallback_ifffi_t )( const intptr_t, const float, const float, const float, const intptr_t ); - ( this->*( eventCallback_ifffi_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ] ); - break; - - case 8207 : - typedef void ( idClass::*eventCallback_ffffi_t )( const float, const float, const float, const float, const intptr_t ); - ( this->*( eventCallback_ffffi_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ] ); - break; - - case 8208 : - typedef void ( idClass::*eventCallback_iiiif_t )( const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_iiiif_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ] ); - break; - - case 8209 : - typedef void ( idClass::*eventCallback_fiiif_t )( const float, const intptr_t, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_fiiif_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ] ); - break; - - case 8210 : - typedef void ( idClass::*eventCallback_ifiif_t )( const intptr_t, const float, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_ifiif_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ] ); - break; - - case 8211 : - typedef void ( idClass::*eventCallback_ffiif_t )( const float, const float, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_ffiif_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ] ); - break; - - case 8212 : - typedef void ( idClass::*eventCallback_iifif_t )( const intptr_t, const intptr_t, const float, const intptr_t, const float ); - ( this->*( eventCallback_iifif_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ] ); - break; - - case 8213 : - typedef void ( idClass::*eventCallback_fifif_t )( const float, const intptr_t, const float, const intptr_t, const float ); - ( this->*( eventCallback_fifif_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ] ); - break; - - case 8214 : - typedef void ( idClass::*eventCallback_iffif_t )( const intptr_t, const float, const float, const intptr_t, const float ); - ( this->*( eventCallback_iffif_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ] ); - break; - - case 8215 : - typedef void ( idClass::*eventCallback_fffif_t )( const float, const float, const float, const intptr_t, const float ); - ( this->*( eventCallback_fffif_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ] ); - break; - - case 8216 : - typedef void ( idClass::*eventCallback_iiiff_t )( const intptr_t, const intptr_t, const intptr_t, const float, const float ); - ( this->*( eventCallback_iiiff_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ] ); - break; - - case 8217 : - typedef void ( idClass::*eventCallback_fiiff_t )( const float, const intptr_t, const intptr_t, const float, const float ); - ( this->*( eventCallback_fiiff_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ] ); - break; - - case 8218 : - typedef void ( idClass::*eventCallback_ififf_t )( const intptr_t, const float, const intptr_t, const float, const float ); - ( this->*( eventCallback_ififf_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ] ); - break; - - case 8219 : - typedef void ( idClass::*eventCallback_ffiff_t )( const float, const float, const intptr_t, const float, const float ); - ( this->*( eventCallback_ffiff_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ] ); - break; - - case 8220 : - typedef void ( idClass::*eventCallback_iifff_t )( const intptr_t, const intptr_t, const float, const float, const float ); - ( this->*( eventCallback_iifff_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ] ); - break; - - case 8221 : - typedef void ( idClass::*eventCallback_fifff_t )( const float, const intptr_t, const float, const float, const float ); - ( this->*( eventCallback_fifff_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ] ); - break; - - case 8222 : - typedef void ( idClass::*eventCallback_iffff_t )( const intptr_t, const float, const float, const float, const float ); - ( this->*( eventCallback_iffff_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ] ); - break; - - case 8223 : - typedef void ( idClass::*eventCallback_fffff_t )( const float, const float, const float, const float, const float ); - ( this->*( eventCallback_fffff_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ] ); - break; - - /******************************************************* - - 6 args - - *******************************************************/ - - case 16384 : - typedef void ( idClass::*eventCallback_iiiiii_t )( const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iiiiii_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ] ); - break; - - case 16385 : - typedef void ( idClass::*eventCallback_fiiiii_t )( const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fiiiii_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ] ); - break; - - case 16386 : - typedef void ( idClass::*eventCallback_ifiiii_t )( const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ifiiii_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ] ); - break; - - case 16387 : - typedef void ( idClass::*eventCallback_ffiiii_t )( const float, const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ffiiii_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ] ); - break; - - case 16388 : - typedef void ( idClass::*eventCallback_iifiii_t )( const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iifiii_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ] ); - break; - - case 16389 : - typedef void ( idClass::*eventCallback_fifiii_t )( const float, const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fifiii_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ] ); - break; - - case 16390 : - typedef void ( idClass::*eventCallback_iffiii_t )( const intptr_t, const float, const float, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iffiii_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ] ); - break; - - case 16391 : - typedef void ( idClass::*eventCallback_fffiii_t )( const float, const float, const float, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fffiii_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ] ); - break; - - case 16392 : - typedef void ( idClass::*eventCallback_iiifii_t )( const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iiifii_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ] ); - break; - - case 16393 : - typedef void ( idClass::*eventCallback_fiifii_t )( const float, const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fiifii_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ] ); - break; - - case 16394 : - typedef void ( idClass::*eventCallback_ififii_t )( const intptr_t, const float, const intptr_t, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ififii_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ] ); - break; - - case 16395 : - typedef void ( idClass::*eventCallback_ffifii_t )( const float, const float, const intptr_t, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ffifii_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ] ); - break; - - case 16396 : - typedef void ( idClass::*eventCallback_iiffii_t )( const intptr_t, const intptr_t, const float, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iiffii_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ] ); - break; - - case 16397 : - typedef void ( idClass::*eventCallback_fiffii_t )( const float, const intptr_t, const float, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fiffii_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ] ); - break; - - case 16398 : - typedef void ( idClass::*eventCallback_ifffii_t )( const intptr_t, const float, const float, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ifffii_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ] ); - break; - - case 16399 : - typedef void ( idClass::*eventCallback_ffffii_t )( const float, const float, const float, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ffffii_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ] ); - break; - - case 16400 : - typedef void ( idClass::*eventCallback_iiiifi_t )( const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_iiiifi_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ] ); - break; - - case 16401 : - typedef void ( idClass::*eventCallback_fiiifi_t )( const float, const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_fiiifi_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ] ); - break; - - case 16402 : - typedef void ( idClass::*eventCallback_ifiifi_t )( const intptr_t, const float, const intptr_t, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_ifiifi_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ] ); - break; - - case 16403 : - typedef void ( idClass::*eventCallback_ffiifi_t )( const float, const float, const intptr_t, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_ffiifi_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ] ); - break; - - case 16404 : - typedef void ( idClass::*eventCallback_iififi_t )( const intptr_t, const intptr_t, const float, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_iififi_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ] ); - break; - - case 16405 : - typedef void ( idClass::*eventCallback_fififi_t )( const float, const intptr_t, const float, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_fififi_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ] ); - break; - - case 16406 : - typedef void ( idClass::*eventCallback_iffifi_t )( const intptr_t, const float, const float, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_iffifi_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ] ); - break; - - case 16407 : - typedef void ( idClass::*eventCallback_fffifi_t )( const float, const float, const float, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_fffifi_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ] ); - break; - - case 16408 : - typedef void ( idClass::*eventCallback_iiiffi_t )( const intptr_t, const intptr_t, const intptr_t, const float, const float, const intptr_t ); - ( this->*( eventCallback_iiiffi_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ] ); - break; - - case 16409 : - typedef void ( idClass::*eventCallback_fiiffi_t )( const float, const intptr_t, const intptr_t, const float, const float, const intptr_t ); - ( this->*( eventCallback_fiiffi_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ] ); - break; - - case 16410 : - typedef void ( idClass::*eventCallback_ififfi_t )( const intptr_t, const float, const intptr_t, const float, const float, const intptr_t ); - ( this->*( eventCallback_ififfi_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ] ); - break; - - case 16411 : - typedef void ( idClass::*eventCallback_ffiffi_t )( const float, const float, const intptr_t, const float, const float, const intptr_t ); - ( this->*( eventCallback_ffiffi_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ] ); - break; - - case 16412 : - typedef void ( idClass::*eventCallback_iifffi_t )( const intptr_t, const intptr_t, const float, const float, const float, const intptr_t ); - ( this->*( eventCallback_iifffi_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ] ); - break; - - case 16413 : - typedef void ( idClass::*eventCallback_fifffi_t )( const float, const intptr_t, const float, const float, const float, const intptr_t ); - ( this->*( eventCallback_fifffi_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ] ); - break; - - case 16414 : - typedef void ( idClass::*eventCallback_iffffi_t )( const intptr_t, const float, const float, const float, const float, const intptr_t ); - ( this->*( eventCallback_iffffi_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ] ); - break; - - case 16415 : - typedef void ( idClass::*eventCallback_fffffi_t )( const float, const float, const float, const float, const float, const intptr_t ); - ( this->*( eventCallback_fffffi_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ] ); - break; - - case 16416 : - typedef void ( idClass::*eventCallback_iiiiif_t )( const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_iiiiif_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ] ); - break; - - case 16417 : - typedef void ( idClass::*eventCallback_fiiiif_t )( const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_fiiiif_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ] ); - break; - - case 16418 : - typedef void ( idClass::*eventCallback_ifiiif_t )( const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_ifiiif_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ] ); - break; - - case 16419 : - typedef void ( idClass::*eventCallback_ffiiif_t )( const float, const float, const intptr_t, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_ffiiif_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ] ); - break; - - case 16420 : - typedef void ( idClass::*eventCallback_iifiif_t )( const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_iifiif_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ] ); - break; - - case 16421 : - typedef void ( idClass::*eventCallback_fifiif_t )( const float, const intptr_t, const float, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_fifiif_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ] ); - break; - - case 16422 : - typedef void ( idClass::*eventCallback_iffiif_t )( const intptr_t, const float, const float, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_iffiif_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ] ); - break; - - case 16423 : - typedef void ( idClass::*eventCallback_fffiif_t )( const float, const float, const float, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_fffiif_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ] ); - break; - - case 16424 : - typedef void ( idClass::*eventCallback_iiifif_t )( const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t, const float ); - ( this->*( eventCallback_iiifif_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ] ); - break; - - case 16425 : - typedef void ( idClass::*eventCallback_fiifif_t )( const float, const intptr_t, const intptr_t, const float, const intptr_t, const float ); - ( this->*( eventCallback_fiifif_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ] ); - break; - - case 16426 : - typedef void ( idClass::*eventCallback_ififif_t )( const intptr_t, const float, const intptr_t, const float, const intptr_t, const float ); - ( this->*( eventCallback_ififif_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ] ); - break; - - case 16427 : - typedef void ( idClass::*eventCallback_ffifif_t )( const float, const float, const intptr_t, const float, const intptr_t, const float ); - ( this->*( eventCallback_ffifif_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ] ); - break; - - case 16428 : - typedef void ( idClass::*eventCallback_iiffif_t )( const intptr_t, const intptr_t, const float, const float, const intptr_t, const float ); - ( this->*( eventCallback_iiffif_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ] ); - break; - - case 16429 : - typedef void ( idClass::*eventCallback_fiffif_t )( const float, const intptr_t, const float, const float, const intptr_t, const float ); - ( this->*( eventCallback_fiffif_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ] ); - break; - - case 16430 : - typedef void ( idClass::*eventCallback_ifffif_t )( const intptr_t, const float, const float, const float, const intptr_t, const float ); - ( this->*( eventCallback_ifffif_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ] ); - break; - - case 16431 : - typedef void ( idClass::*eventCallback_ffffif_t )( const float, const float, const float, const float, const intptr_t, const float ); - ( this->*( eventCallback_ffffif_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ] ); - break; - - case 16432 : - typedef void ( idClass::*eventCallback_iiiiff_t )( const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float, const float ); - ( this->*( eventCallback_iiiiff_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ] ); - break; - - case 16433 : - typedef void ( idClass::*eventCallback_fiiiff_t )( const float, const intptr_t, const intptr_t, const intptr_t, const float, const float ); - ( this->*( eventCallback_fiiiff_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ] ); - break; - - case 16434 : - typedef void ( idClass::*eventCallback_ifiiff_t )( const intptr_t, const float, const intptr_t, const intptr_t, const float, const float ); - ( this->*( eventCallback_ifiiff_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ] ); - break; - - case 16435 : - typedef void ( idClass::*eventCallback_ffiiff_t )( const float, const float, const intptr_t, const intptr_t, const float, const float ); - ( this->*( eventCallback_ffiiff_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ] ); - break; - - case 16436 : - typedef void ( idClass::*eventCallback_iififf_t )( const intptr_t, const intptr_t, const float, const intptr_t, const float, const float ); - ( this->*( eventCallback_iififf_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ] ); - break; - - case 16437 : - typedef void ( idClass::*eventCallback_fififf_t )( const float, const intptr_t, const float, const intptr_t, const float, const float ); - ( this->*( eventCallback_fififf_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ] ); - break; - - case 16438 : - typedef void ( idClass::*eventCallback_iffiff_t )( const intptr_t, const float, const float, const intptr_t, const float, const float ); - ( this->*( eventCallback_iffiff_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ] ); - break; - - case 16439 : - typedef void ( idClass::*eventCallback_fffiff_t )( const float, const float, const float, const intptr_t, const float, const float ); - ( this->*( eventCallback_fffiff_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ] ); - break; - - case 16440 : - typedef void ( idClass::*eventCallback_iiifff_t )( const intptr_t, const intptr_t, const intptr_t, const float, const float, const float ); - ( this->*( eventCallback_iiifff_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ] ); - break; - - case 16441 : - typedef void ( idClass::*eventCallback_fiifff_t )( const float, const intptr_t, const intptr_t, const float, const float, const float ); - ( this->*( eventCallback_fiifff_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ] ); - break; - - case 16442 : - typedef void ( idClass::*eventCallback_ififff_t )( const intptr_t, const float, const intptr_t, const float, const float, const float ); - ( this->*( eventCallback_ififff_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ] ); - break; - - case 16443 : - typedef void ( idClass::*eventCallback_ffifff_t )( const float, const float, const intptr_t, const float, const float, const float ); - ( this->*( eventCallback_ffifff_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ] ); - break; - - case 16444 : - typedef void ( idClass::*eventCallback_iiffff_t )( const intptr_t, const intptr_t, const float, const float, const float, const float ); - ( this->*( eventCallback_iiffff_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ] ); - break; - - case 16445 : - typedef void ( idClass::*eventCallback_fiffff_t )( const float, const intptr_t, const float, const float, const float, const float ); - ( this->*( eventCallback_fiffff_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ] ); - break; - - case 16446 : - typedef void ( idClass::*eventCallback_ifffff_t )( const intptr_t, const float, const float, const float, const float, const float ); - ( this->*( eventCallback_ifffff_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ] ); - break; - - case 16447 : - typedef void ( idClass::*eventCallback_ffffff_t )( const float, const float, const float, const float, const float, const float ); - ( this->*( eventCallback_ffffff_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ] ); - break; - - /******************************************************* - - 7 args - - *******************************************************/ - - case 32768 : - typedef void ( idClass::*eventCallback_iiiiiii_t )( const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iiiiiii_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ] ); - break; - - case 32769 : - typedef void ( idClass::*eventCallback_fiiiiii_t )( const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fiiiiii_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ] ); - break; - - case 32770 : - typedef void ( idClass::*eventCallback_ifiiiii_t )( const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ifiiiii_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ] ); - break; - - case 32771 : - typedef void ( idClass::*eventCallback_ffiiiii_t )( const float, const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ffiiiii_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ] ); - break; - - case 32772 : - typedef void ( idClass::*eventCallback_iifiiii_t )( const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iifiiii_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ] ); - break; - - case 32773 : - typedef void ( idClass::*eventCallback_fifiiii_t )( const float, const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fifiiii_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ] ); - break; - - case 32774 : - typedef void ( idClass::*eventCallback_iffiiii_t )( const intptr_t, const float, const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iffiiii_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ] ); - break; - - case 32775 : - typedef void ( idClass::*eventCallback_fffiiii_t )( const float, const float, const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fffiiii_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ] ); - break; - - case 32776 : - typedef void ( idClass::*eventCallback_iiifiii_t )( const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iiifiii_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ] ); - break; - - case 32777 : - typedef void ( idClass::*eventCallback_fiifiii_t )( const float, const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fiifiii_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ] ); - break; - - case 32778 : - typedef void ( idClass::*eventCallback_ififiii_t )( const intptr_t, const float, const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ififiii_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ] ); - break; - - case 32779 : - typedef void ( idClass::*eventCallback_ffifiii_t )( const float, const float, const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ffifiii_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ] ); - break; - - case 32780 : - typedef void ( idClass::*eventCallback_iiffiii_t )( const intptr_t, const intptr_t, const float, const float, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iiffiii_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ] ); - break; - - case 32781 : - typedef void ( idClass::*eventCallback_fiffiii_t )( const float, const intptr_t, const float, const float, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fiffiii_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ] ); - break; - - case 32782 : - typedef void ( idClass::*eventCallback_ifffiii_t )( const intptr_t, const float, const float, const float, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ifffiii_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ] ); - break; - - case 32783 : - typedef void ( idClass::*eventCallback_ffffiii_t )( const float, const float, const float, const float, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ffffiii_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ] ); - break; - - case 32784 : - typedef void ( idClass::*eventCallback_iiiifii_t )( const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iiiifii_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ] ); - break; - - case 32785 : - typedef void ( idClass::*eventCallback_fiiifii_t )( const float, const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fiiifii_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ] ); - break; - - case 32786 : - typedef void ( idClass::*eventCallback_ifiifii_t )( const intptr_t, const float, const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ifiifii_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ] ); - break; - - case 32787 : - typedef void ( idClass::*eventCallback_ffiifii_t )( const float, const float, const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ffiifii_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ] ); - break; - - case 32788 : - typedef void ( idClass::*eventCallback_iififii_t )( const intptr_t, const intptr_t, const float, const intptr_t, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iififii_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ] ); - break; - - case 32789 : - typedef void ( idClass::*eventCallback_fififii_t )( const float, const intptr_t, const float, const intptr_t, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fififii_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ] ); - break; - - case 32790 : - typedef void ( idClass::*eventCallback_iffifii_t )( const intptr_t, const float, const float, const intptr_t, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iffifii_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ] ); - break; - - case 32791 : - typedef void ( idClass::*eventCallback_fffifii_t )( const float, const float, const float, const intptr_t, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fffifii_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ] ); - break; - - case 32792 : - typedef void ( idClass::*eventCallback_iiiffii_t )( const intptr_t, const intptr_t, const intptr_t, const float, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iiiffii_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ] ); - break; - - case 32793 : - typedef void ( idClass::*eventCallback_fiiffii_t )( const float, const intptr_t, const intptr_t, const float, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fiiffii_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ] ); - break; - - case 32794 : - typedef void ( idClass::*eventCallback_ififfii_t )( const intptr_t, const float, const intptr_t, const float, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ififfii_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ] ); - break; - - case 32795 : - typedef void ( idClass::*eventCallback_ffiffii_t )( const float, const float, const intptr_t, const float, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ffiffii_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ] ); - break; - - case 32796 : - typedef void ( idClass::*eventCallback_iifffii_t )( const intptr_t, const intptr_t, const float, const float, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iifffii_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ] ); - break; - - case 32797 : - typedef void ( idClass::*eventCallback_fifffii_t )( const float, const intptr_t, const float, const float, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fifffii_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ] ); - break; - - case 32798 : - typedef void ( idClass::*eventCallback_iffffii_t )( const intptr_t, const float, const float, const float, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iffffii_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ] ); - break; - - case 32799 : - typedef void ( idClass::*eventCallback_fffffii_t )( const float, const float, const float, const float, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fffffii_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ] ); - break; - - case 32800 : - typedef void ( idClass::*eventCallback_iiiiifi_t )( const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_iiiiifi_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ] ); - break; - - case 32801 : - typedef void ( idClass::*eventCallback_fiiiifi_t )( const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_fiiiifi_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ] ); - break; - - case 32802 : - typedef void ( idClass::*eventCallback_ifiiifi_t )( const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_ifiiifi_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ] ); - break; - - case 32803 : - typedef void ( idClass::*eventCallback_ffiiifi_t )( const float, const float, const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_ffiiifi_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ] ); - break; - - case 32804 : - typedef void ( idClass::*eventCallback_iifiifi_t )( const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_iifiifi_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ] ); - break; - - case 32805 : - typedef void ( idClass::*eventCallback_fifiifi_t )( const float, const intptr_t, const float, const intptr_t, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_fifiifi_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ] ); - break; - - case 32806 : - typedef void ( idClass::*eventCallback_iffiifi_t )( const intptr_t, const float, const float, const intptr_t, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_iffiifi_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ] ); - break; - - case 32807 : - typedef void ( idClass::*eventCallback_fffiifi_t )( const float, const float, const float, const intptr_t, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_fffiifi_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ] ); - break; - - case 32808 : - typedef void ( idClass::*eventCallback_iiififi_t )( const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_iiififi_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ] ); - break; - - case 32809 : - typedef void ( idClass::*eventCallback_fiififi_t )( const float, const intptr_t, const intptr_t, const float, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_fiififi_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ] ); - break; - - case 32810 : - typedef void ( idClass::*eventCallback_ifififi_t )( const intptr_t, const float, const intptr_t, const float, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_ifififi_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ] ); - break; - - case 32811 : - typedef void ( idClass::*eventCallback_ffififi_t )( const float, const float, const intptr_t, const float, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_ffififi_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ] ); - break; - - case 32812 : - typedef void ( idClass::*eventCallback_iiffifi_t )( const intptr_t, const intptr_t, const float, const float, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_iiffifi_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ] ); - break; - - case 32813 : - typedef void ( idClass::*eventCallback_fiffifi_t )( const float, const intptr_t, const float, const float, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_fiffifi_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ] ); - break; - - case 32814 : - typedef void ( idClass::*eventCallback_ifffifi_t )( const intptr_t, const float, const float, const float, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_ifffifi_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ] ); - break; - - case 32815 : - typedef void ( idClass::*eventCallback_ffffifi_t )( const float, const float, const float, const float, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_ffffifi_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ] ); - break; - - case 32816 : - typedef void ( idClass::*eventCallback_iiiiffi_t )( const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float, const float, const intptr_t ); - ( this->*( eventCallback_iiiiffi_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ] ); - break; - - case 32817 : - typedef void ( idClass::*eventCallback_fiiiffi_t )( const float, const intptr_t, const intptr_t, const intptr_t, const float, const float, const intptr_t ); - ( this->*( eventCallback_fiiiffi_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ] ); - break; - - case 32818 : - typedef void ( idClass::*eventCallback_ifiiffi_t )( const intptr_t, const float, const intptr_t, const intptr_t, const float, const float, const intptr_t ); - ( this->*( eventCallback_ifiiffi_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ] ); - break; - - case 32819 : - typedef void ( idClass::*eventCallback_ffiiffi_t )( const float, const float, const intptr_t, const intptr_t, const float, const float, const intptr_t ); - ( this->*( eventCallback_ffiiffi_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ] ); - break; - - case 32820 : - typedef void ( idClass::*eventCallback_iififfi_t )( const intptr_t, const intptr_t, const float, const intptr_t, const float, const float, const intptr_t ); - ( this->*( eventCallback_iififfi_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ] ); - break; - - case 32821 : - typedef void ( idClass::*eventCallback_fififfi_t )( const float, const intptr_t, const float, const intptr_t, const float, const float, const intptr_t ); - ( this->*( eventCallback_fififfi_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ] ); - break; - - case 32822 : - typedef void ( idClass::*eventCallback_iffiffi_t )( const intptr_t, const float, const float, const intptr_t, const float, const float, const intptr_t ); - ( this->*( eventCallback_iffiffi_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ] ); - break; - - case 32823 : - typedef void ( idClass::*eventCallback_fffiffi_t )( const float, const float, const float, const intptr_t, const float, const float, const intptr_t ); - ( this->*( eventCallback_fffiffi_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ] ); - break; - - case 32824 : - typedef void ( idClass::*eventCallback_iiifffi_t )( const intptr_t, const intptr_t, const intptr_t, const float, const float, const float, const intptr_t ); - ( this->*( eventCallback_iiifffi_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ] ); - break; - - case 32825 : - typedef void ( idClass::*eventCallback_fiifffi_t )( const float, const intptr_t, const intptr_t, const float, const float, const float, const intptr_t ); - ( this->*( eventCallback_fiifffi_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ] ); - break; - - case 32826 : - typedef void ( idClass::*eventCallback_ififffi_t )( const intptr_t, const float, const intptr_t, const float, const float, const float, const intptr_t ); - ( this->*( eventCallback_ififffi_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ] ); - break; - - case 32827 : - typedef void ( idClass::*eventCallback_ffifffi_t )( const float, const float, const intptr_t, const float, const float, const float, const intptr_t ); - ( this->*( eventCallback_ffifffi_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ] ); - break; - - case 32828 : - typedef void ( idClass::*eventCallback_iiffffi_t )( const intptr_t, const intptr_t, const float, const float, const float, const float, const intptr_t ); - ( this->*( eventCallback_iiffffi_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ] ); - break; - - case 32829 : - typedef void ( idClass::*eventCallback_fiffffi_t )( const float, const intptr_t, const float, const float, const float, const float, const intptr_t ); - ( this->*( eventCallback_fiffffi_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ] ); - break; - - case 32830 : - typedef void ( idClass::*eventCallback_ifffffi_t )( const intptr_t, const float, const float, const float, const float, const float, const intptr_t ); - ( this->*( eventCallback_ifffffi_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ] ); - break; - - case 32831 : - typedef void ( idClass::*eventCallback_ffffffi_t )( const float, const float, const float, const float, const float, const float, const intptr_t ); - ( this->*( eventCallback_ffffffi_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ] ); - break; - - case 32832 : - typedef void ( idClass::*eventCallback_iiiiiif_t )( const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_iiiiiif_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32833 : - typedef void ( idClass::*eventCallback_fiiiiif_t )( const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_fiiiiif_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32834 : - typedef void ( idClass::*eventCallback_ifiiiif_t )( const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_ifiiiif_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32835 : - typedef void ( idClass::*eventCallback_ffiiiif_t )( const float, const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_ffiiiif_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32836 : - typedef void ( idClass::*eventCallback_iifiiif_t )( const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_iifiiif_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32837 : - typedef void ( idClass::*eventCallback_fifiiif_t )( const float, const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_fifiiif_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32838 : - typedef void ( idClass::*eventCallback_iffiiif_t )( const intptr_t, const float, const float, const intptr_t, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_iffiiif_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32839 : - typedef void ( idClass::*eventCallback_fffiiif_t )( const float, const float, const float, const intptr_t, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_fffiiif_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32840 : - typedef void ( idClass::*eventCallback_iiifiif_t )( const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_iiifiif_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32841 : - typedef void ( idClass::*eventCallback_fiifiif_t )( const float, const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_fiifiif_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32842 : - typedef void ( idClass::*eventCallback_ififiif_t )( const intptr_t, const float, const intptr_t, const float, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_ififiif_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32843 : - typedef void ( idClass::*eventCallback_ffifiif_t )( const float, const float, const intptr_t, const float, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_ffifiif_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32844 : - typedef void ( idClass::*eventCallback_iiffiif_t )( const intptr_t, const intptr_t, const float, const float, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_iiffiif_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32845 : - typedef void ( idClass::*eventCallback_fiffiif_t )( const float, const intptr_t, const float, const float, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_fiffiif_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32846 : - typedef void ( idClass::*eventCallback_ifffiif_t )( const intptr_t, const float, const float, const float, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_ifffiif_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32847 : - typedef void ( idClass::*eventCallback_ffffiif_t )( const float, const float, const float, const float, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_ffffiif_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32848 : - typedef void ( idClass::*eventCallback_iiiifif_t )( const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t, const float ); - ( this->*( eventCallback_iiiifif_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32849 : - typedef void ( idClass::*eventCallback_fiiifif_t )( const float, const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t, const float ); - ( this->*( eventCallback_fiiifif_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32850 : - typedef void ( idClass::*eventCallback_ifiifif_t )( const intptr_t, const float, const intptr_t, const intptr_t, const float, const intptr_t, const float ); - ( this->*( eventCallback_ifiifif_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32851 : - typedef void ( idClass::*eventCallback_ffiifif_t )( const float, const float, const intptr_t, const intptr_t, const float, const intptr_t, const float ); - ( this->*( eventCallback_ffiifif_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32852 : - typedef void ( idClass::*eventCallback_iififif_t )( const intptr_t, const intptr_t, const float, const intptr_t, const float, const intptr_t, const float ); - ( this->*( eventCallback_iififif_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32853 : - typedef void ( idClass::*eventCallback_fififif_t )( const float, const intptr_t, const float, const intptr_t, const float, const intptr_t, const float ); - ( this->*( eventCallback_fififif_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32854 : - typedef void ( idClass::*eventCallback_iffifif_t )( const intptr_t, const float, const float, const intptr_t, const float, const intptr_t, const float ); - ( this->*( eventCallback_iffifif_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32855 : - typedef void ( idClass::*eventCallback_fffifif_t )( const float, const float, const float, const intptr_t, const float, const intptr_t, const float ); - ( this->*( eventCallback_fffifif_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32856 : - typedef void ( idClass::*eventCallback_iiiffif_t )( const intptr_t, const intptr_t, const intptr_t, const float, const float, const intptr_t, const float ); - ( this->*( eventCallback_iiiffif_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32857 : - typedef void ( idClass::*eventCallback_fiiffif_t )( const float, const intptr_t, const intptr_t, const float, const float, const intptr_t, const float ); - ( this->*( eventCallback_fiiffif_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32858 : - typedef void ( idClass::*eventCallback_ififfif_t )( const intptr_t, const float, const intptr_t, const float, const float, const intptr_t, const float ); - ( this->*( eventCallback_ififfif_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32859 : - typedef void ( idClass::*eventCallback_ffiffif_t )( const float, const float, const intptr_t, const float, const float, const intptr_t, const float ); - ( this->*( eventCallback_ffiffif_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32860 : - typedef void ( idClass::*eventCallback_iifffif_t )( const intptr_t, const intptr_t, const float, const float, const float, const intptr_t, const float ); - ( this->*( eventCallback_iifffif_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32861 : - typedef void ( idClass::*eventCallback_fifffif_t )( const float, const intptr_t, const float, const float, const float, const intptr_t, const float ); - ( this->*( eventCallback_fifffif_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32862 : - typedef void ( idClass::*eventCallback_iffffif_t )( const intptr_t, const float, const float, const float, const float, const intptr_t, const float ); - ( this->*( eventCallback_iffffif_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32863 : - typedef void ( idClass::*eventCallback_fffffif_t )( const float, const float, const float, const float, const float, const intptr_t, const float ); - ( this->*( eventCallback_fffffif_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32864 : - typedef void ( idClass::*eventCallback_iiiiiff_t )( const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float, const float ); - ( this->*( eventCallback_iiiiiff_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32865 : - typedef void ( idClass::*eventCallback_fiiiiff_t )( const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float, const float ); - ( this->*( eventCallback_fiiiiff_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32866 : - typedef void ( idClass::*eventCallback_ifiiiff_t )( const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t, const float, const float ); - ( this->*( eventCallback_ifiiiff_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32867 : - typedef void ( idClass::*eventCallback_ffiiiff_t )( const float, const float, const intptr_t, const intptr_t, const intptr_t, const float, const float ); - ( this->*( eventCallback_ffiiiff_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32868 : - typedef void ( idClass::*eventCallback_iifiiff_t )( const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t, const float, const float ); - ( this->*( eventCallback_iifiiff_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32869 : - typedef void ( idClass::*eventCallback_fifiiff_t )( const float, const intptr_t, const float, const intptr_t, const intptr_t, const float, const float ); - ( this->*( eventCallback_fifiiff_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32870 : - typedef void ( idClass::*eventCallback_iffiiff_t )( const intptr_t, const float, const float, const intptr_t, const intptr_t, const float, const float ); - ( this->*( eventCallback_iffiiff_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32871 : - typedef void ( idClass::*eventCallback_fffiiff_t )( const float, const float, const float, const intptr_t, const intptr_t, const float, const float ); - ( this->*( eventCallback_fffiiff_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32872 : - typedef void ( idClass::*eventCallback_iiififf_t )( const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t, const float, const float ); - ( this->*( eventCallback_iiififf_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32873 : - typedef void ( idClass::*eventCallback_fiififf_t )( const float, const intptr_t, const intptr_t, const float, const intptr_t, const float, const float ); - ( this->*( eventCallback_fiififf_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32874 : - typedef void ( idClass::*eventCallback_ifififf_t )( const intptr_t, const float, const intptr_t, const float, const intptr_t, const float, const float ); - ( this->*( eventCallback_ifififf_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32875 : - typedef void ( idClass::*eventCallback_ffififf_t )( const float, const float, const intptr_t, const float, const intptr_t, const float, const float ); - ( this->*( eventCallback_ffififf_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32876 : - typedef void ( idClass::*eventCallback_iiffiff_t )( const intptr_t, const intptr_t, const float, const float, const intptr_t, const float, const float ); - ( this->*( eventCallback_iiffiff_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32877 : - typedef void ( idClass::*eventCallback_fiffiff_t )( const float, const intptr_t, const float, const float, const intptr_t, const float, const float ); - ( this->*( eventCallback_fiffiff_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32878 : - typedef void ( idClass::*eventCallback_ifffiff_t )( const intptr_t, const float, const float, const float, const intptr_t, const float, const float ); - ( this->*( eventCallback_ifffiff_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32879 : - typedef void ( idClass::*eventCallback_ffffiff_t )( const float, const float, const float, const float, const intptr_t, const float, const float ); - ( this->*( eventCallback_ffffiff_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32880 : - typedef void ( idClass::*eventCallback_iiiifff_t )( const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float, const float, const float ); - ( this->*( eventCallback_iiiifff_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32881 : - typedef void ( idClass::*eventCallback_fiiifff_t )( const float, const intptr_t, const intptr_t, const intptr_t, const float, const float, const float ); - ( this->*( eventCallback_fiiifff_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32882 : - typedef void ( idClass::*eventCallback_ifiifff_t )( const intptr_t, const float, const intptr_t, const intptr_t, const float, const float, const float ); - ( this->*( eventCallback_ifiifff_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32883 : - typedef void ( idClass::*eventCallback_ffiifff_t )( const float, const float, const intptr_t, const intptr_t, const float, const float, const float ); - ( this->*( eventCallback_ffiifff_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32884 : - typedef void ( idClass::*eventCallback_iififff_t )( const intptr_t, const intptr_t, const float, const intptr_t, const float, const float, const float ); - ( this->*( eventCallback_iififff_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32885 : - typedef void ( idClass::*eventCallback_fififff_t )( const float, const intptr_t, const float, const intptr_t, const float, const float, const float ); - ( this->*( eventCallback_fififff_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32886 : - typedef void ( idClass::*eventCallback_iffifff_t )( const intptr_t, const float, const float, const intptr_t, const float, const float, const float ); - ( this->*( eventCallback_iffifff_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32887 : - typedef void ( idClass::*eventCallback_fffifff_t )( const float, const float, const float, const intptr_t, const float, const float, const float ); - ( this->*( eventCallback_fffifff_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32888 : - typedef void ( idClass::*eventCallback_iiiffff_t )( const intptr_t, const intptr_t, const intptr_t, const float, const float, const float, const float ); - ( this->*( eventCallback_iiiffff_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32889 : - typedef void ( idClass::*eventCallback_fiiffff_t )( const float, const intptr_t, const intptr_t, const float, const float, const float, const float ); - ( this->*( eventCallback_fiiffff_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32890 : - typedef void ( idClass::*eventCallback_ififfff_t )( const intptr_t, const float, const intptr_t, const float, const float, const float, const float ); - ( this->*( eventCallback_ififfff_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32891 : - typedef void ( idClass::*eventCallback_ffiffff_t )( const float, const float, const intptr_t, const float, const float, const float, const float ); - ( this->*( eventCallback_ffiffff_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32892 : - typedef void ( idClass::*eventCallback_iifffff_t )( const intptr_t, const intptr_t, const float, const float, const float, const float, const float ); - ( this->*( eventCallback_iifffff_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32893 : - typedef void ( idClass::*eventCallback_fifffff_t )( const float, const intptr_t, const float, const float, const float, const float, const float ); - ( this->*( eventCallback_fifffff_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32894 : - typedef void ( idClass::*eventCallback_iffffff_t )( const intptr_t, const float, const float, const float, const float, const float, const float ); - ( this->*( eventCallback_iffffff_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ] ); - break; - - case 32895 : - typedef void ( idClass::*eventCallback_fffffff_t )( const float, const float, const float, const float, const float, const float, const float ); - ( this->*( eventCallback_fffffff_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ] ); - break; - - /******************************************************* - - 8 args - - *******************************************************/ - - case 65536 : - typedef void ( idClass::*eventCallback_iiiiiiii_t )( const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iiiiiiii_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65537 : - typedef void ( idClass::*eventCallback_fiiiiiii_t )( const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fiiiiiii_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65538 : - typedef void ( idClass::*eventCallback_ifiiiiii_t )( const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ifiiiiii_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65539 : - typedef void ( idClass::*eventCallback_ffiiiiii_t )( const float, const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ffiiiiii_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65540 : - typedef void ( idClass::*eventCallback_iifiiiii_t )( const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iifiiiii_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65541 : - typedef void ( idClass::*eventCallback_fifiiiii_t )( const float, const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fifiiiii_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65542 : - typedef void ( idClass::*eventCallback_iffiiiii_t )( const intptr_t, const float, const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iffiiiii_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65543 : - typedef void ( idClass::*eventCallback_fffiiiii_t )( const float, const float, const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fffiiiii_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65544 : - typedef void ( idClass::*eventCallback_iiifiiii_t )( const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iiifiiii_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65545 : - typedef void ( idClass::*eventCallback_fiifiiii_t )( const float, const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fiifiiii_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65546 : - typedef void ( idClass::*eventCallback_ififiiii_t )( const intptr_t, const float, const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ififiiii_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65547 : - typedef void ( idClass::*eventCallback_ffifiiii_t )( const float, const float, const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ffifiiii_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65548 : - typedef void ( idClass::*eventCallback_iiffiiii_t )( const intptr_t, const intptr_t, const float, const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iiffiiii_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65549 : - typedef void ( idClass::*eventCallback_fiffiiii_t )( const float, const intptr_t, const float, const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fiffiiii_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65550 : - typedef void ( idClass::*eventCallback_ifffiiii_t )( const intptr_t, const float, const float, const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ifffiiii_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65551 : - typedef void ( idClass::*eventCallback_ffffiiii_t )( const float, const float, const float, const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ffffiiii_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65552 : - typedef void ( idClass::*eventCallback_iiiifiii_t )( const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iiiifiii_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65553 : - typedef void ( idClass::*eventCallback_fiiifiii_t )( const float, const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fiiifiii_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65554 : - typedef void ( idClass::*eventCallback_ifiifiii_t )( const intptr_t, const float, const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ifiifiii_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65555 : - typedef void ( idClass::*eventCallback_ffiifiii_t )( const float, const float, const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ffiifiii_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65556 : - typedef void ( idClass::*eventCallback_iififiii_t )( const intptr_t, const intptr_t, const float, const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iififiii_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65557 : - typedef void ( idClass::*eventCallback_fififiii_t )( const float, const intptr_t, const float, const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fififiii_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65558 : - typedef void ( idClass::*eventCallback_iffifiii_t )( const intptr_t, const float, const float, const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iffifiii_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65559 : - typedef void ( idClass::*eventCallback_fffifiii_t )( const float, const float, const float, const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fffifiii_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65560 : - typedef void ( idClass::*eventCallback_iiiffiii_t )( const intptr_t, const intptr_t, const intptr_t, const float, const float, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iiiffiii_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65561 : - typedef void ( idClass::*eventCallback_fiiffiii_t )( const float, const intptr_t, const intptr_t, const float, const float, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fiiffiii_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65562 : - typedef void ( idClass::*eventCallback_ififfiii_t )( const intptr_t, const float, const intptr_t, const float, const float, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ififfiii_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65563 : - typedef void ( idClass::*eventCallback_ffiffiii_t )( const float, const float, const intptr_t, const float, const float, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ffiffiii_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65564 : - typedef void ( idClass::*eventCallback_iifffiii_t )( const intptr_t, const intptr_t, const float, const float, const float, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iifffiii_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65565 : - typedef void ( idClass::*eventCallback_fifffiii_t )( const float, const intptr_t, const float, const float, const float, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fifffiii_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65566 : - typedef void ( idClass::*eventCallback_iffffiii_t )( const intptr_t, const float, const float, const float, const float, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iffffiii_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65567 : - typedef void ( idClass::*eventCallback_fffffiii_t )( const float, const float, const float, const float, const float, const intptr_t, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fffffiii_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65568 : - typedef void ( idClass::*eventCallback_iiiiifii_t )( const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iiiiifii_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65569 : - typedef void ( idClass::*eventCallback_fiiiifii_t )( const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fiiiifii_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65570 : - typedef void ( idClass::*eventCallback_ifiiifii_t )( const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ifiiifii_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65571 : - typedef void ( idClass::*eventCallback_ffiiifii_t )( const float, const float, const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ffiiifii_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65572 : - typedef void ( idClass::*eventCallback_iifiifii_t )( const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iifiifii_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65573 : - typedef void ( idClass::*eventCallback_fifiifii_t )( const float, const intptr_t, const float, const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fifiifii_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65574 : - typedef void ( idClass::*eventCallback_iffiifii_t )( const intptr_t, const float, const float, const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iffiifii_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65575 : - typedef void ( idClass::*eventCallback_fffiifii_t )( const float, const float, const float, const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fffiifii_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65576 : - typedef void ( idClass::*eventCallback_iiififii_t )( const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iiififii_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65577 : - typedef void ( idClass::*eventCallback_fiififii_t )( const float, const intptr_t, const intptr_t, const float, const intptr_t, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fiififii_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65578 : - typedef void ( idClass::*eventCallback_ifififii_t )( const intptr_t, const float, const intptr_t, const float, const intptr_t, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ifififii_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65579 : - typedef void ( idClass::*eventCallback_ffififii_t )( const float, const float, const intptr_t, const float, const intptr_t, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ffififii_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65580 : - typedef void ( idClass::*eventCallback_iiffifii_t )( const intptr_t, const intptr_t, const float, const float, const intptr_t, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iiffifii_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65581 : - typedef void ( idClass::*eventCallback_fiffifii_t )( const float, const intptr_t, const float, const float, const intptr_t, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fiffifii_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65582 : - typedef void ( idClass::*eventCallback_ifffifii_t )( const intptr_t, const float, const float, const float, const intptr_t, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ifffifii_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65583 : - typedef void ( idClass::*eventCallback_ffffifii_t )( const float, const float, const float, const float, const intptr_t, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ffffifii_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65584 : - typedef void ( idClass::*eventCallback_iiiiffii_t )( const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iiiiffii_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65585 : - typedef void ( idClass::*eventCallback_fiiiffii_t )( const float, const intptr_t, const intptr_t, const intptr_t, const float, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fiiiffii_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65586 : - typedef void ( idClass::*eventCallback_ifiiffii_t )( const intptr_t, const float, const intptr_t, const intptr_t, const float, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ifiiffii_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65587 : - typedef void ( idClass::*eventCallback_ffiiffii_t )( const float, const float, const intptr_t, const intptr_t, const float, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ffiiffii_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65588 : - typedef void ( idClass::*eventCallback_iififfii_t )( const intptr_t, const intptr_t, const float, const intptr_t, const float, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iififfii_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65589 : - typedef void ( idClass::*eventCallback_fififfii_t )( const float, const intptr_t, const float, const intptr_t, const float, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fififfii_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65590 : - typedef void ( idClass::*eventCallback_iffiffii_t )( const intptr_t, const float, const float, const intptr_t, const float, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iffiffii_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65591 : - typedef void ( idClass::*eventCallback_fffiffii_t )( const float, const float, const float, const intptr_t, const float, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fffiffii_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65592 : - typedef void ( idClass::*eventCallback_iiifffii_t )( const intptr_t, const intptr_t, const intptr_t, const float, const float, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iiifffii_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65593 : - typedef void ( idClass::*eventCallback_fiifffii_t )( const float, const intptr_t, const intptr_t, const float, const float, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fiifffii_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65594 : - typedef void ( idClass::*eventCallback_ififffii_t )( const intptr_t, const float, const intptr_t, const float, const float, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ififffii_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65595 : - typedef void ( idClass::*eventCallback_ffifffii_t )( const float, const float, const intptr_t, const float, const float, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ffifffii_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65596 : - typedef void ( idClass::*eventCallback_iiffffii_t )( const intptr_t, const intptr_t, const float, const float, const float, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_iiffffii_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65597 : - typedef void ( idClass::*eventCallback_fiffffii_t )( const float, const intptr_t, const float, const float, const float, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_fiffffii_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65598 : - typedef void ( idClass::*eventCallback_ifffffii_t )( const intptr_t, const float, const float, const float, const float, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ifffffii_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65599 : - typedef void ( idClass::*eventCallback_ffffffii_t )( const float, const float, const float, const float, const float, const float, const intptr_t, const intptr_t ); - ( this->*( eventCallback_ffffffii_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], data[ 7 ] ); - break; - - case 65600 : - typedef void ( idClass::*eventCallback_iiiiiifi_t )( const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_iiiiiifi_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65601 : - typedef void ( idClass::*eventCallback_fiiiiifi_t )( const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_fiiiiifi_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65602 : - typedef void ( idClass::*eventCallback_ifiiiifi_t )( const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_ifiiiifi_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65603 : - typedef void ( idClass::*eventCallback_ffiiiifi_t )( const float, const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_ffiiiifi_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65604 : - typedef void ( idClass::*eventCallback_iifiiifi_t )( const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_iifiiifi_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65605 : - typedef void ( idClass::*eventCallback_fifiiifi_t )( const float, const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_fifiiifi_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65606 : - typedef void ( idClass::*eventCallback_iffiiifi_t )( const intptr_t, const float, const float, const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_iffiiifi_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65607 : - typedef void ( idClass::*eventCallback_fffiiifi_t )( const float, const float, const float, const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_fffiiifi_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65608 : - typedef void ( idClass::*eventCallback_iiifiifi_t )( const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_iiifiifi_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65609 : - typedef void ( idClass::*eventCallback_fiifiifi_t )( const float, const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_fiifiifi_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65610 : - typedef void ( idClass::*eventCallback_ififiifi_t )( const intptr_t, const float, const intptr_t, const float, const intptr_t, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_ififiifi_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65611 : - typedef void ( idClass::*eventCallback_ffifiifi_t )( const float, const float, const intptr_t, const float, const intptr_t, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_ffifiifi_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65612 : - typedef void ( idClass::*eventCallback_iiffiifi_t )( const intptr_t, const intptr_t, const float, const float, const intptr_t, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_iiffiifi_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65613 : - typedef void ( idClass::*eventCallback_fiffiifi_t )( const float, const intptr_t, const float, const float, const intptr_t, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_fiffiifi_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65614 : - typedef void ( idClass::*eventCallback_ifffiifi_t )( const intptr_t, const float, const float, const float, const intptr_t, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_ifffiifi_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65615 : - typedef void ( idClass::*eventCallback_ffffiifi_t )( const float, const float, const float, const float, const intptr_t, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_ffffiifi_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65616 : - typedef void ( idClass::*eventCallback_iiiififi_t )( const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_iiiififi_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65617 : - typedef void ( idClass::*eventCallback_fiiififi_t )( const float, const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_fiiififi_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65618 : - typedef void ( idClass::*eventCallback_ifiififi_t )( const intptr_t, const float, const intptr_t, const intptr_t, const float, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_ifiififi_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65619 : - typedef void ( idClass::*eventCallback_ffiififi_t )( const float, const float, const intptr_t, const intptr_t, const float, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_ffiififi_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65620 : - typedef void ( idClass::*eventCallback_iifififi_t )( const intptr_t, const intptr_t, const float, const intptr_t, const float, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_iifififi_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65621 : - typedef void ( idClass::*eventCallback_fifififi_t )( const float, const intptr_t, const float, const intptr_t, const float, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_fifififi_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65622 : - typedef void ( idClass::*eventCallback_iffififi_t )( const intptr_t, const float, const float, const intptr_t, const float, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_iffififi_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65623 : - typedef void ( idClass::*eventCallback_fffififi_t )( const float, const float, const float, const intptr_t, const float, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_fffififi_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65624 : - typedef void ( idClass::*eventCallback_iiiffifi_t )( const intptr_t, const intptr_t, const intptr_t, const float, const float, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_iiiffifi_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65625 : - typedef void ( idClass::*eventCallback_fiiffifi_t )( const float, const intptr_t, const intptr_t, const float, const float, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_fiiffifi_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65626 : - typedef void ( idClass::*eventCallback_ififfifi_t )( const intptr_t, const float, const intptr_t, const float, const float, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_ififfifi_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65627 : - typedef void ( idClass::*eventCallback_ffiffifi_t )( const float, const float, const intptr_t, const float, const float, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_ffiffifi_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65628 : - typedef void ( idClass::*eventCallback_iifffifi_t )( const intptr_t, const intptr_t, const float, const float, const float, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_iifffifi_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65629 : - typedef void ( idClass::*eventCallback_fifffifi_t )( const float, const intptr_t, const float, const float, const float, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_fifffifi_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65630 : - typedef void ( idClass::*eventCallback_iffffifi_t )( const intptr_t, const float, const float, const float, const float, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_iffffifi_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65631 : - typedef void ( idClass::*eventCallback_fffffifi_t )( const float, const float, const float, const float, const float, const intptr_t, const float, const intptr_t ); - ( this->*( eventCallback_fffffifi_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65632 : - typedef void ( idClass::*eventCallback_iiiiiffi_t )( const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float, const float, const intptr_t ); - ( this->*( eventCallback_iiiiiffi_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65633 : - typedef void ( idClass::*eventCallback_fiiiiffi_t )( const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float, const float, const intptr_t ); - ( this->*( eventCallback_fiiiiffi_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65634 : - typedef void ( idClass::*eventCallback_ifiiiffi_t )( const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t, const float, const float, const intptr_t ); - ( this->*( eventCallback_ifiiiffi_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65635 : - typedef void ( idClass::*eventCallback_ffiiiffi_t )( const float, const float, const intptr_t, const intptr_t, const intptr_t, const float, const float, const intptr_t ); - ( this->*( eventCallback_ffiiiffi_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65636 : - typedef void ( idClass::*eventCallback_iifiiffi_t )( const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t, const float, const float, const intptr_t ); - ( this->*( eventCallback_iifiiffi_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65637 : - typedef void ( idClass::*eventCallback_fifiiffi_t )( const float, const intptr_t, const float, const intptr_t, const intptr_t, const float, const float, const intptr_t ); - ( this->*( eventCallback_fifiiffi_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65638 : - typedef void ( idClass::*eventCallback_iffiiffi_t )( const intptr_t, const float, const float, const intptr_t, const intptr_t, const float, const float, const intptr_t ); - ( this->*( eventCallback_iffiiffi_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65639 : - typedef void ( idClass::*eventCallback_fffiiffi_t )( const float, const float, const float, const intptr_t, const intptr_t, const float, const float, const intptr_t ); - ( this->*( eventCallback_fffiiffi_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65640 : - typedef void ( idClass::*eventCallback_iiififfi_t )( const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t, const float, const float, const intptr_t ); - ( this->*( eventCallback_iiififfi_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65641 : - typedef void ( idClass::*eventCallback_fiififfi_t )( const float, const intptr_t, const intptr_t, const float, const intptr_t, const float, const float, const intptr_t ); - ( this->*( eventCallback_fiififfi_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65642 : - typedef void ( idClass::*eventCallback_ifififfi_t )( const intptr_t, const float, const intptr_t, const float, const intptr_t, const float, const float, const intptr_t ); - ( this->*( eventCallback_ifififfi_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65643 : - typedef void ( idClass::*eventCallback_ffififfi_t )( const float, const float, const intptr_t, const float, const intptr_t, const float, const float, const intptr_t ); - ( this->*( eventCallback_ffififfi_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65644 : - typedef void ( idClass::*eventCallback_iiffiffi_t )( const intptr_t, const intptr_t, const float, const float, const intptr_t, const float, const float, const intptr_t ); - ( this->*( eventCallback_iiffiffi_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65645 : - typedef void ( idClass::*eventCallback_fiffiffi_t )( const float, const intptr_t, const float, const float, const intptr_t, const float, const float, const intptr_t ); - ( this->*( eventCallback_fiffiffi_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65646 : - typedef void ( idClass::*eventCallback_ifffiffi_t )( const intptr_t, const float, const float, const float, const intptr_t, const float, const float, const intptr_t ); - ( this->*( eventCallback_ifffiffi_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65647 : - typedef void ( idClass::*eventCallback_ffffiffi_t )( const float, const float, const float, const float, const intptr_t, const float, const float, const intptr_t ); - ( this->*( eventCallback_ffffiffi_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65648 : - typedef void ( idClass::*eventCallback_iiiifffi_t )( const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float, const float, const float, const intptr_t ); - ( this->*( eventCallback_iiiifffi_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65649 : - typedef void ( idClass::*eventCallback_fiiifffi_t )( const float, const intptr_t, const intptr_t, const intptr_t, const float, const float, const float, const intptr_t ); - ( this->*( eventCallback_fiiifffi_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65650 : - typedef void ( idClass::*eventCallback_ifiifffi_t )( const intptr_t, const float, const intptr_t, const intptr_t, const float, const float, const float, const intptr_t ); - ( this->*( eventCallback_ifiifffi_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65651 : - typedef void ( idClass::*eventCallback_ffiifffi_t )( const float, const float, const intptr_t, const intptr_t, const float, const float, const float, const intptr_t ); - ( this->*( eventCallback_ffiifffi_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65652 : - typedef void ( idClass::*eventCallback_iififffi_t )( const intptr_t, const intptr_t, const float, const intptr_t, const float, const float, const float, const intptr_t ); - ( this->*( eventCallback_iififffi_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65653 : - typedef void ( idClass::*eventCallback_fififffi_t )( const float, const intptr_t, const float, const intptr_t, const float, const float, const float, const intptr_t ); - ( this->*( eventCallback_fififffi_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65654 : - typedef void ( idClass::*eventCallback_iffifffi_t )( const intptr_t, const float, const float, const intptr_t, const float, const float, const float, const intptr_t ); - ( this->*( eventCallback_iffifffi_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65655 : - typedef void ( idClass::*eventCallback_fffifffi_t )( const float, const float, const float, const intptr_t, const float, const float, const float, const intptr_t ); - ( this->*( eventCallback_fffifffi_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65656 : - typedef void ( idClass::*eventCallback_iiiffffi_t )( const intptr_t, const intptr_t, const intptr_t, const float, const float, const float, const float, const intptr_t ); - ( this->*( eventCallback_iiiffffi_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65657 : - typedef void ( idClass::*eventCallback_fiiffffi_t )( const float, const intptr_t, const intptr_t, const float, const float, const float, const float, const intptr_t ); - ( this->*( eventCallback_fiiffffi_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65658 : - typedef void ( idClass::*eventCallback_ififfffi_t )( const intptr_t, const float, const intptr_t, const float, const float, const float, const float, const intptr_t ); - ( this->*( eventCallback_ififfffi_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65659 : - typedef void ( idClass::*eventCallback_ffiffffi_t )( const float, const float, const intptr_t, const float, const float, const float, const float, const intptr_t ); - ( this->*( eventCallback_ffiffffi_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65660 : - typedef void ( idClass::*eventCallback_iifffffi_t )( const intptr_t, const intptr_t, const float, const float, const float, const float, const float, const intptr_t ); - ( this->*( eventCallback_iifffffi_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65661 : - typedef void ( idClass::*eventCallback_fifffffi_t )( const float, const intptr_t, const float, const float, const float, const float, const float, const intptr_t ); - ( this->*( eventCallback_fifffffi_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65662 : - typedef void ( idClass::*eventCallback_iffffffi_t )( const intptr_t, const float, const float, const float, const float, const float, const float, const intptr_t ); - ( this->*( eventCallback_iffffffi_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65663 : - typedef void ( idClass::*eventCallback_fffffffi_t )( const float, const float, const float, const float, const float, const float, const float, const intptr_t ); - ( this->*( eventCallback_fffffffi_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], data[ 7 ] ); - break; - - case 65664 : - typedef void ( idClass::*eventCallback_iiiiiiif_t )( const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_iiiiiiif_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65665 : - typedef void ( idClass::*eventCallback_fiiiiiif_t )( const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_fiiiiiif_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65666 : - typedef void ( idClass::*eventCallback_ifiiiiif_t )( const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_ifiiiiif_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65667 : - typedef void ( idClass::*eventCallback_ffiiiiif_t )( const float, const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_ffiiiiif_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65668 : - typedef void ( idClass::*eventCallback_iifiiiif_t )( const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_iifiiiif_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65669 : - typedef void ( idClass::*eventCallback_fifiiiif_t )( const float, const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_fifiiiif_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65670 : - typedef void ( idClass::*eventCallback_iffiiiif_t )( const intptr_t, const float, const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_iffiiiif_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65671 : - typedef void ( idClass::*eventCallback_fffiiiif_t )( const float, const float, const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_fffiiiif_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65672 : - typedef void ( idClass::*eventCallback_iiifiiif_t )( const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_iiifiiif_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65673 : - typedef void ( idClass::*eventCallback_fiifiiif_t )( const float, const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_fiifiiif_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65674 : - typedef void ( idClass::*eventCallback_ififiiif_t )( const intptr_t, const float, const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_ififiiif_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65675 : - typedef void ( idClass::*eventCallback_ffifiiif_t )( const float, const float, const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_ffifiiif_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65676 : - typedef void ( idClass::*eventCallback_iiffiiif_t )( const intptr_t, const intptr_t, const float, const float, const intptr_t, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_iiffiiif_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65677 : - typedef void ( idClass::*eventCallback_fiffiiif_t )( const float, const intptr_t, const float, const float, const intptr_t, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_fiffiiif_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65678 : - typedef void ( idClass::*eventCallback_ifffiiif_t )( const intptr_t, const float, const float, const float, const intptr_t, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_ifffiiif_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65679 : - typedef void ( idClass::*eventCallback_ffffiiif_t )( const float, const float, const float, const float, const intptr_t, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_ffffiiif_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65680 : - typedef void ( idClass::*eventCallback_iiiifiif_t )( const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_iiiifiif_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65681 : - typedef void ( idClass::*eventCallback_fiiifiif_t )( const float, const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_fiiifiif_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65682 : - typedef void ( idClass::*eventCallback_ifiifiif_t )( const intptr_t, const float, const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_ifiifiif_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65683 : - typedef void ( idClass::*eventCallback_ffiifiif_t )( const float, const float, const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_ffiifiif_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65684 : - typedef void ( idClass::*eventCallback_iififiif_t )( const intptr_t, const intptr_t, const float, const intptr_t, const float, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_iififiif_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65685 : - typedef void ( idClass::*eventCallback_fififiif_t )( const float, const intptr_t, const float, const intptr_t, const float, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_fififiif_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65686 : - typedef void ( idClass::*eventCallback_iffifiif_t )( const intptr_t, const float, const float, const intptr_t, const float, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_iffifiif_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65687 : - typedef void ( idClass::*eventCallback_fffifiif_t )( const float, const float, const float, const intptr_t, const float, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_fffifiif_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65688 : - typedef void ( idClass::*eventCallback_iiiffiif_t )( const intptr_t, const intptr_t, const intptr_t, const float, const float, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_iiiffiif_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65689 : - typedef void ( idClass::*eventCallback_fiiffiif_t )( const float, const intptr_t, const intptr_t, const float, const float, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_fiiffiif_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65690 : - typedef void ( idClass::*eventCallback_ififfiif_t )( const intptr_t, const float, const intptr_t, const float, const float, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_ififfiif_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65691 : - typedef void ( idClass::*eventCallback_ffiffiif_t )( const float, const float, const intptr_t, const float, const float, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_ffiffiif_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65692 : - typedef void ( idClass::*eventCallback_iifffiif_t )( const intptr_t, const intptr_t, const float, const float, const float, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_iifffiif_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65693 : - typedef void ( idClass::*eventCallback_fifffiif_t )( const float, const intptr_t, const float, const float, const float, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_fifffiif_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65694 : - typedef void ( idClass::*eventCallback_iffffiif_t )( const intptr_t, const float, const float, const float, const float, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_iffffiif_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65695 : - typedef void ( idClass::*eventCallback_fffffiif_t )( const float, const float, const float, const float, const float, const intptr_t, const intptr_t, const float ); - ( this->*( eventCallback_fffffiif_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65696 : - typedef void ( idClass::*eventCallback_iiiiifif_t )( const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t, const float ); - ( this->*( eventCallback_iiiiifif_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65697 : - typedef void ( idClass::*eventCallback_fiiiifif_t )( const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t, const float ); - ( this->*( eventCallback_fiiiifif_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65698 : - typedef void ( idClass::*eventCallback_ifiiifif_t )( const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t, const float ); - ( this->*( eventCallback_ifiiifif_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65699 : - typedef void ( idClass::*eventCallback_ffiiifif_t )( const float, const float, const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t, const float ); - ( this->*( eventCallback_ffiiifif_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65700 : - typedef void ( idClass::*eventCallback_iifiifif_t )( const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t, const float, const intptr_t, const float ); - ( this->*( eventCallback_iifiifif_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65701 : - typedef void ( idClass::*eventCallback_fifiifif_t )( const float, const intptr_t, const float, const intptr_t, const intptr_t, const float, const intptr_t, const float ); - ( this->*( eventCallback_fifiifif_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65702 : - typedef void ( idClass::*eventCallback_iffiifif_t )( const intptr_t, const float, const float, const intptr_t, const intptr_t, const float, const intptr_t, const float ); - ( this->*( eventCallback_iffiifif_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65703 : - typedef void ( idClass::*eventCallback_fffiifif_t )( const float, const float, const float, const intptr_t, const intptr_t, const float, const intptr_t, const float ); - ( this->*( eventCallback_fffiifif_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65704 : - typedef void ( idClass::*eventCallback_iiififif_t )( const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t, const float, const intptr_t, const float ); - ( this->*( eventCallback_iiififif_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65705 : - typedef void ( idClass::*eventCallback_fiififif_t )( const float, const intptr_t, const intptr_t, const float, const intptr_t, const float, const intptr_t, const float ); - ( this->*( eventCallback_fiififif_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65706 : - typedef void ( idClass::*eventCallback_ifififif_t )( const intptr_t, const float, const intptr_t, const float, const intptr_t, const float, const intptr_t, const float ); - ( this->*( eventCallback_ifififif_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65707 : - typedef void ( idClass::*eventCallback_ffififif_t )( const float, const float, const intptr_t, const float, const intptr_t, const float, const intptr_t, const float ); - ( this->*( eventCallback_ffififif_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65708 : - typedef void ( idClass::*eventCallback_iiffifif_t )( const intptr_t, const intptr_t, const float, const float, const intptr_t, const float, const intptr_t, const float ); - ( this->*( eventCallback_iiffifif_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65709 : - typedef void ( idClass::*eventCallback_fiffifif_t )( const float, const intptr_t, const float, const float, const intptr_t, const float, const intptr_t, const float ); - ( this->*( eventCallback_fiffifif_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65710 : - typedef void ( idClass::*eventCallback_ifffifif_t )( const intptr_t, const float, const float, const float, const intptr_t, const float, const intptr_t, const float ); - ( this->*( eventCallback_ifffifif_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65711 : - typedef void ( idClass::*eventCallback_ffffifif_t )( const float, const float, const float, const float, const intptr_t, const float, const intptr_t, const float ); - ( this->*( eventCallback_ffffifif_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65712 : - typedef void ( idClass::*eventCallback_iiiiffif_t )( const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float, const float, const intptr_t, const float ); - ( this->*( eventCallback_iiiiffif_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65713 : - typedef void ( idClass::*eventCallback_fiiiffif_t )( const float, const intptr_t, const intptr_t, const intptr_t, const float, const float, const intptr_t, const float ); - ( this->*( eventCallback_fiiiffif_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65714 : - typedef void ( idClass::*eventCallback_ifiiffif_t )( const intptr_t, const float, const intptr_t, const intptr_t, const float, const float, const intptr_t, const float ); - ( this->*( eventCallback_ifiiffif_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65715 : - typedef void ( idClass::*eventCallback_ffiiffif_t )( const float, const float, const intptr_t, const intptr_t, const float, const float, const intptr_t, const float ); - ( this->*( eventCallback_ffiiffif_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65716 : - typedef void ( idClass::*eventCallback_iififfif_t )( const intptr_t, const intptr_t, const float, const intptr_t, const float, const float, const intptr_t, const float ); - ( this->*( eventCallback_iififfif_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65717 : - typedef void ( idClass::*eventCallback_fififfif_t )( const float, const intptr_t, const float, const intptr_t, const float, const float, const intptr_t, const float ); - ( this->*( eventCallback_fififfif_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65718 : - typedef void ( idClass::*eventCallback_iffiffif_t )( const intptr_t, const float, const float, const intptr_t, const float, const float, const intptr_t, const float ); - ( this->*( eventCallback_iffiffif_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65719 : - typedef void ( idClass::*eventCallback_fffiffif_t )( const float, const float, const float, const intptr_t, const float, const float, const intptr_t, const float ); - ( this->*( eventCallback_fffiffif_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65720 : - typedef void ( idClass::*eventCallback_iiifffif_t )( const intptr_t, const intptr_t, const intptr_t, const float, const float, const float, const intptr_t, const float ); - ( this->*( eventCallback_iiifffif_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65721 : - typedef void ( idClass::*eventCallback_fiifffif_t )( const float, const intptr_t, const intptr_t, const float, const float, const float, const intptr_t, const float ); - ( this->*( eventCallback_fiifffif_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65722 : - typedef void ( idClass::*eventCallback_ififffif_t )( const intptr_t, const float, const intptr_t, const float, const float, const float, const intptr_t, const float ); - ( this->*( eventCallback_ififffif_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65723 : - typedef void ( idClass::*eventCallback_ffifffif_t )( const float, const float, const intptr_t, const float, const float, const float, const intptr_t, const float ); - ( this->*( eventCallback_ffifffif_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65724 : - typedef void ( idClass::*eventCallback_iiffffif_t )( const intptr_t, const intptr_t, const float, const float, const float, const float, const intptr_t, const float ); - ( this->*( eventCallback_iiffffif_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65725 : - typedef void ( idClass::*eventCallback_fiffffif_t )( const float, const intptr_t, const float, const float, const float, const float, const intptr_t, const float ); - ( this->*( eventCallback_fiffffif_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65726 : - typedef void ( idClass::*eventCallback_ifffffif_t )( const intptr_t, const float, const float, const float, const float, const float, const intptr_t, const float ); - ( this->*( eventCallback_ifffffif_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65727 : - typedef void ( idClass::*eventCallback_ffffffif_t )( const float, const float, const float, const float, const float, const float, const intptr_t, const float ); - ( this->*( eventCallback_ffffffif_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65728 : - typedef void ( idClass::*eventCallback_iiiiiiff_t )( const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float, const float ); - ( this->*( eventCallback_iiiiiiff_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65729 : - typedef void ( idClass::*eventCallback_fiiiiiff_t )( const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float, const float ); - ( this->*( eventCallback_fiiiiiff_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65730 : - typedef void ( idClass::*eventCallback_ifiiiiff_t )( const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float, const float ); - ( this->*( eventCallback_ifiiiiff_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65731 : - typedef void ( idClass::*eventCallback_ffiiiiff_t )( const float, const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float, const float ); - ( this->*( eventCallback_ffiiiiff_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65732 : - typedef void ( idClass::*eventCallback_iifiiiff_t )( const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t, const float, const float ); - ( this->*( eventCallback_iifiiiff_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65733 : - typedef void ( idClass::*eventCallback_fifiiiff_t )( const float, const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t, const float, const float ); - ( this->*( eventCallback_fifiiiff_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65734 : - typedef void ( idClass::*eventCallback_iffiiiff_t )( const intptr_t, const float, const float, const intptr_t, const intptr_t, const intptr_t, const float, const float ); - ( this->*( eventCallback_iffiiiff_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65735 : - typedef void ( idClass::*eventCallback_fffiiiff_t )( const float, const float, const float, const intptr_t, const intptr_t, const intptr_t, const float, const float ); - ( this->*( eventCallback_fffiiiff_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65736 : - typedef void ( idClass::*eventCallback_iiifiiff_t )( const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t, const float, const float ); - ( this->*( eventCallback_iiifiiff_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65737 : - typedef void ( idClass::*eventCallback_fiifiiff_t )( const float, const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t, const float, const float ); - ( this->*( eventCallback_fiifiiff_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65738 : - typedef void ( idClass::*eventCallback_ififiiff_t )( const intptr_t, const float, const intptr_t, const float, const intptr_t, const intptr_t, const float, const float ); - ( this->*( eventCallback_ififiiff_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65739 : - typedef void ( idClass::*eventCallback_ffifiiff_t )( const float, const float, const intptr_t, const float, const intptr_t, const intptr_t, const float, const float ); - ( this->*( eventCallback_ffifiiff_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65740 : - typedef void ( idClass::*eventCallback_iiffiiff_t )( const intptr_t, const intptr_t, const float, const float, const intptr_t, const intptr_t, const float, const float ); - ( this->*( eventCallback_iiffiiff_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65741 : - typedef void ( idClass::*eventCallback_fiffiiff_t )( const float, const intptr_t, const float, const float, const intptr_t, const intptr_t, const float, const float ); - ( this->*( eventCallback_fiffiiff_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65742 : - typedef void ( idClass::*eventCallback_ifffiiff_t )( const intptr_t, const float, const float, const float, const intptr_t, const intptr_t, const float, const float ); - ( this->*( eventCallback_ifffiiff_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65743 : - typedef void ( idClass::*eventCallback_ffffiiff_t )( const float, const float, const float, const float, const intptr_t, const intptr_t, const float, const float ); - ( this->*( eventCallback_ffffiiff_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65744 : - typedef void ( idClass::*eventCallback_iiiififf_t )( const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t, const float, const float ); - ( this->*( eventCallback_iiiififf_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65745 : - typedef void ( idClass::*eventCallback_fiiififf_t )( const float, const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t, const float, const float ); - ( this->*( eventCallback_fiiififf_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65746 : - typedef void ( idClass::*eventCallback_ifiififf_t )( const intptr_t, const float, const intptr_t, const intptr_t, const float, const intptr_t, const float, const float ); - ( this->*( eventCallback_ifiififf_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65747 : - typedef void ( idClass::*eventCallback_ffiififf_t )( const float, const float, const intptr_t, const intptr_t, const float, const intptr_t, const float, const float ); - ( this->*( eventCallback_ffiififf_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65748 : - typedef void ( idClass::*eventCallback_iifififf_t )( const intptr_t, const intptr_t, const float, const intptr_t, const float, const intptr_t, const float, const float ); - ( this->*( eventCallback_iifififf_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65749 : - typedef void ( idClass::*eventCallback_fifififf_t )( const float, const intptr_t, const float, const intptr_t, const float, const intptr_t, const float, const float ); - ( this->*( eventCallback_fifififf_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65750 : - typedef void ( idClass::*eventCallback_iffififf_t )( const intptr_t, const float, const float, const intptr_t, const float, const intptr_t, const float, const float ); - ( this->*( eventCallback_iffififf_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65751 : - typedef void ( idClass::*eventCallback_fffififf_t )( const float, const float, const float, const intptr_t, const float, const intptr_t, const float, const float ); - ( this->*( eventCallback_fffififf_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65752 : - typedef void ( idClass::*eventCallback_iiiffiff_t )( const intptr_t, const intptr_t, const intptr_t, const float, const float, const intptr_t, const float, const float ); - ( this->*( eventCallback_iiiffiff_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65753 : - typedef void ( idClass::*eventCallback_fiiffiff_t )( const float, const intptr_t, const intptr_t, const float, const float, const intptr_t, const float, const float ); - ( this->*( eventCallback_fiiffiff_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65754 : - typedef void ( idClass::*eventCallback_ififfiff_t )( const intptr_t, const float, const intptr_t, const float, const float, const intptr_t, const float, const float ); - ( this->*( eventCallback_ififfiff_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65755 : - typedef void ( idClass::*eventCallback_ffiffiff_t )( const float, const float, const intptr_t, const float, const float, const intptr_t, const float, const float ); - ( this->*( eventCallback_ffiffiff_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65756 : - typedef void ( idClass::*eventCallback_iifffiff_t )( const intptr_t, const intptr_t, const float, const float, const float, const intptr_t, const float, const float ); - ( this->*( eventCallback_iifffiff_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65757 : - typedef void ( idClass::*eventCallback_fifffiff_t )( const float, const intptr_t, const float, const float, const float, const intptr_t, const float, const float ); - ( this->*( eventCallback_fifffiff_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65758 : - typedef void ( idClass::*eventCallback_iffffiff_t )( const intptr_t, const float, const float, const float, const float, const intptr_t, const float, const float ); - ( this->*( eventCallback_iffffiff_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65759 : - typedef void ( idClass::*eventCallback_fffffiff_t )( const float, const float, const float, const float, const float, const intptr_t, const float, const float ); - ( this->*( eventCallback_fffffiff_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65760 : - typedef void ( idClass::*eventCallback_iiiiifff_t )( const intptr_t, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float, const float, const float ); - ( this->*( eventCallback_iiiiifff_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65761 : - typedef void ( idClass::*eventCallback_fiiiifff_t )( const float, const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float, const float, const float ); - ( this->*( eventCallback_fiiiifff_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65762 : - typedef void ( idClass::*eventCallback_ifiiifff_t )( const intptr_t, const float, const intptr_t, const intptr_t, const intptr_t, const float, const float, const float ); - ( this->*( eventCallback_ifiiifff_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65763 : - typedef void ( idClass::*eventCallback_ffiiifff_t )( const float, const float, const intptr_t, const intptr_t, const intptr_t, const float, const float, const float ); - ( this->*( eventCallback_ffiiifff_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65764 : - typedef void ( idClass::*eventCallback_iifiifff_t )( const intptr_t, const intptr_t, const float, const intptr_t, const intptr_t, const float, const float, const float ); - ( this->*( eventCallback_iifiifff_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65765 : - typedef void ( idClass::*eventCallback_fifiifff_t )( const float, const intptr_t, const float, const intptr_t, const intptr_t, const float, const float, const float ); - ( this->*( eventCallback_fifiifff_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65766 : - typedef void ( idClass::*eventCallback_iffiifff_t )( const intptr_t, const float, const float, const intptr_t, const intptr_t, const float, const float, const float ); - ( this->*( eventCallback_iffiifff_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65767 : - typedef void ( idClass::*eventCallback_fffiifff_t )( const float, const float, const float, const intptr_t, const intptr_t, const float, const float, const float ); - ( this->*( eventCallback_fffiifff_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65768 : - typedef void ( idClass::*eventCallback_iiififff_t )( const intptr_t, const intptr_t, const intptr_t, const float, const intptr_t, const float, const float, const float ); - ( this->*( eventCallback_iiififff_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65769 : - typedef void ( idClass::*eventCallback_fiififff_t )( const float, const intptr_t, const intptr_t, const float, const intptr_t, const float, const float, const float ); - ( this->*( eventCallback_fiififff_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65770 : - typedef void ( idClass::*eventCallback_ifififff_t )( const intptr_t, const float, const intptr_t, const float, const intptr_t, const float, const float, const float ); - ( this->*( eventCallback_ifififff_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65771 : - typedef void ( idClass::*eventCallback_ffififff_t )( const float, const float, const intptr_t, const float, const intptr_t, const float, const float, const float ); - ( this->*( eventCallback_ffififff_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65772 : - typedef void ( idClass::*eventCallback_iiffifff_t )( const intptr_t, const intptr_t, const float, const float, const intptr_t, const float, const float, const float ); - ( this->*( eventCallback_iiffifff_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65773 : - typedef void ( idClass::*eventCallback_fiffifff_t )( const float, const intptr_t, const float, const float, const intptr_t, const float, const float, const float ); - ( this->*( eventCallback_fiffifff_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65774 : - typedef void ( idClass::*eventCallback_ifffifff_t )( const intptr_t, const float, const float, const float, const intptr_t, const float, const float, const float ); - ( this->*( eventCallback_ifffifff_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65775 : - typedef void ( idClass::*eventCallback_ffffifff_t )( const float, const float, const float, const float, const intptr_t, const float, const float, const float ); - ( this->*( eventCallback_ffffifff_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65776 : - typedef void ( idClass::*eventCallback_iiiiffff_t )( const intptr_t, const intptr_t, const intptr_t, const intptr_t, const float, const float, const float, const float ); - ( this->*( eventCallback_iiiiffff_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65777 : - typedef void ( idClass::*eventCallback_fiiiffff_t )( const float, const intptr_t, const intptr_t, const intptr_t, const float, const float, const float, const float ); - ( this->*( eventCallback_fiiiffff_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65778 : - typedef void ( idClass::*eventCallback_ifiiffff_t )( const intptr_t, const float, const intptr_t, const intptr_t, const float, const float, const float, const float ); - ( this->*( eventCallback_ifiiffff_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65779 : - typedef void ( idClass::*eventCallback_ffiiffff_t )( const float, const float, const intptr_t, const intptr_t, const float, const float, const float, const float ); - ( this->*( eventCallback_ffiiffff_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65780 : - typedef void ( idClass::*eventCallback_iififfff_t )( const intptr_t, const intptr_t, const float, const intptr_t, const float, const float, const float, const float ); - ( this->*( eventCallback_iififfff_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65781 : - typedef void ( idClass::*eventCallback_fififfff_t )( const float, const intptr_t, const float, const intptr_t, const float, const float, const float, const float ); - ( this->*( eventCallback_fififfff_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65782 : - typedef void ( idClass::*eventCallback_iffiffff_t )( const intptr_t, const float, const float, const intptr_t, const float, const float, const float, const float ); - ( this->*( eventCallback_iffiffff_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65783 : - typedef void ( idClass::*eventCallback_fffiffff_t )( const float, const float, const float, const intptr_t, const float, const float, const float, const float ); - ( this->*( eventCallback_fffiffff_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65784 : - typedef void ( idClass::*eventCallback_iiifffff_t )( const intptr_t, const intptr_t, const intptr_t, const float, const float, const float, const float, const float ); - ( this->*( eventCallback_iiifffff_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65785 : - typedef void ( idClass::*eventCallback_fiifffff_t )( const float, const intptr_t, const intptr_t, const float, const float, const float, const float, const float ); - ( this->*( eventCallback_fiifffff_t )callback )( *( float * )&data[ 0 ], data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65786 : - typedef void ( idClass::*eventCallback_ififffff_t )( const intptr_t, const float, const intptr_t, const float, const float, const float, const float, const float ); - ( this->*( eventCallback_ififffff_t )callback )( data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65787 : - typedef void ( idClass::*eventCallback_ffifffff_t )( const float, const float, const intptr_t, const float, const float, const float, const float, const float ); - ( this->*( eventCallback_ffifffff_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65788 : - typedef void ( idClass::*eventCallback_iiffffff_t )( const intptr_t, const intptr_t, const float, const float, const float, const float, const float, const float ); - ( this->*( eventCallback_iiffffff_t )callback )( data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65789 : - typedef void ( idClass::*eventCallback_fiffffff_t )( const float, const intptr_t, const float, const float, const float, const float, const float, const float ); - ( this->*( eventCallback_fiffffff_t )callback )( *( float * )&data[ 0 ], data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65790 : - typedef void ( idClass::*eventCallback_ifffffff_t )( const intptr_t, const float, const float, const float, const float, const float, const float, const float ); - ( this->*( eventCallback_ifffffff_t )callback )( data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; - - case 65791 : - typedef void ( idClass::*eventCallback_ffffffff_t )( const float, const float, const float, const float, const float, const float, const float, const float ); - ( this->*( eventCallback_ffffffff_t )callback )( *( float * )&data[ 0 ], *( float * )&data[ 1 ], *( float * )&data[ 2 ], *( float * )&data[ 3 ], *( float * )&data[ 4 ], *( float * )&data[ 5 ], *( float * )&data[ 6 ], *( float * )&data[ 7 ] ); - break; diff --git a/d3xp/gamesys/Class.cpp b/d3xp/gamesys/Class.cpp deleted file mode 100644 index 10dd4a0d..00000000 --- a/d3xp/gamesys/Class.cpp +++ /dev/null @@ -1,1002 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "gamesys/SysCvar.h" -#include "script/Script_Thread.h" - -#include "Class.h" - -/* - -Base class for all C++ objects. Provides fast run-time type checking and run-time -instancing of objects. - -*/ - -/*********************************************************************** - - idTypeInfo - -***********************************************************************/ - -// this is the head of a singly linked list of all the idTypes -static idTypeInfo *typelist = NULL; -static idHierarchy classHierarchy; -static int eventCallbackMemory = 0; - -/* -================ -idTypeInfo::idClassType() - -Constructor for class. Should only be called from CLASS_DECLARATION macro. -Handles linking class definition into class hierarchy. This should only happen -at startup as idTypeInfos are statically defined. Since static variables can be -initialized in any order, the constructor must handle the case that subclasses -are initialized before superclasses. -================ -*/ -idTypeInfo::idTypeInfo( const char *classname, const char *superclass, idEventFunc *eventCallbacks, idClass *( *CreateInstance )( void ), - void ( idClass::*Spawn )( void ), void ( idClass::*Save )( idSaveGame *savefile ) const, void ( idClass::*Restore )( idRestoreGame *savefile ) ) { - - idTypeInfo *type; - idTypeInfo **insert; - - this->classname = classname; - this->superclass = superclass; - this->eventCallbacks = eventCallbacks; - this->eventMap = NULL; - this->Spawn = Spawn; - this->Save = Save; - this->Restore = Restore; - this->CreateInstance = CreateInstance; - this->super = idClass::GetClass( superclass ); - this->freeEventMap = false; - typeNum = 0; - lastChild = 0; - - // Check if any subclasses were initialized before their superclass - for( type = typelist; type != NULL; type = type->next ) { - if ( ( type->super == NULL ) && !idStr::Cmp( type->superclass, this->classname ) && - idStr::Cmp( type->classname, "idClass" ) ) { - type->super = this; - } - } - - // Insert sorted - for ( insert = &typelist; *insert; insert = &(*insert)->next ) { - assert( idStr::Cmp( classname, (*insert)->classname ) ); - if ( idStr::Cmp( classname, (*insert)->classname ) < 0 ) { - next = *insert; - *insert = this; - break; - } - } - if ( !*insert ) { - *insert = this; - next = NULL; - } -} - -/* -================ -idTypeInfo::~idTypeInfo -================ -*/ -idTypeInfo::~idTypeInfo() { - Shutdown(); -} - -/* -================ -idTypeInfo::Init - -Initializes the event callback table for the class. Creates a -table for fast lookups of event functions. Should only be called once. -================ -*/ -void idTypeInfo::Init( void ) { - idTypeInfo *c; - idEventFunc *def; - int ev; - int i; - bool *set; - int num; - - if ( eventMap ) { - // we've already been initialized by a subclass - return; - } - - // make sure our superclass is initialized first - if ( super && !super->eventMap ) { - super->Init(); - } - - // add to our node hierarchy - if ( super ) { - node.ParentTo( super->node ); - } else { - node.ParentTo( classHierarchy ); - } - node.SetOwner( this ); - - // keep track of the number of children below each class - for( c = super; c != NULL; c = c->super ) { - c->lastChild++; - } - - // if we're not adding any new event callbacks, we can just use our superclass's table - if ( ( !eventCallbacks || !eventCallbacks->event ) && super ) { - eventMap = super->eventMap; - return; - } - - // set a flag so we know to delete the eventMap table - freeEventMap = true; - - // Allocate our new table. It has to have as many entries as there - // are events. NOTE: could save some space by keeping track of the maximum - // event that the class responds to and doing range checking. - num = idEventDef::NumEventCommands(); - eventMap = new eventCallback_t[ num ]; - memset( eventMap, 0, sizeof( eventCallback_t ) * num ); - eventCallbackMemory += sizeof( eventCallback_t ) * num; - - // allocate temporary memory for flags so that the subclass's event callbacks - // override the superclass's event callback - set = new bool[ num ]; - memset( set, 0, sizeof( bool ) * num ); - - // go through the inheritence order and copies the event callback function into - // a list indexed by the event number. This allows fast lookups of - // event functions. - for( c = this; c != NULL; c = c->super ) { - def = c->eventCallbacks; - if ( !def ) { - continue; - } - - // go through each entry until we hit the NULL terminator - for( i = 0; def[ i ].event != NULL; i++ ) { - ev = def[ i ].event->GetEventNum(); - - if ( set[ ev ] ) { - continue; - } - set[ ev ] = true; - eventMap[ ev ] = def[ i ].function; - } - } - - delete[] set; -} - -/* -================ -idTypeInfo::Shutdown - -Should only be called when DLL or EXE is being shutdown. -Although it cleans up any allocated memory, it doesn't bother to remove itself -from the class list since the program is shutting down. -================ -*/ -void idTypeInfo::Shutdown() { - // free up the memory used for event lookups - if ( eventMap ) { - if ( freeEventMap ) { - delete[] eventMap; - } - eventMap = NULL; - } - typeNum = 0; - lastChild = 0; -} - - -/*********************************************************************** - - idClass - -***********************************************************************/ - -const idEventDef EV_Remove( "", NULL ); -const idEventDef EV_SafeRemove( "remove", NULL ); - -ABSTRACT_DECLARATION( NULL, idClass ) - EVENT( EV_Remove, idClass::Event_Remove ) - EVENT( EV_SafeRemove, idClass::Event_SafeRemove ) -END_CLASS - -// alphabetical order -idList idClass::types; -// typenum order -idList idClass::typenums; - -bool idClass::initialized = false; -int idClass::typeNumBits = 0; -int idClass::memused = 0; -int idClass::numobjects = 0; - -/* -================ -idClass::CallSpawn -================ -*/ -void idClass::CallSpawn( void ) { - idTypeInfo *type; - - type = GetType(); - CallSpawnFunc( type ); -} - -/* -================ -idClass::CallSpawnFunc -================ -*/ -classSpawnFunc_t idClass::CallSpawnFunc( idTypeInfo *cls ) { - classSpawnFunc_t func; - - if ( cls->super ) { - func = CallSpawnFunc( cls->super ); - if ( func == cls->Spawn ) { - // don't call the same function twice in a row. - // this can happen when subclasses don't have their own spawn function. - return func; - } - } - - ( this->*cls->Spawn )(); - - return cls->Spawn; -} - -/* -================ -idClass::FindUninitializedMemory -================ -*/ -void idClass::FindUninitializedMemory( void ) { -#ifdef ID_DEBUG_UNINITIALIZED_MEMORY - unsigned int *ptr = ( ( unsigned int * )this ) - 1; - int size = *ptr; - assert( ( size & 3 ) == 0 ); - size >>= 2; - for ( int i = 0; i < size; i++ ) { - if ( ptr[i] == 0xcdcdcdcd ) { - const char *varName = GetTypeVariableName( GetClassname(), i << 2 ); - gameLocal.Warning( "type '%s' has uninitialized variable %s (offset %d)", GetClassname(), varName, i << 2 ); - } - } -#endif -} - -/* -================ -idClass::Spawn -================ -*/ -void idClass::Spawn( void ) { -} - -/* -================ -idClass::~idClass - -Destructor for object. Cancels any events that depend on this object. -================ -*/ -idClass::~idClass() { - idEvent::CancelEvents( this ); -} - -/* -================ -idClass::DisplayInfo_f -================ -*/ -void idClass::DisplayInfo_f( const idCmdArgs &args ) { - gameLocal.Printf( "Class memory status: %i bytes allocated in %i objects\n", memused, numobjects ); -} - -/* -================ -idClass::ListClasses_f -================ -*/ -void idClass::ListClasses_f( const idCmdArgs &args ) { - int i; - idTypeInfo *type; - - gameLocal.Printf( "%-24s %-24s %-6s %-6s\n", "Classname", "Superclass", "Type", "Subclasses" ); - gameLocal.Printf( "----------------------------------------------------------------------\n" ); - - for( i = 0; i < types.Num(); i++ ) { - type = types[ i ]; - gameLocal.Printf( "%-24s %-24s %6d %6d\n", type->classname, type->superclass, type->typeNum, type->lastChild - type->typeNum ); - } - - gameLocal.Printf( "...%d classes", types.Num() ); -} - -/* -================ -idClass::CreateInstance -================ -*/ -idClass *idClass::CreateInstance( const char *name ) { - const idTypeInfo *type; - idClass *obj; - - type = idClass::GetClass( name ); - if ( !type ) { - return NULL; - } - - obj = type->CreateInstance(); - return obj; -} - -/* -================ -idClass::Init - -Should be called after all idTypeInfos are initialized, so must be called -manually upon game code initialization. Tells all the idTypeInfos to initialize -their event callback table for the associated class. This should only be called -once during the execution of the program or DLL. -================ -*/ -void idClass::Init( void ) { - idTypeInfo *c; - int num; - - gameLocal.Printf( "Initializing class hierarchy\n" ); - - if ( initialized ) { - gameLocal.Printf( "...already initialized\n" ); - return; - } - - // init the event callback tables for all the classes - for( c = typelist; c != NULL; c = c->next ) { - c->Init(); - } - - // number the types according to the class hierarchy so we can quickly determine if a class - // is a subclass of another - num = 0; - for( c = classHierarchy.GetNext(); c != NULL; c = c->node.GetNext(), num++ ) { - c->typeNum = num; - c->lastChild += num; - } - - // number of bits needed to send types over network - typeNumBits = idMath::BitsForInteger( num ); - - // create a list of the types so we can do quick lookups - // one list in alphabetical order, one in typenum order - types.SetGranularity( 1 ); - types.SetNum( num ); - typenums.SetGranularity( 1 ); - typenums.SetNum( num ); - num = 0; - for( c = typelist; c != NULL; c = c->next, num++ ) { - types[ num ] = c; - typenums[ c->typeNum ] = c; - } - - initialized = true; - - gameLocal.Printf( "...%i classes, %i bytes for event callbacks\n", types.Num(), eventCallbackMemory ); -} - -/* -================ -idClass::Shutdown -================ -*/ -void idClass::Shutdown( void ) { - idTypeInfo *c; - - for( c = typelist; c != NULL; c = c->next ) { - c->Shutdown(); - } - types.Clear(); - typenums.Clear(); - - initialized = false; -} - -/* -================ -idClass::new -================ -*/ -#ifdef ID_DEBUG_MEMORY -#undef new -#endif - -void * idClass::operator new( size_t s ) { - int *p; - - s += sizeof( int ); - p = (int *)Mem_Alloc( s ); - *p = s; - memused += s; - numobjects++; - -#ifdef ID_DEBUG_UNINITIALIZED_MEMORY - unsigned int *ptr = (unsigned int *)p; - int size = s; - assert( ( size & 3 ) == 0 ); - size >>= 3; - for ( int i = 1; i < size; i++ ) { - ptr[i] = 0xcdcdcdcd; - } -#endif - - return p + 1; -} - -void * idClass::operator new( size_t s, int, int, char *, int ) { - int *p; - - s += sizeof( int ); - p = (int *)Mem_Alloc( s ); - *p = s; - memused += s; - numobjects++; - -#ifdef ID_DEBUG_UNINITIALIZED_MEMORY - unsigned int *ptr = (unsigned int *)p; - int size = s; - assert( ( size & 3 ) == 0 ); - size >>= 3; - for ( int i = 1; i < size; i++ ) { - ptr[i] = 0xcdcdcdcd; - } -#endif - - return p + 1; -} - -#ifdef ID_DEBUG_MEMORY -#define new ID_DEBUG_NEW -#endif - -/* -================ -idClass::delete -================ -*/ -void idClass::operator delete( void *ptr ) { - int *p; - - if ( ptr ) { - p = ( ( int * )ptr ) - 1; - memused -= *p; - numobjects--; - Mem_Free( p ); - } -} - -void idClass::operator delete( void *ptr, int, int, char *, int ) { - int *p; - - if ( ptr ) { - p = ( ( int * )ptr ) - 1; - memused -= *p; - numobjects--; - Mem_Free( p ); - } -} - -/* -================ -idClass::GetClass - -Returns the idTypeInfo for the name of the class passed in. This is a static function -so it must be called as idClass::GetClass( classname ) -================ -*/ -idTypeInfo *idClass::GetClass( const char *name ) { - idTypeInfo *c; - int order; - int mid; - int min; - int max; - - if ( !initialized ) { - // idClass::Init hasn't been called yet, so do a slow lookup - for( c = typelist; c != NULL; c = c->next ) { - if ( !idStr::Cmp( c->classname, name ) ) { - return c; - } - } - } else { - // do a binary search through the list of types - min = 0; - max = types.Num() - 1; - while( min <= max ) { - mid = ( min + max ) / 2; - c = types[ mid ]; - order = idStr::Cmp( c->classname, name ); - if ( !order ) { - return c; - } else if ( order > 0 ) { - max = mid - 1; - } else { - min = mid + 1; - } - } - } - - return NULL; -} - -/* -================ -idClass::GetType -================ -*/ -idTypeInfo *idClass::GetType( const int typeNum ) { - idTypeInfo *c; - - if ( !initialized ) { - for( c = typelist; c != NULL; c = c->next ) { - if ( c->typeNum == typeNum ) { - return c; - } - } - } else if ( ( typeNum >= 0 ) && ( typeNum < types.Num() ) ) { - return typenums[ typeNum ]; - } - - return NULL; -} - -/* -================ -idClass::GetClassname - -Returns the text classname of the object. -================ -*/ -const char *idClass::GetClassname( void ) const { - idTypeInfo *type; - - type = GetType(); - return type->classname; -} - -/* -================ -idClass::GetSuperclass - -Returns the text classname of the superclass. -================ -*/ -const char *idClass::GetSuperclass( void ) const { - idTypeInfo *cls; - - cls = GetType(); - return cls->superclass; -} - -/* -================ -idClass::CancelEvents -================ -*/ -void idClass::CancelEvents( const idEventDef *ev ) { - idEvent::CancelEvents( this, ev ); -} - -/* -================ -idClass::PostEventArgs -================ -*/ -bool idClass::PostEventArgs( const idEventDef *ev, int time, int numargs, ... ) { - idTypeInfo *c; - idEvent *event; - va_list args; - - assert( ev ); - - if ( !idEvent::initialized ) { - return false; - } - - c = GetType(); - if ( !c->eventMap[ ev->GetEventNum() ] ) { - // we don't respond to this event, so ignore it - return false; - } - - // we service events on the client to avoid any bad code filling up the event pool - // we don't want them processed usually, unless when the map is (re)loading. - // we allow threads to run fine, though. - if ( gameLocal.isClient && ( gameLocal.GameState() != GAMESTATE_STARTUP ) && !IsType( idThread::Type ) ) { - return true; - } - - va_start( args, numargs ); - event = idEvent::Alloc( ev, numargs, args ); - va_end( args ); - - event->Schedule( this, c, time ); - - return true; -} - -/* -================ -idClass::PostEventMS -================ -*/ -bool idClass::PostEventMS( const idEventDef *ev, int time ) { - return PostEventArgs( ev, time, 0 ); -} - -/* -================ -idClass::PostEventMS -================ -*/ -bool idClass::PostEventMS( const idEventDef *ev, int time, idEventArg arg1 ) { - return PostEventArgs( ev, time, 1, &arg1 ); -} - -/* -================ -idClass::PostEventMS -================ -*/ -bool idClass::PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2 ) { - return PostEventArgs( ev, time, 2, &arg1, &arg2 ); -} - -/* -================ -idClass::PostEventMS -================ -*/ -bool idClass::PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2, idEventArg arg3 ) { - return PostEventArgs( ev, time, 3, &arg1, &arg2, &arg3 ); -} - -/* -================ -idClass::PostEventMS -================ -*/ -bool idClass::PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4 ) { - return PostEventArgs( ev, time, 4, &arg1, &arg2, &arg3, &arg4 ); -} - -/* -================ -idClass::PostEventMS -================ -*/ -bool idClass::PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5 ) { - return PostEventArgs( ev, time, 5, &arg1, &arg2, &arg3, &arg4, &arg5 ); -} - -/* -================ -idClass::PostEventMS -================ -*/ -bool idClass::PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6 ) { - return PostEventArgs( ev, time, 6, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6 ); -} - -/* -================ -idClass::PostEventMS -================ -*/ -bool idClass::PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6, idEventArg arg7 ) { - return PostEventArgs( ev, time, 7, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7 ); -} - -/* -================ -idClass::PostEventMS -================ -*/ -bool idClass::PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6, idEventArg arg7, idEventArg arg8 ) { - return PostEventArgs( ev, time, 8, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7, &arg8 ); -} - -/* -================ -idClass::PostEventSec -================ -*/ -bool idClass::PostEventSec( const idEventDef *ev, float time ) { - return PostEventArgs( ev, SEC2MS( time ), 0 ); -} - -/* -================ -idClass::PostEventSec -================ -*/ -bool idClass::PostEventSec( const idEventDef *ev, float time, idEventArg arg1 ) { - return PostEventArgs( ev, SEC2MS( time ), 1, &arg1 ); -} - -/* -================ -idClass::PostEventSec -================ -*/ -bool idClass::PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2 ) { - return PostEventArgs( ev, SEC2MS( time ), 2, &arg1, &arg2 ); -} - -/* -================ -idClass::PostEventSec -================ -*/ -bool idClass::PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2, idEventArg arg3 ) { - return PostEventArgs( ev, SEC2MS( time ), 3, &arg1, &arg2, &arg3 ); -} - -/* -================ -idClass::PostEventSec -================ -*/ -bool idClass::PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4 ) { - return PostEventArgs( ev, SEC2MS( time ), 4, &arg1, &arg2, &arg3, &arg4 ); -} - -/* -================ -idClass::PostEventSec -================ -*/ -bool idClass::PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5 ) { - return PostEventArgs( ev, SEC2MS( time ), 5, &arg1, &arg2, &arg3, &arg4, &arg5 ); -} - -/* -================ -idClass::PostEventSec -================ -*/ -bool idClass::PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6 ) { - return PostEventArgs( ev, SEC2MS( time ), 6, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6 ); -} - -/* -================ -idClass::PostEventSec -================ -*/ -bool idClass::PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6, idEventArg arg7 ) { - return PostEventArgs( ev, SEC2MS( time ), 7, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7 ); -} - -/* -================ -idClass::PostEventSec -================ -*/ -bool idClass::PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6, idEventArg arg7, idEventArg arg8 ) { - return PostEventArgs( ev, SEC2MS( time ), 8, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7, &arg8 ); -} - -/* -================ -idClass::ProcessEventArgs -================ -*/ -bool idClass::ProcessEventArgs( const idEventDef *ev, int numargs, ... ) { - idTypeInfo *c; - int num; - intptr_t data[ D_EVENT_MAXARGS ]; - va_list args; - - assert( ev ); - assert( idEvent::initialized ); - - c = GetType(); - num = ev->GetEventNum(); - if ( !c->eventMap[ num ] ) { - // we don't respond to this event, so ignore it - return false; - } - - va_start( args, numargs ); - idEvent::CopyArgs( ev, numargs, args, data ); - va_end( args ); - - ProcessEventArgPtr( ev, data ); - - return true; -} - -/* -================ -idClass::ProcessEvent -================ -*/ -bool idClass::ProcessEvent( const idEventDef *ev ) { - return ProcessEventArgs( ev, 0 ); -} - -/* -================ -idClass::ProcessEvent -================ -*/ -bool idClass::ProcessEvent( const idEventDef *ev, idEventArg arg1 ) { - return ProcessEventArgs( ev, 1, &arg1 ); -} - -/* -================ -idClass::ProcessEvent -================ -*/ -bool idClass::ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2 ) { - return ProcessEventArgs( ev, 2, &arg1, &arg2 ); -} - -/* -================ -idClass::ProcessEvent -================ -*/ -bool idClass::ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2, idEventArg arg3 ) { - return ProcessEventArgs( ev, 3, &arg1, &arg2, &arg3 ); -} - -/* -================ -idClass::ProcessEvent -================ -*/ -bool idClass::ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4 ) { - return ProcessEventArgs( ev, 4, &arg1, &arg2, &arg3, &arg4 ); -} - -/* -================ -idClass::ProcessEvent -================ -*/ -bool idClass::ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5 ) { - return ProcessEventArgs( ev, 5, &arg1, &arg2, &arg3, &arg4, &arg5 ); -} - -/* -================ -idClass::ProcessEvent -================ -*/ -bool idClass::ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6 ) { - return ProcessEventArgs( ev, 6, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6 ); -} - -/* -================ -idClass::ProcessEvent -================ -*/ -bool idClass::ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6, idEventArg arg7 ) { - return ProcessEventArgs( ev, 7, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7 ); -} - -/* -================ -idClass::ProcessEvent -================ -*/ -bool idClass::ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6, idEventArg arg7, idEventArg arg8 ) { - return ProcessEventArgs( ev, 8, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7, &arg8 ); -} - -/* -================ -idClass::ProcessEventArgPtr -================ -*/ -bool idClass::ProcessEventArgPtr( const idEventDef *ev, intptr_t *data ) { - idTypeInfo *c; - int num; - eventCallback_t callback; - - assert( ev ); - assert( idEvent::initialized ); - -#ifdef _D3XP - SetTimeState ts; - - if ( IsType( idEntity::Type ) ) { - idEntity *ent = (idEntity*)this; - ts.PushState( ent->timeGroup ); - } -#endif - - if ( g_debugTriggers.GetBool() && ( ev == &EV_Activate ) && IsType( idEntity::Type ) ) { - const idEntity *ent = *reinterpret_cast( data ); - gameLocal.Printf( "%d: '%s' activated by '%s'\n", gameLocal.framenum, static_cast( this )->GetName(), ent ? ent->GetName() : "NULL" ); - } - - c = GetType(); - num = ev->GetEventNum(); - if ( !c->eventMap[ num ] ) { - // we don't respond to this event, so ignore it - return false; - } - - callback = c->eventMap[ num ]; - - switch( ev->GetFormatspecIndex() ) { - case 1 << D_EVENT_MAXARGS : - ( this->*callback )(); - break; - -// generated file - see CREATE_EVENT_CODE -#include "Callbacks.cpp" - - default: - gameLocal.Warning( "Invalid formatspec on event '%s'", ev->GetName() ); - break; - } - - return true; -} - -/* -================ -idClass::Event_Remove -================ -*/ -void idClass::Event_Remove( void ) { - delete this; -} - -/* -================ -idClass::Event_SafeRemove -================ -*/ -void idClass::Event_SafeRemove( void ) { - // Forces the remove to be done at a safe time - PostEventMS( &EV_Remove, 0 ); -} diff --git a/d3xp/gamesys/Class.h b/d3xp/gamesys/Class.h deleted file mode 100644 index 99040feb..00000000 --- a/d3xp/gamesys/Class.h +++ /dev/null @@ -1,362 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __SYS_CLASS_H__ -#define __SYS_CLASS_H__ - -#include "idlib/containers/Hierarchy.h" - -#include "gamesys/Event.h" - -class idClass; -class idTypeInfo; - -/* - -Base class for all game objects. Provides fast run-time type checking and run-time -instancing of objects. - -*/ - -extern const idEventDef EV_Remove; -extern const idEventDef EV_SafeRemove; - -typedef void ( idClass::*eventCallback_t )( void ); - -template< class Type > -struct idEventFunc { - const idEventDef *event; - eventCallback_t function; -}; - -// added & so gcc could compile this -#define EVENT( event, function ) { &( event ), ( void ( idClass::* )( void ) )( &function ) }, -#define END_CLASS { NULL, NULL } }; - - -class idEventArg { -public: - int type; - intptr_t value; - - idEventArg() { type = D_EVENT_INTEGER; value = 0; }; - idEventArg( int data ) { type = D_EVENT_INTEGER; value = data; }; - idEventArg( float data ) { type = D_EVENT_FLOAT; value = *reinterpret_cast( &data ); }; - idEventArg( idVec3 &data ) { type = D_EVENT_VECTOR; value = reinterpret_cast( &data ); }; - idEventArg( const idStr &data ) { type = D_EVENT_STRING; value = reinterpret_cast( data.c_str() ); }; - idEventArg( const char *data ) { type = D_EVENT_STRING; value = reinterpret_cast( data ); }; - idEventArg( const class idEntity *data ) { type = D_EVENT_ENTITY; value = reinterpret_cast( data ); }; - idEventArg( const struct trace_s *data ) { type = D_EVENT_TRACE; value = reinterpret_cast( data ); }; -}; - -class idAllocError : public idException { -public: - idAllocError( const char *text = "" ) : idException( text ) {} -}; - -/*********************************************************************** - - idClass - -***********************************************************************/ - -/* -================ -CLASS_PROTOTYPE - -This macro must be included in the definition of any subclass of idClass. -It prototypes variables used in class instanciation and type checking. -Use this on single inheritance concrete classes only. -================ -*/ -#define CLASS_PROTOTYPE( nameofclass ) \ -public: \ - static idTypeInfo Type; \ - static idClass *CreateInstance( void ); \ - virtual idTypeInfo *GetType( void ) const; \ - static idEventFunc eventCallbacks[] - -/* -================ -CLASS_DECLARATION - -This macro must be included in the code to properly initialize variables -used in type checking and run-time instanciation. It also defines the list -of events that the class responds to. Take special care to ensure that the -proper superclass is indicated or the run-time type information will be -incorrect. Use this on concrete classes only. -================ -*/ -#define CLASS_DECLARATION( nameofsuperclass, nameofclass ) \ - idTypeInfo nameofclass::Type( #nameofclass, #nameofsuperclass, \ - ( idEventFunc * )nameofclass::eventCallbacks, nameofclass::CreateInstance, ( void ( idClass::* )( void ) )&nameofclass::Spawn, \ - ( void ( idClass::* )( idSaveGame * ) const )&nameofclass::Save, ( void ( idClass::* )( idRestoreGame * ) )&nameofclass::Restore ); \ - idClass *nameofclass::CreateInstance( void ) { \ - try { \ - nameofclass *ptr = new nameofclass; \ - ptr->FindUninitializedMemory(); \ - return ptr; \ - } \ - catch( idAllocError & ) { \ - return NULL; \ - } \ - } \ - idTypeInfo *nameofclass::GetType( void ) const { \ - return &( nameofclass::Type ); \ - } \ -idEventFunc nameofclass::eventCallbacks[] = { - -/* -================ -ABSTRACT_PROTOTYPE - -This macro must be included in the definition of any abstract subclass of idClass. -It prototypes variables used in class instanciation and type checking. -Use this on single inheritance abstract classes only. -================ -*/ -#define ABSTRACT_PROTOTYPE( nameofclass ) \ -public: \ - static idTypeInfo Type; \ - static idClass *CreateInstance( void ); \ - virtual idTypeInfo *GetType( void ) const; \ - static idEventFunc eventCallbacks[] - -/* -================ -ABSTRACT_DECLARATION - -This macro must be included in the code to properly initialize variables -used in type checking. It also defines the list of events that the class -responds to. Take special care to ensure that the proper superclass is -indicated or the run-time tyep information will be incorrect. Use this -on abstract classes only. -================ -*/ -#define ABSTRACT_DECLARATION( nameofsuperclass, nameofclass ) \ - idTypeInfo nameofclass::Type( #nameofclass, #nameofsuperclass, \ - ( idEventFunc * )nameofclass::eventCallbacks, nameofclass::CreateInstance, ( void ( idClass::* )( void ) )&nameofclass::Spawn, \ - ( void ( idClass::* )( idSaveGame * ) const )&nameofclass::Save, ( void ( idClass::* )( idRestoreGame * ) )&nameofclass::Restore ); \ - idClass *nameofclass::CreateInstance( void ) { \ - gameLocal.Error( "Cannot instanciate abstract class %s.", #nameofclass ); \ - return NULL; \ - } \ - idTypeInfo *nameofclass::GetType( void ) const { \ - return &( nameofclass::Type ); \ - } \ - idEventFunc nameofclass::eventCallbacks[] = { - -typedef void ( idClass::*classSpawnFunc_t )( void ); - -class idSaveGame; -class idRestoreGame; - -class idClass { -public: - ABSTRACT_PROTOTYPE( idClass ); - -#ifdef ID_REDIRECT_NEWDELETE -#undef new -#endif - void * operator new( size_t ); - void * operator new( size_t s, int, int, char *, int ); - void operator delete( void * ); - void operator delete( void *, int, int, char *, int ); -#ifdef ID_REDIRECT_NEWDELETE -#define new ID_DEBUG_NEW -#endif - - virtual ~idClass(); - - void Spawn( void ); - void CallSpawn( void ); - bool IsType( const idTypeInfo &c ) const; - const char * GetClassname( void ) const; - const char * GetSuperclass( void ) const; - void FindUninitializedMemory( void ); - - void Save( idSaveGame *savefile ) const {}; - void Restore( idRestoreGame *savefile ) {}; - - bool RespondsTo( const idEventDef &ev ) const; - - bool PostEventMS( const idEventDef *ev, int time ); - bool PostEventMS( const idEventDef *ev, int time, idEventArg arg1 ); - bool PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2 ); - bool PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2, idEventArg arg3 ); - bool PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4 ); - bool PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5 ); - bool PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6 ); - bool PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6, idEventArg arg7 ); - bool PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6, idEventArg arg7, idEventArg arg8 ); - - bool PostEventSec( const idEventDef *ev, float time ); - bool PostEventSec( const idEventDef *ev, float time, idEventArg arg1 ); - bool PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2 ); - bool PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2, idEventArg arg3 ); - bool PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4 ); - bool PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5 ); - bool PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6 ); - bool PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6, idEventArg arg7 ); - bool PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6, idEventArg arg7, idEventArg arg8 ); - - bool ProcessEvent( const idEventDef *ev ); - bool ProcessEvent( const idEventDef *ev, idEventArg arg1 ); - bool ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2 ); - bool ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2, idEventArg arg3 ); - bool ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4 ); - bool ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5 ); - bool ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6 ); - bool ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6, idEventArg arg7 ); - bool ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6, idEventArg arg7, idEventArg arg8 ); - - bool ProcessEventArgPtr( const idEventDef *ev, intptr_t *data ); - void CancelEvents( const idEventDef *ev ); - - void Event_Remove( void ); - - // Static functions - static void Init( void ); - static void Shutdown( void ); - static idTypeInfo * GetClass( const char *name ); - static void DisplayInfo_f( const idCmdArgs &args ); - static void ListClasses_f( const idCmdArgs &args ); - static idClass * CreateInstance( const char *name ); - static int GetNumTypes( void ) { return types.Num(); } - static int GetTypeNumBits( void ) { return typeNumBits; } - static idTypeInfo * GetType( int num ); - -private: - classSpawnFunc_t CallSpawnFunc( idTypeInfo *cls ); - - bool PostEventArgs( const idEventDef *ev, int time, int numargs, ... ); - bool ProcessEventArgs( const idEventDef *ev, int numargs, ... ); - - void Event_SafeRemove( void ); - - static bool initialized; - static idList types; - static idList typenums; - static int typeNumBits; - static int memused; - static int numobjects; -}; - -/*********************************************************************** - - idTypeInfo - -***********************************************************************/ - -class idTypeInfo { -public: - const char * classname; - const char * superclass; - idClass * ( *CreateInstance )( void ); - void ( idClass::*Spawn )( void ); - void ( idClass::*Save )( idSaveGame *savefile ) const; - void ( idClass::*Restore )( idRestoreGame *savefile ); - - idEventFunc * eventCallbacks; - eventCallback_t * eventMap; - idTypeInfo * super; - idTypeInfo * next; - bool freeEventMap; - int typeNum; - int lastChild; - - idHierarchy node; - - idTypeInfo( const char *classname, const char *superclass, - idEventFunc *eventCallbacks, idClass *( *CreateInstance )( void ), void ( idClass::*Spawn )( void ), - void ( idClass::*Save )( idSaveGame *savefile ) const, void ( idClass::*Restore )( idRestoreGame *savefile ) ); - ~idTypeInfo(); - - void Init( void ); - void Shutdown( void ); - - bool IsType( const idTypeInfo &superclass ) const; - bool RespondsTo( const idEventDef &ev ) const; -}; - -/* -================ -idTypeInfo::IsType - -Checks if the object's class is a subclass of the class defined by the -passed in idTypeInfo. -================ -*/ -ID_INLINE bool idTypeInfo::IsType( const idTypeInfo &type ) const { - return ( ( typeNum >= type.typeNum ) && ( typeNum <= type.lastChild ) ); -} - -/* -================ -idTypeInfo::RespondsTo -================ -*/ -ID_INLINE bool idTypeInfo::RespondsTo( const idEventDef &ev ) const { - assert( idEvent::initialized ); - if ( !eventMap[ ev.GetEventNum() ] ) { - // we don't respond to this event - return false; - } - - return true; -} - -/* -================ -idClass::IsType - -Checks if the object's class is a subclass of the class defined by the -passed in idTypeInfo. -================ -*/ -ID_INLINE bool idClass::IsType( const idTypeInfo &superclass ) const { - idTypeInfo *subclass; - - subclass = GetType(); - return subclass->IsType( superclass ); -} - -/* -================ -idClass::RespondsTo -================ -*/ -ID_INLINE bool idClass::RespondsTo( const idEventDef &ev ) const { - const idTypeInfo *c; - - assert( idEvent::initialized ); - c = GetType(); - return c->RespondsTo( ev ); -} - -#endif /* !__SYS_CLASS_H__ */ diff --git a/d3xp/gamesys/DebugGraph.cpp b/d3xp/gamesys/DebugGraph.cpp deleted file mode 100644 index 4f98662f..00000000 --- a/d3xp/gamesys/DebugGraph.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "Player.h" -#include "Game_local.h" - -#include "DebugGraph.h" - -/* -================ -idDebugGraph::idDebugGraph -================ -*/ -idDebugGraph::idDebugGraph() { - index = 0; -} - -/* -================ -idDebugGraph::SetNumSamples -================ -*/ -void idDebugGraph::SetNumSamples( int num ) { - index = 0; - samples.Clear(); - samples.SetNum( num ); - memset( samples.Ptr(), 0, samples.MemoryUsed() ); -} - -/* -================ -idDebugGraph::AddValue -================ -*/ -void idDebugGraph::AddValue( float value ) { - samples[ index ] = value; - index++; - if ( index >= samples.Num() ) { - index = 0; - } -} - -/* -================ -idDebugGraph::Draw -================ -*/ -void idDebugGraph::Draw( const idVec4 &color, float scale ) const { - int i; - float value1; - float value2; - idVec3 vec1; - idVec3 vec2; - - const idMat3 &axis = gameLocal.GetLocalPlayer()->viewAxis; - const idVec3 pos = gameLocal.GetLocalPlayer()->GetPhysics()->GetOrigin() + axis[ 1 ] * samples.Num() * 0.5f; - - value1 = samples[ index ] * scale; - for( i = 1; i < samples.Num(); i++ ) { - value2 = samples[ ( i + index ) % samples.Num() ] * scale; - - vec1 = pos + axis[ 2 ] * value1 - axis[ 1 ] * ( i - 1 ) + axis[ 0 ] * samples.Num(); - vec2 = pos + axis[ 2 ] * value2 - axis[ 1 ] * i + axis[ 0 ] * samples.Num(); - - gameRenderWorld->DebugLine( color, vec1, vec2, gameLocal.msec, false ); - value1 = value2; - } -} diff --git a/d3xp/gamesys/DebugGraph.h b/d3xp/gamesys/DebugGraph.h deleted file mode 100644 index 17602480..00000000 --- a/d3xp/gamesys/DebugGraph.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __DEBUGGRAPH_H__ -#define __DEBUGGRAPH_H__ - -#include "idlib/containers/List.h" -#include "idlib/math/Vector.h" - -class idDebugGraph { -public: - idDebugGraph(); - void SetNumSamples( int num ); - void AddValue( float value ); - void Draw( const idVec4 &color, float scale ) const; - -private: - idList samples; - int index; -}; - -#endif diff --git a/d3xp/gamesys/Event.cpp b/d3xp/gamesys/Event.cpp deleted file mode 100644 index 16920de9..00000000 --- a/d3xp/gamesys/Event.cpp +++ /dev/null @@ -1,1066 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "script/Script_Program.h" -#include "Entity.h" -#include "Game_local.h" - -#include "Event.h" - -/* -sys_event.cpp - -Event are used for scheduling tasks and for linking script commands. - -*/ - -#define MAX_EVENTSPERFRAME 4096 -//#define CREATE_EVENT_CODE - -/*********************************************************************** - - idEventDef - -***********************************************************************/ - -idEventDef *idEventDef::eventDefList[MAX_EVENTS]; -int idEventDef::numEventDefs = 0; - -static bool eventError = false; -static char eventErrorMsg[ 128 ]; - -/* -================ -idEventDef::idEventDef -================ -*/ -idEventDef::idEventDef( const char *command, const char *formatspec, char returnType ) { - idEventDef *ev; - int i; - unsigned int bits; - - assert( command ); - assert( !idEvent::initialized ); - - // Allow NULL to indicate no args, but always store it as "" - // so we don't have to check for it. - if ( !formatspec ) { - formatspec = ""; - } - - this->name = command; - this->formatspec = formatspec; - this->returnType = returnType; - - numargs = strlen( formatspec ); - assert( numargs <= D_EVENT_MAXARGS ); - if ( numargs > D_EVENT_MAXARGS ) { - eventError = true; - sprintf( eventErrorMsg, "idEventDef::idEventDef : Too many args for '%s' event.", name ); - return; - } - - // make sure the format for the args is valid, calculate the formatspecindex, and the offsets for each arg - bits = 0; - argsize = 0; - memset( argOffset, 0, sizeof( argOffset ) ); - for( i = 0; i < numargs;i++ ) { - argOffset[ i ] = argsize; - switch( formatspec[ i ] ) { - case D_EVENT_FLOAT : - bits |= 1 << i; - argsize += sizeof( intptr_t ); - break; - - case D_EVENT_INTEGER : - case D_EVENT_ENTITY : - case D_EVENT_ENTITY_NULL : - argsize += sizeof( intptr_t ); - break; - - case D_EVENT_VECTOR : - argsize += E_EVENT_SIZEOF_VEC; - break; - - case D_EVENT_STRING : - argsize += MAX_STRING_LEN; - break; - - case D_EVENT_TRACE : - argsize += sizeof( trace_t ) + MAX_STRING_LEN + sizeof( bool ); - break; - - default : - eventError = true; - sprintf( eventErrorMsg, "idEventDef::idEventDef : Invalid arg format '%s' string for '%s' event.", formatspec, name ); - return; - break; - } - } - - // calculate the formatspecindex - formatspecIndex = ( 1 << ( numargs + D_EVENT_MAXARGS ) ) | bits; - - // go through the list of defined events and check for duplicates - // and mismatched format strings - eventnum = numEventDefs; - for( i = 0; i < eventnum; i++ ) { - ev = eventDefList[ i ]; - if ( strcmp( command, ev->name ) == 0 ) { - if ( strcmp( formatspec, ev->formatspec ) != 0 ) { - eventError = true; - sprintf( eventErrorMsg, "idEvent '%s' defined twice with same name but differing format strings ('%s'!='%s').", - command, formatspec, ev->formatspec ); - return; - } - - if ( ev->returnType != returnType ) { - eventError = true; - sprintf( eventErrorMsg, "idEvent '%s' defined twice with same name but differing return types ('%c'!='%c').", - command, returnType, ev->returnType ); - return; - } - // Don't bother putting the duplicate event in list. - eventnum = ev->eventnum; - return; - } - } - - ev = this; - - if ( numEventDefs >= MAX_EVENTS ) { - eventError = true; - sprintf( eventErrorMsg, "numEventDefs >= MAX_EVENTS" ); - return; - } - eventDefList[numEventDefs] = ev; - numEventDefs++; -} - -/* -================ -idEventDef::NumEventCommands -================ -*/ -int idEventDef::NumEventCommands( void ) { - return numEventDefs; -} - -/* -================ -idEventDef::GetEventCommand -================ -*/ -const idEventDef *idEventDef::GetEventCommand( int eventnum ) { - return eventDefList[ eventnum ]; -} - -/* -================ -idEventDef::FindEvent -================ -*/ -const idEventDef *idEventDef::FindEvent( const char *name ) { - idEventDef *ev; - int num; - int i; - - assert( name ); - - num = numEventDefs; - for( i = 0; i < num; i++ ) { - ev = eventDefList[ i ]; - if ( strcmp( name, ev->name ) == 0 ) { - return ev; - } - } - - return NULL; -} - -/*********************************************************************** - - idEvent - -***********************************************************************/ - -static idLinkList FreeEvents; -static idLinkList EventQueue; -#ifdef _D3XP -static idLinkList FastEventQueue; -#endif -static idEvent EventPool[ MAX_EVENTS ]; - -bool idEvent::initialized = false; - -idDynamicBlockAlloc idEvent::eventDataAllocator; - -/* -================ -idEvent::~idEvent() -================ -*/ -idEvent::~idEvent() { - Free(); -} - -/* -================ -idEvent::Alloc -================ -*/ -idEvent *idEvent::Alloc( const idEventDef *evdef, int numargs, va_list args ) { - idEvent *ev; - size_t size; - const char *format; - idEventArg *arg; - byte *dataPtr; - int i; - const char *materialName; - - if ( FreeEvents.IsListEmpty() ) { - gameLocal.Error( "idEvent::Alloc : No more free events" ); - } - - ev = FreeEvents.Next(); - ev->eventNode.Remove(); - - ev->eventdef = evdef; - - if ( numargs != evdef->GetNumArgs() ) { - gameLocal.Error( "idEvent::Alloc : Wrong number of args for '%s' event.", evdef->GetName() ); - } - - size = evdef->GetArgSize(); - if ( size ) { - ev->data = eventDataAllocator.Alloc( size ); - memset( ev->data, 0, size ); - } else { - ev->data = NULL; - } - - format = evdef->GetArgFormat(); - for( i = 0; i < numargs; i++ ) { - arg = va_arg( args, idEventArg * ); - if ( format[ i ] != arg->type ) { - // when NULL is passed in for an entity, it gets cast as an integer 0, so don't give an error when it happens - if ( !( ( ( format[ i ] == D_EVENT_TRACE ) || ( format[ i ] == D_EVENT_ENTITY ) ) && ( arg->type == 'd' ) && ( arg->value == 0 ) ) ) { - gameLocal.Error( "idEvent::Alloc : Wrong type passed in for arg # %d on '%s' event.", i, evdef->GetName() ); - } - } - - dataPtr = &ev->data[ evdef->GetArgOffset( i ) ]; - - switch( format[ i ] ) { - case D_EVENT_FLOAT : - case D_EVENT_INTEGER : - *reinterpret_cast( dataPtr ) = arg->value; - break; - - case D_EVENT_VECTOR : - if ( arg->value ) { - *reinterpret_cast( dataPtr ) = *reinterpret_cast( arg->value ); - } - break; - - case D_EVENT_STRING : - if ( arg->value ) { - idStr::Copynz( reinterpret_cast( dataPtr ), reinterpret_cast( arg->value ), MAX_STRING_LEN ); - } - break; - - case D_EVENT_ENTITY : - case D_EVENT_ENTITY_NULL : - *reinterpret_cast< idEntityPtr * >( dataPtr ) = reinterpret_cast( arg->value ); - break; - - case D_EVENT_TRACE : - if ( arg->value ) { - *reinterpret_cast( dataPtr ) = true; - *reinterpret_cast( dataPtr + sizeof( bool ) ) = *reinterpret_cast( arg->value ); - - // save off the material as a string since the pointer won't be valid in save games. - // since we save off the entire trace_t structure, if the material is NULL here, - // it will be NULL when we process it, so we don't need to save off anything in that case. - if ( reinterpret_cast( arg->value )->c.material ) { - materialName = reinterpret_cast( arg->value )->c.material->GetName(); - idStr::Copynz( reinterpret_cast( dataPtr + sizeof( bool ) + sizeof( trace_t ) ), materialName, MAX_STRING_LEN ); - } - } else { - *reinterpret_cast( dataPtr ) = false; - } - break; - - default : - gameLocal.Error( "idEvent::Alloc : Invalid arg format '%s' string for '%s' event.", format, evdef->GetName() ); - break; - } - } - - return ev; -} - -/* -================ -idEvent::CopyArgs -================ -*/ -void idEvent::CopyArgs( const idEventDef *evdef, int numargs, va_list args, intptr_t data[ D_EVENT_MAXARGS ] ) { - int i; - const char *format; - idEventArg *arg; - - format = evdef->GetArgFormat(); - if ( numargs != evdef->GetNumArgs() ) { - gameLocal.Error( "idEvent::CopyArgs : Wrong number of args for '%s' event.", evdef->GetName() ); - } - - for( i = 0; i < numargs; i++ ) { - arg = va_arg( args, idEventArg * ); - if ( format[ i ] != arg->type ) { - // when NULL is passed in for an entity, it gets cast as an integer 0, so don't give an error when it happens - if ( !( ( ( format[ i ] == D_EVENT_TRACE ) || ( format[ i ] == D_EVENT_ENTITY ) ) && ( arg->type == 'd' ) && ( arg->value == 0 ) ) ) { - gameLocal.Error( "idEvent::CopyArgs : Wrong type passed in for arg # %d on '%s' event.", i, evdef->GetName() ); - } - } - - data[ i ] = arg->value; - } -} - -/* -================ -idEvent::Free -================ -*/ -void idEvent::Free( void ) { - if ( data ) { - eventDataAllocator.Free( data ); - data = NULL; - } - - eventdef = NULL; - time = 0; - object = NULL; - typeinfo = NULL; - - eventNode.SetOwner( this ); - eventNode.AddToEnd( FreeEvents ); -} - -/* -================ -idEvent::Schedule -================ -*/ -void idEvent::Schedule( idClass *obj, const idTypeInfo *type, int time ) { - idEvent *event; - - assert( initialized ); - if ( !initialized ) { - return; - } - - object = obj; - typeinfo = type; - - // wraps after 24 days...like I care. ;) - this->time = gameLocal.time + time; - - eventNode.Remove(); - -#ifdef _D3XP - if ( obj->IsType( idEntity::Type ) && ( ( (idEntity*)(obj) )->timeGroup == TIME_GROUP2 ) ) { - event = FastEventQueue.Next(); - while( ( event != NULL ) && ( this->time >= event->time ) ) { - event = event->eventNode.Next(); - } - - if ( event ) { - eventNode.InsertBefore( event->eventNode ); - } else { - eventNode.AddToEnd( FastEventQueue ); - } - - return; - } else { - this->time = gameLocal.slow.time + time; - } -#endif - - event = EventQueue.Next(); - while( ( event != NULL ) && ( this->time >= event->time ) ) { - event = event->eventNode.Next(); - } - - if ( event ) { - eventNode.InsertBefore( event->eventNode ); - } else { - eventNode.AddToEnd( EventQueue ); - } -} - -/* -================ -idEvent::CancelEvents -================ -*/ -void idEvent::CancelEvents( const idClass *obj, const idEventDef *evdef ) { - idEvent *event; - idEvent *next; - - if ( !initialized ) { - return; - } - - for( event = EventQueue.Next(); event != NULL; event = next ) { - next = event->eventNode.Next(); - if ( event->object == obj ) { - if ( !evdef || ( evdef == event->eventdef ) ) { - event->Free(); - } - } - } - -#ifdef _D3XP - for( event = FastEventQueue.Next(); event != NULL; event = next ) { - next = event->eventNode.Next(); - if ( event->object == obj ) { - if ( !evdef || ( evdef == event->eventdef ) ) { - event->Free(); - } - } - } -#endif -} - -/* -================ -idEvent::ClearEventList -================ -*/ -void idEvent::ClearEventList( void ) { - int i; - - // - // initialize lists - // - FreeEvents.Clear(); - EventQueue.Clear(); - - // - // add the events to the free list - // - for( i = 0; i < MAX_EVENTS; i++ ) { - EventPool[ i ].Free(); - } -} - -/* -================ -idEvent::ServiceEvents -================ -*/ -void idEvent::ServiceEvents( void ) { - idEvent *event; - int num; - intptr_t args[ D_EVENT_MAXARGS ]; - int offset; - int i; - int numargs; - const char *formatspec; - trace_t **tracePtr; - const idEventDef *ev; - byte *data; - const char *materialName; - - num = 0; - while( !EventQueue.IsListEmpty() ) { - event = EventQueue.Next(); - assert( event ); - - if ( event->time > gameLocal.time ) { - break; - } - - // copy the data into the local args array and set up pointers - ev = event->eventdef; - formatspec = ev->GetArgFormat(); - numargs = ev->GetNumArgs(); - for( i = 0; i < numargs; i++ ) { - offset = ev->GetArgOffset( i ); - data = event->data; - switch( formatspec[ i ] ) { - case D_EVENT_FLOAT : - case D_EVENT_INTEGER : - args[ i ] = *reinterpret_cast( &data[ offset ] ); - break; - - case D_EVENT_VECTOR : - *reinterpret_cast( &args[ i ] ) = reinterpret_cast( &data[ offset ] ); - break; - - case D_EVENT_STRING : - *reinterpret_cast( &args[ i ] ) = reinterpret_cast( &data[ offset ] ); - break; - - case D_EVENT_ENTITY : - case D_EVENT_ENTITY_NULL : - *reinterpret_cast( &args[ i ] ) = reinterpret_cast< idEntityPtr * >( &data[ offset ] )->GetEntity(); - break; - - case D_EVENT_TRACE : - tracePtr = reinterpret_cast( &args[ i ] ); - if ( *reinterpret_cast( &data[ offset ] ) ) { - *tracePtr = reinterpret_cast( &data[ offset + sizeof( bool ) ] ); - - if ( ( *tracePtr )->c.material != NULL ) { - // look up the material name to get the material pointer - materialName = reinterpret_cast( &data[ offset + sizeof( bool ) + sizeof( trace_t ) ] ); - ( *tracePtr )->c.material = declManager->FindMaterial( materialName, true ); - } - } else { - *tracePtr = NULL; - } - break; - - default: - gameLocal.Error( "idEvent::ServiceEvents : Invalid arg format '%s' string for '%s' event.", formatspec, ev->GetName() ); - } - } - - // the event is removed from its list so that if then object - // is deleted, the event won't be freed twice - event->eventNode.Remove(); - assert( event->object ); - event->object->ProcessEventArgPtr( ev, args ); - - // return the event to the free list - event->Free(); - - // Don't allow ourselves to stay in here too long. An abnormally high number - // of events being processed is evidence of an infinite loop of events. - num++; - if ( num > MAX_EVENTSPERFRAME ) { - gameLocal.Error( "Event overflow. Possible infinite loop in script." ); - } - } -} - -#ifdef _D3XP -/* -================ -idEvent::ServiceFastEvents -================ -*/ -void idEvent::ServiceFastEvents() { - idEvent *event; - int num; - intptr_t args[ D_EVENT_MAXARGS ]; - int offset; - int i; - int numargs; - const char *formatspec; - trace_t **tracePtr; - const idEventDef *ev; - byte *data; - const char *materialName; - - num = 0; - while( !FastEventQueue.IsListEmpty() ) { - event = FastEventQueue.Next(); - assert( event ); - - if ( event->time > gameLocal.fast.time ) { - break; - } - - // copy the data into the local args array and set up pointers - ev = event->eventdef; - formatspec = ev->GetArgFormat(); - numargs = ev->GetNumArgs(); - for( i = 0; i < numargs; i++ ) { - offset = ev->GetArgOffset( i ); - data = event->data; - switch( formatspec[ i ] ) { - case D_EVENT_FLOAT : - case D_EVENT_INTEGER : - args[ i ] = *reinterpret_cast( &data[ offset ] ); - break; - - case D_EVENT_VECTOR : - *reinterpret_cast( &args[ i ] ) = reinterpret_cast( &data[ offset ] ); - break; - - case D_EVENT_STRING : - *reinterpret_cast( &args[ i ] ) = reinterpret_cast( &data[ offset ] ); - break; - - case D_EVENT_ENTITY : - case D_EVENT_ENTITY_NULL : - *reinterpret_cast( &args[ i ] ) = reinterpret_cast< idEntityPtr * >( &data[ offset ] )->GetEntity(); - break; - - case D_EVENT_TRACE : - tracePtr = reinterpret_cast( &args[ i ] ); - if ( *reinterpret_cast( &data[ offset ] ) ) { - *tracePtr = reinterpret_cast( &data[ offset + sizeof( bool ) ] ); - - if ( ( *tracePtr )->c.material != NULL ) { - // look up the material name to get the material pointer - materialName = reinterpret_cast( &data[ offset + sizeof( bool ) + sizeof( trace_t ) ] ); - ( *tracePtr )->c.material = declManager->FindMaterial( materialName, true ); - } - } else { - *tracePtr = NULL; - } - break; - - default: - gameLocal.Error( "idEvent::ServiceFastEvents : Invalid arg format '%s' string for '%s' event.", formatspec, ev->GetName() ); - } - } - - // the event is removed from its list so that if then object - // is deleted, the event won't be freed twice - event->eventNode.Remove(); - assert( event->object ); - event->object->ProcessEventArgPtr( ev, args ); - - // return the event to the free list - event->Free(); - - // Don't allow ourselves to stay in here too long. An abnormally high number - // of events being processed is evidence of an infinite loop of events. - num++; - if ( num > MAX_EVENTSPERFRAME ) { - gameLocal.Error( "Event overflow. Possible infinite loop in script." ); - } - } -} -#endif - -/* -================ -idEvent::Init -================ -*/ -void idEvent::Init( void ) { - gameLocal.Printf( "Initializing event system\n" ); - - if ( eventError ) { - gameLocal.Error( "%s", eventErrorMsg ); - } - -#ifdef CREATE_EVENT_CODE - void CreateEventCallbackHandler(); - CreateEventCallbackHandler(); - gameLocal.Error( "Wrote event callback handler" ); -#endif - - if ( initialized ) { - gameLocal.Printf( "...already initialized\n" ); - ClearEventList(); - return; - } - - ClearEventList(); - - eventDataAllocator.Init(); - - gameLocal.Printf( "...%i event definitions\n", idEventDef::NumEventCommands() ); - - // the event system has started - initialized = true; -} - -/* -================ -idEvent::Shutdown -================ -*/ -void idEvent::Shutdown( void ) { - gameLocal.Printf( "Shutdown event system\n" ); - - if ( !initialized ) { - gameLocal.Printf( "...not started\n" ); - return; - } - - ClearEventList(); - - eventDataAllocator.Shutdown(); - - // say it is now shutdown - initialized = false; -} - -/* -================ -idEvent::Save -================ -*/ -void idEvent::Save( idSaveGame *savefile ) { - char *str; - int i, size; - idEvent *event; - byte *dataPtr; - bool validTrace; - const char *format; - idStr s; - - savefile->WriteInt( EventQueue.Num() ); - - event = EventQueue.Next(); - while( event != NULL ) { - savefile->WriteInt( event->time ); - savefile->WriteString( event->eventdef->GetName() ); - savefile->WriteString( event->typeinfo->classname ); - savefile->WriteObject( event->object ); - savefile->WriteInt( event->eventdef->GetArgSize() ); - format = event->eventdef->GetArgFormat(); - for ( i = 0, size = 0; i < event->eventdef->GetNumArgs(); ++i) { - dataPtr = &event->data[ event->eventdef->GetArgOffset( i ) ]; - switch( format[ i ] ) { - case D_EVENT_FLOAT : - savefile->WriteFloat( *reinterpret_cast( dataPtr ) ); - size += sizeof( intptr_t ); - break; - case D_EVENT_INTEGER : - savefile->WriteInt( *reinterpret_cast( dataPtr ) ); - size += sizeof( intptr_t ); - break; - case D_EVENT_ENTITY : - case D_EVENT_ENTITY_NULL : - reinterpret_cast< idEntityPtr * >( dataPtr )->Save(savefile); - size += sizeof( intptr_t ); - break; - case D_EVENT_VECTOR : - savefile->WriteVec3( *reinterpret_cast( dataPtr ) ); - size += E_EVENT_SIZEOF_VEC; - break; - case D_EVENT_STRING : - s.Clear(); - s.Append(reinterpret_cast(dataPtr)); - savefile->WriteString(s); - size += MAX_STRING_LEN; - break; - case D_EVENT_TRACE : - validTrace = *reinterpret_cast( dataPtr ); - savefile->WriteBool( validTrace ); - size += sizeof( bool ); - if ( validTrace ) { - size += sizeof( trace_t ); - const trace_t &t = *reinterpret_cast( dataPtr + sizeof( bool ) ); - SaveTrace( savefile, t ); - if ( t.c.material ) { - size += MAX_STRING_LEN; - str = reinterpret_cast( dataPtr + sizeof( bool ) + sizeof( trace_t ) ); - savefile->Write( str, MAX_STRING_LEN ); - } - } - break; - default: - break; - } - } - assert( size == event->eventdef->GetArgSize() ); - event = event->eventNode.Next(); - } - -#ifdef _D3XP - // Save the Fast EventQueue - savefile->WriteInt( FastEventQueue.Num() ); - - event = FastEventQueue.Next(); - while( event != NULL ) { - savefile->WriteInt( event->time ); - savefile->WriteString( event->eventdef->GetName() ); - savefile->WriteString( event->typeinfo->classname ); - savefile->WriteObject( event->object ); - savefile->WriteInt( event->eventdef->GetArgSize() ); - savefile->Write( event->data, event->eventdef->GetArgSize() ); - - event = event->eventNode.Next(); - } -#endif -} - -/* -================ -idEvent::Restore -================ -*/ -void idEvent::Restore( idRestoreGame *savefile ) { - char *str; - int num, argsize, i, j, size; - idStr name; - byte *dataPtr; - idEvent *event; - const char *format; - idStr s; - - savefile->ReadInt( num ); - - for ( i = 0; i < num; i++ ) { - if ( FreeEvents.IsListEmpty() ) { - gameLocal.Error( "idEvent::Restore : No more free events" ); - } - - event = FreeEvents.Next(); - event->eventNode.Remove(); - event->eventNode.AddToEnd( EventQueue ); - - savefile->ReadInt( event->time ); - - // read the event name - savefile->ReadString( name ); - event->eventdef = idEventDef::FindEvent( name ); - if ( !event->eventdef ) { - savefile->Error( "idEvent::Restore: unknown event '%s'", name.c_str() ); - } - - // read the classtype - savefile->ReadString( name ); - event->typeinfo = idClass::GetClass( name ); - if ( !event->typeinfo ) { - savefile->Error( "idEvent::Restore: unknown class '%s' on event '%s'", name.c_str(), event->eventdef->GetName() ); - } - - savefile->ReadObject( event->object ); - - // read the args - savefile->ReadInt( argsize ); - if ( argsize != event->eventdef->GetArgSize() ) { - savefile->Error( "idEvent::Restore: arg size (%zd) doesn't match saved arg size(%d) on event '%s'", event->eventdef->GetArgSize(), argsize, event->eventdef->GetName() ); - } - if ( argsize ) { - event->data = eventDataAllocator.Alloc( argsize ); - format = event->eventdef->GetArgFormat(); - assert( format ); - for ( j = 0, size = 0; j < event->eventdef->GetNumArgs(); ++j) { - dataPtr = &event->data[ event->eventdef->GetArgOffset( j ) ]; - switch( format[ j ] ) { - case D_EVENT_FLOAT : - savefile->ReadFloat( *reinterpret_cast( dataPtr ) ); - size += sizeof( intptr_t ); - break; - case D_EVENT_INTEGER : - savefile->ReadInt( *reinterpret_cast( dataPtr ) ); - size += sizeof( intptr_t ); - break; - case D_EVENT_ENTITY : - case D_EVENT_ENTITY_NULL : - reinterpret_cast< idEntityPtr * >( dataPtr )->Restore(savefile); - size += sizeof( intptr_t ); - break; - case D_EVENT_VECTOR : - savefile->ReadVec3( *reinterpret_cast( dataPtr ) ); - size += E_EVENT_SIZEOF_VEC; - break; - case D_EVENT_STRING : - savefile->ReadString(s); - idStr::Copynz(reinterpret_cast(dataPtr), s, MAX_STRING_LEN); - size += MAX_STRING_LEN; - break; - case D_EVENT_TRACE : - savefile->ReadBool( *reinterpret_cast( dataPtr ) ); - size += sizeof( bool ); - if ( *reinterpret_cast( dataPtr ) ) { - size += sizeof( trace_t ); - trace_t &t = *reinterpret_cast( dataPtr + sizeof( bool ) ); - RestoreTrace( savefile, t) ; - if ( t.c.material ) { - size += MAX_STRING_LEN; - str = reinterpret_cast( dataPtr + sizeof( bool ) + sizeof( trace_t ) ); - savefile->Read( str, MAX_STRING_LEN ); - } - } - break; - default: - break; - } - } - assert( size == event->eventdef->GetArgSize() ); - } else { - event->data = NULL; - } - } - -#ifdef _D3XP - // Restore the Fast EventQueue - savefile->ReadInt( num ); - - for ( i = 0; i < num; i++ ) { - if ( FreeEvents.IsListEmpty() ) { - gameLocal.Error( "idEvent::Restore : No more free events" ); - } - - event = FreeEvents.Next(); - event->eventNode.Remove(); - event->eventNode.AddToEnd( FastEventQueue ); - - savefile->ReadInt( event->time ); - - // read the event name - savefile->ReadString( name ); - event->eventdef = idEventDef::FindEvent( name ); - if ( !event->eventdef ) { - savefile->Error( "idEvent::Restore: unknown event '%s'", name.c_str() ); - } - - // read the classtype - savefile->ReadString( name ); - event->typeinfo = idClass::GetClass( name ); - if ( !event->typeinfo ) { - savefile->Error( "idEvent::Restore: unknown class '%s' on event '%s'", name.c_str(), event->eventdef->GetName() ); - } - - savefile->ReadObject( event->object ); - - // read the args - savefile->ReadInt( argsize ); - if ( argsize != event->eventdef->GetArgSize() ) { - savefile->Error( "idEvent::Restore: arg size (%zd) doesn't match saved arg size(%d) on event '%s'", event->eventdef->GetArgSize(), argsize, event->eventdef->GetName() ); - } - if ( argsize ) { - event->data = eventDataAllocator.Alloc( argsize ); - savefile->Read( event->data, argsize ); - } else { - event->data = NULL; - } - } -#endif -} - -/* - ================ - idEvent::ReadTrace - - idRestoreGame has a ReadTrace procedure, but unfortunately idEvent wants the material - string name at the of the data structure rather than in the middle - ================ - */ -void idEvent::RestoreTrace( idRestoreGame *savefile, trace_t &trace ) { - savefile->ReadFloat( trace.fraction ); - savefile->ReadVec3( trace.endpos ); - savefile->ReadMat3( trace.endAxis ); - savefile->ReadInt( (int&)trace.c.type ); - savefile->ReadVec3( trace.c.point ); - savefile->ReadVec3( trace.c.normal ); - savefile->ReadFloat( trace.c.dist ); - savefile->ReadInt( trace.c.contents ); - savefile->ReadInt( (int&)trace.c.material ); - savefile->ReadInt( trace.c.contents ); - savefile->ReadInt( trace.c.modelFeature ); - savefile->ReadInt( trace.c.trmFeature ); - savefile->ReadInt( trace.c.id ); -} - -/* - ================ - idEvent::WriteTrace - - idSaveGame has a WriteTrace procedure, but unfortunately idEvent wants the material - string name at the of the data structure rather than in the middle -================ - */ -void idEvent::SaveTrace( idSaveGame *savefile, const trace_t &trace ) { - savefile->WriteFloat( trace.fraction ); - savefile->WriteVec3( trace.endpos ); - savefile->WriteMat3( trace.endAxis ); - savefile->WriteInt( trace.c.type ); - savefile->WriteVec3( trace.c.point ); - savefile->WriteVec3( trace.c.normal ); - savefile->WriteFloat( trace.c.dist ); - savefile->WriteInt( trace.c.contents ); - savefile->WriteInt( (int&)trace.c.material ); - savefile->WriteInt( trace.c.contents ); - savefile->WriteInt( trace.c.modelFeature ); - savefile->WriteInt( trace.c.trmFeature ); - savefile->WriteInt( trace.c.id ); -} - - - -#ifdef CREATE_EVENT_CODE -/* -================ -CreateEventCallbackHandler -================ -*/ -void CreateEventCallbackHandler( void ) { - int i, j, k; - char argString[ D_EVENT_MAXARGS + 1 ]; - idStr string1; - idStr string2; - idFile *file; - - file = fileSystem->OpenFileWrite( "Callbacks.cpp" ); - - file->Printf( "// generated file - see CREATE_EVENT_CODE\n\n" ); - - for( i = 1; i <= D_EVENT_MAXARGS; i++ ) { - - file->Printf( "\t/*******************************************************\n\n\t\t%d args\n\n\t*******************************************************/\n\n", i ); - - for ( j = 0; j < ( 1 << i ); j++ ) { - for( k = 0; k < i; k++ ) { - argString[ k ] = j & ( 1 << k ) ? 'f' : 'i'; - } - argString[ i ] = '\0'; - - string1.Empty(); - string2.Empty(); - - for( k = 0; k < i; k++ ) { - if ( j & ( 1 << k ) ) { - string1 += "const float"; - string2 += va( "*( float * )&data[ %d ]", k ); - } else { - string1 += "const intptr_t"; - string2 += va( "data[ %d ]", k ); - } - - if ( k < i - 1 ) { - string1 += ", "; - string2 += ", "; - } - } - - file->Printf( "\tcase %d :\n\t\ttypedef void ( idClass::*eventCallback_%s_t )( %s );\n", ( 1 << ( i + D_EVENT_MAXARGS ) ) + j, argString, string1.c_str() ); - file->Printf( "\t\t( this->*( eventCallback_%s_t )callback )( %s );\n\t\tbreak;\n\n", argString, string2.c_str() ); - - } - } - - fileSystem->CloseFile( file ); -} - -#endif diff --git a/d3xp/gamesys/Event.h b/d3xp/gamesys/Event.h deleted file mode 100644 index 178fc270..00000000 --- a/d3xp/gamesys/Event.h +++ /dev/null @@ -1,216 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __SYS_EVENT_H__ -#define __SYS_EVENT_H__ - -#include "idlib/containers/LinkList.h" -#include "cm/CollisionModel.h" - -// Event are used for scheduling tasks and for linking script commands. - -#define D_EVENT_MAXARGS 8 // if changed, enable the CREATE_EVENT_CODE define in Event.cpp to generate switch statement for idClass::ProcessEventArgPtr. - // running the game will then generate c:\doom\base\events.txt, the contents of which should be copied into the switch statement. - -// stack size of idVec3, aligned to native pointer size -#define E_EVENT_SIZEOF_VEC ((sizeof(idVec3) + (sizeof(intptr_t) - 1)) & ~(sizeof(intptr_t) - 1)) - -#define D_EVENT_VOID ( ( char )0 ) -#define D_EVENT_INTEGER 'd' -#define D_EVENT_FLOAT 'f' -#define D_EVENT_VECTOR 'v' -#define D_EVENT_STRING 's' -#define D_EVENT_ENTITY 'e' -#define D_EVENT_ENTITY_NULL 'E' // event can handle NULL entity pointers -#define D_EVENT_TRACE 't' - -#define MAX_EVENTS 4096 - -class idClass; -class idTypeInfo; - -class idEventDef { -private: - const char *name; - const char *formatspec; - unsigned int formatspecIndex; - int returnType; - int numargs; - size_t argsize; - int argOffset[ D_EVENT_MAXARGS ]; - int eventnum; - const idEventDef * next; - - static idEventDef * eventDefList[MAX_EVENTS]; - static int numEventDefs; - -public: - idEventDef( const char *command, const char *formatspec = NULL, char returnType = 0 ); - - const char *GetName( void ) const; - const char *GetArgFormat( void ) const; - unsigned int GetFormatspecIndex( void ) const; - char GetReturnType( void ) const; - int GetEventNum( void ) const; - int GetNumArgs( void ) const; - size_t GetArgSize( void ) const; - int GetArgOffset( int arg ) const; - - static int NumEventCommands( void ); - static const idEventDef *GetEventCommand( int eventnum ); - static const idEventDef *FindEvent( const char *name ); -}; - -class idSaveGame; -class idRestoreGame; - -class idEvent { -private: - const idEventDef *eventdef; - byte *data; - int time; - idClass *object; - const idTypeInfo *typeinfo; - - idLinkList eventNode; - - static idDynamicBlockAlloc eventDataAllocator; - - -public: - static bool initialized; - - ~idEvent(); - - static idEvent *Alloc( const idEventDef *evdef, int numargs, va_list args ); - static void CopyArgs( const idEventDef *evdef, int numargs, va_list args, intptr_t data[ D_EVENT_MAXARGS ] ); - - void Free( void ); - void Schedule( idClass *object, const idTypeInfo *cls, int time ); - byte *GetData( void ); - - static void CancelEvents( const idClass *obj, const idEventDef *evdef = NULL ); - static void ClearEventList( void ); - static void ServiceEvents( void ); -#ifdef _D3XP - static void ServiceFastEvents(); -#endif - static void Init( void ); - static void Shutdown( void ); - - // save games - static void Save( idSaveGame *savefile ); // archives object for save game file - static void Restore( idRestoreGame *savefile ); // unarchives object from save game file - static void SaveTrace( idSaveGame *savefile, const trace_t &trace ); - static void RestoreTrace( idRestoreGame *savefile, trace_t &trace ); - -}; - -/* -================ -idEvent::GetData -================ -*/ -ID_INLINE byte *idEvent::GetData( void ) { - return data; -} - -/* -================ -idEventDef::GetName -================ -*/ -ID_INLINE const char *idEventDef::GetName( void ) const { - return name; -} - -/* -================ -idEventDef::GetArgFormat -================ -*/ -ID_INLINE const char *idEventDef::GetArgFormat( void ) const { - return formatspec; -} - -/* -================ -idEventDef::GetFormatspecIndex -================ -*/ -ID_INLINE unsigned int idEventDef::GetFormatspecIndex( void ) const { - return formatspecIndex; -} - -/* -================ -idEventDef::GetReturnType -================ -*/ -ID_INLINE char idEventDef::GetReturnType( void ) const { - return returnType; -} - -/* -================ -idEventDef::GetNumArgs -================ -*/ -ID_INLINE int idEventDef::GetNumArgs( void ) const { - return numargs; -} - -/* -================ -idEventDef::GetArgSize -================ -*/ -ID_INLINE size_t idEventDef::GetArgSize( void ) const { - return argsize; -} - -/* -================ -idEventDef::GetArgOffset -================ -*/ -ID_INLINE int idEventDef::GetArgOffset( int arg ) const { - assert( ( arg >= 0 ) && ( arg < D_EVENT_MAXARGS ) ); - return argOffset[ arg ]; -} - -/* -================ -idEventDef::GetEventNum -================ -*/ -ID_INLINE int idEventDef::GetEventNum( void ) const { - return eventnum; -} - -#endif /* !__SYS_EVENT_H__ */ diff --git a/d3xp/gamesys/NoGameTypeInfo.h b/d3xp/gamesys/NoGameTypeInfo.h deleted file mode 100644 index 11ae5a87..00000000 --- a/d3xp/gamesys/NoGameTypeInfo.h +++ /dev/null @@ -1,79 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __GAMETYPEINFO_H__ -#define __GAMETYPEINFO_H__ - -/* -=================================================================================== - - This file has been generated with the Type Info Generator v1.0 (c) 2004 id Software - -=================================================================================== -*/ - -typedef struct { - const char * name; - const char * type; - const char * value; -} constantInfo_t; - -typedef struct { - const char * name; - int value; -} enumValueInfo_t; - -typedef struct { - const char * typeName; - const enumValueInfo_t * values; -} enumTypeInfo_t; - -typedef struct { - const char * type; - const char * name; - int offset; - int size; -} classVariableInfo_t; - -typedef struct { - const char * typeName; - const char * superType; - int size; - const classVariableInfo_t * variables; -} classTypeInfo_t; - - -static enumTypeInfo_t enumTypeInfo[] = { - { NULL, NULL } -}; - -static classTypeInfo_t classTypeInfo[] = { - { NULL, NULL, 0, NULL } -}; - -#endif /* !__GAMETYPEINFO_H__ */ diff --git a/d3xp/gamesys/SaveGame.cpp b/d3xp/gamesys/SaveGame.cpp deleted file mode 100644 index ce31cf0a..00000000 --- a/d3xp/gamesys/SaveGame.cpp +++ /dev/null @@ -1,1563 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "framework/BuildVersion.h" -#include "framework/DeclSkin.h" -#include "renderer/ModelManager.h" -#include "framework/File.h" - -#include "physics/Clip.h" -#include "Entity.h" -#include "Game_local.h" - -#include "SaveGame.h" - -/* -Save game related helper classes. - -Save games are implemented in two classes, idSaveGame and idRestoreGame, that implement write/read functions for -common types. They're passed in to each entity and object for them to archive themselves. Each class -implements save/restore functions for it's own data. When restoring, all the objects are instantiated, -then the restore function is called on each, superclass first, then subclasses. - -Pointers are restored by saving out an object index for each unique object pointer and adding them to a list of -objects that are to be saved. Restore instantiates all the objects in the list before calling the Restore function -on each object so that the pointers returned are valid. No object's restore function should rely on any other objects -being fully instantiated until after the restore process is complete. Post restore fixup should be done by posting -events with 0 delay. - -The savegame header will have the Game Name, Version, Map Name, and Player Persistent Info. - -Changes in version make savegames incompatible, and the game will start from the beginning of the level with -the player's persistent info. - -Changes to classes that don't need to break compatibilty can use the build number as the savegame version. -Later versions are responsible for restoring from previous versions by ignoring any unused data and initializing -variables that weren't in previous versions with safe information. - -At the head of the save game is enough information to restore the player to the beginning of the level should the -file be unloadable in some way (for example, due to script changes). -*/ - -/* -================ -idSaveGame::idSaveGame() -================ -*/ -idSaveGame::idSaveGame( idFile *savefile ) { - - file = savefile; - - // Put NULL at the start of the list so we can skip over it. - objects.Clear(); - objects.Append( NULL ); -} - -/* -================ -idSaveGame::~idSaveGame() -================ -*/ -idSaveGame::~idSaveGame() { - if ( objects.Num() ) { - Close(); - } -} - -/* -================ -idSaveGame::Close -================ -*/ -void idSaveGame::Close( void ) { - int i; - - WriteSoundCommands(); - - // read trace models - idClipModel::SaveTraceModels( this ); - - for( i = 1; i < objects.Num(); i++ ) { - CallSave_r( objects[ i ]->GetType(), objects[ i ] ); - } - - objects.Clear(); - -#ifdef ID_DEBUG_MEMORY - idStr gameState = file->GetName(); - gameState.StripFileExtension(); - WriteGameState_f( idCmdArgs( va( "test %s_save", gameState.c_str() ), false ) ); -#endif -} - -/* -================ -idSaveGame::WriteObjectList -================ -*/ -void idSaveGame::WriteObjectList( void ) { - int i; - - WriteInt( objects.Num() - 1 ); - for( i = 1; i < objects.Num(); i++ ) { - WriteString( objects[ i ]->GetClassname() ); - } -} - -/* -================ -idSaveGame::CallSave_r -================ -*/ -void idSaveGame::CallSave_r( const idTypeInfo *cls, const idClass *obj ) { - if ( cls->super ) { - CallSave_r( cls->super, obj ); - if ( cls->super->Save == cls->Save ) { - // don't call save on this inheritance level since the function was called in the super class - return; - } - } - - ( obj->*cls->Save )( this ); -} - -/* -================ -idSaveGame::AddObject -================ -*/ -void idSaveGame::AddObject( const idClass *obj ) { - objects.AddUnique( obj ); -} - -/* -================ -idSaveGame::Write -================ -*/ -void idSaveGame::Write( const void *buffer, int len ) { - file->Write( buffer, len ); -} - -/* -================ -idSaveGame::WriteInt -================ -*/ -void idSaveGame::WriteInt( const int value ) { - file->WriteInt( value ); -} - -/* -================ -idSaveGame::WriteJoint -================ -*/ -void idSaveGame::WriteJoint( const jointHandle_t value ) { - file->WriteInt( (int&)value ); -} - -/* -================ -idSaveGame::WriteShort -================ -*/ -void idSaveGame::WriteShort( const short value ) { - file->WriteShort( value ); -} - -/* -================ -idSaveGame::WriteByte -================ -*/ -void idSaveGame::WriteByte( const byte value ) { - file->Write( &value, sizeof( value ) ); -} - -/* -================ -idSaveGame::WriteSignedChar -================ -*/ -void idSaveGame::WriteSignedChar( const signed char value ) { - file->Write( &value, sizeof( value ) ); -} - -/* -================ -idSaveGame::WriteFloat -================ -*/ -void idSaveGame::WriteFloat( const float value ) { - file->WriteFloat( value ); -} - -/* -================ -idSaveGame::WriteBool -================ -*/ -void idSaveGame::WriteBool( const bool value ) { - file->WriteBool( value ); -} - -/* -================ -idSaveGame::WriteString -================ -*/ -void idSaveGame::WriteString( const char *string ) { - int len; - - len = strlen( string ); - WriteInt( len ); - file->Write( string, len ); -} - -/* -================ -idSaveGame::WriteVec2 -================ -*/ -void idSaveGame::WriteVec2( const idVec2 &vec ) { - file->WriteVec2( vec ); -} - -/* -================ -idSaveGame::WriteVec3 -================ -*/ -void idSaveGame::WriteVec3( const idVec3 &vec ) { - file->WriteVec3( vec ); -} - -/* -================ -idSaveGame::WriteVec4 -================ -*/ -void idSaveGame::WriteVec4( const idVec4 &vec ) { - file->WriteVec4( vec ); -} - -/* -================ -idSaveGame::WriteVec6 -================ -*/ -void idSaveGame::WriteVec6( const idVec6 &vec ) { - file->WriteVec6( vec ); -} - -/* -================ -idSaveGame::WriteBounds -================ -*/ -void idSaveGame::WriteBounds( const idBounds &bounds ) { - idBounds b = bounds; - LittleRevBytes( &b, sizeof(float), sizeof(b)/sizeof(float) ); - file->Write( &b, sizeof( b ) ); -} - -/* -================ -idSaveGame::WriteBounds -================ -*/ -void idSaveGame::WriteWinding( const idWinding &w ) -{ - int i, num; - num = w.GetNumPoints(); - file->WriteInt( num ); - for ( i = 0; i < num; i++ ) { - idVec5 v = w[i]; - LittleRevBytes(&v, sizeof(float), sizeof(v)/sizeof(float) ); - file->Write( &v, sizeof(v) ); - } -} - - -/* -================ -idSaveGame::WriteMat3 -================ -*/ -void idSaveGame::WriteMat3( const idMat3 &mat ) { - file->WriteMat3( mat ); -} - -/* -================ -idSaveGame::WriteAngles -================ -*/ -void idSaveGame::WriteAngles( const idAngles &angles ) { - idAngles v = angles; - LittleRevBytes(&v, sizeof(float), sizeof(v)/sizeof(float) ); - file->Write( &v, sizeof( v ) ); -} - -/* -================ -idSaveGame::WriteObject -================ -*/ -void idSaveGame::WriteObject( const idClass *obj ) { - int index; - - index = objects.FindIndex( obj ); - if ( index < 0 ) { - gameLocal.DPrintf( "idSaveGame::WriteObject - WriteObject FindIndex failed\n" ); - - // Use the NULL index - index = 0; - } - - WriteInt( index ); -} - -/* -================ -idSaveGame::WriteStaticObject -================ -*/ -void idSaveGame::WriteStaticObject( const idClass &obj ) { - CallSave_r( obj.GetType(), &obj ); -} - -/* -================ -idSaveGame::WriteDict -================ -*/ -void idSaveGame::WriteDict( const idDict *dict ) { - int num; - int i; - const idKeyValue *kv; - - if ( !dict ) { - WriteInt( -1 ); - } else { - num = dict->GetNumKeyVals(); - WriteInt( num ); - for( i = 0; i < num; i++ ) { - kv = dict->GetKeyVal( i ); - WriteString( kv->GetKey() ); - WriteString( kv->GetValue() ); - } - } -} - -/* -================ -idSaveGame::WriteMaterial -================ -*/ -void idSaveGame::WriteMaterial( const idMaterial *material ) { - if ( !material ) { - WriteString( "" ); - } else { - WriteString( material->GetName() ); - } -} - -/* -================ -idSaveGame::WriteSkin -================ -*/ -void idSaveGame::WriteSkin( const idDeclSkin *skin ) { - if ( !skin ) { - WriteString( "" ); - } else { - WriteString( skin->GetName() ); - } -} - -/* -================ -idSaveGame::WriteParticle -================ -*/ -void idSaveGame::WriteParticle( const idDeclParticle *particle ) { - if ( !particle ) { - WriteString( "" ); - } else { - WriteString( particle->GetName() ); - } -} - -/* -================ -idSaveGame::WriteFX -================ -*/ -void idSaveGame::WriteFX( const idDeclFX *fx ) { - if ( !fx ) { - WriteString( "" ); - } else { - WriteString( fx->GetName() ); - } -} - -/* -================ -idSaveGame::WriteModelDef -================ -*/ -void idSaveGame::WriteModelDef( const idDeclModelDef *modelDef ) { - if ( !modelDef ) { - WriteString( "" ); - } else { - WriteString( modelDef->GetName() ); - } -} - -/* -================ -idSaveGame::WriteSoundShader -================ -*/ -void idSaveGame::WriteSoundShader( const idSoundShader *shader ) { - const char *name; - - if ( !shader ) { - WriteString( "" ); - } else { - name = shader->GetName(); - WriteString( name ); - } -} - -/* -================ -idSaveGame::WriteModel -================ -*/ -void idSaveGame::WriteModel( const idRenderModel *model ) { - const char *name; - - if ( !model ) { - WriteString( "" ); - } else { - name = model->Name(); - WriteString( name ); - } -} - -/* -================ -idSaveGame::WriteUserInterface -================ -*/ -void idSaveGame::WriteUserInterface( const idUserInterface *ui, bool unique ) { - const char *name; - - if ( !ui ) { - WriteString( "" ); - } else { - name = ui->Name(); - WriteString( name ); - WriteBool( unique ); - if ( ui->WriteToSaveGame( file ) == false ) { - gameLocal.Error( "idSaveGame::WriteUserInterface: ui failed to write properly\n" ); - } - } -} - -/* -================ -idSaveGame::WriteRenderEntity -================ -*/ -void idSaveGame::WriteRenderEntity( const renderEntity_t &renderEntity ) { - int i; - - WriteModel( renderEntity.hModel ); - - WriteInt( renderEntity.entityNum ); - WriteInt( renderEntity.bodyId ); - - WriteBounds( renderEntity.bounds ); - - // callback is set by class's Restore function - - WriteInt( renderEntity.suppressSurfaceInViewID ); - WriteInt( renderEntity.suppressShadowInViewID ); - WriteInt( renderEntity.suppressShadowInLightID ); - WriteInt( renderEntity.allowSurfaceInViewID ); - - WriteVec3( renderEntity.origin ); - WriteMat3( renderEntity.axis ); - - WriteMaterial( renderEntity.customShader ); - WriteMaterial( renderEntity.referenceShader ); - WriteSkin( renderEntity.customSkin ); - - if ( renderEntity.referenceSound != NULL ) { - WriteInt( renderEntity.referenceSound->Index() ); - } else { - WriteInt( 0 ); - } - - for( i = 0; i < MAX_ENTITY_SHADER_PARMS; i++ ) { - WriteFloat( renderEntity.shaderParms[ i ] ); - } - - for( i = 0; i < MAX_RENDERENTITY_GUI; i++ ) { - WriteUserInterface( renderEntity.gui[ i ], renderEntity.gui[ i ] ? renderEntity.gui[ i ]->IsUniqued() : false ); - } - - WriteFloat( renderEntity.modelDepthHack ); - - WriteBool( renderEntity.noSelfShadow ); - WriteBool( renderEntity.noShadow ); - WriteBool( renderEntity.noDynamicInteractions ); - WriteBool( renderEntity.weaponDepthHack ); - - WriteInt( renderEntity.forceUpdate ); - -#ifdef _D3XP - WriteInt( renderEntity.timeGroup ); - WriteInt( renderEntity.xrayIndex ); -#endif -} - -/* -================ -idSaveGame::WriteRenderLight -================ -*/ -void idSaveGame::WriteRenderLight( const renderLight_t &renderLight ) { - int i; - - WriteMat3( renderLight.axis ); - WriteVec3( renderLight.origin ); - - WriteInt( renderLight.suppressLightInViewID ); - WriteInt( renderLight.allowLightInViewID ); - WriteBool( renderLight.noShadows ); - WriteBool( renderLight.noSpecular ); - WriteBool( renderLight.pointLight ); - WriteBool( renderLight.parallel ); - - WriteVec3( renderLight.lightRadius ); - WriteVec3( renderLight.lightCenter ); - - WriteVec3( renderLight.target ); - WriteVec3( renderLight.right ); - WriteVec3( renderLight.up ); - WriteVec3( renderLight.start ); - WriteVec3( renderLight.end ); - - // only idLight has a prelightModel and it's always based on the entityname, so we'll restore it there - // WriteModel( renderLight.prelightModel ); - - WriteInt( renderLight.lightId ); - - WriteMaterial( renderLight.shader ); - - for( i = 0; i < MAX_ENTITY_SHADER_PARMS; i++ ) { - WriteFloat( renderLight.shaderParms[ i ] ); - } - - if ( renderLight.referenceSound != NULL ) { - WriteInt( renderLight.referenceSound->Index() ); - } else { - WriteInt( 0 ); - } -} - -/* -================ -idSaveGame::WriteRefSound -================ -*/ -void idSaveGame::WriteRefSound( const refSound_t &refSound ) { - if ( refSound.referenceSound ) { - WriteInt( refSound.referenceSound->Index() ); - } else { - WriteInt( 0 ); - } - WriteVec3( refSound.origin ); - WriteInt( refSound.listenerId ); - WriteSoundShader( refSound.shader ); - WriteFloat( refSound.diversity ); - WriteBool( refSound.waitfortrigger ); - - WriteFloat( refSound.parms.minDistance ); - WriteFloat( refSound.parms.maxDistance ); - WriteFloat( refSound.parms.volume ); - WriteFloat( refSound.parms.shakes ); - WriteInt( refSound.parms.soundShaderFlags ); - WriteInt( refSound.parms.soundClass ); -} - -/* -================ -idSaveGame::WriteRenderView -================ -*/ -void idSaveGame::WriteRenderView( const renderView_t &view ) { - int i; - - WriteInt( view.viewID ); - WriteInt( view.x ); - WriteInt( view.y ); - WriteInt( view.width ); - WriteInt( view.height ); - - WriteFloat( view.fov_x ); - WriteFloat( view.fov_y ); - WriteVec3( view.vieworg ); - WriteMat3( view.viewaxis ); - - WriteBool( view.cramZNear ); - - WriteInt( view.time ); - - for( i = 0; i < MAX_GLOBAL_SHADER_PARMS; i++ ) { - WriteFloat( view.shaderParms[ i ] ); - } -} - -/* -=================== -idSaveGame::WriteUsercmd -=================== -*/ -void idSaveGame::WriteUsercmd( const usercmd_t &usercmd ) { - WriteInt( usercmd.gameFrame ); - WriteInt( usercmd.gameTime ); - WriteInt( usercmd.duplicateCount ); - WriteByte( usercmd.buttons ); - WriteSignedChar( usercmd.forwardmove ); - WriteSignedChar( usercmd.rightmove ); - WriteSignedChar( usercmd.upmove ); - WriteShort( usercmd.angles[0] ); - WriteShort( usercmd.angles[1] ); - WriteShort( usercmd.angles[2] ); - WriteShort( usercmd.mx ); - WriteShort( usercmd.my ); - WriteSignedChar( usercmd.impulse ); - WriteByte( usercmd.flags ); - WriteInt( usercmd.sequence ); -} - -/* -=================== -idSaveGame::WriteContactInfo -=================== -*/ -void idSaveGame::WriteContactInfo( const contactInfo_t &contactInfo ) { - WriteInt( (int)contactInfo.type ); - WriteVec3( contactInfo.point ); - WriteVec3( contactInfo.normal ); - WriteFloat( contactInfo.dist ); - WriteInt( contactInfo.contents ); - WriteMaterial( contactInfo.material ); - WriteInt( contactInfo.modelFeature ); - WriteInt( contactInfo.trmFeature ); - WriteInt( contactInfo.entityNum ); - WriteInt( contactInfo.id ); -} - -/* -=================== -idSaveGame::WriteTrace -=================== -*/ -void idSaveGame::WriteTrace( const trace_t &trace ) { - WriteFloat( trace.fraction ); - WriteVec3( trace.endpos ); - WriteMat3( trace.endAxis ); - WriteContactInfo( trace.c ); -} - -/* - =================== - idRestoreGame::WriteTraceModel - =================== - */ -void idSaveGame::WriteTraceModel( const idTraceModel &trace ) { - int j, k; - - WriteInt( (int&)trace.type ); - WriteInt( trace.numVerts ); - for ( j = 0; j < MAX_TRACEMODEL_VERTS; j++ ) { - WriteVec3( trace.verts[j] ); - } - WriteInt( trace.numEdges ); - for ( j = 0; j < (MAX_TRACEMODEL_EDGES+1); j++ ) { - WriteInt( trace.edges[j].v[0] ); - WriteInt( trace.edges[j].v[1] ); - WriteVec3( trace.edges[j].normal ); - } - WriteInt( trace.numPolys ); - for ( j = 0; j < MAX_TRACEMODEL_POLYS; j++ ) { - WriteVec3( trace.polys[j].normal ); - WriteFloat( trace.polys[j].dist ); - WriteBounds( trace.polys[j].bounds ); - WriteInt( trace.polys[j].numEdges ); - for ( k = 0; k < MAX_TRACEMODEL_POLYEDGES; k++ ) { - WriteInt( trace.polys[j].edges[k] ); - } - } - WriteVec3( trace.offset ); - WriteBounds( trace.bounds ); - WriteBool( trace.isConvex ); - // padding win32 native structs - char tmp[3]; - memset( tmp, 0, sizeof( tmp ) ); - file->Write( tmp, 3 ); -} - -/* -=================== -idSaveGame::WriteClipModel -=================== -*/ -void idSaveGame::WriteClipModel( const idClipModel *clipModel ) { - if ( clipModel != NULL ) { - WriteBool( true ); - clipModel->Save( this ); - } else { - WriteBool( false ); - } -} - -/* -=================== -idSaveGame::WriteSoundCommands -=================== -*/ -void idSaveGame::WriteSoundCommands( void ) { - gameSoundWorld->WriteToSaveGame( file ); -} - -/* -====================== -idSaveGame::WriteBuildNumber -====================== -*/ -void idSaveGame::WriteBuildNumber( const int value ) { - file->WriteInt( BUILD_NUMBER ); -} - -/*********************************************************************** - - idRestoreGame - -***********************************************************************/ - -/* -================ -idRestoreGame::RestoreGame -================ -*/ -idRestoreGame::idRestoreGame( idFile *savefile ) { - file = savefile; - internalSavegameVersion = 0; -} - -/* -================ -idRestoreGame::~idRestoreGame() -================ -*/ -idRestoreGame::~idRestoreGame() { -} - -/* -================ -void idRestoreGame::CreateObjects -================ -*/ -void idRestoreGame::CreateObjects( void ) { - int i, num; - idStr classname; - idTypeInfo *type; - - ReadInt( num ); - - // create all the objects - objects.SetNum( num + 1 ); - memset( objects.Ptr(), 0, sizeof( objects[ 0 ] ) * objects.Num() ); - - for( i = 1; i < objects.Num(); i++ ) { - ReadString( classname ); - type = idClass::GetClass( classname ); - if ( !type ) { - Error( "idRestoreGame::CreateObjects: Unknown class '%s'", classname.c_str() ); - } - objects[ i ] = type->CreateInstance(); - -#ifdef ID_DEBUG_MEMORY - InitTypeVariables( objects[i], type->classname, 0xce ); -#endif - } -} - -/* -================ -void idRestoreGame::RestoreObjects -================ -*/ -void idRestoreGame::RestoreObjects( void ) { - int i; - - ReadSoundCommands(); - - // read trace models - idClipModel::RestoreTraceModels( this ); - - // restore all the objects - for( i = 1; i < objects.Num(); i++ ) { - CallRestore_r( objects[ i ]->GetType(), objects[ i ] ); - } - - // regenerate render entities and render lights because are not saved - for( i = 1; i < objects.Num(); i++ ) { - if ( objects[ i ]->IsType( idEntity::Type ) ) { - idEntity *ent = static_cast( objects[ i ] ); - ent->UpdateVisuals(); - ent->Present(); - } - } - -#ifdef ID_DEBUG_MEMORY - idStr gameState = file->GetName(); - gameState.StripFileExtension(); - WriteGameState_f( idCmdArgs( va( "test %s_restore", gameState.c_str() ), false ) ); - //CompareGameState_f( idCmdArgs( va( "test %s_save", gameState.c_str() ) ) ); - gameLocal.Error( "dumped game states" ); -#endif -} - -/* -==================== -void idRestoreGame::DeleteObjects -==================== -*/ -void idRestoreGame::DeleteObjects( void ) { - - // Remove the NULL object before deleting - objects.RemoveIndex( 0 ); - - objects.DeleteContents( true ); -} - -/* -================ -idRestoreGame::Error -================ -*/ -void idRestoreGame::Error( const char *fmt, ... ) { - va_list argptr; - char text[ 1024 ]; - - va_start( argptr, fmt ); - vsprintf( text, fmt, argptr ); - va_end( argptr ); - - objects.DeleteContents( true ); - - gameLocal.Error( "%s", text ); -} - -/* -================ -idRestoreGame::CallRestore_r -================ -*/ -void idRestoreGame::CallRestore_r( const idTypeInfo *cls, idClass *obj ) { - if ( cls->super ) { - CallRestore_r( cls->super, obj ); - if ( cls->super->Restore == cls->Restore ) { - // don't call save on this inheritance level since the function was called in the super class - return; - } - } - - ( obj->*cls->Restore )( this ); -} - -/* -================ -idRestoreGame::Read -================ -*/ -void idRestoreGame::Read( void *buffer, int len ) { - file->Read( buffer, len ); -} - -/* -================ -idRestoreGame::ReadInt -================ -*/ -void idRestoreGame::ReadInt( int &value ) { - file->ReadInt( value ); -} - -/* -================ -idRestoreGame::ReadJoint -================ -*/ -void idRestoreGame::ReadJoint( jointHandle_t &value ) { - file->ReadInt( (int&)value ); -} - -/* -================ -idRestoreGame::ReadShort -================ -*/ -void idRestoreGame::ReadShort( short &value ) { - file->ReadShort( value ); -} - -/* -================ -idRestoreGame::ReadByte -================ -*/ -void idRestoreGame::ReadByte( byte &value ) { - file->Read( &value, sizeof( value ) ); -} - -/* -================ -idRestoreGame::ReadSignedChar -================ -*/ -void idRestoreGame::ReadSignedChar( signed char &value ) { - file->Read( &value, sizeof( value ) ); -} - -/* -================ -idRestoreGame::ReadFloat -================ -*/ -void idRestoreGame::ReadFloat( float &value ) { - file->ReadFloat( value ); -} - -/* -================ -idRestoreGame::ReadBool -================ -*/ -void idRestoreGame::ReadBool( bool &value ) { - file->ReadBool( value ); -} - -/* -================ -idRestoreGame::ReadString -================ -*/ -void idRestoreGame::ReadString( idStr &string ) { - int len; - - ReadInt( len ); - if ( len < 0 ) { - Error( "idRestoreGame::ReadString: invalid length" ); - } - - string.Fill( ' ', len ); - file->Read( &string[ 0 ], len ); -} - -/* -================ -idRestoreGame::ReadVec2 -================ -*/ -void idRestoreGame::ReadVec2( idVec2 &vec ) { - file->ReadVec2( vec ); -} - -/* -================ -idRestoreGame::ReadVec3 -================ -*/ -void idRestoreGame::ReadVec3( idVec3 &vec ) { - file->ReadVec3( vec ); -} - -/* -================ -idRestoreGame::ReadVec4 -================ -*/ -void idRestoreGame::ReadVec4( idVec4 &vec ) { - file->ReadVec4( vec ); -} - -/* -================ -idRestoreGame::ReadVec6 -================ -*/ -void idRestoreGame::ReadVec6( idVec6 &vec ) { - file->ReadVec6( vec ); -} - -/* -================ -idRestoreGame::ReadBounds -================ -*/ -void idRestoreGame::ReadBounds( idBounds &bounds ) { - file->Read( &bounds, sizeof( bounds ) ); - LittleRevBytes( &bounds, sizeof(float), sizeof(bounds)/sizeof(float) ); -} - -/* -================ -idRestoreGame::ReadWinding -================ -*/ -void idRestoreGame::ReadWinding( idWinding &w ) -{ - int i, num; - file->ReadInt( num ); - w.SetNumPoints( num ); - for ( i = 0; i < num; i++ ) { - file->Read( &w[i], sizeof(idVec5) ); - LittleRevBytes(&w[i], sizeof(float), sizeof(idVec5)/sizeof(float) ); - } -} - -/* -================ -idRestoreGame::ReadMat3 -================ -*/ -void idRestoreGame::ReadMat3( idMat3 &mat ) { - file->ReadMat3( mat ); -} - -/* -================ -idRestoreGame::ReadAngles -================ -*/ -void idRestoreGame::ReadAngles( idAngles &angles ) { - file->Read( &angles, sizeof( angles ) ); - LittleRevBytes(&angles, sizeof(float), sizeof(idAngles)/sizeof(float) ); -} - -/* -================ -idRestoreGame::ReadObject -================ -*/ -void idRestoreGame::ReadObject( idClass *&obj ) { - int index; - - ReadInt( index ); - if ( ( index < 0 ) || ( index >= objects.Num() ) ) { - Error( "idRestoreGame::ReadObject: invalid object index" ); - } - obj = objects[ index ]; -} - -/* -================ -idRestoreGame::ReadStaticObject -================ -*/ -void idRestoreGame::ReadStaticObject( idClass &obj ) { - CallRestore_r( obj.GetType(), &obj ); -} - -/* -================ -idRestoreGame::ReadDict -================ -*/ -void idRestoreGame::ReadDict( idDict *dict ) { - int num; - int i; - idStr key; - idStr value; - - ReadInt( num ); - - if ( num < 0 ) { - dict = NULL; - } else { - dict->Clear(); - for( i = 0; i < num; i++ ) { - ReadString( key ); - ReadString( value ); - dict->Set( key, value ); - } - } -} - -/* -================ -idRestoreGame::ReadMaterial -================ -*/ -void idRestoreGame::ReadMaterial( const idMaterial *&material ) { - idStr name; - - ReadString( name ); - if ( !name.Length() ) { - material = NULL; - } else { - material = declManager->FindMaterial( name ); - } -} - -/* -================ -idRestoreGame::ReadSkin -================ -*/ -void idRestoreGame::ReadSkin( const idDeclSkin *&skin ) { - idStr name; - - ReadString( name ); - if ( !name.Length() ) { - skin = NULL; - } else { - skin = declManager->FindSkin( name ); - } -} - -/* -================ -idRestoreGame::ReadParticle -================ -*/ -void idRestoreGame::ReadParticle( const idDeclParticle *&particle ) { - idStr name; - - ReadString( name ); - if ( !name.Length() ) { - particle = NULL; - } else { - particle = static_cast( declManager->FindType( DECL_PARTICLE, name ) ); - } -} - -/* -================ -idRestoreGame::ReadFX -================ -*/ -void idRestoreGame::ReadFX( const idDeclFX *&fx ) { - idStr name; - - ReadString( name ); - if ( !name.Length() ) { - fx = NULL; - } else { - fx = static_cast( declManager->FindType( DECL_FX, name ) ); - } -} - -/* -================ -idRestoreGame::ReadSoundShader -================ -*/ -void idRestoreGame::ReadSoundShader( const idSoundShader *&shader ) { - idStr name; - - ReadString( name ); - if ( !name.Length() ) { - shader = NULL; - } else { - shader = declManager->FindSound( name ); - } -} - -/* -================ -idRestoreGame::ReadModelDef -================ -*/ -void idRestoreGame::ReadModelDef( const idDeclModelDef *&modelDef ) { - idStr name; - - ReadString( name ); - if ( !name.Length() ) { - modelDef = NULL; - } else { - modelDef = static_cast( declManager->FindType( DECL_MODELDEF, name, false ) ); - } -} - -/* -================ -idRestoreGame::ReadModel -================ -*/ -void idRestoreGame::ReadModel( idRenderModel *&model ) { - idStr name; - - ReadString( name ); - if ( !name.Length() ) { - model = NULL; - } else { - model = renderModelManager->FindModel( name ); - } -} - -/* -================ -idRestoreGame::ReadUserInterface -================ -*/ -void idRestoreGame::ReadUserInterface( idUserInterface *&ui ) { - idStr name; - - ReadString( name ); - if ( !name.Length() ) { - ui = NULL; - } else { - bool unique; - ReadBool( unique ); - ui = uiManager->FindGui( name, true, unique ); - if ( ui ) { - if ( ui->ReadFromSaveGame( file ) == false ) { - Error( "idSaveGame::ReadUserInterface: ui failed to read properly\n" ); - } else { - ui->StateChanged( gameLocal.time ); - } - } - } -} - -/* -================ -idRestoreGame::ReadRenderEntity -================ -*/ -void idRestoreGame::ReadRenderEntity( renderEntity_t &renderEntity ) { - int i; - int index; - - ReadModel( renderEntity.hModel ); - - ReadInt( renderEntity.entityNum ); - ReadInt( renderEntity.bodyId ); - - ReadBounds( renderEntity.bounds ); - - // callback is set by class's Restore function - renderEntity.callback = NULL; - renderEntity.callbackData = NULL; - - ReadInt( renderEntity.suppressSurfaceInViewID ); - ReadInt( renderEntity.suppressShadowInViewID ); - ReadInt( renderEntity.suppressShadowInLightID ); - ReadInt( renderEntity.allowSurfaceInViewID ); - - ReadVec3( renderEntity.origin ); - ReadMat3( renderEntity.axis ); - - ReadMaterial( renderEntity.customShader ); - ReadMaterial( renderEntity.referenceShader ); - ReadSkin( renderEntity.customSkin ); - - ReadInt( index ); - renderEntity.referenceSound = gameSoundWorld->EmitterForIndex( index ); - - for( i = 0; i < MAX_ENTITY_SHADER_PARMS; i++ ) { - ReadFloat( renderEntity.shaderParms[ i ] ); - } - - for( i = 0; i < MAX_RENDERENTITY_GUI; i++ ) { - ReadUserInterface( renderEntity.gui[ i ] ); - } - - // idEntity will restore "cameraTarget", which will be used in idEntity::Present to restore the remoteRenderView - renderEntity.remoteRenderView = NULL; - - renderEntity.joints = NULL; - renderEntity.numJoints = 0; - - ReadFloat( renderEntity.modelDepthHack ); - - ReadBool( renderEntity.noSelfShadow ); - ReadBool( renderEntity.noShadow ); - ReadBool( renderEntity.noDynamicInteractions ); - ReadBool( renderEntity.weaponDepthHack ); - - ReadInt( renderEntity.forceUpdate ); - -#ifdef _D3XP - ReadInt( renderEntity.timeGroup ); - ReadInt( renderEntity.xrayIndex ); -#endif -} - -/* -================ -idRestoreGame::ReadRenderLight -================ -*/ -void idRestoreGame::ReadRenderLight( renderLight_t &renderLight ) { - int index; - int i; - - ReadMat3( renderLight.axis ); - ReadVec3( renderLight.origin ); - - ReadInt( renderLight.suppressLightInViewID ); - ReadInt( renderLight.allowLightInViewID ); - ReadBool( renderLight.noShadows ); - ReadBool( renderLight.noSpecular ); - ReadBool( renderLight.pointLight ); - ReadBool( renderLight.parallel ); - - ReadVec3( renderLight.lightRadius ); - ReadVec3( renderLight.lightCenter ); - - ReadVec3( renderLight.target ); - ReadVec3( renderLight.right ); - ReadVec3( renderLight.up ); - ReadVec3( renderLight.start ); - ReadVec3( renderLight.end ); - - // only idLight has a prelightModel and it's always based on the entityname, so we'll restore it there - // ReadModel( renderLight.prelightModel ); - renderLight.prelightModel = NULL; - - ReadInt( renderLight.lightId ); - - ReadMaterial( renderLight.shader ); - - for( i = 0; i < MAX_ENTITY_SHADER_PARMS; i++ ) { - ReadFloat( renderLight.shaderParms[ i ] ); - } - - ReadInt( index ); - renderLight.referenceSound = gameSoundWorld->EmitterForIndex( index ); -} - -/* -================ -idRestoreGame::ReadRefSound -================ -*/ -void idRestoreGame::ReadRefSound( refSound_t &refSound ) { - int index; - ReadInt( index ); - - refSound.referenceSound = gameSoundWorld->EmitterForIndex( index ); - ReadVec3( refSound.origin ); - ReadInt( refSound.listenerId ); - ReadSoundShader( refSound.shader ); - ReadFloat( refSound.diversity ); - ReadBool( refSound.waitfortrigger ); - - ReadFloat( refSound.parms.minDistance ); - ReadFloat( refSound.parms.maxDistance ); - ReadFloat( refSound.parms.volume ); - ReadFloat( refSound.parms.shakes ); - ReadInt( refSound.parms.soundShaderFlags ); - ReadInt( refSound.parms.soundClass ); -} - -/* -================ -idRestoreGame::ReadRenderView -================ -*/ -void idRestoreGame::ReadRenderView( renderView_t &view ) { - int i; - - ReadInt( view.viewID ); - ReadInt( view.x ); - ReadInt( view.y ); - ReadInt( view.width ); - ReadInt( view.height ); - - ReadFloat( view.fov_x ); - ReadFloat( view.fov_y ); - ReadVec3( view.vieworg ); - ReadMat3( view.viewaxis ); - - ReadBool( view.cramZNear ); - - ReadInt( view.time ); - - for( i = 0; i < MAX_GLOBAL_SHADER_PARMS; i++ ) { - ReadFloat( view.shaderParms[ i ] ); - } -} - -/* -================= -idRestoreGame::ReadUsercmd -================= -*/ -void idRestoreGame::ReadUsercmd( usercmd_t &usercmd ) { - ReadInt( usercmd.gameFrame ); - ReadInt( usercmd.gameTime ); - ReadInt( usercmd.duplicateCount ); - ReadByte( usercmd.buttons ); - ReadSignedChar( usercmd.forwardmove ); - ReadSignedChar( usercmd.rightmove ); - ReadSignedChar( usercmd.upmove ); - ReadShort( usercmd.angles[0] ); - ReadShort( usercmd.angles[1] ); - ReadShort( usercmd.angles[2] ); - ReadShort( usercmd.mx ); - ReadShort( usercmd.my ); - ReadSignedChar( usercmd.impulse ); - ReadByte( usercmd.flags ); - ReadInt( usercmd.sequence ); -} - -/* -=================== -idRestoreGame::ReadContactInfo -=================== -*/ -void idRestoreGame::ReadContactInfo( contactInfo_t &contactInfo ) { - ReadInt( (int &)contactInfo.type ); - ReadVec3( contactInfo.point ); - ReadVec3( contactInfo.normal ); - ReadFloat( contactInfo.dist ); - ReadInt( contactInfo.contents ); - ReadMaterial( contactInfo.material ); - ReadInt( contactInfo.modelFeature ); - ReadInt( contactInfo.trmFeature ); - ReadInt( contactInfo.entityNum ); - ReadInt( contactInfo.id ); -} - -/* -=================== -idRestoreGame::ReadTrace -=================== -*/ -void idRestoreGame::ReadTrace( trace_t &trace ) { - ReadFloat( trace.fraction ); - ReadVec3( trace.endpos ); - ReadMat3( trace.endAxis ); - ReadContactInfo( trace.c ); -} - -/* - =================== - idRestoreGame::ReadTraceModel - =================== - */ -void idRestoreGame::ReadTraceModel( idTraceModel &trace ) { - int j, k; - - ReadInt( (int&)trace.type ); - ReadInt( trace.numVerts ); - for ( j = 0; j < MAX_TRACEMODEL_VERTS; j++ ) { - ReadVec3( trace.verts[j] ); - } - ReadInt( trace.numEdges ); - for ( j = 0; j < (MAX_TRACEMODEL_EDGES+1); j++ ) { - ReadInt( trace.edges[j].v[0] ); - ReadInt( trace.edges[j].v[1] ); - ReadVec3( trace.edges[j].normal ); - } - ReadInt( trace.numPolys ); - for ( j = 0; j < MAX_TRACEMODEL_POLYS; j++ ) { - ReadVec3( trace.polys[j].normal ); - ReadFloat( trace.polys[j].dist ); - ReadBounds( trace.polys[j].bounds ); - ReadInt( trace.polys[j].numEdges ); - for ( k = 0; k < MAX_TRACEMODEL_POLYEDGES; k++ ) { - ReadInt( trace.polys[j].edges[k] ); - } - } - ReadVec3( trace.offset ); - ReadBounds( trace.bounds ); - ReadBool( trace.isConvex ); - // padding win32 native structs - char tmp[3]; - file->Read( tmp, 3 ); -} - -/* -===================== -idRestoreGame::ReadClipModel -===================== -*/ -void idRestoreGame::ReadClipModel( idClipModel *&clipModel ) { - bool restoreClipModel; - - ReadBool( restoreClipModel ); - if ( restoreClipModel ) { - clipModel = new idClipModel(); - clipModel->Restore( this ); - } else { - clipModel = NULL; - } -} - -/* -===================== -idRestoreGame::ReadSoundCommands -===================== -*/ -void idRestoreGame::ReadSoundCommands( void ) { - gameSoundWorld->StopAllSounds(); - gameSoundWorld->ReadFromSaveGame( file ); -} - -/* -===================== -idRestoreGame::ReadBuildNumber -===================== -*/ -void idRestoreGame::ReadBuildNumber( void ) { - file->ReadInt( buildNumber ); -} - -/* -===================== -idRestoreGame::GetBuildNumber -===================== -*/ -int idRestoreGame::GetBuildNumber( void ) { - return buildNumber; -} diff --git a/d3xp/gamesys/SaveGame.h b/d3xp/gamesys/SaveGame.h deleted file mode 100644 index b7816597..00000000 --- a/d3xp/gamesys/SaveGame.h +++ /dev/null @@ -1,186 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __SAVEGAME_H__ -#define __SAVEGAME_H__ - -#include "framework/DeclFX.h" -#include "framework/Game.h" -#include "renderer/Model.h" -#include "renderer/RenderSystem.h" - -#include "gamesys/Class.h" - -/* - -Save game related helper classes. - -*/ - -const int INITIAL_RELEASE_BUILD_NUMBER = 1262; - -class idSaveGame { -public: - idSaveGame( idFile *savefile ); - ~idSaveGame(); - - void Close( void ); - - void AddObject( const idClass *obj ); - void WriteObjectList( void ); - - void Write( const void *buffer, int len ); - void WriteInt( const int value ); - void WriteJoint( const jointHandle_t value ); - void WriteShort( const short value ); - void WriteByte( const byte value ); - void WriteSignedChar( const signed char value ); - void WriteFloat( const float value ); - void WriteBool( const bool value ); - void WriteString( const char *string ); - void WriteVec2( const idVec2 &vec ); - void WriteVec3( const idVec3 &vec ); - void WriteVec4( const idVec4 &vec ); - void WriteVec6( const idVec6 &vec ); - void WriteWinding( const idWinding &winding ); - void WriteBounds( const idBounds &bounds ); - void WriteMat3( const idMat3 &mat ); - void WriteAngles( const idAngles &angles ); - void WriteObject( const idClass *obj ); - void WriteStaticObject( const idClass &obj ); - void WriteDict( const idDict *dict ); - void WriteMaterial( const idMaterial *material ); - void WriteSkin( const idDeclSkin *skin ); - void WriteParticle( const idDeclParticle *particle ); - void WriteFX( const idDeclFX *fx ); - void WriteSoundShader( const idSoundShader *shader ); - void WriteModelDef( const class idDeclModelDef *modelDef ); - void WriteModel( const idRenderModel *model ); - void WriteUserInterface( const idUserInterface *ui, bool unique ); - void WriteRenderEntity( const renderEntity_t &renderEntity ); - void WriteRenderLight( const renderLight_t &renderLight ); - void WriteRefSound( const refSound_t &refSound ); - void WriteRenderView( const renderView_t &view ); - void WriteUsercmd( const usercmd_t &usercmd ); - void WriteContactInfo( const contactInfo_t &contactInfo ); - void WriteTrace( const trace_t &trace ); - void WriteTraceModel( const idTraceModel &trace ); - void WriteClipModel( const class idClipModel *clipModel ); - void WriteSoundCommands( void ); - - void WriteBuildNumber( const int value ); - -private: - idFile * file; - - idList objects; - - void CallSave_r( const idTypeInfo *cls, const idClass *obj ); -}; - -class idRestoreGame { -public: - idRestoreGame( idFile *savefile ); - ~idRestoreGame(); - - void CreateObjects( void ); - void RestoreObjects( void ); - void DeleteObjects( void ); - - void Error( const char *fmt, ... ) id_attribute((format(printf,2,3))); - - void Read( void *buffer, int len ); - void ReadInt( int &value ); - void ReadJoint( jointHandle_t &value ); - void ReadShort( short &value ); - void ReadByte( byte &value ); - void ReadSignedChar( signed char &value ); - void ReadFloat( float &value ); - void ReadBool( bool &value ); - void ReadString( idStr &string ); - void ReadVec2( idVec2 &vec ); - void ReadVec3( idVec3 &vec ); - void ReadVec4( idVec4 &vec ); - void ReadVec6( idVec6 &vec ); - void ReadWinding( idWinding &winding ); - void ReadBounds( idBounds &bounds ); - void ReadMat3( idMat3 &mat ); - void ReadAngles( idAngles &angles ); - void ReadObject( idClass *&obj ); - void ReadStaticObject( idClass &obj ); - void ReadDict( idDict *dict ); - void ReadMaterial( const idMaterial *&material ); - void ReadSkin( const idDeclSkin *&skin ); - void ReadParticle( const idDeclParticle *&particle ); - void ReadFX( const idDeclFX *&fx ); - void ReadSoundShader( const idSoundShader *&shader ); - void ReadModelDef( const idDeclModelDef *&modelDef ); - void ReadModel( idRenderModel *&model ); - void ReadUserInterface( idUserInterface *&ui ); - void ReadRenderEntity( renderEntity_t &renderEntity ); - void ReadRenderLight( renderLight_t &renderLight ); - void ReadRefSound( refSound_t &refSound ); - void ReadRenderView( renderView_t &view ); - void ReadUsercmd( usercmd_t &usercmd ); - void ReadContactInfo( contactInfo_t &contactInfo ); - void ReadTrace( trace_t &trace ); - void ReadTraceModel( idTraceModel &trace ); - void ReadClipModel( idClipModel *&clipModel ); - void ReadSoundCommands( void ); - - void ReadBuildNumber( void ); - - // Used to retrieve the saved game buildNumber from within class Restore methods - int GetBuildNumber( void ); - - // DG: added these methods, internalSavegameVersion makes us independent of the global BUILD_NUMBER - void ReadInternalSavegameVersion( void ) - { - ReadInt( internalSavegameVersion ); - } - - // if it's 0, this is from a GetBuildNumber() < 1305 savegame - // otherwise, compare it to idGameLocal::INTERNAL_SAVEGAME_VERSION - int GetInternalSavegameVersion( void ) const - { - return internalSavegameVersion; - } - // DG end - -private: - int buildNumber; - int internalSavegameVersion; // DG added this - - idFile * file; - - idList objects; - - void CallRestore_r( const idTypeInfo *cls, idClass *obj ); -}; - -#endif /* !__SAVEGAME_H__*/ diff --git a/d3xp/gamesys/SysCmds.cpp b/d3xp/gamesys/SysCmds.cpp deleted file mode 100644 index 9871fe09..00000000 --- a/d3xp/gamesys/SysCmds.cpp +++ /dev/null @@ -1,2520 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "idlib/LangDict.h" -#include "framework/async/NetworkSystem.h" -#include "framework/FileSystem.h" - -#include "gamesys/TypeInfo.h" -#include "gamesys/SysCvar.h" -#include "script/Script_Thread.h" -#include "ai/AI.h" -#include "anim/Anim_Testmodel.h" -#include "Entity.h" -#include "Moveable.h" -#include "WorldSpawn.h" -#include "Fx.h" -#include "Misc.h" - -#include "SysCmds.h" - -/* -================== -Cmd_GetFloatArg -================== -*/ -float Cmd_GetFloatArg( const idCmdArgs &args, int &argNum ) { - const char *value; - - value = args.Argv( argNum++ ); - return atof( value ); -} - -/* -=================== -Cmd_EntityList_f -=================== -*/ -void Cmd_EntityList_f( const idCmdArgs &args ) { - int e; - idEntity *check; - int count; - size_t size; - idStr match; - - if ( args.Argc() > 1 ) { - match = args.Args(); - match.Replace( " ", "" ); - } else { - match = ""; - } - - count = 0; - size = 0; - - gameLocal.Printf( "%-4s %-20s %-20s %s\n", " Num", "EntityDef", "Class", "Name" ); - gameLocal.Printf( "--------------------------------------------------------------------\n" ); - for( e = 0; e < MAX_GENTITIES; e++ ) { - check = gameLocal.entities[ e ]; - - if ( !check ) { - continue; - } - - if ( !check->name.Filter( match, true ) ) { - continue; - } - - gameLocal.Printf( "%4i: %-20s %-20s %s\n", e, - check->GetEntityDefName(), check->GetClassname(), check->name.c_str() ); - - count++; - size += check->spawnArgs.Allocated(); - } - - gameLocal.Printf( "...%d entities\n...%zd bytes of spawnargs\n", count, size ); -} - -/* -=================== -Cmd_ActiveEntityList_f -=================== -*/ -void Cmd_ActiveEntityList_f( const idCmdArgs &args ) { - idEntity *check; - int count; - - count = 0; - - gameLocal.Printf( "%-4s %-20s %-20s %s\n", " Num", "EntityDef", "Class", "Name" ); - gameLocal.Printf( "--------------------------------------------------------------------\n" ); - for( check = gameLocal.activeEntities.Next(); check != NULL; check = check->activeNode.Next() ) { - char dormant = check->fl.isDormant ? '-' : ' '; - gameLocal.Printf( "%4i:%c%-20s %-20s %s\n", check->entityNumber, dormant, check->GetEntityDefName(), check->GetClassname(), check->name.c_str() ); - count++; - } - - gameLocal.Printf( "...%d active entities\n", count ); -} - -/* -=================== -Cmd_ListSpawnArgs_f -=================== -*/ -void Cmd_ListSpawnArgs_f( const idCmdArgs &args ) { - int i; - idEntity *ent; - - ent = gameLocal.FindEntity( args.Argv( 1 ) ); - if ( !ent ) { - gameLocal.Printf( "entity not found\n" ); - return; - } - - for ( i = 0; i < ent->spawnArgs.GetNumKeyVals(); i++ ) { - const idKeyValue *kv = ent->spawnArgs.GetKeyVal( i ); - gameLocal.Printf( "\"%s\" " S_COLOR_WHITE "\"%s\"\n", kv->GetKey().c_str(), kv->GetValue().c_str() ); - } -} - -/* -=================== -Cmd_ReloadScript_f -=================== -*/ -void Cmd_ReloadScript_f( const idCmdArgs &args ) { - // shutdown the map because entities may point to script objects - gameLocal.MapShutdown(); - - // recompile the scripts - gameLocal.program.Startup( SCRIPT_DEFAULT ); - -#ifdef _D3XP - // loads a game specific main script file - idStr gamedir; - int i; - for ( i = 0; i < 2; i++ ) { - if ( i == 0 ) { - gamedir = cvarSystem->GetCVarString( "fs_game_base" ); - } else if ( i == 1 ) { - gamedir = cvarSystem->GetCVarString( "fs_game" ); - } - if ( gamedir.Length() > 0 ) { - idStr scriptFile = va( "script/%s_main.script", gamedir.c_str() ); - if ( fileSystem->ReadFile(scriptFile.c_str(), NULL) > 0 ) { - gameLocal.program.CompileFile( scriptFile.c_str() ); - gameLocal.program.FinishCompilation(); - } - } - } -#endif - - // error out so that the user can rerun the scripts - gameLocal.Error( "Exiting map to reload scripts" ); -} - -/* -=================== -Cmd_Script_f -=================== -*/ -void Cmd_Script_f( const idCmdArgs &args ) { - const char * script; - idStr text; - idStr funcname; - static int funccount = 0; - idThread * thread; - const function_t *func; - idEntity *ent; - - if ( !gameLocal.CheatsOk() ) { - return; - } - - sprintf( funcname, "ConsoleFunction_%d", funccount++ ); - - script = args.Args(); - sprintf( text, "void %s() {%s;}\n", funcname.c_str(), script ); - if ( gameLocal.program.CompileText( "console", text, true ) ) { - func = gameLocal.program.FindFunction( funcname ); - if ( func ) { - // set all the entity names in case the user named one in the script that wasn't referenced in the default script - for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) { - gameLocal.program.SetEntity( ent->name, ent ); - } - - thread = new idThread( func ); - thread->Start(); - } - } -} - -/* -================== -KillEntities - -Kills all the entities of the given class in a level. -================== -*/ -void KillEntities( const idCmdArgs &args, const idTypeInfo &superClass ) { - idEntity *ent; - idStrList ignore; - const char *name; - int i; - - if ( !gameLocal.GetLocalPlayer() || !gameLocal.CheatsOk( false ) ) { - return; - } - - for( i = 1; i < args.Argc(); i++ ) { - name = args.Argv( i ); - ignore.Append( name ); - } - - for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) { - if ( ent->IsType( superClass ) ) { - for( i = 0; i < ignore.Num(); i++ ) { - if ( ignore[ i ] == ent->name ) { - break; - } - } - - if ( i >= ignore.Num() ) { - ent->PostEventMS( &EV_Remove, 0 ); - } - } - } -} - -/* -================== -Cmd_KillMonsters_f - -Kills all the monsters in a level. -================== -*/ -void Cmd_KillMonsters_f( const idCmdArgs &args ) { - KillEntities( args, idAI::Type ); - - // kill any projectiles as well since they have pointers to the monster that created them - KillEntities( args, idProjectile::Type ); -} - -/* -================== -Cmd_KillMovables_f - -Kills all the moveables in a level. -================== -*/ -void Cmd_KillMovables_f( const idCmdArgs &args ) { - if ( !gameLocal.GetLocalPlayer() || !gameLocal.CheatsOk( false ) ) { - return; - } - KillEntities( args, idMoveable::Type ); -} - -/* -================== -Cmd_KillRagdolls_f - -Kills all the ragdolls in a level. -================== -*/ -void Cmd_KillRagdolls_f( const idCmdArgs &args ) { - if ( !gameLocal.GetLocalPlayer() || !gameLocal.CheatsOk( false ) ) { - return; - } - KillEntities( args, idAFEntity_Generic::Type ); - KillEntities( args, idAFEntity_WithAttachedHead::Type ); -} - -/* -================== -Cmd_Give_f - -Give items to a client -================== -*/ -void Cmd_Give_f( const idCmdArgs &args ) { - const char *name; - int i; - bool give_all; - idPlayer *player; - - player = gameLocal.GetLocalPlayer(); - if ( !player || !gameLocal.CheatsOk() ) { - return; - } - - name = args.Argv( 1 ); - - if ( idStr::Icmp( name, "all" ) == 0 ) { - give_all = true; - } else { - give_all = false; - } - - if ( give_all || ( idStr::Cmpn( name, "weapon", 6 ) == 0 ) ) { - if ( gameLocal.world->spawnArgs.GetBool( "no_Weapons" ) ) { - gameLocal.world->spawnArgs.SetBool( "no_Weapons", false ); - for( i = 0; i < gameLocal.numClients; i++ ) { - if ( gameLocal.entities[ i ] ) { - gameLocal.entities[ i ]->PostEventSec( &EV_Player_SelectWeapon, 0.5f, gameLocal.entities[ i ]->spawnArgs.GetString( "def_weapon1" ) ); - } - } - } - } - - if ( ( idStr::Cmpn( name, "weapon_", 7 ) == 0 ) || ( idStr::Cmpn( name, "item_", 5 ) == 0 ) || ( idStr::Cmpn( name, "ammo_", 5 ) == 0 ) ) { - player->GiveItem( name ); - return; - } - - if ( give_all || idStr::Icmp( name, "health" ) == 0 ) { - player->health = player->inventory.maxHealth; - if ( !give_all ) { - return; - } - } - - if ( give_all || idStr::Icmp( name, "weapons" ) == 0 ) { - player->inventory.weapons = 0xffffffff >> ( 32 - MAX_WEAPONS ); - player->CacheWeapons(); - - if ( !give_all ) { - return; - } - } - - if ( give_all || idStr::Icmp( name, "ammo" ) == 0 ) { - for ( i = 0 ; i < AMMO_NUMTYPES; i++ ) { - player->inventory.ammo[ i ] = player->inventory.MaxAmmoForAmmoClass( player, idWeapon::GetAmmoNameForNum( ( ammo_t )i ) ); - } - if ( !give_all ) { - return; - } - } - - if ( give_all || idStr::Icmp( name, "armor" ) == 0 ) { - player->inventory.armor = player->inventory.maxarmor; - if ( !give_all ) { - return; - } - } - - if ( idStr::Icmp( name, "berserk" ) == 0 ) { - player->GivePowerUp( BERSERK, SEC2MS( 30.0f ) ); - return; - } - - if ( idStr::Icmp( name, "invis" ) == 0 ) { - player->GivePowerUp( INVISIBILITY, SEC2MS( 30.0f ) ); - return; - } - -#ifdef _D3XP - if ( idStr::Icmp( name, "invulnerability" ) == 0 ) { - if ( args.Argc() > 2 ) { - player->GivePowerUp( INVULNERABILITY, atoi( args.Argv( 2 ) ) ); - } - else { - player->GivePowerUp( INVULNERABILITY, 30000 ); - } - return; - } - - if ( idStr::Icmp( name, "helltime" ) == 0 ) { - if ( args.Argc() > 2 ) { - player->GivePowerUp( HELLTIME, atoi( args.Argv( 2 ) ) ); - } - else { - player->GivePowerUp( HELLTIME, 30000 ); - } - return; - } - - if ( idStr::Icmp( name, "envirosuit" ) == 0 ) { - if ( args.Argc() > 2 ) { - player->GivePowerUp( ENVIROSUIT, atoi( args.Argv( 2 ) ) ); - } - else { - player->GivePowerUp( ENVIROSUIT, 30000 ); - } - return; - } -#endif - if ( idStr::Icmp( name, "pda" ) == 0 ) { - player->GivePDA( args.Argv(2), NULL ); - return; - } - - if ( idStr::Icmp( name, "video" ) == 0 ) { - player->GiveVideo( args.Argv(2), NULL ); - return; - } - - if ( !give_all && !player->Give( args.Argv(1), args.Argv(2) ) ) { - gameLocal.Printf( "unknown item\n" ); - } -} - -/* -================== -Cmd_CenterView_f - -Centers the players pitch -================== -*/ -void Cmd_CenterView_f( const idCmdArgs &args ) { - idPlayer *player; - idAngles ang; - - player = gameLocal.GetLocalPlayer(); - if ( !player ) { - return; - } - - ang = player->viewAngles; - ang.pitch = 0.0f; - player->SetViewAngles( ang ); -} - -/* -================== -Cmd_God_f - -Sets client to godmode - -argv(0) god -================== -*/ -void Cmd_God_f( const idCmdArgs &args ) { - const char *msg; - idPlayer *player; - - player = gameLocal.GetLocalPlayer(); - if ( !player || !gameLocal.CheatsOk() ) { - return; - } - - if ( player->godmode ) { - player->godmode = false; - msg = "godmode OFF\n"; - } else { - player->godmode = true; - msg = "godmode ON\n"; - } - - gameLocal.Printf( "%s", msg ); -} - -/* -================== -Cmd_Notarget_f - -Sets client to notarget - -argv(0) notarget -================== -*/ -void Cmd_Notarget_f( const idCmdArgs &args ) { - const char *msg; - idPlayer *player; - - player = gameLocal.GetLocalPlayer(); - if ( !player || !gameLocal.CheatsOk() ) { - return; - } - - if ( player->fl.notarget ) { - player->fl.notarget = false; - msg = "notarget OFF\n"; - } else { - player->fl.notarget = true; - msg = "notarget ON\n"; - } - - gameLocal.Printf( "%s", msg ); -} - -/* -================== -Cmd_Noclip_f - -argv(0) noclip -================== -*/ -void Cmd_Noclip_f( const idCmdArgs &args ) { - const char *msg; - idPlayer *player; - - player = gameLocal.GetLocalPlayer(); - if ( !player || !gameLocal.CheatsOk() ) { - return; - } - - if ( player->noclip ) { - msg = "noclip OFF\n"; - } else { - msg = "noclip ON\n"; - } - player->noclip = !player->noclip; - - gameLocal.Printf( "%s", msg ); -} - -/* -================= -Cmd_Kill_f -================= -*/ -void Cmd_Kill_f( const idCmdArgs &args ) { - idPlayer *player; - - if ( gameLocal.isMultiplayer ) { - if ( gameLocal.isClient ) { - idBitMsg outMsg; - byte msgBuf[ MAX_GAME_MESSAGE_SIZE ]; - outMsg.Init( msgBuf, sizeof( msgBuf ) ); - outMsg.WriteByte( GAME_RELIABLE_MESSAGE_KILL ); - networkSystem->ClientSendReliableMessage( outMsg ); - } else { - player = gameLocal.GetClientByCmdArgs( args ); - if ( !player ) { - common->Printf( "kill or kill \n" ); - return; - } - player->Kill( false, false ); - cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "say killed client %d '%s^0'\n", player->entityNumber, gameLocal.userInfo[ player->entityNumber ].GetString( "ui_name" ) ) ); - } - } else { - player = gameLocal.GetLocalPlayer(); - if ( !player ) { - return; - } - player->Kill( false, false ); - } -} - -/* -================= -Cmd_PlayerModel_f -================= -*/ -void Cmd_PlayerModel_f( const idCmdArgs &args ) { - idPlayer *player; - const char *name; - idVec3 pos; - idAngles ang; - - player = gameLocal.GetLocalPlayer(); - if ( !player || !gameLocal.CheatsOk() ) { - return; - } - - if ( args.Argc() < 2 ) { - gameLocal.Printf( "usage: playerModel \n" ); - return; - } - - name = args.Argv( 1 ); - player->spawnArgs.Set( "model", name ); - - pos = player->GetPhysics()->GetOrigin(); - ang = player->viewAngles; - player->SpawnToPoint( pos, ang ); -} - -/* -================== -Cmd_Say -================== -*/ -static void Cmd_Say( bool team, const idCmdArgs &args ) { - const char *name; - idStr text; - const char *cmd = team ? "sayTeam" : "say" ; - - if ( !gameLocal.isMultiplayer ) { - gameLocal.Printf( "%s can only be used in a multiplayer game\n", cmd ); - return; - } - - if ( args.Argc() < 2 ) { - gameLocal.Printf( "usage: %s \n", cmd ); - return; - } - - text = args.Args(); - if ( text.Length() == 0 ) { - return; - } - - if ( text[ text.Length() - 1 ] == '\n' ) { - text[ text.Length() - 1 ] = '\0'; - } - name = "player"; - - idPlayer * player; - - // here we need to special case a listen server to use the real client name instead of "server" - // "server" will only appear on a dedicated server - if ( gameLocal.isClient || cvarSystem->GetCVarInteger( "net_serverDedicated" ) == 0 ) { - player = gameLocal.localClientNum >= 0 ? static_cast( gameLocal.entities[ gameLocal.localClientNum ] ) : NULL; - if ( player ) { - name = player->GetUserInfo()->GetString( "ui_name", "player" ); - } - -#ifdef CTF - // Append the player's location to team chat messages in CTF - if ( gameLocal.mpGame.IsGametypeFlagBased() && team && player ) { - idLocationEntity *locationEntity = gameLocal.LocationForPoint( player->GetEyePosition() ); - - if ( locationEntity ) { - idStr temp = "["; - temp += locationEntity->GetLocation(); - temp += "] "; - temp += text; - text = temp; - } - - } -#endif - - - } else { - name = "server"; - } - - if ( gameLocal.isClient ) { - idBitMsg outMsg; - byte msgBuf[ 256 ]; - outMsg.Init( msgBuf, sizeof( msgBuf ) ); - outMsg.WriteByte( team ? GAME_RELIABLE_MESSAGE_TCHAT : GAME_RELIABLE_MESSAGE_CHAT ); - outMsg.WriteString( name ); - outMsg.WriteString( text, -1, false ); - networkSystem->ClientSendReliableMessage( outMsg ); - } else { - gameLocal.mpGame.ProcessChatMessage( gameLocal.localClientNum, team, name, text, NULL ); - } -} - -/* -================== -Cmd_Say_f -================== -*/ -static void Cmd_Say_f( const idCmdArgs &args ) { - Cmd_Say( false, args ); -} - -/* -================== -Cmd_SayTeam_f -================== -*/ -static void Cmd_SayTeam_f( const idCmdArgs &args ) { - Cmd_Say( true, args ); -} - -/* -================== -Cmd_AddChatLine_f -================== -*/ -static void Cmd_AddChatLine_f( const idCmdArgs &args ) { - gameLocal.mpGame.AddChatLine( args.Argv( 1 ) ); -} - -/* -================== -Cmd_Kick_f -================== -*/ -static void Cmd_Kick_f( const idCmdArgs &args ) { - idPlayer *player; - - if ( !gameLocal.isMultiplayer ) { - gameLocal.Printf( "kick can only be used in a multiplayer game\n" ); - return; - } - - if ( gameLocal.isClient ) { - gameLocal.Printf( "You have no such power. This is a server command\n" ); - return; - } - - player = gameLocal.GetClientByCmdArgs( args ); - if ( !player ) { - gameLocal.Printf( "usage: kick or kick \n" ); - return; - } - cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "say kicking out client %d '%s^0'\n", player->entityNumber, gameLocal.userInfo[ player->entityNumber ].GetString( "ui_name" ) ) ); - cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "kick %d\n", player->entityNumber ) ); -} - -/* -================== -Cmd_GetViewpos_f -================== -*/ -void Cmd_GetViewpos_f( const idCmdArgs &args ) { - idPlayer *player; - idVec3 origin; - idMat3 axis; - - player = gameLocal.GetLocalPlayer(); - if ( !player ) { - return; - } - - const renderView_t *view = player->GetRenderView(); - if ( view ) { - gameLocal.Printf( "(%s) %.1f\n", view->vieworg.ToString(), view->viewaxis[0].ToYaw() ); - } else { - player->GetViewPos( origin, axis ); - gameLocal.Printf( "(%s) %.1f\n", origin.ToString(), axis[0].ToYaw() ); - } -} - -/* -================= -Cmd_SetViewpos_f -================= -*/ -void Cmd_SetViewpos_f( const idCmdArgs &args ) { - idVec3 origin; - idAngles angles; - int i; - idPlayer *player; - - player = gameLocal.GetLocalPlayer(); - if ( !player || !gameLocal.CheatsOk() ) { - return; - } - - if ( ( args.Argc() != 4 ) && ( args.Argc() != 5 ) ) { - gameLocal.Printf( "usage: setviewpos \n" ); - return; - } - - angles.Zero(); - if ( args.Argc() == 5 ) { - angles.yaw = atof( args.Argv( 4 ) ); - } - - for ( i = 0 ; i < 3 ; i++ ) { - origin[i] = atof( args.Argv( i + 1 ) ); - } - origin.z -= pm_normalviewheight.GetFloat() - 0.25f; - - player->Teleport( origin, angles, NULL ); -} - -/* -================= -Cmd_Teleport_f -================= -*/ -void Cmd_Teleport_f( const idCmdArgs &args ) { - idVec3 origin; - idAngles angles; - idPlayer *player; - idEntity *ent; - - player = gameLocal.GetLocalPlayer(); - if ( !player || !gameLocal.CheatsOk() ) { - return; - } - - if ( args.Argc() != 2 ) { - gameLocal.Printf( "usage: teleport \n" ); - return; - } - - ent = gameLocal.FindEntity( args.Argv( 1 ) ); - if ( !ent ) { - gameLocal.Printf( "entity not found\n" ); - return; - } - - angles.Zero(); - angles.yaw = ent->GetPhysics()->GetAxis()[ 0 ].ToYaw(); - origin = ent->GetPhysics()->GetOrigin(); - - player->Teleport( origin, angles, ent ); -} - -/* -================= -Cmd_Trigger_f -================= -*/ -void Cmd_Trigger_f( const idCmdArgs &args ) { - idVec3 origin; - idAngles angles; - idPlayer *player; - idEntity *ent; - - player = gameLocal.GetLocalPlayer(); - if ( !player || !gameLocal.CheatsOk() ) { - return; - } - - if ( args.Argc() != 2 ) { - gameLocal.Printf( "usage: trigger \n" ); - return; - } - - ent = gameLocal.FindEntity( args.Argv( 1 ) ); - if ( !ent ) { - gameLocal.Printf( "entity not found\n" ); - return; - } - - ent->Signal( SIG_TRIGGER ); - ent->ProcessEvent( &EV_Activate, player ); - ent->TriggerGuis(); -} - -/* -=================== -Cmd_Spawn_f -=================== -*/ -void Cmd_Spawn_f( const idCmdArgs &args ) { - const char *key, *value; - int i; - float yaw; - idVec3 org; - idPlayer *player; - idDict dict; - - player = gameLocal.GetLocalPlayer(); - if ( !player || !gameLocal.CheatsOk( false ) ) { - return; - } - - if ( args.Argc() & 1 ) { // must always have an even number of arguments - gameLocal.Printf( "usage: spawn classname [key/value pairs]\n" ); - return; - } - - yaw = player->viewAngles.yaw; - - value = args.Argv( 1 ); - dict.Set( "classname", value ); - dict.Set( "angle", va( "%f", yaw + 180 ) ); - - org = player->GetPhysics()->GetOrigin() + idAngles( 0, yaw, 0 ).ToForward() * 80 + idVec3( 0, 0, 1 ); - dict.Set( "origin", org.ToString() ); - - for( i = 2; i < args.Argc() - 1; i += 2 ) { - - key = args.Argv( i ); - value = args.Argv( i + 1 ); - - dict.Set( key, value ); - } - - gameLocal.SpawnEntityDef( dict ); -} - -/* -================== -Cmd_Damage_f - -Damages the specified entity -================== -*/ -void Cmd_Damage_f( const idCmdArgs &args ) { - if ( !gameLocal.GetLocalPlayer() || !gameLocal.CheatsOk( false ) ) { - return; - } - if ( args.Argc() != 3 ) { - gameLocal.Printf( "usage: damage \n" ); - return; - } - - idEntity *ent = gameLocal.FindEntity( args.Argv( 1 ) ); - if ( !ent ) { - gameLocal.Printf( "entity not found\n" ); - return; - } - - ent->Damage( gameLocal.world, gameLocal.world, idVec3( 0, 0, 1 ), "damage_moverCrush", atoi( args.Argv( 2 ) ), INVALID_JOINT ); -} - - -/* -================== -Cmd_Remove_f - -Removes the specified entity -================== -*/ -void Cmd_Remove_f( const idCmdArgs &args ) { - if ( !gameLocal.GetLocalPlayer() || !gameLocal.CheatsOk( false ) ) { - return; - } - if ( args.Argc() != 2 ) { - gameLocal.Printf( "usage: remove \n" ); - return; - } - - idEntity *ent = gameLocal.FindEntity( args.Argv( 1 ) ); - if ( !ent ) { - gameLocal.Printf( "entity not found\n" ); - return; - } - - delete ent; -} - -/* -=================== -Cmd_TestLight_f -=================== -*/ -void Cmd_TestLight_f( const idCmdArgs &args ) { - int i; - idStr filename; - const char *key, *value, *name; - idPlayer * player; - idDict dict; - - player = gameLocal.GetLocalPlayer(); - if ( !player || !gameLocal.CheatsOk( false ) ) { - return; - } - - renderView_t *rv = player->GetRenderView(); - - float fov = tan( idMath::M_DEG2RAD * rv->fov_x / 2 ); - - - dict.SetMatrix( "rotation", mat3_default ); - dict.SetVector( "origin", rv->vieworg ); - dict.SetVector( "light_target", rv->viewaxis[0] ); - dict.SetVector( "light_right", rv->viewaxis[1] * -fov ); - dict.SetVector( "light_up", rv->viewaxis[2] * fov ); - dict.SetVector( "light_start", rv->viewaxis[0] * 16 ); - dict.SetVector( "light_end", rv->viewaxis[0] * 1000 ); - - if ( args.Argc() >= 2 ) { - value = args.Argv( 1 ); - filename = args.Argv(1); - filename.DefaultFileExtension( ".tga" ); - dict.Set( "texture", filename ); - } - - dict.Set( "classname", "light" ); - for( i = 2; i < args.Argc() - 1; i += 2 ) { - - key = args.Argv( i ); - value = args.Argv( i + 1 ); - - dict.Set( key, value ); - } - - for ( i = 0; i < MAX_GENTITIES; i++ ) { - name = va( "spawned_light_%d", i ); // not just light_, or it might pick up a prelight shadow - if ( !gameLocal.FindEntity( name ) ) { - break; - } - } - dict.Set( "name", name ); - - gameLocal.SpawnEntityDef( dict ); - - gameLocal.Printf( "Created new light\n"); -} - -/* -=================== -Cmd_TestPointLight_f -=================== -*/ -void Cmd_TestPointLight_f( const idCmdArgs &args ) { - const char *key, *value, *name; - int i; - idPlayer *player; - idDict dict; - - player = gameLocal.GetLocalPlayer(); - if ( !player || !gameLocal.CheatsOk( false ) ) { - return; - } - - dict.SetVector("origin", player->GetRenderView()->vieworg); - - if ( args.Argc() >= 2 ) { - value = args.Argv( 1 ); - dict.Set("light", value); - } else { - dict.Set("light", "300"); - } - - dict.Set( "classname", "light" ); - for( i = 2; i < args.Argc() - 1; i += 2 ) { - - key = args.Argv( i ); - value = args.Argv( i + 1 ); - - dict.Set( key, value ); - } - - for ( i = 0; i < MAX_GENTITIES; i++ ) { - name = va( "light_%d", i ); - if ( !gameLocal.FindEntity( name ) ) { - break; - } - } - dict.Set( "name", name ); - - gameLocal.SpawnEntityDef( dict ); - - gameLocal.Printf( "Created new point light\n"); -} - -/* -================== -Cmd_PopLight_f -================== -*/ -void Cmd_PopLight_f( const idCmdArgs &args ) { - idEntity *ent; - idMapEntity *mapEnt; - idMapFile *mapFile = gameLocal.GetLevelMap(); - idLight *lastLight; - int last; - - if ( !gameLocal.CheatsOk() ) { - return; - } - - bool removeFromMap = ( args.Argc() > 1 ); - - lastLight = NULL; - last = -1; - for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) { - if ( !ent->IsType( idLight::Type ) ) { - continue; - } - - if ( gameLocal.spawnIds[ ent->entityNumber ] > last ) { - last = gameLocal.spawnIds[ ent->entityNumber ]; - lastLight = static_cast( ent ); - } - } - - if ( lastLight ) { - // find map file entity - mapEnt = mapFile->FindEntity( lastLight->name ); - - if ( removeFromMap && mapEnt ) { - mapFile->RemoveEntity( mapEnt ); - } - gameLocal.Printf( "Removing light %i\n", lastLight->GetLightDefHandle() ); - delete lastLight; - } else { - gameLocal.Printf( "No lights to clear.\n" ); - } - -} - -/* -==================== -Cmd_ClearLights_f -==================== -*/ -void Cmd_ClearLights_f( const idCmdArgs &args ) { - idEntity *ent; - idEntity *next; - idLight *light; - idMapEntity *mapEnt; - idMapFile *mapFile = gameLocal.GetLevelMap(); - - bool removeFromMap = ( args.Argc() > 1 ); - - gameLocal.Printf( "Clearing all lights.\n" ); - for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = next ) { - next = ent->spawnNode.Next(); - if ( !ent->IsType( idLight::Type ) ) { - continue; - } - - light = static_cast( ent ); - mapEnt = mapFile->FindEntity( light->name ); - - if ( removeFromMap && mapEnt ) { - mapFile->RemoveEntity( mapEnt ); - } - - delete light; - } -} - -/* -================== -Cmd_TestFx_f -================== -*/ -void Cmd_TestFx_f( const idCmdArgs &args ) { - idVec3 offset; - const char *name; - idPlayer * player; - idDict dict; - - player = gameLocal.GetLocalPlayer(); - if ( !player || !gameLocal.CheatsOk() ) { - return; - } - - // delete the testModel if active - if ( gameLocal.testFx ) { - delete gameLocal.testFx; - gameLocal.testFx = NULL; - } - - if ( args.Argc() < 2 ) { - return; - } - - name = args.Argv( 1 ); - - offset = player->GetPhysics()->GetOrigin() + player->viewAngles.ToForward() * 100.0f; - - dict.Set( "origin", offset.ToString() ); - dict.Set( "test", "1"); - dict.Set( "fx", name ); - gameLocal.testFx = ( idEntityFx * )gameLocal.SpawnEntityType( idEntityFx::Type, &dict ); -} - -#define MAX_DEBUGLINES 128 - -typedef struct { - bool used; - idVec3 start, end; - int color; - bool blink; - bool arrow; -} gameDebugLine_t; - -gameDebugLine_t debugLines[MAX_DEBUGLINES]; - -/* -================== -Cmd_AddDebugLine_f -================== -*/ -static void Cmd_AddDebugLine_f( const idCmdArgs &args ) { - int i, argNum; - const char *value; - - if ( !gameLocal.CheatsOk() ) { - return; - } - - if ( args.Argc () < 7 ) { - gameLocal.Printf( "usage: addline \n" ); - return; - } - for ( i = 0; i < MAX_DEBUGLINES; i++ ) { - if ( !debugLines[i].used ) { - break; - } - } - if ( i >= MAX_DEBUGLINES ) { - gameLocal.Printf( "no free debug lines\n" ); - return; - } - value = args.Argv( 0 ); - if ( !idStr::Icmp( value, "addarrow" ) ) { - debugLines[i].arrow = true; - } else { - debugLines[i].arrow = false; - } - debugLines[i].used = true; - debugLines[i].blink = false; - argNum = 1; - debugLines[i].start.x = Cmd_GetFloatArg( args, argNum ); - debugLines[i].start.y = Cmd_GetFloatArg( args, argNum ); - debugLines[i].start.z = Cmd_GetFloatArg( args, argNum ); - debugLines[i].end.x = Cmd_GetFloatArg( args, argNum ); - debugLines[i].end.y = Cmd_GetFloatArg( args, argNum ); - debugLines[i].end.z = Cmd_GetFloatArg( args, argNum ); - debugLines[i].color = Cmd_GetFloatArg( args, argNum ); -} - -/* -================== -Cmd_RemoveDebugLine_f -================== -*/ -static void Cmd_RemoveDebugLine_f( const idCmdArgs &args ) { - int i, num; - const char *value; - - if ( !gameLocal.CheatsOk() ) { - return; - } - - if ( args.Argc () < 2 ) { - gameLocal.Printf( "usage: removeline \n" ); - return; - } - value = args.Argv( 1 ); - num = atoi(value); - for ( i = 0; i < MAX_DEBUGLINES; i++ ) { - if ( debugLines[i].used ) { - if ( --num < 0 ) { - break; - } - } - } - if ( i >= MAX_DEBUGLINES ) { - gameLocal.Printf( "line not found\n" ); - return; - } - debugLines[i].used = false; -} - -/* -================== -Cmd_BlinkDebugLine_f -================== -*/ -static void Cmd_BlinkDebugLine_f( const idCmdArgs &args ) { - int i, num; - const char *value; - - if ( !gameLocal.CheatsOk() ) { - return; - } - - if ( args.Argc () < 2 ) { - gameLocal.Printf( "usage: blinkline \n" ); - return; - } - value = args.Argv( 1 ); - num = atoi( value ); - for ( i = 0; i < MAX_DEBUGLINES; i++ ) { - if ( debugLines[i].used ) { - if ( --num < 0 ) { - break; - } - } - } - if ( i >= MAX_DEBUGLINES ) { - gameLocal.Printf( "line not found\n" ); - return; - } - debugLines[i].blink = !debugLines[i].blink; -} - -/* -================== -PrintFloat -================== -*/ -static void PrintFloat( float f ) { - char buf[128]; - int i; - - for ( i = sprintf( buf, "%3.2f", f ); i < 7; i++ ) { - buf[i] = ' '; - } - buf[i] = '\0'; - gameLocal.Printf( buf ); -} - -/* -================== -Cmd_ListDebugLines_f -================== -*/ -static void Cmd_ListDebugLines_f( const idCmdArgs &args ) { - int i, num; - - if ( !gameLocal.CheatsOk() ) { - return; - } - - num = 0; - gameLocal.Printf( "line num: x1 y1 z1 x2 y2 z2 c b a\n" ); - for ( i = 0; i < MAX_DEBUGLINES; i++ ) { - if ( debugLines[i].used ) { - gameLocal.Printf( "line %3d: ", num ); - PrintFloat( debugLines[i].start.x ); - PrintFloat( debugLines[i].start.y ); - PrintFloat( debugLines[i].start.z ); - PrintFloat( debugLines[i].end.x ); - PrintFloat( debugLines[i].end.y ); - PrintFloat( debugLines[i].end.z ); - gameLocal.Printf( "%d %d %d\n", debugLines[i].color, debugLines[i].blink, debugLines[i].arrow ); - num++; - } - } - if ( !num ) { - gameLocal.Printf( "no debug lines\n" ); - } -} - -/* -================== -D_DrawDebugLines -================== -*/ -void D_DrawDebugLines( void ) { - int i; - idVec3 forward, right, up, p1, p2; - idVec4 color; - float l; - - for ( i = 0; i < MAX_DEBUGLINES; i++ ) { - if ( debugLines[i].used ) { - if ( !debugLines[i].blink || (gameLocal.time & (1<<9)) ) { - color = idVec4( debugLines[i].color&1, (debugLines[i].color>>1)&1, (debugLines[i].color>>2)&1, 1 ); - gameRenderWorld->DebugLine( color, debugLines[i].start, debugLines[i].end ); - // - if ( debugLines[i].arrow ) { - // draw a nice arrow - forward = debugLines[i].end - debugLines[i].start; - l = forward.Normalize() * 0.2f; - forward.NormalVectors( right, up); - - if ( l > 3.0f ) { - l = 3.0f; - } - p1 = debugLines[i].end - l * forward + (l * 0.4f) * right; - p2 = debugLines[i].end - l * forward - (l * 0.4f) * right; - gameRenderWorld->DebugLine( color, debugLines[i].end, p1 ); - gameRenderWorld->DebugLine( color, debugLines[i].end, p2 ); - gameRenderWorld->DebugLine( color, p1, p2 ); - } - } - } - } -} - -/* -================== -Cmd_ListCollisionModels_f -================== -*/ -static void Cmd_ListCollisionModels_f( const idCmdArgs &args ) { - if ( !gameLocal.CheatsOk() ) { - return; - } - - collisionModelManager->ListModels(); -} - -/* -================== -Cmd_CollisionModelInfo_f -================== -*/ -static void Cmd_CollisionModelInfo_f( const idCmdArgs &args ) { - const char *value; - - if ( !gameLocal.CheatsOk() ) { - return; - } - - if ( args.Argc () < 2 ) { - gameLocal.Printf( "usage: collisionModelInfo \n" - "use 'all' instead of the model number for accumulated info\n" ); - return; - } - - value = args.Argv( 1 ); - if ( !idStr::Icmp( value, "all" ) ) { - collisionModelManager->ModelInfo( -1 ); - } else { - collisionModelManager->ModelInfo( atoi(value) ); - } -} - -/* -================== -Cmd_ExportModels_f -================== -*/ -static void Cmd_ExportModels_f( const idCmdArgs &args ) { - idModelExport exporter; - idStr name; - - // don't allow exporting models when cheats are disabled, - // but if we're not in the game, it's ok - if ( gameLocal.GetLocalPlayer() && !gameLocal.CheatsOk( false ) ) { - return; - } - - if ( args.Argc() < 2 ) { - exporter.ExportModels( "def", ".def" ); - } else { - name = args.Argv( 1 ); - name = "def/" + name; - name.DefaultFileExtension( ".def" ); - exporter.ExportDefFile( name ); - } -} - -/* -================== -Cmd_ReexportModels_f -================== -*/ -static void Cmd_ReexportModels_f( const idCmdArgs &args ) { - idModelExport exporter; - idStr name; - - // don't allow exporting models when cheats are disabled, - // but if we're not in the game, it's ok - if ( gameLocal.GetLocalPlayer() && !gameLocal.CheatsOk( false ) ) { - return; - } - - idAnimManager::forceExport = true; - if ( args.Argc() < 2 ) { - exporter.ExportModels( "def", ".def" ); - } else { - name = args.Argv( 1 ); - name = "def/" + name; - name.DefaultFileExtension( ".def" ); - exporter.ExportDefFile( name ); - } - idAnimManager::forceExport = false; -} - -/* -================== -Cmd_ReloadAnims_f -================== -*/ -static void Cmd_ReloadAnims_f( const idCmdArgs &args ) { - // don't allow reloading anims when cheats are disabled, - // but if we're not in the game, it's ok - if ( gameLocal.GetLocalPlayer() && !gameLocal.CheatsOk( false ) ) { - return; - } - - animationLib.ReloadAnims(); -} - -/* -================== -Cmd_ListAnims_f -================== -*/ -static void Cmd_ListAnims_f( const idCmdArgs &args ) { - idEntity * ent; - int num; - size_t size; - size_t alloced; - idAnimator * animator; - const char * classname; - const idDict * dict; - int i; - - if ( args.Argc() > 1 ) { - idAnimator animator; - - classname = args.Argv( 1 ); - - dict = gameLocal.FindEntityDefDict( classname, false ); - if ( !dict ) { - gameLocal.Printf( "Entitydef '%s' not found\n", classname ); - return; - } - animator.SetModel( dict->GetString( "model" ) ); - - gameLocal.Printf( "----------------\n" ); - num = animator.NumAnims(); - for( i = 0; i < num; i++ ) { - gameLocal.Printf( "%s\n", animator.AnimFullName( i ) ); - } - gameLocal.Printf( "%d anims\n", num ); - } else { - animationLib.ListAnims(); - - size = 0; - num = 0; - for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) { - animator = ent->GetAnimator(); - if ( animator ) { - alloced = animator->Allocated(); - size += alloced; - num++; - } - } - - gameLocal.Printf( "%zd memory used in %d entity animators\n", size, num ); - } -} - -/* -================== -Cmd_AASStats_f -================== -*/ -static void Cmd_AASStats_f( const idCmdArgs &args ) { - int aasNum; - - if ( !gameLocal.CheatsOk() ) { - return; - } - - aasNum = aas_test.GetInteger(); - idAAS *aas = gameLocal.GetAAS( aasNum ); - if ( !aas ) { - gameLocal.Printf( "No aas #%d loaded\n", aasNum ); - } else { - aas->Stats(); - } -} - -/* -================== -Cmd_TestDamage_f -================== -*/ -static void Cmd_TestDamage_f( const idCmdArgs &args ) { - idPlayer *player; - const char *damageDefName; - - player = gameLocal.GetLocalPlayer(); - if ( !player || !gameLocal.CheatsOk() ) { - return; - } - - if ( args.Argc() < 2 || args.Argc() > 3 ) { - gameLocal.Printf( "usage: testDamage [angle]\n" ); - return; - } - - damageDefName = args.Argv( 1 ); - - idVec3 dir; - if ( args.Argc() == 3 ) { - float angle = atof( args.Argv( 2 ) ); - - idMath::SinCos( DEG2RAD( angle ), dir[1], dir[0] ); - dir[2] = 0; - } else { - dir.Zero(); - } - - // give the player full health before and after - // running the damage - player->health = player->inventory.maxHealth; - player->Damage( NULL, NULL, dir, damageDefName, 1.0f, INVALID_JOINT ); - player->health = player->inventory.maxHealth; -} - -/* -================== -Cmd_TestBoneFx_f -================== -*/ -static void Cmd_TestBoneFx_f( const idCmdArgs &args ) { - idPlayer *player; - const char *bone, *fx; - - player = gameLocal.GetLocalPlayer(); - if ( !player || !gameLocal.CheatsOk() ) { - return; - } - - if ( args.Argc() < 3 || args.Argc() > 4 ) { - gameLocal.Printf( "usage: testBoneFx \n" ); - return; - } - - fx = args.Argv( 1 ); - bone = args.Argv( 2 ); - - player->StartFxOnBone( fx, bone ); -} - -/* -================== -Cmd_TestDamage_f -================== -*/ -static void Cmd_TestDeath_f( const idCmdArgs &args ) { - idPlayer *player; - - player = gameLocal.GetLocalPlayer(); - if ( !player || !gameLocal.CheatsOk() ) { - return; - } - - idVec3 dir; - idMath::SinCos( DEG2RAD( 45.0f ), dir[1], dir[0] ); - dir[2] = 0; - - g_testDeath.SetBool( 1 ); - player->Damage( NULL, NULL, dir, "damage_triggerhurt_1000", 1.0f, INVALID_JOINT ); - if ( args.Argc() >= 2) { - player->SpawnGibs( dir, "damage_triggerhurt_1000" ); - } - -} - -/* -================== -Cmd_WeaponSplat_f -================== -*/ -static void Cmd_WeaponSplat_f( const idCmdArgs &args ) { - idPlayer *player; - - player = gameLocal.GetLocalPlayer(); - if ( !player || !gameLocal.CheatsOk() ) { - return; - } - - player->weapon.GetEntity()->BloodSplat( 2.0f ); -} - -/* -================== -Cmd_SaveSelected_f -================== -*/ -static void Cmd_SaveSelected_f( const idCmdArgs &args ) { - int i; - idPlayer *player; - idEntity *s; - idMapEntity *mapEnt; - idMapFile *mapFile = gameLocal.GetLevelMap(); - idDict dict; - idStr mapName; - const char *name; - - player = gameLocal.GetLocalPlayer(); - if ( !player || !gameLocal.CheatsOk() ) { - return; - } - - s = player->dragEntity.GetSelected(); - if ( !s ) { - gameLocal.Printf( "no entity selected, set g_dragShowSelection 1 to show the current selection\n" ); - return; - } - - if ( args.Argc() > 1 ) { - mapName = args.Argv( 1 ); - mapName = "maps/" + mapName; - } - else { - mapName = mapFile->GetName(); - } - - // find map file entity - mapEnt = mapFile->FindEntity( s->name ); - // create new map file entity if there isn't one for this articulated figure - if ( !mapEnt ) { - mapEnt = new idMapEntity(); - mapFile->AddEntity( mapEnt ); - for ( i = 0; i < 9999; i++ ) { - name = va( "%s_%d", s->GetEntityDefName(), i ); - if ( !gameLocal.FindEntity( name ) ) { - break; - } - } - s->name = name; - mapEnt->epairs.Set( "classname", s->GetEntityDefName() ); - mapEnt->epairs.Set( "name", s->name ); - } - - if ( s->IsType( idMoveable::Type ) ) { - // save the moveable state - mapEnt->epairs.Set( "origin", s->GetPhysics()->GetOrigin().ToString( 8 ) ); - mapEnt->epairs.Set( "rotation", s->GetPhysics()->GetAxis().ToString( 8 ) ); - } - else if ( s->IsType( idAFEntity_Generic::Type ) || s->IsType( idAFEntity_WithAttachedHead::Type ) ) { - // save the articulated figure state - dict.Clear(); - static_cast(s)->SaveState( dict ); - mapEnt->epairs.Copy( dict ); - } - - // write out the map file - mapFile->Write( mapName, ".map" ); -} - -/* -================== -Cmd_DeleteSelected_f -================== -*/ -static void Cmd_DeleteSelected_f( const idCmdArgs &args ) { - idPlayer *player; - - player = gameLocal.GetLocalPlayer(); - if ( !player || !gameLocal.CheatsOk() ) { - return; - } - - if ( player ) { - player->dragEntity.DeleteSelected(); - } -} - -/* -================== -Cmd_SaveMoveables_f -================== -*/ -static void Cmd_SaveMoveables_f( const idCmdArgs &args ) { - int e, i; - idMoveable *m; - idMapEntity *mapEnt; - idMapFile *mapFile = gameLocal.GetLevelMap(); - idStr mapName; - const char *name; - - if ( !gameLocal.CheatsOk() ) { - return; - } - - for( e = 0; e < MAX_GENTITIES; e++ ) { - m = static_cast(gameLocal.entities[ e ]); - - if ( !m || !m->IsType( idMoveable::Type ) ) { - continue; - } - - if ( m->IsBound() ) { - continue; - } - - if ( !m->IsAtRest() ) { - break; - } - } - - if ( e < MAX_GENTITIES ) { - gameLocal.Warning( "map not saved because the moveable entity %s is not at rest", gameLocal.entities[ e ]->name.c_str() ); - return; - } - - if ( args.Argc() > 1 ) { - mapName = args.Argv( 1 ); - mapName = "maps/" + mapName; - } - else { - mapName = mapFile->GetName(); - } - - for( e = 0; e < MAX_GENTITIES; e++ ) { - m = static_cast(gameLocal.entities[ e ]); - - if ( !m || !m->IsType( idMoveable::Type ) ) { - continue; - } - - if ( m->IsBound() ) { - continue; - } - - // find map file entity - mapEnt = mapFile->FindEntity( m->name ); - // create new map file entity if there isn't one for this articulated figure - if ( !mapEnt ) { - mapEnt = new idMapEntity(); - mapFile->AddEntity( mapEnt ); - for ( i = 0; i < 9999; i++ ) { - name = va( "%s_%d", m->GetEntityDefName(), i ); - if ( !gameLocal.FindEntity( name ) ) { - break; - } - } - m->name = name; - mapEnt->epairs.Set( "classname", m->GetEntityDefName() ); - mapEnt->epairs.Set( "name", m->name ); - } - // save the moveable state - mapEnt->epairs.Set( "origin", m->GetPhysics()->GetOrigin().ToString( 8 ) ); - mapEnt->epairs.Set( "rotation", m->GetPhysics()->GetAxis().ToString( 8 ) ); - } - - // write out the map file - mapFile->Write( mapName, ".map" ); -} - -/* -================== -Cmd_SaveRagdolls_f -================== -*/ -static void Cmd_SaveRagdolls_f( const idCmdArgs &args ) { - int e, i; - idAFEntity_Base *af; - idMapEntity *mapEnt; - idMapFile *mapFile = gameLocal.GetLevelMap(); - idDict dict; - idStr mapName; - const char *name; - - if ( !gameLocal.CheatsOk() ) { - return; - } - - if ( args.Argc() > 1 ) { - mapName = args.Argv( 1 ); - mapName = "maps/" + mapName; - } - else { - mapName = mapFile->GetName(); - } - - for( e = 0; e < MAX_GENTITIES; e++ ) { - af = static_cast(gameLocal.entities[ e ]); - - if ( !af ) { - continue; - } - - if ( !af->IsType( idAFEntity_WithAttachedHead::Type ) && !af->IsType( idAFEntity_Generic::Type ) ) { - continue; - } - - if ( af->IsBound() ) { - continue; - } - - if ( !af->IsAtRest() ) { - gameLocal.Warning( "the articulated figure for entity %s is not at rest", gameLocal.entities[ e ]->name.c_str() ); - } - - dict.Clear(); - af->SaveState( dict ); - - // find map file entity - mapEnt = mapFile->FindEntity( af->name ); - // create new map file entity if there isn't one for this articulated figure - if ( !mapEnt ) { - mapEnt = new idMapEntity(); - mapFile->AddEntity( mapEnt ); - for ( i = 0; i < 9999; i++ ) { - name = va( "%s_%d", af->GetEntityDefName(), i ); - if ( !gameLocal.FindEntity( name ) ) { - break; - } - } - af->name = name; - mapEnt->epairs.Set( "classname", af->GetEntityDefName() ); - mapEnt->epairs.Set( "name", af->name ); - } - // save the articulated figure state - mapEnt->epairs.Copy( dict ); - } - - // write out the map file - mapFile->Write( mapName, ".map" ); -} - -/* -================== -Cmd_BindRagdoll_f -================== -*/ -static void Cmd_BindRagdoll_f( const idCmdArgs &args ) { - idPlayer *player; - - player = gameLocal.GetLocalPlayer(); - if ( !player || !gameLocal.CheatsOk() ) { - return; - } - - if ( player ) { - player->dragEntity.BindSelected(); - } -} - -/* -================== -Cmd_UnbindRagdoll_f -================== -*/ -static void Cmd_UnbindRagdoll_f( const idCmdArgs &args ) { - idPlayer *player; - - player = gameLocal.GetLocalPlayer(); - if ( !player || !gameLocal.CheatsOk() ) { - return; - } - - if ( player ) { - player->dragEntity.UnbindSelected(); - } -} - -/* -================== -Cmd_GameError_f -================== -*/ -static void Cmd_GameError_f( const idCmdArgs &args ) { - gameLocal.Error( "game error" ); -} - -/* -================== -Cmd_SaveLights_f -================== -*/ -static void Cmd_SaveLights_f( const idCmdArgs &args ) { - int e, i; - idLight *light; - idMapEntity *mapEnt; - idMapFile *mapFile = gameLocal.GetLevelMap(); - idDict dict; - idStr mapName; - const char *name; - - if ( !gameLocal.CheatsOk() ) { - return; - } - - if ( args.Argc() > 1 ) { - mapName = args.Argv( 1 ); - mapName = "maps/" + mapName; - } - else { - mapName = mapFile->GetName(); - } - - for( e = 0; e < MAX_GENTITIES; e++ ) { - light = static_cast(gameLocal.entities[ e ]); - - if ( !light || !light->IsType( idLight::Type ) ) { - continue; - } - - dict.Clear(); - light->SaveState( &dict ); - - // find map file entity - mapEnt = mapFile->FindEntity( light->name ); - // create new map file entity if there isn't one for this light - if ( !mapEnt ) { - mapEnt = new idMapEntity(); - mapFile->AddEntity( mapEnt ); - for ( i = 0; i < 9999; i++ ) { - name = va( "%s_%d", light->GetEntityDefName(), i ); - if ( !gameLocal.FindEntity( name ) ) { - break; - } - } - light->name = name; - mapEnt->epairs.Set( "classname", light->GetEntityDefName() ); - mapEnt->epairs.Set( "name", light->name ); - } - // save the light state - mapEnt->epairs.Copy( dict ); - } - - // write out the map file - mapFile->Write( mapName, ".map" ); -} - - -/* -================== -Cmd_SaveParticles_f -================== -*/ -static void Cmd_SaveParticles_f( const idCmdArgs &args ) { - int e; - idEntity *ent; - idMapEntity *mapEnt; - idMapFile *mapFile = gameLocal.GetLevelMap(); - idDict dict; - idStr mapName, strModel; - - if ( !gameLocal.CheatsOk() ) { - return; - } - - if ( args.Argc() > 1 ) { - mapName = args.Argv( 1 ); - mapName = "maps/" + mapName; - } - else { - mapName = mapFile->GetName(); - } - - for( e = 0; e < MAX_GENTITIES; e++ ) { - - ent = static_cast ( gameLocal.entities[ e ] ); - - if ( !ent ) { - continue; - } - - strModel = ent->spawnArgs.GetString( "model" ); - if ( strModel.Length() && strModel.Find( ".prt") > 0 ) { - dict.Clear(); - dict.Set( "model", ent->spawnArgs.GetString( "model" ) ); - dict.SetVector( "origin", ent->GetPhysics()->GetOrigin() ); - - // find map file entity - mapEnt = mapFile->FindEntity( ent->name ); - // create new map file entity if there isn't one for this entity - if ( !mapEnt ) { - continue; - } - // save the particle state - mapEnt->epairs.Copy( dict ); - } - } - - // write out the map file - mapFile->Write( mapName, ".map" ); -} - - -/* -================== -Cmd_DisasmScript_f -================== -*/ -static void Cmd_DisasmScript_f( const idCmdArgs &args ) { - gameLocal.program.Disassemble(); -} - -/* -================== -Cmd_TestSave_f -================== -*/ -static void Cmd_TestSave_f( const idCmdArgs &args ) { - idFile *f; - - f = fileSystem->OpenFileWrite( "test.sav" ); - gameLocal.SaveGame( f ); - fileSystem->CloseFile( f ); -} - -/* -================== -Cmd_RecordViewNotes_f -================== -*/ -static void Cmd_RecordViewNotes_f( const idCmdArgs &args ) { - idPlayer *player; - idVec3 origin; - idMat3 axis; - - if ( args.Argc() <= 3 ) { - return; - } - - player = gameLocal.GetLocalPlayer(); - if ( !player ) { - return; - } - - player->GetViewPos( origin, axis ); - - // Argv(1) = filename for map (viewnotes/mapname/person) - // Argv(2) = note number (person0001) - // Argv(3) = comments - - idStr str = args.Argv(1); - str.SetFileExtension( ".txt" ); - -#ifdef _D3XP - idFile *file = fileSystem->OpenFileAppend( str, false, "fs_cdpath" ); -#else - idFile *file = fileSystem->OpenFileAppend( str ); -#endif - - if ( file ) { - file->WriteFloatString( "\"view\"\t( %s )\t( %s )\r\n", origin.ToString(), axis.ToString() ); - file->WriteFloatString( "\"comments\"\t\"%s: %s\"\r\n\r\n", args.Argv(2), args.Argv(3) ); - fileSystem->CloseFile( file ); - } - - idStr viewComments = args.Argv(1); - viewComments.StripLeading("viewnotes/"); - viewComments += " -- Loc: "; - viewComments += origin.ToString(); - viewComments += "\n"; - viewComments += args.Argv(3); - player->hud->SetStateString( "viewcomments", viewComments ); - player->hud->HandleNamedEvent( "showViewComments" ); -} - -/* -================== -Cmd_CloseViewNotes_f -================== -*/ -static void Cmd_CloseViewNotes_f( const idCmdArgs &args ) { - idPlayer *player = gameLocal.GetLocalPlayer(); - - if ( !player ) { - return; - } - - player->hud->SetStateString( "viewcomments", "" ); - player->hud->HandleNamedEvent( "hideViewComments" ); -} - -/* -================== -Cmd_ShowViewNotes_f -================== -*/ -static void Cmd_ShowViewNotes_f( const idCmdArgs &args ) { - static idLexer parser( LEXFL_ALLOWPATHNAMES | LEXFL_NOSTRINGESCAPECHARS | LEXFL_NOSTRINGCONCAT | LEXFL_NOFATALERRORS ); - idToken token; - idPlayer *player; - idVec3 origin; - idMat3 axis; - - player = gameLocal.GetLocalPlayer(); - - if ( !player ) { - return; - } - - if ( !parser.IsLoaded() ) { - idStr str = "viewnotes/"; - str += gameLocal.GetMapName(); - str.StripFileExtension(); - str += "/"; - if ( args.Argc() > 1 ) { - str += args.Argv( 1 ); - } else { - str += "comments"; - } - str.SetFileExtension( ".txt" ); - if ( !parser.LoadFile( str ) ) { - gameLocal.Printf( "No view notes for %s\n", gameLocal.GetMapName() ); - return; - } - } - - if ( parser.ExpectTokenString( "view" ) && parser.Parse1DMatrix( 3, origin.ToFloatPtr() ) && - parser.Parse1DMatrix( 9, axis.ToFloatPtr() ) && parser.ExpectTokenString( "comments" ) && parser.ReadToken( &token ) ) { - player->hud->SetStateString( "viewcomments", token ); - player->hud->HandleNamedEvent( "showViewComments" ); - player->Teleport( origin, axis.ToAngles(), NULL ); - } else { - parser.FreeSource(); - player->hud->HandleNamedEvent( "hideViewComments" ); - return; - } -} - -/* -================= -FindEntityGUIs - -helper function for Cmd_NextGUI_f. Checks the passed entity to determine if it -has any valid gui surfaces. -================= -*/ -bool FindEntityGUIs( idEntity *ent, const modelSurface_t ** surfaces, int maxSurfs, int &guiSurfaces ) { - renderEntity_t *renderEnt; - idRenderModel *renderModel; - const modelSurface_t *surf; - const idMaterial *shader; - int i; - - assert( surfaces != NULL ); - assert( ent != NULL ); - - memset( surfaces, 0x00, sizeof( modelSurface_t *) * maxSurfs ); - guiSurfaces = 0; - - renderEnt = ent->GetRenderEntity(); - renderModel = renderEnt->hModel; - if ( renderModel == NULL ) { - return false; - } - - for( i = 0; i < renderModel->NumSurfaces(); i++ ) { - surf = renderModel->Surface( i ); - if ( surf == NULL ) { - continue; - } - shader = surf->shader; - if ( shader == NULL ) { - continue; - } - if ( shader->GetEntityGui() > 0 ) { - surfaces[ guiSurfaces++ ] = surf; - } - } - - return ( guiSurfaces != 0 ); -} - -/* -================= -Cmd_NextGUI_f -================= -*/ -void Cmd_NextGUI_f( const idCmdArgs &args ) { - idVec3 origin; - idAngles angles; - idPlayer *player; - idEntity *ent; - int guiSurfaces; - bool newEnt; - renderEntity_t *renderEnt; - int surfIndex; - srfTriangles_t *geom; - idMat4 modelMatrix; - idVec3 normal; - idVec3 center; - const modelSurface_t *surfaces[ MAX_RENDERENTITY_GUI ]; - - player = gameLocal.GetLocalPlayer(); - if ( !player || !gameLocal.CheatsOk() ) { - return; - } - - if ( args.Argc() != 1 ) { - gameLocal.Printf( "usage: nextgui\n" ); - return; - } - - // start at the last entity - ent = gameLocal.lastGUIEnt.GetEntity(); - - // see if we have any gui surfaces left to go to on the current entity. - guiSurfaces = 0; - newEnt = false; - if ( ent == NULL ) { - newEnt = true; - } else if ( FindEntityGUIs( ent, surfaces, MAX_RENDERENTITY_GUI, guiSurfaces ) == true ) { - if ( gameLocal.lastGUI >= guiSurfaces ) { - newEnt = true; - } - } else { - // no actual gui surfaces on this ent, so skip it - newEnt = true; - } - - if ( newEnt == true ) { - // go ahead and skip to the next entity with a gui... - if ( ent == NULL ) { - ent = gameLocal.spawnedEntities.Next(); - } else { - ent = ent->spawnNode.Next(); - } - - for ( ; ent != NULL; ent = ent->spawnNode.Next() ) { - if ( ent->spawnArgs.GetString( "gui", NULL ) != NULL ) { - break; - } - - if ( ent->spawnArgs.GetString( "gui2", NULL ) != NULL ) { - break; - } - - if ( ent->spawnArgs.GetString( "gui3", NULL ) != NULL ) { - break; - } - - // try the next entity - gameLocal.lastGUIEnt = ent; - } - - gameLocal.lastGUIEnt = ent; - gameLocal.lastGUI = 0; - - if ( !ent ) { - gameLocal.Printf( "No more gui entities. Starting over...\n" ); - return; - } - } - - if ( FindEntityGUIs( ent, surfaces, MAX_RENDERENTITY_GUI, guiSurfaces ) == false ) { - gameLocal.Printf( "Entity \"%s\" has gui properties but no gui surfaces.\n", ent->name.c_str() ); - } - - if ( guiSurfaces == 0 ) { - gameLocal.Printf( "Entity \"%s\" has gui properties but no gui surfaces!\n", ent->name.c_str() ); - return; - } - - gameLocal.Printf( "Teleporting to gui entity \"%s\", gui #%d.\n" , ent->name.c_str (), gameLocal.lastGUI ); - - renderEnt = ent->GetRenderEntity(); - surfIndex = gameLocal.lastGUI++; - geom = surfaces[ surfIndex ]->geometry; - if ( geom == NULL ) { - gameLocal.Printf( "Entity \"%s\" has gui surface %d without geometry!\n", ent->name.c_str(), surfIndex ); - return; - } - - assert( geom->facePlanes != NULL ); - - modelMatrix = idMat4( renderEnt->axis, renderEnt->origin ); - normal = geom->facePlanes[ 0 ].Normal() * renderEnt->axis; - center = geom->bounds.GetCenter() * modelMatrix; - - origin = center + (normal * 32.0f); - origin.z -= player->EyeHeight(); - normal *= -1.0f; - angles = normal.ToAngles (); - - // make sure the player is in noclip - player->noclip = true; - player->Teleport( origin, angles, NULL ); -} - -#ifdef _D3XP -void Cmd_SetActorState_f( const idCmdArgs &args ) { - - if ( args.Argc() != 3 ) { - common->Printf( "usage: setActorState \n" ); - return; - } - - idEntity* ent; - ent = gameLocal.FindEntity( args.Argv( 1 ) ); - if ( !ent ) { - gameLocal.Printf( "entity not found\n" ); - return; - } - - - if(!ent->IsType(idActor::Type)) { - gameLocal.Printf( "entity not an actor\n" ); - return; - } - - idActor* actor = (idActor*)ent; - actor->PostEventMS(&AI_SetState, 0, args.Argv(2)); -} -#endif - -static void ArgCompletion_DefFile( const idCmdArgs &args, void(*callback)( const char *s ) ) { - cmdSystem->ArgCompletion_FolderExtension( args, callback, "def/", true, ".def", NULL ); -} - -/* -=============== -Cmd_TestId_f -outputs a string from the string table for the specified id -=============== -*/ -void Cmd_TestId_f( const idCmdArgs &args ) { - idStr id; - int i; - if ( args.Argc() == 1 ) { - common->Printf( "usage: testid \n" ); - return; - } - - for ( i = 1; i < args.Argc(); i++ ) { - id += args.Argv( i ); - } - if ( idStr::Cmpn( id, STRTABLE_ID, STRTABLE_ID_LENGTH ) != 0 ) { - id = STRTABLE_ID + id; - } - gameLocal.mpGame.AddChatLine( common->GetLanguageDict()->GetString( id ), "", "", "" ); -} - -/* -================= -idGameLocal::InitConsoleCommands - -Let the system know about all of our commands -so it can perform tab completion -================= -*/ -void idGameLocal::InitConsoleCommands( void ) { - cmdSystem->AddCommand( "listTypeInfo", ListTypeInfo_f, CMD_FL_GAME, "list type info" ); - cmdSystem->AddCommand( "writeGameState", WriteGameState_f, CMD_FL_GAME, "write game state" ); - cmdSystem->AddCommand( "testSaveGame", TestSaveGame_f, CMD_FL_GAME|CMD_FL_CHEAT, "test a save game for a level" ); - cmdSystem->AddCommand( "game_memory", idClass::DisplayInfo_f, CMD_FL_GAME, "displays game class info" ); - cmdSystem->AddCommand( "listClasses", idClass::ListClasses_f, CMD_FL_GAME, "lists game classes" ); - cmdSystem->AddCommand( "listThreads", idThread::ListThreads_f, CMD_FL_GAME|CMD_FL_CHEAT, "lists script threads" ); - cmdSystem->AddCommand( "listEntities", Cmd_EntityList_f, CMD_FL_GAME|CMD_FL_CHEAT, "lists game entities" ); - cmdSystem->AddCommand( "listActiveEntities", Cmd_ActiveEntityList_f, CMD_FL_GAME|CMD_FL_CHEAT, "lists active game entities" ); - cmdSystem->AddCommand( "listMonsters", idAI::List_f, CMD_FL_GAME|CMD_FL_CHEAT, "lists monsters" ); - cmdSystem->AddCommand( "listSpawnArgs", Cmd_ListSpawnArgs_f, CMD_FL_GAME|CMD_FL_CHEAT, "list the spawn args of an entity", idGameLocal::ArgCompletion_EntityName ); - cmdSystem->AddCommand( "say", Cmd_Say_f, CMD_FL_GAME, "text chat" ); - cmdSystem->AddCommand( "sayTeam", Cmd_SayTeam_f, CMD_FL_GAME, "team text chat" ); - cmdSystem->AddCommand( "addChatLine", Cmd_AddChatLine_f, CMD_FL_GAME, "internal use - core to game chat lines" ); - cmdSystem->AddCommand( "gameKick", Cmd_Kick_f, CMD_FL_GAME, "same as kick, but recognizes player names" ); - cmdSystem->AddCommand( "give", Cmd_Give_f, CMD_FL_GAME|CMD_FL_CHEAT, "gives one or more items" ); - cmdSystem->AddCommand( "centerview", Cmd_CenterView_f, CMD_FL_GAME, "centers the view" ); - cmdSystem->AddCommand( "god", Cmd_God_f, CMD_FL_GAME|CMD_FL_CHEAT, "enables god mode" ); - cmdSystem->AddCommand( "notarget", Cmd_Notarget_f, CMD_FL_GAME|CMD_FL_CHEAT, "disables the player as a target" ); - cmdSystem->AddCommand( "noclip", Cmd_Noclip_f, CMD_FL_GAME|CMD_FL_CHEAT, "disables collision detection for the player" ); - cmdSystem->AddCommand( "kill", Cmd_Kill_f, CMD_FL_GAME, "kills the player" ); - cmdSystem->AddCommand( "where", Cmd_GetViewpos_f, CMD_FL_GAME|CMD_FL_CHEAT, "prints the current view position" ); - cmdSystem->AddCommand( "getviewpos", Cmd_GetViewpos_f, CMD_FL_GAME|CMD_FL_CHEAT, "prints the current view position" ); - cmdSystem->AddCommand( "setviewpos", Cmd_SetViewpos_f, CMD_FL_GAME|CMD_FL_CHEAT, "sets the current view position" ); - cmdSystem->AddCommand( "teleport", Cmd_Teleport_f, CMD_FL_GAME|CMD_FL_CHEAT, "teleports the player to an entity location", idGameLocal::ArgCompletion_EntityName ); - cmdSystem->AddCommand( "trigger", Cmd_Trigger_f, CMD_FL_GAME|CMD_FL_CHEAT, "triggers an entity", idGameLocal::ArgCompletion_EntityName ); - cmdSystem->AddCommand( "spawn", Cmd_Spawn_f, CMD_FL_GAME|CMD_FL_CHEAT, "spawns a game entity", idCmdSystem::ArgCompletion_Decl ); - cmdSystem->AddCommand( "damage", Cmd_Damage_f, CMD_FL_GAME|CMD_FL_CHEAT, "apply damage to an entity", idGameLocal::ArgCompletion_EntityName ); - cmdSystem->AddCommand( "remove", Cmd_Remove_f, CMD_FL_GAME|CMD_FL_CHEAT, "removes an entity", idGameLocal::ArgCompletion_EntityName ); - cmdSystem->AddCommand( "killMonsters", Cmd_KillMonsters_f, CMD_FL_GAME|CMD_FL_CHEAT, "removes all monsters" ); - cmdSystem->AddCommand( "killMoveables", Cmd_KillMovables_f, CMD_FL_GAME|CMD_FL_CHEAT, "removes all moveables" ); - cmdSystem->AddCommand( "killRagdolls", Cmd_KillRagdolls_f, CMD_FL_GAME|CMD_FL_CHEAT, "removes all ragdolls" ); - cmdSystem->AddCommand( "addline", Cmd_AddDebugLine_f, CMD_FL_GAME|CMD_FL_CHEAT, "adds a debug line" ); - cmdSystem->AddCommand( "addarrow", Cmd_AddDebugLine_f, CMD_FL_GAME|CMD_FL_CHEAT, "adds a debug arrow" ); - cmdSystem->AddCommand( "removeline", Cmd_RemoveDebugLine_f, CMD_FL_GAME|CMD_FL_CHEAT, "removes a debug line" ); - cmdSystem->AddCommand( "blinkline", Cmd_BlinkDebugLine_f, CMD_FL_GAME|CMD_FL_CHEAT, "blinks a debug line" ); - cmdSystem->AddCommand( "listLines", Cmd_ListDebugLines_f, CMD_FL_GAME|CMD_FL_CHEAT, "lists all debug lines" ); - cmdSystem->AddCommand( "playerModel", Cmd_PlayerModel_f, CMD_FL_GAME|CMD_FL_CHEAT, "sets the given model on the player", idCmdSystem::ArgCompletion_Decl ); - cmdSystem->AddCommand( "testFx", Cmd_TestFx_f, CMD_FL_GAME|CMD_FL_CHEAT, "tests an FX system", idCmdSystem::ArgCompletion_Decl ); - cmdSystem->AddCommand( "testBoneFx", Cmd_TestBoneFx_f, CMD_FL_GAME|CMD_FL_CHEAT, "tests an FX system bound to a joint", idCmdSystem::ArgCompletion_Decl ); - cmdSystem->AddCommand( "testLight", Cmd_TestLight_f, CMD_FL_GAME|CMD_FL_CHEAT, "tests a light" ); - cmdSystem->AddCommand( "testPointLight", Cmd_TestPointLight_f, CMD_FL_GAME|CMD_FL_CHEAT, "tests a point light" ); - cmdSystem->AddCommand( "popLight", Cmd_PopLight_f, CMD_FL_GAME|CMD_FL_CHEAT, "removes the last created light" ); - cmdSystem->AddCommand( "testDeath", Cmd_TestDeath_f, CMD_FL_GAME|CMD_FL_CHEAT, "tests death" ); - cmdSystem->AddCommand( "testSave", Cmd_TestSave_f, CMD_FL_GAME|CMD_FL_CHEAT, "writes out a test savegame" ); - cmdSystem->AddCommand( "testModel", idTestModel::TestModel_f, CMD_FL_GAME|CMD_FL_CHEAT, "tests a model", idTestModel::ArgCompletion_TestModel ); - cmdSystem->AddCommand( "testSkin", idTestModel::TestSkin_f, CMD_FL_GAME|CMD_FL_CHEAT, "tests a skin on an existing testModel", idCmdSystem::ArgCompletion_Decl ); - cmdSystem->AddCommand( "testShaderParm", idTestModel::TestShaderParm_f, CMD_FL_GAME|CMD_FL_CHEAT, "sets a shaderParm on an existing testModel" ); - cmdSystem->AddCommand( "keepTestModel", idTestModel::KeepTestModel_f, CMD_FL_GAME|CMD_FL_CHEAT, "keeps the last test model in the game" ); - cmdSystem->AddCommand( "testAnim", idTestModel::TestAnim_f, CMD_FL_GAME|CMD_FL_CHEAT, "tests an animation", idTestModel::ArgCompletion_TestAnim ); - cmdSystem->AddCommand( "testParticleStopTime", idTestModel::TestParticleStopTime_f,CMD_FL_GAME|CMD_FL_CHEAT, "tests particle stop time on a test model" ); - cmdSystem->AddCommand( "nextAnim", idTestModel::TestModelNextAnim_f, CMD_FL_GAME|CMD_FL_CHEAT, "shows next animation on test model" ); - cmdSystem->AddCommand( "prevAnim", idTestModel::TestModelPrevAnim_f, CMD_FL_GAME|CMD_FL_CHEAT, "shows previous animation on test model" ); - cmdSystem->AddCommand( "nextFrame", idTestModel::TestModelNextFrame_f, CMD_FL_GAME|CMD_FL_CHEAT, "shows next animation frame on test model" ); - cmdSystem->AddCommand( "prevFrame", idTestModel::TestModelPrevFrame_f, CMD_FL_GAME|CMD_FL_CHEAT, "shows previous animation frame on test model" ); - cmdSystem->AddCommand( "testBlend", idTestModel::TestBlend_f, CMD_FL_GAME|CMD_FL_CHEAT, "tests animation blending" ); - cmdSystem->AddCommand( "reloadScript", Cmd_ReloadScript_f, CMD_FL_GAME|CMD_FL_CHEAT, "reloads scripts" ); - cmdSystem->AddCommand( "script", Cmd_Script_f, CMD_FL_GAME|CMD_FL_CHEAT, "executes a line of script" ); - cmdSystem->AddCommand( "listCollisionModels", Cmd_ListCollisionModels_f, CMD_FL_GAME, "lists collision models" ); - cmdSystem->AddCommand( "collisionModelInfo", Cmd_CollisionModelInfo_f, CMD_FL_GAME, "shows collision model info" ); - cmdSystem->AddCommand( "reexportmodels", Cmd_ReexportModels_f, CMD_FL_GAME|CMD_FL_CHEAT, "reexports models", ArgCompletion_DefFile ); - cmdSystem->AddCommand( "reloadanims", Cmd_ReloadAnims_f, CMD_FL_GAME|CMD_FL_CHEAT, "reloads animations" ); - cmdSystem->AddCommand( "listAnims", Cmd_ListAnims_f, CMD_FL_GAME, "lists all animations" ); - cmdSystem->AddCommand( "aasStats", Cmd_AASStats_f, CMD_FL_GAME, "shows AAS stats" ); - cmdSystem->AddCommand( "testDamage", Cmd_TestDamage_f, CMD_FL_GAME|CMD_FL_CHEAT, "tests a damage def", idCmdSystem::ArgCompletion_Decl ); - cmdSystem->AddCommand( "weaponSplat", Cmd_WeaponSplat_f, CMD_FL_GAME|CMD_FL_CHEAT, "projects a blood splat on the player weapon" ); - cmdSystem->AddCommand( "saveSelected", Cmd_SaveSelected_f, CMD_FL_GAME|CMD_FL_CHEAT, "saves the selected entity to the .map file" ); - cmdSystem->AddCommand( "deleteSelected", Cmd_DeleteSelected_f, CMD_FL_GAME|CMD_FL_CHEAT, "deletes selected entity" ); - cmdSystem->AddCommand( "saveMoveables", Cmd_SaveMoveables_f, CMD_FL_GAME|CMD_FL_CHEAT, "save all moveables to the .map file" ); - cmdSystem->AddCommand( "saveRagdolls", Cmd_SaveRagdolls_f, CMD_FL_GAME|CMD_FL_CHEAT, "save all ragdoll poses to the .map file" ); - cmdSystem->AddCommand( "bindRagdoll", Cmd_BindRagdoll_f, CMD_FL_GAME|CMD_FL_CHEAT, "binds ragdoll at the current drag position" ); - cmdSystem->AddCommand( "unbindRagdoll", Cmd_UnbindRagdoll_f, CMD_FL_GAME|CMD_FL_CHEAT, "unbinds the selected ragdoll" ); - cmdSystem->AddCommand( "saveLights", Cmd_SaveLights_f, CMD_FL_GAME|CMD_FL_CHEAT, "saves all lights to the .map file" ); - cmdSystem->AddCommand( "saveParticles", Cmd_SaveParticles_f, CMD_FL_GAME|CMD_FL_CHEAT, "saves all lights to the .map file" ); - cmdSystem->AddCommand( "clearLights", Cmd_ClearLights_f, CMD_FL_GAME|CMD_FL_CHEAT, "clears all lights" ); - cmdSystem->AddCommand( "gameError", Cmd_GameError_f, CMD_FL_GAME|CMD_FL_CHEAT, "causes a game error" ); - - cmdSystem->AddCommand( "disasmScript", Cmd_DisasmScript_f, CMD_FL_GAME|CMD_FL_CHEAT, "disassembles script" ); - cmdSystem->AddCommand( "recordViewNotes", Cmd_RecordViewNotes_f, CMD_FL_GAME|CMD_FL_CHEAT, "record the current view position with notes" ); - cmdSystem->AddCommand( "showViewNotes", Cmd_ShowViewNotes_f, CMD_FL_GAME|CMD_FL_CHEAT, "show any view notes for the current map, successive calls will cycle to the next note" ); - cmdSystem->AddCommand( "closeViewNotes", Cmd_CloseViewNotes_f, CMD_FL_GAME|CMD_FL_CHEAT, "close the view showing any notes for this map" ); - cmdSystem->AddCommand( "exportmodels", Cmd_ExportModels_f, CMD_FL_GAME|CMD_FL_CHEAT, "exports models", ArgCompletion_DefFile ); - - // multiplayer client commands ( replaces old impulses stuff ) - cmdSystem->AddCommand( "clientDropWeapon", idMultiplayerGame::DropWeapon_f, CMD_FL_GAME, "drop current weapon" ); - cmdSystem->AddCommand( "clientMessageMode", idMultiplayerGame::MessageMode_f, CMD_FL_GAME, "ingame gui message mode" ); - // FIXME: implement -// cmdSystem->AddCommand( "clientVote", idMultiplayerGame::Vote_f, CMD_FL_GAME, "cast your vote: clientVote yes | no" ); -// cmdSystem->AddCommand( "clientCallVote", idMultiplayerGame::CallVote_f, CMD_FL_GAME, "call a vote: clientCallVote si_.. proposed_value" ); - cmdSystem->AddCommand( "clientVoiceChat", idMultiplayerGame::VoiceChat_f, CMD_FL_GAME, "voice chats: clientVoiceChat " ); - cmdSystem->AddCommand( "clientVoiceChatTeam", idMultiplayerGame::VoiceChatTeam_f, CMD_FL_GAME, "team voice chats: clientVoiceChat " ); - - // multiplayer server commands - cmdSystem->AddCommand( "serverMapRestart", idGameLocal::MapRestart_f, CMD_FL_GAME, "restart the current game" ); - cmdSystem->AddCommand( "serverForceReady", idMultiplayerGame::ForceReady_f,CMD_FL_GAME, "force all players ready" ); - cmdSystem->AddCommand( "serverNextMap", idGameLocal::NextMap_f, CMD_FL_GAME, "change to the next map" ); - - // localization help commands - cmdSystem->AddCommand( "nextGUI", Cmd_NextGUI_f, CMD_FL_GAME|CMD_FL_CHEAT, "teleport the player to the next func_static with a gui" ); - cmdSystem->AddCommand( "testid", Cmd_TestId_f, CMD_FL_GAME|CMD_FL_CHEAT, "output the string for the specified id." ); - -#ifdef _D3XP - cmdSystem->AddCommand( "setActorState", Cmd_SetActorState_f, CMD_FL_GAME|CMD_FL_CHEAT, "Manually sets an actors script state", idGameLocal::ArgCompletion_EntityName ); -#endif -} - -/* -================= -idGameLocal::ShutdownConsoleCommands -================= -*/ -void idGameLocal::ShutdownConsoleCommands( void ) { - cmdSystem->RemoveFlaggedCommands( CMD_FL_GAME ); -} diff --git a/d3xp/gamesys/SysCmds.h b/d3xp/gamesys/SysCmds.h deleted file mode 100644 index 2b1abcd8..00000000 --- a/d3xp/gamesys/SysCmds.h +++ /dev/null @@ -1,34 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __SYS_CMDS_H__ -#define __SYS_CMDS_H__ - -void D_DrawDebugLines( void ); - -#endif /* !__SYS_CMDS_H__ */ diff --git a/d3xp/gamesys/SysCvar.cpp b/d3xp/gamesys/SysCvar.cpp deleted file mode 100644 index f2bb0b7a..00000000 --- a/d3xp/gamesys/SysCvar.cpp +++ /dev/null @@ -1,419 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "framework/Licensee.h" -#include "framework/BuildVersion.h" - -#include "GameBase.h" -#include "MultiplayerGame.h" - -#include "SysCvar.h" - -#if defined( _DEBUG ) - #define BUILD_DEBUG "-debug" -#else - #define BUILD_DEBUG "-release" -#endif - -/* - -All game cvars should be defined here. - -*/ - -#ifdef CTF -const char *si_gameTypeArgs[] = { "singleplayer", "deathmatch", "Tourney", "Team DM", "Last Man", "CTF", NULL }; -#else -const char *si_gameTypeArgs[] = { "singleplayer", "deathmatch", "Tourney", "Team DM", "Last Man", NULL }; -#endif - -const char *si_readyArgs[] = { "Not Ready", "Ready", NULL }; -const char *si_spectateArgs[] = { "Play", "Spectate", NULL }; - -#ifdef _D3XP -const char *ui_skinArgs[] = { "skins/characters/player/marine_mp", "skins/characters/player/marine_mp_red", "skins/characters/player/marine_mp_blue", "skins/characters/player/marine_mp_green", "skins/characters/player/marine_mp_yellow", "skins/characters/player/marine_mp_purple", "skins/characters/player/marine_mp_grey", "skins/characters/player/marine_mp_orange", NULL }; -#else -const char *ui_skinArgs[] = { "skins/characters/player/marine_mp", "skins/characters/player/marine_mp_red", "skins/characters/player/marine_mp_blue", "skins/characters/player/marine_mp_green", "skins/characters/player/marine_mp_yellow", NULL }; -#endif - -const char *ui_teamArgs[] = { "Red", "Blue", NULL }; - -struct gameVersion_s { - gameVersion_s( void ) { sprintf( string, "%s.%d%s %s-%s %s %s", ENGINE_VERSION, BUILD_NUMBER, BUILD_DEBUG, BUILD_OS, BUILD_CPU, __DATE__, __TIME__ ); } - char string[256]; -} gameVersion; - -idCVar g_version( "g_version", gameVersion.string, CVAR_GAME | CVAR_ROM, "game version" ); - -// noset vars -idCVar gamename( "gamename", GAME_VERSION, CVAR_GAME | CVAR_SERVERINFO | CVAR_ROM, "" ); -idCVar gamedate( "gamedate", __DATE__, CVAR_GAME | CVAR_ROM, "" ); - -// server info -idCVar si_name( "si_name", "dhewm server", CVAR_GAME | CVAR_SERVERINFO | CVAR_ARCHIVE, "name of the server" ); - -#ifdef CTF -idCVar si_gameType( "si_gameType", si_gameTypeArgs[ 0 ], CVAR_GAME | CVAR_SERVERINFO | CVAR_ARCHIVE, "game type - singleplayer, deathmatch, Tourney, Team DM, Last Man or CTF", si_gameTypeArgs, idCmdSystem::ArgCompletion_String ); -#else -idCVar si_gameType( "si_gameType", si_gameTypeArgs[ 0 ], CVAR_GAME | CVAR_SERVERINFO | CVAR_ARCHIVE, "game type - singleplayer, deathmatch, Tourney, Team DM or Last Man", si_gameTypeArgs, idCmdSystem::ArgCompletion_String ); -#endif - -idCVar si_map( "si_map", "game/mp/d3dm1",CVAR_GAME | CVAR_SERVERINFO | CVAR_ARCHIVE, "map to be played next on server", idCmdSystem::ArgCompletion_MapName ); -idCVar si_maxPlayers( "si_maxPlayers", "8", CVAR_GAME | CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_INTEGER, "max number of players allowed on the server", 1, 8 ); -idCVar si_fragLimit( "si_fragLimit", "10", CVAR_GAME | CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_INTEGER, "frag limit", 1, MP_PLAYER_MAXFRAGS ); -idCVar si_timeLimit( "si_timeLimit", "10", CVAR_GAME | CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_INTEGER, "time limit in minutes", 0, 60 ); -idCVar si_teamDamage( "si_teamDamage", "0", CVAR_GAME | CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_BOOL, "enable team damage" ); -idCVar si_warmup( "si_warmup", "0", CVAR_GAME | CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_BOOL, "do pre-game warmup" ); -idCVar si_usePass( "si_usePass", "0", CVAR_GAME | CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_BOOL, "enable client password checking" ); -idCVar si_pure( "si_pure", "1", CVAR_GAME | CVAR_SERVERINFO | CVAR_BOOL, "server is pure and does not allow modified data" ); -idCVar si_spectators( "si_spectators", "1", CVAR_GAME | CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_BOOL, "allow spectators or require all clients to play" ); -idCVar si_serverURL( "si_serverURL", "", CVAR_GAME | CVAR_SERVERINFO | CVAR_ARCHIVE, "where to reach the server admins and get information about the server" ); - -#ifdef CTF -//idCVar si_pointLimit( "si_pointlimit", "8", CVAR_GAME | CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_INTEGER, "team points limit to win in CTF" ); -idCVar si_flagDropTimeLimit( "si_flagDropTimeLimit", "30", CVAR_GAME | CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_INTEGER, "seconds before a dropped CTF flag is returned" ); -idCVar si_midnight( "si_midnight", "0", CVAR_GAME | CVAR_INTEGER | CVAR_SERVERINFO, "Start the game up in midnight CTF (completely dark)" ); -#endif - - -// user info -idCVar ui_name( "ui_name", "Player", CVAR_GAME | CVAR_USERINFO | CVAR_ARCHIVE, "player name" ); -idCVar ui_skin( "ui_skin", ui_skinArgs[ 0 ], CVAR_GAME | CVAR_USERINFO | CVAR_ARCHIVE, "player skin", ui_skinArgs, idCmdSystem::ArgCompletion_String ); -idCVar ui_team( "ui_team", ui_teamArgs[ 0 ], CVAR_GAME | CVAR_USERINFO | CVAR_ARCHIVE, "player team", ui_teamArgs, idCmdSystem::ArgCompletion_String ); -idCVar ui_autoSwitch( "ui_autoSwitch", "1", CVAR_GAME | CVAR_USERINFO | CVAR_ARCHIVE | CVAR_BOOL, "auto switch weapon" ); -idCVar ui_autoReload( "ui_autoReload", "1", CVAR_GAME | CVAR_USERINFO | CVAR_ARCHIVE | CVAR_BOOL, "auto reload weapon" ); -idCVar ui_showGun( "ui_showGun", "1", CVAR_GAME | CVAR_USERINFO | CVAR_ARCHIVE | CVAR_BOOL, "show gun" ); -idCVar ui_ready( "ui_ready", si_readyArgs[ 0 ], CVAR_GAME | CVAR_USERINFO, "player is ready to start playing", idCmdSystem::ArgCompletion_String ); -idCVar ui_spectate( "ui_spectate", si_spectateArgs[ 0 ], CVAR_GAME | CVAR_USERINFO, "play or spectate", idCmdSystem::ArgCompletion_String ); -idCVar ui_chat( "ui_chat", "0", CVAR_GAME | CVAR_USERINFO | CVAR_BOOL | CVAR_ROM | CVAR_CHEAT, "player is chatting" ); - -// change anytime vars -idCVar developer( "developer", "0", CVAR_GAME | CVAR_BOOL, "" ); - -idCVar r_aspectRatio( "r_aspectRatio", "-1", CVAR_RENDERER | CVAR_INTEGER | CVAR_ARCHIVE, "aspect ratio of view:\n0 = 4:3\n1 = 16:9\n2 = 16:10\n-1 = auto (guess from resolution)", -1, 2 ); - -idCVar g_cinematic( "g_cinematic", "1", CVAR_GAME | CVAR_BOOL, "skips updating entities that aren't marked 'cinematic' '1' during cinematics" ); -idCVar g_cinematicMaxSkipTime( "g_cinematicMaxSkipTime", "600", CVAR_GAME | CVAR_FLOAT, "# of seconds to allow game to run when skipping cinematic. prevents lock-up when cinematic doesn't end.", 0, 3600 ); - -idCVar g_muzzleFlash( "g_muzzleFlash", "1", CVAR_GAME | CVAR_ARCHIVE | CVAR_BOOL, "show muzzle flashes" ); -idCVar g_projectileLights( "g_projectileLights", "1", CVAR_GAME | CVAR_ARCHIVE | CVAR_BOOL, "show dynamic lights on projectiles" ); -idCVar g_bloodEffects( "g_bloodEffects", "1", CVAR_GAME | CVAR_ARCHIVE | CVAR_BOOL, "show blood splats, sprays and gibs" ); -idCVar g_doubleVision( "g_doubleVision", "1", CVAR_GAME | CVAR_ARCHIVE | CVAR_BOOL, "show double vision when taking damage" ); -idCVar g_monsters( "g_monsters", "1", CVAR_GAME | CVAR_BOOL, "" ); -idCVar g_decals( "g_decals", "1", CVAR_GAME | CVAR_ARCHIVE | CVAR_BOOL, "show decals such as bullet holes" ); -idCVar g_knockback( "g_knockback", "1000", CVAR_GAME | CVAR_INTEGER, "" ); -idCVar g_skill( "g_skill", "1", CVAR_GAME | CVAR_INTEGER, "" ); -idCVar g_nightmare( "g_nightmare", "0", CVAR_GAME | CVAR_ARCHIVE | CVAR_BOOL, "if nightmare mode is allowed" ); -idCVar g_gravity( "g_gravity", DEFAULT_GRAVITY_STRING, CVAR_GAME | CVAR_FLOAT, "" ); -idCVar g_skipFX( "g_skipFX", "0", CVAR_GAME | CVAR_BOOL, "" ); -idCVar g_skipParticles( "g_skipParticles", "0", CVAR_GAME | CVAR_BOOL, "" ); - -idCVar g_disasm( "g_disasm", "0", CVAR_GAME | CVAR_BOOL, "disassemble script into base/script/disasm.txt on the local drive when script is compiled" ); -idCVar g_debugBounds( "g_debugBounds", "0", CVAR_GAME | CVAR_BOOL, "checks for models with bounds > 2048" ); -idCVar g_debugAnim( "g_debugAnim", "-1", CVAR_GAME | CVAR_INTEGER, "displays information on which animations are playing on the specified entity number. set to -1 to disable." ); -idCVar g_debugMove( "g_debugMove", "0", CVAR_GAME | CVAR_BOOL, "" ); -idCVar g_debugDamage( "g_debugDamage", "0", CVAR_GAME | CVAR_BOOL, "" ); -idCVar g_debugWeapon( "g_debugWeapon", "0", CVAR_GAME | CVAR_BOOL, "" ); -idCVar g_debugScript( "g_debugScript", "0", CVAR_GAME | CVAR_BOOL, "" ); -idCVar g_debugMover( "g_debugMover", "0", CVAR_GAME | CVAR_BOOL, "" ); -idCVar g_debugTriggers( "g_debugTriggers", "0", CVAR_GAME | CVAR_BOOL, "" ); -idCVar g_debugCinematic( "g_debugCinematic", "0", CVAR_GAME | CVAR_BOOL, "" ); -idCVar g_stopTime( "g_stopTime", "0", CVAR_GAME | CVAR_BOOL, "" ); -idCVar g_damageScale( "g_damageScale", "1", CVAR_GAME | CVAR_FLOAT | CVAR_ARCHIVE, "scale final damage on player by this factor" ); -idCVar g_armorProtection( "g_armorProtection", "0.3", CVAR_GAME | CVAR_FLOAT | CVAR_ARCHIVE, "armor takes this percentage of damage" ); -idCVar g_armorProtectionMP( "g_armorProtectionMP", "0.6", CVAR_GAME | CVAR_FLOAT | CVAR_ARCHIVE, "armor takes this percentage of damage in mp" ); -idCVar g_useDynamicProtection( "g_useDynamicProtection", "1", CVAR_GAME | CVAR_BOOL | CVAR_ARCHIVE, "scale damage and armor dynamically to keep the player alive more often" ); -idCVar g_healthTakeTime( "g_healthTakeTime", "5", CVAR_GAME | CVAR_INTEGER | CVAR_ARCHIVE, "how often to take health in nightmare mode" ); -idCVar g_healthTakeAmt( "g_healthTakeAmt", "5", CVAR_GAME | CVAR_INTEGER | CVAR_ARCHIVE, "how much health to take in nightmare mode" ); -idCVar g_healthTakeLimit( "g_healthTakeLimit", "25", CVAR_GAME | CVAR_INTEGER | CVAR_ARCHIVE, "how low can health get taken in nightmare mode" ); - - - -idCVar g_showPVS( "g_showPVS", "0", CVAR_GAME | CVAR_INTEGER, "", 0, 2 ); -idCVar g_showTargets( "g_showTargets", "0", CVAR_GAME | CVAR_BOOL, "draws entities and their targets. hidden entities are drawn grey." ); -idCVar g_showTriggers( "g_showTriggers", "0", CVAR_GAME | CVAR_BOOL, "draws trigger entities (orange) and their targets (green). disabled triggers are drawn grey." ); -idCVar g_showCollisionWorld( "g_showCollisionWorld", "0", CVAR_GAME | CVAR_BOOL, "" ); -idCVar g_showCollisionModels( "g_showCollisionModels", "0", CVAR_GAME | CVAR_BOOL, "" ); -idCVar g_showCollisionTraces( "g_showCollisionTraces", "0", CVAR_GAME | CVAR_BOOL, "" ); -idCVar g_maxShowDistance( "g_maxShowDistance", "128", CVAR_GAME | CVAR_FLOAT, "" ); -idCVar g_showEntityInfo( "g_showEntityInfo", "0", CVAR_GAME | CVAR_BOOL, "" ); -idCVar g_showviewpos( "g_showviewpos", "0", CVAR_GAME | CVAR_BOOL, "" ); -idCVar g_showcamerainfo( "g_showcamerainfo", "0", CVAR_GAME | CVAR_ARCHIVE, "displays the current frame # for the camera when playing cinematics" ); -idCVar g_showTestModelFrame( "g_showTestModelFrame", "0", CVAR_GAME | CVAR_BOOL, "displays the current animation and frame # for testmodels" ); -idCVar g_showActiveEntities( "g_showActiveEntities", "0", CVAR_GAME | CVAR_BOOL, "draws boxes around thinking entities. dormant entities (outside of pvs) are drawn yellow. non-dormant are green." ); -idCVar g_showEnemies( "g_showEnemies", "0", CVAR_GAME | CVAR_BOOL, "draws boxes around monsters that have targeted the the player" ); - -idCVar g_frametime( "g_frametime", "0", CVAR_GAME | CVAR_BOOL, "displays timing information for each game frame" ); -idCVar g_timeentities( "g_timeEntities", "0", CVAR_GAME | CVAR_FLOAT, "when non-zero, shows entities whose think functions exceeded the # of milliseconds specified" ); - -#ifdef _D3XP -idCVar g_testPistolFlashlight( "g_testPistolFlashlight", "1", CVAR_GAME | CVAR_BOOL, "Test out having a flashlight out with the pistol" ); -idCVar g_debugShockwave( "g_debugShockwave", "0", CVAR_GAME | CVAR_BOOL, "Debug the shockwave" ); - -idCVar g_enableSlowmo( "g_enableSlowmo", "0", CVAR_GAME | CVAR_BOOL, "for testing purposes only" ); -idCVar g_slowmoStepRate( "g_slowmoStepRate", "0.02", CVAR_GAME | CVAR_FLOAT, "" ); - -idCVar g_enablePortalSky( "g_enablePortalSky", "1", CVAR_GAME | CVAR_BOOL, "enables the portal sky" ); -idCVar g_testFullscreenFX( "g_testFullscreenFX", "-1", CVAR_GAME | CVAR_INTEGER, "index will activate specific fx, -2 is for all on, -1 is off" ); -idCVar g_testHelltimeFX( "g_testHelltimeFX", "-1", CVAR_GAME | CVAR_INTEGER, "set to 0, 1, 2 to test helltime, -1 is off" ); -idCVar g_testMultiplayerFX( "g_testMultiplayerFX", "-1", CVAR_GAME | CVAR_INTEGER, "set to 0, 1, 2 to test multiplayer, -1 is off" ); -idCVar g_lowresFullscreenFX( "g_lowresFullscreenFX", "0", CVAR_GAME | CVAR_BOOL, "enable lores mode for fx" ); - -idCVar g_moveableDamageScale( "g_moveableDamageScale", "0.1", CVAR_GAME | CVAR_FLOAT, "scales damage wrt mass of object in multiplayer" ); - -idCVar g_testBloomSpeed( "g_testBloomSpeed", "1", CVAR_GAME | CVAR_FLOAT, "" ); -idCVar g_testBloomIntensity( "g_testBloomIntensity", "-0.01", CVAR_GAME | CVAR_FLOAT, "" ); -idCVar g_testBloomNumPasses( "g_testBloomNumPasses", "30", CVAR_GAME | CVAR_INTEGER, "" ); -#endif - -idCVar ai_debugScript( "ai_debugScript", "-1", CVAR_GAME | CVAR_INTEGER, "displays script calls for the specified monster entity number" ); -idCVar ai_debugMove( "ai_debugMove", "0", CVAR_GAME | CVAR_BOOL, "draws movement information for monsters" ); -idCVar ai_debugTrajectory( "ai_debugTrajectory", "0", CVAR_GAME | CVAR_BOOL, "draws trajectory tests for monsters" ); -idCVar ai_testPredictPath( "ai_testPredictPath", "0", CVAR_GAME | CVAR_BOOL, "" ); -idCVar ai_showCombatNodes( "ai_showCombatNodes", "0", CVAR_GAME | CVAR_BOOL, "draws attack cones for monsters" ); -idCVar ai_showPaths( "ai_showPaths", "0", CVAR_GAME | CVAR_BOOL, "draws path_* entities" ); -idCVar ai_showObstacleAvoidance( "ai_showObstacleAvoidance", "0", CVAR_GAME | CVAR_INTEGER, "draws obstacle avoidance information for monsters. if 2, draws obstacles for player, as well", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> ); -idCVar ai_blockedFailSafe( "ai_blockedFailSafe", "1", CVAR_GAME | CVAR_BOOL, "enable blocked fail safe handling" ); - -#ifdef _D3XP -idCVar ai_showHealth( "ai_showHealth", "0", CVAR_GAME | CVAR_BOOL, "Draws the AI's health above its head" ); -#endif - -idCVar g_dvTime( "g_dvTime", "1", CVAR_GAME | CVAR_FLOAT, "" ); -idCVar g_dvAmplitude( "g_dvAmplitude", "0.001", CVAR_GAME | CVAR_FLOAT, "" ); -idCVar g_dvFrequency( "g_dvFrequency", "0.5", CVAR_GAME | CVAR_FLOAT, "" ); - -idCVar g_kickTime( "g_kickTime", "1", CVAR_GAME | CVAR_FLOAT, "" ); -idCVar g_kickAmplitude( "g_kickAmplitude", "0.0001", CVAR_GAME | CVAR_FLOAT, "" ); -idCVar g_blobTime( "g_blobTime", "1", CVAR_GAME | CVAR_FLOAT, "" ); -idCVar g_blobSize( "g_blobSize", "1", CVAR_GAME | CVAR_FLOAT, "" ); - -idCVar g_testHealthVision( "g_testHealthVision", "0", CVAR_GAME | CVAR_FLOAT, "" ); -idCVar g_editEntityMode( "g_editEntityMode", "0", CVAR_GAME | CVAR_INTEGER, "0 = off\n" - "1 = lights\n" - "2 = sounds\n" - "3 = articulated figures\n" - "4 = particle systems\n" - "5 = monsters\n" - "6 = entity names\n" - "7 = entity models", 0, 7, idCmdSystem::ArgCompletion_Integer<0,7> ); -idCVar g_dragEntity( "g_dragEntity", "0", CVAR_GAME | CVAR_BOOL, "allows dragging physics objects around by placing the crosshair over them and holding the fire button" ); -idCVar g_dragDamping( "g_dragDamping", "0.5", CVAR_GAME | CVAR_FLOAT, "" ); -idCVar g_dragShowSelection( "g_dragShowSelection", "0", CVAR_GAME | CVAR_BOOL, "" ); -idCVar g_dropItemRotation( "g_dropItemRotation", "", CVAR_GAME, "" ); - -#ifdef CTF -// Note: These cvars do not necessarily need to be in the shipping game. -idCVar g_flagAttachJoint( "g_flagAttachJoint", "Chest", CVAR_GAME | CVAR_CHEAT, "player joint to attach CTF flag to" ); -idCVar g_flagAttachOffsetX( "g_flagAttachOffsetX", "8", CVAR_GAME | CVAR_CHEAT, "X offset of CTF flag when carried" ); -idCVar g_flagAttachOffsetY( "g_flagAttachOffsetY", "4", CVAR_GAME | CVAR_CHEAT, "Y offset of CTF flag when carried" ); -idCVar g_flagAttachOffsetZ( "g_flagAttachOffsetZ", "-12", CVAR_GAME | CVAR_CHEAT, "Z offset of CTF flag when carried" ); -idCVar g_flagAttachAngleX( "g_flagAttachAngleX", "90", CVAR_GAME | CVAR_CHEAT, "X angle of CTF flag when carried" ); -idCVar g_flagAttachAngleY( "g_flagAttachAngleY", "25", CVAR_GAME | CVAR_CHEAT, "Y angle of CTF flag when carried" ); -idCVar g_flagAttachAngleZ( "g_flagAttachAngleZ", "-90", CVAR_GAME | CVAR_CHEAT, "Z angle of CTF flag when carried" ); -#endif - - -idCVar g_vehicleVelocity( "g_vehicleVelocity", "1000", CVAR_GAME | CVAR_FLOAT, "" ); -idCVar g_vehicleForce( "g_vehicleForce", "50000", CVAR_GAME | CVAR_FLOAT, "" ); -idCVar g_vehicleSuspensionUp( "g_vehicleSuspensionUp", "32", CVAR_GAME | CVAR_FLOAT, "" ); -idCVar g_vehicleSuspensionDown( "g_vehicleSuspensionDown", "20", CVAR_GAME | CVAR_FLOAT, "" ); -idCVar g_vehicleSuspensionKCompress("g_vehicleSuspensionKCompress","200", CVAR_GAME | CVAR_FLOAT, "" ); -idCVar g_vehicleSuspensionDamping( "g_vehicleSuspensionDamping","400", CVAR_GAME | CVAR_FLOAT, "" ); -idCVar g_vehicleTireFriction( "g_vehicleTireFriction", "0.8", CVAR_GAME | CVAR_FLOAT, "" ); -#ifdef _D3XP -idCVar g_vehicleDebug( "g_vehicleDebug", "0", CVAR_GAME | CVAR_BOOL, "" ); -#endif - -idCVar ik_enable( "ik_enable", "1", CVAR_GAME | CVAR_BOOL, "enable IK" ); -idCVar ik_debug( "ik_debug", "0", CVAR_GAME | CVAR_BOOL, "show IK debug lines" ); - -idCVar af_useLinearTime( "af_useLinearTime", "1", CVAR_GAME | CVAR_BOOL, "use linear time algorithm for tree-like structures" ); -idCVar af_useImpulseFriction( "af_useImpulseFriction", "0", CVAR_GAME | CVAR_BOOL, "use impulse based contact friction" ); -idCVar af_useJointImpulseFriction( "af_useJointImpulseFriction","0", CVAR_GAME | CVAR_BOOL, "use impulse based joint friction" ); -idCVar af_useSymmetry( "af_useSymmetry", "1", CVAR_GAME | CVAR_BOOL, "use constraint matrix symmetry" ); -idCVar af_skipSelfCollision( "af_skipSelfCollision", "0", CVAR_GAME | CVAR_BOOL, "skip self collision detection" ); -idCVar af_skipLimits( "af_skipLimits", "0", CVAR_GAME | CVAR_BOOL, "skip joint limits" ); -idCVar af_skipFriction( "af_skipFriction", "0", CVAR_GAME | CVAR_BOOL, "skip friction" ); -idCVar af_forceFriction( "af_forceFriction", "-1", CVAR_GAME | CVAR_FLOAT, "force the given friction value" ); -idCVar af_maxLinearVelocity( "af_maxLinearVelocity", "128", CVAR_GAME | CVAR_FLOAT, "maximum linear velocity" ); -idCVar af_maxAngularVelocity( "af_maxAngularVelocity", "1.57", CVAR_GAME | CVAR_FLOAT, "maximum angular velocity" ); -idCVar af_timeScale( "af_timeScale", "1", CVAR_GAME | CVAR_FLOAT, "scales the time" ); -idCVar af_jointFrictionScale( "af_jointFrictionScale", "0", CVAR_GAME | CVAR_FLOAT, "scales the joint friction" ); -idCVar af_contactFrictionScale( "af_contactFrictionScale", "0", CVAR_GAME | CVAR_FLOAT, "scales the contact friction" ); -idCVar af_highlightBody( "af_highlightBody", "", CVAR_GAME, "name of the body to highlight" ); -idCVar af_highlightConstraint( "af_highlightConstraint", "", CVAR_GAME, "name of the constraint to highlight" ); -idCVar af_showTimings( "af_showTimings", "0", CVAR_GAME | CVAR_BOOL, "show articulated figure cpu usage" ); -idCVar af_showConstraints( "af_showConstraints", "0", CVAR_GAME | CVAR_BOOL, "show constraints" ); -idCVar af_showConstraintNames( "af_showConstraintNames", "0", CVAR_GAME | CVAR_BOOL, "show constraint names" ); -idCVar af_showConstrainedBodies( "af_showConstrainedBodies", "0", CVAR_GAME | CVAR_BOOL, "show the two bodies contrained by the highlighted constraint" ); -idCVar af_showPrimaryOnly( "af_showPrimaryOnly", "0", CVAR_GAME | CVAR_BOOL, "show primary constraints only" ); -idCVar af_showTrees( "af_showTrees", "0", CVAR_GAME | CVAR_BOOL, "show tree-like structures" ); -idCVar af_showLimits( "af_showLimits", "0", CVAR_GAME | CVAR_BOOL, "show joint limits" ); -idCVar af_showBodies( "af_showBodies", "0", CVAR_GAME | CVAR_BOOL, "show bodies" ); -idCVar af_showBodyNames( "af_showBodyNames", "0", CVAR_GAME | CVAR_BOOL, "show body names" ); -idCVar af_showMass( "af_showMass", "0", CVAR_GAME | CVAR_BOOL, "show the mass of each body" ); -idCVar af_showTotalMass( "af_showTotalMass", "0", CVAR_GAME | CVAR_BOOL, "show the total mass of each articulated figure" ); -idCVar af_showInertia( "af_showInertia", "0", CVAR_GAME | CVAR_BOOL, "show the inertia tensor of each body" ); -idCVar af_showVelocity( "af_showVelocity", "0", CVAR_GAME | CVAR_BOOL, "show the velocity of each body" ); -idCVar af_showActive( "af_showActive", "0", CVAR_GAME | CVAR_BOOL, "show tree-like structures of articulated figures not at rest" ); -idCVar af_testSolid( "af_testSolid", "1", CVAR_GAME | CVAR_BOOL, "test for bodies initially stuck in solid" ); - -idCVar rb_showTimings( "rb_showTimings", "0", CVAR_GAME | CVAR_BOOL, "show rigid body cpu usage" ); -idCVar rb_showBodies( "rb_showBodies", "0", CVAR_GAME | CVAR_BOOL, "show rigid bodies" ); -idCVar rb_showMass( "rb_showMass", "0", CVAR_GAME | CVAR_BOOL, "show the mass of each rigid body" ); -idCVar rb_showInertia( "rb_showInertia", "0", CVAR_GAME | CVAR_BOOL, "show the inertia tensor of each rigid body" ); -idCVar rb_showVelocity( "rb_showVelocity", "0", CVAR_GAME | CVAR_BOOL, "show the velocity of each rigid body" ); -idCVar rb_showActive( "rb_showActive", "0", CVAR_GAME | CVAR_BOOL, "show rigid bodies that are not at rest" ); - -// The default values for player movement cvars are set in def/player.def -idCVar pm_jumpheight( "pm_jumpheight", "48", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "approximate hieght the player can jump" ); -idCVar pm_stepsize( "pm_stepsize", "16", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "maximum height the player can step up without jumping" ); -idCVar pm_crouchspeed( "pm_crouchspeed", "80", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "speed the player can move while crouched" ); -idCVar pm_walkspeed( "pm_walkspeed", "140", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "speed the player can move while walking" ); -idCVar pm_runspeed( "pm_runspeed", "220", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "speed the player can move while running" ); -idCVar pm_noclipspeed( "pm_noclipspeed", "200", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "speed the player can move while in noclip" ); -idCVar pm_spectatespeed( "pm_spectatespeed", "450", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "speed the player can move while spectating" ); -idCVar pm_spectatebbox( "pm_spectatebbox", "32", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "size of the spectator bounding box" ); -idCVar pm_usecylinder( "pm_usecylinder", "0", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_BOOL, "use a cylinder approximation instead of a bounding box for player collision detection" ); -idCVar pm_minviewpitch( "pm_minviewpitch", "-89", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "amount player's view can look up (negative values are up)" ); -idCVar pm_maxviewpitch( "pm_maxviewpitch", "89", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "amount player's view can look down" ); -idCVar pm_stamina( "pm_stamina", "24", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "length of time player can run" ); -idCVar pm_staminathreshold( "pm_staminathreshold", "45", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "when stamina drops below this value, player gradually slows to a walk" ); -idCVar pm_staminarate( "pm_staminarate", "0.75", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "rate that player regains stamina. divide pm_stamina by this value to determine how long it takes to fully recharge." ); -idCVar pm_crouchheight( "pm_crouchheight", "38", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "height of player's bounding box while crouched" ); -idCVar pm_crouchviewheight( "pm_crouchviewheight", "32", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "height of player's view while crouched" ); -idCVar pm_normalheight( "pm_normalheight", "74", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "height of player's bounding box while standing" ); -idCVar pm_normalviewheight( "pm_normalviewheight", "68", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "height of player's view while standing" ); -idCVar pm_deadheight( "pm_deadheight", "20", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "height of player's bounding box while dead" ); -idCVar pm_deadviewheight( "pm_deadviewheight", "10", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "height of player's view while dead" ); -idCVar pm_crouchrate( "pm_crouchrate", "0.87", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "time it takes for player's view to change from standing to crouching" ); -idCVar pm_bboxwidth( "pm_bboxwidth", "32", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "x/y size of player's bounding box" ); -idCVar pm_crouchbob( "pm_crouchbob", "0.5", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "bob much faster when crouched" ); -idCVar pm_walkbob( "pm_walkbob", "0.3", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "bob slowly when walking" ); -idCVar pm_runbob( "pm_runbob", "0.4", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "bob faster when running" ); -idCVar pm_runpitch( "pm_runpitch", "0.002", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "" ); -idCVar pm_runroll( "pm_runroll", "0.005", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "" ); -idCVar pm_bobup( "pm_bobup", "0.005", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "" ); -idCVar pm_bobpitch( "pm_bobpitch", "0.002", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "" ); -idCVar pm_bobroll( "pm_bobroll", "0.002", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "" ); -idCVar pm_thirdPersonRange( "pm_thirdPersonRange", "80", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "camera distance from player in 3rd person" ); -idCVar pm_thirdPersonHeight( "pm_thirdPersonHeight", "0", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "height of camera from normal view height in 3rd person" ); -idCVar pm_thirdPersonAngle( "pm_thirdPersonAngle", "0", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "direction of camera from player in 3rd person in degrees (0 = behind player, 180 = in front)" ); -idCVar pm_thirdPersonClip( "pm_thirdPersonClip", "1", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_BOOL, "clip third person view into world space" ); -idCVar pm_thirdPerson( "pm_thirdPerson", "0", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_BOOL, "enables third person view" ); -idCVar pm_thirdPersonDeath( "pm_thirdPersonDeath", "0", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_BOOL, "enables third person view when player dies" ); -idCVar pm_modelView( "pm_modelView", "0", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_INTEGER, "draws camera from POV of player model (1 = always, 2 = when dead)", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> ); -idCVar pm_airTics( "pm_air", "1800", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_INTEGER, "how long in milliseconds the player can go without air before he starts taking damage" ); - -idCVar g_showPlayerShadow( "g_showPlayerShadow", "0", CVAR_GAME | CVAR_ARCHIVE | CVAR_BOOL, "enables shadow of player model" ); -idCVar g_showHud( "g_showHud", "1", CVAR_GAME | CVAR_ARCHIVE | CVAR_BOOL, "" ); -idCVar g_showProjectilePct( "g_showProjectilePct", "0", CVAR_GAME | CVAR_ARCHIVE | CVAR_BOOL, "enables display of player hit percentage" ); -idCVar g_showBrass( "g_showBrass", "1", CVAR_GAME | CVAR_ARCHIVE | CVAR_BOOL, "enables ejected shells from weapon" ); -idCVar g_gun_x( "g_gunX", "0", CVAR_GAME | CVAR_FLOAT, "" ); -idCVar g_gun_y( "g_gunY", "0", CVAR_GAME | CVAR_FLOAT, "" ); -idCVar g_gun_z( "g_gunZ", "0", CVAR_GAME | CVAR_FLOAT, "" ); -idCVar g_viewNodalX( "g_viewNodalX", "0", CVAR_GAME | CVAR_FLOAT, "" ); -idCVar g_viewNodalZ( "g_viewNodalZ", "0", CVAR_GAME | CVAR_FLOAT, "" ); -idCVar g_fov( "g_fov", "90", CVAR_GAME | CVAR_INTEGER | CVAR_NOCHEAT, "" ); -idCVar g_skipViewEffects( "g_skipViewEffects", "0", CVAR_GAME | CVAR_BOOL, "skip damage and other view effects" ); -idCVar g_mpWeaponAngleScale( "g_mpWeaponAngleScale", "0", CVAR_GAME | CVAR_FLOAT, "Control the weapon sway in MP" ); - -idCVar g_testParticle( "g_testParticle", "0", CVAR_GAME | CVAR_INTEGER, "test particle visualation, set by the particle editor" ); -idCVar g_testParticleName( "g_testParticleName", "", CVAR_GAME, "name of the particle being tested by the particle editor" ); -idCVar g_testModelRotate( "g_testModelRotate", "0", CVAR_GAME, "test model rotation speed" ); -idCVar g_testPostProcess( "g_testPostProcess", "", CVAR_GAME, "name of material to draw over screen" ); -idCVar g_testModelAnimate( "g_testModelAnimate", "0", CVAR_GAME | CVAR_INTEGER, "test model animation,\n" - "0 = cycle anim with origin reset\n" - "1 = cycle anim with fixed origin\n" - "2 = cycle anim with continuous origin\n" - "3 = frame by frame with continuous origin\n" - "4 = play anim once", 0, 4, idCmdSystem::ArgCompletion_Integer<0,4> ); -idCVar g_testModelBlend( "g_testModelBlend", "0", CVAR_GAME | CVAR_INTEGER, "number of frames to blend" ); -idCVar g_testDeath( "g_testDeath", "0", CVAR_GAME | CVAR_BOOL, "" ); -idCVar g_exportMask( "g_exportMask", "", CVAR_GAME, "" ); -idCVar g_flushSave( "g_flushSave", "0", CVAR_GAME | CVAR_BOOL, "1 = don't buffer file writing for save games." ); - -idCVar aas_test( "aas_test", "0", CVAR_GAME | CVAR_INTEGER, "" ); -idCVar aas_showAreas( "aas_showAreas", "0", CVAR_GAME | CVAR_BOOL, "" ); -idCVar aas_showPath( "aas_showPath", "0", CVAR_GAME | CVAR_INTEGER, "" ); -idCVar aas_showFlyPath( "aas_showFlyPath", "0", CVAR_GAME | CVAR_INTEGER, "" ); -idCVar aas_showWallEdges( "aas_showWallEdges", "0", CVAR_GAME | CVAR_BOOL, "" ); -idCVar aas_showHideArea( "aas_showHideArea", "0", CVAR_GAME | CVAR_INTEGER, "" ); -idCVar aas_pullPlayer( "aas_pullPlayer", "0", CVAR_GAME | CVAR_INTEGER, "" ); -idCVar aas_randomPullPlayer( "aas_randomPullPlayer", "0", CVAR_GAME | CVAR_BOOL, "" ); -idCVar aas_goalArea( "aas_goalArea", "0", CVAR_GAME | CVAR_INTEGER, "" ); -idCVar aas_showPushIntoArea( "aas_showPushIntoArea", "0", CVAR_GAME | CVAR_BOOL, "" ); - -idCVar g_password( "g_password", "", CVAR_GAME | CVAR_ARCHIVE, "game password" ); -idCVar password( "password", "", CVAR_GAME | CVAR_NOCHEAT, "client password used when connecting" ); - -idCVar g_countDown( "g_countDown", "10", CVAR_GAME | CVAR_INTEGER | CVAR_ARCHIVE, "pregame countdown in seconds", 4, 3600 ); -idCVar g_gameReviewPause( "g_gameReviewPause", "10", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_INTEGER | CVAR_ARCHIVE, "scores review time in seconds (at end game)", 2, 3600 ); -idCVar g_TDMArrows( "g_TDMArrows", "1", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_BOOL, "draw arrows over teammates in team deathmatch" ); -idCVar g_balanceTDM( "g_balanceTDM", "1", CVAR_GAME | CVAR_BOOL, "maintain even teams" ); -#ifdef CTF -idCVar g_CTFArrows( "g_CTFArrows", "1", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_BOOL, "draw arrows over teammates in CTF" ); -#endif - -idCVar net_clientPredictGUI( "net_clientPredictGUI", "1", CVAR_GAME | CVAR_BOOL, "test guis in networking without prediction" ); - -idCVar g_voteFlags( "g_voteFlags", "0", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_INTEGER | CVAR_ARCHIVE, "vote flags. bit mask of votes not allowed on this server\n" - "bit 0 (+1) restart now\n" - "bit 1 (+2) time limit\n" - "bit 2 (+4) frag limit\n" - "bit 3 (+8) game type\n" - "bit 4 (+16) kick player\n" - "bit 5 (+32) change map\n" - "bit 6 (+64) spectators\n" - "bit 7 (+128) next map" ); -idCVar g_mapCycle( "g_mapCycle", "mapcycle", CVAR_GAME | CVAR_ARCHIVE, "map cycling script for multiplayer games - see mapcycle.scriptcfg" ); - -#ifdef _D3XP -idCVar mod_validSkins( "mod_validSkins", "skins/characters/player/marine_mp;skins/characters/player/marine_mp_green;skins/characters/player/marine_mp_blue;skins/characters/player/marine_mp_red;skins/characters/player/marine_mp_yellow;skins/characters/player/marine_mp_purple;skins/characters/player/marine_mp_grey;skins/characters/player/marine_mp_orange", CVAR_GAME | CVAR_ARCHIVE, "valid skins for the game" ); -#else -idCVar mod_validSkins( "mod_validSkins", "skins/characters/player/marine_mp;skins/characters/player/marine_mp_green;skins/characters/player/marine_mp_blue;skins/characters/player/marine_mp_red;skins/characters/player/marine_mp_yellow", CVAR_GAME | CVAR_ARCHIVE, "valid skins for the game" ); -#endif - - -#ifdef _D3XP -idCVar g_grabberHoldSeconds( "g_grabberHoldSeconds", "3", CVAR_GAME | CVAR_FLOAT | CVAR_CHEAT, "number of seconds to hold object" ); -idCVar g_grabberEnableShake( "g_grabberEnableShake", "1", CVAR_GAME | CVAR_BOOL | CVAR_CHEAT, "enable the grabber shake" ); -idCVar g_grabberRandomMotion( "g_grabberRandomMotion", "1", CVAR_GAME | CVAR_BOOL | CVAR_CHEAT, "enable random motion on the grabbed object" ); -idCVar g_grabberHardStop( "g_grabberHardStop", "1", CVAR_GAME | CVAR_BOOL | CVAR_CHEAT, "hard stops object if too fast" ); -idCVar g_grabberDamping( "g_grabberDamping", "0.5", CVAR_GAME | CVAR_FLOAT | CVAR_CHEAT, "damping of grabber" ); -#endif - -#ifdef _D3XP -idCVar g_xp_bind_run_once( "g_xp_bind_run_once", "0", CVAR_GAME | CVAR_BOOL | CVAR_ARCHIVE, "Rebind all controls once for D3XP." ); -#endif - -idCVar net_serverDownload( "net_serverDownload", "0", CVAR_GAME | CVAR_INTEGER | CVAR_ARCHIVE, "enable server download redirects. 0: off 1: redirect to si_serverURL 2: use builtin download. see net_serverDl cvars for configuration" ); -idCVar net_serverDlBaseURL( "net_serverDlBaseURL", "", CVAR_GAME | CVAR_ARCHIVE, "base URL for the download redirection" ); -idCVar net_serverDlTable( "net_serverDlTable", "", CVAR_GAME | CVAR_ARCHIVE, "pak names for which download is provided, separated by ;" ); diff --git a/d3xp/gamesys/SysCvar.h b/d3xp/gamesys/SysCvar.h deleted file mode 100644 index 37ddbb69..00000000 --- a/d3xp/gamesys/SysCvar.h +++ /dev/null @@ -1,306 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __SYS_CVAR_H__ -#define __SYS_CVAR_H__ - -#include "framework/CVarSystem.h" - -extern idCVar developer; - -extern idCVar g_cinematic; -extern idCVar g_cinematicMaxSkipTime; - -extern idCVar r_aspectRatio; - -extern idCVar g_monsters; -extern idCVar g_decals; -extern idCVar g_knockback; -extern idCVar g_skill; -extern idCVar g_gravity; -extern idCVar g_skipFX; -extern idCVar g_skipParticles; -extern idCVar g_bloodEffects; -extern idCVar g_projectileLights; -extern idCVar g_doubleVision; -extern idCVar g_muzzleFlash; - -extern idCVar g_disasm; -extern idCVar g_debugBounds; -extern idCVar g_debugAnim; -extern idCVar g_debugMove; -extern idCVar g_debugDamage; -extern idCVar g_debugWeapon; -extern idCVar g_debugScript; -extern idCVar g_debugMover; -extern idCVar g_debugTriggers; -extern idCVar g_debugCinematic; -extern idCVar g_stopTime; -extern idCVar g_armorProtection; -extern idCVar g_armorProtectionMP; -extern idCVar g_damageScale; -extern idCVar g_useDynamicProtection; -extern idCVar g_healthTakeTime; -extern idCVar g_healthTakeAmt; -extern idCVar g_healthTakeLimit; - -extern idCVar g_showPVS; -extern idCVar g_showTargets; -extern idCVar g_showTriggers; -extern idCVar g_showCollisionWorld; -extern idCVar g_showCollisionModels; -extern idCVar g_showCollisionTraces; -extern idCVar g_maxShowDistance; -extern idCVar g_showEntityInfo; -extern idCVar g_showviewpos; -extern idCVar g_showcamerainfo; -extern idCVar g_showTestModelFrame; -extern idCVar g_showActiveEntities; -extern idCVar g_showEnemies; - -extern idCVar g_frametime; -extern idCVar g_timeentities; - -extern idCVar ai_debugScript; -extern idCVar ai_debugMove; -extern idCVar ai_debugTrajectory; -extern idCVar ai_testPredictPath; -extern idCVar ai_showCombatNodes; -extern idCVar ai_showPaths; -extern idCVar ai_showObstacleAvoidance; -extern idCVar ai_blockedFailSafe; -#ifdef _D3XP -extern idCVar ai_showHealth; -#endif - -extern idCVar g_dvTime; -extern idCVar g_dvAmplitude; -extern idCVar g_dvFrequency; - -extern idCVar g_kickTime; -extern idCVar g_kickAmplitude; -extern idCVar g_blobTime; -extern idCVar g_blobSize; - -extern idCVar g_testHealthVision; -extern idCVar g_editEntityMode; -extern idCVar g_dragEntity; -extern idCVar g_dragDamping; -extern idCVar g_dragShowSelection; -extern idCVar g_dropItemRotation; - -extern idCVar g_vehicleVelocity; -extern idCVar g_vehicleForce; -extern idCVar g_vehicleSuspensionUp; -extern idCVar g_vehicleSuspensionDown; -extern idCVar g_vehicleSuspensionKCompress; -extern idCVar g_vehicleSuspensionDamping; -extern idCVar g_vehicleTireFriction; -#ifdef _D3XP -extern idCVar g_vehicleDebug; -extern idCVar g_debugShockwave; -extern idCVar g_enablePortalSky; -#endif - -extern idCVar ik_enable; -extern idCVar ik_debug; - -extern idCVar af_useLinearTime; -extern idCVar af_useImpulseFriction; -extern idCVar af_useJointImpulseFriction; -extern idCVar af_useSymmetry; -extern idCVar af_skipSelfCollision; -extern idCVar af_skipLimits; -extern idCVar af_skipFriction; -extern idCVar af_forceFriction; -extern idCVar af_maxLinearVelocity; -extern idCVar af_maxAngularVelocity; -extern idCVar af_timeScale; -extern idCVar af_jointFrictionScale; -extern idCVar af_contactFrictionScale; -extern idCVar af_highlightBody; -extern idCVar af_highlightConstraint; -extern idCVar af_showTimings; -extern idCVar af_showConstraints; -extern idCVar af_showConstraintNames; -extern idCVar af_showConstrainedBodies; -extern idCVar af_showPrimaryOnly; -extern idCVar af_showTrees; -extern idCVar af_showLimits; -extern idCVar af_showBodies; -extern idCVar af_showBodyNames; -extern idCVar af_showMass; -extern idCVar af_showTotalMass; -extern idCVar af_showInertia; -extern idCVar af_showVelocity; -extern idCVar af_showActive; -extern idCVar af_testSolid; - -extern idCVar rb_showTimings; -extern idCVar rb_showBodies; -extern idCVar rb_showMass; -extern idCVar rb_showInertia; -extern idCVar rb_showVelocity; -extern idCVar rb_showActive; - -extern idCVar pm_jumpheight; -extern idCVar pm_stepsize; -extern idCVar pm_crouchspeed; -extern idCVar pm_walkspeed; -extern idCVar pm_runspeed; -extern idCVar pm_noclipspeed; -extern idCVar pm_spectatespeed; -extern idCVar pm_spectatebbox; -extern idCVar pm_usecylinder; -extern idCVar pm_minviewpitch; -extern idCVar pm_maxviewpitch; -extern idCVar pm_stamina; -extern idCVar pm_staminathreshold; -extern idCVar pm_staminarate; -extern idCVar pm_crouchheight; -extern idCVar pm_crouchviewheight; -extern idCVar pm_normalheight; -extern idCVar pm_normalviewheight; -extern idCVar pm_deadheight; -extern idCVar pm_deadviewheight; -extern idCVar pm_crouchrate; -extern idCVar pm_bboxwidth; -extern idCVar pm_crouchbob; -extern idCVar pm_walkbob; -extern idCVar pm_runbob; -extern idCVar pm_runpitch; -extern idCVar pm_runroll; -extern idCVar pm_bobup; -extern idCVar pm_bobpitch; -extern idCVar pm_bobroll; -extern idCVar pm_thirdPersonRange; -extern idCVar pm_thirdPersonHeight; -extern idCVar pm_thirdPersonAngle; -extern idCVar pm_thirdPersonClip; -extern idCVar pm_thirdPerson; -extern idCVar pm_thirdPersonDeath; -extern idCVar pm_modelView; -extern idCVar pm_airTics; - -extern idCVar g_showPlayerShadow; -extern idCVar g_showHud; -extern idCVar g_showProjectilePct; -extern idCVar g_showBrass; -extern idCVar g_gun_x; -extern idCVar g_gun_y; -extern idCVar g_gun_z; -extern idCVar g_viewNodalX; -extern idCVar g_viewNodalZ; -extern idCVar g_fov; -extern idCVar g_testDeath; -extern idCVar g_skipViewEffects; -extern idCVar g_mpWeaponAngleScale; - -extern idCVar g_testParticle; -extern idCVar g_testParticleName; - -extern idCVar g_testPostProcess; - -extern idCVar g_testModelRotate; -extern idCVar g_testModelAnimate; -extern idCVar g_testModelBlend; -extern idCVar g_exportMask; -extern idCVar g_flushSave; - -#ifdef _D3XP -extern idCVar g_enableSlowmo; -extern idCVar g_slowmoStepRate; -extern idCVar g_testFullscreenFX; -extern idCVar g_testHelltimeFX; -extern idCVar g_testMultiplayerFX; -extern idCVar g_lowresFullscreenFX; -extern idCVar g_moveableDamageScale; -extern idCVar g_testBloomSpeed; -extern idCVar g_testBloomIntensity; -extern idCVar g_testBloomNumPasses; -#endif - -#ifdef _D3XP -extern idCVar g_grabberHoldSeconds; -extern idCVar g_grabberEnableShake; -extern idCVar g_grabberRandomMotion; -extern idCVar g_grabberHardStop; -extern idCVar g_grabberDamping; -#endif - -#ifdef _D3XP -extern idCVar g_xp_bind_run_once; -#endif - -extern idCVar aas_test; -extern idCVar aas_showAreas; -extern idCVar aas_showPath; -extern idCVar aas_showFlyPath; -extern idCVar aas_showWallEdges; -extern idCVar aas_showHideArea; -extern idCVar aas_pullPlayer; -extern idCVar aas_randomPullPlayer; -extern idCVar aas_goalArea; -extern idCVar aas_showPushIntoArea; - -extern idCVar net_clientPredictGUI; - -extern idCVar g_voteFlags; -extern idCVar g_mapCycle; -extern idCVar g_balanceTDM; - -extern idCVar si_timeLimit; -extern idCVar si_fragLimit; -extern idCVar si_gameType; -extern idCVar si_map; -extern idCVar si_spectators; - -#ifdef CTF -extern idCVar si_flagDropTimeLimit; -extern idCVar si_midnight; - -extern idCVar g_flagAttachJoint; -extern idCVar g_flagAttachOffsetX; -extern idCVar g_flagAttachOffsetY; -extern idCVar g_flagAttachOffsetZ; -extern idCVar g_flagAttachAngleX; -extern idCVar g_flagAttachAngleY; -extern idCVar g_flagAttachAngleZ; - -extern idCVar g_CTFArrows; - -#endif - -extern idCVar net_clientSelfSmoothing; -extern idCVar net_clientLagOMeter; - -extern const char *si_gameTypeArgs[]; - -extern const char *ui_skinArgs[]; - -#endif /* !__SYS_CVAR_H__ */ diff --git a/d3xp/gamesys/TypeInfo.cpp b/d3xp/gamesys/TypeInfo.cpp deleted file mode 100644 index aab6c465..00000000 --- a/d3xp/gamesys/TypeInfo.cpp +++ /dev/null @@ -1,1448 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -// This is real evil but allows the code to inspect arbitrary class variables. -#define private public -#define protected public - -#include "sys/platform.h" -#include "idlib/containers/LinkList.h" -#include "idlib/containers/StaticList.h" -#include "idlib/math/Quat.h" -#include "idlib/math/Interpolate.h" -#include "idlib/bv/Bounds.h" -#include "idlib/Lexer.h" -#include "framework/Common.h" -#include "framework/FileSystem.h" - -#include "Entity.h" - -#ifdef ID_DEBUG_MEMORY -#include "GameTypeInfo.h" // Make sure this is up to date! -#else -#include "NoGameTypeInfo.h" -#endif - -#include "TypeInfo.h" - -// disabled because it's adds about 64MB to state dumps and takes a really long time -//#define DUMP_GAMELOCAL - - -typedef void (*WriteVariableType_t)( const char *varName, const char *varType, const char *scope, const char *prefix, const char *postfix, const char *value, const void *varPtr, int varSize ); - - -class idTypeInfoTools { -public: - static const classTypeInfo_t * FindClassInfo( const char *typeName ); - static const enumTypeInfo_t * FindEnumInfo( const char *typeName ); - static bool IsSubclassOf( const char *typeName, const char *superType ); - static void PrintType( const void *typePtr, const char *typeName ); - static void WriteTypeToFile( idFile *fp, const void *typePtr, const char *typeName ); - static void InitTypeVariables( const void *typePtr, const char *typeName, int value ); - static void WriteGameState( const char *fileName ); - static void CompareGameState( const char *fileName ); - -private: - static idFile * fp; - static int initValue; - static WriteVariableType_t Write; - static idLexer * src; - static bool typeError; - - static const char * OutputString( const char *string ); - static bool ParseTemplateArguments( idLexer &src, idStr &arguments ); - static void PrintVariable( const char *varName, const char *varType, const char *scope, const char *prefix, const char *postfix, const char *value, const void *varPtr, int varSize ); - static void WriteVariable( const char *varName, const char *varType, const char *scope, const char *prefix, const char *postfix, const char *value, const void *varPtr, int varSize ); - static void WriteGameStateVariable( const char *varName, const char *varType, const char *scope, const char *prefix, const char *postfix, const char *value, const void *varPtr, int varSize ); - static void InitVariable( const char *varName, const char *varType, const char *scope, const char *prefix, const char *postfix, const char *value, const void *varPtr, int varSize ); - static void VerifyVariable( const char *varName, const char *varType, const char *scope, const char *prefix, const char *postfix, const char *value, const void *varPtr, int varSize ); - static int WriteVariable_r( const void *varPtr, const char *varName, const char *varType, const char *scope, const char *prefix, const int pointerDepth ); - static void WriteClass_r( const void *classPtr, const char *className, const char *classType, const char *scope, const char *prefix, const int pointerDepth ); -}; - -idFile * idTypeInfoTools::fp = NULL; -int idTypeInfoTools::initValue = 0; -WriteVariableType_t idTypeInfoTools::Write = NULL; -idLexer * idTypeInfoTools::src = NULL; -bool idTypeInfoTools::typeError = false; - - -/* -================ -GetTypeVariableName -================ -*/ -const char *GetTypeVariableName( const char *typeName, int offset ) { - static char varName[1024]; - int i; - - for ( i = 0; classTypeInfo[i].typeName != NULL; i++ ) { - if ( idStr::Cmp( typeName, classTypeInfo[i].typeName ) == 0 ) { - if ( classTypeInfo[i].variables[0].name != NULL && offset >= classTypeInfo[i].variables[0].offset ) { - break; - } - typeName = classTypeInfo[i].superType; - if ( *typeName == '\0' ) { - return ""; - } - i = -1; - } - } - - const classTypeInfo_t &classInfo = classTypeInfo[i]; - - for ( i = 0; classInfo.variables[i].name != NULL; i++ ) { - if ( offset <= classInfo.variables[i].offset ) { - break; - } - } - if ( i == 0 ) { - idStr::snPrintf( varName, sizeof( varName ), "%s::", classInfo.typeName ); - } else { - idStr::snPrintf( varName, sizeof( varName ), "%s::%s", classInfo.typeName, classInfo.variables[i-1].name ); - } - return varName; -} - -/* -================ -idTypeInfoTools::FindClassInfo -================ -*/ -const classTypeInfo_t *idTypeInfoTools::FindClassInfo( const char *typeName ) { - int i; - - for ( i = 0; classTypeInfo[i].typeName != NULL; i++ ) { - if ( idStr::Cmp( typeName, classTypeInfo[i].typeName ) == 0 ) { - return &classTypeInfo[i]; - } - } - return NULL; -} - -/* -================ -idTypeInfoTools::FindEnumInfo -================ -*/ -const enumTypeInfo_t *idTypeInfoTools::FindEnumInfo( const char *typeName ) { - int i; - - for ( i = 0; enumTypeInfo[i].typeName != NULL; i++ ) { - if ( idStr::Cmp( typeName, enumTypeInfo[i].typeName ) == 0 ) { - return &enumTypeInfo[i]; - } - } - return NULL; -} - -/* -================ -idTypeInfoTools::IsSubclassOf -================ -*/ -bool idTypeInfoTools::IsSubclassOf( const char *typeName, const char *superType ) { - int i; - - while( *typeName != '\0' ) { - if ( idStr::Cmp( typeName, superType ) == 0 ) { - return true; - } - for ( i = 0; classTypeInfo[i].typeName != NULL; i++ ) { - if ( idStr::Cmp( typeName, classTypeInfo[i].typeName ) == 0 ) { - typeName = classTypeInfo[i].superType; - break; - } - } - if ( classTypeInfo[i].typeName == NULL ) { - common->Warning( "super class %s not found", typeName ); - break; - } - } - return false; -} - -/* -================ -idTypeInfoTools::OutputString -================ -*/ -const char *idTypeInfoTools::OutputString( const char *string ) { - static int index = 0; - static char buffers[4][16384]; - char *out; - int i, c; - - out = buffers[index]; - index = ( index + 1 ) & 3; - - if ( string == NULL ) { - return NULL; - } - - for ( i = 0; i < sizeof( buffers[0] ) - 2; i++ ) { - c = *string++; - switch( c ) { - case '\0': out[i] = '\0'; return out; - case '\\': out[i++] = '\\'; out[i] = '\\'; break; - case '\n': out[i++] = '\\'; out[i] = 'n'; break; - case '\r': out[i++] = '\\'; out[i] = 'r'; break; - case '\t': out[i++] = '\\'; out[i] = 't'; break; - case '\v': out[i++] = '\\'; out[i] = 'v'; break; - default: out[i] = c; break; - } - } - out[i] = '\0'; - return out; -} - -/* -================ -idTypeInfoTools::ParseTemplateArguments -================ -*/ -bool idTypeInfoTools::ParseTemplateArguments( idLexer &src, idStr &arguments ) { - int indent; - idToken token; - - arguments = ""; - - if ( !src.ExpectTokenString( "<" ) ) { - return false; - } - - indent = 1; - while( indent ) { - if ( !src.ReadToken( &token ) ) { - break; - } - if ( token == "<" ) { - indent++; - } else if ( token == ">" ) { - indent--; - } else { - if ( arguments.Length() ) { - arguments += " "; - } - arguments += token; - } - } - return true; -} - -/* -================ -idTypeInfoTools::PrintType -================ -*/ -void idTypeInfoTools::PrintType( const void *typePtr, const char *typeName ) { - idTypeInfoTools::fp = NULL; - idTypeInfoTools::initValue = 0; - idTypeInfoTools::Write = PrintVariable; - WriteClass_r( typePtr, "", typeName, "", "", 0 ); -} - -/* -================ -idTypeInfoTools::WriteTypeToFile -================ -*/ -void idTypeInfoTools::WriteTypeToFile( idFile *fp, const void *typePtr, const char *typeName ) { - idTypeInfoTools::fp = fp; - idTypeInfoTools::initValue = 0; - idTypeInfoTools::Write = WriteVariable; - WriteClass_r( typePtr, "", typeName, "", "", 0 ); -} - -/* -================ -idTypeInfoTools::InitTypeVariables -================ -*/ -void idTypeInfoTools::InitTypeVariables( const void *typePtr, const char *typeName, int value ) { - idTypeInfoTools::fp = NULL; - idTypeInfoTools::initValue = value; - idTypeInfoTools::Write = InitVariable; - WriteClass_r( typePtr, "", typeName, "", "", 0 ); -} - -/* -================ -IsAllowedToChangedFromSaveGames -================ -*/ -bool IsAllowedToChangedFromSaveGames( const char *varName, const char *varType, const char *scope, const char *prefix, const char *postfix, const char *value ) { - if ( idStr::Icmp( scope, "idAnimator" ) == 0 ) { - if ( idStr::Icmp( varName, "forceUpdate" ) == 0 ) { - return true; - } - if ( idStr::Icmp( varName, "lastTransformTime" ) == 0 ) { - return true; - } - if ( idStr::Icmp( varName, "AFPoseTime" ) == 0 ) { - return true; - } - if ( idStr::Icmp( varName, "frameBounds" ) == 0 ) { - return true; - } - } else if ( idStr::Icmp( scope, "idClipModel" ) == 0 ) { - if ( idStr::Icmp( varName, "touchCount" ) == 0 ) { - return true; - } - } else if ( idStr::Icmp( scope, "idEntity" ) == 0 ) { - if ( idStr::Icmp( varName, "numPVSAreas" ) == 0 ) { - return true; - } - if ( idStr::Icmp( varName, "renderView" ) == 0 ) { - return true; - } - } else if ( idStr::Icmp( scope, "idBrittleFracture" ) == 0 ) { - if ( idStr::Icmp( varName, "changed" ) == 0 ) { - return true; - } - } else if ( idStr::Icmp( scope, "idPhysics_AF" ) == 0 ) { - return true; - } else if ( idStr::Icmp( scope, "renderEntity_t" ) == 0 ) { - // These get fixed up when UpdateVisuals is called - if ( idStr::Icmp( varName, "origin" ) == 0 ) { - return true; - } - if ( idStr::Icmp( varName, "axis" ) == 0 ) { - return true; - } - if ( idStr::Icmp( varName, "bounds" ) == 0 ) { - return true; - } - } - - if ( idStr::Icmpn( prefix, "idAFEntity_Base::af.idAF::physicsObj.idPhysics_AF", 49) == 0 ) { - return true; - } - - return false; -} - -/* -================ -IsRenderHandleVariable -================ -*/ -bool IsRenderHandleVariable( const char *varName, const char *varType, const char *scope, const char *prefix, const char *postfix, const char *value ) { - if ( idStr::Icmp( scope, "idClipModel" ) == 0 ) { - if ( idStr::Icmp( varName, "renderModelHandle" ) == 0 ) { - return true; - } - } else if ( idStr::Icmp( scope, "idFXLocalAction" ) == 0 ) { - if ( idStr::Icmp( varName, "lightDefHandle" ) == 0 ) { - return true; - } - if ( idStr::Icmp( varName, "modelDefHandle" ) == 0 ) { - return true; - } - } else if ( idStr::Icmp( scope, "idEntity" ) == 0 ) { - if ( idStr::Icmp( varName, "modelDefHandle" ) == 0 ) { - return true; - } - } else if ( idStr::Icmp( scope, "idLight" ) == 0 ) { - if ( idStr::Icmp( varName, "lightDefHandle" ) == 0 ) { - return true; - } - } else if ( idStr::Icmp( scope, "idAFEntity_Gibbable" ) == 0 ) { - if ( idStr::Icmp( varName, "skeletonModelDefHandle" ) == 0 ) { - return true; - } - } else if ( idStr::Icmp( scope, "idAFEntity_SteamPipe" ) == 0 ) { - if ( idStr::Icmp( varName, "steamModelHandle" ) == 0 ) { - return true; - } - } else if ( idStr::Icmp( scope, "idItem" ) == 0 ) { - if ( idStr::Icmp( varName, "itemShellHandle" ) == 0 ) { - return true; - } - } else if ( idStr::Icmp( scope, "idExplodingBarrel" ) == 0 ) { - if ( idStr::Icmp( varName, "particleModelDefHandle" ) == 0 ) { - return true; - } - if ( idStr::Icmp( varName, "lightDefHandle" ) == 0 ) { - return true; - } - } else if ( idStr::Icmp( scope, "idProjectile" ) == 0 ) { - if ( idStr::Icmp( varName, "lightDefHandle" ) == 0 ) { - return true; - } - } else if ( idStr::Icmp( scope, "idBFGProjectile" ) == 0 ) { - if ( idStr::Icmp( varName, "secondModelDefHandle" ) == 0 ) { - return true; - } - } else if ( idStr::Icmp( scope, "idSmokeParticles" ) == 0 ) { - if ( idStr::Icmp( varName, "renderEntityHandle" ) == 0 ) { - return true; - } - } else if ( idStr::Icmp( scope, "idWeapon" ) == 0 ) { - if ( idStr::Icmp( varName, "muzzleFlashHandle" ) == 0 ) { - return true; - } - if ( idStr::Icmp( varName, "worldMuzzleFlashHandle" ) == 0 ) { - return true; - } - if ( idStr::Icmp( varName, "guiLightHandle" ) == 0 ) { - return true; - } - if ( idStr::Icmp( varName, "nozzleGlowHandle" ) == 0 ) { - return true; - } - } - return false; -} - -/* -================ -idTypeInfoTools::PrintVariable -================ -*/ -void idTypeInfoTools::PrintVariable( const char *varName, const char *varType, const char *scope, const char *prefix, const char *postfix, const char *value, const void *varPtr, int varSize ) { - common->Printf( "%s%s::%s%s = \"%s\"\n", prefix, scope, varName, postfix, value ); -} - -/* -================ -idTypeInfoTools::WriteVariable -================ -*/ -void idTypeInfoTools::WriteVariable( const char *varName, const char *varType, const char *scope, const char *prefix, const char *postfix, const char *value, const void *varPtr, int varSize ) { - - for ( int i = idStr::FindChar( value, '#', 0 ); i >= 0; i = idStr::FindChar( value, '#', i+1 ) ) { - if ( idStr::Icmpn( value+i+1, "INF", 3 ) == 0 || - idStr::Icmpn( value+i+1, "IND", 3 ) == 0 || - idStr::Icmpn( value+i+1, "NAN", 3 ) == 0 || - idStr::Icmpn( value+i+1, "QNAN", 4 ) == 0 || - idStr::Icmpn( value+i+1, "SNAN", 4 ) == 0 ) { - common->Warning( "%s%s::%s%s = \"%s\"", prefix, scope, varName, postfix, value ); - break; - } - } - fp->WriteFloatString( "%s%s::%s%s = \"%s\"\n", prefix, scope, varName, postfix, value ); -} - -/* -================ -idTypeInfoTools::WriteGameStateVariable -================ -*/ -void idTypeInfoTools::WriteGameStateVariable( const char *varName, const char *varType, const char *scope, const char *prefix, const char *postfix, const char *value, const void *varPtr, int varSize ) { - - for ( int i = idStr::FindChar( value, '#', 0 ); i >= 0; i = idStr::FindChar( value, '#', i+1 ) ) { - if ( idStr::Icmpn( value+i+1, "INF", 3 ) == 0 || - idStr::Icmpn( value+i+1, "IND", 3 ) == 0 || - idStr::Icmpn( value+i+1, "NAN", 3 ) == 0 || - idStr::Icmpn( value+i+1, "QNAN", 4 ) == 0 || - idStr::Icmpn( value+i+1, "SNAN", 4 ) == 0 ) { - common->Warning( "%s%s::%s%s = \"%s\"", prefix, scope, varName, postfix, value ); - break; - } - } - - if ( IsRenderHandleVariable( varName, varType, scope, prefix, postfix, value ) ) { - return; - } - - if ( IsAllowedToChangedFromSaveGames( varName, varType, scope, prefix, postfix, value ) ) { - return; - } - - fp->WriteFloatString( "%s%s::%s%s = \"%s\"\n", prefix, scope, varName, postfix, value ); -} - -/* -================ -idTypeInfoTools::InitVariable -================ -*/ -void idTypeInfoTools::InitVariable( const char *varName, const char *varType, const char *scope, const char *prefix, const char *postfix, const char *value, const void *varPtr, int varSize ) { - if ( varPtr != NULL && varSize > 0 ) { - // NOTE: skip renderer handles - if ( IsRenderHandleVariable( varName, varType, scope, prefix, postfix, value ) ) { - return; - } - memset( const_cast(varPtr), initValue, varSize ); - } -} - -/* -================ -idTypeInfoTools::VerifyVariable -================ -*/ -void idTypeInfoTools::VerifyVariable( const char *varName, const char *varType, const char *scope, const char *prefix, const char *postfix, const char *value, const void *varPtr, int varSize ) { - idToken token; - - if ( typeError ) { - return; - } - - src->SkipUntilString( "=" ); - src->ExpectTokenType( TT_STRING, 0, &token ); - if ( token.Cmp( value ) != 0 ) { - - // NOTE: skip several things - - if ( IsRenderHandleVariable( varName, varType, scope, prefix, postfix, value ) ) { - return; - } - - if ( IsAllowedToChangedFromSaveGames( varName, varType, scope, prefix, postfix, value ) ) { - return; - } - - src->Warning( "state diff for %s%s::%s%s\n%s\n%s", prefix, scope, varName, postfix, token.c_str(), value ); - typeError = true; - } -} - -/* -================ -idTypeInfoTools::WriteVariable_r -================ -*/ -int idTypeInfoTools::WriteVariable_r( const void *varPtr, const char *varName, const char *varType, const char *scope, const char *prefix, const int pointerDepth ) { - int i, isPointer, typeSize; - idLexer typeSrc; - idToken token; - idStr typeString, templateArgs; - - isPointer = 0; - typeSize = -1; - - // create a type string without 'const', 'mutable', 'class', 'struct', 'union' - typeSrc.LoadMemory( varType, idStr::Length( varType ), varName ); - while( typeSrc.ReadToken( &token ) ) { - if ( token != "const" && token != "mutable" && token != "class" && token != "struct" && token != "union" ) { - typeString += token + " "; - } - } - typeString.StripTrailing( ' ' ); - typeSrc.FreeSource(); - - // if this is an array - if ( typeString[typeString.Length() - 1] == ']' ) { - for ( i = typeString.Length(); i > 0 && typeString[i - 1] != '['; i-- ) { - } - int num = atoi( &typeString[i] ); - idStr listVarType = typeString; - listVarType.CapLength( i - 1 ); - typeSize = 0; - for ( i = 0; i < num; i++ ) { - idStr listVarName = va( "%s[%d]", varName, i ); - int size = WriteVariable_r( varPtr, listVarName, listVarType, scope, prefix, pointerDepth ); - typeSize += size; - if ( size == -1 ) { - break; - } - varPtr = (void *)( ( (byte *) varPtr ) + size ); - } - return typeSize; - } - -#if D3_SIZEOFPTR == 4 - const uintptr_t uninitPtr = (uintptr_t)0xcdcdcdcdUL; -#elif D3_SIZEOFPTR == 8 - const uintptr_t uninitPtr = (uintptr_t)0xcdcdcdcdcdcdcdcdULL; -#else -#error "Unexpected pointer size" -#endif - - // if this is a pointer - isPointer = 0; - for ( i = typeString.Length(); i > 0 && typeString[i - 1] == '*'; i -= 2 ) { - if ( varPtr == (void*)uninitPtr || ( varPtr != NULL && *((unsigned int *)varPtr) == 0xcdcdcdcd ) ) { - common->Warning( "%s%s::%s%s references uninitialized memory", prefix, scope, varName, "" ); - return typeSize; - } - if ( varPtr != NULL ) { - varPtr = *((void **)varPtr); - } - isPointer++; - } - - if ( varPtr == NULL ) { - Write( varName, varType, scope, prefix, "", "", varPtr, 0 ); - return sizeof( void * ); - } - - typeSrc.LoadMemory( typeString, typeString.Length(), varName ); - - if ( !typeSrc.ReadToken( &token ) ) { - Write( varName, varType, scope, prefix, "", va( "", varType ), varPtr, 0 ); - return -1; - } - - // get full type - while( typeSrc.CheckTokenString( "::" ) ) { - idToken newToken; - typeSrc.ExpectTokenType( TT_NAME, 0, &newToken ); - token += "::" + newToken; - } - - if ( token == "signed" ) { - - if ( !typeSrc.ReadToken( &token ) ) { - Write( varName, varType, scope, prefix, "", va( "", varType ), varPtr, 0 ); - return -1; - } - if ( token == "char" ) { - - typeSize = sizeof( signed char ); - Write( varName, varType, scope, prefix, "", va( "%d", *((signed char *)varPtr) ), varPtr, typeSize ); - - } else if ( token == "short" ) { - - typeSize = sizeof( signed short ); - Write( varName, varType, scope, prefix, "", va( "%d", *((signed short *)varPtr) ), varPtr, typeSize ); - - } else if ( token == "int" ) { - - typeSize = sizeof( signed int ); - Write( varName, varType, scope, prefix, "", va( "%d", *((signed int *)varPtr) ), varPtr, typeSize ); - - } else if ( token == "long" ) { - - typeSize = sizeof( signed long ); - Write( varName, varType, scope, prefix, "", va( "%ld", *((signed long *)varPtr) ), varPtr, typeSize ); - - } else { - - Write( varName, varType, scope, prefix, "", va( "", varType ), varPtr, 0 ); - return -1; - } - - } else if ( token == "unsigned" ) { - - if ( !typeSrc.ReadToken( &token ) ) { - Write( varName, varType, scope, prefix, "", va( "", varType ), varPtr, 0 ); - return -1; - } - if ( token == "char" ) { - - typeSize = sizeof( unsigned char ); - Write( varName, varType, scope, prefix, "", va( "%d", *((unsigned char *)varPtr) ), varPtr, typeSize ); - - } else if ( token == "short" ) { - - typeSize = sizeof( unsigned short ); - Write( varName, varType, scope, prefix, "", va( "%d", *((unsigned short *)varPtr) ), varPtr, typeSize ); - - } else if ( token == "int" ) { - - typeSize = sizeof( unsigned int ); - Write( varName, varType, scope, prefix, "", va( "%d", *((unsigned int *)varPtr) ), varPtr, typeSize ); - - } else if ( token == "long" ) { - - typeSize = sizeof( unsigned long ); - Write( varName, varType, scope, prefix, "", va( "%lu", *((unsigned long *)varPtr) ), varPtr, typeSize ); - - } else { - - Write( varName, varType, scope, prefix, "", va( "", varType ), varPtr, 0 ); - return -1; - } - - } else if ( token == "byte" ) { - - typeSize = sizeof( byte ); - Write( varName, varType, scope, prefix, "", va( "%d", *((byte *)varPtr) ), varPtr, typeSize ); - - } else if ( token == "word" ) { - - typeSize = sizeof( word ); - Write( varName, varType, scope, prefix, "", va( "%d", *((word *)varPtr) ), varPtr, typeSize ); - - } else if ( token == "dword" ) { - - typeSize = sizeof( dword ); - Write( varName, varType, scope, prefix, "", va( "%d", *((dword *)varPtr) ), varPtr, typeSize ); - - } else if ( token == "bool" ) { - - typeSize = sizeof( bool ); - Write( varName, varType, scope, prefix, "", va( "%d", *((bool *)varPtr) ), varPtr, typeSize ); - - } else if ( token == "char" ) { - - typeSize = sizeof( char ); - Write( varName, varType, scope, prefix, "", va( "%d", *((char *)varPtr) ), varPtr, typeSize ); - - } else if ( token == "short" ) { - - typeSize = sizeof( short ); - Write( varName, varType, scope, prefix, "", va( "%d", *((short *)varPtr) ), varPtr, typeSize ); - - } else if ( token == "int" ) { - - typeSize = sizeof( int ); - Write( varName, varType, scope, prefix, "", va( "%d", *((int *)varPtr) ), varPtr, typeSize ); - - } else if ( token == "long" ) { - - typeSize = sizeof( long ); - Write( varName, varType, scope, prefix, "", va( "%ld", *((long *)varPtr) ), varPtr, typeSize ); - - } else if ( token == "float" ) { - - typeSize = sizeof( float ); - Write( varName, varType, scope, prefix, "", idStr( *((float *)varPtr) ).c_str(), varPtr, typeSize ); - - } else if ( token == "double" ) { - - typeSize = sizeof( double ); - Write( varName, varType, scope, prefix, "", idStr( (float)*((double *)varPtr) ).c_str(), varPtr, typeSize ); - - } else if ( token == "idVec2" ) { - - typeSize = sizeof( idVec2 ); - Write( varName, varType, scope, prefix, "", ((idVec2 *)varPtr)->ToString( 8 ), varPtr, typeSize ); - - } else if ( token == "idVec3" ) { - - typeSize = sizeof( idVec3 ); - Write( varName, varType, scope, prefix, "", ((idVec3 *)varPtr)->ToString( 8 ), varPtr, typeSize ); - - } else if ( token == "idVec4" ) { - - typeSize = sizeof( idVec4 ); - Write( varName, varType, scope, prefix, "", ((idVec4 *)varPtr)->ToString( 8 ), varPtr, typeSize ); - - } else if ( token == "idVec5" ) { - - typeSize = sizeof( idVec5 ); - Write( varName, varType, scope, prefix, "", ((idVec5 *)varPtr)->ToString( 8 ), varPtr, typeSize ); - - } else if ( token == "idVec6" ) { - - typeSize = sizeof( idVec6 ); - Write( varName, varType, scope, prefix, "", ((idVec6 *)varPtr)->ToString( 8 ), varPtr, typeSize ); - - } else if ( token == "idVecX" ) { - - const idVecX *vec = ((idVecX *)varPtr); - if ( vec->ToFloatPtr() != NULL ) { - Write( varName, varType, scope, prefix, "", vec->ToString( 8 ), vec->ToFloatPtr(), vec->GetSize() * sizeof( float ) ); - } else { - Write( varName, varType, scope, prefix, "", "", varPtr, 0 ); - } - typeSize = sizeof( idVecX ); - - } else if ( token == "idMat2" ) { - - typeSize = sizeof( idMat2 ); - Write( varName, varType, scope, prefix, "", ((idMat2 *)varPtr)->ToString( 8 ), varPtr, typeSize ); - - } else if ( token == "idMat3" ) { - - typeSize = sizeof( idMat3 ); - Write( varName, varType, scope, prefix, "", ((idMat3 *)varPtr)->ToString( 8 ), varPtr, typeSize ); - - } else if ( token == "idMat4" ) { - - typeSize = sizeof( idMat4 ); - Write( varName, varType, scope, prefix, "", ((idMat4 *)varPtr)->ToString( 8 ), varPtr, typeSize ); - - } else if ( token == "idMat5" ) { - - typeSize = sizeof( idMat5 ); - Write( varName, varType, scope, prefix, "", ((idMat5 *)varPtr)->ToString( 8 ), varPtr, typeSize ); - - } else if ( token == "idMat6" ) { - - typeSize = sizeof( idMat6 ); - Write( varName, varType, scope, prefix, "", ((idMat6 *)varPtr)->ToString( 8 ), varPtr, typeSize ); - - } else if ( token == "idMatX" ) { - - typeSize = sizeof( idMatX ); - const idMatX *mat = ((idMatX *)varPtr); - if ( mat->ToFloatPtr() != NULL ) { - Write( varName, varType, scope, prefix, "", mat->ToString( 8 ), mat->ToFloatPtr(), mat->GetNumColumns() * mat->GetNumRows() * sizeof( float ) ); - } else { - Write( varName, varType, scope, prefix, "", "", NULL, 0 ); - } - - } else if ( token == "idAngles" ) { - - typeSize = sizeof( idAngles ); - Write( varName, varType, scope, prefix, "", ((idAngles *)varPtr)->ToString( 8 ), varPtr, typeSize ); - - } else if ( token == "idQuat" ) { - - typeSize = sizeof( idQuat ); - Write( varName, varType, scope, prefix, "", ((idQuat *)varPtr)->ToString( 8 ), varPtr, typeSize ); - - } else if ( token == "idBounds" ) { - - typeSize = sizeof( idBounds ); - const idBounds *bounds = ((idBounds *)varPtr); - if ( bounds->IsCleared() ) { - Write( varName, varType, scope, prefix, "", "", varPtr, typeSize ); - } else { - Write( varName, varType, scope, prefix, "", va( "(%s)-(%s)", (*bounds)[0].ToString( 8 ), (*bounds)[1].ToString( 8 ) ), varPtr, typeSize ); - } - - } else if ( token == "idList" ) { - - idList *list = ((idList *)varPtr); - Write( varName, varType, scope, prefix, ".num", va( "%d", list->Num() ), NULL, 0 ); - // NOTE: we don't care about the amount of memory allocated - //Write( varName, varType, scope, prefix, ".size", va( "%d", list->Size() ), NULL, 0 ); - Write( varName, varType, scope, prefix, ".granularity", va( "%d", list->GetGranularity() ), NULL, 0 ); - - if ( list->Num() && ParseTemplateArguments( typeSrc, templateArgs ) ) { - void *listVarPtr = list->Ptr(); - for ( i = 0; i < list->Num(); i++ ) { - idStr listVarName = va( "%s[%d]", varName, i ); - int size = WriteVariable_r( listVarPtr, listVarName, templateArgs, scope, prefix, pointerDepth ); - if ( size == -1 ) { - break; - } - listVarPtr = (void *)( ( (byte *) listVarPtr ) + size ); - } - } - - typeSize = sizeof( idList ); - - } else if ( token == "idStaticList" ) { - - idStaticList *list = ((idStaticList *)varPtr); - Write( varName, varType, scope, prefix, ".num", va( "%d", list->Num() ), NULL, 0 ); - - int totalSize = 0; - if ( list->Num() && ParseTemplateArguments( typeSrc, templateArgs ) ) { - void *listVarPtr = list->Ptr(); - for ( i = 0; i < list->Num(); i++ ) { - idStr listVarName = va( "%s[%d]", varName, i ); - int size = WriteVariable_r( listVarPtr, listVarName, templateArgs, scope, prefix, pointerDepth ); - if ( size == -1 ) { - break; - } - totalSize += size; - listVarPtr = (void *)( ( (byte *) listVarPtr ) + size ); - } - } - - typeSize = sizeof( int ) + totalSize; - - } else if ( token == "idLinkList" ) { - - // FIXME: implement - typeSize = sizeof( idLinkList ); - Write( varName, varType, scope, prefix, "", va( "", varType ), NULL, 0 ); - - } else if ( token == "idStr" ) { - - typeSize = sizeof( idStr ); - - const idStr *str = ((idStr *)varPtr); - Write( varName, varType, scope, prefix, "", OutputString( str->c_str() ), str->c_str(), str->Length() ); - - } else if ( token == "idStrList" ) { - - typeSize = sizeof( idStrList ); - - const idStrList *list = ((idStrList *)varPtr); - if ( list->Num() ) { - for ( i = 0; i < list->Num(); i++ ) { - Write( varName, varType, scope, prefix, va("[%d]", i ), OutputString( (*list)[i].c_str() ), (*list)[i].c_str(), (*list)[i].Length() ); - } - } else { - Write( varName, varType, scope, prefix, "", "", NULL, 0 ); - } - - } else if ( token == "idDict" ) { - - typeSize = sizeof( idDict ); - - const idDict *dict = ((idDict *)varPtr); - if ( dict->GetNumKeyVals() ) { - for ( i = 0; i < dict->GetNumKeyVals(); i++ ) { - const idKeyValue *kv = dict->GetKeyVal( i ); - Write( varName, varType, scope, prefix, va("[%d]", i ), va( "\'%s\' \'%s\'", OutputString( kv->GetKey().c_str() ), OutputString( kv->GetValue().c_str() ) ), NULL, 0 ); - } - } else { - Write( varName, varType, scope, prefix, "", "", NULL, 0 ); - } - - } else if ( token == "idExtrapolate" ) { - - const idExtrapolate *interpolate = ((idExtrapolate *)varPtr); - Write( varName, varType, scope, prefix, ".extrapolationType", idStr( interpolate->GetExtrapolationType() ).c_str(), &interpolate->extrapolationType, sizeof( interpolate->extrapolationType ) ); - Write( varName, varType, scope, prefix, ".startTime", idStr( interpolate->GetStartTime() ).c_str(), &interpolate->startTime, sizeof( interpolate->startTime ) ); - Write( varName, varType, scope, prefix, ".duration", idStr( interpolate->GetDuration() ).c_str(), &interpolate->duration, sizeof( interpolate->duration ) ); - - if ( ParseTemplateArguments( typeSrc, templateArgs ) ) { - if ( templateArgs == "int" ) { - const idExtrapolate *interpolate = ((idExtrapolate *)varPtr); - Write( varName, varType, scope, prefix, ".startValue", idStr( interpolate->GetStartValue() ).c_str(), &interpolate->startValue, sizeof( interpolate->startValue ) ); - Write( varName, varType, scope, prefix, ".baseSpeed", idStr( interpolate->GetBaseSpeed() ).c_str(), &interpolate->baseSpeed, sizeof( interpolate->baseSpeed ) ); - Write( varName, varType, scope, prefix, ".speed", idStr( interpolate->GetSpeed() ).c_str(), &interpolate->speed, sizeof( interpolate->speed ) ); - typeSize = sizeof( idExtrapolate ); - } else if ( templateArgs == "float" ) { - const idExtrapolate *interpolate = ((idExtrapolate *)varPtr); - Write( varName, varType, scope, prefix, ".startValue", idStr( interpolate->GetStartValue() ).c_str(), &interpolate->startValue, sizeof( interpolate->startValue ) ); - Write( varName, varType, scope, prefix, ".baseSpeed", idStr( interpolate->GetBaseSpeed() ).c_str(), &interpolate->baseSpeed, sizeof( interpolate->baseSpeed ) ); - Write( varName, varType, scope, prefix, ".speed", idStr( interpolate->GetSpeed() ).c_str(), &interpolate->speed, sizeof( interpolate->speed ) ); - typeSize = sizeof( idExtrapolate ); - } else if ( templateArgs == "idVec3" ) { - const idExtrapolate *interpolate = ((idExtrapolate *)varPtr); - Write( varName, varType, scope, prefix, ".startValue", interpolate->GetStartValue().ToString( 8 ), &interpolate->startValue, sizeof( interpolate->startValue ) ); - Write( varName, varType, scope, prefix, ".baseSpeed", interpolate->GetBaseSpeed().ToString( 8 ), &interpolate->baseSpeed, sizeof( interpolate->baseSpeed ) ); - Write( varName, varType, scope, prefix, ".speed", interpolate->GetSpeed().ToString( 8 ), &interpolate->speed, sizeof( interpolate->speed ) ); - typeSize = sizeof( idExtrapolate ); - } else if ( templateArgs == "idAngles" ) { - const idExtrapolate *interpolate = ((idExtrapolate *)varPtr); - Write( varName, varType, scope, prefix, ".startValue", interpolate->GetStartValue().ToString( 8 ), &interpolate->startValue, sizeof( interpolate->startValue ) ); - Write( varName, varType, scope, prefix, ".baseSpeed", interpolate->GetBaseSpeed().ToString( 8 ), &interpolate->baseSpeed, sizeof( interpolate->baseSpeed ) ); - Write( varName, varType, scope, prefix, ".speed", interpolate->GetSpeed().ToString( 8 ), &interpolate->speed, sizeof( interpolate->speed ) ); - typeSize = sizeof( idExtrapolate ); - } else { - Write( varName, varType, scope, prefix, "", va( "", templateArgs.c_str() ), NULL, 0 ); - } - } - - } else if ( token == "idInterpolate" ) { - - const idInterpolate *interpolate = ((idInterpolate *)varPtr); - Write( varName, varType, scope, prefix, ".startTime", idStr( interpolate->GetStartTime() ).c_str(), &interpolate->startTime, sizeof( interpolate->startTime ) ); - Write( varName, varType, scope, prefix, ".duration", idStr( interpolate->GetDuration() ).c_str(), &interpolate->duration, sizeof( interpolate->duration ) ); - - if ( ParseTemplateArguments( typeSrc, templateArgs ) ) { - if ( templateArgs == "int" ) { - const idInterpolate *interpolate = ((idInterpolate *)varPtr); - Write( varName, varType, scope, prefix, ".startValue", idStr( interpolate->GetStartValue() ).c_str(), &interpolate->startValue, sizeof( interpolate->startValue ) ); - Write( varName, varType, scope, prefix, ".endValue", idStr( interpolate->GetEndValue() ).c_str(), &interpolate->endValue, sizeof( interpolate->endValue ) ); - typeSize = sizeof( idInterpolate ); - } else if ( templateArgs == "float" ) { - const idInterpolate *interpolate = ((idInterpolate *)varPtr); - Write( varName, varType, scope, prefix, ".startValue", idStr( interpolate->GetStartValue() ).c_str(), &interpolate->startValue, sizeof( interpolate->startValue ) ); - Write( varName, varType, scope, prefix, ".endValue", idStr( interpolate->GetEndValue() ).c_str(), &interpolate->endValue, sizeof( interpolate->endValue ) ); - typeSize = sizeof( idInterpolate ); - } else { - Write( varName, varType, scope, prefix, "", va( "", templateArgs.c_str() ), NULL, 0 ); - } - } - - } else if ( token == "idInterpolateAccelDecelLinear" ) { - - const idInterpolateAccelDecelLinear *interpolate = ((idInterpolateAccelDecelLinear *)varPtr); - Write( varName, varType, scope, prefix, ".startTime", idStr( interpolate->GetStartTime() ).c_str(), &interpolate->startTime, sizeof( interpolate->startTime ) ); - Write( varName, varType, scope, prefix, ".accelTime", idStr( interpolate->GetAcceleration() ).c_str(), &interpolate->accelTime, sizeof( interpolate->accelTime ) ); - Write( varName, varType, scope, prefix, ".linearTime", idStr( interpolate->linearTime ).c_str(), &interpolate->linearTime, sizeof( interpolate->linearTime ) ); - Write( varName, varType, scope, prefix, ".decelTime", idStr( interpolate->GetDeceleration() ).c_str(), &interpolate->decelTime, sizeof( interpolate->decelTime ) ); - - if ( ParseTemplateArguments( typeSrc, templateArgs ) ) { - if ( templateArgs == "int" ) { - const idInterpolateAccelDecelLinear *interpolate = ((idInterpolateAccelDecelLinear *)varPtr); - Write( varName, varType, scope, prefix, ".startValue", idStr( interpolate->GetStartValue() ).c_str(), &interpolate->startValue, sizeof( interpolate->startValue ) ); - Write( varName, varType, scope, prefix, ".endValue", idStr( interpolate->GetEndValue() ).c_str(), &interpolate->endValue, sizeof( interpolate->endValue ) ); - typeSize = sizeof( idInterpolateAccelDecelLinear ); - } else if ( templateArgs == "float" ) { - const idInterpolateAccelDecelLinear *interpolate = ((idInterpolateAccelDecelLinear *)varPtr); - Write( varName, varType, scope, prefix, ".startValue", idStr( interpolate->GetStartValue() ).c_str(), &interpolate->startValue, sizeof( interpolate->startValue ) ); - Write( varName, varType, scope, prefix, ".endValue", idStr( interpolate->GetEndValue() ).c_str(), &interpolate->endValue, sizeof( interpolate->endValue ) ); - typeSize = sizeof( idInterpolateAccelDecelLinear ); - } else { - Write( varName, varType, scope, prefix, "", va( "", templateArgs.c_str() ), NULL, 0 ); - } - } - - } else if ( token == "idInterpolateAccelDecelSine" ) { - - const idInterpolateAccelDecelSine *interpolate = ((idInterpolateAccelDecelSine *)varPtr); - Write( varName, varType, scope, prefix, ".startTime", idStr( interpolate->GetStartTime() ).c_str(), &interpolate->startTime, sizeof( interpolate->startTime ) ); - Write( varName, varType, scope, prefix, ".accelTime", idStr( interpolate->GetAcceleration() ).c_str(), &interpolate->accelTime, sizeof( interpolate->accelTime ) ); - Write( varName, varType, scope, prefix, ".linearTime", idStr( interpolate->linearTime ).c_str(), &interpolate->linearTime, sizeof( interpolate->linearTime ) ); - Write( varName, varType, scope, prefix, ".decelTime", idStr( interpolate->GetDeceleration() ).c_str(), &interpolate->decelTime, sizeof( interpolate->decelTime ) ); - - if ( ParseTemplateArguments( typeSrc, templateArgs ) ) { - if ( templateArgs == "int" ) { - const idInterpolateAccelDecelSine *interpolate = ((idInterpolateAccelDecelSine *)varPtr); - Write( varName, varType, scope, prefix, ".startValue", idStr( interpolate->GetStartValue() ).c_str(), &interpolate->startValue, sizeof( interpolate->startValue ) ); - Write( varName, varType, scope, prefix, ".endValue", idStr( interpolate->GetEndValue() ).c_str(), &interpolate->endValue, sizeof( interpolate->endValue ) ); - typeSize = sizeof( idInterpolateAccelDecelSine ); - } else if ( templateArgs == "float" ) { - const idInterpolateAccelDecelSine *interpolate = ((idInterpolateAccelDecelSine *)varPtr); - Write( varName, varType, scope, prefix, ".startValue", idStr( interpolate->GetStartValue() ).c_str(), &interpolate->startValue, sizeof( interpolate->startValue ) ); - Write( varName, varType, scope, prefix, ".endValue", idStr( interpolate->GetEndValue() ).c_str(), &interpolate->endValue, sizeof( interpolate->endValue ) ); - typeSize = sizeof( idInterpolateAccelDecelSine ); - } else { - Write( varName, varType, scope, prefix, "", va( "", templateArgs.c_str() ), NULL, 0 ); - } - } - - } else if ( token == "idUserInterface" ) { - - typeSize = sizeof( idUserInterface ); - const idUserInterface *gui = ((idUserInterface *)varPtr); - Write( varName, varType, scope, prefix, "", gui->Name(), varPtr, sizeof( varPtr ) ); - - } else if ( token == "idRenderModel" ) { - - typeSize = sizeof( idRenderModel ); - const idRenderModel *model = ((idRenderModel *)varPtr); - Write( varName, varType, scope, prefix, "", model->Name(), varPtr, sizeof( varPtr ) ); - - } else if ( token == "qhandle_t" ) { - - typeSize = sizeof( int ); - Write( varName, varType, scope, prefix, "", va( "%d", *((int *)varPtr) ), varPtr, typeSize ); - - } else if ( token == "cmHandle_t" ) { - - typeSize = sizeof( int ); - Write( varName, varType, scope, prefix, "", va( "%d", *((int *)varPtr) ), varPtr, typeSize ); - - } else if ( token == "idEntityPtr" ) { - - typeSize = sizeof( idEntityPtr ); - - const idEntityPtr *entPtr = ((idEntityPtr *)varPtr); - if ( entPtr->GetEntity() ) { - idEntity *entity = entPtr->GetEntity(); - Write( varName, varType, scope, prefix, ".", va( "entity %d: \'%s\'", entity->entityNumber, entity->name.c_str() ), varPtr, typeSize ); - } else { - Write( varName, varType, scope, prefix, "", "", varPtr, typeSize ); - } - - } else if ( token == "idEntity::entityFlags_s" ) { - - const idEntity::entityFlags_s *flags = ((idEntity::entityFlags_s *)varPtr); - Write( varName, varType, scope, prefix, ".notarget", flags->notarget ? "true" : "false", NULL, 0 ); - Write( varName, varType, scope, prefix, ".noknockback", flags->noknockback ? "true" : "false", NULL, 0 ); - Write( varName, varType, scope, prefix, ".takedamage", flags->takedamage ? "true" : "false", NULL, 0 ); - Write( varName, varType, scope, prefix, ".hidden", flags->hidden ? "true" : "false", NULL, 0 ); - Write( varName, varType, scope, prefix, ".bindOrientated", flags->bindOrientated ? "true" : "false", NULL, 0 ); - Write( varName, varType, scope, prefix, ".solidForTeam", flags->solidForTeam ? "true" : "false", NULL, 0 ); - Write( varName, varType, scope, prefix, ".forcePhysicsUpdate", flags->forcePhysicsUpdate ? "true" : "false", NULL, 0 ); - Write( varName, varType, scope, prefix, ".selected", flags->selected ? "true" : "false", NULL, 0 ); - Write( varName, varType, scope, prefix, ".neverDormant", flags->neverDormant ? "true" : "false", NULL, 0 ); - Write( varName, varType, scope, prefix, ".isDormant", flags->isDormant ? "true" : "false", NULL, 0 ); - Write( varName, varType, scope, prefix, ".hasAwakened", flags->hasAwakened ? "true" : "false", NULL, 0 ); - Write( varName, varType, scope, prefix, ".networkSync", flags->networkSync ? "true" : "false", NULL, 0 ); - typeSize = sizeof( idEntity::entityFlags_s ); - - } else if ( token == "idScriptBool" ) { - - typeSize = sizeof( idScriptBool ); - - const idScriptBool *scriptBool = ((idScriptBool *)varPtr); - if ( scriptBool->IsLinked() ) { - Write( varName, varType, scope, prefix, "", ( *scriptBool != 0 ) ? "true" : "false", varPtr, typeSize ); - } else { - Write( varName, varType, scope, prefix, "", "", varPtr, typeSize ); - } - - } else { - - const classTypeInfo_t *classTypeInfo = FindClassInfo( scope + ( "::" + token ) ); - if ( classTypeInfo == NULL ) { - classTypeInfo = FindClassInfo( token ); - } - if ( classTypeInfo != NULL ) { - - typeSize = classTypeInfo->size; - - if ( !isPointer ) { - - char newPrefix[1024]; - idStr::snPrintf( newPrefix, sizeof( newPrefix ), "%s%s::%s.", prefix, scope, varName ); - WriteClass_r( varPtr, "", token, token, newPrefix, pointerDepth ); - - } else if ( token == "idAnim" ) { - - const idAnim *anim = ((idAnim*)varPtr); - Write( varName, varType, scope, prefix, "", anim->Name(), NULL, 0 ); - - } else if ( token == "idPhysics" ) { - - const idPhysics *physics = ((idPhysics*)varPtr); - Write( varName, varType, scope, prefix, "", physics->GetType()->classname, NULL, 0 ); - - } else if ( IsSubclassOf( token, "idEntity" ) ) { - - const idEntity *entity = ((idEntity*)varPtr); - Write( varName, varType, scope, prefix, "", va( "entity %d: \'%s\'", entity->entityNumber, entity->name.c_str() ), NULL, 0 ); - - } else if ( IsSubclassOf( token, "idDecl" ) ) { - - const idDecl *decl = ((idDecl *)varPtr); - Write( varName, varType, scope, prefix, "", decl->GetName(), NULL, 0 ); - - } else if ( pointerDepth == 0 && ( - token == "idAFBody" || - token == "idAFTree" || - token == "idClipModel" || - IsSubclassOf( token, "idAFConstraint" ) - ) ) { - - char newPrefix[1024]; - idStr::snPrintf( newPrefix, sizeof( newPrefix ), "%s%s::%s->", prefix, scope, varName ); - WriteClass_r( varPtr, "", token, token, newPrefix, pointerDepth + 1 ); - - } else { - - Write( varName, varType, scope, prefix, "", va( "", varType ), NULL, 0 ); - return -1; - } - } else { - const enumTypeInfo_t *enumTypeInfo = FindEnumInfo( scope + ( "::" + token ) ); - if ( enumTypeInfo == NULL ) { - enumTypeInfo = FindEnumInfo( token ); - } - if ( enumTypeInfo != NULL ) { - - typeSize = sizeof( int ); // NOTE: assuming sizeof( enum ) is sizeof( int ) - - for ( i = 0; enumTypeInfo->values[i].name != NULL; i++ ) { - if ( *((int *)varPtr) == enumTypeInfo->values[i].value ) { - break; - } - } - if ( enumTypeInfo->values[i].name != NULL ) { - Write( varName, varType, scope, prefix, "", enumTypeInfo->values[i].name, NULL, 0 ); - } else { - Write( varName, varType, scope, prefix, "", va( "%d", *((int *)varPtr) ), NULL, 0 ); - } - - } else { - Write( varName, varType, scope, prefix, "", va( "", varType ), NULL, 0 ); - return -1; - } - } - } - - i = 0; - do { - if ( *((unsigned int *)varPtr) == 0xcdcdcdcd ) { - common->Warning( "%s%s::%s%s uses uninitialized memory", prefix, scope, varName, "" ); - break; - } - } while( ++i < typeSize ); - - if ( isPointer ) { - return sizeof( void * ); - } - return typeSize; -} - -/* -================ -idTypeInfoTools::WriteClass_r -================ -*/ -void idTypeInfoTools::WriteClass_r( const void *classPtr, const char *className, const char *classType, const char *scope, const char *prefix, const int pointerDepth ) { - int i; - - const classTypeInfo_t *classInfo = FindClassInfo( classType ); - if ( !classInfo ) { - return; - } - if ( *classInfo->superType != '\0' ) { - WriteClass_r( classPtr, className, classInfo->superType, scope, prefix, pointerDepth ); - } - - for ( i = 0; classInfo->variables[i].name != NULL; i++ ) { - const classVariableInfo_t &classVar = classInfo->variables[i]; - - void *varPtr = (void *) (((byte *)classPtr) + classVar.offset); - - WriteVariable_r( varPtr, classVar.name, classVar.type, classType, prefix, pointerDepth ); - } -} - -/* -================ -idTypeInfoTools::WriteGameState -================ -*/ -void idTypeInfoTools::WriteGameState( const char *fileName ) { - int i, num; - idFile *file; - - file = fileSystem->OpenFileWrite( fileName ); - if ( !file ) { - common->Warning( "couldn't open %s", fileName ); - return; - } - - fp = file; - Write = WriteGameStateVariable; //WriteVariable; - -#ifdef DUMP_GAMELOCAL - - file->WriteFloatString( "\ngameLocal {\n" ); - WriteClass_r( (void *)&gameLocal, "", "idGameLocal", "idGameLocal", "", 0 ); - file->WriteFloatString( "}\n" ); - -#endif - - for ( num = i = 0; i < gameLocal.num_entities; i++ ) { - idEntity *ent = gameLocal.entities[i]; - if ( ent == NULL ) { - continue; - } - file->WriteFloatString( "\nentity %d %s {\n", i, ent->GetType()->classname ); - WriteClass_r( (void *)ent, "", ent->GetType()->classname, ent->GetType()->classname, "", 0 ); - file->WriteFloatString( "}\n" ); - num++; - } - - fileSystem->CloseFile( file ); - - common->Printf( "%d entities written\n", num ); -} - -/* -================ -idTypeInfoTools::CompareGameState -================ -*/ -void idTypeInfoTools::CompareGameState( const char *fileName ) { - int entityNum; - idToken token; - - src = new idLexer(); - src->SetFlags( LEXFL_NOSTRINGESCAPECHARS ); - - if ( !src->LoadFile( fileName ) ) { - common->Warning( "couldn't load %s", fileName ); - delete src; - src = NULL; - return; - } - - fp = NULL; - Write = VerifyVariable; - -#ifdef DUMP_GAMELOCAL - - if ( !src->ExpectTokenString( "gameLocal" ) || !src->ExpectTokenString( "{" ) ) { - delete src; - src = NULL; - return; - } - - WriteClass_r( (void *)&gameLocal, "", "idGameLocal", "idGameLocal", "", 0 ); - - if ( !src->ExpectTokenString( "}" ) ) { - delete src; - src = NULL; - return; - } - -#endif - - while( src->ReadToken( &token ) ) { - if ( token != "entity" ) { - break; - } - if ( !src->ExpectTokenType( TT_NUMBER, TT_INTEGER, &token ) ) { - break; - } - - entityNum = token.GetIntValue(); - - if ( entityNum < 0 || entityNum >= gameLocal.num_entities ) { - src->Warning( "entity number %d out of range", entityNum ); - break; - } - - typeError = false; - - idEntity *ent = gameLocal.entities[entityNum]; - if ( !ent ) { - src->Warning( "entity %d is not spawned", entityNum ); - src->SkipBracedSection( true ); - continue; - } - - if ( !src->ExpectTokenType( TT_NAME, 0, &token ) ) { - break; - } - - if ( token.Cmp( ent->GetType()->classname ) != 0 ) { - src->Warning( "entity %d has wrong type", entityNum ); - src->SkipBracedSection( true ); - continue; - } - - if ( !src->ExpectTokenString( "{" ) ) { - src->Warning( "entity %d missing leading {", entityNum ); - break; - } - - WriteClass_r( (void *)ent, "", ent->GetType()->classname, ent->GetType()->classname, "", 0 ); - - if ( !src->SkipBracedSection( false ) ) { - src->Warning( "entity %d missing trailing }", entityNum ); - break; - } - } - - delete src; - src = NULL; -} - -/* -================ -WriteGameState_f -================ -*/ -void WriteGameState_f( const idCmdArgs &args ) { - idStr fileName; - - if ( args.Argc() > 1 ) { - fileName = args.Argv(1); - } else { - fileName = "GameState.txt"; - } - fileName.SetFileExtension( "gameState.txt" ); - - idTypeInfoTools::WriteGameState( fileName ); -} - -/* -================ -CompareGameState_f -================ -*/ -void CompareGameState_f( const idCmdArgs &args ) { - idStr fileName; - - if ( args.Argc() > 1 ) { - fileName = args.Argv(1); - } else { - fileName = "GameState.txt"; - } - fileName.SetFileExtension( "gameState.txt" ); - - idTypeInfoTools::CompareGameState( fileName ); -} - -/* -================ -TestSaveGame_f -================ -*/ -void TestSaveGame_f( const idCmdArgs &args ) { - idStr name; - - if ( args.Argc() <= 1 ) { - gameLocal.Printf( "testSaveGame \n" ); - return; - } - - name = args.Argv( 1 ); - - try { - cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "map %s", name.c_str() ) ); - name.Replace( "\\", "_" ); - name.Replace( "/", "_" ); - cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "saveGame test_%s", name.c_str() ) ); - cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "loadGame test_%s", name.c_str() ) ); - } - catch( idException & ) { - // an ERR_DROP was thrown - } - cmdSystem->BufferCommandText( CMD_EXEC_NOW, "quit" ); -} - -/* -================ -WriteTypeToFile -================ -*/ -void WriteTypeToFile( idFile *fp, const void *typePtr, const char *typeName ) { - idTypeInfoTools::WriteTypeToFile( fp, typePtr, typeName ); -} - -/* -================ -PrintType -================ -*/ -void PrintType( const void *typePtr, const char *typeName ) { - idTypeInfoTools::PrintType( typePtr, typeName ); -} - -/* -================ -InitTypeVariables -================ -*/ -void InitTypeVariables( const void *typePtr, const char *typeName, int value ) { - idTypeInfoTools::InitTypeVariables( typePtr, typeName, value ); -} - -/* -================ -ListTypeInfo_f -================ -*/ -int SortTypeInfoByName( const int *a, const int *b ) { - return idStr::Icmp( classTypeInfo[*a].typeName, classTypeInfo[*b].typeName ); -} - -int SortTypeInfoBySize( const int *a, const int *b ) { - if ( classTypeInfo[*a].size < classTypeInfo[*b].size ) { - return -1; - } - if ( classTypeInfo[*a].size > classTypeInfo[*b].size ) { - return 1; - } - return 0; -} - -void ListTypeInfo_f( const idCmdArgs &args ) { - int i, j; - idList index; - - common->Printf( "%-32s : %-32s size (B)\n", "type name", "super type name" ); - for ( i = 0; classTypeInfo[i].typeName != NULL; i++ ) { - index.Append( i ); - } - - if ( args.Argc() > 1 && idStr::Icmp( args.Argv( 1 ), "size" ) == 0 ) { - index.Sort( SortTypeInfoBySize ); - } else { - index.Sort( SortTypeInfoByName ); - } - - for ( i = 0; classTypeInfo[i].typeName != NULL; i++ ) { - j = index[i]; - common->Printf( "%-32s : %-32s %d\n", classTypeInfo[j].typeName, classTypeInfo[j].superType, classTypeInfo[j].size ); - } -} diff --git a/d3xp/gamesys/TypeInfo.h b/d3xp/gamesys/TypeInfo.h deleted file mode 100644 index b9efa2db..00000000 --- a/d3xp/gamesys/TypeInfo.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __SYS_TYPEINFO_H__ -#define __SYS_TYPEINFO_H__ - -#include "idlib/CmdArgs.h" - -class idFile; - -/* -=================================================================================== - - Game Type Info - -=================================================================================== -*/ - -const char * GetTypeVariableName( const char *typeName, int offset ); - -void PrintType( const void *typePtr, const char *typeName ); -void WriteTypeToFile( idFile *fp, const void *typePtr, const char *typeName ); -void InitTypeVariables( const void *typePtr, const char *typeName, int value ); - -void ListTypeInfo_f( const idCmdArgs &args ); - -void WriteGameState_f( const idCmdArgs &args ); -void CompareGameState_f( const idCmdArgs &args ); -void TestSaveGame_f( const idCmdArgs &args ); - -#endif /* !__SYS_TYPEINFO_H__ */ diff --git a/d3xp/physics/Clip.cpp b/d3xp/physics/Clip.cpp deleted file mode 100644 index f1fb1236..00000000 --- a/d3xp/physics/Clip.cpp +++ /dev/null @@ -1,1674 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "gamesys/SaveGame.h" -#include "Entity.h" -#include "Game_local.h" - -#include "physics/Clip.h" - -#define MAX_SECTOR_DEPTH 12 -#define MAX_SECTORS ((1<<(MAX_SECTOR_DEPTH+1))-1) - -typedef struct clipSector_s { - int axis; // -1 = leaf node - float dist; - struct clipSector_s * children[2]; - struct clipLink_s * clipLinks; -} clipSector_t; - -typedef struct clipLink_s { - idClipModel * clipModel; - struct clipSector_s * sector; - struct clipLink_s * prevInSector; - struct clipLink_s * nextInSector; - struct clipLink_s * nextLink; -} clipLink_t; - -typedef struct trmCache_s { - idTraceModel trm; - int refCount; - float volume; - idVec3 centerOfMass; - idMat3 inertiaTensor; -} trmCache_t; - -idVec3 vec3_boxEpsilon( CM_BOX_EPSILON, CM_BOX_EPSILON, CM_BOX_EPSILON ); - -idBlockAlloc clipLinkAllocator; - - -/* -=============================================================== - - idClipModel trace model cache - -=============================================================== -*/ - -static idList traceModelCache; -static idHashIndex traceModelHash; - -/* -=============== -idClipModel::ClearTraceModelCache -=============== -*/ -void idClipModel::ClearTraceModelCache( void ) { - traceModelCache.DeleteContents( true ); - traceModelHash.Free(); -} - -/* -=============== -idClipModel::TraceModelCacheSize -=============== -*/ -int idClipModel::TraceModelCacheSize( void ) { - return traceModelCache.Num() * sizeof( idTraceModel ); -} - -/* -=============== -idClipModel::AllocTraceModel -=============== -*/ -int idClipModel::AllocTraceModel( const idTraceModel &trm ) { - int i, hashKey, traceModelIndex; - trmCache_t *entry; - - hashKey = GetTraceModelHashKey( trm ); - for ( i = traceModelHash.First( hashKey ); i >= 0; i = traceModelHash.Next( i ) ) { - if ( traceModelCache[i]->trm == trm ) { - traceModelCache[i]->refCount++; - return i; - } - } - - entry = new trmCache_t; - entry->trm = trm; - entry->trm.GetMassProperties( 1.0f, entry->volume, entry->centerOfMass, entry->inertiaTensor ); - entry->refCount = 1; - - traceModelIndex = traceModelCache.Append( entry ); - traceModelHash.Add( hashKey, traceModelIndex ); - return traceModelIndex; -} - -/* -=============== -idClipModel::FreeTraceModel -=============== -*/ -void idClipModel::FreeTraceModel( int traceModelIndex ) { - if ( traceModelIndex < 0 || traceModelIndex >= traceModelCache.Num() || traceModelCache[traceModelIndex]->refCount <= 0 ) { - gameLocal.Warning( "idClipModel::FreeTraceModel: tried to free uncached trace model" ); - return; - } - traceModelCache[traceModelIndex]->refCount--; -} - -/* -=============== -idClipModel::GetCachedTraceModel -=============== -*/ -idTraceModel *idClipModel::GetCachedTraceModel( int traceModelIndex ) { - return &traceModelCache[traceModelIndex]->trm; -} - -/* -=============== -idClipModel::GetTraceModelHashKey -=============== -*/ -int idClipModel::GetTraceModelHashKey( const idTraceModel &trm ) { - const idVec3 &v = trm.bounds[0]; - return ( trm.type << 8 ) ^ ( trm.numVerts << 4 ) ^ ( trm.numEdges << 2 ) ^ ( trm.numPolys << 0 ) ^ idMath::FloatHash( v.ToFloatPtr(), v.GetDimension() ); -} - -/* -=============== -idClipModel::SaveTraceModels -=============== -*/ -void idClipModel::SaveTraceModels( idSaveGame *savefile ) { - int i; - - savefile->WriteInt( traceModelCache.Num() ); - for ( i = 0; i < traceModelCache.Num(); i++ ) { - trmCache_t *entry = traceModelCache[i]; - - savefile->WriteTraceModel( entry->trm ); - savefile->WriteFloat( entry->volume ); - savefile->WriteVec3( entry->centerOfMass ); - savefile->WriteMat3( entry->inertiaTensor ); - } -} - -/* -=============== -idClipModel::RestoreTraceModels -=============== -*/ -void idClipModel::RestoreTraceModels( idRestoreGame *savefile ) { - int i, num; - - ClearTraceModelCache(); - - savefile->ReadInt( num ); - traceModelCache.SetNum( num ); - - for ( i = 0; i < num; i++ ) { - trmCache_t *entry = new trmCache_t; - - savefile->ReadTraceModel( entry->trm ); - - savefile->ReadFloat( entry->volume ); - savefile->ReadVec3( entry->centerOfMass ); - savefile->ReadMat3( entry->inertiaTensor ); - entry->refCount = 0; - - traceModelCache[i] = entry; - traceModelHash.Add( GetTraceModelHashKey( entry->trm ), i ); - } -} - - -/* -=============================================================== - - idClipModel - -=============================================================== -*/ - -/* -================ -idClipModel::LoadModel -================ -*/ -bool idClipModel::LoadModel( const char *name ) { - renderModelHandle = -1; - if ( traceModelIndex != -1 ) { - FreeTraceModel( traceModelIndex ); - traceModelIndex = -1; - } - collisionModelHandle = collisionModelManager->LoadModel( name, false ); - if ( collisionModelHandle ) { - collisionModelManager->GetModelBounds( collisionModelHandle, bounds ); - collisionModelManager->GetModelContents( collisionModelHandle, contents ); - return true; - } else { - bounds.Zero(); - return false; - } -} - -/* -================ -idClipModel::LoadModel -================ -*/ -void idClipModel::LoadModel( const idTraceModel &trm ) { - collisionModelHandle = 0; - renderModelHandle = -1; - if ( traceModelIndex != -1 ) { - FreeTraceModel( traceModelIndex ); - } - traceModelIndex = AllocTraceModel( trm ); - bounds = trm.bounds; -} - -/* -================ -idClipModel::LoadModel -================ -*/ -void idClipModel::LoadModel( const int renderModelHandle ) { - collisionModelHandle = 0; - this->renderModelHandle = renderModelHandle; - if ( renderModelHandle != -1 ) { - const renderEntity_t *renderEntity = gameRenderWorld->GetRenderEntity( renderModelHandle ); - if ( renderEntity ) { - bounds = renderEntity->bounds; - } - } - if ( traceModelIndex != -1 ) { - FreeTraceModel( traceModelIndex ); - traceModelIndex = -1; - } -} - -/* -================ -idClipModel::Init -================ -*/ -void idClipModel::Init( void ) { - enabled = true; - entity = NULL; - id = 0; - owner = NULL; - origin.Zero(); - axis.Identity(); - bounds.Zero(); - absBounds.Zero(); - material = NULL; - contents = CONTENTS_BODY; - collisionModelHandle = 0; - renderModelHandle = -1; - traceModelIndex = -1; - clipLinks = NULL; - touchCount = -1; -} - -/* -================ -idClipModel::idClipModel -================ -*/ -idClipModel::idClipModel( void ) { - Init(); -} - -/* -================ -idClipModel::idClipModel -================ -*/ -idClipModel::idClipModel( const char *name ) { - Init(); - LoadModel( name ); -} - -/* -================ -idClipModel::idClipModel -================ -*/ -idClipModel::idClipModel( const idTraceModel &trm ) { - Init(); - LoadModel( trm ); -} - -/* -================ -idClipModel::idClipModel -================ -*/ -idClipModel::idClipModel( const int renderModelHandle ) { - Init(); - contents = CONTENTS_RENDERMODEL; - LoadModel( renderModelHandle ); -} - -/* -================ -idClipModel::idClipModel -================ -*/ -idClipModel::idClipModel( const idClipModel *model ) { - enabled = model->enabled; - entity = model->entity; - id = model->id; - owner = model->owner; - origin = model->origin; - axis = model->axis; - bounds = model->bounds; - absBounds = model->absBounds; - material = model->material; - contents = model->contents; - collisionModelHandle = model->collisionModelHandle; - traceModelIndex = -1; - if ( model->traceModelIndex != -1 ) { - LoadModel( *GetCachedTraceModel( model->traceModelIndex ) ); - } - renderModelHandle = model->renderModelHandle; - clipLinks = NULL; - touchCount = -1; -} - -/* -================ -idClipModel::~idClipModel -================ -*/ -idClipModel::~idClipModel( void ) { - // make sure the clip model is no longer linked - Unlink(); - if ( traceModelIndex != -1 ) { - FreeTraceModel( traceModelIndex ); - } -} - -/* -================ -idClipModel::Save -================ -*/ -void idClipModel::Save( idSaveGame *savefile ) const { - savefile->WriteBool( enabled ); - savefile->WriteObject( entity ); - savefile->WriteInt( id ); - savefile->WriteObject( owner ); - savefile->WriteVec3( origin ); - savefile->WriteMat3( axis ); - savefile->WriteBounds( bounds ); - savefile->WriteBounds( absBounds ); - savefile->WriteMaterial( material ); - savefile->WriteInt( contents ); - if ( collisionModelHandle >= 0 ) { - savefile->WriteString( collisionModelManager->GetModelName( collisionModelHandle ) ); - } else { - savefile->WriteString( "" ); - } - savefile->WriteInt( traceModelIndex ); - savefile->WriteInt( renderModelHandle ); - savefile->WriteBool( clipLinks != NULL ); - savefile->WriteInt( touchCount ); -} - -/* -================ -idClipModel::Restore -================ -*/ -void idClipModel::Restore( idRestoreGame *savefile ) { - idStr collisionModelName; - bool linked; - - savefile->ReadBool( enabled ); - savefile->ReadObject( reinterpret_cast( entity ) ); - savefile->ReadInt( id ); - savefile->ReadObject( reinterpret_cast( owner ) ); - savefile->ReadVec3( origin ); - savefile->ReadMat3( axis ); - savefile->ReadBounds( bounds ); - savefile->ReadBounds( absBounds ); - savefile->ReadMaterial( material ); - savefile->ReadInt( contents ); - savefile->ReadString( collisionModelName ); - if ( collisionModelName.Length() ) { - collisionModelHandle = collisionModelManager->LoadModel( collisionModelName, false ); - } else { - collisionModelHandle = -1; - } - savefile->ReadInt( traceModelIndex ); - if ( traceModelIndex >= 0 ) { - traceModelCache[traceModelIndex]->refCount++; - } - savefile->ReadInt( renderModelHandle ); - savefile->ReadBool( linked ); - savefile->ReadInt( touchCount ); - - // the render model will be set when the clip model is linked - renderModelHandle = -1; - clipLinks = NULL; - touchCount = -1; - - if ( linked ) { - Link( gameLocal.clip, entity, id, origin, axis, renderModelHandle ); - } -} - -/* -================ -idClipModel::SetPosition -================ -*/ -void idClipModel::SetPosition( const idVec3 &newOrigin, const idMat3 &newAxis ) { - if ( clipLinks ) { - Unlink(); // unlink from old position - } - origin = newOrigin; - axis = newAxis; -} - -/* -================ -idClipModel::Handle -================ -*/ -cmHandle_t idClipModel::Handle( void ) const { - assert( renderModelHandle == -1 ); - if ( collisionModelHandle ) { - return collisionModelHandle; - } else if ( traceModelIndex != -1 ) { - return collisionModelManager->SetupTrmModel( *GetCachedTraceModel( traceModelIndex ), material ); - } else { - // this happens in multiplayer on the combat models - gameLocal.Warning( "idClipModel::Handle: clip model %d on '%s' (%x) is not a collision or trace model", id, entity->name.c_str(), entity->entityNumber ); - return 0; - } -} - -/* -================ -idClipModel::GetMassProperties -================ -*/ -void idClipModel::GetMassProperties( const float density, float &mass, idVec3 ¢erOfMass, idMat3 &inertiaTensor ) const { - if ( traceModelIndex == -1 ) { - gameLocal.Error( "idClipModel::GetMassProperties: clip model %d on '%s' is not a trace model\n", id, entity->name.c_str() ); - } - - trmCache_t *entry = traceModelCache[traceModelIndex]; - mass = entry->volume * density; - centerOfMass = entry->centerOfMass; - inertiaTensor = density * entry->inertiaTensor; -} - -/* -=============== -idClipModel::Unlink -=============== -*/ -void idClipModel::Unlink( void ) { - clipLink_t *link; - - for ( link = clipLinks; link; link = clipLinks ) { - clipLinks = link->nextLink; - if ( link->prevInSector ) { - link->prevInSector->nextInSector = link->nextInSector; - } else { - link->sector->clipLinks = link->nextInSector; - } - if ( link->nextInSector ) { - link->nextInSector->prevInSector = link->prevInSector; - } - clipLinkAllocator.Free( link ); - } -} - -/* -=============== -idClipModel::Link_r -=============== -*/ -void idClipModel::Link_r( struct clipSector_s *node ) { - clipLink_t *link; - - while( node->axis != -1 ) { - if ( absBounds[0][node->axis] > node->dist ) { - node = node->children[0]; - } else if ( absBounds[1][node->axis] < node->dist ) { - node = node->children[1]; - } else { - Link_r( node->children[0] ); - node = node->children[1]; - } - } - - link = clipLinkAllocator.Alloc(); - link->clipModel = this; - link->sector = node; - link->nextInSector = node->clipLinks; - link->prevInSector = NULL; - if ( node->clipLinks ) { - node->clipLinks->prevInSector = link; - } - node->clipLinks = link; - link->nextLink = clipLinks; - clipLinks = link; -} - -/* -=============== -idClipModel::Link -=============== -*/ -void idClipModel::Link( idClip &clp ) { - - assert( idClipModel::entity ); - if ( !idClipModel::entity ) { - return; - } - - if ( clipLinks ) { - Unlink(); // unlink from old position - } - - if ( bounds.IsCleared() ) { - return; - } - - // set the abs box - if ( axis.IsRotated() ) { - // expand for rotation - absBounds.FromTransformedBounds( bounds, origin, axis ); - } else { - // normal - absBounds[0] = bounds[0] + origin; - absBounds[1] = bounds[1] + origin; - } - - // because movement is clipped an epsilon away from an actual edge, - // we must fully check even when bounding boxes don't quite touch - absBounds[0] -= vec3_boxEpsilon; - absBounds[1] += vec3_boxEpsilon; - - Link_r( clp.clipSectors ); -} - -/* -=============== -idClipModel::Link -=============== -*/ -void idClipModel::Link( idClip &clp, idEntity *ent, int newId, const idVec3 &newOrigin, const idMat3 &newAxis, int renderModelHandle ) { - - this->entity = ent; - this->id = newId; - this->origin = newOrigin; - this->axis = newAxis; - if ( renderModelHandle != -1 ) { - this->renderModelHandle = renderModelHandle; - const renderEntity_t *renderEntity = gameRenderWorld->GetRenderEntity( renderModelHandle ); - if ( renderEntity ) { - this->bounds = renderEntity->bounds; - } - } - this->Link( clp ); -} - -/* -============ -idClipModel::CheckModel -============ -*/ -cmHandle_t idClipModel::CheckModel( const char *name ) { - return collisionModelManager->LoadModel( name, false ); -} - - -/* -=============================================================== - - idClip - -=============================================================== -*/ - -/* -=============== -idClip::idClip -=============== -*/ -idClip::idClip( void ) { - numClipSectors = 0; - clipSectors = NULL; - worldBounds.Zero(); - numRotations = numTranslations = numMotions = numRenderModelTraces = numContents = numContacts = 0; -} - -/* -=============== -idClip::CreateClipSectors_r - -Builds a uniformly subdivided tree for the given world size -=============== -*/ -clipSector_t *idClip::CreateClipSectors_r( const int depth, const idBounds &bounds, idVec3 &maxSector ) { - int i; - clipSector_t *anode; - idVec3 size; - idBounds front, back; - - anode = &clipSectors[idClip::numClipSectors]; - idClip::numClipSectors++; - - if ( depth == MAX_SECTOR_DEPTH ) { - anode->axis = -1; - anode->children[0] = anode->children[1] = NULL; - - for ( i = 0; i < 3; i++ ) { - if ( bounds[1][i] - bounds[0][i] > maxSector[i] ) { - maxSector[i] = bounds[1][i] - bounds[0][i]; - } - } - return anode; - } - - size = bounds[1] - bounds[0]; - if ( size[0] >= size[1] && size[0] >= size[2] ) { - anode->axis = 0; - } else if ( size[1] >= size[0] && size[1] >= size[2] ) { - anode->axis = 1; - } else { - anode->axis = 2; - } - - anode->dist = 0.5f * ( bounds[1][anode->axis] + bounds[0][anode->axis] ); - - front = bounds; - back = bounds; - - front[0][anode->axis] = back[1][anode->axis] = anode->dist; - - anode->children[0] = CreateClipSectors_r( depth+1, front, maxSector ); - anode->children[1] = CreateClipSectors_r( depth+1, back, maxSector ); - - return anode; -} - -/* -=============== -idClip::Init -=============== -*/ -void idClip::Init( void ) { - cmHandle_t h; - idVec3 size, maxSector = vec3_origin; - - // clear clip sectors - clipSectors = new clipSector_t[MAX_SECTORS]; - memset( clipSectors, 0, MAX_SECTORS * sizeof( clipSector_t ) ); - numClipSectors = 0; - touchCount = -1; - // get world map bounds - h = collisionModelManager->LoadModel( "worldMap", false ); - collisionModelManager->GetModelBounds( h, worldBounds ); - // create world sectors - CreateClipSectors_r( 0, worldBounds, maxSector ); - - size = worldBounds[1] - worldBounds[0]; - gameLocal.Printf( "map bounds are (%1.1f, %1.1f, %1.1f)\n", size[0], size[1], size[2] ); - gameLocal.Printf( "max clip sector is (%1.1f, %1.1f, %1.1f)\n", maxSector[0], maxSector[1], maxSector[2] ); - - // initialize a default clip model - defaultClipModel.LoadModel( idTraceModel( idBounds( idVec3( 0, 0, 0 ) ).Expand( 8 ) ) ); - - // set counters to zero - numRotations = numTranslations = numMotions = numRenderModelTraces = numContents = numContacts = 0; -} - -/* -=============== -idClip::Shutdown -=============== -*/ -void idClip::Shutdown( void ) { - delete[] clipSectors; - clipSectors = NULL; - - // free the trace model used for the temporaryClipModel - if ( temporaryClipModel.traceModelIndex != -1 ) { - idClipModel::FreeTraceModel( temporaryClipModel.traceModelIndex ); - temporaryClipModel.traceModelIndex = -1; - } - - // free the trace model used for the defaultClipModel - if ( defaultClipModel.traceModelIndex != -1 ) { - idClipModel::FreeTraceModel( defaultClipModel.traceModelIndex ); - defaultClipModel.traceModelIndex = -1; - } - - clipLinkAllocator.Shutdown(); -} - -/* -==================== -idClip::ClipModelsTouchingBounds_r -==================== -*/ -typedef struct listParms_s { - idBounds bounds; - int contentMask; - idClipModel ** list; - int count; - int maxCount; -} listParms_t; - -void idClip::ClipModelsTouchingBounds_r( const struct clipSector_s *node, listParms_t &parms ) const { - - while( node->axis != -1 ) { - if ( parms.bounds[0][node->axis] > node->dist ) { - node = node->children[0]; - } else if ( parms.bounds[1][node->axis] < node->dist ) { - node = node->children[1]; - } else { - ClipModelsTouchingBounds_r( node->children[0], parms ); - node = node->children[1]; - } - } - - for ( clipLink_t *link = node->clipLinks; link; link = link->nextInSector ) { - idClipModel *check = link->clipModel; - - // if the clip model is enabled - if ( !check->enabled ) { - continue; - } - - // avoid duplicates in the list - if ( check->touchCount == touchCount ) { - continue; - } - - // if the clip model does not have any contents we are looking for - if ( !( check->contents & parms.contentMask ) ) { - continue; - } - - // if the bounds really do overlap - if ( check->absBounds[0][0] > parms.bounds[1][0] || - check->absBounds[1][0] < parms.bounds[0][0] || - check->absBounds[0][1] > parms.bounds[1][1] || - check->absBounds[1][1] < parms.bounds[0][1] || - check->absBounds[0][2] > parms.bounds[1][2] || - check->absBounds[1][2] < parms.bounds[0][2] ) { - continue; - } - - if ( parms.count >= parms.maxCount ) { - gameLocal.Warning( "idClip::ClipModelsTouchingBounds_r: max count" ); - return; - } - - check->touchCount = touchCount; - parms.list[parms.count] = check; - parms.count++; - } -} - -/* -================ -idClip::ClipModelsTouchingBounds -================ -*/ -int idClip::ClipModelsTouchingBounds( const idBounds &bounds, int contentMask, idClipModel **clipModelList, int maxCount ) const { - listParms_t parms; - - if ( bounds[0][0] > bounds[1][0] || - bounds[0][1] > bounds[1][1] || - bounds[0][2] > bounds[1][2] ) { - // we should not go through the tree for degenerate or backwards bounds - assert( false ); - return 0; - } - - parms.bounds[0] = bounds[0] - vec3_boxEpsilon; - parms.bounds[1] = bounds[1] + vec3_boxEpsilon; - parms.contentMask = contentMask; - parms.list = clipModelList; - parms.count = 0; - parms.maxCount = maxCount; - - touchCount++; - ClipModelsTouchingBounds_r( clipSectors, parms ); - - return parms.count; -} - -/* -================ -idClip::EntitiesTouchingBounds -================ -*/ -int idClip::EntitiesTouchingBounds( const idBounds &bounds, int contentMask, idEntity **entityList, int maxCount ) const { - idClipModel *clipModelList[MAX_GENTITIES]; - int i, j, count, entCount; - - count = idClip::ClipModelsTouchingBounds( bounds, contentMask, clipModelList, MAX_GENTITIES ); - entCount = 0; - for ( i = 0; i < count; i++ ) { - // entity could already be in the list because an entity can use multiple clip models - for ( j = 0; j < entCount; j++ ) { - if ( entityList[j] == clipModelList[i]->entity ) { - break; - } - } - if ( j >= entCount ) { - if ( entCount >= maxCount ) { - gameLocal.Warning( "idClip::EntitiesTouchingBounds: max count" ); - return entCount; - } - entityList[entCount] = clipModelList[i]->entity; - entCount++; - } - } - - return entCount; -} - -/* -==================== -idClip::GetTraceClipModels - - an ent will be excluded from testing if: - cm->entity == passEntity ( don't clip against the pass entity ) - cm->entity == passOwner ( missiles don't clip with owner ) - cm->owner == passEntity ( don't interact with your own missiles ) - cm->owner == passOwner ( don't interact with other missiles from same owner ) -==================== -*/ -int idClip::GetTraceClipModels( const idBounds &bounds, int contentMask, const idEntity *passEntity, idClipModel **clipModelList ) const { - int i, num; - idClipModel *cm; - idEntity *passOwner; - - num = ClipModelsTouchingBounds( bounds, contentMask, clipModelList, MAX_GENTITIES ); - - if ( !passEntity ) { - return num; - } - - if ( passEntity->GetPhysics()->GetNumClipModels() > 0 ) { - passOwner = passEntity->GetPhysics()->GetClipModel()->GetOwner(); - } else { - passOwner = NULL; - } - - for ( i = 0; i < num; i++ ) { - - cm = clipModelList[i]; - - // check if we should ignore this entity - if ( cm->entity == passEntity ) { - clipModelList[i] = NULL; // don't clip against the pass entity - } else if ( cm->entity == passOwner ) { - clipModelList[i] = NULL; // missiles don't clip with their owner - } else if ( cm->owner ) { - if ( cm->owner == passEntity ) { - clipModelList[i] = NULL; // don't clip against own missiles - } else if ( cm->owner == passOwner ) { - clipModelList[i] = NULL; // don't clip against other missiles from same owner - } - } - } - - return num; -} - -/* -============ -idClip::TraceRenderModel -============ -*/ -void idClip::TraceRenderModel( trace_t &trace, const idVec3 &start, const idVec3 &end, const float radius, const idMat3 &axis, idClipModel *touch ) const { - trace.fraction = 1.0f; - - // if the trace is passing through the bounds - if ( touch->absBounds.Expand( radius ).LineIntersection( start, end ) ) { - modelTrace_t modelTrace; - - // test with exact render model and modify trace_t structure accordingly - if ( gameRenderWorld->ModelTrace( modelTrace, touch->renderModelHandle, start, end, radius ) ) { - trace.fraction = modelTrace.fraction; - trace.endAxis = axis; - trace.endpos = modelTrace.point; - trace.c.normal = modelTrace.normal; - trace.c.dist = modelTrace.point * modelTrace.normal; - trace.c.point = modelTrace.point; - trace.c.type = CONTACT_TRMVERTEX; - trace.c.modelFeature = 0; - trace.c.trmFeature = 0; - trace.c.contents = modelTrace.material->GetContentFlags(); - trace.c.material = modelTrace.material; - // NOTE: trace.c.id will be the joint number - touch->id = JOINT_HANDLE_TO_CLIPMODEL_ID( modelTrace.jointNumber ); - } - } -} - -/* -============ -idClip::TraceModelForClipModel -============ -*/ -const idTraceModel *idClip::TraceModelForClipModel( const idClipModel *mdl ) const { - if ( !mdl ) { - return NULL; - } else { - if ( !mdl->IsTraceModel() ) { - if ( mdl->GetEntity() ) { - gameLocal.Error( "TraceModelForClipModel: clip model %d on '%s' is not a trace model\n", mdl->GetId(), mdl->GetEntity()->name.c_str() ); - } else { - gameLocal.Error( "TraceModelForClipModel: clip model %d is not a trace model\n", mdl->GetId() ); - } - } - return idClipModel::GetCachedTraceModel( mdl->traceModelIndex ); - } -} - -/* -============ -idClip::TestHugeTranslation -============ -*/ -ID_INLINE bool TestHugeTranslation( trace_t &results, const idClipModel *mdl, const idVec3 &start, const idVec3 &end, const idMat3 &trmAxis ) { - if ( mdl != NULL && ( end - start ).LengthSqr() > Square( CM_MAX_TRACE_DIST ) ) { - results.fraction = 0.0f; - results.endpos = start; - results.endAxis = trmAxis; - memset( &results.c, 0, sizeof( results.c ) ); - results.c.point = start; - - if ( mdl->GetEntity() ) { - gameLocal.Printf( "huge translation for clip model %d on entity %d '%s'\n", mdl->GetId(), mdl->GetEntity()->entityNumber, mdl->GetEntity()->GetName() ); - } else { - gameLocal.Printf( "huge translation for clip model %d\n", mdl->GetId() ); - } - gameLocal.Printf( " from (%.2f %.2f %.2f) to (%.2f %.2f %.2f)\n", start.x, start.y, start.z, end.x, end.y, end.z); - -#ifndef CTF - // May be important: This occurs in CTF when a player connects and spawns - // in the PVS of a player that has a flag that is spawning the idMoveableItem - // "nuggets". The error seems benign and the assert was getting in the way - // of testing. - assert( 0 ); -#endif - return true; - } - return false; -} - -/* -============ -idClip::TranslationEntities -============ -*/ -void idClip::TranslationEntities( trace_t &results, const idVec3 &start, const idVec3 &end, - const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity ) { - int i, num; - idClipModel *touch, *clipModelList[MAX_GENTITIES]; - idBounds traceBounds; - float radius; - trace_t trace; - const idTraceModel *trm; - - if ( TestHugeTranslation( results, mdl, start, end, trmAxis ) ) { - return; - } - - trm = TraceModelForClipModel( mdl ); - - results.fraction = 1.0f; - results.endpos = end; - results.endAxis = trmAxis; - - if ( !trm ) { - traceBounds.FromPointTranslation( start, end - start ); - radius = 0.0f; - } else { - traceBounds.FromBoundsTranslation( trm->bounds, start, trmAxis, end - start ); - radius = trm->bounds.GetRadius(); - } - - num = GetTraceClipModels( traceBounds, contentMask, passEntity, clipModelList ); - - for ( i = 0; i < num; i++ ) { - touch = clipModelList[i]; - - if ( !touch ) { - continue; - } - - if ( touch->renderModelHandle != -1 ) { - idClip::numRenderModelTraces++; - TraceRenderModel( trace, start, end, radius, trmAxis, touch ); - } else { - idClip::numTranslations++; - collisionModelManager->Translation( &trace, start, end, trm, trmAxis, contentMask, - touch->Handle(), touch->origin, touch->axis ); - } - - if ( trace.fraction < results.fraction ) { - results = trace; - results.c.entityNum = touch->entity->entityNumber; - results.c.id = touch->id; - if ( results.fraction == 0.0f ) { - break; - } - } - } -} - -/* -============ -idClip::Translation -============ -*/ -bool idClip::Translation( trace_t &results, const idVec3 &start, const idVec3 &end, - const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity ) { - int i, num; - idClipModel *touch, *clipModelList[MAX_GENTITIES]; - idBounds traceBounds; - float radius; - trace_t trace; - const idTraceModel *trm; - - if ( TestHugeTranslation( results, mdl, start, end, trmAxis ) ) { - return true; - } - - trm = TraceModelForClipModel( mdl ); - - if ( !passEntity || passEntity->entityNumber != ENTITYNUM_WORLD ) { - // test world - idClip::numTranslations++; - collisionModelManager->Translation( &results, start, end, trm, trmAxis, contentMask, 0, vec3_origin, mat3_default ); - results.c.entityNum = results.fraction != 1.0f ? ENTITYNUM_WORLD : ENTITYNUM_NONE; - if ( results.fraction == 0.0f ) { - return true; // blocked immediately by the world - } - } else { - memset( &results, 0, sizeof( results ) ); - results.fraction = 1.0f; - results.endpos = end; - results.endAxis = trmAxis; - } - - if ( !trm ) { - traceBounds.FromPointTranslation( start, results.endpos - start ); - radius = 0.0f; - } else { - traceBounds.FromBoundsTranslation( trm->bounds, start, trmAxis, results.endpos - start ); - radius = trm->bounds.GetRadius(); - } - - num = GetTraceClipModels( traceBounds, contentMask, passEntity, clipModelList ); - - for ( i = 0; i < num; i++ ) { - touch = clipModelList[i]; - - if ( !touch ) { - continue; - } - - if ( touch->renderModelHandle != -1 ) { - idClip::numRenderModelTraces++; - TraceRenderModel( trace, start, end, radius, trmAxis, touch ); - } else { - idClip::numTranslations++; - collisionModelManager->Translation( &trace, start, end, trm, trmAxis, contentMask, - touch->Handle(), touch->origin, touch->axis ); - } - - if ( trace.fraction < results.fraction ) { - results = trace; - results.c.entityNum = touch->entity->entityNumber; - results.c.id = touch->id; - if ( results.fraction == 0.0f ) { - break; - } - } - } - - return ( results.fraction < 1.0f ); -} - -/* -============ -idClip::Rotation -============ -*/ -bool idClip::Rotation( trace_t &results, const idVec3 &start, const idRotation &rotation, - const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity ) { - int i, num; - idClipModel *touch, *clipModelList[MAX_GENTITIES]; - idBounds traceBounds; - trace_t trace; - const idTraceModel *trm; - - trm = TraceModelForClipModel( mdl ); - - if ( !passEntity || passEntity->entityNumber != ENTITYNUM_WORLD ) { - // test world - idClip::numRotations++; - collisionModelManager->Rotation( &results, start, rotation, trm, trmAxis, contentMask, 0, vec3_origin, mat3_default ); - results.c.entityNum = results.fraction != 1.0f ? ENTITYNUM_WORLD : ENTITYNUM_NONE; - if ( results.fraction == 0.0f ) { - return true; // blocked immediately by the world - } - } else { - memset( &results, 0, sizeof( results ) ); - results.fraction = 1.0f; - results.endpos = start; - results.endAxis = trmAxis * rotation.ToMat3(); - } - - if ( !trm ) { - traceBounds.FromPointRotation( start, rotation ); - } else { - traceBounds.FromBoundsRotation( trm->bounds, start, trmAxis, rotation ); - } - - num = GetTraceClipModels( traceBounds, contentMask, passEntity, clipModelList ); - - for ( i = 0; i < num; i++ ) { - touch = clipModelList[i]; - - if ( !touch ) { - continue; - } - - // no rotational collision with render models - if ( touch->renderModelHandle != -1 ) { - continue; - } - - idClip::numRotations++; - collisionModelManager->Rotation( &trace, start, rotation, trm, trmAxis, contentMask, - touch->Handle(), touch->origin, touch->axis ); - - if ( trace.fraction < results.fraction ) { - results = trace; - results.c.entityNum = touch->entity->entityNumber; - results.c.id = touch->id; - if ( results.fraction == 0.0f ) { - break; - } - } - } - - return ( results.fraction < 1.0f ); -} - -/* -============ -idClip::Motion -============ -*/ -bool idClip::Motion( trace_t &results, const idVec3 &start, const idVec3 &end, const idRotation &rotation, - const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity ) { - int i, num; - idClipModel *touch, *clipModelList[MAX_GENTITIES]; - idVec3 dir, endPosition; - idBounds traceBounds; - float radius; - trace_t translationalTrace, rotationalTrace, trace; - idRotation endRotation; - const idTraceModel *trm; - - assert( rotation.GetOrigin() == start ); - - if ( TestHugeTranslation( results, mdl, start, end, trmAxis ) ) { - return true; - } - - if ( mdl != NULL && rotation.GetAngle() != 0.0f && rotation.GetVec() != vec3_origin ) { - // if no translation - if ( start == end ) { - // pure rotation - return Rotation( results, start, rotation, mdl, trmAxis, contentMask, passEntity ); - } - } else if ( start != end ) { - // pure translation - return Translation( results, start, end, mdl, trmAxis, contentMask, passEntity ); - } else { - // no motion - results.fraction = 1.0f; - results.endpos = start; - results.endAxis = trmAxis; - return false; - } - - trm = TraceModelForClipModel( mdl ); - - radius = trm->bounds.GetRadius(); - - if ( !passEntity || passEntity->entityNumber != ENTITYNUM_WORLD ) { - // translational collision with world - idClip::numTranslations++; - collisionModelManager->Translation( &translationalTrace, start, end, trm, trmAxis, contentMask, 0, vec3_origin, mat3_default ); - translationalTrace.c.entityNum = translationalTrace.fraction != 1.0f ? ENTITYNUM_WORLD : ENTITYNUM_NONE; - } else { - memset( &translationalTrace, 0, sizeof( translationalTrace ) ); - translationalTrace.fraction = 1.0f; - translationalTrace.endpos = end; - translationalTrace.endAxis = trmAxis; - } - - if ( translationalTrace.fraction != 0.0f ) { - - traceBounds.FromBoundsRotation( trm->bounds, start, trmAxis, rotation ); - dir = translationalTrace.endpos - start; - for ( i = 0; i < 3; i++ ) { - if ( dir[i] < 0.0f ) { - traceBounds[0][i] += dir[i]; - } - else { - traceBounds[1][i] += dir[i]; - } - } - - num = GetTraceClipModels( traceBounds, contentMask, passEntity, clipModelList ); - - for ( i = 0; i < num; i++ ) { - touch = clipModelList[i]; - - if ( !touch ) { - continue; - } - - if ( touch->renderModelHandle != -1 ) { - idClip::numRenderModelTraces++; - TraceRenderModel( trace, start, end, radius, trmAxis, touch ); - } else { - idClip::numTranslations++; - collisionModelManager->Translation( &trace, start, end, trm, trmAxis, contentMask, - touch->Handle(), touch->origin, touch->axis ); - } - - if ( trace.fraction < translationalTrace.fraction ) { - translationalTrace = trace; - translationalTrace.c.entityNum = touch->entity->entityNumber; - translationalTrace.c.id = touch->id; - if ( translationalTrace.fraction == 0.0f ) { - break; - } - } - } - } else { - num = -1; - } - - endPosition = translationalTrace.endpos; - endRotation = rotation; - endRotation.SetOrigin( endPosition ); - - if ( !passEntity || passEntity->entityNumber != ENTITYNUM_WORLD ) { - // rotational collision with world - idClip::numRotations++; - collisionModelManager->Rotation( &rotationalTrace, endPosition, endRotation, trm, trmAxis, contentMask, 0, vec3_origin, mat3_default ); - rotationalTrace.c.entityNum = rotationalTrace.fraction != 1.0f ? ENTITYNUM_WORLD : ENTITYNUM_NONE; - } else { - memset( &rotationalTrace, 0, sizeof( rotationalTrace ) ); - rotationalTrace.fraction = 1.0f; - rotationalTrace.endpos = endPosition; - rotationalTrace.endAxis = trmAxis * rotation.ToMat3(); - } - - if ( rotationalTrace.fraction != 0.0f ) { - - if ( num == -1 ) { - traceBounds.FromBoundsRotation( trm->bounds, endPosition, trmAxis, endRotation ); - num = GetTraceClipModels( traceBounds, contentMask, passEntity, clipModelList ); - } - - for ( i = 0; i < num; i++ ) { - touch = clipModelList[i]; - - if ( !touch ) { - continue; - } - - // no rotational collision detection with render models - if ( touch->renderModelHandle != -1 ) { - continue; - } - - idClip::numRotations++; - collisionModelManager->Rotation( &trace, endPosition, endRotation, trm, trmAxis, contentMask, - touch->Handle(), touch->origin, touch->axis ); - - if ( trace.fraction < rotationalTrace.fraction ) { - rotationalTrace = trace; - rotationalTrace.c.entityNum = touch->entity->entityNumber; - rotationalTrace.c.id = touch->id; - if ( rotationalTrace.fraction == 0.0f ) { - break; - } - } - } - } - - if ( rotationalTrace.fraction < 1.0f ) { - results = rotationalTrace; - } else { - results = translationalTrace; - results.endAxis = rotationalTrace.endAxis; - } - - results.fraction = Max( translationalTrace.fraction, rotationalTrace.fraction ); - - return ( translationalTrace.fraction < 1.0f || rotationalTrace.fraction < 1.0f ); -} - -/* -============ -idClip::Contacts -============ -*/ -int idClip::Contacts( contactInfo_t *contacts, const int maxContacts, const idVec3 &start, const idVec6 &dir, const float depth, - const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity ) { - int i, j, num, n, numContacts; - idClipModel *touch, *clipModelList[MAX_GENTITIES]; - idBounds traceBounds; - const idTraceModel *trm; - - trm = TraceModelForClipModel( mdl ); - - if ( !passEntity || passEntity->entityNumber != ENTITYNUM_WORLD ) { - // test world - idClip::numContacts++; - numContacts = collisionModelManager->Contacts( contacts, maxContacts, start, dir, depth, trm, trmAxis, contentMask, 0, vec3_origin, mat3_default ); - } else { - numContacts = 0; - } - - for ( i = 0; i < numContacts; i++ ) { - contacts[i].entityNum = ENTITYNUM_WORLD; - contacts[i].id = 0; - } - - if ( numContacts >= maxContacts ) { - return numContacts; - } - - if ( !trm ) { - traceBounds = idBounds( start ).Expand( depth ); - } else { - traceBounds.FromTransformedBounds( trm->bounds, start, trmAxis ); - traceBounds.ExpandSelf( depth ); - } - - num = GetTraceClipModels( traceBounds, contentMask, passEntity, clipModelList ); - - for ( i = 0; i < num; i++ ) { - touch = clipModelList[i]; - - if ( !touch ) { - continue; - } - - // no contacts with render models - if ( touch->renderModelHandle != -1 ) { - continue; - } - - idClip::numContacts++; - n = collisionModelManager->Contacts( contacts + numContacts, maxContacts - numContacts, - start, dir, depth, trm, trmAxis, contentMask, - touch->Handle(), touch->origin, touch->axis ); - - for ( j = 0; j < n; j++ ) { - contacts[numContacts].entityNum = touch->entity->entityNumber; - contacts[numContacts].id = touch->id; - numContacts++; - } - - if ( numContacts >= maxContacts ) { - break; - } - } - - return numContacts; -} - -/* -============ -idClip::Contents -============ -*/ -int idClip::Contents( const idVec3 &start, const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity ) { - int i, num, contents; - idClipModel *touch, *clipModelList[MAX_GENTITIES]; - idBounds traceBounds; - const idTraceModel *trm; - - trm = TraceModelForClipModel( mdl ); - - if ( !passEntity || passEntity->entityNumber != ENTITYNUM_WORLD ) { - // test world - idClip::numContents++; - contents = collisionModelManager->Contents( start, trm, trmAxis, contentMask, 0, vec3_origin, mat3_default ); - } else { - contents = 0; - } - - if ( !trm ) { - traceBounds[0] = start; - traceBounds[1] = start; - } else if ( trmAxis.IsRotated() ) { - traceBounds.FromTransformedBounds( trm->bounds, start, trmAxis ); - } else { - traceBounds[0] = trm->bounds[0] + start; - traceBounds[1] = trm->bounds[1] + start; - } - - num = GetTraceClipModels( traceBounds, -1, passEntity, clipModelList ); - - for ( i = 0; i < num; i++ ) { - touch = clipModelList[i]; - - if ( !touch ) { - continue; - } - - // no contents test with render models - if ( touch->renderModelHandle != -1 ) { - continue; - } - - // if the entity does not have any contents we are looking for - if ( ( touch->contents & contentMask ) == 0 ) { - continue; - } - - // if the entity has no new contents flags - if ( ( touch->contents & contents ) == touch->contents ) { - continue; - } - - idClip::numContents++; - if ( collisionModelManager->Contents( start, trm, trmAxis, contentMask, touch->Handle(), touch->origin, touch->axis ) ) { - contents |= ( touch->contents & contentMask ); - } - } - - return contents; -} - -/* -============ -idClip::TranslationModel -============ -*/ -void idClip::TranslationModel( trace_t &results, const idVec3 &start, const idVec3 &end, - const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, - cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis ) { - const idTraceModel *trm = TraceModelForClipModel( mdl ); - idClip::numTranslations++; - collisionModelManager->Translation( &results, start, end, trm, trmAxis, contentMask, model, modelOrigin, modelAxis ); -} - -/* -============ -idClip::RotationModel -============ -*/ -void idClip::RotationModel( trace_t &results, const idVec3 &start, const idRotation &rotation, - const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, - cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis ) { - const idTraceModel *trm = TraceModelForClipModel( mdl ); - idClip::numRotations++; - collisionModelManager->Rotation( &results, start, rotation, trm, trmAxis, contentMask, model, modelOrigin, modelAxis ); -} - -/* -============ -idClip::ContactsModel -============ -*/ -int idClip::ContactsModel( contactInfo_t *contacts, const int maxContacts, const idVec3 &start, const idVec6 &dir, const float depth, - const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, - cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis ) { - const idTraceModel *trm = TraceModelForClipModel( mdl ); - idClip::numContacts++; - return collisionModelManager->Contacts( contacts, maxContacts, start, dir, depth, trm, trmAxis, contentMask, model, modelOrigin, modelAxis ); -} - -/* -============ -idClip::ContentsModel -============ -*/ -int idClip::ContentsModel( const idVec3 &start, - const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, - cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis ) { - const idTraceModel *trm = TraceModelForClipModel( mdl ); - idClip::numContents++; - return collisionModelManager->Contents( start, trm, trmAxis, contentMask, model, modelOrigin, modelAxis ); -} - -/* -============ -idClip::GetModelContactFeature -============ -*/ -bool idClip::GetModelContactFeature( const contactInfo_t &contact, const idClipModel *clipModel, idFixedWinding &winding ) const { - int i; - cmHandle_t handle; - idVec3 start, end; - - handle = -1; - winding.Clear(); - - if ( clipModel == NULL ) { - handle = 0; - } else { - if ( clipModel->renderModelHandle != -1 ) { - winding += contact.point; - return true; - } else if ( clipModel->traceModelIndex != -1 ) { - handle = collisionModelManager->SetupTrmModel( *idClipModel::GetCachedTraceModel( clipModel->traceModelIndex ), clipModel->material ); - } else { - handle = clipModel->collisionModelHandle; - } - } - - // if contact with a collision model - if ( handle != -1 ) { - switch( contact.type ) { - case CONTACT_EDGE: { - // the model contact feature is a collision model edge - collisionModelManager->GetModelEdge( handle, contact.modelFeature, start, end ); - winding += start; - winding += end; - break; - } - case CONTACT_MODELVERTEX: { - // the model contact feature is a collision model vertex - collisionModelManager->GetModelVertex( handle, contact.modelFeature, start ); - winding += start; - break; - } - case CONTACT_TRMVERTEX: { - // the model contact feature is a collision model polygon - collisionModelManager->GetModelPolygon( handle, contact.modelFeature, winding ); - break; - } - } - } - - // transform the winding to world space - if ( clipModel ) { - for ( i = 0; i < winding.GetNumPoints(); i++ ) { - winding[i].ToVec3() *= clipModel->axis; - winding[i].ToVec3() += clipModel->origin; - } - } - - return true; -} - -/* -============ -idClip::PrintStatistics -============ -*/ -void idClip::PrintStatistics( void ) { - gameLocal.Printf( "t = %-3d, r = %-3d, m = %-3d, render = %-3d, contents = %-3d, contacts = %-3d\n", - numTranslations, numRotations, numMotions, numRenderModelTraces, numContents, numContacts ); - numRotations = numTranslations = numMotions = numRenderModelTraces = numContents = numContacts = 0; -} - -/* -============ -idClip::DrawClipModels -============ -*/ -void idClip::DrawClipModels( const idVec3 &eye, const float radius, const idEntity *passEntity ) { - int i, num; - idBounds bounds; - idClipModel *clipModelList[MAX_GENTITIES]; - idClipModel *clipModel; - - bounds = idBounds( eye ).Expand( radius ); - - num = idClip::ClipModelsTouchingBounds( bounds, -1, clipModelList, MAX_GENTITIES ); - - for ( i = 0; i < num; i++ ) { - clipModel = clipModelList[i]; - if ( clipModel->GetEntity() == passEntity ) { - continue; - } - if ( clipModel->renderModelHandle != -1 ) { - gameRenderWorld->DebugBounds( colorCyan, clipModel->GetAbsBounds() ); - } else { - collisionModelManager->DrawModel( clipModel->Handle(), clipModel->GetOrigin(), clipModel->GetAxis(), eye, radius ); - } - } -} - -/* -============ -idClip::DrawModelContactFeature -============ -*/ -bool idClip::DrawModelContactFeature( const contactInfo_t &contact, const idClipModel *clipModel, int lifetime ) const { - int i; - idMat3 axis; - idFixedWinding winding; - - if ( !GetModelContactFeature( contact, clipModel, winding ) ) { - return false; - } - - axis = contact.normal.ToMat3(); - - if ( winding.GetNumPoints() == 1 ) { - gameRenderWorld->DebugLine( colorCyan, winding[0].ToVec3(), winding[0].ToVec3() + 2.0f * axis[0], lifetime ); - gameRenderWorld->DebugLine( colorWhite, winding[0].ToVec3() - 1.0f * axis[1], winding[0].ToVec3() + 1.0f * axis[1], lifetime ); - gameRenderWorld->DebugLine( colorWhite, winding[0].ToVec3() - 1.0f * axis[2], winding[0].ToVec3() + 1.0f * axis[2], lifetime ); - } else { - for ( i = 0; i < winding.GetNumPoints(); i++ ) { - gameRenderWorld->DebugLine( colorCyan, winding[i].ToVec3(), winding[(i+1)%winding.GetNumPoints()].ToVec3(), lifetime ); - } - } - - axis[0] = -axis[0]; - axis[2] = -axis[2]; - gameRenderWorld->DrawText( contact.material->GetName(), winding.GetCenter() - 4.0f * axis[2], 0.1f, colorWhite, axis, 1, 5000 ); - - return true; -} diff --git a/d3xp/physics/Clip.h b/d3xp/physics/Clip.h deleted file mode 100644 index e6f0c205..00000000 --- a/d3xp/physics/Clip.h +++ /dev/null @@ -1,357 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __CLIP_H__ -#define __CLIP_H__ - -#include "idlib/geometry/TraceModel.h" -#include "cm/CollisionModel.h" - -class idSaveGame; -class idRestoreGame; - -/* -=============================================================================== - - Handles collision detection with the world and between physics objects. - -=============================================================================== -*/ - -#define CLIPMODEL_ID_TO_JOINT_HANDLE( id ) ( ( id ) >= 0 ? INVALID_JOINT : ((jointHandle_t) ( -1 - id )) ) -#define JOINT_HANDLE_TO_CLIPMODEL_ID( id ) ( -1 - id ) - -class idClip; -class idEntity; - - -//=============================================================== -// -// idClipModel -// -//=============================================================== - -class idClipModel { - - friend class idClip; - -public: - idClipModel( void ); - explicit idClipModel( const char *name ); - explicit idClipModel( const idTraceModel &trm ); - explicit idClipModel( const int renderModelHandle ); - explicit idClipModel( const idClipModel *model ); - ~idClipModel( void ); - - bool LoadModel( const char *name ); - void LoadModel( const idTraceModel &trm ); - void LoadModel( const int renderModelHandle ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void Link( idClip &clp ); // must have been linked with an entity and id before - void Link( idClip &clp, idEntity *ent, int newId, const idVec3 &newOrigin, const idMat3 &newAxis, int renderModelHandle = -1 ); - void Unlink( void ); // unlink from sectors - void SetPosition( const idVec3 &newOrigin, const idMat3 &newAxis ); // unlinks the clip model - void Translate( const idVec3 &translation ); // unlinks the clip model - void Rotate( const idRotation &rotation ); // unlinks the clip model - void Enable( void ); // enable for clipping - void Disable( void ); // keep linked but disable for clipping - void SetMaterial( const idMaterial *m ); - const idMaterial * GetMaterial( void ) const; - void SetContents( int newContents ); // override contents - int GetContents( void ) const; - void SetEntity( idEntity *newEntity ); - idEntity * GetEntity( void ) const; - void SetId( int newId ); - int GetId( void ) const; - void SetOwner( idEntity *newOwner ); - idEntity * GetOwner( void ) const; - const idBounds & GetBounds( void ) const; - const idBounds & GetAbsBounds( void ) const; - const idVec3 & GetOrigin( void ) const; - const idMat3 & GetAxis( void ) const; - bool IsTraceModel( void ) const; // returns true if this is a trace model - bool IsRenderModel( void ) const; // returns true if this is a render model - bool IsLinked( void ) const; // returns true if the clip model is linked - bool IsEnabled( void ) const; // returns true if enabled for collision detection - bool IsEqual( const idTraceModel &trm ) const; - cmHandle_t Handle( void ) const; // returns handle used to collide vs this model - const idTraceModel * GetTraceModel( void ) const; - void GetMassProperties( const float density, float &mass, idVec3 ¢erOfMass, idMat3 &inertiaTensor ) const; - - static cmHandle_t CheckModel( const char *name ); - static void ClearTraceModelCache( void ); - static int TraceModelCacheSize( void ); - - static void SaveTraceModels( idSaveGame *savefile ); - static void RestoreTraceModels( idRestoreGame *savefile ); - -private: - bool enabled; // true if this clip model is used for clipping - idEntity * entity; // entity using this clip model - int id; // id for entities that use multiple clip models - idEntity * owner; // owner of the entity that owns this clip model - idVec3 origin; // origin of clip model - idMat3 axis; // orientation of clip model - idBounds bounds; // bounds - idBounds absBounds; // absolute bounds - const idMaterial * material; // material for trace models - int contents; // all contents ored together - cmHandle_t collisionModelHandle; // handle to collision model - int traceModelIndex; // trace model used for collision detection - int renderModelHandle; // render model def handle - - struct clipLink_s * clipLinks; // links into sectors - int touchCount; - - void Init( void ); // initialize - void Link_r( struct clipSector_s *node ); - - static int AllocTraceModel( const idTraceModel &trm ); - static void FreeTraceModel( int traceModelIndex ); - static idTraceModel * GetCachedTraceModel( int traceModelIndex ); - static int GetTraceModelHashKey( const idTraceModel &trm ); -}; - - -ID_INLINE void idClipModel::Translate( const idVec3 &translation ) { - Unlink(); - origin += translation; -} - -ID_INLINE void idClipModel::Rotate( const idRotation &rotation ) { - Unlink(); - origin *= rotation; - axis *= rotation.ToMat3(); -} - -ID_INLINE void idClipModel::Enable( void ) { - enabled = true; -} - -ID_INLINE void idClipModel::Disable( void ) { - enabled = false; -} - -ID_INLINE void idClipModel::SetMaterial( const idMaterial *m ) { - material = m; -} - -ID_INLINE const idMaterial * idClipModel::GetMaterial( void ) const { - return material; -} - -ID_INLINE void idClipModel::SetContents( int newContents ) { - contents = newContents; -} - -ID_INLINE int idClipModel::GetContents( void ) const { - return contents; -} - -ID_INLINE void idClipModel::SetEntity( idEntity *newEntity ) { - entity = newEntity; -} - -ID_INLINE idEntity *idClipModel::GetEntity( void ) const { - return entity; -} - -ID_INLINE void idClipModel::SetId( int newId ) { - id = newId; -} - -ID_INLINE int idClipModel::GetId( void ) const { - return id; -} - -ID_INLINE void idClipModel::SetOwner( idEntity *newOwner ) { - owner = newOwner; -} - -ID_INLINE idEntity *idClipModel::GetOwner( void ) const { - return owner; -} - -ID_INLINE const idBounds &idClipModel::GetBounds( void ) const { - return bounds; -} - -ID_INLINE const idBounds &idClipModel::GetAbsBounds( void ) const { - return absBounds; -} - -ID_INLINE const idVec3 &idClipModel::GetOrigin( void ) const { - return origin; -} - -ID_INLINE const idMat3 &idClipModel::GetAxis( void ) const { - return axis; -} - -ID_INLINE bool idClipModel::IsRenderModel( void ) const { - return ( renderModelHandle != -1 ); -} - -ID_INLINE bool idClipModel::IsTraceModel( void ) const { - return ( traceModelIndex != -1 ); -} - -ID_INLINE bool idClipModel::IsLinked( void ) const { - return ( clipLinks != NULL ); -} - -ID_INLINE bool idClipModel::IsEnabled( void ) const { - return enabled; -} - -ID_INLINE bool idClipModel::IsEqual( const idTraceModel &trm ) const { - return ( traceModelIndex != -1 && *GetCachedTraceModel( traceModelIndex ) == trm ); -} - -ID_INLINE const idTraceModel *idClipModel::GetTraceModel( void ) const { - if ( !IsTraceModel() ) { - return NULL; - } - return idClipModel::GetCachedTraceModel( traceModelIndex ); -} - - -//=============================================================== -// -// idClip -// -//=============================================================== - -class idClip { - - friend class idClipModel; - -public: - idClip( void ); - - void Init( void ); - void Shutdown( void ); - - // clip versus the rest of the world - bool Translation( trace_t &results, const idVec3 &start, const idVec3 &end, - const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity ); - bool Rotation( trace_t &results, const idVec3 &start, const idRotation &rotation, - const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity ); - bool Motion( trace_t &results, const idVec3 &start, const idVec3 &end, const idRotation &rotation, - const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity ); - int Contacts( contactInfo_t *contacts, const int maxContacts, const idVec3 &start, const idVec6 &dir, const float depth, - const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity ); - int Contents( const idVec3 &start, - const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity ); - - // special case translations versus the rest of the world - bool TracePoint( trace_t &results, const idVec3 &start, const idVec3 &end, - int contentMask, const idEntity *passEntity ); - bool TraceBounds( trace_t &results, const idVec3 &start, const idVec3 &end, const idBounds &bounds, - int contentMask, const idEntity *passEntity ); - - // clip versus a specific model - void TranslationModel( trace_t &results, const idVec3 &start, const idVec3 &end, - const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, - cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis ); - void RotationModel( trace_t &results, const idVec3 &start, const idRotation &rotation, - const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, - cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis ); - int ContactsModel( contactInfo_t *contacts, const int maxContacts, const idVec3 &start, const idVec6 &dir, const float depth, - const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, - cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis ); - int ContentsModel( const idVec3 &start, - const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, - cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis ); - - // clip versus all entities but not the world - void TranslationEntities( trace_t &results, const idVec3 &start, const idVec3 &end, - const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity ); - - // get a contact feature - bool GetModelContactFeature( const contactInfo_t &contact, const idClipModel *clipModel, idFixedWinding &winding ) const; - - // get entities/clip models within or touching the given bounds - int EntitiesTouchingBounds( const idBounds &bounds, int contentMask, idEntity **entityList, int maxCount ) const; - int ClipModelsTouchingBounds( const idBounds &bounds, int contentMask, idClipModel **clipModelList, int maxCount ) const; - - const idBounds & GetWorldBounds( void ) const; - idClipModel * DefaultClipModel( void ); - - // stats and debug drawing - void PrintStatistics( void ); - void DrawClipModels( const idVec3 &eye, const float radius, const idEntity *passEntity ); - bool DrawModelContactFeature( const contactInfo_t &contact, const idClipModel *clipModel, int lifetime ) const; - -private: - int numClipSectors; - struct clipSector_s * clipSectors; - idBounds worldBounds; - idClipModel temporaryClipModel; - idClipModel defaultClipModel; - mutable int touchCount; - // statistics - int numTranslations; - int numRotations; - int numMotions; - int numRenderModelTraces; - int numContents; - int numContacts; - -private: - struct clipSector_s * CreateClipSectors_r( const int depth, const idBounds &bounds, idVec3 &maxSector ); - void ClipModelsTouchingBounds_r( const struct clipSector_s *node, struct listParms_s &parms ) const; - const idTraceModel * TraceModelForClipModel( const idClipModel *mdl ) const; - int GetTraceClipModels( const idBounds &bounds, int contentMask, const idEntity *passEntity, idClipModel **clipModelList ) const; - void TraceRenderModel( trace_t &trace, const idVec3 &start, const idVec3 &end, const float radius, const idMat3 &axis, idClipModel *touch ) const; -}; - - -ID_INLINE bool idClip::TracePoint( trace_t &results, const idVec3 &start, const idVec3 &end, int contentMask, const idEntity *passEntity ) { - Translation( results, start, end, NULL, mat3_identity, contentMask, passEntity ); - return ( results.fraction < 1.0f ); -} - -ID_INLINE bool idClip::TraceBounds( trace_t &results, const idVec3 &start, const idVec3 &end, const idBounds &bounds, int contentMask, const idEntity *passEntity ) { - temporaryClipModel.LoadModel( idTraceModel( bounds ) ); - Translation( results, start, end, &temporaryClipModel, mat3_identity, contentMask, passEntity ); - return ( results.fraction < 1.0f ); -} - -ID_INLINE const idBounds & idClip::GetWorldBounds( void ) const { - return worldBounds; -} - -ID_INLINE idClipModel *idClip::DefaultClipModel( void ) { - return &defaultClipModel; -} - -#endif /* !__CLIP_H__ */ diff --git a/d3xp/physics/Force.cpp b/d3xp/physics/Force.cpp deleted file mode 100644 index 874bdd04..00000000 --- a/d3xp/physics/Force.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" - -#include "physics/Force.h" - -CLASS_DECLARATION( idClass, idForce ) -END_CLASS - -idList idForce::forceList; - -/* -================ -idForce::idForce -================ -*/ -idForce::idForce( void ) { - forceList.Append( this ); -} - -/* -================ -idForce::~idForce -================ -*/ -idForce::~idForce( void ) { - forceList.Remove( this ); -} - -/* -================ -idForce::DeletePhysics -================ -*/ -void idForce::DeletePhysics( const idPhysics *phys ) { - int i; - - for ( i = 0; i < forceList.Num(); i++ ) { - forceList[i]->RemovePhysics( phys ); - } -} - -/* -================ -idForce::ClearForceList -================ -*/ -void idForce::ClearForceList( void ) { - forceList.Clear(); -} - -/* -================ -idForce::Evaluate -================ -*/ -void idForce::Evaluate( int time ) { -} - -/* -================ -idForce::RemovePhysics -================ -*/ -void idForce::RemovePhysics( const idPhysics *phys ) { -} diff --git a/d3xp/physics/Force.h b/d3xp/physics/Force.h deleted file mode 100644 index 582225e6..00000000 --- a/d3xp/physics/Force.h +++ /dev/null @@ -1,68 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __FORCE_H__ -#define __FORCE_H__ - -#include "gamesys/Class.h" - -/* -=============================================================================== - - Force base class - - A force object applies a force to a physics object. - -=============================================================================== -*/ - -class idEntity; -class idPhysics; - -class idForce : public idClass { - -public: - CLASS_PROTOTYPE( idForce ); - - idForce( void ); - virtual ~idForce( void ); - static void DeletePhysics( const idPhysics *phys ); - static void ClearForceList( void ); - -public: // common force interface - // evalulate the force up to the given time - virtual void Evaluate( int time ); - // removes any pointers to the physics object - virtual void RemovePhysics( const idPhysics *phys ); - -private: - - static idList forceList; -}; - -#endif /* !__FORCE_H__ */ diff --git a/d3xp/physics/Force_Constant.cpp b/d3xp/physics/Force_Constant.cpp deleted file mode 100644 index d62bc348..00000000 --- a/d3xp/physics/Force_Constant.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "physics/Physics.h" -#include "gamesys/SaveGame.h" - -#include "physics/Force_Constant.h" - -CLASS_DECLARATION( idForce, idForce_Constant ) -END_CLASS - -/* -================ -idForce_Constant::idForce_Constant -================ -*/ -idForce_Constant::idForce_Constant( void ) { - force = vec3_zero; - physics = NULL; - id = 0; - point = vec3_zero; -} - -/* -================ -idForce_Constant::~idForce_Constant -================ -*/ -idForce_Constant::~idForce_Constant( void ) { -} - -/* -================ -idForce_Constant::Save -================ -*/ -void idForce_Constant::Save( idSaveGame *savefile ) const { - savefile->WriteVec3( force ); - savefile->WriteInt( id ); - savefile->WriteVec3( point ); -} - -/* -================ -idForce_Constant::Restore -================ -*/ -void idForce_Constant::Restore( idRestoreGame *savefile ) { - // Owner needs to call SetPhysics!! - savefile->ReadVec3( force ); - savefile->ReadInt( id ); - savefile->ReadVec3( point ); -} - -/* -================ -idForce_Constant::SetPosition -================ -*/ -void idForce_Constant::SetPosition( idPhysics *physics, int id, const idVec3 &point ) { - this->physics = physics; - this->id = id; - this->point = point; -} - -/* -================ -idForce_Constant::SetForce -================ -*/ -void idForce_Constant::SetForce( const idVec3 &force ) { - this->force = force; -} - -/* -================ -idForce_Constant::SetPhysics -================ -*/ -void idForce_Constant::SetPhysics( idPhysics *physics ) { - this->physics = physics; -} - -/* -================ -idForce_Constant::Evaluate -================ -*/ -void idForce_Constant::Evaluate( int time ) { - idVec3 p; - - if ( !physics ) { - return; - } - - p = physics->GetOrigin( id ) + point * physics->GetAxis( id ); - - physics->AddForce( id, p, force ); -} - -/* -================ -idForce_Constant::RemovePhysics -================ -*/ -void idForce_Constant::RemovePhysics( const idPhysics *phys ) { - if ( physics == phys ) { - physics = NULL; - } -} diff --git a/d3xp/physics/Force_Constant.h b/d3xp/physics/Force_Constant.h deleted file mode 100644 index e62df35c..00000000 --- a/d3xp/physics/Force_Constant.h +++ /dev/null @@ -1,73 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __FORCE_CONSTANT_H__ -#define __FORCE_CONSTANT_H__ - -#include "physics/Force.h" - -/* -=============================================================================== - - Constant force - -=============================================================================== -*/ - -class idForce_Constant : public idForce { - -public: - CLASS_PROTOTYPE( idForce_Constant ); - - idForce_Constant( void ); - virtual ~idForce_Constant( void ); - - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - // constant force - void SetForce( const idVec3 &force ); - // set force position - void SetPosition( idPhysics *physics, int id, const idVec3 &point ); - - void SetPhysics( idPhysics *physics ); - -public: // common force interface - virtual void Evaluate( int time ); - virtual void RemovePhysics( const idPhysics *phys ); - -private: - // force properties - idVec3 force; - idPhysics * physics; - int id; - idVec3 point; -}; - -#endif /* !__FORCE_CONSTANT_H__ */ diff --git a/d3xp/physics/Force_Drag.cpp b/d3xp/physics/Force_Drag.cpp deleted file mode 100644 index f8682a11..00000000 --- a/d3xp/physics/Force_Drag.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "framework/UsercmdGen.h" - -#include "physics/Physics.h" - -#include "physics/Force_Drag.h" - -CLASS_DECLARATION( idForce, idForce_Drag ) -END_CLASS - -/* -================ -idForce_Drag::idForce_Drag -================ -*/ -idForce_Drag::idForce_Drag( void ) { - damping = 0.5f; - dragPosition = vec3_zero; - physics = NULL; - id = 0; - p = vec3_zero; - dragPosition = vec3_zero; -} - -/* -================ -idForce_Drag::~idForce_Drag -================ -*/ -idForce_Drag::~idForce_Drag( void ) { -} - -/* -================ -idForce_Drag::Init -================ -*/ -void idForce_Drag::Init( float damping ) { - if ( damping >= 0.0f && damping < 1.0f ) { - this->damping = damping; - } -} - -/* -================ -idForce_Drag::SetPhysics -================ -*/ -void idForce_Drag::SetPhysics( idPhysics *phys, int id, const idVec3 &p ) { - this->physics = phys; - this->id = id; - this->p = p; -} - -/* -================ -idForce_Drag::SetDragPosition -================ -*/ -void idForce_Drag::SetDragPosition( const idVec3 &pos ) { - this->dragPosition = pos; -} - -/* -================ -idForce_Drag::GetDragPosition -================ -*/ -const idVec3 &idForce_Drag::GetDragPosition( void ) const { - return this->dragPosition; -} - -/* -================ -idForce_Drag::GetDraggedPosition -================ -*/ -const idVec3 idForce_Drag::GetDraggedPosition( void ) const { - return ( physics->GetOrigin( id ) + p * physics->GetAxis( id ) ); -} - -/* -================ -idForce_Drag::Evaluate -================ -*/ -void idForce_Drag::Evaluate( int time ) { - float l1, l2, mass; - idVec3 dragOrigin, dir1, dir2, velocity, centerOfMass; - idMat3 inertiaTensor; - idRotation rotation; - idClipModel *clipModel; - - if ( !physics ) { - return; - } - - clipModel = physics->GetClipModel( id ); - if ( clipModel != NULL && clipModel->IsTraceModel() ) { - clipModel->GetMassProperties( 1.0f, mass, centerOfMass, inertiaTensor ); - } else { - centerOfMass.Zero(); - } - - centerOfMass = physics->GetOrigin( id ) + centerOfMass * physics->GetAxis( id ); - dragOrigin = physics->GetOrigin( id ) + p * physics->GetAxis( id ); - - dir1 = dragPosition - centerOfMass; - dir2 = dragOrigin - centerOfMass; - l1 = dir1.Normalize(); - l2 = dir2.Normalize(); - - rotation.Set( centerOfMass, dir2.Cross( dir1 ), RAD2DEG( idMath::ACos( dir1 * dir2 ) ) ); - physics->SetAngularVelocity( rotation.ToAngularVelocity() / MS2SEC( USERCMD_MSEC ), id ); - - velocity = physics->GetLinearVelocity( id ) * damping + dir1 * ( ( l1 - l2 ) * ( 1.0f - damping ) / MS2SEC( USERCMD_MSEC ) ); - physics->SetLinearVelocity( velocity, id ); -} - -/* -================ -idForce_Drag::RemovePhysics -================ -*/ -void idForce_Drag::RemovePhysics( const idPhysics *phys ) { - if ( physics == phys ) { - physics = NULL; - } -} diff --git a/d3xp/physics/Force_Drag.h b/d3xp/physics/Force_Drag.h deleted file mode 100644 index 4010845b..00000000 --- a/d3xp/physics/Force_Drag.h +++ /dev/null @@ -1,76 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __FORCE_DRAG_H__ -#define __FORCE_DRAG_H__ - -#include "physics/Force.h" - -/* -=============================================================================== - - Drag force - -=============================================================================== -*/ - -class idForce_Drag : public idForce { - -public: - CLASS_PROTOTYPE( idForce_Drag ); - - idForce_Drag( void ); - virtual ~idForce_Drag( void ); - // initialize the drag force - void Init( float damping ); - // set physics object being dragged - void SetPhysics( idPhysics *physics, int id, const idVec3 &p ); - // set position to drag towards - void SetDragPosition( const idVec3 &pos ); - // get the position dragged towards - const idVec3 & GetDragPosition( void ) const; - // get the position on the dragged physics object - const idVec3 GetDraggedPosition( void ) const; - -public: // common force interface - virtual void Evaluate( int time ); - virtual void RemovePhysics( const idPhysics *phys ); - -private: - - // properties - float damping; - - // positioning - idPhysics * physics; // physics object - int id; // clip model id of physics object - idVec3 p; // position on clip model - idVec3 dragPosition; // drag towards this position -}; - -#endif /* !__FORCE_DRAG_H__ */ diff --git a/d3xp/physics/Force_Field.cpp b/d3xp/physics/Force_Field.cpp deleted file mode 100644 index 8c02b120..00000000 --- a/d3xp/physics/Force_Field.cpp +++ /dev/null @@ -1,261 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "physics/Physics_Player.h" -#include "physics/Physics_Monster.h" -#include "WorldSpawn.h" - -#include "physics/Force_Field.h" - -CLASS_DECLARATION( idForce, idForce_Field ) -END_CLASS - -/* -================ -idForce_Field::idForce_Field -================ -*/ -idForce_Field::idForce_Field( void ) { - type = FORCEFIELD_UNIFORM; - applyType = FORCEFIELD_APPLY_FORCE; - magnitude = 0.0f; - dir.Set( 0, 0, 1 ); - randomTorque = 0.0f; - playerOnly = false; - monsterOnly = false; - clipModel = NULL; -} - -/* -================ -idForce_Field::~idForce_Field -================ -*/ -idForce_Field::~idForce_Field( void ) { - if ( this->clipModel ) { - delete this->clipModel; - } -} - -/* -================ -idForce_Field::Save -================ -*/ -void idForce_Field::Save( idSaveGame *savefile ) const { - savefile->WriteInt( type ); - savefile->WriteInt( applyType); - savefile->WriteFloat( magnitude ); - savefile->WriteVec3( dir ); - savefile->WriteFloat( randomTorque ); - savefile->WriteBool( playerOnly ); - savefile->WriteBool( monsterOnly ); - savefile->WriteClipModel( clipModel ); -} - -/* -================ -idForce_Field::Restore -================ -*/ -void idForce_Field::Restore( idRestoreGame *savefile ) { - savefile->ReadInt( (int &)type ); - savefile->ReadInt( (int &)applyType); - savefile->ReadFloat( magnitude ); - savefile->ReadVec3( dir ); - savefile->ReadFloat( randomTorque ); - savefile->ReadBool( playerOnly ); - savefile->ReadBool( monsterOnly ); - savefile->ReadClipModel( clipModel ); -} - -/* -================ -idForce_Field::SetClipModel -================ -*/ -void idForce_Field::SetClipModel( idClipModel *clipModel ) { - if ( this->clipModel && clipModel != this->clipModel ) { - delete this->clipModel; - } - this->clipModel = clipModel; -} - -/* -================ -idForce_Field::Uniform -================ -*/ -void idForce_Field::Uniform( const idVec3 &force ) { - dir = force; - magnitude = dir.Normalize(); - type = FORCEFIELD_UNIFORM; -} - -/* -================ -idForce_Field::Explosion -================ -*/ -void idForce_Field::Explosion( float force ) { - magnitude = force; - type = FORCEFIELD_EXPLOSION; -} - -/* -================ -idForce_Field::Implosion -================ -*/ -void idForce_Field::Implosion( float force ) { - magnitude = force; - type = FORCEFIELD_IMPLOSION; -} - -/* -================ -idForce_Field::RandomTorque -================ -*/ -void idForce_Field::RandomTorque( float force ) { - randomTorque = force; -} - -/* -================ -idForce_Field::Evaluate -================ -*/ -void idForce_Field::Evaluate( int time ) { - int numClipModels, i; - idBounds bounds; - idVec3 force, torque, angularVelocity; - idClipModel *cm, *clipModelList[ MAX_GENTITIES ]; - - assert( clipModel ); - - bounds.FromTransformedBounds( clipModel->GetBounds(), clipModel->GetOrigin(), clipModel->GetAxis() ); - numClipModels = gameLocal.clip.ClipModelsTouchingBounds( bounds, -1, clipModelList, MAX_GENTITIES ); - - torque.Zero(); - - for ( i = 0; i < numClipModels; i++ ) { - cm = clipModelList[ i ]; - - if ( !cm->IsTraceModel() ) { - continue; - } - - idEntity *entity = cm->GetEntity(); - - if ( !entity ) { - continue; - } - - idPhysics *physics = entity->GetPhysics(); - - if ( playerOnly ) { - if ( !physics->IsType( idPhysics_Player::Type ) ) { - continue; - } - } else if ( monsterOnly ) { - if ( !physics->IsType( idPhysics_Monster::Type ) ) { - continue; - } - } - - if ( !gameLocal.clip.ContentsModel( cm->GetOrigin(), cm, cm->GetAxis(), -1, - clipModel->Handle(), clipModel->GetOrigin(), clipModel->GetAxis() ) ) { - continue; - } - - switch( type ) { - case FORCEFIELD_UNIFORM: { - force = dir; - break; - } - case FORCEFIELD_EXPLOSION: { - force = cm->GetOrigin() - clipModel->GetOrigin(); - force.Normalize(); - break; - } - case FORCEFIELD_IMPLOSION: { - force = clipModel->GetOrigin() - cm->GetOrigin(); - force.Normalize(); - break; - } - default: { - gameLocal.Error( "idForce_Field: invalid type" ); - return; - } - } - - if ( randomTorque != 0.0f ) { - torque[0] = gameLocal.random.CRandomFloat(); - torque[1] = gameLocal.random.CRandomFloat(); - torque[2] = gameLocal.random.CRandomFloat(); - if ( torque.Normalize() == 0.0f ) { - torque[2] = 1.0f; - } - } - - switch( applyType ) { - case FORCEFIELD_APPLY_FORCE: { - if ( randomTorque != 0.0f ) { - entity->AddForce( gameLocal.world, cm->GetId(), cm->GetOrigin() + torque.Cross( dir ) * randomTorque, dir * magnitude ); - } - else { - entity->AddForce( gameLocal.world, cm->GetId(), cm->GetOrigin(), force * magnitude ); - } - break; - } - case FORCEFIELD_APPLY_VELOCITY: { - physics->SetLinearVelocity( force * magnitude, cm->GetId() ); - if ( randomTorque != 0.0f ) { - angularVelocity = physics->GetAngularVelocity( cm->GetId() ); - physics->SetAngularVelocity( 0.5f * (angularVelocity + torque * randomTorque), cm->GetId() ); - } - break; - } - case FORCEFIELD_APPLY_IMPULSE: { - if ( randomTorque != 0.0f ) { - entity->ApplyImpulse( gameLocal.world, cm->GetId(), cm->GetOrigin() + torque.Cross( dir ) * randomTorque, dir * magnitude ); - } - else { - entity->ApplyImpulse( gameLocal.world, cm->GetId(), cm->GetOrigin(), force * magnitude ); - } - break; - } - default: { - gameLocal.Error( "idForce_Field: invalid apply type" ); - return; - } - } - } -} diff --git a/d3xp/physics/Force_Field.h b/d3xp/physics/Force_Field.h deleted file mode 100644 index ea963ac1..00000000 --- a/d3xp/physics/Force_Field.h +++ /dev/null @@ -1,99 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __FORCE_FIELD_H__ -#define __FORCE_FIELD_H__ - -#include "physics/Force.h" -#include "physics/Clip.h" -#include "Entity.h" -#include "AFEntity.h" - -/* -=============================================================================== - - Force field - -=============================================================================== -*/ - -enum forceFieldType { - FORCEFIELD_UNIFORM, - FORCEFIELD_EXPLOSION, - FORCEFIELD_IMPLOSION -}; - -enum forceFieldApplyType { - FORCEFIELD_APPLY_FORCE, - FORCEFIELD_APPLY_VELOCITY, - FORCEFIELD_APPLY_IMPULSE -}; - -class idForce_Field : public idForce { - -public: - CLASS_PROTOTYPE( idForce_Field ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - idForce_Field( void ); - virtual ~idForce_Field( void ); - // uniform constant force - void Uniform( const idVec3 &force ); - // explosion from clip model origin - void Explosion( float force ); - // implosion towards clip model origin - void Implosion( float force ); - // add random torque - void RandomTorque( float force ); - // should the force field apply a force, velocity or impulse - void SetApplyType( const forceFieldApplyType type ) { applyType = type; } - // make the force field only push players - void SetPlayerOnly( bool set ) { playerOnly = set; } - // make the force field only push monsters - void SetMonsterOnly( bool set ) { monsterOnly = set; } - // clip model describing the extents of the force field - void SetClipModel( idClipModel *clipModel ); - -public: // common force interface - virtual void Evaluate( int time ); - -private: - // force properties - forceFieldType type; - forceFieldApplyType applyType; - float magnitude; - idVec3 dir; - float randomTorque; - bool playerOnly; - bool monsterOnly; - idClipModel * clipModel; -}; - -#endif /* !__FORCE_FIELD_H__ */ diff --git a/d3xp/physics/Force_Spring.cpp b/d3xp/physics/Force_Spring.cpp deleted file mode 100644 index c805b7a9..00000000 --- a/d3xp/physics/Force_Spring.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "physics/Physics.h" - -#include "physics/Force_Spring.h" - -CLASS_DECLARATION( idForce, idForce_Spring ) -END_CLASS - -/* -================ -idForce_Spring::idForce_Spring -================ -*/ -idForce_Spring::idForce_Spring( void ) { - Kstretch = 100.0f; - Kcompress = 100.0f; - damping = 0.0f; - restLength = 0.0f; - physics1 = NULL; - id1 = 0; - p1 = vec3_zero; - physics2 = NULL; - id2 = 0; - p2 = vec3_zero; -} - -/* -================ -idForce_Spring::~idForce_Spring -================ -*/ -idForce_Spring::~idForce_Spring( void ) { -} - -/* -================ -idForce_Spring::InitSpring -================ -*/ -void idForce_Spring::InitSpring( float Kstretch, float Kcompress, float damping, float restLength ) { - this->Kstretch = Kstretch; - this->Kcompress = Kcompress; - this->damping = damping; - this->restLength = restLength; -} - -/* -================ -idForce_Spring::SetPosition -================ -*/ -void idForce_Spring::SetPosition( idPhysics *physics1, int id1, const idVec3 &p1, idPhysics *physics2, int id2, const idVec3 &p2 ) { - this->physics1 = physics1; - this->id1 = id1; - this->p1 = p1; - this->physics2 = physics2; - this->id2 = id2; - this->p2 = p2; -} - -/* -================ -idForce_Spring::Evaluate -================ -*/ -void idForce_Spring::Evaluate( int time ) { - float length; - idMat3 axis; - idVec3 pos1, pos2, velocity1, velocity2, force, dampingForce; - impactInfo_t info; - - pos1 = p1; - pos2 = p2; - velocity1 = velocity2 = vec3_origin; - - if ( physics1 ) { - axis = physics1->GetAxis( id1 ); - pos1 = physics1->GetOrigin( id1 ); - pos1 += p1 * axis; - if ( damping > 0.0f ) { - physics1->GetImpactInfo( id1, pos1, &info ); - velocity1 = info.velocity; - } - } - - if ( physics2 ) { - axis = physics2->GetAxis( id2 ); - pos2 = physics2->GetOrigin( id2 ); - pos2 += p2 * axis; - if ( damping > 0.0f ) { - physics2->GetImpactInfo( id2, pos2, &info ); - velocity2 = info.velocity; - } - } - - force = pos2 - pos1; - dampingForce = ( damping * ( ((velocity2 - velocity1) * force) / (force * force) ) ) * force; - length = force.Normalize(); - - // if the spring is stretched - if ( length > restLength ) { - if ( Kstretch > 0.0f ) { - force = ( Square( length - restLength ) * Kstretch ) * force - dampingForce; - if ( physics1 ) { - physics1->AddForce( id1, pos1, force ); - } - if ( physics2 ) { - physics2->AddForce( id2, pos2, -force ); - } - } - } - else { - if ( Kcompress > 0.0f ) { - force = ( Square( length - restLength ) * Kcompress ) * force - dampingForce; - if ( physics1 ) { - physics1->AddForce( id1, pos1, -force ); - } - if ( physics2 ) { - physics2->AddForce( id2, pos2, force ); - } - } - } -} - -/* -================ -idForce_Spring::RemovePhysics -================ -*/ -void idForce_Spring::RemovePhysics( const idPhysics *phys ) { - if ( physics1 == phys ) { - physics1 = NULL; - } - if ( physics2 == phys ) { - physics2 = NULL; - } -} diff --git a/d3xp/physics/Force_Spring.h b/d3xp/physics/Force_Spring.h deleted file mode 100644 index 2a890b2c..00000000 --- a/d3xp/physics/Force_Spring.h +++ /dev/null @@ -1,77 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __FORCE_SPRING_H__ -#define __FORCE_SPRING_H__ - -#include "physics/Force.h" - -/* -=============================================================================== - - Spring force - -=============================================================================== -*/ - -class idForce_Spring : public idForce { - -public: - CLASS_PROTOTYPE( idForce_Spring ); - - idForce_Spring( void ); - virtual ~idForce_Spring( void ); - // initialize the spring - void InitSpring( float Kstretch, float Kcompress, float damping, float restLength ); - // set the entities and positions on these entities the spring is attached to - void SetPosition( idPhysics *physics1, int id1, const idVec3 &p1, - idPhysics *physics2, int id2, const idVec3 &p2 ); - -public: // common force interface - virtual void Evaluate( int time ); - virtual void RemovePhysics( const idPhysics *phys ); - -private: - - // spring properties - float Kstretch; - float Kcompress; - float damping; - float restLength; - - // positioning - idPhysics * physics1; // first physics object - int id1; // clip model id of first physics object - idVec3 p1; // position on clip model - idPhysics * physics2; // second physics object - int id2; // clip model id of second physics object - idVec3 p2; // position on clip model - -}; - -#endif /* !__FORCE_SPRING_H__ */ diff --git a/d3xp/physics/Physics.cpp b/d3xp/physics/Physics.cpp deleted file mode 100644 index 86e35d46..00000000 --- a/d3xp/physics/Physics.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "Game_local.h" - -#include "physics/Physics.h" - -ABSTRACT_DECLARATION( idClass, idPhysics ) -END_CLASS - - -/* -================ -idPhysics::~idPhysics -================ -*/ -idPhysics::~idPhysics( void ) { -} - -/* -================ -idPhysics::Save -================ -*/ -void idPhysics::Save( idSaveGame *savefile ) const { -} - -/* -================ -idPhysics::Restore -================ -*/ -void idPhysics::Restore( idRestoreGame *savefile ) { -} - -/* -================ -idPhysics::SetClipBox -================ -*/ -void idPhysics::SetClipBox( const idBounds &bounds, float density ) { - SetClipModel( new idClipModel( idTraceModel( bounds ) ), density ); -} - -/* -================ -idPhysics::SnapTimeToPhysicsFrame -================ -*/ -int idPhysics::SnapTimeToPhysicsFrame( int t ) { - int s; - s = t + USERCMD_MSEC - 1; - return ( s - s % USERCMD_MSEC ); -} diff --git a/d3xp/physics/Physics.h b/d3xp/physics/Physics.h deleted file mode 100644 index 545c6ee2..00000000 --- a/d3xp/physics/Physics.h +++ /dev/null @@ -1,189 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __PHYSICS_H__ -#define __PHYSICS_H__ - -#include "idlib/BitMsg.h" - -#include "gamesys/Class.h" -#include "physics/Clip.h" -#include "GameBase.h" - -/* -=============================================================================== - - Physics abstract class - - A physics object is a tool to manipulate the position and orientation of - an entity. The physics object is a container for idClipModels used for - collision detection. The physics deals with moving these collision models - through the world according to the laws of physics or other rules. - - The mass of a clip model is the volume of the clip model times the density. - An arbitrary mass can however be set for specific clip models or the - whole physics object. The contents of a clip model is a set of bit flags - that define the contents. The clip mask defines the contents a clip model - collides with. - - The linear velocity of a physics object is a vector that defines the - translation of the center of mass in units per second. The angular velocity - of a physics object is a vector that passes through the center of mass. The - direction of this vector defines the axis of rotation and the magnitude - defines the rate of rotation about the axis in radians per second. - The gravity is the change in velocity per second due to gravitational force. - - Entities update their visual position and orientation from the physics - using GetOrigin() and GetAxis(). Direct origin and axis changes of - entities should go through the physics. In other words the physics origin - and axis are updated first and the entity updates it's visual position - from the physics. - -=============================================================================== -*/ - -#define CONTACT_EPSILON 0.25f // maximum contact seperation distance - -class idEntity; - -typedef struct impactInfo_s { - float invMass; // inverse mass - idMat3 invInertiaTensor; // inverse inertia tensor - idVec3 position; // impact position relative to center of mass - idVec3 velocity; // velocity at the impact position -} impactInfo_t; - - -class idPhysics : public idClass { - -public: - ABSTRACT_PROTOTYPE( idPhysics ); - - virtual ~idPhysics( void ); - static int SnapTimeToPhysicsFrame( int t ); - - // Must not be virtual - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - -public: // common physics interface - // set pointer to entity using physics - virtual void SetSelf( idEntity *e ) = 0; - // clip models - virtual void SetClipModel( idClipModel *model, float density, int id = 0, bool freeOld = true ) = 0; - virtual void SetClipBox( const idBounds &bounds, float density ); - virtual idClipModel * GetClipModel( int id = 0 ) const = 0; - virtual int GetNumClipModels( void ) const = 0; - // get/set the mass of a specific clip model or the whole physics object - virtual void SetMass( float mass, int id = -1 ) = 0; - virtual float GetMass( int id = -1 ) const = 0; - // get/set the contents of a specific clip model or the whole physics object - virtual void SetContents( int contents, int id = -1 ) = 0; - virtual int GetContents( int id = -1 ) const = 0; - // get/set the contents a specific clip model or the whole physics object collides with - virtual void SetClipMask( int mask, int id = -1 ) = 0; - virtual int GetClipMask( int id = -1 ) const = 0; - // get the bounds of a specific clip model or the whole physics object - virtual const idBounds & GetBounds( int id = -1 ) const = 0; - virtual const idBounds & GetAbsBounds( int id = -1 ) const = 0; - // evaluate the physics with the given time step, returns true if the object moved - virtual bool Evaluate( int timeStepMSec, int endTimeMSec ) = 0; - // update the time without moving - virtual void UpdateTime( int endTimeMSec ) = 0; - // get the last physics update time - virtual int GetTime( void ) const = 0; - // collision interaction between different physics objects - virtual void GetImpactInfo( const int id, const idVec3 &point, impactInfo_t *info ) const = 0; - virtual void ApplyImpulse( const int id, const idVec3 &point, const idVec3 &impulse ) = 0; - virtual void AddForce( const int id, const idVec3 &point, const idVec3 &force ) = 0; - virtual void Activate( void ) = 0; - virtual void PutToRest( void ) = 0; - virtual bool IsAtRest( void ) const = 0; - virtual int GetRestStartTime( void ) const = 0; - virtual bool IsPushable( void ) const = 0; - // save and restore the physics state - virtual void SaveState( void ) = 0; - virtual void RestoreState( void ) = 0; - // set the position and orientation in master space or world space if no master set - virtual void SetOrigin( const idVec3 &newOrigin, int id = -1 ) = 0; - virtual void SetAxis( const idMat3 &newAxis, int id = -1 ) = 0; - // translate or rotate the physics object in world space - virtual void Translate( const idVec3 &translation, int id = -1 ) = 0; - virtual void Rotate( const idRotation &rotation, int id = -1 ) = 0; - // get the position and orientation in world space - virtual const idVec3 & GetOrigin( int id = 0 ) const = 0; - virtual const idMat3 & GetAxis( int id = 0 ) const = 0; - // set linear and angular velocity - virtual void SetLinearVelocity( const idVec3 &newLinearVelocity, int id = 0 ) = 0; - virtual void SetAngularVelocity( const idVec3 &newAngularVelocity, int id = 0 ) = 0; - // get linear and angular velocity - virtual const idVec3 & GetLinearVelocity( int id = 0 ) const = 0; - virtual const idVec3 & GetAngularVelocity( int id = 0 ) const = 0; - // gravity - virtual void SetGravity( const idVec3 &newGravity ) = 0; - virtual const idVec3 & GetGravity( void ) const = 0; - virtual const idVec3 & GetGravityNormal( void ) const = 0; - // get first collision when translating or rotating this physics object - virtual void ClipTranslation( trace_t &results, const idVec3 &translation, const idClipModel *model ) const = 0; - virtual void ClipRotation( trace_t &results, const idRotation &rotation, const idClipModel *model ) const = 0; - virtual int ClipContents( const idClipModel *model ) const = 0; - // disable/enable the clip models contained by this physics object - virtual void DisableClip( void ) = 0; - virtual void EnableClip( void ) = 0; - // link/unlink the clip models contained by this physics object - virtual void UnlinkClip( void ) = 0; - virtual void LinkClip( void ) = 0; - // contacts - virtual bool EvaluateContacts( void ) = 0; - virtual int GetNumContacts( void ) const = 0; - virtual const contactInfo_t &GetContact( int num ) const = 0; - virtual void ClearContacts( void ) = 0; - virtual void AddContactEntity( idEntity *e ) = 0; - virtual void RemoveContactEntity( idEntity *e ) = 0; - // ground contacts - virtual bool HasGroundContacts( void ) const = 0; - virtual bool IsGroundEntity( int entityNum ) const = 0; - virtual bool IsGroundClipModel( int entityNum, int id ) const = 0; - // set the master entity for objects bound to a master - virtual void SetMaster( idEntity *master, const bool orientated = true ) = 0; - // set pushed state - virtual void SetPushed( int deltaTime ) = 0; - virtual const idVec3 & GetPushedLinearVelocity( const int id = 0 ) const = 0; - virtual const idVec3 & GetPushedAngularVelocity( const int id = 0 ) const = 0; - // get blocking info, returns NULL if the object is not blocked - virtual const trace_t * GetBlockingInfo( void ) const = 0; - virtual idEntity * GetBlockingEntity( void ) const = 0; - // movement end times in msec for reached events at the end of predefined motion - virtual int GetLinearEndTime( void ) const = 0; - virtual int GetAngularEndTime( void ) const = 0; - // networking - virtual void WriteToSnapshot( idBitMsgDelta &msg ) const = 0; - virtual void ReadFromSnapshot( const idBitMsgDelta &msg ) = 0; -}; - -#endif /* !__PHYSICS_H__ */ diff --git a/d3xp/physics/Physics_AF.cpp b/d3xp/physics/Physics_AF.cpp deleted file mode 100644 index 098a4bfc..00000000 --- a/d3xp/physics/Physics_AF.cpp +++ /dev/null @@ -1,8014 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "idlib/math/Quat.h" -#include "idlib/Timer.h" - -#include "gamesys/SysCvar.h" -#include "Entity.h" -#include "Player.h" -#include "WorldSpawn.h" - -#include "physics/Physics_AF.h" - -CLASS_DECLARATION( idPhysics_Base, idPhysics_AF ) -END_CLASS - -const float ERROR_REDUCTION = 0.5f; -const float ERROR_REDUCTION_MAX = 256.0f; -const float LIMIT_ERROR_REDUCTION = 0.3f; -const float LCP_EPSILON = 1e-7f; -const float LIMIT_LCP_EPSILON = 1e-4f; -const float CONTACT_LCP_EPSILON = 1e-6f; -const float CENTER_OF_MASS_EPSILON = 1e-4f; -const float NO_MOVE_TIME = 1.0f; -const float NO_MOVE_TRANSLATION_TOLERANCE = 10.0f; -const float NO_MOVE_ROTATION_TOLERANCE = 10.0f; -const float MIN_MOVE_TIME = -1.0f; -const float MAX_MOVE_TIME = -1.0f; -const float IMPULSE_THRESHOLD = 500.0f; -const float SUSPEND_LINEAR_VELOCITY = 10.0f; -const float SUSPEND_ANGULAR_VELOCITY = 15.0f; -const float SUSPEND_LINEAR_ACCELERATION = 20.0f; -const float SUSPEND_ANGULAR_ACCELERATION = 30.0f; -const idVec6 vec6_lcp_epsilon = idVec6( LCP_EPSILON, LCP_EPSILON, LCP_EPSILON, - LCP_EPSILON, LCP_EPSILON, LCP_EPSILON ); - -#define AF_TIMINGS - -#ifdef AF_TIMINGS -static int lastTimerReset = 0; -static int numArticulatedFigures = 0; -static idTimer timer_total, timer_pc, timer_ac, timer_collision, timer_lcp; -#endif - - - -//=============================================================== -// -// idAFConstraint -// -//=============================================================== - -/* -================ -idAFConstraint::idAFConstraint -================ -*/ -idAFConstraint::idAFConstraint( void ) { - type = CONSTRAINT_INVALID; - name = "noname"; - body1 = NULL; - body2 = NULL; - physics = NULL; - - lo.Zero( 6 ); - lo.SubVec6(0) = -vec6_infinity; - hi.Zero( 6 ); - hi.SubVec6(0) = vec6_infinity; - e.SetSize( 6 ); - e.SubVec6(0) = vec6_lcp_epsilon; - - boxConstraint = NULL; - boxIndex[0] = -1; - boxIndex[1] = -1; - boxIndex[2] = -1; - boxIndex[3] = -1; - boxIndex[4] = -1; - boxIndex[5] = -1; - - firstIndex = 0; - - memset( &fl, 0, sizeof( fl ) ); -} - -/* -================ -idAFConstraint::~idAFConstraint -================ -*/ -idAFConstraint::~idAFConstraint( void ) { -} - -/* -================ -idAFConstraint::SetBody1 -================ -*/ -void idAFConstraint::SetBody1( idAFBody *body ) { - if ( body1 != body) { - body1 = body; - if ( physics ) { - physics->SetChanged(); - } - } -} - -/* -================ -idAFConstraint::SetBody2 -================ -*/ -void idAFConstraint::SetBody2( idAFBody *body ) { - if ( body2 != body ) { - body2 = body; - if ( physics ) { - physics->SetChanged(); - } - } -} - -/* -================ -idAFConstraint::GetMultiplier -================ -*/ -const idVecX &idAFConstraint::GetMultiplier( void ) { - return lm; -} - -/* -================ -idAFConstraint::Evaluate -================ -*/ -void idAFConstraint::Evaluate( float invTimeStep ) { - assert( 0 ); -} - -/* -================ -idAFConstraint::ApplyFriction -================ -*/ -void idAFConstraint::ApplyFriction( float invTimeStep ) { -} - -/* -================ -idAFConstraint::GetForce -================ -*/ -void idAFConstraint::GetForce( idAFBody *body, idVec6 &force ) { - idVecX v; - - v.SetData( 6, VECX_ALLOCA( 6 ) ); - if ( body == body1 ) { - J1.TransposeMultiply( v, lm ); - } - else if ( body == body2 ) { - J2.TransposeMultiply( v, lm ); - } - else { - v.Zero(); - } - force[0] = v[0]; force[1] = v[1]; force[2] = v[2]; force[3] = v[3]; force[4] = v[4]; force[5] = v[5]; -} - -/* -================ -idAFConstraint::Translate -================ -*/ -void idAFConstraint::Translate( const idVec3 &translation ) { - assert( 0 ); -} - -/* -================ -idAFConstraint::Rotate -================ -*/ -void idAFConstraint::Rotate( const idRotation &rotation ) { - assert( 0 ); -} - -/* -================ -idAFConstraint::GetCenter -================ -*/ -void idAFConstraint::GetCenter( idVec3 ¢er ) { - center.Zero(); -} - -/* -================ -idAFConstraint::DebugDraw -================ -*/ -void idAFConstraint::DebugDraw( void ) { -} - -/* -================ -idAFConstraint::InitSize -================ -*/ -void idAFConstraint::InitSize( int size ) { - J1.Zero( size, 6 ); - J2.Zero( size, 6 ); - c1.Zero( size ); - c2.Zero( size ); - s.Zero( size ); - lm.Zero( size ); -} - -/* -================ -idAFConstraint::Save -================ -*/ -void idAFConstraint::Save( idSaveGame *saveFile ) const { - saveFile->WriteInt( type ); -} - -/* -================ -idAFConstraint::Restore -================ -*/ -void idAFConstraint::Restore( idRestoreGame *saveFile ) { - constraintType_t t; - saveFile->ReadInt( (int &)t ); - assert( t == type ); -} - - -//=============================================================== -// -// idAFConstraint_Fixed -// -//=============================================================== - -/* -================ -idAFConstraint_Fixed::idAFConstraint_Fixed -================ -*/ -idAFConstraint_Fixed::idAFConstraint_Fixed( const idStr &name, idAFBody *body1, idAFBody *body2 ) { - assert( body1 ); - type = CONSTRAINT_FIXED; - this->name = name; - this->body1 = body1; - this->body2 = body2; - InitSize( 6 ); - fl.allowPrimary = true; - fl.noCollision = true; - - InitOffset(); -} - -/* -================ -idAFConstraint_Fixed::InitOffset -================ -*/ -void idAFConstraint_Fixed::InitOffset( void ) { - if ( body2 ) { - offset = ( body1->GetWorldOrigin() - body2->GetWorldOrigin() ) * body2->GetWorldAxis().Transpose(); - relAxis = body1->GetWorldAxis() * body2->GetWorldAxis().Transpose(); - } - else { - offset = body1->GetWorldOrigin(); - relAxis = body1->GetWorldAxis(); - } -} - -/* -================ -idAFConstraint_Fixed::SetBody1 -================ -*/ -void idAFConstraint_Fixed::SetBody1( idAFBody *body ) { - if ( body1 != body) { - body1 = body; - InitOffset(); - if ( physics ) { - physics->SetChanged(); - } - } -} - -/* -================ -idAFConstraint_Fixed::SetBody2 -================ -*/ -void idAFConstraint_Fixed::SetBody2( idAFBody *body ) { - if ( body2 != body ) { - body2 = body; - InitOffset(); - if ( physics ) { - physics->SetChanged(); - } - } -} - -/* -================ -idAFConstraint_Fixed::Evaluate -================ -*/ -void idAFConstraint_Fixed::Evaluate( float invTimeStep ) { - idVec3 ofs, a2; - idMat3 ax; - idRotation r; - idAFBody *master; - - master = body2 ? body2 : physics->GetMasterBody(); - - if ( master ) { - a2 = offset * master->GetWorldAxis(); - ofs = a2 + master->GetWorldOrigin(); - ax = relAxis * master->GetWorldAxis(); - } - else { - a2.Zero(); - ofs = offset; - ax = relAxis; - } - - J1.Set( mat3_identity, mat3_zero, - mat3_zero, mat3_identity ); - - if ( body2 ) { - J2.Set( -mat3_identity, SkewSymmetric( a2 ), - mat3_zero, -mat3_identity ); - } - else { - J2.Zero( 6, 6 ); - } - - c1.SubVec3(0) = -( invTimeStep * ERROR_REDUCTION ) * ( ofs - body1->GetWorldOrigin() ); - r = ( body1->GetWorldAxis().Transpose() * ax ).ToRotation(); - c1.SubVec3(1) = -( invTimeStep * ERROR_REDUCTION ) * ( r.GetVec() * -(float) DEG2RAD( r.GetAngle() ) ); - - c1.Clamp( -ERROR_REDUCTION_MAX, ERROR_REDUCTION_MAX ); -} - -/* -================ -idAFConstraint_Fixed::ApplyFriction -================ -*/ -void idAFConstraint_Fixed::ApplyFriction( float invTimeStep ) { - // no friction -} - -/* -================ -idAFConstraint_Fixed::Translate -================ -*/ -void idAFConstraint_Fixed::Translate( const idVec3 &translation ) { - if ( !body2 ) { - offset += translation; - } -} - -/* -================ -idAFConstraint_Fixed::Rotate -================ -*/ -void idAFConstraint_Fixed::Rotate( const idRotation &rotation ) { - if ( !body2 ) { - offset *= rotation; - relAxis *= rotation.ToMat3(); - } -} - -/* -================ -idAFConstraint_Fixed::GetCenter -================ -*/ -void idAFConstraint_Fixed::GetCenter( idVec3 ¢er ) { - center = body1->GetWorldOrigin(); -} - -/* -================ -idAFConstraint_Fixed::DebugDraw -================ -*/ -void idAFConstraint_Fixed::DebugDraw( void ) { - idAFBody *master; - - master = body2 ? body2 : physics->GetMasterBody(); - if ( master ) { - gameRenderWorld->DebugLine( colorRed, body1->GetWorldOrigin(), master->GetWorldOrigin() ); - } - else { - gameRenderWorld->DebugLine( colorRed, body1->GetWorldOrigin(), vec3_origin ); - } -} - -/* -================ -idAFConstraint_Fixed::Save -================ -*/ -void idAFConstraint_Fixed::Save( idSaveGame *saveFile ) const { - idAFConstraint::Save( saveFile ); - saveFile->WriteVec3( offset ); - saveFile->WriteMat3( relAxis ); -} - -/* -================ -idAFConstraint_Fixed::Restore -================ -*/ -void idAFConstraint_Fixed::Restore( idRestoreGame *saveFile ) { - idAFConstraint::Restore( saveFile ); - saveFile->ReadVec3( offset ); - saveFile->ReadMat3( relAxis ); -} - - -//=============================================================== -// -// idAFConstraint_BallAndSocketJoint -// -//=============================================================== - -/* -================ -idAFConstraint_BallAndSocketJoint::idAFConstraint_BallAndSocketJoint -================ -*/ -idAFConstraint_BallAndSocketJoint::idAFConstraint_BallAndSocketJoint( const idStr &name, idAFBody *body1, idAFBody *body2 ) { - assert( body1 ); - type = CONSTRAINT_BALLANDSOCKETJOINT; - this->name = name; - this->body1 = body1; - this->body2 = body2; - InitSize( 3 ); - coneLimit = NULL; - pyramidLimit = NULL; - friction = 0.0f; - fc = NULL; - fl.allowPrimary = true; - fl.noCollision = true; -} - -/* -================ -idAFConstraint_BallAndSocketJoint::~idAFConstraint_BallAndSocketJoint -================ -*/ -idAFConstraint_BallAndSocketJoint::~idAFConstraint_BallAndSocketJoint( void ) { - if ( coneLimit ) { - delete coneLimit; - } - if ( pyramidLimit ) { - delete pyramidLimit; - } -} - -/* -================ -idAFConstraint_BallAndSocketJoint::SetAnchor -================ -*/ -void idAFConstraint_BallAndSocketJoint::SetAnchor( const idVec3 &worldPosition ) { - - // get anchor relative to center of mass of body1 - anchor1 = ( worldPosition - body1->GetWorldOrigin() ) * body1->GetWorldAxis().Transpose(); - if ( body2 ) { - // get anchor relative to center of mass of body2 - anchor2 = ( worldPosition - body2->GetWorldOrigin() ) * body2->GetWorldAxis().Transpose(); - } - else { - anchor2 = worldPosition; - } - - if ( coneLimit ) { - coneLimit->SetAnchor( anchor2 ); - } - if ( pyramidLimit ) { - pyramidLimit->SetAnchor( anchor2 ); - } -} - -/* -================ -idAFConstraint_BallAndSocketJoint::GetAnchor -================ -*/ -idVec3 idAFConstraint_BallAndSocketJoint::GetAnchor( void ) const { - if ( body2 ) { - return body2->GetWorldOrigin() + body2->GetWorldAxis() * anchor2; - } - return anchor2; -} - -/* -================ -idAFConstraint_BallAndSocketJoint::SetNoLimit -================ -*/ -void idAFConstraint_BallAndSocketJoint::SetNoLimit( void ) { - if ( coneLimit ) { - delete coneLimit; - coneLimit = NULL; - } - if ( pyramidLimit ) { - delete pyramidLimit; - pyramidLimit = NULL; - } -} - -/* -================ -idAFConstraint_BallAndSocketJoint::SetConeLimit -================ -*/ -void idAFConstraint_BallAndSocketJoint::SetConeLimit( const idVec3 &coneAxis, const float coneAngle, const idVec3 &body1Axis ) { - if ( pyramidLimit ) { - delete pyramidLimit; - pyramidLimit = NULL; - } - if ( !coneLimit ) { - coneLimit = new idAFConstraint_ConeLimit; - coneLimit->SetPhysics( physics ); - } - if ( body2 ) { - coneLimit->Setup( body1, body2, anchor2, coneAxis * body2->GetWorldAxis().Transpose(), coneAngle, body1Axis * body1->GetWorldAxis().Transpose() ); - } - else { - coneLimit->Setup( body1, body2, anchor2, coneAxis, coneAngle, body1Axis * body1->GetWorldAxis().Transpose() ); - } -} - -/* -================ -idAFConstraint_BallAndSocketJoint::SetPyramidLimit -================ -*/ -void idAFConstraint_BallAndSocketJoint::SetPyramidLimit( const idVec3 &pyramidAxis, const idVec3 &baseAxis, - const float angle1, const float angle2, const idVec3 &body1Axis ) { - if ( coneLimit ) { - delete coneLimit; - coneLimit = NULL; - } - if ( !pyramidLimit ) { - pyramidLimit = new idAFConstraint_PyramidLimit; - pyramidLimit->SetPhysics( physics ); - } - if ( body2 ) { - pyramidLimit->Setup( body1, body2, anchor2, pyramidAxis * body2->GetWorldAxis().Transpose(), - baseAxis * body2->GetWorldAxis().Transpose(), angle1, angle2, - body1Axis * body1->GetWorldAxis().Transpose() ); - } - else { - pyramidLimit->Setup( body1, body2, anchor2, pyramidAxis, baseAxis, angle1, angle2, - body1Axis * body1->GetWorldAxis().Transpose() ); - } -} - -/* -================ -idAFConstraint_BallAndSocketJoint::SetLimitEpsilon -================ -*/ -void idAFConstraint_BallAndSocketJoint::SetLimitEpsilon( const float e ) { - if ( coneLimit ) { - coneLimit->SetEpsilon( e ); - } - if ( pyramidLimit ) { - pyramidLimit->SetEpsilon( e ); - } -} - -/* -================ -idAFConstraint_BallAndSocketJoint::GetFriction -================ -*/ -float idAFConstraint_BallAndSocketJoint::GetFriction( void ) const { - if ( af_forceFriction.GetFloat() > 0.0f ) { - return af_forceFriction.GetFloat(); - } - return friction * physics->GetJointFrictionScale(); -} - -/* -================ -idAFConstraint_BallAndSocketJoint::Evaluate -================ -*/ -void idAFConstraint_BallAndSocketJoint::Evaluate( float invTimeStep ) { - idVec3 a1, a2; - idAFBody *master; - - master = body2 ? body2 : physics->GetMasterBody(); - - a1 = anchor1 * body1->GetWorldAxis(); - - if ( master ) { - a2 = anchor2 * master->GetWorldAxis(); - c1.SubVec3(0) = -( invTimeStep * ERROR_REDUCTION ) * ( a2 + master->GetWorldOrigin() - ( a1 + body1->GetWorldOrigin() ) ); - } - else { - a2.Zero(); - c1.SubVec3(0) = -( invTimeStep * ERROR_REDUCTION ) * ( anchor2 - ( a1 + body1->GetWorldOrigin() ) ); - } - - c1.Clamp( -ERROR_REDUCTION_MAX, ERROR_REDUCTION_MAX ); - - J1.Set( mat3_identity, -SkewSymmetric( a1 ) ); - - if ( body2 ) { - J2.Set( -mat3_identity, SkewSymmetric( a2 ) ); - } - else { - J2.Zero( 3, 6 ); - } - - if ( coneLimit ) { - coneLimit->Add( physics, invTimeStep ); - } - else if ( pyramidLimit ) { - pyramidLimit->Add( physics, invTimeStep ); - } -} - -/* -================ -idAFConstraint_BallAndSocketJoint::ApplyFriction -================ -*/ -void idAFConstraint_BallAndSocketJoint::ApplyFriction( float invTimeStep ) { - idVec3 angular; - float invMass, currentFriction; - - currentFriction = GetFriction(); - - if ( currentFriction <= 0.0f ) { - return; - } - - if ( af_useImpulseFriction.GetBool() || af_useJointImpulseFriction.GetBool() ) { - - angular = body1->GetAngularVelocity(); - invMass = body1->GetInverseMass(); - if ( body2 ) { - angular -= body2->GetAngularVelocity(); - invMass += body2->GetInverseMass(); - } - - angular *= currentFriction / invMass; - - body1->SetAngularVelocity( body1->GetAngularVelocity() - angular * body1->GetInverseMass() ); - if ( body2 ) { - body2->SetAngularVelocity( body2->GetAngularVelocity() + angular * body2->GetInverseMass() ); - } - } - else { - if ( !fc ) { - fc = new idAFConstraint_BallAndSocketJointFriction; - fc->Setup( this ); - } - - fc->Add( physics, invTimeStep ); - } -} - -/* -================ -idAFConstraint_BallAndSocketJoint::GetForce -================ -*/ -void idAFConstraint_BallAndSocketJoint::GetForce( idAFBody *body, idVec6 &force ) { - idAFConstraint::GetForce( body, force ); - // FIXME: add limit force -} - -/* -================ -idAFConstraint_BallAndSocketJoint::Translate -================ -*/ -void idAFConstraint_BallAndSocketJoint::Translate( const idVec3 &translation ) { - if ( !body2 ) { - anchor2 += translation; - } - if ( coneLimit ) { - coneLimit->Translate( translation ); - } - else if ( pyramidLimit ) { - pyramidLimit->Translate( translation ); - } -} - -/* -================ -idAFConstraint_BallAndSocketJoint::Rotate -================ -*/ -void idAFConstraint_BallAndSocketJoint::Rotate( const idRotation &rotation ) { - if ( !body2 ) { - anchor2 *= rotation; - } - if ( coneLimit ) { - coneLimit->Rotate( rotation ); - } - else if ( pyramidLimit ) { - pyramidLimit->Rotate( rotation ); - } -} - -/* -================ -idAFConstraint_BallAndSocketJoint::GetCenter -================ -*/ -void idAFConstraint_BallAndSocketJoint::GetCenter( idVec3 ¢er ) { - center = body1->GetWorldOrigin() + anchor1 * body1->GetWorldAxis(); -} - -/* -================ -idAFConstraint_BallAndSocketJoint::DebugDraw -================ -*/ -void idAFConstraint_BallAndSocketJoint::DebugDraw( void ) { - idVec3 a1 = body1->GetWorldOrigin() + anchor1 * body1->GetWorldAxis(); - gameRenderWorld->DebugLine( colorBlue, a1 - idVec3( 5, 0, 0 ), a1 + idVec3( 5, 0, 0 ) ); - gameRenderWorld->DebugLine( colorBlue, a1 - idVec3( 0, 5, 0 ), a1 + idVec3( 0, 5, 0 ) ); - gameRenderWorld->DebugLine( colorBlue, a1 - idVec3( 0, 0, 5 ), a1 + idVec3( 0, 0, 5 ) ); - - if ( af_showLimits.GetBool() ) { - if ( coneLimit ) { - coneLimit->DebugDraw(); - } - if ( pyramidLimit ) { - pyramidLimit->DebugDraw(); - } - } -} - -/* -================ -idAFConstraint_BallAndSocketJoint::Save -================ -*/ -void idAFConstraint_BallAndSocketJoint::Save( idSaveGame *saveFile ) const { - idAFConstraint::Save( saveFile ); - saveFile->WriteVec3( anchor1 ); - saveFile->WriteVec3( anchor2 ); - saveFile->WriteFloat( friction ); - if ( coneLimit ) { - coneLimit->Save( saveFile ); - } - if ( pyramidLimit ) { - pyramidLimit->Save( saveFile ); - } -} - -/* -================ -idAFConstraint_BallAndSocketJoint::Restore -================ -*/ -void idAFConstraint_BallAndSocketJoint::Restore( idRestoreGame *saveFile ) { - idAFConstraint::Restore( saveFile ); - saveFile->ReadVec3( anchor1 ); - saveFile->ReadVec3( anchor2 ); - saveFile->ReadFloat( friction ); - if ( coneLimit ) { - coneLimit->Restore( saveFile ); - } - if ( pyramidLimit ) { - pyramidLimit->Restore( saveFile ); - } -} - - -//=============================================================== -// -// idAFConstraint_BallAndSocketJointFriction -// -//=============================================================== - -/* -================ -idAFConstraint_BallAndSocketJointFriction::idAFConstraint_BallAndSocketJointFriction -================ -*/ -idAFConstraint_BallAndSocketJointFriction::idAFConstraint_BallAndSocketJointFriction( void ) { - type = CONSTRAINT_FRICTION; - name = "ballAndSocketJointFriction"; - InitSize( 3 ); - joint = NULL; - fl.allowPrimary = false; - fl.frameConstraint = true; -} - -/* -================ -idAFConstraint_BallAndSocketJointFriction::Setup -================ -*/ -void idAFConstraint_BallAndSocketJointFriction::Setup( idAFConstraint_BallAndSocketJoint *bsj ) { - this->joint = bsj; - body1 = bsj->GetBody1(); - body2 = bsj->GetBody2(); -} - -/* -================ -idAFConstraint_BallAndSocketJointFriction::Evaluate -================ -*/ -void idAFConstraint_BallAndSocketJointFriction::Evaluate( float invTimeStep ) { - // do nothing -} - -/* -================ -idAFConstraint_BallAndSocketJointFriction::ApplyFriction -================ -*/ -void idAFConstraint_BallAndSocketJointFriction::ApplyFriction( float invTimeStep ) { - // do nothing -} - -/* -================ -idAFConstraint_BallAndSocketJointFriction::Add -================ -*/ -bool idAFConstraint_BallAndSocketJointFriction::Add( idPhysics_AF *phys, float invTimeStep ) { - float f; - - physics = phys; - - f = joint->GetFriction() * joint->GetMultiplier().Length(); - if ( f == 0.0f ) { - return false; - } - - lo[0] = lo[1] = lo[2] = -f; - hi[0] = hi[1] = hi[2] = f; - - J1.Zero( 3, 6 ); - J1[0][3] = J1[1][4] = J1[2][5] = 1.0f; - - if ( body2 ) { - - J2.Zero( 3, 6 ); - J2[0][3] = J2[1][4] = J2[2][5] = 1.0f; - } - - physics->AddFrameConstraint( this ); - - return true; -} - -/* -================ -idAFConstraint_BallAndSocketJointFriction::Translate -================ -*/ -void idAFConstraint_BallAndSocketJointFriction::Translate( const idVec3 &translation ) { -} - -/* -================ -idAFConstraint_BallAndSocketJointFriction::Rotate -================ -*/ -void idAFConstraint_BallAndSocketJointFriction::Rotate( const idRotation &rotation ) { -} - - -//=============================================================== -// -// idAFConstraint_UniversalJoint -// -//=============================================================== - -/* -================ -idAFConstraint_UniversalJoint::idAFConstraint_UniversalJoint -================ -*/ -idAFConstraint_UniversalJoint::idAFConstraint_UniversalJoint( const idStr &name, idAFBody *body1, idAFBody *body2 ) { - assert( body1 ); - type = CONSTRAINT_UNIVERSALJOINT; - this->name = name; - this->body1 = body1; - this->body2 = body2; - InitSize( 4 ); - coneLimit = NULL; - pyramidLimit = NULL; - friction = 0.0f; - fc = NULL; - fl.allowPrimary = true; - fl.noCollision = true; -} - -/* -================ -idAFConstraint_UniversalJoint::~idAFConstraint_UniversalJoint -================ -*/ -idAFConstraint_UniversalJoint::~idAFConstraint_UniversalJoint( void ) { - if ( coneLimit ) { - delete coneLimit; - } - if ( pyramidLimit ) { - delete pyramidLimit; - } - if ( fc ) { - delete fc; - } -} - -/* -================ -idAFConstraint_UniversalJoint::SetAnchor -================ -*/ -void idAFConstraint_UniversalJoint::SetAnchor( const idVec3 &worldPosition ) { - - // get anchor relative to center of mass of body1 - anchor1 = ( worldPosition - body1->GetWorldOrigin() ) * body1->GetWorldAxis().Transpose(); - if ( body2 ) { - // get anchor relative to center of mass of body2 - anchor2 = ( worldPosition - body2->GetWorldOrigin() ) * body2->GetWorldAxis().Transpose(); - } - else { - anchor2 = worldPosition; - } - - if ( coneLimit ) { - coneLimit->SetAnchor( anchor2 ); - } - if ( pyramidLimit ) { - pyramidLimit->SetAnchor( anchor2 ); - } -} - -/* -================ -idAFConstraint_UniversalJoint::GetAnchor -================ -*/ -idVec3 idAFConstraint_UniversalJoint::GetAnchor( void ) const { - if ( body2 ) { - return body2->GetWorldOrigin() + body2->GetWorldAxis() * anchor2; - } - return anchor2; -} - -/* -================ -idAFConstraint_UniversalJoint::SetShafts -================ -*/ -void idAFConstraint_UniversalJoint::SetShafts( const idVec3 &cardanShaft1, const idVec3 &cardanShaft2 ) { - idVec3 cardanAxis; - float l id_attribute((unused)); - - shaft1 = cardanShaft1; - l = shaft1.Normalize(); - assert( l != 0.0f ); - shaft2 = cardanShaft2; - l = shaft2.Normalize(); - assert( l != 0.0f ); - - // the cardan axis is a vector orthogonal to both cardan shafts - cardanAxis = shaft1.Cross( shaft2 ); - if ( cardanAxis.Normalize() == 0.0f ) { - idVec3 vecY; - shaft1.OrthogonalBasis( cardanAxis, vecY ); - cardanAxis.Normalize(); - } - - shaft1 *= body1->GetWorldAxis().Transpose(); - axis1 = cardanAxis * body1->GetWorldAxis().Transpose(); - if ( body2 ) { - shaft2 *= body2->GetWorldAxis().Transpose(); - axis2 = cardanAxis * body2->GetWorldAxis().Transpose(); - } - else { - axis2 = cardanAxis; - } - - if ( coneLimit ) { - coneLimit->SetBody1Axis( shaft1 ); - } - if ( pyramidLimit ) { - pyramidLimit->SetBody1Axis( shaft1 ); - } -} - -/* -================ -idAFConstraint_UniversalJoint::SetNoLimit -================ -*/ -void idAFConstraint_UniversalJoint::SetNoLimit( void ) { - if ( coneLimit ) { - delete coneLimit; - coneLimit = NULL; - } - if ( pyramidLimit ) { - delete pyramidLimit; - pyramidLimit = NULL; - } -} - -/* -================ -idAFConstraint_UniversalJoint::SetConeLimit -================ -*/ -void idAFConstraint_UniversalJoint::SetConeLimit( const idVec3 &coneAxis, const float coneAngle ) { - if ( pyramidLimit ) { - delete pyramidLimit; - pyramidLimit = NULL; - } - if ( !coneLimit ) { - coneLimit = new idAFConstraint_ConeLimit; - coneLimit->SetPhysics( physics ); - } - if ( body2 ) { - coneLimit->Setup( body1, body2, anchor2, coneAxis * body2->GetWorldAxis().Transpose(), coneAngle, shaft1 ); - } - else { - coneLimit->Setup( body1, body2, anchor2, coneAxis, coneAngle, shaft1 ); - } -} - -/* -================ -idAFConstraint_UniversalJoint::SetPyramidLimit -================ -*/ -void idAFConstraint_UniversalJoint::SetPyramidLimit( const idVec3 &pyramidAxis, const idVec3 &baseAxis, - const float angle1, const float angle2 ) { - if ( coneLimit ) { - delete coneLimit; - coneLimit = NULL; - } - if ( !pyramidLimit ) { - pyramidLimit = new idAFConstraint_PyramidLimit; - pyramidLimit->SetPhysics( physics ); - } - if ( body2 ) { - pyramidLimit->Setup( body1, body2, anchor2, pyramidAxis * body2->GetWorldAxis().Transpose(), - baseAxis * body2->GetWorldAxis().Transpose(), angle1, angle2, shaft1 ); - } - else { - pyramidLimit->Setup( body1, body2, anchor2, pyramidAxis, baseAxis, angle1, angle2, shaft1 ); - } -} - -/* -================ -idAFConstraint_UniversalJoint::SetLimitEpsilon -================ -*/ -void idAFConstraint_UniversalJoint::SetLimitEpsilon( const float e ) { - if ( coneLimit ) { - coneLimit->SetEpsilon( e ); - } - if ( pyramidLimit ) { - pyramidLimit->SetEpsilon( e ); - } -} - -/* -================ -idAFConstraint_UniversalJoint::GetFriction -================ -*/ -float idAFConstraint_UniversalJoint::GetFriction( void ) const { - if ( af_forceFriction.GetFloat() > 0.0f ) { - return af_forceFriction.GetFloat(); - } - return friction * physics->GetJointFrictionScale(); -} - -/* -================ -idAFConstraint_UniversalJoint::Evaluate - - NOTE: this joint is homokinetic -================ -*/ -void idAFConstraint_UniversalJoint::Evaluate( float invTimeStep ) { - idVec3 a1, a2, s1, s2, d1, d2, v; - idAFBody *master; - - master = body2 ? body2 : physics->GetMasterBody(); - - a1 = anchor1 * body1->GetWorldAxis(); - s1 = shaft1 * body1->GetWorldAxis(); - d1 = s1.Cross( axis1 * body1->GetWorldAxis() ); - - if ( master ) { - a2 = anchor2 * master->GetWorldAxis(); - s2 = shaft2 * master->GetWorldAxis(); - d2 = axis2 * master->GetWorldAxis(); - c1.SubVec3(0) = -( invTimeStep * ERROR_REDUCTION ) * ( a2 + master->GetWorldOrigin() - ( a1 + body1->GetWorldOrigin() ) ); - } - else { - a2 = anchor2; - s2 = shaft2; - d2 = axis2; - c1.SubVec3(0) = -( invTimeStep * ERROR_REDUCTION ) * ( a2 - ( a1 + body1->GetWorldOrigin() ) ); - } - - J1.Set( mat3_identity, -SkewSymmetric( a1 ), - mat3_zero, idMat3( s1[0], s1[1], s1[2], - 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f ) ); - J1.SetSize( 4, 6 ); - - if ( body2 ) { - J2.Set( -mat3_identity, SkewSymmetric( a2 ), - mat3_zero, idMat3( s2[0], s2[1], s2[2], - 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f ) ); - J2.SetSize( 4, 6 ); - } - else { - J2.Zero( 4, 6 ); - } - - v = s1.Cross( s2 ); - if ( v.Normalize() != 0.0f ) { - idMat3 m1, m2; - - m1[0] = s1; - m1[1] = v; - m1[2] = v.Cross( m1[0] ); - - m2[0] = -s2; - m2[1] = v; - m2[2] = v.Cross( m2[0] ); - - d2 *= m2.Transpose() * m1; - } - - c1[3] = -( invTimeStep * ERROR_REDUCTION ) * ( d1 * d2 ); - - c1.Clamp( -ERROR_REDUCTION_MAX, ERROR_REDUCTION_MAX ); - - if ( coneLimit ) { - coneLimit->Add( physics, invTimeStep ); - } - else if ( pyramidLimit ) { - pyramidLimit->Add( physics, invTimeStep ); - } -} - -/* -================ -idAFConstraint_UniversalJoint::ApplyFriction -================ -*/ -void idAFConstraint_UniversalJoint::ApplyFriction( float invTimeStep ) { - idVec3 angular; - float invMass, currentFriction; - - currentFriction = GetFriction(); - - if ( currentFriction <= 0.0f ) { - return; - } - - if ( af_useImpulseFriction.GetBool() || af_useJointImpulseFriction.GetBool() ) { - - angular = body1->GetAngularVelocity(); - invMass = body1->GetInverseMass(); - if ( body2 ) { - angular -= body2->GetAngularVelocity(); - invMass += body2->GetInverseMass(); - } - - angular *= currentFriction / invMass; - - body1->SetAngularVelocity( body1->GetAngularVelocity() - angular * body1->GetInverseMass() ); - if ( body2 ) { - body2->SetAngularVelocity( body2->GetAngularVelocity() + angular * body2->GetInverseMass() ); - } - } - else { - if ( !fc ) { - fc = new idAFConstraint_UniversalJointFriction; - fc->Setup( this ); - } - - fc->Add( physics, invTimeStep ); - } -} - -/* -================ -idAFConstraint_UniversalJoint::GetForce -================ -*/ -void idAFConstraint_UniversalJoint::GetForce( idAFBody *body, idVec6 &force ) { - idAFConstraint::GetForce( body, force ); - // FIXME: add limit force -} - -/* -================ -idAFConstraint_UniversalJoint::Translate -================ -*/ -void idAFConstraint_UniversalJoint::Translate( const idVec3 &translation ) { - if ( !body2 ) { - anchor2 += translation; - } - if ( coneLimit ) { - coneLimit->Translate( translation ); - } - else if ( pyramidLimit ) { - pyramidLimit->Translate( translation ); - } -} - -/* -================ -idAFConstraint_UniversalJoint::Rotate -================ -*/ -void idAFConstraint_UniversalJoint::Rotate( const idRotation &rotation ) { - if ( !body2 ) { - anchor2 *= rotation; - shaft2 *= rotation.ToMat3(); - axis2 *= rotation.ToMat3(); - } - if ( coneLimit ) { - coneLimit->Rotate( rotation ); - } - else if ( pyramidLimit ) { - pyramidLimit->Rotate( rotation ); - } -} - -/* -================ -idAFConstraint_UniversalJoint::GetCenter -================ -*/ -void idAFConstraint_UniversalJoint::GetCenter( idVec3 ¢er ) { - center = body1->GetWorldOrigin() + anchor1 * body1->GetWorldAxis(); -} - -/* -================ -idAFConstraint_UniversalJoint::DebugDraw -================ -*/ -void idAFConstraint_UniversalJoint::DebugDraw( void ) { - idVec3 a1, a2, s1, s2, d1, d2, v; - idAFBody *master; - - master = body2 ? body2 : physics->GetMasterBody(); - - a1 = body1->GetWorldOrigin() + anchor1 * body1->GetWorldAxis(); - s1 = shaft1 * body1->GetWorldAxis(); - d1 = axis1 * body1->GetWorldAxis(); - - if ( master ) { - a2 = master->GetWorldOrigin() + anchor2 * master->GetWorldAxis(); - s2 = shaft2 * master->GetWorldAxis(); - d2 = axis2 * master->GetWorldAxis(); - } - else { - a2 = anchor2; - s2 = shaft2; - d2 = axis2; - } - - v = s1.Cross( s2 ); - if ( v.Normalize() != 0.0f ) { - idMat3 m1, m2; - - m1[0] = s1; - m1[1] = v; - m1[2] = v.Cross( m1[0] ); - - m2[0] = -s2; - m2[1] = v; - m2[2] = v.Cross( m2[0] ); - - d2 *= m2.Transpose() * m1; - } - - gameRenderWorld->DebugArrow( colorCyan, a1, a1 + s1 * 5.0f, 1.0f ); - gameRenderWorld->DebugArrow( colorBlue, a2, a2 + s2 * 5.0f, 1.0f ); - gameRenderWorld->DebugLine( colorGreen, a1, a1 + d1 * 5.0f ); - gameRenderWorld->DebugLine( colorGreen, a2, a2 + d2 * 5.0f ); - - if ( af_showLimits.GetBool() ) { - if ( coneLimit ) { - coneLimit->DebugDraw(); - } - if ( pyramidLimit ) { - pyramidLimit->DebugDraw(); - } - } -} - -/* -================ -idAFConstraint_UniversalJoint::Save -================ -*/ -void idAFConstraint_UniversalJoint::Save( idSaveGame *saveFile ) const { - idAFConstraint::Save( saveFile ); - saveFile->WriteVec3( anchor1 ); - saveFile->WriteVec3( anchor2 ); - saveFile->WriteVec3( shaft1 ); - saveFile->WriteVec3( shaft2 ); - saveFile->WriteVec3( axis1 ); - saveFile->WriteVec3( axis2 ); - saveFile->WriteFloat( friction ); - if ( coneLimit ) { - coneLimit->Save( saveFile ); - } - if ( pyramidLimit ) { - pyramidLimit->Save( saveFile ); - } -} - -/* -================ -idAFConstraint_UniversalJoint::Restore -================ -*/ -void idAFConstraint_UniversalJoint::Restore( idRestoreGame *saveFile ) { - idAFConstraint::Restore( saveFile ); - saveFile->ReadVec3( anchor1 ); - saveFile->ReadVec3( anchor2 ); - saveFile->ReadVec3( shaft1 ); - saveFile->ReadVec3( shaft2 ); - saveFile->ReadVec3( axis1 ); - saveFile->ReadVec3( axis2 ); - saveFile->ReadFloat( friction ); - if ( coneLimit ) { - coneLimit->Restore( saveFile ); - } - if ( pyramidLimit ) { - pyramidLimit->Restore( saveFile ); - } -} - - -//=============================================================== -// -// idAFConstraint_UniversalJointFriction -// -//=============================================================== - -/* -================ -idAFConstraint_UniversalJointFriction::idAFConstraint_UniversalJointFriction -================ -*/ -idAFConstraint_UniversalJointFriction::idAFConstraint_UniversalJointFriction( void ) { - type = CONSTRAINT_FRICTION; - name = "universalJointFriction"; - InitSize( 2 ); - joint = NULL; - fl.allowPrimary = false; - fl.frameConstraint = true; -} - -/* -================ -idAFConstraint_UniversalJointFriction::Setup -================ -*/ -void idAFConstraint_UniversalJointFriction::Setup( idAFConstraint_UniversalJoint *uj ) { - this->joint = uj; - body1 = uj->GetBody1(); - body2 = uj->GetBody2(); -} - -/* -================ -idAFConstraint_UniversalJointFriction::Evaluate -================ -*/ -void idAFConstraint_UniversalJointFriction::Evaluate( float invTimeStep ) { - // do nothing -} - -/* -================ -idAFConstraint_UniversalJointFriction::ApplyFriction -================ -*/ -void idAFConstraint_UniversalJointFriction::ApplyFriction( float invTimeStep ) { - // do nothing -} - -/* -================ -idAFConstraint_UniversalJointFriction::Add -================ -*/ -bool idAFConstraint_UniversalJointFriction::Add( idPhysics_AF *phys, float invTimeStep ) { - idVec3 s1, s2, dir1, dir2; - float f; - - physics = phys; - - f = joint->GetFriction() * joint->GetMultiplier().Length(); - if ( f == 0.0f ) { - return false; - } - - lo[0] = lo[1] = -f; - hi[0] = hi[1] = f; - - joint->GetShafts( s1, s2 ); - - s1 *= body1->GetWorldAxis(); - s1.NormalVectors( dir1, dir2 ); - - J1.SetSize( 2, 6 ); - J1.SubVec6(0).SubVec3(0).Zero(); - J1.SubVec6(0).SubVec3(1) = dir1; - J1.SubVec6(1).SubVec3(0).Zero(); - J1.SubVec6(1).SubVec3(1) = dir2; - - if ( body2 ) { - - J2.SetSize( 2, 6 ); - J2.SubVec6(0).SubVec3(0).Zero(); - J2.SubVec6(0).SubVec3(1) = -dir1; - J2.SubVec6(1).SubVec3(0).Zero(); - J2.SubVec6(1).SubVec3(1) = -dir2; - } - - physics->AddFrameConstraint( this ); - - return true; -} - -/* -================ -idAFConstraint_UniversalJointFriction::Translate -================ -*/ -void idAFConstraint_UniversalJointFriction::Translate( const idVec3 &translation ) { -} - -/* -================ -idAFConstraint_UniversalJointFriction::Rotate -================ -*/ -void idAFConstraint_UniversalJointFriction::Rotate( const idRotation &rotation ) { -} - - -//=============================================================== -// -// idAFConstraint_CylindricalJoint -// -//=============================================================== - -/* -================ -idAFConstraint_CylindricalJoint::idAFConstraint_CylindricalJoint -================ -*/ -idAFConstraint_CylindricalJoint::idAFConstraint_CylindricalJoint( const idStr &name, idAFBody *body1, idAFBody *body2 ) { - assert( 0 ); // FIXME: implement -} - -/* -================ -idAFConstraint_CylindricalJoint::Evaluate -================ -*/ -void idAFConstraint_CylindricalJoint::Evaluate( float invTimeStep ) { - assert( 0 ); // FIXME: implement -} - -/* -================ -idAFConstraint_CylindricalJoint::ApplyFriction -================ -*/ -void idAFConstraint_CylindricalJoint::ApplyFriction( float invTimeStep ) { - assert( 0 ); // FIXME: implement -} - -/* -================ -idAFConstraint_CylindricalJoint::Translate -================ -*/ -void idAFConstraint_CylindricalJoint::Translate( const idVec3 &translation ) { - assert( 0 ); // FIXME: implement -} - -/* -================ -idAFConstraint_CylindricalJoint::Rotate -================ -*/ -void idAFConstraint_CylindricalJoint::Rotate( const idRotation &rotation ) { - assert( 0 ); // FIXME: implement -} - -/* -================ -idAFConstraint_CylindricalJoint::DebugDraw -================ -*/ -void idAFConstraint_CylindricalJoint::DebugDraw( void ) { - assert( 0 ); // FIXME: implement -} - - -//=============================================================== -// -// idAFConstraint_Hinge -// -//=============================================================== - -/* -================ -idAFConstraint_Hinge::idAFConstraint_Hinge -================ -*/ -idAFConstraint_Hinge::idAFConstraint_Hinge( const idStr &name, idAFBody *body1, idAFBody *body2 ) { - assert( body1 ); - type = CONSTRAINT_HINGE; - this->name = name; - this->body1 = body1; - this->body2 = body2; - InitSize( 5 ); - coneLimit = NULL; - steering = NULL; - friction = 0.0f; - fc = NULL; - fl.allowPrimary = true; - fl.noCollision = true; - initialAxis = body1->GetWorldAxis(); - if ( body2 ) { - initialAxis *= body2->GetWorldAxis().Transpose(); - } -} - -/* -================ -idAFConstraint_Hinge::~idAFConstraint_Hinge -================ -*/ -idAFConstraint_Hinge::~idAFConstraint_Hinge( void ) { - if ( coneLimit ) { - delete coneLimit; - } - if ( fc ) { - delete fc; - } - if ( steering ) { - delete steering; - } -} - -/* -================ -idAFConstraint_Hinge::SetAnchor -================ -*/ -void idAFConstraint_Hinge::SetAnchor( const idVec3 &worldPosition ) { - // get anchor relative to center of mass of body1 - anchor1 = ( worldPosition - body1->GetWorldOrigin() ) * body1->GetWorldAxis().Transpose(); - if ( body2 ) { - // get anchor relative to center of mass of body2 - anchor2 = ( worldPosition - body2->GetWorldOrigin() ) * body2->GetWorldAxis().Transpose(); - } - else { - anchor2 = worldPosition; - } - - if ( coneLimit ) { - coneLimit->SetAnchor( anchor2 ); - } -} - -/* -================ -idAFConstraint_Hinge::GetAnchor -================ -*/ -idVec3 idAFConstraint_Hinge::GetAnchor( void ) const { - if ( body2 ) { - return body2->GetWorldOrigin() + body2->GetWorldAxis() * anchor2; - } - return anchor2; -} - -/* -================ -idAFConstraint_Hinge::SetAxis -================ -*/ -void idAFConstraint_Hinge::SetAxis( const idVec3 &axis ) { - idVec3 normAxis; - - normAxis = axis; - normAxis.Normalize(); - - // get axis relative to body1 - axis1 = normAxis * body1->GetWorldAxis().Transpose(); - if ( body2 ) { - // get axis relative to body2 - axis2 = normAxis * body2->GetWorldAxis().Transpose(); - } - else { - axis2 = normAxis; - } -} - -/* -================ -idAFConstraint_Hinge::GetAxis -================ -*/ -idVec3 idAFConstraint_Hinge::GetAxis( void ) const { - if ( body2 ) { - return axis2 * body2->GetWorldAxis(); - } - return axis2; -} - -/* -================ -idAFConstraint_Hinge::SetNoLimit -================ -*/ -void idAFConstraint_Hinge::SetNoLimit( void ) { - if ( coneLimit ) { - delete coneLimit; - coneLimit = NULL; - } -} - -/* -================ -idAFConstraint_Hinge::SetLimit -================ -*/ -void idAFConstraint_Hinge::SetLimit( const idVec3 &axis, const float angle, const idVec3 &body1Axis ) { - if ( !coneLimit ) { - coneLimit = new idAFConstraint_ConeLimit; - coneLimit->SetPhysics( physics ); - } - if ( body2 ) { - coneLimit->Setup( body1, body2, anchor2, axis * body2->GetWorldAxis().Transpose(), angle, body1Axis * body1->GetWorldAxis().Transpose() ); - } - else { - coneLimit->Setup( body1, body2, anchor2, axis, angle, body1Axis * body1->GetWorldAxis().Transpose() ); - } -} - -/* -================ -idAFConstraint_Hinge::SetLimitEpsilon -================ -*/ -void idAFConstraint_Hinge::SetLimitEpsilon( const float e ) { - if ( coneLimit ) { - coneLimit->SetEpsilon( e ); - } -} - -/* -================ -idAFConstraint_Hinge::GetFriction -================ -*/ -float idAFConstraint_Hinge::GetFriction( void ) const { - if ( af_forceFriction.GetFloat() > 0.0f ) { - return af_forceFriction.GetFloat(); - } - return friction * physics->GetJointFrictionScale(); -} - -/* -================ -idAFConstraint_Hinge::GetAngle -================ -*/ -float idAFConstraint_Hinge::GetAngle( void ) const { - idMat3 axis; - idRotation rotation; - float angle; - - axis = body1->GetWorldAxis() * body2->GetWorldAxis().Transpose() * initialAxis.Transpose(); - rotation = axis.ToRotation(); - angle = rotation.GetAngle(); - if ( rotation.GetVec() * axis1 < 0.0f ) { - return -angle; - } - return angle; -} - -/* -================ -idAFConstraint_Hinge::SetSteerAngle -================ -*/ -void idAFConstraint_Hinge::SetSteerAngle( const float degrees ) { - if ( coneLimit ) { - delete coneLimit; - coneLimit = NULL; - } - if ( !steering ) { - steering = new idAFConstraint_HingeSteering(); - steering->Setup( this ); - } - steering->SetSteerAngle( degrees ); -} - -/* -================ -idAFConstraint_Hinge::SetSteerSpeed -================ -*/ -void idAFConstraint_Hinge::SetSteerSpeed( const float speed ) { - if ( steering ) { - steering->SetSteerSpeed( speed ); - } -} - -/* -================ -idAFConstraint_Hinge::Evaluate -================ -*/ -void idAFConstraint_Hinge::Evaluate( float invTimeStep ) { - idVec3 a1, a2; - idVec3 x1, x2, cross; - idVec3 vecX, vecY; - idAFBody *master; - - master = body2 ? body2 : physics->GetMasterBody(); - - x1 = axis1 * body1->GetWorldAxis(); // axis in body1 space - x1.OrthogonalBasis( vecX, vecY ); // basis for axis in body1 space - - a1 = anchor1 * body1->GetWorldAxis(); // anchor in body1 space - - if ( master ) { - a2 = anchor2 * master->GetWorldAxis(); // anchor in master space - x2 = axis2 * master->GetWorldAxis(); - c1.SubVec3(0) = -( invTimeStep * ERROR_REDUCTION ) * ( a2 + master->GetWorldOrigin() - ( a1 + body1->GetWorldOrigin() ) ); - } - else { - a2 = anchor2; - x2 = axis2; - c1.SubVec3(0) = -( invTimeStep * ERROR_REDUCTION ) * ( a2 - ( a1 + body1->GetWorldOrigin() ) ); - } - - J1.Set( mat3_identity, -SkewSymmetric( a1 ), - mat3_zero, idMat3( vecX[0], vecX[1], vecX[2], - vecY[0], vecY[1], vecY[2], - 0.0f, 0.0f, 0.0f ) ); - J1.SetSize( 5, 6 ); - - if ( body2 ) { - J2.Set( -mat3_identity, SkewSymmetric( a2 ), - mat3_zero, idMat3( -vecX[0], -vecX[1], -vecX[2], - -vecY[0], -vecY[1], -vecY[2], - 0.0f, 0.0f, 0.0f ) ); - J2.SetSize( 5, 6 ); - } - else { - J2.Zero( 5, 6 ); - } - - cross = x1.Cross( x2 ); - - c1[3] = -( invTimeStep * ERROR_REDUCTION ) * ( cross * vecX ); - c1[4] = -( invTimeStep * ERROR_REDUCTION ) * ( cross * vecY ); - - c1.Clamp( -ERROR_REDUCTION_MAX, ERROR_REDUCTION_MAX ); - - if ( steering ) { - steering->Add( physics, invTimeStep ); - } - else if ( coneLimit ) { - coneLimit->Add( physics, invTimeStep ); - } -} - -/* -================ -idAFConstraint_Hinge::ApplyFriction -================ -*/ -void idAFConstraint_Hinge::ApplyFriction( float invTimeStep ) { - idVec3 angular; - float invMass, currentFriction; - - currentFriction = GetFriction(); - - if ( currentFriction <= 0.0f ) { - return; - } - - if ( af_useImpulseFriction.GetBool() || af_useJointImpulseFriction.GetBool() ) { - - angular = body1->GetAngularVelocity(); - invMass = body1->GetInverseMass(); - if ( body2 ) { - angular -= body2->GetAngularVelocity(); - invMass += body2->GetInverseMass(); - } - - angular *= currentFriction / invMass; - - body1->SetAngularVelocity( body1->GetAngularVelocity() - angular * body1->GetInverseMass() ); - if ( body2 ) { - body2->SetAngularVelocity( body2->GetAngularVelocity() + angular * body2->GetInverseMass() ); - } - } - else { - if ( !fc ) { - fc = new idAFConstraint_HingeFriction; - fc->Setup( this ); - } - - fc->Add( physics, invTimeStep ); - } -} - -/* -================ -idAFConstraint_Hinge::GetForce -================ -*/ -void idAFConstraint_Hinge::GetForce( idAFBody *body, idVec6 &force ) { - idAFConstraint::GetForce( body, force ); - // FIXME: add limit force -} - -/* -================ -idAFConstraint_Hinge::Translate -================ -*/ -void idAFConstraint_Hinge::Translate( const idVec3 &translation ) { - if ( !body2 ) { - anchor2 += translation; - } - if ( coneLimit ) { - coneLimit->Translate( translation ); - } -} - -/* -================ -idAFConstraint_Hinge::Rotate -================ -*/ -void idAFConstraint_Hinge::Rotate( const idRotation &rotation ) { - if ( !body2 ) { - anchor2 *= rotation; - axis2 *= rotation.ToMat3(); - } - if ( coneLimit ) { - coneLimit->Rotate( rotation ); - } -} - -/* -================ -idAFConstraint_Hinge::GetCenter -================ -*/ -void idAFConstraint_Hinge::GetCenter( idVec3 ¢er ) { - center = body1->GetWorldOrigin() + anchor1 * body1->GetWorldAxis(); -} - -/* -================ -idAFConstraint_Hinge::DebugDraw -================ -*/ -void idAFConstraint_Hinge::DebugDraw( void ) { - idVec3 vecX, vecY; - idVec3 a1 = body1->GetWorldOrigin() + anchor1 * body1->GetWorldAxis(); - idVec3 x1 = axis1 * body1->GetWorldAxis(); - x1.OrthogonalBasis( vecX, vecY ); - - gameRenderWorld->DebugArrow( colorBlue, a1 - 4.0f * x1, a1 + 4.0f * x1, 1 ); - gameRenderWorld->DebugLine( colorBlue, a1 - 2.0f * vecX, a1 + 2.0f * vecX ); - gameRenderWorld->DebugLine( colorBlue, a1 - 2.0f * vecY, a1 + 2.0f * vecY ); - - if ( af_showLimits.GetBool() ) { - if ( coneLimit ) { - coneLimit->DebugDraw(); - } - } -} - -/* -================ -idAFConstraint_Hinge::Save -================ -*/ -void idAFConstraint_Hinge::Save( idSaveGame *saveFile ) const { - idAFConstraint::Save( saveFile ); - saveFile->WriteVec3( anchor1 ); - saveFile->WriteVec3( anchor2 ); - saveFile->WriteVec3( axis1 ); - saveFile->WriteVec3( axis2 ); - saveFile->WriteMat3( initialAxis ); - saveFile->WriteFloat( friction ); - if ( coneLimit ) { - saveFile->WriteBool( true ); - coneLimit->Save( saveFile ); - } else { - saveFile->WriteBool( false ); - } - if ( steering ) { - saveFile->WriteBool( true ); - steering->Save( saveFile ); - } else { - saveFile->WriteBool( false ); - } - if ( fc ) { - saveFile->WriteBool( true ); - fc->Save( saveFile ); - } else { - saveFile->WriteBool( false ); - } -} - -/* -================ -idAFConstraint_Hinge::Restore -================ -*/ -void idAFConstraint_Hinge::Restore( idRestoreGame *saveFile ) { - bool b; - idAFConstraint::Restore( saveFile ); - saveFile->ReadVec3( anchor1 ); - saveFile->ReadVec3( anchor2 ); - saveFile->ReadVec3( axis1 ); - saveFile->ReadVec3( axis2 ); - saveFile->ReadMat3( initialAxis ); - saveFile->ReadFloat( friction ); - - saveFile->ReadBool( b ); - if ( b ) { - if ( !coneLimit ) { - coneLimit = new idAFConstraint_ConeLimit; - } - coneLimit->SetPhysics( physics ); - coneLimit->Restore( saveFile ); - } - saveFile->ReadBool( b ); - if ( b ) { - if ( !steering ) { - steering = new idAFConstraint_HingeSteering; - } - steering->Setup( this ); - steering->Restore( saveFile ); - } - saveFile->ReadBool( b ); - if ( b ) { - if ( !fc ) { - fc = new idAFConstraint_HingeFriction; - } - fc->Setup( this ); - fc->Restore( saveFile ); - } -} - - -//=============================================================== -// -// idAFConstraint_HingeFriction -// -//=============================================================== - -/* -================ -idAFConstraint_HingeFriction::idAFConstraint_HingeFriction -================ -*/ -idAFConstraint_HingeFriction::idAFConstraint_HingeFriction( void ) { - type = CONSTRAINT_FRICTION; - name = "hingeFriction"; - InitSize( 1 ); - hinge = NULL; - fl.allowPrimary = false; - fl.frameConstraint = true; -} - -/* -================ -idAFConstraint_HingeFriction::Setup -================ -*/ -void idAFConstraint_HingeFriction::Setup( idAFConstraint_Hinge *h ) { - this->hinge = h; - body1 = h->GetBody1(); - body2 = h->GetBody2(); -} - -/* -================ -idAFConstraint_HingeFriction::Evaluate -================ -*/ -void idAFConstraint_HingeFriction::Evaluate( float invTimeStep ) { - // do nothing -} - -/* -================ -idAFConstraint_HingeFriction::ApplyFriction -================ -*/ -void idAFConstraint_HingeFriction::ApplyFriction( float invTimeStep ) { - // do nothing -} - -/* -================ -idAFConstraint_HingeFriction::Add -================ -*/ -bool idAFConstraint_HingeFriction::Add( idPhysics_AF *phys, float invTimeStep ) { - idVec3 a1, a2; - float f; - - physics = phys; - - f = hinge->GetFriction() * hinge->GetMultiplier().Length(); - if ( f == 0.0f ) { - return false; - } - - lo[0] = -f; - hi[0] = f; - - hinge->GetAxis( a1, a2 ); - - a1 *= body1->GetWorldAxis(); - - J1.SetSize( 1, 6 ); - J1.SubVec6(0).SubVec3(0).Zero(); - J1.SubVec6(0).SubVec3(1) = a1; - - if ( body2 ) { - a2 *= body2->GetWorldAxis(); - - J2.SetSize( 1, 6 ); - J2.SubVec6(0).SubVec3(0).Zero(); - J2.SubVec6(0).SubVec3(1) = -a2; - } - - physics->AddFrameConstraint( this ); - - return true; -} - -/* -================ -idAFConstraint_HingeFriction::Translate -================ -*/ -void idAFConstraint_HingeFriction::Translate( const idVec3 &translation ) { -} - -/* -================ -idAFConstraint_HingeFriction::Rotate -================ -*/ -void idAFConstraint_HingeFriction::Rotate( const idRotation &rotation ) { -} - - -//=============================================================== -// -// idAFConstraint_HingeSteering -// -//=============================================================== - -/* -================ -idAFConstraint_HingeSteering::idAFConstraint_HingeSteering -================ -*/ -idAFConstraint_HingeSteering::idAFConstraint_HingeSteering( void ) { - type = CONSTRAINT_HINGESTEERING; - name = "hingeFriction"; - InitSize( 1 ); - hinge = NULL; - fl.allowPrimary = false; - fl.frameConstraint = true; - steerSpeed = 0.0f; - epsilon = LCP_EPSILON; -} - -/* -================ -idAFConstraint_HingeSteering::Save -================ -*/ -void idAFConstraint_HingeSteering::Save( idSaveGame *saveFile ) const { - saveFile->WriteFloat(steerAngle); - saveFile->WriteFloat(steerSpeed); - saveFile->WriteFloat(epsilon); -} - -/* -================ -idAFConstraint_HingeSteering::Restore -================ -*/ -void idAFConstraint_HingeSteering::Restore( idRestoreGame *saveFile ) { - saveFile->ReadFloat(steerAngle); - saveFile->ReadFloat(steerSpeed); - saveFile->ReadFloat(epsilon); -} - -/* -================ -idAFConstraint_HingeSteering::Setup -================ -*/ -void idAFConstraint_HingeSteering::Setup( idAFConstraint_Hinge *h ) { - this->hinge = h; - body1 = h->GetBody1(); - body2 = h->GetBody2(); -} - -/* -================ -idAFConstraint_HingeSteering::Evaluate -================ -*/ -void idAFConstraint_HingeSteering::Evaluate( float invTimeStep ) { - // do nothing -} - -/* -================ -idAFConstraint_HingeSteering::ApplyFriction -================ -*/ -void idAFConstraint_HingeSteering::ApplyFriction( float invTimeStep ) { - // do nothing -} - -/* -================ -idAFConstraint_HingeSteering::Add -================ -*/ -bool idAFConstraint_HingeSteering::Add( idPhysics_AF *phys, float invTimeStep ) { - float angle, speed; - idVec3 a1, a2; - - physics = phys; - - hinge->GetAxis( a1, a2 ); - angle = hinge->GetAngle(); - - a1 *= body1->GetWorldAxis(); - - J1.SetSize( 1, 6 ); - J1.SubVec6(0).SubVec3(0).Zero(); - J1.SubVec6(0).SubVec3(1) = a1; - - if ( body2 ) { - a2 *= body2->GetWorldAxis(); - - J2.SetSize( 1, 6 ); - J2.SubVec6(0).SubVec3(0).Zero(); - J2.SubVec6(0).SubVec3(1) = -a2; - } - - speed = steerAngle - angle; - if ( steerSpeed != 0.0f ) { - if ( speed > steerSpeed ) { - speed = steerSpeed; - } - else if ( speed < -steerSpeed ) { - speed = -steerSpeed; - } - } - - c1[0] = DEG2RAD( speed ) * invTimeStep; - - physics->AddFrameConstraint( this ); - - return true; -} - -/* -================ -idAFConstraint_HingeSteering::Translate -================ -*/ -void idAFConstraint_HingeSteering::Translate( const idVec3 &translation ) { -} - -/* -================ -idAFConstraint_HingeSteering::Rotate -================ -*/ -void idAFConstraint_HingeSteering::Rotate( const idRotation &rotation ) { -} - - -//=============================================================== -// -// idAFConstraint_Slider -// -//=============================================================== - -/* -================ -idAFConstraint_Slider::idAFConstraint_Slider -================ -*/ -idAFConstraint_Slider::idAFConstraint_Slider( const idStr &name, idAFBody *body1, idAFBody *body2 ) { - assert( body1 ); - type = CONSTRAINT_SLIDER; - this->name = name; - this->body1 = body1; - this->body2 = body2; - InitSize( 5 ); - fl.allowPrimary = true; - fl.noCollision = true; - - if ( body2 ) { - offset = ( body1->GetWorldOrigin() - body2->GetWorldOrigin() ) * body1->GetWorldAxis().Transpose(); - relAxis = body1->GetWorldAxis() * body2->GetWorldAxis().Transpose(); - } - else { - offset = body1->GetWorldOrigin(); - relAxis = body1->GetWorldAxis(); - } -} - -/* -================ -idAFConstraint_Slider::SetAxis -================ -*/ -void idAFConstraint_Slider::SetAxis( const idVec3 &ax ) { - idVec3 normAxis; - - // get normalized axis relative to body1 - normAxis = ax; - normAxis.Normalize(); - if ( body2 ) { - axis = normAxis * body2->GetWorldAxis().Transpose(); - } - else { - axis = normAxis; - } -} - -/* -================ -idAFConstraint_Slider::Evaluate -================ -*/ -void idAFConstraint_Slider::Evaluate( float invTimeStep ) { - idVec3 vecX, vecY, ofs; - idRotation r; - idAFBody *master; - - master = body2 ? body2 : physics->GetMasterBody(); - - if ( master ) { - (axis * master->GetWorldAxis()).OrthogonalBasis( vecX, vecY ); - ofs = master->GetWorldOrigin() + master->GetWorldAxis() * offset - body1->GetWorldOrigin(); - r = ( body1->GetWorldAxis().Transpose() * (relAxis * master->GetWorldAxis()) ).ToRotation(); - } - else { - axis.OrthogonalBasis( vecX, vecY ); - ofs = offset - body1->GetWorldOrigin(); - r = ( body1->GetWorldAxis().Transpose() * relAxis ).ToRotation(); - } - - J1.Set( mat3_zero, mat3_identity, - idMat3( vecX, vecY, vec3_origin ), mat3_zero ); - J1.SetSize( 5, 6 ); - - if ( body2 ) { - - J2.Set( mat3_zero, -mat3_identity, - idMat3( -vecX, -vecY, vec3_origin ), mat3_zero ); - J2.SetSize( 5, 6 ); - } - else { - J2.Zero( 5, 6 ); - } - - c1.SubVec3(0) = -( invTimeStep * ERROR_REDUCTION ) * ( r.GetVec() * - (float) DEG2RAD( r.GetAngle() ) ); - - c1[3] = -( invTimeStep * ERROR_REDUCTION ) * ( vecX * ofs ); - c1[4] = -( invTimeStep * ERROR_REDUCTION ) * ( vecY * ofs ); - - c1.Clamp( -ERROR_REDUCTION_MAX, ERROR_REDUCTION_MAX ); -} - -/* -================ -idAFConstraint_Slider::ApplyFriction -================ -*/ -void idAFConstraint_Slider::ApplyFriction( float invTimeStep ) { - // no friction -} - -/* -================ -idAFConstraint_Slider::Translate -================ -*/ -void idAFConstraint_Slider::Translate( const idVec3 &translation ) { - if ( !body2 ) { - offset += translation; - } -} - -/* -================ -idAFConstraint_Slider::Rotate -================ -*/ -void idAFConstraint_Slider::Rotate( const idRotation &rotation ) { - if ( !body2 ) { - offset *= rotation; - } -} - -/* -================ -idAFConstraint_Slider::GetCenter -================ -*/ -void idAFConstraint_Slider::GetCenter( idVec3 ¢er ) { - idAFBody *master; - - master = body2 ? body2 : physics->GetMasterBody(); - if ( master ) { - center = master->GetWorldOrigin() + master->GetWorldAxis() * offset - body1->GetWorldOrigin(); - } - else { - center = offset - body1->GetWorldOrigin(); - } -} - -/* -================ -idAFConstraint_Slider::DebugDraw -================ -*/ -void idAFConstraint_Slider::DebugDraw( void ) { - idVec3 ofs; - idAFBody *master; - - master = body2 ? body2 : physics->GetMasterBody(); - if ( master ) { - ofs = master->GetWorldOrigin() + master->GetWorldAxis() * offset - body1->GetWorldOrigin(); - } - else { - ofs = offset - body1->GetWorldOrigin(); - } - gameRenderWorld->DebugLine( colorGreen, ofs, ofs + axis * body1->GetWorldAxis() ); -} - -/* -================ -idAFConstraint_Slider::Save -================ -*/ -void idAFConstraint_Slider::Save( idSaveGame *saveFile ) const { - idAFConstraint::Save( saveFile ); - saveFile->WriteVec3( axis ); - saveFile->WriteVec3( offset ); - saveFile->WriteMat3( relAxis ); -} - -/* -================ -idAFConstraint_Slider::Restore -================ -*/ -void idAFConstraint_Slider::Restore( idRestoreGame *saveFile ) { - idAFConstraint::Restore( saveFile ); - saveFile->ReadVec3( axis ); - saveFile->ReadVec3( offset ); - saveFile->ReadMat3( relAxis ); -} - - -//=============================================================== -// -// idAFConstraint_Line -// -//=============================================================== - -/* -================ -idAFConstraint_Line::idAFConstraint_Line -================ -*/ -idAFConstraint_Line::idAFConstraint_Line( const idStr &name, idAFBody *body1, idAFBody *body2 ) { - assert( 0 ); // FIXME: implement -} - -/* -================ -idAFConstraint_Line::Evaluate -================ -*/ -void idAFConstraint_Line::Evaluate( float invTimeStep ) { - assert( 0 ); // FIXME: implement -} - -/* -================ -idAFConstraint_Line::ApplyFriction -================ -*/ -void idAFConstraint_Line::ApplyFriction( float invTimeStep ) { - assert( 0 ); // FIXME: implement -} - -/* -================ -idAFConstraint_Line::Translate -================ -*/ -void idAFConstraint_Line::Translate( const idVec3 &translation ) { - assert( 0 ); // FIXME: implement -} - -/* -================ -idAFConstraint_Line::Rotate -================ -*/ -void idAFConstraint_Line::Rotate( const idRotation &rotation ) { - assert( 0 ); // FIXME: implement -} - -/* -================ -idAFConstraint_Line::DebugDraw -================ -*/ -void idAFConstraint_Line::DebugDraw( void ) { - assert( 0 ); // FIXME: implement -} - - -//=============================================================== -// -// idAFConstraint_Plane -// -//=============================================================== - -/* -================ -idAFConstraint_Plane::idAFConstraint_Plane -================ -*/ -idAFConstraint_Plane::idAFConstraint_Plane( const idStr &name, idAFBody *body1, idAFBody *body2 ) { - assert( body1 ); - type = CONSTRAINT_PLANE; - this->name = name; - this->body1 = body1; - this->body2 = body2; - InitSize( 1 ); - fl.allowPrimary = true; - fl.noCollision = true; -} - -/* -================ -idAFConstraint_Plane::SetPlane -================ -*/ -void idAFConstraint_Plane::SetPlane( const idVec3 &normal, const idVec3 &anchor ) { - // get anchor relative to center of mass of body1 - anchor1 = ( anchor - body1->GetWorldOrigin() ) * body1->GetWorldAxis().Transpose(); - if ( body2 ) { - // get anchor relative to center of mass of body2 - anchor2 = ( anchor - body2->GetWorldOrigin() ) * body2->GetWorldAxis().Transpose(); - planeNormal = normal * body2->GetWorldAxis().Transpose(); - } - else { - anchor2 = anchor; - planeNormal = normal; - } -} - -/* -================ -idAFConstraint_Plane::Evaluate -================ -*/ -void idAFConstraint_Plane::Evaluate( float invTimeStep ) { - idVec3 a1, a2, normal, p; - idVec6 v; - idAFBody *master; - - master = body2 ? body2 : physics->GetMasterBody(); - - a1 = body1->GetWorldOrigin() + anchor1 * body1->GetWorldAxis(); - if ( master ) { - a2 = master->GetWorldOrigin() + anchor2 * master->GetWorldAxis(); - normal = planeNormal * master->GetWorldAxis(); - } - else { - a2 = anchor2; - normal = planeNormal; - } - - p = a1 - body1->GetWorldOrigin(); - v.SubVec3(0) = normal; - v.SubVec3(1) = p.Cross( normal ); - J1.Set( 1, 6, v.ToFloatPtr() ); - - if ( body2 ) { - p = a1 - body2->GetWorldOrigin(); - v.SubVec3(0) = -normal; - v.SubVec3(1) = p.Cross( -normal ); - J2.Set( 1, 6, v.ToFloatPtr() ); - } - - c1[0] = -( invTimeStep * ERROR_REDUCTION ) * (a1 * normal - a2 * normal); - - c1.Clamp( -ERROR_REDUCTION_MAX, ERROR_REDUCTION_MAX ); -} - -/* -================ -idAFConstraint_Plane::ApplyFriction -================ -*/ -void idAFConstraint_Plane::ApplyFriction( float invTimeStep ) { - // no friction -} - -/* -================ -idAFConstraint_Plane::Translate -================ -*/ -void idAFConstraint_Plane::Translate( const idVec3 &translation ) { - if ( !body2 ) { - anchor2 += translation; - } -} - -/* -================ -idAFConstraint_Plane::Rotate -================ -*/ -void idAFConstraint_Plane::Rotate( const idRotation &rotation ) { - if ( !body2 ) { - anchor2 *= rotation; - planeNormal *= rotation.ToMat3(); - } -} - -/* -================ -idAFConstraint_Plane::DebugDraw -================ -*/ -void idAFConstraint_Plane::DebugDraw( void ) { - idVec3 a1, normal, right, up; - idAFBody *master; - - master = body2 ? body2 : physics->GetMasterBody(); - - a1 = body1->GetWorldOrigin() + anchor1 * body1->GetWorldAxis(); - if ( master ) { - normal = planeNormal * master->GetWorldAxis(); - } - else { - normal = planeNormal; - } - normal.NormalVectors( right, up ); - normal *= 4.0f; - right *= 4.0f; - up *= 4.0f; - - gameRenderWorld->DebugLine( colorCyan, a1 - right, a1 + right ); - gameRenderWorld->DebugLine( colorCyan, a1 - up, a1 + up ); - gameRenderWorld->DebugArrow( colorCyan, a1, a1 + normal, 1 ); -} - -/* -================ -idAFConstraint_Plane::Save -================ -*/ -void idAFConstraint_Plane::Save( idSaveGame *saveFile ) const { - idAFConstraint::Save( saveFile ); - saveFile->WriteVec3( anchor1 ); - saveFile->WriteVec3( anchor2 ); - saveFile->WriteVec3( planeNormal ); -} - -/* -================ -idAFConstraint_Plane::Restore -================ -*/ -void idAFConstraint_Plane::Restore( idRestoreGame *saveFile ) { - idAFConstraint::Restore( saveFile ); - saveFile->ReadVec3( anchor1 ); - saveFile->ReadVec3( anchor2 ); - saveFile->ReadVec3( planeNormal ); -} - - -//=============================================================== -// -// idAFConstraint_Spring -// -//=============================================================== - -/* -================ -idAFConstraint_Spring::idAFConstraint_Spring -================ -*/ -idAFConstraint_Spring::idAFConstraint_Spring( const idStr &name, idAFBody *body1, idAFBody *body2 ) { - assert( body1 ); - type = CONSTRAINT_SPRING; - this->name = name; - this->body1 = body1; - this->body2 = body2; - InitSize( 1 ); - fl.allowPrimary = false; - kstretch = kcompress = damping = 1.0f; - minLength = maxLength = restLength = 0.0f; -} - -/* -================ -idAFConstraint_Spring::SetAnchor -================ -*/ -void idAFConstraint_Spring::SetAnchor( const idVec3 &worldAnchor1, const idVec3 &worldAnchor2 ) { - // get anchor relative to center of mass of body1 - anchor1 = ( worldAnchor1 - body1->GetWorldOrigin() ) * body1->GetWorldAxis().Transpose(); - if ( body2 ) { - // get anchor relative to center of mass of body2 - anchor2 = ( worldAnchor2 - body2->GetWorldOrigin() ) * body2->GetWorldAxis().Transpose(); - } - else { - anchor2 = worldAnchor2; - } -} - -/* -================ -idAFConstraint_Spring::SetSpring -================ -*/ -void idAFConstraint_Spring::SetSpring( const float stretch, const float compress, const float damping, const float restLength ) { - assert( stretch >= 0.0f && compress >= 0.0f && restLength >= 0.0f ); - this->kstretch = stretch; - this->kcompress = compress; - this->damping = damping; - this->restLength = restLength; -} - -/* -================ -idAFConstraint_Spring::SetLimit -================ -*/ -void idAFConstraint_Spring::SetLimit( const float minLength, const float maxLength ) { - assert( minLength >= 0.0f && maxLength >= 0.0f && maxLength >= minLength ); - this->minLength = minLength; - this->maxLength = maxLength; -} - -/* -================ -idAFConstraint_Spring::Evaluate -================ -*/ -void idAFConstraint_Spring::Evaluate( float invTimeStep ) { - idVec3 a1, a2, velocity1, velocity2, force; - idVec6 v1, v2; - float d, dampingForce, length, error; - bool limit; - idAFBody *master; - - master = body2 ? body2 : physics->GetMasterBody(); - - a1 = body1->GetWorldOrigin() + anchor1 * body1->GetWorldAxis(); - velocity1 = body1->GetPointVelocity( a1 ); - - if ( master ) { - a2 = master->GetWorldOrigin() + anchor2 * master->GetWorldAxis(); - velocity2 = master->GetPointVelocity( a2 ); - } - else { - a2 = anchor2; - velocity2.Zero(); - } - - force = a2 - a1; - d = force * force; - if ( d != 0.0f ) { - dampingForce = damping * idMath::Fabs( (velocity2 - velocity1) * force ) / d; - } - else { - dampingForce = 0.0f; - } - length = force.Normalize(); - - if ( length > restLength ) { - if ( kstretch > 0.0f ) { - idVec3 springForce = force * ( Square( length - restLength ) * kstretch - dampingForce ); - body1->AddForce( a1, springForce ); - if ( master ) { - master->AddForce( a2, -springForce ); - } - } - } - else { - if ( kcompress > 0.0f ) { - idVec3 springForce = force * -( Square( restLength - length ) * kcompress - dampingForce ); - body1->AddForce( a1, springForce ); - if ( master ) { - master->AddForce( a2, -springForce ); - } - } - } - - // check for spring limits - if ( length < minLength ) { - force = -force; - error = minLength - length; - limit = true; - } - else if ( maxLength > 0.0f && length > maxLength ) { - error = length - maxLength; - limit = true; - } - else { - error = 0.0f; - limit = false; - } - - if ( limit ) { - a1 -= body1->GetWorldOrigin(); - v1.SubVec3(0) = force; - v1.SubVec3(1) = a1.Cross( force ); - J1.Set( 1, 6, v1.ToFloatPtr() ); - if ( body2 ) { - a2 -= body2->GetWorldOrigin(); - v2.SubVec3(0) = -force; - v2.SubVec3(1) = a2.Cross( -force ); - J2.Set( 1, 6, v2.ToFloatPtr() ); - } - c1[0] = -( invTimeStep * ERROR_REDUCTION ) * error; - lo[0] = 0.0f; - } - else { - J1.Zero( 0, 0 ); - J2.Zero( 0, 0 ); - } - - c1.Clamp( -ERROR_REDUCTION_MAX, ERROR_REDUCTION_MAX ); -} - -/* -================ -idAFConstraint_Spring::ApplyFriction -================ -*/ -void idAFConstraint_Spring::ApplyFriction( float invTimeStep ) { - // no friction -} - -/* -================ -idAFConstraint_Spring::Translate -================ -*/ -void idAFConstraint_Spring::Translate( const idVec3 &translation ) { - if ( !body2 ) { - anchor2 += translation; - } -} - -/* -================ -idAFConstraint_Spring::Rotate -================ -*/ -void idAFConstraint_Spring::Rotate( const idRotation &rotation ) { - if ( !body2 ) { - anchor2 *= rotation; - } -} - -/* -================ -idAFConstraint_Spring::GetCenter -================ -*/ -void idAFConstraint_Spring::GetCenter( idVec3 ¢er ) { - idAFBody *master; - idVec3 a1, a2; - - master = body2 ? body2 : physics->GetMasterBody(); - a1 = body1->GetWorldOrigin() + anchor1 * body1->GetWorldAxis(); - if ( master ) { - a2 = master->GetWorldOrigin() + anchor2 * master->GetWorldAxis(); - } - else { - a2 = anchor2; - } - center = ( a1 + a2 ) * 0.5f; -} - -/* -================ -idAFConstraint_Spring::DebugDraw -================ -*/ -void idAFConstraint_Spring::DebugDraw( void ) { - idAFBody *master; - float length; - idVec3 a1, a2, dir, mid, p; - - master = body2 ? body2 : physics->GetMasterBody(); - a1 = body1->GetWorldOrigin() + anchor1 * body1->GetWorldAxis(); - if ( master ) { - a2 = master->GetWorldOrigin() + anchor2 * master->GetWorldAxis(); - } - else { - a2 = anchor2; - } - dir = a2 - a1; - mid = a1 + 0.5f * dir; - length = dir.Normalize(); - - // draw spring - gameRenderWorld->DebugLine( colorGreen, a1, a2 ); - - // draw rest length - p = restLength * 0.5f * dir; - gameRenderWorld->DebugCircle( colorWhite, mid + p, dir, 1.0f, 10 ); - gameRenderWorld->DebugCircle( colorWhite, mid - p, dir, 1.0f, 10 ); - if ( restLength > length ) { - gameRenderWorld->DebugLine( colorWhite, a2, mid + p ); - gameRenderWorld->DebugLine( colorWhite, a1, mid - p ); - } - - if ( minLength > 0.0f ) { - // draw min length - gameRenderWorld->DebugCircle( colorBlue, mid + minLength * 0.5f * dir, dir, 2.0f, 10 ); - gameRenderWorld->DebugCircle( colorBlue, mid - minLength * 0.5f * dir, dir, 2.0f, 10 ); - } - - if ( maxLength > 0.0f ) { - // draw max length - gameRenderWorld->DebugCircle( colorRed, mid + maxLength * 0.5f * dir, dir, 2.0f, 10 ); - gameRenderWorld->DebugCircle( colorRed, mid - maxLength * 0.5f * dir, dir, 2.0f, 10 ); - } -} - -/* -================ -idAFConstraint_Spring::Save -================ -*/ -void idAFConstraint_Spring::Save( idSaveGame *saveFile ) const { - idAFConstraint::Save( saveFile ); - saveFile->WriteVec3( anchor1 ); - saveFile->WriteVec3( anchor2 ); - saveFile->WriteFloat( kstretch ); - saveFile->WriteFloat( kcompress ); - saveFile->WriteFloat( damping ); - saveFile->WriteFloat( restLength ); - saveFile->WriteFloat( minLength ); - saveFile->WriteFloat( maxLength ); -} - -/* -================ -idAFConstraint_Spring::Restore -================ -*/ -void idAFConstraint_Spring::Restore( idRestoreGame *saveFile ) { - idAFConstraint::Restore( saveFile ); - saveFile->ReadVec3( anchor1 ); - saveFile->ReadVec3( anchor2 ); - saveFile->ReadFloat( kstretch ); - saveFile->ReadFloat( kcompress ); - saveFile->ReadFloat( damping ); - saveFile->ReadFloat( restLength ); - saveFile->ReadFloat( minLength ); - saveFile->ReadFloat( maxLength ); -} - - -//=============================================================== -// -// idAFConstraint_Contact -// -//=============================================================== - -/* -================ -idAFConstraint_Contact::idAFConstraint_Contact -================ -*/ -idAFConstraint_Contact::idAFConstraint_Contact( void ) { - name = "contact"; - type = CONSTRAINT_CONTACT; - InitSize( 1 ); - fc = NULL; - fl.allowPrimary = false; - fl.frameConstraint = true; -} - -/* -================ -idAFConstraint_Contact::~idAFConstraint_Contact -================ -*/ -idAFConstraint_Contact::~idAFConstraint_Contact( void ) { - if ( fc ) { - delete fc; - } -} - -/* -================ -idAFConstraint_Contact::Setup -================ -*/ -void idAFConstraint_Contact::Setup( idAFBody *b1, idAFBody *b2, contactInfo_t &c ) { - idVec3 p; - idVec6 v; - float vel; - float minBounceVelocity = 2.0f; - - assert( b1 ); - - body1 = b1; - body2 = b2; - contact = c; - - p = c.point - body1->GetWorldOrigin(); - v.SubVec3(0) = c.normal; - v.SubVec3(1) = p.Cross( c.normal ); - J1.Set( 1, 6, v.ToFloatPtr() ); - vel = v.SubVec3(0) * body1->GetLinearVelocity() + v.SubVec3(1) * body1->GetAngularVelocity(); - - if ( body2 ) { - p = c.point - body2->GetWorldOrigin(); - v.SubVec3(0) = -c.normal; - v.SubVec3(1) = p.Cross( -c.normal ); - J2.Set( 1, 6, v.ToFloatPtr() ); - vel += v.SubVec3(0) * body2->GetLinearVelocity() + v.SubVec3(1) * body2->GetAngularVelocity(); - c2[0] = 0.0f; - } - - if ( body1->GetBouncyness() > 0.0f && -vel > minBounceVelocity ) { - c1[0] = body1->GetBouncyness() * vel; - } - else { - c1[0] = 0.0f; - } - - e[0] = CONTACT_LCP_EPSILON; - lo[0] = 0.0f; - hi[0] = idMath::INFINITY; - boxConstraint = NULL; - boxIndex[0] = -1; -} - -/* -================ -idAFConstraint_Contact::Evaluate -================ -*/ -void idAFConstraint_Contact::Evaluate( float invTimeStep ) { - // do nothing -} - -/* -================ -idAFConstraint_Contact::ApplyFriction -================ -*/ -void idAFConstraint_Contact::ApplyFriction( float invTimeStep ) { - idVec3 r, velocity, normal, dir1, dir2; - float friction, magnitude, forceNumerator, forceDenominator; - idVecX impulse, dv; - - friction = body1->GetContactFriction(); - if ( body2 && body2->GetContactFriction() < friction ) { - friction = body2->GetContactFriction(); - } - - friction *= physics->GetContactFrictionScale(); - - if ( friction <= 0.0f ) { - return; - } - - // separate friction per contact is silly but it's fast and often looks close enough - if ( af_useImpulseFriction.GetBool() ) { - - impulse.SetData( 6, VECX_ALLOCA( 6 ) ); - dv.SetData( 6, VECX_ALLOCA( 6 ) ); - - // calculate velocity in the contact plane - r = contact.point - body1->GetWorldOrigin(); - velocity = body1->GetLinearVelocity() + body1->GetAngularVelocity().Cross( r ); - velocity -= contact.normal * velocity * contact.normal; - - // get normalized direction of friction and magnitude of velocity - normal = -velocity; - magnitude = normal.Normalize(); - - forceNumerator = friction * magnitude; - forceDenominator = body1->GetInverseMass() + ( ( body1->GetInverseWorldInertia() * r.Cross( normal ) ).Cross( r ) * normal ); - impulse.SubVec3(0) = (forceNumerator / forceDenominator) * normal; - impulse.SubVec3(1) = r.Cross( impulse.SubVec3(0) ); - body1->InverseWorldSpatialInertiaMultiply( dv, impulse.ToFloatPtr() ); - - // modify velocity with friction force - body1->SetLinearVelocity( body1->GetLinearVelocity() + dv.SubVec3(0) ); - body1->SetAngularVelocity( body1->GetAngularVelocity() + dv.SubVec3(1) ); - } - else { - - if ( !fc ) { - fc = new idAFConstraint_ContactFriction; - } - // call setup each frame because contact constraints are re-used for different bodies - fc->Setup( this ); - fc->Add( physics, invTimeStep ); - } -} - -/* -================ -idAFConstraint_Contact::Translate -================ -*/ -void idAFConstraint_Contact::Translate( const idVec3 &translation ) { - assert( 0 ); // contact should never be translated -} - -/* -================ -idAFConstraint_Contact::Rotate -================ -*/ -void idAFConstraint_Contact::Rotate( const idRotation &rotation ) { - assert( 0 ); // contact should never be rotated -} - -/* -================ -idAFConstraint_Contact::GetCenter -================ -*/ -void idAFConstraint_Contact::GetCenter( idVec3 ¢er ) { - center = contact.point; -} - -/* -================ -idAFConstraint_Contact::DebugDraw -================ -*/ -void idAFConstraint_Contact::DebugDraw( void ) { - idVec3 x, y; - contact.normal.NormalVectors( x, y ); - gameRenderWorld->DebugLine( colorWhite, contact.point, contact.point + 6.0f * contact.normal ); - gameRenderWorld->DebugLine( colorWhite, contact.point - 2.0f * x, contact.point + 2.0f * x ); - gameRenderWorld->DebugLine( colorWhite, contact.point - 2.0f * y, contact.point + 2.0f * y ); -} - - -//=============================================================== -// -// idAFConstraint_ContactFriction -// -//=============================================================== - -/* -================ -idAFConstraint_ContactFriction::idAFConstraint_ContactFriction -================ -*/ -idAFConstraint_ContactFriction::idAFConstraint_ContactFriction( void ) { - type = CONSTRAINT_FRICTION; - name = "contactFriction"; - InitSize( 2 ); - cc = NULL; - fl.allowPrimary = false; - fl.frameConstraint = true; -} - -/* -================ -idAFConstraint_ContactFriction::Setup -================ -*/ -void idAFConstraint_ContactFriction::Setup( idAFConstraint_Contact *cc ) { - this->cc = cc; - body1 = cc->GetBody1(); - body2 = cc->GetBody2(); -} - -/* -================ -idAFConstraint_ContactFriction::Evaluate -================ -*/ -void idAFConstraint_ContactFriction::Evaluate( float invTimeStep ) { - // do nothing -} - -/* -================ -idAFConstraint_ContactFriction::ApplyFriction -================ -*/ -void idAFConstraint_ContactFriction::ApplyFriction( float invTimeStep ) { - // do nothing -} - -/* -================ -idAFConstraint_ContactFriction::Add -================ -*/ -bool idAFConstraint_ContactFriction::Add( idPhysics_AF *phys, float invTimeStep ) { - idVec3 r, dir1, dir2; - float friction; - int newRow; - - physics = phys; - - friction = body1->GetContactFriction() * physics->GetContactFrictionScale(); - - // if the body only has friction in one direction - if ( body1->GetFrictionDirection( dir1 ) ) { - // project the friction direction into the contact plane - dir1 -= dir1 * cc->GetContact().normal * dir1; - dir1.Normalize(); - - r = cc->GetContact().point - body1->GetWorldOrigin(); - - J1.SetSize( 1, 6 ); - J1.SubVec6(0).SubVec3(0) = dir1; - J1.SubVec6(0).SubVec3(1) = r.Cross( dir1 ); - c1.SetSize( 1 ); - c1[0] = 0.0f; - - if ( body2 ) { - r = cc->GetContact().point - body2->GetWorldOrigin(); - - J2.SetSize( 1, 6 ); - J2.SubVec6(0).SubVec3(0) = -dir1; - J2.SubVec6(0).SubVec3(1) = r.Cross( -dir1 ); - c2.SetSize( 1 ); - c2[0] = 0.0f; - } - - lo[0] = -friction; - hi[0] = friction; - boxConstraint = cc; - boxIndex[0] = 0; - } - else { - // get two friction directions orthogonal to contact normal - cc->GetContact().normal.NormalVectors( dir1, dir2 ); - - r = cc->GetContact().point - body1->GetWorldOrigin(); - - J1.SetSize( 2, 6 ); - J1.SubVec6(0).SubVec3(0) = dir1; - J1.SubVec6(0).SubVec3(1) = r.Cross( dir1 ); - J1.SubVec6(1).SubVec3(0) = dir2; - J1.SubVec6(1).SubVec3(1) = r.Cross( dir2 ); - c1.SetSize( 2 ); - c1[0] = c1[1] = 0.0f; - - if ( body2 ) { - r = cc->GetContact().point - body2->GetWorldOrigin(); - - J2.SetSize( 2, 6 ); - J2.SubVec6(0).SubVec3(0) = -dir1; - J2.SubVec6(0).SubVec3(1) = r.Cross( -dir1 ); - J2.SubVec6(1).SubVec3(0) = -dir2; - J2.SubVec6(1).SubVec3(1) = r.Cross( -dir2 ); - c2.SetSize( 2 ); - c2[0] = c2[1] = 0.0f; - - if ( body2->GetContactFriction() < friction ) { - friction = body2->GetContactFriction(); - } - } - - lo[0] = -friction; - hi[0] = friction; - boxConstraint = cc; - boxIndex[0] = 0; - lo[1] = -friction; - hi[1] = friction; - boxIndex[1] = 0; - } - - if ( body1->GetContactMotorDirection( dir1 ) && body1->GetContactMotorForce() > 0.0f ) { - // project the motor force direction into the contact plane - dir1 -= dir1 * cc->GetContact().normal * dir1; - dir1.Normalize(); - - r = cc->GetContact().point - body1->GetWorldOrigin(); - - newRow = J1.GetNumRows(); - J1.ChangeSize( newRow+1, J1.GetNumColumns() ); - J1.SubVec6(newRow).SubVec3(0) = -dir1; - J1.SubVec6(newRow).SubVec3(1) = r.Cross( -dir1 ); - c1.ChangeSize( newRow+1 ); - c1[newRow] = body1->GetContactMotorVelocity(); - - if ( body2 ) { - r = cc->GetContact().point - body2->GetWorldOrigin(); - - J2.ChangeSize( newRow+1, J2.GetNumColumns() ); - J2.SubVec6(newRow).SubVec3(0) = -dir1; - J2.SubVec6(newRow).SubVec3(1) = r.Cross( -dir1 ); - c2.ChangeSize( newRow+1 ); - c2[newRow] = 0.0f; - } - - lo[newRow] = -body1->GetContactMotorForce(); - hi[newRow] = body1->GetContactMotorForce(); - boxIndex[newRow] = -1; - } - - physics->AddFrameConstraint( this ); - - return true; -} - -/* -================ -idAFConstraint_ContactFriction::Translate -================ -*/ -void idAFConstraint_ContactFriction::Translate( const idVec3 &translation ) { -} - -/* -================ -idAFConstraint_ContactFriction::Rotate -================ -*/ -void idAFConstraint_ContactFriction::Rotate( const idRotation &rotation ) { -} - -/* -================ -idAFConstraint_ContactFriction::DebugDraw -================ -*/ -void idAFConstraint_ContactFriction::DebugDraw( void ) { -} - - -//=============================================================== -// -// idAFConstraint_ConeLimit -// -//=============================================================== - -/* -================ -idAFConstraint_ConeLimit::idAFConstraint_ConeLimit -================ -*/ -idAFConstraint_ConeLimit::idAFConstraint_ConeLimit( void ) { - type = CONSTRAINT_CONELIMIT; - name = "coneLimit"; - InitSize( 1 ); - fl.allowPrimary = false; - fl.frameConstraint = true; -} - -/* -================ -idAFConstraint_ConeLimit::Setup - - the coneAnchor is the top of the cone in body2 space - the coneAxis is the axis of the cone in body2 space - the coneAngle is the angle the cone hull makes at the top - the body1Axis is the axis in body1 space that should stay within the cone -================ -*/ -void idAFConstraint_ConeLimit::Setup( idAFBody *b1, idAFBody *b2, const idVec3 &coneAnchor, const idVec3 &coneAxis, const float coneAngle, const idVec3 &body1Axis ) { - this->body1 = b1; - this->body2 = b2; - this->coneAxis = coneAxis; - this->coneAxis.Normalize(); - this->coneAnchor = coneAnchor; - this->body1Axis = body1Axis; - this->body1Axis.Normalize(); - this->cosAngle = (float) cos( DEG2RAD( coneAngle * 0.5f ) ); - this->sinHalfAngle = (float) sin( DEG2RAD( coneAngle * 0.25f ) ); - this->cosHalfAngle = (float) cos( DEG2RAD( coneAngle * 0.25f ) ); -} - -/* -================ -idAFConstraint_ConeLimit::SetAnchor -================ -*/ -void idAFConstraint_ConeLimit::SetAnchor( const idVec3 &coneAnchor ) { - this->coneAnchor = coneAnchor; -} - -/* -================ -idAFConstraint_ConeLimit::SetBody1Axis -================ -*/ -void idAFConstraint_ConeLimit::SetBody1Axis( const idVec3 &body1Axis ) { - this->body1Axis = body1Axis; -} - -/* -================ -idAFConstraint_ConeLimit::Evaluate -================ -*/ -void idAFConstraint_ConeLimit::Evaluate( float invTimeStep ) { - // do nothing -} - -/* -================ -idAFConstraint_ConeLimit::ApplyFriction -================ -*/ -void idAFConstraint_ConeLimit::ApplyFriction( float invTimeStep ) { -} - -/* -================ -idAFConstraint_ConeLimit::Add -================ -*/ -bool idAFConstraint_ConeLimit::Add( idPhysics_AF *phys, float invTimeStep ) { - float a; - idVec6 J1row, J2row; - idVec3 ax, anchor, body1ax, normal, coneVector, p1, p2; - idQuat q; - idAFBody *master; - - if ( af_skipLimits.GetBool() ) { - lm.Zero(); // constraint exerts no force - return false; - } - - physics = phys; - - master = body2 ? body2 : physics->GetMasterBody(); - - if ( master ) { - ax = coneAxis * master->GetWorldAxis(); - anchor = master->GetWorldOrigin() + coneAnchor * master->GetWorldAxis(); - } - else { - ax = coneAxis; - anchor = coneAnchor; - } - - body1ax = body1Axis * body1->GetWorldAxis(); - - a = ax * body1ax; - - // if the body1 axis is inside the cone - if ( a > cosAngle ) { - lm.Zero(); // constraint exerts no force - return false; - } - - // calculate the inward cone normal for the position the body1 axis went outside the cone - normal = body1ax.Cross( ax ); - normal.Normalize(); - q.x = normal.x * sinHalfAngle; - q.y = normal.y * sinHalfAngle; - q.z = normal.z * sinHalfAngle; - q.w = cosHalfAngle; - coneVector = ax * q.ToMat3(); - normal = coneVector.Cross( ax ).Cross( coneVector ); - normal.Normalize(); - - p1 = anchor + 32.0f * coneVector - body1->GetWorldOrigin(); - - J1row.SubVec3(0) = normal; - J1row.SubVec3(1) = p1.Cross( normal ); - J1.Set( 1, 6, J1row.ToFloatPtr() ); - - c1[0] = (invTimeStep * LIMIT_ERROR_REDUCTION) * ( normal * (32.0f * body1ax) ); - - if ( body2 ) { - - p2 = anchor + 32.0f * coneVector - master->GetWorldOrigin(); - - J2row.SubVec3(0) = -normal; - J2row.SubVec3(1) = p2.Cross( -normal ); - J2.Set( 1, 6, J2row.ToFloatPtr() ); - - c2[0] = 0.0f; - } - - lo[0] = 0.0f; - e[0] = LIMIT_LCP_EPSILON; - - physics->AddFrameConstraint( this ); - - return true; -} - -/* -================ -idAFConstraint_ConeLimit::Translate -================ -*/ -void idAFConstraint_ConeLimit::Translate( const idVec3 &translation ) { - if ( !body2 ) { - coneAnchor += translation; - } -} - -/* -================ -idAFConstraint_ConeLimit::Rotate -================ -*/ -void idAFConstraint_ConeLimit::Rotate( const idRotation &rotation ) { - if ( !body2 ) { - coneAnchor *= rotation; - coneAxis *= rotation.ToMat3(); - } -} - -/* -================ -idAFConstraint_ConeLimit::DebugDraw -================ -*/ -void idAFConstraint_ConeLimit::DebugDraw( void ) { - idVec3 ax, anchor, x, y, z, start, end; - float sinAngle, a, size = 10.0f; - idAFBody *master; - - master = body2 ? body2 : physics->GetMasterBody(); - - if ( master ) { - ax = coneAxis * master->GetWorldAxis(); - anchor = master->GetWorldOrigin() + coneAnchor * master->GetWorldAxis(); - } - else { - ax = coneAxis; - anchor = coneAnchor; - } - - // draw body1 axis - gameRenderWorld->DebugLine( colorGreen, anchor, anchor + size * (body1Axis * body1->GetWorldAxis()) ); - - // draw cone - ax.NormalVectors( x, y ); - sinAngle = idMath::Sqrt( 1.0f - cosAngle * cosAngle ); - x *= size * sinAngle; - y *= size * sinAngle; - z = anchor + ax * size * cosAngle; - start = x + z; - for ( a = 0.0f; a < 360.0f; a += 45.0f ) { - end = x * (float) cos( DEG2RAD(a + 45.0f) ) + y * (float) sin( DEG2RAD(a + 45.0f) ) + z; - gameRenderWorld->DebugLine( colorMagenta, anchor, start ); - gameRenderWorld->DebugLine( colorMagenta, start, end ); - start = end; - } -} - -/* -================ -idAFConstraint_ConeLimit::Save -================ -*/ -void idAFConstraint_ConeLimit::Save( idSaveGame *saveFile ) const { - idAFConstraint::Save( saveFile ); - saveFile->WriteVec3( coneAnchor ); - saveFile->WriteVec3( coneAxis ); - saveFile->WriteVec3( body1Axis ); - saveFile->WriteFloat( cosAngle ); - saveFile->WriteFloat( sinHalfAngle ); - saveFile->WriteFloat( cosHalfAngle ); - saveFile->WriteFloat( epsilon ); -} - -/* -================ -idAFConstraint_ConeLimit::Restore -================ -*/ -void idAFConstraint_ConeLimit::Restore( idRestoreGame *saveFile ) { - idAFConstraint::Restore( saveFile ); - saveFile->ReadVec3( coneAnchor ); - saveFile->ReadVec3( coneAxis ); - saveFile->ReadVec3( body1Axis ); - saveFile->ReadFloat( cosAngle ); - saveFile->ReadFloat( sinHalfAngle ); - saveFile->ReadFloat( cosHalfAngle ); - saveFile->ReadFloat( epsilon ); -} - - -//=============================================================== -// -// idAFConstraint_PyramidLimit -// -//=============================================================== - -/* -================ -idAFConstraint_PyramidLimit::idAFConstraint_PyramidLimit -================ -*/ -idAFConstraint_PyramidLimit::idAFConstraint_PyramidLimit( void ) { - type = CONSTRAINT_PYRAMIDLIMIT; - name = "pyramidLimit"; - InitSize( 1 ); - fl.allowPrimary = false; - fl.frameConstraint = true; -} - -/* -================ -idAFConstraint_PyramidLimit::Setup -================ -*/ -void idAFConstraint_PyramidLimit::Setup( idAFBody *b1, idAFBody *b2, const idVec3 &pyramidAnchor, - const idVec3 &pyramidAxis, const idVec3 &baseAxis, - const float pyramidAngle1, const float pyramidAngle2, const idVec3 &body1Axis ) { - body1 = b1; - body2 = b2; - // setup the base and make sure the basis is orthonormal - pyramidBasis[2] = pyramidAxis; - pyramidBasis[2].Normalize(); - pyramidBasis[0] = baseAxis; - pyramidBasis[0] -= pyramidBasis[2] * baseAxis * pyramidBasis[2]; - pyramidBasis[0].Normalize(); - pyramidBasis[1] = pyramidBasis[0].Cross( pyramidBasis[2] ); - // pyramid top - this->pyramidAnchor = pyramidAnchor; - // angles - cosAngle[0] = (float) cos( DEG2RAD( pyramidAngle1 * 0.5f ) ); - cosAngle[1] = (float) cos( DEG2RAD( pyramidAngle2 * 0.5f ) ); - sinHalfAngle[0] = (float) sin( DEG2RAD( pyramidAngle1 * 0.25f ) ); - sinHalfAngle[1] = (float) sin( DEG2RAD( pyramidAngle2 * 0.25f ) ); - cosHalfAngle[0] = (float) cos( DEG2RAD( pyramidAngle1 * 0.25f ) ); - cosHalfAngle[1] = (float) cos( DEG2RAD( pyramidAngle2 * 0.25f ) ); - - this->body1Axis = body1Axis; -} - -/* -================ -idAFConstraint_PyramidLimit::SetAnchor -================ -*/ -void idAFConstraint_PyramidLimit::SetAnchor( const idVec3 &pyramidAnchor ) { - this->pyramidAnchor = pyramidAnchor; -} - -/* -================ -idAFConstraint_PyramidLimit::SetBody1Axis -================ -*/ -void idAFConstraint_PyramidLimit::SetBody1Axis( const idVec3 &body1Axis ) { - this->body1Axis = body1Axis; -} - -/* -================ -idAFConstraint_PyramidLimit::Evaluate -================ -*/ -void idAFConstraint_PyramidLimit::Evaluate( float invTimeStep ) { - // do nothing -} - -/* -================ -idAFConstraint_PyramidLimit::ApplyFriction -================ -*/ -void idAFConstraint_PyramidLimit::ApplyFriction( float invTimeStep ) { -} - -/* -================ -idAFConstraint_PyramidLimit::Add -================ -*/ -bool idAFConstraint_PyramidLimit::Add( idPhysics_AF *phys, float invTimeStep ) { - int i; - float a[2]; - idVec6 J1row, J2row; - idMat3 worldBase; - idVec3 anchor, body1ax, ax[2], v, normal, pyramidVector, p1, p2; - idQuat q; - idAFBody *master; - - if ( af_skipLimits.GetBool() ) { - lm.Zero(); // constraint exerts no force - return false; - } - - physics = phys; - master = body2 ? body2 : physics->GetMasterBody(); - - if ( master ) { - worldBase[0] = pyramidBasis[0] * master->GetWorldAxis(); - worldBase[1] = pyramidBasis[1] * master->GetWorldAxis(); - worldBase[2] = pyramidBasis[2] * master->GetWorldAxis(); - anchor = master->GetWorldOrigin() + pyramidAnchor * master->GetWorldAxis(); - } - else { - worldBase = pyramidBasis; - anchor = pyramidAnchor; - } - - body1ax = body1Axis * body1->GetWorldAxis(); - - for ( i = 0; i < 2; i++ ) { - ax[i] = body1ax - worldBase[!i] * body1ax * worldBase[!i]; - ax[i].Normalize(); - a[i] = worldBase[2] * ax[i]; - } - - // if the body1 axis is inside the pyramid - if ( a[0] > cosAngle[0] && a[1] > cosAngle[1] ) { - lm.Zero(); // constraint exerts no force - return false; - } - - // calculate the inward pyramid normal for the position the body1 axis went outside the pyramid - pyramidVector = worldBase[2]; - for ( i = 0; i < 2; i++ ) { - if ( a[i] <= cosAngle[i] ) { - v = ax[i].Cross( worldBase[2] ); - v.Normalize(); - q.x = v.x * sinHalfAngle[i]; - q.y = v.y * sinHalfAngle[i]; - q.z = v.z * sinHalfAngle[i]; - q.w = cosHalfAngle[i]; - pyramidVector *= q.ToMat3(); - } - } - normal = pyramidVector.Cross( worldBase[2] ).Cross( pyramidVector ); - normal.Normalize(); - - p1 = anchor + 32.0f * pyramidVector - body1->GetWorldOrigin(); - - J1row.SubVec3(0) = normal; - J1row.SubVec3(1) = p1.Cross( normal ); - J1.Set( 1, 6, J1row.ToFloatPtr() ); - - c1[0] = (invTimeStep * LIMIT_ERROR_REDUCTION) * ( normal * (32.0f * body1ax) ); - - if ( body2 ) { - - p2 = anchor + 32.0f * pyramidVector - master->GetWorldOrigin(); - - J2row.SubVec3(0) = -normal; - J2row.SubVec3(1) = p2.Cross( -normal ); - J2.Set( 1, 6, J2row.ToFloatPtr() ); - - c2[0] = 0.0f; - } - - lo[0] = 0.0f; - e[0] = LIMIT_LCP_EPSILON; - - physics->AddFrameConstraint( this ); - - return true; -} - -/* -================ -idAFConstraint_PyramidLimit::Translate -================ -*/ -void idAFConstraint_PyramidLimit::Translate( const idVec3 &translation ) { - if ( !body2 ) { - pyramidAnchor += translation; - } -} - -/* -================ -idAFConstraint_PyramidLimit::Rotate -================ -*/ -void idAFConstraint_PyramidLimit::Rotate( const idRotation &rotation ) { - if ( !body2 ) { - pyramidAnchor *= rotation; - pyramidBasis[0] *= rotation.ToMat3(); - pyramidBasis[1] *= rotation.ToMat3(); - pyramidBasis[2] *= rotation.ToMat3(); - } -} - -/* -================ -idAFConstraint_PyramidLimit::DebugDraw -================ -*/ -void idAFConstraint_PyramidLimit::DebugDraw( void ) { - int i; - float size = 10.0f; - idVec3 anchor, dir, p[4]; - idMat3 worldBase, m[2]; - idQuat q; - idAFBody *master; - - master = body2 ? body2 : physics->GetMasterBody(); - - if ( master ) { - worldBase[0] = pyramidBasis[0] * master->GetWorldAxis(); - worldBase[1] = pyramidBasis[1] * master->GetWorldAxis(); - worldBase[2] = pyramidBasis[2] * master->GetWorldAxis(); - anchor = master->GetWorldOrigin() + pyramidAnchor * master->GetWorldAxis(); - } - else { - worldBase = pyramidBasis; - anchor = pyramidAnchor; - } - - // draw body1 axis - gameRenderWorld->DebugLine( colorGreen, anchor, anchor + size * (body1Axis * body1->GetWorldAxis()) ); - - // draw the pyramid - for ( i = 0; i < 2; i++ ) { - q.x = worldBase[!i].x * sinHalfAngle[i]; - q.y = worldBase[!i].y * sinHalfAngle[i]; - q.z = worldBase[!i].z * sinHalfAngle[i]; - q.w = cosHalfAngle[i]; - m[i] = q.ToMat3(); - } - - dir = worldBase[2] * size; - p[0] = anchor + m[0] * (m[1] * dir); - p[1] = anchor + m[0] * (m[1].Transpose() * dir); - p[2] = anchor + m[0].Transpose() * (m[1].Transpose() * dir); - p[3] = anchor + m[0].Transpose() * (m[1] * dir); - - for ( i = 0; i < 4; i++ ) { - gameRenderWorld->DebugLine( colorMagenta, anchor, p[i] ); - gameRenderWorld->DebugLine( colorMagenta, p[i], p[(i+1)&3] ); - } -} - -/* -================ -idAFConstraint_PyramidLimit::Save -================ -*/ -void idAFConstraint_PyramidLimit::Save( idSaveGame *saveFile ) const { - idAFConstraint::Save( saveFile ); - saveFile->WriteVec3( pyramidAnchor ); - saveFile->WriteMat3( pyramidBasis ); - saveFile->WriteVec3( body1Axis ); - saveFile->WriteFloat( cosAngle[0] ); - saveFile->WriteFloat( cosAngle[1] ); - saveFile->WriteFloat( sinHalfAngle[0] ); - saveFile->WriteFloat( sinHalfAngle[1] ); - saveFile->WriteFloat( cosHalfAngle[0] ); - saveFile->WriteFloat( cosHalfAngle[1] ); - saveFile->WriteFloat( epsilon ); -} - -/* -================ -idAFConstraint_PyramidLimit::Restore -================ -*/ -void idAFConstraint_PyramidLimit::Restore( idRestoreGame *saveFile ) { - idAFConstraint::Restore( saveFile ); - saveFile->ReadVec3( pyramidAnchor ); - saveFile->ReadMat3( pyramidBasis ); - saveFile->ReadVec3( body1Axis ); - saveFile->ReadFloat( cosAngle[0] ); - saveFile->ReadFloat( cosAngle[1] ); - saveFile->ReadFloat( sinHalfAngle[0] ); - saveFile->ReadFloat( sinHalfAngle[1] ); - saveFile->ReadFloat( cosHalfAngle[0] ); - saveFile->ReadFloat( cosHalfAngle[1] ); - saveFile->ReadFloat( epsilon ); -} - - -//=============================================================== -// -// idAFConstraint_Suspension -// -//=============================================================== - -/* -================ -idAFConstraint_Suspension::idAFConstraint_Suspension -================ -*/ -idAFConstraint_Suspension::idAFConstraint_Suspension( void ) { - type = CONSTRAINT_SUSPENSION; - name = "suspension"; - InitSize( 3 ); - fl.allowPrimary = false; - fl.frameConstraint = true; - - localOrigin.Zero(); - localAxis.Identity(); - suspensionUp = 0.0f; - suspensionDown = 0.0f; - suspensionKCompress = 0.0f; - suspensionDamping = 0.0f; - steerAngle = 0.0f; - friction = 2.0f; - motorEnabled = false; - motorForce = 0.0f; - motorVelocity = 0.0f; - wheelModel = NULL; - memset( &trace, 0, sizeof( trace ) ); - epsilon = LCP_EPSILON; -} - -/* -================ -idAFConstraint_Suspension::Setup -================ -*/ -void idAFConstraint_Suspension::Setup( const char *name, idAFBody *body, const idVec3 &origin, const idMat3 &axis, idClipModel *clipModel ) { - this->name = name; - body1 = body; - body2 = NULL; - localOrigin = ( origin - body->GetWorldOrigin() ) * body->GetWorldAxis().Transpose(); - localAxis = axis * body->GetWorldAxis().Transpose(); - wheelModel = clipModel; -} - -/* -================ -idAFConstraint_Suspension::SetSuspension -================ -*/ -void idAFConstraint_Suspension::SetSuspension( const float up, const float down, const float k, const float d, const float f ) { - suspensionUp = up; - suspensionDown = down; - suspensionKCompress = k; - suspensionDamping = d; - friction = f; -} - -/* -================ -idAFConstraint_Suspension::GetWheelOrigin -================ -*/ -const idVec3 idAFConstraint_Suspension::GetWheelOrigin( void ) const { - return body1->GetWorldOrigin() + wheelOffset * body1->GetWorldAxis(); -} - -/* -================ -idAFConstraint_Suspension::Evaluate -================ -*/ -void idAFConstraint_Suspension::Evaluate( float invTimeStep ) { - float velocity, suspensionLength, springLength, compression, dampingForce, springForce; - idVec3 origin, start, end, vel1, vel2, springDir, r, frictionDir, motorDir; - idMat3 axis; - idRotation rotation; - - axis = localAxis * body1->GetWorldAxis(); - origin = body1->GetWorldOrigin() + localOrigin * body1->GetWorldAxis(); - start = origin + suspensionUp * axis[2]; - end = origin - suspensionDown * axis[2]; - - rotation.SetVec( axis[2] ); - rotation.SetAngle( steerAngle ); - - axis *= rotation.ToMat3(); - - gameLocal.clip.Translation( trace, start, end, wheelModel, axis, MASK_SOLID, NULL ); - - wheelOffset = ( trace.endpos - body1->GetWorldOrigin() ) * body1->GetWorldAxis().Transpose(); - - if ( trace.fraction >= 1.0f ) { - J1.SetSize( 0, 6 ); - if ( body2 ) { - J2.SetSize( 0, 6 ); - } - return; - } - - // calculate and add spring force - vel1 = body1->GetPointVelocity( start ); - if ( body2 ) { - vel2 = body2->GetPointVelocity( trace.c.point ); - } else { - vel2.Zero(); - } - - suspensionLength = suspensionUp + suspensionDown; - springDir = trace.endpos - start; - springLength = trace.fraction * suspensionLength; - dampingForce = suspensionDamping * idMath::Fabs( ( vel2 - vel1 ) * springDir ) / ( 1.0f + springLength * springLength ); - compression = suspensionLength - springLength; - springForce = compression * compression * suspensionKCompress - dampingForce; - - r = trace.c.point - body1->GetWorldOrigin(); - J1.SetSize( 2, 6 ); - J1.SubVec6(0).SubVec3(0) = trace.c.normal; - J1.SubVec6(0).SubVec3(1) = r.Cross( trace.c.normal ); - c1.SetSize( 2 ); - c1[0] = 0.0f; - velocity = J1.SubVec6(0).SubVec3(0) * body1->GetLinearVelocity() + J1.SubVec6(0).SubVec3(1) * body1->GetAngularVelocity(); - - if ( body2 ) { - r = trace.c.point - body2->GetWorldOrigin(); - J2.SetSize( 2, 6 ); - J2.SubVec6(0).SubVec3(0) = -trace.c.normal; - J2.SubVec6(0).SubVec3(1) = r.Cross( -trace.c.normal ); - c2.SetSize( 2 ); - c2[0] = 0.0f; - velocity += J2.SubVec6(0).SubVec3(0) * body2->GetLinearVelocity() + J2.SubVec6(0).SubVec3(1) * body2->GetAngularVelocity(); - } - - c1[0] = -compression; // + 0.5f * -velocity; - - e[0] = 1e-4f; - lo[0] = 0.0f; - hi[0] = springForce; - boxConstraint = NULL; - boxIndex[0] = -1; - - // project the friction direction into the contact plane - frictionDir = axis[1] - axis[1] * trace.c.normal * axis[1]; - frictionDir.Normalize(); - - r = trace.c.point - body1->GetWorldOrigin(); - - J1.SubVec6(1).SubVec3(0) = frictionDir; - J1.SubVec6(1).SubVec3(1) = r.Cross( frictionDir ); - c1[1] = 0.0f; - - if ( body2 ) { - r = trace.c.point - body2->GetWorldOrigin(); - - J2.SubVec6(1).SubVec3(0) = -frictionDir; - J2.SubVec6(1).SubVec3(1) = r.Cross( -frictionDir ); - c2[1] = 0.0f; - } - - lo[1] = -friction * physics->GetContactFrictionScale(); - hi[1] = friction * physics->GetContactFrictionScale(); - - boxConstraint = this; - boxIndex[1] = 0; - - - if ( motorEnabled ) { - // project the motor force direction into the contact plane - motorDir = axis[0] - axis[0] * trace.c.normal * axis[0]; - motorDir.Normalize(); - - r = trace.c.point - body1->GetWorldOrigin(); - - J1.ChangeSize( 3, J1.GetNumColumns() ); - J1.SubVec6(2).SubVec3(0) = -motorDir; - J1.SubVec6(2).SubVec3(1) = r.Cross( -motorDir ); - c1.ChangeSize( 3 ); - c1[2] = motorVelocity; - - if ( body2 ) { - r = trace.c.point - body2->GetWorldOrigin(); - - J2.ChangeSize( 3, J2.GetNumColumns() ); - J2.SubVec6(2).SubVec3(0) = -motorDir; - J2.SubVec6(2).SubVec3(1) = r.Cross( -motorDir ); - c2.ChangeSize( 3 ); - c2[2] = 0.0f; - } - - lo[2] = -motorForce; - hi[2] = motorForce; - boxIndex[2] = -1; - } -} - -/* -================ -idAFConstraint_Suspension::ApplyFriction -================ -*/ -void idAFConstraint_Suspension::ApplyFriction( float invTimeStep ) { - // do nothing -} - -/* -================ -idAFConstraint_Suspension::Translate -================ -*/ -void idAFConstraint_Suspension::Translate( const idVec3 &translation ) { -} - -/* -================ -idAFConstraint_Suspension::Rotate -================ -*/ -void idAFConstraint_Suspension::Rotate( const idRotation &rotation ) { -} - -/* -================ -idAFConstraint_Suspension::DebugDraw -================ -*/ -void idAFConstraint_Suspension::DebugDraw( void ) { - idVec3 origin; - idMat3 axis; - idRotation rotation; - - axis = localAxis * body1->GetWorldAxis(); - - rotation.SetVec( axis[2] ); - rotation.SetAngle( steerAngle ); - - axis *= rotation.ToMat3(); - - if ( trace.fraction < 1.0f ) { - origin = trace.c.point; - - gameRenderWorld->DebugLine( colorWhite, origin, origin + 6.0f * axis[2] ); - gameRenderWorld->DebugLine( colorWhite, origin - 4.0f * axis[0], origin + 4.0f * axis[0] ); - gameRenderWorld->DebugLine( colorWhite, origin - 2.0f * axis[1], origin + 2.0f * axis[1] ); - } -} - - -//=============================================================== -// -// idAFBody -// -//=============================================================== - -/* -================ -idAFBody::idAFBody -================ -*/ -idAFBody::idAFBody( void ) { - Init(); -} - -/* -================ -idAFBody::idAFBody -================ -*/ -idAFBody::idAFBody( const idStr &name, idClipModel *clipModel, float density ) { - - assert( clipModel ); - assert( clipModel->IsTraceModel() ); - - Init(); - - this->name = name; - this->clipModel = NULL; - - SetClipModel( clipModel ); - SetDensity( density ); - - current->worldOrigin = clipModel->GetOrigin(); - current->worldAxis = clipModel->GetAxis(); - *next = *current; - -} - -/* -================ -idAFBody::~idAFBody -================ -*/ -idAFBody::~idAFBody( void ) { - delete clipModel; -} - -/* -================ -idAFBody::Init -================ -*/ -void idAFBody::Init( void ) { - name = "noname"; - parent = NULL; - clipModel = NULL; - primaryConstraint = NULL; - tree = NULL; - - linearFriction = -1.0f; - angularFriction = -1.0f; - contactFriction = -1.0f; - bouncyness = -1.0f; - clipMask = 0; - - frictionDir = vec3_zero; - contactMotorDir = vec3_zero; - contactMotorVelocity = 0.0f; - contactMotorForce = 0.0f; - - mass = 1.0f; - invMass = 1.0f; - centerOfMass = vec3_zero; - inertiaTensor = mat3_identity; - inverseInertiaTensor = mat3_identity; - - current = &state[0]; - next = &state[1]; - current->worldOrigin = vec3_zero; - current->worldAxis = mat3_identity; - current->spatialVelocity = vec6_zero; - current->externalForce = vec6_zero; - *next = *current; - saved = *current; - atRestOrigin = vec3_zero; - atRestAxis = mat3_identity; - - s.Zero( 6 ); - totalForce.Zero( 6 ); - auxForce.Zero( 6 ); - acceleration.Zero( 6 ); - - response = NULL; - responseIndex = NULL; - numResponses = 0; - maxAuxiliaryIndex = 0; - maxSubTreeAuxiliaryIndex = 0; - - memset( &fl, 0, sizeof( fl ) ); - - fl.selfCollision = true; - fl.isZero = true; -} - -/* -================ -idAFBody::SetClipModel -================ -*/ -void idAFBody::SetClipModel( idClipModel *clipModel ) { - if ( this->clipModel && this->clipModel != clipModel ) { - delete this->clipModel; - } - this->clipModel = clipModel; -} - -/* -================ -idAFBody::SetFriction -================ -*/ -void idAFBody::SetFriction( float linear, float angular, float contact ) { - if ( linear < 0.0f || linear > 1.0f || - angular < 0.0f || angular > 1.0f || - contact < 0.0f ) { - gameLocal.Warning( "idAFBody::SetFriction: friction out of range, linear = %.1f, angular = %.1f, contact = %.1f", linear, angular, contact ); - return; - } - linearFriction = linear; - angularFriction = angular; - contactFriction = contact; -} - -/* -================ -idAFBody::SetBouncyness -================ -*/ -void idAFBody::SetBouncyness( float bounce ) { - if ( bounce < 0.0f || bounce > 1.0f ) { - gameLocal.Warning( "idAFBody::SetBouncyness: bouncyness out of range, bounce = %.1f", bounce ); - return; - } - bouncyness = bounce; -} - -/* -================ -idAFBody::SetDensity -================ -*/ -void idAFBody::SetDensity( float density, const idMat3 &inertiaScale ) { - - // get the body mass properties - clipModel->GetMassProperties( density, mass, centerOfMass, inertiaTensor ); - - // make sure we have a valid mass - if ( mass <= 0.0f || FLOAT_IS_NAN( mass ) ) { - gameLocal.Warning( "idAFBody::SetDensity: invalid mass for body '%s'", name.c_str() ); - mass = 1.0f; - centerOfMass.Zero(); - inertiaTensor.Identity(); - } - - // make sure the center of mass is at the body origin - if ( !centerOfMass.Compare( vec3_origin, CENTER_OF_MASS_EPSILON ) ) { - gameLocal.Warning( "idAFBody::SetDentity: center of mass not at origin for body '%s'", name.c_str() ); - } - centerOfMass.Zero(); - - // calculate the inverse mass and inverse inertia tensor - invMass = 1.0f / mass; - if ( inertiaScale != mat3_identity ) { - inertiaTensor *= inertiaScale; - } - if ( inertiaTensor.IsDiagonal( 1e-3f ) ) { - inertiaTensor[0][1] = inertiaTensor[0][2] = 0.0f; - inertiaTensor[1][0] = inertiaTensor[1][2] = 0.0f; - inertiaTensor[2][0] = inertiaTensor[2][1] = 0.0f; - inverseInertiaTensor.Identity(); - inverseInertiaTensor[0][0] = 1.0f / inertiaTensor[0][0]; - inverseInertiaTensor[1][1] = 1.0f / inertiaTensor[1][1]; - inverseInertiaTensor[2][2] = 1.0f / inertiaTensor[2][2]; - } - else { - inverseInertiaTensor = inertiaTensor.Inverse(); - } -} - -/* -================ -idAFBody::SetFrictionDirection -================ -*/ -void idAFBody::SetFrictionDirection( const idVec3 &dir ) { - frictionDir = dir * current->worldAxis.Transpose(); - fl.useFrictionDir = true; -} - -/* -================ -idAFBody::GetFrictionDirection -================ -*/ -bool idAFBody::GetFrictionDirection( idVec3 &dir ) const { - if ( fl.useFrictionDir ) { - dir = frictionDir * current->worldAxis; - return true; - } - return false; -} - -/* -================ -idAFBody::SetContactMotorDirection -================ -*/ -void idAFBody::SetContactMotorDirection( const idVec3 &dir ) { - contactMotorDir = dir * current->worldAxis.Transpose(); - fl.useContactMotorDir = true; -} - -/* -================ -idAFBody::GetContactMotorDirection -================ -*/ -bool idAFBody::GetContactMotorDirection( idVec3 &dir ) const { - if ( fl.useContactMotorDir ) { - dir = contactMotorDir * current->worldAxis; - return true; - } - return false; -} - -/* -================ -idAFBody::GetPointVelocity -================ -*/ -idVec3 idAFBody::GetPointVelocity( const idVec3 &point ) const { - idVec3 r = point - current->worldOrigin; - return current->spatialVelocity.SubVec3(0) + current->spatialVelocity.SubVec3(1).Cross( r ); -} - -/* -================ -idAFBody::AddForce -================ -*/ -void idAFBody::AddForce( const idVec3 &point, const idVec3 &force ) { - current->externalForce.SubVec3(0) += force; - current->externalForce.SubVec3(1) += (point - current->worldOrigin).Cross( force ); -} - -/* -================ -idAFBody::InverseWorldSpatialInertiaMultiply - - dst = this->inverseWorldSpatialInertia * v; -================ -*/ -ID_INLINE void idAFBody::InverseWorldSpatialInertiaMultiply( idVecX &dst, const float *v ) const { - const float *mPtr = inverseWorldSpatialInertia.ToFloatPtr(); - const float *vPtr = v; - float *dstPtr = dst.ToFloatPtr(); - - if ( fl.spatialInertiaSparse ) { - dstPtr[0] = mPtr[0*6+0] * vPtr[0]; - dstPtr[1] = mPtr[1*6+1] * vPtr[1]; - dstPtr[2] = mPtr[2*6+2] * vPtr[2]; - dstPtr[3] = mPtr[3*6+3] * vPtr[3] + mPtr[3*6+4] * vPtr[4] + mPtr[3*6+5] * vPtr[5]; - dstPtr[4] = mPtr[4*6+3] * vPtr[3] + mPtr[4*6+4] * vPtr[4] + mPtr[4*6+5] * vPtr[5]; - dstPtr[5] = mPtr[5*6+3] * vPtr[3] + mPtr[5*6+4] * vPtr[4] + mPtr[5*6+5] * vPtr[5]; - } else { - gameLocal.Warning( "spatial inertia is not sparse for body %s", name.c_str() ); - } -} - -/* -================ -idAFBody::Save -================ -*/ -void idAFBody::Save( idSaveGame *saveFile ) { - saveFile->WriteFloat( linearFriction ); - saveFile->WriteFloat( angularFriction ); - saveFile->WriteFloat( contactFriction ); - saveFile->WriteFloat( bouncyness ); - saveFile->WriteInt( clipMask ); - saveFile->WriteVec3( frictionDir ); - saveFile->WriteVec3( contactMotorDir ); - saveFile->WriteFloat( contactMotorVelocity ); - saveFile->WriteFloat( contactMotorForce ); - - saveFile->WriteFloat( mass ); - saveFile->WriteFloat( invMass ); - saveFile->WriteVec3( centerOfMass ); - saveFile->WriteMat3( inertiaTensor ); - saveFile->WriteMat3( inverseInertiaTensor ); - - saveFile->WriteVec3( current->worldOrigin ); - saveFile->WriteMat3( current->worldAxis ); - saveFile->WriteVec6( current->spatialVelocity ); - saveFile->WriteVec6( current->externalForce ); - saveFile->WriteVec3( atRestOrigin ); - saveFile->WriteMat3( atRestAxis ); -} - -/* -================ -idAFBody::Restore -================ -*/ -void idAFBody::Restore( idRestoreGame *saveFile ) { - saveFile->ReadFloat( linearFriction ); - saveFile->ReadFloat( angularFriction ); - saveFile->ReadFloat( contactFriction ); - saveFile->ReadFloat( bouncyness ); - saveFile->ReadInt( clipMask ); - saveFile->ReadVec3( frictionDir ); - saveFile->ReadVec3( contactMotorDir ); - saveFile->ReadFloat( contactMotorVelocity ); - saveFile->ReadFloat( contactMotorForce ); - - saveFile->ReadFloat( mass ); - saveFile->ReadFloat( invMass ); - saveFile->ReadVec3( centerOfMass ); - saveFile->ReadMat3( inertiaTensor ); - saveFile->ReadMat3( inverseInertiaTensor ); - - saveFile->ReadVec3( current->worldOrigin ); - saveFile->ReadMat3( current->worldAxis ); - saveFile->ReadVec6( current->spatialVelocity ); - saveFile->ReadVec6( current->externalForce ); - saveFile->ReadVec3( atRestOrigin ); - saveFile->ReadMat3( atRestAxis ); -} - - - -//=============================================================== -// M -// idAFTree MrE -// E -//=============================================================== - -/* -================ -idAFTree::Factor - - factor matrix for the primary constraints in the tree -================ -*/ -void idAFTree::Factor( void ) const { - int i, j; - idAFBody *body; - idAFConstraint *child = NULL; - idMatX childI; - - childI.SetData( 6, 6, MATX_ALLOCA( 6 * 6 ) ); - - // from the leaves up towards the root - for ( i = sortedBodies.Num() - 1; i >= 0; i-- ) { - body = sortedBodies[i]; - - if ( body->children.Num() ) { - - for ( j = 0; j < body->children.Num(); j++ ) { - - child = body->children[j]->primaryConstraint; - - // child->I = - child->body1->J.Transpose() * child->body1->I * child->body1->J; - childI.SetSize( child->J1.GetNumRows(), child->J1.GetNumRows() ); - child->body1->J.TransposeMultiply( child->body1->I ).Multiply( childI, child->body1->J ); - childI.Negate(); - - child->invI = childI; - if ( !child->invI.InverseFastSelf() ) { - gameLocal.Warning( "idAFTree::Factor: couldn't invert %dx%d matrix for constraint '%s'", - child->invI.GetNumRows(), child->invI.GetNumColumns(), child->GetName().c_str() ); - } - child->J = child->invI * child->J; - - body->I -= child->J.TransposeMultiply( childI ) * child->J; - } - - body->invI = body->I; - if ( !body->invI.InverseFastSelf() ) { - gameLocal.Warning( "idAFTree::Factor: couldn't invert %dx%d matrix for body %s", - child->invI.GetNumRows(), child->invI.GetNumColumns(), body->GetName().c_str() ); - } - if ( body->primaryConstraint ) { - body->J = body->invI * body->J; - } - } - else if ( body->primaryConstraint ) { - body->J = body->inverseWorldSpatialInertia * body->J; - } - } -} - -/* -================ -idAFTree::Solve - - solve for primary constraints in the tree -================ -*/ -void idAFTree::Solve( int auxiliaryIndex ) const { - int i, j; - idAFBody *body, *child; - idAFConstraint *primaryConstraint; - - // from the leaves up towards the root - for ( i = sortedBodies.Num() - 1; i >= 0; i-- ) { - body = sortedBodies[i]; - - for ( j = 0; j < body->children.Num(); j++ ) { - child = body->children[j]; - primaryConstraint = child->primaryConstraint; - - if ( !child->fl.isZero ) { - child->J.TransposeMultiplySub( primaryConstraint->s, child->s ); - primaryConstraint->fl.isZero = false; - } - if ( !primaryConstraint->fl.isZero ) { - primaryConstraint->J.TransposeMultiplySub( body->s, primaryConstraint->s ); - body->fl.isZero = false; - } - } - } - - bool useSymmetry = af_useSymmetry.GetBool(); - - // from the root down towards the leaves - for ( i = 0; i < sortedBodies.Num(); i++ ) { - body = sortedBodies[i]; - primaryConstraint = body->primaryConstraint; - - if ( primaryConstraint ) { - - if ( useSymmetry && body->parent->maxSubTreeAuxiliaryIndex < auxiliaryIndex ) { - continue; - } - - if ( !primaryConstraint->fl.isZero ) { - primaryConstraint->s = primaryConstraint->invI * primaryConstraint->s; - } - primaryConstraint->J.MultiplySub( primaryConstraint->s, primaryConstraint->body2->s ); - - primaryConstraint->lm = primaryConstraint->s; - - if ( useSymmetry && body->maxSubTreeAuxiliaryIndex < auxiliaryIndex ) { - continue; - } - - if ( body->children.Num() ) { - if ( !body->fl.isZero ) { - body->s = body->invI * body->s; - } - body->J.MultiplySub( body->s, primaryConstraint->s ); - } - } else if ( body->children.Num() ) { - body->s = body->invI * body->s; - } - } -} - -/* -================ -idAFTree::Response - - calculate body forces in the tree in response to a constraint force -================ -*/ -void idAFTree::Response( const idAFConstraint *constraint, int row, int auxiliaryIndex ) const { - int i, j; - idAFBody *body; - idAFConstraint *child, *primaryConstraint; - idVecX v; - - // if a single body don't waste time because there aren't any primary constraints - if ( sortedBodies.Num() == 1 ) { - body = constraint->body1; - if ( body->tree == this ) { - body->GetResponseForce( body->numResponses ) = constraint->J1.SubVec6( row ); - body->responseIndex[body->numResponses++] = auxiliaryIndex; - } - else { - body = constraint->body2; - body->GetResponseForce( body->numResponses ) = constraint->J2.SubVec6( row ); - body->responseIndex[body->numResponses++] = auxiliaryIndex; - } - return; - } - - v.SetData( 6, VECX_ALLOCA( 6 ) ); - - // initialize right hand side to zero - for ( i = 0; i < sortedBodies.Num(); i++ ) { - body = sortedBodies[i]; - primaryConstraint = body->primaryConstraint; - if ( primaryConstraint ) { - primaryConstraint->s.Zero(); - primaryConstraint->fl.isZero = true; - } - body->s.Zero(); - body->fl.isZero = true; - body->GetResponseForce( body->numResponses ).Zero(); - } - - // set right hand side for first constrained body - body = constraint->body1; - if ( body->tree == this ) { - body->InverseWorldSpatialInertiaMultiply( v, constraint->J1[row] ); - primaryConstraint = body->primaryConstraint; - if ( primaryConstraint ) { - primaryConstraint->J1.Multiply( primaryConstraint->s, v ); - primaryConstraint->fl.isZero = false; - } - for ( i = 0; i < body->children.Num(); i++ ) { - child = body->children[i]->primaryConstraint; - child->J2.Multiply( child->s, v ); - child->fl.isZero = false; - } - body->GetResponseForce( body->numResponses ) = constraint->J1.SubVec6( row ); - } - - // set right hand side for second constrained body - body = constraint->body2; - if ( body && body->tree == this ) { - body->InverseWorldSpatialInertiaMultiply( v, constraint->J2[row] ); - primaryConstraint = body->primaryConstraint; - if ( primaryConstraint ) { - primaryConstraint->J1.MultiplyAdd( primaryConstraint->s, v ); - primaryConstraint->fl.isZero = false; - } - for ( i = 0; i < body->children.Num(); i++ ) { - child = body->children[i]->primaryConstraint; - child->J2.MultiplyAdd( child->s, v ); - child->fl.isZero = false; - } - body->GetResponseForce( body->numResponses ) = constraint->J2.SubVec6( row ); - } - - - // solve for primary constraints - Solve( auxiliaryIndex ); - - bool useSymmetry = af_useSymmetry.GetBool(); - - // store body forces in response to the constraint force - idVecX force; - for ( i = 0; i < sortedBodies.Num(); i++ ) { - body = sortedBodies[i]; - - if ( useSymmetry && body->maxAuxiliaryIndex < auxiliaryIndex ) { - continue; - } - - force.SetData( 6, body->response + body->numResponses * 8 ); - - // add forces of all primary constraints acting on this body - primaryConstraint = body->primaryConstraint; - if ( primaryConstraint ) { - primaryConstraint->J1.TransposeMultiplyAdd( force, primaryConstraint->lm ); - } - for ( j = 0; j < body->children.Num(); j++ ) { - child = body->children[j]->primaryConstraint; - child->J2.TransposeMultiplyAdd( force, child->lm ); - } - - body->responseIndex[body->numResponses++] = auxiliaryIndex; - } -} - -/* -================ -idAFTree::CalculateForces - - calculate forces on the bodies in the tree -================ -*/ -void idAFTree::CalculateForces( float timeStep ) const { - int i, j; - float invStep; - idAFBody *body; - idAFConstraint *child, *c, *primaryConstraint; - - // forces on bodies - for ( i = 0; i < sortedBodies.Num(); i++ ) { - body = sortedBodies[i]; - - body->totalForce.SubVec6(0) = body->current->externalForce + body->auxForce.SubVec6(0); - } - - // if a single body don't waste time because there aren't any primary constraints - if ( sortedBodies.Num() == 1 ) { - return; - } - - invStep = 1.0f / timeStep; - - // initialize right hand side - for ( i = 0; i < sortedBodies.Num(); i++ ) { - body = sortedBodies[i]; - - body->InverseWorldSpatialInertiaMultiply( body->acceleration, body->totalForce.ToFloatPtr() ); - body->acceleration.SubVec6(0) += body->current->spatialVelocity * invStep; - primaryConstraint = body->primaryConstraint; - if ( primaryConstraint ) { - // b = ( J * acc + c ) - c = primaryConstraint; - c->s = c->J1 * c->body1->acceleration + c->J2 * c->body2->acceleration + invStep * ( c->c1 + c->c2 ); - c->fl.isZero = false; - } - body->s.Zero(); - body->fl.isZero = true; - } - - // solve for primary constraints - Solve(); - - // calculate forces on bodies after applying primary constraints - for ( i = 0; i < sortedBodies.Num(); i++ ) { - body = sortedBodies[i]; - - // add forces of all primary constraints acting on this body - primaryConstraint = body->primaryConstraint; - if ( primaryConstraint ) { - primaryConstraint->J1.TransposeMultiplyAdd( body->totalForce, primaryConstraint->lm ); - } - for ( j = 0; j < body->children.Num(); j++ ) { - child = body->children[j]->primaryConstraint; - child->J2.TransposeMultiplyAdd( body->totalForce, child->lm ); - } - } -} - -/* -================ -idAFTree::SetMaxSubTreeAuxiliaryIndex -================ -*/ -void idAFTree::SetMaxSubTreeAuxiliaryIndex( void ) { - int i, j; - idAFBody *body, *child; - - // from the leaves up towards the root - for ( i = sortedBodies.Num() - 1; i >= 0; i-- ) { - body = sortedBodies[i]; - - body->maxSubTreeAuxiliaryIndex = body->maxAuxiliaryIndex; - for ( j = 0; j < body->children.Num(); j++ ) { - child = body->children[j]; - if ( child->maxSubTreeAuxiliaryIndex > body->maxSubTreeAuxiliaryIndex ) { - body->maxSubTreeAuxiliaryIndex = child->maxSubTreeAuxiliaryIndex; - } - } - } -} - -/* -================ -idAFTree::SortBodies_r -================ -*/ -void idAFTree::SortBodies_r( idList&sortedList, idAFBody *body ) { - int i; - - for ( i = 0; i < body->children.Num(); i++ ) { - sortedList.Append( body->children[i] ); - } - for ( i = 0; i < body->children.Num(); i++ ) { - SortBodies_r( sortedList, body->children[i] ); - } -} - -/* -================ -idAFTree::SortBodies - - sort body list to make sure parents come first -================ -*/ -void idAFTree::SortBodies( void ) { - int i; - idAFBody *body; - - // find the root - for ( i = 0; i < sortedBodies.Num(); i++ ) { - if ( !sortedBodies[i]->parent ) { - break; - } - } - - if ( i >= sortedBodies.Num() ) { - gameLocal.Error( "Articulated figure tree has no root." ); - } - - body = sortedBodies[i]; - sortedBodies.Clear(); - sortedBodies.Append( body ); - SortBodies_r( sortedBodies, body ); -} - -/* -================ -idAFTree::DebugDraw -================ -*/ -void idAFTree::DebugDraw( const idVec4 &color ) const { - int i; - idAFBody *body; - - for ( i = 1; i < sortedBodies.Num(); i++ ) { - body = sortedBodies[i]; - gameRenderWorld->DebugArrow( color, body->parent->current->worldOrigin, body->current->worldOrigin, 1 ); - } -} - - -//=============================================================== -// M -// idPhysics_AF MrE -// E -//=============================================================== - -/* -================ -idPhysics_AF::EvaluateConstraints -================ -*/ -void idPhysics_AF::EvaluateConstraints( float timeStep ) { - int i; - float invTimeStep; - idAFBody *body; - idAFConstraint *c; - - invTimeStep = 1.0f / timeStep; - - // setup the constraint equations for the current position and orientation of the bodies - for ( i = 0; i < primaryConstraints.Num(); i++ ) { - c = primaryConstraints[i]; - c->Evaluate( invTimeStep ); - c->J = c->J2; - } - for ( i = 0; i < auxiliaryConstraints.Num(); i++ ) { - auxiliaryConstraints[i]->Evaluate( invTimeStep ); - } - - // add contact constraints to the list with frame constraints - for ( i = 0; i < contactConstraints.Num(); i++ ) { - AddFrameConstraint( contactConstraints[i] ); - } - - // setup body primary constraint matrix - for ( i = 0; i < bodies.Num(); i++ ) { - body = bodies[i]; - - if ( body->primaryConstraint ) { - body->J = body->primaryConstraint->J1.Transpose(); - } - } -} - -/* -================ -idPhysics_AF::EvaluateBodies -================ -*/ -void idPhysics_AF::EvaluateBodies( float timeStep ) { - int i; - idAFBody *body; - idMat3 axis; - - for ( i = 0; i < bodies.Num(); i++ ) { - body = bodies[i]; - - // we transpose the axis before using it because idMat3 is column-major - axis = body->current->worldAxis.Transpose(); - - // if the center of mass is at the body point of reference - if ( body->centerOfMass.Compare( vec3_origin, CENTER_OF_MASS_EPSILON ) ) { - - // spatial inertia in world space - body->I.Set( body->mass * mat3_identity, mat3_zero, - mat3_zero, axis * body->inertiaTensor * axis.Transpose() ); - - // inverse spatial inertia in world space - body->inverseWorldSpatialInertia.Set( body->invMass * mat3_identity, mat3_zero, - mat3_zero, axis * body->inverseInertiaTensor * axis.Transpose() ); - - body->fl.spatialInertiaSparse = true; - } - else { - idMat3 massMoment = body->mass * SkewSymmetric( body->centerOfMass ); - - // spatial inertia in world space - body->I.Set( body->mass * mat3_identity, massMoment, - massMoment.Transpose(), axis * body->inertiaTensor * axis.Transpose() ); - - // inverse spatial inertia in world space - body->inverseWorldSpatialInertia = body->I.InverseFast(); - - body->fl.spatialInertiaSparse = false; - } - - // initialize auxiliary constraint force to zero - body->auxForce.Zero(); - } -} - -/* -================ -idPhysics_AF::AddFrameConstraints -================ -*/ -void idPhysics_AF::AddFrameConstraints( void ) { - int i; - - // add frame constraints to auxiliary constraints - for ( i = 0; i < frameConstraints.Num(); i++ ) { - auxiliaryConstraints.Append( frameConstraints[i] ); - } -} - -/* -================ -idPhysics_AF::RemoveFrameConstraints -================ -*/ -void idPhysics_AF::RemoveFrameConstraints( void ) { - // remove all the frame constraints from the auxiliary constraints - auxiliaryConstraints.SetNum( auxiliaryConstraints.Num() - frameConstraints.Num(), false ); - frameConstraints.SetNum( 0, false ); -} - -/* -================ -idPhysics_AF::ApplyFriction -================ -*/ -void idPhysics_AF::ApplyFriction( float timeStep, float endTimeMSec ) { - int i; - float invTimeStep; - - if ( af_skipFriction.GetBool() ) { - return; - } - - if ( jointFrictionDentStart < MS2SEC( endTimeMSec ) && jointFrictionDentEnd > MS2SEC( endTimeMSec ) ) { - float halfTime = ( jointFrictionDentEnd - jointFrictionDentStart ) * 0.5f; - if ( jointFrictionDentStart + halfTime > MS2SEC( endTimeMSec ) ) { - jointFrictionDentScale = 1.0f - ( 1.0f - jointFrictionDent ) * ( MS2SEC( endTimeMSec ) - jointFrictionDentStart ) / halfTime; - } else { - jointFrictionDentScale = jointFrictionDent + ( 1.0f - jointFrictionDent ) * ( MS2SEC( endTimeMSec ) - jointFrictionDentStart - halfTime ) / halfTime; - } - } else { - jointFrictionDentScale = 0.0f; - } - - if ( contactFrictionDentStart < MS2SEC( endTimeMSec ) && contactFrictionDentEnd > MS2SEC( endTimeMSec ) ) { - float halfTime = ( contactFrictionDentEnd - contactFrictionDentStart ) * 0.5f; - if ( contactFrictionDentStart + halfTime > MS2SEC( endTimeMSec ) ) { - contactFrictionDentScale = 1.0f - ( 1.0f - contactFrictionDent ) * ( MS2SEC( endTimeMSec ) - contactFrictionDentStart ) / halfTime; - } else { - contactFrictionDentScale = contactFrictionDent + ( 1.0f - contactFrictionDent ) * ( MS2SEC( endTimeMSec ) - contactFrictionDentStart - halfTime ) / halfTime; - } - } else { - contactFrictionDentScale = 0.0f; - } - - invTimeStep = 1.0f / timeStep; - - for ( i = 0; i < primaryConstraints.Num(); i++ ) { - primaryConstraints[i]->ApplyFriction( invTimeStep ); - } - for ( i = 0; i < auxiliaryConstraints.Num(); i++ ) { - auxiliaryConstraints[i]->ApplyFriction( invTimeStep ); - } - for ( i = 0; i < frameConstraints.Num(); i++ ) { - frameConstraints[i]->ApplyFriction( invTimeStep ); - } -} - -/* -================ -idPhysics_AF::PrimaryFactor -================ -*/ -void idPhysics_AF::PrimaryFactor( void ) { - int i; - - for ( i = 0; i < trees.Num(); i++ ) { - trees[i]->Factor(); - } -} - -/* -================ -idPhysics_AF::PrimaryForces -================ -*/ -void idPhysics_AF::PrimaryForces( float timeStep ) { - int i; - - for ( i = 0; i < trees.Num(); i++ ) { - trees[i]->CalculateForces( timeStep ); - } -} - -/* -================ -idPhysics_AF::AuxiliaryForces -================ -*/ -void idPhysics_AF::AuxiliaryForces( float timeStep ) { - int i, j, k, l, n, m, s, numAuxConstraints, *index, *boxIndex; - float *ptr, *j1, *j2, *dstPtr, *forcePtr; - float invStep, u; - idAFBody *body; - idAFConstraint *constraint; - idVecX tmp; - idMatX jmk; - idVecX rhs, w, lm, lo, hi; - - // get the number of one dimensional auxiliary constraints - for ( numAuxConstraints = 0, i = 0; i < auxiliaryConstraints.Num(); i++ ) { - numAuxConstraints += auxiliaryConstraints[i]->J1.GetNumRows(); - } - - if ( numAuxConstraints == 0 ) { - return; - } - - // allocate memory to store the body response to auxiliary constraint forces - forcePtr = (float *) _alloca16( bodies.Num() * numAuxConstraints * 8 * sizeof( float ) ); - index = (int *) _alloca16( bodies.Num() * numAuxConstraints * sizeof( int ) ); - for ( i = 0; i < bodies.Num(); i++ ) { - body = bodies[i]; - body->response = forcePtr; - body->responseIndex = index; - body->numResponses = 0; - body->maxAuxiliaryIndex = 0; - forcePtr += numAuxConstraints * 8; - index += numAuxConstraints; - } - - // set on each body the largest index of an auxiliary constraint constraining the body - if ( af_useSymmetry.GetBool() ) { - for ( k = 0, i = 0; i < auxiliaryConstraints.Num(); i++ ) { - constraint = auxiliaryConstraints[i]; - for ( j = 0; j < constraint->J1.GetNumRows(); j++, k++ ) { - if ( k > constraint->body1->maxAuxiliaryIndex ) { - constraint->body1->maxAuxiliaryIndex = k; - } - if ( constraint->body2 && k > constraint->body2->maxAuxiliaryIndex ) { - constraint->body2->maxAuxiliaryIndex = k; - } - } - } - for ( i = 0; i < trees.Num(); i++ ) { - trees[i]->SetMaxSubTreeAuxiliaryIndex(); - } - } - - // calculate forces of primary constraints in response to the auxiliary constraint forces - for ( k = 0, i = 0; i < auxiliaryConstraints.Num(); i++ ) { - constraint = auxiliaryConstraints[i]; - - for ( j = 0; j < constraint->J1.GetNumRows(); j++, k++ ) { - - // calculate body forces in the tree in response to the constraint force - constraint->body1->tree->Response( constraint, j, k ); - // if there is a second body which is part of a different tree - if ( constraint->body2 && constraint->body2->tree != constraint->body1->tree ) { - // calculate body forces in the second tree in response to the constraint force - constraint->body2->tree->Response( constraint, j, k ); - } - } - } - - // NOTE: the rows are 16 byte padded - jmk.SetData( numAuxConstraints, ((numAuxConstraints+3)&~3), MATX_ALLOCA( numAuxConstraints * ((numAuxConstraints+3)&~3) ) ); - tmp.SetData( 6, VECX_ALLOCA( 6 ) ); - - // create constraint matrix for auxiliary constraints using a mass matrix adjusted for the primary constraints - for ( k = 0, i = 0; i < auxiliaryConstraints.Num(); i++ ) { - constraint = auxiliaryConstraints[i]; - - for ( j = 0; j < constraint->J1.GetNumRows(); j++, k++ ) { - constraint->body1->InverseWorldSpatialInertiaMultiply( tmp, constraint->J1[j] ); - j1 = tmp.ToFloatPtr(); - ptr = constraint->body1->response; - index = constraint->body1->responseIndex; - dstPtr = jmk[k]; - s = af_useSymmetry.GetBool() ? k + 1 : numAuxConstraints; - for ( l = n = 0, m = index[n]; n < constraint->body1->numResponses && m < s; n++, m = index[n] ) { - while( l < m ) { - dstPtr[l++] = 0.0f; - } - dstPtr[l++] = j1[0] * ptr[0] + j1[1] * ptr[1] + j1[2] * ptr[2] + - j1[3] * ptr[3] + j1[4] * ptr[4] + j1[5] * ptr[5]; - ptr += 8; - } - - while( l < s ) { - dstPtr[l++] = 0.0f; - } - - if ( constraint->body2 ) { - constraint->body2->InverseWorldSpatialInertiaMultiply( tmp, constraint->J2[j] ); - j2 = tmp.ToFloatPtr(); - ptr = constraint->body2->response; - index = constraint->body2->responseIndex; - for ( n = 0, m = index[n]; n < constraint->body2->numResponses && m < s; n++, m = index[n] ) { - dstPtr[m] += j2[0] * ptr[0] + j2[1] * ptr[1] + j2[2] * ptr[2] + - j2[3] * ptr[3] + j2[4] * ptr[4] + j2[5] * ptr[5]; - ptr += 8; - } - } - } - } - - if ( af_useSymmetry.GetBool() ) { - n = jmk.GetNumColumns(); - for ( i = 0; i < numAuxConstraints; i++ ) { - ptr = jmk.ToFloatPtr() + ( i + 1 ) * n + i; - dstPtr = jmk.ToFloatPtr() + i * n + i + 1; - for ( j = i+1; j < numAuxConstraints; j++ ) { - *dstPtr++ = *ptr; - ptr += n; - } - } - } - - invStep = 1.0f / timeStep; - - // calculate body acceleration - for ( i = 0; i < bodies.Num(); i++ ) { - body = bodies[i]; - body->InverseWorldSpatialInertiaMultiply( body->acceleration, body->totalForce.ToFloatPtr() ); - body->acceleration.SubVec6(0) += body->current->spatialVelocity * invStep; - } - - rhs.SetData( numAuxConstraints, VECX_ALLOCA( numAuxConstraints ) ); - lo.SetData( numAuxConstraints, VECX_ALLOCA( numAuxConstraints ) ); - hi.SetData( numAuxConstraints, VECX_ALLOCA( numAuxConstraints ) ); - lm.SetData( numAuxConstraints, VECX_ALLOCA( numAuxConstraints ) ); - boxIndex = (int *) _alloca16( numAuxConstraints * sizeof( int ) ); - - // set first index for special box constrained variables - for ( k = 0, i = 0; i < auxiliaryConstraints.Num(); i++ ) { - auxiliaryConstraints[i]->firstIndex = k; - k += auxiliaryConstraints[i]->J1.GetNumRows(); - } - - // initialize right hand side and low and high bounds for auxiliary constraints - for ( k = 0, i = 0; i < auxiliaryConstraints.Num(); i++ ) { - constraint = auxiliaryConstraints[i]; - n = k; - - for ( j = 0; j < constraint->J1.GetNumRows(); j++, k++ ) { - - j1 = constraint->J1[j]; - ptr = constraint->body1->acceleration.ToFloatPtr(); - rhs[k] = j1[0] * ptr[0] + j1[1] * ptr[1] + j1[2] * ptr[2] + j1[3] * ptr[3] + j1[4] * ptr[4] + j1[5] * ptr[5]; - rhs[k] += constraint->c1[j] * invStep; - - if ( constraint->body2 ) { - j2 = constraint->J2[j]; - ptr = constraint->body2->acceleration.ToFloatPtr(); - rhs[k] += j2[0] * ptr[0] + j2[1] * ptr[1] + j2[2] * ptr[2] + j2[3] * ptr[3] + j2[4] * ptr[4] + j2[5] * ptr[5]; - rhs[k] += constraint->c2[j] * invStep; - } - - rhs[k] = -rhs[k]; - lo[k] = constraint->lo[j]; - hi[k] = constraint->hi[j]; - - if ( constraint->boxIndex[j] >= 0 ) { - if ( constraint->boxConstraint->fl.isPrimary ) { - gameLocal.Error( "cannot reference primary constraints for the box index" ); - } - boxIndex[k] = constraint->boxConstraint->firstIndex + constraint->boxIndex[j]; - } - else { - boxIndex[k] = -1; - } - jmk[k][k] += constraint->e[j] * invStep; - } - } - -#ifdef AF_TIMINGS - timer_lcp.Start(); -#endif - - // calculate lagrange multipliers for auxiliary constraints - if ( !lcp->Solve( jmk, lm, rhs, lo, hi, boxIndex ) ) { - return; // bad monkey! - } - -#ifdef AF_TIMINGS - timer_lcp.Stop(); -#endif - - // calculate auxiliary constraint forces - for ( k = 0, i = 0; i < auxiliaryConstraints.Num(); i++ ) { - constraint = auxiliaryConstraints[i]; - - for ( j = 0; j < constraint->J1.GetNumRows(); j++, k++ ) { - constraint->lm[j] = u = lm[k]; - - j1 = constraint->J1[j]; - ptr = constraint->body1->auxForce.ToFloatPtr(); - ptr[0] += j1[0] * u; ptr[1] += j1[1] * u; ptr[2] += j1[2] * u; - ptr[3] += j1[3] * u; ptr[4] += j1[4] * u; ptr[5] += j1[5] * u; - - if ( constraint->body2 ) { - j2 = constraint->J2[j]; - ptr = constraint->body2->auxForce.ToFloatPtr(); - ptr[0] += j2[0] * u; ptr[1] += j2[1] * u; ptr[2] += j2[2] * u; - ptr[3] += j2[3] * u; ptr[4] += j2[4] * u; ptr[5] += j2[5] * u; - } - } - } - - // recalculate primary constraint forces in response to auxiliary constraint forces - PrimaryForces( timeStep ); - - // clear pointers pointing to stack space so tools don't get confused - for ( i = 0; i < bodies.Num(); i++ ) { - body = bodies[i]; - body->response = NULL; - body->responseIndex = NULL; - } -} - -/* -================ -idPhysics_AF::VerifyContactConstraints -================ -*/ -void idPhysics_AF::VerifyContactConstraints( void ) { -#if 0 - int i; - float impulseNumerator, impulseDenominator; - idVec3 r, velocity, normalVelocity, normal, impulse; - idAFBody *body; - - for ( i = 0; i < contactConstraints.Num(); i++ ) { - body = contactConstraints[i]->body1; - const contactInfo_t &contact = contactConstraints[i]->GetContact(); - - r = contact.point - body->GetCenterOfMass(); - - // calculate velocity at contact point - velocity = body->GetLinearVelocity() + body->GetAngularVelocity().Cross( r ); - - // velocity along normal vector - normalVelocity = ( velocity * contact.normal ) * contact.normal; - - // if moving towards the surface at the contact point - if ( normalVelocity * contact.normal < 0.0f ) { - // calculate impulse - normal = -normalVelocity; - impulseNumerator = normal.Normalize(); - impulseDenominator = body->GetInverseMass() + ( ( body->GetInverseWorldInertia() * r.Cross( normal ) ).Cross( r ) * normal ); - impulse = (impulseNumerator / impulseDenominator) * normal * 1.0001f; - - // apply impulse - body->SetLinearVelocity( body->GetLinearVelocity() + impulse ); - body->SetAngularVelocity( body->GetAngularVelocity() + r.Cross( impulse ) ); - } - } -#else - int i; - idAFBody *body; - idVec3 normal; - - for ( i = 0; i < contactConstraints.Num(); i++ ) { - body = contactConstraints[i]->body1; - normal = contactConstraints[i]->GetContact().normal; - if ( normal * body->next->spatialVelocity.SubVec3(0) <= 0.0f ) { - body->next->spatialVelocity.SubVec3(0) -= 1.0001f * (normal * body->next->spatialVelocity.SubVec3(0)) * normal; - } - body = contactConstraints[i]->body2; - if ( !body ) { - continue; - } - normal = -normal; - if ( normal * body->next->spatialVelocity.SubVec3(0) <= 0.0f ) { - body->next->spatialVelocity.SubVec3(0) -= 1.0001f * (normal * body->next->spatialVelocity.SubVec3(0)) * normal; - } - } -#endif -} - -/* -================ -idPhysics_AF::Evolve -================ -*/ -void idPhysics_AF::Evolve( float timeStep ) { - int i; - float angle; - idVec3 vec; - idAFBody *body; - idVec6 force; - idRotation rotation; - float vSqr, maxLinearVelocity, maxAngularVelocity; - - maxLinearVelocity = af_maxLinearVelocity.GetFloat() / timeStep; - maxAngularVelocity = af_maxAngularVelocity.GetFloat() / timeStep; - - for ( i = 0; i < bodies.Num(); i++ ) { - body = bodies[i]; - - // calculate the spatial velocity for the next physics state - body->InverseWorldSpatialInertiaMultiply( body->acceleration, body->totalForce.ToFloatPtr() ); - body->next->spatialVelocity = body->current->spatialVelocity + timeStep * body->acceleration.SubVec6(0); - - if ( maxLinearVelocity > 0.0f ) { - // cap the linear velocity - vSqr = body->next->spatialVelocity.SubVec3(0).LengthSqr(); - if ( vSqr > Square( maxLinearVelocity ) ) { - body->next->spatialVelocity.SubVec3(0) *= idMath::InvSqrt( vSqr ) * maxLinearVelocity; - } - } - - if ( maxAngularVelocity > 0.0f ) { - // cap the angular velocity - vSqr = body->next->spatialVelocity.SubVec3(1).LengthSqr(); - if ( vSqr > Square( maxAngularVelocity ) ) { - body->next->spatialVelocity.SubVec3(1) *= idMath::InvSqrt( vSqr ) * maxAngularVelocity; - } - } - } - - // make absolutely sure all contact constraints are satisfied - VerifyContactConstraints(); - - // calculate the position of the bodies for the next physics state - for ( i = 0; i < bodies.Num(); i++ ) { - body = bodies[i]; - - // translate world origin - body->next->worldOrigin = body->current->worldOrigin + timeStep * body->next->spatialVelocity.SubVec3( 0 ); - - // convert angular velocity to a rotation matrix - vec = body->next->spatialVelocity.SubVec3( 1 ); - angle = -timeStep * (float) RAD2DEG( vec.Normalize() ); - rotation = idRotation( vec3_origin, vec, angle ); - rotation.Normalize180(); - - // rotate world axis - body->next->worldAxis = body->current->worldAxis * rotation.ToMat3(); - body->next->worldAxis.OrthoNormalizeSelf(); - - // linear and angular friction - body->next->spatialVelocity.SubVec3(0) -= body->linearFriction * body->next->spatialVelocity.SubVec3(0); - body->next->spatialVelocity.SubVec3(1) -= body->angularFriction * body->next->spatialVelocity.SubVec3(1); - } -} - -/* -================ -idPhysics_AF::CollisionImpulse - - apply impulse to the colliding bodies - the current state of the body should be set to the moment of impact - this is silly as it doesn't take the AF structure into account -================ -*/ -bool idPhysics_AF::CollisionImpulse( float timeStep, idAFBody *body, trace_t &collision ) { - idVec3 r, velocity, impulse; - idMat3 inverseWorldInertiaTensor; - float impulseNumerator, impulseDenominator; - impactInfo_t info; - idEntity *ent; - - ent = gameLocal.entities[collision.c.entityNum]; - if ( ent == self ) { - return false; - } - - // get info from other entity involved - ent->GetImpactInfo( self, collision.c.id, collision.c.point, &info ); - // collision point relative to the body center of mass - r = collision.c.point - (body->current->worldOrigin + body->centerOfMass * body->current->worldAxis); - // the velocity at the collision point - velocity = body->current->spatialVelocity.SubVec3(0) + body->current->spatialVelocity.SubVec3(1).Cross(r); - // subtract velocity of other entity - velocity -= info.velocity; - // never stick - if ( velocity * collision.c.normal > 0.0f ) { - velocity = collision.c.normal; - } - inverseWorldInertiaTensor = body->current->worldAxis.Transpose() * body->inverseInertiaTensor * body->current->worldAxis; - impulseNumerator = -( 1.0f + body->bouncyness ) * ( velocity * collision.c.normal ); - impulseDenominator = body->invMass + ( ( inverseWorldInertiaTensor * r.Cross( collision.c.normal ) ).Cross( r ) * collision.c.normal ); - if ( info.invMass ) { - impulseDenominator += info.invMass + ( ( info.invInertiaTensor * info.position.Cross( collision.c.normal ) ).Cross( info.position ) * collision.c.normal ); - } - impulse = (impulseNumerator / impulseDenominator) * collision.c.normal; - - // apply impact to other entity - ent->ApplyImpulse( self, collision.c.id, collision.c.point, -impulse ); - - // callback to self to let the entity know about the impact - return self->Collide( collision, velocity ); -} - -/* -================ -idPhysics_AF::ApplyCollisions -================ -*/ -bool idPhysics_AF::ApplyCollisions( float timeStep ) { - int i; - - for ( i = 0; i < collisions.Num(); i++ ) { - if ( CollisionImpulse( timeStep, collisions[i].body, collisions[i].trace ) ) { - return true; - } - } - return false; -} - -/* -================ -idPhysics_AF::SetupCollisionForBody -================ -*/ -idEntity *idPhysics_AF::SetupCollisionForBody( idAFBody *body ) const { - int i; - idAFBody *b; - idEntity *passEntity; - - passEntity = NULL; - - if ( !selfCollision || !body->fl.selfCollision || af_skipSelfCollision.GetBool() ) { - - // disable all bodies - for ( i = 0; i < bodies.Num(); i++ ) { - bodies[i]->clipModel->Disable(); - } - - // don't collide with world collision model if attached to the world - for ( i = 0; i < body->constraints.Num(); i++ ) { - if ( !body->constraints[i]->fl.noCollision ) { - continue; - } - // if this constraint attaches the body to the world - if ( body->constraints[i]->body2 == NULL ) { - // don't collide with the world collision model - passEntity = gameLocal.world; - } - } - - } else { - - // enable all bodies that have self collision - for ( i = 0; i < bodies.Num(); i++ ) { - if ( bodies[i]->fl.selfCollision ) { - bodies[i]->clipModel->Enable(); - } else { - bodies[i]->clipModel->Disable(); - } - } - - // don't let the body collide with itself - body->clipModel->Disable(); - - // disable any bodies attached with constraints - for ( i = 0; i < body->constraints.Num(); i++ ) { - if ( !body->constraints[i]->fl.noCollision ) { - continue; - } - // if this constraint attaches the body to the world - if ( body->constraints[i]->body2 == NULL ) { - // don't collide with the world collision model - passEntity = gameLocal.world; - } else { - if ( body->constraints[i]->body1 == body ) { - b = body->constraints[i]->body2; - } else if ( body->constraints[i]->body2 == body ) { - b = body->constraints[i]->body1; - } else { - continue; - } - // don't collide with this body - b->clipModel->Disable(); - } - } - } - - return passEntity; -} - -/* -================ -idPhysics_AF::CheckForCollisions - - check for collisions between the current and next state - if there is a collision the next state is set to the state at the moment of impact - assumes all bodies are linked for collision detection and relinks all bodies after moving them -================ -*/ -void idPhysics_AF::CheckForCollisions( float timeStep ) { -// #define TEST_COLLISION_DETECTION - int i, index; - idAFBody *body; - idMat3 axis; - idRotation rotation; - trace_t collision; - idEntity *passEntity; - - // clear list with collisions - collisions.SetNum( 0, false ); - - if ( !enableCollision ) { - return; - } - - for ( i = 0; i < bodies.Num(); i++ ) { - body = bodies[i]; - - if ( body->clipMask != 0 ) { - - passEntity = SetupCollisionForBody( body ); - -#ifdef TEST_COLLISION_DETECTION - bool startsolid = false; - if ( gameLocal.clip.Contents( body->current->worldOrigin, body->clipModel, - body->current->worldAxis, body->clipMask, passEntity ) ) { - startsolid = true; - } -#endif - - TransposeMultiply( body->current->worldAxis, body->next->worldAxis, axis ); - rotation = axis.ToRotation(); - rotation.SetOrigin( body->current->worldOrigin ); - - // if there was a collision - if ( gameLocal.clip.Motion( collision, body->current->worldOrigin, body->next->worldOrigin, rotation, - body->clipModel, body->current->worldAxis, body->clipMask, passEntity ) ) { - - // set the next state to the state at the moment of impact - body->next->worldOrigin = collision.endpos; - body->next->worldAxis = collision.endAxis; - - // add collision to the list - index = collisions.Num(); - collisions.SetNum( index + 1, false ); - collisions[index].trace = collision; - collisions[index].body = body; - } - -#ifdef TEST_COLLISION_DETECTION - if ( gameLocal.clip.Contents( body->next->worldOrigin, body->clipModel, - body->next->worldAxis, body->clipMask, passEntity ) ) { - if ( !startsolid ) { - int bah = 1; - } - } -#endif - } - - body->clipModel->Link( gameLocal.clip, self, body->clipModel->GetId(), body->next->worldOrigin, body->next->worldAxis ); - } -} - -/* -================ -idPhysics_AF::EvaluateContacts -================ -*/ -bool idPhysics_AF::EvaluateContacts( void ) { - int i, j, k, numContacts, numBodyContacts; - idAFBody *body; - contactInfo_t contactInfo[10]; - idEntity *passEntity; - idVecX dir( 6, VECX_ALLOCA( 6 ) ); - - // evaluate bodies - EvaluateBodies( current.lastTimeStep ); - - // remove all existing contacts - ClearContacts(); - - contactBodies.SetNum( 0, false ); - - if ( !enableCollision ) { - return false; - } - - // find all the contacts - for ( i = 0; i < bodies.Num(); i++ ) { - body = bodies[i]; - - if ( body->clipMask == 0 ) { - continue; - } - - passEntity = SetupCollisionForBody( body ); - - body->InverseWorldSpatialInertiaMultiply( dir, body->current->externalForce.ToFloatPtr() ); - dir.SubVec6(0) = body->current->spatialVelocity + current.lastTimeStep * dir.SubVec6(0); - dir.SubVec3(0).Normalize(); - dir.SubVec3(1).Normalize(); - - numContacts = gameLocal.clip.Contacts( contactInfo, 10, body->current->worldOrigin, dir.SubVec6(0), 2.0f, //CONTACT_EPSILON, - body->clipModel, body->current->worldAxis, body->clipMask, passEntity ); - -#if 1 - // merge nearby contacts between the same bodies - // and assure there are at most three planar contacts between any pair of bodies - for ( j = 0; j < numContacts; j++ ) { - - numBodyContacts = 0; - for ( k = 0; k < contacts.Num(); k++ ) { - if ( contacts[k].entityNum == contactInfo[j].entityNum ) { - if ( ( contacts[k].id == i && contactInfo[j].id == contactBodies[k] ) || - ( contactBodies[k] == i && contacts[k].id == contactInfo[j].id ) ) { - - if ( ( contacts[k].point - contactInfo[j].point ).LengthSqr() < Square( 2.0f ) ) { - break; - } - if ( idMath::Fabs( contacts[k].normal * contactInfo[j].normal ) > 0.9f ) { - numBodyContacts++; - } - } - } - } - - if ( k >= contacts.Num() && numBodyContacts < 3 ) { - contacts.Append( contactInfo[j] ); - contactBodies.Append( i ); - } - } - -#else - - for ( j = 0; j < numContacts; j++ ) { - contacts.Append( contactInfo[j] ); - contactBodies.Append( i ); - } -#endif - - } - - AddContactEntitiesForContacts(); - - return ( contacts.Num() != 0 ); -} - -/* -================ -idPhysics_AF::SetupContactConstraints -================ -*/ -void idPhysics_AF::SetupContactConstraints( void ) { - int i; - - // make sure enough contact constraints are allocated - contactConstraints.AssureSizeAlloc( contacts.Num(), idListNewElement ); - contactConstraints.SetNum( contacts.Num(), false ); - - // setup contact constraints - for ( i = 0; i < contacts.Num(); i++ ) { - // add contact constraint - contactConstraints[i]->physics = this; - if ( contacts[i].entityNum == self->entityNumber ) { - contactConstraints[i]->Setup( bodies[contactBodies[i]], bodies[ contacts[i].id ], contacts[i] ); - } - else { - contactConstraints[i]->Setup( bodies[contactBodies[i]], NULL, contacts[i] ); - } - } -} - -/* -================ -idPhysics_AF::ApplyContactForces -================ -*/ -void idPhysics_AF::ApplyContactForces( void ) { -#if 0 - int i; - idEntity *ent; - idVec3 force; - - for ( i = 0; i < contactConstraints.Num(); i++ ) { - if ( contactConstraints[i]->body2 != NULL ) { - continue; - } - const contactInfo_t &contact = contactConstraints[i]->GetContact(); - ent = gameLocal.entities[contact.entityNum]; - if ( !ent ) { - continue; - } - force.Zero(); - ent->AddForce( self, contact.id, contact.point, force ); - } -#endif -} - -/* -================ -idPhysics_AF::ClearExternalForce -================ -*/ -void idPhysics_AF::ClearExternalForce( void ) { - int i; - idAFBody *body; - - for ( i = 0; i < bodies.Num(); i++ ) { - body = bodies[i]; - - // clear external force - body->current->externalForce.Zero(); - body->next->externalForce.Zero(); - } -} - -/* -================ -idPhysics_AF::AddGravity -================ -*/ -void idPhysics_AF::AddGravity( void ) { - int i; - idAFBody *body; - - for ( i = 0; i < bodies.Num(); i++ ) { - body = bodies[i]; - // add gravitational force - body->current->externalForce.SubVec3( 0 ) += body->mass * gravityVector; - } -} - -/* -================ -idPhysics_AF::SwapStates -================ -*/ -void idPhysics_AF::SwapStates( void ) { - int i; - idAFBody *body; - AFBodyPState_t *swap; - - for ( i = 0; i < bodies.Num(); i++ ) { - - body = bodies[i]; - - // swap the current and next state for next simulation step - swap = body->current; - body->current = body->next; - body->next = swap; - } -} - -/* -================ -idPhysics_AF::UpdateClipModels -================ -*/ -void idPhysics_AF::UpdateClipModels( void ) { - int i; - idAFBody *body; - - for ( i = 0; i < bodies.Num(); i++ ) { - body = bodies[i]; - body->clipModel->Link( gameLocal.clip, self, body->clipModel->GetId(), body->current->worldOrigin, body->current->worldAxis ); - } -} - -/* -================ -idPhysics_AF::SetSuspendSpeed -================ -*/ -void idPhysics_AF::SetSuspendSpeed( const idVec2 &velocity, const idVec2 &acceleration ) { - this->suspendVelocity = velocity; - this->suspendAcceleration = acceleration; -} - -/* -================ -idPhysics_AF::SetSuspendTime -================ -*/ -void idPhysics_AF::SetSuspendTime( const float minTime, const float maxTime ) { - this->minMoveTime = minTime; - this->maxMoveTime = maxTime; -} - -/* -================ -idPhysics_AF::SetSuspendTolerance -================ -*/ -void idPhysics_AF::SetSuspendTolerance( const float noMoveTime, const float noMoveTranslation, const float noMoveRotation ) { - this->noMoveTime = noMoveTime; - this->noMoveTranslation = noMoveTranslation; - this->noMoveRotation = noMoveRotation; -} - -/* -================ -idPhysics_AF::SetTimeScaleRamp -================ -*/ -void idPhysics_AF::SetTimeScaleRamp( const float start, const float end ) { - timeScaleRampStart = start; - timeScaleRampEnd = end; -} - -/* -================ -idPhysics_AF::SetJointFrictionDent -================ -*/ -void idPhysics_AF::SetJointFrictionDent( const float dent, const float start, const float end ) { - jointFrictionDent = dent; - jointFrictionDentStart = start; - jointFrictionDentEnd = end; -} - -/* -================ -idPhysics_AF::GetJointFrictionScale -================ -*/ -float idPhysics_AF::GetJointFrictionScale( void ) const { - if ( jointFrictionDentScale > 0.0f ) { - return jointFrictionDentScale; - } else if ( jointFrictionScale > 0.0f ) { - return jointFrictionScale; - } else if ( af_jointFrictionScale.GetFloat() > 0.0f ) { - return af_jointFrictionScale.GetFloat(); - } - return 1.0f; -} - -/* -================ -idPhysics_AF::SetContactFrictionDent -================ -*/ -void idPhysics_AF::SetContactFrictionDent( const float dent, const float start, const float end ) { - contactFrictionDent = dent; - contactFrictionDentStart = start; - contactFrictionDentEnd = end; -} - -/* -================ -idPhysics_AF::GetContactFrictionScale -================ -*/ -float idPhysics_AF::GetContactFrictionScale( void ) const { - if ( contactFrictionDentScale > 0.0f ) { - return contactFrictionDentScale; - } else if ( contactFrictionScale > 0.0f ) { - return contactFrictionScale; - } else if ( af_contactFrictionScale.GetFloat() > 0.0f ) { - return af_contactFrictionScale.GetFloat(); - } - return 1.0f; -} - -/* -================ -idPhysics_AF::TestIfAtRest -================ -*/ -bool idPhysics_AF::TestIfAtRest( float timeStep ) { - int i; - float translationSqr, maxTranslationSqr, rotation, maxRotation; - idAFBody *body; - - if ( current.atRest >= 0 ) { - return true; - } - - current.activateTime += timeStep; - - // if the simulation should never be suspended before a certaint amount of time passed - if ( minMoveTime > 0.0f && current.activateTime < minMoveTime ) { - return false; - } - - // if the simulation should always be suspended after a certain amount time passed - if ( maxMoveTime > 0.0f && current.activateTime > maxMoveTime ) { - return true; - } - - // test if all bodies hardly moved over a period of time - if ( current.noMoveTime == 0.0f ) { - for ( i = 0; i < bodies.Num(); i++ ) { - body = bodies[i]; - body->atRestOrigin = body->current->worldOrigin; - body->atRestAxis = body->current->worldAxis; - } - current.noMoveTime += timeStep; - } - else if ( current.noMoveTime > noMoveTime ) { - current.noMoveTime = 0.0f; - maxTranslationSqr = 0.0f; - maxRotation = 0.0f; - for ( i = 0; i < bodies.Num(); i++ ) { - body = bodies[i]; - - translationSqr = ( body->current->worldOrigin - body->atRestOrigin ).LengthSqr(); - if ( translationSqr > maxTranslationSqr ) { - maxTranslationSqr = translationSqr; - } - rotation = ( body->atRestAxis.Transpose() * body->current->worldAxis ).ToRotation().GetAngle(); - if ( rotation > maxRotation ) { - maxRotation = rotation; - } - } - - if ( maxTranslationSqr < Square( noMoveTranslation ) && maxRotation < noMoveRotation ) { - // hardly moved over a period of time so the articulated figure may come to rest - return true; - } - } else { - current.noMoveTime += timeStep; - } - - // test if the velocity or acceleration of any body is still too large to come to rest - for ( i = 0; i < bodies.Num(); i++ ) { - body = bodies[i]; - - if ( body->current->spatialVelocity.SubVec3(0).LengthSqr() > Square( suspendVelocity[0] ) ) { - return false; - } - if ( body->current->spatialVelocity.SubVec3(1).LengthSqr() > Square( suspendVelocity[1] ) ) { - return false; - } - if ( body->acceleration.SubVec3(0).LengthSqr() > Square( suspendAcceleration[0] ) ) { - return false; - } - if ( body->acceleration.SubVec3(1).LengthSqr() > Square( suspendAcceleration[1] ) ) { - return false; - } - } - - // all bodies have a velocity and acceleration small enough to come to rest - return true; -} - -/* -================ -idPhysics_AF::Rest -================ -*/ -void idPhysics_AF::Rest( void ) { - int i; - - current.atRest = gameLocal.time; - - for ( i = 0; i < bodies.Num(); i++ ) { - bodies[i]->current->spatialVelocity.Zero(); - bodies[i]->current->externalForce.Zero(); - } - - self->BecomeInactive( TH_PHYSICS ); -} - -/* -================ -idPhysics_AF::Activate -================ -*/ -void idPhysics_AF::Activate( void ) { - // if the articulated figure was at rest - if ( current.atRest >= 0 ) { - // normally gravity is added at the end of a simulation frame - // if the figure was at rest add gravity here so it is applied this simulation frame - AddGravity(); - // reset the active time for the max move time - current.activateTime = 0.0f; - } - current.atRest = -1; - current.noMoveTime = 0.0f; - self->BecomeActive( TH_PHYSICS ); -} - -/* -================ -idPhysics_AF::PutToRest - - put to rest untill something collides with this physics object -================ -*/ -void idPhysics_AF::PutToRest( void ) { - Rest(); -} - -/* -================ -idPhysics_AF::EnableImpact -================ -*/ -void idPhysics_AF::EnableImpact( void ) { - noImpact = false; -} - -/* -================ -idPhysics_AF::DisableImpact -================ -*/ -void idPhysics_AF::DisableImpact( void ) { - noImpact = true; -} - -/* -================ -idPhysics_AF::AddPushVelocity -================ -*/ -void idPhysics_AF::AddPushVelocity( const idVec6 &pushVelocity ) { - int i; - - if ( pushVelocity != vec6_origin ) { - for ( i = 0; i < bodies.Num(); i++ ) { - bodies[i]->current->spatialVelocity += pushVelocity; - } - } -} - -/* -================ -idPhysics_AF::SetClipModel -================ -*/ -void idPhysics_AF::SetClipModel( idClipModel *model, float density, int id, bool freeOld ) { -} - -/* -================ -idPhysics_AF::GetClipModel -================ -*/ -idClipModel *idPhysics_AF::GetClipModel( int id ) const { - if ( id >= 0 && id < bodies.Num() ) { - return bodies[id]->GetClipModel(); - } - return NULL; -} - -/* -================ -idPhysics_AF::GetNumClipModels -================ -*/ -int idPhysics_AF::GetNumClipModels( void ) const { - return bodies.Num(); -} - -/* -================ -idPhysics_AF::SetMass -================ -*/ -void idPhysics_AF::SetMass( float mass, int id ) { - if ( id >= 0 && id < bodies.Num() ) { - } - else { - forceTotalMass = mass; - } - SetChanged(); -} - -/* -================ -idPhysics_AF::GetMass -================ -*/ -float idPhysics_AF::GetMass( int id ) const { - if ( id >= 0 && id < bodies.Num() ) { - return bodies[id]->mass; - } - return totalMass; -} - -/* -================ -idPhysics_AF::SetContents -================ -*/ -void idPhysics_AF::SetContents( int contents, int id ) { - int i; - - if ( id >= 0 && id < bodies.Num() ) { - bodies[id]->GetClipModel()->SetContents( contents ); - } - else { - for ( i = 0; i < bodies.Num(); i++ ) { - bodies[i]->GetClipModel()->SetContents( contents ); - } - } -} - -/* -================ -idPhysics_AF::GetContents -================ -*/ -int idPhysics_AF::GetContents( int id ) const { - int i, contents; - - if ( id >= 0 && id < bodies.Num() ) { - return bodies[id]->GetClipModel()->GetContents(); - } - else { - contents = 0; - for ( i = 0; i < bodies.Num(); i++ ) { - contents |= bodies[i]->GetClipModel()->GetContents(); - } - return contents; - } -} - -/* -================ -idPhysics_AF::GetBounds -================ -*/ -const idBounds &idPhysics_AF::GetBounds( int id ) const { - int i; - static idBounds relBounds; - - if ( id >= 0 && id < bodies.Num() ) { - return bodies[id]->GetClipModel()->GetBounds(); - } - else if ( !bodies.Num() ) { - relBounds.Zero(); - return relBounds; - } - else { - relBounds = bodies[0]->GetClipModel()->GetBounds(); - for ( i = 1; i < bodies.Num(); i++ ) { - idBounds bounds; - idVec3 origin = ( bodies[i]->GetWorldOrigin() - bodies[0]->GetWorldOrigin() ) * bodies[0]->GetWorldAxis().Transpose(); - idMat3 axis = bodies[i]->GetWorldAxis() * bodies[0]->GetWorldAxis().Transpose(); - bounds.FromTransformedBounds( bodies[i]->GetClipModel()->GetBounds(), origin, axis ); - relBounds += bounds; - } - return relBounds; - } -} - -/* -================ -idPhysics_AF::GetAbsBounds -================ -*/ -const idBounds &idPhysics_AF::GetAbsBounds( int id ) const { - int i; - static idBounds absBounds; - - if ( id >= 0 && id < bodies.Num() ) { - return bodies[id]->GetClipModel()->GetAbsBounds(); - } - else if ( !bodies.Num() ) { - absBounds.Zero(); - return absBounds; - } - else { - absBounds = bodies[0]->GetClipModel()->GetAbsBounds(); - for ( i = 1; i < bodies.Num(); i++ ) { - absBounds += bodies[i]->GetClipModel()->GetAbsBounds(); - } - return absBounds; - } -} - -/* -================ -idPhysics_AF::Evaluate -================ -*/ -bool idPhysics_AF::Evaluate( int timeStepMSec, int endTimeMSec ) { - float timeStep; - - if ( timeScaleRampStart < MS2SEC( endTimeMSec ) && timeScaleRampEnd > MS2SEC( endTimeMSec ) ) { - timeStep = MS2SEC( timeStepMSec ) * ( MS2SEC( endTimeMSec ) - timeScaleRampStart ) / ( timeScaleRampEnd - timeScaleRampStart ); - } else if ( af_timeScale.GetFloat() != 1.0f ) { - timeStep = MS2SEC( timeStepMSec ) * af_timeScale.GetFloat(); - } else { - timeStep = MS2SEC( timeStepMSec ) * timeScale; - } - current.lastTimeStep = timeStep; - - - // if the articulated figure changed - if ( changedAF || ( linearTime != af_useLinearTime.GetBool() ) ) { - BuildTrees(); - changedAF = false; - linearTime = af_useLinearTime.GetBool(); - } - - // get the new master position - if ( masterBody ) { - idVec3 masterOrigin; - idMat3 masterAxis; - self->GetMasterPosition( masterOrigin, masterAxis ); - if ( current.atRest >= 0 && ( masterBody->current->worldOrigin != masterOrigin || masterBody->current->worldAxis != masterAxis ) ) { - Activate(); - } - masterBody->current->worldOrigin = masterOrigin; - masterBody->current->worldAxis = masterAxis; - } - - // if the simulation is suspended because the figure is at rest - if ( current.atRest >= 0 || timeStep <= 0.0f ) { - DebugDraw(); - return false; - } - - // move the af velocity into the frame of a pusher - AddPushVelocity( -current.pushVelocity ); - -#ifdef AF_TIMINGS - timer_total.Start(); -#endif - -#ifdef AF_TIMINGS - timer_collision.Start(); -#endif - - // evaluate contacts - EvaluateContacts(); - - // setup contact constraints - SetupContactConstraints(); - -#ifdef AF_TIMINGS - timer_collision.Stop(); -#endif - - // evaluate constraint equations - EvaluateConstraints( timeStep ); - - // apply friction - ApplyFriction( timeStep, endTimeMSec ); - - // add frame constraints - AddFrameConstraints(); - -#ifdef AF_TIMINGS - int i, numPrimary = 0, numAuxiliary = 0; - for ( i = 0; i < primaryConstraints.Num(); i++ ) { - numPrimary += primaryConstraints[i]->J1.GetNumRows(); - } - for ( i = 0; i < auxiliaryConstraints.Num(); i++ ) { - numAuxiliary += auxiliaryConstraints[i]->J1.GetNumRows(); - } - timer_pc.Start(); -#endif - - // factor matrices for primary constraints - PrimaryFactor(); - - // calculate forces on bodies after applying primary constraints - PrimaryForces( timeStep ); - -#ifdef AF_TIMINGS - timer_pc.Stop(); - timer_ac.Start(); -#endif - - // calculate and apply auxiliary constraint forces - AuxiliaryForces( timeStep ); - -#ifdef AF_TIMINGS - timer_ac.Stop(); -#endif - - // evolve current state to next state - Evolve( timeStep ); - - // debug graphics - DebugDraw(); - - // clear external forces on all bodies - ClearExternalForce(); - - // apply contact force to other entities - ApplyContactForces(); - - // remove all frame constraints - RemoveFrameConstraints(); - -#ifdef AF_TIMINGS - timer_collision.Start(); -#endif - - // check for collisions between current and next state - CheckForCollisions( timeStep ); - -#ifdef AF_TIMINGS - timer_collision.Stop(); -#endif - - // swap the current and next state - SwapStates(); - - // make sure all clip models are disabled in case they were enabled for self collision - if ( selfCollision && !af_skipSelfCollision.GetBool() ) { - DisableClip(); - } - - // apply collision impulses - if ( ApplyCollisions( timeStep ) ) { - current.atRest = gameLocal.time; - comeToRest = true; - } - - // test if the simulation can be suspended because the whole figure is at rest - if ( comeToRest && TestIfAtRest( timeStep ) ) { - Rest(); - } else { - ActivateContactEntities(); - } - - // add gravitational force - AddGravity(); - - // move the af velocity back into the world frame - AddPushVelocity( current.pushVelocity ); - current.pushVelocity.Zero(); - - if ( IsOutsideWorld() ) { - gameLocal.Warning( "articulated figure moved outside world bounds for entity '%s' type '%s' at (%s)", - self->name.c_str(), self->GetType()->classname, bodies[0]->current->worldOrigin.ToString(0) ); - Rest(); - } - -#ifdef AF_TIMINGS - timer_total.Stop(); - - if ( af_showTimings.GetInteger() == 1 ) { - gameLocal.Printf( "%12s: t %u pc %2d, %u ac %2d %u lcp %u cd %u\n", - self->name.c_str(), - timer_total.Milliseconds(), - numPrimary, timer_pc.Milliseconds(), - numAuxiliary, timer_ac.Milliseconds() - timer_lcp.Milliseconds(), - timer_lcp.Milliseconds(), timer_collision.Milliseconds() ); - } - else if ( af_showTimings.GetInteger() == 2 ) { - numArticulatedFigures++; - if ( endTimeMSec > lastTimerReset ) { - gameLocal.Printf( "af %d: t %u pc %2d, %u ac %2d %u lcp %u cd %u\n", - numArticulatedFigures, - timer_total.Milliseconds(), - numPrimary, timer_pc.Milliseconds(), - numAuxiliary, timer_ac.Milliseconds() - timer_lcp.Milliseconds(), - timer_lcp.Milliseconds(), timer_collision.Milliseconds() ); - } - } - - if ( endTimeMSec > lastTimerReset ) { - lastTimerReset = endTimeMSec; - numArticulatedFigures = 0; - timer_total.Clear(); - timer_pc.Clear(); - timer_ac.Clear(); - timer_collision.Clear(); - timer_lcp.Clear(); - } -#endif - - return true; -} - -/* -================ -idPhysics_AF::UpdateTime -================ -*/ -void idPhysics_AF::UpdateTime( int endTimeMSec ) { -} - -/* -================ -idPhysics_AF::GetTime -================ -*/ -int idPhysics_AF::GetTime( void ) const { - return gameLocal.time; -} - -/* -================ -DrawTraceModelSilhouette -================ -*/ -void DrawTraceModelSilhouette( const idVec3 &projectionOrigin, const idClipModel *clipModel ) { - int i, numSilEdges; - int silEdges[MAX_TRACEMODEL_EDGES]; - idVec3 v1, v2; - const idTraceModel *trm = clipModel->GetTraceModel(); - const idVec3 &origin = clipModel->GetOrigin(); - const idMat3 &axis = clipModel->GetAxis(); - - numSilEdges = trm->GetProjectionSilhouetteEdges( ( projectionOrigin - origin ) * axis.Transpose(), silEdges ); - for ( i = 0; i < numSilEdges; i++ ) { - v1 = trm->verts[ trm->edges[ abs(silEdges[i]) ].v[ INTSIGNBITSET( silEdges[i] ) ] ]; - v2 = trm->verts[ trm->edges[ abs(silEdges[i]) ].v[ INTSIGNBITNOTSET( silEdges[i] ) ] ]; - gameRenderWorld->DebugArrow( colorRed, origin + v1 * axis, origin + v2 * axis, 1 ); - } -} - -/* -================ -idPhysics_AF::DebugDraw -================ -*/ -void idPhysics_AF::DebugDraw( void ) { - int i; - idAFBody *body, *highlightBody = NULL, *constrainedBody1 = NULL, *constrainedBody2 = NULL; - idAFConstraint *constraint; - idVec3 center; - idMat3 axis; - - if ( af_highlightConstraint.GetString()[0] ) { - constraint = GetConstraint( af_highlightConstraint.GetString() ); - if ( constraint ) { - constraint->GetCenter( center ); - axis = gameLocal.GetLocalPlayer()->viewAngles.ToMat3(); - gameRenderWorld->DebugCone( colorYellow, center, (axis[2] - axis[1]) * 4.0f, 0.0f, 1.0f, 0 ); - - if ( af_showConstrainedBodies.GetBool() ) { - cvarSystem->SetCVarString( "cm_drawColor", colorCyan.ToString( 0 ) ); - constrainedBody1 = constraint->body1; - if ( constrainedBody1 ) { - collisionModelManager->DrawModel( constrainedBody1->clipModel->Handle(), constrainedBody1->clipModel->GetOrigin(), - constrainedBody1->clipModel->GetAxis(), vec3_origin, 0.0f ); - } - cvarSystem->SetCVarString( "cm_drawColor", colorBlue.ToString( 0 ) ); - constrainedBody2 = constraint->body2; - if ( constrainedBody2 ) { - collisionModelManager->DrawModel( constrainedBody2->clipModel->Handle(), constrainedBody2->clipModel->GetOrigin(), - constrainedBody2->clipModel->GetAxis(), vec3_origin, 0.0f ); - } - cvarSystem->SetCVarString( "cm_drawColor", colorRed.ToString( 0 ) ); - } - } - } - - if ( af_highlightBody.GetString()[0] ) { - highlightBody = GetBody( af_highlightBody.GetString() ); - if ( highlightBody ) { - cvarSystem->SetCVarString( "cm_drawColor", colorYellow.ToString( 0 ) ); - collisionModelManager->DrawModel( highlightBody->clipModel->Handle(), highlightBody->clipModel->GetOrigin(), - highlightBody->clipModel->GetAxis(), vec3_origin, 0.0f ); - cvarSystem->SetCVarString( "cm_drawColor", colorRed.ToString( 0 ) ); - } - } - - if ( af_showBodies.GetBool() ) { - for ( i = 0; i < bodies.Num(); i++ ) { - body = bodies[i]; - if ( body == constrainedBody1 || body == constrainedBody2 ) { - continue; - } - if ( body == highlightBody ) { - continue; - } - collisionModelManager->DrawModel( body->clipModel->Handle(), body->clipModel->GetOrigin(), - body->clipModel->GetAxis(), vec3_origin, 0.0f ); - //DrawTraceModelSilhouette( gameLocal.GetLocalPlayer()->GetEyePosition(), body->clipModel ); - } - } - - if ( af_showBodyNames.GetBool() ) { - for ( i = 0; i < bodies.Num(); i++ ) { - body = bodies[i]; - gameRenderWorld->DrawText( body->GetName().c_str(), body->GetWorldOrigin(), 0.08f, colorCyan, gameLocal.GetLocalPlayer()->viewAngles.ToMat3(), 1 ); - } - } - - if ( af_showMass.GetBool() ) { - for ( i = 0; i < bodies.Num(); i++ ) { - body = bodies[i]; - gameRenderWorld->DrawText( va( "\n%1.2f", 1.0f / body->GetInverseMass() ), body->GetWorldOrigin(), 0.08f, colorCyan, gameLocal.GetLocalPlayer()->viewAngles.ToMat3(), 1 ); - } - } - - if ( af_showTotalMass.GetBool() ) { - axis = gameLocal.GetLocalPlayer()->viewAngles.ToMat3(); - gameRenderWorld->DrawText( va( "\n%1.2f", totalMass ), bodies[0]->GetWorldOrigin() + axis[2] * 8.0f, 0.15f, colorCyan, axis, 1 ); - } - - if ( af_showInertia.GetBool() ) { - for ( i = 0; i < bodies.Num(); i++ ) { - body = bodies[i]; - idMat3 &I = body->inertiaTensor; - gameRenderWorld->DrawText( va( "\n\n\n( %.1f %.1f %.1f )\n( %.1f %.1f %.1f )\n( %.1f %.1f %.1f )", - I[0].x, I[0].y, I[0].z, - I[1].x, I[1].y, I[1].z, - I[2].x, I[2].y, I[2].z ), - body->GetWorldOrigin(), 0.05f, colorCyan, gameLocal.GetLocalPlayer()->viewAngles.ToMat3(), 1 ); - } - } - - if ( af_showVelocity.GetBool() ) { - for ( i = 0; i < bodies.Num(); i++ ) { - DrawVelocity( bodies[i]->clipModel->GetId(), 0.1f, 4.0f ); - } - } - - if ( af_showConstraints.GetBool() ) { - for ( i = 0; i < primaryConstraints.Num(); i++ ) { - constraint = primaryConstraints[i]; - constraint->DebugDraw(); - } - if ( !af_showPrimaryOnly.GetBool() ) { - for ( i = 0; i < auxiliaryConstraints.Num(); i++ ) { - constraint = auxiliaryConstraints[i]; - constraint->DebugDraw(); - } - } - } - - if ( af_showConstraintNames.GetBool() ) { - for ( i = 0; i < primaryConstraints.Num(); i++ ) { - constraint = primaryConstraints[i]; - constraint->GetCenter( center ); - gameRenderWorld->DrawText( constraint->GetName().c_str(), center, 0.08f, colorCyan, gameLocal.GetLocalPlayer()->viewAngles.ToMat3(), 1 ); - } - if ( !af_showPrimaryOnly.GetBool() ) { - for ( i = 0; i < auxiliaryConstraints.Num(); i++ ) { - constraint = auxiliaryConstraints[i]; - constraint->GetCenter( center ); - gameRenderWorld->DrawText( constraint->GetName().c_str(), center, 0.08f, colorCyan, gameLocal.GetLocalPlayer()->viewAngles.ToMat3(), 1 ); - } - } - } - - if ( af_showTrees.GetBool() || ( af_showActive.GetBool() && current.atRest < 0 ) ) { - for ( i = 0; i < trees.Num(); i++ ) { - trees[i]->DebugDraw( idStr::ColorForIndex( i+3 ) ); - } - } -} - -/* -================ -idPhysics_AF::idPhysics_AF -================ -*/ -idPhysics_AF::idPhysics_AF( void ) { - trees.Clear(); - bodies.Clear(); - constraints.Clear(); - primaryConstraints.Clear(); - auxiliaryConstraints.Clear(); - frameConstraints.Clear(); - contacts.Clear(); - collisions.Clear(); - changedAF = true; - masterBody = NULL; - - lcp = idLCP::AllocSymmetric(); - - memset( ¤t, 0, sizeof( current ) ); - current.atRest = -1; - current.lastTimeStep = USERCMD_MSEC; - saved = current; - - linearFriction = 0.005f; - angularFriction = 0.005f; - contactFriction = 0.8f; - bouncyness = 0.4f; - totalMass = 0.0f; - forceTotalMass = -1.0f; - - suspendVelocity.Set( SUSPEND_LINEAR_VELOCITY, SUSPEND_ANGULAR_VELOCITY ); - suspendAcceleration.Set( SUSPEND_LINEAR_ACCELERATION, SUSPEND_LINEAR_ACCELERATION ); - noMoveTime = NO_MOVE_TIME; - noMoveTranslation = NO_MOVE_TRANSLATION_TOLERANCE; - noMoveRotation = NO_MOVE_ROTATION_TOLERANCE; - minMoveTime = MIN_MOVE_TIME; - maxMoveTime = MAX_MOVE_TIME; - impulseThreshold = IMPULSE_THRESHOLD; - - timeScale = 1.0f; - timeScaleRampStart = 0.0f; - timeScaleRampEnd = 0.0f; - - jointFrictionScale = 0.0f; - jointFrictionDent = 0.0f; - jointFrictionDentStart = 0.0f; - jointFrictionDentEnd = 0.0f; - jointFrictionDentScale = 0.0f; - - contactFrictionScale = 0.0f; - contactFrictionDent = 0.0f; - contactFrictionDentStart = 0.0f; - contactFrictionDentEnd = 0.0f; - contactFrictionDentScale = 0.0f; - - enableCollision = true; - selfCollision = true; - comeToRest = true; - linearTime = true; - noImpact = false; - worldConstraintsLocked = false; - forcePushable = false; - -#ifdef AF_TIMINGS - lastTimerReset = 0; -#endif -} - -/* -================ -idPhysics_AF::~idPhysics_AF -================ -*/ -idPhysics_AF::~idPhysics_AF( void ) { - int i; - - trees.DeleteContents( true ); - - for ( i = 0; i < bodies.Num(); i++ ) { - delete bodies[i]; - } - - for ( i = 0; i < constraints.Num(); i++ ) { - delete constraints[i]; - } - - contactConstraints.SetNum( contactConstraints.NumAllocated(), false ); - for ( i = 0; i < contactConstraints.NumAllocated(); i++ ) { - delete contactConstraints[i]; - } - - delete lcp; - - if ( masterBody ) { - delete masterBody; - } -} - -/* -================ -idPhysics_AF_SavePState -================ -*/ -void idPhysics_AF_SavePState( idSaveGame *saveFile, const AFPState_t &state ) { - saveFile->WriteInt( state.atRest ); - saveFile->WriteFloat( state.noMoveTime ); - saveFile->WriteFloat( state.activateTime ); - saveFile->WriteFloat( state.lastTimeStep ); - saveFile->WriteVec6( state.pushVelocity ); -} - -/* -================ -idPhysics_AF_RestorePState -================ -*/ -void idPhysics_AF_RestorePState( idRestoreGame *saveFile, AFPState_t &state ) { - saveFile->ReadInt( state.atRest ); - saveFile->ReadFloat( state.noMoveTime ); - saveFile->ReadFloat( state.activateTime ); - saveFile->ReadFloat( state.lastTimeStep ); - saveFile->ReadVec6( state.pushVelocity ); -} - -/* -================ -idPhysics_AF::Save -================ -*/ -void idPhysics_AF::Save( idSaveGame *saveFile ) const { - int i; - - // the articulated figure structure is handled by the owner - - idPhysics_AF_SavePState( saveFile, current ); - idPhysics_AF_SavePState( saveFile, saved ); - - saveFile->WriteInt( bodies.Num() ); - for ( i = 0; i < bodies.Num(); i++ ) { - bodies[i]->Save( saveFile ); - } - if ( masterBody ) { - saveFile->WriteBool( true ); - masterBody->Save( saveFile ); - } else { - saveFile->WriteBool( false ); - } - - saveFile->WriteInt( constraints.Num() ); - for ( i = 0; i < constraints.Num(); i++ ) { - constraints[i]->Save( saveFile ); - } - - saveFile->WriteBool( changedAF ); - - saveFile->WriteFloat( linearFriction ); - saveFile->WriteFloat( angularFriction ); - saveFile->WriteFloat( contactFriction ); - saveFile->WriteFloat( bouncyness ); - saveFile->WriteFloat( totalMass ); - saveFile->WriteFloat( forceTotalMass ); - - saveFile->WriteVec2( suspendVelocity ); - saveFile->WriteVec2( suspendAcceleration ); - saveFile->WriteFloat( noMoveTime ); - saveFile->WriteFloat( noMoveTranslation ); - saveFile->WriteFloat( noMoveRotation ); - saveFile->WriteFloat( minMoveTime ); - saveFile->WriteFloat( maxMoveTime ); - saveFile->WriteFloat( impulseThreshold ); - - saveFile->WriteFloat( timeScale ); - saveFile->WriteFloat( timeScaleRampStart ); - saveFile->WriteFloat( timeScaleRampEnd ); - - saveFile->WriteFloat( jointFrictionScale ); - saveFile->WriteFloat( jointFrictionDent ); - saveFile->WriteFloat( jointFrictionDentStart ); - saveFile->WriteFloat( jointFrictionDentEnd ); - saveFile->WriteFloat( jointFrictionDentScale ); - - saveFile->WriteFloat( contactFrictionScale ); - saveFile->WriteFloat( contactFrictionDent ); - saveFile->WriteFloat( contactFrictionDentStart ); - saveFile->WriteFloat( contactFrictionDentEnd ); - saveFile->WriteFloat( contactFrictionDentScale ); - - saveFile->WriteBool( enableCollision ); - saveFile->WriteBool( selfCollision ); - saveFile->WriteBool( comeToRest ); - saveFile->WriteBool( linearTime ); - saveFile->WriteBool( noImpact ); - saveFile->WriteBool( worldConstraintsLocked ); - saveFile->WriteBool( forcePushable ); -} - -/* -================ -idPhysics_AF::Restore -================ -*/ -void idPhysics_AF::Restore( idRestoreGame *saveFile ) { - int i, num; - bool hasMaster; - - // the articulated figure structure should have already been restored - - idPhysics_AF_RestorePState( saveFile, current ); - idPhysics_AF_RestorePState( saveFile, saved ); - - saveFile->ReadInt( num ); - assert( num == bodies.Num() ); - for ( i = 0; i < bodies.Num(); i++ ) { - bodies[i]->Restore( saveFile ); - } - saveFile->ReadBool( hasMaster ); - if ( hasMaster ) { - masterBody = new idAFBody(); - masterBody->Restore( saveFile ); - } - - saveFile->ReadInt( num ); - assert( num == constraints.Num() ); - for ( i = 0; i < constraints.Num(); i++ ) { - constraints[i]->Restore( saveFile ); - } - - saveFile->ReadBool( changedAF ); - - saveFile->ReadFloat( linearFriction ); - saveFile->ReadFloat( angularFriction ); - saveFile->ReadFloat( contactFriction ); - saveFile->ReadFloat( bouncyness ); - saveFile->ReadFloat( totalMass ); - saveFile->ReadFloat( forceTotalMass ); - - saveFile->ReadVec2( suspendVelocity ); - saveFile->ReadVec2( suspendAcceleration ); - saveFile->ReadFloat( noMoveTime ); - saveFile->ReadFloat( noMoveTranslation ); - saveFile->ReadFloat( noMoveRotation ); - saveFile->ReadFloat( minMoveTime ); - saveFile->ReadFloat( maxMoveTime ); - saveFile->ReadFloat( impulseThreshold ); - - saveFile->ReadFloat( timeScale ); - saveFile->ReadFloat( timeScaleRampStart ); - saveFile->ReadFloat( timeScaleRampEnd ); - - saveFile->ReadFloat( jointFrictionScale ); - saveFile->ReadFloat( jointFrictionDent ); - saveFile->ReadFloat( jointFrictionDentStart ); - saveFile->ReadFloat( jointFrictionDentEnd ); - saveFile->ReadFloat( jointFrictionDentScale ); - - saveFile->ReadFloat( contactFrictionScale ); - saveFile->ReadFloat( contactFrictionDent ); - saveFile->ReadFloat( contactFrictionDentStart ); - saveFile->ReadFloat( contactFrictionDentEnd ); - saveFile->ReadFloat( contactFrictionDentScale ); - - saveFile->ReadBool( enableCollision ); - saveFile->ReadBool( selfCollision ); - saveFile->ReadBool( comeToRest ); - saveFile->ReadBool( linearTime ); - saveFile->ReadBool( noImpact ); - saveFile->ReadBool( worldConstraintsLocked ); - saveFile->ReadBool( forcePushable ); - - changedAF = true; - - UpdateClipModels(); -} - -/* -================ -idPhysics_AF::IsClosedLoop -================ -*/ -bool idPhysics_AF::IsClosedLoop( const idAFBody *body1, const idAFBody *body2 ) const { - const idAFBody *b1, *b2; - - for ( b1 = body1; b1->parent; b1 = b1->parent ) { - } - for ( b2 = body2; b2->parent; b2 = b2->parent ) { - } - return ( b1 == b2 ); -} - -/* -================ -idPhysics_AF::BuildTrees -================ -*/ -void idPhysics_AF::BuildTrees( void ) { - int i; - float scale; - idAFBody *b; - idAFConstraint *c; - idAFTree *tree; - - primaryConstraints.Clear(); - auxiliaryConstraints.Clear(); - trees.DeleteContents( true ); - - totalMass = 0.0f; - for ( i = 0; i < bodies.Num(); i++ ) { - b = bodies[i]; - b->parent = NULL; - b->primaryConstraint = NULL; - b->constraints.SetNum( 0, false ); - b->children.Clear(); - b->tree = NULL; - totalMass += b->mass; - } - - if ( forceTotalMass > 0.0f ) { - scale = forceTotalMass / totalMass; - for ( i = 0; i < bodies.Num(); i++ ) { - b = bodies[i]; - b->mass *= scale; - b->invMass = 1.0f / b->mass; - b->inertiaTensor *= scale; - b->inverseInertiaTensor = b->inertiaTensor.Inverse(); - } - totalMass = forceTotalMass; - } - - if ( af_useLinearTime.GetBool() ) { - - for ( i = 0; i < constraints.Num(); i++ ) { - c = constraints[i]; - - c->body1->constraints.Append( c ); - if ( c->body2 ) { - c->body2->constraints.Append( c ); - } - - // only bilateral constraints between two non-world bodies that do not - // create loops can be used as primary constraints - if ( !c->body1->primaryConstraint && c->fl.allowPrimary && c->body2 != NULL && !IsClosedLoop( c->body1, c->body2 ) ) { - c->body1->primaryConstraint = c; - c->body1->parent = c->body2; - c->body2->children.Append( c->body1 ); - c->fl.isPrimary = true; - c->firstIndex = 0; - primaryConstraints.Append( c ); - } else { - c->fl.isPrimary = false; - auxiliaryConstraints.Append( c ); - } - } - - // create trees for all parent bodies - for ( i = 0; i < bodies.Num(); i++ ) { - if ( !bodies[i]->parent ) { - tree = new idAFTree(); - tree->sortedBodies.Clear(); - tree->sortedBodies.Append( bodies[i] ); - bodies[i]->tree = tree; - trees.Append( tree ); - } - } - - // add each child body to the appropriate tree - for ( i = 0; i < bodies.Num(); i++ ) { - if ( bodies[i]->parent ) { - for ( b = bodies[i]->parent; !b->tree; b = b->parent ) { - } - b->tree->sortedBodies.Append( bodies[i] ); - bodies[i]->tree = b->tree; - } - } - - if ( trees.Num() > 1 ) { - gameLocal.Warning( "Articulated figure has multiple separate tree structures for entity '%s' type '%s'.", - self->name.c_str(), self->GetType()->classname ); - } - - // sort bodies in each tree to make sure parents come first - for ( i = 0; i < trees.Num(); i++ ) { - trees[i]->SortBodies(); - } - - } else { - - // create a tree for each body - for ( i = 0; i < bodies.Num(); i++ ) { - tree = new idAFTree(); - tree->sortedBodies.Clear(); - tree->sortedBodies.Append( bodies[i] ); - bodies[i]->tree = tree; - trees.Append( tree ); - } - - for ( i = 0; i < constraints.Num(); i++ ) { - c = constraints[i]; - - c->body1->constraints.Append( c ); - if ( c->body2 ) { - c->body2->constraints.Append( c ); - } - - c->fl.isPrimary = false; - auxiliaryConstraints.Append( c ); - } - } -} - -/* -================ -idPhysics_AF::AddBody - - bodies get an id in the order they are added starting at zero - as such the first body added will get id zero -================ -*/ -int idPhysics_AF::AddBody( idAFBody *body ) { - int id = 0; - - if ( !body->clipModel ) { - gameLocal.Error( "idPhysics_AF::AddBody: body '%s' has no clip model.", body->name.c_str() ); - } - - if ( bodies.Find( body ) ) { - gameLocal.Error( "idPhysics_AF::AddBody: body '%s' added twice.", body->name.c_str() ); - } - - if ( GetBody( body->name ) ) { - gameLocal.Error( "idPhysics_AF::AddBody: a body with the name '%s' already exists.", body->name.c_str() ); - } - - id = bodies.Num(); - body->clipModel->SetId( id ); - if ( body->linearFriction < 0.0f ) { - body->linearFriction = linearFriction; - body->angularFriction = angularFriction; - body->contactFriction = contactFriction; - } - if ( body->bouncyness < 0.0f ) { - body->bouncyness = bouncyness; - } - if ( !body->fl.clipMaskSet ) { - body->clipMask = clipMask; - } - - bodies.Append( body ); - - changedAF = true; - - return id; -} - -/* -================ -idPhysics_AF::AddConstraint -================ -*/ -void idPhysics_AF::AddConstraint( idAFConstraint *constraint ) { - - if ( constraints.Find( constraint ) ) { - gameLocal.Error( "idPhysics_AF::AddConstraint: constraint '%s' added twice.", constraint->name.c_str() ); - } - if ( GetConstraint( constraint->name ) ) { - gameLocal.Error( "idPhysics_AF::AddConstraint: a constraint with the name '%s' already exists.", constraint->name.c_str() ); - } - if ( !constraint->body1 ) { - gameLocal.Error( "idPhysics_AF::AddConstraint: body1 == NULL on constraint '%s'.", constraint->name.c_str() ); - } - if ( !bodies.Find( constraint->body1 ) ) { - gameLocal.Error( "idPhysics_AF::AddConstraint: body1 of constraint '%s' is not part of the articulated figure.", constraint->name.c_str() ); - } - if ( constraint->body2 && !bodies.Find( constraint->body2 ) ) { - gameLocal.Error( "idPhysics_AF::AddConstraint: body2 of constraint '%s' is not part of the articulated figure.", constraint->name.c_str() ); - } - if ( constraint->body1 == constraint->body2 ) { - gameLocal.Error( "idPhysics_AF::AddConstraint: body1 and body2 of constraint '%s' are the same.", constraint->name.c_str() ); - } - - constraints.Append( constraint ); - constraint->physics = this; - - changedAF = true; -} - -/* -================ -idPhysics_AF::AddFrameConstraint -================ -*/ -void idPhysics_AF::AddFrameConstraint( idAFConstraint *constraint ) { - frameConstraints.Append( constraint ); - constraint->physics = this; -} - -/* -================ -idPhysics_AF::ForceBodyId -================ -*/ -void idPhysics_AF::ForceBodyId( idAFBody *body, int newId ) { - int id; - - id = bodies.FindIndex( body ); - if ( id == -1 ) { - gameLocal.Error( "ForceBodyId: body '%s' is not part of the articulated figure.\n", body->name.c_str() ); - } - if ( id != newId ) { - idAFBody *b = bodies[newId]; - bodies[newId] = bodies[id]; - bodies[id] = b; - changedAF = true; - } -} - -/* -================ -idPhysics_AF::GetBodyId -================ -*/ -int idPhysics_AF::GetBodyId( idAFBody *body ) const { - int id; - - id = bodies.FindIndex( body ); - if ( id == -1 && body ) { - gameLocal.Error( "GetBodyId: body '%s' is not part of the articulated figure.\n", body->name.c_str() ); - } - return id; -} - -/* -================ -idPhysics_AF::GetBodyId -================ -*/ -int idPhysics_AF::GetBodyId( const char *bodyName ) const { - int i; - - for ( i = 0; i < bodies.Num(); i++ ) { - if ( !bodies[i]->name.Icmp( bodyName ) ) { - return i; - } - } - gameLocal.Error( "GetBodyId: no body with the name '%s' is not part of the articulated figure.\n", bodyName ); - return 0; -} - -/* -================ -idPhysics_AF::GetConstraintId -================ -*/ -int idPhysics_AF::GetConstraintId( idAFConstraint *constraint ) const { - int id; - - id = constraints.FindIndex( constraint ); - if ( id == -1 && constraint ) { - gameLocal.Error( "GetConstraintId: constraint '%s' is not part of the articulated figure.\n", constraint->name.c_str() ); - } - return id; -} - -/* -================ -idPhysics_AF::GetConstraintId -================ -*/ -int idPhysics_AF::GetConstraintId( const char *constraintName ) const { - int i; - - for ( i = 0; i < constraints.Num(); i++ ) { - if ( constraints[i]->name.Icmp( constraintName ) == 0 ) { - return i; - } - } - gameLocal.Error( "GetConstraintId: no constraint with the name '%s' is not part of the articulated figure.\n", constraintName ); - return 0; -} - -/* -================ -idPhysics_AF::GetNumBodies -================ -*/ -int idPhysics_AF::GetNumBodies( void ) const { - return bodies.Num(); -} - -/* -================ -idPhysics_AF::GetNumConstraints -================ -*/ -int idPhysics_AF::GetNumConstraints( void ) const { - return constraints.Num(); -} - -/* -================ -idPhysics_AF::GetBody -================ -*/ -idAFBody *idPhysics_AF::GetBody( const char *bodyName ) const { - int i; - - for ( i = 0; i < bodies.Num(); i++ ) { - if ( !bodies[i]->name.Icmp( bodyName ) ) { - return bodies[i]; - } - } - - return NULL; -} - -/* -================ -idPhysics_AF::GetBody -================ -*/ -idAFBody *idPhysics_AF::GetBody( const int id ) const { - if ( id < 0 || id >= bodies.Num() ) { - gameLocal.Error( "GetBody: no body with id %d exists\n", id ); - return NULL; - } - return bodies[id]; -} - -/* -================ -idPhysics_AF::GetConstraint -================ -*/ -idAFConstraint *idPhysics_AF::GetConstraint( const char *constraintName ) const { - int i; - - for ( i = 0; i < constraints.Num(); i++ ) { - if ( constraints[i]->name.Icmp( constraintName ) == 0 ) { - return constraints[i]; - } - } - - return NULL; -} - -/* -================ -idPhysics_AF::GetConstraint -================ -*/ -idAFConstraint *idPhysics_AF::GetConstraint( const int id ) const { - if ( id < 0 || id >= constraints.Num() ) { - gameLocal.Error( "GetConstraint: no constraint with id %d exists\n", id ); - return NULL; - } - return constraints[id]; -} - -/* -================ -idPhysics_AF::DeleteBody -================ -*/ -void idPhysics_AF::DeleteBody( const char *bodyName ) { - int i; - - // find the body with the given name - for ( i = 0; i < bodies.Num(); i++ ) { - if ( !bodies[i]->name.Icmp( bodyName ) ) { - break; - } - } - - if ( i >= bodies.Num() ) { - gameLocal.Warning( "DeleteBody: no body found in the articulated figure with the name '%s' for entity '%s' type '%s'.", - bodyName, self->name.c_str(), self->GetType()->classname ); - return; - } - - DeleteBody( i ); -} - -/* -================ -idPhysics_AF::DeleteBody -================ -*/ -void idPhysics_AF::DeleteBody( const int id ) { - int j; - - if ( id < 0 || id > bodies.Num() ) { - gameLocal.Error( "DeleteBody: no body with id %d.", id ); - return; - } - - // remove any constraints attached to this body - for ( j = 0; j < constraints.Num(); j++ ) { - if ( constraints[j]->body1 == bodies[id] || constraints[j]->body2 == bodies[id] ) { - delete constraints[j]; - constraints.RemoveIndex( j ); - j--; - } - } - - // remove the body - delete bodies[id]; - bodies.RemoveIndex( id ); - - // set new body ids - for ( j = 0; j < bodies.Num(); j++ ) { - bodies[j]->clipModel->SetId( j ); - } - - changedAF = true; -} - -/* -================ -idPhysics_AF::DeleteConstraint -================ -*/ -void idPhysics_AF::DeleteConstraint( const char *constraintName ) { - int i; - - // find the constraint with the given name - for ( i = 0; i < constraints.Num(); i++ ) { - if ( !constraints[i]->name.Icmp( constraintName ) ) { - break; - } - } - - if ( i >= constraints.Num() ) { - gameLocal.Warning( "DeleteConstraint: no constriant found in the articulated figure with the name '%s' for entity '%s' type '%s'.", - constraintName, self->name.c_str(), self->GetType()->classname ); - return; - } - - DeleteConstraint( i ); -} - -/* -================ -idPhysics_AF::DeleteConstraint -================ -*/ -void idPhysics_AF::DeleteConstraint( const int id ) { - - if ( id < 0 || id >= constraints.Num() ) { - gameLocal.Error( "DeleteConstraint: no constraint with id %d.", id ); - return; - } - - // remove the constraint - delete constraints[id]; - constraints.RemoveIndex( id ); - - changedAF = true; -} - -/* -================ -idPhysics_AF::GetBodyContactConstraints -================ -*/ -int idPhysics_AF::GetBodyContactConstraints( const int id, idAFConstraint_Contact *contacts[], int maxContacts ) const { - int i, numContacts; - idAFBody *body; - idAFConstraint_Contact *contact; - - if ( id < 0 || id >= bodies.Num() || maxContacts <= 0 ) { - return 0; - } - - numContacts = 0; - body = bodies[id]; - for ( i = 0; i < contactConstraints.Num(); i++ ) { - contact = contactConstraints[i]; - if ( contact->body1 == body || contact->body2 == body ) { - contacts[numContacts++] = contact; - if ( numContacts >= maxContacts ) { - return numContacts; - } - } - } - return numContacts; -} - -/* -================ -idPhysics_AF::SetDefaultFriction -================ -*/ -void idPhysics_AF::SetDefaultFriction( float linear, float angular, float contact ) { - if ( linear < 0.0f || linear > 1.0f || - angular < 0.0f || angular > 1.0f || - contact < 0.0f || contact > 1.0f ) { - return; - } - linearFriction = linear; - angularFriction = angular; - contactFriction = contact; -} - -/* -================ -idPhysics_AF::GetImpactInfo -================ -*/ -void idPhysics_AF::GetImpactInfo( const int id, const idVec3 &point, impactInfo_t *info ) const { - if ( id < 0 || id >= bodies.Num() ) { - memset( info, 0, sizeof( *info ) ); - return; - } - info->invMass = 1.0f / bodies[id]->mass; - info->invInertiaTensor = bodies[id]->current->worldAxis.Transpose() * bodies[id]->inverseInertiaTensor * bodies[id]->current->worldAxis; - info->position = point - bodies[id]->current->worldOrigin; - info->velocity = bodies[id]->current->spatialVelocity.SubVec3(0) + bodies[id]->current->spatialVelocity.SubVec3(1).Cross( info->position ); -} - -/* -================ -idPhysics_AF::ApplyImpulse -================ -*/ -void idPhysics_AF::ApplyImpulse( const int id, const idVec3 &point, const idVec3 &impulse ) { - if ( id < 0 || id >= bodies.Num() ) { - return; - } - if ( noImpact || impulse.LengthSqr() < Square( impulseThreshold ) ) { - return; - } - idMat3 invWorldInertiaTensor = bodies[id]->current->worldAxis.Transpose() * bodies[id]->inverseInertiaTensor * bodies[id]->current->worldAxis; - bodies[id]->current->spatialVelocity.SubVec3(0) += bodies[id]->invMass * impulse; - bodies[id]->current->spatialVelocity.SubVec3(1) += invWorldInertiaTensor * (point - bodies[id]->current->worldOrigin).Cross( impulse ); - Activate(); -} - -/* -================ -idPhysics_AF::AddForce -================ -*/ -void idPhysics_AF::AddForce( const int id, const idVec3 &point, const idVec3 &force ) { - if ( noImpact ) { - return; - } - if ( id < 0 || id >= bodies.Num() ) { - return; - } - bodies[id]->current->externalForce.SubVec3( 0 ) += force; - bodies[id]->current->externalForce.SubVec3( 1 ) += (point - bodies[id]->current->worldOrigin).Cross( force ); - Activate(); -} - -/* -================ -idPhysics_AF::IsAtRest -================ -*/ -bool idPhysics_AF::IsAtRest( void ) const { - return current.atRest >= 0; -} - -/* -================ -idPhysics_AF::GetRestStartTime -================ -*/ -int idPhysics_AF::GetRestStartTime( void ) const { - return current.atRest; -} - -/* -================ -idPhysics_AF::IsPushable -================ -*/ -bool idPhysics_AF::IsPushable( void ) const { - return ( !noImpact && ( masterBody == NULL || forcePushable ) ); -} - -/* -================ -idPhysics_AF::SaveState -================ -*/ -void idPhysics_AF::SaveState( void ) { - int i; - - saved = current; - - for ( i = 0; i < bodies.Num(); i++ ) { - memcpy( &bodies[i]->saved, bodies[i]->current, sizeof( AFBodyPState_t ) ); - } -} - -/* -================ -idPhysics_AF::RestoreState -================ -*/ -void idPhysics_AF::RestoreState( void ) { - int i; - - current = saved; - - for ( i = 0; i < bodies.Num(); i++ ) { - *(bodies[i]->current) = bodies[i]->saved; - } - - EvaluateContacts(); -} - -/* -================ -idPhysics_AF::SetOrigin -================ -*/ -void idPhysics_AF::SetOrigin( const idVec3 &newOrigin, int id ) { - if ( masterBody ) { - Translate( masterBody->current->worldOrigin + masterBody->current->worldAxis * newOrigin - bodies[0]->current->worldOrigin ); - } else { - Translate( newOrigin - bodies[0]->current->worldOrigin ); - } -} - -/* -================ -idPhysics_AF::SetAxis -================ -*/ -void idPhysics_AF::SetAxis( const idMat3 &newAxis, int id ) { - idMat3 axis; - idRotation rotation; - - if ( masterBody ) { - axis = bodies[0]->current->worldAxis.Transpose() * ( newAxis * masterBody->current->worldAxis ); - } else { - axis = bodies[0]->current->worldAxis.Transpose() * newAxis; - } - rotation = axis.ToRotation(); - rotation.SetOrigin( bodies[0]->current->worldOrigin ); - - Rotate( rotation ); -} - -/* -================ -idPhysics_AF::Translate -================ -*/ -void idPhysics_AF::Translate( const idVec3 &translation, int id ) { - int i; - idAFBody *body; - - if ( !worldConstraintsLocked ) { - // translate constraints attached to the world - for ( i = 0; i < constraints.Num(); i++ ) { - constraints[i]->Translate( translation ); - } - } - - // translate all the bodies - for ( i = 0; i < bodies.Num(); i++ ) { - - body = bodies[i]; - body->current->worldOrigin += translation; - } - - Activate(); - - UpdateClipModels(); -} - -/* -================ -idPhysics_AF::Rotate -================ -*/ -void idPhysics_AF::Rotate( const idRotation &rotation, int id ) { - int i; - idAFBody *body; - - if ( !worldConstraintsLocked ) { - // rotate constraints attached to the world - for ( i = 0; i < constraints.Num(); i++ ) { - constraints[i]->Rotate( rotation ); - } - } - - // rotate all the bodies - for ( i = 0; i < bodies.Num(); i++ ) { - body = bodies[i]; - - body->current->worldOrigin *= rotation; - body->current->worldAxis *= rotation.ToMat3(); - } - - Activate(); - - UpdateClipModels(); -} - -/* -================ -idPhysics_AF::GetOrigin -================ -*/ -const idVec3 &idPhysics_AF::GetOrigin( int id ) const { - if ( id < 0 || id >= bodies.Num() ) { - return vec3_origin; - } - else { - return bodies[id]->current->worldOrigin; - } -} - -/* -================ -idPhysics_AF::GetAxis -================ -*/ -const idMat3 &idPhysics_AF::GetAxis( int id ) const { - if ( id < 0 || id >= bodies.Num() ) { - return mat3_identity; - } - else { - return bodies[id]->current->worldAxis; - } -} - -/* -================ -idPhysics_AF::SetLinearVelocity -================ -*/ -void idPhysics_AF::SetLinearVelocity( const idVec3 &newLinearVelocity, int id ) { - if ( id < 0 || id >= bodies.Num() ) { - return; - } - bodies[id]->current->spatialVelocity.SubVec3( 0 ) = newLinearVelocity; - Activate(); -} - -/* -================ -idPhysics_AF::SetAngularVelocity -================ -*/ -void idPhysics_AF::SetAngularVelocity( const idVec3 &newAngularVelocity, int id ) { - if ( id < 0 || id >= bodies.Num() ) { - return; - } - bodies[id]->current->spatialVelocity.SubVec3( 1 ) = newAngularVelocity; - Activate(); -} - -/* -================ -idPhysics_AF::GetLinearVelocity -================ -*/ -const idVec3 &idPhysics_AF::GetLinearVelocity( int id ) const { - if ( id < 0 || id >= bodies.Num() ) { - return vec3_origin; - } - else { - return bodies[id]->current->spatialVelocity.SubVec3( 0 ); - } -} - -/* -================ -idPhysics_AF::GetAngularVelocity -================ -*/ -const idVec3 &idPhysics_AF::GetAngularVelocity( int id ) const { - if ( id < 0 || id >= bodies.Num() ) { - return vec3_origin; - } - else { - return bodies[id]->current->spatialVelocity.SubVec3( 1 ); - } -} - -/* -================ -idPhysics_AF::ClipTranslation -================ -*/ -void idPhysics_AF::ClipTranslation( trace_t &results, const idVec3 &translation, const idClipModel *model ) const { - int i; - idAFBody *body; - trace_t bodyResults; - - results.fraction = 1.0f; - - for ( i = 0; i < bodies.Num(); i++ ) { - body = bodies[i]; - - if ( body->clipModel->IsTraceModel() ) { - if ( model ) { - gameLocal.clip.TranslationModel( bodyResults, body->current->worldOrigin, body->current->worldOrigin + translation, - body->clipModel, body->current->worldAxis, body->clipMask, - model->Handle(), model->GetOrigin(), model->GetAxis() ); - } - else { - gameLocal.clip.Translation( bodyResults, body->current->worldOrigin, body->current->worldOrigin + translation, - body->clipModel, body->current->worldAxis, body->clipMask, self ); - } - if ( bodyResults.fraction < results.fraction ) { - results = bodyResults; - } - } - } - - results.endpos = bodies[0]->current->worldOrigin + results.fraction * translation; - results.endAxis = bodies[0]->current->worldAxis; -} - -/* -================ -idPhysics_AF::ClipRotation -================ -*/ -void idPhysics_AF::ClipRotation( trace_t &results, const idRotation &rotation, const idClipModel *model ) const { - int i; - idAFBody *body; - trace_t bodyResults; - idRotation partialRotation; - - results.fraction = 1.0f; - - for ( i = 0; i < bodies.Num(); i++ ) { - body = bodies[i]; - - if ( body->clipModel->IsTraceModel() ) { - if ( model ) { - gameLocal.clip.RotationModel( bodyResults, body->current->worldOrigin, rotation, - body->clipModel, body->current->worldAxis, body->clipMask, - model->Handle(), model->GetOrigin(), model->GetAxis() ); - } - else { - gameLocal.clip.Rotation( bodyResults, body->current->worldOrigin, rotation, - body->clipModel, body->current->worldAxis, body->clipMask, self ); - } - if ( bodyResults.fraction < results.fraction ) { - results = bodyResults; - } - } - } - - partialRotation = rotation * results.fraction; - results.endpos = bodies[0]->current->worldOrigin * partialRotation; - results.endAxis = bodies[0]->current->worldAxis * partialRotation.ToMat3(); -} - -/* -================ -idPhysics_AF::ClipContents -================ -*/ -int idPhysics_AF::ClipContents( const idClipModel *model ) const { - int i, contents; - idAFBody *body; - - contents = 0; - - for ( i = 0; i < bodies.Num(); i++ ) { - body = bodies[i]; - - if ( body->clipModel->IsTraceModel() ) { - if ( model ) { - contents |= gameLocal.clip.ContentsModel( body->current->worldOrigin, - body->clipModel, body->current->worldAxis, -1, - model->Handle(), model->GetOrigin(), model->GetAxis() ); - } - else { - contents |= gameLocal.clip.Contents( body->current->worldOrigin, - body->clipModel, body->current->worldAxis, -1, NULL ); - } - } - } - - return contents; -} - -/* -================ -idPhysics_AF::DisableClip -================ -*/ -void idPhysics_AF::DisableClip( void ) { - int i; - - for ( i = 0; i < bodies.Num(); i++ ) { - bodies[i]->clipModel->Disable(); - } -} - -/* -================ -idPhysics_AF::EnableClip -================ -*/ -void idPhysics_AF::EnableClip( void ) { - int i; - - for ( i = 0; i < bodies.Num(); i++ ) { - bodies[i]->clipModel->Enable(); - } -} - -/* -================ -idPhysics_AF::UnlinkClip -================ -*/ -void idPhysics_AF::UnlinkClip( void ) { - int i; - - for ( i = 0; i < bodies.Num(); i++ ) { - bodies[i]->clipModel->Unlink(); - } -} - -/* -================ -idPhysics_AF::LinkClip -================ -*/ -void idPhysics_AF::LinkClip( void ) { - UpdateClipModels(); -} - -/* -================ -idPhysics_AF::SetPushed -================ -*/ -void idPhysics_AF::SetPushed( int deltaTime ) { - idAFBody *body; - idRotation rotation; - - if ( bodies.Num() ) { - body = bodies[0]; - rotation = ( body->saved.worldAxis.Transpose() * body->current->worldAxis ).ToRotation(); - - // velocity with which the af is pushed - current.pushVelocity.SubVec3(0) += ( body->current->worldOrigin - body->saved.worldOrigin ) / ( deltaTime * idMath::M_MS2SEC ); - current.pushVelocity.SubVec3(1) += rotation.GetVec() * -DEG2RAD( rotation.GetAngle() ) / ( deltaTime * idMath::M_MS2SEC ); - } -} - -/* -================ -idPhysics_AF::GetPushedLinearVelocity -================ -*/ -const idVec3 &idPhysics_AF::GetPushedLinearVelocity( const int id ) const { - return current.pushVelocity.SubVec3(0); -} - -/* -================ -idPhysics_AF::GetPushedAngularVelocity -================ -*/ -const idVec3 &idPhysics_AF::GetPushedAngularVelocity( const int id ) const { - return current.pushVelocity.SubVec3(1); -} - -/* -================ -idPhysics_AF::SetMaster - - the binding is orientated based on the constraints being used -================ -*/ -void idPhysics_AF::SetMaster( idEntity *master, const bool orientated ) { - int i; - idVec3 masterOrigin; - idMat3 masterAxis; - idRotation rotation; - - if ( master ) { - self->GetMasterPosition( masterOrigin, masterAxis ); - if ( !masterBody ) { - masterBody = new idAFBody(); - // translate and rotate all the constraints with body2 == NULL from world space to master space - rotation = masterAxis.Transpose().ToRotation(); - for ( i = 0; i < constraints.Num(); i++ ) { - if ( constraints[i]->GetBody2() == NULL ) { - constraints[i]->Translate( -masterOrigin ); - constraints[i]->Rotate( rotation ); - } - } - Activate(); - } - masterBody->current->worldOrigin = masterOrigin; - masterBody->current->worldAxis = masterAxis; - } - else { - if ( masterBody ) { - // translate and rotate all the constraints with body2 == NULL from master space to world space - rotation = masterBody->current->worldAxis.ToRotation(); - for ( i = 0; i < constraints.Num(); i++ ) { - if ( constraints[i]->GetBody2() == NULL ) { - constraints[i]->Rotate( rotation ); - constraints[i]->Translate( masterBody->current->worldOrigin ); - } - } - delete masterBody; - masterBody = NULL; - Activate(); - } - } -} - - -const float AF_VELOCITY_MAX = 16000; -const int AF_VELOCITY_TOTAL_BITS = 16; -const int AF_VELOCITY_EXPONENT_BITS = idMath::BitsForInteger( idMath::BitsForFloat( AF_VELOCITY_MAX ) ) + 1; -const int AF_VELOCITY_MANTISSA_BITS = AF_VELOCITY_TOTAL_BITS - 1 - AF_VELOCITY_EXPONENT_BITS; -//const float AF_FORCE_MAX = 1e20f; -//const int AF_FORCE_TOTAL_BITS = 16; -//const int AF_FORCE_EXPONENT_BITS = idMath::BitsForInteger( idMath::BitsForFloat( AF_FORCE_MAX ) ) + 1; -//const int AF_FORCE_MANTISSA_BITS = AF_FORCE_TOTAL_BITS - 1 - AF_FORCE_EXPONENT_BITS; - -/* -================ -idPhysics_AF::WriteToSnapshot -================ -*/ -void idPhysics_AF::WriteToSnapshot( idBitMsgDelta &msg ) const { - int i; - idCQuat quat; - - msg.WriteInt( current.atRest ); - msg.WriteFloat( current.noMoveTime ); - msg.WriteFloat( current.activateTime ); - msg.WriteDeltaFloat( 0.0f, current.pushVelocity[0], AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); - msg.WriteDeltaFloat( 0.0f, current.pushVelocity[1], AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); - msg.WriteDeltaFloat( 0.0f, current.pushVelocity[2], AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); - msg.WriteDeltaFloat( 0.0f, current.pushVelocity[3], AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); - msg.WriteDeltaFloat( 0.0f, current.pushVelocity[4], AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); - msg.WriteDeltaFloat( 0.0f, current.pushVelocity[5], AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); - - msg.WriteByte( bodies.Num() ); - - for ( i = 0; i < bodies.Num(); i++ ) { - AFBodyPState_t *state = bodies[i]->current; - quat = state->worldAxis.ToCQuat(); - - msg.WriteFloat( state->worldOrigin[0] ); - msg.WriteFloat( state->worldOrigin[1] ); - msg.WriteFloat( state->worldOrigin[2] ); - msg.WriteFloat( quat.x ); - msg.WriteFloat( quat.y ); - msg.WriteFloat( quat.z ); - msg.WriteDeltaFloat( 0.0f, state->spatialVelocity[0], AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); - msg.WriteDeltaFloat( 0.0f, state->spatialVelocity[1], AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); - msg.WriteDeltaFloat( 0.0f, state->spatialVelocity[2], AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); - msg.WriteDeltaFloat( 0.0f, state->spatialVelocity[3], AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); - msg.WriteDeltaFloat( 0.0f, state->spatialVelocity[4], AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); - msg.WriteDeltaFloat( 0.0f, state->spatialVelocity[5], AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); -/* msg.WriteDeltaFloat( 0.0f, state->externalForce[0], AF_FORCE_EXPONENT_BITS, AF_FORCE_MANTISSA_BITS ); - msg.WriteDeltaFloat( 0.0f, state->externalForce[1], AF_FORCE_EXPONENT_BITS, AF_FORCE_MANTISSA_BITS ); - msg.WriteDeltaFloat( 0.0f, state->externalForce[2], AF_FORCE_EXPONENT_BITS, AF_FORCE_MANTISSA_BITS ); - msg.WriteDeltaFloat( 0.0f, state->externalForce[3], AF_FORCE_EXPONENT_BITS, AF_FORCE_MANTISSA_BITS ); - msg.WriteDeltaFloat( 0.0f, state->externalForce[4], AF_FORCE_EXPONENT_BITS, AF_FORCE_MANTISSA_BITS ); - msg.WriteDeltaFloat( 0.0f, state->externalForce[5], AF_FORCE_EXPONENT_BITS, AF_FORCE_MANTISSA_BITS ); -*/ - } -} - -/* -================ -idPhysics_AF::ReadFromSnapshot -================ -*/ -void idPhysics_AF::ReadFromSnapshot( const idBitMsgDelta &msg ) { - int i, num id_attribute((unused)); - idCQuat quat; - - current.atRest = msg.ReadInt(); - current.noMoveTime = msg.ReadFloat(); - current.activateTime = msg.ReadFloat(); - current.pushVelocity[0] = msg.ReadDeltaFloat( 0.0f, AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); - current.pushVelocity[1] = msg.ReadDeltaFloat( 0.0f, AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); - current.pushVelocity[2] = msg.ReadDeltaFloat( 0.0f, AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); - current.pushVelocity[3] = msg.ReadDeltaFloat( 0.0f, AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); - current.pushVelocity[4] = msg.ReadDeltaFloat( 0.0f, AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); - current.pushVelocity[5] = msg.ReadDeltaFloat( 0.0f, AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); - - num = msg.ReadByte(); - assert( num == bodies.Num() ); - - for ( i = 0; i < bodies.Num(); i++ ) { - AFBodyPState_t *state = bodies[i]->current; - - state->worldOrigin[0] = msg.ReadFloat(); - state->worldOrigin[1] = msg.ReadFloat(); - state->worldOrigin[2] = msg.ReadFloat(); - quat.x = msg.ReadFloat(); - quat.y = msg.ReadFloat(); - quat.z = msg.ReadFloat(); - state->spatialVelocity[0] = msg.ReadDeltaFloat( 0.0f, AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); - state->spatialVelocity[1] = msg.ReadDeltaFloat( 0.0f, AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); - state->spatialVelocity[2] = msg.ReadDeltaFloat( 0.0f, AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); - state->spatialVelocity[3] = msg.ReadDeltaFloat( 0.0f, AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); - state->spatialVelocity[4] = msg.ReadDeltaFloat( 0.0f, AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); - state->spatialVelocity[5] = msg.ReadDeltaFloat( 0.0f, AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); -/* state->externalForce[0] = msg.ReadDeltaFloat( 0.0f, AF_FORCE_EXPONENT_BITS, AF_FORCE_MANTISSA_BITS ); - state->externalForce[1] = msg.ReadDeltaFloat( 0.0f, AF_FORCE_EXPONENT_BITS, AF_FORCE_MANTISSA_BITS ); - state->externalForce[2] = msg.ReadDeltaFloat( 0.0f, AF_FORCE_EXPONENT_BITS, AF_FORCE_MANTISSA_BITS ); - state->externalForce[3] = msg.ReadDeltaFloat( 0.0f, AF_FORCE_EXPONENT_BITS, AF_FORCE_MANTISSA_BITS ); - state->externalForce[4] = msg.ReadDeltaFloat( 0.0f, AF_FORCE_EXPONENT_BITS, AF_FORCE_MANTISSA_BITS ); - state->externalForce[5] = msg.ReadDeltaFloat( 0.0f, AF_FORCE_EXPONENT_BITS, AF_FORCE_MANTISSA_BITS ); -*/ - state->worldAxis = quat.ToMat3(); - } - - UpdateClipModels(); -} diff --git a/d3xp/physics/Physics_AF.h b/d3xp/physics/Physics_AF.h deleted file mode 100644 index 90b57c96..00000000 --- a/d3xp/physics/Physics_AF.h +++ /dev/null @@ -1,1051 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __PHYSICS_AF_H__ -#define __PHYSICS_AF_H__ - -#include "idlib/math/Lcp.h" - -#include "physics/Physics_Base.h" - -/* -=================================================================================== - - Articulated Figure physics - - Employs a constraint force based dynamic simulation using a lagrangian - multiplier method to solve for the constraint forces. - -=================================================================================== -*/ - -class idAFConstraint; -class idAFConstraint_Fixed; -class idAFConstraint_BallAndSocketJoint; -class idAFConstraint_BallAndSocketJointFriction; -class idAFConstraint_UniversalJoint; -class idAFConstraint_UniversalJointFriction; -class idAFConstraint_CylindricalJoint; -class idAFConstraint_Hinge; -class idAFConstraint_HingeFriction; -class idAFConstraint_HingeSteering; -class idAFConstraint_Slider; -class idAFConstraint_Line; -class idAFConstraint_Plane; -class idAFConstraint_Spring; -class idAFConstraint_Contact; -class idAFConstraint_ContactFriction; -class idAFConstraint_ConeLimit; -class idAFConstraint_PyramidLimit; -class idAFConstraint_Suspension; -class idAFBody; -class idAFTree; -class idPhysics_AF; - -typedef enum { - CONSTRAINT_INVALID, - CONSTRAINT_FIXED, - CONSTRAINT_BALLANDSOCKETJOINT, - CONSTRAINT_UNIVERSALJOINT, - CONSTRAINT_HINGE, - CONSTRAINT_HINGESTEERING, - CONSTRAINT_SLIDER, - CONSTRAINT_CYLINDRICALJOINT, - CONSTRAINT_LINE, - CONSTRAINT_PLANE, - CONSTRAINT_SPRING, - CONSTRAINT_CONTACT, - CONSTRAINT_FRICTION, - CONSTRAINT_CONELIMIT, - CONSTRAINT_PYRAMIDLIMIT, - CONSTRAINT_SUSPENSION -} constraintType_t; - - -//=============================================================== -// -// idAFConstraint -// -//=============================================================== - -// base class for all constraints -class idAFConstraint { - - friend class idPhysics_AF; - friend class idAFTree; - -public: - idAFConstraint( void ); - virtual ~idAFConstraint( void ); - constraintType_t GetType( void ) const { return type; } - const idStr & GetName( void ) const { return name; } - idAFBody * GetBody1( void ) const { return body1; } - idAFBody * GetBody2( void ) const { return body2; } - void SetPhysics( idPhysics_AF *p ) { physics = p; } - const idVecX & GetMultiplier( void ); - virtual void SetBody1( idAFBody *body ); - virtual void SetBody2( idAFBody *body ); - virtual void DebugDraw( void ); - virtual void GetForce( idAFBody *body, idVec6 &force ); - virtual void Translate( const idVec3 &translation ); - virtual void Rotate( const idRotation &rotation ); - virtual void GetCenter( idVec3 ¢er ); - virtual void Save( idSaveGame *saveFile ) const; - virtual void Restore( idRestoreGame *saveFile ); - -protected: - constraintType_t type; // constraint type - idStr name; // name of constraint - idAFBody * body1; // first constrained body - idAFBody * body2; // second constrained body, NULL for world - idPhysics_AF * physics; // for adding additional constraints like limits - - // simulation variables set by Evaluate - idMatX J1, J2; // matrix with left hand side of constraint equations - idVecX c1, c2; // right hand side of constraint equations - idVecX lo, hi, e; // low and high bounds and lcp epsilon - idAFConstraint * boxConstraint; // constraint the boxIndex refers to - int boxIndex[6]; // indexes for special box constrained variables - - // simulation variables used during calculations - idMatX invI; // transformed inertia - idMatX J; // transformed constraint matrix - idVecX s; // temp solution - idVecX lm; // lagrange multipliers - int firstIndex; // index of the first constraint row in the lcp matrix - - struct constraintFlags_s { - bool allowPrimary : 1; // true if the constraint can be used as a primary constraint - bool frameConstraint : 1; // true if this constraint is added to the frame constraints - bool noCollision : 1; // true if body1 and body2 never collide with each other - bool isPrimary : 1; // true if this is a primary constraint - bool isZero : 1; // true if 's' is zero during calculations - } fl; - -protected: - virtual void Evaluate( float invTimeStep ); - virtual void ApplyFriction( float invTimeStep ); - void InitSize( int size ); -}; - -// fixed or rigid joint which allows zero degrees of freedom -// constrains body1 to have a fixed position and orientation relative to body2 -class idAFConstraint_Fixed : public idAFConstraint { - -public: - idAFConstraint_Fixed( const idStr &name, idAFBody *body1, idAFBody *body2 ); - void SetRelativeOrigin( const idVec3 &origin ) { this->offset = origin; } - void SetRelativeAxis( const idMat3 &axis ) { this->relAxis = axis; } - virtual void SetBody1( idAFBody *body ); - virtual void SetBody2( idAFBody *body ); - virtual void DebugDraw( void ); - virtual void Translate( const idVec3 &translation ); - virtual void Rotate( const idRotation &rotation ); - virtual void GetCenter( idVec3 ¢er ); - virtual void Save( idSaveGame *saveFile ) const; - virtual void Restore( idRestoreGame *saveFile ); - -protected: - idVec3 offset; // offset of body1 relative to body2 in body2 space - idMat3 relAxis; // rotation of body1 relative to body2 - -protected: - virtual void Evaluate( float invTimeStep ); - virtual void ApplyFriction( float invTimeStep ); - void InitOffset( void ); -}; - -// ball and socket or spherical joint which allows 3 degrees of freedom -// constrains body1 relative to body2 with a ball and socket joint -class idAFConstraint_BallAndSocketJoint : public idAFConstraint { - -public: - idAFConstraint_BallAndSocketJoint( const idStr &name, idAFBody *body1, idAFBody *body2 ); - ~idAFConstraint_BallAndSocketJoint( void ); - void SetAnchor( const idVec3 &worldPosition ); - idVec3 GetAnchor( void ) const; - void SetNoLimit( void ); - void SetConeLimit( const idVec3 &coneAxis, const float coneAngle, const idVec3 &body1Axis ); - void SetPyramidLimit( const idVec3 &pyramidAxis, const idVec3 &baseAxis, - const float angle1, const float angle2, const idVec3 &body1Axis ); - void SetLimitEpsilon( const float e ); - void SetFriction( const float f ) { friction = f; } - float GetFriction( void ) const; - virtual void DebugDraw( void ); - virtual void GetForce( idAFBody *body, idVec6 &force ); - virtual void Translate( const idVec3 &translation ); - virtual void Rotate( const idRotation &rotation ); - virtual void GetCenter( idVec3 ¢er ); - virtual void Save( idSaveGame *saveFile ) const; - virtual void Restore( idRestoreGame *saveFile ); - -protected: - idVec3 anchor1; // anchor in body1 space - idVec3 anchor2; // anchor in body2 space - float friction; // joint friction - idAFConstraint_ConeLimit *coneLimit; // cone shaped limit - idAFConstraint_PyramidLimit *pyramidLimit; // pyramid shaped limit - idAFConstraint_BallAndSocketJointFriction *fc; // friction constraint - -protected: - virtual void Evaluate( float invTimeStep ); - virtual void ApplyFriction( float invTimeStep ); -}; - -// ball and socket joint friction -class idAFConstraint_BallAndSocketJointFriction : public idAFConstraint { - -public: - idAFConstraint_BallAndSocketJointFriction( void ); - void Setup( idAFConstraint_BallAndSocketJoint *cc ); - bool Add( idPhysics_AF *phys, float invTimeStep ); - virtual void Translate( const idVec3 &translation ); - virtual void Rotate( const idRotation &rotation ); - -protected: - idAFConstraint_BallAndSocketJoint *joint; - -protected: - virtual void Evaluate( float invTimeStep ); - virtual void ApplyFriction( float invTimeStep ); -}; - -// universal, Cardan or Hooke joint which allows 2 degrees of freedom -// like a ball and socket joint but also constrains the rotation about the cardan shafts -class idAFConstraint_UniversalJoint : public idAFConstraint { - -public: - idAFConstraint_UniversalJoint( const idStr &name, idAFBody *body1, idAFBody *body2 ); - ~idAFConstraint_UniversalJoint( void ); - void SetAnchor( const idVec3 &worldPosition ); - idVec3 GetAnchor( void ) const; - void SetShafts( const idVec3 &cardanShaft1, const idVec3 &cardanShaft2 ); - void GetShafts( idVec3 &cardanShaft1, idVec3 &cardanShaft2 ) { cardanShaft1 = shaft1; cardanShaft2 = shaft2; } - void SetNoLimit( void ); - void SetConeLimit( const idVec3 &coneAxis, const float coneAngle ); - void SetPyramidLimit( const idVec3 &pyramidAxis, const idVec3 &baseAxis, - const float angle1, const float angle2 ); - void SetLimitEpsilon( const float e ); - void SetFriction( const float f ) { friction = f; } - float GetFriction( void ) const; - virtual void DebugDraw( void ); - virtual void GetForce( idAFBody *body, idVec6 &force ); - virtual void Translate( const idVec3 &translation ); - virtual void Rotate( const idRotation &rotation ); - virtual void GetCenter( idVec3 ¢er ); - virtual void Save( idSaveGame *saveFile ) const; - virtual void Restore( idRestoreGame *saveFile ); - -protected: - idVec3 anchor1; // anchor in body1 space - idVec3 anchor2; // anchor in body2 space - idVec3 shaft1; // body1 cardan shaft in body1 space - idVec3 shaft2; // body2 cardan shaft in body2 space - idVec3 axis1; // cardan axis in body1 space - idVec3 axis2; // cardan axis in body2 space - float friction; // joint friction - idAFConstraint_ConeLimit *coneLimit; // cone shaped limit - idAFConstraint_PyramidLimit *pyramidLimit; // pyramid shaped limit - idAFConstraint_UniversalJointFriction *fc; // friction constraint - -protected: - virtual void Evaluate( float invTimeStep ); - virtual void ApplyFriction( float invTimeStep ); -}; - -// universal joint friction -class idAFConstraint_UniversalJointFriction : public idAFConstraint { - -public: - idAFConstraint_UniversalJointFriction( void ); - void Setup( idAFConstraint_UniversalJoint *cc ); - bool Add( idPhysics_AF *phys, float invTimeStep ); - virtual void Translate( const idVec3 &translation ); - virtual void Rotate( const idRotation &rotation ); - -protected: - idAFConstraint_UniversalJoint *joint; // universal joint - -protected: - virtual void Evaluate( float invTimeStep ); - virtual void ApplyFriction( float invTimeStep ); -}; - -// cylindrical joint which allows 2 degrees of freedom -// constrains body1 to lie on a line relative to body2 and allows only translation along and rotation about the line -class idAFConstraint_CylindricalJoint : public idAFConstraint { - -public: - idAFConstraint_CylindricalJoint( const idStr &name, idAFBody *body1, idAFBody *body2 ); - virtual void DebugDraw( void ); - virtual void Translate( const idVec3 &translation ); - virtual void Rotate( const idRotation &rotation ); - -protected: - -protected: - virtual void Evaluate( float invTimeStep ); - virtual void ApplyFriction( float invTimeStep ); -}; - -// hinge, revolute or pin joint which allows 1 degree of freedom -// constrains all motion of body1 relative to body2 except the rotation about the hinge axis -class idAFConstraint_Hinge : public idAFConstraint { - -public: - idAFConstraint_Hinge( const idStr &name, idAFBody *body1, idAFBody *body2 ); - ~idAFConstraint_Hinge( void ); - void SetAnchor( const idVec3 &worldPosition ); - idVec3 GetAnchor( void ) const; - void SetAxis( const idVec3 &axis ); - void GetAxis( idVec3 &a1, idVec3 &a2 ) const { a1 = axis1; a2 = axis2; } - idVec3 GetAxis( void ) const; - void SetNoLimit( void ); - void SetLimit( const idVec3 &axis, const float angle, const idVec3 &body1Axis ); - void SetLimitEpsilon( const float e ); - float GetAngle( void ) const; - void SetSteerAngle( const float degrees ); - void SetSteerSpeed( const float speed ); - void SetFriction( const float f ) { friction = f; } - float GetFriction( void ) const; - virtual void DebugDraw( void ); - virtual void GetForce( idAFBody *body, idVec6 &force ); - virtual void Translate( const idVec3 &translation ); - virtual void Rotate( const idRotation &rotation ); - virtual void GetCenter( idVec3 ¢er ); - virtual void Save( idSaveGame *saveFile ) const; - virtual void Restore( idRestoreGame *saveFile ); - -protected: - idVec3 anchor1; // anchor in body1 space - idVec3 anchor2; // anchor in body2 space - idVec3 axis1; // axis in body1 space - idVec3 axis2; // axis in body2 space - idMat3 initialAxis; // initial axis of body1 relative to body2 - float friction; // hinge friction - idAFConstraint_ConeLimit *coneLimit; // cone limit - idAFConstraint_HingeSteering *steering; // steering - idAFConstraint_HingeFriction *fc; // friction constraint - -protected: - virtual void Evaluate( float invTimeStep ); - virtual void ApplyFriction( float invTimeStep ); -}; - -// hinge joint friction -class idAFConstraint_HingeFriction : public idAFConstraint { - -public: - idAFConstraint_HingeFriction( void ); - void Setup( idAFConstraint_Hinge *cc ); - bool Add( idPhysics_AF *phys, float invTimeStep ); - virtual void Translate( const idVec3 &translation ); - virtual void Rotate( const idRotation &rotation ); - -protected: - idAFConstraint_Hinge * hinge; // hinge - -protected: - virtual void Evaluate( float invTimeStep ); - virtual void ApplyFriction( float invTimeStep ); -}; - -// constrains two bodies attached to each other with a hinge to get a specified relative orientation -class idAFConstraint_HingeSteering : public idAFConstraint { - -public: - idAFConstraint_HingeSteering( void ); - void Setup( idAFConstraint_Hinge *cc ); - void SetSteerAngle( const float degrees ) { steerAngle = degrees; } - void SetSteerSpeed( const float speed ) { steerSpeed = speed; } - void SetEpsilon( const float e ) { epsilon = e; } - bool Add( idPhysics_AF *phys, float invTimeStep ); - virtual void Translate( const idVec3 &translation ); - virtual void Rotate( const idRotation &rotation ); - - virtual void Save( idSaveGame *saveFile ) const; - virtual void Restore( idRestoreGame *saveFile ); - -protected: - idAFConstraint_Hinge * hinge; // hinge - float steerAngle; // desired steer angle in degrees - float steerSpeed; // steer speed - float epsilon; // lcp epsilon - -protected: - virtual void Evaluate( float invTimeStep ); - virtual void ApplyFriction( float invTimeStep ); -}; - -// slider, prismatic or translational constraint which allows 1 degree of freedom -// constrains body1 to lie on a line relative to body2, the orientation is also fixed relative to body2 -class idAFConstraint_Slider : public idAFConstraint { - -public: - idAFConstraint_Slider( const idStr &name, idAFBody *body1, idAFBody *body2 ); - void SetAxis( const idVec3 &ax ); - virtual void DebugDraw( void ); - virtual void Translate( const idVec3 &translation ); - virtual void Rotate( const idRotation &rotation ); - virtual void GetCenter( idVec3 ¢er ); - virtual void Save( idSaveGame *saveFile ) const; - virtual void Restore( idRestoreGame *saveFile ); - -protected: - idVec3 axis; // axis along which body1 slides in body2 space - idVec3 offset; // offset of body1 relative to body2 - idMat3 relAxis; // rotation of body1 relative to body2 - -protected: - virtual void Evaluate( float invTimeStep ); - virtual void ApplyFriction( float invTimeStep ); -}; - -// line constraint which allows 4 degrees of freedom -// constrains body1 to lie on a line relative to body2, does not constrain the orientation. -class idAFConstraint_Line : public idAFConstraint { - -public: - idAFConstraint_Line( const idStr &name, idAFBody *body1, idAFBody *body2 ); - virtual void DebugDraw( void ); - virtual void Translate( const idVec3 &translation ); - virtual void Rotate( const idRotation &rotation ); - -protected: - -protected: - virtual void Evaluate( float invTimeStep ); - virtual void ApplyFriction( float invTimeStep ); -}; - -// plane constraint which allows 5 degrees of freedom -// constrains body1 to lie in a plane relative to body2, does not constrain the orientation. -class idAFConstraint_Plane : public idAFConstraint { - -public: - idAFConstraint_Plane( const idStr &name, idAFBody *body1, idAFBody *body2 ); - void SetPlane( const idVec3 &normal, const idVec3 &anchor ); - virtual void DebugDraw( void ); - virtual void Translate( const idVec3 &translation ); - virtual void Rotate( const idRotation &rotation ); - virtual void Save( idSaveGame *saveFile ) const; - virtual void Restore( idRestoreGame *saveFile ); - -protected: - idVec3 anchor1; // anchor in body1 space - idVec3 anchor2; // anchor in body2 space - idVec3 planeNormal; // plane normal in body2 space - -protected: - virtual void Evaluate( float invTimeStep ); - virtual void ApplyFriction( float invTimeStep ); -}; - -// spring constraint which allows 6 or 5 degrees of freedom based on the spring limits -// constrains body1 relative to body2 with a spring -class idAFConstraint_Spring : public idAFConstraint { - -public: - idAFConstraint_Spring( const idStr &name, idAFBody *body1, idAFBody *body2 ); - void SetAnchor( const idVec3 &worldAnchor1, const idVec3 &worldAnchor2 ); - void SetSpring( const float stretch, const float compress, const float damping, const float restLength ); - void SetLimit( const float minLength, const float maxLength ); - virtual void DebugDraw( void ); - virtual void Translate( const idVec3 &translation ); - virtual void Rotate( const idRotation &rotation ); - virtual void GetCenter( idVec3 ¢er ); - virtual void Save( idSaveGame *saveFile ) const; - virtual void Restore( idRestoreGame *saveFile ); - -protected: - idVec3 anchor1; // anchor in body1 space - idVec3 anchor2; // anchor in body2 space - float kstretch; // spring constant when stretched - float kcompress; // spring constant when compressed - float damping; // spring damping - float restLength; // rest length of spring - float minLength; // minimum spring length - float maxLength; // maximum spring length - -protected: - virtual void Evaluate( float invTimeStep ); - virtual void ApplyFriction( float invTimeStep ); -}; - -// constrains body1 to either be in contact with or move away from body2 -class idAFConstraint_Contact : public idAFConstraint { - -public: - idAFConstraint_Contact( void ); - ~idAFConstraint_Contact( void ); - void Setup( idAFBody *b1, idAFBody *b2, contactInfo_t &c ); - const contactInfo_t & GetContact( void ) const { return contact; } - virtual void DebugDraw( void ); - virtual void Translate( const idVec3 &translation ); - virtual void Rotate( const idRotation &rotation ); - virtual void GetCenter( idVec3 ¢er ); - -protected: - contactInfo_t contact; // contact information - idAFConstraint_ContactFriction *fc; // contact friction - -protected: - virtual void Evaluate( float invTimeStep ); - virtual void ApplyFriction( float invTimeStep ); -}; - -// contact friction -class idAFConstraint_ContactFriction : public idAFConstraint { - -public: - idAFConstraint_ContactFriction( void ); - void Setup( idAFConstraint_Contact *cc ); - bool Add( idPhysics_AF *phys, float invTimeStep ); - virtual void DebugDraw( void ); - virtual void Translate( const idVec3 &translation ); - virtual void Rotate( const idRotation &rotation ); - -protected: - idAFConstraint_Contact *cc; // contact constraint - -protected: - virtual void Evaluate( float invTimeStep ); - virtual void ApplyFriction( float invTimeStep ); -}; - -// constrains an axis attached to body1 to be inside a cone relative to body2 -class idAFConstraint_ConeLimit : public idAFConstraint { - -public: - idAFConstraint_ConeLimit( void ); - void Setup( idAFBody *b1, idAFBody *b2, const idVec3 &coneAnchor, const idVec3 &coneAxis, - const float coneAngle, const idVec3 &body1Axis ); - void SetAnchor( const idVec3 &coneAnchor ); - void SetBody1Axis( const idVec3 &body1Axis ); - void SetEpsilon( const float e ) { epsilon = e; } - bool Add( idPhysics_AF *phys, float invTimeStep ); - virtual void DebugDraw( void ); - virtual void Translate( const idVec3 &translation ); - virtual void Rotate( const idRotation &rotation ); - virtual void Save( idSaveGame *saveFile ) const; - virtual void Restore( idRestoreGame *saveFile ); - -protected: - idVec3 coneAnchor; // top of the cone in body2 space - idVec3 coneAxis; // cone axis in body2 space - idVec3 body1Axis; // axis in body1 space that should stay within the cone - float cosAngle; // cos( coneAngle / 2 ) - float sinHalfAngle; // sin( coneAngle / 4 ) - float cosHalfAngle; // cos( coneAngle / 4 ) - float epsilon; // lcp epsilon - -protected: - virtual void Evaluate( float invTimeStep ); - virtual void ApplyFriction( float invTimeStep ); -}; - -// constrains an axis attached to body1 to be inside a pyramid relative to body2 -class idAFConstraint_PyramidLimit : public idAFConstraint { - -public: - idAFConstraint_PyramidLimit( void ); - void Setup( idAFBody *b1, idAFBody *b2, const idVec3 &pyramidAnchor, - const idVec3 &pyramidAxis, const idVec3 &baseAxis, - const float pyramidAngle1, const float pyramidAngle2, const idVec3 &body1Axis ); - void SetAnchor( const idVec3 &pyramidAxis ); - void SetBody1Axis( const idVec3 &body1Axis ); - void SetEpsilon( const float e ) { epsilon = e; } - bool Add( idPhysics_AF *phys, float invTimeStep ); - virtual void DebugDraw( void ); - virtual void Translate( const idVec3 &translation ); - virtual void Rotate( const idRotation &rotation ); - virtual void Save( idSaveGame *saveFile ) const; - virtual void Restore( idRestoreGame *saveFile ); - -protected: - idVec3 pyramidAnchor; // top of the pyramid in body2 space - idMat3 pyramidBasis; // pyramid basis in body2 space with base[2] being the pyramid axis - idVec3 body1Axis; // axis in body1 space that should stay within the cone - float cosAngle[2]; // cos( pyramidAngle / 2 ) - float sinHalfAngle[2]; // sin( pyramidAngle / 4 ) - float cosHalfAngle[2]; // cos( pyramidAngle / 4 ) - float epsilon; // lcp epsilon - -protected: - virtual void Evaluate( float invTimeStep ); - virtual void ApplyFriction( float invTimeStep ); -}; - -// vehicle suspension -class idAFConstraint_Suspension : public idAFConstraint { - -public: - idAFConstraint_Suspension( void ); - - void Setup( const char *name, idAFBody *body, const idVec3 &origin, const idMat3 &axis, idClipModel *clipModel ); - void SetSuspension( const float up, const float down, const float k, const float d, const float f ); - - void SetSteerAngle( const float degrees ) { steerAngle = degrees; } - void EnableMotor( const bool enable ) { motorEnabled = enable; } - void SetMotorForce( const float force ) { motorForce = force; } - void SetMotorVelocity( const float vel ) { motorVelocity = vel; } - void SetEpsilon( const float e ) { epsilon = e; } - const idVec3 GetWheelOrigin( void ) const; - - virtual void DebugDraw( void ); - virtual void Translate( const idVec3 &translation ); - virtual void Rotate( const idRotation &rotation ); - -protected: - idVec3 localOrigin; // position of suspension relative to body1 - idMat3 localAxis; // orientation of suspension relative to body1 - float suspensionUp; // suspension up movement - float suspensionDown; // suspension down movement - float suspensionKCompress; // spring compress constant - float suspensionDamping; // spring damping - float steerAngle; // desired steer angle in degrees - float friction; // friction - bool motorEnabled; // whether the motor is enabled or not - float motorForce; // motor force - float motorVelocity; // desired velocity - idClipModel * wheelModel; // wheel model - idVec3 wheelOffset; // wheel position relative to body1 - trace_t trace; // contact point with the ground - float epsilon; // lcp epsilon - -protected: - virtual void Evaluate( float invTimeStep ); - virtual void ApplyFriction( float invTimeStep ); -}; - - -//=============================================================== -// -// idAFBody -// -//=============================================================== - -typedef struct AFBodyPState_s { - idVec3 worldOrigin; // position in world space - idMat3 worldAxis; // axis at worldOrigin - idVec6 spatialVelocity; // linear and rotational velocity of body - idVec6 externalForce; // external force and torque applied to body -} AFBodyPState_t; - - -class idAFBody { - - friend class idPhysics_AF; - friend class idAFTree; - -public: - idAFBody( void ); - idAFBody( const idStr &name, idClipModel *clipModel, float density ); - ~idAFBody( void ); - - void Init( void ); - const idStr & GetName( void ) const { return name; } - const idVec3 & GetWorldOrigin( void ) const { return current->worldOrigin; } - const idMat3 & GetWorldAxis( void ) const { return current->worldAxis; } - const idVec3 & GetLinearVelocity( void ) const { return current->spatialVelocity.SubVec3(0); } - const idVec3 & GetAngularVelocity( void ) const { return current->spatialVelocity.SubVec3(1); } - idVec3 GetPointVelocity( const idVec3 &point ) const; - const idVec3 & GetCenterOfMass( void ) const { return centerOfMass; } - void SetClipModel( idClipModel *clipModel ); - idClipModel * GetClipModel( void ) const { return clipModel; } - void SetClipMask( const int mask ) { clipMask = mask; fl.clipMaskSet = true; } - int GetClipMask( void ) const { return clipMask; } - void SetSelfCollision( const bool enable ) { fl.selfCollision = enable; } - void SetWorldOrigin( const idVec3 &origin ) { current->worldOrigin = origin; } - void SetWorldAxis( const idMat3 &axis ) { current->worldAxis = axis; } - void SetLinearVelocity( const idVec3 &linear ) const { current->spatialVelocity.SubVec3(0) = linear; } - void SetAngularVelocity( const idVec3 &angular ) const { current->spatialVelocity.SubVec3(1) = angular; } - void SetFriction( float linear, float angular, float contact ); - float GetContactFriction( void ) const { return contactFriction; } - void SetBouncyness( float bounce ); - float GetBouncyness( void ) const { return bouncyness; } - void SetDensity( float density, const idMat3 &inertiaScale = mat3_identity ); - float GetInverseMass( void ) const { return invMass; } - idMat3 GetInverseWorldInertia( void ) const { return current->worldAxis.Transpose() * inverseInertiaTensor * current->worldAxis; } - - void SetFrictionDirection( const idVec3 &dir ); - bool GetFrictionDirection( idVec3 &dir ) const; - - void SetContactMotorDirection( const idVec3 &dir ); - bool GetContactMotorDirection( idVec3 &dir ) const; - void SetContactMotorVelocity( float vel ) { contactMotorVelocity = vel; } - float GetContactMotorVelocity( void ) const { return contactMotorVelocity; } - void SetContactMotorForce( float force ) { contactMotorForce = force; } - float GetContactMotorForce( void ) const { return contactMotorForce; } - - void AddForce( const idVec3 &point, const idVec3 &force ); - void InverseWorldSpatialInertiaMultiply( idVecX &dst, const float *v ) const; - idVec6 & GetResponseForce( int index ) { return reinterpret_cast(response[ index * 8 ]); } - - void Save( idSaveGame *saveFile ); - void Restore( idRestoreGame *saveFile ); - -private: - // properties - idStr name; // name of body - idAFBody * parent; // parent of this body - idList children; // children of this body - idClipModel * clipModel; // model used for collision detection - idAFConstraint * primaryConstraint; // primary constraint (this->constraint->body1 = this) - idListconstraints; // all constraints attached to this body - idAFTree * tree; // tree structure this body is part of - float linearFriction; // translational friction - float angularFriction; // rotational friction - float contactFriction; // friction with contact surfaces - float bouncyness; // bounce - int clipMask; // contents this body collides with - idVec3 frictionDir; // specifies a single direction of friction in body space - idVec3 contactMotorDir; // contact motor direction - float contactMotorVelocity; // contact motor velocity - float contactMotorForce; // maximum force applied to reach the motor velocity - - // derived properties - float mass; // mass of body - float invMass; // inverse mass - idVec3 centerOfMass; // center of mass of body - idMat3 inertiaTensor; // inertia tensor - idMat3 inverseInertiaTensor; // inverse inertia tensor - - // physics state - AFBodyPState_t state[2]; - AFBodyPState_t * current; // current physics state - AFBodyPState_t * next; // next physics state - AFBodyPState_t saved; // saved physics state - idVec3 atRestOrigin; // origin at rest - idMat3 atRestAxis; // axis at rest - - // simulation variables used during calculations - idMatX inverseWorldSpatialInertia; // inverse spatial inertia in world space - idMatX I, invI; // transformed inertia - idMatX J; // transformed constraint matrix - idVecX s; // temp solution - idVecX totalForce; // total force acting on body - idVecX auxForce; // force from auxiliary constraints - idVecX acceleration; // acceleration - float * response; // forces on body in response to auxiliary constraint forces - int * responseIndex; // index to response forces - int numResponses; // number of response forces - int maxAuxiliaryIndex; // largest index of an auxiliary constraint constraining this body - int maxSubTreeAuxiliaryIndex; // largest index of an auxiliary constraint constraining this body or one of it's children - - struct bodyFlags_s { - bool clipMaskSet : 1; // true if this body has a clip mask set - bool selfCollision : 1; // true if this body can collide with other bodies of this AF - bool spatialInertiaSparse: 1; // true if the spatial inertia matrix is sparse - bool useFrictionDir : 1; // true if a single friction direction should be used - bool useContactMotorDir : 1; // true if a contact motor should be used - bool isZero : 1; // true if 's' is zero during calculations - } fl; -}; - - -//=============================================================== -// -// idAFTree -// -//=============================================================== - -class idAFTree { - friend class idPhysics_AF; - -public: - void Factor( void ) const; - void Solve( int auxiliaryIndex = 0 ) const; - void Response( const idAFConstraint *constraint, int row, int auxiliaryIndex ) const; - void CalculateForces( float timeStep ) const; - void SetMaxSubTreeAuxiliaryIndex( void ); - void SortBodies( void ); - void SortBodies_r( idList&sortedList, idAFBody *body ); - void DebugDraw( const idVec4 &color ) const; - -private: - idList sortedBodies; -}; - - -//=============================================================== -// -// idPhysics_AF -// -//=============================================================== - -typedef struct AFPState_s { - int atRest; // >= 0 if articulated figure is at rest - float noMoveTime; // time the articulated figure is hardly moving - float activateTime; // time since last activation - float lastTimeStep; // last time step - idVec6 pushVelocity; // velocity with which the af is pushed -} AFPState_t; - -typedef struct AFCollision_s { - trace_t trace; - idAFBody * body; -} AFCollision_t; - - -class idPhysics_AF : public idPhysics_Base { - -public: - CLASS_PROTOTYPE( idPhysics_AF ); - - idPhysics_AF( void ); - ~idPhysics_AF( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - // initialisation - int AddBody( idAFBody *body ); // returns body id - void AddConstraint( idAFConstraint *constraint ); - void AddFrameConstraint( idAFConstraint *constraint ); - // force a body to have a certain id - void ForceBodyId( idAFBody *body, int newId ); - // get body or constraint id - int GetBodyId( idAFBody *body ) const; - int GetBodyId( const char *bodyName ) const; - int GetConstraintId( idAFConstraint *constraint ) const; - int GetConstraintId( const char *constraintName ) const; - // number of bodies and constraints - int GetNumBodies( void ) const; - int GetNumConstraints( void ) const; - // retrieve body or constraint - idAFBody * GetBody( const char *bodyName ) const; - idAFBody * GetBody( const int id ) const; - idAFBody * GetMasterBody( void ) const { return masterBody; } - idAFConstraint * GetConstraint( const char *constraintName ) const; - idAFConstraint * GetConstraint( const int id ) const; - // delete body or constraint - void DeleteBody( const char *bodyName ); - void DeleteBody( const int id ); - void DeleteConstraint( const char *constraintName ); - void DeleteConstraint( const int id ); - // get all the contact constraints acting on the body - int GetBodyContactConstraints( const int id, idAFConstraint_Contact *contacts[], int maxContacts ) const; - // set the default friction for bodies - void SetDefaultFriction( float linear, float angular, float contact ); - // suspend settings - void SetSuspendSpeed( const idVec2 &velocity, const idVec2 &acceleration ); - // set the time and tolerances used to determine if the simulation can be suspended when the figure hardly moves for a while - void SetSuspendTolerance( const float noMoveTime, const float translationTolerance, const float rotationTolerance ); - // set minimum and maximum simulation time in seconds - void SetSuspendTime( const float minTime, const float maxTime ); - // set the time scale value - void SetTimeScale( const float ts ) { timeScale = ts; } - // set time scale ramp - void SetTimeScaleRamp( const float start, const float end ); - // set the joint friction scale - void SetJointFrictionScale( const float scale ) { jointFrictionScale = scale; } - // set joint friction dent - void SetJointFrictionDent( const float dent, const float start, const float end ); - // get the current joint friction scale - float GetJointFrictionScale( void ) const; - // set the contact friction scale - void SetContactFrictionScale( const float scale ) { contactFrictionScale = scale; } - // set contact friction dent - void SetContactFrictionDent( const float dent, const float start, const float end ); - // get the current contact friction scale - float GetContactFrictionScale( void ) const; - // enable or disable collision detection - void SetCollision( const bool enable ) { enableCollision = enable; } - // enable or disable self collision - void SetSelfCollision( const bool enable ) { selfCollision = enable; } - // enable or disable coming to a dead stop - void SetComeToRest( bool enable ) { comeToRest = enable; } - // call when structure of articulated figure changes - void SetChanged( void ) { changedAF = true; } - // enable/disable activation by impact - void EnableImpact( void ); - void DisableImpact( void ); - // lock of unlock the world constraints - void LockWorldConstraints( const bool lock ) { worldConstraintsLocked = lock; } - // set force pushable - void SetForcePushable( const bool enable ) { forcePushable = enable; } - // update the clip model positions - void UpdateClipModels( void ); - -public: // common physics interface - void SetClipModel( idClipModel *model, float density, int id = 0, bool freeOld = true ); - idClipModel * GetClipModel( int id = 0 ) const; - int GetNumClipModels( void ) const; - - void SetMass( float mass, int id = -1 ); - float GetMass( int id = -1 ) const; - - void SetContents( int contents, int id = -1 ); - int GetContents( int id = -1 ) const; - - const idBounds & GetBounds( int id = -1 ) const; - const idBounds & GetAbsBounds( int id = -1 ) const; - - bool Evaluate( int timeStepMSec, int endTimeMSec ); - void UpdateTime( int endTimeMSec ); - int GetTime( void ) const; - - void GetImpactInfo( const int id, const idVec3 &point, impactInfo_t *info ) const; - void ApplyImpulse( const int id, const idVec3 &point, const idVec3 &impulse ); - void AddForce( const int id, const idVec3 &point, const idVec3 &force ); - bool IsAtRest( void ) const; - int GetRestStartTime( void ) const; - void Activate( void ); - void PutToRest( void ); - bool IsPushable( void ) const; - - void SaveState( void ); - void RestoreState( void ); - - void SetOrigin( const idVec3 &newOrigin, int id = -1 ); - void SetAxis( const idMat3 &newAxis, int id = -1 ); - - void Translate( const idVec3 &translation, int id = -1 ); - void Rotate( const idRotation &rotation, int id = -1 ); - - const idVec3 & GetOrigin( int id = 0 ) const; - const idMat3 & GetAxis( int id = 0 ) const; - - void SetLinearVelocity( const idVec3 &newLinearVelocity, int id = 0 ); - void SetAngularVelocity( const idVec3 &newAngularVelocity, int id = 0 ); - - const idVec3 & GetLinearVelocity( int id = 0 ) const; - const idVec3 & GetAngularVelocity( int id = 0 ) const; - - void ClipTranslation( trace_t &results, const idVec3 &translation, const idClipModel *model ) const; - void ClipRotation( trace_t &results, const idRotation &rotation, const idClipModel *model ) const; - int ClipContents( const idClipModel *model ) const; - - void DisableClip( void ); - void EnableClip( void ); - - void UnlinkClip( void ); - void LinkClip( void ); - - bool EvaluateContacts( void ); - - void SetPushed( int deltaTime ); - const idVec3 & GetPushedLinearVelocity( const int id = 0 ) const; - const idVec3 & GetPushedAngularVelocity( const int id = 0 ) const; - - void SetMaster( idEntity *master, const bool orientated = true ); - - void WriteToSnapshot( idBitMsgDelta &msg ) const; - void ReadFromSnapshot( const idBitMsgDelta &msg ); - -private: - // articulated figure - idList trees; // tree structures - idList bodies; // all bodies - idListconstraints; // all frame independent constraints - idListprimaryConstraints; // list with primary constraints - idListauxiliaryConstraints; // list with auxiliary constraints - idListframeConstraints; // constraints that only live one frame - idListcontactConstraints; // contact constraints - idList contactBodies; // body id for each contact - idList collisions; // collisions - bool changedAF; // true when the articulated figure just changed - - // properties - float linearFriction; // default translational friction - float angularFriction; // default rotational friction - float contactFriction; // default friction with contact surfaces - float bouncyness; // default bouncyness - float totalMass; // total mass of articulated figure - float forceTotalMass; // force this total mass - - idVec2 suspendVelocity; // simulation may not be suspended if a body has more velocity - idVec2 suspendAcceleration; // simulation may not be suspended if a body has more acceleration - float noMoveTime; // suspend simulation if hardly any movement for this many seconds - float noMoveTranslation; // maximum translation considered no movement - float noMoveRotation; // maximum rotation considered no movement - float minMoveTime; // if > 0 the simulation is never suspended before running this many seconds - float maxMoveTime; // if > 0 the simulation is always suspeded after running this many seconds - float impulseThreshold; // threshold below which impulses are ignored to avoid continuous activation - - float timeScale; // the time is scaled with this value for slow motion effects - float timeScaleRampStart; // start of time scale change - float timeScaleRampEnd; // end of time scale change - - float jointFrictionScale; // joint friction scale - float jointFrictionDent; // joint friction dives from 1 to this value and goes up again - float jointFrictionDentStart; // start time of joint friction dent - float jointFrictionDentEnd; // end time of joint friction dent - float jointFrictionDentScale; // dent scale - - float contactFrictionScale; // contact friction scale - float contactFrictionDent; // contact friction dives from 1 to this value and goes up again - float contactFrictionDentStart; // start time of contact friction dent - float contactFrictionDentEnd; // end time of contact friction dent - float contactFrictionDentScale; // dent scale - - bool enableCollision; // if true collision detection is enabled - bool selfCollision; // if true the self collision is allowed - bool comeToRest; // if true the figure can come to rest - bool linearTime; // if true use the linear time algorithm - bool noImpact; // if true do not activate when another object collides - bool worldConstraintsLocked; // if true world constraints cannot be moved - bool forcePushable; // if true can be pushed even when bound to a master - - // physics state - AFPState_t current; - AFPState_t saved; - - idAFBody * masterBody; // master body - idLCP * lcp; // linear complementarity problem solver - -private: - void BuildTrees( void ); - bool IsClosedLoop( const idAFBody *body1, const idAFBody *body2 ) const; - void PrimaryFactor( void ); - void EvaluateBodies( float timeStep ); - void EvaluateConstraints( float timeStep ); - void AddFrameConstraints( void ); - void RemoveFrameConstraints( void ); - void ApplyFriction( float timeStep, float endTimeMSec ); - void PrimaryForces( float timeStep ); - void AuxiliaryForces( float timeStep ); - void VerifyContactConstraints( void ); - void SetupContactConstraints( void ); - void ApplyContactForces( void ); - void Evolve( float timeStep ); - idEntity * SetupCollisionForBody( idAFBody *body ) const; - bool CollisionImpulse( float timeStep, idAFBody *body, trace_t &collision ); - bool ApplyCollisions( float timeStep ); - void CheckForCollisions( float timeStep ); - void ClearExternalForce( void ); - void AddGravity( void ); - void SwapStates( void ); - bool TestIfAtRest( float timeStep ); - void Rest( void ); - void AddPushVelocity( const idVec6 &pushVelocity ); - void DebugDraw( void ); -}; - -#endif /* !__PHYSICS_AF_H__ */ diff --git a/d3xp/physics/Physics_Actor.cpp b/d3xp/physics/Physics_Actor.cpp deleted file mode 100644 index 85a45a7f..00000000 --- a/d3xp/physics/Physics_Actor.cpp +++ /dev/null @@ -1,382 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "Entity.h" - -#include "physics/Physics_Actor.h" - -CLASS_DECLARATION( idPhysics_Base, idPhysics_Actor ) -END_CLASS - -/* -================ -idPhysics_Actor::idPhysics_Actor -================ -*/ -idPhysics_Actor::idPhysics_Actor( void ) { - clipModel = NULL; - SetClipModelAxis(); - mass = 100.0f; - invMass = 1.0f / mass; - masterEntity = NULL; - masterYaw = 0.0f; - masterDeltaYaw = 0.0f; - groundEntityPtr = NULL; -} - -/* -================ -idPhysics_Actor::~idPhysics_Actor -================ -*/ -idPhysics_Actor::~idPhysics_Actor( void ) { - if ( clipModel ) { - delete clipModel; - clipModel = NULL; - } -} - -/* -================ -idPhysics_Actor::Save -================ -*/ -void idPhysics_Actor::Save( idSaveGame *savefile ) const { - - savefile->WriteClipModel( clipModel ); - savefile->WriteMat3( clipModelAxis ); - - savefile->WriteFloat( mass ); - savefile->WriteFloat( invMass ); - - savefile->WriteObject( masterEntity ); - savefile->WriteFloat( masterYaw ); - savefile->WriteFloat( masterDeltaYaw ); - - groundEntityPtr.Save( savefile ); -} - -/* -================ -idPhysics_Actor::Restore -================ -*/ -void idPhysics_Actor::Restore( idRestoreGame *savefile ) { - - savefile->ReadClipModel( clipModel ); - savefile->ReadMat3( clipModelAxis ); - - savefile->ReadFloat( mass ); - savefile->ReadFloat( invMass ); - - savefile->ReadObject( reinterpret_cast( masterEntity ) ); - savefile->ReadFloat( masterYaw ); - savefile->ReadFloat( masterDeltaYaw ); - - groundEntityPtr.Restore( savefile ); -} - -/* -================ -idPhysics_Actor::SetClipModelAxis -================ -*/ -void idPhysics_Actor::SetClipModelAxis( void ) { - // align clip model to gravity direction - if ( ( gravityNormal[2] == -1.0f ) || ( gravityNormal == vec3_zero ) ) { - clipModelAxis.Identity(); - } - else { - clipModelAxis[2] = -gravityNormal; - clipModelAxis[2].NormalVectors( clipModelAxis[0], clipModelAxis[1] ); - clipModelAxis[1] = -clipModelAxis[1]; - } - - if ( clipModel ) { - clipModel->Link( gameLocal.clip, self, 0, clipModel->GetOrigin(), clipModelAxis ); - } -} - -/* -================ -idPhysics_Actor::GetGravityAxis -================ -*/ -const idMat3 &idPhysics_Actor::GetGravityAxis( void ) const { - return clipModelAxis; -} - -/* -================ -idPhysics_Actor::GetMasterDeltaYaw -================ -*/ -float idPhysics_Actor::GetMasterDeltaYaw( void ) const { - return masterDeltaYaw; -} - -/* -================ -idPhysics_Actor::GetGroundEntity -================ -*/ -idEntity *idPhysics_Actor::GetGroundEntity( void ) const { - return groundEntityPtr.GetEntity(); -} - -/* -================ -idPhysics_Actor::SetClipModel -================ -*/ -void idPhysics_Actor::SetClipModel( idClipModel *model, const float density, int id, bool freeOld ) { - assert( self ); - assert( model ); // a clip model is required - assert( model->IsTraceModel() ); // and it should be a trace model - assert( density > 0.0f ); // density should be valid - - if ( clipModel && clipModel != model && freeOld ) { - delete clipModel; - } - clipModel = model; - clipModel->Link( gameLocal.clip, self, 0, clipModel->GetOrigin(), clipModelAxis ); -} - -/* -================ -idPhysics_Actor::GetClipModel -================ -*/ -idClipModel *idPhysics_Actor::GetClipModel( int id ) const { - return clipModel; -} - -/* -================ -idPhysics_Actor::GetNumClipModels -================ -*/ -int idPhysics_Actor::GetNumClipModels( void ) const { - return 1; -} - -/* -================ -idPhysics_Actor::SetMass -================ -*/ -void idPhysics_Actor::SetMass( float _mass, int id ) { - assert( _mass > 0.0f ); - mass = _mass; - invMass = 1.0f / _mass; -} - -/* -================ -idPhysics_Actor::GetMass -================ -*/ -float idPhysics_Actor::GetMass( int id ) const { - return mass; -} - -/* -================ -idPhysics_Actor::SetClipMask -================ -*/ -void idPhysics_Actor::SetContents( int contents, int id ) { - clipModel->SetContents( contents ); -} - -/* -================ -idPhysics_Actor::SetClipMask -================ -*/ -int idPhysics_Actor::GetContents( int id ) const { - return clipModel->GetContents(); -} - -/* -================ -idPhysics_Actor::GetBounds -================ -*/ -const idBounds &idPhysics_Actor::GetBounds( int id ) const { - return clipModel->GetBounds(); -} - -/* -================ -idPhysics_Actor::GetAbsBounds -================ -*/ -const idBounds &idPhysics_Actor::GetAbsBounds( int id ) const { - return clipModel->GetAbsBounds(); -} - -/* -================ -idPhysics_Actor::IsPushable -================ -*/ -bool idPhysics_Actor::IsPushable( void ) const { - return ( masterEntity == NULL ); -} - -/* -================ -idPhysics_Actor::GetOrigin -================ -*/ -const idVec3 &idPhysics_Actor::GetOrigin( int id ) const { - return clipModel->GetOrigin(); -} - -/* -================ -idPhysics_Player::GetAxis -================ -*/ -const idMat3 &idPhysics_Actor::GetAxis( int id ) const { - return clipModel->GetAxis(); -} - -/* -================ -idPhysics_Actor::SetGravity -================ -*/ -void idPhysics_Actor::SetGravity( const idVec3 &newGravity ) { - if ( newGravity != gravityVector ) { - idPhysics_Base::SetGravity( newGravity ); - SetClipModelAxis(); - } -} - -/* -================ -idPhysics_Actor::ClipTranslation -================ -*/ -void idPhysics_Actor::ClipTranslation( trace_t &results, const idVec3 &translation, const idClipModel *model ) const { - if ( model ) { - gameLocal.clip.TranslationModel( results, clipModel->GetOrigin(), clipModel->GetOrigin() + translation, - clipModel, clipModel->GetAxis(), clipMask, - model->Handle(), model->GetOrigin(), model->GetAxis() ); - } - else { - gameLocal.clip.Translation( results, clipModel->GetOrigin(), clipModel->GetOrigin() + translation, - clipModel, clipModel->GetAxis(), clipMask, self ); - } -} - -/* -================ -idPhysics_Actor::ClipRotation -================ -*/ -void idPhysics_Actor::ClipRotation( trace_t &results, const idRotation &rotation, const idClipModel *model ) const { - if ( model ) { - gameLocal.clip.RotationModel( results, clipModel->GetOrigin(), rotation, - clipModel, clipModel->GetAxis(), clipMask, - model->Handle(), model->GetOrigin(), model->GetAxis() ); - } - else { - gameLocal.clip.Rotation( results, clipModel->GetOrigin(), rotation, - clipModel, clipModel->GetAxis(), clipMask, self ); - } -} - -/* -================ -idPhysics_Actor::ClipContents -================ -*/ -int idPhysics_Actor::ClipContents( const idClipModel *model ) const { - if ( model ) { - return gameLocal.clip.ContentsModel( clipModel->GetOrigin(), clipModel, clipModel->GetAxis(), -1, - model->Handle(), model->GetOrigin(), model->GetAxis() ); - } - else { - return gameLocal.clip.Contents( clipModel->GetOrigin(), clipModel, clipModel->GetAxis(), -1, NULL ); - } -} - -/* -================ -idPhysics_Actor::DisableClip -================ -*/ -void idPhysics_Actor::DisableClip( void ) { - clipModel->Disable(); -} - -/* -================ -idPhysics_Actor::EnableClip -================ -*/ -void idPhysics_Actor::EnableClip( void ) { - clipModel->Enable(); -} - -/* -================ -idPhysics_Actor::UnlinkClip -================ -*/ -void idPhysics_Actor::UnlinkClip( void ) { - clipModel->Unlink(); -} - -/* -================ -idPhysics_Actor::LinkClip -================ -*/ -void idPhysics_Actor::LinkClip( void ) { - clipModel->Link( gameLocal.clip, self, 0, clipModel->GetOrigin(), clipModel->GetAxis() ); -} - -/* -================ -idPhysics_Actor::EvaluateContacts -================ -*/ -bool idPhysics_Actor::EvaluateContacts( void ) { - - // get all the ground contacts - ClearContacts(); - AddGroundContacts( clipModel ); - AddContactEntitiesForContacts(); - - return ( contacts.Num() != 0 ); -} diff --git a/d3xp/physics/Physics_Actor.h b/d3xp/physics/Physics_Actor.h deleted file mode 100644 index e50ae17e..00000000 --- a/d3xp/physics/Physics_Actor.h +++ /dev/null @@ -1,115 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __PHYSICS_ACTOR_H__ -#define __PHYSICS_ACTOR_H__ - -#include "physics/Physics_Base.h" - -/* -=================================================================================== - - Actor physics base class - - An actor typically uses one collision model which is aligned with the gravity - direction. The collision model is usually a simple box with the origin at the - bottom center. - -=================================================================================== -*/ - -class idPhysics_Actor : public idPhysics_Base { - -public: - CLASS_PROTOTYPE( idPhysics_Actor ); - - idPhysics_Actor( void ); - ~idPhysics_Actor( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - // get delta yaw of master - float GetMasterDeltaYaw( void ) const; - // returns the ground entity - idEntity * GetGroundEntity( void ) const; - // align the clip model with the gravity direction - void SetClipModelAxis( void ); - -public: // common physics interface - void SetClipModel( idClipModel *model, float density, int id = 0, bool freeOld = true ); - idClipModel * GetClipModel( int id = 0 ) const; - int GetNumClipModels( void ) const; - - void SetMass( float mass, int id = -1 ); - float GetMass( int id = -1 ) const; - - void SetContents( int contents, int id = -1 ); - int GetContents( int id = -1 ) const; - - const idBounds & GetBounds( int id = -1 ) const; - const idBounds & GetAbsBounds( int id = -1 ) const; - - bool IsPushable( void ) const; - - const idVec3 & GetOrigin( int id = 0 ) const; - const idMat3 & GetAxis( int id = 0 ) const; - - void SetGravity( const idVec3 &newGravity ); - const idMat3 & GetGravityAxis( void ) const; - - void ClipTranslation( trace_t &results, const idVec3 &translation, const idClipModel *model ) const; - void ClipRotation( trace_t &results, const idRotation &rotation, const idClipModel *model ) const; - int ClipContents( const idClipModel *model ) const; - - void DisableClip( void ); - void EnableClip( void ); - - void UnlinkClip( void ); - void LinkClip( void ); - - bool EvaluateContacts( void ); - -protected: - idClipModel * clipModel; // clip model used for collision detection - idMat3 clipModelAxis; // axis of clip model aligned with gravity direction - - // derived properties - float mass; - float invMass; - - // master - idEntity * masterEntity; - float masterYaw; - float masterDeltaYaw; - - // results of last evaluate - idEntityPtr groundEntityPtr; -}; - -#endif /* !__PHYSICS_ACTOR_H__ */ diff --git a/d3xp/physics/Physics_Base.cpp b/d3xp/physics/Physics_Base.cpp deleted file mode 100644 index 41b455b5..00000000 --- a/d3xp/physics/Physics_Base.cpp +++ /dev/null @@ -1,838 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "physics/Force.h" -#include "Entity.h" - -#include "physics/Physics_Base.h" - -CLASS_DECLARATION( idPhysics, idPhysics_Base ) -END_CLASS - -/* -================ -idPhysics_Base::idPhysics_Base -================ -*/ -idPhysics_Base::idPhysics_Base( void ) { - self = NULL; - clipMask = 0; - SetGravity( gameLocal.GetGravity() ); - ClearContacts(); -} - -/* -================ -idPhysics_Base::~idPhysics_Base -================ -*/ -idPhysics_Base::~idPhysics_Base( void ) { - if ( self && self->GetPhysics() == this ) { - self->SetPhysics( NULL ); - } - idForce::DeletePhysics( this ); - ClearContacts(); -} - -/* -================ -idPhysics_Base::Save -================ -*/ -void idPhysics_Base::Save( idSaveGame *savefile ) const { - int i; - - savefile->WriteObject( self ); - savefile->WriteInt( clipMask ); - savefile->WriteVec3( gravityVector ); - savefile->WriteVec3( gravityNormal ); - - savefile->WriteInt( contacts.Num() ); - for ( i = 0; i < contacts.Num(); i++ ) { - savefile->WriteContactInfo( contacts[i] ); - } - - savefile->WriteInt( contactEntities.Num() ); - for ( i = 0; i < contactEntities.Num(); i++ ) { - contactEntities[i].Save( savefile ); - } -} - -/* -================ -idPhysics_Base::Restore -================ -*/ -void idPhysics_Base::Restore( idRestoreGame *savefile ) { - int i, num; - - savefile->ReadObject( reinterpret_cast( self ) ); - savefile->ReadInt( clipMask ); - savefile->ReadVec3( gravityVector ); - savefile->ReadVec3( gravityNormal ); - - savefile->ReadInt( num ); - contacts.SetNum( num ); - for ( i = 0; i < contacts.Num(); i++ ) { - savefile->ReadContactInfo( contacts[i] ); - } - - savefile->ReadInt( num ); - contactEntities.SetNum( num ); - for ( i = 0; i < contactEntities.Num(); i++ ) { - contactEntities[i].Restore( savefile ); - } -} - -/* -================ -idPhysics_Base::SetSelf -================ -*/ -void idPhysics_Base::SetSelf( idEntity *e ) { - assert( e ); - self = e; -} - -/* -================ -idPhysics_Base::SetClipModel -================ -*/ -void idPhysics_Base::SetClipModel( idClipModel *model, float density, int id, bool freeOld ) { -} - -/* -================ -idPhysics_Base::GetClipModel -================ -*/ -idClipModel *idPhysics_Base::GetClipModel( int id ) const { - return NULL; -} - -/* -================ -idPhysics_Base::GetNumClipModels -================ -*/ -int idPhysics_Base::GetNumClipModels( void ) const { - return 0; -} - -/* -================ -idPhysics_Base::SetMass -================ -*/ -void idPhysics_Base::SetMass( float mass, int id ) { -} - -/* -================ -idPhysics_Base::GetMass -================ -*/ -float idPhysics_Base::GetMass( int id ) const { - return 0.0f; -} - -/* -================ -idPhysics_Base::SetContents -================ -*/ -void idPhysics_Base::SetContents( int contents, int id ) { -} - -/* -================ -idPhysics_Base::SetClipMask -================ -*/ -int idPhysics_Base::GetContents( int id ) const { - return 0; -} - -/* -================ -idPhysics_Base::SetClipMask -================ -*/ -void idPhysics_Base::SetClipMask( int mask, int id ) { - clipMask = mask; -} - -/* -================ -idPhysics_Base::GetClipMask -================ -*/ -int idPhysics_Base::GetClipMask( int id ) const { - return clipMask; -} - -/* -================ -idPhysics_Base::GetBounds -================ -*/ -const idBounds &idPhysics_Base::GetBounds( int id ) const { - return bounds_zero; -} - -/* -================ -idPhysics_Base::GetAbsBounds -================ -*/ -const idBounds &idPhysics_Base::GetAbsBounds( int id ) const { - return bounds_zero; -} - -/* -================ -idPhysics_Base::Evaluate -================ -*/ -bool idPhysics_Base::Evaluate( int timeStepMSec, int endTimeMSec ) { - return false; -} - -/* -================ -idPhysics_Base::UpdateTime -================ -*/ -void idPhysics_Base::UpdateTime( int endTimeMSec ) { -} - -/* -================ -idPhysics_Base::GetTime -================ -*/ -int idPhysics_Base::GetTime( void ) const { - return 0; -} - -/* -================ -idPhysics_Base::GetImpactInfo -================ -*/ -void idPhysics_Base::GetImpactInfo( const int id, const idVec3 &point, impactInfo_t *info ) const { - memset( info, 0, sizeof( *info ) ); -} - -/* -================ -idPhysics_Base::ApplyImpulse -================ -*/ -void idPhysics_Base::ApplyImpulse( const int id, const idVec3 &point, const idVec3 &impulse ) { -} - -/* -================ -idPhysics_Base::AddForce -================ -*/ -void idPhysics_Base::AddForce( const int id, const idVec3 &point, const idVec3 &force ) { -} - -/* -================ -idPhysics_Base::Activate -================ -*/ -void idPhysics_Base::Activate( void ) { -} - -/* -================ -idPhysics_Base::PutToRest -================ -*/ -void idPhysics_Base::PutToRest( void ) { -} - -/* -================ -idPhysics_Base::IsAtRest -================ -*/ -bool idPhysics_Base::IsAtRest( void ) const { - return true; -} - -/* -================ -idPhysics_Base::GetRestStartTime -================ -*/ -int idPhysics_Base::GetRestStartTime( void ) const { - return 0; -} - -/* -================ -idPhysics_Base::IsPushable -================ -*/ -bool idPhysics_Base::IsPushable( void ) const { - return true; -} - -/* -================ -idPhysics_Base::SaveState -================ -*/ -void idPhysics_Base::SaveState( void ) { -} - -/* -================ -idPhysics_Base::RestoreState -================ -*/ -void idPhysics_Base::RestoreState( void ) { -} - -/* -================ -idPhysics_Base::SetOrigin -================ -*/ -void idPhysics_Base::SetOrigin( const idVec3 &newOrigin, int id ) { -} - -/* -================ -idPhysics_Base::SetAxis -================ -*/ -void idPhysics_Base::SetAxis( const idMat3 &newAxis, int id ) { -} - -/* -================ -idPhysics_Base::Translate -================ -*/ -void idPhysics_Base::Translate( const idVec3 &translation, int id ) { -} - -/* -================ -idPhysics_Base::Rotate -================ -*/ -void idPhysics_Base::Rotate( const idRotation &rotation, int id ) { -} - -/* -================ -idPhysics_Base::GetOrigin -================ -*/ -const idVec3 &idPhysics_Base::GetOrigin( int id ) const { - return vec3_origin; -} - -/* -================ -idPhysics_Base::GetAxis -================ -*/ -const idMat3 &idPhysics_Base::GetAxis( int id ) const { - return mat3_identity; -} - -/* -================ -idPhysics_Base::SetLinearVelocity -================ -*/ -void idPhysics_Base::SetLinearVelocity( const idVec3 &newLinearVelocity, int id ) { -} - -/* -================ -idPhysics_Base::SetAngularVelocity -================ -*/ -void idPhysics_Base::SetAngularVelocity( const idVec3 &newAngularVelocity, int id ) { -} - -/* -================ -idPhysics_Base::GetLinearVelocity -================ -*/ -const idVec3 &idPhysics_Base::GetLinearVelocity( int id ) const { - return vec3_origin; -} - -/* -================ -idPhysics_Base::GetAngularVelocity -================ -*/ -const idVec3 &idPhysics_Base::GetAngularVelocity( int id ) const { - return vec3_origin; -} - -/* -================ -idPhysics_Base::SetGravity -================ -*/ -void idPhysics_Base::SetGravity( const idVec3 &newGravity ) { - gravityVector = newGravity; - gravityNormal = newGravity; - gravityNormal.Normalize(); -} - -/* -================ -idPhysics_Base::GetGravity -================ -*/ -const idVec3 &idPhysics_Base::GetGravity( void ) const { - return gravityVector; -} - -/* -================ -idPhysics_Base::GetGravityNormal -================ -*/ -const idVec3 &idPhysics_Base::GetGravityNormal( void ) const { - return gravityNormal; -} - -/* -================ -idPhysics_Base::ClipTranslation -================ -*/ -void idPhysics_Base::ClipTranslation( trace_t &results, const idVec3 &translation, const idClipModel *model ) const { - memset( &results, 0, sizeof( trace_t ) ); -} - -/* -================ -idPhysics_Base::ClipRotation -================ -*/ -void idPhysics_Base::ClipRotation( trace_t &results, const idRotation &rotation, const idClipModel *model ) const { - memset( &results, 0, sizeof( trace_t ) ); -} - -/* -================ -idPhysics_Base::ClipContents -================ -*/ -int idPhysics_Base::ClipContents( const idClipModel *model ) const { - return 0; -} - -/* -================ -idPhysics_Base::DisableClip -================ -*/ -void idPhysics_Base::DisableClip( void ) { -} - -/* -================ -idPhysics_Base::EnableClip -================ -*/ -void idPhysics_Base::EnableClip( void ) { -} - -/* -================ -idPhysics_Base::UnlinkClip -================ -*/ -void idPhysics_Base::UnlinkClip( void ) { -} - -/* -================ -idPhysics_Base::LinkClip -================ -*/ -void idPhysics_Base::LinkClip( void ) { -} - -/* -================ -idPhysics_Base::EvaluateContacts -================ -*/ -bool idPhysics_Base::EvaluateContacts( void ) { - return false; -} - -/* -================ -idPhysics_Base::GetNumContacts -================ -*/ -int idPhysics_Base::GetNumContacts( void ) const { - return contacts.Num(); -} - -/* -================ -idPhysics_Base::GetContact -================ -*/ -const contactInfo_t &idPhysics_Base::GetContact( int num ) const { - return contacts[num]; -} - -/* -================ -idPhysics_Base::ClearContacts -================ -*/ -void idPhysics_Base::ClearContacts( void ) { - int i; - idEntity *ent; - - for ( i = 0; i < contacts.Num(); i++ ) { - ent = gameLocal.entities[ contacts[i].entityNum ]; - if ( ent ) { - ent->RemoveContactEntity( self ); - } - } - contacts.SetNum( 0, false ); -} - -/* -================ -idPhysics_Base::AddContactEntity -================ -*/ -void idPhysics_Base::AddContactEntity( idEntity *e ) { - int i; - idEntity *ent; - bool found = false; - - for ( i = 0; i < contactEntities.Num(); i++ ) { - ent = contactEntities[i].GetEntity(); - if ( ent == NULL ) { - contactEntities.RemoveIndex( i-- ); - } - if ( ent == e ) { - found = true; - } - } - if ( !found ) { - contactEntities.Alloc() = e; - } -} - -/* -================ -idPhysics_Base::RemoveContactEntity -================ -*/ -void idPhysics_Base::RemoveContactEntity( idEntity *e ) { - int i; - idEntity *ent; - - for ( i = 0; i < contactEntities.Num(); i++ ) { - ent = contactEntities[i].GetEntity(); - if ( !ent ) { - contactEntities.RemoveIndex( i-- ); - continue; - } - if ( ent == e ) { - contactEntities.RemoveIndex( i-- ); - return; - } - } -} - -/* -================ -idPhysics_Base::HasGroundContacts -================ -*/ -bool idPhysics_Base::HasGroundContacts( void ) const { - int i; - - for ( i = 0; i < contacts.Num(); i++ ) { - if ( contacts[i].normal * -gravityNormal > 0.0f ) { - return true; - } - } - return false; -} - -/* -================ -idPhysics_Base::IsGroundEntity -================ -*/ -bool idPhysics_Base::IsGroundEntity( int entityNum ) const { - int i; - - for ( i = 0; i < contacts.Num(); i++ ) { - if ( contacts[i].entityNum == entityNum && ( contacts[i].normal * -gravityNormal > 0.0f ) ) { - return true; - } - } - return false; -} - -/* -================ -idPhysics_Base::IsGroundClipModel -================ -*/ -bool idPhysics_Base::IsGroundClipModel( int entityNum, int id ) const { - int i; - - for ( i = 0; i < contacts.Num(); i++ ) { - if ( contacts[i].entityNum == entityNum && contacts[i].id == id && ( contacts[i].normal * -gravityNormal > 0.0f ) ) { - return true; - } - } - return false; -} - -/* -================ -idPhysics_Base::SetPushed -================ -*/ -void idPhysics_Base::SetPushed( int deltaTime ) { -} - -/* -================ -idPhysics_Base::GetPushedLinearVelocity -================ -*/ -const idVec3 &idPhysics_Base::GetPushedLinearVelocity( const int id ) const { - return vec3_origin; -} - -/* -================ -idPhysics_Base::GetPushedAngularVelocity -================ -*/ -const idVec3 &idPhysics_Base::GetPushedAngularVelocity( const int id ) const { - return vec3_origin; -} - -/* -================ -idPhysics_Base::SetMaster -================ -*/ -void idPhysics_Base::SetMaster( idEntity *master, const bool orientated ) { -} - -/* -================ -idPhysics_Base::GetBlockingInfo -================ -*/ -const trace_t *idPhysics_Base::GetBlockingInfo( void ) const { - return NULL; -} - -/* -================ -idPhysics_Base::GetBlockingEntity -================ -*/ -idEntity *idPhysics_Base::GetBlockingEntity( void ) const { - return NULL; -} - -/* -================ -idPhysics_Base::GetLinearEndTime -================ -*/ -int idPhysics_Base::GetLinearEndTime( void ) const { - return 0; -} - -/* -================ -idPhysics_Base::GetAngularEndTime -================ -*/ -int idPhysics_Base::GetAngularEndTime( void ) const { - return 0; -} - -/* -================ -idPhysics_Base::AddGroundContacts -================ -*/ -void idPhysics_Base::AddGroundContacts( const idClipModel *clipModel ) { - idVec6 dir; - int index, num; - - index = contacts.Num(); - contacts.SetNum( index + 10, false ); - - dir.SubVec3(0) = gravityNormal; - dir.SubVec3(1) = vec3_origin; - num = gameLocal.clip.Contacts( &contacts[index], 10, clipModel->GetOrigin(), - dir, CONTACT_EPSILON, clipModel, clipModel->GetAxis(), clipMask, self ); - contacts.SetNum( index + num, false ); -} - -/* -================ -idPhysics_Base::AddContactEntitiesForContacts -================ -*/ -void idPhysics_Base::AddContactEntitiesForContacts( void ) { - int i; - idEntity *ent; - - for ( i = 0; i < contacts.Num(); i++ ) { - ent = gameLocal.entities[ contacts[i].entityNum ]; - if ( ent && ent != self ) { - ent->AddContactEntity( self ); - } - } -} - -/* -================ -idPhysics_Base::ActivateContactEntities -================ -*/ -void idPhysics_Base::ActivateContactEntities( void ) { - int i; - idEntity *ent; - - for ( i = 0; i < contactEntities.Num(); i++ ) { - ent = contactEntities[i].GetEntity(); - if ( ent ) { - ent->ActivatePhysics( self ); - } else { - contactEntities.RemoveIndex( i-- ); - } - } -} - -/* -================ -idPhysics_Base::IsOutsideWorld -================ -*/ -bool idPhysics_Base::IsOutsideWorld( void ) const { - if ( !gameLocal.clip.GetWorldBounds().Expand( 128.0f ).IntersectsBounds( GetAbsBounds() ) ) { - return true; - } - return false; -} - -/* -================ -idPhysics_Base::DrawVelocity -================ -*/ -void idPhysics_Base::DrawVelocity( int id, float linearScale, float angularScale ) const { - idVec3 dir, org, vec, start, end; - idMat3 axis; - float length, a; - - dir = GetLinearVelocity( id ); - dir *= linearScale; - if ( dir.LengthSqr() > Square( 0.1f ) ) { - dir.Truncate( 10.0f ); - org = GetOrigin( id ); - gameRenderWorld->DebugArrow( colorRed, org, org + dir, 1 ); - } - - dir = GetAngularVelocity( id ); - length = dir.Normalize(); - length *= angularScale; - if ( length > 0.1f ) { - if ( length < 60.0f ) { - length = 60.0f; - } - else if ( length > 360.0f ) { - length = 360.0f; - } - axis = GetAxis( id ); - vec = axis[2]; - if ( idMath::Fabs( dir * vec ) > 0.99f ) { - vec = axis[0]; - } - vec -= vec * dir * vec; - vec.Normalize(); - vec *= 4.0f; - start = org + vec; - for ( a = 20.0f; a < length; a += 20.0f ) { - end = org + idRotation( vec3_origin, dir, -a ).ToMat3() * vec; - gameRenderWorld->DebugLine( colorBlue, start, end, 1 ); - start = end; - } - end = org + idRotation( vec3_origin, dir, -length ).ToMat3() * vec; - gameRenderWorld->DebugArrow( colorBlue, start, end, 1 ); - } -} - -/* -================ -idPhysics_Base::WriteToSnapshot -================ -*/ -void idPhysics_Base::WriteToSnapshot( idBitMsgDelta &msg ) const { -} - -/* -================ -idPhysics_Base::ReadFromSnapshot -================ -*/ -void idPhysics_Base::ReadFromSnapshot( const idBitMsgDelta &msg ) { -} diff --git a/d3xp/physics/Physics_Base.h b/d3xp/physics/Physics_Base.h deleted file mode 100644 index 0d739342..00000000 --- a/d3xp/physics/Physics_Base.h +++ /dev/null @@ -1,168 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __PHYSICS_BASE_H__ -#define __PHYSICS_BASE_H__ - -#include "physics/Physics.h" -#include "Game_local.h" - -/* -=============================================================================== - - Physics base for a moving object using one or more collision models. - -=============================================================================== -*/ - -#define contactEntity_t idEntityPtr - -class idPhysics_Base : public idPhysics { - -public: - CLASS_PROTOTYPE( idPhysics_Base ); - - idPhysics_Base( void ); - ~idPhysics_Base( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - -public: // common physics interface - - void SetSelf( idEntity *e ); - - void SetClipModel( idClipModel *model, float density, int id = 0, bool freeOld = true ); - idClipModel * GetClipModel( int id = 0 ) const; - int GetNumClipModels( void ) const; - - void SetMass( float mass, int id = -1 ); - float GetMass( int id = -1 ) const; - - void SetContents( int contents, int id = -1 ); - int GetContents( int id = -1 ) const; - - void SetClipMask( int mask, int id = -1 ); - int GetClipMask( int id = -1 ) const; - - const idBounds & GetBounds( int id = -1 ) const; - const idBounds & GetAbsBounds( int id = -1 ) const; - - bool Evaluate( int timeStepMSec, int endTimeMSec ); - void UpdateTime( int endTimeMSec ); - int GetTime( void ) const; - - void GetImpactInfo( const int id, const idVec3 &point, impactInfo_t *info ) const; - void ApplyImpulse( const int id, const idVec3 &point, const idVec3 &impulse ); - void AddForce( const int id, const idVec3 &point, const idVec3 &force ); - void Activate( void ); - void PutToRest( void ); - bool IsAtRest( void ) const; - int GetRestStartTime( void ) const; - bool IsPushable( void ) const; - - void SaveState( void ); - void RestoreState( void ); - - void SetOrigin( const idVec3 &newOrigin, int id = -1 ); - void SetAxis( const idMat3 &newAxis, int id = -1 ); - - void Translate( const idVec3 &translation, int id = -1 ); - void Rotate( const idRotation &rotation, int id = -1 ); - - const idVec3 & GetOrigin( int id = 0 ) const; - const idMat3 & GetAxis( int id = 0 ) const; - - void SetLinearVelocity( const idVec3 &newLinearVelocity, int id = 0 ); - void SetAngularVelocity( const idVec3 &newAngularVelocity, int id = 0 ); - - const idVec3 & GetLinearVelocity( int id = 0 ) const; - const idVec3 & GetAngularVelocity( int id = 0 ) const; - - void SetGravity( const idVec3 &newGravity ); - const idVec3 & GetGravity( void ) const; - const idVec3 & GetGravityNormal( void ) const; - - void ClipTranslation( trace_t &results, const idVec3 &translation, const idClipModel *model ) const; - void ClipRotation( trace_t &results, const idRotation &rotation, const idClipModel *model ) const; - int ClipContents( const idClipModel *model ) const; - - void DisableClip( void ); - void EnableClip( void ); - - void UnlinkClip( void ); - void LinkClip( void ); - - bool EvaluateContacts( void ); - int GetNumContacts( void ) const; - const contactInfo_t & GetContact( int num ) const; - void ClearContacts( void ); - void AddContactEntity( idEntity *e ); - void RemoveContactEntity( idEntity *e ); - - bool HasGroundContacts( void ) const; - bool IsGroundEntity( int entityNum ) const; - bool IsGroundClipModel( int entityNum, int id ) const; - - void SetPushed( int deltaTime ); - const idVec3 & GetPushedLinearVelocity( const int id = 0 ) const; - const idVec3 & GetPushedAngularVelocity( const int id = 0 ) const; - - void SetMaster( idEntity *master, const bool orientated = true ); - - const trace_t * GetBlockingInfo( void ) const; - idEntity * GetBlockingEntity( void ) const; - - int GetLinearEndTime( void ) const; - int GetAngularEndTime( void ) const; - - void WriteToSnapshot( idBitMsgDelta &msg ) const; - void ReadFromSnapshot( const idBitMsgDelta &msg ); - -protected: - idEntity * self; // entity using this physics object - int clipMask; // contents the physics object collides with - idVec3 gravityVector; // direction and magnitude of gravity - idVec3 gravityNormal; // normalized direction of gravity - idList contacts; // contacts with other physics objects - idList contactEntities; // entities touching this physics object - -protected: - // add ground contacts for the clip model - void AddGroundContacts( const idClipModel *clipModel ); - // add contact entity links to contact entities - void AddContactEntitiesForContacts( void ); - // active all contact entities - void ActivateContactEntities( void ); - // returns true if the whole physics object is outside the world bounds - bool IsOutsideWorld( void ) const; - // draw linear and angular velocity - void DrawVelocity( int id, float linearScale, float angularScale ) const; -}; - -#endif /* !__PHYSICS_BASE_H__ */ diff --git a/d3xp/physics/Physics_Monster.cpp b/d3xp/physics/Physics_Monster.cpp deleted file mode 100644 index 8b74d3a7..00000000 --- a/d3xp/physics/Physics_Monster.cpp +++ /dev/null @@ -1,807 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "Entity.h" -#include "Actor.h" - -#include "physics/Physics_Monster.h" - -CLASS_DECLARATION( idPhysics_Actor, idPhysics_Monster ) -END_CLASS - -const float OVERCLIP = 1.001f; - -/* -===================== -idPhysics_Monster::CheckGround -===================== -*/ -void idPhysics_Monster::CheckGround( monsterPState_t &state ) { - trace_t groundTrace; - idVec3 down; - - if ( gravityNormal == vec3_zero ) { - state.onGround = false; - groundEntityPtr = NULL; - return; - } - - down = state.origin + gravityNormal * CONTACT_EPSILON; - gameLocal.clip.Translation( groundTrace, state.origin, down, clipModel, clipModel->GetAxis(), clipMask, self ); - - if ( groundTrace.fraction == 1.0f ) { - state.onGround = false; - groundEntityPtr = NULL; - return; - } - - groundEntityPtr = gameLocal.entities[ groundTrace.c.entityNum ]; - - if ( ( groundTrace.c.normal * -gravityNormal ) < minFloorCosine ) { - state.onGround = false; - return; - } - - state.onGround = true; - - // let the entity know about the collision - self->Collide( groundTrace, state.velocity ); - - // apply impact to a non world floor entity - if ( groundTrace.c.entityNum != ENTITYNUM_WORLD && groundEntityPtr.GetEntity() ) { - impactInfo_t info; - groundEntityPtr.GetEntity()->GetImpactInfo( self, groundTrace.c.id, groundTrace.c.point, &info ); - if ( info.invMass != 0.0f ) { - groundEntityPtr.GetEntity()->ApplyImpulse( self, 0, groundTrace.c.point, state.velocity / ( info.invMass * 10.0f ) ); - } - } -} - -/* -===================== -idPhysics_Monster::SlideMove -===================== -*/ -monsterMoveResult_t idPhysics_Monster::SlideMove( idVec3 &start, idVec3 &velocity, const idVec3 &delta ) { - int i; - trace_t tr; - idVec3 move; - - blockingEntity = NULL; - move = delta; - for( i = 0; i < 3; i++ ) { - gameLocal.clip.Translation( tr, start, start + move, clipModel, clipModel->GetAxis(), clipMask, self ); - - start = tr.endpos; - - if ( tr.fraction == 1.0f ) { - if ( i > 0 ) { - return MM_SLIDING; - } - return MM_OK; - } - - if ( tr.c.entityNum != ENTITYNUM_NONE ) { - blockingEntity = gameLocal.entities[ tr.c.entityNum ]; - } - - // clip the movement delta and velocity - move.ProjectOntoPlane( tr.c.normal, OVERCLIP ); - velocity.ProjectOntoPlane( tr.c.normal, OVERCLIP ); - } - - return MM_BLOCKED; -} - -/* -===================== -idPhysics_Monster::StepMove - - move start into the delta direction - the velocity is clipped conform any collisions -===================== -*/ -monsterMoveResult_t idPhysics_Monster::StepMove( idVec3 &start, idVec3 &velocity, const idVec3 &delta ) { - trace_t tr; - idVec3 up, down, noStepPos, noStepVel, stepPos, stepVel; - monsterMoveResult_t result1, result2; - float stepdist; - float nostepdist; - - if ( delta == vec3_origin ) { - return MM_OK; - } - - // try to move without stepping up - noStepPos = start; - noStepVel = velocity; - result1 = SlideMove( noStepPos, noStepVel, delta ); - if ( result1 == MM_OK ) { - velocity = noStepVel; - if ( gravityNormal == vec3_zero ) { - start = noStepPos; - return MM_OK; - } - - // try to step down so that we walk down slopes and stairs at a normal rate - down = noStepPos + gravityNormal * maxStepHeight; - gameLocal.clip.Translation( tr, noStepPos, down, clipModel, clipModel->GetAxis(), clipMask, self ); - if ( tr.fraction < 1.0f ) { - start = tr.endpos; - return MM_STEPPED; - } else { - start = noStepPos; - return MM_OK; - } - } - - if ( blockingEntity && blockingEntity->IsType( idActor::Type ) ) { - // try to step down in case walking into an actor while going down steps - down = noStepPos + gravityNormal * maxStepHeight; - gameLocal.clip.Translation( tr, noStepPos, down, clipModel, clipModel->GetAxis(), clipMask, self ); - start = tr.endpos; - velocity = noStepVel; - return MM_BLOCKED; - } - - if ( gravityNormal == vec3_zero ) { - return result1; - } - - // try to step up - up = start - gravityNormal * maxStepHeight; - gameLocal.clip.Translation( tr, start, up, clipModel, clipModel->GetAxis(), clipMask, self ); - if ( tr.fraction == 0.0f ) { - start = noStepPos; - velocity = noStepVel; - return result1; - } - - // try to move at the stepped up position - stepPos = tr.endpos; - stepVel = velocity; - result2 = SlideMove( stepPos, stepVel, delta ); - if ( result2 == MM_BLOCKED ) { - start = noStepPos; - velocity = noStepVel; - return result1; - } - - // step down again - down = stepPos + gravityNormal * maxStepHeight; - gameLocal.clip.Translation( tr, stepPos, down, clipModel, clipModel->GetAxis(), clipMask, self ); - stepPos = tr.endpos; - - // if the move is further without stepping up, or the slope is too steap, don't step up - nostepdist = ( noStepPos - start ).LengthSqr(); - stepdist = ( stepPos - start ).LengthSqr(); - if ( ( nostepdist >= stepdist ) || ( ( tr.c.normal * -gravityNormal ) < minFloorCosine ) ) { - start = noStepPos; - velocity = noStepVel; - return MM_SLIDING; - } - - start = stepPos; - velocity = stepVel; - - return MM_STEPPED; -} - -/* -================ -idPhysics_Monster::Activate -================ -*/ -void idPhysics_Monster::Activate( void ) { - current.atRest = -1; - self->BecomeActive( TH_PHYSICS ); -} - -/* -================ -idPhysics_Monster::Rest -================ -*/ -void idPhysics_Monster::Rest( void ) { - current.atRest = gameLocal.time; - current.velocity.Zero(); - self->BecomeInactive( TH_PHYSICS ); -} - -/* -================ -idPhysics_Monster::PutToRest -================ -*/ -void idPhysics_Monster::PutToRest( void ) { - Rest(); -} - -/* -================ -idPhysics_Monster::idPhysics_Monster -================ -*/ -idPhysics_Monster::idPhysics_Monster( void ) { - - memset( ¤t, 0, sizeof( current ) ); - current.atRest = -1; - saved = current; - - delta.Zero(); - maxStepHeight = 18.0f; - minFloorCosine = 0.7f; - moveResult = MM_OK; - forceDeltaMove = false; - fly = false; - useVelocityMove = false; - noImpact = false; - blockingEntity = NULL; -} - -/* -================ -idPhysics_Monster_SavePState -================ -*/ -void idPhysics_Monster_SavePState( idSaveGame *savefile, const monsterPState_t &state ) { - savefile->WriteVec3( state.origin ); - savefile->WriteVec3( state.velocity ); - savefile->WriteVec3( state.localOrigin ); - savefile->WriteVec3( state.pushVelocity ); - savefile->WriteBool( state.onGround ); - savefile->WriteInt( state.atRest ); -} - -/* -================ -idPhysics_Monster_RestorePState -================ -*/ -void idPhysics_Monster_RestorePState( idRestoreGame *savefile, monsterPState_t &state ) { - savefile->ReadVec3( state.origin ); - savefile->ReadVec3( state.velocity ); - savefile->ReadVec3( state.localOrigin ); - savefile->ReadVec3( state.pushVelocity ); - savefile->ReadBool( state.onGround ); - savefile->ReadInt( state.atRest ); -} - -/* -================ -idPhysics_Monster::Save -================ -*/ -void idPhysics_Monster::Save( idSaveGame *savefile ) const { - - idPhysics_Monster_SavePState( savefile, current ); - idPhysics_Monster_SavePState( savefile, saved ); - - savefile->WriteFloat( maxStepHeight ); - savefile->WriteFloat( minFloorCosine ); - savefile->WriteVec3( delta ); - - savefile->WriteBool( forceDeltaMove ); - savefile->WriteBool( fly ); - savefile->WriteBool( useVelocityMove ); - savefile->WriteBool( noImpact ); - - savefile->WriteInt( (int)moveResult ); - savefile->WriteObject( blockingEntity ); -} - -/* -================ -idPhysics_Monster::Restore -================ -*/ -void idPhysics_Monster::Restore( idRestoreGame *savefile ) { - - idPhysics_Monster_RestorePState( savefile, current ); - idPhysics_Monster_RestorePState( savefile, saved ); - - savefile->ReadFloat( maxStepHeight ); - savefile->ReadFloat( minFloorCosine ); - savefile->ReadVec3( delta ); - - savefile->ReadBool( forceDeltaMove ); - savefile->ReadBool( fly ); - savefile->ReadBool( useVelocityMove ); - savefile->ReadBool( noImpact ); - - savefile->ReadInt( (int &)moveResult ); - savefile->ReadObject( reinterpret_cast( blockingEntity ) ); -} - -/* -================ -idPhysics_Monster::SetDelta -================ -*/ -void idPhysics_Monster::SetDelta( const idVec3 &d ) { - delta = d; - if ( delta != vec3_origin ) { - Activate(); - } -} - -/* -================ -idPhysics_Monster::SetMaxStepHeight -================ -*/ -void idPhysics_Monster::SetMaxStepHeight( const float newMaxStepHeight ) { - maxStepHeight = newMaxStepHeight; -} - -/* -================ -idPhysics_Monster::GetMaxStepHeight -================ -*/ -float idPhysics_Monster::GetMaxStepHeight( void ) const { - return maxStepHeight; -} - -/* -================ -idPhysics_Monster::OnGround -================ -*/ -bool idPhysics_Monster::OnGround( void ) const { - return current.onGround; -} - -/* -================ -idPhysics_Monster::GetSlideMoveEntity -================ -*/ -idEntity *idPhysics_Monster::GetSlideMoveEntity( void ) const { - return blockingEntity; -} - -/* -================ -idPhysics_Monster::GetMoveResult -================ -*/ -monsterMoveResult_t idPhysics_Monster::GetMoveResult( void ) const { - return moveResult; -} - -/* -================ -idPhysics_Monster::ForceDeltaMove -================ -*/ -void idPhysics_Monster::ForceDeltaMove( bool force ) { - forceDeltaMove = force; -} - -/* -================ -idPhysics_Monster::UseFlyMove -================ -*/ -void idPhysics_Monster::UseFlyMove( bool force ) { - fly = force; -} - -/* -================ -idPhysics_Monster::UseVelocityMove -================ -*/ -void idPhysics_Monster::UseVelocityMove( bool force ) { - useVelocityMove = force; -} - -/* -================ -idPhysics_Monster::EnableImpact -================ -*/ -void idPhysics_Monster::EnableImpact( void ) { - noImpact = false; -} - -/* -================ -idPhysics_Monster::DisableImpact -================ -*/ -void idPhysics_Monster::DisableImpact( void ) { - noImpact = true; -} - -/* -================ -idPhysics_Monster::Evaluate -================ -*/ -bool idPhysics_Monster::Evaluate( int timeStepMSec, int endTimeMSec ) { - idVec3 masterOrigin, oldOrigin; - idMat3 masterAxis; - float timeStep; - - timeStep = MS2SEC( timeStepMSec ); - - moveResult = MM_OK; - blockingEntity = NULL; - oldOrigin = current.origin; - - // if bound to a master - if ( masterEntity ) { - self->GetMasterPosition( masterOrigin, masterAxis ); - current.origin = masterOrigin + current.localOrigin * masterAxis; - clipModel->Link( gameLocal.clip, self, 0, current.origin, clipModel->GetAxis() ); - current.velocity = ( current.origin - oldOrigin ) / timeStep; - masterDeltaYaw = masterYaw; - masterYaw = masterAxis[0].ToYaw(); - masterDeltaYaw = masterYaw - masterDeltaYaw; - return true; - } - - // if the monster is at rest - if ( current.atRest >= 0 ) { - return false; - } - - ActivateContactEntities(); - - // move the monster velocity into the frame of a pusher - current.velocity -= current.pushVelocity; - - clipModel->Unlink(); - - // check if on the ground - idPhysics_Monster::CheckGround( current ); - - // if not on the ground or moving upwards - float upspeed; - if ( gravityNormal != vec3_zero ) { - upspeed = -( current.velocity * gravityNormal ); - } else { - upspeed = current.velocity.z; - } - if ( fly || ( !forceDeltaMove && ( !current.onGround || upspeed > 1.0f ) ) ) { - if ( upspeed < 0.0f ) { - moveResult = MM_FALLING; - } - else { - current.onGround = false; - moveResult = MM_OK; - } - delta = current.velocity * timeStep; - if ( delta != vec3_origin ) { - moveResult = idPhysics_Monster::SlideMove( current.origin, current.velocity, delta ); - delta.Zero(); - } - - if ( !fly ) { - current.velocity += gravityVector * timeStep; - } - } else { - if ( useVelocityMove ) { - delta = current.velocity * timeStep; - } else { - current.velocity = delta / timeStep; - } - - current.velocity -= ( current.velocity * gravityNormal ) * gravityNormal; - - if ( delta == vec3_origin ) { - Rest(); - } else { - // try moving into the desired direction - moveResult = idPhysics_Monster::StepMove( current.origin, current.velocity, delta ); - delta.Zero(); - } - } - - clipModel->Link( gameLocal.clip, self, 0, current.origin, clipModel->GetAxis() ); - - // get all the ground contacts - EvaluateContacts(); - - // move the monster velocity back into the world frame - current.velocity += current.pushVelocity; - current.pushVelocity.Zero(); - - if ( IsOutsideWorld() ) { - gameLocal.Warning( "clip model outside world bounds for entity '%s' at (%s)", self->name.c_str(), current.origin.ToString(0) ); - Rest(); - } - - return ( current.origin != oldOrigin ); -} - -/* -================ -idPhysics_Monster::UpdateTime -================ -*/ -void idPhysics_Monster::UpdateTime( int endTimeMSec ) { -} - -/* -================ -idPhysics_Monster::GetTime -================ -*/ -int idPhysics_Monster::GetTime( void ) const { - return gameLocal.time; -} - -/* -================ -idPhysics_Monster::GetImpactInfo -================ -*/ -void idPhysics_Monster::GetImpactInfo( const int id, const idVec3 &point, impactInfo_t *info ) const { - info->invMass = invMass; - info->invInertiaTensor.Zero(); - info->position.Zero(); - info->velocity = current.velocity; -} - -/* -================ -idPhysics_Monster::ApplyImpulse -================ -*/ -void idPhysics_Monster::ApplyImpulse( const int id, const idVec3 &point, const idVec3 &impulse ) { - if ( noImpact ) { - return; - } - current.velocity += impulse * invMass; - Activate(); -} - -/* -================ -idPhysics_Monster::IsAtRest -================ -*/ -bool idPhysics_Monster::IsAtRest( void ) const { - return current.atRest >= 0; -} - -/* -================ -idPhysics_Monster::GetRestStartTime -================ -*/ -int idPhysics_Monster::GetRestStartTime( void ) const { - return current.atRest; -} - -/* -================ -idPhysics_Monster::SaveState -================ -*/ -void idPhysics_Monster::SaveState( void ) { - saved = current; -} - -/* -================ -idPhysics_Monster::RestoreState -================ -*/ -void idPhysics_Monster::RestoreState( void ) { - current = saved; - - clipModel->Link( gameLocal.clip, self, 0, current.origin, clipModel->GetAxis() ); - - EvaluateContacts(); -} - -/* -================ -idPhysics_Player::SetOrigin -================ -*/ -void idPhysics_Monster::SetOrigin( const idVec3 &newOrigin, int id ) { - idVec3 masterOrigin; - idMat3 masterAxis; - - current.localOrigin = newOrigin; - if ( masterEntity ) { - self->GetMasterPosition( masterOrigin, masterAxis ); - current.origin = masterOrigin + newOrigin * masterAxis; - } - else { - current.origin = newOrigin; - } - clipModel->Link( gameLocal.clip, self, 0, newOrigin, clipModel->GetAxis() ); - Activate(); -} - -/* -================ -idPhysics_Player::SetAxis -================ -*/ -void idPhysics_Monster::SetAxis( const idMat3 &newAxis, int id ) { - clipModel->Link( gameLocal.clip, self, 0, clipModel->GetOrigin(), newAxis ); - Activate(); -} - -/* -================ -idPhysics_Monster::Translate -================ -*/ -void idPhysics_Monster::Translate( const idVec3 &translation, int id ) { - - current.localOrigin += translation; - current.origin += translation; - clipModel->Link( gameLocal.clip, self, 0, current.origin, clipModel->GetAxis() ); - Activate(); -} - -/* -================ -idPhysics_Monster::Rotate -================ -*/ -void idPhysics_Monster::Rotate( const idRotation &rotation, int id ) { - idVec3 masterOrigin; - idMat3 masterAxis; - - current.origin *= rotation; - if ( masterEntity ) { - self->GetMasterPosition( masterOrigin, masterAxis ); - current.localOrigin = ( current.origin - masterOrigin ) * masterAxis.Transpose(); - } - else { - current.localOrigin = current.origin; - } - clipModel->Link( gameLocal.clip, self, 0, current.origin, clipModel->GetAxis() * rotation.ToMat3() ); - Activate(); -} - -/* -================ -idPhysics_Monster::SetLinearVelocity -================ -*/ -void idPhysics_Monster::SetLinearVelocity( const idVec3 &newLinearVelocity, int id ) { - current.velocity = newLinearVelocity; - Activate(); -} - -/* -================ -idPhysics_Monster::GetLinearVelocity -================ -*/ -const idVec3 &idPhysics_Monster::GetLinearVelocity( int id ) const { - return current.velocity; -} - -/* -================ -idPhysics_Monster::SetPushed -================ -*/ -void idPhysics_Monster::SetPushed( int deltaTime ) { - // velocity with which the monster is pushed - current.pushVelocity += ( current.origin - saved.origin ) / ( deltaTime * idMath::M_MS2SEC ); -} - -/* -================ -idPhysics_Monster::GetPushedLinearVelocity -================ -*/ -const idVec3 &idPhysics_Monster::GetPushedLinearVelocity( const int id ) const { - return current.pushVelocity; -} - -/* -================ -idPhysics_Monster::SetMaster - - the binding is never orientated -================ -*/ -void idPhysics_Monster::SetMaster( idEntity *master, const bool orientated ) { - idVec3 masterOrigin; - idMat3 masterAxis; - - if ( master ) { - if ( !masterEntity ) { - // transform from world space to master space - self->GetMasterPosition( masterOrigin, masterAxis ); - current.localOrigin = ( current.origin - masterOrigin ) * masterAxis.Transpose(); - masterEntity = master; - masterYaw = masterAxis[0].ToYaw(); - } - ClearContacts(); - } - else { - if ( masterEntity ) { - masterEntity = NULL; - Activate(); - } - } -} - -const float MONSTER_VELOCITY_MAX = 4000; -const int MONSTER_VELOCITY_TOTAL_BITS = 16; -const int MONSTER_VELOCITY_EXPONENT_BITS = idMath::BitsForInteger( idMath::BitsForFloat( MONSTER_VELOCITY_MAX ) ) + 1; -const int MONSTER_VELOCITY_MANTISSA_BITS = MONSTER_VELOCITY_TOTAL_BITS - 1 - MONSTER_VELOCITY_EXPONENT_BITS; - -/* -================ -idPhysics_Monster::WriteToSnapshot -================ -*/ -void idPhysics_Monster::WriteToSnapshot( idBitMsgDelta &msg ) const { - msg.WriteFloat( current.origin[0] ); - msg.WriteFloat( current.origin[1] ); - msg.WriteFloat( current.origin[2] ); - msg.WriteFloat( current.velocity[0], MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS ); - msg.WriteFloat( current.velocity[1], MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS ); - msg.WriteFloat( current.velocity[2], MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS ); - msg.WriteDeltaFloat( current.origin[0], current.localOrigin[0] ); - msg.WriteDeltaFloat( current.origin[1], current.localOrigin[1] ); - msg.WriteDeltaFloat( current.origin[2], current.localOrigin[2] ); - msg.WriteDeltaFloat( 0.0f, current.pushVelocity[0], MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS ); - msg.WriteDeltaFloat( 0.0f, current.pushVelocity[1], MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS ); - msg.WriteDeltaFloat( 0.0f, current.pushVelocity[2], MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS ); - msg.WriteInt( current.atRest ); - msg.WriteBits( current.onGround, 1 ); -} - -/* -================ -idPhysics_Monster::ReadFromSnapshot -================ -*/ -void idPhysics_Monster::ReadFromSnapshot( const idBitMsgDelta &msg ) { - current.origin[0] = msg.ReadFloat(); - current.origin[1] = msg.ReadFloat(); - current.origin[2] = msg.ReadFloat(); - current.velocity[0] = msg.ReadFloat( MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS ); - current.velocity[1] = msg.ReadFloat( MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS ); - current.velocity[2] = msg.ReadFloat( MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS ); - current.localOrigin[0] = msg.ReadDeltaFloat( current.origin[0] ); - current.localOrigin[1] = msg.ReadDeltaFloat( current.origin[1] ); - current.localOrigin[2] = msg.ReadDeltaFloat( current.origin[2] ); - current.pushVelocity[0] = msg.ReadDeltaFloat( 0.0f, MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS ); - current.pushVelocity[1] = msg.ReadDeltaFloat( 0.0f, MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS ); - current.pushVelocity[2] = msg.ReadDeltaFloat( 0.0f, MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS ); - current.atRest = msg.ReadInt(); - current.onGround = msg.ReadBits( 1 ) != 0; -} diff --git a/d3xp/physics/Physics_Monster.h b/d3xp/physics/Physics_Monster.h deleted file mode 100644 index 0df59dd8..00000000 --- a/d3xp/physics/Physics_Monster.h +++ /dev/null @@ -1,156 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __PHYSICS_MONSTER_H__ -#define __PHYSICS_MONSTER_H__ - -#include "idlib/math/Vector.h" - -#include "physics/Physics_Actor.h" - -/* -=================================================================================== - - Monster physics - - Simulates the motion of a monster through the environment. The monster motion - is typically driven by animations. - -=================================================================================== -*/ - -typedef enum { - MM_OK, - MM_SLIDING, - MM_BLOCKED, - MM_STEPPED, - MM_FALLING -} monsterMoveResult_t; - -typedef struct monsterPState_s { - int atRest; - bool onGround; - idVec3 origin; - idVec3 velocity; - idVec3 localOrigin; - idVec3 pushVelocity; -} monsterPState_t; - -class idPhysics_Monster : public idPhysics_Actor { - -public: - CLASS_PROTOTYPE( idPhysics_Monster ); - - idPhysics_Monster( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - // maximum step up the monster can take, default 18 units - void SetMaxStepHeight( const float newMaxStepHeight ); - float GetMaxStepHeight( void ) const; - // minimum cosine of floor angle to be able to stand on the floor - void SetMinFloorCosine( const float newMinFloorCosine ); - // set delta for next move - void SetDelta( const idVec3 &d ); - // returns true if monster is standing on the ground - bool OnGround( void ) const; - // returns the movement result - monsterMoveResult_t GetMoveResult( void ) const; - // overrides any velocity for pure delta movement - void ForceDeltaMove( bool force ); - // whether velocity should be affected by gravity - void UseFlyMove( bool force ); - // don't use delta movement - void UseVelocityMove( bool force ); - // get entity blocking the move - idEntity * GetSlideMoveEntity( void ) const; - // enable/disable activation by impact - void EnableImpact( void ); - void DisableImpact( void ); - -public: // common physics interface - bool Evaluate( int timeStepMSec, int endTimeMSec ); - void UpdateTime( int endTimeMSec ); - int GetTime( void ) const; - - void GetImpactInfo( const int id, const idVec3 &point, impactInfo_t *info ) const; - void ApplyImpulse( const int id, const idVec3 &point, const idVec3 &impulse ); - void Activate( void ); - void PutToRest( void ); - bool IsAtRest( void ) const; - int GetRestStartTime( void ) const; - - void SaveState( void ); - void RestoreState( void ); - - void SetOrigin( const idVec3 &newOrigin, int id = -1 ); - void SetAxis( const idMat3 &newAxis, int id = -1 ); - - void Translate( const idVec3 &translation, int id = -1 ); - void Rotate( const idRotation &rotation, int id = -1 ); - - void SetLinearVelocity( const idVec3 &newLinearVelocity, int id = 0 ); - - const idVec3 & GetLinearVelocity( int id = 0 ) const; - - void SetPushed( int deltaTime ); - const idVec3 & GetPushedLinearVelocity( const int id = 0 ) const; - - void SetMaster( idEntity *master, const bool orientated = true ); - - void WriteToSnapshot( idBitMsgDelta &msg ) const; - void ReadFromSnapshot( const idBitMsgDelta &msg ); - -private: - // monster physics state - monsterPState_t current; - monsterPState_t saved; - - // properties - float maxStepHeight; // maximum step height - float minFloorCosine; // minimum cosine of floor angle - idVec3 delta; // delta for next move - - bool forceDeltaMove; - bool fly; - bool useVelocityMove; - bool noImpact; // if true do not activate when another object collides - - // results of last evaluate - monsterMoveResult_t moveResult; - idEntity * blockingEntity; - -private: - void CheckGround( monsterPState_t &state ); - monsterMoveResult_t SlideMove( idVec3 &start, idVec3 &velocity, const idVec3 &delta ); - monsterMoveResult_t StepMove( idVec3 &start, idVec3 &velocity, const idVec3 &delta ); - void Rest( void ); -}; - -#endif /* !__PHYSICS_MONSTER_H__ */ diff --git a/d3xp/physics/Physics_Parametric.cpp b/d3xp/physics/Physics_Parametric.cpp deleted file mode 100644 index 123439ce..00000000 --- a/d3xp/physics/Physics_Parametric.cpp +++ /dev/null @@ -1,1181 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "Entity.h" - -#include "physics/Physics_Parametric.h" - -CLASS_DECLARATION( idPhysics_Base, idPhysics_Parametric ) -END_CLASS - - -/* -================ -idPhysics_Parametric::Activate -================ -*/ -void idPhysics_Parametric::Activate( void ) { - current.atRest = -1; - self->BecomeActive( TH_PHYSICS ); -} - -/* -================ -idPhysics_Parametric::TestIfAtRest -================ -*/ -bool idPhysics_Parametric::TestIfAtRest( void ) const { - - if ( ( current.linearExtrapolation.GetExtrapolationType() & ~EXTRAPOLATION_NOSTOP ) == EXTRAPOLATION_NONE && - ( current.angularExtrapolation.GetExtrapolationType() & ~EXTRAPOLATION_NOSTOP ) == EXTRAPOLATION_NONE && - current.linearInterpolation.GetDuration() == 0 && - current.angularInterpolation.GetDuration() == 0 && - current.spline == NULL ) { - return true; - } - - if ( !current.linearExtrapolation.IsDone( current.time ) ) { - return false; - } - - if ( !current.angularExtrapolation.IsDone( current.time ) ) { - return false; - } - - if ( !current.linearInterpolation.IsDone( current.time ) ) { - return false; - } - - if ( !current.angularInterpolation.IsDone( current.time ) ) { - return false; - } - - if ( current.spline != NULL && !current.spline->IsDone( current.time ) ) { - return false; - } - - return true; -} - -/* -================ -idPhysics_Parametric::Rest -================ -*/ -void idPhysics_Parametric::Rest( void ) { - current.atRest = gameLocal.time; - self->BecomeInactive( TH_PHYSICS ); -} - -/* -================ -idPhysics_Parametric::idPhysics_Parametric -================ -*/ -idPhysics_Parametric::idPhysics_Parametric( void ) { - - current.time = gameLocal.time; - current.atRest = -1; - current.useSplineAngles = false; - current.origin.Zero(); - current.angles.Zero(); - current.axis.Identity(); - current.localOrigin.Zero(); - current.localAngles.Zero(); - current.linearExtrapolation.Init( 0, 0, vec3_zero, vec3_zero, vec3_zero, EXTRAPOLATION_NONE ); - current.angularExtrapolation.Init( 0, 0, ang_zero, ang_zero, ang_zero, EXTRAPOLATION_NONE ); - current.linearInterpolation.Init( 0, 0, 0, 0, vec3_zero, vec3_zero ); - current.angularInterpolation.Init( 0, 0, 0, 0, ang_zero, ang_zero ); - current.spline = NULL; - current.splineInterpolate.Init( 0, 1, 1, 2, 0, 0 ); - - saved = current; - - isPusher = false; - pushFlags = 0; - clipModel = NULL; - isBlocked = false; - memset( &pushResults, 0, sizeof( pushResults ) ); - - hasMaster = false; - isOrientated = false; -} - -/* -================ -idPhysics_Parametric::~idPhysics_Parametric -================ -*/ -idPhysics_Parametric::~idPhysics_Parametric( void ) { - if ( clipModel != NULL ) { - delete clipModel; - clipModel = NULL; - } - if ( current.spline != NULL ) { - delete current.spline; - current.spline = NULL; - } -} - -/* -================ -idPhysics_Parametric_SavePState -================ -*/ -void idPhysics_Parametric_SavePState( idSaveGame *savefile, const parametricPState_t &state ) { - savefile->WriteInt( state.time ); - savefile->WriteInt( state.atRest ); - savefile->WriteBool( state.useSplineAngles ); - savefile->WriteVec3( state.origin ); - savefile->WriteAngles( state.angles ); - savefile->WriteMat3( state.axis ); - savefile->WriteVec3( state.localOrigin ); - savefile->WriteAngles( state.localAngles ); - - savefile->WriteInt( (int)state.linearExtrapolation.GetExtrapolationType() ); - savefile->WriteFloat( state.linearExtrapolation.GetStartTime() ); - savefile->WriteFloat( state.linearExtrapolation.GetDuration() ); - savefile->WriteVec3( state.linearExtrapolation.GetStartValue() ); - savefile->WriteVec3( state.linearExtrapolation.GetBaseSpeed() ); - savefile->WriteVec3( state.linearExtrapolation.GetSpeed() ); - - savefile->WriteInt( (int)state.angularExtrapolation.GetExtrapolationType() ); - savefile->WriteFloat( state.angularExtrapolation.GetStartTime() ); - savefile->WriteFloat( state.angularExtrapolation.GetDuration() ); - savefile->WriteAngles( state.angularExtrapolation.GetStartValue() ); - savefile->WriteAngles( state.angularExtrapolation.GetBaseSpeed() ); - savefile->WriteAngles( state.angularExtrapolation.GetSpeed() ); - - savefile->WriteFloat( state.linearInterpolation.GetStartTime() ); - savefile->WriteFloat( state.linearInterpolation.GetAcceleration() ); - savefile->WriteFloat( state.linearInterpolation.GetDeceleration() ); - savefile->WriteFloat( state.linearInterpolation.GetDuration() ); - savefile->WriteVec3( state.linearInterpolation.GetStartValue() ); - savefile->WriteVec3( state.linearInterpolation.GetEndValue() ); - - savefile->WriteFloat( state.angularInterpolation.GetStartTime() ); - savefile->WriteFloat( state.angularInterpolation.GetAcceleration() ); - savefile->WriteFloat( state.angularInterpolation.GetDeceleration() ); - savefile->WriteFloat( state.angularInterpolation.GetDuration() ); - savefile->WriteAngles( state.angularInterpolation.GetStartValue() ); - savefile->WriteAngles( state.angularInterpolation.GetEndValue() ); - - // spline is handled by owner - - savefile->WriteFloat( state.splineInterpolate.GetStartTime() ); - savefile->WriteFloat( state.splineInterpolate.GetAcceleration() ); - savefile->WriteFloat( state.splineInterpolate.GetDuration() ); - savefile->WriteFloat( state.splineInterpolate.GetDeceleration() ); - savefile->WriteFloat( state.splineInterpolate.GetStartValue() ); - savefile->WriteFloat( state.splineInterpolate.GetEndValue() ); -} - -/* -================ -idPhysics_Parametric_RestorePState -================ -*/ -void idPhysics_Parametric_RestorePState( idRestoreGame *savefile, parametricPState_t &state ) { - extrapolation_t etype; - float startTime, duration, accelTime, decelTime, startValue, endValue; - idVec3 linearStartValue, linearBaseSpeed, linearSpeed, startPos, endPos; - idAngles angularStartValue, angularBaseSpeed, angularSpeed, startAng, endAng; - - savefile->ReadInt( state.time ); - savefile->ReadInt( state.atRest ); - savefile->ReadBool( state.useSplineAngles ); - savefile->ReadVec3( state.origin ); - savefile->ReadAngles( state.angles ); - savefile->ReadMat3( state.axis ); - savefile->ReadVec3( state.localOrigin ); - savefile->ReadAngles( state.localAngles ); - - savefile->ReadInt( (int &)etype ); - savefile->ReadFloat( startTime ); - savefile->ReadFloat( duration ); - savefile->ReadVec3( linearStartValue ); - savefile->ReadVec3( linearBaseSpeed ); - savefile->ReadVec3( linearSpeed ); - - state.linearExtrapolation.Init( startTime, duration, linearStartValue, linearBaseSpeed, linearSpeed, etype ); - - savefile->ReadInt( (int &)etype ); - savefile->ReadFloat( startTime ); - savefile->ReadFloat( duration ); - savefile->ReadAngles( angularStartValue ); - savefile->ReadAngles( angularBaseSpeed ); - savefile->ReadAngles( angularSpeed ); - - state.angularExtrapolation.Init( startTime, duration, angularStartValue, angularBaseSpeed, angularSpeed, etype ); - - savefile->ReadFloat( startTime ); - savefile->ReadFloat( accelTime ); - savefile->ReadFloat( decelTime ); - savefile->ReadFloat( duration ); - savefile->ReadVec3( startPos ); - savefile->ReadVec3( endPos ); - - state.linearInterpolation.Init( startTime, accelTime, decelTime, duration, startPos, endPos ); - - savefile->ReadFloat( startTime ); - savefile->ReadFloat( accelTime ); - savefile->ReadFloat( decelTime ); - savefile->ReadFloat( duration ); - savefile->ReadAngles( startAng ); - savefile->ReadAngles( endAng ); - - state.angularInterpolation.Init( startTime, accelTime, decelTime, duration, startAng, endAng ); - - // spline is handled by owner - - savefile->ReadFloat( startTime ); - savefile->ReadFloat( accelTime ); - savefile->ReadFloat( duration ); - savefile->ReadFloat( decelTime ); - savefile->ReadFloat( startValue ); - savefile->ReadFloat( endValue ); - - state.splineInterpolate.Init( startTime, accelTime, decelTime, duration, startValue, endValue ); -} - -/* -================ -idPhysics_Parametric::Save -================ -*/ -void idPhysics_Parametric::Save( idSaveGame *savefile ) const { - - idPhysics_Parametric_SavePState( savefile, current ); - idPhysics_Parametric_SavePState( savefile, saved ); - - savefile->WriteBool( isPusher ); - savefile->WriteClipModel( clipModel ); - savefile->WriteInt( pushFlags ); - - savefile->WriteTrace( pushResults ); - savefile->WriteBool( isBlocked ); - - savefile->WriteBool( hasMaster ); - savefile->WriteBool( isOrientated ); -} - -/* -================ -idPhysics_Parametric::Restore -================ -*/ -void idPhysics_Parametric::Restore( idRestoreGame *savefile ) { - - idPhysics_Parametric_RestorePState( savefile, current ); - idPhysics_Parametric_RestorePState( savefile, saved ); - - savefile->ReadBool( isPusher ); - savefile->ReadClipModel( clipModel ); - savefile->ReadInt( pushFlags ); - - savefile->ReadTrace( pushResults ); - savefile->ReadBool( isBlocked ); - - savefile->ReadBool( hasMaster ); - savefile->ReadBool( isOrientated ); -} - -/* -================ -idPhysics_Parametric::SetPusher -================ -*/ -void idPhysics_Parametric::SetPusher( int flags ) { - assert( clipModel ); - isPusher = true; - pushFlags = flags; -} - -/* -================ -idPhysics_Parametric::IsPusher -================ -*/ -bool idPhysics_Parametric::IsPusher( void ) const { - return isPusher; -} - -/* -================ -idPhysics_Parametric::SetLinearExtrapolation -================ -*/ -void idPhysics_Parametric::SetLinearExtrapolation( extrapolation_t type, int time, int duration, const idVec3 &base, const idVec3 &speed, const idVec3 &baseSpeed ) { - current.time = gameLocal.time; - current.linearExtrapolation.Init( time, duration, base, baseSpeed, speed, type ); - current.localOrigin = base; - Activate(); -} - -/* -================ -idPhysics_Parametric::SetAngularExtrapolation -================ -*/ -void idPhysics_Parametric::SetAngularExtrapolation( extrapolation_t type, int time, int duration, const idAngles &base, const idAngles &speed, const idAngles &baseSpeed ) { - current.time = gameLocal.time; - current.angularExtrapolation.Init( time, duration, base, baseSpeed, speed, type ); - current.localAngles = base; - Activate(); -} - -/* -================ -idPhysics_Parametric::GetLinearExtrapolationType -================ -*/ -extrapolation_t idPhysics_Parametric::GetLinearExtrapolationType( void ) const { - return current.linearExtrapolation.GetExtrapolationType(); -} - -/* -================ -idPhysics_Parametric::GetAngularExtrapolationType -================ -*/ -extrapolation_t idPhysics_Parametric::GetAngularExtrapolationType( void ) const { - return current.angularExtrapolation.GetExtrapolationType(); -} - -/* -================ -idPhysics_Parametric::SetLinearInterpolation -================ -*/ -void idPhysics_Parametric::SetLinearInterpolation( int time, int accelTime, int decelTime, int duration, const idVec3 &startPos, const idVec3 &endPos ) { - current.time = gameLocal.time; - current.linearInterpolation.Init( time, accelTime, decelTime, duration, startPos, endPos ); - current.localOrigin = startPos; - Activate(); -} - -/* -================ -idPhysics_Parametric::SetAngularInterpolation -================ -*/ -void idPhysics_Parametric::SetAngularInterpolation( int time, int accelTime, int decelTime, int duration, const idAngles &startAng, const idAngles &endAng ) { - current.time = gameLocal.time; - current.angularInterpolation.Init( time, accelTime, decelTime, duration, startAng, endAng ); - current.localAngles = startAng; - Activate(); -} - -/* -================ -idPhysics_Parametric::SetSpline -================ -*/ -void idPhysics_Parametric::SetSpline( idCurve_Spline *spline, int accelTime, int decelTime, bool useSplineAngles ) { - if ( current.spline != NULL ) { - delete current.spline; - current.spline = NULL; - } - current.spline = spline; - if ( current.spline != NULL ) { - float startTime = current.spline->GetTime( 0 ); - float endTime = current.spline->GetTime( current.spline->GetNumValues() - 1 ); - float length = current.spline->GetLengthForTime( endTime ); - current.splineInterpolate.Init( startTime, accelTime, decelTime, endTime - startTime, 0.0f, length ); - } - current.useSplineAngles = useSplineAngles; - Activate(); -} - -/* -================ -idPhysics_Parametric::GetSpline -================ -*/ -idCurve_Spline *idPhysics_Parametric::GetSpline( void ) const { - return current.spline; -} - -/* -================ -idPhysics_Parametric::GetSplineAcceleration -================ -*/ -int idPhysics_Parametric::GetSplineAcceleration( void ) const { - return current.splineInterpolate.GetAcceleration(); -} - -/* -================ -idPhysics_Parametric::GetSplineDeceleration -================ -*/ -int idPhysics_Parametric::GetSplineDeceleration( void ) const { - return current.splineInterpolate.GetDeceleration(); -} - -/* -================ -idPhysics_Parametric::UsingSplineAngles -================ -*/ -bool idPhysics_Parametric::UsingSplineAngles( void ) const { - return current.useSplineAngles; -} - -/* -================ -idPhysics_Parametric::GetLocalOrigin -================ -*/ -void idPhysics_Parametric::GetLocalOrigin( idVec3 &curOrigin ) const { - curOrigin = current.localOrigin; -} - -/* -================ -idPhysics_Parametric::GetLocalAngles -================ -*/ -void idPhysics_Parametric::GetLocalAngles( idAngles &curAngles ) const { - curAngles = current.localAngles; -} - -/* -================ -idPhysics_Parametric::SetClipModel -================ -*/ -void idPhysics_Parametric::SetClipModel( idClipModel *model, float density, int id, bool freeOld ) { - - assert( self ); - assert( model ); - - if ( clipModel && clipModel != model && freeOld ) { - delete clipModel; - } - clipModel = model; - clipModel->Link( gameLocal.clip, self, 0, current.origin, current.axis ); -} - -/* -================ -idPhysics_Parametric::GetClipModel -================ -*/ -idClipModel *idPhysics_Parametric::GetClipModel( int id ) const { - return clipModel; -} - -/* -================ -idPhysics_Parametric::GetNumClipModels -================ -*/ -int idPhysics_Parametric::GetNumClipModels( void ) const { - return ( clipModel != NULL ); -} - -/* -================ -idPhysics_Parametric::SetMass -================ -*/ -void idPhysics_Parametric::SetMass( float mass, int id ) { -} - -/* -================ -idPhysics_Parametric::GetMass -================ -*/ -float idPhysics_Parametric::GetMass( int id ) const { - return 0.0f; -} - -/* -================ -idPhysics_Parametric::SetClipMask -================ -*/ -void idPhysics_Parametric::SetContents( int contents, int id ) { - if ( clipModel ) { - clipModel->SetContents( contents ); - } -} - -/* -================ -idPhysics_Parametric::SetClipMask -================ -*/ -int idPhysics_Parametric::GetContents( int id ) const { - if ( clipModel ) { - return clipModel->GetContents(); - } - return 0; -} - -/* -================ -idPhysics_Parametric::GetBounds -================ -*/ -const idBounds &idPhysics_Parametric::GetBounds( int id ) const { - if ( clipModel ) { - return clipModel->GetBounds(); - } - return idPhysics_Base::GetBounds(); -} - -/* -================ -idPhysics_Parametric::GetAbsBounds -================ -*/ -const idBounds &idPhysics_Parametric::GetAbsBounds( int id ) const { - if ( clipModel ) { - return clipModel->GetAbsBounds(); - } - return idPhysics_Base::GetAbsBounds(); -} - -/* -================ -idPhysics_Parametric::Evaluate -================ -*/ -bool idPhysics_Parametric::Evaluate( int timeStepMSec, int endTimeMSec ) { - idVec3 oldLocalOrigin, oldOrigin, masterOrigin; - idAngles oldLocalAngles, oldAngles; - idMat3 oldAxis, masterAxis; - - isBlocked = false; - oldLocalOrigin = current.localOrigin; - oldOrigin = current.origin; - oldLocalAngles = current.localAngles; - oldAngles = current.angles; - oldAxis = current.axis; - - current.localOrigin.Zero(); - current.localAngles.Zero(); - - if ( current.spline != NULL ) { - float length = current.splineInterpolate.GetCurrentValue( endTimeMSec ); - float t = current.spline->GetTimeForLength( length, 0.01f ); - current.localOrigin = current.spline->GetCurrentValue( t ); - if ( current.useSplineAngles ) { - current.localAngles = current.spline->GetCurrentFirstDerivative( t ).ToAngles(); - } - } else if ( current.linearInterpolation.GetDuration() != 0 ) { - current.localOrigin += current.linearInterpolation.GetCurrentValue( endTimeMSec ); - } else { - current.localOrigin += current.linearExtrapolation.GetCurrentValue( endTimeMSec ); - } - - if ( current.angularInterpolation.GetDuration() != 0 ) { - current.localAngles += current.angularInterpolation.GetCurrentValue( endTimeMSec ); - } else { - current.localAngles += current.angularExtrapolation.GetCurrentValue( endTimeMSec ); - } - - current.localAngles.Normalize360(); - current.origin = current.localOrigin; - current.angles = current.localAngles; - current.axis = current.localAngles.ToMat3(); - - if ( hasMaster ) { - self->GetMasterPosition( masterOrigin, masterAxis ); - if ( masterAxis.IsRotated() ) { - current.origin = current.origin * masterAxis + masterOrigin; - if ( isOrientated ) { - current.axis *= masterAxis; - current.angles = current.axis.ToAngles(); - } - } - else { - current.origin += masterOrigin; - } - } - - if ( isPusher ) { - - gameLocal.push.ClipPush( pushResults, self, pushFlags, oldOrigin, oldAxis, current.origin, current.axis ); - if ( pushResults.fraction < 1.0f ) { - clipModel->Link( gameLocal.clip, self, 0, oldOrigin, oldAxis ); - current.localOrigin = oldLocalOrigin; - current.origin = oldOrigin; - current.localAngles = oldLocalAngles; - current.angles = oldAngles; - current.axis = oldAxis; - isBlocked = true; - return false; - } - - current.angles = current.axis.ToAngles(); - } - - if ( clipModel ) { - clipModel->Link( gameLocal.clip, self, 0, current.origin, current.axis ); - } - - current.time = endTimeMSec; - - if ( TestIfAtRest() ) { - Rest(); - } - - return ( current.origin != oldOrigin || current.axis != oldAxis ); -} - -/* -================ -idPhysics_Parametric::UpdateTime -================ -*/ -void idPhysics_Parametric::UpdateTime( int endTimeMSec ) { - int timeLeap = endTimeMSec - current.time; - - current.time = endTimeMSec; - // move the trajectory start times to sync the trajectory with the current endTime - current.linearExtrapolation.SetStartTime( current.linearExtrapolation.GetStartTime() + timeLeap ); - current.angularExtrapolation.SetStartTime( current.angularExtrapolation.GetStartTime() + timeLeap ); - current.linearInterpolation.SetStartTime( current.linearInterpolation.GetStartTime() + timeLeap ); - current.angularInterpolation.SetStartTime( current.angularInterpolation.GetStartTime() + timeLeap ); - if ( current.spline != NULL ) { - current.spline->ShiftTime( timeLeap ); - current.splineInterpolate.SetStartTime( current.splineInterpolate.GetStartTime() + timeLeap ); - } -} - -/* -================ -idPhysics_Parametric::GetTime -================ -*/ -int idPhysics_Parametric::GetTime( void ) const { - return current.time; -} - -/* -================ -idPhysics_Parametric::IsAtRest -================ -*/ -bool idPhysics_Parametric::IsAtRest( void ) const { - return current.atRest >= 0; -} - -/* -================ -idPhysics_Parametric::GetRestStartTime -================ -*/ -int idPhysics_Parametric::GetRestStartTime( void ) const { - return current.atRest; -} - -/* -================ -idPhysics_Parametric::IsPushable -================ -*/ -bool idPhysics_Parametric::IsPushable( void ) const { - return false; -} - -/* -================ -idPhysics_Parametric::SaveState -================ -*/ -void idPhysics_Parametric::SaveState( void ) { - saved = current; -} - -/* -================ -idPhysics_Parametric::RestoreState -================ -*/ -void idPhysics_Parametric::RestoreState( void ) { - - current = saved; - - if ( clipModel ) { - clipModel->Link( gameLocal.clip, self, 0, current.origin, current.axis ); - } -} - -/* -================ -idPhysics_Parametric::SetOrigin -================ -*/ -void idPhysics_Parametric::SetOrigin( const idVec3 &newOrigin, int id ) { - idVec3 masterOrigin; - idMat3 masterAxis; - - current.linearExtrapolation.SetStartValue( newOrigin ); - current.linearInterpolation.SetStartValue( newOrigin ); - - current.localOrigin = current.linearExtrapolation.GetCurrentValue( current.time ); - if ( hasMaster ) { - self->GetMasterPosition( masterOrigin, masterAxis ); - current.origin = masterOrigin + current.localOrigin * masterAxis; - } - else { - current.origin = current.localOrigin; - } - if ( clipModel ) { - clipModel->Link( gameLocal.clip, self, 0, current.origin, current.axis ); - } - Activate(); -} - -/* -================ -idPhysics_Parametric::SetAxis -================ -*/ -void idPhysics_Parametric::SetAxis( const idMat3 &newAxis, int id ) { - idVec3 masterOrigin; - idMat3 masterAxis; - - current.localAngles = newAxis.ToAngles(); - - current.angularExtrapolation.SetStartValue( current.localAngles ); - current.angularInterpolation.SetStartValue( current.localAngles ); - - current.localAngles = current.angularExtrapolation.GetCurrentValue( current.time ); - if ( hasMaster && isOrientated ) { - self->GetMasterPosition( masterOrigin, masterAxis ); - current.axis = current.localAngles.ToMat3() * masterAxis; - current.angles = current.axis.ToAngles(); - } - else { - current.axis = current.localAngles.ToMat3(); - current.angles = current.localAngles; - } - if ( clipModel ) { - clipModel->Link( gameLocal.clip, self, 0, current.origin, current.axis ); - } - Activate(); -} - -/* -================ -idPhysics_Parametric::Move -================ -*/ -void idPhysics_Parametric::Translate( const idVec3 &translation, int id ) { -} - -/* -================ -idPhysics_Parametric::Rotate -================ -*/ -void idPhysics_Parametric::Rotate( const idRotation &rotation, int id ) { -} - -/* -================ -idPhysics_Parametric::GetOrigin -================ -*/ -const idVec3 &idPhysics_Parametric::GetOrigin( int id ) const { - return current.origin; -} - -/* -================ -idPhysics_Parametric::GetAxis -================ -*/ -const idMat3 &idPhysics_Parametric::GetAxis( int id ) const { - return current.axis; -} - -/* -================ -idPhysics_Parametric::GetAngles -================ -*/ -void idPhysics_Parametric::GetAngles( idAngles &curAngles ) const { - curAngles = current.angles; -} - -/* -================ -idPhysics_Parametric::SetLinearVelocity -================ -*/ -void idPhysics_Parametric::SetLinearVelocity( const idVec3 &newLinearVelocity, int id ) { - SetLinearExtrapolation( extrapolation_t(EXTRAPOLATION_LINEAR|EXTRAPOLATION_NOSTOP), gameLocal.time, 0, current.origin, newLinearVelocity, vec3_origin ); - current.linearInterpolation.Init( 0, 0, 0, 0, vec3_zero, vec3_zero ); - Activate(); -} - -/* -================ -idPhysics_Parametric::SetAngularVelocity -================ -*/ -void idPhysics_Parametric::SetAngularVelocity( const idVec3 &newAngularVelocity, int id ) { - idRotation rotation; - idVec3 vec; - float angle; - - vec = newAngularVelocity; - angle = vec.Normalize(); - rotation.Set( vec3_origin, vec, (float) RAD2DEG( angle ) ); - - SetAngularExtrapolation( extrapolation_t(EXTRAPOLATION_LINEAR|EXTRAPOLATION_NOSTOP), gameLocal.time, 0, current.angles, rotation.ToAngles(), ang_zero ); - current.angularInterpolation.Init( 0, 0, 0, 0, ang_zero, ang_zero ); - Activate(); -} - -/* -================ -idPhysics_Parametric::GetLinearVelocity -================ -*/ -const idVec3 &idPhysics_Parametric::GetLinearVelocity( int id ) const { - static idVec3 curLinearVelocity; - - curLinearVelocity = current.linearExtrapolation.GetCurrentSpeed( gameLocal.time ); - return curLinearVelocity; -} - -/* -================ -idPhysics_Parametric::GetAngularVelocity -================ -*/ -const idVec3 &idPhysics_Parametric::GetAngularVelocity( int id ) const { - static idVec3 curAngularVelocity; - idAngles angles; - - angles = current.angularExtrapolation.GetCurrentSpeed( gameLocal.time ); - curAngularVelocity = angles.ToAngularVelocity(); - return curAngularVelocity; -} - -/* -================ -idPhysics_Parametric::DisableClip -================ -*/ -void idPhysics_Parametric::DisableClip( void ) { - if ( clipModel ) { - clipModel->Disable(); - } -} - -/* -================ -idPhysics_Parametric::EnableClip -================ -*/ -void idPhysics_Parametric::EnableClip( void ) { - if ( clipModel ) { - clipModel->Enable(); - } -} - -/* -================ -idPhysics_Parametric::UnlinkClip -================ -*/ -void idPhysics_Parametric::UnlinkClip( void ) { - if ( clipModel ) { - clipModel->Unlink(); - } -} - -/* -================ -idPhysics_Parametric::LinkClip -================ -*/ -void idPhysics_Parametric::LinkClip( void ) { - if ( clipModel ) { - clipModel->Link( gameLocal.clip, self, 0, current.origin, current.axis ); - } -} - -/* -================ -idPhysics_Parametric::GetBlockingInfo -================ -*/ -const trace_t *idPhysics_Parametric::GetBlockingInfo( void ) const { - return ( isBlocked ? &pushResults : NULL ); -} - -/* -================ -idPhysics_Parametric::GetBlockingEntity -================ -*/ -idEntity *idPhysics_Parametric::GetBlockingEntity( void ) const { - if ( isBlocked ) { - return gameLocal.entities[ pushResults.c.entityNum ]; - } - return NULL; -} - -/* -================ -idPhysics_Parametric::SetMaster -================ -*/ -void idPhysics_Parametric::SetMaster( idEntity *master, const bool orientated ) { - idVec3 masterOrigin; - idMat3 masterAxis; - - if ( master ) { - if ( !hasMaster ) { - - // transform from world space to master space - self->GetMasterPosition( masterOrigin, masterAxis ); - current.localOrigin = ( current.origin - masterOrigin ) * masterAxis.Transpose(); - if ( orientated ) { - current.localAngles = ( current.axis * masterAxis.Transpose() ).ToAngles(); - } - else { - current.localAngles = current.axis.ToAngles(); - } - - current.linearExtrapolation.SetStartValue( current.localOrigin ); - current.angularExtrapolation.SetStartValue( current.localAngles ); - hasMaster = true; - isOrientated = orientated; - } - } - else { - if ( hasMaster ) { - // transform from master space to world space - current.localOrigin = current.origin; - current.localAngles = current.angles; - SetLinearExtrapolation( EXTRAPOLATION_NONE, 0, 0, current.origin, vec3_origin, vec3_origin ); - SetAngularExtrapolation( EXTRAPOLATION_NONE, 0, 0, current.angles, ang_zero, ang_zero ); - hasMaster = false; - } - } -} - -/* -================ -idPhysics_Parametric::GetLinearEndTime -================ -*/ -int idPhysics_Parametric::GetLinearEndTime( void ) const { - if ( current.spline != NULL ) { - if ( current.spline->GetBoundaryType() != idCurve_Spline::BT_CLOSED ) { - return current.spline->GetTime( current.spline->GetNumValues() - 1 ); - } else { - return 0; - } - } else if ( current.linearInterpolation.GetDuration() != 0 ) { - return current.linearInterpolation.GetEndTime(); - } else { - return current.linearExtrapolation.GetEndTime(); - } -} - -/* -================ -idPhysics_Parametric::GetAngularEndTime -================ -*/ -int idPhysics_Parametric::GetAngularEndTime( void ) const { - if ( current.angularInterpolation.GetDuration() != 0 ) { - return current.angularInterpolation.GetEndTime(); - } else { - return current.angularExtrapolation.GetEndTime(); - } -} - -/* -================ -idPhysics_Parametric::WriteToSnapshot -================ -*/ -void idPhysics_Parametric::WriteToSnapshot( idBitMsgDelta &msg ) const { - msg.WriteInt( current.time ); - msg.WriteInt( current.atRest ); - msg.WriteFloat( current.origin[0] ); - msg.WriteFloat( current.origin[1] ); - msg.WriteFloat( current.origin[2] ); - msg.WriteFloat( current.angles[0] ); - msg.WriteFloat( current.angles[1] ); - msg.WriteFloat( current.angles[2] ); - msg.WriteDeltaFloat( current.origin[0], current.localOrigin[0] ); - msg.WriteDeltaFloat( current.origin[1], current.localOrigin[1] ); - msg.WriteDeltaFloat( current.origin[2], current.localOrigin[2] ); - msg.WriteDeltaFloat( current.angles[0], current.localAngles[0] ); - msg.WriteDeltaFloat( current.angles[1], current.localAngles[1] ); - msg.WriteDeltaFloat( current.angles[2], current.localAngles[2] ); - - msg.WriteBits( current.linearExtrapolation.GetExtrapolationType(), 8 ); - msg.WriteDeltaFloat( 0.0f, current.linearExtrapolation.GetStartTime() ); - msg.WriteDeltaFloat( 0.0f, current.linearExtrapolation.GetDuration() ); - msg.WriteDeltaFloat( 0.0f, current.linearExtrapolation.GetStartValue()[0] ); - msg.WriteDeltaFloat( 0.0f, current.linearExtrapolation.GetStartValue()[1] ); - msg.WriteDeltaFloat( 0.0f, current.linearExtrapolation.GetStartValue()[2] ); - msg.WriteDeltaFloat( 0.0f, current.linearExtrapolation.GetSpeed()[0] ); - msg.WriteDeltaFloat( 0.0f, current.linearExtrapolation.GetSpeed()[1] ); - msg.WriteDeltaFloat( 0.0f, current.linearExtrapolation.GetSpeed()[2] ); - msg.WriteDeltaFloat( 0.0f, current.linearExtrapolation.GetBaseSpeed()[0] ); - msg.WriteDeltaFloat( 0.0f, current.linearExtrapolation.GetBaseSpeed()[1] ); - msg.WriteDeltaFloat( 0.0f, current.linearExtrapolation.GetBaseSpeed()[2] ); - - msg.WriteBits( current.angularExtrapolation.GetExtrapolationType(), 8 ); - msg.WriteDeltaFloat( 0.0f, current.angularExtrapolation.GetStartTime() ); - msg.WriteDeltaFloat( 0.0f, current.angularExtrapolation.GetDuration() ); - msg.WriteDeltaFloat( 0.0f, current.angularExtrapolation.GetStartValue()[0] ); - msg.WriteDeltaFloat( 0.0f, current.angularExtrapolation.GetStartValue()[1] ); - msg.WriteDeltaFloat( 0.0f, current.angularExtrapolation.GetStartValue()[2] ); - msg.WriteDeltaFloat( 0.0f, current.angularExtrapolation.GetSpeed()[0] ); - msg.WriteDeltaFloat( 0.0f, current.angularExtrapolation.GetSpeed()[1] ); - msg.WriteDeltaFloat( 0.0f, current.angularExtrapolation.GetSpeed()[2] ); - msg.WriteDeltaFloat( 0.0f, current.angularExtrapolation.GetBaseSpeed()[0] ); - msg.WriteDeltaFloat( 0.0f, current.angularExtrapolation.GetBaseSpeed()[1] ); - msg.WriteDeltaFloat( 0.0f, current.angularExtrapolation.GetBaseSpeed()[2] ); - - msg.WriteDeltaFloat( 0.0f, current.linearInterpolation.GetStartTime() ); - msg.WriteDeltaFloat( 0.0f, current.linearInterpolation.GetAcceleration() ); - msg.WriteDeltaFloat( 0.0f, current.linearInterpolation.GetDeceleration() ); - msg.WriteDeltaFloat( 0.0f, current.linearInterpolation.GetDuration() ); - msg.WriteDeltaFloat( 0.0f, current.linearInterpolation.GetStartValue()[0] ); - msg.WriteDeltaFloat( 0.0f, current.linearInterpolation.GetStartValue()[1] ); - msg.WriteDeltaFloat( 0.0f, current.linearInterpolation.GetStartValue()[2] ); - msg.WriteDeltaFloat( 0.0f, current.linearInterpolation.GetEndValue()[0] ); - msg.WriteDeltaFloat( 0.0f, current.linearInterpolation.GetEndValue()[1] ); - msg.WriteDeltaFloat( 0.0f, current.linearInterpolation.GetEndValue()[2] ); - - msg.WriteDeltaFloat( 0.0f, current.angularInterpolation.GetStartTime() ); - msg.WriteDeltaFloat( 0.0f, current.angularInterpolation.GetAcceleration() ); - msg.WriteDeltaFloat( 0.0f, current.angularInterpolation.GetDeceleration() ); - msg.WriteDeltaFloat( 0.0f, current.angularInterpolation.GetDuration() ); - msg.WriteDeltaFloat( 0.0f, current.angularInterpolation.GetStartValue()[0] ); - msg.WriteDeltaFloat( 0.0f, current.angularInterpolation.GetStartValue()[1] ); - msg.WriteDeltaFloat( 0.0f, current.angularInterpolation.GetStartValue()[2] ); - msg.WriteDeltaFloat( 0.0f, current.angularInterpolation.GetEndValue()[0] ); - msg.WriteDeltaFloat( 0.0f, current.angularInterpolation.GetEndValue()[1] ); - msg.WriteDeltaFloat( 0.0f, current.angularInterpolation.GetEndValue()[2] ); -} - -/* -================ -idPhysics_Parametric::ReadFromSnapshot -================ -*/ -void idPhysics_Parametric::ReadFromSnapshot( const idBitMsgDelta &msg ) { - extrapolation_t linearType, angularType; - float startTime, duration, accelTime, decelTime; - idVec3 linearStartValue, linearSpeed, linearBaseSpeed, startPos, endPos; - idAngles angularStartValue, angularSpeed, angularBaseSpeed, startAng, endAng; - - current.time = msg.ReadInt(); - current.atRest = msg.ReadInt(); - current.origin[0] = msg.ReadFloat(); - current.origin[1] = msg.ReadFloat(); - current.origin[2] = msg.ReadFloat(); - current.angles[0] = msg.ReadFloat(); - current.angles[1] = msg.ReadFloat(); - current.angles[2] = msg.ReadFloat(); - current.localOrigin[0] = msg.ReadDeltaFloat( current.origin[0] ); - current.localOrigin[1] = msg.ReadDeltaFloat( current.origin[1] ); - current.localOrigin[2] = msg.ReadDeltaFloat( current.origin[2] ); - current.localAngles[0] = msg.ReadDeltaFloat( current.angles[0] ); - current.localAngles[1] = msg.ReadDeltaFloat( current.angles[1] ); - current.localAngles[2] = msg.ReadDeltaFloat( current.angles[2] ); - - linearType = (extrapolation_t) msg.ReadBits( 8 ); - startTime = msg.ReadDeltaFloat( 0.0f ); - duration = msg.ReadDeltaFloat( 0.0f ); - linearStartValue[0] = msg.ReadDeltaFloat( 0.0f ); - linearStartValue[1] = msg.ReadDeltaFloat( 0.0f ); - linearStartValue[2] = msg.ReadDeltaFloat( 0.0f ); - linearSpeed[0] = msg.ReadDeltaFloat( 0.0f ); - linearSpeed[1] = msg.ReadDeltaFloat( 0.0f ); - linearSpeed[2] = msg.ReadDeltaFloat( 0.0f ); - linearBaseSpeed[0] = msg.ReadDeltaFloat( 0.0f ); - linearBaseSpeed[1] = msg.ReadDeltaFloat( 0.0f ); - linearBaseSpeed[2] = msg.ReadDeltaFloat( 0.0f ); - current.linearExtrapolation.Init( startTime, duration, linearStartValue, linearBaseSpeed, linearSpeed, linearType ); - - angularType = (extrapolation_t) msg.ReadBits( 8 ); - startTime = msg.ReadDeltaFloat( 0.0f ); - duration = msg.ReadDeltaFloat( 0.0f ); - angularStartValue[0] = msg.ReadDeltaFloat( 0.0f ); - angularStartValue[1] = msg.ReadDeltaFloat( 0.0f ); - angularStartValue[2] = msg.ReadDeltaFloat( 0.0f ); - angularSpeed[0] = msg.ReadDeltaFloat( 0.0f ); - angularSpeed[1] = msg.ReadDeltaFloat( 0.0f ); - angularSpeed[2] = msg.ReadDeltaFloat( 0.0f ); - angularBaseSpeed[0] = msg.ReadDeltaFloat( 0.0f ); - angularBaseSpeed[1] = msg.ReadDeltaFloat( 0.0f ); - angularBaseSpeed[2] = msg.ReadDeltaFloat( 0.0f ); - current.angularExtrapolation.Init( startTime, duration, angularStartValue, angularBaseSpeed, angularSpeed, angularType ); - - startTime = msg.ReadDeltaFloat( 0.0f ); - accelTime = msg.ReadDeltaFloat( 0.0f ); - decelTime = msg.ReadDeltaFloat( 0.0f ); - duration = msg.ReadDeltaFloat( 0.0f ); - startPos[0] = msg.ReadDeltaFloat( 0.0f ); - startPos[1] = msg.ReadDeltaFloat( 0.0f ); - startPos[2] = msg.ReadDeltaFloat( 0.0f ); - endPos[0] = msg.ReadDeltaFloat( 0.0f ); - endPos[1] = msg.ReadDeltaFloat( 0.0f ); - endPos[2] = msg.ReadDeltaFloat( 0.0f ); - current.linearInterpolation.Init( startTime, accelTime, decelTime, duration, startPos, endPos ); - - startTime = msg.ReadDeltaFloat( 0.0f ); - accelTime = msg.ReadDeltaFloat( 0.0f ); - decelTime = msg.ReadDeltaFloat( 0.0f ); - duration = msg.ReadDeltaFloat( 0.0f ); - startAng[0] = msg.ReadDeltaFloat( 0.0f ); - startAng[1] = msg.ReadDeltaFloat( 0.0f ); - startAng[2] = msg.ReadDeltaFloat( 0.0f ); - endAng[0] = msg.ReadDeltaFloat( 0.0f ); - endAng[1] = msg.ReadDeltaFloat( 0.0f ); - endAng[2] = msg.ReadDeltaFloat( 0.0f ); - current.angularInterpolation.Init( startTime, accelTime, decelTime, duration, startAng, endAng ); - - current.axis = current.angles.ToMat3(); - - if ( clipModel ) { - clipModel->Link( gameLocal.clip, self, 0, current.origin, current.axis ); - } -} diff --git a/d3xp/physics/Physics_Parametric.h b/d3xp/physics/Physics_Parametric.h deleted file mode 100644 index ad4745b1..00000000 --- a/d3xp/physics/Physics_Parametric.h +++ /dev/null @@ -1,181 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __PHYSICS_PARAMETRIC_H__ -#define __PHYSICS_PARAMETRIC_H__ - -#include "idlib/math/Curve.h" -#include "idlib/math/Interpolate.h" - -#include "physics/Physics_Base.h" - -/* -=================================================================================== - - Parametric physics - - Used for predefined or scripted motion. The motion of an object is completely - parametrized. By adjusting the parameters an object is forced to follow a - predefined path. The parametric physics is typically used for doors, bridges, - rotating fans etc. - -=================================================================================== -*/ - -typedef struct parametricPState_s { - int time; // physics time - int atRest; // set when simulation is suspended - idVec3 origin; // world origin - idAngles angles; // world angles - idMat3 axis; // world axis - idVec3 localOrigin; // local origin - idAngles localAngles; // local angles - idExtrapolate linearExtrapolation; // extrapolation based description of the position over time - idExtrapolate angularExtrapolation; // extrapolation based description of the orientation over time - idInterpolateAccelDecelLinear linearInterpolation; // interpolation based description of the position over time - idInterpolateAccelDecelLinear angularInterpolation; // interpolation based description of the orientation over time - idCurve_Spline * spline; // spline based description of the position over time - idInterpolateAccelDecelLinear splineInterpolate; // position along the spline over time - bool useSplineAngles; // set the orientation using the spline -} parametricPState_t; - -class idPhysics_Parametric : public idPhysics_Base { - -public: - CLASS_PROTOTYPE( idPhysics_Parametric ); - - idPhysics_Parametric( void ); - ~idPhysics_Parametric( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void SetPusher( int flags ); - bool IsPusher( void ) const; - - void SetLinearExtrapolation( extrapolation_t type, int time, int duration, const idVec3 &base, const idVec3 &speed, const idVec3 &baseSpeed ); - void SetAngularExtrapolation( extrapolation_t type, int time, int duration, const idAngles &base, const idAngles &speed, const idAngles &baseSpeed ); - extrapolation_t GetLinearExtrapolationType( void ) const; - extrapolation_t GetAngularExtrapolationType( void ) const; - - void SetLinearInterpolation( int time, int accelTime, int decelTime, int duration, const idVec3 &startPos, const idVec3 &endPos ); - void SetAngularInterpolation( int time, int accelTime, int decelTime, int duration, const idAngles &startAng, const idAngles &endAng ); - - void SetSpline( idCurve_Spline *spline, int accelTime, int decelTime, bool useSplineAngles ); - idCurve_Spline *GetSpline( void ) const; - int GetSplineAcceleration( void ) const; - int GetSplineDeceleration( void ) const; - bool UsingSplineAngles( void ) const; - - void GetLocalOrigin( idVec3 &curOrigin ) const; - void GetLocalAngles( idAngles &curAngles ) const; - - void GetAngles( idAngles &curAngles ) const; - -public: // common physics interface - void SetClipModel( idClipModel *model, float density, int id = 0, bool freeOld = true ); - idClipModel * GetClipModel( int id = 0 ) const; - int GetNumClipModels( void ) const; - - void SetMass( float mass, int id = -1 ); - float GetMass( int id = -1 ) const; - - void SetContents( int contents, int id = -1 ); - int GetContents( int id = -1 ) const; - - const idBounds & GetBounds( int id = -1 ) const; - const idBounds & GetAbsBounds( int id = -1 ) const; - - bool Evaluate( int timeStepMSec, int endTimeMSec ); - void UpdateTime( int endTimeMSec ); - int GetTime( void ) const; - - void Activate( void ); - bool IsAtRest( void ) const; - int GetRestStartTime( void ) const; - bool IsPushable( void ) const; - - void SaveState( void ); - void RestoreState( void ); - - void SetOrigin( const idVec3 &newOrigin, int id = -1 ); - void SetAxis( const idMat3 &newAxis, int id = -1 ); - - void Translate( const idVec3 &translation, int id = -1 ); - void Rotate( const idRotation &rotation, int id = -1 ); - - const idVec3 & GetOrigin( int id = 0 ) const; - const idMat3 & GetAxis( int id = 0 ) const; - - void SetLinearVelocity( const idVec3 &newLinearVelocity, int id = 0 ); - void SetAngularVelocity( const idVec3 &newAngularVelocity, int id = 0 ); - - const idVec3 & GetLinearVelocity( int id = 0 ) const; - const idVec3 & GetAngularVelocity( int id = 0 ) const; - - void DisableClip( void ); - void EnableClip( void ); - - void UnlinkClip( void ); - void LinkClip( void ); - - void SetMaster( idEntity *master, const bool orientated = true ); - - const trace_t * GetBlockingInfo( void ) const; - idEntity * GetBlockingEntity( void ) const; - - int GetLinearEndTime( void ) const; - int GetAngularEndTime( void ) const; - - void WriteToSnapshot( idBitMsgDelta &msg ) const; - void ReadFromSnapshot( const idBitMsgDelta &msg ); - -private: - // parametric physics state - parametricPState_t current; - parametricPState_t saved; - - // pusher - bool isPusher; - idClipModel * clipModel; - int pushFlags; - - // results of last evaluate - trace_t pushResults; - bool isBlocked; - - // master - bool hasMaster; - bool isOrientated; - -private: - bool TestIfAtRest( void ) const; - void Rest( void ); -}; - -#endif /* !__PHYSICS_PARAMETRIC_H__ */ diff --git a/d3xp/physics/Physics_Player.cpp b/d3xp/physics/Physics_Player.cpp deleted file mode 100644 index 82ac8121..00000000 --- a/d3xp/physics/Physics_Player.cpp +++ /dev/null @@ -1,2058 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "gamesys/SysCvar.h" -#include "Entity.h" - -#include "physics/Physics_Player.h" - -CLASS_DECLARATION( idPhysics_Actor, idPhysics_Player ) -END_CLASS - -// movement parameters -const float PM_STOPSPEED = 100.0f; -const float PM_SWIMSCALE = 0.5f; -const float PM_LADDERSPEED = 100.0f; -const float PM_STEPSCALE = 1.0f; - -const float PM_ACCELERATE = 10.0f; -const float PM_AIRACCELERATE = 1.0f; -const float PM_WATERACCELERATE = 4.0f; -const float PM_FLYACCELERATE = 8.0f; - -const float PM_FRICTION = 6.0f; -const float PM_AIRFRICTION = 0.0f; -const float PM_WATERFRICTION = 1.0f; -const float PM_FLYFRICTION = 3.0f; -const float PM_NOCLIPFRICTION = 12.0f; - -const float MIN_WALK_NORMAL = 0.7f; // can't walk on very steep slopes -const float OVERCLIP = 1.001f; - -// movementFlags -const int PMF_DUCKED = 1; // set when ducking -const int PMF_JUMPED = 2; // set when the player jumped this frame -const int PMF_STEPPED_UP = 4; // set when the player stepped up this frame -const int PMF_STEPPED_DOWN = 8; // set when the player stepped down this frame -const int PMF_JUMP_HELD = 16; // set when jump button is held down -const int PMF_TIME_LAND = 32; // movementTime is time before rejump -const int PMF_TIME_KNOCKBACK = 64; // movementTime is an air-accelerate only time -const int PMF_TIME_WATERJUMP = 128; // movementTime is waterjump -const int PMF_ALL_TIMES = (PMF_TIME_WATERJUMP|PMF_TIME_LAND|PMF_TIME_KNOCKBACK); - -int c_pmove = 0; - -/* -============ -idPhysics_Player::CmdScale - -Returns the scale factor to apply to cmd movements -This allows the clients to use axial -127 to 127 values for all directions -without getting a sqrt(2) distortion in speed. -============ -*/ -float idPhysics_Player::CmdScale( const usercmd_t &cmd ) const { - int max; - float total; - float scale; - int forwardmove; - int rightmove; - int upmove; - - forwardmove = cmd.forwardmove; - rightmove = cmd.rightmove; - - // since the crouch key doubles as downward movement, ignore downward movement when we're on the ground - // otherwise crouch speed will be lower than specified - if ( walking ) { - upmove = 0; - } else { - upmove = cmd.upmove; - } - - max = abs( forwardmove ); - if ( abs( rightmove ) > max ) { - max = abs( rightmove ); - } - if ( abs( upmove ) > max ) { - max = abs( upmove ); - } - - if ( !max ) { - return 0.0f; - } - - total = idMath::Sqrt( (float) forwardmove * forwardmove + rightmove * rightmove + upmove * upmove ); - scale = (float) playerSpeed * max / ( 127.0f * total ); - - return scale; -} - -/* -============== -idPhysics_Player::Accelerate - -Handles user intended acceleration -============== -*/ -void idPhysics_Player::Accelerate( const idVec3 &wishdir, const float wishspeed, const float accel ) { -#if 1 - // q2 style - float addspeed, accelspeed, currentspeed; - - currentspeed = current.velocity * wishdir; - addspeed = wishspeed - currentspeed; - if (addspeed <= 0) { - return; - } - accelspeed = accel * frametime * wishspeed; - if (accelspeed > addspeed) { - accelspeed = addspeed; - } - - current.velocity += accelspeed * wishdir; -#else - // proper way (avoids strafe jump maxspeed bug), but feels bad - idVec3 wishVelocity; - idVec3 pushDir; - float pushLen; - float canPush; - - wishVelocity = wishdir * wishspeed; - pushDir = wishVelocity - current.velocity; - pushLen = pushDir.Normalize(); - - canPush = accel * frametime * wishspeed; - if (canPush > pushLen) { - canPush = pushLen; - } - - current.velocity += canPush * pushDir; -#endif -} - -/* -================== -idPhysics_Player::SlideMove - -Returns true if the velocity was clipped in some way -================== -*/ -#define MAX_CLIP_PLANES 5 - -bool idPhysics_Player::SlideMove( bool gravity, bool stepUp, bool stepDown, bool push ) { - int i, j, k, pushFlags; - int bumpcount, numbumps, numplanes; - float d, time_left, into, totalMass; - idVec3 dir, planes[MAX_CLIP_PLANES]; - idVec3 end, stepEnd, primal_velocity, endVelocity, endClipVelocity, clipVelocity; - trace_t trace, stepTrace, downTrace; - bool nearGround, stepped, pushed; - - numbumps = 4; - - primal_velocity = current.velocity; - - if ( gravity ) { - endVelocity = current.velocity + gravityVector * frametime; - current.velocity = ( current.velocity + endVelocity ) * 0.5f; - primal_velocity = endVelocity; - if ( groundPlane ) { - // slide along the ground plane - current.velocity.ProjectOntoPlane( groundTrace.c.normal, OVERCLIP ); - } - } - else { - endVelocity = current.velocity; - } - - time_left = frametime; - - // never turn against the ground plane - if ( groundPlane ) { - numplanes = 1; - planes[0] = groundTrace.c.normal; - } else { - numplanes = 0; - } - - // never turn against original velocity - planes[numplanes] = current.velocity; - planes[numplanes].Normalize(); - numplanes++; - - for ( bumpcount = 0; bumpcount < numbumps; bumpcount++ ) { - - // calculate position we are trying to move to - end = current.origin + time_left * current.velocity; - - // see if we can make it there - gameLocal.clip.Translation( trace, current.origin, end, clipModel, clipModel->GetAxis(), clipMask, self ); - - time_left -= time_left * trace.fraction; - current.origin = trace.endpos; - - // if moved the entire distance - if ( trace.fraction >= 1.0f ) { - break; - } - - stepped = pushed = false; - - // if we are allowed to step up - if ( stepUp ) { - - nearGround = groundPlane | ladder; - - if ( !nearGround ) { - // trace down to see if the player is near the ground - // step checking when near the ground allows the player to move up stairs smoothly while jumping - stepEnd = current.origin + maxStepHeight * gravityNormal; - gameLocal.clip.Translation( downTrace, current.origin, stepEnd, clipModel, clipModel->GetAxis(), clipMask, self ); - nearGround = ( downTrace.fraction < 1.0f && (downTrace.c.normal * -gravityNormal) > MIN_WALK_NORMAL ); - } - - // may only step up if near the ground or on a ladder - if ( nearGround ) { - - // step up - stepEnd = current.origin - maxStepHeight * gravityNormal; - gameLocal.clip.Translation( downTrace, current.origin, stepEnd, clipModel, clipModel->GetAxis(), clipMask, self ); - - // trace along velocity - stepEnd = downTrace.endpos + time_left * current.velocity; - gameLocal.clip.Translation( stepTrace, downTrace.endpos, stepEnd, clipModel, clipModel->GetAxis(), clipMask, self ); - - // step down - stepEnd = stepTrace.endpos + maxStepHeight * gravityNormal; - gameLocal.clip.Translation( downTrace, stepTrace.endpos, stepEnd, clipModel, clipModel->GetAxis(), clipMask, self ); - - if ( downTrace.fraction >= 1.0f || (downTrace.c.normal * -gravityNormal) > MIN_WALK_NORMAL ) { - - // if moved the entire distance - if ( stepTrace.fraction >= 1.0f ) { - time_left = 0; - current.stepUp -= ( downTrace.endpos - current.origin ) * gravityNormal; - current.origin = downTrace.endpos; - current.movementFlags |= PMF_STEPPED_UP; - current.velocity *= PM_STEPSCALE; - break; - } - - // if the move is further when stepping up - if ( stepTrace.fraction > trace.fraction ) { - time_left -= time_left * stepTrace.fraction; - current.stepUp -= ( downTrace.endpos - current.origin ) * gravityNormal; - current.origin = downTrace.endpos; - current.movementFlags |= PMF_STEPPED_UP; - current.velocity *= PM_STEPSCALE; - trace = stepTrace; - stepped = true; - } - } - } - } - - // if we can push other entities and not blocked by the world - if ( push && trace.c.entityNum != ENTITYNUM_WORLD ) { - - clipModel->SetPosition( current.origin, clipModel->GetAxis() ); - - // clip movement, only push idMoveables, don't push entities the player is standing on - // apply impact to pushed objects - pushFlags = PUSHFL_CLIP|PUSHFL_ONLYMOVEABLE|PUSHFL_NOGROUNDENTITIES|PUSHFL_APPLYIMPULSE; - - // clip & push - totalMass = gameLocal.push.ClipTranslationalPush( trace, self, pushFlags, end, end - current.origin ); - - if ( totalMass > 0.0f ) { - // decrease velocity based on the total mass of the objects being pushed ? - current.velocity *= 1.0f - idMath::ClampFloat( 0.0f, 1000.0f, totalMass - 20.0f ) * ( 1.0f / 950.0f ); - pushed = true; - } - - current.origin = trace.endpos; - time_left -= time_left * trace.fraction; - - // if moved the entire distance - if ( trace.fraction >= 1.0f ) { - break; - } - } - - if ( !stepped ) { - // let the entity know about the collision - self->Collide( trace, current.velocity ); - } - - if ( numplanes >= MAX_CLIP_PLANES ) { - // MrElusive: I think we have some relatively high poly LWO models with a lot of slanted tris - // where it may hit the max clip planes - current.velocity = vec3_origin; - return true; - } - - // - // if this is the same plane we hit before, nudge velocity - // out along it, which fixes some epsilon issues with - // non-axial planes - // - for ( i = 0; i < numplanes; i++ ) { - if ( ( trace.c.normal * planes[i] ) > 0.999f ) { - current.velocity += trace.c.normal; - break; - } - } - if ( i < numplanes ) { - continue; - } - planes[numplanes] = trace.c.normal; - numplanes++; - - // - // modify velocity so it parallels all of the clip planes - // - - // find a plane that it enters - for ( i = 0; i < numplanes; i++ ) { - into = current.velocity * planes[i]; - if ( into >= 0.1f ) { - continue; // move doesn't interact with the plane - } - - // slide along the plane - clipVelocity = current.velocity; - clipVelocity.ProjectOntoPlane( planes[i], OVERCLIP ); - - // slide along the plane - endClipVelocity = endVelocity; - endClipVelocity.ProjectOntoPlane( planes[i], OVERCLIP ); - - // see if there is a second plane that the new move enters - for ( j = 0; j < numplanes; j++ ) { - if ( j == i ) { - continue; - } - if ( ( clipVelocity * planes[j] ) >= 0.1f ) { - continue; // move doesn't interact with the plane - } - - // try clipping the move to the plane - clipVelocity.ProjectOntoPlane( planes[j], OVERCLIP ); - endClipVelocity.ProjectOntoPlane( planes[j], OVERCLIP ); - - // see if it goes back into the first clip plane - if ( ( clipVelocity * planes[i] ) >= 0 ) { - continue; - } - - // slide the original velocity along the crease - dir = planes[i].Cross( planes[j] ); - dir.Normalize(); - d = dir * current.velocity; - clipVelocity = d * dir; - - dir = planes[i].Cross( planes[j] ); - dir.Normalize(); - d = dir * endVelocity; - endClipVelocity = d * dir; - - // see if there is a third plane the the new move enters - for ( k = 0; k < numplanes; k++ ) { - if ( k == i || k == j ) { - continue; - } - if ( ( clipVelocity * planes[k] ) >= 0.1f ) { - continue; // move doesn't interact with the plane - } - - // stop dead at a tripple plane interaction - current.velocity = vec3_origin; - return true; - } - } - - // if we have fixed all interactions, try another move - current.velocity = clipVelocity; - endVelocity = endClipVelocity; - break; - } - } - - // step down - if ( stepDown && groundPlane ) { - stepEnd = current.origin + gravityNormal * maxStepHeight; - gameLocal.clip.Translation( downTrace, current.origin, stepEnd, clipModel, clipModel->GetAxis(), clipMask, self ); - if ( downTrace.fraction > 1e-4f && downTrace.fraction < 1.0f ) { - current.stepUp -= ( downTrace.endpos - current.origin ) * gravityNormal; - current.origin = downTrace.endpos; - current.movementFlags |= PMF_STEPPED_DOWN; - current.velocity *= PM_STEPSCALE; - } - } - - if ( gravity ) { - current.velocity = endVelocity; - } - - // come to a dead stop when the velocity orthogonal to the gravity flipped - clipVelocity = current.velocity - gravityNormal * current.velocity * gravityNormal; - endClipVelocity = endVelocity - gravityNormal * endVelocity * gravityNormal; - if ( clipVelocity * endClipVelocity < 0.0f ) { - current.velocity = gravityNormal * current.velocity * gravityNormal; - } - - return (bool)( bumpcount == 0 ); -} - -/* -================== -idPhysics_Player::Friction - -Handles both ground friction and water friction -================== -*/ -void idPhysics_Player::Friction( void ) { - idVec3 vel; - float speed, newspeed, control; - float drop; - - vel = current.velocity; - if ( walking ) { - // ignore slope movement, remove all velocity in gravity direction - vel += (vel * gravityNormal) * gravityNormal; - } - - speed = vel.Length(); - if ( speed < 1.0f ) { - // remove all movement orthogonal to gravity, allows for sinking underwater - if ( fabs( current.velocity * gravityNormal ) < 1e-5f ) { - current.velocity.Zero(); - } else { - current.velocity = (current.velocity * gravityNormal) * gravityNormal; - } - // FIXME: still have z friction underwater? - return; - } - - drop = 0; - - // spectator friction - if ( current.movementType == PM_SPECTATOR ) { - drop += speed * PM_FLYFRICTION * frametime; - } - // apply ground friction - else if ( walking && waterLevel <= WATERLEVEL_FEET ) { - // no friction on slick surfaces - if ( !(groundMaterial && groundMaterial->GetSurfaceFlags() & SURF_SLICK) ) { - // if getting knocked back, no friction - if ( !(current.movementFlags & PMF_TIME_KNOCKBACK) ) { - control = speed < PM_STOPSPEED ? PM_STOPSPEED : speed; - drop += control * PM_FRICTION * frametime; - } - } - } - // apply water friction even if just wading - else if ( waterLevel ) { - drop += speed * PM_WATERFRICTION * waterLevel * frametime; - } - // apply air friction - else { - drop += speed * PM_AIRFRICTION * frametime; - } - - // scale the velocity - newspeed = speed - drop; - if (newspeed < 0) { - newspeed = 0; - } - current.velocity *= ( newspeed / speed ); -} - -/* -=================== -idPhysics_Player::WaterJumpMove - -Flying out of the water -=================== -*/ -void idPhysics_Player::WaterJumpMove( void ) { - - // waterjump has no control, but falls - idPhysics_Player::SlideMove( true, true, false, false ); - - // add gravity - current.velocity += gravityNormal * frametime; - // if falling down - if ( current.velocity * gravityNormal > 0.0f ) { - // cancel as soon as we are falling down again - current.movementFlags &= ~PMF_ALL_TIMES; - current.movementTime = 0; - } -} - -/* -=================== -idPhysics_Player::WaterMove -=================== -*/ -void idPhysics_Player::WaterMove( void ) { - idVec3 wishvel; - float wishspeed; - idVec3 wishdir; - float scale; - float vel; - - if ( idPhysics_Player::CheckWaterJump() ) { - idPhysics_Player::WaterJumpMove(); - return; - } - - idPhysics_Player::Friction(); - - scale = idPhysics_Player::CmdScale( command ); - - // user intentions - if ( !scale ) { - wishvel = gravityNormal * 60; // sink towards bottom - } else { - wishvel = scale * (viewForward * command.forwardmove + viewRight * command.rightmove); - wishvel -= scale * gravityNormal * command.upmove; - } - - wishdir = wishvel; - wishspeed = wishdir.Normalize(); - - if ( wishspeed > playerSpeed * PM_SWIMSCALE ) { - wishspeed = playerSpeed * PM_SWIMSCALE; - } - - idPhysics_Player::Accelerate( wishdir, wishspeed, PM_WATERACCELERATE ); - - // make sure we can go up slopes easily under water - if ( groundPlane && ( current.velocity * groundTrace.c.normal ) < 0.0f ) { - vel = current.velocity.Length(); - // slide along the ground plane - current.velocity.ProjectOntoPlane( groundTrace.c.normal, OVERCLIP ); - - current.velocity.Normalize(); - current.velocity *= vel; - } - - idPhysics_Player::SlideMove( false, true, false, false ); -} - -/* -=================== -idPhysics_Player::FlyMove -=================== -*/ -void idPhysics_Player::FlyMove( void ) { - idVec3 wishvel; - float wishspeed; - idVec3 wishdir; - float scale; - - // normal slowdown - idPhysics_Player::Friction(); - - scale = idPhysics_Player::CmdScale( command ); - - if ( !scale ) { - wishvel = vec3_origin; - } else { - wishvel = scale * (viewForward * command.forwardmove + viewRight * command.rightmove); - wishvel -= scale * gravityNormal * command.upmove; - } - - wishdir = wishvel; - wishspeed = wishdir.Normalize(); - - idPhysics_Player::Accelerate( wishdir, wishspeed, PM_FLYACCELERATE ); - - idPhysics_Player::SlideMove( false, false, false, false ); -} - -/* -=================== -idPhysics_Player::AirMove -=================== -*/ -void idPhysics_Player::AirMove( void ) { - idVec3 wishvel; - idVec3 wishdir; - float wishspeed; - float scale; - - idPhysics_Player::Friction(); - - scale = idPhysics_Player::CmdScale( command ); - - // project moves down to flat plane - viewForward -= (viewForward * gravityNormal) * gravityNormal; - viewRight -= (viewRight * gravityNormal) * gravityNormal; - viewForward.Normalize(); - viewRight.Normalize(); - - wishvel = viewForward * command.forwardmove + viewRight * command.rightmove; - wishvel -= (wishvel * gravityNormal) * gravityNormal; - wishdir = wishvel; - wishspeed = wishdir.Normalize(); - wishspeed *= scale; - - // not on ground, so little effect on velocity - idPhysics_Player::Accelerate( wishdir, wishspeed, PM_AIRACCELERATE ); - - // we may have a ground plane that is very steep, even - // though we don't have a groundentity - // slide along the steep plane - if ( groundPlane ) { - current.velocity.ProjectOntoPlane( groundTrace.c.normal, OVERCLIP ); - } - - idPhysics_Player::SlideMove( true, false, false, false ); -} - -/* -=================== -idPhysics_Player::WalkMove -=================== -*/ -void idPhysics_Player::WalkMove( void ) { - idVec3 wishvel; - idVec3 wishdir; - float wishspeed; - float scale; - float accelerate; - idVec3 oldVelocity, vel; - float oldVel, newVel; - - if ( waterLevel > WATERLEVEL_WAIST && ( viewForward * groundTrace.c.normal ) > 0.0f ) { - // begin swimming - idPhysics_Player::WaterMove(); - return; - } - - if ( idPhysics_Player::CheckJump() ) { - // jumped away - if ( waterLevel > WATERLEVEL_FEET ) { - idPhysics_Player::WaterMove(); - } - else { - idPhysics_Player::AirMove(); - } - return; - } - - idPhysics_Player::Friction(); - - scale = idPhysics_Player::CmdScale( command ); - - // project moves down to flat plane - viewForward -= (viewForward * gravityNormal) * gravityNormal; - viewRight -= (viewRight * gravityNormal) * gravityNormal; - - // project the forward and right directions onto the ground plane - viewForward.ProjectOntoPlane( groundTrace.c.normal, OVERCLIP ); - viewRight.ProjectOntoPlane( groundTrace.c.normal, OVERCLIP ); - // - viewForward.Normalize(); - viewRight.Normalize(); - - wishvel = viewForward * command.forwardmove + viewRight * command.rightmove; - wishdir = wishvel; - wishspeed = wishdir.Normalize(); - wishspeed *= scale; - - // clamp the speed lower if wading or walking on the bottom - if ( waterLevel ) { - float waterScale; - - waterScale = waterLevel / 3.0f; - waterScale = 1.0f - ( 1.0f - PM_SWIMSCALE ) * waterScale; - if ( wishspeed > playerSpeed * waterScale ) { - wishspeed = playerSpeed * waterScale; - } - } - - // when a player gets hit, they temporarily lose full control, which allows them to be moved a bit - if ( ( groundMaterial && groundMaterial->GetSurfaceFlags() & SURF_SLICK ) || current.movementFlags & PMF_TIME_KNOCKBACK ) { - accelerate = PM_AIRACCELERATE; - } - else { - accelerate = PM_ACCELERATE; - } - - idPhysics_Player::Accelerate( wishdir, wishspeed, accelerate ); - - if ( ( groundMaterial && groundMaterial->GetSurfaceFlags() & SURF_SLICK ) || current.movementFlags & PMF_TIME_KNOCKBACK ) { - current.velocity += gravityVector * frametime; - } - - oldVelocity = current.velocity; - - // slide along the ground plane - current.velocity.ProjectOntoPlane( groundTrace.c.normal, OVERCLIP ); - - // if not clipped into the opposite direction - if ( oldVelocity * current.velocity > 0.0f ) { - newVel = current.velocity.LengthSqr(); - if ( newVel > 1.0f ) { - oldVel = oldVelocity.LengthSqr(); - if ( oldVel > 1.0f ) { - // don't decrease velocity when going up or down a slope - current.velocity *= idMath::Sqrt( oldVel / newVel ); - } - } - } - - // don't do anything if standing still - vel = current.velocity - (current.velocity * gravityNormal) * gravityNormal; - if ( !vel.LengthSqr() ) { - return; - } - - gameLocal.push.InitSavingPushedEntityPositions(); - - idPhysics_Player::SlideMove( false, true, true, true ); -} - -/* -============== -idPhysics_Player::DeadMove -============== -*/ -void idPhysics_Player::DeadMove( void ) { - float forward; - - if ( !walking ) { - return; - } - - // extra friction - forward = current.velocity.Length(); - forward -= 20; - if ( forward <= 0 ) { - current.velocity = vec3_origin; - } - else { - current.velocity.Normalize(); - current.velocity *= forward; - } -} - -/* -=============== -idPhysics_Player::NoclipMove -=============== -*/ -void idPhysics_Player::NoclipMove( void ) { - float speed, drop, friction, newspeed, stopspeed; - float scale, wishspeed; - idVec3 wishdir; - - // friction - speed = current.velocity.Length(); - if ( speed < 20.0f ) { - current.velocity = vec3_origin; - } - else { - stopspeed = playerSpeed * 0.3f; - if ( speed < stopspeed ) { - speed = stopspeed; - } - friction = PM_NOCLIPFRICTION; - drop = speed * friction * frametime; - - // scale the velocity - newspeed = speed - drop; - if (newspeed < 0) { - newspeed = 0; - } - - current.velocity *= newspeed / speed; - } - - // accelerate - scale = idPhysics_Player::CmdScale( command ); - - wishdir = scale * (viewForward * command.forwardmove + viewRight * command.rightmove); - wishdir -= scale * gravityNormal * command.upmove; - wishspeed = wishdir.Normalize(); - wishspeed *= scale; - - idPhysics_Player::Accelerate( wishdir, wishspeed, PM_ACCELERATE ); - - // move - current.origin += frametime * current.velocity; -} - -/* -=============== -idPhysics_Player::SpectatorMove -=============== -*/ -void idPhysics_Player::SpectatorMove( void ) { - idVec3 wishvel; - float wishspeed; - idVec3 wishdir; - float scale; - - idVec3 end; - - // fly movement - - idPhysics_Player::Friction(); - - scale = idPhysics_Player::CmdScale( command ); - - if ( !scale ) { - wishvel = vec3_origin; - } else { - wishvel = scale * (viewForward * command.forwardmove + viewRight * command.rightmove); - } - - wishdir = wishvel; - wishspeed = wishdir.Normalize(); - - idPhysics_Player::Accelerate( wishdir, wishspeed, PM_FLYACCELERATE ); - - idPhysics_Player::SlideMove( false, false, false, false ); -} - -/* -============ -idPhysics_Player::LadderMove -============ -*/ -void idPhysics_Player::LadderMove( void ) { - idVec3 wishdir, wishvel, right; - float wishspeed, scale; - float upscale; - - // stick to the ladder - wishvel = -100.0f * ladderNormal; - current.velocity = (gravityNormal * current.velocity) * gravityNormal + wishvel; - - upscale = (-gravityNormal * viewForward + 0.5f) * 2.5f; - if ( upscale > 1.0f ) { - upscale = 1.0f; - } - else if ( upscale < -1.0f ) { - upscale = -1.0f; - } - - scale = idPhysics_Player::CmdScale( command ); - wishvel = -0.9f * gravityNormal * upscale * scale * (float)command.forwardmove; - - // strafe - if ( command.rightmove ) { - // right vector orthogonal to gravity - right = viewRight - (gravityNormal * viewRight) * gravityNormal; - // project right vector into ladder plane - right = right - (ladderNormal * right) * ladderNormal; - right.Normalize(); - - // if we are looking away from the ladder, reverse the right vector - if ( ladderNormal * viewForward > 0.0f ) { - right = -right; - } - wishvel += 2.0f * right * scale * (float) command.rightmove; - } - - // up down movement - if ( command.upmove ) { - wishvel += -0.5f * gravityNormal * scale * (float) command.upmove; - } - - // do strafe friction - idPhysics_Player::Friction(); - - // accelerate - wishspeed = wishvel.Normalize(); - idPhysics_Player::Accelerate( wishvel, wishspeed, PM_ACCELERATE ); - - // cap the vertical velocity - upscale = current.velocity * -gravityNormal; - if ( upscale < -PM_LADDERSPEED ) { - current.velocity += gravityNormal * (upscale + PM_LADDERSPEED); - } - else if ( upscale > PM_LADDERSPEED ) { - current.velocity += gravityNormal * (upscale - PM_LADDERSPEED); - } - - if ( (wishvel * gravityNormal) == 0.0f ) { - if ( current.velocity * gravityNormal < 0.0f ) { - current.velocity += gravityVector * frametime; - if ( current.velocity * gravityNormal > 0.0f ) { - current.velocity -= (gravityNormal * current.velocity) * gravityNormal; - } - } - else { - current.velocity -= gravityVector * frametime; - if ( current.velocity * gravityNormal < 0.0f ) { - current.velocity -= (gravityNormal * current.velocity) * gravityNormal; - } - } - } - - idPhysics_Player::SlideMove( false, ( command.forwardmove > 0 ), false, false ); -} - -/* -============= -idPhysics_Player::CorrectAllSolid -============= -*/ -void idPhysics_Player::CorrectAllSolid( trace_t &trace, int contents ) { - if ( debugLevel ) { - gameLocal.Printf( "%i:allsolid\n", c_pmove ); - } - - // FIXME: jitter around to find a free spot ? - - if ( trace.fraction >= 1.0f ) { - memset( &trace, 0, sizeof( trace ) ); - trace.endpos = current.origin; - trace.endAxis = clipModelAxis; - trace.fraction = 0.0f; - trace.c.dist = current.origin.z; - trace.c.normal.Set( 0, 0, 1 ); - trace.c.point = current.origin; - trace.c.entityNum = ENTITYNUM_WORLD; - trace.c.id = 0; - trace.c.type = CONTACT_TRMVERTEX; - trace.c.material = NULL; - trace.c.contents = contents; - } -} - -/* -============= -idPhysics_Player::CheckGround -============= -*/ -void idPhysics_Player::CheckGround( void ) { - int i, contents; - idVec3 point; - bool hadGroundContacts; - - hadGroundContacts = HasGroundContacts(); - - // set the clip model origin before getting the contacts - clipModel->SetPosition( current.origin, clipModel->GetAxis() ); - - EvaluateContacts(); - - // setup a ground trace from the contacts - groundTrace.endpos = current.origin; - groundTrace.endAxis = clipModel->GetAxis(); - if ( contacts.Num() ) { - groundTrace.fraction = 0.0f; - groundTrace.c = contacts[0]; - for ( i = 1; i < contacts.Num(); i++ ) { - groundTrace.c.normal += contacts[i].normal; - } - groundTrace.c.normal.Normalize(); - } else { - groundTrace.fraction = 1.0f; - } - - contents = gameLocal.clip.Contents( current.origin, clipModel, clipModel->GetAxis(), -1, self ); - if ( contents & MASK_SOLID ) { - // do something corrective if stuck in solid - idPhysics_Player::CorrectAllSolid( groundTrace, contents ); - } - - // if the trace didn't hit anything, we are in free fall - if ( groundTrace.fraction == 1.0f ) { - groundPlane = false; - walking = false; - groundEntityPtr = NULL; - return; - } - - groundMaterial = groundTrace.c.material; - groundEntityPtr = gameLocal.entities[ groundTrace.c.entityNum ]; - - // check if getting thrown off the ground - if ( (current.velocity * -gravityNormal) > 0.0f && ( current.velocity * groundTrace.c.normal ) > 10.0f ) { - if ( debugLevel ) { - gameLocal.Printf( "%i:kickoff\n", c_pmove ); - } - - groundPlane = false; - walking = false; - return; - } - - // slopes that are too steep will not be considered onground - if ( ( groundTrace.c.normal * -gravityNormal ) < MIN_WALK_NORMAL ) { - if ( debugLevel ) { - gameLocal.Printf( "%i:steep\n", c_pmove ); - } - - // FIXME: if they can't slide down the slope, let them walk (sharp crevices) - - // make sure we don't die from sliding down a steep slope - if ( current.velocity * gravityNormal > 150.0f ) { - current.velocity -= ( current.velocity * gravityNormal - 150.0f ) * gravityNormal; - } - - groundPlane = true; - walking = false; - return; - } - - groundPlane = true; - walking = true; - - // hitting solid ground will end a waterjump - if ( current.movementFlags & PMF_TIME_WATERJUMP ) { - current.movementFlags &= ~( PMF_TIME_WATERJUMP | PMF_TIME_LAND ); - current.movementTime = 0; - } - - // if the player didn't have ground contacts the previous frame - if ( !hadGroundContacts ) { - - // don't do landing time if we were just going down a slope - if ( (current.velocity * -gravityNormal) < -200.0f ) { - // don't allow another jump for a little while - current.movementFlags |= PMF_TIME_LAND; - current.movementTime = 250; - } - } - - // let the entity know about the collision - self->Collide( groundTrace, current.velocity ); - - if ( groundEntityPtr.GetEntity() ) { - impactInfo_t info; - groundEntityPtr.GetEntity()->GetImpactInfo( self, groundTrace.c.id, groundTrace.c.point, &info ); - if ( info.invMass != 0.0f ) { - groundEntityPtr.GetEntity()->ApplyImpulse( self, groundTrace.c.id, groundTrace.c.point, current.velocity / ( info.invMass * 10.0f ) ); - } - } -} - -/* -============== -idPhysics_Player::CheckDuck - -Sets clip model size -============== -*/ -void idPhysics_Player::CheckDuck( void ) { - trace_t trace; - idVec3 end; - idBounds bounds; - float maxZ; - - if ( current.movementType == PM_DEAD ) { - maxZ = pm_deadheight.GetFloat(); - } else { - // stand up when up against a ladder - if ( command.upmove < 0 && !ladder ) { - // duck - current.movementFlags |= PMF_DUCKED; - } else { - // stand up if possible - if ( current.movementFlags & PMF_DUCKED ) { - // try to stand up - end = current.origin - ( pm_normalheight.GetFloat() - pm_crouchheight.GetFloat() ) * gravityNormal; - gameLocal.clip.Translation( trace, current.origin, end, clipModel, clipModel->GetAxis(), clipMask, self ); - if ( trace.fraction >= 1.0f ) { - current.movementFlags &= ~PMF_DUCKED; - } - } - } - - if ( current.movementFlags & PMF_DUCKED ) { - playerSpeed = crouchSpeed; - maxZ = pm_crouchheight.GetFloat(); - } else { - maxZ = pm_normalheight.GetFloat(); - } - } - // if the clipModel height should change - if ( clipModel->GetBounds()[1][2] != maxZ ) { - - bounds = clipModel->GetBounds(); - bounds[1][2] = maxZ; - if ( pm_usecylinder.GetBool() ) { - clipModel->LoadModel( idTraceModel( bounds, 8 ) ); - } else { - clipModel->LoadModel( idTraceModel( bounds ) ); - } - } -} - -/* -================ -idPhysics_Player::CheckLadder -================ -*/ -void idPhysics_Player::CheckLadder( void ) { - idVec3 forward, start, end; - trace_t trace; - float tracedist; - - if ( current.movementTime ) { - return; - } - - // if on the ground moving backwards - if ( walking && command.forwardmove <= 0 ) { - return; - } - - // forward vector orthogonal to gravity - forward = viewForward - (gravityNormal * viewForward) * gravityNormal; - forward.Normalize(); - - if ( walking ) { - // don't want to get sucked towards the ladder when still walking - tracedist = 1.0f; - } else { - tracedist = 48.0f; - } - - end = current.origin + tracedist * forward; - gameLocal.clip.Translation( trace, current.origin, end, clipModel, clipModel->GetAxis(), clipMask, self ); - - // if near a surface - if ( trace.fraction < 1.0f ) { - - // if a ladder surface - if ( trace.c.material && ( trace.c.material->GetSurfaceFlags() & SURF_LADDER ) ) { - - // check a step height higher - end = current.origin - gravityNormal * ( maxStepHeight * 0.75f ); - gameLocal.clip.Translation( trace, current.origin, end, clipModel, clipModel->GetAxis(), clipMask, self ); - start = trace.endpos; - end = start + tracedist * forward; - gameLocal.clip.Translation( trace, start, end, clipModel, clipModel->GetAxis(), clipMask, self ); - - // if also near a surface a step height higher - if ( trace.fraction < 1.0f ) { - - // if it also is a ladder surface - if ( trace.c.material && trace.c.material->GetSurfaceFlags() & SURF_LADDER ) { - ladder = true; - ladderNormal = trace.c.normal; - } - } - } - } -} - -/* -============= -idPhysics_Player::CheckJump -============= -*/ -bool idPhysics_Player::CheckJump( void ) { - idVec3 addVelocity; - - if ( command.upmove < 10 ) { - // not holding jump - return false; - } - - // must wait for jump to be released - if ( current.movementFlags & PMF_JUMP_HELD ) { - return false; - } - - // don't jump if we can't stand up - if ( current.movementFlags & PMF_DUCKED ) { - return false; - } - - groundPlane = false; // jumping away - walking = false; - current.movementFlags |= PMF_JUMP_HELD | PMF_JUMPED; - - addVelocity = 2.0f * maxJumpHeight * -gravityVector; - addVelocity *= idMath::Sqrt( addVelocity.Normalize() ); - current.velocity += addVelocity; - - return true; -} - -/* -============= -idPhysics_Player::CheckWaterJump -============= -*/ -bool idPhysics_Player::CheckWaterJump( void ) { - idVec3 spot; - int cont; - idVec3 flatforward; - - if ( current.movementTime ) { - return false; - } - - // check for water jump - if ( waterLevel != WATERLEVEL_WAIST ) { - return false; - } - - flatforward = viewForward - (viewForward * gravityNormal) * gravityNormal; - flatforward.Normalize(); - - spot = current.origin + 30.0f * flatforward; - spot -= 4.0f * gravityNormal; - cont = gameLocal.clip.Contents( spot, NULL, mat3_identity, -1, self ); - if ( !(cont & CONTENTS_SOLID) ) { - return false; - } - - spot -= 16.0f * gravityNormal; - cont = gameLocal.clip.Contents( spot, NULL, mat3_identity, -1, self ); - if ( cont ) { - return false; - } - - // jump out of water - current.velocity = 200.0f * viewForward - 350.0f * gravityNormal; - current.movementFlags |= PMF_TIME_WATERJUMP; - current.movementTime = 2000; - - return true; -} - -/* -============= -idPhysics_Player::SetWaterLevel -============= -*/ -void idPhysics_Player::SetWaterLevel( void ) { - idVec3 point; - idBounds bounds; - int contents; - - // - // get waterlevel, accounting for ducking - // - waterLevel = WATERLEVEL_NONE; - waterType = 0; - - bounds = clipModel->GetBounds(); - - // check at feet level - point = current.origin - ( bounds[0][2] + 1.0f ) * gravityNormal; - contents = gameLocal.clip.Contents( point, NULL, mat3_identity, -1, self ); - if ( contents & MASK_WATER ) { - - waterType = contents; - waterLevel = WATERLEVEL_FEET; - - // check at waist level - point = current.origin - ( bounds[1][2] - bounds[0][2] ) * 0.5f * gravityNormal; - contents = gameLocal.clip.Contents( point, NULL, mat3_identity, -1, self ); - if ( contents & MASK_WATER ) { - - waterLevel = WATERLEVEL_WAIST; - - // check at head level - point = current.origin - ( bounds[1][2] - 1.0f ) * gravityNormal; - contents = gameLocal.clip.Contents( point, NULL, mat3_identity, -1, self ); - if ( contents & MASK_WATER ) { - waterLevel = WATERLEVEL_HEAD; - } - } - } -} - -/* -================ -idPhysics_Player::DropTimers -================ -*/ -void idPhysics_Player::DropTimers( void ) { - // drop misc timing counter - if ( current.movementTime ) { - if ( framemsec >= current.movementTime ) { - current.movementFlags &= ~PMF_ALL_TIMES; - current.movementTime = 0; - } - else { - current.movementTime -= framemsec; - } - } -} - -/* -================ -idPhysics_Player::MovePlayer -================ -*/ -void idPhysics_Player::MovePlayer( int msec ) { - - // this counter lets us debug movement problems with a journal - // by setting a conditional breakpoint for the previous frame - c_pmove++; - - walking = false; - groundPlane = false; - ladder = false; - - // determine the time - framemsec = msec; - frametime = framemsec * 0.001f; - - // default speed - playerSpeed = walkSpeed; - - // remove jumped and stepped up flag - current.movementFlags &= ~(PMF_JUMPED|PMF_STEPPED_UP|PMF_STEPPED_DOWN); - current.stepUp = 0.0f; - - if ( command.upmove < 10 ) { - // not holding jump - current.movementFlags &= ~PMF_JUMP_HELD; - } - - // if no movement at all - if ( current.movementType == PM_FREEZE ) { - return; - } - - // move the player velocity into the frame of a pusher - current.velocity -= current.pushVelocity; - - // view vectors - viewAngles.ToVectors( &viewForward, NULL, NULL ); - viewForward *= clipModelAxis; - viewRight = gravityNormal.Cross( viewForward ); - viewRight.Normalize(); - - // fly in spectator mode - if ( current.movementType == PM_SPECTATOR ) { - SpectatorMove(); - idPhysics_Player::DropTimers(); - return; - } - - // special no clip mode - if ( current.movementType == PM_NOCLIP ) { - idPhysics_Player::NoclipMove(); - idPhysics_Player::DropTimers(); - return; - } - - // no control when dead - if ( current.movementType == PM_DEAD ) { - command.forwardmove = 0; - command.rightmove = 0; - command.upmove = 0; - } - - // set watertype and waterlevel - idPhysics_Player::SetWaterLevel(); - - // check for ground - idPhysics_Player::CheckGround(); - - // check if up against a ladder - idPhysics_Player::CheckLadder(); - - // set clip model size - idPhysics_Player::CheckDuck(); - - // handle timers - idPhysics_Player::DropTimers(); - - // move - if ( current.movementType == PM_DEAD ) { - // dead - idPhysics_Player::DeadMove(); - } - else if ( ladder ) { - // going up or down a ladder - idPhysics_Player::LadderMove(); - } - else if ( current.movementFlags & PMF_TIME_WATERJUMP ) { - // jumping out of water - idPhysics_Player::WaterJumpMove(); - } - else if ( waterLevel > 1 ) { - // swimming - idPhysics_Player::WaterMove(); - } - else if ( walking ) { - // walking on ground - idPhysics_Player::WalkMove(); - } - else { - // airborne - idPhysics_Player::AirMove(); - } - - // set watertype, waterlevel and groundentity - idPhysics_Player::SetWaterLevel(); - idPhysics_Player::CheckGround(); - - // move the player velocity back into the world frame - current.velocity += current.pushVelocity; - current.pushVelocity.Zero(); -} - -/* -================ -idPhysics_Player::GetWaterLevel -================ -*/ -waterLevel_t idPhysics_Player::GetWaterLevel( void ) const { - return waterLevel; -} - -/* -================ -idPhysics_Player::GetWaterType -================ -*/ -int idPhysics_Player::GetWaterType( void ) const { - return waterType; -} - -/* -================ -idPhysics_Player::HasJumped -================ -*/ -bool idPhysics_Player::HasJumped( void ) const { - return ( ( current.movementFlags & PMF_JUMPED ) != 0 ); -} - -/* -================ -idPhysics_Player::HasSteppedUp -================ -*/ -bool idPhysics_Player::HasSteppedUp( void ) const { - return ( ( current.movementFlags & ( PMF_STEPPED_UP | PMF_STEPPED_DOWN ) ) != 0 ); -} - -/* -================ -idPhysics_Player::GetStepUp -================ -*/ -float idPhysics_Player::GetStepUp( void ) const { - return current.stepUp; -} - -/* -================ -idPhysics_Player::IsCrouching -================ -*/ -bool idPhysics_Player::IsCrouching( void ) const { - return ( ( current.movementFlags & PMF_DUCKED ) != 0 ); -} - -/* -================ -idPhysics_Player::OnLadder -================ -*/ -bool idPhysics_Player::OnLadder( void ) const { - return ladder; -} - -/* -================ -idPhysics_Player::idPhysics_Player -================ -*/ -idPhysics_Player::idPhysics_Player( void ) { - debugLevel = false; - clipModel = NULL; - clipMask = 0; - memset( ¤t, 0, sizeof( current ) ); - saved = current; - walkSpeed = 0; - crouchSpeed = 0; - maxStepHeight = 0; - maxJumpHeight = 0; - memset( &command, 0, sizeof( command ) ); - viewAngles.Zero(); - framemsec = 0; - frametime = 0; - playerSpeed = 0; - viewForward.Zero(); - viewRight.Zero(); - walking = false; - groundPlane = false; - memset( &groundTrace, 0, sizeof( groundTrace ) ); - groundMaterial = NULL; - ladder = false; - ladderNormal.Zero(); - waterLevel = WATERLEVEL_NONE; - waterType = 0; -} - -/* -================ -idPhysics_Player_SavePState -================ -*/ -void idPhysics_Player_SavePState( idSaveGame *savefile, const playerPState_t &state ) { - savefile->WriteVec3( state.origin ); - savefile->WriteVec3( state.velocity ); - savefile->WriteVec3( state.localOrigin ); - savefile->WriteVec3( state.pushVelocity ); - savefile->WriteFloat( state.stepUp ); - savefile->WriteInt( state.movementType ); - savefile->WriteInt( state.movementFlags ); - savefile->WriteInt( state.movementTime ); -} - -/* -================ -idPhysics_Player_RestorePState -================ -*/ -void idPhysics_Player_RestorePState( idRestoreGame *savefile, playerPState_t &state ) { - savefile->ReadVec3( state.origin ); - savefile->ReadVec3( state.velocity ); - savefile->ReadVec3( state.localOrigin ); - savefile->ReadVec3( state.pushVelocity ); - savefile->ReadFloat( state.stepUp ); - savefile->ReadInt( state.movementType ); - savefile->ReadInt( state.movementFlags ); - savefile->ReadInt( state.movementTime ); -} - -/* -================ -idPhysics_Player::Save -================ -*/ -void idPhysics_Player::Save( idSaveGame *savefile ) const { - - idPhysics_Player_SavePState( savefile, current ); - idPhysics_Player_SavePState( savefile, saved ); - - savefile->WriteFloat( walkSpeed ); - savefile->WriteFloat( crouchSpeed ); - savefile->WriteFloat( maxStepHeight ); - savefile->WriteFloat( maxJumpHeight ); - savefile->WriteInt( debugLevel ); - - savefile->WriteUsercmd( command ); - savefile->WriteAngles( viewAngles ); - - savefile->WriteInt( framemsec ); - savefile->WriteFloat( frametime ); - savefile->WriteFloat( playerSpeed ); - savefile->WriteVec3( viewForward ); - savefile->WriteVec3( viewRight ); - - savefile->WriteBool( walking ); - savefile->WriteBool( groundPlane ); - savefile->WriteTrace( groundTrace ); - savefile->WriteMaterial( groundMaterial ); - - savefile->WriteBool( ladder ); - savefile->WriteVec3( ladderNormal ); - - savefile->WriteInt( (int)waterLevel ); - savefile->WriteInt( waterType ); -} - -/* -================ -idPhysics_Player::Restore -================ -*/ -void idPhysics_Player::Restore( idRestoreGame *savefile ) { - - idPhysics_Player_RestorePState( savefile, current ); - idPhysics_Player_RestorePState( savefile, saved ); - - savefile->ReadFloat( walkSpeed ); - savefile->ReadFloat( crouchSpeed ); - savefile->ReadFloat( maxStepHeight ); - savefile->ReadFloat( maxJumpHeight ); - savefile->ReadInt( debugLevel ); - - savefile->ReadUsercmd( command ); - savefile->ReadAngles( viewAngles ); - - savefile->ReadInt( framemsec ); - savefile->ReadFloat( frametime ); - savefile->ReadFloat( playerSpeed ); - savefile->ReadVec3( viewForward ); - savefile->ReadVec3( viewRight ); - - savefile->ReadBool( walking ); - savefile->ReadBool( groundPlane ); - savefile->ReadTrace( groundTrace ); - savefile->ReadMaterial( groundMaterial ); - - savefile->ReadBool( ladder ); - savefile->ReadVec3( ladderNormal ); - - savefile->ReadInt( (int &)waterLevel ); - savefile->ReadInt( waterType ); - - /* DG: It can apparently happen that the player saves while the clipModel's axis are - * modified by idPush::TryRotatePushEntity() -> idPhysics_Player::Rotate() -> idClipModel::Link() - * Normally idPush seems to reset them to the identity matrix in the next frame, - * but apparently not when coming from a savegame. - * Usually clipModel->axis is the identity matrix, and if it isn't there's clipping bugs - * like CheckGround() reporting that it's steep even though the player is only trying to - * walk up normal stairs. - * Resetting the axis to mat3_identity when restoring a savegame works around that issue - * and makes sure players can go on playing if their savegame was "corrupted" by saving - * while idPush was active. See https://github.com/dhewm/dhewm3/issues/328 for more details */ - if ( clipModel != NULL ) { - clipModel->SetPosition( clipModel->GetOrigin(), mat3_identity ); - } -} - -/* -================ -idPhysics_Player::SetPlayerInput -================ -*/ -void idPhysics_Player::SetPlayerInput( const usercmd_t &cmd, const idAngles &newViewAngles ) { - command = cmd; - viewAngles = newViewAngles; // can't use cmd.angles cause of the delta_angles -} - -/* -================ -idPhysics_Player::SetSpeed -================ -*/ -void idPhysics_Player::SetSpeed( const float newWalkSpeed, const float newCrouchSpeed ) { - walkSpeed = newWalkSpeed; - crouchSpeed = newCrouchSpeed; -} - -/* -================ -idPhysics_Player::SetMaxStepHeight -================ -*/ -void idPhysics_Player::SetMaxStepHeight( const float newMaxStepHeight ) { - maxStepHeight = newMaxStepHeight; -} - -/* -================ -idPhysics_Player::GetMaxStepHeight -================ -*/ -float idPhysics_Player::GetMaxStepHeight( void ) const { - return maxStepHeight; -} - -/* -================ -idPhysics_Player::SetMaxJumpHeight -================ -*/ -void idPhysics_Player::SetMaxJumpHeight( const float newMaxJumpHeight ) { - maxJumpHeight = newMaxJumpHeight; -} - -/* -================ -idPhysics_Player::SetMovementType -================ -*/ -void idPhysics_Player::SetMovementType( const pmtype_t type ) { - current.movementType = type; -} - -/* -================ -idPhysics_Player::SetKnockBack -================ -*/ -void idPhysics_Player::SetKnockBack( const int knockBackTime ) { - if ( current.movementTime ) { - return; - } - current.movementFlags |= PMF_TIME_KNOCKBACK; - current.movementTime = knockBackTime; -} - -/* -================ -idPhysics_Player::SetDebugLevel -================ -*/ -void idPhysics_Player::SetDebugLevel( bool set ) { - debugLevel = set; -} - -/* -================ -idPhysics_Player::Evaluate -================ -*/ -bool idPhysics_Player::Evaluate( int timeStepMSec, int endTimeMSec ) { - idVec3 masterOrigin, oldOrigin; - idMat3 masterAxis; - - waterLevel = WATERLEVEL_NONE; - waterType = 0; - oldOrigin = current.origin; - - clipModel->Unlink(); - - // if bound to a master - if ( masterEntity ) { - self->GetMasterPosition( masterOrigin, masterAxis ); - current.origin = masterOrigin + current.localOrigin * masterAxis; - clipModel->Link( gameLocal.clip, self, 0, current.origin, clipModel->GetAxis() ); - current.velocity = ( current.origin - oldOrigin ) / ( timeStepMSec * 0.001f ); - masterDeltaYaw = masterYaw; - masterYaw = masterAxis[0].ToYaw(); - masterDeltaYaw = masterYaw - masterDeltaYaw; - return true; - } - - ActivateContactEntities(); - - idPhysics_Player::MovePlayer( timeStepMSec ); - - clipModel->Link( gameLocal.clip, self, 0, current.origin, clipModel->GetAxis() ); - - if ( IsOutsideWorld() ) { - gameLocal.Warning( "clip model outside world bounds for entity '%s' at (%s)", self->name.c_str(), current.origin.ToString(0) ); - } - - return true; //( current.origin != oldOrigin ); -} - -/* -================ -idPhysics_Player::UpdateTime -================ -*/ -void idPhysics_Player::UpdateTime( int endTimeMSec ) { -} - -/* -================ -idPhysics_Player::GetTime -================ -*/ -int idPhysics_Player::GetTime( void ) const { - return gameLocal.time; -} - -/* -================ -idPhysics_Player::GetImpactInfo -================ -*/ -void idPhysics_Player::GetImpactInfo( const int id, const idVec3 &point, impactInfo_t *info ) const { - info->invMass = invMass; - info->invInertiaTensor.Zero(); - info->position.Zero(); - info->velocity = current.velocity; -} - -/* -================ -idPhysics_Player::ApplyImpulse -================ -*/ -void idPhysics_Player::ApplyImpulse( const int id, const idVec3 &point, const idVec3 &impulse ) { - if ( current.movementType != PM_NOCLIP ) { - current.velocity += impulse * invMass; - } -} - -/* -================ -idPhysics_Player::IsAtRest -================ -*/ -bool idPhysics_Player::IsAtRest( void ) const { - return false; -} - -/* -================ -idPhysics_Player::GetRestStartTime -================ -*/ -int idPhysics_Player::GetRestStartTime( void ) const { - return -1; -} - -/* -================ -idPhysics_Player::SaveState -================ -*/ -void idPhysics_Player::SaveState( void ) { - saved = current; -} - -/* -================ -idPhysics_Player::RestoreState -================ -*/ -void idPhysics_Player::RestoreState( void ) { - current = saved; - - clipModel->Link( gameLocal.clip, self, 0, current.origin, clipModel->GetAxis() ); - - EvaluateContacts(); -} - -/* -================ -idPhysics_Player::SetOrigin -================ -*/ -void idPhysics_Player::SetOrigin( const idVec3 &newOrigin, int id ) { - idVec3 masterOrigin; - idMat3 masterAxis; - - current.localOrigin = newOrigin; - if ( masterEntity ) { - self->GetMasterPosition( masterOrigin, masterAxis ); - current.origin = masterOrigin + newOrigin * masterAxis; - } - else { - current.origin = newOrigin; - } - - clipModel->Link( gameLocal.clip, self, 0, newOrigin, clipModel->GetAxis() ); -} - -/* -================ -idPhysics_Player::GetOrigin -================ -*/ -const idVec3 & idPhysics_Player::PlayerGetOrigin( void ) const { - return current.origin; -} - -/* -================ -idPhysics_Player::SetAxis -================ -*/ -void idPhysics_Player::SetAxis( const idMat3 &newAxis, int id ) { - clipModel->Link( gameLocal.clip, self, 0, clipModel->GetOrigin(), newAxis ); -} - -/* -================ -idPhysics_Player::Translate -================ -*/ -void idPhysics_Player::Translate( const idVec3 &translation, int id ) { - - current.localOrigin += translation; - current.origin += translation; - - clipModel->Link( gameLocal.clip, self, 0, current.origin, clipModel->GetAxis() ); -} - -/* -================ -idPhysics_Player::Rotate -================ -*/ -void idPhysics_Player::Rotate( const idRotation &rotation, int id ) { - idVec3 masterOrigin; - idMat3 masterAxis; - - current.origin *= rotation; - if ( masterEntity ) { - self->GetMasterPosition( masterOrigin, masterAxis ); - current.localOrigin = ( current.origin - masterOrigin ) * masterAxis.Transpose(); - } - else { - current.localOrigin = current.origin; - } - - clipModel->Link( gameLocal.clip, self, 0, current.origin, clipModel->GetAxis() * rotation.ToMat3() ); -} - -/* -================ -idPhysics_Player::SetLinearVelocity -================ -*/ -void idPhysics_Player::SetLinearVelocity( const idVec3 &newLinearVelocity, int id ) { - current.velocity = newLinearVelocity; -} - -/* -================ -idPhysics_Player::GetLinearVelocity -================ -*/ -const idVec3 &idPhysics_Player::GetLinearVelocity( int id ) const { - return current.velocity; -} - -/* -================ -idPhysics_Player::SetPushed -================ -*/ -void idPhysics_Player::SetPushed( int deltaTime ) { - idVec3 velocity; - float d; - - // velocity with which the player is pushed - velocity = ( current.origin - saved.origin ) / ( deltaTime * idMath::M_MS2SEC ); - - // remove any downward push velocity - d = velocity * gravityNormal; - if ( d > 0.0f ) { - velocity -= d * gravityNormal; - } - - current.pushVelocity += velocity; -} - -/* -================ -idPhysics_Player::GetPushedLinearVelocity -================ -*/ -const idVec3 &idPhysics_Player::GetPushedLinearVelocity( const int id ) const { - return current.pushVelocity; -} - -/* -================ -idPhysics_Player::ClearPushedVelocity -================ -*/ -void idPhysics_Player::ClearPushedVelocity( void ) { - current.pushVelocity.Zero(); -} - -/* -================ -idPhysics_Player::SetMaster - - the binding is never orientated -================ -*/ -void idPhysics_Player::SetMaster( idEntity *master, const bool orientated ) { - idVec3 masterOrigin; - idMat3 masterAxis; - - if ( master ) { - if ( !masterEntity ) { - // transform from world space to master space - self->GetMasterPosition( masterOrigin, masterAxis ); - current.localOrigin = ( current.origin - masterOrigin ) * masterAxis.Transpose(); - masterEntity = master; - masterYaw = masterAxis[0].ToYaw(); - } - ClearContacts(); - } - else { - if ( masterEntity ) { - masterEntity = NULL; - } - } -} - -const float PLAYER_VELOCITY_MAX = 4000; -const int PLAYER_VELOCITY_TOTAL_BITS = 16; -const int PLAYER_VELOCITY_EXPONENT_BITS = idMath::BitsForInteger( idMath::BitsForFloat( PLAYER_VELOCITY_MAX ) ) + 1; -const int PLAYER_VELOCITY_MANTISSA_BITS = PLAYER_VELOCITY_TOTAL_BITS - 1 - PLAYER_VELOCITY_EXPONENT_BITS; -const int PLAYER_MOVEMENT_TYPE_BITS = 3; -const int PLAYER_MOVEMENT_FLAGS_BITS = 8; - -/* -================ -idPhysics_Player::WriteToSnapshot -================ -*/ -void idPhysics_Player::WriteToSnapshot( idBitMsgDelta &msg ) const { - msg.WriteFloat( current.origin[0] ); - msg.WriteFloat( current.origin[1] ); - msg.WriteFloat( current.origin[2] ); - msg.WriteFloat( current.velocity[0], PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS ); - msg.WriteFloat( current.velocity[1], PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS ); - msg.WriteFloat( current.velocity[2], PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS ); - msg.WriteDeltaFloat( current.origin[0], current.localOrigin[0] ); - msg.WriteDeltaFloat( current.origin[1], current.localOrigin[1] ); - msg.WriteDeltaFloat( current.origin[2], current.localOrigin[2] ); - msg.WriteDeltaFloat( 0.0f, current.pushVelocity[0], PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS ); - msg.WriteDeltaFloat( 0.0f, current.pushVelocity[1], PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS ); - msg.WriteDeltaFloat( 0.0f, current.pushVelocity[2], PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS ); - msg.WriteDeltaFloat( 0.0f, current.stepUp ); - msg.WriteBits( current.movementType, PLAYER_MOVEMENT_TYPE_BITS ); - msg.WriteBits( current.movementFlags, PLAYER_MOVEMENT_FLAGS_BITS ); - msg.WriteDeltaInt( 0, current.movementTime ); -} - -/* -================ -idPhysics_Player::ReadFromSnapshot -================ -*/ -void idPhysics_Player::ReadFromSnapshot( const idBitMsgDelta &msg ) { - current.origin[0] = msg.ReadFloat(); - current.origin[1] = msg.ReadFloat(); - current.origin[2] = msg.ReadFloat(); - current.velocity[0] = msg.ReadFloat( PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS ); - current.velocity[1] = msg.ReadFloat( PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS ); - current.velocity[2] = msg.ReadFloat( PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS ); - current.localOrigin[0] = msg.ReadDeltaFloat( current.origin[0] ); - current.localOrigin[1] = msg.ReadDeltaFloat( current.origin[1] ); - current.localOrigin[2] = msg.ReadDeltaFloat( current.origin[2] ); - current.pushVelocity[0] = msg.ReadDeltaFloat( 0.0f, PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS ); - current.pushVelocity[1] = msg.ReadDeltaFloat( 0.0f, PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS ); - current.pushVelocity[2] = msg.ReadDeltaFloat( 0.0f, PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS ); - current.stepUp = msg.ReadDeltaFloat( 0.0f ); - current.movementType = msg.ReadBits( PLAYER_MOVEMENT_TYPE_BITS ); - current.movementFlags = msg.ReadBits( PLAYER_MOVEMENT_FLAGS_BITS ); - current.movementTime = msg.ReadDeltaInt( 0 ); - - if ( clipModel ) { - clipModel->Link( gameLocal.clip, self, 0, current.origin, clipModel->GetAxis() ); - } -} diff --git a/d3xp/physics/Physics_Player.h b/d3xp/physics/Physics_Player.h deleted file mode 100644 index 40d52e7e..00000000 --- a/d3xp/physics/Physics_Player.h +++ /dev/null @@ -1,197 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __PHYSICS_PLAYER_H__ -#define __PHYSICS_PLAYER_H__ - -#include "physics/Physics_Actor.h" - -/* -=================================================================================== - - Player physics - - Simulates the motion of a player through the environment. Input from the - player is used to allow a certain degree of control over the motion. - -=================================================================================== -*/ - -// movementType -typedef enum { - PM_NORMAL, // normal physics - PM_DEAD, // no acceleration or turning, but free falling - PM_SPECTATOR, // flying without gravity but with collision detection - PM_FREEZE, // stuck in place without control - PM_NOCLIP // flying without collision detection nor gravity -} pmtype_t; - -typedef enum { - WATERLEVEL_NONE, - WATERLEVEL_FEET, - WATERLEVEL_WAIST, - WATERLEVEL_HEAD -} waterLevel_t; - -#define MAXTOUCH 32 - -typedef struct playerPState_s { - idVec3 origin; - idVec3 velocity; - idVec3 localOrigin; - idVec3 pushVelocity; - float stepUp; - int movementType; - int movementFlags; - int movementTime; -} playerPState_t; - -class idPhysics_Player : public idPhysics_Actor { - -public: - CLASS_PROTOTYPE( idPhysics_Player ); - - idPhysics_Player( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - // initialisation - void SetSpeed( const float newWalkSpeed, const float newCrouchSpeed ); - void SetMaxStepHeight( const float newMaxStepHeight ); - float GetMaxStepHeight( void ) const; - void SetMaxJumpHeight( const float newMaxJumpHeight ); - void SetMovementType( const pmtype_t type ); - void SetPlayerInput( const usercmd_t &cmd, const idAngles &newViewAngles ); - void SetKnockBack( const int knockBackTime ); - void SetDebugLevel( bool set ); - // feed back from last physics frame - waterLevel_t GetWaterLevel( void ) const; - int GetWaterType( void ) const; - bool HasJumped( void ) const; - bool HasSteppedUp( void ) const; - float GetStepUp( void ) const; - bool IsCrouching( void ) const; - bool OnLadder( void ) const; - const idVec3 & PlayerGetOrigin( void ) const; // != GetOrigin - -public: // common physics interface - bool Evaluate( int timeStepMSec, int endTimeMSec ); - void UpdateTime( int endTimeMSec ); - int GetTime( void ) const; - - void GetImpactInfo( const int id, const idVec3 &point, impactInfo_t *info ) const; - void ApplyImpulse( const int id, const idVec3 &point, const idVec3 &impulse ); - bool IsAtRest( void ) const; - int GetRestStartTime( void ) const; - - void SaveState( void ); - void RestoreState( void ); - - void SetOrigin( const idVec3 &newOrigin, int id = -1 ); - void SetAxis( const idMat3 &newAxis, int id = -1 ); - - void Translate( const idVec3 &translation, int id = -1 ); - void Rotate( const idRotation &rotation, int id = -1 ); - - void SetLinearVelocity( const idVec3 &newLinearVelocity, int id = 0 ); - - const idVec3 & GetLinearVelocity( int id = 0 ) const; - - void SetPushed( int deltaTime ); - const idVec3 & GetPushedLinearVelocity( const int id = 0 ) const; - void ClearPushedVelocity( void ); - - void SetMaster( idEntity *master, const bool orientated = true ); - - void WriteToSnapshot( idBitMsgDelta &msg ) const; - void ReadFromSnapshot( const idBitMsgDelta &msg ); - -private: - // player physics state - playerPState_t current; - playerPState_t saved; - - // properties - float walkSpeed; - float crouchSpeed; - float maxStepHeight; - float maxJumpHeight; - int debugLevel; // if set, diagnostic output will be printed - - // player input - usercmd_t command; - idAngles viewAngles; - - // run-time variables - int framemsec; - float frametime; - float playerSpeed; - idVec3 viewForward; - idVec3 viewRight; - - // walk movement - bool walking; - bool groundPlane; - trace_t groundTrace; - const idMaterial * groundMaterial; - - // ladder movement - bool ladder; - idVec3 ladderNormal; - - // results of last evaluate - waterLevel_t waterLevel; - int waterType; - -private: - float CmdScale( const usercmd_t &cmd ) const; - void Accelerate( const idVec3 &wishdir, const float wishspeed, const float accel ); - bool SlideMove( bool gravity, bool stepUp, bool stepDown, bool push ); - void Friction( void ); - void WaterJumpMove( void ); - void WaterMove( void ); - void FlyMove( void ); - void AirMove( void ); - void WalkMove( void ); - void DeadMove( void ); - void NoclipMove( void ); - void SpectatorMove( void ); - void LadderMove( void ); - void CorrectAllSolid( trace_t &trace, int contents ); - void CheckGround( void ); - void CheckDuck( void ); - void CheckLadder( void ); - bool CheckJump( void ); - bool CheckWaterJump( void ); - void SetWaterLevel( void ); - void DropTimers( void ); - void MovePlayer( int msec ); -}; - -#endif /* !__PHYSICS_PLAYER_H__ */ diff --git a/d3xp/physics/Physics_RigidBody.cpp b/d3xp/physics/Physics_RigidBody.cpp deleted file mode 100644 index 83806569..00000000 --- a/d3xp/physics/Physics_RigidBody.cpp +++ /dev/null @@ -1,1542 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "idlib/math/Quat.h" - -#include "gamesys/SysCvar.h" -#include "Entity.h" -#include "Player.h" - -#include "physics/Physics_RigidBody.h" - -CLASS_DECLARATION( idPhysics_Base, idPhysics_RigidBody ) -END_CLASS - -const float STOP_SPEED = 10.0f; - - -#undef RB_TIMINGS - -#ifdef RB_TIMINGS -static int lastTimerReset = 0; -static int numRigidBodies = 0; -static idTimer timer_total, timer_collision; -#endif - - -/* -================ -RigidBodyDerivatives -================ -*/ -void RigidBodyDerivatives( const float t, const void *clientData, const float *state, float *derivatives ) { - const idPhysics_RigidBody *p = (idPhysics_RigidBody *) clientData; - rigidBodyIState_t *s = (rigidBodyIState_t *) state; - // NOTE: this struct should be build conform rigidBodyIState_t - struct rigidBodyDerivatives_s { - idVec3 linearVelocity; - idMat3 angularMatrix; - idVec3 force; - idVec3 torque; - } *d = (struct rigidBodyDerivatives_s *) derivatives; - idVec3 angularVelocity; - idMat3 inverseWorldInertiaTensor; - - inverseWorldInertiaTensor = s->orientation * p->inverseInertiaTensor * s->orientation.Transpose(); - angularVelocity = inverseWorldInertiaTensor * s->angularMomentum; - // derivatives - d->linearVelocity = p->inverseMass * s->linearMomentum; - d->angularMatrix = SkewSymmetric( angularVelocity ) * s->orientation; - d->force = - p->linearFriction * s->linearMomentum + p->current.externalForce; - d->torque = - p->angularFriction * s->angularMomentum + p->current.externalTorque; -} - -/* -================ -idPhysics_RigidBody::Integrate - - Calculate next state from the current state using an integrator. -================ -*/ -void idPhysics_RigidBody::Integrate( float deltaTime, rigidBodyPState_t &next ) { - idVec3 position; - - position = current.i.position; - current.i.position += centerOfMass * current.i.orientation; - - current.i.orientation.TransposeSelf(); - - integrator->Evaluate( (float *) ¤t.i, (float *) &next.i, 0, deltaTime ); - next.i.orientation.OrthoNormalizeSelf(); - - // apply gravity - next.i.linearMomentum += deltaTime * gravityVector * mass; - - current.i.orientation.TransposeSelf(); - next.i.orientation.TransposeSelf(); - - current.i.position = position; - next.i.position -= centerOfMass * next.i.orientation; - - next.atRest = current.atRest; -} - -/* -================ -idPhysics_RigidBody::CollisionImpulse - - Calculates the collision impulse using the velocity relative to the collision object. - The current state should be set to the moment of impact. -================ -*/ -bool idPhysics_RigidBody::CollisionImpulse( const trace_t &collision, idVec3 &impulse ) { - idVec3 r, linearVelocity, angularVelocity, velocity; - idMat3 inverseWorldInertiaTensor; - float impulseNumerator, impulseDenominator, vel; - impactInfo_t info; - idEntity *ent; - - // get info from other entity involved - ent = gameLocal.entities[collision.c.entityNum]; - ent->GetImpactInfo( self, collision.c.id, collision.c.point, &info ); - - // collision point relative to the body center of mass - r = collision.c.point - ( current.i.position + centerOfMass * current.i.orientation ); - // the velocity at the collision point - linearVelocity = inverseMass * current.i.linearMomentum; - inverseWorldInertiaTensor = current.i.orientation.Transpose() * inverseInertiaTensor * current.i.orientation; - angularVelocity = inverseWorldInertiaTensor * current.i.angularMomentum; - velocity = linearVelocity + angularVelocity.Cross(r); - // subtract velocity of other entity - velocity -= info.velocity; - - // velocity in normal direction - vel = velocity * collision.c.normal; - - if ( vel > -STOP_SPEED ) { - impulseNumerator = STOP_SPEED; - } - else { - impulseNumerator = -( 1.0f + bouncyness ) * vel; - } - impulseDenominator = inverseMass + ( ( inverseWorldInertiaTensor * r.Cross( collision.c.normal ) ).Cross( r ) * collision.c.normal ); - if ( info.invMass ) { - impulseDenominator += info.invMass + ( ( info.invInertiaTensor * info.position.Cross( collision.c.normal ) ).Cross( info.position ) * collision.c.normal ); - } - impulse = (impulseNumerator / impulseDenominator) * collision.c.normal; - - // update linear and angular momentum with impulse - current.i.linearMomentum += impulse; - current.i.angularMomentum += r.Cross(impulse); - - // if no movement at all don't blow up - if ( collision.fraction < 0.0001f ) { - current.i.linearMomentum *= 0.5f; - current.i.angularMomentum *= 0.5f; - } - - // callback to self to let the entity know about the collision - return self->Collide( collision, velocity ); -} - -/* -================ -idPhysics_RigidBody::CheckForCollisions - - Check for collisions between the current and next state. - If there is a collision the next state is set to the state at the moment of impact. -================ -*/ -bool idPhysics_RigidBody::CheckForCollisions( const float deltaTime, rigidBodyPState_t &next, trace_t &collision ) { -//#define TEST_COLLISION_DETECTION - idMat3 axis; - idRotation rotation; - bool collided = false; - -#ifdef TEST_COLLISION_DETECTION - bool startsolid; - if ( gameLocal.clip.Contents( current.i.position, clipModel, current.i.orientation, clipMask, self ) ) { - startsolid = true; - } -#endif - - TransposeMultiply( current.i.orientation, next.i.orientation, axis ); - rotation = axis.ToRotation(); - rotation.SetOrigin( current.i.position ); - - // if there was a collision - if ( gameLocal.clip.Motion( collision, current.i.position, next.i.position, rotation, clipModel, current.i.orientation, clipMask, self ) ) { - // set the next state to the state at the moment of impact - next.i.position = collision.endpos; - next.i.orientation = collision.endAxis; - next.i.linearMomentum = current.i.linearMomentum; - next.i.angularMomentum = current.i.angularMomentum; - collided = true; - } - -#ifdef TEST_COLLISION_DETECTION - if ( gameLocal.clip.Contents( next.i.position, clipModel, next.i.orientation, clipMask, self ) ) { - if ( !startsolid ) { - int bah = 1; - } - } -#endif - return collided; -} - -/* -================ -idPhysics_RigidBody::ContactFriction - - Does not solve friction for multiple simultaneous contacts but applies contact friction in isolation. - Uses absolute velocity at the contact points instead of the velocity relative to the contact object. -================ -*/ -void idPhysics_RigidBody::ContactFriction( float deltaTime ) { - int i; - float magnitude, impulseNumerator, impulseDenominator; - idMat3 inverseWorldInertiaTensor; - idVec3 linearVelocity, angularVelocity; - idVec3 massCenter, r, velocity, normal, impulse, normalVelocity; - - inverseWorldInertiaTensor = current.i.orientation.Transpose() * inverseInertiaTensor * current.i.orientation; - - massCenter = current.i.position + centerOfMass * current.i.orientation; - - for ( i = 0; i < contacts.Num(); i++ ) { - - r = contacts[i].point - massCenter; - - // calculate velocity at contact point - linearVelocity = inverseMass * current.i.linearMomentum; - angularVelocity = inverseWorldInertiaTensor * current.i.angularMomentum; - velocity = linearVelocity + angularVelocity.Cross(r); - - // velocity along normal vector - normalVelocity = ( velocity * contacts[i].normal ) * contacts[i].normal; - - // calculate friction impulse - normal = -( velocity - normalVelocity ); - magnitude = normal.Normalize(); - impulseNumerator = contactFriction * magnitude; - impulseDenominator = inverseMass + ( ( inverseWorldInertiaTensor * r.Cross( normal ) ).Cross( r ) * normal ); - impulse = (impulseNumerator / impulseDenominator) * normal; - - // apply friction impulse - current.i.linearMomentum += impulse; - current.i.angularMomentum += r.Cross(impulse); - - // if moving towards the surface at the contact point - if ( normalVelocity * contacts[i].normal < 0.0f ) { - // calculate impulse - normal = -normalVelocity; - impulseNumerator = normal.Normalize(); - impulseDenominator = inverseMass + ( ( inverseWorldInertiaTensor * r.Cross( normal ) ).Cross( r ) * normal ); - impulse = (impulseNumerator / impulseDenominator) * normal; - - // apply impulse - current.i.linearMomentum += impulse; - current.i.angularMomentum += r.Cross( impulse ); - } - } -} - -/* -================ -idPhysics_RigidBody::TestIfAtRest - - Returns true if the body is considered at rest. - Does not catch all cases where the body is at rest but is generally good enough. -================ -*/ -bool idPhysics_RigidBody::TestIfAtRest( void ) const { - int i; - float gv; - idVec3 v, av, normal, point; - idMat3 inverseWorldInertiaTensor; - idFixedWinding contactWinding; - - if ( current.atRest >= 0 ) { - return true; - } - - // need at least 3 contact points to come to rest - if ( contacts.Num() < 3 ) { - return false; - } - - // get average contact plane normal - normal.Zero(); - for ( i = 0; i < contacts.Num(); i++ ) { - normal += contacts[i].normal; - } - normal /= (float) contacts.Num(); - normal.Normalize(); - - // if on a too steep surface - if ( (normal * gravityNormal) > -0.7f ) { - return false; - } - - // create bounds for contact points - contactWinding.Clear(); - for ( i = 0; i < contacts.Num(); i++ ) { - // project point onto plane through origin orthogonal to the gravity - point = contacts[i].point - (contacts[i].point * gravityNormal) * gravityNormal; - contactWinding.AddToConvexHull( point, gravityNormal ); - } - - // need at least 3 contact points to come to rest - if ( contactWinding.GetNumPoints() < 3 ) { - return false; - } - - // center of mass in world space - point = current.i.position + centerOfMass * current.i.orientation; - point -= (point * gravityNormal) * gravityNormal; - - // if the point is not inside the winding - if ( !contactWinding.PointInside( gravityNormal, point, 0 ) ) { - return false; - } - - // linear velocity of body - v = inverseMass * current.i.linearMomentum; - // linear velocity in gravity direction - gv = v * gravityNormal; - // linear velocity orthogonal to gravity direction - v -= gv * gravityNormal; - - // if too much velocity orthogonal to gravity direction - if ( v.Length() > STOP_SPEED ) { - return false; - } - // if too much velocity in gravity direction - if ( gv > 2.0f * STOP_SPEED || gv < -2.0f * STOP_SPEED ) { - return false; - } - - // calculate rotational velocity - inverseWorldInertiaTensor = current.i.orientation * inverseInertiaTensor * current.i.orientation.Transpose(); - av = inverseWorldInertiaTensor * current.i.angularMomentum; - - // if too much rotational velocity - if ( av.LengthSqr() > STOP_SPEED ) { - return false; - } - - return true; -} - -/* -================ -idPhysics_RigidBody::DropToFloorAndRest - - Drops the object straight down to the floor and verifies if the object is at rest on the floor. -================ -*/ -void idPhysics_RigidBody::DropToFloorAndRest( void ) { - idVec3 down; - trace_t tr; - - if ( testSolid ) { - - testSolid = false; - - if ( gameLocal.clip.Contents( current.i.position, clipModel, current.i.orientation, clipMask, self ) ) { - gameLocal.DWarning( "rigid body in solid for entity '%s' type '%s' at (%s)", - self->name.c_str(), self->GetType()->classname, current.i.position.ToString(0) ); - Rest(); - dropToFloor = false; - return; - } - } - - // put the body on the floor - down = current.i.position + gravityNormal * 128.0f; - gameLocal.clip.Translation( tr, current.i.position, down, clipModel, current.i.orientation, clipMask, self ); - current.i.position = tr.endpos; - clipModel->Link( gameLocal.clip, self, clipModel->GetId(), tr.endpos, current.i.orientation ); - - // if on the floor already - if ( tr.fraction == 0.0f ) { - // test if we are really at rest - EvaluateContacts(); - if ( !TestIfAtRest() ) { - gameLocal.DWarning( "rigid body not at rest for entity '%s' type '%s' at (%s)", - self->name.c_str(), self->GetType()->classname, current.i.position.ToString(0) ); - } - Rest(); - dropToFloor = false; - } else if ( IsOutsideWorld() ) { - gameLocal.Warning( "rigid body outside world bounds for entity '%s' type '%s' at (%s)", - self->name.c_str(), self->GetType()->classname, current.i.position.ToString(0) ); - Rest(); - dropToFloor = false; - } -} - -/* -================ -idPhysics_RigidBody::DebugDraw -================ -*/ -void idPhysics_RigidBody::DebugDraw( void ) { - - if ( rb_showBodies.GetBool() || ( rb_showActive.GetBool() && current.atRest < 0 ) ) { - collisionModelManager->DrawModel( clipModel->Handle(), clipModel->GetOrigin(), clipModel->GetAxis(), vec3_origin, 0.0f ); - } - - if ( rb_showMass.GetBool() ) { - gameRenderWorld->DrawText( va( "\n%1.2f", mass ), current.i.position, 0.08f, colorCyan, gameLocal.GetLocalPlayer()->viewAngles.ToMat3(), 1 ); - } - - if ( rb_showInertia.GetBool() ) { - idMat3 &I = inertiaTensor; - gameRenderWorld->DrawText( va( "\n\n\n( %.1f %.1f %.1f )\n( %.1f %.1f %.1f )\n( %.1f %.1f %.1f )", - I[0].x, I[0].y, I[0].z, - I[1].x, I[1].y, I[1].z, - I[2].x, I[2].y, I[2].z ), - current.i.position, 0.05f, colorCyan, gameLocal.GetLocalPlayer()->viewAngles.ToMat3(), 1 ); - } - - if ( rb_showVelocity.GetBool() ) { - DrawVelocity( clipModel->GetId(), 0.1f, 4.0f ); - } -} - -/* -================ -idPhysics_RigidBody::idPhysics_RigidBody -================ -*/ -idPhysics_RigidBody::idPhysics_RigidBody( void ) { - - // set default rigid body properties - SetClipMask( MASK_SOLID ); - SetBouncyness( 0.6f ); - SetFriction( 0.6f, 0.6f, 0.0f ); - clipModel = NULL; - - memset( ¤t, 0, sizeof( current ) ); - - current.atRest = -1; - current.lastTimeStep = USERCMD_MSEC; - - current.i.position.Zero(); - current.i.orientation.Identity(); - - current.i.linearMomentum.Zero(); - current.i.angularMomentum.Zero(); - - saved = current; - - mass = 1.0f; - inverseMass = 1.0f; - centerOfMass.Zero(); - inertiaTensor.Identity(); - inverseInertiaTensor.Identity(); - - // use the least expensive euler integrator - integrator = new idODE_Euler( sizeof(rigidBodyIState_t) / sizeof(float), RigidBodyDerivatives, this ); - - dropToFloor = false; - noImpact = false; - noContact = false; - - hasMaster = false; - isOrientated = false; - -#ifdef RB_TIMINGS - lastTimerReset = 0; -#endif -} - -/* -================ -idPhysics_RigidBody::~idPhysics_RigidBody -================ -*/ -idPhysics_RigidBody::~idPhysics_RigidBody( void ) { - if ( clipModel ) { - delete clipModel; - clipModel = NULL; - } - delete integrator; -} - -/* -================ -idPhysics_RigidBody_SavePState -================ -*/ -void idPhysics_RigidBody_SavePState( idSaveGame *savefile, const rigidBodyPState_t &state ) { - savefile->WriteInt( state.atRest ); - savefile->WriteFloat( state.lastTimeStep ); - savefile->WriteVec3( state.localOrigin ); - savefile->WriteMat3( state.localAxis ); - savefile->WriteVec6( state.pushVelocity ); - savefile->WriteVec3( state.externalForce ); - savefile->WriteVec3( state.externalTorque ); - - savefile->WriteVec3( state.i.position ); - savefile->WriteMat3( state.i.orientation ); - savefile->WriteVec3( state.i.linearMomentum ); - savefile->WriteVec3( state.i.angularMomentum ); -} - -/* -================ -idPhysics_RigidBody_RestorePState -================ -*/ -void idPhysics_RigidBody_RestorePState( idRestoreGame *savefile, rigidBodyPState_t &state ) { - savefile->ReadInt( state.atRest ); - savefile->ReadFloat( state.lastTimeStep ); - savefile->ReadVec3( state.localOrigin ); - savefile->ReadMat3( state.localAxis ); - savefile->ReadVec6( state.pushVelocity ); - savefile->ReadVec3( state.externalForce ); - savefile->ReadVec3( state.externalTorque ); - - savefile->ReadVec3( state.i.position ); - savefile->ReadMat3( state.i.orientation ); - savefile->ReadVec3( state.i.linearMomentum ); - savefile->ReadVec3( state.i.angularMomentum ); -} - -/* -================ -idPhysics_RigidBody::Save -================ -*/ -void idPhysics_RigidBody::Save( idSaveGame *savefile ) const { - - idPhysics_RigidBody_SavePState( savefile, current ); - idPhysics_RigidBody_SavePState( savefile, saved ); - - savefile->WriteFloat( linearFriction ); - savefile->WriteFloat( angularFriction ); - savefile->WriteFloat( contactFriction ); - savefile->WriteFloat( bouncyness ); - savefile->WriteClipModel( clipModel ); - - savefile->WriteFloat( mass ); - savefile->WriteFloat( inverseMass ); - savefile->WriteVec3( centerOfMass ); - savefile->WriteMat3( inertiaTensor ); - savefile->WriteMat3( inverseInertiaTensor ); - - savefile->WriteBool( dropToFloor ); - savefile->WriteBool( testSolid ); - savefile->WriteBool( noImpact ); - savefile->WriteBool( noContact ); - - savefile->WriteBool( hasMaster ); - savefile->WriteBool( isOrientated ); -} - -/* -================ -idPhysics_RigidBody::Restore -================ -*/ -void idPhysics_RigidBody::Restore( idRestoreGame *savefile ) { - - idPhysics_RigidBody_RestorePState( savefile, current ); - idPhysics_RigidBody_RestorePState( savefile, saved ); - - savefile->ReadFloat( linearFriction ); - savefile->ReadFloat( angularFriction ); - savefile->ReadFloat( contactFriction ); - savefile->ReadFloat( bouncyness ); - savefile->ReadClipModel( clipModel ); - - savefile->ReadFloat( mass ); - savefile->ReadFloat( inverseMass ); - savefile->ReadVec3( centerOfMass ); - savefile->ReadMat3( inertiaTensor ); - savefile->ReadMat3( inverseInertiaTensor ); - - savefile->ReadBool( dropToFloor ); - savefile->ReadBool( testSolid ); - savefile->ReadBool( noImpact ); - savefile->ReadBool( noContact ); - - savefile->ReadBool( hasMaster ); - savefile->ReadBool( isOrientated ); -} - -/* -================ -idPhysics_RigidBody::SetClipModel -================ -*/ -#define MAX_INERTIA_SCALE 10.0f - -void idPhysics_RigidBody::SetClipModel( idClipModel *model, const float density, int id, bool freeOld ) { - int minIndex; - idMat3 inertiaScale; - - assert( self ); - assert( model ); // we need a clip model - assert( model->IsTraceModel() ); // and it should be a trace model - assert( density > 0.0f ); // density should be valid - - if ( clipModel && clipModel != model && freeOld ) { - delete clipModel; - } - clipModel = model; - clipModel->Link( gameLocal.clip, self, 0, current.i.position, current.i.orientation ); - - // get mass properties from the trace model - clipModel->GetMassProperties( density, mass, centerOfMass, inertiaTensor ); - - // check whether or not the clip model has valid mass properties - if ( mass <= 0.0f || FLOAT_IS_NAN( mass ) ) { - gameLocal.Warning( "idPhysics_RigidBody::SetClipModel: invalid mass for entity '%s' type '%s'", - self->name.c_str(), self->GetType()->classname ); - mass = 1.0f; - centerOfMass.Zero(); - inertiaTensor.Identity(); - } - - // check whether or not the inertia tensor is balanced - minIndex = Min3Index( inertiaTensor[0][0], inertiaTensor[1][1], inertiaTensor[2][2] ); - inertiaScale.Identity(); - inertiaScale[0][0] = inertiaTensor[0][0] / inertiaTensor[minIndex][minIndex]; - inertiaScale[1][1] = inertiaTensor[1][1] / inertiaTensor[minIndex][minIndex]; - inertiaScale[2][2] = inertiaTensor[2][2] / inertiaTensor[minIndex][minIndex]; - - if ( inertiaScale[0][0] > MAX_INERTIA_SCALE || inertiaScale[1][1] > MAX_INERTIA_SCALE || inertiaScale[2][2] > MAX_INERTIA_SCALE ) { - gameLocal.DWarning( "idPhysics_RigidBody::SetClipModel: unbalanced inertia tensor for entity '%s' type '%s'", - self->name.c_str(), self->GetType()->classname ); - float min = inertiaTensor[minIndex][minIndex] * MAX_INERTIA_SCALE; - inertiaScale[(minIndex+1)%3][(minIndex+1)%3] = min / inertiaTensor[(minIndex+1)%3][(minIndex+1)%3]; - inertiaScale[(minIndex+2)%3][(minIndex+2)%3] = min / inertiaTensor[(minIndex+2)%3][(minIndex+2)%3]; - inertiaTensor *= inertiaScale; - } - - inverseMass = 1.0f / mass; - inverseInertiaTensor = inertiaTensor.Inverse() * ( 1.0f / 6.0f ); - - current.i.linearMomentum.Zero(); - current.i.angularMomentum.Zero(); -} - -/* -================ -idPhysics_RigidBody::GetClipModel -================ -*/ -idClipModel *idPhysics_RigidBody::GetClipModel( int id ) const { - return clipModel; -} - -/* -================ -idPhysics_RigidBody::GetNumClipModels -================ -*/ -int idPhysics_RigidBody::GetNumClipModels( void ) const { - return 1; -} - -/* -================ -idPhysics_RigidBody::SetMass -================ -*/ -void idPhysics_RigidBody::SetMass( float mass, int id ) { - assert( mass > 0.0f ); - inertiaTensor *= mass / this->mass; - inverseInertiaTensor = inertiaTensor.Inverse() * (1.0f / 6.0f); - this->mass = mass; - inverseMass = 1.0f / mass; -} - -/* -================ -idPhysics_RigidBody::GetMass -================ -*/ -float idPhysics_RigidBody::GetMass( int id ) const { - return mass; -} - -/* -================ -idPhysics_RigidBody::SetFriction -================ -*/ -void idPhysics_RigidBody::SetFriction( const float linear, const float angular, const float contact ) { - if ( linear < 0.0f || linear > 1.0f || - angular < 0.0f || angular > 1.0f || - contact < 0.0f || contact > 1.0f ) { - return; - } - linearFriction = linear; - angularFriction = angular; - contactFriction = contact; -} - -/* -================ -idPhysics_RigidBody::SetBouncyness -================ -*/ -void idPhysics_RigidBody::SetBouncyness( const float b ) { - if ( b < 0.0f || b > 1.0f ) { - return; - } - bouncyness = b; -} - -/* -================ -idPhysics_RigidBody::Rest -================ -*/ -void idPhysics_RigidBody::Rest( void ) { - current.atRest = gameLocal.time; - current.i.linearMomentum.Zero(); - current.i.angularMomentum.Zero(); - self->BecomeInactive( TH_PHYSICS ); -} - -/* -================ -idPhysics_RigidBody::DropToFloor -================ -*/ -void idPhysics_RigidBody::DropToFloor( void ) { - dropToFloor = true; - testSolid = true; -} - -/* -================ -idPhysics_RigidBody::NoContact -================ -*/ -void idPhysics_RigidBody::NoContact( void ) { - noContact = true; -} - -/* -================ -idPhysics_RigidBody::Activate -================ -*/ -void idPhysics_RigidBody::Activate( void ) { - current.atRest = -1; - self->BecomeActive( TH_PHYSICS ); -} - -/* -================ -idPhysics_RigidBody::PutToRest - - put to rest untill something collides with this physics object -================ -*/ -void idPhysics_RigidBody::PutToRest( void ) { - Rest(); -} - -/* -================ -idPhysics_RigidBody::EnableImpact -================ -*/ -void idPhysics_RigidBody::EnableImpact( void ) { - noImpact = false; -} - -/* -================ -idPhysics_RigidBody::DisableImpact -================ -*/ -void idPhysics_RigidBody::DisableImpact( void ) { - noImpact = true; -} - -/* -================ -idPhysics_RigidBody::SetContents -================ -*/ -void idPhysics_RigidBody::SetContents( int contents, int id ) { - clipModel->SetContents( contents ); -} - -/* -================ -idPhysics_RigidBody::GetContents -================ -*/ -int idPhysics_RigidBody::GetContents( int id ) const { - return clipModel->GetContents(); -} - -/* -================ -idPhysics_RigidBody::GetBounds -================ -*/ -const idBounds &idPhysics_RigidBody::GetBounds( int id ) const { - return clipModel->GetBounds(); -} - -/* -================ -idPhysics_RigidBody::GetAbsBounds -================ -*/ -const idBounds &idPhysics_RigidBody::GetAbsBounds( int id ) const { - return clipModel->GetAbsBounds(); -} - -/* -================ -idPhysics_RigidBody::Evaluate - - Evaluate the impulse based rigid body physics. - When a collision occurs an impulse is applied at the moment of impact but - the remaining time after the collision is ignored. -================ -*/ -bool idPhysics_RigidBody::Evaluate( int timeStepMSec, int endTimeMSec ) { - rigidBodyPState_t next; - idAngles angles; - trace_t collision; - idVec3 impulse; - idEntity *ent; - idVec3 oldOrigin, masterOrigin; - idMat3 oldAxis, masterAxis; - float timeStep; - bool collided, cameToRest = false; - - timeStep = MS2SEC( timeStepMSec ); - current.lastTimeStep = timeStep; - - if ( hasMaster ) { - oldOrigin = current.i.position; - oldAxis = current.i.orientation; - self->GetMasterPosition( masterOrigin, masterAxis ); - current.i.position = masterOrigin + current.localOrigin * masterAxis; - if ( isOrientated ) { - current.i.orientation = current.localAxis * masterAxis; - } - else { - current.i.orientation = current.localAxis; - } - clipModel->Link( gameLocal.clip, self, clipModel->GetId(), current.i.position, current.i.orientation ); - current.i.linearMomentum = mass * ( ( current.i.position - oldOrigin ) / timeStep ); - current.i.angularMomentum = inertiaTensor * ( ( current.i.orientation * oldAxis.Transpose() ).ToAngularVelocity() / timeStep ); - current.externalForce.Zero(); - current.externalTorque.Zero(); - - return ( current.i.position != oldOrigin || current.i.orientation != oldAxis ); - } - - // if the body is at rest - if ( current.atRest >= 0 || timeStep <= 0.0f ) { - DebugDraw(); - return false; - } - - // if putting the body to rest - if ( dropToFloor ) { - DropToFloorAndRest(); - current.externalForce.Zero(); - current.externalTorque.Zero(); - return true; - } - -#ifdef RB_TIMINGS - timer_total.Start(); -#endif - - // move the rigid body velocity into the frame of a pusher -// current.i.linearMomentum -= current.pushVelocity.SubVec3( 0 ) * mass; -// current.i.angularMomentum -= current.pushVelocity.SubVec3( 1 ) * inertiaTensor; - - clipModel->Unlink(); - - next = current; - - // calculate next position and orientation - Integrate( timeStep, next ); - -#ifdef RB_TIMINGS - timer_collision.Start(); -#endif - - // check for collisions from the current to the next state - collided = CheckForCollisions( timeStep, next, collision ); - -#ifdef RB_TIMINGS - timer_collision.Stop(); -#endif - - // set the new state - current = next; - - if ( collided ) { - // apply collision impulse - if ( CollisionImpulse( collision, impulse ) ) { - current.atRest = gameLocal.time; - } - } - - // update the position of the clip model - clipModel->Link( gameLocal.clip, self, clipModel->GetId(), current.i.position, current.i.orientation ); - - DebugDraw(); - - if ( !noContact ) { - -#ifdef RB_TIMINGS - timer_collision.Start(); -#endif - // get contacts - EvaluateContacts(); - -#ifdef RB_TIMINGS - timer_collision.Stop(); -#endif - - // check if the body has come to rest - if ( TestIfAtRest() ) { - // put to rest - Rest(); - cameToRest = true; - } else { - // apply contact friction - ContactFriction( timeStep ); - } - } - - if ( current.atRest < 0 ) { - ActivateContactEntities(); - } - - if ( collided ) { - // if the rigid body didn't come to rest or the other entity is not at rest - ent = gameLocal.entities[collision.c.entityNum]; - if ( ent && ( !cameToRest || !ent->IsAtRest() ) ) { - // apply impact to other entity - ent->ApplyImpulse( self, collision.c.id, collision.c.point, -impulse ); - } - } - - // move the rigid body velocity back into the world frame -// current.i.linearMomentum += current.pushVelocity.SubVec3( 0 ) * mass; -// current.i.angularMomentum += current.pushVelocity.SubVec3( 1 ) * inertiaTensor; - current.pushVelocity.Zero(); - - current.lastTimeStep = timeStep; - current.externalForce.Zero(); - current.externalTorque.Zero(); - - if ( IsOutsideWorld() ) { - gameLocal.Warning( "rigid body moved outside world bounds for entity '%s' type '%s' at (%s)", - self->name.c_str(), self->GetType()->classname, current.i.position.ToString(0) ); - Rest(); - } - -#ifdef RB_TIMINGS - timer_total.Stop(); - - if ( rb_showTimings->integer == 1 ) { - gameLocal.Printf( "%12s: t %u cd %u\n", - self->name.c_str(), - timer_total.Milliseconds(), timer_collision.Milliseconds() ); - lastTimerReset = 0; - } - else if ( rb_showTimings->integer == 2 ) { - numRigidBodies++; - if ( endTimeMSec > lastTimerReset ) { - gameLocal.Printf( "rb %d: t %u cd %u\n", - numRigidBodies, - timer_total.Milliseconds(), timer_collision.Milliseconds() ); - } - } - if ( endTimeMSec > lastTimerReset ) { - lastTimerReset = endTimeMSec; - numRigidBodies = 0; - timer_total.Clear(); - timer_collision.Clear(); - } -#endif - - return true; -} - -/* -================ -idPhysics_RigidBody::UpdateTime -================ -*/ -void idPhysics_RigidBody::UpdateTime( int endTimeMSec ) { -} - -/* -================ -idPhysics_RigidBody::GetTime -================ -*/ -int idPhysics_RigidBody::GetTime( void ) const { - return gameLocal.time; -} - -/* -================ -idPhysics_RigidBody::GetImpactInfo -================ -*/ -void idPhysics_RigidBody::GetImpactInfo( const int id, const idVec3 &point, impactInfo_t *info ) const { - idVec3 linearVelocity, angularVelocity; - idMat3 inverseWorldInertiaTensor; - - linearVelocity = inverseMass * current.i.linearMomentum; - inverseWorldInertiaTensor = current.i.orientation.Transpose() * inverseInertiaTensor * current.i.orientation; - angularVelocity = inverseWorldInertiaTensor * current.i.angularMomentum; - - info->invMass = inverseMass; - info->invInertiaTensor = inverseWorldInertiaTensor; - info->position = point - ( current.i.position + centerOfMass * current.i.orientation ); - info->velocity = linearVelocity + angularVelocity.Cross( info->position ); -} - -/* -================ -idPhysics_RigidBody::ApplyImpulse -================ -*/ -void idPhysics_RigidBody::ApplyImpulse( const int id, const idVec3 &point, const idVec3 &impulse ) { - if ( noImpact ) { - return; - } - current.i.linearMomentum += impulse; - current.i.angularMomentum += ( point - ( current.i.position + centerOfMass * current.i.orientation ) ).Cross( impulse ); - Activate(); -} - -/* -================ -idPhysics_RigidBody::AddForce -================ -*/ -void idPhysics_RigidBody::AddForce( const int id, const idVec3 &point, const idVec3 &force ) { - if ( noImpact ) { - return; - } - current.externalForce += force; - current.externalTorque += ( point - ( current.i.position + centerOfMass * current.i.orientation ) ).Cross( force ); - Activate(); -} - -/* -================ -idPhysics_RigidBody::IsAtRest -================ -*/ -bool idPhysics_RigidBody::IsAtRest( void ) const { - return current.atRest >= 0; -} - -/* -================ -idPhysics_RigidBody::GetRestStartTime -================ -*/ -int idPhysics_RigidBody::GetRestStartTime( void ) const { - return current.atRest; -} - -/* -================ -idPhysics_RigidBody::IsPushable -================ -*/ -bool idPhysics_RigidBody::IsPushable( void ) const { - return ( !noImpact && !hasMaster ); -} - -/* -================ -idPhysics_RigidBody::SaveState -================ -*/ -void idPhysics_RigidBody::SaveState( void ) { - saved = current; -} - -/* -================ -idPhysics_RigidBody::RestoreState -================ -*/ -void idPhysics_RigidBody::RestoreState( void ) { - current = saved; - - clipModel->Link( gameLocal.clip, self, clipModel->GetId(), current.i.position, current.i.orientation ); - - EvaluateContacts(); -} - -/* -================ -idPhysics::SetOrigin -================ -*/ -void idPhysics_RigidBody::SetOrigin( const idVec3 &newOrigin, int id ) { - idVec3 masterOrigin; - idMat3 masterAxis; - - current.localOrigin = newOrigin; - if ( hasMaster ) { - self->GetMasterPosition( masterOrigin, masterAxis ); - current.i.position = masterOrigin + newOrigin * masterAxis; - } - else { - current.i.position = newOrigin; - } - - clipModel->Link( gameLocal.clip, self, clipModel->GetId(), current.i.position, clipModel->GetAxis() ); - - Activate(); -} - -/* -================ -idPhysics::SetAxis -================ -*/ -void idPhysics_RigidBody::SetAxis( const idMat3 &newAxis, int id ) { - idVec3 masterOrigin; - idMat3 masterAxis; - - current.localAxis = newAxis; - if ( hasMaster && isOrientated ) { - self->GetMasterPosition( masterOrigin, masterAxis ); - current.i.orientation = newAxis * masterAxis; - } - else { - current.i.orientation = newAxis; - } - - clipModel->Link( gameLocal.clip, self, clipModel->GetId(), clipModel->GetOrigin(), current.i.orientation ); - - Activate(); -} - -/* -================ -idPhysics::Move -================ -*/ -void idPhysics_RigidBody::Translate( const idVec3 &translation, int id ) { - - current.localOrigin += translation; - current.i.position += translation; - - clipModel->Link( gameLocal.clip, self, clipModel->GetId(), current.i.position, clipModel->GetAxis() ); - - Activate(); -} - -/* -================ -idPhysics::Rotate -================ -*/ -void idPhysics_RigidBody::Rotate( const idRotation &rotation, int id ) { - idVec3 masterOrigin; - idMat3 masterAxis; - - current.i.orientation *= rotation.ToMat3(); - current.i.position *= rotation; - - if ( hasMaster ) { - self->GetMasterPosition( masterOrigin, masterAxis ); - current.localAxis *= rotation.ToMat3(); - current.localOrigin = ( current.i.position - masterOrigin ) * masterAxis.Transpose(); - } - else { - current.localAxis = current.i.orientation; - current.localOrigin = current.i.position; - } - - clipModel->Link( gameLocal.clip, self, clipModel->GetId(), current.i.position, current.i.orientation ); - - Activate(); -} - -/* -================ -idPhysics_RigidBody::GetOrigin -================ -*/ -const idVec3 &idPhysics_RigidBody::GetOrigin( int id ) const { - return current.i.position; -} - -/* -================ -idPhysics_RigidBody::GetAxis -================ -*/ -const idMat3 &idPhysics_RigidBody::GetAxis( int id ) const { - return current.i.orientation; -} - -/* -================ -idPhysics_RigidBody::SetLinearVelocity -================ -*/ -void idPhysics_RigidBody::SetLinearVelocity( const idVec3 &newLinearVelocity, int id ) { - current.i.linearMomentum = newLinearVelocity * mass; - Activate(); -} - -/* -================ -idPhysics_RigidBody::SetAngularVelocity -================ -*/ -void idPhysics_RigidBody::SetAngularVelocity( const idVec3 &newAngularVelocity, int id ) { - current.i.angularMomentum = newAngularVelocity * inertiaTensor; - Activate(); -} - -/* -================ -idPhysics_RigidBody::GetLinearVelocity -================ -*/ -const idVec3 &idPhysics_RigidBody::GetLinearVelocity( int id ) const { - static idVec3 curLinearVelocity; - curLinearVelocity = current.i.linearMomentum * inverseMass; - return curLinearVelocity; -} - -/* -================ -idPhysics_RigidBody::GetAngularVelocity -================ -*/ -const idVec3 &idPhysics_RigidBody::GetAngularVelocity( int id ) const { - static idVec3 curAngularVelocity; - idMat3 inverseWorldInertiaTensor; - - inverseWorldInertiaTensor = current.i.orientation.Transpose() * inverseInertiaTensor * current.i.orientation; - curAngularVelocity = inverseWorldInertiaTensor * current.i.angularMomentum; - return curAngularVelocity; -} - -/* -================ -idPhysics_RigidBody::ClipTranslation -================ -*/ -void idPhysics_RigidBody::ClipTranslation( trace_t &results, const idVec3 &translation, const idClipModel *model ) const { - if ( model ) { - gameLocal.clip.TranslationModel( results, clipModel->GetOrigin(), clipModel->GetOrigin() + translation, - clipModel, clipModel->GetAxis(), clipMask, - model->Handle(), model->GetOrigin(), model->GetAxis() ); - } - else { - gameLocal.clip.Translation( results, clipModel->GetOrigin(), clipModel->GetOrigin() + translation, - clipModel, clipModel->GetAxis(), clipMask, self ); - } -} - -/* -================ -idPhysics_RigidBody::ClipRotation -================ -*/ -void idPhysics_RigidBody::ClipRotation( trace_t &results, const idRotation &rotation, const idClipModel *model ) const { - if ( model ) { - gameLocal.clip.RotationModel( results, clipModel->GetOrigin(), rotation, - clipModel, clipModel->GetAxis(), clipMask, - model->Handle(), model->GetOrigin(), model->GetAxis() ); - } - else { - gameLocal.clip.Rotation( results, clipModel->GetOrigin(), rotation, - clipModel, clipModel->GetAxis(), clipMask, self ); - } -} - -/* -================ -idPhysics_RigidBody::ClipContents -================ -*/ -int idPhysics_RigidBody::ClipContents( const idClipModel *model ) const { - if ( model ) { - return gameLocal.clip.ContentsModel( clipModel->GetOrigin(), clipModel, clipModel->GetAxis(), -1, - model->Handle(), model->GetOrigin(), model->GetAxis() ); - } - else { - return gameLocal.clip.Contents( clipModel->GetOrigin(), clipModel, clipModel->GetAxis(), -1, NULL ); - } -} - -/* -================ -idPhysics_RigidBody::DisableClip -================ -*/ -void idPhysics_RigidBody::DisableClip( void ) { - clipModel->Disable(); -} - -/* -================ -idPhysics_RigidBody::EnableClip -================ -*/ -void idPhysics_RigidBody::EnableClip( void ) { - clipModel->Enable(); -} - -/* -================ -idPhysics_RigidBody::UnlinkClip -================ -*/ -void idPhysics_RigidBody::UnlinkClip( void ) { - clipModel->Unlink(); -} - -/* -================ -idPhysics_RigidBody::LinkClip -================ -*/ -void idPhysics_RigidBody::LinkClip( void ) { - clipModel->Link( gameLocal.clip, self, clipModel->GetId(), current.i.position, current.i.orientation ); -} - -/* -================ -idPhysics_RigidBody::EvaluateContacts -================ -*/ -bool idPhysics_RigidBody::EvaluateContacts( void ) { - idVec6 dir; - int num; - - ClearContacts(); - - contacts.SetNum( 10, false ); - - dir.SubVec3(0) = current.i.linearMomentum + current.lastTimeStep * gravityVector * mass; - dir.SubVec3(1) = current.i.angularMomentum; - dir.SubVec3(0).Normalize(); - dir.SubVec3(1).Normalize(); - num = gameLocal.clip.Contacts( &contacts[0], 10, clipModel->GetOrigin(), - dir, CONTACT_EPSILON, clipModel, clipModel->GetAxis(), clipMask, self ); - contacts.SetNum( num, false ); - - AddContactEntitiesForContacts(); - - return ( contacts.Num() != 0 ); -} - -/* -================ -idPhysics_RigidBody::SetPushed -================ -*/ -void idPhysics_RigidBody::SetPushed( int deltaTime ) { - idRotation rotation; - - rotation = ( saved.i.orientation * current.i.orientation ).ToRotation(); - - // velocity with which the af is pushed - current.pushVelocity.SubVec3(0) += ( current.i.position - saved.i.position ) / ( deltaTime * idMath::M_MS2SEC ); - current.pushVelocity.SubVec3(1) += rotation.GetVec() * -DEG2RAD( rotation.GetAngle() ) / ( deltaTime * idMath::M_MS2SEC ); -} - -/* -================ -idPhysics_RigidBody::GetPushedLinearVelocity -================ -*/ -const idVec3 &idPhysics_RigidBody::GetPushedLinearVelocity( const int id ) const { - return current.pushVelocity.SubVec3(0); -} - -/* -================ -idPhysics_RigidBody::GetPushedAngularVelocity -================ -*/ -const idVec3 &idPhysics_RigidBody::GetPushedAngularVelocity( const int id ) const { - return current.pushVelocity.SubVec3(1); -} - -/* -================ -idPhysics_RigidBody::SetMaster -================ -*/ -void idPhysics_RigidBody::SetMaster( idEntity *master, const bool orientated ) { - idVec3 masterOrigin; - idMat3 masterAxis; - - if ( master ) { - if ( !hasMaster ) { - // transform from world space to master space - self->GetMasterPosition( masterOrigin, masterAxis ); - current.localOrigin = ( current.i.position - masterOrigin ) * masterAxis.Transpose(); - if ( orientated ) { - current.localAxis = current.i.orientation * masterAxis.Transpose(); - } - else { - current.localAxis = current.i.orientation; - } - hasMaster = true; - isOrientated = orientated; - ClearContacts(); - } - } - else { - if ( hasMaster ) { - hasMaster = false; - Activate(); - } - } -} - -const float RB_VELOCITY_MAX = 16000; -const int RB_VELOCITY_TOTAL_BITS = 16; -const int RB_VELOCITY_EXPONENT_BITS = idMath::BitsForInteger( idMath::BitsForFloat( RB_VELOCITY_MAX ) ) + 1; -const int RB_VELOCITY_MANTISSA_BITS = RB_VELOCITY_TOTAL_BITS - 1 - RB_VELOCITY_EXPONENT_BITS; -const float RB_MOMENTUM_MAX = 1e20f; -const int RB_MOMENTUM_TOTAL_BITS = 16; -const int RB_MOMENTUM_EXPONENT_BITS = idMath::BitsForInteger( idMath::BitsForFloat( RB_MOMENTUM_MAX ) ) + 1; -const int RB_MOMENTUM_MANTISSA_BITS = RB_MOMENTUM_TOTAL_BITS - 1 - RB_MOMENTUM_EXPONENT_BITS; -const float RB_FORCE_MAX = 1e20f; -const int RB_FORCE_TOTAL_BITS = 16; -const int RB_FORCE_EXPONENT_BITS = idMath::BitsForInteger( idMath::BitsForFloat( RB_FORCE_MAX ) ) + 1; -const int RB_FORCE_MANTISSA_BITS = RB_FORCE_TOTAL_BITS - 1 - RB_FORCE_EXPONENT_BITS; - -/* -================ -idPhysics_RigidBody::WriteToSnapshot -================ -*/ -void idPhysics_RigidBody::WriteToSnapshot( idBitMsgDelta &msg ) const { - idCQuat quat, localQuat; - - quat = current.i.orientation.ToCQuat(); - localQuat = current.localAxis.ToCQuat(); - - msg.WriteInt( current.atRest ); - msg.WriteFloat( current.i.position[0] ); - msg.WriteFloat( current.i.position[1] ); - msg.WriteFloat( current.i.position[2] ); - msg.WriteFloat( quat.x ); - msg.WriteFloat( quat.y ); - msg.WriteFloat( quat.z ); - msg.WriteFloat( current.i.linearMomentum[0], RB_MOMENTUM_EXPONENT_BITS, RB_MOMENTUM_MANTISSA_BITS ); - msg.WriteFloat( current.i.linearMomentum[1], RB_MOMENTUM_EXPONENT_BITS, RB_MOMENTUM_MANTISSA_BITS ); - msg.WriteFloat( current.i.linearMomentum[2], RB_MOMENTUM_EXPONENT_BITS, RB_MOMENTUM_MANTISSA_BITS ); - msg.WriteFloat( current.i.angularMomentum[0], RB_MOMENTUM_EXPONENT_BITS, RB_MOMENTUM_MANTISSA_BITS ); - msg.WriteFloat( current.i.angularMomentum[1], RB_MOMENTUM_EXPONENT_BITS, RB_MOMENTUM_MANTISSA_BITS ); - msg.WriteFloat( current.i.angularMomentum[2], RB_MOMENTUM_EXPONENT_BITS, RB_MOMENTUM_MANTISSA_BITS ); - msg.WriteDeltaFloat( current.i.position[0], current.localOrigin[0] ); - msg.WriteDeltaFloat( current.i.position[1], current.localOrigin[1] ); - msg.WriteDeltaFloat( current.i.position[2], current.localOrigin[2] ); - msg.WriteDeltaFloat( quat.x, localQuat.x ); - msg.WriteDeltaFloat( quat.y, localQuat.y ); - msg.WriteDeltaFloat( quat.z, localQuat.z ); - msg.WriteDeltaFloat( 0.0f, current.pushVelocity[0], RB_VELOCITY_EXPONENT_BITS, RB_VELOCITY_MANTISSA_BITS ); - msg.WriteDeltaFloat( 0.0f, current.pushVelocity[1], RB_VELOCITY_EXPONENT_BITS, RB_VELOCITY_MANTISSA_BITS ); - msg.WriteDeltaFloat( 0.0f, current.pushVelocity[2], RB_VELOCITY_EXPONENT_BITS, RB_VELOCITY_MANTISSA_BITS ); - msg.WriteDeltaFloat( 0.0f, current.externalForce[0], RB_FORCE_EXPONENT_BITS, RB_FORCE_MANTISSA_BITS ); - msg.WriteDeltaFloat( 0.0f, current.externalForce[1], RB_FORCE_EXPONENT_BITS, RB_FORCE_MANTISSA_BITS ); - msg.WriteDeltaFloat( 0.0f, current.externalForce[2], RB_FORCE_EXPONENT_BITS, RB_FORCE_MANTISSA_BITS ); - msg.WriteDeltaFloat( 0.0f, current.externalTorque[0], RB_FORCE_EXPONENT_BITS, RB_FORCE_MANTISSA_BITS ); - msg.WriteDeltaFloat( 0.0f, current.externalTorque[1], RB_FORCE_EXPONENT_BITS, RB_FORCE_MANTISSA_BITS ); - msg.WriteDeltaFloat( 0.0f, current.externalTorque[2], RB_FORCE_EXPONENT_BITS, RB_FORCE_MANTISSA_BITS ); -} - -/* -================ -idPhysics_RigidBody::ReadFromSnapshot -================ -*/ -void idPhysics_RigidBody::ReadFromSnapshot( const idBitMsgDelta &msg ) { - idCQuat quat, localQuat; - - current.atRest = msg.ReadInt(); - current.i.position[0] = msg.ReadFloat(); - current.i.position[1] = msg.ReadFloat(); - current.i.position[2] = msg.ReadFloat(); - quat.x = msg.ReadFloat(); - quat.y = msg.ReadFloat(); - quat.z = msg.ReadFloat(); - current.i.linearMomentum[0] = msg.ReadFloat( RB_MOMENTUM_EXPONENT_BITS, RB_MOMENTUM_MANTISSA_BITS ); - current.i.linearMomentum[1] = msg.ReadFloat( RB_MOMENTUM_EXPONENT_BITS, RB_MOMENTUM_MANTISSA_BITS ); - current.i.linearMomentum[2] = msg.ReadFloat( RB_MOMENTUM_EXPONENT_BITS, RB_MOMENTUM_MANTISSA_BITS ); - current.i.angularMomentum[0] = msg.ReadFloat( RB_MOMENTUM_EXPONENT_BITS, RB_MOMENTUM_MANTISSA_BITS ); - current.i.angularMomentum[1] = msg.ReadFloat( RB_MOMENTUM_EXPONENT_BITS, RB_MOMENTUM_MANTISSA_BITS ); - current.i.angularMomentum[2] = msg.ReadFloat( RB_MOMENTUM_EXPONENT_BITS, RB_MOMENTUM_MANTISSA_BITS ); - current.localOrigin[0] = msg.ReadDeltaFloat( current.i.position[0] ); - current.localOrigin[1] = msg.ReadDeltaFloat( current.i.position[1] ); - current.localOrigin[2] = msg.ReadDeltaFloat( current.i.position[2] ); - localQuat.x = msg.ReadDeltaFloat( quat.x ); - localQuat.y = msg.ReadDeltaFloat( quat.y ); - localQuat.z = msg.ReadDeltaFloat( quat.z ); - current.pushVelocity[0] = msg.ReadDeltaFloat( 0.0f, RB_VELOCITY_EXPONENT_BITS, RB_VELOCITY_MANTISSA_BITS ); - current.pushVelocity[1] = msg.ReadDeltaFloat( 0.0f, RB_VELOCITY_EXPONENT_BITS, RB_VELOCITY_MANTISSA_BITS ); - current.pushVelocity[2] = msg.ReadDeltaFloat( 0.0f, RB_VELOCITY_EXPONENT_BITS, RB_VELOCITY_MANTISSA_BITS ); - current.externalForce[0] = msg.ReadDeltaFloat( 0.0f, RB_FORCE_EXPONENT_BITS, RB_FORCE_MANTISSA_BITS ); - current.externalForce[1] = msg.ReadDeltaFloat( 0.0f, RB_FORCE_EXPONENT_BITS, RB_FORCE_MANTISSA_BITS ); - current.externalForce[2] = msg.ReadDeltaFloat( 0.0f, RB_FORCE_EXPONENT_BITS, RB_FORCE_MANTISSA_BITS ); - current.externalTorque[0] = msg.ReadDeltaFloat( 0.0f, RB_FORCE_EXPONENT_BITS, RB_FORCE_MANTISSA_BITS ); - current.externalTorque[1] = msg.ReadDeltaFloat( 0.0f, RB_FORCE_EXPONENT_BITS, RB_FORCE_MANTISSA_BITS ); - current.externalTorque[2] = msg.ReadDeltaFloat( 0.0f, RB_FORCE_EXPONENT_BITS, RB_FORCE_MANTISSA_BITS ); - - current.i.orientation = quat.ToMat3(); - current.localAxis = localQuat.ToMat3(); - - if ( clipModel ) { - clipModel->Link( gameLocal.clip, self, clipModel->GetId(), current.i.position, current.i.orientation ); - } -} diff --git a/d3xp/physics/Physics_RigidBody.h b/d3xp/physics/Physics_RigidBody.h deleted file mode 100644 index d211ebea..00000000 --- a/d3xp/physics/Physics_RigidBody.h +++ /dev/null @@ -1,200 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __PHYSICS_RIGIDBODY_H__ -#define __PHYSICS_RIGIDBODY_H__ - -#include "idlib/math/Ode.h" - -#include "physics/Physics_Base.h" - -/* -=================================================================================== - - Rigid body physics - - Employs an impulse based dynamic simulation which is not very accurate but - relatively fast and still reliable due to the continuous collision detection. - -=================================================================================== -*/ - -extern const float RB_VELOCITY_MAX; -extern const int RB_VELOCITY_TOTAL_BITS; -extern const int RB_VELOCITY_EXPONENT_BITS; -extern const int RB_VELOCITY_MANTISSA_BITS; - -typedef struct rididBodyIState_s { - idVec3 position; // position of trace model - idMat3 orientation; // orientation of trace model - idVec3 linearMomentum; // translational momentum relative to center of mass - idVec3 angularMomentum; // rotational momentum relative to center of mass -} rigidBodyIState_t; - -typedef struct rigidBodyPState_s { - int atRest; // set when simulation is suspended - float lastTimeStep; // length of last time step - idVec3 localOrigin; // origin relative to master - idMat3 localAxis; // axis relative to master - idVec6 pushVelocity; // push velocity - idVec3 externalForce; // external force relative to center of mass - idVec3 externalTorque; // external torque relative to center of mass - rigidBodyIState_t i; // state used for integration -} rigidBodyPState_t; - -class idPhysics_RigidBody : public idPhysics_Base { - -public: - - CLASS_PROTOTYPE( idPhysics_RigidBody ); - - idPhysics_RigidBody( void ); - ~idPhysics_RigidBody( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - // initialisation - void SetFriction( const float linear, const float angular, const float contact ); - void SetBouncyness( const float b ); - // same as above but drop to the floor first - void DropToFloor( void ); - // no contact determination and contact friction - void NoContact( void ); - // enable/disable activation by impact - void EnableImpact( void ); - void DisableImpact( void ); - -public: // common physics interface - void SetClipModel( idClipModel *model, float density, int id = 0, bool freeOld = true ); - idClipModel * GetClipModel( int id = 0 ) const; - int GetNumClipModels( void ) const; - - void SetMass( float mass, int id = -1 ); - float GetMass( int id = -1 ) const; - - void SetContents( int contents, int id = -1 ); - int GetContents( int id = -1 ) const; - - const idBounds & GetBounds( int id = -1 ) const; - const idBounds & GetAbsBounds( int id = -1 ) const; - - bool Evaluate( int timeStepMSec, int endTimeMSec ); - void UpdateTime( int endTimeMSec ); - int GetTime( void ) const; - - void GetImpactInfo( const int id, const idVec3 &point, impactInfo_t *info ) const; - void ApplyImpulse( const int id, const idVec3 &point, const idVec3 &impulse ); - void AddForce( const int id, const idVec3 &point, const idVec3 &force ); - void Activate( void ); - void PutToRest( void ); - bool IsAtRest( void ) const; - int GetRestStartTime( void ) const; - bool IsPushable( void ) const; - - void SaveState( void ); - void RestoreState( void ); - - void SetOrigin( const idVec3 &newOrigin, int id = -1 ); - void SetAxis( const idMat3 &newAxis, int id = -1 ); - - void Translate( const idVec3 &translation, int id = -1 ); - void Rotate( const idRotation &rotation, int id = -1 ); - - const idVec3 & GetOrigin( int id = 0 ) const; - const idMat3 & GetAxis( int id = 0 ) const; - - void SetLinearVelocity( const idVec3 &newLinearVelocity, int id = 0 ); - void SetAngularVelocity( const idVec3 &newAngularVelocity, int id = 0 ); - - const idVec3 & GetLinearVelocity( int id = 0 ) const; - const idVec3 & GetAngularVelocity( int id = 0 ) const; - - void ClipTranslation( trace_t &results, const idVec3 &translation, const idClipModel *model ) const; - void ClipRotation( trace_t &results, const idRotation &rotation, const idClipModel *model ) const; - int ClipContents( const idClipModel *model ) const; - - void DisableClip( void ); - void EnableClip( void ); - - void UnlinkClip( void ); - void LinkClip( void ); - - bool EvaluateContacts( void ); - - void SetPushed( int deltaTime ); - const idVec3 & GetPushedLinearVelocity( const int id = 0 ) const; - const idVec3 & GetPushedAngularVelocity( const int id = 0 ) const; - - void SetMaster( idEntity *master, const bool orientated ); - - void WriteToSnapshot( idBitMsgDelta &msg ) const; - void ReadFromSnapshot( const idBitMsgDelta &msg ); - -private: - // state of the rigid body - rigidBodyPState_t current; - rigidBodyPState_t saved; - - // rigid body properties - float linearFriction; // translational friction - float angularFriction; // rotational friction - float contactFriction; // friction with contact surfaces - float bouncyness; // bouncyness - idClipModel * clipModel; // clip model used for collision detection - - // derived properties - float mass; // mass of body - float inverseMass; // 1 / mass - idVec3 centerOfMass; // center of mass of trace model - idMat3 inertiaTensor; // mass distribution - idMat3 inverseInertiaTensor; // inverse inertia tensor - - idODE * integrator; // integrator - bool dropToFloor; // true if dropping to the floor and putting to rest - bool testSolid; // true if testing for solid when dropping to the floor - bool noImpact; // if true do not activate when another object collides - bool noContact; // if true do not determine contacts and no contact friction - - // master - bool hasMaster; - bool isOrientated; - -private: - friend void RigidBodyDerivatives( const float t, const void *clientData, const float *state, float *derivatives ); - void Integrate( const float deltaTime, rigidBodyPState_t &next ); - bool CheckForCollisions( const float deltaTime, rigidBodyPState_t &next, trace_t &collision ); - bool CollisionImpulse( const trace_t &collision, idVec3 &impulse ); - void ContactFriction( float deltaTime ); - void DropToFloorAndRest( void ); - bool TestIfAtRest( void ) const; - void Rest( void ); - void DebugDraw( void ); -}; - -#endif /* !__PHYSICS_RIGIDBODY_H__ */ diff --git a/d3xp/physics/Physics_Static.cpp b/d3xp/physics/Physics_Static.cpp deleted file mode 100644 index cf9f0cfb..00000000 --- a/d3xp/physics/Physics_Static.cpp +++ /dev/null @@ -1,846 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "idlib/math/Quat.h" - -#include "gamesys/SysCvar.h" -#include "physics/Force.h" -#include "Entity.h" - -#include "physics/Physics_Static.h" - -CLASS_DECLARATION( idPhysics, idPhysics_Static ) -END_CLASS - -/* -================ -idPhysics_Static::idPhysics_Static -================ -*/ -idPhysics_Static::idPhysics_Static( void ) { - self = NULL; - clipModel = NULL; - current.origin.Zero(); - current.axis.Identity(); - current.localOrigin.Zero(); - current.localAxis.Identity(); - hasMaster = false; - isOrientated = false; -} - -/* -================ -idPhysics_Static::~idPhysics_Static -================ -*/ -idPhysics_Static::~idPhysics_Static( void ) { - if ( self && self->GetPhysics() == this ) { - self->SetPhysics( NULL ); - } - idForce::DeletePhysics( this ); - if ( clipModel ) { - delete clipModel; - } -} - -/* -================ -idPhysics_Static::Save -================ -*/ -void idPhysics_Static::Save( idSaveGame *savefile ) const { - savefile->WriteObject( self ); - - savefile->WriteVec3( current.origin ); - savefile->WriteMat3( current.axis ); - savefile->WriteVec3( current.localOrigin ); - savefile->WriteMat3( current.localAxis ); - savefile->WriteClipModel( clipModel ); - - savefile->WriteBool( hasMaster ); - savefile->WriteBool( isOrientated ); -} - -/* -================ -idPhysics_Static::Restore -================ -*/ -void idPhysics_Static::Restore( idRestoreGame *savefile ) { - savefile->ReadObject( reinterpret_cast( self ) ); - - savefile->ReadVec3( current.origin ); - savefile->ReadMat3( current.axis ); - savefile->ReadVec3( current.localOrigin ); - savefile->ReadMat3( current.localAxis ); - savefile->ReadClipModel( clipModel ); - - savefile->ReadBool( hasMaster ); - savefile->ReadBool( isOrientated ); -} - -/* -================ -idPhysics_Static::SetSelf -================ -*/ -void idPhysics_Static::SetSelf( idEntity *e ) { - assert( e ); - self = e; -} - -/* -================ -idPhysics_Static::SetClipModel -================ -*/ -void idPhysics_Static::SetClipModel( idClipModel *model, float density, int id, bool freeOld ) { - assert( self ); - - if ( clipModel && clipModel != model && freeOld ) { - delete clipModel; - } - clipModel = model; - if ( clipModel ) { - clipModel->Link( gameLocal.clip, self, 0, current.origin, current.axis ); - } -} - -/* -================ -idPhysics_Static::GetClipModel -================ -*/ -idClipModel *idPhysics_Static::GetClipModel( int id ) const { - if ( clipModel ) { - return clipModel; - } - return gameLocal.clip.DefaultClipModel(); -} - -/* -================ -idPhysics_Static::GetNumClipModels -================ -*/ -int idPhysics_Static::GetNumClipModels( void ) const { - return ( clipModel != NULL ); -} - -/* -================ -idPhysics_Static::SetMass -================ -*/ -void idPhysics_Static::SetMass( float mass, int id ) { -} - -/* -================ -idPhysics_Static::GetMass -================ -*/ -float idPhysics_Static::GetMass( int id ) const { - return 0.0f; -} - -/* -================ -idPhysics_Static::SetContents -================ -*/ -void idPhysics_Static::SetContents( int contents, int id ) { - if ( clipModel ) { - clipModel->SetContents( contents ); - } -} - -/* -================ -idPhysics_Static::GetContents -================ -*/ -int idPhysics_Static::GetContents( int id ) const { - if ( clipModel ) { - return clipModel->GetContents(); - } - return 0; -} - -/* -================ -idPhysics_Static::SetClipMask -================ -*/ -void idPhysics_Static::SetClipMask( int mask, int id ) { -} - -/* -================ -idPhysics_Static::GetClipMask -================ -*/ -int idPhysics_Static::GetClipMask( int id ) const { - return 0; -} - -/* -================ -idPhysics_Static::GetBounds -================ -*/ -const idBounds &idPhysics_Static::GetBounds( int id ) const { - if ( clipModel ) { - return clipModel->GetBounds(); - } - return bounds_zero; -} - -/* -================ -idPhysics_Static::GetAbsBounds -================ -*/ -const idBounds &idPhysics_Static::GetAbsBounds( int id ) const { - static idBounds absBounds; - - if ( clipModel ) { - return clipModel->GetAbsBounds(); - } - absBounds[0] = absBounds[1] = current.origin; - return absBounds; -} - -/* -================ -idPhysics_Static::Evaluate -================ -*/ -bool idPhysics_Static::Evaluate( int timeStepMSec, int endTimeMSec ) { - idVec3 masterOrigin, oldOrigin; - idMat3 masterAxis, oldAxis; - - - if ( hasMaster ) { - oldOrigin = current.origin; - oldAxis = current.axis; - - self->GetMasterPosition( masterOrigin, masterAxis ); - current.origin = masterOrigin + current.localOrigin * masterAxis; - if ( isOrientated ) { - current.axis = current.localAxis * masterAxis; - } else { - current.axis = current.localAxis; - } - if ( clipModel ) { - clipModel->Link( gameLocal.clip, self, 0, current.origin, current.axis ); - } - - return ( current.origin != oldOrigin || current.axis != oldAxis ); - } - return false; -} - -/* -================ -idPhysics_Static::UpdateTime -================ -*/ -void idPhysics_Static::UpdateTime( int endTimeMSec ) { -} - -/* -================ -idPhysics_Static::GetTime -================ -*/ -int idPhysics_Static::GetTime( void ) const { - return 0; -} - -/* -================ -idPhysics_Static::GetImpactInfo -================ -*/ -void idPhysics_Static::GetImpactInfo( const int id, const idVec3 &point, impactInfo_t *info ) const { - memset( info, 0, sizeof( *info ) ); -} - -/* -================ -idPhysics_Static::ApplyImpulse -================ -*/ -void idPhysics_Static::ApplyImpulse( const int id, const idVec3 &point, const idVec3 &impulse ) { -} - -/* -================ -idPhysics_Static::AddForce -================ -*/ -void idPhysics_Static::AddForce( const int id, const idVec3 &point, const idVec3 &force ) { -} - -/* -================ -idPhysics_Static::Activate -================ -*/ -void idPhysics_Static::Activate( void ) { -} - -/* -================ -idPhysics_Static::PutToRest -================ -*/ -void idPhysics_Static::PutToRest( void ) { -} - -/* -================ -idPhysics_Static::IsAtRest -================ -*/ -bool idPhysics_Static::IsAtRest( void ) const { - return true; -} - -/* -================ -idPhysics_Static::GetRestStartTime -================ -*/ -int idPhysics_Static::GetRestStartTime( void ) const { - return 0; -} - -/* -================ -idPhysics_Static::IsPushable -================ -*/ -bool idPhysics_Static::IsPushable( void ) const { - return false; -} - -/* -================ -idPhysics_Static::SaveState -================ -*/ -void idPhysics_Static::SaveState( void ) { -} - -/* -================ -idPhysics_Static::RestoreState -================ -*/ -void idPhysics_Static::RestoreState( void ) { -} - -/* -================ -idPhysics_Static::SetOrigin -================ -*/ -void idPhysics_Static::SetOrigin( const idVec3 &newOrigin, int id ) { - idVec3 masterOrigin; - idMat3 masterAxis; - - current.localOrigin = newOrigin; - - if ( hasMaster ) { - self->GetMasterPosition( masterOrigin, masterAxis ); - current.origin = masterOrigin + newOrigin * masterAxis; - } else { - current.origin = newOrigin; - } - - if ( clipModel ) { - clipModel->Link( gameLocal.clip, self, 0, current.origin, current.axis ); - } -} - -/* -================ -idPhysics_Static::SetAxis -================ -*/ -void idPhysics_Static::SetAxis( const idMat3 &newAxis, int id ) { - idVec3 masterOrigin; - idMat3 masterAxis; - - current.localAxis = newAxis; - - if ( hasMaster && isOrientated ) { - self->GetMasterPosition( masterOrigin, masterAxis ); - current.axis = newAxis * masterAxis; - } else { - current.axis = newAxis; - } - - if ( clipModel ) { - clipModel->Link( gameLocal.clip, self, 0, current.origin, current.axis ); - } -} - -/* -================ -idPhysics_Static::Translate -================ -*/ -void idPhysics_Static::Translate( const idVec3 &translation, int id ) { - current.localOrigin += translation; - current.origin += translation; - - if ( clipModel ) { - clipModel->Link( gameLocal.clip, self, 0, current.origin, current.axis ); - } -} - -/* -================ -idPhysics_Static::Rotate -================ -*/ -void idPhysics_Static::Rotate( const idRotation &rotation, int id ) { - idVec3 masterOrigin; - idMat3 masterAxis; - - current.origin *= rotation; - current.axis *= rotation.ToMat3(); - - if ( hasMaster ) { - self->GetMasterPosition( masterOrigin, masterAxis ); - current.localAxis *= rotation.ToMat3(); - current.localOrigin = ( current.origin - masterOrigin ) * masterAxis.Transpose(); - } else { - current.localAxis = current.axis; - current.localOrigin = current.origin; - } - - if ( clipModel ) { - clipModel->Link( gameLocal.clip, self, 0, current.origin, current.axis ); - } -} - -/* -================ -idPhysics_Static::GetOrigin -================ -*/ -const idVec3 &idPhysics_Static::GetOrigin( int id ) const { - return current.origin; -} - -/* -================ -idPhysics_Static::GetAxis -================ -*/ -const idMat3 &idPhysics_Static::GetAxis( int id ) const { - return current.axis; -} - -/* -================ -idPhysics_Static::SetLinearVelocity -================ -*/ -void idPhysics_Static::SetLinearVelocity( const idVec3 &newLinearVelocity, int id ) { -} - -/* -================ -idPhysics_Static::SetAngularVelocity -================ -*/ -void idPhysics_Static::SetAngularVelocity( const idVec3 &newAngularVelocity, int id ) { -} - -/* -================ -idPhysics_Static::GetLinearVelocity -================ -*/ -const idVec3 &idPhysics_Static::GetLinearVelocity( int id ) const { - return vec3_origin; -} - -/* -================ -idPhysics_Static::GetAngularVelocity -================ -*/ -const idVec3 &idPhysics_Static::GetAngularVelocity( int id ) const { - return vec3_origin; -} - -/* -================ -idPhysics_Static::SetGravity -================ -*/ -void idPhysics_Static::SetGravity( const idVec3 &newGravity ) { -} - -/* -================ -idPhysics_Static::GetGravity -================ -*/ -const idVec3 &idPhysics_Static::GetGravity( void ) const { - static idVec3 gravity( 0, 0, -g_gravity.GetFloat() ); - return gravity; -} - -/* -================ -idPhysics_Static::GetGravityNormal -================ -*/ -const idVec3 &idPhysics_Static::GetGravityNormal( void ) const { - static idVec3 gravity( 0, 0, -1 ); - return gravity; -} - -/* -================ -idPhysics_Static::ClipTranslation -================ -*/ -void idPhysics_Static::ClipTranslation( trace_t &results, const idVec3 &translation, const idClipModel *model ) const { - if ( model ) { - gameLocal.clip.TranslationModel( results, current.origin, current.origin + translation, - clipModel, current.axis, MASK_SOLID, model->Handle(), model->GetOrigin(), model->GetAxis() ); - } else { - gameLocal.clip.Translation( results, current.origin, current.origin + translation, - clipModel, current.axis, MASK_SOLID, self ); - } -} - -/* -================ -idPhysics_Static::ClipRotation -================ -*/ -void idPhysics_Static::ClipRotation( trace_t &results, const idRotation &rotation, const idClipModel *model ) const { - if ( model ) { - gameLocal.clip.RotationModel( results, current.origin, rotation, - clipModel, current.axis, MASK_SOLID, model->Handle(), model->GetOrigin(), model->GetAxis() ); - } else { - gameLocal.clip.Rotation( results, current.origin, rotation, clipModel, current.axis, MASK_SOLID, self ); - } -} - -/* -================ -idPhysics_Static::ClipContents -================ -*/ -int idPhysics_Static::ClipContents( const idClipModel *model ) const { - if ( clipModel ) { - if ( model ) { - return gameLocal.clip.ContentsModel( clipModel->GetOrigin(), clipModel, clipModel->GetAxis(), -1, - model->Handle(), model->GetOrigin(), model->GetAxis() ); - } else { - return gameLocal.clip.Contents( clipModel->GetOrigin(), clipModel, clipModel->GetAxis(), -1, NULL ); - } - } - return 0; -} - -/* -================ -idPhysics_Static::DisableClip -================ -*/ -void idPhysics_Static::DisableClip( void ) { - if ( clipModel ) { - clipModel->Disable(); - } -} - -/* -================ -idPhysics_Static::EnableClip -================ -*/ -void idPhysics_Static::EnableClip( void ) { - if ( clipModel ) { - clipModel->Enable(); - } -} - -/* -================ -idPhysics_Static::UnlinkClip -================ -*/ -void idPhysics_Static::UnlinkClip( void ) { - if ( clipModel ) { - clipModel->Unlink(); - } -} - -/* -================ -idPhysics_Static::LinkClip -================ -*/ -void idPhysics_Static::LinkClip( void ) { - if ( clipModel ) { - clipModel->Link( gameLocal.clip, self, 0, current.origin, current.axis ); - } -} - -/* -================ -idPhysics_Static::EvaluateContacts -================ -*/ -bool idPhysics_Static::EvaluateContacts( void ) { - return false; -} - -/* -================ -idPhysics_Static::GetNumContacts -================ -*/ -int idPhysics_Static::GetNumContacts( void ) const { - return 0; -} - -/* -================ -idPhysics_Static::GetContact -================ -*/ -const contactInfo_t &idPhysics_Static::GetContact( int num ) const { - static contactInfo_t info; - memset( &info, 0, sizeof( info ) ); - return info; -} - -/* -================ -idPhysics_Static::ClearContacts -================ -*/ -void idPhysics_Static::ClearContacts( void ) { -} - -/* -================ -idPhysics_Static::AddContactEntity -================ -*/ -void idPhysics_Static::AddContactEntity( idEntity *e ) { -} - -/* -================ -idPhysics_Static::RemoveContactEntity -================ -*/ -void idPhysics_Static::RemoveContactEntity( idEntity *e ) { -} - -/* -================ -idPhysics_Static::HasGroundContacts -================ -*/ -bool idPhysics_Static::HasGroundContacts( void ) const { - return false; -} - -/* -================ -idPhysics_Static::IsGroundEntity -================ -*/ -bool idPhysics_Static::IsGroundEntity( int entityNum ) const { - return false; -} - -/* -================ -idPhysics_Static::IsGroundClipModel -================ -*/ -bool idPhysics_Static::IsGroundClipModel( int entityNum, int id ) const { - return false; -} - -/* -================ -idPhysics_Static::SetPushed -================ -*/ -void idPhysics_Static::SetPushed( int deltaTime ) { -} - -/* -================ -idPhysics_Static::GetPushedLinearVelocity -================ -*/ -const idVec3 &idPhysics_Static::GetPushedLinearVelocity( const int id ) const { - return vec3_origin; -} - -/* -================ -idPhysics_Static::GetPushedAngularVelocity -================ -*/ -const idVec3 &idPhysics_Static::GetPushedAngularVelocity( const int id ) const { - return vec3_origin; -} - -/* -================ -idPhysics_Static::SetMaster -================ -*/ -void idPhysics_Static::SetMaster( idEntity *master, const bool orientated ) { - idVec3 masterOrigin; - idMat3 masterAxis; - - if ( master ) { - if ( !hasMaster ) { - // transform from world space to master space - self->GetMasterPosition( masterOrigin, masterAxis ); - current.localOrigin = ( current.origin - masterOrigin ) * masterAxis.Transpose(); - if ( orientated ) { - current.localAxis = current.axis * masterAxis.Transpose(); - } else { - current.localAxis = current.axis; - } - hasMaster = true; - isOrientated = orientated; - } - } else { - if ( hasMaster ) { - hasMaster = false; - } - } -} - -/* -================ -idPhysics_Static::GetBlockingInfo -================ -*/ -const trace_t *idPhysics_Static::GetBlockingInfo( void ) const { - return NULL; -} - -/* -================ -idPhysics_Static::GetBlockingEntity -================ -*/ -idEntity *idPhysics_Static::GetBlockingEntity( void ) const { - return NULL; -} - -/* -================ -idPhysics_Static::GetLinearEndTime -================ -*/ -int idPhysics_Static::GetLinearEndTime( void ) const { - return 0; -} - -/* -================ -idPhysics_Static::GetAngularEndTime -================ -*/ -int idPhysics_Static::GetAngularEndTime( void ) const { - return 0; -} - -/* -================ -idPhysics_Static::WriteToSnapshot -================ -*/ -void idPhysics_Static::WriteToSnapshot( idBitMsgDelta &msg ) const { - idCQuat quat, localQuat; - - quat = current.axis.ToCQuat(); - localQuat = current.localAxis.ToCQuat(); - - msg.WriteFloat( current.origin[0] ); - msg.WriteFloat( current.origin[1] ); - msg.WriteFloat( current.origin[2] ); - msg.WriteFloat( quat.x ); - msg.WriteFloat( quat.y ); - msg.WriteFloat( quat.z ); - msg.WriteDeltaFloat( current.origin[0], current.localOrigin[0] ); - msg.WriteDeltaFloat( current.origin[1], current.localOrigin[1] ); - msg.WriteDeltaFloat( current.origin[2], current.localOrigin[2] ); - msg.WriteDeltaFloat( quat.x, localQuat.x ); - msg.WriteDeltaFloat( quat.y, localQuat.y ); - msg.WriteDeltaFloat( quat.z, localQuat.z ); -} - -/* -================ -idPhysics_Base::ReadFromSnapshot -================ -*/ -void idPhysics_Static::ReadFromSnapshot( const idBitMsgDelta &msg ) { - idCQuat quat, localQuat; - - current.origin[0] = msg.ReadFloat(); - current.origin[1] = msg.ReadFloat(); - current.origin[2] = msg.ReadFloat(); - quat.x = msg.ReadFloat(); - quat.y = msg.ReadFloat(); - quat.z = msg.ReadFloat(); - current.localOrigin[0] = msg.ReadDeltaFloat( current.origin[0] ); - current.localOrigin[1] = msg.ReadDeltaFloat( current.origin[1] ); - current.localOrigin[2] = msg.ReadDeltaFloat( current.origin[2] ); - localQuat.x = msg.ReadDeltaFloat( quat.x ); - localQuat.y = msg.ReadDeltaFloat( quat.y ); - localQuat.z = msg.ReadDeltaFloat( quat.z ); - - current.axis = quat.ToMat3(); - current.localAxis = localQuat.ToMat3(); -} diff --git a/d3xp/physics/Physics_Static.h b/d3xp/physics/Physics_Static.h deleted file mode 100644 index bb589513..00000000 --- a/d3xp/physics/Physics_Static.h +++ /dev/null @@ -1,160 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __PHYSICS_STATIC_H__ -#define __PHYSICS_STATIC_H__ - -#include "physics/Physics.h" - -/* -=============================================================================== - - Physics for a non moving object using at most one collision model. - -=============================================================================== -*/ - -typedef struct staticPState_s { - idVec3 origin; - idMat3 axis; - idVec3 localOrigin; - idMat3 localAxis; -} staticPState_t; - -class idPhysics_Static : public idPhysics { - -public: - CLASS_PROTOTYPE( idPhysics_Static ); - - idPhysics_Static( void ); - ~idPhysics_Static( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - -public: // common physics interface - void SetSelf( idEntity *e ); - - void SetClipModel( idClipModel *model, float density, int id = 0, bool freeOld = true ); - idClipModel * GetClipModel( int id = 0 ) const; - int GetNumClipModels( void ) const; - - void SetMass( float mass, int id = -1 ); - float GetMass( int id = -1 ) const; - - void SetContents( int contents, int id = -1 ); - int GetContents( int id = -1 ) const; - - void SetClipMask( int mask, int id = -1 ); - int GetClipMask( int id = -1 ) const; - - const idBounds & GetBounds( int id = -1 ) const; - const idBounds & GetAbsBounds( int id = -1 ) const; - - bool Evaluate( int timeStepMSec, int endTimeMSec ); - void UpdateTime( int endTimeMSec ); - int GetTime( void ) const; - - void GetImpactInfo( const int id, const idVec3 &point, impactInfo_t *info ) const; - void ApplyImpulse( const int id, const idVec3 &point, const idVec3 &impulse ); - void AddForce( const int id, const idVec3 &point, const idVec3 &force ); - void Activate( void ); - void PutToRest( void ); - bool IsAtRest( void ) const; - int GetRestStartTime( void ) const; - bool IsPushable( void ) const; - - void SaveState( void ); - void RestoreState( void ); - - void SetOrigin( const idVec3 &newOrigin, int id = -1 ); - void SetAxis( const idMat3 &newAxis, int id = -1 ); - - void Translate( const idVec3 &translation, int id = -1 ); - void Rotate( const idRotation &rotation, int id = -1 ); - - const idVec3 & GetOrigin( int id = 0 ) const; - const idMat3 & GetAxis( int id = 0 ) const; - - void SetLinearVelocity( const idVec3 &newLinearVelocity, int id = 0 ); - void SetAngularVelocity( const idVec3 &newAngularVelocity, int id = 0 ); - - const idVec3 & GetLinearVelocity( int id = 0 ) const; - const idVec3 & GetAngularVelocity( int id = 0 ) const; - - void SetGravity( const idVec3 &newGravity ); - const idVec3 & GetGravity( void ) const; - const idVec3 & GetGravityNormal( void ) const; - - void ClipTranslation( trace_t &results, const idVec3 &translation, const idClipModel *model ) const; - void ClipRotation( trace_t &results, const idRotation &rotation, const idClipModel *model ) const; - int ClipContents( const idClipModel *model ) const; - - void DisableClip( void ); - void EnableClip( void ); - - void UnlinkClip( void ); - void LinkClip( void ); - - bool EvaluateContacts( void ); - int GetNumContacts( void ) const; - const contactInfo_t & GetContact( int num ) const; - void ClearContacts( void ); - void AddContactEntity( idEntity *e ); - void RemoveContactEntity( idEntity *e ); - - bool HasGroundContacts( void ) const; - bool IsGroundEntity( int entityNum ) const; - bool IsGroundClipModel( int entityNum, int id ) const; - - void SetPushed( int deltaTime ); - const idVec3 & GetPushedLinearVelocity( const int id = 0 ) const; - const idVec3 & GetPushedAngularVelocity( const int id = 0 ) const; - - void SetMaster( idEntity *master, const bool orientated = true ); - - const trace_t * GetBlockingInfo( void ) const; - idEntity * GetBlockingEntity( void ) const; - - int GetLinearEndTime( void ) const; - int GetAngularEndTime( void ) const; - - void WriteToSnapshot( idBitMsgDelta &msg ) const; - void ReadFromSnapshot( const idBitMsgDelta &msg ); - -protected: - idEntity * self; // entity using this physics object - staticPState_t current; // physics state - idClipModel * clipModel; // collision model - - // master - bool hasMaster; - bool isOrientated; -}; - -#endif /* !__PHYSICS_STATIC_H__ */ diff --git a/d3xp/physics/Physics_StaticMulti.cpp b/d3xp/physics/Physics_StaticMulti.cpp deleted file mode 100644 index 287d901c..00000000 --- a/d3xp/physics/Physics_StaticMulti.cpp +++ /dev/null @@ -1,1053 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "idlib/math/Quat.h" - -#include "gamesys/SysCvar.h" -#include "physics/Force.h" -#include "Entity.h" - -#include "physics/Physics_StaticMulti.h" - -CLASS_DECLARATION( idPhysics, idPhysics_StaticMulti ) -END_CLASS - -staticPState_t defaultState; - - -/* -================ -idPhysics_StaticMulti::idPhysics_StaticMulti -================ -*/ -idPhysics_StaticMulti::idPhysics_StaticMulti( void ) { - self = NULL; - hasMaster = false; - isOrientated = false; - - defaultState.origin.Zero(); - defaultState.axis.Identity(); - defaultState.localOrigin.Zero(); - defaultState.localAxis.Identity(); - - current.SetNum( 1 ); - current[0] = defaultState; - clipModels.SetNum( 1 ); - clipModels[0] = NULL; -} - -/* -================ -idPhysics_StaticMulti::~idPhysics_StaticMulti -================ -*/ -idPhysics_StaticMulti::~idPhysics_StaticMulti( void ) { - if ( self && self->GetPhysics() == this ) { - self->SetPhysics( NULL ); - } - idForce::DeletePhysics( this ); - for ( int i = 0; i < clipModels.Num(); i++ ) { - delete clipModels[i]; - } -} - -/* -================ -idPhysics_StaticMulti::Save -================ -*/ -void idPhysics_StaticMulti::Save( idSaveGame *savefile ) const { - int i; - - savefile->WriteObject( self ); - - savefile->WriteInt(current.Num()); - for ( i = 0; i < current.Num(); i++ ) { - savefile->WriteVec3( current[i].origin ); - savefile->WriteMat3( current[i].axis ); - savefile->WriteVec3( current[i].localOrigin ); - savefile->WriteMat3( current[i].localAxis ); - } - - savefile->WriteInt( clipModels.Num() ); - for ( i = 0; i < clipModels.Num(); i++ ) { - savefile->WriteClipModel( clipModels[i] ); - } - - savefile->WriteBool(hasMaster); - savefile->WriteBool(isOrientated); -} - -/* -================ -idPhysics_StaticMulti::Restore -================ -*/ -void idPhysics_StaticMulti::Restore( idRestoreGame *savefile ) { - int i, num; - - savefile->ReadObject( reinterpret_cast( self ) ); - - savefile->ReadInt(num); - current.AssureSize( num ); - for ( i = 0; i < num; i++ ) { - savefile->ReadVec3( current[i].origin ); - savefile->ReadMat3( current[i].axis ); - savefile->ReadVec3( current[i].localOrigin ); - savefile->ReadMat3( current[i].localAxis ); - } - - savefile->ReadInt(num); - clipModels.SetNum( num ); - for ( i = 0; i < num; i++ ) { - savefile->ReadClipModel( clipModels[i] ); - } - - savefile->ReadBool(hasMaster); - savefile->ReadBool(isOrientated); -} - -/* -================ -idPhysics_StaticMulti::SetSelf -================ -*/ -void idPhysics_StaticMulti::SetSelf( idEntity *e ) { - assert( e ); - self = e; -} - -/* -================ -idPhysics_StaticMulti::RemoveIndex -================ -*/ -void idPhysics_StaticMulti::RemoveIndex( int id, bool freeClipModel ) { - if ( id < 0 || id >= clipModels.Num() ) { - return; - } - if ( clipModels[id] && freeClipModel ) { - delete clipModels[id]; - clipModels[id] = NULL; - } - clipModels.RemoveIndex( id ); - current.RemoveIndex( id ); -} - -/* -================ -idPhysics_StaticMulti::SetClipModel -================ -*/ -void idPhysics_StaticMulti::SetClipModel( idClipModel *model, float density, int id, bool freeOld ) { - int i; - - assert( self ); - - if ( id >= clipModels.Num() ) { - current.AssureSize( id+1, defaultState ); - clipModels.AssureSize( id+1, NULL ); - } - - if ( clipModels[id] && clipModels[id] != model && freeOld ) { - delete clipModels[id]; - } - clipModels[id] = model; - if ( clipModels[id] ) { - clipModels[id]->Link( gameLocal.clip, self, id, current[id].origin, current[id].axis ); - } - - for ( i = clipModels.Num() - 1; i >= 1; i-- ) { - if ( clipModels[i] ) { - break; - } - } - current.SetNum( i+1, false ); - clipModels.SetNum( i+1, false ); -} - -/* -================ -idPhysics_StaticMulti::GetClipModel -================ -*/ -idClipModel *idPhysics_StaticMulti::GetClipModel( int id ) const { - if ( id >= 0 && id < clipModels.Num() && clipModels[id] ) { - return clipModels[id]; - } - return gameLocal.clip.DefaultClipModel(); -} - -/* -================ -idPhysics_StaticMulti::GetNumClipModels -================ -*/ -int idPhysics_StaticMulti::GetNumClipModels( void ) const { - return clipModels.Num(); -} - -/* -================ -idPhysics_StaticMulti::SetMass -================ -*/ -void idPhysics_StaticMulti::SetMass( float mass, int id ) { -} - -/* -================ -idPhysics_StaticMulti::GetMass -================ -*/ -float idPhysics_StaticMulti::GetMass( int id ) const { - return 0.0f; -} - -/* -================ -idPhysics_StaticMulti::SetContents -================ -*/ -void idPhysics_StaticMulti::SetContents( int contents, int id ) { - int i; - - if ( id >= 0 && id < clipModels.Num() ) { - if ( clipModels[id] ) { - clipModels[id]->SetContents( contents ); - } - } else if ( id == -1 ) { - for ( i = 0; i < clipModels.Num(); i++ ) { - if ( clipModels[i] ) { - clipModels[i]->SetContents( contents ); - } - } - } -} - -/* -================ -idPhysics_StaticMulti::GetContents -================ -*/ -int idPhysics_StaticMulti::GetContents( int id ) const { - int i, contents = 0; - - if ( id >= 0 && id < clipModels.Num() ) { - if ( clipModels[id] ) { - contents = clipModels[id]->GetContents(); - } - } else if ( id == -1 ) { - for ( i = 0; i < clipModels.Num(); i++ ) { - if ( clipModels[i] ) { - contents |= clipModels[i]->GetContents(); - } - } - } - return contents; -} - -/* -================ -idPhysics_StaticMulti::SetClipMask -================ -*/ -void idPhysics_StaticMulti::SetClipMask( int mask, int id ) { -} - -/* -================ -idPhysics_StaticMulti::GetClipMask -================ -*/ -int idPhysics_StaticMulti::GetClipMask( int id ) const { - return 0; -} - -/* -================ -idPhysics_StaticMulti::GetBounds -================ -*/ -const idBounds &idPhysics_StaticMulti::GetBounds( int id ) const { - int i; - static idBounds bounds; - - if ( id >= 0 && id < clipModels.Num() ) { - if ( clipModels[id] ) { - return clipModels[id]->GetBounds(); - } - } - if ( id == -1 ) { - bounds.Clear(); - for ( i = 0; i < clipModels.Num(); i++ ) { - if ( clipModels[i] ) { - bounds.AddBounds( clipModels[i]->GetAbsBounds() ); - } - } - for ( i = 0; i < clipModels.Num(); i++ ) { - if ( clipModels[i] ) { - bounds[0] -= clipModels[i]->GetOrigin(); - bounds[1] -= clipModels[i]->GetOrigin(); - break; - } - } - return bounds; - } - return bounds_zero; -} - -/* -================ -idPhysics_StaticMulti::GetAbsBounds -================ -*/ -const idBounds &idPhysics_StaticMulti::GetAbsBounds( int id ) const { - int i; - static idBounds absBounds; - - if ( id >= 0 && id < clipModels.Num() ) { - if ( clipModels[id] ) { - return clipModels[id]->GetAbsBounds(); - } - } - if ( id == -1 ) { - absBounds.Clear(); - for ( i = 0; i < clipModels.Num(); i++ ) { - if ( clipModels[i] ) { - absBounds.AddBounds( clipModels[i]->GetAbsBounds() ); - } - } - return absBounds; - } - return bounds_zero; -} - -/* -================ -idPhysics_StaticMulti::Evaluate -================ -*/ -bool idPhysics_StaticMulti::Evaluate( int timeStepMSec, int endTimeMSec ) { - int i; - idVec3 masterOrigin; - idMat3 masterAxis; - - if ( hasMaster ) { - self->GetMasterPosition( masterOrigin, masterAxis ); - for ( i = 0; i < clipModels.Num(); i++ ) { - current[i].origin = masterOrigin + current[i].localOrigin * masterAxis; - if ( isOrientated ) { - current[i].axis = current[i].localAxis * masterAxis; - } else { - current[i].axis = current[i].localAxis; - } - if ( clipModels[i] ) { - clipModels[i]->Link( gameLocal.clip, self, i, current[i].origin, current[i].axis ); - } - } - - // FIXME: return false if master did not move - return true; - } - return false; -} - -/* -================ -idPhysics_StaticMulti::UpdateTime -================ -*/ -void idPhysics_StaticMulti::UpdateTime( int endTimeMSec ) { -} - -/* -================ -idPhysics_StaticMulti::GetTime -================ -*/ -int idPhysics_StaticMulti::GetTime( void ) const { - return 0; -} - -/* -================ -idPhysics_StaticMulti::GetImpactInfo -================ -*/ -void idPhysics_StaticMulti::GetImpactInfo( const int id, const idVec3 &point, impactInfo_t *info ) const { - memset( info, 0, sizeof( *info ) ); -} - -/* -================ -idPhysics_StaticMulti::ApplyImpulse -================ -*/ -void idPhysics_StaticMulti::ApplyImpulse( const int id, const idVec3 &point, const idVec3 &impulse ) { -} - -/* -================ -idPhysics_StaticMulti::AddForce -================ -*/ -void idPhysics_StaticMulti::AddForce( const int id, const idVec3 &point, const idVec3 &force ) { -} - -/* -================ -idPhysics_StaticMulti::Activate -================ -*/ -void idPhysics_StaticMulti::Activate( void ) { -} - -/* -================ -idPhysics_StaticMulti::PutToRest -================ -*/ -void idPhysics_StaticMulti::PutToRest( void ) { -} - -/* -================ -idPhysics_StaticMulti::IsAtRest -================ -*/ -bool idPhysics_StaticMulti::IsAtRest( void ) const { - return true; -} - -/* -================ -idPhysics_StaticMulti::GetRestStartTime -================ -*/ -int idPhysics_StaticMulti::GetRestStartTime( void ) const { - return 0; -} - -/* -================ -idPhysics_StaticMulti::IsPushable -================ -*/ -bool idPhysics_StaticMulti::IsPushable( void ) const { - return false; -} - -/* -================ -idPhysics_StaticMulti::SaveState -================ -*/ -void idPhysics_StaticMulti::SaveState( void ) { -} - -/* -================ -idPhysics_StaticMulti::RestoreState -================ -*/ -void idPhysics_StaticMulti::RestoreState( void ) { -} - -/* -================ -idPhysics_StaticMulti::SetOrigin -================ -*/ -void idPhysics_StaticMulti::SetOrigin( const idVec3 &newOrigin, int id ) { - idVec3 masterOrigin; - idMat3 masterAxis; - - if ( id >= 0 && id < clipModels.Num() ) { - current[id].localOrigin = newOrigin; - if ( hasMaster ) { - self->GetMasterPosition( masterOrigin, masterAxis ); - current[id].origin = masterOrigin + newOrigin * masterAxis; - } else { - current[id].origin = newOrigin; - } - if ( clipModels[id] ) { - clipModels[id]->Link( gameLocal.clip, self, id, current[id].origin, current[id].axis ); - } - } else if ( id == -1 ) { - if ( hasMaster ) { - self->GetMasterPosition( masterOrigin, masterAxis ); - Translate( masterOrigin + masterAxis * newOrigin - current[0].origin ); - } else { - Translate( newOrigin - current[0].origin ); - } - } -} - -/* -================ -idPhysics_StaticMulti::SetAxis -================ -*/ -void idPhysics_StaticMulti::SetAxis( const idMat3 &newAxis, int id ) { - idVec3 masterOrigin; - idMat3 masterAxis; - - if ( id >= 0 && id < clipModels.Num() ) { - current[id].localAxis = newAxis; - if ( hasMaster && isOrientated ) { - self->GetMasterPosition( masterOrigin, masterAxis ); - current[id].axis = newAxis * masterAxis; - } else { - current[id].axis = newAxis; - } - if ( clipModels[id] ) { - clipModels[id]->Link( gameLocal.clip, self, id, current[id].origin, current[id].axis ); - } - } else if ( id == -1 ) { - idMat3 axis; - idRotation rotation; - - if ( hasMaster ) { - self->GetMasterPosition( masterOrigin, masterAxis ); - axis = current[0].axis.Transpose() * ( newAxis * masterAxis ); - } else { - axis = current[0].axis.Transpose() * newAxis; - } - rotation = axis.ToRotation(); - rotation.SetOrigin( current[0].origin ); - - Rotate( rotation ); - } -} - -/* -================ -idPhysics_StaticMulti::Translate -================ -*/ -void idPhysics_StaticMulti::Translate( const idVec3 &translation, int id ) { - int i; - - if ( id >= 0 && id < clipModels.Num() ) { - current[id].localOrigin += translation; - current[id].origin += translation; - - if ( clipModels[id] ) { - clipModels[id]->Link( gameLocal.clip, self, id, current[id].origin, current[id].axis ); - } - } else if ( id == -1 ) { - for ( i = 0; i < clipModels.Num(); i++ ) { - current[i].localOrigin += translation; - current[i].origin += translation; - - if ( clipModels[i] ) { - clipModels[i]->Link( gameLocal.clip, self, i, current[i].origin, current[i].axis ); - } - } - } -} - -/* -================ -idPhysics_StaticMulti::Rotate -================ -*/ -void idPhysics_StaticMulti::Rotate( const idRotation &rotation, int id ) { - int i; - idVec3 masterOrigin; - idMat3 masterAxis; - - if ( id >= 0 && id < clipModels.Num() ) { - current[id].origin *= rotation; - current[id].axis *= rotation.ToMat3(); - - if ( hasMaster ) { - self->GetMasterPosition( masterOrigin, masterAxis ); - current[id].localAxis *= rotation.ToMat3(); - current[id].localOrigin = ( current[id].origin - masterOrigin ) * masterAxis.Transpose(); - } else { - current[id].localAxis = current[id].axis; - current[id].localOrigin = current[id].origin; - } - - if ( clipModels[id] ) { - clipModels[id]->Link( gameLocal.clip, self, id, current[id].origin, current[id].axis ); - } - } else if ( id == -1 ) { - for ( i = 0; i < clipModels.Num(); i++ ) { - current[i].origin *= rotation; - current[i].axis *= rotation.ToMat3(); - - if ( hasMaster ) { - self->GetMasterPosition( masterOrigin, masterAxis ); - current[i].localAxis *= rotation.ToMat3(); - current[i].localOrigin = ( current[i].origin - masterOrigin ) * masterAxis.Transpose(); - } else { - current[i].localAxis = current[i].axis; - current[i].localOrigin = current[i].origin; - } - - if ( clipModels[i] ) { - clipModels[i]->Link( gameLocal.clip, self, i, current[i].origin, current[i].axis ); - } - } - } -} - -/* -================ -idPhysics_StaticMulti::GetOrigin -================ -*/ -const idVec3 &idPhysics_StaticMulti::GetOrigin( int id ) const { - if ( id >= 0 && id < clipModels.Num() ) { - return current[id].origin; - } - if ( clipModels.Num() ) { - return current[0].origin; - } else { - return vec3_origin; - } -} - -/* -================ -idPhysics_StaticMulti::GetAxis -================ -*/ -const idMat3 &idPhysics_StaticMulti::GetAxis( int id ) const { - if ( id >= 0 && id < clipModels.Num() ) { - return current[id].axis; - } - if ( clipModels.Num() ) { - return current[0].axis; - } else { - return mat3_identity; - } -} - -/* -================ -idPhysics_StaticMulti::SetLinearVelocity -================ -*/ -void idPhysics_StaticMulti::SetLinearVelocity( const idVec3 &newLinearVelocity, int id ) { -} - -/* -================ -idPhysics_StaticMulti::SetAngularVelocity -================ -*/ -void idPhysics_StaticMulti::SetAngularVelocity( const idVec3 &newAngularVelocity, int id ) { -} - -/* -================ -idPhysics_StaticMulti::GetLinearVelocity -================ -*/ -const idVec3 &idPhysics_StaticMulti::GetLinearVelocity( int id ) const { - return vec3_origin; -} - -/* -================ -idPhysics_StaticMulti::GetAngularVelocity -================ -*/ -const idVec3 &idPhysics_StaticMulti::GetAngularVelocity( int id ) const { - return vec3_origin; -} - -/* -================ -idPhysics_StaticMulti::SetGravity -================ -*/ -void idPhysics_StaticMulti::SetGravity( const idVec3 &newGravity ) { -} - -/* -================ -idPhysics_StaticMulti::GetGravity -================ -*/ -const idVec3 &idPhysics_StaticMulti::GetGravity( void ) const { - static idVec3 gravity( 0, 0, -g_gravity.GetFloat() ); - return gravity; -} - -/* -================ -idPhysics_StaticMulti::GetGravityNormal -================ -*/ -const idVec3 &idPhysics_StaticMulti::GetGravityNormal( void ) const { - static idVec3 gravity( 0, 0, -1 ); - return gravity; -} - -/* -================ -idPhysics_StaticMulti::ClipTranslation -================ -*/ -void idPhysics_StaticMulti::ClipTranslation( trace_t &results, const idVec3 &translation, const idClipModel *model ) const { - memset( &results, 0, sizeof( trace_t ) ); - gameLocal.Warning( "idPhysics_StaticMulti::ClipTranslation called" ); -} - -/* -================ -idPhysics_StaticMulti::ClipRotation -================ -*/ -void idPhysics_StaticMulti::ClipRotation( trace_t &results, const idRotation &rotation, const idClipModel *model ) const { - memset( &results, 0, sizeof( trace_t ) ); - gameLocal.Warning( "idPhysics_StaticMulti::ClipRotation called" ); -} - -/* -================ -idPhysics_StaticMulti::ClipContents -================ -*/ -int idPhysics_StaticMulti::ClipContents( const idClipModel *model ) const { - int i, contents; - - contents = 0; - for ( i = 0; i < clipModels.Num(); i++ ) { - if ( clipModels[i] ) { - if ( model ) { - contents |= gameLocal.clip.ContentsModel( clipModels[i]->GetOrigin(), clipModels[i], clipModels[i]->GetAxis(), -1, - model->Handle(), model->GetOrigin(), model->GetAxis() ); - } else { - contents |= gameLocal.clip.Contents( clipModels[i]->GetOrigin(), clipModels[i], clipModels[i]->GetAxis(), -1, NULL ); - } - } - } - return contents; -} - -/* -================ -idPhysics_StaticMulti::DisableClip -================ -*/ -void idPhysics_StaticMulti::DisableClip( void ) { - int i; - - for ( i = 0; i < clipModels.Num(); i++ ) { - if ( clipModels[i] ) { - clipModels[i]->Disable(); - } - } -} - -/* -================ -idPhysics_StaticMulti::EnableClip -================ -*/ -void idPhysics_StaticMulti::EnableClip( void ) { - int i; - - for ( i = 0; i < clipModels.Num(); i++ ) { - if ( clipModels[i] ) { - clipModels[i]->Enable(); - } - } -} - -/* -================ -idPhysics_StaticMulti::UnlinkClip -================ -*/ -void idPhysics_StaticMulti::UnlinkClip( void ) { - int i; - - for ( i = 0; i < clipModels.Num(); i++ ) { - if ( clipModels[i] ) { - clipModels[i]->Unlink(); - } - } -} - -/* -================ -idPhysics_StaticMulti::LinkClip -================ -*/ -void idPhysics_StaticMulti::LinkClip( void ) { - int i; - - for ( i = 0; i < clipModels.Num(); i++ ) { - if ( clipModels[i] ) { - clipModels[i]->Link( gameLocal.clip, self, i, current[i].origin, current[i].axis ); - } - } -} - -/* -================ -idPhysics_StaticMulti::EvaluateContacts -================ -*/ -bool idPhysics_StaticMulti::EvaluateContacts( void ) { - return false; -} - -/* -================ -idPhysics_StaticMulti::GetNumContacts -================ -*/ -int idPhysics_StaticMulti::GetNumContacts( void ) const { - return 0; -} - -/* -================ -idPhysics_StaticMulti::GetContact -================ -*/ -const contactInfo_t &idPhysics_StaticMulti::GetContact( int num ) const { - static contactInfo_t info; - memset( &info, 0, sizeof( info ) ); - return info; -} - -/* -================ -idPhysics_StaticMulti::ClearContacts -================ -*/ -void idPhysics_StaticMulti::ClearContacts( void ) { -} - -/* -================ -idPhysics_StaticMulti::AddContactEntity -================ -*/ -void idPhysics_StaticMulti::AddContactEntity( idEntity *e ) { -} - -/* -================ -idPhysics_StaticMulti::RemoveContactEntity -================ -*/ -void idPhysics_StaticMulti::RemoveContactEntity( idEntity *e ) { -} - -/* -================ -idPhysics_StaticMulti::HasGroundContacts -================ -*/ -bool idPhysics_StaticMulti::HasGroundContacts( void ) const { - return false; -} - -/* -================ -idPhysics_StaticMulti::IsGroundEntity -================ -*/ -bool idPhysics_StaticMulti::IsGroundEntity( int entityNum ) const { - return false; -} - -/* -================ -idPhysics_StaticMulti::IsGroundClipModel -================ -*/ -bool idPhysics_StaticMulti::IsGroundClipModel( int entityNum, int id ) const { - return false; -} - -/* -================ -idPhysics_StaticMulti::SetPushed -================ -*/ -void idPhysics_StaticMulti::SetPushed( int deltaTime ) { -} - -/* -================ -idPhysics_StaticMulti::GetPushedLinearVelocity -================ -*/ -const idVec3 &idPhysics_StaticMulti::GetPushedLinearVelocity( const int id ) const { - return vec3_origin; -} - -/* -================ -idPhysics_StaticMulti::GetPushedAngularVelocity -================ -*/ -const idVec3 &idPhysics_StaticMulti::GetPushedAngularVelocity( const int id ) const { - return vec3_origin; -} - -/* -================ -idPhysics_StaticMulti::SetMaster -================ -*/ -void idPhysics_StaticMulti::SetMaster( idEntity *master, const bool orientated ) { - int i; - idVec3 masterOrigin; - idMat3 masterAxis; - - if ( master ) { - if ( !hasMaster ) { - // transform from world space to master space - self->GetMasterPosition( masterOrigin, masterAxis ); - for ( i = 0; i < clipModels.Num(); i++ ) { - current[i].localOrigin = ( current[i].origin - masterOrigin ) * masterAxis.Transpose(); - if ( orientated ) { - current[i].localAxis = current[i].axis * masterAxis.Transpose(); - } else { - current[i].localAxis = current[i].axis; - } - } - hasMaster = true; - isOrientated = orientated; - } - } else { - if ( hasMaster ) { - hasMaster = false; - } - } -} - -/* -================ -idPhysics_StaticMulti::GetBlockingInfo -================ -*/ -const trace_t *idPhysics_StaticMulti::GetBlockingInfo( void ) const { - return NULL; -} - -/* -================ -idPhysics_StaticMulti::GetBlockingEntity -================ -*/ -idEntity *idPhysics_StaticMulti::GetBlockingEntity( void ) const { - return NULL; -} - -/* -================ -idPhysics_StaticMulti::GetLinearEndTime -================ -*/ -int idPhysics_StaticMulti::GetLinearEndTime( void ) const { - return 0; -} - -/* -================ -idPhysics_StaticMulti::GetAngularEndTime -================ -*/ -int idPhysics_StaticMulti::GetAngularEndTime( void ) const { - return 0; -} - -/* -================ -idPhysics_StaticMulti::WriteToSnapshot -================ -*/ -void idPhysics_StaticMulti::WriteToSnapshot( idBitMsgDelta &msg ) const { - int i; - idCQuat quat, localQuat; - - msg.WriteByte( current.Num() ); - - for ( i = 0; i < current.Num(); i++ ) { - quat = current[i].axis.ToCQuat(); - localQuat = current[i].localAxis.ToCQuat(); - - msg.WriteFloat( current[i].origin[0] ); - msg.WriteFloat( current[i].origin[1] ); - msg.WriteFloat( current[i].origin[2] ); - msg.WriteFloat( quat.x ); - msg.WriteFloat( quat.y ); - msg.WriteFloat( quat.z ); - msg.WriteDeltaFloat( current[i].origin[0], current[i].localOrigin[0] ); - msg.WriteDeltaFloat( current[i].origin[1], current[i].localOrigin[1] ); - msg.WriteDeltaFloat( current[i].origin[2], current[i].localOrigin[2] ); - msg.WriteDeltaFloat( quat.x, localQuat.x ); - msg.WriteDeltaFloat( quat.y, localQuat.y ); - msg.WriteDeltaFloat( quat.z, localQuat.z ); - } -} - -/* -================ -idPhysics_StaticMulti::ReadFromSnapshot -================ -*/ -void idPhysics_StaticMulti::ReadFromSnapshot( const idBitMsgDelta &msg ) { - int i, num id_attribute((unused)); - idCQuat quat, localQuat; - - num = msg.ReadByte(); - assert( num == current.Num() ); - - for ( i = 0; i < current.Num(); i++ ) { - current[i].origin[0] = msg.ReadFloat(); - current[i].origin[1] = msg.ReadFloat(); - current[i].origin[2] = msg.ReadFloat(); - quat.x = msg.ReadFloat(); - quat.y = msg.ReadFloat(); - quat.z = msg.ReadFloat(); - current[i].localOrigin[0] = msg.ReadDeltaFloat( current[i].origin[0] ); - current[i].localOrigin[1] = msg.ReadDeltaFloat( current[i].origin[1] ); - current[i].localOrigin[2] = msg.ReadDeltaFloat( current[i].origin[2] ); - localQuat.x = msg.ReadDeltaFloat( quat.x ); - localQuat.y = msg.ReadDeltaFloat( quat.y ); - localQuat.z = msg.ReadDeltaFloat( quat.z ); - - current[i].axis = quat.ToMat3(); - current[i].localAxis = localQuat.ToMat3(); - } -} diff --git a/d3xp/physics/Physics_StaticMulti.h b/d3xp/physics/Physics_StaticMulti.h deleted file mode 100644 index 0cd94ed2..00000000 --- a/d3xp/physics/Physics_StaticMulti.h +++ /dev/null @@ -1,156 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __PHYSICS_STATICMULTI_H__ -#define __PHYSICS_STATICMULTI_H__ - -#include "physics/Physics_Static.h" - -/* -=============================================================================== - - Physics for a non moving object using no or multiple collision models. - -=============================================================================== -*/ - -class idPhysics_StaticMulti : public idPhysics { - -public: - CLASS_PROTOTYPE( idPhysics_StaticMulti ); - - idPhysics_StaticMulti( void ); - ~idPhysics_StaticMulti( void ); - - void Save( idSaveGame *savefile ) const; - void Restore( idRestoreGame *savefile ); - - void RemoveIndex( int id = 0, bool freeClipModel = true ); - -public: // common physics interface - - void SetSelf( idEntity *e ); - - void SetClipModel( idClipModel *model, float density, int id = 0, bool freeOld = true ); - idClipModel * GetClipModel( int id = 0 ) const; - int GetNumClipModels( void ) const; - - void SetMass( float mass, int id = -1 ); - float GetMass( int id = -1 ) const; - - void SetContents( int contents, int id = -1 ); - int GetContents( int id = -1 ) const; - - void SetClipMask( int mask, int id = -1 ); - int GetClipMask( int id = -1 ) const; - - const idBounds & GetBounds( int id = -1 ) const; - const idBounds & GetAbsBounds( int id = -1 ) const; - - bool Evaluate( int timeStepMSec, int endTimeMSec ); - void UpdateTime( int endTimeMSec ); - int GetTime( void ) const; - - void GetImpactInfo( const int id, const idVec3 &point, impactInfo_t *info ) const; - void ApplyImpulse( const int id, const idVec3 &point, const idVec3 &impulse ); - void AddForce( const int id, const idVec3 &point, const idVec3 &force ); - void Activate( void ); - void PutToRest( void ); - bool IsAtRest( void ) const; - int GetRestStartTime( void ) const; - bool IsPushable( void ) const; - - void SaveState( void ); - void RestoreState( void ); - - void SetOrigin( const idVec3 &newOrigin, int id = -1 ); - void SetAxis( const idMat3 &newAxis, int id = -1 ); - - void Translate( const idVec3 &translation, int id = -1 ); - void Rotate( const idRotation &rotation, int id = -1 ); - - const idVec3 & GetOrigin( int id = 0 ) const; - const idMat3 & GetAxis( int id = 0 ) const; - - void SetLinearVelocity( const idVec3 &newLinearVelocity, int id = 0 ); - void SetAngularVelocity( const idVec3 &newAngularVelocity, int id = 0 ); - - const idVec3 & GetLinearVelocity( int id = 0 ) const; - const idVec3 & GetAngularVelocity( int id = 0 ) const; - - void SetGravity( const idVec3 &newGravity ); - const idVec3 & GetGravity( void ) const; - const idVec3 & GetGravityNormal( void ) const; - - void ClipTranslation( trace_t &results, const idVec3 &translation, const idClipModel *model ) const; - void ClipRotation( trace_t &results, const idRotation &rotation, const idClipModel *model ) const; - int ClipContents( const idClipModel *model ) const; - - void DisableClip( void ); - void EnableClip( void ); - - void UnlinkClip( void ); - void LinkClip( void ); - - bool EvaluateContacts( void ); - int GetNumContacts( void ) const; - const contactInfo_t & GetContact( int num ) const; - void ClearContacts( void ); - void AddContactEntity( idEntity *e ); - void RemoveContactEntity( idEntity *e ); - - bool HasGroundContacts( void ) const; - bool IsGroundEntity( int entityNum ) const; - bool IsGroundClipModel( int entityNum, int id ) const; - - void SetPushed( int deltaTime ); - const idVec3 & GetPushedLinearVelocity( const int id = 0 ) const; - const idVec3 & GetPushedAngularVelocity( const int id = 0 ) const; - - void SetMaster( idEntity *master, const bool orientated = true ); - - const trace_t * GetBlockingInfo( void ) const; - idEntity * GetBlockingEntity( void ) const; - - int GetLinearEndTime( void ) const; - int GetAngularEndTime( void ) const; - - void WriteToSnapshot( idBitMsgDelta &msg ) const; - void ReadFromSnapshot( const idBitMsgDelta &msg ); - -protected: - idEntity * self; // entity using this physics object - idList current; // physics state - idList clipModels; // collision model - - // master - bool hasMaster; - bool isOrientated; -}; - -#endif /* !__PHYSICS_STATICMULTI_H__ */ diff --git a/d3xp/physics/Push.cpp b/d3xp/physics/Push.cpp deleted file mode 100644 index 0b986130..00000000 --- a/d3xp/physics/Push.cpp +++ /dev/null @@ -1,1448 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "physics/Physics_Actor.h" -#include "Entity.h" -#include "Player.h" -#include "Moveable.h" -#include "Game_local.h" - -#include "physics/Push.h" - -/* -============ -idPush::InitSavingPushedEntityPositions -============ -*/ -void idPush::InitSavingPushedEntityPositions( void ) { - numPushed = 0; -} - -/* -============ -idPush::SaveEntityPosition -============ -*/ -void idPush::SaveEntityPosition( idEntity *ent ) { - int i; - - // if already saved the physics state for this entity - for ( i = 0; i < numPushed; i++ ) { - if ( pushed[i].ent == ent ) { - return; - } - } - - // don't overflow - if ( numPushed >= MAX_GENTITIES ) { - gameLocal.Error( "more than MAX_GENTITIES pushed entities" ); - return; - } - - pushed[numPushed].ent = ent; - - // if the entity is an actor - if ( ent->IsType( idActor::Type ) ) { - // save the delta view angles - pushed[numPushed].deltaViewAngles = static_cast(ent)->GetDeltaViewAngles(); - } - - // save the physics state - ent->GetPhysics()->SaveState(); - - numPushed++; -} - -/* -============ -idPush::RestorePushedEntityPositions -============ -*/ -void idPush::RestorePushedEntityPositions( void ) { - int i; - - for ( i = 0; i < numPushed; i++ ) { - - // if the entity is an actor - if ( pushed[i].ent->IsType( idActor::Type ) ) { - // set back the delta view angles - static_cast(pushed[i].ent)->SetDeltaViewAngles( pushed[i].deltaViewAngles ); - } - - // restore the physics state - pushed[i].ent->GetPhysics()->RestoreState(); - } -} - -/* -============ -idPush::RotateEntityToAxial -============ -*/ -bool idPush::RotateEntityToAxial( idEntity *ent, idVec3 rotationPoint ) { - int i; - trace_t trace; - idRotation rotation; - idMat3 axis; - idPhysics *physics; - - physics = ent->GetPhysics(); - axis = physics->GetAxis(); - if ( !axis.IsRotated() ) { - return true; - } - // try to rotate the bbox back to axial with at most four rotations - for ( i = 0; i < 4; i++ ) { - axis = physics->GetAxis(); - rotation = axis.ToRotation(); - rotation.Scale( -1 ); - rotation.SetOrigin( rotationPoint ); - // tiny float numbers in the clip axis, this can get the entity stuck - if ( rotation.GetAngle() == 0.0f ) { - physics->SetAxis( mat3_identity ); - return true; - } - // - ent->GetPhysics()->ClipRotation( trace, rotation, NULL ); - // if the full rotation is possible - if ( trace.fraction >= 1.0f ) { - // set bbox in final axial position - physics->SetOrigin( trace.endpos ); - physics->SetAxis( mat3_identity ); - return true; - } - // if partial rotation was possible - else if ( trace.fraction > 0.0f ) { - // partial rotation - physics->SetOrigin( trace.endpos ); - physics->SetAxis( trace.endAxis ); - } - // next rotate around collision point - rotationPoint = trace.c.point; - } - return false; -} - -#ifdef NEW_PUSH - -/* -============ -idPush::CanPushEntity -============ -*/ -bool idPush::CanPushEntity( idEntity *ent, idEntity *pusher, idEntity *initialPusher, const int flags ) { - - // if the physics object is not pushable - if ( !ent->GetPhysics()->IsPushable() ) { - return false; - } - - // if the entity doesn't clip with this pusher - if ( !( ent->GetPhysics()->GetClipMask() & pusher->GetPhysics()->GetContents() ) ) { - return false; - } - - // don't push players in noclip mode - if ( ent->client && ent->client->noclip ) { - return false; - } - - // if we should only push idMoveable entities - if ( ( flags & PUSHFL_ONLYMOVEABLE ) && !ent->IsType( idMoveable::Type ) ) { - return false; - } - - // if we shouldn't push entities the original pusher rests upon - if ( flags & PUSHFL_NOGROUNDENTITIES ) { - if ( initialPusher->GetPhysics()->IsGroundEntity( ent->entityNumber ) ) { - return false; - } - } - - return true; -} - -/* -============ -idPush::AddEntityToPushedGroup -============ -*/ -void idPush::AddEntityToPushedGroup( idEntity *ent, float fraction, bool groundContact ) { - int i, j; - - for ( i = 0; i < pushedGroupSize; i++ ) { - if ( ent == pushedGroup[i].ent ) { - if ( fraction > pushedGroup[i].fraction ) { - pushedGroup[i].fraction = fraction; - pushedGroup[i].groundContact &= groundContact; - pushedGroup[i].test = true; - } - return; - } - else if ( fraction > pushedGroup[i].fraction ) { - for ( j = pushedGroupSize; j > i; j-- ) { - pushedGroup[j] = pushedGroup[j-1]; - } - break; - } - } - - // put the entity in the group - pushedGroupSize++; - pushedGroup[i].ent = ent; - pushedGroup[i].fraction = fraction; - pushedGroup[i].groundContact = groundContact; - pushedGroup[i].test = true; - - // remove any further occurances of the same entity in the group - for ( i++; i < pushedGroupSize; i++ ) { - if ( ent == pushedGroup[i].ent ) { - for ( j = i+1; j < pushedGroupSize; j++ ) { - pushedGroup[j-1] = pushedGroup[j]; - } - pushedGroupSize--; - break; - } - } -} - -/* -============ -idPush::IsFullyPushed -============ -*/ -bool idPush::IsFullyPushed( idEntity *ent ) { - int i; - - for ( i = 0; i < pushedGroupSize; i++ ) { - if ( pushedGroup[i].fraction < 1.0f ) { - return false; - } - if ( ent == pushedGroup[i].ent ) { - return true; - } - } - return false; -} - -/* -============ -idPush::ClipTranslationAgainstPusher -============ -*/ -bool idPush::ClipTranslationAgainstPusher( trace_t &results, idEntity *ent, idEntity *pusher, const idVec3 &translation ) { - int i, n; - trace_t t; - - results.fraction = 1.0f; - - n = pusher->GetPhysics()->GetNumClipModels(); - for ( i = 0; i < n; i++ ) { - ent->GetPhysics()->ClipTranslation( t, translation, pusher->GetPhysics()->GetClipModel( i ) ); - if ( t.fraction < results.fraction ) { - results = t; - } - } - return ( results.fraction < 1.0f ); -} - -/* -============ -idPush::GetPushableEntitiesForTranslation -============ -*/ -int idPush::GetPushableEntitiesForTranslation( idEntity *pusher, idEntity *initialPusher, const int flags, - const idVec3 &translation, idEntity *entityList[], int maxEntities ) { - int i, n, l; - idBounds bounds, pushBounds; - idPhysics *physics; - - // get bounds for the whole movement - physics = pusher->GetPhysics(); - bounds = physics->GetBounds(); - pushBounds.FromBoundsTranslation( bounds, physics->GetOrigin(), physics->GetAxis(), translation ); - pushBounds.ExpandSelf( 2.0f ); - - // get all entities within the push bounds - n = gameLocal.clip.EntitiesTouchingBounds( pushBounds, -1, entityList, MAX_GENTITIES ); - - for ( l = i = 0; i < n; i++ ) { - if ( entityList[i] == pusher || entityList[i] == initialPusher ) { - continue; - } - if ( CanPushEntity( entityList[i], pusher, initialPusher, flags ) ) { - entityList[l++] = entityList[i]; - } - } - - return l; -} - -/* -============ -idPush::ClipTranslationalPush - - Try to push other entities by translating the given entity. -============ -*/ -float idPush::ClipTranslationalPush( trace_t &results, idEntity *pusher, const int flags, - const idVec3 &newOrigin, const idVec3 &translation ) { - int i, j, numListedEntities; - idEntity *curPusher, *ent, *entityList[ MAX_GENTITIES ]; - float fraction; - bool groundContact, blocked = false; - float totalMass; - trace_t trace; - idVec3 realTranslation, partialTranslation; - - totalMass = 0.0f; - - results.fraction = 1.0f; - results.endpos = newOrigin; - results.endAxis = pusher->GetPhysics()->GetAxis(); - memset( results.c, 0, sizeof( results.c ) ); - - if ( translation == vec3_origin ) { - return totalMass; - } - - // clip against all non-pushable physics objects - if ( flags & PUSHFL_CLIP ) { - - numListedEntities = GetPushableEntitiesForTranslation( pusher, pusher, flags, translation, entityList, MAX_GENTITIES ); - // disable pushable entities for collision detection - for ( i = 0; i < numListedEntities; i++ ) { - entityList[i]->GetPhysics()->DisableClip(); - } - // clip translation - pusher->GetPhysics()->ClipTranslation( results, translation, NULL ); - // enable pushable entities - for ( i = 0; i < numListedEntities; i++ ) { - entityList[i]->GetPhysics()->EnableClip(); - } - if ( results.fraction == 0.0f ) { - return totalMass; - } - realTranslation = results.fraction * translation; - } - else { - realTranslation = translation; - } - - // put the pusher in the group of pushed physics objects - pushedGroup[0].ent = pusher; - pushedGroup[0].fraction = 1.0f; - pushedGroup[0].groundContact = true; - pushedGroup[0].test = true; - pushedGroupSize = 1; - - // get all physics objects that need to be pushed - for ( i = 0; i < pushedGroupSize; ) { - if ( !pushedGroup[i].test ) { - i++; - continue; - } - pushedGroup[i].test = false; - curPusher = pushedGroup[i].ent; - fraction = pushedGroup[i].fraction; - groundContact = pushedGroup[i].groundContact; - i = 0; - - numListedEntities = GetPushableEntitiesForTranslation( curPusher, pusher, flags, realTranslation, entityList, MAX_GENTITIES ); - - for ( j = 0; j < numListedEntities; j++ ) { - ent = entityList[ j ]; - - if ( IsFullyPushed( ent ) ) { - continue; - } - - if ( !CanPushEntity( ent, curPusher, pusher, flags ) ) { - continue; - } - - if ( ent->GetPhysics()->IsGroundEntity( curPusher->entityNumber ) ) { - AddEntityToPushedGroup( ent, 1.0f * fraction, false ); - } - else if ( ClipTranslationAgainstPusher( trace, ent, curPusher, -fraction * realTranslation ) ) { - AddEntityToPushedGroup( ent, ( 1.0f - trace.fraction ) * fraction, groundContact ); - } - } - } - - // save physics states and disable physics objects for collision detection - for ( i = 0; i < pushedGroupSize; i++ ) { - SaveEntityPosition( pushedGroup[i].ent ); - pushedGroup[i].ent->GetPhysics()->DisableClip(); - } - - // clip all pushed physics objects - for ( i = 1; i < pushedGroupSize; i++ ) { - partialTranslation = realTranslation * pushedGroup[i].fraction; - - pushedGroup[i].ent->GetPhysics()->ClipTranslation( trace, partialTranslation, NULL ); - - if ( trace.fraction < 1.0f ) { - blocked = true; - break; - } - } - - // enable all physics objects for collision detection - for ( i = 1; i < pushedGroupSize; i++ ) { - pushedGroup[i].ent->GetPhysics()->EnableClip(); - } - - // push all or nothing - if ( blocked ) { - if ( flags & PUSHFL_CLIP ) { - pusher->GetPhysics()->ClipTranslation( results, realTranslation, NULL ); - } - else { - results.fraction = 0.0f; - results.endpos = pusher->GetPhysics()->GetOrigin(); - results.endAxis = pusher->GetPhysics()->GetAxis(); - } - } - else { - // translate all pushed physics objects - for ( i = 1; i < pushedGroupSize; i++ ) { - partialTranslation = realTranslation * pushedGroup[i].fraction; - pushedGroup[i].ent->GetPhysics()->Translate( partialTranslation ); - totalMass += pushedGroup[i].ent->GetPhysics()->GetMass(); - } - // translate the clip models of the pusher - for ( i = 0; i < pusher->GetPhysics()->GetNumClipModels(); i++ ) { - pusher->GetPhysics()->GetClipModel(i)->Translate( results.fraction * realTranslation ); - pusher->GetPhysics()->GetClipModel(i)->Link( gameLocal.clip ); - } - } - - return totalMass; -} - -/* -============ -idPush::ClipRotationAgainstPusher -============ -*/ -bool idPush::ClipRotationAgainstPusher( trace_t &results, idEntity *ent, idEntity *pusher, const idRotation &rotation ) { - int i, n; - trace_t t; - - results.fraction = 1.0f; - - n = pusher->GetPhysics()->GetNumClipModels(); - for ( i = 0; i < n; i++ ) { - ent->GetPhysics()->ClipRotation( t, rotation, pusher->GetPhysics()->GetClipModel( i ) ); - if ( t.fraction < results.fraction ) { - results = t; - } - } - return ( results.fraction < 1.0f ); -} - -/* -============ -idPush::GetPushableEntitiesForRotation -============ -*/ -int idPush::GetPushableEntitiesForRotation( idEntity *pusher, idEntity *initialPusher, const int flags, - const idRotation &rotation, idEntity *entityList[], int maxEntities ) { - int i, n, l; - idBounds bounds, pushBounds; - idPhysics *physics; - - // get bounds for the whole movement - physics = pusher->GetPhysics(); - bounds = physics->GetBounds(); - pushBounds.FromBoundsRotation( bounds, physics->GetOrigin(), physics->GetAxis(), rotation ); - pushBounds.ExpandSelf( 2.0f ); - - // get all entities within the push bounds - n = gameLocal.clip.EntitiesTouchingBounds( pushBounds, -1, entityList, MAX_GENTITIES ); - - for ( l = i = 0; i < n; i++ ) { - if ( entityList[i] == pusher || entityList[i] == initialPusher ) { - continue; - } - if ( CanPushEntity( entityList[i], pusher, initialPusher, flags ) ) { - entityList[l++] = entityList[i]; - } - } - - return l; -} - -/* -============ -idPush::ClipRotationalPush - - Try to push other entities by rotating the given entity. -============ -*/ -float idPush::ClipRotationalPush( trace_t &results, idEntity *pusher, const int flags, - const idMat3 &newAxis, const idRotation &rotation ) { - int i, j, numListedEntities; - idEntity *curPusher, *ent, *entityList[ MAX_GENTITIES ]; - float fraction; - bool groundContact, blocked = false; - float totalMass; - trace_t trace; - idRotation realRotation, partialRotation; - idMat3 oldAxis; - - totalMass = 0.0f; - - results.fraction = 1.0f; - results.endpos = pusher->GetPhysics()->GetOrigin(); - results.endAxis = newAxis; - memset( results.c, 0, sizeof( results.c ) ); - - if ( !rotation.GetAngle() ) { - return totalMass; - } - - // clip against all non-pushable physics objects - if ( flags & PUSHFL_CLIP ) { - - numListedEntities = GetPushableEntitiesForRotation( pusher, pusher, flags, rotation, entityList, MAX_GENTITIES ); - // disable pushable entities for collision detection - for ( i = 0; i < numListedEntities; i++ ) { - entityList[i]->GetPhysics()->DisableClip(); - } - // clip rotation - pusher->GetPhysics()->ClipRotation( results, rotation, NULL ); - // enable pushable entities - for ( i = 0; i < numListedEntities; i++ ) { - entityList[i]->GetPhysics()->EnableClip(); - } - if ( results.fraction == 0.0f ) { - return totalMass; - } - realRotation = results.fraction * rotation; - } - else { - realRotation = rotation; - } - - // put the pusher in the group of pushed physics objects - pushedGroup[0].ent = pusher; - pushedGroup[0].fraction = 1.0f; - pushedGroup[0].groundContact = true; - pushedGroup[0].test = true; - pushedGroupSize = 1; - - // get all physics objects that need to be pushed - for ( i = 0; i < pushedGroupSize; ) { - if ( !pushedGroup[i].test ) { - i++; - continue; - } - pushedGroup[i].test = false; - curPusher = pushedGroup[i].ent; - fraction = pushedGroup[i].fraction; - groundContact = pushedGroup[i].groundContact; - i = 0; - - numListedEntities = GetPushableEntitiesForRotation( curPusher, pusher, flags, realRotation, entityList, MAX_GENTITIES ); - - for ( j = 0; j < numListedEntities; j++ ) { - ent = entityList[ j ]; - - if ( IsFullyPushed( ent ) ) { - continue; - } - - if ( ent->GetPhysics()->IsGroundEntity( curPusher->entityNumber ) ) { - AddEntityToPushedGroup( ent, 1.0f * fraction, false ); - } - else if ( ClipRotationAgainstPusher( trace, ent, curPusher, -fraction * realRotation ) ) { - AddEntityToPushedGroup( ent, ( 1.0f - trace.fraction ) * fraction, groundContact ); - } - } - } - - // save physics states and disable physics objects for collision detection - for ( i = 1; i < pushedGroupSize; i++ ) { - SaveEntityPosition( pushedGroup[i].ent ); - pushedGroup[i].ent->GetPhysics()->DisableClip(); - } - - // clip all pushed physics objects - for ( i = 1; i < pushedGroupSize; i++ ) { - partialRotation = realRotation * pushedGroup[i].fraction; - - pushedGroup[i].ent->GetPhysics()->ClipRotation( trace, partialRotation, NULL ); - - if ( trace.fraction < 1.0f ) { - blocked = true; - break; - } - } - - // enable all physics objects for collision detection - for ( i = 1; i < pushedGroupSize; i++ ) { - pushedGroup[i].ent->GetPhysics()->EnableClip(); - } - - // push all or nothing - if ( blocked ) { - if ( flags & PUSHFL_CLIP ) { - pusher->GetPhysics()->ClipRotation( results, realRotation, NULL ); - } - else { - results.fraction = 0.0f; - results.endpos = pusher->GetPhysics()->GetOrigin(); - results.endAxis = pusher->GetPhysics()->GetAxis(); - } - } - else { - // rotate all pushed physics objects - for ( i = 1; i < pushedGroupSize; i++ ) { - partialRotation = realRotation * pushedGroup[i].fraction; - pushedGroup[i].ent->GetPhysics()->Rotate( partialRotation ); - totalMass += pushedGroup[i].ent->GetPhysics()->GetMass(); - } - // rotate the clip models of the pusher - for ( i = 0; i < pusher->GetPhysics()->GetNumClipModels(); i++ ) { - pusher->GetPhysics()->GetClipModel(i)->Rotate( realRotation ); - pusher->GetPhysics()->GetClipModel(i)->Link( gameLocal.clip ); - pusher->GetPhysics()->GetClipModel(i)->Enable(); - } - // rotate any actors back to axial - for ( i = 1; i < pushedGroupSize; i++ ) { - // if the entity is using actor physics - if ( pushedGroup[i].ent->GetPhysics()->IsType( idPhysics_Actor::Type ) ) { - - // rotate the collision model back to axial - if ( !RotateEntityToAxial( pushedGroup[i].ent, pushedGroup[i].ent->GetPhysics()->GetOrigin() ) ) { - // don't allow rotation if the bbox is no longer axial - results.fraction = 0.0f; - results.endpos = pusher->GetPhysics()->GetOrigin(); - results.endAxis = pusher->GetPhysics()->GetAxis(); - } - } - } - } - - return totalMass; -} - -#else /* !NEW_PUSH */ - -enum { - PUSH_NO, // not pushed - PUSH_OK, // pushed ok - PUSH_BLOCKED // blocked -}; - -/* -============ -idPush::ClipEntityRotation -============ -*/ -void idPush::ClipEntityRotation( trace_t &trace, const idEntity *ent, const idClipModel *clipModel, idClipModel *skip, const idRotation &rotation ) { - - if ( skip ) { - skip->Disable(); - } - - ent->GetPhysics()->ClipRotation( trace, rotation, clipModel ); - - if ( skip ) { - skip->Enable(); - } -} - -/* -============ -idPush::ClipEntityTranslation -============ -*/ -void idPush::ClipEntityTranslation( trace_t &trace, const idEntity *ent, const idClipModel *clipModel, idClipModel *skip, const idVec3 &translation ) { - - if ( skip ) { - skip->Disable(); - } - - ent->GetPhysics()->ClipTranslation( trace, translation, clipModel ); - - if ( skip ) { - skip->Enable(); - } -} - -/* -============ -idPush::TryRotatePushEntity -============ -*/ -#ifdef _DEBUG -// #define ROTATIONAL_PUSH_DEBUG -#endif - -int idPush::TryRotatePushEntity( trace_t &results, idEntity *check, idClipModel *clipModel, const int flags, - const idMat3 &newAxis, const idRotation &rotation ) { - trace_t trace; - idVec3 rotationPoint; - idRotation newRotation; - float checkAngle; - idPhysics *physics; - - physics = check->GetPhysics(); - -#ifdef ROTATIONAL_PUSH_DEBUG - bool startsolid = false; - if ( physics->ClipContents( clipModel ) ) { - startsolid = true; - } -#endif - - results.fraction = 1.0f; - results.endpos = clipModel->GetOrigin(); - results.endAxis = newAxis; - memset( &results.c, 0, sizeof( results.c ) ); - - // always pushed when standing on the pusher - if ( physics->IsGroundClipModel( clipModel->GetEntity()->entityNumber, clipModel->GetId() ) ) { - // rotate the entity colliding with all other entities except the pusher itself - ClipEntityRotation( trace, check, NULL, clipModel, rotation ); - // if there is a collision - if ( trace.fraction < 1.0f ) { - // angle along which the entity is pushed - checkAngle = rotation.GetAngle() * trace.fraction; - // test if the entity can stay at it's partly pushed position by rotating - // the entity in reverse only colliding with pusher - newRotation.Set( rotation.GetOrigin(), rotation.GetVec(), -(rotation.GetAngle() - checkAngle) ); - ClipEntityRotation( results, check, clipModel, NULL, newRotation ); - // if there is a collision - if ( results.fraction < 1.0f ) { - - // FIXME: try to push the blocking entity as well or try to slide along collision plane(s)? - - results.c.normal = -results.c.normal; - results.c.dist = -results.c.dist; - - // the entity will be crushed between the pusher and some other entity - return PUSH_BLOCKED; - } - } - else { - // angle along which the entity is pushed - checkAngle = rotation.GetAngle(); - } - // point to rotate entity bbox around back to axial - rotationPoint = physics->GetOrigin(); - } - else { - // rotate entity in reverse only colliding with pusher - newRotation = rotation; - newRotation.Scale( -1 ); - // - ClipEntityRotation( results, check, clipModel, NULL, newRotation ); - // if no collision with the pusher then the entity is not pushed by the pusher - if ( results.fraction >= 1.0f ) { -#ifdef ROTATIONAL_PUSH_DEBUG - // set pusher into final position - clipModel->Link( gameLocal.clip, clipModel->GetEntity(), clipModel->GetId(), clipModel->GetOrigin(), newAxis ); - if ( physics->ClipContents( clipModel ) ) { - if ( !startsolid ) { - int bah = 1; - } - } -#endif - return PUSH_NO; - } - // get point to rotate bbox around back to axial - rotationPoint = results.c.point; - // angle along which the entity will be pushed - checkAngle = rotation.GetAngle() * (1.0f - results.fraction); - // rotate the entity colliding with all other entities except the pusher itself - newRotation.Set( rotation.GetOrigin(), rotation.GetVec(), checkAngle ); - ClipEntityRotation( trace, check, NULL, clipModel, newRotation ); - // if there is a collision - if ( trace.fraction < 1.0f ) { - - // FIXME: try to push the blocking entity as well or try to slide along collision plane(s)? - - results.c.normal = -results.c.normal; - results.c.dist = -results.c.dist; - - // the entity will be crushed between the pusher and some other entity - return PUSH_BLOCKED; - } - } - - SaveEntityPosition( check ); - - newRotation.Set( rotation.GetOrigin(), rotation.GetVec(), checkAngle ); - - newRotation.RotatePoint( rotationPoint ); - - // rotate the entity - physics->Rotate( newRotation ); - - // set pusher into final position - clipModel->Link( gameLocal.clip, clipModel->GetEntity(), clipModel->GetId(), clipModel->GetOrigin(), newAxis ); - -#ifdef ROTATIONAL_PUSH_DEBUG - if ( physics->ClipContents( clipModel ) ) { - if ( !startsolid ) { - int bah = 1; - } - } -#endif - - // if the entity uses actor physics - if ( physics->IsType( idPhysics_Actor::Type ) ) { - - // rotate the collision model back to axial - if ( !RotateEntityToAxial( check, rotationPoint ) ) { - // don't allow rotation if the bbox is no longer axial - return PUSH_BLOCKED; - } - } - -#ifdef ROTATIONAL_PUSH_DEBUG - if ( physics->ClipContents( clipModel ) ) { - if ( !startsolid ) { - int bah = 1; - } - } -#endif - - // if the entity is an actor using actor physics - if ( check->IsType( idActor::Type ) && physics->IsType( idPhysics_Actor::Type ) ) { - - // if the entity is standing ontop of the pusher - if ( physics->IsGroundClipModel( clipModel->GetEntity()->entityNumber, clipModel->GetId() ) ) { - // rotate actor view - idActor *actor = static_cast(check); - idAngles delta = actor->GetDeltaViewAngles(); - delta.yaw += newRotation.ToMat3()[0].ToYaw(); - actor->SetDeltaViewAngles( delta ); - } - } - - return PUSH_OK; -} - -/* -============ -idPush::TryTranslatePushEntity -============ -*/ -#ifdef _DEBUG -// #define TRANSLATIONAL_PUSH_DEBUG -#endif - -int idPush::TryTranslatePushEntity( trace_t &results, idEntity *check, idClipModel *clipModel, const int flags, - const idVec3 &newOrigin, const idVec3 &move ) { - trace_t trace; - idVec3 checkMove; - idVec3 oldOrigin; - idPhysics *physics; - - physics = check->GetPhysics(); - -#ifdef TRANSLATIONAL_PUSH_DEBUG - bool startsolid = false; - if ( physics->ClipContents( clipModel ) ) { - startsolid = true; - } -#endif - - results.fraction = 1.0f; - results.endpos = newOrigin; - results.endAxis = clipModel->GetAxis(); - memset( &results.c, 0, sizeof( results.c ) ); - - // always pushed when standing on the pusher - if ( physics->IsGroundClipModel( clipModel->GetEntity()->entityNumber, clipModel->GetId() ) ) { - // move the entity colliding with all other entities except the pusher itself - ClipEntityTranslation( trace, check, NULL, clipModel, move ); - // if there is a collision - if ( trace.fraction < 1.0f ) { - // vector along which the entity is pushed - checkMove = move * trace.fraction; - // test if the entity can stay at it's partly pushed position by moving the entity in reverse only colliding with pusher - ClipEntityTranslation( results, check, clipModel, NULL, -(move - checkMove) ); - // if there is a collision - if ( results.fraction < 1.0f ) { - - // FIXME: try to push the blocking entity as well or try to slide along collision plane(s)? - - results.c.normal = -results.c.normal; - results.c.dist = -results.c.dist; - - // the entity will be crushed between the pusher and some other entity - return PUSH_BLOCKED; - } - } - else { - // vector along which the entity is pushed - checkMove = move; - } - } - else { - // move entity in reverse only colliding with pusher - ClipEntityTranslation( results, check, clipModel, NULL, -move ); - // if no collision with the pusher then the entity is not pushed by the pusher - if ( results.fraction >= 1.0f ) { - return PUSH_NO; - } - // vector along which the entity is pushed - checkMove = move * (1.0f - results.fraction); - // move the entity colliding with all other entities except the pusher itself - ClipEntityTranslation( trace, check, NULL, clipModel, checkMove ); - // if there is a collisions - if ( trace.fraction < 1.0f ) { - - results.c.normal = -results.c.normal; - results.c.dist = -results.c.dist; - - // FIXME: try to push the blocking entity as well ? - // FIXME: handle sliding along more than one collision plane ? - // FIXME: this code has issues, player pushing box into corner in "maps/mre/aaron/test.map" - -/* - oldOrigin = physics->GetOrigin(); - - // movement still remaining - checkMove *= (1.0f - trace.fraction); - - // project the movement along the collision plane - if ( !checkMove.ProjectAlongPlane( trace.c.normal, 0.1f, 1.001f ) ) { - return PUSH_BLOCKED; - } - checkMove *= 1.001f; - - // move entity from collision point along the collision plane - physics->SetOrigin( trace.endpos ); - ClipEntityTranslation( trace, check, NULL, NULL, checkMove ); - - if ( trace.fraction < 1.0f ) { - physics->SetOrigin( oldOrigin ); - return PUSH_BLOCKED; - } - - checkMove = trace.endpos - oldOrigin; - - // move entity in reverse only colliding with pusher - physics->SetOrigin( trace.endpos ); - ClipEntityTranslation( trace, check, clipModel, NULL, -move ); - - physics->SetOrigin( oldOrigin ); -*/ - if ( trace.fraction < 1.0f ) { - return PUSH_BLOCKED; - } - } - } - - SaveEntityPosition( check ); - - // translate the entity - physics->Translate( checkMove ); - -#ifdef TRANSLATIONAL_PUSH_DEBUG - // set the pusher in the translated position - clipModel->Link( gameLocal.clip, clipModel->GetEntity(), clipModel->GetId(), newOrigin, clipModel->GetAxis() ); - if ( physics->ClipContents( clipModel ) ) { - if ( !startsolid ) { - int bah = 1; - } - } -#endif - - return PUSH_OK; -} - -/* -============ -idPush::DiscardEntities -============ -*/ -int idPush::DiscardEntities( idEntity *entityList[], int numEntities, int flags, idEntity *pusher ) { - int i, num; - idEntity *check; - - // remove all entities we cannot or should not push from the list - for ( num = i = 0; i < numEntities; i++ ) { - check = entityList[ i ]; - - // if the physics object is not pushable - if ( !check->GetPhysics()->IsPushable() ) { - continue; - } - - // if the entity doesn't clip with this pusher - if ( !( check->GetPhysics()->GetClipMask() & pusher->GetPhysics()->GetContents() ) ) { - continue; - } - - // don't push players in noclip mode - if ( check->IsType( idPlayer::Type ) && static_cast(check)->noclip ) { - continue; - } - - // if we should only push idMoveable entities - if ( ( flags & PUSHFL_ONLYMOVEABLE ) && !check->IsType( idMoveable::Type ) ) { - continue; - } - - // if we shouldn't push entities the clip model rests upon - if ( flags & PUSHFL_NOGROUNDENTITIES ) { - if ( pusher->GetPhysics()->IsGroundEntity( check->entityNumber ) ) { - continue; - } - } - - // keep entity in list - entityList[ num++ ] = entityList[i]; - } - - return num; -} - -/* -============ -idPush::ClipTranslationalPush - - Try to push other entities by moving the given entity. -============ -*/ -float idPush::ClipTranslationalPush( trace_t &results, idEntity *pusher, const int flags, - const idVec3 &newOrigin, const idVec3 &translation ) { - int i, listedEntities, res; - idEntity *check, *entityList[ MAX_GENTITIES ]; - idBounds bounds, pushBounds; - idVec3 clipMove, clipOrigin, oldOrigin, dir, impulse; - trace_t pushResults; - bool wasEnabled; - float totalMass; - idClipModel *clipModel; - - clipModel = pusher->GetPhysics()->GetClipModel(); - - totalMass = 0.0f; - - results.fraction = 1.0f; - results.endpos = newOrigin; - results.endAxis = clipModel->GetAxis(); - memset( &results.c, 0, sizeof( results.c ) ); - - if ( translation == vec3_origin ) { - return totalMass; - } - - dir = translation; - dir.Normalize(); - dir.z += 1.0f; - dir *= 10.0f; - - // get bounds for the whole movement - bounds = clipModel->GetBounds(); - if ( bounds[0].x >= bounds[1].x ) { - return totalMass; - } - pushBounds.FromBoundsTranslation( bounds, clipModel->GetOrigin(), clipModel->GetAxis(), translation ); - - wasEnabled = clipModel->IsEnabled(); - - // make sure we don't get the pushing clip model in the list - clipModel->Disable(); - - listedEntities = gameLocal.clip.EntitiesTouchingBounds( pushBounds, -1, entityList, MAX_GENTITIES ); - - // discard entities we cannot or should not push - listedEntities = DiscardEntities( entityList, listedEntities, flags, pusher ); - - if ( flags & PUSHFL_CLIP ) { - - // can only clip movement of a trace model - assert( clipModel->IsTraceModel() ); - - // disable to be pushed entities for collision detection - for ( i = 0; i < listedEntities; i++ ) { - entityList[i]->GetPhysics()->DisableClip(); - } - - gameLocal.clip.Translation( results, clipModel->GetOrigin(), clipModel->GetOrigin() + translation, clipModel, clipModel->GetAxis(), pusher->GetPhysics()->GetClipMask(), NULL ); - - // enable to be pushed entities for collision detection - for ( i = 0; i < listedEntities; i++ ) { - entityList[i]->GetPhysics()->EnableClip(); - } - - if ( results.fraction == 0.0f ) { - if ( wasEnabled ) { - clipModel->Enable(); - } - return totalMass; - } - - clipMove = results.endpos - clipModel->GetOrigin(); - clipOrigin = results.endpos; - - } - else { - - clipMove = translation; - clipOrigin = newOrigin; - } - - // we have to enable the clip model because we use it during pushing - clipModel->Enable(); - - // save pusher old position - oldOrigin = clipModel->GetOrigin(); - - // try to push the entities - for ( i = 0; i < listedEntities; i++ ) { - - check = entityList[ i ]; - - idPhysics *physics = check->GetPhysics(); - - // disable the entity for collision detection - physics->DisableClip(); - - res = TryTranslatePushEntity( pushResults, check, clipModel, flags, clipOrigin, clipMove ); - - // enable the entity for collision detection - physics->EnableClip(); - - // if the entity is pushed - if ( res == PUSH_OK ) { - // set the pusher in the translated position - clipModel->Link( gameLocal.clip, clipModel->GetEntity(), clipModel->GetId(), newOrigin, clipModel->GetAxis() ); - // the entity might be pushed off the ground - physics->EvaluateContacts(); - // put pusher back in old position - clipModel->Link( gameLocal.clip, clipModel->GetEntity(), clipModel->GetId(), oldOrigin, clipModel->GetAxis() ); - - // wake up this object - if ( flags & PUSHFL_APPLYIMPULSE ) { - impulse = physics->GetMass() * dir; - } else { - impulse.Zero(); - } - check->ApplyImpulse( clipModel->GetEntity(), clipModel->GetId(), clipModel->GetOrigin(), impulse ); - - // add mass of pushed entity - totalMass += physics->GetMass(); - } - - // if the entity is not blocking - if ( res != PUSH_BLOCKED ) { - continue; - } - - // if the blocking entity is a projectile - if ( check->IsType( idProjectile::Type ) ) { - check->ProcessEvent( &EV_Explode ); - continue; - } - - // if blocking entities should be crushed - if ( flags & PUSHFL_CRUSH ) { - check->Damage( clipModel->GetEntity(), clipModel->GetEntity(), vec3_origin, "damage_crush", 1.0f, CLIPMODEL_ID_TO_JOINT_HANDLE( pushResults.c.id ) ); - continue; - } - - // if the entity is an active articulated figure and gibs - if ( check->IsType( idAFEntity_Base::Type ) && check->spawnArgs.GetBool( "gib" ) ) { - if ( static_cast(check)->IsActiveAF() ) { - check->ProcessEvent( &EV_Gib, "damage_Gib" ); - } - } - - // if the entity is a moveable item and gibs - if ( check->IsType( idMoveableItem::Type ) && check->spawnArgs.GetBool( "gib" ) ) { - check->ProcessEvent( &EV_Gib, "damage_Gib" ); - } - - // blocked - results = pushResults; - results.fraction = 0.0f; - results.endAxis = clipModel->GetAxis(); - results.endpos = clipModel->GetOrigin(); - results.c.entityNum = check->entityNumber; - results.c.id = 0; - - if ( !wasEnabled ) { - clipModel->Disable(); - } - - return totalMass; - } - - if ( !wasEnabled ) { - clipModel->Disable(); - } - - return totalMass; -} - -/* -============ -idPush::ClipRotationalPush - - Try to push other entities by moving the given entity. -============ -*/ -float idPush::ClipRotationalPush( trace_t &results, idEntity *pusher, const int flags, - const idMat3 &newAxis, const idRotation &rotation ) { - int i, listedEntities, res; - idEntity *check, *entityList[ MAX_GENTITIES ]; - idBounds bounds, pushBounds; - idRotation clipRotation; - idMat3 clipAxis, oldAxis; - trace_t pushResults; - bool wasEnabled; - float totalMass; - idClipModel *clipModel; - - clipModel = pusher->GetPhysics()->GetClipModel(); - - totalMass = 0.0f; - - results.fraction = 1.0f; - results.endpos = clipModel->GetOrigin(); - results.endAxis = newAxis; - memset( &results.c, 0, sizeof( results.c ) ); - - if ( !rotation.GetAngle() ) { - return totalMass; - } - - // get bounds for the whole movement - bounds = clipModel->GetBounds(); - if ( bounds[0].x >= bounds[1].x ) { - return totalMass; - } - pushBounds.FromBoundsRotation( bounds, clipModel->GetOrigin(), clipModel->GetAxis(), rotation ); - - wasEnabled = clipModel->IsEnabled(); - - // make sure we don't get the pushing clip model in the list - clipModel->Disable(); - - listedEntities = gameLocal.clip.EntitiesTouchingBounds( pushBounds, -1, entityList, MAX_GENTITIES ); - - // discard entities we cannot or should not push - listedEntities = DiscardEntities( entityList, listedEntities, flags, pusher ); - - if ( flags & PUSHFL_CLIP ) { - - // can only clip movement of a trace model - assert( clipModel->IsTraceModel() ); - - // disable to be pushed entities for collision detection - for ( i = 0; i < listedEntities; i++ ) { - entityList[i]->GetPhysics()->DisableClip(); - } - - gameLocal.clip.Rotation( results, clipModel->GetOrigin(), rotation, clipModel, clipModel->GetAxis(), pusher->GetPhysics()->GetClipMask(), NULL ); - - // enable to be pushed entities for collision detection - for ( i = 0; i < listedEntities; i++ ) { - entityList[i]->GetPhysics()->EnableClip(); - } - - if ( results.fraction == 0.0f ) { - if ( wasEnabled ) { - clipModel->Enable(); - } - return totalMass; - } - - clipRotation = rotation * results.fraction; - clipAxis = results.endAxis; - } - else { - - clipRotation = rotation; - clipAxis = newAxis; - } - - // we have to enable the clip model because we use it during pushing - clipModel->Enable(); - - // save pusher old position - oldAxis = clipModel->GetAxis(); - - // try to push all the entities - for ( i = 0; i < listedEntities; i++ ) { - - check = entityList[ i ]; - - idPhysics *physics = check->GetPhysics(); - - // disable the entity for collision detection - physics->DisableClip(); - - res = TryRotatePushEntity( pushResults, check, clipModel, flags, clipAxis, clipRotation ); - - // enable the entity for collision detection - physics->EnableClip(); - - // if the entity is pushed - if ( res == PUSH_OK ) { - // set the pusher in the rotated position - clipModel->Link( gameLocal.clip, clipModel->GetEntity(), clipModel->GetId(), clipModel->GetOrigin(), newAxis ); - // the entity might be pushed off the ground - physics->EvaluateContacts(); - // put pusher back in old position - clipModel->Link( gameLocal.clip, clipModel->GetEntity(), clipModel->GetId(), clipModel->GetOrigin(), oldAxis ); - - // wake up this object - check->ApplyImpulse( clipModel->GetEntity(), clipModel->GetId(), clipModel->GetOrigin(), vec3_origin ); - - // add mass of pushed entity - totalMass += physics->GetMass(); - } - - // if the entity is not blocking - if ( res != PUSH_BLOCKED ) { - continue; - } - - // if the blocking entity is a projectile - if ( check->IsType( idProjectile::Type ) ) { - check->ProcessEvent( &EV_Explode ); - continue; - } - - // if blocking entities should be crushed - if ( flags & PUSHFL_CRUSH ) { - check->Damage( clipModel->GetEntity(), clipModel->GetEntity(), vec3_origin, "damage_crush", 1.0f, CLIPMODEL_ID_TO_JOINT_HANDLE( pushResults.c.id ) ); - continue; - } - - // if the entity is an active articulated figure and gibs - if ( check->IsType( idAFEntity_Base::Type ) && check->spawnArgs.GetBool( "gib" ) ) { - if ( static_cast(check)->IsActiveAF() ) { - check->ProcessEvent( &EV_Gib, "damage_Gib" ); - } - } - - // blocked - results = pushResults; - results.fraction = 0.0f; - results.endAxis = clipModel->GetAxis(); - results.endpos = clipModel->GetOrigin(); - results.c.entityNum = check->entityNumber; - results.c.id = 0; - - if ( !wasEnabled ) { - clipModel->Disable(); - } - - return totalMass; - } - - if ( !wasEnabled ) { - clipModel->Disable(); - } - - return totalMass; -} - -#endif /* !NEW_PUSH */ - - -/* -============ -idPush::ClipPush - - Try to push other entities by moving the given entity. -============ -*/ -float idPush::ClipPush( trace_t &results, idEntity *pusher, const int flags, - const idVec3 &oldOrigin, const idMat3 &oldAxis, - idVec3 &newOrigin, idMat3 &newAxis ) { - idVec3 translation; - idRotation rotation; - float mass; - - mass = 0.0f; - - results.fraction = 1.0f; - results.endpos = newOrigin; - results.endAxis = newAxis; - memset( &results.c, 0, sizeof( results.c ) ); - - // translational push - translation = newOrigin - oldOrigin; - - // if the pusher translates - if ( translation != vec3_origin ) { - - mass += ClipTranslationalPush( results, pusher, flags, newOrigin, translation ); - if ( results.fraction < 1.0f ) { - newOrigin = oldOrigin; - newAxis = oldAxis; - return mass; - } - } else { - newOrigin = oldOrigin; - } - - // rotational push - rotation = ( oldAxis.Transpose() * newAxis ).ToRotation(); - rotation.SetOrigin( newOrigin ); - rotation.Normalize180(); - rotation.ReCalculateMatrix(); // recalculate the rotation matrix to avoid accumulating rounding errors - - // if the pusher rotates - if ( rotation.GetAngle() != 0.0f ) { - - // recalculate new axis to avoid floating point rounding problems - newAxis = oldAxis * rotation.ToMat3(); - newAxis.OrthoNormalizeSelf(); - newAxis.FixDenormals(); - newAxis.FixDegeneracies(); - - pusher->GetPhysics()->GetClipModel()->SetPosition( newOrigin, oldAxis ); - - mass += ClipRotationalPush( results, pusher, flags, newAxis, rotation ); - if ( results.fraction < 1.0f ) { - newOrigin = oldOrigin; - newAxis = oldAxis; - return mass; - } - } else { - newAxis = oldAxis; - } - - return mass; -} diff --git a/d3xp/physics/Push.h b/d3xp/physics/Push.h deleted file mode 100644 index 0cb7406a..00000000 --- a/d3xp/physics/Push.h +++ /dev/null @@ -1,120 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __PUSH_H__ -#define __PUSH_H__ - -#include "cm/CollisionModel.h" - -#include "physics/Clip.h" -#include "GameBase.h" - -class idEntity; - -/* -=============================================================================== - - Allows physics objects to be pushed geometrically. - -=============================================================================== -*/ - -#define PUSHFL_ONLYMOVEABLE 1 // only push moveable entities -#define PUSHFL_NOGROUNDENTITIES 2 // don't push entities the clip model rests upon -#define PUSHFL_CLIP 4 // also clip against all non-moveable entities -#define PUSHFL_CRUSH 8 // kill blocking entities -#define PUSHFL_APPLYIMPULSE 16 // apply impulse to pushed entities - -//#define NEW_PUSH - -class idPush { -public: - // Try to push other entities by moving the given entity. - // If results.fraction < 1.0 the move was blocked by results.c.entityNum - // Returns total mass of all pushed entities. - float ClipTranslationalPush( trace_t &results, idEntity *pusher, const int flags, - const idVec3 &newOrigin, const idVec3 &move ); - - float ClipRotationalPush( trace_t &results, idEntity *pusher, const int flags, - const idMat3 &newAxis, const idRotation &rotation ); - - float ClipPush( trace_t &results, idEntity *pusher, const int flags, - const idVec3 &oldOrigin, const idMat3 &oldAxis, - idVec3 &newOrigin, idMat3 &newAxis ); - - // initialize saving the positions of entities being pushed - void InitSavingPushedEntityPositions( void ); - // move all pushed entities back to their previous position - void RestorePushedEntityPositions( void ); - // returns the number of pushed entities - int GetNumPushedEntities( void ) const { return numPushed; } - // get the ith pushed entity - idEntity * GetPushedEntity( int i ) const { assert( i >= 0 && i < numPushed ); return pushed[i].ent; } - -private: - struct pushed_s { - idEntity * ent; // pushed entity - idAngles deltaViewAngles; // actor delta view angles - } pushed[MAX_GENTITIES]; // pushed entities - int numPushed; // number of pushed entities - - struct pushedGroup_s { - idEntity * ent; - float fraction; - bool groundContact; - bool test; - } pushedGroup[MAX_GENTITIES]; - int pushedGroupSize; - -private: - void SaveEntityPosition( idEntity *ent ); - bool RotateEntityToAxial( idEntity *ent, idVec3 rotationPoint ); -#ifdef NEW_PUSH - bool CanPushEntity( idEntity *ent, idEntity *pusher, idEntity *initialPusher, const int flags ); - void AddEntityToPushedGroup( idEntity *ent, float fraction, bool groundContact ); - bool IsFullyPushed( idEntity *ent ); - bool ClipTranslationAgainstPusher( trace_t &results, idEntity *ent, idEntity *pusher, const idVec3 &translation ); - int GetPushableEntitiesForTranslation( idEntity *pusher, idEntity *initialPusher, const int flags, - const idVec3 &translation, idEntity *entityList[], int maxEntities ); - bool ClipRotationAgainstPusher( trace_t &results, idEntity *ent, idEntity *pusher, const idRotation &rotation ); - int GetPushableEntitiesForRotation( idEntity *pusher, idEntity *initialPusher, const int flags, - const idRotation &rotation, idEntity *entityList[], int maxEntities ); -#else - void ClipEntityRotation( trace_t &trace, const idEntity *ent, const idClipModel *clipModel, - idClipModel *skip, const idRotation &rotation ); - void ClipEntityTranslation( trace_t &trace, const idEntity *ent, const idClipModel *clipModel, - idClipModel *skip, const idVec3 &translation ); - int TryTranslatePushEntity( trace_t &results, idEntity *check, idClipModel *clipModel, const int flags, - const idVec3 &newOrigin, const idVec3 &move ); - int TryRotatePushEntity( trace_t &results, idEntity *check, idClipModel *clipModel, const int flags, - const idMat3 &newAxis, const idRotation &rotation ); - int DiscardEntities( idEntity *entityList[], int numEntities, int flags, idEntity *pusher ); -#endif -}; - -#endif /* !__PUSH_H__ */ diff --git a/d3xp/script/Script_Compiler.cpp b/d3xp/script/Script_Compiler.cpp deleted file mode 100644 index 7f28d8e7..00000000 --- a/d3xp/script/Script_Compiler.cpp +++ /dev/null @@ -1,2700 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "idlib/Timer.h" -#include "framework/FileSystem.h" - -#include "script/Script_Thread.h" -#include "Game_local.h" - -#include "script/Script_Compiler.h" - -#define FUNCTION_PRIORITY 2 -#define INT_PRIORITY 2 -#define NOT_PRIORITY 5 -#define TILDE_PRIORITY 5 -#define TOP_PRIORITY 7 - -bool idCompiler::punctuationValid[ 256 ]; -const char *idCompiler::punctuation[] = { - "+=", "-=", "*=", "/=", "%=", "&=", "|=", "++", "--", - "&&", "||", "<=", ">=", "==", "!=", "::", ";", ",", - "~", "!", "*", "/", "%", "(", ")", "-", "+", - "=", "[", "]", ".", "<", ">" , "&", "|", ":", NULL -}; - -const opcode_t idCompiler::opcodes[] = { - { "", "RETURN", -1, false, &def_void, &def_void, &def_void }, - - { "++", "UINC_F", 1, true, &def_float, &def_void, &def_void }, - { "++", "UINCP_F", 1, true, &def_object, &def_field, &def_float }, - { "--", "UDEC_F", 1, true, &def_float, &def_void, &def_void }, - { "--", "UDECP_F", 1, true, &def_object, &def_field, &def_float }, - - { "~", "COMP_F", -1, false, &def_float, &def_void, &def_float }, - - { "*", "MUL_F", 3, false, &def_float, &def_float, &def_float }, - { "*", "MUL_V", 3, false, &def_vector, &def_vector, &def_float }, - { "*", "MUL_FV", 3, false, &def_float, &def_vector, &def_vector }, - { "*", "MUL_VF", 3, false, &def_vector, &def_float, &def_vector }, - - { "/", "DIV", 3, false, &def_float, &def_float, &def_float }, - { "%", "MOD_F", 3, false, &def_float, &def_float, &def_float }, - - { "+", "ADD_F", 4, false, &def_float, &def_float, &def_float }, - { "+", "ADD_V", 4, false, &def_vector, &def_vector, &def_vector }, - { "+", "ADD_S", 4, false, &def_string, &def_string, &def_string }, - { "+", "ADD_FS", 4, false, &def_float, &def_string, &def_string }, - { "+", "ADD_SF", 4, false, &def_string, &def_float, &def_string }, - { "+", "ADD_VS", 4, false, &def_vector, &def_string, &def_string }, - { "+", "ADD_SV", 4, false, &def_string, &def_vector, &def_string }, - - { "-", "SUB_F", 4, false, &def_float, &def_float, &def_float }, - { "-", "SUB_V", 4, false, &def_vector, &def_vector, &def_vector }, - - { "==", "EQ_F", 5, false, &def_float, &def_float, &def_float }, - { "==", "EQ_V", 5, false, &def_vector, &def_vector, &def_float }, - { "==", "EQ_S", 5, false, &def_string, &def_string, &def_float }, - { "==", "EQ_E", 5, false, &def_entity, &def_entity, &def_float }, - { "==", "EQ_EO", 5, false, &def_entity, &def_object, &def_float }, - { "==", "EQ_OE", 5, false, &def_object, &def_entity, &def_float }, - { "==", "EQ_OO", 5, false, &def_object, &def_object, &def_float }, - - { "!=", "NE_F", 5, false, &def_float, &def_float, &def_float }, - { "!=", "NE_V", 5, false, &def_vector, &def_vector, &def_float }, - { "!=", "NE_S", 5, false, &def_string, &def_string, &def_float }, - { "!=", "NE_E", 5, false, &def_entity, &def_entity, &def_float }, - { "!=", "NE_EO", 5, false, &def_entity, &def_object, &def_float }, - { "!=", "NE_OE", 5, false, &def_object, &def_entity, &def_float }, - { "!=", "NE_OO", 5, false, &def_object, &def_object, &def_float }, - - { "<=", "LE", 5, false, &def_float, &def_float, &def_float }, - { ">=", "GE", 5, false, &def_float, &def_float, &def_float }, - { "<", "LT", 5, false, &def_float, &def_float, &def_float }, - { ">", "GT", 5, false, &def_float, &def_float, &def_float }, - - { ".", "INDIRECT_F", 1, false, &def_object, &def_field, &def_float }, - { ".", "INDIRECT_V", 1, false, &def_object, &def_field, &def_vector }, - { ".", "INDIRECT_S", 1, false, &def_object, &def_field, &def_string }, - { ".", "INDIRECT_E", 1, false, &def_object, &def_field, &def_entity }, - { ".", "INDIRECT_BOOL", 1, false, &def_object, &def_field, &def_boolean }, - { ".", "INDIRECT_OBJ", 1, false, &def_object, &def_field, &def_object }, - - { ".", "ADDRESS", 1, false, &def_entity, &def_field, &def_pointer }, - - { ".", "EVENTCALL", 2, false, &def_entity, &def_function, &def_void }, - { ".", "OBJECTCALL", 2, false, &def_object, &def_function, &def_void }, - { ".", "SYSCALL", 2, false, &def_void, &def_function, &def_void }, - - { "=", "STORE_F", 6, true, &def_float, &def_float, &def_float }, - { "=", "STORE_V", 6, true, &def_vector, &def_vector, &def_vector }, - { "=", "STORE_S", 6, true, &def_string, &def_string, &def_string }, - { "=", "STORE_ENT", 6, true, &def_entity, &def_entity, &def_entity }, - { "=", "STORE_BOOL", 6, true, &def_boolean, &def_boolean, &def_boolean }, - { "=", "STORE_OBJENT", 6, true, &def_object, &def_entity, &def_object }, - { "=", "STORE_OBJ", 6, true, &def_object, &def_object, &def_object }, - { "=", "STORE_OBJENT", 6, true, &def_entity, &def_object, &def_object }, - - { "=", "STORE_FTOS", 6, true, &def_string, &def_float, &def_string }, - { "=", "STORE_BTOS", 6, true, &def_string, &def_boolean, &def_string }, - { "=", "STORE_VTOS", 6, true, &def_string, &def_vector, &def_string }, - { "=", "STORE_FTOBOOL", 6, true, &def_boolean, &def_float, &def_boolean }, - { "=", "STORE_BOOLTOF", 6, true, &def_float, &def_boolean, &def_float }, - - { "=", "STOREP_F", 6, true, &def_pointer, &def_float, &def_float }, - { "=", "STOREP_V", 6, true, &def_pointer, &def_vector, &def_vector }, - { "=", "STOREP_S", 6, true, &def_pointer, &def_string, &def_string }, - { "=", "STOREP_ENT", 6, true, &def_pointer, &def_entity, &def_entity }, - { "=", "STOREP_FLD", 6, true, &def_pointer, &def_field, &def_field }, - { "=", "STOREP_BOOL", 6, true, &def_pointer, &def_boolean, &def_boolean }, - { "=", "STOREP_OBJ", 6, true, &def_pointer, &def_object, &def_object }, - { "=", "STOREP_OBJENT", 6, true, &def_pointer, &def_object, &def_object }, - - { "<=>", "STOREP_FTOS", 6, true, &def_pointer, &def_float, &def_string }, - { "<=>", "STOREP_BTOS", 6, true, &def_pointer, &def_boolean, &def_string }, - { "<=>", "STOREP_VTOS", 6, true, &def_pointer, &def_vector, &def_string }, - { "<=>", "STOREP_FTOBOOL", 6, true, &def_pointer, &def_float, &def_boolean }, - { "<=>", "STOREP_BOOLTOF", 6, true, &def_pointer, &def_boolean, &def_float }, - - { "*=", "UMUL_F", 6, true, &def_float, &def_float, &def_void }, - { "*=", "UMUL_V", 6, true, &def_vector, &def_float, &def_void }, - { "/=", "UDIV_F", 6, true, &def_float, &def_float, &def_void }, - { "/=", "UDIV_V", 6, true, &def_vector, &def_float, &def_void }, - { "%=", "UMOD_F", 6, true, &def_float, &def_float, &def_void }, - { "+=", "UADD_F", 6, true, &def_float, &def_float, &def_void }, - { "+=", "UADD_V", 6, true, &def_vector, &def_vector, &def_void }, - { "-=", "USUB_F", 6, true, &def_float, &def_float, &def_void }, - { "-=", "USUB_V", 6, true, &def_vector, &def_vector, &def_void }, - { "&=", "UAND_F", 6, true, &def_float, &def_float, &def_void }, - { "|=", "UOR_F", 6, true, &def_float, &def_float, &def_void }, - - { "!", "NOT_BOOL", -1, false, &def_boolean, &def_void, &def_float }, - { "!", "NOT_F", -1, false, &def_float, &def_void, &def_float }, - { "!", "NOT_V", -1, false, &def_vector, &def_void, &def_float }, - { "!", "NOT_S", -1, false, &def_vector, &def_void, &def_float }, - { "!", "NOT_ENT", -1, false, &def_entity, &def_void, &def_float }, - - { "", "NEG_F", -1, false, &def_float, &def_void, &def_float }, - { "", "NEG_V", -1, false, &def_vector, &def_void, &def_vector }, - - { "int", "INT_F", -1, false, &def_float, &def_void, &def_float }, - - { "", "IF", -1, false, &def_float, &def_jumpoffset, &def_void }, - { "", "IFNOT", -1, false, &def_float, &def_jumpoffset, &def_void }, - - // calls returns REG_RETURN - { "", "CALL", -1, false, &def_function, &def_argsize, &def_void }, - { "", "THREAD", -1, false, &def_function, &def_argsize, &def_void }, - { "", "OBJTHREAD", -1, false, &def_function, &def_argsize, &def_void }, - - { "", "PUSH_F", -1, false, &def_float, &def_float, &def_void }, - { "", "PUSH_V", -1, false, &def_vector, &def_vector, &def_void }, - { "", "PUSH_S", -1, false, &def_string, &def_string, &def_void }, - { "", "PUSH_ENT", -1, false, &def_entity, &def_entity, &def_void }, - { "", "PUSH_OBJ", -1, false, &def_object, &def_object, &def_void }, - { "", "PUSH_OBJENT", -1, false, &def_entity, &def_object, &def_void }, - { "", "PUSH_FTOS", -1, false, &def_string, &def_float, &def_void }, - { "", "PUSH_BTOF", -1, false, &def_float, &def_boolean, &def_void }, - { "", "PUSH_FTOB", -1, false, &def_boolean, &def_float, &def_void }, - { "", "PUSH_VTOS", -1, false, &def_string, &def_vector, &def_void }, - { "", "PUSH_BTOS", -1, false, &def_string, &def_boolean, &def_void }, - - { "", "GOTO", -1, false, &def_jumpoffset, &def_void, &def_void }, - - { "&&", "AND", 7, false, &def_float, &def_float, &def_float }, - { "&&", "AND_BOOLF", 7, false, &def_boolean, &def_float, &def_float }, - { "&&", "AND_FBOOL", 7, false, &def_float, &def_boolean, &def_float }, - { "&&", "AND_BOOLBOOL", 7, false, &def_boolean, &def_boolean, &def_float }, - { "||", "OR", 7, false, &def_float, &def_float, &def_float }, - { "||", "OR_BOOLF", 7, false, &def_boolean, &def_float, &def_float }, - { "||", "OR_FBOOL", 7, false, &def_float, &def_boolean, &def_float }, - { "||", "OR_BOOLBOOL", 7, false, &def_boolean, &def_boolean, &def_float }, - - { "&", "BITAND", 3, false, &def_float, &def_float, &def_float }, - { "|", "BITOR", 3, false, &def_float, &def_float, &def_float }, - - { "", "BREAK", -1, false, &def_float, &def_void, &def_void }, - { "", "CONTINUE", -1, false, &def_float, &def_void, &def_void }, - - { NULL } -}; - -/* -================ -idCompiler::idCompiler() -================ -*/ -idCompiler::idCompiler() { - const char **ptr; - int id; - - // make sure we have the right # of opcodes in the table - assert( ( sizeof( opcodes ) / sizeof( opcodes[ 0 ] ) ) == ( NUM_OPCODES + 1 ) ); - - eof = true; - parserPtr = &parser; - - callthread = false; - loopDepth = 0; - eof = false; - braceDepth = 0; - immediateType = NULL; - basetype = NULL; - currentLineNumber = 0; - currentFileNumber = 0; - errorCount = 0; - console = false; - scope = &def_namespace; - - memset( &immediate, 0, sizeof( immediate ) ); - memset( punctuationValid, 0, sizeof( punctuationValid ) ); - for( ptr = punctuation; *ptr != NULL; ptr++ ) { - id = parserPtr->GetPunctuationId( *ptr ); - if ( ( id >= 0 ) && ( id < 256 ) ) { - punctuationValid[ id ] = true; - } - } -} - -/* -============ -idCompiler::Error - -Aborts the current file load -============ -*/ -void idCompiler::Error( const char *message, ... ) const { - va_list argptr; - char string[ 1024 ]; - - va_start( argptr, message ); - vsprintf( string, message, argptr ); - va_end( argptr ); - - throw idCompileError( string ); -} - -/* -============ -idCompiler::Warning - -Prints a warning about the current line -============ -*/ -void idCompiler::Warning( const char *message, ... ) const { - va_list argptr; - char string[ 1024 ]; - - va_start( argptr, message ); - vsprintf( string, message, argptr ); - va_end( argptr ); - - parserPtr->Warning( "%s", string ); -} - -/* -============ -idCompiler::VirtualFunctionConstant - -Creates a def for an index into a virtual function table -============ -*/ -ID_INLINE idVarDef *idCompiler::VirtualFunctionConstant( idVarDef *func ) { - eval_t eval; - - memset( &eval, 0, sizeof( eval ) ); - eval._int = func->scope->TypeDef()->GetFunctionNumber( func->value.functionPtr ); - if ( eval._int < 0 ) { - Error( "Function '%s' not found in scope '%s'", func->Name(), func->scope->Name() ); - } - - return GetImmediate( &type_virtualfunction, &eval, "" ); -} - -/* -============ -idCompiler::SizeConstant - -Creates a def for a size constant -============ -*/ -ID_INLINE idVarDef *idCompiler::SizeConstant( int size ) { - eval_t eval; - - memset( &eval, 0, sizeof( eval ) ); - eval._int = size; - return GetImmediate( &type_argsize, &eval, "" ); -} - -/* -============ -idCompiler::JumpConstant - -Creates a def for a jump constant -============ -*/ -ID_INLINE idVarDef *idCompiler::JumpConstant( int value ) { - eval_t eval; - - memset( &eval, 0, sizeof( eval ) ); - eval._int = value; - return GetImmediate( &type_jumpoffset, &eval, "" ); -} - -/* -============ -idCompiler::JumpDef - -Creates a def for a relative jump from one code location to another -============ -*/ -ID_INLINE idVarDef *idCompiler::JumpDef( int jumpfrom, int jumpto ) { - return JumpConstant( jumpto - jumpfrom ); -} - -/* -============ -idCompiler::JumpTo - -Creates a def for a relative jump from current code location -============ -*/ -ID_INLINE idVarDef *idCompiler::JumpTo( int jumpto ) { - return JumpDef( gameLocal.program.NumStatements(), jumpto ); -} - -/* -============ -idCompiler::JumpFrom - -Creates a def for a relative jump from code location to current code location -============ -*/ -ID_INLINE idVarDef *idCompiler::JumpFrom( int jumpfrom ) { - return JumpDef( jumpfrom, gameLocal.program.NumStatements() ); -} - -/* -============ -idCompiler::Divide -============ -*/ -ID_INLINE float idCompiler::Divide( float numerator, float denominator ) { - if ( denominator == 0 ) { - Error( "Divide by zero" ); - return 0; - } - - return numerator / denominator; -} - -/* -============ -idCompiler::FindImmediate - -tries to find an existing immediate with the same value -============ -*/ -idVarDef *idCompiler::FindImmediate( const idTypeDef *type, const eval_t *eval, const char *string ) const { - idVarDef *def; - etype_t etype; - - etype = type->Type(); - - // check for a constant with the same value - for( def = gameLocal.program.GetDefList( "" ); def != NULL; def = def->Next() ) { - if ( def->TypeDef() != type ) { - continue; - } - - switch( etype ) { - case ev_field : - if ( *def->value.intPtr == eval->_int ) { - return def; - } - break; - - case ev_argsize : - if ( def->value.argSize == eval->_int ) { - return def; - } - break; - - case ev_jumpoffset : - if ( def->value.jumpOffset == eval->_int ) { - return def; - } - break; - - case ev_entity : - if ( *def->value.intPtr == eval->entity ) { - return def; - } - break; - - case ev_string : - if ( idStr::Cmp( def->value.stringPtr, string ) == 0 ) { - return def; - } - break; - - case ev_float : - if ( *def->value.floatPtr == eval->_float ) { - return def; - } - break; - - case ev_virtualfunction : - if ( def->value.virtualFunction == eval->_int ) { - return def; - } - break; - - - case ev_vector : - if ( ( def->value.vectorPtr->x == eval->vector[ 0 ] ) && - ( def->value.vectorPtr->y == eval->vector[ 1 ] ) && - ( def->value.vectorPtr->z == eval->vector[ 2 ] ) ) { - return def; - } - break; - - default : - Error( "weird immediate type" ); - break; - } - } - - return NULL; -} - -/* -============ -idCompiler::GetImmediate - -returns an existing immediate with the same value, or allocates a new one -============ -*/ -idVarDef *idCompiler::GetImmediate( idTypeDef *type, const eval_t *eval, const char *string ) { - idVarDef *def; - - def = FindImmediate( type, eval, string ); - if ( def ) { - def->numUsers++; - } else { - // allocate a new def - def = gameLocal.program.AllocDef( type, "", &def_namespace, true ); - if ( type->Type() == ev_string ) { - def->SetString( string, true ); - } else { - def->SetValue( *eval, true ); - } - } - - return def; -} - -/* -============ -idCompiler::OptimizeOpcode - -try to optimize when the operator works on constants only -============ -*/ -idVarDef *idCompiler::OptimizeOpcode( const opcode_t *op, idVarDef *var_a, idVarDef *var_b ) { - eval_t c; - idTypeDef *type; - - if ( var_a && var_a->initialized != idVarDef::initializedConstant ) { - return NULL; - } - if ( var_b && var_b->initialized != idVarDef::initializedConstant ) { - return NULL; - } - - idVec3 &vec_c = *reinterpret_cast( &c.vector[ 0 ] ); - - memset( &c, 0, sizeof( c ) ); - switch( op - opcodes ) { - case OP_ADD_F: c._float = *var_a->value.floatPtr + *var_b->value.floatPtr; type = &type_float; break; - case OP_ADD_V: vec_c = *var_a->value.vectorPtr + *var_b->value.vectorPtr; type = &type_vector; break; - case OP_SUB_F: c._float = *var_a->value.floatPtr - *var_b->value.floatPtr; type = &type_float; break; - case OP_SUB_V: vec_c = *var_a->value.vectorPtr - *var_b->value.vectorPtr; type = &type_vector; break; - case OP_MUL_F: c._float = *var_a->value.floatPtr * *var_b->value.floatPtr; type = &type_float; break; - case OP_MUL_V: c._float = *var_a->value.vectorPtr * *var_b->value.vectorPtr; type = &type_float; break; - case OP_MUL_FV: vec_c = *var_b->value.vectorPtr * *var_a->value.floatPtr; type = &type_vector; break; - case OP_MUL_VF: vec_c = *var_a->value.vectorPtr * *var_b->value.floatPtr; type = &type_vector; break; - case OP_DIV_F: c._float = Divide( *var_a->value.floatPtr, *var_b->value.floatPtr ); type = &type_float; break; - case OP_MOD_F: c._float = (int)*var_a->value.floatPtr % (int)*var_b->value.floatPtr; type = &type_float; break; - case OP_BITAND: c._float = ( int )*var_a->value.floatPtr & ( int )*var_b->value.floatPtr; type = &type_float; break; - case OP_BITOR: c._float = ( int )*var_a->value.floatPtr | ( int )*var_b->value.floatPtr; type = &type_float; break; - case OP_GE: c._float = *var_a->value.floatPtr >= *var_b->value.floatPtr; type = &type_float; break; - case OP_LE: c._float = *var_a->value.floatPtr <= *var_b->value.floatPtr; type = &type_float; break; - case OP_GT: c._float = *var_a->value.floatPtr > *var_b->value.floatPtr; type = &type_float; break; - case OP_LT: c._float = *var_a->value.floatPtr < *var_b->value.floatPtr; type = &type_float; break; - case OP_AND: c._float = *var_a->value.floatPtr && *var_b->value.floatPtr; type = &type_float; break; - case OP_OR: c._float = *var_a->value.floatPtr || *var_b->value.floatPtr; type = &type_float; break; - case OP_NOT_BOOL: c._int = !*var_a->value.intPtr; type = &type_boolean; break; - case OP_NOT_F: c._float = !*var_a->value.floatPtr; type = &type_float; break; - case OP_NOT_V: c._float = !var_a->value.vectorPtr->x && !var_a->value.vectorPtr->y && !var_a->value.vectorPtr->z; type = &type_float; break; - case OP_NEG_F: c._float = -*var_a->value.floatPtr; type = &type_float; break; - case OP_NEG_V: vec_c = -*var_a->value.vectorPtr; type = &type_vector; break; - case OP_INT_F: c._float = ( int )*var_a->value.floatPtr; type = &type_float; break; - case OP_EQ_F: c._float = ( *var_a->value.floatPtr == *var_b->value.floatPtr ); type = &type_float; break; - case OP_EQ_V: c._float = var_a->value.vectorPtr->Compare( *var_b->value.vectorPtr ); type = &type_float; break; - case OP_EQ_E: c._float = ( *var_a->value.intPtr == *var_b->value.intPtr ); type = &type_float; break; - case OP_NE_F: c._float = ( *var_a->value.floatPtr != *var_b->value.floatPtr ); type = &type_float; break; - case OP_NE_V: c._float = !var_a->value.vectorPtr->Compare( *var_b->value.vectorPtr ); type = &type_float; break; - case OP_NE_E: c._float = ( *var_a->value.intPtr != *var_b->value.intPtr ); type = &type_float; break; - case OP_UADD_F: c._float = *var_b->value.floatPtr + *var_a->value.floatPtr; type = &type_float; break; - case OP_USUB_F: c._float = *var_b->value.floatPtr - *var_a->value.floatPtr; type = &type_float; break; - case OP_UMUL_F: c._float = *var_b->value.floatPtr * *var_a->value.floatPtr; type = &type_float; break; - case OP_UDIV_F: c._float = Divide( *var_b->value.floatPtr, *var_a->value.floatPtr ); type = &type_float; break; - case OP_UMOD_F: c._float = ( int ) *var_b->value.floatPtr % ( int )*var_a->value.floatPtr; type = &type_float; break; - case OP_UOR_F: c._float = ( int )*var_b->value.floatPtr | ( int )*var_a->value.floatPtr; type = &type_float; break; - case OP_UAND_F: c._float = ( int )*var_b->value.floatPtr & ( int )*var_a->value.floatPtr; type = &type_float; break; - case OP_UINC_F: c._float = *var_a->value.floatPtr + 1; type = &type_float; break; - case OP_UDEC_F: c._float = *var_a->value.floatPtr - 1; type = &type_float; break; - case OP_COMP_F: c._float = ( float )~( int )*var_a->value.floatPtr; type = &type_float; break; - default: type = NULL; break; - } - - if ( !type ) { - return NULL; - } - - if ( var_a ) { - var_a->numUsers--; - if ( var_a->numUsers <= 0 ) { - gameLocal.program.FreeDef( var_a, NULL ); - } - } - if ( var_b ) { - var_b->numUsers--; - if ( var_b->numUsers <= 0 ) { - gameLocal.program.FreeDef( var_b, NULL ); - } - } - - return GetImmediate( type, &c, "" ); -} - -/* -============ -idCompiler::EmitOpcode - -Emits a primitive statement, returning the var it places it's value in -============ -*/ -idVarDef *idCompiler::EmitOpcode( const opcode_t *op, idVarDef *var_a, idVarDef *var_b ) { - statement_t *statement; - idVarDef *var_c; - - var_c = OptimizeOpcode( op, var_a, var_b ); - if ( var_c ) { - return var_c; - } - - if ( var_a && !strcmp( var_a->Name(), RESULT_STRING ) ) { - var_a->numUsers++; - } - if ( var_b && !strcmp( var_b->Name(), RESULT_STRING ) ) { - var_b->numUsers++; - } - - statement = gameLocal.program.AllocStatement(); - statement->linenumber = currentLineNumber; - statement->file = currentFileNumber; - - if ( ( op->type_c == &def_void ) || op->rightAssociative ) { - // ifs, gotos, and assignments don't need vars allocated - var_c = NULL; - } else { - // allocate result space - // try to reuse result defs as much as possible - var_c = gameLocal.program.FindFreeResultDef( op->type_c->TypeDef(), RESULT_STRING, scope, var_a, var_b ); - // set user count back to 1, a result def needs to be used twice before it can be reused - var_c->numUsers = 1; - } - - statement->op = op - opcodes; - statement->a = var_a; - statement->b = var_b; - statement->c = var_c; - - if ( op->rightAssociative ) { - return var_a; - } - - return var_c; -} - -/* -============ -idCompiler::EmitOpcode - -Emits a primitive statement, returning the var it places it's value in -============ -*/ -ID_INLINE idVarDef *idCompiler::EmitOpcode( int op, idVarDef *var_a, idVarDef *var_b ) { - return EmitOpcode( &opcodes[ op ], var_a, var_b ); -} - -/* -============ -idCompiler::EmitPush - -Emits an opcode to push the variable onto the stack. -============ -*/ -bool idCompiler::EmitPush( idVarDef *expression, const idTypeDef *funcArg ) { - const opcode_t *op; - const opcode_t *out; - - out = NULL; - for( op = &opcodes[ OP_PUSH_F ]; op->name && !strcmp( op->name, "" ); op++ ) { - if ( ( funcArg->Type() == op->type_a->Type() ) && ( expression->Type() == op->type_b->Type() ) ) { - out = op; - break; - } - } - - if ( !out ) { - if ( ( expression->TypeDef() != funcArg ) && !expression->TypeDef()->Inherits( funcArg ) ) { - return false; - } - - out = &opcodes[ OP_PUSH_ENT ]; - } - - EmitOpcode( out, expression, 0 ); - - return true; -} - -/* -============== -idCompiler::NextToken - -Sets token, immediateType, and possibly immediate -============== -*/ -void idCompiler::NextToken( void ) { - int i; - - // reset our type - immediateType = NULL; - memset( &immediate, 0, sizeof( immediate ) ); - - // Save the token's line number and filename since when we emit opcodes the current - // token is always the next one to be read - currentLineNumber = token.line; - currentFileNumber = gameLocal.program.GetFilenum( parserPtr->GetFileName() ); - - if ( !parserPtr->ReadToken( &token ) ) { - eof = true; - return; - } - - if ( currentFileNumber != gameLocal.program.GetFilenum( parserPtr->GetFileName() ) ) { - if ( ( braceDepth > 0 ) && ( token != "}" ) ) { - // missing a closing brace. try to give as much info as possible. - if ( scope->Type() == ev_function ) { - Error( "Unexpected end of file inside function '%s'. Missing closing braces.", scope->Name() ); - } else if ( scope->Type() == ev_object ) { - Error( "Unexpected end of file inside object '%s'. Missing closing braces.", scope->Name() ); - } else if ( scope->Type() == ev_namespace ) { - Error( "Unexpected end of file inside namespace '%s'. Missing closing braces.", scope->Name() ); - } else { - Error( "Unexpected end of file inside braced section" ); - } - } - } - - switch( token.type ) { - case TT_STRING: - // handle quoted strings as a unit - immediateType = &type_string; - return; - - case TT_LITERAL: { - // handle quoted vectors as a unit - immediateType = &type_vector; - idLexer lex( token, token.Length(), parserPtr->GetFileName(), LEXFL_NOERRORS ); - idToken token2; - for( i = 0; i < 3; i++ ) { - if ( !lex.ReadToken( &token2 ) ) { - Error( "Couldn't read vector. '%s' is not in the form of 'x y z'", token.c_str() ); - } - if ( token2.type == TT_PUNCTUATION && token2 == "-" ) { - if ( !lex.CheckTokenType( TT_NUMBER, 0, &token2 ) ) { - Error( "expected a number following '-' but found '%s' in vector '%s'", token2.c_str(), token.c_str() ); - } - immediate.vector[ i ] = -token2.GetFloatValue(); - } else if ( token2.type == TT_NUMBER ) { - immediate.vector[ i ] = token2.GetFloatValue(); - } else { - Error( "vector '%s' is not in the form of 'x y z'. expected float value, found '%s'", token.c_str(), token2.c_str() ); - } - } - return; - } - - case TT_NUMBER: - immediateType = &type_float; - immediate._float = token.GetFloatValue(); - return; - - case TT_PUNCTUATION: - // entity names - if ( token == "$" ) { - immediateType = &type_entity; - parserPtr->ReadToken( &token ); - return; - } - - if ( token == "{" ) { - braceDepth++; - return; - } - - if ( token == "}" ) { - braceDepth--; - return; - } - - if ( punctuationValid[ token.subtype ] ) { - return; - } - - Error( "Unknown punctuation '%s'", token.c_str() ); - break; - - case TT_NAME: - return; - - default: - Error( "Unknown token '%s'", token.c_str() ); - } -} - -/* -============= -idCompiler::ExpectToken - -Issues an Error if the current token isn't equal to string -Gets the next token -============= -*/ -void idCompiler::ExpectToken( const char *string ) { - if ( token != string ) { - Error( "expected '%s', found '%s'", string, token.c_str() ); - } - - NextToken(); -} - -/* -============= -idCompiler::CheckToken - -Returns true and gets the next token if the current token equals string -Returns false and does nothing otherwise -============= -*/ -bool idCompiler::CheckToken( const char *string ) { - if ( token != string ) { - return false; - } - - NextToken(); - - return true; -} - -/* -============ -idCompiler::ParseName - -Checks to see if the current token is a valid name -============ -*/ -void idCompiler::ParseName( idStr &name ) { - if ( token.type != TT_NAME ) { - Error( "'%s' is not a name", token.c_str() ); - } - - name = token; - NextToken(); -} - -/* -============ -idCompiler::SkipOutOfFunction - -For error recovery, pops out of nested braces -============ -*/ -void idCompiler::SkipOutOfFunction( void ) { - while( braceDepth ) { - parserPtr->SkipBracedSection( false ); - braceDepth--; - } - NextToken(); -} - -/* -============ -idCompiler::SkipToSemicolon - -For error recovery -============ -*/ -void idCompiler::SkipToSemicolon( void ) { - do { - if ( CheckToken( ";" ) ) { - return; - } - - NextToken(); - } while( !eof ); -} - -/* -============ -idCompiler::CheckType - -Parses a variable type, including functions types -============ -*/ -idTypeDef *idCompiler::CheckType( void ) { - idTypeDef *type; - - if ( token == "float" ) { - type = &type_float; - } else if ( token == "vector" ) { - type = &type_vector; - } else if ( token == "entity" ) { - type = &type_entity; - } else if ( token == "string" ) { - type = &type_string; - } else if ( token == "void" ) { - type = &type_void; - } else if ( token == "object" ) { - type = &type_object; - } else if ( token == "boolean" ) { - type = &type_boolean; - } else if ( token == "namespace" ) { - type = &type_namespace; - } else if ( token == "scriptEvent" ) { - type = &type_scriptevent; - } else { - type = gameLocal.program.FindType( token.c_str() ); - if ( type && !type->Inherits( &type_object ) ) { - type = NULL; - } - } - - return type; -} - -/* -============ -idCompiler::ParseType - -Parses a variable type, including functions types -============ -*/ -idTypeDef *idCompiler::ParseType( void ) { - idTypeDef *type; - - type = CheckType(); - if ( !type ) { - Error( "\"%s\" is not a type", token.c_str() ); - } - - if ( ( type == &type_scriptevent ) && ( scope != &def_namespace ) ) { - Error( "scriptEvents can only defined in the global namespace" ); - } - - if ( ( type == &type_namespace ) && ( scope->Type() != ev_namespace ) ) { - Error( "A namespace may only be defined globally, or within another namespace" ); - } - - NextToken(); - - return type; -} - -/* -============ -idCompiler::ParseImmediate - -Looks for a preexisting constant -============ -*/ -idVarDef *idCompiler::ParseImmediate( void ) { - idVarDef *def; - - def = GetImmediate( immediateType, &immediate, token.c_str() ); - NextToken(); - - return def; -} - -/* -============ -idCompiler::EmitFunctionParms -============ -*/ -idVarDef *idCompiler::EmitFunctionParms( int op, idVarDef *func, int startarg, int startsize, idVarDef *object ) { - idVarDef *e; - const idTypeDef *type; - const idTypeDef *funcArg; - idVarDef *returnDef; - idTypeDef *returnType; - int arg; - int size; - int resultOp; - - type = func->TypeDef(); - if ( func->Type() != ev_function ) { - Error( "'%s' is not a function", func->Name() ); - } - - // copy the parameters to the global parameter variables - arg = startarg; - size = startsize; - if ( !CheckToken( ")" ) ) { - do { - if ( arg >= type->NumParameters() ) { - Error( "too many parameters" ); - } - - e = GetExpression( TOP_PRIORITY ); - - funcArg = type->GetParmType( arg ); - if ( !EmitPush( e, funcArg ) ) { - Error( "type mismatch on parm %i of call to '%s'", arg + 1, func->Name() ); - } - - if ( funcArg->Type() == ev_object ) { - size += type_object.Size(); - } else { - size += funcArg->Size(); - } - - arg++; - } while( CheckToken( "," ) ); - - ExpectToken( ")" ); - } - - if ( arg < type->NumParameters() ) { - Error( "too few parameters for function '%s'", func->Name() ); - } - - if ( op == OP_CALL ) { - EmitOpcode( op, func, 0 ); - } else if ( ( op == OP_OBJECTCALL ) || ( op == OP_OBJTHREAD ) ) { - EmitOpcode( op, object, VirtualFunctionConstant( func ) ); - - // need arg size seperate since script object may be NULL - statement_t &statement = gameLocal.program.GetStatement( gameLocal.program.NumStatements() - 1 ); - statement.c = SizeConstant( func->value.functionPtr->parmTotal ); - // DG: before changes I did to ParseFunctionDef(), func->value.functionPtr->parmTotal was 0 - // if the function declaration/prototype has been parsed already, but the - // definition/implementation hadn't been parsed yet. That was wrong and sometimes - // (with debug game DLLs) lead to assertions in custom scripts, because the - // stack space reserved for function parameters was wrong. - // Now func->value.functionPtr->parmTotal is calculated when parsing the prototype, - // but func->value.functionPtr->parmSize[i] is still only calculated when parsing - // the implementation (as it's not needed before and so we can tell the cases apart here). - // However, savegames from before the change have script checksums - // (by idProgram::CalculateChecksum()) from statements with the wrong size, so - // loading them would fail as the checksum doesn't match. - // Setting this flag allows using the parmTotal argSize 0 when calculating the checksum - // so it matches the one from old savegames (unless something else has also changed in - // the script state so they really are incompatible). That's only done when actually - // loading old savegames (detected via BUILD_NUMBER/savegame.GetBuildNumber()) - if ( op == OP_OBJECTCALL && func->value.functionPtr->parmTotal > 0 - && func->value.functionPtr->parmSize.Num() == 0 ) { - statement.flags = statement_t::FLAG_OBJECTCALL_IMPL_NOT_PARSED_YET; - } - } else { - EmitOpcode( op, func, SizeConstant( size ) ); - } - - // we need to copy off the result into a temporary result location, so figure out the opcode - returnType = type->ReturnType(); - if ( returnType->Type() == ev_string ) { - resultOp = OP_STORE_S; - returnDef = gameLocal.program.returnStringDef; - } else { - gameLocal.program.returnDef->SetTypeDef( returnType ); - returnDef = gameLocal.program.returnDef; - - switch( returnType->Type() ) { - case ev_void : - resultOp = OP_STORE_F; - break; - - case ev_boolean : - resultOp = OP_STORE_BOOL; - break; - - case ev_float : - resultOp = OP_STORE_F; - break; - - case ev_vector : - resultOp = OP_STORE_V; - break; - - case ev_entity : - resultOp = OP_STORE_ENT; - break; - - case ev_object : - resultOp = OP_STORE_OBJ; - break; - - default : - Error( "Invalid return type for function '%s'", func->Name() ); - // shut up compiler - resultOp = OP_STORE_OBJ; - break; - } - } - - if ( returnType->Type() == ev_void ) { - // don't need result space since there's no result, so just return the normal result def. - return returnDef; - } - - // allocate result space - // try to reuse result defs as much as possible - statement_t &statement = gameLocal.program.GetStatement( gameLocal.program.NumStatements() - 1 ); - idVarDef *resultDef = gameLocal.program.FindFreeResultDef( returnType, RESULT_STRING, scope, statement.a, statement.b ); - // set user count back to 0, a result def needs to be used twice before it can be reused - resultDef->numUsers = 0; - - EmitOpcode( resultOp, returnDef, resultDef ); - - return resultDef; -} - -/* -============ -idCompiler::ParseFunctionCall -============ -*/ -idVarDef *idCompiler::ParseFunctionCall( idVarDef *funcDef ) { - assert( funcDef ); - - if ( funcDef->Type() != ev_function ) { - Error( "'%s' is not a function", funcDef->Name() ); - } - - if ( funcDef->initialized == idVarDef::uninitialized ) { - Error( "Function '%s' has not been defined yet", funcDef->GlobalName() ); - } - - assert( funcDef->value.functionPtr ); - if ( callthread ) { - if ( ( funcDef->initialized != idVarDef::uninitialized ) && funcDef->value.functionPtr->eventdef ) { - Error( "Built-in functions cannot be called as threads" ); - } - callthread = false; - return EmitFunctionParms( OP_THREAD, funcDef, 0, 0, NULL ); - } else { - if ( ( funcDef->initialized != idVarDef::uninitialized ) && funcDef->value.functionPtr->eventdef ) { - if ( ( scope->Type() != ev_namespace ) && ( scope->scope->Type() == ev_object ) ) { - // get the local object pointer - idVarDef *thisdef = gameLocal.program.GetDef( scope->scope->TypeDef(), "self", scope ); - if ( !thisdef ) { - Error( "No 'self' within scope" ); - } - - return ParseEventCall( thisdef, funcDef ); - } else { - Error( "Built-in functions cannot be called without an object" ); - } - } - - return EmitFunctionParms( OP_CALL, funcDef, 0, 0, NULL ); - } -} - -/* -============ -idCompiler::ParseObjectCall -============ -*/ -idVarDef *idCompiler::ParseObjectCall( idVarDef *object, idVarDef *func ) { - EmitPush( object, object->TypeDef() ); - if ( callthread ) { - callthread = false; - return EmitFunctionParms( OP_OBJTHREAD, func, 1, type_object.Size(), object ); - } else { - return EmitFunctionParms( OP_OBJECTCALL, func, 1, 0, object ); - } -} - -/* -============ -idCompiler::ParseEventCall -============ -*/ -idVarDef *idCompiler::ParseEventCall( idVarDef *object, idVarDef *funcDef ) { - if ( callthread ) { - Error( "Cannot call built-in functions as a thread" ); - } - - if ( funcDef->Type() != ev_function ) { - Error( "'%s' is not a function", funcDef->Name() ); - } - - if ( !funcDef->value.functionPtr->eventdef ) { - Error( "\"%s\" cannot be called with object notation", funcDef->Name() ); - } - - if ( object->Type() == ev_object ) { - EmitPush( object, &type_entity ); - } else { - EmitPush( object, object->TypeDef() ); - } - - return EmitFunctionParms( OP_EVENTCALL, funcDef, 0, type_object.Size(), NULL ); -} - -/* -============ -idCompiler::ParseSysObjectCall -============ -*/ -idVarDef *idCompiler::ParseSysObjectCall( idVarDef *funcDef ) { - if ( callthread ) { - Error( "Cannot call built-in functions as a thread" ); - } - - if ( funcDef->Type() != ev_function ) { - Error( "'%s' is not a function", funcDef->Name() ); - } - - if ( !funcDef->value.functionPtr->eventdef ) { - Error( "\"%s\" cannot be called with object notation", funcDef->Name() ); - } - - if ( !idThread::Type.RespondsTo( *funcDef->value.functionPtr->eventdef ) ) { - Error( "\"%s\" is not callable as a 'sys' function", funcDef->Name() ); - } - - return EmitFunctionParms( OP_SYSCALL, funcDef, 0, 0, NULL ); -} - -/* -============ -idCompiler::LookupDef -============ -*/ -idVarDef *idCompiler::LookupDef( const char *name, const idVarDef *baseobj ) { - idVarDef *def; - idVarDef *field; - etype_t type_b; - etype_t type_c; - const opcode_t *op; - - // check if we're accessing a field - if ( baseobj && ( baseobj->Type() == ev_object ) ) { - const idVarDef *tdef; - - def = NULL; - for( tdef = baseobj; tdef != &def_object; tdef = tdef->TypeDef()->SuperClass()->def ) { - def = gameLocal.program.GetDef( NULL, name, tdef ); - if ( def ) { - break; - } - } - } else { - // first look through the defs in our scope - def = gameLocal.program.GetDef( NULL, name, scope ); - if ( !def ) { - // if we're in a member function, check types local to the object - if ( ( scope->Type() != ev_namespace ) && ( scope->scope->Type() == ev_object ) ) { - // get the local object pointer - idVarDef *thisdef = gameLocal.program.GetDef( scope->scope->TypeDef(), "self", scope ); - - field = LookupDef( name, scope->scope->TypeDef()->def ); - if ( !field ) { - Error( "Unknown value \"%s\"", name ); - } - - // type check - type_b = field->Type(); - if ( field->Type() == ev_function ) { - type_c = field->TypeDef()->ReturnType()->Type(); - } else { - type_c = field->TypeDef()->FieldType()->Type(); // field access gets type from field - if ( CheckToken( "++" ) ) { - if ( type_c != ev_float ) { - Error( "Invalid type for ++" ); - } - def = EmitOpcode( OP_UINCP_F, thisdef, field ); - return def; - } else if ( CheckToken( "--" ) ) { - if ( type_c != ev_float ) { - Error( "Invalid type for --" ); - } - def = EmitOpcode( OP_UDECP_F, thisdef, field ); - return def; - } - } - - op = &opcodes[ OP_INDIRECT_F ]; - while( ( op->type_a->Type() != ev_object ) - || ( type_b != op->type_b->Type() ) || ( type_c != op->type_c->Type() ) ) { - if ( ( op->priority == FUNCTION_PRIORITY ) && ( op->type_a->Type() == ev_object ) && ( op->type_c->Type() == ev_void ) && - ( type_c != op->type_c->Type() ) ) { - // catches object calls that return a value - break; - } - op++; - if ( !op->name || strcmp( op->name, "." ) ) { - Error( "no valid opcode to access type '%s'", field->TypeDef()->SuperClass()->Name() ); - } - } - - if ( ( op - opcodes ) == OP_OBJECTCALL ) { - ExpectToken( "(" ); - def = ParseObjectCall( thisdef, field ); - } else { - // emit the conversion opcode - def = EmitOpcode( op, thisdef, field ); - - // field access gets type from field - def->SetTypeDef( field->TypeDef()->FieldType() ); - } - } - } - } - - return def; -} - -/* -============ -idCompiler::ParseValue - -Returns the def for the current token -============ -*/ -idVarDef *idCompiler::ParseValue( void ) { - idVarDef *def; - idVarDef *namespaceDef; - idStr name; - - if ( immediateType == &type_entity ) { - // if an immediate entity ($-prefaced name) then create or lookup a def for it. - // when entities are spawned, they'll lookup the def and point it to them. - def = gameLocal.program.GetDef( &type_entity, "$" + token, &def_namespace ); - if ( !def ) { - def = gameLocal.program.AllocDef( &type_entity, "$" + token, &def_namespace, true ); - } - NextToken(); - return def; - } else if ( immediateType ) { - // if the token is an immediate, allocate a constant for it - return ParseImmediate(); - } - - ParseName( name ); - def = LookupDef( name, basetype ); - if ( !def ) { - if ( basetype ) { - Error( "%s is not a member of %s", name.c_str(), basetype->TypeDef()->Name() ); - } else { - Error( "Unknown value \"%s\"", name.c_str() ); - } - // if namespace, then look up the variable in that namespace - } else if ( def->Type() == ev_namespace ) { - while( def->Type() == ev_namespace ) { - ExpectToken( "::" ); - ParseName( name ); - namespaceDef = def; - def = gameLocal.program.GetDef( NULL, name, namespaceDef ); - if ( !def ) { - Error( "Unknown value \"%s::%s\"", namespaceDef->GlobalName(), name.c_str() ); - } - } - //def = LookupDef( name, basetype ); - } - - return def; -} - -/* -============ -idCompiler::GetTerm -============ -*/ -idVarDef *idCompiler::GetTerm( void ) { - idVarDef *e; - int op; - - if ( !immediateType && CheckToken( "~" ) ) { - e = GetExpression( TILDE_PRIORITY ); - switch( e->Type() ) { - case ev_float : - op = OP_COMP_F; - break; - - default : - Error( "type mismatch for ~" ); - - // shut up compiler - op = OP_COMP_F; - break; - } - - return EmitOpcode( op, e, 0 ); - } - - if ( !immediateType && CheckToken( "!" ) ) { - e = GetExpression( NOT_PRIORITY ); - switch( e->Type() ) { - case ev_boolean : - op = OP_NOT_BOOL; - break; - - case ev_float : - op = OP_NOT_F; - break; - - case ev_string : - op = OP_NOT_S; - break; - - case ev_vector : - op = OP_NOT_V; - break; - - case ev_entity : - op = OP_NOT_ENT; - break; - - case ev_function : - Error( "Invalid type for !" ); - - // shut up compiler - op = OP_NOT_F; - break; - - case ev_object : - op = OP_NOT_ENT; - break; - - default : - Error( "type mismatch for !" ); - - // shut up compiler - op = OP_NOT_F; - break; - } - - return EmitOpcode( op, e, 0 ); - } - - // check for negation operator - if ( !immediateType && CheckToken( "-" ) ) { - // constants are directly negated without an instruction - if ( immediateType == &type_float ) { - immediate._float = -immediate._float; - return ParseImmediate(); - } else if ( immediateType == &type_vector ) { - immediate.vector[0] = -immediate.vector[0]; - immediate.vector[1] = -immediate.vector[1]; - immediate.vector[2] = -immediate.vector[2]; - return ParseImmediate(); - } else { - e = GetExpression( NOT_PRIORITY ); - switch( e->Type() ) { - case ev_float : - op = OP_NEG_F; - break; - - case ev_vector : - op = OP_NEG_V; - break; - default : - Error( "type mismatch for -" ); - - // shut up compiler - op = OP_NEG_F; - break; - } - return EmitOpcode( &opcodes[ op ], e, 0 ); - } - } - - if ( CheckToken( "int" ) ) { - ExpectToken( "(" ); - - e = GetExpression( INT_PRIORITY ); - if ( e->Type() != ev_float ) { - Error( "type mismatch for int()" ); - } - - ExpectToken( ")" ); - - return EmitOpcode( OP_INT_F, e, 0 ); - } - - if ( CheckToken( "thread" ) ) { - callthread = true; - e = GetExpression( FUNCTION_PRIORITY ); - - if ( callthread ) { - Error( "Invalid thread call" ); - } - - // threads return the thread number - gameLocal.program.returnDef->SetTypeDef( &type_float ); - return gameLocal.program.returnDef; - } - - if ( !immediateType && CheckToken( "(" ) ) { - e = GetExpression( TOP_PRIORITY ); - ExpectToken( ")" ); - - return e; - } - - return ParseValue(); -} - -/* -============== -idCompiler::TypeMatches -============== -*/ -bool idCompiler::TypeMatches( etype_t type1, etype_t type2 ) const { - if ( type1 == type2 ) { - return true; - } - - //if ( ( type1 == ev_entity ) && ( type2 == ev_object ) ) { - // return true; - //} - - //if ( ( type2 == ev_entity ) && ( type1 == ev_object ) ) { - // return true; - //} - - return false; -} - -/* -============== -idCompiler::GetExpression -============== -*/ -idVarDef *idCompiler::GetExpression( int priority ) { - const opcode_t *op; - const opcode_t *oldop; - idVarDef *e; - idVarDef *e2; - const idVarDef *oldtype; - etype_t type_a; - etype_t type_b; - etype_t type_c; - - if ( priority == 0 ) { - return GetTerm(); - } - - e = GetExpression( priority - 1 ); - if ( token == ";" ) { - // save us from searching through the opcodes unneccesarily - return e; - } - - while( 1 ) { - if ( ( priority == FUNCTION_PRIORITY ) && CheckToken( "(" ) ) { - return ParseFunctionCall( e ); - } - - // has to be a punctuation - if ( immediateType ) { - break; - } - - for( op = opcodes; op->name; op++ ) { - if ( ( op->priority == priority ) && CheckToken( op->name ) ) { - break; - } - } - - if ( !op->name ) { - // next token isn't at this priority level - break; - } - - // unary operators act only on the left operand - if ( op->type_b == &def_void ) { - e = EmitOpcode( op, e, 0 ); - return e; - } - - // preserve our base type - oldtype = basetype; - - // field access needs scope from object - if ( ( op->name[ 0 ] == '.' ) && e->TypeDef()->Inherits( &type_object ) ) { - // save off what type this field is part of - basetype = e->TypeDef()->def; - } - - if ( op->rightAssociative ) { - // if last statement is an indirect, change it to an address of - if ( gameLocal.program.NumStatements() > 0 ) { - statement_t &statement = gameLocal.program.GetStatement( gameLocal.program.NumStatements() - 1 ); - if ( ( statement.op >= OP_INDIRECT_F ) && ( statement.op < OP_ADDRESS ) ) { - statement.op = OP_ADDRESS; - type_pointer.SetPointerType( e->TypeDef() ); - e->SetTypeDef( &type_pointer ); - } - } - - e2 = GetExpression( priority ); - } else { - e2 = GetExpression( priority - 1 ); - } - - // restore type - basetype = oldtype; - - // type check - type_a = e->Type(); - type_b = e2->Type(); - - // field access gets type from field - if ( op->name[ 0 ] == '.' ) { - if ( ( e2->Type() == ev_function ) && e2->TypeDef()->ReturnType() ) { - type_c = e2->TypeDef()->ReturnType()->Type(); - } else if ( e2->TypeDef()->FieldType() ) { - type_c = e2->TypeDef()->FieldType()->Type(); - } else { - // not a field - type_c = ev_error; - } - } else { - type_c = ev_void; - } - - oldop = op; - while( !TypeMatches( type_a, op->type_a->Type() ) || !TypeMatches( type_b, op->type_b->Type() ) || - ( ( type_c != ev_void ) && !TypeMatches( type_c, op->type_c->Type() ) ) ) { - if ( ( op->priority == FUNCTION_PRIORITY ) && TypeMatches( type_a, op->type_a->Type() ) && TypeMatches( type_b, op->type_b->Type() ) ) { - break; - } - - op++; - if ( !op->name || strcmp( op->name, oldop->name ) ) { - Error( "type mismatch for '%s'", oldop->name ); - } - } - - switch( op - opcodes ) { - case OP_SYSCALL : - ExpectToken( "(" ); - e = ParseSysObjectCall( e2 ); - break; - - case OP_OBJECTCALL : - ExpectToken( "(" ); - if ( ( e2->initialized != idVarDef::uninitialized ) && e2->value.functionPtr->eventdef ) { - e = ParseEventCall( e, e2 ); - } else { - e = ParseObjectCall( e, e2 ); - } - break; - - case OP_EVENTCALL : - ExpectToken( "(" ); - if ( ( e2->initialized != idVarDef::uninitialized ) && e2->value.functionPtr->eventdef ) { - e = ParseEventCall( e, e2 ); - } else { - e = ParseObjectCall( e, e2 ); - } - break; - - default: - if ( callthread ) { - Error( "Expecting function call after 'thread'" ); - } - - if ( ( type_a == ev_pointer ) && ( type_b != e->TypeDef()->PointerType()->Type() ) ) { - // FIXME: need to make a general case for this - if ( ( op - opcodes == OP_STOREP_F ) && ( e->TypeDef()->PointerType()->Type() == ev_boolean ) ) { - // copy from float to boolean pointer - op = &opcodes[ OP_STOREP_FTOBOOL ]; - } else if ( ( op - opcodes == OP_STOREP_BOOL ) && ( e->TypeDef()->PointerType()->Type() == ev_float ) ) { - // copy from boolean to float pointer - op = &opcodes[ OP_STOREP_BOOLTOF ]; - } else if ( ( op - opcodes == OP_STOREP_F ) && ( e->TypeDef()->PointerType()->Type() == ev_string ) ) { - // copy from float to string pointer - op = &opcodes[ OP_STOREP_FTOS ]; - } else if ( ( op - opcodes == OP_STOREP_BOOL ) && ( e->TypeDef()->PointerType()->Type() == ev_string ) ) { - // copy from boolean to string pointer - op = &opcodes[ OP_STOREP_BTOS ]; - } else if ( ( op - opcodes == OP_STOREP_V ) && ( e->TypeDef()->PointerType()->Type() == ev_string ) ) { - // copy from vector to string pointer - op = &opcodes[ OP_STOREP_VTOS ]; - } else if ( ( op - opcodes == OP_STOREP_ENT ) && ( e->TypeDef()->PointerType()->Type() == ev_object ) ) { - // store an entity into an object pointer - op = &opcodes[ OP_STOREP_OBJENT ]; - } else { - Error( "type mismatch for '%s'", op->name ); - } - } - - if ( op->rightAssociative ) { - e = EmitOpcode( op, e2, e ); - } else { - e = EmitOpcode( op, e, e2 ); - } - - if ( op - opcodes == OP_STOREP_OBJENT ) { - // statement.b points to type_pointer, which is just a temporary that gets its type reassigned, so we store the real type in statement.c - // so that we can do a type check during run time since we don't know what type the script object is at compile time because it - // comes from an entity - statement_t &statement = gameLocal.program.GetStatement( gameLocal.program.NumStatements() - 1 ); - statement.c = type_pointer.PointerType()->def; - } - - // field access gets type from field - if ( type_c != ev_void ) { - e->SetTypeDef( e2->TypeDef()->FieldType() ); - } - break; - } - } - - return e; -} - -/* -================ -idCompiler::PatchLoop -================ -*/ -void idCompiler::PatchLoop( int start, int continuePos ) { - int i; - statement_t *pos; - - pos = &gameLocal.program.GetStatement( start ); - for( i = start; i < gameLocal.program.NumStatements(); i++, pos++ ) { - if ( pos->op == OP_BREAK ) { - pos->op = OP_GOTO; - pos->a = JumpFrom( i ); - } else if ( pos->op == OP_CONTINUE ) { - pos->op = OP_GOTO; - pos->a = JumpDef( i, continuePos ); - } - } -} - -/* -================ -idCompiler::ParseReturnStatement -================ -*/ -void idCompiler::ParseReturnStatement( void ) { - idVarDef *e; - etype_t type_a; - etype_t type_b; - const opcode_t *op; - - if ( CheckToken( ";" ) ) { - if ( scope->TypeDef()->ReturnType()->Type() != ev_void ) { - Error( "expecting return value" ); - } - - EmitOpcode( OP_RETURN, 0, 0 ); - return; - } - - e = GetExpression( TOP_PRIORITY ); - ExpectToken( ";" ); - - type_a = e->Type(); - type_b = scope->TypeDef()->ReturnType()->Type(); - - if ( TypeMatches( type_a, type_b ) ) { - EmitOpcode( OP_RETURN, e, 0 ); - return; - } - - for( op = opcodes; op->name; op++ ) { - if ( !strcmp( op->name, "=" ) ) { - break; - } - } - - assert( op->name ); - - while( !TypeMatches( type_a, op->type_a->Type() ) || !TypeMatches( type_b, op->type_b->Type() ) ) { - op++; - if ( !op->name || strcmp( op->name, "=" ) ) { - Error( "type mismatch for return value" ); - } - } - - idTypeDef *returnType = scope->TypeDef()->ReturnType(); - if ( returnType->Type() == ev_string ) { - EmitOpcode( op, e, gameLocal.program.returnStringDef ); - } else { - gameLocal.program.returnDef->SetTypeDef( returnType ); - EmitOpcode( op, e, gameLocal.program.returnDef ); - } - EmitOpcode( OP_RETURN, 0, 0 ); -} - -/* -================ -idCompiler::ParseWhileStatement -================ -*/ -void idCompiler::ParseWhileStatement( void ) { - idVarDef *e; - int patch1; - int patch2; - - loopDepth++; - - ExpectToken( "(" ); - - patch2 = gameLocal.program.NumStatements(); - e = GetExpression( TOP_PRIORITY ); - ExpectToken( ")" ); - - if ( ( e->initialized == idVarDef::initializedConstant ) && ( *e->value.intPtr != 0 ) ) { - //FIXME: we can completely skip generation of this code in the opposite case - ParseStatement(); - EmitOpcode( OP_GOTO, JumpTo( patch2 ), 0 ); - } else { - patch1 = gameLocal.program.NumStatements(); - EmitOpcode( OP_IFNOT, e, 0 ); - ParseStatement(); - EmitOpcode( OP_GOTO, JumpTo( patch2 ), 0 ); - gameLocal.program.GetStatement( patch1 ).b = JumpFrom( patch1 ); - } - - // fixup breaks and continues - PatchLoop( patch2, patch2 ); - - loopDepth--; -} - -/* -================ -idCompiler::ParseForStatement - -Form of for statement with a counter: - - a = 0; -start: << patch4 - if ( !( a < 10 ) ) { - goto end; << patch1 - } else { - goto process; << patch3 - } - -increment: << patch2 - a = a + 1; - goto start; << goto patch4 - -process: - statements; - goto increment; << goto patch2 - -end: - -Form of for statement without a counter: - - a = 0; -start: << patch2 - if ( !( a < 10 ) ) { - goto end; << patch1 - } - -process: - statements; - goto start; << goto patch2 - -end: -================ -*/ -void idCompiler::ParseForStatement( void ) { - idVarDef *e; - int start; - int patch1; - int patch2; - int patch3; - int patch4; - - loopDepth++; - - start = gameLocal.program.NumStatements(); - - ExpectToken( "(" ); - - // init - if ( !CheckToken( ";" ) ) { - do { - GetExpression( TOP_PRIORITY ); - } while( CheckToken( "," ) ); - - ExpectToken( ";" ); - } - - // condition - patch2 = gameLocal.program.NumStatements(); - - e = GetExpression( TOP_PRIORITY ); - ExpectToken( ";" ); - - //FIXME: add check for constant expression - patch1 = gameLocal.program.NumStatements(); - EmitOpcode( OP_IFNOT, e, 0 ); - - // counter - if ( !CheckToken( ")" ) ) { - patch3 = gameLocal.program.NumStatements(); - EmitOpcode( OP_IF, e, 0 ); - - patch4 = patch2; - patch2 = gameLocal.program.NumStatements(); - do { - GetExpression( TOP_PRIORITY ); - } while( CheckToken( "," ) ); - - ExpectToken( ")" ); - - // goto patch4 - EmitOpcode( OP_GOTO, JumpTo( patch4 ), 0 ); - - // fixup patch3 - gameLocal.program.GetStatement( patch3 ).b = JumpFrom( patch3 ); - } - - ParseStatement(); - - // goto patch2 - EmitOpcode( OP_GOTO, JumpTo( patch2 ), 0 ); - - // fixup patch1 - gameLocal.program.GetStatement( patch1 ).b = JumpFrom( patch1 ); - - // fixup breaks and continues - PatchLoop( start, patch2 ); - - loopDepth--; -} - -/* -================ -idCompiler::ParseDoWhileStatement -================ -*/ -void idCompiler::ParseDoWhileStatement( void ) { - idVarDef *e; - int patch1; - - loopDepth++; - - patch1 = gameLocal.program.NumStatements(); - ParseStatement(); - ExpectToken( "while" ); - ExpectToken( "(" ); - e = GetExpression( TOP_PRIORITY ); - ExpectToken( ")" ); - ExpectToken( ";" ); - - EmitOpcode( OP_IF, e, JumpTo( patch1 ) ); - - // fixup breaks and continues - PatchLoop( patch1, patch1 ); - - loopDepth--; -} - -/* -================ -idCompiler::ParseIfStatement -================ -*/ -void idCompiler::ParseIfStatement( void ) { - idVarDef *e; - int patch1; - int patch2; - - ExpectToken( "(" ); - e = GetExpression( TOP_PRIORITY ); - ExpectToken( ")" ); - - //FIXME: add check for constant expression - patch1 = gameLocal.program.NumStatements(); - EmitOpcode( OP_IFNOT, e, 0 ); - - ParseStatement(); - - if ( CheckToken( "else" ) ) { - patch2 = gameLocal.program.NumStatements(); - EmitOpcode( OP_GOTO, 0, 0 ); - gameLocal.program.GetStatement( patch1 ).b = JumpFrom( patch1 ); - ParseStatement(); - gameLocal.program.GetStatement( patch2 ).a = JumpFrom( patch2 ); - } else { - gameLocal.program.GetStatement( patch1 ).b = JumpFrom( patch1 ); - } -} - -/* -============ -idCompiler::ParseStatement -============ -*/ -void idCompiler::ParseStatement( void ) { - if ( CheckToken( ";" ) ) { - // skip semicolons, which are harmless and ok syntax - return; - } - - if ( CheckToken( "{" ) ) { - do { - ParseStatement(); - } while( !CheckToken( "}" ) ); - - return; - } - - if ( CheckToken( "return" ) ) { - ParseReturnStatement(); - return; - } - - if ( CheckToken( "while" ) ) { - ParseWhileStatement(); - return; - } - - if ( CheckToken( "for" ) ) { - ParseForStatement(); - return; - } - - if ( CheckToken( "do" ) ) { - ParseDoWhileStatement(); - return; - } - - if ( CheckToken( "break" ) ) { - ExpectToken( ";" ); - if ( !loopDepth ) { - Error( "cannot break outside of a loop" ); - } - EmitOpcode( OP_BREAK, 0, 0 ); - return; - } - - if ( CheckToken( "continue" ) ) { - ExpectToken( ";" ); - if ( !loopDepth ) { - Error( "cannot contine outside of a loop" ); - } - EmitOpcode( OP_CONTINUE, 0, 0 ); - return; - } - - if ( CheckType() != NULL ) { - ParseDefs(); - return; - } - - if ( CheckToken( "if" ) ) { - ParseIfStatement(); - return; - } - - GetExpression( TOP_PRIORITY ); - ExpectToken(";"); -} - -/* -================ -idCompiler::ParseObjectDef -================ -*/ -void idCompiler::ParseObjectDef( const char *objname ) { - idTypeDef *objtype; - idTypeDef *type; - idTypeDef *parentType; - idTypeDef *fieldtype; - idStr name; - const char *fieldname; - idTypeDef newtype( ev_field, NULL, "", 0, NULL ); - idVarDef *oldscope; - int i; - - oldscope = scope; - if ( scope->Type() != ev_namespace ) { - Error( "Objects cannot be defined within functions or other objects" ); - } - - // make sure it doesn't exist before we create it - if ( gameLocal.program.FindType( objname ) != NULL ) { - Error( "'%s' : redefinition; different basic types", objname ); - } - - // base type - if ( !CheckToken( ":" ) ) { - parentType = &type_object; - } else { - parentType = ParseType(); - if ( !parentType->Inherits( &type_object ) ) { - Error( "Objects may only inherit from objects." ); - } - } - - objtype = gameLocal.program.AllocType( ev_object, NULL, objname, parentType == &type_object ? 0 : parentType->Size(), parentType ); - objtype->def = gameLocal.program.AllocDef( objtype, objname, scope, true ); - scope = objtype->def; - - // inherit all the functions - for( i = 0; i < parentType->NumFunctions(); i++ ) { - const function_t *func = parentType->GetFunction( i ); - objtype->AddFunction( func ); - } - - ExpectToken( "{" ); - - do { - if ( CheckToken( ";" ) ) { - // skip semicolons, which are harmless and ok syntax - continue; - } - - fieldtype = ParseType(); - newtype.SetFieldType( fieldtype ); - - fieldname = va( "%s field", fieldtype->Name() ); - newtype.SetName( fieldname ); - - ParseName( name ); - - // check for a function prototype or declaraction - if ( CheckToken( "(" ) ) { - ParseFunctionDef( newtype.FieldType(), name ); - } else { - type = gameLocal.program.GetType( newtype, true ); - assert( !type->def ); - gameLocal.program.AllocDef( type, name, scope, true ); - objtype->AddField( type, name ); - ExpectToken( ";" ); - } - } while( !CheckToken( "}" ) ); - - scope = oldscope; - - ExpectToken( ";" ); -} - -/* -============ -idCompiler::ParseFunction - -parse a function type -============ -*/ -idTypeDef *idCompiler::ParseFunction( idTypeDef *returnType, const char *name ) { - idTypeDef newtype( ev_function, NULL, name, type_function.Size(), returnType ); - idTypeDef *type; - - if ( scope->Type() != ev_namespace ) { - // create self pointer - newtype.AddFunctionParm( scope->TypeDef(), "self" ); - } - - if ( !CheckToken( ")" ) ) { - idStr parmName; - do { - type = ParseType(); - ParseName( parmName ); - newtype.AddFunctionParm( type, parmName ); - } while( CheckToken( "," ) ); - - ExpectToken( ")" ); - } - - return gameLocal.program.GetType( newtype, true ); -} - -/* -================ -idCompiler::ParseFunctionDef -================ -*/ -void idCompiler::ParseFunctionDef( idTypeDef *returnType, const char *name ) { - idTypeDef *type; - idVarDef *def; - idVarDef *oldscope; - int i; - int numParms; - const idTypeDef *parmType; - function_t *func; - statement_t *pos; - - if ( ( scope->Type() != ev_namespace ) && !scope->TypeDef()->Inherits( &type_object ) ) { - Error( "Functions may not be defined within other functions" ); - } - - type = ParseFunction( returnType, name ); - def = gameLocal.program.GetDef( type, name, scope ); - if ( !def ) { - def = gameLocal.program.AllocDef( type, name, scope, true ); - type->def = def; - - func = &gameLocal.program.AllocFunction( def ); - if ( scope->TypeDef()->Inherits( &type_object ) ) { - scope->TypeDef()->AddFunction( func ); - } - } else { - func = def->value.functionPtr; - assert( func ); - if ( func->firstStatement ) { - Error( "%s redeclared", def->GlobalName() ); - } - } - - // DG: make sure parmTotal gets calculated when parsing prototype (not just when parsing - // implementation) so calling this function/method before the implementation has been parsed - // works without getting Assertions in IdInterpreter::Execute() and ::LeaveFunction() - // ("st->c->value.argSize == func->parmTotal", "localstackUsed == localstackBase", see #303 and #344) - - // calculate stack space used by parms - numParms = type->NumParameters(); - if ( !CheckToken( "{" ) ) { - // it's just a prototype, so get the ; and move on - ExpectToken( ";" ); - // DG: BUT only after calculating the stack space for the arguments because this - // function might be called before the implementation is parsed (see #303 and #344) - // which otherwise causes Assertions in IdInterpreter::Execute() and ::LeaveFunction() - // ("st->c->value.argSize == func->parmTotal", "localstackUsed == localstackBase") - func->parmTotal = 0; - for( i = 0; i < numParms; i++ ) { - parmType = type->GetParmType( i ); - int size = parmType->Inherits( &type_object ) ? type_object.Size() : parmType->Size(); - func->parmTotal += size; - // NOTE: Don't set func->parmSize[] yet, the workaround to keep compatibility - // with old savegames checks for func->parmSize.Num() == 0 - // (see EmitFunctionParms() for more explanation of that workaround) - // Also not defining the parms yet, otherwise they're defined in a different order - // than before, so their .num is different which breaks compat with old savegames - } - return; - } - - - int totalSize = 0; // DG: totalsize might already have been calculated for the prototype, see a few lines above - func->parmSize.SetNum( numParms ); - for( i = 0; i < numParms; i++ ) { - parmType = type->GetParmType( i ); - if ( parmType->Inherits( &type_object ) ) { - func->parmSize[ i ] = type_object.Size(); - } else { - func->parmSize[ i ] = parmType->Size(); - } - totalSize += func->parmSize[ i ]; - } - // DG: if parmTotal has been calculated before, it shouldn't have changed - assert((func->parmTotal == 0 || totalSize == func->parmTotal) && "function parameter sizes differ between protype vs implementation?!"); - func->parmTotal = totalSize; - - // define the parms - for( i = 0; i < numParms; i++ ) { - if ( gameLocal.program.GetDef( type->GetParmType( i ), type->GetParmName( i ), def ) ) { - Error( "'%s' defined more than once in function parameters", type->GetParmName( i ) ); - } - gameLocal.program.AllocDef( type->GetParmType( i ), type->GetParmName( i ), def, false ); - } - - oldscope = scope; - scope = def; - - func->firstStatement = gameLocal.program.NumStatements(); - - // check if we should call the super class constructor - if ( oldscope->TypeDef()->Inherits( &type_object ) && !idStr::Icmp( name, "init" ) ) { - idTypeDef *superClass; - function_t *constructorFunc = NULL; - - // find the superclass constructor - for( superClass = oldscope->TypeDef()->SuperClass(); superClass != &type_object; superClass = superClass->SuperClass() ) { - constructorFunc = gameLocal.program.FindFunction( va( "%s::init", superClass->Name() ) ); - if ( constructorFunc ) { - break; - } - } - - // emit the call to the constructor - if ( constructorFunc ) { - idVarDef *selfDef = gameLocal.program.GetDef( type->GetParmType( 0 ), type->GetParmName( 0 ), def ); - assert( selfDef ); - EmitPush( selfDef, selfDef->TypeDef() ); - EmitOpcode( &opcodes[ OP_CALL ], constructorFunc->def, 0 ); - } - } - - // parse regular statements - while( !CheckToken( "}" ) ) { - ParseStatement(); - } - - // check if we should call the super class destructor - if ( oldscope->TypeDef()->Inherits( &type_object ) && !idStr::Icmp( name, "destroy" ) ) { - idTypeDef *superClass; - function_t *destructorFunc = NULL; - - // find the superclass destructor - for( superClass = oldscope->TypeDef()->SuperClass(); superClass != &type_object; superClass = superClass->SuperClass() ) { - destructorFunc = gameLocal.program.FindFunction( va( "%s::destroy", superClass->Name() ) ); - if ( destructorFunc ) { - break; - } - } - - if ( destructorFunc ) { - if ( func->firstStatement < gameLocal.program.NumStatements() ) { - // change all returns to point to the call to the destructor - pos = &gameLocal.program.GetStatement( func->firstStatement ); - for( i = func->firstStatement; i < gameLocal.program.NumStatements(); i++, pos++ ) { - if ( pos->op == OP_RETURN ) { - pos->op = OP_GOTO; - pos->a = JumpDef( i, gameLocal.program.NumStatements() ); - } - } - } - - // emit the call to the destructor - idVarDef *selfDef = gameLocal.program.GetDef( type->GetParmType( 0 ), type->GetParmName( 0 ), def ); - assert( selfDef ); - EmitPush( selfDef, selfDef->TypeDef() ); - EmitOpcode( &opcodes[ OP_CALL ], destructorFunc->def, 0 ); - } - } - -// Disabled code since it caused a function to fall through to the next function when last statement is in the form "if ( x ) { return; }" -#if 0 - // don't bother adding a return opcode if the "return" statement was used. - if ( ( func->firstStatement == gameLocal.program.NumStatements() ) || ( gameLocal.program.GetStatement( gameLocal.program.NumStatements() - 1 ).op != OP_RETURN ) ) { - // emit an end of statements opcode - EmitOpcode( OP_RETURN, 0, 0 ); - } -#else - // always emit the return opcode - EmitOpcode( OP_RETURN, 0, 0 ); -#endif - - // record the number of statements in the function - func->numStatements = gameLocal.program.NumStatements() - func->firstStatement; - - scope = oldscope; -} - -/* -================ -idCompiler::ParseVariableDef -================ -*/ -void idCompiler::ParseVariableDef( idTypeDef *type, const char *name ) { - idVarDef *def, *def2; - bool negate; - - def = gameLocal.program.GetDef( type, name, scope ); - if ( def ) { - Error( "%s redeclared", name ); - } - - def = gameLocal.program.AllocDef( type, name, scope, false ); - - // check for an initialization - if ( CheckToken( "=" ) ) { - // if a local variable in a function then write out interpreter code to initialize variable - if ( scope->Type() == ev_function ) { - def2 = GetExpression( TOP_PRIORITY ); - if ( ( type == &type_float ) && ( def2->TypeDef() == &type_float ) ) { - EmitOpcode( OP_STORE_F, def2, def ); - } else if ( ( type == &type_vector ) && ( def2->TypeDef() == &type_vector ) ) { - EmitOpcode( OP_STORE_V, def2, def ); - } else if ( ( type == &type_string ) && ( def2->TypeDef() == &type_string ) ) { - EmitOpcode( OP_STORE_S, def2, def ); - } else if ( ( type == &type_entity ) && ( ( def2->TypeDef() == &type_entity ) || ( def2->TypeDef()->Inherits( &type_object ) ) ) ) { - EmitOpcode( OP_STORE_ENT, def2, def ); - } else if ( ( type->Inherits( &type_object ) ) && ( def2->TypeDef() == &type_entity ) ) { - EmitOpcode( OP_STORE_OBJENT, def2, def ); - } else if ( ( type->Inherits( &type_object ) ) && ( def2->TypeDef()->Inherits( type ) ) ) { - EmitOpcode( OP_STORE_OBJ, def2, def ); - } else if ( ( type == &type_boolean ) && ( def2->TypeDef() == &type_boolean ) ) { - EmitOpcode( OP_STORE_BOOL, def2, def ); - } else if ( ( type == &type_string ) && ( def2->TypeDef() == &type_float ) ) { - EmitOpcode( OP_STORE_FTOS, def2, def ); - } else if ( ( type == &type_string ) && ( def2->TypeDef() == &type_boolean ) ) { - EmitOpcode( OP_STORE_BTOS, def2, def ); - } else if ( ( type == &type_string ) && ( def2->TypeDef() == &type_vector ) ) { - EmitOpcode( OP_STORE_VTOS, def2, def ); - } else if ( ( type == &type_boolean ) && ( def2->TypeDef() == &type_float ) ) { - EmitOpcode( OP_STORE_FTOBOOL, def2, def ); - } else if ( ( type == &type_float ) && ( def2->TypeDef() == &type_boolean ) ) { - EmitOpcode( OP_STORE_BOOLTOF, def2, def ); - } else { - Error( "bad initialization for '%s'", name ); - } - } else { - // global variables can only be initialized with immediate values - negate = false; - if ( token.type == TT_PUNCTUATION && token == "-" ) { - negate = true; - NextToken(); - if ( immediateType != &type_float ) { - Error( "wrong immediate type for '-' on variable '%s'", name ); - } - } - - if ( immediateType != type ) { - Error( "wrong immediate type for '%s'", name ); - } - - // global variables are initialized at start up - if ( type == &type_string ) { - def->SetString( token, false ); - } else { - if ( negate ) { - immediate._float = -immediate._float; - } - def->SetValue( immediate, false ); - } - NextToken(); - } - } else if ( type == &type_string ) { - // local strings on the stack are initialized in the interpreter - if ( scope->Type() != ev_function ) { - def->SetString( "", false ); - } - } else if ( type->Inherits( &type_object ) ) { - if ( scope->Type() != ev_function ) { - def->SetObject( NULL ); - } - } -} - -/* -================ -idCompiler::GetTypeForEventArg -================ -*/ -idTypeDef *idCompiler::GetTypeForEventArg( char argType ) { - idTypeDef *type; - - switch( argType ) { - case D_EVENT_INTEGER : - // this will get converted to int by the interpreter - type = &type_float; - break; - - case D_EVENT_FLOAT : - type = &type_float; - break; - - case D_EVENT_VECTOR : - type = &type_vector; - break; - - case D_EVENT_STRING : - type = &type_string; - break; - - case D_EVENT_ENTITY : - case D_EVENT_ENTITY_NULL : - type = &type_entity; - break; - - case D_EVENT_VOID : - type = &type_void; - break; - - case D_EVENT_TRACE : - // This data type isn't available from script - type = NULL; - break; - - default: - // probably a typo - type = NULL; - break; - } - - return type; -} - -/* -================ -idCompiler::ParseEventDef -================ -*/ -void idCompiler::ParseEventDef( idTypeDef *returnType, const char *name ) { - const idTypeDef *expectedType; - idTypeDef *argType; - idTypeDef *type; - int i; - int num; - const char *format; - const idEventDef *ev; - idStr parmName; - - ev = idEventDef::FindEvent( name ); - if ( !ev ) { - Error( "Unknown event '%s'", name ); - } - - // set the return type - expectedType = GetTypeForEventArg( ev->GetReturnType() ); - if ( !expectedType ) { - Error( "Invalid return type '%c' in definition of '%s' event.", ev->GetReturnType(), name ); - } - if ( returnType != expectedType ) { - Error( "Return type doesn't match internal return type '%s'", expectedType->Name() ); - } - - idTypeDef newtype( ev_function, NULL, name, type_function.Size(), returnType ); - - ExpectToken( "(" ); - - format = ev->GetArgFormat(); - num = strlen( format ); - for( i = 0; i < num; i++ ) { - expectedType = GetTypeForEventArg( format[ i ] ); - if ( !expectedType || ( expectedType == &type_void ) ) { - Error( "Invalid parameter '%c' in definition of '%s' event.", format[ i ], name ); - } - - argType = ParseType(); - ParseName( parmName ); - if ( argType != expectedType ) { - Error( "The type of parm %d ('%s') does not match the internal type '%s' in definition of '%s' event.", - i + 1, parmName.c_str(), expectedType->Name(), name ); - } - - newtype.AddFunctionParm( argType, "" ); - - if ( i < num - 1 ) { - if ( CheckToken( ")" ) ) { - Error( "Too few parameters for event definition. Internal definition has %d parameters.", num ); - } - ExpectToken( "," ); - } - } - if ( !CheckToken( ")" ) ) { - Error( "Too many parameters for event definition. Internal definition has %d parameters.", num ); - } - ExpectToken( ";" ); - - type = gameLocal.program.FindType( name ); - if ( type ) { - if ( !newtype.MatchesType( *type ) || ( type->def->value.functionPtr->eventdef != ev ) ) { - Error( "Type mismatch on redefinition of '%s'", name ); - } - } else { - type = gameLocal.program.AllocType( newtype ); - type->def = gameLocal.program.AllocDef( type, name, &def_namespace, true ); - - function_t &func = gameLocal.program.AllocFunction( type->def ); - func.eventdef = ev; - func.parmSize.SetNum( num ); - for( i = 0; i < num; i++ ) { - argType = newtype.GetParmType( i ); - func.parmTotal += argType->Size(); - func.parmSize[ i ] = argType->Size(); - } - - // mark the parms as local - func.locals = func.parmTotal; - } -} - -/* -================ -idCompiler::ParseDefs - -Called at the outer layer and when a local statement is hit -================ -*/ -void idCompiler::ParseDefs( void ) { - idStr name; - idTypeDef *type; - idVarDef *def; - idVarDef *oldscope; - - if ( CheckToken( ";" ) ) { - // skip semicolons, which are harmless and ok syntax - return; - } - - type = ParseType(); - if ( type == &type_scriptevent ) { - type = ParseType(); - ParseName( name ); - ParseEventDef( type, name ); - return; - } - - ParseName( name ); - - if ( type == &type_namespace ) { - def = gameLocal.program.GetDef( type, name, scope ); - if ( !def ) { - def = gameLocal.program.AllocDef( type, name, scope, true ); - } - ParseNamespace( def ); - } else if ( CheckToken( "::" ) ) { - def = gameLocal.program.GetDef( NULL, name, scope ); - if ( !def ) { - Error( "Unknown object name '%s'", name.c_str() ); - } - ParseName( name ); - oldscope = scope; - scope = def; - - ExpectToken( "(" ); - ParseFunctionDef( type, name.c_str() ); - scope = oldscope; - } else if ( type == &type_object ) { - ParseObjectDef( name.c_str() ); - } else if ( CheckToken( "(" ) ) { // check for a function prototype or declaraction - ParseFunctionDef( type, name.c_str() ); - } else { - ParseVariableDef( type, name.c_str() ); - while( CheckToken( "," ) ) { - ParseName( name ); - ParseVariableDef( type, name.c_str() ); - } - ExpectToken( ";" ); - } -} - -/* -================ -idCompiler::ParseNamespace - -Parses anything within a namespace definition -================ -*/ -void idCompiler::ParseNamespace( idVarDef *newScope ) { - idVarDef *oldscope; - - oldscope = scope; - if ( newScope != &def_namespace ) { - ExpectToken( "{" ); - } - - while( !eof ) { - scope = newScope; - callthread = false; - - if ( ( newScope != &def_namespace ) && CheckToken( "}" ) ) { - break; - } - - ParseDefs(); - } - - scope = oldscope; -} - -/* -============ -idCompiler::CompileFile - -compiles the 0 terminated text, adding definitions to the program structure -============ -*/ -void idCompiler::CompileFile( const char *text, const char *filename, bool toConsole ) { - idTimer compile_time; - bool error; - - compile_time.Start(); - - idStr origFileName = filename; // DG: filename pointer might become invalid when calling NextToken() below - - scope = &def_namespace; - basetype = NULL; - callthread = false; - loopDepth = 0; - eof = false; - braceDepth = 0; - immediateType = NULL; - currentLineNumber = 0; - console = toConsole; - - memset( &immediate, 0, sizeof( immediate ) ); - - parser.SetFlags( LEXFL_ALLOWMULTICHARLITERALS ); - parser.LoadMemory( text, strlen( text ), filename ); - parserPtr = &parser; - - // unread tokens to include script defines - token = SCRIPT_DEFAULTDEFS; - token.type = TT_STRING; - token.subtype = token.Length(); - token.line = token.linesCrossed = 0; - parser.UnreadToken( &token ); - - token = "include"; - token.type = TT_NAME; - token.subtype = token.Length(); - token.line = token.linesCrossed = 0; - parser.UnreadToken( &token ); - - token = "#"; - token.type = TT_PUNCTUATION; - token.subtype = P_PRECOMP; - token.line = token.linesCrossed = 0; - parser.UnreadToken( &token ); - - // init the current token line to be the first line so that currentLineNumber is set correctly in NextToken - token.line = 1; - - error = false; - try { - // read first token - NextToken(); - while( !eof && !error ) { - // parse from global namespace - ParseNamespace( &def_namespace ); - } - } - - catch( idCompileError &err ) { - idStr error; - - if ( console ) { - // don't print line number of an error if were calling script from the console using the "script" command - sprintf( error, "Error: %s\n", err.error ); - } else { - sprintf( error, "Error: file %s, line %d: %s\n", gameLocal.program.GetFilename( currentFileNumber ), currentLineNumber, err.error ); - } - - parser.FreeSource(); - - throw idCompileError( error ); - } - - parser.FreeSource(); - - compile_time.Stop(); - if ( !toConsole ) { - // DG: filename can be overwritten by NextToken() (via gameLocal.program.GetFilenum()), so - // use a copy, origFileName, that's still valid here. Furthermore, the path is nonsense, - // as idProgram::CompileText() called fileSystem->RelativePathToOSPath() on it - // which does not return the *actual* full path of that file but invents one, - // so revert that to the relative filename which at least isn't misleading - gameLocal.Printf( "Compiled '%s': %u ms\n", fileSystem->OSPathToRelativePath(origFileName), compile_time.Milliseconds() ); - } -} diff --git a/d3xp/script/Script_Compiler.h b/d3xp/script/Script_Compiler.h deleted file mode 100644 index be9fb68d..00000000 --- a/d3xp/script/Script_Compiler.h +++ /dev/null @@ -1,282 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ -#ifndef __SCRIPT_COMPILER_H__ -#define __SCRIPT_COMPILER_H__ - -#include "idlib/Parser.h" - -#include "script/Script_Program.h" - -const char * const RESULT_STRING = ""; - -typedef struct opcode_s { - const char *name; - const char *opname; - int priority; - bool rightAssociative; - idVarDef *type_a; - idVarDef *type_b; - idVarDef *type_c; -} opcode_t; - -// These opcodes are no longer necessary: -// OP_PUSH_OBJ: -// OP_PUSH_OBJENT: - -enum { - OP_RETURN, - - OP_UINC_F, - OP_UINCP_F, - OP_UDEC_F, - OP_UDECP_F, - OP_COMP_F, - - OP_MUL_F, - OP_MUL_V, - OP_MUL_FV, - OP_MUL_VF, - OP_DIV_F, - OP_MOD_F, - OP_ADD_F, - OP_ADD_V, - OP_ADD_S, - OP_ADD_FS, - OP_ADD_SF, - OP_ADD_VS, - OP_ADD_SV, - OP_SUB_F, - OP_SUB_V, - - OP_EQ_F, - OP_EQ_V, - OP_EQ_S, - OP_EQ_E, - OP_EQ_EO, - OP_EQ_OE, - OP_EQ_OO, - - OP_NE_F, - OP_NE_V, - OP_NE_S, - OP_NE_E, - OP_NE_EO, - OP_NE_OE, - OP_NE_OO, - - OP_LE, - OP_GE, - OP_LT, - OP_GT, - - OP_INDIRECT_F, - OP_INDIRECT_V, - OP_INDIRECT_S, - OP_INDIRECT_ENT, - OP_INDIRECT_BOOL, - OP_INDIRECT_OBJ, - - OP_ADDRESS, - - OP_EVENTCALL, - OP_OBJECTCALL, - OP_SYSCALL, - - OP_STORE_F, - OP_STORE_V, - OP_STORE_S, - OP_STORE_ENT, - OP_STORE_BOOL, - OP_STORE_OBJENT, - OP_STORE_OBJ, - OP_STORE_ENTOBJ, - - OP_STORE_FTOS, - OP_STORE_BTOS, - OP_STORE_VTOS, - OP_STORE_FTOBOOL, - OP_STORE_BOOLTOF, - - OP_STOREP_F, - OP_STOREP_V, - OP_STOREP_S, - OP_STOREP_ENT, - OP_STOREP_FLD, - OP_STOREP_BOOL, - OP_STOREP_OBJ, - OP_STOREP_OBJENT, - - OP_STOREP_FTOS, - OP_STOREP_BTOS, - OP_STOREP_VTOS, - OP_STOREP_FTOBOOL, - OP_STOREP_BOOLTOF, - - OP_UMUL_F, - OP_UMUL_V, - OP_UDIV_F, - OP_UDIV_V, - OP_UMOD_F, - OP_UADD_F, - OP_UADD_V, - OP_USUB_F, - OP_USUB_V, - OP_UAND_F, - OP_UOR_F, - - OP_NOT_BOOL, - OP_NOT_F, - OP_NOT_V, - OP_NOT_S, - OP_NOT_ENT, - - OP_NEG_F, - OP_NEG_V, - - OP_INT_F, - OP_IF, - OP_IFNOT, - - OP_CALL, - OP_THREAD, - OP_OBJTHREAD, - - OP_PUSH_F, - OP_PUSH_V, - OP_PUSH_S, - OP_PUSH_ENT, - OP_PUSH_OBJ, - OP_PUSH_OBJENT, - OP_PUSH_FTOS, - OP_PUSH_BTOF, - OP_PUSH_FTOB, - OP_PUSH_VTOS, - OP_PUSH_BTOS, - - OP_GOTO, - - OP_AND, - OP_AND_BOOLF, - OP_AND_FBOOL, - OP_AND_BOOLBOOL, - OP_OR, - OP_OR_BOOLF, - OP_OR_FBOOL, - OP_OR_BOOLBOOL, - - OP_BITAND, - OP_BITOR, - - OP_BREAK, // placeholder op. not used in final code - OP_CONTINUE, // placeholder op. not used in final code - - NUM_OPCODES -}; - -class idCompiler { -private: - static bool punctuationValid[ 256 ]; - static const char *punctuation[]; - - idParser parser; - idParser *parserPtr; - idToken token; - - idTypeDef *immediateType; - eval_t immediate; - - bool eof; - bool console; - bool callthread; - int braceDepth; - int loopDepth; - int currentLineNumber; - int currentFileNumber; - int errorCount; - - idVarDef *scope; // the function being parsed, or NULL - const idVarDef *basetype; // for accessing fields - - float Divide( float numerator, float denominator ); - void Error( const char *error, ... ) const id_attribute((format(printf,2,3))); - void Warning( const char *message, ... ) const id_attribute((format(printf,2,3))); - idVarDef *OptimizeOpcode( const opcode_t *op, idVarDef *var_a, idVarDef *var_b ); - idVarDef *EmitOpcode( const opcode_t *op, idVarDef *var_a, idVarDef *var_b ); - idVarDef *EmitOpcode( int op, idVarDef *var_a, idVarDef *var_b ); - bool EmitPush( idVarDef *expression, const idTypeDef *funcArg ); - void NextToken( void ); - void ExpectToken( const char *string ); - bool CheckToken( const char *string ); - void ParseName( idStr &name ); - void SkipOutOfFunction( void ); - void SkipToSemicolon( void ); - idTypeDef *CheckType( void ); - idTypeDef *ParseType( void ); - idVarDef *FindImmediate( const idTypeDef *type, const eval_t *eval, const char *string ) const; - idVarDef *GetImmediate( idTypeDef *type, const eval_t *eval, const char *string ); - idVarDef *VirtualFunctionConstant( idVarDef *func ); - idVarDef *SizeConstant( int size ); - idVarDef *JumpConstant( int value ); - idVarDef *JumpDef( int jumpfrom, int jumpto ); - idVarDef *JumpTo( int jumpto ); - idVarDef *JumpFrom( int jumpfrom ); - idVarDef *ParseImmediate( void ); - idVarDef *EmitFunctionParms( int op, idVarDef *func, int startarg, int startsize, idVarDef *object ); - idVarDef *ParseFunctionCall( idVarDef *func ); - idVarDef *ParseObjectCall( idVarDef *object, idVarDef *func ); - idVarDef *ParseEventCall( idVarDef *object, idVarDef *func ); - idVarDef *ParseSysObjectCall( idVarDef *func ); - idVarDef *LookupDef( const char *name, const idVarDef *baseobj ); - idVarDef *ParseValue( void ); - idVarDef *GetTerm( void ); - bool TypeMatches( etype_t type1, etype_t type2 ) const; - idVarDef *GetExpression( int priority ); - idTypeDef *GetTypeForEventArg( char argType ); - void PatchLoop( int start, int continuePos ); - void ParseReturnStatement( void ); - void ParseWhileStatement( void ); - void ParseForStatement( void ); - void ParseDoWhileStatement( void ); - void ParseIfStatement( void ); - void ParseStatement( void ); - void ParseObjectDef( const char *objname ); - idTypeDef *ParseFunction( idTypeDef *returnType, const char *name ); - void ParseFunctionDef( idTypeDef *returnType, const char *name ); - void ParseVariableDef( idTypeDef *type, const char *name ); - void ParseEventDef( idTypeDef *type, const char *name ); - void ParseDefs( void ); - void ParseNamespace( idVarDef *newScope ); - -public : - static const opcode_t opcodes[]; - - idCompiler(); - void CompileFile( const char *text, const char *filename, bool console ); -}; - -#endif /* !__SCRIPT_COMPILER_H__ */ diff --git a/d3xp/script/Script_Interpreter.cpp b/d3xp/script/Script_Interpreter.cpp deleted file mode 100644 index c8e0cc45..00000000 --- a/d3xp/script/Script_Interpreter.cpp +++ /dev/null @@ -1,1835 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "gamesys/SysCvar.h" -#include "script/Script_Compiler.h" -#include "script/Script_Thread.h" - -#include "script/Script_Interpreter.h" - -/* -================ -idInterpreter::idInterpreter() -================ -*/ -idInterpreter::idInterpreter() { - localstackUsed = 0; - terminateOnExit = true; - debug = 0; - memset( localstack, 0, sizeof( localstack ) ); - memset( callStack, 0, sizeof( callStack ) ); - Reset(); -} - -/* -================ -idInterpreter::Save -================ -*/ -void idInterpreter::Save( idSaveGame *savefile ) const { - int i; - - savefile->WriteInt( callStackDepth ); - for( i = 0; i < callStackDepth; i++ ) { - savefile->WriteInt( callStack[i].s ); - if ( callStack[i].f ) { - savefile->WriteInt( gameLocal.program.GetFunctionIndex( callStack[i].f ) ); - } else { - savefile->WriteInt( -1 ); - } - savefile->WriteInt( callStack[i].stackbase ); - } - savefile->WriteInt( maxStackDepth ); - - savefile->WriteInt( localstackUsed ); - savefile->Write( &localstack, localstackUsed ); - - savefile->WriteInt( localstackBase ); - savefile->WriteInt( maxLocalstackUsed ); - - if ( currentFunction ) { - savefile->WriteInt( gameLocal.program.GetFunctionIndex( currentFunction ) ); - } else { - savefile->WriteInt( -1 ); - } - savefile->WriteInt( instructionPointer ); - - savefile->WriteInt( popParms ); - - if ( multiFrameEvent ) { - savefile->WriteString( multiFrameEvent->GetName() ); - } else { - savefile->WriteString( "" ); - } - savefile->WriteObject( eventEntity ); - - savefile->WriteObject( thread ); - - savefile->WriteBool( doneProcessing ); - savefile->WriteBool( threadDying ); - savefile->WriteBool( terminateOnExit ); - savefile->WriteBool( debug ); -} - -/* -================ -idInterpreter::Restore -================ -*/ -void idInterpreter::Restore( idRestoreGame *savefile ) { - int i; - idStr funcname; - int func_index; - - savefile->ReadInt( callStackDepth ); - for( i = 0; i < callStackDepth; i++ ) { - savefile->ReadInt( callStack[i].s ); - - savefile->ReadInt( func_index ); - if ( func_index >= 0 ) { - callStack[i].f = gameLocal.program.GetFunction( func_index ); - } else { - callStack[i].f = NULL; - } - - savefile->ReadInt( callStack[i].stackbase ); - } - savefile->ReadInt( maxStackDepth ); - - savefile->ReadInt( localstackUsed ); - savefile->Read( &localstack, localstackUsed ); - - savefile->ReadInt( localstackBase ); - savefile->ReadInt( maxLocalstackUsed ); - - savefile->ReadInt( func_index ); - if ( func_index >= 0 ) { - currentFunction = gameLocal.program.GetFunction( func_index ); - } else { - currentFunction = NULL; - } - savefile->ReadInt( instructionPointer ); - - savefile->ReadInt( popParms ); - - savefile->ReadString( funcname ); - if ( funcname.Length() ) { - multiFrameEvent = idEventDef::FindEvent( funcname ); - } - - savefile->ReadObject( reinterpret_cast( eventEntity ) ); - savefile->ReadObject( reinterpret_cast( thread ) ); - - savefile->ReadBool( doneProcessing ); - savefile->ReadBool( threadDying ); - savefile->ReadBool( terminateOnExit ); - savefile->ReadBool( debug ); -} - -/* -================ -idInterpreter::Reset -================ -*/ -void idInterpreter::Reset( void ) { - callStackDepth = 0; - localstackUsed = 0; - localstackBase = 0; - - maxLocalstackUsed = 0; - maxStackDepth = 0; - - popParms = 0; - multiFrameEvent = NULL; - eventEntity = NULL; - - currentFunction = 0; - NextInstruction( 0 ); - - threadDying = false; - doneProcessing = true; -} - -/* -================ -idInterpreter::GetRegisterValue - -Returns a string representation of the value of the register. This is -used primarily for the debugger and debugging - -//FIXME: This is pretty much wrong. won't access data in most situations. -================ -*/ -bool idInterpreter::GetRegisterValue( const char *name, idStr &out, int scopeDepth ) { - varEval_t reg; - idVarDef *d; - char funcObject[ 1024 ]; - char *funcName; - const idVarDef *scope; - const idTypeDef *field; - const idScriptObject *obj; - const function_t *func; - - out.Empty(); - - if ( scopeDepth == -1 ) { - scopeDepth = callStackDepth; - } - - if ( scopeDepth == callStackDepth ) { - func = currentFunction; - } else { - func = callStack[ scopeDepth ].f; - } - if ( !func ) { - return false; - } - - idStr::Copynz( funcObject, func->Name(), sizeof( funcObject ) ); - funcName = strstr( funcObject, "::" ); - if ( funcName ) { - *funcName = '\0'; - scope = gameLocal.program.GetDef( NULL, funcObject, &def_namespace ); - funcName += 2; - } else { - funcName = funcObject; - scope = &def_namespace; - } - - // Get the function from the object - d = gameLocal.program.GetDef( NULL, funcName, scope ); - if ( !d ) { - return false; - } - - // Get the variable itself and check various namespaces - d = gameLocal.program.GetDef( NULL, name, d ); - if ( !d ) { - if ( scope == &def_namespace ) { - return false; - } - - d = gameLocal.program.GetDef( NULL, name, scope ); - if ( !d ) { - d = gameLocal.program.GetDef( NULL, name, &def_namespace ); - if ( !d ) { - return false; - } - } - } - - reg = GetVariable( d ); - switch( d->Type() ) { - case ev_float: - if ( reg.floatPtr ) { - out = va("%g", *reg.floatPtr ); - } else { - out = "0"; - } - return true; - break; - - case ev_vector: - if ( reg.vectorPtr ) { - out = va( "%g,%g,%g", reg.vectorPtr->x, reg.vectorPtr->y, reg.vectorPtr->z ); - } else { - out = "0,0,0"; - } - return true; - break; - - case ev_boolean: - if ( reg.intPtr ) { - out = va( "%d", *reg.intPtr ); - } else { - out = "0"; - } - return true; - break; - - case ev_field: - if ( scope == &def_namespace ) { - // should never happen, but handle it safely anyway - return false; - } - - field = scope->TypeDef()->GetParmType( reg.ptrOffset )->FieldType(); - obj = *reinterpret_cast( &localstack[ callStack[ callStackDepth ].stackbase ] ); - if ( !field || !obj ) { - return false; - } - - switch ( field->Type() ) { - case ev_boolean: - out = va( "%d", *( reinterpret_cast( &obj->data[ reg.ptrOffset ] ) ) ); - return true; - - case ev_float: - out = va( "%g", *( reinterpret_cast( &obj->data[ reg.ptrOffset ] ) ) ); - return true; - - default: - return false; - } - break; - - case ev_string: - if ( reg.stringPtr ) { - out = "\""; - out += reg.stringPtr; - out += "\""; - } else { - out = "\"\""; - } - return true; - - default: - return false; - } -} - -/* -================ -idInterpreter::GetCallstackDepth -================ -*/ -int idInterpreter::GetCallstackDepth( void ) const { - return callStackDepth; -} - -/* -================ -idInterpreter::GetCallstack -================ -*/ -const prstack_t *idInterpreter::GetCallstack( void ) const { - return &callStack[ 0 ]; -} - -/* -================ -idInterpreter::GetCurrentFunction -================ -*/ -const function_t *idInterpreter::GetCurrentFunction( void ) const { - return currentFunction; -} - -/* -================ -idInterpreter::GetThread -================ -*/ -idThread *idInterpreter::GetThread( void ) const { - return thread; -} - - -/* -================ -idInterpreter::SetThread -================ -*/ -void idInterpreter::SetThread( idThread *pThread ) { - thread = pThread; -} - -/* -================ -idInterpreter::CurrentLine -================ -*/ -int idInterpreter::CurrentLine( void ) const { - if ( instructionPointer < 0 ) { - return 0; - } - return gameLocal.program.GetLineNumberForStatement( instructionPointer ); -} - -/* -================ -idInterpreter::CurrentFile -================ -*/ -const char *idInterpreter::CurrentFile( void ) const { - if ( instructionPointer < 0 ) { - return ""; - } - return gameLocal.program.GetFilenameForStatement( instructionPointer ); -} - -/* -============ -idInterpreter::StackTrace -============ -*/ -void idInterpreter::StackTrace( void ) const { - const function_t *f; - int i; - int top; - - if ( callStackDepth == 0 ) { - gameLocal.Printf( "\n" ); - return; - } - - top = callStackDepth; - if ( top >= MAX_STACK_DEPTH ) { - top = MAX_STACK_DEPTH - 1; - } - - if ( !currentFunction ) { - gameLocal.Printf( "\n" ); - } else { - gameLocal.Printf( "%12s : %s\n", gameLocal.program.GetFilename( currentFunction->filenum ), currentFunction->Name() ); - } - - for( i = top; i >= 0; i-- ) { - f = callStack[ i ].f; - if ( !f ) { - gameLocal.Printf( "\n" ); - } else { - gameLocal.Printf( "%12s : %s\n", gameLocal.program.GetFilename( f->filenum ), f->Name() ); - } - } -} - -/* -============ -idInterpreter::Error - -Aborts the currently executing function -============ -*/ -void idInterpreter::Error( const char *fmt, ... ) const { - va_list argptr; - char text[ 1024 ]; - - va_start( argptr, fmt ); - vsprintf( text, fmt, argptr ); - va_end( argptr ); - - StackTrace(); - - if ( ( instructionPointer >= 0 ) && ( instructionPointer < gameLocal.program.NumStatements() ) ) { - statement_t &line = gameLocal.program.GetStatement( instructionPointer ); - common->Error( "%s(%d): Thread '%s': %s\n", gameLocal.program.GetFilename( line.file ), line.linenumber, thread->GetThreadName(), text ); - } else { - common->Error( "Thread '%s': %s\n", thread->GetThreadName(), text ); - } -} - -/* -============ -idInterpreter::Warning - -Prints file and line number information with warning. -============ -*/ -void idInterpreter::Warning( const char *fmt, ... ) const { - va_list argptr; - char text[ 1024 ]; - - va_start( argptr, fmt ); - vsprintf( text, fmt, argptr ); - va_end( argptr ); - - if ( ( instructionPointer >= 0 ) && ( instructionPointer < gameLocal.program.NumStatements() ) ) { - statement_t &line = gameLocal.program.GetStatement( instructionPointer ); - common->Warning( "%s(%d): Thread '%s': %s", gameLocal.program.GetFilename( line.file ), line.linenumber, thread->GetThreadName(), text ); - } else { - common->Warning( "Thread '%s' : %s", thread->GetThreadName(), text ); - } -} - -/* -================ -idInterpreter::DisplayInfo -================ -*/ -void idInterpreter::DisplayInfo( void ) const { - const function_t *f; - int i; - - gameLocal.Printf( " Stack depth: %d bytes, %d max\n", localstackUsed, maxLocalstackUsed ); - gameLocal.Printf( " Call depth: %d, %d max\n", callStackDepth, maxStackDepth ); - gameLocal.Printf( " Call Stack: " ); - - if ( callStackDepth == 0 ) { - gameLocal.Printf( "\n" ); - } else { - if ( !currentFunction ) { - gameLocal.Printf( "\n" ); - } else { - gameLocal.Printf( "%12s : %s\n", gameLocal.program.GetFilename( currentFunction->filenum ), currentFunction->Name() ); - } - - for( i = callStackDepth; i > 0; i-- ) { - gameLocal.Printf( " " ); - f = callStack[ i ].f; - if ( !f ) { - gameLocal.Printf( "\n" ); - } else { - gameLocal.Printf( "%12s : %s\n", gameLocal.program.GetFilename( f->filenum ), f->Name() ); - } - } - } -} - -/* -==================== -idInterpreter::ThreadCall - -Copys the args from the calling thread's stack -==================== -*/ -void idInterpreter::ThreadCall( idInterpreter *source, const function_t *func, int args ) { - Reset(); - - memcpy( localstack, &source->localstack[ source->localstackUsed - args ], args ); - - localstackUsed = args; - localstackBase = 0; - - maxLocalstackUsed = localstackUsed; - EnterFunction( func, false ); - - thread->SetThreadName( currentFunction->Name() ); -} - -/* -================ -idInterpreter::EnterObjectFunction - -Calls a function on a script object. - -NOTE: If this is called from within a event called by this interpreter, the function arguments will be invalid after calling this function. -================ -*/ -void idInterpreter::EnterObjectFunction( idEntity *self, const function_t *func, bool clearStack ) { - if ( clearStack ) { - Reset(); - } - if ( popParms ) { - PopParms( popParms ); - popParms = 0; - } - Push( self->entityNumber + 1 ); - EnterFunction( func, false ); -} - -/* -==================== -idInterpreter::EnterFunction - -Returns the new program statement counter - -NOTE: If this is called from within a event called by this interpreter, the function arguments will be invalid after calling this function. -==================== -*/ -void idInterpreter::EnterFunction( const function_t *func, bool clearStack ) { - int c; - prstack_t *stack; - - if ( clearStack ) { - Reset(); - } - if ( popParms ) { - PopParms( popParms ); - popParms = 0; - } - - if ( callStackDepth >= MAX_STACK_DEPTH ) { - Error( "call stack overflow" ); - } - - stack = &callStack[ callStackDepth ]; - - stack->s = instructionPointer + 1; // point to the next instruction to execute - stack->f = currentFunction; - stack->stackbase = localstackBase; - - callStackDepth++; - if ( callStackDepth > maxStackDepth ) { - maxStackDepth = callStackDepth; - } - - if ( !func ) { - Error( "NULL function" ); - } - - if ( debug ) { - if ( currentFunction ) { - gameLocal.Printf( "%d: call '%s' from '%s'(line %d)%s\n", gameLocal.time, func->Name(), currentFunction->Name(), - gameLocal.program.GetStatement( instructionPointer ).linenumber, clearStack ? " clear stack" : "" ); - } else { - gameLocal.Printf( "%d: call '%s'%s\n", gameLocal.time, func->Name(), clearStack ? " clear stack" : "" ); - } - } - - currentFunction = func; - assert( !func->eventdef ); - NextInstruction( func->firstStatement ); - - // allocate space on the stack for locals - // parms are already on stack - c = func->locals - func->parmTotal; - assert( c >= 0 ); - - if ( localstackUsed + c > LOCALSTACK_SIZE ) { - Error( "EnterFuncton: locals stack overflow\n" ); - } - - // initialize local stack variables to zero - memset( &localstack[ localstackUsed ], 0, c ); - - localstackUsed += c; - localstackBase = localstackUsed - func->locals; - - if ( localstackUsed > maxLocalstackUsed ) { - maxLocalstackUsed = localstackUsed ; - } -} - -/* -==================== -idInterpreter::LeaveFunction -==================== -*/ -void idInterpreter::LeaveFunction( idVarDef *returnDef ) { - prstack_t *stack; - varEval_t ret; - - if ( callStackDepth <= 0 ) { - Error( "prog stack underflow" ); - } - - // return value - if ( returnDef ) { - switch( returnDef->Type() ) { - case ev_string : - gameLocal.program.ReturnString( GetString( returnDef ) ); - break; - - case ev_vector : - ret = GetVariable( returnDef ); - gameLocal.program.ReturnVector( *ret.vectorPtr ); - break; - - default : - ret = GetVariable( returnDef ); - gameLocal.program.ReturnInteger( *ret.intPtr ); - } - } - - // remove locals from the stack - PopParms( currentFunction->locals ); - assert( localstackUsed == localstackBase ); - - if ( debug ) { - statement_t &line = gameLocal.program.GetStatement( instructionPointer ); - gameLocal.Printf( "%d: %s(%d): exit %s", gameLocal.time, gameLocal.program.GetFilename( line.file ), line.linenumber, currentFunction->Name() ); - if ( callStackDepth > 1 ) { - gameLocal.Printf( " return to %s(line %d)\n", callStack[ callStackDepth - 1 ].f->Name(), gameLocal.program.GetStatement( callStack[ callStackDepth - 1 ].s ).linenumber ); - } else { - gameLocal.Printf( " done\n" ); - } - } - - // up stack - callStackDepth--; - stack = &callStack[ callStackDepth ]; - currentFunction = stack->f; - localstackBase = stack->stackbase; - NextInstruction( stack->s ); - - if ( !callStackDepth ) { - // all done - doneProcessing = true; - threadDying = true; - currentFunction = 0; - } -} - -/* -================ -idInterpreter::CallEvent -================ -*/ -void idInterpreter::CallEvent( const function_t *func, int argsize ) { - int i; - int j; - varEval_t var; - int pos; - int start; - intptr_t data[ D_EVENT_MAXARGS ]; - const idEventDef *evdef; - const char *format; - - if ( !func ) { - Error( "NULL function" ); - } - - assert( func->eventdef ); - evdef = func->eventdef; - - start = localstackUsed - argsize; - var.intPtr = ( int * )&localstack[ start ]; - eventEntity = GetEntity( *var.entityNumberPtr ); - - if ( !eventEntity || !eventEntity->RespondsTo( *evdef ) ) { - if ( eventEntity && developer.GetBool() ) { - // give a warning in developer mode - Warning( "Function '%s' not supported on entity '%s'", evdef->GetName(), eventEntity->name.c_str() ); - } - // always return a safe value when an object doesn't exist - switch( evdef->GetReturnType() ) { - case D_EVENT_INTEGER : - gameLocal.program.ReturnInteger( 0 ); - break; - - case D_EVENT_FLOAT : - gameLocal.program.ReturnFloat( 0 ); - break; - - case D_EVENT_VECTOR : - gameLocal.program.ReturnVector( vec3_zero ); - break; - - case D_EVENT_STRING : - gameLocal.program.ReturnString( "" ); - break; - - case D_EVENT_ENTITY : - case D_EVENT_ENTITY_NULL : - gameLocal.program.ReturnEntity( ( idEntity * )NULL ); - break; - - case D_EVENT_TRACE : - default: - // unsupported data type - break; - } - - PopParms( argsize ); - eventEntity = NULL; - return; - } - - format = evdef->GetArgFormat(); - for( j = 0, i = 0, pos = type_object.Size(); ( pos < argsize ) || ( format[ i ] != 0 ); i++ ) { - switch( format[ i ] ) { - case D_EVENT_INTEGER : - var.intPtr = ( int * )&localstack[ start + pos ]; - ( *( int * )&data[ i ] ) = int( *var.floatPtr ); - break; - - case D_EVENT_FLOAT : - var.intPtr = ( int * )&localstack[ start + pos ]; - ( *( float * )&data[ i ] ) = *var.floatPtr; - break; - - case D_EVENT_VECTOR : - var.intPtr = ( int * )&localstack[ start + pos ]; - ( *( idVec3 ** )&data[ i ] ) = var.vectorPtr; - break; - - case D_EVENT_STRING : - ( *( const char ** )&data[ i ] ) = ( char * )&localstack[ start + pos ]; - break; - - case D_EVENT_ENTITY : - var.intPtr = ( int * )&localstack[ start + pos ]; - ( *( idEntity ** )&data[ i ] ) = GetEntity( *var.entityNumberPtr ); - if ( !( *( idEntity ** )&data[ i ] ) ) { - Warning( "Entity not found for event '%s'. Terminating thread.", evdef->GetName() ); - threadDying = true; - PopParms( argsize ); - return; - } - break; - - case D_EVENT_ENTITY_NULL : - var.intPtr = ( int * )&localstack[ start + pos ]; - ( *( idEntity ** )&data[ i ] ) = GetEntity( *var.entityNumberPtr ); - break; - - case D_EVENT_TRACE : - Error( "trace type not supported from script for '%s' event.", evdef->GetName() ); - break; - - default : - Error( "Invalid arg format string for '%s' event.", evdef->GetName() ); - break; - } - - pos += func->parmSize[ j++ ]; - } - - popParms = argsize; - eventEntity->ProcessEventArgPtr( evdef, data ); - - if ( !multiFrameEvent ) { - if ( popParms ) { - PopParms( popParms ); - } - eventEntity = NULL; - } else { - doneProcessing = true; - } - popParms = 0; -} - -/* -================ -idInterpreter::BeginMultiFrameEvent -================ -*/ -bool idInterpreter::BeginMultiFrameEvent( idEntity *ent, const idEventDef *event ) { - if ( eventEntity != ent ) { - Error( "idInterpreter::BeginMultiFrameEvent called with wrong entity" ); - } - if ( multiFrameEvent ) { - if ( multiFrameEvent != event ) { - Error( "idInterpreter::BeginMultiFrameEvent called with wrong event" ); - } - return false; - } - - multiFrameEvent = event; - return true; -} - -/* -================ -idInterpreter::EndMultiFrameEvent -================ -*/ -void idInterpreter::EndMultiFrameEvent( idEntity *ent, const idEventDef *event ) { - if ( multiFrameEvent != event ) { - Error( "idInterpreter::EndMultiFrameEvent called with wrong event" ); - } - - multiFrameEvent = NULL; -} - -/* -================ -idInterpreter::MultiFrameEventInProgress -================ -*/ -bool idInterpreter::MultiFrameEventInProgress( void ) const { - return multiFrameEvent != NULL; -} - -/* -================ -idInterpreter::CallSysEvent -================ -*/ -void idInterpreter::CallSysEvent( const function_t *func, int argsize ) { - int i; - int j; - varEval_t source; - int pos; - int start; - intptr_t data[ D_EVENT_MAXARGS ]; - const idEventDef *evdef; - const char *format; - - if ( !func ) { - Error( "NULL function" ); - } - - assert( func->eventdef ); - evdef = func->eventdef; - - start = localstackUsed - argsize; - - format = evdef->GetArgFormat(); - for( j = 0, i = 0, pos = 0; ( pos < argsize ) || ( format[ i ] != 0 ); i++ ) { - switch( format[ i ] ) { - case D_EVENT_INTEGER : - source.intPtr = ( int * )&localstack[ start + pos ]; - *( int * )&data[ i ] = int( *source.floatPtr ); - break; - - case D_EVENT_FLOAT : - source.intPtr = ( int * )&localstack[ start + pos ]; - *( float * )&data[ i ] = *source.floatPtr; - break; - - case D_EVENT_VECTOR : - source.intPtr = ( int * )&localstack[ start + pos ]; - *( idVec3 ** )&data[ i ] = source.vectorPtr; - break; - - case D_EVENT_STRING : - *( const char ** )&data[ i ] = ( char * )&localstack[ start + pos ]; - break; - - case D_EVENT_ENTITY : - source.intPtr = ( int * )&localstack[ start + pos ]; - *( idEntity ** )&data[ i ] = GetEntity( *source.entityNumberPtr ); - if ( !*( idEntity ** )&data[ i ] ) { - Warning( "Entity not found for event '%s'. Terminating thread.", evdef->GetName() ); - threadDying = true; - PopParms( argsize ); - return; - } - break; - - case D_EVENT_ENTITY_NULL : - source.intPtr = ( int * )&localstack[ start + pos ]; - *( idEntity ** )&data[ i ] = GetEntity( *source.entityNumberPtr ); - break; - - case D_EVENT_TRACE : - Error( "trace type not supported from script for '%s' event.", evdef->GetName() ); - break; - - default : - Error( "Invalid arg format string for '%s' event.", evdef->GetName() ); - break; - } - - pos += func->parmSize[ j++ ]; - } - - popParms = argsize; - thread->ProcessEventArgPtr( evdef, data ); - if ( popParms ) { - PopParms( popParms ); - } - popParms = 0; -} - -/* -==================== -idInterpreter::Execute -==================== -*/ -bool idInterpreter::Execute( void ) { - varEval_t var_a; - varEval_t var_b; - varEval_t var_c; - varEval_t var; - statement_t *st; - int runaway; - idThread *newThread; - float floatVal; - idScriptObject *obj; - const function_t *func; - - if ( threadDying || !currentFunction ) { - return true; - } - - if ( multiFrameEvent ) { - // move to previous instruction and call it again - instructionPointer--; - } - - runaway = 5000000; - - doneProcessing = false; - while( !doneProcessing && !threadDying ) { - instructionPointer++; - - if ( !--runaway ) { - Error( "runaway loop error" ); - } - - // next statement - st = &gameLocal.program.GetStatement( instructionPointer ); - - switch( st->op ) { - case OP_RETURN: - LeaveFunction( st->a ); - break; - - case OP_THREAD: - newThread = new idThread( this, st->a->value.functionPtr, st->b->value.argSize ); - newThread->Start(); - - // return the thread number to the script - gameLocal.program.ReturnFloat( newThread->GetThreadNum() ); - PopParms( st->b->value.argSize ); - break; - - case OP_OBJTHREAD: - var_a = GetVariable( st->a ); - obj = GetScriptObject( *var_a.entityNumberPtr ); - if ( obj ) { - func = obj->GetTypeDef()->GetFunction( st->b->value.virtualFunction ); - assert( st->c->value.argSize == func->parmTotal ); - newThread = new idThread( this, GetEntity( *var_a.entityNumberPtr ), func, func->parmTotal ); - newThread->Start(); - - // return the thread number to the script - gameLocal.program.ReturnFloat( newThread->GetThreadNum() ); - } else { - // return a null thread to the script - gameLocal.program.ReturnFloat( 0.0f ); - } - PopParms( st->c->value.argSize ); - break; - - case OP_CALL: - EnterFunction( st->a->value.functionPtr, false ); - break; - - case OP_EVENTCALL: - CallEvent( st->a->value.functionPtr, st->b->value.argSize ); - break; - - case OP_OBJECTCALL: - var_a = GetVariable( st->a ); - obj = GetScriptObject( *var_a.entityNumberPtr ); - if ( obj ) { - func = obj->GetTypeDef()->GetFunction( st->b->value.virtualFunction ); - EnterFunction( func, false ); - } else { - // return a 'safe' value - gameLocal.program.ReturnVector( vec3_zero ); - gameLocal.program.ReturnString( "" ); - PopParms( st->c->value.argSize ); - } - break; - - case OP_SYSCALL: - CallSysEvent( st->a->value.functionPtr, st->b->value.argSize ); - break; - - case OP_IFNOT: - var_a = GetVariable( st->a ); - if ( *var_a.intPtr == 0 ) { - NextInstruction( instructionPointer + st->b->value.jumpOffset ); - } - break; - - case OP_IF: - var_a = GetVariable( st->a ); - if ( *var_a.intPtr != 0 ) { - NextInstruction( instructionPointer + st->b->value.jumpOffset ); - } - break; - - case OP_GOTO: - NextInstruction( instructionPointer + st->a->value.jumpOffset ); - break; - - case OP_ADD_F: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - var_c = GetVariable( st->c ); - *var_c.floatPtr = *var_a.floatPtr + *var_b.floatPtr; - break; - - case OP_ADD_V: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - var_c = GetVariable( st->c ); - *var_c.vectorPtr = *var_a.vectorPtr + *var_b.vectorPtr; - break; - - case OP_ADD_S: - SetString( st->c, GetString( st->a ) ); - AppendString( st->c, GetString( st->b ) ); - break; - - case OP_ADD_FS: - var_a = GetVariable( st->a ); - SetString( st->c, FloatToString( *var_a.floatPtr ) ); - AppendString( st->c, GetString( st->b ) ); - break; - - case OP_ADD_SF: - var_b = GetVariable( st->b ); - SetString( st->c, GetString( st->a ) ); - AppendString( st->c, FloatToString( *var_b.floatPtr ) ); - break; - - case OP_ADD_VS: - var_a = GetVariable( st->a ); - SetString( st->c, var_a.vectorPtr->ToString() ); - AppendString( st->c, GetString( st->b ) ); - break; - - case OP_ADD_SV: - var_b = GetVariable( st->b ); - SetString( st->c, GetString( st->a ) ); - AppendString( st->c, var_b.vectorPtr->ToString() ); - break; - - case OP_SUB_F: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - var_c = GetVariable( st->c ); - *var_c.floatPtr = *var_a.floatPtr - *var_b.floatPtr; - break; - - case OP_SUB_V: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - var_c = GetVariable( st->c ); - *var_c.vectorPtr = *var_a.vectorPtr - *var_b.vectorPtr; - break; - - case OP_MUL_F: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - var_c = GetVariable( st->c ); - *var_c.floatPtr = *var_a.floatPtr * *var_b.floatPtr; - break; - - case OP_MUL_V: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - var_c = GetVariable( st->c ); - *var_c.floatPtr = *var_a.vectorPtr * *var_b.vectorPtr; - break; - - case OP_MUL_FV: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - var_c = GetVariable( st->c ); - *var_c.vectorPtr = *var_a.floatPtr * *var_b.vectorPtr; - break; - - case OP_MUL_VF: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - var_c = GetVariable( st->c ); - *var_c.vectorPtr = *var_a.vectorPtr * *var_b.floatPtr; - break; - - case OP_DIV_F: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - var_c = GetVariable( st->c ); - - if ( *var_b.floatPtr == 0.0f ) { - Warning( "Divide by zero" ); - *var_c.floatPtr = idMath::INFINITY; - } else { - *var_c.floatPtr = *var_a.floatPtr / *var_b.floatPtr; - } - break; - - case OP_MOD_F: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - var_c = GetVariable ( st->c ); - - if ( *var_b.floatPtr == 0.0f ) { - Warning( "Divide by zero" ); - *var_c.floatPtr = *var_a.floatPtr; - } else { - *var_c.floatPtr = static_cast( *var_a.floatPtr ) % static_cast( *var_b.floatPtr ); - } - break; - - case OP_BITAND: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - var_c = GetVariable( st->c ); - *var_c.floatPtr = static_cast( *var_a.floatPtr ) & static_cast( *var_b.floatPtr ); - break; - - case OP_BITOR: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - var_c = GetVariable( st->c ); - *var_c.floatPtr = static_cast( *var_a.floatPtr ) | static_cast( *var_b.floatPtr ); - break; - - case OP_GE: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - var_c = GetVariable( st->c ); - *var_c.floatPtr = ( *var_a.floatPtr >= *var_b.floatPtr ); - break; - - case OP_LE: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - var_c = GetVariable( st->c ); - *var_c.floatPtr = ( *var_a.floatPtr <= *var_b.floatPtr ); - break; - - case OP_GT: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - var_c = GetVariable( st->c ); - *var_c.floatPtr = ( *var_a.floatPtr > *var_b.floatPtr ); - break; - - case OP_LT: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - var_c = GetVariable( st->c ); - *var_c.floatPtr = ( *var_a.floatPtr < *var_b.floatPtr ); - break; - - case OP_AND: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - var_c = GetVariable( st->c ); - *var_c.floatPtr = ( *var_a.floatPtr != 0.0f ) && ( *var_b.floatPtr != 0.0f ); - break; - - case OP_AND_BOOLF: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - var_c = GetVariable( st->c ); - *var_c.floatPtr = ( *var_a.intPtr != 0 ) && ( *var_b.floatPtr != 0.0f ); - break; - - case OP_AND_FBOOL: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - var_c = GetVariable( st->c ); - *var_c.floatPtr = ( *var_a.floatPtr != 0.0f ) && ( *var_b.intPtr != 0 ); - break; - - case OP_AND_BOOLBOOL: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - var_c = GetVariable( st->c ); - *var_c.floatPtr = ( *var_a.intPtr != 0 ) && ( *var_b.intPtr != 0 ); - break; - - case OP_OR: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - var_c = GetVariable( st->c ); - *var_c.floatPtr = ( *var_a.floatPtr != 0.0f ) || ( *var_b.floatPtr != 0.0f ); - break; - - case OP_OR_BOOLF: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - var_c = GetVariable( st->c ); - *var_c.floatPtr = ( *var_a.intPtr != 0 ) || ( *var_b.floatPtr != 0.0f ); - break; - - case OP_OR_FBOOL: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - var_c = GetVariable( st->c ); - *var_c.floatPtr = ( *var_a.floatPtr != 0.0f ) || ( *var_b.intPtr != 0 ); - break; - - case OP_OR_BOOLBOOL: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - var_c = GetVariable( st->c ); - *var_c.floatPtr = ( *var_a.intPtr != 0 ) || ( *var_b.intPtr != 0 ); - break; - - case OP_NOT_BOOL: - var_a = GetVariable( st->a ); - var_c = GetVariable( st->c ); - *var_c.floatPtr = ( *var_a.intPtr == 0 ); - break; - - case OP_NOT_F: - var_a = GetVariable( st->a ); - var_c = GetVariable( st->c ); - *var_c.floatPtr = ( *var_a.floatPtr == 0.0f ); - break; - - case OP_NOT_V: - var_a = GetVariable( st->a ); - var_c = GetVariable( st->c ); - *var_c.floatPtr = ( *var_a.vectorPtr == vec3_zero ); - break; - - case OP_NOT_S: - var_c = GetVariable( st->c ); - *var_c.floatPtr = ( strlen( GetString( st->a ) ) == 0 ); - break; - - case OP_NOT_ENT: - var_a = GetVariable( st->a ); - var_c = GetVariable( st->c ); - *var_c.floatPtr = ( GetEntity( *var_a.entityNumberPtr ) == NULL ); - break; - - case OP_NEG_F: - var_a = GetVariable( st->a ); - var_c = GetVariable( st->c ); - *var_c.floatPtr = -*var_a.floatPtr; - break; - - case OP_NEG_V: - var_a = GetVariable( st->a ); - var_c = GetVariable( st->c ); - *var_c.vectorPtr = -*var_a.vectorPtr; - break; - - case OP_INT_F: - var_a = GetVariable( st->a ); - var_c = GetVariable( st->c ); - *var_c.floatPtr = static_cast( *var_a.floatPtr ); - break; - - case OP_EQ_F: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - var_c = GetVariable( st->c ); - *var_c.floatPtr = ( *var_a.floatPtr == *var_b.floatPtr ); - break; - - case OP_EQ_V: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - var_c = GetVariable( st->c ); - *var_c.floatPtr = ( *var_a.vectorPtr == *var_b.vectorPtr ); - break; - - case OP_EQ_S: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - var_c = GetVariable( st->c ); - *var_c.floatPtr = ( idStr::Cmp( GetString( st->a ), GetString( st->b ) ) == 0 ); - break; - - case OP_EQ_E: - case OP_EQ_EO: - case OP_EQ_OE: - case OP_EQ_OO: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - var_c = GetVariable( st->c ); - *var_c.floatPtr = ( *var_a.entityNumberPtr == *var_b.entityNumberPtr ); - break; - - case OP_NE_F: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - var_c = GetVariable( st->c ); - *var_c.floatPtr = ( *var_a.floatPtr != *var_b.floatPtr ); - break; - - case OP_NE_V: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - var_c = GetVariable( st->c ); - *var_c.floatPtr = ( *var_a.vectorPtr != *var_b.vectorPtr ); - break; - - case OP_NE_S: - var_c = GetVariable( st->c ); - *var_c.floatPtr = ( idStr::Cmp( GetString( st->a ), GetString( st->b ) ) != 0 ); - break; - - case OP_NE_E: - case OP_NE_EO: - case OP_NE_OE: - case OP_NE_OO: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - var_c = GetVariable( st->c ); - *var_c.floatPtr = ( *var_a.entityNumberPtr != *var_b.entityNumberPtr ); - break; - - case OP_UADD_F: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - *var_b.floatPtr += *var_a.floatPtr; - break; - - case OP_UADD_V: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - *var_b.vectorPtr += *var_a.vectorPtr; - break; - - case OP_USUB_F: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - *var_b.floatPtr -= *var_a.floatPtr; - break; - - case OP_USUB_V: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - *var_b.vectorPtr -= *var_a.vectorPtr; - break; - - case OP_UMUL_F: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - *var_b.floatPtr *= *var_a.floatPtr; - break; - - case OP_UMUL_V: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - *var_b.vectorPtr *= *var_a.floatPtr; - break; - - case OP_UDIV_F: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - - if ( *var_a.floatPtr == 0.0f ) { - Warning( "Divide by zero" ); - *var_b.floatPtr = idMath::INFINITY; - } else { - *var_b.floatPtr = *var_b.floatPtr / *var_a.floatPtr; - } - break; - - case OP_UDIV_V: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - - if ( *var_a.floatPtr == 0.0f ) { - Warning( "Divide by zero" ); - var_b.vectorPtr->Set( idMath::INFINITY, idMath::INFINITY, idMath::INFINITY ); - } else { - *var_b.vectorPtr = *var_b.vectorPtr / *var_a.floatPtr; - } - break; - - case OP_UMOD_F: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - - if ( *var_a.floatPtr == 0.0f ) { - Warning( "Divide by zero" ); - *var_b.floatPtr = *var_a.floatPtr; - } else { - *var_b.floatPtr = static_cast( *var_b.floatPtr ) % static_cast( *var_a.floatPtr ); - } - break; - - case OP_UOR_F: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - *var_b.floatPtr = static_cast( *var_b.floatPtr ) | static_cast( *var_a.floatPtr ); - break; - - case OP_UAND_F: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - *var_b.floatPtr = static_cast( *var_b.floatPtr ) & static_cast( *var_a.floatPtr ); - break; - - case OP_UINC_F: - var_a = GetVariable( st->a ); - ( *var_a.floatPtr )++; - break; - - case OP_UINCP_F: - var_a = GetVariable( st->a ); - obj = GetScriptObject( *var_a.entityNumberPtr ); - if ( obj ) { - var.bytePtr = &obj->data[ st->b->value.ptrOffset ]; - ( *var.floatPtr )++; - } - break; - - case OP_UDEC_F: - var_a = GetVariable( st->a ); - ( *var_a.floatPtr )--; - break; - - case OP_UDECP_F: - var_a = GetVariable( st->a ); - obj = GetScriptObject( *var_a.entityNumberPtr ); - if ( obj ) { - var.bytePtr = &obj->data[ st->b->value.ptrOffset ]; - ( *var.floatPtr )--; - } - break; - - case OP_COMP_F: - var_a = GetVariable( st->a ); - var_c = GetVariable( st->c ); - *var_c.floatPtr = ~static_cast( *var_a.floatPtr ); - break; - - case OP_STORE_F: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - *var_b.floatPtr = *var_a.floatPtr; - break; - - case OP_STORE_ENT: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - *var_b.entityNumberPtr = *var_a.entityNumberPtr; - break; - - case OP_STORE_BOOL: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - *var_b.intPtr = *var_a.intPtr; - break; - - case OP_STORE_OBJENT: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - obj = GetScriptObject( *var_a.entityNumberPtr ); - if ( !obj ) { - *var_b.entityNumberPtr = 0; - } else if ( !obj->GetTypeDef()->Inherits( st->b->TypeDef() ) ) { - //Warning( "object '%s' cannot be converted to '%s'", obj->GetTypeName(), st->b->TypeDef()->Name() ); - *var_b.entityNumberPtr = 0; - } else { - *var_b.entityNumberPtr = *var_a.entityNumberPtr; - } - break; - - case OP_STORE_OBJ: - case OP_STORE_ENTOBJ: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - *var_b.entityNumberPtr = *var_a.entityNumberPtr; - break; - - case OP_STORE_S: - SetString( st->b, GetString( st->a ) ); - break; - - case OP_STORE_V: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - *var_b.vectorPtr = *var_a.vectorPtr; - break; - - case OP_STORE_FTOS: - var_a = GetVariable( st->a ); - SetString( st->b, FloatToString( *var_a.floatPtr ) ); - break; - - case OP_STORE_BTOS: - var_a = GetVariable( st->a ); - SetString( st->b, *var_a.intPtr ? "true" : "false" ); - break; - - case OP_STORE_VTOS: - var_a = GetVariable( st->a ); - SetString( st->b, var_a.vectorPtr->ToString() ); - break; - - case OP_STORE_FTOBOOL: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - if ( *var_a.floatPtr != 0.0f ) { - *var_b.intPtr = 1; - } else { - *var_b.intPtr = 0; - } - break; - - case OP_STORE_BOOLTOF: - var_a = GetVariable( st->a ); - var_b = GetVariable( st->b ); - *var_b.floatPtr = static_cast( *var_a.intPtr ); - break; - - case OP_STOREP_F: - var_b = GetVariable( st->b ); - if ( var_b.evalPtr && var_b.evalPtr->floatPtr ) { - var_a = GetVariable( st->a ); - *var_b.evalPtr->floatPtr = *var_a.floatPtr; - } - break; - - case OP_STOREP_ENT: - var_b = GetVariable( st->b ); - if ( var_b.evalPtr && var_b.evalPtr->entityNumberPtr ) { - var_a = GetVariable( st->a ); - *var_b.evalPtr->entityNumberPtr = *var_a.entityNumberPtr; - } - break; - - case OP_STOREP_FLD: - var_b = GetVariable( st->b ); - if ( var_b.evalPtr && var_b.evalPtr->intPtr ) { - var_a = GetVariable( st->a ); - *var_b.evalPtr->intPtr = *var_a.intPtr; - } - break; - - case OP_STOREP_BOOL: - var_b = GetVariable( st->b ); - if ( var_b.evalPtr && var_b.evalPtr->intPtr ) { - var_a = GetVariable( st->a ); - *var_b.evalPtr->intPtr = *var_a.intPtr; - } - break; - - case OP_STOREP_S: - var_b = GetVariable( st->b ); - if ( var_b.evalPtr && var_b.evalPtr->stringPtr ) { - idStr::Copynz( var_b.evalPtr->stringPtr, GetString( st->a ), MAX_STRING_LEN ); - } - break; - - case OP_STOREP_V: - var_b = GetVariable( st->b ); - if ( var_b.evalPtr && var_b.evalPtr->vectorPtr ) { - var_a = GetVariable( st->a ); - *var_b.evalPtr->vectorPtr = *var_a.vectorPtr; - } - break; - - case OP_STOREP_FTOS: - var_b = GetVariable( st->b ); - if ( var_b.evalPtr && var_b.evalPtr->stringPtr ) { - var_a = GetVariable( st->a ); - idStr::Copynz( var_b.evalPtr->stringPtr, FloatToString( *var_a.floatPtr ), MAX_STRING_LEN ); - } - break; - - case OP_STOREP_BTOS: - var_b = GetVariable( st->b ); - if ( var_b.evalPtr && var_b.evalPtr->stringPtr ) { - var_a = GetVariable( st->a ); - if ( *var_a.floatPtr != 0.0f ) { - idStr::Copynz( var_b.evalPtr->stringPtr, "true", MAX_STRING_LEN ); - } else { - idStr::Copynz( var_b.evalPtr->stringPtr, "false", MAX_STRING_LEN ); - } - } - break; - - case OP_STOREP_VTOS: - var_b = GetVariable( st->b ); - if ( var_b.evalPtr && var_b.evalPtr->stringPtr ) { - var_a = GetVariable( st->a ); - idStr::Copynz( var_b.evalPtr->stringPtr, var_a.vectorPtr->ToString(), MAX_STRING_LEN ); - } - break; - - case OP_STOREP_FTOBOOL: - var_b = GetVariable( st->b ); - if ( var_b.evalPtr && var_b.evalPtr->intPtr ) { - var_a = GetVariable( st->a ); - if ( *var_a.floatPtr != 0.0f ) { - *var_b.evalPtr->intPtr = 1; - } else { - *var_b.evalPtr->intPtr = 0; - } - } - break; - - case OP_STOREP_BOOLTOF: - var_b = GetVariable( st->b ); - if ( var_b.evalPtr && var_b.evalPtr->floatPtr ) { - var_a = GetVariable( st->a ); - *var_b.evalPtr->floatPtr = static_cast( *var_a.intPtr ); - } - break; - - case OP_STOREP_OBJ: - var_b = GetVariable( st->b ); - if ( var_b.evalPtr && var_b.evalPtr->entityNumberPtr ) { - var_a = GetVariable( st->a ); - *var_b.evalPtr->entityNumberPtr = *var_a.entityNumberPtr; - } - break; - - case OP_STOREP_OBJENT: - var_b = GetVariable( st->b ); - if ( var_b.evalPtr && var_b.evalPtr->entityNumberPtr ) { - var_a = GetVariable( st->a ); - obj = GetScriptObject( *var_a.entityNumberPtr ); - if ( !obj ) { - *var_b.evalPtr->entityNumberPtr = 0; - - // st->b points to type_pointer, which is just a temporary that gets its type reassigned, so we store the real type in st->c - // so that we can do a type check during run time since we don't know what type the script object is at compile time because it - // comes from an entity - } else if ( !obj->GetTypeDef()->Inherits( st->c->TypeDef() ) ) { - //Warning( "object '%s' cannot be converted to '%s'", obj->GetTypeName(), st->c->TypeDef()->Name() ); - *var_b.evalPtr->entityNumberPtr = 0; - } else { - *var_b.evalPtr->entityNumberPtr = *var_a.entityNumberPtr; - } - } - break; - - case OP_ADDRESS: - var_a = GetVariable( st->a ); - var_c = GetVariable( st->c ); - obj = GetScriptObject( *var_a.entityNumberPtr ); - if ( obj ) { - var_c.evalPtr->bytePtr = &obj->data[ st->b->value.ptrOffset ]; - } else { - var_c.evalPtr->bytePtr = NULL; - } - break; - - case OP_INDIRECT_F: - var_a = GetVariable( st->a ); - var_c = GetVariable( st->c ); - obj = GetScriptObject( *var_a.entityNumberPtr ); - if ( obj ) { - var.bytePtr = &obj->data[ st->b->value.ptrOffset ]; - *var_c.floatPtr = *var.floatPtr; - } else { - *var_c.floatPtr = 0.0f; - } - break; - - case OP_INDIRECT_ENT: - var_a = GetVariable( st->a ); - var_c = GetVariable( st->c ); - obj = GetScriptObject( *var_a.entityNumberPtr ); - if ( obj ) { - var.bytePtr = &obj->data[ st->b->value.ptrOffset ]; - *var_c.entityNumberPtr = *var.entityNumberPtr; - } else { - *var_c.entityNumberPtr = 0; - } - break; - - case OP_INDIRECT_BOOL: - var_a = GetVariable( st->a ); - var_c = GetVariable( st->c ); - obj = GetScriptObject( *var_a.entityNumberPtr ); - if ( obj ) { - var.bytePtr = &obj->data[ st->b->value.ptrOffset ]; - *var_c.intPtr = *var.intPtr; - } else { - *var_c.intPtr = 0; - } - break; - - case OP_INDIRECT_S: - var_a = GetVariable( st->a ); - obj = GetScriptObject( *var_a.entityNumberPtr ); - if ( obj ) { - var.bytePtr = &obj->data[ st->b->value.ptrOffset ]; - SetString( st->c, var.stringPtr ); - } else { - SetString( st->c, "" ); - } - break; - - case OP_INDIRECT_V: - var_a = GetVariable( st->a ); - var_c = GetVariable( st->c ); - obj = GetScriptObject( *var_a.entityNumberPtr ); - if ( obj ) { - var.bytePtr = &obj->data[ st->b->value.ptrOffset ]; - *var_c.vectorPtr = *var.vectorPtr; - } else { - var_c.vectorPtr->Zero(); - } - break; - - case OP_INDIRECT_OBJ: - var_a = GetVariable( st->a ); - var_c = GetVariable( st->c ); - obj = GetScriptObject( *var_a.entityNumberPtr ); - if ( !obj ) { - *var_c.entityNumberPtr = 0; - } else { - var.bytePtr = &obj->data[ st->b->value.ptrOffset ]; - *var_c.entityNumberPtr = *var.entityNumberPtr; - } - break; - - case OP_PUSH_F: - var_a = GetVariable( st->a ); - Push( *var_a.intPtr ); - break; - - case OP_PUSH_FTOS: - var_a = GetVariable( st->a ); - PushString( FloatToString( *var_a.floatPtr ) ); - break; - - case OP_PUSH_BTOF: - var_a = GetVariable( st->a ); - floatVal = *var_a.intPtr; - Push( *reinterpret_cast( &floatVal ) ); - break; - - case OP_PUSH_FTOB: - var_a = GetVariable( st->a ); - if ( *var_a.floatPtr != 0.0f ) { - Push( 1 ); - } else { - Push( 0 ); - } - break; - - case OP_PUSH_VTOS: - var_a = GetVariable( st->a ); - PushString( var_a.vectorPtr->ToString() ); - break; - - case OP_PUSH_BTOS: - var_a = GetVariable( st->a ); - PushString( *var_a.intPtr ? "true" : "false" ); - break; - - case OP_PUSH_ENT: - var_a = GetVariable( st->a ); - Push( *var_a.entityNumberPtr ); - break; - - case OP_PUSH_S: - PushString( GetString( st->a ) ); - break; - - case OP_PUSH_V: - var_a = GetVariable( st->a ); - PushVector(*var_a.vectorPtr); - break; - - case OP_PUSH_OBJ: - var_a = GetVariable( st->a ); - Push( *var_a.entityNumberPtr ); - break; - - case OP_PUSH_OBJENT: - var_a = GetVariable( st->a ); - Push( *var_a.entityNumberPtr ); - break; - - case OP_BREAK: - case OP_CONTINUE: - default: - Error( "Bad opcode %i", st->op ); - break; - } - } - - return threadDying; -} diff --git a/d3xp/script/Script_Interpreter.h b/d3xp/script/Script_Interpreter.h deleted file mode 100644 index e7ec0f64..00000000 --- a/d3xp/script/Script_Interpreter.h +++ /dev/null @@ -1,291 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __SCRIPT_INTERPRETER_H__ -#define __SCRIPT_INTERPRETER_H__ - -#include "script/Script_Program.h" -#include "Entity.h" -#include "Game_local.h" - -class idThread; - -#define MAX_STACK_DEPTH 64 -#define LOCALSTACK_SIZE (6144 * 2) - -typedef struct prstack_s { - int s; - const function_t *f; - int stackbase; -} prstack_t; - -class idInterpreter { -private: - prstack_t callStack[ MAX_STACK_DEPTH ]; - int callStackDepth; - int maxStackDepth; - - byte localstack[ LOCALSTACK_SIZE ]; - int localstackUsed; - int localstackBase; - int maxLocalstackUsed; - - const function_t *currentFunction; - int instructionPointer; - - int popParms; - const idEventDef *multiFrameEvent; - idEntity *eventEntity; - - idThread *thread; - - void PopParms( int numParms ); - void PushString( const char *string ); - void PushVector( const idVec3 &vector ); - void Push( intptr_t value ); - const char *FloatToString( float value ); - void AppendString( idVarDef *def, const char *from ); - void SetString( idVarDef *def, const char *from ); - const char *GetString( idVarDef *def ); - varEval_t GetVariable( idVarDef *def ); - idEntity *GetEntity( int entnum ) const; - idScriptObject *GetScriptObject( int entnum ) const; - void NextInstruction( int position ); - - void LeaveFunction( idVarDef *returnDef ); - void CallEvent( const function_t *func, int argsize ); - void CallSysEvent( const function_t *func, int argsize ); - -public: - bool doneProcessing; - bool threadDying; - bool terminateOnExit; - bool debug; - - idInterpreter(); - - // save games - void Save( idSaveGame *savefile ) const; // archives object for save game file - void Restore( idRestoreGame *savefile ); // unarchives object from save game file - - void SetThread( idThread *pThread ); - - void StackTrace( void ) const; - - int CurrentLine( void ) const; - const char *CurrentFile( void ) const; - - void Error( const char *fmt, ... ) const id_attribute((format(printf,2,3))); - void Warning( const char *fmt, ... ) const id_attribute((format(printf,2,3))); - void DisplayInfo( void ) const; - - bool BeginMultiFrameEvent( idEntity *ent, const idEventDef *event ); - void EndMultiFrameEvent( idEntity *ent, const idEventDef *event ); - bool MultiFrameEventInProgress( void ) const; - - void ThreadCall( idInterpreter *source, const function_t *func, int args ); - void EnterFunction( const function_t *func, bool clearStack ); - void EnterObjectFunction( idEntity *self, const function_t *func, bool clearStack ); - - bool Execute( void ); - void Reset( void ); - - bool GetRegisterValue( const char *name, idStr &out, int scopeDepth ); - int GetCallstackDepth( void ) const; - const prstack_t *GetCallstack( void ) const; - const function_t *GetCurrentFunction( void ) const; - idThread *GetThread( void ) const; - -}; - -/* -==================== -idInterpreter::PopParms -==================== -*/ -ID_INLINE void idInterpreter::PopParms( int numParms ) { - // pop our parms off the stack - if ( localstackUsed < numParms ) { - Error( "locals stack underflow\n" ); - } - - localstackUsed -= numParms; -} - -/* -==================== -idInterpreter::Push -==================== -*/ -ID_INLINE void idInterpreter::Push( intptr_t value ) { - if ( localstackUsed + sizeof( intptr_t ) > LOCALSTACK_SIZE ) { - Error( "Push: locals stack overflow\n" ); - } - *( intptr_t * )&localstack[ localstackUsed ] = value; - localstackUsed += sizeof( intptr_t ); -} - -/* -==================== -idInterpreter::PushVector -==================== -*/ -ID_INLINE void idInterpreter::PushVector( const idVec3 &vector ) { - if ( localstackUsed + E_EVENT_SIZEOF_VEC > LOCALSTACK_SIZE ) { - Error( "Push: locals stack overflow\n" ); - } - *( idVec3 * )&localstack[ localstackUsed ] = vector; - localstackUsed += E_EVENT_SIZEOF_VEC; -} - -/* -==================== -idInterpreter::PushString -==================== -*/ -ID_INLINE void idInterpreter::PushString( const char *string ) { - if ( localstackUsed + MAX_STRING_LEN > LOCALSTACK_SIZE ) { - Error( "PushString: locals stack overflow\n" ); - } - idStr::Copynz( ( char * )&localstack[ localstackUsed ], string, MAX_STRING_LEN ); - localstackUsed += MAX_STRING_LEN; -} - -/* -==================== -idInterpreter::FloatToString -==================== -*/ -ID_INLINE const char *idInterpreter::FloatToString( float value ) { - static char text[ 32 ]; - - if ( value == ( float )( int )value ) { - sprintf( text, "%d", ( int )value ); - } else { - sprintf( text, "%f", value ); - } - return text; -} - -/* -==================== -idInterpreter::AppendString -==================== -*/ -ID_INLINE void idInterpreter::AppendString( idVarDef *def, const char *from ) { - if ( def->initialized == idVarDef::stackVariable ) { - idStr::Append( ( char * )&localstack[ localstackBase + def->value.stackOffset ], MAX_STRING_LEN, from ); - } else { - idStr::Append( def->value.stringPtr, MAX_STRING_LEN, from ); - } -} - -/* -==================== -idInterpreter::SetString -==================== -*/ -ID_INLINE void idInterpreter::SetString( idVarDef *def, const char *from ) { - if ( def->initialized == idVarDef::stackVariable ) { - idStr::Copynz( ( char * )&localstack[ localstackBase + def->value.stackOffset ], from, MAX_STRING_LEN ); - } else { - idStr::Copynz( def->value.stringPtr, from, MAX_STRING_LEN ); - } -} - -/* -==================== -idInterpreter::GetString -==================== -*/ -ID_INLINE const char *idInterpreter::GetString( idVarDef *def ) { - if ( def->initialized == idVarDef::stackVariable ) { - return ( char * )&localstack[ localstackBase + def->value.stackOffset ]; - } else { - return def->value.stringPtr; - } -} - -/* -==================== -idInterpreter::GetVariable -==================== -*/ -ID_INLINE varEval_t idInterpreter::GetVariable( idVarDef *def ) { - if ( def->initialized == idVarDef::stackVariable ) { - varEval_t val; - val.intPtr = ( int * )&localstack[ localstackBase + def->value.stackOffset ]; - return val; - } else { - return def->value; - } -} - -/* -================ -idInterpreter::GetEntity -================ -*/ -ID_INLINE idEntity *idInterpreter::GetEntity( int entnum ) const{ - assert( entnum <= MAX_GENTITIES ); - if ( ( entnum > 0 ) && ( entnum <= MAX_GENTITIES ) ) { - return gameLocal.entities[ entnum - 1 ]; - } - return NULL; -} - -/* -================ -idInterpreter::GetScriptObject -================ -*/ -ID_INLINE idScriptObject *idInterpreter::GetScriptObject( int entnum ) const { - idEntity *ent; - - assert( entnum <= MAX_GENTITIES ); - if ( ( entnum > 0 ) && ( entnum <= MAX_GENTITIES ) ) { - ent = gameLocal.entities[ entnum - 1 ]; - if ( ent && ent->scriptObject.data ) { - return &ent->scriptObject; - } - } - return NULL; -} - -/* -==================== -idInterpreter::NextInstruction -==================== -*/ -ID_INLINE void idInterpreter::NextInstruction( int position ) { - // Before we execute an instruction, we increment instructionPointer, - // therefore we need to compensate for that here. - instructionPointer = position - 1; -} - -#endif /* !__SCRIPT_INTERPRETER_H__ */ diff --git a/d3xp/script/Script_Program.cpp b/d3xp/script/Script_Program.cpp deleted file mode 100644 index adbbb19d..00000000 --- a/d3xp/script/Script_Program.cpp +++ /dev/null @@ -1,2223 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "idlib/hashing/MD4.h" -#include "framework/FileSystem.h" - -#include "gamesys/Event.h" -#include "gamesys/SysCvar.h" -#include "script/Script_Compiler.h" -#include "script/Script_Thread.h" -#include "Entity.h" -#include "Game_local.h" - -#include "script/Script_Program.h" - -// simple types. function types are dynamically allocated -idTypeDef type_void( ev_void, &def_void, "void", 0, NULL ); -idTypeDef type_scriptevent( ev_scriptevent, &def_scriptevent, "scriptevent", sizeof( intptr_t ), NULL ); -idTypeDef type_namespace( ev_namespace, &def_namespace, "namespace", sizeof( intptr_t ), NULL ); -idTypeDef type_string( ev_string, &def_string, "string", MAX_STRING_LEN, NULL ); -idTypeDef type_float( ev_float, &def_float, "float", sizeof( intptr_t ), NULL ); -idTypeDef type_vector( ev_vector, &def_vector, "vector", E_EVENT_SIZEOF_VEC, NULL ); -idTypeDef type_entity( ev_entity, &def_entity, "entity", sizeof( intptr_t ), NULL ); // stored as entity number pointer -idTypeDef type_field( ev_field, &def_field, "field", sizeof( intptr_t ), NULL ); -idTypeDef type_function( ev_function, &def_function, "function", sizeof( intptr_t ), &type_void ); -idTypeDef type_virtualfunction( ev_virtualfunction, &def_virtualfunction, "virtual function", sizeof( intptr_t ), NULL ); -idTypeDef type_pointer( ev_pointer, &def_pointer, "pointer", sizeof( intptr_t ), NULL ); -idTypeDef type_object( ev_object, &def_object, "object", sizeof( intptr_t ), NULL ); // stored as entity number pointer -idTypeDef type_jumpoffset( ev_jumpoffset, &def_jumpoffset, "", sizeof( intptr_t ), NULL ); // only used for jump opcodes -idTypeDef type_argsize( ev_argsize, &def_argsize, "", sizeof( intptr_t ), NULL ); // only used for function call and thread opcodes -idTypeDef type_boolean( ev_boolean, &def_boolean, "boolean", sizeof( intptr_t ), NULL ); - -idVarDef def_void( &type_void ); -idVarDef def_scriptevent( &type_scriptevent ); -idVarDef def_namespace( &type_namespace ); -idVarDef def_string( &type_string ); -idVarDef def_float( &type_float ); -idVarDef def_vector( &type_vector ); -idVarDef def_entity( &type_entity ); -idVarDef def_field( &type_field ); -idVarDef def_function( &type_function ); -idVarDef def_virtualfunction( &type_virtualfunction ); -idVarDef def_pointer( &type_pointer ); -idVarDef def_object( &type_object ); -idVarDef def_jumpoffset( &type_jumpoffset ); // only used for jump opcodes -idVarDef def_argsize( &type_argsize ); -idVarDef def_boolean( &type_boolean ); - -/*********************************************************************** - - function_t - -***********************************************************************/ - -/* -================ -function_t::function_t -================ -*/ -function_t::function_t() { - Clear(); -} - -/* -================ -function_t::Allocated -================ -*/ -size_t function_t::Allocated( void ) const { - return name.Allocated() + parmSize.Allocated(); -} - -/* -================ -function_t::SetName -================ -*/ -void function_t::SetName( const char *name ) { - this->name = name; -} - -/* -================ -function_t::Name -================ -*/ -const char *function_t::Name( void ) const { - return name; -} - -/* -================ -function_t::Clear -================ -*/ -void function_t::Clear( void ) { - eventdef = NULL; - def = NULL; - type = NULL; - firstStatement = 0; - numStatements = 0; - parmTotal = 0; - locals = 0; - filenum = 0; - name.Clear(); - parmSize.Clear(); -} - -/*********************************************************************** - - idTypeDef - -***********************************************************************/ - -/* -================ -idTypeDef::idTypeDef -================ -*/ -idTypeDef::idTypeDef( etype_t etype, idVarDef *edef, const char *ename, int esize, idTypeDef *aux ) { - name = ename; - type = etype; - def = edef; - size = esize; - auxType = aux; - - parmTypes.SetGranularity( 1 ); - parmNames.SetGranularity( 1 ); - functions.SetGranularity( 1 ); -} - -/* -================ -idTypeDef::idTypeDef -================ -*/ -idTypeDef::idTypeDef( const idTypeDef &other ) { - *this = other; -} - -/* -================ -idTypeDef::operator= -================ -*/ -void idTypeDef::operator=( const idTypeDef& other ) { - type = other.type; - def = other.def; - name = other.name; - size = other.size; - auxType = other.auxType; - parmTypes = other.parmTypes; - parmNames = other.parmNames; - functions = other.functions; -} - -/* -================ -idTypeDef::Allocated -================ -*/ -size_t idTypeDef::Allocated( void ) const { - size_t memsize; - int i; - - memsize = name.Allocated() + parmTypes.Allocated() + parmNames.Allocated() + functions.Allocated(); - for( i = 0; i < parmTypes.Num(); i++ ) { - memsize += parmNames[ i ].Allocated(); - } - - return memsize; -} - -/* -================ -idTypeDef::Inherits - -Returns true if basetype is an ancestor of this type. -================ -*/ -bool idTypeDef::Inherits( const idTypeDef *basetype ) const { - idTypeDef *superType; - - if ( type != ev_object ) { - return false; - } - - if ( this == basetype ) { - return true; - } - for( superType = auxType; superType != NULL; superType = superType->auxType ) { - if ( superType == basetype ) { - return true; - } - } - - return false; -} - -/* -================ -idTypeDef::MatchesType - -Returns true if both types' base types and parameters match -================ -*/ -bool idTypeDef::MatchesType( const idTypeDef &matchtype ) const { - int i; - - if ( this == &matchtype ) { - return true; - } - - if ( ( type != matchtype.type ) || ( auxType != matchtype.auxType ) ) { - return false; - } - - if ( parmTypes.Num() != matchtype.parmTypes.Num() ) { - return false; - } - - for( i = 0; i < matchtype.parmTypes.Num(); i++ ) { - if ( parmTypes[ i ] != matchtype.parmTypes[ i ] ) { - return false; - } - } - - return true; -} - -/* -================ -idTypeDef::MatchesVirtualFunction - -Returns true if both functions' base types and parameters match -================ -*/ -bool idTypeDef::MatchesVirtualFunction( const idTypeDef &matchfunc ) const { - int i; - - if ( this == &matchfunc ) { - return true; - } - - if ( ( type != matchfunc.type ) || ( auxType != matchfunc.auxType ) ) { - return false; - } - - if ( parmTypes.Num() != matchfunc.parmTypes.Num() ) { - return false; - } - - if ( parmTypes.Num() > 0 ) { - if ( !parmTypes[ 0 ]->Inherits( matchfunc.parmTypes[ 0 ] ) ) { - return false; - } - } - - for( i = 1; i < matchfunc.parmTypes.Num(); i++ ) { - if ( parmTypes[ i ] != matchfunc.parmTypes[ i ] ) { - return false; - } - } - - return true; -} - -/* -================ -idTypeDef::AddFunctionParm - -Adds a new parameter for a function type. -================ -*/ -void idTypeDef::AddFunctionParm( idTypeDef *parmtype, const char *name ) { - if ( type != ev_function ) { - throw idCompileError( "idTypeDef::AddFunctionParm : tried to add parameter on non-function type" ); - } - - parmTypes.Append( parmtype ); - idStr &parmName = parmNames.Alloc(); - parmName = name; -} - -/* -================ -idTypeDef::AddField - -Adds a new field to an object type. -================ -*/ -void idTypeDef::AddField( idTypeDef *fieldtype, const char *name ) { - if ( type != ev_object ) { - throw idCompileError( "idTypeDef::AddField : tried to add field to non-object type" ); - } - - parmTypes.Append( fieldtype ); - idStr &parmName = parmNames.Alloc(); - parmName = name; - - if ( fieldtype->FieldType()->Inherits( &type_object ) ) { - size += type_object.Size(); - } else { - size += fieldtype->FieldType()->Size(); - } -} - -/* -================ -idTypeDef::SetName -================ -*/ -void idTypeDef::SetName( const char *newname ) { - name = newname; -} - -/* -================ -idTypeDef::Name -================ -*/ -const char *idTypeDef::Name( void ) const { - return name; -} - -/* -================ -idTypeDef::Type -================ -*/ -etype_t idTypeDef::Type( void ) const { - return type; -} - -/* -================ -idTypeDef::Size -================ -*/ -int idTypeDef::Size( void ) const { - return size; -} - -/* -================ -idTypeDef::SuperClass - -If type is an object, then returns the object's superclass -================ -*/ -idTypeDef *idTypeDef::SuperClass( void ) const { - if ( type != ev_object ) { - throw idCompileError( "idTypeDef::SuperClass : tried to get superclass of a non-object type" ); - } - - return auxType; -} - -/* -================ -idTypeDef::ReturnType - -If type is a function, then returns the function's return type -================ -*/ -idTypeDef *idTypeDef::ReturnType( void ) const { - if ( type != ev_function ) { - throw idCompileError( "idTypeDef::ReturnType: tried to get return type on non-function type" ); - } - - return auxType; -} - -/* -================ -idTypeDef::SetReturnType - -If type is a function, then sets the function's return type -================ -*/ -void idTypeDef::SetReturnType( idTypeDef *returntype ) { - if ( type != ev_function ) { - throw idCompileError( "idTypeDef::SetReturnType: tried to set return type on non-function type" ); - } - - auxType = returntype; -} - -/* -================ -idTypeDef::FieldType - -If type is a field, then returns it's type -================ -*/ -idTypeDef *idTypeDef::FieldType( void ) const { - if ( type != ev_field ) { - throw idCompileError( "idTypeDef::FieldType: tried to get field type on non-field type" ); - } - - return auxType; -} - -/* -================ -idTypeDef::SetFieldType - -If type is a field, then sets the function's return type -================ -*/ -void idTypeDef::SetFieldType( idTypeDef *fieldtype ) { - if ( type != ev_field ) { - throw idCompileError( "idTypeDef::SetFieldType: tried to set return type on non-function type" ); - } - - auxType = fieldtype; -} - -/* -================ -idTypeDef::PointerType - -If type is a pointer, then returns the type it points to -================ -*/ -idTypeDef *idTypeDef::PointerType( void ) const { - if ( type != ev_pointer ) { - throw idCompileError( "idTypeDef::PointerType: tried to get pointer type on non-pointer" ); - } - - return auxType; -} - -/* -================ -idTypeDef::SetPointerType - -If type is a pointer, then sets the pointer's type -================ -*/ -void idTypeDef::SetPointerType( idTypeDef *pointertype ) { - if ( type != ev_pointer ) { - throw idCompileError( "idTypeDef::SetPointerType: tried to set type on non-pointer" ); - } - - auxType = pointertype; -} - -/* -================ -idTypeDef::NumParameters -================ -*/ -int idTypeDef::NumParameters( void ) const { - return parmTypes.Num(); -} - -/* -================ -idTypeDef::GetParmType -================ -*/ -idTypeDef *idTypeDef::GetParmType( int parmNumber ) const { - assert( parmNumber >= 0 ); - assert( parmNumber < parmTypes.Num() ); - return parmTypes[ parmNumber ]; -} - -/* -================ -idTypeDef::GetParmName -================ -*/ -const char *idTypeDef::GetParmName( int parmNumber ) const { - assert( parmNumber >= 0 ); - assert( parmNumber < parmTypes.Num() ); - return parmNames[ parmNumber ]; -} - -/* -================ -idTypeDef::NumFunctions -================ -*/ -int idTypeDef::NumFunctions( void ) const { - return functions.Num(); -} - -/* -================ -idTypeDef::GetFunctionNumber -================ -*/ -int idTypeDef::GetFunctionNumber( const function_t *func ) const { - int i; - - for( i = 0; i < functions.Num(); i++ ) { - if ( functions[ i ] == func ) { - return i; - } - } - return -1; -} - -/* -================ -idTypeDef::GetFunction -================ -*/ -const function_t *idTypeDef::GetFunction( int funcNumber ) const { - assert( funcNumber >= 0 ); - assert( funcNumber < functions.Num() ); - return functions[ funcNumber ]; -} - -/* -================ -idTypeDef::AddFunction -================ -*/ -void idTypeDef::AddFunction( const function_t *func ) { - int i; - - for( i = 0; i < functions.Num(); i++ ) { - if ( !strcmp( functions[ i ]->def->Name(), func->def->Name() ) ) { - if ( func->def->TypeDef()->MatchesVirtualFunction( *functions[ i ]->def->TypeDef() ) ) { - functions[ i ] = func; - return; - } - } - } - functions.Append( func ); -} - -/*********************************************************************** - - idVarDef - -***********************************************************************/ - -/* -================ -idVarDef::idVarDef() -================ -*/ -idVarDef::idVarDef( idTypeDef *typeptr ) { - typeDef = typeptr; - num = 0; - scope = NULL; - numUsers = 0; - initialized = idVarDef::uninitialized; - memset( &value, 0, sizeof( value ) ); - name = NULL; - next = NULL; -} - -/* -============ -idVarDef::~idVarDef -============ -*/ -idVarDef::~idVarDef() { - if ( name ) { - name->RemoveDef( this ); - } -} - -/* -============ -idVarDef::Name -============ -*/ -const char *idVarDef::Name( void ) const { - return name->Name(); -} - -/* -============ -idVarDef::GlobalName -============ -*/ -const char *idVarDef::GlobalName( void ) const { - if ( scope != &def_namespace ) { - return va( "%s::%s", scope->GlobalName(), name->Name() ); - } else { - return name->Name(); - } -} - -/* -============ -idVarDef::DepthOfScope -============ -*/ -int idVarDef::DepthOfScope( const idVarDef *otherScope ) const { - const idVarDef *def; - int depth; - - depth = 1; - for( def = otherScope; def != NULL; def = def->scope ) { - if ( def == scope ) { - return depth; - } - depth++; - } - - return 0; -} - -/* -============ -idVarDef::SetFunction -============ -*/ -void idVarDef::SetFunction( function_t *func ) { - assert( typeDef ); - initialized = initializedConstant; - assert( typeDef->Type() == ev_function ); - value.functionPtr = func; -} - -/* -============ -idVarDef::SetObject -============ -*/ -void idVarDef::SetObject( idScriptObject *object ) { - assert( typeDef ); - initialized = initialized; - assert( typeDef->Inherits( &type_object ) ); - *value.objectPtrPtr = object; -} - -/* -============ -idVarDef::SetValue -============ -*/ -void idVarDef::SetValue( const eval_t &_value, bool constant ) { - assert( typeDef ); - if ( constant ) { - initialized = initializedConstant; - } else { - initialized = initializedVariable; - } - - switch( typeDef->Type() ) { - case ev_pointer : - case ev_boolean : - case ev_field : - *value.intPtr = _value._int; - break; - - case ev_jumpoffset : - value.jumpOffset = _value._int; - break; - - case ev_argsize : - value.argSize = _value._int; - break; - - case ev_entity : - *value.entityNumberPtr = _value.entity; - break; - - case ev_string : - idStr::Copynz( value.stringPtr, _value.stringPtr, MAX_STRING_LEN ); - break; - - case ev_float : - *value.floatPtr = _value._float; - break; - - case ev_vector : - value.vectorPtr->x = _value.vector[ 0 ]; - value.vectorPtr->y = _value.vector[ 1 ]; - value.vectorPtr->z = _value.vector[ 2 ]; - break; - - case ev_function : - value.functionPtr = _value.function; - break; - - case ev_virtualfunction : - value.virtualFunction = _value._int; - break; - - case ev_object : - *value.entityNumberPtr = _value.entity; - break; - - default : - throw idCompileError( va( "weird type on '%s'", Name() ) ); - break; - } -} - -/* -============ -idVarDef::SetString -============ -*/ -void idVarDef::SetString( const char *string, bool constant ) { - if ( constant ) { - initialized = initializedConstant; - } else { - initialized = initializedVariable; - } - - assert( typeDef && ( typeDef->Type() == ev_string ) ); - idStr::Copynz( value.stringPtr, string, MAX_STRING_LEN ); -} - -/* -============ -idVarDef::PrintInfo -============ -*/ -void idVarDef::PrintInfo( idFile *file, int instructionPointer ) const { - statement_t *jumpst; - int jumpto; - etype_t etype; - int i; - int len; - const char *ch; - - if ( initialized == initializedConstant ) { - file->Printf( "const " ); - } - - etype = typeDef->Type(); - switch( etype ) { - case ev_jumpoffset : - jumpto = instructionPointer + value.jumpOffset; - jumpst = &gameLocal.program.GetStatement( jumpto ); - file->Printf( "address %d [%s(%d)]", jumpto, gameLocal.program.GetFilename( jumpst->file ), jumpst->linenumber ); - break; - - case ev_function : - if ( value.functionPtr->eventdef ) { - file->Printf( "event %s", GlobalName() ); - } else { - file->Printf( "function %s", GlobalName() ); - } - break; - - case ev_field : - file->Printf( "field %d", value.ptrOffset ); - break; - - case ev_argsize: - file->Printf( "args %d", value.argSize ); - break; - - default: - file->Printf( "%s ", typeDef->Name() ); - if ( initialized == initializedConstant ) { - switch( etype ) { - case ev_string : - file->Printf( "\"" ); - len = strlen( value.stringPtr ); - ch = value.stringPtr; - for( i = 0; i < len; i++, ch++ ) { - if ( idStr::CharIsPrintable( *ch ) ) { - file->Printf( "%c", *ch ); - } else if ( *ch == '\n' ) { - file->Printf( "\\n" ); - } else { - file->Printf( "\\x%.2x", static_cast( *ch ) ); - } - } - file->Printf( "\"" ); - break; - - case ev_vector : - file->Printf( "'%s'", value.vectorPtr->ToString() ); - break; - - case ev_float : - file->Printf( "%f", *value.floatPtr ); - break; - - case ev_virtualfunction : - file->Printf( "vtable[ %d ]", value.virtualFunction ); - break; - - default : - file->Printf( "%d", *value.intPtr ); - break; - } - } else if ( initialized == stackVariable ) { - file->Printf( "stack[%d]", value.stackOffset ); - } else { - file->Printf( "global[%d]", num ); - } - break; - } -} - -/*********************************************************************** - - idVarDef - -***********************************************************************/ - -/* -============ -idVarDefName::AddDef -============ -*/ -void idVarDefName::AddDef( idVarDef *def ) { - assert( def->next == NULL ); - def->name = this; - def->next = defs; - defs = def; -} - -/* -============ -idVarDefName::RemoveDef -============ -*/ -void idVarDefName::RemoveDef( idVarDef *def ) { - if ( defs == def ) { - defs = def->next; - } else { - for ( idVarDef *d = defs; d->next != NULL; d = d->next ) { - if ( d->next == def ) { - d->next = def->next; - break; - } - } - } - def->next = NULL; - def->name = NULL; -} - -/*********************************************************************** - - idScriptObject - -***********************************************************************/ - -/* -============ -idScriptObject::idScriptObject -============ -*/ -idScriptObject::idScriptObject() { - data = NULL; - type = &type_object; -} - -/* -============ -idScriptObject::~idScriptObject -============ -*/ -idScriptObject::~idScriptObject() { - Free(); -} - -/* -============ -idScriptObject::Free -============ -*/ -void idScriptObject::Free( void ) { - if ( data ) { - Mem_Free( data ); - } - - data = NULL; - type = &type_object; -} - -/* -================ -idScriptObject::Save -================ -*/ -void idScriptObject::Save( idSaveGame *savefile ) const { - int size; - - if ( type == &type_object && data == NULL ) { - // Write empty string for uninitialized object - savefile->WriteString( "" ); - } else { - savefile->WriteString( type->Name() ); - size = type->Size(); - savefile->WriteInt( size ); - savefile->Write( data, size ); - } -} - -/* -================ -idScriptObject::Restore -================ -*/ -void idScriptObject::Restore( idRestoreGame *savefile ) { - idStr typeName; - int size; - - savefile->ReadString( typeName ); - - // Empty string signals uninitialized object - if ( typeName.Length() == 0 ) { - return; - } - - if ( !SetType( typeName ) ) { - savefile->Error( "idScriptObject::Restore: failed to restore object of type '%s'.", typeName.c_str() ); - } - - savefile->ReadInt( size ); - if ( size != type->Size() ) { - savefile->Error( "idScriptObject::Restore: size of object '%s' doesn't match size in save game.", typeName.c_str() ); - } - - savefile->Read( data, size ); -} - -/* -============ -idScriptObject::SetType - -Allocates an object and initializes memory. -============ -*/ -bool idScriptObject::SetType( const char *typeName ) { - size_t size; - idTypeDef *newtype; - - // lookup the type - newtype = gameLocal.program.FindType( typeName ); - - // only allocate memory if the object type changes - if ( newtype != type ) { - Free(); - if ( !newtype ) { - gameLocal.Warning( "idScriptObject::SetType: Unknown type '%s'", typeName ); - return false; - } - - if ( !newtype->Inherits( &type_object ) ) { - gameLocal.Warning( "idScriptObject::SetType: Can't create object of type '%s'. Must be an object type.", newtype->Name() ); - return false; - } - - // set the type - type = newtype; - - // allocate the memory - size = type->Size(); - data = ( byte * )Mem_Alloc( size ); - } - - // init object memory - ClearObject(); - - return true; -} - -/* -============ -idScriptObject::ClearObject - -Resets the memory for the script object without changing its type. -============ -*/ -void idScriptObject::ClearObject( void ) { - size_t size; - - if ( type != &type_object ) { - // init object memory - size = type->Size(); - memset( data, 0, size ); - } -} - -/* -============ -idScriptObject::HasObject -============ -*/ -bool idScriptObject::HasObject( void ) const { - return ( type != &type_object ); -} - -/* -============ -idScriptObject::GetTypeDef -============ -*/ -idTypeDef *idScriptObject::GetTypeDef( void ) const { - return type; -} - -/* -============ -idScriptObject::GetTypeName -============ -*/ -const char *idScriptObject::GetTypeName( void ) const { - return type->Name(); -} - -/* -============ -idScriptObject::GetConstructor -============ -*/ -const function_t *idScriptObject::GetConstructor( void ) const { - const function_t *func; - - func = GetFunction( "init" ); - return func; -} - -/* -============ -idScriptObject::GetDestructor -============ -*/ -const function_t *idScriptObject::GetDestructor( void ) const { - const function_t *func; - - func = GetFunction( "destroy" ); - return func; -} - -/* -============ -idScriptObject::GetFunction -============ -*/ -const function_t *idScriptObject::GetFunction( const char *name ) const { - const function_t *func; - - if ( type == &type_object ) { - return NULL; - } - - func = gameLocal.program.FindFunction( name, type ); - return func; -} - -/* -============ -idScriptObject::GetVariable -============ -*/ -byte *idScriptObject::GetVariable( const char *name, etype_t etype ) const { - int i; - int pos; - const idTypeDef *t; - const idTypeDef *parm; - - if ( type == &type_object ) { - return NULL; - } - - t = type; - do { - if ( t->SuperClass() != &type_object ) { - pos = t->SuperClass()->Size(); - } else { - pos = 0; - } - for( i = 0; i < t->NumParameters(); i++ ) { - parm = t->GetParmType( i ); - if ( !strcmp( t->GetParmName( i ), name ) ) { - if ( etype != parm->FieldType()->Type() ) { - return NULL; - } - return &data[ pos ]; - } - - if ( parm->FieldType()->Inherits( &type_object ) ) { - pos += type_object.Size(); - } else { - pos += parm->FieldType()->Size(); - } - } - t = t->SuperClass(); - } while( t && ( t != &type_object ) ); - - return NULL; -} - -/*********************************************************************** - - idProgram - -***********************************************************************/ - -/* -============ -idProgram::AllocType -============ -*/ -idTypeDef *idProgram::AllocType( idTypeDef &type ) { - idTypeDef *newtype; - - newtype = new idTypeDef( type ); - types.Append( newtype ); - - return newtype; -} - -/* -============ -idProgram::AllocType -============ -*/ -idTypeDef *idProgram::AllocType( etype_t etype, idVarDef *edef, const char *ename, int esize, idTypeDef *aux ) { - idTypeDef *newtype; - - newtype = new idTypeDef( etype, edef, ename, esize, aux ); - types.Append( newtype ); - - return newtype; -} - -/* -============ -idProgram::GetType - -Returns a preexisting complex type that matches the parm, or allocates -a new one and copies it out. -============ -*/ -idTypeDef *idProgram::GetType( idTypeDef &type, bool allocate ) { - int i; - - //FIXME: linear search == slow - for( i = types.Num() - 1; i >= 0; i-- ) { - if ( types[ i ]->MatchesType( type ) && !strcmp( types[ i ]->Name(), type.Name() ) ) { - return types[ i ]; - } - } - - if ( !allocate ) { - return NULL; - } - - // allocate a new one - return AllocType( type ); -} - -/* -============ -idProgram::FindType - -Returns a preexisting complex type that matches the name, or returns NULL if not found -============ -*/ -idTypeDef *idProgram::FindType( const char *name ) { - idTypeDef *check; - int i; - - for( i = types.Num() - 1; i >= 0; i-- ) { - check = types[ i ]; - if ( !strcmp( check->Name(), name ) ) { - return check; - } - } - - return NULL; -} - -/* -============ -idProgram::GetDefList -============ -*/ -idVarDef *idProgram::GetDefList( const char *name ) const { - int i, hash; - - hash = varDefNameHash.GenerateKey( name, true ); - for ( i = varDefNameHash.First( hash ); i != -1; i = varDefNameHash.Next( i ) ) { - if ( idStr::Cmp( varDefNames[i]->Name(), name ) == 0 ) { - return varDefNames[i]->GetDefs(); - } - } - return NULL; -} - -/* -============ -idProgram::AddDefToNameList -============ -*/ -void idProgram::AddDefToNameList( idVarDef *def, const char *name ) { - int i, hash; - - hash = varDefNameHash.GenerateKey( name, true ); - for ( i = varDefNameHash.First( hash ); i != -1; i = varDefNameHash.Next( i ) ) { - if ( idStr::Cmp( varDefNames[i]->Name(), name ) == 0 ) { - break; - } - } - if ( i == -1 ) { - i = varDefNames.Append( new idVarDefName( name ) ); - varDefNameHash.Add( hash, i ); - } - varDefNames[i]->AddDef( def ); -} - -/* -============== -idProgram::ReserveMem - -reserves memory for global variables and returns the starting pointer -============== -*/ -byte *idProgram::ReserveMem(int size) { - byte *res = &variables[ numVariables ]; - numVariables += size; - if ( numVariables > sizeof( variables ) ) { - throw idCompileError( va( "Exceeded global memory size (%zd bytes)", sizeof( variables ) ) ); - } - - memset( res, 0, size ); - - return res; -} - -/* -============ -idProgram::AllocVarDef -============ -*/ -idVarDef *idProgram::AllocVarDef(idTypeDef *type, const char *name, idVarDef *scope) { - idVarDef *def; - - def = new idVarDef( type ); - def->scope = scope; - def->numUsers = 1; - def->num = varDefs.Append( def ); - - // add the def to the list with defs with this name and set the name pointer - AddDefToNameList( def, name ); - - return def; -} - -/* -============ -idProgram::AllocDef -============ -*/ -idVarDef *idProgram::AllocDef( idTypeDef *type, const char *name, idVarDef *scope, bool constant ) { - idVarDef *def; - idStr element; - idVarDef *def_x; - idVarDef *def_y; - idVarDef *def_z; - - // allocate a new def - def = AllocVarDef(type, name, scope); - - if ( ( type->Type() == ev_vector ) || ( ( type->Type() == ev_field ) && ( type->FieldType()->Type() == ev_vector ) ) ) { - // - // vector - // - if ( !strcmp( name, RESULT_STRING ) ) { - // vector defs don't need the _x, _y and _z components - assert( scope->Type() == ev_function ); - def->value.stackOffset = scope->value.functionPtr->locals; - def->initialized = idVarDef::stackVariable; - scope->value.functionPtr->locals += type->Size(); - } else if ( scope->TypeDef()->Inherits( &type_object ) ) { - idTypeDef newtype( ev_field, NULL, "float field", 0, &type_float ); - idTypeDef *ftype = GetType( newtype, true ); - - // set the value to the variable's position in the object - def->value.ptrOffset = scope->TypeDef()->Size(); - - // make automatic defs for the vectors elements - // origin can be accessed as origin_x, origin_y, and origin_z - sprintf( element, "%s_x", def->Name() ); - def_x = AllocDef( ftype, element, scope, constant ); - - sprintf( element, "%s_y", def->Name() ); - def_y = AllocDef( ftype, element, scope, constant ); - def_y->value.ptrOffset = def_x->value.ptrOffset + sizeof(float); - - sprintf( element, "%s_z", def->Name() ); - def_z = AllocDef( ftype, element, scope, constant ); - def_z->value.ptrOffset = def_y->value.ptrOffset + sizeof(float); - } else { - idTypeDef newtype( ev_float, &def_float, "vector float", 0, NULL ); - idTypeDef *ftype = GetType( newtype, true ); - - // make automatic defs for the vectors elements - // origin can be accessed as origin_x, origin_y, and origin_z - sprintf( element, "%s_x", def->Name() ); - def_x = AllocVarDef( ftype, element, scope ); - - sprintf( element, "%s_y", def->Name() ); - def_y = AllocVarDef( ftype, element, scope ); - - sprintf( element, "%s_z", def->Name() ); - def_z = AllocVarDef( ftype, element, scope ); - - // get the memory for the full vector and point the _x, _y and _z - // defs at the vector member offsets - if ( scope->Type() == ev_function ) { - // vector on stack - def->value.stackOffset = scope->value.functionPtr->locals; - def->initialized = idVarDef::stackVariable; - scope->value.functionPtr->locals += type->Size(); - - def_x->value.stackOffset = def->value.stackOffset; - def_y->value.stackOffset = def_x->value.stackOffset + sizeof(float); - def_z->value.stackOffset = def_y->value.stackOffset + sizeof(float); - } else { - // global vector - def->value.bytePtr = ReserveMem(type->Size()); - def_x->value.bytePtr = def->value.bytePtr; - def_y->value.bytePtr = def_x->value.bytePtr + sizeof(float); - def_z->value.bytePtr = def_y->value.bytePtr + sizeof(float); - } - - def_x->initialized = def->initialized; - def_y->initialized = def->initialized; - def_z->initialized = def->initialized; - } - } else if ( scope->TypeDef()->Inherits( &type_object ) ) { - // - // object variable - // - // set the value to the variable's position in the object - def->value.ptrOffset = scope->TypeDef()->Size(); - } else if ( scope->Type() == ev_function ) { - // - // stack variable - // - // since we don't know how many local variables there are, - // we have to have them go backwards on the stack - def->value.stackOffset = scope->value.functionPtr->locals; - def->initialized = idVarDef::stackVariable; - - if ( type->Inherits( &type_object ) ) { - // objects only have their entity number on the stack, not the entire object - scope->value.functionPtr->locals += type_object.Size(); - } else { - scope->value.functionPtr->locals += type->Size(); - } - } else { - // - // global variable - // - def->value.bytePtr = ReserveMem(def->TypeDef()->Size()); - } - - return def; -} - -/* -============ -idProgram::GetDef - -If type is NULL, it will match any type -============ -*/ -idVarDef *idProgram::GetDef( const idTypeDef *type, const char *name, const idVarDef *scope ) const { - idVarDef *def; - idVarDef *bestDef; - int bestDepth; - int depth; - - bestDepth = 0; - bestDef = NULL; - for( def = GetDefList( name ); def != NULL; def = def->Next() ) { - if ( def->scope->Type() == ev_namespace ) { - depth = def->DepthOfScope( scope ); - if ( !depth ) { - // not in the same namespace - continue; - } - } else if ( def->scope != scope ) { - // in a different function - continue; - } else { - depth = 1; - } - - if ( !bestDef || ( depth < bestDepth ) ) { - bestDepth = depth; - bestDef = def; - } - } - - // see if the name is already in use for another type - if ( bestDef && type && ( bestDef->TypeDef() != type ) ) { - throw idCompileError( va( "Type mismatch on redeclaration of %s", name ) ); - } - - return bestDef; -} - -/* -============ -idProgram::FreeDef -============ -*/ -void idProgram::FreeDef( idVarDef *def, const idVarDef *scope ) { - idVarDef *e; - int i; - - if ( def->Type() == ev_vector ) { - idStr name; - - sprintf( name, "%s_x", def->Name() ); - e = GetDef( NULL, name, scope ); - if ( e ) { - FreeDef( e, scope ); - } - - sprintf( name, "%s_y", def->Name() ); - e = GetDef( NULL, name, scope ); - if ( e ) { - FreeDef( e, scope ); - } - - sprintf( name, "%s_z", def->Name() ); - e = GetDef( NULL, name, scope ); - if ( e ) { - FreeDef( e, scope ); - } - } - - varDefs.RemoveIndex( def->num ); - for( i = def->num; i < varDefs.Num(); i++ ) { - varDefs[ i ]->num = i; - } - - delete def; -} - -/* -============ -idProgram::FindFreeResultDef -============ -*/ -idVarDef *idProgram::FindFreeResultDef( idTypeDef *type, const char *name, idVarDef *scope, const idVarDef *a, const idVarDef *b ) { - idVarDef *def; - - for( def = GetDefList( name ); def != NULL; def = def->Next() ) { - if ( def == a || def == b ) { - continue; - } - if ( def->TypeDef() != type ) { - continue; - } - if ( def->scope != scope ) { - continue; - } - if ( def->numUsers <= 1 ) { - continue; - } - return def; - } - - return AllocDef( type, name, scope, false ); -} - -/* -================ -idProgram::FindFunction - -Searches for the specified function in the currently loaded script. A full namespace should be -specified if not in the global namespace. - -Returns 0 if function not found. -Returns >0 if function found. -================ -*/ -function_t *idProgram::FindFunction( const char *name ) const { - int start; - int pos; - idVarDef *namespaceDef; - idVarDef *def; - - assert( name ); - - idStr fullname = name; - start = 0; - namespaceDef = &def_namespace; - do { - pos = fullname.Find( "::", true, start ); - if ( pos < 0 ) { - break; - } - - idStr namespaceName = fullname.Mid( start, pos - start ); - def = GetDef( NULL, namespaceName, namespaceDef ); - if ( !def ) { - // couldn't find namespace - return NULL; - } - namespaceDef = def; - - // skip past the :: - start = pos + 2; - } while( def->Type() == ev_namespace ); - - idStr funcName = fullname.Right( fullname.Length() - start ); - def = GetDef( NULL, funcName, namespaceDef ); - if ( !def ) { - // couldn't find function - return NULL; - } - - if ( ( def->Type() == ev_function ) && ( def->value.functionPtr->eventdef == NULL ) ) { - return def->value.functionPtr; - } - - // is not a function, or is an eventdef - return NULL; -} - -/* -================ -idProgram::FindFunction - -Searches for the specified object function in the currently loaded script. - -Returns 0 if function not found. -Returns >0 if function found. -================ -*/ -function_t *idProgram::FindFunction( const char *name, const idTypeDef *type ) const { - const idVarDef *tdef; - const idVarDef *def; - - // look for the function - def = NULL; - for( tdef = type->def; tdef != &def_object; tdef = tdef->TypeDef()->SuperClass()->def ) { - def = GetDef( NULL, name, tdef ); - if ( def ) { - return def->value.functionPtr; - } - } - - return NULL; -} - -/* -================ -idProgram::AllocFunction -================ -*/ -function_t &idProgram::AllocFunction( idVarDef *def ) { - if ( functions.Num() >= functions.Max() ) { - throw idCompileError( va( "Exceeded maximum allowed number of functions (%d)", functions.Max() ) ); - } - - // fill in the dfunction - function_t &func = *functions.Alloc(); - func.eventdef = NULL; - func.def = def; - func.type = def->TypeDef(); - func.firstStatement = 0; - func.numStatements = 0; - func.parmTotal = 0; - func.locals = 0; - func.filenum = filenum; - func.parmSize.SetGranularity( 1 ); - func.SetName( def->GlobalName() ); - - def->SetFunction( &func ); - - return func; -} - -/* -================ -idProgram::SetEntity -================ -*/ -void idProgram::SetEntity( const char *name, idEntity *ent ) { - idVarDef *def; - idStr defName( "$" ); - - defName += name; - - def = GetDef( &type_entity, defName, &def_namespace ); - if ( def && ( def->initialized != idVarDef::stackVariable ) ) { - // 0 is reserved for NULL entity - if ( !ent ) { - *def->value.entityNumberPtr = 0; - } else { - *def->value.entityNumberPtr = ent->entityNumber + 1; - } - } -} - -/* -================ -idProgram::AllocStatement -================ -*/ -statement_t *idProgram::AllocStatement( void ) { - if ( statements.Num() >= statements.Max() ) { - throw idCompileError( va( "Exceeded maximum allowed number of statements (%d)", statements.Max() ) ); - } - statement_t* ret = statements.Alloc(); - ret->flags = 0; // DG: initialize the added flags (that are rarely set/used otherwise) to 0 - return ret; -} - -/* -============== -idProgram::BeginCompilation - -called before compiling a batch of files, clears the pr struct -============== -*/ -void idProgram::BeginCompilation( void ) { - statement_t *statement; - - FreeData(); - - try { - // make the first statement a return for a "NULL" function - statement = AllocStatement(); - statement->linenumber = 0; - statement->file = 0; - statement->op = OP_RETURN; - statement->a = NULL; - statement->b = NULL; - statement->c = NULL; - - // define NULL - //AllocDef( &type_void, "", &def_namespace, true ); - - // define the return def - returnDef = AllocDef( &type_vector, "", &def_namespace, false ); - - // define the return def for strings - returnStringDef = AllocDef( &type_string, "", &def_namespace, false ); - - // define the sys object - sysDef = AllocDef( &type_void, "sys", &def_namespace, true ); - } - - catch( idCompileError &err ) { - gameLocal.Error( "%s", err.error ); - } -} - -/* -============== -idProgram::DisassembleStatement -============== -*/ -void idProgram::DisassembleStatement( idFile *file, int instructionPointer ) const { - const opcode_t *op; - const statement_t *statement; - - statement = &statements[ instructionPointer ]; - op = &idCompiler::opcodes[ statement->op ]; - file->Printf( "%20s(%d):\t%6d: %15s\t", fileList[ statement->file ].c_str(), statement->linenumber, instructionPointer, op->opname ); - - if ( statement->a ) { - file->Printf( "\ta: " ); - statement->a->PrintInfo( file, instructionPointer ); - } - - if ( statement->b ) { - file->Printf( "\tb: " ); - statement->b->PrintInfo( file, instructionPointer ); - } - - if ( statement->c ) { - file->Printf( "\tc: " ); - statement->c->PrintInfo( file, instructionPointer ); - } - - file->Printf( "\n" ); -} - -/* -============== -idProgram::Disassemble -============== -*/ -void idProgram::Disassemble( void ) const { - int i; - int instructionPointer; - const function_t *func; - idFile *file; - - file = fileSystem->OpenFileByMode( "script/disasm.txt", FS_WRITE ); - - for( i = 0; i < functions.Num(); i++ ) { - func = &functions[ i ]; - if ( func->eventdef ) { - // skip eventdefs - continue; - } - - file->Printf( "\nfunction %s() %d stack used, %d parms, %d locals {\n", func->Name(), func->locals, func->parmTotal, func->locals - func->parmTotal ); - - for( instructionPointer = 0; instructionPointer < func->numStatements; instructionPointer++ ) { - DisassembleStatement( file, func->firstStatement + instructionPointer ); - } - - file->Printf( "}\n" ); - } - - fileSystem->CloseFile( file ); -} - -/* -============== -idProgram::FinishCompilation - -Called after all files are compiled to check for errors -============== -*/ -void idProgram::FinishCompilation( void ) { - int i; - - top_functions = functions.Num(); - top_statements = statements.Num(); - top_types = types.Num(); - top_defs = varDefs.Num(); - top_files = fileList.Num(); - - variableDefaults.Clear(); - variableDefaults.SetNum( numVariables ); - - for( i = 0; i < numVariables; i++ ) { - variableDefaults[ i ] = variables[ i ]; - } -} - -/* -============== -idProgram::CompileStats - -called after all files are compiled to report memory usage. -============== -*/ -void idProgram::CompileStats( void ) { - int memused; - int memallocated; - int stringspace; - int funcMem; - int i; - - gameLocal.Printf( "----- Compile stats -----\n" ); - gameLocal.DPrintf( "Files loaded:\n" ); - - stringspace = 0; - for( i = 0; i < fileList.Num(); i++ ) { - gameLocal.DPrintf( " %s\n", fileList[ i ].c_str() ); - stringspace += fileList[ i ].Allocated(); - } - stringspace += fileList.Size(); - - memused = varDefs.Num() * sizeof( idVarDef ); - memused += types.Num() * sizeof( idTypeDef ); - memused += stringspace; - - for( i = 0; i < types.Num(); i++ ) { - memused += types[ i ]->Allocated(); - } - - funcMem = functions.MemoryUsed(); - for( i = 0; i < functions.Num(); i++ ) { - funcMem += functions[ i ].Allocated(); - } - - memallocated = funcMem + memused + sizeof( idProgram ); - - memused += statements.MemoryUsed(); - memused += functions.MemoryUsed(); // name and filename of functions are shared, so no need to include them - memused += sizeof( variables ); - - gameLocal.Printf( "Memory usage:\n" ); - gameLocal.Printf( " Strings: %d, %d bytes\n", fileList.Num(), stringspace ); - gameLocal.Printf( " Statements: %d, %zd bytes\n", statements.Num(), statements.MemoryUsed() ); - gameLocal.Printf( " Functions: %d, %d bytes\n", functions.Num(), funcMem ); - gameLocal.Printf( " Variables: %d bytes\n", numVariables ); - gameLocal.Printf( " Mem used: %d bytes\n", memused ); - gameLocal.Printf( " Static data: %zd bytes\n", sizeof( idProgram ) ); - gameLocal.Printf( " Allocated: %d bytes\n", memallocated ); - gameLocal.Printf( " Thread size: %zd bytes\n", sizeof( idThread ) ); -} - -/* -================ -idProgram::CompileText -================ -*/ -bool idProgram::CompileText( const char *source, const char *text, bool console ) { - idCompiler compiler; - int i; - idVarDef *def; - idStr ospath; - - // use a full os path for GetFilenum since it calls OSPathToRelativePath to convert filenames from the parser - ospath = fileSystem->RelativePathToOSPath( source ); - filenum = GetFilenum( ospath ); - - try { - compiler.CompileFile( text, filename, console ); - - // check to make sure all functions prototyped have code - for( i = 0; i < varDefs.Num(); i++ ) { - def = varDefs[ i ]; - if ( ( def->Type() == ev_function ) && ( ( def->scope->Type() == ev_namespace ) || def->scope->TypeDef()->Inherits( &type_object ) ) ) { - if ( !def->value.functionPtr->eventdef && !def->value.functionPtr->firstStatement ) { - throw idCompileError( va( "function %s was not defined\n", def->GlobalName() ) ); - } - } - } - } - - catch( idCompileError &err ) { - if ( console ) { - gameLocal.Printf( "%s\n", err.error ); - return false; - } else { - gameLocal.Error( "%s\n", err.error ); - } - }; - - if ( !console ) { - CompileStats(); - } - - return true; -} - -/* -================ -idProgram::CompileFunction -================ -*/ -const function_t *idProgram::CompileFunction( const char *functionName, const char *text ) { - bool result; - - result = CompileText( functionName, text, false ); - - if ( g_disasm.GetBool() ) { - Disassemble(); - } - - if ( !result ) { - gameLocal.Error( "Compile failed." ); - } - - return FindFunction( functionName ); -} - -/* -================ -idProgram::CompileFile -================ -*/ -void idProgram::CompileFile( const char *filename ) { - char *src; - bool result; - - if ( fileSystem->ReadFile( filename, ( void ** )&src, NULL ) < 0 ) { - gameLocal.Error( "Couldn't load %s\n", filename ); - } - - result = CompileText( filename, src, false ); - - fileSystem->FreeFile( src ); - - if ( g_disasm.GetBool() ) { - Disassemble(); - } - - if ( !result ) { - gameLocal.Error( "Compile failed in file %s.", filename ); - } -} - -/* -================ -idProgram::FreeData -================ -*/ -void idProgram::FreeData( void ) { - int i; - - // free the defs - varDefs.DeleteContents( true ); - varDefNames.DeleteContents( true ); - varDefNameHash.Free(); - - returnDef = NULL; - returnStringDef = NULL; - sysDef = NULL; - - // free any special types we've created - types.DeleteContents( true ); - - filenum = 0; - - numVariables = 0; - memset( variables, 0, sizeof( variables ) ); - - // clear all the strings in the functions so that it doesn't look like we're leaking memory. - for( i = 0; i < functions.Num(); i++ ) { - functions[ i ].Clear(); - } - - filename.Clear(); - fileList.Clear(); - statements.Clear(); - functions.Clear(); - - top_functions = 0; - top_statements = 0; - top_types = 0; - top_defs = 0; - top_files = 0; - - filename = ""; -} - -/* -================ -idProgram::Startup -================ -*/ -void idProgram::Startup( const char *defaultScript ) { - gameLocal.Printf( "Initializing scripts\n" ); - - // make sure all data is freed up - idThread::Restart(); - - // get ready for loading scripts - BeginCompilation(); - - // load the default script - if ( defaultScript && *defaultScript ) { - CompileFile( defaultScript ); - } - - FinishCompilation(); -} - -/* -================ -idProgram::Save -================ -*/ -void idProgram::Save( idSaveGame *savefile ) const { - int i; - int currentFileNum = top_files; - - savefile->WriteInt( (fileList.Num() - currentFileNum) ); - while ( currentFileNum < fileList.Num() ) { - savefile->WriteString( fileList[ currentFileNum ] ); - currentFileNum++; - } - - for ( i = 0; i < variableDefaults.Num(); i++ ) { - if ( variables[i] != variableDefaults[i] ) { - savefile->WriteInt( i ); - savefile->WriteByte( variables[i] ); - } - } - // Mark the end of the diff with default variables with -1 - savefile->WriteInt( -1 ); - - savefile->WriteInt( numVariables ); - for ( i = variableDefaults.Num(); i < numVariables; i++ ) { - savefile->WriteByte( variables[i] ); - } - - int checksum = CalculateChecksum(false); - savefile->WriteInt( checksum ); -} - -/* -================ -idProgram::Restore -================ -*/ -bool idProgram::Restore( idRestoreGame *savefile ) { - int i, num, index; - bool result = true; - idStr scriptname; - - savefile->ReadInt( num ); - for ( i = 0; i < num; i++ ) { - savefile->ReadString( scriptname ); - CompileFile( scriptname ); - } - - savefile->ReadInt( index ); - while( index >= 0 ) { - savefile->ReadByte( variables[index] ); - savefile->ReadInt( index ); - } - - savefile->ReadInt( num ); - for ( i = variableDefaults.Num(); i < num; i++ ) { - savefile->ReadByte( variables[i] ); - } - - int saved_checksum, checksum; - - savefile->ReadInt( saved_checksum ); - bool isOldSavegame = savefile->GetBuildNumber() <= 1304; - checksum = CalculateChecksum(isOldSavegame); - - if ( saved_checksum != checksum ) { - gameLocal.Warning( "WARNING: Real Script checksum didn't match the one from the savegame!"); - result = false; - } - - return result; -} - -/* -================ -idProgram::CalculateChecksum -================ -*/ -int idProgram::CalculateChecksum( bool forOldSavegame ) const { - int i, result; - - typedef struct { - unsigned short op; - int a; - int b; - int c; - unsigned short linenumber; - unsigned short file; - } statementBlock_t; - - statementBlock_t *statementList = new statementBlock_t[ statements.Num() ]; - - memset( statementList, 0, ( sizeof(statementBlock_t) * statements.Num() ) ); - - // DG hack: get the vardef for the argSize == 0 constant for savegame-compat - int constantZeroNum = -1; - if ( forOldSavegame ) { - for( idVarDef* def = GetDefList( "" ); def != NULL; def = def->Next() ) { - if ( def->Type() == ev_argsize && def->value.argSize == 0 ) { - constantZeroNum = def->num; - break; - } - } - } - - // Copy info into new list, using the variable numbers instead of a pointer to the variable - for( i = 0; i < statements.Num(); i++ ) { - statementList[i].op = statements[i].op; - - if ( statements[i].a ) { - statementList[i].a = statements[i].a->num; - } else { - statementList[i].a = -1; - } - if ( statements[i].b ) { - statementList[i].b = statements[i].b->num; - } else { - statementList[i].b = -1; - } - if ( statements[i].c ) { - // DG: old savegames wrongly assumed argSize 0 for some statements. - // So for the checksums to match we need to use the corresponding vardef num here - // See idCompiler::EmitFunctionParms() and ParseFunctionDef() for more details. - if ( forOldSavegame && statements[i].op == OP_OBJECTCALL - && statements[i].flags == statement_t::FLAG_OBJECTCALL_IMPL_NOT_PARSED_YET ) { - statementList[i].c = constantZeroNum; - } else { - statementList[i].c = statements[i].c->num; - } - } else { - statementList[i].c = -1; - } - - statementList[i].linenumber = statements[i].linenumber; - statementList[i].file = statements[i].file; - } - - result = MD4_BlockChecksum( statementList, ( sizeof(statementBlock_t) * statements.Num() ) ); - - delete [] statementList; - - return result; -} - -/* -============== -idProgram::Restart - -Restores all variables to their initial value -============== -*/ -void idProgram::Restart( void ) { - int i; - - idThread::Restart(); - - // - // since there may have been a script loaded by the map or the user may - // have typed "script" from the console, free up any types and vardefs that - // have been allocated after the initial startup - // - for( i = top_types; i < types.Num(); i++ ) { - delete types[ i ]; - } - types.SetNum( top_types, false ); - - for( i = top_defs; i < varDefs.Num(); i++ ) { - delete varDefs[ i ]; - } - varDefs.SetNum( top_defs, false ); - - for( i = top_functions; i < functions.Num(); i++ ) { - functions[ i ].Clear(); - } - functions.SetNum( top_functions ); - - statements.SetNum( top_statements ); - fileList.SetNum( top_files, false ); - filename.Clear(); - - // reset the variables to their default values - numVariables = variableDefaults.Num(); - for( i = 0; i < numVariables; i++ ) { - variables[ i ] = variableDefaults[ i ]; - } -} - -/* -================ -idProgram::GetFilenum -================ -*/ -int idProgram::GetFilenum( const char *name ) { - if ( filename == name ) { - return filenum; - } - - idStr strippedName; - strippedName = fileSystem->OSPathToRelativePath( name ); - if ( !strippedName.Length() ) { - // not off the base path so just use the full path - filenum = fileList.AddUnique( name ); - } else { - filenum = fileList.AddUnique( strippedName ); - } - - // save the unstripped name so that we don't have to strip the incoming name every time we call GetFilenum - filename = name; - - return filenum; -} - -/* -================ -idProgram::idProgram -================ -*/ -idProgram::idProgram() { - FreeData(); -} - -/* -================ -idProgram::~idProgram -================ -*/ -idProgram::~idProgram() { - FreeData(); -} - -/* -================ -idProgram::ReturnEntity -================ -*/ -void idProgram::ReturnEntity( idEntity *ent ) { - if ( ent ) { - *returnDef->value.entityNumberPtr = ent->entityNumber + 1; - } else { - *returnDef->value.entityNumberPtr = 0; - } -} diff --git a/d3xp/script/Script_Program.h b/d3xp/script/Script_Program.h deleted file mode 100644 index 93a7eb84..00000000 --- a/d3xp/script/Script_Program.h +++ /dev/null @@ -1,652 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __SCRIPT_PROGRAM_H__ -#define __SCRIPT_PROGRAM_H__ - -#include "idlib/containers/StrList.h" -#include "idlib/containers/StaticList.h" -#include "idlib/containers/HashIndex.h" -#include "idlib/math/Vector.h" - -#include "GameBase.h" - -class idEventDef; -class idVarDef; -class idTypeDef; -class idEntity; -class idSaveGame; -class idRestoreGame; - -#define MAX_STRING_LEN 128 -#ifdef _D3XP -#define MAX_GLOBALS 296608 // in bytes -#else -#define MAX_GLOBALS 196608 // in bytes -#endif -#define MAX_STRINGS 1024 - -#ifdef _D3XP -#define MAX_FUNCS 3584 -#else -#define MAX_FUNCS 3072 -#endif - -#ifdef _D3XP -#define MAX_STATEMENTS 131072 // statement_t - 18 bytes last I checked -#else -#define MAX_STATEMENTS 81920 // statement_t - 18 bytes last I checked -#endif - -typedef enum { - ev_error = -1, ev_void, ev_scriptevent, ev_namespace, ev_string, ev_float, ev_vector, ev_entity, ev_field, ev_function, ev_virtualfunction, ev_pointer, ev_object, ev_jumpoffset, ev_argsize, ev_boolean -} etype_t; - -class function_t { -public: - function_t(); - - size_t Allocated( void ) const; - void SetName( const char *name ); - const char *Name( void ) const; - void Clear( void ); - -private: - idStr name; -public: - const idEventDef *eventdef; - idVarDef *def; - const idTypeDef *type; - int firstStatement; - int numStatements; - int parmTotal; - int locals; // total ints of parms + locals - int filenum; // source file defined in - idList parmSize; -}; - -typedef union eval_s { - const char *stringPtr; - float _float; - float vector[ 3 ]; - function_t *function; - int _int; - int entity; -} eval_t; - -/*********************************************************************** - -idTypeDef - -Contains type information for variables and functions. - -***********************************************************************/ - -class idTypeDef { -private: - etype_t type; - idStr name; - int size; - - // function types are more complex - idTypeDef *auxType; // return type - idList parmTypes; - idStrList parmNames; - idList functions; - -public: - idVarDef *def; // a def that points to this type - - idTypeDef( const idTypeDef &other ); - idTypeDef( etype_t etype, idVarDef *edef, const char *ename, int esize, idTypeDef *aux ); - void operator=( const idTypeDef& other ); - size_t Allocated( void ) const; - - bool Inherits( const idTypeDef *basetype ) const; - bool MatchesType( const idTypeDef &matchtype ) const; - bool MatchesVirtualFunction( const idTypeDef &matchfunc ) const; - void AddFunctionParm( idTypeDef *parmtype, const char *name ); - void AddField( idTypeDef *fieldtype, const char *name ); - - void SetName( const char *newname ); - const char *Name( void ) const; - - etype_t Type( void ) const; - int Size( void ) const; - - idTypeDef *SuperClass( void ) const; - - idTypeDef *ReturnType( void ) const; - void SetReturnType( idTypeDef *type ); - - idTypeDef *FieldType( void ) const; - void SetFieldType( idTypeDef *type ); - - idTypeDef *PointerType( void ) const; - void SetPointerType( idTypeDef *type ); - - int NumParameters( void ) const; - idTypeDef *GetParmType( int parmNumber ) const; - const char *GetParmName( int parmNumber ) const; - - int NumFunctions( void ) const; - int GetFunctionNumber( const function_t *func ) const; - const function_t *GetFunction( int funcNumber ) const; - void AddFunction( const function_t *func ); -}; - -/*********************************************************************** - -idScriptObject - -In-game representation of objects in scripts. Use the idScriptVariable template -(below) to access variables. - -***********************************************************************/ - -class idScriptObject { -private: - idTypeDef *type; - -public: - byte *data; - - idScriptObject(); - ~idScriptObject(); - - void Save( idSaveGame *savefile ) const; // archives object for save game file - void Restore( idRestoreGame *savefile ); // unarchives object from save game file - - void Free( void ); - bool SetType( const char *typeName ); - void ClearObject( void ); - bool HasObject( void ) const; - idTypeDef *GetTypeDef( void ) const; - const char *GetTypeName( void ) const; - const function_t *GetConstructor( void ) const; - const function_t *GetDestructor( void ) const; - const function_t *GetFunction( const char *name ) const; - - byte *GetVariable( const char *name, etype_t etype ) const; -}; - -/*********************************************************************** - -idScriptVariable - -Helper template that handles looking up script variables stored in objects. -If the specified variable doesn't exist, or is the wrong data type, idScriptVariable -will cause an error. - -***********************************************************************/ - -template -class idScriptVariable { -private: - type *data; - -public: - idScriptVariable(); - bool IsLinked( void ) const; - void Unlink( void ); - void LinkTo( idScriptObject &obj, const char *name ); - idScriptVariable &operator=( const returnType &value ); - operator returnType() const; -}; - -template -ID_INLINE idScriptVariable::idScriptVariable() { - data = NULL; -} - -template -ID_INLINE bool idScriptVariable::IsLinked( void ) const { - return ( data != NULL ); -} - -template -ID_INLINE void idScriptVariable::Unlink( void ) { - data = NULL; -} - -template -ID_INLINE void idScriptVariable::LinkTo( idScriptObject &obj, const char *name ) { - data = ( type * )obj.GetVariable( name, etype ); - if ( !data ) { - gameError( "Missing '%s' field in script object '%s'", name, obj.GetTypeName() ); - } -} - -template -ID_INLINE idScriptVariable &idScriptVariable::operator=( const returnType &value ) { - // check if we attempt to access the object before it's been linked - assert( data ); - - // make sure we don't crash if we don't have a pointer - if ( data ) { - *data = ( type )value; - } - return *this; -} - -template -ID_INLINE idScriptVariable::operator returnType() const { - // check if we attempt to access the object before it's been linked - assert( data ); - - // make sure we don't crash if we don't have a pointer - if ( data ) { - return ( const returnType )*data; - } else { - // reasonably safe value - return ( const returnType )0; - } -} - -/*********************************************************************** - -Script object variable access template instantiations - -These objects will automatically handle looking up of the current value -of a variable in a script object. They can be stored as part of a class -for up-to-date values of the variable, or can be used in functions to -sample the data for non-dynamic values. - -***********************************************************************/ - -typedef idScriptVariable idScriptBool; -typedef idScriptVariable idScriptFloat; -typedef idScriptVariable idScriptInt; -typedef idScriptVariable idScriptVector; -typedef idScriptVariable idScriptString; - -/*********************************************************************** - -idCompileError - -Causes the compiler to exit out of compiling the current function and -display an error message with line and file info. - -***********************************************************************/ - -class idCompileError : public idException { -public: - idCompileError( const char *text ) : idException( text ) {} -}; - -/*********************************************************************** - -idVarDef - -Define the name, type, and location of variables, functions, and objects -defined in script. - -***********************************************************************/ - -typedef union varEval_s { - idScriptObject **objectPtrPtr; - char *stringPtr; - float *floatPtr; - idVec3 *vectorPtr; - function_t *functionPtr; - int *intPtr; - byte *bytePtr; - int *entityNumberPtr; - int virtualFunction; - int jumpOffset; - int stackOffset; // offset in stack for local variables - int argSize; - varEval_s *evalPtr; - int ptrOffset; -} varEval_t; - -class idVarDefName; - -class idVarDef { - friend class idVarDefName; - -public: - int num; // global index/ID of variable - varEval_t value; - idVarDef * scope; // function, namespace, or object the var was defined in - int numUsers; // number of users if this is a constant - - typedef enum { - uninitialized, initializedVariable, initializedConstant, stackVariable - } initialized_t; - - initialized_t initialized; - -public: - idVarDef( idTypeDef *typeptr = NULL ); - ~idVarDef(); - - const char * Name( void ) const; - const char * GlobalName( void ) const; - - void SetTypeDef( idTypeDef *_type ) { typeDef = _type; } - idTypeDef * TypeDef( void ) const { return typeDef; } - etype_t Type( void ) const { return ( typeDef != NULL ) ? typeDef->Type() : ev_void; } - - int DepthOfScope( const idVarDef *otherScope ) const; - - void SetFunction( function_t *func ); - void SetObject( idScriptObject *object ); - void SetValue( const eval_t &value, bool constant ); - void SetString( const char *string, bool constant ); - - idVarDef * Next( void ) const { return next; } // next var def with same name - - void PrintInfo( idFile *file, int instructionPointer ) const; - -private: - idTypeDef * typeDef; - idVarDefName * name; // name of this var - idVarDef * next; // next var with the same name -}; - -/*********************************************************************** - - idVarDefName - -***********************************************************************/ - -class idVarDefName { -public: - idVarDefName( void ) { defs = NULL; } - idVarDefName( const char *n ) { name = n; defs = NULL; } - - const char * Name( void ) const { return name; } - idVarDef * GetDefs( void ) const { return defs; } - - void AddDef( idVarDef *def ); - void RemoveDef( idVarDef *def ); - -private: - idStr name; - idVarDef * defs; -}; - -/*********************************************************************** - - Variable and type defintions - -***********************************************************************/ - -extern idTypeDef type_void; -extern idTypeDef type_scriptevent; -extern idTypeDef type_namespace; -extern idTypeDef type_string; -extern idTypeDef type_float; -extern idTypeDef type_vector; -extern idTypeDef type_entity; -extern idTypeDef type_field; -extern idTypeDef type_function; -extern idTypeDef type_virtualfunction; -extern idTypeDef type_pointer; -extern idTypeDef type_object; -extern idTypeDef type_jumpoffset; // only used for jump opcodes -extern idTypeDef type_argsize; // only used for function call and thread opcodes -extern idTypeDef type_boolean; - -extern idVarDef def_void; -extern idVarDef def_scriptevent; -extern idVarDef def_namespace; -extern idVarDef def_string; -extern idVarDef def_float; -extern idVarDef def_vector; -extern idVarDef def_entity; -extern idVarDef def_field; -extern idVarDef def_function; -extern idVarDef def_virtualfunction; -extern idVarDef def_pointer; -extern idVarDef def_object; -extern idVarDef def_jumpoffset; // only used for jump opcodes -extern idVarDef def_argsize; // only used for function call and thread opcodes -extern idVarDef def_boolean; - -typedef struct statement_s { - unsigned short op; - unsigned short flags; // DG: added this for ugly hacks - enum { - // op is OP_OBJECTCALL and when the statement was created the function/method - // implementation hasn't been parsed yet (only the declaration/prototype) - // see idCompiler::EmitFunctionParms() and idProgram::CalculateChecksum() - FLAG_OBJECTCALL_IMPL_NOT_PARSED_YET = 1, - }; - // DG: moved linenumber and file up here to prevent wasting 8 bytes of padding on 64bit - unsigned short linenumber; - unsigned short file; - idVarDef *a; - idVarDef *b; - idVarDef *c; -} statement_t; - -/*********************************************************************** - -idProgram - -Handles compiling and storage of script data. Multiple idProgram objects -would represent seperate programs with no knowledge of each other. Scripts -meant to access shared data and functions should all be compiled by a -single idProgram. - -***********************************************************************/ - -class idProgram { -private: - idStrList fileList; - idStr filename; - int filenum; - - int numVariables; - byte variables[ MAX_GLOBALS ]; - idStaticList variableDefaults; - idStaticList functions; - idStaticList statements; - idList types; - idList varDefNames; - idHashIndex varDefNameHash; - idList varDefs; - - idVarDef *sysDef; - - int top_functions; - int top_statements; - int top_types; - int top_defs; - int top_files; - - void CompileStats( void ); - byte *ReserveMem(int size); - idVarDef *AllocVarDef(idTypeDef *type, const char *name, idVarDef *scope); - -public: - idVarDef *returnDef; - idVarDef *returnStringDef; - - idProgram(); - ~idProgram(); - - // save games - void Save( idSaveGame *savefile ) const; - bool Restore( idRestoreGame *savefile ); - int CalculateChecksum( bool forOldSavegame ) const; // Used to insure program code has not - // changed between savegames - - void Startup( const char *defaultScript ); - void Restart( void ); - bool CompileText( const char *source, const char *text, bool console ); - const function_t *CompileFunction( const char *functionName, const char *text ); - void CompileFile( const char *filename ); - void BeginCompilation( void ); - void FinishCompilation( void ); - void DisassembleStatement( idFile *file, int instructionPointer ) const; - void Disassemble( void ) const; - void FreeData( void ); - - const char *GetFilename( int num ); - int GetFilenum( const char *name ); - int GetLineNumberForStatement( int index ); - const char *GetFilenameForStatement( int index ); - - idTypeDef *AllocType( idTypeDef &type ); - idTypeDef *AllocType( etype_t etype, idVarDef *edef, const char *ename, int esize, idTypeDef *aux ); - idTypeDef *GetType( idTypeDef &type, bool allocate ); - idTypeDef *FindType( const char *name ); - - idVarDef *AllocDef( idTypeDef *type, const char *name, idVarDef *scope, bool constant ); - idVarDef *GetDef( const idTypeDef *type, const char *name, const idVarDef *scope ) const; - void FreeDef( idVarDef *d, const idVarDef *scope ); - idVarDef *FindFreeResultDef( idTypeDef *type, const char *name, idVarDef *scope, const idVarDef *a, const idVarDef *b ); - idVarDef *GetDefList( const char *name ) const; - void AddDefToNameList( idVarDef *def, const char *name ); - - function_t *FindFunction( const char *name ) const; // returns NULL if function not found - function_t *FindFunction( const char *name, const idTypeDef *type ) const; // returns NULL if function not found - function_t &AllocFunction( idVarDef *def ); - function_t *GetFunction( int index ); - int GetFunctionIndex( const function_t *func ); - - void SetEntity( const char *name, idEntity *ent ); - - statement_t *AllocStatement( void ); - statement_t &GetStatement( int index ); - int NumStatements( void ) { return statements.Num(); } - - int GetReturnedInteger( void ); - - void ReturnFloat( float value ); - void ReturnInteger( int value ); - void ReturnVector( idVec3 const &vec ); - void ReturnString( const char *string ); - void ReturnEntity( idEntity *ent ); - - int NumFilenames( void ) { return fileList.Num( ); } -}; - -/* -================ -idProgram::GetStatement -================ -*/ -ID_INLINE statement_t &idProgram::GetStatement( int index ) { - return statements[ index ]; -} - -/* -================ -idProgram::GetFunction -================ -*/ -ID_INLINE function_t *idProgram::GetFunction( int index ) { - return &functions[ index ]; -} - -/* -================ -idProgram::GetFunctionIndex -================ -*/ -ID_INLINE int idProgram::GetFunctionIndex( const function_t *func ) { - return func - &functions[0]; -} - -/* -================ -idProgram::GetReturnedInteger -================ -*/ -ID_INLINE int idProgram::GetReturnedInteger( void ) { - return *returnDef->value.intPtr; -} - -/* -================ -idProgram::ReturnFloat -================ -*/ -ID_INLINE void idProgram::ReturnFloat( float value ) { - *returnDef->value.floatPtr = value; -} - -/* -================ -idProgram::ReturnInteger -================ -*/ -ID_INLINE void idProgram::ReturnInteger( int value ) { - *returnDef->value.intPtr = value; -} - -/* -================ -idProgram::ReturnVector -================ -*/ -ID_INLINE void idProgram::ReturnVector( idVec3 const &vec ) { - *returnDef->value.vectorPtr = vec; -} - -/* -================ -idProgram::ReturnString -================ -*/ -ID_INLINE void idProgram::ReturnString( const char *string ) { - idStr::Copynz( returnStringDef->value.stringPtr, string, MAX_STRING_LEN ); -} - -/* -================ -idProgram::GetFilename -================ -*/ -ID_INLINE const char *idProgram::GetFilename( int num ) { - return fileList[ num ]; -} - -/* -================ -idProgram::GetLineNumberForStatement -================ -*/ -ID_INLINE int idProgram::GetLineNumberForStatement( int index ) { - return statements[ index ].linenumber; -} - -/* -================ -idProgram::GetFilenameForStatement -================ -*/ -ID_INLINE const char *idProgram::GetFilenameForStatement( int index ) { - return GetFilename( statements[ index ].file ); -} - -#endif /* !__SCRIPT_PROGRAM_H__ */ diff --git a/d3xp/script/Script_Thread.cpp b/d3xp/script/Script_Thread.cpp deleted file mode 100644 index cb826331..00000000 --- a/d3xp/script/Script_Thread.cpp +++ /dev/null @@ -1,1923 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" - -#include "gamesys/SysCvar.h" -#include "Player.h" -#include "Camera.h" - -#include "script/Script_Thread.h" - -const idEventDef EV_Thread_Execute( "", NULL ); -const idEventDef EV_Thread_SetCallback( "", NULL ); - -// script callable events -const idEventDef EV_Thread_TerminateThread( "terminate", "d" ); -const idEventDef EV_Thread_Pause( "pause", NULL ); -const idEventDef EV_Thread_Wait( "wait", "f" ); -const idEventDef EV_Thread_WaitFrame( "waitFrame" ); -const idEventDef EV_Thread_WaitFor( "waitFor", "e" ); -const idEventDef EV_Thread_WaitForThread( "waitForThread", "d" ); -const idEventDef EV_Thread_Print( "print", "s" ); -const idEventDef EV_Thread_PrintLn( "println", "s" ); -const idEventDef EV_Thread_Say( "say", "s" ); -const idEventDef EV_Thread_Assert( "assert", "f" ); -const idEventDef EV_Thread_Trigger( "trigger", "e" ); -const idEventDef EV_Thread_SetCvar( "setcvar", "ss" ); -const idEventDef EV_Thread_GetCvar( "getcvar", "s", 's' ); -const idEventDef EV_Thread_Random( "random", "f", 'f' ); -#ifdef _D3XP -const idEventDef EV_Thread_RandomInt( "randomInt", "d", 'd' ); -#endif -const idEventDef EV_Thread_GetTime( "getTime", NULL, 'f' ); -const idEventDef EV_Thread_KillThread( "killthread", "s" ); -const idEventDef EV_Thread_SetThreadName( "threadname", "s" ); -const idEventDef EV_Thread_GetEntity( "getEntity", "s", 'e' ); -const idEventDef EV_Thread_Spawn( "spawn", "s", 'e' ); -const idEventDef EV_Thread_CopySpawnArgs( "copySpawnArgs", "e" ); -const idEventDef EV_Thread_SetSpawnArg( "setSpawnArg", "ss" ); -const idEventDef EV_Thread_SpawnString( "SpawnString", "ss", 's' ); -const idEventDef EV_Thread_SpawnFloat( "SpawnFloat", "sf", 'f' ); -const idEventDef EV_Thread_SpawnVector( "SpawnVector", "sv", 'v' ); -const idEventDef EV_Thread_ClearPersistantArgs( "clearPersistantArgs" ); -const idEventDef EV_Thread_SetPersistantArg( "setPersistantArg", "ss" ); -const idEventDef EV_Thread_GetPersistantString( "getPersistantString", "s", 's' ); -const idEventDef EV_Thread_GetPersistantFloat( "getPersistantFloat", "s", 'f' ); -const idEventDef EV_Thread_GetPersistantVector( "getPersistantVector", "s", 'v' ); -const idEventDef EV_Thread_AngToForward( "angToForward", "v", 'v' ); -const idEventDef EV_Thread_AngToRight( "angToRight", "v", 'v' ); -const idEventDef EV_Thread_AngToUp( "angToUp", "v", 'v' ); -const idEventDef EV_Thread_Sine( "sin", "f", 'f' ); -const idEventDef EV_Thread_Cosine( "cos", "f", 'f' ); -#ifdef _D3XP -const idEventDef EV_Thread_ArcSine( "asin", "f", 'f' ); -const idEventDef EV_Thread_ArcCosine( "acos", "f", 'f' ); -#endif -const idEventDef EV_Thread_SquareRoot( "sqrt", "f", 'f' ); -const idEventDef EV_Thread_Normalize( "vecNormalize", "v", 'v' ); -const idEventDef EV_Thread_VecLength( "vecLength", "v", 'f' ); -const idEventDef EV_Thread_VecDotProduct( "DotProduct", "vv", 'f' ); -const idEventDef EV_Thread_VecCrossProduct( "CrossProduct", "vv", 'v' ); -const idEventDef EV_Thread_VecToAngles( "VecToAngles", "v", 'v' ); -#ifdef _D3XP -const idEventDef EV_Thread_VecToOrthoBasisAngles( "VecToOrthoBasisAngles", "v", 'v' ); -const idEventDef EV_Thread_RotateVector("rotateVector", "vv", 'v'); -#endif -const idEventDef EV_Thread_OnSignal( "onSignal", "des" ); -const idEventDef EV_Thread_ClearSignal( "clearSignalThread", "de" ); -const idEventDef EV_Thread_SetCamera( "setCamera", "e" ); -const idEventDef EV_Thread_FirstPerson( "firstPerson", NULL ); -const idEventDef EV_Thread_Trace( "trace", "vvvvde", 'f' ); -const idEventDef EV_Thread_TracePoint( "tracePoint", "vvde", 'f' ); -const idEventDef EV_Thread_GetTraceFraction( "getTraceFraction", NULL, 'f' ); -const idEventDef EV_Thread_GetTraceEndPos( "getTraceEndPos", NULL, 'v' ); -const idEventDef EV_Thread_GetTraceNormal( "getTraceNormal", NULL, 'v' ); -const idEventDef EV_Thread_GetTraceEntity( "getTraceEntity", NULL, 'e' ); -const idEventDef EV_Thread_GetTraceJoint( "getTraceJoint", NULL, 's' ); -const idEventDef EV_Thread_GetTraceBody( "getTraceBody", NULL, 's' ); -const idEventDef EV_Thread_FadeIn( "fadeIn", "vf" ); -const idEventDef EV_Thread_FadeOut( "fadeOut", "vf" ); -const idEventDef EV_Thread_FadeTo( "fadeTo", "vff" ); -const idEventDef EV_Thread_StartMusic( "music", "s" ); -const idEventDef EV_Thread_Error( "error", "s" ); -const idEventDef EV_Thread_Warning( "warning", "s" ); -const idEventDef EV_Thread_StrLen( "strLength", "s", 'd' ); -const idEventDef EV_Thread_StrLeft( "strLeft", "sd", 's' ); -const idEventDef EV_Thread_StrRight( "strRight", "sd", 's' ); -const idEventDef EV_Thread_StrSkip( "strSkip", "sd", 's' ); -const idEventDef EV_Thread_StrMid( "strMid", "sdd", 's' ); -const idEventDef EV_Thread_StrToFloat( "strToFloat", "s", 'f' ); -const idEventDef EV_Thread_RadiusDamage( "radiusDamage", "vEEEsf" ); -const idEventDef EV_Thread_IsClient( "isClient", NULL, 'f' ); -const idEventDef EV_Thread_IsMultiplayer( "isMultiplayer", NULL, 'f' ); -const idEventDef EV_Thread_GetFrameTime( "getFrameTime", NULL, 'f' ); -const idEventDef EV_Thread_GetTicsPerSecond( "getTicsPerSecond", NULL, 'f' ); -const idEventDef EV_Thread_DebugLine( "debugLine", "vvvf" ); -const idEventDef EV_Thread_DebugArrow( "debugArrow", "vvvdf" ); -const idEventDef EV_Thread_DebugCircle( "debugCircle", "vvvfdf" ); -const idEventDef EV_Thread_DebugBounds( "debugBounds", "vvvf" ); -const idEventDef EV_Thread_DrawText( "drawText", "svfvdf" ); -const idEventDef EV_Thread_InfluenceActive( "influenceActive", NULL, 'd' ); - -CLASS_DECLARATION( idClass, idThread ) - EVENT( EV_Thread_Execute, idThread::Event_Execute ) - EVENT( EV_Thread_TerminateThread, idThread::Event_TerminateThread ) - EVENT( EV_Thread_Pause, idThread::Event_Pause ) - EVENT( EV_Thread_Wait, idThread::Event_Wait ) - EVENT( EV_Thread_WaitFrame, idThread::Event_WaitFrame ) - EVENT( EV_Thread_WaitFor, idThread::Event_WaitFor ) - EVENT( EV_Thread_WaitForThread, idThread::Event_WaitForThread ) - EVENT( EV_Thread_Print, idThread::Event_Print ) - EVENT( EV_Thread_PrintLn, idThread::Event_PrintLn ) - EVENT( EV_Thread_Say, idThread::Event_Say ) - EVENT( EV_Thread_Assert, idThread::Event_Assert ) - EVENT( EV_Thread_Trigger, idThread::Event_Trigger ) - EVENT( EV_Thread_SetCvar, idThread::Event_SetCvar ) - EVENT( EV_Thread_GetCvar, idThread::Event_GetCvar ) - EVENT( EV_Thread_Random, idThread::Event_Random ) -#ifdef _D3XP - EVENT( EV_Thread_RandomInt, idThread::Event_RandomInt ) -#endif - EVENT( EV_Thread_GetTime, idThread::Event_GetTime ) - EVENT( EV_Thread_KillThread, idThread::Event_KillThread ) - EVENT( EV_Thread_SetThreadName, idThread::Event_SetThreadName ) - EVENT( EV_Thread_GetEntity, idThread::Event_GetEntity ) - EVENT( EV_Thread_Spawn, idThread::Event_Spawn ) - EVENT( EV_Thread_CopySpawnArgs, idThread::Event_CopySpawnArgs ) - EVENT( EV_Thread_SetSpawnArg, idThread::Event_SetSpawnArg ) - EVENT( EV_Thread_SpawnString, idThread::Event_SpawnString ) - EVENT( EV_Thread_SpawnFloat, idThread::Event_SpawnFloat ) - EVENT( EV_Thread_SpawnVector, idThread::Event_SpawnVector ) - EVENT( EV_Thread_ClearPersistantArgs, idThread::Event_ClearPersistantArgs ) - EVENT( EV_Thread_SetPersistantArg, idThread::Event_SetPersistantArg ) - EVENT( EV_Thread_GetPersistantString, idThread::Event_GetPersistantString ) - EVENT( EV_Thread_GetPersistantFloat, idThread::Event_GetPersistantFloat ) - EVENT( EV_Thread_GetPersistantVector, idThread::Event_GetPersistantVector ) - EVENT( EV_Thread_AngToForward, idThread::Event_AngToForward ) - EVENT( EV_Thread_AngToRight, idThread::Event_AngToRight ) - EVENT( EV_Thread_AngToUp, idThread::Event_AngToUp ) - EVENT( EV_Thread_Sine, idThread::Event_GetSine ) - EVENT( EV_Thread_Cosine, idThread::Event_GetCosine ) -#ifdef _D3XP - EVENT( EV_Thread_ArcSine, idThread::Event_GetArcSine ) - EVENT( EV_Thread_ArcCosine, idThread::Event_GetArcCosine ) -#endif - EVENT( EV_Thread_SquareRoot, idThread::Event_GetSquareRoot ) - EVENT( EV_Thread_Normalize, idThread::Event_VecNormalize ) - EVENT( EV_Thread_VecLength, idThread::Event_VecLength ) - EVENT( EV_Thread_VecDotProduct, idThread::Event_VecDotProduct ) - EVENT( EV_Thread_VecCrossProduct, idThread::Event_VecCrossProduct ) - EVENT( EV_Thread_VecToAngles, idThread::Event_VecToAngles ) -#ifdef _D3XP - EVENT( EV_Thread_VecToOrthoBasisAngles, idThread::Event_VecToOrthoBasisAngles ) - EVENT( EV_Thread_RotateVector, idThread::Event_RotateVector ) -#endif - EVENT( EV_Thread_OnSignal, idThread::Event_OnSignal ) - EVENT( EV_Thread_ClearSignal, idThread::Event_ClearSignalThread ) - EVENT( EV_Thread_SetCamera, idThread::Event_SetCamera ) - EVENT( EV_Thread_FirstPerson, idThread::Event_FirstPerson ) - EVENT( EV_Thread_Trace, idThread::Event_Trace ) - EVENT( EV_Thread_TracePoint, idThread::Event_TracePoint ) - EVENT( EV_Thread_GetTraceFraction, idThread::Event_GetTraceFraction ) - EVENT( EV_Thread_GetTraceEndPos, idThread::Event_GetTraceEndPos ) - EVENT( EV_Thread_GetTraceNormal, idThread::Event_GetTraceNormal ) - EVENT( EV_Thread_GetTraceEntity, idThread::Event_GetTraceEntity ) - EVENT( EV_Thread_GetTraceJoint, idThread::Event_GetTraceJoint ) - EVENT( EV_Thread_GetTraceBody, idThread::Event_GetTraceBody ) - EVENT( EV_Thread_FadeIn, idThread::Event_FadeIn ) - EVENT( EV_Thread_FadeOut, idThread::Event_FadeOut ) - EVENT( EV_Thread_FadeTo, idThread::Event_FadeTo ) - EVENT( EV_SetShaderParm, idThread::Event_SetShaderParm ) - EVENT( EV_Thread_StartMusic, idThread::Event_StartMusic ) - EVENT( EV_Thread_Warning, idThread::Event_Warning ) - EVENT( EV_Thread_Error, idThread::Event_Error ) - EVENT( EV_Thread_StrLen, idThread::Event_StrLen ) - EVENT( EV_Thread_StrLeft, idThread::Event_StrLeft ) - EVENT( EV_Thread_StrRight, idThread::Event_StrRight ) - EVENT( EV_Thread_StrSkip, idThread::Event_StrSkip ) - EVENT( EV_Thread_StrMid, idThread::Event_StrMid ) - EVENT( EV_Thread_StrToFloat, idThread::Event_StrToFloat ) - EVENT( EV_Thread_RadiusDamage, idThread::Event_RadiusDamage ) - EVENT( EV_Thread_IsClient, idThread::Event_IsClient ) - EVENT( EV_Thread_IsMultiplayer, idThread::Event_IsMultiplayer ) - EVENT( EV_Thread_GetFrameTime, idThread::Event_GetFrameTime ) - EVENT( EV_Thread_GetTicsPerSecond, idThread::Event_GetTicsPerSecond ) - EVENT( EV_CacheSoundShader, idThread::Event_CacheSoundShader ) - EVENT( EV_Thread_DebugLine, idThread::Event_DebugLine ) - EVENT( EV_Thread_DebugArrow, idThread::Event_DebugArrow ) - EVENT( EV_Thread_DebugCircle, idThread::Event_DebugCircle ) - EVENT( EV_Thread_DebugBounds, idThread::Event_DebugBounds ) - EVENT( EV_Thread_DrawText, idThread::Event_DrawText ) - EVENT( EV_Thread_InfluenceActive, idThread::Event_InfluenceActive ) -END_CLASS - -idThread *idThread::currentThread = NULL; -int idThread::threadIndex = 0; -idList idThread::threadList; -trace_t idThread::trace; - -/* -================ -idThread::CurrentThread -================ -*/ -idThread *idThread::CurrentThread( void ) { - return currentThread; -} - -/* -================ -idThread::CurrentThreadNum -================ -*/ -int idThread::CurrentThreadNum( void ) { - if ( currentThread ) { - return currentThread->GetThreadNum(); - } else { - return 0; - } -} - -/* -================ -idThread::BeginMultiFrameEvent -================ -*/ -bool idThread::BeginMultiFrameEvent( idEntity *ent, const idEventDef *event ) { - if ( !currentThread ) { - gameLocal.Error( "idThread::BeginMultiFrameEvent called without a current thread" ); - } - return currentThread->interpreter.BeginMultiFrameEvent( ent, event ); -} - -/* -================ -idThread::EndMultiFrameEvent -================ -*/ -void idThread::EndMultiFrameEvent( idEntity *ent, const idEventDef *event ) { - if ( !currentThread ) { - gameLocal.Error( "idThread::EndMultiFrameEvent called without a current thread" ); - } - currentThread->interpreter.EndMultiFrameEvent( ent, event ); -} - -/* -================ -idThread::idThread -================ -*/ -idThread::idThread() { - Init(); - SetThreadName( va( "thread_%d", threadIndex ) ); - if ( g_debugScript.GetBool() ) { - gameLocal.Printf( "%d: create thread (%d) '%s'\n", gameLocal.time, threadNum, threadName.c_str() ); - } -} - -/* -================ -idThread::idThread -================ -*/ -idThread::idThread( idEntity *self, const function_t *func ) { - assert( self ); - - Init(); - SetThreadName( self->name ); - interpreter.EnterObjectFunction( self, func, false ); - if ( g_debugScript.GetBool() ) { - gameLocal.Printf( "%d: create thread (%d) '%s'\n", gameLocal.time, threadNum, threadName.c_str() ); - } -} - -/* -================ -idThread::idThread -================ -*/ -idThread::idThread( const function_t *func ) { - assert( func ); - - Init(); - SetThreadName( func->Name() ); - interpreter.EnterFunction( func, false ); - if ( g_debugScript.GetBool() ) { - gameLocal.Printf( "%d: create thread (%d) '%s'\n", gameLocal.time, threadNum, threadName.c_str() ); - } -} - -/* -================ -idThread::idThread -================ -*/ -idThread::idThread( idInterpreter *source, const function_t *func, int args ) { - Init(); - interpreter.ThreadCall( source, func, args ); - if ( g_debugScript.GetBool() ) { - gameLocal.Printf( "%d: create thread (%d) '%s'\n", gameLocal.time, threadNum, threadName.c_str() ); - } -} - -/* -================ -idThread::idThread -================ -*/ -idThread::idThread( idInterpreter *source, idEntity *self, const function_t *func, int args ) { - assert( self ); - - Init(); - SetThreadName( self->name ); - interpreter.ThreadCall( source, func, args ); - if ( g_debugScript.GetBool() ) { - gameLocal.Printf( "%d: create thread (%d) '%s'\n", gameLocal.time, threadNum, threadName.c_str() ); - } -} - -/* -================ -idThread::~idThread -================ -*/ -idThread::~idThread() { - idThread *thread; - int i; - int n; - - if ( g_debugScript.GetBool() ) { - gameLocal.Printf( "%d: end thread (%d) '%s'\n", gameLocal.time, threadNum, threadName.c_str() ); - } - threadList.Remove( this ); - n = threadList.Num(); - for( i = 0; i < n; i++ ) { - thread = threadList[ i ]; - if ( thread->WaitingOnThread() == this ) { - thread->ThreadCallback( this ); - } - } - - if ( currentThread == this ) { - currentThread = NULL; - } -} - -/* -================ -idThread::ManualDelete -================ -*/ -void idThread::ManualDelete( void ) { - interpreter.terminateOnExit = false; -} - -/* -================ -idThread::Save -================ -*/ -void idThread::Save( idSaveGame *savefile ) const { - - // We will check on restore that threadNum is still the same, - // threads should have been restored in the same order. - savefile->WriteInt( threadNum ); - - savefile->WriteObject( waitingForThread ); - savefile->WriteInt( waitingFor ); - savefile->WriteInt( waitingUntil ); - - interpreter.Save( savefile ); - - savefile->WriteDict( &spawnArgs ); - savefile->WriteString( threadName ); - - savefile->WriteInt( lastExecuteTime ); - savefile->WriteInt( creationTime ); - - savefile->WriteBool( manualControl ); -} - -/* -================ -idThread::Restore -================ -*/ -void idThread::Restore( idRestoreGame *savefile ) { - savefile->ReadInt( threadNum ); - - savefile->ReadObject( reinterpret_cast( waitingForThread ) ); - savefile->ReadInt( waitingFor ); - savefile->ReadInt( waitingUntil ); - - interpreter.Restore( savefile ); - - savefile->ReadDict( &spawnArgs ); - savefile->ReadString( threadName ); - - savefile->ReadInt( lastExecuteTime ); - savefile->ReadInt( creationTime ); - - savefile->ReadBool( manualControl ); -} - -/* -================ -idThread::Init -================ -*/ -void idThread::Init( void ) { - // create a unique threadNum - do { - threadIndex++; - if ( threadIndex == 0 ) { - threadIndex = 1; - } - } while( GetThread( threadIndex ) ); - - threadNum = threadIndex; - threadList.Append( this ); - - creationTime = gameLocal.time; - lastExecuteTime = 0; - manualControl = false; - - ClearWaitFor(); - - interpreter.SetThread( this ); -} - -/* -================ -idThread::GetThread -================ -*/ -idThread *idThread::GetThread( int num ) { - int i; - int n; - idThread *thread; - - n = threadList.Num(); - for( i = 0; i < n; i++ ) { - thread = threadList[ i ]; - if ( thread->GetThreadNum() == num ) { - return thread; - } - } - - return NULL; -} - -/* -================ -idThread::DisplayInfo -================ -*/ -void idThread::DisplayInfo( void ) { - gameLocal.Printf( - "%12i: '%s'\n" - " File: %s(%d)\n" - " Created: %d (%d ms ago)\n" - " Status: ", - threadNum, threadName.c_str(), - interpreter.CurrentFile(), interpreter.CurrentLine(), - creationTime, gameLocal.time - creationTime ); - - if ( interpreter.threadDying ) { - gameLocal.Printf( "Dying\n" ); - } else if ( interpreter.doneProcessing ) { - gameLocal.Printf( - "Paused since %d (%d ms)\n" - " Reason: ", lastExecuteTime, gameLocal.time - lastExecuteTime ); - if ( waitingForThread ) { - gameLocal.Printf( "Waiting for thread #%3i '%s'\n", waitingForThread->GetThreadNum(), waitingForThread->GetThreadName() ); - } else if ( ( waitingFor != ENTITYNUM_NONE ) && ( gameLocal.entities[ waitingFor ] ) ) { - gameLocal.Printf( "Waiting for entity #%3i '%s'\n", waitingFor, gameLocal.entities[ waitingFor ]->name.c_str() ); - } else if ( waitingUntil ) { - gameLocal.Printf( "Waiting until %d (%d ms total wait time)\n", waitingUntil, waitingUntil - lastExecuteTime ); - } else { - gameLocal.Printf( "None\n" ); - } - } else { - gameLocal.Printf( "Processing\n" ); - } - - interpreter.DisplayInfo(); - - gameLocal.Printf( "\n" ); -} - -/* -================ -idThread::ListThreads_f -================ -*/ -void idThread::ListThreads_f( const idCmdArgs &args ) { - int i; - int n; - - n = threadList.Num(); - for( i = 0; i < n; i++ ) { - //threadList[ i ]->DisplayInfo(); - gameLocal.Printf( "%3i: %-20s : %s(%d)\n", threadList[ i ]->threadNum, threadList[ i ]->threadName.c_str(), threadList[ i ]->interpreter.CurrentFile(), threadList[ i ]->interpreter.CurrentLine() ); - } - gameLocal.Printf( "%d active threads\n\n", n ); -} - -/* -================ -idThread::Restart -================ -*/ -void idThread::Restart( void ) { - int i; - int n; - - // reset the threadIndex - threadIndex = 0; - - currentThread = NULL; - n = threadList.Num(); - for( i = n - 1; i >= 0; i-- ) { - delete threadList[ i ]; - } - threadList.Clear(); - - memset( &trace, 0, sizeof( trace ) ); - trace.c.entityNum = ENTITYNUM_NONE; -} - -/* -================ -idThread::DelayedStart -================ -*/ -void idThread::DelayedStart( int delay ) { - CancelEvents( &EV_Thread_Execute ); - if ( gameLocal.time <= 0 ) { - delay++; - } - PostEventMS( &EV_Thread_Execute, delay ); -} - -/* -================ -idThread::Start -================ -*/ -bool idThread::Start( void ) { - bool result; - - CancelEvents( &EV_Thread_Execute ); - result = Execute(); - - return result; -} - -/* -================ -idThread::SetThreadName -================ -*/ -void idThread::SetThreadName( const char *name ) { - threadName = name; -} - -/* -================ -idThread::ObjectMoveDone -================ -*/ -void idThread::ObjectMoveDone( int threadnum, idEntity *obj ) { - idThread *thread; - - if ( !threadnum ) { - return; - } - - thread = GetThread( threadnum ); - if ( thread ) { - thread->ObjectMoveDone( obj ); - } -} - -/* -================ -idThread::End -================ -*/ -void idThread::End( void ) { - // Tell thread to die. It will exit on its own. - Pause(); - interpreter.threadDying = true; -} - -/* -================ -idThread::KillThread -================ -*/ -void idThread::KillThread( const char *name ) { - int i; - int num; - int len; - const char *ptr; - idThread *thread; - - // see if the name uses a wild card - ptr = strchr( name, '*' ); - if ( ptr ) { - len = ptr - name; - } else { - len = strlen( name ); - } - - // kill only those threads whose name matches name - num = threadList.Num(); - for( i = 0; i < num; i++ ) { - thread = threadList[ i ]; - if ( !idStr::Cmpn( thread->GetThreadName(), name, len ) ) { - thread->End(); - } - } -} - -/* -================ -idThread::KillThread -================ -*/ -void idThread::KillThread( int num ) { - idThread *thread; - - thread = GetThread( num ); - if ( thread ) { - // Tell thread to die. It will delete itself on it's own. - thread->End(); - } -} - -/* -================ -idThread::Execute -================ -*/ -bool idThread::Execute( void ) { - idThread *oldThread; - bool done; - - if ( manualControl && ( waitingUntil > gameLocal.time ) ) { - return false; - } - - oldThread = currentThread; - currentThread = this; - - lastExecuteTime = gameLocal.time; - ClearWaitFor(); - done = interpreter.Execute(); - if ( done ) { - End(); - if ( interpreter.terminateOnExit ) { - PostEventMS( &EV_Remove, 0 ); - } - } else if ( !manualControl ) { - if ( waitingUntil > lastExecuteTime ) { - PostEventMS( &EV_Thread_Execute, waitingUntil - lastExecuteTime ); - } else if ( interpreter.MultiFrameEventInProgress() ) { - PostEventMS( &EV_Thread_Execute, gameLocal.msec ); - } - } - - currentThread = oldThread; - - return done; -} - -/* -================ -idThread::IsWaiting - -Checks if thread is still waiting for some event to occur. -================ -*/ -bool idThread::IsWaiting( void ) { - if ( waitingForThread || ( waitingFor != ENTITYNUM_NONE ) ) { - return true; - } - - if ( waitingUntil && ( waitingUntil > gameLocal.time ) ) { - return true; - } - - return false; -} - -/* -================ -idThread::CallFunction - -NOTE: If this is called from within a event called by this thread, the function arguments will be invalid after calling this function. -================ -*/ -void idThread::CallFunction( const function_t *func, bool clearStack ) { - ClearWaitFor(); - interpreter.EnterFunction( func, clearStack ); -} - -/* -================ -idThread::CallFunction - -NOTE: If this is called from within a event called by this thread, the function arguments will be invalid after calling this function. -================ -*/ -void idThread::CallFunction( idEntity *self, const function_t *func, bool clearStack ) { - assert( self ); - ClearWaitFor(); - interpreter.EnterObjectFunction( self, func, clearStack ); -} - -/* -================ -idThread::ClearWaitFor -================ -*/ -void idThread::ClearWaitFor( void ) { - waitingFor = ENTITYNUM_NONE; - waitingForThread = NULL; - waitingUntil = 0; -} - -/* -================ -idThread::IsWaitingFor -================ -*/ -bool idThread::IsWaitingFor( idEntity *obj ) { - assert( obj ); - return waitingFor == obj->entityNumber; -} - -/* -================ -idThread::ObjectMoveDone -================ -*/ -void idThread::ObjectMoveDone( idEntity *obj ) { - assert( obj ); - - if ( IsWaitingFor( obj ) ) { - ClearWaitFor(); - DelayedStart( 0 ); - } -} - -/* -================ -idThread::ThreadCallback -================ -*/ -void idThread::ThreadCallback( idThread *thread ) { - if ( interpreter.threadDying ) { - return; - } - - if ( thread == waitingForThread ) { - ClearWaitFor(); - DelayedStart( 0 ); - } -} - -/* -================ -idThread::Event_SetThreadName -================ -*/ -void idThread::Event_SetThreadName( const char *name ) { - SetThreadName( name ); -} - -/* -================ -idThread::Error -================ -*/ -void idThread::Error( const char *fmt, ... ) const { - va_list argptr; - char text[ 1024 ]; - - va_start( argptr, fmt ); - vsprintf( text, fmt, argptr ); - va_end( argptr ); - - interpreter.Error( text ); -} - -/* -================ -idThread::Warning -================ -*/ -void idThread::Warning( const char *fmt, ... ) const { - va_list argptr; - char text[ 1024 ]; - - va_start( argptr, fmt ); - vsprintf( text, fmt, argptr ); - va_end( argptr ); - - interpreter.Warning( text ); -} - -/* -================ -idThread::ReturnString -================ -*/ -void idThread::ReturnString( const char *text ) { - gameLocal.program.ReturnString( text ); -} - -/* -================ -idThread::ReturnFloat -================ -*/ -void idThread::ReturnFloat( float value ) { - gameLocal.program.ReturnFloat( value ); -} - -/* -================ -idThread::ReturnInt -================ -*/ -void idThread::ReturnInt( int value ) { - // true integers aren't supported in the compiler, - // so int values are stored as floats - gameLocal.program.ReturnFloat( value ); -} - -/* -================ -idThread::ReturnVector -================ -*/ -void idThread::ReturnVector( idVec3 const &vec ) { - gameLocal.program.ReturnVector( vec ); -} - -/* -================ -idThread::ReturnEntity -================ -*/ -void idThread::ReturnEntity( idEntity *ent ) { - gameLocal.program.ReturnEntity( ent ); -} - -/* -================ -idThread::Event_Execute -================ -*/ -void idThread::Event_Execute( void ) { - Execute(); -} - -/* -================ -idThread::Pause -================ -*/ -void idThread::Pause( void ) { - ClearWaitFor(); - interpreter.doneProcessing = true; -} - -/* -================ -idThread::WaitMS -================ -*/ -void idThread::WaitMS( int time ) { - Pause(); - waitingUntil = gameLocal.time + time; -} - -/* -================ -idThread::WaitSec -================ -*/ -void idThread::WaitSec( float time ) { - WaitMS( SEC2MS( time ) ); -} - -/* -================ -idThread::WaitFrame -================ -*/ -void idThread::WaitFrame( void ) { - Pause(); - - // manual control threads don't set waitingUntil so that they can be run again - // that frame if necessary. - if ( !manualControl ) { - waitingUntil = gameLocal.time + gameLocal.msec; - } -} - -/*********************************************************************** - - Script callable events - -***********************************************************************/ - -/* -================ -idThread::Event_TerminateThread -================ -*/ -void idThread::Event_TerminateThread( int num ) { - KillThread( num ); -} - -/* -================ -idThread::Event_Pause -================ -*/ -void idThread::Event_Pause( void ) { - Pause(); -} - -/* -================ -idThread::Event_Wait -================ -*/ -void idThread::Event_Wait( float time ) { - WaitSec( time ); -} - -/* -================ -idThread::Event_WaitFrame -================ -*/ -void idThread::Event_WaitFrame( void ) { - WaitFrame(); -} - -/* -================ -idThread::Event_WaitFor -================ -*/ -void idThread::Event_WaitFor( idEntity *ent ) { - if ( ent && ent->RespondsTo( EV_Thread_SetCallback ) ) { - ent->ProcessEvent( &EV_Thread_SetCallback ); - if ( gameLocal.program.GetReturnedInteger() ) { - Pause(); - waitingFor = ent->entityNumber; - } - } -} - -/* -================ -idThread::Event_WaitForThread -================ -*/ -void idThread::Event_WaitForThread( int num ) { - idThread *thread; - - thread = GetThread( num ); - if ( !thread ) { - if ( g_debugScript.GetBool() ) { - // just print a warning and continue executing - Warning( "Thread %d not running", num ); - } - } else { - Pause(); - waitingForThread = thread; - } -} - -/* -================ -idThread::Event_Print -================ -*/ -void idThread::Event_Print( const char *text ) { - gameLocal.Printf( "%s", text ); -} - -/* -================ -idThread::Event_PrintLn -================ -*/ -void idThread::Event_PrintLn( const char *text ) { - gameLocal.Printf( "%s\n", text ); -} - -/* -================ -idThread::Event_Say -================ -*/ -void idThread::Event_Say( const char *text ) { - cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "say \"%s\"", text ) ); -} - -/* -================ -idThread::Event_Assert -================ -*/ -void idThread::Event_Assert( float value ) { - assert( value ); -} - -/* -================ -idThread::Event_Trigger -================ -*/ -void idThread::Event_Trigger( idEntity *ent ) { - if ( ent ) { - ent->Signal( SIG_TRIGGER ); - ent->ProcessEvent( &EV_Activate, gameLocal.GetLocalPlayer() ); - ent->TriggerGuis(); - } -} - -/* -================ -idThread::Event_SetCvar -================ -*/ -void idThread::Event_SetCvar( const char *name, const char *value ) const { - cvarSystem->SetCVarString( name, value ); -} - -/* -================ -idThread::Event_GetCvar -================ -*/ -void idThread::Event_GetCvar( const char *name ) const { - ReturnString( cvarSystem->GetCVarString( name ) ); -} - -/* -================ -idThread::Event_Random -================ -*/ -void idThread::Event_Random( float range ) const { - float result; - - result = gameLocal.random.RandomFloat(); - ReturnFloat( range * result ); -} - -#ifdef _D3XP - -void idThread::Event_RandomInt( int range ) const { - int result; - result = gameLocal.random.RandomInt(range); - ReturnFloat(result); -} - -#endif - -/* -================ -idThread::Event_GetTime -================ -*/ -void idThread::Event_GetTime( void ) { - ReturnFloat( MS2SEC( gameLocal.realClientTime ) ); -} - -/* -================ -idThread::Event_KillThread -================ -*/ -void idThread::Event_KillThread( const char *name ) { - KillThread( name ); -} - -/* -================ -idThread::Event_GetEntity -================ -*/ -void idThread::Event_GetEntity( const char *name ) { - int entnum; - idEntity *ent; - - assert( name ); - - if ( name[ 0 ] == '*' ) { - entnum = atoi( &name[ 1 ] ); - if ( ( entnum < 0 ) || ( entnum >= MAX_GENTITIES ) ) { - Error( "Entity number in string out of range." ); - } - ReturnEntity( gameLocal.entities[ entnum ] ); - } else { - ent = gameLocal.FindEntity( name ); - ReturnEntity( ent ); - } -} - -/* -================ -idThread::Event_Spawn -================ -*/ -void idThread::Event_Spawn( const char *classname ) { - idEntity *ent; - - spawnArgs.Set( "classname", classname ); - gameLocal.SpawnEntityDef( spawnArgs, &ent ); - ReturnEntity( ent ); - spawnArgs.Clear(); -} - -/* -================ -idThread::Event_CopySpawnArgs -================ -*/ -void idThread::Event_CopySpawnArgs( idEntity *ent ) { - spawnArgs.Copy( ent->spawnArgs ); -} - -/* -================ -idThread::Event_SetSpawnArg -================ -*/ -void idThread::Event_SetSpawnArg( const char *key, const char *value ) { - spawnArgs.Set( key, value ); -} - -/* -================ -idThread::Event_SpawnString -================ -*/ -void idThread::Event_SpawnString( const char *key, const char *defaultvalue ) { - const char *result; - - spawnArgs.GetString( key, defaultvalue, &result ); - ReturnString( result ); -} - -/* -================ -idThread::Event_SpawnFloat -================ -*/ -void idThread::Event_SpawnFloat( const char *key, float defaultvalue ) { - float result; - - spawnArgs.GetFloat( key, va( "%f", defaultvalue ), result ); - ReturnFloat( result ); -} - -/* -================ -idThread::Event_SpawnVector -================ -*/ -void idThread::Event_SpawnVector( const char *key, idVec3 &defaultvalue ) { - idVec3 result; - - spawnArgs.GetVector( key, va( "%f %f %f", defaultvalue.x, defaultvalue.y, defaultvalue.z ), result ); - ReturnVector( result ); -} - -/* -================ -idThread::Event_ClearPersistantArgs -================ -*/ -void idThread::Event_ClearPersistantArgs( void ) { - gameLocal.persistentLevelInfo.Clear(); -} - - -/* -================ -idThread::Event_SetPersistantArg -================ -*/ -void idThread::Event_SetPersistantArg( const char *key, const char *value ) { - gameLocal.persistentLevelInfo.Set( key, value ); -} - -/* -================ -idThread::Event_GetPersistantString -================ -*/ -void idThread::Event_GetPersistantString( const char *key ) { - const char *result; - - gameLocal.persistentLevelInfo.GetString( key, "", &result ); - ReturnString( result ); -} - -/* -================ -idThread::Event_GetPersistantFloat -================ -*/ -void idThread::Event_GetPersistantFloat( const char *key ) { - float result; - - gameLocal.persistentLevelInfo.GetFloat( key, "0", result ); - ReturnFloat( result ); -} - -/* -================ -idThread::Event_GetPersistantVector -================ -*/ -void idThread::Event_GetPersistantVector( const char *key ) { - idVec3 result; - - gameLocal.persistentLevelInfo.GetVector( key, "0 0 0", result ); - ReturnVector( result ); -} - -/* -================ -idThread::Event_AngToForward -================ -*/ -void idThread::Event_AngToForward( idAngles &ang ) { - ReturnVector( ang.ToForward() ); -} - -/* -================ -idThread::Event_AngToRight -================ -*/ -void idThread::Event_AngToRight( idAngles &ang ) { - idVec3 vec; - - ang.ToVectors( NULL, &vec ); - ReturnVector( vec ); -} - -/* -================ -idThread::Event_AngToUp -================ -*/ -void idThread::Event_AngToUp( idAngles &ang ) { - idVec3 vec; - - ang.ToVectors( NULL, NULL, &vec ); - ReturnVector( vec ); -} - -/* -================ -idThread::Event_GetSine -================ -*/ -void idThread::Event_GetSine( float angle ) { - ReturnFloat( idMath::Sin( DEG2RAD( angle ) ) ); -} - -/* -================ -idThread::Event_GetCosine -================ -*/ -void idThread::Event_GetCosine( float angle ) { - ReturnFloat( idMath::Cos( DEG2RAD( angle ) ) ); -} - -#ifdef _D3XP -/* -================ -idThread::Event_GetArcSine -================ -*/ -void idThread::Event_GetArcSine( float a ) { - ReturnFloat(RAD2DEG(idMath::ASin(a))); -} - -/* -================ -idThread::Event_GetArcCosine -================ -*/ -void idThread::Event_GetArcCosine( float a ) { - ReturnFloat(RAD2DEG(idMath::ACos(a))); -} -#endif - -/* -================ -idThread::Event_GetSquareRoot -================ -*/ -void idThread::Event_GetSquareRoot( float theSquare ) { - ReturnFloat( idMath::Sqrt( theSquare ) ); -} - -/* -================ -idThread::Event_VecNormalize -================ -*/ -void idThread::Event_VecNormalize( idVec3 &vec ) { - idVec3 n; - - n = vec; - n.Normalize(); - ReturnVector( n ); -} - -/* -================ -idThread::Event_VecLength -================ -*/ -void idThread::Event_VecLength( idVec3 &vec ) { - ReturnFloat( vec.Length() ); -} - -/* -================ -idThread::Event_VecDotProduct -================ -*/ -void idThread::Event_VecDotProduct( idVec3 &vec1, idVec3 &vec2 ) { - ReturnFloat( vec1 * vec2 ); -} - -/* -================ -idThread::Event_VecCrossProduct -================ -*/ -void idThread::Event_VecCrossProduct( idVec3 &vec1, idVec3 &vec2 ) { - ReturnVector( vec1.Cross( vec2 ) ); -} - -/* -================ -idThread::Event_VecToAngles -================ -*/ -void idThread::Event_VecToAngles( idVec3 &vec ) { - idAngles ang = vec.ToAngles(); - ReturnVector( idVec3( ang[0], ang[1], ang[2] ) ); -} - -#ifdef _D3XP -/* -================ -idThread::Event_VecToOrthoBasisAngles -================ -*/ -void idThread::Event_VecToOrthoBasisAngles( idVec3 &vec ) { - idVec3 left, up; - idAngles ang; - - vec.OrthogonalBasis( left, up ); - idMat3 axis( left, up, vec ); - - ang = axis.ToAngles(); - - ReturnVector( idVec3( ang[0], ang[1], ang[2] ) ); -} - -void idThread::Event_RotateVector( idVec3 &vec, idVec3 &ang ) { - - idAngles tempAng(ang); - idMat3 axis = tempAng.ToMat3(); - idVec3 ret = vec * axis; - ReturnVector(ret); - -} -#endif - -/* -================ -idThread::Event_OnSignal -================ -*/ -void idThread::Event_OnSignal( int signal, idEntity *ent, const char *func ) { - const function_t *function; - - assert( func ); - - if ( !ent ) { - Error( "Entity not found" ); - } - - if ( ( signal < 0 ) || ( signal >= NUM_SIGNALS ) ) { - Error( "Signal out of range" ); - } - - function = gameLocal.program.FindFunction( func ); - if ( !function ) { - Error( "Function '%s' not found", func ); - } - - ent->SetSignal( ( signalNum_t )signal, this, function ); -} - -/* -================ -idThread::Event_ClearSignalThread -================ -*/ -void idThread::Event_ClearSignalThread( int signal, idEntity *ent ) { - if ( !ent ) { - Error( "Entity not found" ); - } - - if ( ( signal < 0 ) || ( signal >= NUM_SIGNALS ) ) { - Error( "Signal out of range" ); - } - - ent->ClearSignalThread( ( signalNum_t )signal, this ); -} - -/* -================ -idThread::Event_SetCamera -================ -*/ -void idThread::Event_SetCamera( idEntity *ent ) { - if ( !ent ) { - Error( "Entity not found" ); - return; - } - - if ( !ent->IsType( idCamera::Type ) ) { - Error( "Entity is not a camera" ); - return; - } - - gameLocal.SetCamera( ( idCamera * )ent ); -} - -/* -================ -idThread::Event_FirstPerson -================ -*/ -void idThread::Event_FirstPerson( void ) { - gameLocal.SetCamera( NULL ); -} - -/* -================ -idThread::Event_Trace -================ -*/ -void idThread::Event_Trace( const idVec3 &start, const idVec3 &end, const idVec3 &mins, const idVec3 &maxs, int contents_mask, idEntity *passEntity ) { - if ( mins == vec3_origin && maxs == vec3_origin ) { - gameLocal.clip.TracePoint( trace, start, end, contents_mask, passEntity ); - } else { - gameLocal.clip.TraceBounds( trace, start, end, idBounds( mins, maxs ), contents_mask, passEntity ); - } - ReturnFloat( trace.fraction ); -} - -/* -================ -idThread::Event_TracePoint -================ -*/ -void idThread::Event_TracePoint( const idVec3 &start, const idVec3 &end, int contents_mask, idEntity *passEntity ) { - gameLocal.clip.TracePoint( trace, start, end, contents_mask, passEntity ); - ReturnFloat( trace.fraction ); -} - -/* -================ -idThread::Event_GetTraceFraction -================ -*/ -void idThread::Event_GetTraceFraction( void ) { - ReturnFloat( trace.fraction ); -} - -/* -================ -idThread::Event_GetTraceEndPos -================ -*/ -void idThread::Event_GetTraceEndPos( void ) { - ReturnVector( trace.endpos ); -} - -/* -================ -idThread::Event_GetTraceNormal -================ -*/ -void idThread::Event_GetTraceNormal( void ) { - if ( trace.fraction < 1.0f ) { - ReturnVector( trace.c.normal ); - } else { - ReturnVector( vec3_origin ); - } -} - -/* -================ -idThread::Event_GetTraceEntity -================ -*/ -void idThread::Event_GetTraceEntity( void ) { - if ( trace.fraction < 1.0f ) { - ReturnEntity( gameLocal.entities[ trace.c.entityNum ] ); - } else { - ReturnEntity( ( idEntity * )NULL ); - } -} - -/* -================ -idThread::Event_GetTraceJoint -================ -*/ -void idThread::Event_GetTraceJoint( void ) { - if ( trace.fraction < 1.0f && trace.c.id < 0 ) { - idAFEntity_Base *af = static_cast( gameLocal.entities[ trace.c.entityNum ] ); - if ( af && af->IsType( idAFEntity_Base::Type ) && af->IsActiveAF() ) { - ReturnString( af->GetAnimator()->GetJointName( CLIPMODEL_ID_TO_JOINT_HANDLE( trace.c.id ) ) ); - return; - } - } - ReturnString( "" ); -} - -/* -================ -idThread::Event_GetTraceBody -================ -*/ -void idThread::Event_GetTraceBody( void ) { - if ( trace.fraction < 1.0f && trace.c.id < 0 ) { - idAFEntity_Base *af = static_cast( gameLocal.entities[ trace.c.entityNum ] ); - if ( af && af->IsType( idAFEntity_Base::Type ) && af->IsActiveAF() ) { - int bodyId = af->BodyForClipModelId( trace.c.id ); - idAFBody *body = af->GetAFPhysics()->GetBody( bodyId ); - if ( body ) { - ReturnString( body->GetName() ); - return; - } - } - } - ReturnString( "" ); -} - -/* -================ -idThread::Event_FadeIn -================ -*/ -void idThread::Event_FadeIn( idVec3 &color, float time ) { - idVec4 fadeColor; - idPlayer *player; - - player = gameLocal.GetLocalPlayer(); - if ( player ) { - fadeColor.Set( color[ 0 ], color[ 1 ], color[ 2 ], 0.0f ); - player->playerView.Fade(fadeColor, SEC2MS( time ) ); - } -} - -/* -================ -idThread::Event_FadeOut -================ -*/ -void idThread::Event_FadeOut( idVec3 &color, float time ) { - idVec4 fadeColor; - idPlayer *player; - - player = gameLocal.GetLocalPlayer(); - if ( player ) { - fadeColor.Set( color[ 0 ], color[ 1 ], color[ 2 ], 1.0f ); - player->playerView.Fade(fadeColor, SEC2MS( time ) ); - } -} - -/* -================ -idThread::Event_FadeTo -================ -*/ -void idThread::Event_FadeTo( idVec3 &color, float alpha, float time ) { - idVec4 fadeColor; - idPlayer *player; - - player = gameLocal.GetLocalPlayer(); - if ( player ) { - fadeColor.Set( color[ 0 ], color[ 1 ], color[ 2 ], alpha ); - player->playerView.Fade(fadeColor, SEC2MS( time ) ); - } -} - -/* -================ -idThread::Event_SetShaderParm -================ -*/ -void idThread::Event_SetShaderParm( int parmnum, float value ) { - if ( ( parmnum < 0 ) || ( parmnum >= MAX_GLOBAL_SHADER_PARMS ) ) { - Error( "shader parm index (%d) out of range", parmnum ); - } - - gameLocal.globalShaderParms[ parmnum ] = value; -} - -/* -================ -idThread::Event_StartMusic -================ -*/ -void idThread::Event_StartMusic( const char *text ) { - gameSoundWorld->PlayShaderDirectly( text ); -} - -/* -================ -idThread::Event_Warning -================ -*/ -void idThread::Event_Warning( const char *text ) { - Warning( "%s", text ); -} - -/* -================ -idThread::Event_Error -================ -*/ -void idThread::Event_Error( const char *text ) { - Error( "%s", text ); -} - -/* -================ -idThread::Event_StrLen -================ -*/ -void idThread::Event_StrLen( const char *string ) { - int len; - - len = strlen( string ); - idThread::ReturnInt( len ); -} - -/* -================ -idThread::Event_StrLeft -================ -*/ -void idThread::Event_StrLeft( const char *string, int num ) { - int len; - - if ( num < 0 ) { - idThread::ReturnString( "" ); - return; - } - - len = strlen( string ); - if ( len < num ) { - idThread::ReturnString( string ); - return; - } - - idStr result( string, 0, num ); - idThread::ReturnString( result ); -} - -/* -================ -idThread::Event_StrRight -================ -*/ -void idThread::Event_StrRight( const char *string, int num ) { - int len; - - if ( num < 0 ) { - idThread::ReturnString( "" ); - return; - } - - len = strlen( string ); - if ( len < num ) { - idThread::ReturnString( string ); - return; - } - - idThread::ReturnString( string + len - num ); -} - -/* -================ -idThread::Event_StrSkip -================ -*/ -void idThread::Event_StrSkip( const char *string, int num ) { - int len; - - if ( num < 0 ) { - idThread::ReturnString( string ); - return; - } - - len = strlen( string ); - if ( len < num ) { - idThread::ReturnString( "" ); - return; - } - - idThread::ReturnString( string + num ); -} - -/* -================ -idThread::Event_StrMid -================ -*/ -void idThread::Event_StrMid( const char *string, int start, int num ) { - int len; - - if ( num < 0 ) { - idThread::ReturnString( "" ); - return; - } - - if ( start < 0 ) { - start = 0; - } - len = strlen( string ); - if ( start > len ) { - start = len; - } - - if ( start + num > len ) { - num = len - start; - } - - idStr result( string, start, start + num ); - idThread::ReturnString( result ); -} - -/* -================ -idThread::Event_StrToFloat( const char *string ) -================ -*/ -void idThread::Event_StrToFloat( const char *string ) { - float result; - - result = atof( string ); - idThread::ReturnFloat( result ); -} - -/* -================ -idThread::Event_RadiusDamage -================ -*/ -void idThread::Event_RadiusDamage( const idVec3 &origin, idEntity *inflictor, idEntity *attacker, idEntity *ignore, const char *damageDefName, float dmgPower ) { - gameLocal.RadiusDamage( origin, inflictor, attacker, ignore, ignore, damageDefName, dmgPower ); -} - -/* -================ -idThread::Event_IsClient -================ -*/ -void idThread::Event_IsClient( void ) { - idThread::ReturnFloat( gameLocal.isClient ); -} - -/* -================ -idThread::Event_IsMultiplayer -================ -*/ -void idThread::Event_IsMultiplayer( void ) { - idThread::ReturnFloat( gameLocal.isMultiplayer ); -} - -/* -================ -idThread::Event_GetFrameTime -================ -*/ -void idThread::Event_GetFrameTime( void ) { - idThread::ReturnFloat( MS2SEC( gameLocal.msec ) ); -} - -/* -================ -idThread::Event_GetTicsPerSecond -================ -*/ -void idThread::Event_GetTicsPerSecond( void ) { - idThread::ReturnFloat( USERCMD_HZ ); -} - -/* -================ -idThread::Event_CacheSoundShader -================ -*/ -void idThread::Event_CacheSoundShader( const char *soundName ) { - declManager->FindSound( soundName ); -} - -/* -================ -idThread::Event_DebugLine -================ -*/ -void idThread::Event_DebugLine( const idVec3 &color, const idVec3 &start, const idVec3 &end, const float lifetime ) { - gameRenderWorld->DebugLine( idVec4( color.x, color.y, color.z, 0.0f ), start, end, SEC2MS( lifetime ) ); -} - -/* -================ -idThread::Event_DebugArrow -================ -*/ -void idThread::Event_DebugArrow( const idVec3 &color, const idVec3 &start, const idVec3 &end, const int size, const float lifetime ) { - gameRenderWorld->DebugArrow( idVec4( color.x, color.y, color.z, 0.0f ), start, end, size, SEC2MS( lifetime ) ); -} - -/* -================ -idThread::Event_DebugCircle -================ -*/ -void idThread::Event_DebugCircle( const idVec3 &color, const idVec3 &origin, const idVec3 &dir, const float radius, const int numSteps, const float lifetime ) { - gameRenderWorld->DebugCircle( idVec4( color.x, color.y, color.z, 0.0f ), origin, dir, radius, numSteps, SEC2MS( lifetime ) ); -} - -/* -================ -idThread::Event_DebugBounds -================ -*/ -void idThread::Event_DebugBounds( const idVec3 &color, const idVec3 &mins, const idVec3 &maxs, const float lifetime ) { - gameRenderWorld->DebugBounds( idVec4( color.x, color.y, color.z, 0.0f ), idBounds( mins, maxs ), vec3_origin, SEC2MS( lifetime ) ); -} - -/* -================ -idThread::Event_DrawText -================ -*/ -void idThread::Event_DrawText( const char *text, const idVec3 &origin, float scale, const idVec3 &color, const int align, const float lifetime ) { - gameRenderWorld->DrawText( text, origin, scale, idVec4( color.x, color.y, color.z, 0.0f ), gameLocal.GetLocalPlayer()->viewAngles.ToMat3(), align, SEC2MS( lifetime ) ); -} - -/* -================ -idThread::Event_InfluenceActive -================ -*/ -void idThread::Event_InfluenceActive( void ) { - idPlayer *player; - - player = gameLocal.GetLocalPlayer(); - if ( player && player->GetInfluenceLevel() ) { - idThread::ReturnInt( true ); - } else { - idThread::ReturnInt( false ); - } -} diff --git a/d3xp/script/Script_Thread.h b/d3xp/script/Script_Thread.h deleted file mode 100644 index 7d776438..00000000 --- a/d3xp/script/Script_Thread.h +++ /dev/null @@ -1,344 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __SCRIPT_THREAD_H__ -#define __SCRIPT_THREAD_H__ - -#include "script/Script_Interpreter.h" -#include "gamesys/Class.h" -#include "gamesys/Event.h" - -extern const idEventDef EV_Thread_Execute; -extern const idEventDef EV_Thread_SetCallback; -extern const idEventDef EV_Thread_TerminateThread; -extern const idEventDef EV_Thread_Pause; -extern const idEventDef EV_Thread_Wait; -extern const idEventDef EV_Thread_WaitFrame; -extern const idEventDef EV_Thread_WaitFor; -extern const idEventDef EV_Thread_WaitForThread; -extern const idEventDef EV_Thread_Print; -extern const idEventDef EV_Thread_PrintLn; -extern const idEventDef EV_Thread_Say; -extern const idEventDef EV_Thread_Assert; -extern const idEventDef EV_Thread_Trigger; -extern const idEventDef EV_Thread_SetCvar; -extern const idEventDef EV_Thread_GetCvar; -extern const idEventDef EV_Thread_Random; -extern const idEventDef EV_Thread_GetTime; -extern const idEventDef EV_Thread_KillThread; -extern const idEventDef EV_Thread_SetThreadName; -extern const idEventDef EV_Thread_GetEntity; -extern const idEventDef EV_Thread_Spawn; -extern const idEventDef EV_Thread_SetSpawnArg; -extern const idEventDef EV_Thread_SpawnString; -extern const idEventDef EV_Thread_SpawnFloat; -extern const idEventDef EV_Thread_SpawnVector; -extern const idEventDef EV_Thread_AngToForward; -extern const idEventDef EV_Thread_AngToRight; -extern const idEventDef EV_Thread_AngToUp; -extern const idEventDef EV_Thread_Sine; -extern const idEventDef EV_Thread_Cosine; -extern const idEventDef EV_Thread_Normalize; -extern const idEventDef EV_Thread_VecLength; -extern const idEventDef EV_Thread_VecDotProduct; -extern const idEventDef EV_Thread_VecCrossProduct; -extern const idEventDef EV_Thread_OnSignal; -extern const idEventDef EV_Thread_ClearSignal; -extern const idEventDef EV_Thread_SetCamera; -extern const idEventDef EV_Thread_FirstPerson; -extern const idEventDef EV_Thread_TraceFraction; -extern const idEventDef EV_Thread_TracePos; -extern const idEventDef EV_Thread_FadeIn; -extern const idEventDef EV_Thread_FadeOut; -extern const idEventDef EV_Thread_FadeTo; -extern const idEventDef EV_Thread_Restart; - -class idThread : public idClass { -private: - static idThread *currentThread; - - idThread *waitingForThread; - int waitingFor; - int waitingUntil; - idInterpreter interpreter; - - idDict spawnArgs; - - int threadNum; - idStr threadName; - - int lastExecuteTime; - int creationTime; - - bool manualControl; - - static int threadIndex; - static idList threadList; - - static trace_t trace; - - void Init( void ); - void Pause( void ); - - void Event_Execute( void ); - void Event_SetThreadName( const char *name ); - - // - // script callable Events - // - void Event_TerminateThread( int num ); - void Event_Pause( void ); - void Event_Wait( float time ); - void Event_WaitFrame( void ); - void Event_WaitFor( idEntity *ent ); - void Event_WaitForThread( int num ); - void Event_Print( const char *text ); - void Event_PrintLn( const char *text ); - void Event_Say( const char *text ); - void Event_Assert( float value ); - void Event_Trigger( idEntity *ent ); - void Event_SetCvar( const char *name, const char *value ) const; - void Event_GetCvar( const char *name ) const; - void Event_Random( float range ) const; -#ifdef _D3XP - void Event_RandomInt( int range ) const; -#endif - void Event_GetTime( void ); - void Event_KillThread( const char *name ); - void Event_GetEntity( const char *name ); - void Event_Spawn( const char *classname ); - void Event_CopySpawnArgs( idEntity *ent ); - void Event_SetSpawnArg( const char *key, const char *value ); - void Event_SpawnString( const char *key, const char *defaultvalue ); - void Event_SpawnFloat( const char *key, float defaultvalue ); - void Event_SpawnVector( const char *key, idVec3 &defaultvalue ); - void Event_ClearPersistantArgs( void ); - void Event_SetPersistantArg( const char *key, const char *value ); - void Event_GetPersistantString( const char *key ); - void Event_GetPersistantFloat( const char *key ); - void Event_GetPersistantVector( const char *key ); - void Event_AngToForward( idAngles &ang ); - void Event_AngToRight( idAngles &ang ); - void Event_AngToUp( idAngles &ang ); - void Event_GetSine( float angle ); - void Event_GetCosine( float angle ); -#ifdef _D3XP - void Event_GetArcSine( float a ); - void Event_GetArcCosine( float a ); -#endif - void Event_GetSquareRoot( float theSquare ); - void Event_VecNormalize( idVec3 &vec ); - void Event_VecLength( idVec3 &vec ); - void Event_VecDotProduct( idVec3 &vec1, idVec3 &vec2 ); - void Event_VecCrossProduct( idVec3 &vec1, idVec3 &vec2 ); - void Event_VecToAngles( idVec3 &vec ); -#ifdef _D3XP - void Event_VecToOrthoBasisAngles( idVec3 &vec ); - void Event_RotateVector( idVec3 &vec, idVec3 &ang ); -#endif - void Event_OnSignal( int signal, idEntity *ent, const char *func ); - void Event_ClearSignalThread( int signal, idEntity *ent ); - void Event_SetCamera( idEntity *ent ); - void Event_FirstPerson( void ); - void Event_Trace( const idVec3 &start, const idVec3 &end, const idVec3 &mins, const idVec3 &maxs, int contents_mask, idEntity *passEntity ); - void Event_TracePoint( const idVec3 &start, const idVec3 &end, int contents_mask, idEntity *passEntity ); - void Event_GetTraceFraction( void ); - void Event_GetTraceEndPos( void ); - void Event_GetTraceNormal( void ); - void Event_GetTraceEntity( void ); - void Event_GetTraceJoint( void ); - void Event_GetTraceBody( void ); - void Event_FadeIn( idVec3 &color, float time ); - void Event_FadeOut( idVec3 &color, float time ); - void Event_FadeTo( idVec3 &color, float alpha, float time ); - void Event_SetShaderParm( int parmnum, float value ); - void Event_StartMusic( const char *name ); - void Event_Warning( const char *text ); - void Event_Error( const char *text ); - void Event_StrLen( const char *string ); - void Event_StrLeft( const char *string, int num ); - void Event_StrRight( const char *string, int num ); - void Event_StrSkip( const char *string, int num ); - void Event_StrMid( const char *string, int start, int num ); - void Event_StrToFloat( const char *string ); - void Event_RadiusDamage( const idVec3 &origin, idEntity *inflictor, idEntity *attacker, idEntity *ignore, const char *damageDefName, float dmgPower ); - void Event_IsClient( void ); - void Event_IsMultiplayer( void ); - void Event_GetFrameTime( void ); - void Event_GetTicsPerSecond( void ); - void Event_CacheSoundShader( const char *soundName ); - void Event_DebugLine( const idVec3 &color, const idVec3 &start, const idVec3 &end, const float lifetime ); - void Event_DebugArrow( const idVec3 &color, const idVec3 &start, const idVec3 &end, const int size, const float lifetime ); - void Event_DebugCircle( const idVec3 &color, const idVec3 &origin, const idVec3 &dir, const float radius, const int numSteps, const float lifetime ); - void Event_DebugBounds( const idVec3 &color, const idVec3 &mins, const idVec3 &maxs, const float lifetime ); - void Event_DrawText( const char *text, const idVec3 &origin, float scale, const idVec3 &color, const int align, const float lifetime ); - void Event_InfluenceActive( void ); - -public: - CLASS_PROTOTYPE( idThread ); - - idThread(); - idThread( idEntity *self, const function_t *func ); - idThread( const function_t *func ); - idThread( idInterpreter *source, const function_t *func, int args ); - idThread( idInterpreter *source, idEntity *self, const function_t *func, int args ); - - virtual ~idThread(); - - // tells the thread manager not to delete this thread when it ends - void ManualDelete( void ); - - // save games - void Save( idSaveGame *savefile ) const; // archives object for save game file - void Restore( idRestoreGame *savefile ); // unarchives object from save game file - - void EnableDebugInfo( void ) { interpreter.debug = true; }; - void DisableDebugInfo( void ) { interpreter.debug = false; }; - - void WaitMS( int time ); - void WaitSec( float time ); - void WaitFrame( void ); - - // NOTE: If this is called from within a event called by this thread, the function arguments will be invalid after calling this function. - void CallFunction( const function_t *func, bool clearStack ); - - // NOTE: If this is called from within a event called by this thread, the function arguments will be invalid after calling this function. - void CallFunction( idEntity *obj, const function_t *func, bool clearStack ); - - void DisplayInfo(); - static idThread *GetThread( int num ); - static void ListThreads_f( const idCmdArgs &args ); - static void Restart( void ); - static void ObjectMoveDone( int threadnum, idEntity *obj ); - - static idList& GetThreads ( void ); - - bool IsDoneProcessing ( void ); - bool IsDying ( void ); - - void End( void ); - static void KillThread( const char *name ); - static void KillThread( int num ); - bool Execute( void ); - void ManualControl( void ) { manualControl = true; CancelEvents( &EV_Thread_Execute ); }; - void DoneProcessing( void ) { interpreter.doneProcessing = true; }; - void ContinueProcessing( void ) { interpreter.doneProcessing = false; }; - bool ThreadDying( void ) { return interpreter.threadDying; }; - void EndThread( void ) { interpreter.threadDying = true; }; - bool IsWaiting( void ); - void ClearWaitFor( void ); - bool IsWaitingFor( idEntity *obj ); - void ObjectMoveDone( idEntity *obj ); - void ThreadCallback( idThread *thread ); - void DelayedStart( int delay ); - bool Start( void ); - idThread *WaitingOnThread( void ); - void SetThreadNum( int num ); - int GetThreadNum( void ); - void SetThreadName( const char *name ); - const char *GetThreadName( void ); - - void Error( const char *fmt, ... ) const id_attribute((format(printf,2,3))); - void Warning( const char *fmt, ... ) const id_attribute((format(printf,2,3))); - - static idThread *CurrentThread( void ); - static int CurrentThreadNum( void ); - static bool BeginMultiFrameEvent( idEntity *ent, const idEventDef *event ); - static void EndMultiFrameEvent( idEntity *ent, const idEventDef *event ); - - static void ReturnString( const char *text ); - static void ReturnFloat( float value ); - static void ReturnInt( int value ); - static void ReturnVector( idVec3 const &vec ); - static void ReturnEntity( idEntity *ent ); -}; - -/* -================ -idThread::WaitingOnThread -================ -*/ -ID_INLINE idThread *idThread::WaitingOnThread( void ) { - return waitingForThread; -} - -/* -================ -idThread::SetThreadNum -================ -*/ -ID_INLINE void idThread::SetThreadNum( int num ) { - threadNum = num; -} - -/* -================ -idThread::GetThreadNum -================ -*/ -ID_INLINE int idThread::GetThreadNum( void ) { - return threadNum; -} - -/* -================ -idThread::GetThreadName -================ -*/ -ID_INLINE const char *idThread::GetThreadName( void ) { - return threadName.c_str(); -} - -/* -================ -idThread::GetThreads -================ -*/ -ID_INLINE idList& idThread::GetThreads ( void ) { - return threadList; -} - -/* -================ -idThread::IsDoneProcessing -================ -*/ -ID_INLINE bool idThread::IsDoneProcessing ( void ) { - return interpreter.doneProcessing; -} - -/* -================ -idThread::IsDying -================ -*/ -ID_INLINE bool idThread::IsDying ( void ) { - return interpreter.threadDying; -} - -#endif /* !__SCRIPT_THREAD_H__ */ diff --git a/game/AFEntity.cpp b/game/AFEntity.cpp index 686263fc..b826433e 100644 --- a/game/AFEntity.cpp +++ b/game/AFEntity.cpp @@ -33,6 +33,7 @@ If you have questions concerning this license or the applicable additional terms #include "gamesys/SysCvar.h" #include "Item.h" #include "Player.h" +#include "Fx.h" #include "SmokeParticles.h" #include "AFEntity.h" @@ -965,6 +966,9 @@ idAFEntity_Gibbable::idAFEntity_Gibbable( void ) { skeletonModel = NULL; skeletonModelDefHandle = -1; gibbed = false; +#ifdef _D3XP + wasThrown = false; +#endif } /* @@ -987,6 +991,9 @@ idAFEntity_Gibbable::Save void idAFEntity_Gibbable::Save( idSaveGame *savefile ) const { savefile->WriteBool( gibbed ); savefile->WriteBool( combatModel != NULL ); +#ifdef _D3XP + savefile->WriteBool( wasThrown ); +#endif } /* @@ -999,6 +1006,9 @@ void idAFEntity_Gibbable::Restore( idRestoreGame *savefile ) { savefile->ReadBool( gibbed ); savefile->ReadBool( hasCombatModel ); +#ifdef _D3XP + savefile->ReadBool( wasThrown ); +#endif InitSkeletonModel(); @@ -1017,6 +1027,9 @@ void idAFEntity_Gibbable::Spawn( void ) { InitSkeletonModel(); gibbed = false; +#ifdef _D3XP + wasThrown = false; +#endif } /* @@ -1097,6 +1110,56 @@ void idAFEntity_Gibbable::Damage( idEntity *inflictor, idEntity *attacker, const } } +#ifdef _D3XP +/* +===================== +idAFEntity_Gibbable::SetThrown +===================== +*/ +void idAFEntity_Gibbable::SetThrown( bool isThrown ) { + + if ( isThrown ) { + int i, num = af.GetPhysics()->GetNumBodies(); + + for ( i=0; iGetBody( i ); + body->SetClipMask( MASK_MONSTERSOLID ); + } + } + + wasThrown = isThrown; +} + +/* +===================== +idAFEntity_Gibbable::Collide +===================== +*/ +bool idAFEntity_Gibbable::Collide( const trace_t &collision, const idVec3 &velocity ) { + + if ( !gibbed && wasThrown ) { + + // Everything gibs (if possible) + if ( spawnArgs.GetBool( "gib" ) ) { + idEntity *ent; + + ent = gameLocal.entities[ collision.c.entityNum ]; + if ( ent->fl.takedamage ) { + ent->Damage( this, gameLocal.GetLocalPlayer(), collision.c.normal, "damage_thrown_ragdoll", 1.f, CLIPMODEL_ID_TO_JOINT_HANDLE( collision.c.id ) ); + } + + idVec3 vel = velocity; + vel.NormalizeFast(); + Gib( vel, "damage_gib" ); + } + } + + return idAFEntity_Base::Collide( collision, velocity ); +} +#endif + /* ===================== idAFEntity_Gibbable::SpawnGibs @@ -1131,13 +1194,21 @@ void idAFEntity_Gibbable::SpawnGibs( const idVec3 &dir, const char *damageDefNam list[i]->GetPhysics()->UnlinkClip(); list[i]->GetPhysics()->PutToRest(); } else { +#ifdef _D3XP + list[i]->GetPhysics()->SetContents( 0 ); +#else list[i]->GetPhysics()->SetContents( CONTENTS_CORPSE ); +#endif list[i]->GetPhysics()->SetClipMask( CONTENTS_SOLID ); velocity = list[i]->GetPhysics()->GetAbsBounds().GetCenter() - entityCenter; velocity.NormalizeFast(); velocity += ( i & 1 ) ? dir : -dir; list[i]->GetPhysics()->SetLinearVelocity( velocity * 75.0f ); } +#ifdef _D3XP + // Don't allow grabber to pick up temporary gibs + list[i]->noGrab = true; +#endif list[i]->GetRenderEntity()->noShadow = true; list[i]->GetRenderEntity()->shaderParms[ SHADERPARM_TIME_OF_DEATH ] = gameLocal.time * 0.001f; list[i]->PostEventSec( &EV_Remove, 4.0f ); @@ -1155,6 +1226,11 @@ void idAFEntity_Gibbable::Gib( const idVec3 &dir, const char *damageDefName ) { return; } +#ifdef _D3XP + // Don't grab this ent after it's been gibbed (and now invisible!) + noGrab = true; +#endif + const idDict *damageDef = gameLocal.FindEntityDefDict( damageDefName ); if ( !damageDef ) { gameLocal.Error( "Unknown damageDef '%s'", damageDefName ); @@ -1422,6 +1498,13 @@ void idAFEntity_WithAttachedHead::SetupHead( void ) { headEnt->SetCombatModel(); head = headEnt; +#ifdef _D3XP + idStr xSkin; + if ( spawnArgs.GetString( "skin_head_xray", "", xSkin ) ) { + headEnt->xraySkin = declManager->FindSkin( xSkin.c_str() ); + headEnt->UpdateModel(); + } +#endif animator.GetJointTransform( joint, gameLocal.time, origin, axis ); origin = renderEntity.origin + origin * renderEntity.axis; headEnt->SetOrigin( origin ); @@ -2047,7 +2130,11 @@ void idAFEntity_VehicleFourWheels::Think( void ) { for ( i = 0; i < 4; i++ ) { numContacts = af.GetPhysics()->GetBodyContactConstraints( wheels[i]->GetClipModel()->GetId(), contacts, 2 ); for ( int j = 0; j < numContacts; j++ ) { - gameLocal.smokeParticles->EmitSmoke( dustSmoke, gameLocal.time, gameLocal.random.RandomFloat(), contacts[j]->GetContact().point, contacts[j]->GetContact().normal.ToMat3() ); +#ifdef _D3XP + gameLocal.smokeParticles->EmitSmoke( dustSmoke, gameLocal.time, gameLocal.random.RandomFloat(), contacts[j]->GetContact().point, contacts[j]->GetContact().normal.ToMat3(), timeGroup /* D3XP */ ); +#else + gameLocal.smokeParticles->EmitSmoke(dustSmoke, gameLocal.time, gameLocal.random.RandomFloat(), contacts[j]->GetContact().point, contacts[j]->GetContact().normal.ToMat3()); +#endif // _D3XP } } } @@ -2164,7 +2251,9 @@ idAFEntity_VehicleSixWheels::Think */ void idAFEntity_VehicleSixWheels::Think( void ) { int i; +#ifndef _D3XP float force = 0.0f, velocity = 0.0f, steerAngle = 0.0f; +#endif idVec3 origin; idMat3 axis; idRotation rotation; @@ -2237,7 +2326,11 @@ void idAFEntity_VehicleSixWheels::Think( void ) { for ( i = 0; i < 6; i++ ) { numContacts = af.GetPhysics()->GetBodyContactConstraints( wheels[i]->GetClipModel()->GetId(), contacts, 2 ); for ( int j = 0; j < numContacts; j++ ) { +#ifdef _D3XP + gameLocal.smokeParticles->EmitSmoke( dustSmoke, gameLocal.time, gameLocal.random.RandomFloat(), contacts[j]->GetContact().point, contacts[j]->GetContact().normal.ToMat3(), timeGroup /* D3XP */ ); +#else gameLocal.smokeParticles->EmitSmoke( dustSmoke, gameLocal.time, gameLocal.random.RandomFloat(), contacts[j]->GetContact().point, contacts[j]->GetContact().normal.ToMat3() ); +#endif // _D3XP } } } @@ -2250,6 +2343,200 @@ void idAFEntity_VehicleSixWheels::Think( void ) { } } +#ifdef _D3XP +/* +=============================================================================== + +idAFEntity_VehicleAutomated + +=============================================================================== +*/ +const idEventDef EV_Vehicle_setVelocity( "setVelocity", "f" ); +const idEventDef EV_Vehicle_setTorque( "setTorque", "f" ); +const idEventDef EV_Vehicle_setSteeringSpeed( "setSteeringSpeed", "f" ); +const idEventDef EV_Vehicle_setWaypoint( "setWaypoint", "e" ); + +CLASS_DECLARATION( idAFEntity_VehicleSixWheels, idAFEntity_VehicleAutomated ) +EVENT( EV_PostSpawn, idAFEntity_VehicleAutomated::PostSpawn ) +EVENT( EV_Vehicle_setVelocity, idAFEntity_VehicleAutomated::Event_SetVelocity ) +EVENT( EV_Vehicle_setTorque, idAFEntity_VehicleAutomated::Event_SetTorque ) +EVENT( EV_Vehicle_setSteeringSpeed, idAFEntity_VehicleAutomated::Event_SetSteeringSpeed ) +EVENT( EV_Vehicle_setWaypoint, idAFEntity_VehicleAutomated::Event_SetWayPoint ) +END_CLASS + +/* +================ +idAFEntity_VehicleAutomated::Spawn +================ +*/ +void idAFEntity_VehicleAutomated::Spawn( void ) { + + velocity = force = steerAngle = 0.f; + currentSteering = steeringSpeed = 0.f; + originHeight = 0.f; + waypoint = NULL; + + spawnArgs.GetFloat( "velocity", "150", velocity ); + spawnArgs.GetFloat( "torque", "200000", force ); + spawnArgs.GetFloat( "steeringSpeed", "1", steeringSpeed ); + spawnArgs.GetFloat( "originHeight", "0", originHeight ); + + PostEventMS( &EV_PostSpawn, 0 ); +} + +/* +================ +idAFEntity_VehicleAutomated::PostSpawn +================ +*/ +void idAFEntity_VehicleAutomated::PostSpawn( void ) { + + if ( targets.Num() ) { + waypoint = targets[0].GetEntity(); + } +} + +/* +================ +idAFEntity_VehicleAutomated::Event_SetVelocity +================ +*/ +void idAFEntity_VehicleAutomated::Event_SetVelocity( float _velocity ) { + velocity = _velocity; +} + +/* +================ +idAFEntity_VehicleAutomated::Event_SetTorque +================ +*/ +void idAFEntity_VehicleAutomated::Event_SetTorque( float _torque ) { + force = _torque; +} + +/* +================ +idAFEntity_VehicleAutomated::Event_SetSteeringSpeed +================ +*/ +void idAFEntity_VehicleAutomated::Event_SetSteeringSpeed( float _steeringSpeed ) { + steeringSpeed = _steeringSpeed; +} + +/* +================ +idAFEntity_VehicleAutomated::Event_SetWayPoint +================ +*/ +void idAFEntity_VehicleAutomated::Event_SetWayPoint( idEntity *_waypoint ) { + waypoint = _waypoint; +} + +/* +================ +idAFEntity_VehicleAutomated::Think +================ +*/ +#define HIT_WAYPOINT_THRESHOLD 80.f + +void idAFEntity_VehicleAutomated::Think( void ) { + + // If we don't have a waypoint, coast to a stop + if ( !waypoint ) { + velocity = force = steerAngle = 0.f; + idAFEntity_VehicleSixWheels::Think(); + return; + } + + idVec3 waypoint_origin, vehicle_origin; + idVec3 travel_vector; + float distance_from_waypoint; + + // Set up the vector from the vehicle origin, to the waypoint + vehicle_origin = GetPhysics()->GetOrigin(); + vehicle_origin.z -= originHeight; + + waypoint_origin = waypoint->GetPhysics()->GetOrigin(); + + travel_vector = waypoint_origin - vehicle_origin; + distance_from_waypoint = travel_vector.Length(); + + // Check if we've hit the waypoint (within a certain threshold) + if ( distance_from_waypoint < HIT_WAYPOINT_THRESHOLD ) { + idStr callfunc; + const function_t *func; + idThread *thread; + + // Waypoints can call script functions + waypoint->spawnArgs.GetString( "call", "", callfunc ); + if ( callfunc.Length() ) { + func = gameLocal.program.FindFunction( callfunc ); + if ( func != NULL ) { + thread = new idThread( func ); + thread->DelayedStart( 0 ); + } + } + + // Get next waypoint + if ( waypoint->targets.Num() ) { + waypoint = waypoint->targets[0].GetEntity(); + } else { + waypoint = NULL; + } + + // We are switching waypoints, adjust steering next frame + idAFEntity_VehicleSixWheels::Think(); + return; + } + + idAngles vehicle_angles, travel_angles; + + // Get the angles we need to steer towards + travel_angles = travel_vector.ToAngles().Normalize360(); + vehicle_angles = this->GetPhysics()->GetAxis().ToAngles().Normalize360(); + + float delta_yaw; + + // Get the shortest steering angle towards the travel angles + delta_yaw = vehicle_angles.yaw - travel_angles.yaw; + if ( idMath::Fabs( delta_yaw ) > 180.f ) { + if ( delta_yaw > 0 ) { + delta_yaw = delta_yaw - 360; + } else { + delta_yaw = delta_yaw + 360; + } + } + + // Maximum steering angle is 35 degrees + delta_yaw = idMath::ClampFloat( -35.f, 35.f, delta_yaw ); + + idealSteering = delta_yaw; + + // Adjust steering incrementally so it doesn't snap to the ideal angle + if ( idMath::Fabs( (idealSteering - currentSteering) ) > steeringSpeed ) { + if ( idealSteering > currentSteering ) { + currentSteering += steeringSpeed; + } else { + currentSteering -= steeringSpeed; + } + } else { + currentSteering = idealSteering; + } + + // DEBUG + if ( g_vehicleDebug.GetBool() ) { + gameRenderWorld->DebugBounds( colorRed, idBounds(idVec3(-4,-4,-4),idVec3(4,4,4)), vehicle_origin ); + gameRenderWorld->DebugBounds( colorRed, idBounds(idVec3(-4,-4,-4),idVec3(4,4,4)), waypoint_origin ); + gameRenderWorld->DrawText( waypoint->name.c_str(), waypoint_origin + idVec3(0,0,16), 0.25f, colorYellow, gameLocal.GetLocalPlayer()->viewAxis ); + gameRenderWorld->DebugArrow( colorWhite, vehicle_origin, waypoint_origin, 12.f ); + } + + // Set the final steerAngle for the vehicle + steerAngle = currentSteering; + + idAFEntity_VehicleSixWheels::Think(); +} +#endif /* =============================================================================== @@ -2882,3 +3169,535 @@ idRenderModel *idGameEdit::AF_CreateMesh( const idDict &args, idVec3 &meshOrigin // instantiate a mesh using the joint information from the render entity return md5->InstantiateDynamicModel( &ent, NULL, NULL ); } + +#ifdef _D3XP + +/* +=============================================================================== +idHarvestable +=============================================================================== +*/ + +const idEventDef EV_Harvest_SpawnHarvestTrigger( "", NULL ); + +CLASS_DECLARATION( idEntity, idHarvestable ) +EVENT( EV_Harvest_SpawnHarvestTrigger, idHarvestable::Event_SpawnHarvestTrigger ) +EVENT( EV_Touch, idHarvestable::Event_Touch ) +END_CLASS + +idHarvestable::idHarvestable() { + trigger = NULL; + parentEnt = NULL; +} + +idHarvestable::~idHarvestable() { + if ( trigger ) { + delete trigger; + trigger = NULL; + } +} + +void idHarvestable::Spawn() { + + startTime = 0; + + spawnArgs.GetFloat( "triggersize", "120", triggersize ); + spawnArgs.GetFloat( "give_delay", "3", giveDelay); + giveDelay *= 1000; + given = false; + + removeDelay = spawnArgs.GetFloat( "remove_delay") * 1000.0f; + + fxFollowPlayer = spawnArgs.GetBool("fx_follow_player", "1"); + fxOrient = spawnArgs.GetString("fx_orient"); + + +} + +void idHarvestable::Init(idEntity* parent) { + + assert(parent); + + parentEnt = parent; + + GetPhysics()->SetOrigin( parent->GetPhysics()->GetOrigin() ); + this->Bind(parent, true); + + //Set the skin of the entity to the harvest skin + idStr skin = parent->spawnArgs.GetString("skin_harvest", ""); + if(skin.Length()) { + parent->SetSkin(declManager->FindSkin(skin.c_str())); + } + + idEntity* head = NULL; + if(parent->IsType(idActor::Type)) { + idActor* withHead = (idActor*)parent; + head = withHead->GetHeadEntity(); + } + if(parent->IsType(idAFEntity_WithAttachedHead::Type)) { + idAFEntity_WithAttachedHead* withHead = (idAFEntity_WithAttachedHead*)parent; + head = withHead->head.GetEntity(); + } + if(head) { + idStr headskin = parent->spawnArgs.GetString("skin_harvest_head", ""); + if(headskin.Length()) { + head->SetSkin(declManager->FindSkin(headskin.c_str())); + } + } + + idStr sound = parent->spawnArgs.GetString("harvest_sound"); + if(sound.Length() > 0) { + parent->StartSound( sound.c_str(), SND_CHANNEL_ANY, 0, false, NULL); + } + + + PostEventMS( &EV_Harvest_SpawnHarvestTrigger, 0 ); +} + +void idHarvestable::Save( idSaveGame *savefile ) const { + savefile->WriteFloat( triggersize ); + savefile->WriteClipModel( trigger ); + savefile->WriteFloat( giveDelay ); + savefile->WriteFloat( removeDelay ); + savefile->WriteBool( given ); + + player.Save( savefile ); + savefile->WriteInt( startTime ); + + savefile->WriteBool( fxFollowPlayer ); + fx.Save( savefile ); + savefile->WriteString( fxOrient ); + + parentEnt.Save(savefile); +} + +void idHarvestable::Restore( idRestoreGame *savefile ) { + savefile->ReadFloat( triggersize ); + savefile->ReadClipModel( trigger ); + savefile->ReadFloat( giveDelay ); + savefile->ReadFloat( removeDelay ); + savefile->ReadBool( given ); + + player.Restore( savefile ); + savefile->ReadInt( startTime ); + + savefile->ReadBool( fxFollowPlayer ); + fx.Restore( savefile ); + savefile->ReadString( fxOrient ); + + parentEnt.Restore(savefile); +} + +void idHarvestable::SetParent(idEntity* parent) { + parentEnt = parent; +} + +void idHarvestable::Think() { + + idEntity* parent = parentEnt.GetEntity(); + if(!parent) { + return; + } + + //Update the orientation of the box + if(trigger && parent && !parent->GetPhysics()->IsAtRest()) { + trigger->Link( gameLocal.clip, this, 0, parent->GetPhysics()->GetOrigin(), parent->GetPhysics()->GetAxis()); + } + + if(startTime && gameLocal.slow.time - startTime > giveDelay && ! given) { + idPlayer *thePlayer = player.GetEntity(); + + thePlayer->Give(spawnArgs.GetString("give_item"), spawnArgs.GetString("give_value")); + thePlayer->harvest_lock = false; + given = true; + } + + if(startTime && gameLocal.slow.time - startTime > removeDelay) { + parent->PostEventMS( &EV_Remove, 0 ); + PostEventMS( &EV_Remove, 0 ); + } + + if(fxFollowPlayer) { + idEntityFx* fxEnt = fx.GetEntity(); + + if(fxEnt) { + idMat3 orientAxisLocal; + if(GetFxOrientationAxis(orientAxisLocal)) { + //gameRenderWorld->DebugAxis(fxEnt->GetPhysics()->GetOrigin(), orientAxisLocal); + fxEnt->GetPhysics()->SetAxis(orientAxisLocal); + } + } + } +} + +/* +================ +idAFEntity_Harvest::Gib +Called when the parent object has been gibbed. +================ +*/ +void idHarvestable::Gib() { + //Stop any looping sound that was playing + idEntity* parent = parentEnt.GetEntity(); + if(parent) { + idStr sound = parent->spawnArgs.GetString("harvest_sound"); + if(sound.Length() > 0) { + parent->StopSound(SND_CHANNEL_ANY, false); + } + } +} + +/* +================ +idAFEntity_Harvest::BeginBurn +================ +*/ +void idHarvestable::BeginBurn() { + + idEntity* parent = parentEnt.GetEntity(); + if(!parent) { + return; + } + + if(!spawnArgs.GetBool("burn")) { + return; + } + + + //Switch Skins if the parent would like us to. + idStr skin = parent->spawnArgs.GetString("skin_harvest_burn", ""); + if(skin.Length()) { + parent->SetSkin(declManager->FindSkin(skin.c_str())); + } + parent->GetRenderEntity()->noShadow = true; + parent->SetShaderParm( SHADERPARM_TIME_OF_DEATH, gameLocal.slow.time * 0.001f ); + + idEntity* head = NULL; + if(parent->IsType(idActor::Type)) { + idActor* withHead = (idActor*)parent; + head = withHead->GetHeadEntity(); + } + if(parent->IsType(idAFEntity_WithAttachedHead::Type)) { + idAFEntity_WithAttachedHead* withHead = (idAFEntity_WithAttachedHead*)parent; + head = withHead->head.GetEntity(); + } + if(head) { + idStr headskin = parent->spawnArgs.GetString("skin_harvest_burn_head", ""); + if(headskin.Length()) { + head->SetSkin(declManager->FindSkin(headskin.c_str())); + } + + head->GetRenderEntity()->noShadow = true; + head->SetShaderParm( SHADERPARM_TIME_OF_DEATH, gameLocal.slow.time * 0.001f ); + } + + + +} + +/* +================ +idAFEntity_Harvest::BeginFX +================ +*/ +void idHarvestable::BeginFX() { + if(strlen(spawnArgs.GetString("fx")) <= 0) { + return; + } + + idMat3* orientAxis = NULL; + idMat3 orientAxisLocal; + + if(GetFxOrientationAxis(orientAxisLocal)) { + orientAxis = &orientAxisLocal; + } + fx = idEntityFx::StartFx( spawnArgs.GetString("fx"), NULL, orientAxis, this, spawnArgs.GetBool("fx_bind") ); +} + +/* +================ +idAFEntity_Harvest::CalcTriggerBounds +================ +*/ +void idHarvestable::CalcTriggerBounds( float size, idBounds &bounds ) { + + idEntity* parent = parentEnt.GetEntity(); + if(!parent) { + return; + } + + //Simple trigger bounds is the absolute bounds of the AF plus a defined size + bounds = parent->GetPhysics()->GetAbsBounds(); + bounds.ExpandSelf(size); + bounds[0] -= parent->GetPhysics()->GetOrigin(); + bounds[1] -= parent->GetPhysics()->GetOrigin(); +} + +bool idHarvestable::GetFxOrientationAxis(idMat3& mat) { + + idEntity* parent = parentEnt.GetEntity(); + if(!parent) { + return false; + } + + idPlayer *thePlayer = player.GetEntity(); + + if(!fxOrient.Icmp("up")) { + //Orient up + idVec3 grav = parent->GetPhysics()->GetGravityNormal()*-1; + idVec3 left, up; + + grav.OrthogonalBasis(left, up); + idMat3 temp(left.x, left.y, left.z, up.x, up.y, up.z, grav.x, grav.y, grav.z); + mat = temp; + + return true; + + } else if(!fxOrient.Icmp("weapon")) { + //Orient the fx towards the muzzle of the weapon + jointHandle_t joint; + idVec3 joint_origin; + idMat3 joint_axis; + + joint = thePlayer->weapon.GetEntity()->GetAnimator()->GetJointHandle( spawnArgs.GetString("fx_weapon_joint") ); + if ( joint != INVALID_JOINT ) { + thePlayer->weapon.GetEntity()->GetJointWorldTransform( joint, gameLocal.slow.time, joint_origin, joint_axis ); + } else { + joint_origin = thePlayer->GetPhysics()->GetOrigin(); + } + + idVec3 toPlayer = joint_origin-parent->GetPhysics()->GetOrigin(); + toPlayer.NormalizeFast(); + + idVec3 left, up; + toPlayer.OrthogonalBasis(left, up); + idMat3 temp(left.x, left.y, left.z, up.x, up.y, up.z, toPlayer.x, toPlayer.y, toPlayer.z); + mat = temp; + + return true; + + } else if(!fxOrient.Icmp("player")) { + //Orient the fx towards the eye of the player + idVec3 eye = thePlayer->GetEyePosition(); + idVec3 toPlayer = eye-parent->GetPhysics()->GetOrigin(); + + toPlayer.Normalize(); + + idVec3 left, up; + up.Set(0, 1, 0); + left = toPlayer.Cross(up); + up = left.Cross(toPlayer); + + + //common->Printf("%.2f %.2f %.2f - %.2f %.2f %.2f - %.2f %.2f %.2f\n", toPlayer.x, toPlayer.y, toPlayer.z, left.x, left.y, left.z, up.x, up.y, up.z ); + + idMat3 temp(left.x, left.y, left.z, up.x, up.y, up.z, toPlayer.x, toPlayer.y, toPlayer.z); + + mat = temp; + + return true; + } + + //Returning false indicates that the orientation is not used; + return false; +} + +/* +================ +idAFEntity_Harvest::Event_SpawnHarvestTrigger +================ +*/ +void idHarvestable::Event_SpawnHarvestTrigger( void ) { + idBounds bounds; + + idEntity* parent = parentEnt.GetEntity(); + if(!parent) { + return; + } + + CalcTriggerBounds( triggersize, bounds ); + + // create a trigger clip model + trigger = new idClipModel( idTraceModel( bounds ) ); + trigger->Link( gameLocal.clip, this, 255, parent->GetPhysics()->GetOrigin(), mat3_identity); + trigger->SetContents( CONTENTS_TRIGGER ); + + startTime = 0; +} + +/* +================ +idAFEntity_Harvest::Event_Touch +================ +*/ +void idHarvestable::Event_Touch( idEntity *other, trace_t *trace ) { + + idEntity* parent = parentEnt.GetEntity(); + if(!parent) { + return; + } + if(parent->IsType(idAFEntity_Gibbable::Type)) { + idAFEntity_Gibbable* gibParent = (idAFEntity_Gibbable*)parent; + if(gibParent->IsGibbed()) + return; + } + + + if(!startTime && other && other->IsType(idPlayer::Type)) { + idPlayer *thePlayer = static_cast(other); + + if(thePlayer->harvest_lock) { + //Don't harvest if the player is in mid harvest + return; + } + + player = thePlayer; + + bool okToGive = true; + idStr requiredWeapons = spawnArgs.GetString("required_weapons"); + + if(requiredWeapons.Length() > 0) { + idStr playerWeap = thePlayer->GetCurrentWeapon(); + if(playerWeap.Length() == 0 || requiredWeapons.Find(playerWeap, false) == -1) { + okToGive = false; + } + } + + if(okToGive) { + if(thePlayer->CanGive(spawnArgs.GetString("give_item"), spawnArgs.GetString("give_value"))) { + + startTime = gameLocal.slow.time; + + //Lock the player from harvesting to prevent multiple harvests when only one is needed + thePlayer->harvest_lock = true; + + idWeapon* weap = (idWeapon*)thePlayer->weapon.GetEntity(); + if(weap) { + //weap->PostEventMS(&EV_Weapon_State, 0, "Charge", 8); + weap->ProcessEvent(&EV_Weapon_State, "Charge", 8); + } + + BeginBurn(); + BeginFX(); + + //Stop any looping sound that was playing + idStr sound = parent->spawnArgs.GetString("harvest_sound"); + if(sound.Length() > 0) { + parent->StopSound(SND_CHANNEL_ANY, false); + } + + //Make the parent object non-solid + parent->GetPhysics()->SetContents( 0 ); + parent->GetPhysics()->GetClipModel()->Unlink(); + + //Turn of the trigger so it doesn't process twice + trigger->SetContents( 0 ); + } + } + } +} + + +/* +=============================================================================== + +idAFEntity_Harvest + +=============================================================================== +*/ + +const idEventDef EV_Harvest_SpawnHarvestEntity( "", NULL ); + +CLASS_DECLARATION( idAFEntity_WithAttachedHead, idAFEntity_Harvest ) +EVENT( EV_Harvest_SpawnHarvestEntity, idAFEntity_Harvest::Event_SpawnHarvestEntity ) +END_CLASS + +/* +================ +idAFEntity_Harvest::idAFEntity_Harvest +================ +*/ +idAFEntity_Harvest::idAFEntity_Harvest() { + harvestEnt = NULL; +} + +/* +================ +idAFEntity_Harvest::~idAFEntity_Harvest +================ +*/ +idAFEntity_Harvest::~idAFEntity_Harvest() { + + if ( harvestEnt.GetEntity() ) { + harvestEnt.GetEntity()->PostEventMS( &EV_Remove, 0 ); + } + +} + +/* +================ +idAFEntity_Harvest::Save +================ +*/ +void idAFEntity_Harvest::Save( idSaveGame *savefile ) const { + harvestEnt.Save(savefile); +} + +/* +================ +idAFEntity_Harvest::Restore +================ +*/ +void idAFEntity_Harvest::Restore( idRestoreGame *savefile ) { + harvestEnt.Restore(savefile); + //if(harvestEnt.GetEntity()) { + // harvestEnt.GetEntity()->SetParent(this); + //} +} + +/* +================ +idAFEntity_Harvest::Spawn +================ +*/ +void idAFEntity_Harvest::Spawn( void ) { + + PostEventMS( &EV_Harvest_SpawnHarvestEntity, 0 ); +} + +/* +================ +idAFEntity_Harvest::Think +================ +*/ +void idAFEntity_Harvest::Think( void ) { + + idAFEntity_WithAttachedHead::Think(); + +} + +void idAFEntity_Harvest::Event_SpawnHarvestEntity( void ) { + + const idDict *harvestDef = gameLocal.FindEntityDefDict( spawnArgs.GetString("def_harvest_type"), false ); + if ( harvestDef ) { + idEntity *temp; + gameLocal.SpawnEntityDef( *harvestDef, &temp, false ); + harvestEnt = static_cast(temp); + } + + if(harvestEnt.GetEntity()) { + //Let the harvest entity set itself up + harvestEnt.GetEntity()->Init(this); + harvestEnt.GetEntity()->BecomeActive( TH_THINK ); + } +} + +void idAFEntity_Harvest::Gib( const idVec3 &dir, const char *damageDefName ) { + if(harvestEnt.GetEntity()) { + //Let the harvest ent know that we gibbed + harvestEnt.GetEntity()->Gib(); + } + idAFEntity_WithAttachedHead::Gib(dir, damageDefName); +} + +#endif diff --git a/game/AFEntity.h b/game/AFEntity.h index bc7dee49..a63dda9a 100644 --- a/game/AFEntity.h +++ b/game/AFEntity.h @@ -226,13 +226,25 @@ class idAFEntity_Gibbable : public idAFEntity_Base { void Restore( idRestoreGame *savefile ); virtual void Present( void ); virtual void Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location ); +#ifdef _D3XP + void SetThrown( bool isThrown ); + virtual bool Collide( const trace_t &collision, const idVec3 &velocity ); +#endif virtual void SpawnGibs( const idVec3 &dir, const char *damageDefName ); +#ifdef _D3XP + bool IsGibbed() { return gibbed; }; +#endif + protected: idRenderModel * skeletonModel; int skeletonModelDefHandle; bool gibbed; +#ifdef _D3XP + bool wasThrown; +#endif + virtual void Gib( const idVec3 &dir, const char *damageDefName ); void InitSkeletonModel( void ); @@ -303,7 +315,11 @@ class idAFEntity_WithAttachedHead : public idAFEntity_Gibbable { protected: virtual void Gib( const idVec3 &dir, const char *damageDefName ); +#ifndef _D3XP private: +#else +public: +#endif idEntityPtr head; void Event_Gib( const char *damageDefName ); @@ -409,6 +425,12 @@ class idAFEntity_VehicleSixWheels : public idAFEntity_Vehicle { void Spawn( void ); virtual void Think( void ); +#ifdef _D3XP + float force; + float velocity; + float steerAngle; +#endif + private: idAFBody * wheels[6]; idAFConstraint_Hinge * steering[4]; @@ -416,6 +438,37 @@ class idAFEntity_VehicleSixWheels : public idAFEntity_Vehicle { float wheelAngles[6]; }; +#ifdef _D3XP +/* +=============================================================================== + +idAFEntity_VehicleAutomated + +=============================================================================== +*/ + +class idAFEntity_VehicleAutomated : public idAFEntity_VehicleSixWheels { +public: + CLASS_PROTOTYPE( idAFEntity_VehicleAutomated ); + + void Spawn( void ); + void PostSpawn( void ); + virtual void Think( void ); + +private: + + idEntity *waypoint; + float steeringSpeed; + float currentSteering; + float idealSteering; + float originHeight; + + void Event_SetVelocity( float _velocity ); + void Event_SetTorque( float _torque ); + void Event_SetSteeringSpeed( float _steeringSpeed ); + void Event_SetWayPoint( idEntity *_waypoint ); +}; +#endif /* =============================================================================== @@ -475,4 +528,89 @@ class idAFEntity_ClawFourFingers : public idAFEntity_Base { void Event_StopFingers( void ); }; +#ifdef _D3XP + +/** +* idHarvestable contains all of the code required to turn an entity into a harvestable +* entity. The entity must create an instance of this class and call the appropriate +* interface methods at the correct time. +*/ +class idHarvestable : public idEntity { +public: + CLASS_PROTOTYPE( idHarvestable ); + + idHarvestable(); + ~idHarvestable(); + + void Spawn(); + void Init(idEntity* parent); + void Save( idSaveGame *savefile ) const; + void Restore( idRestoreGame *savefile ); + + void SetParent(idEntity* parent); + + void Think(); + void Gib(); + +protected: + idEntityPtr parentEnt; + float triggersize; + idClipModel * trigger; + float giveDelay; + float removeDelay; + bool given; + + idEntityPtr player; + int startTime; + + bool fxFollowPlayer; + idEntityPtr fx; + idStr fxOrient; + +protected: + void BeginBurn(); + void BeginFX(); + void CalcTriggerBounds( float size, idBounds &bounds ); + + bool GetFxOrientationAxis(idMat3& mat); + + void Event_SpawnHarvestTrigger( void ); + void Event_Touch( idEntity *other, trace_t *trace ); +} ; + + +/* +=============================================================================== + +idAFEntity_Harvest + +=============================================================================== +*/ + + + +class idAFEntity_Harvest : public idAFEntity_WithAttachedHead { +public: + CLASS_PROTOTYPE( idAFEntity_Harvest ); + + idAFEntity_Harvest(); + ~idAFEntity_Harvest(); + + void Spawn( void ); + + void Save( idSaveGame *savefile ) const; + void Restore( idRestoreGame *savefile ); + + virtual void Think( void ); + + virtual void Gib( const idVec3 &dir, const char *damageDefName ); + +protected: + idEntityPtr harvestEnt; +protected: + void Event_SpawnHarvestEntity( void ); + +}; +#endif + #endif /* !__GAME_AFENTITY_H__ */ diff --git a/game/Actor.cpp b/game/Actor.cpp index 15061a29..39cec391 100644 --- a/game/Actor.cpp +++ b/game/Actor.cpp @@ -365,6 +365,14 @@ const idEventDef AI_SetNextState( "setNextState", "s" ); const idEventDef AI_SetState( "setState", "s" ); const idEventDef AI_GetState( "getState", NULL, 's' ); const idEventDef AI_GetHead( "getHead", NULL, 'e' ); +#ifdef _D3XP +const idEventDef EV_SetDamageGroupScale( "setDamageGroupScale", "sf" ); +const idEventDef EV_SetDamageGroupScaleAll( "setDamageGroupScaleAll", "f" ); +const idEventDef EV_GetDamageGroupScale( "getDamageGroupScale", "s", 'f' ); +const idEventDef EV_SetDamageCap( "setDamageCap", "f" ); +const idEventDef EV_SetWaitState( "setWaitState" , "s" ); +const idEventDef EV_GetWaitState( "getWaitState", NULL, 's' ); +#endif CLASS_DECLARATION( idAFEntity_Gibbable, idActor ) EVENT( AI_EnableEyeFocus, idActor::Event_EnableEyeFocus ) @@ -408,6 +416,14 @@ CLASS_DECLARATION( idAFEntity_Gibbable, idActor ) EVENT( AI_SetState, idActor::Event_SetState ) EVENT( AI_GetState, idActor::Event_GetState ) EVENT( AI_GetHead, idActor::Event_GetHead ) +#ifdef _D3XP + EVENT( EV_SetDamageGroupScale, idActor::Event_SetDamageGroupScale ) + EVENT( EV_SetDamageGroupScaleAll, idActor::Event_SetDamageGroupScaleAll ) + EVENT( EV_GetDamageGroupScale, idActor::Event_GetDamageGroupScale ) + EVENT( EV_SetDamageCap, idActor::Event_SetDamageCap ) + EVENT( EV_SetWaitState, idActor::Event_SetWaitState ) + EVENT( EV_GetWaitState, idActor::Event_GetWaitState ) +#endif END_CLASS /* @@ -458,6 +474,10 @@ idActor::idActor( void ) { enemyNode.SetOwner( this ); enemyList.SetOwner( this ); + +#ifdef _D3XP + damageCap = -1; +#endif } /* @@ -693,11 +713,25 @@ void idActor::SetupHead( void ) { sndKV = spawnArgs.MatchPrefix( "snd_", sndKV ); } +#ifdef _D3XP + // copy slowmo param to the head + args.SetBool( "slowmo", spawnArgs.GetBool("slowmo", "1") ); +#endif + + headEnt = static_cast( gameLocal.SpawnEntityType( idAFAttachment::Type, &args ) ); headEnt->SetName( va( "%s_head", name.c_str() ) ); headEnt->SetBody( this, headModel, damageJoint ); head = headEnt; +#ifdef _D3XP + idStr xSkin; + if ( spawnArgs.GetString( "skin_head_xray", "", xSkin ) ) { + headEnt->xraySkin = declManager->FindSkin( xSkin.c_str() ); + headEnt->UpdateModel(); + } +#endif + idVec3 origin; idMat3 axis; idAttachInfo &attach = attachments.Alloc(); @@ -869,6 +903,10 @@ void idActor::Save( idSaveGame *savefile ) const { savefile->WriteString( "" ); } +#ifdef _D3XP + savefile->WriteInt(damageCap); +#endif + } /* @@ -977,6 +1015,10 @@ void idActor::Restore( idRestoreGame *savefile ) { if ( statename.Length() > 0 ) { idealState = GetScriptFunction( statename ); } + +#ifdef _D3XP + savefile->ReadInt(damageCap); +#endif } /* @@ -1023,7 +1065,13 @@ void idActor::Show( void ) { if ( ent->GetBindMaster() == this ) { ent->Show(); if ( ent->IsType( idLight::Type ) ) { - static_cast( ent )->On(); +#ifdef _D3XP + if(!spawnArgs.GetBool("lights_off", "0")) { + static_cast( ent )->On(); + } +#endif + + } } } @@ -2170,9 +2218,24 @@ void idActor::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir attacker = gameLocal.world; } +#ifdef _D3XP + SetTimeState ts( timeGroup ); + + // Helltime boss is immune to all projectiles except the helltime killer + if ( finalBoss && idStr::Icmp(inflictor->GetEntityDefName(), "projectile_helltime_killer") ) { + return; + } + + // Maledict is immume to the falling asteroids + if ( !idStr::Icmp( GetEntityDefName(), "monster_boss_d3xp_maledict" ) && + (!idStr::Icmp( damageDefName, "damage_maledict_asteroid" ) || !idStr::Icmp( damageDefName, "damage_maledict_asteroid_splash" ) ) ) { + return; + } +#else if ( finalBoss && !inflictor->IsType( idSoulCubeMissile::Type ) ) { return; } +#endif const idDict *damageDef = gameLocal.FindEntityDefDict( damageDefName ); if ( !damageDef ) { @@ -2186,6 +2249,14 @@ void idActor::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir attacker->DamageFeedback( this, inflictor, damage ); if ( damage > 0 ) { health -= damage; + +#ifdef _D3XP + //Check the health against any damage cap that is currently set + if(damageCap >= 0 && health < damageCap) { + health = damageCap; + } +#endif + if ( health <= 0 ) { if ( health < -999 ) { health = -999; @@ -3276,3 +3347,59 @@ idActor::Event_GetHead void idActor::Event_GetHead( void ) { idThread::ReturnEntity( head.GetEntity() ); } + +#ifdef _D3XP +/* +================ +idActor::Event_SetDamageGroupScale +================ +*/ +void idActor::Event_SetDamageGroupScale( const char* groupName, float scale) { + + for( int i = 0; i < damageScale.Num(); i++ ) { + if ( damageGroups[ i ] == groupName ) { + damageScale[ i ] = scale; + } + } +} + +/* +================ +idActor::Event_SetDamageGroupScaleAll +================ +*/ +void idActor::Event_SetDamageGroupScaleAll( float scale ) { + + for( int i = 0; i < damageScale.Num(); i++ ) { + damageScale[ i ] = scale; + } +} + +void idActor::Event_GetDamageGroupScale( const char* groupName ) { + + for( int i = 0; i < damageScale.Num(); i++ ) { + if ( damageGroups[ i ] == groupName ) { + idThread::ReturnFloat(damageScale[i]); + return; + } + } + + idThread::ReturnFloat(0); +} + +void idActor::Event_SetDamageCap( float _damageCap ) { + damageCap = _damageCap; +} + +void idActor::Event_SetWaitState( const char* waitState) { + SetWaitState(waitState); +} + +void idActor::Event_GetWaitState() { + if(WaitState()) { + idThread::ReturnString(WaitState()); + } else { + idThread::ReturnString(""); + } +} +#endif diff --git a/game/Actor.h b/game/Actor.h index c52fb27f..5ecef15c 100644 --- a/game/Actor.h +++ b/game/Actor.h @@ -57,6 +57,10 @@ extern const idEventDef AI_AnimDone; extern const idEventDef AI_SetBlendFrames; extern const idEventDef AI_GetBlendFrames; +#ifdef _D3XP +extern const idEventDef AI_SetState; +#endif + class idDeclParticle; class idAnimState { @@ -209,6 +213,10 @@ class idActor : public idAFEntity_Gibbable { bool AnimDone( int channel, int blendFrames ) const; virtual void SpawnGibs( const idVec3 &dir, const char *damageDefName ); +#ifdef _D3XP + idEntity* GetHeadEntity() { return head.GetEntity(); }; +#endif + protected: friend class idAnimState; @@ -264,6 +272,10 @@ class idActor : public idAFEntity_Gibbable { idList attachments; +#ifdef _D3XP + int damageCap; +#endif + virtual void Gib( const idVec3 &dir, const char *damageDefName ); // removes attachments with "remove" set for when character dies @@ -318,6 +330,15 @@ class idActor : public idAFEntity_Gibbable { void Event_SetState( const char *name ); void Event_GetState( void ); void Event_GetHead( void ); +#ifdef _D3XP + void Event_SetDamageGroupScale( const char* groupName, float scale); + void Event_SetDamageGroupScaleAll( float scale ); + void Event_GetDamageGroupScale( const char* groupName ); + void Event_SetDamageCap( float _damageCap ); + void Event_SetWaitState( const char* waitState); + void Event_GetWaitState(); + +#endif }; #endif /* !__GAME_ACTOR_H__ */ diff --git a/game/BrittleFracture.cpp b/game/BrittleFracture.cpp index 58557a0f..d05022a2 100644 --- a/game/BrittleFracture.cpp +++ b/game/BrittleFracture.cpp @@ -71,6 +71,10 @@ idBrittleFracture::idBrittleFracture( void ) { changed = false; fl.networkSync = true; + +#ifdef _D3XP + isXraySurface = false; +#endif } /* @@ -154,6 +158,10 @@ void idBrittleFracture::Save( idSaveGame *savefile ) const { savefile->WriteBool( shards[i]->atEdge ); savefile->WriteStaticObject( shards[i]->physicsObj ); } + +#ifdef _D3XP + savefile->WriteBool( isXraySurface ); +#endif } /* @@ -241,6 +249,10 @@ void idBrittleFracture::Restore( idRestoreGame *savefile ) { shards[i]->clipModel = shards[i]->physicsObj.GetClipModel(); } } + +#ifdef _D3XP + savefile->ReadBool( isXraySurface ); +#endif } /* @@ -278,6 +290,24 @@ void idBrittleFracture::Spawn( void ) { // FIXME: set "bleed" so idProjectile calls AddDamageEffect spawnArgs.SetBool( "bleed", 1 ); +#ifdef _D3XP + // check for xray surface + if ( 1 ) { + const idRenderModel *model = renderEntity.hModel; + + isXraySurface = false; + + for ( int i = 0; i < model->NumSurfaces(); i++ ) { + const modelSurface_t *surf = model->Surface( i ); + + if ( idStr( surf->shader->GetName() ) == "textures/smf/window_scratch" ) { + isXraySurface = true; + break; + } + } + } +#endif + CreateFractures( renderEntity.hModel ); FindNeighbours(); @@ -1027,10 +1057,19 @@ void idBrittleFracture::Fracture_r( idFixedWinding &w ) { } // randomly create a split plane + axis[2] = windingPlane.Normal(); +#ifdef _D3XP + if ( isXraySurface ) { + a = idMath::TWO_PI / 2.f; + } + else { + a = gameLocal.random.RandomFloat() * idMath::TWO_PI; + } +#else a = gameLocal.random.RandomFloat() * idMath::TWO_PI; +#endif c = cos( a ); s = -sin( a ); - axis[2] = windingPlane.Normal(); axis[2].NormalVectors( axistemp[0], axistemp[1] ); axis[0] = axistemp[ 0 ] * c + axistemp[ 1 ] * s; axis[1] = axistemp[ 0 ] * s + axistemp[ 1 ] * -c; @@ -1096,6 +1135,60 @@ void idBrittleFracture::CreateFractures( const idRenderModel *renderModel ) { physicsObj.SetOrigin( GetPhysics()->GetOrigin(), 0 ); physicsObj.SetAxis( GetPhysics()->GetAxis(), 0 ); +#ifdef _D3XP + if ( isXraySurface ) { + for ( i = 0; i < 1 /*renderModel->NumSurfaces()*/; i++ ) { + surf = renderModel->Surface( i ); + material = surf->shader; + + w.Clear(); + + int k = 0; + v = &surf->geometry->verts[k]; + w.AddPoint( v->xyz ); + w[k].s = v->st[0]; + w[k].t = v->st[1]; + + k = 1; + v = &surf->geometry->verts[k]; + w.AddPoint( v->xyz ); + w[k].s = v->st[0]; + w[k].t = v->st[1]; + + k = 3; + v = &surf->geometry->verts[k]; + w.AddPoint( v->xyz ); + w[k].s = v->st[0]; + w[k].t = v->st[1]; + + k = 2; + v = &surf->geometry->verts[k]; + w.AddPoint( v->xyz ); + w[k].s = v->st[0]; + w[k].t = v->st[1]; + + Fracture_r( w ); + } + + } + else { + for ( i = 0; i < 1 /*renderModel->NumSurfaces()*/; i++ ) { + surf = renderModel->Surface( i ); + material = surf->shader; + + for ( j = 0; j < surf->geometry->numIndexes; j += 3 ) { + w.Clear(); + for ( k = 0; k < 3; k++ ) { + v = &surf->geometry->verts[ surf->geometry->indexes[ j + 2 - k ] ]; + w.AddPoint( v->xyz ); + w[k].s = v->st[0]; + w[k].t = v->st[1]; + } + Fracture_r( w ); + } + } + } +#else for ( i = 0; i < 1 /*renderModel->NumSurfaces()*/; i++ ) { surf = renderModel->Surface( i ); material = surf->shader; @@ -1111,6 +1204,7 @@ void idBrittleFracture::CreateFractures( const idRenderModel *renderModel ) { Fracture_r( w ); } } +#endif physicsObj.SetContents( material->GetContentFlags() ); SetPhysics( &physicsObj ); diff --git a/game/BrittleFracture.h b/game/BrittleFracture.h index 3eeca480..0ccc1b0c 100644 --- a/game/BrittleFracture.h +++ b/game/BrittleFracture.h @@ -104,6 +104,10 @@ class idBrittleFracture : public idEntity { float bouncyness; idStr fxFracture; +#ifdef _D3XP + bool isXraySurface; +#endif + // state idPhysics_StaticMulti physicsObj; idList shards; diff --git a/game/Camera.cpp b/game/Camera.cpp index eddef373..dedba94f 100644 --- a/game/Camera.cpp +++ b/game/Camera.cpp @@ -564,6 +564,10 @@ void idCameraAnim::GetViewParms( renderView_t *view ) { return; } +#ifdef _D3XP + SetTimeState ts( timeGroup ); +#endif + if ( frameRate == USERCMD_HZ ) { frameTime = gameLocal.time - starttime; frame = frameTime / gameLocal.msec; diff --git a/game/EndLevel.cpp b/game/EndLevel.cpp index 9bfc321d..f6c03b99 100644 --- a/game/EndLevel.cpp +++ b/game/EndLevel.cpp @@ -26,8 +26,8 @@ If you have questions concerning this license or the applicable additional terms =========================================================================== */ -// NOTE: even though this file is part of the Doom3 GPL source (but not the original SDK in game/), -// it has never been part of the build (=> not compiled into base.dll) +// NOTE: even though this file is part of the Doom3 GPL source (and the original SDK in d3xp/), +// it has never been part of the build (=> not compiled into d3xp.dll) #include "sys/platform.h" diff --git a/game/Entity.cpp b/game/Entity.cpp index 8ae5f13d..6fd42d7e 100644 --- a/game/Entity.cpp +++ b/game/Entity.cpp @@ -120,6 +120,15 @@ const idEventDef EV_StartFx( "startFx", "s" ); const idEventDef EV_HasFunction( "hasFunction", "s", 'd' ); const idEventDef EV_CallFunction( "callFunction", "s" ); const idEventDef EV_SetNeverDormant( "setNeverDormant", "d" ); +#ifdef _D3XP +const idEventDef EV_SetGui ( "setGui", "ds" ); +const idEventDef EV_PrecacheGui ( "precacheGui", "s" ); +const idEventDef EV_GetGuiParm ( "getGuiParm", "ds", 's' ); +const idEventDef EV_GetGuiParmFloat ( "getGuiParmFloat", "ds", 'f' ); +const idEventDef EV_MotionBlurOn( "motionBlurOn" ); +const idEventDef EV_MotionBlurOff( "motionBlurOff" ); +const idEventDef EV_GuiNamedEvent ( "guiNamedEvent", "ds" ); +#endif ABSTRACT_DECLARATION( idClass, idEntity ) EVENT( EV_GetName, idEntity::Event_GetName ) @@ -185,6 +194,13 @@ ABSTRACT_DECLARATION( idClass, idEntity ) EVENT( EV_HasFunction, idEntity::Event_HasFunction ) EVENT( EV_CallFunction, idEntity::Event_CallFunction ) EVENT( EV_SetNeverDormant, idEntity::Event_SetNeverDormant ) +#ifdef _D3XP + EVENT( EV_SetGui, idEntity::Event_SetGui ) + EVENT( EV_PrecacheGui, idEntity::Event_PrecacheGui ) + EVENT( EV_GetGuiParm, idEntity::Event_GetGuiParm ) + EVENT( EV_GetGuiParmFloat, idEntity::Event_GetGuiParmFloat ) + EVENT( EV_GuiNamedEvent, idEntity::Event_GuiNamedEvent ) +#endif END_CLASS /* @@ -435,6 +451,16 @@ idEntity::idEntity() { memset( &refSound, 0, sizeof( refSound ) ); mpGUIState = -1; + +#ifdef _D3XP + memset( &xrayEntity, 0, sizeof( xrayEntity ) ); + + timeGroup = TIME_GROUP1; + xrayEntityHandle = -1; + xraySkin = NULL; + + noGrab = false; +#endif } /* @@ -480,6 +506,18 @@ void idEntity::Spawn( void ) { renderEntity.entityNum = entityNumber; +#ifdef _D3XP + noGrab = spawnArgs.GetBool( "noGrab", "0" ); + + xraySkin = NULL; + renderEntity.xrayIndex = 1; + + idStr str; + if ( spawnArgs.GetString( "skin_xray", "", str ) ) { + xraySkin = declManager->FindSkin( str.c_str() ); + } +#endif + // go dormant within 5 frames so that when the map starts most monsters are dormant dormantStart = gameLocal.time - DELAY_DORMANT_TIME + gameLocal.msec * 5; @@ -570,6 +608,11 @@ void idEntity::Spawn( void ) { ConstructScriptObject(); } + +#ifdef _D3XP + // determine time group + DetermineTimeGroup( spawnArgs.GetBool( "slowmo", "1" ) ); +#endif } /* @@ -621,6 +664,13 @@ idEntity::~idEntity( void ) { FreeModelDef(); FreeSoundEmitter( false ); +#ifdef _D3XP + if ( xrayEntityHandle != -1) { + gameRenderWorld->FreeEntityDef( xrayEntityHandle ); + xrayEntityHandle = -1; + } +#endif + gameLocal.UnregisterEntity( this ); } @@ -661,6 +711,14 @@ void idEntity::Save( idSaveGame *savefile ) const { LittleBitField( &flags, sizeof( flags ) ); savefile->Write( &flags, sizeof( flags ) ); +#ifdef _D3XP + savefile->WriteInt( timeGroup ); + savefile->WriteBool( noGrab ); + savefile->WriteRenderEntity( xrayEntity ); + savefile->WriteInt( xrayEntityHandle ); + savefile->WriteSkin( xraySkin ); +#endif + savefile->WriteRenderEntity( renderEntity ); savefile->WriteInt( modelDefHandle ); savefile->WriteRefSound( refSound ); @@ -736,6 +794,17 @@ void idEntity::Restore( idRestoreGame *savefile ) { savefile->Read( &fl, sizeof( fl ) ); LittleBitField( &fl, sizeof( fl ) ); +#ifdef _D3XP + savefile->ReadInt( timeGroup ); + savefile->ReadBool( noGrab ); + savefile->ReadRenderEntity( xrayEntity ); + savefile->ReadInt( xrayEntityHandle ); + if ( xrayEntityHandle != -1 ) { + xrayEntityHandle = gameRenderWorld->AddEntityDef( &xrayEntity ); + } + savefile->ReadSkin( xraySkin ); +#endif + savefile->ReadRenderEntity( renderEntity ); savefile->ReadInt( modelDefHandle ); savefile->ReadRefSound( refSound ); @@ -1212,6 +1281,10 @@ idEntity::UpdateModel ================ */ void idEntity::UpdateModel( void ) { +#ifdef _D3XP + renderEntity.timeGroup = timeGroup; +#endif + UpdateModelTransform(); // check if the entity has an MD5 model @@ -1226,6 +1299,21 @@ void idEntity::UpdateModel( void ) { // ensure that we call Present this frame BecomeActive( TH_UPDATEVISUALS ); + +#ifdef _D3XP + // If the entity has an xray skin, go ahead and add it + if ( xraySkin != NULL ) { + xrayEntity = renderEntity; + xrayEntity.xrayIndex = 2; + xrayEntity.customSkin = xraySkin; + + if ( xrayEntityHandle == -1 ) { + xrayEntityHandle = gameRenderWorld->AddEntityDef( &xrayEntity ); + } else { + gameRenderWorld->UpdateEntityDef( xrayEntityHandle, &xrayEntity ); + } + } +#endif } /* @@ -1254,7 +1342,7 @@ void idEntity::UpdatePVSAreas( void ) { // FIXME: some particle systems may have huge bounds and end up in many PVS areas // the first MAX_PVS_AREAS may not be visible to a network client and as a result the particle system may not show up when it should if ( localNumPVSAreas > MAX_PVS_AREAS ) { - localNumPVSAreas = gameLocal.pvs.GetPVSAreas( idBounds( modelAbsBounds.GetCenter() ).Expand( 64.0f ), localPVSAreas, sizeof( localPVSAreas ) / sizeof( localPVSAreas[0] ) ); + localNumPVSAreas = gameLocal.pvs.GetPVSAreas( idBounds( renderEntity.origin ).Expand( 64.0f ), localPVSAreas, sizeof( localPVSAreas ) / sizeof( localPVSAreas[0] ) ); } for ( numPVSAreas = 0; numPVSAreas < MAX_PVS_AREAS && numPVSAreas < localNumPVSAreas; numPVSAreas++ ) { @@ -1454,6 +1542,10 @@ bool idEntity::UpdateRenderEntity( renderEntity_s *renderEntity, const renderVie idAnimator *animator = GetAnimator(); if ( animator ) { +#ifdef _D3XP + SetTimeState ts( timeGroup ); +#endif + return animator->CreateFrame( gameLocal.time, false ); } @@ -1616,7 +1708,11 @@ bool idEntity::StartSoundShader( const idSoundShader *shader, const s_channelTyp UpdateSound(); +#ifdef _D3XP + len = refSound.referenceSound->StartSound( shader, channel, diversity, soundShaderFlags, !timeGroup /*_D3XP*/ ); +#else len = refSound.referenceSound->StartSound( shader, channel, diversity, soundShaderFlags ); +#endif // _D3XP if ( length ) { *length = len; } @@ -2985,6 +3081,10 @@ void idEntity::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &di return; } +#ifdef _D3XP + SetTimeState ts( timeGroup ); +#endif + if ( !inflictor ) { inflictor = gameLocal.world; } @@ -3108,7 +3208,7 @@ Can be overridden by subclasses when a thread doesn't need to be allocated. ================ */ idThread *idEntity::ConstructScriptObject( void ) { - idThread *thread; + idThread *thread; const function_t *constructor; // init the script object's data @@ -3450,6 +3550,15 @@ bool idEntity::HandleGuiCommands( idEntity *entityGui, const char *cmds ) { continue; } +#ifdef _D3XP + + if ( !token.Icmp( "martianbuddycomplete" ) ) { + gameLocal.GetLocalPlayer()->GiveEmail( "MartianBuddyGameComplete" ); + continue; + } + +#endif + // handy for debugging GUI stuff if ( !token.Icmp( "print" ) ) { @@ -3633,6 +3742,10 @@ bool idEntity::TouchTriggers( void ) const { continue; } +#ifdef _D3XP + SetTimeState ts( ent->timeGroup ); +#endif + numEntities++; trace.c.contents = cm->GetContents(); @@ -4309,6 +4422,9 @@ idEntity::Event_SetKey */ void idEntity::Event_SetKey( const char *key, const char *value ) { spawnArgs.Set( key, value ); +#ifdef _D3XP + UpdateChangeableSpawnArgs( NULL ); +#endif } /* @@ -4571,6 +4687,68 @@ void idEntity::Event_SetNeverDormant( int enable ) { dormantStart = 0; } +#ifdef _D3XP +/* +================ +idEntity::Event_SetGui +================ +* BSM Nerve: Allows guis to be changed at runtime. Guis that are +* loaded after the level loads should be precahced using PrecacheGui. +*/ +void idEntity::Event_SetGui( int guiNum, const char *guiName) { + idUserInterface** gui = NULL; + + if ( guiNum >= 1 && guiNum <= MAX_RENDERENTITY_GUI ) { + gui = &renderEntity.gui[ guiNum-1 ]; + } + + if( gui ) { + *gui = uiManager->FindGui( guiName, true, false ); + UpdateGuiParms( *gui, &spawnArgs ); + UpdateChangeableSpawnArgs( NULL ); + gameRenderWorld->UpdateEntityDef(modelDefHandle, &renderEntity); + + } else { + gameLocal.Error( "Entity '%s' doesn't have a GUI %d", name.c_str(), guiNum ); + } + +} + +/* +================ +idEntity::Event_PrecacheGui +================ +* BSM Nerve: Forces the engine to initialize a gui even if it is not specified as used in a level. +* This is useful for preventing load hitches when switching guis during the game using "setGui" +*/ +void idEntity::Event_PrecacheGui( const char *guiName ) { + uiManager->FindGui( guiName, true, true ); +} + +void idEntity::Event_GetGuiParm(int guiNum, const char *key) { + if(renderEntity.gui[guiNum-1]) { + idThread::ReturnString(renderEntity.gui[guiNum-1]->GetStateString(key)); + return; + } + idThread::ReturnString(""); +} + +void idEntity::Event_GetGuiParmFloat(int guiNum, const char *key) { + if(renderEntity.gui[guiNum-1]) { + idThread::ReturnFloat(renderEntity.gui[guiNum-1]->GetStateFloat(key)); + return; + } + idThread::ReturnFloat(0.0f); +} + +void idEntity::Event_GuiNamedEvent(int guiNum, const char *event) { + if(renderEntity.gui[guiNum-1]) { + renderEntity.gui[guiNum-1]->HandleNamedEvent(event); + } +} + +#endif + /*********************************************************************** Network @@ -4860,6 +5038,40 @@ bool idEntity::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) { return false; } +#ifdef _D3XP +/* +================ +idEntity::DetermineTimeGroup +================ +*/ +void idEntity::DetermineTimeGroup( bool slowmo ) { + if ( slowmo || gameLocal.isMultiplayer ) { + timeGroup = TIME_GROUP1; + } + else { + timeGroup = TIME_GROUP2; + } +} + +/* +================ +idEntity::SetGrabbedState +================ +*/ +void idEntity::SetGrabbedState( bool grabbed ) { + fl.grabbed = grabbed; +} + +/* +================ +idEntity::IsGrabbed +================ +*/ +bool idEntity::IsGrabbed() { + return fl.grabbed; +} +#endif + /* =============================================================================== @@ -5166,6 +5378,10 @@ void idAnimatedEntity::AddLocalDamageEffect( jointHandle_t jointNum, const idVec idVec3 origin, dir; idMat3 axis; +#ifdef _D3XP + SetTimeState ts( timeGroup ); +#endif + axis = renderEntity.joints[jointNum].ToMat3() * renderEntity.axis; origin = renderEntity.origin + renderEntity.joints[jointNum].ToVec3() * renderEntity.axis; @@ -5264,7 +5480,11 @@ void idAnimatedEntity::UpdateDamageEffects( void ) { axis *= renderEntity.axis; origin = renderEntity.origin + origin * renderEntity.axis; start = origin + de->localOrigin * axis; +#ifdef _D3XP + if ( !gameLocal.smokeParticles->EmitSmoke( de->type, de->time, gameLocal.random.CRandomFloat(), start, axis, timeGroup /*_D3XP*/ ) ) { +#else if ( !gameLocal.smokeParticles->EmitSmoke( de->type, de->time, gameLocal.random.CRandomFloat(), start, axis ) ) { +#endif // _D3XP de->time = 0; } } diff --git a/game/Entity.h b/game/Entity.h index 709543b1..4413c303 100644 --- a/game/Entity.h +++ b/game/Entity.h @@ -156,8 +156,24 @@ class idEntity : public idClass { bool isDormant :1; // if true the entity is dormant bool hasAwakened :1; // before a monster has been awakened the first time, use full PVS for dormant instead of area-connected bool networkSync :1; // if true the entity is synchronized over the network + bool grabbed :1; // if true object is currently being grabbed } fl; +#ifdef _D3XP + int timeGroup; + + bool noGrab; + + renderEntity_t xrayEntity; + qhandle_t xrayEntityHandle; + const idDeclSkin * xraySkin; + + void DetermineTimeGroup( bool slowmo ); + + void SetGrabbedState( bool grabbed ); + bool IsGrabbed(); +#endif + public: ABSTRACT_PROTOTYPE( idEntity ); @@ -465,6 +481,13 @@ class idEntity : public idClass { void Event_HasFunction( const char *name ); void Event_CallFunction( const char *name ); void Event_SetNeverDormant( int enable ); +#ifdef _D3XP + void Event_SetGui( int guiNum, const char *guiName); + void Event_PrecacheGui( const char *guiName ); + void Event_GetGuiParm(int guiNum, const char *key); + void Event_GetGuiParmFloat(int guiNum, const char *key); + void Event_GuiNamedEvent(int guiNum, const char *event); +#endif }; /* @@ -531,4 +554,76 @@ class idAnimatedEntity : public idEntity { void Event_GetJointAngle( jointHandle_t jointnum ); }; + +#ifdef _D3XP +class SetTimeState { + bool activated; + bool previousFast; + bool fast; + +public: + SetTimeState(); + SetTimeState( int timeGroup ); + ~SetTimeState(); + + void PushState( int timeGroup ); +}; + +ID_INLINE SetTimeState::SetTimeState() { + activated = false; + previousFast = false; +} + +ID_INLINE SetTimeState::SetTimeState( int timeGroup ) { + activated = false; + previousFast = false; + PushState( timeGroup ); +} + +ID_INLINE void SetTimeState::PushState( int timeGroup ) { + + // Don't mess with time in Multiplayer + if ( !gameLocal.isMultiplayer ) { + + activated = true; + + // determine previous fast setting + if ( gameLocal.time == gameLocal.slow.time ) { + previousFast = false; + } + else { + previousFast = true; + } + + // determine new fast setting + if ( timeGroup ) { + fast = true; + } + else { + fast = false; + } + + // set correct time + if ( fast ) { + gameLocal.fast.Get( gameLocal.time, gameLocal.previousTime, gameLocal.msec, gameLocal.framenum, gameLocal.realClientTime ); + } + else { + gameLocal.slow.Get( gameLocal.time, gameLocal.previousTime, gameLocal.msec, gameLocal.framenum, gameLocal.realClientTime ); + } + } +} + +ID_INLINE SetTimeState::~SetTimeState() { + if ( activated && !gameLocal.isMultiplayer ) { + // set previous correct time + if ( previousFast ) { + gameLocal.fast.Get( gameLocal.time, gameLocal.previousTime, gameLocal.msec, gameLocal.framenum, gameLocal.realClientTime ); + } + else { + gameLocal.slow.Get( gameLocal.time, gameLocal.previousTime, gameLocal.msec, gameLocal.framenum, gameLocal.realClientTime ); + } + } +} +#endif + #endif /* !__GAME_ENTITY_H__ */ diff --git a/game/Fx.cpp b/game/Fx.cpp index 549f9e13..ea8a09f5 100644 --- a/game/Fx.cpp +++ b/game/Fx.cpp @@ -516,6 +516,9 @@ void idEntityFx::Run( int time ) { } else if ( fxaction.trackOrigin ) { useAction->renderEntity.origin = GetPhysics()->GetOrigin() + fxaction.offset; useAction->renderEntity.axis = fxaction.explicitAxis ? fxaction.axis : GetPhysics()->GetAxis(); +#ifdef _D3XP + gameRenderWorld->UpdateEntityDef( useAction->modelDefHandle, &useAction->renderEntity ); +#endif } ApplyFade( fxaction, *useAction, time, actualStart ); break; @@ -544,6 +547,33 @@ void idEntityFx::Run( int time ) { } break; } +#ifdef _D3XP + case FX_SHOCKWAVE: { + if ( gameLocal.isClient ) { + useAction->shakeStarted = true; + break; + } + if ( !useAction->shakeStarted ) { + idStr shockDefName; + useAction->shakeStarted = true; + + shockDefName = fxaction.data; + if ( !shockDefName.Length() ) { + shockDefName = "func_shockwave"; + } + + projectileDef = gameLocal.FindEntityDefDict( shockDefName, false ); + if ( !projectileDef ) { + gameLocal.Warning( "shockwave \'%s\' not found", shockDefName.c_str() ); + } else { + gameLocal.SpawnEntityDef( *projectileDef, &ent ); + ent->SetOrigin( GetPhysics()->GetOrigin() + fxaction.offset ); + ent->PostEventMS( &EV_Remove, ent->spawnArgs.GetInt( "duration" ) ); + } + } + break; + } +#endif } } } diff --git a/game/GameBase.h b/game/GameBase.h index 5269b673..9ff3a4ab 100644 --- a/game/GameBase.h +++ b/game/GameBase.h @@ -34,6 +34,9 @@ If you have questions concerning this license or the applicable additional terms #define SCRIPT_DEFAULT "script/doom_main.script" #define SCRIPT_DEFAULTFUNC "doom_main" +#define TIME_GROUP1 0 +#define TIME_GROUP2 1 + #define LAGO_IMG_WIDTH 64 #define LAGO_IMG_HEIGHT 64 #define LAGO_WIDTH 64 diff --git a/game/Game_local.cpp b/game/Game_local.cpp index ae1eb864..449b49aa 100644 --- a/game/Game_local.cpp +++ b/game/Game_local.cpp @@ -53,8 +53,9 @@ If you have questions concerning this license or the applicable additional terms const int NUM_RENDER_PORTAL_BITS = idMath::BitsForInteger( PS_BLOCK_ALL ); -const float DEFAULT_GRAVITY = 1066.0f; -const idVec3 DEFAULT_GRAVITY_VEC3( 0, 0, -DEFAULT_GRAVITY ); +const float DEFAULT_GRAVITY = 1066.0f; +const idVec3 DEFAULT_GRAVITY_VEC3( 0, 0, -DEFAULT_GRAVITY ); + const int CINEMATIC_SKIP_DELAY = SEC2MS( 2.0f ); #ifdef GAME_DLL @@ -95,12 +96,48 @@ const char *idGameLocal::sufaceTypeNames[ MAX_SURFACE_TYPES ] = { "ricochet", "surftype10", "surftype11", "surftype12", "surftype13", "surftype14", "surftype15" }; +#ifdef _D3XP +// List of all defs used by the player that will stay on the fast timeline +static const char* fastEntityList[] = { + "player_doommarine", + "weapon_chainsaw", + "weapon_fists", + "weapon_flashlight", + "weapon_rocketlauncher", + "projectile_rocket", + "weapon_machinegun", + "projectile_bullet_machinegun", + "weapon_pistol", + "projectile_bullet_pistol", + "weapon_handgrenade", + "projectile_grenade", + "weapon_bfg", + "projectile_bfg", + "weapon_chaingun", + "projectile_chaingunbullet", + "weapon_pda", + "weapon_plasmagun", + "projectile_plasmablast", + "weapon_shotgun", + "projectile_bullet_shotgun", + "weapon_soulcube", + "projectile_soulblast", + "weapon_shotgun_double", + "projectile_shotgunbullet_double", + "weapon_grabber", + "weapon_bloodstone_active1", + "weapon_bloodstone_active2", + "weapon_bloodstone_active3", + "weapon_bloodstone_passive", + NULL }; +#endif /* =========== GetGameAPI ============ */ extern "C" ID_GAME_API gameExport_t *GetGameAPI( gameImport_t *import ) { + if ( import->version == GAME_API_VERSION ) { // set interface pointers used by the game @@ -225,8 +262,8 @@ void idGameLocal::Clear( void ) { lastAIAlertTime = 0; spawnArgs.Clear(); gravity.Set( 0, 0, -1 ); - playerPVS.h = (unsigned int)-1; - playerConnectedAreas.h = (unsigned int)-1; + playerPVS.h = -1; + playerConnectedAreas.h = -1; gamestate = GAMESTATE_UNINITIALIZED; skipCinematic = false; influenceActive = false; @@ -254,6 +291,13 @@ void idGameLocal::Clear( void ) { savedEventQueue.Init(); memset( lagometer, 0, sizeof( lagometer ) ); + +#ifdef _D3XP + portalSkyEnt = NULL; + portalSkyActive = false; + + ResetSlowTimeVars(); +#endif } /* @@ -309,9 +353,41 @@ void idGameLocal::Init( void ) { InitConsoleCommands(); + +#ifdef _D3XP + if(!g_xp_bind_run_once.GetBool()) { + //The default config file contains remapped controls that support the XP weapons + //We want to run this once after the base doom config file has run so we can + //have the correct xp binds + cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "exec default.cfg\n" ); + cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "seta g_xp_bind_run_once 1\n" ); + cmdSystem->ExecuteCommandBuffer(); + } +#endif + // load default scripts program.Startup( SCRIPT_DEFAULT ); +#ifdef _D3XP + //BSM Nerve: Loads a game specific main script file + idStr gamedir; + int i; + for ( i = 0; i < 2; i++ ) { + if ( i == 0 ) { + gamedir = cvarSystem->GetCVarString( "fs_game_base" ); + } else if ( i == 1 ) { + gamedir = cvarSystem->GetCVarString( "fs_game" ); + } + if( gamedir.Length() > 0 ) { + idStr scriptFile = va( "script/%s_main.script", gamedir.c_str() ); + if ( fileSystem->ReadFile( scriptFile.c_str(), NULL ) > 0 ) { + program.CompileFile( scriptFile.c_str() ); + program.FinishCompilation(); + } + } + } +#endif + smokeParticles = new idSmokeParticles; // set up the aas @@ -533,6 +609,10 @@ void idGameLocal::SaveGame( idFile *f ) { savegame.WriteInt( previousTime ); savegame.WriteInt( time ); +#ifdef _D3XP + savegame.WriteInt( msec ); +#endif + savegame.WriteInt( vacuumAreaNum ); savegame.WriteInt( entityDefBits ); @@ -547,6 +627,18 @@ void idGameLocal::SaveGame( idFile *f ) { savegame.WriteBool( isNewFrame ); savegame.WriteFloat( clientSmoothing ); +#ifdef _D3XP + portalSkyEnt.Save( &savegame ); + savegame.WriteBool( portalSkyActive ); + + fast.Save( &savegame ); + slow.Save( &savegame ); + + savegame.WriteInt( slowmoState ); + savegame.WriteFloat( slowmoMsec ); + savegame.WriteBool( quickSlowmoReset ); +#endif + savegame.WriteBool( mapCycleLoaded ); savegame.WriteInt( spawnCount ); @@ -855,6 +947,12 @@ void idGameLocal::LoadMap( const char *mapName, int randseed ) { // clear the sound system gameSoundWorld->ClearAllSoundEmitters(); +#ifdef _D3XP + // clear envirosuit sound fx + gameSoundWorld->SetEnviroSuit( false ); + gameSoundWorld->SetSlowmo( false ); +#endif + InitAsyncNetwork(); if ( !sameMap || ( mapFile && mapFile->NeedsReload() ) ) { @@ -917,6 +1015,13 @@ void idGameLocal::LoadMap( const char *mapName, int randseed ) { sessionCommand = ""; nextGibTime = 0; +#ifdef _D3XP + portalSkyEnt = NULL; + portalSkyActive = false; + + ResetSlowTimeVars(); +#endif + vacuumAreaNum = -1; // if an info_vacuum is spawned, it will set this if ( !editEntities ) { @@ -977,12 +1082,19 @@ void idGameLocal::LocalMapRestart( ) { MapClear( false ); + + // clear the smoke particle free list smokeParticles->Init(); // clear the sound system if ( gameSoundWorld ) { gameSoundWorld->ClearAllSoundEmitters(); +#ifdef _D3XP + // clear envirosuit sound fx + gameSoundWorld->SetEnviroSuit( false ); + gameSoundWorld->SetSlowmo( false ); +#endif } // the spawnCount is reset to zero temporarily to spawn the map entities with the same spawnId @@ -1024,6 +1136,20 @@ void idGameLocal::MapRestart( ) { int i; const idKeyValue *keyval, *keyval2; +#ifdef _D3XP + if ( isMultiplayer && isServer ) { + char buf[ MAX_STRING_CHARS ]; + idStr gametype; + GetBestGameType( si_map.GetString(), si_gameType.GetString(), buf ); + gametype = buf; + if ( gametype != si_gameType.GetString() ) { + cvarSystem->SetCVarString( "si_gameType", gametype ); + } + } +#endif + + + if ( isClient ) { LocalMapRestart(); } else { @@ -1041,6 +1167,7 @@ void idGameLocal::MapRestart( ) { } } cmdSystem->BufferCommandText( CMD_EXEC_NOW, "rescanSI" ); + if ( i != newInfo.GetNumKeyVals() ) { cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "nextMap" ); } else { @@ -1054,6 +1181,17 @@ void idGameLocal::MapRestart( ) { mpGame.MapRestart(); } } + +#ifdef CTF + if ( isMultiplayer ) { + gameLocal.mpGame.ReloadScoreboard(); + // gameLocal.mpGame.Reset(); // force reconstruct the GUIs when reloading maps, different gametypes have different GUIs + // gameLocal.mpGame.UpdateMainGui(); + // gameLocal.mpGame.StartMenu(); + // gameLocal.mpGame.DisableMenu(); + // gameLocal.mpGame.Precache(); + } +#endif } /* @@ -1380,6 +1518,10 @@ bool idGameLocal::InitFromSaveGame( const char *mapName, idRenderWorld *renderWo savegame.ReadInt( previousTime ); savegame.ReadInt( time ); +#ifdef _D3XP + savegame.ReadInt( msec ); +#endif + savegame.ReadInt( vacuumAreaNum ); savegame.ReadInt( entityDefBits ); @@ -1394,6 +1536,35 @@ bool idGameLocal::InitFromSaveGame( const char *mapName, idRenderWorld *renderWo savegame.ReadBool( isNewFrame ); savegame.ReadFloat( clientSmoothing ); +#ifdef _D3XP + portalSkyEnt.Restore( &savegame ); + savegame.ReadBool( portalSkyActive ); + + fast.Restore( &savegame ); + slow.Restore( &savegame ); + + int blah; + savegame.ReadInt( blah ); + slowmoState = (slowmoState_t)blah; + + savegame.ReadFloat( slowmoMsec ); + savegame.ReadBool( quickSlowmoReset ); + + if ( slowmoState == SLOWMO_STATE_OFF ) { + if ( gameSoundWorld ) { + gameSoundWorld->SetSlowmo( false ); + } + } + else { + if ( gameSoundWorld ) { + gameSoundWorld->SetSlowmo( true ); + } + } + if ( gameSoundWorld ) { + gameSoundWorld->SetSlowmoSpeed( slowmoMsec / (float)USERCMD_MSEC ); + } +#endif + savegame.ReadBool( mapCycleLoaded ); savegame.ReadInt( spawnCount ); @@ -1565,6 +1736,20 @@ void idGameLocal::DumpOggSounds( void ) { soundName = soundShader->GetSound( j ); soundName.BackSlashesToSlashes(); +#ifdef _D3XP + // D3XP :: don't add sounds that are in Doom 3's pak files + if ( fileSystem->FileIsInPAK( soundName ) ) { + continue; + } else { + // Also check for a pre-ogg'd version in the pak file + idStr testName = soundName; + + testName.SetFileExtension( ".ogg" ); + if ( fileSystem->FileIsInPAK( testName ) ) { + continue; + } + } +#endif // don't OGG sounds that cause a shake because that would // cause continuous seeking on the OGG file which is expensive if ( parms->shakes != 0.0f ) { @@ -1635,8 +1820,8 @@ void idGameLocal::DumpOggSounds( void ) { size = fileSystem->ReadFile( oggSounds[i], NULL, NULL ); totalSize += size; oggSounds[i].Replace( "/", "\\" ); - file->Printf( "w:\\doom\\ogg\\oggenc -q 0 \"c:\\doom\\base\\%s\"\n", oggSounds[i].c_str() ); - file->Printf( "del \"c:\\doom\\base\\%s\"\n", oggSounds[i].c_str() ); + file->Printf( "z:\\d3xp\\ogg\\oggenc -q 0 \"%s\\d3xp\\%s\"\n", cvarSystem->GetCVarString( "fs_basepath" ), oggSounds[i].c_str() ); + file->Printf( "del \"%s\\d3xp\\%s\"\n", cvarSystem->GetCVarString( "fs_basepath" ), oggSounds[i].c_str() ); } file->Printf( "\n\necho %d kB in OGG sounds\n\n\n", totalSize >> 10 ); @@ -1871,7 +2056,16 @@ void idGameLocal::SpawnPlayer( int clientNum ) { args.SetInt( "spawn_entnum", clientNum ); args.Set( "name", va( "player%d", clientNum + 1 ) ); +#ifdef CTF + if ( isMultiplayer && gameType != GAME_CTF ) + args.Set( "classname", "player_doommarine_mp" ); + else if ( isMultiplayer && gameType == GAME_CTF ) + args.Set( "classname", "player_doommarine_ctf" ); + else + args.Set( "classname", "player_doommarine" ); +#else args.Set( "classname", isMultiplayer ? "player_doommarine_mp" : "player_doommarine" ); +#endif if ( !SpawnEntityDef( args, &ent ) || !entities[ clientNum ] ) { Error( "Failed to spawn player as '%s'", args.GetString( "classname" ) ); } @@ -2040,6 +2234,25 @@ void idGameLocal::SetupPlayerPVS( void ) { pvs.FreeCurrentPVS( otherPVS ); playerConnectedAreas = newPVS; } + +#ifdef _D3XP + // if portalSky is preset, then merge into pvs so we get rotating brushes, etc + if ( portalSkyEnt.GetEntity() ) { + idEntity *skyEnt = portalSkyEnt.GetEntity(); + + otherPVS = pvs.SetupCurrentPVS( skyEnt->GetPVSAreas(), skyEnt->GetNumPVSAreas() ); + newPVS = pvs.MergeCurrentPVS( playerPVS, otherPVS ); + pvs.FreeCurrentPVS( playerPVS ); + pvs.FreeCurrentPVS( otherPVS ); + playerPVS = newPVS; + + otherPVS = pvs.SetupCurrentPVS( skyEnt->GetPVSAreas(), skyEnt->GetNumPVSAreas() ); + newPVS = pvs.MergeCurrentPVS( playerConnectedAreas, otherPVS ); + pvs.FreeCurrentPVS( playerConnectedAreas ); + pvs.FreeCurrentPVS( otherPVS ); + playerConnectedAreas = newPVS; + } +#endif } } @@ -2190,6 +2403,32 @@ void idGameLocal::SortActiveEntityList( void ) { sortPushers = false; } +#ifdef _D3XP +/* +================ +idGameLocal::RunTimeGroup2 +================ +*/ +void idGameLocal::RunTimeGroup2() { + idEntity *ent; + int num = 0; + + fast.Increment(); + fast.Get( time, previousTime, msec, framenum, realClientTime ); + + for( ent = activeEntities.Next(); ent != NULL; ent = ent->activeNode.Next() ) { + if ( ent->timeGroup != TIME_GROUP2 ) { + continue; + } + + ent->Think(); + num++; + } + + slow.Get( time, previousTime, msec, framenum, realClientTime ); +} +#endif + /* ================ idGameLocal::RunFrame @@ -2212,6 +2451,13 @@ gameReturn_t idGameLocal::RunFrame( const usercmd_t *clientCmds ) { player = GetLocalPlayer(); +#ifdef _D3XP + ComputeSlowMsec(); + + slow.Get( time, previousTime, msec, framenum, realClientTime ); + msec = slowmoMsec; +#endif + if ( !isMultiplayer && g_stopTime.GetBool() ) { // clear any debug lines from a previous frame gameRenderWorld->DebugClearLines( time + 1 ); @@ -2229,6 +2475,10 @@ gameReturn_t idGameLocal::RunFrame( const usercmd_t *clientCmds ) { time += msec; realClientTime = time; +#ifdef _D3XP + slow.Set( time, previousTime, msec, framenum, realClientTime ); +#endif + #ifdef GAME_DLL // allow changing SIMD usage on the fly if ( com_forceGenericSIMD.IsModified() ) { @@ -2289,7 +2539,7 @@ gameReturn_t idGameLocal::RunFrame( const usercmd_t *clientCmds ) { timer_singlethink.Stop(); ms = timer_singlethink.Milliseconds(); if ( ms >= g_timeentities.GetFloat() ) { - Printf( "%d: entity '%s': %.1f ms\n", time, ent->name.c_str(), ms ); + Printf( "%d: entity '%s': %f ms\n", time, ent->name.c_str(), ms ); } num++; } @@ -2307,12 +2557,21 @@ gameReturn_t idGameLocal::RunFrame( const usercmd_t *clientCmds ) { } else { num = 0; for( ent = activeEntities.Next(); ent != NULL; ent = ent->activeNode.Next() ) { +#ifdef _D3XP + if ( ent->timeGroup != TIME_GROUP1 ) { + continue; + } +#endif ent->Think(); num++; } } } +#ifdef _D3XP + RunTimeGroup2(); +#endif + // remove any entities that have stopped thinking if ( numEntitiesToDeactivate ) { idEntity *next_ent; @@ -2335,6 +2594,13 @@ gameReturn_t idGameLocal::RunFrame( const usercmd_t *clientCmds ) { // service any pending events idEvent::ServiceEvents(); +#ifdef _D3XP + // service pending fast events + fast.Get( time, previousTime, msec, framenum, realClientTime ); + idEvent::ServiceFastEvents(); + slow.Get( time, previousTime, msec, framenum, realClientTime ); +#endif + timer_events.Stop(); // free the player pvs @@ -3083,19 +3349,36 @@ bool idGameLocal::SpawnEntityDef( const idDict &args, idEntity **ent, bool setDe spawnArgs.SetDefaults( &def->dict ); +#ifdef _D3XP + if ( !spawnArgs.FindKey( "slowmo" ) ) { + bool slowmo = true; + + for ( int i = 0; fastEntityList[i]; i++ ) { + if ( !idStr::Cmp( classname, fastEntityList[i] ) ) { + slowmo = false; + break; + } + } + + if ( !slowmo ) { + spawnArgs.SetBool( "slowmo", slowmo ); + } + } +#endif + // check if we should spawn a class object spawnArgs.GetString( "spawnclass", NULL, &spawn ); if ( spawn ) { cls = idClass::GetClass( spawn ); if ( !cls ) { - Warning( "Could not spawn '%s'. Class '%s' not found%s.", classname, spawn, error.c_str() ); + Warning( "Could not spawn '%s'. Class '%s' not found %s.", classname, spawn, error.c_str() ); return false; } obj = cls->CreateInstance(); if ( !obj ) { - Warning( "Could not spawn '%s'. Instance could not be created%s.", classname, error.c_str() ); + Warning( "Could not spawn '%s'. Instance could not be created %s.", classname, error.c_str() ); return false; } @@ -3168,12 +3451,21 @@ bool idGameLocal::InhibitEntitySpawn( idDict &spawnArgs ) { spawnArgs.GetBool( "not_medium", "0", result ); } else { spawnArgs.GetBool( "not_hard", "0", result ); +#ifdef _D3XP + if ( !result && g_skill.GetInteger() == 3 ) { + spawnArgs.GetBool( "not_nightmare", "0", result ); + } +#endif } + const char *name; if ( g_skill.GetInteger() == 3 ) { name = spawnArgs.GetString( "classname" ); - if ( idStr::Icmp( name, "item_medkit" ) == 0 || idStr::Icmp( name, "item_medkit_small" ) == 0 ) { + // _D3XP :: remove moveable medkit packs also + if ( idStr::Icmp( name, "item_medkit" ) == 0 || idStr::Icmp( name, "item_medkit_small" ) == 0 || + idStr::Icmp( name, "moveable_item_medkit" ) == 0 || idStr::Icmp( name, "moveable_item_medkit_small" ) == 0 ) { + result = true; } } @@ -3572,6 +3864,14 @@ idGameLocal::GetAlertEntity ============ */ idActor *idGameLocal::GetAlertEntity( void ) { +#ifdef _D3XP + int timeGroup = 0; + if ( lastAIAlertTime && lastAIAlertEntity.GetEntity() ) { + timeGroup = lastAIAlertEntity.GetEntity()->timeGroup; + } + SetTimeState ts( timeGroup ); +#endif + if ( lastAIAlertTime >= time ) { return lastAIAlertEntity.GetEntity(); } @@ -3862,7 +4162,11 @@ void idGameLocal::ProjectDecal( const idVec3 &origin, const idVec3 &dir, float d winding += idVec5( windingOrigin + ( axis * decalWinding[1] ) * size, idVec2( 0, 1 ) ); winding += idVec5( windingOrigin + ( axis * decalWinding[2] ) * size, idVec2( 0, 0 ) ); winding += idVec5( windingOrigin + ( axis * decalWinding[3] ) * size, idVec2( 1, 0 ) ); +#ifdef _D3XP + gameRenderWorld->ProjectDecalOntoWorld( winding, projectionOrigin, parallel, depth * 0.5f, declManager->FindMaterial( material ), gameLocal.slow.time /* _D3XP */ ); +#else gameRenderWorld->ProjectDecalOntoWorld( winding, projectionOrigin, parallel, depth * 0.5f, declManager->FindMaterial( material ), time ); +#endif } /* @@ -4143,6 +4447,10 @@ prepare for a sequence of initial player spawns void idGameLocal::RandomizeInitialSpawns( void ) { spawnSpot_t spot; int i, j; +#ifdef CTF + int k; +#endif + idEntity *ent; if ( !isMultiplayer || isClient ) { @@ -4150,19 +4458,84 @@ void idGameLocal::RandomizeInitialSpawns( void ) { } spawnSpots.Clear(); initialSpots.Clear(); +#ifdef CTF + teamSpawnSpots[0].Clear(); + teamSpawnSpots[1].Clear(); + teamInitialSpots[0].Clear(); + teamInitialSpots[1].Clear(); +#endif + spot.dist = 0; spot.ent = FindEntityUsingDef( NULL, "info_player_deathmatch" ); while( spot.ent ) { +#ifdef CTF + spot.ent->spawnArgs.GetInt( "team", "-1", spot.team ); + + if ( mpGame.IsGametypeFlagBased() ) /* CTF */ + { + if ( spot.team == 0 || spot.team == 1 ) + teamSpawnSpots[spot.team].Append( spot ); + else + common->Warning( "info_player_deathmatch : invalid or no team attached to spawn point\n"); + } +#endif spawnSpots.Append( spot ); if ( spot.ent->spawnArgs.GetBool( "initial" ) ) { +#ifdef CTF + if ( mpGame.IsGametypeFlagBased() ) /* CTF */ + { + assert( spot.team == 0 || spot.team == 1 ); + teamInitialSpots[ spot.team ].Append( spot.ent ); + } +#endif + initialSpots.Append( spot.ent ); } spot.ent = FindEntityUsingDef( spot.ent, "info_player_deathmatch" ); } + +#ifdef CTF + if ( mpGame.IsGametypeFlagBased() ) /* CTF */ + { + if ( !teamSpawnSpots[0].Num() ) + common->Warning( "red team : no info_player_deathmatch in map" ); + if ( !teamSpawnSpots[1].Num() ) + common->Warning( "blue team : no info_player_deathmatch in map" ); + + if ( !teamSpawnSpots[0].Num() || !teamSpawnSpots[1].Num() ) + return; + } +#endif + if ( !spawnSpots.Num() ) { common->Warning( "no info_player_deathmatch in map" ); return; } + +#ifdef CTF + if ( mpGame.IsGametypeFlagBased() ) /* CTF */ + { + common->Printf( "red team : %d spawns (%d initials)\n", teamSpawnSpots[ 0 ].Num(), teamInitialSpots[ 0 ].Num() ); + // if there are no initial spots in the map, consider they can all be used as initial + if ( !teamInitialSpots[ 0 ].Num() ) { + common->Warning( "red team : no info_player_deathmatch entities marked initial in map" ); + for ( i = 0; i < teamSpawnSpots[ 0 ].Num(); i++ ) { + teamInitialSpots[ 0 ].Append( teamSpawnSpots[ 0 ][ i ].ent ); + } + } + + common->Printf( "blue team : %d spawns (%d initials)\n", teamSpawnSpots[ 1 ].Num(), teamInitialSpots[ 1 ].Num() ); + // if there are no initial spots in the map, consider they can all be used as initial + if ( !teamInitialSpots[ 1 ].Num() ) { + common->Warning( "blue team : no info_player_deathmatch entities marked initial in map" ); + for ( i = 0; i < teamSpawnSpots[ 1 ].Num(); i++ ) { + teamInitialSpots[ 1 ].Append( teamSpawnSpots[ 1 ][ i ].ent ); + } + } + } +#endif + + common->Printf( "%d spawns (%d initials)\n", spawnSpots.Num(), initialSpots.Num() ); // if there are no initial spots in the map, consider they can all be used as initial if ( !initialSpots.Num() ) { @@ -4171,6 +4544,17 @@ void idGameLocal::RandomizeInitialSpawns( void ) { initialSpots.Append( spawnSpots[ i ].ent ); } } + +#ifdef CTF + for ( k = 0; k < 2; k++ ) + for ( i = 0; i < teamInitialSpots[ k ].Num(); i++ ) { + j = random.RandomInt( teamInitialSpots[ k ].Num() ); + ent = teamInitialSpots[ k ][ i ]; + teamInitialSpots[ k ][ i ] = teamInitialSpots[ k ][ j ]; + teamInitialSpots[ k ][ j ] = ent; + } +#endif + for ( i = 0; i < initialSpots.Num(); i++ ) { j = random.RandomInt( initialSpots.Num() ); ent = initialSpots[ i ]; @@ -4179,6 +4563,11 @@ void idGameLocal::RandomizeInitialSpawns( void ) { } // reset the counter currentInitialSpot = 0; + +#ifdef CTF + teamCurrentInitialSpot[0] = 0; + teamCurrentInitialSpot[1] = 0; +#endif } /* @@ -4197,18 +4586,43 @@ idEntity *idGameLocal::SelectInitialSpawnPoint( idPlayer *player ) { float dist; bool alone; +#ifdef CTF + if ( !isMultiplayer || !spawnSpots.Num() || ( mpGame.IsGametypeFlagBased() && ( !teamSpawnSpots[0].Num() || !teamSpawnSpots[1].Num() ) ) ) { /* CTF */ +#else if ( !isMultiplayer || !spawnSpots.Num() ) { +#endif spot.ent = FindEntityUsingDef( NULL, "info_player_start" ); if ( !spot.ent ) { Error( "No info_player_start on map.\n" ); } return spot.ent; } + +#ifdef CTF + bool useInitialSpots = false; + if ( mpGame.IsGametypeFlagBased() ) { /* CTF */ + assert( player->team == 0 || player->team == 1 ); + useInitialSpots = player->useInitialSpawns && teamCurrentInitialSpot[ player->team ] < teamInitialSpots[ player->team ].Num(); + } else { + useInitialSpots = player->useInitialSpawns && currentInitialSpot < initialSpots.Num(); + } +#endif + if ( player->spectating ) { // plain random spot, don't bother return spawnSpots[ random.RandomInt( spawnSpots.Num() ) ].ent; +#ifdef CTF + } else if ( useInitialSpots ) { + if ( mpGame.IsGametypeFlagBased() ) { /* CTF */ + assert( player->team == 0 || player->team == 1 ); + player->useInitialSpawns = false; // only use the initial spawn once + return teamInitialSpots[ player->team ][ teamCurrentInitialSpot[ player->team ]++ ]; + } + return initialSpots[ currentInitialSpot++ ]; +#else } else if ( player->useInitialSpawns && currentInitialSpot < initialSpots.Num() ) { return initialSpots[ currentInitialSpot++ ]; +#endif } else { // check if we are alone in map alone = true; @@ -4219,10 +4633,62 @@ idEntity *idGameLocal::SelectInitialSpawnPoint( idPlayer *player ) { } } if ( alone ) { +#ifdef CTF + if ( mpGame.IsGametypeFlagBased() ) /* CTF */ + { + assert( player->team == 0 || player->team == 1 ); + return teamSpawnSpots[ player->team ][ random.RandomInt( teamSpawnSpots[ player->team ].Num() ) ].ent; + } +#endif // don't do distance-based return spawnSpots[ random.RandomInt( spawnSpots.Num() ) ].ent; } +#ifdef CTF + if ( mpGame.IsGametypeFlagBased() ) /* CTF */ + { + // TODO : make as reusable method, same code as below + int team = player->team; + assert( team == 0 || team == 1 ); + + // find the distance to the closest active player for each spawn spot + for( i = 0; i < teamSpawnSpots[ team ].Num(); i++ ) { + pos = teamSpawnSpots[ team ][ i ].ent->GetPhysics()->GetOrigin(); + + // skip initial spawn points for CTF + if ( teamSpawnSpots[ team ][ i ].ent->spawnArgs.GetBool("initial") ) { + teamSpawnSpots[ team ][ i ].dist = 0x0; + continue; + } + + teamSpawnSpots[ team ][ i ].dist = 0x7fffffff; + + for( j = 0; j < MAX_CLIENTS; j++ ) { + if ( !entities[ j ] || !entities[ j ]->IsType( idPlayer::Type ) + || entities[ j ] == player + || static_cast< idPlayer * >( entities[ j ] )->spectating ) { + continue; + } + + dist = ( pos - entities[ j ]->GetPhysics()->GetOrigin() ).LengthSqr(); + if ( dist < teamSpawnSpots[ team ][ i ].dist ) { + teamSpawnSpots[ team ][ i ].dist = dist; + } + } + } + + // sort the list + qsort( ( void * )teamSpawnSpots[ team ].Ptr(), teamSpawnSpots[ team ].Num(), sizeof( spawnSpot_t ), ( int (*)(const void *, const void *) )sortSpawnPoints ); + + // choose a random one in the top half + which = random.RandomInt( teamSpawnSpots[ team ].Num() / 2 ); + spot = teamSpawnSpots[ team ][ which ]; +// assert( teamSpawnSpots[ team ][ which ].dist != 0 ); + + return spot.ent; + } +#endif + // find the distance to the closest active player for each spawn spot for( i = 0; i < spawnSpots.Num(); i++ ) { pos = spawnSpots[ i ].ent->GetPhysics()->GetOrigin(); @@ -4267,6 +4733,12 @@ void idGameLocal::UpdateServerInfoFlags() { } else if ( ( idStr::Icmp( serverInfo.GetString( "si_gameType" ), "Last Man" ) == 0 ) ) { gameType = GAME_LASTMAN; } +#ifdef CTF + else if ( ( idStr::Icmp( serverInfo.GetString( "si_gameType" ), "CTF" ) == 0 ) ) { + gameType = GAME_CTF; + } +#endif + if ( gameType == GAME_LASTMAN ) { if ( !serverInfo.GetInt( "si_warmup" ) ) { common->Warning( "Last Man Standing - forcing warmup on" ); @@ -4316,12 +4788,39 @@ void idGameLocal::ThrottleUserInfo( void ) { mpGame.ThrottleUserInfo(); } +#ifdef _D3XP +/* +================= +idPlayer::SetPortalSkyEnt +================= +*/ +void idGameLocal::SetPortalSkyEnt( idEntity *ent ) { + portalSkyEnt = ent; +} + +/* +================= +idPlayer::IsPortalSkyAcive +================= +*/ +bool idGameLocal::IsPortalSkyAcive() { + return portalSkyActive; +} +#endif /* =========== idGameLocal::SelectTimeGroup ============ */ -void idGameLocal::SelectTimeGroup( int timeGroup ) { } +void idGameLocal::SelectTimeGroup( int timeGroup ) { +#ifdef _D3XP + if ( timeGroup ) { + fast.Get( time, previousTime, msec, framenum, realClientTime ); + } else { + slow.Get( time, previousTime, msec, framenum, realClientTime ); + } +#endif // _D3XP +} /* =========== @@ -4329,24 +4828,160 @@ idGameLocal::GetTimeGroupTime ============ */ int idGameLocal::GetTimeGroupTime( int timeGroup ) { +#ifdef _D3XP + if ( timeGroup ) { + return fast.time; + } else { + return slow.time; + } +#else return gameLocal.time; +#endif // _D3XP } /* -=========== +=============== idGameLocal::GetBestGameType -============ +=============== */ void idGameLocal::GetBestGameType( const char* map, const char* gametype, char buf[ MAX_STRING_CHARS ] ) { +#ifdef _D3XP + idStr aux = mpGame.GetBestGametype( map, gametype ); + idStr::Copynz( buf, aux.c_str(), MAX_STRING_CHARS ); + buf[ MAX_STRING_CHARS - 1 ] = '\0'; +#else idStr::Copynz( buf, gametype, MAX_STRING_CHARS ); buf[ MAX_STRING_CHARS - 1 ] = '\0'; +#endif // _D3XP } +#ifdef _D3XP /* =========== -idGameLocal::NeedRestart +idGameLocal::ComputeSlowMsec ============ */ +void idGameLocal::ComputeSlowMsec() { + idPlayer *player; + bool powerupOn; + float delta; + + // check if we need to do a quick reset + if ( quickSlowmoReset ) { + quickSlowmoReset = false; + + // stop the sounds + if ( gameSoundWorld ) { + gameSoundWorld->SetSlowmo( false ); + gameSoundWorld->SetSlowmoSpeed( 1 ); + } + + // stop the state + slowmoState = SLOWMO_STATE_OFF; + slowmoMsec = USERCMD_MSEC; + } + + // check the player state + player = GetLocalPlayer(); + powerupOn = false; + + if ( player && player->PowerUpActive( HELLTIME ) ) { + powerupOn = true; + } + else if ( g_enableSlowmo.GetBool() ) { + powerupOn = true; + } + + // determine proper slowmo state + if ( powerupOn && slowmoState == SLOWMO_STATE_OFF ) { + slowmoState = SLOWMO_STATE_RAMPUP; + + slowmoMsec = msec; + if ( gameSoundWorld ) { + gameSoundWorld->SetSlowmo( true ); + gameSoundWorld->SetSlowmoSpeed( slowmoMsec / (float)USERCMD_MSEC ); + } + } + else if ( !powerupOn && slowmoState == SLOWMO_STATE_ON ) { + slowmoState = SLOWMO_STATE_RAMPDOWN; + + // play the stop sound + if ( player ) { + player->PlayHelltimeStopSound(); + } + } + + // do any necessary ramping + if ( slowmoState == SLOWMO_STATE_RAMPUP ) { + delta = 4 - slowmoMsec; + + if ( fabs( delta ) < g_slowmoStepRate.GetFloat() ) { + slowmoMsec = 4; + slowmoState = SLOWMO_STATE_ON; + } + else { + slowmoMsec += delta * g_slowmoStepRate.GetFloat(); + } + + if ( gameSoundWorld ) { + gameSoundWorld->SetSlowmoSpeed( slowmoMsec / (float)USERCMD_MSEC ); + } + } + else if ( slowmoState == SLOWMO_STATE_RAMPDOWN ) { + delta = 16 - slowmoMsec; + + if ( fabs( delta ) < g_slowmoStepRate.GetFloat() ) { + slowmoMsec = 16; + slowmoState = SLOWMO_STATE_OFF; + if ( gameSoundWorld ) { + gameSoundWorld->SetSlowmo( false ); + } + } + else { + slowmoMsec += delta * g_slowmoStepRate.GetFloat(); + } + + if ( gameSoundWorld ) { + gameSoundWorld->SetSlowmoSpeed( slowmoMsec / (float)USERCMD_MSEC ); + } + } +} + +/* +=========== +idGameLocal::ResetSlowTimeVars +============ +*/ +void idGameLocal::ResetSlowTimeVars() { + msec = USERCMD_MSEC; + slowmoMsec = USERCMD_MSEC; + slowmoState = SLOWMO_STATE_OFF; + + fast.framenum = 0; + fast.previousTime = 0; + fast.time = 0; + fast.msec = USERCMD_MSEC; + + slow.framenum = 0; + slow.previousTime = 0; + slow.time = 0; + slow.msec = USERCMD_MSEC; +} + +/* +=========== +idGameLocal::QuickSlowmoReset +============ +*/ +void idGameLocal::QuickSlowmoReset() { + quickSlowmoReset = true; +} + +/* +=============== +idGameLocal::NeedRestart +=============== +*/ bool idGameLocal::NeedRestart() { idDict newInfo; @@ -4368,6 +5003,8 @@ bool idGameLocal::NeedRestart() { return false; } +#endif + /* ================ idGameLocal::GetClientStats @@ -4386,12 +5023,8 @@ idGameLocal::SwitchTeam void idGameLocal::SwitchTeam( int clientNum, int team ) { idPlayer * player; - player = clientNum >= 0 ? static_cast( gameLocal.entities[ clientNum ] ) : NULL; - - if ( !player ) - return; - - int oldTeam = player->team; + player = static_cast< idPlayer * >( entities[ clientNum ] ); + int oldTeam = player->team ; // Put in spectator mode if ( team == -1 ) { @@ -4401,6 +5034,7 @@ void idGameLocal::SwitchTeam( int clientNum, int team ) { else { mpGame.SwitchToTeam ( clientNum, oldTeam, team ); } + player->forceRespawn = true ; } /* diff --git a/game/Game_local.h b/game/Game_local.h index df7456d1..9b38fb19 100644 --- a/game/Game_local.h +++ b/game/Game_local.h @@ -161,6 +161,9 @@ typedef enum { typedef struct { idEntity *ent; int dist; +#ifdef CTF + int team; +#endif } spawnSpot_t; //============================================================================ @@ -218,6 +221,29 @@ class idEntityPtr { int spawnId; }; +#ifdef _D3XP +struct timeState_t { + int time; + int previousTime; + int msec; + int framenum; + int realClientTime; + + void Set( int t, int pt, int ms, int f, int rct ) { time = t; previousTime = pt; msec = ms; framenum = f; realClientTime = rct; }; + void Get( int& t, int& pt, int& ms, int& f, int& rct ) { t = time; pt = previousTime; ms = msec; f = framenum; rct = realClientTime; }; + void Save( idSaveGame *savefile ) const { savefile->WriteInt( time ); savefile->WriteInt( previousTime ); savefile->WriteInt( msec ); savefile->WriteInt( framenum ); savefile->WriteInt( realClientTime ); } + void Restore( idRestoreGame *savefile ) { savefile->ReadInt( time ); savefile->ReadInt( previousTime ); savefile->ReadInt( msec ); savefile->ReadInt( framenum ); savefile->ReadInt( realClientTime ); } + void Increment() { framenum++; previousTime = time; time += msec; realClientTime = time; }; +}; + +enum slowmoState_t { + SLOWMO_STATE_OFF, + SLOWMO_STATE_RAMPUP, + SLOWMO_STATE_ON, + SLOWMO_STATE_RAMPDOWN +}; +#endif + //============================================================================ class idGameLocal : public idGame { @@ -272,7 +298,11 @@ class idGameLocal : public idGame { int framenum; int previousTime; // time in msec of last frame int time; // in msec +#ifdef _D3XP + int msec; // time since last update in milliseconds +#else static const int msec = USERCMD_MSEC; // time since last update in milliseconds +#endif // _D3XP int vacuumAreaNum; // -1 if level doesn't have any outside areas @@ -294,6 +324,27 @@ class idGameLocal : public idGame { idEntityPtr lastGUIEnt; // last entity with a GUI, used by Cmd_NextGUI_f int lastGUI; // last GUI on the lastGUIEnt +#ifdef _D3XP + idEntityPtr portalSkyEnt; + bool portalSkyActive; + + void SetPortalSkyEnt( idEntity *ent ); + bool IsPortalSkyAcive(); + + timeState_t fast; + timeState_t slow; + + slowmoState_t slowmoState; + float slowmoMsec; + + bool quickSlowmoReset; + + void ComputeSlowMsec(); + void RunTimeGroup2(); + + void ResetSlowTimeVars(); + void QuickSlowmoReset(); +#endif // ---------------------- Public idGame Interface ------------------- idGameLocal(); @@ -386,6 +437,9 @@ class idGameLocal : public idGame { bool InPlayerPVS( idEntity *ent ) const; bool InPlayerConnectedArea( idEntity *ent ) const; +#ifdef _D3XP + pvsHandle_t GetPlayerPVS() { return playerPVS; }; +#endif void SetCamera( idCamera *cam ); idCamera * GetCamera( void ) const; @@ -495,6 +549,12 @@ class idGameLocal : public idGame { idStaticList initialSpots; int currentInitialSpot; +#ifdef CTF + idStaticList teamSpawnSpots[2]; + idStaticList teamInitialSpots[2]; + int teamCurrentInitialSpot[2]; +#endif + idDict newInfo; idStrList shakeSounds; @@ -627,7 +687,7 @@ ID_INLINE int idEntityPtr::GetEntityNum( void ) const { return ( spawnId & ( ( 1 << GENTITYNUM_BITS ) - 1 ) ); } -//============================================================================ +// =========================================================================== // // these defines work for all startsounds from all entity types diff --git a/game/Game_network.cpp b/game/Game_network.cpp index d7e22688..7c3bb140 100644 --- a/game/Game_network.cpp +++ b/game/Game_network.cpp @@ -589,6 +589,20 @@ void idGameLocal::ServerWriteSnapshot( int clientNum, int sequence, idBitMsg &ms numSourceAreas = gameRenderWorld->BoundsInAreas( spectated->GetPlayerPhysics()->GetAbsBounds(), sourceAreas, idEntity::MAX_PVS_AREAS ); pvsHandle = gameLocal.pvs.SetupCurrentPVS( sourceAreas, numSourceAreas, PVS_NORMAL ); +#ifdef _D3XP + // Add portalSky areas to PVS + if ( portalSkyEnt.GetEntity() ) { + pvsHandle_t otherPVS, newPVS; + idEntity *skyEnt = portalSkyEnt.GetEntity(); + + otherPVS = gameLocal.pvs.SetupCurrentPVS( skyEnt->GetPVSAreas(), skyEnt->GetNumPVSAreas() ); + newPVS = gameLocal.pvs.MergeCurrentPVS( pvsHandle, otherPVS ); + pvs.FreeCurrentPVS( pvsHandle ); + pvs.FreeCurrentPVS( otherPVS ); + pvsHandle = newPVS; + } +#endif + #if ASYNC_WRITE_TAGS idRandom tagRandom; tagRandom.SetSeed( random.RandomInt() ); @@ -1120,6 +1134,20 @@ void idGameLocal::ClientReadSnapshot( int clientNum, int sequence, const int gam numSourceAreas = gameRenderWorld->BoundsInAreas( spectated->GetPlayerPhysics()->GetAbsBounds(), sourceAreas, idEntity::MAX_PVS_AREAS ); pvsHandle = gameLocal.pvs.SetupCurrentPVS( sourceAreas, numSourceAreas, PVS_NORMAL ); +#ifdef _D3XP + // Add portalSky areas to PVS + if ( portalSkyEnt.GetEntity() ) { + pvsHandle_t otherPVS, newPVS; + idEntity *skyEnt = portalSkyEnt.GetEntity(); + + otherPVS = gameLocal.pvs.SetupCurrentPVS( skyEnt->GetPVSAreas(), skyEnt->GetNumPVSAreas() ); + newPVS = gameLocal.pvs.MergeCurrentPVS( pvsHandle, otherPVS ); + pvs.FreeCurrentPVS( pvsHandle ); + pvs.FreeCurrentPVS( otherPVS ); + pvsHandle = newPVS; + } +#endif + // read the PVS from the snapshot #if ASYNC_WRITE_PVS int serverPVS[idEntity::MAX_PVS_AREAS]; @@ -1158,7 +1186,7 @@ void idGameLocal::ClientReadSnapshot( int clientNum, int sequence, const int gam // if the entity is not in the snapshot PVS if ( !( snapshot->pvs[ent->entityNumber >> 5] & ( 1 << ( ent->entityNumber & 31 ) ) ) ) { if ( ent->PhysicsTeamInPVS( pvsHandle ) ) { - if ( ent->entityNumber >= MAX_CLIENTS && ent->entityNumber < mapSpawnCount ) { + if ( ent->entityNumber >= MAX_CLIENTS && ent->entityNumber < mapSpawnCount && !ent->spawnArgs.GetBool("net_dynamic", "0")) { //_D3XP // server says it's not in PVS, client says it's in PVS // if that happens on map entities, most likely something is wrong // I can see that moving pieces along several PVS could be a legit situation though @@ -1166,6 +1194,10 @@ void idGameLocal::ClientReadSnapshot( int clientNum, int sequence, const int gam common->DWarning( "client thinks map entity 0x%x (%s) is stale, sequence 0x%x", ent->entityNumber, ent->name.c_str(), sequence ); } else { ent->FreeModelDef(); +#ifdef CTF + // possible fix for left over lights on CTF flag + ent->FreeLightDef(); +#endif ent->UpdateVisuals(); ent->GetPhysics()->UnlinkClip(); } @@ -1407,6 +1439,14 @@ void idGameLocal::ClientProcessReliableMessage( int clientNum, const idBitMsg &m break; } case GAME_RELIABLE_MESSAGE_RESTART: { +#ifdef _D3XP + int newServerInfo = msg.ReadBits(1); + if(newServerInfo) { + idDict info; + msg.ReadDeltaDict( info, NULL ); + gameLocal.SetServerInfo( info ); + } +#endif MapRestart(); break; } @@ -1502,6 +1542,11 @@ gameReturn_t idGameLocal::ClientPrediction( int clientNum, const usercmd_t *clie isNewFrame = false; } +#ifdef _D3XP + slow.Set( time, previousTime, msec, framenum, realClientTime ); + fast.Set( time, previousTime, msec, framenum, realClientTime ); +#endif + // set the user commands for this frame memcpy( usercmds, clientCmds, numClients * sizeof( usercmds[ 0 ] ) ); diff --git a/d3xp/Grabber.cpp b/game/Grabber.cpp similarity index 100% rename from d3xp/Grabber.cpp rename to game/Grabber.cpp diff --git a/d3xp/Grabber.h b/game/Grabber.h similarity index 100% rename from d3xp/Grabber.h rename to game/Grabber.h diff --git a/game/Item.cpp b/game/Item.cpp index 97ae9523..1a5de2e5 100644 --- a/game/Item.cpp +++ b/game/Item.cpp @@ -301,10 +301,18 @@ void idItem::Spawn( void ) { PostEventMS( &EV_Touch, 0, ent, 0 ); } +#ifdef CTF + // idItemTeam does not rotate and bob + if ( spawnArgs.GetBool( "spin" ) || (gameLocal.isMultiplayer && !this->IsType( idItemTeam::Type ) ) ) { + spin = true; + BecomeActive( TH_THINK ); + } +#else if ( spawnArgs.GetBool( "spin" ) || gameLocal.isMultiplayer ) { spin = true; BecomeActive( TH_THINK ); } +#endif //pulse = !spawnArgs.GetBool( "nopulse" ); //temp hack for tim @@ -640,6 +648,709 @@ bool idItemPowerup::GiveToPlayer( idPlayer *player ) { return true; } +#ifdef CTF + + +/* +=============================================================================== + + idItemTeam + + Used for flags in Capture the Flag + +=============================================================================== +*/ + +// temporarely removed these events + +const idEventDef EV_FlagReturn( "flagreturn", "e" ); +const idEventDef EV_TakeFlag( "takeflag", "e" ); +const idEventDef EV_DropFlag( "dropflag", "d" ); +const idEventDef EV_FlagCapture( "flagcapture" ); + +CLASS_DECLARATION( idItem, idItemTeam ) + EVENT( EV_FlagReturn, idItemTeam::Event_FlagReturn ) + EVENT( EV_TakeFlag, idItemTeam::Event_TakeFlag ) + EVENT( EV_DropFlag, idItemTeam::Event_DropFlag ) + EVENT( EV_FlagCapture, idItemTeam::Event_FlagCapture ) +END_CLASS + +/* +=============== +idItemTeam::idItemTeam +=============== +*/ +idItemTeam::idItemTeam() { + team = -1; + carried = false; + dropped = false; + lastDrop = 0; + + itemGlowHandle = -1; + + skinDefault = NULL; + skinCarried = NULL; + + scriptTaken = NULL; + scriptDropped = NULL; + scriptReturned = NULL; + scriptCaptured = NULL; + + lastNuggetDrop = 0; + nuggetName = 0; +} + +/* +=============== +idItemTeam::~idItemTeam +=============== +*/ +idItemTeam::~idItemTeam() { + FreeLightDef(); +} +/* +=============== +idItemTeam::Spawn +=============== +*/ +void idItemTeam::Spawn( void ) { + team = spawnArgs.GetInt( "team" ); + returnOrigin = GetPhysics()->GetOrigin() + idVec3( 0, 0, 20 ); + returnAxis = GetPhysics()->GetAxis(); + + BecomeActive( TH_THINK ); + + const char * skinName; + skinName = spawnArgs.GetString( "skin", "" ); + if ( skinName[0] ) + skinDefault = declManager->FindSkin( skinName ); + + skinName = spawnArgs.GetString( "skin_carried", "" ); + if ( skinName[0] ) + skinCarried = declManager->FindSkin( skinName ); + + nuggetName = spawnArgs.GetString( "nugget_name", "" ); + if ( !nuggetName[0] ) { + nuggetName = NULL; + } + + scriptTaken = LoadScript( "script_taken" ); + scriptDropped = LoadScript( "script_dropped" ); + scriptReturned = LoadScript( "script_returned" ); + scriptCaptured = LoadScript( "script_captured" ); + + /* Spawn attached dlight */ + /* + idDict args; + idVec3 lightOffset( 0.0f, 20.0f, 0.0f ); + + // Set up the flag's dynamic light + memset( &itemGlow, 0, sizeof( itemGlow ) ); + itemGlow.axis = mat3_identity; + itemGlow.lightRadius.x = 128.0f; + itemGlow.lightRadius.y = itemGlow.lightRadius.z = itemGlow.lightRadius.x; + itemGlow.noShadows = true; + itemGlow.pointLight = true; + itemGlow.shaderParms[ SHADERPARM_RED ] = 0.0f; + itemGlow.shaderParms[ SHADERPARM_GREEN ] = 0.0f; + itemGlow.shaderParms[ SHADERPARM_BLUE ] = 0.0f; + itemGlow.shaderParms[ SHADERPARM_ALPHA ] = 0.0f; + + // Select a shader based on the team + if ( team == 0 ) + itemGlow.shader = declManager->FindMaterial( "lights/redflag" ); + else + itemGlow.shader = declManager->FindMaterial( "lights/blueflag" ); + */ + + idMoveableItem::Spawn(); + + physicsObj.SetContents( 0 ); + physicsObj.SetClipMask( MASK_SOLID | CONTENTS_MOVEABLECLIP ); + physicsObj.SetGravity( idVec3( 0, 0, spawnArgs.GetInt("gravity", "-30" ) ) ); +} + + +/* +=============== +idItemTeam::LoadScript +=============== +*/ +function_t * idItemTeam::LoadScript( const char * script ) { + function_t * function = NULL; + idStr funcname = spawnArgs.GetString( script, "" ); + if ( funcname.Length() ) { + function = gameLocal.program.FindFunction( funcname ); + if ( function == NULL ) { +#ifdef _DEBUG + gameLocal.Warning( "idItemTeam '%s' at (%s) calls unknown function '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), funcname.c_str() ); +#endif + } + } + return function; +} + + +/* +=============== +idItemTeam::Think +=============== +*/ +void idItemTeam::Think( void ) { + idMoveableItem::Think(); + + TouchTriggers(); + + // TODO : only update on updatevisuals + /*idVec3 offset( 0.0f, 0.0f, 20.0f ); + itemGlow.origin = GetPhysics()->GetOrigin() + offset; + if ( itemGlowHandle == -1 ) { + itemGlowHandle = gameRenderWorld->AddLightDef( &itemGlow ); + } else { + gameRenderWorld->UpdateLightDef( itemGlowHandle, &itemGlow ); + }*/ + +#if 1 + // should only the server do this? + if ( gameLocal.isServer && nuggetName && carried && ( !lastNuggetDrop || (gameLocal.time - lastNuggetDrop) > spawnArgs.GetInt("nugget_frequency") ) ) { + + SpawnNugget( GetPhysics()->GetOrigin() ); + lastNuggetDrop = gameLocal.time; + } +#endif + + // return dropped flag after si_flagDropTimeLimit seconds + if ( dropped && !carried && lastDrop != 0 && (gameLocal.time - lastDrop) > ( si_flagDropTimeLimit.GetInteger()*1000 ) ) { + + Return(); // return flag after 30 seconds on ground + return; + } +} + +/* +=============== +idItemTeam::Pickup +=============== +*/ +bool idItemTeam::Pickup( idPlayer *player ) { + if ( !gameLocal.mpGame.IsGametypeFlagBased() ) /* CTF */ + return false; + + if ( gameLocal.mpGame.GetGameState() == idMultiplayerGame::WARMUP || + gameLocal.mpGame.GetGameState() == idMultiplayerGame::COUNTDOWN ) + return false; + + // wait 2 seconds after drop before beeing picked up again + if ( lastDrop != 0 && (gameLocal.time - lastDrop) < spawnArgs.GetInt("pickupDelay", "500") ) + return false; + + if ( carried == false && player->team != this->team ) { + + PostEventMS( &EV_TakeFlag, 0, player ); + + return true; + } else if ( carried == false && dropped == true && player->team == this->team ) { + + gameLocal.mpGame.PlayerScoreCTF( player->entityNumber, 5 ); + + // return flag + PostEventMS( &EV_FlagReturn, 0, player ); + + return false; + } + + return false; +} + +/* +=============== +idItemTeam::ClientReceiveEvent +=============== +*/ +bool idItemTeam::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) { + gameLocal.DPrintf("ClientRecieveEvent: %i\n", event ); + + switch ( event ) { + case EVENT_TAKEFLAG: { + idPlayer * player = static_cast(gameLocal.entities[ msg.ReadBits( GENTITYNUM_BITS ) ]); + if ( player == NULL ) { + gameLocal.Warning( "NULL player takes flag?\n" ); + return false; + } + + Event_TakeFlag( player ); + } + return true; + + case EVENT_DROPFLAG : { + bool death = bool( msg.ReadBits( 1 ) == 1 ); + Event_DropFlag( death ); + } + return true; + + case EVENT_FLAGRETURN : { + Hide(); + + FreeModelDef(); + FreeLightDef(); + + Event_FlagReturn(); + } + return true; + + case EVENT_FLAGCAPTURE : { + Hide(); + + FreeModelDef(); + FreeLightDef(); + + Event_FlagCapture(); + } + return true; + }; + + return false; +} + +/* +================ +idItemTeam::Drop +================ +*/ +void idItemTeam::Drop( bool death ) +{ +// PostEventMS( &EV_DropFlag, 0, int(death == true) ); +// had to remove the delayed drop because of drop flag on disconnect + Event_DropFlag( death ); +} + +/* +================ +idItemTeam::Return +================ +*/ +void idItemTeam::Return( idPlayer * player ) +{ + if ( team != 0 && team != 1 ) + return; + +// PostEventMS( &EV_FlagReturn, 0 ); + Event_FlagReturn(); +} + +/* +================ +idItemTeam::Capture +================ +*/ +void idItemTeam::Capture( void ) +{ + if ( team != 0 && team != 1 ) + return; + + PostEventMS( &EV_FlagCapture, 0 ); +} + +/* +================ +idItemTeam::PrivateReturn +================ +*/ +void idItemTeam::PrivateReturn( void ) +{ + Unbind(); + + if ( gameLocal.isServer && carried && !dropped ) { + int playerIdx = gameLocal.mpGame.GetFlagCarrier( 1-team ); + if ( playerIdx != -1 ) { + idPlayer * player = static_cast( gameLocal.entities[ playerIdx ] ); + player->carryingFlag = false; + } else { + gameLocal.Warning( "BUG: carried flag has no carrier before return" ); + } + } + + dropped = false; + carried = false; + + SetOrigin( returnOrigin ); + SetAxis( returnAxis ); + + trigger->Link( gameLocal.clip, this, 0, GetPhysics()->GetOrigin(), mat3_identity ); + + SetSkin( skinDefault ); + + // Turn off the light + /*itemGlow.shaderParms[ SHADERPARM_RED ] = 0.0f; + itemGlow.shaderParms[ SHADERPARM_GREEN ] = 0.0f; + itemGlow.shaderParms[ SHADERPARM_BLUE ] = 0.0f; + itemGlow.shaderParms[ SHADERPARM_ALPHA ] = 0.0f; + + if ( itemGlowHandle != -1 ) + gameRenderWorld->UpdateLightDef( itemGlowHandle, &itemGlow );*/ + + GetPhysics()->SetLinearVelocity( idVec3(0, 0, 0) ); + GetPhysics()->SetAngularVelocity( idVec3(0, 0, 0) ); +} + +/* +================ +idItemTeam::Event_TakeFlag +================ +*/ +void idItemTeam::Event_TakeFlag( idPlayer * player ) { + gameLocal.DPrintf("Event_TakeFlag()!\n"); + + if ( gameLocal.isServer ) { + idBitMsg msg; + byte msgBuf[MAX_EVENT_PARAM_SIZE]; + // Send the event + msg.Init( msgBuf, sizeof( msgBuf ) ); + msg.BeginWriting(); + msg.WriteBits( player->entityNumber, GENTITYNUM_BITS ); + ServerSendEvent( EVENT_TAKEFLAG, &msg, false, -1 ); + + gameLocal.mpGame.PlayTeamSound( player->team, SND_FLAG_TAKEN_THEIRS ); + gameLocal.mpGame.PlayTeamSound( team, SND_FLAG_TAKEN_YOURS ); + + gameLocal.mpGame.PrintMessageEvent( -1, idMultiplayerGame::MSG_FLAGTAKEN, team, player->entityNumber ); + + // dont drop a nugget RIGHT away + lastNuggetDrop = gameLocal.time - gameLocal.random.RandomInt( 1000 ); + + } + + BindToJoint( player, g_flagAttachJoint.GetString(), true ); + idVec3 origin( g_flagAttachOffsetX.GetFloat(), g_flagAttachOffsetY.GetFloat(), g_flagAttachOffsetZ.GetFloat() ); + idAngles angle( g_flagAttachAngleX.GetFloat(), g_flagAttachAngleY.GetFloat(), g_flagAttachAngleZ.GetFloat() ); + SetAngles( angle ); + SetOrigin( origin ); + + // Turn the light on + /*itemGlow.shaderParms[ SHADERPARM_RED ] = 1.0f; + itemGlow.shaderParms[ SHADERPARM_GREEN ] = 1.0f; + itemGlow.shaderParms[ SHADERPARM_BLUE ] = 1.0f; + itemGlow.shaderParms[ SHADERPARM_ALPHA ] = 1.0f; + + if ( itemGlowHandle != -1 ) + gameRenderWorld->UpdateLightDef( itemGlowHandle, &itemGlow );*/ + + if ( scriptTaken ) { + idThread *thread = new idThread(); + thread->CallFunction( scriptTaken, false ); + thread->DelayedStart( 0 ); + } + + dropped = false; + carried = true; + player->carryingFlag = true; + + SetSkin( skinCarried ); + + UpdateVisuals(); + UpdateGuis(); + + if ( gameLocal.isServer ) { + if ( team == 0 ) + gameLocal.mpGame.player_red_flag = player->entityNumber; + else + gameLocal.mpGame.player_blue_flag = player->entityNumber; + } +} + +/* +================ +idItemTeam::Event_DropFlag +================ +*/ +void idItemTeam::Event_DropFlag( bool death ) { + gameLocal.DPrintf("Event_DropFlag()!\n"); + + if ( gameLocal.isServer ) { + idBitMsg msg; + byte msgBuf[MAX_EVENT_PARAM_SIZE]; + // Send the event + msg.Init( msgBuf, sizeof( msgBuf ) ); + msg.BeginWriting(); + msg.WriteBits( death, 1 ); + ServerSendEvent( EVENT_DROPFLAG, &msg, false, -1 ); + + if ( gameLocal.mpGame.IsFlagMsgOn() ) { + gameLocal.mpGame.PlayTeamSound( 1-team, SND_FLAG_DROPPED_THEIRS ); + gameLocal.mpGame.PlayTeamSound( team, SND_FLAG_DROPPED_YOURS ); + + gameLocal.mpGame.PrintMessageEvent( -1, idMultiplayerGame::MSG_FLAGDROP, team ); + } + } + + lastDrop = gameLocal.time; + + BecomeActive( TH_THINK ); + Show(); + + if ( death ) + GetPhysics()->SetLinearVelocity( idVec3(0, 0, 0) ); + else + GetPhysics()->SetLinearVelocity( idVec3(0, 0, 20) ); + + GetPhysics()->SetAngularVelocity( idVec3(0, 0, 0) ); + +// GetPhysics()->SetLinearVelocity( ( GetPhysics()->GetLinearVelocity() * GetBindMaster()->GetPhysics()->GetAxis() ) + GetBindMaster()->GetPhysics()->GetLinearVelocity() ); + + if ( GetBindMaster() ) { + const idBounds bounds = GetPhysics()->GetBounds(); + idVec3 origin = GetBindMaster()->GetPhysics()->GetOrigin() + idVec3(0, 0, ( bounds[1].z-bounds[0].z )*0.6f ); + + Unbind(); + + SetOrigin( origin ); + } + + idAngles angle = GetPhysics()->GetAxis().ToAngles(); + angle.roll = 0; + angle.pitch = 0; + SetAxis( angle.ToMat3() ); + + dropped = true; + carried = false; + + if ( scriptDropped ) { + idThread *thread = new idThread(); + thread->CallFunction( scriptDropped, false ); + thread->DelayedStart( 0 ); + } + + SetSkin( skinDefault ); + UpdateVisuals(); + UpdateGuis(); + + + if ( gameLocal.isServer ) { + if ( team == 0 ) + gameLocal.mpGame.player_red_flag = -1; + else + gameLocal.mpGame.player_blue_flag = -1; + + } +} + +/* +================ +idItemTeam::Event_FlagReturn +================ +*/ +void idItemTeam::Event_FlagReturn( idPlayer * player ) { + gameLocal.DPrintf("Event_FlagReturn()!\n"); + + if ( gameLocal.isServer ) { + ServerSendEvent( EVENT_FLAGRETURN, NULL, false, -1 ); + + if ( gameLocal.mpGame.IsFlagMsgOn() ) { + gameLocal.mpGame.PlayTeamSound( 1-team, SND_FLAG_RETURN ); + gameLocal.mpGame.PlayTeamSound( team, SND_FLAG_RETURN ); + + int entitynum = 255; + if ( player ) { + entitynum = player->entityNumber; + } + + gameLocal.mpGame.PrintMessageEvent( -1, idMultiplayerGame::MSG_FLAGRETURN, team, entitynum ); + } + } + + BecomeActive( TH_THINK ); + Show(); + + PrivateReturn(); + + if ( scriptReturned ) { + idThread *thread = new idThread(); + thread->CallFunction( scriptReturned, false ); + thread->DelayedStart( 0 ); + } + + UpdateVisuals(); + UpdateGuis(); +// Present(); + + if ( gameLocal.isServer ) { + if ( team == 0 ) + gameLocal.mpGame.player_red_flag = -1; + else + gameLocal.mpGame.player_blue_flag = -1; + } +} + +/* +================ +idItemTeam::Event_FlagCapture +================ +*/ +void idItemTeam::Event_FlagCapture( void ) { + gameLocal.DPrintf("Event_FlagCapture()!\n"); + + if ( gameLocal.isServer ) { + ServerSendEvent( EVENT_FLAGCAPTURE, NULL, false, -1 ); + + gameLocal.mpGame.PlayTeamSound( 1-team, SND_FLAG_CAPTURED_THEIRS ); + gameLocal.mpGame.PlayTeamSound( team, SND_FLAG_CAPTURED_YOURS ); + + gameLocal.mpGame.TeamScoreCTF( 1-team, 1 ); + + int playerIdx = gameLocal.mpGame.GetFlagCarrier( 1-team ); + if ( playerIdx != -1 ) { + gameLocal.mpGame.PlayerScoreCTF( playerIdx, 10 ); + } else { + playerIdx = 255; + } + + gameLocal.mpGame.PrintMessageEvent( -1, idMultiplayerGame::MSG_FLAGCAPTURE, team, playerIdx ); + } + + BecomeActive( TH_THINK ); + Show(); + + PrivateReturn(); + + if ( scriptCaptured ) { + idThread *thread = new idThread(); + thread->CallFunction( scriptCaptured, false ); + thread->DelayedStart( 0 ); + } + + UpdateVisuals(); + UpdateGuis(); + + + if ( gameLocal.isServer ) { + if ( team == 0 ) + gameLocal.mpGame.player_red_flag = -1; + else + gameLocal.mpGame.player_blue_flag = -1; + } + +} + +/* +================ +idItemTeam::FreeLightDef +================ +*/ +void idItemTeam::FreeLightDef( void ) { + if ( itemGlowHandle != -1 ) { + gameRenderWorld->FreeLightDef( itemGlowHandle ); + itemGlowHandle = -1; + } +} + +/* +================ +idItemTeam::SpawnNugget +================ +*/ +void idItemTeam::SpawnNugget( idVec3 pos ) { + + idAngles angle( gameLocal.random.RandomInt(spawnArgs.GetInt("nugget_pitch", "30")), gameLocal.random.RandomInt(spawnArgs.GetInt("nugget_yaw", "360" )), 0 ); + float velocity = float(gameLocal.random.RandomInt( 40 )+15); + + velocity *= spawnArgs.GetFloat("nugget_velocity", "1" ); + + idEntity * ent = idMoveableItem::DropItem( nuggetName, pos, GetPhysics()->GetAxis(), angle.ToMat3()*idVec3(velocity, velocity, velocity), 0, spawnArgs.GetInt("nugget_removedelay") ); + idPhysics_RigidBody * physics = static_cast( ent->GetPhysics() ); + + if ( physics && physics->IsType( idPhysics_RigidBody::Type ) ) { + physics->DisableImpact(); + } +} + + + +/* +================ +idItemTeam::Event_FlagCapture +================ +*/ +void idItemTeam::WriteToSnapshot( idBitMsgDelta &msg ) const { + msg.WriteBits( carried, 1 ); + msg.WriteBits( dropped, 1 ); + + WriteBindToSnapshot( msg ); + + idMoveableItem::WriteToSnapshot( msg ); +} + + +/* +================ +idItemTeam::ReadFromSnapshot +================ +*/ +void idItemTeam::ReadFromSnapshot( const idBitMsgDelta &msg ) { + carried = msg.ReadBits( 1 ) == 1; + dropped = msg.ReadBits( 1 ) == 1; + + ReadBindFromSnapshot( msg ); + + if ( msg.HasChanged() ) + { + UpdateGuis(); + + if ( carried == true ) + SetSkin( skinCarried ); + else + SetSkin( skinDefault ); + } + + idMoveableItem::ReadFromSnapshot( msg ); +} + +/* +================ +idItemTeam::UpdateGuis + +Update all client's huds wrt the flag status. +================ +*/ +void idItemTeam::UpdateGuis( void ) { + idPlayer *player; + + for ( int i = 0; i < gameLocal.numClients; i++ ) { + player = static_cast( gameLocal.entities[ i ] ); + + if ( player == NULL || player->hud == NULL ) + continue; + + player->hud->SetStateInt( "red_flagstatus", gameLocal.mpGame.GetFlagStatus( 0 ) ); + player->hud->SetStateInt( "blue_flagstatus", gameLocal.mpGame.GetFlagStatus( 1 ) ); + + player->hud->SetStateInt( "red_team_score", gameLocal.mpGame.GetFlagPoints( 0 ) ); + player->hud->SetStateInt( "blue_team_score", gameLocal.mpGame.GetFlagPoints( 1 ) ); + + } + +} + +/* +================ +idItemTeam::Present +================ +*/ +void idItemTeam::Present( void ) { + // hide the flag for localplayer if in first person + if ( carried && GetBindMaster() ) { + idPlayer * player = static_cast( GetBindMaster() ); + if ( player == gameLocal.GetLocalPlayer() && !pm_thirdPerson.GetBool() ) { + FreeModelDef(); + BecomeActive( TH_UPDATEVISUALS ); + return; + } + } + + idEntity::Present(); +} + +#endif + /* =============================================================================== @@ -680,7 +1391,9 @@ idObjective::Restore */ void idObjective::Restore( idRestoreGame *savefile ) { savefile->ReadVec3( playerPos ); +#ifndef _D3XP PostEventMS( &EV_CamShot, 250 ); +#endif // _D3XP } /* @@ -690,7 +1403,13 @@ idObjective::Spawn */ void idObjective::Spawn( void ) { Hide(); - PostEventMS( &EV_CamShot, 250 ); +#ifdef _D3XP + if ( cvarSystem->GetCVarBool( "com_makingBuild") ) { +#endif // _D3XP + PostEventMS( &EV_CamShot, 250 ); +#ifdef _D3XP + } +#endif // _D3XP } /* @@ -712,6 +1431,44 @@ void idObjective::Event_CamShot( ) { renderView_t fullView = *view; fullView.width = SCREEN_WIDTH; fullView.height = SCREEN_HEIGHT; + +#ifdef _D3XP + // HACK : always draw sky-portal view if there is one in the map, this isn't real-time + if ( gameLocal.portalSkyEnt.GetEntity() && g_enablePortalSky.GetBool() ) { + renderView_t portalView = fullView; + portalView.vieworg = gameLocal.portalSkyEnt.GetEntity()->GetPhysics()->GetOrigin(); + + // setup global fixup projection vars + if ( 1 ) { + int vidWidth, vidHeight; + idVec2 shiftScale; + + renderSystem->GetGLSettings( vidWidth, vidHeight ); + + float pot; + int temp; + + int w = vidWidth; + for (temp = 1 ; temp < w ; temp<<=1) { + } + pot = (float)temp; + shiftScale.x = (float)w / pot; + + int h = vidHeight; + for (temp = 1 ; temp < h ; temp<<=1) { + } + pot = (float)temp; + shiftScale.y = (float)h / pot; + + fullView.shaderParms[4] = shiftScale.x; + fullView.shaderParms[5] = shiftScale.y; + } + + gameRenderWorld->RenderScene( &portalView ); + renderSystem->CaptureRenderToImage( "_currentRender" ); + } +#endif + // draw a view to a texture renderSystem->CropRenderSize( 256, 256, true ); gameRenderWorld->RenderScene( &fullView ); @@ -870,6 +1627,12 @@ idMoveableItem::idMoveableItem() { trigger = NULL; smoke = NULL; smokeTime = 0; +#ifdef _D3XP + nextSoundTime = 0; +#endif +#ifdef CTF + repeatSmoke = false; +#endif } /* @@ -895,6 +1658,9 @@ void idMoveableItem::Save( idSaveGame *savefile ) const { savefile->WriteParticle( smoke ); savefile->WriteInt( smokeTime ); +#ifdef _D3XP + savefile->WriteInt( nextSoundTime ); +#endif } /* @@ -910,6 +1676,9 @@ void idMoveableItem::Restore( idRestoreGame *savefile ) { savefile->ReadParticle( smoke ); savefile->ReadInt( smokeTime ); +#ifdef _D3XP + savefile->ReadInt( nextSoundTime ); +#endif } /* @@ -922,6 +1691,9 @@ void idMoveableItem::Spawn( void ) { float density, friction, bouncyness, tsize; idStr clipModelName; idBounds bounds; +#ifdef _D3XP + SetTimeState ts( timeGroup ); +#endif // create a trigger for item pickup spawnArgs.GetFloat( "triggersize", "16.0", tsize ); @@ -968,12 +1740,19 @@ void idMoveableItem::Spawn( void ) { smoke = NULL; smokeTime = 0; +#ifdef _D3XP + nextSoundTime = 0; +#endif const char *smokeName = spawnArgs.GetString( "smoke_trail" ); if ( *smokeName != '\0' ) { smoke = static_cast( declManager->FindType( DECL_PARTICLE, smokeName ) ); smokeTime = gameLocal.time; BecomeActive( TH_UPDATEPARTICLES ); } + +#ifdef CTF + repeatSmoke = spawnArgs.GetBool( "repeatSmoke", "0" ); +#endif } /* @@ -991,15 +1770,52 @@ void idMoveableItem::Think( void ) { } if ( thinkFlags & TH_UPDATEPARTICLES ) { +#ifdef _D3XP + if ( !gameLocal.smokeParticles->EmitSmoke( smoke, smokeTime, gameLocal.random.CRandomFloat(), GetPhysics()->GetOrigin(), GetPhysics()->GetAxis(), timeGroup /*_D3XP*/ ) ) { +#else if ( !gameLocal.smokeParticles->EmitSmoke( smoke, smokeTime, gameLocal.random.CRandomFloat(), GetPhysics()->GetOrigin(), GetPhysics()->GetAxis() ) ) { +#endif // _D3XP +#ifdef CTF + if ( !repeatSmoke ) { + smokeTime = 0; + BecomeInactive( TH_UPDATEPARTICLES ); + } else { + smokeTime = gameLocal.time; + } +#else smokeTime = 0; BecomeInactive( TH_UPDATEPARTICLES ); +#endif } } Present(); } +#ifdef _D3XP +/* +================= +idMoveableItem::Collide +================= +*/ +bool idMoveableItem::Collide( const trace_t &collision, const idVec3 &velocity ) { + float v, f; + + v = -( velocity * collision.c.normal ); + if ( v > 80 && gameLocal.time > nextSoundTime ) { + f = v > 200 ? 1.0f : idMath::Sqrt( v - 80 ) * 0.091f; + if ( StartSound( "snd_bounce", SND_CHANNEL_ANY, 0, false, NULL ) ) { + // don't set the volume unless there is a bounce sound as it overrides the entire channel + // which causes footsteps on ai's to not honor their shader parms + SetSoundVolume( f ); + } + nextSoundTime = gameLocal.time + 500; + } + + return false; +} +#endif + /* ================ idMoveableItem::Pickup @@ -1158,7 +1974,11 @@ void idMoveableItem::Gib( const idVec3 &dir, const char *damageDefName ) { const char *smokeName = spawnArgs.GetString( "smoke_gib" ); if ( *smokeName != '\0' ) { const idDeclParticle *smoke = static_cast( declManager->FindType( DECL_PARTICLE, smokeName ) ); +#ifdef _D3XP + gameLocal.smokeParticles->EmitSmoke( smoke, gameLocal.time, gameLocal.random.CRandomFloat(), renderEntity.origin, renderEntity.axis, timeGroup /*_D3XP*/ ); +#else gameLocal.smokeParticles->EmitSmoke( smoke, gameLocal.time, gameLocal.random.CRandomFloat(), renderEntity.origin, renderEntity.axis ); +#endif // _D3XP } // remove the entity PostEventMS( &EV_Remove, 0 ); @@ -1315,9 +2135,14 @@ void idObjectiveComplete::Event_Trigger( idEntity *activator ) { if ( spawnArgs.GetString( "inv_objective", NULL ) ) { if ( player->hud ) { - player->hud->SetStateString( "objective", "2" ); + player->hud->SetStateString( "objective", "2"); + player->hud->SetStateString( "objectivetext", spawnArgs.GetString( "objectivetext" ) ); +#ifdef _D3XP + player->hud->SetStateString( "objectivecompletetitle", spawnArgs.GetString( "objectivetitle" ) ); +#else player->hud->SetStateString( "objectivetitle", spawnArgs.GetString( "objectivetitle" ) ); +#endif player->CompleteObjective( spawnArgs.GetString( "objectivetitle" ) ); PostEventMS( &EV_GetPlayerPos, 2000 ); } diff --git a/game/Item.h b/game/Item.h index acf7c0c9..d02b7b26 100644 --- a/game/Item.h +++ b/game/Item.h @@ -61,6 +61,12 @@ class idItem : public idEntity { EVENT_PICKUP = idEntity::EVENT_MAXEVENTS, EVENT_RESPAWN, EVENT_RESPAWNFX, +#ifdef CTF + EVENT_TAKEFLAG, + EVENT_DROPFLAG, + EVENT_FLAGRETURN, + EVENT_FLAGCAPTURE, +#endif EVENT_MAXEVENTS }; @@ -161,6 +167,9 @@ class idMoveableItem : public idItem { void Spawn( void ); virtual void Think( void ); +#ifdef _D3XP + virtual bool Collide( const trace_t &collision, const idVec3 &velocity ); +#endif virtual bool Pickup( idPlayer *player ); static void DropItems( idAnimatedEntity *ent, const char *type, idList *list ); @@ -169,18 +178,96 @@ class idMoveableItem : public idItem { virtual void WriteToSnapshot( idBitMsgDelta &msg ) const; virtual void ReadFromSnapshot( const idBitMsgDelta &msg ); +#ifdef CTF +protected: +#else private: +#endif idPhysics_RigidBody physicsObj; idClipModel * trigger; const idDeclParticle * smoke; int smokeTime; +#ifdef _D3XP + int nextSoundTime; +#endif +#ifdef CTF + bool repeatSmoke; // never stop updating the particles +#endif + void Gib( const idVec3 &dir, const char *damageDefName ); void Event_DropToFloor( void ); void Event_Gib( const char *damageDefName ); }; +#ifdef CTF + +class idItemTeam : public idMoveableItem { +public: + CLASS_PROTOTYPE( idItemTeam ); + + idItemTeam(); + virtual ~idItemTeam(); + + void Spawn(); + virtual bool Pickup( idPlayer *player ); + virtual bool ClientReceiveEvent( int event, int time, const idBitMsg &msg ); + virtual void Think(void ); + + void Drop( bool death = false ); // was the drop caused by death of carrier? + void Return( idPlayer * player = NULL ); + void Capture( void ); + + virtual void FreeLightDef( void ); + virtual void Present( void ); + + // networking + virtual void WriteToSnapshot( idBitMsgDelta &msg ) const; + virtual void ReadFromSnapshot( const idBitMsgDelta &msg ); + +public: + int team; + // TODO : turn this into a state : + bool carried; // is it beeing carried by a player? + bool dropped; // was it dropped? + +private: + idVec3 returnOrigin; + idMat3 returnAxis; + int lastDrop; + + const idDeclSkin * skinDefault; + const idDeclSkin * skinCarried; + + const function_t * scriptTaken; + const function_t * scriptDropped; + const function_t * scriptReturned; + const function_t * scriptCaptured; + + renderLight_t itemGlow; // Used by flags when they are picked up + int itemGlowHandle; + + int lastNuggetDrop; + const char * nuggetName; + +private: + + void Event_TakeFlag( idPlayer * player ); + void Event_DropFlag( bool death ); + void Event_FlagReturn( idPlayer * player = NULL ); + void Event_FlagCapture( void ); + + void PrivateReturn( void ); + function_t * LoadScript( const char * script ); + + void SpawnNugget( idVec3 pos ); + void UpdateGuis( void ); +}; + +#endif + + class idMoveablePDAItem : public idMoveableItem { public: CLASS_PROTOTYPE( idMoveablePDAItem ); diff --git a/game/Light.cpp b/game/Light.cpp index cc24a42d..8db6eb3d 100644 --- a/game/Light.cpp +++ b/game/Light.cpp @@ -359,6 +359,13 @@ void idLight::Spawn( void ) { Off(); } +#ifdef CTF + // Midnight CTF + if ( gameLocal.mpGame.IsGametypeFlagBased() && gameLocal.serverInfo.GetBool("si_midnight") && !spawnArgs.GetBool("midnight_override") ) { + Off(); + } +#endif + health = spawnArgs.GetInt( "health", "0" ); spawnArgs.GetString( "broken", "", brokenModel ); spawnArgs.GetBool( "break", "0", breakOnTrigger ); diff --git a/game/Misc.cpp b/game/Misc.cpp index bfde7193..5172e9f8 100644 --- a/game/Misc.cpp +++ b/game/Misc.cpp @@ -197,6 +197,10 @@ void idPlayerStart::TeleportPlayer( idPlayer *player ) { const char *viewName = spawnArgs.GetString( "visualView", "" ); idEntity *ent = viewName ? gameLocal.FindEntity( viewName ) : NULL; +#ifdef _D3XP + SetTimeState ts( player->timeGroup ); +#endif + if ( f && ent ) { // place in private camera view for some time // the entity needs to teleport to where the camera view is to have the PVS right @@ -564,6 +568,28 @@ void idDamagable::Killed( idEntity *inflictor, idEntity *attacker, int damage, c BecomeBroken( attacker ); } +#ifdef _D3XP +/* +================ +idDamagable::Hide +================ +*/ +void idDamagable::Hide( void ) { + idEntity::Hide(); + GetPhysics()->SetContents( 0 ); +} + +/* +================ +idDamagable::Show +================ +*/ +void idDamagable::Show( void ) { + idEntity::Show(); + GetPhysics()->SetContents( CONTENTS_SOLID ); +} +#endif + /* ================ idDamagable::Event_BecomeBroken @@ -892,6 +918,10 @@ const idEventDef EV_LaunchMissiles( "launchMissiles", "ssssdf" ); const idEventDef EV_LaunchMissilesUpdate( "", "dddd" ); const idEventDef EV_AnimDone( "", "d" ); const idEventDef EV_StartRagdoll( "startRagdoll" ); +#ifdef _D3XP +const idEventDef EV_SetAnimation( "setAnimation", "s" ); +const idEventDef EV_GetAnimationLength( "getAnimationLength", NULL, 'f' ); +#endif CLASS_DECLARATION( idAFEntity_Gibbable, idAnimated ) EVENT( EV_Activate, idAnimated::Event_Activate ) @@ -903,6 +933,10 @@ CLASS_DECLARATION( idAFEntity_Gibbable, idAnimated ) EVENT( EV_FootstepRight, idAnimated::Event_Footstep ) EVENT( EV_LaunchMissiles, idAnimated::Event_LaunchMissiles ) EVENT( EV_LaunchMissilesUpdate, idAnimated::Event_LaunchMissilesUpdate ) +#ifdef _D3XP + EVENT( EV_SetAnimation, idAnimated::Event_SetAnimation ) + EVENT( EV_GetAnimationLength, idAnimated::Event_GetAnimationLength ) +#endif END_CLASS /* @@ -1332,6 +1366,38 @@ void idAnimated::Event_LaunchMissiles( const char *projectilename, const char *s ProcessEvent( &EV_LaunchMissilesUpdate, launch, target, numshots - 1, framedelay ); } +#ifdef _D3XP +/* +===================== +idAnimated::Event_SetAnimation +===================== +*/ +void idAnimated::Event_SetAnimation( const char *animName ) { + + //BSM Nerve: Need to add some error checking so we don't change the animation + //in the middle of the existing animation + anim = animator.GetAnim( animName ); + if ( !anim ) { + gameLocal.Error( "idAnimated '%s' at (%s): cannot find anim '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), animName ); + } + +} + +/* +===================== +idAnimated::Event_GetAnimationLength +===================== +*/ +void idAnimated::Event_GetAnimationLength() { + float length = 0; + + if(anim) { + length = (float)(animator.AnimLength( anim )) / 1000.f; + } + + idThread::ReturnFloat(length); +} +#endif /* =============================================================================== @@ -1841,7 +1907,11 @@ void idFuncSmoke::Think( void ) { } if ( ( thinkFlags & TH_UPDATEPARTICLES) && !IsHidden() ) { +#ifdef _D3XP + if ( !gameLocal.smokeParticles->EmitSmoke( smoke, smokeTime, gameLocal.random.CRandomFloat(), GetPhysics()->GetOrigin(), GetPhysics()->GetAxis(), timeGroup /*_D3XP*/ ) ) { +#else if ( !gameLocal.smokeParticles->EmitSmoke( smoke, smokeTime, gameLocal.random.CRandomFloat(), GetPhysics()->GetOrigin(), GetPhysics()->GetAxis() ) ) { +#endif // _D3XP if ( restart ) { smokeTime = gameLocal.time; } else { @@ -2941,11 +3011,11 @@ void idPhantomObjects::Save( idSaveGame *savefile ) const { savefile->WriteInt( min_wait ); savefile->WriteInt( max_wait ); target.Save( savefile ); + savefile->WriteInt( targetTime.Num() ); for( i = 0; i < targetTime.Num(); i++ ) { savefile->WriteInt( targetTime[ i ] ); } - for( i = 0; i < lastTargetPos.Num(); i++ ) { savefile->WriteVec3( lastTargetPos[ i ] ); } @@ -2978,16 +3048,8 @@ void idPhantomObjects::Restore( idRestoreGame *savefile ) { for( i = 0; i < num; i++ ) { savefile->ReadInt( targetTime[ i ] ); } - - if ( savefile->GetBuildNumber() == INITIAL_RELEASE_BUILD_NUMBER ) { - // these weren't saved out in the first release - for( i = 0; i < num; i++ ) { - lastTargetPos[ i ].Zero(); - } - } else { - for( i = 0; i < num; i++ ) { - savefile->ReadVec3( lastTargetPos[ i ] ); - } + for( i = 0; i < num; i++ ) { + savefile->ReadVec3( lastTargetPos[ i ] ); } } @@ -3156,3 +3218,549 @@ void idPhantomObjects::Think( void ) { BecomeInactive( TH_THINK ); } } + +#ifdef _D3XP +/* +=============================================================================== + +idShockwave + +=============================================================================== +*/ +CLASS_DECLARATION( idEntity, idShockwave ) +EVENT( EV_Activate, idShockwave::Event_Activate ) +END_CLASS + +/* +=============== +idShockwave::idShockwave +=============== +*/ +idShockwave::idShockwave() { + isActive = false; + startTime = 0; + duration = 0; + startSize = 0.f; + endSize = 0.f; + currentSize = 0.f; + magnitude = 0.f; + + height = 0.0f; + playerDamaged = false; + playerDamageSize = 0.0f; +} + +/* +=============== +idShockwave::~idShockwave +=============== +*/ +idShockwave::~idShockwave() { +} + +/* +=============== +idShockwave::Save +=============== +*/ +void idShockwave::Save( idSaveGame *savefile ) const { + savefile->WriteBool( isActive ); + savefile->WriteInt( startTime ); + savefile->WriteInt( duration ); + + savefile->WriteFloat( startSize ); + savefile->WriteFloat( endSize ); + savefile->WriteFloat( currentSize ); + + savefile->WriteFloat( magnitude ); + + savefile->WriteFloat( height ); + savefile->WriteBool( playerDamaged ); + savefile->WriteFloat( playerDamageSize ); +} + +/* +=============== +idShockwave::Restore +=============== +*/ +void idShockwave::Restore( idRestoreGame *savefile ) { + savefile->ReadBool( isActive ); + savefile->ReadInt( startTime ); + savefile->ReadInt( duration ); + + savefile->ReadFloat( startSize ); + savefile->ReadFloat( endSize ); + savefile->ReadFloat( currentSize ); + + savefile->ReadFloat( magnitude ); + + savefile->ReadFloat( height ); + savefile->ReadBool( playerDamaged ); + savefile->ReadFloat( playerDamageSize ); + +} + +/* +=============== +idShockwave::Spawn +=============== +*/ +void idShockwave::Spawn() { + + spawnArgs.GetInt( "duration", "1000", duration ); + spawnArgs.GetFloat( "startsize", "8", startSize ); + spawnArgs.GetFloat( "endsize", "512", endSize ); + spawnArgs.GetFloat( "magnitude", "100", magnitude ); + + spawnArgs.GetFloat( "height", "0", height); + spawnArgs.GetFloat( "player_damage_size", "20", playerDamageSize); + + if ( spawnArgs.GetBool( "start_on" ) ) { + ProcessEvent( &EV_Activate, this ); + } +} + +/* +=============== +idShockwave::Think +=============== +*/ +void idShockwave::Think() { + int endTime; + + if ( !isActive ) { + BecomeInactive( TH_THINK ); + return; + } + + endTime = startTime + duration; + + if ( gameLocal.time < endTime ) { + float u; + float newSize; + + // Expand shockwave + u = (float)(gameLocal.time - startTime) / (float)duration; + newSize = startSize + u * (endSize - startSize); + + // Find all clipmodels between currentSize and newSize + idVec3 pos, end; + idClipModel *clipModelList[ MAX_GENTITIES ]; + idClipModel *clip; + idEntity *ent; + int i, listedClipModels; + + // Set bounds + pos = GetPhysics()->GetOrigin(); + + float zVal; + if(!height) { + zVal = newSize; + } else { + zVal = height/2.0f; + } + + //Expand in a sphere + end = pos + idVec3( newSize, newSize, zVal ); + idBounds bounds( end ); + end = pos + idVec3( -newSize, -newSize, -zVal ); + bounds.AddPoint( end ); + + if(g_debugShockwave.GetBool()) { + gameRenderWorld->DebugBounds(colorRed, bounds, vec3_origin); + } + + listedClipModels = gameLocal.clip.ClipModelsTouchingBounds( bounds, -1, clipModelList, MAX_GENTITIES ); + + for ( i = 0; i < listedClipModels; i++ ) { + clip = clipModelList[ i ]; + ent = clip->GetEntity(); + + if ( ent->IsHidden() ) { + continue; + } + + if ( !ent->IsType( idMoveable::Type ) && !ent->IsType( idAFEntity_Base::Type ) && !ent->IsType( idPlayer::Type )) { + continue; + } + + idVec3 point = ent->GetPhysics()->GetOrigin(); + idVec3 force = point - pos; + + float dist = force.Normalize(); + + if(ent->IsType( idPlayer::Type )) { + + if(ent->GetPhysics()->GetAbsBounds().IntersectsBounds(bounds)) { + + //For player damage we check the current radius and a specified player damage ring size + if ( dist <= newSize && dist > newSize-playerDamageSize ) { + + idStr damageDef = spawnArgs.GetString("def_player_damage", ""); + if(damageDef.Length() > 0 && !playerDamaged) { + + playerDamaged = true; //Only damage once per shockwave + idPlayer* player = static_cast< idPlayer* >( ent ); + idVec3 dir = ent->GetPhysics()->GetOrigin() - pos; + dir.NormalizeFast(); + player->Damage(NULL, NULL, dir, damageDef, 1.0f, INVALID_JOINT); + } + } + } + + } else { + + // If the object is inside the current expansion... + if ( dist <= newSize && dist > currentSize ) { + force.z += 4.f; + force.NormalizeFast(); + + if ( ent->IsType( idAFEntity_Base::Type ) ) { + force = force * (ent->GetPhysics()->GetMass() * magnitude * 0.01f); + } else { + force = force * ent->GetPhysics()->GetMass() * magnitude; + } + + // Kick it up, move force point off object origin + float rad = ent->GetPhysics()->GetBounds().GetRadius(); + point.x += gameLocal.random.CRandomFloat() * rad; + point.y += gameLocal.random.CRandomFloat() * rad; + + int j; + for( j=0; j < ent->GetPhysics()->GetNumClipModels(); j++ ) { + ent->GetPhysics()->AddForce( j, point, force ); + } + } + } + } + + // Update currentSize for next frame + currentSize = newSize; + + } else { + + // turn off + isActive = false; + } +} + +/* +=============== +idShockwave::Event_Activate +=============== +*/ +void idShockwave::Event_Activate( idEntity *activator ) { + + isActive = true; + startTime = gameLocal.time; + playerDamaged = false; + + BecomeActive( TH_THINK ); +} + + +/* +=============================================================================== + +idFuncMountedObject + +=============================================================================== +*/ + +CLASS_DECLARATION( idEntity, idFuncMountedObject ) +EVENT( EV_Touch, idFuncMountedObject::Event_Touch ) +EVENT( EV_Activate, idFuncMountedObject::Event_Activate ) +END_CLASS + +/* +=============== +idFuncMountedObject::idFuncMountedObject +=============== +*/ +idFuncMountedObject::idFuncMountedObject() { + isMounted = false; + scriptFunction = NULL; + mountedPlayer = NULL; + harc = 0; + varc = 0; +} + +/* +=============== +idFuncMountedObject::idFuncMountedObject +=============== +*/ +idFuncMountedObject::~idFuncMountedObject() { +} + +/* +=============== +idFuncMountedObject::Spawn +=============== +*/ +void idFuncMountedObject::Spawn( void ) { + // Get viewOffset + spawnArgs.GetInt( "harc", "45", harc ); + spawnArgs.GetInt( "varc", "30", varc ); + + // Get script function + idStr funcName = spawnArgs.GetString( "call", "" ); + if ( funcName.Length() ) { + scriptFunction = gameLocal.program.FindFunction( funcName ); + if ( scriptFunction == NULL ) { + gameLocal.Warning( "idFuncMountedObject '%s' at (%s) calls unknown function '%s'\n", name.c_str(), GetPhysics()->GetOrigin().ToString(0), funcName.c_str() ); + } + } + + BecomeActive( TH_THINK ); +} + +/* +================ +idFuncMountedObject::Think +================ +*/ +void idFuncMountedObject::Think( void ) { + + idEntity::Think(); +} + +/* +================ +idFuncMountedObject::GetViewInfo +================ +*/ +void idFuncMountedObject::GetAngleRestrictions( int &yaw_min, int &yaw_max, int &pitch ) { + idMat3 axis; + idAngles angs; + + axis = GetPhysics()->GetAxis(); + angs = axis.ToAngles(); + + yaw_min = angs.yaw - harc; + yaw_min = idMath::AngleNormalize180( yaw_min ); + + yaw_max = angs.yaw + harc; + yaw_max = idMath::AngleNormalize180( yaw_max ); + + pitch = varc; +} + +/* +================ +idFuncMountedObject::Event_Touch +================ +*/ +void idFuncMountedObject::Event_Touch( idEntity *other, trace_t *trace ) { + + ProcessEvent( &EV_Activate, other ); +} + +/* +================ +idFuncMountedObject::Event_Activate +================ +*/ +void idFuncMountedObject::Event_Activate( idEntity *activator ) { + if ( !isMounted && activator->IsType( idPlayer::Type ) ) { + idPlayer *client = (idPlayer *)activator; + + mountedPlayer = client; + + /* + // Place player at path_corner targeted by mounted object + int i; + idPathCorner *spot; + + for ( i = 0; i < targets.Num(); i++ ) { + if ( targets[i]->IsType( idPathCorner::Type ) ) { + spot = (idPathCorner*)targets[i]; + break; + } + } + + mountedPlayer->GetPhysics()->SetOrigin( spot->GetPhysics()->GetOrigin() ); + mountedPlayer->GetPhysics()->SetAxis( spot->GetPhysics()->GetAxis() ); + */ + + mountedPlayer->Bind( this, true ); + mountedPlayer->mountedObject = this; + + // Call a script function + idThread *mountthread; + if ( scriptFunction ) { + mountthread = new idThread( scriptFunction ); + mountthread->DelayedStart( 0 ); + } + + isMounted = true; + } +} + +/* +=============================================================================== + +idFuncMountedWeapon + +=============================================================================== +*/ +CLASS_DECLARATION( idFuncMountedObject, idFuncMountedWeapon ) +EVENT( EV_PostSpawn, idFuncMountedWeapon::Event_PostSpawn ) +END_CLASS + +idFuncMountedWeapon::idFuncMountedWeapon() { + turret = NULL; + weaponLastFireTime = 0; + weaponFireDelay = 0; + projectile = NULL; +} + +idFuncMountedWeapon::~idFuncMountedWeapon() { +} + + +void idFuncMountedWeapon::Spawn( void ) { + + // Get projectile info + projectile = gameLocal.FindEntityDefDict( spawnArgs.GetString( "def_projectile" ), false ); + if ( !projectile ) { + gameLocal.Warning( "Invalid projectile on func_mountedweapon." ); + } + + float firerate; + spawnArgs.GetFloat( "firerate", "3", firerate ); + weaponFireDelay = 1000.f / firerate; + + // Get the firing sound + idStr fireSound; + spawnArgs.GetString( "snd_fire", "", fireSound ); + soundFireWeapon = declManager->FindSound( fireSound ); + + PostEventMS( &EV_PostSpawn, 0 ); +} + +void idFuncMountedWeapon::Think( void ) { + + if ( isMounted && turret ) { + idVec3 vec = mountedPlayer->viewAngles.ToForward(); + idAngles ang = mountedPlayer->GetLocalVector( vec ).ToAngles(); + + turret->GetPhysics()->SetAxis( ang.ToMat3() ); + turret->UpdateVisuals(); + + // Check for firing + if ( mountedPlayer->usercmd.buttons & BUTTON_ATTACK && ( gameLocal.time > weaponLastFireTime + weaponFireDelay ) ) { + // FIRE! + idEntity *ent; + idProjectile *proj; + idBounds projBounds; + idVec3 dir; + + gameLocal.SpawnEntityDef( *projectile, &ent ); + if ( !ent || !ent->IsType( idProjectile::Type ) ) { + const char *projectileName = spawnArgs.GetString( "def_projectile" ); + gameLocal.Error( "'%s' is not an idProjectile", projectileName ); + } + + mountedPlayer->GetViewPos( muzzleOrigin, muzzleAxis ); + + muzzleOrigin += ( muzzleAxis[0] * 128 ); + muzzleOrigin -= ( muzzleAxis[2] * 20 ); + + dir = muzzleAxis[0]; + + proj = static_cast(ent); + proj->Create( this, muzzleOrigin, dir ); + + projBounds = proj->GetPhysics()->GetBounds().Rotate( proj->GetPhysics()->GetAxis() ); + + proj->Launch( muzzleOrigin, dir, vec3_origin ); + StartSoundShader( soundFireWeapon, SND_CHANNEL_WEAPON, SSF_GLOBAL, false, NULL ); + + weaponLastFireTime = gameLocal.time; + } + } + + idFuncMountedObject::Think(); +} + +void idFuncMountedWeapon::Event_PostSpawn( void ) { + + if ( targets.Num() >= 1 ) { + for ( int i=0; i < targets.Num(); i++ ) { + if ( targets[i].GetEntity()->IsType( idStaticEntity::Type ) ) { + turret = targets[i].GetEntity(); + break; + } + } + } else { + gameLocal.Warning( "idFuncMountedWeapon::Spawn: Please target one model for a turret\n" ); + } +} + + + + + + +/* +=============================================================================== + +idPortalSky + +=============================================================================== +*/ + +CLASS_DECLARATION( idEntity, idPortalSky ) + EVENT( EV_PostSpawn, idPortalSky::Event_PostSpawn ) + EVENT( EV_Activate, idPortalSky::Event_Activate ) +END_CLASS + +/* +=============== +idPortalSky::idPortalSky +=============== +*/ +idPortalSky::idPortalSky( void ) { + +} + +/* +=============== +idPortalSky::~idPortalSky +=============== +*/ +idPortalSky::~idPortalSky( void ) { + +} + +/* +=============== +idPortalSky::Spawn +=============== +*/ +void idPortalSky::Spawn( void ) { + if ( !spawnArgs.GetBool( "triggered" ) ) { + PostEventMS( &EV_PostSpawn, 1 ); + } +} + +/* +================ +idPortalSky::Event_PostSpawn +================ +*/ +void idPortalSky::Event_PostSpawn() { + gameLocal.SetPortalSkyEnt( this ); +} + +/* +================ +idPortalSky::Event_Activate +================ +*/ +void idPortalSky::Event_Activate( idEntity *activator ) { + gameLocal.SetPortalSkyEnt( this ); +} +#endif /* _D3XP */ diff --git a/game/Misc.h b/game/Misc.h index 89a4235e..a3254096 100644 --- a/game/Misc.h +++ b/game/Misc.h @@ -164,6 +164,11 @@ class idDamagable : public idEntity { void Spawn( void ); void Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ); +#ifdef _D3XP + virtual void Hide( void ); + virtual void Show( void ); +#endif + private: int count; int nextTriggerTime; @@ -293,6 +298,10 @@ class idAnimated : public idAFEntity_Gibbable { void Event_Footstep( void ); void Event_LaunchMissiles( const char *projectilename, const char *sound, const char *launchjoint, const char *targetjoint, int numshots, int framedelay ); void Event_LaunchMissilesUpdate( int launchjoint, int targetjoint, int numshots, int framedelay ); +#ifdef _D3XP + void Event_SetAnimation( const char *animName ); + void Event_GetAnimationLength(); +#endif }; @@ -765,4 +774,127 @@ class idPhantomObjects : public idEntity { idList lastTargetPos; }; +#ifdef _D3XP +/* +=============================================================================== + +idShockwave + +=============================================================================== +*/ +class idShockwave : public idEntity { +public: + CLASS_PROTOTYPE( idShockwave ); + + idShockwave(); + ~idShockwave(); + + void Spawn( void ); + void Think( void ); + + void Save( idSaveGame *savefile ) const; + void Restore( idRestoreGame *savefile ); + +private: + void Event_Activate( idEntity *activator ); + + bool isActive; + int startTime; + int duration; + + float startSize; + float endSize; + float currentSize; + + float magnitude; + + float height; + bool playerDamaged; + float playerDamageSize; + +}; + +/* +=============================================================================== + +idFuncMountedObject + +=============================================================================== +*/ +class idFuncMountedObject : public idEntity { +public: + CLASS_PROTOTYPE( idFuncMountedObject ); + + idFuncMountedObject(); + ~idFuncMountedObject(); + + void Spawn( void ); + void Think( void ); + + void GetAngleRestrictions( int &yaw_min, int &yaw_max, int &pitch ); + +private: + int harc; + int varc; + + void Event_Touch( idEntity *other, trace_t *trace ); + void Event_Activate( idEntity *activator ); + +public: + bool isMounted; + function_t * scriptFunction; + idPlayer * mountedPlayer; +}; + + +class idFuncMountedWeapon : public idFuncMountedObject { +public: + CLASS_PROTOTYPE( idFuncMountedWeapon ); + + idFuncMountedWeapon(); + ~idFuncMountedWeapon(); + + void Spawn( void ); + void Think( void ); + +private: + + // The actual turret that moves with the player's view + idEntity * turret; + + // the muzzle bone's position, used for launching projectiles and trailing smoke + idVec3 muzzleOrigin; + idMat3 muzzleAxis; + + float weaponLastFireTime; + float weaponFireDelay; + + const idDict * projectile; + + const idSoundShader *soundFireWeapon; + + void Event_PostSpawn( void ); +}; + +/* +=============================================================================== + +idPortalSky + +=============================================================================== +*/ +class idPortalSky : public idEntity { +public: + CLASS_PROTOTYPE( idPortalSky ); + + idPortalSky(); + ~idPortalSky(); + + void Spawn( void ); + void Event_PostSpawn(); + void Event_Activate( idEntity *activator ); +}; + +#endif /* _D3XP */ + #endif /* !__GAME_MISC_H__ */ diff --git a/game/Moveable.cpp b/game/Moveable.cpp index e13ecd6a..f29e2d99 100644 --- a/game/Moveable.cpp +++ b/game/Moveable.cpp @@ -29,6 +29,8 @@ If you have questions concerning this license or the applicable additional terms #include "sys/platform.h" #include "renderer/ModelManager.h" +#include "gamesys/SysCvar.h" +#include "ai/AI.h" #include "Fx.h" #include "Moveable.h" @@ -75,6 +77,9 @@ idMoveable::idMoveable( void ) { unbindOnDeath = false; allowStep = false; canDamage = false; +#ifdef _D3XP + attacker = NULL; +#endif } /* @@ -130,9 +135,14 @@ void idMoveable::Spawn( void ) { fl.takedamage = true; damage = spawnArgs.GetString( "def_damage", "" ); +#ifdef _D3XP + monsterDamage = spawnArgs.GetString( "monster_damage", "" ); + fl.networkSync = true; + attacker = NULL; +#endif canDamage = spawnArgs.GetBool( "damageWhenActive" ) ? false : true; - minDamageVelocity = spawnArgs.GetFloat( "minDamageVelocity", "100" ); - maxDamageVelocity = spawnArgs.GetFloat( "maxDamageVelocity", "200" ); + minDamageVelocity = spawnArgs.GetFloat( "minDamageVelocity", "300" ); // _D3XP + maxDamageVelocity = spawnArgs.GetFloat( "maxDamageVelocity", "700" ); // _D3XP nextDamageTime = 0; nextSoundTime = 0; @@ -190,6 +200,10 @@ void idMoveable::Save( idSaveGame *savefile ) const { savefile->WriteString( brokenModel ); savefile->WriteString( damage ); +#ifdef _D3XP + savefile->WriteString( monsterDamage ); + savefile->WriteObject( attacker ); +#endif savefile->WriteString( fxCollide ); savefile->WriteInt( nextCollideFxTime ); savefile->WriteFloat( minDamageVelocity ); @@ -216,6 +230,10 @@ void idMoveable::Restore( idRestoreGame *savefile ) { savefile->ReadString( brokenModel ); savefile->ReadString( damage ); +#ifdef _D3XP + savefile->ReadString( monsterDamage ); + savefile->ReadObject( reinterpret_cast( attacker ) ); +#endif savefile->ReadString( fxCollide ); savefile->ReadInt( nextCollideFxTime ); savefile->ReadFloat( minDamageVelocity ); @@ -282,16 +300,63 @@ bool idMoveable::Collide( const trace_t &collision, const idVec3 &velocity ) { nextSoundTime = gameLocal.time + 500; } + // _D3XP :: changes relating to the addition of monsterDamage +#ifdef _D3XP + if ( !gameLocal.isClient && canDamage && gameLocal.time > nextDamageTime ) { + bool hasDamage = damage.Length() > 0; + bool hasMonsterDamage = monsterDamage.Length() > 0; + + if ( hasDamage || hasMonsterDamage ) { +#else if ( canDamage && damage.Length() && gameLocal.time > nextDamageTime ) { - ent = gameLocal.entities[ collision.c.entityNum ]; - if ( ent && v > minDamageVelocity ) { - f = v > maxDamageVelocity ? 1.0f : idMath::Sqrt( v - minDamageVelocity ) * ( 1.0f / idMath::Sqrt( maxDamageVelocity - minDamageVelocity ) ); - dir = velocity; - dir.NormalizeFast(); - ent->Damage( this, GetPhysics()->GetClipModel()->GetOwner(), dir, damage, f, INVALID_JOINT ); - nextDamageTime = gameLocal.time + 1000; +#endif // _D3XP + ent = gameLocal.entities[ collision.c.entityNum ]; + if ( ent && v > minDamageVelocity ) { + f = v > maxDamageVelocity ? 1.0f : idMath::Sqrt( v - minDamageVelocity ) * ( 1.0f / idMath::Sqrt( maxDamageVelocity - minDamageVelocity ) ); + dir = velocity; + dir.NormalizeFast(); +#ifdef _D3XP + if ( ent->IsType( idAI::Type ) && hasMonsterDamage ) { + if ( attacker ) { + ent->Damage( this, attacker, dir, monsterDamage, f, INVALID_JOINT ); + } + else { + ent->Damage( this, GetPhysics()->GetClipModel()->GetOwner(), dir, monsterDamage, f, INVALID_JOINT ); + } + ent->Damage( this, GetPhysics()->GetClipModel()->GetOwner(), dir, monsterDamage, f, INVALID_JOINT ); + } else if ( hasDamage ) { + // in multiplayer, scale damage wrt mass of object + if ( gameLocal.isMultiplayer ) { + f *= GetPhysics()->GetMass() * g_moveableDamageScale.GetFloat(); + } + + if ( attacker ) { + ent->Damage( this, attacker, dir, damage, f, INVALID_JOINT ); + } + else { + ent->Damage( this, GetPhysics()->GetClipModel()->GetOwner(), dir, damage, f, INVALID_JOINT ); + } + } +#else + ent->Damage( this, GetPhysics()->GetClipModel()->GetOwner(), dir, damage, f, INVALID_JOINT ); +#endif + + nextDamageTime = gameLocal.time + 1000; + } + } +#ifdef _D3XP + } +#endif + +#ifdef _D3XP + if ( this->IsType( idExplodingBarrel::Type ) ) { + idExplodingBarrel *ebarrel = static_cast(this); + + if ( !ebarrel->IsStable() ) { + PostEventSec( &EV_Explode, 0.04f ); } } +#endif if ( fxCollide.Length() && gameLocal.time > nextCollideFxTime ) { idEntityFx::StartFx( fxCollide, &collision.c.point, NULL, this, false ); @@ -356,9 +421,15 @@ idMoveable::EnableDamage ================ */ void idMoveable::EnableDamage( bool enable, float duration ) { +#ifdef _D3XP + if ( canDamage == enable ) { + return; + } +#endif + canDamage = enable; if ( duration ) { - PostEventSec( &EV_EnableDamage, duration, ( !enable ) ? 0.0f : 1.0f ); + PostEventSec( &EV_EnableDamage, duration, ( /*_D3XP*/enable ) ? 0.0f : 1.0f ); } } @@ -469,6 +540,17 @@ void idMoveable::Event_BecomeNonSolid( void ) { BecomeNonSolid(); } +#ifdef _D3XP +/* +================ +idMoveable::SetAttacker +================ +*/ +void idMoveable::SetAttacker( idEntity *ent ) { + attacker = ent; +} +#endif + /* ================ idMoveable::Event_Activate @@ -534,6 +616,11 @@ idMoveable::Event_EnableDamage ================ */ void idMoveable::Event_EnableDamage( float enable ) { +#ifdef _D3XP + // clear out attacker + attacker = NULL; +#endif + canDamage = ( enable != 0.0f ); } @@ -709,6 +796,10 @@ void idBarrel::Spawn( void ) { additionalRotation = 0.0f; additionalAxis.Identity(); + +#ifdef _D3XP + fl.networkSync = true; +#endif } /* @@ -747,6 +838,9 @@ idExplodingBarrel::idExplodingBarrel() { spawnOrigin.Zero(); spawnAxis.Zero(); state = NORMAL; +#ifdef _D3XP + isStable = true; +#endif particleModelDefHandle = -1; lightDefHandle = -1; memset( &particleRenderEntity, 0, sizeof( particleRenderEntity ) ); @@ -789,6 +883,10 @@ void idExplodingBarrel::Save( idSaveGame *savefile ) const { savefile->WriteInt( particleTime ); savefile->WriteInt( lightTime ); savefile->WriteFloat( time ); + +#ifdef _D3XP + savefile->WriteBool( isStable ); +#endif } /* @@ -810,6 +908,17 @@ void idExplodingBarrel::Restore( idRestoreGame *savefile ) { savefile->ReadInt( particleTime ); savefile->ReadInt( lightTime ); savefile->ReadFloat( time ); + +#ifdef _D3XP + savefile->ReadBool( isStable ); + + if ( lightDefHandle != -1 ) { + lightDefHandle = gameRenderWorld->AddLightDef( &light ); + } + if ( particleModelDefHandle != -1 ) { + particleModelDefHandle = gameRenderWorld->AddEntityDef( &particleRenderEntity ); + } +#endif } /* @@ -820,6 +929,10 @@ idExplodingBarrel::Spawn void idExplodingBarrel::Spawn( void ) { health = spawnArgs.GetInt( "health", "5" ); fl.takedamage = true; +#ifdef _D3XP + isStable = true; + fl.networkSync = true; +#endif spawnOrigin = GetPhysics()->GetOrigin(); spawnAxis = GetPhysics()->GetAxis(); state = NORMAL; @@ -875,6 +988,53 @@ void idExplodingBarrel::Think( void ) { } } +#ifdef _D3XP +/* +================ +idExplodingBarrel::SetStability +================ +*/ +void idExplodingBarrel::SetStability( bool stability ) { + isStable = stability; +} + +/* +================ +idExplodingBarrel::IsStable +================ +*/ +bool idExplodingBarrel::IsStable( void ) { + return isStable; +} + +/* +================ +idExplodingBarrel::StartBurning +================ +*/ +void idExplodingBarrel::StartBurning( void ) { + state = BURNING; + AddParticles( "barrelfire.prt", true ); +} + +/* +================ +idExplodingBarrel::StartBurning +================ +*/ +void idExplodingBarrel::StopBurning( void ) { + state = NORMAL; + + if ( particleModelDefHandle >= 0 ){ + gameRenderWorld->FreeEntityDef( particleModelDefHandle ); + particleModelDefHandle = -1; + + particleTime = 0; + memset( &particleRenderEntity, 0, sizeof( particleRenderEntity ) ); + } +} +#endif + /* ================ idExplodingBarrel::AddParticles @@ -882,6 +1042,10 @@ idExplodingBarrel::AddParticles */ void idExplodingBarrel::AddParticles( const char *name, bool burn ) { if ( name && *name ) { +#ifdef _D3XP + int explicitTimeGroup = timeGroup; + SetTimeState explicitTS( explicitTimeGroup ); +#endif if ( particleModelDefHandle >= 0 ){ gameRenderWorld->FreeEntityDef( particleModelDefHandle ); } @@ -898,6 +1062,9 @@ void idExplodingBarrel::AddParticles( const char *name, bool burn ) { particleRenderEntity.shaderParms[ SHADERPARM_ALPHA ] = rgb; particleRenderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.realClientTime ); particleRenderEntity.shaderParms[ SHADERPARM_DIVERSITY ] = ( burn ) ? 1.0f : gameLocal.random.RandomInt( 90 ); +#ifdef _D3XP + particleRenderEntity.timeGroup = explicitTimeGroup; +#endif if ( !particleRenderEntity.hModel ) { particleRenderEntity.hModel = renderModelManager->FindModel( name ); } diff --git a/game/Moveable.h b/game/Moveable.h index 21f0092a..53f27514 100644 --- a/game/Moveable.h +++ b/game/Moveable.h @@ -71,10 +71,18 @@ class idMoveable : public idEntity { virtual void WriteToSnapshot( idBitMsgDelta &msg ) const; virtual void ReadFromSnapshot( const idBitMsgDelta &msg ); +#ifdef _D3XP + void SetAttacker( idEntity *ent ); +#endif + protected: idPhysics_RigidBody physicsObj; // physics object idStr brokenModel; // model set when health drops down to or below zero idStr damage; // if > 0 apply damage to hit entities +#ifdef _D3XP + idStr monsterDamage; + idEntity *attacker; +#endif idStr fxCollide; // fx system to start when collides with something int nextCollideFxTime; // next time it is ok to spawn collision fx float minDamageVelocity; // minimum velocity before moveable applies damage @@ -158,6 +166,13 @@ class idExplodingBarrel : public idBarrel { void Save( idSaveGame *savefile ) const; void Restore( idRestoreGame *savefile ); +#ifdef _D3XP + bool IsStable( void ); + void SetStability( bool stability ); + void StartBurning( void ); + void StopBurning( void ); +#endif + virtual void Think( void ); virtual void Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location ); @@ -190,6 +205,9 @@ class idExplodingBarrel : public idBarrel { int particleTime; int lightTime; float time; +#ifdef _D3XP + bool isStable; +#endif void AddParticles( const char *name, bool burn ); void AddLight( const char *name , bool burn ); diff --git a/game/Mover.cpp b/game/Mover.cpp index 9f1a8199..95758f45 100644 --- a/game/Mover.cpp +++ b/game/Mover.cpp @@ -33,6 +33,8 @@ If you have questions concerning this license or the applicable additional terms #include "Mover.h" +// _D3XP : rename all gameLocal.time to gameLocal.slow.time for merge! + // a mover will update any gui entities in it's target list with // a key/val pair of "mover" "state" from below.. guis can represent // realtime info like this @@ -542,7 +544,11 @@ void idMover::SetGuiState( const char *key, const char *val ) const { for ( int j = 0; j < MAX_RENDERENTITY_GUI; j++ ) { if ( ent->GetRenderEntity() && ent->GetRenderEntity()->gui[ j ] ) { ent->GetRenderEntity()->gui[ j ]->SetStateString( key, val ); +#ifdef _D3XP + ent->GetRenderEntity()->gui[ j ]->StateChanged( gameLocal.slow.time, true ); +#else ent->GetRenderEntity()->gui[ j ]->StateChanged( gameLocal.time, true ); +#endif // _D3XP } } ent->UpdateVisuals(); @@ -572,7 +578,11 @@ void idMover::SetGuiStates( const char *state ) { for ( i = 0; i < MAX_RENDERENTITY_GUI; i++ ) { if ( renderEntity.gui[ i ] ) { renderEntity.gui[ i ]->SetStateString( "movestate", state ); +#ifdef _D3XP + renderEntity.gui[ i ]->StateChanged( gameLocal.slow.time, true ); +#else renderEntity.gui[ i ]->StateChanged( gameLocal.time, true ); +#endif // _D3XP } } } @@ -663,7 +673,11 @@ void idMover::Event_UpdateMove( void ) { switch( move.stage ) { case ACCELERATION_STAGE: { +#ifdef _D3XP + physicsObj.SetLinearExtrapolation( EXTRAPOLATION_ACCELLINEAR, gameLocal.slow.time, move.acceleration, org, move.dir, vec3_origin ); +#else physicsObj.SetLinearExtrapolation( EXTRAPOLATION_ACCELLINEAR, gameLocal.time, move.acceleration, org, move.dir, vec3_origin ); +#endif // _D3XP if ( move.movetime > 0 ) { move.stage = LINEAR_STAGE; } else if ( move.deceleration > 0 ) { @@ -674,7 +688,11 @@ void idMover::Event_UpdateMove( void ) { break; } case LINEAR_STAGE: { +#ifdef _D3XP + physicsObj.SetLinearExtrapolation( EXTRAPOLATION_LINEAR, gameLocal.slow.time, move.movetime, org, move.dir, vec3_origin ); +#else physicsObj.SetLinearExtrapolation( EXTRAPOLATION_LINEAR, gameLocal.time, move.movetime, org, move.dir, vec3_origin ); +#endif // _D3XP if ( move.deceleration ) { move.stage = DECELERATION_STAGE; } else { @@ -683,13 +701,21 @@ void idMover::Event_UpdateMove( void ) { break; } case DECELERATION_STAGE: { +#ifdef _D3XP + physicsObj.SetLinearExtrapolation( EXTRAPOLATION_DECELLINEAR, gameLocal.slow.time, move.deceleration, org, move.dir, vec3_origin ); +#else physicsObj.SetLinearExtrapolation( EXTRAPOLATION_DECELLINEAR, gameLocal.time, move.deceleration, org, move.dir, vec3_origin ); +#endif // _D3XP move.stage = FINISHED_STAGE; break; } case FINISHED_STAGE: { if ( g_debugMover.GetBool() ) { +#ifdef _D3XP + gameLocal.Printf( "%d: '%s' move done\n", gameLocal.slow.time, name.c_str() ); +#else gameLocal.Printf( "%d: '%s' move done\n", gameLocal.time, name.c_str() ); +#endif // _D3XP } DoneMoving(); break; @@ -851,7 +877,10 @@ void idMover::Event_UpdateRotation( void ) { switch( rot.stage ) { case ACCELERATION_STAGE: { - physicsObj.SetAngularExtrapolation( EXTRAPOLATION_ACCELLINEAR, gameLocal.time, rot.acceleration, ang, rot.rot, ang_zero ); +#ifdef _D3XP + physicsObj.SetAngularExtrapolation( EXTRAPOLATION_ACCELLINEAR, gameLocal.slow.time, rot.acceleration, ang, rot.rot, ang_zero ); +#else +#endif // _D3XP if ( rot.movetime > 0 ) { rot.stage = LINEAR_STAGE; } else if ( rot.deceleration > 0 ) { @@ -862,11 +891,19 @@ void idMover::Event_UpdateRotation( void ) { break; } case LINEAR_STAGE: { +#ifdef _D3XP + if ( !stopRotation && !rot.deceleration ) { + physicsObj.SetAngularExtrapolation( extrapolation_t(EXTRAPOLATION_LINEAR|EXTRAPOLATION_NOSTOP), gameLocal.slow.time, rot.movetime, ang, rot.rot, ang_zero ); + } else { + physicsObj.SetAngularExtrapolation( EXTRAPOLATION_LINEAR, gameLocal.slow.time, rot.movetime, ang, rot.rot, ang_zero ); + } +#else if ( !stopRotation && !rot.deceleration ) { physicsObj.SetAngularExtrapolation( extrapolation_t(EXTRAPOLATION_LINEAR|EXTRAPOLATION_NOSTOP), gameLocal.time, rot.movetime, ang, rot.rot, ang_zero ); } else { physicsObj.SetAngularExtrapolation( EXTRAPOLATION_LINEAR, gameLocal.time, rot.movetime, ang, rot.rot, ang_zero ); } +#endif // _D3XP if ( rot.deceleration ) { rot.stage = DECELERATION_STAGE; @@ -876,7 +913,11 @@ void idMover::Event_UpdateRotation( void ) { break; } case DECELERATION_STAGE: { - physicsObj.SetAngularExtrapolation( EXTRAPOLATION_DECELLINEAR, gameLocal.time, rot.deceleration, ang, rot.rot, ang_zero ); +#ifdef _D3XP + physicsObj.SetAngularExtrapolation( EXTRAPOLATION_DECELLINEAR, gameLocal.slow.time, rot.deceleration, ang, rot.rot, ang_zero ); +#else + physicsObj.SetAngularExtrapolation(EXTRAPOLATION_DECELLINEAR, gameLocal.time, rot.deceleration, ang, rot.rot, ang_zero); +#endif // _D3XP rot.stage = FINISHED_STAGE; break; } @@ -889,11 +930,17 @@ void idMover::Event_UpdateRotation( void ) { stopRotation = false; } else if ( physicsObj.GetAngularExtrapolationType() == EXTRAPOLATION_ACCELLINEAR ) { // keep our angular velocity constant - physicsObj.SetAngularExtrapolation( extrapolation_t(EXTRAPOLATION_LINEAR|EXTRAPOLATION_NOSTOP), gameLocal.time, 0, ang, rot.rot, ang_zero ); +#ifdef _D3XP + physicsObj.SetAngularExtrapolation( extrapolation_t(EXTRAPOLATION_LINEAR|EXTRAPOLATION_NOSTOP), gameLocal.slow.time, 0, ang, rot.rot, ang_zero ); +#else +#endif // _D3XP } if ( g_debugMover.GetBool() ) { - gameLocal.Printf( "%d: '%s' rotation done\n", gameLocal.time, name.c_str() ); +#ifdef _D3XP + gameLocal.Printf( "%d: '%s' rotation done\n", gameLocal.slow.time, name.c_str() ); +#else +#endif // _D3XP } DoneRotating(); @@ -988,7 +1035,11 @@ idMover::Event_TeamBlocked */ void idMover::Event_TeamBlocked( idEntity *blockedEntity, idEntity *blockingEntity ) { if ( g_debugMover.GetBool() ) { +#ifdef _D3XP + gameLocal.Printf( "%d: '%s' stopped due to team member '%s' blocked by '%s'\n", gameLocal.slow.time, name.c_str(), blockedEntity->name.c_str(), blockingEntity->name.c_str() ); +#else gameLocal.Printf( "%d: '%s' stopped due to team member '%s' blocked by '%s'\n", gameLocal.time, name.c_str(), blockedEntity->name.c_str(), blockingEntity->name.c_str() ); +#endif // _D3XP } } @@ -1002,7 +1053,11 @@ void idMover::Event_PartBlocked( idEntity *blockingEntity ) { blockingEntity->Damage( this, this, vec3_origin, "damage_moverCrush", damage, INVALID_JOINT ); } if ( g_debugMover.GetBool() ) { +#ifdef _D3XP + gameLocal.Printf( "%d: '%s' blocked by '%s'\n", gameLocal.slow.time, name.c_str(), blockingEntity->name.c_str() ); +#else gameLocal.Printf( "%d: '%s' blocked by '%s'\n", gameLocal.time, name.c_str(), blockingEntity->name.c_str() ); +#endif // _D3XP } } @@ -1149,7 +1204,11 @@ void idMover::Event_MoveAccelerateTo( float speed, float time ) { StartSound( "snd_accel", SND_CHANNEL_BODY2, 0, false, NULL ); StartSound( "snd_move", SND_CHANNEL_BODY, 0, false, NULL ); +#ifdef _D3XP + physicsObj.SetLinearExtrapolation( EXTRAPOLATION_ACCELLINEAR, gameLocal.slow.time, move.acceleration, org, dir * ( speed - v ), dir * v ); +#else physicsObj.SetLinearExtrapolation( EXTRAPOLATION_ACCELLINEAR, gameLocal.time, move.acceleration, org, dir * ( speed - v ), dir * v ); +#endif // _D3XP } /* @@ -1192,7 +1251,11 @@ void idMover::Event_MoveDecelerateTo( float speed, float time ) { StartSound( "snd_decel", SND_CHANNEL_BODY2, 0, false, NULL ); StartSound( "snd_move", SND_CHANNEL_BODY, 0, false, NULL ); +#ifdef _D3XP + physicsObj.SetLinearExtrapolation( EXTRAPOLATION_DECELLINEAR, gameLocal.slow.time, move.deceleration, org, dir * ( v - speed ), dir * speed ); +#else physicsObj.SetLinearExtrapolation( EXTRAPOLATION_DECELLINEAR, gameLocal.time, move.deceleration, org, dir * ( v - speed ), dir * speed ); +#endif // _D3XP } /* @@ -1434,7 +1497,11 @@ void idMover::Event_StartSpline( idEntity *splineEntity ) { move.deceleration = deceltime; spline->MakeUniform( move_time ); +#ifdef _D3XP + spline->ShiftTime( gameLocal.slow.time - spline->GetTime( 0 ) ); +#else spline->ShiftTime( gameLocal.time - spline->GetTime( 0 ) ); +#endif // _D3XP physicsObj.SetSpline( spline, move.acceleration, move.deceleration, useSplineAngles ); physicsObj.SetLinearExtrapolation( EXTRAPOLATION_NONE, 0, 0, dest_position, vec3_origin, vec3_origin ); @@ -1572,6 +1639,9 @@ idElevator */ const idEventDef EV_PostArrival( "postArrival", NULL ); const idEventDef EV_GotoFloor( "gotoFloor", "d" ); +#ifdef _D3XP +const idEventDef EV_SetGuiStates( "setGuiStates" ); +#endif CLASS_DECLARATION( idMover, idElevator ) EVENT( EV_Activate, idElevator::Event_Activate ) @@ -1580,6 +1650,9 @@ CLASS_DECLARATION( idMover, idElevator ) EVENT( EV_PostArrival, idElevator::Event_PostFloorArrival ) EVENT( EV_GotoFloor, idElevator::Event_GotoFloor ) EVENT( EV_Touch, idElevator::Event_Touch ) +#ifdef _D3XP + EVENT( EV_SetGuiStates, idElevator::Event_SetGuiStates ) +#endif END_CLASS /* @@ -1696,8 +1769,11 @@ idElevator::Event_Touch =============== */ void idElevator::Event_Touch( idEntity *other, trace_t *trace ) { - +#ifdef _D3XP + if ( gameLocal.slow.time < lastTouchTime + 2000 ) { +#else if ( gameLocal.time < lastTouchTime + 2000 ) { +#endif // _D3XP return; } @@ -1705,7 +1781,11 @@ void idElevator::Event_Touch( idEntity *other, trace_t *trace ) { return; } +#ifdef _D3XP + lastTouchTime = gameLocal.slow.time; +#else lastTouchTime = gameLocal.time; +#endif // _D3XP if ( thinkFlags & TH_PHYSICS ) { return; @@ -1795,7 +1875,6 @@ void idElevator::Event_TeamBlocked( idEntity *blockedEntity, idEntity *blockingE } } - /* =============== idElevator::HandleSingleGuiCommand @@ -1918,7 +1997,11 @@ void idElevator::BeginMove( idThread *thread ) { for ( int j = 0; j < MAX_RENDERENTITY_GUI; j++ ) { if ( ent->GetRenderEntity() && ent->GetRenderEntity()->gui[ j ] ) { ent->GetRenderEntity()->gui[ j ]->SetStateString( "floor", "" ); +#ifdef _D3XP + ent->GetRenderEntity()->gui[ j ]->StateChanged( gameLocal.slow.time, true ); +#else ent->GetRenderEntity()->gui[ j ]->StateChanged( gameLocal.time, true ); +#endif // _D3XP } } ent->UpdateVisuals(); @@ -1973,6 +2056,12 @@ void idElevator::Event_PostFloorArrival() { } } +#ifdef _D3XP +void idElevator::Event_SetGuiStates() { + SetGuiStates( ( currentFloor == 1 ) ? guiBinaryMoverStates[0] : guiBinaryMoverStates[1] ); +} +#endif + /* ================ idElevator::DoneMoving @@ -1988,7 +2077,11 @@ void idElevator::DoneMoving( void ) { for ( int j = 0; j < MAX_RENDERENTITY_GUI; j++ ) { if ( ent->GetRenderEntity() && ent->GetRenderEntity()->gui[ j ] ) { ent->GetRenderEntity()->gui[ j ]->SetStateString( "floor", va( "%i", currentFloor ) ); - ent->GetRenderEntity()->gui[ j ]->StateChanged( gameLocal.time, true ); +#ifdef _D3XP + ent->GetRenderEntity()->gui[ j ]->StateChanged( gameLocal.slow.time, true ); +#else + ent->GetRenderEntity()->gui[ j ]->StateChanged(gameLocal.time, true); +#endif // _D3XP } } ent->UpdateVisuals(); @@ -2119,6 +2212,9 @@ idMover_Binary::idMover_Binary() { updateStatus = 0; areaPortal = 0; blocked = false; +#ifdef _D3XP + playerOnly = false; +#endif fl.networkSync = true; } @@ -2197,6 +2293,9 @@ void idMover_Binary::Save( idSaveGame *savefile ) const { savefile->WriteInt( gameRenderWorld->GetPortalState( areaPortal ) ); } savefile->WriteBool( blocked ); +#ifdef _D3XP + savefile->WriteBool( playerOnly ); +#endif savefile->WriteInt( guiTargets.Num() ); for( i = 0; i < guiTargets.Num(); i++ ) { @@ -2258,6 +2357,9 @@ void idMover_Binary::Restore( idRestoreGame *savefile ) { gameLocal.SetPortalState( areaPortal, portalState ); } savefile->ReadBool( blocked ); +#ifdef _D3XP + savefile->ReadBool( playerOnly ); +#endif guiTargets.Clear(); savefile->ReadInt( num ); @@ -2567,6 +2669,11 @@ void idMover_Binary::Event_OpenPortal( void ) { if ( slave->areaPortal ) { slave->SetPortalState( true ); } +#ifdef _D3XP + if ( slave->playerOnly ) { + gameLocal.SetAASAreaState( slave->GetPhysics()->GetAbsBounds(), AREACONTENTS_CLUSTERPORTAL, false ); + } +#endif } } @@ -2585,6 +2692,11 @@ void idMover_Binary::Event_ClosePortal( void ) { if ( slave->areaPortal ) { slave->SetPortalState( false ); } +#ifdef _D3XP + if ( slave->playerOnly ) { + gameLocal.SetAASAreaState( slave->GetPhysics()->GetAbsBounds(), AREACONTENTS_CLUSTERPORTAL, true ); + } +#endif } } } @@ -2595,7 +2707,11 @@ idMover_Binary::Event_ReturnToPos1 ================ */ void idMover_Binary::Event_ReturnToPos1( void ) { +#ifdef _D3XP + MatchActivateTeam( MOVER_2TO1, gameLocal.slow.time ); +#else MatchActivateTeam( MOVER_2TO1, gameLocal.time ); +#endif // _D3XP } /* @@ -2614,7 +2730,11 @@ void idMover_Binary::Event_Reached_BinaryMover( void ) { StartSound( "snd_opened", SND_CHANNEL_ANY, 0, false, NULL ); } +#ifdef _D3XP + SetMoverState( MOVER_POS2, gameLocal.slow.time ); +#else SetMoverState( MOVER_POS2, gameLocal.time ); +#endif // _D3XP SetGuiStates( guiBinaryMoverStates[MOVER_POS2] ); @@ -2634,7 +2754,11 @@ void idMover_Binary::Event_Reached_BinaryMover( void ) { idThread::ObjectMoveDone( move_thread, this ); move_thread = 0; +#ifdef _D3XP + SetMoverState( MOVER_POS1, gameLocal.slow.time ); +#else SetMoverState( MOVER_POS1, gameLocal.time ); +#endif // _D3XP SetGuiStates( guiBinaryMoverStates[MOVER_POS1] ); @@ -2648,7 +2772,6 @@ void idMover_Binary::Event_Reached_BinaryMover( void ) { if ( enabled && wait >= 0 && spawnArgs.GetBool( "continuous" ) ) { PostEventSec( &EV_Activate, wait, this ); } - SetBlocked(false); } else { gameLocal.Error( "Event_Reached_BinaryMover: bad moverState" ); @@ -2725,7 +2848,11 @@ void idMover_Binary::GotoPosition2( void ) { } if ( moverState == MOVER_POS1 ) { +#ifdef _D3XP + MatchActivateTeam( MOVER_1TO2, gameLocal.slow.time ); +#else MatchActivateTeam( MOVER_1TO2, gameLocal.time ); +#endif // _D3XP // open areaportal ProcessEvent( &EV_Mover_OpenPortal ); @@ -2809,7 +2936,11 @@ void idMover_Binary::Use_BinaryMover( idEntity *activator ) { if ( moverState == MOVER_POS1 ) { // FIXME: start moving USERCMD_MSEC later, because if this was player // triggered, gameLocal.time hasn't been advanced yet +#ifdef _D3XP + MatchActivateTeam( MOVER_1TO2, gameLocal.slow.time + USERCMD_MSEC ); +#else MatchActivateTeam( MOVER_1TO2, gameLocal.time + USERCMD_MSEC ); +#endif // _D3XP SetGuiStates( guiBinaryMoverStates[MOVER_1TO2] ); // open areaportal @@ -2901,7 +3032,11 @@ void idMover_Binary::SetGuiState( const char *key, const char *val ) const { for ( int j = 0; j < MAX_RENDERENTITY_GUI; j++ ) { if ( ent->GetRenderEntity() && ent->GetRenderEntity()->gui[ j ] ) { ent->GetRenderEntity()->gui[ j ]->SetStateString( key, val ); +#ifdef _D3XP + ent->GetRenderEntity()->gui[ j ]->StateChanged( gameLocal.slow.time, true ); +#else ent->GetRenderEntity()->gui[ j ]->StateChanged( gameLocal.time, true ); +#endif // _D3XP } } ent->UpdateVisuals(); @@ -3251,6 +3386,9 @@ void idDoor::Spawn( void ) { spawnArgs.GetBool( "crusher", "0", crusher ); spawnArgs.GetBool( "start_open", "0", start_open ); spawnArgs.GetBool( "no_touch", "0", noTouch ); +#ifdef _D3XP + spawnArgs.GetBool( "player_only", "0", playerOnly ); +#endif // expects syncLock to be a door that must be closed before this door will open spawnArgs.GetString( "syncLock", "", syncLock ); @@ -3292,7 +3430,11 @@ void idDoor::Spawn( void ) { } if ( noTouch || health ) { // non touch/shoot doors +#ifdef _D3XP + PostEventMS( &EV_Mover_MatchTeam, 0, moverState, gameLocal.slow.time ); +#else PostEventMS( &EV_Mover_MatchTeam, 0, moverState, gameLocal.time ); +#endif // _D3XP const char *sndtemp = spawnArgs.GetString( "snd_locked" ); if ( spawnArgs.GetInt( "locked" ) && sndtemp && *sndtemp ) { @@ -3309,6 +3451,12 @@ void idDoor::Spawn( void ) { if ( !start_open ) { // start closed ProcessEvent( &EV_Mover_ClosePortal ); + +#ifdef _D3XP + if ( playerOnly ) { + gameLocal.SetAASAreaState( GetPhysics()->GetAbsBounds(), AREACONTENTS_CLUSTERPORTAL, true ); + } +#endif } int locked = spawnArgs.GetInt( "locked" ); @@ -3580,6 +3728,21 @@ bool idDoor::IsNoTouch( void ) { return noTouch; } +#ifdef _D3XP +/* +================ +idDoor::AllowPlayerOnly +================ +*/ +bool idDoor::AllowPlayerOnly( idEntity *ent ) { + if ( playerOnly && !ent->IsType(idPlayer::Type) ) { + return false; + } + + return true; +} +#endif + /* ====================== idDoor::CalcTriggerBounds @@ -3696,7 +3859,11 @@ void idDoor::Event_SpawnDoorTrigger( void ) { GetLocalTriggerPosition( trigger ); +#ifdef _D3XP + MatchActivateTeam( moverState, gameLocal.slow.time ); +#else MatchActivateTeam( moverState, gameLocal.time ); +#endif // _D3XP } /* @@ -3808,13 +3975,26 @@ void idDoor::Event_Touch( idEntity *other, trace_t *trace ) { if ( trigger && trace->c.id == trigger->GetId() ) { if ( !IsNoTouch() && !IsLocked() && GetMoverState() != MOVER_1TO2 ) { - Use( this, other ); +#ifdef _D3XP + if ( AllowPlayerOnly( other ) ) { +#endif + Use( this, other ); +#ifdef _D3XP + } +#endif } } else if ( sndTrigger && trace->c.id == sndTrigger->GetId() ) { +#ifdef _D3XP + if ( other && other->IsType( idPlayer::Type ) && IsLocked() && gameLocal.slow.time > nextSndTriggerTime ) { + StartSound( "snd_locked", SND_CHANNEL_ANY, 0, false, NULL ); + nextSndTriggerTime = gameLocal.slow.time + 10000; + } +#else if ( other && other->IsType( idPlayer::Type ) && IsLocked() && gameLocal.time > nextSndTriggerTime ) { StartSound( "snd_locked", SND_CHANNEL_ANY, 0, false, NULL ); nextSndTriggerTime = gameLocal.time + 10000; } +#endif // _D3XP } } @@ -3832,7 +4012,11 @@ void idDoor::Event_SpectatorTouch( idEntity *other, trace_t *trace ) { p = static_cast< idPlayer * >( other ); // avoid flicker when stopping right at clip box boundaries +#ifdef _D3XP + if ( p->lastSpectateTeleport > gameLocal.slow.time - 1000 ) { +#else if ( p->lastSpectateTeleport > gameLocal.time - 1000 ) { +#endif // _D3XP return; } if ( trigger && !IsOpen() ) { @@ -3848,7 +4032,11 @@ void idDoor::Event_SpectatorTouch( idEntity *other, trace_t *trace ) { translate[ normalAxisIndex ] += ( bounds[ 1 ][ normalAxisIndex ] - translate[ normalAxisIndex ] ) * 0.5f; } p->SetOrigin( translate ); +#ifdef _D3XP + p->lastSpectateTeleport = gameLocal.slow.time; +#else p->lastSpectateTeleport = gameLocal.time; +#endif // _D3XP } } @@ -4088,7 +4276,11 @@ void idPlat::Spawn( void ) { InitSpeed( pos1, pos2, speed, accel, decel ); } +#ifdef _D3XP + SetMoverState( MOVER_POS1, gameLocal.slow.time ); +#else SetMoverState( MOVER_POS1, gameLocal.time ); +#endif // _D3XP UpdateVisuals(); // spawn the trigger if one hasn't been custom made @@ -4380,8 +4572,13 @@ void idRotater::Spawn( void ) { if ( !spawnArgs.GetBool( "nopush" ) ) { physicsObj.SetPusher( 0 ); } +#ifdef _D3XP + physicsObj.SetLinearExtrapolation( EXTRAPOLATION_NONE, gameLocal.slow.time, 0, GetPhysics()->GetOrigin(), vec3_origin, vec3_origin ); + physicsObj.SetAngularExtrapolation( extrapolation_t(EXTRAPOLATION_LINEAR|EXTRAPOLATION_NOSTOP), gameLocal.slow.time, 0, GetPhysics()->GetAxis().ToAngles(), ang_zero, ang_zero ); +#else physicsObj.SetLinearExtrapolation( EXTRAPOLATION_NONE, gameLocal.time, 0, GetPhysics()->GetOrigin(), vec3_origin, vec3_origin ); physicsObj.SetAngularExtrapolation( extrapolation_t(EXTRAPOLATION_LINEAR|EXTRAPOLATION_NOSTOP), gameLocal.time, 0, GetPhysics()->GetAxis().ToAngles(), ang_zero, ang_zero ); +#endif // _D3XP SetPhysics( &physicsObj ); if ( spawnArgs.GetBool( "start_on" ) ) { @@ -4440,7 +4637,11 @@ void idRotater::Event_Activate( idEntity *activator ) { spawnArgs.Set( "rotate", "0" ); } +#ifdef _D3XP + physicsObj.SetAngularExtrapolation( extrapolation_t(EXTRAPOLATION_LINEAR|EXTRAPOLATION_NOSTOP), gameLocal.slow.time, 0, physicsObj.GetAxis().ToAngles(), delta, ang_zero ); +#else physicsObj.SetAngularExtrapolation( extrapolation_t(EXTRAPOLATION_LINEAR|EXTRAPOLATION_NOSTOP), gameLocal.time, 0, physicsObj.GetAxis().ToAngles(), delta, ang_zero ); +#endif // _D3XP } @@ -4629,6 +4830,10 @@ void idRiser::Event_Activate( idEntity *activator ) { delta = vec3_origin; delta[ 2 ] = height; +#ifdef _D3XP + physicsObj.SetLinearExtrapolation( EXTRAPOLATION_LINEAR, gameLocal.slow.time, time * 1000, physicsObj.GetOrigin(), delta, vec3_origin ); +#else physicsObj.SetLinearExtrapolation( EXTRAPOLATION_LINEAR, gameLocal.time, time * 1000, physicsObj.GetOrigin(), delta, vec3_origin ); +#endif // _D3XP } } diff --git a/game/Mover.h b/game/Mover.h index 7b955987..dc660da1 100644 --- a/game/Mover.h +++ b/game/Mover.h @@ -265,6 +265,10 @@ class idElevator : public idMover { void Event_Activate( idEntity *activator ); void Event_PostFloorArrival(); +#ifdef _D3XP + void Event_SetGuiStates(); +#endif + }; @@ -344,6 +348,9 @@ class idMover_Binary : public idEntity { idPhysics_Parametric physicsObj; qhandle_t areaPortal; // 0 = no portal bool blocked; +#ifdef _D3XP + bool playerOnly; +#endif idList< idEntityPtr > guiTargets; void MatchActivateTeam( moverState_t newstate, int time ); @@ -390,6 +397,9 @@ class idDoor : public idMover_Binary { bool IsOpen( void ); bool IsNoTouch( void ); +#ifdef _D3XP + bool AllowPlayerOnly( idEntity *ent ); +#endif int IsLocked( void ); void Lock( int f ); void Use( idEntity *other, idEntity *activator ); diff --git a/game/MultiplayerGame.cpp b/game/MultiplayerGame.cpp index 94a0affb..c05ea30b 100644 --- a/game/MultiplayerGame.cpp +++ b/game/MultiplayerGame.cpp @@ -32,6 +32,7 @@ If you have questions concerning this license or the applicable additional terms #include "idlib/LangDict.h" #include "framework/async/NetworkSystem.h" #include "framework/FileSystem.h" +#include "framework/DeclEntityDef.h" #include "ui/UserInterface.h" #include "gamesys/SysCvar.h" @@ -58,6 +59,15 @@ const char *idMultiplayerGame::GlobalSoundStrings[] = { "sound/feedback/two.wav", "sound/feedback/one.wav", "sound/feedback/sudden_death.wav", +#ifdef CTF + "sound/ctf/flag_capped_yours.wav", + "sound/ctf/flag_capped_theirs.wav", + "sound/ctf/flag_return.wav", + "sound/ctf/flag_taken_yours.wav", + "sound/ctf/flag_taken_theirs.wav", + "sound/ctf/flag_dropped_yours.wav", + "sound/ctf/flag_dropped_theirs.wav" +#endif }; // handy verbose @@ -112,6 +122,20 @@ idMultiplayerGame::idMultiplayerGame() { mapList = NULL; msgmodeGui = NULL; lastGameType = GAME_SP; + +#ifdef CTF + teamFlags[0] = NULL; + teamFlags[1] = NULL; + + teamPoints[0] = 0; + teamPoints[1] = 0; + + flagMsgOn = true; + + player_blue_flag = -1; + player_red_flag = -1; +#endif + Clear(); } @@ -165,7 +189,15 @@ idMultiplayerGame::Reset void idMultiplayerGame::Reset() { Clear(); assert( !scoreBoard && !spectateGui && !guiChat && !mainGui && !mapList ); + +#ifdef CTF + // CTF uses its own scoreboard + if ( IsGametypeFlagBased() ) + scoreBoard = uiManager->FindGui( "guis/ctfscoreboard.gui", true, false, true ); + else +#endif scoreBoard = uiManager->FindGui( "guis/scoreboard.gui", true, false, true ); + spectateGui = uiManager->FindGui( "guis/spectate.gui", true, false, true ); guiChat = uiManager->FindGui( "guis/chat.gui", true, false, true ); mainGui = uiManager->FindGui( "guis/mpmain.gui", true, false, true ); @@ -205,7 +237,8 @@ void idMultiplayerGame::SpawnPlayer( int clientNum ) { if ( !gameLocal.isClient ) { idPlayer *p = static_cast< idPlayer * >( gameLocal.entities[ clientNum ] ); p->spawnedTime = gameLocal.time; - if ( gameLocal.gameType == GAME_TDM ) { + + if ( IsGametypeTeamBased() ) { /* CTF */ SwitchToTeam( clientNum, -1, p->team ); } p->tourneyRank = 0; @@ -289,9 +322,58 @@ void idMultiplayerGame::ClearGuis() { player->hud->SetStateString( va( "player%i_ready", i+1 ), "" ); scoreBoard->SetStateInt( va( "rank%i", i+1 ), 0 ); player->hud->SetStateInt( "rank_self", 0 ); + } + +#ifdef CTF + ClearHUDStatus(); +#endif +} + +#ifdef CTF +/* +================ +idMultiplayerGame::ClearHUDStatus +================ +*/ +void idMultiplayerGame::ClearHUDStatus( void ) { + int i; + + for ( i = 0; i < MAX_CLIENTS; i++ ) { + + idPlayer *player = static_cast( gameLocal.entities[ i ] ); + if ( !player || !player->hud ) { + continue; + } + + player->hud->SetStateInt( "red_flagstatus", 0 ); + player->hud->SetStateInt( "blue_flagstatus", 0 ); + if ( IsGametypeFlagBased()) + player->hud->SetStateInt( "self_team", player->team ); + else + player->hud->SetStateInt( "self_team", -1 ); // Invisible. + } + } +/* +================ +idMultiplayerGame::GetFlagPoints + +Gets number of captures in CTF game. + +0 = red team +1 = blue team +================ +*/ +int idMultiplayerGame::GetFlagPoints( int team ) +{ + assert( team <= 1 ); + + return teamPoints[ team ]; +} +#endif + /* ================ idMultiplayerGame::UpdatePlayerRanks @@ -325,7 +407,8 @@ void idMultiplayerGame::UpdatePlayerRanks() { } for ( j = 0; j < numRankedPlayers; j++ ) { bool insert = false; - if ( gameLocal.gameType == GAME_TDM ) { + + if ( IsGametypeTeamBased() ) { /* CTF */ if ( player->team != players[ j ]->team ) { if ( playerState[ i ].teamFragCount > playerState[ players[ j ]->entityNumber ].teamFragCount ) { // team scores @@ -380,6 +463,7 @@ void idMultiplayerGame::UpdateScoreboard( idUserInterface *scoreBoard, idPlayer idStr gameinfo; idStr livesinfo; idStr timeinfo; + idEntity *ent; idPlayer *p; int value; @@ -392,7 +476,7 @@ void idMultiplayerGame::UpdateScoreboard( idUserInterface *scoreBoard, idPlayer // ranked player iline++; scoreBoard->SetStateString( va( "player%i", iline ), rankedPlayers[ i ]->GetUserInfo()->GetString( "ui_name" ) ); - if ( gameLocal.gameType == GAME_TDM ) { + if ( IsGametypeTeamBased() ) { /* CTF */ value = idMath::ClampInt( MP_PLAYER_MINFRAGS, MP_PLAYER_MAXFRAGS, playerState[ rankedPlayers[ i ]->entityNumber ].fragCount ); scoreBoard->SetStateInt( va( "player%i_tdm_score", iline ), value ); value = idMath::ClampInt( MP_PLAYER_MINFRAGS, MP_PLAYER_MAXFRAGS, playerState[ rankedPlayers[ i ]->entityNumber ].teamFragCount ); @@ -404,6 +488,7 @@ void idMultiplayerGame::UpdateScoreboard( idUserInterface *scoreBoard, idPlayer scoreBoard->SetStateString( va( "player%i_tdm_tscore", iline ), "" ); scoreBoard->SetStateString( va( "player%i_tdm_score", iline ), "" ); } + value = idMath::ClampInt( 0, MP_PLAYER_MAXWINS, playerState[ rankedPlayers[ i ]->entityNumber ].wins ); scoreBoard->SetStateInt( va( "player%i_wins", iline ), value ); scoreBoard->SetStateInt( va( "player%i_ping", iline ), playerState[ rankedPlayers[ i ]->entityNumber ].ping ); @@ -492,7 +577,11 @@ void idMultiplayerGame::UpdateScoreboard( idUserInterface *scoreBoard, idPlayer // clear remaining lines (empty slots) iline++; +#ifdef _D3XP + while ( iline < MAX_CLIENTS ) { //Max players is now 8 +#else while ( iline < 5 ) { +#endif scoreBoard->SetStateString( va( "player%i", iline ), "" ); scoreBoard->SetStateString( va( "player%i_score", iline ), "" ); scoreBoard->SetStateString( va( "player%i_tdm_tscore", iline ), "" ); @@ -510,8 +599,11 @@ void idMultiplayerGame::UpdateScoreboard( idUserInterface *scoreBoard, idPlayer } else { livesinfo = va( "%s: %i", common->GetLanguageDict()->GetString( "#str_04264" ), gameLocal.serverInfo.GetInt( "si_fragLimit" ) ); } - +#ifdef CTF + } else if ( gameLocal.gameType != GAME_CTF ) { +#else } else { +#endif livesinfo = va( "%s: %i", common->GetLanguageDict()->GetString( "#str_01982" ), gameLocal.serverInfo.GetInt( "si_fragLimit" ) ); } if ( gameLocal.serverInfo.GetInt( "si_timeLimit" ) > 0 ) { @@ -526,6 +618,213 @@ void idMultiplayerGame::UpdateScoreboard( idUserInterface *scoreBoard, idPlayer scoreBoard->Redraw( gameLocal.time ); } +#ifdef CTF +/* +================ +idMultiplayerGame::UpdateCTFScoreboard +================ +*/ +void idMultiplayerGame::UpdateCTFScoreboard( idUserInterface *scoreBoard, idPlayer *player ) { + int i, j; + idStr gameinfo; + idEntity *ent; + int value; + + // The display lines + int ilines[2] = {0,0}; + + // The team strings + char redTeam[] = "red"; + char blueTeam[] = "blue"; + char *curTeam = NULL; + + /* Word "frags" */ + scoreBoard->SetStateString( "scoretext", gameLocal.gameType == GAME_LASTMAN ? common->GetLanguageDict()->GetString( "#str_04242" ) : common->GetLanguageDict()->GetString( "#str_04243" ) ); + + // Blank the flag carrier on the scoreboard. We update these in the loop below if necessary. + if ( this->player_blue_flag == -1 ) + scoreBoard->SetStateInt( "player_blue_flag", 0 ); + + if ( this->player_red_flag == -1 ) + scoreBoard->SetStateInt( "player_red_flag", 0 ); + + if ( gameState != WARMUP ) { + for ( i = 0; i < numRankedPlayers; i++ ) { + + idPlayer *player = rankedPlayers[ i ]; + assert( player ); + + if ( player->team == 0 ) + curTeam = redTeam; + else + curTeam = blueTeam; + + // Increase the appropriate iline + assert( player->team <= 1 ); + ilines[ player->team ]++; + + + // Update the flag status + if ( this->player_blue_flag == player->entityNumber ) + scoreBoard->SetStateInt( "player_blue_flag", ilines[ player->team ] ); + + if ( player->team == 1 && this->player_red_flag == player->entityNumber ) + scoreBoard->SetStateInt( "player_red_flag", ilines[ player->team ] ); + + + + /* Player Name */ + scoreBoard->SetStateString( va( "player%i_%s", ilines[ player->team ], curTeam ), player->GetUserInfo()->GetString( "ui_name" ) ); + + if ( IsGametypeTeamBased() ) { + + value = idMath::ClampInt( MP_PLAYER_MINFRAGS, MP_PLAYER_MAXFRAGS, playerState[ rankedPlayers[ i ]->entityNumber ].fragCount ); + scoreBoard->SetStateInt( va( "player%i_%s_score", ilines[ player->team ], curTeam ), value ); + + /* Team score and score, blanked */ + scoreBoard->SetStateString( va( "player%i_%s_tscore", ilines[ player->team ], curTeam ), "" ); + //scoreBoard->SetStateString( va( "player%i_%s_score", ilines[ player->team ], curTeam ), "" ); + } + + /* Wins */ + value = idMath::ClampInt( 0, MP_PLAYER_MAXWINS, playerState[ rankedPlayers[ i ]->entityNumber ].wins ); + scoreBoard->SetStateInt( va( "player%i_%s_wins", ilines[ player->team ], curTeam ), value ); + + /* Ping */ + scoreBoard->SetStateInt( va( "player%i_%s_ping", ilines[ player->team ], curTeam ), playerState[ rankedPlayers[ i ]->entityNumber ].ping ); + } + } + + for ( i = 0; i < MAX_CLIENTS; i++ ) { + + ent = gameLocal.entities[ i ]; + if ( !ent || !ent->IsType( idPlayer::Type ) ) { + continue; + } + + if ( gameState != WARMUP ) { + // check he's not covered by ranks already + for ( j = 0; j < numRankedPlayers; j++ ) { + if ( ent == rankedPlayers[ j ] ) { + break; + } + } + + if ( j != numRankedPlayers ) { + continue; + } + + } + player = static_cast< idPlayer * >( ent ); + + if ( player->spectating ) + continue; + + if ( player->team == 0 ) + curTeam = redTeam; + else + curTeam = blueTeam; + + ilines[ player->team ]++; + + + + + + if ( !playerState[ i ].ingame ) { + + /* "New Player" on player's name location */ + scoreBoard->SetStateString( va( "player%i_%s", ilines[ player->team ], curTeam ), common->GetLanguageDict()->GetString( "#str_04244" ) ); + + /* "Connecting" on player's score location */ + scoreBoard->SetStateString( va( "player%i_%s_score", ilines[ player->team ], curTeam ), common->GetLanguageDict()->GetString( "#str_04245" ) ); + + + } else { + + /* Player's name in player's name location */ + if ( !player->spectating ) + scoreBoard->SetStateString( va( "player%i_%s", ilines[ player->team ], curTeam ), gameLocal.userInfo[ i ].GetString( "ui_name" ) ); + + if ( gameState == WARMUP ) { + + if ( player->spectating ) { + + /* "Spectating" on player's score location */ + scoreBoard->SetStateString( va( "player%i_%s_score", ilines[ player->team ], curTeam ), common->GetLanguageDict()->GetString( "#str_04246" ) ); + + } else { + + /* Display "ready" in player's score location if they're ready. Display nothing if not. No room for 'not ready'. */ + scoreBoard->SetStateString( va( "player%i_%s_score", ilines[ player->team ], curTeam ), player->IsReady() ? common->GetLanguageDict()->GetString( "#str_04247" ) : "" ); + + } + } + } + + } + + // Clear remaining slots + for ( i = 0; i < 2; i++ ) + { + if ( i ) + curTeam = blueTeam; + else + curTeam = redTeam; + + for ( j = ilines[ i ]+1; j <= 8; j++ ) + { + scoreBoard->SetStateString( va( "player%i_%s", j, curTeam ), "" ); + scoreBoard->SetStateString( va( "player%i_%s_score", j, curTeam ), "" ); + scoreBoard->SetStateString( va( "player%i_%s_wins", j, curTeam ), "" ); + scoreBoard->SetStateString( va( "player%i_%s_ping", j, curTeam ), "" ); + scoreBoard->SetStateInt( "rank_self", 0 ); + } + } + + + // Don't display "CTF" -- if this scoreboard comes up, it should be apparent. + + if ( gameLocal.gameType == GAME_CTF ) { + + int captureLimit = gameLocal.serverInfo.GetInt( "si_fragLimit" ); + + if ( captureLimit > MP_CTF_MAXPOINTS ) + captureLimit = MP_CTF_MAXPOINTS; + + int timeLimit = gameLocal.serverInfo.GetInt( "si_timeLimit" ); + + /* Prints "Capture Limit: %i" at the bottom of the scoreboard, left */ + if ( captureLimit ) + scoreBoard->SetStateString( "gameinfo_red", va( common->GetLanguageDict()->GetString( "#str_11108" ), captureLimit) ); + else + scoreBoard->SetStateString( "gameinfo_red", "" ); + + /* Prints "Time Limit: %i" at the bottom of the scoreboard, right */ + if ( timeLimit ) + scoreBoard->SetStateString( "gameinfo_blue", va( common->GetLanguageDict()->GetString( "#str_11109" ), timeLimit) ); + else + scoreBoard->SetStateString( "gameinfo_blue", "" ); + } + + + + // Set team scores + scoreBoard->SetStateInt( "red_team_score", GetFlagPoints( 0 ) ); + scoreBoard->SetStateInt( "blue_team_score", GetFlagPoints( 1 ) ); + + // Handle flag status changed event + scoreBoard->HandleNamedEvent( "BlueFlagStatusChange" ); + scoreBoard->HandleNamedEvent( "RedFlagStatusChange" ); + + scoreBoard->Redraw( gameLocal.time ); + + + + +} +#endif + /* ================ idMultiplayerGame::GameTime @@ -601,7 +900,7 @@ idMultiplayerGame::EnoughClientsToPlay bool idMultiplayerGame::EnoughClientsToPlay() { int team[ 2 ]; int clients = NumActualClients( false, &team[ 0 ] ); - if ( gameLocal.gameType == GAME_TDM ) { + if ( IsGametypeTeamBased() ) { /* CTF */ return clients >= 2 && team[ 0 ] && team[ 1 ]; } else { return clients >= 2; @@ -623,7 +922,7 @@ bool idMultiplayerGame::AllPlayersReady() { return false; } - if ( gameLocal.gameType == GAME_TDM ) { + if ( IsGametypeTeamBased() ) { /* CTF */ if ( !team[ 0 ] || !team[ 1 ] ) { return false; } @@ -660,9 +959,14 @@ if there is no FragLeader(), the game is tied and we return NULL */ idPlayer *idMultiplayerGame::FragLimitHit() { int i; - int fragLimit = gameLocal.serverInfo.GetInt( "si_fragLimit" ); + int fragLimit = gameLocal.serverInfo.GetInt( "si_fragLimit" ); idPlayer *leader; +#ifdef CTF + if ( IsGametypeFlagBased() ) /* CTF */ + return NULL; +#endif + leader = FragLeader(); if ( !leader ) { return NULL; @@ -692,7 +996,7 @@ idPlayer *idMultiplayerGame::FragLimitHit() { } // there is a leader, his score may even be negative, but no one else has frags left or is !lastManOver return leader; - } else if ( gameLocal.gameType == GAME_TDM ) { + } else if ( IsGametypeTeamBased() ) { /* CTF */ if ( playerState[ leader->entityNumber ].teamFragCount >= fragLimit ) { return leader; } @@ -720,6 +1024,48 @@ bool idMultiplayerGame::TimeLimitHit() { return false; } +#ifdef CTF + +/* +================ +idMultiplayerGame::WinningTeam +return winning team +-1 if tied or no players +================ +*/ +int idMultiplayerGame::WinningTeam( void ) { + if ( teamPoints[0] > teamPoints[1] ) + return 0; + if ( teamPoints[0] < teamPoints[1] ) + return 1; + return -1; +} + +/* +================ +idMultiplayerGame::PointLimitHit +================ +*/ +bool idMultiplayerGame::PointLimitHit( void ) { + int pointLimit = gameLocal.serverInfo.GetInt( "si_fragLimit" ); + + // default to MP_CTF_MAXPOINTS if needed + if ( pointLimit > MP_CTF_MAXPOINTS ) + pointLimit = MP_CTF_MAXPOINTS; + else if ( pointLimit <= 0 ) + pointLimit = MP_CTF_MAXPOINTS; + + if ( teamPoints[0] == teamPoints[1] ) + return false; + + if ( teamPoints[0] >= pointLimit || + teamPoints[1] >= pointLimit ) + return true; + + return false; +} +#endif + /* ================ idMultiplayerGame::FragLeader @@ -752,7 +1098,7 @@ idPlayer *idMultiplayerGame::FragLeader( void ) { continue; } - int fragc = ( gameLocal.gameType == GAME_TDM ) ? playerState[i].teamFragCount : playerState[i].fragCount; + int fragc = ( IsGametypeTeamBased() ) ? playerState[i].teamFragCount : playerState[i].fragCount; /* CTF */ if ( fragc > high ) { high = fragc; } @@ -785,13 +1131,13 @@ idPlayer *idMultiplayerGame::FragLeader( void ) { leader = p; count++; p->SetLeader( true ); - if ( gameLocal.gameType == GAME_TDM ) { + if ( IsGametypeTeamBased() ) { /* CTF */ teamLead[ p->team ] = true; } } } - if ( gameLocal.gameType != GAME_TDM ) { + if ( !IsGametypeTeamBased() ) { /* CTF */ // more than one player at the highest frags if ( count > 1 ) { return NULL; @@ -821,7 +1167,7 @@ void idMultiplayerGame::UpdateWinsLosses( idPlayer *winner ) { continue; } idPlayer *player = static_cast(ent); - if ( gameLocal.gameType == GAME_TDM ) { + if ( IsGametypeTeamBased() ) { /* CTF */ if ( player == winner || ( player != winner && player->team == winner->team ) ) { playerState[ i ].wins++; PlayGlobalSound( player->entityNumber, SND_YOUWIN ); @@ -852,6 +1198,27 @@ void idMultiplayerGame::UpdateWinsLosses( idPlayer *winner ) { } } } +#ifdef CTF + else if ( IsGametypeFlagBased() ) { /* CTF */ + int winteam = WinningTeam(); + + if ( winteam != -1 ) // TODO : print a message telling it why the hell the game ended with no winning team? + for( int i = 0; i < gameLocal.numClients; i++ ) { + idEntity *ent = gameLocal.entities[ i ]; + if ( !ent || !ent->IsType( idPlayer::Type ) ) { + continue; + } + idPlayer *player = static_cast(ent); + + if ( player->team == winteam ) { + PlayGlobalSound( player->entityNumber, SND_YOUWIN ); + } else { + PlayGlobalSound( player->entityNumber, SND_YOULOSE ); + } + } + } +#endif + if ( winner ) { lastWinner = winner->entityNumber; } else { @@ -859,6 +1226,66 @@ void idMultiplayerGame::UpdateWinsLosses( idPlayer *winner ) { } } +#ifdef CTF +/* +================ +idMultiplayerGame::TeamScoreCTF +================ +*/ +void idMultiplayerGame::TeamScoreCTF( int team, int delta ) { + if ( team < 0 || team > 1 ) + return; + + teamPoints[team] += delta; + + if ( gameState == GAMEON || gameState == SUDDENDEATH ) + PrintMessageEvent( -1, MSG_SCOREUPDATE, teamPoints[0], teamPoints[1] ); +} + +/* +================ +idMultiplayerGame::PlayerScoreCTF +================ +*/ +void idMultiplayerGame::PlayerScoreCTF( int playerIdx, int delta ) { + if ( playerIdx < 0 || playerIdx >= MAX_CLIENTS ) + return; + + playerState[ playerIdx ].fragCount += delta; +} + +/* +================ +idMultiplayerGame::GetFlagCarrier +================ +*/ +int idMultiplayerGame::GetFlagCarrier( int team ) { + int iFlagCarrier = -1; + + for ( int i = 0; i < gameLocal.numClients; i++ ) { + idEntity * ent = gameLocal.entities[ i ]; + if ( !ent || !ent->IsType( idPlayer::Type ) ) { + continue; + } + + idPlayer * player = static_cast( ent ); + if ( player->team != team ) + continue; + + if ( player->carryingFlag ) { + if ( iFlagCarrier != -1 ) + gameLocal.Warning( "BUG: more than one flag carrier on %s team", team == 0 ? "red" : "blue" ); + iFlagCarrier = i; + } + } + + return iFlagCarrier; +} + + + +#endif + /* ================ idMultiplayerGame::TeamScore @@ -891,7 +1318,8 @@ void idMultiplayerGame::PlayerDeath( idPlayer *dead, idPlayer *killer, bool tele if ( killer ) { if ( gameLocal.gameType == GAME_LASTMAN ) { playerState[ dead->entityNumber ].fragCount--; - } else if ( gameLocal.gameType == GAME_TDM ) { + + } else if ( IsGametypeTeamBased() ) { /* CTF */ if ( killer == dead || killer->team == dead->team ) { // suicide or teamkill TeamScore( killer->entityNumber, killer->team, -1 ); @@ -908,7 +1336,7 @@ void idMultiplayerGame::PlayerDeath( idPlayer *dead, idPlayer *killer, bool tele } else if ( killer ) { if ( telefrag ) { PrintMessageEvent( -1, MSG_TELEFRAGGED, dead->entityNumber, killer->entityNumber ); - } else if ( gameLocal.gameType == GAME_TDM && dead->team == killer->team ) { + } else if ( IsGametypeTeamBased() && dead->team == killer->team ) { /* CTF */ PrintMessageEvent( -1, MSG_KILLEDTEAM, dead->entityNumber, killer->entityNumber ); } else { PrintMessageEvent( -1, MSG_KILLED, dead->entityNumber, killer->entityNumber ); @@ -994,6 +1422,13 @@ void idMultiplayerGame::NewState( gameState_t news, idPlayer *player ) { outMsg.WriteBits( 0, 1 ); networkSystem->ServerSendReliableMessage( -1, outMsg ); +#ifdef CTF + teamPoints[0] = 0; + teamPoints[1] = 0; + + ClearHUDStatus(); +#endif + PlayGlobalSound( -1, SND_FIGHT ); matchStartedTime = gameLocal.time; fragLimitTimeout = 0; @@ -1031,6 +1466,9 @@ void idMultiplayerGame::NewState( gameState_t news, idPlayer *player ) { break; } case GAMEREVIEW: { +#ifdef CTF + SetFlagMsg( false ); +#endif nextState = INACTIVE; // used to abort a game. cancel out any upcoming state change // set all players not ready and spectating for( i = 0; i < gameLocal.numClients; i++ ) { @@ -1042,6 +1480,9 @@ void idMultiplayerGame::NewState( gameState_t news, idPlayer *player ) { static_cast(ent)->ServerSpectate( true ); } UpdateWinsLosses( player ); +#ifdef CTF + SetFlagMsg( true ); +#endif break; } case SUDDENDEATH: { @@ -1062,6 +1503,23 @@ void idMultiplayerGame::NewState( gameState_t news, idPlayer *player ) { break; } +#ifdef CTF + case WARMUP: { + teamPoints[0] = 0; + teamPoints[1] = 0; + + if ( IsGametypeFlagBased() ) { + // reset player scores to zero, only required for CTF + for( i = 0; i < gameLocal.numClients; i++ ) { + idEntity *ent = gameLocal.entities[ i ]; + if ( !ent || !ent->IsType( idPlayer::Type ) ) { + continue; + } + playerState[ i ].fragCount = 0; + } + } + } +#endif default: break; } @@ -1213,19 +1671,23 @@ void idMultiplayerGame::ExecuteVote( void ) { break; case VOTE_TIMELIMIT: si_timeLimit.SetInteger( atoi( voteValue ) ); +#ifdef _D3XP needRestart = gameLocal.NeedRestart(); cmdSystem->BufferCommandText( CMD_EXEC_NOW, "rescanSI" ); if ( needRestart ) { cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "nextMap" ); } +#endif break; case VOTE_FRAGLIMIT: si_fragLimit.SetInteger( atoi( voteValue ) ); +#ifdef _D3XP needRestart = gameLocal.NeedRestart(); cmdSystem->BufferCommandText( CMD_EXEC_NOW, "rescanSI" ); if ( needRestart ) { cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "nextMap" ); } +#endif break; case VOTE_GAMETYPE: si_gameType.SetString( voteValue ); @@ -1240,11 +1702,13 @@ void idMultiplayerGame::ExecuteVote( void ) { break; case VOTE_SPECTATORS: si_spectators.SetBool( !si_spectators.GetBool() ); +#ifdef _D3XP needRestart = gameLocal.NeedRestart(); cmdSystem->BufferCommandText( CMD_EXEC_NOW, "rescanSI" ); if ( needRestart ) { cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "nextMap" ); } +#endif break; case VOTE_NEXTMAP: cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "serverNextMap\n" ); @@ -1367,6 +1831,20 @@ void idMultiplayerGame::Run() { cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "serverMapRestart\n" ); return; } +#ifdef CTF + // make sure flags are returned + if ( IsGametypeFlagBased() ) { + idItemTeam * flag; + flag = GetTeamFlag( 0 ); + if ( flag ) { + flag->Return(); + } + flag = GetTeamFlag( 1 ); + if ( flag ) { + flag->Return(); + } + } +#endif NewState( WARMUP ); if ( gameLocal.gameType == GAME_TOURNEY ) { CycleTourneyPlayers(); @@ -1409,6 +1887,28 @@ void idMultiplayerGame::Run() { break; } case GAMEON: { +#ifdef CTF + if ( IsGametypeFlagBased() ) { /* CTF */ + // totally different logic branch for CTF + if ( PointLimitHit() ) { + int team = WinningTeam(); + assert( team != -1 ); + + NewState( GAMEREVIEW, NULL ); + PrintMessageEvent( -1, MSG_POINTLIMIT, team ); + } else if ( TimeLimitHit() ) { + int team = WinningTeam(); + if ( EnoughClientsToPlay() && team == -1 ) { + NewState( SUDDENDEATH ); + } else { + NewState( GAMEREVIEW, NULL ); + PrintMessageEvent( -1, MSG_TIMELIMIT ); + } + } + break; + } +#endif + player = FragLimitHit(); if ( player ) { // delay between detecting frag limit and ending game. let the death anims play @@ -1441,6 +1941,18 @@ void idMultiplayerGame::Run() { break; } case SUDDENDEATH: { +#ifdef CTF + if ( IsGametypeFlagBased() ) { /* CTF */ + int team = WinningTeam(); + if ( team != -1 ) { + // TODO : implement pointLimitTimeout + NewState( GAMEREVIEW, NULL ); + PrintMessageEvent( -1, MSG_POINTLIMIT, team ); + } + break; + } +#endif + player = FragLeader(); if ( player ) { if ( !fragLimitTimeout ) { @@ -1477,11 +1989,16 @@ void idMultiplayerGame::UpdateMainGui( void ) { strReady = common->GetLanguageDict()->GetString( "#str_04247" ); } mainGui->SetStateString( "ui_ready", strReady ); - mainGui->SetStateInt( "teamon", gameLocal.gameType == GAME_TDM ? 1 : 0 ); - mainGui->SetStateInt( "teamoff", gameLocal.gameType != GAME_TDM ? 1 : 0 ); - if ( gameLocal.gameType == GAME_TDM ) { + mainGui->SetStateInt( "teamon", IsGametypeTeamBased() ? 1 : 0 ); /* CTF */ + mainGui->SetStateInt( "teamoff", (!IsGametypeTeamBased()) ? 1 : 0 ); /* CTF */ + if ( IsGametypeTeamBased() ) { idPlayer *p = gameLocal.GetClientByNum( gameLocal.localClientNum ); - mainGui->SetStateInt( "team", p->team ); + if ( p ) { + mainGui->SetStateInt( "team", p->team ); + } + else { + mainGui->SetStateInt( "team", 0 ); + } } // setup vote mainGui->SetStateInt( "voteon", ( vote != VOTE_NONE && !voted ) ? 1 : 0 ); @@ -1560,6 +2077,37 @@ idUserInterface* idMultiplayerGame::StartMenu( void ) { } mainGui->SetStateString( "kickChoices", kickList ); +#ifdef CTF + const char *gametype = gameLocal.serverInfo.GetString( "si_gameType" ); + const char *map = gameLocal.serverInfo.GetString( "si_map" ); // what if server changes this strings while user in UI? + int num = declManager->GetNumDecls( DECL_MAPDEF ); + + for ( i = 0; i < num; i++ ) { + const idDeclEntityDef *mapDef = static_cast( declManager->DeclByIndex( DECL_MAPDEF, i ) ); + + if ( mapDef && idStr::Icmp( mapDef->GetName(), map ) == 0 && mapDef->dict.GetBool( gametype ) ) { + int k = 0; + + idStr gametypeList; + + for ( j = 0; si_gameTypeArgs[ j ]; j++ ) { + if ( mapDef->dict.GetBool( si_gameTypeArgs[ j ] ) ) { + if ( gametypeList.Length() ) { + gametypeList += ";"; + } + gametypeList += va( "%s", si_gameTypeArgs[ j ] ); + gameTypeVoteMap[ k ] = si_gameTypeArgs[ j ]; + k++; + } + } + + mainGui->SetStateString( "gametypeChoices", gametypeList ); + + break; + } + } +#endif + mainGui->SetStateString( "chattext", "" ); mainGui->Activate( true, gameLocal.time ); return mainGui; @@ -1735,6 +2283,17 @@ const char* idMultiplayerGame::HandleGuiCommands( const char *_menuCommand ) { if ( voteIndex == VOTE_KICK ) { vote_clientNum = kickVoteMap[ atoi( voteValue ) ]; ClientCallVote( voteIndex, va( "%d", vote_clientNum ) ); +#ifdef CTF + } else if ( voteIndex == VOTE_GAMETYPE ) { + // send the actual gametype index, not an index in the choice list + int i; + for ( i = 0; si_gameTypeArgs[i]; i++ ) { + if ( !idStr::Icmp( gameTypeVoteMap[ atoi( voteValue ) ], si_gameTypeArgs[i] ) ) { + ClientCallVote( voteIndex, va( "%d", i ) ); + break; + } + } +#endif } else { ClientCallVote( voteIndex, voteValue ); } @@ -1978,7 +2537,7 @@ void idMultiplayerGame::UpdateHud( idPlayer *player, idUserInterface *hud ) { hud->SetStateInt( "rank_self", 0 ); if ( gameState == GAMEON ) { for ( i = 0; i < numRankedPlayers; i++ ) { - if ( gameLocal.gameType == GAME_TDM ) { + if ( IsGametypeTeamBased() ) { /* CTF */ hud->SetStateInt( va( "player%i_score", i+1 ), playerState[ rankedPlayers[ i ]->entityNumber ].teamFragCount ); } else { hud->SetStateInt( va( "player%i_score", i+1 ), playerState[ rankedPlayers[ i ]->entityNumber ].fragCount ); @@ -1990,11 +2549,23 @@ void idMultiplayerGame::UpdateHud( idPlayer *player, idUserInterface *hud ) { } } } +#ifdef _D3XP + for ( i = ( gameState == GAMEON ? numRankedPlayers : 0 ) ; i < MAX_CLIENTS; i++ ) { +#else for ( i = ( gameState == GAMEON ? numRankedPlayers : 0 ) ; i < 5; i++ ) { +#endif hud->SetStateString( va( "player%i", i+1 ), "" ); hud->SetStateString( va( "player%i_score", i+1 ), "" ); hud->SetStateInt( va( "rank%i", i+1 ), 0 ); } + +#ifdef CTF + if ( IsGametypeFlagBased() ) + hud->SetStateInt( "self_team", player->team ); + else + hud->SetStateInt( "self_team", -1 ); /* Disable */ +#endif + } /* @@ -2008,7 +2579,14 @@ void idMultiplayerGame::DrawScoreBoard( idPlayer *player ) { scoreBoard->Activate( true, gameLocal.time ); playerState[ player->entityNumber ].scoreBoardUp = true; } + +#ifdef CTF + if ( IsGametypeFlagBased() ) + UpdateCTFScoreboard( scoreBoard, player ); + else +#endif UpdateScoreboard( scoreBoard, player ); + } else { if ( playerState[ player->entityNumber ].scoreBoardUp ) { scoreBoard->Activate( false, gameLocal.time ); @@ -2094,7 +2672,12 @@ void idMultiplayerGame::DrawChat() { } } +#ifdef _D3XP +//D3XP: Adding one to frag count to allow for the negative flag in numbers greater than 255 +const int ASYNC_PLAYER_FRAG_BITS = -(idMath::BitsForInteger( MP_PLAYER_MAXFRAGS - MP_PLAYER_MINFRAGS )+1); // player can have negative frags +#else const int ASYNC_PLAYER_FRAG_BITS = -idMath::BitsForInteger( MP_PLAYER_MAXFRAGS - MP_PLAYER_MINFRAGS ); // player can have negative frags +#endif const int ASYNC_PLAYER_WINS_BITS = idMath::BitsForInteger( MP_PLAYER_MAXWINS ); const int ASYNC_PLAYER_PING_BITS = idMath::BitsForInteger( MP_PLAYER_MAXPING ); @@ -2122,6 +2705,13 @@ void idMultiplayerGame::WriteToSnapshot( idBitMsgDelta &msg ) const { msg.WriteBits( value, ASYNC_PLAYER_PING_BITS ); msg.WriteBits( playerState[i].ingame, 1 ); } + +#ifdef CTF + msg.WriteShort( teamPoints[0] ); + msg.WriteShort( teamPoints[1] ); + msg.WriteShort( player_red_flag ); + msg.WriteShort( player_blue_flag ); +#endif } /* @@ -2154,6 +2744,16 @@ void idMultiplayerGame::ReadFromSnapshot( const idBitMsgDelta &msg ) { playerState[i].ping = msg.ReadBits( ASYNC_PLAYER_PING_BITS ); playerState[i].ingame = msg.ReadBits( 1 ) != 0; } + +#ifdef CTF + teamPoints[0] = msg.ReadShort(); + teamPoints[1] = msg.ReadShort(); + + player_red_flag = msg.ReadShort(); + player_blue_flag = msg.ReadShort(); + +#endif + } /* @@ -2166,9 +2766,13 @@ void idMultiplayerGame::PlayGlobalSound( int to, snd_evt_t evt, const char *shad if ( to == -1 || to == gameLocal.localClientNum ) { if ( shader ) { - gameSoundWorld->PlayShaderDirectly( shader ); + if ( gameSoundWorld ) { + gameSoundWorld->PlayShaderDirectly( shader ); + } } else { - gameSoundWorld->PlayShaderDirectly( GlobalSoundStrings[ evt ] ); + if ( gameSoundWorld ) { + gameSoundWorld->PlayShaderDirectly( GlobalSoundStrings[ evt ] ); + } } } @@ -2193,6 +2797,26 @@ void idMultiplayerGame::PlayGlobalSound( int to, snd_evt_t evt, const char *shad } } +#ifdef CTF +/* +================ +idMultiplayerGame::PlayTeamSound +================ +*/ +void idMultiplayerGame::PlayTeamSound( int toTeam, snd_evt_t evt, const char *shader ) { + for( int i = 0; i < gameLocal.numClients; i++ ) { + idEntity *ent = gameLocal.entities[ i ]; + if ( !ent || !ent->IsType( idPlayer::Type ) ) { + continue; + } + idPlayer * player = static_cast(ent); + if ( player->team != toTeam ) + continue; + PlayGlobalSound( i, evt, shader ); + } +} +#endif + /* ================ idMultiplayerGame::PrintMessageEvent @@ -2241,7 +2865,7 @@ void idMultiplayerGame::PrintMessageEvent( int to, msg_evt_t evt, int parm1, int case MSG_FRAGLIMIT: if ( gameLocal.gameType == GAME_LASTMAN ) { AddChatLine( common->GetLanguageDict()->GetString( "#str_04283" ), gameLocal.userInfo[ parm1 ].GetString( "ui_name" ) ); - } else if ( gameLocal.gameType == GAME_TDM ) { + } else if ( IsGametypeTeamBased() ) { /* CTF */ AddChatLine( common->GetLanguageDict()->GetString( "#str_04282" ), gameLocal.userInfo[ parm1 ].GetString( "ui_team" ) ); } else { AddChatLine( common->GetLanguageDict()->GetString( "#str_04281" ), gameLocal.userInfo[ parm1 ].GetString( "ui_name" ) ); @@ -2253,6 +2877,71 @@ void idMultiplayerGame::PrintMessageEvent( int to, msg_evt_t evt, int parm1, int case MSG_HOLYSHIT: AddChatLine( common->GetLanguageDict()->GetString( "#str_06732" ) ); break; +#ifdef CTF + case MSG_POINTLIMIT: + AddChatLine( common->GetLanguageDict()->GetString( "#str_11100" ), parm1 ? common->GetLanguageDict()->GetString( "#str_11110" ) : common->GetLanguageDict()->GetString( "#str_11111" ) ); + break; + + case MSG_FLAGTAKEN : + if ( gameLocal.GetLocalPlayer() == NULL ) + break; + + if ( parm2 < 0 || parm2 >= MAX_CLIENTS ) + break; + + if ( gameLocal.GetLocalPlayer()->team != parm1 ) { + AddChatLine( common->GetLanguageDict()->GetString( "#str_11101" ), gameLocal.userInfo[ parm2 ].GetString( "ui_name" ) ); // your team + } else { + AddChatLine( common->GetLanguageDict()->GetString( "#str_11102" ), gameLocal.userInfo[ parm2 ].GetString( "ui_name" ) ); // enemy + } + break; + + case MSG_FLAGDROP : + if ( gameLocal.GetLocalPlayer() == NULL ) + break; + + if ( gameLocal.GetLocalPlayer()->team != parm1 ) { + AddChatLine( common->GetLanguageDict()->GetString( "#str_11103" ) ); // your team + } else { + AddChatLine( common->GetLanguageDict()->GetString( "#str_11104" ) ); // enemy + } + break; + + case MSG_FLAGRETURN : + if ( gameLocal.GetLocalPlayer() == NULL ) + break; + + if ( parm2 >= 0 && parm2 < MAX_CLIENTS ) { + if ( gameLocal.GetLocalPlayer()->team != parm1 ) { + AddChatLine( common->GetLanguageDict()->GetString( "#str_11120" ), gameLocal.userInfo[ parm2 ].GetString( "ui_name" ) ); // your team + } else { + AddChatLine( common->GetLanguageDict()->GetString( "#str_11121" ), gameLocal.userInfo[ parm2 ].GetString( "ui_name" ) ); // enemy + } + } else { + AddChatLine( common->GetLanguageDict()->GetString( "#str_11105" ), parm1 ? common->GetLanguageDict()->GetString( "#str_11110" ) : common->GetLanguageDict()->GetString( "#str_11111" ) ); + } + break; + + case MSG_FLAGCAPTURE : + if ( gameLocal.GetLocalPlayer() == NULL ) + break; + + if ( parm2 < 0 || parm2 >= MAX_CLIENTS ) + break; + + if ( gameLocal.GetLocalPlayer()->team != parm1 ) { + AddChatLine( common->GetLanguageDict()->GetString( "#str_11122" ), gameLocal.userInfo[ parm2 ].GetString( "ui_name" ) ); // your team + } else { + AddChatLine( common->GetLanguageDict()->GetString( "#str_11123" ), gameLocal.userInfo[ parm2 ].GetString( "ui_name" ) ); // enemy + } + +// AddChatLine( common->GetLanguageDict()->GetString( "#str_11106" ), parm1 ? common->GetLanguageDict()->GetString( "#str_11110" ) : common->GetLanguageDict()->GetString( "#str_11111" ) ); + break; + + case MSG_SCOREUPDATE: + AddChatLine( common->GetLanguageDict()->GetString( "#str_11107" ), parm1, parm2 ); + break; +#endif default: gameLocal.DPrintf( "PrintMessageEvent: unknown message type %d\n", evt ); return; @@ -2316,7 +3005,7 @@ void idMultiplayerGame::CheckRespawns( idPlayer *spectator ) { // sudden death may trigger while a player is dead, so there are still cases where we need to respawn // don't do any respawns while we are in end game delay though if ( !fragLimitTimeout ) { - if ( gameLocal.gameType == GAME_TDM || p->IsLeader() ) { + if ( IsGametypeTeamBased() || p->IsLeader() ) { /* CTF */ #ifdef _DEBUG if ( gameLocal.gameType == GAME_TOURNEY ) { assert( p->entityNumber == currentTourneyPlayer[ 0 ] || p->entityNumber == currentTourneyPlayer[ 1 ] ); @@ -2330,8 +3019,9 @@ void idMultiplayerGame::CheckRespawns( idPlayer *spectator ) { } } } else { - if ( gameLocal.gameType == GAME_DM || - gameLocal.gameType == GAME_TDM ) { + if ( gameLocal.gameType == GAME_DM || // CTF : 3wave sboily, was DM really included before? + IsGametypeTeamBased() ) + { if ( gameState == WARMUP || gameState == COUNTDOWN || gameState == GAMEON ) { p->ServerSpectate( false ); } @@ -2764,7 +3454,16 @@ void idMultiplayerGame::ServerCallVote( int clientNum, const idBitMsg &msg ) { break; case VOTE_GAMETYPE: vote_gameTypeIndex = strtol( value, NULL, 10 ); +#ifdef CTF + assert( vote_gameTypeIndex > 0 && vote_gameTypeIndex < GAME_COUNT ); + strcpy( value, si_gameTypeArgs[ vote_gameTypeIndex ] ); +#endif + +/*#ifdef CTF + assert( vote_gameTypeIndex >= 0 && vote_gameTypeIndex <= 4 ); +#else assert( vote_gameTypeIndex >= 0 && vote_gameTypeIndex <= 3 ); +#endif switch ( vote_gameTypeIndex ) { case 0: strcpy( value, "Deathmatch" ); @@ -2778,7 +3477,12 @@ void idMultiplayerGame::ServerCallVote( int clientNum, const idBitMsg &msg ) { case 3: strcpy( value, "Last Man" ); break; - } +#ifdef CTF + case 4: + strcpy( value, "CTF" ); + break; +#endif + }*/ if ( !idStr::Icmp( value, gameLocal.serverInfo.GetString( "si_gameType" ) ) ) { gameLocal.ServerSendChatMessage( clientNum, "server", common->GetLanguageDict()->GetString( "#str_04259" ) ); common->DPrintf( "client %d: already at the voted Game Type\n", clientNum ); @@ -2913,7 +3617,20 @@ void idMultiplayerGame::MapRestart( void ) { nextState = INACTIVE; nextStateSwitch = 0; } + +#ifdef CTF + teamPoints[0] = 0; + teamPoints[1] = 0; + + ClearHUDStatus(); +#endif + +#ifdef CTF + // still balance teams in CTF + if ( g_balanceTDM.GetBool() && lastGameType != GAME_TDM && lastGameType != GAME_CTF && gameLocal.mpGame.IsGametypeTeamBased() ) { +#else if ( g_balanceTDM.GetBool() && lastGameType != GAME_TDM && gameLocal.gameType == GAME_TDM ) { +#endif for ( clientNum = 0; clientNum < gameLocal.numClients; clientNum++ ) { if ( gameLocal.entities[ clientNum ] && gameLocal.entities[ clientNum ]->IsType( idPlayer::Type ) ) { if ( static_cast< idPlayer* >( gameLocal.entities[ clientNum ] )->BalanceTDM() ) { @@ -2936,7 +3653,7 @@ void idMultiplayerGame::SwitchToTeam( int clientNum, int oldteam, int newteam ) idEntity *ent; int i; - assert( gameLocal.gameType == GAME_TDM ); + assert( IsGametypeTeamBased() ); /* CTF */ assert( oldteam != newteam ); assert( !gameLocal.isClient ); @@ -2957,8 +3674,13 @@ void idMultiplayerGame::SwitchToTeam( int clientNum, int oldteam, int newteam ) if ( i == gameLocal.numClients ) { // alone on this team playerState[ clientNum ].teamFragCount = 0; + } +#ifdef CTF + if ( ( gameState == GAMEON || ( IsGametypeFlagBased() && gameState == SUDDENDEATH ) ) && oldteam != -1 ) { +#else if ( gameState == GAMEON && oldteam != -1 ) { +#endif // when changing teams during game, kill and respawn idPlayer *p = static_cast( gameLocal.entities[ clientNum ] ); if ( p->IsInTeleport() ) { @@ -2966,8 +3688,18 @@ void idMultiplayerGame::SwitchToTeam( int clientNum, int oldteam, int newteam ) p->SetPrivateCameraView( NULL ); } p->Kill( true, true ); +#ifdef CTF + if ( IsGametypeFlagBased() ) + p->DropFlag(); +#endif CheckAbortGame(); } +#ifdef CTF + else if ( IsGametypeFlagBased() && oldteam != -1 ) { + idPlayer *p = static_cast( gameLocal.entities[ clientNum ] ); + p->DropFlag(); + } +#endif } /* @@ -3411,3 +4143,246 @@ idMultiplayerGame::ClientReadWarmupTime void idMultiplayerGame::ClientReadWarmupTime( const idBitMsg &msg ) { warmupEndTime = msg.ReadInt(); } + +/* +#ifdef CTF + + Threewave note: + The below IsGametype...() functions were implemented for CTF, + but we did not #ifdef CTF them, because doing so would clutter + the codebase substantially. Please consider them part of the merged + CTF code. +*/ + +/* +================ +idMultiplayerGame::IsGametypeTeamBased +================ +*/ +bool idMultiplayerGame::IsGametypeTeamBased( void ) /* CTF */ +{ + switch ( gameLocal.gameType ) + { + case GAME_SP: + case GAME_DM: + case GAME_TOURNEY: + case GAME_LASTMAN: + return false; +#ifdef CTF + case GAME_CTF: +#endif + case GAME_TDM: + return true; + + default: + assert( !"Add support for your new gametype here." ); + } + + return false; +} + +/* +================ +idMultiplayerGame::IsGametypeFlagBased +================ +*/ +bool idMultiplayerGame::IsGametypeFlagBased( void ) { + switch ( gameLocal.gameType ) + { + case GAME_SP: + case GAME_DM: + case GAME_TOURNEY: + case GAME_LASTMAN: + case GAME_TDM: + return false; + +#ifdef CTF + case GAME_CTF: + return true; +#endif + + default: + assert( !"Add support for your new gametype here." ); + } + + return false; + +} +#ifdef CTF + +/* +================ +idMultiplayerGame::GetTeamFlag +================ +*/ +idItemTeam * idMultiplayerGame::GetTeamFlag( int team ) { + assert( team == 0 || team == 1 ); + + if ( !IsGametypeFlagBased() || ( team != 0 && team != 1 ) ) /* CTF */ + return NULL; + + // TODO : just call on map start + FindTeamFlags(); + + return teamFlags[team]; +} + +/* +================ +idMultiplayerGame::GetTeamFlag +================ +*/ +void idMultiplayerGame::FindTeamFlags( void ) { + const char * flagDefs[2] = + { + "team_CTF_redflag", + "team_CTF_blueflag" + }; + + for ( int i = 0; i < 2; i++) + { + idEntity * entity = gameLocal.FindEntityUsingDef( NULL, flagDefs[i] ); + do + { + if ( entity == NULL ) + return; + + idItemTeam * flag = static_cast(entity); + + if ( flag->team == i ) + { + teamFlags[i] = flag; + break; + } + + entity = gameLocal.FindEntityUsingDef( entity, flagDefs[i] ); + } while( entity ); + } +} + +/* +================ +idMultiplayerGame::GetFlagStatus +================ +*/ +flagStatus_t idMultiplayerGame::GetFlagStatus( int team ) { + //assert( IsGametypeFlagBased() ); + + idItemTeam *teamFlag = GetTeamFlag( team ); + //assert( teamFlag != NULL ); + + if ( teamFlag != NULL ) { + if ( teamFlag->carried == false && teamFlag->dropped == false ) + return FLAGSTATUS_INBASE; + + if ( teamFlag->carried == true ) + return FLAGSTATUS_TAKEN; + + if ( teamFlag->carried == false && teamFlag->dropped == true ) + return FLAGSTATUS_STRAY; + } + + //assert( !"Invalid flag state." ); + return FLAGSTATUS_NONE; +} + +/* +================ +idMultiplayerGame::SetFlagMsgs +================ +*/ +void idMultiplayerGame::SetFlagMsg( bool b ) { + flagMsgOn = b; +} + +/* +================ +idMultiplayerGame::IsFlagMsgOn +================ +*/ +bool idMultiplayerGame::IsFlagMsgOn( void ) { + return ( GetGameState() == WARMUP || GetGameState() == GAMEON || GetGameState() == SUDDENDEATH ) && flagMsgOn; +} + + +/* +================ +idMultiplayerGame::SetBestGametype +================ +*/ +void idMultiplayerGame::SetBestGametype( const char * map ) { + const char *gametype = gameLocal.serverInfo.GetString( "si_gameType" ); + // const char *map = gameLocal.serverInfo.GetString( "si_map" ); + int num = declManager->GetNumDecls( DECL_MAPDEF ); + int i, j; + + for ( i = 0; i < num; i++ ) { + const idDeclEntityDef *mapDef = static_cast( declManager->DeclByIndex( DECL_MAPDEF, i ) ); + + if ( mapDef && idStr::Icmp( mapDef->GetName(), map ) == 0 ) { + if ( mapDef->dict.GetBool( gametype ) ) { + // dont change gametype + return; + } + + for ( j = 1; si_gameTypeArgs[ j ]; j++ ) { + if ( mapDef->dict.GetBool( si_gameTypeArgs[ j ] ) ) { + si_gameType.SetString( si_gameTypeArgs[ j ] ); + return; + } + } + + // error out, no valid gametype + return; + } + } +} + +/* +================ +idMultiplayerGame::ReloadScoreboard +================ +*/ +void idMultiplayerGame::ReloadScoreboard() { + // CTF uses its own scoreboard + if ( IsGametypeFlagBased() ) + scoreBoard = uiManager->FindGui( "guis/ctfscoreboard.gui", true, false, true ); + else + scoreBoard = uiManager->FindGui( "guis/scoreboard.gui", true, false, true ); + + Precache(); +} + + +#endif + +#ifdef _D3XP +idStr idMultiplayerGame::GetBestGametype( const char* map, const char* gametype ) { + + int num = declManager->GetNumDecls( DECL_MAPDEF ); + int i, j; + + for ( i = 0; i < num; i++ ) { + const idDeclEntityDef *mapDef = static_cast( declManager->DeclByIndex( DECL_MAPDEF, i ) ); + + if ( mapDef && idStr::Icmp( mapDef->GetName(), map ) == 0 ) { + if ( mapDef->dict.GetBool( gametype ) ) { + // dont change gametype + return gametype; + } + + for ( j = 1; si_gameTypeArgs[ j ]; j++ ) { + if ( mapDef->dict.GetBool( si_gameTypeArgs[ j ] ) ) { + return si_gameTypeArgs[ j ]; + } + } + + // error out, no valid gametype + return "deathmatch"; + } + } + + //For testing a new map let it play any gametpye + return gametype; +} +#endif diff --git a/game/MultiplayerGame.h b/game/MultiplayerGame.h index 15fc2eb6..100f9878 100644 --- a/game/MultiplayerGame.h +++ b/game/MultiplayerGame.h @@ -45,14 +45,36 @@ If you have questions concerning this license or the applicable additional terms class idPlayer; +#ifdef CTF +class idItemTeam; +#endif + + typedef enum { - GAME_SP, + GAME_SP = 0, GAME_DM, GAME_TOURNEY, GAME_TDM, - GAME_LASTMAN + GAME_LASTMAN, +#ifdef CTF + GAME_CTF, + GAME_COUNT, +#endif } gameType_t; +#ifdef CTF + +// Used by the UI +typedef enum { + FLAGSTATUS_INBASE = 0, + FLAGSTATUS_TAKEN = 1, + FLAGSTATUS_STRAY = 2, + FLAGSTATUS_NONE = 3 +} flagStatus_t; + +#endif + + typedef enum { PLAYER_VOTE_NONE, PLAYER_VOTE_NO, @@ -75,10 +97,18 @@ const int CHAT_FADE_TIME = 400; const int FRAGLIMIT_DELAY = 2000; const int MP_PLAYER_MINFRAGS = -100; +#ifdef CTF +const int MP_PLAYER_MAXFRAGS = 400; // in CTF frags are player points +#else const int MP_PLAYER_MAXFRAGS = 100; +#endif const int MP_PLAYER_MAXWINS = 100; const int MP_PLAYER_MAXPING = 999; +#ifdef CTF +const int MP_CTF_MAXPOINTS = 25; +#endif + typedef struct mpChatLine_s { idStr line; short fade; // starts high and decreases, line is removed once reached 0 @@ -95,6 +125,15 @@ typedef enum { SND_TWO, SND_ONE, SND_SUDDENDEATH, +#ifdef CTF + SND_FLAG_CAPTURED_YOURS, + SND_FLAG_CAPTURED_THEIRS, + SND_FLAG_RETURN, + SND_FLAG_TAKEN_YOURS, + SND_FLAG_TAKEN_THEIRS, + SND_FLAG_DROPPED_YOURS, + SND_FLAG_DROPPED_THEIRS, +#endif SND_COUNT } snd_evt_t; @@ -149,6 +188,9 @@ class idMultiplayerGame { static const char *GlobalSoundStrings[ SND_COUNT ]; void PlayGlobalSound( int to, snd_evt_t evt, const char *shader = NULL ); +#ifdef CTF + void PlayTeamSound( int toTeam, snd_evt_t evt, const char *shader = NULL ); // sound that's sent only to member of toTeam team +#endif // more compact than a chat line typedef enum { @@ -167,6 +209,16 @@ class idMultiplayerGame { MSG_TELEFRAGGED, MSG_JOINTEAM, MSG_HOLYSHIT, +#ifdef CTF + MSG_POINTLIMIT, + + MSG_FLAGTAKEN, + MSG_FLAGDROP, + MSG_FLAGRETURN, + MSG_FLAGCAPTURE, + MSG_SCOREUPDATE, + +#endif MSG_COUNT } msg_evt_t; void PrintMessageEvent( int to, msg_evt_t evt, int parm1 = -1, int parm2 = -1 ); @@ -239,7 +291,17 @@ class idMultiplayerGame { void ClientReadWarmupTime( const idBitMsg &msg ); void ServerClientConnect( int clientNum ); +#ifdef CTF + void ClearHUDStatus( void ); + int GetFlagPoints( int team ); // Team points in CTF + void SetFlagMsg( bool b ); // allow flag event messages to be sent + bool IsFlagMsgOn( void ); // should flag event messages go through? + void ClearGuis( void ); + + int player_red_flag; // Ent num of red flag carrier for HUD + int player_blue_flag; // Ent num of blue flag carrier for HUD +#endif void PlayerStats( int clientNum, char *data, const int len ); private: @@ -312,14 +374,30 @@ class idMultiplayerGame { gameType_t lastGameType; // for restarts int startFragLimit; // synchronize to clients in initial state, set on -> GAMEON +#ifdef CTF + idItemTeam * teamFlags[ 2 ]; + int teamPoints[ 2 ]; + + bool flagMsgOn; + + const char * gameTypeVoteMap[ GAME_COUNT ]; +#endif + private: void UpdatePlayerRanks(); // updates the passed gui with current score information void UpdateRankColor( idUserInterface *gui, const char *mask, int i, const idVec3 &vec ); void UpdateScoreboard( idUserInterface *scoreBoard, idPlayer *player ); +#ifdef CTF + void UpdateCTFScoreboard( idUserInterface *scoreBoard, idPlayer *player ); +#endif +#ifndef CTF + // We declare this publically above so we can call it during a map restart. void ClearGuis( void ); +#endif + void DrawScoreBoard( idPlayer *player ); void UpdateHud( idPlayer *player, idUserInterface *hud ); bool Warmup( void ); @@ -328,6 +406,11 @@ class idMultiplayerGame { idPlayer * FragLimitHit( void ); idPlayer * FragLeader( void ); bool TimeLimitHit( void ); +#ifdef CTF + bool PointLimitHit( void ); + // return team with most points + int WinningTeam( void ); +#endif void NewState( gameState_t news, idPlayer *player = NULL ); void UpdateWinsLosses( idPlayer *winner ); // fill any empty tourney slots based on the current tourney ranks @@ -355,6 +438,35 @@ class idMultiplayerGame { void VoiceChat( const idCmdArgs &args, bool team ); void DumpTourneyLine( void ); void SuddenRespawn( void ); + +#ifdef CTF + void FindTeamFlags( void ); +#endif + +public: + +#ifdef CTF + idItemTeam * GetTeamFlag( int team ); + flagStatus_t GetFlagStatus( int team ); + void TeamScoreCTF( int team, int delta ); + void PlayerScoreCTF( int playerIdx, int delta ); + // returns entityNum to team flag carrier, -1 if no flag carrier + int GetFlagCarrier( int team ); + void UpdateScoreboardFlagStatus( void ); + + void SetBestGametype( const char * map ); + void ReloadScoreboard(); +#endif + +#ifdef _D3XP + idStr GetBestGametype( const char* map, const char* gametype ); +#endif + +/* #ifdef CTF ... merge the below IsGametypeFlagBased */ +bool IsGametypeFlagBased( void ); +bool IsGametypeTeamBased( void ); +/* #endif CTF */ + }; ID_INLINE idMultiplayerGame::gameState_t idMultiplayerGame::GetGameState( void ) const { diff --git a/game/Player.cpp b/game/Player.cpp index 45c9f8d5..36ae3393 100644 --- a/game/Player.cpp +++ b/game/Player.cpp @@ -43,7 +43,6 @@ If you have questions concerning this license or the applicable additional terms const int ASYNC_PLAYER_INV_AMMO_BITS = idMath::BitsForInteger( 999 ); // 9 bits to cover the range [0, 999] const int ASYNC_PLAYER_INV_CLIP_BITS = -7; // -7 bits to cover the range [-1, 60] - /* =============================================================================== @@ -90,7 +89,18 @@ const idEventDef EV_Player_StopAudioLog( "stopAudioLog" ); const idEventDef EV_Player_HideTip( "hideTip" ); const idEventDef EV_Player_LevelTrigger( "levelTrigger" ); const idEventDef EV_SpectatorTouch( "spectatorTouch", "et" ); +#ifdef _D3XP +const idEventDef EV_Player_GiveInventoryItem( "giveInventoryItem", "s" ); +const idEventDef EV_Player_RemoveInventoryItem( "removeInventoryItem", "s" ); const idEventDef EV_Player_GetIdealWeapon( "getIdealWeapon", NULL, 's' ); +const idEventDef EV_Player_SetPowerupTime( "setPowerupTime", "dd" ); +const idEventDef EV_Player_IsPowerupActive( "isPowerupActive", "d", 'd' ); +const idEventDef EV_Player_WeaponAvailable( "weaponAvailable", "s", 'd'); +const idEventDef EV_Player_StartWarp( "startWarp" ); +const idEventDef EV_Player_StopHelltime( "stopHelltime", "d" ); +const idEventDef EV_Player_ToggleBloom( "toggleBloom", "d" ); +const idEventDef EV_Player_SetBloomParms( "setBloomParms", "ff" ); +#endif CLASS_DECLARATION( idActor, idPlayer ) EVENT( EV_Player_GetButtons, idPlayer::Event_GetButtons ) @@ -110,7 +120,18 @@ CLASS_DECLARATION( idActor, idPlayer ) EVENT( EV_Player_HideTip, idPlayer::Event_HideTip ) EVENT( EV_Player_LevelTrigger, idPlayer::Event_LevelTrigger ) EVENT( EV_Gibbed, idPlayer::Event_Gibbed ) +#ifdef _D3XP + EVENT( EV_Player_GiveInventoryItem, idPlayer::Event_GiveInventoryItem ) + EVENT( EV_Player_RemoveInventoryItem, idPlayer::Event_RemoveInventoryItem ) EVENT( EV_Player_GetIdealWeapon, idPlayer::Event_GetIdealWeapon ) + EVENT( EV_Player_WeaponAvailable, idPlayer::Event_WeaponAvailable ) + EVENT( EV_Player_SetPowerupTime, idPlayer::Event_SetPowerupTime ) + EVENT( EV_Player_IsPowerupActive, idPlayer::Event_IsPowerupActive ) + EVENT( EV_Player_StartWarp, idPlayer::Event_StartWarp ) + EVENT( EV_Player_StopHelltime, idPlayer::Event_StopHelltime ) + EVENT( EV_Player_ToggleBloom, idPlayer::Event_ToggleBloom ) + EVENT( EV_Player_SetBloomParms, idPlayer::Event_SetBloomParms ) +#endif END_CLASS const int MAX_RESPAWN_TIME = 10000; @@ -120,12 +141,22 @@ const int MAX_PDA_ITEMS = 128; const int STEPUP_TIME = 200; const int MAX_INVENTORY_ITEMS = 20; + +#ifdef _D3XP +idVec3 idPlayer::colorBarTable[ 8 ] = { +#else idVec3 idPlayer::colorBarTable[ 5 ] = { +#endif idVec3( 0.25f, 0.25f, 0.25f ), idVec3( 1.00f, 0.00f, 0.00f ), idVec3( 0.00f, 0.80f, 0.10f ), idVec3( 0.20f, 0.50f, 0.80f ), idVec3( 1.00f, 0.80f, 0.10f ) +#ifdef _D3XP + ,idVec3( 0.425f, 0.484f, 0.445f ), + idVec3( 0.39f, 0.199f, 0.3f ), + idVec3( 0.484f, 0.312f, 0.074f) +#endif }; /* @@ -202,6 +233,14 @@ void idInventory::GivePowerUp( idPlayer *player, int powerup, int msec ) { case ADRENALINE: def = gameLocal.FindEntityDef( "powerup_adrenaline", false ); break; +#ifdef _D3XP + case INVULNERABILITY: + def = gameLocal.FindEntityDef( "powerup_invulnerability", false ); + break; + /*case HASTE: + def = gameLocal.FindEntityDef( "powerup_haste", false ); + break;*/ +#endif } assert( def ); msec = def->dict.GetInt( "time" ) * 1000; @@ -249,6 +288,13 @@ void idInventory::GetPersistantData( idDict &dict ) { } } +#ifdef _D3XP + //Save the clip data + for( i = 0; i < MAX_WEAPONS; i++ ) { + dict.SetInt( va("clip%i", i), clip[ i ] ); + } +#endif + // items num = 0; for( i = 0; i < items.Num(); i++ ) { @@ -346,6 +392,13 @@ void idInventory::RestoreInventory( idPlayer *owner, const idDict &dict ) { } } +#ifdef _D3XP + //Restore the clip data + for( i = 0; i < MAX_WEAPONS; i++ ) { + clip[i] = dict.GetInt(va("clip%i", i), "-1"); + } +#endif + // items num = dict.GetInt( "items" ); items.SetNum( num ); @@ -513,6 +566,14 @@ void idInventory::Save( idSaveGame *savefile ) const { savefile->WriteBool( armorPulse ); savefile->WriteInt( lastGiveTime ); + +#ifdef _D3XP + for(i = 0; i < AMMO_NUMTYPES; i++) { + savefile->WriteInt(rechargeAmmo[i].ammo); + savefile->WriteInt(rechargeAmmo[i].rechargeTime); + savefile->WriteString(rechargeAmmo[i].ammoName); + } +#endif } /* @@ -633,6 +694,17 @@ void idInventory::Restore( idRestoreGame *savefile ) { savefile->ReadBool( armorPulse ); savefile->ReadInt( lastGiveTime ); + +#ifdef _D3XP + for(i = 0; i < AMMO_NUMTYPES; i++) { + savefile->ReadInt(rechargeAmmo[i].ammo); + savefile->ReadInt(rechargeAmmo[i].rechargeTime); + + idStr name; + savefile->ReadString(name); + strcpy(rechargeAmmo[i].ammoName, name); + } +#endif } /* @@ -709,7 +781,7 @@ ammo_t idInventory::AmmoIndexForWeaponClass( const char *weapon_classname, int * idInventory::AddPickupName ============== */ -void idInventory::AddPickupName( const char *name, const char *icon ) { +void idInventory::AddPickupName( const char *name, const char *icon, idPlayer* owner ) { //_D3XP int num; num = pickupItemNames.Num(); @@ -722,6 +794,17 @@ void idInventory::AddPickupName( const char *name, const char *icon ) { info.name = name; } info.icon = icon; + +#ifdef _D3XP + if ( gameLocal.isServer ) { + idBitMsg msg; + byte msgBuf[MAX_EVENT_PARAM_SIZE]; + + msg.Init( msgBuf, sizeof( msgBuf ) ); + msg.WriteString( name, MAX_EVENT_PARAM_SIZE ); + owner->ServerSendEvent( idPlayer::EVENT_PICKUPNAME, &msg, false, -1 ); + } +#endif } } @@ -730,7 +813,7 @@ void idInventory::AddPickupName( const char *name, const char *icon ) { idInventory::Give ============== */ -bool idInventory::Give( idPlayer *owner, const idDict &spawnArgs, const char *statname, const char *value, int *idealWeapon, bool updateHud ) { +bool idInventory::Give( idPlayer * owner, const idDict & spawnArgs, const char* statname, const char* value, int* idealWeapon, bool updateHud ) { int i; const char *pos; const char *end; @@ -743,6 +826,29 @@ bool idInventory::Give( idPlayer *owner, const idDict &spawnArgs, const char *st idItemInfo info; const char *name; +#ifdef _D3XP + if ( !idStr::Icmp( statname, "ammo_bloodstone" ) ) { + i = AmmoIndexForAmmoClass( statname ); + max = MaxAmmoForAmmoClass( owner, statname ); + + if(max <= 0) { + //No Max + ammo[ i ] += atoi( value ); + } else { + //Already at or above the max so don't allow the give + if(ammo[ i ] >= max) { + ammo[ i ] = max; + return false; + } + //We were below the max so accept the give but cap it at the max + ammo[ i ] += atoi( value ); + if(ammo[ i ] > max) { + ammo[ i ] = max; + } + } + } else +#endif + if ( !idStr::Icmpn( statname, "ammo_", 5 ) ) { i = AmmoIndexForAmmoClass( statname ); max = MaxAmmoForAmmoClass( owner, statname ); @@ -759,7 +865,7 @@ bool idInventory::Give( idPlayer *owner, const idDict &spawnArgs, const char *st name = AmmoPickupNameForIndex( i ); if ( idStr::Length( name ) ) { - AddPickupName( name, "" ); + AddPickupName( name, "", owner ); //_D3XP } } } else if ( !idStr::Icmp( statname, "armor" ) ) { @@ -776,13 +882,34 @@ bool idInventory::Give( idPlayer *owner, const idDict &spawnArgs, const char *st armorPulse = true; } } else if ( idStr::FindText( statname, "inclip_" ) == 0 ) { +#ifdef _D3XP + idStr temp = statname; + i = atoi(temp.Mid(7, 2)); +#else i = WeaponIndexForAmmoClass( spawnArgs, statname + 7 ); +#endif if ( i != -1 ) { // set, don't add. not going over the clip size limit. +#ifndef _D3XP clip[ i ] = atoi( value ); +#endif } +#ifdef _D3XP + } else if ( !idStr::Icmp( statname, "invulnerability" ) ) { + owner->GivePowerUp( INVULNERABILITY, SEC2MS( atof( value ) ) ); + } else if ( !idStr::Icmp( statname, "helltime" ) ) { + owner->GivePowerUp( HELLTIME, SEC2MS( atof( value ) ) ); + } else if ( !idStr::Icmp( statname, "envirosuit" ) ) { + owner->GivePowerUp( ENVIROSUIT, SEC2MS( atof( value ) ) ); + owner->GivePowerUp( ENVIROTIME, SEC2MS( atof( value ) ) ); + } else if ( !idStr::Icmp( statname, "berserk" ) ) { + owner->GivePowerUp( BERSERK, SEC2MS( atof( value ) ) ); + //} else if ( !idStr::Icmp( statname, "haste" ) ) { + // owner->GivePowerUp( HASTE, SEC2MS( atof( value ) ) ); +#else } else if ( !idStr::Icmp( statname, "berserk" ) ) { GivePowerUp( owner, BERSERK, SEC2MS( atof( value ) ) ); +#endif } else if ( !idStr::Icmp( statname, "mega" ) ) { GivePowerUp( owner, MEGAHEALTH, SEC2MS( atof( value ) ) ); } else if ( !idStr::Icmp( statname, "weapon" ) ) { @@ -806,7 +933,12 @@ bool idInventory::Give( idPlayer *owner, const idDict &spawnArgs, const char *st } if ( i >= MAX_WEAPONS ) { +#ifdef _D3XP + gameLocal.Warning( "Unknown weapon '%s'", weaponName.c_str() ); + continue; +#else gameLocal.Error( "Unknown weapon '%s'", weaponName.c_str() ); +#endif } // cache the media for this weapon @@ -821,7 +953,11 @@ bool idInventory::Give( idPlayer *owner, const idDict &spawnArgs, const char *st if ( !gameLocal.world->spawnArgs.GetBool( "no_Weapons" ) || ( weaponName == "weapon_fists" ) || ( weaponName == "weapon_soulcube" ) ) { if ( ( weapons & ( 1 << i ) ) == 0 || gameLocal.isMultiplayer ) { +#ifdef _D3XP + if ( owner->GetUserInfo()->GetBool( "ui_autoSwitch" ) && idealWeapon && i != owner->weapon_bloodstone_active1 && i != owner->weapon_bloodstone_active2 && i != owner->weapon_bloodstone_active3) { +#else if ( owner->GetUserInfo()->GetBool( "ui_autoSwitch" ) && idealWeapon ) { +#endif // _D3XP assert( !gameLocal.isClient ); *idealWeapon = i; } @@ -896,6 +1032,7 @@ int idInventory::HasAmmo( ammo_t type, int amount ) { // return how many shots we can fire return ammo[ type ] / amount; + } /* @@ -903,11 +1040,53 @@ int idInventory::HasAmmo( ammo_t type, int amount ) { idInventory::HasAmmo =============== */ -int idInventory::HasAmmo( const char *weapon_classname ) { +int idInventory::HasAmmo( const char *weapon_classname, bool includeClip, idPlayer* owner ) { //_D3XP int ammoRequired; ammo_t ammo_i = AmmoIndexForWeaponClass( weapon_classname, &ammoRequired ); + +#ifdef _D3XP + int ammoCount = HasAmmo( ammo_i, ammoRequired ); + if(includeClip && owner) { + ammoCount += clip[owner->SlotForWeapon(weapon_classname)]; + } + return ammoCount; +#else return HasAmmo( ammo_i, ammoRequired ); +#endif + +} + +#ifdef _D3XP +/* +=============== +idInventory::HasEmptyClipCannotRefill +=============== +*/ +bool idInventory::HasEmptyClipCannotRefill(const char *weapon_classname, idPlayer* owner) { + + int clipSize = clip[owner->SlotForWeapon(weapon_classname)]; + if(clipSize) { + return false; + } + + const idDeclEntityDef *decl = gameLocal.FindEntityDef( weapon_classname, false ); + if ( !decl ) { + gameLocal.Error( "Unknown weapon in decl '%s'", weapon_classname ); + } + int minclip = decl->dict.GetInt("minclipsize"); + if(!minclip) { + return false; + } + + ammo_t ammo_i = AmmoIndexForAmmoClass( decl->dict.GetString( "ammoType" ) ); + int ammoRequired = decl->dict.GetInt( "ammoRequired" ); + int ammoCount = HasAmmo( ammo_i, ammoRequired ); + if(ammoCount < minclip) { + return true; + } + return false; } +#endif /* =============== @@ -947,6 +1126,90 @@ void idInventory::UpdateArmor( void ) { } } +#ifdef _D3XP +/* +=============== +idInventory::InitRechargeAmmo +=============== +* Loads any recharge ammo definitions from the ammo_types entity definitions. +*/ +void idInventory::InitRechargeAmmo(idPlayer *owner) { + + memset (rechargeAmmo, 0, sizeof(rechargeAmmo)); + + const idKeyValue *kv = owner->spawnArgs.MatchPrefix( "ammorecharge_" ); + while( kv ) { + idStr key = kv->GetKey(); + idStr ammoname = key.Right(key.Length()- strlen("ammorecharge_")); + int ammoType = AmmoIndexForAmmoClass(ammoname); + rechargeAmmo[ammoType].ammo = (atof(kv->GetValue().c_str())*1000); + strcpy(rechargeAmmo[ammoType].ammoName, ammoname); + kv = owner->spawnArgs.MatchPrefix( "ammorecharge_", kv ); + } +} + +/* +=============== +idInventory::RechargeAmmo +=============== +* Called once per frame to update any ammo amount for ammo types that recharge. +*/ +void idInventory::RechargeAmmo(idPlayer *owner) { + + for(int i = 0; i < AMMO_NUMTYPES; i++) { + if(rechargeAmmo[i].ammo > 0) { + if(!rechargeAmmo[i].rechargeTime) { + //Initialize the recharge timer. + rechargeAmmo[i].rechargeTime = gameLocal.time; + } + int elapsed = gameLocal.time - rechargeAmmo[i].rechargeTime; + if(elapsed >= rechargeAmmo[i].ammo) { + int intervals = (gameLocal.time - rechargeAmmo[i].rechargeTime)/rechargeAmmo[i].ammo; + ammo[i] += intervals; + + int max = MaxAmmoForAmmoClass(owner, rechargeAmmo[i].ammoName); + if(max > 0) { + if(ammo[i] > max) { + ammo[i] = max; + } + } + rechargeAmmo[i].rechargeTime += intervals*rechargeAmmo[i].ammo; + } + } + } +} + +/* +=============== +idInventory::CanGive +=============== +*/ +bool idInventory::CanGive( idPlayer *owner, const idDict &spawnArgs, const char *statname, const char *value, int *idealWeapon ) { + + if ( !idStr::Icmp( statname, "ammo_bloodstone" ) ) { + int max = MaxAmmoForAmmoClass(owner, statname); + int i = AmmoIndexForAmmoClass(statname); + + if(max <= 0) { + //No Max + return true; + } else { + //Already at or above the max so don't allow the give + if(ammo[ i ] >= max) { + ammo[ i ] = max; + return false; + } + return true; + } + } else if ( !idStr::Icmp( statname, "item" ) || !idStr::Icmp( statname, "icon" ) || !idStr::Icmp( statname, "name" ) ) { + // ignore these as they're handled elsewhere + //These items should not be considered as succesful gives because it messes up the max ammo items + return false; + } + return true; +} +#endif + /* ============== idPlayer::idPlayer @@ -977,6 +1240,11 @@ idPlayer::idPlayer() { objectiveSystem = NULL; objectiveSystemOpen = false; +#ifdef _D3XP + mountedObject = NULL; + enviroSuitLight = NULL; +#endif + heartRate = BASE_HEARTRATE; heartInfo.Init( 0, 0, 0, 0 ); lastHeartAdjust = 0; @@ -1001,6 +1269,10 @@ idPlayer::idPlayer() { forcedReady = false; wantSpectate = false; +#ifdef CTF + carryingFlag = false; +#endif + lastHitToggle = false; minRespawnTime = 0; @@ -1037,6 +1309,17 @@ idPlayer::idPlayer() { weapon_soulcube = -1; weapon_pda = -1; weapon_fists = -1; +#ifdef _D3XP + weapon_bloodstone = -1; + weapon_bloodstone_active1 = -1; + weapon_bloodstone_active2 = -1; + weapon_bloodstone_active3 = -1; + harvest_lock = false; + + hudPowerup = -1; + lastHudPowerup = -1; + hudPowerupDuration = 0; +#endif showWeaponViewModel = true; skin = NULL; @@ -1214,6 +1497,13 @@ void idPlayer::Init( void ) { weapon_soulcube = SlotForWeapon( "weapon_soulcube" ); weapon_pda = SlotForWeapon( "weapon_pda" ); weapon_fists = SlotForWeapon( "weapon_fists" ); +#ifdef _D3XP + weapon_bloodstone = SlotForWeapon( "weapon_bloodstone_passive" ); + weapon_bloodstone_active1 = SlotForWeapon( "weapon_bloodstone_active1" ); + weapon_bloodstone_active2 = SlotForWeapon( "weapon_bloodstone_active2" ); + weapon_bloodstone_active3 = SlotForWeapon( "weapon_bloodstone_active3" ); + harvest_lock = false; +#endif showWeaponViewModel = GetUserInfo()->GetBool( "ui_showGun" ); @@ -1238,6 +1528,25 @@ void idPlayer::Init( void ) { influenceMaterial = NULL; influenceSkin = NULL; +#ifdef _D3XP + mountedObject = NULL; + if( enviroSuitLight.IsValid() ) { + enviroSuitLight.GetEntity()->PostEventMS( &EV_Remove, 0 ); + } + enviroSuitLight = NULL; + healthRecharge = false; + lastHealthRechargeTime = 0; + rechargeSpeed = 500; + new_g_damageScale = 1.f; + bloomEnabled = false; + bloomSpeed = 1.f; + bloomIntensity = -0.01f; + inventory.InitRechargeAmmo(this); + hudPowerup = -1; + lastHudPowerup = -1; + hudPowerupDuration = 0; +#endif + currentLoggedAccel = 0; focusTime = 0; @@ -1323,6 +1632,9 @@ void idPlayer::Init( void ) { cursor->SetStateString( "combatcursor", "1" ); cursor->SetStateString( "itemcursor", "0" ); cursor->SetStateString( "guicursor", "0" ); +#ifdef _D3XP + cursor->SetStateString( "grabbercursor", "0" ); +#endif } if ( ( gameLocal.isMultiplayer || g_testDeath.GetBool() ) && skin ) { @@ -1408,7 +1720,8 @@ void idPlayer::Init( void ) { hud->HandleNamedEvent( "aim_clear" ); } - cvarSystem->SetCVarBool( "ui_chat", false ); + //isChatting = false; + cvarSystem->SetCVarBool("ui_chat", false); } /* @@ -1457,6 +1770,12 @@ void idPlayer::Spawn( void ) { } if ( hud ) { hud->Activate( true, gameLocal.time ); +#ifdef CTF + if ( gameLocal.mpGame.IsGametypeFlagBased() ) { + hud->SetStateInt( "red_team_score", gameLocal.mpGame.GetFlagPoints(0) ); + hud->SetStateInt( "blue_team_score", gameLocal.mpGame.GetFlagPoints(1) ); + } +#endif } // load cursor @@ -1532,12 +1851,23 @@ void idPlayer::Spawn( void ) { } if ( hud ) { // We can spawn with a full soul cube, so we need to make sure the hud knows this +#ifndef _D3XP if ( weapon_soulcube > 0 && ( inventory.weapons & ( 1 << weapon_soulcube ) ) ) { int max_souls = inventory.MaxAmmoForAmmoClass( this, "ammo_souls" ); if ( inventory.ammo[ idWeapon::GetAmmoNumForName( "ammo_souls" ) ] >= max_souls ) { hud->HandleNamedEvent( "soulCubeReady" ); } } +#endif +#ifdef _D3XP + //We can spawn with a full bloodstone, so make sure the hud knows + if ( weapon_bloodstone > 0 && ( inventory.weapons & ( 1 << weapon_bloodstone ) ) ) { + //int max_blood = inventory.MaxAmmoForAmmoClass( this, "ammo_bloodstone" ); + //if ( inventory.ammo[ idWeapon::GetAmmoNumForName( "ammo_bloodstone" ) ] >= max_blood ) { + hud->HandleNamedEvent( "bloodstoneReady" ); + //} + } +#endif hud->HandleNamedEvent( "itemPickup" ); } @@ -1580,10 +1910,18 @@ void idPlayer::Spawn( void ) { health = 25; } if ( g_useDynamicProtection.GetBool() ) { +#ifdef _D3XP + new_g_damageScale = 1.0f; +#else g_damageScale.SetFloat( 1.0f ); +#endif } } else { +#ifdef _D3XP + new_g_damageScale = 1.0f; +#else g_damageScale.SetFloat( 1.0f ); +#endif g_armorProtection.SetFloat( ( g_skill.GetInteger() < 2 ) ? 0.4f : 0.2f ); if ( g_skill.GetInteger() == 3 ) { @@ -1592,6 +1930,56 @@ void idPlayer::Spawn( void ) { } } } + +#ifdef _D3XP + //Setup the weapon toggle lists + const idKeyValue *kv; + kv = spawnArgs.MatchPrefix( "weapontoggle", NULL ); + while( kv ) { + WeaponToggle_t newToggle; + strcpy(newToggle.name, kv->GetKey().c_str()); + + idStr toggleData = kv->GetValue(); + + idLexer src; + idToken token; + src.LoadMemory(toggleData, toggleData.Length(), "toggleData"); + while(1) { + if(!src.ReadToken(&token)) { + break; + } + int index = atoi(token.c_str()); + newToggle.toggleList.Append(index); + + //Skip the , + src.ReadToken(&token); + } + weaponToggles.Set(newToggle.name, newToggle); + + kv = spawnArgs.MatchPrefix( "weapontoggle", kv ); + } +#endif + +#ifdef _D3XP + if(g_skill.GetInteger() >= 3) { + if(!WeaponAvailable("weapon_bloodstone_passive")) { + GiveInventoryItem("weapon_bloodstone_passive"); + } + if(!WeaponAvailable("weapon_bloodstone_active1")) { + GiveInventoryItem("weapon_bloodstone_active1"); + } + if(!WeaponAvailable("weapon_bloodstone_active2")) { + GiveInventoryItem("weapon_bloodstone_active2"); + } + if(!WeaponAvailable("weapon_bloodstone_active3")) { + GiveInventoryItem("weapon_bloodstone_active3"); + } + } + + bloomEnabled = false; + bloomSpeed = 1; + bloomIntensity = -0.01f; +#endif } /* @@ -1604,6 +1992,15 @@ Release any resources used by the player. idPlayer::~idPlayer() { delete weapon.GetEntity(); weapon = NULL; +#ifdef CTF + if ( enviroSuitLight.IsValid() ) { + enviroSuitLight.GetEntity()->ProcessEvent( &EV_Remove ); + } + // have to do this here, idMultiplayerGame::DisconnectClient() is too late + if ( gameLocal.isMultiplayer && gameLocal.mpGame.IsGametypeFlagBased() ) { + ReturnFlag(); + } +#endif } /* @@ -1645,6 +2042,18 @@ void idPlayer::Save( idSaveGame *savefile ) const { savefile->WriteInt( weapon_soulcube ); savefile->WriteInt( weapon_pda ); savefile->WriteInt( weapon_fists ); +#ifdef _D3XP + savefile->WriteInt( weapon_bloodstone ); + savefile->WriteInt( weapon_bloodstone_active1 ); + savefile->WriteInt( weapon_bloodstone_active2 ); + savefile->WriteInt( weapon_bloodstone_active3 ); + savefile->WriteBool( harvest_lock ); + savefile->WriteInt( hudPowerup ); + savefile->WriteInt( lastHudPowerup ); + savefile->WriteInt( hudPowerupDuration ); + + +#endif savefile->WriteInt( heartRate ); @@ -1815,6 +2224,29 @@ void idPlayer::Save( idSaveGame *savefile ) const { hud->SetStateString( "message", common->GetLanguageDict()->GetString( "#str_02916" ) ); hud->HandleNamedEvent( "Message" ); } + +#ifdef _D3XP + savefile->WriteInt(weaponToggles.Num()); + for(i = 0; i < weaponToggles.Num(); i++) { + WeaponToggle_t* weaponToggle = weaponToggles.GetIndex(i); + savefile->WriteString(weaponToggle->name); + savefile->WriteInt(weaponToggle->toggleList.Num()); + for(int j = 0; j < weaponToggle->toggleList.Num(); j++) { + savefile->WriteInt(weaponToggle->toggleList[j]); + } + } + savefile->WriteObject( mountedObject ); + enviroSuitLight.Save( savefile ); + savefile->WriteBool( healthRecharge ); + savefile->WriteInt( lastHealthRechargeTime ); + savefile->WriteInt( rechargeSpeed ); + savefile->WriteFloat( new_g_damageScale ); + + savefile->WriteBool( bloomEnabled ); + savefile->WriteFloat( bloomSpeed ); + savefile->WriteFloat( bloomIntensity ); + +#endif } /* @@ -1869,6 +2301,19 @@ void idPlayer::Restore( idRestoreGame *savefile ) { savefile->ReadInt( weapon_soulcube ); savefile->ReadInt( weapon_pda ); savefile->ReadInt( weapon_fists ); +#ifdef _D3XP + savefile->ReadInt( weapon_bloodstone ); + savefile->ReadInt( weapon_bloodstone_active1 ); + savefile->ReadInt( weapon_bloodstone_active2 ); + savefile->ReadInt( weapon_bloodstone_active3 ); + + savefile->ReadBool( harvest_lock ); + savefile->ReadInt( hudPowerup ); + savefile->ReadInt( lastHudPowerup ); + savefile->ReadInt( hudPowerupDuration ); + + +#endif savefile->ReadInt( heartRate ); @@ -2064,6 +2509,38 @@ void idPlayer::Restore( idRestoreGame *savefile ) { // create combat collision hull for exact collision detection SetCombatModel(); +#ifdef _D3XP + int weaponToggleCount; + savefile->ReadInt(weaponToggleCount); + for(i = 0; i < weaponToggleCount; i++) { + WeaponToggle_t newToggle; + memset(&newToggle, 0, sizeof(newToggle)); + + idStr name; + savefile->ReadString(name); + strcpy(newToggle.name, name.c_str()); + + int indexCount; + savefile->ReadInt(indexCount); + for(int j = 0; j < indexCount; j++) { + int temp; + savefile->ReadInt(temp); + newToggle.toggleList.Append(temp); + } + weaponToggles.Set(newToggle.name, newToggle); + } + savefile->ReadObject(reinterpret_cast(mountedObject)); + enviroSuitLight.Restore( savefile ); + savefile->ReadBool( healthRecharge ); + savefile->ReadInt( lastHealthRechargeTime ); + savefile->ReadInt( rechargeSpeed ); + savefile->ReadFloat( new_g_damageScale ); + + savefile->ReadBool( bloomEnabled ); + savefile->ReadFloat( bloomSpeed ); + savefile->ReadFloat( bloomIntensity ); +#endif + // DG: workaround for lingering messages that are shown forever after loading a savegame // (one way to get them is saving again, while the message from first save is still // shown, and then load) @@ -2082,6 +2559,16 @@ void idPlayer::PrepareForRestart( void ) { Spectate( true ); forceRespawn = true; +#ifdef CTF + // Confirm reset hud states + DropFlag(); + + if ( hud ) { + hud->SetStateInt( "red_flagstatus", 0 ); + hud->SetStateInt( "blue_flagstatus", 0 ); + } +#endif + // we will be restarting program, clear the client entities from program-related things first ShutdownThreads(); @@ -2133,6 +2620,14 @@ void idPlayer::ServerSpectate( bool spectate ) { if ( !spectate ) { SpawnFromSpawnSpot(); } +#ifdef CTF + // drop the flag if player was carrying it + if ( spectate && gameLocal.isMultiplayer && gameLocal.mpGame.IsGametypeFlagBased() && + carryingFlag ) + { + DropFlag(); + } +#endif } /* @@ -2341,7 +2836,7 @@ void idPlayer::UpdateSkinSetup( bool restart ) { if ( restart ) { team = ( idStr::Icmp( GetUserInfo()->GetString( "ui_team" ), "Blue" ) == 0 ); } - if ( gameLocal.gameType == GAME_TDM ) { + if ( gameLocal.mpGame.IsGametypeTeamBased() ) { /* CTF */ if ( team ) { baseSkinName = "skins/characters/player/marine_mp_blue"; } else { @@ -2368,6 +2863,12 @@ void idPlayer::UpdateSkinSetup( bool restart ) { colorBarIndex = 3; } else if ( baseSkinName.Find( "yellow" ) != -1 ) { colorBarIndex = 4; + } else if ( baseSkinName.Find( "grey" ) != -1 ) { + colorBarIndex = 5; + } else if ( baseSkinName.Find( "purple" ) != -1 ) { + colorBarIndex = 6; + } else if ( baseSkinName.Find( "orange" ) != -1 ) { + colorBarIndex = 7; } else { colorBarIndex = 0; } @@ -2375,6 +2876,13 @@ void idPlayer::UpdateSkinSetup( bool restart ) { if ( PowerUpActive( BERSERK ) ) { powerUpSkin = declManager->FindSkin( baseSkinName + "_berserk" ); } +#ifdef _D3XP + else if ( PowerUpActive( INVULNERABILITY ) ) { + powerUpSkin = declManager->FindSkin( baseSkinName + "_invuln" ); + //} else if ( PowerUpActive( HASTE ) ) { + // powerUpSkin = declManager->FindSkin( baseSkinName + "_haste" ); + } +#endif } /* @@ -2459,7 +2967,7 @@ bool idPlayer::UserInfoChanged( bool canModify ) { ready = newready; team = ( idStr::Icmp( userInfo->GetString( "ui_team" ), "Blue" ) == 0 ); // server maintains TDM balance - if ( canModify && gameLocal.gameType == GAME_TDM && !gameLocal.mpGame.IsInGame( entityNumber ) && g_balanceTDM.GetBool() ) { + if ( canModify && gameLocal.mpGame.IsGametypeTeamBased() && !gameLocal.mpGame.IsInGame( entityNumber ) && g_balanceTDM.GetBool() ) { /* CTF */ modifiedInfo |= BalanceTDM( ); } UpdateSkinSetup( false ); @@ -2489,22 +2997,60 @@ void idPlayer::UpdateHudAmmo( idUserInterface *_hud ) { inclip = weapon.GetEntity()->AmmoInClip(); ammoamount = weapon.GetEntity()->AmmoAvailable(); + +#ifdef _D3XP + //Hack to stop the bloodstone ammo to display when it is being activated + if ( ammoamount < 0 || !weapon.GetEntity()->IsReady() || currentWeapon == weapon_bloodstone) { +#else if ( ammoamount < 0 || !weapon.GetEntity()->IsReady() ) { +#endif // show infinite ammo _hud->SetStateString( "player_ammo", "" ); _hud->SetStateString( "player_totalammo", "" ); } else { // show remaining ammo +#ifdef _D3XP + _hud->SetStateString( "player_totalammo", va( "%i", ammoamount ) ); +#else _hud->SetStateString( "player_totalammo", va( "%i", ammoamount - inclip ) ); +#endif _hud->SetStateString( "player_ammo", weapon.GetEntity()->ClipSize() ? va( "%i", inclip ) : "--" ); // how much in the current clip _hud->SetStateString( "player_clips", weapon.GetEntity()->ClipSize() ? va( "%i", ammoamount / weapon.GetEntity()->ClipSize() ) : "--" ); + +#ifdef _D3XP + _hud->SetStateString( "player_allammo", va( "%i/%i", inclip, ammoamount ) ); +#else _hud->SetStateString( "player_allammo", va( "%i/%i", inclip, ammoamount - inclip ) ); +#endif } _hud->SetStateBool( "player_ammo_empty", ( ammoamount == 0 ) ); _hud->SetStateBool( "player_clip_empty", ( weapon.GetEntity()->ClipSize() ? inclip == 0 : false ) ); _hud->SetStateBool( "player_clip_low", ( weapon.GetEntity()->ClipSize() ? inclip <= weapon.GetEntity()->LowAmmo() : false ) ); +#ifdef _D3XP + //Hack to stop the bloodstone ammo to display when it is being activated + if(currentWeapon == weapon_bloodstone) { + _hud->SetStateBool( "player_ammo_empty", false ); + _hud->SetStateBool( "player_clip_empty", false ); + _hud->SetStateBool( "player_clip_low", false ); + } +#endif + +#ifdef _D3XP + //Let the HUD know the total amount of ammo regardless of the ammo required value + _hud->SetStateString( "player_ammo_count", va("%i", weapon.GetEntity()->AmmoCount())); +#endif + +#ifdef _D3XP + //Make sure the hud always knows how many bloodstone charges there are + int ammoRequired; + ammo_t ammo_i = inventory.AmmoIndexForWeaponClass( "weapon_bloodstone_passive", &ammoRequired ); + int bloodstoneAmmo = inventory.HasAmmo( ammo_i, ammoRequired ); + _hud->SetStateString("player_bloodstone_ammo", va("%i", bloodstoneAmmo)); + _hud->HandleNamedEvent( "bloodstoneAmmoUpdate" ); +#endif + _hud->HandleNamedEvent( "updateAmmo" ); } @@ -2531,10 +3077,15 @@ void idPlayer::UpdateHudStats( idUserInterface *_hud ) { _hud->SetStateInt( "player_stamina", staminapercentage ); _hud->SetStateInt( "player_armor", inventory.armor ); _hud->SetStateInt( "player_hr", heartRate ); + _hud->SetStateInt( "player_nostamina", ( max_stamina == 0 ) ? 1 : 0 ); _hud->HandleNamedEvent( "updateArmorHealthAir" ); +#ifdef _D3XP + _hud->HandleNamedEvent( "updatePowerup" ); +#endif + if ( healthPulse ) { _hud->HandleNamedEvent( "healthPulse" ); StartSound( "snd_healthpulse", SND_CHANNEL_ITEM, 0, false, NULL ); @@ -2564,6 +3115,24 @@ void idPlayer::UpdateHudStats( idUserInterface *_hud ) { inventory.armorPulse = false; } +#ifdef CTF + if ( gameLocal.mpGame.IsGametypeFlagBased() && _hud ) + { + _hud->SetStateInt( "red_flagstatus", gameLocal.mpGame.GetFlagStatus( 0 ) ); + _hud->SetStateInt( "blue_flagstatus", gameLocal.mpGame.GetFlagStatus( 1 ) ); + + _hud->SetStateInt( "red_team_score", gameLocal.mpGame.GetFlagPoints( 0 ) ); + _hud->SetStateInt( "blue_team_score", gameLocal.mpGame.GetFlagPoints( 1 ) ); + + _hud->HandleNamedEvent( "RedFlagStatusChange" ); + _hud->HandleNamedEvent( "BlueFlagStatusChange" ); + } + + _hud->HandleNamedEvent( "selfTeam" ); + +#endif + + UpdateHudAmmo( _hud ); } @@ -2604,6 +3173,19 @@ void idPlayer::UpdateHudWeapon( bool flashWeapon ) { hud->SetStateInt( hudWeap, weapstate ); } if ( flashWeapon ) { + +/*#ifdef _D3XP + //Clear all hud weapon varaibles for the weapon change + hud->SetStateString( "player_ammo", "" ); + hud->SetStateString( "player_totalammo", "" ); + hud->SetStateString( "player_clips", "" ); + hud->SetStateString( "player_allammo", "" ); + hud->SetStateBool( "player_ammo_empty", false ); + hud->SetStateBool( "player_clip_empty", false ); + hud->SetStateBool( "player_clip_low", false ); + hud->SetStateString( "player_ammo_count", ""); +#endif*/ + hud->HandleNamedEvent( "weaponChange" ); } } @@ -2635,6 +3217,17 @@ void idPlayer::DrawHUD( idUserInterface *_hud ) { // weapon targeting crosshair if ( !GuiActive() ) { if ( cursor && weapon.GetEntity()->ShowCrosshair() ) { + +#ifdef _D3XP + if ( weapon.GetEntity()->GetGrabberState() == 1 || weapon.GetEntity()->GetGrabberState() == 2 ) { + cursor->SetStateString( "grabbercursor", "1" ); + cursor->SetStateString( "combatcursor", "0" ); + } else { + cursor->SetStateString( "grabbercursor", "0" ); + cursor->SetStateString( "combatcursor", "1" ); + } +#endif + cursor->Redraw( gameLocal.realClientTime ); } } @@ -2646,6 +3239,12 @@ idPlayer::EnterCinematic =============== */ void idPlayer::EnterCinematic( void ) { +#ifdef _D3XP + if ( PowerUpActive( HELLTIME ) ) { + StopHelltime(); + } +#endif + Hide(); StopAudioLog(); StopSound( SND_CHANNEL_PDA, false ); @@ -2803,6 +3402,20 @@ void idPlayer::FireWeapon( void ) { } SelectWeapon( previousWeapon, false ); } +#ifdef _D3XP + if( (weapon_bloodstone >= 0) && (currentWeapon == weapon_bloodstone) && inventory.weapons & ( 1 << weapon_bloodstone_active1 ) && weapon.GetEntity()->GetStatus() == WP_READY) { + // tell it to switch to the previous weapon. Only do this once to prevent + // weapon toggling messing up the previous weapon + if(idealWeapon == weapon_bloodstone) { + if(previousWeapon == weapon_bloodstone || previousWeapon == -1) { + NextBestWeapon(); + } else { + //Since this is a toggle weapon just select itself and it will toggle to the last weapon + SelectWeapon( weapon_bloodstone, false ); + } + } + } +#endif } else { NextBestWeapon(); } @@ -2896,8 +3509,36 @@ bool idPlayer::Give( const char *statname, const char *value ) { if ( airTics > pm_airTics.GetInteger() ) { airTics = pm_airTics.GetInteger(); } +#ifdef _D3XP + } else if ( !idStr::Icmp( statname, "enviroTime" ) ) { + if ( PowerUpActive( ENVIROTIME ) ) { + inventory.powerupEndTime[ ENVIROTIME ] += (atof(value) * 1000); + } else { + GivePowerUp( ENVIROTIME, atoi(value)*1000 ); + } } else { + bool ret = inventory.Give( this, spawnArgs, statname, value, &idealWeapon, true ); + if(!idStr::Icmp( statname, "ammo_bloodstone" ) ) { + //int i = inventory.AmmoIndexForAmmoClass( statname ); + //int max = inventory.MaxAmmoForAmmoClass( this, statname ); + //if(hud && inventory.ammo[ i ] >= max) { + if(hud) { + + //Force an update of the bloodstone ammount + int ammoRequired; + ammo_t ammo_i = inventory.AmmoIndexForWeaponClass( "weapon_bloodstone_passive", &ammoRequired ); + int bloodstoneAmmo = inventory.HasAmmo( ammo_i, ammoRequired ); + hud->SetStateString("player_bloodstone_ammo", va("%i", bloodstoneAmmo)); + + hud->HandleNamedEvent("bloodstoneReady"); + //Make sure we unlock the ability to harvest + harvest_lock = false; + } + } + return ret; +#else return inventory.Give( this, spawnArgs, statname, value, &idealWeapon, true ); +#endif } return true; } @@ -2965,7 +3606,7 @@ bool idPlayer::GiveItem( idItem *item ) { // display the pickup feedback on the hud if ( gave && ( numPickup == inventory.pickupItemNames.Num() ) ) { - inventory.AddPickupName( item->spawnArgs.GetString( "inv_name" ), item->spawnArgs.GetString( "inv_icon" ) ); + inventory.AddPickupName( item->spawnArgs.GetString( "inv_name" ), item->spawnArgs.GetString( "inv_icon" ), this ); //_D3XP } return gave; @@ -3008,6 +3649,17 @@ float idPlayer::PowerUpModifier( int type ) { } else { healthPool = 0; } + +#ifdef _D3XP + /*if( PowerUpActive( HASTE ) ) { + switch( type ) { + case SPEED: { + mod = 1.7f; + break; + } + } + }*/ +#endif } return mod; @@ -3051,18 +3703,40 @@ bool idPlayer::GivePowerUp( int powerup, int time ) { switch( powerup ) { case BERSERK: { - if ( spawnArgs.GetString( "snd_berserk_third", "", &sound ) ) { - StartSoundShader( declManager->FindSound( sound ), SND_CHANNEL_DEMONIC, 0, false, NULL ); + if(gameLocal.isMultiplayer && !gameLocal.isClient) { + inventory.AddPickupName("#str_00100627", "", this); + } + + if(gameLocal.isMultiplayer) { + if ( spawnArgs.GetString( "snd_berserk_third", "", &sound ) ) { + StartSoundShader( declManager->FindSound( sound ), SND_CHANNEL_DEMONIC, 0, false, NULL ); + } } + + if ( baseSkinName.Length() ) { powerUpSkin = declManager->FindSkin( baseSkinName + "_berserk" ); } if ( !gameLocal.isClient ) { +#ifdef _D3XP + if( !gameLocal.isMultiplayer ) { + // Trying it out without the health boost (1/3/05) + // Give the player full health in single-player + // health = 100; + } else { + // Switch to fists in multiplayer + idealWeapon = 1; + } +#else idealWeapon = 0; +#endif } break; } case INVISIBILITY: { + if(gameLocal.isMultiplayer && !gameLocal.isClient) { + inventory.AddPickupName("#str_00100628", "", this); + } spawnArgs.GetString( "skin_invisibility", "", &skin ); powerUpSkin = declManager->FindSkin( skin ); // remove any decals from the model @@ -3072,16 +3746,22 @@ bool idPlayer::GivePowerUp( int powerup, int time ) { if ( weapon.GetEntity() ) { weapon.GetEntity()->UpdateSkin(); } - if ( spawnArgs.GetString( "snd_invisibility", "", &sound ) ) { +/* if ( spawnArgs.GetString( "snd_invisibility", "", &sound ) ) { StartSoundShader( declManager->FindSound( sound ), SND_CHANNEL_ANY, 0, false, NULL ); - } + } */ break; } case ADRENALINE: { +#ifdef _D3XP + inventory.AddPickupName("#str_00100799", "", this); +#endif stamina = 100.0f; break; } case MEGAHEALTH: { + if(gameLocal.isMultiplayer && !gameLocal.isClient) { + inventory.AddPickupName("#str_00100629", "", this); + } if ( spawnArgs.GetString( "snd_megahealth", "", &sound ) ) { StartSoundShader( declManager->FindSound( sound ), SND_CHANNEL_ANY, 0, false, NULL ); } @@ -3091,20 +3771,85 @@ bool idPlayer::GivePowerUp( int powerup, int time ) { } break; } - } +#ifdef _D3XP + case HELLTIME: { + if ( spawnArgs.GetString( "snd_helltime_start", "", &sound ) ) { + PostEventMS( &EV_StartSoundShader, 0, sound, SND_CHANNEL_ANY ); + } + if ( spawnArgs.GetString( "snd_helltime_loop", "", &sound ) ) { + PostEventMS( &EV_StartSoundShader, 0, sound, SND_CHANNEL_DEMONIC ); + } + break; + } + case ENVIROSUIT: { + // Turn on the envirosuit sound + if ( gameSoundWorld ) { + gameSoundWorld->SetEnviroSuit( true ); + } - if ( hud ) { - hud->HandleNamedEvent( "itemPickup" ); - } + // Put the helmet and lights on the player + idDict args; - return true; - } else { - gameLocal.Warning( "Player given power up %i\n which is out of range", powerup ); - } - return false; -} + // Light + const idDict *lightDef = gameLocal.FindEntityDefDict( "envirosuit_light", false ); + if ( lightDef ) { + idEntity *temp; + gameLocal.SpawnEntityDef( *lightDef, &temp, false ); -/* + idLight *eLight = static_cast(temp); + eLight->GetPhysics()->SetOrigin( firstPersonViewOrigin ); + eLight->UpdateVisuals(); + eLight->Present(); + + enviroSuitLight = eLight; + } + break; + } + case ENVIROTIME: { + hudPowerup = ENVIROTIME; + // The HUD display bar is fixed at 60 seconds + hudPowerupDuration = 60000; + break; + } + case INVULNERABILITY: { + if(gameLocal.isMultiplayer && !gameLocal.isClient) { + inventory.AddPickupName("#str_00100630", "", this); + } + if(gameLocal.isMultiplayer) { + /*if ( spawnArgs.GetString( "snd_invulnerable", "", &sound ) ) { + StartSoundShader( declManager->FindSound( sound ), SND_CHANNEL_DEMONIC, 0, false, NULL ); + }*/ + if ( baseSkinName.Length() ) { + powerUpSkin = declManager->FindSkin( baseSkinName + "_invuln" ); + } + } + break; + } + /*case HASTE: { + if(gameLocal.isMultiplayer && !gameLocal.isClient) { + inventory.AddPickupName("#str_00100631", "", this); + } + + if ( baseSkinName.Length() ) { + powerUpSkin = declManager->FindSkin( baseSkinName + "_haste" ); + } + break; + }*/ +#endif + } + + if ( hud ) { + hud->HandleNamedEvent( "itemPickup" ); + } + + return true; + } else { + gameLocal.Warning( "Player given power up %i\n which is out of range", powerup ); + } + return false; +} + +/* ============== idPlayer::ClearPowerup ============== @@ -3126,7 +3871,14 @@ void idPlayer::ClearPowerup( int i ) { inventory.powerupEndTime[ i ] = 0; switch( i ) { case BERSERK: { - StopSound( SND_CHANNEL_DEMONIC, false ); + if(gameLocal.isMultiplayer) { + StopSound( SND_CHANNEL_DEMONIC, false ); + } +#ifdef _D3XP + if(!gameLocal.isMultiplayer) { + StopHealthRecharge(); + } +#endif break; } case INVISIBILITY: { @@ -3135,6 +3887,38 @@ void idPlayer::ClearPowerup( int i ) { } break; } +#ifdef _D3XP + case HELLTIME: { + StopSound( SND_CHANNEL_DEMONIC, false ); + break; + } + case ENVIROSUIT: { + + hudPowerup = -1; + + // Turn off the envirosuit sound + if ( gameSoundWorld ) { + gameSoundWorld->SetEnviroSuit( false ); + } + + // Take off the helmet and lights + if ( enviroSuitLight.IsValid() ) { + enviroSuitLight.GetEntity()->PostEventMS( &EV_Remove, 0 ); + } + enviroSuitLight = NULL; + break; + } + case INVULNERABILITY: { + if(gameLocal.isMultiplayer) { + StopSound( SND_CHANNEL_DEMONIC, false ); + } + } + /*case HASTE: { + if(gameLocal.isMultiplayer) { + StopSound( SND_CHANNEL_DEMONIC, false ); + } + }*/ +#endif } } @@ -3148,6 +3932,38 @@ void idPlayer::UpdatePowerUps( void ) { if ( !gameLocal.isClient ) { for ( i = 0; i < MAX_POWERUPS; i++ ) { +#ifdef _D3XP + if ( ( inventory.powerups & ( 1 << i ) ) && inventory.powerupEndTime[i] > gameLocal.time ) { + switch( i ) { + case ENVIROSUIT: { + if ( enviroSuitLight.IsValid() ) { + idAngles lightAng = firstPersonViewAxis.ToAngles(); + idVec3 lightOrg = firstPersonViewOrigin; + const idDict *lightDef = gameLocal.FindEntityDefDict( "envirosuit_light", false ); + + idVec3 enviroOffset = lightDef->GetVector( "enviro_offset" ); + idVec3 enviroAngleOffset = lightDef->GetVector( "enviro_angle_offset" ); + + lightOrg += (enviroOffset.x * firstPersonViewAxis[0]); + lightOrg += (enviroOffset.y * firstPersonViewAxis[1]); + lightOrg += (enviroOffset.z * firstPersonViewAxis[2]); + lightAng.pitch += enviroAngleOffset.x; + lightAng.yaw += enviroAngleOffset.y; + lightAng.roll += enviroAngleOffset.z; + + enviroSuitLight.GetEntity()->GetPhysics()->SetOrigin( lightOrg ); + enviroSuitLight.GetEntity()->GetPhysics()->SetAxis( lightAng.ToMat3() ); + enviroSuitLight.GetEntity()->UpdateVisuals(); + enviroSuitLight.GetEntity()->Present(); + } + break; + } + default: { + break; + } + } + } +#endif if ( PowerUpActive( i ) && inventory.powerupEndTime[i] <= gameLocal.time ) { ClearPowerup( i ); } @@ -3178,10 +3994,17 @@ void idPlayer::UpdatePowerUps( void ) { if ( !gameLocal.inCinematic && influenceActive == 0 && g_skill.GetInteger() == 3 && gameLocal.time > nextHealthTake && !AI_DEAD && health > g_healthTakeLimit.GetInteger() ) { assert( !gameLocal.isClient ); // healthPool never be set on client + +#ifdef _D3XP + if(!PowerUpActive(INVULNERABILITY)) { +#endif health -= g_healthTakeAmt.GetInteger(); if ( health < g_healthTakeLimit.GetInteger() ) { health = g_healthTakeLimit.GetInteger(); } +#ifdef _D3XP + } +#endif nextHealthTake = gameLocal.time + g_healthTakeTime.GetInteger() * 1000; healthTake = true; } @@ -3200,6 +4023,14 @@ void idPlayer::ClearPowerUps( void ) { } } inventory.ClearPowerUps(); + +#ifdef _D3XP + if ( gameLocal.isMultiplayer ) { + if ( enviroSuitLight.IsValid() ) { + enviroSuitLight.GetEntity()->PostEventMS( &EV_Remove, 0 ); + } + } +#endif } /* @@ -3225,9 +4056,40 @@ bool idPlayer::GiveInventoryItem( idDict *item ) { hud->SetStateString( "itemicon", info.icon ); hud->HandleNamedEvent( "invPickup" ); } + +#ifdef _D3XP //Added to support powercells + if(item->GetInt("inv_powercell") && focusUI) { + //Reset the powercell count + int powerCellCount = 0; + for ( int j = 0; j < inventory.items.Num(); j++ ) { + idDict *item = inventory.items[ j ]; + if(item->GetInt("inv_powercell")) { + powerCellCount++; + } + } + focusUI->SetStateInt( "powercell_count", powerCellCount ); + } +#endif + return true; } +#ifdef _D3XP //BSM: Implementing this defined function for scripted give inventory items +/* +============== +idPlayer::GiveInventoryItem +============== +*/ +bool idPlayer::GiveInventoryItem( const char *name ) { + idDict args; + + args.Set( "classname", name ); + args.Set( "owner", this->name.c_str() ); + gameLocal.SpawnEntityDef( args); + return true; +} +#endif + /* ============== idPlayer::UpdateObjectiveInfo @@ -3424,6 +4286,10 @@ idPlayer::RemoveInventoryItem =============== */ void idPlayer::RemoveInventoryItem( const char *name ) { + //Hack for localization + if(!idStr::Icmp(name, "Pwr Cell")) { + name = common->GetLanguageDict()->GetString( "#str_00101056" ); + } idDict *item = FindInventoryItem(name); if ( item ) { RemoveInventoryItem( item ); @@ -3437,6 +4303,21 @@ idPlayer::RemoveInventoryItem */ void idPlayer::RemoveInventoryItem( idDict *item ) { inventory.items.Remove( item ); + +#ifdef _D3XP //Added to support powercells + if(item->GetInt("inv_powercell") && focusUI) { + //Reset the powercell count + int powerCellCount = 0; + for ( int j = 0; j < inventory.items.Num(); j++ ) { + idDict *item = inventory.items[ j ]; + if(item->GetInt("inv_powercell")) { + powerCellCount++; + } + } + focusUI->SetStateInt( "powercell_count", powerCellCount ); + } +#endif + delete item; } @@ -3510,12 +4391,26 @@ void idPlayer::NextBestWeapon( void ) { while ( w > 0 ) { w--; weap = spawnArgs.GetString( va( "def_weapon%d", w ) ); - if ( !weap[ 0 ] || ( ( inventory.weapons & ( 1 << w ) ) == 0 ) || ( !inventory.HasAmmo( weap ) ) ) { +#ifdef _D3XP + if ( !weap[ 0 ] || ( ( inventory.weapons & ( 1 << w ) ) == 0 ) || ( !inventory.HasAmmo( weap, true, this ) ) ) { +#else + if ( !weap[ 0 ] || ( ( inventory.weapons & ( 1 << w ) ) == 0 ) || ( !(inventory.HasAmmo( weap )) ) ) { +#endif continue; } if ( !spawnArgs.GetBool( va( "weapon%d_best", w ) ) ) { continue; } + +#ifdef _D3XP + //Some weapons will report having ammo but the clip is empty and + //will not have enough to fill the clip (i.e. Double Barrel Shotgun with 1 round left) + //We need to skip these weapons because they cannot be used + if(inventory.HasEmptyClipCannotRefill(weap, this)) { + continue; + } +#endif + break; } idealWeapon = w; @@ -3529,6 +4424,7 @@ idPlayer::NextWeapon =============== */ void idPlayer::NextWeapon( void ) { + const char *weap; int w; @@ -3561,7 +4457,12 @@ void idPlayer::NextWeapon( void ) { if ( ( inventory.weapons & ( 1 << w ) ) == 0 ) { continue; } + +#ifdef _D3XP + if ( inventory.HasAmmo( weap, true, this ) || w == weapon_bloodstone ) { +#else if ( inventory.HasAmmo( weap ) ) { +#endif break; } } @@ -3579,6 +4480,7 @@ idPlayer::PrevWeapon =============== */ void idPlayer::PrevWeapon( void ) { + const char *weap; int w; @@ -3611,7 +4513,11 @@ void idPlayer::PrevWeapon( void ) { if ( ( inventory.weapons & ( 1 << w ) ) == 0 ) { continue; } +#ifdef _D3XP + if ( inventory.HasAmmo( weap, true, this ) || w == weapon_bloodstone ) { +#else if ( inventory.HasAmmo( weap ) ) { +#endif break; } } @@ -3659,13 +4565,65 @@ void idPlayer::SelectWeapon( int num, bool force ) { return; } +#ifdef _D3XP + //Is the weapon a toggle weapon + WeaponToggle_t* weaponToggle; + if(weaponToggles.Get(va("weapontoggle%d", num), &weaponToggle)) { + + int weaponToggleIndex = 0; + + //Find the current Weapon in the list + int currentIndex = -1; + for(int i = 0; i < weaponToggle->toggleList.Num(); i++) { + if(weaponToggle->toggleList[i] == idealWeapon) { + currentIndex = i; + break; + } + } + if(currentIndex == -1) { + //Didn't find the current weapon so select the first item + weaponToggleIndex = 0; + } else { + //Roll to the next available item in the list + weaponToggleIndex = currentIndex; + weaponToggleIndex++; + if(weaponToggleIndex >= weaponToggle->toggleList.Num()) { + weaponToggleIndex = 0; + } + } + + for(int i = 0; i < weaponToggle->toggleList.Num(); i++) { + + //Is it available + if(inventory.weapons & ( 1 << weaponToggle->toggleList[weaponToggleIndex])) { + break; + } + + weaponToggleIndex++; + if(weaponToggleIndex >= weaponToggle->toggleList.Num()) { + weaponToggleIndex = 0; + } + } + + num = weaponToggle->toggleList[weaponToggleIndex]; + } +#endif + if ( force || ( inventory.weapons & ( 1 << num ) ) ) { +#ifdef _D3XP + if ( !inventory.HasAmmo( weap, true, this ) && !spawnArgs.GetBool( va( "weapon%d_allowempty", num ) ) ) { +#else if ( !inventory.HasAmmo( weap ) && !spawnArgs.GetBool( va( "weapon%d_allowempty", num ) ) ) { +#endif return; } if ( ( previousWeapon >= 0 ) && ( idealWeapon == num ) && ( spawnArgs.GetBool( va( "weapon%d_toggle", num ) ) ) ) { weap = spawnArgs.GetString( va( "def_weapon%d", previousWeapon ) ); +#ifdef _D3XP + if ( !inventory.HasAmmo( weap, true, this ) && !spawnArgs.GetBool( va( "weapon%d_allowempty", previousWeapon ) ) ) { +#else if ( !inventory.HasAmmo( weap ) && !spawnArgs.GetBool( va( "weapon%d_allowempty", previousWeapon ) ) ) { +#endif return; } idealWeapon = previousWeapon; @@ -3707,11 +4665,16 @@ void idPlayer::DropWeapon( bool died ) { return; } +#ifdef _D3XP + ammoavailable += inclip; +#endif + // expect an ammo setup that makes sense before doing any dropping // ammoavailable is -1 for infinite ammo, and weapons like chainsaw // a bad ammo config usually indicates a bad weapon state, so we should not drop // used to be an assertion check, but it still happens in edge cases - if ( ( ammoavailable != -1 ) && ( ammoavailable - inclip < 0 ) ) { + + if ( ( ammoavailable != -1 ) && ( ammoavailable < 0 ) ) { common->DPrintf( "idPlayer::DropWeapon: bad ammo setup\n" ); return; } @@ -3732,6 +4695,9 @@ void idPlayer::DropWeapon( bool died ) { item->spawnArgs.SetInt( keyval->GetKey(), ammoavailable ); idStr inclipKey = keyval->GetKey(); inclipKey.Insert( "inclip_", 4 ); +#ifdef _D3XP + inclipKey.Insert( va("%.2d", currentWeapon), 11); +#endif item->spawnArgs.SetInt( inclipKey, inclip ); } if ( !died ) { @@ -3771,7 +4737,12 @@ void idPlayer::StealWeapon( idPlayer *player ) { assert( weapon_classname ); int ammoavailable = player->weapon.GetEntity()->AmmoAvailable(); int inclip = player->weapon.GetEntity()->AmmoInClip(); - if ( ( ammoavailable != -1 ) && ( ammoavailable - inclip < 0 ) ) { + +#ifdef _D3XP + ammoavailable += inclip; +#endif + + if ( ( ammoavailable != -1 ) && ( ammoavailable < 0 ) ) { // see DropWeapon common->DPrintf( "idPlayer::StealWeapon: bad ammo setup\n" ); // we still steal the weapon, so let's use the default ammo levels @@ -3795,7 +4766,10 @@ void idPlayer::StealWeapon( idPlayer *player ) { ammo_t ammo_i = player->inventory.AmmoIndexForWeaponClass( weapon_classname, NULL ); idealWeapon = newweap; inventory.ammo[ ammo_i ] += ammoavailable; + +#ifndef _D3XP inventory.clip[ newweap ] = inclip; +#endif } /* @@ -4517,6 +5491,17 @@ void idPlayer::UpdateFocus( void ) { } } +#ifdef _D3XP //BSM: Added for powercells + int powerCellCount = 0; + for ( j = 0; j < inventory.items.Num(); j++ ) { + idDict *item = inventory.items[ j ]; + if(item->GetInt("inv_powercell")) { + powerCellCount++; + } + } + focusUI->SetStateInt( "powercell_count", powerCellCount ); +#endif + int staminapercentage = ( int )( 100.0f * stamina / pm_stamina.GetFloat() ); focusUI->SetStateString( "player_health", va("%i", health ) ); focusUI->SetStateString( "player_stamina", va( "%i%%", staminapercentage ) ); @@ -4564,11 +5549,18 @@ void idPlayer::UpdateFocus( void ) { if ( oldChar != focusCharacter && hud ) { if ( focusCharacter ) { hud->SetStateString( "npc", focusCharacter->spawnArgs.GetString( "npc_name", "Joe" ) ); +#ifdef _D3XP + //Use to code to update the npc action string to fix bug 1159 + hud->SetStateString( "npc_action", common->GetLanguageDict()->GetString( "#str_02036" )); +#endif hud->HandleNamedEvent( "showNPC" ); // HideTip(); // HideObjective(); } else { hud->SetStateString( "npc", "" ); +#ifdef _D3XP + hud->SetStateString( "npc_action", "" ); +#endif hud->HandleNamedEvent( "hideNPC" ); } } @@ -4909,6 +5901,23 @@ void idPlayer::UpdateViewAngles( void ) { // don't let the player look up more than 89 degrees while noclipping viewAngles.pitch = -89.0f; } +#ifdef _D3XP + } else if ( mountedObject ) { + int yaw_min, yaw_max, varc; + + mountedObject->GetAngleRestrictions( yaw_min, yaw_max, varc ); + + if ( yaw_min < yaw_max ) { + viewAngles.yaw = idMath::ClampFloat( yaw_min, yaw_max, viewAngles.yaw ); + } else { + if ( viewAngles.yaw < 0 ) { + viewAngles.yaw = idMath::ClampFloat( -180.f, yaw_max, viewAngles.yaw ); + } else { + viewAngles.yaw = idMath::ClampFloat( yaw_min, 180.f, viewAngles.yaw ); + } + } + viewAngles.pitch = idMath::ClampFloat( -varc, varc, viewAngles.pitch ); +#endif } else { if ( viewAngles.pitch > pm_maxviewpitch.GetFloat() ) { // don't let the player look down enough to see the shadow of his (non-existant) feet @@ -5068,6 +6077,12 @@ void idPlayer::UpdateAir( void ) { } } +#ifdef _D3XP + if ( PowerUpActive( ENVIROTIME ) ) { + newAirless = false; + } +#endif + if ( newAirless ) { if ( !airless ) { StartSound( "snd_decompress", SND_CHANNEL_ANY, SSF_GLOBAL, false, NULL ); @@ -5109,6 +6124,49 @@ void idPlayer::UpdateAir( void ) { } } +#ifdef _D3XP +/* +============== +idPlayer::UpdatePowerupHud +============== + */ +void idPlayer::UpdatePowerupHud() { + + if ( health <= 0 ) { + return; + } + + if(lastHudPowerup != hudPowerup) { + + if(hudPowerup == -1) { + //The powerup hud should be turned off + if ( hud ) { + hud->HandleNamedEvent( "noPowerup" ); + } + } else { + //Turn the pwoerup hud on + if ( hud ) { + hud->HandleNamedEvent( "Powerup" ); + } + } + + lastHudPowerup = hudPowerup; + } + + if(hudPowerup != -1) { + if(PowerUpActive(hudPowerup)) { + int remaining = inventory.powerupEndTime[ hudPowerup ] - gameLocal.time; + int filledbar = idMath::ClampInt( 0, hudPowerupDuration, remaining ); + + if ( hud ) { + hud->SetStateInt( "player_powerup", 100 * filledbar / hudPowerupDuration ); + hud->SetStateInt( "player_poweruptime", remaining / 1000 ); + } + } + } +} +#endif + /* ============== idPlayer::AddGuiPDAData @@ -5608,6 +6666,46 @@ void idPlayer::PerformImpulse( int impulse ) { } break; } +#ifdef _D3XP + case IMPULSE_25: { + if ( gameLocal.isServer && gameLocal.mpGame.IsGametypeFlagBased() && (gameLocal.serverInfo.GetInt( "si_midnight" ) == 2) ) { + if ( enviroSuitLight.IsValid() ) { + enviroSuitLight.GetEntity()->PostEventMS( &EV_Remove, 0 ); + enviroSuitLight = NULL; + } else { + const idDict *lightDef = gameLocal.FindEntityDefDict( "envirosuit_light", false ); + if ( lightDef ) { + idEntity *temp = static_cast(enviroSuitLight.GetEntity()); + idAngles lightAng = firstPersonViewAxis.ToAngles(); + idVec3 lightOrg = firstPersonViewOrigin; + + idVec3 enviroOffset = lightDef->GetVector( "enviro_offset" ); + idVec3 enviroAngleOffset = lightDef->GetVector( "enviro_angle_offset" ); + + gameLocal.SpawnEntityDef( *lightDef, &temp, false ); + enviroSuitLight = static_cast(temp); + + enviroSuitLight.GetEntity()->fl.networkSync = true; + + lightOrg += (enviroOffset.x * firstPersonViewAxis[0]); + lightOrg += (enviroOffset.y * firstPersonViewAxis[1]); + lightOrg += (enviroOffset.z * firstPersonViewAxis[2]); + lightAng.pitch += enviroAngleOffset.x; + lightAng.yaw += enviroAngleOffset.y; + lightAng.roll += enviroAngleOffset.z; + + enviroSuitLight.GetEntity()->GetPhysics()->SetOrigin( lightOrg ); + enviroSuitLight.GetEntity()->GetPhysics()->SetAxis( lightAng.ToMat3() ); + + enviroSuitLight.GetEntity()->UpdateVisuals(); + enviroSuitLight.GetEntity()->Present(); + } + } + } + break; + } +#endif // _D3XP + case IMPULSE_28: { if ( gameLocal.isClient || entityNumber == gameLocal.localClientNum ) { gameLocal.mpGame.CastVote( gameLocal.localClientNum, true ); @@ -5624,6 +6722,13 @@ void idPlayer::PerformImpulse( int impulse ) { UseVehicle(); break; } +#ifdef _D3XP + //Hack so the chainsaw will work in MP + case IMPULSE_27: { + SelectWeapon(18, false); + break; + } +#endif } } @@ -5952,6 +7057,11 @@ void idPlayer::Move( void ) { } else if ( gameLocal.inCinematic || gameLocal.GetCamera() || privateCameraView || ( influenceActive == INFLUENCE_LEVEL2 ) ) { physicsObj.SetContents( CONTENTS_BODY ); physicsObj.SetMovementType( PM_FREEZE ); +#ifdef _D3XP + } else if ( mountedObject ) { + physicsObj.SetContents( 0 ); + physicsObj.SetMovementType( PM_FREEZE ); +#endif } else { physicsObj.SetContents( CONTENTS_BODY ); physicsObj.SetMovementType( PM_NORMAL ); @@ -6067,15 +7177,23 @@ void idPlayer::UpdateHud( void ) { if ( inventory.nextItemPickup && gameLocal.time - inventory.nextItemPickup > 2000 ) { inventory.nextItemNum = 1; } - int i; - for ( i = 0; i < 5 && i < c; i++ ) { + int i, count = 5; +#ifdef _D3XP + if(gameLocal.isMultiplayer) { + count = 3; + } + + if (count < c) + c = count; +#endif + for ( i = 0; i < c; i++ ) { //_D3XP hud->SetStateString( va( "itemtext%i", inventory.nextItemNum ), inventory.pickupItemNames[0].name ); hud->SetStateString( va( "itemicon%i", inventory.nextItemNum ), inventory.pickupItemNames[0].icon ); hud->HandleNamedEvent( va( "itemPickup%i", inventory.nextItemNum++ ) ); inventory.pickupItemNames.RemoveIndex( 0 ); if (inventory.nextItemNum == 1 ) { inventory.onePickupTime = gameLocal.time; - } else if ( inventory.nextItemNum > 5 ) { + } else if ( inventory.nextItemNum > count ) { //_D3XP inventory.nextItemNum = 1; inventory.nextItemPickup = inventory.onePickupTime + 2000; } else { @@ -6086,7 +7204,7 @@ void idPlayer::UpdateHud( void ) { } if ( gameLocal.realClientTime == lastMPAimTime ) { - if ( MPAim != -1 && gameLocal.gameType == GAME_TDM + if ( MPAim != -1 && gameLocal.mpGame.IsGametypeTeamBased() /* CTF */ && gameLocal.entities[ MPAim ] && gameLocal.entities[ MPAim ]->IsType( idPlayer::Type ) && static_cast< idPlayer * >( gameLocal.entities[ MPAim ] )->team == team ) { aimed = static_cast< idPlayer * >( gameLocal.entities[ MPAim ] ); @@ -6216,6 +7334,14 @@ void idPlayer::Think( void ) { oldFlags = usercmd.flags; } +#ifdef _D3XP + if ( mountedObject ) { + usercmd.forwardmove = 0; + usercmd.rightmove = 0; + usercmd.upmove = 0; + } +#endif + if ( objectiveSystemOpen || gameLocal.inCinematic || influenceActive ) { if ( objectiveSystemOpen && AI_PAIN ) { TogglePDA(); @@ -6286,7 +7412,11 @@ void idPlayer::Think( void ) { // not done on clients for various reasons. don't do it on server and save the sound channel for other things if ( !gameLocal.isMultiplayer ) { SetCurrentHeartRate(); +#ifdef _D3XP + float scale = new_g_damageScale; +#else float scale = g_damageScale.GetFloat(); +#endif if ( g_useDynamicProtection.GetBool() && scale < 1.0f && gameLocal.time - lastDmgTime > 500 ) { if ( scale < 1.0f ) { scale += 0.05f; @@ -6294,7 +7424,11 @@ void idPlayer::Think( void ) { if ( scale > 1.0f ) { scale = 1.0f; } +#ifdef _D3XP + new_g_damageScale = scale; +#else g_damageScale.SetFloat( scale ); +#endif } } @@ -6334,6 +7468,10 @@ void idPlayer::Think( void ) { UpdateAir(); +#ifdef _D3XP + UpdatePowerupHud(); +#endif + UpdateHud(); UpdatePowerUps(); @@ -6342,6 +7480,29 @@ void idPlayer::Think( void ) { if ( gameLocal.isMultiplayer ) { DrawPlayerIcons(); + +#ifdef _D3XP + if ( enviroSuitLight.IsValid() ) { + idAngles lightAng = firstPersonViewAxis.ToAngles(); + idVec3 lightOrg = firstPersonViewOrigin; + const idDict *lightDef = gameLocal.FindEntityDefDict( "envirosuit_light", false ); + + idVec3 enviroOffset = lightDef->GetVector( "enviro_offset" ); + idVec3 enviroAngleOffset = lightDef->GetVector( "enviro_angle_offset" ); + + lightOrg += (enviroOffset.x * firstPersonViewAxis[0]); + lightOrg += (enviroOffset.y * firstPersonViewAxis[1]); + lightOrg += (enviroOffset.z * firstPersonViewAxis[2]); + lightAng.pitch += enviroAngleOffset.x; + lightAng.yaw += enviroAngleOffset.y; + lightAng.roll += enviroAngleOffset.z; + + enviroSuitLight.GetEntity()->GetPhysics()->SetOrigin( lightOrg ); + enviroSuitLight.GetEntity()->GetPhysics()->SetAxis( lightAng.ToMat3() ); + enviroSuitLight.GetEntity()->UpdateVisuals(); + enviroSuitLight.GetEntity()->Present(); + } +#endif } if ( head.GetEntity() ) { @@ -6401,7 +7562,166 @@ void idPlayer::Think( void ) { } gameLocal.Printf( "%d: enemies\n", num ); } + +#ifdef _D3XP + inventory.RechargeAmmo(this); + + if(healthRecharge) { + int elapsed = gameLocal.time - lastHealthRechargeTime; + if(elapsed >= rechargeSpeed) { + int intervals = (gameLocal.time - lastHealthRechargeTime)/rechargeSpeed; + Give("health", va("%d", intervals)); + lastHealthRechargeTime += intervals*rechargeSpeed; + } + } + + // determine if portal sky is in pvs + gameLocal.portalSkyActive = gameLocal.pvs.CheckAreasForPortalSky( gameLocal.GetPlayerPVS(), GetPhysics()->GetOrigin() ); +#endif +} + +#ifdef _D3XP +/* +================= +idPlayer::StartHealthRecharge +================= +*/ +void idPlayer::StartHealthRecharge(int speed) { + lastHealthRechargeTime = gameLocal.time; + healthRecharge = true; + rechargeSpeed = speed; +} + +/* +================= +idPlayer::StopHealthRecharge +================= +*/ +void idPlayer::StopHealthRecharge() { + healthRecharge = false; +} + +/* +================= +idPlayer::GetCurrentWeapon +================= +*/ +idStr idPlayer::GetCurrentWeapon() { + const char *weapon; + + if ( currentWeapon >= 0 ) { + weapon = spawnArgs.GetString( va( "def_weapon%d", currentWeapon ) ); + return weapon; + } else { + return ""; + } +} + +/* +================= +idPlayer::CanGive +================= +*/ +bool idPlayer::CanGive( const char *statname, const char *value ) { + if ( AI_DEAD ) { + return false; + } + + if ( !idStr::Icmp( statname, "health" ) ) { + if ( health >= inventory.maxHealth ) { + return false; + } + return true; + } else if ( !idStr::Icmp( statname, "stamina" ) ) { + if ( stamina >= 100 ) { + return false; + } + return true; + + } else if ( !idStr::Icmp( statname, "heartRate" ) ) { + return true; + + } else if ( !idStr::Icmp( statname, "air" ) ) { + if ( airTics >= pm_airTics.GetInteger() ) { + return false; + } + return true; + } + + return inventory.CanGive( this, spawnArgs, statname, value, &idealWeapon ); +} + +/* +================= +idPlayer::StopHelltime + +provides a quick non-ramping way of stopping helltime +================= +*/ +void idPlayer::StopHelltime( bool quick ) { + if ( !PowerUpActive( HELLTIME ) ) { + return; + } + + // take away the powerups + if ( PowerUpActive( INVULNERABILITY ) ) { + ClearPowerup( INVULNERABILITY ); + } + + if ( PowerUpActive( BERSERK ) ) { + ClearPowerup( BERSERK ); + } + + if ( PowerUpActive( HELLTIME ) ) { + ClearPowerup( HELLTIME ); + } + + // stop the looping sound + StopSound( SND_CHANNEL_DEMONIC, false ); + + // reset the game vars + if ( quick ) { + gameLocal.QuickSlowmoReset(); + } +} + +/* +================= +idPlayer::Event_ToggleBloom +================= +*/ +void idPlayer::Event_ToggleBloom( int on ) { + if ( on ) { + bloomEnabled = true; + } + else { + bloomEnabled = false; + } +} + +/* +================= +idPlayer::Event_SetBloomParms +================= +*/ +void idPlayer::Event_SetBloomParms( float speed, float intensity ) { + bloomSpeed = speed; + bloomIntensity = intensity; +} + +/* +================= +idPlayer::PlayHelltimeStopSound +================= +*/ +void idPlayer::PlayHelltimeStopSound() { + const char* sound; + + if ( spawnArgs.GetString( "snd_helltime_stop", "", &sound ) ) { + PostEventMS( &EV_StartSoundShader, 0, sound, SND_CHANNEL_ANY ); + } } +#endif /* ================= @@ -6523,6 +7843,15 @@ void idPlayer::Killed( idEntity *inflictor, idEntity *attacker, int damage, cons // drop the weapon as an item DropWeapon( true ); +#ifdef CTF + // drop the flag if player was carrying it + if ( gameLocal.isMultiplayer && gameLocal.mpGame.IsGametypeFlagBased() && + carryingFlag ) + { + DropFlag(); + } +#endif + if ( !g_testDeath.GetBool() ) { LookAtKiller( inflictor, attacker ); } @@ -6581,8 +7910,21 @@ callback function for when another entity received damage from this entity. dam void idPlayer::DamageFeedback( idEntity *victim, idEntity *inflictor, int &damage ) { assert( !gameLocal.isClient ); damage *= PowerUpModifier( BERSERK ); - if ( damage && ( victim != this ) && victim->IsType( idActor::Type ) ) { - SetLastHitTime( gameLocal.time ); + if ( damage && ( victim != this ) && ( victim->IsType( idActor::Type ) || victim->IsType( idDamagable::Type ) ) ) { + + idPlayer *victimPlayer = NULL; + + /* No damage feedback sound for hitting friendlies in CTF */ + if ( victim->IsType( idPlayer::Type ) ) { + victimPlayer = static_cast(victim); + } + + if ( gameLocal.mpGame.IsGametypeFlagBased() && victimPlayer && this->team == victimPlayer->team ) { + /* Do nothing ... */ + } + else { + SetLastHitTime( gameLocal.time ); + } } } @@ -6643,6 +7985,12 @@ void idPlayer::CalcDamagePoints( idEntity *inflictor, idEntity *attacker, const if ( godmode ) { damage = 0; } +#ifdef _D3XP + //Invulnerability is just like god mode + if( PowerUpActive( INVULNERABILITY ) ) { + damage = 0; + } +#endif } // inform the attacker that they hit someone @@ -6672,7 +8020,7 @@ void idPlayer::CalcDamagePoints( idEntity *inflictor, idEntity *attacker, const } // check for team damage - if ( gameLocal.gameType == GAME_TDM + if ( gameLocal.mpGame.IsGametypeTeamBased() /* CTF */ && !gameLocal.serverInfo.GetBool( "si_teamDamage" ) && !damageDef->GetBool( "noTeam" ) && player @@ -6710,6 +8058,9 @@ void idPlayer::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &di idVec3 damage_from; idVec3 localDamageVector; float attackerPushScale; +#ifdef _D3XP + SetTimeState ts( timeGroup ); +#endif // damage is only processed on server if ( gameLocal.isClient ) { @@ -6728,9 +8079,11 @@ void idPlayer::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &di } if ( attacker->IsType( idAI::Type ) ) { +#ifndef _D3XP if ( PowerUpActive( BERSERK ) ) { return; } +#endif // don't take damage from monsters during influences if ( influenceActive != 0 ) { return; @@ -6752,6 +8105,19 @@ void idPlayer::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &di // determine knockback damageDef->dict.GetInt( "knockback", "20", knockback ); +/*#ifdef _D3XP + idPlayer *player = attacker->IsType( idPlayer::Type ) ? static_cast(attacker) : NULL; + + if ( gameLocal.mpGame.IsGametypeTeamBased() + && !gameLocal.serverInfo.GetBool( "si_teamDamage" ) + && !damageDef->dict.GetBool( "noTeam" ) + && player + && player != this // you get self damage no matter what + && player->team == team ) { + knockback = 0; + } +#endif*/ + if ( knockback != 0 && !fl.noknockback ) { if ( attacker == this ) { damageDef->dict.GetFloat( "attackerPushScale", "0", attackerPushScale ); @@ -6768,6 +8134,7 @@ void idPlayer::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &di physicsObj.SetKnockBack( idMath::ClampInt( 50, 200, knockback * 2 ) ); } + // give feedback on the player view and audibly when armor is helping if ( armorSave ) { inventory.armor -= armorSave; @@ -6808,11 +8175,19 @@ void idPlayer::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &di if ( damage > 0 ) { if ( !gameLocal.isMultiplayer ) { +#ifdef _D3XP + float scale = new_g_damageScale; +#else float scale = g_damageScale.GetFloat(); +#endif if ( g_useDynamicProtection.GetBool() && g_skill.GetInteger() < 2 ) { if ( gameLocal.time > lastDmgTime + 500 && scale > 0.25f ) { scale -= 0.05f; +#ifdef _D3XP + new_g_damageScale = scale; +#else g_damageScale.SetFloat( scale ); +#endif } } @@ -6909,6 +8284,12 @@ void idPlayer::Teleport( const idVec3 &origin, const idAngles &angles, idEntity gameLocal.KillBox( this, true ); } } + +#ifdef _D3XP + if ( PowerUpActive( HELLTIME ) ) { + StopHelltime(); + } +#endif } /* @@ -7319,7 +8700,10 @@ void idPlayer::CalculateRenderView( void ) { renderView->shaderParms[ i ] = gameLocal.globalShaderParms[ i ]; } renderView->globalMaterial = gameLocal.GetGlobalMaterial(); - renderView->time = gameLocal.time; + +#ifdef _D3XP + renderView->time = gameLocal.slow.time; +#endif // calculate size of 3D view renderView->x = 0; @@ -7379,6 +8763,9 @@ idPlayer::AddAIKill ============= */ void idPlayer::AddAIKill( void ) { + +#ifndef _D3XP + int max_souls; int ammo_souls; @@ -7388,6 +8775,7 @@ void idPlayer::AddAIKill( void ) { assert( hud ); + ammo_souls = idWeapon::GetAmmoNumForName( "ammo_souls" ); max_souls = inventory.MaxAmmoForAmmoClass( this, "ammo_souls" ); if ( inventory.ammo[ ammo_souls ] < max_souls ) { @@ -7397,6 +8785,7 @@ void idPlayer::AddAIKill( void ) { StartSound( "snd_soulcube_ready", SND_CHANNEL_ANY, 0, false, NULL ); } } +#endif } /* @@ -7624,6 +9013,110 @@ void idPlayer::Event_DisableWeapon( void ) { } } +#ifdef _D3XP +/* +================== +idPlayer::Event_GiveInventoryItem +================== +*/ +void idPlayer::Event_GiveInventoryItem( const char* name ) { + GiveInventoryItem(name); +} + +/* +================== +idPlayer::Event_RemoveInventoryItem +================== +*/ +void idPlayer::Event_RemoveInventoryItem( const char* name ) { + RemoveInventoryItem(name); +} + +/* +================== +idPlayer::Event_GetIdealWeapon +================== +*/ +void idPlayer::Event_GetIdealWeapon( void ) { + const char *weapon; + + if ( idealWeapon >= 0 ) { + weapon = spawnArgs.GetString( va( "def_weapon%d", idealWeapon ) ); + idThread::ReturnString( weapon ); + } else { + idThread::ReturnString( "" ); + } +} + +/* +================== +idPlayer::Event_SetPowerupTime +================== +*/ +void idPlayer::Event_SetPowerupTime( int powerup, int time ) { + if ( time > 0 ) { + GivePowerUp( powerup, time ); + } else { + ClearPowerup( powerup ); + } +} + +/* +================== +idPlayer::Event_IsPowerupActive +================== +*/ +void idPlayer::Event_IsPowerupActive( int powerup ) { + idThread::ReturnInt(this->PowerUpActive(powerup) ? 1 : 0); +} + +/* +================== +idPlayer::Event_StartWarp +================== +*/ +void idPlayer::Event_StartWarp() { + playerView.AddWarp( idVec3( 0, 0, 0 ), SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, 100, 1000 ); +} + +/* +================== +idPlayer::Event_StopHelltime +================== +*/ +void idPlayer::Event_StopHelltime( int mode ) { + if ( mode == 1 ) { + StopHelltime( true ); + } + else { + StopHelltime( false ); + } +} + +/* +================== +idPlayer::Event_WeaponAvailable +================== +*/ +void idPlayer::Event_WeaponAvailable( const char* name ) { + + idThread::ReturnInt( WeaponAvailable(name) ? 1 : 0 ); +} + +bool idPlayer::WeaponAvailable( const char* name ) { + for( int i = 0; i < MAX_WEAPONS; i++ ) { + if ( inventory.weapons & ( 1 << i ) ) { + const char *weap = spawnArgs.GetString( va( "def_weapon%d", i ) ); + if ( !idStr::Cmp( weap, name ) ) { + return true; + } + } + } + return false; +} + +#endif + /* ================== idPlayer::Event_GetCurrentWeapon @@ -7807,6 +9300,14 @@ void idPlayer::ClientPredictionThink( void ) { buttonMask &= usercmd.buttons; usercmd.buttons &= ~buttonMask; +#ifdef _D3XP + if ( mountedObject ) { + usercmd.forwardmove = 0; + usercmd.rightmove = 0; + usercmd.upmove = 0; + } +#endif + if ( objectiveSystemOpen ) { usercmd.forwardmove = 0; usercmd.rightmove = 0; @@ -7917,6 +9418,29 @@ void idPlayer::ClientPredictionThink( void ) { UpdateAnimation(); } +#ifdef _D3XP + if ( enviroSuitLight.IsValid() ) { + idAngles lightAng = firstPersonViewAxis.ToAngles(); + idVec3 lightOrg = firstPersonViewOrigin; + const idDict *lightDef = gameLocal.FindEntityDefDict( "envirosuit_light", false ); + + idVec3 enviroOffset = lightDef->GetVector( "enviro_offset" ); + idVec3 enviroAngleOffset = lightDef->GetVector( "enviro_angle_offset" ); + + lightOrg += (enviroOffset.x * firstPersonViewAxis[0]); + lightOrg += (enviroOffset.y * firstPersonViewAxis[1]); + lightOrg += (enviroOffset.z * firstPersonViewAxis[2]); + lightAng.pitch += enviroAngleOffset.x; + lightAng.yaw += enviroAngleOffset.y; + lightAng.roll += enviroAngleOffset.z; + + enviroSuitLight.GetEntity()->GetPhysics()->SetOrigin( lightOrg ); + enviroSuitLight.GetEntity()->GetPhysics()->SetAxis( lightAng.ToMat3() ); + enviroSuitLight.GetEntity()->UpdateVisuals(); + enviroSuitLight.GetEntity()->Present(); + } +#endif + if ( gameLocal.isMultiplayer ) { DrawPlayerIcons(); } @@ -7930,6 +9454,13 @@ void idPlayer::ClientPredictionThink( void ) { if ( gameLocal.isNewFrame && entityNumber == gameLocal.localClientNum ) { playerView.CalculateShake(); } + +#ifdef _D3XP + // determine if portal sky is in pvs + pvsHandle_t clientPVS = gameLocal.pvs.SetupCurrentPVS( GetPVSAreas(), GetNumPVSAreas() ); + gameLocal.portalSkyActive = gameLocal.pvs.CheckAreasForPortalSky( clientPVS, GetPhysics()->GetOrigin() ); + gameLocal.pvs.FreeCurrentPVS( clientPVS ); +#endif } /* @@ -8029,6 +9560,13 @@ void idPlayer::WriteToSnapshot( idBitMsgDelta &msg ) const { msg.WriteBits( weaponGone, 1 ); msg.WriteBits( isLagged, 1 ); msg.WriteBits( isChatting, 1 ); +#ifdef CTF + /* Needed for the scoreboard */ + msg.WriteBits( carryingFlag, 1 ); +#endif +#ifdef _D3XP + msg.WriteBits( enviroSuitLight.GetSpawnId(), 32 ); +#endif } /* @@ -8066,6 +9604,14 @@ void idPlayer::ReadFromSnapshot( const idBitMsgDelta &msg ) { weaponGone = msg.ReadBits( 1 ) != 0; isLagged = msg.ReadBits( 1 ) != 0; isChatting = msg.ReadBits( 1 ) != 0; +#ifdef CTF + carryingFlag = msg.ReadBits( 1 ) != 0; +#endif +#ifdef _D3XP + int enviroSpawnId; + enviroSpawnId = msg.ReadBits( 32 ); + enviroSuitLight.SetSpawnId( enviroSpawnId ); +#endif // no msg reading below this @@ -8132,6 +9678,7 @@ void idPlayer::ReadFromSnapshot( const idBitMsgDelta &msg ) { healthPulse = true; } +#ifdef _D3XP // If the player is alive, restore proper physics object if ( health > 0 && IsActiveAF() ) { StopRagdoll(); @@ -8139,6 +9686,7 @@ void idPlayer::ReadFromSnapshot( const idBitMsgDelta &msg ) { physicsObj.EnableClip(); SetCombatContents( true ); } +#endif if ( idealWeapon != newIdealWeapon ) { if ( stateHitch ) { @@ -8168,7 +9716,11 @@ void idPlayer::WritePlayerStateToSnapshot( idBitMsgDelta &msg ) const { msg.WriteByte( bobCycle ); msg.WriteInt( stepUpTime ); msg.WriteFloat( stepUpDelta ); +#ifdef _D3XP + msg.WriteInt( inventory.weapons ); +#else msg.WriteShort( inventory.weapons ); +#endif msg.WriteByte( inventory.armor ); for( i = 0; i < AMMO_NUMTYPES; i++ ) { @@ -8190,7 +9742,11 @@ void idPlayer::ReadPlayerStateFromSnapshot( const idBitMsgDelta &msg ) { bobCycle = msg.ReadByte(); stepUpTime = msg.ReadInt(); stepUpDelta = msg.ReadFloat(); +#ifdef _D3XP + inventory.weapons = msg.ReadInt(); +#else inventory.weapons = msg.ReadShort(); +#endif inventory.armor = msg.ReadByte(); for( i = 0; i < AMMO_NUMTYPES; i++ ) { @@ -8253,6 +9809,14 @@ bool idPlayer::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) { } return true; } +#ifdef _D3XP + case EVENT_PICKUPNAME: { + char buf[MAX_EVENT_PARAM_SIZE]; + msg.ReadString(buf, MAX_EVENT_PARAM_SIZE); + inventory.AddPickupName(buf, "", this); //_D3XP + return true; + } +#endif case EVENT_SPECTATE: { bool spectate = ( msg.ReadBits( 1 ) != 0 ); Spectate( spectate ); @@ -8464,22 +10028,7 @@ idPlayer::Event_Gibbed =============== */ void idPlayer::Event_Gibbed( void ) { -} - -/* -================== -idPlayer::Event_GetIdealWeapon -================== -*/ -void idPlayer::Event_GetIdealWeapon( void ) { - const char *weapon; - - if ( idealWeapon >= 0 ) { - weapon = spawnArgs.GetString( va( "def_weapon%d", idealWeapon ) ); - idThread::ReturnString( weapon ); - } else { - idThread::ReturnString( "" ); - } + // do nothing } /* @@ -8494,6 +10043,7 @@ void idPlayer::UpdatePlayerIcons( void ) { } else { isLagged = false; } + // TODO: chatting, PDA, etc? } /* @@ -8506,6 +10056,13 @@ void idPlayer::DrawPlayerIcons( void ) { playerIcon.FreeIcon(); return; } + +#ifdef CTF + // Never draw icons for hidden players. + if ( this->IsHidden() ) + return; +#endif + playerIcon.Draw( this, headJoint ); } @@ -8525,5 +10082,56 @@ idPlayer::NeedsIcon */ bool idPlayer::NeedsIcon( void ) { // local clients don't render their own icons... they're only info for other clients +#ifdef CTF + // always draw icons in CTF games + return entityNumber != gameLocal.localClientNum && ( ( g_CTFArrows.GetBool() && gameLocal.mpGame.IsGametypeFlagBased() && !IsHidden() && !AI_DEAD ) || ( isLagged || isChatting ) ); +#else return entityNumber != gameLocal.localClientNum && ( isLagged || isChatting ); +#endif +} + +#ifdef CTF +/* +=============== +idPlayer::DropFlag() +============== +*/ +void idPlayer::DropFlag( void ) { + if ( !carryingFlag || !gameLocal.isMultiplayer || !gameLocal.mpGame.IsGametypeFlagBased() ) /* CTF */ + return; + + idEntity * entity = gameLocal.mpGame.GetTeamFlag( 1 - this->latchedTeam ); + if ( entity ) { + idItemTeam * item = static_cast(entity); + + if ( item->carried && !item->dropped ) { + item->Drop( health <= 0 ); + carryingFlag = false; + } + } + } + +void idPlayer::ReturnFlag() { + + if ( !carryingFlag || !gameLocal.isMultiplayer || !gameLocal.mpGame.IsGametypeFlagBased() ) /* CTF */ + return; + + idEntity * entity = gameLocal.mpGame.GetTeamFlag( 1 - this->latchedTeam ); + if ( entity ) { + idItemTeam * item = static_cast(entity); + + if ( item->carried && !item->dropped ) { + item->Return(); + carryingFlag = false; + } + } +} + +void idPlayer::FreeModelDef( void ) { + idAFEntity_Base::FreeModelDef(); + if ( gameLocal.isMultiplayer && gameLocal.mpGame.IsGametypeFlagBased() ) + playerIcon.FreeIcon(); +} + +#endif diff --git a/game/Player.h b/game/Player.h index b411a0c0..aadf8550 100644 --- a/game/Player.h +++ b/game/Player.h @@ -40,6 +40,7 @@ If you have questions concerning this license or the applicable additional terms #include "GameEdit.h" class idAI; +class idFuncMountedObject; /* =============================================================================== @@ -64,7 +65,11 @@ const int LAND_RETURN_TIME = 300; const int FOCUS_TIME = 300; const int FOCUS_GUI_TIME = 500; +#ifdef _D3XP +const int MAX_WEAPONS = 32; +#else const int MAX_WEAPONS = 16; +#endif const int DEAD_HEARTRATE = 0; // fall to as you die const int LOWHEALTH_HEARTRATE_ADJ = 20; // @@ -103,6 +108,13 @@ enum { INVISIBILITY, MEGAHEALTH, ADRENALINE, +#ifdef _D3XP + INVULNERABILITY, + HELLTIME, + ENVIROSUIT, + //HASTE, + ENVIROTIME, +#endif MAX_POWERUPS }; @@ -122,6 +134,19 @@ enum { INFLUENCE_LEVEL3, // slow player movement }; +#ifdef _D3XP +typedef struct { + int ammo; + int rechargeTime; + char ammoName[128]; +} RechargeAmmo_t; + +typedef struct { + char name[64]; + idList toggleList; +} WeaponToggle_t; +#endif + class idInventory { public: int maxHealth; @@ -133,6 +158,10 @@ class idInventory { int clip[ MAX_WEAPONS ]; int powerupEndTime[ MAX_POWERUPS ]; +#ifdef _D3XP + RechargeAmmo_t rechargeAmmo[ AMMO_NUMTYPES ]; +#endif + // mp int ammoPredictTime; @@ -181,11 +210,15 @@ class idInventory { int WeaponIndexForAmmoClass( const idDict & spawnArgs, const char *ammo_classname ) const; ammo_t AmmoIndexForWeaponClass( const char *weapon_classname, int *ammoRequired ); const char * AmmoPickupNameForIndex( ammo_t ammonum ) const; - void AddPickupName( const char *name, const char *icon ); + void AddPickupName( const char *name, const char *icon, idPlayer* owner ); //_D3XP int HasAmmo( ammo_t type, int amount ); bool UseAmmo( ammo_t type, int amount ); - int HasAmmo( const char *weapon_classname ); // looks up the ammo information for the weapon class first + int HasAmmo( const char *weapon_classname, bool includeClip = false, idPlayer* owner = NULL ); // _D3XP + +#ifdef _D3XP + bool HasEmptyClipCannotRefill(const char *weapon_classname, idPlayer* owner); +#endif void UpdateArmor( void ); @@ -194,6 +227,12 @@ class idInventory { int onePickupTime; idList pickupItemNames; idList objectiveNames; + +#ifdef _D3XP + void InitRechargeAmmo(idPlayer *owner); + void RechargeAmmo(idPlayer *owner); + bool CanGive( idPlayer *owner, const idDict &spawnArgs, const char *statname, const char *value, int *idealWeapon ); +#endif }; typedef struct { @@ -214,6 +253,9 @@ class idPlayer : public idActor { EVENT_ABORT_TELEPORTER, EVENT_POWERUP, EVENT_SPECTATE, +#ifdef _D3XP + EVENT_PICKUPNAME, +#endif EVENT_MAXEVENTS }; @@ -268,6 +310,13 @@ class idPlayer : public idActor { int weapon_soulcube; int weapon_pda; int weapon_fists; +#ifdef _D3XP + int weapon_bloodstone; + int weapon_bloodstone_active1; + int weapon_bloodstone_active2; + int weapon_bloodstone_active3; + bool harvest_lock; +#endif int heartRate; idInterpolate heartInfo; @@ -289,7 +338,12 @@ class idPlayer : public idActor { idEntityPtr soulCubeProjectile; // mp stuff +#ifdef _D3XP + static idVec3 colorBarTable[ 8 ]; +#else static idVec3 colorBarTable[ 5 ]; +#endif + int spectator; idVec3 colorBar; // used for scoreboard and hud display int colorBarIndex; @@ -308,6 +362,10 @@ class idPlayer : public idActor { int tourneyLine; // client side - our spot in the wait line. 0 means no info. int spawnedTime; // when client first enters the game +#ifdef CTF + bool carryingFlag; // is the player carrying the flag? +#endif + idEntityPtr teleportEntity; // while being teleported, this is set to the entity we'll use for exit int teleportKiller; // entity number of an entity killing us at teleporter exit bool lastManOver; // can't respawn in last man anymore (srv only) @@ -327,6 +385,21 @@ class idPlayer : public idActor { idDragEntity dragEntity; +#ifdef _D3XP + idFuncMountedObject * mountedObject; + idEntityPtr enviroSuitLight; + + bool healthRecharge; + int lastHealthRechargeTime; + int rechargeSpeed; + + float new_g_damageScale; + + bool bloomEnabled; + float bloomSpeed; + float bloomIntensity; +#endif + public: CLASS_PROTOTYPE( idPlayer ); @@ -454,6 +527,10 @@ class idPlayer : public idActor { int GetBaseHeartRate( void ); void UpdateAir( void ); +#ifdef _D3XP + void UpdatePowerupHud(); +#endif + virtual bool HandleSingleGuiCommand( idEntity *entityGui, idLexer *src ); bool GuiActive( void ) { return focusGUIent != NULL; } @@ -521,6 +598,24 @@ class idPlayer : public idActor { virtual void HidePlayerIcons( void ); bool NeedsIcon( void ); +#ifdef _D3XP + void StartHealthRecharge(int speed); + void StopHealthRecharge(); + + idStr GetCurrentWeapon(); + + bool CanGive( const char *statname, const char *value ); + + void StopHelltime( bool quick = true ); + void PlayHelltimeStopSound(); +#endif + +#ifdef CTF + void DropFlag( void ); // drop CTF item + void ReturnFlag(); + virtual void FreeModelDef( void ); +#endif + bool SelfSmooth( void ); void SetSelfSmooth( bool b ); @@ -618,6 +713,14 @@ class idPlayer : public idActor { idVec3 smoothedOrigin; idAngles smoothedAngles; +#ifdef _D3XP + idHashTable weaponToggles; + + int hudPowerup; + int lastHudPowerup; + int hudPowerupDuration; +#endif + // mp bool ready; // from userInfo bool respawning; // set to true while in SpawnToPoint for telefrag checks @@ -675,6 +778,10 @@ class idPlayer : public idActor { void ExtractEmailInfo( const idStr &email, const char *scan, idStr &out ); void UpdateObjectiveInfo( void ); +#ifdef _D3XP + bool WeaponAvailable( const char* name ); +#endif + void UseVehicle( void ); void Event_GetButtons( void ); @@ -694,7 +801,20 @@ class idPlayer : public idActor { void Event_HideTip( void ); void Event_LevelTrigger( void ); void Event_Gibbed( void ); + +#ifdef _D3XP //BSM: Event to remove inventory items. Useful with powercells. + void Event_GiveInventoryItem( const char* name ); + void Event_RemoveInventoryItem( const char* name ); + void Event_GetIdealWeapon( void ); + void Event_WeaponAvailable( const char* name ); + void Event_SetPowerupTime( int powerup, int time ); + void Event_IsPowerupActive( int powerup ); + void Event_StartWarp(); + void Event_StopHelltime( int mode ); + void Event_ToggleBloom( int on ); + void Event_SetBloomParms( float speed, float intensity ); +#endif }; ID_INLINE bool idPlayer::IsReady( void ) { diff --git a/game/PlayerIcon.cpp b/game/PlayerIcon.cpp index 9f590a1a..3fd58efa 100644 --- a/game/PlayerIcon.cpp +++ b/game/PlayerIcon.cpp @@ -29,6 +29,7 @@ If you have questions concerning this license or the applicable additional terms #include "sys/platform.h" #include "renderer/ModelManager.h" +#include "gamesys/SysCvar.h" #include "Player.h" #include "PlayerIcon.h" @@ -36,6 +37,10 @@ If you have questions concerning this license or the applicable additional terms static const char * iconKeys[ ICON_NONE ] = { "mtr_icon_lag", "mtr_icon_chat" +#ifdef CTF + ,"mtr_icon_redteam", + "mtr_icon_blueteam" +#endif }; /* @@ -91,15 +96,26 @@ void idPlayerIcon::Draw( idPlayer *player, const idVec3 &origin ) { idMat3 axis = localPlayer->GetRenderView()->viewaxis; - if ( player->isLagged ) { + if ( player->isLagged && !player->spectating ) { // create the icon if necessary, or update if already created if ( !CreateIcon( player, ICON_LAG, origin, axis ) ) { UpdateIcon( player, origin, axis ); } - } else if ( player->isChatting ) { + } else if ( player->isChatting && !player->spectating ) { if ( !CreateIcon( player, ICON_CHAT, origin, axis ) ) { UpdateIcon( player, origin, axis ); } +#ifdef CTF + } else if ( g_CTFArrows.GetBool() && gameLocal.mpGame.IsGametypeFlagBased() && gameLocal.GetLocalPlayer() && player->team == gameLocal.GetLocalPlayer()->team && !player->IsHidden() && !player->AI_DEAD ) { + int icon = ICON_TEAM_RED + player->team; + + if ( icon != ICON_TEAM_RED && icon != ICON_TEAM_BLUE ) + return; + + if ( !CreateIcon( player, ( playerIconType_t )icon, origin, axis ) ) { + UpdateIcon( player, origin, axis ); + } +#endif } else { FreeIcon(); } diff --git a/game/PlayerIcon.h b/game/PlayerIcon.h index 9890d000..cbf582d4 100644 --- a/game/PlayerIcon.h +++ b/game/PlayerIcon.h @@ -32,6 +32,10 @@ If you have questions concerning this license or the applicable additional terms typedef enum { ICON_LAG, ICON_CHAT, +#ifdef CTF + ICON_TEAM_RED, + ICON_TEAM_BLUE, +#endif ICON_NONE } playerIconType_t; diff --git a/game/PlayerView.cpp b/game/PlayerView.cpp index 149b8292..512d8dbc 100644 --- a/game/PlayerView.cpp +++ b/game/PlayerView.cpp @@ -36,6 +36,17 @@ If you have questions concerning this license or the applicable additional terms #include "PlayerView.h" +// _D3XP : rename all gameLocal.time to gameLocal.slow.time for merge! + +#ifdef _D3XP +static int MakePowerOfTwo( int num ) { + int pot; + for (pot = 1 ; pot < num ; pot<<=1) { + } + return pot; +} +#endif + const int IMPULSE_DELAY = 150; /* ============== @@ -65,6 +76,14 @@ idPlayerView::idPlayerView() { fadeToColor.Zero(); fadeColor.Zero(); shakeAng.Zero(); +#ifdef _D3XP + fxManager = NULL; + + if ( !fxManager ) { + fxManager = new FullscreenFXManager; + fxManager->Initialize( this ); + } +#endif ClearEffects(); } @@ -118,6 +137,12 @@ void idPlayerView::Save( idSaveGame *savefile ) const { savefile->WriteObject( player ); savefile->WriteRenderView( view ); + +#ifdef _D3XP + if ( fxManager ) { + fxManager->Save( savefile ); + } +#endif } /* @@ -169,6 +194,12 @@ void idPlayerView::Restore( idRestoreGame *savefile ) { savefile->ReadObject( reinterpret_cast( player ) ); savefile->ReadRenderView( view ); + +#ifdef _D3XP + if ( fxManager ) { + fxManager->Restore( savefile ); + } +#endif } /* @@ -186,6 +217,16 @@ idPlayerView::ClearEffects ============== */ void idPlayerView::ClearEffects() { +#ifdef _D3XP + lastDamageTime = MS2SEC( gameLocal.slow.time - 99999 ); + + dvFinishTime = ( gameLocal.fast.time - 99999 ); + kickFinishTime = ( gameLocal.slow.time - 99999 ); + + for ( int i = 0 ; i < MAX_SCREEN_BLOBS ; i++ ) { + screenBlobs[i].finishTime = gameLocal.slow.time; + } +#else lastDamageTime = MS2SEC( gameLocal.time - 99999 ); dvFinishTime = ( gameLocal.time - 99999 ); @@ -194,6 +235,7 @@ void idPlayerView::ClearEffects() { for ( int i = 0 ; i < MAX_SCREEN_BLOBS ; i++ ) { screenBlobs[i].finishTime = gameLocal.time; } +#endif // _D3XP fadeTime = 0; bfgVision = false; @@ -227,13 +269,27 @@ void idPlayerView::DamageImpulse( idVec3 localKickDir, const idDict *damageDef ) // // double vision effect // +#ifdef _D3XP + if ( lastDamageTime > 0.0f && SEC2MS( lastDamageTime ) + IMPULSE_DELAY > gameLocal.slow.time ) { +#else if ( lastDamageTime > 0.0f && SEC2MS( lastDamageTime ) + IMPULSE_DELAY > gameLocal.time ) { +#endif // _D3XP // keep shotgun from obliterating the view return; } float dvTime = damageDef->GetFloat( "dv_time" ); if ( dvTime ) { +#ifdef _D3XP + if ( dvFinishTime < gameLocal.fast.time ) { + dvFinishTime = gameLocal.fast.time; + } + dvFinishTime += g_dvTime.GetFloat() * dvTime; + // don't let it add up too much in god mode + if ( dvFinishTime > gameLocal.fast.time + 5000 ) { + dvFinishTime = gameLocal.fast.time + 5000; + } +#else if ( dvFinishTime < gameLocal.time ) { dvFinishTime = gameLocal.time; } @@ -242,6 +298,7 @@ void idPlayerView::DamageImpulse( idVec3 localKickDir, const idDict *damageDef ) if ( dvFinishTime > gameLocal.time + 5000 ) { dvFinishTime = gameLocal.time + 5000; } +#endif // _D3XP } // @@ -249,7 +306,11 @@ void idPlayerView::DamageImpulse( idVec3 localKickDir, const idDict *damageDef ) // float kickTime = damageDef->GetFloat( "kick_time" ); if ( kickTime ) { +#ifdef _D3XP + kickFinishTime = gameLocal.slow.time + g_kickTime.GetFloat() * kickTime; +#else kickFinishTime = gameLocal.time + g_kickTime.GetFloat() * kickTime; +#endif // _D3XP // forward / back kick will pitch view kickAngles[0] = localKickDir[0]; @@ -275,8 +336,13 @@ void idPlayerView::DamageImpulse( idVec3 localKickDir, const idDict *damageDef ) float blobTime = damageDef->GetFloat( "blob_time" ); if ( blobTime ) { screenBlob_t *blob = GetScreenBlob(); +#ifdef _D3XP + blob->startFadeTime = gameLocal.slow.time; + blob->finishTime = gameLocal.slow.time + blobTime * g_blobTime.GetFloat() * ((float)gameLocal.msec / USERCMD_MSEC); +#else blob->startFadeTime = gameLocal.time; blob->finishTime = gameLocal.time + blobTime * g_blobTime.GetFloat(); +#endif // _D3XP const char *materialName = damageDef->GetString( "mtr_blob" ); blob->material = declManager->FindMaterial( materialName ); @@ -297,7 +363,11 @@ void idPlayerView::DamageImpulse( idVec3 localKickDir, const idDict *damageDef ) // // save lastDamageTime for tunnel vision accentuation // +#ifdef _D3XP + lastDamageTime = MS2SEC( gameLocal.slow.time ); +#else lastDamageTime = MS2SEC( gameLocal.time ); +#endif // _D3XP } @@ -316,8 +386,8 @@ void idPlayerView::AddBloodSpray( float duration ) { } // visit this for chainsaw screenBlob_t *blob = GetScreenBlob(); - blob->startFadeTime = gameLocal.time; - blob->finishTime = gameLocal.time + ( duration * 1000 ); + blob->startFadeTime = gameLocal.slow.time; + blob->finishTime = gameLocal.slow.time + ( duration * 1000 ); blob->material = bloodSprayMaterial; blob->x = ( gameLocal.random.RandomInt() & 63 ) - 32; blob->y = ( gameLocal.random.RandomInt() & 63 ) - 32; @@ -360,11 +430,19 @@ void idPlayerView::WeaponFireFeedback( const idDict *weaponDef ) { recoilTime = weaponDef->GetInt( "recoilTime" ); // don't shorten a damage kick in progress +#ifdef _D3XP + if ( recoilTime && kickFinishTime < gameLocal.slow.time ) { +#else if ( recoilTime && kickFinishTime < gameLocal.time ) { +#endif // _D3XP idAngles angles; weaponDef->GetAngles( "recoilAngles", "5 0 0", angles ); kickAngles = angles; +#ifdef _D3XP + int finish = gameLocal.slow.time + g_kickTime.GetFloat() * recoilTime; +#else int finish = gameLocal.time + g_kickTime.GetFloat() * recoilTime; +#endif // _D3XP kickFinishTime = finish; } @@ -378,7 +456,11 @@ idPlayerView::CalculateShake void idPlayerView::CalculateShake() { idVec3 origin, matrix; +#ifdef _D3XP + float shakeVolume = gameSoundWorld->CurrentShakeAmplitudeForPosition( gameLocal.slow.time, player->firstPersonViewOrigin ); +#else float shakeVolume = gameSoundWorld->CurrentShakeAmplitudeForPosition( gameLocal.time, player->firstPersonViewOrigin ); +#endif // _D3XP // // shakeVolume should somehow be molded into an angle here // it should be thought of as being in the range 0.0 -> 1.0, although @@ -411,8 +493,13 @@ idAngles idPlayerView::AngleOffset() const { ang.Zero(); +#ifdef _D3XP + if ( gameLocal.slow.time < kickFinishTime ) { + float offset = kickFinishTime - gameLocal.slow.time; +#else if ( gameLocal.time < kickFinishTime ) { float offset = kickFinishTime - gameLocal.time; +#endif // _D3XP ang = kickAngles * offset * offset * g_kickAmplitude.GetFloat(); @@ -440,11 +527,19 @@ void idPlayerView::SingleView( idUserInterface *hud, const renderView_t *view ) } // place the sound origin for the player +#ifdef _D3XP + gameSoundWorld->PlaceListener( view->vieworg, view->viewaxis, player->entityNumber + 1, gameLocal.slow.time, hud ? hud->State().GetString( "location" ) : "Undefined" ); +#else gameSoundWorld->PlaceListener( view->vieworg, view->viewaxis, player->entityNumber + 1, gameLocal.time, hud ? hud->State().GetString( "location" ) : "Undefined" ); +#endif // _D3XP // if the objective system is up, don't do normal drawing if ( player->objectiveSystemOpen ) { +#ifdef _D3XP + player->objectiveSystem->Redraw( gameLocal.fast.time ); +#else player->objectiveSystem->Redraw( gameLocal.time ); +#endif // _D3XP return; } @@ -452,23 +547,72 @@ void idPlayerView::SingleView( idUserInterface *hud, const renderView_t *view ) renderView_t hackedView = *view; hackedView.viewaxis = hackedView.viewaxis * ShakeAxis(); +#ifdef _D3XP + if ( gameLocal.portalSkyEnt.GetEntity() && gameLocal.IsPortalSkyAcive() && g_enablePortalSky.GetBool() ) { + renderView_t portalView = hackedView; + portalView.vieworg = gameLocal.portalSkyEnt.GetEntity()->GetPhysics()->GetOrigin(); + + // setup global fixup projection vars + if ( 1 ) { + int vidWidth, vidHeight; + idVec2 shiftScale; + + renderSystem->GetGLSettings( vidWidth, vidHeight ); + + float pot; + int w = vidWidth; + pot = MakePowerOfTwo( w ); + shiftScale.x = (float)w / pot; + + int h = vidHeight; + pot = MakePowerOfTwo( h ); + shiftScale.y = (float)h / pot; + + hackedView.shaderParms[4] = shiftScale.x; + hackedView.shaderParms[5] = shiftScale.y; + } + + gameRenderWorld->RenderScene( &portalView ); + renderSystem->CaptureRenderToImage( "_currentRender" ); + + hackedView.forceUpdate = true; // FIX: for smoke particles not drawing when portalSky present + } + + // process the frame + fxManager->Process( &hackedView ); +#else gameRenderWorld->RenderScene( &hackedView ); +#endif if ( player->spectating ) { return; } +#ifdef _D3XP + if ( !hud ) { + return; + } +#endif + // draw screen blobs if ( !pm_thirdPerson.GetBool() && !g_skipViewEffects.GetBool() ) { for ( int i = 0 ; i < MAX_SCREEN_BLOBS ; i++ ) { screenBlob_t *blob = &screenBlobs[i]; +#ifdef _D3XP + if ( blob->finishTime <= gameLocal.slow.time ) { +#else if ( blob->finishTime <= gameLocal.time ) { +#endif // _D3XP continue; } blob->y += blob->driftAmount; +#ifdef _D3XP + float fade = (float)( blob->finishTime - gameLocal.slow.time ) / ( blob->finishTime - blob->startFadeTime ); +#else float fade = (float)( blob->finishTime - gameLocal.time ) / ( blob->finishTime - blob->startFadeTime ); +#endif // _D3XP if ( fade > 1.0f ) { fade = 1.0f; } @@ -480,7 +624,11 @@ void idPlayerView::SingleView( idUserInterface *hud, const renderView_t *view ) player->DrawHUD( hud ); // armor impulse feedback +#ifdef _D3XP + float armorPulse = ( gameLocal.fast.time - player->lastArmorPulse ) / 250.0f; +#else float armorPulse = ( gameLocal.time - player->lastArmorPulse ) / 250.0f; +#endif // _D3XP if ( armorPulse > 0.0f && armorPulse < 1.0f ) { renderSystem->SetColor4( 1, 1, 1, 1.0 - armorPulse ); @@ -504,10 +652,15 @@ void idPlayerView::SingleView( idUserInterface *hud, const renderView_t *view ) } if ( alpha < 1.0f ) { +#ifdef _D3XP + renderSystem->SetColor4( ( player->health <= 0.0f ) ? MS2SEC( gameLocal.slow.time ) : lastDamageTime, 1.0f, 1.0f, ( player->health <= 0.0f ) ? 0.0f : alpha ); +#else renderSystem->SetColor4( ( player->health <= 0.0f ) ? MS2SEC( gameLocal.time ) : lastDamageTime, 1.0f, 1.0f, ( player->health <= 0.0f ) ? 0.0f : alpha ); +#endif // _D3XP renderSystem->DrawStretchPic( 0.0f, 0.0f, 640.0f, 480.0f, 0.0f, 0.0f, 1.0f, 1.0f, tunnelMaterial ); } +#ifndef _D3XP if ( player->PowerUpActive(BERSERK) ) { int berserkTime = player->inventory.powerupEndTime[ BERSERK ] - gameLocal.time; if ( berserkTime > 0 ) { @@ -517,7 +670,7 @@ void idPlayerView::SingleView( idUserInterface *hud, const renderView_t *view ) renderSystem->DrawStretchPic( 0.0f, 0.0f, 640.0f, 480.0f, 0.0f, 0.0f, 1.0f, 1.0f, berserkMaterial ); } } - +#endif // not _D3XP if ( bfgVision ) { renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, 1.0f ); renderSystem->DrawStretchPic( 0.0f, 0.0f, 640.0f, 480.0f, 0.0f, 0.0f, 1.0f, 1.0f, bfgMaterial ); @@ -538,58 +691,6 @@ void idPlayerView::SingleView( idUserInterface *hud, const renderView_t *view ) } } -/* -=================== -idPlayerView::DoubleVision -=================== -*/ -void idPlayerView::DoubleVision( idUserInterface *hud, const renderView_t *view, int offset ) { - - if ( !g_doubleVision.GetBool() ) { - SingleView( hud, view ); - return; - } - - float scale = offset * g_dvAmplitude.GetFloat(); - if ( scale > 0.5f ) { - scale = 0.5f; - } - float shift = scale * sin( sqrtf( offset ) * g_dvFrequency.GetFloat() ); - shift = fabs( shift ); - - // if double vision, render to a texture - renderSystem->CropRenderSize( 512, 256, true ); - SingleView( hud, view ); - renderSystem->CaptureRenderToImage( "_scratch" ); - renderSystem->UnCrop(); - - // carry red tint if in berserk mode - idVec4 color(1, 1, 1, 1); - if ( gameLocal.time < player->inventory.powerupEndTime[ BERSERK ] ) { - color.y = 0; - color.z = 0; - } - - renderSystem->SetColor4( color.x, color.y, color.z, 1.0f ); - renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, shift, 1, 1, 0, dvMaterial ); - renderSystem->SetColor4( color.x, color.y, color.z, 0.5f ); - renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 1, 1-shift, 0, dvMaterial ); -} - -/* -=================== -idPlayerView::BerserkVision -=================== -*/ -void idPlayerView::BerserkVision( idUserInterface *hud, const renderView_t *view ) { - renderSystem->CropRenderSize( 512, 256, true ); - SingleView( hud, view ); - renderSystem->CaptureRenderToImage( "_scratch" ); - renderSystem->UnCrop(); - renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, 1.0f ); - renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 1, 1, 0, dvMaterial ); -} - /* ================= @@ -612,6 +713,9 @@ assumes: color.w is 0 or 1 ================= */ void idPlayerView::Fade( idVec4 color, int time ) { +#ifdef _D3XP + SetTimeState ts( player->timeGroup ); +#endif if ( !fadeTime ) { fadeFromColor.Set( 0.0f, 0.0f, 0.0f, 1.0f - color[ 3 ] ); @@ -648,6 +752,10 @@ void idPlayerView::ScreenFade() { return; } +#ifdef _D3XP + SetTimeState ts( player->timeGroup ); +#endif + msec = fadeTime - gameLocal.realClientTime; if ( msec <= 0 ) { @@ -668,59 +776,1173 @@ void idPlayerView::ScreenFade() { /* =================== -idPlayerView::InfluenceVision +idPlayerView::RenderPlayerView =================== */ -void idPlayerView::InfluenceVision( idUserInterface *hud, const renderView_t *view ) { +void idPlayerView::RenderPlayerView( idUserInterface *hud ) { + const renderView_t *view = player->GetRenderView(); - float distance = 0.0f; - float pct = 1.0f; - if ( player->GetInfluenceEntity() ) { - distance = ( player->GetInfluenceEntity()->GetPhysics()->GetOrigin() - player->GetPhysics()->GetOrigin() ).Length(); - if ( player->GetInfluenceRadius() != 0.0f && distance < player->GetInfluenceRadius() ) { - pct = distance / player->GetInfluenceRadius(); - pct = 1.0f - idMath::ClampFloat( 0.0f, 1.0f, pct ); - } - } - if ( player->GetInfluenceMaterial() ) { - SingleView( hud, view ); - renderSystem->CaptureRenderToImage( "_currentRender" ); - renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, pct ); - renderSystem->DrawStretchPic( 0.0f, 0.0f, 640.0f, 480.0f, 0.0f, 0.0f, 1.0f, 1.0f, player->GetInfluenceMaterial() ); - } else if ( player->GetInfluenceEntity() == NULL ) { - SingleView( hud, view ); - return; - } else { - int offset = 25 + sinf( gameLocal.time ); - DoubleVision( hud, view, pct * offset ); + SingleView( hud, view ); + ScreenFade(); + + if ( net_clientLagOMeter.GetBool() && lagoMaterial && gameLocal.isClient ) { + renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, 1.0f ); + renderSystem->DrawStretchPic( 10.0f, 380.0f, 64.0f, 64.0f, 0.0f, 0.0f, 1.0f, 1.0f, lagoMaterial ); } } +#ifdef _D3XP /* =================== -idPlayerView::RenderPlayerView +idPlayerView::WarpVision =================== */ -void idPlayerView::RenderPlayerView( idUserInterface *hud ) { - const renderView_t *view = player->GetRenderView(); +int idPlayerView::AddWarp( idVec3 worldOrigin, float centerx, float centery, float initialRadius, float durationMsec ) { + FullscreenFX_Warp *fx = (FullscreenFX_Warp*)( fxManager->FindFX( "warp" ) ); - if ( g_skipViewEffects.GetBool() ) { - SingleView( hud, view ); - } else { - if ( player->GetInfluenceMaterial() || player->GetInfluenceEntity() ) { - InfluenceVision( hud, view ); - } else if ( gameLocal.time < dvFinishTime ) { - DoubleVision( hud, view, dvFinishTime - gameLocal.time ); - } else if ( player->PowerUpActive( BERSERK ) ) { - BerserkVision( hud, view ); - } else { - SingleView( hud, view ); + if ( fx ) { + fx->EnableGrabber( true ); + return 1; + } + + return 1; +} + +void idPlayerView::FreeWarp( int id ) { + FullscreenFX_Warp *fx = (FullscreenFX_Warp*)( fxManager->FindFX( "warp" ) ); + + if ( fx ) { + fx->EnableGrabber( false ); + return; + } +} + + + + + +/* +================== +FxFader::FxFader +================== +*/ +FxFader::FxFader() { + time = 0; + state = FX_STATE_OFF; + alpha = 0; + msec = 1000; +} + +/* +================== +FxFader::SetTriggerState +================== +*/ +bool FxFader::SetTriggerState( bool active ) { + + // handle on/off states + if ( active && state == FX_STATE_OFF ) { + state = FX_STATE_RAMPUP; + time = gameLocal.slow.time + msec; + } + else if ( !active && state == FX_STATE_ON ) { + state = FX_STATE_RAMPDOWN; + time = gameLocal.slow.time + msec; + } + + // handle rampup/rampdown states + if ( state == FX_STATE_RAMPUP ) { + if ( gameLocal.slow.time >= time ) { + state = FX_STATE_ON; + } + } + else if ( state == FX_STATE_RAMPDOWN ) { + if ( gameLocal.slow.time >= time ) { + state = FX_STATE_OFF; } - ScreenFade(); } - if ( net_clientLagOMeter.GetBool() && lagoMaterial && gameLocal.isClient ) { - renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, 1.0f ); - renderSystem->DrawStretchPic( 10.0f, 380.0f, 64.0f, 64.0f, 0.0f, 0.0f, 1.0f, 1.0f, lagoMaterial ); + // compute alpha + switch ( state ) { + case FX_STATE_ON: alpha = 1; break; + case FX_STATE_OFF: alpha = 0; break; + case FX_STATE_RAMPUP: alpha = 1 - (float)( time - gameLocal.slow.time ) / msec; break; + case FX_STATE_RAMPDOWN: alpha = (float)( time - gameLocal.slow.time ) / msec; break; + } + + if ( alpha > 0 ) { + return true; + } + else { + return false; + } +} + +/* +================== +FxFader::Save +================== +*/ +void FxFader::Save( idSaveGame *savefile ) { + savefile->WriteInt( time ); + savefile->WriteInt( state ); + savefile->WriteFloat( alpha ); + savefile->WriteInt( msec ); +} + +/* +================== +FxFader::Restore +================== +*/ +void FxFader::Restore( idRestoreGame *savefile ) { + savefile->ReadInt( time ); + savefile->ReadInt( state ); + savefile->ReadFloat( alpha ); + savefile->ReadInt( msec ); +} + + + + + +/* +================== +FullscreenFX_Helltime::Save +================== +*/ +void FullscreenFX::Save( idSaveGame *savefile ) { + fader.Save( savefile ); +} + +/* +================== +FullscreenFX_Helltime::Restore +================== +*/ +void FullscreenFX::Restore( idRestoreGame *savefile ) { + fader.Restore( savefile ); +} + + +/* +================== +FullscreenFX_Helltime::Initialize +================== +*/ +void FullscreenFX_Helltime::Initialize() { + acInitMaterials[0] = declManager->FindMaterial( "textures/smf/bloodorb1/ac_init" ); + acInitMaterials[1] = declManager->FindMaterial( "textures/smf/bloodorb2/ac_init" ); + acInitMaterials[2] = declManager->FindMaterial( "textures/smf/bloodorb3/ac_init" ); + + acCaptureMaterials[0] = declManager->FindMaterial( "textures/smf/bloodorb1/ac_capture" ); + acCaptureMaterials[1] = declManager->FindMaterial( "textures/smf/bloodorb2/ac_capture" ); + acCaptureMaterials[2] = declManager->FindMaterial( "textures/smf/bloodorb3/ac_capture" ); + + acDrawMaterials[0] = declManager->FindMaterial( "textures/smf/bloodorb1/ac_draw" ); + acDrawMaterials[1] = declManager->FindMaterial( "textures/smf/bloodorb2/ac_draw" ); + acDrawMaterials[2] = declManager->FindMaterial( "textures/smf/bloodorb3/ac_draw" ); + + crCaptureMaterials[0] = declManager->FindMaterial( "textures/smf/bloodorb1/cr_capture" ); + crCaptureMaterials[1] = declManager->FindMaterial( "textures/smf/bloodorb2/cr_capture" ); + crCaptureMaterials[2] = declManager->FindMaterial( "textures/smf/bloodorb3/cr_capture" ); + + crDrawMaterials[0] = declManager->FindMaterial( "textures/smf/bloodorb1/cr_draw" ); + crDrawMaterials[1] = declManager->FindMaterial( "textures/smf/bloodorb2/cr_draw" ); + crDrawMaterials[2] = declManager->FindMaterial( "textures/smf/bloodorb3/cr_draw" ); + + clearAccumBuffer = true; +} + +/* +================== +FullscreenFX_Helltime::DetermineLevel +================== +*/ +int FullscreenFX_Helltime::DetermineLevel() { + idPlayer *player; + int testfx = g_testHelltimeFX.GetInteger(); + + // for testing purposes + if ( testfx >= 0 && testfx < 3 ) { + return testfx; + } + + player = fxman->GetPlayer(); + + if ( player->PowerUpActive( INVULNERABILITY ) ) { + return 2; + } + else if ( player->PowerUpActive( BERSERK ) ) { + return 1; + } + else if ( player->PowerUpActive( HELLTIME ) ) { + return 0; + } + + return -1; +} + +/* +================== +FullscreenFX_Helltime::Active +================== +*/ +bool FullscreenFX_Helltime::Active() { + + if ( gameLocal.inCinematic || gameLocal.isMultiplayer ) { + return false; + } + + if ( DetermineLevel() >= 0 ) { + return true; + } + else { + // latch the clear flag + if ( fader.GetAlpha() == 0 ) { + clearAccumBuffer = true; + } + } + + return false; +} + +/* +================== +FullscreenFX_Helltime::AccumPass +================== +*/ +void FullscreenFX_Helltime::AccumPass( const renderView_t *view ) { + idVec2 shiftScale; + int level = DetermineLevel(); + + // for testing + if ( level < 0 || level > 2 ) { + level = 0; + } + + shiftScale = fxman->GetShiftScale(); + renderSystem->SetColor4( 1, 1, 1, 1 ); + + // capture pass + if ( clearAccumBuffer ) { + clearAccumBuffer = false; + renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 1, 1, 0, acInitMaterials[level] ); + } + else { + renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 1, 1, 0, acCaptureMaterials[level] ); + renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, shiftScale.y, shiftScale.x, 0, crCaptureMaterials[level] ); + } + + renderSystem->CaptureRenderToImage( "_accum" ); +} + +/* +================== +FullscreenFX_Helltime::HighQuality +================== +*/ +void FullscreenFX_Helltime::HighQuality() { + idVec2 shiftScale; + int level = DetermineLevel(); + + // for testing + if ( level < 0 || level > 2 ) { + level = 0; } + + shiftScale = fxman->GetShiftScale(); + renderSystem->SetColor4( 1, 1, 1, 1 ); + + // draw pass + renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 1, 1, 0, acDrawMaterials[level] ); + renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, shiftScale.y, shiftScale.x, 0, crDrawMaterials[level] ); +} + +/* +================== +FullscreenFX_Helltime::Restore +================== +*/ +void FullscreenFX_Helltime::Restore( idRestoreGame *savefile ) { + FullscreenFX::Restore( savefile ); + + // latch the clear flag + clearAccumBuffer = true; +} + + + + + +/* +================== +FullscreenFX_Multiplayer::Initialize +================== +*/ +void FullscreenFX_Multiplayer::Initialize() { + acInitMaterials = declManager->FindMaterial( "textures/smf/multiplayer1/ac_init" ); + acCaptureMaterials = declManager->FindMaterial( "textures/smf/multiplayer1/ac_capture" ); + acDrawMaterials = declManager->FindMaterial( "textures/smf/multiplayer1/ac_draw" ); + crCaptureMaterials = declManager->FindMaterial( "textures/smf/multiplayer1/cr_capture" ); + crDrawMaterials = declManager->FindMaterial( "textures/smf/multiplayer1/cr_draw" ); + clearAccumBuffer = true; } + +/* +================== +FullscreenFX_Multiplayer::DetermineLevel +================== +*/ +int FullscreenFX_Multiplayer::DetermineLevel() { + idPlayer *player; + int testfx = g_testMultiplayerFX.GetInteger(); + + // for testing purposes + if ( testfx >= 0 && testfx < 3 ) { + return testfx; + } + + player = fxman->GetPlayer(); + + if ( player->PowerUpActive( INVULNERABILITY ) ) { + return 2; + } + //else if ( player->PowerUpActive( HASTE ) ) { + // return 1; + //} + else if ( player->PowerUpActive( BERSERK ) ) { + return 0; + } + + return -1; +} + +/* +================== +FullscreenFX_Multiplayer::Active +================== +*/ +bool FullscreenFX_Multiplayer::Active() { + + if ( !gameLocal.isMultiplayer && g_testMultiplayerFX.GetInteger() == -1 ) { + return false; + } + + if ( DetermineLevel() >= 0 ) { + return true; + } + else { + // latch the clear flag + if ( fader.GetAlpha() == 0 ) { + clearAccumBuffer = true; + } + } + + return false; +} + +/* +================== +FullscreenFX_Multiplayer::AccumPass +================== +*/ +void FullscreenFX_Multiplayer::AccumPass( const renderView_t *view ) { + idVec2 shiftScale; + int level = DetermineLevel(); + + // for testing + if ( level < 0 || level > 2 ) { + level = 0; + } + + shiftScale = fxman->GetShiftScale(); + renderSystem->SetColor4( 1, 1, 1, 1 ); + + // capture pass + if ( clearAccumBuffer ) { + clearAccumBuffer = false; + renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 1, 1, 0, acInitMaterials ); + } + else { + renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 1, 1, 0, acCaptureMaterials ); + renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, shiftScale.y, shiftScale.x, 0, crCaptureMaterials ); + } + + renderSystem->CaptureRenderToImage( "_accum" ); +} + +/* +================== +FullscreenFX_Multiplayer::HighQuality +================== +*/ +void FullscreenFX_Multiplayer::HighQuality() { + idVec2 shiftScale; + int level = DetermineLevel(); + + // for testing + if ( level < 0 || level > 2 ) { + level = 0; + } + + shiftScale = fxman->GetShiftScale(); + renderSystem->SetColor4( 1, 1, 1, 1 ); + + // draw pass + renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 1, 1, 0, acDrawMaterials ); + renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, shiftScale.y, shiftScale.x, 0, crDrawMaterials ); +} + +/* +================== +FullscreenFX_Multiplayer::Restore +================== +*/ +void FullscreenFX_Multiplayer::Restore( idRestoreGame *savefile ) { + FullscreenFX::Restore( savefile ); + + // latch the clear flag + clearAccumBuffer = true; +} + + + + + +/* +================== +FullscreenFX_Warp::Initialize +================== +*/ +void FullscreenFX_Warp::Initialize() { + material = declManager->FindMaterial( "textures/smf/warp" ); + grabberEnabled = false; + startWarpTime = 0; +} + +/* +================== +FullscreenFX_Warp::Active +================== +*/ +bool FullscreenFX_Warp::Active() { + if ( grabberEnabled ) { + return true; + } + + return false; +} + +/* +================== +FullscreenFX_Warp::Save +================== +*/ +void FullscreenFX_Warp::Save( idSaveGame *savefile ) { + FullscreenFX::Save( savefile ); + + savefile->WriteBool( grabberEnabled ); + savefile->WriteInt( startWarpTime ); +} + +/* +================== +FullscreenFX_Warp::Restore +================== +*/ +void FullscreenFX_Warp::Restore( idRestoreGame *savefile ) { + FullscreenFX::Restore( savefile ); + + savefile->ReadBool( grabberEnabled ); + savefile->ReadInt( startWarpTime ); +} + +/* +================== +FullscreenFX_Warp::DrawWarp +================== +*/ +void FullscreenFX_Warp::DrawWarp( WarpPolygon_t wp, float interp ) { + idVec4 mid1_uv, mid2_uv; + idVec4 mid1, mid2; + idVec2 drawPts[6], shiftScale; + WarpPolygon_t trans; + + trans = wp; + shiftScale = fxman->GetShiftScale(); + + // compute mid points + mid1 = trans.outer1 * ( interp ) + trans.center * ( 1 - interp ); + mid2 = trans.outer2 * ( interp ) + trans.center * ( 1 - interp ); + mid1_uv = trans.outer1 * ( 0.5 ) + trans.center * ( 1 - 0.5 ); + mid2_uv = trans.outer2 * ( 0.5 ) + trans.center * ( 1 - 0.5 ); + + // draw [outer1, mid2, mid1] + drawPts[0].Set( trans.outer1.x, trans.outer1.y ); + drawPts[1].Set( mid2.x, mid2.y ); + drawPts[2].Set( mid1.x, mid1.y ); + drawPts[3].Set( trans.outer1.z, trans.outer1.w ); + drawPts[4].Set( mid2_uv.z, mid2_uv.w ); + drawPts[5].Set( mid1_uv.z, mid1_uv.w ); + for ( int j = 0; j < 3; j++ ) { + drawPts[j+3].x *= shiftScale.x; + drawPts[j+3].y *= shiftScale.y; + } + renderSystem->DrawStretchTri( drawPts[0], drawPts[1], drawPts[2], drawPts[3], drawPts[4], drawPts[5], material ); + + // draw [outer1, outer2, mid2] + drawPts[0].Set( trans.outer1.x, trans.outer1.y ); + drawPts[1].Set( trans.outer2.x, trans.outer2.y ); + drawPts[2].Set( mid2.x, mid2.y ); + drawPts[3].Set( trans.outer1.z, trans.outer1.w ); + drawPts[4].Set( trans.outer2.z, trans.outer2.w ); + drawPts[5].Set( mid2_uv.z, mid2_uv.w ); + for ( int j = 0; j < 3; j++ ) { + drawPts[j+3].x *= shiftScale.x; + drawPts[j+3].y *= shiftScale.y; + } + renderSystem->DrawStretchTri( drawPts[0], drawPts[1], drawPts[2], drawPts[3], drawPts[4], drawPts[5], material ); + + // draw [mid1, mid2, center] + drawPts[0].Set( mid1.x, mid1.y ); + drawPts[1].Set( mid2.x, mid2.y ); + drawPts[2].Set( trans.center.x, trans.center.y ); + drawPts[3].Set( mid1_uv.z, mid1_uv.w ); + drawPts[4].Set( mid2_uv.z, mid2_uv.w ); + drawPts[5].Set( trans.center.z, trans.center.w ); + for ( int j = 0; j < 3; j++ ) { + drawPts[j+3].x *= shiftScale.x; + drawPts[j+3].y *= shiftScale.y; + } + renderSystem->DrawStretchTri( drawPts[0], drawPts[1], drawPts[2], drawPts[3], drawPts[4], drawPts[5], material ); +} + +/* +================== +FullscreenFX_Warp::HighQuality +================== +*/ +void FullscreenFX_Warp::HighQuality() { + float x1, y1, x2, y2, radius, interp; + idVec2 center; + int STEP = 9; + + interp = ( idMath::Sin( (float)( gameLocal.slow.time - startWarpTime ) / 1000 ) + 1 ) / 2.f; + interp = 0.7 * ( 1 - interp ) + 0.3 * ( interp ); + + // draw the warps + center.x = 320; + center.y = 240; + radius = 200; + + for ( float i = 0; i < 360; i += STEP ) { + // compute the values + x1 = idMath::Sin( DEG2RAD( i ) ); + y1 = idMath::Cos( DEG2RAD( i ) ); + + x2 = idMath::Sin( DEG2RAD( i + STEP ) ); + y2 = idMath::Cos( DEG2RAD( i + STEP ) ); + + // add warp polygon + WarpPolygon_t p; + + p.outer1.x = center.x + x1 * radius; + p.outer1.y = center.y + y1 * radius; + p.outer1.z = p.outer1.x / 640.f; + p.outer1.w = 1 - ( p.outer1.y / 480.f ); + + p.outer2.x = center.x + x2 * radius; + p.outer2.y = center.y + y2 * radius; + p.outer2.z = p.outer2.x / 640.f; + p.outer2.w = 1 - ( p.outer2.y / 480.f ); + + p.center.x = center.x; + p.center.y = center.y; + p.center.z = p.center.x / 640.f; + p.center.w = 1 - ( p.center.y / 480.f ); + + // draw it + DrawWarp( p, interp ); + } +} + + + + + +/* +================== +FullscreenFX_EnviroSuit::Initialize +================== +*/ +void FullscreenFX_EnviroSuit::Initialize() { + material = declManager->FindMaterial( "textures/smf/enviro_suit" ); +} + +/* +================== +FullscreenFX_EnviroSuit::Active +================== +*/ +bool FullscreenFX_EnviroSuit::Active() { + idPlayer *player; + + player = fxman->GetPlayer(); + + if ( player->PowerUpActive( ENVIROSUIT ) ) { + return true; + } + + return false; +} + +/* +================== +FullscreenFX_EnviroSuit::HighQuality +================== +*/ +void FullscreenFX_EnviroSuit::HighQuality() { + renderSystem->SetColor4( 1, 1, 1, 1 ); + renderSystem->DrawStretchPic( 0.0f, 0.0f, 640.0f, 480.0f, 0.0f, 0.0f, 1.0f, 1.0f, material ); +} + + + + + +/* +================== +FullscreenFX_DoubleVision::Initialize +================== +*/ +void FullscreenFX_DoubleVision::Initialize() { + material = declManager->FindMaterial( "textures/smf/doubleVision" ); +} + +/* +================== +FullscreenFX_DoubleVision::Active +================== +*/ +bool FullscreenFX_DoubleVision::Active() { + + if ( gameLocal.fast.time < fxman->GetPlayerView()->dvFinishTime ) { + return true; + } + + return false; +} + +/* +================== +FullscreenFX_DoubleVision::HighQuality +================== +*/ +void FullscreenFX_DoubleVision::HighQuality() { + int offset = fxman->GetPlayerView()->dvFinishTime - gameLocal.fast.time; + float scale = offset * g_dvAmplitude.GetFloat(); + idPlayer *player; + idVec2 shiftScale; + + // for testing purposes + if ( !Active() ) { + static int test = 0; + if ( test > 312 ) { + test = 0; + } + + offset = test++; + scale = offset * g_dvAmplitude.GetFloat(); + } + + player = fxman->GetPlayer(); + shiftScale = fxman->GetShiftScale(); + + offset *= 2; // crutch up for higher res + + // set the scale and shift + if ( scale > 0.5f ) { + scale = 0.5f; + } + float shift = scale * sin( sqrtf( (float)offset ) * g_dvFrequency.GetFloat() ); + shift = fabs( shift ); + + // carry red tint if in berserk mode + idVec4 color(1, 1, 1, 1); + if ( gameLocal.fast.time < player->inventory.powerupEndTime[ BERSERK ] ) { + color.y = 0; + color.z = 0; + } + + if ( !gameLocal.isMultiplayer && (gameLocal.fast.time < player->inventory.powerupEndTime[ HELLTIME ] || gameLocal.fast.time < player->inventory.powerupEndTime[ INVULNERABILITY ])) { + color.y = 0; + color.z = 0; + } + + renderSystem->SetColor4( color.x, color.y, color.z, 1.0f ); + renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, shift, shiftScale.y, shiftScale.x, 0, material ); + renderSystem->SetColor4( color.x, color.y, color.z, 0.5f ); + renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, shiftScale.y, (1-shift) * shiftScale.x, 0, material ); +} + + + + +/* +================== +FullscreenFX_InfluenceVision::Initialize +================== +*/ +void FullscreenFX_InfluenceVision::Initialize() { + +} + +/* +================== +FullscreenFX_InfluenceVision::Active +================== +*/ +bool FullscreenFX_InfluenceVision::Active() { + idPlayer *player; + + player = fxman->GetPlayer(); + + if ( player->GetInfluenceMaterial() || player->GetInfluenceEntity() ) { + return true; + } + + return false; +} + +/* +================== +FullscreenFX_InfluenceVision::HighQuality +================== +*/ +void FullscreenFX_InfluenceVision::HighQuality() { + float distance = 0.0f; + float pct = 1.0f; + idPlayer *player; + idVec2 shiftScale; + + shiftScale = fxman->GetShiftScale(); + player = fxman->GetPlayer(); + + if ( player->GetInfluenceEntity() ) { + distance = ( player->GetInfluenceEntity()->GetPhysics()->GetOrigin() - player->GetPhysics()->GetOrigin() ).Length(); + if ( player->GetInfluenceRadius() != 0.0f && distance < player->GetInfluenceRadius() ) { + pct = distance / player->GetInfluenceRadius(); + pct = 1.0f - idMath::ClampFloat( 0.0f, 1.0f, pct ); + } + } + + if ( player->GetInfluenceMaterial() ) { + renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, pct ); + renderSystem->DrawStretchPic( 0.0f, 0.0f, 640.0f, 480.0f, 0.0f, 0.0f, 1.0f, 1.0f, player->GetInfluenceMaterial() ); + } else if ( player->GetInfluenceEntity() == NULL ) { + return; + } else { +// int offset = 25 + sinf( gameLocal.slow.time ); +// DoubleVision( hud, view, pct * offset ); + } +} + + + + +/* +================== +FullscreenFX_Bloom::Initialize +================== +*/ +void FullscreenFX_Bloom::Initialize() { + drawMaterial = declManager->FindMaterial( "textures/smf/bloom2/draw" ); + initMaterial = declManager->FindMaterial( "textures/smf/bloom2/init" ); + currentMaterial = declManager->FindMaterial( "textures/smf/bloom2/currentMaterial" ); + + currentIntensity = 0; + targetIntensity = 0; +} + +/* +================== +FullscreenFX_Bloom::Active +================== +*/ +bool FullscreenFX_Bloom::Active() { + idPlayer *player; + + player = fxman->GetPlayer(); + + if ( player && player->bloomEnabled ) { + return true; + } + + return false; +} + +/* +================== +FullscreenFX_Bloom::HighQuality +================== +*/ +void FullscreenFX_Bloom::HighQuality() { + float shift, delta; + idVec2 shiftScale; + idPlayer *player; + int num; + + shift = 1; + player = fxman->GetPlayer(); + shiftScale = fxman->GetShiftScale(); + renderSystem->SetColor4( 1, 1, 1, 1 ); + + // if intensity value is different, start the blend + targetIntensity = g_testBloomIntensity.GetFloat(); + + if ( player && player->bloomEnabled ) { + targetIntensity = player->bloomIntensity; + } + + delta = targetIntensity - currentIntensity; + float step = 0.001f; + + if ( step < fabs( delta ) ) { + if ( delta < 0 ) { + step = -step; + } + + currentIntensity += step; + } + + // draw the blends + num = g_testBloomNumPasses.GetInteger(); + + for ( int i = 0; i < num; i++ ) { + float s1 = 0, t1 = 0, s2 = 1, t2 = 1; + float alpha; + + // do the center scale + s1 -= 0.5; + s1 *= shift; + s1 += 0.5; + s1 *= shiftScale.x; + + t1 -= 0.5; + t1 *= shift; + t1 += 0.5; + t1 *= shiftScale.y; + + s2 -= 0.5; + s2 *= shift; + s2 += 0.5; + s2 *= shiftScale.x; + + t2 -= 0.5; + t2 *= shift; + t2 += 0.5; + t2 *= shiftScale.y; + + // draw it + if ( num == 1 ) { + alpha = 1; + } + else { + alpha = 1 - (float)i / ( num - 1 ); + } + + renderSystem->SetColor4( alpha, alpha, alpha, 1 ); + renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, s1, t2, s2, t1, drawMaterial ); + + shift += currentIntensity; + } +} + +/* +================== +FullscreenFX_Bloom::Save +================== +*/ +void FullscreenFX_Bloom::Save( idSaveGame *savefile ) { + FullscreenFX::Save( savefile ); + savefile->WriteFloat( currentIntensity ); + savefile->WriteFloat( targetIntensity ); +} + +/* +================== +FullscreenFX_Bloom::Restore +================== +*/ +void FullscreenFX_Bloom::Restore( idRestoreGame *savefile ) { + FullscreenFX::Restore( savefile ); + savefile->ReadFloat( currentIntensity ); + savefile->ReadFloat( targetIntensity ); +} + + + + + + +/* +================== +FullscreenFXManager::FullscreenFXManager +================== +*/ +FullscreenFXManager::FullscreenFXManager() { + highQualityMode = false; + playerView = NULL; + blendBackMaterial = NULL; + shiftScale.Set( 0, 0 ); +} + +/* +================== +FullscreenFXManager::~FullscreenFXManager +================== +*/ +FullscreenFXManager::~FullscreenFXManager() { + +} + +/* +================== +FullscreenFXManager::FindFX +================== +*/ +FullscreenFX* FullscreenFXManager::FindFX( idStr name ) { + for ( int i = 0; i < fx.Num(); i++ ) { + if ( fx[i]->GetName() == name ) { + return fx[i]; + } + } + + return NULL; +} + +/* +================== +FullscreenFXManager::CreateFX +================== +*/ +void FullscreenFXManager::CreateFX( idStr name, idStr fxtype, int fade ) { + FullscreenFX *pfx = NULL; + + if ( fxtype == "helltime" ) { + pfx = new FullscreenFX_Helltime; + } + else if ( fxtype == "warp" ) { + pfx = new FullscreenFX_Warp; + } + else if ( fxtype == "envirosuit" ) { + pfx = new FullscreenFX_EnviroSuit; + } + else if ( fxtype == "doublevision" ) { + pfx = new FullscreenFX_DoubleVision; + } + else if ( fxtype == "multiplayer" ) { + pfx = new FullscreenFX_Multiplayer; + } + else if ( fxtype == "influencevision" ) { + pfx = new FullscreenFX_InfluenceVision; + } + else if ( fxtype == "bloom" ) { + pfx = new FullscreenFX_Bloom; + } + else { + assert( 0 ); + } + + if ( pfx ) { + pfx->Initialize(); + pfx->SetFXManager( this ); + pfx->SetName( name ); + pfx->SetFadeSpeed( fade ); + fx.Append( pfx ); + } +} + +/* +================== +FullscreenFXManager::Initialize +================== +*/ +void FullscreenFXManager::Initialize( idPlayerView *pv ) { + // set the playerview + playerView = pv; + blendBackMaterial = declManager->FindMaterial( "textures/smf/blendBack" ); + + // allocate the fx + CreateFX( "helltime", "helltime", 1000 ); + CreateFX( "warp", "warp", 0 ); + CreateFX( "envirosuit", "envirosuit", 500 ); + CreateFX( "doublevision", "doublevision", 0 ); + CreateFX( "multiplayer", "multiplayer", 1000 ); + CreateFX( "influencevision", "influencevision", 1000 ); + CreateFX( "bloom", "bloom", 0 ); + + // pre-cache the texture grab so we dont hitch + renderSystem->CropRenderSize( 512, 512, true ); + renderSystem->CaptureRenderToImage( "_accum" ); + renderSystem->UnCrop(); + + renderSystem->CropRenderSize( 512, 256, true ); + renderSystem->CaptureRenderToImage( "_scratch" ); + renderSystem->UnCrop(); + + renderSystem->CaptureRenderToImage( "_currentRender" ); +} + +/* +================== +FullscreenFXManager::Blendback +================== +*/ +void FullscreenFXManager::Blendback( float alpha ) { + // alpha fade + if ( alpha < 1.f ) { + renderSystem->SetColor4( 1, 1, 1, 1 - alpha ); + renderSystem->DrawStretchPic( 0.0f, 0.0f, 640.0f, 480.0f, 0.0f, shiftScale.y, shiftScale.x, 0.f, blendBackMaterial ); + } +} + +/* +================== +FullscreenFXManager::Save +================== +*/ +void FullscreenFXManager::Save( idSaveGame *savefile ) { + savefile->WriteBool( highQualityMode ); + savefile->WriteVec2( shiftScale ); + + for ( int i = 0; i < fx.Num(); i++ ) { + FullscreenFX *pfx = fx[i]; + pfx->Save( savefile ); + } +} + +/* +================== +FullscreenFXManager::Restore +================== +*/ +void FullscreenFXManager::Restore( idRestoreGame *savefile ) { + savefile->ReadBool( highQualityMode ); + savefile->ReadVec2( shiftScale ); + + for ( int i = 0; i < fx.Num(); i++ ) { + FullscreenFX *pfx = fx[i]; + pfx->Restore( savefile ); + } +} + +/* +================== +FullscreenFXManager::CaptureCurrentRender +================== +*/ +void FullscreenFXManager::CaptureCurrentRender() { + renderSystem->CaptureRenderToImage( "_currentRender" ); +} + +/* +================== +FullscreenFXManager::Process +================== +*/ +void FullscreenFXManager::Process( const renderView_t *view ) { + bool allpass = false; + + if ( g_testFullscreenFX.GetInteger() == -2 ) { + allpass = true; + } + + if ( g_lowresFullscreenFX.GetBool() ) { + highQualityMode = false; + } + else { + highQualityMode = true; + } + + // compute the shift scale + if ( highQualityMode ) { + int vidWidth, vidHeight; + renderSystem->GetGLSettings( vidWidth, vidHeight ); + + float pot; + int w = vidWidth; + pot = MakePowerOfTwo( w ); + shiftScale.x = (float)w / pot; + + int h = vidHeight; + pot = MakePowerOfTwo( h ); + shiftScale.y = (float)h / pot; + } + else { + // if we're in low-res mode, shrink view down + shiftScale.x = 1; + shiftScale.y = 1; + renderSystem->CropRenderSize( 512, 512, true ); + } + + // do the first render + gameRenderWorld->RenderScene( view ); + + // do the process + for ( int i = 0; i < fx.Num(); i++ ) { + FullscreenFX *pfx = fx[i]; + bool drawIt = false; + + // determine if we need to draw + if ( pfx->Active() || g_testFullscreenFX.GetInteger() == i || allpass ) { + drawIt = pfx->SetTriggerState( true ); + } + else { + drawIt = pfx->SetTriggerState( false ); + } + + // do the actual drawing + if ( drawIt ) { + // we need to dump to _currentRender + CaptureCurrentRender(); + + // handle the accum pass if we have one + if ( pfx->HasAccum() ) { + + // if we're in high quality mode, we need to crop the accum pass + if ( highQualityMode ) { + renderSystem->CropRenderSize( 512, 512, true ); + pfx->AccumPass( view ); + renderSystem->UnCrop(); + } + else { + pfx->AccumPass( view ); + } + } + + // do the high quality pass + pfx->HighQuality(); + + // do the blendback + Blendback( pfx->GetFadeAlpha() ); + } + } + + if ( !highQualityMode ) { + // we need to dump to _currentRender + CaptureCurrentRender(); + + // uncrop view + renderSystem->UnCrop(); + + // draw the final full-screen image + renderSystem->SetColor4( 1, 1, 1, 1 ); + renderSystem->DrawStretchPic( 0.0f, 0.0f, 640.0f, 480.0f, 0.0f, 1, 1, 0.f, blendBackMaterial ); + } +} + + + +#endif diff --git a/game/PlayerView.h b/game/PlayerView.h index bc904588..502abb87 100644 --- a/game/PlayerView.h +++ b/game/PlayerView.h @@ -57,6 +57,303 @@ typedef struct { #define MAX_SCREEN_BLOBS 8 + + + + +#ifdef _D3XP +class WarpPolygon_t { +public: + idVec4 outer1; + idVec4 outer2; + idVec4 center; +}; + +class Warp_t { +public: + int id; + bool active; + + int startTime; + float initialRadius; + + idVec3 worldOrigin; + idVec2 screenOrigin; + + int durationMsec; + + idList polys; +}; +#endif + + + + + + + +#ifdef _D3XP + +class idPlayerView; +class FullscreenFXManager; + + +/* +================== +FxFader +================== +*/ +class FxFader { + enum { + FX_STATE_OFF, + FX_STATE_RAMPUP, + FX_STATE_RAMPDOWN, + FX_STATE_ON + }; + + int time; + int state; + float alpha; + int msec; + +public: + FxFader(); + + // primary functions + bool SetTriggerState( bool active ); + + virtual void Save( idSaveGame *savefile ); + virtual void Restore( idRestoreGame *savefile ); + + // fader functions + void SetFadeTime( int t ) { msec = t; }; + int GetFadeTime() { return msec; }; + + // misc functions + float GetAlpha() { return alpha; }; +}; + + +/* +================== +FullscreenFX +================== +*/ +class FullscreenFX { +protected: + idStr name; + FxFader fader; + FullscreenFXManager *fxman; + +public: + FullscreenFX() { fxman = NULL; }; + virtual ~FullscreenFX() { }; + + virtual void Initialize() = 0; + virtual bool Active() = 0; + virtual void HighQuality() = 0; + virtual void LowQuality() { }; + virtual void AccumPass( const renderView_t *view ) { }; + virtual bool HasAccum() { return false; }; + + void SetName( idStr n ) { name = n; }; + idStr GetName() { return name; }; + + void SetFXManager( FullscreenFXManager *fx ) { fxman = fx; }; + + bool SetTriggerState( bool state ) { return fader.SetTriggerState( state ); }; + void SetFadeSpeed( int msec ) { fader.SetFadeTime( msec ); }; + float GetFadeAlpha() { return fader.GetAlpha(); }; + + virtual void Save( idSaveGame *savefile ); + virtual void Restore( idRestoreGame *savefile ); +}; + +/* +================== +FullscreenFX_Helltime +================== +*/ +class FullscreenFX_Helltime : public FullscreenFX { + const idMaterial* acInitMaterials[3]; + const idMaterial* acCaptureMaterials[3]; + const idMaterial* acDrawMaterials[3]; + const idMaterial* crCaptureMaterials[3]; + const idMaterial* crDrawMaterials[3]; + bool clearAccumBuffer; + + int DetermineLevel(); + +public: + virtual void Initialize(); + virtual bool Active(); + virtual void HighQuality(); + virtual void AccumPass( const renderView_t *view ); + virtual bool HasAccum() { return true; }; + + virtual void Restore( idRestoreGame *savefile ); +}; + +/* +================== +FullscreenFX_Multiplayer +================== +*/ +class FullscreenFX_Multiplayer : public FullscreenFX { + const idMaterial* acInitMaterials; + const idMaterial* acCaptureMaterials; + const idMaterial* acDrawMaterials; + const idMaterial* crCaptureMaterials; + const idMaterial* crDrawMaterials; + bool clearAccumBuffer; + + int DetermineLevel(); + +public: + virtual void Initialize(); + virtual bool Active(); + virtual void HighQuality(); + virtual void AccumPass( const renderView_t *view ); + virtual bool HasAccum() { return true; }; + + virtual void Restore( idRestoreGame *savefile ); +}; + +/* +================== +FullscreenFX_Warp +================== +*/ +class FullscreenFX_Warp : public FullscreenFX { + const idMaterial* material; + bool grabberEnabled; + int startWarpTime; + + void DrawWarp( WarpPolygon_t wp, float interp ); + +public: + virtual void Initialize(); + virtual bool Active(); + virtual void HighQuality(); + + void EnableGrabber( bool active ) { grabberEnabled = active; startWarpTime = gameLocal.slow.time; }; + + virtual void Save( idSaveGame *savefile ); + virtual void Restore( idRestoreGame *savefile ); +}; + +/* +================== +FullscreenFX_EnviroSuit +================== +*/ +class FullscreenFX_EnviroSuit : public FullscreenFX { + const idMaterial* material; + +public: + virtual void Initialize(); + virtual bool Active(); + virtual void HighQuality(); +}; + +/* +================== +FullscreenFX_DoubleVision +================== +*/ +class FullscreenFX_DoubleVision : public FullscreenFX { + const idMaterial* material; + +public: + virtual void Initialize(); + virtual bool Active(); + virtual void HighQuality(); +}; + +/* +================== +FullscreenFX_InfluenceVision +================== +*/ +class FullscreenFX_InfluenceVision : public FullscreenFX { + +public: + virtual void Initialize(); + virtual bool Active(); + virtual void HighQuality(); +}; + +/* +================== +FullscreenFX_Bloom +================== +*/ +class FullscreenFX_Bloom : public FullscreenFX { + const idMaterial* drawMaterial; + const idMaterial* initMaterial; + const idMaterial* currentMaterial; + + float currentIntensity; + float targetIntensity; + +public: + virtual void Initialize(); + virtual bool Active(); + virtual void HighQuality(); + + virtual void Save( idSaveGame *savefile ); + virtual void Restore( idRestoreGame *savefile ); +}; + + + +/* +================== +FullscreenFXManager +================== +*/ +class FullscreenFXManager { + idList fx; + bool highQualityMode; + idVec2 shiftScale; + + idPlayerView *playerView; + const idMaterial* blendBackMaterial; + + void CreateFX( idStr name, idStr fxtype, int fade ); + +public: + FullscreenFXManager(); + virtual ~FullscreenFXManager(); + + void Initialize( idPlayerView *pv ); + + void Process( const renderView_t *view ); + void CaptureCurrentRender(); + void Blendback( float alpha ); + + idVec2 GetShiftScale() { return shiftScale; }; + idPlayerView* GetPlayerView() { return playerView; }; + idPlayer* GetPlayer() { return gameLocal.GetLocalPlayer(); }; + + int GetNum() { return fx.Num(); }; + FullscreenFX* GetFX( int index ) { return fx[index]; }; + FullscreenFX* FindFX( idStr name ); + + void Save( idSaveGame *savefile ); + void Restore( idRestoreGame *savefile ); +}; + +#endif + + + + + + + + + class idPlayerView { public: idPlayerView(); @@ -93,15 +390,13 @@ class idPlayerView { private: void SingleView( idUserInterface *hud, const renderView_t *view ); - void DoubleVision( idUserInterface *hud, const renderView_t *view, int offset ); - void BerserkVision( idUserInterface *hud, const renderView_t *view ); - void InfluenceVision( idUserInterface *hud, const renderView_t *view ); void ScreenFade(); screenBlob_t * GetScreenBlob(); screenBlob_t screenBlobs[MAX_SCREEN_BLOBS]; +public: int dvFinishTime; // double vision will be stopped at this time const idMaterial * dvMaterial; // material to take the double vision screen shot @@ -129,6 +424,14 @@ class idPlayerView { idPlayer * player; renderView_t view; + +#ifdef _D3XP + FullscreenFXManager *fxManager; + +public: + int AddWarp( idVec3 worldOrigin, float centerx, float centery, float initialRadius, float durationMsec ); + void FreeWarp( int id ); +#endif }; #endif /* !__GAME_PLAYERVIEW_H__ */ diff --git a/game/Projectile.cpp b/game/Projectile.cpp index c353ca0c..8011598a 100644 --- a/game/Projectile.cpp +++ b/game/Projectile.cpp @@ -35,6 +35,7 @@ If you have questions concerning this license or the applicable additional terms #include "Player.h" #include "Mover.h" #include "SmokeParticles.h" +#include "Misc.h" #include "Projectile.h" @@ -56,12 +57,23 @@ const idEventDef EV_Fizzle( "", NULL ); const idEventDef EV_RadiusDamage( "", "e" ); const idEventDef EV_GetProjectileState( "getProjectileState", NULL, 'd' ); +#ifdef _D3XP +const idEventDef EV_CreateProjectile( "projectileCreateProjectile", "evv" ); +const idEventDef EV_LaunchProjectile( "projectileLaunchProjectile", "vvv" ); +const idEventDef EV_SetGravity( "setGravity", "f" ); +#endif + CLASS_DECLARATION( idEntity, idProjectile ) EVENT( EV_Explode, idProjectile::Event_Explode ) EVENT( EV_Fizzle, idProjectile::Event_Fizzle ) EVENT( EV_Touch, idProjectile::Event_Touch ) EVENT( EV_RadiusDamage, idProjectile::Event_RadiusDamage ) EVENT( EV_GetProjectileState, idProjectile::Event_GetProjectileState ) +#ifdef _D3XP + EVENT( EV_CreateProjectile, idProjectile::Event_CreateProjectile ) + EVENT( EV_LaunchProjectile, idProjectile::Event_LaunchProjectile ) + EVENT( EV_SetGravity, idProjectile::Event_SetGravity ) +#endif END_CLASS /* @@ -132,6 +144,10 @@ void idProjectile::Save( idSaveGame *savefile ) const { savefile->WriteParticle( smokeFly ); savefile->WriteInt( smokeFlyTime ); +#ifdef _D3XP + savefile->WriteInt( originalTimeGroup ); +#endif + savefile->WriteInt( (int)state ); savefile->WriteFloat( damagePower ); @@ -165,6 +181,10 @@ void idProjectile::Restore( idRestoreGame *savefile ) { savefile->ReadParticle( smokeFly ); savefile->ReadInt( smokeFlyTime ); +#ifdef _D3XP + savefile->ReadInt( originalTimeGroup ); +#endif + savefile->ReadInt( (int &)state ); savefile->ReadFloat( damagePower ); @@ -179,8 +199,18 @@ void idProjectile::Restore( idRestoreGame *savefile ) { idVec3 dir; dir = physicsObj.GetLinearVelocity(); dir.NormalizeFast(); +#ifdef _D3XP + gameLocal.smokeParticles->EmitSmoke( smokeFly, gameLocal.time, gameLocal.random.RandomFloat(), GetPhysics()->GetOrigin(), GetPhysics()->GetAxis(), timeGroup /*_D3XP*/ ); +#else gameLocal.smokeParticles->EmitSmoke( smokeFly, gameLocal.time, gameLocal.random.RandomFloat(), GetPhysics()->GetOrigin(), GetPhysics()->GetAxis() ); +#endif // _D3XP + } + +#ifdef _D3XP + if ( lightDefHandle >= 0 ) { + lightDefHandle = gameRenderWorld->AddLightDef( &renderLight ); } +#endif } /* @@ -243,6 +273,12 @@ void idProjectile::Create( idEntity *owner, const idVec3 &start, const idVec3 &d damagePower = 1.0f; +#ifdef _D3XP + if(spawnArgs.GetBool("reset_time_offset", "0")) { + renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time ); + } +#endif + UpdateVisuals(); state = CREATED; @@ -362,6 +398,13 @@ void idProjectile::Launch( const idVec3 &start, const idVec3 &dir, const idVec3 clipMask |= CONTENTS_PROJECTILE; } +#ifdef _D3XP + if ( !idStr::Cmp( this->GetEntityDefName(), "projectile_helltime_killer" ) ) { + contents = CONTENTS_MOVEABLECLIP; + clipMask = CONTENTS_MOVEABLECLIP; + } +#endif + // don't do tracers on client, we don't know origin and direction if ( spawnArgs.GetBool( "tracers" ) && gameLocal.random.RandomFloat() > 0.5f ) { SetModel( spawnArgs.GetString( "model_tracer" ) ); @@ -417,6 +460,10 @@ void idProjectile::Launch( const idVec3 &start, const idVec3 &dir, const idVec3 smokeFlyTime = gameLocal.time; } +#ifdef _D3XP + originalTimeGroup = timeGroup; +#endif + // used for the plasma bolts but may have other uses as well if ( projectileFlags.randomShaderSpin ) { float f = gameLocal.random.RandomFloat(); @@ -453,7 +500,12 @@ void idProjectile::Think( void ) { if ( smokeFly != NULL && smokeFlyTime && !IsHidden() ) { idVec3 dir = -GetPhysics()->GetLinearVelocity(); dir.Normalize(); +#ifdef _D3XP + SetTimeState ts(originalTimeGroup); + if ( !gameLocal.smokeParticles->EmitSmoke( smokeFly, smokeFlyTime, gameLocal.random.RandomFloat(), GetPhysics()->GetOrigin(), dir.ToMat3(), timeGroup /*_D3XP*/ ) ) { +#else if ( !gameLocal.smokeParticles->EmitSmoke( smokeFly, smokeFlyTime, gameLocal.random.RandomFloat(), GetPhysics()->GetOrigin(), dir.ToMat3() ) ) { +#endif // _D3XP smokeFlyTime = gameLocal.time; } } @@ -830,6 +882,29 @@ void idProjectile::Explode( const trace_t &collision, idEntity *ignore ) { } } +#ifdef _D3XP + // If the explosion is in liquid, spawn a particle splash + idVec3 testOrg = GetPhysics()->GetOrigin(); + int testC = gameLocal.clip.Contents( testOrg, NULL, mat3_identity, CONTENTS_WATER, this ); + if ( testC & CONTENTS_WATER ) { + idFuncEmitter *splashEnt; + idDict splashArgs; + + splashArgs.Set( "model", "sludgebulletimpact.prt" ); + splashArgs.Set( "start_off", "1" ); + splashEnt = static_cast( gameLocal.SpawnEntityType( idFuncEmitter::Type, &splashArgs ) ); + + splashEnt->GetPhysics()->SetOrigin( testOrg ); + splashEnt->PostEventMS( &EV_Activate, 0, this ); + splashEnt->PostEventMS( &EV_Remove, 1500 ); + + // HACK - if this is a chaingun bullet, don't do the normal effect + if ( !idStr::Cmp( spawnArgs.GetString( "def_damage" ), "damage_bullet_chaingun" ) ) { + fxname = NULL; + } + } +#endif + if ( fxname && *fxname ) { SetModel( fxname ); renderEntity.shaderParms[SHADERPARM_RED] = @@ -844,18 +919,47 @@ void idProjectile::Explode( const trace_t &collision, idEntity *ignore ) { // explosion light light_shader = spawnArgs.GetString( "mtr_explode_light_shader" ); + +#ifdef CTF + if ( gameLocal.mpGame.IsGametypeFlagBased() && gameLocal.serverInfo.GetBool("si_midnight") ) + { + light_shader = "lights/midnight_grenade"; + } +#endif + if ( *light_shader ) { renderLight.shader = declManager->FindMaterial( light_shader, false ); renderLight.pointLight = true; renderLight.lightRadius[0] = renderLight.lightRadius[1] = renderLight.lightRadius[2] = spawnArgs.GetFloat( "explode_light_radius" ); + +#ifdef CTF + // Midnight ctf + if ( gameLocal.mpGame.IsGametypeFlagBased() && gameLocal.serverInfo.GetBool("si_midnight") ) + { + renderLight.lightRadius[0] = + renderLight.lightRadius[1] = + renderLight.lightRadius[2] = spawnArgs.GetFloat( "explode_light_radius" ) * 2; + } + +#endif + spawnArgs.GetVector( "explode_light_color", "1 1 1", lightColor ); renderLight.shaderParms[SHADERPARM_RED] = lightColor.x; renderLight.shaderParms[SHADERPARM_GREEN] = lightColor.y; renderLight.shaderParms[SHADERPARM_BLUE] = lightColor.z; renderLight.shaderParms[SHADERPARM_ALPHA] = 1.0f; renderLight.shaderParms[SHADERPARM_TIMEOFFSET] = -MS2SEC( gameLocal.time ); + +#ifdef CTF + // Midnight ctf + if ( gameLocal.mpGame.IsGametypeFlagBased() && gameLocal.serverInfo.GetBool("si_midnight") ) + { + light_fadetime = 3.0f; + } + else +#endif light_fadetime = spawnArgs.GetFloat( "explode_light_fadetime", "0.5" ); lightStartTime = gameLocal.time; lightEndTime = gameLocal.time + SEC2MS( light_fadetime ); @@ -1005,6 +1109,12 @@ void idProjectile::Event_Touch( idEntity *other, trace_t *trace ) { return; } +#ifdef CTF + // Projectiles do not collide with flags + if ( other->IsType( idItemTeam::Type ) ) + return; +#endif + if ( other != owner.GetEntity() ) { trace_t collision; @@ -1018,6 +1128,75 @@ void idProjectile::Event_Touch( idEntity *other, trace_t *trace ) { } } +#ifdef _D3XP +/* +================ +idProjectile::CatchProjectile +================ +*/ +void idProjectile::CatchProjectile( idEntity* o, const char* reflectName ) { + idEntity *prevowner = owner.GetEntity(); + + owner = o; + physicsObj.GetClipModel()->SetOwner( o ); + + if ( this->IsType( idGuidedProjectile::Type ) ) { + idGuidedProjectile *proj = static_cast(this); + + proj->SetEnemy( prevowner ); + } + + idStr s = spawnArgs.GetString( "def_damage" ); + s += reflectName; + + const idDict *damageDef = gameLocal.FindEntityDefDict( s, false ); + if ( damageDef ) { + spawnArgs.Set( "def_damage", s ); + } +} + +/* +================ +idProjectile::GetProjectileState +================ +*/ +int idProjectile::GetProjectileState( void ) { + + return (int)state; +} + +/* +================ +idProjectile::Event_CreateProjectile +================ +*/ +void idProjectile::Event_CreateProjectile( idEntity *owner, const idVec3 &start, const idVec3 &dir ) { + Create(owner, start, dir); +} + +/* +================ +idProjectile::Event_LaunchProjectile +================ +*/ +void idProjectile::Event_LaunchProjectile( const idVec3 &start, const idVec3 &dir, const idVec3 &pushVelocity ) { + Launch(start, dir, pushVelocity); +} + +/* +================ +idProjectile::Event_SetGravity +================ +*/ +void idProjectile::Event_SetGravity( float gravity ) { + idVec3 gravVec; + + gravVec = gameLocal.GetGravity(); + gravVec.NormalizeFast(); + physicsObj.SetGravity(gravVec * gravity); +} +#endif + /* ================= idProjectile::ClientPredictionCollide @@ -1225,7 +1404,14 @@ bool idProjectile::ClientReceiveEvent( int event, int time, const idBitMsg &msg =============================================================================== */ +#ifdef _D3XP +const idEventDef EV_SetEnemy( "setEnemy", "E" ); +#endif + CLASS_DECLARATION( idProjectile, idGuidedProjectile ) +#ifdef _D3XP + EVENT( EV_SetEnemy, idGuidedProjectile::Event_SetEnemy ) +#endif END_CLASS /* @@ -1439,6 +1625,14 @@ void idGuidedProjectile::Launch( const idVec3 &start, const idVec3 &dir, const i UpdateVisuals(); } +#ifdef _D3XP +void idGuidedProjectile::SetEnemy( idEntity *ent ) { + enemy = ent; +} +void idGuidedProjectile::Event_SetEnemy(idEntity *ent) { + SetEnemy(ent); +} +#endif /* =============================================================================== @@ -1559,7 +1753,11 @@ void idSoulCubeMissile::Think( void ) { if ( killPhase ) { // orbit the mob, cascading down if ( gameLocal.time < orbitTime + 1500 ) { +#ifdef _D3XP + if ( !gameLocal.smokeParticles->EmitSmoke( smokeKill, smokeKillTime, gameLocal.random.CRandomFloat(), orbitOrg, mat3_identity, timeGroup /*_D3XP*/ ) ) { +#else if ( !gameLocal.smokeParticles->EmitSmoke( smokeKill, smokeKillTime, gameLocal.random.CRandomFloat(), orbitOrg, mat3_identity ) ) { +#endif // _D3XP smokeKillTime = gameLocal.time; } } @@ -1807,7 +2005,28 @@ void idBFGProjectile::Think( void ) { continue; } idPlayer *player = ( beamTargets[i].target.GetEntity()->IsType( idPlayer::Type ) ) ? static_cast( beamTargets[i].target.GetEntity() ) : NULL; +#ifdef _D3XP + // Major hack for end boss. :( + idAnimatedEntity *beamEnt; + idVec3 org; + bool forceDamage = false; + + beamEnt = static_cast(beamTargets[i].target.GetEntity()); + if ( !idStr::Cmp( beamEnt->GetEntityDefName(), "monster_boss_d3xp_maledict" ) ) { + SetTimeState ts( beamEnt->timeGroup ); + idMat3 temp; + jointHandle_t bodyJoint; + + bodyJoint = beamEnt->GetAnimator()->GetJointHandle( "Chest1" ); + beamEnt->GetJointWorldTransform( bodyJoint, gameLocal.time, org, temp ); + + forceDamage = true; + } else { + org = beamEnt->GetPhysics()->GetAbsBounds().GetCenter(); + } +#else idVec3 org = beamTargets[i].target.GetEntity()->GetPhysics()->GetAbsBounds().GetCenter(); +#endif beamTargets[i].renderEntity.origin = GetPhysics()->GetOrigin(); beamTargets[i].renderEntity.shaderParms[ SHADERPARM_BEAM_END_X ] = org.x; beamTargets[i].renderEntity.shaderParms[ SHADERPARM_BEAM_END_Y ] = org.y; @@ -1818,7 +2037,11 @@ void idBFGProjectile::Think( void ) { beamTargets[i].renderEntity.shaderParms[ SHADERPARM_ALPHA ] = 1.0f; if ( gameLocal.time > nextDamageTime ) { bool bfgVision = true; +#ifdef _D3XP + if ( damageFreq && *(const char *)damageFreq && beamTargets[i].target.GetEntity() && ( forceDamage || beamTargets[i].target.GetEntity()->CanDamage( GetPhysics()->GetOrigin(), org ) ) ) { +#else if ( damageFreq && *(const char *)damageFreq && beamTargets[i].target.GetEntity() && beamTargets[i].target.GetEntity()->CanDamage( GetPhysics()->GetOrigin(), org ) ) { +#endif org = beamTargets[i].target.GetEntity()->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin(); org.Normalize(); beamTargets[i].target.GetEntity()->Damage( this, owner.GetEntity(), org, damageFreq, ( damagePower ) ? damagePower : 1.0f, INVALID_JOINT ); @@ -1946,6 +2169,50 @@ void idBFGProjectile::Launch( const idVec3 &start, const idVec3 &dir, const idVe bt.modelDefHandle = gameRenderWorld->AddEntityDef( &bt.renderEntity ); beamTargets.Append( bt ); } + +#ifdef _D3XP + // Major hack for end boss. :( + idAnimatedEntity *maledict = static_cast(gameLocal.FindEntity( "monster_boss_d3xp_maledict_1" )); + + if ( maledict ) { + SetTimeState ts( maledict->timeGroup ); + + idVec3 realPoint; + idMat3 temp; + float dist; + jointHandle_t bodyJoint; + + bodyJoint = maledict->GetAnimator()->GetJointHandle( "Chest1" ); + maledict->GetJointWorldTransform( bodyJoint, gameLocal.time, realPoint, temp ); + + dist = idVec3( realPoint - GetPhysics()->GetOrigin() ).Length(); + + if ( dist < radius ) { + beamTarget_t bt; + memset( &bt.renderEntity, 0, sizeof( renderEntity_t ) ); + bt.renderEntity.origin = GetPhysics()->GetOrigin(); + bt.renderEntity.axis = GetPhysics()->GetAxis(); + bt.renderEntity.shaderParms[ SHADERPARM_BEAM_WIDTH ] = beamWidth; + bt.renderEntity.shaderParms[ SHADERPARM_RED ] = 1.0f; + bt.renderEntity.shaderParms[ SHADERPARM_GREEN ] = 1.0f; + bt.renderEntity.shaderParms[ SHADERPARM_BLUE ] = 1.0f; + bt.renderEntity.shaderParms[ SHADERPARM_ALPHA ] = 1.0f; + bt.renderEntity.shaderParms[ SHADERPARM_DIVERSITY] = gameLocal.random.CRandomFloat() * 0.75; + bt.renderEntity.hModel = renderModelManager->FindModel( "_beam" ); + bt.renderEntity.callback = NULL; + bt.renderEntity.numJoints = 0; + bt.renderEntity.joints = NULL; + bt.renderEntity.bounds.Clear(); + bt.renderEntity.customSkin = declManager->FindSkin( skin ); + bt.target = maledict; + bt.modelDefHandle = gameRenderWorld->AddEntityDef( &bt.renderEntity ); + beamTargets.Append( bt ); + + numListedEntities++; + } + } +#endif + if ( numListedEntities ) { StartSound( "snd_beam", SND_CHANNEL_BODY2, 0, false, NULL ); } @@ -2083,6 +2350,9 @@ void idDebris::Create( idEntity *owner, const idVec3 &start, const idMat3 &axis smokeFly = NULL; smokeFlyTime = 0; sndBounce = NULL; +#ifdef _D3XP + noGrab = true; +#endif UpdateVisuals(); } @@ -2251,7 +2521,11 @@ void idDebris::Launch( void ) { if ( *smokeName != '\0' ) { smokeFly = static_cast( declManager->FindType( DECL_PARTICLE, smokeName ) ); smokeFlyTime = gameLocal.time; +#ifdef _D3XP + gameLocal.smokeParticles->EmitSmoke( smokeFly, smokeFlyTime, gameLocal.random.CRandomFloat(), GetPhysics()->GetOrigin(), GetPhysics()->GetAxis(), timeGroup /*_D3XP*/ ); +#else gameLocal.smokeParticles->EmitSmoke( smokeFly, smokeFlyTime, gameLocal.random.CRandomFloat(), GetPhysics()->GetOrigin(), GetPhysics()->GetAxis() ); +#endif // _D3XP } const char *sndName = spawnArgs.GetString( "snd_bounce" ); @@ -2274,7 +2548,11 @@ void idDebris::Think( void ) { Present(); if ( smokeFly && smokeFlyTime ) { +#ifdef _D3XP + if ( !gameLocal.smokeParticles->EmitSmoke( smokeFly, smokeFlyTime, gameLocal.random.CRandomFloat(), GetPhysics()->GetOrigin(), GetPhysics()->GetAxis(), timeGroup /*_D3XP*/ ) ) { +#else if ( !gameLocal.smokeParticles->EmitSmoke( smokeFly, smokeFlyTime, gameLocal.random.CRandomFloat(), GetPhysics()->GetOrigin(), GetPhysics()->GetAxis() ) ) { +#endif // _D3XP smokeFlyTime = 0; } } @@ -2326,7 +2604,11 @@ void idDebris::Fizzle( void ) { if ( *smokeName != '\0' ) { smokeFly = static_cast( declManager->FindType( DECL_PARTICLE, smokeName ) ); smokeFlyTime = gameLocal.time; +#ifdef _D3XP + gameLocal.smokeParticles->EmitSmoke( smokeFly, smokeFlyTime, gameLocal.random.CRandomFloat(), GetPhysics()->GetOrigin(), GetPhysics()->GetAxis(), timeGroup /*_D3XP*/ ); +#else gameLocal.smokeParticles->EmitSmoke( smokeFly, smokeFlyTime, gameLocal.random.CRandomFloat(), GetPhysics()->GetOrigin(), GetPhysics()->GetAxis() ); +#endif // _D3XP } fl.takedamage = false; @@ -2366,7 +2648,11 @@ void idDebris::Explode( void ) { if ( *smokeName != '\0' ) { smokeFly = static_cast( declManager->FindType( DECL_PARTICLE, smokeName ) ); smokeFlyTime = gameLocal.time; +#ifdef _D3XP + gameLocal.smokeParticles->EmitSmoke( smokeFly, smokeFlyTime, gameLocal.random.CRandomFloat(), GetPhysics()->GetOrigin(), GetPhysics()->GetAxis(), timeGroup /*_D3XP*/ ); +#else gameLocal.smokeParticles->EmitSmoke( smokeFly, smokeFlyTime, gameLocal.random.CRandomFloat(), GetPhysics()->GetOrigin(), GetPhysics()->GetAxis() ); +#endif // _D3XP } fl.takedamage = false; diff --git a/game/Projectile.h b/game/Projectile.h index 3ada8a3d..ed2433a0 100644 --- a/game/Projectile.h +++ b/game/Projectile.h @@ -60,6 +60,13 @@ public : virtual void FreeLightDef( void ); idEntity * GetOwner( void ) const; +#ifdef _D3XP + void CatchProjectile( idEntity* o, const char* reflectName ); + int GetProjectileState( void ); + void Event_CreateProjectile( idEntity *owner, const idVec3 &start, const idVec3 &dir ); + void Event_LaunchProjectile( const idVec3 &start, const idVec3 &dir, const idVec3 &pushVelocity ); + void Event_SetGravity( float gravity ); +#endif virtual void Think( void ); virtual void Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ); @@ -110,6 +117,10 @@ public : const idDeclParticle * smokeFly; int smokeFlyTime; +#ifdef _D3XP + int originalTimeGroup; +#endif + typedef enum { // must update these in script/doom_defs.script if changed SPAWNED = 0, @@ -146,6 +157,10 @@ public : void Spawn( void ); virtual void Think( void ); virtual void Launch( const idVec3 &start, const idVec3 &dir, const idVec3 &pushVelocity, const float timeSinceFire = 0.0f, const float launchPower = 1.0f, const float dmgPower = 1.0f ); +#ifdef _D3XP + void SetEnemy( idEntity *ent ); + void Event_SetEnemy(idEntity *ent); +#endif protected: float speed; diff --git a/game/Pvs.cpp b/game/Pvs.cpp index 16e845a6..46e16f11 100644 --- a/game/Pvs.cpp +++ b/game/Pvs.cpp @@ -1420,3 +1420,38 @@ void idPVS::ReadPVS( const pvsHandle_t handle, const idBitMsg &msg ) { } #endif + + +#ifdef _D3XP +/* +================ +idPVS::CheckAreasForPortalSky +================ +*/ +bool idPVS::CheckAreasForPortalSky( const pvsHandle_t handle, const idVec3 &origin ) { + int j, sourceArea; + + if ( handle.i < 0 || handle.i >= MAX_CURRENT_PVS || handle.h != currentPVS[handle.i].handle.h ) { + return false; + } + + sourceArea = gameRenderWorld->PointInArea( origin ); + + if ( sourceArea == -1 ) { + return false; + } + + for ( j = 0; j < numAreas; j++ ) { + + if ( !( currentPVS[handle.i].pvs[j>>3] & (1 << (j&7)) ) ) { + continue; + } + + if ( gameRenderWorld->CheckAreaForPortalSky( j ) ) { + return true; + } + } + + return false; +} +#endif diff --git a/game/Pvs.h b/game/Pvs.h index 963b1786..f97d6cfe 100644 --- a/game/Pvs.h +++ b/game/Pvs.h @@ -97,6 +97,10 @@ class idPVS { void ReadPVS( const pvsHandle_t handle, const idBitMsg &msg ); #endif +#ifdef _D3XP + bool CheckAreasForPortalSky( const pvsHandle_t handle, const idVec3 &origin ); +#endif + private: int numAreas; int numPortals; diff --git a/game/SmokeParticles.cpp b/game/SmokeParticles.cpp index e63307d4..bc8b277f 100644 --- a/game/SmokeParticles.cpp +++ b/game/SmokeParticles.cpp @@ -28,6 +28,7 @@ If you have questions concerning this license or the applicable additional terms #include "sys/platform.h" #include "renderer/ModelManager.h" +#include "Entity.h" #include "Game_local.h" #include "SmokeParticles.h" @@ -130,7 +131,18 @@ void idSmokeParticles::FreeSmokes( void ) { for ( last = NULL, smoke = active->smokes; smoke; smoke = next ) { next = smoke->next; +#ifdef _D3XP + float frac; + + if ( smoke->timeGroup ) { + frac = (float)( gameLocal.fast.time - smoke->privateStartTime ) / ( stage->particleLife * 1000 ); + } + else { + frac = (float)( gameLocal.slow.time - smoke->privateStartTime ) / ( stage->particleLife * 1000 ); + } +#else float frac = (float)( gameLocal.time - smoke->privateStartTime ) / ( stage->particleLife * 1000 ); +#endif if ( frac >= 1.0f ) { // remove the particle from the stage list if ( last != NULL ) { @@ -163,8 +175,15 @@ idSmokeParticles::EmitSmoke Called by game code to drop another particle into the list ================ */ +#ifdef _D3XP +bool idSmokeParticles::EmitSmoke( const idDeclParticle *smoke, const int systemStartTime, const float diversity, const idVec3 &origin, const idMat3 &axis, int timeGroup /*_D3XP*/ ) { +#else bool idSmokeParticles::EmitSmoke( const idDeclParticle *smoke, const int systemStartTime, const float diversity, const idVec3 &origin, const idMat3 &axis ) { +#endif // _D3XP bool continues = false; +#ifdef _D3XP + SetTimeState ts( timeGroup ); +#endif if ( !smoke ) { return false; @@ -221,7 +240,7 @@ bool idSmokeParticles::EmitSmoke( const idDeclParticle *smoke, const int systemS if ( nowCount >= stage->totalParticles ) { nowCount = stage->totalParticles-1; } - prevCount = floor( ((float)( deltaMsec - USERCMD_MSEC ) / finalParticleTime) * stage->totalParticles ); + prevCount = floor( ((float)( deltaMsec - gameLocal.msec /*_D3XP - FIX - was USERCMD_MSEC*/ ) / finalParticleTime) * stage->totalParticles ); if ( prevCount < -1 ) { prevCount = -1; } @@ -266,6 +285,9 @@ bool idSmokeParticles::EmitSmoke( const idDeclParticle *smoke, const int systemS freeSmokes = freeSmokes->next; numActiveSmokes++; +#ifdef _D3XP + newSmoke->timeGroup = timeGroup; +#endif newSmoke->index = prevCount; newSmoke->axis = axis; newSmoke->origin = origin; @@ -340,7 +362,16 @@ bool idSmokeParticles::UpdateRenderEntity( renderEntity_s *renderEntity, const r for ( last = NULL, smoke = active->smokes; smoke; smoke = next ) { next = smoke->next; - g.frac = (float)( gameLocal.time - smoke->privateStartTime ) / ( stage->particleLife * 1000 ); +#ifdef _D3XP + if ( smoke->timeGroup ) { + g.frac = (float)( gameLocal.fast.time - smoke->privateStartTime ) / (stage->particleLife * 1000); + } + else { + g.frac = (float)( gameLocal.time - smoke->privateStartTime ) / (stage->particleLife * 1000); + } +#else + g.frac = (float)( gameLocal.time - smoke->privateStartTime ) / (stage->particleLife * 1000); +#endif if ( g.frac >= 1.0f ) { // remove the particle from the stage list if ( last != NULL ) { diff --git a/game/SmokeParticles.h b/game/SmokeParticles.h index 7fafb8a2..3d3cc951 100644 --- a/game/SmokeParticles.h +++ b/game/SmokeParticles.h @@ -64,6 +64,9 @@ typedef struct singleSmoke_s { idRandom random; idVec3 origin; idMat3 axis; +#ifdef _D3XP + int timeGroup; +#endif } singleSmoke_t; typedef struct { @@ -81,8 +84,13 @@ class idSmokeParticles { void Shutdown( void ); // spits out a particle, returning false if the system will not emit any more particles in the future +#ifdef _D3XP bool EmitSmoke( const idDeclParticle *smoke, const int startTime, const float diversity, - const idVec3 &origin, const idMat3 &axis ); + const idVec3 &origin, const idMat3 &axis, int timeGroup /*_D3XP*/ ); +#else + bool EmitSmoke( const idDeclParticle* smoke, const int startTime, const float diversity, + const idVec3& origin, const idMat3& axis ); +#endif // _D3XP // free old smokes void FreeSmokes( void ); diff --git a/game/Target.cpp b/game/Target.cpp index 1912a788..3a3f74cd 100644 --- a/game/Target.cpp +++ b/game/Target.cpp @@ -788,6 +788,15 @@ void idTarget_SetInfluence::Save( idSaveGame *savefile ) const { savefile->WriteBool( soundFaded ); savefile->WriteBool( restoreOnTrigger ); + +#ifdef _D3XP + savefile->WriteInt( savedGuiList.Num() ); + for( i = 0; i < savedGuiList.Num(); i++ ) { + for(int j = 0; j < MAX_RENDERENTITY_GUI; j++) { + savefile->WriteUserInterface(savedGuiList[i].gui[j], savedGuiList[i].gui[j] ? savedGuiList[i].gui[j]->IsUniqued() : false); + } + } +#endif } /* @@ -845,6 +854,17 @@ void idTarget_SetInfluence::Restore( idRestoreGame *savefile ) { savefile->ReadBool( soundFaded ); savefile->ReadBool( restoreOnTrigger ); + +#ifdef _D3XP + savefile->ReadInt( num ); + for( i = 0; i < num; i++ ) { + SavedGui_t temp; + for(int j = 0; j < MAX_RENDERENTITY_GUI; j++) { + savefile->ReadUserInterface(temp.gui[j]); + } + savedGuiList.Append( temp ); + } +#endif } /* @@ -914,6 +934,9 @@ void idTarget_SetInfluence::Event_GatherEntities() { lightList.Clear(); guiList.Clear(); soundList.Clear(); +#ifdef _D3XP + savedGuiList.Clear(); +#endif if ( spawnArgs.GetBool( "effect_all" ) ) { lights = sounds = guis = models = vision = true; @@ -942,6 +965,10 @@ void idTarget_SetInfluence::Event_GatherEntities() { } if ( guis && ent->GetRenderEntity() && ent->GetRenderEntity()->gui[ 0 ] && ent->spawnArgs.FindKey( "gui_demonic" ) ) { guiList.Append( ent->entityNumber ); +#ifdef _D3XP + SavedGui_t temp; + savedGuiList.Append(temp); +#endif continue; } if ( ent->IsType( idStaticEntity::Type ) && ent->spawnArgs.FindKey( "color_demonic" ) ) { @@ -1075,8 +1102,13 @@ void idTarget_SetInfluence::Event_Activate( idEntity *activator ) { continue; } update = false; + for ( j = 0; j < MAX_RENDERENTITY_GUI; j++ ) { if ( ent->GetRenderEntity()->gui[ j ] && ent->spawnArgs.FindKey( j == 0 ? "gui_demonic" : va( "gui_demonic%d", j+1 ) ) ) { +#ifdef _D3XP + //Backup the old one + savedGuiList[i].gui[j] = ent->GetRenderEntity()->gui[ j ]; +#endif ent->GetRenderEntity()->gui[ j ] = uiManager->FindGui( ent->spawnArgs.GetString( j == 0 ? "gui_demonic" : va( "gui_demonic%d", j+1 ) ), true ); update = true; } @@ -1200,7 +1232,11 @@ void idTarget_SetInfluence::Event_RestoreInfluence() { update = false; for( j = 0; j < MAX_RENDERENTITY_GUI; j++ ) { if ( ent->GetRenderEntity()->gui[ j ] ) { +#ifdef _D3XP + ent->GetRenderEntity()->gui[ j ] = savedGuiList[i].gui[j]; +#else ent->GetRenderEntity()->gui[ j ] = uiManager->FindGui( ent->spawnArgs.GetString( j == 0 ? "gui" : va( "gui%d", j+1 ) ) ); +#endif update = true; } } diff --git a/game/Target.h b/game/Target.h index a0d2fc75..9c2c0a80 100644 --- a/game/Target.h +++ b/game/Target.h @@ -324,6 +324,13 @@ idTarget_SetInfluence =============================================================================== */ +#ifdef _D3XP +typedef struct SavedGui_s { + SavedGui_s() {memset(gui, 0, sizeof(idUserInterface*)*MAX_RENDERENTITY_GUI); }; + idUserInterface* gui[MAX_RENDERENTITY_GUI]; +} SavedGui_t; +#endif + class idTarget_SetInfluence : public idTarget { public: CLASS_PROTOTYPE( idTarget_SetInfluence ); @@ -356,6 +363,10 @@ class idTarget_SetInfluence : public idTarget { idInterpolatefovSetting; bool soundFaded; bool restoreOnTrigger; + +#ifdef _D3XP + idList savedGuiList; +#endif }; diff --git a/game/Trigger.cpp b/game/Trigger.cpp index 212b2b07..c3943440 100644 --- a/game/Trigger.cpp +++ b/game/Trigger.cpp @@ -399,7 +399,13 @@ void idTrigger_Multi::TriggerAction( idEntity *activator ) { } else { // we can't just remove (this) here, because this is a touch function // called while looping through area links... +#ifdef _D3XP + // If the player spawned inside the trigger, the player Spawn function called Think directly, + // allowing for multiple triggers on a trigger_once. Increasing the nextTriggerTime prevents it. + nextTriggerTime = gameLocal.time + 99999; +#else nextTriggerTime = gameLocal.time + 1; +#endif PostEventMS( &EV_Remove, 0 ); } } @@ -997,8 +1003,26 @@ void idTrigger_Hurt::Event_Touch( idEntity *other, trace_t *trace ) { const char *damage; if ( on && other && gameLocal.time >= nextTime ) { +#ifdef _D3XP + bool playerOnly = spawnArgs.GetBool( "playerOnly" ); + if ( playerOnly ) { + if ( !other->IsType( idPlayer::Type ) ) { + return; + } + } +#endif damage = spawnArgs.GetString( "def_damage", "damage_painTrigger" ); + +#ifdef _D3XP + idVec3 dir = vec3_origin; + if(spawnArgs.GetBool("kick_from_center", "0")) { + dir = other->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin(); + dir.Normalize(); + } + other->Damage( NULL, NULL, dir, damage, 1.0f, INVALID_JOINT ); +#else other->Damage( NULL, NULL, vec3_origin, damage, 1.0f, INVALID_JOINT ); +#endif ActivateTargets( other ); CallScript(); @@ -1190,3 +1214,113 @@ idTrigger_Touch::Disable void idTrigger_Touch::Disable( void ) { BecomeInactive( TH_THINK ); } + +#ifdef CTF +/* +=============================================================================== + + idTrigger_Flag + +=============================================================================== +*/ + +CLASS_DECLARATION( idTrigger_Multi, idTrigger_Flag ) + EVENT( EV_Touch, idTrigger_Flag::Event_Touch ) +END_CLASS + +idTrigger_Flag::idTrigger_Flag( void ) { + team = -1; + player = false; + eventFlag = NULL; +} + +void idTrigger_Flag::Spawn( void ) { + team = spawnArgs.GetInt( "team", "0" ); + player = spawnArgs.GetBool( "player", "0" ); + + idStr funcname = spawnArgs.GetString( "eventflag", "" ); + if ( funcname.Length() ) { + eventFlag = idEventDef::FindEvent( funcname );// gameLocal.program.FindFunction( funcname );//, &idItemTeam::Type ); + if ( eventFlag == NULL ) { + gameLocal.Warning( "trigger '%s' at (%s) event unknown '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), funcname.c_str() ); + } + } else { + eventFlag = NULL; + } + + idTrigger_Multi::Spawn(); +} + +void idTrigger_Flag::Event_Touch( idEntity *other, trace_t *trace ) { + + idItemTeam * flag = NULL; + + if ( player ) { + if ( !other->IsType( idPlayer::Type ) ) + return; + + idPlayer * player = static_cast(other); + if ( player->carryingFlag == false ) + return; + + if ( team != -1 && ( player->team != team || (player->team != 0 && player->team != 1)) ) + return; + + idItemTeam * flags[2]; + + flags[0] = gameLocal.mpGame.GetTeamFlag( 0 ); + flags[1] = gameLocal.mpGame.GetTeamFlag( 1 ); + + int iFriend = 1 - player->team; // index to the flag player team wants + int iOpp = player->team; // index to the flag opp team wants + + // flag is captured if : + // 1)flag is truely bound to the player + // 2)opponent flag has been return + if ( flags[iFriend]->carried && !flags[iFriend]->dropped && //flags[iFriend]->IsBoundTo( player ) && + !flags[iOpp]->carried && !flags[iOpp]->dropped ) + flag = flags[iFriend]; + else + return; + } else { + if ( !other->IsType( idItemTeam::Type ) ) + return; + + idItemTeam * item = static_cast( other ); + + if ( item->team == team || team == -1 ) { + flag = item; + } + else + return; + } + + if ( flag ) { + switch ( eventFlag->GetNumArgs() ) { + default : + case 0 : + flag->PostEventMS( eventFlag, 0 ); + break; + case 1 : + flag->PostEventMS( eventFlag, 0, 0 ); + break; + case 2 : + flag->PostEventMS( eventFlag, 0, 0, 0 ); + break; + } + +/* + ServerSendEvent( eventFlag->GetEventNum(), NULL, true, false ); + + idThread *thread; + if ( scriptFlag ) { + thread = new idThread(); + thread->CallFunction( flag, scriptFlag, false ); + thread->DelayedStart( 0 ); + } +*/ + idTrigger_Multi::Event_Touch( other, trace ); + } +} + +#endif diff --git a/game/Trigger.h b/game/Trigger.h index 74d503e3..7e4e348a 100644 --- a/game/Trigger.h +++ b/game/Trigger.h @@ -89,7 +89,12 @@ class idTrigger_Multi : public idTrigger { void Save( idSaveGame *savefile ) const; void Restore( idRestoreGame *savefile ); +#ifdef CTF +protected: +#else private: +#endif + float wait; float random; float delay; @@ -287,4 +292,30 @@ class idTrigger_Touch : public idTrigger { void Event_Trigger( idEntity *activator ); }; +#ifdef CTF +/* +=============================================================================== + + Trigger that responces to CTF flags + +=============================================================================== +*/ +class idTrigger_Flag : public idTrigger_Multi { +public: + CLASS_PROTOTYPE( idTrigger_Flag ); + + idTrigger_Flag( void ); + void Spawn( void ); + +private: + int team; + bool player; // flag must be attached/carried by player + + const idEventDef * eventFlag; + + void Event_Touch( idEntity *other, trace_t *trace ); +}; + +#endif /* CTF */ + #endif /* !__GAME_TRIGGER_H__ */ diff --git a/game/Weapon.cpp b/game/Weapon.cpp index a381ae24..c0fa8e5c 100644 --- a/game/Weapon.cpp +++ b/game/Weapon.cpp @@ -36,6 +36,7 @@ If you have questions concerning this license or the applicable additional terms #include "Trigger.h" #include "SmokeParticles.h" #include "WorldSpawn.h" +#include "Misc.h" #include "Weapon.h" @@ -75,6 +76,19 @@ const idEventDef EV_Weapon_AutoReload( "autoReload", NULL, 'f' ); const idEventDef EV_Weapon_NetReload( "netReload" ); const idEventDef EV_Weapon_IsInvisible( "isInvisible", NULL, 'f' ); const idEventDef EV_Weapon_NetEndReload( "netEndReload" ); +#ifdef _D3XP +const idEventDef EV_Weapon_GrabberHasTarget( "grabberHasTarget", NULL, 'd' ); +const idEventDef EV_Weapon_Grabber( "grabber", "d" ); +const idEventDef EV_Weapon_Grabber_SetGrabDistance( "grabberGrabDistance", "f" ); +const idEventDef EV_Weapon_LaunchProjectilesEllipse( "launchProjectilesEllipse", "dffff" ); +const idEventDef EV_Weapon_LaunchPowerup( "launchPowerup", "sfd" ); +const idEventDef EV_Weapon_StartWeaponSmoke( "startWeaponSmoke" ); +const idEventDef EV_Weapon_StopWeaponSmoke( "stopWeaponSmoke" ); +const idEventDef EV_Weapon_StartWeaponParticle( "startWeaponParticle", "s" ); +const idEventDef EV_Weapon_StopWeaponParticle( "stopWeaponParticle", "s" ); +const idEventDef EV_Weapon_StartWeaponLight( "startWeaponLight", "s" ); +const idEventDef EV_Weapon_StopWeaponLight( "stopWeaponLight", "s" ); +#endif // // class def @@ -116,6 +130,19 @@ CLASS_DECLARATION( idAnimatedEntity, idWeapon ) EVENT( EV_Weapon_NetReload, idWeapon::Event_NetReload ) EVENT( EV_Weapon_IsInvisible, idWeapon::Event_IsInvisible ) EVENT( EV_Weapon_NetEndReload, idWeapon::Event_NetEndReload ) +#ifdef _D3XP + EVENT( EV_Weapon_Grabber, idWeapon::Event_Grabber ) + EVENT( EV_Weapon_GrabberHasTarget, idWeapon::Event_GrabberHasTarget ) + EVENT( EV_Weapon_Grabber_SetGrabDistance, idWeapon::Event_GrabberSetGrabDistance ) + EVENT( EV_Weapon_LaunchProjectilesEllipse, idWeapon::Event_LaunchProjectilesEllipse ) + EVENT( EV_Weapon_LaunchPowerup, idWeapon::Event_LaunchPowerup ) + EVENT( EV_Weapon_StartWeaponSmoke, idWeapon::Event_StartWeaponSmoke ) + EVENT( EV_Weapon_StopWeaponSmoke, idWeapon::Event_StopWeaponSmoke ) + EVENT( EV_Weapon_StartWeaponParticle, idWeapon::Event_StartWeaponParticle ) + EVENT( EV_Weapon_StopWeaponParticle, idWeapon::Event_StopWeaponParticle ) + EVENT( EV_Weapon_StartWeaponLight, idWeapon::Event_StartWeaponLight ) + EVENT( EV_Weapon_StopWeaponLight, idWeapon::Event_StopWeaponLight ) +#endif END_CLASS /*********************************************************************** @@ -147,6 +174,9 @@ idWeapon::idWeapon() { guiLightHandle = -1; nozzleGlowHandle = -1; modelDefHandle = -1; +#ifdef _D3XP + grabberState = -1; +#endif berserk = 2; brassDelay = 0; @@ -181,6 +211,12 @@ void idWeapon::Spawn( void ) { worldModel.GetEntity()->fl.networkSync = true; } +#ifdef _D3XP + if ( 1 /*!gameLocal.isMultiplayer*/ ) { + grabber.Initialize(); + } +#endif + thread = new idThread(); thread->ManualDelete(); thread->ManualControl(); @@ -376,6 +412,37 @@ void idWeapon::Save( idSaveGame *savefile ) const { savefile->WriteBool( allowDrop ); savefile->WriteObject( projectileEnt ); +#ifdef _D3XP + savefile->WriteStaticObject( grabber ); + savefile->WriteInt( grabberState ); + + savefile->WriteJoint ( smokeJointView ); + + savefile->WriteInt(weaponParticles.Num()); + for(int i = 0; i < weaponParticles.Num(); i++) { + WeaponParticle_t* part = weaponParticles.GetIndex(i); + savefile->WriteString( part->name ); + savefile->WriteString( part->particlename ); + savefile->WriteBool( part->active ); + savefile->WriteInt( part->startTime ); + savefile->WriteJoint( part->joint ); + savefile->WriteBool( part->smoke ); + if(!part->smoke) { + savefile->WriteObject(part->emitter); + } + } + savefile->WriteInt(weaponLights.Num()); + for(int i = 0; i < weaponLights.Num(); i++) { + WeaponLight_t* light = weaponLights.GetIndex(i); + savefile->WriteString( light->name ); + savefile->WriteBool( light->active ); + savefile->WriteInt( light->startTime ); + savefile->WriteJoint( light->joint ); + savefile->WriteInt( light->lightHandle ); + savefile->WriteRenderLight( light->light ); + } +#endif + } /* @@ -453,12 +520,27 @@ void idWeapon::Restore( idRestoreGame *savefile ) { savefile->ReadInt( guiLightHandle ); savefile->ReadRenderLight( guiLight ); +#ifdef _D3XP + if ( guiLightHandle >= 0 ) { + guiLightHandle = gameRenderWorld->AddLightDef( &guiLight ); + } +#endif savefile->ReadInt( muzzleFlashHandle ); savefile->ReadRenderLight( muzzleFlash ); +#ifdef _D3XP + if ( muzzleFlashHandle >= 0 ) { + muzzleFlashHandle = gameRenderWorld->AddLightDef( &muzzleFlash ); + } +#endif savefile->ReadInt( worldMuzzleFlashHandle ); savefile->ReadRenderLight( worldMuzzleFlash ); +#ifdef _D3XP + if ( worldMuzzleFlashHandle >= 0 ) { + worldMuzzleFlashHandle = gameRenderWorld->AddLightDef( &worldMuzzleFlash ); + } +#endif savefile->ReadVec3( flashColor ); savefile->ReadInt( muzzleFlashEnd ); @@ -516,6 +598,11 @@ void idWeapon::Restore( idRestoreGame *savefile ) { savefile->ReadInt( nozzleGlowHandle ); savefile->ReadRenderLight( nozzleGlow ); +#ifdef _D3XP + if ( nozzleGlowHandle >= 0 ) { + nozzleGlowHandle = gameRenderWorld->AddLightDef( &nozzleGlow ); + } +#endif savefile->ReadVec3( nozzleGlowColor ); savefile->ReadMaterial( nozzleGlowShader ); @@ -529,6 +616,60 @@ void idWeapon::Restore( idRestoreGame *savefile ) { savefile->ReadBool( allowDrop ); savefile->ReadObject( reinterpret_cast( projectileEnt ) ); + +#ifdef _D3XP + savefile->ReadStaticObject( grabber ); + savefile->ReadInt( grabberState ); + + savefile->ReadJoint ( smokeJointView ); + + int particleCount; + savefile->ReadInt( particleCount ); + for(int i = 0; i < particleCount; i++) { + WeaponParticle_t newParticle; + memset(&newParticle, 0, sizeof(newParticle)); + + idStr name, particlename; + savefile->ReadString( name ); + savefile->ReadString( particlename ); + + strcpy( newParticle.name, name.c_str() ); + strcpy( newParticle.particlename, particlename.c_str() ); + + savefile->ReadBool( newParticle.active ); + savefile->ReadInt( newParticle.startTime ); + savefile->ReadJoint( newParticle.joint ); + savefile->ReadBool( newParticle.smoke ); + if(newParticle.smoke) { + newParticle.particle = static_cast( declManager->FindType( DECL_PARTICLE, particlename, false ) ); + } else { + savefile->ReadObject(reinterpret_cast(newParticle.emitter)); + } + + weaponParticles.Set(newParticle.name, newParticle); + } + + int lightCount; + savefile->ReadInt( lightCount ); + for(int i = 0; i < lightCount; i++) { + WeaponLight_t newLight; + memset(&newLight, 0, sizeof(newLight)); + + idStr name; + savefile->ReadString( name ); + strcpy( newLight.name, name.c_str() ); + + savefile->ReadBool( newLight.active ); + savefile->ReadInt( newLight.startTime ); + savefile->ReadJoint( newLight.joint ); + savefile->ReadInt( newLight.lightHandle ); + savefile->ReadRenderLight( newLight.light ); + if ( newLight.lightHandle >= 0 ) { + newLight.lightHandle = gameRenderWorld->AddLightDef( &newLight.light ); + } + weaponLights.Set(newLight.name, newLight); + } +#endif } /*********************************************************************** @@ -658,6 +799,11 @@ void idWeapon::Clear( void ) { lightOn = false; silent_fire = false; +#ifdef _D3XP + grabberState = -1; + grabber.Update( owner, true ); +#endif + ammoType = 0; ammoRequired = 0; ammoClip = 0; @@ -683,6 +829,29 @@ void idWeapon::Clear( void ) { flashJointWorld = INVALID_JOINT; ejectJointWorld = INVALID_JOINT; +#ifdef _D3XP + smokeJointView = INVALID_JOINT; + + //Clean up the weapon particles + for(int i = 0; i < weaponParticles.Num(); i++) { + WeaponParticle_t* part = weaponParticles.GetIndex(i); + if(!part->smoke) { + //Destroy the emitters + part->emitter->PostEventMS(&EV_Remove, 0 ); + } + } + weaponParticles.Clear(); + + //Clean up the weapon lights + for(int i = 0; i < weaponLights.Num(); i++) { + WeaponLight_t* light = weaponLights.GetIndex(i); + if ( light->lightHandle != -1 ) { + gameRenderWorld->FreeLightDef( light->lightHandle ); + } + } + weaponLights.Clear(); +#endif + hasBloodSplat = false; nozzleFx = false; nozzleFxFade = 1500; @@ -850,6 +1019,15 @@ void idWeapon::GetWeaponDef( const char *objectname, int ammoinclip ) { guiLightJointView = animator.GetJointHandle( "guiLight" ); ventLightJointView = animator.GetJointHandle( "ventLight" ); +#ifdef _D3XP + idStr smokeJoint = weaponDef->dict.GetString("smoke_joint"); + if(smokeJoint.Length() > 0) { + smokeJointView = animator.GetJointHandle( smokeJoint ); + } else { + smokeJointView = INVALID_JOINT; + } +#endif + // get the projectile projectileDict.Clear(); @@ -964,6 +1142,10 @@ void idWeapon::GetWeaponDef( const char *objectname, int ammoinclip ) { if ( ammoClip > ammoAvail ) { ammoClip = ammoAvail; } +#ifdef _D3XP + //In D3XP we use ammo as soon as it is moved into the clip. This allows for weapons that share ammo + owner->inventory.UseAmmo(ammoType, ammoClip); +#endif } renderEntity.gui[ 0 ] = NULL; @@ -1014,6 +1196,88 @@ void idWeapon::GetWeaponDef( const char *objectname, int ammoinclip ) { // make sure we have the correct skin UpdateSkin(); + +#ifdef _D3XP + idEntity *ent = worldModel.GetEntity(); + DetermineTimeGroup( weaponDef->dict.GetBool( "slowmo", "0" ) ); + if ( ent ) { + ent->DetermineTimeGroup( weaponDef->dict.GetBool( "slowmo", "0" ) ); + } + + //Initialize the particles + if ( !gameLocal.isMultiplayer ) { + + const idKeyValue *pkv = weaponDef->dict.MatchPrefix( "weapon_particle", NULL ); + while( pkv ) { + WeaponParticle_t newParticle; + memset( &newParticle, 0, sizeof( newParticle ) ); + + idStr name = pkv->GetValue(); + + strcpy(newParticle.name, name.c_str()); + + idStr jointName = weaponDef->dict.GetString(va("%s_joint", name.c_str())); + newParticle.joint = animator.GetJointHandle(jointName.c_str()); + newParticle.smoke = weaponDef->dict.GetBool(va("%s_smoke", name.c_str())); + newParticle.active = false; + newParticle.startTime = 0; + + idStr particle = weaponDef->dict.GetString(va("%s_particle", name.c_str())); + strcpy(newParticle.particlename, particle.c_str()); + + if(newParticle.smoke) { + newParticle.particle = static_cast( declManager->FindType( DECL_PARTICLE, particle, false ) ); + } else { + idDict args; + + const idDeclEntityDef *emitterDef = gameLocal.FindEntityDef( "func_emitter", false ); + args = emitterDef->dict; + args.Set("model", particle.c_str()); + args.SetBool("start_off", true); + + idEntity* ent; + gameLocal.SpawnEntityDef(args, &ent, false); + newParticle.emitter = (idFuncEmitter*)ent; + + newParticle.emitter->BecomeActive(TH_THINK); + } + + weaponParticles.Set(name.c_str(), newParticle); + + pkv = weaponDef->dict.MatchPrefix( "weapon_particle", pkv ); + } + + const idKeyValue *lkv = weaponDef->dict.MatchPrefix( "weapon_light", NULL ); + while( lkv ) { + WeaponLight_t newLight; + memset( &newLight, 0, sizeof( newLight ) ); + + newLight.lightHandle = -1; + newLight.active = false; + newLight.startTime = 0; + + idStr name = lkv->GetValue(); + strcpy(newLight.name, name.c_str()); + + idStr jointName = weaponDef->dict.GetString(va("%s_joint", name.c_str())); + newLight.joint = animator.GetJointHandle(jointName.c_str()); + + idStr shader = weaponDef->dict.GetString(va("%s_shader", name.c_str())); + newLight.light.shader = declManager->FindMaterial( shader, false ); + + float radius = weaponDef->dict.GetFloat(va("%s_radius", name.c_str())); + newLight.light.lightRadius[0] = newLight.light.lightRadius[1] = newLight.light.lightRadius[2] = radius; + newLight.light.pointLight = true; + newLight.light.noShadows = true; + + newLight.light.allowLightInViewID = owner->entityNumber+1; + + weaponLights.Set(name.c_str(), newLight); + + lkv = weaponDef->dict.MatchPrefix( "weapon_light", lkv ); + } + } +#endif } /*********************************************************************** @@ -1070,14 +1334,31 @@ void idWeapon::UpdateGUI( void ) { renderEntity.gui[ 0 ]->SetStateString( "player_ammo", "" ); } else { // show remaining ammo +#ifdef _D3XP + renderEntity.gui[ 0 ]->SetStateString( "player_totalammo", va( "%i", ammoamount) ); +#else renderEntity.gui[ 0 ]->SetStateString( "player_totalammo", va( "%i", ammoamount - inclip) ); +#endif renderEntity.gui[ 0 ]->SetStateString( "player_ammo", ClipSize() ? va( "%i", inclip ) : "--" ); renderEntity.gui[ 0 ]->SetStateString( "player_clips", ClipSize() ? va("%i", ammoamount / ClipSize()) : "--" ); + +#ifdef _D3XP + renderEntity.gui[ 0 ]->SetStateString( "player_allammo", va( "%i/%i", inclip, ammoamount ) ); +#else renderEntity.gui[ 0 ]->SetStateString( "player_allammo", va( "%i/%i", inclip, ammoamount - inclip ) ); +#endif } renderEntity.gui[ 0 ]->SetStateBool( "player_ammo_empty", ( ammoamount == 0 ) ); renderEntity.gui[ 0 ]->SetStateBool( "player_clip_empty", ( inclip == 0 ) ); renderEntity.gui[ 0 ]->SetStateBool( "player_clip_low", ( inclip <= lowAmmo ) ); + +#ifdef _D3XP + //Let the HUD know the total amount of ammo regardless of the ammo required value + renderEntity.gui[ 0 ]->SetStateString( "player_ammo_count", va("%i", AmmoCount())); + + //Grabber Gui Info + renderEntity.gui[ 0 ]->SetStateString( "grabber_state", va("%i", grabberState)); +#endif } /*********************************************************************** @@ -1380,6 +1661,13 @@ void idWeapon::OwnerDied( void ) { if ( isLinked ) { SetState( "OwnerDied", 0 ); thread->Execute(); + +#ifdef _D3XP + // Update the grabber effects + if ( /*!gameLocal.isMultiplayer &&*/ grabberState != -1 ) { + grabber.Update( owner, hide ); + } +#endif } Hide(); @@ -1407,7 +1695,11 @@ void idWeapon::BeginAttack( void ) { } if ( !WEAPON_ATTACK ) { +#ifdef _D3XP + if ( sndHum && grabberState == -1 ) { // _D3XP :: don't stop grabber hum +#else if ( sndHum ) { +#endif // _D3XP StopSound( SND_CHANNEL_BODY, false ); } } @@ -1425,7 +1717,11 @@ void idWeapon::EndAttack( void ) { } if ( WEAPON_ATTACK ) { WEAPON_ATTACK = false; +#ifdef _D3XP + if ( sndHum && grabberState == -1 ) { // _D3XP :: don't stop grabber hum +#else if ( sndHum ) { +#endif // _D3XP StartSoundShader( sndHum, SND_CHANNEL_BODY, 0, false, NULL ); } } @@ -1941,26 +2237,94 @@ void idWeapon::PresentWeapon( bool showViewModel ) { // muzzle smoke if ( showViewModel && !disabled && weaponSmoke && ( weaponSmokeStartTime != 0 ) ) { // use the barrel joint if available + +#ifdef _D3XP + if(smokeJointView != INVALID_JOINT) { + GetGlobalJointTransform( true, smokeJointView, muzzleOrigin, muzzleAxis ); + } else if (barrelJointView != INVALID_JOINT) { + GetGlobalJointTransform( true, barrelJointView, muzzleOrigin, muzzleAxis ); +#else if ( barrelJointView ) { GetGlobalJointTransform( true, barrelJointView, muzzleOrigin, muzzleAxis ); +#endif } else { // default to going straight out the view muzzleOrigin = playerViewOrigin; muzzleAxis = playerViewAxis; } // spit out a particle +#ifdef _D3XP + if ( !gameLocal.smokeParticles->EmitSmoke( weaponSmoke, weaponSmokeStartTime, gameLocal.random.RandomFloat(), muzzleOrigin, muzzleAxis, timeGroup /*_D3XP*/ ) ) { +#else if ( !gameLocal.smokeParticles->EmitSmoke( weaponSmoke, weaponSmokeStartTime, gameLocal.random.RandomFloat(), muzzleOrigin, muzzleAxis ) ) { +#endif // _D3XP weaponSmokeStartTime = ( continuousSmoke ) ? gameLocal.time : 0; } } if ( showViewModel && strikeSmoke && strikeSmokeStartTime != 0 ) { // spit out a particle +#ifdef _D3XP + if ( !gameLocal.smokeParticles->EmitSmoke( strikeSmoke, strikeSmokeStartTime, gameLocal.random.RandomFloat(), strikePos, strikeAxis, timeGroup /*_D3XP*/ ) ) { +#else if ( !gameLocal.smokeParticles->EmitSmoke( strikeSmoke, strikeSmokeStartTime, gameLocal.random.RandomFloat(), strikePos, strikeAxis ) ) { +#endif // _D3XP strikeSmokeStartTime = 0; } } +#ifdef _D3XP + if ( showViewModel && !hide ) { + + for( int i = 0; i < weaponParticles.Num(); i++ ) { + WeaponParticle_t* part = weaponParticles.GetIndex(i); + + if(part->active) { + if(part->smoke) { + if(part->joint != INVALID_JOINT) { + GetGlobalJointTransform( true, part->joint, muzzleOrigin, muzzleAxis ); + } else { + // default to going straight out the view + muzzleOrigin = playerViewOrigin; + muzzleAxis = playerViewAxis; + } + if ( !gameLocal.smokeParticles->EmitSmoke( part->particle, part->startTime, gameLocal.random.RandomFloat(), muzzleOrigin, muzzleAxis, timeGroup /*_D3XP*/ ) ) { + part->active = false; // all done + part->startTime = 0; + } + } else { + //Manually update the position of the emitter so it follows the weapon + renderEntity_t* rendEnt = part->emitter->GetRenderEntity(); + GetGlobalJointTransform( true, part->joint, rendEnt->origin, rendEnt->axis ); + + if ( part->emitter->GetModelDefHandle() != -1 ) { + gameRenderWorld->UpdateEntityDef( part->emitter->GetModelDefHandle(), rendEnt ); + } + } + } + } + + for(int i = 0; i < weaponLights.Num(); i++) { + WeaponLight_t* light = weaponLights.GetIndex(i); + + if(light->active) { + + GetGlobalJointTransform( true, light->joint, light->light.origin, light->light.axis ); + if ( ( light->lightHandle != -1 ) ) { + gameRenderWorld->UpdateLightDef( light->lightHandle, &light->light ); + } else { + light->lightHandle = gameRenderWorld->AddLightDef( &light->light ); + } + } + } + } + + // Update the grabber effects + if ( grabberState != -1 ) { + grabberState = grabber.Update( owner, hide ); + } +#endif + // remove the muzzle flash light when it's done if ( ( !lightOn && ( gameLocal.time >= muzzleFlashEnd ) ) || IsHidden() ) { if ( muzzleFlashHandle != -1 ) { @@ -2022,6 +2386,10 @@ void idWeapon::EnterCinematic( void ) { WEAPON_NETFIRING = false; WEAPON_RAISEWEAPON = false; WEAPON_LOWERWEAPON = false; + +#ifdef _D3XP + grabber.Update( this->GetOwner(), true ); +#endif } disabled = true; @@ -2115,7 +2483,29 @@ ammo_t idWeapon::GetAmmoNumForName( const char *ammoname ) { } if ( !ammoDict->GetInt( ammoname, "-1", num ) ) { - gameLocal.Error( "Unknown ammo type '%s'", ammoname ); +#ifdef _D3XP + //Lets look in a game specific ammo type definition for the weapon + idStr gamedir; + int i; + for ( i = 0; i < 2; i++ ) { + if ( i == 0 ) { + gamedir = cvarSystem->GetCVarString( "fs_game_base" ); + } else if ( i == 1 ) { + gamedir = cvarSystem->GetCVarString( "fs_game" ); + } + if ( gamedir.Length() > 0 ) { + ammoDict = gameLocal.FindEntityDefDict( va("ammo_types_%s", gamedir.c_str()), false ); + if ( ammoDict ) { + if ( ammoDict->GetInt( ammoname, "-1", num ) ) { + break; + } + } + } + } + if ( i == 2 ) { + gameLocal.Error( "Unknown ammo type '%s'", ammoname ); + } +#endif } if ( ( num < 0 ) || ( num >= AMMO_NUMTYPES ) ) { @@ -2131,7 +2521,7 @@ idWeapon::GetAmmoNameForNum ================ */ const char *idWeapon::GetAmmoNameForNum( ammo_t ammonum ) { - int i; + int i, j; int num; const idDict *ammoDict; const idKeyValue *kv; @@ -2152,6 +2542,30 @@ const char *idWeapon::GetAmmoNameForNum( ammo_t ammonum ) { } } +#ifdef _D3XP + // Look in the game specific ammo types + idStr gamedir; + for ( i = 0; i < 2; i++ ) { + if ( i == 0 ) { + gamedir = cvarSystem->GetCVarString( "fs_game_base" ); + } else if ( i == 1 ) { + gamedir = cvarSystem->GetCVarString( "fs_game" ); + } + if ( gamedir.Length() > 0 ) { + ammoDict = gameLocal.FindEntityDefDict( va("ammo_types_%s", gamedir.c_str()), false ); + if ( ammoDict ) { + num = ammoDict->GetNumKeyVals(); + for( j = 0; j < num; j++ ) { + kv = ammoDict->GetKeyVal( j ); + if ( kv->GetValue() == text ) { + return kv->GetKey(); + } + } + } + } + } +#endif + return NULL; } @@ -2253,6 +2667,36 @@ int idWeapon::AmmoRequired( void ) const { return ammoRequired; } +#ifdef _D3XP +/* +================ +idWeapon::GetGrabberState + +Returns the current grabberState +================ +*/ +int idWeapon::GetGrabberState() const { + + return grabberState; +} + +/* +================ +idWeapon::AmmoCount + +Returns the total number of rounds regardless of the required ammo +================ +*/ +int idWeapon::AmmoCount() const { + + if ( owner ) { + return owner->inventory.HasAmmo( ammoType, 1 ); + } else { + return 0; + } +} +#endif + /* ================ idWeapon::WriteToSnapshot @@ -2492,15 +2936,30 @@ void idWeapon::Event_AddToClip( int amount ) { return; } +#ifdef _D3XP + int oldAmmo = ammoClip; + ammoAvail = owner->inventory.HasAmmo( ammoType, ammoRequired ) + AmmoInClip(); +#endif + ammoClip += amount; if ( ammoClip > clipSize ) { ammoClip = clipSize; } +#ifdef _D3XP +#else ammoAvail = owner->inventory.HasAmmo( ammoType, ammoRequired ); +#endif + if ( ammoClip > ammoAvail ) { ammoClip = ammoAvail; } + +#ifdef _D3XP + // for shared ammo we need to use the ammo when it is moved into the clip + int usedAmmo = ammoClip - oldAmmo; + owner->inventory.UseAmmo(ammoType, usedAmmo); +#endif } /* @@ -2519,7 +2978,13 @@ idWeapon::Event_AmmoAvailable =============== */ void idWeapon::Event_AmmoAvailable( void ) { +#ifdef _D3XP + int ammoAvail = owner->inventory.HasAmmo( ammoType, ammoRequired ); + ammoAvail += AmmoInClip(); +#else int ammoAvail = owner->inventory.HasAmmo( ammoType, ammoRequired ); +#endif + idThread::ReturnFloat( ammoAvail ); } @@ -2772,6 +3237,40 @@ void idWeapon::Event_SetLightParms( float parm0, float parm1, float parm2, float UpdateVisuals(); } +#ifdef _D3XP +/* +================ +idWeapon::Event_Grabber +================ +*/ +void idWeapon::Event_Grabber( int enable ) { + if ( enable ) { + grabberState = 0; + } else { + grabberState = -1; + } +} + +/* +================ +idWeapon::Event_GrabberHasTarget +================ +*/ +void idWeapon::Event_GrabberHasTarget() { + idThread::ReturnInt( grabberState ); +} + +/* +================ +idWeapon::Event_GrabberSetGrabDistance +================ +*/ +void idWeapon::Event_GrabberSetGrabDistance( float dist ) { + + grabber.SetDragDistance( dist ); +} +#endif + /* ================ idWeapon::Event_CreateProjectile @@ -2823,12 +3322,19 @@ void idWeapon::Event_LaunchProjectiles( int num_projectiles, float spread, float // avoid all ammo considerations on an MP client if ( !gameLocal.isClient ) { +#ifdef _D3XP + + if ( ( clipSize != 0 ) && ( ammoClip <= 0 ) ) { + return; + } + +#else // check if we're out of ammo or the clip is empty int ammoAvail = owner->inventory.HasAmmo( ammoType, ammoRequired ); if ( !ammoAvail || ( ( clipSize != 0 ) && ( ammoClip <= 0 ) ) ) { return; } - +#endif // if this is a power ammo weapon ( currently only the bfg ) then make sure // we only fire as much power as available in each clip if ( powerAmmo ) { @@ -2842,9 +3348,24 @@ void idWeapon::Event_LaunchProjectiles( int num_projectiles, float spread, float } } - owner->inventory.UseAmmo( ammoType, ( powerAmmo ) ? dmgPower : ammoRequired ); +#ifdef _D3XP + if(clipSize == 0) { + //Weapons with a clip size of 0 launch strait from inventory without moving to a clip +#endif + //In D3XP we used the ammo when the ammo was moved into the clip so we don't want to + //use it now. + owner->inventory.UseAmmo( ammoType, ( powerAmmo ) ? dmgPower : ammoRequired ); + +#ifdef _D3XP + } +#endif + if ( clipSize && ammoRequired ) { +#ifdef _D3XP + ammoClip -= powerAmmo ? dmgPower : ammoRequired; +#else ammoClip -= powerAmmo ? dmgPower : 1; +#endif } } @@ -2941,6 +3462,7 @@ void idWeapon::Event_LaunchProjectiles( int num_projectiles, float spread, float // make sure the projectile starts inside the bounding box of the owner if ( i == 0 ) { muzzle_pos = muzzleOrigin + playerViewAxis[ 0 ] * 2.0f; + // DG: sometimes the assertion in idBounds::operator-(const idBounds&) triggers // (would get bounding box with negative volume) // => check that before doing ownerBounds - projBounds (equivalent to the check in the assertion) @@ -2960,6 +3482,9 @@ void idWeapon::Event_LaunchProjectiles( int num_projectiles, float spread, float } // toss the brass +#ifdef _D3XP + if(brassDelay >= 0) +#endif PostEventMS( &EV_Weapon_EjectBrass, brassDelay ); } @@ -2974,6 +3499,251 @@ void idWeapon::Event_LaunchProjectiles( int num_projectiles, float spread, float weaponSmokeStartTime = gameLocal.realClientTime; } +#ifdef _D3XP +/* +================ +idWeapon::Event_LaunchProjectilesEllipse +================ +*/ +void idWeapon::Event_LaunchProjectilesEllipse( int num_projectiles, float spreada, float spreadb, float fuseOffset, float power ) { + idProjectile *proj; + idEntity *ent; + int i; + idVec3 dir; + float anga, angb; + float spin; + float distance; + trace_t tr; + idVec3 start; + idVec3 muzzle_pos; + idBounds ownerBounds, projBounds; + + if ( IsHidden() ) { + return; + } + + if ( !projectileDict.GetNumKeyVals() ) { + const char *classname = weaponDef->dict.GetString( "classname" ); + gameLocal.Warning( "No projectile defined on '%s'", classname ); + return; + } + + // avoid all ammo considerations on a client + if ( !gameLocal.isClient ) { + + if ( ( clipSize != 0 ) && ( ammoClip <= 0 ) ) { + return; + } + + if( clipSize == 0 ) { + //Weapons with a clip size of 0 launch strait from inventory without moving to a clip + owner->inventory.UseAmmo( ammoType, ammoRequired ); + } + + if ( clipSize && ammoRequired ) { + ammoClip -= ammoRequired; + } + + if ( !silent_fire ) { + // wake up nearby monsters + gameLocal.AlertAI( owner ); + } + + } + + // set the shader parm to the time of last projectile firing, + // which the gun material shaders can reference for single shot barrel glows, etc + renderEntity.shaderParms[ SHADERPARM_DIVERSITY ] = gameLocal.random.CRandomFloat(); + renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time ); + + if ( worldModel.GetEntity() ) { + worldModel.GetEntity()->SetShaderParm( SHADERPARM_DIVERSITY, renderEntity.shaderParms[ SHADERPARM_DIVERSITY ] ); + worldModel.GetEntity()->SetShaderParm( SHADERPARM_TIMEOFFSET, renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] ); + } + + // calculate the muzzle position + if ( barrelJointView != INVALID_JOINT && projectileDict.GetBool( "launchFromBarrel" ) ) { + // there is an explicit joint for the muzzle + GetGlobalJointTransform( true, barrelJointView, muzzleOrigin, muzzleAxis ); + } else { + // go straight out of the view + muzzleOrigin = playerViewOrigin; + muzzleAxis = playerViewAxis; + } + + // add some to the kick time, incrementally moving repeat firing weapons back + if ( kick_endtime < gameLocal.time ) { + kick_endtime = gameLocal.time; + } + kick_endtime += muzzle_kick_time; + if ( kick_endtime > gameLocal.time + muzzle_kick_maxtime ) { + kick_endtime = gameLocal.time + muzzle_kick_maxtime; + } + + if ( !gameLocal.isClient ) { + ownerBounds = owner->GetPhysics()->GetAbsBounds(); + + owner->AddProjectilesFired( num_projectiles ); + + float spreadRadA = DEG2RAD( spreada ); + float spreadRadB = DEG2RAD( spreadb ); + + for( i = 0; i < num_projectiles; i++ ) { + //Ellipse Form + spin = (float)DEG2RAD( 360.0f ) * gameLocal.random.RandomFloat(); + anga = idMath::Sin(spreadRadA * gameLocal.random.RandomFloat()); + angb = idMath::Sin(spreadRadB * gameLocal.random.RandomFloat()); + dir = playerViewAxis[ 0 ] + playerViewAxis[ 2 ] * ( angb*idMath::Sin( spin ) ) - playerViewAxis[ 1 ] * ( anga*idMath::Cos( spin ) ); + dir.Normalize(); + + gameLocal.SpawnEntityDef( projectileDict, &ent ); + if ( !ent || !ent->IsType( idProjectile::Type ) ) { + const char *projectileName = weaponDef->dict.GetString( "def_projectile" ); + gameLocal.Error( "'%s' is not an idProjectile", projectileName ); + } + + proj = static_cast(ent); + proj->Create( owner, muzzleOrigin, dir ); + + projBounds = proj->GetPhysics()->GetBounds().Rotate( proj->GetPhysics()->GetAxis() ); + + // make sure the projectile starts inside the bounding box of the owner + if ( i == 0 ) { + muzzle_pos = muzzleOrigin + playerViewAxis[ 0 ] * 2.0f; + if ( ( ownerBounds - projBounds).RayIntersection( muzzle_pos, playerViewAxis[0], distance ) ) { + start = muzzle_pos + distance * playerViewAxis[0]; + } + else { + start = ownerBounds.GetCenter(); + } + gameLocal.clip.Translation( tr, start, muzzle_pos, proj->GetPhysics()->GetClipModel(), proj->GetPhysics()->GetClipModel()->GetAxis(), MASK_SHOT_RENDERMODEL, owner ); + muzzle_pos = tr.endpos; + } + + proj->Launch( muzzle_pos, dir, pushVelocity, fuseOffset, power ); + } + + // toss the brass + if( brassDelay >= 0 ) { + PostEventMS( &EV_Weapon_EjectBrass, brassDelay ); + } + } + + // add the light for the muzzleflash + if ( !lightOn ) { + MuzzleFlashLight(); + } + + owner->WeaponFireFeedback( &weaponDef->dict ); + + // reset muzzle smoke + weaponSmokeStartTime = gameLocal.time; + +} + +/** +* Gives the player a powerup as if it were a weapon shot. It will use the ammo amount specified +* as ammoRequired. +*/ +void idWeapon::Event_LaunchPowerup( const char* powerup, float duration, int useAmmo ) { + + if ( IsHidden() ) { + return; + } + + // check if we're out of ammo + if(useAmmo) { + int ammoAvail = owner->inventory.HasAmmo( ammoType, ammoRequired ); + if ( !ammoAvail ) { + return; + } + owner->inventory.UseAmmo( ammoType, ammoRequired ); + } + + // set the shader parm to the time of last projectile firing, + // which the gun material shaders can reference for single shot barrel glows, etc + renderEntity.shaderParms[ SHADERPARM_DIVERSITY ] = gameLocal.random.CRandomFloat(); + renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time ); + + if ( worldModel.GetEntity() ) { + worldModel.GetEntity()->SetShaderParm( SHADERPARM_DIVERSITY, renderEntity.shaderParms[ SHADERPARM_DIVERSITY ] ); + worldModel.GetEntity()->SetShaderParm( SHADERPARM_TIMEOFFSET, renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] ); + } + + // add the light for the muzzleflash + if ( !lightOn ) { + MuzzleFlashLight(); + } + + owner->Give(powerup, va("%f", duration)); + + +} + +void idWeapon::Event_StartWeaponSmoke() { + + // reset muzzle smoke + weaponSmokeStartTime = gameLocal.time; +} + +void idWeapon::Event_StopWeaponSmoke() { + + // reset muzzle smoke + weaponSmokeStartTime = 0; +} + +void idWeapon::Event_StartWeaponParticle( const char* name) { + WeaponParticle_t* part; + weaponParticles.Get(name, &part); + if(part) { + part->active = true; + part->startTime = gameLocal.time; + + //Toggle the emitter + if(!part->smoke) { + part->emitter->Show(); + part->emitter->PostEventMS(&EV_Activate, 0, this); + } + } +} + +void idWeapon::Event_StopWeaponParticle( const char* name) { + WeaponParticle_t* part; + weaponParticles.Get(name, &part); + if(part) { + part->active = false; + part->startTime = 0; + + //Toggle the emitter + if(!part->smoke) { + part->emitter->Hide(); + part->emitter->PostEventMS(&EV_Activate, 0, this); + } + } +} + +void idWeapon::Event_StartWeaponLight( const char* name) { + WeaponLight_t* light; + weaponLights.Get(name, &light); + if(light) { + light->active = true; + light->startTime = gameLocal.time; + } +} + +void idWeapon::Event_StopWeaponLight( const char* name) { + WeaponLight_t* light; + weaponLights.Get(name, &light); + if(light) { + light->active = false; + light->startTime = 0; + if(light->lightHandle != -1) { + gameRenderWorld->FreeLightDef( light->lightHandle ); + light->lightHandle = -1; + } + } +} +#endif /* ===================== idWeapon::Event_Melee @@ -3024,8 +3794,15 @@ void idWeapon::Event_Melee( void ) { && weaponDef && weaponDef->dict.GetBool( "stealing" ) && ent->IsType( idPlayer::Type ) && !owner->PowerUpActive( BERSERK ) - && ( gameLocal.gameType != GAME_TDM || gameLocal.serverInfo.GetBool( "si_teamDamage" ) || ( owner->team != static_cast< idPlayer * >( ent )->team ) ) + && ( (gameLocal.gameType != GAME_TDM ) || gameLocal.serverInfo.GetBool( "si_teamDamage" ) || ( owner->team != static_cast< idPlayer * >( ent )->team ) ) ) { + +#ifdef CTF /* Code is formed oddly for easy merge */ + + if ( gameLocal.mpGame.IsGametypeFlagBased() ) + { /* Do nothing ... */ } + else +#endif owner->StealWeapon( static_cast< idPlayer * >( ent ) ); } @@ -3033,7 +3810,17 @@ void idWeapon::Event_Melee( void ) { idVec3 kickDir, globalKickDir; meleeDef->dict.GetVector( "kickDir", "0 0 0", kickDir ); globalKickDir = muzzleAxis * kickDir; +#ifdef _D3XP + //Adjust the melee powerup modifier for the invulnerability boss fight + float mod = owner->PowerUpModifier( MELEE_DAMAGE ); + if(!strcmp(ent->GetEntityDefName(), "monster_hunter_invul")) { + //Only do a quater of the damage mod + mod *= 0.25f; + } + ent->Damage( owner, owner, globalKickDir, meleeDefName, mod, tr.c.id ); +#else ent->Damage( owner, owner, globalKickDir, meleeDefName, owner->PowerUpModifier( MELEE_DAMAGE ), tr.c.id ); +#endif hit = true; } diff --git a/game/Weapon.h b/game/Weapon.h index 4f8b3744..8e7a1d0e 100644 --- a/game/Weapon.h +++ b/game/Weapon.h @@ -32,8 +32,11 @@ If you have questions concerning this license or the applicable additional terms #include "script/Script_Thread.h" #include "Entity.h" #include "Light.h" +#include "Grabber.h" #include "Actor.h" +class idFuncEmitter; + /* =============================================================================== @@ -42,6 +45,10 @@ If you have questions concerning this license or the applicable additional terms =============================================================================== */ +#ifdef _D3XP +extern const idEventDef EV_Weapon_State; +#endif + typedef enum { WP_READY, WP_OUTOFAMMO, @@ -61,6 +68,28 @@ static const int LIGHTID_VIEW_MUZZLE_FLASH = 100; class idMoveableItem; +#ifdef _D3XP +typedef struct { + char name[64]; + char particlename[128]; + bool active; + int startTime; + jointHandle_t joint; //The joint on which to attach the particle + bool smoke; //Is this a smoke particle + const idDeclParticle* particle; //Used for smoke particles + idFuncEmitter* emitter; //Used for non-smoke particles +} WeaponParticle_t; + +typedef struct { + char name[64]; + bool active; + int startTime; + jointHandle_t joint; + int lightHandle; + renderLight_t light; +} WeaponLight_t; +#endif + class idWeapon : public idAnimatedEntity { public: CLASS_PROTOTYPE( idWeapon ); @@ -117,6 +146,11 @@ class idWeapon : public idAnimatedEntity { bool CanDrop( void ) const; void WeaponStolen( void ); +#ifdef _D3XP + weaponStatus_t GetStatus() { return status; }; + +#endif + // Script state management virtual idThread * ConstructScriptObject( void ); virtual void DeconstructScriptObject( void ); @@ -144,6 +178,10 @@ class idWeapon : public idAnimatedEntity { int ClipSize( void ) const; int LowAmmo( void ) const; int AmmoRequired( void ) const; +#ifdef _D3XP + int AmmoCount() const; + int GetGrabberState() const; +#endif virtual void WriteToSnapshot( idBitMsgDelta &msg ) const; virtual void ReadFromSnapshot( const idBitMsgDelta &msg ); @@ -273,6 +311,13 @@ class idWeapon : public idAnimatedEntity { jointHandle_t barrelJointWorld; jointHandle_t ejectJointWorld; +#ifdef _D3XP + jointHandle_t smokeJointView; + + idHashTable weaponParticles; + idHashTable weaponLights; +#endif + // sound const idSoundShader * sndHum; @@ -353,6 +398,26 @@ class idWeapon : public idAnimatedEntity { void Event_NetReload( void ); void Event_IsInvisible( void ); void Event_NetEndReload( void ); + +#ifdef _D3XP + idGrabber grabber; + int grabberState; + + void Event_Grabber( int enable ); + void Event_GrabberHasTarget( void ); + void Event_GrabberSetGrabDistance( float dist ); + void Event_LaunchProjectilesEllipse( int num_projectiles, float spreada, float spreadb, float fuseOffset, float power ); + void Event_LaunchPowerup( const char* powerup, float duration, int useAmmo ); + + void Event_StartWeaponSmoke(); + void Event_StopWeaponSmoke(); + + void Event_StartWeaponParticle( const char* name); + void Event_StopWeaponParticle( const char* name); + + void Event_StartWeaponLight( const char* name); + void Event_StopWeaponLight( const char* name); +#endif }; ID_INLINE bool idWeapon::IsLinked( void ) { diff --git a/game/ai/AAS_debug.cpp b/game/ai/AAS_debug.cpp index ad9d8c6c..a3b04e1d 100644 --- a/game/ai/AAS_debug.cpp +++ b/game/ai/AAS_debug.cpp @@ -27,7 +27,7 @@ If you have questions concerning this license or the applicable additional terms */ #include "sys/platform.h" -#include "gamesys/SysCvar.h" +#include #include "ai/AI.h" #include "Player.h" #include "Game_local.h" diff --git a/game/ai/AAS_routing.cpp b/game/ai/AAS_routing.cpp index eafd01e3..e82ca4eb 100644 --- a/game/ai/AAS_routing.cpp +++ b/game/ai/AAS_routing.cpp @@ -166,7 +166,7 @@ void idAASLocal::CalculateAreaTravelTimes(void) { } } - assert( ( (ptrdiff_t) bytePtr - (ptrdiff_t) areaTravelTimes ) <= numAreaTravelTimes * sizeof( unsigned short ) ); + assert( ( ( ptrdiff_t ) bytePtr - ( ptrdiff_t ) areaTravelTimes ) <= numAreaTravelTimes * sizeof( unsigned short ) ); } /* @@ -326,9 +326,9 @@ void idAASLocal::RoutingStats( void ) const { gameLocal.Printf( "%6d area cache (%d KB)\n", numAreaCache, totalAreaCacheMemory >> 10 ); gameLocal.Printf( "%6d portal cache (%d KB)\n", numPortalCache, totalPortalCacheMemory >> 10 ); gameLocal.Printf( "%6d total cache (%d KB)\n", numAreaCache + numPortalCache, totalCacheMemory >> 10 ); - gameLocal.Printf( "%6d area travel times (%zu KB)\n", numAreaTravelTimes, ( numAreaTravelTimes * sizeof( unsigned short ) ) >> 10 ); - gameLocal.Printf( "%6d area cache entries (%zu KB)\n", areaCacheIndexSize, ( areaCacheIndexSize * sizeof( idRoutingCache * ) ) >> 10 ); - gameLocal.Printf( "%6d portal cache entries (%zu KB)\n", portalCacheIndexSize, ( portalCacheIndexSize * sizeof( idRoutingCache * ) ) >> 10 ); + gameLocal.Printf( "%6d area travel times (%zd KB)\n", numAreaTravelTimes, ( numAreaTravelTimes * sizeof( unsigned short ) ) >> 10 ); + gameLocal.Printf( "%6d area cache entries (%zd KB)\n", areaCacheIndexSize, ( areaCacheIndexSize * sizeof( idRoutingCache * ) ) >> 10 ); + gameLocal.Printf( "%6d portal cache entries (%zd KB)\n", portalCacheIndexSize, ( portalCacheIndexSize * sizeof( idRoutingCache * ) ) >> 10 ); } /* diff --git a/game/ai/AI.cpp b/game/ai/AI.cpp index 2ac99486..6ff04ac2 100644 --- a/game/ai/AI.cpp +++ b/game/ai/AI.cpp @@ -28,10 +28,13 @@ If you have questions concerning this license or the applicable additional terms #include "sys/platform.h" #include "idlib/math/Quat.h" +#include "framework/DeclEntityDef.h" #include "gamesys/SysCvar.h" #include "Moveable.h" +#include "Fx.h" #include "SmokeParticles.h" +#include "Misc.h" #include "ai/AI.h" @@ -351,6 +354,11 @@ idAI::idAI() { current_yaw = 0.0f; ideal_yaw = 0.0f; +#ifdef _D3XP + spawnClearMoveables = false; + harvestEnt = NULL; +#endif + num_cinematics = 0; current_cinematic = 0; @@ -399,6 +407,12 @@ idAI::~idAI() { gameRenderWorld->FreeLightDef( worldMuzzleFlashHandle ); worldMuzzleFlashHandle = -1; } + +#ifdef _D3XP + if ( harvestEnt.GetEntity() ) { + harvestEnt.GetEntity()->PostEventMS( &EV_Remove, 0 ); + } +#endif } /* @@ -531,6 +545,18 @@ void idAI::Save( idSaveGame *savefile ) const { savefile->WriteJoint( flyTiltJoint ); savefile->WriteBool( GetPhysics() == static_cast(&physicsObj) ); + +#ifdef _D3XP + savefile->WriteInt(funcEmitters.Num()); + for(int i = 0; i < funcEmitters.Num(); i++) { + funcEmitter_t* emitter = funcEmitters.GetIndex(i); + savefile->WriteString(emitter->name); + savefile->WriteJoint(emitter->joint); + savefile->WriteObject(emitter->particle); + } + + harvestEnt.Save( savefile); +#endif } /* @@ -698,6 +724,42 @@ void idAI::Restore( idRestoreGame *savefile ) { if ( restorePhysics ) { RestorePhysics( &physicsObj ); } + +#ifdef _D3XP + + //Clean up the emitters + for(int i = 0; i < funcEmitters.Num(); i++) { + funcEmitter_t* emitter = funcEmitters.GetIndex(i); + if(emitter->particle) { + //Destroy the emitters + emitter->particle->PostEventMS(&EV_Remove, 0 ); + } + } + funcEmitters.Clear(); + + int emitterCount; + savefile->ReadInt( emitterCount ); + for(int i = 0; i < emitterCount; i++) { + funcEmitter_t newEmitter; + memset(&newEmitter, 0, sizeof(newEmitter)); + + idStr name; + savefile->ReadString( name ); + + strcpy( newEmitter.name, name.c_str() ); + + savefile->ReadJoint( newEmitter.joint ); + savefile->ReadObject(reinterpret_cast(newEmitter.particle)); + + funcEmitters.Set(newEmitter.name, newEmitter); + } + + harvestEnt.Restore(savefile); + //if(harvestEnt.GetEntity()) { + // harvestEnt.GetEntity()->SetParent(this); + //} + +#endif } /* @@ -932,8 +994,24 @@ void idAI::Spawn( void ) { // init the move variables StopMove( MOVE_STATUS_DONE ); + + +#ifdef _D3XP + spawnArgs.GetBool( "spawnClearMoveables", "0", spawnClearMoveables ); +#endif } + +#ifdef _D3XP +void idAI::Gib( const idVec3 &dir, const char *damageDefName ) { + if(harvestEnt.GetEntity()) { + //Let the harvest ent know that we gibbed + harvestEnt.GetEntity()->Gib(); + } + idActor::Gib(dir, damageDefName); +} +#endif + /* =================== idAI::InitMuzzleFlash @@ -1153,6 +1231,13 @@ void idAI::Think( void ) { Present(); UpdateDamageEffects(); LinkCombat(); + +#ifdef _D3XP + if(ai_showHealth.GetBool()) { + idVec3 aboveHead(0,0,20); + gameRenderWorld->DrawText( va( "%d", ( int )health), this->GetEyePosition()+aboveHead, 0.5f, colorWhite, gameLocal.GetLocalPlayer()->viewAngles.ToMat3() ); + } +#endif } /*********************************************************************** @@ -2702,6 +2787,9 @@ void idAI::AnimMove( void ) { } } +#ifdef _D3XP + physicsObj.UseFlyMove( false ); +#endif physicsObj.SetDelta( delta ); physicsObj.ForceDeltaMove( disableGravity ); @@ -3293,7 +3381,11 @@ const idDeclParticle *idAI::SpawnParticlesOnJoint( particleEmitter_t &pe, const pe.time = gameLocal.time; } pe.particle = static_cast( declManager->FindType( DECL_PARTICLE, particleName ) ); +#ifdef _D3XP + gameLocal.smokeParticles->EmitSmoke( pe.particle, pe.time, gameLocal.random.CRandomFloat(), origin, axis, timeGroup /*_D3XP*/ ); +#else gameLocal.smokeParticles->EmitSmoke( pe.particle, pe.time, gameLocal.random.CRandomFloat(), origin, axis ); +#endif // _D3XP } return pe.particle; @@ -3377,6 +3469,10 @@ void idAI::Killed( idEntity *inflictor, idEntity *attacker, int damage, const id physicsObj.SetLinearVelocity( vec3_zero ); physicsObj.PutToRest(); physicsObj.DisableImpact(); +#ifdef _D3XP + // No grabbing if "model_death" + noGrab = true; +#endif } restartParticles = false; @@ -3395,9 +3491,29 @@ void idAI::Killed( idEntity *inflictor, idEntity *attacker, int damage, const id kv = spawnArgs.MatchPrefix( "def_drops", kv ); } +#ifndef _D3XP if ( ( attacker && attacker->IsType( idPlayer::Type ) ) && ( inflictor && !inflictor->IsType( idSoulCubeMissile::Type ) ) ) { static_cast< idPlayer* >( attacker )->AddAIKill(); } +#endif + +#ifdef _D3XP + if(spawnArgs.GetBool("harvest_on_death")) { + const idDict *harvestDef = gameLocal.FindEntityDefDict( spawnArgs.GetString("def_harvest_type"), false ); + if ( harvestDef ) { + idEntity *temp; + gameLocal.SpawnEntityDef( *harvestDef, &temp, false ); + harvestEnt = static_cast(temp); + + } + + if(harvestEnt.GetEntity()) { + //Let the harvest entity set itself up + harvestEnt.GetEntity()->Init(this); + harvestEnt.GetEntity()->BecomeActive( TH_THINK ); + } + } +#endif } /*********************************************************************** @@ -3559,6 +3675,13 @@ void idAI::TalkTo( idActor *actor ) { return; } +#ifdef _D3XP + // Wake up monsters that are pretending to be NPC's + if ( team == 1 && actor->team != team ) { + ProcessEvent( &EV_Activate, actor ); + } +#endif + talkTarget = actor; if ( actor ) { AI_TALK = true; @@ -3995,6 +4118,13 @@ bool idAI::GetAimDir( const idVec3 &firePos, idEntity *aimAtEnt, const idEntity targetPos2 = targetPos1; } +#ifdef _D3XP + if ( this->team == 0 && !idStr::Cmp( aimAtEnt->GetEntityDefName(), "monster_demon_vulgar" ) ) { + targetPos1.z -= 28.f; + targetPos2.z -= 12.f; + } +#endif + // try aiming for chest delta = firePos - targetPos1; max_height = delta.LengthFast() * projectile_height_to_distance_ratio; @@ -4093,6 +4223,10 @@ idProjectile *idAI::LaunchProjectile( const char *jointname, idEntity *target, b int num_projectiles; int i; idMat3 axis; +#ifdef _D3XP + idMat3 proj_axis; + bool forceMuzzle; +#endif idVec3 tmp; idProjectile *lastProjectile; @@ -4105,6 +4239,9 @@ idProjectile *idAI::LaunchProjectile( const char *jointname, idEntity *target, b attack_cone = spawnArgs.GetFloat( "attack_cone", "70" ); projectile_spread = spawnArgs.GetFloat( "projectile_spread", "0" ); num_projectiles = spawnArgs.GetInt( "num_projectiles", "1" ); +#ifdef _D3XP + forceMuzzle = spawnArgs.GetBool( "forceMuzzle", "0" ); +#endif GetMuzzle( jointname, muzzle, axis ); @@ -4127,27 +4264,34 @@ idProjectile *idAI::LaunchProjectile( const char *jointname, idEntity *target, b axis[2] = axis[0]; axis[0] = -tmp; - // make sure the projectile starts inside the monster bounding box - const idBounds &ownerBounds = physicsObj.GetAbsBounds(); - projClip = lastProjectile->GetPhysics()->GetClipModel(); - projBounds = projClip->GetBounds().Rotate( axis ); - - // check if the owner bounds is bigger than the projectile bounds - if ( ( ( ownerBounds[1][0] - ownerBounds[0][0] ) > ( projBounds[1][0] - projBounds[0][0] ) ) && - ( ( ownerBounds[1][1] - ownerBounds[0][1] ) > ( projBounds[1][1] - projBounds[0][1] ) ) && - ( ( ownerBounds[1][2] - ownerBounds[0][2] ) > ( projBounds[1][2] - projBounds[0][2] ) ) ) { - if ( (ownerBounds - projBounds).RayIntersection( muzzle, viewAxis[ 0 ], distance ) ) { - start = muzzle + distance * viewAxis[ 0 ]; +#ifdef _D3XP + proj_axis = axis; + if ( !forceMuzzle ) { // _D3XP +#endif // _D3XP + // make sure the projectile starts inside the monster bounding box + const idBounds &ownerBounds = physicsObj.GetAbsBounds(); + projClip = lastProjectile->GetPhysics()->GetClipModel(); + projBounds = projClip->GetBounds().Rotate( axis ); + + // check if the owner bounds is bigger than the projectile bounds + if ( ( ( ownerBounds[1][0] - ownerBounds[0][0] ) > ( projBounds[1][0] - projBounds[0][0] ) ) && + ( ( ownerBounds[1][1] - ownerBounds[0][1] ) > ( projBounds[1][1] - projBounds[0][1] ) ) && + ( ( ownerBounds[1][2] - ownerBounds[0][2] ) > ( projBounds[1][2] - projBounds[0][2] ) ) ) { + if ( (ownerBounds - projBounds).RayIntersection( muzzle, viewAxis[ 0 ], distance ) ) { + start = muzzle + distance * viewAxis[ 0 ]; + } else { + start = ownerBounds.GetCenter(); + } } else { + // projectile bounds bigger than the owner bounds, so just start it from the center start = ownerBounds.GetCenter(); } - } else { - // projectile bounds bigger than the owner bounds, so just start it from the center - start = ownerBounds.GetCenter(); - } - gameLocal.clip.Translation( tr, start, muzzle, projClip, axis, MASK_SHOT_RENDERMODEL, this ); - muzzle = tr.endpos; + gameLocal.clip.Translation( tr, start, muzzle, projClip, axis, MASK_SHOT_RENDERMODEL, this ); + muzzle = tr.endpos; +#ifdef _D3XP + } +#endif // _D3XP // set aiming direction GetAimDir( muzzle, target, this, dir ); @@ -4648,6 +4792,10 @@ void idAI::UpdateParticles( void ) { int particlesAlive = 0; for ( int i = 0; i < particles.Num(); i++ ) { +#ifdef _D3XP + // Smoke particles on AI characters will always be "slow", even when held by grabber + SetTimeState ts(TIME_GROUP1); +#endif if ( particles[i].particle && particles[i].time ) { particlesAlive++; if (af.IsActive()) { @@ -4659,7 +4807,11 @@ void idAI::UpdateParticles( void ) { realVector = physicsObj.GetOrigin() + ( realVector + modelOffset ) * ( viewAxis * physicsObj.GetGravityAxis() ); } +#ifdef _D3XP + if ( !gameLocal.smokeParticles->EmitSmoke( particles[i].particle, particles[i].time, gameLocal.random.CRandomFloat(), realVector, realAxis, timeGroup /*_D3XP*/ )) { +#else if ( !gameLocal.smokeParticles->EmitSmoke( particles[i].particle, particles[i].time, gameLocal.random.CRandomFloat(), realVector, realAxis )) { +#endif // _D3XP if ( restartParticles ) { particles[i].time = gameLocal.time; } else { @@ -4692,6 +4844,114 @@ void idAI::TriggerParticles( const char *jointName ) { } } +#ifdef _D3XP +void idAI::TriggerFX( const char* joint, const char* fx ) { + + if( !strcmp(joint, "origin") ) { + idEntityFx::StartFx( fx, NULL, NULL, this, true ); + } else { + idVec3 joint_origin; + idMat3 joint_axis; + jointHandle_t jointNum; + jointNum = animator.GetJointHandle( joint ); + + if ( jointNum == INVALID_JOINT ) { + gameLocal.Warning( "Unknown fx joint '%s' on entity %s", joint, name.c_str() ); + return; + } + + GetJointWorldTransform( jointNum, gameLocal.time, joint_origin, joint_axis ); + idEntityFx::StartFx( fx, &joint_origin, &joint_axis, this, true ); + } +} + +idEntity* idAI::StartEmitter( const char* name, const char* joint, const char* particle ) { + + idEntity* existing = GetEmitter(name); + if(existing) { + return existing; + } + + jointHandle_t jointNum; + jointNum = animator.GetJointHandle( joint ); + + idVec3 offset; + idMat3 axis; + + GetJointWorldTransform( jointNum, gameLocal.time, offset, axis ); + + /*animator.GetJointTransform( jointNum, gameLocal.time, offset, axis ); + offset = GetPhysics()->GetOrigin() + offset * GetPhysics()->GetAxis(); + axis = axis * GetPhysics()->GetAxis();*/ + + + + idDict args; + + const idDeclEntityDef *emitterDef = gameLocal.FindEntityDef( "func_emitter", false ); + args = emitterDef->dict; + args.Set("model", particle); + args.Set( "origin", offset.ToString() ); + args.SetBool("start_off", true); + + idEntity* ent; + gameLocal.SpawnEntityDef(args, &ent, false); + + ent->GetPhysics()->SetOrigin(offset); + //ent->GetPhysics()->SetAxis(axis); + + // align z-axis of model with the direction + /*idVec3 tmp; + axis = (viewAxis[ 0 ] * physicsObj.GetGravityAxis()).ToMat3(); + tmp = axis[2]; + axis[2] = axis[0]; + axis[0] = -tmp; + + ent->GetPhysics()->SetAxis(axis);*/ + + axis = physicsObj.GetGravityAxis(); + ent->GetPhysics()->SetAxis(axis); + + + ent->GetPhysics()->GetClipModel()->SetOwner( this ); + + + //Keep a reference to the emitter so we can track it + funcEmitter_t newEmitter; + strcpy(newEmitter.name, name); + newEmitter.particle = (idFuncEmitter*)ent; + newEmitter.joint = jointNum; + funcEmitters.Set(newEmitter.name, newEmitter); + + //Bind it to the joint and make it active + newEmitter.particle->BindToJoint(this, jointNum, true); + newEmitter.particle->BecomeActive(TH_THINK); + newEmitter.particle->Show(); + newEmitter.particle->PostEventMS(&EV_Activate, 0, this); + return newEmitter.particle; +} + +idEntity* idAI::GetEmitter( const char* name ) { + funcEmitter_t* emitter; + funcEmitters.Get(name, &emitter); + if(emitter) { + return emitter->particle; + } + return NULL; +} + +void idAI::StopEmitter( const char* name ) { + funcEmitter_t* emitter; + funcEmitters.Get(name, &emitter); + if(emitter) { + emitter->particle->Unbind(); + emitter->particle->PostEventMS( &EV_Remove, 0 ); + funcEmitters.Remove(name); + } +} + +#endif + /*********************************************************************** diff --git a/game/ai/AI.h b/game/ai/AI.h index b038ba41..7264869a 100644 --- a/game/ai/AI.h +++ b/game/ai/AI.h @@ -34,6 +34,8 @@ If you have questions concerning this license or the applicable additional terms #include "Actor.h" #include "Projectile.h" +class idFuncEmitter; + /* =============================================================================== @@ -149,6 +151,12 @@ extern const idEventDef AI_MuzzleFlash; extern const idEventDef AI_CreateMissile; extern const idEventDef AI_AttackMissile; extern const idEventDef AI_FireMissileAtTarget; +#ifdef _D3XP +extern const idEventDef AI_LaunchProjectile; +extern const idEventDef AI_TriggerFX; +extern const idEventDef AI_StartEmitter; +extern const idEventDef AI_StopEmitter; +#endif extern const idEventDef AI_AttackMelee; extern const idEventDef AI_DirectDamage; extern const idEventDef AI_JumpFrame; @@ -172,6 +180,14 @@ typedef struct particleEmitter_s { jointHandle_t joint; } particleEmitter_t; +#ifdef _D3XP +typedef struct funcEmitter_s { + char name[64]; + idFuncEmitter* particle; + jointHandle_t joint; +} funcEmitter_t; +#endif + class idMoveState { public: idMoveState(); @@ -277,6 +293,10 @@ class idAI : public idActor { // Finds the best collision free trajectory for a clip model. static bool PredictTrajectory( const idVec3 &firePos, const idVec3 &target, float projectileSpeed, const idVec3 &projGravity, const idClipModel *clip, int clipmask, float max_height, const idEntity *ignore, const idEntity *targetEntity, int drawtime, idVec3 &aimDir ); +#ifdef _D3XP + virtual void Gib( const idVec3 &dir, const char *damageDefName ); +#endif + protected: // navigation idAAS * aas; @@ -399,6 +419,14 @@ class idAI : public idActor { idVec3 lastReachableEnemyPos; bool wakeOnFlashlight; +#ifdef _D3XP + bool spawnClearMoveables; + + idHashTable funcEmitters; + + idEntityPtr harvestEnt; +#endif + // script variables idScriptBool AI_TALK; idScriptBool AI_DAMAGE; @@ -529,6 +557,13 @@ class idAI : public idActor { void UpdateParticles( void ); void TriggerParticles( const char *jointName ); +#ifdef _D3XP + void TriggerFX( const char* joint, const char* fx ); + idEntity* StartEmitter( const char* name, const char* joint, const char* particle ); + idEntity* GetEmitter( const char* name ); + void StopEmitter( const char* name ); +#endif + // AI script state management void LinkScriptVariables( void ); void UpdateAIScript( void ); @@ -550,6 +585,9 @@ class idAI : public idActor { void Event_AttackMissile( const char *jointname ); void Event_FireMissileAtTarget( const char *jointname, const char *targetname ); void Event_LaunchMissile( const idVec3 &muzzle, const idAngles &ang ); +#ifdef _D3XP + void Event_LaunchProjectile( const char *entityDefName ); +#endif void Event_AttackMelee( const char *meleeDefName ); void Event_DirectDamage( idEntity *damageTarget, const char *damageDefName ); void Event_RadiusDamageFromJoint( const char *jointname, const char *damageDefName ); @@ -664,6 +702,15 @@ class idAI : public idActor { void Event_CanReachEntity( idEntity *ent ); void Event_CanReachEnemy( void ); void Event_GetReachableEntityPosition( idEntity *ent ); +#ifdef _D3XP + void Event_MoveToPositionDirect( const idVec3 &pos ); + void Event_AvoidObstacles( int ignore); + void Event_TriggerFX( const char* joint, const char* fx ); + + void Event_StartEmitter( const char* name, const char* joint, const char* particle ); + void Event_GetEmitter( const char* name ); + void Event_StopEmitter( const char* name ); +#endif }; class idCombatNode : public idEntity { diff --git a/game/ai/AI_events.cpp b/game/ai/AI_events.cpp index 04d66870..15bbced2 100644 --- a/game/ai/AI_events.cpp +++ b/game/ai/AI_events.cpp @@ -51,6 +51,9 @@ const idEventDef AI_CreateMissile( "createMissile", "s", 'e' ); const idEventDef AI_AttackMissile( "attackMissile", "s", 'e' ); const idEventDef AI_FireMissileAtTarget( "fireMissileAtTarget", "ss", 'e' ); const idEventDef AI_LaunchMissile( "launchMissile", "vv", 'e' ); +#ifdef _D3XP +const idEventDef AI_LaunchProjectile( "launchProjectile", "s" ); +#endif const idEventDef AI_AttackMelee( "attackMelee", "s", 'd' ); const idEventDef AI_DirectDamage( "directDamage", "es" ); const idEventDef AI_RadiusDamageFromJoint( "radiusDamageFromJoint", "ss" ); @@ -162,6 +165,16 @@ const idEventDef AI_CanReachPosition( "canReachPosition", "v", 'd' ); const idEventDef AI_CanReachEntity( "canReachEntity", "E", 'd' ); const idEventDef AI_CanReachEnemy( "canReachEnemy", NULL, 'd' ); const idEventDef AI_GetReachableEntityPosition( "getReachableEntityPosition", "e", 'v' ); +#ifdef _D3XP +const idEventDef AI_MoveToPositionDirect( "moveToPositionDirect", "v" ); +const idEventDef AI_AvoidObstacles( "avoidObstacles", "d" ); +const idEventDef AI_TriggerFX( "triggerFX", "ss" ); +const idEventDef AI_StartEmitter( "startEmitter", "sss", 'e' ); +const idEventDef AI_GetEmitter( "getEmitter", "s", 'e' ); +const idEventDef AI_StopEmitter( "stopEmitter", "s" ); + + +#endif CLASS_DECLARATION( idActor, idAI ) EVENT( EV_Activate, idAI::Event_Activate ) @@ -178,6 +191,9 @@ CLASS_DECLARATION( idActor, idAI ) EVENT( AI_AttackMissile, idAI::Event_AttackMissile ) EVENT( AI_FireMissileAtTarget, idAI::Event_FireMissileAtTarget ) EVENT( AI_LaunchMissile, idAI::Event_LaunchMissile ) +#ifdef _D3XP + EVENT( AI_LaunchProjectile, idAI::Event_LaunchProjectile ) +#endif EVENT( AI_AttackMelee, idAI::Event_AttackMelee ) EVENT( AI_DirectDamage, idAI::Event_DirectDamage ) EVENT( AI_RadiusDamageFromJoint, idAI::Event_RadiusDamageFromJoint ) @@ -292,6 +308,14 @@ CLASS_DECLARATION( idActor, idAI ) EVENT( AI_CanReachEntity, idAI::Event_CanReachEntity ) EVENT( AI_CanReachEnemy, idAI::Event_CanReachEnemy ) EVENT( AI_GetReachableEntityPosition, idAI::Event_GetReachableEntityPosition ) +#ifdef _D3XP + EVENT( AI_MoveToPositionDirect, idAI::Event_MoveToPositionDirect ) + EVENT( AI_AvoidObstacles, idAI::Event_AvoidObstacles ) + EVENT( AI_TriggerFX, idAI::Event_TriggerFX ) + EVENT( AI_StartEmitter, idAI::Event_StartEmitter ) + EVENT( AI_GetEmitter, idAI::Event_GetEmitter ) + EVENT( AI_StopEmitter, idAI::Event_StopEmitter ) +#endif END_CLASS /* @@ -654,6 +678,64 @@ void idAI::Event_LaunchMissile( const idVec3 &org, const idAngles &ang ) { lastAttackTime = gameLocal.time; } + +#ifdef _D3XP +/* +===================== +idAI::Event_LaunchProjectile +===================== +*/ +void idAI::Event_LaunchProjectile( const char *entityDefName ) { + idVec3 muzzle, start, dir; + const idDict *projDef; + idMat3 axis; + const idClipModel *projClip; + idBounds projBounds; + trace_t tr; + idEntity *ent; + const char *clsname; + float distance; + idProjectile *proj = NULL; + + projDef = gameLocal.FindEntityDefDict( entityDefName ); + + gameLocal.SpawnEntityDef( *projDef, &ent, false ); + if ( !ent ) { + clsname = projectileDef->GetString( "classname" ); + gameLocal.Error( "Could not spawn entityDef '%s'", clsname ); + } + + if ( !ent->IsType( idProjectile::Type ) ) { + clsname = ent->GetClassname(); + gameLocal.Error( "'%s' is not an idProjectile", clsname ); + } + proj = ( idProjectile * )ent; + + GetMuzzle( "pistol", muzzle, axis ); + proj->Create( this, muzzle, axis[0] ); + + // make sure the projectile starts inside the monster bounding box + const idBounds &ownerBounds = physicsObj.GetAbsBounds(); + projClip = proj->GetPhysics()->GetClipModel(); + projBounds = projClip->GetBounds().Rotate( projClip->GetAxis() ); + if ( (ownerBounds - projBounds).RayIntersection( muzzle, viewAxis[ 0 ], distance ) ) { + start = muzzle + distance * viewAxis[ 0 ]; + } else { + start = ownerBounds.GetCenter(); + } + gameLocal.clip.Translation( tr, start, muzzle, projClip, projClip->GetAxis(), MASK_SHOT_RENDERMODEL, this ); + muzzle = tr.endpos; + + GetAimDir( muzzle, enemy.GetEntity(), this, dir ); + + proj->Launch( muzzle, dir, vec3_origin ); + + TriggerWeaponEffects( muzzle ); +} + +#endif + + /* ===================== idAI::Event_AttackMelee @@ -774,6 +856,9 @@ idAI::Event_CanBecomeSolid void idAI::Event_CanBecomeSolid( void ) { int i; int num; +#ifdef _D3XP + bool returnValue = true; +#endif idEntity * hit; idClipModel *cm; idClipModel *clipModels[ MAX_GENTITIES ]; @@ -792,13 +877,36 @@ void idAI::Event_CanBecomeSolid( void ) { continue; } +#ifdef _D3XP + if ( (spawnClearMoveables && hit->IsType( idMoveable::Type )) || (hit->IsType( idBarrel::Type ) || hit->IsType( idExplodingBarrel::Type) ) ) { + idVec3 push; + push = hit->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin(); + push.z = 30.f; + push.NormalizeFast(); + if ( (idMath::Fabs(push.x) < 0.15f) && (idMath::Fabs(push.y) < 0.15f) ) { + push.x = 10.f; push.y = 10.f; push.z = 15.f; + push.NormalizeFast(); + } + push *= 300.f; + hit->GetPhysics()->SetLinearVelocity( push ); + } +#endif + if ( physicsObj.ClipContents( cm ) ) { +#ifdef _D3XP + returnValue = false; +#else idThread::ReturnFloat( false ); return; +#endif } } +#ifdef _D3XP + idThread::ReturnFloat( returnValue ); +#else idThread::ReturnFloat( true ); +#endif } /* @@ -1121,6 +1229,38 @@ void idAI::Event_GetCombatNode( void ) { if ( !enemyEnt || !EnemyPositionValid() ) { // don't return a combat node if we don't have an enemy or // if we can see he's not in the last place we saw him + +#ifdef _D3XP + if ( team == 0 ) { + // find the closest attack node to the player + bestNode = NULL; + const idVec3 &myPos = physicsObj.GetOrigin(); + const idVec3 &playerPos = gameLocal.GetLocalPlayer()->GetPhysics()->GetOrigin(); + + bestDist = ( myPos - playerPos ).LengthSqr(); + + for( i = 0; i < targets.Num(); i++ ) { + targetEnt = targets[ i ].GetEntity(); + if ( !targetEnt || !targetEnt->IsType( idCombatNode::Type ) ) { + continue; + } + + node = static_cast( targetEnt ); + if ( !node->IsDisabled() ) { + idVec3 org = node->GetPhysics()->GetOrigin(); + dist = ( playerPos - org ).LengthSqr(); + if ( dist < bestDist ) { + bestNode = node; + bestDist = dist; + } + } + } + + idThread::ReturnEntity( bestNode ); + return; + } +#endif + idThread::ReturnEntity( NULL ); return; } @@ -1177,6 +1317,15 @@ void idAI::Event_EnemyInCombatCone( idEntity *ent, int use_current_enemy_locatio return; } +#ifdef _D3XP + //Allow the level designers define attack nodes that the enemy should never leave. + //This is different that the turrent type combat nodes because they can play an animation + if(ent->spawnArgs.GetBool("neverLeave", "0")) { + idThread::ReturnInt( true ); + return; + } +#endif + node = static_cast( ent ); if ( use_current_enemy_location ) { const idVec3 &pos = enemyEnt->GetPhysics()->GetOrigin(); @@ -1835,6 +1984,11 @@ idAI::Event_PreBurn ===================== */ void idAI::Event_PreBurn( void ) { +#ifdef _D3XP + // No grabbing after the burn has started! + noGrab = true; +#endif + // for now this just turns shadows off renderEntity.noShadow = true; } @@ -2706,3 +2860,47 @@ void idAI::Event_GetReachableEntityPosition( idEntity *ent ) { idThread::ReturnVector( pos ); } + +#ifdef _D3XP +/* +================ +idAI::Event_MoveToPositionDirect +================ +*/ +void idAI::Event_MoveToPositionDirect( const idVec3 &pos ) { + StopMove( MOVE_STATUS_DONE ); + DirectMoveToPosition( pos ); +} + +/* +================ +idAI::Event_AvoidObstacles +================ +*/ +void idAI::Event_AvoidObstacles( int ignore) { + ignore_obstacles = (ignore == 1) ? false : true; +} + +/* +================ +idAI::Event_TriggerFX +================ +*/ +void idAI::Event_TriggerFX( const char* joint, const char* fx ) { + TriggerFX(joint, fx); +} + +void idAI::Event_StartEmitter( const char* name, const char* joint, const char* particle ) { + idEntity *ent = StartEmitter(name, joint, particle); + idThread::ReturnEntity(ent); +} + +void idAI::Event_GetEmitter( const char* name ) { + idThread::ReturnEntity(GetEmitter(name)); +} + +void idAI::Event_StopEmitter( const char* name ) { + StopEmitter(name); +} + +#endif diff --git a/game/ai/AI_pathing.cpp b/game/ai/AI_pathing.cpp index 9c961a9c..4b043dc5 100644 --- a/game/ai/AI_pathing.cpp +++ b/game/ai/AI_pathing.cpp @@ -36,8 +36,6 @@ If you have questions concerning this license or the applicable additional terms #include "ai/AI.h" -#include - /* =============================================================================== @@ -613,7 +611,6 @@ pathNode_t *BuildPathTree( const obstacle_t *obstacles, int numObstacles, const root->delta = seekPos - root->pos; root->numNodes = 0; - pathNodeQueue.Add( root ); for ( node = pathNodeQueue.Get(); node && pathNodeAllocator.GetAllocCount() < MAX_PATH_NODES; node = pathNodeQueue.Get() ) { diff --git a/game/anim/Anim.h b/game/anim/Anim.h index dcba8531..b37b2096 100644 --- a/game/anim/Anim.h +++ b/game/anim/Anim.h @@ -153,6 +153,12 @@ typedef enum { FC_DISABLE_LEG_IK, FC_RECORDDEMO, FC_AVIGAME +#ifdef _D3XP + , FC_LAUNCH_PROJECTILE, + FC_TRIGGER_FX, + FC_START_EMITTER, + FC_STOP_EMITTER, +#endif } frameCommandType_t; typedef struct { diff --git a/game/anim/Anim_Blend.cpp b/game/anim/Anim_Blend.cpp index 0cbd4af7..da1249a6 100644 --- a/game/anim/Anim_Blend.cpp +++ b/game/anim/Anim_Blend.cpp @@ -574,6 +574,67 @@ const char *idAnim::AddFrameCommand( const idDeclModelDef *modelDef, int framenu fc.type = FC_FIREMISSILEATTARGET; fc.string = new idStr( token ); fc.index = jointInfo->num; +#ifdef _D3XP + } else if ( token == "launch_projectile" ) { + if( !src.ReadTokenOnLine( &token ) ) { + return "Unexpected end of line"; + } + if ( !declManager->FindDeclWithoutParsing( DECL_ENTITYDEF, token, false ) ) { + return "Unknown projectile def"; + } + fc.type = FC_LAUNCH_PROJECTILE; + fc.string = new idStr( token ); + } else if ( token == "trigger_fx" ) { + + if( !src.ReadTokenOnLine( &token ) ) { + return "Unexpected end of line"; + } + jointInfo = modelDef->FindJoint( token ); + if ( !jointInfo ) { + return va( "Joint '%s' not found", token.c_str() ); + } + if( !src.ReadTokenOnLine( &token ) ) { + return "Unexpected end of line"; + } + if ( !declManager->FindType( DECL_FX, token, false ) ) { + return "Unknown FX def"; + } + + fc.type = FC_TRIGGER_FX; + fc.string = new idStr( token ); + fc.index = jointInfo->num; + + } else if ( token == "start_emitter" ) { + + idStr str; + if( !src.ReadTokenOnLine( &token ) ) { + return "Unexpected end of line"; + } + str = token + " "; + + if( !src.ReadTokenOnLine( &token ) ) { + return "Unexpected end of line"; + } + jointInfo = modelDef->FindJoint( token ); + if ( !jointInfo ) { + return va( "Joint '%s' not found", token.c_str() ); + } + if( !src.ReadTokenOnLine( &token ) ) { + return "Unexpected end of line"; + } + str += token; + fc.type = FC_START_EMITTER; + fc.string = new idStr( str ); + fc.index = jointInfo->num; + + } else if ( token == "stop_emitter" ) { + + if( !src.ReadTokenOnLine( &token ) ) { + return "Unexpected end of line"; + } + fc.type = FC_STOP_EMITTER; + fc.string = new idStr( token ); +#endif } else if ( token == "footstep" ) { fc.type = FC_FOOTSTEP; } else if ( token == "leftfoot" ) { @@ -824,6 +885,9 @@ void idAnim::CallFrameCommands( idEntity *ent, int from, int to ) const { target = gameLocal.FindEntity( command.string->c_str() ); if ( target ) { +#ifdef _D3XP + SetTimeState ts(target->timeGroup); +#endif target->Signal( SIG_TRIGGER ); target->ProcessEvent( &EV_Activate, ent ); target->TriggerGuis(); @@ -869,6 +933,28 @@ void idAnim::CallFrameCommands( idEntity *ent, int from, int to ) const { ent->ProcessEvent( &AI_FireMissileAtTarget, modelDef->GetJointName( command.index ), command.string->c_str() ); break; } +#ifdef _D3XP + case FC_LAUNCH_PROJECTILE: { + ent->ProcessEvent( &AI_LaunchProjectile, command.string->c_str() ); + break; + } + case FC_TRIGGER_FX: { + ent->ProcessEvent( &AI_TriggerFX, modelDef->GetJointName( command.index ), command.string->c_str() ); + break; + } + case FC_START_EMITTER: { + int index = command.string->Find(" "); + if(index >= 0) { + idStr name = command.string->Left(index); + idStr particle = command.string->Right(command.string->Length() - index - 1); + ent->ProcessEvent( &AI_StartEmitter, name.c_str(), modelDef->GetJointName( command.index ), particle.c_str() ); + } + } + + case FC_STOP_EMITTER: { + ent->ProcessEvent( &AI_StopEmitter, command.string->c_str() ); + } +#endif case FC_FOOTSTEP : { ent->ProcessEvent( &EV_Footstep ); break; diff --git a/game/anim/Anim_Import.cpp b/game/anim/Anim_Import.cpp index c9397238..035f5884 100644 --- a/game/anim/Anim_Import.cpp +++ b/game/anim/Anim_Import.cpp @@ -176,8 +176,7 @@ version number has changed. ===================== */ bool idModelExport::ConvertMayaToMD5( void ) { - ID_TIME_T - sourceTime; + ID_TIME_T sourceTime; ID_TIME_T destTime; int version; idToken cmdLine; @@ -242,8 +241,9 @@ bool idModelExport::ConvertMayaToMD5( void ) { } // we need to make sure we have a full path, so convert the filename to an OS path - src = fileSystem->RelativePathToOSPath( src ); - dest = fileSystem->RelativePathToOSPath( dest ); + // _D3XP :: we work out of the cdpath, at least until we get Alienbrain + src = fileSystem->RelativePathToOSPath( src, "fs_cdpath" ); + dest = fileSystem->RelativePathToOSPath( dest, "fs_cdpath" ); dest.ExtractFilePath( path ); if ( path.Length() ) { @@ -251,7 +251,7 @@ bool idModelExport::ConvertMayaToMD5( void ) { } // get the os path in case it needs to create one - path = fileSystem->RelativePathToOSPath( "" ); + path = fileSystem->RelativePathToOSPath( "", "fs_cdpath" /* _D3XP */ ); common->SetRefreshOnPrint( true ); Maya_Error = Maya_ConvertModel( path, commandLine ); @@ -405,6 +405,12 @@ int idModelExport::ParseExportSection( idParser &parser ) { idStr parms; int count; + const char *game = cvarSystem->GetCVarString( "fs_game" ); + + if ( strlen(game) == 0 ) { + game = BASE_GAMEDIR; + } + // only export sections that match our export mask if ( g_exportMask.GetString()[ 0 ] ) { if ( parser.CheckTokenString( "{" ) ) { diff --git a/game/anim/Anim_Testmodel.cpp b/game/anim/Anim_Testmodel.cpp index eea46e4b..d4cbc4cc 100644 --- a/game/anim/Anim_Testmodel.cpp +++ b/game/anim/Anim_Testmodel.cpp @@ -530,16 +530,17 @@ idTestModel::TestAnim void idTestModel::TestAnim( const idCmdArgs &args ) { idStr name; int animNum; + //const idAnim *newanim; if ( args.Argc() < 2 ) { gameLocal.Printf( "usage: testanim \n" ); return; } + //newanim = NULL; + name = args.Argv( 1 ); #if 0 - const idAnim *newanim = NULL; - if ( strstr( name, ".ma" ) || strstr( name, ".mb" ) ) { const idMD5Anim *md5anims[ ANIM_MaxSyncedAnims ]; idModelExport exporter; @@ -771,11 +772,14 @@ void idTestModel::TestModel_f( const idCmdArgs &args ) { name.DefaultFileExtension( ".ase" ); } +#ifndef _D3XP + // Maya ascii format is supported natively now if ( strstr( name, ".ma" ) || strstr( name, ".mb" ) ) { idModelExport exporter; exporter.ExportModel( name ); name.SetFileExtension( MD5_MESH_EXT ); } +#endif if ( !renderModelManager->CheckModel( name ) ) { gameLocal.Printf( "Can't register model\n" ); diff --git a/game/gamesys/Class.cpp b/game/gamesys/Class.cpp index 750e441f..10dd4a0d 100644 --- a/game/gamesys/Class.cpp +++ b/game/gamesys/Class.cpp @@ -943,6 +943,15 @@ bool idClass::ProcessEventArgPtr( const idEventDef *ev, intptr_t *data ) { assert( ev ); assert( idEvent::initialized ); +#ifdef _D3XP + SetTimeState ts; + + if ( IsType( idEntity::Type ) ) { + idEntity *ent = (idEntity*)this; + ts.PushState( ent->timeGroup ); + } +#endif + if ( g_debugTriggers.GetBool() && ( ev == &EV_Activate ) && IsType( idEntity::Type ) ) { const idEntity *ent = *reinterpret_cast( data ); gameLocal.Printf( "%d: '%s' activated by '%s'\n", gameLocal.framenum, static_cast( this )->GetName(), ent ? ent->GetName() : "NULL" ); diff --git a/game/gamesys/Event.cpp b/game/gamesys/Event.cpp index 013b13dd..16920de9 100644 --- a/game/gamesys/Event.cpp +++ b/game/gamesys/Event.cpp @@ -61,8 +61,8 @@ idEventDef::idEventDef ================ */ idEventDef::idEventDef( const char *command, const char *formatspec, char returnType ) { - idEventDef *ev; - int i; + idEventDef *ev; + int i; unsigned int bits; assert( command ); @@ -90,7 +90,7 @@ idEventDef::idEventDef( const char *command, const char *formatspec, char return bits = 0; argsize = 0; memset( argOffset, 0, sizeof( argOffset ) ); - for( i = 0; i < numargs; i++ ) { + for( i = 0; i < numargs;i++ ) { argOffset[ i ] = argsize; switch( formatspec[ i ] ) { case D_EVENT_FLOAT : @@ -212,6 +212,9 @@ const idEventDef *idEventDef::FindEvent( const char *name ) { static idLinkList FreeEvents; static idLinkList EventQueue; +#ifdef _D3XP +static idLinkList FastEventQueue; +#endif static idEvent EventPool[ MAX_EVENTS ]; bool idEvent::initialized = false; @@ -392,6 +395,25 @@ void idEvent::Schedule( idClass *obj, const idTypeInfo *type, int time ) { eventNode.Remove(); +#ifdef _D3XP + if ( obj->IsType( idEntity::Type ) && ( ( (idEntity*)(obj) )->timeGroup == TIME_GROUP2 ) ) { + event = FastEventQueue.Next(); + while( ( event != NULL ) && ( this->time >= event->time ) ) { + event = event->eventNode.Next(); + } + + if ( event ) { + eventNode.InsertBefore( event->eventNode ); + } else { + eventNode.AddToEnd( FastEventQueue ); + } + + return; + } else { + this->time = gameLocal.slow.time + time; + } +#endif + event = EventQueue.Next(); while( ( event != NULL ) && ( this->time >= event->time ) ) { event = event->eventNode.Next(); @@ -425,6 +447,17 @@ void idEvent::CancelEvents( const idClass *obj, const idEventDef *evdef ) { } } } + +#ifdef _D3XP + for( event = FastEventQueue.Next(); event != NULL; event = next ) { + next = event->eventNode.Next(); + if ( event->object == obj ) { + if ( !evdef || ( evdef == event->eventdef ) ) { + event->Free(); + } + } + } +#endif } /* @@ -540,6 +573,99 @@ void idEvent::ServiceEvents( void ) { } } +#ifdef _D3XP +/* +================ +idEvent::ServiceFastEvents +================ +*/ +void idEvent::ServiceFastEvents() { + idEvent *event; + int num; + intptr_t args[ D_EVENT_MAXARGS ]; + int offset; + int i; + int numargs; + const char *formatspec; + trace_t **tracePtr; + const idEventDef *ev; + byte *data; + const char *materialName; + + num = 0; + while( !FastEventQueue.IsListEmpty() ) { + event = FastEventQueue.Next(); + assert( event ); + + if ( event->time > gameLocal.fast.time ) { + break; + } + + // copy the data into the local args array and set up pointers + ev = event->eventdef; + formatspec = ev->GetArgFormat(); + numargs = ev->GetNumArgs(); + for( i = 0; i < numargs; i++ ) { + offset = ev->GetArgOffset( i ); + data = event->data; + switch( formatspec[ i ] ) { + case D_EVENT_FLOAT : + case D_EVENT_INTEGER : + args[ i ] = *reinterpret_cast( &data[ offset ] ); + break; + + case D_EVENT_VECTOR : + *reinterpret_cast( &args[ i ] ) = reinterpret_cast( &data[ offset ] ); + break; + + case D_EVENT_STRING : + *reinterpret_cast( &args[ i ] ) = reinterpret_cast( &data[ offset ] ); + break; + + case D_EVENT_ENTITY : + case D_EVENT_ENTITY_NULL : + *reinterpret_cast( &args[ i ] ) = reinterpret_cast< idEntityPtr * >( &data[ offset ] )->GetEntity(); + break; + + case D_EVENT_TRACE : + tracePtr = reinterpret_cast( &args[ i ] ); + if ( *reinterpret_cast( &data[ offset ] ) ) { + *tracePtr = reinterpret_cast( &data[ offset + sizeof( bool ) ] ); + + if ( ( *tracePtr )->c.material != NULL ) { + // look up the material name to get the material pointer + materialName = reinterpret_cast( &data[ offset + sizeof( bool ) + sizeof( trace_t ) ] ); + ( *tracePtr )->c.material = declManager->FindMaterial( materialName, true ); + } + } else { + *tracePtr = NULL; + } + break; + + default: + gameLocal.Error( "idEvent::ServiceFastEvents : Invalid arg format '%s' string for '%s' event.", formatspec, ev->GetName() ); + } + } + + // the event is removed from its list so that if then object + // is deleted, the event won't be freed twice + event->eventNode.Remove(); + assert( event->object ); + event->object->ProcessEventArgPtr( ev, args ); + + // return the event to the free list + event->Free(); + + // Don't allow ourselves to stay in here too long. An abnormally high number + // of events being processed is evidence of an infinite loop of events. + num++; + if ( num > MAX_EVENTSPERFRAME ) { + gameLocal.Error( "Event overflow. Possible infinite loop in script." ); + } + } +} +#endif + /* ================ idEvent::Init @@ -667,6 +793,23 @@ void idEvent::Save( idSaveGame *savefile ) { assert( size == event->eventdef->GetArgSize() ); event = event->eventNode.Next(); } + +#ifdef _D3XP + // Save the Fast EventQueue + savefile->WriteInt( FastEventQueue.Num() ); + + event = FastEventQueue.Next(); + while( event != NULL ) { + savefile->WriteInt( event->time ); + savefile->WriteString( event->eventdef->GetName() ); + savefile->WriteString( event->typeinfo->classname ); + savefile->WriteObject( event->object ); + savefile->WriteInt( event->eventdef->GetArgSize() ); + savefile->Write( event->data, event->eventdef->GetArgSize() ); + + event = event->eventNode.Next(); + } +#endif } /* @@ -769,6 +912,51 @@ void idEvent::Restore( idRestoreGame *savefile ) { event->data = NULL; } } + +#ifdef _D3XP + // Restore the Fast EventQueue + savefile->ReadInt( num ); + + for ( i = 0; i < num; i++ ) { + if ( FreeEvents.IsListEmpty() ) { + gameLocal.Error( "idEvent::Restore : No more free events" ); + } + + event = FreeEvents.Next(); + event->eventNode.Remove(); + event->eventNode.AddToEnd( FastEventQueue ); + + savefile->ReadInt( event->time ); + + // read the event name + savefile->ReadString( name ); + event->eventdef = idEventDef::FindEvent( name ); + if ( !event->eventdef ) { + savefile->Error( "idEvent::Restore: unknown event '%s'", name.c_str() ); + } + + // read the classtype + savefile->ReadString( name ); + event->typeinfo = idClass::GetClass( name ); + if ( !event->typeinfo ) { + savefile->Error( "idEvent::Restore: unknown class '%s' on event '%s'", name.c_str(), event->eventdef->GetName() ); + } + + savefile->ReadObject( event->object ); + + // read the args + savefile->ReadInt( argsize ); + if ( argsize != event->eventdef->GetArgSize() ) { + savefile->Error( "idEvent::Restore: arg size (%zd) doesn't match saved arg size(%d) on event '%s'", event->eventdef->GetArgSize(), argsize, event->eventdef->GetName() ); + } + if ( argsize ) { + event->data = eventDataAllocator.Alloc( argsize ); + savefile->Read( event->data, argsize ); + } else { + event->data = NULL; + } + } +#endif } /* @@ -828,8 +1016,6 @@ CreateEventCallbackHandler ================ */ void CreateEventCallbackHandler( void ) { - int num; - int count; int i, j, k; char argString[ D_EVENT_MAXARGS + 1 ]; idStr string1; @@ -845,7 +1031,7 @@ void CreateEventCallbackHandler( void ) { file->Printf( "\t/*******************************************************\n\n\t\t%d args\n\n\t*******************************************************/\n\n", i ); for ( j = 0; j < ( 1 << i ); j++ ) { - for ( k = 0; k < i; k++ ) { + for( k = 0; k < i; k++ ) { argString[ k ] = j & ( 1 << k ) ? 'f' : 'i'; } argString[ i ] = '\0'; diff --git a/game/gamesys/Event.h b/game/gamesys/Event.h index c90c0674..178fc270 100644 --- a/game/gamesys/Event.h +++ b/game/gamesys/Event.h @@ -117,6 +117,9 @@ class idEvent { static void CancelEvents( const idClass *obj, const idEventDef *evdef = NULL ); static void ClearEventList( void ); static void ServiceEvents( void ); +#ifdef _D3XP + static void ServiceFastEvents(); +#endif static void Init( void ); static void Shutdown( void ); diff --git a/game/gamesys/SaveGame.cpp b/game/gamesys/SaveGame.cpp index 158f5abe..ce31cf0a 100644 --- a/game/gamesys/SaveGame.cpp +++ b/game/gamesys/SaveGame.cpp @@ -545,6 +545,11 @@ void idSaveGame::WriteRenderEntity( const renderEntity_t &renderEntity ) { WriteBool( renderEntity.weaponDepthHack ); WriteInt( renderEntity.forceUpdate ); + +#ifdef _D3XP + WriteInt( renderEntity.timeGroup ); + WriteInt( renderEntity.xrayIndex ); +#endif } /* @@ -1319,6 +1324,11 @@ void idRestoreGame::ReadRenderEntity( renderEntity_t &renderEntity ) { ReadBool( renderEntity.weaponDepthHack ); ReadInt( renderEntity.forceUpdate ); + +#ifdef _D3XP + ReadInt( renderEntity.timeGroup ); + ReadInt( renderEntity.xrayIndex ); +#endif } /* diff --git a/game/gamesys/SysCmds.cpp b/game/gamesys/SysCmds.cpp index 732d5067..9871fe09 100644 --- a/game/gamesys/SysCmds.cpp +++ b/game/gamesys/SysCmds.cpp @@ -156,6 +156,26 @@ void Cmd_ReloadScript_f( const idCmdArgs &args ) { // recompile the scripts gameLocal.program.Startup( SCRIPT_DEFAULT ); +#ifdef _D3XP + // loads a game specific main script file + idStr gamedir; + int i; + for ( i = 0; i < 2; i++ ) { + if ( i == 0 ) { + gamedir = cvarSystem->GetCVarString( "fs_game_base" ); + } else if ( i == 1 ) { + gamedir = cvarSystem->GetCVarString( "fs_game" ); + } + if ( gamedir.Length() > 0 ) { + idStr scriptFile = va( "script/%s_main.script", gamedir.c_str() ); + if ( fileSystem->ReadFile(scriptFile.c_str(), NULL) > 0 ) { + gameLocal.program.CompileFile( scriptFile.c_str() ); + gameLocal.program.FinishCompilation(); + } + } + } +#endif + // error out so that the user can rerun the scripts gameLocal.Error( "Exiting map to reload scripts" ); } @@ -326,7 +346,7 @@ void Cmd_Give_f( const idCmdArgs &args ) { } if ( give_all || idStr::Icmp( name, "weapons" ) == 0 ) { - player->inventory.weapons = BIT( MAX_WEAPONS ) - 1; + player->inventory.weapons = 0xffffffff >> ( 32 - MAX_WEAPONS ); player->CacheWeapons(); if ( !give_all ) { @@ -360,6 +380,37 @@ void Cmd_Give_f( const idCmdArgs &args ) { return; } +#ifdef _D3XP + if ( idStr::Icmp( name, "invulnerability" ) == 0 ) { + if ( args.Argc() > 2 ) { + player->GivePowerUp( INVULNERABILITY, atoi( args.Argv( 2 ) ) ); + } + else { + player->GivePowerUp( INVULNERABILITY, 30000 ); + } + return; + } + + if ( idStr::Icmp( name, "helltime" ) == 0 ) { + if ( args.Argc() > 2 ) { + player->GivePowerUp( HELLTIME, atoi( args.Argv( 2 ) ) ); + } + else { + player->GivePowerUp( HELLTIME, 30000 ); + } + return; + } + + if ( idStr::Icmp( name, "envirosuit" ) == 0 ) { + if ( args.Argc() > 2 ) { + player->GivePowerUp( ENVIROSUIT, atoi( args.Argv( 2 ) ) ); + } + else { + player->GivePowerUp( ENVIROSUIT, 30000 ); + } + return; + } +#endif if ( idStr::Icmp( name, "pda" ) == 0 ) { player->GivePDA( args.Argv(2), NULL ); return; @@ -581,6 +632,24 @@ static void Cmd_Say( bool team, const idCmdArgs &args ) { if ( player ) { name = player->GetUserInfo()->GetString( "ui_name", "player" ); } + +#ifdef CTF + // Append the player's location to team chat messages in CTF + if ( gameLocal.mpGame.IsGametypeFlagBased() && team && player ) { + idLocationEntity *locationEntity = gameLocal.LocationForPoint( player->GetEyePosition() ); + + if ( locationEntity ) { + idStr temp = "["; + temp += locationEntity->GetLocation(); + temp += "] "; + temp += text; + text = temp; + } + + } +#endif + + } else { name = "server"; } @@ -2028,7 +2097,13 @@ static void Cmd_RecordViewNotes_f( const idCmdArgs &args ) { idStr str = args.Argv(1); str.SetFileExtension( ".txt" ); + +#ifdef _D3XP + idFile *file = fileSystem->OpenFileAppend( str, false, "fs_cdpath" ); +#else idFile *file = fileSystem->OpenFileAppend( str ); +#endif + if ( file ) { file->WriteFloatString( "\"view\"\t( %s )\t( %s )\r\n", origin.ToString(), axis.ToString() ); file->WriteFloatString( "\"comments\"\t\"%s: %s\"\r\n\r\n", args.Argv(2), args.Argv(3) ); @@ -2268,6 +2343,32 @@ void Cmd_NextGUI_f( const idCmdArgs &args ) { player->Teleport( origin, angles, NULL ); } +#ifdef _D3XP +void Cmd_SetActorState_f( const idCmdArgs &args ) { + + if ( args.Argc() != 3 ) { + common->Printf( "usage: setActorState \n" ); + return; + } + + idEntity* ent; + ent = gameLocal.FindEntity( args.Argv( 1 ) ); + if ( !ent ) { + gameLocal.Printf( "entity not found\n" ); + return; + } + + + if(!ent->IsType(idActor::Type)) { + gameLocal.Printf( "entity not an actor\n" ); + return; + } + + idActor* actor = (idActor*)ent; + actor->PostEventMS(&AI_SetState, 0, args.Argv(2)); +} +#endif + static void ArgCompletion_DefFile( const idCmdArgs &args, void(*callback)( const char *s ) ) { cmdSystem->ArgCompletion_FolderExtension( args, callback, "def/", true, ".def", NULL ); } @@ -2403,6 +2504,10 @@ void idGameLocal::InitConsoleCommands( void ) { // localization help commands cmdSystem->AddCommand( "nextGUI", Cmd_NextGUI_f, CMD_FL_GAME|CMD_FL_CHEAT, "teleport the player to the next func_static with a gui" ); cmdSystem->AddCommand( "testid", Cmd_TestId_f, CMD_FL_GAME|CMD_FL_CHEAT, "output the string for the specified id." ); + +#ifdef _D3XP + cmdSystem->AddCommand( "setActorState", Cmd_SetActorState_f, CMD_FL_GAME|CMD_FL_CHEAT, "Manually sets an actors script state", idGameLocal::ArgCompletion_EntityName ); +#endif } /* diff --git a/game/gamesys/SysCvar.cpp b/game/gamesys/SysCvar.cpp index 7aad60d8..f2bb0b7a 100644 --- a/game/gamesys/SysCvar.cpp +++ b/game/gamesys/SysCvar.cpp @@ -47,11 +47,21 @@ All game cvars should be defined here. */ +#ifdef CTF +const char *si_gameTypeArgs[] = { "singleplayer", "deathmatch", "Tourney", "Team DM", "Last Man", "CTF", NULL }; +#else const char *si_gameTypeArgs[] = { "singleplayer", "deathmatch", "Tourney", "Team DM", "Last Man", NULL }; +#endif + const char *si_readyArgs[] = { "Not Ready", "Ready", NULL }; const char *si_spectateArgs[] = { "Play", "Spectate", NULL }; +#ifdef _D3XP +const char *ui_skinArgs[] = { "skins/characters/player/marine_mp", "skins/characters/player/marine_mp_red", "skins/characters/player/marine_mp_blue", "skins/characters/player/marine_mp_green", "skins/characters/player/marine_mp_yellow", "skins/characters/player/marine_mp_purple", "skins/characters/player/marine_mp_grey", "skins/characters/player/marine_mp_orange", NULL }; +#else const char *ui_skinArgs[] = { "skins/characters/player/marine_mp", "skins/characters/player/marine_mp_red", "skins/characters/player/marine_mp_blue", "skins/characters/player/marine_mp_green", "skins/characters/player/marine_mp_yellow", NULL }; +#endif + const char *ui_teamArgs[] = { "Red", "Blue", NULL }; struct gameVersion_s { @@ -67,9 +77,15 @@ idCVar gamedate( "gamedate", __DATE__, CVAR_GAME | CVAR_ROM, "" ); // server info idCVar si_name( "si_name", "dhewm server", CVAR_GAME | CVAR_SERVERINFO | CVAR_ARCHIVE, "name of the server" ); + +#ifdef CTF +idCVar si_gameType( "si_gameType", si_gameTypeArgs[ 0 ], CVAR_GAME | CVAR_SERVERINFO | CVAR_ARCHIVE, "game type - singleplayer, deathmatch, Tourney, Team DM, Last Man or CTF", si_gameTypeArgs, idCmdSystem::ArgCompletion_String ); +#else idCVar si_gameType( "si_gameType", si_gameTypeArgs[ 0 ], CVAR_GAME | CVAR_SERVERINFO | CVAR_ARCHIVE, "game type - singleplayer, deathmatch, Tourney, Team DM or Last Man", si_gameTypeArgs, idCmdSystem::ArgCompletion_String ); +#endif + idCVar si_map( "si_map", "game/mp/d3dm1",CVAR_GAME | CVAR_SERVERINFO | CVAR_ARCHIVE, "map to be played next on server", idCmdSystem::ArgCompletion_MapName ); -idCVar si_maxPlayers( "si_maxPlayers", "4", CVAR_GAME | CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_INTEGER, "max number of players allowed on the server", 1, 4 ); +idCVar si_maxPlayers( "si_maxPlayers", "8", CVAR_GAME | CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_INTEGER, "max number of players allowed on the server", 1, 8 ); idCVar si_fragLimit( "si_fragLimit", "10", CVAR_GAME | CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_INTEGER, "frag limit", 1, MP_PLAYER_MAXFRAGS ); idCVar si_timeLimit( "si_timeLimit", "10", CVAR_GAME | CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_INTEGER, "time limit in minutes", 0, 60 ); idCVar si_teamDamage( "si_teamDamage", "0", CVAR_GAME | CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_BOOL, "enable team damage" ); @@ -79,6 +95,13 @@ idCVar si_pure( "si_pure", "1", CVAR_GAME | CVAR_SERVERINFO | CVAR_BO idCVar si_spectators( "si_spectators", "1", CVAR_GAME | CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_BOOL, "allow spectators or require all clients to play" ); idCVar si_serverURL( "si_serverURL", "", CVAR_GAME | CVAR_SERVERINFO | CVAR_ARCHIVE, "where to reach the server admins and get information about the server" ); +#ifdef CTF +//idCVar si_pointLimit( "si_pointlimit", "8", CVAR_GAME | CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_INTEGER, "team points limit to win in CTF" ); +idCVar si_flagDropTimeLimit( "si_flagDropTimeLimit", "30", CVAR_GAME | CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_INTEGER, "seconds before a dropped CTF flag is returned" ); +idCVar si_midnight( "si_midnight", "0", CVAR_GAME | CVAR_INTEGER | CVAR_SERVERINFO, "Start the game up in midnight CTF (completely dark)" ); +#endif + + // user info idCVar ui_name( "ui_name", "Player", CVAR_GAME | CVAR_USERINFO | CVAR_ARCHIVE, "player name" ); idCVar ui_skin( "ui_skin", ui_skinArgs[ 0 ], CVAR_GAME | CVAR_USERINFO | CVAR_ARCHIVE, "player skin", ui_skinArgs, idCmdSystem::ArgCompletion_String ); @@ -149,6 +172,26 @@ idCVar g_showEnemies( "g_showEnemies", "0", CVAR_GAME | CVAR_BOOL, "draws idCVar g_frametime( "g_frametime", "0", CVAR_GAME | CVAR_BOOL, "displays timing information for each game frame" ); idCVar g_timeentities( "g_timeEntities", "0", CVAR_GAME | CVAR_FLOAT, "when non-zero, shows entities whose think functions exceeded the # of milliseconds specified" ); +#ifdef _D3XP +idCVar g_testPistolFlashlight( "g_testPistolFlashlight", "1", CVAR_GAME | CVAR_BOOL, "Test out having a flashlight out with the pistol" ); +idCVar g_debugShockwave( "g_debugShockwave", "0", CVAR_GAME | CVAR_BOOL, "Debug the shockwave" ); + +idCVar g_enableSlowmo( "g_enableSlowmo", "0", CVAR_GAME | CVAR_BOOL, "for testing purposes only" ); +idCVar g_slowmoStepRate( "g_slowmoStepRate", "0.02", CVAR_GAME | CVAR_FLOAT, "" ); + +idCVar g_enablePortalSky( "g_enablePortalSky", "1", CVAR_GAME | CVAR_BOOL, "enables the portal sky" ); +idCVar g_testFullscreenFX( "g_testFullscreenFX", "-1", CVAR_GAME | CVAR_INTEGER, "index will activate specific fx, -2 is for all on, -1 is off" ); +idCVar g_testHelltimeFX( "g_testHelltimeFX", "-1", CVAR_GAME | CVAR_INTEGER, "set to 0, 1, 2 to test helltime, -1 is off" ); +idCVar g_testMultiplayerFX( "g_testMultiplayerFX", "-1", CVAR_GAME | CVAR_INTEGER, "set to 0, 1, 2 to test multiplayer, -1 is off" ); +idCVar g_lowresFullscreenFX( "g_lowresFullscreenFX", "0", CVAR_GAME | CVAR_BOOL, "enable lores mode for fx" ); + +idCVar g_moveableDamageScale( "g_moveableDamageScale", "0.1", CVAR_GAME | CVAR_FLOAT, "scales damage wrt mass of object in multiplayer" ); + +idCVar g_testBloomSpeed( "g_testBloomSpeed", "1", CVAR_GAME | CVAR_FLOAT, "" ); +idCVar g_testBloomIntensity( "g_testBloomIntensity", "-0.01", CVAR_GAME | CVAR_FLOAT, "" ); +idCVar g_testBloomNumPasses( "g_testBloomNumPasses", "30", CVAR_GAME | CVAR_INTEGER, "" ); +#endif + idCVar ai_debugScript( "ai_debugScript", "-1", CVAR_GAME | CVAR_INTEGER, "displays script calls for the specified monster entity number" ); idCVar ai_debugMove( "ai_debugMove", "0", CVAR_GAME | CVAR_BOOL, "draws movement information for monsters" ); idCVar ai_debugTrajectory( "ai_debugTrajectory", "0", CVAR_GAME | CVAR_BOOL, "draws trajectory tests for monsters" ); @@ -158,6 +201,10 @@ idCVar ai_showPaths( "ai_showPaths", "0", CVAR_GAME | CVAR_BOOL, "draws idCVar ai_showObstacleAvoidance( "ai_showObstacleAvoidance", "0", CVAR_GAME | CVAR_INTEGER, "draws obstacle avoidance information for monsters. if 2, draws obstacles for player, as well", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> ); idCVar ai_blockedFailSafe( "ai_blockedFailSafe", "1", CVAR_GAME | CVAR_BOOL, "enable blocked fail safe handling" ); +#ifdef _D3XP +idCVar ai_showHealth( "ai_showHealth", "0", CVAR_GAME | CVAR_BOOL, "Draws the AI's health above its head" ); +#endif + idCVar g_dvTime( "g_dvTime", "1", CVAR_GAME | CVAR_FLOAT, "" ); idCVar g_dvAmplitude( "g_dvAmplitude", "0.001", CVAR_GAME | CVAR_FLOAT, "" ); idCVar g_dvFrequency( "g_dvFrequency", "0.5", CVAR_GAME | CVAR_FLOAT, "" ); @@ -181,6 +228,18 @@ idCVar g_dragDamping( "g_dragDamping", "0.5", CVAR_GAME | CVAR_FLOAT, "" idCVar g_dragShowSelection( "g_dragShowSelection", "0", CVAR_GAME | CVAR_BOOL, "" ); idCVar g_dropItemRotation( "g_dropItemRotation", "", CVAR_GAME, "" ); +#ifdef CTF +// Note: These cvars do not necessarily need to be in the shipping game. +idCVar g_flagAttachJoint( "g_flagAttachJoint", "Chest", CVAR_GAME | CVAR_CHEAT, "player joint to attach CTF flag to" ); +idCVar g_flagAttachOffsetX( "g_flagAttachOffsetX", "8", CVAR_GAME | CVAR_CHEAT, "X offset of CTF flag when carried" ); +idCVar g_flagAttachOffsetY( "g_flagAttachOffsetY", "4", CVAR_GAME | CVAR_CHEAT, "Y offset of CTF flag when carried" ); +idCVar g_flagAttachOffsetZ( "g_flagAttachOffsetZ", "-12", CVAR_GAME | CVAR_CHEAT, "Z offset of CTF flag when carried" ); +idCVar g_flagAttachAngleX( "g_flagAttachAngleX", "90", CVAR_GAME | CVAR_CHEAT, "X angle of CTF flag when carried" ); +idCVar g_flagAttachAngleY( "g_flagAttachAngleY", "25", CVAR_GAME | CVAR_CHEAT, "Y angle of CTF flag when carried" ); +idCVar g_flagAttachAngleZ( "g_flagAttachAngleZ", "-90", CVAR_GAME | CVAR_CHEAT, "Z angle of CTF flag when carried" ); +#endif + + idCVar g_vehicleVelocity( "g_vehicleVelocity", "1000", CVAR_GAME | CVAR_FLOAT, "" ); idCVar g_vehicleForce( "g_vehicleForce", "50000", CVAR_GAME | CVAR_FLOAT, "" ); idCVar g_vehicleSuspensionUp( "g_vehicleSuspensionUp", "32", CVAR_GAME | CVAR_FLOAT, "" ); @@ -188,6 +247,9 @@ idCVar g_vehicleSuspensionDown( "g_vehicleSuspensionDown", "20", CVAR_GAME | idCVar g_vehicleSuspensionKCompress("g_vehicleSuspensionKCompress","200", CVAR_GAME | CVAR_FLOAT, "" ); idCVar g_vehicleSuspensionDamping( "g_vehicleSuspensionDamping","400", CVAR_GAME | CVAR_FLOAT, "" ); idCVar g_vehicleTireFriction( "g_vehicleTireFriction", "0.8", CVAR_GAME | CVAR_FLOAT, "" ); +#ifdef _D3XP +idCVar g_vehicleDebug( "g_vehicleDebug", "0", CVAR_GAME | CVAR_BOOL, "" ); +#endif idCVar ik_enable( "ik_enable", "1", CVAR_GAME | CVAR_BOOL, "enable IK" ); idCVar ik_debug( "ik_debug", "0", CVAR_GAME | CVAR_BOOL, "show IK debug lines" ); @@ -316,6 +378,9 @@ idCVar g_countDown( "g_countDown", "10", CVAR_GAME | CVAR_INTEGER | CVA idCVar g_gameReviewPause( "g_gameReviewPause", "10", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_INTEGER | CVAR_ARCHIVE, "scores review time in seconds (at end game)", 2, 3600 ); idCVar g_TDMArrows( "g_TDMArrows", "1", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_BOOL, "draw arrows over teammates in team deathmatch" ); idCVar g_balanceTDM( "g_balanceTDM", "1", CVAR_GAME | CVAR_BOOL, "maintain even teams" ); +#ifdef CTF +idCVar g_CTFArrows( "g_CTFArrows", "1", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_BOOL, "draw arrows over teammates in CTF" ); +#endif idCVar net_clientPredictGUI( "net_clientPredictGUI", "1", CVAR_GAME | CVAR_BOOL, "test guis in networking without prediction" ); @@ -330,7 +395,24 @@ idCVar g_voteFlags( "g_voteFlags", "0", CVAR_GAME | CVAR_NETWORKSYNC | "bit 7 (+128) next map" ); idCVar g_mapCycle( "g_mapCycle", "mapcycle", CVAR_GAME | CVAR_ARCHIVE, "map cycling script for multiplayer games - see mapcycle.scriptcfg" ); +#ifdef _D3XP +idCVar mod_validSkins( "mod_validSkins", "skins/characters/player/marine_mp;skins/characters/player/marine_mp_green;skins/characters/player/marine_mp_blue;skins/characters/player/marine_mp_red;skins/characters/player/marine_mp_yellow;skins/characters/player/marine_mp_purple;skins/characters/player/marine_mp_grey;skins/characters/player/marine_mp_orange", CVAR_GAME | CVAR_ARCHIVE, "valid skins for the game" ); +#else idCVar mod_validSkins( "mod_validSkins", "skins/characters/player/marine_mp;skins/characters/player/marine_mp_green;skins/characters/player/marine_mp_blue;skins/characters/player/marine_mp_red;skins/characters/player/marine_mp_yellow", CVAR_GAME | CVAR_ARCHIVE, "valid skins for the game" ); +#endif + + +#ifdef _D3XP +idCVar g_grabberHoldSeconds( "g_grabberHoldSeconds", "3", CVAR_GAME | CVAR_FLOAT | CVAR_CHEAT, "number of seconds to hold object" ); +idCVar g_grabberEnableShake( "g_grabberEnableShake", "1", CVAR_GAME | CVAR_BOOL | CVAR_CHEAT, "enable the grabber shake" ); +idCVar g_grabberRandomMotion( "g_grabberRandomMotion", "1", CVAR_GAME | CVAR_BOOL | CVAR_CHEAT, "enable random motion on the grabbed object" ); +idCVar g_grabberHardStop( "g_grabberHardStop", "1", CVAR_GAME | CVAR_BOOL | CVAR_CHEAT, "hard stops object if too fast" ); +idCVar g_grabberDamping( "g_grabberDamping", "0.5", CVAR_GAME | CVAR_FLOAT | CVAR_CHEAT, "damping of grabber" ); +#endif + +#ifdef _D3XP +idCVar g_xp_bind_run_once( "g_xp_bind_run_once", "0", CVAR_GAME | CVAR_BOOL | CVAR_ARCHIVE, "Rebind all controls once for D3XP." ); +#endif idCVar net_serverDownload( "net_serverDownload", "0", CVAR_GAME | CVAR_INTEGER | CVAR_ARCHIVE, "enable server download redirects. 0: off 1: redirect to si_serverURL 2: use builtin download. see net_serverDl cvars for configuration" ); idCVar net_serverDlBaseURL( "net_serverDlBaseURL", "", CVAR_GAME | CVAR_ARCHIVE, "base URL for the download redirection" ); diff --git a/game/gamesys/SysCvar.h b/game/gamesys/SysCvar.h index da8e26ee..37ddbb69 100644 --- a/game/gamesys/SysCvar.h +++ b/game/gamesys/SysCvar.h @@ -94,6 +94,9 @@ extern idCVar ai_showCombatNodes; extern idCVar ai_showPaths; extern idCVar ai_showObstacleAvoidance; extern idCVar ai_blockedFailSafe; +#ifdef _D3XP +extern idCVar ai_showHealth; +#endif extern idCVar g_dvTime; extern idCVar g_dvAmplitude; @@ -118,6 +121,11 @@ extern idCVar g_vehicleSuspensionDown; extern idCVar g_vehicleSuspensionKCompress; extern idCVar g_vehicleSuspensionDamping; extern idCVar g_vehicleTireFriction; +#ifdef _D3XP +extern idCVar g_vehicleDebug; +extern idCVar g_debugShockwave; +extern idCVar g_enablePortalSky; +#endif extern idCVar ik_enable; extern idCVar ik_debug; @@ -224,6 +232,31 @@ extern idCVar g_testModelBlend; extern idCVar g_exportMask; extern idCVar g_flushSave; +#ifdef _D3XP +extern idCVar g_enableSlowmo; +extern idCVar g_slowmoStepRate; +extern idCVar g_testFullscreenFX; +extern idCVar g_testHelltimeFX; +extern idCVar g_testMultiplayerFX; +extern idCVar g_lowresFullscreenFX; +extern idCVar g_moveableDamageScale; +extern idCVar g_testBloomSpeed; +extern idCVar g_testBloomIntensity; +extern idCVar g_testBloomNumPasses; +#endif + +#ifdef _D3XP +extern idCVar g_grabberHoldSeconds; +extern idCVar g_grabberEnableShake; +extern idCVar g_grabberRandomMotion; +extern idCVar g_grabberHardStop; +extern idCVar g_grabberDamping; +#endif + +#ifdef _D3XP +extern idCVar g_xp_bind_run_once; +#endif + extern idCVar aas_test; extern idCVar aas_showAreas; extern idCVar aas_showPath; @@ -247,6 +280,22 @@ extern idCVar si_gameType; extern idCVar si_map; extern idCVar si_spectators; +#ifdef CTF +extern idCVar si_flagDropTimeLimit; +extern idCVar si_midnight; + +extern idCVar g_flagAttachJoint; +extern idCVar g_flagAttachOffsetX; +extern idCVar g_flagAttachOffsetY; +extern idCVar g_flagAttachOffsetZ; +extern idCVar g_flagAttachAngleX; +extern idCVar g_flagAttachAngleY; +extern idCVar g_flagAttachAngleZ; + +extern idCVar g_CTFArrows; + +#endif + extern idCVar net_clientSelfSmoothing; extern idCVar net_clientLagOMeter; diff --git a/game/gamesys/TypeInfo.cpp b/game/gamesys/TypeInfo.cpp index 40f55e84..aab6c465 100644 --- a/game/gamesys/TypeInfo.cpp +++ b/game/gamesys/TypeInfo.cpp @@ -569,16 +569,15 @@ int idTypeInfoTools::WriteVariable_r( const void *varPtr, const char *varName, c return typeSize; } - // if this is a pointer - #if D3_SIZEOFPTR == 4 const uintptr_t uninitPtr = (uintptr_t)0xcdcdcdcdUL; #elif D3_SIZEOFPTR == 8 const uintptr_t uninitPtr = (uintptr_t)0xcdcdcdcdcdcdcdcdULL; #else - #error "Unexpected pointer size" +#error "Unexpected pointer size" #endif + // if this is a pointer isPointer = 0; for ( i = typeString.Length(); i > 0 && typeString[i - 1] == '*'; i -= 2 ) { if ( varPtr == (void*)uninitPtr || ( varPtr != NULL && *((unsigned int *)varPtr) == 0xcdcdcdcd ) ) { diff --git a/game/physics/Clip.cpp b/game/physics/Clip.cpp index b2a237be..f1fb1236 100644 --- a/game/physics/Clip.cpp +++ b/game/physics/Clip.cpp @@ -965,24 +965,26 @@ idClip::TestHugeTranslation */ ID_INLINE bool TestHugeTranslation( trace_t &results, const idClipModel *mdl, const idVec3 &start, const idVec3 &end, const idMat3 &trmAxis ) { if ( mdl != NULL && ( end - start ).LengthSqr() > Square( CM_MAX_TRACE_DIST ) ) { - - results.fraction = 0.0f; results.endpos = start; results.endAxis = trmAxis; memset( &results.c, 0, sizeof( results.c ) ); results.c.point = start; - results.c.entityNum = ENTITYNUM_WORLD; if ( mdl->GetEntity() ) { gameLocal.Printf( "huge translation for clip model %d on entity %d '%s'\n", mdl->GetId(), mdl->GetEntity()->entityNumber, mdl->GetEntity()->GetName() ); } else { gameLocal.Printf( "huge translation for clip model %d\n", mdl->GetId() ); } - gameLocal.Printf( " from (%.2f %.2f %.2f) to (%.2f %.2f %.2f)\n", start.x, start.y, start.z, end.x, end.y, end.z); +#ifndef CTF + // May be important: This occurs in CTF when a player connects and spawns + // in the PVS of a player that has a flag that is spawning the idMoveableItem + // "nuggets". The error seems benign and the assert was getting in the way + // of testing. assert( 0 ); +#endif return true; } return false; diff --git a/d3xp/physics/Force_Grab.cpp b/game/physics/Force_Grab.cpp similarity index 100% rename from d3xp/physics/Force_Grab.cpp rename to game/physics/Force_Grab.cpp diff --git a/d3xp/physics/Force_Grab.h b/game/physics/Force_Grab.h similarity index 100% rename from d3xp/physics/Force_Grab.h rename to game/physics/Force_Grab.h diff --git a/game/physics/Physics_AF.cpp b/game/physics/Physics_AF.cpp index 37304807..098a4bfc 100644 --- a/game/physics/Physics_AF.cpp +++ b/game/physics/Physics_AF.cpp @@ -3033,7 +3033,8 @@ void idAFConstraint_Contact::Setup( idAFBody *b1, idAFBody *b2, contactInfo_t &c if ( body1->GetBouncyness() > 0.0f && -vel > minBounceVelocity ) { c1[0] = body1->GetBouncyness() * vel; - } else { + } + else { c1[0] = 0.0f; } diff --git a/game/script/Script_Compiler.cpp b/game/script/Script_Compiler.cpp index 5ee0c77a..7f28d8e7 100644 --- a/game/script/Script_Compiler.cpp +++ b/game/script/Script_Compiler.cpp @@ -1486,8 +1486,8 @@ idCompiler::GetExpression ============== */ idVarDef *idCompiler::GetExpression( int priority ) { - const opcode_t *op; - const opcode_t *oldop; + const opcode_t *op; + const opcode_t *oldop; idVarDef *e; idVarDef *e2; const idVarDef *oldtype; diff --git a/game/script/Script_Interpreter.cpp b/game/script/Script_Interpreter.cpp index b6d044cf..c8e0cc45 100644 --- a/game/script/Script_Interpreter.cpp +++ b/game/script/Script_Interpreter.cpp @@ -172,7 +172,7 @@ void idInterpreter::Reset( void ) { currentFunction = 0; NextInstruction( 0 ); - threadDying = false; + threadDying = false; doneProcessing = true; } diff --git a/game/script/Script_Program.h b/game/script/Script_Program.h index 29ee8a0e..93a7eb84 100644 --- a/game/script/Script_Program.h +++ b/game/script/Script_Program.h @@ -44,10 +44,24 @@ class idSaveGame; class idRestoreGame; #define MAX_STRING_LEN 128 -#define MAX_GLOBALS 296608 // in bytes - DG: increased this to the same value d3xp uses +#ifdef _D3XP +#define MAX_GLOBALS 296608 // in bytes +#else +#define MAX_GLOBALS 196608 // in bytes +#endif #define MAX_STRINGS 1024 + +#ifdef _D3XP +#define MAX_FUNCS 3584 +#else #define MAX_FUNCS 3072 +#endif + +#ifdef _D3XP +#define MAX_STATEMENTS 131072 // statement_t - 18 bytes last I checked +#else #define MAX_STATEMENTS 81920 // statement_t - 18 bytes last I checked +#endif typedef enum { ev_error = -1, ev_void, ev_scriptevent, ev_namespace, ev_string, ev_float, ev_vector, ev_entity, ev_field, ev_function, ev_virtualfunction, ev_pointer, ev_object, ev_jumpoffset, ev_argsize, ev_boolean @@ -71,7 +85,7 @@ class function_t { int firstStatement; int numStatements; int parmTotal; - int locals; // total ints of parms + locals + int locals; // total ints of parms + locals int filenum; // source file defined in idList parmSize; }; diff --git a/game/script/Script_Thread.cpp b/game/script/Script_Thread.cpp index 58daa5d9..cb826331 100644 --- a/game/script/Script_Thread.cpp +++ b/game/script/Script_Thread.cpp @@ -52,6 +52,9 @@ const idEventDef EV_Thread_Trigger( "trigger", "e" ); const idEventDef EV_Thread_SetCvar( "setcvar", "ss" ); const idEventDef EV_Thread_GetCvar( "getcvar", "s", 's' ); const idEventDef EV_Thread_Random( "random", "f", 'f' ); +#ifdef _D3XP +const idEventDef EV_Thread_RandomInt( "randomInt", "d", 'd' ); +#endif const idEventDef EV_Thread_GetTime( "getTime", NULL, 'f' ); const idEventDef EV_Thread_KillThread( "killthread", "s" ); const idEventDef EV_Thread_SetThreadName( "threadname", "s" ); @@ -72,12 +75,20 @@ const idEventDef EV_Thread_AngToRight( "angToRight", "v", 'v' ); const idEventDef EV_Thread_AngToUp( "angToUp", "v", 'v' ); const idEventDef EV_Thread_Sine( "sin", "f", 'f' ); const idEventDef EV_Thread_Cosine( "cos", "f", 'f' ); +#ifdef _D3XP +const idEventDef EV_Thread_ArcSine( "asin", "f", 'f' ); +const idEventDef EV_Thread_ArcCosine( "acos", "f", 'f' ); +#endif const idEventDef EV_Thread_SquareRoot( "sqrt", "f", 'f' ); const idEventDef EV_Thread_Normalize( "vecNormalize", "v", 'v' ); const idEventDef EV_Thread_VecLength( "vecLength", "v", 'f' ); const idEventDef EV_Thread_VecDotProduct( "DotProduct", "vv", 'f' ); const idEventDef EV_Thread_VecCrossProduct( "CrossProduct", "vv", 'v' ); const idEventDef EV_Thread_VecToAngles( "VecToAngles", "v", 'v' ); +#ifdef _D3XP +const idEventDef EV_Thread_VecToOrthoBasisAngles( "VecToOrthoBasisAngles", "v", 'v' ); +const idEventDef EV_Thread_RotateVector("rotateVector", "vv", 'v'); +#endif const idEventDef EV_Thread_OnSignal( "onSignal", "des" ); const idEventDef EV_Thread_ClearSignal( "clearSignalThread", "de" ); const idEventDef EV_Thread_SetCamera( "setCamera", "e" ); @@ -130,6 +141,9 @@ CLASS_DECLARATION( idClass, idThread ) EVENT( EV_Thread_SetCvar, idThread::Event_SetCvar ) EVENT( EV_Thread_GetCvar, idThread::Event_GetCvar ) EVENT( EV_Thread_Random, idThread::Event_Random ) +#ifdef _D3XP + EVENT( EV_Thread_RandomInt, idThread::Event_RandomInt ) +#endif EVENT( EV_Thread_GetTime, idThread::Event_GetTime ) EVENT( EV_Thread_KillThread, idThread::Event_KillThread ) EVENT( EV_Thread_SetThreadName, idThread::Event_SetThreadName ) @@ -150,12 +164,20 @@ CLASS_DECLARATION( idClass, idThread ) EVENT( EV_Thread_AngToUp, idThread::Event_AngToUp ) EVENT( EV_Thread_Sine, idThread::Event_GetSine ) EVENT( EV_Thread_Cosine, idThread::Event_GetCosine ) +#ifdef _D3XP + EVENT( EV_Thread_ArcSine, idThread::Event_GetArcSine ) + EVENT( EV_Thread_ArcCosine, idThread::Event_GetArcCosine ) +#endif EVENT( EV_Thread_SquareRoot, idThread::Event_GetSquareRoot ) EVENT( EV_Thread_Normalize, idThread::Event_VecNormalize ) EVENT( EV_Thread_VecLength, idThread::Event_VecLength ) EVENT( EV_Thread_VecDotProduct, idThread::Event_VecDotProduct ) EVENT( EV_Thread_VecCrossProduct, idThread::Event_VecCrossProduct ) EVENT( EV_Thread_VecToAngles, idThread::Event_VecToAngles ) +#ifdef _D3XP + EVENT( EV_Thread_VecToOrthoBasisAngles, idThread::Event_VecToOrthoBasisAngles ) + EVENT( EV_Thread_RotateVector, idThread::Event_RotateVector ) +#endif EVENT( EV_Thread_OnSignal, idThread::Event_OnSignal ) EVENT( EV_Thread_ClearSignal, idThread::Event_ClearSignalThread ) EVENT( EV_Thread_SetCamera, idThread::Event_SetCamera ) @@ -1070,6 +1092,16 @@ void idThread::Event_Random( float range ) const { ReturnFloat( range * result ); } +#ifdef _D3XP + +void idThread::Event_RandomInt( int range ) const { + int result; + result = gameLocal.random.RandomInt(range); + ReturnFloat(result); +} + +#endif + /* ================ idThread::Event_GetTime @@ -1285,6 +1317,26 @@ void idThread::Event_GetCosine( float angle ) { ReturnFloat( idMath::Cos( DEG2RAD( angle ) ) ); } +#ifdef _D3XP +/* +================ +idThread::Event_GetArcSine +================ +*/ +void idThread::Event_GetArcSine( float a ) { + ReturnFloat(RAD2DEG(idMath::ASin(a))); +} + +/* +================ +idThread::Event_GetArcCosine +================ +*/ +void idThread::Event_GetArcCosine( float a ) { + ReturnFloat(RAD2DEG(idMath::ACos(a))); +} +#endif + /* ================ idThread::Event_GetSquareRoot @@ -1344,6 +1396,34 @@ void idThread::Event_VecToAngles( idVec3 &vec ) { ReturnVector( idVec3( ang[0], ang[1], ang[2] ) ); } +#ifdef _D3XP +/* +================ +idThread::Event_VecToOrthoBasisAngles +================ +*/ +void idThread::Event_VecToOrthoBasisAngles( idVec3 &vec ) { + idVec3 left, up; + idAngles ang; + + vec.OrthogonalBasis( left, up ); + idMat3 axis( left, up, vec ); + + ang = axis.ToAngles(); + + ReturnVector( idVec3( ang[0], ang[1], ang[2] ) ); +} + +void idThread::Event_RotateVector( idVec3 &vec, idVec3 &ang ) { + + idAngles tempAng(ang); + idMat3 axis = tempAng.ToMat3(); + idVec3 ret = vec * axis; + ReturnVector(ret); + +} +#endif + /* ================ idThread::Event_OnSignal diff --git a/game/script/Script_Thread.h b/game/script/Script_Thread.h index fe24943f..7d776438 100644 --- a/game/script/Script_Thread.h +++ b/game/script/Script_Thread.h @@ -125,6 +125,9 @@ class idThread : public idClass { void Event_SetCvar( const char *name, const char *value ) const; void Event_GetCvar( const char *name ) const; void Event_Random( float range ) const; +#ifdef _D3XP + void Event_RandomInt( int range ) const; +#endif void Event_GetTime( void ); void Event_KillThread( const char *name ); void Event_GetEntity( const char *name ); @@ -144,12 +147,20 @@ class idThread : public idClass { void Event_AngToUp( idAngles &ang ); void Event_GetSine( float angle ); void Event_GetCosine( float angle ); +#ifdef _D3XP + void Event_GetArcSine( float a ); + void Event_GetArcCosine( float a ); +#endif void Event_GetSquareRoot( float theSquare ); void Event_VecNormalize( idVec3 &vec ); void Event_VecLength( idVec3 &vec ); void Event_VecDotProduct( idVec3 &vec1, idVec3 &vec2 ); void Event_VecCrossProduct( idVec3 &vec1, idVec3 &vec2 ); void Event_VecToAngles( idVec3 &vec ); +#ifdef _D3XP + void Event_VecToOrthoBasisAngles( idVec3 &vec ); + void Event_RotateVector( idVec3 &vec, idVec3 &ang ); +#endif void Event_OnSignal( int signal, idEntity *ent, const char *func ); void Event_ClearSignalThread( int signal, idEntity *ent ); void Event_SetCamera( idEntity *ent ); From 7a593156f70b7594c3e648e48bc7880842f53553 Mon Sep 17 00:00:00 2001 From: Nick Whitlock Date: Wed, 24 May 2023 02:26:38 -0400 Subject: [PATCH 2/3] Some code accidentally got caught in a macro that shouldn't have been. --- game/Player.cpp | 6 ++++-- game/Player.h | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/game/Player.cpp b/game/Player.cpp index 36ae3393..294a14d1 100644 --- a/game/Player.cpp +++ b/game/Player.cpp @@ -92,7 +92,6 @@ const idEventDef EV_SpectatorTouch( "spectatorTouch", "et" ); #ifdef _D3XP const idEventDef EV_Player_GiveInventoryItem( "giveInventoryItem", "s" ); const idEventDef EV_Player_RemoveInventoryItem( "removeInventoryItem", "s" ); -const idEventDef EV_Player_GetIdealWeapon( "getIdealWeapon", NULL, 's' ); const idEventDef EV_Player_SetPowerupTime( "setPowerupTime", "dd" ); const idEventDef EV_Player_IsPowerupActive( "isPowerupActive", "d", 'd' ); const idEventDef EV_Player_WeaponAvailable( "weaponAvailable", "s", 'd'); @@ -101,6 +100,7 @@ const idEventDef EV_Player_StopHelltime( "stopHelltime", "d" ); const idEventDef EV_Player_ToggleBloom( "toggleBloom", "d" ); const idEventDef EV_Player_SetBloomParms( "setBloomParms", "ff" ); #endif +const idEventDef EV_Player_GetIdealWeapon("getIdealWeapon", NULL, 's'); CLASS_DECLARATION( idActor, idPlayer ) EVENT( EV_Player_GetButtons, idPlayer::Event_GetButtons ) @@ -123,7 +123,6 @@ CLASS_DECLARATION( idActor, idPlayer ) #ifdef _D3XP EVENT( EV_Player_GiveInventoryItem, idPlayer::Event_GiveInventoryItem ) EVENT( EV_Player_RemoveInventoryItem, idPlayer::Event_RemoveInventoryItem ) - EVENT( EV_Player_GetIdealWeapon, idPlayer::Event_GetIdealWeapon ) EVENT( EV_Player_WeaponAvailable, idPlayer::Event_WeaponAvailable ) EVENT( EV_Player_SetPowerupTime, idPlayer::Event_SetPowerupTime ) EVENT( EV_Player_IsPowerupActive, idPlayer::Event_IsPowerupActive ) @@ -132,6 +131,7 @@ CLASS_DECLARATION( idActor, idPlayer ) EVENT( EV_Player_ToggleBloom, idPlayer::Event_ToggleBloom ) EVENT( EV_Player_SetBloomParms, idPlayer::Event_SetBloomParms ) #endif + EVENT( EV_Player_GetIdealWeapon, idPlayer::Event_GetIdealWeapon ) END_CLASS const int MAX_RESPAWN_TIME = 10000; @@ -9031,6 +9031,7 @@ idPlayer::Event_RemoveInventoryItem void idPlayer::Event_RemoveInventoryItem( const char* name ) { RemoveInventoryItem(name); } +#endif /* ================== @@ -9048,6 +9049,7 @@ void idPlayer::Event_GetIdealWeapon( void ) { } } +#ifdef _D3XP /* ================== idPlayer::Event_SetPowerupTime diff --git a/game/Player.h b/game/Player.h index aadf8550..29b4c898 100644 --- a/game/Player.h +++ b/game/Player.h @@ -806,7 +806,6 @@ class idPlayer : public idActor { void Event_GiveInventoryItem( const char* name ); void Event_RemoveInventoryItem( const char* name ); - void Event_GetIdealWeapon( void ); void Event_WeaponAvailable( const char* name ); void Event_SetPowerupTime( int powerup, int time ); void Event_IsPowerupActive( int powerup ); @@ -815,6 +814,7 @@ class idPlayer : public idActor { void Event_ToggleBloom( int on ); void Event_SetBloomParms( float speed, float intensity ); #endif + void Event_GetIdealWeapon(void); }; ID_INLINE bool idPlayer::IsReady( void ) { From 2072cb7f527e86f684da3fa5db86d54f9d73b5da Mon Sep 17 00:00:00 2001 From: Nick Whitlock Date: Wed, 24 May 2023 02:51:59 -0400 Subject: [PATCH 3/3] Fixed smoke particle effects. --- game/Player.cpp | 2 ++ game/SmokeParticles.cpp | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/game/Player.cpp b/game/Player.cpp index 294a14d1..163844ae 100644 --- a/game/Player.cpp +++ b/game/Player.cpp @@ -8703,6 +8703,8 @@ void idPlayer::CalculateRenderView( void ) { #ifdef _D3XP renderView->time = gameLocal.slow.time; +#else + renderView->time = gameLocal.time; #endif // calculate size of 3D view diff --git a/game/SmokeParticles.cpp b/game/SmokeParticles.cpp index bc8b277f..bd3ea6ae 100644 --- a/game/SmokeParticles.cpp +++ b/game/SmokeParticles.cpp @@ -240,7 +240,11 @@ bool idSmokeParticles::EmitSmoke( const idDeclParticle *smoke, const int systemS if ( nowCount >= stage->totalParticles ) { nowCount = stage->totalParticles-1; } +#ifdef _D3XP prevCount = floor( ((float)( deltaMsec - gameLocal.msec /*_D3XP - FIX - was USERCMD_MSEC*/ ) / finalParticleTime) * stage->totalParticles ); +#else + prevCount = floor( ((float)( deltaMsec - USERCMD_MSEC ) / finalParticleTime) * stage->totalParticles ); +#endif // _D3XP if ( prevCount < -1 ) { prevCount = -1; }