]> git.jsancho.org Git - lugaru.git/commitdiff
Moved Skeleton and Animation to their own folder.
authorCôme Chilliet <come@chilliet.eu>
Fri, 9 Dec 2016 09:29:14 +0000 (16:29 +0700)
committerCôme Chilliet <come@chilliet.eu>
Fri, 9 Dec 2016 10:51:21 +0000 (17:51 +0700)
Moved Animation class in Animation.* files.
Using a vector for animations.
Deactivated the deallocation for now, probable memory leaks, will be
fixed by futur commit

19 files changed:
CMakeLists.txt
Source/Animation.cpp [deleted file]
Source/Animation.def [deleted file]
Source/Animation.h [deleted file]
Source/Animation/Animation.cpp [new file with mode: 0644]
Source/Animation/Animation.def [new file with mode: 0644]
Source/Animation/Animation.h [new file with mode: 0644]
Source/Animation/Skeleton.cpp [new file with mode: 0644]
Source/Animation/Skeleton.h [new file with mode: 0644]
Source/Game.h
Source/GameInitDispose.cpp
Source/GameTick.cpp
Source/Globals.cpp
Source/Person.cpp
Source/Person.h
Source/Skeleton.cpp [deleted file]
Source/Skeleton.h [deleted file]
Source/Weapons.cpp
Source/Weapons.h

