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
16
What is place where you want exactly add this new hook?

My thinking was more or less immediately after the `selectSprite` scripts run in BattleItem and... BattleUnit (I haven't investigated that one yet, I assume the code is similar, though).

I feel like I'm about 90% of the way there right now. What I've done so far:

# Binding (this all looks to be working)
Added two bindings to Mod to allow retrieval of arbitrary surfaces (either by name or library/index)
Added two bindings to Surface to allow Blit-ing and writing of text.
Added the bindings of the Surface pointer type to the appropriate registers.

# execution
Added my new parser and its constructor.
Added the call (just sending the raw sprite for now).

I'll be honest this has been pretty rough going, though I feel I'm 90% of the way there. I went ahead and pushed my fork up. I haven't added all the calls just this one to test with. You can see it here..

This is, uh, coincidently, where I'm still having some trouble. Getting an error about unable to convert to initialize list, which I assume means I've got a type error between the call and the ctor someplace, but I ain't seeing it. (Unless there is something else I'm missing, totally possible).

17
What exactly is use case you want to handle by this?
Oh man, lots of things. But I had two primary use cases in mind. One I would like to do immediately, one maybe sometime later:
 * being able to more easily give feedback on an item's state via script. Right now this can be done by selecting another sprite which involves creating another sprite, which can be tedious if you want to apply it to a lot of sprites and/or give information on a lot of states. Or via recolor which has limitations.
 * being able to give feedback on events in the battle state. Right now this can be accomplished via recolor and its "hit flash" which is very cool, but if you could blit sprites/draw on the surface you could essentially display arbitrary information. One thing I'd like for my personal use is to flash a number of damage taken to the user (I know some people hate the concept but allowing for this ability lets me write a script that people who do like it can use, and people who don't like it don't have to).

But if the surface is exposed via script potentially you can draw in almost arbitrary ways, depending upon what functionality is enabled. So there is a lot of potential. Meridian mentioned above someone wanting some sort of overlay graphic when a shield was active (Doing this via recolor is cool, but an overlay would also be cool).

Quote
To have very basic custom biting in script should be very simple to add, you register `Surface` and add couple of helpers that blit one surface to another.
This is the approach I've settled on. Just a bit hard to parse where all the different pieces get added. So far I've added the necessary binding to Surface and Mod (to allow for finding other sprites, though those sprites would be read-only).

Now I just need to figure out (am figuring out) how to add another script to call, how to pass it arguments, etc (basically you need the current battleState, itemState, and the sprite). I suppose in theory this should return a surface though really since all the modifications are happening to the surface, I guess I would hope that it could just be treated as an "out" parameter basically. Returning a pointer seems redundant.

And of course, all the things I didn't know I didn't know while working on this.

