From 78f632ceb1a15876834cfa9370a1367ddee76a4e Mon Sep 17 00:00:00 2001 From: Jereth Date: Tue, 1 Apr 2025 23:01:45 +1100 Subject: [PATCH 1/3] Camera --- TheForceEngine/TFE_Asset/dfKeywords.cpp | 3 +- TheForceEngine/TFE_Asset/dfKeywords.h | 3 +- TheForceEngine/TFE_DarkForces/logic.cpp | 7 +++- TheForceEngine/TFE_DarkForces/mission.cpp | 2 +- TheForceEngine/TFE_DarkForces/player.cpp | 8 +++- TheForceEngine/TFE_DarkForces/player.h | 2 + TheForceEngine/TFE_DarkForces/weapon.cpp | 12 +++++- .../TFE_Jedi/InfSystem/infSystem.cpp | 41 +++++++++++++++++++ TheForceEngine/TFE_Jedi/InfSystem/message.h | 1 + TheForceEngine/TFE_Jedi/Level/robjData.h | 1 + 10 files changed, 73 insertions(+), 7 deletions(-) diff --git a/TheForceEngine/TFE_Asset/dfKeywords.cpp b/TheForceEngine/TFE_Asset/dfKeywords.cpp index 3601394d4..1f8b36f51 100644 --- a/TheForceEngine/TFE_Asset/dfKeywords.cpp +++ b/TheForceEngine/TFE_Asset/dfKeywords.cpp @@ -227,7 +227,8 @@ static const char* c_keywords[] = "M_TRIGGER", // TFE "SCRIPTCALL:", - "NAME:" + "NAME:", + "CAMERA", }; #define KEYWORD_COUNT TFE_ARRAYSIZE(c_keywords) diff --git a/TheForceEngine/TFE_Asset/dfKeywords.h b/TheForceEngine/TFE_Asset/dfKeywords.h index 373dcef67..d9dea4519 100644 --- a/TheForceEngine/TFE_Asset/dfKeywords.h +++ b/TheForceEngine/TFE_Asset/dfKeywords.h @@ -235,7 +235,8 @@ enum KEYWORD // TFE ADDED KW_SCRIPTCALL, KW_NAME, + KW_CAMERA, // TFE - camera feature KW_COUNT }; -extern KEYWORD getKeywordIndex(const char* keywordString); \ No newline at end of file +extern KEYWORD getKeywordIndex(const char* keywordString); diff --git a/TheForceEngine/TFE_DarkForces/logic.cpp b/TheForceEngine/TFE_DarkForces/logic.cpp index a900ecb83..999dbc317 100644 --- a/TheForceEngine/TFE_DarkForces/logic.cpp +++ b/TheForceEngine/TFE_DarkForces/logic.cpp @@ -102,6 +102,11 @@ namespace TFE_DarkForces { obj->worldWidth = floatToFixed16(strtof(s_objSeqArg1, &endPtr)); } + // New in TFE + else if (key == KW_CAMERA) + { + obj->flags |= OBJ_FLAG_CAMERA; + } else if (key == KW_NAME) { // TFE - scripting @@ -496,4 +501,4 @@ namespace TFE_DarkForces return nullptr; } -} // TFE_DarkForces \ No newline at end of file +} // TFE_DarkForces diff --git a/TheForceEngine/TFE_DarkForces/mission.cpp b/TheForceEngine/TFE_DarkForces/mission.cpp index 69b423310..303b163f1 100644 --- a/TheForceEngine/TFE_DarkForces/mission.cpp +++ b/TheForceEngine/TFE_DarkForces/mission.cpp @@ -986,7 +986,7 @@ namespace TFE_DarkForces void enableNightVision() { - if (!s_playerInfo.itemGoggles) { return; } + if (!s_playerInfo.itemGoggles || s_externalCameraMode) { return; } if (!s_batteryPower) { diff --git a/TheForceEngine/TFE_DarkForces/player.cpp b/TheForceEngine/TFE_DarkForces/player.cpp index d45fe8de2..0fb8b0c0f 100644 --- a/TheForceEngine/TFE_DarkForces/player.cpp +++ b/TheForceEngine/TFE_DarkForces/player.cpp @@ -222,6 +222,7 @@ namespace TFE_DarkForces SecObject* s_playerEye = nullptr; vec3_fixed s_eyePos = { 0 }; // s_camX, s_camY, s_camZ in the DOS code. angle14_32 s_eyePitch = 0, s_eyeYaw = 0, s_eyeRoll = 0; + JBool s_externalCameraMode = JFALSE; u32 s_playerEyeFlags = OBJ_FLAG_NEEDS_TRANSFORM; Tick s_playerTick; Tick s_prevPlayerTick; @@ -899,6 +900,8 @@ namespace TFE_DarkForces s_disablePlayerRotation = JFALSE; s_disablePlayerFire = JFALSE; + s_externalCameraMode = JFALSE; + s_crushSoundId = 0; s_kyleScreamSoundId = 0; @@ -1415,7 +1418,7 @@ namespace TFE_DarkForces { renderer_computeCameraTransform(s_playerEye->sector, s_eyePitch, s_eyeYaw, s_eyePos.x, s_eyePos.y, s_eyePos.z); } - renderer_setWorldAmbient(s_playerLight); + renderer_setWorldAmbient(s_externalCameraMode ? 0 : s_playerLight); // don't apply headlamp attentuation when camera is away from player } } @@ -1554,6 +1557,9 @@ namespace TFE_DarkForces s_disablePlayerMovement = JFALSE; s_disablePlayerRotation = JFALSE; s_disablePlayerFire = JFALSE; + + s_externalCameraMode = JFALSE; + player_setupEyeObject(s_playerObject); } void player_changeSector(RSector* newSector) diff --git a/TheForceEngine/TFE_DarkForces/player.h b/TheForceEngine/TFE_DarkForces/player.h index 8f6dd36bf..ec26ff177 100644 --- a/TheForceEngine/TFE_DarkForces/player.h +++ b/TheForceEngine/TFE_DarkForces/player.h @@ -106,6 +106,8 @@ namespace TFE_DarkForces extern fixed16_16 s_playerYPos; extern vec3_fixed s_eyePos; // s_camX, s_camY, s_camZ in the DOS code. extern angle14_32 s_eyePitch, s_eyeYaw, s_eyeRoll; + extern JBool s_externalCameraMode; // TFE - camera feature + extern angle14_32 s_playerYaw; extern Tick s_playerTick; extern Tick s_prevPlayerTick; diff --git a/TheForceEngine/TFE_DarkForces/weapon.cpp b/TheForceEngine/TFE_DarkForces/weapon.cpp index 51852fc6e..5a9ba05ce 100644 --- a/TheForceEngine/TFE_DarkForces/weapon.cpp +++ b/TheForceEngine/TFE_DarkForces/weapon.cpp @@ -892,6 +892,7 @@ namespace TFE_DarkForces if (!s_weaponOffAnim) { + // Remove weapon from screen weapon_setIdle(); s_weaponAnimState = @@ -906,6 +907,7 @@ namespace TFE_DarkForces } else { + // Return weapon to screen s_weaponOffAnim = JFALSE; if (s_curWeapon == WPN_PISTOL || s_curWeapon == WPN_RIFLE || s_curWeapon == WPN_REPEATER || s_curWeapon == WPN_FUSION || s_curWeapon == WPN_MORTAR || s_curWeapon == WPN_CONCUSSION || s_curWeapon == WPN_CANNON) @@ -986,6 +988,12 @@ namespace TFE_DarkForces // for TFE I split it out to limit the amount of game code in the renderer. void weapon_draw(u8* display, DrawRect* rect) { + // TFE - don't draw weapon in external camera mode + if (s_externalCameraMode) + { + return; + } + const fixed16_16 weaponLightingZDist = FIXED(6); const fixed16_16 gasmaskLightingZDist = FIXED(2); @@ -1009,7 +1017,7 @@ namespace TFE_DarkForces x += weapon->xOffset; y += weapon->yOffset; } - + const u8* atten = RClassic_Fixed::computeLighting(weaponLightingZDist, 0); TextureData* tex = weapon->frames[weapon->frame]; if (weapon->ammo && *weapon->ammo == 0 && (weapon->ammo == &s_playerInfo.ammoDetonator || weapon->ammo == &s_playerInfo.ammoMine)) @@ -1109,4 +1117,4 @@ namespace TFE_DarkForces } } } -} // namespace TFE_DarkForces \ No newline at end of file +} // namespace TFE_DarkForces diff --git a/TheForceEngine/TFE_Jedi/InfSystem/infSystem.cpp b/TheForceEngine/TFE_Jedi/InfSystem/infSystem.cpp index f2baa97f1..d3b9f066a 100644 --- a/TheForceEngine/TFE_Jedi/InfSystem/infSystem.cpp +++ b/TheForceEngine/TFE_Jedi/InfSystem/infSystem.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -1921,6 +1922,10 @@ namespace TFE_Jedi case KW_LIGHTS: *type = MSG_LIGHTS; break; + // TFE - camera feature + case KW_CAMERA: + *type = MSG_CAMERA; + break; case KW_M_TRIGGER: default: if (elevator) @@ -3232,6 +3237,42 @@ namespace TFE_Jedi } } } break; + // TFE - camera feature + case MSG_CAMERA: + { + if (s_externalCameraMode == JFALSE) + { + // Change EYE to external camera if there is one + s32 objCount = sector->objectCount; + s32 objCapacity = sector->objectCapacity; + SecObject** objList = sector->objectList; + + for (s32 i = 0; i < objCount && i < objCapacity; objList++) + { + SecObject* obj = *objList; + if (obj) + { + if (obj->flags & OBJ_FLAG_CAMERA) + { + // Disable night vision + if (s_nightVisionActive) { disableNightVision(); } + + player_setupEyeObject(obj); + s_externalCameraMode = JTRUE; + break; + } + i++; + } + } + } + else + { + // Move EYE back to player + player_setupEyeObject(s_playerObject); + s_externalCameraMode = JFALSE; + } + + } break; case MSG_SET_BITS: { u32 flagsIndex = s_msgArg1; diff --git a/TheForceEngine/TFE_Jedi/InfSystem/message.h b/TheForceEngine/TFE_Jedi/InfSystem/message.h index 1f086aec7..625df0e56 100644 --- a/TheForceEngine/TFE_Jedi/InfSystem/message.h +++ b/TheForceEngine/TFE_Jedi/InfSystem/message.h @@ -37,6 +37,7 @@ enum MessageType MSG_CLEAR_BITS = 32, MSG_COMPLETE = 33, MSG_LIGHTS = 34, + MSG_CAMERA = 35, // TFE - camera feature MSG_COUNT }; diff --git a/TheForceEngine/TFE_Jedi/Level/robjData.h b/TheForceEngine/TFE_Jedi/Level/robjData.h index bdf3d886c..0bb05968f 100644 --- a/TheForceEngine/TFE_Jedi/Level/robjData.h +++ b/TheForceEngine/TFE_Jedi/Level/robjData.h @@ -31,6 +31,7 @@ enum ObjectFlags OBJ_FLAG_MOVABLE = FLAG_BIT(4), // Object is movable. OBJ_FLAG_BOSS = FLAG_BIT(5), // Boss enemy. OBJ_FLAG_NO_REMOVE = FLAG_BIT(6), // Do not remove when crushed + OBJ_FLAG_CAMERA = FLAG_BIT(7), // New in TFE }; enum EntityTypeFlags From 5339ca33d2c05f01bb792833db978b4c6cf2940f Mon Sep 17 00:00:00 2001 From: Jereth Date: Fri, 18 Apr 2025 21:03:33 +1000 Subject: [PATCH 2/3] Serialization --- TheForceEngine/TFE_DarkForces/player.cpp | 1 + TheForceEngine/TFE_Jedi/Level/robjData.h | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/TheForceEngine/TFE_DarkForces/player.cpp b/TheForceEngine/TFE_DarkForces/player.cpp index 0fb8b0c0f..ee0c30cc8 100644 --- a/TheForceEngine/TFE_DarkForces/player.cpp +++ b/TheForceEngine/TFE_DarkForces/player.cpp @@ -3370,6 +3370,7 @@ namespace TFE_DarkForces SERIALIZE(ObjState_DisablePlayerMovement, s_disablePlayerMovement, JFALSE); SERIALIZE(ObjState_DisablePlayerMovement, s_disablePlayerRotation, JFALSE); SERIALIZE(ObjState_DisablePlayerMovement, s_disablePlayerFire, JFALSE); + SERIALIZE(ObjState_ExternalCamera, s_externalCameraMode, JFALSE); s32 invSavedSize = 0; if (serialization_getMode() == SMODE_WRITE && s_playerInvSaved) diff --git a/TheForceEngine/TFE_Jedi/Level/robjData.h b/TheForceEngine/TFE_Jedi/Level/robjData.h index 0bb05968f..4b00d73d6 100644 --- a/TheForceEngine/TFE_Jedi/Level/robjData.h +++ b/TheForceEngine/TFE_Jedi/Level/robjData.h @@ -67,7 +67,8 @@ enum ObjStateVersion : u32 ObjState_ConstOverrides = 7, ObjState_DisablePlayerMovement = 8, ObjState_RefList = 9, - ObjState_CurVersion = ObjState_RefList, + ObjState_ExternalCamera = 10, + ObjState_CurVersion = ObjState_ExternalCamera, }; // TFE Scripting From b3f2ace61ac4a880e86ec64794731695acb4ae42 Mon Sep 17 00:00:00 2001 From: Jereth Date: Sat, 19 Apr 2025 21:45:59 +1000 Subject: [PATCH 3/3] Set camera via scripting --- .../TFE_DarkForces/Scripting/gs_player.cpp | 7 +++++++ .../TFE_DarkForces/Scripting/scriptObject.cpp | 13 +++++++++++++ TheForceEngine/TFE_DarkForces/logic.cpp | 10 +++++----- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/TheForceEngine/TFE_DarkForces/Scripting/gs_player.cpp b/TheForceEngine/TFE_DarkForces/Scripting/gs_player.cpp index 458c5fd28..64de19705 100644 --- a/TheForceEngine/TFE_DarkForces/Scripting/gs_player.cpp +++ b/TheForceEngine/TFE_DarkForces/Scripting/gs_player.cpp @@ -603,6 +603,12 @@ namespace TFE_DarkForces return result; } + void setCamera() + { + player_setupEyeObject(s_playerObject); + s_externalCameraMode = JFALSE; + } + bool GS_Player::scriptRegister(ScriptAPI api) { ScriptClassBegin("Player", "player", api); @@ -644,6 +650,7 @@ namespace TFE_DarkForces ScriptObjFunc("void disableActions(uint)", disableActions); ScriptObjFunc("void enableActions(uint)", enableActions); ScriptPropertyGetFunc("uint get_disabledActions()", getDisabledActions); + ScriptObjFunc("void setCamera()", setCamera); // Position and velocity ScriptPropertyGetFunc("float3 get_position()", getPlayerPosition); diff --git a/TheForceEngine/TFE_DarkForces/Scripting/scriptObject.cpp b/TheForceEngine/TFE_DarkForces/Scripting/scriptObject.cpp index c65e76f54..cf4373c57 100644 --- a/TheForceEngine/TFE_DarkForces/Scripting/scriptObject.cpp +++ b/TheForceEngine/TFE_DarkForces/Scripting/scriptObject.cpp @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include #include #include @@ -265,6 +267,16 @@ namespace TFE_DarkForces // TODO enable adding custom logic } + void setCamera(ScriptObject* sObject) + { + if (!doesObjectExist(sObject)) { return; } + + SecObject* obj = TFE_Jedi::s_objectRefList[sObject->m_id].object; + player_setupEyeObject(obj); + s_externalCameraMode = obj == s_playerObject ? JFALSE : JTRUE; + if (s_nightVisionActive) { disableNightVision(); } + } + void ScriptObject::registerType() { s32 res = 0; @@ -301,5 +313,6 @@ namespace TFE_DarkForces // Other functions ScriptObjFunc("void delete()", deleteObject); ScriptObjFunc("void addLogic(string)", addLogicToObject); + ScriptObjFunc("void setCamera()", setCamera); } } diff --git a/TheForceEngine/TFE_DarkForces/logic.cpp b/TheForceEngine/TFE_DarkForces/logic.cpp index 999dbc317..1db274124 100644 --- a/TheForceEngine/TFE_DarkForces/logic.cpp +++ b/TheForceEngine/TFE_DarkForces/logic.cpp @@ -102,16 +102,16 @@ namespace TFE_DarkForces { obj->worldWidth = floatToFixed16(strtof(s_objSeqArg1, &endPtr)); } + // TFE - scripting + else if (key == KW_NAME) + { + TFE_Jedi::obj_addName(s_objSeqArg1, obj); + } // New in TFE else if (key == KW_CAMERA) { obj->flags |= OBJ_FLAG_CAMERA; } - else if (key == KW_NAME) - { - // TFE - scripting - TFE_Jedi::obj_addName(s_objSeqArg1, obj); - } else // Invalid key. { retValue = JFALSE;