index dfcea4fc1118bcae3caf47768dd640c60e5401fe..ddcbd7004c5c6c3f88ea2c4ac47df3c8778d395b 100644 (file)
@@ -39,6 +39,8 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
 
 set(LUGARU_SRCS
     ${SRCDIR}/main.cpp
+    ${SRCDIR}/Animation/Animation.cpp
+    ${SRCDIR}/Animation/Skeleton.cpp
     ${SRCDIR}/Frustum.cpp
     ${SRCDIR}/Account.cpp
     ${SRCDIR}/ConsoleCmds.cpp
@@ -56,7 +58,6 @@ set(LUGARU_SRCS
     ${SRCDIR}/Person.cpp
     ${SRCDIR}/private.c
     ${SRCDIR}/Quaternions.cpp
-    ${SRCDIR}/Skeleton.cpp
     ${SRCDIR}/Skybox.cpp
     ${SRCDIR}/Sprite.cpp
     ${SRCDIR}/Terrain.cpp
@@ -69,13 +70,14 @@ set(LUGARU_SRCS
     ${SRCDIR}/Input.cpp
     ${SRCDIR}/Settings.cpp
     ${SRCDIR}/Stereo.cpp
-    ${SRCDIR}/Animation.cpp
     ${SRCDIR}/Sounds.cpp
     ${SRCDIR}/Awards.cpp
     ${SRCDIR}/Utils/Folders.cpp
 )
 
 set(LUGARU_H
+    ${SRCDIR}/Animation/Animation.h
+    ${SRCDIR}/Animation/Skeleton.h
     ${SRCDIR}/Frustum.h
     ${SRCDIR}/Account.h
     ${SRCDIR}/ConsoleCmds.h
@@ -89,7 +91,6 @@ set(LUGARU_H
     ${SRCDIR}/PhysicsMath.h
     ${SRCDIR}/Quaternions.h
     ${SRCDIR}/Random.h
-    ${SRCDIR}/Skeleton.h
     ${SRCDIR}/Skybox.h
     ${SRCDIR}/Sprite.h
     ${SRCDIR}/ImageIO.h
@@ -105,7 +106,6 @@ set(LUGARU_H
     ${SRCDIR}/private.h
     ${SRCDIR}/Settings.h
     ${SRCDIR}/Stereo.h
-    ${SRCDIR}/Animation.h
     ${SRCDIR}/Sounds.h
     ${SRCDIR}/Utils/Folders.h
 )
diff --git a/Source/Animation.cpp b/Source/Animation.cpp
deleted file mode 100644 (file)
index b7e3995..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
-Copyright (C) 2010-2016 - Lugaru contributors (see AUTHORS file)
-
-This file is part of Lugaru.
-
-Lugaru is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-Lugaru is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Lugaru.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "Skeleton.h"
-#include "Animation.h"
-
-struct animation_data_elt {
-    const std::string& filename;
-    int height;
-    int attack;
-};
-
-static animation_data_elt animation_data[animation_count] = {
-#define DECLARE_ANIM(id, file, height, attack, ...) {file, height, attack},
-#include "Animation.def"
-#undef DECLARE_ANIM
-};
-
-void loadAllAnimations()
-{
-    for (int i = 0; i < loadable_anim_end; i++) {
-        animation_data_elt *e = animation_data + i;
-        animation[i].Load(e->filename, e->height, e->attack);
-    }
-}
diff --git a/Source/Animation.def b/Source/Animation.def
deleted file mode 100644 (file)
index de695f7..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
-Copyright (C) 2010-2016 - Lugaru contributors (see AUTHORS file)
-
-This file is part of Lugaru.
-
-Lugaru is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-Lugaru is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Lugaru.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifdef DECLARE_ANIM_BIT
-DECLARE_ANIM_BIT(ab_idle)
-DECLARE_ANIM_BIT(ab_sit)
-DECLARE_ANIM_BIT(ab_sleep)
-DECLARE_ANIM_BIT(ab_crouch)
-DECLARE_ANIM_BIT(ab_run)
-DECLARE_ANIM_BIT(ab_stop)
-DECLARE_ANIM_BIT(ab_land)
-DECLARE_ANIM_BIT(ab_landhard)
-DECLARE_ANIM_BIT(ab_flip)
-DECLARE_ANIM_BIT(ab_walljump)
-#endif
-
-#ifdef DECLARE_ANIM
-DECLARE_ANIM(runanim, "Run", middleheight, neutral, ab_run)
-DECLARE_ANIM(bounceidleanim, "Idle", middleheight, neutral, ab_idle)
-DECLARE_ANIM(stopanim, "Stop", middleheight, neutral, ab_stop)
-DECLARE_ANIM(jumpupanim, "JumpUp", highheight, neutral, 0)
-DECLARE_ANIM(jumpdownanim, "JumpDown", highheight, neutral, 0)
-DECLARE_ANIM(landanim, "Landing", lowheight, neutral, ab_land)
-DECLARE_ANIM(landhardanim, "LandHard", lowheight, neutral, ab_landhard)
-DECLARE_ANIM(climbanim, "Climb", lowheight, neutral, 0)
-DECLARE_ANIM(hanganim, "HangOn", lowheight, neutral, 0)
-DECLARE_ANIM(spinkickanim, "SpinKick", middleheight, normalattack, 0)
-DECLARE_ANIM(getupfromfrontanim, "GetUpFromFront", lowheight, neutral, 0)
-DECLARE_ANIM(getupfrombackanim, "GetUpFromBack", lowheight, neutral, 0)
-DECLARE_ANIM(crouchanim, "Crouch", lowheight, neutral, ab_crouch)
-DECLARE_ANIM(sneakanim, "Sneak", lowheight, neutral, 0)
-DECLARE_ANIM(rollanim, "Roll", lowheight, neutral, 0)
-DECLARE_ANIM(flipanim, "Flip", highheight, neutral, ab_flip)
-DECLARE_ANIM(frontflipanim, "Flip", highheight, neutral, ab_flip)
-DECLARE_ANIM(spinkickreversedanim, "SpinKickCaught", middleheight, reversed, 0)
-DECLARE_ANIM(spinkickreversalanim, "SpinKickCatch", middleheight, reversal, 0)
-DECLARE_ANIM(lowkickanim, "LowKick", middleheight, normalattack, 0)
-DECLARE_ANIM(sweepanim, "Sweep", lowheight, normalattack, 0)
-DECLARE_ANIM(sweepreversedanim, "SweepCaught", lowheight, reversed, 0)
-DECLARE_ANIM(sweepreversalanim, "SweepCatch", middleheight, reversal, 0)
-DECLARE_ANIM(rabbitkickanim, "RabbitKick", middleheight, normalattack, 0)
-DECLARE_ANIM(rabbitkickreversedanim, "RabbitKickCaught", middleheight, reversed, 0)
-DECLARE_ANIM(rabbitkickreversalanim, "RabbitKickCatch", lowheight, reversal, 0)
-DECLARE_ANIM(upunchanim, "Upunch", middleheight, normalattack, 0)
-DECLARE_ANIM(staggerbackhighanim, "StaggerBackHigh", middleheight, neutral, 0)
-DECLARE_ANIM(upunchreversedanim, "UpunchCaught", middleheight, reversed, 0)
-DECLARE_ANIM(upunchreversalanim, "UpunchCatch", middleheight, reversal, 0)
-DECLARE_ANIM(hurtidleanim, "HurtIdle", middleheight, neutral, ab_idle)
-DECLARE_ANIM(backhandspringanim, "BackHandspring", middleheight, neutral, 0)
-DECLARE_ANIM(fightidleanim, "FightIdle", middleheight, neutral, ab_idle)
-DECLARE_ANIM(walkanim, "Walk", middleheight, neutral, 0)
-DECLARE_ANIM(fightsidestep, "FightSideStep", middleheight, neutral, ab_idle)
-DECLARE_ANIM(killanim, "Kill", middleheight, normalattack, 0)
-DECLARE_ANIM(sneakattackanim, "SneakAttack", middleheight, reversal, 0)
-DECLARE_ANIM(sneakattackedanim, "SneakAttacked", middleheight, reversed, 0)
-DECLARE_ANIM(drawrightanim, "DrawRight", middleheight, neutral, 0)
-DECLARE_ANIM(knifeslashstartanim, "SlashStart", middleheight, normalattack, 0)
-DECLARE_ANIM(crouchdrawrightanim, "CrouchDrawRight", lowheight, neutral, 0)
-DECLARE_ANIM(crouchstabanim, "CrouchStab", lowheight, normalattack, 0)
-DECLARE_ANIM(knifefollowanim, "SlashFollow", middleheight, reversal, 0)
-DECLARE_ANIM(knifefollowedanim, "SlashFollowed", middleheight, reversed, 0)
-DECLARE_ANIM(knifethrowanim, "KnifeThrow", middleheight, normalattack, 0)
-DECLARE_ANIM(removeknifeanim, "RemoveKnife", middleheight, neutral, 0)
-DECLARE_ANIM(crouchremoveknifeanim, "CrouchRemoveKnife", lowheight, neutral, 0)
-DECLARE_ANIM(jumpreversedanim, "JumpCaught", middleheight, reversed, 0)
-DECLARE_ANIM(jumpreversalanim, "JumpCatch", middleheight, reversal, 0)
-DECLARE_ANIM(staggerbackhardanim, "StaggerBackHard", middleheight, neutral, 0)
-DECLARE_ANIM(dropkickanim, "DropKick", middleheight, normalattack, 0)
-DECLARE_ANIM(winduppunchanim, "WindUpPunch", middleheight, normalattack, 0)
-DECLARE_ANIM(winduppunchblockedanim, "WindUpPunchBlocked", middleheight, normalattack, 0)
-DECLARE_ANIM(blockhighleftanim, "BlockHighLeft", middleheight, normalattack, 0)
-DECLARE_ANIM(blockhighleftstrikeanim, "BlockHighLeftStrike", middleheight, normalattack, 0)
-DECLARE_ANIM(backflipanim, "BackFlip", highheight, neutral, ab_flip)
-DECLARE_ANIM(walljumpbackanim, "WallJumpBack", highheight, neutral, ab_walljump)
-DECLARE_ANIM(walljumpfrontanim, "WallJumpFront", highheight, neutral, ab_walljump)
-DECLARE_ANIM(rightflipanim, "RightFlip", highheight, neutral, ab_flip)
-DECLARE_ANIM(walljumprightanim, "WallJumpRight", highheight, neutral, ab_walljump)
-DECLARE_ANIM(leftflipanim, "LeftFlip", highheight, neutral, ab_flip)
-DECLARE_ANIM(walljumpleftanim, "WallJumpLeft", highheight, neutral, ab_walljump)
-DECLARE_ANIM(walljumprightkickanim, "WallJumpRightKick", highheight, neutral, ab_flip)
-DECLARE_ANIM(walljumpleftkickanim, "WallJumpLeftKick", highheight, neutral, ab_flip)
-DECLARE_ANIM(knifefightidleanim, "KnifeFightIdle", middleheight, neutral, ab_idle)
-DECLARE_ANIM(knifesneakattackanim, "KnifeSneakAttack", middleheight, reversal, 0)
-DECLARE_ANIM(knifesneakattackedanim, "KnifeSneakAttacked", middleheight, reversed, 0)
-DECLARE_ANIM(swordfightidleanim, "SwordFightIdle", middleheight, neutral, ab_idle)
-DECLARE_ANIM(drawleftanim, "DrawLeft", middleheight, neutral, 0)
-DECLARE_ANIM(swordslashanim, "SwordSlash", middleheight, normalattack, 0)
-DECLARE_ANIM(swordgroundstabanim, "SwordGroundStab", lowheight, normalattack, 0)
-DECLARE_ANIM(dodgebackanim, "DodgeBack", middleheight, neutral, 0)
-DECLARE_ANIM(swordsneakattackanim, "SwordSneakAttack", middleheight, reversal, 0)
-DECLARE_ANIM(swordsneakattackedanim, "SwordSneakAttacked", middleheight, reversed, 0)
-DECLARE_ANIM(swordslashreversedanim, "SwordSlashCaught", middleheight, reversed, 0)
-DECLARE_ANIM(swordslashreversalanim, "SwordSlashCatch", middleheight, reversal, 0)
-DECLARE_ANIM(knifeslashreversedanim, "KnifeSlashCaught", middleheight, reversed, 0)
-DECLARE_ANIM(knifeslashreversalanim, "KnifeSlashCatch", middleheight, reversal, 0)
-DECLARE_ANIM(swordfightidlebothanim, "SwordFightIdleBoth", middleheight, neutral, ab_idle)
-DECLARE_ANIM(swordslashparryanim, "SwordUprightParry", middleheight, normalattack, 0)
-DECLARE_ANIM(swordslashparriedanim, "SwordSlashParried", middleheight, normalattack, 0)
-DECLARE_ANIM(wolfidle, "WolfIdle", middleheight, neutral, ab_idle)
-DECLARE_ANIM(wolfcrouchanim, "WolfCrouch", lowheight, neutral, ab_crouch)
-DECLARE_ANIM(wolflandanim, "WolfLanding", lowheight, neutral, ab_land)
-DECLARE_ANIM(wolflandhardanim, "WolfLandHard", lowheight, neutral, ab_landhard)
-DECLARE_ANIM(wolfrunanim, "WolfRun", middleheight, neutral, ab_run)
-DECLARE_ANIM(wolfrunninganim, "WolfRunning", middleheight, neutral, ab_run)
-DECLARE_ANIM(rabbitrunninganim, "RabbitRunning", middleheight, neutral, ab_run)
-DECLARE_ANIM(wolfstopanim, "WolfStop", middleheight, neutral, ab_stop)
-DECLARE_ANIM(rabbittackleanim, "RabbitTackle", middleheight, neutral, 0)
-DECLARE_ANIM(rabbittacklinganim, "RabbitTackling", middleheight, reversal, 0)
-DECLARE_ANIM(rabbittackledbackanim, "RabbitTackledBack", middleheight, reversed, 0)
-DECLARE_ANIM(rabbittackledfrontanim, "RabbitTackledFront", middleheight, reversed, 0)
-DECLARE_ANIM(wolfslapanim, "WolfSlap", middleheight, normalattack, 0)
-DECLARE_ANIM(staffhitanim, "StaffHit", middleheight, normalattack, 0)
-DECLARE_ANIM(staffgroundsmashanim, "StaffGroundSmash", lowheight, normalattack, 0)
-DECLARE_ANIM(staffspinhitanim, "SpinWhack", middleheight, normalattack, 0)
-DECLARE_ANIM(staffhitreversedanim, "StaffHitCaught", middleheight, reversed, 0)
-DECLARE_ANIM(staffhitreversalanim, "StaffHitCatch", middleheight, reversal, 0)
-DECLARE_ANIM(staffspinhitreversedanim, "SpinWhackCaught", middleheight, reversed, 0)
-DECLARE_ANIM(staffspinhitreversalanim, "SpinWhackCatch", middleheight, reversal, 0)
-DECLARE_ANIM(sitanim, "Sit", lowheight, neutral, ab_idle | ab_sit)
-DECLARE_ANIM(sleepanim, "Sleep", lowheight, neutral, ab_idle | ab_sleep)
-DECLARE_ANIM(talkidleanim, "TalkIdle", middleheight, neutral, ab_idle)
-DECLARE_ANIM(sitwallanim, "Dying", lowheight, neutral, ab_sit)
-DECLARE_ANIM(dead1anim, "Dead1", lowheight, neutral, ab_sleep)
-DECLARE_ANIM(dead2anim, "Dead2", lowheight, neutral, ab_sleep)
-DECLARE_ANIM(dead3anim, "Dead3", lowheight, neutral, ab_sleep)
-DECLARE_ANIM(dead4anim, "Dead4", lowheight, neutral, ab_sleep)
-
-DECLARE_ANIM(loadable_anim_end, "", 0, 0, 0)
-
-/* Not implemented.  */
-DECLARE_ANIM(rabbittacklereversal, "", 0, 0, 0)
-DECLARE_ANIM(rabbittacklereversed, "", 0, 0, 0)
-DECLARE_ANIM(sworddisarmanim, "", 0, 0, 0)
-DECLARE_ANIM(swordslashleftanim, "", 0, 0, 0)
-DECLARE_ANIM(swordslashrightanim, "", 0, 0, 0)
-DECLARE_ANIM(swordstabanim, "", 0, 0, 0)
-DECLARE_ANIM(wolfbashanim, "", 0, 0, 0)
-DECLARE_ANIM(wolfclawanim, "", 0, 0, 0)
-DECLARE_ANIM(wolffightidle, "", 0, 0, 0)
-DECLARE_ANIM(wolfhurtidle, "", 0, 0, 0)
-DECLARE_ANIM(wolfsneakanim, "", 0, 0, 0)
-DECLARE_ANIM(wolfswordidle, "", 0, 0, 0)
-DECLARE_ANIM(wolftackleanim, "", 0, 0, 0)
-DECLARE_ANIM(wolftackledbacanim, "", 0, 0, 0)
-DECLARE_ANIM(wolftackledfrontanim, "", 0, 0, 0)
-DECLARE_ANIM(wolftacklereversal, "", 0, 0, 0)
-DECLARE_ANIM(wolftacklereversed, "", 0, 0, 0)
-DECLARE_ANIM(wolftacklinganim, "", 0, 0, 0)
-
-DECLARE_ANIM(tempanim, "", 0, 0, 0)
-#endif
diff --git a/Source/Animation.h b/Source/Animation.h
deleted file mode 100644 (file)
index 7448589..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
-Copyright (C) 2010-2016 - Lugaru contributors (see AUTHORS file)
-
-This file is part of Lugaru.
-
-Lugaru is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-Lugaru is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Lugaru.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef ANIMATION_H
-#define ANIMATION_H
-
-enum anim_attack_type {
-    neutral, normalattack, reversed, reversal
-};
-
-enum anim_height_type {
-    lowheight, middleheight, highheight
-};
-
-enum animation_types {
-#define DECLARE_ANIM(id, ...) id,
-#include "Animation.def"
-#undef DECLARE_ANIM
-    animation_count
-};
-
-enum animation_bit_offsets {
-#define DECLARE_ANIM_BIT(bit) o_##bit,
-#include "Animation.def"
-#undef DECLARE_ANIM_BIT
-    animation_bit_count
-};
-
-enum animation_bits_def {
-#define DECLARE_ANIM_BIT(bit) bit = 1 << o_##bit,
-#include "Animation.def"
-#undef DECLARE_ANIM_BIT
-};
-
-static const int animation_bits[animation_count] = {
-#define DECLARE_ANIM(id, name, height, type, bits) bits,
-#include "Animation.def"
-#undef DECLARE_ANIM
-};
-
-extern Animation animation[animation_count];
-
-extern void loadAllAnimations();
-#endif
diff --git a/Source/Animation/Animation.cpp b/Source/Animation/Animation.cpp
new file mode 100644 (file)
index 0000000..3ccd17c
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+Copyright (C) 2010-2016 - Lugaru contributors (see AUTHORS file)
+
+This file is part of Lugaru.
+
+Lugaru is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+Lugaru is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Lugaru.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "Animation/Skeleton.h"
+#include "Animation/Animation.h"
+#include "Utils/Folders.h"
+#include "Game.h"
+
+extern bool visibleloading;
+
+//~ struct animation_data_elt {
+    //~ const std::string& filename;
+    //~ int height;
+    //~ int attack;
+//~ };
+
+//~ static animation_data_elt animation_data[animation_count] = {
+//~ #define DECLARE_ANIM(id, file, height, attack, ...) {file, height, attack},
+//~ #include "Animation.def"
+//~ #undef DECLARE_ANIM
+//~ };
+std::vector<Animation> Animation::animations;
+
+void Animation::loadAll()
+{
+    int i = 0;
+#define DECLARE_ANIM(id, file, height, attack, ...) if (i++ < loadable_anim_end) animations.emplace_back(file, height, attack);
+#include "Animation.def"
+#undef DECLARE_ANIM
+}
+
+
+Animation::Animation():
+    numframes(0),
+    height(0),
+    attack(0),
+    joints(0),
+    weapontargetnum(0),
+
+    position(0),
+    twist(0),
+    twist2(0),
+    speed(0),
+    onground(0),
+    forward(0),
+    label(0),
+    weapontarget(0)
+{
+}
+
+/* EFFECT
+ * load an animation from file
+ */
+Animation::Animation(const std::string& filename, int aheight, int aattack):
+    Animation()
+{
+    FILE *tfile;
+    int i, j;
+    XYZ endoffset;
+
+    LOGFUNC;
+
+    // Changing the filename into something the OS can understand
+    std::string filepath = Folders::getResourcePath("Animations/"+filename);
+
+    LOG(std::string("Loading animation...") + filepath);
+
+    height = aheight;
+    attack = aattack;
+
+    if (visibleloading)
+        Game::LoadingScreen();
+
+    // read file in binary mode
+    tfile = Folders::openMandatoryFile( filepath, "rb" );
+
+    // read numframes, joints to know how much memory to allocate
+    funpackf(tfile, "Bi Bi", &numframes, &joints);
+
+    // allocate memory for everything
+
+    position = (XYZ**)malloc(sizeof(XYZ*) * joints);
+    for (i = 0; i < joints; i++)
+        position[i] = (XYZ*)malloc(sizeof(XYZ) * numframes);
+
+    twist = (float**)malloc(sizeof(float*) * joints);
+    for (i = 0; i < joints; i++)
+        twist[i] = (float*)malloc(sizeof(float) * numframes);
+
+    twist2 = (float**)malloc(sizeof(float*) * joints);
+    for (i = 0; i < joints; i++)
+        twist2[i] = (float*)malloc(sizeof(float) * numframes);
+
+    speed = (float*)malloc(sizeof(float) * numframes);
+
+    onground = (bool**)malloc(sizeof(bool*) * joints);
+    for (i = 0; i < joints; i++)
+        onground[i] = (bool*)malloc(sizeof(bool) * numframes);
+
+    forward = (XYZ*)malloc(sizeof(XYZ) * numframes);
+    weapontarget = (XYZ*)malloc(sizeof(XYZ) * numframes);
+    label = (int*)malloc(sizeof(int) * numframes);
+
+    // read binary data as animation
+
+    // for each frame...
+    for (i = 0; i < numframes; i++) {
+        // for each joint in the skeleton...
+        for (j = 0; j < joints; j++) {
+            // read joint position
+            funpackf(tfile, "Bf Bf Bf", &position[j][i].x, &position[j][i].y, &position[j][i].z);
+        }
+        for (j = 0; j < joints; j++) {
+            // read twist
+            funpackf(tfile, "Bf", &twist[j][i]);
+        }
+        for (j = 0; j < joints; j++) {
+            // read onground (boolean)
+            unsigned char uch;
+            funpackf(tfile, "Bb", &uch);
+            onground[j][i] = (uch != 0);
+        }
+        // read frame speed (?)
+        funpackf(tfile, "Bf", &speed[i]);
+    }
+    // read twist2 for whole animation
+    for (i = 0; i < numframes; i++) {
+        for (j = 0; j < joints; j++) {
+            funpackf(tfile, "Bf", &twist2[j][i]);
+        }
+    }
+    // read label for each frame
+    for (i = 0; i < numframes; i++) {
+        funpackf(tfile, "Bf", &label[i]);
+    }
+    // read weapontargetnum
+    funpackf(tfile, "Bi", &weapontargetnum);
+    // read weapontarget positions for each frame
+    for (i = 0; i < numframes; i++) {
+        funpackf(tfile, "Bf Bf Bf", &weapontarget[i].x, &weapontarget[i].y, &weapontarget[i].z);
+    }
+
+    fclose(tfile);
+
+    endoffset = 0;
+    // find average position of certain joints on last frames
+    // and save in endoffset
+    // (not sure what exactly this accomplishes. the y < 1 test confuses me.)
+    for (j = 0; j < joints; j++) {
+        if (position[j][numframes - 1].y < 1)
+            endoffset += position[j][numframes - 1];
+    }
+    endoffset /= joints;
+    offset = endoffset;
+    offset.y = 0;
+}
+
+Animation::~Animation()
+{
+    //~ deallocate();
+}
+
+void Animation::deallocate()
+{
+    int i = 0;
+
+    if (position) {
+        for (i = 0; i < joints; i++)
+            free(position[i]);
+
+        free(position);
+    }
+    position = 0;
+
+    if (twist) {
+        for (i = 0; i < joints; i++)
+            free(twist[i]);
+
+        free(twist);
+    }
+    twist = 0;
+
+    if (twist2) {
+        for (i = 0; i < joints; i++)
+            free(twist2[i]);
+
+        free(twist2);
+    }
+    twist2 = 0;
+
+    if (onground) {
+        for (i = 0; i < joints; i++)
+            free(onground[i]);
+
+        free(onground);
+    }
+    onground = 0;
+
+    if (speed)
+        free(speed);
+    speed = 0;
+
+    if (forward)
+        free(forward);
+    forward = 0;
+
+    if (weapontarget)
+        free(weapontarget);
+    weapontarget = 0;
+
+    if (label)
+        free(label);
+    label = 0;
+
+    joints = 0;
+}
+
+Animation & Animation::operator = (const Animation & ani)
+{
+    int i = 0;
+
+    bool allocate = ((ani.numframes != numframes) || (ani.joints != joints));
+
+    if (allocate)
+        deallocate();
+
+    numframes = ani.numframes;
+    height = ani.height;
+    attack = ani.attack;
+    joints = ani.joints;
+    weapontargetnum = ani.weapontargetnum;
+    offset = ani.offset;
+
+    if (allocate)
+        position = (XYZ**)malloc(sizeof(XYZ*)*ani.joints);
+    for (i = 0; i < ani.joints; i++) {
+        if (allocate)
+            position[i] = (XYZ*)malloc(sizeof(XYZ) * ani.numframes);
+        memcpy(position[i], ani.position[i], sizeof(XYZ)*ani.numframes);
+    }
+
+    if (allocate)
+        twist = (float**)malloc(sizeof(float*)*ani.joints);
+    for (i = 0; i < ani.joints; i++) {
+        if (allocate)
+            twist[i] = (float*)malloc(sizeof(float) * ani.numframes);
+        memcpy(twist[i], ani.twist[i], sizeof(float)*ani.numframes);
+    }
+
+    if (allocate)
+        twist2 = (float**)malloc(sizeof(float*)*ani.joints);
+    for (i = 0; i < ani.joints; i++) {
+        if (allocate)
+            twist2[i] = (float*)malloc(sizeof(float) * ani.numframes);
+        memcpy(twist2[i], ani.twist2[i], sizeof(float)*ani.numframes);
+    }
+
+    if (allocate)
+        speed = (float*)malloc(sizeof(float) * ani.numframes);
+    memcpy(speed, ani.speed, sizeof(float)*ani.numframes);
+
+    if (allocate)
+        onground = (bool**)malloc(sizeof(bool*)*ani.joints);
+    for (i = 0; i < ani.joints; i++) {
+        if (allocate)
+            onground[i] = (bool*)malloc(sizeof(bool) * ani.numframes);
+        memcpy(onground[i], ani.onground[i], sizeof(bool)*ani.numframes);
+    }
+
+    if (allocate)
+        forward = (XYZ*)malloc(sizeof(XYZ) * ani.numframes);
+    memcpy(forward, ani.forward, sizeof(XYZ)*ani.numframes);
+
+    if (allocate)
+        weapontarget = (XYZ*)malloc(sizeof(XYZ) * ani.numframes);
+    memcpy(weapontarget, ani.weapontarget, sizeof(XYZ)*ani.numframes);
+
+    if (allocate)
+        label = (int*)malloc(sizeof(int) * ani.numframes);
+    memcpy(label, ani.label, sizeof(int)*ani.numframes);
+
+    return (*this);
+}
diff --git a/Source/Animation/Animation.def b/Source/Animation/Animation.def
new file mode 100644 (file)
index 0000000..2a48c42
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+Copyright (C) 2010-2016 - Lugaru contributors (see AUTHORS file)
+
+This file is part of Lugaru.
+
+Lugaru is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+Lugaru is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Lugaru.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifdef DECLARE_ANIM_BIT
+DECLARE_ANIM_BIT(ab_idle)
+DECLARE_ANIM_BIT(ab_sit)
+DECLARE_ANIM_BIT(ab_sleep)
+DECLARE_ANIM_BIT(ab_crouch)
+DECLARE_ANIM_BIT(ab_run)
+DECLARE_ANIM_BIT(ab_stop)
+DECLARE_ANIM_BIT(ab_land)
+DECLARE_ANIM_BIT(ab_landhard)
+DECLARE_ANIM_BIT(ab_flip)
+DECLARE_ANIM_BIT(ab_walljump)
+#endif
+
+#ifdef DECLARE_ANIM
+DECLARE_ANIM(runanim, "Run", middleheight, neutral, ab_run)
+DECLARE_ANIM(bounceidleanim, "Idle", middleheight, neutral, ab_idle)
+DECLARE_ANIM(stopanim, "Stop", middleheight, neutral, ab_stop)
+DECLARE_ANIM(jumpupanim, "JumpUp", highheight, neutral, 0)
+DECLARE_ANIM(jumpdownanim, "JumpDown", highheight, neutral, 0)
+DECLARE_ANIM(landanim, "Landing", lowheight, neutral, ab_land)
+DECLARE_ANIM(landhardanim, "LandHard", lowheight, neutral, ab_landhard)
+DECLARE_ANIM(climbanim, "Climb", lowheight, neutral, 0)
+DECLARE_ANIM(hanganim, "HangOn", lowheight, neutral, 0)
+DECLARE_ANIM(spinkickanim, "SpinKick", middleheight, normalattack, 0)
+DECLARE_ANIM(getupfromfrontanim, "GetUpFromFront", lowheight, neutral, 0)
+DECLARE_ANIM(getupfrombackanim, "GetUpFromBack", lowheight, neutral, 0)
+DECLARE_ANIM(crouchanim, "Crouch", lowheight, neutral, ab_crouch)
+DECLARE_ANIM(sneakanim, "Sneak", lowheight, neutral, 0)
+DECLARE_ANIM(rollanim, "Roll", lowheight, neutral, 0)
+DECLARE_ANIM(flipanim, "Flip", highheight, neutral, ab_flip)
+DECLARE_ANIM(frontflipanim, "Flip", highheight, neutral, ab_flip)
+DECLARE_ANIM(spinkickreversedanim, "SpinKickCaught", middleheight, reversed, 0)
+DECLARE_ANIM(spinkickreversalanim, "SpinKickCatch", middleheight, reversal, 0)
+DECLARE_ANIM(lowkickanim, "LowKick", middleheight, normalattack, 0)
+DECLARE_ANIM(sweepanim, "Sweep", lowheight, normalattack, 0)
+DECLARE_ANIM(sweepreversedanim, "SweepCaught", lowheight, reversed, 0)
+DECLARE_ANIM(sweepreversalanim, "SweepCatch", middleheight, reversal, 0)
+DECLARE_ANIM(rabbitkickanim, "RabbitKick", middleheight, normalattack, 0)
+DECLARE_ANIM(rabbitkickreversedanim, "RabbitKickCaught", middleheight, reversed, 0)
+DECLARE_ANIM(rabbitkickreversalanim, "RabbitKickCatch", lowheight, reversal, 0)
+DECLARE_ANIM(upunchanim, "Upunch", middleheight, normalattack, 0)
+DECLARE_ANIM(staggerbackhighanim, "StaggerBackHigh", middleheight, neutral, 0)
+DECLARE_ANIM(upunchreversedanim, "UpunchCaught", middleheight, reversed, 0)
+DECLARE_ANIM(upunchreversalanim, "UpunchCatch", middleheight, reversal, 0)
+DECLARE_ANIM(hurtidleanim, "HurtIdle", middleheight, neutral, ab_idle)
+DECLARE_ANIM(backhandspringanim, "BackHandspring", middleheight, neutral, 0)
+DECLARE_ANIM(fightidleanim, "FightIdle", middleheight, neutral, ab_idle)
+DECLARE_ANIM(walkanim, "Walk", middleheight, neutral, 0)
+DECLARE_ANIM(fightsidestep, "FightSideStep", middleheight, neutral, ab_idle)
+DECLARE_ANIM(killanim, "Kill", middleheight, normalattack, 0)
+DECLARE_ANIM(sneakattackanim, "SneakAttack", middleheight, reversal, 0)
+DECLARE_ANIM(sneakattackedanim, "SneakAttacked", middleheight, reversed, 0)
+DECLARE_ANIM(drawrightanim, "DrawRight", middleheight, neutral, 0)
+DECLARE_ANIM(knifeslashstartanim, "SlashStart", middleheight, normalattack, 0)
+DECLARE_ANIM(crouchdrawrightanim, "CrouchDrawRight", lowheight, neutral, 0)
+DECLARE_ANIM(crouchstabanim, "CrouchStab", lowheight, normalattack, 0)
+DECLARE_ANIM(knifefollowanim, "SlashFollow", middleheight, reversal, 0)
+DECLARE_ANIM(knifefollowedanim, "SlashFollowed", middleheight, reversed, 0)
+DECLARE_ANIM(knifethrowanim, "KnifeThrow", middleheight, normalattack, 0)
+DECLARE_ANIM(removeknifeanim, "RemoveKnife", middleheight, neutral, 0)
+DECLARE_ANIM(crouchremoveknifeanim, "CrouchRemoveKnife", lowheight, neutral, 0)
+DECLARE_ANIM(jumpreversedanim, "JumpCaught", middleheight, reversed, 0)
+DECLARE_ANIM(jumpreversalanim, "JumpCatch", middleheight, reversal, 0)
+DECLARE_ANIM(staggerbackhardanim, "StaggerBackHard", middleheight, neutral, 0)
+DECLARE_ANIM(dropkickanim, "DropKick", middleheight, normalattack, 0)
+DECLARE_ANIM(winduppunchanim, "WindUpPunch", middleheight, normalattack, 0)
+DECLARE_ANIM(winduppunchblockedanim, "WindUpPunchBlocked", middleheight, normalattack, 0)
+DECLARE_ANIM(blockhighleftanim, "BlockHighLeft", middleheight, normalattack, 0)
+DECLARE_ANIM(blockhighleftstrikeanim, "BlockHighLeftStrike", middleheight, normalattack, 0)
+DECLARE_ANIM(backflipanim, "BackFlip", highheight, neutral, ab_flip)
+DECLARE_ANIM(walljumpbackanim, "WallJumpBack", highheight, neutral, ab_walljump)
+DECLARE_ANIM(walljumpfrontanim, "WallJumpFront", highheight, neutral, ab_walljump)
+DECLARE_ANIM(rightflipanim, "RightFlip", highheight, neutral, ab_flip)
+DECLARE_ANIM(walljumprightanim, "WallJumpRight", highheight, neutral, ab_walljump)
+DECLARE_ANIM(leftflipanim, "LeftFlip", highheight, neutral, ab_flip)
+DECLARE_ANIM(walljumpleftanim, "WallJumpLeft", highheight, neutral, ab_walljump)
+DECLARE_ANIM(walljumprightkickanim, "WallJumpRightKick", highheight, neutral, ab_flip)
+DECLARE_ANIM(walljumpleftkickanim, "WallJumpLeftKick", highheight, neutral, ab_flip)
+DECLARE_ANIM(knifefightidleanim, "KnifeFightIdle", middleheight, neutral, ab_idle)
+DECLARE_ANIM(knifesneakattackanim, "KnifeSneakAttack", middleheight, reversal, 0)
+DECLARE_ANIM(knifesneakattackedanim, "KnifeSneakAttacked", middleheight, reversed, 0)
+DECLARE_ANIM(swordfightidleanim, "SwordFightIdle", middleheight, neutral, ab_idle)
+DECLARE_ANIM(drawleftanim, "DrawLeft", middleheight, neutral, 0)
+DECLARE_ANIM(swordslashanim, "SwordSlash", middleheight, normalattack, 0)
+DECLARE_ANIM(swordgroundstabanim, "SwordGroundStab", lowheight, normalattack, 0)
+DECLARE_ANIM(dodgebackanim, "DodgeBack", middleheight, neutral, 0)
+DECLARE_ANIM(swordsneakattackanim, "SwordSneakAttack", middleheight, reversal, 0)
+DECLARE_ANIM(swordsneakattackedanim, "SwordSneakAttacked", middleheight, reversed, 0)
+DECLARE_ANIM(swordslashreversedanim, "SwordSlashCaught", middleheight, reversed, 0)
+DECLARE_ANIM(swordslashreversalanim, "SwordSlashCatch", middleheight, reversal, 0)
+DECLARE_ANIM(knifeslashreversedanim, "KnifeSlashCaught", middleheight, reversed, 0)
+DECLARE_ANIM(knifeslashreversalanim, "KnifeSlashCatch", middleheight, reversal, 0)
+DECLARE_ANIM(swordfightidlebothanim, "SwordFightIdleBoth", middleheight, neutral, ab_idle)
+DECLARE_ANIM(swordslashparryanim, "SwordUprightParry", middleheight, normalattack, 0)
+DECLARE_ANIM(swordslashparriedanim, "SwordSlashParried", middleheight, normalattack, 0)
+DECLARE_ANIM(wolfidle, "WolfIdle", middleheight, neutral, ab_idle)
+DECLARE_ANIM(wolfcrouchanim, "WolfCrouch", lowheight, neutral, ab_crouch)
+DECLARE_ANIM(wolflandanim, "WolfLanding", lowheight, neutral, ab_land)
+DECLARE_ANIM(wolflandhardanim, "WolfLandHard", lowheight, neutral, ab_landhard)
+DECLARE_ANIM(wolfrunanim, "WolfRun", middleheight, neutral, ab_run)
+DECLARE_ANIM(wolfrunninganim, "WolfRunning", middleheight, neutral, ab_run)
+DECLARE_ANIM(rabbitrunninganim, "RabbitRunning", middleheight, neutral, ab_run)
+DECLARE_ANIM(wolfstopanim, "WolfStop", middleheight, neutral, ab_stop)
+DECLARE_ANIM(rabbittackleanim, "RabbitTackle", middleheight, neutral, 0)
+DECLARE_ANIM(rabbittacklinganim, "RabbitTackling", middleheight, reversal, 0)
+DECLARE_ANIM(rabbittackledbackanim, "RabbitTackledBack", middleheight, reversed, 0)
+DECLARE_ANIM(rabbittackledfrontanim, "RabbitTackledFront", middleheight, reversed, 0)
+DECLARE_ANIM(wolfslapanim, "WolfSlap", middleheight, normalattack, 0)
+DECLARE_ANIM(staffhitanim, "StaffHit", middleheight, normalattack, 0)
+DECLARE_ANIM(staffgroundsmashanim, "StaffGroundSmash", lowheight, normalattack, 0)
+DECLARE_ANIM(staffspinhitanim, "SpinWhack", middleheight, normalattack, 0)
+DECLARE_ANIM(staffhitreversedanim, "StaffHitCaught", middleheight, reversed, 0)
+DECLARE_ANIM(staffhitreversalanim, "StaffHitCatch", middleheight, reversal, 0)
+DECLARE_ANIM(staffspinhitreversedanim, "SpinWhackCaught", middleheight, reversed, 0)
+DECLARE_ANIM(staffspinhitreversalanim, "SpinWhackCatch", middleheight, reversal, 0)
+DECLARE_ANIM(sitanim, "Sit", lowheight, neutral, ab_idle | ab_sit)
+DECLARE_ANIM(sleepanim, "Sleep", lowheight, neutral, ab_idle | ab_sleep)
+DECLARE_ANIM(talkidleanim, "TalkIdle", middleheight, neutral, ab_idle)
+DECLARE_ANIM(sitwallanim, "Dying", lowheight, neutral, ab_sit)
+DECLARE_ANIM(dead1anim, "Dead1", lowheight, neutral, ab_sleep)
+DECLARE_ANIM(dead2anim, "Dead2", lowheight, neutral, ab_sleep)
+DECLARE_ANIM(dead3anim, "Dead3", lowheight, neutral, ab_sleep)
+DECLARE_ANIM(dead4anim, "Dead4", lowheight, neutral, ab_sleep)
+
+DECLARE_ANIM(tempanim, "", 0, 0, 0)
+
+DECLARE_ANIM(loadable_anim_end, "", 0, 0, 0)
+
+/* Not implemented.  */
+DECLARE_ANIM(rabbittacklereversal, "", 0, 0, 0)
+DECLARE_ANIM(rabbittacklereversed, "", 0, 0, 0)
+DECLARE_ANIM(sworddisarmanim, "", 0, 0, 0)
+DECLARE_ANIM(swordslashleftanim, "", 0, 0, 0)
+DECLARE_ANIM(swordslashrightanim, "", 0, 0, 0)
+DECLARE_ANIM(swordstabanim, "", 0, 0, 0)
+DECLARE_ANIM(wolfbashanim, "", 0, 0, 0)
+DECLARE_ANIM(wolfclawanim, "", 0, 0, 0)
+DECLARE_ANIM(wolffightidle, "", 0, 0, 0)
+DECLARE_ANIM(wolfhurtidle, "", 0, 0, 0)
+DECLARE_ANIM(wolfsneakanim, "", 0, 0, 0)
+DECLARE_ANIM(wolfswordidle, "", 0, 0, 0)
+DECLARE_ANIM(wolftackleanim, "", 0, 0, 0)
+DECLARE_ANIM(wolftackledbacanim, "", 0, 0, 0)
+DECLARE_ANIM(wolftackledfrontanim, "", 0, 0, 0)
+DECLARE_ANIM(wolftacklereversal, "", 0, 0, 0)
+DECLARE_ANIM(wolftacklereversed, "", 0, 0, 0)
+DECLARE_ANIM(wolftacklinganim, "", 0, 0, 0)
+#endif
diff --git a/Source/Animation/Animation.h b/Source/Animation/Animation.h
new file mode 100644 (file)
index 0000000..3633de9
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+Copyright (C) 2010-2016 - Lugaru contributors (see AUTHORS file)
+
+This file is part of Lugaru.
+
+Lugaru is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+Lugaru is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Lugaru.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef ANIMATION_H
+#define ANIMATION_H
+
+#include <vector>
+
+enum anim_attack_type {
+    neutral, normalattack, reversed, reversal
+};
+
+enum anim_height_type {
+    lowheight, middleheight, highheight
+};
+
+enum animation_types {
+#define DECLARE_ANIM(id, ...) id,
+#include "Animation.def"
+#undef DECLARE_ANIM
+    animation_count
+};
+
+enum animation_bit_offsets {
+#define DECLARE_ANIM_BIT(bit) o_##bit,
+#include "Animation.def"
+#undef DECLARE_ANIM_BIT
+    animation_bit_count
+};
+
+enum animation_bits_def {
+#define DECLARE_ANIM_BIT(bit) bit = 1 << o_##bit,
+#include "Animation.def"
+#undef DECLARE_ANIM_BIT
+};
+
+static const int animation_bits[animation_count] = {
+#define DECLARE_ANIM(id, name, height, type, bits) bits,
+#include "Animation.def"
+#undef DECLARE_ANIM
+};
+
+class Animation
+{
+public:
+    static std::vector<Animation> animations;
+    static void loadAll();
+
+    int numframes;
+    int height;
+    int attack;
+    int joints;
+    int weapontargetnum;
+
+    XYZ**  position;
+    float** twist;
+    float** twist2;
+    float* speed;
+    bool** onground;
+    XYZ* forward;
+    int* label;
+    XYZ* weapontarget;
+
+    XYZ offset;
+
+    Animation();
+    Animation(const std::string& fileName, int aheight, int aattack);
+    ~Animation();
+    Animation & operator = (const Animation & ani);
+
+protected:
+    void deallocate();
+};
+#endif
diff --git a/Source/Animation/Skeleton.cpp b/Source/Animation/Skeleton.cpp
new file mode 100644 (file)
index 0000000..aac06ee
--- /dev/null
@@ -0,0 +1,1451 @@
+/*
+Copyright (C) 2003, 2010 - Wolfire Games
+Copyright (C) 2010-2016 - Lugaru contributors (see AUTHORS file)
+
+This file is part of Lugaru.
+
+Lugaru is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+Lugaru is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Lugaru.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**> HEADER FILES <**/
+#include "Game.h"
+#include "Animation/Skeleton.h"
+#include "openal_wrapper.h"
+#include "Animation/Animation.h"
+#include "Utils/Folders.h"
+
+extern float multiplier;
+extern float gravity;
+extern Terrain terrain;
+extern Objects objects;
+extern int environment;
+extern float camerashake;
+extern bool freeze;
+extern int detail;
+extern int tutoriallevel;
+
+extern int whichjointstartarray[26];
+extern int whichjointendarray[26];
+
+extern bool visibleloading;
+
+/* EFFECT
+ */
+void dealloc2(void* param)
+{
+    free(param);
+}
+
+enum {boneconnect, constraint, muscle};
+
+
+/* EFFECT
+ * sets strength, length,
+ *      parent1->position, parent2->position,
+ *      parent1->velocity, parent2->velocity
+ * used for ragdolls?
+ *
+ * USES:
+ * Skeleton::DoConstraints
+ */
+void Muscle::DoConstraint(bool spinny)
+{
+    // FIXME: relaxlength shouldn't be static, but may not always be set
+    // so I don't want to change the existing behavior even though it's probably a bug
+    static float relaxlength;
+
+    float oldlength = length;
+
+    if (type != boneconnect)
+        relaxlength = findDistance(&parent1->position, &parent2->position);
+
+    if (type == boneconnect)
+        strength = 1;
+    if (type == constraint)
+        strength = 0;
+
+    // clamp strength
+    if (strength < 0)
+        strength = 0;
+    if (strength > 1)
+        strength = 1;
+
+    length -= (length - relaxlength) * (1 - strength) * multiplier * 10000;
+    length -= (length - targetlength) * (strength) * multiplier * 10000;
+    if (strength == 0)
+        length = relaxlength;
+
+    if ((relaxlength - length > 0 && relaxlength - oldlength < 0) || (relaxlength - length < 0 && relaxlength - oldlength > 0))
+        length = relaxlength;
+
+    // clamp length
+    if (length < minlength)
+        length = minlength;
+    if (length > maxlength)
+        length = maxlength;
+
+    if (length == relaxlength)
+        return;
+
+    // relax muscle?
+
+    //Find midpoint
+    XYZ midp = (parent1->position * parent1->mass + parent2->position * parent2->mass) / (parent1->mass + parent2->mass);
+
+    //Find vector from midpoint to second vector
+    XYZ vel = parent2->position - midp;
+
+    //Change to unit vector
+    Normalise(&vel);
+
+    //Apply velocity change
+    XYZ newpoint1 = midp - vel * length * (parent2->mass / (parent1->mass + parent2->mass));
+    XYZ newpoint2 = midp + vel * length * (parent1->mass / (parent1->mass + parent2->mass));
+    if (!freeze && spinny) {
+        parent1->velocity = parent1->velocity + (newpoint1 - parent1->position) / multiplier / 4;
+        parent2->velocity = parent2->velocity + (newpoint2 - parent2->position) / multiplier / 4;
+    } else {
+        parent1->velocity = parent1->velocity + (newpoint1 - parent1->position);
+        parent2->velocity = parent2->velocity + (newpoint2 - parent2->position);
+    }
+
+    //Move child point to within certain distance of parent point
+    parent1->position = newpoint1;
+    parent2->position = newpoint2;
+}
+
+/* EFFECT
+ * sets forward, lowforward, specialforward[]
+ *
+ * USES:
+ * Skeleton::Load
+ * Person/Person::DoAnimations
+ * Person/Person::DrawSkeleton
+ */
+void Skeleton::FindForwards()
+{
+    //Find forward vectors
+    CrossProduct(joints[forwardjoints[1]].position - joints[forwardjoints[0]].position, joints[forwardjoints[2]].position - joints[forwardjoints[0]].position, &forward);
+    Normalise(&forward);
+
+    CrossProduct(joints[lowforwardjoints[1]].position - joints[lowforwardjoints[0]].position, joints[lowforwardjoints[2]].position - joints[lowforwardjoints[0]].position, &lowforward);
+    Normalise(&lowforward);
+
+    //Special forwards
+    specialforward[0] = forward;
+
+    specialforward[1] = jointPos(rightshoulder) + jointPos(rightwrist);
+    specialforward[1] = jointPos(rightelbow) - specialforward[1] / 2;
+    specialforward[1] += forward * .4;
+    Normalise(&specialforward[1]);
+    specialforward[2] = jointPos(leftshoulder) + jointPos(leftwrist);
+    specialforward[2] = jointPos(leftelbow) - specialforward[2] / 2;
+    specialforward[2] += forward * .4;
+    Normalise(&specialforward[2]);
+
+    specialforward[3] = jointPos(righthip) + jointPos(rightankle);
+    specialforward[3] = specialforward[3] / 2 - jointPos(rightknee);
+    specialforward[3] += lowforward * .4;
+    Normalise(&specialforward[3]);
+    specialforward[4] = jointPos(lefthip) + jointPos(leftankle);
+    specialforward[4] = specialforward[4] / 2 - jointPos(leftknee);
+    specialforward[4] += lowforward * .4;
+    Normalise(&specialforward[4]);
+}
+
+/* EFFECT
+ * TODO
+ *
+ * USES:
+ * Person/Person::RagDoll
+ * Person/Person::DoStuff
+ * Person/IKHelper
+ */
+float Skeleton::DoConstraints(XYZ *coords, float *scale)
+{
+    float friction = 1.5;
+    const float elasticity = .3;
+    XYZ bounceness;
+    const int numrepeats = 3;
+    float groundlevel = .15;
+    int i, j, k, m;
+    XYZ temp;
+    XYZ terrainnormal;
+    int whichhit;
+    float frictionness;
+    XYZ terrainlight;
+    int whichpatchx;
+    int whichpatchz;
+    float damage = 0; // eventually returned from function
+    bool breaking = false;
+
+    if (free) {
+        freetime += multiplier;
+
+        whichpatchx = coords->x / (terrain.size / subdivision * terrain.scale);
+        whichpatchz = coords->z / (terrain.size / subdivision * terrain.scale);
+
+        terrainlight = *coords;
+        objects.SphereCheckPossible(&terrainlight, 1);
+
+        //Add velocity
+        for (i = 0; i < num_joints; i++) {
+            joints[i].position = joints[i].position + joints[i].velocity * multiplier;
+
+            switch (joints[i].label) {
+            case head:
+                groundlevel = .8;
+                break;
+            case righthand:
+            case rightwrist:
+            case rightelbow:
+            case lefthand:
+            case leftwrist:
+            case leftelbow:
+                groundlevel = .2;
+                break;
+            default:
+                groundlevel = .15;
+                break;
+            }
+
+            joints[i].position.y -= groundlevel;
+            joints[i].oldvelocity = joints[i].velocity;
+        }
+
+        float tempmult = multiplier;
+        //multiplier/=numrepeats;
+
+        for (j = 0; j < numrepeats; j++) {
+            float r = .05;
+            // right leg constraints?
+            if (!joint(rightknee).locked && !joint(righthip).locked) {
+                temp = jointPos(rightknee) - (jointPos(righthip) + jointPos(rightankle)) / 2;
+                while (normaldotproduct(temp, lowforward) > -.1 && !sphere_line_intersection(&jointPos(righthip), &jointPos(rightankle), &jointPos(rightknee), &r)) {
+                    jointPos(rightknee) -= lowforward * .05;
+                    if (spinny)
+                        jointVel(rightknee) -= lowforward * .05 / multiplier / 4;
+                    else
+                        jointVel(rightknee) -= lowforward * .05;
+                    jointPos(rightankle) += lowforward * .025;
+                    if (spinny)
+                        jointVel(rightankle) += lowforward * .025 / multiplier / 4;
+                    else
+                        jointVel(rightankle) += lowforward * .25;
+                    jointPos(righthip) += lowforward * .025;
+                    if (spinny)
+                        jointVel(righthip) += lowforward * .025 / multiplier / 4;
+                    else
+                        jointVel(righthip) += lowforward * .025;
+                    temp = jointPos(rightknee) - (jointPos(righthip) + jointPos(rightankle)) / 2;
+                }
+            }
+
+            // left leg constraints?
+            if (!joint(leftknee).locked && !joint(lefthip).locked) {
+                temp = jointPos(leftknee) - (jointPos(lefthip) + jointPos(leftankle)) / 2;
+                while (normaldotproduct(temp, lowforward) > -.1 && !sphere_line_intersection(&jointPos(lefthip), &jointPos(leftankle), &jointPos(leftknee), &r)) {
+                    jointPos(leftknee) -= lowforward * .05;
+                    if (spinny)
+                        jointVel(leftknee) -= lowforward * .05 / multiplier / 4;
+                    else
+                        jointVel(leftknee) -= lowforward * .05;
+                    jointPos(leftankle) += lowforward * .025;
+                    if (spinny)
+                        jointVel(leftankle) += lowforward * .025 / multiplier / 4;
+                    else
+                        jointVel(leftankle) += lowforward * .25;
+                    jointPos(lefthip) += lowforward * .025;
+                    if (spinny)
+                        jointVel(lefthip) += lowforward * .025 / multiplier / 4;
+                    else
+                        jointVel(lefthip) += lowforward * .025;
+                    temp = jointPos(leftknee) - (jointPos(lefthip) + jointPos(leftankle)) / 2;
+                }
+            }
+
+            for (i = 0; i < num_joints; i++) {
+                if (joints[i].locked && !spinny && findLengthfast(&joints[i].velocity) > 320)
+                    joints[i].locked = 0;
+                if (spinny && findLengthfast(&joints[i].velocity) > 600)
+                    joints[i].locked = 0;
+                if (joints[i].delay > 0) {
+                    bool freely = true;
+                    for (j = 0; j < num_joints; j++) {
+                        if (joints[j].locked)
+                            freely = false;
+                    }
+                    if (freely)
+                        joints[i].delay -= multiplier * 3;
+                }
+            }
+
+            if (num_muscles)
+                for (i = 0; i < num_muscles; i++) {
+                    //Length constraints
+                    muscles[i].DoConstraint(spinny);
+                }
+
+            for (i = 0; i < num_joints; i++) {
+                //Length constraints
+                //Ground constraint
+                groundlevel = 0;
+                if (joints[i].position.y * (*scale) + coords->y < terrain.getHeight(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z) + groundlevel) {
+                    freefall = 0;
+                    friction = 1.5;
+                    if (joints[i].label == groin && !joints[i].locked && joints[i].delay <= 0) {
+                        joints[i].locked = 1;
+                        joints[i].delay = 1;
+                        if (tutoriallevel != 1 || id == 0) {
+                            emit_sound_at(landsound1, joints[i].position * (*scale) + *coords, 128.);
+                        }
+                        breaking = true;
+                    }
+
+                    if (joints[i].label == head && !joints[i].locked && joints[i].delay <= 0) {
+                        joints[i].locked = 1;
+                        joints[i].delay = 1;
+                        if (tutoriallevel != 1 || id == 0) {
+                            emit_sound_at(landsound2, joints[i].position * (*scale) + *coords, 128.);
+                        }
+                    }
+
+                    terrainnormal = terrain.getNormal(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z);
+                    ReflectVector(&joints[i].velocity, &terrainnormal);
+                    bounceness = terrainnormal * findLength(&joints[i].velocity) * (abs(normaldotproduct(joints[i].velocity, terrainnormal)));
+                    if (!joints[i].locked)
+                        damage += findLengthfast(&bounceness) / 4000;
+                    if (findLengthfast(&joints[i].velocity) < findLengthfast(&bounceness))
+                        bounceness = 0;
+                    frictionness = abs(normaldotproduct(joints[i].velocity, terrainnormal));
+                    joints[i].velocity -= bounceness;
+                    if (1 - friction * frictionness > 0)
+                        joints[i].velocity *= 1 - friction * frictionness;
+                    else
+                        joints[i].velocity = 0;
+
+                    if (tutoriallevel != 1 || id == 0)
+                        if (findLengthfast(&bounceness) > 8000 && breaking) {
+                            // FIXME: this crashes because k is not initialized!
+                            // to reproduce, type 'wolfie' in console and play a while
+                            // I'll just comment it out for now
+                            //objects.model[k].MakeDecal(breakdecal, DoRotation(temp - objects.position[k], 0, -objects.yaw[k], 0), .4, .5, Random() % 360);
+                            Sprite::MakeSprite(cloudsprite, joints[i].position * (*scale) + *coords, joints[i].velocity * .06, 1, 1, 1, 4, .2);
+                            breaking = false;
+                            camerashake += .6;
+
+                            emit_sound_at(breaksound2, joints[i].position * (*scale) + *coords);
+
+                            addEnvSound(*coords, 64);
+                        }
+
+                    if (findLengthfast(&bounceness) > 2500) {
+                        Normalise(&bounceness);
+                        bounceness = bounceness * 50;
+                    }
+
+                    joints[i].velocity += bounceness * elasticity;
+
+                    if (findLengthfast(&joints[i].velocity) > findLengthfast(&joints[i].oldvelocity)) {
+                        bounceness = 0;
+                        joints[i].velocity = joints[i].oldvelocity;
+                    }
+
+
+                    if (joints[i].locked == 0)
+                        if (findLengthfast(&joints[i].velocity) < 1)
+                            joints[i].locked = 1;
+
+                    if (environment == snowyenvironment && findLengthfast(&bounceness) > 500 && terrain.getOpacity(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z) < .2) {
+                        terrainlight = terrain.getLighting(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z);
+                        Sprite::MakeSprite(cloudsprite, joints[i].position * (*scale) + *coords, joints[i].velocity * .06, terrainlight.x, terrainlight.y, terrainlight.z, .5, .7);
+                        if (detail == 2)
+                            terrain.MakeDecal(bodyprintdecal, joints[i].position * (*scale) + *coords, .4, .4, 0);
+                    } else if (environment == desertenvironment && findLengthfast(&bounceness) > 500 && terrain.getOpacity(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z) < .2) {
+                        terrainlight = terrain.getLighting(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z);
+                        Sprite::MakeSprite(cloudsprite, joints[i].position * (*scale) + *coords, joints[i].velocity * .06, terrainlight.x * 190 / 255, terrainlight.y * 170 / 255, terrainlight.z * 108 / 255, .5, .7);
+                    }
+
+                    else if (environment == grassyenvironment && findLengthfast(&bounceness) > 500 && terrain.getOpacity(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z) < .2) {
+                        terrainlight = terrain.getLighting(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z);
+                        Sprite::MakeSprite(cloudsprite, joints[i].position * (*scale) + *coords, joints[i].velocity * .06, terrainlight.x * 90 / 255, terrainlight.y * 70 / 255, terrainlight.z * 8 / 255, .5, .5);
+                    } else if (findLengthfast(&bounceness) > 500)
+                        Sprite::MakeSprite(cloudsprite, joints[i].position * (*scale) + *coords, joints[i].velocity * .06, terrainlight.x, terrainlight.y, terrainlight.z, .5, .2);
+
+
+                    joints[i].position.y = (terrain.getHeight(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z) + groundlevel - coords->y) / (*scale);
+                    if (longdead > 100)
+                        broken = 1;
+                }
+                if (terrain.patchobjectnum[whichpatchx][whichpatchz])
+                    for (m = 0; m < terrain.patchobjectnum[whichpatchx][whichpatchz]; m++) {
+                        k = terrain.patchobjects[whichpatchx][whichpatchz][m];
+                        if (k < objects.numobjects && k >= 0)
+                            if (objects.possible[k]) {
+                                friction = objects.friction[k];
+                                XYZ start = joints[i].realoldposition;
+                                XYZ end = joints[i].position * (*scale) + *coords;
+                                whichhit = objects.model[k].LineCheckPossible(&start, &end, &temp, &objects.position[k], &objects.yaw[k]);
+                                if (whichhit != -1) {
+                                    if (joints[i].label == groin && !joints[i].locked && joints[i].delay <= 0) {
+                                        joints[i].locked = 1;
+                                        joints[i].delay = 1;
+                                        if (tutoriallevel != 1 || id == 0) {
+                                            emit_sound_at(landsound1, joints[i].position * (*scale) + *coords, 128.);
+                                        }
+                                        breaking = true;
+                                    }
+
+                                    if (joints[i].label == head && !joints[i].locked && joints[i].delay <= 0) {
+                                        joints[i].locked = 1;
+                                        joints[i].delay = 1;
+                                        if (tutoriallevel != 1 || id == 0) {
+                                            emit_sound_at(landsound2, joints[i].position * (*scale) + *coords, 128.);
+                                        }
+                                    }
+
+                                    terrainnormal = DoRotation(objects.model[k].facenormals[whichhit], 0, objects.yaw[k], 0) * -1;
+                                    if (terrainnormal.y > .8)
+                                        freefall = 0;
+                                    bounceness = terrainnormal * findLength(&joints[i].velocity) * (abs(normaldotproduct(joints[i].velocity, terrainnormal)));
+                                    if (findLengthfast(&joints[i].velocity) > findLengthfast(&joints[i].oldvelocity)) {
+                                        bounceness = 0;
+                                        joints[i].velocity = joints[i].oldvelocity;
+                                    }
+                                    if (tutoriallevel != 1 || id == 0)
+                                        if (findLengthfast(&bounceness) > 4000 && breaking) {
+                                            objects.model[k].MakeDecal(breakdecal, DoRotation(temp - objects.position[k], 0, -objects.yaw[k], 0), .4, .5, Random() % 360);
+                                            Sprite::MakeSprite(cloudsprite, joints[i].position * (*scale) + *coords, joints[i].velocity * .06, 1, 1, 1, 4, .2);
+                                            breaking = false;
+                                            camerashake += .6;
+
+                                            emit_sound_at(breaksound2, joints[i].position * (*scale) + *coords);
+
+                                            addEnvSound(*coords, 64);
+                                        }
+                                    if (objects.type[k] == treetrunktype) {
+                                        objects.rotx[k] += joints[i].velocity.x * multiplier * .4;
+                                        objects.roty[k] += joints[i].velocity.z * multiplier * .4;
+                                        objects.rotx[k + 1] += joints[i].velocity.x * multiplier * .4;
+                                        objects.roty[k + 1] += joints[i].velocity.z * multiplier * .4;
+                                    }
+                                    if (!joints[i].locked)
+                                        damage += findLengthfast(&bounceness) / 2500;
+                                    ReflectVector(&joints[i].velocity, &terrainnormal);
+                                    frictionness = abs(normaldotproduct(joints[i].velocity, terrainnormal));
+                                    joints[i].velocity -= bounceness;
+                                    if (1 - friction * frictionness > 0)
+                                        joints[i].velocity *= 1 - friction * frictionness;
+                                    else
+                                        joints[i].velocity = 0;
+                                    if (findLengthfast(&bounceness) > 2500) {
+                                        Normalise(&bounceness);
+                                        bounceness = bounceness * 50;
+                                    }
+                                    joints[i].velocity += bounceness * elasticity;
+
+
+                                    if (!joints[i].locked)
+                                        if (findLengthfast(&joints[i].velocity) < 1) {
+                                            joints[i].locked = 1;
+                                        }
+                                    if (findLengthfast(&bounceness) > 500)
+                                        Sprite::MakeSprite(cloudsprite, joints[i].position * (*scale) + *coords, joints[i].velocity * .06, 1, 1, 1, .5, .2);
+                                    joints[i].position = (temp - *coords) / (*scale) + terrainnormal * .005;
+                                    if (longdead > 100)
+                                        broken = 1;
+                                }
+                            }
+                    }
+                joints[i].realoldposition = joints[i].position * (*scale) + *coords;
+            }
+        }
+        multiplier = tempmult;
+
+
+        if (terrain.patchobjectnum[whichpatchx][whichpatchz])
+            for (m = 0; m < terrain.patchobjectnum[whichpatchx][whichpatchz]; m++) {
+                k = terrain.patchobjects[whichpatchx][whichpatchz][m];
+                if (objects.possible[k]) {
+                    for (i = 0; i < 26; i++) {
+                        //Make this less stupid
+                        XYZ start = joints[jointlabels[whichjointstartarray[i]]].position * (*scale) + *coords;
+                        XYZ end = joints[jointlabels[whichjointendarray[i]]].position * (*scale) + *coords;
+                        whichhit = objects.model[k].LineCheckSlidePossible(&start, &end, &temp, &objects.position[k], &objects.yaw[k]);
+                        if (whichhit != -1) {
+                            joints[jointlabels[whichjointendarray[i]]].position = (end - *coords) / (*scale);
+                            for (j = 0; j < num_muscles; j++) {
+                                if ((muscles[j].parent1->label == whichjointstartarray[i] && muscles[j].parent2->label == whichjointendarray[i]) || (muscles[j].parent2->label == whichjointstartarray[i] && muscles[j].parent1->label == whichjointendarray[i]))
+                                    muscles[j].DoConstraint(spinny);
+                            }
+                        }
+                    }
+                }
+            }
+
+        for (i = 0; i < num_joints; i++) {
+            switch (joints[i].label) {
+            case head:
+                groundlevel = .8;
+                break;
+            case righthand:
+            case rightwrist:
+            case rightelbow:
+            case lefthand:
+            case leftwrist:
+            case leftelbow:
+                groundlevel = .2;
+                break;
+            default:
+                groundlevel = .15;
+                break;
+            }
+            joints[i].position.y += groundlevel;
+            joints[i].mass = 1;
+            if (joints[i].label == lefthip || joints[i].label == leftknee || joints[i].label == leftankle || joints[i].label == righthip || joints[i].label == rightknee || joints[i].label == rightankle)
+                joints[i].mass = 2;
+            if (joints[i].locked) {
+                joints[i].mass = 4;
+            }
+        }
+
+        return damage;
+    }
+
+    if (!free) {
+        for (i = 0; i < num_muscles; i++) {
+            if (muscles[i].type == boneconnect)
+                muscles[i].DoConstraint(0);
+        }
+    }
+
+    return 0;
+}
+
+/* EFFECT
+ * applies gravity to the skeleton
+ *
+ * USES:
+ * Person/Person::DoStuff
+ */
+void Skeleton::DoGravity(float *scale)
+{
+    static int i;
+    for (i = 0; i < num_joints; i++) {
+        if (
+                (
+                    ((joints[i].label != leftknee) && (joints[i].label != rightknee)) ||
+                    (lowforward.y > -.1) ||
+                    (joints[i].mass < 5)
+                ) && (
+                    ((joints[i].label != leftelbow) && (joints[i].label != rightelbow)) ||
+                    (forward.y < .3)
+                )
+            )
+            joints[i].velocity.y += gravity * multiplier / (*scale);
+    }
+}
+
+/* EFFECT
+ * set muscles[which].rotate1
+ *     .rotate2
+ *     .rotate3
+ *
+ * special case if animation == hanganim
+ */
+void Skeleton::FindRotationMuscle(int which, int animation)
+{
+    XYZ p1, p2, fwd;
+    float dist;
+
+    p1 = muscles[which].parent1->position;
+    p2 = muscles[which].parent2->position;
+    dist = findDistance(&p1, &p2);
+    if (p1.y - p2.y <= dist)
+        muscles[which].rotate2 = asin((p1.y - p2.y) / dist);
+    if (p1.y - p2.y > dist)
+        muscles[which].rotate2 = asin(1.f);
+    muscles[which].rotate2 *= 360.0 / 6.2831853;
+
+    p1.y = 0;
+    p2.y = 0;
+    dist = findDistance(&p1, &p2);
+    if (p1.z - p2.z <= dist)
+        muscles[which].rotate1 = acos((p1.z - p2.z) / dist);
+    if (p1.z - p2.z > dist)
+        muscles[which].rotate1 = acos(1.f);
+    muscles[which].rotate1 *= 360.0 / 6.2831853;
+    if (p1.x > p2.x)
+        muscles[which].rotate1 = 360 - muscles[which].rotate1;
+    if (!isnormal(muscles[which].rotate1))
+        muscles[which].rotate1 = 0;
+    if (!isnormal(muscles[which].rotate2))
+        muscles[which].rotate2 = 0;
+
+    const int label1 = muscles[which].parent1->label;
+    const int label2 = muscles[which].parent2->label;
+    switch (label1) {
+    case head:
+        fwd = specialforward[0];
+        break;
+    case rightshoulder:
+    case rightelbow:
+    case rightwrist:
+    case righthand:
+        fwd = specialforward[1];
+        break;
+    case leftshoulder:
+    case leftelbow:
+    case leftwrist:
+    case lefthand:
+        fwd = specialforward[2];
+        break;
+    case righthip:
+    case rightknee:
+    case rightankle:
+    case rightfoot:
+        fwd = specialforward[3];
+        break;
+    case lefthip:
+    case leftknee:
+    case leftankle:
+    case leftfoot:
+        fwd = specialforward[4];
+        break;
+    default:
+        if (muscles[which].parent1->lower)
+            fwd = lowforward;
+        else
+            fwd = forward;
+        break;
+    }
+
+    if (animation == hanganim) {
+        if (label1 == righthand || label2 == righthand) {
+            fwd = 0;
+            fwd.x = -1;
+        }
+        if (label1 == lefthand || label2 == lefthand) {
+            fwd = 0;
+            fwd.x = 1;
+        }
+    }
+
+    if (free == 0) {
+        if (label1 == rightfoot || label2 == rightfoot) {
+            fwd.y -= .3;
+        }
+        if (label1 == leftfoot || label2 == leftfoot) {
+            fwd.y -= .3;
+        }
+    }
+
+    fwd = DoRotation(fwd, 0, muscles[which].rotate1 - 90, 0);
+    fwd = DoRotation(fwd, 0, 0, muscles[which].rotate2 - 90);
+    fwd.y = 0;
+    fwd /= findLength(&fwd);
+    if (fwd.z <= 1 && fwd.z >= -1)
+        muscles[which].rotate3 = acos(0 - fwd.z);
+    else
+        muscles[which].rotate3 = acos(-1.f);
+    muscles[which].rotate3 *= 360.0 / 6.2831853;
+    if (0 > fwd.x)
+        muscles[which].rotate3 = 360 - muscles[which].rotate3;
+    if (!isnormal(muscles[which].rotate3))
+        muscles[which].rotate3 = 0;
+}
+
+/* EFFECT
+ * load skeleton
+ * takes filenames for three skeleton files and various models
+ */
+void Skeleton::Load(const std::string& filename,       const std::string& lowfilename, const std::string& clothesfilename,
+                    const std::string& modelfilename,  const std::string& model2filename,
+                    const std::string& model3filename, const std::string& model4filename,
+                    const std::string& model5filename, const std::string& model6filename,
+                    const std::string& model7filename, const std::string& modellowfilename,
+                    const std::string& modelclothesfilename, bool clothes)
+{
+    GLfloat M[16];
+    int parentID;
+    FILE *tfile;
+    float lSize;
+    int i, j;
+    int edit;
+
+    LOGFUNC;
+
+    num_models = 7;
+
+    // load various models
+    // rotate, scale, do normals, do texcoords for each as needed
+
+    model[0].loadnotex(modelfilename);
+    model[1].loadnotex(model2filename);
+    model[2].loadnotex(model3filename);
+    model[3].loadnotex(model4filename);
+    model[4].loadnotex(model5filename);
+    model[5].loadnotex(model6filename);
+    model[6].loadnotex(model7filename);
+
+    for (i = 0; i < num_models; i++) {
+        model[i].Rotate(180, 0, 0);
+        model[i].Scale(.04, .04, .04);
+        model[i].CalculateNormals(0);
+    }
+
+    drawmodel.load(modelfilename, 0);
+    drawmodel.Rotate(180, 0, 0);
+    drawmodel.Scale(.04, .04, .04);
+    drawmodel.FlipTexCoords();
+    if (tutoriallevel == 1 && id != 0)
+        drawmodel.UniformTexCoords();
+    if (tutoriallevel == 1 && id != 0)
+        drawmodel.ScaleTexCoords(0.1);
+    drawmodel.CalculateNormals(0);
+
+    modellow.loadnotex(modellowfilename);
+    modellow.Rotate(180, 0, 0);
+    modellow.Scale(.04, .04, .04);
+    modellow.CalculateNormals(0);
+
+    drawmodellow.load(modellowfilename, 0);
+    drawmodellow.Rotate(180, 0, 0);
+    drawmodellow.Scale(.04, .04, .04);
+    drawmodellow.FlipTexCoords();
+    if (tutoriallevel == 1 && id != 0)
+        drawmodellow.UniformTexCoords();
+    if (tutoriallevel == 1 && id != 0)
+        drawmodellow.ScaleTexCoords(0.1);
+    drawmodellow.CalculateNormals(0);
+
+    if (clothes) {
+        modelclothes.loadnotex(modelclothesfilename);
+        modelclothes.Rotate(180, 0, 0);
+        modelclothes.Scale(.041, .04, .041);
+        modelclothes.CalculateNormals(0);
+
+        drawmodelclothes.load(modelclothesfilename, 0);
+        drawmodelclothes.Rotate(180, 0, 0);
+        drawmodelclothes.Scale(.04, .04, .04);
+        drawmodelclothes.FlipTexCoords();
+        drawmodelclothes.CalculateNormals(0);
+    }
+
+    // FIXME: three similar blocks follow, one for each of:
+    // filename, lowfilename, clothesfilename
+
+    // load skeleton
+
+    tfile = Folders::openMandatoryFile( Folders::getResourcePath(filename), "rb" );
+
+    // read num_joints
+    funpackf(tfile, "Bi", &num_joints);
+
+    // allocate memory
+    if (joints)
+        delete [] joints; //dealloc2(joints);
+    joints = (Joint*)new Joint[num_joints];
+
+    // read info for each joint
+    for (i = 0; i < num_joints; i++) {
+        funpackf(tfile, "Bf Bf Bf Bf Bf", &joints[i].position.x, &joints[i].position.y, &joints[i].position.z, &joints[i].length, &joints[i].mass);
+        funpackf(tfile, "Bb Bb", &joints[i].hasparent, &joints[i].locked);
+        funpackf(tfile, "Bi", &joints[i].modelnum);
+        funpackf(tfile, "Bb Bb", &joints[i].visible, &joints[i].sametwist);
+        funpackf(tfile, "Bi Bi", &joints[i].label, &joints[i].hasgun);
+        funpackf(tfile, "Bb", &joints[i].lower);
+        funpackf(tfile, "Bi", &parentID);
+        if (joints[i].hasparent)
+            joints[i].parent = &joints[parentID];
+        joints[i].velocity = 0;
+        joints[i].oldposition = joints[i].position;
+    }
+
+    // read num_muscles
+    funpackf(tfile, "Bi", &num_muscles);
+
+    // allocate memory
+    if (muscles)
+        delete [] muscles; //dealloc2(muscles);
+    muscles = (Muscle*)new Muscle[num_muscles]; //malloc(sizeof(Muscle)*num_muscles);
+
+    // for each muscle...
+    for (i = 0; i < num_muscles; i++) {
+        // read info
+        funpackf(tfile, "Bf Bf Bf Bf Bf Bi Bi", &muscles[i].length, &muscles[i].targetlength, &muscles[i].minlength, &muscles[i].maxlength, &muscles[i].strength, &muscles[i].type, &muscles[i].numvertices);
+
+        // allocate memory for vertices
+        muscles[i].vertices = (int*)malloc(sizeof(int) * muscles[i].numvertices);
+
+        // read vertices
+        edit = 0;
+        for (j = 0; j < muscles[i].numvertices - edit; j++) {
+            funpackf(tfile, "Bi", &muscles[i].vertices[j + edit]);
+            if (muscles[i].vertices[j + edit] >= model[0].vertexNum) {
+                muscles[i].numvertices--;
+                edit--;
+            }
+        }
+
+        // read more info
+        funpackf(tfile, "Bb Bi", &muscles[i].visible, &parentID);
+        muscles[i].parent1 = &joints[parentID];
+        funpackf(tfile, "Bi", &parentID);
+        muscles[i].parent2 = &joints[parentID];
+    }
+
+    // read forwardjoints (?)
+    for (j = 0; j < 3; j++) {
+        funpackf(tfile, "Bi", &forwardjoints[j]);
+    }
+    // read lowforwardjoints (?)
+    for (j = 0; j < 3; j++) {
+        funpackf(tfile, "Bi", &lowforwardjoints[j]);
+    }
+
+    // ???
+    for (j = 0; j < num_muscles; j++) {
+        for (i = 0; i < muscles[j].numvertices; i++) {
+            for (int k = 0; k < num_models; k++) {
+                if (muscles[j].numvertices && muscles[j].vertices[i] < model[k].vertexNum)
+                    model[k].owner[muscles[j].vertices[i]] = j;
+            }
+        }
+    }
+
+    // calculate some stuff
+    FindForwards();
+    for (i = 0; i < num_joints; i++) {
+        joints[i].startpos = joints[i].position;
+    }
+    for (i = 0; i < num_muscles; i++) {
+        FindRotationMuscle(i, -1);
+    }
+    // this seems to use opengl purely for matrix calculations
+    for (int k = 0; k < num_models; k++) {
+        for (i = 0; i < model[k].vertexNum; i++) {
+            model[k].vertex[i] = model[k].vertex[i] - (muscles[model[k].owner[i]].parent1->position + muscles[model[k].owner[i]].parent2->position) / 2;
+            glMatrixMode(GL_MODELVIEW);
+            glPushMatrix();
+            glLoadIdentity();
+            glRotatef(muscles[model[k].owner[i]].rotate3, 0, 1, 0);
+            glRotatef(muscles[model[k].owner[i]].rotate2 - 90, 0, 0, 1);
+            glRotatef(muscles[model[k].owner[i]].rotate1 - 90, 0, 1, 0);
+            glTranslatef(model[k].vertex[i].x, model[k].vertex[i].y, model[k].vertex[i].z);
+            glGetFloatv(GL_MODELVIEW_MATRIX, M);
+            model[k].vertex[i].x = M[12] * 1;
+            model[k].vertex[i].y = M[13] * 1;
+            model[k].vertex[i].z = M[14] * 1;
+            glPopMatrix();
+        }
+        model[k].CalculateNormals(0);
+    }
+    fclose(tfile);
+
+    // load ???
+
+    tfile = Folders::openMandatoryFile( Folders::getResourcePath(lowfilename), "rb" );
+
+    // skip joints section
+
+    lSize = sizeof(num_joints);
+    fseek(tfile, lSize, SEEK_CUR);
+    for (i = 0; i < num_joints; i++) {
+        // skip joint info
+        lSize = sizeof(XYZ)
+                + sizeof(float)
+                + sizeof(float)
+                + 1 //sizeof(bool)
+                + 1 //sizeof(bool)
+                + sizeof(int)
+                + 1 //sizeof(bool)
+                + 1 //sizeof(bool)
+                + sizeof(int)
+                + sizeof(int)
+                + 1 //sizeof(bool)
+                + sizeof(int);
+        fseek(tfile, lSize, SEEK_CUR);
+
+        if (joints[i].hasparent)
+            joints[i].parent = &joints[parentID];
+        joints[i].velocity = 0;
+        joints[i].oldposition = joints[i].position;
+    }
+
+    // read num_muscles
+    funpackf(tfile, "Bi", &num_muscles);
+
+    for (i = 0; i < num_muscles; i++) {
+        // skip muscle info
+        lSize = sizeof(float)
+                + sizeof(float)
+                + sizeof(float)
+                + sizeof(float)
+                + sizeof(float)
+                + sizeof(int);
+        fseek(tfile, lSize, SEEK_CUR);
+
+        // read numverticeslow
+        funpackf(tfile, "Bi", &muscles[i].numverticeslow);
+
+        if (muscles[i].numverticeslow) {
+            // allocate memory
+            muscles[i].verticeslow = (int*)malloc(sizeof(int) * muscles[i].numverticeslow);
+
+            // read verticeslow
+            edit = 0;
+            for (j = 0; j < muscles[i].numverticeslow - edit; j++) {
+                funpackf(tfile, "Bi", &muscles[i].verticeslow[j + edit]);
+                if (muscles[i].verticeslow[j + edit] >= modellow.vertexNum) {
+                    muscles[i].numverticeslow--;
+                    edit--;
+                }
+            }
+        }
+
+        // skip more stuff
+        lSize = 1; //sizeof(bool);
+        fseek ( tfile, lSize, SEEK_CUR);
+        lSize = sizeof(int);
+        fseek ( tfile, lSize, SEEK_CUR);
+        fseek ( tfile, lSize, SEEK_CUR);
+    }
+
+    for (j = 0; j < num_muscles; j++) {
+        for (i = 0; i < muscles[j].numverticeslow; i++) {
+            if (muscles[j].verticeslow[i] < modellow.vertexNum)
+                modellow.owner[muscles[j].verticeslow[i]] = j;
+        }
+    }
+
+    // use opengl for its matrix math
+    for (i = 0; i < modellow.vertexNum; i++) {
+        modellow.vertex[i] = modellow.vertex[i] - (muscles[modellow.owner[i]].parent1->position + muscles[modellow.owner[i]].parent2->position) / 2;
+        glMatrixMode(GL_MODELVIEW);
+        glPushMatrix();
+        glLoadIdentity();
+        glRotatef(muscles[modellow.owner[i]].rotate3, 0, 1, 0);
+        glRotatef(muscles[modellow.owner[i]].rotate2 - 90, 0, 0, 1);
+        glRotatef(muscles[modellow.owner[i]].rotate1 - 90, 0, 1, 0);
+        glTranslatef(modellow.vertex[i].x, modellow.vertex[i].y, modellow.vertex[i].z);
+        glGetFloatv(GL_MODELVIEW_MATRIX, M);
+        modellow.vertex[i].x = M[12];
+        modellow.vertex[i].y = M[13];
+        modellow.vertex[i].z = M[14];
+        glPopMatrix();
+    }
+
+    modellow.CalculateNormals(0);
+
+    // load clothes
+
+    if (clothes) {
+        tfile = Folders::openMandatoryFile( Folders::getResourcePath(clothesfilename), "rb" );
+
+        // skip num_joints
+        lSize = sizeof(num_joints);
+        fseek ( tfile, lSize, SEEK_CUR);
+
+        for (i = 0; i < num_joints; i++) {
+            // skip joint info
+            lSize = sizeof(XYZ)
+                    + sizeof(float)
+                    + sizeof(float)
+                    + 1 //sizeof(bool)
+                    + 1 //sizeof(bool)
+                    + sizeof(int)
+                    + 1 //sizeof(bool)
+                    + 1 //sizeof(bool)
+                    + sizeof(int)
+                    + sizeof(int)
+                    + 1 //sizeof(bool)
+                    + sizeof(int);
+            fseek(tfile, lSize, SEEK_CUR);
+
+            if (joints[i].hasparent)
+                joints[i].parent = &joints[parentID];
+            joints[i].velocity = 0;
+            joints[i].oldposition = joints[i].position;
+        }
+
+        // read num_muscles
+        funpackf(tfile, "Bi", &num_muscles);
+
+        for (i = 0; i < num_muscles; i++) {
+            // skip muscle info
+            lSize = sizeof(float)
+                    + sizeof(float)
+                    + sizeof(float)
+                    + sizeof(float)
+                    + sizeof(float)
+                    + sizeof(int);
+            fseek(tfile, lSize, SEEK_CUR);
+
+            // read numverticesclothes
+            funpackf(tfile, "Bi", &muscles[i].numverticesclothes);
+
+            // read verticesclothes
+            if (muscles[i].numverticesclothes) {
+                muscles[i].verticesclothes = (int*)malloc(sizeof(int) * muscles[i].numverticesclothes);
+                edit = 0;
+                for (j = 0; j < muscles[i].numverticesclothes - edit; j++) {
+                    funpackf(tfile, "Bi", &muscles[i].verticesclothes[j + edit]);
+                    if (muscles[i].verticesclothes[j + edit] >= modelclothes.vertexNum) {
+                        muscles[i].numverticesclothes--;
+                        edit--;
+                    }
+                }
+            }
+
+            // skip more stuff
+            lSize = 1; //sizeof(bool);
+            fseek ( tfile, lSize, SEEK_CUR);
+            lSize = sizeof(int);
+            fseek ( tfile, lSize, SEEK_CUR);
+            fseek ( tfile, lSize, SEEK_CUR);
+        }
+
+        // ???
+        lSize = sizeof(int);
+        for (j = 0; j < num_muscles; j++) {
+            for (i = 0; i < muscles[j].numverticesclothes; i++) {
+                if (muscles[j].numverticesclothes && muscles[j].verticesclothes[i] < modelclothes.vertexNum)
+                    modelclothes.owner[muscles[j].verticesclothes[i]] = j;
+            }
+        }
+
+        // use opengl for its matrix math
+        for (i = 0; i < modelclothes.vertexNum; i++) {
+            modelclothes.vertex[i] = modelclothes.vertex[i] - (muscles[modelclothes.owner[i]].parent1->position + muscles[modelclothes.owner[i]].parent2->position) / 2;
+            glMatrixMode(GL_MODELVIEW);
+            glPushMatrix();
+            glLoadIdentity();
+            glRotatef(muscles[modelclothes.owner[i]].rotate3, 0, 1, 0);
+            glRotatef(muscles[modelclothes.owner[i]].rotate2 - 90, 0, 0, 1);
+            glRotatef(muscles[modelclothes.owner[i]].rotate1 - 90, 0, 1, 0);
+            glTranslatef(modelclothes.vertex[i].x, modelclothes.vertex[i].y, modelclothes.vertex[i].z);
+            glGetFloatv(GL_MODELVIEW_MATRIX, M);
+            modelclothes.vertex[i].x = M[12];
+            modelclothes.vertex[i].y = M[13];
+            modelclothes.vertex[i].z = M[14];
+            glPopMatrix();
+        }
+
+        modelclothes.CalculateNormals(0);
+    }
+    fclose(tfile);
+
+    for (i = 0; i < num_joints; i++) {
+        for (j = 0; j < num_joints; j++) {
+            if (joints[i].label == j)
+                jointlabels[j] = i;
+        }
+    }
+
+    free = 0;
+}
+
+Skeleton::Skeleton()
+{
+    num_joints = 0;
+
+    num_muscles = 0;
+
+    selected = 0;
+
+    memset(forwardjoints, 0, sizeof(forwardjoints));
+    // XYZ forward;
+
+    id = 0;
+
+    memset(lowforwardjoints, 0, sizeof(lowforwardjoints));
+    // XYZ lowforward;
+
+    // XYZ specialforward[5];
+    memset(jointlabels, 0, sizeof(jointlabels));
+
+    // Model model[7];
+    // Model modellow;
+    // Model modelclothes;
+    num_models = 0;
+
+    // Model drawmodel;
+    // Model drawmodellow;
+    // Model drawmodelclothes;
+
+    clothes = 0;
+    spinny = 0;
+
+    memset(skinText, 0, sizeof(skinText));
+    skinsize = 0;
+
+    checkdelay = 0;
+
+    longdead = 0;
+    broken = 0;
+
+    free = 0;
+    oldfree = 0;
+    freetime = 0;
+    freefall = 0;
+
+    joints = 0;
+    muscles = 0;
+}
+
+Skeleton::~Skeleton()
+{
+    if (muscles) {
+        delete [] muscles;
+    }
+    muscles = 0;
+
+    if (joints) {
+        delete [] joints;
+    }
+    joints = 0;
+}
+
+Muscle::Muscle()
+{
+    vertices = 0;
+    verticeslow = 0;
+    verticesclothes = 0;
+
+    numvertices = 0;
+    numverticeslow = 0;
+    numverticesclothes = 0;
+    length = 0;
+    targetlength = 0;
+    parent1 = 0;
+    parent2 = 0;
+    maxlength = 0;
+    minlength = 0;
+    type = 0;
+    visible = 0;
+    rotate1 = 0, rotate2 = 0, rotate3 = 0;
+    lastrotate1 = 0, lastrotate2 = 0, lastrotate3 = 0;
+    oldrotate1 = 0, oldrotate2 = 0, oldrotate3 = 0;
+    newrotate1 = 0, newrotate2 = 0, newrotate3 = 0;
+
+    strength = 0;
+}
+
+Muscle::~Muscle()
+{
+    dealloc2(vertices);
+    dealloc2(verticeslow);
+    dealloc2(verticesclothes);
+}
+
+#if 0
+
+// the following functions are not used anywhere
+
+/* EFFECT
+ * sets forward, lowforward, specialforward[]
+ *
+ * USES:
+ * NONE
+ */
+void Skeleton::FindForwardsfirst()
+{
+    //Find forward vectors
+    CrossProduct(joints[forwardjoints[1]].position - joints[forwardjoints[0]].position, joints[forwardjoints[2]].position - joints[forwardjoints[0]].position, &forward);
+    Normalise(&forward);
+
+    CrossProduct(joints[lowforwardjoints[1]].position - joints[lowforwardjoints[0]].position, joints[lowforwardjoints[2]].position - joints[lowforwardjoints[0]].position, &lowforward);
+    Normalise(&lowforward);
+
+    //Special forwards
+    specialforward[0] = forward;
+    specialforward[1] = forward;
+    specialforward[2] = forward;
+    specialforward[3] = forward;
+    specialforward[4] = forward;
+
+}
+
+/* EFFECT
+ *
+ * USES:
+ * NONE
+ */
+void Skeleton::Draw(int muscleview)
+{
+    static float jointcolor[4];
+
+    if (muscleview != 2) {
+        jointcolor[0] = 0;
+        jointcolor[1] = 0;
+        jointcolor[2] = .5;
+        jointcolor[3] = 1;
+    }
+
+    if (muscleview == 2) {
+        jointcolor[0] = 0;
+        jointcolor[1] = 0;
+        jointcolor[2] = 0;
+        jointcolor[3] = .5;
+    }
+    //Calc motionblur-ness
+    for (int i = 0; i < num_joints; i++) {
+        joints[i].oldposition = joints[i].position;
+        joints[i].blurred = findDistance(&joints[i].position, &joints[i].oldposition) * 100;
+        if (joints[i].blurred < 1)
+            joints[i].blurred = 1;
+    }
+
+    //Do Motionblur
+    glDepthMask(0);
+    glEnable(GL_BLEND);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    glBegin(GL_QUADS);
+    for (int i = 0; i < num_joints; i++) {
+        if (joints[i].hasparent) {
+            glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / joints[i].blurred);
+            glVertex3f(joints[i].position.x, joints[i].position.y, joints[i].position.z);
+            glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / joints[i].parent->blurred);
+            glVertex3f(joints[i].parent->position.x, joints[i].parent->position.y, joints[i].parent->position.z);
+            glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / joints[i].parent->blurred);
+            glVertex3f(joints[i].parent->oldposition.x, joints[i].parent->oldposition.y, joints[i].parent->oldposition.z);
+            glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / joints[i].blurred);
+            glVertex3f(joints[i].oldposition.x, joints[i].oldposition.y, joints[i].oldposition.z);
+        }
+    }
+    for (int i = 0; i < num_muscles; i++) {
+        if (muscles[i].type == boneconnect) {
+            glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / muscles[i].parent2->blurred);
+            glVertex3f(muscles[i].parent1->position.x, muscles[i].parent1->position.y, muscles[i].parent1->position.z);
+            glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / muscles[i].parent2->blurred);
+            glVertex3f(muscles[i].parent2->position.x, muscles[i].parent2->position.y, muscles[i].parent2->position.z);
+            glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / muscles[i].parent2->blurred);
+            glVertex3f(muscles[i].parent2->oldposition.x, muscles[i].parent2->oldposition.y, muscles[i].parent2->oldposition.z);
+            glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / muscles[i].parent1->blurred);
+            glVertex3f(muscles[i].parent1->oldposition.x, muscles[i].parent1->oldposition.y, muscles[i].parent1->oldposition.z);
+        }
+    }
+    glEnd();
+
+    glBegin(GL_LINES);
+    for (int i = 0; i < num_joints; i++) {
+        if (joints[i].hasparent) {
+            glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / joints[i].blurred);
+            glVertex3f(joints[i].position.x, joints[i].position.y, joints[i].position.z);
+            glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / joints[i].parent->blurred);
+            glVertex3f(joints[i].parent->position.x, joints[i].parent->position.y, joints[i].parent->position.z);
+        }
+    }
+    for (int i = 0; i < num_muscles; i++) {
+        if (muscles[i].type == boneconnect) {
+            glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / muscles[i].parent1->blurred);
+            glVertex3f(muscles[i].parent1->position.x, muscles[i].parent1->position.y, muscles[i].parent1->position.z);
+            glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / muscles[i].parent2->blurred);
+            glVertex3f(muscles[i].parent2->position.x, muscles[i].parent2->position.y, muscles[i].parent2->position.z);
+        }
+    }
+    glColor3f(.6, .6, 0);
+    if (muscleview == 1)
+        for (int i = 0; i < num_muscles; i++) {
+            if (muscles[i].type != boneconnect) {
+                glVertex3f(muscles[i].parent1->position.x, muscles[i].parent1->position.y, muscles[i].parent1->position.z);
+                glVertex3f(muscles[i].parent2->position.x, muscles[i].parent2->position.y, muscles[i].parent2->position.z);
+            }
+        }
+    glEnd();
+
+    if (muscleview != 2) {
+        glPointSize(3);
+        glBegin(GL_POINTS);
+        for (int i = 0; i < num_joints; i++) {
+            if (i != selected)
+                glColor4f(0, 0, .5, 1);
+            if (i == selected)
+                glColor4f(1, 1, 0, 1);
+            if (joints[i].locked && i != selected)
+                glColor4f(1, 0, 0, 1);
+            glVertex3f(joints[i].position.x, joints[i].position.y, joints[i].position.z);
+        }
+        glEnd();
+    }
+
+    //Set old position to current position
+    if (muscleview == 2)
+        for (int i = 0; i < num_joints; i++) {
+            joints[i].oldposition = joints[i].position;
+        }
+    glDepthMask(1);
+}
+
+/* EFFECT
+ *
+ * USES:
+ * NONE
+ */
+void Skeleton::AddJoint(float x, float y, float z, int which)
+{
+    if (num_joints < max_joints - 1) {
+        joints[num_joints].velocity = 0;
+        joints[num_joints].position.x = x;
+        joints[num_joints].position.y = y;
+        joints[num_joints].position.z = z;
+        joints[num_joints].mass = 1;
+        joints[num_joints].locked = 0;
+
+        joints[num_joints].hasparent = 0;
+        num_joints++;
+        if (which < num_joints && which >= 0)
+            AddMuscle(num_joints - 1, which, 0, 10, boneconnect);
+    }
+}
+
+/* EFFECT
+ *
+ * USES:
+ * NONE
+ */
+void Skeleton::DeleteJoint(int whichjoint)
+{
+    if (whichjoint < num_joints && whichjoint >= 0) {
+        joints[whichjoint].velocity = joints[num_joints - 1].velocity;
+        joints[whichjoint].position = joints[num_joints - 1].position;
+        joints[whichjoint].oldposition = joints[num_joints - 1].oldposition;
+        joints[whichjoint].hasparent = joints[num_joints - 1].hasparent;
+        joints[whichjoint].parent = joints[num_joints - 1].parent;
+        joints[whichjoint].length = joints[num_joints - 1].length;
+        joints[whichjoint].locked = joints[num_joints - 1].locked;
+        joints[whichjoint].modelnum = joints[num_joints - 1].modelnum;
+        joints[whichjoint].visible = joints[num_joints - 1].visible;
+
+        for (int i = 0; i < num_muscles; i++) {
+            while (muscles[i].parent1 == &joints[whichjoint] && i < num_muscles)DeleteMuscle(i);
+            while (muscles[i].parent2 == &joints[whichjoint] && i < num_muscles)DeleteMuscle(i);
+        }
+        for (int i = 0; i < num_muscles; i++) {
+            while (muscles[i].parent1 == &joints[num_joints - 1] && i < num_muscles)muscles[i].parent1 = &joints[whichjoint];
+            while (muscles[i].parent2 == &joints[num_joints - 1] && i < num_muscles)muscles[i].parent2 = &joints[whichjoint];
+        }
+        for (int i = 0; i < num_joints; i++) {
+            if (joints[i].parent == &joints[whichjoint])
+                joints[i].hasparent = 0;
+        }
+        for (int i = 0; i < num_joints; i++) {
+            if (joints[i].parent == &joints[num_joints - 1])
+                joints[i].parent = &joints[whichjoint];
+        }
+
+        num_joints--;
+    }
+}
+
+/* EFFECT
+ *
+ * USES:
+ * Skeleton::DeleteJoint - UNUSED
+ */
+void Skeleton::DeleteMuscle(int whichmuscle)
+{
+    if (whichmuscle < num_muscles) {
+        muscles[whichmuscle].minlength = muscles[num_muscles - 1].minlength;
+        muscles[whichmuscle].maxlength = muscles[num_muscles - 1].maxlength;
+        muscles[whichmuscle].strength = muscles[num_muscles - 1].strength;
+        muscles[whichmuscle].parent1 = muscles[num_muscles - 1].parent1;
+        muscles[whichmuscle].parent2 = muscles[num_muscles - 1].parent2;
+        muscles[whichmuscle].length = muscles[num_muscles - 1].length;
+        muscles[whichmuscle].visible = muscles[num_muscles - 1].visible;
+        muscles[whichmuscle].type = muscles[num_muscles - 1].type;
+        muscles[whichmuscle].targetlength = muscles[num_muscles - 1].targetlength;
+
+        num_muscles--;
+    }
+}
+
+/* EFFECT
+ *
+ * USES:
+ * NONE
+ */
+void Skeleton::SetJoint(float x, float y, float z, int which, int whichjoint)
+{
+    if (whichjoint < num_joints) {
+        joints[whichjoint].velocity = 0;
+        joints[whichjoint].position.x = x;
+        joints[whichjoint].position.y = y;
+        joints[whichjoint].position.z = z;
+
+        if (which >= num_joints || which < 0)
+            joints[whichjoint].hasparent = 0;
+        if (which < num_joints && which >= 0) {
+            joints[whichjoint].parent = &joints[which];
+            joints[whichjoint].hasparent = 1;
+            joints[whichjoint].length = findDistance(&joints[whichjoint].position, &joints[whichjoint].parent->position);
+        }
+    }
+}
+
+/* EFFECT
+ *
+ * USES:
+ * Skeleton::AddJoint - UNUSED
+ */
+void Skeleton::AddMuscle(int attach1, int attach2, float minlength, float maxlength, int type)
+{
+    const int max_muscles = 100; // FIXME: Probably can be dropped
+    if (num_muscles < max_muscles - 1 && attach1 < num_joints && attach1 >= 0 && attach2 < num_joints && attach2 >= 0 && attach1 != attach2) {
+        muscles[num_muscles].parent1 = &joints[attach1];
+        muscles[num_muscles].parent2 = &joints[attach2];
+        muscles[num_muscles].length = findDistance(&muscles[num_muscles].parent1->position, &muscles[num_muscles].parent2->position);
+        muscles[num_muscles].targetlength = findDistance(&muscles[num_muscles].parent1->position, &muscles[num_muscles].parent2->position);
+        muscles[num_muscles].strength = .7;
+        muscles[num_muscles].type = type;
+        muscles[num_muscles].minlength = minlength;
+        muscles[num_muscles].maxlength = maxlength;
+
+        num_muscles++;
+    }
+}
+
+/* EFFECT
+ *
+ * USES:
+ * NONE
+ */
+void Skeleton::MusclesSet()
+{
+    for (int i = 0; i < num_muscles; i++) {
+        muscles[i].length = findDistance(&muscles[i].parent1->position, &muscles[i].parent2->position);
+    }
+}
+
+/* EFFECT
+ *
+ * USES:
+ * NONE
+ */
+void Skeleton::DoBalance()
+{
+    /*XYZ newpoint;
+    newpoint=joints[0].position;
+    newpoint.x=(joints[2].position.x+joints[4].position.x)/2;
+    newpoint.z=(joints[2].position.z+joints[4].position.z)/2;
+    joints[0].velocity=joints[0].velocity+(newpoint-joints[0].position);
+    //Move child point to within certain distance of parent point
+    joints[0].position=newpoint;
+
+    MusclesSet();*/
+}
+
+#endif
+
diff --git a/Source/Animation/Skeleton.h b/Source/Animation/Skeleton.h
new file mode 100644 (file)
index 0000000..7c482f9
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+Copyright (C) 2003, 2010 - Wolfire Games
+Copyright (C) 2010-2016 - Lugaru contributors (see AUTHORS file)
+
+This file is part of Lugaru.
+
+Lugaru is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+Lugaru is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Lugaru.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SKELETON_H_
+#define _SKELETON_H_
+
+#include "Models.h"
+#include "Quaternions.h"
+
+
+/**> HEADER FILES <**/
+#include "gamegl.h"
+#include "Quaternions.h"
+#include "Objects.h"
+#include "Sprite.h"
+#include "binio.h"
+#include "Animation/Animation.h"
+
+enum bodyparts {
+    head, neck,
+    leftshoulder,  leftelbow,  leftwrist,  lefthand,
+    rightshoulder, rightelbow, rightwrist, righthand,
+    abdomen, lefthip, righthip, groin,
+    leftknee,  leftankle,  leftfoot,
+    rightknee, rightankle, rightfoot
+};
+
+class Joint
+{
+public:
+    XYZ position;
+    XYZ oldposition;
+    XYZ realoldposition;
+    XYZ velocity;
+    XYZ oldvelocity;
+    XYZ startpos;
+    float blurred;
+    float length;
+    float mass;
+    bool lower;
+    bool hasparent;
+    bool locked;
+    int modelnum;
+    bool visible;
+    Joint* parent;
+    bool sametwist;
+    int label;
+    int hasgun;
+    float delay;
+    XYZ velchange;
+
+    Joint() {
+        blurred = 0;
+        length = 0;
+        mass = 0;
+        lower = 0;
+        hasparent = 0;
+        locked = 0;
+        modelnum = 0;
+        visible = 0;
+        parent = 0;
+        sametwist = 0;
+        label = 0;
+        hasgun = 0;
+        delay = 0;
+    }
+};
+
+class Muscle
+{
+public:
+    int numvertices;
+    int* vertices;
+    int numverticeslow;
+    int* verticeslow;
+    int numverticesclothes;
+    int* verticesclothes;
+    float length;
+    float targetlength;
+    Joint* parent1;
+    Joint* parent2;
+    float maxlength;
+    float minlength;
+    int type;
+    bool visible;
+    float rotate1, rotate2, rotate3;
+    float lastrotate1, lastrotate2, lastrotate3;
+    float oldrotate1, oldrotate2, oldrotate3;
+    float newrotate1, newrotate2, newrotate3;
+
+    float strength;
+
+    Muscle();
+    ~Muscle();
+    void DoConstraint(bool spinny);
+};
+
+const int max_joints = 50;
+
+class Skeleton
+{
+public:
+    int num_joints;
+    //Joint joints[max_joints];
+    //Joint *joints;
+    Joint* joints;
+
+    int num_muscles;
+    //Muscle muscles[max_muscles];
+    //Muscle *muscles;
+    Muscle* muscles;
+
+    int selected;
+
+    int forwardjoints[3];
+    XYZ forward;
+
+    int id;
+
+    int lowforwardjoints[3];
+    XYZ lowforward;
+
+    XYZ specialforward[5];
+    int jointlabels[max_joints];
+
+    Model model[7];
+    Model modellow;
+    Model modelclothes;
+    int num_models;
+
+    Model drawmodel;
+    Model drawmodellow;
+    Model drawmodelclothes;
+
+    bool clothes;
+    bool spinny;
+
+    GLubyte skinText[512 * 512 * 3];
+    int skinsize;
+
+    float checkdelay;
+
+    float longdead;
+    bool broken;
+
+    int free;
+    int oldfree;
+    float freetime;
+    bool freefall;
+
+    void FindForwards();
+    float DoConstraints(XYZ *coords, float *scale);
+    void DoGravity(float *scale);
+    void FindRotationJoint(int which);
+    void FindRotationJointSameTwist(int which);
+    void FindRotationMuscle(int which, int animation);
+    void Load(const std::string& fileName, const std::string& lowfileName, const std::string& clothesfileName, const std::string& modelfileName, const std::string& model2fileName, const std::string& model3fileName, const std::string& model4fileName, const std::string& model5fileNamee, const std::string& model6fileName, const std::string& model7fileName, const std::string& modellowfileName, const std::string& modelclothesfileName, bool aclothes);
+
+    /*
+    // unused
+    void FindForwardsfirst();
+    void Draw(int muscleview);
+    void AddJoint(float x, float y, float z, int which);
+    void SetJoint(float x, float y, float z, int which, int whichjoint);
+    void DeleteJoint(int whichjoint);
+    void AddMuscle(int attach1, int attach2, float maxlength, float minlength, int type);
+    void DeleteMuscle(int whichmuscle);
+    void DoBalance();
+    void MusclesSet();
+    */
+
+    Skeleton();
+    ~Skeleton();
+
+private:
+    // convenience functions
+    // only for Skeleton.cpp
+    inline Joint& joint(int bodypart) { return joints[jointlabels[bodypart]]; }
+    inline XYZ& jointPos(int bodypart) { return joint(bodypart).position; }
+    inline XYZ& jointVel(int bodypart) { return joint(bodypart).velocity; }
+
+};
+
+#endif
index 4f7a2aaa1422b797386d41347a9bf31250a20d57..5526681c5900ec6c9018fe0cedc18fe1e1000f4b 100644 (file)
@@ -27,7 +27,7 @@ along with Lugaru.  If not, see <http://www.gnu.org/licenses/>.
 
 #include "Terrain.h"
 #include "Skybox.h"