18
OXCE Suggestions DONE / Re: [Suggestion] Manual Promotions
« on: March 19, 2023, 01:45:02 am »
Thanks for the detailed review. Sorry for all the typos, sperling is not my strong suit. I'll push a patch in a bit that should resolve all the ones marked resolved. The few remaining are either ones I didn't know the right fix for (I don't have TFTD installed right now to test) or wasn't sure your preferred resolution of.

19
Yeah this would have the ability to do that (and more). Though honestly a pure overlay might be a better fit for the existing recolor script, depending upon exactly the method wanted.

After more digging and pondering, I think I've decided (subject to other input, of course) that passing the script the Surface object (and binding some of its methods) is probably the best bet. It's virtually risk free and offers maximum flexibility with little extra work. The problem remains how to reference other sprites/surfaces for blit-ing. Natively they are stored in mod, which seems not that desirable to expose (though I'm still learning about how this all works).

I'll keep poking.

Edit: And I'm dumb, I see there *are* some exposed methods on Mod... interesting.

20
This is a kind of big one, but it feels like it has a lot of possibilities. Correct me if I'm wrong, but I've dived in pretty deep to the scripting but there isn't anyway to do this at the moment. Instead scripts can either recolor sprites or select a new sprite to be displayed. XPZ uses the second style to achieve basically this for wounded/stunned markers on corpses. The ability to blit a sprite on top of the existing sprite would allow this to be done without having to generate a ton of extra sprites for this purpose. There are lots of other concepts it would be useful for, displaying data about an items state on the paper doll, or even maybe a numerical "damage" display when a soldier gets hit.

So I've been digging around a lot in the scripting section of the code to get a sense of what would be necessary to allow this. But this section is pretty wooly so it's somewhat slow going (not an insult, just the nature of the beast). I haven't started a fork yet (don't worry!) but I have dug around enough that I feel I could at least make an attempt at an approach, though I feel it would be somewhat suboptimal.

Using the existing selectSprite scripts as a guide, I could implement a similar method that exposed similar data, but the return value(s) would be used to identify another sprite to blit onto the current sprite. I could imagine making this pretty flexible in terms of returning data that identifies the sprite, sprite library, and possibly X/Y coordinates (probably... maybe). The blit operation would then be handled using these return values after the execution of the script.

The limitation here is it would allow for blit of only a single item. This is probably good enough for most use-cases, but I figure if we're going to do this feature, might as well make it full featured.

Alas while I have several ideas about how a more full-featured blit could be done, I don't currently see how I would implement them... yet. If people don't hate this idea, I'm willing to work on it though.

Any pointers as to a better approach would be appreciated. The ideas I currently have are:
 * pass in a pointer to a "blit instruction" stack or something. The stack could be filled up blit instructions (and maybe other instructions?) that would get executed after the script completes. Upside is I could imagine how to approach this. Downside is it's basically building a script engine within a script engine, which seems extra pointless.
 * Have the mutations happen while the script is live? A blit operator. This was my original idea but that static operators are, obviously, static, and would lack the proper contexts, which means it would need to be provided by the script execution engine. Maybe this is something I can crib from the recolor scripts? I haven't dove into them yet.
 * Pass in the surface? This seems reasonable and the script could mutate it to its hearts content without much risk. The issue, again, is lack of context. A surface object lacks easy access to the other sprites. I suppose the appropriate SurfaceSet could also be passed in, though passing data between the two via the script seems like a dubious idea (if perhaps possible).

In all cases this operation would run as a separate script, probably after the selectSprite scripts have run (in the same context though). Anyways, thoughts welcome.

21
Sorry, I didn't mean to step on any toes. I do this mostly for the fun of it, so any request I send is either going to be something I want for myself or something that looks fun (and probably easy) to do. If you don't want the patch, feel free to close it. I've already got my enjoyment out of doing it :P

22
OXCE Suggestions Archive / Re: [Suggestion] Statstring Enhancements
« on: March 18, 2023, 11:14:47 am »
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.
Honestly, I'm not sure. I'll check.

23
The feature seemed easy and reasonable, so I went ahead and implemented it. Pull request here. I also added the feature to craft as well. Now the only items lacking it are scientists and engineers. I would have added it to them, but the location to put the key in the rule is not so straightforward, so I held off.

24
OXCE Suggestions Archive / Re: [Suggestion] Statstring Enhancements
« on: March 18, 2023, 01:17:10 am »
This feature is finished, pull request sent.

Details are described in the pull request, but I think all the issues discussed should be handled.
  • The ability to have both sorts of rules concurrently is provided by using new keys: "percentTu", "percentHealth", ect.
  • Range conflicts should be handled by float math. Percent ranges are done inclusive, exclusive ie: [min, max).
  • Percents are stored in a 0-100 notation, rather than 0-1 (this can also help avoid some unintuitive limitations of float storage)
  • There is now a tag that allows for global rules to be processed with type-specific rules "globalRule". If not present, the old behavior is preserved. If set to true, this rule is processed with the soldier rules (global rules happening first)
  • Soldiers can be tagged (and anti-tagged) in physicalTraining as well as psi training with the new "physTraining" rule. (setting this, or psiTraining to false will tag soldiers *not* in training.
  • The stat string divider can be customized with an OXCE option "oxceStatStringDivider" which defaults to "/" it is not present in the menu but can be changed in the cfg file or by mod.
[li]
[/li][/list]

25
OXCE Suggestions OK / Re: [SUGGESTION]Custom Hangar/Craft types
« on: March 17, 2023, 07:45:03 pm »
Btw, the same problem with prison type. But I don't have a solution here except overhauling base info state UI, so just saying.

I have an idea for this (clicking on the name to cycle the prison type) or maybe something else but I haven't had a chance to poke at it yet.

26
OXCE Suggestions Archive / Re: [Suggestion] Statstring Enhancements
« on: March 15, 2023, 07:46:35 pm »
There could be point where complexity of rules like this would excess of complexity of my script engine and would be easier to use it instead.

The thought did definitely occur to me. But such a task was beyond my (current) level of knowledge of the code. I'm trying to ease you guy's burden, not add to it! And frankly providing a percent-based stat string both felt more accessible and fit my specific need for it. It also seemed that the relative sparseness of text manipulation in the scripting language might potentially pose a difficulty, though you would obviously know more about the limitations there than I.

But if you're willing to add it, I would certainly not want to stand in your way! Frankly, there is a lot of stuff in here related to this stat string concept that I'd like to rip out/replace, though I imagine you all will want it to stay for backward compatibility reasons regardless.

As it is, I've got a working concept running at this point, though I still need to do a lot of testing, obviously. As usual, I stuck to the conservative approach so most of the code outside my "scope" (statString and statStringConditional) remains unchanged.

27
OXCE Suggestions Archive / Re: [Suggestion] Statstring Enhancements
« on: March 15, 2023, 03:19:58 pm »
I do not want break fun, but:
Code: [Select]
statStrings:
 - string: "x"
   firing: [75, ~, p] # Percentage based but it could map to a value of [40, ~] if base value is pretty low.
   firing: [60, ~]    # We only consider soldiers that can identify: "the business end of a gun".
this code is illegal and can't be handed by OXCE in any way. You are not allowed to duplicated key names in one block in yaml.
Game will read only `[75, ~, p]` or `[60, ~]`.

My bad, you are, of course, right. No duplicate keys. However, with the alternate design that uses a different key for percent-based conditions, it would be allowed. This is the one I'm moving forward with at the moment.

However, I should also note that conditions are inherently and based, so if you have a percent condition and an "absolute" condition active on the same attribute (which would be allowed), you would have to satisfy them both to trigger the stat string. This probably limits the usefulness of such an approach, but changing the logic to be or based is well beyond the scope of what I'm doing here.

28
OXCE Suggestions Archive / Re: [Suggestion] Statstring Enhancements
« on: March 15, 2023, 02:04:23 am »
I thought I'd make a separate post giving a short update on stuff I've had to back away from and new stuff I've been able to implement.

1. While I think the ability to base stat strings of a soldier's augmented stats could be quite useful to some people, generating those stats relies on having a reference to the `Mod` object (to refresh the bonuses, apparently). Unless I'm missing something (always possible) I don't have easy access to this object from this code section, so I'll back off on this one for now.

2. The existing code allows for a binary condition "is this soldier in psiTraining or not." While I'm rewriting this section, it is easy enough to extend it to also allow for normal training, so a new binary condition, "training," will also be allowed.

29
OXCE Suggestions Archive / Re: [Suggestion] Statstring Enhancements
« on: March 15, 2023, 01:58:41 am »
Wow, you've given me a lot to reply to, but that's good, I really appreciate the feedback. I cut some of your post together to cut down on the amount of spaghetti in my response.

A. Base value
===========
Percentages need a base value as to what constitutes as 100%, there are multiple candidates one can chose:
1) Max of soldier 'statCaps'
2) Max of soldier 'trainingStatCaps'
3) Max of current soldiers on craft
4) Max of current soldiers on base
5) Max of all soldiers still alive on the globe (e.g. all bases)
6) Something else ...
Based on your post I suspect you've chosen '1' but it would not hurt to specify which one (or multiple?) you want to support.

