space-wizards / space-station-14

A multiplayer game about paranoia and chaos on a space station. Remake of the cult-classic Space Station 13.
https://spacestation14.io
MIT License
2.71k stars 3.42k forks source link

Chemistry #170

Closed Acruid closed 3 years ago

Acruid commented 5 years ago

Entities need to be able to contain reagents, and this system controls it.

PrPleGoo commented 5 years ago

Make some Reagent prototype. This reagent prototype should implement some IMetabolizable interface. Metabolizer can be a Component on mobs or whatever with an enum type. The Metabolizer loops through a List that it gets from the solution.

The implementation of such an IMetabolizable would look something like this initially:

public class Beer : IMetabolizable
{
    private int Strength;
    public void Metabolize(Metabolizer metabolizer, float frameTime){
        metabolizer.dizzness+=Strength * frameTime;
    }
}

But if you want the metabolizers type to infuence that, say a metabolism reacts differently to a reagent. You need to either:

public void Metabolize(Metabolizer metabolizer, float frameTime){
    switch(metabolizer.Type)
    {
        case(Cat):
            MyPrivateMethod();
            break;
        case(Human):
        default:
            metabolizer.dizzness+= Strength * frameTime
            break;
    }
}

But that would be disgusting. Instead add a dictionary that can be filled via YML on the Reagent prototype. Then the implementation could look like this:

public void Metabolize(Metabolizer metabolizer, float frameTime){
{
    if(_dictionary.TryGetValue(metabolizer.Type, out var strategy))
    {
        strategy.Metabolize(metabolizer, frameTime);
    }
}

The resulting YML could look a little like this:

- type:reagent
  name: beer
  - type: handler
    metabolism: cat
    behavior:
    - type: DoThing
  - type: handler
    metabolism: human
    behavior:
    - type: MakeDizzy

With a MakeDizzy implementation as such:

public class MakeDizzy : IMetabolizable
{
    public void Metabolize(Metabolizer metabolizer, float frameTime){
    {
        metabolizer.dizzness+=10 * frameTime
    }
}

Because the specific behaviors are defined genericly they can also be initialized with different values:

- type:reagent
  name: beer
  - type: handler
    metabolism: human
    behavior:
    - type: MakeDizzy
      strength: 5
    - type: AddFood
      nutrition: 5
- type:reagent
  name: fancy beer
  - type: handler
    metabolism: human
    behavior:
    - type: MakeDizzy
      strength: 8
    - type: AddFood
      nutrition: 8
- type:reagent
  name: vodka
  - type: handler
    metabolism: human
    behavior:
    - type: MakeDizzy
      strength: 40

In the YML you could even define a some extra behaviors bound as a field. Maybe a default behavior that happens only when the reagent doesn't have a handler for your MetabolismType. And a default behavior that just always happens. Beer's YML could look a little like this:

- type:reagent
  name: beer
  - type: handler
    defaultExcludedBehavior:
    - type: MakeDizzy
    - type: AddFood
  - type: handler
    metabolism: rockPeople
    behavior:
    - type: AddFood

Pretty sure I'm messing up how to write YML here so take it all with a grain of salt.

PrPleGoo commented 5 years ago

Reagents can also interact with things outside a Metabolizer. Like splashing uranium or plasma on the floor or throwing thermite on a wall. Spraying people in the face with a bottle of soap also comes to mind. You could add simple strategy fields to the Reagent prototype. These would implement a specific interface like ITileSplasher or IAirExposable. When a reagent is then asked to perform the tile splashing or face touching or whatever it can just call the relevant interface where the reagent's interaction with different components is defined.

PrPleGoo commented 5 years ago

Define recipes somewhere else. Honestly outside the scope of this issue but since we're revved up. Recipes being the way they are in SS13 seems fine tbh. Where you define reagents, the required ratios, the resulting reagent, what happens after (think potasium and water), any catalysts or temperatures that need to (not) be present. Solutions can check for recipes when their contents change (ss13 does this) or on a tick call or whatever (how to not call all solutions every tick though?).

Moneyl commented 5 years ago

Could you assign me to this issue?

Moneyl commented 5 years ago

It's been a while since this issue was made, so I figure it's a good time to make a post with up to date info on this feature. Below are some key parts of chemistry and their statuses:

Lemme know if there's anything important missing, and I'll try to keep this issue up to date.

gradientvera commented 4 years ago

Is there anything left to do in regards of this issue, or can it be closed already?

PrPleGoo commented 4 years ago

@Zumorica Moneyl's comment still has some unticked boxes.

Moneyl commented 4 years ago

Yeah all the things that are unchecked in that list aren't done yet. The "Status effects on mobs when they ingest, inject, or have chemicals spilled on them" one is partially done. We have a bunch of common chem recipes from vg and a system for metabolism effects, but almost none of the chems have their metabolism or environmental effects implemented.

If we want to use this as a general chemistry feature issue it's not complete. Do you think it'd be a good idea to close this issue and open a bunch of smaller issues for the unchecked things in that list? Might make it easier for people to pick the larger feature apart rather than having to find this issue and read to the bottom.

gradientvera commented 4 years ago

Do you think it'd be a good idea to close this issue and open a bunch of smaller issues for the unchecked things in that list?

Yeah, I personally think that'd be much better for the reasons you listed. I'll leave the final decision in regards to closing this issue to the people who've actually coded chemistry though.