Jump to content

suy

Members
  • Posts

    223
  • Joined

  • Last visited

Posts posted by suy

  1. If you kill a fiend in the prime material plane... do you really kill it?

    I thought you actually destroy a "shell" of a body there, but then it returns to its own plane, and you would need to kill them there to actually destroy them for real.

    I assumed it was the same for a Planetar or Deva: you just destroy a body in the Prime, not the creature for real. I'm saying this because it was mentioned the "problem" of a good-aligned character treating them as disposable. Well, you don't really send them to death.

     

  2. I knew that, and also, it just seems less convenient for you also. That's why I never got why you did not register before, as you seem to be somewhat regular, and for a while. I am super lazy at registering at sites, but there is a moment where the laziness gets surpassed by the inconvenience. 😅

    In any case, welcome.

  3. Respect the flags: I've not bothered to try it myself, but I've always assumed that it is not possible, or someone would have proposed a tweak to make Belm, Kundane or Defender of Easthaven a right-handed weapon only. But if someone finds a combination of them that works, I'll surely would like to use it for exactly that purpose. 😛

    That said, there is a workaround that it has not been mentioned (maybe because it's ugly): add a ranged component to the weapon. Thrown axes/daggers can't be equipped in the left hand because of that reason.

  4. Oh, maybe I've looked at it wrong. But I mean this block:

    BEGIN_ACTION_DEFINITION
    	Name(Attack)
    	TRIGGER
                    ActionListEmpty()
    	        !StateCheck(Myself,STATE_INVISIBLE)
    	        !CheckStatGT(Myself,0,SANCTUARY)
    	        !ModalState(TURNUNDEAD)
             	!HasItem("eneblade",Myself)
    	        !HasItem("melfmet",Myself)
    	        See(scstarget)
    	        Allegiance(scstarget,ENEMY)
    	        !InParty(scstarget)
    	        InParty(Myself)
    	        !StateCheck(scstarget,STATE_REALLY_DEAD)
                    WeaponEffectiveVs(scstarget,MAINHAND)
                    WeaponCanDamage(scstarget,MAINHAND)
    	ACTION
    		RESPONSE #scsprob1
    		Attack(scstarget)
    END
    

    The action at the end seems will just expand to Attack(NearestEnemyOf(Myself)) (or 2nd, 3rd nearest, etc, as it's used with 3 targets).

  5. If the words "console", "javascript" and "python" sound familiar (and not too scary) for you, then maybe... I got a script that I've used to hook into the engine, then output most of what's logged to a file. I've used to see the combat log in a separate window, and search/filter into it. The script is super messy (I rarely upload code looking like that), and so far works only on Linux because the names of the functions to hook into the engine are different (but I have another script which works on Linux and Windows, so I know that it's possible to make it work on both). Surely Bubb can come up with something nicer using EEex, or have some further suggestion.

    In case it's useful, for you or someone else, here is the script: https://gitlab.com/moebiusproject/proprietary-binary-modification/-/blob/master/frida/intercept-messagehandler-addmessage.js

    Eventually, I'll update it myself to work on both platforms and be a bit better (and merge it with other scripts that do other useful thing), but this is very low priority for me because I don't use it that often, and I rarely reboot on Windows.

  6. Thank you everyone for the feedback. I'll try what you all suggested, and see if I can get a clearer picture. I see that bdefai.bcs uses AttackOneRound, while SCS's bddefai.ssl uses Attack. I'll try both and see how they feel differently.

    A quick question though:

    On 11/23/2022 at 10:47 PM, jmerry said:

    If you were issuing a one-time command for a single action, they would be fine - but this attack command is expected to last a full five rounds.

    I may be misunderstanding something. IESDP says that the reevaluation period "is measured in AI updates (which default to 15 per second). (...) Just to give an idea, AttackOneRound() would be equivalent to AttackReevaluate() with a 100 tick reevaluation period".

    I thought that, at 30 FPS, the period being 30 would be 2 seconds (since the AI runs each other frame).

     

  7. Well, this is even funnier: after an enemy gets killed, even with the AI disabled, it goes for the next creature. So maybe it's some engine quirk, and the AI script is not to blame? Some other script beyond the party AI? Attached another short video. Note how the AI is disabled from the start. Charname and Jaheira are attacking a true enemy, with Corwin charmed in the middle. After the goblin is killed, they go for Corwin because it's the one closer, apparently. But again, the AI is disabled. At the end of the video happens again. I toggle AI with a shortcut.

    Edit: I could not upload the video (sorry for spamming the forum with attachments). Here is a link: https://imgur.com/a/tkpDBDv

  8. Yep, that was one of the combinations that I tried.

    With that it mostly works. It doesn't do the weird targeting of a team member by default. But has two problems:

    • If a character stands next to a charmed teammate, it doesn't go for any enemy. I guess it's fine, and I just need to repeat the block with the "second nearest". Is there no other better way?
    • But the main issue is that if an enemy gets killed, and the next close hostile creature is a team member, it goes for it! How can that be?

    Here is a video to show what I mean: https://imgur.com/a/Q9UQiry It's puzzling me.

     

  9. I have a humble AI script that I have been iterating on slowly by imitating other scripts that I've found, specially the ones coming from the game (e.g. thief0.bs, bard0.bs, etc.).

    It does some simple checks at the start to let the user change variables with a key, then depending on those variables find traps/sing bard song/etc. That part seems to work perfectly well. The last part, attacking, it's what I get wrong. The attack block is at the very bottom, and just has this:

    IF
    	Global("suy#fight","LOCALS",1)
    	ActionListEmpty()
    	!StateCheck(Myself,STATE_INVISIBLE)
    	CheckStatLT(Myself,1,SANCTUARY)
    	See(NearestEnemyOf(Myself))
    	!InParty(LastSeenBy(Myself))
    	!Allegiance(LastSeenBy(Myself),GOODCUTOFF)
    	!Class(LastSeenBy(Myself),INNOCENT)
    	OR(2)
    		Range(LastSeenBy(Myself),8)
    		InWeaponRange(LastSeenBy(Myself))
    	!ModalState(DETECTTRAPS)
    	!ModalState(STEALTH)
    	!ModalState(TURNUNDEAD)
    	!ModalState(BATTLESONG)
    THEN
    	RESPONSE #100
    		AttackReevaluate(LastSeenBy(Myself),30)
    END

    With this exact block, it more or less works well, but I get that sometimes a party member attacks another. If it matters, it's Jaheira (slot #2) that attacks Charname (in slot #1). I seem to reproduce this reliably, but it doesn't happen the other way around. I got it on a recording if it helps to show it (I need to trim it a bit to upload it though).

    I've tried different variations. One is that instead of `AttackReevaluate(LastSeenBy(Myself), 30)` I use `AttackReevaluate([EVILCUTOFF],30)`. With that, never the party member is attacked, but I find that if a party member gets charmed, this might end up attacked. I've also tried `See([EVILCUTOFF])` in the trigger.

    I look at the existing simple AI scripts, and they seem to do different for the attacking block. I don't know what's right. I know from other conversations that I've read that `See()` is a bit more complicated than what shows on the surface, so I guess that's my issue, but I can't find the details.

    Any idea? Thanks!

  10. From my side, as "responsible" of the axis being like it is, I'll file an issue to look at this to see how to improve it. On occasions I thought of controlling the values of the axes (like the "ticks" or other stuff), or provide rubber-band zooming, etc. I've personally liked the behavior that it has right now, where I basically have to fiddle very little with the axes to make it display something meaningful.

    In fairness, most of the times the lowest value that it's gonna show with the current implementation it's gonna be 0. Only in extreme cases like here is gonna appear to be "zoomed in" to the upper values. This is the worst offender in the original post that I did about 4 years ago:

    damage monk swashbuckler paladin late tob

    I 100% honestly can't tell if that is misleading to people, or it is fine enough. I look at lot at the numbers in the points, and it's kinda obvious to me that it's zoomed in to see the values better (otherwise they are stacked on top of each other much more often). So it is low priority for me to add the feature, but I'll definitely consider it for the benefit of others and to avoid any controversy. 😄

  11. The differences would be tinier, but IMHO, not tiny. I've had the Y axis always adjust automatically for about 4 years, and I've never felt the need to set the minimum to zero. The axis have clear values, and so do the data points. I'll consider adding the option of adjusting all the axis details, but it would just squish the lines and labels a lot in cases like this.

  12. 8 hours ago, Guest nerd mode on said:

    Such graphs are literally a staple of every "how to lie with statistics" article. Usually item #2 or #3: "don't start your axis from 0, and/or include gaps in the middle".

    Wut? Are you sure you understand what you are saying? The chart starts at the worst possible AC (10), then goes to the best (-20). When you have such a good to-hit number, it's entirely irrelevant if the enemy has 10 or 0 AC (because you still hit 95% of the times, i.e., only fail on critical miss), it's a flat line. It doesn't matter if it starts at 10 or 0 or -6 like here. It's a flat line.

    8 hours ago, Guest nerd mode on said:

    Also, most bosses are going to have missile resistance, further reducing the difference.

    And? This is a ranged-to-ranged comparison. If you use a throwing dagger in ranged combat it does missile damage instead of piercing.

    If you are talking about the piercing damage of the special arrows, then yes, a difference in resistance between piercing and missile damage matters. Just state which boss you want to chart this for, and that can be accounted for (as the calculator can apply 90% resistance to one and 50% to the other, for example, or whatever combination that boss has).

    8 hours ago, Guest nerd mode on said:

    So, while not questioning the ultimate conclusion, I'd like to point out that the in-game performance difference is far less than one would expect just by looking at the graph.

    What would be the difference, then? What would be different at all? For the generic case why is this incorrect?

  13. Barbarian and Monk get a bit of an increased movement rate. Both start with 2 extra points of movement rate at level 1 compared to other characters. Monk gets the movement improved at some levels (5, 10, 15, etc.) up to 10 more movement rate.

    In terms of implementation, both get the extra movement rate via a #176 (movement modifier 2), which is "As opcode #126, but unaffected by Free Action", according to IESDP. Other items/spells use the 126 one. Makes sense. From a past conversation on effects:

    Quote

    Yeah, this. 126 and 176 are identical AFAIK; it's simply convention that 176 is reserved as the 'unblockable' movement rate opcode. It's like hold via ops 175 and 185--by convention 185 is the 'unblockable' hold, used to freeze your party member in the Hell selfish test or to hold undead.

    The thing is, the Potion of Freedom and the spell, both have other effects besides Free Action (#163). I think the culprit is that there is a "Movement Rate Bonus (126)" setting speed to 100% (I have not tried anything, though). Seems that this effect, in being applied after, resets the speed that was gained via the innate improved speed, even if it's from a different "kind". The potion/spell also set an immunity to 126, so things like re-equipping the boots of speed doesn't work. But you can't re-equip the innate ability...

    I think the proper way to do this would be engine-side: start with the 6 movement rate, apply the 126 effects, then the 176. If the innate abilities just add to the movement rate, then a "plot spell" needs to set it later to 0 for a cutscene, etc., then it would add up properly.

    Otherwise I can't think of a nice way, unless one makes the innate effect reapply via casting it repeatedly each 5-ish seconds, then make the same thing with any "plot" that sets the speed to 0, but make that repeat even more often?

    Another consideration: is the 176 *actually* used for plot reasons? Because if for locking someone in place for plot reasons the 185/Hold 2 effect is the only effect used, the 176 would be free for this innates, then making the repeating effect for the Monk/Barbarian movement could probably overcome the effects of the Free Action items/spells, I think.

    This seems way beyond my knowledge to understand and fix, but I hope someone can give some input on how to tackle this. 🙂

    The Free Action spell (or equivalent effect in items) is infamously known to be changed by some players because it doesn't seem to fit P&P or maybe even its description in some past incarnation. I'm fine with using a tweak mod to change it to what makes sense to me instead of blocking Haste, but Free Action blocking the innate movement seems broken to me. 🙂 Now I hope it isn't as controversial as the Hardiness vs Breach thread. 😄

  14. I don't know if the following is relevant, but mentioning something I've recently experienced, in case it is (and apologies for the noise if it isn't):

    1. Start SoD, and get across the chasm, to face the first battle.
    2. Find Porios, who gives his threatening speech. If Player1 doesn't have the right stats, he goes through state 11/response 40 in the dialog, which triggers Enemy(), so the next battle happens.
    3. Charm Porios during the battle (e.g. Safana's kiss), and attempt to find if he has some BG1-style charmed dialog by force-talking him.
    4. He doesn't, so the charmed state breaks because it triggers Enemy() again. :)

    This is no biggie, but it's certainly not polished. And I have not seen a duplicated journal entry, but the same action that has the Enemy() it also has a AddJournalEntry(). I wonder if this is worth considering, given that I imagine is not easy to fix without going case by case?

  15. On 1/29/2021 at 3:58 PM, subtledoctor said:

    The older functions have one sole advantage over the newer, broader one: I believe they can take negative numbers as arguments. ALTER_EFFECT cannot. 

    FWIW, in case someone finds this thread on a forum search, like I did myself: I don't think that it's the case. The alternative for negative values seems to be DavidW's extended function:

    I know subtledoctor knows, just for the rest that might find the post by chance. :)

  16. For the curious, here are some charts that compare the XP amounts that are needed to start/complete some level combinations. The axis need some love to look better/useful, but I hope is still useful. Indeed, at level 16 it's a lot of total XP.

    image.thumb.png.46cb5d9401bef2a58cfaddfc1ab1b47d.pngimage.thumb.png.0ad33269a442c0ed89180cd0c043df06.png

  17. 32 minutes ago, CamDawg said:

    And I know this will horrify all of the real programmers here, but most of the time limiting scope is not worth the effort.

    If WeiDU doesn't make it easy, certainly not. So far I'm ignoring it as much as I can. I wasn't even going to reply to this, but I just got hurt by this right now... 😅 I was looping over all the weapon proficiency IDs (bastard sword to sling):

    OUTER_FOR (proficiency = bastardSwordProficiencyId; proficiency <= slingProficiencyId; ++proficiency) BEGIN
        OUTER_FOR (value = 1; value <= 3; ++value) BEGIN
            // (...)
            LPF ALTER_EFFECT INT_VAR match_opcode = 233
                parameter1 = %value% parameter2 = %proficiency%
            END
        END
    END

     then below adding an extra block for the club, which is some positions below. So I copied and pasted, adjusting accordingly:

    OUTER_FOR (value = 1; value <= 3; ++value) BEGIN
        // (...)
        LPF ALTER_EFFECT INT_VAR match_opcode = 233
            parameter1 = %value% parameter2 = %proficiency%
        END
    END

    But I accidentally left the use of "proficiency" unchanged, so it picked up the value of the previous loop. This is typically an error in most languages because the introduced variable on the loop would be local to said loop. Here it just runs without errors, but it doesn't do the right thing. So I think I'll have to consider WITH_SCOPE for future use.

  18. Thanks. I kinda keep well the context in which I'm in, but being new to the language, I'm totally missing when the keyword has a prefix, the other, or none at all. Like, for the usual "if" there is ACTION_IF and PATCH_IF, but for the usual "for", there is OUTER_FOR and FOR. That's terrible for my awful memory. So I have a scrap of paper by my side right now... 😄

  19. 7 hours ago, subtledoctor said:

    Oh, sorry, I misunderstood. I was suggesting you simply take my whole function and run it to create like 4 extra proficiency choices for you kit. So instead of getting 4 prof points at level 1 CharGen your kit would get 8. Instead of an 8th level fighter starting SoA with 6 points to spend, they would get 10. Etc.

    But, it's possible to do that, at CharGen? Or you mean at the start of the game via the in-game dialog with an invisible creature?

    The latter method is very nice to do exactly what I wanted initially, balance wise (e.g. give more initial points to a Kensai compared to a Fighter). But I think I'm settling now for the trick of bumping all proficiencies by one. On one hand, because as powerful as it is, it breaks a bit the 4th wall to me (I use the customization component of SCS, and it's great, but thankfully is kinda optional for most NPCs because I'm find with how they are set). On the other, because for the experiment I'm doing, this also seems balanced to me.

    7 hours ago, subtledoctor said:

    I’ve had success increasing proficiencies after CharGen - I give a bonus in Slings to halflings, for example. But I have had lots of trouble setting proficiencies, for the simple reason that different games start at different levels. Say “this warrior begins the game with proficiency in all weapons” and it works great when you test in BG1, but if you start a BG2 or SoD or ToB game the player cannot reproduce what they could have if they had started from BG1 and built up their proficiencies organically.

    The exception is if you set a proficiency to the max value. This works great with weapon styles: you could say “Barbarians begin the game with 2 pips in two-handed style,” and set that proficiency to its max (2 pips) and don’t let players put any pips into it (because they don’t need to).

    This is probably not what you want to hear, but I just want to give fair warning about complications I’ve already run into. If you get this working to your satisfaction then that’s great.

    Thank you for the warning. In some simple tests with leveling up and all, it seems to work. Since I'm setting the proficiency to a certain level (but conditionally to simulate bumping it by one), I might have some luck here. But I'll need to try importing the character through campaigns and all that.

    Thank you everyone again!

×
×
  • Create New...