A. Option (1) seemed to be the most logical one. Certainly more stable than 3-5 (not depending on RNG and not varying during the course of a campaign).
    Should prevent situations where: "One-eye would become *the* marksman in the land of the blind".
I'm working on a design that is flexible and allows (potentially) multiple designs. (Specifically, I'm reworking how the `StatStringCondition` class works so that it has a bunch of sub-classes that can implement different behavior. Its `isMet` method will now take a reference to the soldier, to allow a lot of flexibility in this). Under this design 1 and 2 are trivial, and 3 and 4 might be possible (soldiers have a reference to their craft and craft's have a reference to their base). Though I don't really see working on 3 and 4 unless there is a lot of desire for it. 5 is likely more difficult as there doesn't appear to be an easy way to get a reference to all soldiers from here (a problem I've run into elsewhere).

In any case, I plan on (well this part is already done actually) #1 as the primary function. I also added support for number #2 while typing this response... I might back it out though. I think there are better ways to display this information that I might address in a different patch.

Quote
B. Stat overflows
=============
It is possible for soldiers to slightly overflow a stat (e.g. percentages > 100), at least for the fixed base values.
Will you cap the values at 100 or recognize percentages above 100?

B. I believe this is less of an issue since I suspect most users will opt to use something akin to '[90, ~, p]' instead of '[90, 100, p]' but it is something to consider.
    My (weak) preference would be allowing percentages > 100. So one could designate: "the best of the best of the best ..." (e.g. '[100, ~, p]').
