Putting the 'role' back in role-playing games since 2002.
Donate to Codex
Good Old Games
  • Welcome to rpgcodex.net, a site dedicated to discussing computer based role-playing games in a free and open fashion. We're less strict than other forums, but please refer to the rules.

    "This message is awaiting moderator approval": All new users must pass through our moderation queue before they will be able to post normally. Until your account has "passed" your posts will only be visible to yourself (and moderators) until they are approved. Give us a week to get around to approving / deleting / ignoring your mundane opinion on crap before hassling us about it. Once you have passed the moderation period (think of it as a test), you will be able to post normally, just like all the other retards.

Pillars of Eternity Coding/Hacking Thread

Sensuki

Arcane
Joined
Oct 26, 2012
Messages
9,799
Location
New North Korea
Codex 2014 Serpent in the Staglands Shadorwun: Hong Kong A Beautifully Desolate Campaign
Might as well download it myself and see if I can reproduce the issue.
 

Naraya

Arcane
Joined
Oct 19, 2014
Messages
1,513
Location
Tuono-Tabr
Well, good news for IE mod, bad news for me. I've disabled Improved AI and it didn't change anything. I've also performed a test where I loaded a way earlier savegame and it's broken in the same way. I am 100% sure it was working fine back then. I have disabled the mod completely - still same problem.

Can someone verify it on their game, please? I reckon savegames can be transferred without problems?
Here's the one from my video (just outside Thieves' Hideout): https://www.sendspace.com/file/ivhzev

output_log.txt, seeing lots of errors there... https://www.sendspace.com/file/k1fqk0
 
Last edited:

Naraya

Arcane
Joined
Oct 19, 2014
Messages
1,513
Location
Tuono-Tabr
OK, I think I have nailed the problem. I have reinstalled the game and there was no change so I reset the keybindings to default (the game won't reset them itself) and this fixed it. Turns out I somehow managed to unbind my Attack, therefore my guess is that when I left-clicked an enemy the game thought I want to move to this position or interact with this NPC (which is NOT the same as attack him, even if he's hostile).

Phew, sorry for the confusion. I still don't know how and when I managed to do that...
 

agris

Arcane
Patron
Joined
Apr 16, 2004
Messages
6,764
Is it possible to modify existing items using Bester's Modding Framework? I'd like to change all the items that do 1 proc/crit per encounter to a flat percentage to proc per hit, no encounter or hit-type limitations.
 

Bester

⚰️☠️⚱️
Patron
Vatnik
Joined
Sep 28, 2014
Messages
11,006
Location
USSR
Yeah, as long as it's optional in the menu. Brandon Wallace reviews and accepts pull requests.

You can run a check on all items in the area on level load, and another one on loot spawn, and modify items any way you want.
 

TheFilthyJack

Educated
Joined
Apr 16, 2013
Messages
54
Thanks for your hard work Bester!

I gave this a try and I have been able to inject code into the assembly with reflector/reflexil without problem but I had a few questions if you don't mind:

-Can you break down how to add a line to OnLevelLoad? I can see the GameState.OnLevelWasLoaded() method with the area name, is this the one?
Would something like this work?

if (area_name == "dyrford")
{
create_npc_from_prefab();
assign_dialog_from_prefab(); // how to do this?
}

-Can we add a brand new dialog/quest to the resources without using Unity? If not does this mean we have to create a bunch of dummy dialog/quest so modders can work without Unity?

Sorry for pestering but I'd love to try a few things ;)
 

Bester

⚰️☠️⚱️
Patron
Vatnik
Joined
Sep 28, 2014
Messages
11,006
Location
USSR
I can see the GameState.OnLevelWasLoaded() method with the area name, is this the one?
No, it's in GameState.FinalizeLevelLoad()

Would something like this work?

if (area_name == "dyrford")
{
create_npc_from_prefab();
assign_dialog_from_prefab(); // how to do this?
}
Yes it would work. It's likely that you only have to create him once (if an NPC has some component, mobile-something, I think it stays on the map forever), so you'll also have to run a check on global variables if you already visited this area at least once or not. In case such global vars don't exist, you'll have to make them yourself.

