Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - MaxMahem

Pages: [1] 2 3 4
1
Brutal AI / Re: [SOURCEMOD] Brutal-OXCE 5.0.6
« on: May 11, 2023, 03:17:56 am »
You might implement randomness to help combat various ways the AI can be "cheesed." If the AI's behavior is entirely deterministic, then it can be possible to predict its behavior in advance and exploit that. By adding a random factor to the AI's behavior, you can help prevent that.

2
I know I'm a broken record about this, but might be another place where a script enables custom logic. I don't think `Country` is currently very wired up for scripting, but it's not a complex object so it seems like doing so would be straightforward. The hook here could be very simple, when `newMonth` is called, at the very end, a `CountryNewMonth` hook is called, passing in the country, funding calculated by the current method, xcom score, alien score, and the average funding. The hook would pass out an adjusted funding amount. Which, if set by the default script, would simply be the amount passed in.

Country could be immutable or mutable for this, though I think having it be partially mutable here would make sense, letting things like pacts formation be controlled by custom scripting logic in this hook as well.

I'm up for taking a crack at this as well, in part because I'd like to look into how objects are wired up for scripting.

3
OXCE Suggestions OK / Re: Option for alien morale loses based on rank
« on: April 24, 2023, 03:12:54 pm »
Maybe best handled as a script hook? So arbitrary transformations could be performed. Something like, "OnAliedUnitDeath" or even "OnDeath." Which is called for every unit on the battlefield when a unit is killed.

Looking through BattlescapeGame::checkForCasualties, where most of this logic happens, a lot is happening here (and this method might be better broken up into smaller methods). But a script hook could be dropped around line 817 after most of the statistic work has been done, and the C++ code has determined who is dying and who the murderer might be.

Currently, there are two branches here, one to give the possible murderer a moral adjustment and one that iterates through all units and applies a moral adjustment to those units. But for purposes of a script, they could be unified into one hook since the possible murderer would be included in the set of all units anyways. I'm thinking the hook would look something like...

`OnDeath(const SaveBattleGame save, BattleUnit unit, int murderId, int victimFaction, const BattleUnit victim)`

The current logic could be transformed into a default script, or the hook could return a bool or some other object indicating whether the default logic should be run for this unit or not. This would allow both the current logic to be overridden and for arbitrary transformations to be done beyond just moral losses following a fixed formula.

I don't know how far you are in to doing this, but I'd be up for taking a crack at this if you like.

4
Just one more thing I had to add...