The easier the logic, the better. So I'll copy the existing functionality here. If you feed it "~" (or actually any non-integer) as the first value in the array, the minimum value will get set to 0 (or 0%). If you set "~" (or any non-integer) as the secondary value, the maximum value will get set to 255 (corresponding to 255%). I don't see any specific reason to limit the ranges otherwise (and the existing code doesn't do so) so yes, percentages over 100% will be allowed. Stats less than 0 aren't meaningful in X-Com, but who knows what might happen in the future, so I'll allow for negative percents as well (the current code allows for them FWIW). We'll assume the user knows best what they are doing if they set some funky values or edge-cases.

Quote
C. Behavior for base values != 100
===================================
From experience most (max) stat values tend to not align neatly with 100, meaning any percentage based range will lead to gaps or duplicates.
For reference, given the following statstring definition:

Code: [Select]
statStrings:
 - string: "x"
   firing: [~, 50, p]
 - string: "M"
   firing: [51, ~, p]

If the base value is < 100 one could end up with:
Code: [Select]
"SoldierName/xM"If the base value is > 100 one could end up with the following naming scheme when a soldier levels up:
Code: [Select]
"SoldierName/x" -> "SoldierName" -> "SoldierName/M" (e.g. missing statstring when a number falls between 50% and 51%).

How would you tackle this?

C. Never found a good way to solve this (yet), currently I tend toward the solution that does extra calculations:
    - If value is at upper boundary (e.g. '[~, 50, p]') calculate the next one up (e.g. '[~, 51, p]').
      + Use the midpoint for a decision if base value > 100.
      + Use floating point rounding for a decission if base value < 100.
    - If value is at lower boundary (e.g. '[51, ~, p]') calculate the next one down (e.g. '[50, ~, p]').
      + Use the midpoint for a decision if base value > 100.
      + Use floating point rounding for a decision if base value < 100.

Wow, you've put a lot of thought into it. My current code here is very basic:
Code: [Select]
const int stat = (*soldier->getCurrentStats())[_conditionName];
const int cap = soldier->getRules()->getStatCaps()[_conditionName];

// percents are stored as integers, ie 50% = 50, so multiply stat by 100 to offset.
int percent = (stat * 100) / cap;

return percent >= _minVal && percent <= _maxVal;
(not tested yet either). I'll investigate more deeply when I get a bit further in design. I was planning on treating the percents as integers in definition, but if necessary switching to floats is possible.

Quote
D. Allow both fixed and percentage for the same stat.
========================================
Although you've already touched this subject it is a bit unclear if you want support "one OR the other" or "both at the same time".
E.g. is the following example supported?

Code: [Select]
statStrings:
 - string: "x"
   firing: [75, ~, p] # Percentage based but it could map to a value of [40, ~] if base value is pretty low.
   firing: [60, ~]    # We only consider soldiers that can identify: "the business end of a gun".

D. Due to the nature of some stats a fixed minimum might be desired, hence my preference to support both at the same time.
    Again: "one-eye ... land of the blind".
Yes, under my current plan, this is supported. Every line corresponds to a new condition, so you can have percentage-based conditions and traditional conditions within the same rule.

Quote
E. Backwards compatibility.
=====================
When using any new definition one probably want to prevent errors (or undefined behavior) when a user tries to load it into an older OXC(E) version.
Worst case the application could choke (crash) on the ruleset. More likely it could lead to unexpected designations (percentages being treated as fixed values).
Any idea how to approach this?

E. Not a strong one since 'metadata.yml' value "requiredExtendedVersion" could prevent this situation, something to consider though.
Well, there is nothing I can do about a new ruleset being used on an old version. Since I can't change old code, incorrect behavior is inevitable. However, under my current plan, it would not crash (elements of the array beyond the first two are just ignored). But as you say, the percentages will be treated as fixed values. If I instead treat the percentages as floats, then I think the most likely behavior is they will fail the conversion, and the minimum (0) and maximum (255) values will get used instead.

Honestly, though this isn't a thing I worry too much about. The new rules won't cause things to blow up if run with an outdated version which is about as good as can be asked for. However, your sidenote offers other possibilities.

Quote
Sidenote (since you are open to suggestions).
+++++++++++++++++++++++++++++++++++
Instead of adding an option to the range array, why not use specialized value definitions (like for example 'firingPercentage: [~, 66]')?
In my opinion that would make the desired use case stands out a bit more in the ruleset.
Wow, this is a great idea, I'm upset I didn't think about it. It makes my design slightly more complicated in someways, but simpler in others (hard to explain without posting all the code). The biggest advantage is backward compatibility would be 0 concern. My current read of the code is that condition names not present in the preset list would simply be ignored. I'll strongly ponder this design.

Quote
As for the statstring divider
++++++++++++++++++++
Although I do not deem it that important, percentage based statsrings deliver more QoL, I do believe it could be beneficial to personalize OXC(E) behavior.
However, there are as many opinions for separators as there are users (for example, "/", "\", " ", "|", etc...).

This means a translatable string (e.g. 'STR_STATSTRING_SEPERATOR' or something akin) has the best potential to cater for user wishes.
Since i understand bringing 'state' into 'soldier.cpp' might be hard (or nearly impossible) you might want to consider the following alternatives:
+ Add a new statstring top-level attribute e.g (replacing the current hard-coded one).
Code: [Select]
statStrings:
 - divider: "|"
 - string: "x"
   firing: [75, ~, p] # Percentage based but it could map to a value of [40, ~] if base value is pretty low.
   firing: [60, ~]    # We only consider soldiers that can identify: "the business end of a gun". 
 

+ Add a divider before each individual statstring (so one can end up with something akin to "Soldier|9|6|8|1|5")
Code: [Select]
statStrings:
 - string: "x"
   divider: "|"
   firing: [75, ~, p] # Percentage based but it could map to a value of [40, ~] if base value is pretty low.
   firing: [60, ~]    # We only consider soldiers that can identify: "the business end of a gun". 
I had considered this as an option. The problem with it is it means either storing the statString divider in the `Soldier` class, where it seems a bit out of place or diving somewhat deeply into the statString class to pull this bit of data out. And the problem here is that there is not just one instance of the `StatString` class, but a vector of them, one for every "rule." Neither are necessarily show-stoppers, but the design feels inelegant. I'll ponder.

The problem with your second option is there simply is not enough screen real estate to make this version very useful. Every character is at a premium.

Quote
Hope this post was of any use.
It was incredibly helpful, thanks so much for the feedback.

30
OXCE Suggestions Archive / [Suggestion] Statstring Enhancements
« on: March 14, 2023, 05:33:46 pm »
So I make fairly heavy use of stat strings, a feature I quite like. And for mods that have a lot of soldiertypes (like piratez) the ability to set stat string by solidertype is a welcome addition.

However, it also means having to set a big-long list of statstrings for all the soldier types, which is both tedious and often open to error when setting values for soldier types that are similar but not identical. And in any case, it seems often the information I want to know is how far (that is, what percentage) a stat is from its cap.

So, why not add the capability of setting a statstring on a percentage basis? The design I am contemplating is pretty straightforward. In an existing statstring block, we simply add another (optional) option to the "range" array after the existing min and max scores. Something like...

Code: [Select]
statStrings:
 - string: "x"
   psiStrength: [~, 30, p] # percentage based
 - string: "P"
   psiStrength: [80, ~] # field absent or any other value, normal behavior
Quite compact and backward compatible.

The disadvantage with this format is that it no longer looks quite so "clean," and I guess it's maybe no longer copy-and-paste backward compatible with x-com util, though I don't know to what degree that is still valuable. Alternatively, the tag could be placed at a higher level, but this eliminates the ability to have differing percentage-based and non-percentage-based conditions within the same rule.

While I am in here working on this, it also occurs that some people might find it desirable to set conditions on an absolute basis. That is; currently, stat strings only take a soldier's "base" stats into account. But with armor, commendations, and other bonuses, a soldier's stats can rise or fall above or below that level. Some people might want to apply statstrings based on this augmented level.

This could be accomplished by adding yet another field to the array after the percentage-based marker, which I don't hate as a method, though at this point, it is becoming somewhat bulky. I'm open to other suggestions.

This is a fairly small patch, so I'm already working on it for my use. I'm not asking for anyone else to do so. I'm just trying to get feedback on what might be desirable. And what might be necessary to get this accepted?

One last thing. While I'm at it, one other minor feature I'd like to bundle with this is the ability to customize the statstring divider, which is currently hardcoded to be a "/". Ideally, I would add this as another translation string, but as the "Soldier->getName" function where this logic resides does not derive from state, I'm quite a long way away from having access to the "tr" function. Other similar classes handle this by passing the language along with the call to "getName," but Soldier does not (because soldier names don't need to be translated). I could add that argument to the method, though this would be a fairly far-reaching change for such a minor feature. Alternatively, since "Options" are global, I could put the functionality there since it is not technically a translation anyway. Open to suggestions on this point as well.

Thanks for your attention.

Pages: 1 [2] 3 4