From 04b86f7e1e2bb0ccacd5d7b661a5e9411a51af37 Mon Sep 17 00:00:00 2001
From: Marc Zinnschlag <marc@zpages.de>
Date: Mon, 26 Jul 2010 12:52:32 +0200
Subject: [PATCH] added first set of character and creature stats (attributes)

---
 apps/openmw/CMakeLists.txt                |  5 ++-
 apps/openmw/mwmechanics/creaturestats.hpp | 15 +++++++
 apps/openmw/mwmechanics/stat.hpp          | 49 +++++++++++++++++++++
 apps/openmw/mwworld/ptr.hpp               | 53 ++++++++++++++++++++++-
 apps/openmw/mwworld/refdata.hpp           | 18 ++++++++
 5 files changed, 138 insertions(+), 2 deletions(-)
 create mode 100644 apps/openmw/mwmechanics/creaturestats.hpp
 create mode 100644 apps/openmw/mwmechanics/stat.hpp

diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt
index 7d19390b66..bac5146692 100644
--- a/apps/openmw/CMakeLists.txt
+++ b/apps/openmw/CMakeLists.txt
@@ -90,7 +90,10 @@ source_group(apps\\openmw\\mwworld FILES ${GAMEWORLD} ${GAMEWORLD_HEADER})
 set(GAMEMECHANICS
     mwmechanics/mechanicsmanager.cpp)
 set(GAMEMECHANICS_HEADER 
-    mwmechanics/mechanicsmanager.hpp)
+    mwmechanics/mechanicsmanager.hpp
+    mwmechanics/stat.hpp
+    mwmechanics/creaturestats.hpp
+    )
 source_group(apps\\openmw\\mwmechanics FILES ${GAMEMECHANICS} ${GAMEMECHANICS_HEADER}) 
 
 set(OPENMW_CPP ${GAME} ${GAMEREND} ${GAMEINPUT} ${GAMESCRIPT} ${GAMESOUND} ${GAMEGUI} ${GAMEWORLD}
diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp
new file mode 100644
index 0000000000..f8aaa3caff
--- /dev/null
+++ b/apps/openmw/mwmechanics/creaturestats.hpp
@@ -0,0 +1,15 @@
+#ifndef GAME_MWMECHANICS_CREATURESTATS_H
+#define GAME_MWMECHANICS_CREATURESTATS_H
+
+#include "stat.hpp"
+
+namespace MWMechanics
+{
+    struct CreatureStats
+    {
+        Stat<int> mAttributes[8];
+    };
+}
+
+#endif
+
diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp
new file mode 100644
index 0000000000..eb0e35bd96
--- /dev/null
+++ b/apps/openmw/mwmechanics/stat.hpp
@@ -0,0 +1,49 @@
+#ifndef GAME_MWMECHANICS_STAT_H
+#define GAME_MWMECHANICS_STAT_H
+
+namespace MWMechanics
+{
+    template<typename T>
+    class Stat
+    {
+            T mBase;
+            T mModified;
+    
+        public:
+        
+            Stat() : mBase (0), mModified (0) {}
+        
+            const T& getBase() const
+            {
+                return mBase;
+            }
+            
+            const T& getModified() const
+            {
+                return mModified;
+            }
+            
+            /// Set base and modified to \a value.
+            void set (const T& value)
+            {
+                mBase = mModified = value;
+            }
+            
+            /// Set base and adjust modified accordingly.
+            void setBase (const T& value)
+            {
+                T diff = value - mBase;
+                mBase = value;
+                mModified += diff;
+            }
+            
+            /// Change modified relatively.
+            void modify (const T& diff)
+            {
+                mModified += diff;            
+            }
+    };
+}
+
+#endif
+
diff --git a/apps/openmw/mwworld/ptr.hpp b/apps/openmw/mwworld/ptr.hpp
index a65fcb7cca..5f8c938a33 100644
--- a/apps/openmw/mwworld/ptr.hpp
+++ b/apps/openmw/mwworld/ptr.hpp
@@ -5,8 +5,12 @@
 
 #include <boost/any.hpp>
 
+#include <components/esm/loadcrea.hpp>
+#include <components/esm/loadnpc.hpp>
 #include <components/esm_store/cell_store.hpp>
 
+#include "../mwmechanics/creaturestats.hpp"
+
 #include "refdata.hpp"
 
 namespace MWWorld
@@ -45,7 +49,7 @@ namespace MWWorld
             template<typename T>
             ESMS::LiveCellRef<T, RefData> *get() const
             {
-                return boost::any_cast<const ESMS::LiveCellRef<T, RefData>*> (mPtr);
+                return boost::any_cast<ESMS::LiveCellRef<T, RefData>*> (mPtr);
             }
     
             ESM::CellRef& getCellRef() const
@@ -65,6 +69,53 @@ namespace MWWorld
                 assert (mCell);
                 return mCell;
             }
