Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add some sort of ranged weapon to the game, other than throwing objects. #115

Open
underscoreharuuu opened this issue Apr 19, 2021 · 31 comments

Comments

@underscoreharuuu
Copy link

Basicly a bit like this: Add some sort of ranged weapons, perhaps simple slingshots, or things ranging up towards guns. While throwing is already in the game, it would make more sense to have a set limit, (If it doesn't have a range cap already,) to offset throwing, so that ranged weapons would feel useful rather than being throwing with specialized ammo. A few ideas: All weapons, thrown or any fired ranged weapon, should have a maximum distance. Now, this doesn't mean the fired object fades out of existence, but perhaps recoil would take effect, and the shot would miss, or hit something else. Also, guns would be much more powerful than other ranged weapons, but both the gun and ammo would have to be very rare. As for things like slingshots, use them like throwing, to sling things farther than throwing them. This is all I have right now, but I'll probably get more ideas later.

@Mikolaj
Copy link
Member

Mikolaj commented Apr 19, 2021

Thanks a lot. That's a sound basis for brainstorming. Let's commence. :)

Edit: whether it's self-contained to only the Allure content definitions, or requires engine extension (most likely) or many extensions is to be seen after the brainstorming. I suggest we focus on gameplay fun vs gameplay complexity. If that trade-off is right, the implementation should not be a problem.

Edit2: as in all brainstorming let's start with blue sky wild contradicting ideas leave trade-offs for a later phase.

@underscoreharuuu
Copy link
Author

underscoreharuuu commented Apr 19, 2021

Alright, if we are going with just ideas first, without any balances or trade-offs, then a few ideas would be this: guns like some pistols and rifles, maybe some kind of energy weapon, and then more "old" ranged weapons like slingshots and bows. Maybe even a rocket launcher. But that seems a bit overpowered, at least in my opinion.
EDIT: An extra idea, perhaps a self charging laser gun, as there is already a "charge" system for items, maybe even like a turret or such strapped to whoever wears it.

@Mikolaj
Copy link
Member

Mikolaj commented Apr 19, 2021

Here's the description of the simplified throwing physics, as implemented for throwing currently: https://github.com/LambdaHack/LambdaHack/wiki/Item-statistics

In particular, projectiles have speeds computed from the weights, They also have bonuses or maluses to their speeds and length of flight derived from their shape, density, etc. Currently, stats (e.g., from equipment) of the actor that throws do not affect the speed nor distance in any way, but it can be implemented in the engine. Normally, an item flies for exactly two standard game turns, then drops.

Edit: And here's a suggestion of AK47 bullet speeds, in the modules that calculates the speeds, etc.: https://github.com/LambdaHack/LambdaHack/blob/6d68d0dbe52d137422c0cb69be02df6abaf090b1/engine-src/Game/LambdaHack/Common/Time.hs#L245

@underscoreharuuu
Copy link
Author

So the engine is based off of throwing physics, and would probably need to be reworked to work with things like guns? Reading through both things, it would seem like part of the system would need to be reworked to account for the speeds of bullets.

@Mikolaj
Copy link
Member

Mikolaj commented Apr 19, 2021

Yes, I guess the bullets would be too deadly with the current system --- you can compute this using modifyDamageBySpeed, where the minimal supported damage right now is 1. Or, alternatively to reworking that or lowering minimal damage, we'd need to find reasons to give maluses to bullets, e.g., that they pass through instead of using the whole energy for damage (but tumbling bullets actually do).

However, regardless how we rescale, this does not seem to be a big problem. Physically, shooting is a special case of throwing and the simplifications I've made fit shooting very well (e.g., 0 angle of hrow, that is, the throw is perfectly horizontal --- exactly as guns (or crossbows) are used, as opposed to bows).

What problems can you forsee?

Edit: perhaps I can foresee one problem: with these speeds projectiles would not be seen in the air, or perhaps in only one or two frames if many actors observe a projectile at once. OTOH, isn't that realistic?

@underscoreharuuu
Copy link
Author

The only problem I can see right now is, as you said, the projectile not being seen, but that is a realistic thing, as you don't see a bullet in travel unless some sort of slow motion capture is used.

@Mikolaj
Copy link
Member

Mikolaj commented Apr 19, 2021

Hah, actually, with high enough SkWait skill, the player can already do something like a slow motion camera, by pressing S-5 instead of 5 for waiting (the same with other movement keysets) and then IIRC only 0.1 of turn passes.

