]> git.jsancho.org Git - lugaru.git/blobdiff - Source/GameTick.cpp
New non-atacking player
[lugaru.git] / Source / GameTick.cpp
index 85cf0e9c3102a3d18f89c0b95756b5f74719582e..ed1aed93a4c4ed8ff8a0652efbf8234c5120a20d 100644 (file)
@@ -148,27 +148,6 @@ float musicvolume[4] = {};
 float oldmusicvolume[4] = {};
 int musicselected = 0;
 
-const char* rabbitskin[] = {
-    "Textures/Fur3.jpg",
-    "Textures/Fur.jpg",
-    "Textures/Fur2.jpg",
-    "Textures/Lynx.jpg",
-    "Textures/Otter.jpg",
-    "Textures/Opal.jpg",
-    "Textures/Sable.jpg",
-    "Textures/Chocolate.jpg",
-    "Textures/BW2.jpg",
-    "Textures/WB2.jpg"
-};
-
-const char* wolfskin[] = {
-    "Textures/Wolf.jpg",
-    "Textures/DarkWolf.jpg",
-    "Textures/SnowWolf.jpg"
-};
-
-const char** creatureskin[] = { rabbitskin, wolfskin };
-
 #define STATIC_ASSERT(x) extern int s_a_dummy[2 * (!!(x)) - 1];
 STATIC_ASSERT(rabbittype == 0 && wolftype == 1)
 
@@ -851,11 +830,7 @@ bool Game::LoadLevel(const std::string& name, bool tutorial)
             Person::players[i]->updatedelay = 0;
             Person::players[i]->normalsupdatedelay = 0;
 
-            Person::players[i]->proportionhead = 1.2;
-            Person::players[i]->proportionbody = 1.05;
-            Person::players[i]->proportionarms = 1.00;
-            Person::players[i]->proportionlegs = 1.1;
-            Person::players[i]->proportionlegs.y = 1.05;
+            Person::players[i]->setProportions(1, 1, 1, 1);
             Person::players[i]->headless = 0;
             Person::players[i]->currentoffset = 0;
             Person::players[i]->targetoffset = 0;
@@ -865,20 +840,11 @@ bool Game::LoadLevel(const std::string& name, bool tutorial)
             } else {
                 Person::players[i]->damagetolerance = 200;
             }
-        }
 
-        Game::LoadingScreen();
+            Game::LoadingScreen();
 
-        if (cellophane) {
-            Person::players[i]->proportionhead.z = 0;
-            Person::players[i]->proportionbody.z = 0;
-            Person::players[i]->proportionarms.z = 0;
-            Person::players[i]->proportionlegs.z = 0;
-        }
+            Person::players[i]->tempanimation = Animation("Tempanim", lowheight, neutral);
 
-        Person::players[i]->tempanimation = Animation("Tempanim", lowheight, neutral);
-
-        if (i == 0) {
             Person::players[i]->headmorphness = 0;
             Person::players[i]->targetheadmorphness = 1;
             Person::players[i]->headmorphstart = 0;
@@ -1009,7 +975,6 @@ void Game::ProcessInput()
         }
     }
 
-
     /* Tutorial mode hotkeys */
     if (Tutorial::active) {
         // Skip current tutorial stage
@@ -1021,24 +986,18 @@ void Game::ProcessInput()
         }
     }
 
-
     /* Screenshot */
     if (Input::isKeyPressed(SDL_SCANCODE_F1)) {
         Screenshot();
     }
 
-
     /* Stereo video mode hotkeys */
     if (Input::isKeyPressed(SDL_SCANCODE_F6)) {
         if (Input::isKeyDown(SDL_SCANCODE_LSHIFT)) {
             stereoreverse = true;
-        } else {
-            stereoreverse = false;
-        }
-
-        if (stereoreverse) {
             printf("Stereo reversed\n");
         } else {
+            stereoreverse = false;
             printf("Stereo unreversed\n");
         }
     }
@@ -1049,7 +1008,7 @@ void Game::ProcessInput()
         } else {
             stereoseparation -= 0.010;
         }
-        printf("Stereo decreased increased to %f\n", stereoseparation);
+        printf("Stereo separation decreased to %f\n", stereoseparation);
     }
 
     if (Input::isKeyDown(SDL_SCANCODE_F8)) {
@@ -1061,23 +1020,9 @@ void Game::ProcessInput()
         printf("Stereo separation increased to %f\n", stereoseparation);
     }
 