+            
+            /// Throws an exception, if the ID type does not support creature stats.
+            MWMechanics::CreatureStats& getCreatureStats() const
+            {
+                RefData& data = getRefData();
+                
+                if (!data.getCreatureStats().get())
+                {
+                    if (mPtr.type()==typeid (ESMS::LiveCellRef<ESM::Creature, RefData> *))
+                    {
+                        boost::shared_ptr<MWMechanics::CreatureStats> stats;
+                        data.getCreatureStats() = stats;
+                    
+                        ESMS::LiveCellRef<ESM::Creature, RefData> *ref = get<ESM::Creature>();
+                        
+                        stats->mAttributes[0].set (ref->base->data.strength);
+                        stats->mAttributes[1].set (ref->base->data.intelligence);
+                        stats->mAttributes[2].set (ref->base->data.willpower);
+                        stats->mAttributes[3].set (ref->base->data.agility);
+                        stats->mAttributes[4].set (ref->base->data.speed);
+                        stats->mAttributes[5].set (ref->base->data.endurance);
+                        stats->mAttributes[6].set (ref->base->data.personality);
+                        stats->mAttributes[7].set (ref->base->data.luck);
+                    }
+                    else if (mPtr.type()==typeid (ESMS::LiveCellRef<ESM::NPC, RefData> *))
+                    {
+                        boost::shared_ptr<MWMechanics::CreatureStats> stats;
+                        data.getCreatureStats() = stats;
+                    
+                        ESMS::LiveCellRef<ESM::NPC, RefData> *ref = get<ESM::NPC>();
+                        
+                        stats->mAttributes[0].set (ref->base->npdt52.strength);
+                        stats->mAttributes[1].set (ref->base->npdt52.intelligence);
+                        stats->mAttributes[2].set (ref->base->npdt52.willpower);
+                        stats->mAttributes[3].set (ref->base->npdt52.agility);
+                        stats->mAttributes[4].set (ref->base->npdt52.speed);
+                        stats->mAttributes[5].set (ref->base->npdt52.endurance);
+                        stats->mAttributes[6].set (ref->base->npdt52.personality);
+                        stats->mAttributes[7].set (ref->base->npdt52.luck);
+                    }
+                    else
+                        throw std::runtime_error (
+                            "CreatureStats not available for this ID type");                
+                }
+            
+                return *data.getCreatureStats();
+            }            
     };
 }
 
diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp
index 58c169c0e5..919f4f8a02 100644
--- a/apps/openmw/mwworld/refdata.hpp
+++ b/apps/openmw/mwworld/refdata.hpp
@@ -3,6 +3,8 @@
 
 #include <string>
 
+#include <boost/shared_ptr.hpp>
+
 #include "../mwscript/locals.hpp"
 
 namespace ESM
@@ -10,6 +12,11 @@ namespace ESM
     class Script;
 }
 
+namespace MWMechanics
+{
+    struct CreatureStats;
+}
+
 namespace MWWorld
 {
     class RefData
@@ -21,6 +28,12 @@ namespace MWWorld
                                       // we can make this a pointer later.
             bool mHasLocals;
             bool mEnabled;
+            
+            // we are using shared pointer here to avoid having to create custom copy-constructor,
+            // assignment operator and destructor. As a consequence though copying a RefData object
+            // manually will probably give unexcepted results. This is not a problem since RefData
+            // are never copied outside of container operations.
+            boost::shared_ptr<MWMechanics::CreatureStats> mCreatureStats;
         
         public:
         
@@ -64,6 +77,11 @@ namespace MWWorld
             {
                 mEnabled = true;
             }
+            
+            boost::shared_ptr<MWMechanics::CreatureStats>& getCreatureStats()
+            {
+                return mCreatureStats;            
+            }
     };        
 }