5
So I got distracted for a bit, but I'm on the homestrech now. I've developed things into a state where it is very easy to add custom drawing to any sprite is very simple (it's basically one/two lines. One to instance the `SpriteOverlay` class and one to call the `draw` method. Adding more scripting hooks is straightforward, but quite a few more lines in `ModScript`. But that's what it's there for no? The long and short of it is it now possible to add "Overlay" drawing scripts to arbitrary parts of the code with minimal disruption.

This leads me to my question to get some feedback on. Where would more hooks be desirable? Currently, I have implemented 4 hooks, as proof of concept.
  • handSpriteOverlay - called in the context of "hand-sized" slots, that are used in a few places, most obviously the hand slots on the inventory and battlescape, but a few other places as well. The scripts expose an object, `spriteInventoryContext` that can be used to distinguish the context and optionally turn off the rendering of default effects.
    Some examples of using that feature:

    Default health display is disabled and color coded on is added. Of trivial use for this but also...

    Overriding the default display also lets items that only have one type of charge, display only that charge.


    Overriding the default ammo display to color code the ammo by its damage type. Also the ammo count is shown in the inventory screen for both weapons and ammo clips.
  • inventorySpriteOverlay - called (almost) everywhere a bigobj inventory sprite is called, minus the ufopedia for now. The same `spriteInventoryContext` object exists to determine which context and to disable default effects (like the grenade primed indicator).
  • unitPaperdollOverlay - called in the context of the drawing of the paperdoll. This one is new.
    And I'm no artist, but there is a lot of capability here. Just a demo example:

    I'm on fire!

    30 wounds jeeze...

    This one is not animated, as I didn't put the hook in a location that gets called every frame. It could be though.
  • unitRankOverlay - drawn in the context of the unit rank. I did this one on a lark for a fun effect SupSuper suggested...


    This one *is* animated as the hook is put in a location that gets drawn every frame.
I did originally intend to add the capability to the rendering of battlescape sprites, and that's still on the table. However, as the code around here is somewhat more complex, I plan on punting on this till a later patch (hopefully, it should still be straightforward, but you know "it should be easy" is famous last words.)

Anyways, what I'd like to collect some feedback on is, two things:
  • What are opinions on multiple hooks, vs reusing the same hook. The first two hooks illustrate the potential problem. Scripts likely want to act differently depending upon the context in which they are drawn. For example, overlays in OXCE are drawn differently depending on the items location. Fatal wounds indicator on a corpse is only drawn when it is on the ground, and not when the item is in the hand or backpack (this is a default that could easily be changed at this point, but I didn't get real clear feedback on this point.)

    What I have done in this case is expose the aforementioned Context object that contains information on the context of where the script is being called, and provides a way to activate and deactivate default effects. This can be done for other scripts (and in fact is done). But having to examine these sorts of objects to decide if you want your scripting logic to execute at runtime is fairly cumbersome and should be avoided. But, OTOH, having a whole tone of script hooks probably isn't desirable either. So there is a balance to be found.

    The line I've tried to draw is "am I likely to ever want to run this set of logic in any other context?" For example, when drawing an overlay on an inventory sprite there are at least some cases where you want to draw the overlay in multiple and/or all the contexts an item is in. The grenade and high-explosive scripts are examples of them. OTOH, the "color ammo counter" overlay I did is useful in limited contexts (when the weapon is in hand). Thus I split the script into to hooks for these two cases.

    But I'm interested in other general feelings on the subject from others. It's not always clear to me when I should implement different hooks, vs when I should just provide a scripting context.
  • On the discord I got some somewhat confusing feedback about the desriability to render an overlay on each individual layer of a layered paperdoll. This is as easy to do as any other overlay at this point, but I didn't do it this way because I didn't see much point to such a capability. But I can add it if it is desirable. (The performance cost will not be great as the layers are only rendered once per inventory screen load).
  • What ptr's are desirable in these given context? To an extent this is kind of a pointless question as given the `BattleItem` or `Unit` ptr, most other desired ptrs can be obtained. But putting them in the script defaults makes things easier I think. Right now I've defaulted to the `BattleItem` and the `RuleItem` being present. But I'm open to other suggestions.
  • Beyond Battlescape unit/item sprites (which I am punting on for now). Is there any other battlescape sprites that would be desirable to get wired up in this initial patch? At this point, the process of doing it is easy and non-intrusive.

6
@MaxMahem one thing to consider if you blit new surface, I think it could be beneficial if it have option of item recolor too (reuse current item scripts hooks)
As if you would allow some items graphic into multiple parts, it would be beneficial if each one were recolored in same way.

This is a great idea, though given the current setup, I'm not entirely sure how I would implement it. Since for efficiency reasons the code now blits directly onto the target surface rather than a temporary surface. I had looked if there was a way to create a new "dummy" surface that shares (a sub-portion of) the target surface buffer to more easily/efficiently manage scripted operations, but I didn't find an easy method in my brief look.

It also occurs to me that it might be useful to call the recolor (and perhaps the blit?) scripts in the context of the ufopedia, which is not currently done. For example, lots of weapons have ammo that is essentially just a minor recolor of the original, so a recolor script could be used to allow for only having to provide one sprite.

7
Okay, so I've made some good progress and can show off some effects. Plus, some people thought sharing this with a wider audience might be beneficial. The current code fork is here and working, though still not done and WIP.

So with this new scripting capability, you can essentially draw anything onto the screen and even animate it to a degree. However, as a practical matter, "bliting" or drawing a sprite on top of another sprite is probably the most useful. Some example effects.

By replacing a weapon like the heavy cannon ammo clip sprite with a new "empty" sprite, you can then blit that full sprite onto it. But then crop that sprite as ammunition is expended to show that ammunition has been expended. For example:


As shown in the example, only one base clip needs to be prepared, and you can apply the same effect to all of them. With a well-designed script, you can even use the same principle across different weapon types, for example...



These sorts of "diegetic" elements can render the same across all locations the item is rendered (except the ufopedia), even if you pick the item up with your cursor. However, you can also control when they take effect if you like.

In any case, the script to produce this effect is fairly straightforward.

Code: [Select]
extended:
  tags: # Remember to add these tags to the same file as items ruleset
    RuleItem:
      NEW_BIGOB: int    # new clip. This will be the empty clip.
      CURRENT_MOD_OFFSET: RuleList
      # CROP_MULT_L or CROP_MULT_R should be 0 if that side of the crop is static.
      CROP_MULT_L: int  # amount to crop left per spent round
      CROP_MULT_R: int  # amount to crop right per spent round (negative if feeding from left)
      CROP_OFFS_L: int  # amount to offset the crop from the left.
      CROP_OFFS_R: int  # amount to offset the crop from the right.

  scripts:
    selectItemSprite:
        # replaces an existing sprite with a new one, everwhere but the ufopedia.
      - new: SpriteReplacement
        offset: 2
        code: |
          if eq blit_part blit_item_big;
            var int newSprite;
            var ptr RuleItem ruleItem;

            item.getRuleItem ruleItem;
            ruleItem.getTag newSprite Tag.NEW_BIGOB;

            if neq newSprite 0;
              var int spriteIndex;
              var int modOffset;
              set sprite_index newSprite;
              ruleItem.getTag modOffset Tag.CURRENT_MOD_OFFSET;
              rules.getSpriteOffsetBigobs sprite_index modOffset;
              return sprite_index;
            end;
          end;
          return sprite_index;

    inventorySpriteOverlay:
      # the script works by bliting the a cropped portion of a full clip onto an image of an empty clip
      # (replaced by script in SpriteReplacement, so the correct image shows in ufopedia)
      # the values need to be set so that the cropOffL and cropOffR represent the min and max x
      # of the full clip to display, in the weapons current state.
      - new: ShowUsedAmmo
        offset: 1
        code: |
          var ptr Sprite fullclip;
          var ptr RuleItem ruleItem;
          var int cropMulL;   # the amount to crop per round on the left side
          var int cropMulR;   # the amount to crop per round on the right side
         
          item.getRuleItem ruleItem;
          ruleItem.getTag cropMulL Tag.CROP_MULT_L;
          ruleItem.getTag cropMulR Tag.CROP_MULT_R;

          if or neq cropMulL 0 neq cropMulR 0;
            var int ammoLeft;    # the number of rounds remaining.
            var int ammoMax;     # the max number of rounds.
            var int cropOffL;    # the amount to offset the left crop.
            var int cropOffR;    # the amount to offset the right crop.
            var int fullClipId;  # id of the original cip

            item.getAmmoQuantity ammoLeft;
            ruleItem.getClipSize ammoMax;
            ruleItem.getTag cropOffL Tag.CROP_OFFS_L;
            ruleItem.getTag cropOffR Tag.CROP_OFFS_R;

            # calculate the crops The formula is. cropOff = (ammoMax - ammoLeft) * cropMul + cropOff
            sub ammoMax  ammoLeft;  # ammoMax  = ammoMax - ammoLeft
            mul cropMulL ammoMax;   # cropMulL = cropMulL * ammoLeft
            mul cropMulR ammoMax;   # cropMulR = cropMulR * ammoLeft
            add cropOffR cropMulR;  # cropOffR = cropOffR + cropMulL
            add cropOffL cropMulL;  # cropOffL = cropOffL + cropMulL

            # get the original clip sprite
            ruleItem.getBigSpriteIndex fullClipId;
            rules.getSpriteFromSet fullclip "BIGOBS.PCK" fullClipId;

            # blit the original sprite onto the empty sprite
            # with a crop from (cropOffL, 0) to (cropOffR, 47)
            overlay.blitCrop fullclip cropOffL 0 cropOffR 47;
          end;
          return;

items:
  # heavycannon ammo appears to feed from the right, 4px per round.
  # Starting 6px from the left. The right side is fixed at 31px.
  - type: STR_HC_AP_AMMO
    tags:
      NEW_BIGOB: 201 # empty AC ammo.
      CURRENT_MOD_OFFSET: UsedAmmo
      CROP_MULT_L: 4
      CROP_OFFS_L: 6
      CROP_MULT_R: 0
      CROP_OFFS_R: 31
  - type: STR_HC_HE_AMMO
    tags:
      NEW_BIGOB: 201 # empty AC ammo.
      CURRENT_MOD_OFFSET: UsedAmmo
      CROP_MULT_L: 4
      CROP_OFFS_L: 6
      CROP_MULT_R: 0
      CROP_OFFS_R: 31
  - type: STR_HC_I_AMMO
    tags:
      NEW_BIGOB: 201 # empty AC ammo.
      CURRENT_MOD_OFFSET: UsedAmmo
      CROP_MULT_L: 4
      CROP_OFFS_L: 6
      CROP_MULT_R: 0
      CROP_OFFS_R: 31

  # autocannon ammo appears to feed from the left, -2px per round.
  # Starting 31px from the left. The left side is fixed at 0px.
  - type: STR_AC_AP_AMMO
    tags:
      NEW_BIGOB: 202 # empty AC ammo.
      CURRENT_MOD_OFFSET: UsedAmmo
      CROP_MULT_L: 0
      CROP_OFFS_L: 0
      CROP_MULT_R: -2
      CROP_OFFS_R: 31
  - type: STR_AC_HE_AMMO
    tags:
      NEW_BIGOB: 202 # empty AC ammo.
      CURRENT_MOD_OFFSET: UsedAmmo
      CROP_MULT_L: 0
      CROP_OFFS_L: 0
      CROP_MULT_R: -2
      CROP_OFFS_R: 31
  - type: STR_AC_I_AMMO
    tags:
      NEW_BIGOB: 202 # empty AC ammo.
      CURRENT_MOD_OFFSET: UsedAmmo
      CROP_MULT_L: 0
      CROP_OFFS_L: 0
      CROP_MULT_R: -2
      CROP_OFFS_R: 31

This effect may not seem very useful (though I like it!). But it demonstrates the ability to write one sort of effect/asset and then reuse it multiple times easily. Doing this with sprite replacement (only) would be a lot more work.

Next up, we have the ability to write numbers onto the interface. Same as numbers are currently written for ammo, medkit charges, etc. These sorts of effects can be recreated exactly (and in previous drafts, they were). So you can use them to define your own sort of interface if wanted. But you can also use them in other creative ways like...



So I hope what's happening here is obvious. But this also demonstrates some limited ways you can animate effects. Since the scripts all take the anim_frame member, if you can build a transformation around that value, you can use it to power an animation. Like the blinking light effect shown here. In addition, you might notice that the normal grenade-primed indicator has been turned off, which is another thing you can do with the scripting.

Code: [Select]
items:
  - type: STR_HIGH_EXPLOSIVE
    bigSprite: 203
    scripts:
      inventorySpriteOverlay: |
        var int timer;

        # unset the grenadeIndicator, we don't want it.
        overlay.unsetOptions OVERLAY_DRAW_GRENADE_INDICATOR;

        item.getFuseTimer timer;
        if ge timer 0;
          var int offsetX 14; # centered in frame for 1 digit
          var int flash anim_frame;
          var int period timer;
         
          # if greater than 10, offset by -2 to allow space
          if ge timer 10;
            sub offsetX 2;
          end;

          # Flash period based on timer. Period starts at 6
          # and increases by 3 every other timer increment.
          # period = (period / 2 + 2) * 3
          div period 2;
          add period 2;
          mul period 3;

          # generate saw wave but only display timer if value greater than 2.
          # this gives a fixed "off" period of 3 ticks (0, 1, 2) with the on period
          # increasing with timer length.
          wavegen_saw flash period period 40;
          if gt flash 2;
            overlay.drawNumber timer 7 5 offsetX 3 55;
          end;
        end;
        return;

One last one, showing a combination of the two effects.



In this example, the normal proximity grenade sprite has been replaced with an "unlit" sprite (replaced via rule file, not script, so the change will appear in the ufopedia). However, when the grenade is primed, we blit another image on top to represent the blinking light. Additionally, that light is shaded using a wave function to give it the "flashing" effect.

The script:
Code: [Select]
items:
  - type: STR_PROXIMITY_GRENADE
    bigSprite: 204 # unlit proximity grenade
    scripts:
      inventorySpriteOverlay: |
        var int timer;

        # unset the grenadeIndicator, we don't want it.
        overlay.unsetOptions OVERLAY_DRAW_GRENADE_INDICATOR;

        item.getFuseTimer timer;
        if ge timer 0;
          var ptr Sprite light;
          var int shade anim_frame;

          rules.getNamedSprite light "Proximity_Grenade_Light";
          wavegen_tri shade 8 8 4;
          add shade -3;
          overlay.blitShade light 0 0 shade;
        end;
        return;

So that's all I got for right now. This is still a WIP, and I still have more to do, but I think these effects are really only scratching the surface of what is possible.

(To be clear, these are just demonstrations of what is possible, not a proposal to change the default behavior that remains unchanged, though I still have the tweaks I suggested earlier).

8
There is also no need to re-implement the existing behavior using scripts.
It is enough to add ability to add new behavior using scripts.

Vanilla grenade indicator, fatal wound indicator and ammo indicator are very unlikely to be changed by anyone. (If someone disagrees, please let me know or create a poll.)
Being able to adjust or reconfigure some of these indicators (primarily the primed grenade indicator and the ammo indicator) is a major rationale for this feature. Examples:

* A high-explosive that displayed its "primed" state instead via display of its timer on its sprite. Or an armed black-powder bomb via a lit fuse. Or a proximity mine via a flashing light.
* A "charged" weapon might display its ammo state via a bar showing a charge percent.
* Weapons with multiple ammo types might display the ammo in a different color as a hint to the ammo type loaded (just today, I had to switch back to the inventory screen to confirm this information).
* The two-hand indicator could be optionally replaced with one that displays the current percentage penalty (or bonus) for a shot taking into account known static factors (kneeling, other hand being occupied) from the items rule.

All of this behavior and more is achievable within the new scripting framework, but it relies upon the ability to disable and/or reconfigure the existing OXCE behavior, preferably on a per-item basis. This is what I've been working to achieve.

Quote
Unless I misunderstood what  "reimplementing" means here.
To make the current OXCE behavior configurable and disableable, by necessity, some of the code that generates these effects must be changed or "reimplemented." I've been working with Yankes on the best way to do that. It is still somewhat up in the air if it is more preferable for these effects to be implemented via script (as some other behavior is now via scripting) or "hardwired" C++ code with flags accessible to the script to enable or disable the default behavior. Or some combination of the two. In any case, the visual appearance and the way the features work for the end user are no different. It has just changed in the backend.

But since, in this process, these effects have been abstracted out in a more general manner to make them more easily configurable, I think it is worth considering to what degree maintaining all aspects of the current behavior is desirable.

Specifically, the three indicators I mentioned are probably useful in other locations but are not currently displayed in these other locations. It seems to me that bringing these effects to the other locations where they could locally appear would be a minor improvement, and doing so would make the code simpler to boot. But as it is a change from the current behavior, I thought it worthwhile to bring up the issue.

Ultimately, if someone is dead-set on this information *not* being displayed in this minorly different manner for whatever reason, then that could be achieved as the entire system is designed to be configurable.

Quote
And for completeness, the OXCE preferred reaction weapon indicator is also optional and moddable and can't/shouldn't be re-implemented.
This and other elements that are more part of the "UI" you might say, and not dependent upon the items themselves are not touched by this patch. However, the groundwork will be in place to make such modifications easier down the road if that is desired. Ultimately I think making the UI configurable via script to the maximum degree possible is desirable, but it's not the feature I am putting forth today.

9
So I've made some progress though I got a bit sidetracked with some restructuring, though that is mainly behind me now. I'm at the point where some more feedback on what default behavior is desirable.

So to give a point of reference again, I'm reimplementing default behavior via script so that it can be modifiable. There are currently 5 different effects I'm considering:

  • The grenade primed indicator. - This applies at the "sprite" level and is always present.
  • The 2-hand indicator. - This applies when the weapon is in a "hand slot"
  • The ammo indicator. - This applies only to the battlescape "HUD" and not the inventory screen.
  • The corpse-state indicator (wounded, stunned, etc...) applies only to a body on the ground in the inventory screen. (You only see these if you have extra sprites that represent them added to your game).
  • The corpse mortal wound indicator. - This applies only to a body on the ground in the inventory screen.

Since I am reimplementing these effects, there is room to adjust (or not) this behavior. So my question specifically are:
  • Should the ammo indicator show up when an item is in hand in the inventory? (It can probably not show up at other times, as weapon sprites are often not large enough for it.
  • Should the corpse-state indicator appear when an item is in inventory? As opposed to just on the ground.
  • Should the corpse wound count indicator appear when an item is in inventory? As opposed to just on the ground.
I still need to implement the ammo indicator so there may yet be some "gotcha" for doing it in the inventory that is not readily apparent yet. However, I think it should be possible.

I have implemented the corpse indicators, and having them in other locations in the inventory works fine as long as any corpse remains 3x2 or so, like the vanilla corpses. The display will become rather cramped if used on a smaller corpse. However, this would also be present in the current code, although it would only happen when the corpse is on the ground.

10
I mainly think from the player end, and it if I had a psi-talented soldier (and maybe even if I did not!) it would be cool that if I came under psi-attack, I knew the position of the attacker. Even if it was only one highlighted square in a see of darkness.

Actually come to think of it, some sort of "remote vision" psi thing would be cool. I should look into that.

11
I need some sanity checks if my new rules are intuitive:

Code: [Select]
transparencyLUTs:
  - colors:
      - [  8,  8, 12, 2 ] # "white"
      - [ 16,  8,  0, 2 ] # orange
      -
        - [ 88, 82, 82,  55 ]
        - [ 48, 48, 42,  30 ]
        - [ 62, 12,  8,  10 ]
        - [ 82, 82,  2,   2 ]
      - [  4, 16,  4, 2 ] # green
What would be intuitive interpretation of this config?

My initial guess would have been x, y, z coordinate and then a color value. But with the comment, I now assume r, g, b, a values?

The semantics of the nested sequence are not clear at all to me. Nested colors, obviously, but nested for what?

12
It sounds to me like this project might be better thought of as two projects (or even more).

One project is the one you've been working on. Improving the AI. It looks like you've made good strides there.

A second project is rebalancing TFTD and XCOM for a more even challenge.

These two projects can be interrelated, the second one might even depend on the first, but it feels like they could be and should be distinct. I'm excited to use your AI in other mods, but not necessarily if I have to take a whole bunch of other balance-related changes with it. (I also might want to use mods that are distinct *not* TFTD and XCOM).

Maybe you were already thinking along these lines, but I thought I'd make that point explicit. To that end, the more you can make the AI's behavior adaptable and configurable, the better.

I think Yankes suggestions have some merit. Especially the one about psi-use giving other psi-capable aliens "vision" of the user. But maybe that could work both ways? Would be interesting. Seems like if you made yet another mod/patch/fork that did this, it could feed into the Brutal AI without any other changes.

Also, having watched a bit of the stream, I think it's worth also considering people who are not-super experts at the game and play at difficulties less than superhuman in TFTD. Frankly, at those levels, I think the gameplay is kind of degenerate. The aliens are super-snipers and countering them with mass grenade spam is... interesting. But I don't think it reflects how most people play the game (it's certainly not how I play it).

I also think it plays up the problems in the game's balance since it kind of becomes a game of rocket tag, where strategy revolves more around being able to infer and predict the enemy's position and kill them on your turn. So positioning and whatnot become somewhat less important.

13
I open to adding functionality like this to engine, but thing that prevent me from doing it was hammer out all details and semantic of this new script hook.

I could say that your experimental version fulfill around 60% thing I would like to have in this new hook(s).
;D But bare in mind, I'm not done yet. I actually changed up the semantics in my current working version (calling the hook an "spriteOverlay" instead of a transformation, which better describes what it is I think).

I also definitely want to get text rendering in a 1.0 version. I just finished getting numberText rendering done. And I have yet even to touch the unit-sprite side of things (though I hope it should be straightforward after I get all the kinks worked out here).

I've also added a different "handOverlay" hook. Because the hand slots have some potential differences in how they might be scripted. A hand slot is 2x3, always, with the item centered, while an item sprite doesn't have to be that size (I know you know this but just for anyone else listening in :P). For an item in the hand slot, both script hooks are called. I can't see this being changed, but we reference the constant in case it ever is.

So yeah, still more to come, but please let me know what else you think this could use.

Quote
For moving some logic to scripts, yes some thing could be moved there without any problem, but some other I would keep hardcoded.
This depend how complex it is and how fundamental is. Prime grade I would keep fixed, but status indicators (stun & overstun) could be moved to scripts.
I'd really like to push hard for moving out as much as possibly can be. Prime grenade is a great example of something that someone could want to put a custom way of giving user feedback on, but doing so will be blocked or at least at great deal more complicated if this logic is hard-coded.

For example, lets say I wanted to change the high-explosive sprite (or use my own sprite) to have a count-down display (number of turns till explosion). This seems like a reasonable and really cool feature to have. But doing so would be tough unless the prime-grenade overlay could be disabled. And since you've already coded in the "override script" functionality, it seems like all the pieces are already in place to make this happen, except for this one. On that specific item, they override the script with their custom behavior, while all the other items get the default behavior.

I actually already went ahead and wrote a script that could mimic the effect as a proof of concept.
Code: [Select]
extended:
  scripts:
    inventorySpriteOverlay:
      - new: GrenadeIndicator
        offset: 1
        code: |
          var int timer;
          var int width;

          # the original logic guarded against 0 width here
          # not sure why but we preserve that check.
          item.getFuseTimer timer;
          if or ge timer 0 neq width 0;
            var int shade anim_frame;
            var int fuseEnabled;
            var int newColor 0;

            var ptr Surface indicator;
            rules.getSpriteFromSet indicator "SCANG.DAT" 6;

            item.isFuseEnabled fuseEnabled;
            if eq 0 fuseEnabled;
              set newColor 32;
            end;

            # this generates a shade offset in the [0, 1, 2, 3, 4, 3, 2, 1] pattern.
            wavegen_tri shade 8 8 4;
            overlay.blitShadeRecolor indicator 0 0 shade newColor;
          end;
          return;

If you want to cross-reference with the current code you'll see they are basically the same, minus a lambda and using your wavegen_tri method instead of the array (though I guess one could argue that a script is just a really big expensive lambda :P). Graphically the two effects are basically identical, minus some potential differences in initial sequence timing which is irrelevant.


(Top one is new script, bottom one is old).

Likewise, a thing I think I might like to do is write a script that replaces the "2 hand" indicator with maybe an indicator that gives the numerical percentage minus to accuracy. Or what if I wanted to change the ammo indicator to have a custom color depending on the ammo type? (Maybe even a brief letter or symbol to represent it?) Lots of potential here I think, but they necessitate opening up some flexibility in the program, which this feature would allow.

The alternative to this is coding in a flag that conditionally disables these elements. But that requires someone to write that code, it to be accepted, and still adds more branching in the code, making it messier, and adds yet another option to the increasingly long list. I'm hardly one to talk as I've done my part in making this situation worse, but I think we should increasingly be looking at ways these options can be reduced and more easily managed. Scripting is one way of doing that.

Quote
Btw when you are toying with scripts and inventory, I have some unfinished business with paper-dolls, one biggest missing functionality is lack of animations and custom script blitting, I had plans to add both but not enough time to do it. Would you be interested to checking it too?
I'm open to looking at it, I'll just need to know more specifically what you want to have happen?

14
OXCE Suggestions Archive / Re: [Suggestion] Statstring Enhancements
« on: March 22, 2023, 08:40:14 am »
The new features look reasonable and backwards-compatible to me.
The code also looks fine (on the first look).
I guess now we wait for community feedback.

PS: is Visual Studio automatically formatting it "const Soldier &soldier" for you or are you doing this manually? VS should be formatting it "const Soldier& soldier", at least it does that for me.

Figured it out. Not sure why more people aren't having this problem, but there is a .clang-format file in the root that has this line:
Code: [Select]
PointerAlignment: Right,Which has the obvious effect.

15
Okay thanks to some helpful advice from Yankee's I got a proof of concept working. You can find the branch here (keep in mind it's still a WIP and git gives me grief so I may force push again unexpectedly).

Currently, I have this working only on the inventory (and alien inventory) screens, though adapting the code to the hand-sprites and the unit-sprites should be straightforward (famous last words, lol). A little screenshot to show the capabilities:



This was created with the following two scripts:
Code: [Select]
extended:
  scripts:
    transformItemSprite:
      - new: ItemBlitTest
        offset: 1
        code: |
          var int id;
          var int width;
          var int height;

          item.getId id;
          if eq id 12; # Heavy Cannon
            var ptr Surface indicator;
            rules.getSpriteFromSet indicator "BIGOBS.PCK" 21; #prox-grenade

            surface.getWidth width;
            surface.getHeight height;
            loop var x width;
              loop var y height;
                var int tempX x;
                var int tempY y;
               
                mul tempX INV_SLOT_WIDTH;
                mul tempY INV_SLOT_HEIGHT;

                surface.blitSprite indicator tempX tempY 0;
              end;
            end;
          end;
         
          return;

      - new: XitOutTest
        offset: 2
        code: |
          var ptr RuleItem ruleItem;
          var int id;
          var int width;
          var int height;

          item.getId id;
          if neq id 12; # Heavy Cannon

            item.getRuleItem ruleItem;
            ruleItem.getInvWidth width;
            ruleItem.getInvHeight height;

            mul width INV_SLOT_WIDTH;  # item width
            mul height INV_SLOT_HEIGHT; # item height

            surface.drawLine 0 0 width height COLOR_X1_RED;
            surface.drawLine 0 height width 0 COLOR_X1_RED;
          end;         
          return;

Basically, this allows you to "blit" items onto items, essentially arbitrarily. As well as having access to some basic geometry drawing. What I haven't got working yet (but would like to before I'm done) is the ability to draw text. (Well actually I do have it working, but not in a way that pleases me yet).

Multiple scripts can run against the same item and stack their overlays. They will stack in order of execution. (IE, the last script to run will be the one on top).

What I'd like some feedback on is two issues:
  • Is there any other functionality I should consider while I'm here doing this?
  • Right now, I have limited the script's ability to draw to the boundaries of the sprite. For item sprites, this is probably always what is wanted, but for unit sprites, I can see the case where you might want to draw beyond those boundaries.

Also, here are a couple of things to consider now that I've got the groundwork in place:
  • These sorts of scripts should easily be able to duplicate some of the OG, OXC, and OXCE effects. For example, the primed grenade indicator, two-hand indicator, ammo counts, body wound indicator, or any overlay currently handled in code. I think we should seriously consider pulling these out and implementing them via these sorts of scripts instead. This would reduce the branching in the C++ code necessary to handle this stuff, as well as making these sorts of effects open to customization by mods as desired.

    This would become more valuable as more code elements are opened up to scripting. As I see it, feedback to the player on the scripted item state is a major roadblock currently. Being able to remove or override these elements with new behavior can really help here, I think.

    I'm willing to do the work to convert these effects if given the thumbs up. This should be completely backward compatible to boot.
  • With this capability in place, a next step might be to allow blit-ing onto the entire screen. This could be used to give feedback on persistent game state information, for example a turn-countdown. I can't see at the moment an easy way to capture a player click into a script, but I still think there could be some uses. Anyways, probably a separate project, but something to think about. The hard part is (probably) done.

Pages: [1] 2 3 4