Friday, May 31, 2013

Menus Everywhere

Saving and Loading

Menus! Right now there are no in-game menus or overlays and everything but new game and quit game do what they are supposed to do. The next task on the list is to fully implement saving/loading. Additionally, I wanted to fix up the menu transition in and out of game. There are two minor issues: you lose your selection of units and your mouse position is also reset.

Also I've been keeping a list of infrastructure debt but that list will be tackled on an as-needed basis to get a working game (also lets me have more time to figure out what I really need to do to solve those problems because I'm fairly unfamiliar with future issues that might arise in Cultura).

Saving/Loading

The saving and loading dialogs need you to be able to select save files or save to disk. I don't know if you really want a full file explorer or just a simplistic "save/load" console style. I'm leaning toward console style.

CEGUI provides something called the layout container which I plan to use to create the list of files to save/load. When the dialog is loaded it scans the save/load director for files following the *.sav format. This creates a cross-platform issue which will be ignored for now (we'll just use the windows directory system to load up the list of files). For each file we create a window and add it to the layout container. Then we will have the same functor used as the subscriber to the onClick event of each. We will set userData on each window so that when the user later clicks on it, in the listener function we can then determine what was clicked and set the correct file as the one to be saved/loaded (also do fancy UI stuff like highlight that box and unhighlight all other boxes).

Here are some CEGUI references that are relevant:

The user then clicks on save/load to perform the actual save or load. For now, I will not allow user defined file names. Instead they will be automatically generated.

Currently, the serialisation works on creating a byte array that is then saved to disk. The serialisation is a bit manual. All objects that need to be serialised essentially derive from CGameEntity. The serialisation uses a custom class known as a CByteBuffer. Objects write to a byte buffer when serialisation or reads from the byte buffer when deserialising. Each class must know how to read/write its member variables inside its serialisation function. Each class calls the super class's serialisation function. That way you get a chain serialisation occurring. It's somewhat tricky to choose which variables inside a class to serialise but there are special considerations (which can be cleaned up with refactoring later): not serialising temporary member variables such as graphic entity pointers.

Also, to simplify serialisation, units/structures and many other entities are being compacted. Originally, I had subclasses for units and structures for different types of units/structures. However, when you get to serialisation that becomes a problem (I have a CUnit pointer but is it really a CAnimal?). Instead of something fancy, the different levels will be compacted into one with a few classes added to record large blobs of data (a new StorageStates class for structures).

I will have to serialise actions as well and in that case, I will have to serialise what action was just serialised (so I can perform proper desserialisation). This means adding a few constants to the UnitAction class and a variable for UnitActionType.

Compacting the Classes

In an effort to simplify serialization, I am compacting my unit and structure classes into a single class with several "container" classes hanging off of them.

Unit:

  • CombatStats
  • EquipmentStats
  • CounterStats
  • Carried items
  • Location

Structure:

  • CombatStats
  • CounterStats
  • StorageStats
  • Location

CombatStats:

  • Hitpoints
  • Damage

EquipmentStats:

  • Item* HeadSlot
  • Torso
  • LeftArm
  • RightArm
  • LeftHand (for weapons or equipment)
  • RightHand (two handed weapons will have both slots point to the same item
  • LeftLeg
  • RightLeg
  • LeftFoot
  • RightFoot

CounterStats:

  • int MoveCounter
  • AttackCounter
  • bool incrementMoveCounter //returns true when move counter gets reset and the unit should move, false otherwise

StorageStats:

  • std::vector Capacity //-1 means unlimited, uses constants for item categories, checks narrowest category first before moving upward, for alpha, just have all/food/non-food categories
  • std::vector StoredAmount //list that mirrors capacity, must update all categories when giving or taking items
  • std::vector StoredItems
  • int GiveItem(Item* item) //returns amount not stored
  • void TakeItem(Item* item)

Carried items can just be a StorageStats object that is not using most of the functionality and only has a single storage limit for all items.

Location is a std::pair to indicate a map location

Tuesday, May 14, 2013

Alpha Design

Designing Cultura

I'd like to pause for a second to develop a clear goal for the alpha and just blab a bit about the game I want to create.

Checklist

  • RTS Interface
  • Management Interfaces
  • Diplomacy and AI Factions
  • Menu Basics

RTS Interface

The core of the game is very much an RTS, the ability to scroll around and watch your empire do work in real time. But, the ultimate intention is not for you to individually control units. As you progress you spend more time managing your empire than you do individual people. There are three main RTS interfaces that will happen: Direct, Partial and Indirect. Direct control means units that do nothing unless you tell them to do things. This will remain true of military units in battle and of only some civilians units (all units at the beginning of stone age will be directly controlled). As you automate more of your labour through the various management interfaces they begin to act automatically. The intention is that as your society gets large and you try to maintain direct control, then you will likely lack enough focus to keep everything running smoothly. Partial control means individuals who are tasked to certain tasks but you can still give them one-time orders. Those one time orders will cause them to deviated from their automated behaviour but once completed they will return to their original task. For indirect control, units will not listen to your orders at all. Instead the only way to manage them is through the management interfaces. At much later stages of the game, such as well into the classical age, portions of the population act completely autonomously and you only affect their behaviour like any government of today: incentives, tax policies, tariffs and so on.

Management Interfaces

The management interfaces are a slew of UI dialogs that you can access in game (which will pause the game) that let you handle different aspects of your society. These interfaces are likely to have to morph through the times (depending on technology). The goal of these interfaces is to lower the amount of direct individual interaction with units in order to manage your society. It is also through this interface to do some special actions such as claiming or abandoning areas.

Wealth Management: An interface that looks at the total stocks, the stocks owned by regions, by individual people and allows you to distribute wealth to individuals. The accuracy, or the ability to have these numbers, will likely depend on technology and bureaucratic size. In addition to that, I am intending to add administrative cost (someone has to count, keep track of records and then physically hand out goods) to distributing goods as an incentive to streamline good distribution without direct government (you) intervention.

Region/Empire Management: This allows you to look at population level and owned structures. It also allows you to claim or abandon regions. Abandoning regions is more common early on when you might leave to find new food sources. As well you can see happiness/health score and perhaps secondary information such as change of disease, revolt or natural disaster. A tab or transition to another screen should allow you to set various social policy. Right now, I'm only thinking of taxation but whether I wanted a "rule" base engine or something less fancy I'll have to contemplate. I don't want it too complex to play but this is already a fairly niche game so whatever.

In addition to the Empire Management it should probably feature a second for population and animal growth (for directly owned animal herds). Since population growth is dependent on food it should be affected here. I figure all new births are in the spring. Because what the hey.

Industry Management: This allows you to assign labour to particular tasks, for all seasons, for particular seasons. Also allows you to set production minimums, maximums, quotas, rate limits and so on.

Technology/Culture: Here you can see the tech tree, culture trait leanings and of course spend tech/culture points to acquire new techs or cultural traits. This should also show you the cumulative effect of your various cultural traits

Diplomacy and AI Factions

The other meat of the game is about diplomacy and so I need at least the existence of AI factions in the alpha. Maybe the AI will be really bad or whatever, but I just need them to exist to allow diplomacy to be conducted (albeit not very useful with a player that does nothing). Of course later on AI factions will play a major role in making the game "fun" because they will be a dynamic part of the world.

Menu Basics

For the alpha, at the very least, we need new game functionality (with world generation) and saving/loading. Other than that, I don't think I'll spend any effort into graphics/audio settings (well in fact I have no audio as of right now :) ). I just need a fully functional menu.

Inspiration

There are a number of games inspiring me to make Cultura, the two most important are Civilization and Dwarf Fortress. Unlike Civilization, this is an RTS (so I suppose more like Rise of Nations). Unlike Dwarf Fortress this is about managing a society rather than individual dwarves.

But because I focus less on individual needs and more on social needs, the focus of the player changes to bigger management decisions with industry, diplomacy, trade and war. Those reflect ideas I pulled from other games. An industry-chain for each finished good; this is like Settlers. Diplomacy based on trade-routes but also intelligently reacting AI: trade is like Anno series and diplomacy is more like Galactic Civilization where they don't simply have a flat point-score in making decisions, they take in the context of the socio-economic condition of the game. But the world is vibrant, with a mixture of mundane, fantasy and steampunk. The exploration of the world is more like Master of Magic where you always wonder what strange new resources exist "over there", or what creatures you might encounter and must deal with.

Ultimately, I'd like to eventually see a game where some Mundane society is sending a trade ship across the ocean carrying ivory carvings when it runs into a kraken just off the coast of a fantasy nation under blockade. Then... BROADSIDE!

Look and Feel

I'd like to capitalize on the 2dness of the graphics that I am implementing and what would be a good fit is a "painterly" look. I think that'd be the most bang for the buck. It'd look really slick but not require any extra special graphics tricks compared to what I am already doing.

For the game itself I'd want it to be a mixture of direct control and indirect management. The entire goal is for you to be building a history with the society you are shaping from the very first days of the discovery of fire all the way on forward. It should be personal, it should be your tribe and you should feel like its leader. But, it's not meant to be about controlling individual people, it's about the whole society. So as you progress you should feel like you are capable of doing more grand things while the society takes care of itself.

You'd start off with a bunch of cave people, the first races being human/elf/ogre, and you need to go out and explore the world. You must find natural caves at first until later you can begin to construct buildings. Before sedentary life you might abandon places seasonally to go on the hunt for more food in different regions. The environment is vibrant, lively with an ecosystem you have to follow. But it's a living environment. Perhaps you want more cherry trees instead of pine trees, so you slowly over time shift the eco system of regions. Then as the land becomes more productive, you can support more people and so you go on from there to build a greater and greater society.

The tech tree is meant to be slow and more about differentiating your society from others. So it's more about very specific technologies with a small section devoted to cultural technologies where you define culture specific luxuries and cuisine. You develop specific good-preferences, value systems and so on which will affect how you manage your society (preference for specific goods will push you to develop those industries) and how you might interact with others (a preference for peace versus war).

Another aspect of the tech tree I hope to differentiate from Civilization is the elimination of the "1000 year war" problem. Where, in the time span of a single war, you can move through 2-3 ages worth of weapons. I think that breaks a lot of the suspension of disbelief. By the time you send your archers and warriors to the frontline, there are axemen and chariots following up behind and finally swordsmen and catapults. I want Cultura to be a game where you don't just "feel" technological progress but there IS technological progress throughout the game yet at the same time you play out whole scenarios in the same tech age.

I accomplish that through being very specific with technology. You develop the burin before a chisel and needle. You have to research scrapers before you can do leatherworking. It's very in-depth and involves a lot of small improvements to society. There will be no clear line between stone age and copper age. You will just slowly shift your industries into the latter. But, I like having a player be able to invest their time into something, have it last and mean something and for them to be able to sit there and formulate grand plans for world domination, to have to worry about this faction and that, while still using stone axes and after all those plans have finished... new technologies and factions come about to upset the balance. I want a player to fight 2-3 major wars just in one age, have convincing stories and history about it and then move into the copper age.

The ultimate goal is for a player to find archaeological ruins of their own making in Cultura. Why, these caves? These were the ones you lived in back in the early stone age but now that you've built Rome in a neighbouring region, they are merely a curiosity.

Less talking. More Raiding.

Saturday, May 11, 2013

Attacking

Attacking

Now available in Cultura, punching other people. To the death.

And after punching the ogre into poop... WE DINE!

Actually, I will make it a cultural trait choice if you want to perform cannibalism or not. Otherwise the resource node that is created will contain the stuff the unit had equipped and/or carried.

The attack action itself is actually fairly simple. It's similar to the move action. It does a distance check to target, moves closer if necessary and when in range it then calls the combatResolver to do damage. In the future when events are implemented it will throw up an attack event rather than call the function directly.

Secondary Action List:

  • Unit Creator
  • Action Architecture
  • Faction redesign

In order to cope with the growing needs of Cultura there are a few items that I'm going to address before my mind melts at the bad code.

Unit Creator

The unit creator is a class with a lot of static functions used primarily to create game entity objects. You call its various functions like createUnit or createAnimal, pass in an integer for an id and it spits back out a pointer to the new object. This is useful for several reasons: it can have an internal counter to use as a unit id (or resource node id etc.) which will be useful for decoupling some classes from direct usage of units/structures. It will know what numbers to assign to what for basic versions of units (I may add in more parameters later to make the entityCreator do more stuff but we'll keep it simple for now). These numbers include hp, damage, mesh names (although this might be changed later, at least it'll be fixed in one place) and so on. One place to make everything, one place to change how anything is made.

There is a little bit of design decision with how the type identifier ids work. Basically, there are around 10-20 raw good categories (I still have to hash out the exact design later) and in each there are several different material types. It would be nice to map those different materials to the item type that they are. For example: oak, pine, silverwood, ironwood would all map to wood for item type. There are all sorts of crazy complex stuff you can think of but rather than do anything special there'll just be a min and max constant for each set of materials and any value that falls between them inclusively will be mapped to a particular item type.

Doing that is useful for a situation such as a deer carcass. You kill a deer it drops an item of type carcass, and the material of the carcass is like deer antler (bone), deer meat (meat), deer bone (bone) and deer skin (skin). When you process the carcass it would be an easy conversion to know that the carcass (deer antler) converts into bone (deer antler).

Action Architecture

As mentioned, I'm switching CUnit* references and other such direct references to objects in actions into knowledge only of integer-based ids. The reason is to decouple actions from those classes. Right now, the flow is GameState->Faction->Unit->Action. But then action has knowledge of the gameState and units. That's just poop. It also makes memory management a nightmare. For instance, say an action is referencing a resource node and then it is deleted. No way to know and you'll get an access violation error. If instead you only know of the node by its id, then you must call gameState->getResourceNodeById(int id) and then if it returns null, then you know it's been destroyed and thus you should stop trying to harvest it.

I can remove the gameState coupling when I introduce an event system but for now, we'll go with the id-based system. We are going to "decouple" through coupling only through the gameState object. When there is an event system we blow away those references make them into events instead.

Faction

Factions, which contain the units and structures, will now need to keep knowledge of units by id and structures by id. The cost of an id is an integer per unit/structure and also a pointer to each unit/structure within a hash set (probably going to use an std::unordered_map). I think that's a reasonable cost for O(1) access time from actions to units when they only know about the id.

As an aside, I had some offline feedback about the fact that the cavemen in the game were carrying about balls of water and punching gazelles. Thus here is potential cover art for Cultura to reflect just that:

                                   `                                                                                       
                                                                                                                           
                                                                                                                           
                                                                                                                           
                                                                                                                           
                                                                           ,       `                    `                  
                                           @                                           `                   `.              
                                           @@              ,@@@@@@`              #.    :@@@@@              @@@ @@+         
        ,@'+##+#@@@@@@:           @@@;    @@@       `   @@@@@@@@@@+       @@@'   @@    @@@@@@#   @@@@@@@  @@@@:@@@@        
         @@@@@@@@@@@@@:          @@@@+    @@@   #@# @@@,@@@@@@@@@@+     ,@@@@@  '@@`   @@@@@@#   @@@@@@@: .@@@@@@@         
        `@@@@@@@@@@@@@:         @@@@@,   +@@@@  @@@:@@@  @#  @@@@@'     @@@@@#  @@@@   @@@@@@    @@@@@@@:   @@@@@.         
        .@@@@@@@@@@@@@.        @@@@@     @@@@@  @@@@@@@  @@  @@@        @@@ #   @@@@   @@@@@@    @@@@@@@     @@@@          
         +@@@@@@@@@@@#         @@@@      @@@@#  @@@@@@@      @@@       ,@@      @@@@`  #@@@@     @@@@@@`     @@@           
         ;+ .+@@@@@            @@@      @@@@@@+ @@@@@@@      @@@       :@@     #@@@@@  @@@@@#    @@@@@       @@@           
              @@@@@            @@@      @@@@@@@ @@@@@@@     #@@@       ;@@@@@  @@@@@@  @@@@@@@  .@@@@@       @@@           
              @@@@@           ;@@@+  @  @#@@@@@ @@@@@@@     @@@@        @@@@@# @@@.+@  @@@@@@@; ;@@@@@`     #@@@           
           @@@@@@@@@@         :@@@@@;@ @@'@@#@@ @@@@@@@     @@@@        @@@@@+:@@@ @@@ @@@,@@@@  ;  @'@     @@@@           
          @@@@@@@@@@@@        .@@@@#@@ @@@@+@@@`@@@# :.   ;              @@@   @@      :@   ,                ':            
           @@@@@@@@@@          @@@@@@` '@,                      ;@:           :                :#                          
           @@@@@@@@@@           :;'                `        @@@@@@@                         @@,;#''@@                      
           @@@@@@+  :.           ,             `           `@@@@@@@                     +.@#       @'#@                    
                :                                           '@@@@                     :  @+ :,  ` :` #'@;                  
             @  `            +      #    '     ;:    @@@@@' `@@@@@                  ` +@@ `         '  #,@                 
            @@@       `  .@ @@@  : ;@@:@#@:  .@@@@,  @@@@ @  @@@#@                 ;@'@@          ;     :#.                
           @@@@  +@@@+@ @@@@@@#  ;@@@@@@#@   @@@@@@  @#@@ @  @@@@#                 @@@    `      :@@      @                
           @@@@  @@@@@@  @@@@@   :@@@@@@#@`  @@@@@@@ +@@#@   @@@@                '@@@@@@        .@  #@ .   @               
           @@@@` #@@@@@  #@@@@    @@@@#@#@: :@@@.@@@ :+#@@   @@@@@@@            #@@@#.#          @@@.'@`   @               
           @@@@@  @@@@@,  @@@@  # @@@@@@#@'  @@@:@@@  @@#@   @@@@@#@`           @@@:@@@#          @@@@+@' . @              
           @@@@@  @@@@@@  @@@@    @@@@@@#@@  @@@ @@@  @@@@@  @@@@@@@@          :@@@@.' ;@            `@@@ + @              
           @@@@@  @@@@@@  +@@     @@@ @ @+@  @@@@@@   @@@#@  +@@++             ;@@,@#@#.,@@            @@ ' @              
          ,@@#@@' @@:@@@  '@@     @@@   @@@  @@@@@#   @@#@                     ,@@@@',#@: .            '. ' @              
          @@@@@@@@@@ @@@  @@@+   .@@@   @@@  @@+@@                             :@@@@@',,#@                ' @              
          @@@@@@@#@  .'    @`      :`         #::              ##@             @@@@:###..#                :+@              
         ,@@ ;                                       @@#@@@@@@@@@@@@           #@@#@@# ##                ' @@              
                                                +#@  '@+`;+'@@@#@@#@@          #@@.;@@',@@ @           @ @:@.              
                                                 :@@@@; @`##@#@@##+:@@         #@@@@'.@;`'.. :,   +  +,@#@@@               
                                               .+ @#@##+@@#@@@@;@++@@@'@,      :@+#@@;.@@ # @'   @  @ @ ;+@'               
                                                 ;@@## #@.#+'@@`@@@@@@#@@       @@@ .@ ;, ':.@ @;@ ##,@@@#@                
                                                @@`#@#.@@+#@#+#@@@;#@,##@@      ;#@@##@@.@ @+:#'+ ;+ ::'@@@                
                                               @@@@;@@:@#@@@@@#@#@#@#,@@@@       @@@@ :# ;,'@+@@@: @#@@ @@                 
                                               @+@':@+#@,#.+## ++@@@@@@@@@        #@@@@@@#@.;@@@@@@@@@@@,@                 
                                               +.@@#@.+@'###:@#`+#@@@@@@@@:`      '@@@@@@ @@+@@@@@@@@@@@@@                 
                                              @@@@@#@;#:@#@`@#@ @@@@@@@@@ #        @#@@@@@###@@@@@@@@@@@,@                 
                                                . @#+#@ @@@@.@#@#@@#@@'+@#        @@ `@@@@@@@@@@@@@@@@@# @.                
                                                 @@@. @@@@@  @@@@@@` @@@+         @  .,.@@@@@@@@@@@@##@: @                 
                                                ;@@+#@ @@    @ .@@ ` @@@@         @``@ :.     ;@@@@@@:@  @'                
                       @                        #@@#+@;@       @#  `  ' .         @@@. . '     ;  :@@,'  @+                
                     :@@@+                    +@@:@@'#@@      ;@   `  ' @         `@@        `:.,     `  @                 
                     @@  #@@ @+               @@@@#@@ #;'#  ` @      @@#+         ,;@@                   @                 
                     @     @@@@@@.   ., :     #@@@@@@#` @@@@@@;@@ ` @@#             @@                  @:                 
                    @#       `@@@#;   .@     ;@@@@@#@#       .+@: '@@@.             :@           #@;';@@@@  ,              
                    @            @@@@@       @ @@@@@ `   @@@@@@@  @@@#:             `@@          @@@@@@+@   @  `           
                   +@              @@@@@@@' # #@@@@@ ``,@,@@@@.`  @@@.         #  ; '@@    @.   @,          @@             
                   @                @@, @@@@@+@@@@@@@ :+  ;@#+'@ # .:@        @@    '@@   :@@' #@           @@+            
                  @@                ,@@;    @@ `@@@@@,@  @@@@@@@: `@@         @@    @`@        @            @@@            
                 @@.                  @@@    @@#@@@@@#@#@@@@@'@@@@;@@'       +@@    #;@.      #@            @ @'           
                '@@ .                  @@` ;  @#@@#@:#@@@@;@@@@,#@@@@@       @@@     ,@        @           ,@;#:           
                .@                      @@  , @@@@#@#@@@@@@@@@@@@@' @@       @@@     `@        @            @@'            
                @@;                     @@  . @@@'@@@@@@@@@: @@@@@@@;@;      @@@     +@        @:                          
                @@@                      @`    +@@#@@@@+@@:.;@ ,  @+#@       @#@@    '@   .    @@                          
                @+                       @@     #@@@@#@##@  .@ @ `@'@         @@     #@   :    @@                          
                @+                  `    @@    #'@@ @@@@#@  `@ #@@`@@@@#      @'     @#        @@                          
                @+                      '@@    @ @@# @@#@@'# @@@, @@#@@@@#           @;        #@                          
                @#                      `+@    @+@@  @@'@@@#@@@:@@+@    @@@          @         @@                          
                @@                     ` @@     @@    @+@@@@@@@@@@ @      @@         @         @@                          
                @@                      .@@@          @@@@@@@@@##@@@   :.  @,        @         '@+                         
                @@                       @@#@         @@@@@@@@@,@@@    @@+ @@        @          @@                         
               .@@                       #@'          @@@@@@;#@@@        @ @@:       @         .@@                         
                @@                       :@'   `      ,##@@@##@       ;@ +  @#       @          @@   #.                    
                .@@                       @@#: @@     ##@@@@@@       @@     @+      :@          @@   '@                    
                 @@@                      @@+#  @@    #'@@@@@@:   ` @@      @#      @@          @@   #@@                   
                 +@@@                     '@+,   @@' , `#@@@,@`   @@@    `  +@, `   @#          @@   @ @                   
                 :@@@#                     @@     +@@,,' @@@     #@@    .    '@:    @:          @@  .@ @+                  
                  ,@@@#                    @@+      ,@@` @@.   .@@           #@@   ,@           @@  #@ #@                  
                   @@@@                `   @@      '     ;@     :       ,    `@@@  :@           @@, +;@@                   
                    ##@@                   @@#   .@@@#   #@           @.       @@: +@           #@# #.                     
                    ;@@@@                  ,@@`@@@   @@: :@           #@;.      @@ @@           #@@.@'                     
                     ##@@;                  +@@@ `    #@ @;            #@:       @@@@           #@# .                      
                     `@:@@         .@#    ;@@@.        +#@              @@       `@@+           ;@@                        
                      +@#.@       @@'`@@@@ @@ `         @`     ;         @`      . @@       , . `@@                        
                       #'#@@    ;@  `   @@+@.``         ,@`    @         @+        @@     ` `  `;@@,      `                
                        #+@@,  @@ `   `@@@@+ ;     ';   @@. `  @@        @@   ,   ,@`          .;@@`                       
                         @'@# +@#    ;@@@@@@+           ;@'+.  +@        #@       @@             @@+                       
                         `@,@@@     '@@#@@@@@          #:@#@@# :@     .  :@.      @, .           @@                        
                            `@+      @@+@@@@@#        ' '@@@@#,,@         @+    ` @#  ,         +@@;                       
                        `,@@@@ ,     @ +@@@@@#`        ..@@:@@@ @        :@.     # @`          ';@   .                     
                      @@@@@. @  ,    @ #@@@@@@#     `  .`@@   @@@        @@    '   #          ; @   #                      
                      @@    '@`     @@ @@@@@@@,        . @@ .  @@   `  . @@@  .  . .,        .#@@  #@'                     
                      @     '@'  ;  @@ '@@@@@@#`       ` @@    #@     ,`##@@@  ;  `.    @@@+  @#@  @@'                     
                     @@      #@   . @@ #@@@@@@@'         #@     @,    ,'#@@#@@';               @@; @@                      
                     @. ,    #@ . `#@: +@@@@@@@@         #@     #@   `; +@@ @@@  `          `  @@@#@@                      
                     @;.      @, . @@  :@@@@@@@@         #@      @'` .,@`@  '@@@+           +#@@@;                         
                    @@        ;@  `#@   @@@@@@@@# .`     .@ ,     @..@  @;.   @@@@@+ ;#`@#'@';@ ,`                         
                    @@        `@`  @@   @@@@@@@@@ `..  `,@        @@.  @@      @@@@@@@@ .@. @;  :+                         
                    @###       +@ :@@ : @@@,@@@@@ ,..   +@        @@  @@        @@@@ +@@  @@@  #:#  `                      
                    `@@,       .@`#@@   +@@@@@@@@  .`,   @         @;@@        #@#; @@  .@.@   +@@ `                       
                     @@ #@      `@#@@@  ,#@@@`@@@  .,`   @        @@@+#     +#. :@@   `@@: @   ;@@                         
                    .;@  @@`@.   @@;@@@  @@@@'@@@@ :  ,  @  ` `   @@+@ `,@#  ;@@:`   @@ @@@    @#@                         
                     :@@ @@@@@# ` +,#@@@  #@@@'@ ;@: ` .@@ ::    ,@@,@:+;'@@+ '#   @@          @@@.                        
                     ` @. @  '@@++@@@#@@ ., #@@@@. @` ..@@      ,@@@@@@@#   :'   @@,          #@;@                         
                    .  .@ @'    @@@@@#+@   ` @'. :::@@@#@@@ `;+@@@@.,    `'    @@;            :@+@                         
                        @@+@  '@@@@;@',     .   #    #@@+@#  ,@#,@     ,+    +@:             , @@@                         
                        ,@@@ ,@@@@`  :+;    :        ,:@@@;'@#+@@#    +@@  .@#               ; @ @                         
                      :#`@#@@ @@@   .  @@##;          . +@@@@@@@@#:   #@ :@#                 ,;@ @                         
             #@@@@@@@@@::++  ,@@     , '`  :@       `    .@#; ,'`. , @,+@'           ,'.:;  :#@@@@,                        
              @@  `'+ ,;+@ ` @@      ::                   #@  `,.  , '@@;.'.:. ,;';,    `@@@#@@  @                         
                @@#. #   ;.  @@         +           `,+    @@+   ` `  ###@@@@#+.    :@@'  '@@ @ #;                         
              + @@@#     ,, :@@                     '     +:@ '#       @@@@@@@@@'@@'    #@@+  @ @                          
             @@@@,  `    #` @@@                       `   +@@@@@@+      @@@'`@@@.     @@; :;@@  ,@             `           
            @@@ .`       ; .@@.                           +@@@@@@@#    #            @@    ;@ @@.,@                         
          @@@,      ,+@@@# :@@                    '        @@@@@@@@#        .    #@'      @`@, @@#                         
       +@@@+     #@@@@#@@@@@.@   .,                         @@@@@@@',   '@`   .@@:        @,@   @@                         
      +@@@@@#+, @@@@   @#,@@@@                              @@@@@@@@'    @.;@@#           @ @   @@                         
          @@@@@@@#  `    #@@@@@`                  .          @@@@@@@@:    + +,@           @@@   +,                         
           +@@@@@@@@; :,   +@@@@@        `                   ,#@@@@@@    ,  @@@;          @@`   @:                         
          @@@@@@@@@@@@@@@@@@@@@@@@ `                            @@@@@       ,@:::         @@,   @                          
         :' @@@@; @        :@@@     `  .            .    `          @@.       #@ `, `    @@  '  @                          
        @.# @@@@@@+@@       # +@+     `              ,                @;   '  +#@        @   #  @                          
          #+.@@@@@@@@@@ @   @  ,     :                `               :@#        `.    ,@   @#  @                          
           @`@@@@@@#@@:@@.@;@@  +                          `           @@@         '  @@`   @  @                 `         
            @#@@@@@@+@@,@@@@@@@  ,.                   .                 @@@   .`     @@    :@  @                           
             #@@@@@@@@@@@@@@@@@;                          `              @@@,,      @@ :   @@ .@                `          
              '@@@@@@@@@+@@@@@@@                .:                   .     @@+  ; @@;   +;#@  @                            
               #@@@@@@@@@.@@@@@@@.            `@@@@@@                       @@#:@@`      +@  .@                            
               @ @@@@@@@@@@@@@@@@            @@@@@@@@@                       @@  ;`      @ `@@.                            
              `+  @#@@@@@@@@@@#. +          #@@ @@@@@@@               .        @# ..   +@   @@ @                           
              @     '@@@@@@  #             `@;@@@@@:@@@@           +           @@`.`,,#@   @@ +,  +                        
              `    +     .@+                #@@@@@@@@@@@                 .  .  @@   : @   '@#  #,,                         
             @     #      @@       .        .@@@@@@@@@@@                ;  ':'+@@@#  #    @@                               
            @   , #       @@    ;',          .@@@@@@@@@   :, ..:          ###+@@@@@; ` @#@@                                
           ;# '   '      + @+     .            .@@@@@@       ` :      @@@@@@@@.@@ @@@@ .@@`                                
          +@'#+@ @      @` @@                     ``   .:           : `@,#@#@@ ;   #@@#@@                           `      
         ;@+;@ @@@     ,@  :@                                          .@@@@@@.;  `'@@@@:@                                 
       #+#@ @  @@      @@   @+                                  '#@@.  `:'#  .;'  ;#@@@                                    
      ''@@''  '#@     @ #   @@     @                      @# #@@@@@@#,  ''.    @, @@@:                                     
      ,`      : @    @ @    #@    #@@                    @@@@@@@@@@@@@@#.+ `    @@@@                                       
                @'  @  @:   `@:    @@@                   :@@@   @@@@@@@@@@#:.:'@@@:`'                                      
               , ` @  ,@@   @@@    '@@@                   @@#  :  `    .#@@@@@@@@+@+                       `               
               @+ #;  @@@  @ ;@.    @@@@@@            ,' .+@@#'+#,.       .'@@@,@@@,   ;                                   
               @`:@     + @  @@@     @;@@@#@@@@@@@@@.`+#@@@#@@@@@@@@@@@@@'  ,`.@@@#                                        
               # @     # :.,##@@      #;++#@@@#@@+ @#    #@@@@@@@@@@@@@@@@@@@@@;'@'                                        
              @ @      @ @ .@@@`       `@@#@@@@@@@:    ,    +@@@@@@@@@` @@@@@#'+@,                                         
              @,+      @@  #@@@          #`   #               @@@@@@@@@@@@#`.@@@@#`                                        
             # @      '.' :#@@                               @@,@ ;;#@@@@@@@@@@@;                                          
            .@@       @@ `+@@#                              @@+#     # '+@@@'@                                             
            +@@       @; .@@@                             :@@.#       # `                                                  
           `;@          ;@@@`                             @@, ,        @  ;   :`                                           
           `@`         ;,@@@                             +@;            @    '          `                                  
           #@         . @@@                             @@#@     +    @@ ;   @                                             
          :@.          +@@@                            .@# @     @'   ' @@@:+@                                             
          @@          :@@@                            .@#  `@    @@`   + @ @@'@                                            
                      @@@@            '               @@    @    @,@   @    @`@.                                           
`                    #@@@                            @@     ',   @ ,@  @     @@                                            
`                   `#@@'                           @@.      @   @  @@;      :@                                            
                    '@@@                           @@'       @@: @   @#       +                                            
                    #@@:                         `@@#        :@@ @    @:                                                   
                   ` @@                          #@@          @@ @     ,                                                   
                    @@                         ':@@             @@                                                         
                    @@                        :,@@              @'                                                         
                   @@                       .` @@.              @;                                                         
                   @'                    .    @@                 @,                                                        
                   @                          @.                 @+                                                        
`                 @:                         @@                  @'                                                        
                  @           `             @@                   +@                                                        
                               `           @@'                    @                                                        
                                           @ ;                    @                                                        
                                                        `         @                                                        

Saturday, May 4, 2013

Harvest Animals

Things for this update:

  • Multiple items carried by units
  • Auto harvest and all drop off
  • Visual cue for harvested nodes
  • Harvest Animal action

Multiple items carried by units

A unit can now carry any number of different stuff as long as they have the carrying capacity to hold it. Watch as this man carries a ball of water with his bare hands, a pile of berries and a wooden log.

Yep. The wooden log completely dominates the graphic. It is like all encompassing poop. Poop looks bad. I will have to make this look nicer later.

Auto harvest and all drop off

A unit will automatically go back to harvest nodes of the same item type (without care about material type, I'm not sure if this is good or not but playtesting later will reveal this UI choice). They will also drop off everything they are holding. They only check around a node up to a distance of 2. Because I intend the game to be about regions, I will eventually change this to have them look for a non-empty resource node of the same item type in a region. I may, after that, think about how to optimise that check.

Additionally, I still need to make a "right-click return". That is, I need to detect that a user has selected units and that the user clicked on a building. Then I should queue a drop-off action. I want to reuse the harvestNode action, so I've added a setState on the action in preparation of this. Essentially, I'll queue an action, set the state to drop off and then when the units are done drop off, they'll see that they are done harvesting and thus finish off the action.

I'd put in a pic but it wouldn't mean much :) Essentially, I queue up a harvestNode action for a unit, put it at drop-off state and give it a dummy resource node. When the unit completes drop-off and checks to see what else there is harvest it will see that they have a dummy resource node and then immediately stop. Any units with nothing simply move toward the building.

Visual cue for harvested nodes

After a tree, bush or grass is harvested, the user should see some visual confirmation that yes this stuff has been harvested. Additionally, I am planning to have stuff regrow on the same spot unless you destroy it, plant something else over top etc. What do I mean by this? Say you chop all the wood from a tree, it becomes a tree stump. Next spring when trees regrow, some of those stumps become full trees again. Automagically.

Right now, all these objects are created via batched geometry because they are many and they do not move. Unfortunately there isn't an easy way to update this with the basic staticGeometry offered in Ogre3d. You basically have to call reset and then add back all the entities. In addition, the visibility rules for individual entities will NOT be respected because it makes whole groupings visible or invisible. Rebuilding small staticGeometry may not be overly expensive but it is certainly suboptimal but I've not yet found a better solution so I'll leave it as is (ie. poop). Whenever you exhaust a resource node it turns into the exhausted entity, which really means I remake all the entities for a forest and then rebuild the staticGeometry object. If later I find that causes FPS to drop below 60 then I'll do something better.

Harvest Animal action

The harvest animal action requires several components:

  • Combat Stats
  • Combat Resolver
  • Death

Combat Stats

Many things will share similar stats for combat resolution. This means hp, damage output, damage types, resistances and of course, everything that affects those stats such as equipped weapons, armour, skills, magical blessings and so on. In another project we put this all into a single object. I'm going to mimic that here as well. We'll start off with just hp and damage. Simple enough for what I need right now.

Later on, this class will also keep track of all equipped items (weapons and armour) as well as magic (say a unit has stone skin cast on her). The combat resolver (discussed next) will then grab a unit's combatStats object and from there go combatStats->getDamage() or something along those lines. This means a unit could be carrying various weapons but only equip some of them. On top of this, a unit may choose to switch through weapons during combat (wasting some amount of time). In essence a unit would do something like combatStats->unequip(int slot) and then combatStats->equip(int slot). This will be useful later to mimic basically any pre-industrial soldier. If you learned your history you might know that soldiers back in the day carried "whatever-the-eff-I-have" package of equipment, most of which was owned by themselves. We, today, might picture an a middle age "archer". But really, back then, even English longbowmen carried significant melee weapons and armour because no battle was ever decided by arrows alone (and most were not decided by arrows at all).

Combat Resolver

The combat resolver will be a class floating somewhere in the nether. Like pathfinder, it sits out there to perform resolution of actions. In this case, it will be harvest animal and later for attack action. When a unit reaches another it will attack it. It simply calls combatResolver->resolve(unit* attacker, unit* defender). This then does a one-way damage calculation. Whether that unit hits back is entirely up to that unit to queue up an attack action that has this unit as a target. The main reason I do not have this as a two-way damage resolution is because the other unit might be doing all sorts of stuff. Imagine playing Starcraft and watching your marines fire on enemies. It's a one-way package.

I intend there to be more than one type of damage that can be dealt in the future, so there may be a loop to get an array of damage types and then figure out the other unit's armour and resistances and then apply the damage and reduce hp. In any case for now, just one damage stat.

Death

I have a baseUnit class so I intend to have something like: "virtual void death() = 0;". Then units and structures will code their own death. When they die in the combatResolver, this is called. So basically they get taken out of a faction's unit or structure list, they are replaced by some corpse and their carried and equipped items will then be added to it. Then you can loot the body. Maybe some of the equipment gets broken and is unrecoverable (or becomes salvageable/repairable items).

ME PUNCH GAZELLE FOR MEAT!

Things for later

Leaking Memory

Right now I have some issues with reference counting before I can delete objects so those things are just plain leaking. I will have to use ref counting and likely I'll just use Ogre's pointers (so that I don't have to touch Boost itself). Leaking memory is like leaking poop. Very bad.

Combat visual cues

For combat visual cues I'm thinking something along the lines of Exile (if you know that indie game from Spiderweb Software). Basically a number inside of a bloody splat atop of a unit which indicates damage done. The colour of the splat changes depending on damage type. It should disappear after half a second.

Reactions

We'll want units to react to being attacked. Animals should flee (have a target attacker and just greedily path away). Units should fight back.

PathFinder

Just a bit of code clean up, right now the only pathfinding I coded was greedy. I am going to call it "greedy" and then also have an A* in there as well. That'll be useful for when reusable paths are created (such as trade routes).

I'd like units to naturally spread out instead of standing on top of each other. This mimics Starcraft like behaviour.

There should be a sort of exit condition for getting as close as possible to a target location. This helps if the actual spot you want to move to is blocked somehow, or the path is impossible then they should move closer but then stop. This is similar to any game where you tell a unit to move to somewhere impossible. The greedy algorithm is an acceptable problem (where the unit moves at all toward an impossible location) and is sometimes desired (you want a unit to move closer to a spot even if they can't get to it).

Item Weight

Right now all items take up the same space. I think I need to add item weight. Everything raw will be the same. It's more about finished products such as military equipment. Otherwise you could have a single soldier huffing about with fifty swords and well that just doesn't seem right. Maybe more like five swords.