-
     /* Devtools */
     if (devtools && !mainmenu) {
-        ProcessDevInput();
-    }
-}
-
-void Game::ProcessDevInput()
-{
-    if (!devtools || mainmenu) {
-        return;
-    }
-
-    float headprop, bodyprop, armprop, legprop;
-
-    if (!mainmenu) {
-        // Console
+        /* Console */
         if (Input::isKeyPressed(consolekey)) {
             console = !console;
             if (console) {
@@ -1088,23 +1033,45 @@ void Game::ProcessDevInput()
             }
         }
 
-        // Freeze
-        if (Input::isKeyDown(SDL_SCANCODE_LALT) && Input::isKeyPressed(SDL_SCANCODE_V)) {
-            freeze = !freeze;
-            if (freeze) {
-                OPENAL_SetFrequency(OPENAL_ALL);
-            }
+        /* Other devtools, disabled when the console is shown */
+        if (!console) {
+            ProcessDevInput();
         }
     }
+}
+
+void Game::ProcessDevInput()
+{
+    if (!devtools || mainmenu || console) {
+        return;
+    }
 
     if (Input::isKeyDown(SDL_SCANCODE_LALT)) {
-        /* Invicible */
+        /* Enable editor */
+        if (Input::isKeyPressed(SDL_SCANCODE_M) && !Input::isKeyDown(SDL_SCANCODE_LSHIFT)) {
+            editorenabled = !editorenabled;
+            if (editorenabled) {
+                Person::players[0]->damagetolerance = 100000;
+                Person::players[0]->damage = 0;
+                Person::players[0]->permanentdamage = 0;
+                Person::players[0]->superpermanentdamage = 0;
+                Person::players[0]->burnt = 0;
+                Person::players[0]->bloodloss = 0;
+                Person::players[0]->deathbleeding = 0;
+            } else {
+                Person::players[0]->damagetolerance = 200;
+            }
+        }
+
+        /* Nullify damage and give 200000 health */
         if (Input::isKeyPressed(SDL_SCANCODE_H)) {
             Person::players[0]->damagetolerance = 200000;
             Person::players[0]->damage = 0;
-            Person::players[0]->burnt = 0;
             Person::players[0]->permanentdamage = 0;
             Person::players[0]->superpermanentdamage = 0;
+            Person::players[0]->burnt = 0;
+            Person::players[0]->bloodloss = 0;
+            Person::players[0]->deathbleeding = 0;
         }
 
         /* Change environment */
@@ -1121,7 +1088,15 @@ void Game::ProcessDevInput()
             cameramode = !cameramode;
         }
 
-        /* Toggle Slow motion */
+        /* Freeze */
+        if (Input::isKeyPressed(SDL_SCANCODE_V)) {
+            freeze = !freeze;
+            if (freeze) {
+                OPENAL_SetFrequency(OPENAL_ALL);
+            }
+        }
+
+        /* Toggle slow motion */
         if (Input::isKeyPressed(SDL_SCANCODE_B)) {
             slomo = 1 - slomo;
             slomodelay = 1000;
@@ -1130,11 +1105,11 @@ void Game::ProcessDevInput()
         /* Ragdoll */
         if (Input::isKeyPressed(SDL_SCANCODE_N)) {
             Person::players[0]->RagDoll(0);
-
             emit_sound_at(whooshsound, Person::players[0]->coords, 128.);
         }
 
-        /* Grow tree leaves?? */
+        /* Shrink tree leaves?? */
+        // FIXME: Can't see what this does in game.
         if (Input::isKeyPressed(SDL_SCANCODE_Y)) {
             for (auto& an_object : Object::objects) {
                 if (an_object->type == treeleavestype) {
@@ -1152,24 +1127,28 @@ void Game::ProcessDevInput()
 
             if (closest >= 0) {
                 if (Person::players[closest]->num_weapons > 0) {
-                    if (weapons[Person::players[closest]->weaponids[0]].getType() == sword) {
-                        weapons[Person::players[closest]->weaponids[0]].setType(staff);
-                    } else if (weapons[Person::players[closest]->weaponids[0]].getType() == staff) {
-                        weapons[Person::players[closest]->weaponids[0]].setType(knife);
-                    } else {
-                        weapons[Person::players[closest]->weaponids[0]].setType(sword);
+                    int weapontype = 0;
+                    switch (weapons[Person::players[closest]->weaponids[0]].getType()) {
+                        case knife:
+                            weapontype = sword;
+                            break;
+                        case sword:
+                            weapontype = staff;
+                            break;
+                        case staff:
+                            weapontype = knife;
+                            break;
                     }
+                    weapons[Person::players[closest]->weaponids[0]].setType(weapontype);
                 } else {
                     Person::players[closest]->weaponids[0] = weapons.size();
-
                     weapons.push_back(Weapon(knife, closest));
-
                     Person::players[closest]->num_weapons = 1;
                 }
             }
         }
 
-        /* Change yaw? */
+        /* Change yaw (rotate around Z axis) */
         if (Input::isKeyDown(SDL_SCANCODE_U)) {
             int closest = 0;
             if (!Input::isKeyDown(SDL_SCANCODE_LCTRL)) {
@@ -1184,18 +1163,24 @@ void Game::ProcessDevInput()
 
         /* Toggle fire */
         if (Input::isKeyPressed(SDL_SCANCODE_F)) {
-            Person::players[0]->onfire = 1 - Person::players[0]->onfire;
-            if (Person::players[0]->onfire) {
-                Person::players[0]->CatchFire();
+            int closest = 0;
+            if (!Input::isKeyDown(SDL_SCANCODE_LCTRL)) {
+                closest = findClosestPlayer();
             }
-            if (!Person::players[0]->onfire) {
-                emit_sound_at(fireendsound, Person::players[0]->coords);
-                pause_sound(stream_firesound);
+
+            if (closest >= 0) {
+                Person::players[closest]->onfire = !Person::players[closest]->onfire;
+                if (Person::players[closest]->onfire) {
+                    Person::players[closest]->CatchFire();
+                } else {
+                    emit_sound_at(fireendsound, Person::players[closest]->coords);
+                    pause_sound(stream_firesound);
+                }
             }
         }
 
         /* Change skin */
-        if (Input::isKeyPressed(SDL_SCANCODE_O) && !Input::isKeyDown(SDL_SCANCODE_LSHIFT)) {
+        if (Input::isKeyPressed(SDL_SCANCODE_T) && !Input::isKeyDown(SDL_SCANCODE_LSHIFT)) {
             int closest = 0;
             if (!Input::isKeyDown(SDL_SCANCODE_LCTRL)) {
                 closest = findClosestPlayer();
@@ -1210,127 +1195,67 @@ void Game::ProcessDevInput()
                     Person::players[closest]->whichskin = 0;
                 }
 
-                Person::players[closest]->skeleton.drawmodel.textureptr.load(creatureskin[Person::players[closest]->creature][Person::players[closest]->whichskin], 1,
-                                                                             &Person::players[closest]->skeleton.skinText[0], &Person::players[closest]->skeleton.skinsize);
+                Person::players[closest]->skeleton.drawmodel.textureptr.load(
+                    PersonType::types[Person::players[closest]->creature].skins[Person::players[closest]->whichskin], 1,
+                    &Person::players[closest]->skeleton.skinText[0], &Person::players[closest]->skeleton.skinsize);
             }
 
             Person::players[closest]->addClothes();
         }
 
         /* Change creature type */
-        if (Input::isKeyPressed(SDL_SCANCODE_O) && Input::isKeyDown(SDL_SCANCODE_LSHIFT)) {
+        if (Input::isKeyPressed(SDL_SCANCODE_T) && Input::isKeyDown(SDL_SCANCODE_LSHIFT)) {
             int closest = 0;
             if (!Input::isKeyDown(SDL_SCANCODE_LCTRL)) {
                 closest = findClosestPlayer();
             }
 
             if (closest >= 0) {
-                if (Person::players[closest]->creature == wolftype) {
-                    headprop = Person::players[closest]->proportionhead.x / 1.1;
-                    bodyprop = Person::players[closest]->proportionbody.x / 1.1;
-                    armprop = Person::players[closest]->proportionarms.x / 1.1;
-                    legprop = Person::players[closest]->proportionlegs.x / 1.1;
-                } else {
-                    // rabbittype
-                    headprop = Person::players[closest]->proportionhead.x / 1.2;
-                    bodyprop = Person::players[closest]->proportionbody.x / 1.05;
-                    armprop = Person::players[closest]->proportionarms.x / 1.00;
-                    legprop = Person::players[closest]->proportionlegs.x / 1.1;
-                }
-
-                if (Person::players[closest]->creature == rabbittype) {
-                    Person::players[closest]->creature = wolftype;
-                    Person::players[closest]->whichskin = 0;
-                    Person::players[closest]->skeletonLoad();
-
-                    Person::players[closest]->proportionhead = 1.1;
-                    Person::players[closest]->proportionbody = 1.1;
-                    Person::players[closest]->proportionarms = 1.1;
-                    Person::players[closest]->proportionlegs = 1.1;
-                    Person::players[closest]->proportionlegs.y = 1.1;
-                    Person::players[closest]->scale = .23 * 5 * Person::players[0]->scale;
-
-                    Person::players[closest]->damagetolerance = 300;
-                } else {
-                    Person::players[closest]->creature = rabbittype;
-                    Person::players[closest]->whichskin = 0;
-                    Person::players[closest]->skeletonLoad(true);
-
-                    Person::players[closest]->proportionhead = 1.2;
-                    Person::players[closest]->proportionbody = 1.05;
-                    Person::players[closest]->proportionarms = 1.00;
-                    Person::players[closest]->proportionlegs = 1.1;
-                    Person::players[closest]->proportionlegs.y = 1.05;
-                    Person::players[closest]->scale = .2 * 5 * Person::players[0]->scale;
-
-                    Person::players[closest]->damagetolerance = 200;
-                }
-
-                if (Person::players[closest]->creature == wolftype) {
-                    Person::players[closest]->proportionhead = 1.1 * headprop;
-                    Person::players[closest]->proportionbody = 1.1 * bodyprop;
-                    Person::players[closest]->proportionarms = 1.1 * armprop;
-                    Person::players[closest]->proportionlegs = 1.1 * legprop;
-                }
-
-                if (Person::players[closest]->creature == rabbittype) {
-                    Person::players[closest]->proportionhead = 1.2 * headprop;
-                    Person::players[closest]->proportionbody = 1.05 * bodyprop;
-                    Person::players[closest]->proportionarms = 1.00 * armprop;
-                    Person::players[closest]->proportionlegs = 1.1 * legprop;
-                    Person::players[closest]->proportionlegs.y = 1.05 * legprop;
-                }
+                person_type nextType = static_cast<person_type>((Person::players[closest]->creature + 1) % PersonType::types.size());
+                Person::players[closest]->changeCreatureType(nextType);
             }
         }
 
-        /* Decapitate */
-        if (((Input::isKeyPressed(SDL_SCANCODE_I) && !Input::isKeyDown(SDL_SCANCODE_LSHIFT)))) {
-            int closest = -1;
-            float closestdist = std::numeric_limits<float>::max();
+        /* Explose nearby player's head */
+        if (Input::isKeyPressed(SDL_SCANCODE_I) && !Input::isKeyDown(SDL_SCANCODE_LSHIFT)) {
+            int closest = findClosestPlayer();
+            if (closest > 0 && distsq(&Person::players[closest]->coords, &Person::players[0]->coords) < 144) {
+                XYZ flatfacing2, flatvelocity2, flatvelocity2_orig;
+                XYZ headspurtdirection;
+                Joint& headjoint = Person::players[closest]->joint(head);
 
-            for (unsigned i = 1; i < Person::players.size(); i++) {
-                float distance = distsq(&Person::players[i]->coords, &Person::players[0]->coords);
-                if (!Person::players[i]->headless) {
-                    if (distance < closestdist) {
-                        closestdist = distance;
-                        closest = i;
-                    }
+                if (!Person::players[closest]->skeleton.free) {
+                    flatvelocity2_orig = Person::players[closest]->velocity;
+                    flatfacing2 = DoRotation(
+                                      DoRotation(
+                                          DoRotation(headjoint.position, 0, 0, Person::players[closest]->tilt),
+                                          Person::players[closest]->tilt2, 0, 0),
+                                      0, Person::players[closest]->yaw, 0) *
+                                      Person::players[closest]->scale +
+                                  Person::players[closest]->coords;
+                } else {
+                    flatvelocity2_orig = headjoint.velocity;
+                    flatfacing2 = headjoint.position * Person::players[closest]->scale + Person::players[closest]->coords;
                 }
-            }
 
-            XYZ flatfacing2, flatvelocity2;
-            XYZ blah;
-            if (closest != -1 && distsq(&Person::players[closest]->coords, &Person::players[0]->coords) < 144) {
-                blah = Person::players[closest]->coords;
-                XYZ headspurtdirection;
-                //int i = Person::players[closest]->skeleton.jointlabels[head];
-                Joint& headjoint = Person::players[closest]->joint(head);
-                for (unsigned k = 0; k < Person::players[closest]->skeleton.joints.size(); k++) {
-                    if (!Person::players[closest]->skeleton.free) {
-                        flatvelocity2 = Person::players[closest]->velocity;
-                    }
-                    if (Person::players[closest]->skeleton.free) {
-                        flatvelocity2 = headjoint.velocity;
-                    }
-                    if (!Person::players[closest]->skeleton.free) {
-                        flatfacing2 = DoRotation(DoRotation(DoRotation(headjoint.position, 0, 0, Person::players[closest]->tilt), Person::players[closest]->tilt2, 0, 0), 0, Person::players[closest]->yaw, 0) * Person::players[closest]->scale + Person::players[closest]->coords;
-                    }
-                    if (Person::players[closest]->skeleton.free) {
-                        flatfacing2 = headjoint.position * Person::players[closest]->scale + Person::players[closest]->coords;
-                    }
+                headspurtdirection = headjoint.position - Person::players[closest]->jointPos(neck);
+                Normalise(&headspurtdirection);
+
+                for (unsigned i = 0; i < Person::players[closest]->skeleton.joints.size(); i++) {
+                    flatvelocity2 = flatvelocity2_orig;
                     flatvelocity2.x += (float)(abs(Random() % 100) - 50) / 10;
                     flatvelocity2.y += (float)(abs(Random() % 100) - 50) / 10;
                     flatvelocity2.z += (float)(abs(Random() % 100) - 50) / 10;
-                    headspurtdirection = headjoint.position - Person::players[closest]->jointPos(neck);
-                    Normalise(&headspurtdirection);
+                    printf("Test: %f\n", flatvelocity2.x);
+                    printf("Test orig: %f\n", flatvelocity2_orig.x);
                     Sprite::MakeSprite(bloodflamesprite, flatfacing2, flatvelocity2, 1, 1, 1, .6, 1);
                     flatvelocity2 += headspurtdirection * 8;
                     Sprite::MakeSprite(bloodsprite, flatfacing2, flatvelocity2 / 2, 1, 1, 1, .16, 1);
                 }
                 Sprite::MakeSprite(cloudsprite, flatfacing2, flatvelocity2 * 0, .6, 0, 0, 1, .5);
 
-                emit_sound_at(splattersound, blah);
-                emit_sound_at(breaksound2, blah, 100.);
+                emit_sound_at(splattersound, Person::players[closest]->coords);
+                emit_sound_at(breaksound2, Person::players[closest]->coords, 100.);
 
                 if (Person::players[closest]->skeleton.free == 2) {
                     Person::players[closest]->skeleton.free = 0;
@@ -1344,90 +1269,59 @@ void Game::ProcessDevInput()
             }
         }
 
-        /* Explode */
-        if (((Input::isKeyPressed(SDL_SCANCODE_I) && Input::isKeyDown(SDL_SCANCODE_LSHIFT)))) {
+        /* Explode nearby player */
+        if (Input::isKeyPressed(SDL_SCANCODE_I) && Input::isKeyDown(SDL_SCANCODE_LSHIFT)) {
             int closest = findClosestPlayer();
-            XYZ flatfacing2, flatvelocity2;
-            XYZ blah;
             if (closest >= 0 && distsq(&Person::players[closest]->coords, &Person::players[0]->coords) < 144) {
-                blah = Person::players[closest]->coords;
-                emit_sound_at(splattersound, blah);
-                emit_sound_at(breaksound2, blah);
+                XYZ flatfacing2, flatvelocity2, flatvelocity2_orig;
+
+                emit_sound_at(splattersound, Person::players[closest]->coords);
+                emit_sound_at(breaksound2, Person::players[closest]->coords);
 
                 for (unsigned i = 0; i < Person::players[closest]->skeleton.joints.size(); i++) {
                     if (!Person::players[closest]->skeleton.free) {
-                        flatvelocity2 = Person::players[closest]->velocity;
-                    }
-                    if (Person::players[closest]->skeleton.free) {
-                        flatvelocity2 = Person::players[closest]->skeleton.joints[i].velocity;
-                    }
-                    if (!Person::players[closest]->skeleton.free) {
-                        flatfacing2 = DoRotation(DoRotation(DoRotation(Person::players[closest]->skeleton.joints[i].position, 0, 0, Person::players[closest]->tilt), Person::players[closest]->tilt2, 0, 0), 0, Person::players[closest]->yaw, 0) * Person::players[closest]->scale + Person::players[closest]->coords;
-                    }
-                    if (Person::players[closest]->skeleton.free) {
-                        flatfacing2 = Person::players[closest]->skeleton.joints[i].position * Person::players[closest]->scale + Person::players[closest]->coords;
+                        flatvelocity2_orig = Person::players[closest]->velocity;
+                        flatfacing2 = DoRotation(
+                                          DoRotation(
+                                              DoRotation(Person::players[closest]->skeleton.joints[i].position, 0, 0, Person::players[closest]->tilt),
+                                              Person::players[closest]->tilt2, 0, 0),
+                                          0, Person::players[closest]->yaw, 0) *
+                                          Person::players[closest]->scale +
+                                      Person::players[closest]->coords;
+                    } else {
+                        flatvelocity2_orig = Person::players[closest]->skeleton.joints[i].velocity;
+                        flatfacing2 = Person::players[closest]->skeleton.joints[i].position *
+                                          Person::players[closest]->scale +
+                                      Person::players[closest]->coords;
                     }
+
+                    // Animation part 1
+                    flatvelocity2 = flatvelocity2_orig;
                     flatvelocity2.x += (float)(abs(Random() % 100) - 50) / 10;
                     flatvelocity2.y += (float)(abs(Random() % 100) - 50) / 10;
                     flatvelocity2.z += (float)(abs(Random() % 100) - 50) / 10;
                     Sprite::MakeSprite(bloodflamesprite, flatfacing2, flatvelocity2, 1, 1, 1, 3, 1);
                     Sprite::MakeSprite(bloodsprite, flatfacing2, flatvelocity2, 1, 1, 1, .3, 1);
                     Sprite::MakeSprite(cloudsprite, flatfacing2, flatvelocity2 * 0, .6, 0, 0, 1, .5);
-                }
 
-                for (unsigned i = 0; i < Person::players[closest]->skeleton.joints.size(); i++) {
-                    if (!Person::players[closest]->skeleton.free) {
-                        flatvelocity2 = Person::players[closest]->velocity;
-                    }
-                    if (Person::players[closest]->skeleton.free) {
-                        flatvelocity2 = Person::players[closest]->skeleton.joints[i].velocity;
-                    }
-                    if (!Person::players[closest]->skeleton.free) {
-                        flatfacing2 = DoRotation(DoRotation(DoRotation(Person::players[closest]->skeleton.joints[i].position, 0, 0, Person::players[closest]->tilt), Person::players[closest]->tilt2, 0, 0), 0, Person::players[closest]->yaw, 0) * Person::players[closest]->scale + Person::players[closest]->coords;
-                    }
-                    if (Person::players[closest]->skeleton.free) {
-                        flatfacing2 = Person::players[closest]->skeleton.joints[i].position * Person::players[closest]->scale + Person::players[closest]->coords;
-                    }
+                    // Animation part 2
+                    flatvelocity2 = flatvelocity2_orig;
                     flatvelocity2.x += (float)(abs(Random() % 100) - 50) / 10;
                     flatvelocity2.y += (float)(abs(Random() % 100) - 50) / 10;
                     flatvelocity2.z += (float)(abs(Random() % 100) - 50) / 10;
                     Sprite::MakeSprite(bloodflamesprite, flatfacing2, flatvelocity2, 1, 1, 1, 3, 1);
                     Sprite::MakeSprite(bloodsprite, flatfacing2, flatvelocity2, 1, 1, 1, .4, 1);
-                }
 
-                for (unsigned i = 0; i < Person::players[closest]->skeleton.joints.size(); i++) {
-                    if (!Person::players[closest]->skeleton.free) {
-                        flatvelocity2 = Person::players[closest]->velocity;
-                    }
-                    if (Person::players[closest]->skeleton.free) {
-                        flatvelocity2 = Person::players[closest]->skeleton.joints[i].velocity;
-                    }
-                    if (!Person::players[closest]->skeleton.free) {
-                        flatfacing2 = DoRotation(DoRotation(DoRotation(Person::players[closest]->skeleton.joints[i].position, 0, 0, Person::players[closest]->tilt), Person::players[closest]->tilt2, 0, 0), 0, Person::players[closest]->yaw, 0) * Person::players[closest]->scale + Person::players[closest]->coords;
-                    }
-                    if (Person::players[closest]->skeleton.free) {
-                        flatfacing2 = Person::players[closest]->skeleton.joints[i].position * Person::players[closest]->scale + Person::players[closest]->coords;
-                    }
+                    // Animation part 3
+                    flatvelocity2 = flatvelocity2_orig;
                     flatvelocity2.x += (float)(abs(Random() % 100) - 50) / 10;
                     flatvelocity2.y += (float)(abs(Random() % 100) - 50) / 10;
                     flatvelocity2.z += (float)(abs(Random() % 100) - 50) / 10;
                     Sprite::MakeSprite(bloodflamesprite, flatfacing2, flatvelocity2 * 2, 1, 1, 1, 3, 1);
                     Sprite::MakeSprite(bloodsprite, flatfacing2, flatvelocity2 * 2, 1, 1, 1, .4, 1);
-                }
 
-                for (unsigned i = 0; i < Person::players[closest]->skeleton.joints.size(); i++) {
-                    if (!Person::players[closest]->skeleton.free) {
-                        flatvelocity2 = Person::players[closest]->velocity;
-                    }
-                    if (Person::players[closest]->skeleton.free) {
-                        flatvelocity2 = Person::players[closest]->skeleton.joints[i].velocity;
-                    }
-                    if (!Person::players[closest]->skeleton.free) {
-                        flatfacing2 = DoRotation(DoRotation(DoRotation(Person::players[closest]->skeleton.joints[i].position, 0, 0, Person::players[closest]->tilt), Person::players[closest]->tilt2, 0, 0), 0, Person::players[closest]->yaw, 0) * Person::players[closest]->scale + Person::players[closest]->coords;
-                    }
-                    if (Person::players[closest]->skeleton.free) {
-                        flatfacing2 = Person::players[closest]->skeleton.joints[i].position * Person::players[closest]->scale + Person::players[closest]->coords;
-                    }
+                    // Animation part 4
+                    flatvelocity2 = flatvelocity2_orig;
                     flatvelocity2.x += (float)(abs(Random() % 100) - 50) / 10;
                     flatvelocity2.y += (float)(abs(Random() % 100) - 50) / 10;
                     flatvelocity2.z += (float)(abs(Random() % 100) - 50) / 10;
@@ -1437,21 +1331,23 @@ void Game::ProcessDevInput()
 
                 XYZ temppos;
                 for (unsigned j = 0; j < Person::players.size(); j++) {
-                    if (int(j) != closest) {
-                        if (distsq(&Person::players[j]->coords, &Person::players[closest]->coords) < 25) {
-                            Person::players[j]->DoDamage((25 - distsq(&Person::players[j]->coords, &Person::players[closest]->coords)) * 60);
-                            if (Person::players[j]->skeleton.free == 2) {
-                                Person::players[j]->skeleton.free = 1;
-                            }
-                            Person::players[j]->skeleton.longdead = 0;
-                            Person::players[j]->RagDoll(0);
-                            for (unsigned i = 0; i < Person::players[j]->skeleton.joints.size(); i++) {
-                                temppos = Person::players[j]->skeleton.joints[i].position + Person::players[j]->coords;
-                                if (distsq(&temppos, &Person::players[closest]->coords) < 25) {
-                                    flatvelocity2 = temppos - Person::players[closest]->coords;
-                                    Normalise(&flatvelocity2);
-                                    Person::players[j]->skeleton.joints[i].velocity += flatvelocity2 * ((20 - distsq(&temppos, &Person::players[closest]->coords)) * 20);
-                                }
+                    if (int(j) == closest) {
+                        continue;
+                    }
+                    if (distsq(&Person::players[j]->coords, &Person::players[closest]->coords) < 25) {
+                        Person::players[j]->DoDamage((25 - distsq(&Person::players[j]->coords, &Person::players[closest]->coords)) * 60);
+                        if (Person::players[j]->skeleton.free == 2) {
+                            Person::players[j]->skeleton.free = 1;
+                        }
+                        Person::players[j]->skeleton.longdead = 0;
+                        Person::players[j]->RagDoll(0);
+                        for (unsigned i = 0; i < Person::players[j]->skeleton.joints.size(); i++) {
+                            temppos = Person::players[j]->skeleton.joints[i].position + Person::players[j]->coords;
+                            if (distsq(&temppos, &Person::players[closest]->coords) < 25) {
+                                flatvelocity2 = temppos - Person::players[closest]->coords;
+                                Normalise(&flatvelocity2);
+                                Person::players[j]->skeleton.joints[i].velocity +=
+                                    flatvelocity2 * ((20 - distsq(&temppos, &Person::players[closest]->coords)) * 20);
                             }
                         }
                     }
@@ -1466,24 +1362,10 @@ void Game::ProcessDevInput()
                 camerashake += .6;
             }
         }
-
-        /* Enable editor */
-        if (Input::isKeyPressed(SDL_SCANCODE_M) && !Input::isKeyDown(SDL_SCANCODE_LSHIFT)) {
-            editorenabled = !editorenabled;
-            if (editorenabled) {
-                Person::players[0]->damagetolerance = 100000;
-            } else {
-                Person::players[0]->damagetolerance = 200;
-            }
-            Person::players[0]->damage = 0; // these lines were in both if and else, but I think they would better fit in the if
-            Person::players[0]->permanentdamage = 0;
-            Person::players[0]->superpermanentdamage = 0;
-            Person::players[0]->bloodloss = 0;
-            Person::players[0]->deathbleeding = 0;
-        }
     }
 
-    //skip level
+    /* Skip level (only for challenges) */
+    // FIXME: Allow skipping levels in campaigns too
     if (whichlevel != -2 && Input::isKeyPressed(SDL_SCANCODE_K) && Input::isKeyDown(SDL_SCANCODE_LSHIFT) && !editorenabled) {
         targetlevel++;
         if (targetlevel > numchallengelevels - 1) {
@@ -1493,6 +1375,7 @@ void Game::ProcessDevInput()
         leveltime = 5;
     }
 
+    /* Editor mode keys */
     if (editorenabled) {
         /* Closest player deletion */
         if (Input::isKeyPressed(SDL_SCANCODE_DELETE) && Input::isKeyDown(SDL_SCANCODE_LSHIFT)) {
@@ -1511,31 +1394,29 @@ void Game::ProcessDevInput()
         }
 
         /* Add object */
-        if (Input::isKeyPressed(SDL_SCANCODE_O) && !Input::isKeyDown(SDL_SCANCODE_LSHIFT)) {
+        if (Input::isKeyPressed(SDL_SCANCODE_O)) {
             if (Object::objects.size() < max_objects - 1) {
-                XYZ scenecoords;
-                scenecoords.x = Person::players[0]->coords.x;
-                scenecoords.z = Person::players[0]->coords.z;
-                scenecoords.y = Person::players[0]->coords.y - 3;
-                if (editortype == bushtype) {
-                    scenecoords.y = Person::players[0]->coords.y - .5;
-                }
-                if (editortype == firetype) {
-                    scenecoords.y = Person::players[0]->coords.y - .5;
+                XYZ scenecoords = Person::players[0]->coords;
+                scenecoords.y -= 3;
+                if (editortype == bushtype || editortype == firetype) {
+                    scenecoords.y -= 3.5;
+                } else {
+                    scenecoords.y -= 3;
                 }
-                float temprotat, temprotat2;
-                temprotat = editoryaw;
-                temprotat2 = editorpitch;
-                if (temprotat < 0 || editortype == bushtype) {
-                    temprotat = Random() % 360;
+
+                float tmpyaw, tmppitch;
+                tmpyaw = editoryaw;
+                tmppitch = editorpitch;
+                if (tmpyaw < 0 || editortype == bushtype) {
+                    tmpyaw = Random() % 360;
                 }
-                if (temprotat2 < 0) {
-                    temprotat2 = Random() % 360;
+                if (tmppitch < 0) {
+                    tmppitch = Random() % 360;
                 }
 
-                Object::MakeObject(editortype, scenecoords, (int)temprotat - ((int)temprotat) % 30, (int)temprotat2, editorsize);
+                Object::MakeObject(editortype, scenecoords, (int)tmpyaw - ((int)tmpyaw) % 30, (int)tmppitch, editorsize);
                 if (editortype == treetrunktype) {
-                    Object::MakeObject(treeleavestype, scenecoords, Random() % 360 * (temprotat2 < 2) + (int)editoryaw - ((int)editoryaw) % 30, editorpitch, editorsize);
+                    Object::MakeObject(treeleavestype, scenecoords, Random() % 360 * (tmppitch < 2) + (int)editoryaw - ((int)editoryaw) % 30, editorpitch, editorsize);
                 }
             }
         }
@@ -1549,17 +1430,9 @@ void Game::ProcessDevInput()
             Person::players.back()->scale = Person::players[0]->scale;
             Person::players.back()->creature = rabbittype;
             Person::players.back()->howactive = editoractive;
+            Person::players.back()->whichskin = (int)(abs(Random() % 3));
 
-            int k = abs(Random() % 2) + 1;
-            if (k == 0) {
-                Person::players.back()->whichskin = 0;
-            } else if (k == 1) {
-                Person::players.back()->whichskin = 1;
-            } else {
-                Person::players.back()->whichskin = 2;
-            }
-
-            Person::players.back()->skeletonLoad(true);
+            Person::players.back()->skeletonLoad();
 
             Person::players.back()->skeleton.drawmodelclothes.textureptr.load("Textures/Belt.png", 1);
             Person::players.back()->speed = 1 + (float)(Random() % 100) / 1000;
@@ -1571,42 +1444,7 @@ void Game::ProcessDevInput()
             Person::players.back()->oldcoords = Person::players.back()->coords;
             Person::players.back()->realoldcoords = Person::players.back()->coords;
 
-            if (Person::players[0]->creature == wolftype) {
-                headprop = Person::players[0]->proportionhead.x / 1.1;
-                bodyprop = Person::players[0]->proportionbody.x / 1.1;
-                armprop = Person::players[0]->proportionarms.x / 1.1;
-                legprop = Person::players[0]->proportionlegs.x / 1.1;
-            } else {
-                // rabbittype
-                headprop = Person::players[0]->proportionhead.x / 1.2;
-                bodyprop = Person::players[0]->proportionbody.x / 1.05;
-                armprop = Person::players[0]->proportionarms.x / 1.00;
-                legprop = Person::players[0]->proportionlegs.x / 1.1;
-            }
-
-            if (Person::players.back()->creature == wolftype) {
-                Person::players.back()->proportionhead = 1.1 * headprop;
-                Person::players.back()->proportionbody = 1.1 * bodyprop;
-                Person::players.back()->proportionarms = 1.1 * armprop;
-                Person::players.back()->proportionlegs = 1.1 * legprop;
-            }
-
-            if (Person::players.back()->creature == rabbittype) {
-                Person::players.back()->proportionhead = 1.2 * headprop;
-                Person::players.back()->proportionbody = 1.05 * bodyprop;
-                Person::players.back()->proportionarms = 1.00 * armprop;
-                Person::players.back()->proportionlegs = 1.1 * legprop;
-                Person::players.back()->proportionlegs.y = 1.05 * legprop;
-            }
-
-            if (cellophane) {
-                Person::players.back()->proportionhead.z = 0;
-                Person::players.back()->proportionbody.z = 0;
-                Person::players.back()->proportionarms.z = 0;
-                Person::players.back()->proportionlegs.z = 0;
-            }
-
-            Person::players.back()->tempanimation = Animation("Tempanim", lowheight, neutral);
+            Person::players.back()->setProportions(1, 1, 1, 1);
 
             Person::players.back()->damagetolerance = 200;
 
@@ -1634,35 +1472,39 @@ void Game::ProcessDevInput()
             Person::players.back()->power = Person::players[0]->power;
             Person::players.back()->speedmult = Person::players[0]->speedmult;
 
+            if (Input::isKeyDown(SDL_SCANCODE_RSHIFT))
+                Person::players.back()->isplayerfriend = true;
+
             Person::players.back()->loaded = true;
         }
 
         /* Add waypoint */
-        if (Input::isKeyPressed(SDL_SCANCODE_P) && Input::isKeyDown(SDL_SCANCODE_LSHIFT)) {
+        if (Input::isKeyPressed(SDL_SCANCODE_P) && Input::isKeyDown(SDL_SCANCODE_LSHIFT) && !Input::isKeyDown(SDL_SCANCODE_LCTRL)) {
             if (Person::players.back()->numwaypoints < 90) {
                 Person::players.back()->waypoints[Person::players.back()->numwaypoints] = Person::players[0]->coords;
                 Person::players.back()->waypointtype[Person::players.back()->numwaypoints] = editorpathtype;
                 Person::players.back()->numwaypoints++;
+            } else {
+                printf("Add waypoint: Reached max number of waypoints (90), aborting.");
             }
         }
 
         /* Connect waypoint */
-        if (Input::isKeyPressed(SDL_SCANCODE_P) && Input::isKeyDown(SDL_SCANCODE_LCTRL)) {
+        if (Input::isKeyPressed(SDL_SCANCODE_P) && Input::isKeyDown(SDL_SCANCODE_LCTRL) && !Input::isKeyDown(SDL_SCANCODE_LSHIFT)) {
             if (numpathpoints < 30) {
-                bool connected, alreadyconnected;
-                connected = 0;
+                bool connected = false;
                 if (numpathpoints > 1) {
                     for (int i = 0; i < numpathpoints; i++) {
                         if (distsq(&pathpoint[i], &Person::players[0]->coords) < .5 && i != pathpointselected && !connected) {
-                            alreadyconnected = 0;
+                            bool alreadyconnected = false;
                             for (int j = 0; j < numpathpointconnect[pathpointselected]; j++) {
                                 if (pathpointconnect[pathpointselected][j] == i) {
-                                    alreadyconnected = 1;
+                                    alreadyconnected = true;
                                 }
                             }
                             if (!alreadyconnected) {
                                 numpathpointconnect[pathpointselected]++;
-                                connected = 1;
+                                connected = true;
                                 pathpointconnect[pathpointselected][numpathpointconnect[pathpointselected] - 1] = i;
                             }
                         }
@@ -1678,9 +1520,12 @@ void Game::ProcessDevInput()
                     }
                     pathpointselected = numpathpoints - 1;
                 }
+            } else {
+                printf("Connect waypoint: Reached max number of path points (30), aborting.");
             }
         }
 
+        /* Select next path waypoint */
         if (Input::isKeyPressed(SDL_SCANCODE_PERIOD)) {
             pathpointselected++;
             if (pathpointselected >= numpathpoints) {
@@ -1688,6 +1533,7 @@ void Game::ProcessDevInput()
             }
         }
 
+        /* Select previous path waypoint */
         if (Input::isKeyPressed(SDL_SCANCODE_COMMA) && !Input::isKeyDown(SDL_SCANCODE_LSHIFT)) {
             pathpointselected--;
             if (pathpointselected <= -2) {
@@ -1695,6 +1541,7 @@ void Game::ProcessDevInput()
             }
         }
 
+        /* Delete path waypoint */
         if (Input::isKeyPressed(SDL_SCANCODE_COMMA) && Input::isKeyDown(SDL_SCANCODE_LSHIFT)) {
             if (pathpointselected != -1) {
                 numpathpoints--;
@@ -1718,6 +1565,7 @@ void Game::ProcessDevInput()
             }
         }
 
+        /* Select previous object type */
         if (Input::isKeyPressed(SDL_SCANCODE_LEFT) && Input::isKeyDown(SDL_SCANCODE_LSHIFT) && !Input::isKeyDown(SDL_SCANCODE_LCTRL)) {
             editortype--;
             if (editortype == treeleavestype || editortype == 10) {
@@ -1728,6 +1576,7 @@ void Game::ProcessDevInput()
             }
         }
 
+        /* Select next object type */
         if (Input::isKeyPressed(SDL_SCANCODE_RIGHT) && Input::isKeyDown(SDL_SCANCODE_LSHIFT) && !Input::isKeyDown(SDL_SCANCODE_LCTRL)) {
             editortype++;
             if (editortype == treeleavestype || editortype == 10) {
@@ -1738,6 +1587,20 @@ void Game::ProcessDevInput()
             }
         }
 
+        /* Decrease size for next object */
+        if (Input::isKeyDown(SDL_SCANCODE_DOWN) && Input::isKeyDown(SDL_SCANCODE_LSHIFT)) {
+            editorsize -= multiplier;
+            if (editorsize < .1) {
+                editorsize = .1;
+            }
+        }
+
+        /* Increase size for next object */
+        if (Input::isKeyDown(SDL_SCANCODE_UP) && Input::isKeyDown(SDL_SCANCODE_LSHIFT)) {
+            editorsize += multiplier;
+        }
+
+        /* Decrease yaw for next object */
         if (Input::isKeyDown(SDL_SCANCODE_LEFT) && !Input::isKeyDown(SDL_SCANCODE_LSHIFT) && !Input::isKeyDown(SDL_SCANCODE_LCTRL)) {
             editoryaw -= multiplier * 100;
             if (editoryaw < -.01) {
@@ -1745,39 +1608,33 @@ void Game::ProcessDevInput()
             }
         }
 
+        /* Increase yaw for next object */
         if (Input::isKeyDown(SDL_SCANCODE_RIGHT) && !Input::isKeyDown(SDL_SCANCODE_LSHIFT) && !Input::isKeyDown(SDL_SCANCODE_LCTRL)) {
             editoryaw += multiplier * 100;
         }
 
-        if (Input::isKeyDown(SDL_SCANCODE_UP) && !Input::isKeyDown(SDL_SCANCODE_LCTRL)) {
-            editorsize += multiplier;
+        /* Decrease pitch for next object */
+        if (Input::isKeyDown(SDL_SCANCODE_DOWN) && Input::isKeyDown(SDL_SCANCODE_LCTRL)) {
+            editorpitch -= multiplier * 100;
+            if (editorpitch < -.01) {
+                editorpitch = -.01;
+            }
         }
 
-        if (Input::isKeyDown(SDL_SCANCODE_DOWN) && !Input::isKeyDown(SDL_SCANCODE_LCTRL)) {
-            editorsize -= multiplier;
-            if (editorsize < .1) {
-                editorsize = .1;
-            }
+        /* Increase pitch for next object */
+        if (Input::isKeyDown(SDL_SCANCODE_UP) && Input::isKeyDown(SDL_SCANCODE_LCTRL)) {
+            editorpitch += multiplier * 100;
         }
 
+        /* Decrease map radius */
         if (Input::isKeyPressed(SDL_SCANCODE_LEFT) && Input::isKeyDown(SDL_SCANCODE_LSHIFT) && Input::isKeyDown(SDL_SCANCODE_LCTRL)) {
             mapradius -= multiplier * 10;
         }
 
+        /* Increase map radius */
         if (Input::isKeyPressed(SDL_SCANCODE_RIGHT) && Input::isKeyDown(SDL_SCANCODE_LSHIFT) && Input::isKeyDown(SDL_SCANCODE_LCTRL)) {
             mapradius += multiplier * 10;
         }
-
-        if (Input::isKeyDown(SDL_SCANCODE_UP) && Input::isKeyDown(SDL_SCANCODE_LCTRL)) {
-            editorpitch += multiplier * 100;
-        }
-
-        if (Input::isKeyDown(SDL_SCANCODE_DOWN) && Input::isKeyDown(SDL_SCANCODE_LCTRL)) {
-            editorpitch -= multiplier * 100;
-            if (editorpitch < -.01) {
-                editorpitch = -.01;
-            }
-        }
     }
 }
 
@@ -1789,8 +1646,8 @@ void doJumpReversals()
                 Person::players[i]->skeleton.oldfree == 0 &&
                 (Person::players[i]->animTarget == jumpupanim ||
                  Person::players[k]->animTarget == jumpupanim) &&
-                (Person::players[i]->aitype == playercontrolled ||
-                 Person::players[k]->aitype == playercontrolled) &&
+                (Person::players[i]->isPlayerControlled() ||
+                 Person::players[k]->isPlayerControlled()) &&
                 ((Person::players[i]->aitype == attacktypecutoff && Person::players[i]->stunned <= 0) ||
                  (Person::players[k]->aitype == attacktypecutoff && Person::players[k]->stunned <= 0))) {
                 if (distsq(&Person::players[i]->coords, &Person::players[k]->coords) < 10 * sq((Person::players[i]->scale + Person::players[k]->scale) * 2.5) &&
@@ -1801,8 +1658,8 @@ void doJumpReversals()
                         Person::players[k]->animTarget != getupfromfrontanim &&
                         Animation::animations[Person::players[k]->animTarget].height == middleheight &&
                         normaldotproduct(Person::players[i]->velocity, Person::players[k]->coords - Person::players[i]->coords) < 0 &&
-                        ((Person::players[k]->aitype == playercontrolled && Person::players[k]->attackkeydown) ||
-                         Person::players[k]->aitype != playercontrolled)) {
+                        ((Person::players[k]->isPlayerControlled() && Person::players[k]->attackkeydown) ||
+                         !Person::players[k]->isPlayerControlled())) {
                         Person::players[i]->victim = Person::players[k];
                         Person::players[i]->velocity = 0;
                         Person::players[i]->animCurrent = jumpreversedanim;
@@ -1841,8 +1698,8 @@ void doJumpReversals()
                         Person::players[i]->animTarget != getupfromfrontanim &&
                         Animation::animations[Person::players[i]->animTarget].height == middleheight &&
                         normaldotproduct(Person::players[k]->velocity, Person::players[i]->coords - Person::players[k]->coords) < 0 &&
-                        ((Person::players[i]->aitype == playercontrolled && Person::players[i]->attackkeydown) ||
-                         Person::players[i]->aitype != playercontrolled)) {
+                        ((Person::players[i]->isPlayerControlled() && Person::players[i]->attackkeydown) ||
+                         !Person::players[i]->isPlayerControlled())) {
                         Person::players[k]->victim = Person::players[i];
                         Person::players[k]->velocity = 0;
                         Person::players[k]->animCurrent = jumpreversedanim;
@@ -1947,7 +1804,7 @@ void doAerialAcrobatics()
             for (unsigned int l = 0; l < terrain.patchobjects[Person::players[k]->whichpatchx][Person::players[k]->whichpatchz].size(); l++) {
                 unsigned int i = terrain.patchobjects[Person::players[k]->whichpatchx][Person::players[k]->whichpatchz][l];
                 if (Object::objects[i]->type != rocktype ||
-                    Object::objects[i]->scale > .5 && Person::players[k]->aitype == playercontrolled ||
+                    Object::objects[i]->scale > .5 && Person::players[k]->isPlayerControlled() ||
                     Object::objects[i]->position.y > Person::players[k]->coords.y) {
                     lowpoint = Person::players[k]->coords;
                     if (Person::players[k]->animTarget != jumpupanim &&
@@ -1969,7 +1826,7 @@ void doAerialAcrobatics()
                         tempcollide = 1;
                         //wall jumps
                         //TODO: refactor four similar blocks
-                        if (Person::players[k]->aitype == playercontrolled &&
+                        if (Person::players[k]->isPlayerControlled() &&
                             (Person::players[k]->animTarget == jumpupanim ||
                              Person::players[k]->animTarget == jumpdownanim ||
                              Person::players[k]->isFlip()) &&
@@ -2125,7 +1982,7 @@ void doAerialAcrobatics()
                             Person::players[k]->coords.y -= 1.35;
                             Person::players[k]->collide = 1;
 
-                            if ((Person::players[k]->grabdelay <= 0 || Person::players[k]->aitype != playercontrolled) &&
+                            if ((Person::players[k]->grabdelay <= 0 || !Person::players[k]->isPlayerControlled()) &&
                                 (Person::players[k]->animCurrent != climbanim &&
                                      Person::players[k]->animCurrent != hanganim &&
                                      !Person::players[k]->isWallJump() ||
@@ -2303,7 +2160,7 @@ void doAttacks()
         playerrealattackkeydown = Input::isKeyDown(attackkey);
     }
     if ((Person::players[0]->parriedrecently <= 0 ||
-         Person::players[0]->weaponactive == -1) &&
+         !Person::players[0]->hasWeapon()) &&
         (!oldattackkey ||
          (realthreat &&
           Person::players[0]->lastattack != swordslashanim &&
@@ -2335,7 +2192,7 @@ void doAttacks()
             Person::players[k]->attackkeydown = 0;
         }
         if (Person::players[k]->animTarget != rabbitrunninganim && Person::players[k]->animTarget != wolfrunninganim) {
-            if (Person::players[k]->aitype != playercontrolled) {
+            if (!Person::players[k]->isPlayerControlled()) {
                 Person::players[k]->victim = Person::players[0];
             }
             //attack key pressed
@@ -2390,7 +2247,7 @@ void doAttacks()
                      Person::players[k]->animTarget == walkanim ||
                      Person::players[k]->animTarget == sneakanim ||
                      Person::players[k]->isCrouch())) {
-                    const int attackweapon = Person::players[k]->weaponactive == -1 ? 0 : weapons[Person::players[k]->weaponids[Person::players[k]->weaponactive]].getType();
+                    const int attackweapon = (Person::players[k]->hasWeapon() ? weapons[Person::players[k]->weaponids[Person::players[k]->weaponactive]].getType() : 0);
                     //normal attacks (?)
                     Person::players[k]->hasvictim = 0;
                     if (Person::players.size() > 1) {
@@ -2417,7 +2274,7 @@ void doAttacks()
                                         Person::players[i]->animTarget != getupfromfrontanim) {
                                         Person::players[k]->victim = Person::players[i];
                                         Person::players[k]->hasvictim = 1;
-                                        if (Person::players[k]->aitype == playercontrolled) { //human player
+                                        if (Person::players[k]->isPlayerControlled()) { //human player
                                             //sweep
                                             if (distance < 2.5 * sq(Person::players[k]->scale * 5) &&
                                                 Person::players[k]->crouchkeydown &&
@@ -2803,7 +2660,7 @@ void doAttacks()
                             }
                         }
                     }
-                    if (Person::players[k]->aitype == playercontrolled) {
+                    if (Person::players[k]->isPlayerControlled()) {
                         //rabbit kick
                         if (Person::players[k]->attackkeydown &&
                             Person::players[k]->isRun() &&
@@ -2815,7 +2672,7 @@ void doAttacks()
                               Person::players[k]->victim->animTarget != getupfrombackanim &&
                               Person::players[k]->victim->animTarget != getupfromfrontanim &&
                               Animation::animations[Person::players[k]->victim->animTarget].height != lowheight &&
-                              Person::players[k]->aitype != playercontrolled && //wat???
+                              !Person::players[k]->isPlayerControlled() && //wat???
                               normaldotproduct(Person::players[k]->facing, Person::players[k]->victim->coords - Person::players[k]->coords) > 0 &&
                               Person::players[k]->rabbitkickenabled) ||
                              Person::players[k]->jumpkeydown)) {
@@ -3554,8 +3411,8 @@ void Game::Tick()
             static bool respawnkeydown;
             if (!editorenabled &&
                 (whichlevel != -2 &&
-                     (Input::isKeyDown(SDL_SCANCODE_Z) &&
-                      Input::isKeyDown(SDL_SCANCODE_LGUI) &&
+                     (Input::isKeyDown(SDL_SCANCODE_K) &&
+                      Input::isKeyDown(SDL_SCANCODE_LALT) &&
                       devtools) ||
                  (Input::isKeyDown(jumpkey) &&
                   !respawnkeydown &&
@@ -3608,7 +3465,7 @@ void Game::Tick()
                         Person::players[i]->targetheadyaw = yaw;
                         Person::players[i]->targetheadpitch = pitch;
                     }
-                    if (i != 0 && Person::players[i]->aitype == playercontrolled && !Dialog::inDialog()) {
+                    if (i != 0 && Person::players[i]->isPlayerControlled() && !Dialog::inDialog()) {
                         if (!Animation::animations[Person::players[i]->animTarget].attack &&
                             Person::players[i]->animTarget != staggerbackhighanim &&
                             Person::players[i]->animTarget != staggerbackhardanim &&
@@ -3745,7 +3602,7 @@ void Game::Tick()
 
                     //pick up weapon
                     if (Person::players[i]->throwkeydown && !Person::players[i]->throwtogglekeydown) {
-                        if (Person::players[i]->weaponactive == -1 &&
+                        if (!Person::players[i]->hasWeapon() &&
                             Person::players[i]->num_weapons < 2 &&
                             (Person::players[i]->isIdle() ||
                              Person::players[i]->isCrouch() ||
@@ -3753,19 +3610,19 @@ void Game::Tick()
                              Person::players[i]->animTarget == rollanim ||
                              Person::players[i]->animTarget == backhandspringanim ||
                              Person::players[i]->isFlip() ||
-                             Person::players[i]->aitype != playercontrolled)) {
+                             !Person::players[i]->isPlayerControlled())) {
                             for (unsigned j = 0; j < weapons.size(); j++) {
                                 if ((weapons[j].velocity.x == 0 && weapons[j].velocity.y == 0 && weapons[j].velocity.z == 0 ||
-                                     Person::players[i]->aitype == playercontrolled) &&
+                                     Person::players[i]->isPlayerControlled()) &&
                                     weapons[j].owner == -1 &&
-                                    Person::players[i]->weaponactive == -1) {
+                                    !Person::players[i]->hasWeapon()) {
                                     if (distsqflat(&Person::players[i]->coords, &weapons[j].position) < 2) {
                                         if (distsq(&Person::players[i]->coords, &weapons[j].position) < 2) {
                                             if (Person::players[i]->isCrouch() ||
                                                 Person::players[i]->animTarget == sneakanim ||
                                                 Person::players[i]->isRun() ||
                                                 Person::players[i]->isIdle() ||
-                                                Person::players[i]->aitype != playercontrolled) {
+                                                !Person::players[i]->isPlayerControlled()) {
                                                 Person::players[i]->throwtogglekeydown = 1;
                                                 Person::players[i]->setTargetAnimation(crouchremoveknifeanim);
                                                 Person::players[i]->targetyaw = roughDirectionTo(Person::players[i]->coords, weapons[j].position);
@@ -3776,11 +3633,11 @@ void Game::Tick()
                                                 Person::players[i]->hasvictim = 0;
 
                                                 if ((weapons[j].velocity.x == 0 && weapons[j].velocity.y == 0 && weapons[j].velocity.z == 0 ||
-                                                     Person::players[i]->aitype == playercontrolled) &&
+                                                     Person::players[i]->isPlayerControlled()) &&
                                                         weapons[j].owner == -1 ||
                                                     Person::players[i]->victim &&
                                                         weapons[j].owner == int(Person::players[i]->victim->id)) {
-                                                    if (distsqflat(&Person::players[i]->coords, &weapons[j].position) < 2 && Person::players[i]->weaponactive == -1) {
+                                                    if (distsqflat(&Person::players[i]->coords, &weapons[j].position) < 2 && !Person::players[i]->hasWeapon()) {
                                                         if (distsq(&Person::players[i]->coords, &weapons[j].position) < 1 || Person::players[i]->victim) {
                                                             if (weapons[j].getType() != staff) {
                                                                 emit_sound_at(knifedrawsound, Person::players[i]->coords, 128.);
@@ -3793,7 +3650,7 @@ void Game::Tick()
                                             }
                                         } else if ((Person::players[i]->isIdle() ||
                                                     Person::players[i]->isFlip() ||
-                                                    Person::players[i]->aitype != playercontrolled) &&
+                                                    !Person::players[i]->isPlayerControlled()) &&
                                                    distsq(&Person::players[i]->coords, &weapons[j].position) < 5 &&
                                                    Person::players[i]->coords.y < weapons[j].position.y) {
                                             if (!Person::players[i]->isFlip()) {
@@ -3806,14 +3663,14 @@ void Game::Tick()
                                                 Person::players[i]->hasvictim = 0;
 
                                                 for (unsigned k = 0; k < weapons.size(); k++) {
-                                                    if (Person::players[i]->weaponactive == -1) {
+                                                    if (!Person::players[i]->hasWeapon()) {
                                                         if ((weapons[k].velocity.x == 0 && weapons[k].velocity.y == 0 && weapons[k].velocity.z == 0 ||
-                                                             Person::players[i]->aitype == playercontrolled) &&
+                                                             Person::players[i]->isPlayerControlled()) &&
                                                                 weapons[k].owner == -1 ||
                                                             Person::players[i]->victim &&
                                                                 weapons[k].owner == int(Person::players[i]->victim->id)) {
                                                             if (distsqflat(&Person::players[i]->coords, &weapons[k].position) < 3 &&
-                                                                Person::players[i]->weaponactive == -1) {
+                                                                !Person::players[i]->hasWeapon()) {
                                                                 if (weapons[k].getType() != staff) {
                                                                     emit_sound_at(knifedrawsound, Person::players[i]->coords, 128.);
                                                                 }
@@ -3835,7 +3692,7 @@ void Game::Tick()
                                 Person::players[i]->animTarget == backhandspringanim) {
                                 if (Person::players.size() > 1) {
                                     for (unsigned j = 0; j < Person::players.size(); j++) {
-                                        if (Person::players[i]->weaponactive == -1) {
+                                        if (!Person::players[i]->hasWeapon()) {
                                             if (j != i) {
                                                 if (Person::players[j]->num_weapons &&
                                                     Person::players[j]->skeleton.free &&
@@ -3936,7 +3793,7 @@ void Game::Tick()
                                 }
                             }
                         }
-                        if (Person::players[i]->weaponactive != -1 && Person::players[i]->aitype == playercontrolled) {
+                        if (Person::players[i]->hasWeapon() && Person::players[i]->isPlayerControlled()) {
                             if (weapons[Person::players[i]->weaponids[0]].getType() == knife) {
                                 if (Person::players[i]->isIdle() ||
                                     Person::players[i]->isRun() ||
@@ -3961,7 +3818,7 @@ void Game::Tick()
                                                                 Person::players[i]->targettilt2 = pitchTo(Person::players[i]->coords, Person::players[j]->coords);
                                                             }
                                                             if (Person::players[i]->isFlip()) {
-                                                                if (Person::players[i]->weaponactive != -1) {
+                                                                if (Person::players[i]->hasWeapon()) {
                                                                     Person::players[i]->throwtogglekeydown = 1;
                                                                     Person::players[i]->victim = Person::players[j];
                                                                     XYZ aim;
@@ -3987,7 +3844,7 @@ void Game::Tick()
                                 }
                             }
                         }
-                        if (Person::players[i]->weaponactive != -1 && Person::players[i]->aitype == playercontrolled) {
+                        if (Person::players[i]->hasWeapon() && Person::players[i]->isPlayerControlled()) {
                             if (Person::players[i]->isCrouch() || Person::players[i]->animTarget == sneakanim) {
                                 Person::players[i]->throwtogglekeydown = 1;
                                 XYZ tempVelocity = Person::players[i]->velocity * .2;
@@ -4012,16 +3869,16 @@ void Game::Tick()
                     }
 
                     //draw weapon
-                    if (i == 0 || !Person::players[0]->dead || (Person::players[i]->weaponactive != -1)) {
+                    if (i == 0 || !Person::players[0]->dead || (Person::players[i]->hasWeapon())) {
                         if (Person::players[i]->drawkeydown && !Person::players[i]->drawtogglekeydown ||
                             (Person::players[i]->num_weapons == 2) &&
-                                (Person::players[i]->weaponactive == -1) &&
+                                (!Person::players[i]->hasWeapon()) &&
                                 Person::players[i]->isIdle() ||
                             Person::players[0]->dead &&
-                                (Person::players[i]->weaponactive != -1) &&
+                                (Person::players[i]->hasWeapon()) &&
                                 i != 0) {
                             bool isgood = true;
-                            if (Person::players[i]->weaponactive != -1) {
+                            if (Person::players[i]->hasWeapon()) {
                                 if (weapons[Person::players[i]->weaponids[Person::players[i]->weaponactive]].getType() == staff) {
                                     isgood = false;
                                 }
@@ -4032,8 +3889,8 @@ void Game::Tick()
                                     Person::players[i]->drawtogglekeydown = 1;
                                 }
                                 if ((Person::players[i]->isIdle() ||
-                                     (Person::players[i]->aitype != playercontrolled &&
-                                      Person::players[0]->weaponactive != -1 &&
+                                     (!Person::players[i]->isPlayerControlled() &&
+                                      Person::players[0]->hasWeapon() &&
                                       Person::players[i]->isRun())) &&
                                     Person::players[i]->num_weapons &&
                                     weapons[Person::players[i]->weaponids[0]].getType() == sword) {
@@ -4049,7 +3906,7 @@ void Game::Tick()
                     }
 
                     //clean weapon
-                    if (Person::players[i]->weaponactive != -1) {
+                    if (Person::players[i]->hasWeapon()) {
                         if (Person::players[i]->isCrouch() &&
                             weapons[Person::players[i]->weaponids[Person::players[i]->weaponactive]].bloody &&
                             bloodtoggle &&
@@ -4227,7 +4084,7 @@ void Game::Tick()
                                 }
                                 Person::players[i]->frameTarget = 0;
                             }
-                            if (Person::players[i]->animTarget == hanganim /*&&(!Person::players[i]->forwardstogglekeydown||Person::players[i]->aitype!=playercontrolled)*/) {
+                            if (Person::players[i]->animTarget == hanganim /*&&(!Person::players[i]->forwardstogglekeydown||!Person::players[i]->isPlayerControlled())*/) {
                                 Person::players[i]->setTargetAnimation(climbanim);
                                 Person::players[i]->frameTarget = 1;
                                 Person::players[i]->jumpclimb = 1;
@@ -4388,7 +4245,7 @@ void Game::Tick()
                                 }
                                 if (target >= 0) {
                                     Person::players[i]->velocity.y = 1;
-                                } else if (Person::players[i]->crouchkeydown || Person::players[i]->aitype != playercontrolled) {
+                                } else if (Person::players[i]->crouchkeydown || !Person::players[i]->isPlayerControlled()) {
                                     Person::players[i]->velocity.y = 7;
                                     Person::players[i]->crouchtogglekeydown = 1;
                                 } else {
@@ -4424,7 +4281,7 @@ void Game::Tick()
                                 (((!floatjump &&
                                    !editorenabled) ||
                                   !devtools) ||
-                                 Person::players[i]->aitype != playercontrolled)) {
+                                 !Person::players[i]->isPlayerControlled())) {
                                 if (Person::players[i]->jumppower > multiplier * 6) {
                                     Person::players[i]->velocity.y += multiplier * 6;
                                     Person::players[i]->jumppower -= multiplier * 6;