]> git.jsancho.org Git - lugaru.git/blobdiff - Source/Objects/Person.cpp
New non-atacking player
[lugaru.git] / Source / Objects / Person.cpp
index 1ac664c896b2dab753eab5890b0e4ce61d7e9715..8022c0fc3323f023bc485bb3ff2eb20a7ae12ad9 100644 (file)
@@ -1,6 +1,6 @@
 /*
 Copyright (C) 2003, 2010 - Wolfire Games
-Copyright (C) 2010-2016 - Lugaru contributors (see AUTHORS file)
+Copyright (C) 2010-2017 - Lugaru contributors (see AUTHORS file)
 
 This file is part of Lugaru.
 
@@ -42,8 +42,6 @@ extern float slomodelay;
 extern bool cellophane;
 extern float texdetail;
 extern float realtexdetail;
-extern GLubyte bloodText[512 * 512 * 3];
-extern GLubyte wolfbloodText[512 * 512 * 3];
 extern int bloodtoggle;
 extern bool autoslomo;
 extern float camerashake;
@@ -74,7 +72,7 @@ extern float envsoundlife[30];
 
 extern XYZ windvector;
 
-std::vector<std::shared_ptr<Person>> Person::players(1, std::shared_ptr<Person>(new Person()));
+std::vector<std::shared_ptr<Person>> Person::players;
 
 Person::Person()
     : whichpatchx(0)
@@ -104,21 +102,12 @@ Person::Person()
     , oldcoords()
     , coords()
     , velocity()
-    ,
 
-    proportionhead()
-    , proportionlegs()
-    , proportionarms()
-    , proportionbody()
-    ,
+    , unconscioustime(0)
 
-    unconscioustime(0)
-    ,
-
-    immobile(false)
-    ,
+    , immobile(false)
 
-    velspeed(0)
+    velspeed(0)
     , targetyaw(0)
     , targetrot(0)
     , rot(0)
@@ -141,30 +130,24 @@ Person::Person()
     , skiddingdelay(0)
     , deathbleeding(0)
     , tempdeltav(0)
-    ,
 
-    damagetolerance(200)
+    , damagetolerance(0)
     , damage(0)
     , permanentdamage(0)
     , superpermanentdamage(0)
     , lastcollide(0)
     , dead(0)
-    ,
 
-    jumppower(5)
+    jumppower(5)
     , onground(false)
-    ,
 
-    wentforweapon(0)
-    ,
+    , wentforweapon(0)
 
-    calcrot(false)
-    ,
+    , calcrot(false)
 
-    facing()
-    ,
+    , facing()
 
-    bleeding(0)
+    bleeding(0)
     , bleedx(0)
     , bleedy(0)
     , direction(0)
@@ -186,6 +169,7 @@ Person::Person()
 
     victim(nullptr)
     , hasvictim(false)
+    , isplayerfriend(false)
     ,
 
     updatedelay(0)
@@ -353,17 +337,16 @@ Person::Person()
     , neckspurtdelay(0)
     , neckspurtparticledelay(0)
     , neckspurtamount(0)
-    ,
 
-    whichskin(0)
+    whichskin(0)
     , rabbitkickragdoll(false)
-    ,
 
-    tempanimation()
-    ,
+    , tempanimation("Tempanim", lowheight, neutral)
 
-    jumpclimb(false)
+    jumpclimb(false)
 {
+    damagetolerance = PersonType::types[creature].defaultDamageTolerance;
+    setProportions(1, 1, 1, 1);
 }
 
 /* Read a person in tfile. Throws an error if it’s not valid */
@@ -426,28 +409,10 @@ Person::Person(FILE* tfile, int mapvers, unsigned i)
     funpackf(tfile, "Bf Bf Bf", &metalhead, &metalhigh, &metallow);
     funpackf(tfile, "Bf Bf", &power, &speedmult);
 
-    float headprop, legprop, armprop, bodyprop;
-
     if (mapvers >= 4) {
-        funpackf(tfile, "Bf Bf Bf Bf", &headprop, &bodyprop, &armprop, &legprop);
+        funpackf(tfile, "Bf Bf Bf Bf", &proportions[0], &proportions[1], &proportions[2], &proportions[3]);
     } else {
-        headprop = 1;
-        bodyprop = 1;
-        armprop = 1;
-        legprop = 1;
-    }
-
-    if (creature == wolftype) {
-        proportionhead = 1.1 * headprop;
-        proportionbody = 1.1 * bodyprop;
-        proportionarms = 1.1 * armprop;
-        proportionlegs = 1.1 * legprop;
-    } else if (creature == rabbittype) {
-        proportionhead = 1.2 * headprop;
-        proportionbody = 1.05 * bodyprop;
-        proportionarms = 1.00 * armprop;
-        proportionlegs = 1.1 * legprop;
-        proportionlegs.y = 1.05 * legprop;
+        setProportions(1, 1, 1, 1);
     }
 
     funpackf(tfile, "Bi", &numclothes);
@@ -463,55 +428,66 @@ Person::Person(FILE* tfile, int mapvers, unsigned i)
 
     loaded = true;
 
+    damagetolerance = PersonType::types[creature].defaultDamageTolerance;
+
     if (scale < 0) {
-        if (creature == wolftype) {
-            scale = .23;
-            damagetolerance = 300;
-        } else {
-            scale = .2;
-        }
+        scale = PersonType::types[creature].defaultScale;
     }
 
     oldcoords = coords;
     realoldcoords = coords;
 }
 
-void Person::skeletonLoad(bool clothes)
+void Person::changeCreatureType(person_type type)
+{
+    creature = type;
+    whichskin = 0;
+    skeletonLoad();
+    scale = PersonType::types[creature].defaultScale;
+    damagetolerance = PersonType::types[creature].defaultDamageTolerance;
+}
+
+void Person::skeletonLoad()
 {
     skeleton.id = id;
-    if (creature != wolftype) {
-        skeleton.Load(
-            "Skeleton/BasicFigure",
-            "Skeleton/BasicFigureLow",
-            "Skeleton/RabbitBelt",
-            "Models/Body.solid",
-            "Models/Body2.solid",
-            "Models/Body3.solid",
-            "Models/Body4.solid",
-            "Models/Body5.solid",
-            "Models/Body6.solid",
-            "Models/Body7.solid",
-            "Models/BodyLow.solid",
-            "Models/Belt.solid",
-            clothes);
-    } else {
-        skeleton.Load(
-            "Skeleton/BasicFigureWolf",
-            "Skeleton/BasicFigureWolfLow",
-            "Skeleton/RabbitBelt",
-            "Models/Wolf.solid",
-            "Models/Wolf2.solid",
-            "Models/Wolf3.solid",
-            "Models/Wolf4.solid",
-            "Models/Wolf5.solid",
-            "Models/Wolf6.solid",
-            "Models/Wolf7.solid",
-            "Models/WolfLow.solid",
-            "Models/Belt.solid",
-            clothes);
-    }
-
-    skeleton.drawmodel.textureptr.load(creatureskin[creature][whichskin], 1, &skeleton.skinText[0], &skeleton.skinsize);
+    skeleton.Load(
+        PersonType::types[creature].figureFileName,
+        PersonType::types[creature].lowFigureFileName,
+        PersonType::types[creature].clothesFileName,
+        PersonType::types[creature].modelFileNames[0],
+        PersonType::types[creature].modelFileNames[1],
+        PersonType::types[creature].modelFileNames[2],
+        PersonType::types[creature].modelFileNames[3],
+        PersonType::types[creature].modelFileNames[4],
+        PersonType::types[creature].modelFileNames[5],
+        PersonType::types[creature].modelFileNames[6],
+        PersonType::types[creature].lowModelFileName,
+        PersonType::types[creature].modelClothesFileName,
+        PersonType::types[creature].clothes);
+
+    skeleton.drawmodel.textureptr.load(PersonType::types[creature].skins[whichskin], 1, &skeleton.skinText[0], &skeleton.skinsize);
+}
+
+void Person::setProportions(float head, float body, float arms, float legs)
+{
+    proportions[0] = head;
+    proportions[1] = body;
+    proportions[2] = arms;
+    proportions[3] = legs;
+}
+
+float Person::getProportion(int part) const
+{
+    return proportions[part];
+}
+
+XYZ Person::getProportionXYZ(int part) const
+{
+    XYZ prop = PersonType::types[creature].proportions[part] * proportions[part];
+    if (cellophane) {
+        prop.z = 0;
+    }
+    return prop;
 }
 
 /* EFFECT
@@ -526,7 +502,7 @@ void Person::CheckKick()
     }
 
     if (Animation::animations[victim->animTarget].height != lowheight) {
-        float damagemult = (creature == wolftype ? 2.5 : 1.) * power * power;
+        float damagemult = PersonType::types[creature].power * power * power;
         XYZ relative = velocity;
         relative.y = 0;
         Normalise(&relative);
@@ -578,8 +554,8 @@ void Person::CheckKick()
 /* EFFECT
  *
  * USES:
- * GameTick/doPlayerCollisions - spread fire between players
- * GameTick/doDevKeys - press f to ignite
+ * GameTick::doPlayerCollisions - spread fire between players
+ * GameTick::ProcessDevKeys - press f to ignite
  * Person::DoStuff - spread fire from lit campfires and bushes
  */
 void Person::CatchFire()
