OrderOfThePorcupine / ProjectPorcupine

Project Porcupine: A Base-Building Game...in Space!
GNU General Public License v3.0
297 stars 89 forks source link

Implementation of Gear #35

Open BraedonWooding opened 7 years ago

BraedonWooding commented 7 years ago

Currently @SidneyArmitage is working on this.

Issue by longtomjr Saturday Jan 21, 2017 at 19:54 GMT # Sample: Friday Sep 13, 2013 at 22:58 GMT Originally opened as https://github.com/TeamPorcupine/ProjectPorcupine/issues/1763


This is open for discussion and will be edited. See original discussion #268

Functionality:

What needs discussion:

BraedonWooding commented 7 years ago

Comment by longtomjr Saturday Jan 21, 2017 at 19:58 GMT # Sample: Friday Sep 13, 2013 at 22:58 GMT


Notable Points

I think wearables should be special items to allow them to be placed in a stockpile or carried around (without being worn). - @NogginBops

  • We can implement this in a way similar to how gear work in rimworld.

This post might be edited to allow easier access to ease discussion

BraedonWooding commented 7 years ago

Comment by koosemose Saturday Jan 21, 2017 at 20:02 GMT # Sample: Friday Sep 13, 2013 at 22:58 GMT


One possible route to handle the "placeable in stockpile" aspect is similar to what I did for installable furniture, which is rather than having a near duplicate definition for the gear as inventory and as gear (or defining gear as sort of a subclass of inventory, or however else one might do it) is creating the inventory prototype in code, based off of the gear data. That way the "concept" of a spacesuit, for example, isn't split between two files.

BraedonWooding commented 7 years ago

Comment by dusho Sunday Jan 22, 2017 at 06:25 GMT # Sample: Friday Sep 13, 2013 at 22:58 GMT


Would propose to use component system again (what we have for furniture now). So Inventory with list of components and then implement WearableComponent class with properties needed to identify required slot for gear and then also gear stats and abilities. Dynamic attributes (e.g. damage) would be handled by Params (as is in Furniture as well). Probably code duplication can be saved if we would introduce class that can have components and Params and Furniture and Inventory would inherit from it.

Gear slots I would maybe place inside Species/Body what was discussed here #1528 . So e.g. for space suit, in Species/Body identify body parts (with tag?) that need to be covered by spacesuit in order to survive open space. Then character state would be dependent on those parts (slots) having proper gear there (having space helm but no space pants -> still get killed in open space).

BraedonWooding commented 7 years ago

Comment by koosemose Sunday Jan 22, 2017 at 08:58 GMT # Sample: Friday Sep 13, 2013 at 22:58 GMT


Components

I think for some stuff at least components would be appropriate, but I also think there should be a baseline of things that can be affected by gear, because, while not all gear may affect the same things, there are also some things that require just a single number (like maybe damage resistance, or cooling, or some such) for which an entire component is perhaps overkill (for example having to cycle through all components to find the one that gives damage resistance).

Params and Common stats

