]> git.jsancho.org Git - lugaru.git/blobdiff - Source/GameTick.cpp
Added a class for Hotspots to avoid using several arrays
[lugaru.git] / Source / GameTick.cpp
index 90786725e4e6c489dcf197fbb1d87a41a9e02bd7..13eb1cbff770768c09f14b06622ef81508e62a93 100644 (file)
@@ -38,12 +38,13 @@ along with Lugaru.  If not, see <http://www.gnu.org/licenses/>.
 #include "openal_wrapper.h"
 #include "Settings.h"
 #include "Input.h"
-#include "Animation.h"
+#include "Animation/Animation.h"
 #include "Awards.h"
 #include "Menu.h"
 #include "ConsoleCmds.h"
 #include "Dialog.h"
 #include "Utils/Folders.h"
+#include "Hotspot.h"
 
 #include <algorithm>
 #include <set>
@@ -130,14 +131,6 @@ extern float hostiletime;
 
 extern bool gamestarted;
 
-extern int numhotspots;
-extern int killhotspot;
-extern XYZ hotspot[40];
-extern int hotspottype[40];
-extern float hotspotsize[40];
-extern char hotspottext[40][256];
-extern int currenthotspot;
-
 extern int hostile;
 
 extern bool stillloading;
@@ -827,7 +820,7 @@ void Game::Loadlevel(const std::string& name)
     hostiletime = 0;
     won = 0;
 
-    animation[bounceidleanim].Load((char *)"Idle", middleheight, neutral);
+    //~ Animation::animations[bounceidleanim].Load("Idle", middleheight, neutral);
 
     Dialog::dialogs.clear();
 
@@ -840,8 +833,8 @@ void Game::Loadlevel(const std::string& name)
     if (accountactive)
         difficulty = accountactive->getDifficulty();
 
-    numhotspots = 0;
-    currenthotspot = -1;
+    Hotspot::hotspots.clear();
+    Hotspot::current = -1;
     bonustime = 1;
 
     skyboxtexture = 1;
@@ -939,10 +932,12 @@ void Game::Loadlevel(const std::string& name)
         skyboxlightg = skyboxg;
         skyboxlightb = skyboxb;
     }
-    if (!stealthloading)
-        funpackf(tfile, "Bf Bf Bf Bf Bf Bi", &Person::players[0]->coords.x, &Person::players[0]->coords.y, &Person::players[0]->coords.z, &Person::players[0]->yaw, &Person::players[0]->targetyaw, &Person::players[0]->num_weapons);
-    if (stealthloading)
+    /* TODO - This should be done in an other way so that we can rebuild main player as well (so coords would need to be copied from old ones after rebuilding) */
+    if (stealthloading) {
         funpackf(tfile, "Bf Bf Bf Bf Bf Bi", &lamefloat, &lamefloat, &lamefloat, &lamefloat, &lamefloat, &Person::players[0]->num_weapons);
+    } else {
+        funpackf(tfile, "Bf Bf Bf Bf Bf Bi", &Person::players[0]->coords.x, &Person::players[0]->coords.y, &Person::players[0]->coords.z, &Person::players[0]->yaw, &Person::players[0]->targetyaw, &Person::players[0]->num_weapons);
+    }
     if (Person::players[0]->num_weapons > 0 && Person::players[0]->num_weapons < 5)
         for (int j = 0; j < Person::players[0]->num_weapons; j++) {
             Person::players[0]->weaponids[j] = weapons.size();
@@ -995,19 +990,22 @@ void Game::Loadlevel(const std::string& name)
     }
 
     if (mapvers >= 7) {
+        int numhotspots;
         funpackf(tfile, "Bi", &numhotspots);
-        for (int i = 0; i < numhotspots; i++) {
-            funpackf(tfile, "Bi Bf Bf Bf Bf", &hotspottype[i], &hotspotsize[i], &hotspot[i].x, &hotspot[i].y, &hotspot[i].z);
+        Hotspot::hotspots.resize(numhotspots);
+        for (int i = 0; i < Hotspot::hotspots.size(); i++) {
+            funpackf(tfile, "Bi Bf Bf Bf Bf", &Hotspot::hotspots[i].type, &Hotspot::hotspots[i].size, &Hotspot::hotspots[i].position.x, &Hotspot::hotspots[i].position.y, &Hotspot::hotspots[i].position.z);
             funpackf(tfile, "Bi", &templength);
             if (templength)
                 for (int l = 0; l < templength; l++)
-                    funpackf(tfile, "Bb", &hotspottext[i][l]);
-            hotspottext[i][templength] = '\0';
-            if (hotspottype[i] == -111)
+                    funpackf(tfile, "Bb", &Hotspot::hotspots[i].text[l]);
+            Hotspot::hotspots[i].text[templength] = '\0';
+            if (Hotspot::hotspots[i].type == -111)
                 indemo = 1;
         }
-    } else
-        numhotspots = 0;
+    } else {
+        Hotspot::hotspots.clear();
+    }
 
     if (visibleloading)
         LoadingScreen();