@@ -614,26 +590,21 @@ void Person::CatchFire()
  */
 int Person::getIdle()
 {
-    if (Dialog::inDialog() && (howactive == typeactive) && (creature == rabbittype)) {
-        return talkidleanim;
+    if (Dialog::inDialog() && (howactive == typeactive) && PersonType::types[creature].hasAnimTalkIdle()) {
+        return PersonType::types[creature].animTalkIdle;
     }
     if (hasvictim && (victim != this->shared_from_this())) {
         if ((!victim->dead && victim->aitype != passivetype &&
              victim->aitype != searchtype && aitype != passivetype && aitype != searchtype &&
              victim->id < Person::players.size())) {
-            if ((aitype == playercontrolled && stunned <= 0 && weaponactive == -1) || pause) {
-                if (creature == rabbittype) {
-                    return fightidleanim;
-                }
-                if (creature == wolftype) {
-                    return wolfidle;
-                }
+            if ((isPlayerControlled() && (stunned <= 0) && !hasWeapon()) || pause) {
+                return PersonType::types[creature].animFightIdle;
             }
-            if (aitype == playercontrolled && stunned <= 0 && weaponactive != -1) {
+            if (isPlayerControlled() && (stunned <= 0) && hasWeapon()) {
                 if (weapons[weaponids[weaponactive]].getType() == knife) {
                     return knifefightidleanim;
                 }
-                if (weapons[weaponids[weaponactive]].getType() == sword && victim->weaponactive != -1) {
+                if (weapons[weaponids[weaponactive]].getType() == sword && victim->hasWeapon()) {
                     return swordfightidlebothanim;
                 }
                 if (weapons[weaponids[weaponactive]].getType() == sword) {
@@ -643,13 +614,13 @@ int Person::getIdle()
                     return swordfightidleanim;
                 }
             }
-            if (aitype != playercontrolled && stunned <= 0 && creature != wolftype && !pause) {
+            if (!isPlayerControlled() && (stunned <= 0) && creature != wolftype) {
                 return fightsidestep;
             }
         }
     }
-    if ((damage > permanentdamage || damage > damagetolerance * .8 || deathbleeding > 0) && creature != wolftype) {
-        return hurtidleanim;
+    if ((damage > permanentdamage || damage > damagetolerance * .8 || deathbleeding > 0) && PersonType::types[creature].hasAnimHurtIdle()) {
+        return PersonType::types[creature].animHurtIdle;
     }
     if (howactive == typesitting) {
         return sitanim;
@@ -672,13 +643,7 @@ int Person::getIdle()
     if (howactive == typedead4) {
         return dead4anim;
     }
-    if (creature == rabbittype) {
-        return bounceidleanim;
-    }
-    if (creature == wolftype) {
-        return wolfidle;
-    }
-    return 0;
+    return PersonType::types[creature].animBounceIdle;
 }
 
 /* FUNCTION
@@ -686,13 +651,7 @@ int Person::getIdle()
  */
 int Person::getCrouch()
 {
-    if (creature == rabbittype) {
-        return crouchanim;
-    }
-    if (creature == wolftype) {
-        return wolfcrouchanim;
-    }
-    return 0;
+    return PersonType::types[creature].animCrouch;
 }
 
 /* FUNCTION
@@ -700,59 +659,32 @@ int Person::getCrouch()
  */
 int Person::getRun()
 {
-    if (creature == rabbittype && (!superruntoggle || weaponactive != -1)) {
-        return runanim;
-    }
-    if (creature == wolftype && (!superruntoggle)) {
-        return wolfrunanim;
-    }
-
-    if (creature == rabbittype && (superruntoggle && weaponactive == -1)) {
-        return rabbitrunninganim;
-    }
-    if (creature == wolftype && (superruntoggle)) {
-        return wolfrunninganim;
+    if (superruntoggle && (!hasWeapon())) {
+        return PersonType::types[creature].animRunning;
+    } else {
+        return PersonType::types[creature].animRun;
     }
-    return 0;
 }
 
 /* FUNCTION
  */
 int Person::getStop()
 {
-    if (creature == rabbittype) {
-        return stopanim;
-    }
-    if (creature == wolftype) {
-        return wolfstopanim;
-    }
-    return 0;
+    return PersonType::types[creature].animStop;
 }
 
 /* FUNCTION
  */
 int Person::getLanding()
 {
-    if (creature == rabbittype) {
-        return landanim;
-    }
-    if (creature == wolftype) {
-        return wolflandanim;
-    }
-    return 0;
+    return PersonType::types[creature].animLanding;
 }
 
 /* FUNCTION
  */
 int Person::getLandhard()
 {
-    if (creature == rabbittype) {
-        return landhardanim;
-    }
-    if (creature == wolftype) {
-        return wolflandhardanim;
-    }
-    return 0;
+    return PersonType::types[creature].animLandingHard;
 }
 
 /* EFFECT
@@ -826,17 +758,9 @@ void Person::DoBlood(float howmuch, int which)
             bleeding = howmuch + (float)abs(Random() % 100) / 200 - .25;
             bleedxint = 0;
             bleedyint = 0;
-            if (creature == rabbittype) {
-                while (bloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] > which + 4 || bloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] < which - 4 || bleedxint < 10 || bleedyint < 10 || bleedxint > 500 || bleedyint > 500) {
-                    bleedxint = abs(Random() % 512);
-                    bleedyint = abs(Random() % 512);
-                }
-            }
-            if (creature == wolftype) {
-                while (wolfbloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] > which + 4 || wolfbloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] < which - 4 || bleedxint < 10 || bleedyint < 10 || bleedxint > 500 || bleedyint > 500) {
-                    bleedxint = abs(Random() % 512);
-                    bleedyint = abs(Random() % 512);
-                }
+            while (PersonType::types[creature].bloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] > which + 4 || PersonType::types[creature].bloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] < which - 4 || bleedxint < 10 || bleedyint < 10 || bleedxint > 500 || bleedyint > 500) {
+                bleedxint = abs(Random() % 512);
+                bleedyint = abs(Random() % 512);
             }
             bleedy = bleedxint;
             bleedx = bleedyint;
@@ -863,7 +787,7 @@ void Person::DoBloodBig(float howmuch, int which)
     }
 
     if (!Tutorial::active || id == 0) {
-        if (aitype != playercontrolled && howmuch > 0) {
+        if (!isPlayerControlled() && howmuch > 0) {
             // play pain sounds
             int whichsound = -1;
 
@@ -949,42 +873,20 @@ void Person::DoBloodBig(float howmuch, int which)
         int endx = 0;
         int endy = 0;
         GLubyte color;
-        if (creature == rabbittype) {
-            for (i = 0; i < 512; i++) {
-                for (j = 0; j < 512; j++) {
-                    if (bloodText[i * 512 * 3 + j * 3 + 0] <= which + 4 && bloodText[i * 512 * 3 + j * 3 + 0] >= which - 4) {
-                        if (i < startx) {
-                            startx = i;
-                        }
-                        if (j < starty) {
-                            starty = j;
-                        }
-                        if (i > endx) {
-                            endx = i;
-                        }
-                        if (j > endy) {
-                            endy = j;
-                        }
+        for (i = 0; i < 512; i++) {
+            for (j = 0; j < 512; j++) {
+                if (PersonType::types[creature].bloodText[i * 512 * 3 + j * 3 + 0] <= which + 4 && PersonType::types[creature].bloodText[i * 512 * 3 + j * 3 + 0] >= which - 4) {
+                    if (i < startx) {
+                        startx = i;
                     }
-                }
-            }
-        }
-        if (creature == wolftype) {
-            for (i = 0; i < 512; i++) {
-                for (j = 0; j < 512; j++) {
-                    if (wolfbloodText[i * 512 * 3 + j * 3 + 0] <= which + 4 && wolfbloodText[i * 512 * 3 + j * 3 + 0] >= which - 4) {
-                        if (i < startx) {
-                            startx = i;
-                        }
-                        if (j < starty) {
-                            starty = j;
-                        }
-                        if (i > endx) {
-                            endx = i;
-                        }
-                        if (j > endy) {
-                            endy = j;
-                        }
+                    if (j < starty) {
+                        starty = j;
+                    }
+                    if (i > endx) {
+                        endx = i;
+                    }
+                    if (j > endy) {
+                        endy = j;
                     }
                 }
             }
@@ -1021,33 +923,16 @@ void Person::DoBloodBig(float howmuch, int which)
 
         int texdetailint = realtexdetail;
         int where;
-        if (creature == rabbittype) {
-            for (i = startx; i < endx; i++) {
-                for (j = starty; j < endy; j++) {
-                    if (bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] <= which + 4 && bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] >= which - 4) {
-                        color = Random() % 85 + 170;
-                        where = i * skeleton.skinsize * 3 + j * 3;
-                        if (skeleton.skinText[where + 0] > color / 2) {
-                            skeleton.skinText[where + 0] = color / 2;
-                        }
-                        skeleton.skinText[where + 1] = 0;
-                        skeleton.skinText[where + 2] = 0;
-                    }
-                }
-            }
-        }
-        if (creature == wolftype) {
-            for (i = startx; i < endx; i++) {
-                for (j = starty; j < endy; j++) {
-                    if (wolfbloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] <= which + 4 && wolfbloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] >= which - 4) {
-                        color = Random() % 85 + 170;
-                        where = i * skeleton.skinsize * 3 + j * 3;
-                        if (skeleton.skinText[where + 0] > color / 2) {
-                            skeleton.skinText[where + 0] = color / 2;
-                        }
-                        skeleton.skinText[where + 1] = 0;
-                        skeleton.skinText[where + 2] = 0;
+        for (i = startx; i < endx; i++) {
+            for (j = starty; j < endy; j++) {
+                if (PersonType::types[creature].bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] <= which + 4 && PersonType::types[creature].bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] >= which - 4) {
+                    color = Random() % 85 + 170;
+                    where = i * skeleton.skinsize * 3 + j * 3;
+                    if (skeleton.skinText[where + 0] > color / 2) {
+                        skeleton.skinText[where + 0] = color / 2;
                     }
+                    skeleton.skinText[where + 1] = 0;
+                    skeleton.skinText[where + 2] = 0;
                 }
             }
         }
@@ -1056,17 +941,9 @@ void Person::DoBloodBig(float howmuch, int which)
 
         bleedxint = 0;
         bleedyint = 0;
-        if (creature == rabbittype) {
-            while (bloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] > which + 4 || bloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] < which - 4 || bleedxint < 10 || bleedyint < 10 || bleedxint > 500 || bleedyint > 500) {
-                bleedxint = abs(Random() % 512);
-                bleedyint = abs(Random() % 512);
-            }
-        }
-        if (creature == wolftype) {
-            while (wolfbloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] > which + 4 || wolfbloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] < which - 4 || bleedxint < 10 || bleedyint < 10 || bleedxint > 500 || bleedyint > 500) {
-                bleedxint = abs(Random() % 512);
-                bleedyint = abs(Random() % 512);
-            }
+        while (PersonType::types[creature].bloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] > which + 4 || PersonType::types[creature].bloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] < which - 4 || bleedxint < 10 || bleedyint < 10 || bleedxint > 500 || bleedyint > 500) {
+            bleedxint = abs(Random() % 512);
+            bleedyint = abs(Random() % 512);
         }
         bleedy = bleedxint + offsetx;
         bleedx = bleedyint + offsety;
@@ -1090,7 +967,7 @@ void Person::DoBloodBig(float howmuch, int which)
     deathbleeding += bleeding;
     bloodloss += bleeding * 3;
 
-    if (!Tutorial::active && aitype != playercontrolled && bloodloss > damagetolerance * 2 / 3 && bloodloss < damagetolerance && creature == rabbittype) {
+    if (!Tutorial::active && !isPlayerControlled() && bloodloss > damagetolerance * 2 / 3 && bloodloss < damagetolerance && creature == rabbittype) {
         if (abs(Random() % 2) == 0) {
             aitype = gethelptype;
             lastseentime = 12;
@@ -1200,42 +1077,20 @@ bool Person::DoBloodBigWhere(float howmuch, int which, XYZ where)
             int endx = 0;
             int endy = 0;
             GLubyte color;
-            if (creature == rabbittype) {
-                for (i = 0; i < 512; i++) {
-                    for (j = 0; j < 512; j++) {
-                        if (bloodText[i * 512 * 3 + j * 3 + 0] <= which + 4 && bloodText[i * 512 * 3 + j * 3 + 0] >= which - 4) {
-                            if (i < startx) {
-                                startx = i;
-                            }
-                            if (j < starty) {
-                                starty = j;
-                            }
-                            if (i > endx) {
-                                endx = i;
-                            }
-                            if (j > endy) {
-                                endy = j;
-                            }
+            for (i = 0; i < 512; i++) {
+                for (j = 0; j < 512; j++) {
+                    if (PersonType::types[creature].bloodText[i * 512 * 3 + j * 3 + 0] <= which + 4 && PersonType::types[creature].bloodText[i * 512 * 3 + j * 3 + 0] >= which - 4) {
+                        if (i < startx) {
+                            startx = i;
                         }
-                    }
-                }
-            }
-            if (creature == wolftype) {
-                for (i = 0; i < 512; i++) {
-                    for (j = 0; j < 512; j++) {
-                        if (wolfbloodText[i * 512 * 3 + j * 3 + 0] <= which + 4 && wolfbloodText[i * 512 * 3 + j * 3 + 0] >= which - 4) {
-                            if (i < startx) {
-                                startx = i;
-                            }
-                            if (j < starty) {
-                                starty = j;
-                            }
-                            if (i > endx) {
-                                endx = i;
-                            }
-                            if (j > endy) {
-                                endy = j;
-                            }
+                        if (j < starty) {
+                            starty = j;
+                        }
+                        if (i > endx) {
+                            endx = i;
+                        }
+                        if (j > endy) {
+                            endy = j;
                         }
                     }
                 }
@@ -1271,49 +1126,24 @@ bool Person::DoBloodBigWhere(float howmuch, int which, XYZ where)
 
             int texdetailint = realtexdetail;
             int where;
-            if (creature == rabbittype) {
-                for (i = startx; i < endx; i++) {
-                    for (j = starty; j < endy; j++) {
-                        if (bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] <= which + 4 && bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] >= which - 4) {
-                            color = Random() % 85 + 170;
-                            where = i * skeleton.skinsize * 3 + j * 3;
-                            if (skeleton.skinText[where + 0] > color / 2) {
-                                skeleton.skinText[where + 0] = color / 2;
-                            }
-                            skeleton.skinText[where + 1] = 0;
-                            skeleton.skinText[where + 2] = 0;
-                        } else if (bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] <= 160 + 4 && bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] >= 160 - 4) {
-                            color = Random() % 85 + 170;
-                            where = i * skeleton.skinsize * 3 + j * 3;
-                            if (skeleton.skinText[where + 0] > color / 2) {
-                                skeleton.skinText[where + 0] = color / 2;
-                            }
-                            skeleton.skinText[where + 1] = 0;
-                            skeleton.skinText[where + 2] = 0;
+            for (i = startx; i < endx; i++) {
+                for (j = starty; j < endy; j++) {
+                    if (PersonType::types[creature].bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] <= which + 4 && PersonType::types[creature].bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] >= which - 4) {
+                        color = Random() % 85 + 170;
+                        where = i * skeleton.skinsize * 3 + j * 3;
+                        if (skeleton.skinText[where + 0] > color / 2) {
+                            skeleton.skinText[where + 0] = color / 2;
                         }
-                    }
-                }
-            }
-            if (creature == wolftype) {
-                for (i = startx; i < endx; i++) {
-                    for (j = starty; j < endy; j++) {
-                        if (wolfbloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] <= which + 4 && wolfbloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] >= which - 4) {
-                            color = Random() % 85 + 170;
-                            where = i * skeleton.skinsize * 3 + j * 3;
-                            if (skeleton.skinText[where + 0] > color / 2) {
-                                skeleton.skinText[where + 0] = color / 2;
-                            }
-                            skeleton.skinText[where + 1] = 0;
-                            skeleton.skinText[where + 2] = 0;
-                        } else if (wolfbloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] <= 160 + 4 && wolfbloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] >= 160 - 4) {
-                            color = Random() % 85 + 170;
-                            where = i * skeleton.skinsize * 3 + j * 3;
-                            if (skeleton.skinText[where + 0] > color / 2) {
-                                skeleton.skinText[where + 0] = color / 2;
-                            }
-                            skeleton.skinText[where + 1] = 0;
-                            skeleton.skinText[where + 2] = 0;
+                        skeleton.skinText[where + 1] = 0;
+                        skeleton.skinText[where + 2] = 0;
+                    } else if (PersonType::types[creature].bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] <= 160 + 4 && PersonType::types[creature].bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] >= 160 - 4) {
+                        color = Random() % 85 + 170;
+                        where = i * skeleton.skinsize * 3 + j * 3;
+                        if (skeleton.skinText[where + 0] > color / 2) {
+                            skeleton.skinText[where + 0] = color / 2;
                         }
+                        skeleton.skinText[where + 1] = 0;
+                        skeleton.skinText[where + 2] = 0;
                     }
                 }
             }
@@ -1346,7 +1176,7 @@ bool Person::DoBloodBigWhere(float howmuch, int which, XYZ where)
     deathbleeding += bleeding;
     bloodloss += bleeding * 3;
 
-    if (!Tutorial::active && aitype != playercontrolled && bloodloss > damagetolerance * 2 / 3 && bloodloss < damagetolerance && creature == rabbittype) {
+    if (!Tutorial::active && !isPlayerControlled() && bloodloss > damagetolerance * 2 / 3 && bloodloss < damagetolerance && creature == rabbittype) {
         if (abs(Random() % 2) == 0) {
             aitype = gethelptype;
             lastseentime = 12;
@@ -1366,7 +1196,7 @@ bool Person::DoBloodBigWhere(float howmuch, int which, XYZ where)
  */
 void Person::Reverse()
 {
-    if (!((victim->aitype == playercontrolled || hostiletime > 1 || staggerdelay <= 0) && victim->animTarget != jumpupanim && victim->animTarget != jumpdownanim && (!Tutorial::active || cananger) && hostile)) {
+    if (!((victim->isPlayerControlled() || hostiletime > 1 || staggerdelay <= 0) && victim->animTarget != jumpupanim && victim->animTarget != jumpdownanim && (!Tutorial::active || cananger) && hostile)) {
         return;
     }
 
@@ -1399,7 +1229,7 @@ void Person::Reverse()
         victim->animTarget = upunchreversalanim;
     }
     if (animTarget == staffhitanim && distsq(&victim->coords, &coords) < 2 && ((victim->id == 0 && victim->crouchkeydown) || Random() % 4 == 0)) {
-        if (victim->weaponactive != -1) {
+        if (victim->hasWeapon()) {
             victim->throwtogglekeydown = 1;
             XYZ tempVelocity = victim->velocity * .2;
             if (tempVelocity.x == 0) {
@@ -1426,7 +1256,7 @@ void Person::Reverse()
         victim->animTarget = staffhitreversalanim;
     }
     if (animTarget == staffspinhitanim && distsq(&victim->coords, &coords) < 2 && ((victim->id == 0 && victim->crouchkeydown) || Random() % 2 == 0)) {
-        if (victim->weaponactive != -1) {
+        if (victim->hasWeapon()) {
             victim->throwtogglekeydown = 1;
             XYZ tempVelocity = victim->velocity * .2;
             if (tempVelocity.x == 0) {
@@ -1452,7 +1282,7 @@ void Person::Reverse()
         victim->animTarget = staffspinhitreversalanim;
     }
     if (animTarget == swordslashanim && distsq(&victim->coords, &coords) < 2 && ((victim->id == 0 && victim->crouchkeydown) || Random() % 4 == 0)) {
-        if (victim->weaponactive != -1) {
+        if (victim->hasWeapon()) {
             victim->throwtogglekeydown = 1;
             XYZ tempVelocity = victim->velocity * .2;
             if (tempVelocity.x == 0) {
@@ -1478,7 +1308,7 @@ void Person::Reverse()
         victim->animTarget = swordslashreversalanim;
     }
     if (animTarget == knifeslashstartanim && distsq(&victim->coords, &coords) < 2 && (victim->id == 0 || Random() % 4 == 0)) {
-        if (victim->weaponactive != -1) {
+        if (victim->hasWeapon()) {
             victim->throwtogglekeydown = 1;
             XYZ tempVelocity = victim->velocity * .2;
             if (tempVelocity.x == 0) {
@@ -1531,7 +1361,7 @@ void Person::Reverse()
         victim->victim = this->shared_from_this();
         victim->targetyaw = targetyaw + 180;
     }
-    if ((animTarget == swordslashanim || animTarget == staffhitanim || animTarget == staffspinhitanim) && victim->weaponactive != -1) {
+    if ((animTarget == swordslashanim || animTarget == staffhitanim || animTarget == staffspinhitanim) && victim->hasWeapon()) {
         animTarget = swordslashparriedanim;
         parriedrecently = .4;
         victim->parriedrecently = 0;
@@ -1542,7 +1372,7 @@ void Person::Reverse()
         victim->targetyaw = targetyaw + 180;
 
         if (abs(Random() % 20) == 0 || weapons[victim->weaponids[victim->weaponactive]].getType() == knife) {
-            if (victim->weaponactive != -1) {
+            if (victim->hasWeapon()) {
                 if (weapons[victim->weaponids[0]].getType() == staff || weapons[weaponids[0]].getType() == staff) {
                     if (weapons[victim->weaponids[0]].getType() == staff) {
                         weapons[victim->weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
@@ -1579,7 +1409,7 @@ void Person::Reverse()
         }
 
         if (abs(Random() % 20) == 0) {
-            if (weaponactive != -1) {
+            if (hasWeapon()) {
                 if (weapons[victim->weaponids[0]].getType() == staff || weapons[weaponids[0]].getType() == staff) {
                     if (weapons[victim->weaponids[0]].getType() == staff) {
                         weapons[victim->weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
@@ -1664,7 +1494,7 @@ void Person::Reverse()
     velocity = 0;
     victim->velocity = 0;
 
-    if (aitype != playercontrolled) {
+    if (!isPlayerControlled()) {
         feint = 0;
         if (escapednum < 2) {
             int chances = ((difficulty == 2) ? 3 : ((difficulty == 1) ? 5 : 10));
@@ -1724,7 +1554,7 @@ void Person::DoDamage(float howmuch)
     if (aitype == passivetype && damage < damagetolerance && ((!Tutorial::active || cananger) && hostile)) {
         aitype = attacktypecutoff;
     }
-    if (!Tutorial::active && aitype != playercontrolled && damage < damagetolerance && damage > damagetolerance * 2 / 3 && creature == rabbittype) {
+    if (!Tutorial::active && !isPlayerControlled() && damage < damagetolerance && damage > damagetolerance * 2 / 3 && creature == rabbittype) {
         if (abs(Random() % 2) == 0) {
             aitype = gethelptype;
             lastseentime = 12;
@@ -1767,7 +1597,7 @@ void Person::DoDamage(float howmuch)
 
     // play sounds
     if (!Tutorial::active || id == 0) {
-        if (speechdelay <= 0 && !dead && aitype != playercontrolled) {
+        if (speechdelay <= 0 && !dead && !isPlayerControlled()) {
             int whichsound = -1;
 
             if (creature == wolftype) {
@@ -2060,7 +1890,7 @@ void Person::RagDoll(bool checkcollision)
 
         // drop weapon
         if (Random() % 2 == 0) {
-            if (weaponactive != -1 && animTarget != rabbitkickanim && num_weapons > 0) {
+            if (hasWeapon() && animTarget != rabbitkickanim && num_weapons > 0) {
                 weapons[weaponids[0]].drop(jointVel(righthand) * scale * -.3, jointVel(righthand) * scale);
                 weapons[weaponids[0]].velocity.x += .01;
                 num_weapons--;
@@ -2177,13 +2007,9 @@ void Person::DoAnimations()
         }
         if (animTarget == jumpupanim || animTarget == jumpdownanim || isFlip()) {
             float gLoc[3];
-            float vel[3];
             gLoc[0] = coords.x;
             gLoc[1] = coords.y;
             gLoc[2] = coords.z;
-            vel[0] = velocity.x;
-            vel[1] = velocity.y;
-            vel[2] = velocity.z;
 
             if (id == 0) {
                 OPENAL_3D_SetAttributes(channels[whooshsound], gLoc);
@@ -2222,11 +2048,11 @@ void Person::DoAnimations()
         }
         if (!crouchkeydown || (isLanding() || isLandhard()) || (wasLanding() || wasLandhard())) {
             crouchtogglekeydown = 0;
-            if (aitype == playercontrolled) {
+            if (isPlayerControlled()) {
                 feint = 0;
             }
         } else {
-            if (!crouchtogglekeydown && Animation::animations[animTarget].attack == reversed && aitype == playercontrolled && (escapednum < 2 || reversaltrain)) {
+            if (!crouchtogglekeydown && Animation::animations[animTarget].attack == reversed && isPlayerControlled() && (escapednum < 2 || reversaltrain)) {
                 feint = 1;
             }
             if (!isFlip()) {
@@ -2265,8 +2091,7 @@ void Person::DoAnimations()
                     if (victim->aitype == gethelptype) {
                         victim->DoDamage(victim->damagetolerance - victim->damage);
                     }
-                    //victim->DoDamage(30);
-                    if (creature == wolftype) {
+                    if (PersonType::types[creature].hasClaws) {
                         DoBloodBig(0, 255);
                         emit_sound_at(clawslicesound, victim->coords);
                         victim->spurt = 1;
@@ -2277,20 +2102,15 @@ void Person::DoAnimations()
                 }
             }
 
-            if (!drawtogglekeydown && drawkeydown && (weaponactive == -1 || num_weapons == 1) && (targetFrame().label || (animTarget != animCurrent && animCurrent == rollanim)) && num_weapons > 0 && creature != wolftype) {
+            if (!drawtogglekeydown && drawkeydown && (!hasWeapon() || num_weapons == 1) && (targetFrame().label || (animTarget != animCurrent && animCurrent == rollanim)) && num_weapons > 0 && creature != wolftype) {
                 if (weapons[weaponids[0]].getType() == knife) {
-                    if (weaponactive == -1) {
+                    if (!hasWeapon()) {
                         weaponactive = 0;
+                        emit_sound_at(knifedrawsound, coords, 128);
                     } else if (weaponactive == 0) {
                         weaponactive = -1;
-                    }
-
-                    if (weaponactive == -1) {
                         emit_sound_at(knifesheathesound, coords);
                     }
-                    if (weaponactive != -1) {
-                        emit_sound_at(knifedrawsound, coords, 128);
-                    }
                 }
                 drawtogglekeydown = 1;
             }
@@ -2331,7 +2151,7 @@ void Person::DoAnimations()
                             whichsound = footstepsound4;
                         }
                     }
-                    if (targetFrame().label == 4 && (weaponactive == -1 || (animTarget != knifeslashstartanim && animTarget != knifethrowanim && animTarget != crouchstabanim && animTarget != swordgroundstabanim && animTarget != knifefollowanim))) {
+                    if (targetFrame().label == 4 && (!hasWeapon() || (animTarget != knifeslashstartanim && animTarget != knifethrowanim && animTarget != crouchstabanim && animTarget != swordgroundstabanim && animTarget != knifefollowanim))) {
                         if (Animation::animations[animTarget].attack != neutral) {
                             unsigned r = abs(Random() % 3);
                             if (r == 0) {
@@ -2381,37 +2201,10 @@ void Person::DoAnimations()
                     if (animTarget != crouchstabanim && animTarget != swordgroundstabanim && animTarget != staffgroundsmashanim) {
                         if ((targetFrame().label && (targetFrame().label < 5 || targetFrame().label == 8))) {
                             int whichsound = -1;
-                            if (targetFrame().label == 4 && aitype != playercontrolled) {
+                            if (targetFrame().label == 4 && !isPlayerControlled()) {
                                 if (Animation::animations[animTarget].attack != neutral) {
                                     unsigned r = abs(Random() % 4);
-                                    if (creature == rabbittype) {
-                                        if (r == 0) {
-                                            whichsound = rabbitattacksound;
-                                        }
-                                        if (r == 1) {
-                                            whichsound = rabbitattack2sound;
-                                        }
-                                        if (r == 2) {
-                                            whichsound = rabbitattack3sound;
-                                        }
-                                        if (r == 3) {
-                                            whichsound = rabbitattack4sound;
-                                        }
-                                    }
-                                    if (creature == wolftype) {
-                                        if (r == 0) {
-                                            whichsound = barksound;
-                                        }
-                                        if (r == 1) {
-                                            whichsound = bark2sound;
-                                        }
-                                        if (r == 2) {
-                                            whichsound = bark3sound;
-                                        }
-                                        if (r == 3) {
-                                            whichsound = barkgrowlsound;
-                                        }
-                                    }
+                                    whichsound = PersonType::types[creature].soundsAttack[r];
                                     speechdelay = .3;
                                 }
                             }
@@ -2435,10 +2228,10 @@ void Person::DoAnimations()
             animCurrent = animTarget;
             frameTarget++;
 
-            if (animTarget == removeknifeanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+            if (animCurrent == removeknifeanim && currentFrame().label == 5) {
                 for (unsigned i = 0; i < weapons.size(); i++) {
                     if (weapons[i].owner == -1) {
-                        if (distsqflat(&coords, &weapons[i].position) < 4 && weaponactive == -1) {
+                        if (distsqflat(&coords, &weapons[i].position) < 4 && !hasWeapon()) {
                             if (distsq(&coords, &weapons[i].position) >= 1) {
                                 if (weapons[i].getType() != staff) {
                                     emit_sound_at(knifedrawsound, coords, 128.);
@@ -2451,7 +2244,7 @@ void Person::DoAnimations()
                 }
             }
 
-            if (animTarget == crouchremoveknifeanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+            if (animCurrent == crouchremoveknifeanim && currentFrame().label == 5) {
                 for (unsigned i = 0; i < weapons.size(); i++) {
                     bool willwork = true;
                     if (weapons[i].owner != -1) {
@@ -2464,7 +2257,7 @@ void Person::DoAnimations()
                         }
                     }
                     if ((weapons[i].owner == -1) || (hasvictim && (weapons[i].owner == int(victim->id)) && victim->skeleton.free)) {
-                        if (willwork && distsqflat(&coords, &weapons[i].position) < 3 && weaponactive == -1) {
+                        if (willwork && distsqflat(&coords, &weapons[i].position) < 3 && !hasWeapon()) {
                             if (distsq(&coords, &weapons[i].position) < 1 || hasvictim) {
                                 bool fleshstuck = false;
                                 if (weapons[i].owner != -1) {
@@ -2537,9 +2330,10 @@ void Person::DoAnimations()
                 }
             }
 
-            if (animCurrent == drawleftanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
-                if (weaponactive == -1) {
+            if (animCurrent == drawleftanim && currentFrame().label == 5) {
+                if (!hasWeapon()) {
                     weaponactive = 0;
+                    emit_sound_at(knifedrawsound, coords, 128.);
                 } else if (weaponactive == 0) {
                     weaponactive = -1;
                     if (num_weapons == 2) {
@@ -2548,13 +2342,8 @@ void Person::DoAnimations()
                         weaponids[0] = weaponids[1];
                         weaponids[1] = buffer;
                     }
-                }
-                if (weaponactive == -1) {
                     emit_sound_at(knifesheathesound, coords, 128.);
                 }
-                if (weaponactive != -1) {
-                    emit_sound_at(knifedrawsound, coords, 128.);
-                }
             }
 
             if ((animCurrent == walljumprightkickanim && animTarget == walljumprightkickanim) || (animCurrent == walljumpleftkickanim && animTarget == walljumpleftkickanim)) {
@@ -2637,31 +2426,28 @@ void Person::DoAnimations()
             }
 
             //Move impacts
-            float damagemult = 1 * power;
-            if (creature == wolftype) {
-                damagemult = 2.5 * power;
-            }
+            float damagemult = PersonType::types[creature].power * power;
             if (hasvictim) {
                 damagemult /= victim->damagetolerance / 200;
             }
             if ((Animation::animations[animTarget].attack == normalattack || animTarget == walljumprightkickanim || animTarget == walljumpleftkickanim) && (!feint) && (victim->skeleton.free != 2 || animTarget == killanim || animTarget == dropkickanim || animTarget == crouchstabanim || animTarget == swordgroundstabanim || animTarget == staffgroundsmashanim)) {
-                if (animTarget == spinkickanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+                if (animCurrent == spinkickanim && currentFrame().label == 5) {
                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && Animation::animations[victim->animTarget].height != lowheight) {
                         escapednum = 0;
                         if (id == 0) {
                             camerashake += .4;
                         }
-                        if (Random() % 2 || creature == wolftype) {
+                        if (Random() % 2 || PersonType::types[creature].hasClaws) {
                             victim->spurt = 1;
                             DoBlood(.2, 250);
-                            if (creature == wolftype) {
+                            if (PersonType::types[creature].hasClaws) {
                                 DoBloodBig(0, 250);
                             }
                         }
                         if (!Tutorial::active) {
                             emit_sound_at(heavyimpactsound, victim->coords, 128.);
                         }
-                        if (creature == wolftype) {
+                        if (PersonType::types[creature].hasClaws) {
                             emit_sound_at(clawslicesound, victim->coords, 128.);
                             victim->spurt = 1;
                             victim->DoBloodBig(2 / victim->armorhead, 175);
@@ -2683,20 +2469,20 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == wolfslapanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+                if (animCurrent == wolfslapanim && currentFrame().label == 5) {
                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && Animation::animations[victim->animTarget].height != lowheight) {
                         escapednum = 0;
                         if (id == 0) {
                             camerashake += .4;
                         }
-                        if (Random() % 2 || creature == wolftype) {
+                        if (Random() % 2 || PersonType::types[creature].hasClaws) {
                             victim->spurt = 1;
-                            if (creature == wolftype) {
+                            if (PersonType::types[creature].hasClaws) {
                                 DoBloodBig(0, 235);
                             }
                         }
                         emit_sound_at(whooshhitsound, victim->coords);
-                        if (creature == wolftype) {
+                        if (PersonType::types[creature].hasClaws) {
                             emit_sound_at(clawslicesound, victim->coords, 128.);
                             victim->spurt = 1;
                             victim->DoBloodBig(2, 175);
@@ -2718,7 +2504,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == walljumprightkickanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+                if (animCurrent == walljumprightkickanim && currentFrame().label == 5) {
                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && Animation::animations[victim->animTarget].height != lowheight) {
                         escapednum = 0;
                         if (id == 0) {
@@ -2729,7 +2515,7 @@ void Person::DoAnimations()
                         if (!Tutorial::active) {
                             emit_sound_at(heavyimpactsound, victim->coords, 160.);
                         }
-                        if (creature == wolftype) {
+                        if (PersonType::types[creature].hasClaws) {
                             emit_sound_at(clawslicesound, victim->coords, 128.);
                             victim->spurt = 1;
                             victim->DoBloodBig(2 / victim->armorhead, 175);
@@ -2755,7 +2541,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == walljumpleftkickanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+                if (animCurrent == walljumpleftkickanim && currentFrame().label == 5) {
                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && Animation::animations[victim->animTarget].height != lowheight) {
                         escapednum = 0;
                         if (id == 0) {
@@ -2766,7 +2552,7 @@ void Person::DoAnimations()
                         if (!Tutorial::active) {
                             emit_sound_at(heavyimpactsound, victim->coords, 160.);
                         }
-                        if (creature == wolftype) {
+                        if (PersonType::types[creature].hasClaws) {
                             emit_sound_at(clawslicesound, victim->coords, 128.);
                             victim->spurt = 1;
                             victim->DoBloodBig(2 / victim->armorhead, 175);
@@ -2792,7 +2578,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == blockhighleftstrikeanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+                if (animCurrent == blockhighleftstrikeanim && currentFrame().label == 5) {
                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && Animation::animations[victim->animTarget].height != lowheight) {
                         escapednum = 0;
                         if (id == 0) {
@@ -2817,7 +2603,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == killanim && Animation::animations[animTarget].frames[frameCurrent].label == 8) {
+                if (animCurrent == killanim && currentFrame().label == 8) {
                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && victim->dead) {
                         escapednum = 0;
                         if (id == 0) {
@@ -2852,7 +2638,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == killanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+                if (animCurrent == killanim && currentFrame().label == 5) {
                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 9 && victim->dead) {
                         escapednum = 0;
                         if (id == 0) {
@@ -2878,7 +2664,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == dropkickanim && Animation::animations[animTarget].frames[frameCurrent].label == 7) {
+                if (animCurrent == dropkickanim && currentFrame().label == 7) {
                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 9 && victim->skeleton.free) {
                         escapednum = 0;
                         if (id == 0) {
@@ -2920,7 +2706,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if ((animTarget == crouchstabanim || animTarget == swordgroundstabanim) && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+                if ((animCurrent == crouchstabanim || animCurrent == swordgroundstabanim) && currentFrame().label == 5) {
 
                     if (hasvictim) {
                         if (!victim->skeleton.free) {
@@ -3017,7 +2803,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if ((animTarget == crouchstabanim || animTarget == swordgroundstabanim) && Animation::animations[animTarget].frames[frameCurrent].label == 6) {
+                if ((animCurrent == crouchstabanim || animCurrent == swordgroundstabanim) && currentFrame().label == 6) {
                     if (!hasvictim) {
                         emit_sound_at(knifedrawsound, coords, 128);
                     }
@@ -3121,7 +2907,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == upunchanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+                if (animCurrent == upunchanim && currentFrame().label == 5) {
                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3) {
                         escapednum = 0;
                         if (id == 0) {
@@ -3159,7 +2945,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == winduppunchanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+                if (animCurrent == winduppunchanim && currentFrame().label == 5) {
                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 2) {
                         escapednum = 0;
                         if (id == 0) {
@@ -3206,7 +2992,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == blockhighleftanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+                if (animCurrent == blockhighleftanim && currentFrame().label == 5) {
                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 4) {
                         if (victim->id == 0) {
                             camerashake += .4;
@@ -3217,13 +3003,13 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == swordslashparryanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+                if (animCurrent == swordslashparryanim && currentFrame().label == 5) {
                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 4) {
                         if (victim->id == 0) {
                             camerashake += .4;
                         }
 
-                        if (weaponactive != -1) {
+                        if (hasWeapon()) {
                             if (weapons[victim->weaponids[0]].getType() == staff || weapons[weaponids[0]].getType() == staff) {
                                 if (weapons[victim->weaponids[0]].getType() == staff) {
                                     weapons[victim->weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
@@ -3242,8 +3028,8 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == knifethrowanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
-                    if (weaponactive != -1) {
+                if (animCurrent == knifethrowanim && currentFrame().label == 5) {
+                    if (hasWeapon()) {
                         escapednum = 0;
                         XYZ aim;
                         aim = victim->coords + DoRotation(victim->jointPos(abdomen), 0, victim->yaw, 0) * victim->scale + victim->velocity * findDistance(&victim->coords, &coords) / 50 - (coords + DoRotation(jointPos(righthand), 0, yaw, 0) * scale);
@@ -3257,9 +3043,9 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == knifeslashstartanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+                if (animCurrent == knifeslashstartanim && currentFrame().label == 5) {
                     if (hasvictim) {
-                        if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 4.5 && /*Animation::animations[victim->animTarget].height!=lowheight&&*/ victim->animTarget != dodgebackanim && victim->animTarget != rollanim) {
+                        if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 4.5 && victim->animTarget != dodgebackanim && victim->animTarget != rollanim) {
                             escapednum = 0;
                             if (!Tutorial::active) {
                                 victim->DoBloodBig(1.5 / victim->armorhigh, 225);
@@ -3270,7 +3056,7 @@ void Person::DoAnimations()
                                 emit_sound_at(knifeslicesound, victim->coords);
                             }
                             //victim->jointVel(abdomen)+=relative*damagemult*200;
-                            if (Animation::animations[victim->animTarget].attack && (victim->aitype != playercontrolled || victim->animTarget == knifeslashstartanim) && (victim->creature == rabbittype || victim->deathbleeding <= 0)) {
+                            if (Animation::animations[victim->animTarget].attack && (!victim->isPlayerControlled() || victim->animTarget == knifeslashstartanim) && (victim->creature == rabbittype || victim->deathbleeding <= 0)) {
                                 if (victim->id != 0 || difficulty == 2) {
                                     victim->frameTarget = 0;
                                     victim->animTarget = staggerbackhardanim;
@@ -3280,7 +3066,7 @@ void Person::DoAnimations()
                             }
                             victim->lowreversaldelay = 0;
                             victim->highreversaldelay = 0;
-                            if (aitype != playercontrolled) {
+                            if (!isPlayerControlled()) {
                                 weaponmissdelay = .6;
                             }
 
@@ -3314,9 +3100,9 @@ void Person::DoAnimations()
                         }
                     }
                 }
-                if (animTarget == swordslashanim && Animation::animations[animTarget].frames[frameCurrent].label == 5 && victim->animTarget != rollanim) {
+                if (animCurrent == swordslashanim && currentFrame().label == 5 && victim->animTarget != rollanim) {
                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 6.5 && victim->animTarget != dodgebackanim) {
-                        if (victim->weaponactive == -1 || normaldotproduct(victim->facing, victim->coords - coords) > 0 || (Random() % 2 == 0)) {
+                        if (!victim->hasWeapon() || normaldotproduct(victim->facing, victim->coords - coords) > 0 || (Random() % 2 == 0)) {
                             award_bonus(id, Slashbonus);
                             escapednum = 0;
                             if (!Tutorial::active) {
@@ -3359,7 +3145,7 @@ void Person::DoAnimations()
                                 Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 2, 1, 1, 1, .3, 1);
                             }
                         } else {
-                            if (victim->weaponactive != -1) {
+                            if (victim->hasWeapon()) {
                                 if (weapons[victim->weaponids[0]].getType() == staff || weapons[weaponids[0]].getType() == staff) {
                                     if (weapons[victim->weaponids[0]].getType() == staff) {
                                         weapons[victim->weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
@@ -3399,7 +3185,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == staffhitanim && Animation::animations[animTarget].frames[frameCurrent].label == 5 && victim->animTarget != rollanim) {
+                if (animCurrent == staffhitanim && currentFrame().label == 5 && victim->animTarget != rollanim) {
                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 6.5 && victim->animTarget != dodgebackanim && victim->animTarget != sweepanim) {
                         if (!Tutorial::active) {
                             weapons[weaponids[0]].damage += .4 + float(abs(Random() % 100) - 50) / 250;
@@ -3407,7 +3193,7 @@ void Person::DoAnimations()
                             if (id == 0) {
                                 camerashake += .4;
                             }
-                            if (Random() % 2 || creature == wolftype) {
+                            if (Random() % 2 || PersonType::types[creature].hasClaws) {
                                 victim->spurt = 1;
                             }
                             emit_sound_at(staffheadsound, victim->coords);
@@ -3434,7 +3220,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == staffspinhitanim && Animation::animations[animTarget].frames[frameCurrent].label == 5 && victim->animTarget != rollanim) {
+                if (animCurrent == staffspinhitanim && currentFrame().label == 5 && victim->animTarget != rollanim) {
                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 6.5 && victim->animTarget != dodgebackanim && victim->animTarget != sweepanim) {
                         if (!Tutorial::active) {
                             weapons[weaponids[0]].damage += .6 + float(abs(Random() % 100) - 50) / 250;
@@ -3442,7 +3228,7 @@ void Person::DoAnimations()
                             if (id == 0) {
                                 camerashake += .4;
                             }
-                            if (Random() % 2 || creature == wolftype) {
+                            if (Random() % 2 || PersonType::types[creature].hasClaws) {
                                 victim->spurt = 1;
                             }
                             emit_sound_at(staffheadsound, victim->coords);
@@ -3467,7 +3253,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == staffgroundsmashanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+                if (animCurrent == staffgroundsmashanim && currentFrame().label == 5) {
                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 6.5) {
                         escapednum = 0;
                         if (!Tutorial::active) {
@@ -3477,7 +3263,7 @@ void Person::DoAnimations()
                             if (id == 0) {
                                 camerashake += .4;
                             }
-                            if (Random() % 2 || creature == wolftype) {
+                            if (Random() % 2 || PersonType::types[creature].hasClaws) {
                                 victim->spurt = 1;
                             }
                             emit_sound_at(staffbodysound, victim->coords);
@@ -3519,7 +3305,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == lowkickanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+                if (animCurrent == lowkickanim && currentFrame().label == 5) {
                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && Animation::animations[victim->animTarget].height != highheight) {
                         escapednum = 0;
                         if (id == 0) {
@@ -3550,7 +3336,7 @@ void Person::DoAnimations()
                             if (victim->howactive == typesleeping) {
                                 victim->DoDamage(damagemult * 150 / victim->protectionhead);
                             }
-                            if (creature == wolftype) {
+                            if (PersonType::types[creature].hasClaws) {
                                 emit_sound_at(clawslicesound, victim->coords, 128.);
                                 victim->spurt = 1;
                                 victim->DoBloodBig(2 / victim->armorhead, 175);
@@ -3572,7 +3358,7 @@ void Person::DoAnimations()
                             }
                             victim->Puff(abdomen);
                             victim->DoDamage(damagemult * 30 / victim->protectionhigh);
-                            if (creature == wolftype) {
+                            if (PersonType::types[creature].hasClaws) {
                                 emit_sound_at(clawslicesound, victim->coords, 128.);
                                 victim->spurt = 1;
                                 victim->DoBloodBig(2 / victim->armorhigh, 170);
@@ -3581,7 +3367,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == sweepanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+                if (animCurrent == sweepanim && currentFrame().label == 5) {
                     if ((victim->animTarget != jumpupanim) &&
                         (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3) &&
                         (victim != this->shared_from_this())) {
@@ -3643,7 +3429,7 @@ void Person::DoAnimations()
                 }
             }
             if (Animation::animations[animTarget].attack == reversal && (!victim->feint || (victim->lastattack == victim->lastattack2 && victim->lastattack2 == victim->lastattack3 && Random() % 2) || animTarget == knifefollowanim)) {
-                if (animTarget == spinkickreversalanim && Animation::animations[animTarget].frames[frameCurrent].label == 7) {
+                if (animCurrent == spinkickreversalanim && currentFrame().label == 7) {
                     escapednum = 0;
                     if (id == 0) {
                         camerashake += .4;
@@ -3655,7 +3441,7 @@ void Person::DoAnimations()
                     if (!Tutorial::active) {
                         emit_sound_at(heavyimpactsound, victim->coords, 128.);
                     }
-                    if (creature == wolftype) {
+                    if (PersonType::types[creature].hasClaws) {
                         emit_sound_at(clawslicesound, victim->coords, 128);
                         victim->spurt = 1;
                         victim->DoBloodBig(2 / victim->armorhigh, 170);
@@ -3676,7 +3462,7 @@ void Person::DoAnimations()
                 }
 
                 if ((animTarget == swordslashreversalanim || animTarget == knifeslashreversalanim || animTarget == staffhitreversalanim || animTarget == staffspinhitreversalanim) && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
-                    if (victim->weaponactive != -1 && victim->num_weapons > 0) {
+                    if (victim->hasWeapon() && victim->num_weapons > 0) {
                         if (weapons[victim->weaponids[victim->weaponactive]].owner == int(victim->id)) {
                             takeWeapon(victim->weaponids[victim->weaponactive]);
                             victim->num_weapons--;
@@ -3688,7 +3474,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == staffhitreversalanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+                if (animCurrent == staffhitreversalanim && currentFrame().label == 5) {
                     escapednum = 0;
                     if (id == 0) {
                         camerashake += .4;
@@ -3711,7 +3497,7 @@ void Person::DoAnimations()
                     victim->DoDamage(damagemult * 70 / victim->protectionhigh);
                 }
 
-                if (animTarget == staffspinhitreversalanim && Animation::animations[animTarget].frames[frameCurrent].label == 7) {
+                if (animCurrent == staffspinhitreversalanim && currentFrame().label == 7) {
                     escapednum = 0;
                     if (id == 0) {
                         camerashake += .4;
@@ -3741,7 +3527,7 @@ void Person::DoAnimations()
                     victim->DoDamage(damagemult * 70 / victim->protectionhigh);
                 }
 
-                if (animTarget == upunchreversalanim && Animation::animations[animTarget].frames[frameCurrent].label == 7) {
+                if (animCurrent == upunchreversalanim && currentFrame().label == 7) {
                     escapednum = 0;
                     victim->RagDoll(1);
                     XYZ relative;
@@ -3767,17 +3553,17 @@ void Person::DoAnimations()
                     award_bonus(id, Reversal);
 
                     bool doslice;
-                    doslice = 0;
-                    if (weaponactive != -1 || creature == wolftype) {
-                        doslice = 1;
-                    }
-                    if (creature == rabbittype && weaponactive != -1) {
-                        if (weapons[weaponids[0]].getType() == staff) {
-                            doslice = 0;
-                        }
+                    if (hasWeapon()) {
+                        doslice = (weapons[weaponids[0]].getType() != staff);
+                    } else {
+                        doslice = PersonType::types[creature].hasClaws;
                     }
                     if (doslice) {
-                        if (weaponactive != -1) {
+                        if (!hasWeapon()) {
+                            emit_sound_at(clawslicesound, victim->coords, 128.);
+                            victim->spurt = 1;
+                            victim->DoBloodBig(2 / victim->armorhigh, 175);
+                        } else {
                             victim->DoBloodBig(2 / victim->armorhigh, 225);
                             emit_sound_at(knifeslicesound, victim->coords);
                             if (bloodtoggle && !weapons[weaponids[weaponactive]].bloody) {
@@ -3785,15 +3571,10 @@ void Person::DoAnimations()
                             }
                             weapons[weaponids[weaponactive]].blooddrip += 3;
                         }
-                        if (weaponactive == -1 && creature == wolftype) {
-                            emit_sound_at(clawslicesound, victim->coords, 128.);
-                            victim->spurt = 1;
-                            victim->DoBloodBig(2 / victim->armorhigh, 175);
-                        }
                     }
                 }
 
-                if (animTarget == swordslashreversalanim && Animation::animations[animTarget].frames[frameCurrent].label == 7) {
+                if (animCurrent == swordslashreversalanim && currentFrame().label == 7) {
                     escapednum = 0;
                     victim->RagDoll(1);
                     XYZ relative;
@@ -3816,7 +3597,7 @@ void Person::DoAnimations()
                     award_bonus(id, swordreversebonus);
                 }
 
-                if (hasvictim && animTarget == knifeslashreversalanim && Animation::animations[animTarget].frames[frameCurrent].label == 7) {
+                if (hasvictim && animCurrent == knifeslashreversalanim && currentFrame().label == 7) {
                     escapednum = 0;
                     if (id == 0) {
                         camerashake += .4;
@@ -3844,7 +3625,7 @@ void Person::DoAnimations()
                     award_bonus(id, Reversal);
                 }
 
-                if (hasvictim && animTarget == sneakattackanim && Animation::animations[animTarget].frames[frameCurrent].label == 7) {
+                if (hasvictim && animCurrent == sneakattackanim && currentFrame().label == 7) {
                     escapednum = 0;
                     victim->RagDoll(0);
                     victim->skeleton.spinny = 0;
@@ -3861,17 +3642,17 @@ void Person::DoAnimations()
                     victim->damage = victim->damagetolerance;
                     victim->permanentdamage = victim->damagetolerance - 1;
                     bool doslice;
-                    doslice = 0;
-                    if (weaponactive != -1 || creature == wolftype) {
-                        doslice = 1;
-                    }
-                    if (creature == rabbittype && weaponactive != -1) {
-                        if (weapons[weaponids[0]].getType() == staff) {
-                            doslice = 0;
-                        }
+                    if (hasWeapon()) {
+                        doslice = (weapons[weaponids[0]].getType() != staff);
+                    } else {
+                        doslice = PersonType::types[creature].hasClaws;
                     }
                     if (doslice) {
-                        if (weaponactive != -1) {
+                        if (!hasWeapon()) {
+                            emit_sound_at(clawslicesound, victim->coords, 128.);
+                            victim->spurt = 1;
+                            victim->DoBloodBig(2, 175);
+                        } else {
                             victim->DoBloodBig(200, 225);
                             emit_sound_at(knifeslicesound, victim->coords);
                             if (bloodtoggle) {
@@ -3879,18 +3660,12 @@ void Person::DoAnimations()
                             }
                             weapons[weaponids[weaponactive]].blooddrip += 5;
                         }
-
-                        if (creature == wolftype && weaponactive == -1) {
-                            emit_sound_at(clawslicesound, victim->coords, 128.);
-                            victim->spurt = 1;
-                            victim->DoBloodBig(2, 175);
-                        }
                     }
                     award_bonus(id, spinecrusher);
                 }
 
-                if (hasvictim && (animTarget == knifefollowanim || animTarget == knifesneakattackanim) && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
-                    if (weaponactive != -1 && victim->bloodloss < victim->damagetolerance) {
+                if (hasvictim && (animCurrent == knifefollowanim || animCurrent == knifesneakattackanim) && currentFrame().label == 5) {
+                    if (hasWeapon() && victim->bloodloss < victim->damagetolerance) {
                         escapednum = 0;
                         if (animTarget == knifefollowanim) {
                             victim->DoBloodBig(200, 210);
@@ -3934,7 +3709,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (hasvictim && (animTarget == knifefollowanim || animTarget == knifesneakattackanim) && Animation::animations[animTarget].frames[frameCurrent].label == 6) {
+                if (hasvictim && (animCurrent == knifefollowanim || animCurrent == knifesneakattackanim) && currentFrame().label == 6) {
                     escapednum = 0;
                     victim->velocity = 0;
                     for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
@@ -3946,7 +3721,7 @@ void Person::DoAnimations()
                             victim->skeleton.joints[i].velocity = 0;
                         }
                     }
-                    if (weaponactive != -1 && Animation::animations[victim->animTarget].attack != reversal) {
+                    if (hasWeapon() && Animation::animations[victim->animTarget].attack != reversal) {
                         emit_sound_at(fleshstabremovesound, victim->coords);
                         if (bloodtoggle) {
                             weapons[weaponids[weaponactive]].bloody = 2;
@@ -3967,8 +3742,8 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (hasvictim && (animTarget == swordsneakattackanim) && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
-                    if (weaponactive != -1 && victim->bloodloss < victim->damagetolerance) {
+                if (hasvictim && (animCurrent == swordsneakattackanim) && currentFrame().label == 5) {
+                    if (hasWeapon() && victim->bloodloss < victim->damagetolerance) {
                         award_bonus(id, backstab);
 
                         escapednum = 0;
@@ -3996,13 +3771,13 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (hasvictim && animTarget == swordsneakattackanim && Animation::animations[animTarget].frames[frameCurrent].label == 6) {
+                if (hasvictim && animCurrent == swordsneakattackanim && currentFrame().label == 6) {
                     escapednum = 0;
                     victim->velocity = 0;
                     for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
                         victim->skeleton.joints[i].velocity = 0;
                     }
-                    if (weaponactive != -1) {
+                    if (hasWeapon()) {
                         emit_sound_at(fleshstabremovesound, victim->coords);
                         if (bloodtoggle) {
                             weapons[weaponids[weaponactive]].bloody = 2;
@@ -4023,7 +3798,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == sweepreversalanim && Animation::animations[animTarget].frames[frameCurrent].label == 7) {
+                if (animCurrent == sweepreversalanim && currentFrame().label == 7) {
                     escapednum = 0;
                     if (id == 0) {
                         camerashake += .4;
@@ -4032,23 +3807,23 @@ void Person::DoAnimations()
                         victim->spurt = 1;
                         DoBlood(.2, 240);
                     }
-                    if (weaponactive == -1) {
+                    if (!hasWeapon()) {
                         if (!Tutorial::active) {
                             emit_sound_at(heavyimpactsound, victim->coords, 128.);
                         }
                     }
                     bool doslice;
-                    doslice = 0;
-                    if (weaponactive != -1 || creature == wolftype) {
-                        doslice = 1;
-                    }
-                    if (creature == rabbittype && weaponactive != -1) {
-                        if (weapons[weaponids[0]].getType() == staff) {
-                            doslice = 0;
-                        }
+                    if (hasWeapon()) {
+                        doslice = (weapons[weaponids[0]].getType() != staff);
+                    } else {
+                        doslice = PersonType::types[creature].hasClaws;
                     }
                     if (doslice) {
-                        if (weaponactive != -1) {
+                        if (!hasWeapon()) {
+                            emit_sound_at(clawslicesound, victim->coords, 128.);
+                            victim->spurt = 1;
+                            victim->DoBloodBig(2 / victim->armorhead, 175);
+                        } else {
                             victim->DoBloodBig(2 / victim->armorhead, 225);
                             emit_sound_at(knifeslicesound, victim->coords);
                             if (bloodtoggle && !weapons[weaponids[weaponactive]].bloody) {
@@ -4056,11 +3831,6 @@ void Person::DoAnimations()
                             }
                             weapons[weaponids[weaponactive]].blooddrip += 3;
                         }
-                        if (weaponactive == -1 && creature == wolftype) {
-                            emit_sound_at(clawslicesound, victim->coords, 128.);
-                            victim->spurt = 1;
-                            victim->DoBloodBig(2 / victim->armorhead, 175);
-                        }
                     }
 
                     award_bonus(id, Reversal);
@@ -4085,7 +3855,7 @@ void Person::DoAnimations()
                     victim->velocity = 0;
                 }
 
-                if (animTarget == sweepreversalanim && ((Animation::animations[animTarget].frames[frameCurrent].label == 9 && victim->damage < victim->damagetolerance) || (Animation::animations[animTarget].frames[frameCurrent].label == 7 && victim->damage > victim->damagetolerance))) {
+                if (animCurrent == sweepreversalanim && ((currentFrame().label == 9 && victim->damage < victim->damagetolerance) || (currentFrame().label == 7 && victim->damage > victim->damagetolerance))) {
                     escapednum = 0;
                     victim->RagDoll(0);
                     XYZ relative;
@@ -4109,7 +3879,7 @@ void Person::DoAnimations()
             }
 
             //Animation end
-            if (frameTarget > int(Animation::animations[animCurrent].frames.size()) - 1) {
+            if (frameTarget >= int(Animation::animations[animCurrent].frames.size())) {
                 frameTarget = 0;
                 if (wasStop()) {
                     animTarget = getIdle();
@@ -4147,8 +3917,9 @@ void Person::DoAnimations()
                     if (animCurrent == crouchdrawrightanim) {
                         animTarget = getCrouch();
                     }
-                    if (weaponactive == -1) {
+                    if (!hasWeapon()) {
                         weaponactive = 0;
+                        emit_sound_at(knifedrawsound, coords, 128.);
                     } else if (weaponactive == 0) {
                         weaponactive = -1;
                         if (num_weapons == 2) {
@@ -4157,14 +3928,8 @@ void Person::DoAnimations()
                             weaponids[0] = weaponids[1];
                             weaponids[1] = buffer;
                         }
-                    }
-
-                    if (weaponactive == -1) {
                         emit_sound_at(knifesheathesound, coords, 128.);
                     }
-                    if (weaponactive != -1) {
-                        emit_sound_at(knifedrawsound, coords, 128.);
-                    }
                 }
                 if (animCurrent == rollanim) {
                     animTarget = getCrouch();
@@ -4518,7 +4283,7 @@ void Person::DoAnimations()
                     animTarget = getIdle();
                     lastfeint = 0;
                 }
-                if (animCurrent == blockhighleftanim && aitype != playercontrolled) {
+                if (animCurrent == blockhighleftanim && !isPlayerControlled()) {
                     animTarget = blockhighleftstrikeanim;
                 }
                 if (animCurrent == knifeslashstartanim || animCurrent == knifethrowanim || animCurrent == swordslashanim || animCurrent == staffhitanim || animCurrent == staffgroundsmashanim || animCurrent == staffspinhitanim) {
@@ -4582,6 +4347,11 @@ void Person::DoAnimations()
                 frameCurrent = frameTarget;
                 target = 1;
             }
+
+            if (frameCurrent >= int(Animation::animations[animCurrent].frames.size())) {
+                frameCurrent = Animation::animations[animCurrent].frames.size() - 1;
+            }
+
             oldrot = rot;
             rot = targetrot * target;
             yaw += rot - oldrot;
@@ -4590,9 +4360,7 @@ void Person::DoAnimations()
                 oldrot = 0;
                 targetrot = 0;
             }
-            if (frameCurrent >= int(Animation::animations[animCurrent].frames.size())) {
-                frameCurrent = Animation::animations[animCurrent].frames.size() - 1;
-            }
+
             if (animCurrent != oldanimCurrent || animTarget != oldanimTarget || ((frameCurrent != oldframeCurrent || frameTarget != oldframeTarget) && !calcrot)) {
                 //Old rotates
                 for (unsigned i = 0; i < skeleton.joints.size(); i++) {
@@ -4737,7 +4505,7 @@ void Person::DoStuff()
         targetoffset = 0;
     }
 
-    if (num_weapons == 1 && weaponactive != -1) {
+    if (num_weapons == 1 && hasWeapon()) {
         weaponstuck = -1;
     }
 
@@ -4784,7 +4552,7 @@ void Person::DoStuff()
             frameTarget = 0;
         }
     }
-    if (weaponactive == -1 && num_weapons > 0) {
+    if (!hasWeapon() && num_weapons > 0) {
         if (weapons[weaponids[0]].getType() == staff) {
             weaponactive = 0;
         }
@@ -4800,13 +4568,9 @@ void Person::DoStuff()
 
         if (animTarget == jumpupanim || animTarget == jumpdownanim || isFlip()) {
             float gLoc[3];
-            float vel[3];
             gLoc[0] = coords.x;
             gLoc[1] = coords.y;
             gLoc[2] = coords.z;
-            vel[0] = velocity.x;
-            vel[1] = velocity.y;
-            vel[2] = velocity.z;
 
             if (id == 0) {
                 OPENAL_3D_SetAttributes(channels[whooshsound], gLoc);
@@ -4900,7 +4664,7 @@ void Person::DoStuff()
             deathbleeding = 0;
         }
         if (bloodloss > damagetolerance && Animation::animations[animTarget].attack == neutral) {
-            if (weaponactive != -1) {
+            if (hasWeapon()) {
                 weapons[weaponids[0]].drop(velocity * scale * -.3, velocity * scale);
                 weapons[weaponids[0]].velocity.x += .01;
                 num_weapons--;
@@ -5331,7 +5095,7 @@ void Person::DoStuff()
 
         RagDoll(0);
 
-        if (weaponactive != -1) {
+        if (hasWeapon()) {
             weapons[weaponids[0]].drop(velocity * scale * -.3, velocity * scale);
             weapons[weaponids[0]].velocity.x += .01;
             num_weapons--;
@@ -5388,7 +5152,7 @@ void Person::DoStuff()
     if (permanentdamage > damagetolerance && dead != 2) {
         DoBlood(1, 255);
 
-        if (weaponactive != -1) {
+        if (hasWeapon()) {
             weapons[weaponids[0]].drop(velocity * scale * -.3, velocity * scale);
             weapons[weaponids[0]].velocity.x += .01;
             num_weapons--;
@@ -5922,25 +5686,12 @@ void Person::DoStuff()
         if (Tutorial::active && id != 0) {
             play = 0;
         }
-        if (play && aitype != playercontrolled) {
+        if (play && !isPlayerControlled()) {
             int whichsound = -1;
             if (speechdelay <= 0) {
                 unsigned int i = abs(Random() % 4);
-                if (creature == rabbittype) {
-                    if (i == 0) {
-                        whichsound = rabbitchitter;
-                    }
-                    if (i == 1) {
-                        whichsound = rabbitchitter2;
-                    }
-                }
-                if (creature == wolftype) {
-                    if (i == 0) {
-                        whichsound = growlsound;
-                    }
-                    if (i == 1) {
-                        whichsound = growl2sound;
-                    }
+                if (i < 2) {
+                    whichsound = PersonType::types[creature].soundsTalk[i];
                 }
             }
             speechdelay = .3;
@@ -6121,7 +5872,7 @@ void Person::DoStuff()
             }
         }
 
-        if (weaponactive != -1) {
+        if (hasWeapon()) {
             if (weapons[weaponids[weaponactive]].getType() != staff) {
                 righthandmorphstart = 1;
                 righthandmorphend = 1;
@@ -6245,19 +5996,10 @@ void Person::DoStuff()
         } else if (isRun()) {
             velocity += facing * multiplier * speed * 700 * scale;
             velspeed = findLength(&velocity);
-            if (creature == rabbittype) {
-                if (velspeed > speed * 55 * scale) {
-                    velocity /= velspeed;
-                    velspeed = speed * 55 * scale;
-                    velocity *= velspeed;
-                }
-            }
-            if (creature == wolftype) {
-                if (velspeed > speed * 75 * scale) {
-                    velocity /= velspeed;
-                    velspeed = speed * 75 * scale;
-                    velocity *= velspeed;
-                }
+            if (velspeed > speed * PersonType::types[creature].maxRunSpeed * scale) {
+                velocity /= velspeed;
+                velspeed = speed * PersonType::types[creature].maxRunSpeed * scale;
+                velocity *= velspeed;
             }
             velocity.y += gravity * multiplier * 20;
             ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
@@ -6729,24 +6471,24 @@ int Person::DrawSkeleton()
                             glMatrixMode(GL_MODELVIEW);
                             glPushMatrix();
                             if (p1 == abdomen || p2 == abdomen) {
-                                glTranslatef((v0.x * (1 - morphness) + v1.x * morphness) * proportionbody.x,
-                                             (v0.y * (1 - morphness) + v1.y * morphness) * proportionbody.y,
-                                             (v0.z * (1 - morphness) + v1.z * morphness) * proportionbody.z);
+                                glTranslatef((v0.x * (1 - morphness) + v1.x * morphness) * getProportionXYZ(1).x,
+                                             (v0.y * (1 - morphness) + v1.y * morphness) * getProportionXYZ(1).y,
+                                             (v0.z * (1 - morphness) + v1.z * morphness) * getProportionXYZ(1).z);
                             }
                             if (p1 == lefthand || p1 == righthand || p1 == leftwrist || p1 == rightwrist || p1 == leftelbow || p1 == rightelbow || p2 == leftelbow || p2 == rightelbow) {
-                                glTranslatef((v0.x * (1 - morphness) + v1.x * morphness) * proportionarms.x,
-                                             (v0.y * (1 - morphness) + v1.y * morphness) * proportionarms.y,
-                                             (v0.z * (1 - morphness) + v1.z * morphness) * proportionarms.z);
+                                glTranslatef((v0.x * (1 - morphness) + v1.x * morphness) * getProportionXYZ(2).x,
+                                             (v0.y * (1 - morphness) + v1.y * morphness) * getProportionXYZ(2).y,
+                                             (v0.z * (1 - morphness) + v1.z * morphness) * getProportionXYZ(2).z);
                             }
                             if (p1 == leftfoot || p1 == rightfoot || p1 == leftankle || p1 == rightankle || p1 == leftknee || p1 == rightknee || p2 == leftknee || p2 == rightknee) {
-                                glTranslatef((v0.x * (1 - morphness) + v1.x * morphness) * proportionlegs.x,
-                                             (v0.y * (1 - morphness) + v1.y * morphness) * proportionlegs.y,
-                                             (v0.z * (1 - morphness) + v1.z * morphness) * proportionlegs.z);
+                                glTranslatef((v0.x * (1 - morphness) + v1.x * morphness) * getProportionXYZ(3).x,
+                                             (v0.y * (1 - morphness) + v1.y * morphness) * getProportionXYZ(3).y,
+                                             (v0.z * (1 - morphness) + v1.z * morphness) * getProportionXYZ(3).z);
                             }
                             if (p1 == head || p2 == head) {
-                                glTranslatef((v0.x * (1 - morphness) + v1.x * morphness) * proportionhead.x,
-                                             (v0.y * (1 - morphness) + v1.y * morphness) * proportionhead.y,
-                                             (v0.z * (1 - morphness) + v1.z * morphness) * proportionhead.z);
+                                glTranslatef((v0.x * (1 - morphness) + v1.x * morphness) * getProportionXYZ(0).x,
+                                             (v0.y * (1 - morphness) + v1.y * morphness) * getProportionXYZ(0).y,
+                                             (v0.z * (1 - morphness) + v1.z * morphness) * getProportionXYZ(0).z);
                             }
                             glGetFloatv(GL_MODELVIEW_MATRIX, M);
                             skeleton.drawmodel.vertex[skeleton.muscles[i].vertices[j]].x = M[12] * scale;
@@ -6761,24 +6503,24 @@ int Person::DrawSkeleton()
                             glMatrixMode(GL_MODELVIEW);
                             glPushMatrix();
                             if (p1 == abdomen || p2 == abdomen) {
-                                glTranslatef(v0.x * proportionbody.x,
-                                             v0.y * proportionbody.y,
-                                             v0.z * proportionbody.z);
+                                glTranslatef(v0.x * getProportionXYZ(1).x,
+                                             v0.y * getProportionXYZ(1).y,
+                                             v0.z * getProportionXYZ(1).z);
                             }
                             if (p1 == lefthand || p1 == righthand || p1 == leftwrist || p1 == rightwrist || p1 == leftelbow || p1 == rightelbow || p2 == leftelbow || p2 == rightelbow) {
-                                glTranslatef(v0.x * proportionarms.x,
-                                             v0.y * proportionarms.y,
-                                             v0.z * proportionarms.z);
+                                glTranslatef(v0.x * getProportionXYZ(2).x,
+                                             v0.y * getProportionXYZ(2).y,
+                                             v0.z * getProportionXYZ(2).z);
                             }
                             if (p1 == leftfoot || p1 == rightfoot || p1 == leftankle || p1 == rightankle || p1 == leftknee || p1 == rightknee || p2 == leftknee || p2 == rightknee) {
-                                glTranslatef(v0.x * proportionlegs.x,
-                                             v0.y * proportionlegs.y,
-                                             v0.z * proportionlegs.z);
+                                glTranslatef(v0.x * getProportionXYZ(3).x,
+                                             v0.y * getProportionXYZ(3).y,
+                                             v0.z * getProportionXYZ(3).z);
                             }
                             if (p1 == head || p2 == head) {
-                                glTranslatef(v0.x * proportionhead.x,
-                                             v0.y * proportionhead.y,
-                                             v0.z * proportionhead.z);
+                                glTranslatef(v0.x * getProportionXYZ(0).x,
+                                             v0.y * getProportionXYZ(0).y,
+                                             v0.z * getProportionXYZ(0).z);
                             }
 
                             glGetFloatv(GL_MODELVIEW_MATRIX, M);
@@ -6817,24 +6559,24 @@ int Person::DrawSkeleton()
                         glMatrixMode(GL_MODELVIEW);
                         glPushMatrix();
                         if (p1 == abdomen || p2 == abdomen) {
-                            glTranslatef(v0.x * proportionbody.x,
-                                         v0.y * proportionbody.y,
-                                         v0.z * proportionbody.z);
+                            glTranslatef(v0.x * getProportionXYZ(1).x,
+                                         v0.y * getProportionXYZ(1).y,
+                                         v0.z * getProportionXYZ(1).z);
                         }
                         if (p1 == lefthand || p1 == righthand || p1 == leftwrist || p1 == rightwrist || p1 == leftelbow || p1 == rightelbow || p2 == leftelbow || p2 == rightelbow) {
-                            glTranslatef(v0.x * proportionarms.x,
-                                         v0.y * proportionarms.y,
-                                         v0.z * proportionarms.z);
+                            glTranslatef(v0.x * getProportionXYZ(2).x,
+                                         v0.y * getProportionXYZ(2).y,
+                                         v0.z * getProportionXYZ(2).z);
                         }
                         if (p1 == leftfoot || p1 == rightfoot || p1 == leftankle || p1 == rightankle || p1 == leftknee || p1 == rightknee || p2 == leftknee || p2 == rightknee) {
-                            glTranslatef(v0.x * proportionlegs.x,
-                                         v0.y * proportionlegs.y,
-                                         v0.z * proportionlegs.z);
+                            glTranslatef(v0.x * getProportionXYZ(3).x,
+                                         v0.y * getProportionXYZ(3).y,
+                                         v0.z * getProportionXYZ(3).z);
                         }
                         if (p1 == head || p2 == head) {
-                            glTranslatef(v0.x * proportionhead.x,
-                                         v0.y * proportionhead.y,
-                                         v0.z * proportionhead.z);
+                            glTranslatef(v0.x * getProportionXYZ(0).x,
+                                         v0.y * getProportionXYZ(0).y,
+                                         v0.z * getProportionXYZ(0).z);
                         }
                         glGetFloatv(GL_MODELVIEW_MATRIX, M);
                         skeleton.drawmodelclothes.vertex[skeleton.muscles[i].verticesclothes[j]].x = M[12] * scale;
@@ -7583,7 +7325,7 @@ bool Person::addClothes(const int& clothesId)
 
 void Person::doAI()
 {
-    if (aitype != playercontrolled && !Dialog::inDialog()) {
+    if (!isPlayerControlled() && !isPlayerFriend() && !Dialog::inDialog()) {
         jumpclimb = 0;
         //disable movement in editor
         if (Game::editorenabled) {
@@ -7601,7 +7343,7 @@ void Person::doAI()
         if (aitype == pathfindtype) {
             if (finalpathfindpoint == -1) {
                 float closestdistance;
-                float tempdist;
+                float tempdist = 0.0f;
                 int closest;
                 XYZ colpoint;
                 closest = -1;
@@ -7631,7 +7373,7 @@ void Person::doAI()
             }
             if (targetpathfindpoint == -1) {
                 float closestdistance;
-                float tempdist;
+                float tempdist = 0.0f;
                 int closest;
                 XYZ colpoint;
                 closest = -1;
@@ -8256,7 +7998,7 @@ void Person::doAI()
                 lastseentime = 12;
 
                 if (!Person::players[0]->dead && ((!Tutorial::active || cananger) && hostile)) {
-                    if (ally < 0 || weaponactive != -1 || lastchecktime <= 0) {
+                    if (ally < 0 || hasWeapon() || lastchecktime <= 0) {
                         aitype = attacktypecutoff;
                         lastseentime = 1;
                     }
@@ -8328,7 +8070,7 @@ void Person::doAI()
                     if (isIdle()) {
                         crouchkeydown = 1;
                     }
-                    if (Person::players[0]->animTarget != rabbitkickanim && Person::players[0]->weaponactive != -1) {
+                    if (Person::players[0]->animTarget != rabbitkickanim && Person::players[0]->hasWeapon()) {
                         if (weapons[Person::players[0]->weaponids[0]].getType() == knife) {
                             if (isIdle() || isCrouch() || isRun() || isFlip()) {
                                 if (abs(Random() % 2) == 0) {
@@ -8442,7 +8184,7 @@ void Person::doAI()
                 animTarget != backhandspringanim &&
                 animTarget != dodgebackanim) {
                 //draw weapon
-                if (weaponactive == -1 && num_weapons > 0) {
+                if (!hasWeapon() && num_weapons > 0) {
                     drawkeydown = Random() % 2;
                 } else {
                     drawkeydown = 0;
@@ -8451,20 +8193,21 @@ void Person::doAI()
                 //chase player
                 XYZ rotatetarget = Person::players[0]->coords + Person::players[0]->velocity;
                 XYZ targetpoint = Person::players[0]->coords;
-                if (findLength(&velocity) != 0 &&
+                float vellength = findLength(&velocity);
+                if (vellength != 0 &&
                     distsq(&Person::players[0]->coords, &coords) < distsq(&rotatetarget, &coords)) {
                     targetpoint += Person::players[0]->velocity *
-                                   findDistance(&Person::players[0]->coords, &coords) / findLength(&velocity);
+                                   findDistance(&Person::players[0]->coords, &coords) / vellength;
                 }
                 targetyaw = roughDirectionTo(coords, targetpoint);
                 lookyaw = targetyaw;
                 aiupdatedelay = .2 + fabs((float)(Random() % 100) / 1000);
 
-                if (distsq(&coords, &Person::players[0]->coords) > 5 && (Person::players[0]->weaponactive == -1 || weaponactive != -1)) {
+                if (distsq(&coords, &Person::players[0]->coords) > 5 && (!Person::players[0]->hasWeapon() || hasWeapon())) {
                     forwardkeydown = 1;
                 } else if ((distsq(&coords, &Person::players[0]->coords) > 16 ||
                             distsq(&coords, &Person::players[0]->coords) < 9) &&
-                           Person::players[0]->weaponactive != -1) {
+                           Person::players[0]->hasWeapon()) {
                     forwardkeydown = 1;
                 } else if (Random() % 6 == 0 || (creature == wolftype && Random() % 3 == 0)) {
                     forwardkeydown = 1;
@@ -8498,7 +8241,7 @@ void Person::doAI()
                     targetyaw += 90 * (whichdirection * 2 - 1);
                 }
                 //attack!!!
-                if (Random() % 2 == 0 || weaponactive != -1 || creature == wolftype) {
+                if (Random() % 2 == 0 || hasWeapon() || creature == wolftype) {
                     attackkeydown = 1;
                 } else {
                     attackkeydown = 0;
@@ -8508,7 +8251,7 @@ void Person::doAI()
                 }
 
                 //TODO: wat
-                if (aitype != playercontrolled &&
+                if (!isPlayerControlled() &&
                     (isIdle() ||
                      isCrouch() ||
                      isRun())) {
@@ -8524,9 +8267,9 @@ void Person::doAI()
                                  Person::players[j]->lastattack3 == Person::players[j]->animTarget &&
                                  (Random() % 2 == 0 || difficulty == 2) ||
                              (isIdle() || isRun()) &&
-                                 Person::players[j]->weaponactive != -1 ||
+                                 Person::players[j]->hasWeapon() ||
                              Person::players[j]->animTarget == swordslashanim &&
-                                 weaponactive != -1 ||
+                                 hasWeapon() ||
                              Person::players[j]->animTarget == staffhitanim ||
                              Person::players[j]->animTarget == staffspinhitanim)) {
                             if (distsq(&Person::players[j]->coords, &Person::players[j]->victim->coords) < 4 &&
@@ -8541,7 +8284,7 @@ void Person::doAI()
                                  Person::players[j]->animTarget == knifeslashstartanim ||
                                  Person::players[j]->animTarget == swordslashanim &&
                                      (distsq(&Person::players[j]->coords, &coords) < 2 ||
-                                      weaponactive != -1))) {
+                                      hasWeapon()))) {
                                 if (target >= 0) {
                                     target = -1;
                                 } else {
@@ -8661,3 +8404,10 @@ void Person::doAI()
         }
     }
 }
+
+bool Person::catchKnife()
+{
+    return
+        ((PersonType::types[creature].knifeCatchingType == 0) && (Random() % 2 != 0) && (!hasWeapon()) && (aitype == attacktypecutoff)) ||
+        ((PersonType::types[creature].knifeCatchingType == 1) && (Random() % 3 != 0) && (!hasWeapon()) && (isIdle() || isRun() || animTarget == walkanim));
+}