// how to do this?
Idk, have a look at a few NPCs in GameObject Browser to see what's what.

Can we add a brand new dialog/quest to the resources without using Unity?
Don't know about quests, but dialogues are external files in the game folder somewhere (don't remember the path exactly).

Also, I really recommend you use modding framework, it's a bit difficult to set up, but once you did it, it'll be a million times easier to mod.
 

TheFilthyJack

Educated
Joined
Apr 16, 2013
Messages
54
Thanks for the info!

I have the code for an external character sheet system working, it follows your summon creature code, adding a file IO call to get the stats from a text file.
The only thing preventing external companion creation is the possibility to assign a brand new dialog file to the GameObject created. Something like GameObject.GetComponent<Conversation>().Load(string);

The problem is, can I just add a string table and a dialog file without serializing it? If you duplicate a creature and change its name it is not usable by console commands even though it exists in the folder. This is why I asked if we had to create dummy "pre-srialized" resources for modders to fiddle with.

Code:
  static void CreateNPC(string prefab_name, string sheet_name)
   {
    Console.AddMessage("Starting test...", UnityEngine.Color.red);
    UnityEngine.GameObject test_npc;
    test_npc = GameResources.LoadPrefab<UnityEngine.GameObject>(prefab_name, true);
 
    if(test_npc == null) return;
 
    Console.AddMessage("Creature loaded: "+prefab_name, UnityEngine.Color.red);
    test_npc.transform.position = GameInput.WorldMousePosition;
    test_npc.transform.rotation = GameState.s_playerCharacter.transform.rotation;
 
    if(test_npc.GetComponent<Faction>() != null)
    {
    test_npc.GetComponent<Faction>().RelationshipToPlayer = Faction.Relationship.Neutral;
    test_npc.GetComponent<Faction>().CurrentTeamInstance = Team.GetTeamByTag("player");
    }

    if(test_npc.GetComponent<AIPackageController>() != null)
    {
    test_npc.GetComponent<AIPackageController>().ChangeBehavior(AIPackageController.PackageType.DefaultAI);
    test_npc.GetComponent<AIPackageController>().InitAI();
    }
 
    StreamReader file1 = new StreamReader(sheet_name);

    if(file1 == null) return;

    test_npc.GetComponent<CharacterStats>().BaseConstitution = int.Parse(file1.ReadLine());
    test_npc.GetComponent<CharacterStats>().BaseDexterity = int.Parse(file1.ReadLine());
    test_npc.GetComponent<CharacterStats>().BaseIntellect = int.Parse(file1.ReadLine());
    test_npc.GetComponent<CharacterStats>().BaseMight = int.Parse(file1.ReadLine());
    test_npc.GetComponent<CharacterStats>().BasePerception = int.Parse(file1.ReadLine());
    test_npc.GetComponent<CharacterStats>().BaseResolve = int.Parse(file1.ReadLine());
 
     file1.Dispose();

    // serialize .conversation, .stringtable ?
    // test_npc.GetComponent<Conversation>().Load(conv_name); ?

   }
If I could somehow find a way to make the last two commented lines happen it would be awesome...

I couldn't install the modding framework properly but from what I see it can be possible to do what I need simply with ilasm or reflexil, maybe...
 
Last edited:

Bester

⚰️☠️⚱️
Patron
Vatnik
Joined
Sep 28, 2014
Messages
11,006
Location
USSR
The problem is, can I just add a string table and a dialog file without serializing it?
Yeah, see how they're loaded and do the same thing.

If you duplicate a creature and change its name it is not usable by console commands even though it exists in the folder.
Why not? ChangeName only changes its overridename or something like that. It's still got the same gameobject name. Or any gameobject name that you assign it in the code. So in your case, just do test_npc.name = "TestNpc"; and then you can access it like that.

This is why I asked if we had to create dummy "pre-srialized" resources for modders to fiddle with.
You can, sure. Or you can just create an empty gameObject and do AddComponent a few times to add the same components that any NPC has. So you can just make a function that creates an npc only using code, or you can make a prefab. Your choice. I think it's easier to do it in the code, until someone can fix the asset editor.