@@ -1093,92 +1091,63 @@ void Game::Loadlevel(const std::string& name)
     for (unsigned i = 0; i < Person::players.size(); i++) {
         if (visibleloading)
             LoadingScreen();
-        Person::players[i]->burnt = 0;
-        Person::players[i]->bled = 0;
-        Person::players[i]->onfire = 0;
-        if (i == 0 || Person::players[i]->scale < 0)
+        if (i == 0) {
+            Person::players[i]->burnt = 0;
+            Person::players[i]->bled = 0;
+            Person::players[i]->onfire = 0;
             Person::players[i]->scale = .2;
-        Person::players[i]->skeleton.free = 0;
-        Person::players[i]->skeleton.id = i;
-        if (i == 0 && mapvers < 9)
-            Person::players[i]->creature = rabbittype;
-        if (Person::players[i]->creature != wolftype) {
-            Person::players[i]->skeleton.Load(
-                (char *)"Skeleton/BasicFigure",
-                (char *)"Skeleton/BasicFigureLow",
-                (char *)"Skeleton/RabbitBelt",
-                (char *)"Models/Body.solid",
-                (char *)"Models/Body2.solid",
-                (char *)"Models/Body3.solid",
-                (char *)"Models/Body4.solid",
-                (char *)"Models/Body5.solid",
-                (char *)"Models/Body6.solid",
-                (char *)"Models/Body7.solid",
-                (char *)"Models/BodyLow.solid",
-                (char *)"Models/Belt.solid", 0);
-        } else {
-            Person::players[i]->skeleton.Load(
-                (char *)"Skeleton/BasicFigureWolf",
-                (char *)"Skeleton/BasicFigureWolfLow",
-                (char *)"Skeleton/RabbitBelt",
-                (char *)"Models/Wolf.solid",
-                (char *)"Models/Wolf2.solid",
-                (char *)"Models/Wolf3.solid",
-                (char *)"Models/Wolf4.solid",
-                (char *)"Models/Wolf5.solid",
-                (char *)"Models/Wolf6.solid",
-                (char *)"Models/Wolf7.solid",
-                (char *)"Models/WolfLow.solid",
-                (char *)"Models/Belt.solid", 0);
+            if (mapvers < 9) {
+                Person::players[i]->creature = rabbittype;
+            }
         }
+        Person::players[i]->skeleton.free = 0;
 
-        Person::players[i]->skeleton.drawmodel.textureptr.load(creatureskin[Person::players[i]->creature][Person::players[i]->whichskin], 1, &Person::players[i]->skeleton.skinText[0], &Person::players[i]->skeleton.skinsize);
+        Person::players[i]->skeletonLoad();
 
         Person::players[i]->addClothes();
 
-        Person::players[i]->animCurrent = bounceidleanim;
-        Person::players[i]->animTarget = bounceidleanim;
-        Person::players[i]->frameCurrent = 0;
-        Person::players[i]->frameTarget = 1;
-        Person::players[i]->target = 0;
+        if (i == 0) {
+            Person::players[i]->animCurrent = bounceidleanim;
+            Person::players[i]->animTarget = bounceidleanim;
+            Person::players[i]->frameCurrent = 0;
+            Person::players[i]->frameTarget = 1;
+            Person::players[i]->target = 0;
+        }
         Person::players[i]->speed = 1 + (float)(Random() % 100) / 1000;
         if (difficulty == 0)
             Person::players[i]->speed -= .2;
         if (difficulty == 1)
             Person::players[i]->speed -= .1;
 
-        Person::players[i]->velocity = 0;
-        Person::players[i]->oldcoords = Person::players[i]->coords;
-        Person::players[i]->realoldcoords = Person::players[i]->coords;
-
-        Person::players[i]->id = i;
-        Person::players[i]->skeleton.id = i;
-        Person::players[i]->updatedelay = 0;
-        Person::players[i]->normalsupdatedelay = 0;
+        if (i == 0) {
+            Person::players[i]->velocity = 0;
+            Person::players[i]->oldcoords = Person::players[i]->coords;
+            Person::players[i]->realoldcoords = Person::players[i]->coords;
 
-        Person::players[i]->aitype = passivetype;
+            Person::players[i]->id = i;
+            Person::players[i]->updatedelay = 0;
+            Person::players[i]->normalsupdatedelay = 0;
 
-        if (i == 0) {
             Person::players[i]->proportionhead = 1.2;
             Person::players[i]->proportionbody = 1.05;
             Person::players[i]->proportionarms = 1.00;
             Person::players[i]->proportionlegs = 1.1;
             Person::players[i]->proportionlegs.y = 1.05;
-        }
-        Person::players[i]->headless = 0;
-        Person::players[i]->currentoffset = 0;
-        Person::players[i]->targetoffset = 0;
-
-        Person::players[i]->damagetolerance = 200;
-
-        if (Person::players[i]->creature == wolftype) {
-            if (i == 0 || Person::players[i]->scale < 0)
+            Person::players[i]->headless = 0;
+            Person::players[i]->currentoffset = 0;
+            Person::players[i]->targetoffset = 0;
+            if (Person::players[i]->creature == wolftype) {
                 Person::players[i]->scale = .23;
-            Person::players[i]->damagetolerance = 300;
+                Person::players[i]->damagetolerance = 300;
+            } else {
+                Person::players[i]->damagetolerance = 200;
+            }
         }
 
+
         if (visibleloading)
             LoadingScreen();
+
         if (cellophane) {
             Person::players[i]->proportionhead.z = 0;
             Person::players[i]->proportionbody.z = 0;
@@ -1186,43 +1155,44 @@ void Game::Loadlevel(const std::string& name)
             Person::players[i]->proportionlegs.z = 0;
         }
 
-        Person::players[i]->tempanimation.Load((char *)"Tempanim", 0, 0);
-
-        Person::players[i]->headmorphness = 0;
-        Person::players[i]->targetheadmorphness = 1;
-        Person::players[i]->headmorphstart = 0;
-        Person::players[i]->headmorphend = 0;
-
-        Person::players[i]->pausetime = 0;
-
-        Person::players[i]->dead = 0;
-        Person::players[i]->jumppower = 5;
-        Person::players[i]->damage = 0;
-        Person::players[i]->permanentdamage = 0;
-        Person::players[i]->superpermanentdamage = 0;
-
-        Person::players[i]->forwardkeydown = 0;
-        Person::players[i]->leftkeydown = 0;
-        Person::players[i]->backkeydown = 0;
-        Person::players[i]->rightkeydown = 0;
-        Person::players[i]->jumpkeydown = 0;
-        Person::players[i]->crouchkeydown = 0;
-        Person::players[i]->throwkeydown = 0;
-
-        Person::players[i]->collided = -10;
-        Person::players[i]->loaded = 1;
-        Person::players[i]->bloodloss = 0;
-        Person::players[i]->weaponactive = -1;
-        Person::players[i]->weaponstuck = -1;
-        Person::players[i]->bleeding = 0;
-        Person::players[i]->deathbleeding = 0;
-        Person::players[i]->stunned = 0;
-        Person::players[i]->hasvictim = 0;
-        Person::players[i]->wentforweapon = 0;
+        Person::players[i]->tempanimation = Animation("Tempanim", lowheight, neutral);
+
+        if (i == 0) {
+            Person::players[i]->headmorphness = 0;
+            Person::players[i]->targetheadmorphness = 1;
+            Person::players[i]->headmorphstart = 0;
+            Person::players[i]->headmorphend = 0;
+
+            Person::players[i]->pausetime = 0;
+
+            Person::players[i]->dead = 0;
+            Person::players[i]->jumppower = 5;
+            Person::players[i]->damage = 0;
+            Person::players[i]->permanentdamage = 0;
+            Person::players[i]->superpermanentdamage = 0;
+
+            Person::players[i]->forwardkeydown = 0;
+            Person::players[i]->leftkeydown = 0;
+            Person::players[i]->backkeydown = 0;
+            Person::players[i]->rightkeydown = 0;
+            Person::players[i]->jumpkeydown = 0;
+            Person::players[i]->crouchkeydown = 0;
+            Person::players[i]->throwkeydown = 0;
+
+            Person::players[i]->collided = -10;
+            Person::players[i]->loaded = 1;
+            Person::players[i]->bloodloss = 0;
+            Person::players[i]->weaponactive = -1;
+            Person::players[i]->weaponstuck = -1;
+            Person::players[i]->bleeding = 0;
+            Person::players[i]->deathbleeding = 0;
+            Person::players[i]->stunned = 0;
+            Person::players[i]->hasvictim = 0;
+            Person::players[i]->wentforweapon = 0;
+        }
     }
 
     Person::players[0]->aitype = playercontrolled;
-    Person::players[0]->weaponactive = -1;
 
     if (difficulty == 1) {
         Person::players[0]->power = 1 / .9;
@@ -1335,7 +1305,7 @@ void doTutorial()
 
             emit_sound_at(fireendsound, Person::players[1]->coords);
 
-            for (int i = 0; i < Person::players[1]->skeleton.num_joints; i++) {
+            for (int i = 0; i < Person::players[1]->skeleton.joints.size(); i++) {
                 if (Random() % 2 == 0) {
                     if (!Person::players[1]->skeleton.free)
                         temp2 = (Person::players[1]->coords - Person::players[1]->oldcoords) / multiplier / 2; //velocity/2;
@@ -1605,7 +1575,7 @@ void doTutorial()
             XYZ temp, temp2;
             emit_sound_at(fireendsound, Person::players[1]->coords);
 
-            for (int i = 0; i < Person::players[1]->skeleton.num_joints; i++) {
+            for (int i = 0; i < Person::players[1]->skeleton.joints.size(); i++) {
                 if (Random() % 2 == 0) {
                     if (!Person::players[1]->skeleton.free)
                         temp2 = (Person::players[1]->coords - Person::players[1]->oldcoords) / multiplier / 2; //velocity/2;
@@ -1720,7 +1690,7 @@ void doTutorial()
                 tutorialsuccess = 1;
             break;
         case 28:
-            if (animation[Person::players[0]->animTarget].attack == reversed && Person::players[0]->feint)
+            if (Animation::animations[Person::players[0]->animTarget].attack == reversed && Person::players[0]->feint)
                 tutorialsuccess = 1;
             break;
         case 29:
@@ -1732,15 +1702,15 @@ void doTutorial()
             }
             break;
         case 33:
-            if (animation[Person::players[0]->animTarget].attack == reversal)
+            if (Animation::animations[Person::players[0]->animTarget].attack == reversal)
                 tutorialsuccess = 1;
             break;
         case 34:
-            if (animation[Person::players[0]->animTarget].attack == reversal)
+            if (Animation::animations[Person::players[0]->animTarget].attack == reversal)
                 tutorialsuccess = 1;
             break;
         case 35:
-            if (animation[Person::players[0]->animTarget].attack == reversal) {
+            if (Animation::animations[Person::players[0]->animTarget].attack == reversal) {
                 tutorialsuccess = 1;
                 reversaltrain = 0;
                 cananger = 0;
@@ -1760,15 +1730,15 @@ void doTutorial()
                 tutorialsuccess = 1;
             break;
         case 44:
-            if (animation[Person::players[0]->animTarget].attack == reversal)
+            if (Animation::animations[Person::players[0]->animTarget].attack == reversal)
                 tutorialsuccess = 1;
             break;
         case 45:
-            if (animation[Person::players[0]->animTarget].attack == reversal)
+            if (Animation::animations[Person::players[0]->animTarget].attack == reversal)
                 tutorialsuccess = 1;
             break;
         case 46:
-            if (animation[Person::players[0]->animTarget].attack == reversal)
+            if (Animation::animations[Person::players[0]->animTarget].attack == reversal)
                 tutorialsuccess = 1;
             break;
         case 49:
@@ -1900,11 +1870,9 @@ void doDebugKeys()
 
 
                 if (Person::players[closest]->creature == rabbittype) {
-                    Person::players[closest]->skeleton.id = closest;
-                    Person::players[closest]->skeleton.Load((char *)"Skeleton/BasicFigureWolf", (char *)"Skeleton/BasicFigureWolfLow", (char *)"Skeleton/RabbitBelt", (char *)"Models/Wolf.solid", (char *)"Models/Wolf2.solid", (char *)"Models/Wolf3.solid", (char *)"Models/Wolf4.solid", (char *)"Models/Wolf5.solid", (char *)"Models/Wolf6.solid", (char *)"Models/Wolf7.solid", (char *)"Models/WolfLow.solid", (char *)"Models/Belt.solid", 0);
-                    Person::players[closest]->skeleton.drawmodel.textureptr.load("Textures/Wolf.jpg", 1, &Person::players[closest]->skeleton.skinText[0], &Person::players[closest]->skeleton.skinsize);
-                    Person::players[closest]->whichskin = 0;
                     Person::players[closest]->creature = wolftype;
+                    Person::players[closest]->whichskin = 0;
+                    Person::players[closest]->skeletonLoad();
 
                     Person::players[closest]->proportionhead = 1.1;
                     Person::players[closest]->proportionbody = 1.1;
@@ -1915,11 +1883,9 @@ void doDebugKeys()
 
                     Person::players[closest]->damagetolerance = 300;
                 } else {
-                    Person::players[closest]->skeleton.id = closest;
-                    Person::players[closest]->skeleton.Load((char *)"Skeleton/BasicFigure", (char *)"Skeleton/BasicFigureLow", (char *)"Skeleton/RabbitBelt", (char *)"Models/Body.solid", (char *)"Models/Body2.solid", (char *)"Models/Body3.solid", (char *)"Models/Body4.solid", (char *)"Models/Body5.solid", (char *)"Models/Body6.solid", (char *)"Models/Body7.solid", (char *)"Models/BodyLow.solid", (char *)"Models/Belt.solid", 1);
-                    Person::players[closest]->skeleton.drawmodel.textureptr.load("Textures/Fur3.jpg", 1, &Person::players[closest]->skeleton.skinText[0], &Person::players[closest]->skeleton.skinsize);
-                    Person::players[closest]->whichskin = 0;
                     Person::players[closest]->creature = rabbittype;
+                    Person::players[closest]->whichskin = 0;
+                    Person::players[closest]->skeletonLoad(true);
 
                     Person::players[closest]->proportionhead = 1.2;
                     Person::players[closest]->proportionbody = 1.05;
@@ -1975,7 +1941,7 @@ void doDebugKeys()
                 XYZ headspurtdirection;
                 //int i = Person::players[closest]->skeleton.jointlabels[head];
                 Joint& headjoint = Person::players[closest]->joint(head);
-                for (int k = 0; k < Person::players[closest]->skeleton.num_joints; k++) {
+                for (int k = 0; k < Person::players[closest]->skeleton.joints.size(); k++) {
                     if (!Person::players[closest]->skeleton.free)
                         flatvelocity2 = Person::players[closest]->velocity;
                     if (Person::players[closest]->skeleton.free)
@@ -2018,7 +1984,7 @@ void doDebugKeys()
                 emit_sound_at(splattersound, blah);
                 emit_sound_at(breaksound2, blah);
 
-                for (int i = 0; i < Person::players[closest]->skeleton.num_joints; i++) {
+                for (int i = 0; i < Person::players[closest]->skeleton.joints.size(); i++) {
                     if (!Person::players[closest]->skeleton.free)
                         flatvelocity2 = Person::players[closest]->velocity;
                     if (Person::players[closest]->skeleton.free)
@@ -2035,7 +2001,7 @@ void doDebugKeys()
                     Sprite::MakeSprite(cloudsprite, flatfacing2, flatvelocity2 * 0, .6, 0, 0, 1, .5);
                 }
 
-                for (int i = 0; i < Person::players[closest]->skeleton.num_joints; i++) {
+                for (int i = 0; i < Person::players[closest]->skeleton.joints.size(); i++) {
                     if (!Person::players[closest]->skeleton.free)
                         flatvelocity2 = Person::players[closest]->velocity;
                     if (Person::players[closest]->skeleton.free)
@@ -2051,7 +2017,7 @@ void doDebugKeys()
                     Sprite::MakeSprite(bloodsprite, flatfacing2, flatvelocity2, 1, 1, 1, .4, 1);
                 }
 
-                for (int i = 0; i < Person::players[closest]->skeleton.num_joints; i++) {
+                for (int i = 0; i < Person::players[closest]->skeleton.joints.size(); i++) {
                     if (!Person::players[closest]->skeleton.free)
                         flatvelocity2 = Person::players[closest]->velocity;
                     if (Person::players[closest]->skeleton.free)
@@ -2067,7 +2033,7 @@ void doDebugKeys()
                     Sprite::MakeSprite(bloodsprite, flatfacing2, flatvelocity2 * 2, 1, 1, 1, .4, 1);
                 }
 
-                for (int i = 0; i < Person::players[closest]->skeleton.num_joints; i++) {
+                for (int i = 0; i < Person::players[closest]->skeleton.joints.size(); i++) {
                     if (!Person::players[closest]->skeleton.free)
                         flatvelocity2 = Person::players[closest]->velocity;
                     if (Person::players[closest]->skeleton.free)
@@ -2092,7 +2058,7 @@ void doDebugKeys()
                                 Person::players[j]->skeleton.free = 1;
                             Person::players[j]->skeleton.longdead = 0;
                             Person::players[j]->RagDoll(0);
-                            for (int i = 0; i < Person::players[j]->skeleton.num_joints; i++) {
+                            for (int i = 0; i < Person::players[j]->skeleton.joints.size(); i++) {
                                 temppos = Person::players[j]->skeleton.joints[i].position + Person::players[j]->coords;
                                 if (distsq(&temppos, &Person::players[closest]->coords) < 25) {
                                     flatvelocity2 = temppos - Person::players[closest]->coords;
@@ -2205,49 +2171,33 @@ void doDebugKeys()
             if (Input::isKeyPressed(SDL_SCANCODE_P) && Input::isKeyDown(SDL_SCANCODE_LSHIFT) && !Input::isKeyDown(SDL_SCANCODE_LCTRL)) {
                 Person::players.push_back(shared_ptr<Person>(new Person()));
 
-                Person::players.back()->scale = .2 * 5 * Person::players[0]->scale;
+                Person::players.back()->id = Person::players.size()-1;
+
+                Person::players.back()->scale = Person::players[0]->scale;
                 Person::players.back()->creature = rabbittype;
                 Person::players.back()->howactive = editoractive;
-                Person::players.back()->skeleton.id = Person::players.size()-1;
-                Person::players.back()->skeleton.Load((char *)"Skeleton/BasicFigure", (char *)"Skeleton/BasicFigureLow", (char *)"Skeleton/RabbitBelt", (char *)"Models/Body.solid", (char *)"Models/Body2.solid", (char *)"Models/Body3.solid", (char *)"Models/Body4.solid", (char *)"Models/Body5.solid", (char *)"Models/Body6.solid", (char *)"Models/Body7.solid", (char *)"Models/BodyLow.solid", (char *)"Models/Belt.solid", 1);
 
                 int k = abs(Random() % 2) + 1;
                 if (k == 0) {
-                    Person::players.back()->skeleton.drawmodel.textureptr.load("Textures/Fur3.jpg", 1, &Person::players.back()->skeleton.skinText[0], &Person::players.back()->skeleton.skinsize);
                     Person::players.back()->whichskin = 0;
                 } else if (k == 1) {
-                    Person::players.back()->skeleton.drawmodel.textureptr.load("Textures/Fur.jpg", 1, &Person::players.back()->skeleton.skinText[0], &Person::players.back()->skeleton.skinsize);
                     Person::players.back()->whichskin = 1;
                 } else {
-                    Person::players.back()->skeleton.drawmodel.textureptr.load("Textures/Fur2.jpg", 1, &Person::players.back()->skeleton.skinText[0], &Person::players.back()->skeleton.skinsize);
                     Person::players.back()->whichskin = 2;
                 }
 
+                Person::players.back()->skeletonLoad(true);
+
                 Person::players.back()->skeleton.drawmodelclothes.textureptr.load("Textures/Belt.png", 1);
-                Person::players.back()->power = 1;
-                Person::players.back()->speedmult = 1;
-                Person::players.back()->animCurrent = bounceidleanim;
-                Person::players.back()->animTarget = bounceidleanim;
-                Person::players.back()->frameCurrent = 0;
-                Person::players.back()->frameTarget = 1;
-                Person::players.back()->target = 0;
-                Person::players.back()->bled = 0;
                 Person::players.back()->speed = 1 + (float)(Random() % 100) / 1000;
 
                 Person::players.back()->targetyaw = Person::players[0]->targetyaw;
                 Person::players.back()->yaw = Person::players[0]->yaw;
 
-                Person::players.back()->velocity = 0;
                 Person::players.back()->coords = Person::players[0]->coords;
                 Person::players.back()->oldcoords = Person::players.back()->coords;
                 Person::players.back()->realoldcoords = Person::players.back()->coords;
 
-                Person::players.back()->id = Person::players.size()-1;
-                Person::players.back()->updatedelay = 0;
-                Person::players.back()->normalsupdatedelay = 0;
-
-                Person::players.back()->aitype = passivetype;
-
                 if (Person::players[0]->creature == wolftype) {
                     headprop = Person::players[0]->proportionhead.x / 1.1;
                     bodyprop = Person::players[0]->proportionbody.x / 1.1;
@@ -2277,9 +2227,6 @@ void doDebugKeys()
                     Person::players.back()->proportionlegs.y = 1.05 * legprop;
                 }
 
-                Person::players.back()->headless = 0;
-                Person::players.back()->onfire = 0;
-
                 if (cellophane) {
                     Person::players.back()->proportionhead.z = 0;
                     Person::players.back()->proportionbody.z = 0;
@@ -2287,7 +2234,7 @@ void doDebugKeys()
                     Person::players.back()->proportionlegs.z = 0;
                 }
 
-                Person::players.back()->tempanimation.Load((char *)"Tempanim", 0, 0);
+                Person::players.back()->tempanimation = Animation("Tempanim", lowheight, neutral);
 
                 Person::players.back()->damagetolerance = 200;
 
@@ -2315,20 +2262,7 @@ void doDebugKeys()
                 Person::players.back()->power = Person::players[0]->power;
                 Person::players.back()->speedmult = Person::players[0]->speedmult;
 
-                Person::players.back()->damage = 0;
-                Person::players.back()->permanentdamage = 0;
-                Person::players.back()->superpermanentdamage = 0;
-                Person::players.back()->deathbleeding = 0;
-                Person::players.back()->bleeding = 0;
-                Person::players.back()->numwaypoints = 0;
-                Person::players.back()->waypoint = 0;
-                Person::players.back()->weaponstuck = -1;
-                Person::players.back()->weaponactive = -1;
-                Person::players.back()->num_weapons = 0;
-                Person::players.back()->bloodloss = 0;
-                Person::players.back()->dead = 0;
-
-                Person::players.back()->loaded = 1;
+                Person::players.back()->loaded = true;
             }
 
             if (Input::isKeyPressed(SDL_SCANCODE_P) && Input::isKeyDown(SDL_SCANCODE_LSHIFT)) {
@@ -2486,7 +2420,7 @@ void doJumpReversals()
                     if (Person::players[i]->animTarget == jumpupanim &&
                             Person::players[k]->animTarget != getupfrombackanim &&
                             Person::players[k]->animTarget != getupfromfrontanim &&
-                            animation[Person::players[k]->animTarget].height == middleheight &&
+                            Animation::animations[Person::players[k]->animTarget].height == middleheight &&
                             normaldotproduct(Person::players[i]->velocity, Person::players[k]->coords - Person::players[i]->coords) < 0 &&
                             ((Person::players[k]->aitype == playercontrolled && Person::players[k]->attackkeydown) ||
                              Person::players[k]->aitype != playercontrolled)) {
@@ -2525,7 +2459,7 @@ void doJumpReversals()
                     if (Person::players[k]->animTarget == jumpupanim &&
                             Person::players[i]->animTarget != getupfrombackanim &&
                             Person::players[i]->animTarget != getupfromfrontanim &&
-                            animation[Person::players[i]->animTarget].height == middleheight &&
+                            Animation::animations[Person::players[i]->animTarget].height == middleheight &&
                             normaldotproduct(Person::players[k]->velocity, Person::players[i]->coords - Person::players[k]->coords) < 0 &&
                             ((Person::players[i]->aitype == playercontrolled && Person::players[i]->attackkeydown) ||
                              Person::players[i]->aitype != playercontrolled)) {
@@ -2593,7 +2527,7 @@ void doAerialAcrobatics()
                 Person::players[k]->animTarget == backhandspringanim ||
                 Person::players[k]->animTarget == dodgebackanim ||
                 Person::players[k]->animTarget == rollanim ||
-                (animation[Person::players[k]->animTarget].attack &&
+                (Animation::animations[Person::players[k]->animTarget].attack &&
                  Person::players[k]->animTarget != rabbitkickanim &&
                  (Person::players[k]->animTarget != crouchstabanim || Person::players[k]->hasvictim) &&
                  (Person::players[k]->animTarget != swordgroundstabanim || Person::players[k]->hasvictim))) {
@@ -2744,7 +2678,7 @@ void doAerialAcrobatics()
 
                         if (Person::players[k]->animTarget == jumpdownanim || Person::players[k]->isFlip()) {
                             //flipped into a rock
-                            if (Person::players[k]->isFlip() && animation[Person::players[k]->animTarget].label[Person::players[k]->frameTarget] == 7)
+                            if (Person::players[k]->isFlip() && Person::players[k]->targetFrame().label == 7)
                                 Person::players[k]->RagDoll(0);
 
                             if (Person::players[k]->animTarget == jumpupanim) {
@@ -3022,7 +2956,7 @@ void doAttacks()
                     }
                 }
                 //attack
-                if (!animation[Person::players[k]->animTarget].attack &&
+                if (!Animation::animations[Person::players[k]->animTarget].attack &&
                         !Person::players[k]->backkeydown &&
                         (Person::players[k]->isIdle() ||
                          Person::players[k]->isRun() ||
@@ -3037,7 +2971,7 @@ void doAttacks()
                             if (i == k || !(k == 0 || i == 0))
                                 continue;
                             if (!Person::players[k]->hasvictim)
-                                if (animation[Person::players[k]->animTarget].attack != reversal) {
+                                if (Animation::animations[Person::players[k]->animTarget].attack != reversal) {
                                     //choose an attack
                                     const float distance = distsq(&Person::players[k]->coords, &Person::players[i]->coords);
                                     if (distance < 4.5 &&
@@ -3049,8 +2983,7 @@ void doAttacks()
                                             Person::players[k]->animTarget != rabbitkickanim &&
                                             Person::players[i]->animTarget != getupfrombackanim &&
                                             (Person::players[i]->animTarget != staggerbackhighanim &&
-                                             (Person::players[i]->animTarget != staggerbackhardanim ||
-                                              animation[staggerbackhardanim].label[Person::players[i]->frameTarget] == 6)) &&
+                                             (Person::players[i]->animTarget != staggerbackhardanim || Person::players[i]->targetFrame().label == 6)) &&
                                             Person::players[i]->animTarget != jumpdownanim &&
                                             Person::players[i]->animTarget != jumpupanim &&
                                             Person::players[i]->animTarget != getupfromfrontanim) {
@@ -3060,11 +2993,11 @@ void doAttacks()
                                             //sweep
                                             if (distance < 2.5 * sq(Person::players[k]->scale * 5) &&
                                                     Person::players[k]->crouchkeydown &&
-                                                    animation[Person::players[i]->animTarget].height != lowheight)
+                                                    Animation::animations[Person::players[i]->animTarget].height != lowheight)
                                                 Person::players[k]->animTarget = sweepanim;
                                             //winduppunch
                                             else if (distance < 1.5 * sq(Person::players[k]->scale * 5) &&
-                                                     animation[Person::players[i]->animTarget].height != lowheight &&
+                                                     Animation::animations[Person::players[i]->animTarget].height != lowheight &&
                                                      !Person::players[k]->forwardkeydown &&
                                                      !Person::players[k]->leftkeydown &&
                                                      !Person::players[k]->rightkeydown &&
@@ -3074,7 +3007,7 @@ void doAttacks()
                                                 Person::players[k]->animTarget = winduppunchanim;
                                             //upunch
                                             else if (distance < 2.5 * sq(Person::players[k]->scale * 5) &&
-                                                     animation[Person::players[i]->animTarget].height != lowheight &&
+                                                     Animation::animations[Person::players[i]->animTarget].height != lowheight &&
                                                      !Person::players[k]->forwardkeydown &&
                                                      !Person::players[k]->leftkeydown &&
                                                      !Person::players[k]->rightkeydown &&
@@ -3089,7 +3022,7 @@ void doAttacks()
                                                 Person::players[k]->animTarget = knifefollowanim;
                                             //knifeslashstart
                                             else if (distance < 2.5 * sq(Person::players[k]->scale * 5) &&
-                                                     animation[Person::players[i]->animTarget].height != lowheight &&
+                                                     Animation::animations[Person::players[i]->animTarget].height != lowheight &&
                                                      !Person::players[k]->forwardkeydown &&
                                                      !Person::players[k]->leftkeydown &&
                                                      !Person::players[k]->rightkeydown &&
@@ -3099,14 +3032,14 @@ void doAttacks()
                                                 Person::players[k]->animTarget = knifeslashstartanim;
                                             //swordslash
                                             else if (distance < 4.5 * sq(Person::players[k]->scale * 5) &&
-                                                     animation[Person::players[i]->animTarget].height != lowheight &&
+                                                     Animation::animations[Person::players[i]->animTarget].height != lowheight &&
                                                      !Person::players[k]->crouchkeydown &&
                                                      attackweapon == sword &&
                                                      Person::players[k]->weaponmissdelay <= 0)
                                                 Person::players[k]->animTarget = swordslashanim;
                                             //staffhit
                                             else if (distance < 4.5 * sq(Person::players[k]->scale * 5) &&
-                                                     animation[Person::players[i]->animTarget].height != lowheight &&
+                                                     Animation::animations[Person::players[i]->animTarget].height != lowheight &&
                                                      !Person::players[k]->crouchkeydown &&
                                                      attackweapon == staff &&
                                                      Person::players[k]->weaponmissdelay <= 0 &&
@@ -3116,36 +3049,36 @@ void doAttacks()
                                                 Person::players[k]->animTarget = staffhitanim;
                                             //staffspinhit
                                             else if (distance < 4.5 * sq(Person::players[k]->scale * 5) &&
-                                                     animation[Person::players[i]->animTarget].height != lowheight &&
+                                                     Animation::animations[Person::players[i]->animTarget].height != lowheight &&
                                                      !Person::players[k]->crouchkeydown &&
                                                      attackweapon == staff &&
                                                      Person::players[k]->weaponmissdelay <= 0)
                                                 Person::players[k]->animTarget = staffspinhitanim;
                                             //spinkick
                                             else if (distance < 2.5 * sq(Person::players[k]->scale * 5) &&
-                                                     animation[Person::players[i]->animTarget].height != lowheight)
+                                                     Animation::animations[Person::players[i]->animTarget].height != lowheight)
                                                 Person::players[k]->animTarget = spinkickanim;
                                             //lowkick
                                             else if (distance < 2.5 * sq(Person::players[k]->scale * 5) &&
-                                                     animation[Person::players[i]->animTarget].height == lowheight &&
-                                                     animation[Person::players[k]->animTarget].attack != normalattack)
+                                                     Animation::animations[Person::players[i]->animTarget].height == lowheight &&
+                                                     Animation::animations[Person::players[k]->animTarget].attack != normalattack)
                                                 Person::players[k]->animTarget = lowkickanim;
                                         } else { //AI player
                                             if (distance < 4.5 * sq(Person::players[k]->scale * 5)) {
                                                 randattack = abs(Random() % 5);
                                                 if (!attackweapon && distance < 2.5 * sq(Person::players[k]->scale * 5)) {
                                                     //sweep
-                                                    if (randattack == 0 && animation[Person::players[i]->animTarget].height != lowheight)
+                                                    if (randattack == 0 && Animation::animations[Person::players[i]->animTarget].height != lowheight)
                                                         Person::players[k]->animTarget = sweepanim;
                                                     //upunch
-                                                    else if (randattack == 1 && animation[Person::players[i]->animTarget].height != lowheight &&
+                                                    else if (randattack == 1 && Animation::animations[Person::players[i]->animTarget].height != lowheight &&
                                                              !attackweapon)
                                                         Person::players[k]->animTarget = upunchanim;
                                                     //spinkick
-                                                    else if (randattack == 2 && animation[Person::players[i]->animTarget].height != lowheight)
+                                                    else if (randattack == 2 && Animation::animations[Person::players[i]->animTarget].height != lowheight)
                                                         Person::players[k]->animTarget = spinkickanim;
                                                     //lowkick
-                                                    else if (animation[Person::players[i]->animTarget].height == lowheight)
+                                                    else if (Animation::animations[Person::players[i]->animTarget].height == lowheight)
                                                         Person::players[k]->animTarget = lowkickanim;
                                                 }
                                                 if (attackweapon) {
@@ -3153,7 +3086,7 @@ void doAttacks()
                                                     if ((tutoriallevel != 1 || !attackweapon) &&
                                                             distance < 2.5 * sq(Person::players[k]->scale * 5) &&
                                                             randattack == 0 &&
-                                                            animation[Person::players[i]->animTarget].height != lowheight)
+                                                            Animation::animations[Person::players[i]->animTarget].height != lowheight)
                                                         Person::players[k]->animTarget = sweepanim;
                                                     //knifeslashstart
                                                     else if (distance < 2.5 * sq(Person::players[k]->scale * 5) &&
@@ -3187,12 +3120,12 @@ void doAttacks()
                                                     else if ((tutoriallevel != 1 || !attackweapon) &&
                                                              distance < 2.5 * sq(Person::players[k]->scale * 5) &&
                                                              randattack == 1 &&
-                                                             animation[Person::players[i]->animTarget].height != lowheight)
+                                                             Animation::animations[Person::players[i]->animTarget].height != lowheight)
                                                         Person::players[k]->animTarget = spinkickanim;
                                                     //lowkick
                                                     else if (distance < 2.5 * sq(Person::players[k]->scale * 5) &&
-                                                             animation[Person::players[i]->animTarget].height == lowheight &&
-                                                             animation[Person::players[k]->animTarget].attack != normalattack)
+                                                             Animation::animations[Person::players[i]->animTarget].height == lowheight &&
+                                                             Animation::animations[Person::players[k]->animTarget].attack != normalattack)
                                                         Person::players[k]->animTarget = lowkickanim;
                                                 }
                                             }
@@ -3257,7 +3190,7 @@ void doAttacks()
                                             Person::players[i]->targetyaw = Person::players[i]->yaw;
                                         }
                                     }
-                                    if (animation[Person::players[k]->animTarget].attack == normalattack &&
+                                    if (Animation::animations[Person::players[k]->animTarget].attack == normalattack &&
                                             Person::players[k]->victim == Person::players[i] &&
                                             (!Person::players[i]->skeleton.free)) {
                                         oldattackkey = 1;
@@ -3307,7 +3240,7 @@ void doAttacks()
                             if (i == k)
                                 continue;
                             if ((playerrealattackkeydown || Person::players[i]->dead || !hasstaff) &&
-                                    animation[Person::players[k]->animTarget].attack == neutral) {
+                                    Animation::animations[Person::players[k]->animTarget].attack == neutral) {
                                 const float distance = distsq(&Person::players[k]->coords, &Person::players[i]->coords);
                                 if (!Person::players[i]->dead || !realthreat || (!attackweapon && Person::players[k]->crouchkeydown))
                                     if (Person::players[i]->skeleton.free)
@@ -3386,7 +3319,7 @@ void doAttacks()
                                                     }
                                                 }
                                         }
-                                if (animation[Person::players[k]->animTarget].attack == normalattack &&
+                                if (Animation::animations[Person::players[k]->animTarget].attack == normalattack &&
                                         Person::players[k]->victim == Person::players[i] &&
                                         (!Person::players[i]->skeleton.free ||
                                          Person::players[k]->animTarget == killanim ||
@@ -3454,7 +3387,7 @@ void doAttacks()
                                   !Person::players[k]->victim->skeleton.free &&
                                   Person::players[k]->victim->animTarget != getupfrombackanim &&
                                   Person::players[k]->victim->animTarget != getupfromfrontanim &&
-                                  animation[Person::players[k]->victim->animTarget].height != lowheight &&
+                                  Animation::animations[Person::players[k]->victim->animTarget].height != lowheight &&
                                   Person::players[k]->aitype != playercontrolled && //wat???
                                   normaldotproduct(Person::players[k]->facing, Person::players[k]->victim->coords - Person::players[k]->coords) > 0 &&
                                   Person::players[k]->rabbitkickenabled) ||
@@ -3463,7 +3396,7 @@ void doAttacks()
                             Person::players[k]->setAnimation(rabbitkickanim);
                         }
                     //update counts
-                    if (animation[Person::players[k]->animTarget].attack && k == 0) {
+                    if (Animation::animations[Person::players[k]->animTarget].attack && k == 0) {
                         numattacks++;
                         switch (attackweapon) {
                         case 0:
@@ -3494,14 +3427,14 @@ void doPlayerCollisions()
         for (unsigned k = 0; k < Person::players.size(); k++)
             for (unsigned i = k + 1; i < Person::players.size(); i++) {
                 //neither player is part of a reversal
-                if ((animation[Person::players[i]->animTarget].attack != reversed &&
-                        animation[Person::players[i]->animTarget].attack != reversal &&
-                        animation[Person::players[k]->animTarget].attack != reversed &&
-                        animation[Person::players[k]->animTarget].attack != reversal) || (i != 0 && k != 0))
-                    if ((animation[Person::players[i]->animCurrent].attack != reversed &&
-                            animation[Person::players[i]->animCurrent].attack != reversal &&
-                            animation[Person::players[k]->animCurrent].attack != reversed &&
-                            animation[Person::players[k]->animCurrent].attack != reversal) || (i != 0 && k != 0))
+                if ((Animation::animations[Person::players[i]->animTarget].attack != reversed &&
+                        Animation::animations[Person::players[i]->animTarget].attack != reversal &&
+                        Animation::animations[Person::players[k]->animTarget].attack != reversed &&
+                        Animation::animations[Person::players[k]->animTarget].attack != reversal) || (i != 0 && k != 0))
+                    if ((Animation::animations[Person::players[i]->animCurrent].attack != reversed &&
+                            Animation::animations[Person::players[i]->animCurrent].attack != reversal &&
+                            Animation::animations[Person::players[k]->animCurrent].attack != reversed &&
+                            Animation::animations[Person::players[k]->animCurrent].attack != reversal) || (i != 0 && k != 0))
                         //neither is sleeping
                         if (Person::players[i]->howactive <= typesleeping && Person::players[k]->howactive <= typesleeping)
                             if (Person::players[i]->howactive != typesittingwall && Person::players[k]->howactive != typesittingwall)
@@ -3581,16 +3514,16 @@ void doPlayerCollisions()
                                                                                 k == 0 && findLengthfast(&rotatetarget) > 50 && Person::players[0]->rabbitkickragdoll) &&
                                                                                 normaldotproduct(rotatetarget, Person::players[k]->coords - Person::players[i]->coords) > 0) &&
                                                                                 (k == 0 ||
-                                                                                 k != 0 && Person::players[i]->skeleton.oldfree == 1 && animation[Person::players[k]->animCurrent].attack == neutral ||
-                                                                                 /*i!=0&&*/Person::players[k]->skeleton.oldfree == 1 && animation[Person::players[i]->animCurrent].attack == neutral)) ||
+                                                                                 k != 0 && Person::players[i]->skeleton.oldfree == 1 && Animation::animations[Person::players[k]->animCurrent].attack == neutral ||
+                                                                                 /*i!=0&&*/Person::players[k]->skeleton.oldfree == 1 && Animation::animations[Person::players[i]->animCurrent].attack == neutral)) ||
                                                                                 (Person::players[i]->animTarget == jumpupanim || Person::players[i]->animTarget == jumpdownanim || Person::players[i]->isFlip()) &&
                                                                                 (Person::players[k]->animTarget == jumpupanim || Person::players[k]->animTarget == jumpdownanim || Person::players[k]->isFlip()) &&
                                                                                 k == 0 && !Person::players[i]->skeleton.oldfree && !Person::players[k]->skeleton.oldfree) {
                                                                             //If hit by body
                                                                             if (     (i != 0 || Person::players[i]->skeleton.free) &&
                                                                                      (k != 0 || Person::players[k]->skeleton.free) ||
-                                                                                     (animation[Person::players[i]->animTarget].height == highheight &&
-                                                                                      animation[Person::players[k]->animTarget].height == highheight)) {
+                                                                                     (Animation::animations[Person::players[i]->animTarget].height == highheight &&
+                                                                                      Animation::animations[Person::players[k]->animTarget].height == highheight)) {
                                                                                 if (tutoriallevel != 1) {
                                                                                     emit_sound_at(heavyimpactsound, Person::players[i]->coords);
                                                                                 }
@@ -3606,19 +3539,19 @@ void doPlayerCollisions()
                                                                                 }
                                                                                 Person::players[k]->DoDamage(findLengthfast(&rotatetarget) / 4);
 
-                                                                                for (int j = 0; j < Person::players[i]->skeleton.num_joints; j++) {
+                                                                                for (int j = 0; j < Person::players[i]->skeleton.joints.size(); j++) {
                                                                                     Person::players[i]->skeleton.joints[j].velocity = Person::players[i]->skeleton.joints[j].velocity / 5 + Person::players[k]->velocity;
                                                                                 }
-                                                                                for (int j = 0; j < Person::players[k]->skeleton.num_joints; j++) {
+                                                                                for (int j = 0; j < Person::players[k]->skeleton.joints.size(); j++) {
                                                                                     Person::players[k]->skeleton.joints[j].velocity = Person::players[k]->skeleton.joints[j].velocity / 5 + Person::players[i]->velocity;
                                                                                 }
 
                                                                             }
                                                                         }
-                                                                    if (     (animation[Person::players[i]->animTarget].attack == neutral ||
-                                                                              animation[Person::players[i]->animTarget].attack == normalattack) &&
-                                                                             (animation[Person::players[k]->animTarget].attack == neutral ||
-                                                                              animation[Person::players[k]->animTarget].attack == normalattack)) {
+                                                                    if (     (Animation::animations[Person::players[i]->animTarget].attack == neutral ||
+                                                                              Animation::animations[Person::players[i]->animTarget].attack == normalattack) &&
+                                                                             (Animation::animations[Person::players[k]->animTarget].attack == neutral ||
+                                                                              Animation::animations[Person::players[k]->animTarget].attack == normalattack)) {
                                                                         //If bumped
                                                                         if (Person::players[i]->skeleton.oldfree == 0 && Person::players[k]->skeleton.oldfree == 0) {
                                                                             if (distsq(&Person::players[k]->coords, &Person::players[i]->coords) < .5 * sq((Person::players[i]->scale + Person::players[k]->scale) * 2.5)) {
@@ -3839,12 +3772,12 @@ void doAI(unsigned i)
                     distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 400 &&
                     Person::players[i]->occluded < 25) {
                 if (distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 12 &&
-                        animation[Person::players[0]->animTarget].height != lowheight &&
+                        Animation::animations[Person::players[0]->animTarget].height != lowheight &&
                         !editorenabled &&
                         (Person::players[0]->coords.y < Person::players[i]->coords.y + 5 || Person::players[0]->onterrain))
                     Person::players[i]->aitype = attacktypecutoff;
                 if (distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 30 &&
-                        animation[Person::players[0]->animTarget].height == highheight &&
+                        Animation::animations[Person::players[0]->animTarget].height == highheight &&
                         !editorenabled)
                     Person::players[i]->aitype = attacktypecutoff;
 
@@ -3852,7 +3785,7 @@ void doAI(unsigned i)
                     Person::players[i]->losupdatedelay = .2;
                     for (unsigned j = 0; j < Person::players.size(); j++)
                         if (j == 0 || Person::players[j]->skeleton.free || Person::players[j]->aitype != passivetype)
-                            if (abs(Random() % 2) || animation[Person::players[j]->animTarget].height != lowheight || j != 0)
+                            if (abs(Random() % 2) || Animation::animations[Person::players[j]->animTarget].height != lowheight || j != 0)
                                 if (distsq(&Person::players[i]->coords, &Person::players[j]->coords) < 400)
                                     if (normaldotproduct(Person::players[i]->facing, Person::players[j]->coords - Person::players[i]->coords) > 0)
                                         if (Person::players[j]->coords.y < Person::players[i]->coords.y + 5 || Person::players[j]->onterrain)
@@ -3962,10 +3895,10 @@ void doAI(unsigned i)
                     distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 400 &&
                     Person::players[i]->occluded < 25) {
                 if (distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 12 &&
-                        animation[Person::players[0]->animTarget].height != lowheight && !editorenabled)
+                        Animation::animations[Person::players[0]->animTarget].height != lowheight && !editorenabled)
                     Person::players[i]->aitype = attacktypecutoff;
                 if (distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 30 &&
-                        animation[Person::players[0]->animTarget].height == highheight && !editorenabled)
+                        Animation::animations[Person::players[0]->animTarget].height == highheight && !editorenabled)
                     Person::players[i]->aitype = attacktypecutoff;
 
                 //wolf smell
@@ -3996,7 +3929,7 @@ void doAI(unsigned i)
                     Person::players[i]->losupdatedelay = .2;
                     for (unsigned j = 0; j < Person::players.size(); j++) {
                         if (j == 0 || Person::players[j]->skeleton.free || Person::players[j]->aitype != passivetype) {
-                            if (abs(Random() % 2) || animation[Person::players[j]->animTarget].height != lowheight || j != 0)
+                            if (abs(Random() % 2) || Animation::animations[Person::players[j]->animTarget].height != lowheight || j != 0)
                                 if (distsq(&Person::players[i]->coords, &Person::players[j]->coords) < 400)
                                     if (normaldotproduct(Person::players[i]->facing, Person::players[j]->coords - Person::players[i]->coords) > 0)
                                         if ((-1 == checkcollide(
@@ -4008,7 +3941,7 @@ void doAI(unsigned i)
                                                 (Person::players[j]->animTarget == hanganim &&
                                                  normaldotproduct(Person::players[j]->facing, Person::players[i]->coords - Person::players[j]->coords) < 0)) {
                                             Person::players[i]->lastseentime -= .2;
-                                            if (j == 0 && animation[Person::players[j]->animTarget].height == lowheight)
+                                            if (j == 0 && Animation::animations[Person::players[j]->animTarget].height == lowheight)
                                                 Person::players[i]->lastseentime -= .4;
                                             else
                                                 Person::players[i]->lastseentime -= .6;
@@ -4130,11 +4063,11 @@ void doAI(unsigned i)
                     Person::players[i]->occluded < 2 &&
                     ((tutoriallevel != 1 || cananger) && hostile)) {
                 Person::players[i]->losupdatedelay = .2;
-                if (distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 4 && animation[Person::players[i]->animTarget].height != lowheight) {
+                if (distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 4 && Animation::animations[Person::players[i]->animTarget].height != lowheight) {
                     Person::players[i]->aitype = attacktypecutoff;
                     Person::players[i]->lastseentime = 1;
                 }
-                if (abs(Random() % 2) || animation[Person::players[i]->animTarget].height != lowheight)
+                if (abs(Random() % 2) || Animation::animations[Person::players[i]->animTarget].height != lowheight)
                     //TODO: factor out canSeePlayer()
                     if (distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 400)
                         if (normaldotproduct(Person::players[i]->facing, Person::players[0]->coords - Person::players[i]->coords) > 0)
@@ -4412,7 +4345,7 @@ void doAI(unsigned i)
                         }
             //dodge/reverse walljump kicks
             if (Person::players[i]->damage < Person::players[i]->damagetolerance / 2)
-                if (animation[Person::players[i]->animTarget].height != highheight)
+                if (Animation::animations[Person::players[i]->animTarget].height != highheight)
                     if (Person::players[i]->damage < Person::players[i]->damagetolerance * .5 &&
                             ((Person::players[0]->animTarget == walljumprightkickanim ||
                               Person::players[0]->animTarget == walljumpleftkickanim) &&
@@ -4450,7 +4383,7 @@ void doAI(unsigned i)
                 }
             //lose sight of player in the air (?)
             if (Person::players[0]->coords.y > Person::players[i]->coords.y + 5 &&
-                    animation[Person::players[0]->animTarget].height != highheight &&
+                    Animation::animations[Person::players[0]->animTarget].height != highheight &&
                     !Person::players[0]->onterrain) {
                 Person::players[i]->aitype = pathfindtype;
                 Person::players[i]->finalfinaltarget = Person::players[i]->waypoints[Person::players[i]->waypoint];
@@ -4463,7 +4396,7 @@ void doAI(unsigned i)
             }
             //it's time to think (?)
             if (Person::players[i]->aiupdatedelay < 0 &&
-                    !animation[Person::players[i]->animTarget].attack &&
+                    !Animation::animations[Person::players[i]->animTarget].attack &&
                     Person::players[i]->animTarget != staggerbackhighanim &&
                     Person::players[i]->animTarget != staggerbackhardanim &&
                     Person::players[i]->animTarget != backhandspringanim &&
@@ -4612,7 +4545,7 @@ void doAI(unsigned i)
                         Person::players[i]->lastseentime = 1;
             }
         }
-        if (animation[Person::players[0]->animTarget].height == highheight &&
+        if (Animation::animations[Person::players[0]->animTarget].height == highheight &&
                 (Person::players[i]->aitype == attacktypecutoff ||
                  Person::players[i]->aitype == searchtype))
             if (Person::players[0]->coords.y > terrain.getHeight(Person::players[0]->coords.x, Person::players[0]->coords.z) + 10) {
@@ -4706,7 +4639,7 @@ void updateSettingsMenu()
 void updateStereoConfigMenu()
 {
     char sbuf[256];
-    sprintf(sbuf, "Stereo mode: %s", StereoModeName(newstereomode));
+    sprintf(sbuf, "Stereo mode: %s", StereoModeName(newstereomode).c_str());
     Menu::setText(0, sbuf);
     sprintf(sbuf, "Stereo separation: %.3f", stereoseparation);
     Menu::setText(1, sbuf);
@@ -5214,7 +5147,7 @@ void MenuTick()
                 if (selected == 0) {
                     newstereomode = (StereoMode)(newstereomode + 1);
                     while (!CanInitStereo(newstereomode)) {
-                        printf("Failed to initialize mode %s (%i)\n", StereoModeName(newstereomode), newstereomode);
+                        printf("Failed to initialize mode %s (%i)\n", StereoModeName(newstereomode).c_str(), newstereomode);
                         newstereomode = (StereoMode)(newstereomode + 1);
                         if (newstereomode >= stereoCount)
                             newstereomode = stereoNone;
@@ -5489,7 +5422,7 @@ void Game::Tick()
                 talkdelay = 1;
             talkdelay -= multiplier;
 
-            if (talkdelay <= 0 && !Dialog::inDialog() && animation[Person::players[0]->animTarget].height != highheight) {
+            if (talkdelay <= 0 && !Dialog::inDialog() && Animation::animations[Person::players[0]->animTarget].height != highheight) {
                 for (int i = 0; i < Dialog::dialogs.size(); i++) {
                     Dialog::dialogs[i].tick(i);
                 }
@@ -5501,27 +5434,27 @@ void Game::Tick()
 
             //hotspots
             static float hotspotvisual[40];
-            if (numhotspots) {
+            if (Hotspot::hotspots.size()) {
                 XYZ hotspotsprite;
                 if (editorenabled)
-                    for (int i = 0; i < numhotspots; i++)
+                    for (int i = 0; i < Hotspot::hotspots.size(); i++)
                         hotspotvisual[i] -= multiplier / 320;
 
-                for (int i = 0; i < numhotspots; i++) {
+                for (int i = 0; i < Hotspot::hotspots.size(); i++) {
                     while (hotspotvisual[i] < 0) {
                         hotspotsprite = 0;
-                        hotspotsprite.x = float(abs(Random() % 100000)) / 100000 * hotspotsize[i];
+                        hotspotsprite.x = float(abs(Random() % 100000)) / 100000 * Hotspot::hotspots[i].size;
                         hotspotsprite = DoRotation(hotspotsprite, 0, 0, Random() % 360);
                         hotspotsprite = DoRotation(hotspotsprite, 0, Random() % 360, 0);
-                        hotspotsprite += hotspot[i];
+                        hotspotsprite += Hotspot::hotspots[i].position;
                         Sprite::MakeSprite(breathsprite, hotspotsprite, hotspotsprite * 0, 1, 0.5, 0, 7, 0.4);
-                        hotspotvisual[i] += 0.1 / hotspotsize[i] / hotspotsize[i] / hotspotsize[i];
+                        hotspotvisual[i] += 0.1 / Hotspot::hotspots[i].size / Hotspot::hotspots[i].size / Hotspot::hotspots[i].size;
                     }
                 }
 
-                for (int i = 0; i < numhotspots; i++) {
-                    if (hotspottype[i] <= 10 && hotspottype[i] > 0) {
-                        hotspot[i] = Person::players[hotspottype[i]]->coords;
+                for (int i = 0; i < Hotspot::hotspots.size(); i++) {
+                    if (Hotspot::hotspots[i].type <= 10 && Hotspot::hotspots[i].type > 0) {
+                        Hotspot::hotspots[i].position = Person::players[Hotspot::hotspots[i].type]->coords;
                     }
                 }
             }
@@ -5730,11 +5663,7 @@ void Game::Tick()
                                 if (Dialog::currentScene().sound != 0) {
                                     playdialoguescenesound();
                                     if (Dialog::currentScene().sound == -5) {
-                                        hotspot[numhotspots] = Person::players[0]->coords;
-                                        hotspotsize[numhotspots] = 10;
-                                        hotspottype[numhotspots] = -1;
-
-                                        numhotspots++;
+                                        Hotspot::hotspots.emplace_back(Person::players[0]->coords, -1, 10);
                                     }
                                     if (Dialog::currentScene().sound == -6) {
                                         hostile = 1;
@@ -5844,7 +5773,7 @@ void Game::Tick()
                     oldtargetyaw = Person::players[i]->targetyaw;
                     if (i == 0 && !Dialog::inDialog()) {
                         //TODO: refactor repetitive code
-                        if (!animation[Person::players[0]->animTarget].attack &&
+                        if (!Animation::animations[Person::players[0]->animTarget].attack &&
                                 Person::players[0]->animTarget != staggerbackhighanim &&
                                 Person::players[0]->animTarget != staggerbackhardanim &&
                                 Person::players[0]->animTarget != crouchremoveknifeanim &&
@@ -5876,7 +5805,7 @@ void Game::Tick()
                         Person::players[i]->targetheadpitch = pitch;
                     }
                     if (i != 0 && Person::players[i]->aitype == playercontrolled && !Dialog::inDialog()) {
-                        if (!animation[Person::players[i]->animTarget].attack &&
+                        if (!Animation::animations[Person::players[i]->animTarget].attack &&
                                 Person::players[i]->animTarget != staggerbackhighanim &&
                                 Person::players[i]->animTarget != staggerbackhardanim &&
                                 Person::players[i]->animTarget != crouchremoveknifeanim &&
@@ -5946,7 +5875,7 @@ void Game::Tick()
 
                     doAI(i);
 
-                    if (animation[Person::players[i]->animTarget].attack == reversed) {
+                    if (Animation::animations[Person::players[i]->animTarget].attack == reversed) {
                         //Person::players[i]->targetyaw=Person::players[i]->yaw;
                         Person::players[i]->forwardkeydown = 0;
                         Person::players[i]->leftkeydown = 0;
@@ -5991,7 +5920,7 @@ void Game::Tick()
                             Person::players[i]->aitype == attacktypecutoff &&
                             !Person::players[i]->dead &&
                             !Person::players[i]->skeleton.free &&
-                            animation[Person::players[i]->animTarget].attack == neutral)
+                            Animation::animations[Person::players[i]->animTarget].attack == neutral)
                         numresponded = 1;
 
                     if (!Person::players[i]->throwkeydown)
@@ -6130,7 +6059,7 @@ void Game::Tick()
                                                                 Person::players[i]->victim->skeleton.free = 1;
                                                                 Person::players[i]->victim->skeleton.broken = 0;
 
-                                                                for (int l = 0; l < Person::players[i]->victim->skeleton.num_joints; l++) {
+                                                                for (int l = 0; l < Person::players[i]->victim->skeleton.joints.size(); l++) {
                                                                     Person::players[i]->victim->skeleton.joints[l].velchange = 0;
                                                                     Person::players[i]->victim->skeleton.joints[l].locked = 0;
                                                                 }
@@ -6319,7 +6248,7 @@ void Game::Tick()
                     }
                     movekey = 0;
                     //Do controls
-                    if (!animation[Person::players[i]->animTarget].attack &&
+                    if (!Animation::animations[Person::players[i]->animTarget].attack &&
                             Person::players[i]->animTarget != staggerbackhighanim &&
                             Person::players[i]->animTarget != staggerbackhardanim &&
                             Person::players[i]->animTarget != backhandspringanim &&
@@ -6757,7 +6686,7 @@ void Game::Tick()
                     if (distsq(&temp, &Person::players[1]->coords) >= distsq(&temp, &temp2) - 1 || distsq(&temp3, &Person::players[1]->coords) < 4) {
                         emit_sound_at(fireendsound, Person::players[1]->coords);
 
-                        for (int i = 0; i < Person::players[1]->skeleton.num_joints; i++) {
+                        for (int i = 0; i < Person::players[1]->skeleton.joints.size(); i++) {
                             if (Random() % 2 == 0) {
                                 if (!Person::players[1]->skeleton.free)
                                     temp2 = (Person::players[1]->coords - Person::players[1]->oldcoords) / multiplier / 2; //velocity/2;
@@ -6772,7 +6701,7 @@ void Game::Tick()
                         }
 
                         Person::players[1]->coords = (oldtemp + oldtemp2) / 2;
-                        for (int i = 0; i < Person::players[1]->skeleton.num_joints; i++) {
+                        for (int i = 0; i < Person::players[1]->skeleton.joints.size(); i++) {
                             Person::players[1]->skeleton.joints[i].velocity = 0;
                             if (Random() % 2 == 0) {
                                 if (!Person::players[1]->skeleton.free)
@@ -6974,23 +6903,23 @@ void Game::TickOnceAfter()
             }
         }
 
-        killhotspot = 2;
-        for (int i = 0; i < numhotspots; i++) {
-            if (hotspottype[i] > 10 && hotspottype[i] < 20) {
-                if (Person::players[hotspottype[i] - 10]->dead == 0)
-                    killhotspot = 0;
-                else if (killhotspot == 2)
-                    killhotspot = 1;
+        Hotspot::killhotspot = 2;
+        for (int i = 0; i < Hotspot::hotspots.size(); i++) {
+            if (Hotspot::hotspots[i].type > 10 && Hotspot::hotspots[i].type < 20) {
+                if (Person::players[Hotspot::hotspots[i].type - 10]->dead == 0)
+                    Hotspot::killhotspot = 0;
+                else if (Hotspot::killhotspot == 2)
+                    Hotspot::killhotspot = 1;
             }
         }
-        if (killhotspot == 2)
-            killhotspot = 0;
+        if (Hotspot::killhotspot == 2)
+            Hotspot::killhotspot = 0;
 
 
         winhotspot = false;
-        for (int i = 0; i < numhotspots; i++)
-            if (hotspottype[i] == -1)
-                if (distsq(&Person::players[0]->coords, &hotspot[i]) < hotspotsize[i])
+        for (int i = 0; i < Hotspot::hotspots.size(); i++)
+            if (Hotspot::hotspots[i].type == -1)
+                if (distsq(&Person::players[0]->coords, &Hotspot::hotspots[i].position) < Hotspot::hotspots[i].size)
                     winhotspot = true;
 
         int numalarmed = 0;
@@ -7028,7 +6957,7 @@ void Game::TickOnceAfter()
             }
 
 
-            if (killhotspot) {
+            if (Hotspot::killhotspot) {
                 changedelay = 1;
                 targetlevel = whichlevel + 1;
                 if (targetlevel > numchallengelevels - 1)
@@ -7054,7 +6983,7 @@ void Game::TickOnceAfter()
                 changedelay = .1;
                 alldead = false;
                 winhotspot = false;
-                killhotspot = 0;
+                Hotspot::killhotspot = 0;
             }
 
             if (!editorenabled && gameon && !mainmenu) {
@@ -7096,13 +7025,13 @@ void Game::TickOnceAfter()
                         (Person::players[0]->dead ||
                          (alldead && maptype == mapkilleveryone) ||
                          (winhotspot) ||
-                         (killhotspot)))
+                         (Hotspot::killhotspot)))
                     loading = 1;
                 if ((Person::players[0]->dead ||
                         (alldead && maptype == mapkilleveryone) ||
                         (winhotspot) ||
                         (windialogue) ||
-                        (killhotspot)) &&
+                        (Hotspot::killhotspot)) &&
                         changedelay <= 0) {
                     if (whichlevel != -2 && !loading && !Person::players[0]->dead) {
                         winfreeze = true;
@@ -7169,13 +7098,13 @@ void Game::TickOnceAfter()
     viewerfacing = facing;
 
     if (!cameramode) {
-        if ((animation[Person::players[0]->animTarget].attack != 3 && animation[Person::players[0]->animCurrent].attack != 3) || Person::players[0]->skeleton.free)
+        if ((Animation::animations[Person::players[0]->animTarget].attack != 3 && Animation::animations[Person::players[0]->animCurrent].attack != 3) || Person::players[0]->skeleton.free)
             target = Person::players[0]->coords + Person::players[0]->currentoffset * (1 - Person::players[0]->target) * Person::players[0]->scale + Person::players[0]->targetoffset * Person::players[0]->target * Person::players[0]->scale - Person::players[0]->facing * .05;
         else
             target = Person::players[0]->oldcoords + Person::players[0]->currentoffset * (1 - Person::players[0]->target) * Person::players[0]->scale + Person::players[0]->targetoffset * Person::players[0]->target * Person::players[0]->scale - Person::players[0]->facing * .05;
         target.y += .1;
         if (Person::players[0]->skeleton.free) {
-            for (int i = 0; i < Person::players[0]->skeleton.num_joints; i++) {
+            for (int i = 0; i < Person::players[0]->skeleton.joints.size(); i++) {
                 if (Person::players[0]->skeleton.joints[i].position.y * Person::players[0]->scale + Person::players[0]->coords.y > target.y)
                     target.y = Person::players[0]->skeleton.joints[i].position.y * Person::players[0]->scale + Person::players[0]->coords.y;
             }