Skip to content
This repository has been archived by the owner on Apr 14, 2020. It is now read-only.

Power cell-like ammo item framework #1044

Open
sumghai opened this issue Feb 22, 2020 · 32 comments
Open

Power cell-like ammo item framework #1044

sumghai opened this issue Feb 22, 2020 · 32 comments
Assignees
Labels
C# Requires C# solution enhancement

Comments

@sumghai
Copy link
Contributor

sumghai commented Feb 22, 2020

At present, CE ammo come in the form of discrete cartridges, shells or rockets, which are suited to various historical and modern projectile firearms, as they account for the wide variety of loading methods and magazine sizes.

I would like to propose an additional, alternative xml/C# framework that would allow modders and patch authors to define power cell-like ammo items, for use with sci-fi and other exotic weapons.

Feature Overview

  • Manufactured at the Machining Table via Bills (too complex for the Loading Bench)
  • Has overall item mass and bulk
  • Stackable
  • Each cell contains a discrete amount of energy/fuel defined by the xml def
  • Weapons using the ammoConsumedPerShot parameter would use up a fixed amount of energy/fuel per shot
    • By default, it is assumed that the ammo item mass and bulk remains constant during use
    • Optional parameter massConsumedPerShot - if specified, reduces the mass of the ammo item by a fixed amount after each shot
  • Partially-depleted cells retain their remaining capacity, and can still be loaded into their weapons
  • Once depleted, the cell is consumed/discarded just like regular ammo

Use Cases

  • A generic Plasma Power cell shared by various Plasma weapons, each consuming different amounts of Plasma per shot
  • Lasers, phasers, disruptors, tazers, etc.
  • Fuel tanks for flamethrowers
    • Should cells and fuel tanks be refillable/rechargeable?

Current Placeholder Implementation

