Jump to content

Magus

Modders
  • Posts

    312
  • Joined

Posts posted by Magus

  1. I'm entertaining an idea to add some preprocessing and/or templating capabilities to MLS/IElib. Looking to gather some feedback before endeavouring.

    Gcc was my first thought, but it's not great with loops, so maybe jinja2 instead (or in addition).

    Some example snippets to get the ball rolling:

    baf

    IF
      See(NearestEnemyOf(Myself))
      Global("abi_dalzim","LOCALS",0)
      LevelGT(LastSeenBy(Myself),15)    // Level 16+
      !GlobalTimerNotExpired("delay","LOCALS")
    THEN
      RESPONSE #100
        SetGlobalTimer("delay","LOCALS",6)
        IncrementGlobal("doomed","LOCALS",1)
        IncrementGlobal("abi_dalzim","LOCALS",1)
        ReallyForceSpell(NearestEnemyOf(Myself),WIZARD_ABI_DALZIMS_HORRID_WILTING)
    END
    
    IF
      See(NearestEnemyOf(Myself))
      Global("efreeti","LOCALS",0)
      LevelGT(LastSeenBy(Myself),15)    // Level 16+
      !GlobalTimerNotExpired("delay","LOCALS")
    THEN
      RESPONSE #100
        SetGlobalTimer("delay","LOCALS",6)
        IncrementGlobal("doomed","LOCALS",1)
        IncrementGlobal("efreeti","LOCALS",1)
        ReallyForceSpell(Myself,WIZARD_SUMMON_EFREET)
    END
    
    IF
      See(NearestEnemyOf(Myself)
      Global("sunfire","LOCALS",0)
      LevelGT(LastSeenBy(Myself),15)    // Level 16+
      !GlobalTimerNotExpired("delay","LOCALS")
    THEN
      RESPONSE #100
        SetGlobalTimer("delay","LOCALS",6)
        IncrementGlobal("doomed","LOCALS",1)
        IncrementGlobal("sunfire","LOCALS",1)
        ReallyForceSpell(NearestEnemyOf(Myself),WIZARD_SUN_FIRE)
    END
     

    gcc equivalent

    #define HASH1 # // special character shenanigans
    #define HASH2(x) x
    #define cast_spell_level(SYMBOL, TARGET, SPELL_VAR, MIN_LEVEL) \
      IF \
        See(NearestEnemyOf(Myself)) \
        Global(#SPELL_VAR,"LOCALS",0) \
        LevelGT(LastSeenBy(Myself),MIN_LEVEL) \
        !GlobalTimerNotExpired("delay","LOCALS") \
      THEN \
        RESPONSE HASH2(HASH1)100 \
          SetGlobalTimer("delay","LOCALS",6) \
          IncrementGlobal("doomed","LOCALS",1) \
          IncrementGlobal(#SPELL_VAR,"LOCALS",1) \
          ReallyForceSpell(SYMBOL, TARGET) \
      END
    
    cast_spell_level(WIZARD_ABI_DALZIMS_HORRID_WILTING, NearestEnemyOf(Myself), abi_dalzim, 15)
    cast_spell_level(WIZARD_SUMMON_EFREET, Myself, efreeti, 15)
    cast_spell_level(WIZARD_SUN_FIRE, Myself, sunfire, 15)

    jinja2

    {% for item in data.battle_spells %} // list defined elsewhere
    IF
      See(NearestEnemyOf(Myself))
      Global("{{ item.var }}","LOCALS",0)
      LevelGT(LastSeenBy(Myself),{{ item.min_level }})
      !GlobalTimerNotExpired("delay","LOCALS")
    THEN
      RESPONSE #100
        SetGlobalTimer("delay","LOCALS",6)
        IncrementGlobal("doomed","LOCALS",1)
        IncrementGlobal("{{ item.var }}","LOCALS",1)
        ReallyForceSpell(NearestEnemyOf(Myself), {{ item.symbol }})
    END
    {% endfor %}

    Of course, complex baf is already dominated by SSL, so this is mostly useful in less complex scripts.

    But on the other hand, the applications are not limited to baf.

    // never again confuse "GLOBAL" and "LOCALS" types
    #define LocalGT(x,y) GlobalGT(x, "LOCALS", y)
    IF
      LocalGT("my_var", value)
      ...
    
    
    // just because I'm tired of typing COPY_EXISING_REGEXP all the time
    #define copy_er COPY_EXISING_REGEXP
    copy_er GLOB ~*.itm~ ~override~
    
    
    // or take it further
    #include header.h
    // header.h:
    #define POUND1 $ // more shenanigans
    #define POUND2(x,y) x ## y
    #define POUND3(x,y) POUND2(x,y)
    #define POUND_APPEND(x) POUND3(x,POUND1)
    #define copy_erg(FILE_EXT) COPY_EXISTING_REGEXP GLOB ~^.+\.POUND_APPEND(FILE_EXT)~ ~override~
    // actual code
    copy_erg(dlg)
      DECOMPILE_AND_PATCH BEGIN x = 0 END
    BUT_ONLY
    
    
    // this is too long...
    IF ~~ study1
      SAY @14 
      IF ~OR(2) Global("wm_book_spell","LOCALS",0) Global("wm_book_spell","LOCALS",1)~ REPLY @20 GOTO 00   // -> +6 = 6/7
      IF ~OR(2) Global("wm_book_spell","LOCALS",0) Global("wm_book_spell","LOCALS",6)~ REPLY @22 GOTO 02   // -> +1 = 1/7
      IF ~OR(2) Global("wm_book_spell","LOCALS",7) Global("wm_book_spell","LOCALS",8)~ REPLY @23 GOTO 03   // -> +2 = 9/10
      IF ~OR(2) Global("wm_book_spell","LOCALS",7) Global("wm_book_spell","LOCALS",9)~ REPLY @24 GOTO 04   // -> +1 = 8/10
    // how about this
    #define if_node(value1, value2, tra, goto) \
      IF ~OR(2) Global("wm_book_spell","LOCALS",value1) Global("wm_book_spell","LOCALS",value2)~ REPLY tra GOTO goto
    IF ~~ study1
      SAY @14
      if_node(0,1,@20,00)
      if_node(0,6,@22,02)
      if_node(7,8,@23,03)
      if_node(7,9,@20,04)

    Technically, all this already can be done manually. But with some glue code in various places it could be automated similarly to how SSL works.

     

    Edit: no one, really? OK, I guess I'll just do my own thing, as always.

  2. This is from v30, but I guess it's the same in the latest.

    So in confrontation with Kaishas I made a foolish choice to focus the adds first. Turned out, reinforcements arrived faster than I could kill them. By the time I realized I really needed to kill Kaishas first, I was already pretty depleted, and stood no chance. Since I played Ironman, I resorted to Invisibility+retreat to previous area. The area was already crowded to the point it was hard to even walk to the exit. All party members died (except Imoen... in a cheap attempt to save her, I dismissed her from the party), but I managed to salvage some useful equipment.

    At this point, I've pretty much given up on this run, but show has to go on, right? In the previous area, I rested, prepared every area damage spell, and every scrupulously saved fire potion, wand, etc. And pre-buffed to the max. I knew I had only one shot, because supplies were limited and there was no way to take them all down with just spells.

    Upon entering the area, it was entirely covered in werewolves, I couldn't walk a single step. New ones continued spawning but they couldn't move too, stuck in the initial spot. I made a screenshot, but can't find it now. It looked extremely overwhelming.

    And I unleashed hell on them (well, to the extent a lvl 10 mage can). After a series of heavy, but carefully placed bombardments (Imoen was still there, and if I attacked her, she'd turn on me, and I'd have no chance to get her back into party) I was able to get to Kaishas and bring her down, then finish off the remaining enemies, while even still packing some firepower.

    While this was definitely interesting, and one of the moments that you play Ironman for, I'm reasonably sure that's not exactly intended behaviour.

    Gathered the rest of the items, invited Imoen back, ressed the rest of the party on the mainland.

    In the end, I got 2 levels from this fight alone.

  3. 34 minutes ago, Nathan82 said:

    I was starting to wonder if that was the cause, I've found quite a lot of enemies with numerous suits of armour etc, I thought it was supposed to do the opposite but might be wrong.

    The corresponding component (overhauler or unborker, don't remember) is really described misleadingly and shouldn't be used in common installations.

    34 minutes ago, Nathan82 said:

    I've attached it, thanks

    I thought it might be less autosaves, but you don't have it installed... so my money is on SCS.

    (I remember once seeing messages from Lamalha assassin group in Durlag's Tower. And another time actually meeting them in Copper Coronet).

  4. On 5/29/2021 at 7:13 AM, Nathan82 said:

    And finally the Bishops in the Chess battle seem to have duplicate items, equipped and in inventory. I ran achangelog on BGBISHOP.CRE, copied the extra .cre files to the override so i could look at them in NearInfinity but i cant work out whats causing them to duplicate.

    Pretty sure it's lolfixer, it does a lot of stuff like that.

    8 hours ago, Nathan82 said:

    Anyway, the fix was to use DLTCEP - Extract from Bif

    I think you can decompress biffs to the same effect.

    On 5/29/2021 at 7:13 AM, Nathan82 said:

    I searched the whole level with true seeing, couldnt find him anywhere. Spawned another one via the console and same thing happened. So i spawned the wardstone and went to level 2 and there they both were.

    What's your current weidu.log?

  5. I think installation/uninstallation are fine in weidu. There's really no much leeway in how to do it, given how IE works and the need to support a plethora of mods.

    Translation is ok too. One way or another, it's going to be a bunch of files with numbered strings.

    We already have an API to edit any files programmatically, it's iesh. The problem is making it compatilbe with weidu mods.

    (And pretty sure there's no need to worry about GUI at the start.)

  6. 13 hours ago, grodrigues said:
    
    
    
    for p in Path(".").glob("*.itm"):
        if p.is_file():
            with Item.patch(p) as f:
                if f.type == itemtypes.longsword:
                    f.min_strength = 10

     

    For each Python snippet I will match and raise you a Weidu one.

    COPY_EXISTING_REGEXP GLOB ~*.itm~ ~override~
      LPF GET_ITEM_TYPE RET type
      PATCH_IF type == ITM_TYPE_LONGSWORD
      LPF ALTER_ITEM_REQS INT_VAR min_str=10

    You have to write the underlying code in both cases. So this argument is null and void.

    The real advantage of a general purpose language is that it's... general purpose. It has much larger community, better docs, more features, isn't dependent on 1-2 mantainers.

    And, it's actually a useful skill to have. While weidu is hardly applicable anywhere else.

    12 hours ago, CamDawg said:

    Sure, and the same could be said for C/C#/C++, Java, Perl*, hell, even OCaml, etc. It's the formal programming structures and libraries (that WeiDU can kinda, sorta do) that we're longing for.

    Not really. A C++ lib would only be developed by a chosen few. Learning curve is far too steep. Python, on the other hand, is widely regarded as one of the best choices for beginners, and since most modders are, and will be on that level, this makes it a very good choice if you want the ecosystem to grow naturally (modders developing their own functions and modules as needed).

    10 hours ago, Ardanis said:

    WeiDU syntax certainly has its share of issues, the LONG_NAMES_IN_CAPS eyesore being one of my pet peeves since ever, but lack of ability to handle your data on abstract level is not one of those.

    Oh, that one you can easily enough work around with a preprocessor. I entertained some thoughts on that, but nothing concrete yet.

    18 hours ago, Taylan said:

    so I'll be off to creating a proof-of-concept Python library and sound set package installer then, wish me luck. 😛

    A "soundset installer" is useless. The only thing that can have a future is a weidu installation/uninstallation/rollback compatible generic installer. If I had to guess, I'd say a week or two should be enough to put together a PoC (assuming that you start with iesh). So, ball's in your court. I'll be watching this with interest.

  7. As @subtledoctor said, you'd need to make the tool backwards compatible with WeiDU. (Not necessarily re-implementing TP2, but at least installation/uninstallation routines).

    We briefly discussed this with @AL|EN a year or two ago. In general, I would say it's possible. However, if your only goal is to package soundsets, it's 100% not worth it. Just bite the bullet and learn WeiDU (and just look for ready functions, most any idea has already been implemented in one form or another).

    But if you're really serious about development, and have time to spare, the place to start with is iesh.

  8. They are triggered by the engine, I believe. Just like BG1-style interactions. You can press the hotkey to advance game time (don't remember which one it is) and see them happen.

    I'm not sure how the system chooses between what to trigger, banter vs interaction. Maybe interactions start flowing after all banters are exhausted between the interacting characters. Maybe it's random.

  9. Imoen was originally intended to die in Spellhold.

    Interact.2da is not for banters, it's for BG1-style in-game interactions. Take a look here.

    On 4/3/2021 at 2:05 AM, jastey said:

    I think it enabled those compliment/insult comments for BG1?


    They work in original BG1 and BGT too. Some mods extend them, though.

  10. 19 hours ago, Bartimaeus said:

    TnT...seems to be your mod? I see we've had a number of similar ideas, including Slayer form, True Sight, and Otiluke's. Does that Project Image tweak work for non-EE games? I would imagine not, but just making sure. I also feel like your statement about it accurately captures how I feel about many exploits: "To clarify, the purpose of this component is to give a normally working spell to the players who don't want to cheese in the first place. The purpose is not to close every possible PI exploit." Especially because I was about to ask you about your Otiluke's tweak and how you would prevent the Otiluked character from, say, casting Fireball at themselves over and over in the middle of a battle...but presumably you haven't done anything to prevent it and are simply trusting that the player won't do so since it's clearly a lame exploit.

    It is mine, and it works on Classic (in fact, I only use Classic for testing).

    I didn't do anything about Otiluke + Fireball, because I didn't think of it. Not sure if something can be done, and doesn't worry me much, too. Although, if a way is found, and it's not too convoluted - everything is possible. Github issues are open for suggestions.

  11. 9 hours ago, subtledoctor said:

    There’s something to be said for learning what’s going on under the hood...

    Point taken. However, learning is one thing, and production usage is another.

    The issue is that magic numbers are in some top 10 of bad programming practices, and generally should be avoided. The reasons why are explained numerous times by experienced programmers, easily googled with "why magic numbers are bad", or "code smell magic numbers".

    And yes, you can add comments to clarify the mumbo-jumbo. But they do not work as well as defined constants.

    For example, the code can be changed to

    OPCODE_hp_damage = 12
    DAMAGETYPE_electricity = 262144  // (0 + (1 << 4))  (0 + (1 << 16))
    LPF ALTER_EFFECT
      INT_VAR
        match_opcode = OPCODE_hp_damage
        parameter2 = DAMAGETYPE_electricity

    This is what "for the love of God" refers to. It is not hyperbolic at all.

     

    Unrelated to the main issue:

    1. Of course, with time you tire of defining and looking at the constants over and over again. The exact numbers are not useful for the context. So you tuck them away into an include. And then you want to use the same include in another mod. So a library is born.
      I do not mean at all that you should use IElib specifically. By all means, build your own or use another one. Just remember, every time when a programmer uses a magic number, God kills a kitten. (Although I do think that combining efforts is more efficient.)
    2. 10 hours ago, subtledoctor said:

      I won't even get into the fact that, as a VSCode extension, I assume this is OS-dependent and thus useless to people with a Mac or Linux.

      - I'm not sure why do you assume that. As far as I can tell, on the contrary, VSCode is the cross-platform code editor.
      - The extension and the library are two separate things. They are integrated, but can be used independently.

    3. 10 hours ago, subtledoctor said:

      I don't know that it's that much easier to remember "DAMAGE_TYPE_lightning" versus "(4 << 16)." And what if you want a %-change in damage, instead of a set number? That variable does not address that.

      Whoops, I mean "DAMAGETYPE_lightning."

      Is it easier to remember 0x248 versus SCRIPT_OVERRIDE?
      Well, to each his own, of course. However, the goal is not having to remember, and focus on logic instead of offsets and bit fields:449426095_Capturadepantallade2021-02-0708-50-43.thumb.png.bfc5aaba79dca80bfa2313135d0ab880.png
       

  12. On 1/24/2021 at 8:29 PM, Greenhorn said:

    Component "Potion of Really Mirrored Eyes: v8.4"  from TNT mod cause CTD in my BG:TotSC vanilla game when used. From my humble experience CTD on one version of the game is usually indicative of problem encountered on all of them so maybe it wouldn't be bad idea to check and fix this ( for all versions ). 

    I'm actually suprised it even installs on it. I didn't test on classic ToSC. Submit an issue on github, with steps to reproduce.

    On 2/2/2021 at 4:04 AM, subtledoctor said:

    I really want to know how you managed to get Project Image to use the caster's memorized spells...

    In the best traditions of IE modding: with horrible hacks. Code is on github, so...

  13. 48 minutes ago, Taylan said:

    Say, creating a new item called "Hello World" (could be a copy of another item, like a gem or something) and dropping it in the inventory of the character upon starting a new game. Or creating a creature which appears aside you when you start the game, and says "Hello World" when you talk to it... You get the idea.

    You can do this with NearInfinity, DLTCEP or Weidu.

    If you want a quick, one-off in-game change, NI/DLTCEP will do fine (edit the file, drop into override dir). Weidu is the heavy machinery for creating mods that you actually want to distribute to other people. (But you still use NI/DLTCEP a lot while creating a mod, even it's weidu-packaged).

    Scripting languages themselves are simple and shouldn't pose a problem for an exprienced developer to get the hang of. Mostly the challenge lies in learning how Infinity Engine works, how the things are connected, and various tricks and quirks.

    And the most often given advice it to look at other mods to learn.

    48 minutes ago, Taylan said:

    I think it would be great if there was a little guide/tutorial like "making your first mod" which lists you the tools you'll need and walks you through the steps to create some basic "Hello World" kind of mod.

    Well, it's in your hands. Once you figured out a thing or two, feel free to create one.

  14. Cool, I did something similar with Otiluke, only handled it a bit differently.

    One tweak that I never find time to implement but still badly want is to be able to cut through Cromwell's chatter and just get straight to the point, selecting the item to be created directly or through some menu. His rummaging through inventory is mildly annoying in the original, but once you get some item upgrade mods, it's a never-ending click fest...

  15. Huh, I don't see what's even talk about then.

    The MVP is to just implement downloading the new iemod packages and that's it. It'll ensure that the update is atomic and all users receive the same files without any confusion.

    Then you could set up some topic with voting on desired features and see the users really do need the extra features, and which ones (deltas, pre-release, etc).

    Me personally, I don't care much about extra 200Mbs. And large mods aren't released that often, anyway.

×
×
  • Create New...