Jump to content

Ardanis

Modders
  • Posts

    2,793
  • Joined

  • Last visited

Posts posted by Ardanis

  1. Actually, I now definitely remember you've been reading stats.ids as array (?) and then using 1-200 range to append a blank file. That is, completely destroying any 200+ stat added for ToBEx :D

    // Detectable Spells v3.1
    //
    // Assembled by Ardanis/GeN1e, using DavidW's version (SCS) as a base
    //
    // Changes from previous version (SCS):
    // - if Khelben's Warding Whip is broken, we first will attempt to repair it
    // - removing older Ascension version of DS is less destructive
    // - patching STATS.IDS is compatible with ToBEx

     

  2. As far as IDS files are concerned, the order of entries is irrelevant. Unlike 2DAs, they exist purely for user's convenience when compiling scripts, and might as well have been empty.
    I'm pretty sure the sorting algorithm was first introduced by David when he updated DS to meet SCS' demands about ten years ago. That version still had inherited some compatibility issues, which I needed to resolve for SR+SCS installations and which brought me to update DS to v3.
    While I suspect SCS' version didn't actually *need* readability of stats.ids, with the advent of ToBEx and its 200+ extended stats there came a potential problem of multiple ToBEx mods adding their own custom stats with possible conflicts. Since maintaining yet another community list of things hardly seemed like a good choice, I wrote a function to dynamically add new stat entries into the first unoccupied slot - much like ADD_SPELL works nowadays, - and for that purpose sorting entries beforehand was actually useful. Though I'm pretty sure one could do with unsorted mess as well, it just seemed extra work when the file was already being sorted even before I jumped in for maintenance.

     

     

     


    In my defense:

    1) I did end up giving such credit at the end of the post.

    2) Some tables (EDIT - 2da tables at any rate) have index numbers and others don't and instead rely on the row #; which ones and why are not obvious to a casual observer.

    3) At the time DS was written, the engine did not contain any effects that reference STATS.IDS indices; opcodes 318, 324, and 326 were added in EE v1.4. It is entirely reasonable to think the writers of that DS function did not take into account an issue that would only manifest 10 years later.

    318, 324 and 326 only reference either a row in SPLPROT.2DA, or an index in specified IDS. The former does depend on the order of rows, the latter doesn't.
  3.  

    ...aaand that's what I get for trying to rush an update in a 2-minute window.

     

    Should be okay now (and yes, it's just a matter of copying iwdspells_divine to the right folder).

    Well shit. This time it's a different error. This one is more opaque to me, but it looks like a counter is going out of bounds in the hidespl.2da, in addition to being copied into override loaded into memory a few hundred times prior to the error. .DEBUG

    [override/hidespl.2da] loaded, 7171 bytes
    Copying and patching 1 file ...
    Copied [book03.itm] to [override/dw#allsp.itm]
    Copying and patching 1 file ...
    [./override/stats.ids] loaded, 4606 bytes
    ERROR: cannot convert ind or %ind% to an integer
    ERROR: [stats.ids] -> [override] Patching Failed (COPY) (Not_found)
    Stopping installation because of error.
    
    edit: totally understand if you can't get to it tonight, but if there's a file modification or two you'd like me to try, I've got a few more runs of this script left in me tonight.

     

    Looks to be happening at stratagems/initial/initial.tpa, line 78:

    END ELSE BEGIN
      
                LAF ds_resolve_stat INT_VAR index=109 STR_VAR id=~WEAPON_ENCHANTMENT~ END // since we use this occasionally even in BG1 scripts, we need it in stats.ids
    
       END

    Best wild guess I have is that something went wrong with stats.ids file, that its entries can't be properly read (the ds_resolve_stat function assumes the rows in the file consist of integer (stat number) followed by string (stat name).

     

    If you have some time for debugging, can you add this line

    COPY_EXISTING + stats.ids debug_stats.ids

    just before where it throws an error, like this:

    END ELSE BEGIN
     COPY_EXISTING + stats.ids debug_stats.ids
                LAF ds_resolve_stat INT_VAR index=109 STR_VAR id=~WEAPON_ENCHANTMENT~ END // since we use this occasionally even in BG1 scripts, we need it in stats.ids
    
       END

    then run it again and upload somewhere the debug_stats.ids file it will create in the main game directory?

     

    This won't solve the issue, but since neither David nor I have an idea what's happening, it may be a step towards discovering the cause.

  4. Sounds like a definite improvement over the old all-or-nothing prebuffing routine (thumbup)

     

    On that note, rather than duration you could try segregating buffs by their type instead. In SoD I grouped them like this:

    1) Buffs against physical attacks, further split into:

    - Decremental defenses (Stoneskin, Mirror Image)

    - Immunity to weapons (Protection from Weapons/Missiles, Physical Mirror)

    2) Buffs against spells, split into:

    - Immunity to spells by level (Spell Turning, Globe of Invulnerability)

    - Invisibility - not really an anti-magic defense with SCS+SR, but nevertheless so in SoD

    3) Partial protections (Pro Evil, Fire Shield, Armor of Faith, Blur, Spirit Armor) and combat enhancements (DUHM, Blade Barrier, again Fire Shield).

     

    On Normal difficulty AI would randomly select a subgroup for both anti-attack and anti-magic protections and cast the strongest buff it has available there. If the wizard had no spells in selected subgroup at all, there'd be no buffing in that category. This effectively reduces the amount of buffing by 50%.

    On Core there'd be no random rolling, and the strongest buff from each subgroup would be precast. In addition, any extra buff from the third group would also be applied.

     

    For high-level BG2 caster with access to wider array of spells the grouping can be further refined and extended across difficulty levels (the SoD buffing routine was mostly for low to mid levels, and I readily admit I was too lazy to spread it across more than three difficulty levels).

  5. When I played some years ago BGT with SCS, Revisions and UB, I ended up finishing BG1 with nearly 400k XP, and I hardly noticed any difference during first steps into BG2 with my previous BG2 SCS playthroughs. This in fact was the main argument during SoD development to not worry much about importing 500k characters into BG2EE, as the difference would be negligible.

    So, for just 500k I wouldn't bother much either, but I thought EET wasn't forcing any XP caps? So it'd be actually about 700k, even without any quest mods.


    It sounds like the power gap if you just import from SoD is more like 1-2 levels? I might look at that, but it’s not too drastic and I’m not sure a gentle introduction to SCS is such a bad idea anyway!

    Pretty sure it should only be an option for trilogy installation, not an introduction for a new BG2EE playthrough :) And a transition from the brutality of insane SoD into gentle early stage of BG2 SCS :p as what I suggested for adjustments would be more appropriate for an SoD dungeon on normal/core.

  6.  

     


    Wait 500K XP vs. 161K XP is not really 3 extra levels is it?? I thought like 1 or 2.
    Also I thought Beamdog wasgoing to address this?

    I was assuming EET playthrough, i.e. without XP caps. So, you'd have about 300k-400k from uncapped BG1, and as much from SoD. Compared to BG2's starting 89k, that's about three extra levels.
  7. About 300k XP per party member if you don't grind too much. No stat boosts.
    With about 250k extra from BG1 part (assuming we're talking about EET here), that would be starting BG2 at about +3 levels compared to vanilla.

     

    PS Also no level 6 wizard spells in SoD for party to find, unless I'm forgetting things.

  8. I think this would more or less suffice:

    1) Replace lesser golems with normal versions

    2) Add a bunch of various slimes to the Otyugh room

    3) Replace mephits in the plane of air with air elementals (normal and greater)

    4) Replace some goblins with aerial servants and/or invisible stalkers (instead of duergars)

    5) Add a couple fighters and a mage to each vanilla duergar encounter

    6) Add a couple levels to enemy thieves

    7) Increase number/frequency of mephits spawning from the portals

     

    Cambion, vampire and doppleganger are probably ok.

  9. Enemy numbers, mostly no: I've mostly implemented difficulty sliding in the AI part of SCS, not the tactical-challenge part, and there's not much scope there. But it shows up in a couple of places: most importantly, random spawns are tied to the slider.

    I suppose it does have more to do with individual encounter design, i.e. a lot more hand-craft work compared to general AI, but since you already have the tactical challenges group of components I would still encourage you to give it a shot. Judging by the insane playthroughs posted on Beamdog forum, particularly Temple of Cyric, Coalition Camp and Dragonspear Basement, the extra numbers were about as fine a challenge as insane-specific AI, and a good change of pace too.

  10.  

    The ONLY thing I don't love about this is that it sounds like it adds an unremovable icon to the innate abilities bar, which already has a tendency to fill up with a lot of stuff.

    - Click on the icon

    - Select "Remove the difficulty control from my Special Abilities."

    - Control the difficulty either by 'C:CreateCreature("dw#diffi")' or directly through the difficulty variables.

     

    (I find objects more immersion-breaking than special abilities.)

     

    You can also bind it to hotkey. This is from Player1's SoD script:

    IF
      HotKey(B)
      OR(2)
         INI("QAMODE",1)
         Global("BD_QAMODE","global",1)
    THEN
      RESPONSE #100
        ActionOverride(Player1,StartDialogOverride("bddebug",Myself))
    END

    It does require a script assigned to Player1, though it may or may not be possible to TriggerOverride(Player1,HotKey(X)) from baldur.bcs.

  11. Sounds a lot like how difficulty is treated in SoD - very limited spell/item/ability usage on easy, partial prebuffing and more spells on normal, full prebuffing and all spells including Fireballs on core, with some select per-encounter improvements on hard and insane.

     

    Also, SoD makes extensive use of difficulty slider to control the number of enemies you encounter, e.g. more grunts on core and an extra mage on insane, and finally allows AI to target AoE damage without hitting its allies. Are these things making their way into v32?

  12. The most intelligent AI doesn't necessarily equal to most enjoyable to play against. While a designer may see it as a challenge to write the best AI possible, the player experience may dictate otherwise.

     

    If you play as a dwarven defender, then chances are you're doing so to take advantage of his tanking ability. Except it ends up completely wasted if AI just starts targeting other characters, so you might as well have taken a kensai instead.

     

    Best solution that I'm aware of - randomize targets, so that if you have half party members e.g. protected from charm, then half the casts of it will be unsuccessful. This is the math at its simplest. And you don't need lengthy triggers for this to work either.

  13. Regarding teleport, I had similar dilemma with neothelid, which I solved by having it sense the entire area via ESP and ignore people protected by Sanctuary and Chaotic Commands.

     

    While liches don't have innate ESP, they still could be presumed to possess divination powers, which are blocked by Non-Detection, SI:DIvination, Sanctuary and whatever else might there be.

  14. Is this a known thing or am I doing something wrong?

     

    Yes, some of SoD's romance triggers have visibility issues.

    Dynamic objects like [PC] or [GOODCUTOFF] require them to be within script owner's direct line of sight to return true. With doors and ground triggers the script's coordinates are at the center of bounding box, so with very large triggers or obstacles over them it's possible for script to not see the entire trigger's area. Or for a door to be blind on its southern side.

     

    Use static objects, like PlayerX or death variable name. If you need it to be any friendly creature, however, then it might get complicated, because as David says you do need a wildcard to match them. I could suggest to split the trigger into few smaller ones, sharing the script. It might be possible to activate both parts of it simultaneously, so to avoid duplication you may need to move the desired action into area script and have the trigger only set the activation variable.

  15. I may have mentioned it sometime ago, but - shouldn't BWS just make a guide about what tp2 input it can process, and then modders who wish to be part of BWS framework will take steps to ensure their code is compliant with its guidelines? I.e. why not just blacklist by default the mods that use of READLN? If their authors are actively interested in participation in BWS project, they can e.g. use some IS_BWS flag to toggle READLN on/off.

  16.  

     

    Most of my ALWAYS block is wrapped in
    Ah, I see. Point taken.
    Well, of course I agree that this is as much aesthetics and taste as anything else.

    That said, if *everything* you do is call functions, there can't be anything left to slip into the next component. (It's not quite true that everything I do is call functions, because my ALWAYS block defines a bunch of variables, but it's relatively easy to keep track of those, and in any case they don't get changed from component to component.)

     

    I meant it more like - if system's stability depends on plugging ten same holes in different places, then you should assume you'll miss some, or may forget to plug new ones when adding new stuff. Learned it hard way during SoD :D

  17.  

    For Encapsulation: Why not put CLEAR_EVERYTHING as the first line in ALWAYS? Any disdavantages?

    Yes. It means you can't read in data in your ALWAYS that's to be used in any component.

     

    Example: SCS's ALWAYS block goes through every spell in the game and sets a variable with name equal to its ids reference, value equal to its spell file. It also goes through and finds a scroll for each wizad spell, and records that as the value of a variable. It takes 2-5 seconds and I'd rather not have those 2-5 seconds every component.

     

    At a more conceptual level, I'd like my encapsulation to be built in to the way the code is structured, not forced explicitly. One of the main points of FUNCTIONs is to deliver this; why not use it? Put another way: why not avoid defining variables with global scope in the first place unless you want them to have global scope, rather than just clearing out the global scope on a regular basis?

     

    I thought ALWAYS is supposed to run always, i.e. you'll spend 2-5 seconds re-reading data regardless of how you clean up the environment.

     

    And while I agree that wrapping the component code is a good habit to have, if you absolutely want to prevent rogue variables slipping into the next component, then always clearing everything *is* how you structure the code to eliminate the human error factor - with a single switch you ensure nothing will slip through even if you forgot to properly encapsulate a component or two - just like you used to forget cleaning up the backup folder.

     

    1) Is immutability really all that huge a concern?

    It's more like something to be aware of, than a real issue. Unless you do a great lot of stuff in multiple places inside your folder, or forget things easily.

     

    2) My (admittedly less-than-perfect) understanding of Weidu functions is that they are really designed and meant to be used for allowing input options and variable-determined output. Not as mere wrappers for a bunch of normal Weidu code. For the latter, I have been using macros, and then I "LAM" the component in my .tp2 file.

    The idea was to control the input and output, using only what you want and removing anything else. It's perfectly normal to have no input/output whatsoever, especially if the code can be used across multiple mods/components (look at DS for example).

     

    Note that unless it was changed in recent years, functions still accept external input that wasn't forcefully set in function definition.

    DEFINE_ACTION_FUNCTION print
      INT_VAR a=1 b=2 BEGIN
        PRINT ~a=%a%, b=%b%, c=%c%~
    END
    OUTER_SET a=10
    OUTER_SET c=30 // you don't really want this to slip inside, but unless I'm mistaken it still does
    LAF print INT_VAR b=200 END // will print ~a=1, b=200, c=30~

    - Do macros similarly clear variables and arrays etc.?

    No.

     

    - Can we really just drop a bunch of commands into a function and call it a day? I don't have a specific instance at hand, but I definitely remember trying to use DEFINE_ACTION_FUNCTION in that way about a year ago, and Weidu gave me parse errors until I gave up and just called it a macro.

    Yes, you need to define it the same way you define macros. The only difference are the optional INT_VAR, STR_VAR etc.
×
×
  • Create New...