Friday, July 6, 2012

Pondering construction plans in ADOM II

I used this evening to do more work on ADOM II - initially I planned to get archer abilities finished (because basically only enhanced fletchery was missing). This lead to an amazing side trek I have not yet returned from as I am right now wrangling with major changes to the construction system :-^

Let me explain...

In ADOM Classic building things always is a special case. ADOM II in contrast got the notion of construction plans to build things when I introduced tinkers. A construction plan in Java roughly is defined like this:

public interface ConstructionPlan
{
    boolean isKnownBy(Being being);


    boolean isExecutableBy(Being being, Position targetPosition);


    Yield getYield();


    boolean executeBy(Being being, Position targetPosition, int sequenceNumber);


    List<ConstructionPlanRequirement> getRequirements();


    int getActionsRequiredToBuildOneYield(Being being);


   ...
}


So a construction plan can
  • determine if it is known by an arbitrary being,
  • if the being could execute the actual construction work,
  • describe the yield of the construction work (is the terminology correct?),
  • actually be executed,
  • describe its requirements and
  • tell you how long it takes to execute the construction plan (counted in actions).
There already now are construction plans for various types of ships, walls and other stuff.

For fletchery in my first implementation attempt I fell back into bad ADOM Classic habits and implemented a special case. Then I remembered construction plans as the seemingly better abstraction and that's where it gets complicated:
  • In ADOM Classic items are pretty simple things and all item types are very different (e.g. mithril arrows and sternum arrows are totally different item types). 
  • This is different in ADOM II: There is only one item type for arrows (actually there are hunting arrows, sheaf arrows and war arrows but the details don't matter) and each such item has a main material (e.g. mithril or iron).
  • In ADOM Classic most missiles were supposedly wood.
  • Since we have more detail in ADOM II it probably would make sense to allow building different missile types with fletchery (e.g. mithril hunting arrows or eternium war arrows).
  • If I were to use construction plans for that I'd either have to define different plans for each type of arrow  in combination with the material (which is not really a problem but could become pretty hard to keep under control for the player if you know a lot of construction plans) or I'd have to make construction plans more flexible to allow for variant requirements (e.g. to build an arrow you need a wooden shaft and some metal tip - and then the plan would have to derive the specific yield from the chosen variant materials).
  • As construction plans are totally generic and requirements basically are complex Boolean expressions this seems to be difficult... or I am missing something.
Then I noticed that it wouldn't be fun to just be able to create one arrow as the result of a construction plan. Ok, I thought, no problem, do something like "4d6 arrows result from one wooden log and...". Oops, I need the tips. So I'd need different kind of construction plan requirements like ("to produce 4d6 mithril arrows you need as many mithril tips and wooden shafts as arrows a total time resulting from a base time multiplied by the amount of arrows"). Which totally does not fit into my current implementation.

So I really need to think about whether I either need to throw away the whole current implementation or patch it somehow... just for that damn fletchery skill as arrows are the first thing to build where you want to build larger quantities with one command and need material resources dependent on the number of things produced. Oh well... I guess, I'm having to change the whole implementation.

The result will be a much more flexible construction system for future ideas but I really had hoped to avoid such large changes in that area.

The life of a programmer... and then people wonder why it's costly to change things in 150.000+ lines of mostly undocumented legacy code... the irony.

Cheers!

P.S.: Yes, I know that this post was probably totally incomprehensible mumble-jumble for non-programmers. Nonetheless I need to talk about this ;-)