Wild ideas about launchers from old TODO notes:

  • just a sling that can propel any item, a sling in equipment with ThrowMod 60 100 5 aspect adds 60% speed, 100% flight time, 5 pierces to the propelled item; however, what if many slings in equipment? so perhaps activate a sling, even in shared stash, and the activation adds the bonus? [edit: but for how long? also, this is a burden on the player --- first a few keypresses to activate bonus, then a couple to throw]

  • with the separate explicitly chosen sling and item being propelled, how to simply choose the sling and the ammo in UI, ideally with a single keypress?

  • cheap ranged weapons as 'bow with 999 arrows' that is really a stack of 999
    arrows with extra stats; perhaps crafted by merging a bow and 10 arrows
    perhaps can be unmerged when at least 1 arrow remains, or auto-unmerge
    when 0 arrows remain; but this removes the fun of 'let's use this special
    piece of ammo for this single shot'; but I have flasks for that (and specialized explosives)

  • implement ranged shooters similar to wands; find arrows, which do less
    damage than darts, but can be joined with bow and then the bow
    creates missiles (fast flying arrow?) that are more powerful?
    quiver is a UI pain, so instead have a time-consuming item
    construction and deconstruction via crafting;
    make wand ammo expensive/rare, shooter ammo cheap;
    enough ammo has to be collected to merge with launcher
    (training launcher use in the process)
    so, bows and pistols are in pack, not in eqp
    and activating a bow creates projectiles, shoots it at cursor and
    subtracts one ammo from the bow [edit: not sure how to represent the spent ammo; perhaps don't?]

  • perhaps different launchers should have different "projectile" actors,
    created when shooting, not ammo items existing before the shot,
    and the projectiles would have ThrowMod, ToRangedDamage, etc.
    depending on their kind, independent of ammo (then needed only to
    keep track of how many shots are permitted) [edit: this is the idea that activated launchers should create ammo items, not take them from inventory; makes sense]

  • how to incorporate the SkProject skill (that the player will, in the future, have the option to increase at level up) into the launcher implementation? Extra bonuses to projectiles? but ammo and launcher already to that; so perhaps permit creation or usage of launchers only when SkProject high enough? or limit what ammo can be used? or replenish ammo with high enough skill? or suffer, or not, recoil that pushes the actor back [edit: or pulls forth]?

@underscoreharuuu
Copy link
Author

Now, I don't have much coding experience, but I assume that the "project" skill is related to vision, so here is my idea: If the skill isn't high enough, maybe (if this is even possible) give the shots fired a higher chance to "miss", and, for larger weapons, if you don't have enough skill, it could push you back, possibly into a wall or such. Also, because Calm is a thing, prevent reloading of weapons if Calm is too low, like how you cant manage or identify equipment if your Calm is to low. Calm could also play a factor in the accuracy of weapons, perhaps making them miss, or otherwise.

@Mikolaj
Copy link
Member

Mikolaj commented Apr 19, 2021

Pardon the jargon: in UI the SkProject stat displays as 'fling stat' in # menu. You can read its description when you press Enter.

Missing is not yet implemented (except missing other projectiles in the same tile) but noted as future idea. I like the recoil mechanics and to tie it exclusively to the skill. It's possible the recoil can be implemented even in Allure content alone by adding PushActor of PullActor (not sure which) to the launcher effects definition, depending on how the launchers are implemented. Recoil mitigation, OTOH, could be implemented by adding fake weight to the actor, based on the skill (which requires engine extension anyway, but a simple one).

Noted the Calm idea. Linking it to misses risks a vicious cycle of compounded failure, but banning reloads may be handy, e.g., if we see min-maxxing reload cycle distracts the player from the fun of the battle.

@underscoreharuuu
Copy link
Author

underscoreharuuu commented Apr 19, 2021

For the recoil, things like pistols, rifles, etc, would push you back, and things with rocket propulsion would push you forward, (I think that is how it works with rocket launchers IRL, not sure)
EDIT: Actually, most rocket launchers have almost no recoil, just the backblast of heat and fumes from the launching of the rocket.

@Mikolaj
Copy link
Member

Mikolaj commented Apr 19, 2021

Let me keep in this comment a list of brainstorming ideas that emerged from discussion as plausible (later on we'd thin the list, estimate gameplay and implementation cost/benefit, make the list consistent, pick a small subset for inclusion in next release as a pilot programme). As we create more idea and discuss them, I will update it.

  • recoil; things like pistols, rifles, etc, would push you back, and things with rocket propulsion would pull you forward (for fun, even if not common IRL);
  • SkProject would mitigate recoil via fake weight proportional to it
  • fast gun bullets are fun and fine with the current throwing mechanics (they are very distinct, because the bullets can't be easily evaded), though the damage needs checking and probably lowering via maluses or rescaling in engine
  • an option is to have guns as activable items that create bullets; then they can recharge (realism: manage recoil or recharge capacitors) and there's no problem with stacking
  • a cheap fun engine extension (no UI complication) is to let each launcher in equipment additively increase speed or time or piercing (probably time-in-the-air is easiest to balance and distinct enough, but unique launchers can increase the other two) of every item flung by an actor
  • however, we'd need to devise an explanation how two equipped slings increase flinging range more than one sling; with air cannons we could perhaps claim they are attached sequentially, resulting in a twice more powerful cannon
  • to use such launchers we'd need to lower range of normal thrown things to compensate (lower speed and increase base damage or lower time-in-the-air)
  • launcher flavours that fit this mechanics are slings and air cannnons
  • later on, perhaps bows, etc., can be created by crafting, where one of the ingredients is ammo; not sure if and how that should be different from guns
  • general item containers (lots of coding and extra complexity, but powerful and deep and replaces most of the above), in particular guns as containers for ammo (and gun attachments); details in this and surrounding comments: Add some sort of ranged weapon to the game, other than throwing objects. #115 (comment)

@underscoreharuuu
Copy link
Author

Though what about turret-style enemies as well? Like, having a robot that cant move, but it has the ability to shoot.

@Mikolaj
Copy link
Member

Mikolaj commented Apr 19, 2021

Haven't you mentioned that one already? Let's discuss this one now, in that case. The game already has turret-like throwing robots that don't have melee attacks. How would the shooting turrets differ?

@underscoreharuuu
Copy link
Author

underscoreharuuu commented Apr 19, 2021

Shooting turrets would be more dangerous, as bullets would most likely pierce almost any armor anyone is wearing, but they would either be lightly armored or not shoot very often, to slightly balance it.
EDIT: I’ll come back to this tomorrow, I have things to do.

@Mikolaj
Copy link
Member

Mikolaj commented Apr 20, 2021

I looked more closely and actually, there is only one kind of immobile actors with ranged attacks:

activeFence = ItemKind
{ isymbol = 'f'
, iname = "active fence"
, ifreq = [(ROBOT, 30), (IMMOBILE_ROBOT, 20)]
, iflavour = zipPlain [BrMagenta]
, icount = 1
, irarity = [(5 * 10/15, 0), (10, 7), (20, 10)]
, iverbHit = "thud"
, iweight = 80000
, idamage = 0
, iaspects = [ AddSkill SkArmorMelee 30, AddSkill SkArmorRanged 15
, AddSkill SkMaxHP 20, AddSkill SkMaxCalm 999
, AddSkill SkSpeed 20, AddSkill SkNocto 2
, AddSkill SkWait 1
, AddSkill SkProject 3 -- no brain, but can lob
, SetFlag Durable ]
, ieffects = []
, idesc = "Makeshift, mostly non-lethal, autonomous perimeter defense outpost."
, ikit = [ (S_VISION_6, COrgan)
, (NEEDLE, CStash), (CAN_OF_STICKY_FOAM, CStash) ]
-- can of sticky foam is exploitable, but it spawns
-- reasonably often only on one level and not for
-- a long period
}

What's your experience with that foe?

@underscoreharuuu
Copy link
Author

Well, (I just woke up don’t mind me) Most of the time I either avoided it, or was able to get close enough to destroy it because of parrying or blocking the hits.

@Mikolaj
Copy link
Member

Mikolaj commented Apr 20, 2021

Huh, no hurry, we have all the time in the world to develop this feature. :) No deadline for v0.10.3.0 nor for v0.11.

My experience is similar: active fence is problematic, because it can't be lured to where I can gang up on it in melee, avoiding the ranged hits. It also tends to hit me from out of my LOS, especially if my Calm is drained, thanks to using spotters.

I imagine, if active fence could instead hit me from the other side of the map, for much higher damage, I'd be quite unhappy.

Any ideas how to make the turrets interestingly distinct from active fence in a different way than by making its ranged attack longer and stronger? Or else, how to let the player cope with the extra power in a fun way? Warn the player? Mark on the map the area affected by the sniper? Other wild ideas?

@underscoreharuuu
Copy link
Author

Maybe have some sort of warning when going to a floor with turrets, perhaps in the level description that shows upon entering a level from a stair, when it gives a description of what the area was used for. Or, have their sight range be low, (for an example, maybe the camera is damaged and it can’t see far) so you can sneak past them if needed.

@Mikolaj
Copy link
Member

Mikolaj commented Apr 20, 2021

Noted about restricting them to only one level. I'm sceptical about warnings in level description --- some people treat is a fluff, some don't read it and it doesn't warn about which tiles are safe, if any, so not much benefit learning you are doomed if you can't help it.

Regarding sight range, see "spotters" above. We would need to create a brand new faction only for turrets (or one for each turret?) to make sure they can only shoot within their own LOS, not faction's. OTOH complicating the rules so that some actors can't use squad sight require major engine changes that also make FOV computation much slower. Any other ideas about making the player less helpless vs turrets, even wilder perhaps? You say they may be old/decrepit/damages --- great, in what ways other than sight range?

@underscoreharuuu
Copy link
Author

If the sight thing would slow it down too much, maybe make it very inaccurate, so that most shots miss, but there is still that risk of getting hit. I’ll think of some other things as well, but that is all I have for now.

@Mikolaj
Copy link
Member

Mikolaj commented Apr 20, 2021

Sure, let's leave the turret among the wild ideas for now. A wild idea from me: its servos can be broken and it can shoot only in one direction along a single line. For best effects, mark the line specially on the map (it's pitted from the turret hitting it often).

However, the deadliness problem is somehow relevant to any foes with guns, even though moving actors are easier to dispatch with some cunning. Perhaps some late game armor should protect very well against ranged weapons (or only bullets) and the single level with such foes should be far off, when the player can have such an armor. A wild idea is to actually model spaceship hull decompression that happens after the first shot (that hits the outer hull wall, or just any gun shot) and so have all actors be buffeted around the level, making any subsequent shots impossible and melee more likely as the actors randomly collide. Edit: or push every actor each turn towards the hull's breach; not sure if closed doors should make a room safe from this effect.

Independently, we can now return to the launchers that work at much slower speeds and so don't have the problem of excessive damage. I haven't yet evaluated my and yours brainstorming ideas about that. When I find some time, I will. Feel free to do that, too, and to agument your ideas (editing or just marking your old comments as supreseded by new ones).

@underscoreharuuu
Copy link
Author

Alright, if we are on the topic of launchers, slingshots, and maybe some kind of air-powered cannon. For the slingshot, it could just improve the "fling" skill, or be loaded with items and give a boost to the speed. As for the cannon, pretty much the same, except you launch things with pressurized air. I'll probably go back and edit some of my comments with ideas.

@Mikolaj
Copy link
Member

Mikolaj commented Apr 24, 2021

I've gone through your ideas. Great job. Let me discuss:

I wasn't clear, by launchers I mean any ranged weapons other than simple throwing. We ruled out guns of any size for now (including rocket launchers and lethal energy weapons that you mention), because they are harder to balance due to one-hit-kill problem that would require a stronger stealth focus in this permadeath game. What remains is slings and air-powered cannons for launching arbitrary items that you propose, but also bows shooting arrows, crossbows shooting bolts, long range non-lethal weapons (tazers, foam shooters, any SciFi future developments), etc.

Noted the improvement to shooting skill as the benefit of a launcher (but if so, we'd need to flesh out the skill). Speed boost, effectively increasing both range and damage, makes sense, too, and require only a minor engine extension. Your idea of "loading" item also solves the problem of 10 launchers at once in equipment, cumulatively boosting speed, and so range and damage, to insane levels. How would the "loading" work, mechanics-wise and UI-wise?

Alternatively to speed increase, your idea from the initial comment about limiting range (probably via speed decrease and base damage increase) of thrown weapons would indeed make the speed-increasing launchers distinct enough from throwing (and the future guns would be also distinct via high speed, making evasion from the projectiles impossible). If damage increase is too steep, we could increase time-in-the-air instead of speed. This would also solve the problem of stacking launchers, because range increases give diminishing returns, so how many launchers to stack becomes an interesting decision for the player. That's good, let me add it to the list of plausible ideas.

Noted the idea that launchers, particularly energy-based, can have cooldowns (need to recharge). This is a possible way of limiting their power, especially if many worn at once. However, we'd need to know which launcher to discharge after a throw (unless we discharge all) and that plays well with either the loading of items into launchers or with guns, if they are implemented as activated items in inventory, not as boosts to throwing (which is probably a bad idea and not distinct enough from slings). Let me add the recharging of guns to the list of plausible ideas.

Have I missed anything major or did you come up with extra ideas?

TODO: review my old proposals quoted in one of the earlier comments

@Mikolaj
Copy link
Member

Mikolaj commented Apr 24, 2021

I've reviewed my old notes cited above and it turns out we came up with many of the same ideas, which confirms their potential and that they should not be too unrealistic for the player to learn and use.

@underscoreharuuu: would you like to add anything to the plausible ideas list above? Any clarification needed? The next steps would be to pick the first feature to implement, judge if it adds to gameplay more than it takes away in complexity, discuss implementation, share the tasks.

@underscoreharuuu
Copy link
Author

On the topic of “loading” a launcher, it could have some sort of way to be triggered from equipment, (For example, a menu to activate specialized equipment.) Triggering a launcher could give you the option to reload, (Assuming it is a single-shot launcher,) or to fire said launcher once it is loaded.
On the topic of any other launchers, some kind of basic energy launcher/sidearm, (Using a self charging mechanic, but would deal low damage and stun, shooting a slow energy “pellet” as the attack.) or, a grenade launcher, to fire any grenades you might find.
For any low power “energy” launcher, (tasers, for example) they could fire, have a random/set cooldown, and then send some kind of message that they can fire again (If that would work)
Most likely other things, but that is all I have for now. Better ideas will probably come later once I have time to think of things.

@Mikolaj
Copy link
Member

Mikolaj commented Apr 25, 2021

Noted loading via triggering the launcher. However, this is still a lot of UI actions per single shot: choose launcher, activate, choose ammo, then on some later turn choose launcher again, activate to fire. I like this mechanics, because they player can prepare launchers before combat and, during combat, firing the launcher has an extra cost in that the next shot would require 2 turns and whether it's worth spending 2 turns may sometimes be an interesting decision. However, to consider this feature plausible, I'd need a way to lower the UI cost. E.g., perhaps default to previous ammo somehow or perhaps load and shoot immediately after via less keystrokes than the two commands separated (e.g., prompt "shoot immediately?" after loading succeeds and turn is spent).
Regarding a grenade launcher, limiting the class of items that fit into a launcher is yet another complication. One that we'd need to handle anyway, if we choose to support a gun that can choose ammo type for each shot separately (hollow tip, full metal jacket, explosive, amor-piercing, etc.), but that we don't need to handle if the gun, after being reloaded, can fire only the loaded kind of ammo.
Regarding charging, this is already implemented and cooldown status of equipped weapons is displayed at the bottom line. However, if guns are triggerable from shared stash, a "recharged again" message can be easily added.

@underscoreharuuu
Copy link
Author

On how to make the UI actions shorter, as you said, both default ammo and a “fire now” option, but also item filters. For example, filter by tag, (which is already kind of a thing, as you can filter by objects that can be activated to use them.) Regarding reloading anything, (that uses ammo,) I believe I’ve said this before, but Calm can effect reloading, at least on some weapons. (For example, a bow or crossbow would be harder to reload than say, an air cannon.) In my spare time I’ll make some kind of list to keep track of my ideas, as I’ll think of things, then sometimes forget. (More just a place to put ideas, if anything.)

@Mikolaj
Copy link
Member

Mikolaj commented Apr 25, 2021

A side note and getting ahead of ourselves: the current convention in UI is that the item on the floor under an actor is affected when the actor triggers another item (whether owned by the actor or inside a wall or floor). If we stick to this, which we don't have to, reloading a launcher would looks as follows: 1 kepress 'r', 1 or more: pick the ammo to be dropped, 1 't', 1 or more: choose the launcher to load it. So 4 keypresses total plus 2 menus to scroll through. With defaulting to previous ammo that would sometimes become: 1 't', 1 or more: choose launcher to reload and given there is no ammo on the ground, it loads the previous one, 2 keypresses, one menu to navigate.
A specialized UI just for loading would be: 1 't', 1 or more: choose launcher to reload and it opens a menu, 1 or more: choose ammo from the menu. That's 3 keypresses, 2 menus to navigate. With default ammo, that's 1 't', 1 or more: choose launcher, 1 answer "load previous ammo y/n". That's 3 keypresses, 1 menu.

@Mikolaj
Copy link
Member

Mikolaj commented Apr 25, 2021

Another side note: having the following a 7 distinct item kinds is easy: Rifle with 20 AP Ammo, Rifle with 18 HE Ammo, Pistol with 5 AP Ammo, Empty Rifle, Empty Pistol, 20 AP Ammo Magazine and 20 HE Ammo Magazine. OTOH, having Sling with loaded {any of 1000 different items} is difficult and requires a general notion of items appearing together (or of item containers containing others), which then changes the code for item naming, description, dropping, throwing, identifying, duplicating, and a lot more.

However, once we have item containers, we can also have a Weak Chip of Zapping, from which a skilled actor can move the zapping code (and 50 other codes) to Strong Chip of Zapping that has a greater effect or 20 other kinds of chips, with multiple uses, area effect, etc. The same for any other kinds of consumable and their containers, including fountains, actor organs, etc.

So this is high cost of implementation and a fair complication of game rules and UI, but the notion is very general and can be used for all launchers and many other kinds of items. It's also relatively natural and so should be easy to learn by the players as opposed to, say, multiple slings in equipment additively affecting throwing range. Tough choice. I think I have somewhere old notes about item containers, but I don't think they offer any hope of doing this cheaply, but rather of how to amortize the cost by using in many places.

@Mikolaj
Copy link
Member

Mikolaj commented Apr 27, 2021

Note to self: items containers (and weapon attachments, weapon ammo, etc.) could we implemented by changing the current type assigning the quantity and cooldowns of each copy to each item in question

type ItemBag = EM.EnumMap ItemId ItemQuant
type ItemQuant = (Int, ItemTimers)
type ItemTimers = [ItemTimer]

where ItemBag is the contents of actor equipment, floor, wall, shared stash of a faction, etc. to a recursive variant

type ItemBag = EM.EnumMap ItemId ItemQuant
type ItemQuant = (Int, ItemTimers, ItemSubitems)
type ItemTimers = [ItemTimer]
type ItemSubitems = [ItemBag]

Edit: the complete sepration of cooldowns and subitems is simple, but to keep it consistent we have to avoid, e.g., a mechanics that a charging container can't be accessed or that reloading a weapon resets its cooldown. I think that's fine.

Edit2: however, this is problematic, because it naturally leads a rifle with AP ammo and a rifle with HE ammo, both in inventory, to share the same slot, making it impossible for an actor to select which one gets activated. That's because, currently, each ItemId (each key in the enum map) corresponds to a single slot (single number-letter symbol) in a UI item menu. Breaking that invariant would be painful (the code is complex and ugly already), but perhaps necessary.
An option is to accept the inability to select the rilfe to activate (the engine can choose one with the most numerous ammo, say), just as currently when dropping a portion of an item stack, the items with cooldown are automatically chosen first IIRC and there is no possibility to choose otherwise. If a rule is imposed that guns need to be in equipment to be fired, as opposed to the shared inventory stash or the floor, at least different teammates would be able to fire with a different ammo for the same kind of gun, even if one actor still can't. However, equipping multiple identical long guns is not realistic anyway, so the UI restriction may be acceptable.
BTW, perhaps a gun in equipment should fire when activated and reload only when all ammo spent and standing over ammo. If changing the ammo is required, the gun should be moved to the floor or inventory and then activating reloads ammo from the floor (or even from other places, if that's not too confusing for the player).

Edi3: However, if I have 10 copies of flask item, each with different content, it's nonsensical not being able to pick which one to quaff. To make it work, content should not be associated to a container, but the other way around. So I'd have the healing elixir item with one copy in a flask, two other copies in two bottles, another copy in a special vial that doubles the effect, another copy without a container. When triggering the elixir I would not be able to choose which copy is activated, which is obviously bad as well and there's no cheap hack to make it work via insisting that elixirs are stored in equipment (and a personal potion pouch is a bad idea due to micromanagement of moving potions among teammates). So, restricting UI choices is a bad idea. We need separate UI menu slots of each combination of item and its set of subitems.

Edit4: While we need separate slots for combinations of items, differing cooldowns don't require yet more slots. However, we need to keep track which cooldown belongs to which combination, so the type definitions above are wrong, sharing cooldowns indiscriminately among all combinations.

Edit5: The definition above is actually fine (though very lax), if we don't assign ItemId to items based only on their kind and stats, but also on their contents. So, although we would not have the 7 distinct item kinds I mentioned in previous comment: Rifle with 20 AP Ammo, Rifle with 18 HE Ammo, Pistol with 5 AP Ammo, Empty Rifle, Empty Pistol, 20 AP Ammo Magazine and 20 HE Ammo Magazine, we would have 7 distinct ItemId values, stored in some special map for easy lookup, and every item would change its ItemId whenever its contents changes (but not cooldown). That actually makes sense because, e.g., AI preference for an item is a map from ItemId to a special type and AI preference for a gun should be different when it's loaded and according to the ammo kind (and attachment kinds, but not number of copies, sadly). However, the state space explodes if the number of ammo should differentiates ItemId, so we can't do that, but it's probably fine: actors won't have the ability to choose if the almost empty or almost full of their guns is fired (the engine would choose the almost empty one if cooldowns are not applicable, the other one, otherwise).
So, whenever ammo is spent, the guns gets transformed into an empty one and added to the stack of 3 other empty guns of the same kind, etc. Alternatively, ammo and other content can be always auto-compacted to the full capacity of the containers and empty containers removed from the stack. Yet alternatively, the ammo (and, say, a single scope) can be shared among all copies from the stack (very helpful when the copies can have cooldowns) and so copies become empty only when all ammo is spent (or when there's even less ammo pieces (and attachements) than container copies, to make sure empty flasks are removed from the stack when a potion quaffed). The type definitions could be tightened with such an interpretation, so perhaps it's also easier to grasp by the player. The tight types are (ItemId choice depends only on the keys of its ItemSubitems map, not its values):

type ItemBag = EM.EnumMap ItemId ItemQuant
type ItemQuant = (Int, ItemTimers, ItemSubitems)
type ItemTimers = [ItemTimer]
type ItemSubitems = ItemBag

Edit6: The set of contained items can be a field of the Item record, because it's never hidden and it never changes (as opposed to the full ItemBag that also lists numbers and charges (cooldowns) of the contained items). This does not waste memory, because the same set needs to be saved in the ItemRev hashmap so that the proper ItemId can be assigned to a created item, if any copies were already created previously.

Edit7: loose design notes:
it would be nice to unify subitems and stores (equipment is an item)
but for that, ItemId of a store needs to be unchanged as subitems change
so the bag map would need to be indexed by id and bag of subitems
and their subitems, too
so not a good idea
similarly items such as backpacks that extend equipment
would lead to dozens of ItemId as their content changes and so are costly
so equipment expansion should be an ad-hoc actor aspect

if we want weapon attachments to be firmly affixed to a particular copy,
and there are a few possible attachments only per any gun
and they can be repeated on a gun a very small number of times,
we can define a single additional gun kind for any subset of the attachments.
also resulting in a different ItemId for items of that kind;
then when a gun with attachments is on cooldown, other guns can't use
the attachments

Edi8: apparentely github can't handle so long or so many times edited comments, so I will continue in a new one.

@Mikolaj Mikolaj added hard and removed medium labels May 5, 2021
@Mikolaj
Copy link
Member

Mikolaj commented May 5, 2021

Continued from previous comment:

Edit8: It's possible to implement guns with ammo by adding a flag NotStackable to the gun items and keeping the type definitions from the start of this comment. However, vials as containers for various elixirs are still broken in this setup. The flag may be used, though, as an addition to the improved type definitions listed later in that comment, to implement guns that have individual amounts of ammo and sets of attachments that are not implicitly moved between copies in the same equipment. Bags that increase equipment capacity (and even equipments and bodies as individual items) would work fine with such a flag.

Then, we have as many gun ItemIds (and a corresponding items stored in game state, e.g., the hash table) as there are individual gun copies created during the game, even if they are completely the same and have the same attachments and ammo, always. However, we avoid as many ItemId are there are ammo number plus attachment sets combinations throughout the game, which is potentially a much larger number, proportional to max ammo capacity of a gun. So if the game has few gun copies with large ammo capacity and being used a lot, this is a beneficial tradeof. However, if the game has gun shops with thousands of gun copies that are always fully reloaded and never used, this is a bad trade-off.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

2 participants