Amineri Posted May 8, 2013 Share Posted May 8, 2013 Well, I updated the DecideNextDestination function in XGAIBehavior.(state 'flee') to: function Vector DecideNextDestination(optional out string strFail){ local XGUnit kEnemy; local Vector vDestination, vCurrLoc, VDir; local float DistSq; m_kUnit.SetDashing(true); vCurrLoc = m_kUnit.GetLocation(); vDestination = vCurrLoc; // End:0xA2 if(m_kTrackingCue.bTracking) { kEnemy = m_kTrackingCue.kTarget; } DistSq = -1.0 - (class'XComEngine'.static.SyncFRand((string(Name) @ string(GetStateName())) @ string(GetFuncName())) * float(3)); // End:0x147 if(!FindRunawayPosition(vDestination, kEnemy, VDir, DistSq, strFail)) { SwitchToAttack(strFail); } return vDestination; } Unfortunately I'm still seeing the same behavior. I did witness the flanked sectoid decide to use it's mindmerge ability, which I thought was a rather poor call. Have another plan, though. Link to comment Share on other sites More sharing options...
Amineri Posted May 8, 2013 Share Posted May 8, 2013 I think I've got this close to figured out. I've made several changes in a few places in the AI code, and now finally my sectoids are moving and shooting even in the face of overwatch and/or flanking. I saw the following behaviors in a mission. 1) Sectoid was flanked by one unit and overwatched by 2. Sectoid moved to a position where it was not flanked, drawing the two overwatch shots. It then proceeded to enter overwatch itself. 2) Dashed a unit to flank a sectoid, and had two units overwatching. Sectoid was in high cover against the two overwatching units. Sectoid chose to shoot at the flanking unit. These behaviors did NOT appear when I applied them and loaded a save game. They only appeared when I started a new mission/campaign with the changes below. --------------------------------------- Here are all of the changes I ended up putting in: 1) Modified AI_GetScore so that ShotStandard always has priority of at least 1. 2) Modified XGAIBehavior.(state 'flee') to allow fleeing AI units to dash (added m_kUnit.SetDashing(true); to the beginning of state) 3) Swapped the order of the checks for GotoState('TacticalMove') and GotoState('Flee') in ExecuteMoveAbility. Previously 'TacticalMove' would be performed if available, disallowing 'Flee'. Now 'Flee' takes priority. 4) Changed the function GetMaxDangerLevelForMovement to return 3 by default instead of 1. Since overwatching nearly always set the OverwatchDangerLevel to 3, this was preventing the MoveAbility from being added to the list of possible abilities to consider. 5) Explicitly overrode the function ShouldAvoidMovement to return false even if the unit is being overwatched 6) Modified the distance check for MinDistanceToCover in the 'Flee' state from 0 to 128 (2 tiles) 7) Modified the FindRunAwayPosition to return true only if it actually found a valid RunAwayPosition. Previously it always returned true, which would prevent SwitchToAttack from executing if FindRunAwayPosition failed to find a valid position to run away to. ---------------------------------- Some of these changes are kind of hacked up, and may cause other undesirable behaviors in other situations, especially for other aliens. Aliens are no longer explicitly prohibited from moving when there are overwatching units -- they instead rely on the priority scheme to make it unlikely for aliens to move. This results in much more reckless aliens, which may not always be a good thing. I'm considering rewriting the overwatchdangerzone function to more accurately represent the the number of overwatching units. The "short range" distance should be much shorter than 90% of visual range ... something around 40% or 50% should be fine, since that is when the to-hit aim bonuses begin to become noticeable. This would prevent aliens from moving when 3 or more XCOM soldier are overwatching in visual range -- though I'm considering making the number 4. Move ability already gets a hefty penalty for multiple overwatching enemies. I've also not observed fleeing aliens attempting using a 'dash' move, even though I think I've added that as a possibility. --------------------------------- Here are the detailed hex changes of what I've done so far. This likely isn't a "good" set of changes, but I'm putting it out so others can play with it a bit. 1) Modified AI_GetScore so that ShotStandard always has priority of at least 1. Hex (original)F3 88 00 00 50 55 00 00 00 00 00 00 D5 88 00 00 00 00 00 00 00 00 00 00 DE 88 00 00 00 00 00 00 3A 01 00 00 CC 28 00 00 6B 01 00 00 07 01 00 00 07 11 00 72 00 DE 88 00 00 2A 16 04 25 0F 00 DB 88 00 00 1B BC 02 00 00 00 00 00 00 00 DE 88 00 00 16 0F 00 DA 88 00 00 1B B3 02 00 00 00 00 00 00 00 DE 88 00 00 16 0F 00 D9 88 00 00 1B B9 02 00 00 00 00 00 00 00 DE 88 00 00 00 DB 88 00 00 00 DA 88 00 00 16 0F 00 D8 88 00 00 38 44 AB 38 3F 2C 64 00 DB 88 00 00 16 0F 00 D7 88 00 00 38 44 AB 38 3F 2C 64 00 DA 88 00 00 16 0F 00 D6 88 00 00 38 44 AB 38 3F 2C 64 00 D9 88 00 00 16 0F 48 DD 88 00 00 70 A8 70 A8 70 A8 1B B5 02 00 00 00 00 00 00 00 DE 88 00 00 16 1F 4F 66 66 3D 00 16 38 53 00 D8 88 00 00 16 1F 44 65 66 3D 00 16 38 53 00 D7 88 00 00 16 1F 49 6E 74 3D 00 16 38 53 00 D6 88 00 00 16 04 38 44 AB 38 3F 92 92 00 D8 88 00 00 00 D7 88 00 00 16 00 D6 88 00 00 16 1B B7 02 00 00 00 00 00 00 00 DE 88 00 00 16 16 04 3A DC 88 00 00 53 Hex (new) (virtual size 0x15F) -- default shotstandard priority 1F3 88 00 00 50 55 00 00 00 00 00 00 D5 88 00 00 00 00 00 00 00 00 00 00 DE 88 00 00 00 00 00 00 3A 01 00 00 CC 28 00 00 5F 01 00 00 07 01 00 00 07 11 00 72 00 DE 88 00 00 2A 16 04 25 0F 00 DB 88 00 00 1B BC 02 00 00 00 00 00 00 00 DE 88 00 00 16 0F 00 DA 88 00 00 1B B3 02 00 00 00 00 00 00 00 DE 88 00 00 16 0F 00 D9 88 00 00 1B B9 02 00 00 00 00 00 00 00 DE 88 00 00 00 DB 88 00 00 00 DA 88 00 00 16 0F 00 D8 88 00 00 38 44 AB 38 3F 2C 64 00 DB 88 00 00 16 0F 00 D7 88 00 00 38 44 AB 38 3F 2C 64 00 DA 88 00 00 16 0F 00 D6 88 00 00 38 44 AB 38 3F 2C 64 00 D9 88 00 00 16 04 FA 38 44 AB 38 3F 92 92 00 D8 88 00 00 00 D7 88 00 00 16 00 D6 88 00 00 16 1B B7 02 00 00 00 00 00 00 00 DE 88 00 00 16 16 45 9A 19 00 DE 88 00 00 09 00 E2 7B 00 00 00 01 E2 7B 00 00 2C 07 16 02 00 2C 01 02 00 2C 00 16 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 53 decompiled code:function int AI_GetScore(XGAbility kAbility, out string strAbilities){ local float fOS, fDS, fIS; local int iOS, Ids, iIS; // End:0x11 if(kAbility == none) { return 0; } fOS = AI_OffenseScore(kAbility); fDS = AI_DefenseScore(kAbility); fIS = AI_IntangiblesScore(kAbility, fOS, fDS); iOS = int(float(100) * fOS); Ids = int(float(100) * fDS); iIS = int(float(100) * fIS); return Max(int(float((iOS + Ids) + iIS) * (AI_GetScoreModifier(kAbility))), ((kAbility.iType == 7) ? 1 : 0)); } 2) Modified XGAIBehavior.(state 'flee') to allow fleeing AI units to dash (added m_kUnit.SetDashing(true); to the beginning of state) original hex:CF 8F 00 00 50 55 00 00 00 00 00 00 B3 8F 00 00 CA 8C 00 00 00 00 00 00 BA 8F 00 00 00 00 00 00 36 1A 00 00 A6 75 03 00 58 01 00 00 E8 00 00 00 0B 0E 1C F9 FF FF 61 43 48 BA 8F 00 00 1F 46 4C 45 45 00 16 0F 00 B6 8F 00 00 19 01 B8 8A 00 00 0A 00 D7 32 00 00 00 1B FE 32 00 00 00 00 00 00 16 0F 00 B7 8F 00 00 00 B6 8F 00 00 07 9E 00 2D 35 64 8A 00 00 65 8A 00 00 00 00 01 DE 8A 00 00 0F 00 B8 8F 00 00 35 60 8A 00 00 65 8A 00 00 00 00 01 DE 8A 00 00 0F 00 B4 8F 00 00 AF 1E 00 00 80 BF AB 12 20 BC 4D 00 00 2A 00 6F 4D 00 00 00 1C 71 4D 00 00 A8 A8 38 57 01 04 FA FF FF 38 57 61 1C 16 16 38 57 1C B5 FC FF FF 16 16 16 38 3F 2C 03 16 16 07 43 01 81 1B 6E 2D 00 00 00 00 00 00 00 B7 8F 00 00 00 B8 8F 00 00 00 B5 8F 00 00 00 B4 8F 00 00 48 BA 8F 00 00 16 16 1B C3 68 00 00 00 00 00 00 48 BA 8F 00 00 16 04 00 B7 8F 00 00 04 3A B9 8F 00 00 53 new hex: (virtual size 0x154)CF 8F 00 00 50 55 00 00 00 00 00 00 B3 8F 00 00 CA 8C 00 00 00 00 00 00 BA 8F 00 00 00 00 00 00 36 1A 00 00 A6 75 03 00 54 01 00 00 E8 00 00 00 19 01 B8 8A 00 00 0B 00 00 00 00 00 00 1B AE 61 00 00 00 00 00 00 27 16 0F 00 B6 8F 00 00 19 01 B8 8A 00 00 0A 00 D7 32 00 00 00 1B FE 32 00 00 00 00 00 00 16 0F 00 B7 8F 00 00 00 B6 8F 00 00 07 A2 00 2D 35 64 8A 00 00 65 8A 00 00 00 00 01 DE 8A 00 00 0F 00 B8 8F 00 00 35 60 8A 00 00 65 8A 00 00 00 00 01 DE 8A 00 00 0F 00 B4 8F 00 00 AF 1E 00 00 80 BF AB 12 20 BC 4D 00 00 2A 00 6F 4D 00 00 00 1C 71 4D 00 00 A8 A8 38 57 01 04 FA FF FF 38 57 61 1C 16 16 38 57 1C B5 FC FF FF 16 16 16 38 3F 2C 03 16 16 07 47 01 81 1B 6E 2D 00 00 00 00 00 00 00 B7 8F 00 00 00 B8 8F 00 00 00 B5 8F 00 00 00 B4 8F 00 00 48 BA 8F 00 00 16 16 1B C3 68 00 00 00 00 00 00 48 BA 8F 00 00 16 04 00 B7 8F 00 00 0B 0B 53 decompiled code:function Vector DecideNextDestination(optional out string strFail){ local XGUnit kEnemy; local Vector vDestination, vCurrLoc, VDir; local float DistSq; m_kUnit.SetDashing(true); vCurrLoc = m_kUnit.GetLocation(); vDestination = vCurrLoc; // End:0xA2 if(m_kTrackingCue.bTracking) { kEnemy = m_kTrackingCue.kTarget; } DistSq = -1.0 - (class'XComEngine'.static.SyncFRand((string(Name) @ string(GetStateName())) @ string(GetFuncName())) * float(3)); // End:0x147 if(!FindRunawayPosition(vDestination, kEnemy, VDir, DistSq, strFail)) { SwitchToAttack(strFail); } return vDestination; } 3) Swapped the order of the checks for GotoState('TacticalMove') and GotoState('Flee') in ExecuteMoveAbility. Previously 'TacticalMove' would be performed if available, disallowing 'Flee'. Now 'Flee' takes priority. before:07 45 01 1B A7 36 00 00 00 00 00 00 16 71 21 13 69 00 00 00 00 00 00 4A 4A 4A 16 06 F0 01 07 63 01 1B 07 64 00 00 00 00 00 00 16 71 21 10 2E 00 00 00 00 00 00 4A 4A 4A 16 after:07 45 01 1B 07 64 00 00 00 00 00 00 16 71 21 10 2E 00 00 00 00 00 00 4A 4A 4A 16 06 F0 01 07 63 01 1B A7 36 00 00 00 00 00 00 16 71 21 13 69 00 00 00 00 00 00 4A 4A 4A 16 decompiled code: if(ShouldFlee()) { GotoState('Flee'); } // End:0x1F0 else { // End:0x163 if(HasScoredCoverOptions()) { GotoState('TacticalMove'); } 4) Changed the function GetMaxDangerLevelForMovement to return 3 by default instead of 1. Since overwatching nearly always set the OverwatchDangerLevel to 3, this was preventing the MoveAbility from being added to the list of possible abilities to consider. before: 07 94 00 9A 00 84 8F 00 00 25 16 04 2C 02 04 26 04 3A 85 8F 00 00 after:07 93 00 9A 00 84 8F 00 00 25 16 04 26 04 2C 03 04 3A 85 8F 00 00 decompiled code:simulated function int GetMaxDangerLevelForMovement(){ local int iDiff; // End:0x10 if(m_bIgnoreOverwatchers) { return 3; } iDiff = XComTacticalGRI(class'Engine'.static.GetCurrentWorldInfo().GRI).m_kBattle.GetDifficulty(); // End:0x93 if(iDiff == 0) { return 1; } return 3; //return ReturnValue; } 5) Explicitly overrode the function ShouldAvoidMovement to return false even if the unit is being overwatched change:04 27 04 28 04 3A 89 8F 00 00 53 to:04 28 04 28 04 3A 89 8F 00 00 53 decompiled code: if((!m_kUnit.IsMeleeOnly() && !m_bIsMindControlled) && m_iOverwatchDangerZone > (GetMaxDangerLevelForMovement())) { return false; } return false; 6) Modified the distance check for MinDistanceToCover in the 'Flee' state from 0 to 128 (2 tiles) before:07 22 00 1B 05 64 00 00 00 00 00 00 4A 16 0F 00 D8 8E 00 00 25 06 2E 00 0F 00 D8 8E 00 00 2C 80 after:0B 0B 0B 1B 05 64 00 00 00 00 00 00 4A 16 0F 00 D8 8E 00 00 25 0B 0B 0B 0F 00 D8 8E 00 00 2C 80 decompiled code:simulated function bool GetFleeLocation(out Vector vCover, XGUnit kEnemy, optional bool bInternal, optional out string strFail){ local int iMinDist; local array<XComCoverPoint> arrValidDest; bInternal = true; ShouldFindCover(); iMinDist = 0; iMinDist = 128; arrValidDest = GetValidDestinations(); // End:0xBA if((CanUseCover()) && m_kUnit.GetBestDestination(vCover, iMinDist, BaseValidator, arrValidDest, m_bCanIgnoreCover, strFail)) { return true; } 7) Modified the XGAIBehavior.(State 'Flee'). FindRunAwayPosition to return true only if it actually found a valid RunAwayPosition. Previously it always returned true, which would prevent SwitchToAttack from executing if FindRunAwayPosition failed to find a valid position to run away to. before:04 27 04 3A AB 8F 00 00 53 after:04 2D 01 D0 8A 00 00 0B 53 decompiled code: simulated function bool FindRunawayPosition(out Vector vLoc, XGUnit kEnemy, optional out Vector vDirToEnemy, optional float fMetersFromEdge, optional out string strFail) { fMetersFromEdge = 0.0; m_bMoveToActionPoint = GetFleeLocation(vLoc, kEnemy, true, strFail); return m_bMoveToActionPoint; } Link to comment Share on other sites More sharing options...
johnnylump Posted May 8, 2013 Author Share Posted May 8, 2013 Wow, well done. I hope the exercise of familiarizing yourself with the AI was useful! Just curious, did you test these in isolation from one another? It strikes me that #7 might be the point of failure that in that it kept SwitchToAttack from firing at all, but that's my read of these changes without having tested them. I may attempt #7 separately first and see if that indeed was the issue. Link to comment Share on other sites More sharing options...
Yzaxtol Posted May 8, 2013 Share Posted May 8, 2013 (edited) "We're not just banging rocks together down here, We know how to put an AI back together!" - Cave Johnson Edit: Very interesting, will probably see If I can stea... use this lovely code :D Edit2: Right after I finish clutching my chest after my 3rd panic attack of the day. Bad day. Edited May 8, 2013 by Yzaxtol Link to comment Share on other sites More sharing options...
Amineri Posted May 8, 2013 Share Posted May 8, 2013 One thing that needs to be addessed is the conditions that will 100% prevent a unit from moving. There are a few specific conditions that will 'hard limit' moving (as opposed to a 'soft' limit from reducing move priority). 1) Alien is suppressed -- this is tested via HasRestrictions/PassesRestrictions This is established via XGAIAbilityRules.BuildConditions, line : SetAbilityRestriction(1, 1); 2) Alien CanMelee -- this is tested via HasRestrictions/PassesRestrictions This is established via XGAIAbilityRules.BuildConditions, line : SetAbilityRestriction(1, 64); 3) ShouldAvoidMovement returns true This is tested in XGAIBehavior.FilterAbilities with the test: if(m_kAbilityDM.m_bShouldAvoidMovement || bLastResort) { kAbility = m_kUnit.GetMoveAbility(); arrSkip.AddItem(kAbility); } ShouldAvoidMovement returns true in the following conditions:1) There are no flanking units, the unit is not the initiator of a Mindmerge, and:a) has a vulnerable target and has a better than 70% chance to hit the vulnerable targetsb) has a better than 70% chance to hit any other target 2) If the unit is not MeleeOnly, not MindControlled and there are "too many" overwatching units The definition of "too many" overwatching units has a few details. The game computes a m_iOverwatchDangerZone.a) m_iOverwatchDangerZone = 0 if there are no enemes on the map overwatching anywhereb) m_iOverwatchDangerZone = 1 if there are any enemies on the map overwatching, even if out of sightc) The game counts the number of enemies overwatching, in visual ranged) If any are within "short" range, m_iOverwatchDangerZone = 3 (short range-- Easy:18 tiles, Normal:20 tiles, Classic/Impossible: 24 tiles)e) If alien has low hp, m_iOverwatchDangerZone = 2f) Otherwise m_iOverwatchDangerZone = number of overwatching enemies at long range, max of 3 The game then computes the GetMaxDangerLevelForMovement -- On Easy this is 2, on Normal/Classic/Impossible this is 1. If m_iOverwatchDangerZone > GetMaxDangerLevelForMovement, the ShouldAvoidMovement is true Because "short" range is so long on Classic/Impossible (24 tiles), just one XCOM soldier overwatching can easily make m_iOverwatchDangerZone = 3, which will make movement impossible for any alien within 24 tiles of that soldier. One soldier can lock down 10 aliens in this manner. Each individual alien is so "afraid" to move that the entire group will fail to move. The 'inaction' bug comes about because the prioritization code for shooting gives a -100 priority to shooting if the alien is flanked, to try and make the alien prioritize movement away from being flanked. If the shot to-hit % is low, this can easily result in a negative priority which disallows ShotStandard from being a valid ability. ---------------------------------------------------------------------- The question then arises: what SHOULD the conditions be under which an alien is prohibited from moving? I'd suggest the following:a) If an alien unit is flanked / exposed (and can use cover), then ShouldAvoidMovement should return falseMovement should always be an option if the unit is in a vulnerable position. Inhibition of movement by overwatching will take place via move priority calculations. b) m_iOverwatchDangerZone should compute "short" range as 10 tiles for all difficultiesReducing the "short" range will prevent 1 soldier from locking down large numbers of enemies. Three XCOM soldiers would need to be in overwatch to reach the maximum DangerZone level c) GetMaxDangerZoneLevelForMovement should return 2 for all difficultiesThis would place a hard restriction on movement only if 3 soldiers are overwatching, or one soldier at 10 tiles or less range (unless the unit is flanked). Movement will still be discouraged by placing priority penalties on movement for being overwatched. d) A score penalty based on m_iOverWatchDangerZone should be applied in GetMoveDefenseScorePenalty of 16 * m_iOverwatchDangerZone reduces the move priority by 16, 32 or 48 for 1, 2 or 3 overwatchers For comparison, the GetMoveOffense score generally ranges from 50 to 100, based on the alien's best to-hit chance at its current location. Score is 90 if 10%, 70 if 30%, and 50 if 50% or higher. Move Priority should never be less than 1. e) There should be no ShotDefense penalty for being flanked if the unit ShouldAvoidMovementIf movement is entirely disallowed then the unit shouldn't be penalized for being flanked. This would allow the unit to correctly prioritize targets when it is essentially forced to shoot (by being disallowed movement) Link to comment Share on other sites More sharing options...
anUser Posted May 8, 2013 Share Posted May 8, 2013 I'm sorry I can't give any insight, there's just too much code for me to catch up, and I see you're doing pretty well so far. So is the aim still making aliens don't skip their turn, is it all so tangled, or are you planning some other enhancements? I must say I'd love seeing aliens performing dash moves inteligently, but just fixing the skipt turn bug would be great, preferably with an easy way to switch between fire / overwatch or 50/50, if that is possible (easy way I mean 1 hex edit or 2). Link to comment Share on other sites More sharing options...
Amineri Posted May 8, 2013 Share Posted May 8, 2013 @anUser I've added code that I believe should allow for Dashing moves when fleeing. I followed the pattern in the code from the 'flank' state. However, I have yet to observe any dashing behavior when fleeing. AI Code can be a bit maddening. I now seem to be unable to replicate the earlier situation where sectoid were doing things even when flanked and overwatched -- somehow I've gotten back to a point where units are essentially prohibited from moving if there are enemies overwatching, even though I modified the ShouldAvoidMovement function. The ShouldAvoidMovement is kind of misnamed. It is really more like an "AbsolutelyForbiddenFromMovement" kind of thing. My primary goal here is to get units doing things even when overwatched and flanked, and to reduce the absolute restrictions on movement if an XCOM unit is overwatching. Allowing fleeing units to Dash was a thought to accomplish this, by giving the fleeing unit more options when attempting to flee. In the vanilla game, units could only attempt to flee if they were flanked or exposed, and NOT overwatched. My goal is to toss fleeing back into the mix if the unit is overwatched, if there aren't very many overwatching units. Link to comment Share on other sites More sharing options...
Amineri Posted May 8, 2013 Share Posted May 8, 2013 (edited) Found one more piece of the puzzle. The function PassesMoveFilter would remove any non-move ability if the unit was exposed or flanked (and had more than 1 move action left). This resulted in the following condition: 1) Move ability is filtered out because OverwatchDangeZone level is too high2) Non-move abilities are filtered out because the unit is flanked or exposed, so should move Result: No abilities left on the list. The conditionQuoteif(m_kAbilityDM.m_nAbilities == 0){ m_iDebugHangLocation = 3;GotoState('EndOfTurn');}at the beginning of (state 'ExecutingAI') would be met and the unit would end its turn. I now have the units reliably shooting when overwatched + flanked/exposed, which is an improvement. If only one unit is overwatching and it has a poor shot, however, it should have the option to flee to cover, I think, based on the relative priorities of the shot versus the 'goodness' of the cover. Still can't quite see how the move abilities is getting lost, but at least some sort of fix is in hand. The hex change to prevent filtering of non-move abilities in PassesMoveFilter is pretty straightforward: EDIT -- I had posted the wrong hex code. See the post below for the correct hex :) Applied to XcomGame.upk Edited May 9, 2013 by Amineri Link to comment Share on other sites More sharing options...
johnnylump Posted May 9, 2013 Author Share Posted May 9, 2013 Amineri, Is that the right hex change? It's identical to change #6 above. Link to comment Share on other sites More sharing options...
Amineri Posted May 9, 2013 Share Posted May 9, 2013 Gah.... my eyes are crossing from looking at this AI code. You are correct, that was the wrong hex replacement. The correct one is: change:69 6F 6E 2E 00 16 04 28 07 96 03 to:69 6F 6E 2E 00 16 04 27 07 96 03 The crazy thing is that now I have the AI consistenly shooting at units when OW + flank/exposed, and they even prioritize to shoot at units that are flanking them / units with low Health. However, I've taken out the changes that should be allowing this, so I'm very puzzled. I'm reverting back to a clean install to see if something got really weird in my install. For some reason when I enabled the developer console using ToolBoks the start screen is the correct dev console menu, but I can't get the command-line from within the game. Craziness... Think I'm going to take a short break from the AI-delving and build the integrated Custom Mod installer for the expanded perk tree... Link to comment Share on other sites More sharing options...
Recommended Posts