-#include "Skeleton.h"
+#include "Animation/Skeleton.h"
 #include "Models.h"
 #include "Lights.h"
 #include "Person.h"
index c12904d3726a6ca6b0e94ff3930ecd316f9d5203..24a9de3e1bbdda9b83c79e5432d8945ef68a0cef 100644 (file)
@@ -20,7 +20,7 @@ along with Lugaru.  If not, see <http://www.gnu.org/licenses/>.
 
 #include "Game.h"
 #include "openal_wrapper.h"
-#include "Animation.h"
+#include "Animation/Animation.h"
 #include "Texture.h"
 #include "Utils/Folders.h"
 
@@ -628,6 +628,8 @@ void Game::InitGame()
     newscreenheight = screenheight;
 
     LoadMenu();
+
+    Animation::loadAll();
 }
 
 
@@ -819,58 +821,57 @@ void Game::LoadStuff()
 
     firstload = 0;
 
-    loadAllAnimations();
     //Fix knife stab, too lazy to do it manually
     XYZ moveamount;
     moveamount = 0;
     moveamount.z = 2;
     for (i = 0; i < Person::players[0]->skeleton.num_joints; i++) {
-        for (j = 0; j < animation[knifesneakattackanim].numframes; j++) {
-            animation[knifesneakattackanim].position[i][j] += moveamount;
+        for (j = 0; j < Animation::animations[knifesneakattackanim].numframes; j++) {
+            Animation::animations[knifesneakattackanim].position[i][j] += moveamount;
         }
     }
 
     LoadingScreen();
 
     for (i = 0; i < Person::players[0]->skeleton.num_joints; i++) {
-        for (j = 0; j < animation[knifesneakattackedanim].numframes; j++) {
-            animation[knifesneakattackedanim].position[i][j] += moveamount;
+        for (j = 0; j < Animation::animations[knifesneakattackedanim].numframes; j++) {
+            Animation::animations[knifesneakattackedanim].position[i][j] += moveamount;
         }
     }
 
     LoadingScreen();
 
     for (i = 0; i < Person::players[0]->skeleton.num_joints; i++) {
-        animation[dead1anim].position[i][1] = animation[dead1anim].position[i][0];
-        animation[dead2anim].position[i][1] = animation[dead2anim].position[i][0];
-        animation[dead3anim].position[i][1] = animation[dead3anim].position[i][0];
-        animation[dead4anim].position[i][1] = animation[dead4anim].position[i][0];
+        Animation::animations[dead1anim].position[i][1] = Animation::animations[dead1anim].position[i][0];
+        Animation::animations[dead2anim].position[i][1] = Animation::animations[dead2anim].position[i][0];
+        Animation::animations[dead3anim].position[i][1] = Animation::animations[dead3anim].position[i][0];
+        Animation::animations[dead4anim].position[i][1] = Animation::animations[dead4anim].position[i][0];
     }
-    animation[dead1anim].speed[0] = 0.001;
-    animation[dead2anim].speed[0] = 0.001;
-    animation[dead3anim].speed[0] = 0.001;
-    animation[dead4anim].speed[0] = 0.001;
+    Animation::animations[dead1anim].speed[0] = 0.001;
+    Animation::animations[dead2anim].speed[0] = 0.001;
+    Animation::animations[dead3anim].speed[0] = 0.001;
+    Animation::animations[dead4anim].speed[0] = 0.001;
 
-    animation[dead1anim].speed[1] = 0.001;
-    animation[dead2anim].speed[1] = 0.001;
-    animation[dead3anim].speed[1] = 0.001;
-    animation[dead4anim].speed[1] = 0.001;
+    Animation::animations[dead1anim].speed[1] = 0.001;
+    Animation::animations[dead2anim].speed[1] = 0.001;
+    Animation::animations[dead3anim].speed[1] = 0.001;
+    Animation::animations[dead4anim].speed[1] = 0.001;
 
     for (i = 0; i < Person::players[0]->skeleton.num_joints; i++) {
-        for (j = 0; j < animation[swordsneakattackanim].numframes; j++) {
-            animation[swordsneakattackanim].position[i][j] += moveamount;
+        for (j = 0; j < Animation::animations[swordsneakattackanim].numframes; j++) {
+            Animation::animations[swordsneakattackanim].position[i][j] += moveamount;
         }
     }
     LoadingScreen();
-    for (j = 0; j < animation[swordsneakattackanim].numframes; j++) {
-        animation[swordsneakattackanim].weapontarget[j] += moveamount;
+    for (j = 0; j < Animation::animations[swordsneakattackanim].numframes; j++) {
+        Animation::animations[swordsneakattackanim].weapontarget[j] += moveamount;
     }
 
     LoadingScreen();
 
     for (i = 0; i < Person::players[0]->skeleton.num_joints; i++) {
-        for (j = 0; j < animation[swordsneakattackedanim].numframes; j++) {
-            animation[swordsneakattackedanim].position[i][j] += moveamount;
+        for (j = 0; j < Animation::animations[swordsneakattackedanim].numframes; j++) {
+            Animation::animations[swordsneakattackedanim].position[i][j] += moveamount;
         }
     }
 
index df0bc200ee2a9d762ea0bd38adc287538ebb7eb7..da2291fc3e6dfe989c8534afadf8848b50174d58 100644 (file)
@@ -38,7 +38,7 @@ along with Lugaru.  If not, see <http://www.gnu.org/licenses/>.
 #include "openal_wrapper.h"
 #include "Settings.h"
 #include "Input.h"
-#include "Animation.h"
+#include "Animation/Animation.h"
 #include "Awards.h"
 #include "Menu.h"
 #include "ConsoleCmds.h"
@@ -827,7 +827,7 @@ void Game::Loadlevel(const std::string& name)
     hostiletime = 0;
     won = 0;
 
-    animation[bounceidleanim].Load("Idle", middleheight, neutral);
+    //~ Animation::animations[bounceidleanim].Load("Idle", middleheight, neutral);
 
     Dialog::dialogs.clear();
 
@@ -1159,7 +1159,7 @@ void Game::Loadlevel(const std::string& name)
             Person::players[i]->proportionlegs.z = 0;
         }
 
-        Person::players[i]->tempanimation.Load("Tempanim", 0, 0);
+        Person::players[i]->tempanimation = Animation("Tempanim", 0, 0);
 
         if (i == 0) {
             Person::players[i]->headmorphness = 0;
@@ -1694,7 +1694,7 @@ void doTutorial()
                 tutorialsuccess = 1;
             break;
         case 28:
-            if (animation[Person::players[0]->animTarget].attack == reversed && Person::players[0]->feint)
+            if (Animation::animations[Person::players[0]->animTarget].attack == reversed && Person::players[0]->feint)
                 tutorialsuccess = 1;
             break;
         case 29:
@@ -1706,15 +1706,15 @@ void doTutorial()
             }
             break;
         case 33:
-            if (animation[Person::players[0]->animTarget].attack == reversal)
+            if (Animation::animations[Person::players[0]->animTarget].attack == reversal)
                 tutorialsuccess = 1;
             break;
         case 34:
-            if (animation[Person::players[0]->animTarget].attack == reversal)
+            if (Animation::animations[Person::players[0]->animTarget].attack == reversal)
                 tutorialsuccess = 1;
             break;
         case 35:
-            if (animation[Person::players[0]->animTarget].attack == reversal) {
+            if (Animation::animations[Person::players[0]->animTarget].attack == reversal) {
                 tutorialsuccess = 1;
                 reversaltrain = 0;
                 cananger = 0;
@@ -1734,15 +1734,15 @@ void doTutorial()
                 tutorialsuccess = 1;
             break;
         case 44:
-            if (animation[Person::players[0]->animTarget].attack == reversal)
+            if (Animation::animations[Person::players[0]->animTarget].attack == reversal)
                 tutorialsuccess = 1;
             break;
         case 45:
-            if (animation[Person::players[0]->animTarget].attack == reversal)
+            if (Animation::animations[Person::players[0]->animTarget].attack == reversal)
                 tutorialsuccess = 1;
             break;
         case 46:
-            if (animation[Person::players[0]->animTarget].attack == reversal)
+            if (Animation::animations[Person::players[0]->animTarget].attack == reversal)
                 tutorialsuccess = 1;
             break;
         case 49:
@@ -2238,7 +2238,7 @@ void doDebugKeys()
                     Person::players.back()->proportionlegs.z = 0;
                 }
 
-                Person::players.back()->tempanimation.Load("Tempanim", 0, 0);
+                Person::players.back()->tempanimation = Animation("Tempanim", 0, 0);
 
                 Person::players.back()->damagetolerance = 200;
 
@@ -2424,7 +2424,7 @@ void doJumpReversals()
                     if (Person::players[i]->animTarget == jumpupanim &&
                             Person::players[k]->animTarget != getupfrombackanim &&
                             Person::players[k]->animTarget != getupfromfrontanim &&
-                            animation[Person::players[k]->animTarget].height == middleheight &&
+                            Animation::animations[Person::players[k]->animTarget].height == middleheight &&
                             normaldotproduct(Person::players[i]->velocity, Person::players[k]->coords - Person::players[i]->coords) < 0 &&
                             ((Person::players[k]->aitype == playercontrolled && Person::players[k]->attackkeydown) ||
                              Person::players[k]->aitype != playercontrolled)) {
@@ -2463,7 +2463,7 @@ void doJumpReversals()
                     if (Person::players[k]->animTarget == jumpupanim &&
                             Person::players[i]->animTarget != getupfrombackanim &&
                             Person::players[i]->animTarget != getupfromfrontanim &&
-                            animation[Person::players[i]->animTarget].height == middleheight &&
+                            Animation::animations[Person::players[i]->animTarget].height == middleheight &&
                             normaldotproduct(Person::players[k]->velocity, Person::players[i]->coords - Person::players[k]->coords) < 0 &&
                             ((Person::players[i]->aitype == playercontrolled && Person::players[i]->attackkeydown) ||
                              Person::players[i]->aitype != playercontrolled)) {
@@ -2531,7 +2531,7 @@ void doAerialAcrobatics()
                 Person::players[k]->animTarget == backhandspringanim ||
                 Person::players[k]->animTarget == dodgebackanim ||
                 Person::players[k]->animTarget == rollanim ||
-                (animation[Person::players[k]->animTarget].attack &&
+                (Animation::animations[Person::players[k]->animTarget].attack &&
                  Person::players[k]->animTarget != rabbitkickanim &&
                  (Person::players[k]->animTarget != crouchstabanim || Person::players[k]->hasvictim) &&
                  (Person::players[k]->animTarget != swordgroundstabanim || Person::players[k]->hasvictim))) {
@@ -2682,7 +2682,7 @@ void doAerialAcrobatics()
 
                         if (Person::players[k]->animTarget == jumpdownanim || Person::players[k]->isFlip()) {
                             //flipped into a rock
-                            if (Person::players[k]->isFlip() && animation[Person::players[k]->animTarget].label[Person::players[k]->frameTarget] == 7)
+                            if (Person::players[k]->isFlip() && Animation::animations[Person::players[k]->animTarget].label[Person::players[k]->frameTarget] == 7)
                                 Person::players[k]->RagDoll(0);
 
                             if (Person::players[k]->animTarget == jumpupanim) {
@@ -2960,7 +2960,7 @@ void doAttacks()
                     }
                 }
                 //attack
-                if (!animation[Person::players[k]->animTarget].attack &&
+                if (!Animation::animations[Person::players[k]->animTarget].attack &&
                         !Person::players[k]->backkeydown &&
                         (Person::players[k]->isIdle() ||
                          Person::players[k]->isRun() ||
@@ -2975,7 +2975,7 @@ void doAttacks()
                             if (i == k || !(k == 0 || i == 0))
                                 continue;
                             if (!Person::players[k]->hasvictim)
-                                if (animation[Person::players[k]->animTarget].attack != reversal) {
+                                if (Animation::animations[Person::players[k]->animTarget].attack != reversal) {
                                     //choose an attack
                                     const float distance = distsq(&Person::players[k]->coords, &Person::players[i]->coords);
                                     if (distance < 4.5 &&
@@ -2988,7 +2988,7 @@ void doAttacks()
                                             Person::players[i]->animTarget != getupfrombackanim &&
                                             (Person::players[i]->animTarget != staggerbackhighanim &&
                                              (Person::players[i]->animTarget != staggerbackhardanim ||
-                                              animation[staggerbackhardanim].label[Person::players[i]->frameTarget] == 6)) &&
+                                              Animation::animations[staggerbackhardanim].label[Person::players[i]->frameTarget] == 6)) &&
                                             Person::players[i]->animTarget != jumpdownanim &&
                                             Person::players[i]->animTarget != jumpupanim &&
                                             Person::players[i]->animTarget != getupfromfrontanim) {
@@ -2998,11 +2998,11 @@ void doAttacks()
                                             //sweep
                                             if (distance < 2.5 * sq(Person::players[k]->scale * 5) &&
                                                     Person::players[k]->crouchkeydown &&
-                                                    animation[Person::players[i]->animTarget].height != lowheight)
+                                                    Animation::animations[Person::players[i]->animTarget].height != lowheight)
                                                 Person::players[k]->animTarget = sweepanim;
                                             //winduppunch
                                             else if (distance < 1.5 * sq(Person::players[k]->scale * 5) &&
-                                                     animation[Person::players[i]->animTarget].height != lowheight &&
+                                                     Animation::animations[Person::players[i]->animTarget].height != lowheight &&
                                                      !Person::players[k]->forwardkeydown &&
                                                      !Person::players[k]->leftkeydown &&
                                                      !Person::players[k]->rightkeydown &&
@@ -3012,7 +3012,7 @@ void doAttacks()
                                                 Person::players[k]->animTarget = winduppunchanim;
                                             //upunch
                                             else if (distance < 2.5 * sq(Person::players[k]->scale * 5) &&
-                                                     animation[Person::players[i]->animTarget].height != lowheight &&
+                                                     Animation::animations[Person::players[i]->animTarget].height != lowheight &&
                                                      !Person::players[k]->forwardkeydown &&
                                                      !Person::players[k]->leftkeydown &&
                                                      !Person::players[k]->rightkeydown &&
@@ -3027,7 +3027,7 @@ void doAttacks()
                                                 Person::players[k]->animTarget = knifefollowanim;
                                             //knifeslashstart
                                             else if (distance < 2.5 * sq(Person::players[k]->scale * 5) &&
-                                                     animation[Person::players[i]->animTarget].height != lowheight &&
+                                                     Animation::animations[Person::players[i]->animTarget].height != lowheight &&
                                                      !Person::players[k]->forwardkeydown &&
                                                      !Person::players[k]->leftkeydown &&
                                                      !Person::players[k]->rightkeydown &&
@@ -3037,14 +3037,14 @@ void doAttacks()
                                                 Person::players[k]->animTarget = knifeslashstartanim;
                                             //swordslash
                                             else if (distance < 4.5 * sq(Person::players[k]->scale * 5) &&
-                                                     animation[Person::players[i]->animTarget].height != lowheight &&
+                                                     Animation::animations[Person::players[i]->animTarget].height != lowheight &&
                                                      !Person::players[k]->crouchkeydown &&
                                                      attackweapon == sword &&
                                                      Person::players[k]->weaponmissdelay <= 0)
                                                 Person::players[k]->animTarget = swordslashanim;
                                             //staffhit
                                             else if (distance < 4.5 * sq(Person::players[k]->scale * 5) &&
-                                                     animation[Person::players[i]->animTarget].height != lowheight &&
+                                                     Animation::animations[Person::players[i]->animTarget].height != lowheight &&
                                                      !Person::players[k]->crouchkeydown &&
                                                      attackweapon == staff &&
                                                      Person::players[k]->weaponmissdelay <= 0 &&
@@ -3054,36 +3054,36 @@ void doAttacks()
                                                 Person::players[k]->animTarget = staffhitanim;
                                             //staffspinhit
                                             else if (distance < 4.5 * sq(Person::players[k]->scale * 5) &&
-                                                     animation[Person::players[i]->animTarget].height != lowheight &&
+                                                     Animation::animations[Person::players[i]->animTarget].height != lowheight &&
                                                      !Person::players[k]->crouchkeydown &&
                                                      attackweapon == staff &&
                                                      Person::players[k]->weaponmissdelay <= 0)
                                                 Person::players[k]->animTarget = staffspinhitanim;
                                             //spinkick
                                             else if (distance < 2.5 * sq(Person::players[k]->scale * 5) &&
-                                                     animation[Person::players[i]->animTarget].height != lowheight)
+                                                     Animation::animations[Person::players[i]->animTarget].height != lowheight)
                                                 Person::players[k]->animTarget = spinkickanim;
                                             //lowkick
                                             else if (distance < 2.5 * sq(Person::players[k]->scale * 5) &&
-                                                     animation[Person::players[i]->animTarget].height == lowheight &&
-                                                     animation[Person::players[k]->animTarget].attack != normalattack)
+                                                     Animation::animations[Person::players[i]->animTarget].height == lowheight &&
+                                                     Animation::animations[Person::players[k]->animTarget].attack != normalattack)
                                                 Person::players[k]->animTarget = lowkickanim;
                                         } else { //AI player
                                             if (distance < 4.5 * sq(Person::players[k]->scale * 5)) {
                                                 randattack = abs(Random() % 5);
                                                 if (!attackweapon && distance < 2.5 * sq(Person::players[k]->scale * 5)) {
                                                     //sweep
-                                                    if (randattack == 0 && animation[Person::players[i]->animTarget].height != lowheight)
+                                                    if (randattack == 0 && Animation::animations[Person::players[i]->animTarget].height != lowheight)
                                                         Person::players[k]->animTarget = sweepanim;
                                                     //upunch
-                                                    else if (randattack == 1 && animation[Person::players[i]->animTarget].height != lowheight &&
+                                                    else if (randattack == 1 && Animation::animations[Person::players[i]->animTarget].height != lowheight &&
                                                              !attackweapon)
                                                         Person::players[k]->animTarget = upunchanim;
                                                     //spinkick
-                                                    else if (randattack == 2 && animation[Person::players[i]->animTarget].height != lowheight)
+                                                    else if (randattack == 2 && Animation::animations[Person::players[i]->animTarget].height != lowheight)
                                                         Person::players[k]->animTarget = spinkickanim;
                                                     //lowkick
-                                                    else if (animation[Person::players[i]->animTarget].height == lowheight)
+                                                    else if (Animation::animations[Person::players[i]->animTarget].height == lowheight)
                                                         Person::players[k]->animTarget = lowkickanim;
                                                 }
                                                 if (attackweapon) {
@@ -3091,7 +3091,7 @@ void doAttacks()
                                                     if ((tutoriallevel != 1 || !attackweapon) &&
                                                             distance < 2.5 * sq(Person::players[k]->scale * 5) &&
                                                             randattack == 0 &&
-                                                            animation[Person::players[i]->animTarget].height != lowheight)
+                                                            Animation::animations[Person::players[i]->animTarget].height != lowheight)
                                                         Person::players[k]->animTarget = sweepanim;
                                                     //knifeslashstart
                                                     else if (distance < 2.5 * sq(Person::players[k]->scale * 5) &&
@@ -3125,12 +3125,12 @@ void doAttacks()
                                                     else if ((tutoriallevel != 1 || !attackweapon) &&
                                                              distance < 2.5 * sq(Person::players[k]->scale * 5) &&
                                                              randattack == 1 &&
-                                                             animation[Person::players[i]->animTarget].height != lowheight)
+                                                             Animation::animations[Person::players[i]->animTarget].height != lowheight)
                                                         Person::players[k]->animTarget = spinkickanim;
                                                     //lowkick
                                                     else if (distance < 2.5 * sq(Person::players[k]->scale * 5) &&
-                                                             animation[Person::players[i]->animTarget].height == lowheight &&
-                                                             animation[Person::players[k]->animTarget].attack != normalattack)
+                                                             Animation::animations[Person::players[i]->animTarget].height == lowheight &&
+                                                             Animation::animations[Person::players[k]->animTarget].attack != normalattack)
                                                         Person::players[k]->animTarget = lowkickanim;
                                                 }
                                             }
@@ -3195,7 +3195,7 @@ void doAttacks()
                                             Person::players[i]->targetyaw = Person::players[i]->yaw;
                                         }
                                     }
-                                    if (animation[Person::players[k]->animTarget].attack == normalattack &&
+                                    if (Animation::animations[Person::players[k]->animTarget].attack == normalattack &&
                                             Person::players[k]->victim == Person::players[i] &&
                                             (!Person::players[i]->skeleton.free)) {
                                         oldattackkey = 1;
@@ -3245,7 +3245,7 @@ void doAttacks()
                             if (i == k)
                                 continue;
                             if ((playerrealattackkeydown || Person::players[i]->dead || !hasstaff) &&
-                                    animation[Person::players[k]->animTarget].attack == neutral) {
+                                    Animation::animations[Person::players[k]->animTarget].attack == neutral) {
                                 const float distance = distsq(&Person::players[k]->coords, &Person::players[i]->coords);
                                 if (!Person::players[i]->dead || !realthreat || (!attackweapon && Person::players[k]->crouchkeydown))
                                     if (Person::players[i]->skeleton.free)
@@ -3324,7 +3324,7 @@ void doAttacks()
                                                     }
                                                 }
                                         }
-                                if (animation[Person::players[k]->animTarget].attack == normalattack &&
+                                if (Animation::animations[Person::players[k]->animTarget].attack == normalattack &&
                                         Person::players[k]->victim == Person::players[i] &&
                                         (!Person::players[i]->skeleton.free ||
                                          Person::players[k]->animTarget == killanim ||
@@ -3392,7 +3392,7 @@ void doAttacks()
                                   !Person::players[k]->victim->skeleton.free &&
                                   Person::players[k]->victim->animTarget != getupfrombackanim &&
                                   Person::players[k]->victim->animTarget != getupfromfrontanim &&
-                                  animation[Person::players[k]->victim->animTarget].height != lowheight &&
+                                  Animation::animations[Person::players[k]->victim->animTarget].height != lowheight &&
                                   Person::players[k]->aitype != playercontrolled && //wat???
                                   normaldotproduct(Person::players[k]->facing, Person::players[k]->victim->coords - Person::players[k]->coords) > 0 &&
                                   Person::players[k]->rabbitkickenabled) ||
@@ -3401,7 +3401,7 @@ void doAttacks()
                             Person::players[k]->setAnimation(rabbitkickanim);
                         }
                     //update counts
-                    if (animation[Person::players[k]->animTarget].attack && k == 0) {
+                    if (Animation::animations[Person::players[k]->animTarget].attack && k == 0) {
                         numattacks++;
                         switch (attackweapon) {
                         case 0:
@@ -3432,14 +3432,14 @@ void doPlayerCollisions()
         for (unsigned k = 0; k < Person::players.size(); k++)
             for (unsigned i = k + 1; i < Person::players.size(); i++) {
                 //neither player is part of a reversal
-                if ((animation[Person::players[i]->animTarget].attack != reversed &&
-                        animation[Person::players[i]->animTarget].attack != reversal &&
-                        animation[Person::players[k]->animTarget].attack != reversed &&
-                        animation[Person::players[k]->animTarget].attack != reversal) || (i != 0 && k != 0))
-                    if ((animation[Person::players[i]->animCurrent].attack != reversed &&
-                            animation[Person::players[i]->animCurrent].attack != reversal &&
-                            animation[Person::players[k]->animCurrent].attack != reversed &&
-                            animation[Person::players[k]->animCurrent].attack != reversal) || (i != 0 && k != 0))
+                if ((Animation::animations[Person::players[i]->animTarget].attack != reversed &&
+                        Animation::animations[Person::players[i]->animTarget].attack != reversal &&
+                        Animation::animations[Person::players[k]->animTarget].attack != reversed &&
+                        Animation::animations[Person::players[k]->animTarget].attack != reversal) || (i != 0 && k != 0))
+                    if ((Animation::animations[Person::players[i]->animCurrent].attack != reversed &&
+                            Animation::animations[Person::players[i]->animCurrent].attack != reversal &&
+                            Animation::animations[Person::players[k]->animCurrent].attack != reversed &&
+                            Animation::animations[Person::players[k]->animCurrent].attack != reversal) || (i != 0 && k != 0))
                         //neither is sleeping
                         if (Person::players[i]->howactive <= typesleeping && Person::players[k]->howactive <= typesleeping)
                             if (Person::players[i]->howactive != typesittingwall && Person::players[k]->howactive != typesittingwall)
@@ -3519,16 +3519,16 @@ void doPlayerCollisions()
                                                                                 k == 0 && findLengthfast(&rotatetarget) > 50 && Person::players[0]->rabbitkickragdoll) &&
                                                                                 normaldotproduct(rotatetarget, Person::players[k]->coords - Person::players[i]->coords) > 0) &&
                                                                                 (k == 0 ||
-                                                                                 k != 0 && Person::players[i]->skeleton.oldfree == 1 && animation[Person::players[k]->animCurrent].attack == neutral ||
-                                                                                 /*i!=0&&*/Person::players[k]->skeleton.oldfree == 1 && animation[Person::players[i]->animCurrent].attack == neutral)) ||
+                                                                                 k != 0 && Person::players[i]->skeleton.oldfree == 1 && Animation::animations[Person::players[k]->animCurrent].attack == neutral ||
+                                                                                 /*i!=0&&*/Person::players[k]->skeleton.oldfree == 1 && Animation::animations[Person::players[i]->animCurrent].attack == neutral)) ||
                                                                                 (Person::players[i]->animTarget == jumpupanim || Person::players[i]->animTarget == jumpdownanim || Person::players[i]->isFlip()) &&
                                                                                 (Person::players[k]->animTarget == jumpupanim || Person::players[k]->animTarget == jumpdownanim || Person::players[k]->isFlip()) &&
                                                                                 k == 0 && !Person::players[i]->skeleton.oldfree && !Person::players[k]->skeleton.oldfree) {
                                                                             //If hit by body
                                                                             if (     (i != 0 || Person::players[i]->skeleton.free) &&
                                                                                      (k != 0 || Person::players[k]->skeleton.free) ||
-                                                                                     (animation[Person::players[i]->animTarget].height == highheight &&
-                                                                                      animation[Person::players[k]->animTarget].height == highheight)) {
+                                                                                     (Animation::animations[Person::players[i]->animTarget].height == highheight &&
+                                                                                      Animation::animations[Person::players[k]->animTarget].height == highheight)) {
                                                                                 if (tutoriallevel != 1) {
                                                                                     emit_sound_at(heavyimpactsound, Person::players[i]->coords);
                                                                                 }
@@ -3553,10 +3553,10 @@ void doPlayerCollisions()
 
                                                                             }
                                                                         }
-                                                                    if (     (animation[Person::players[i]->animTarget].attack == neutral ||
-                                                                              animation[Person::players[i]->animTarget].attack == normalattack) &&
-                                                                             (animation[Person::players[k]->animTarget].attack == neutral ||
-                                                                              animation[Person::players[k]->animTarget].attack == normalattack)) {
+                                                                    if (     (Animation::animations[Person::players[i]->animTarget].attack == neutral ||
+                                                                              Animation::animations[Person::players[i]->animTarget].attack == normalattack) &&
+                                                                             (Animation::animations[Person::players[k]->animTarget].attack == neutral ||
+                                                                              Animation::animations[Person::players[k]->animTarget].attack == normalattack)) {
                                                                         //If bumped
                                                                         if (Person::players[i]->skeleton.oldfree == 0 && Person::players[k]->skeleton.oldfree == 0) {
                                                                             if (distsq(&Person::players[k]->coords, &Person::players[i]->coords) < .5 * sq((Person::players[i]->scale + Person::players[k]->scale) * 2.5)) {
@@ -3777,12 +3777,12 @@ void doAI(unsigned i)
                     distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 400 &&
                     Person::players[i]->occluded < 25) {
                 if (distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 12 &&
-                        animation[Person::players[0]->animTarget].height != lowheight &&
+                        Animation::animations[Person::players[0]->animTarget].height != lowheight &&
                         !editorenabled &&
                         (Person::players[0]->coords.y < Person::players[i]->coords.y + 5 || Person::players[0]->onterrain))
                     Person::players[i]->aitype = attacktypecutoff;
                 if (distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 30 &&
-                        animation[Person::players[0]->animTarget].height == highheight &&
+                        Animation::animations[Person::players[0]->animTarget].height == highheight &&
                         !editorenabled)
                     Person::players[i]->aitype = attacktypecutoff;
 
@@ -3790,7 +3790,7 @@ void doAI(unsigned i)
                     Person::players[i]->losupdatedelay = .2;
                     for (unsigned j = 0; j < Person::players.size(); j++)
                         if (j == 0 || Person::players[j]->skeleton.free || Person::players[j]->aitype != passivetype)
-                            if (abs(Random() % 2) || animation[Person::players[j]->animTarget].height != lowheight || j != 0)
+                            if (abs(Random() % 2) || Animation::animations[Person::players[j]->animTarget].height != lowheight || j != 0)
                                 if (distsq(&Person::players[i]->coords, &Person::players[j]->coords) < 400)
                                     if (normaldotproduct(Person::players[i]->facing, Person::players[j]->coords - Person::players[i]->coords) > 0)
                                         if (Person::players[j]->coords.y < Person::players[i]->coords.y + 5 || Person::players[j]->onterrain)
@@ -3900,10 +3900,10 @@ void doAI(unsigned i)
                     distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 400 &&
                     Person::players[i]->occluded < 25) {
                 if (distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 12 &&
-                        animation[Person::players[0]->animTarget].height != lowheight && !editorenabled)
+                        Animation::animations[Person::players[0]->animTarget].height != lowheight && !editorenabled)
                     Person::players[i]->aitype = attacktypecutoff;
                 if (distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 30 &&
-                        animation[Person::players[0]->animTarget].height == highheight && !editorenabled)
+                        Animation::animations[Person::players[0]->animTarget].height == highheight && !editorenabled)
                     Person::players[i]->aitype = attacktypecutoff;
 
                 //wolf smell
@@ -3934,7 +3934,7 @@ void doAI(unsigned i)
                     Person::players[i]->losupdatedelay = .2;
                     for (unsigned j = 0; j < Person::players.size(); j++) {
                         if (j == 0 || Person::players[j]->skeleton.free || Person::players[j]->aitype != passivetype) {
-                            if (abs(Random() % 2) || animation[Person::players[j]->animTarget].height != lowheight || j != 0)
+                            if (abs(Random() % 2) || Animation::animations[Person::players[j]->animTarget].height != lowheight || j != 0)
                                 if (distsq(&Person::players[i]->coords, &Person::players[j]->coords) < 400)
                                     if (normaldotproduct(Person::players[i]->facing, Person::players[j]->coords - Person::players[i]->coords) > 0)
                                         if ((-1 == checkcollide(
@@ -3946,7 +3946,7 @@ void doAI(unsigned i)
                                                 (Person::players[j]->animTarget == hanganim &&
                                                  normaldotproduct(Person::players[j]->facing, Person::players[i]->coords - Person::players[j]->coords) < 0)) {
                                             Person::players[i]->lastseentime -= .2;
-                                            if (j == 0 && animation[Person::players[j]->animTarget].height == lowheight)
+                                            if (j == 0 && Animation::animations[Person::players[j]->animTarget].height == lowheight)
                                                 Person::players[i]->lastseentime -= .4;
                                             else
                                                 Person::players[i]->lastseentime -= .6;
@@ -4068,11 +4068,11 @@ void doAI(unsigned i)
                     Person::players[i]->occluded < 2 &&
                     ((tutoriallevel != 1 || cananger) && hostile)) {
                 Person::players[i]->losupdatedelay = .2;
-                if (distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 4 && animation[Person::players[i]->animTarget].height != lowheight) {
+                if (distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 4 && Animation::animations[Person::players[i]->animTarget].height != lowheight) {
                     Person::players[i]->aitype = attacktypecutoff;
                     Person::players[i]->lastseentime = 1;
                 }
-                if (abs(Random() % 2) || animation[Person::players[i]->animTarget].height != lowheight)
+                if (abs(Random() % 2) || Animation::animations[Person::players[i]->animTarget].height != lowheight)
                     //TODO: factor out canSeePlayer()
                     if (distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 400)
                         if (normaldotproduct(Person::players[i]->facing, Person::players[0]->coords - Person::players[i]->coords) > 0)
@@ -4350,7 +4350,7 @@ void doAI(unsigned i)
                         }
             //dodge/reverse walljump kicks
             if (Person::players[i]->damage < Person::players[i]->damagetolerance / 2)
-                if (animation[Person::players[i]->animTarget].height != highheight)
+                if (Animation::animations[Person::players[i]->animTarget].height != highheight)
                     if (Person::players[i]->damage < Person::players[i]->damagetolerance * .5 &&
                             ((Person::players[0]->animTarget == walljumprightkickanim ||
                               Person::players[0]->animTarget == walljumpleftkickanim) &&
@@ -4388,7 +4388,7 @@ void doAI(unsigned i)
                 }
             //lose sight of player in the air (?)
             if (Person::players[0]->coords.y > Person::players[i]->coords.y + 5 &&
-                    animation[Person::players[0]->animTarget].height != highheight &&
+                    Animation::animations[Person::players[0]->animTarget].height != highheight &&
                     !Person::players[0]->onterrain) {
                 Person::players[i]->aitype = pathfindtype;
                 Person::players[i]->finalfinaltarget = Person::players[i]->waypoints[Person::players[i]->waypoint];
@@ -4401,7 +4401,7 @@ void doAI(unsigned i)
             }
             //it's time to think (?)
             if (Person::players[i]->aiupdatedelay < 0 &&
-                    !animation[Person::players[i]->animTarget].attack &&
+                    !Animation::animations[Person::players[i]->animTarget].attack &&
                     Person::players[i]->animTarget != staggerbackhighanim &&
                     Person::players[i]->animTarget != staggerbackhardanim &&
                     Person::players[i]->animTarget != backhandspringanim &&
@@ -4550,7 +4550,7 @@ void doAI(unsigned i)
                         Person::players[i]->lastseentime = 1;
             }
         }
-        if (animation[Person::players[0]->animTarget].height == highheight &&
+        if (Animation::animations[Person::players[0]->animTarget].height == highheight &&
                 (Person::players[i]->aitype == attacktypecutoff ||
                  Person::players[i]->aitype == searchtype))
             if (Person::players[0]->coords.y > terrain.getHeight(Person::players[0]->coords.x, Person::players[0]->coords.z) + 10) {
@@ -5427,7 +5427,7 @@ void Game::Tick()
                 talkdelay = 1;
             talkdelay -= multiplier;
 
-            if (talkdelay <= 0 && !Dialog::inDialog() && animation[Person::players[0]->animTarget].height != highheight) {
+            if (talkdelay <= 0 && !Dialog::inDialog() && Animation::animations[Person::players[0]->animTarget].height != highheight) {
                 for (int i = 0; i < Dialog::dialogs.size(); i++) {
                     Dialog::dialogs[i].tick(i);
                 }
@@ -5782,7 +5782,7 @@ void Game::Tick()
                     oldtargetyaw = Person::players[i]->targetyaw;
                     if (i == 0 && !Dialog::inDialog()) {
                         //TODO: refactor repetitive code
-                        if (!animation[Person::players[0]->animTarget].attack &&
+                        if (!Animation::animations[Person::players[0]->animTarget].attack &&
                                 Person::players[0]->animTarget != staggerbackhighanim &&
                                 Person::players[0]->animTarget != staggerbackhardanim &&
                                 Person::players[0]->animTarget != crouchremoveknifeanim &&
@@ -5814,7 +5814,7 @@ void Game::Tick()
                         Person::players[i]->targetheadpitch = pitch;
                     }
                     if (i != 0 && Person::players[i]->aitype == playercontrolled && !Dialog::inDialog()) {
-                        if (!animation[Person::players[i]->animTarget].attack &&
+                        if (!Animation::animations[Person::players[i]->animTarget].attack &&
                                 Person::players[i]->animTarget != staggerbackhighanim &&
                                 Person::players[i]->animTarget != staggerbackhardanim &&
                                 Person::players[i]->animTarget != crouchremoveknifeanim &&
@@ -5884,7 +5884,7 @@ void Game::Tick()
 
                     doAI(i);
 
-                    if (animation[Person::players[i]->animTarget].attack == reversed) {
+                    if (Animation::animations[Person::players[i]->animTarget].attack == reversed) {
                         //Person::players[i]->targetyaw=Person::players[i]->yaw;
                         Person::players[i]->forwardkeydown = 0;
                         Person::players[i]->leftkeydown = 0;
@@ -5929,7 +5929,7 @@ void Game::Tick()
                             Person::players[i]->aitype == attacktypecutoff &&
                             !Person::players[i]->dead &&
                             !Person::players[i]->skeleton.free &&
-                            animation[Person::players[i]->animTarget].attack == neutral)
+                            Animation::animations[Person::players[i]->animTarget].attack == neutral)
                         numresponded = 1;
 
                     if (!Person::players[i]->throwkeydown)
@@ -6257,7 +6257,7 @@ void Game::Tick()
                     }
                     movekey = 0;
                     //Do controls
-                    if (!animation[Person::players[i]->animTarget].attack &&
+                    if (!Animation::animations[Person::players[i]->animTarget].attack &&
                             Person::players[i]->animTarget != staggerbackhighanim &&
                             Person::players[i]->animTarget != staggerbackhardanim &&
                             Person::players[i]->animTarget != backhandspringanim &&
@@ -7107,7 +7107,7 @@ void Game::TickOnceAfter()
     viewerfacing = facing;
 
     if (!cameramode) {
-        if ((animation[Person::players[0]->animTarget].attack != 3 && animation[Person::players[0]->animCurrent].attack != 3) || Person::players[0]->skeleton.free)
+        if ((Animation::animations[Person::players[0]->animTarget].attack != 3 && Animation::animations[Person::players[0]->animCurrent].attack != 3) || Person::players[0]->skeleton.free)
             target = Person::players[0]->coords + Person::players[0]->currentoffset * (1 - Person::players[0]->target) * Person::players[0]->scale + Person::players[0]->targetoffset * Person::players[0]->target * Person::players[0]->scale - Person::players[0]->facing * .05;
         else
             target = Person::players[0]->oldcoords + Person::players[0]->currentoffset * (1 - Person::players[0]->target) * Person::players[0]->scale + Person::players[0]->targetoffset * Person::players[0]->target * Person::players[0]->scale - Person::players[0]->facing * .05;
index 9e688230bd2f3abd6d591eb6ec88bb324febd39e..8c09b7b1304eaa3740fdf77ea4d7cc76d00db31b 100644 (file)
@@ -23,7 +23,8 @@ along with Lugaru.  If not, see <http://www.gnu.org/licenses/>.
 #include "gamegl.h"
 #include "Quaternions.h"
 #include "Lights.h"
-#include "Skeleton.h"
+#include "Animation/Animation.h"
+#include "Animation/Skeleton.h"
 #include "Terrain.h"
 #include "Sprite.h"
 #include "Frustum.h"
@@ -34,7 +35,6 @@ along with Lugaru.  If not, see <http://www.gnu.org/licenses/>.
 #include "openal_wrapper.h"
 #include "Stereo.h"
 
-#include "Animation.h"
 
 bool visibleloading = 0;
 
@@ -66,7 +66,6 @@ int environment = 0;
 float texscale = 0;
 float gravity = 0;
 Light light;
-Animation animation[animation_count];
 Terrain terrain;
 
 SDL_Window *sdlwindow;
index 3c9a123263d7e823068618b1900c02a28d1a946c..b745378ae0bd91abe7f4c617591f65ada85cfc29 100644 (file)
@@ -21,7 +21,7 @@ along with Lugaru.  If not, see <http://www.gnu.org/licenses/>.
 /**> HEADER FILES <**/
 #include "Person.h"
 #include "openal_wrapper.h"
-#include "Animation.h"
+#include "Animation/Animation.h"
 #include "Sounds.h"
 #include "Awards.h"
 #include "Game.h"
@@ -472,7 +472,7 @@ void Person::CheckKick()
             && !victim->skeleton.free))
         return;
 
-    if (animation[victim->animTarget].height != lowheight) {
+    if (Animation::animations[victim->animTarget].height != lowheight) {
         float damagemult = (creature == wolftype ? 2.5 : 1.) * power * power;
         XYZ relative = velocity;
         relative.y = 0;
@@ -1477,7 +1477,7 @@ void Person::Reverse()
     if (aitype != playercontrolled && Random() % 10 == 0 && escapednum < 2 && difficulty == 0)
         feint = 1;
 
-    if (victim->id == 0 && animation[victim->animTarget].attack == reversal)
+    if (victim->id == 0 && Animation::animations[victim->animTarget].attack == reversal)
         numreversals++;
 }
 
@@ -1736,16 +1736,16 @@ void Person::RagDoll(bool checkcollision)
             skeleton.joints[i].velchange = 0;
         }
         skeleton.DoConstraints(&coords, &scale);
-        if (animation[animCurrent].height == lowheight || animation[animTarget].height == lowheight) {
+        if (Animation::animations[animCurrent].height == lowheight || Animation::animations[animTarget].height == lowheight) {
             skeleton.DoConstraints(&coords, &scale);
             skeleton.DoConstraints(&coords, &scale);
             skeleton.DoConstraints(&coords, &scale);
             skeleton.DoConstraints(&coords, &scale);
         }
 
-        speed = animation[animTarget].speed[frameTarget] * 2;
-        if (animation[animCurrent].speed[frameCurrent] > animation[animTarget].speed[frameTarget]) {
-            speed = animation[animCurrent].speed[frameCurrent] * 2;
+        speed = Animation::animations[animTarget].speed[frameTarget] * 2;
+        if (Animation::animations[animCurrent].speed[frameCurrent] > Animation::animations[animTarget].speed[frameTarget]) {
+            speed = Animation::animations[animCurrent].speed[frameCurrent] * 2;
         }
         if (transspeed)
             speed = transspeed * 2;
@@ -1753,8 +1753,8 @@ void Person::RagDoll(bool checkcollision)
         speed *= speedmult;
 
         for (int i = 0; i < skeleton.num_joints; i++) {
-            if ((animation[animCurrent].attack != reversed || animCurrent == swordslashreversedanim) && animCurrent != rabbitkickanim && !isLanding() && !wasLanding() && animation[animCurrent].height == animation[animTarget].height)
-                skeleton.joints[i].velocity = velocity / scale + facing * 5 + DoRotation(DoRotation(DoRotation((animation[animTarget].position[i][frameTarget] - animation[animCurrent].position[i][frameCurrent]) * speed, 0, 0, tilt), tilt2, 0, 0), 0, yaw, 0);
+            if ((Animation::animations[animCurrent].attack != reversed || animCurrent == swordslashreversedanim) && animCurrent != rabbitkickanim && !isLanding() && !wasLanding() && Animation::animations[animCurrent].height == Animation::animations[animTarget].height)
+                skeleton.joints[i].velocity = velocity / scale + facing * 5 + DoRotation(DoRotation(DoRotation((Animation::animations[animTarget].position[i][frameTarget] - Animation::animations[animCurrent].position[i][frameCurrent]) * speed, 0, 0, tilt), tilt2, 0, 0), 0, yaw, 0);
             else
                 skeleton.joints[i].velocity = velocity / scale + facing * 5;
             change.x = (float)(Random() % 100) / 100;
@@ -1922,7 +1922,7 @@ void Person::DoAnimations()
             normalsupdatedelay = 0;
 
         if (animTarget == tempanim || animCurrent == tempanim) {
-            animation[tempanim] = tempanimation;
+            Animation::animations[tempanim] = tempanimation;
         }
         if (animTarget == jumpupanim || animTarget == jumpdownanim || isFlip()) {
             float gLoc[3];
@@ -1962,21 +1962,21 @@ void Person::DoAnimations()
                 numflipped++;
         }
 
-        if (animation[animTarget].attack != reversed)
+        if (Animation::animations[animTarget].attack != reversed)
             feint = 0;
         if (!crouchkeydown || (isLanding() || isLandhard()) || (wasLanding() || wasLandhard())) {
             crouchtogglekeydown = 0;
             if (aitype == playercontrolled)
                 feint = 0;
         } else {
-            if (!crouchtogglekeydown && animation[animTarget].attack == reversed && aitype == playercontrolled && (escapednum < 2 || reversaltrain))
+            if (!crouchtogglekeydown && Animation::animations[animTarget].attack == reversed && aitype == playercontrolled && (escapednum < 2 || reversaltrain))
                 feint = 1;
             if (!isFlip())
                 crouchtogglekeydown = 1;
         }
 
 
-        if (animation[animTarget].attack || animCurrent == getupfrombackanim || animCurrent == getupfromfrontanim) {
+        if (Animation::animations[animTarget].attack || animCurrent == getupfrombackanim || animCurrent == getupfromfrontanim) {
             if (detail)
                 normalsupdatedelay = 0;
         }
@@ -2015,7 +2015,7 @@ void Person::DoAnimations()
                 }
             }
 
-            if (!drawtogglekeydown && drawkeydown && (weaponactive == -1 || num_weapons == 1) && (animation[animTarget].label[frameTarget] || (animTarget != animCurrent && animCurrent == rollanim)) && num_weapons > 0 && creature != wolftype) {
+            if (!drawtogglekeydown && drawkeydown && (weaponactive == -1 || num_weapons == 1) && (Animation::animations[animTarget].label[frameTarget] || (animTarget != animCurrent && animCurrent == rollanim)) && num_weapons > 0 && creature != wolftype) {
                 if (weapons[weaponids[0]].getType() == knife) {
                     if (weaponactive == -1)
                         weaponactive = 0;
@@ -2033,39 +2033,39 @@ void Person::DoAnimations()
             }
             //Footstep sounds
             if (tutoriallevel != 1 || id == 0)
-                if ((animation[animTarget].label[frameTarget] && (animation[animTarget].label[frameTarget] < 5 || animation[animTarget].label[frameTarget] == 8))/*||(animTarget==rollanim&&frameTarget==animation[rollanim].numframes-1)*/) {
+                if ((Animation::animations[animTarget].label[frameTarget] && (Animation::animations[animTarget].label[frameTarget] < 5 || Animation::animations[animTarget].label[frameTarget] == 8))/*||(animTarget==rollanim&&frameTarget==Animation::animations[rollanim].numframes-1)*/) {
                     int whichsound;
                     if (onterrain) {
                         if (terrain.getOpacity(coords.x, coords.z) < .2) {
-                            if (animation[animTarget].label[frameTarget] == 1)
+                            if (Animation::animations[animTarget].label[frameTarget] == 1)
                                 whichsound = footstepsound;
                             else
                                 whichsound = footstepsound2;
-                            if (animation[animTarget].label[frameTarget] == 1)
+                            if (Animation::animations[animTarget].label[frameTarget] == 1)
                                 FootLand(leftfoot, 1);
-                            if (animation[animTarget].label[frameTarget] == 2)
+                            if (Animation::animations[animTarget].label[frameTarget] == 2)
                                 FootLand(rightfoot, 1);
-                            if (animation[animTarget].label[frameTarget] == 3 && isRun()) {
+                            if (Animation::animations[animTarget].label[frameTarget] == 3 && isRun()) {
                                 FootLand(rightfoot, 1);
                                 FootLand(leftfoot, 1);
                             }
 
                         }
                         if (terrain.getOpacity(coords.x, coords.z) >= .2) {
-                            if (animation[animTarget].label[frameTarget] == 1)
+                            if (Animation::animations[animTarget].label[frameTarget] == 1)
                                 whichsound = footstepsound3;
                             else
                                 whichsound = footstepsound4;
                         }
                     }
                     if (!onterrain) {
-                        if (animation[animTarget].label[frameTarget] == 1)
+                        if (Animation::animations[animTarget].label[frameTarget] == 1)
                             whichsound = footstepsound3;
                         else
                             whichsound = footstepsound4;
                     }
-                    if (animation[animTarget].label[frameTarget] == 4 && (weaponactive == -1 || (animTarget != knifeslashstartanim && animTarget != knifethrowanim && animTarget != crouchstabanim && animTarget != swordgroundstabanim && animTarget != knifefollowanim))) {
-                        if (animation[animTarget].attack != neutral) {
+                    if (Animation::animations[animTarget].label[frameTarget] == 4 && (weaponactive == -1 || (animTarget != knifeslashstartanim && animTarget != knifethrowanim && animTarget != crouchstabanim && animTarget != swordgroundstabanim && animTarget != knifefollowanim))) {
+                        if (Animation::animations[animTarget].attack != neutral) {
                             unsigned r = abs(Random() % 3);
                             if (r == 0)
                                 whichsound = lowwhooshsound;
@@ -2074,11 +2074,11 @@ void Person::DoAnimations()
                             if (r == 2)
                                 whichsound = highwhooshsound;
                         }
-                        if (animation[animTarget].attack == neutral)
+                        if (Animation::animations[animTarget].attack == neutral)
                             whichsound = movewhooshsound;
-                    } else if (animation[animTarget].label[frameTarget] == 4)
+                    } else if (Animation::animations[animTarget].label[frameTarget] == 4)
                         whichsound = knifeswishsound;
-                    if (animation[animTarget].label[frameTarget] == 8 && tutoriallevel != 1)
+                    if (Animation::animations[animTarget].label[frameTarget] == 8 && tutoriallevel != 1)
                         whichsound = landsound2;
 
                     emit_sound_at(whichsound, coords, 256.);
@@ -2092,7 +2092,7 @@ void Person::DoAnimations()
                             }
                         }
 
-                    if (animation[animTarget].label[frameTarget] == 3) {
+                    if (Animation::animations[animTarget].label[frameTarget] == 3) {
                         whichsound--;
                         emit_sound_at(whichsound, coords, 128.);
                     }
@@ -2102,10 +2102,10 @@ void Person::DoAnimations()
             if (tutoriallevel != 1 || id == 0)
                 if (speechdelay <= 0)
                     if (animTarget != crouchstabanim && animTarget != swordgroundstabanim && animTarget != staffgroundsmashanim)
-                        if ((animation[animTarget].label[frameTarget] && (animation[animTarget].label[frameTarget] < 5 || animation[animTarget].label[frameTarget] == 8))/*||(animTarget==rollanim&&frameTarget==animation[rollanim].numframes-1)*/) {
+                        if ((Animation::animations[animTarget].label[frameTarget] && (Animation::animations[animTarget].label[frameTarget] < 5 || Animation::animations[animTarget].label[frameTarget] == 8))/*||(animTarget==rollanim&&frameTarget==Animation::animations[rollanim].numframes-1)*/) {
                             int whichsound = -1;
-                            if (animation[animTarget].label[frameTarget] == 4 && aitype != playercontrolled) {
-                                if (animation[animTarget].attack != neutral) {
+                            if (Animation::animations[animTarget].label[frameTarget] == 4 && aitype != playercontrolled) {
+                                if (Animation::animations[animTarget].attack != neutral) {
                                     unsigned r = abs(Random() % 4);
                                     if (creature == rabbittype) {
                                         if (r == 0) whichsound = rabbitattacksound;
@@ -2141,7 +2141,7 @@ void Person::DoAnimations()
             animCurrent = animTarget;
             frameTarget++;
 
-            if (animTarget == removeknifeanim && animation[animTarget].label[frameCurrent] == 5) {
+            if (animTarget == removeknifeanim && Animation::animations[animTarget].label[frameCurrent] == 5) {
                 for (unsigned i = 0; i < weapons.size(); i++) {
                     if (weapons[i].owner == -1)
                         if (distsqflat(&coords, &weapons[i].position) < 4 && weaponactive == -1) {
@@ -2156,7 +2156,7 @@ void Person::DoAnimations()
                 }
             }
 
-            if (animTarget == crouchremoveknifeanim && animation[animTarget].label[frameCurrent] == 5) {
+            if (animTarget == crouchremoveknifeanim && Animation::animations[animTarget].label[frameCurrent] == 5) {
                 for (unsigned i = 0; i < weapons.size(); i++) {
                     bool willwork = true;
                     if (weapons[i].owner != -1)
@@ -2232,7 +2232,7 @@ void Person::DoAnimations()
                 }
             }
 
-            if (animCurrent == drawleftanim && animation[animTarget].label[frameCurrent] == 5) {
+            if (animCurrent == drawleftanim && Animation::animations[animTarget].label[frameCurrent] == 5) {
                 if (weaponactive == -1)
                     weaponactive = 0;
                 else if (weaponactive == 0) {
@@ -2299,7 +2299,7 @@ void Person::DoAnimations()
                         }
                 }
                 if (closestid != -1)
-                    if (closestdist < 5 && !Person::players[closestid]->dead && animation[Person::players[closestid]->animTarget].height != lowheight && Person::players[closestid]->animTarget != backhandspringanim) {
+                    if (closestdist < 5 && !Person::players[closestid]->dead && Animation::animations[Person::players[closestid]->animTarget].height != lowheight && Person::players[closestid]->animTarget != backhandspringanim) {
                         hasvictim = 1;
                         victim = Person::players[closestid];
                         coords = victim->coords;
@@ -2329,9 +2329,9 @@ void Person::DoAnimations()
             if (hasvictim) {
                 damagemult /= victim->damagetolerance / 200;
             }
-            if ((animation[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[animTarget].label[frameCurrent] == 5) {
-                    if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && 3 && animation[victim->animTarget].height != lowheight) {
+            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].label[frameCurrent] == 5) {
+                    if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && 3 && Animation::animations[victim->animTarget].height != lowheight) {
                         escapednum = 0;
                         if (id == 0)
                             camerashake += .4;
@@ -2366,8 +2366,8 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == wolfslapanim && animation[animTarget].label[frameCurrent] == 5) {
-                    if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && 3 && animation[victim->animTarget].height != lowheight) {
+                if (animTarget == wolfslapanim && Animation::animations[animTarget].label[frameCurrent] == 5) {
+                    if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && 3 && Animation::animations[victim->animTarget].height != lowheight) {
                         escapednum = 0;
                         if (id == 0)
                             camerashake += .4;
@@ -2399,8 +2399,8 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == walljumprightkickanim && animation[animTarget].label[frameCurrent] == 5) {
-                    if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && animation[victim->animTarget].height != lowheight) {
+                if (animTarget == walljumprightkickanim && Animation::animations[animTarget].label[frameCurrent] == 5) {
+                    if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && Animation::animations[victim->animTarget].height != lowheight) {
                         escapednum = 0;
                         if (id == 0)
                             camerashake += .4;
@@ -2434,8 +2434,8 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == walljumpleftkickanim && animation[animTarget].label[frameCurrent] == 5) {
-                    if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && animation[victim->animTarget].height != lowheight) {
+                if (animTarget == walljumpleftkickanim && Animation::animations[animTarget].label[frameCurrent] == 5) {
+                    if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && Animation::animations[victim->animTarget].height != lowheight) {
                         escapednum = 0;
                         if (id == 0)
                             camerashake += .4;
@@ -2469,8 +2469,8 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == blockhighleftstrikeanim && animation[animTarget].label[frameCurrent] == 5) {
-                    if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && animation[victim->animTarget].height != lowheight) {
+                if (animTarget == blockhighleftstrikeanim && Animation::animations[animTarget].label[frameCurrent] == 5) {
+                    if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && Animation::animations[victim->animTarget].height != lowheight) {
                         escapednum = 0;
                         if (id == 0)
                             camerashake += .4;
@@ -2493,7 +2493,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == killanim && animation[animTarget].label[frameCurrent] == 8) {
+                if (animTarget == killanim && Animation::animations[animTarget].label[frameCurrent] == 8) {
                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && victim->dead) {
                         escapednum = 0;
                         if (id == 0)
@@ -2527,7 +2527,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == killanim && animation[animTarget].label[frameCurrent] == 5) {
+                if (animTarget == killanim && Animation::animations[animTarget].label[frameCurrent] == 5) {
                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 9 && victim->dead) {
                         escapednum = 0;
                         if (id == 0)
@@ -2552,7 +2552,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == dropkickanim && animation[animTarget].label[frameCurrent] == 7) {
+                if (animTarget == dropkickanim && Animation::animations[animTarget].label[frameCurrent] == 7) {
                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 9 && victim->skeleton.free) {
                         escapednum = 0;
                         if (id == 0)
@@ -2593,7 +2593,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if ((animTarget == crouchstabanim || animTarget == swordgroundstabanim) && animation[animTarget].label[frameCurrent] == 5) {
+                if ((animTarget == crouchstabanim || animTarget == swordgroundstabanim) && Animation::animations[animTarget].label[frameCurrent] == 5) {
 
                     if (hasvictim)
                         if (!victim->skeleton.free)
@@ -2682,7 +2682,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if ((animTarget == crouchstabanim || animTarget == swordgroundstabanim) && animation[animTarget].label[frameCurrent] == 6) {
+                if ((animTarget == crouchstabanim || animTarget == swordgroundstabanim) && Animation::animations[animTarget].label[frameCurrent] == 6) {
                     if (!hasvictim) {
                         emit_sound_at(knifedrawsound, coords, 128);
                     }
@@ -2781,7 +2781,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == upunchanim && animation[animTarget].label[frameCurrent] == 5) {
+                if (animTarget == upunchanim && Animation::animations[animTarget].label[frameCurrent] == 5) {
                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3) {
                         escapednum = 0;
                         if (id == 0)
@@ -2819,16 +2819,16 @@ void Person::DoAnimations()
                 }
 
 
-                if (animTarget == winduppunchanim && animation[animTarget].label[frameCurrent] == 5) {
+                if (animTarget == winduppunchanim && Animation::animations[animTarget].label[frameCurrent] == 5) {
                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 2) {
                         escapednum = 0;
                         if (id == 0)
                             camerashake += .4;
-                        if (victim->damage <= victim->damagetolerance - 60 && normaldotproduct(victim->facing, victim->coords - coords) < (scale * 5) * (scale * 5) * 0 && animation[victim->animTarget].height != lowheight) {
+                        if (victim->damage <= victim->damagetolerance - 60 && normaldotproduct(victim->facing, victim->coords - coords) < (scale * 5) * (scale * 5) * 0 && Animation::animations[victim->animTarget].height != lowheight) {
                             if (tutoriallevel != 1) {
                                 emit_sound_at(thudsound, victim->coords);
                             }
-                        } else if (victim->damage <= victim->damagetolerance - 60 && normaldotproduct(victim->facing, victim->coords - coords) < (scale * 5) * (scale * 5) * 0 && animation[victim->animTarget].height == lowheight) {
+                        } else if (victim->damage <= victim->damagetolerance - 60 && normaldotproduct(victim->facing, victim->coords - coords) < (scale * 5) * (scale * 5) * 0 && Animation::animations[victim->animTarget].height == lowheight) {
                             if (tutoriallevel != 1) {
                                 emit_sound_at(whooshhitsound, victim->coords);
                             }
@@ -2838,7 +2838,7 @@ void Person::DoAnimations()
                             }
                         }
 
-                        if (victim->damage > victim->damagetolerance - 60 || normaldotproduct(victim->facing, victim->coords - coords) > 0 || animation[victim->animTarget].height == lowheight)
+                        if (victim->damage > victim->damagetolerance - 60 || normaldotproduct(victim->facing, victim->coords - coords) > 0 || Animation::animations[victim->animTarget].height == lowheight)
                             victim->RagDoll(0);
                         XYZ relative;
                         relative = victim->coords - coords;
@@ -2864,7 +2864,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == blockhighleftanim && animation[animTarget].label[frameCurrent] == 5) {
+                if (animTarget == blockhighleftanim && Animation::animations[animTarget].label[frameCurrent] == 5) {
                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 4) {
                         if (victim->id == 0)
                             camerashake += .4;
@@ -2874,7 +2874,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == swordslashparryanim && animation[animTarget].label[frameCurrent] == 5) {
+                if (animTarget == swordslashparryanim && Animation::animations[animTarget].label[frameCurrent] == 5) {
                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 4) {
                         if (victim->id == 0)
                             camerashake += .4;
@@ -2896,7 +2896,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == knifethrowanim && animation[animTarget].label[frameCurrent] == 5) {
+                if (animTarget == knifethrowanim && Animation::animations[animTarget].label[frameCurrent] == 5) {
                     if (weaponactive != -1) {
                         escapednum = 0;
                         XYZ aim;
@@ -2911,9 +2911,9 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == knifeslashstartanim && animation[animTarget].label[frameCurrent] == 5) {
+                if (animTarget == knifeslashstartanim && Animation::animations[animTarget].label[frameCurrent] == 5) {
                     if (hasvictim)
-                        if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 4.5 &&/*animation[victim->animTarget].height!=lowheight&&*/victim->animTarget != dodgebackanim && victim->animTarget != rollanim) {
+                        if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 4.5 &&/*Animation::animations[victim->animTarget].height!=lowheight&&*/victim->animTarget != dodgebackanim && victim->animTarget != rollanim) {
                             escapednum = 0;
                             if (tutoriallevel != 1)
                                 victim->DoBloodBig(1.5 / victim->armorhigh, 225);
@@ -2923,7 +2923,7 @@ void Person::DoAnimations()
                                 emit_sound_at(knifeslicesound, victim->coords);
                             }
                             //victim->jointVel(abdomen)+=relative*damagemult*200;
-                            if (animation[victim->animTarget].attack && (victim->aitype != playercontrolled || victim->animTarget == knifeslashstartanim) && (victim->creature == rabbittype || victim->deathbleeding <= 0)) {
+                            if (Animation::animations[victim->animTarget].attack && (victim->aitype != playercontrolled || victim->animTarget == knifeslashstartanim) && (victim->creature == rabbittype || victim->deathbleeding <= 0)) {
                                 if (victim->id != 0 || difficulty == 2) {
                                     victim->frameTarget = 0;
                                     victim->animTarget = staggerbackhardanim;
@@ -2965,7 +2965,7 @@ void Person::DoAnimations()
                             victim->DoDamage(damagemult * 0);
                         }
                 }
-                if (animTarget == swordslashanim && animation[animTarget].label[frameCurrent] == 5 && victim->animTarget != rollanim) {
+                if (animTarget == swordslashanim && Animation::animations[animTarget].label[frameCurrent] == 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)) {
                             award_bonus(id, Slashbonus);
@@ -3053,7 +3053,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == staffhitanim && animation[animTarget].label[frameCurrent] == 5 && victim->animTarget != rollanim) {
+                if (animTarget == staffhitanim && Animation::animations[animTarget].label[frameCurrent] == 5 && victim->animTarget != rollanim) {
                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 6.5 && victim->animTarget != dodgebackanim && victim->animTarget != sweepanim) {
                         if (tutoriallevel != 1) {
                             weapons[weaponids[0]].damage += .4 + float(abs(Random() % 100) - 50) / 250;
@@ -3087,7 +3087,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == staffspinhitanim && animation[animTarget].label[frameCurrent] == 5 && victim->animTarget != rollanim) {
+                if (animTarget == staffspinhitanim && Animation::animations[animTarget].label[frameCurrent] == 5 && victim->animTarget != rollanim) {
                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 6.5 && victim->animTarget != dodgebackanim && victim->animTarget != sweepanim) {
                         if (tutoriallevel != 1) {
                             weapons[weaponids[0]].damage += .6 + float(abs(Random() % 100) - 50) / 250;
@@ -3119,7 +3119,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == staffgroundsmashanim && animation[animTarget].label[frameCurrent] == 5) {
+                if (animTarget == staffgroundsmashanim && Animation::animations[animTarget].label[frameCurrent] == 5) {
                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 6.5) {
                         escapednum = 0;
                         if (tutoriallevel != 1) {
@@ -3169,8 +3169,8 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == lowkickanim && animation[animTarget].label[frameCurrent] == 5) {
-                    if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && animation[victim->animTarget].height != highheight) {
+                if (animTarget == lowkickanim && Animation::animations[animTarget].label[frameCurrent] == 5) {
+                    if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && Animation::animations[victim->animTarget].height != highheight) {
                         escapednum = 0;
                         if (id == 0)
                             camerashake += .4;
@@ -3181,7 +3181,7 @@ void Person::DoAnimations()
 
                         SolidHitBonus(id);
 
-                        if (animation[victim->animTarget].height == lowheight) {
+                        if (Animation::animations[victim->animTarget].height == lowheight) {
                             if (Random() % 2) {
                                 victim->spurt = 1;
                                 DoBlood(.2, 250);
@@ -3229,7 +3229,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == sweepanim && animation[animTarget].label[frameCurrent] == 5) {
+                if (animTarget == sweepanim && Animation::animations[animTarget].label[frameCurrent] == 5) {
                     if ((victim->animTarget != jumpupanim) &&
                         (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3) &&
                         (victim != this->shared_from_this())) {
@@ -3244,7 +3244,7 @@ void Person::DoAnimations()
                         relative.y = 0;
                         Normalise(&relative);
 
-                        if (animation[victim->animTarget].height == middleheight || animation[victim->animCurrent].height == middleheight || victim->damage >= victim->damagetolerance - 40) {
+                        if (Animation::animations[victim->animTarget].height == middleheight || Animation::animations[victim->animCurrent].height == middleheight || victim->damage >= victim->damagetolerance - 40) {
                             victim->RagDoll(0);
 
                             for (int i = 0; i < victim->skeleton.num_joints; i++) {
@@ -3287,8 +3287,8 @@ void Person::DoAnimations()
                     }
                 }
             }
-            if (animation[animTarget].attack == reversal && (!victim->feint || (victim->lastattack == victim->lastattack2 && victim->lastattack2 == victim->lastattack3 && Random() % 2) || animTarget == knifefollowanim)) {
-                if (animTarget == spinkickreversalanim && animation[animTarget].label[frameCurrent] == 7) {
+            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].label[frameCurrent] == 7) {
                     escapednum = 0;
                     if (id == 0)
                         camerashake += .4;
@@ -3319,7 +3319,7 @@ void Person::DoAnimations()
                     award_bonus(id, Reversal);
                 }
 
-                if ((animTarget == swordslashreversalanim || animTarget == knifeslashreversalanim || animTarget == staffhitreversalanim || animTarget == staffspinhitreversalanim) && animation[animTarget].label[frameCurrent] == 5) {
+                if ((animTarget == swordslashreversalanim || animTarget == knifeslashreversalanim || animTarget == staffhitreversalanim || animTarget == staffspinhitreversalanim) && Animation::animations[animTarget].label[frameCurrent] == 5) {
                     if (victim->weaponactive != -1 && victim->num_weapons > 0) {
                         if (weapons[victim->weaponids[victim->weaponactive]].owner == int(victim->id)) {
                             takeWeapon(victim->weaponids[victim->weaponactive]);
@@ -3332,7 +3332,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == staffhitreversalanim && animation[animTarget].label[frameCurrent] == 5) {
+                if (animTarget == staffhitreversalanim && Animation::animations[animTarget].label[frameCurrent] == 5) {
                     escapednum = 0;
                     if (id == 0)
                         camerashake += .4;
@@ -3354,7 +3354,7 @@ void Person::DoAnimations()
                     victim->DoDamage(damagemult * 70 / victim->protectionhigh);
                 }
 
-                if (animTarget == staffspinhitreversalanim && animation[animTarget].label[frameCurrent] == 7) {
+                if (animTarget == staffspinhitreversalanim && Animation::animations[animTarget].label[frameCurrent] == 7) {
                     escapednum = 0;
                     if (id == 0)
                         camerashake += .4;
@@ -3383,7 +3383,7 @@ void Person::DoAnimations()
                     victim->DoDamage(damagemult * 70 / victim->protectionhigh);
                 }
 
-                if (animTarget == upunchreversalanim && animation[animTarget].label[frameCurrent] == 7) {
+                if (animTarget == upunchreversalanim && Animation::animations[animTarget].label[frameCurrent] == 7) {
                     escapednum = 0;
                     victim->RagDoll(1);
                     XYZ relative;
@@ -3433,7 +3433,7 @@ void Person::DoAnimations()
 
 
 
-                if (animTarget == swordslashreversalanim && animation[animTarget].label[frameCurrent] == 7) {
+                if (animTarget == swordslashreversalanim && Animation::animations[animTarget].label[frameCurrent] == 7) {
                     escapednum = 0;
                     victim->RagDoll(1);
                     XYZ relative;
@@ -3456,7 +3456,7 @@ void Person::DoAnimations()
                     award_bonus(id, swordreversebonus);
                 }
 
-                if (hasvictim && animTarget == knifeslashreversalanim && animation[animTarget].label[frameCurrent] == 7) {
+                if (hasvictim && animTarget == knifeslashreversalanim && Animation::animations[animTarget].label[frameCurrent] == 7) {
                     escapednum = 0;
                     if (id == 0)
                         camerashake += .4;
@@ -3483,7 +3483,7 @@ void Person::DoAnimations()
                     award_bonus(id, Reversal);
                 }
 
-                if (hasvictim && animTarget == sneakattackanim && animation[animTarget].label[frameCurrent] == 7) {
+                if (hasvictim && animTarget == sneakattackanim && Animation::animations[animTarget].label[frameCurrent] == 7) {
                     escapednum = 0;
                     victim->RagDoll(0);
                     victim->skeleton.spinny = 0;
@@ -3523,7 +3523,7 @@ void Person::DoAnimations()
                     award_bonus(id, spinecrusher);
                 }
 
-                if (hasvictim && (animTarget == knifefollowanim || animTarget == knifesneakattackanim) && animation[animTarget].label[frameCurrent] == 5) {
+                if (hasvictim && (animTarget == knifefollowanim || animTarget == knifesneakattackanim) && Animation::animations[animTarget].label[frameCurrent] == 5) {
                     if (weaponactive != -1 && victim->bloodloss < victim->damagetolerance) {
                         escapednum = 0;
                         if (animTarget == knifefollowanim)
@@ -3565,7 +3565,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (hasvictim && (animTarget == knifefollowanim || animTarget == knifesneakattackanim) && animation[animTarget].label[frameCurrent] == 6) {
+                if (hasvictim && (animTarget == knifefollowanim || animTarget == knifesneakattackanim) && Animation::animations[animTarget].label[frameCurrent] == 6) {
                     escapednum = 0;
                     victim->velocity = 0;
                     for (int i = 0; i < victim->skeleton.num_joints; i++) {
@@ -3577,7 +3577,7 @@ void Person::DoAnimations()
                             victim->skeleton.joints[i].velocity = 0;
                         }
                     }
-                    if (weaponactive != -1 && animation[victim->animTarget].attack != reversal) {
+                    if (weaponactive != -1 && Animation::animations[victim->animTarget].attack != reversal) {
                         emit_sound_at(fleshstabremovesound, victim->coords);
                         if (bloodtoggle)
                             weapons[weaponids[weaponactive]].bloody = 2;
@@ -3596,7 +3596,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (hasvictim && (animTarget == swordsneakattackanim) && animation[animTarget].label[frameCurrent] == 5) {
+                if (hasvictim && (animTarget == swordsneakattackanim) && Animation::animations[animTarget].label[frameCurrent] == 5) {
                     if (weaponactive != -1 && victim->bloodloss < victim->damagetolerance) {
                         award_bonus(id, backstab);
 
@@ -3623,7 +3623,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (hasvictim && animTarget == swordsneakattackanim && animation[animTarget].label[frameCurrent] == 6) {
+                if (hasvictim && animTarget == swordsneakattackanim && Animation::animations[animTarget].label[frameCurrent] == 6) {
                     escapednum = 0;
                     victim->velocity = 0;
                     for (int i = 0; i < victim->skeleton.num_joints; i++) {
@@ -3648,7 +3648,7 @@ void Person::DoAnimations()
                     }
                 }
 
-                if (animTarget == sweepreversalanim && animation[animTarget].label[frameCurrent] == 7) {
+                if (animTarget == sweepreversalanim && Animation::animations[animTarget].label[frameCurrent] == 7) {
                     escapednum = 0;
                     if (id == 0)
                         camerashake += .4;
@@ -3704,7 +3704,7 @@ void Person::DoAnimations()
                     victim->velocity = 0;
                 }
 
-                if (animTarget == sweepreversalanim && ((animation[animTarget].label[frameCurrent] == 9 && victim->damage < victim->damagetolerance) || (animation[animTarget].label[frameCurrent] == 7 && victim->damage > victim->damagetolerance))) {
+                if (animTarget == sweepreversalanim && ((Animation::animations[animTarget].label[frameCurrent] == 9 && victim->damage < victim->damagetolerance) || (Animation::animations[animTarget].label[frameCurrent] == 7 && victim->damage > victim->damagetolerance))) {
                     escapednum = 0;
                     victim->RagDoll(0);
                     XYZ relative;
@@ -3728,7 +3728,7 @@ void Person::DoAnimations()
 
 
             //Animation end
-            if (frameTarget > animation[animCurrent].numframes - 1) {
+            if (frameTarget > Animation::animations[animCurrent].numframes - 1) {
                 frameTarget = 0;
                 if (wasStop()) {
                     animTarget = getIdle();
@@ -3951,7 +3951,7 @@ void Person::DoAnimations()
                     animTarget = getIdle();
                     lastfeint = 0;
                 }
-                if (animation[animTarget].attack == reversal && animCurrent != sneakattackanim && animCurrent != knifesneakattackanim && animCurrent != swordsneakattackanim && animCurrent != knifefollowanim) {
+                if (Animation::animations[animTarget].attack == reversal && animCurrent != sneakattackanim && animCurrent != knifesneakattackanim && animCurrent != swordsneakattackanim && animCurrent != knifefollowanim) {
                     float ycoords = oldcoords.y;
                     animTarget = getStop();
                     targetyaw += 180;
@@ -4002,7 +4002,7 @@ void Person::DoAnimations()
                     velocity.y = -5;
                     RagDoll(0);
                 }
-                if (animation[animTarget].attack == reversed) {
+                if (Animation::animations[animTarget].attack == reversed) {
                     escapednum++;
                     if (animTarget == sweepreversedanim)
                         targetyaw += 90;
@@ -4039,11 +4039,11 @@ void Person::DoAnimations()
                     oldcoords = coords;
                     coords += (DoRotation(jointPos(leftfoot), 0, yaw, 0) + DoRotation(jointPos(rightfoot), 0, yaw, 0)) / 2 * scale;
                     coords.y = oldcoords.y;
-                    //coords+=DoRotation(animation[animCurrent].offset,0,yaw,0)*scale;
+                    //coords+=DoRotation(Animation::animations[animCurrent].offset,0,yaw,0)*scale;
                     targetoffset.y = coords.y;
                     if (onterrain)
                         targetoffset.y = terrain.getHeight(coords.x, coords.z);
-                    currentoffset = DoRotation(animation[animCurrent].offset * -1, 0, yaw, 0) * scale;
+                    currentoffset = DoRotation(Animation::animations[animCurrent].offset * -1, 0, yaw, 0) * scale;
                     currentoffset.y -= (coords.y - targetoffset.y);
                     coords.y = targetoffset.y;
                     targetoffset = 0;
@@ -4110,10 +4110,10 @@ void Person::DoAnimations()
                     lastfeint = 0;
                 }
 
-                if (animation[animCurrent].attack == normalattack && !victim->skeleton.free && victim->animTarget != staggerbackhighanim && victim->animTarget != staggerbackhardanim && animTarget != winduppunchblockedanim && animTarget != blockhighleftanim && animTarget != swordslashparryanim && animTarget != swordslashparriedanim && animTarget != crouchstabanim && animTarget != swordgroundstabanim) {
+                if (Animation::animations[animCurrent].attack == normalattack && !victim->skeleton.free && victim->animTarget != staggerbackhighanim && victim->animTarget != staggerbackhardanim && animTarget != winduppunchblockedanim && animTarget != blockhighleftanim && animTarget != swordslashparryanim && animTarget != swordslashparriedanim && animTarget != crouchstabanim && animTarget != swordgroundstabanim) {
                     animTarget = getupfromfrontanim;
                     lastfeint = 0;
-                } else if (animation[animCurrent].attack == normalattack) {
+                } else if (Animation::animations[animCurrent].attack == normalattack) {
                     animTarget = getIdle();
                     lastfeint = 0;
                 }
@@ -4140,28 +4140,28 @@ void Person::DoAnimations()
         }
         if (!skeleton.free) {
             oldtarget = target;
-            if (!transspeed && animation[animTarget].attack != 2 && animation[animTarget].attack != 3) {
+            if (!transspeed && Animation::animations[animTarget].attack != 2 && Animation::animations[animTarget].attack != 3) {
                 if (!isRun() || !wasRun()) {
-                    if (animation[animTarget].speed[frameTarget] > animation[animCurrent].speed[frameCurrent])
-                        target += multiplier * animation[animTarget].speed[frameTarget] * speed * 2;
-                    if (animation[animTarget].speed[frameTarget] <= animation[animCurrent].speed[frameCurrent])
-                        target += multiplier * animation[animCurrent].speed[frameCurrent] * speed * 2;
+                    if (Animation::animations[animTarget].speed[frameTarget] > Animation::animations[animCurrent].speed[frameCurrent])
+                        target += multiplier * Animation::animations[animTarget].speed[frameTarget] * speed * 2;
+                    if (Animation::animations[animTarget].speed[frameTarget] <= Animation::animations[animCurrent].speed[frameCurrent])
+                        target += multiplier * Animation::animations[animCurrent].speed[frameCurrent] * speed * 2;
                 }
                 if (isRun() && wasRun()) {
                     float tempspeed;
                     tempspeed = velspeed;
                     if (tempspeed < 10 * speedmult)
                         tempspeed = 10 * speedmult;
-                    target += multiplier * animation[animTarget].speed[frameCurrent] * speed * 1.7 * tempspeed / (speed * 45 * scale);
+                    target += multiplier * Animation::animations[animTarget].speed[frameCurrent] * speed * 1.7 * tempspeed / (speed * 45 * scale);
                 }
             } else if (transspeed)
                 target += multiplier * transspeed * speed * 2;
             else {
                 if (!isRun() || !wasRun()) {
-                    if (animation[animTarget].speed[frameTarget] > animation[animCurrent].speed[frameCurrent])
-                        target += multiplier * animation[animTarget].speed[frameTarget] * 2;
-                    if (animation[animTarget].speed[frameTarget] <= animation[animCurrent].speed[frameCurrent])
-                        target += multiplier * animation[animCurrent].speed[frameCurrent] * 2;
+                    if (Animation::animations[animTarget].speed[frameTarget] > Animation::animations[animCurrent].speed[frameCurrent])
+                        target += multiplier * Animation::animations[animTarget].speed[frameTarget] * 2;
+                    if (Animation::animations[animTarget].speed[frameTarget] <= Animation::animations[animCurrent].speed[frameCurrent])
+                        target += multiplier * Animation::animations[animCurrent].speed[frameCurrent] * 2;
                 }
             }
 
@@ -4183,7 +4183,7 @@ void Person::DoAnimations()
             if (animCurrent != oldanimCurrent || animTarget != oldanimTarget || ((frameCurrent != oldframeCurrent || frameTarget != oldframeTarget) && !calcrot)) {
                 //Old rotates
                 for (int i = 0; i < skeleton.num_joints; i++) {
-                    skeleton.joints[i].position = animation[animCurrent].position[i][frameCurrent];
+                    skeleton.joints[i].position = Animation::animations[animCurrent].position[i][frameCurrent];
                 }
 
                 skeleton.FindForwards();
@@ -4206,7 +4206,7 @@ void Person::DoAnimations()
 
                 //New rotates
                 for (int i = 0; i < skeleton.num_joints; i++) {
-                    skeleton.joints[i].position = animation[animTarget].position[i][frameTarget];
+                    skeleton.joints[i].position = Animation::animations[animTarget].position[i][frameTarget];
                 }
 
                 skeleton.FindForwards();
@@ -4233,8 +4233,8 @@ void Person::DoAnimations()
                     }
                 }
             }
-            if (frameCurrent >= animation[animCurrent].numframes)
-                frameCurrent = animation[animCurrent].numframes - 1;
+            if (frameCurrent >= Animation::animations[animCurrent].numframes)
+                frameCurrent = Animation::animations[animCurrent].numframes - 1;
 
             oldanimCurrent = animCurrent;
             oldanimTarget = animTarget;
@@ -4242,8 +4242,8 @@ void Person::DoAnimations()
             oldframeCurrent = frameCurrent;
 
             for (int i = 0; i < skeleton.num_joints; i++) {
-                skeleton.joints[i].velocity = (animation[animCurrent].position[i][frameCurrent] * (1 - target) + animation[animTarget].position[i][frameTarget] * (target) - skeleton.joints[i].position) / multiplier;
-                skeleton.joints[i].position = animation[animCurrent].position[i][frameCurrent] * (1 - target) + animation[animTarget].position[i][frameTarget] * (target);
+                skeleton.joints[i].velocity = (Animation::animations[animCurrent].position[i][frameCurrent] * (1 - target) + Animation::animations[animTarget].position[i][frameTarget] * (target) - skeleton.joints[i].position) / multiplier;
+                skeleton.joints[i].position = Animation::animations[animCurrent].position[i][frameCurrent] * (1 - target) + Animation::animations[animTarget].position[i][frameTarget] * (target);
             }
             offset = currentoffset * (1 - target) + targetoffset * target;
             for (int i = 0; i < skeleton.num_muscles; i++) {
@@ -4458,7 +4458,7 @@ void Person::DoStuff()
         deathbleeding -= multiplier * 1.6;
         if (deathbleeding < 0)
             deathbleeding = 0;
-        if (bloodloss > damagetolerance && animation[animTarget].attack == neutral) {
+        if (bloodloss > damagetolerance && Animation::animations[animTarget].attack == neutral) {
             if (weaponactive != -1) {
                 weapons[weaponids[0]].drop(velocity * scale * -.3, velocity * scale);
                 weapons[weaponids[0]].velocity.x += .01;
@@ -5592,7 +5592,7 @@ void Person::DoStuff()
 
         terrainnormal = terrain.getNormal(coords.x, coords.z);
 
-        if (animation[animTarget].attack != reversal) {
+        if (Animation::animations[animTarget].attack != reversal) {
             if (!isnormal(coords.x))
                 coords = oldcoords;
             oldcoords = coords;
@@ -5613,7 +5613,7 @@ void Person::DoStuff()
                 targettilt2 = 0;
         }
         onterrain = 0;
-        if (!isRun() && !animation[animTarget].attack && animTarget != getupfromfrontanim && animTarget != getupfrombackanim && animTarget != sneakanim)
+        if (!isRun() && !Animation::animations[animTarget].attack && animTarget != getupfromfrontanim && animTarget != getupfrombackanim && animTarget != sneakanim)
             targettilt2 = 0;
         if (animTarget == jumpupanim || animTarget == jumpdownanim || isFlip()) {
             flatvelocity = velocity;
@@ -5642,7 +5642,7 @@ void Person::DoStuff()
         } else if (tilt2 < targettilt2) {
             tilt2 += multiplier * 400;
         }
-        if (!animation[animTarget].attack && animTarget != getupfrombackanim && animTarget != getupfromfrontanim) {
+        if (!Animation::animations[animTarget].attack && animTarget != getupfrombackanim && animTarget != getupfromfrontanim) {
             if (tilt2 > 25)
                 tilt2 = 25;
             if (tilt2 < -25)
@@ -5709,7 +5709,7 @@ void Person::DoStuff()
             velocity = flatfacing * velspeed;
         }
 
-        if (animTarget == rollanim && animation[animTarget].label[frameTarget] != 6) {
+        if (animTarget == rollanim && Animation::animations[animTarget].label[frameTarget] != 6) {
             velocity += facing * multiplier * speed * 700 * scale;
             velspeed = findLength(&velocity);
             if (velspeed > speed * 45 * scale) {
@@ -5784,7 +5784,7 @@ void Person::DoStuff()
             coords -= facing * multiplier * speed * 16 * scale;
             velocity = 0;
         }
-        if (animTarget == staggerbackhardanim && animation[staggerbackhardanim].label[frameTarget] != 6) {
+        if (animTarget == staggerbackhardanim && Animation::animations[staggerbackhardanim].label[frameTarget] != 6) {
             coords -= facing * multiplier * speed * 20 * scale;
             velocity = 0;
         }
@@ -5831,7 +5831,7 @@ void Person::DoStuff()
             coords += velocity * multiplier;
 
         if (coords.y < terrain.getHeight(coords.x, coords.z) && (animTarget == jumpdownanim || animTarget == jumpupanim || isFlip())) {
-            if (isFlip() && animation[animTarget].label[frameTarget] == 7)
+            if (isFlip() && Animation::animations[animTarget].label[frameTarget] == 7)
                 RagDoll(0);
 
             if (animTarget == jumpupanim) {
@@ -5866,7 +5866,7 @@ void Person::DoStuff()
         }
 
 
-        if (isIdle() || animTarget == drawrightanim || animTarget == drawleftanim || animTarget == crouchdrawrightanim || animTarget == crouchstabanim || animTarget == swordgroundstabanim || isStop() || animTarget == removeknifeanim || animTarget == crouchremoveknifeanim || isLanding() || isCrouch() || animation[animTarget].attack || (animTarget == rollanim && animation[animTarget].label[frameTarget] == 6)) {
+        if (isIdle() || animTarget == drawrightanim || animTarget == drawleftanim || animTarget == crouchdrawrightanim || animTarget == crouchstabanim || animTarget == swordgroundstabanim || isStop() || animTarget == removeknifeanim || animTarget == crouchremoveknifeanim || isLanding() || isCrouch() || Animation::animations[animTarget].attack || (animTarget == rollanim && Animation::animations[animTarget].label[frameTarget] == 6)) {
             velspeed = findLength(&velocity);
             velocity.y = 0;
             if (velspeed < multiplier * 300 * scale) {
@@ -5914,7 +5914,7 @@ void Person::DoStuff()
             }
         }
 
-        if (animation[animTarget].attack == normalattack && animTarget != rabbitkickanim && !victim->skeleton.free) {
+        if (Animation::animations[animTarget].attack == normalattack && animTarget != rabbitkickanim && !victim->skeleton.free) {
             terrainnormal = victim->coords - coords;
             Normalise(&terrainnormal);
             targetyaw = -asin(0 - terrainnormal.x);
@@ -5924,7 +5924,7 @@ void Person::DoStuff()
             targettilt2 = -asin(terrainnormal.y) * 360 / 6.28; //*-70;
         }
 
-        if (animation[animTarget].attack == reversal && animTarget != rabbittacklinganim) {
+        if (Animation::animations[animTarget].attack == reversal && animTarget != rabbittacklinganim) {
             targetyaw = victim->targetyaw;
         }
         if (animTarget == rabbittacklinganim) {
@@ -6079,12 +6079,12 @@ int Person::DrawSkeleton()
                 }
             }
 
-            if (!skeleton.free && (!animation[animTarget].attack && animTarget != getupfrombackanim && ((animTarget != rollanim && !isFlip()) || animation[animTarget].label[frameTarget] == 6) && animTarget != getupfromfrontanim && animTarget != wolfrunninganim && animTarget != rabbitrunninganim && animTarget != backhandspringanim && animTarget != walljumpfrontanim && animTarget != hurtidleanim && !isLandhard() && !isSleeping()))
+            if (!skeleton.free && (!Animation::animations[animTarget].attack && animTarget != getupfrombackanim && ((animTarget != rollanim && !isFlip()) || Animation::animations[animTarget].label[frameTarget] == 6) && animTarget != getupfromfrontanim && animTarget != wolfrunninganim && animTarget != rabbitrunninganim && animTarget != backhandspringanim && animTarget != walljumpfrontanim && animTarget != hurtidleanim && !isLandhard() && !isSleeping()))
                 DoHead();
             else {
                 targetheadyaw = -targetyaw;
                 targetheadpitch = 0;
-                if (animation[animTarget].attack == 3)
+                if (Animation::animations[animTarget].attack == 3)
                     targetheadyaw += 180;
             }
             for (i = 0; i < skeleton.drawmodel.vertexNum; i++) {
@@ -6363,7 +6363,7 @@ int Person::DrawSkeleton()
                 glEnable(GL_LIGHTING);
                 glEnable(GL_BLEND);
                 if (canattack && cananger)
-                    if (animation[animTarget].attack == normalattack || animation[animTarget].attack == reversed) {
+                    if (Animation::animations[animTarget].attack == normalattack || Animation::animations[animTarget].attack == reversed) {
                         glDisable(GL_TEXTURE_2D);
                         glColor4f(1, 0, 0, 0.8);
                     }
@@ -6387,7 +6387,7 @@ int Person::DrawSkeleton()
                     skeleton.drawmodellow.drawdifftex(skeleton.drawmodel.textureptr);
             }
 
-            if (!(animation[animTarget].attack == normalattack || animation[animTarget].attack == reversed))
+            if (!(Animation::animations[animTarget].attack == normalattack || Animation::animations[animTarget].attack == reversed))
                 if (tutoriallevel && id != 0) {
                     glPopMatrix();
                     glMatrixMode(GL_MODELVIEW);
@@ -6397,7 +6397,7 @@ int Person::DrawSkeleton()
                     glEnable(GL_LIGHTING);
                     glEnable(GL_BLEND);
                     if (canattack && cananger)
-                        if (animation[animTarget].attack == normalattack || animation[animTarget].attack == reversed) {
+                        if (Animation::animations[animTarget].attack == normalattack || Animation::animations[animTarget].attack == reversed) {
                             glDisable(GL_TEXTURE_2D);
                             glColor4f(1, 0, 0, 0.8);
                         }
@@ -6534,7 +6534,7 @@ int Person::DrawSkeleton()
                             float distance;
 
                             temppoint1 = jointPos(righthand);
-                            temppoint2 = animation[animCurrent].weapontarget[frameCurrent] * (1 - target) + animation[animTarget].weapontarget[frameTarget] * (target);
+                            temppoint2 = Animation::animations[animCurrent].weapontarget[frameCurrent] * (1 - target) + Animation::animations[animTarget].weapontarget[frameTarget] * (target);
                             distance = findDistance(&temppoint1, &temppoint2);
                             weapons[i].rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
                             weapons[i].rotation2 *= 360 / 6.28;
@@ -6553,7 +6553,7 @@ int Person::DrawSkeleton()
                             float distance;
 
                             temppoint1 = jointPos(righthand);
-                            temppoint2 = animation[animCurrent].weapontarget[frameCurrent] * (1 - target) + animation[animTarget].weapontarget[frameTarget] * (target);
+                            temppoint2 = Animation::animations[animCurrent].weapontarget[frameCurrent] * (1 - target) + Animation::animations[animTarget].weapontarget[frameTarget] * (target);
                             distance = findDistance(&temppoint1, &temppoint2);
                             weapons[i].rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
                             weapons[i].rotation2 *= 360 / 6.28;
@@ -6596,8 +6596,8 @@ int Person::DrawSkeleton()
                             XYZ temppoint1, temppoint2;
                             float distance;
 
-                            temppoint1 = animation[animCurrent].position[skeleton.jointlabels[righthand]][frameCurrent] * (1 - target) + animation[animTarget].position[skeleton.jointlabels[righthand]][frameTarget] * (target); //jointPos(righthand);
-                            temppoint2 = animation[animCurrent].weapontarget[frameCurrent] * (1 - target) + animation[animTarget].weapontarget[frameTarget] * (target);
+                            temppoint1 = Animation::animations[animCurrent].position[skeleton.jointlabels[righthand]][frameCurrent] * (1 - target) + Animation::animations[animTarget].position[skeleton.jointlabels[righthand]][frameTarget] * (target); //jointPos(righthand);
+                            temppoint2 = Animation::animations[animCurrent].weapontarget[frameCurrent] * (1 - target) + Animation::animations[animTarget].weapontarget[frameTarget] * (target);
                             distance = findDistance(&temppoint1, &temppoint2);
                             weapons[i].rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
                             weapons[i].rotation2 *= 360 / 6.28;
@@ -6619,8 +6619,8 @@ int Person::DrawSkeleton()
                             XYZ temppoint1, temppoint2;
                             float distance;
 
-                            temppoint1 = animation[animCurrent].position[skeleton.jointlabels[righthand]][frameCurrent] * (1 - target) + animation[animTarget].position[skeleton.jointlabels[righthand]][frameTarget] * (target); //jointPos(righthand);
-                            temppoint2 = animation[animCurrent].weapontarget[frameCurrent] * (1 - target) + animation[animTarget].weapontarget[frameTarget] * (target);
+                            temppoint1 = Animation::animations[animCurrent].position[skeleton.jointlabels[righthand]][frameCurrent] * (1 - target) + Animation::animations[animTarget].position[skeleton.jointlabels[righthand]][frameTarget] * (target); //jointPos(righthand);
+                            temppoint2 = Animation::animations[animCurrent].weapontarget[frameCurrent] * (1 - target) + Animation::animations[animTarget].weapontarget[frameTarget] * (target);
                             distance = findDistance(&temppoint1, &temppoint2);
                             weapons[i].rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
                             weapons[i].rotation2 *= 360 / 6.28;
@@ -6664,7 +6664,7 @@ int Person::DrawSkeleton()
     calcrot = 0;
     if (skeleton.free)
         calcrot = 1;
-    if (animation[animTarget].attack || isRun() || animTarget == staggerbackhardanim || isFlip() || animTarget == climbanim || animTarget == sneakanim || animTarget == rollanim || animTarget == walkanim || animTarget == backhandspringanim || isWallJump())
+    if (Animation::animations[animTarget].attack || isRun() || animTarget == staggerbackhardanim || isFlip() || animTarget == climbanim || animTarget == sneakanim || animTarget == rollanim || animTarget == walkanim || animTarget == backhandspringanim || isWallJump())
         calcrot = 1;
     if (animCurrent != animTarget)
         calcrot = 1;
@@ -6726,7 +6726,7 @@ int Person::SphereCheck(XYZ *p1, float radius, XYZ *p, XYZ *move, float *rotate,
                         if (LineFacetd(&start, &end, &model->vertex[model->Triangles[j].vertex[0]], &model->vertex[model->Triangles[j].vertex[1]], &model->vertex[model->Triangles[j].vertex[2]], &model->facenormals[j], &point)) {
                             p1->y = point.y + radius;
                             if ((animTarget == jumpdownanim || isFlip())) {
-                                if (isFlip() && (frameTarget < 5 || animation[animTarget].label[frameTarget] == 7 || animation[animTarget].label[frameTarget] == 4))
+                                if (isFlip() && (frameTarget < 5 || Animation::animations[animTarget].label[frameTarget] == 7 || Animation::animations[animTarget].label[frameTarget] == 4))
                                     RagDoll(0);
 
                                 if (animTarget == jumpupanim) {
index 4e0edaecb6dcf46be4f093007d2d5a7235053071..21768a4f2494ea64fea340c33cea7ed62349fc1e 100644 (file)
@@ -25,14 +25,14 @@ along with Lugaru.  If not, see <http://www.gnu.org/licenses/>.
 
 #include "gamegl.h"
 #include "Quaternions.h"
-#include "Skeleton.h"
+#include "Animation/Skeleton.h"
 #include "Models.h"
 #include "Terrain.h"
 #include "Sprite.h"
 #include <cmath>
 #include <memory>
 #include "Weapons.h"
-#include "Animation.h"
+#include "Animation/Animation.h"
 
 #define passivetype 0
 #define guardtype 1
diff --git a/Source/Skeleton.cpp b/Source/Skeleton.cpp
deleted file mode 100644 (file)
index 5a0e274..0000000
+++ /dev/null
@@ -1,1709 +0,0 @@
-/*
-Copyright (C) 2003, 2010 - Wolfire Games
-Copyright (C) 2010-2016 - Lugaru contributors (see AUTHORS file)
-
-This file is part of Lugaru.
-
-Lugaru is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-Lugaru is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Lugaru.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/**> HEADER FILES <**/
-#include "Game.h"
-#include "Skeleton.h"
-#include "openal_wrapper.h"
-#include "Animation.h"
-#include "Utils/Folders.h"
-
-extern float multiplier;
-extern float gravity;
-extern Terrain terrain;
-extern Objects objects;
-extern int environment;
-extern float camerashake;
-extern bool freeze;
-extern int detail;
-extern int tutoriallevel;
-
-extern int whichjointstartarray[26];
-extern int whichjointendarray[26];
-
-extern bool visibleloading;
-
-/* EFFECT
- */
-void dealloc2(void* param)
-{
-    free(param);
-}
-
-enum {boneconnect, constraint, muscle};
-
-
-/* EFFECT
- * sets strength, length,
- *      parent1->position, parent2->position,
- *      parent1->velocity, parent2->velocity
- * used for ragdolls?
- *
- * USES:
- * Skeleton::DoConstraints
- */
-void Muscle::DoConstraint(bool spinny)
-{
-    // FIXME: relaxlength shouldn't be static, but may not always be set
-    // so I don't want to change the existing behavior even though it's probably a bug
-    static float relaxlength;
-
-    float oldlength = length;
-
-    if (type != boneconnect)
-        relaxlength = findDistance(&parent1->position, &parent2->position);
-
-    if (type == boneconnect)
-        strength = 1;
-    if (type == constraint)
-        strength = 0;
-
-    // clamp strength
-    if (strength < 0)
-        strength = 0;
-    if (strength > 1)
-        strength = 1;
-
-    length -= (length - relaxlength) * (1 - strength) * multiplier * 10000;
-    length -= (length - targetlength) * (strength) * multiplier * 10000;
-    if (strength == 0)
-        length = relaxlength;
-
-    if ((relaxlength - length > 0 && relaxlength - oldlength < 0) || (relaxlength - length < 0 && relaxlength - oldlength > 0))
-        length = relaxlength;
-
-    // clamp length
-    if (length < minlength)
-        length = minlength;
-    if (length > maxlength)
-        length = maxlength;
-
-    if (length == relaxlength)
-        return;
-
-    // relax muscle?
-
-    //Find midpoint
-    XYZ midp = (parent1->position * parent1->mass + parent2->position * parent2->mass) / (parent1->mass + parent2->mass);
-
-    //Find vector from midpoint to second vector
-    XYZ vel = parent2->position - midp;
-
-    //Change to unit vector
-    Normalise(&vel);
-
-    //Apply velocity change
-    XYZ newpoint1 = midp - vel * length * (parent2->mass / (parent1->mass + parent2->mass));
-    XYZ newpoint2 = midp + vel * length * (parent1->mass / (parent1->mass + parent2->mass));
-    if (!freeze && spinny) {
-        parent1->velocity = parent1->velocity + (newpoint1 - parent1->position) / multiplier / 4;
-        parent2->velocity = parent2->velocity + (newpoint2 - parent2->position) / multiplier / 4;
-    } else {
-        parent1->velocity = parent1->velocity + (newpoint1 - parent1->position);
-        parent2->velocity = parent2->velocity + (newpoint2 - parent2->position);
-    }
-
-    //Move child point to within certain distance of parent point
-    parent1->position = newpoint1;
-    parent2->position = newpoint2;
-}
-
-/* EFFECT
- * sets forward, lowforward, specialforward[]
- *
- * USES:
- * Skeleton::Load
- * Person/Person::DoAnimations
- * Person/Person::DrawSkeleton
- */
-void Skeleton::FindForwards()
-{
-    //Find forward vectors
-    CrossProduct(joints[forwardjoints[1]].position - joints[forwardjoints[0]].position, joints[forwardjoints[2]].position - joints[forwardjoints[0]].position, &forward);
-    Normalise(&forward);
-
-    CrossProduct(joints[lowforwardjoints[1]].position - joints[lowforwardjoints[0]].position, joints[lowforwardjoints[2]].position - joints[lowforwardjoints[0]].position, &lowforward);
-    Normalise(&lowforward);
-
-    //Special forwards
-    specialforward[0] = forward;
-
-    specialforward[1] = jointPos(rightshoulder) + jointPos(rightwrist);
-    specialforward[1] = jointPos(rightelbow) - specialforward[1] / 2;
-    specialforward[1] += forward * .4;
-    Normalise(&specialforward[1]);
-    specialforward[2] = jointPos(leftshoulder) + jointPos(leftwrist);
-    specialforward[2] = jointPos(leftelbow) - specialforward[2] / 2;
-    specialforward[2] += forward * .4;
-    Normalise(&specialforward[2]);
-
-    specialforward[3] = jointPos(righthip) + jointPos(rightankle);
-    specialforward[3] = specialforward[3] / 2 - jointPos(rightknee);
-    specialforward[3] += lowforward * .4;
-    Normalise(&specialforward[3]);
-    specialforward[4] = jointPos(lefthip) + jointPos(leftankle);
-    specialforward[4] = specialforward[4] / 2 - jointPos(leftknee);
-    specialforward[4] += lowforward * .4;
-    Normalise(&specialforward[4]);
-}
-
-/* EFFECT
- * TODO
- *
- * USES:
- * Person/Person::RagDoll
- * Person/Person::DoStuff
- * Person/IKHelper
- */
-float Skeleton::DoConstraints(XYZ *coords, float *scale)
-{
-    float friction = 1.5;
-    const float elasticity = .3;
-    XYZ bounceness;
-    const int numrepeats = 3;
-    float groundlevel = .15;
-    int i, j, k, m;
-    XYZ temp;
-    XYZ terrainnormal;
-    int whichhit;
-    float frictionness;
-    XYZ terrainlight;
-    int whichpatchx;
-    int whichpatchz;
-    float damage = 0; // eventually returned from function
-    bool breaking = false;
-
-    if (free) {
-        freetime += multiplier;
-
-        whichpatchx = coords->x / (terrain.size / subdivision * terrain.scale);
-        whichpatchz = coords->z / (terrain.size / subdivision * terrain.scale);
-
-        terrainlight = *coords;
-        objects.SphereCheckPossible(&terrainlight, 1);
-
-        //Add velocity
-        for (i = 0; i < num_joints; i++) {
-            joints[i].position = joints[i].position + joints[i].velocity * multiplier;
-
-            switch (joints[i].label) {
-            case head:
-                groundlevel = .8;
-                break;
-            case righthand:
-            case rightwrist:
-            case rightelbow:
-            case lefthand:
-            case leftwrist:
-            case leftelbow:
-                groundlevel = .2;
-                break;
-            default:
-                groundlevel = .15;
-                break;
-            }
-
-            joints[i].position.y -= groundlevel;
-            joints[i].oldvelocity = joints[i].velocity;
-        }
-
-        float tempmult = multiplier;
-        //multiplier/=numrepeats;
-
-        for (j = 0; j < numrepeats; j++) {
-            float r = .05;
-            // right leg constraints?
-            if (!joint(rightknee).locked && !joint(righthip).locked) {
-                temp = jointPos(rightknee) - (jointPos(righthip) + jointPos(rightankle)) / 2;
-                while (normaldotproduct(temp, lowforward) > -.1 && !sphere_line_intersection(&jointPos(righthip), &jointPos(rightankle), &jointPos(rightknee), &r)) {
-                    jointPos(rightknee) -= lowforward * .05;
-                    if (spinny)
-                        jointVel(rightknee) -= lowforward * .05 / multiplier / 4;
-                    else
-                        jointVel(rightknee) -= lowforward * .05;
-                    jointPos(rightankle) += lowforward * .025;
-                    if (spinny)
-                        jointVel(rightankle) += lowforward * .025 / multiplier / 4;
-                    else
-                        jointVel(rightankle) += lowforward * .25;
-                    jointPos(righthip) += lowforward * .025;
-                    if (spinny)
-                        jointVel(righthip) += lowforward * .025 / multiplier / 4;
-                    else
-                        jointVel(righthip) += lowforward * .025;
-                    temp = jointPos(rightknee) - (jointPos(righthip) + jointPos(rightankle)) / 2;
-                }
-            }
-
-            // left leg constraints?
-            if (!joint(leftknee).locked && !joint(lefthip).locked) {
-                temp = jointPos(leftknee) - (jointPos(lefthip) + jointPos(leftankle)) / 2;
-                while (normaldotproduct(temp, lowforward) > -.1 && !sphere_line_intersection(&jointPos(lefthip), &jointPos(leftankle), &jointPos(leftknee), &r)) {
-                    jointPos(leftknee) -= lowforward * .05;
-                    if (spinny)
-                        jointVel(leftknee) -= lowforward * .05 / multiplier / 4;
-                    else
-                        jointVel(leftknee) -= lowforward * .05;
-                    jointPos(leftankle) += lowforward * .025;
-                    if (spinny)
-                        jointVel(leftankle) += lowforward * .025 / multiplier / 4;
-                    else
-                        jointVel(leftankle) += lowforward * .25;
-                    jointPos(lefthip) += lowforward * .025;
-                    if (spinny)
-                        jointVel(lefthip) += lowforward * .025 / multiplier / 4;
-                    else
-                        jointVel(lefthip) += lowforward * .025;
-                    temp = jointPos(leftknee) - (jointPos(lefthip) + jointPos(leftankle)) / 2;
-                }
-            }
-
-            for (i = 0; i < num_joints; i++) {
-                if (joints[i].locked && !spinny && findLengthfast(&joints[i].velocity) > 320)
-                    joints[i].locked = 0;
-                if (spinny && findLengthfast(&joints[i].velocity) > 600)
-                    joints[i].locked = 0;
-                if (joints[i].delay > 0) {
-                    bool freely = true;
-                    for (j = 0; j < num_joints; j++) {
-                        if (joints[j].locked)
-                            freely = false;
-                    }
-                    if (freely)
-                        joints[i].delay -= multiplier * 3;
-                }
-            }
-
-            if (num_muscles)
-                for (i = 0; i < num_muscles; i++) {
-                    //Length constraints
-                    muscles[i].DoConstraint(spinny);
-                }
-
-            for (i = 0; i < num_joints; i++) {
-                //Length constraints
-                //Ground constraint
-                groundlevel = 0;
-                if (joints[i].position.y * (*scale) + coords->y < terrain.getHeight(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z) + groundlevel) {
-                    freefall = 0;
-                    friction = 1.5;
-                    if (joints[i].label == groin && !joints[i].locked && joints[i].delay <= 0) {
-                        joints[i].locked = 1;
-                        joints[i].delay = 1;
-                        if (tutoriallevel != 1 || id == 0) {
-                            emit_sound_at(landsound1, joints[i].position * (*scale) + *coords, 128.);
-                        }
-                        breaking = true;
-                    }
-
-                    if (joints[i].label == head && !joints[i].locked && joints[i].delay <= 0) {
-                        joints[i].locked = 1;
-                        joints[i].delay = 1;
-                        if (tutoriallevel != 1 || id == 0) {
-                            emit_sound_at(landsound2, joints[i].position * (*scale) + *coords, 128.);
-                        }
-                    }
-
-                    terrainnormal = terrain.getNormal(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z);
-                    ReflectVector(&joints[i].velocity, &terrainnormal);
-                    bounceness = terrainnormal * findLength(&joints[i].velocity) * (abs(normaldotproduct(joints[i].velocity, terrainnormal)));
-                    if (!joints[i].locked)
-                        damage += findLengthfast(&bounceness) / 4000;
-                    if (findLengthfast(&joints[i].velocity) < findLengthfast(&bounceness))
-                        bounceness = 0;
-                    frictionness = abs(normaldotproduct(joints[i].velocity, terrainnormal));
-                    joints[i].velocity -= bounceness;
-                    if (1 - friction * frictionness > 0)
-                        joints[i].velocity *= 1 - friction * frictionness;
-                    else
-                        joints[i].velocity = 0;
-
-                    if (tutoriallevel != 1 || id == 0)
-                        if (findLengthfast(&bounceness) > 8000 && breaking) {
-                            // FIXME: this crashes because k is not initialized!
-                            // to reproduce, type 'wolfie' in console and play a while
-                            // I'll just comment it out for now
-                            //objects.model[k].MakeDecal(breakdecal, DoRotation(temp - objects.position[k], 0, -objects.yaw[k], 0), .4, .5, Random() % 360);
-                            Sprite::MakeSprite(cloudsprite, joints[i].position * (*scale) + *coords, joints[i].velocity * .06, 1, 1, 1, 4, .2);
-                            breaking = false;
-                            camerashake += .6;
-
-                            emit_sound_at(breaksound2, joints[i].position * (*scale) + *coords);
-
-                            addEnvSound(*coords, 64);
-                        }
-
-                    if (findLengthfast(&bounceness) > 2500) {
-                        Normalise(&bounceness);
-                        bounceness = bounceness * 50;
-                    }
-
-                    joints[i].velocity += bounceness * elasticity;
-
-                    if (findLengthfast(&joints[i].velocity) > findLengthfast(&joints[i].oldvelocity)) {
-                        bounceness = 0;
-                        joints[i].velocity = joints[i].oldvelocity;
-                    }
-
-
-                    if (joints[i].locked == 0)
-                        if (findLengthfast(&joints[i].velocity) < 1)
-                            joints[i].locked = 1;
-
-                    if (environment == snowyenvironment && findLengthfast(&bounceness) > 500 && terrain.getOpacity(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z) < .2) {
-                        terrainlight = terrain.getLighting(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z);
-                        Sprite::MakeSprite(cloudsprite, joints[i].position * (*scale) + *coords, joints[i].velocity * .06, terrainlight.x, terrainlight.y, terrainlight.z, .5, .7);
-                        if (detail == 2)
-                            terrain.MakeDecal(bodyprintdecal, joints[i].position * (*scale) + *coords, .4, .4, 0);
-                    } else if (environment == desertenvironment && findLengthfast(&bounceness) > 500 && terrain.getOpacity(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z) < .2) {
-                        terrainlight = terrain.getLighting(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z);
-                        Sprite::MakeSprite(cloudsprite, joints[i].position * (*scale) + *coords, joints[i].velocity * .06, terrainlight.x * 190 / 255, terrainlight.y * 170 / 255, terrainlight.z * 108 / 255, .5, .7);
-                    }
-
-                    else if (environment == grassyenvironment && findLengthfast(&bounceness) > 500 && terrain.getOpacity(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z) < .2) {
-                        terrainlight = terrain.getLighting(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z);
-                        Sprite::MakeSprite(cloudsprite, joints[i].position * (*scale) + *coords, joints[i].velocity * .06, terrainlight.x * 90 / 255, terrainlight.y * 70 / 255, terrainlight.z * 8 / 255, .5, .5);
-                    } else if (findLengthfast(&bounceness) > 500)
-                        Sprite::MakeSprite(cloudsprite, joints[i].position * (*scale) + *coords, joints[i].velocity * .06, terrainlight.x, terrainlight.y, terrainlight.z, .5, .2);
-
-
-                    joints[i].position.y = (terrain.getHeight(joints[i].position.x * (*scale) + coords->x, joints[i].position.z * (*scale) + coords->z) + groundlevel - coords->y) / (*scale);
-                    if (longdead > 100)
-                        broken = 1;
-                }
-                if (terrain.patchobjectnum[whichpatchx][whichpatchz])
-                    for (m = 0; m < terrain.patchobjectnum[whichpatchx][whichpatchz]; m++) {
-                        k = terrain.patchobjects[whichpatchx][whichpatchz][m];
-                        if (k < objects.numobjects && k >= 0)
-                            if (objects.possible[k]) {
-                                friction = objects.friction[k];
-                                XYZ start = joints[i].realoldposition;
-                                XYZ end = joints[i].position * (*scale) + *coords;
-                                whichhit = objects.model[k].LineCheckPossible(&start, &end, &temp, &objects.position[k], &objects.yaw[k]);
-                                if (whichhit != -1) {
-                                    if (joints[i].label == groin && !joints[i].locked && joints[i].delay <= 0) {
-                                        joints[i].locked = 1;
-                                        joints[i].delay = 1;
-                                        if (tutoriallevel != 1 || id == 0) {
-                                            emit_sound_at(landsound1, joints[i].position * (*scale) + *coords, 128.);
-                                        }
-                                        breaking = true;
-                                    }
-
-                                    if (joints[i].label == head && !joints[i].locked && joints[i].delay <= 0) {
-                                        joints[i].locked = 1;
-                                        joints[i].delay = 1;
-                                        if (tutoriallevel != 1 || id == 0) {
-                                            emit_sound_at(landsound2, joints[i].position * (*scale) + *coords, 128.);
-                                        }
-                                    }
-
-                                    terrainnormal = DoRotation(objects.model[k].facenormals[whichhit], 0, objects.yaw[k], 0) * -1;
-                                    if (terrainnormal.y > .8)
-                                        freefall = 0;
-                                    bounceness = terrainnormal * findLength(&joints[i].velocity) * (abs(normaldotproduct(joints[i].velocity, terrainnormal)));
-                                    if (findLengthfast(&joints[i].velocity) > findLengthfast(&joints[i].oldvelocity)) {
-                                        bounceness = 0;
-                                        joints[i].velocity = joints[i].oldvelocity;
-                                    }
-                                    if (tutoriallevel != 1 || id == 0)
-                                        if (findLengthfast(&bounceness) > 4000 && breaking) {
-                                            objects.model[k].MakeDecal(breakdecal, DoRotation(temp - objects.position[k], 0, -objects.yaw[k], 0), .4, .5, Random() % 360);
-                                            Sprite::MakeSprite(cloudsprite, joints[i].position * (*scale) + *coords, joints[i].velocity * .06, 1, 1, 1, 4, .2);
-                                            breaking = false;
-                                            camerashake += .6;
-
-                                            emit_sound_at(breaksound2, joints[i].position * (*scale) + *coords);
-
-                                            addEnvSound(*coords, 64);
-                                        }
-                                    if (objects.type[k] == treetrunktype) {
-                                        objects.rotx[k] += joints[i].velocity.x * multiplier * .4;
-                                        objects.roty[k] += joints[i].velocity.z * multiplier * .4;
-                                        objects.rotx[k + 1] += joints[i].velocity.x * multiplier * .4;
-                                        objects.roty[k + 1] += joints[i].velocity.z * multiplier * .4;
-                                    }
-                                    if (!joints[i].locked)
-                                        damage += findLengthfast(&bounceness) / 2500;
-                                    ReflectVector(&joints[i].velocity, &terrainnormal);
-                                    frictionness = abs(normaldotproduct(joints[i].velocity, terrainnormal));
-                                    joints[i].velocity -= bounceness;
-                                    if (1 - friction * frictionness > 0)
-                                        joints[i].velocity *= 1 - friction * frictionness;
-                                    else
-                                        joints[i].velocity = 0;
-                                    if (findLengthfast(&bounceness) > 2500) {
-                                        Normalise(&bounceness);
-                                        bounceness = bounceness * 50;
-                                    }
-                                    joints[i].velocity += bounceness * elasticity;
-
-
-                                    if (!joints[i].locked)
-                                        if (findLengthfast(&joints[i].velocity) < 1) {
-                                            joints[i].locked = 1;
-                                        }
-                                    if (findLengthfast(&bounceness) > 500)
-                                        Sprite::MakeSprite(cloudsprite, joints[i].position * (*scale) + *coords, joints[i].velocity * .06, 1, 1, 1, .5, .2);
-                                    joints[i].position = (temp - *coords) / (*scale) + terrainnormal * .005;
-                                    if (longdead > 100)
-                                        broken = 1;
-                                }
-                            }
-                    }
-                joints[i].realoldposition = joints[i].position * (*scale) + *coords;
-            }
-        }
-        multiplier = tempmult;
-
-
-        if (terrain.patchobjectnum[whichpatchx][whichpatchz])
-            for (m = 0; m < terrain.patchobjectnum[whichpatchx][whichpatchz]; m++) {
-                k = terrain.patchobjects[whichpatchx][whichpatchz][m];
-                if (objects.possible[k]) {
-                    for (i = 0; i < 26; i++) {
-                        //Make this less stupid
-                        XYZ start = joints[jointlabels[whichjointstartarray[i]]].position * (*scale) + *coords;
-                        XYZ end = joints[jointlabels[whichjointendarray[i]]].position * (*scale) + *coords;
-                        whichhit = objects.model[k].LineCheckSlidePossible(&start, &end, &temp, &objects.position[k], &objects.yaw[k]);
-                        if (whichhit != -1) {
-                            joints[jointlabels[whichjointendarray[i]]].position = (end - *coords) / (*scale);
-                            for (j = 0; j < num_muscles; j++) {
-                                if ((muscles[j].parent1->label == whichjointstartarray[i] && muscles[j].parent2->label == whichjointendarray[i]) || (muscles[j].parent2->label == whichjointstartarray[i] && muscles[j].parent1->label == whichjointendarray[i]))
-                                    muscles[j].DoConstraint(spinny);
-                            }
-                        }
-                    }
-                }
-            }
-
-        for (i = 0; i < num_joints; i++) {
-            switch (joints[i].label) {
-            case head:
-                groundlevel = .8;
-                break;
-            case righthand:
-            case rightwrist:
-            case rightelbow:
-            case lefthand:
-            case leftwrist:
-            case leftelbow:
-                groundlevel = .2;
-                break;
-            default:
-                groundlevel = .15;
-                break;
-            }
-            joints[i].position.y += groundlevel;
-            joints[i].mass = 1;
-            if (joints[i].label == lefthip || joints[i].label == leftknee || joints[i].label == leftankle || joints[i].label == righthip || joints[i].label == rightknee || joints[i].label == rightankle)
-                joints[i].mass = 2;
-            if (joints[i].locked) {
-                joints[i].mass = 4;
-            }
-        }
-
-        return damage;
-    }
-
-    if (!free) {
-        for (i = 0; i < num_muscles; i++) {
-            if (muscles[i].type == boneconnect)
-                muscles[i].DoConstraint(0);
-        }
-    }
-
-    return 0;
-}
-
-/* EFFECT
- * applies gravity to the skeleton
- *
- * USES:
- * Person/Person::DoStuff
- */
-void Skeleton::DoGravity(float *scale)
-{
-    static int i;
-    for (i = 0; i < num_joints; i++) {
-        if (
-                (
-                    ((joints[i].label != leftknee) && (joints[i].label != rightknee)) ||
-                    (lowforward.y > -.1) ||
-                    (joints[i].mass < 5)
-                ) && (
-                    ((joints[i].label != leftelbow) && (joints[i].label != rightelbow)) ||
-                    (forward.y < .3)
-                )
-            )
-            joints[i].velocity.y += gravity * multiplier / (*scale);
-    }
-}
-
-/* EFFECT
- * set muscles[which].rotate1
- *     .rotate2
- *     .rotate3
- *
- * special case if animation == hanganim
- */
-void Skeleton::FindRotationMuscle(int which, int animation)
-{
-    XYZ p1, p2, fwd;
-    float dist;
-
-    p1 = muscles[which].parent1->position;
-    p2 = muscles[which].parent2->position;
-    dist = findDistance(&p1, &p2);
-    if (p1.y - p2.y <= dist)
-        muscles[which].rotate2 = asin((p1.y - p2.y) / dist);
-    if (p1.y - p2.y > dist)
-        muscles[which].rotate2 = asin(1.f);
-    muscles[which].rotate2 *= 360.0 / 6.2831853;
-
-    p1.y = 0;
-    p2.y = 0;
-    dist = findDistance(&p1, &p2);
-    if (p1.z - p2.z <= dist)
-        muscles[which].rotate1 = acos((p1.z - p2.z) / dist);
-    if (p1.z - p2.z > dist)
-        muscles[which].rotate1 = acos(1.f);
-    muscles[which].rotate1 *= 360.0 / 6.2831853;
-    if (p1.x > p2.x)
-        muscles[which].rotate1 = 360 - muscles[which].rotate1;
-    if (!isnormal(muscles[which].rotate1))
-        muscles[which].rotate1 = 0;
-    if (!isnormal(muscles[which].rotate2))
-        muscles[which].rotate2 = 0;
-
-    const int label1 = muscles[which].parent1->label;
-    const int label2 = muscles[which].parent2->label;
-    switch (label1) {
-    case head:
-        fwd = specialforward[0];
-        break;
-    case rightshoulder:
-    case rightelbow:
-    case rightwrist:
-    case righthand:
-        fwd = specialforward[1];
-        break;
-    case leftshoulder:
-    case leftelbow:
-    case leftwrist:
-    case lefthand:
-        fwd = specialforward[2];
-        break;
-    case righthip:
-    case rightknee:
-    case rightankle:
-    case rightfoot:
-        fwd = specialforward[3];
-        break;
-    case lefthip:
-    case leftknee:
-    case leftankle:
-    case leftfoot:
-        fwd = specialforward[4];
-        break;
-    default:
-        if (muscles[which].parent1->lower)
-            fwd = lowforward;
-        else
-            fwd = forward;
-        break;
-    }
-
-    if (animation == hanganim) {
-        if (label1 == righthand || label2 == righthand) {
-            fwd = 0;
-            fwd.x = -1;
-        }
-        if (label1 == lefthand || label2 == lefthand) {
-            fwd = 0;
-            fwd.x = 1;
-        }
-    }
-
-    if (free == 0) {
-        if (label1 == rightfoot || label2 == rightfoot) {
-            fwd.y -= .3;
-        }
-        if (label1 == leftfoot || label2 == leftfoot) {
-            fwd.y -= .3;
-        }
-    }
-
-    fwd = DoRotation(fwd, 0, muscles[which].rotate1 - 90, 0);
-    fwd = DoRotation(fwd, 0, 0, muscles[which].rotate2 - 90);
-    fwd.y = 0;
-    fwd /= findLength(&fwd);
-    if (fwd.z <= 1 && fwd.z >= -1)
-        muscles[which].rotate3 = acos(0 - fwd.z);
-    else
-        muscles[which].rotate3 = acos(-1.f);
-    muscles[which].rotate3 *= 360.0 / 6.2831853;
-    if (0 > fwd.x)
-        muscles[which].rotate3 = 360 - muscles[which].rotate3;
-    if (!isnormal(muscles[which].rotate3))
-        muscles[which].rotate3 = 0;
-}
-
-/* EFFECT
- * load an animation from file
- */
-void Animation::Load(const std::string& filename, int aheight, int aattack)
-{
-    FILE *tfile;
-    int i, j;
-    XYZ endoffset;
-
-    LOGFUNC;
-
-    // Changing the filename into something the OS can understand
-    std::string filepath = Folders::getResourcePath("Animations/"+filename);
-
-    LOG(std::string("Loading animation...") + filepath);
-
-    // clear existing data
-    deallocate();
-
-    height = aheight;
-    attack = aattack;
-
-    if (visibleloading)
-        Game::LoadingScreen();
-
-    // read file in binary mode
-    tfile = Folders::openMandatoryFile( filepath, "rb" );
-
-    // read numframes, joints to know how much memory to allocate
-    funpackf(tfile, "Bi Bi", &numframes, &joints);
-
-    // allocate memory for everything
-
-    position = (XYZ**)malloc(sizeof(XYZ*) * joints);
-    for (i = 0; i < joints; i++)
-        position[i] = (XYZ*)malloc(sizeof(XYZ) * numframes);
-
-    twist = (float**)malloc(sizeof(float*) * joints);
-    for (i = 0; i < joints; i++)
-        twist[i] = (float*)malloc(sizeof(float) * numframes);
-
-    twist2 = (float**)malloc(sizeof(float*) * joints);
-    for (i = 0; i < joints; i++)
-        twist2[i] = (float*)malloc(sizeof(float) * numframes);
-
-    speed = (float*)malloc(sizeof(float) * numframes);
-
-    onground = (bool**)malloc(sizeof(bool*) * joints);
-    for (i = 0; i < joints; i++)
-        onground[i] = (bool*)malloc(sizeof(bool) * numframes);
-
-    forward = (XYZ*)malloc(sizeof(XYZ) * numframes);
-    weapontarget = (XYZ*)malloc(sizeof(XYZ) * numframes);
-    label = (int*)malloc(sizeof(int) * numframes);
-
-    // read binary data as animation
-
-    // for each frame...
-    for (i = 0; i < numframes; i++) {
-        // for each joint in the skeleton...
-        for (j = 0; j < joints; j++) {
-            // read joint position
-            funpackf(tfile, "Bf Bf Bf", &position[j][i].x, &position[j][i].y, &position[j][i].z);
-        }
-        for (j = 0; j < joints; j++) {
-            // read twist
-            funpackf(tfile, "Bf", &twist[j][i]);
-        }
-        for (j = 0; j < joints; j++) {
-            // read onground (boolean)
-            unsigned char uch;
-            funpackf(tfile, "Bb", &uch);
-            onground[j][i] = (uch != 0);
-        }
-        // read frame speed (?)
-        funpackf(tfile, "Bf", &speed[i]);
-    }
-    // read twist2 for whole animation
-    for (i = 0; i < numframes; i++) {
-        for (j = 0; j < joints; j++) {
-            funpackf(tfile, "Bf", &twist2[j][i]);
-        }
-    }
-    // read label for each frame
-    for (i = 0; i < numframes; i++) {
-        funpackf(tfile, "Bf", &label[i]);
-    }
-    // read weapontargetnum
-    funpackf(tfile, "Bi", &weapontargetnum);
-    // read weapontarget positions for each frame
-    for (i = 0; i < numframes; i++) {
-        funpackf(tfile, "Bf Bf Bf", &weapontarget[i].x, &weapontarget[i].y, &weapontarget[i].z);
-    }
-
-    fclose(tfile);
-
-    endoffset = 0;
-    // find average position of certain joints on last frames
-    // and save in endoffset
-    // (not sure what exactly this accomplishes. the y < 1 test confuses me.)
-    for (j = 0; j < joints; j++) {
-        if (position[j][numframes - 1].y < 1)
-            endoffset += position[j][numframes - 1];
-    }
-    endoffset /= joints;
-    offset = endoffset;
-    offset.y = 0;
-}
-
-
-/* EFFECT
- * load skeleton
- * takes filenames for three skeleton files and various models
- */
-void Skeleton::Load(const std::string& filename,       const std::string& lowfilename, const std::string& clothesfilename,
-                    const std::string& modelfilename,  const std::string& model2filename,
-                    const std::string& model3filename, const std::string& model4filename,
-                    const std::string& model5filename, const std::string& model6filename,
-                    const std::string& model7filename, const std::string& modellowfilename,
-                    const std::string& modelclothesfilename, bool clothes)
-{
-    GLfloat M[16];
-    int parentID;
-    FILE *tfile;
-    float lSize;
-    int i, j;
-    int edit;
-
-    LOGFUNC;
-
-    num_models = 7;
-
-    // load various models
-    // rotate, scale, do normals, do texcoords for each as needed
-
-    model[0].loadnotex(modelfilename);
-    model[1].loadnotex(model2filename);
-    model[2].loadnotex(model3filename);
-    model[3].loadnotex(model4filename);
-    model[4].loadnotex(model5filename);
-    model[5].loadnotex(model6filename);
-    model[6].loadnotex(model7filename);
-
-    for (i = 0; i < num_models; i++) {
-        model[i].Rotate(180, 0, 0);
-        model[i].Scale(.04, .04, .04);
-        model[i].CalculateNormals(0);
-    }
-
-    drawmodel.load(modelfilename, 0);
-    drawmodel.Rotate(180, 0, 0);
-    drawmodel.Scale(.04, .04, .04);
-    drawmodel.FlipTexCoords();
-    if (tutoriallevel == 1 && id != 0)
-        drawmodel.UniformTexCoords();
-    if (tutoriallevel == 1 && id != 0)
-        drawmodel.ScaleTexCoords(0.1);
-    drawmodel.CalculateNormals(0);
-
-    modellow.loadnotex(modellowfilename);
-    modellow.Rotate(180, 0, 0);
-    modellow.Scale(.04, .04, .04);
-    modellow.CalculateNormals(0);
-
-    drawmodellow.load(modellowfilename, 0);
-    drawmodellow.Rotate(180, 0, 0);
-    drawmodellow.Scale(.04, .04, .04);
-    drawmodellow.FlipTexCoords();
-    if (tutoriallevel == 1 && id != 0)
-        drawmodellow.UniformTexCoords();
-    if (tutoriallevel == 1 && id != 0)
-        drawmodellow.ScaleTexCoords(0.1);
-    drawmodellow.CalculateNormals(0);
-
-    if (clothes) {
-        modelclothes.loadnotex(modelclothesfilename);
-        modelclothes.Rotate(180, 0, 0);
-        modelclothes.Scale(.041, .04, .041);
-        modelclothes.CalculateNormals(0);
-
-        drawmodelclothes.load(modelclothesfilename, 0);
-        drawmodelclothes.Rotate(180, 0, 0);
-        drawmodelclothes.Scale(.04, .04, .04);
-        drawmodelclothes.FlipTexCoords();
-        drawmodelclothes.CalculateNormals(0);
-    }
-
-    // FIXME: three similar blocks follow, one for each of:
-    // filename, lowfilename, clothesfilename
-
-    // load skeleton
-
-    tfile = Folders::openMandatoryFile( Folders::getResourcePath(filename), "rb" );
-
-    // read num_joints
-    funpackf(tfile, "Bi", &num_joints);
-
-    // allocate memory
-    if (joints)
-        delete [] joints; //dealloc2(joints);
-    joints = (Joint*)new Joint[num_joints];
-
-    // read info for each joint
-    for (i = 0; i < num_joints; i++) {
-        funpackf(tfile, "Bf Bf Bf Bf Bf", &joints[i].position.x, &joints[i].position.y, &joints[i].position.z, &joints[i].length, &joints[i].mass);
-        funpackf(tfile, "Bb Bb", &joints[i].hasparent, &joints[i].locked);
-        funpackf(tfile, "Bi", &joints[i].modelnum);
-        funpackf(tfile, "Bb Bb", &joints[i].visible, &joints[i].sametwist);
-        funpackf(tfile, "Bi Bi", &joints[i].label, &joints[i].hasgun);
-        funpackf(tfile, "Bb", &joints[i].lower);
-        funpackf(tfile, "Bi", &parentID);
-        if (joints[i].hasparent)
-            joints[i].parent = &joints[parentID];
-        joints[i].velocity = 0;
-        joints[i].oldposition = joints[i].position;
-    }
-
-    // read num_muscles
-    funpackf(tfile, "Bi", &num_muscles);
-
-    // allocate memory
-    if (muscles)
-        delete [] muscles; //dealloc2(muscles);
-    muscles = (Muscle*)new Muscle[num_muscles]; //malloc(sizeof(Muscle)*num_muscles);
-
-    // for each muscle...
-    for (i = 0; i < num_muscles; i++) {
-        // read info
-        funpackf(tfile, "Bf Bf Bf Bf Bf Bi Bi", &muscles[i].length, &muscles[i].targetlength, &muscles[i].minlength, &muscles[i].maxlength, &muscles[i].strength, &muscles[i].type, &muscles[i].numvertices);
-
-        // allocate memory for vertices
-        muscles[i].vertices = (int*)malloc(sizeof(int) * muscles[i].numvertices);
-
-        // read vertices
-        edit = 0;
-        for (j = 0; j < muscles[i].numvertices - edit; j++) {
-            funpackf(tfile, "Bi", &muscles[i].vertices[j + edit]);
-            if (muscles[i].vertices[j + edit] >= model[0].vertexNum) {
-                muscles[i].numvertices--;
-                edit--;
-            }
-        }
-
-        // read more info
-        funpackf(tfile, "Bb Bi", &muscles[i].visible, &parentID);
-        muscles[i].parent1 = &joints[parentID];
-        funpackf(tfile, "Bi", &parentID);
-        muscles[i].parent2 = &joints[parentID];
-    }
-
-    // read forwardjoints (?)
-    for (j = 0; j < 3; j++) {
-        funpackf(tfile, "Bi", &forwardjoints[j]);
-    }
-    // read lowforwardjoints (?)
-    for (j = 0; j < 3; j++) {
-        funpackf(tfile, "Bi", &lowforwardjoints[j]);
-    }
-
-    // ???
-    for (j = 0; j < num_muscles; j++) {
-        for (i = 0; i < muscles[j].numvertices; i++) {
-            for (int k = 0; k < num_models; k++) {
-                if (muscles[j].numvertices && muscles[j].vertices[i] < model[k].vertexNum)
-                    model[k].owner[muscles[j].vertices[i]] = j;
-            }
-        }
-    }
-
-    // calculate some stuff
-    FindForwards();
-    for (i = 0; i < num_joints; i++) {
-        joints[i].startpos = joints[i].position;
-    }
-    for (i = 0; i < num_muscles; i++) {
-        FindRotationMuscle(i, -1);
-    }
-    // this seems to use opengl purely for matrix calculations
-    for (int k = 0; k < num_models; k++) {
-        for (i = 0; i < model[k].vertexNum; i++) {
-            model[k].vertex[i] = model[k].vertex[i] - (muscles[model[k].owner[i]].parent1->position + muscles[model[k].owner[i]].parent2->position) / 2;
-            glMatrixMode(GL_MODELVIEW);
-            glPushMatrix();
-            glLoadIdentity();
-            glRotatef(muscles[model[k].owner[i]].rotate3, 0, 1, 0);
-            glRotatef(muscles[model[k].owner[i]].rotate2 - 90, 0, 0, 1);
-            glRotatef(muscles[model[k].owner[i]].rotate1 - 90, 0, 1, 0);
-            glTranslatef(model[k].vertex[i].x, model[k].vertex[i].y, model[k].vertex[i].z);
-            glGetFloatv(GL_MODELVIEW_MATRIX, M);
-            model[k].vertex[i].x = M[12] * 1;
-            model[k].vertex[i].y = M[13] * 1;
-            model[k].vertex[i].z = M[14] * 1;
-            glPopMatrix();
-        }
-        model[k].CalculateNormals(0);
-    }
-    fclose(tfile);
-
-    // load ???
-
-    tfile = Folders::openMandatoryFile( Folders::getResourcePath(lowfilename), "rb" );
-
-    // skip joints section
-
-    lSize = sizeof(num_joints);
-    fseek(tfile, lSize, SEEK_CUR);
-    for (i = 0; i < num_joints; i++) {
-        // skip joint info
-        lSize = sizeof(XYZ)
-                + sizeof(float)
-                + sizeof(float)
-                + 1 //sizeof(bool)
-                + 1 //sizeof(bool)
-                + sizeof(int)
-                + 1 //sizeof(bool)
-                + 1 //sizeof(bool)
-                + sizeof(int)
-                + sizeof(int)
-                + 1 //sizeof(bool)
-                + sizeof(int);
-        fseek(tfile, lSize, SEEK_CUR);
-
-        if (joints[i].hasparent)
-            joints[i].parent = &joints[parentID];
-        joints[i].velocity = 0;
-        joints[i].oldposition = joints[i].position;
-    }
-
-    // read num_muscles
-    funpackf(tfile, "Bi", &num_muscles);
-
-    for (i = 0; i < num_muscles; i++) {
-        // skip muscle info
-        lSize = sizeof(float)
-                + sizeof(float)
-                + sizeof(float)
-                + sizeof(float)
-                + sizeof(float)
-                + sizeof(int);
-        fseek(tfile, lSize, SEEK_CUR);
-
-        // read numverticeslow
-        funpackf(tfile, "Bi", &muscles[i].numverticeslow);
-
-        if (muscles[i].numverticeslow) {
-            // allocate memory
-            muscles[i].verticeslow = (int*)malloc(sizeof(int) * muscles[i].numverticeslow);
-
-            // read verticeslow
-            edit = 0;
-            for (j = 0; j < muscles[i].numverticeslow - edit; j++) {
-                funpackf(tfile, "Bi", &muscles[i].verticeslow[j + edit]);
-                if (muscles[i].verticeslow[j + edit] >= modellow.vertexNum) {
-                    muscles[i].numverticeslow--;
-                    edit--;
-                }
-            }
-        }
-
-        // skip more stuff
-        lSize = 1; //sizeof(bool);
-        fseek ( tfile, lSize, SEEK_CUR);
-        lSize = sizeof(int);
-        fseek ( tfile, lSize, SEEK_CUR);
-        fseek ( tfile, lSize, SEEK_CUR);
-    }
-
-    for (j = 0; j < num_muscles; j++) {
-        for (i = 0; i < muscles[j].numverticeslow; i++) {
-            if (muscles[j].verticeslow[i] < modellow.vertexNum)
-                modellow.owner[muscles[j].verticeslow[i]] = j;
-        }
-    }
-
-    // use opengl for its matrix math
-    for (i = 0; i < modellow.vertexNum; i++) {
-        modellow.vertex[i] = modellow.vertex[i] - (muscles[modellow.owner[i]].parent1->position + muscles[modellow.owner[i]].parent2->position) / 2;
-        glMatrixMode(GL_MODELVIEW);
-        glPushMatrix();
-        glLoadIdentity();
-        glRotatef(muscles[modellow.owner[i]].rotate3, 0, 1, 0);
-        glRotatef(muscles[modellow.owner[i]].rotate2 - 90, 0, 0, 1);
-        glRotatef(muscles[modellow.owner[i]].rotate1 - 90, 0, 1, 0);
-        glTranslatef(modellow.vertex[i].x, modellow.vertex[i].y, modellow.vertex[i].z);
-        glGetFloatv(GL_MODELVIEW_MATRIX, M);
-        modellow.vertex[i].x = M[12];
-        modellow.vertex[i].y = M[13];
-        modellow.vertex[i].z = M[14];
-        glPopMatrix();
-    }
-
-    modellow.CalculateNormals(0);
-
-    // load clothes
-
-    if (clothes) {
-        tfile = Folders::openMandatoryFile( Folders::getResourcePath(clothesfilename), "rb" );
-
-        // skip num_joints
-        lSize = sizeof(num_joints);
-        fseek ( tfile, lSize, SEEK_CUR);
-
-        for (i = 0; i < num_joints; i++) {
-            // skip joint info
-            lSize = sizeof(XYZ)
-                    + sizeof(float)
-                    + sizeof(float)
-                    + 1 //sizeof(bool)
-                    + 1 //sizeof(bool)
-                    + sizeof(int)
-                    + 1 //sizeof(bool)
-                    + 1 //sizeof(bool)
-                    + sizeof(int)
-                    + sizeof(int)
-                    + 1 //sizeof(bool)
-                    + sizeof(int);
-            fseek(tfile, lSize, SEEK_CUR);
-
-            if (joints[i].hasparent)
-                joints[i].parent = &joints[parentID];
-            joints[i].velocity = 0;
-            joints[i].oldposition = joints[i].position;
-        }
-
-        // read num_muscles
-        funpackf(tfile, "Bi", &num_muscles);
-
-        for (i = 0; i < num_muscles; i++) {
-            // skip muscle info
-            lSize = sizeof(float)
-                    + sizeof(float)
-                    + sizeof(float)
-                    + sizeof(float)
-                    + sizeof(float)
-                    + sizeof(int);
-            fseek(tfile, lSize, SEEK_CUR);
-
-            // read numverticesclothes
-            funpackf(tfile, "Bi", &muscles[i].numverticesclothes);
-
-            // read verticesclothes
-            if (muscles[i].numverticesclothes) {
-                muscles[i].verticesclothes = (int*)malloc(sizeof(int) * muscles[i].numverticesclothes);
-                edit = 0;
-                for (j = 0; j < muscles[i].numverticesclothes - edit; j++) {
-                    funpackf(tfile, "Bi", &muscles[i].verticesclothes[j + edit]);
-                    if (muscles[i].verticesclothes[j + edit] >= modelclothes.vertexNum) {
-                        muscles[i].numverticesclothes--;
-                        edit--;
-                    }
-                }
-            }
-
-            // skip more stuff
-            lSize = 1; //sizeof(bool);
-            fseek ( tfile, lSize, SEEK_CUR);
-            lSize = sizeof(int);
-            fseek ( tfile, lSize, SEEK_CUR);
-            fseek ( tfile, lSize, SEEK_CUR);
-        }
-
-        // ???
-        lSize = sizeof(int);
-        for (j = 0; j < num_muscles; j++) {
-            for (i = 0; i < muscles[j].numverticesclothes; i++) {
-                if (muscles[j].numverticesclothes && muscles[j].verticesclothes[i] < modelclothes.vertexNum)
-                    modelclothes.owner[muscles[j].verticesclothes[i]] = j;
-            }
-        }
-
-        // use opengl for its matrix math
-        for (i = 0; i < modelclothes.vertexNum; i++) {
-            modelclothes.vertex[i] = modelclothes.vertex[i] - (muscles[modelclothes.owner[i]].parent1->position + muscles[modelclothes.owner[i]].parent2->position) / 2;
-            glMatrixMode(GL_MODELVIEW);
-            glPushMatrix();
-            glLoadIdentity();
-            glRotatef(muscles[modelclothes.owner[i]].rotate3, 0, 1, 0);
-            glRotatef(muscles[modelclothes.owner[i]].rotate2 - 90, 0, 0, 1);
-            glRotatef(muscles[modelclothes.owner[i]].rotate1 - 90, 0, 1, 0);
-            glTranslatef(modelclothes.vertex[i].x, modelclothes.vertex[i].y, modelclothes.vertex[i].z);
-            glGetFloatv(GL_MODELVIEW_MATRIX, M);
-            modelclothes.vertex[i].x = M[12];
-            modelclothes.vertex[i].y = M[13];
-            modelclothes.vertex[i].z = M[14];
-            glPopMatrix();
-        }
-
-        modelclothes.CalculateNormals(0);
-    }
-    fclose(tfile);
-
-    for (i = 0; i < num_joints; i++) {
-        for (j = 0; j < num_joints; j++) {
-            if (joints[i].label == j)
-                jointlabels[j] = i;
-        }
-    }
-
-    free = 0;
-}
-
-Animation::Animation()
-{
-    numframes = 0;
-    height = 0;
-    attack = 0;
-    joints = 0;
-    weapontargetnum = 0;
-
-    position = 0;
-    twist = 0;
-    twist2 = 0;
-    speed = 0;
-    onground = 0;
-    forward = 0;
-    label = 0;
-    weapontarget = 0;
-}
-
-Animation::~Animation()
-{
-    deallocate();
-}
-
-void Animation::deallocate()
-{
-    int i = 0;
-
-    if (position) {
-        for (i = 0; i < joints; i++)
-            dealloc2(position[i]);
-
-        dealloc2(position);
-    }
-    position = 0;
-
-    if (twist) {
-        for (i = 0; i < joints; i++)
-            dealloc2(twist[i]);
-
-        dealloc2(twist);
-    }
-    twist = 0;
-
-    if (twist2) {
-        for (i = 0; i < joints; i++)
-            dealloc2(twist2[i]);
-
-        dealloc2(twist2);
-    }
-    twist2 = 0;
-
-    if (onground) {
-        for (i = 0; i < joints; i++)
-            dealloc2(onground[i]);
-
-        dealloc2(onground);
-    }
-    onground = 0;
-
-    if (speed)
-        dealloc2(speed);
-    speed = 0;
-
-    if (forward)
-        dealloc2(forward);
-    forward = 0;
-
-    if (weapontarget)
-        dealloc2(weapontarget);
-    weapontarget = 0;
-
-    if (label)
-        dealloc2(label);
-    label = 0;
-
-    joints = 0;
-}
-
-Skeleton::Skeleton()
-{
-    num_joints = 0;
-
-    num_muscles = 0;
-
-    selected = 0;
-
-    memset(forwardjoints, 0, sizeof(forwardjoints));
-    // XYZ forward;
-
-    id = 0;
-
-    memset(lowforwardjoints, 0, sizeof(lowforwardjoints));
-    // XYZ lowforward;
-
-    // XYZ specialforward[5];
-    memset(jointlabels, 0, sizeof(jointlabels));
-
-    // Model model[7];
-    // Model modellow;
-    // Model modelclothes;
-    num_models = 0;
-
-    // Model drawmodel;
-    // Model drawmodellow;
-    // Model drawmodelclothes;
-
-    clothes = 0;
-    spinny = 0;
-
-    memset(skinText, 0, sizeof(skinText));
-    skinsize = 0;
-
-    checkdelay = 0;
-
-    longdead = 0;
-    broken = 0;
-
-    free = 0;
-    oldfree = 0;
-    freetime = 0;
-    freefall = 0;
-
-    joints = 0;
-    muscles = 0;
-}
-
-Skeleton::~Skeleton()
-{
-    if (muscles) {
-        delete [] muscles;
-    }
-    muscles = 0;
-
-    if (joints) {
-        delete [] joints;
-    }
-    joints = 0;
-}
-
-Muscle::Muscle()
-{
-    vertices = 0;
-    verticeslow = 0;
-    verticesclothes = 0;
-
-    numvertices = 0;
-    numverticeslow = 0;
-    numverticesclothes = 0;
-    length = 0;
-    targetlength = 0;
-    parent1 = 0;
-    parent2 = 0;
-    maxlength = 0;
-    minlength = 0;
-    type = 0;
-    visible = 0;
-    rotate1 = 0, rotate2 = 0, rotate3 = 0;
-    lastrotate1 = 0, lastrotate2 = 0, lastrotate3 = 0;
-    oldrotate1 = 0, oldrotate2 = 0, oldrotate3 = 0;
-    newrotate1 = 0, newrotate2 = 0, newrotate3 = 0;
-
-    strength = 0;
-}
-
-Muscle::~Muscle()
-{
-    dealloc2(vertices);
-    dealloc2(verticeslow);
-    dealloc2(verticesclothes);
-}
-
-Animation & Animation::operator = (const Animation & ani)
-{
-    int i = 0;
-
-    bool allocate = ((ani.numframes != numframes) || (ani.joints != joints));
-
-    if (allocate)
-        deallocate();
-
-    numframes = ani.numframes;
-    height = ani.height;
-    attack = ani.attack;
-    joints = ani.joints;
-    weapontargetnum = ani.weapontargetnum;
-    offset = ani.offset;
-
-    if (allocate)
-        position = (XYZ**)malloc(sizeof(XYZ*)*ani.joints);
-    for (i = 0; i < ani.joints; i++) {
-        if (allocate)
-            position[i] = (XYZ*)malloc(sizeof(XYZ) * ani.numframes);
-        memcpy(position[i], ani.position[i], sizeof(XYZ)*ani.numframes);
-    }
-
-    if (allocate)
-        twist = (float**)malloc(sizeof(float*)*ani.joints);
-    for (i = 0; i < ani.joints; i++) {
-        if (allocate)
-            twist[i] = (float*)malloc(sizeof(float) * ani.numframes);
-        memcpy(twist[i], ani.twist[i], sizeof(float)*ani.numframes);
-    }
-
-    if (allocate)
-        twist2 = (float**)malloc(sizeof(float*)*ani.joints);
-    for (i = 0; i < ani.joints; i++) {
-        if (allocate)
-            twist2[i] = (float*)malloc(sizeof(float) * ani.numframes);
-        memcpy(twist2[i], ani.twist2[i], sizeof(float)*ani.numframes);
-    }
-
-    if (allocate)
-        speed = (float*)malloc(sizeof(float) * ani.numframes);
-    memcpy(speed, ani.speed, sizeof(float)*ani.numframes);
-
-    if (allocate)
-        onground = (bool**)malloc(sizeof(bool*)*ani.joints);
-    for (i = 0; i < ani.joints; i++) {
-        if (allocate)
-            onground[i] = (bool*)malloc(sizeof(bool) * ani.numframes);
-        memcpy(onground[i], ani.onground[i], sizeof(bool)*ani.numframes);
-    }
-
-    if (allocate)
-        forward = (XYZ*)malloc(sizeof(XYZ) * ani.numframes);
-    memcpy(forward, ani.forward, sizeof(XYZ)*ani.numframes);
-
-    if (allocate)
-        weapontarget = (XYZ*)malloc(sizeof(XYZ) * ani.numframes);
-    memcpy(weapontarget, ani.weapontarget, sizeof(XYZ)*ani.numframes);
-
-    if (allocate)
-        label = (int*)malloc(sizeof(int) * ani.numframes);
-    memcpy(label, ani.label, sizeof(int)*ani.numframes);
-
-    return (*this);
-}
-
-
-
-
-#if 0
-
-// the following functions are not used anywhere
-
-/* EFFECT
- * sets forward, lowforward, specialforward[]
- *
- * USES:
- * NONE
- */
-void Skeleton::FindForwardsfirst()
-{
-    //Find forward vectors
-    CrossProduct(joints[forwardjoints[1]].position - joints[forwardjoints[0]].position, joints[forwardjoints[2]].position - joints[forwardjoints[0]].position, &forward);
-    Normalise(&forward);
-
-    CrossProduct(joints[lowforwardjoints[1]].position - joints[lowforwardjoints[0]].position, joints[lowforwardjoints[2]].position - joints[lowforwardjoints[0]].position, &lowforward);
-    Normalise(&lowforward);
-
-    //Special forwards
-    specialforward[0] = forward;
-    specialforward[1] = forward;
-    specialforward[2] = forward;
-    specialforward[3] = forward;
-    specialforward[4] = forward;
-
-}
-
-/* EFFECT
- *
- * USES:
- * NONE
- */
-void Skeleton::Draw(int muscleview)
-{
-    static float jointcolor[4];
-
-    if (muscleview != 2) {
-        jointcolor[0] = 0;
-        jointcolor[1] = 0;
-        jointcolor[2] = .5;
-        jointcolor[3] = 1;
-    }
-
-    if (muscleview == 2) {
-        jointcolor[0] = 0;
-        jointcolor[1] = 0;
-        jointcolor[2] = 0;
-        jointcolor[3] = .5;
-    }
-    //Calc motionblur-ness
-    for (int i = 0; i < num_joints; i++) {
-        joints[i].oldposition = joints[i].position;
-        joints[i].blurred = findDistance(&joints[i].position, &joints[i].oldposition) * 100;
-        if (joints[i].blurred < 1)
-            joints[i].blurred = 1;
-    }
-
-    //Do Motionblur
-    glDepthMask(0);
-    glEnable(GL_BLEND);
-    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-    glBegin(GL_QUADS);
-    for (int i = 0; i < num_joints; i++) {
-        if (joints[i].hasparent) {
-            glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / joints[i].blurred);
-            glVertex3f(joints[i].position.x, joints[i].position.y, joints[i].position.z);
-            glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / joints[i].parent->blurred);
-            glVertex3f(joints[i].parent->position.x, joints[i].parent->position.y, joints[i].parent->position.z);
-            glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / joints[i].parent->blurred);
-            glVertex3f(joints[i].parent->oldposition.x, joints[i].parent->oldposition.y, joints[i].parent->oldposition.z);
-            glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / joints[i].blurred);
-            glVertex3f(joints[i].oldposition.x, joints[i].oldposition.y, joints[i].oldposition.z);
-        }
-    }
-    for (int i = 0; i < num_muscles; i++) {
-        if (muscles[i].type == boneconnect) {
-            glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / muscles[i].parent2->blurred);
-            glVertex3f(muscles[i].parent1->position.x, muscles[i].parent1->position.y, muscles[i].parent1->position.z);
-            glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / muscles[i].parent2->blurred);
-            glVertex3f(muscles[i].parent2->position.x, muscles[i].parent2->position.y, muscles[i].parent2->position.z);
-            glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / muscles[i].parent2->blurred);
-            glVertex3f(muscles[i].parent2->oldposition.x, muscles[i].parent2->oldposition.y, muscles[i].parent2->oldposition.z);
-            glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / muscles[i].parent1->blurred);
-            glVertex3f(muscles[i].parent1->oldposition.x, muscles[i].parent1->oldposition.y, muscles[i].parent1->oldposition.z);
-        }
-    }
-    glEnd();
-
-    glBegin(GL_LINES);
-    for (int i = 0; i < num_joints; i++) {
-        if (joints[i].hasparent) {
-            glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / joints[i].blurred);
-            glVertex3f(joints[i].position.x, joints[i].position.y, joints[i].position.z);
-            glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / joints[i].parent->blurred);
-            glVertex3f(joints[i].parent->position.x, joints[i].parent->position.y, joints[i].parent->position.z);
-        }
-    }
-    for (int i = 0; i < num_muscles; i++) {
-        if (muscles[i].type == boneconnect) {
-            glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / muscles[i].parent1->blurred);
-            glVertex3f(muscles[i].parent1->position.x, muscles[i].parent1->position.y, muscles[i].parent1->position.z);
-            glColor4f(jointcolor[0], jointcolor[1], jointcolor[2], jointcolor[3] / muscles[i].parent2->blurred);
-            glVertex3f(muscles[i].parent2->position.x, muscles[i].parent2->position.y, muscles[i].parent2->position.z);
-        }
-    }
-    glColor3f(.6, .6, 0);
-    if (muscleview == 1)
-        for (int i = 0; i < num_muscles; i++) {
-            if (muscles[i].type != boneconnect) {
-                glVertex3f(muscles[i].parent1->position.x, muscles[i].parent1->position.y, muscles[i].parent1->position.z);
-                glVertex3f(muscles[i].parent2->position.x, muscles[i].parent2->position.y, muscles[i].parent2->position.z);
-            }
-        }
-    glEnd();
-
-    if (muscleview != 2) {
-        glPointSize(3);
-        glBegin(GL_POINTS);
-        for (int i = 0; i < num_joints; i++) {
-            if (i != selected)
-                glColor4f(0, 0, .5, 1);
-            if (i == selected)
-                glColor4f(1, 1, 0, 1);
-            if (joints[i].locked && i != selected)
-                glColor4f(1, 0, 0, 1);
-            glVertex3f(joints[i].position.x, joints[i].position.y, joints[i].position.z);
-        }
-        glEnd();
-    }
-
-    //Set old position to current position
-    if (muscleview == 2)
-        for (int i = 0; i < num_joints; i++) {
-            joints[i].oldposition = joints[i].position;
-        }
-    glDepthMask(1);
-}
-
-/* EFFECT
- *
- * USES:
- * NONE
- */
-void Skeleton::AddJoint(float x, float y, float z, int which)
-{
-    if (num_joints < max_joints - 1) {
-        joints[num_joints].velocity = 0;
-        joints[num_joints].position.x = x;
-        joints[num_joints].position.y = y;
-        joints[num_joints].position.z = z;
-        joints[num_joints].mass = 1;
-        joints[num_joints].locked = 0;
-
-        joints[num_joints].hasparent = 0;
-        num_joints++;
-        if (which < num_joints && which >= 0)
-            AddMuscle(num_joints - 1, which, 0, 10, boneconnect);
-    }
-}
-
-/* EFFECT
- *
- * USES:
- * NONE
- */
-void Skeleton::DeleteJoint(int whichjoint)
-{
-    if (whichjoint < num_joints && whichjoint >= 0) {
-        joints[whichjoint].velocity = joints[num_joints - 1].velocity;
-        joints[whichjoint].position = joints[num_joints - 1].position;
-        joints[whichjoint].oldposition = joints[num_joints - 1].oldposition;
-        joints[whichjoint].hasparent = joints[num_joints - 1].hasparent;
-        joints[whichjoint].parent = joints[num_joints - 1].parent;
-        joints[whichjoint].length = joints[num_joints - 1].length;
-        joints[whichjoint].locked = joints[num_joints - 1].locked;
-        joints[whichjoint].modelnum = joints[num_joints - 1].modelnum;
-        joints[whichjoint].visible = joints[num_joints - 1].visible;
-
-        for (int i = 0; i < num_muscles; i++) {
-            while (muscles[i].parent1 == &joints[whichjoint] && i < num_muscles)DeleteMuscle(i);
-            while (muscles[i].parent2 == &joints[whichjoint] && i < num_muscles)DeleteMuscle(i);
-        }
-        for (int i = 0; i < num_muscles; i++) {
-            while (muscles[i].parent1 == &joints[num_joints - 1] && i < num_muscles)muscles[i].parent1 = &joints[whichjoint];
-            while (muscles[i].parent2 == &joints[num_joints - 1] && i < num_muscles)muscles[i].parent2 = &joints[whichjoint];
-        }
-        for (int i = 0; i < num_joints; i++) {
-            if (joints[i].parent == &joints[whichjoint])
-                joints[i].hasparent = 0;
-        }
-        for (int i = 0; i < num_joints; i++) {
-            if (joints[i].parent == &joints[num_joints - 1])
-                joints[i].parent = &joints[whichjoint];
-        }
-
-        num_joints--;
-    }
-}
-
-/* EFFECT
- *
- * USES:
- * Skeleton::DeleteJoint - UNUSED
- */
-void Skeleton::DeleteMuscle(int whichmuscle)
-{
-    if (whichmuscle < num_muscles) {
-        muscles[whichmuscle].minlength = muscles[num_muscles - 1].minlength;
-        muscles[whichmuscle].maxlength = muscles[num_muscles - 1].maxlength;
-        muscles[whichmuscle].strength = muscles[num_muscles - 1].strength;
-        muscles[whichmuscle].parent1 = muscles[num_muscles - 1].parent1;
-        muscles[whichmuscle].parent2 = muscles[num_muscles - 1].parent2;
-        muscles[whichmuscle].length = muscles[num_muscles - 1].length;
-        muscles[whichmuscle].visible = muscles[num_muscles - 1].visible;
-        muscles[whichmuscle].type = muscles[num_muscles - 1].type;
-        muscles[whichmuscle].targetlength = muscles[num_muscles - 1].targetlength;
-
-        num_muscles--;
-    }
-}
-
-/* EFFECT
- *
- * USES:
- * NONE
- */
-void Skeleton::SetJoint(float x, float y, float z, int which, int whichjoint)
-{
-    if (whichjoint < num_joints) {
-        joints[whichjoint].velocity = 0;
-        joints[whichjoint].position.x = x;
-        joints[whichjoint].position.y = y;
-        joints[whichjoint].position.z = z;
-
-        if (which >= num_joints || which < 0)
-            joints[whichjoint].hasparent = 0;
-        if (which < num_joints && which >= 0) {
-            joints[whichjoint].parent = &joints[which];
-            joints[whichjoint].hasparent = 1;
-            joints[whichjoint].length = findDistance(&joints[whichjoint].position, &joints[whichjoint].parent->position);
-        }
-    }
-}
-
-/* EFFECT
- *
- * USES:
- * Skeleton::AddJoint - UNUSED
- */
-void Skeleton::AddMuscle(int attach1, int attach2, float minlength, float maxlength, int type)
-{
-    const int max_muscles = 100; // FIXME: Probably can be dropped
-    if (num_muscles < max_muscles - 1 && attach1 < num_joints && attach1 >= 0 && attach2 < num_joints && attach2 >= 0 && attach1 != attach2) {
-        muscles[num_muscles].parent1 = &joints[attach1];
-        muscles[num_muscles].parent2 = &joints[attach2];
-        muscles[num_muscles].length = findDistance(&muscles[num_muscles].parent1->position, &muscles[num_muscles].parent2->position);
-        muscles[num_muscles].targetlength = findDistance(&muscles[num_muscles].parent1->position, &muscles[num_muscles].parent2->position);
-        muscles[num_muscles].strength = .7;
-        muscles[num_muscles].type = type;
-        muscles[num_muscles].minlength = minlength;
-        muscles[num_muscles].maxlength = maxlength;
-
-        num_muscles++;
-    }
-}
-
-/* EFFECT
- *
- * USES:
- * NONE
- */
-void Skeleton::MusclesSet()
-{
-    for (int i = 0; i < num_muscles; i++) {
-        muscles[i].length = findDistance(&muscles[i].parent1->position, &muscles[i].parent2->position);
-    }
-}
-
-/* EFFECT
- *
- * USES:
- * NONE
- */
-void Skeleton::DoBalance()
-{
-    /*XYZ newpoint;
-    newpoint=joints[0].position;
-    newpoint.x=(joints[2].position.x+joints[4].position.x)/2;
-    newpoint.z=(joints[2].position.z+joints[4].position.z)/2;
-    joints[0].velocity=joints[0].velocity+(newpoint-joints[0].position);
-    //Move child point to within certain distance of parent point
-    joints[0].position=newpoint;
-
-    MusclesSet();*/
-}
-
-#endif
-
diff --git a/Source/Skeleton.h b/Source/Skeleton.h
deleted file mode 100644 (file)
index eb2afff..0000000
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
-Copyright (C) 2003, 2010 - Wolfire Games
-Copyright (C) 2010-2016 - Lugaru contributors (see AUTHORS file)
-
-This file is part of Lugaru.
-
-Lugaru is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-Lugaru is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Lugaru.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _SKELETON_H_
-#define _SKELETON_H_
-
-#include "Models.h"
-#include "Quaternions.h"
-
-
-/**> HEADER FILES <**/
-#include "gamegl.h"
-#include "Quaternions.h"
-#include "Objects.h"
-#include "Sprite.h"
-#include "binio.h"
-
-enum bodyparts {
-    head, neck,
-    leftshoulder,  leftelbow,  leftwrist,  lefthand,
-    rightshoulder, rightelbow, rightwrist, righthand,
-    abdomen, lefthip, righthip, groin,
-    leftknee,  leftankle,  leftfoot,
-    rightknee, rightankle, rightfoot
-};
-
-class Joint
-{
-public:
-    XYZ position;
-    XYZ oldposition;
-    XYZ realoldposition;
-    XYZ velocity;
-    XYZ oldvelocity;
-    XYZ startpos;
-    float blurred;
-    float length;
-    float mass;
-    bool lower;
-    bool hasparent;
-    bool locked;
-    int modelnum;
-    bool visible;
-    Joint* parent;
-    bool sametwist;
-    int label;
-    int hasgun;
-    float delay;
-    XYZ velchange;
-
-    Joint() {
-        blurred = 0;
-        length = 0;
-        mass = 0;
-        lower = 0;
-        hasparent = 0;
-        locked = 0;
-        modelnum = 0;
-        visible = 0;
-        parent = 0;
-        sametwist = 0;
-        label = 0;
-        hasgun = 0;
-        delay = 0;
-    }
-};
-
-class Muscle
-{
-public:
-    int numvertices;
-    int* vertices;
-    int numverticeslow;
-    int* verticeslow;
-    int numverticesclothes;
-    int* verticesclothes;
-    float length;
-    float targetlength;
-    Joint* parent1;
-    Joint* parent2;
-    float maxlength;
-    float minlength;
-    int type;
-    bool visible;
-    float rotate1, rotate2, rotate3;
-    float lastrotate1, lastrotate2, lastrotate3;
-    float oldrotate1, oldrotate2, oldrotate3;
-    float newrotate1, newrotate2, newrotate3;
-
-    float strength;
-
-    Muscle();
-    ~Muscle();
-    void DoConstraint(bool spinny);
-};
-
-class Animation
-{
-public:
-    int numframes;
-    int height;
-    int attack;
-    int joints;
-    int weapontargetnum;
-
-    XYZ**  position;
-    float** twist;
-    float** twist2;
-    float* speed;
-    bool** onground;
-    XYZ* forward;
-    int* label;
-    XYZ* weapontarget;
-
-    XYZ offset;
-
-    Animation();
-    ~Animation();
-    Animation & operator = (const Animation & ani);
-
-    void Load(const std::string& fileName, int aheight, int aattack);
-
-protected:
-    void deallocate();
-};
-
-
-const int max_joints = 50;
-
-class Skeleton
-{
-public:
-    int num_joints;
-    //Joint joints[max_joints];
-    //Joint *joints;
-    Joint* joints;
-
-    int num_muscles;
-    //Muscle muscles[max_muscles];
-    //Muscle *muscles;
-    Muscle* muscles;
-
-    int selected;
-
-    int forwardjoints[3];
-    XYZ forward;
-
-    int id;
-
-    int lowforwardjoints[3];
-    XYZ lowforward;
-
-    XYZ specialforward[5];
-    int jointlabels[max_joints];
-
-    Model model[7];
-    Model modellow;
-    Model modelclothes;
-    int num_models;
-
-    Model drawmodel;
-    Model drawmodellow;
-    Model drawmodelclothes;
-
-    bool clothes;
-    bool spinny;
-
-    GLubyte skinText[512 * 512 * 3];
-    int skinsize;
-
-    float checkdelay;
-
-    float longdead;
-    bool broken;
-
-    int free;
-    int oldfree;
-    float freetime;
-    bool freefall;
-
-    void FindForwards();
-    float DoConstraints(XYZ *coords, float *scale);
-    void DoGravity(float *scale);
-    void FindRotationJoint(int which);
-    void FindRotationJointSameTwist(int which);
-    void FindRotationMuscle(int which, int animation);
-    void Load(const std::string& fileName, const std::string& lowfileName, const std::string& clothesfileName, const std::string& modelfileName, const std::string& model2fileName, const std::string& model3fileName, const std::string& model4fileName, const std::string& model5fileNamee, const std::string& model6fileName, const std::string& model7fileName, const std::string& modellowfileName, const std::string& modelclothesfileName, bool aclothes);
-
-    /*
-    // unused
-    void FindForwardsfirst();
-    void Draw(int muscleview);
-    void AddJoint(float x, float y, float z, int which);
-    void SetJoint(float x, float y, float z, int which, int whichjoint);
-    void DeleteJoint(int whichjoint);
-    void AddMuscle(int attach1, int attach2, float maxlength, float minlength, int type);
-    void DeleteMuscle(int whichmuscle);
-    void DoBalance();
-    void MusclesSet();
-    */
-
-    Skeleton();
-    ~Skeleton();
-
-private:
-    // convenience functions
-    // only for Skeleton.cpp
-    inline Joint& joint(int bodypart) { return joints[jointlabels[bodypart]]; }
-    inline XYZ& jointPos(int bodypart) { return joint(bodypart).position; }
-    inline XYZ& jointVel(int bodypart) { return joint(bodypart).velocity; }
-
-};
-
-#endif
index 7b694a1b69851102a8dd41a466fe2a607a969829..35f73c291be888e57fe7db026f26a266f87afe20 100644 (file)
@@ -23,7 +23,7 @@ along with Lugaru.  If not, see <http://www.gnu.org/licenses/>.
 /**> HEADER FILES <**/
 #include "Weapons.h"
 #include "openal_wrapper.h"
-#include "Animation.h"
+#include "Animation/Animation.h"
 #include "Sounds.h"
 #include "Game.h"
 #include "Awards.h"
@@ -271,7 +271,7 @@ void Weapon::DoStuff(int i)
 
                             emit_sound_at(fleshstabsound, position, 128.);
 
-                            if (animation[Person::players[0]->animTarget].height == highheight)
+                            if (Animation::animations[Person::players[0]->animTarget].height == highheight)
                                 award_bonus(0, ninja);
                             else
                                 award_bonus(0, Bullseyebonus);
index 5954d8ff69ac82ac8853d7dd0e56781ead335763..74725413b47f02a970f79167390e0bec67d714a9 100644 (file)
@@ -25,7 +25,7 @@ along with Lugaru.  If not, see <http://www.gnu.org/licenses/>.
 
 #include "gamegl.h"
 #include "Quaternions.h"
-#include "Skeleton.h"
+#include "Animation/Skeleton.h"
 #include "Models.h"
 #include "Terrain.h"
 #include "Sprite.h"