If I could somehow find a way to make the last two commented lines happen it would be awesome...
Well like I said, have a look at existing NPCs with GameObject Browser to see what they have on their dialogue-related components and then do the same thing.
 

TheFilthyJack

Educated
Joined
Apr 16, 2013
Messages
54
You're awesome... I didn't get it when you talked about the object editor, just installed your assembly and it works perfectly!
 

agris

Arcane
Patron
Joined
Apr 16, 2004
Messages
6,764
Does anyone know if the saved UI positions are externalized, and where I can find them? I'd like to backup certain UI configurations.
 

Bester

⚰️☠️⚱️
Patron
Vatnik
Joined
Sep 28, 2014
Messages
11,006
Location
USSR
Does anyone know if the saved UI positions are externalized, and where I can find them? I'd like to backup certain UI configurations.
Somewhere in the registry, along with all the other poe's settings.
 

Somberlain

Arcane
Zionist Agent
Joined
Mar 5, 2012
Messages
6,202
Location
Basement
Is it likely that someone will eventually make a mod that allows characters to stealth individually, or is there some gameplay reason why this couldn't be done?
 

Ninjerk

Arcane
Joined
Jul 10, 2013
Messages
14,323
Is it likely that someone will eventually make a mod that allows characters to stealth individually, or is there some gameplay reason why this couldn't be done?
I believe there was an announcement that they wanted to change stealth implementation themselves, because the release version was just for stability.
 

agris

Arcane
Patron
Joined
Apr 16, 2004
Messages
6,764
yeah, download and install the latest one from here and use my settings-file. You can tune the sharpness up/down if you like to by changing one line under "LumaSharpen settings":
#define sharp_strength 0.60 // [0.10 to 3.00] Strength of the sharpening

So, download sweetfx and install, copy my settings-file to \pillars of eternity\sweetfx\
I've been using this modification for a while, and found that it made the weight of text (character sheet, item descriptions) really uneven at 1920x1200. I can get about the same map sharpness without the text distortion using these settings (LumaSharpen is the only option enabled in the SweetFX_settings.txt file)
Code:
  /*-----------------------------------------------------------.
  /  LumaSharpen settings  /
  '-----------------------------------------------------------*/
// -- Sharpening --
#define sharp_strength 0.50  //[0.10 to 3.00] Strength of the sharpening
#define sharp_clamp  0.045  //[0.000 to 1.000] Limits maximum amount of sharpening a pixel recieves - Default is 0.035

// -- Advanced sharpening settings --
#define pattern 3  //[1|2|3|4] Choose a sample pattern. 1 = Fast, 2 = Normal, 3 = Wider, 4 = Pyramid shaped.
#define offset_bias 4.0  //[0.0 to 6.0] Offset bias adjusts the radius of the sampling pattern.
  //I designed the pattern for offset_bias 1.0, but feel free to experiment.

// -- Debug sharpening settings --
#define show_sharpen 0  //[0 or 1] Visualize the strength of the sharpen (multiplied by 4 to see it better)

edit: updated
 
Last edited:

Florimel

Barely Literate
Joined
Aug 11, 2015
Messages
3
Hello everyone...

I found manual handling of the camera quite annoying in PoE.

I've therefore patched the game (ildasm/ilasm, as explained in this thread) in order to:
- automatically center the camera when moving the characters around
- allow camera zoom (with the mouse wheel) even if UI windows (such as conversations) are displayed

Both enhancement are only active when "scroll lock" is off. The original behavior is restored when "scoll lock" is on.

Code:
// BEGIN MOD
[DllImport("user32.dll", SetLastError = true, PreserveSig = false)]
private static extern short /* GameInput:: */ GetKeyState(IntPtr keyCode);

public static bool /* GameInput:: */ GetScrollLock()
{
	return (bool)(GetKeyState(0x91) & 1);
}
// END MOD

/*
.class public auto ansi GameInput
//...

// BEGIN MOD
  .method private hidebysig static pinvokeimpl("user32.dll" lasterr winapi) int16 GetKeyState(native int keyCode) cil managed
  {
  }
  .method public hidebysig static bool GetScrollLock() cil managed
  {
    .maxstack  8
    ldc.i4     0x91
    call       int16 GameInput::GetKeyState(native int)
    ldc.i4.1
    and
    ret
  }
// END MOD

*/