And for common stats I would also prefer having an actual variable, simply because, as much as I like Params, for core code accessing things via a string keyed object is, of course, vulnerable to issues resulting from name changes and not catching all the instances (since you can't just use the rename function of your IDE).

Species/Bodypart

As far as involving the Species/Body part thing, I personally am not a fan of nonhumanoid crew, and aside from that think that, at least initially, gear should be developed preset to work for humanoids, simply because trying to implement it to cover multiple body shapes initially will lead to excess complication in creating it.

BraedonWooding commented 7 years ago

Comment by dusho Sunday Jan 22, 2017 at 09:54 GMT # Sample: Friday Sep 13, 2013 at 22:58 GMT


Not sure what you mean by multiple components.. Inventory would have just one component (if it's suppose to be gear) - WearableComponent and it would contain definition for BaseStats which will contain those resistances and stuff listed.

<Component type="Wearable">
 <Effects>
  <BaseStatModifier type="Strength" bonusInPerc="30" />
  <ResistanceModifier type="Cold" value="100" />
 </Effects>
</Component>

As I understand Params, it was made so it's fully supporting modding and mods changing params on the fly. If you want to keep things flexible for modding (adding new stats, use them and have effect and so on) I don't see other way than having is as Params - so accessible through strings.

If the game will be humans only, then Species/Body is indeed not needed, but if there is some super-human or robot variation (with extra arm or something), then I think Species/Body is a way to go. I don't think it's overkill to use for human and if you start coding in generic way, it may be just applied for anything you will throw in later on.

BraedonWooding commented 7 years ago

Comment by koosemose Sunday Jan 22, 2017 at 10:36 GMT # Sample: Friday Sep 13, 2013 at 22:58 GMT


Components

I thought you were proposing having gear use components in such a way that, for example, Cold Resistance would be a component on the gear itself, and Strength boost would be another component.

Params vs C# variables

Params were made to support modding, but mostly because Lua can't have variables specific to an instance of a furniture (or whatever else), having actual C# variables will be just as accessible from modding, and allow cleaner code on our side. It should work equally as well using either params or c# variables, but with Params there's the string access issue. We could have the core effects of gear as variables and that doesn't prevent modders from rigging up their own via params, but if we can at least have the most common stuff as variables that would at least save us constantly having to convert from string to int or bool or whatever else, which, while I haven't done any profiling, I find it hard to imagine doesn't incur a fair bit of overhead.

Body forms

It's just with multiple body forms or even coding with the assumption that they will be a thing will mean at least a basic system for handling species (even if just humanoid) will need to be in place, and then gear will need the more complex coding required for basically unknown body forms. And of course either things like a space suit will have to, either be actually multiple gear for each slot, or have multiple versions for each body form. It drastically increases the workload required by a single developer to get a single system in place.

BraedonWooding commented 7 years ago

Comment by ComputerOverlord Friday Mar 31, 2017 at 18:51 GMT # Sample: Friday Sep 13, 2013 at 22:58 GMT


I was actually dissapointed when this wasn't about cogs... If our character is a space squid, amputee, or cybernetics enthusiast,, we'll want to add or remove slots. For humanoids, a structure like this would work

Heads

"Head"

Limbs

Arms

"Left" "Right"

Legs

"Left" "Right"`

And assume all creatures can wear chestplates

SidneyArmitage commented 7 years ago

So I was thinking that the best way to do this would be with full abstraction using a JSON and as such we would be able to allow for very flexible development of the equipment system. In this system even the character could be considered a piece of equipment which would allow for the customization of the equipment system. It would also allow for items to easily have sub slots. The following is an example of the what the different fields could be. Keep in mind that the less than (< and greater than(>) signs are used to encapsulate changing fields.

    "name": "<Display name>",
    "type": "<Slot type to connect to>",
    "slots": {
        "<slot name>": {
            "type": "<Slot type to be connected>",
                        "equip":"<NULL or the equipment to be inserted>"
        },
        "<slot name>": {
            "type": "<Slot type to be connected>",
                        "equip":"<NULL or the equipment to be inserted>"
        }
    },
    "properties":{
        "<property id>": "<property value>",
        "<property id>": "<property value>"
    }
}

The following is an example of this filled out for a character`s inventory system.

    "name": "equipment",
    "type": "FullBody",
    "slots": {
        "head": {
            "type": "Head",
        },
        "torso": {
            "type": "Torso",
        },
        "left arm": {
            "type": "Arm",
        },
        "right arm": {
            "type": "Arm",
        },
        "left leg": {
            "type": "Leg",
        },
        "right leg": {
            "type": "Leg",
        }
    }
}

The following is the previous example with what I may consider a full example load out.

"defaultCharacter" : {
    "name": "equipment",
    "type": "FullBody",
    "slots": {
        "head": {
            "type": "Head",
            "equip":"NULL"
        },
        "torso": {
            "type": "Torso",
            "equip":"NULL"
        },
        "left arm": {
            "type": "Arm",
            "equip":{
                "name": "arm",
                "type": "arm",
                "slots": {
                    "arm": {
                        "type": "sleeve",
                        "equip":"NULL"
                    },"hand": {
                        "type": "gripable",
                        "equip":"NULL"
                    }
                }
            }
        },
        "right arm": {
            "type": "Arm",
            "equip":{
                "name": "arm",
                "type": "arm",
                "slots": {
                    "arm": {
                        "type": "sleeve",
                        "equip":"NULL"
                    },"hand": {
                        "type": "gripable",
                        "equip":"NULL"
                    }
                }
            }
        },
        "left leg": {
            "type": "Leg",
            "equip":{
                "name": "leg",
                "type": "leg",
                "slots": {
                    "sleeve": {
                        "type": "legSleeve",
                        "equip":"NULL"
                    },"boot": {
                        "type": "boot",
                        "equip":"NULL"
                    }
                }
            }
        },
        "right leg": {
            "type": "Leg",
            "equip":{
                "name": "leg",
                "type": "leg",
                "slots": {
                    "sleeve": {
                        "type": "legSleeve",
                        "equip":"NULL"
                    },"boot": {
                        "type": "boot",
                        "equip":"NULL"
                    }
                }
            }
        }
    }
}

Using the properties in the first example equipment can be given properties and/ or links to assets ect.

koosemose commented 7 years ago

One potential issue with an abstracted system like this, as it stands there is no way to translate from things in a slot, to where they should be rendered as a sprite.

This is particularly notable for anything which goes on an extremity, as with a clearly defined system (such as all characters having the standard "humanoid" slots, it could be preset so that any character sprites have to fall into certain parameters (such as always having hands be in the same position), this would allow for example, a gun to properly stick with the hand. Whereas with an abstract system, you would either have to have data somewhere telling it where the hand is (and it would have to be with this equipment definition, else it would be pointless to have the abstract slots as it would have to stick to defined render areas), or something handheld will just always float in the same position.

SidneyArmitage commented 7 years ago

So like this?


    "type": "<Slot type to connect to>",
    "slots": {
        "<slot name>": {
            "type": "<Slot type to be connected>",
                        "equip":"<NULL or the equipment to be inserted>",
                    "properties":{
                     "<property id>": "<property value>",
                     "<property id>": "<property value>"
                    }
        },
        "<slot name>": {
            "type": "<Slot type to be connected>",
                        "equip":"<NULL or the equipment to be inserted>",
                    "properties":{
                     "<property id>": "<property value>",
                     "<property id>": "<property value>"
                    }
        }
    },
    "properties":{
        "<property id>": "<property value>",
        "<property id>": "<property value>"
    }
}```
SidneyArmitage commented 7 years ago

So I have changed the elements so that they have properties and no equip? Because we are going to still need a way to store it



 "defaultCharacter" : {
      "<property id>": "<property value>",
      "<property id>": "<property value>",
    "slots": {
        "head": {
          "<property id>": "<property value>",
          "<property id>": "<property value>"
        },
        "torso": {
           "<property id>": "<property value>",
           "<property id>": "<property value>"
        },
        "left arm": {
           "<property id>": "<property value>",
           "<property id>": "<property value>",
            "slots": {
                "arm": {
                   "<property id>": "<property value>",
                   "<property id>": "<property value>"
                },"hand": {           
                   "<property id>": "<property value>",
                   "<property id>": "<property value>"
                }
            }
            }
        },
        "right arm": {
           "<property id>": "<property value>",
           "<property id>": "<property value>",
            "slots": {
                    "arm": {
                       "<property id>": "<property value>",
                       "<property id>": "<property value>"
                    },"hand": {
                       "<property id>": "<property value>",
                       "<property id>": "<property value>"
                    }
                }
            }
        },
        "left leg": {
            "type": "Leg",
            "equip":{
                    "<property id>": "<property value>",
                    "<property id>": "<property value>",
                "slots": {
                    "sleeve": {
                       "<property id>": "<property value>",
                       "<property id>": "<property value>"
                    },"boot": {
                       "<property id>": "<property value>",
                       "<property id>": "<property value>"
                    }
                }
            }
        },
        "right leg": {
                "<property id>": "<property value>",
                "<property id>": "<property value>",
                "slots": {
                    "sleeve": {
                        "<property id>": "<property value>",
                        "<property id>": "<property value>"
                    },"boot": {
                        "<property id>": "<property value>",
                        "<property id>": "<property value>"
                    }
                }
            }
        }
    }
}```
koosemose commented 7 years ago

Something like that (though of course with my suggestion over Discord for a flatter structure).

SidneyArmitage commented 7 years ago

"Koosemose - Today at 4:21 AM @sichy Should have mentioned this last night... but I was tired, so I blame it on that. First, 1 part of Json structure that is required, Everything must be wrapped in a "Gear" tag (or whatever term you use), it should be in the singular rather than plural. Each "item" of gear should be wrapped in a tag, i.e. a spacesuit would be "SpaceSuit: { ... stuff ... }. Assume on Json reading code, the Gear class will receive the tag starting from , so in previous example a spacesuit would recieve "SpaceSuit: { ... stuff ... }. And finally it should implement IPrototypable, the xml related functions can be dummied, since they will of course need to be replaced with appropriate Json functions. And if I remember correctly, it will recieve a JObject (I could be wrong on that one, I'll update you if I discover it's different)"

BraedonWooding commented 5 years ago

No longer in milestone 0.3, pushed back till atleast 0.5 along with needs

koosemose commented 5 years ago

If you mean Needs as in the Needs systems, gear needs to exist in some form before Needs can be implemented to any notable degree, as many needs (such as for air), will make play impossible without gear to deal with it.

BraedonWooding commented 5 years ago

They should come in parallel (updated it to indicate that), since gear is useless without needs/stats, and needs/stats is useless without gear.

SidneyArmitage commented 5 years ago

The gear will be imported from its own prototype file called gear