pioneerspacesim / pioneer

A game of lonely space adventure
https://pioneerspacesim.net
1.62k stars 376 forks source link

Custom equipment #717

Closed Brianetta closed 10 years ago

Brianetta commented 12 years ago
[00:52] <_robn> Yep. One day all equipment and cargo will be decoupled from the engine. All scriptable, all modifier based
[00:52] <_robn> It will be delicious

Because If it isn't on the issue tracker it didn't happen, here we are. We need to specify our future equipment system, even if we don't actually code it right away.

We need to cater for:

You get the picture.

robn commented 12 years ago

I've given this some thought in the past. What I think I want is a system where all equipment and cargo provide modifiers to enable certain functions and affect how they work.

The idea is that every equipment or cargo item would provide some number (perhaps zero) of modifiers, each with some numeric value attached to it. What that number means depends on the mechanism that relies on it.

Some examples, off the top of my head:

Many "traditional" equipment items, like the scanner, would simply provide eg +1 scanner to enable/disable the equipment in question. However most could probably have some kind concept of "strength" applied. Again using the scanner as an example, each increment in the "scanner" modifier could correspond to some increase in scanner range. This then allows for a "Signal Amplifier" equipment that gives +50% scanner.

Some are trickier, like the ECM. Naively we could say that ECM gives +1 ecm while "Advanced ECM" gives +2 ecm. This forces fixed functions in the game engine. We could say +1 ecm and _+1 advancedecm but that's not really much better. It might be better to allow certain functions to be handed to Lua, but I'm not sure exactly what this looks like (but read on).

Costs could possibly be applied in this way, with an absolute 123.45 cost or possibly -123.45 money.

I figure we need active "always on" traits, like most of the examples above, and passive/informational traits like the cost one. The distinction is perhaps unimportant if we leave it up to the relevant game mechanism/subsystem to use it how and when it sees fit. Shields will interrogate the modifiers every physics step, while cost modifiers only get checked when actually trading something.

There may be a need to mark items as unique or limited in amount allowed, or conflicting with another item. I'm not sure how to mark this using simple modifiers; another mechanism may be necessary. The existing slot system might be a help here, but I kinda want to get rid of that.

It might be useful to be able to have an item that is not active right now, for example a spare widget stored in the cargo hold until you can find someone who can install it.

Crew and other mission-specific things could also apply modifiers. For example, hiring an "Elite Engineer" might give _+20% hyperspacerange, _+20% hullrepair, _-1 crewcabin, 123.45 wages. Travelling too close to a "Hyperspace Disruption Satellite" might give _-50% hyperspacerange, _+90% hyperspacecountdown

I expect that all these things will be defined by Lua. Ideally the game core will not know anything about equipment, cargo, free space, and so on. All it will know how to do is check modifiers and apply them. Its up to the appropriate bit of Lua API to populate those modifiers.

I also want items to be able to provide Lua callbacks/events that occur when stuff happens. I figure this is how recon cameras might operate. Items will also need to be able to provide UI elements, so we can add a camera button to the panel. More complicated items might need whole screens, but this should be possible via the planned UI overhaul and Lua UI interfaces.

I've thought about how some of this stuff might work but I don't have all the answers yet. Of course this is only my ideas; please take it apart and add more of your own :)

Brianetta commented 12 years ago

An "Elite Engineer" might specified in a Character object. We'd need some method of registering a character as crew.

fluffyfreak commented 12 years ago

It almost sounds like a component based system. You'd define what each component did in the code base, but you put the objects together using Lua/XML/etc.

Not sure in my own head exactly how it'd break down but for arguments sake lets take a laser cannon as an example, it's components might be: (Damagable, UseFuel, Laser, Mass) So when you updated the object it'd loop over each component and they'd all do their own thing: Damagable checks to see if it has any health - if not it emits a message saying the object is destroyed, UseFuel does nothing on update - but on it's "use" call it confirms if there is enough fuel or not, Laser would have a dependency on UseFuel and IF it does then it fires relying on whatever data it's been setup with, Mass is only used for deciding how much junk there is if Damagable emits its destruction, on purchase etc

You'd build up each object out of these component atoms and vary them by changing the data they used.

Of course there is the counter argument to all of this which is simply: Why bother? Does all of the above give us anything more than simply adding the extra 2 or 3 enums to the relevant arrays would? Because it introduces a lot of effort and moving everything into Lua doesn't really seem worth it.

winterdyne commented 12 years ago

You don't even need to define what components do particularly in the code base; All you need is a stat / variable wrapper that Lua scripts can interrogate sensibly.

I'm coding this now, as it's partly what I need for the custom mesh system I'm putting together. The principle is simple, game dataobjects (entity components) hold a number of named stats, and are derived from a parent entity. Stats are inherited from the parent. The C++ side syntax is something like this;

dataObject = equipmentDataTree.CreateDataObject("CargoBay"); // Creates the CargoBay object.
dataObject.setVariable("CargoCapacityT",1.0f);    // Hold 1 metric ton of cargo
dataObject.setVariable("PowerDrainMW",0.0f);     // Drain 0 MW of power

We can the do something like this:

dataObject = equipmentDataTree.CreateObject("StasisCargoBay","CargoBay");
dataObject.setVariable("PowerDrainMW",0.5f);                   // This type of cargo bay drains 0.5 MW of power
dataObject.setVariable("CargoDecayModifier",0.0001f);     // Perishable cargo looks for a CargoDecayModifier...

We obviously retrieve the stat we want using a getVariable( ) method. This checks parent dataObjects until it finds the named variable, just like inheriting an object in C++. Our example StasisCargoBay therefore has a 1.0 ton capacity, inherently.

Wrapping this up into a lua script accessible form means that we can have different cargo 'doing' different stuff and also responding sensibly - implementing a lua callback system will allow a change on a ship's position or stats to be checked by cargo (for example passengers - "I said get me to Mars, what the heck are we doing in Proxima Centauri?", or something like the reactor being knocked out or power being diverted to shields stopping the example stasis holds from working... Lots of possibilities.

Brianetta commented 12 years ago

Should PowerDrainMW simply be PowerMW - and signed?

winterdyne commented 12 years ago

Could be, was just an example, although that would make viable equipment checking have to sum all the components of a ship. Having the drain as a separate statistic allows you to make the assessment on a component by component basis, and also allows the player to monitor what systems on his ship are draining power, switch them on / off. In fact rather than have a set power draw per component, have a minium and optimum draw, so you can run a 5MW shield at a lower efficiency for example...

Brianetta commented 12 years ago

You still have to check each component for the presence of power drain; you'd just need to check the sign bit. Summing the lot would let you know if you were in deficit. It's an implementation detail, anyway.

winterdyne commented 12 years ago

Indeed, getting back to the point in question, does the data handling system I'm proposing look like it could have legs to you guys?

Brianetta commented 12 years ago

As long as it's exposed to Lua with an at least half-sane API, then sure (:

Brianetta commented 12 years ago

Wiki article

laarmen commented 12 years ago

For the record, I'm currently working on this at https://github.com/laarmen/pioneer/tree/luaequipment

laarmen commented 10 years ago

For this one too, I guess we could say that #1719 did the job.