private void /* Player:: */ Update()
{
//...
	if (GameInput.GetControlDownWithoutModifiers(MappedControl.ROTATE_FORMATION) || GameInput.GetControlDownWithoutModifiers(MappedControl.MOVE))
	{
		this.FormationRotationPickPosition = GameInput.WorldMousePosition;
		this.m_ignoreNextMoveControlUp = false;
// BEGIN MOD
		if ((GameCursor.ActiveCursor == GameCursor.CursorType.Walk) && !GameInput.GetScrollLock())
			Camera.main.GetComponent<CameraControl>().FocusOnPoint(GameInput.WorldMousePosition, 1.5f);
// END MOD
	}
//...
}

/*
    IL_08cf:  ldc.i4.s   9
    IL_08d1:  call       bool GameInput::GetControlDownWithoutModifiers(valuetype MappedControl)
    IL_08d6:  brtrue     IL_08e6

    IL_08db:  ldc.i4.3
    IL_08dc:  call       bool GameInput::GetControlDownWithoutModifiers(valuetype MappedControl)
    IL_08e1:  brfalse    IL_08f8

    IL_08e6:  ldarg.0
    IL_08e7:  call       valuetype [UnityEngine]UnityEngine.Vector3 GameInput::get_WorldMousePosition()
    IL_08ec:  call       instance void Player::set_FormationRotationPickPosition(valuetype [UnityEngine]UnityEngine.Vector3)
    IL_08f1:  ldarg.0
    IL_08f2:  ldc.i4.0
    IL_08f3:  stfld      bool Player::m_ignoreNextMoveControlUp

// BEGIN MOD
              call       valuetype GameCursor/CursorType GameCursor::get_ActiveCursor()
              ldc.i4.2
              bne.un     IL_08f8
              call       bool GameInput::GetScrollLock()
              brtrue     IL_08f8
              call       class [UnityEngine]UnityEngine.Camera [UnityEngine]UnityEngine.Camera::get_main()
              callvirt   instance !!0 [UnityEngine]UnityEngine.Component::GetComponent<class CameraControl>()
              call       valuetype [UnityEngine]UnityEngine.Vector3 GameInput::get_WorldMousePosition()
              ldc.r4     1.5
              callvirt   instance void CameraControl::FocusOnPoint(valuetype [UnityEngine]UnityEngine.Vector3, float32)
// END MOD

    IL_08f8:
*/

public void /* UIWindowManager:: */ WindowShown(UIHudWindow window)
{
//...
	if (window.EatsKeyInput && (CameraControl.Instance != null)
// BEGIN MOD
		&& GameInput.GetScrollLock())
// END MOD
	{
		CameraControl.Instance.EnablePlayerControl(false);
	}
}

/*
    IL_014f:  ldarg.1
    IL_0150:  ldfld      bool UIHudWindow::EatsKeyInput
    IL_0155:  brfalse    IL_0174

    IL_015a:  call       class CameraControl CameraControl::get_Instance()
    IL_015f:  call       bool [UnityEngine]UnityEngine.Object::op_Implicit(class [UnityEngine]UnityEngine.Object)
    IL_0164:  brfalse    IL_0174

// BEGIN MOD
                      call       bool GameInput::GetScrollLock()
                      brfalse     IL_0174
// END MOD

    IL_0169:  call       class CameraControl CameraControl::get_Instance()
    IL_016e:  ldc.i4.0
    IL_016f:  callvirt   instance void CameraControl::EnablePlayerControl(bool)
    IL_0174:  ret
*/
 

Florimel

Barely Literate
Joined
Aug 11, 2015
Messages
3
Just fixing a bug with the previous patch (camera control when UI windows). Should be better by adding also the changes below...