Phase I of the FastTrack merger (#1006) contained a crude placeholder implementation of generic Plasma Power Cells. The current stats were conceived by defining the desired overall mass and dimensions of each power cell, then dividing these initial stats by the number of shots/rounds contained in the cell.

While the current faux power cells fits with the existing 1 cartridge = 1 shot framework, they break immersion in that the cells are not supposed to lose bulk as they are being used, especially for batteries; even an empty plasma or flamethrower fuel tank is a rigid container that should retain its bulk until it is discarded.

Misc Thoughts

  • How would we display the current remaining charge/capacity for each cell?
    • The current percentage next to each item name should still represent hitpoints remaining, for consistency with other items
    • Perhaps a second bar graph in the properties inspector when the cell is selected?
      power cell concept 1
    • What about in the pawn inventory tab?
@Alicecomma
Copy link
Contributor

Alicecomma commented Feb 22, 2020

Critiques

Okay, so the critiques on the currently available systems are as follows:

resolved
  • Not possible to add "sci-fi" or "unique" weapons [Not quantified/quantifiable]
  • Should be added to machining table, should be stackable (possible)
  • Should have mass and constant bulk, regardless of "charge" [Implementable in StatPart_LoadedAmmo and additional StatParts] (Added d210c94)
  • Specify amount of energy/fuel per cell (ignored)
  • Allow for variable amount of energy/fuel spent per projectile/shot/discharge (Added d210c94)
    • Item mass/bulk should stay constant (duplicate)
    • Item mass could decrease [Implementable in StatPart_LoadedAmmo and additional StatParts] (ignored)
  • Remaining energy/fuel should be stored in cells when unloaded (This will not be added, instead the gun will store a deficit in energy/fuel when unloaded)
  • Destroy when fully depleted [Slight changes to current destroy code - keep if remaining energy/fuel] (Added in commits)

Examples given:

Universal plasma power cell
    • All weapons should use different amount (of energy/fuel) per shot from the same cell (duplicate)
    • Mass and bulk should be defined for a clip/cell of ammo, not per round (duplicate)
    • Item should not lose bulk, as this "breaks immersion" (duplicate, not quantified)
    • Remaining charge should be displayed on inspector and pawn inventory tab (ignored)
  • Lasers, phasers, disruptors
  • Tazers [Realistically, tazers use single-use cartridges, not an "energy/fuel" system, so I don't see the point of including them]
  • Flamethrower fuel tanks

Thus, changes suggested:
resolved
  • Allow mass and bulk of an item (fuel cell) to remain constant (default behaviour)
  • Set energy/fuel in an item [possibly Comp changes, or ignore] (chose to ignore)
  • Set energy/fuel amount used per fired projectile for various projectiles [AmmoSetDef changes, possibly Comp changes] (Added d210c94)
  • Allow mass of cell to decrease [StatPart required, or ignore - chose to ignore]
  • Return energy/fuel to depleted energy cells when unloaded, e.g store loaded energy/fuel [Comp or Thing change required, or ignore] (chose to ignore)
  • Remaining charge in a cell should be displayed in inspector [UI changes, or ignore] (chose to ignore)
  • Remaining charge should be displayed in pawn inventory [UI changes, or ignore] (chose to ignore)
  • Allow mass and bulk of a stack of items to remain constant [StatPart required]
  • Consider destroying behaviour of cells only when no energy/fuel is stored [consider]

To allow for examples:

  • Universal plasma power cells
  • Lasers, phasers, disruptors
  • Flamethrower fuel tanks

These issues suggest two courses of action:

  1. Add separate fuel cell items with complex Comp/Thing behaviour, holding multiple charges
  2. Keep simple fuel cell items, with charge expressed in amount and with fuel cell-like mass/bulk set per multiple of a stack

StatPart required changes:

resolved
  • Solves practically all currently raised flamethrower fuel tank issues (constant bulk, decreasing mass)
  • Solves universal power cells as long as AmmoSetDef changes are performed to allow multiple ammoDefs to be used for a single projectile (Added d210c94)
  • Could solve lasers/phasers/disruptors and other batteries if tiered mass/bulk are considered
  • No need for considering destroy behaviour, returning/considering charge etc. for these changes specifically (incorrect)
  • Ideally implemented on a per-weapon basis for the bulk (e.g, a "magazineBulk" part to its AmmoUser) -- Although, the bulk should also depend on ammo loaded somehow
  • Either implemented on a per-ammo basis for the mass, or already possible (Added d210c94)
  • Highly possible, minimal code changes to allow constant or varying (Added d210c94) mass/bulk

Complex Comp/Thing storage:

  • Introduces parallel ammo behaviour
  • Introduces "energy/fuel" in item -- instead, is stored on weapon
  • Solves lasers/phasers/disruptors differently
  • More complex return behaviour, shot behaviour, loading behaviour
  • Additional UI work

To my mind, complex storage adds too many code changes and would need to be implemented in-depth in all classes handling ammo. This makes it not worth implementing, when universal plasma power cells, fuel tanks and battery-like ammo could be implemented much more easily and do not parallelize the ammo system (Complex storage is more or less the current plan, although on the gun and not on the ammo)

@N7Huntsman N7Huntsman added C# Requires C# solution enhancement labels Feb 22, 2020
@N7Huntsman
Copy link
Contributor

N7Huntsman commented Feb 22, 2020

I see the <ammoConsumedPerShot> as a solution to allowing for "power cells" in a manner that doesn't require what is essentially a parallel ammo system.

@Alicecomma

This comment has been minimized.

@Alicecomma

This comment has been minimized.

@Alicecomma Alicecomma self-assigned this Feb 22, 2020
@Alicecomma

This comment has been minimized.

@Alicecomma

This comment has been minimized.

@Alicecomma

This comment has been minimized.

@Alicecomma

This comment has been minimized.

@sumghai

This comment has been minimized.

@Alicecomma

This comment has been minimized.

@Alicecomma

This comment has been minimized.

@sumghai
Copy link
Contributor Author

sumghai commented Feb 22, 2020

Nice! I definitely prefer adding to the existing ammo framework, rather than having a separate system that runs in parallel.

Looking forward to trying these out myself once the backend is implemented.

Alicecomma added a commit that referenced this issue Feb 22, 2020
@Alicecomma
Copy link
Contributor

Alicecomma commented Feb 22, 2020

TODO:

  • [ ]
  • Handle a gun with insufficient loaded ammo (< Amount) as an empty gun and attempt to reload (check inventory for Amount of ammo) or unequip.
  • Add warning on startup for AmmoSetDef that has the above property (no fallback on a projectile with lower resource cost)
  • Cull ammo set selection of multiple AmmoLink with the same AmmoDef with varying amounts from the reload Gizmo (when appropriate!)
  • Add to the ammo selection Gizmo additional information about non-trivial AmmoDef differences
  • Consider changes to magazineBulk (bulk added due to magazine volume) with different AmmoDef loaded
  • Consider changes to magazineSize (amount of ammo loadable) with different AmmoDef loaded
  • "make catapult use stone blocks instead, 15 at a time with that optional parameter added by fasttrack something like < ammousepershot>"; this comment suggests that the Amount="" tag isn't enough, there should also be some way to handle when it is desired to take up a certain amount of shot and allow smaller values with an automatically scaled fallback.

@Alicecomma

This comment has been minimized.

Alicecomma added a commit that referenced this issue Feb 22, 2020
- Remove FT implementation
- SpentAmmo having mass costs implemented
- Magazine bulk implemented
- Set Revolver to ejectsCasings = FALSE
- Ported over previous "Fix-for-#1044" to new Development with PRs
- ConservedMassFactorWhenFired added
- ConfigError checking for Amount without backup
- Loaded ammo statPart now includes several discussed things
- VerbShootCE ejecting casings checks whether conservedMassFactorWhenFiring is positive
@Alicecomma

This comment has been minimized.

@Alicecomma

This comment has been minimized.

@Alicecomma

This comment has been minimized.

@Alicecomma
Copy link
Contributor

Alicecomma commented Feb 23, 2020

The issue: as long as 1 ammoDef produces 1 firing event, things go well. However, as more charges are gained and consumed, and those charge changes become disproportional, magazines can become messy and a pain to handle.

Mathematically, there are optimal solutions to these issues. Magazines can remain in harmony, while loading, unloading and firing events can be allowed to occur in harmony with one another and with the player, investing resources into the gun system.

To prevent fractional charges in the magazine

Content
  1. Only allow mod authors to set the amount of "charges" needed to fill a mag and the amount of "charges" fired from a full mag. E.g, allow them to set the following:
  • B/X
  • B/Y

To ensure that only integer values of "charges" are stored, the values [X] and [Y] are calculated as [B/(B/X)] and [B/(B/Y)]. The brackets indicate this is an integer value. This way, no fractional values of "charges" can exist within the gun.

  1. Calculate magazine size from suggested size, changing it to fit the requirements set by the ammoSetDef.
  2. Allow an overflow of charges to be present in the magazine, so magazineSize is only determining the maximum amount of rounds after which no reload is possible.

Fireable - Unloadable dilemma

Content

Calculate X / Y

  • If X / Y is integer, the loaded gun is always fireable.
  • However, it can be incapable of unloading

Calculate Y / X

  • if Y / X is integer, the gun is always unloadable
  • However, it can be incapable of firing loaded rounds

Problems are only averted when X = Y

Firing backlog (X / Y isn't integer)

Content
  1. Fire a shot as long as there's at least one charge remaining, simplest option [HIGHER VALUE ROUNDS OR INSIGNIFICANTLY DAMAGING ROUNDS]
  2. Having an option with the current X and different Y which does have X / Y integer as fallback, handling a tiered decrease in projectile properties.
  3. Somehow linearly decreasing projectile stats with lower ammo amounts, e.g cutting pelletCount or damage or AP, or speed.
  4. Allow for an underflow of rounds, which has to be replenished with newly loaded ammo (AmmoSetDef < Ammo Underflow="True">)

Examples:

  • Double-barrel shotgun firing 2 cartridges: should act exactly as a 2-round burst with -1 ticks between burst shots, and should allow firing with a single cartridge as well (Y = 2 or 1; X = 1, solution 2)
  • Catapult firing 15 stone bricks: don't care about underflow for firing, however add a flat penalty to pelletCount or other variables (Y = 15, X = 1, solution 3)
  • Napalm launcher, each shot uses multiple charges of fuel, and size of the explosion is decreased (Y = 2; X = 1; solution 3)

Unloading backlog (Y / X isn't integer)

Content
  1. Unload charge counts below X by destroying them. [LOW VALUE ROUNDS - DESTROY]
  2. Convert non-X charge count to depleted ammo ThingDefs (set by a new XML tag) - no partially spent rounds allowed [MID VALUE ROUNDS - SPENT ROUNDS] (AmmoDef.SpentDef)
  3. Give a chance to recover a full X cartridge depending on the discrepancy between X and charge [HIGH VALUE ROUNDS - CHANCE TO RETURN] (AmmoSetDef < Ammo RandBacklog="True">)
  4. Create a fallback ThingDef for X = 1 or appropriate value, which backlog charges are converted to [VERY HIGH VALUE ROUNDS - RECUPERATION]
  5. Allow for an underflow of rounds, which has to be replenished with newly loaded ammo. (AmmoSetDef < Ammo Underflow="True">)

Examples:

  • Junker furnace rifle (or something) which takes Steel and turns it into multiple charges. Shots take varying amounts of charges. Unloading the weapon means spilling the furnace (or something) and all charges are lost, regardless of being backlog or not (Y = above 1, X = above 1, solution 1).
  • Laser rifle firing 1 charge, with each cartridge loading 10 charges and a spent cartridge being returned upon unloading a backlog, suggesting that using one charge destroys the integrity of the round (Y = 1, X = 10, solution 2).
  • Plasma rifle as above, using solution 3 suggesting that using a charge has a chance to drain the entire cell.. somehow.
  • High value energy cell round, providing 20 charges for a 1-charge using weapon. Unloading provides a smaller energy cell variant, which can however not be loaded into the weapon for lore reasons (Y = 1, X = 20, solution 4).

image

@Alicecomma

This comment has been minimized.

@sumghai

This comment has been minimized.

@Alicecomma

This comment has been minimized.

@sumghai
Copy link
Contributor Author

sumghai commented Feb 24, 2020

Okie doke - I'll touch base with you again once you have a working implementation, so you can walk me through the Xenn cell (and maybe a couple of DOOM batteries) as examples.

Apologies again for being obtuse!

@Alicecomma

This comment has been minimized.

@Alicecomma
Copy link
Contributor

Alicecomma commented Feb 25, 2020

Additional structure

The requirements of any "charge holder" are as follows:

  • [LOAD] Decide on the best single ThingDef from a list to be loaded into the gun, and return it
  • [LOAD] Decide on the best combination of ThingDefs from a list to fully load the gun, and return them
  • [LOAD] Return whether a certain ThingDef can ever be loaded
  • [STORE] In certain cases, store the exact ThingDef/Thing in the gun
  • [USE] Decide on the best projectile to fire (e.g maximum use of charges), and return it
  • [UNLOAD] Make a list of ThingDefs/Things to be unloaded and return it
  • [RESIZE] Change the magazine size if appropriate

Since only very few guns would need to use a much expanded toolset for handling charges, perhaps these functionalities could be added as virtuals in a class, such that if the exact implementation of them has to be changed for a new ThingDef, someone could extend the class.

@Alicecomma
Copy link
Contributor

Alicecomma commented Feb 25, 2020

Code impacted by changes

  • CompAmmoUser.LoadAmmo
  • Building_TurretGunCE.TryOrderReload
  • Verb_LaunchProjectile.TryCastShot
  • Verb_ShootCE.TryCastShot has reference to CurrentAmmo.conservedMassFactorWhenFired
  • JobGiver_DoReloadCheck doesn't assign AmmoLink, but assigns AmmoType
  • CompAmmuUser.ResetAmmoCount
  • LoadoutPropertiesExtension.TryGenerateAmmoFor uses CurrentAmmo
  • CurrentAmmoUser.CompGetGizmosExtra icons can't use CurrentAmmo or selectedAmmo
  • StatPart_LoadedAmmo if everything's turned into charges, what mass and/or bulk do you assign to a charge?
  • Utility_HoldTracker "" "", how are ammodefs cached in the holdtracker?
  • Dialog_ManageLoadout.DrawSlot how can ammo be added to a gun if there's no one type of ammo that can be loaded?
  • JobGiver_TakeAndEquip.GetPriorityWork uses ammo count rather than charges added by that ammo
  • WorkGiver_ReloadTurret.HasJobOnThing what ammoDef should it look for?
  • Command_Reload.BuildAmmoOptions groups menumaker options by ammoClass, however that isn't as clear anymore unless a default is used
  • Harmony-Thing.SmeltProducts needs to take into account unloadNext code

@Alicecomma

This comment has been minimized.

@Alicecomma

This comment has been minimized.

@Alicecomma
Copy link
Contributor

TODO

  • Allow fallback to charge adders with smaller charge added values, somewhat intelligently

@Alicecomma
Copy link
Contributor

Alicecomma commented Feb 28, 2020

Just an update, currently figuring out all the issues with the system as programmed

@Alicecomma
Copy link
Contributor

I think the scope of some of the changes I suggested is too large for the intended use for the feature. Currently, all features as-requested appear to be present.

I'd prefer rounding off the rework for now, perhaps revisiting it for further changes if desired, however I'd imagine that the current implementations in the WIP branch are more than enough.

@Alicecomma
Copy link
Contributor

A short tutorial for the changes. The following XML tags and attributes have been added.

Attributes w/ defaults

  • AmmoCharge = "1"
  • ProjCharge = "1"
  • Overflow = "False"
  • WastefulOverflow = "False"
  • Underflow = "False"
  • RandBacklog = "False"
  • DefaultAmmoCount = "1"
  • IconDef = name of the tag (e.g Ammo_44Magnum_AP)
  • AmmoClass = (IconDef as AmmoDef).ammoClass
  • LabelCap = AmmoClass.label
  • LabelCapShort = AmmoClass.labelShort

Examples

Multiple charges per ammo
<Ammo_44Magnum_AP AmmoCharge="4" RandBacklog="True" Overflow="True">
	Bullet_44Magnum_AP
</Ammo_44Magnum_AP>

Here, the ammo would add 4 charges per consumed ammo. Each shot would consume 1 charge (by default). RandBacklog indicates that unloading ammo at a less-than-divisible-by-four chargecount will result in a 3/4, 2/4, 1/4 or 0/4 chance of recovering the ammo item. The overflow tag indicates that loading more than magazineSize (=6) charges into the magazine will result in an overflow (e.g 8/6). Charges are otherwise handled as normal, so no charges are wasted when too much ammunition is loaded.

Default behaviour without RandBacklog and Overflow is intended to be a wasteful overflow (too much loaded) and a wasteful underflow (no recovery), although currently they are a lack of loading behaviour (not loaded beyond AmmoCharge-intervals) and I'm not sure about the underflow.

Multiple charges per shot
<Ammo_44Magnum_HP ProjCharge="4" Underflow="True">
	Bullet_44Magnum_HP
</Ammo_44Magnum_HP>

Here, ammo adds 1 charge, but each shot consumes 4 charges. Whenever a shot is fired at a chargecount below four, the chargecount will underflow, requiring consumption of additional ammo to recover its value before being able to shoot again.

Without the Underflow tag, firing is intended to be possible but will not consume additional charges, as in the original FT implementation.

Multiple projectiles
<Ammo_44Magnum_FMJ>
	<Bullet_44Magnum_FMJ>1</Bullet_44Magnum_FMJ>
	<Bullet_44Magnum_AP>1</Bullet_44Magnum_AP>
	<Bullet_44Magnum_HP>1</Bullet_44Magnum_HP>
</Ammo_44Magnum_FMJ>

The construct above allows setting multiple types of projectiles to be fired from a single discharge. Trajectories of additional projectiles are very similar to the FIRST projectile in the list. It is allowed to have pelletCount set for each of these projectiles as well, resulting in even more projectiles being fired per shot. The syntax is exactly as for the CompExplosiveCE fragments list, with similar functionality otherwise.

  • The defaultAmmoCount is an indication for weapons with a very small magazine of how many pieces of ammo to add as default to the loadout. This value is defined on the AmmoDef, although it can be overridden here.

  • IconDef could allow is setting a ThingDef which represents the AmmoSetDef in the reload gizmo. However, right now it is automatically set to the only ammodef specified (in the tag).

  • AmmoClass is used mainly for the displayed string, and by default is set to the ammoClass of the iconAdder.

  • Attributes LabelCap and LabelCapShort are present. These would allow setting custom names for ammosets, to be displayed in the gizmos' floatmenus.

@Alicecomma
Copy link
Contributor

While the following changes could technically be added, they were somewhat ignored due to assumed time constraints as a result of a lack of team members working on the 1.1 update:

  • The ability to load multiple types of ammo into a weapon with a single ammotype selected. Currently, a single ammotype will fire a single ammo projectile and it is necessary to unload to switch to a different ammotype.
  • The ability to fire multiple types of projectiles with a single ammotype loaded (e.g 5-charge, 3-charge or 2-charge with the same ammo loaded). This can still be done, although each amount of charges used will be considered a different option (as in FMJ, AP, HP) in the gizmo.

Code for these things are there, although their implementation may likely take another week.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
C# Requires C# solution enhancement
Projects
None yet
Development

No branches or pull requests

3 participants