17 comments:

  1. Quick comment:

    Looks like you need some kind of CompositeConstructionPlan, which is basically a list of sub construction plans: steel arrow = steel shaft + steel tip. (You could get complex trees of plans like this)

    The "steel arrow" plan would still need to specify the overhead of constructing the arrow from both components though, like extra time, extra components (glue? :))...

    ReplyDelete
  2. Hi Thomas, loved your video at indiegogo, especially that big red D, turned my blood to ice with fear.

    When I tried out ADOM II, I got the impression that constructing just about anything is really hard. You have to invest tons and tons of skill into construction even to make things as simple as a boat, and then materials aren't easy to get ahold of either.

    Have you played Minecraft or Terraria? Those games have re-invented inventing... and the result is: It's Good! Maybe it would be cool if ADOMII did construction more along those lines.

    ReplyDelete
  3. I think maybe construction plans need to contain component parts. Each component should affect the finished product in a different way, but ultimately the choice of material used for each part should be the player's choice.

    So to take a simple object like an arrow. Perhaps it only needs a shaft and a head. To produce the arrow (or arrows as I agree you don't want to make them one at a time), you would choose a material for the shaft and that would perhaps define the accuracy of the arrow, then choose a tip that would affect the damage.

    You could preset "sensible" materials for each component, but I would think that if the player wants to produce an arrow with a cork tip and a cotton shaft then that's up to them (although obviously, such an arrow wouldn't be launchable from a bow). By leaving it flexible like this, you could allow for some inventive and unexpected applications for the construction plans.

    With more complex items like boats, I guess you'd have component parts for hulls and oars and rudders etc.

    ReplyDelete
    Replies
    1. I would say that an arrow has three parts -- arrowhead, shaft and the feathers. It's the feathers that stabilize the flight path, and therefore affect the accuracy.

      First order of business: If it's going to be hard to make arrows, they need to be more available elsewhere -- for example there could be large bundles of arrows in the shops.
      Also, workshops -- if I'm going to make arrows, I don't want to do it in a dungeon where a monster could attack me at any moment, unless I absolutely don't have another choice.

      But, let's look at the individual components more clearly.

      Arrowhead: Arrowhead is the thing that actually deals damage. It does thrust damage, I guess, since it only hits a single point, although blunt arrows that deal blunt damage are possible as well. Arrowheads would have to be made in advance. Possible materials are all metals, bones of various animals, and even some stones (like flint or obsidian). There are several methods how to attach them to the shaft, like binding with vines, screwing or gluing... I think that part can be left unspecified because it depends on the exact type.

      Arrowhead, however, also affects the accuracy, since it needs to be heavy to make the arrow's center of gravity close to the head. This would translate into accuracy penalties if the arrowhead is too light compared to the rest of the arrow (think eternium head on iron shaft). I think this is a reason why there even ARE arrowheads (I'm not an expert) and why you don't simply shoot homogeneous sticks.

      The shaft: The main stat affected by the shaft would be the probability of breaking. Shaft is basically a narrow cylinder made of some material, and if the material snaps too easily (wood) or breaks easily (glass), that would make the arrow prone to breaking. On the other hand, eternium shafts would basically never break.
      And, of course, even if the arrow DOES break, the arrowhead should still be salvageable. So should be the broken shaft, if it's metallic.

      Finally, the feathers. This would be a very fun addition because every new bird (or beast like griffons) could have different kind of feathers, and feathers of magical beasts (griffons, hippogriffs, sphinxs, harpies), could very well have some interesting effects on arrows.

      I don't know enough about crossbow bolts to extend my analysis (I know little about arrows as it is), but one thing that should hold is that a bolt should compute its probability of breaking in a different way since it's shorter, so there's less places where it can break. On the other hand, it hits with greater force.

      Delete
    2. So, in short, the accuracy would be dependent on feathers and on the weight ratio of tip to shaft, while damage would be dependent on the sharpness of the tip and on the total weight of the projectile (tip and shaft, since feathers are negligible). This means that for blunt arrows to have any reasonable effect, the tip would have to be made of lead or something...

      I wonder how the salvaging would work? Perhaps salvaging could be an alternate action to picking things up? You pick up things that can be useful as they are, and you salvage the trash. And the trash wouldn't even appear to you on the screen unless you possess the necessary skills to salvage it.

      A character without fletchery would simply ignore broken arrows, while a seasoned fletcher would see them and could decide to take the arrowheads from them or salvage the broken shafts. (How fun would it be if druids got, as a class power, the ability to "melt" wood and transform it into new items, like weaponsmiths do with metals?)

      I wonder how affixes would be handled. I can see two basic options: have affixes each part of the arrow separately or have one set of affixes for the missile as a whole. The first option would make it much more attractive to salvage unusual arrows (that broken arrow had enchantment to deal more damage, I'd better take the arrowhead and re-use it elsewhere), the second one would mean that once you dismantle the arrow, the special ability is gone forever.

      Delete
    3. (How fun would it be if druids got, as a class power, the ability to "melt" wood and transform it into new items, like weaponsmiths do with metals?)

      Best - Idea - EVER

      Delete
  4. int maxAttempts = Math.Min(countTips,countShafts);
    DateTime productionTime = singleArrowProdTime * maxAttempts;
    int newArroes = 0;
    for(int attempt = 0; attempt < maxAttempts; attempt++)
    {
    bool ok = TryProduceSingleNewArrow();
    if (ok)
    {
    newArroes++;
    ...
    }
    }

    ReplyDelete
    Replies
    1. That's basically the ADOM Classic approach ;-)

      Delete
  5. Hi,
    I think you can also try to rename current ConstructionPlan to ConstructionStep, and the make a new class ConstructionPlan which aggregates the ConstructionStep objects, which will have similary to the ConstructionStep class methods.

    ReplyDelete
  6. Yeah, an example that programming roguelikes is complex!

    How about the following (of course, this is high-level pseudocode, and only guessing what you might have now):

    - ConstructionPlanRequirements could be objects with:
    * a boolean method canFulfillRequirement(Item it) that tells us whether an item meets the requirement (e.g. for the arrow head, we would look for either ingots or pieces of wood),
    * a state that tells us whether the requirement has already been fulfilled or not and with which item,
    * a fulfill(Item it) method that tries to fulfill the requirement with the given item. If the item is valid as per the canFulfillRequirement() method, then it changes the state of the requirement to fulfilled, and it stores the given item.
    * Specific construction plan requirements that need to be parameterized can have extra methods. For example, the ArrowheadRequirement would have a getArrowHeadMaterial() method that would return the material of the item that was used to fulfill the requirement.

    - Modify getYield() method in ConstructionPlan so that it takes as a parameter the fulfilled requirements. With this, we could do something like:

    Yield getYield ( List fulfilledReqs )
    {
    List theItems = ArrowFactory.createBunchOfArrows ( dice.throw("3d6") , fulfilledReqs.get(0).getArrowHeadMaterial() );
    return new Yield ( theItems );
    }

    ReplyDelete
  7. I just want to give an example how elegant and amazingly crafting can be if you implement "Minecraft" style craft.
    The outcome will be extend game pleasure to new dimension.


    [ ][ ][ ]
    [ ][ ][ ]
    [ ][ ][ ]

    Place items:

    [ ][12\][ ]
    [ ][12\][ ]
    [ ][12\][ ]

    Combine [yes] [no]
    Result: Congratulation ! You just create 12 wooden arrows

    [ ][7m][ ]
    [ ][7\][ ]
    [ ][7\][ ]

    Combine [yes] [no]
    Result: Congratulation ! You just create 7 mithril headed wooden arrows

    [ ][3m] [ ]
    [ ][3i] [ ]
    [ ][3i] [ ]

    Combine [yes] [no]
    Result: Congratulation ! You just create 3 mithril headed iron arrows

    [ ][ ][ ]
    [10\][ ][10\]
    [10\][10\][10\]

    Combine [yes] [no]
    Result: Congratulation ! You just create 1 wooden boat

    ReplyDelete
  8. [3m][][]
    [3/][][]
    [3/][][]
    3 mithril headed wooden spears

    [][3m][]
    [][3/][]
    [][3/][]
    3 mithril headed wooden javelines

    [][][3m]
    [][][3/]
    [][][3/]
    3 mithril headed wooden arrows

    [][][3m]
    [][3/][]
    [3/][][]
    3 mithril headed wooden long spears

    ReplyDelete
  9. I'm guessing that currently, the implementation of isExecutableBy() will call getRequirements(), and check if the Being satisfies each ConstructionPlanRequirement.

    Well, maybe you could separate 'requirements' and 'materials', with 'materials' being the stuff that gets used up to construct the item, while 'requirements' are things like needing to have an anvil, hammer, tongs, and furnace in order to make a sword.

    Then you can have the requirements check work recursively on the materials. For each requirement, if that item has its own ConstructionPlan, see if the Being meets the requirements and has the materials for *that*, and so on down to the lowest-level, non-constructable materials (trees, boulders, dead dragons, etc.) This way, you can ultimately build up a tree of every possible way the Being could make the item, and (if this is the player), present them with that list along with how many times they can do each of them, the time units each one takes.

    As an example, say that the materials to construct a hot dog are a bun and a weiner. The materials to make a bun are flour and water, and the only material to make a weiner is a dead pig. We'll assume the player has all the necessary ovens, butcher's knives, weinermancy training, and whatever else is necessary. They also happen to have three buns and five weiners, and have just happened across a poor pig that drowned in a river after tripping over a sack of flour.

    So, looking at the hot dog construction plan, we first check for buns.
    - There are three buns in the player's inventory, so that's an option for the bun requirement
    -- There's a sack of flour, let's say enough to make ten buns, and a limitless source of water. So another option for the bun requirement would be to bake fresh buns.

    Similarly, for weiners:
    - There are five weiners in the player's inventory
    -- There's a pig whose flesh and organs can be shaped by dark magics into fifty delicious meat tubes

    So, we know the player can make hot dogs. Now present them with the material options.

    So, first option:
    1. Use buns (3 in inventory)
    2. Make buns (can make up to 10)

    So, the player can choose to use up to 3 buns, and to make up to 10 more. If they chose to make any buns, they'd have to go through a similar dialogue for that (although in cases like this where there's only one option for how to make the buns, you could make things more convenient by just having that option appear directly in the parent option)

    Choosing how to supply the weiners would work similarly, but constrained such that the player needs to pick the same number of weiners as buns.

    So, that's the basic idea. A couple things to watch out for, though:
    - If you have any construction plans where two materials share a sub-material, you'll need additional logic that calculates how many of the submaterial can be used for one while still having enough left for the other.
    - If you have a material that can be used to make a sub material (some construction plans might be *deconstruction* plans, such being able to turn a log raft back into logs), you'll need additional logic to prevent the material check from looping endlessly

    ReplyDelete
  10. Well, you could always "abstract" the tips. Wooden log + mithril ingot = 4d6 mithril arrows. No hassle and player can move on to the important part, which is shooting goblins in the face with said arrows ;).

    ReplyDelete
  11. Yes, you want to be careful not to overthink construction. Some classes will want to do a lot with it (tinkers, smiths, other?). But for archers, I think you can assume that they just have a stash of arrowheads, these being the easiest thing to recover and most durable part of an arrow. Same for fletching feathers.

    Or on another level, you could say that a wasted arrow turns into an arrowhead of the right type when it falls.

    Having to find a good source of feathers, wood, and metal, then smith arrowheads, then make arrows--this doesn't sound like fun for a class that is not very invested in building things.

    ReplyDelete
    Replies
    1. Well, the question is: Is it even true that archers should be good in fletchery? After all, archers are trained to use missile weapons -- not necessarily making provisional ammo. If someone should be good in fletchery, it would be logically RANGERS, whose shtick is "surviving in wilderness". A reasonably civilized archer would probably buy his arrows, just like a civilized fighter buys his swords instead of forging his own.

      This would make basic fletchery a sort of last-ditch resort for an archer, and he could use wooden sticks to make out provisional arrows -- nothing more than sharpened sticks with right weighting. Usable in emergency, but vastly inferior to properly crafted arrows made by professionals.

      If you want really strong arrows, making them yourself would be so hard that it would only be an option for the most dedicated fletchers. Most of archers would buy them or get them from enemies, invest to arrows that are as unbreakable as possible, etc.

      There would be middle ground, i.e. fairly passable arrows that a fletcher could make reasonably easily, but the real top-rate stuff, that needs more than just a knife, a piece of wood, and a few turns.

      Delete
  12. Nice information, these constructions plans are very helpful to me. Thanks for sharing.

    Construction Job Responsibilities

    ReplyDelete