Code:
public void /* CameraControl:: */ DoUpdate()
{
//...
   if (this.PlayerScrollEnabled
// BEGIN MOD
          && !UINoClick.MouseOverUI && GameCursor.UiObjectUnderCursor == null)
// END MOD
   {
          float axisRaw = Input.GetAxisRaw("Mouse ScrollWheel");
//...
   }
   if (GameInput.GetDoublePressed(KeyCode.Mouse0, true) && !UINoClick.MouseOverUI
// BEGIN MOD
          && GameCursor.UiObjectUnderCursor == null)
// END MOD
//...
}

/*

    IL_0074:  ldarg.0
    IL_0075:  call       instance bool CameraControl::get_PlayerScrollEnabled()
    IL_007a:  brfalse    IL_00a7

// BEGIN MOD
              call       bool UINoClick::get_MouseOverUI()
              brtrue     IL_00a7
              ldsfld     class [UnityEngine]UnityEngine.GameObject GameCursor::UiObjectUnderCursor
              call       bool [UnityEngine]UnityEngine.Object::op_Implicit(class [UnityEngine]UnityEngine.Object)
              brtrue     IL_00a7
// END MOD

    IL_007f:  ldstr      "Mouse ScrollWheel"
    IL_0084:  call       float32 [UnityEngine]UnityEngine.Input::GetAxisRaw(string)
    IL_0089:  stloc.1
    IL_008a:  ldloc.1
    IL_008b:  ldc.r4     0.0
    IL_0090:  beq        IL_00a7

    IL_0095:  ldarg.0
    IL_0096:  call       instance class SyncCameraOrthoSettings CameraControl::get_OrthoSettings()
    IL_009b:  ldloc.1
    IL_009c:  callvirt   instance void SyncCameraOrthoSettings::SetZoomLevelDelta(float32)
    IL_00a1:  ldarg.0
    IL_00a2:  call       instance void CameraControl::ResetAtEdges()
    IL_00a7:  ldc.i4     0x143
    IL_00ac:  ldc.i4.1
    IL_00ad:  call       bool GameInput::GetDoublePressed(valuetype [UnityEngine]UnityEngine.KeyCode,
                                                          bool)
    IL_00b2:  brfalse    IL_0111

    IL_00b7:  call       bool UINoClick::get_MouseOverUI()
    IL_00bc:  brtrue     IL_0111

// BEGIN MOD
              ldsfld     class [UnityEngine]UnityEngine.GameObject GameCursor::UiObjectUnderCursor
              call       bool [UnityEngine]UnityEngine.Object::op_Implicit(class [UnityEngine]UnityEngine.Object)
              brtrue     IL_0111
// END MOD

*/
 

Florimel

Barely Literate
Joined
Aug 11, 2015
Messages
3
A good shortcut for quick camera movement in PoE is to double-press the 0 to 9 keys, to center on a given character or group... except that it was failing for 0 (but OK for 1 to 9).

This additional patch fixes that bug in PoE :
Code:
private void /*  UIPartyPortraitBar:: */ Update()
{
//...
// BEGIN MOD
                int num4 = (i + 1) % 10;
// END MOD
                if (GameInput.GetDoublePressed((KeyCode) (0x30 + num4), true) || GameInput.GetDoublePressed((KeyCode) (0x100 + num4), true))
//...
        if (num9 == -1)
        {
// BEGIN MOD
            num9 = 9;
// END MOD
        }

}

/*

    IL_01b3:  ldloc.s    V_7
    IL_01b5:  ldc.i4.1
    IL_01b6:  add
// BEGIN MOD
              ldc.i4.s   10
              rem
    IL_01b7:  stloc.s    V_8
//  IL_01b9:  ldloc.s    V_8
//  IL_01bb:  ldc.i4.s   10
//  IL_01bd:  ble        IL_01c5
//  IL_01c2:  ldc.i4.0
//  IL_01c3:  stloc.s    V_8
// END MOD

//...

    IL_0298:  ldloc.s    V_15
    IL_029a:  ldc.i4.m1
    IL_029b:  bne.un     IL_02a4
// BEGIN MOD
    IL_02a0:  ldc.i4.s   9
// END MOD
    IL_02a2:  stloc.s    V_15

*/
 

As an Amazon Associate, rpgcodex.net earns from qualifying purchases.
Back
Top Bottom