From d72d6b311b44ee8af27d595c135d75f84d41e232 Mon Sep 17 00:00:00 2001 From: anatoliy-savchak <40269424+anatoliy-savchak@users.noreply.github.com> Date: Sun, 25 Feb 2024 16:00:01 +0200 Subject: [PATCH] temp temp --- TemplePlus/action_sequence.cpp | 4 +- TemplePlus/ai.cpp | 110 ++++++++++++++++++- TemplePlus/ai.h | 2 +- TemplePlus/animgoals/animgoals.cpp | 6 +- TemplePlus/animgoals/animgoals_callbacks.cpp | 6 +- TemplePlus/condition.h | 2 +- TemplePlus/d20.cpp | 13 +++ TemplePlus/fonts/fonts_hooks.cpp | 2 +- TemplePlus/obj.cpp | 6 +- TemplePlus/pathfinding.cpp | 18 +-- TemplePlus/python/python_debug.cpp | 20 ++++ TemplePlus/python/python_integration_obj.cpp | 1 + TemplePlus/python/python_object.cpp | 99 +++++++++++++++++ TemplePlus/secret_door.cpp | 14 +++ TemplePlus/sound.cpp | 2 +- TemplePlus/ui/ui_intgame_turnbased.cpp | 2 +- 16 files changed, 286 insertions(+), 21 deletions(-) diff --git a/TemplePlus/action_sequence.cpp b/TemplePlus/action_sequence.cpp index 7e78d3156..572c9235c 100644 --- a/TemplePlus/action_sequence.cpp +++ b/TemplePlus/action_sequence.cpp @@ -1115,7 +1115,7 @@ uint32_t ActionSequenceSystem::MoveSequenceParse(D20Actn* d20aIn, ActnSeq* actSe | PathQueryFlags::PQF_TARGET_OBJ | PathQueryFlags::PQF_ADJUST_RADIUS | PathQueryFlags::PQF_ADJ_RADIUS_REQUIRE_LOS); - if (reach < 0.1){ reach = 3.0; } + if (reach < 0.1){ reach = 1.0; } actSeq->targetObj = d20a->d20ATarget; pathQ.distanceToTargetMin = distToTgtMin * INCH_PER_FEET; pathQ.tolRadius = reach * INCH_PER_FEET - fourPointSevenPlusEight; @@ -1143,7 +1143,7 @@ uint32_t ActionSequenceSystem::MoveSequenceParse(D20Actn* d20aIn, ActnSeq* actSe // find path *pathfindingSys.rollbackSequenceFlag = 0; - if ( (d20aCopy.d20Caf & D20CAF_CHARGE ) || d20a->d20ActType == D20A_RUN || d20a->d20ActType == D20A_DOUBLE_MOVE) + if ( (d20aCopy.d20Caf & D20CAF_CHARGE ) || d20a->d20ActType == D20A_RUN /* || d20a->d20ActType == D20A_DOUBLE_MOVE*/) { *reinterpret_cast(&pathQ.flags) |= PQF_DONT_USE_PATHNODES; // so it runs in a straight line } diff --git a/TemplePlus/ai.cpp b/TemplePlus/ai.cpp index d11749f0c..202a87e7c 100644 --- a/TemplePlus/ai.cpp +++ b/TemplePlus/ai.cpp @@ -821,6 +821,16 @@ objHndl AiSystem::FindSuitableTarget(objHndl handle){ if (aiSearchingTgt) return objHndl::null; + auto kosCandidate = objHndl::null; + + py::tuple args = py::make_tuple(py::cast(handle), py::cast(aiSearchingTgt)); + auto pyResult = pythonObjIntegration.ExecuteScript("d20_ai.targeting", "find_suitable_target", args.ptr()); + if (pyResult && PyObjHndl_Check(pyResult) && ConvertObjHndl(pyResult, &kosCandidate)) { + if (!objSystem->IsValidHandle(kosCandidate)) + kosCandidate = objHndl::null; + } + return kosCandidate; + // begin search section aiSearchingTgt = 1; @@ -863,7 +873,6 @@ objHndl AiSystem::FindSuitableTarget(objHndl handle){ } } - auto kosCandidate = objHndl::null; for (auto i =0; i < numCritters; i++){ auto target = critterList[i]; @@ -1071,6 +1080,16 @@ void AiSystem::GetAiFightStatus(objHndl handle, AiFightStatus* status, objHndl* void AiSystem::AlertAllies(objHndl handle, objHndl alertFrom, int rangeIdx){ + auto kosCandidate = objHndl::null; + + py::tuple args = py::make_tuple(py::cast(handle), py::cast(alertFrom)); + auto pyResult = pythonObjIntegration.ExecuteScript("d20_ai.targeting", "alert_allies", args.ptr()); + if (PyInt_Check(pyResult)) { + auto result = _PyInt_AsInt(pyResult); + if (!result) + return; + } + auto rangeTiles = temple::GetRef(0x102BD4D0)[rangeIdx]; auto tileDelta = locSys.GetTileDeltaMax(alertFrom, handle); @@ -1145,6 +1164,14 @@ void AiSystem::AlertAlly(objHndl handle, objHndl alertFrom, objHndl alertDispatc void AiSystem::AlertAllies2(objHndl handle, objHndl alertFrom) { + py::tuple args = py::make_tuple(py::cast(handle), py::cast(alertFrom)); + auto pyResult = pythonObjIntegration.ExecuteScript("d20_ai.targeting", "alert_allies2", args.ptr()); + if (PyInt_Check(pyResult)) { + auto result = _PyInt_AsInt(pyResult); + if (!result) + return; + } + ObjList objList; const int ALLY_ALERTING_DISTANCE = 24; // test cases: @@ -3448,6 +3475,83 @@ int AiSystem::AiTimeEventExpires(TimeEvent* evt) return 1; } +BOOL AiSystem::NpcWander(objHndl handle, int move) +{ + static auto GetStandPointLoc = [](locXY& loc, objHndl critter) { + if (critterSys.GetLeader(critter).handle) + return 0; + + auto is_day = gameSystems->GetTimeEvent().IsDaytime(); + auto npc_flags = objSystem->GetObject(critter)->GetNPCFlags(); + StandPoint sp; + if (is_day || ((npc_flags & NpcFlag::ONF_WAYPOINTS_DAY) && !scriptSys.GetGlobalFlag(144))) { + sp = critterSys.GetStandPoint(critter, StandPointType::Day); + } + else + sp = critterSys.GetStandPoint(critter, StandPointType::Night); + loc = sp.location.location; + if (loc.locx || loc.locy) + return 1; + return 0; + }; + + auto obj = objSystem->GetObject(handle); + auto isSleeping = critterSys.IsSleeping(handle); + locXY standPointLoc; + if (!isSleeping && obj->GetFlags() & (OF_DONTDRAW | OF_OFF) || !GetStandPointLoc(standPointLoc, handle)) + return 0; + + auto critterMapId = critterSys.GetCritterMap(handle); + auto currentMapId = maps.GetCurrentMapId(); + if (critterMapId == currentMapId) { + if (!move) { + auto hour = temple::GetRef(0x1005FF70)(); // GetElapsedTimeHour + if (hour == 6) + { + if (rngSys.GetInt(1, 1000) != 1) { + return 0; + } + } + else if (hour == 18 && (rngSys.GetInt(1, 1000) != 1)) { + return 0; + } + } + } + else if (!move) + return 0; + + auto npcFlags = obj->GetNPCFlags(); + int64_t threshhold = (npcFlags & (NpcFlag::ONF_WANDERS_IN_DARK | NpcFlag::ONF_WANDERS)) != 0 ? 4 : 1; + int64_t tileDelta = locSys.GetTileDeltaMaxBtwnLocs(standPointLoc, obj->GetLocation()); + if (tileDelta > threshhold) { + if (!isSleeping) { + if (move) { + if (critterMapId == currentMapId) { + gameSystems->GetAnim().Interrupt(handle, AnimGoalPriority::AGP_4, false); + objects.Move(handle, LocAndOffsets::create(standPointLoc, 0, 0)); + return 1; + } + } + else { + temple::GetRef(0x10058590)(handle, LocAndOffsets::create(standPointLoc, 0, 0), 1.0f); // NpcWander_10058590 + } + } + } + else if (!isSleeping) + { + if (npcFlags & NpcFlag::ONF_AI_SPREAD_OUT) { + //temple::GetRef(0x10058590)(handle, LocAndOffsets::create(standPointLoc, 0, 0), 1.0f); // NpcWander_10058590 + return 1; + } + if (npcFlags & NpcFlag::ONF_JILTED) { + temple::GetRef(0x1001A720)(handle, (uint64_t)standPointLoc, 4); // PickLockInRadius + return 1; + } + return 0; + } + return 1; +} + #pragma endregion #pragma region AI replacement functions @@ -4019,6 +4123,10 @@ class AiReplacements : public TempleFix return result; }); + replaceFunction(0x1005BC00, [](objHndl obj, int move) { + return aiSys.NpcWander(obj, move); + }); + } } aiReplacements; diff --git a/TemplePlus/ai.h b/TemplePlus/ai.h index ec91094fd..5b0dedbec 100644 --- a/TemplePlus/ai.h +++ b/TemplePlus/ai.h @@ -279,7 +279,7 @@ struct AiSystem : temple::AddressTable bool AiProcessPc(objHndl handle); int AiTimeEventExpires(TimeEvent* evt); - + BOOL NpcWander(objHndl handle, int move); private: void (__cdecl *_ShitlistAdd)(objHndl npc, objHndl target); void (__cdecl *_AiRemoveFromList)(objHndl npc, objHndl target, int listType); diff --git a/TemplePlus/animgoals/animgoals.cpp b/TemplePlus/animgoals/animgoals.cpp index 2bef93301..6766546b4 100644 --- a/TemplePlus/animgoals/animgoals.cpp +++ b/TemplePlus/animgoals/animgoals.cpp @@ -2568,8 +2568,10 @@ AnimationGoals::AnimationGoals() const AnimGoal & AnimationGoals::GetByType(AnimGoalType type) const { - using AnimGoalArray = const AnimGoal*[82]; - static auto mGoals = temple::GetRef(0x102BD1B0); + //using AnimGoalArray = const AnimGoal*[82]; + //static auto mGoals = temple::GetRef(0x102BD1B0); + using AnimGoalArray = const AnimGoal* [82]; + AnimGoalArray& goals = temple::GetRef(0x102BD1B0); //return *mGoals[type]; diff --git a/TemplePlus/animgoals/animgoals_callbacks.cpp b/TemplePlus/animgoals/animgoals_callbacks.cpp index 62eeee9d4..e171ccca0 100644 --- a/TemplePlus/animgoals/animgoals_callbacks.cpp +++ b/TemplePlus/animgoals/animgoals_callbacks.cpp @@ -1099,7 +1099,11 @@ int GoalUnconcealCleanup(AnimSlot &slot) { // Originally @ 0x10018050 int GoalResetToIdleAnim(AnimSlot &slot) { static auto org = temple::GetRef::type>(0x10018050); - return org(slot); + auto result = org(slot); + if (slot.animObj && slot.uniqueActionId) { + d20Sys.D20SignalPython(slot.animObj, "GoalResetToIdleAnim", slot.uniqueActionId, slot.id.uniqueId); + } + return result; } // Originally @ 0x10018160 diff --git a/TemplePlus/condition.h b/TemplePlus/condition.h index 8bc8ebab3..99ff6c6cd 100644 --- a/TemplePlus/condition.h +++ b/TemplePlus/condition.h @@ -24,7 +24,7 @@ struct CondHashSystem : ToEEHashtableSystem < CondStruct > uint32_t ConditionHashtableInit(ToEEHashtable * hashtable) { - return HashtableInit(hashtable, 1000); + return HashtableInit(hashtable, 2000); } uint32_t CondStructAddToHashtable(CondStruct * condStruct, bool overriding = false) diff --git a/TemplePlus/d20.cpp b/TemplePlus/d20.cpp index e1114b874..c7614302f 100644 --- a/TemplePlus/d20.cpp +++ b/TemplePlus/d20.cpp @@ -628,6 +628,19 @@ void LegacyD20System::NewD20ActionsInit() //d20Defs[D20A_DISARM] = d20Defs[D20A_STANDARD_ATTACK]; //d20Defs[d20Type].actionCost = _ActionCostNull; // just for testing - REMOVE!!! + + d20Type = D20A_THROW_GRENADE; + //d20Defs[d20Type].addToSeqFunc = AddToSeqGrenade @0x10094840 + //d20Defs[d20Type].turnBasedStatusCheck = actSeqSys.StdAttackTurnBasedStatusCheck; + //d20Defs[d20Type].actionCheckFunc = nullptr; + //d20Defs[d20Type].tgtCheckFunc = nullptr; + //d20Defs[d20Type].locCheckFunc = ActionCheckThrowGrenade @ 0x1008f690; + //d20Defs[d20Type].performFunc = PerformFuncThrowGrenade @ 0x1008fb50 + //d20Defs[d20Type].actionFrameFunc = ActionFrameThrowGrenade @ 0x10090000 + //d20Defs[d20Type].projectileHitFunc = ThrowGrenadeProjectilePerformFunc @ 0x1008fbe0 + //d20Defs[d20Type].actionCost = ActionCostStandardAttack + //d20Defs[d20Type].seqRenderFunc = PickerFuncAttackChancesWithCoverProvidersHighlighted @ 0x1008f460 + } void LegacyD20System::InfinityEngineBullshit(){ diff --git a/TemplePlus/fonts/fonts_hooks.cpp b/TemplePlus/fonts/fonts_hooks.cpp index 261c88e05..429ed7d85 100644 --- a/TemplePlus/fonts/fonts_hooks.cpp +++ b/TemplePlus/fonts/fonts_hooks.cpp @@ -46,7 +46,7 @@ int FontRenderFix::FontDraw(const char* text, TigRect* extents, TigTextStyle* st auto& layouter = tig->GetTextLayouter(); if (extents->x < 0 || extents->width < 0){ - logger->warn("Negative Text extents! Aborting draw."); + //logger->warn("Negative Text extents! Aborting draw."); return 0; } diff --git a/TemplePlus/obj.cpp b/TemplePlus/obj.cpp index 67ddcfc66..b8540b09e 100644 --- a/TemplePlus/obj.cpp +++ b/TemplePlus/obj.cpp @@ -1158,7 +1158,11 @@ class ObjectReplacements : public TempleFix { replaceFunction(0x1002B390, [](objHndl handle) ->BOOL { return objects.IsPlayerControlled(handle) ? TRUE:FALSE; }); -} + + static BOOL(__cdecl * orgaiForceSpreadout)(objHndl, LocAndOffsets) = replaceFunction(0x1005A640, [](objHndl handle, LocAndOffsets location)->BOOL { + return orgaiForceSpreadout(handle, location); + }); + } } objReplacements; int(*ObjectReplacements::orgMove)(objHndl, LocAndOffsets); diff --git a/TemplePlus/pathfinding.cpp b/TemplePlus/pathfinding.cpp index 6106ecf38..8b1dea347 100644 --- a/TemplePlus/pathfinding.cpp +++ b/TemplePlus/pathfinding.cpp @@ -245,8 +245,8 @@ Pathfinding::Pathfinding() { loc = &locSys; - aStarMaxTimeMs = 4000; - aStarMaxWindowMs = 5000; + aStarMaxTimeMs = 10000; + aStarMaxWindowMs = 10000; aStarTimeIdx = -1; memset(pathCache, 0, sizeof(pathCache)); @@ -1554,7 +1554,7 @@ int Pathfinding::FindPath(PathQuery* pq, PathQueryResult* pqr) if (pq->critter) { pdbgMover = pq->critter; - logger->info("Starting path attempt for {}", description.getDisplayName(pdbgMover)); + //logger->info("Starting path attempt for {}", description.getDisplayName(pdbgMover)); } pdbgFrom = pq->from; if ((pq->flags & PQF_TARGET_OBJ) && pq->targetObj ) @@ -1591,10 +1591,10 @@ int Pathfinding::FindPath(PathQuery* pq, PathQueryResult* pqr) } //if (!config.pathfindingDebugModeFlushCache ) - if (PathCacheGet(pq, pqr)){ + if (PathCacheGet(pq, pqr) && pqr->flags & PF_COMPLETE){ // has this query been done before? if so copies it and returns the result if (config.pathfindingDebugMode || !combatSys.isCombatActive()) - logger->info("Query found in cache, fetching result."); + //logger->info("Query found in cache, fetching result."); return pqr->nodeCount; } @@ -1624,7 +1624,7 @@ int Pathfinding::FindPath(PathQuery* pq, PathQueryResult* pqr) { if (config.pathfindingDebugMode || !combatSys.isCombatActive()) { - logger->info("Attempting sans nodes..."); + ;// logger->info("Attempting sans nodes..."); } gotPath = FindPathSansNodes(pq, pqr); } @@ -1651,7 +1651,7 @@ int Pathfinding::FindPath(PathQuery* pq, PathQueryResult* pqr) if (config.pathfindingDebugMode || !combatSys.isCombatActive()) { if (pq->critter) - logger->info("{} pathed successfully to {}", description.getDisplayName(pq->critter), pqr->to); + ;// logger->info("{} pathed successfully to {}", description.getDisplayName(pq->critter), pqr->to); } pqr->flags |= PF_COMPLETE; @@ -2099,10 +2099,10 @@ int Pathfinding::FindPathShortDistanceSansTarget(PathQuery* pq, Path* pqr) int attemptCount; if (objects.GetType(pq->critter) == obj_t_npc) { - if (npcPathFindRefTime && (timeGetTime() - npcPathFindRefTime) < 1000 ) // && !pathNodeSys.hasClearanceData limits the number of attempt to 10 per second and cumulative time to 250 sec + if (npcPathFindRefTime && (timeGetTime() - npcPathFindRefTime) < 10000 ) // && !pathNodeSys.hasClearanceData limits the number of attempt to 10 per second and cumulative time to 250 sec { attemptCount = npcPathFindAttemptCount; - if ( (npcPathFindAttemptCount > 10 + (40 * (pathNodeSys.hasClearanceData == true)) ) || npcPathTimeCumulative > 250) + if ( (npcPathFindAttemptCount > 100 + (40 * (pathNodeSys.hasClearanceData == true)) ) || npcPathTimeCumulative > 2500) { if (config.pathfindingDebugMode) { diff --git a/TemplePlus/python/python_debug.cpp b/TemplePlus/python/python_debug.cpp index bcd2fbb8f..87a47c6a7 100644 --- a/TemplePlus/python/python_debug.cpp +++ b/TemplePlus/python/python_debug.cpp @@ -10,6 +10,7 @@ #include #include #include +#include static std::string GetNiceName(void* ptr) { @@ -227,6 +228,24 @@ PyObject *PyDebug_DumpAiTactics() { return result; } +PyObject* PyDebug_DumpAnimGoals() { + using AnimGoalArray = const AnimGoal* [82]; + AnimGoalArray& goals = temple::GetRef(0x102BD1B0); + auto cap = 82; + auto result = PyList_New(cap); + + for (int i = 0; i < cap; ++i) { + auto goal = goals[i]; + if (!goal) continue; + auto c = Py_BuildValue("s", + GetAnimGoalTypeName((AnimGoalType)i) + ); + + PyList_SET_ITEM(result, i, c); + } + + return result; +} PyObject *PyDebug_RecalculatePathNodeNeighbours() { @@ -349,6 +368,7 @@ static PyMethodDef PyDebug_Methods[] = { { "dump_feats", (PyCFunction)PyDebug_DumpFeats, METH_NOARGS, NULL }, { "dump_d20actions", (PyCFunction)PyDebug_DumpD20Actions, METH_NOARGS, NULL }, { "dump_ai_tactics", (PyCFunction)PyDebug_DumpAiTactics, METH_NOARGS, NULL }, + { "dump_anim_goals", (PyCFunction)PyDebug_DumpAnimGoals, METH_NOARGS, NULL }, { "recalc_neighbours", (PyCFunction)PyDebug_RecalculatePathNodeNeighbours, METH_NOARGS, NULL }, { "flush_nodes", (PyCFunction)PyDebug_FlushNodes, METH_NOARGS, NULL }, { "recip", (PyCFunction)PyDebug_ReciprocityDebug, METH_NOARGS, NULL }, diff --git a/TemplePlus/python/python_integration_obj.cpp b/TemplePlus/python/python_integration_obj.cpp index 09aec46a7..287f2dec1 100644 --- a/TemplePlus/python/python_integration_obj.cpp +++ b/TemplePlus/python/python_integration_obj.cpp @@ -363,6 +363,7 @@ PyObject* PythonObjIntegration::ExecuteScript(const char* moduleName, const char Py_DECREF(locals); if (!module) { */ logger->error("Unable to find Python module {}", moduleName); + PyErr_Print(); Py_RETURN_NONE; } diff --git a/TemplePlus/python/python_object.cpp b/TemplePlus/python/python_object.cpp index 2a3cd29ed..fde23cac6 100644 --- a/TemplePlus/python/python_object.cpp +++ b/TemplePlus/python/python_object.cpp @@ -49,6 +49,7 @@ #include #include "python_spell.h" #include "xp.h" +#include "animgoals\animgoals_stackentry.h" namespace py = pybind11; @@ -636,6 +637,8 @@ static PyObject* PyObjHandle_CanFindPathToObj(PyObject* obj, PyObject* args) { auto nodeCount = pathfindingSys.FindPath(&pathQ, &pqr); auto pathLen = pathfindingSys.GetPathLength(&pqr); + if (!(pqr.flags & PF_COMPLETE)) + pathLen = 0; return PyInt_FromLong(static_cast(pathLen)); } @@ -684,6 +687,35 @@ static PyObject* PyObjHandle_FindPathToObj(PyObject* obj, PyObject* args) { return pyLoc.ptr(); } +static PyObject* PyObjHandle_CantApproach(PyObject* obj, PyObject* args) { + auto self = GetSelf(obj); + if (!self->handle) { + return PyInt_FromLong(0); + } + auto handle = self->handle; + + objHndl tgtObj; + int32_t act = D20ActionType::D20A_UNSPECIFIED_MOVE; + int data1 = 0; + int result = 0; + + // get target + if (!PyArg_ParseTuple(args, "O&|ii:objhndl.cant_approach", &ConvertObjHndl, &tgtObj, &act, &data1)) { + return 0; + } + int initialActNum = (*actSeqSys.actSeqCur)->d20ActArrayNum; + actSeqSys.curSeqReset(handle); + d20Sys.GlobD20ActnInit(); + d20Sys.GlobD20ActnSetTypeAndData1((D20ActionType)act, data1); + d20Sys.GlobD20ActnSetTarget(tgtObj, 0); + result = actSeqSys.ActionAddToSeq(); + if (result == AEC_OK) { + result = actSeqSys.ActionSequenceChecksWithPerformerLocation(); + actSeqSys.ActionSequenceRevertPath(initialActNum); + } + return PyInt_FromLong(result); +} + static PyObject* PyObjHandle_CanMelee(PyObject* obj, PyObject* args) { auto self = GetSelf(obj); if (!self->handle) { @@ -1112,6 +1144,18 @@ static PyObject* PyObjHandle_HasLos(PyObject* obj, PyObject* args) { return PyInt_FromLong(obstacles == 0); } +static PyObject* PyObjHandle_HasLoa(PyObject* obj, PyObject* args) { + auto self = GetSelf(obj); + if (!self->handle) { + return PyInt_FromLong(0); + } + objHndl target; + if (!PyArg_ParseTuple(args, "O&:objHndl.has_loa", &ConvertObjHndl, &target)) { + return 0; + } + auto result = combatSys.HasLineOfAttack(self->handle, target); + return PyInt_FromLong(result); +} // CanSee and HasLos are the same @@ -2446,11 +2490,16 @@ static PyObject* PyObjHandle_ActionPerform(PyObject* obj, PyObject* args) { } auto performer = self->handle; D20Actn action; + int pythonAction = 0; if (!PyArg_ParseTuple(args, "iO&|L:objhndl.action_perform", &action.d20ActType, &ConvertObjHndl, &action.d20ATarget, &action.destLoc.location)) { return 0; } if (action.d20ActType == D20A_NONE) { return nullptr; + } + else if (action.d20ActType >= D20A_NUMACTIONS) { + pythonAction = action.d20ActType; + action.d20ActType = D20A_PYTHON_ACTION; } if (!actSeqSys.TurnBasedStatusInit(performer)) { PyErr_SetString(PyExc_RuntimeError, "action_perform: couldn't init turn based status"); @@ -2462,6 +2511,8 @@ static PyObject* PyObjHandle_ActionPerform(PyObject* obj, PyObject* args) { d20Sys.GlobD20ActnInit(); d20Sys.GlobD20ActnSetTypeAndData1(action.d20ActType, 0); d20Sys.GlobD20ActnSetTarget(action.d20ATarget, hasLocation ? &action.destLoc : nullptr); + if (action.d20ActType == D20A_PYTHON_ACTION) + d20Sys.globD20Action->SetPythonActionEnum((D20DispatcherKey)pythonAction); auto result = actSeqSys.ActionAddToSeq(); if (result != AEC_OK) { PyErr_SetString(PyExc_RuntimeError, "action_perform: ActionAddToSeq error"); @@ -2478,6 +2529,9 @@ static PyObject* PyObjHandle_AddToInitiative(PyObject* obj, PyObject* args) { return 0; } combatSys.AddToInitiative(self->handle); + auto uiCallback = temple::GetRef(0x10AA83F4); // something to do with refreshing the initiative list portraits + uiCallback(); + Py_RETURN_NONE; } @@ -2878,6 +2932,19 @@ static PyObject* PyObjHandle_AnimGoalPushUseObject(PyObject* obj, PyObject* args return PyInt_FromLong(1); } +static PyObject* PyObjHandle_AnimGoalPushAnimate(PyObject* obj, PyObject* args) { + auto self = GetSelf(obj); + if (!self->handle) { + return PyInt_FromLong(0); + } + + int anim; + if (!PyArg_ParseTuple(args, "i:objhndl.anim_goal_animate", &anim)) { + return 0; + } + return PyInt_FromLong(gameSystems->GetAnim().PushAnimate(self->handle, anim)); +} + static PyObject* PyObjHandle_AnimGoalPushWalkToTile(PyObject* obj, PyObject* args) { auto self = GetSelf(obj); if (!self->handle) { @@ -3437,6 +3504,34 @@ static PyObject* PyObjHandle_GetInt(PyObject* obj, PyObject* args) { return PyInt_FromLong(value); } +static PyObject* PyObjHandle_GetFloat(PyObject* obj, PyObject* args) { + auto self = GetSelf(obj); + if (!self->handle) { + return PyInt_FromLong(0); + } + obj_f field; + if (!PyArg_ParseTuple(args, "i:objhndl.obj_get_float", &field)) { + return 0; + } + float value = 0; + if (!self->handle) // python users aren't always so careful :P + { + logger->warn("Warning: Python obj_get_float called with null object handle! Field was {}, returning 0.", objectFields.GetFieldName(field)); + return PyInt_FromLong(value); + } + if (objectFields.GetType(field) == ObjectFieldType::Int32) + { + value = (float)objects.getInt32(self->handle, field); + + } + else if (objectFields.GetType(field) == ObjectFieldType::Float32) + { + value = objSystem->GetObject(self->handle)->GetFloat(field); + } + + return PyFloat_FromDouble(value); +} + static PyObject* PyObjHandle_GetIdxInt(PyObject* obj, PyObject* args) { auto self = GetSelf(obj); if (!self->handle) { @@ -4511,6 +4606,7 @@ static PyMethodDef PyObjHandleMethods[] = { { "anim_goal_push_walk_to_tile", PyObjHandle_AnimGoalPushWalkToTile, METH_VARARGS, NULL }, { "anim_goal_push_run_to_tile", PyObjHandle_AnimGoalPushRunToTile, METH_VARARGS, NULL }, { "anim_goal_get_new_id", PyObjHandle_AnimGoalGetNewId, METH_VARARGS, NULL }, + { "anim_goal_animate", PyObjHandle_AnimGoalPushAnimate, METH_VARARGS, NULL }, { "apply_projectile_particles", PyObjHandle_ApplyProjectileParticles, METH_VARARGS, NULL }, { "apply_projectile_hit_particles", PyObjHandle_ApplyProjectileHitParticles, METH_VARARGS, NULL }, { "arcane_spell_level_can_cast", PyObjHandle_ArcaneSpellLevelCanCast, METH_VARARGS, NULL }, @@ -4535,6 +4631,7 @@ static PyMethodDef PyObjHandleMethods[] = { {"can_blindsee", PyObjHandle_CanBlindsee, METH_VARARGS, "obj has blind sight, and target is within observation range of blindsight ability"}, {"can_sense", PyObjHandle_CanSense, METH_VARARGS, NULL }, { "can_sneak_attack", PyObjHandle_CanSneakAttack, METH_VARARGS, NULL }, + { "cant_approach", PyObjHandle_CantApproach, METH_VARARGS, NULL }, { "concealed_set", PyObjHandle_ConcealedSet, METH_VARARGS, NULL }, { "condition_add_with_args", PyObjHandle_ConditionAddWithArgs, METH_VARARGS, NULL }, { "condition_add", PyObjHandle_ConditionAddWithArgs, METH_VARARGS, NULL }, @@ -4607,6 +4704,7 @@ static PyMethodDef PyObjHandleMethods[] = { { "has_follower", PyObjHandle_HasFollower, METH_VARARGS, NULL }, { "has_item", PyObjHandle_HasItem, METH_VARARGS, NULL }, { "has_los", PyObjHandle_HasLos, METH_VARARGS, NULL }, + { "has_loa", PyObjHandle_HasLoa, METH_VARARGS, NULL }, { "has_met", PyObjHandle_HasMet, METH_VARARGS, NULL }, { "has_spell_effects", PyObjHandle_HasSpellEffects, METH_VARARGS, NULL }, { "has_wielded", PyObjHandle_HasWielded, METH_VARARGS, NULL }, @@ -4678,6 +4776,7 @@ static PyMethodDef PyObjHandleMethods[] = { { "obj_get_idx_obj", PyObjHandle_GetIdxObj, METH_VARARGS, "Gets Object Array field" }, { "obj_get_idx_obj_size", PyObjHandle_GetIdxObjSize, METH_VARARGS, "Gets Object Array field" }, { "obj_get_spell", PyObjHandle_GetSpell, METH_VARARGS, NULL }, + { "obj_get_float", PyObjHandle_GetFloat, METH_VARARGS, NULL }, { "obj_remove_from_all_groups", PyObjHandle_RemoveFromAllGroups, METH_VARARGS, "Removes the object from all the groups (GroupList, PCs, NPCs, AI controlled followers, Currently Selected" }, { "obj_set_int", PyObjHandle_SetInt, METH_VARARGS, NULL }, { "obj_set_float", PyObjHandle_SetFloat, METH_VARARGS, NULL }, diff --git a/TemplePlus/secret_door.cpp b/TemplePlus/secret_door.cpp index 957b04938..f1f17f092 100644 --- a/TemplePlus/secret_door.cpp +++ b/TemplePlus/secret_door.cpp @@ -101,6 +101,18 @@ class SecretDoorReplacements : public TempleFix return secretdoorSys.SecretDoorRollAndReveal(secdoor, seeker, bonList); }); + static void(__cdecl * floatMesLineOrg)(objHndl, int categoryBit, FloatLineColor color, const char* text)= replaceFunction(0x100A2200, [](objHndl handle, int categoryBit, FloatLineColor color, const char* text) + { + logger->info("Floating: {}", text); + floatMesLineOrg(handle, categoryBit, color, text); + }); + + static int(__cdecl * ShowTextBubbleOrg)(objHndl pc, objHndl speakingTo, const char* text, int speechId) = replaceFunction(0x1014CDE0, [](objHndl pc, objHndl speakingTo, const char* text, int speechId) + { + logger->info("Bubble: {}", text); + return ShowTextBubbleOrg(pc, speakingTo, text, speechId); + }); + replaceFunction(0x10046650, [](objHndl handle) { return secretdoorSys.TaggedSceneryWasSeen(handle) ? TRUE:FALSE; }); @@ -282,6 +294,8 @@ BOOL SecretDoorSys::SecretDoorDetect(objHndl sd, objHndl seeker) auto markSeen = temple::GetRef(0x10046620); markSeen(sd); + + objects.ClearFlag(sd, ObjectFlag::OF_DONTDRAW); auto sdEffectName = sdObj->GetInt32(obj_f_secretdoor_effectname); if (sdEffectName) { diff --git a/TemplePlus/sound.cpp b/TemplePlus/sound.cpp index 015ea4648..93aa304a4 100644 --- a/TemplePlus/sound.cpp +++ b/TemplePlus/sound.cpp @@ -116,7 +116,7 @@ class SoundHooks: TempleFix if (soundType != 1) { auto result = orgAllocStream(streamId, soundType); if (result != 0) { - logger->debug("Failed to allocate stream! Stream ID {}, sound type {}", *streamId, soundType); + ;// logger->debug("Failed to allocate stream! Stream ID {}, sound type {}", *streamId, soundType); } auto &mss = temple::GetRef(0x10EE7578)[*streamId]; if (mss.streamSthg) { diff --git a/TemplePlus/ui/ui_intgame_turnbased.cpp b/TemplePlus/ui/ui_intgame_turnbased.cpp index 219133cca..522dbfd91 100644 --- a/TemplePlus/ui/ui_intgame_turnbased.cpp +++ b/TemplePlus/ui/ui_intgame_turnbased.cpp @@ -1072,7 +1072,7 @@ void UiIntgameTurnbased::CursorRenderUpdate(){ cursorState = specialCursor; if (cursorState != cursorPrevState){ - logger->debug("Changing cursor from {} to {}", cursorState, cursorPrevState); + //logger->debug("Changing cursor from {} to {}", cursorState, cursorPrevState); if (cursorPrevState) temple::GetRef(0x101DD770)();