Thoughts on wearables

mrangel
25 Aug 2018, 22:19

Just been looking at the wearables code, and it seems a bit clunky. It would be easy for a naive user to change the 'worn' flag directly, not realising that they need to use functions to ensure that any bonuses from a garment are applied correctly.

Wouldn't it be neater to have something like:

<function name="SetBonuses" parameters="garment, wearflag">
  // This function provided for backwards compatibility
  //   in case any scripts call it manually. In most cases it will do nothing,
  //   but the existing wearables library advises users to call it, so it's better to replace it
  //   with a do-nothing function rather than break any libraries that call it

  // Small piece of code so that this function will behave sanely if called for some reason on a non-garment
  if (not DoesInherit (garment, "wearable")) {
    if (HasString (garment, "bonusatts")) {
      ApplyBonuses (game.pov, garment.bonusatts, not wearflag)
    }
  }
</function>

<function name="ApplyBonuses" parameters="character, bonuses, remove">
  foreach (att, Split(bonuses, ";")) {
    bonus = 1
    plusarray = Split(att, "+")
    minusarray = Split(att, "-")
    if (ListCount(plusarray) = 2) {
      att = StringListitem(plusarray, 0)
      if (not IsInt(StringListitem(plusarray, 1))) error ("Bonus attribute not properly formatted: " + att)
      bonus = ToInt(StringListitem(plusarray, 1))
    }
    if (ListCount(minusarray) = 2) {
      att = StringListitem(minusarray, 0)
      if (not IsInt(StringListitem(minusarray, 1))) error ("Negative bonus attribute not properly formatted: " + att)
      bonus = -ToInt(StringListitem(minusarray, 1))
    }
    if (remove) {
      bonus = -bonus
    }
    bonus = ClothingBonusMultiplier() * bonus
    n = GetInt(character, att) + bonus
    set (character, att, n)
  }
</function>

<type name="wearable">
  <changedworn type="script">
    if (HasString (this, "bonusatts")) {
      ApplyBonuses (this.parent, this.bonusatts, this.worn)
    }
    _SetGarmentAlias (this)
  </changedworn>

  <changedbonusatts type="script">
    if (GetBoolean (this, "worn")) {
      if (TypeOf (oldvalue) = "string") {
        ApplyBonuses (this.parent, oldvalue, false)
      }
      if (TypeOf (this, "bonusatts") = "string") {
        ApplyBonuses (this.parent, this.bonusatts, true)
      }
    }
  </changedbonusatts>

  <changedparent type="script">
    if (GetBoolean (this, "worn") and HasString (this, "bonusatts")) {
      if (TypeOf(oldvalue) = "object") {
        ApplyBonuses (oldvalue, this.bonusatts, false)
      }
      if (TypeOf(this, "parent") = "object") {
        ApplyBonuses (this.parent, this.bonusatts, true)
      }
    }
    this.worn = false
  </changedparent>
</type>

(this would make garments work more easily when worn by NPCs. Wearing / removing / multistate changes would work elegantly; as would any other script that changes a garment's bonuses while the player is wearing it. The only thing that wouldn't be accounted for is a script calling destroy() on a garment, which I think we can't check for.)


mrangel
26 Aug 2018, 19:25

(Also, I think a lot of the functionality from WearGarment and RemoveGarment could be moved into the changedworn script; which guards against a naïve user changing the worn attribute rather than calling the functions. Not sure if that's essential, though)


ahmed11
27 Aug 2018, 09:13

Great