This made me laugh. Although I doubt if Kojima works on any code.CantStoptheBipBop wrote:nasanhak wrote:
@Tex
Dear God I feel exactly like I did looking at the game's code 9 months ago.
It's a well known fact that he's actually Hideo Kojima. It's the only explanation that fits.
TBH your approach is pretty much the only way to go about it since the game won't support any UI modding. If anybody wants to build a menu that's pretty much the only way they'll achieve it.Tex wrote:Part of that is my overengineering again.
The original goals for that were:
'easily' add update functions without having to add them to TppMain.SetUpdateFunction
Filter execution for performance since updates are per frame.
The updateRate stuff was built for the enemy phase change feature, but now I think that using repeating timer messages might be better.
Putting the update state info in the Ivars was a so-so idea, it broke down a bit as some updates are either not really associated with any option, or actually associated with multiple options.
If you are gonna use timer messages then remember that demos seem to disable all timers.
Now for some sharing:
I had been tinkering with route randomization and may have figured it out. It's not really by any engine call but rather intercepting the engine calls and randomizing the about to be selected routes.
https://youtu.be/z4YFRaQkS3A
The same mission played twice at the same time of day with different results (apologies for the shitty quality). What the randomization does is simple shift entries around in the table to be returned. Not really a big deal. BUT it kinda looks cool. The video clearly shows issues with LRRP route selection which has been addressed in the code below.
Pros:
1. Doing a mission at the same time over and over will no longer be a sniper here, armor there kind of run
2. Triggering a caution alert sends the base into a sort of chaotic frenzy. Normally, each soldier will be assigned a caution route closest to their position but with randomization, this isn't the case. Soldiers will run about till they get to their route positions. Things quiet down after but it looks cool nonetheless.
Cons:
1.a. LRRPs have issues that may not be possible to sort out. While testing, LRRP foot patrols work gloriously but vehicles do not. So it turns out, for each outpost LRRPs have an in route("_lin_") and an out route("_lout_") as well as a "hold" route("_l_") in between for that outpost. When they travel out of the outpost, the engine fires the route selector and if a new random route is picked, different than where they are supposed to be going originally, well - all hell breaks loose if the LRRP is driving a vehicle. They'll suddenly gain a craving for off-roading. So LRRPs are a no go.
1.b. In the case of LRRPs, the very first route assigned seems to be fixed and is actually a good thing but adding it here anyways since further randomization is not really feasible.
2. Game(Fox Engine?) has no path finding unless in combat alert. This sucks as soldiers follow a fixed path when a caution alert is triggered to get to new far away route.
3. Over use of the phantom cigar may sometimes lead to soldiers in close proximity leaving wide gaps to sneak in.
4. Needs extensive testing for each mission obviously.
Replace following two functions in TppEnemy. ShuffleRoutes func is mine.
Code: Select all
function this.RouteSelector(cpId,routeTypeStrCode32,sysPhaseOrSoldierGroupOrLrrpTravelOrDefault)
--sysPhaseOrSoldierGroupOrLrrpTravelOrDefault - check mvars.ene_routeSets for clarity on absurd naming
local routeSetsForCpId=mvars.ene_routeSets[cpId]
if routeSetsForCpId==nil then
return{"dummyRoute"}
end
if sysPhaseOrSoldierGroupOrLrrpTravelOrDefault==StrCode32"immediately"then
if routeTypeStrCode32==StrCode32"old"then
local routeTypeToSelect=this.GetCurrentRouteSetType(nil,this.GetPhaseByCPID(cpId),cpId)
return this.GetPrioritizedRouteTable(cpId,mvars.ene_routeSetsTemporary[cpId][routeTypeToSelect],mvars.ene_routeSetsPriorityTemporary)
else
local routeTypeToSelect=this.GetCurrentRouteSetType(nil,this.GetPhaseByCPID(cpId),cpId)
return this.GetPrioritizedRouteTable(cpId,routeSetsForCpId[routeTypeToSelect],mvars.ene_routeSetsPriority)
end
end
if sysPhaseOrSoldierGroupOrLrrpTravelOrDefault==StrCode32"SYS_Sneak"then
local routeTypeToSelect=this.GetCurrentRouteSetType(nil,this.PHASE.SNEAK,cpId)
return this.GetPrioritizedRouteTable(cpId,routeSetsForCpId[routeTypeToSelect],mvars.ene_routeSetsPriority,sysPhaseOrSoldierGroupOrLrrpTravelOrDefault)
end
if sysPhaseOrSoldierGroupOrLrrpTravelOrDefault==StrCode32"SYS_Caution"then
local routeTypeToSelect=this.GetCurrentRouteSetType(nil,this.PHASE.CAUTION,cpId)
return this.GetPrioritizedRouteTable(cpId,routeSetsForCpId[routeTypeToSelect],mvars.ene_routeSetsPriority,sysPhaseOrSoldierGroupOrLrrpTravelOrDefault)
end
local routeTypeToSelect=this.GetCurrentRouteSetType(routeTypeStrCode32,this.GetPhaseByCPID(cpId),cpId)
local routesToUse=routeSetsForCpId[routeTypeToSelect][sysPhaseOrSoldierGroupOrLrrpTravelOrDefault]
if routesToUse then
-- TppPlayer.DebugPrint(
-- "_______________________EarlyReturn_______________________"
-- .."\ncpId: "..tostring(cpId)
-- .."\nrouteTypeToSelect: "..tostring(routeTypeToSelect)
-- .."\nsysPhaseOrSoldierGroupOrLrrpTravelOrDefault: "..tostring(sysPhaseOrSoldierGroupOrLrrpTravelOrDefault)
-- ,1)
local tableSize=0
for k,v in pairs(routeSetsForCpId[routeTypeToSelect]) do
tableSize=tableSize+1
end
-- TppPlayer.DebugPrint(
-- "routeSetsForCpId["..tostring(routeTypeToSelect).."]: "..tostring(InfInspect.Inspect(routeSetsForCpId[routeTypeToSelect]))
-- .."\nrouteSetsForCpId["..tostring(routeTypeToSelect).."]Size: "..tostring(tableSize)
-- ,1)
-- TppPlayer.DebugPrint(
-- "-------------------BeforeShuffle-------------------"
-- .."\nroutesToUse: "..tostring(InfInspect.Inspect(routesToUse))
-- .."\nroutesToUseSize: "..tostring(InfInspect.Inspect(#routesToUse))
-- ,1)
--Nope sadly, even with the conditions, while you can "fix" LRRP routes while *at* an outpost, the moment they leave new routes are selected using this same function. So, simply exclude LRRP from this over randomization
if tableSize>1 and routeTypeToSelect~="travel" and not string.find(routesToUse[1], '_l_') and not string.find(routesToUse[1], '_lin_') and not string.find(routesToUse[1], '_lout_') then
TppPlayer.DebugPrint("Setting new route!",1)
local indexOfRouteToSelect = math.random(tableSize)
local i=0
local nameOfNewRouteToSelect=nil
for indexName, routes in pairs(routeSetsForCpId[routeTypeToSelect]) do
i=i+1
if (i==indexOfRouteToSelect) then
nameOfNewRouteToSelect=indexName
break
end
end
-- TppPlayer.DebugPrint(
-- "OLDsysPhaseOrSoldierGroupOrLrrpTravelOrDefault:"..tostring(sysPhaseOrSoldierGroupOrLrrpTravelOrDefault)
-- .." nameOfNewRouteToSelect:"..tostring(nameOfNewRouteToSelect)
-- ,1)
routesToUse=routeSetsForCpId[routeTypeToSelect][nameOfNewRouteToSelect]
end
routesToUse=this.ShuffleRoutes(routesToUse)
-- TppPlayer.DebugPrint(
-- "-------------------AfterSuffle-------------------"
-- .."\nroutesToUse: "..tostring(InfInspect.Inspect(routesToUse))
-- .."\nroutesToUseSize: "..tostring(InfInspect.Inspect(#routesToUse))
-- ,1)
return routesToUse
else
if routeTypeToSelect=="hold"then
local routeTypeToSelect=this.GetCurrentRouteSetType(nil,this.GetPhaseByCPID(cpId),cpId)
return this.GetPrioritizedRouteTable(cpId,routeSetsForCpId[routeTypeToSelect],mvars.ene_routeSetsPriority)
else
local routeTypeToSelect=this.GetCurrentRouteSetType(nil,this.GetPhaseByCPID(cpId),cpId)
return this.GetPrioritizedRouteTable(cpId,routeSetsForCpId[routeTypeToSelect],mvars.ene_routeSetsPriority)
end
end
end
function this.GetPrioritizedRouteTable(cpId,selectedRoutesForCpId,routeSetsPriority,sysPhaseOrSoldierGroupOrLrrpTravelOrDefault)
-- TppPlayer.DebugPrint("_______________________TppEnemy.GetPrioritizedRouteTable BEG_______________________"
-- .."\ncpId: "..tostring(cpId)
-- .." sysPhase: "..tostring(sysPhaseOrSoldierGroupOrLrrpTravelOrDefault)
-- ,1)
local routesToUse={}
local priorityRouteSetsForCP=routeSetsPriority[cpId]
if not IsTypeTable(priorityRouteSetsForCP)then
return
end
if mvars.ene_funcRouteSetPriority then
routesToUse=mvars.ene_funcRouteSetPriority(cpId,selectedRoutesForCpId,routeSetsPriority,sysPhaseOrSoldierGroupOrLrrpTravelOrDefault)
else
local t=0
for a,e in ipairs(priorityRouteSetsForCP)do
if selectedRoutesForCpId[e]then
local e=#selectedRoutesForCpId[e]
if e>t then
t=e
end
end
end
local e=1
for t=1,t do
for r,a in ipairs(priorityRouteSetsForCP)do
local n=selectedRoutesForCpId[a]
if n then
local n=n[t]
if n and Tpp.IsTypeTable(n)then
routesToUse[e]=n
e=e+1
end
end
end
end
for r=1,t do
for a,t in ipairs(priorityRouteSetsForCP)do
local n=selectedRoutesForCpId[t]
if n then
local n=n[r]
if n and not Tpp.IsTypeTable(n)then
routesToUse[e]=n
e=e+1
end
end
end
end
end
-- TppPlayer.DebugPrint(
-- "selectedRoutesForCpId: "..tostring(InfInspect.Inspect(selectedRoutesForCpId))
-- .."\nrouteSetsPriority["..tostring(cpId).."]: "..tostring(InfInspect.Inspect(routeSetsPriority[cpId]))
-- ,1)
-- TppPlayer.DebugPrint(
-- "-------------------BeforeShuffle-------------------"
-- .."\nroutesToUse: "..tostring(InfInspect.Inspect(routesToUse))
-- .."\nroutesToUseSize: "..tostring(InfInspect.Inspect(#routesToUse))
-- ,1)
routesToUse=this.ShuffleRoutes(routesToUse)
-- TppPlayer.DebugPrint(
-- "-------------------AfterSuffle-------------------"
-- .."\nroutesToUse: "..tostring(InfInspect.Inspect(routesToUse))
-- .."\nroutesToUseSize: "..tostring(InfInspect.Inspect(#routesToUse))
-- ,1)
-- TppPlayer.DebugPrint("TppEnemy.GetPrioritizedRouteTable END",3)
return routesToUse
end
function this.ShuffleRoutes(routesToUse)
math.random()math.random()math.random()
local tempRoutesList = {}
local actualRoutesCopy={}
if #routesToUse > 0 then
for k,v in pairs(routesToUse) do
table.insert(actualRoutesCopy, v)
end
end
while #actualRoutesCopy>0 do
local index=math.random(#actualRoutesCopy)
table.insert(tempRoutesList, actualRoutesCopy[index])
table.remove(actualRoutesCopy, index)
math.random()math.random()math.random()
end
return tempRoutesList
-- for index,routeName in ipairs(routesToUse) do
-- table.insert(tempRoutesList, routeName)
-- table.remove(routesToUse, index)
-- end
-- TppMain.Randomize()
-- while #tempRoutesList > 0 do
-- local index=math.random(#tempRoutesList)
-- table.insert(routesToUse, tempRoutesList[index])
-- table.remove(tempRoutesList, index)
-- end
--
-- return routesToUse
end
Doing this I learned that '#' operator only works on array tables and not on indexed tables.
A randomseed can be set on the mission random seed value to create a bit more consistent inconsistency - specially for mission restarts, checkpoint reloads won't work as well. While this randomization does not make a big deal of difference, I played the same mission thrice at the deployment time with slightly different results so it's somewhat worth it.
This would have been perfect if there could be 31 soldiers per outpost, but then that also involves adding in (even if repeated) new routes for those additional soldiers.
Soldier chat routes are triggered by player proximity and have nothing to do with the route selector. Chats worked fine.
Firing this randomization on MB leads to something very special. The 4 (or 2 if using roof LZ) salute soldiers may be from any platform on the command cluster. Meaning they move back to their appropriate platform. But when I used the Phantom Cigar, TppEnemy.RouteSelector did not fire even though it is registered for the MB Cps.
mtbs_enemy.GetRouteSetPriority doesn't fire on MB either, I think it's FOB only. If MB route randomization can be figured out it would be really cool having the default soldiers move about platforms at shift change.
Looking at the routes for MB, there do seem to be different night/day route names at least, so either they never change once assigned or even if they are changed somewhere, then they are the same routes anyway(most likely). Still, a shuffle wouldn't hurt.
