${SRCDIR}/Animation/Joint.cpp
${SRCDIR}/Animation/Muscle.cpp
${SRCDIR}/Animation/Skeleton.cpp
- ${SRCDIR}/Frustum.cpp
- ${SRCDIR}/Account.cpp
- ${SRCDIR}/Campaign.cpp
- ${SRCDIR}/ConsoleCmds.cpp
- ${SRCDIR}/Dialog.cpp
- ${SRCDIR}/Hotspot.cpp
+ ${SRCDIR}/Audio/openal_wrapper.cpp
+ ${SRCDIR}/Audio/Sounds.cpp
+ ${SRCDIR}/Devtools/ConsoleCmds.cpp
+ ${SRCDIR}/Environment/Lights.cpp
+ ${SRCDIR}/Environment/Skybox.cpp
+ ${SRCDIR}/Environment/Terrain.cpp
+ ${SRCDIR}/Graphic/Models.cpp
+ ${SRCDIR}/Graphic/Sprite.cpp
+ ${SRCDIR}/Graphic/Stereo.cpp
+ ${SRCDIR}/Graphic/Text.cpp
+ ${SRCDIR}/Graphic/Texture.cpp
+ ${SRCDIR}/Level/Awards.cpp
+ ${SRCDIR}/Level/Campaign.cpp
+ ${SRCDIR}/Level/Dialog.cpp
+ ${SRCDIR}/Level/Hotspot.cpp
+ ${SRCDIR}/Math/Frustum.cpp
+ ${SRCDIR}/Math/Quaternions.cpp
+ ${SRCDIR}/Menu/Menu.cpp
+ ${SRCDIR}/Objects/Objects.cpp
+ ${SRCDIR}/Objects/Person.cpp
+ ${SRCDIR}/Objects/Weapons.cpp
+ ${SRCDIR}/User/Account.cpp
+ ${SRCDIR}/User/Settings.cpp
+ ${SRCDIR}/Utils/Folders.cpp
+ ${SRCDIR}/Utils/ImageIO.cpp
+ ${SRCDIR}/Utils/Input.cpp
+ ${SRCDIR}/Utils/pack.c
+ ${SRCDIR}/Utils/private.c
+ ${SRCDIR}/Utils/unpack.c
${SRCDIR}/Game.cpp
${SRCDIR}/GameDraw.cpp
${SRCDIR}/GameInitDispose.cpp
${SRCDIR}/GameTick.cpp
${SRCDIR}/Globals.cpp
- ${SRCDIR}/Lights.cpp
- ${SRCDIR}/Menu.cpp
- ${SRCDIR}/Models.cpp
- ${SRCDIR}/Objects.cpp
- ${SRCDIR}/pack.c
- ${SRCDIR}/Person.cpp
- ${SRCDIR}/private.c
- ${SRCDIR}/Quaternions.cpp
- ${SRCDIR}/Skybox.cpp
- ${SRCDIR}/Sprite.cpp
- ${SRCDIR}/Terrain.cpp
- ${SRCDIR}/Texture.cpp
- ${SRCDIR}/Text.cpp
- ${SRCDIR}/ImageIO.cpp
- ${SRCDIR}/unpack.c
- ${SRCDIR}/Weapons.cpp
- ${SRCDIR}/openal_wrapper.cpp
- ${SRCDIR}/Input.cpp
- ${SRCDIR}/Settings.cpp
- ${SRCDIR}/Stereo.cpp
- ${SRCDIR}/Sounds.cpp
- ${SRCDIR}/Awards.cpp
- ${SRCDIR}/Utils/Folders.cpp
+
)
set(LUGARU_H
${SRCDIR}/Animation/Joint.h
${SRCDIR}/Animation/Muscle.h
${SRCDIR}/Animation/Skeleton.h
- ${SRCDIR}/Frustum.h
- ${SRCDIR}/Account.h
- ${SRCDIR}/Campaign.h
- ${SRCDIR}/ConsoleCmds.h
- ${SRCDIR}/Dialog.h
- ${SRCDIR}/Hotspot.h
- ${SRCDIR}/Game.h
- ${SRCDIR}/Lights.h
- ${SRCDIR}/Menu.h
- ${SRCDIR}/Models.h
- ${SRCDIR}/Objects.h
- ${SRCDIR}/Person.h
- ${SRCDIR}/PhysicsMath.h
- ${SRCDIR}/Quaternions.h
- ${SRCDIR}/Random.h
- ${SRCDIR}/Skybox.h
- ${SRCDIR}/Sprite.h
- ${SRCDIR}/ImageIO.h
- ${SRCDIR}/Terrain.h
- ${SRCDIR}/Texture.h
- ${SRCDIR}/Text.h
- ${SRCDIR}/Weapons.h
- ${SRCDIR}/Input.h
- ${SRCDIR}/binio.h
- ${SRCDIR}/openal_wrapper.h
- ${SRCDIR}/optionparser.h
- ${SRCDIR}/gamegl.h
- ${SRCDIR}/private.h
- ${SRCDIR}/Settings.h
- ${SRCDIR}/Stereo.h
- ${SRCDIR}/Sounds.h
+ ${SRCDIR}/Audio/openal_wrapper.h
+ ${SRCDIR}/Audio/Sounds.h
+ ${SRCDIR}/Devtools/ConsoleCmds.h
+ ${SRCDIR}/Environment/Lights.h
+ ${SRCDIR}/Environment/Skybox.h
+ ${SRCDIR}/Environment/Terrain.h
+ ${SRCDIR}/Graphic/gamegl.h
+ ${SRCDIR}/Graphic/Models.h
+ ${SRCDIR}/Graphic/Sprite.h
+ ${SRCDIR}/Graphic/Stereo.h
+ ${SRCDIR}/Graphic/Text.h
+ ${SRCDIR}/Graphic/Texture.h
+ ${SRCDIR}/Level/Campaign.h
+ ${SRCDIR}/Level/Dialog.h
+ ${SRCDIR}/Level/Hotspot.h
+ ${SRCDIR}/Math/Frustum.h
+ ${SRCDIR}/Math/PhysicsMath.h
+ ${SRCDIR}/Math/Quaternions.h
+ ${SRCDIR}/Math/Random.h
+ ${SRCDIR}/Menu/Menu.h
+ ${SRCDIR}/Objects/Objects.h
+ ${SRCDIR}/Objects/Person.h
+ ${SRCDIR}/Objects/Weapons.h
+ ${SRCDIR}/Thirdparty/optionparser.h
+ ${SRCDIR}/User/Account.h
+ ${SRCDIR}/User/Settings.h
+ ${SRCDIR}/Utils/binio.h
${SRCDIR}/Utils/Folders.h
+ ${SRCDIR}/Utils/ImageIO.h
+ ${SRCDIR}/Utils/Input.h
+ ${SRCDIR}/Utils/private.h
+ ${SRCDIR}/Game.h
+
)
if(UNIX)
+++ /dev/null
-/*
-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/>.
-*/
-
-#include "Account.h"
-#include "binio.h"
-#include <fstream>
-#include "MacCompatibility.h"
-#include "string.h"
-#include <iostream>
-
-using namespace std;
-
-extern bool devtools;
-
-vector<Account> Account::accounts;
-int Account::i_active = -1;
-
-Account::Account(const string& name) : name(name), campaignProgress()
-{
- difficulty = 0;
- progress = 0;
- points = 0;
- memset(highscore, 0, sizeof(highscore));
- memset(fasttime, 0, sizeof(fasttime));
- memset(unlocked, 0, sizeof(unlocked));
-
- setCurrentCampaign("main");
-}
-
-Account::Account(FILE* tfile) : Account("")
-{
- funpackf(tfile, "Bi", &difficulty);
- funpackf(tfile, "Bi", &progress);
- int nbCampaigns;
- funpackf(tfile, "Bi", &nbCampaigns);
-
- for (int k = 0; k < nbCampaigns; ++k) {
- string campaignName = "";
- int t;
- char c;
- funpackf(tfile, "Bi", &t);
- for (int j = 0; j < t; j++) {
- funpackf(tfile, "Bb", &c);
- campaignName.append(1, c);
- }
- funpackf(tfile, "Bf", &(campaignProgress[campaignName].time));
- funpackf(tfile, "Bf", &(campaignProgress[campaignName].score));
- funpackf(tfile, "Bf", &(campaignProgress[campaignName].fasttime));
- funpackf(tfile, "Bf", &(campaignProgress[campaignName].highscore));
- int campaignchoicesmade, campaignchoice;
- funpackf(tfile, "Bi", &campaignchoicesmade);
- for (int j = 0; j < campaignchoicesmade; j++) {
- funpackf(tfile, "Bi", &campaignchoice);
- if (campaignchoice >= 10) { // what is that for?
- campaignchoice = 0;
- }
- campaignProgress[campaignName].choices.push_back(campaignchoice);
- }
- }
-
- currentCampaign = "";
- int t;
- char c;
- funpackf(tfile, "Bi", &t);
- for (int i = 0; i < t; i++) {
- funpackf(tfile, "Bb", &c);
- currentCampaign.append(1, c);
- }
-
- funpackf(tfile, "Bf", &points);
- for (int i = 0; i < 50; i++) {
- funpackf(tfile, "Bf", &(highscore[i]));
- funpackf(tfile, "Bf", &(fasttime[i]));
- }
- for (int i = 0; i < 60; i++) {
- funpackf(tfile, "Bb", &(unlocked[i]));
- }
- int temp;
- char ctemp;
- funpackf(tfile, "Bi", &temp);
- for (int i = 0; i < temp; i++) {
- funpackf(tfile, "Bb", &ctemp);
- name.append(1, ctemp);
- }
- if (name.empty()) {
- name = "Lugaru Player"; // no empty player name security.
- }
-}
-
-void Account::save(FILE* tfile)
-{
- fpackf(tfile, "Bi", difficulty);
- fpackf(tfile, "Bi", progress);
- fpackf(tfile, "Bi", campaignProgress.size());
-
- map<string, CampaignProgress>::const_iterator it;
- for (it = campaignProgress.begin(); it != campaignProgress.end(); ++it) {
- fpackf(tfile, "Bi", it->first.size());
- for (unsigned j = 0; j < it->first.size(); j++) {
- fpackf(tfile, "Bb", it->first[j]);
- }
- fpackf(tfile, "Bf", it->second.time);
- fpackf(tfile, "Bf", it->second.score);
- fpackf(tfile, "Bf", it->second.fasttime);
- fpackf(tfile, "Bf", it->second.highscore);
- fpackf(tfile, "Bi", it->second.choices.size());
- for (unsigned j = 0; j < it->second.choices.size(); j++) {
- fpackf(tfile, "Bi", it->second.choices[j]);
- }
- }
-
- fpackf(tfile, "Bi", getCurrentCampaign().size());
- for (unsigned j = 0; j < getCurrentCampaign().size(); j++) {
- fpackf(tfile, "Bb", getCurrentCampaign()[j]);
- }
-
- fpackf(tfile, "Bf", points);
- for (unsigned j = 0; j < 50; j++) {
- fpackf(tfile, "Bf", highscore[j]);
- fpackf(tfile, "Bf", fasttime[j]);
- }
- for (unsigned j = 0; j < 60; j++) {
- fpackf(tfile, "Bb", unlocked[j]);
- }
- fpackf(tfile, "Bi", name.size());
- for (unsigned j = 0; j < name.size(); j++) {
- fpackf(tfile, "Bb", name[j]);
- }
-}
-
-void Account::setCurrentCampaign(const string& name)
-{
- currentCampaign = name;
-}
-
-void Account::add(const string& name)
-{
- accounts.emplace_back(name);
- i_active = accounts.size() - 1;
-}
-
-Account& Account::get(int i)
-{
- return accounts.at(i);
-}
-
-int Account::getNbAccounts()
-{
- return accounts.size();
-}
-
-bool Account::hasActive()
-{
- return (i_active >= 0);
-}
-
-Account& Account::active()
-{
- return accounts.at(i_active);
-}
-
-void Account::setActive(int i)
-{
- if ((i >= 0) && (i < int(accounts.size()))) {
- i_active = i;
- } else {
- cerr << "Tried to set active account to " << i << " but there is not such account" << endl;
- i_active = -1;
- }
-}
-
-void Account::destroyActive()
-{
- if ((i_active >= 0) && (i_active < int(accounts.size()))) {
- accounts.erase(accounts.begin() + i_active);
- i_active = -1;
- } else {
- cerr << "Tried to destroy active account " << i_active << " but there is not such account" << endl;
- i_active = -1;
- }
-}
-
-int Account::getDifficulty()
-{
- return difficulty;
-}
-
-void Account::endGame()
-{
- campaignProgress[currentCampaign].choices.clear();
- campaignProgress[currentCampaign].score = 0;
- campaignProgress[currentCampaign].time = 0;
-}
-
-void Account::winCampaignLevel(int choice, float score, float time)
-{
- campaignProgress[currentCampaign].choices.push_back(choice);
- setCampaignScore(campaignProgress[currentCampaign].score + score);
- campaignProgress[currentCampaign].time = time;
-}
-
-void Account::winLevel(int level, float score, float time)
-{
- if (!devtools) {
- if (score > highscore[level])
- highscore[level] = score;
- if (time < fasttime[level] || fasttime[level] == 0)
- fasttime[level] = time;
- }
- if (progress < level + 1)
- progress = level + 1;
-}
-
-void Account::loadFile(string filename)
-{
- FILE *tfile;
- int numaccounts;
- int iactive;
- errno = 0;
-
- tfile = fopen(filename.c_str(), "rb" );
-
- if (tfile) {
- funpackf(tfile, "Bi", &numaccounts);
- funpackf(tfile, "Bi", &iactive);
- printf("Loading %d accounts\n", numaccounts);
- for (int i = 0; i < numaccounts; i++) {
- printf("Loading account %d/%d\n", i, numaccounts);
- accounts.emplace_back(tfile);
- }
-
- fclose(tfile);
- setActive(iactive);
- } else {
- perror(("Couldn't load users from " + filename).c_str());
- i_active = -1;
- }
-}
-
-void Account::saveFile(string filename)
-{
- FILE *tfile;
- errno = 0;
-
- tfile = fopen(filename.c_str(), "wb" );
- if (tfile) {
- fpackf(tfile, "Bi", getNbAccounts());
- fpackf(tfile, "Bi", i_active);
-
- for (int i = 0; i < getNbAccounts(); i++) {
- printf("writing account %d/%d (%s)\n", i + 1, getNbAccounts(), accounts[i].getName().c_str());
- accounts[i].save(tfile);
- }
-
- fclose(tfile);
- } else {
- perror(("Couldn't save users in " + filename).c_str());
- }
-}
+++ /dev/null
-/*
-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 _Account_H_
-#define _Account_H_
-
-#include <vector>
-#include <string>
-#include <map>
-#include <fstream>
-
-struct CampaignProgress {
- float highscore;
- float fasttime;
- float score;
- float time;
- std::vector<int> choices;
- CampaignProgress() {
- highscore = 0;
- fasttime = 0;
- score = 0;
- time = 0;
- }
-};
-
-class Account
-{
-public:
- static void destroyActive();
- static void setActive(int i);
- static void add(const std::string& name);
- static Account& get(int i);
- static void loadFile(std::string filename);
- static void saveFile(std::string filename);
- static int getNbAccounts();
-
- static bool hasActive();
- static Account& active();
-
- Account(const std::string& name = "");
- Account(FILE* tfile);
-
- void endGame();
- void winCampaignLevel(int choice, float score, float time);
- void winLevel(int level, float score, float time);
-
- // getter and setters
- int getDifficulty();
- void setDifficulty(int i) {
- difficulty = i;
- };
- const std::string& getName() {
- return name;
- };
- float getCampaignScore() {
- return campaignProgress[currentCampaign].score;
- };
- int getCampaignChoicesMade() {
- return campaignProgress[currentCampaign].choices.size();
- };
- int getCampaignChoice(int i) {
- return campaignProgress[currentCampaign].choices[i];
- };
- void setCampaignScore(int s) {
- campaignProgress[currentCampaign].score = s;
- if (s > campaignProgress[currentCampaign].highscore)
- campaignProgress[currentCampaign].highscore = s;
- };
- void setCampaignFinalTime(float t) {
- campaignProgress[currentCampaign].time = t;
- if ((t < campaignProgress[currentCampaign].fasttime) || ((campaignProgress[currentCampaign].fasttime == 0) && (t != 0)))
- campaignProgress[currentCampaign].fasttime = t;
- };
- float getCampaignFasttime() {
- return campaignProgress[currentCampaign].fasttime;
- };
- void resetFasttime() {
- campaignProgress[currentCampaign].fasttime = 0;
- };
- float getCampaignHighScore() {
- return campaignProgress[currentCampaign].highscore;
- };
- float getHighScore(int i) {
- return highscore[i];
- };
- float getFastTime(int i) {
- return fasttime[i];
- };
- int getProgress() {
- return progress;
- };
- std::string getCurrentCampaign() {
- return currentCampaign;
- };
- void setCurrentCampaign(const std::string& name);
-
-private:
- //statics
- static std::vector<Account> accounts;
- static int i_active;
-
- void save(FILE* tfile);
-
- int difficulty;
- int progress; // progress in challenge levels
- float points;
- float highscore[50];
- float fasttime[50];
- bool unlocked[60];
- std::string name;
-
- std::string currentCampaign;
- std::map<std::string, CampaignProgress> campaignProgress;
-};
-
-#endif
along with Lugaru. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "Animation/Skeleton.h"
#include "Animation/Animation.h"
+#include "Animation/Skeleton.h"
#include "Utils/Folders.h"
#include "Game.h"
#define ANIMATION_H
#include <vector>
+#include "Math/Quaternions.h"
enum anim_attack_type {
neutral, normalattack, reversed, reversal
*/
#include "Animation/Joint.h"
-#include "binio.h"
+#include "Utils/binio.h"
Joint::Joint() :
blurred(0),
#ifndef _JOINT_H_
#define _JOINT_H_
-#include "Quaternions.h"
+#include "Math/Quaternions.h"
#include <vector>
enum bodypart {
*/
#include "Animation/Muscle.h"
-#include "binio.h"
+#include "Utils/binio.h"
extern float multiplier;
extern bool freeze;
/**> HEADER FILES <**/
#include "Game.h"
-#include "Animation/Skeleton.h"
-#include "openal_wrapper.h"
#include "Animation/Animation.h"
+#include "Animation/Skeleton.h"
+#include "Audio/openal_wrapper.h"
#include "Utils/Folders.h"
extern float multiplier;
#ifndef _SKELETON_H_
#define _SKELETON_H_
-#include "Models.h"
-
/**> HEADER FILES <**/
-#include "gamegl.h"
-#include "Quaternions.h"
-#include "Objects.h"
-#include "Sprite.h"
-#include "binio.h"
#include "Animation/Animation.h"
#include "Animation/Joint.h"
#include "Animation/Muscle.h"
+#include "Graphic/gamegl.h"
+#include "Graphic/Models.h"
+#include "Graphic/Sprite.h"
+#include "Math/Quaternions.h"
+#include "Objects/Objects.h"
+#include "Utils/binio.h"
const int max_joints = 50;
--- /dev/null
+/*
+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 "Audio/openal_wrapper.h"
+#include "Audio/Sounds.h"
+#include "Math/Quaternions.h"
+#include "Utils/Folders.h"
+
+struct OPENAL_SAMPLE *samp[sounds_count];
+
+extern XYZ envsound[30];
+extern float envsoundvol[30];
+extern int numenvsounds;
+extern float envsoundlife[30];
+
+int footstepsound, footstepsound2, footstepsound3, footstepsound4;
+
+int channels[100];
+
+static const char *sound_data[sounds_count] = {
+#define DECLARE_SOUND(id, filename) filename,
+#include "Sounds.def"
+#undef DECLARE_SOUND
+};
+
+// FIXME: dimensionality is not a property of the sound sample.
+// This should be decided at the time of playback
+static int snd_mode(int snd)
+{
+ switch (snd) {
+ case alarmsound:
+ case consolefailsound:
+ case consolesuccesssound:
+ case firestartsound:
+ case fireendsound:
+ return OPENAL_2D;
+ default:
+ return OPENAL_HW3D;
+ }
+}
+
+void loadAllSounds()
+{
+ for (int i = 0; i < sounds_count; i++) {
+ std::string buf = std::string("Sounds/") + sound_data[i];
+ samp[i] = OPENAL_Sample_Load(OPENAL_FREE,
+ Folders::getResourcePath(buf).c_str(),
+ snd_mode(i),
+ 0, 0);
+ }
+ footstepsound = footstepsn1;
+ footstepsound2 = footstepsn2;
+ footstepsound3 = footstepst1;
+ footstepsound4 = footstepst2;
+ // Huh?
+ // OPENAL_Sample_SetMode(samp[whooshsound], OPENAL_LOOP_NORMAL);
+ for (int i = stream_firesound; i <= stream_menutheme; i++)
+ OPENAL_Stream_SetMode(samp[i], OPENAL_LOOP_NORMAL);
+}
+
+void addEnvSound(XYZ coords, float vol, float life)
+{
+ envsound[numenvsounds] = coords;
+ envsoundvol[numenvsounds] = vol;
+ envsoundlife[numenvsounds] = life;
+ numenvsounds++;
+}
+
+void emit_sound_at(int soundid, const XYZ &pos, float vol)
+{
+ PlaySoundEx (soundid, samp[soundid], NULL, true);
+ OPENAL_3D_SetAttributes_ (channels[soundid], pos, NULL);
+ OPENAL_SetVolume (channels[soundid], vol);
+ OPENAL_SetPaused (channels[soundid], false);
+}
+
+void emit_sound_np(int soundid, float vol)
+{
+ PlaySoundEx (soundid, samp[soundid], NULL, true);
+ OPENAL_SetVolume (channels[soundid], vol);
+ OPENAL_SetPaused (channels[soundid], false);
+}
+
+void emit_stream_at(int soundid, const XYZ &pos, float vol)
+{
+ PlayStreamEx (soundid, samp[soundid], NULL, true);
+ OPENAL_3D_SetAttributes_ (channels[soundid], pos, NULL);
+ OPENAL_SetVolume (channels[soundid], vol);
+ OPENAL_SetPaused (channels[soundid], false);
+}
+
+void emit_stream_np(int soundid, float vol)
+{
+ PlayStreamEx (soundid, samp[soundid], NULL, true);
+ OPENAL_SetVolume (channels[soundid], vol);
+ OPENAL_SetPaused (channels[soundid], false);
+}
+
+void resume_stream(int soundid)
+{
+ OPENAL_SetPaused (channels[soundid], false);
+}
+
+void pause_sound(int soundid)
+{
+ OPENAL_SetPaused (channels[soundid], true);
+}
--- /dev/null
+/*
+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/>.
+*/
+
+DECLARE_SOUND(footstepsn1, "FootStepSnow1.ogg")
+DECLARE_SOUND(footstepsn2, "FootStepSnow2.ogg")
+DECLARE_SOUND(footstepst1, "FootStepStone1.ogg")
+DECLARE_SOUND(footstepst2, "FootStepStone2.ogg")
+DECLARE_SOUND(footstepgr1, "FootStepGrass1.ogg")
+DECLARE_SOUND(footstepgr2, "FootStepGrass2.ogg")
+DECLARE_SOUND(landsound, "Land.ogg")
+DECLARE_SOUND(jumpsound, "Jump.ogg")
+DECLARE_SOUND(hawksound, "Hawk.ogg")
+DECLARE_SOUND(whooshsound, "Whoosh.ogg")
+DECLARE_SOUND(landsound1, "Land1.ogg")
+DECLARE_SOUND(landsound2, "Land2.ogg")
+DECLARE_SOUND(breaksound, "Broken.ogg")
+DECLARE_SOUND(lowwhooshsound, "LowWhoosh.ogg")
+DECLARE_SOUND(midwhooshsound, "MidWhoosh.ogg")
+DECLARE_SOUND(highwhooshsound, "HighWhoosh.ogg")
+DECLARE_SOUND(movewhooshsound, "MoveWhoosh.ogg")
+DECLARE_SOUND(heavyimpactsound, "HeavyImpact.ogg")
+DECLARE_SOUND(whooshhitsound, "WhooshHit.ogg")
+DECLARE_SOUND(thudsound, "Thud.ogg")
+DECLARE_SOUND(alarmsound, "Alarm.ogg")
+DECLARE_SOUND(breaksound2, "Break.ogg")
+DECLARE_SOUND(knifedrawsound, "KnifeDraw.ogg")
+DECLARE_SOUND(knifesheathesound, "KnifeSheathe.ogg")
+DECLARE_SOUND(fleshstabsound, "FleshStab.ogg")
+DECLARE_SOUND(fleshstabremovesound, "FleshStabRemove.ogg")
+DECLARE_SOUND(knifeswishsound, "KnifeSwish.ogg")
+DECLARE_SOUND(knifeslicesound, "KnifeSlice.ogg")
+DECLARE_SOUND(swordslicesound, "SwordSlice.ogg")
+DECLARE_SOUND(skidsound, "Skid.ogg")
+DECLARE_SOUND(snowskidsound, "SnowSkid.ogg")
+DECLARE_SOUND(bushrustle, "BushRustle.ogg")
+DECLARE_SOUND(clank1sound, "Clank1.ogg")
+DECLARE_SOUND(clank2sound, "Clank2.ogg")
+DECLARE_SOUND(clank3sound, "Clank3.ogg")
+DECLARE_SOUND(clank4sound, "Clank4.ogg")
+DECLARE_SOUND(consolesuccesssound, "ConsoleSuccess.ogg")
+DECLARE_SOUND(consolefailsound, "ConsoleFail.ogg")
+DECLARE_SOUND(metalhitsound, "MetalHit.ogg")
+DECLARE_SOUND(clawslicesound, "ClawSlice.ogg")
+DECLARE_SOUND(splattersound, "Splatter.ogg")
+DECLARE_SOUND(growlsound, "Growl.ogg")
+DECLARE_SOUND(growl2sound, "Growl2.ogg")
+DECLARE_SOUND(barksound, "Bark.ogg")
+DECLARE_SOUND(bark2sound, "Bark2.ogg")
+DECLARE_SOUND(bark3sound, "Bark3.ogg")
+DECLARE_SOUND(snarlsound, "Snarl.ogg")
+DECLARE_SOUND(snarl2sound, "Snarl2.ogg")
+DECLARE_SOUND(barkgrowlsound, "BarkGrowl.ogg")
+DECLARE_SOUND(rabbitattacksound, "RabbitAttack.ogg")
+DECLARE_SOUND(rabbitattack2sound, "RabbitAttack2.ogg")
+DECLARE_SOUND(rabbitattack3sound, "RabbitAttack3.ogg")
+DECLARE_SOUND(rabbitattack4sound, "RabbitAttack4.ogg")
+DECLARE_SOUND(rabbitpainsound, "RabbitPain.ogg")
+DECLARE_SOUND(rabbitpain1sound, "RabbitPain2.ogg")
+DECLARE_SOUND(rabbitchitter, "RabbitChitter.ogg")
+DECLARE_SOUND(rabbitchitter2, "RabbitChitter2.ogg")
+DECLARE_SOUND(swordstaffsound, "SwordStaff.ogg")
+DECLARE_SOUND(staffbodysound, "StaffBody.ogg")
+DECLARE_SOUND(staffheadsound, "StaffHead.ogg")
+DECLARE_SOUND(staffbreaksound, "StaffBreak.ogg")
+DECLARE_SOUND(firestartsound, "FireStart.ogg")
+DECLARE_SOUND(fireendsound, "FireEnd.ogg")
+DECLARE_SOUND(stream_firesound, "Fire.ogg")
+DECLARE_SOUND(stream_grasstheme, "Music1Grass.ogg")
+DECLARE_SOUND(stream_snowtheme, "Music1Snow.ogg")
+DECLARE_SOUND(stream_deserttheme, "Music1Desert.ogg")
+DECLARE_SOUND(stream_wind, "Wind.ogg")
+DECLARE_SOUND(stream_desertambient, "DesertAmbient.ogg")
+DECLARE_SOUND(stream_fighttheme, "Music2.ogg")
+DECLARE_SOUND(stream_menutheme, "Music3.ogg")
--- /dev/null
+/*
+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 SOUNDS_H
+#define SOUNDS_H
+
+enum sound_types {
+#define DECLARE_SOUND(id, filename) id,
+#include "Sounds.def"
+#undef DECLARE_SOUND
+ sounds_count
+};
+
+extern struct OPENAL_SAMPLE *samp[sounds_count];
+extern int channels[];
+
+extern void loadAllSounds();
+
+extern void addEnvSound(XYZ coords, float vol = 16, float life = .4);
+
+extern void emit_sound_at(int soundid, const XYZ &pos = XYZ(), float vol = 256.f);
+extern void emit_sound_np(int soundid, float vol = 256.f);
+extern void emit_stream_at(int soundid, const XYZ &pos = XYZ(), float vol = 256.f);
+extern void emit_stream_np(int soundid, float vol = 256.f);
+extern void resume_stream(int soundid);
+extern void pause_sound(int soundid);
+
+extern int footstepsound, footstepsound2, footstepsound3, footstepsound4;
+#endif
--- /dev/null
+/*
+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/>.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "Math/Quaternions.h"
+#include "Audio/openal_wrapper.h"
+#include "Audio/Sounds.h"
+#include "Game.h"
+
+extern float slomofreq;
+
+// NOTE:
+// FMOD uses a Left Handed Coordinate system, OpenAL uses a Right Handed
+// one...so we just need to flip the sign on the Z axis when appropriate.
+
+typedef struct {
+ ALuint sid;
+ OPENAL_SAMPLE *sample;
+ bool startpaused;
+ float position[3];
+} OPENAL_Channels;
+
+typedef struct OPENAL_SAMPLE {
+ char *name;
+ ALuint bid; // buffer id.
+ int mode;
+ int is2d;
+} OPENAL_SAMPLE;
+
+static size_t num_channels = 0;
+static OPENAL_Channels *impl_channels = NULL;
+static bool initialized = false;
+static float listener_position[3];
+
+static void set_channel_position(const int channel, const float x,
+ const float y, const float z)
+{
+ OPENAL_Channels *chan = &impl_channels[channel];
+
+ chan->position[0] = x;
+ chan->position[1] = y;
+ chan->position[2] = z;
+
+ OPENAL_SAMPLE *sptr = chan->sample;
+ if (sptr == NULL)
+ return;
+
+ const ALuint sid = chan->sid;
+ const bool no_attenuate = sptr->is2d;
+
+ if (no_attenuate) {
+ alSourcei(sid, AL_SOURCE_RELATIVE, AL_TRUE);
+ alSource3f(sid, AL_POSITION, 0.0f, 0.0f, 0.0f);
+ } else {
+ alSourcei(sid, AL_SOURCE_RELATIVE, AL_FALSE);
+ alSource3f(sid, AL_POSITION, x, y, z);
+ }
+}
+
+
+AL_API void OPENAL_3D_Listener_SetAttributes(const float *pos, const float *vel, float fx, float fy, float fz, float tx, float ty, float tz)
+{
+ if (!initialized)
+ return;
+ if (pos != NULL) {
+ alListener3f(AL_POSITION, pos[0], pos[1], -pos[2]);
+ listener_position[0] = pos[0];
+ listener_position[1] = pos[1];
+ listener_position[2] = -pos[2];
+ }
+
+ ALfloat vec[6] = { fx, fy, -fz, tz, ty, -tz };
+ alListenerfv(AL_ORIENTATION, vec);
+
+ // we ignore velocity, since doppler's broken in the Linux AL at the moment...
+
+ // adjust existing positions...
+ for (int i = 0; i < num_channels; i++) {
+ const float *p = impl_channels[i].position;
+ set_channel_position(i, p[0], p[1], p[2]);
+ }
+}
+
+AL_API signed char OPENAL_3D_SetAttributes(int channel, const float *pos, const float *vel)
+{
+ if (!initialized)
+ return false;
+ if ((channel < 0) || (channel >= num_channels))
+ return false;
+
+ if (pos != NULL)
+ set_channel_position(channel, pos[0], pos[1], -pos[2]);
+
+ // we ignore velocity, since doppler's broken in the Linux AL at the moment...
+
+ return true;
+}
+
+AL_API signed char OPENAL_3D_SetAttributes_(int channel, const XYZ &pos, const float *vel)
+{
+ if (!initialized)
+ return false;
+ if ((channel < 0) || (channel >= num_channels))
+ return false;
+
+ set_channel_position(channel, pos.x, pos.y, -pos.z);
+
+ return true;
+}
+
+AL_API signed char OPENAL_Init(int mixrate, int maxsoftwarechannels, unsigned int flags)
+{
+ if (initialized)
+ return false;
+ if (maxsoftwarechannels == 0)
+ return false;
+
+ if (flags != 0) // unsupported.
+ return false;
+
+ ALCdevice *dev = alcOpenDevice(NULL);
+ if (!dev)
+ return false;
+
+ ALint caps[] = { ALC_FREQUENCY, mixrate, 0 };
+ ALCcontext *ctx = alcCreateContext(dev, caps);
+ if (!ctx) {
+ alcCloseDevice(dev);
+ return false;
+ }
+
+ alcMakeContextCurrent(ctx);
+ alcProcessContext(ctx);
+
+ if (commandLineOptions[OPENALINFO]) {
+ printf("AL_VENDOR: %s\n", (char *) alGetString(AL_VENDOR));
+ printf("AL_RENDERER: %s\n", (char *) alGetString(AL_RENDERER));
+ printf("AL_VERSION: %s\n", (char *) alGetString(AL_VERSION));
+ printf("AL_EXTENSIONS: %s\n", (char *) alGetString(AL_EXTENSIONS));
+ }
+
+ num_channels = maxsoftwarechannels;
+ impl_channels = new OPENAL_Channels[maxsoftwarechannels];
+ memset(impl_channels, '\0', sizeof (OPENAL_Channels) * num_channels);
+ for (int i = 0; i < num_channels; i++)
+ alGenSources(1, &impl_channels[i].sid); // !!! FIXME: verify this didn't fail!
+
+ initialized = true;
+ return true;
+}
+
+AL_API void OPENAL_Close()
+{
+ if (!initialized)
+ return;
+
+ ALCcontext *ctx = alcGetCurrentContext();
+ if (ctx) {
+ for (int i = 0; i < num_channels; i++) {
+ alSourceStop(impl_channels[i].sid);
+ alSourcei(impl_channels[i].sid, AL_BUFFER, 0);
+ alDeleteSources(1, &impl_channels[i].sid);
+ }
+ ALCdevice *dev = alcGetContextsDevice(ctx);
+ alcMakeContextCurrent(NULL);
+ alcSuspendContext(ctx);
+ alcDestroyContext(ctx);
+ alcCloseDevice(dev);
+ }
+
+ num_channels = 0;
+ delete[] impl_channels;
+ impl_channels = NULL;
+
+ initialized = false;
+}
+
+static OPENAL_SAMPLE *OPENAL_GetCurrentSample(int channel)
+{
+ if (!initialized)
+ return NULL;
+ if ((channel < 0) || (channel >= num_channels))
+ return NULL;
+ return impl_channels[channel].sample;
+}
+
+static signed char OPENAL_GetPaused(int channel)
+{
+ if (!initialized)
+ return false;
+ if ((channel < 0) || (channel >= num_channels))
+ return false;
+ if (impl_channels[channel].startpaused)
+ return(true);
+
+ ALint state = 0;
+ alGetSourceiv(impl_channels[channel].sid, AL_SOURCE_STATE, &state);
+ return((state == AL_PAUSED) ? true : false);
+}
+
+static unsigned int OPENAL_GetLoopMode(int channel)
+{
+ if (!initialized)
+ return 0;
+ if ((channel < 0) || (channel >= num_channels))
+ return 0;
+ ALint loop = 0;
+ alGetSourceiv(impl_channels[channel].sid, AL_LOOPING, &loop);
+ if (loop)
+ return(OPENAL_LOOP_NORMAL);
+ return OPENAL_LOOP_OFF;
+}
+
+static signed char OPENAL_IsPlaying(int channel)
+{
+ if (!initialized)
+ return false;
+ if ((channel < 0) || (channel >= num_channels))
+ return false;
+ ALint state = 0;
+ alGetSourceiv(impl_channels[channel].sid, AL_SOURCE_STATE, &state);
+ return((state == AL_PLAYING) ? true : false);
+}
+
+static int OPENAL_PlaySoundEx(int channel, OPENAL_SAMPLE *sptr, OPENAL_DSPUNIT *dsp, signed char startpaused)
+{
+ if (!initialized)
+ return -1;
+ if (sptr == NULL)
+ return -1;
+ if (dsp != NULL)
+ return -1;
+ if (channel == OPENAL_FREE) {
+ for (int i = 0; i < num_channels; i++) {
+ ALint state = 0;
+ alGetSourceiv(impl_channels[i].sid, AL_SOURCE_STATE, &state);
+ if ((state != AL_PLAYING) && (state != AL_PAUSED)) {
+ channel = i;
+ break;
+ }
+ }
+ }
+
+ if ((channel < 0) || (channel >= num_channels))
+ return -1;
+ alSourceStop(impl_channels[channel].sid);
+ impl_channels[channel].sample = sptr;
+ alSourcei(impl_channels[channel].sid, AL_BUFFER, sptr->bid);
+ alSourcei(impl_channels[channel].sid, AL_LOOPING, (sptr->mode == OPENAL_LOOP_OFF) ? AL_FALSE : AL_TRUE);
+ set_channel_position(channel, 0.0f, 0.0f, 0.0f);
+
+ impl_channels[channel].startpaused = ((startpaused) ? true : false);
+ if (!startpaused)
+ alSourcePlay(impl_channels[channel].sid);
+ return channel;
+}
+
+
+static void *decode_to_pcm(const char *_fname, ALenum &format, ALsizei &size, ALuint &freq)
+{
+#ifdef __POWERPC__
+ const int bigendian = 1;
+#else
+ const int bigendian = 0;
+#endif
+
+ // !!! FIXME: if it's not Ogg, we don't have a decoder. I'm lazy. :/
+ char *fname = (char *) alloca(strlen(_fname) + 16);
+ strcpy(fname, _fname);
+ char *ptr = strchr(fname, '.');
+ if (ptr)
+ *ptr = '\0';
+ strcat(fname, ".ogg");
+
+ // just in case...
+ FILE *io = fopen(fname, "rb");
+ if (io == NULL)
+ return NULL;
+
+ ALubyte *retval = NULL;
+
+#if 0 // untested, so disable this!
+ // Can we just feed it to the AL compressed?
+ if (alIsExtensionPresent((const ALubyte *) "AL_EXT_vorbis")) {
+ format = alGetEnumValue((const ALubyte *) "AL_FORMAT_VORBIS_EXT");
+ freq = 44100;
+ fseek(io, 0, SEEK_END);
+ size = ftell(io);
+ fseek(io, 0, SEEK_SET);
+ retval = (ALubyte *) malloc(size);
+ size_t rc = fread(retval, size, 1, io);
+ fclose(io);
+ if (rc != 1) {
+ free(retval);
+ return NULL;
+ }
+ return retval;
+ }
+#endif
+
+ // Uncompress and feed to the AL.
+ OggVorbis_File vf;
+ memset(&vf, '\0', sizeof (vf));
+ if (ov_open(io, &vf, NULL, 0) == 0) {
+ int bitstream = 0;
+ vorbis_info *info = ov_info(&vf, -1);
+ size = 0;
+ format = (info->channels == 1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
+ freq = info->rate;
+
+ if ((info->channels != 1) && (info->channels != 2)) {
+ ov_clear(&vf);
+ return NULL;
+ }
+
+ char buf[1024 * 16];
+ long rc = 0;
+ size_t allocated = 64 * 1024;
+ retval = (ALubyte *) malloc(allocated);
+ while ( (rc = ov_read(&vf, buf, sizeof (buf), bigendian, 2, 1, &bitstream)) != 0 ) {
+ if (rc > 0) {
+ size += rc;
+ if (size >= allocated) {
+ allocated *= 2;
+ ALubyte *tmp = (ALubyte *) realloc(retval, allocated);
+ if (tmp == NULL) {
+ free(retval);
+ retval = NULL;
+ break;
+ }
+ retval = tmp;
+ }
+ memcpy(retval + (size - rc), buf, rc);
+ }
+ }
+ ov_clear(&vf);
+ return retval;
+ }
+
+ fclose(io);
+ return NULL;
+}
+
+
+AL_API OPENAL_SAMPLE *OPENAL_Sample_Load(int index, const char *name_or_data, unsigned int mode, int offset, int length)
+{
+ if (!initialized)
+ return NULL;
+ if (index != OPENAL_FREE)
+ return NULL; // this is all the game does...
+ if (offset != 0)
+ return NULL; // this is all the game does...
+ if (length != 0)
+ return NULL; // this is all the game does...
+ if ((mode != OPENAL_HW3D) && (mode != OPENAL_2D))
+ return NULL; // this is all the game does...
+
+ OPENAL_SAMPLE *retval = NULL;
+ ALenum format = AL_NONE;
+ ALsizei size = 0;
+ ALuint frequency = 0;
+ void *data = decode_to_pcm(name_or_data, format, size, frequency);
+ if (data == NULL)
+ return NULL;
+
+ ALuint bid = 0;
+ alGetError();
+ alGenBuffers(1, &bid);
+ if (alGetError() == AL_NO_ERROR) {
+ alBufferData(bid, format, data, size, frequency);
+ retval = new OPENAL_SAMPLE;
+ retval->bid = bid;
+ retval->mode = OPENAL_LOOP_OFF;
+ retval->is2d = (mode == OPENAL_2D);
+ retval->name = new char[strlen(name_or_data) + 1];
+ if (retval->name)
+ strcpy(retval->name, name_or_data);
+ }
+
+ free(data);
+ return(retval);
+}
+
+AL_API void OPENAL_Sample_Free(OPENAL_SAMPLE *sptr)
+{
+ if (!initialized)
+ return;
+ if (sptr) {
+ for (int i = 0; i < num_channels; i++) {
+ if (impl_channels[i].sample == sptr) {
+ alSourceStop(impl_channels[i].sid);
+ alSourcei(impl_channels[i].sid, AL_BUFFER, 0);
+ impl_channels[i].sample = NULL;
+ }
+ }
+ alDeleteBuffers(1, &sptr->bid);
+ delete[] sptr->name;
+ delete sptr;
+ }
+}
+
+static signed char OPENAL_Sample_SetMode(OPENAL_SAMPLE *sptr, unsigned int mode)
+{
+ if (!initialized)
+ return false;
+ if ((mode != OPENAL_LOOP_NORMAL) && (mode != OPENAL_LOOP_OFF))
+ return false;
+ if (!sptr)
+ return false;
+ sptr->mode = mode;
+ return true;
+}
+
+AL_API signed char OPENAL_SetFrequency(int channel, bool slomo)
+{
+ if (!initialized)
+ return false;
+ if (channel == OPENAL_ALL) {
+ for (int i = 0; i < num_channels; i++)
+ OPENAL_SetFrequency(i, slomo);
+ return true;
+ }
+
+ if ((channel < 0) || (channel >= num_channels))
+ return false;
+ if (slomo)
+ alSourcef(impl_channels[channel].sid, AL_PITCH, ((ALfloat) slomofreq) / 44100.0f);
+ else
+ alSourcef(impl_channels[channel].sid, AL_PITCH, 1.0f);
+ return true;
+}
+
+AL_API signed char OPENAL_SetVolume(int channel, int vol)
+{
+ if (!initialized)
+ return false;
+
+ if (channel == OPENAL_ALL) {
+ for (int i = 0; i < num_channels; i++)
+ OPENAL_SetVolume(i, vol);
+ return true;
+ }
+
+ if ((channel < 0) || (channel >= num_channels))
+ return false;
+
+ if (vol < 0)
+ vol = 0;
+ else if (vol > 255)
+ vol = 255;
+ ALfloat gain = ((ALfloat) vol) / 255.0f;
+ alSourcef(impl_channels[channel].sid, AL_GAIN, gain);
+ return true;
+}
+
+AL_API signed char OPENAL_SetPaused(int channel, signed char paused)
+{
+ if (!initialized)
+ return false;
+
+ if (channel == OPENAL_ALL) {
+ for (int i = 0; i < num_channels; i++)
+ OPENAL_SetPaused(i, paused);
+ return true;
+ }
+
+ if ((channel < 0) || (channel >= num_channels))
+ return false;
+
+ ALint state = 0;
+ if (impl_channels[channel].startpaused)
+ state = AL_PAUSED;
+ else
+ alGetSourceiv(impl_channels[channel].sid, AL_SOURCE_STATE, &state);
+
+ if ((paused) && (state == AL_PLAYING))
+ alSourcePause(impl_channels[channel].sid);
+ else if ((!paused) && (state == AL_PAUSED)) {
+ alSourcePlay(impl_channels[channel].sid);
+ impl_channels[channel].startpaused = false;
+ }
+ return true;
+}
+
+AL_API void OPENAL_SetSFXMasterVolume(int volume)
+{
+ if (!initialized)
+ return;
+ ALfloat gain = ((ALfloat) volume) / 255.0f;
+ alListenerf(AL_GAIN, gain);
+}
+
+AL_API signed char OPENAL_StopSound(int channel)
+{
+ if (!initialized)
+ return false;
+
+ if (channel == OPENAL_ALL) {
+ for (int i = 0; i < num_channels; i++)
+ OPENAL_StopSound(i);
+ return true;
+ }
+
+ if ((channel < 0) || (channel >= num_channels))
+ return false;
+ alSourceStop(impl_channels[channel].sid);
+ impl_channels[channel].startpaused = false;
+ return true;
+}
+
+static OPENAL_SAMPLE *OPENAL_Stream_GetSample(OPENAL_STREAM *stream)
+{
+ if (!initialized)
+ return NULL;
+ return (OPENAL_SAMPLE *) stream;
+}
+
+static int OPENAL_Stream_PlayEx(int channel, OPENAL_STREAM *stream, OPENAL_DSPUNIT *dsp, signed char startpaused)
+{
+ return OPENAL_PlaySoundEx(channel, (OPENAL_SAMPLE *) stream, dsp, startpaused);
+}
+
+static signed char OPENAL_Stream_Stop(OPENAL_STREAM *stream)
+{
+ if (!initialized)
+ return false;
+ for (int i = 0; i < num_channels; i++) {
+ if (impl_channels[i].sample == (OPENAL_SAMPLE *) stream) {
+ alSourceStop(impl_channels[i].sid);
+ impl_channels[i].startpaused = false;
+ }
+ }
+ return true;
+}
+
+AL_API signed char OPENAL_Stream_SetMode(OPENAL_STREAM *stream, unsigned int mode)
+{
+ return OPENAL_Sample_SetMode((OPENAL_SAMPLE *) stream, mode);
+}
+
+AL_API void OPENAL_Update()
+{
+ if (!initialized)
+ return;
+ alcProcessContext(alcGetCurrentContext());
+}
+
+AL_API signed char OPENAL_SetOutput(int outputtype)
+{
+ return true;
+}
+
+extern int channels[];
+
+extern "C" void PlaySoundEx(int chan, OPENAL_SAMPLE *sptr, OPENAL_DSPUNIT *dsp, signed char startpaused)
+{
+ const OPENAL_SAMPLE * currSample = OPENAL_GetCurrentSample(channels[chan]);
+ if (currSample && currSample == samp[chan]) {
+ if (OPENAL_GetPaused(channels[chan])) {
+ OPENAL_StopSound(channels[chan]);
+ channels[chan] = OPENAL_FREE;
+ } else if (OPENAL_IsPlaying(channels[chan])) {
+ int loop_mode = OPENAL_GetLoopMode(channels[chan]);
+ if (loop_mode & OPENAL_LOOP_OFF) {
+ channels[chan] = OPENAL_FREE;
+ }
+ }
+ } else {
+ channels[chan] = OPENAL_FREE;
+ }
+
+ channels[chan] = OPENAL_PlaySoundEx(channels[chan], sptr, dsp, startpaused);
+ if (channels[chan] < 0) {
+ channels[chan] = OPENAL_PlaySoundEx(OPENAL_FREE, sptr, dsp, startpaused);
+ }
+}
+
+extern "C" void PlayStreamEx(int chan, OPENAL_STREAM *sptr, OPENAL_DSPUNIT *dsp, signed char startpaused)
+{
+ const OPENAL_SAMPLE * currSample = OPENAL_GetCurrentSample(channels[chan]);
+ if (currSample && currSample == OPENAL_Stream_GetSample(sptr)) {
+ OPENAL_StopSound(channels[chan]);
+ OPENAL_Stream_Stop(sptr);
+ } else {
+ OPENAL_Stream_Stop(sptr);
+ channels[chan] = OPENAL_FREE;
+ }
+
+ channels[chan] = OPENAL_Stream_PlayEx(channels[chan], sptr, dsp, startpaused);
+ if (channels[chan] < 0) {
+ channels[chan] = OPENAL_Stream_PlayEx(OPENAL_FREE, sptr, dsp, startpaused);
+ }
+}
--- /dev/null
+/*
+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 OPENAL_WRAPPER_H
+#define OPENAL_WRAPPER_H
+
+#ifdef _WIN32
+#include <malloc.h>
+#endif
+
+#include "AL/al.h"
+#include "AL/alc.h"
+
+#include "ogg/ogg.h"
+#include "vorbis/vorbisfile.h"
+
+#include "Math/Quaternions.h"
+#include "MacCompatibility.h"
+
+#if 0 /* this should only be enable if OPENAL doesn't provide AL_API on all platforms */
+#if (!defined(WIN32) && !defined(_WIN32) && !defined(__WIN32__) && !defined(_WIN64) && !defined(_WIN32_WCE) && !defined(_XBOX)) || (defined(__GNUC__) && defined(WIN32))
+#ifndef __cdecl
+#define __cdecl
+#endif
+#ifndef __stdcall
+#define __stdcall
+#endif
+#endif
+
+#if defined(_WIN32_WCE)
+#define AL_API _cdecl
+#define F_CALLBACKAPI _cdecl
+#else
+#define AL_API __stdcall
+#define F_CALLBACKAPI __stdcall
+#endif
+
+#ifdef DLL_EXPORTS
+#define DLL_API __declspec(dllexport)
+#else
+#if defined(__LCC__) || defined(__MINGW32__) || defined(__CYGWIN32__)
+#define DLL_API AL_API
+#else
+#define DLL_API
+#endif /* __LCC__ || __MINGW32__ || __CYGWIN32__ */
+#endif /* DLL_EXPORTS */
+#endif /* if 0 */
+
+
+typedef struct OPENAL_SAMPLE OPENAL_SAMPLE;
+typedef OPENAL_SAMPLE OPENAL_STREAM;
+typedef struct OPENAL_DSPUNIT OPENAL_DSPUNIT;
+
+enum OPENAL_OUTPUTTYPES {
+ OPENAL_OUTPUT_NOSOUND, /* NoSound driver, all calls to this succeed but do nothing. */
+ OPENAL_OUTPUT_OSS, /* Linux/Unix OSS (Open Sound System) driver, i.e. the kernel sound drivers. */
+ OPENAL_OUTPUT_ALSA, /* Linux Alsa driver. */
+};
+
+#define OPENAL_LOOP_OFF 0x00000001 /* For non looping samples. */
+#define OPENAL_LOOP_NORMAL 0x00000002 /* For forward looping samples. */
+#define OPENAL_HW3D 0x00001000 /* Attempts to make samples use 3d hardware acceleration. (if the card supports it) */
+#define OPENAL_2D 0x00002000 /* Tells software (not hardware) based sample not to be included in 3d processing. */
+#define OPENAL_FREE -1 /* value to play on any free channel, or to allocate a sample in a free sample slot. */
+#define OPENAL_ALL -3 /* for a channel index , this flag will affect ALL channels available! Not supported by every function. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#undef AL_API
+#define AL_API
+
+ AL_API void OPENAL_3D_Listener_SetAttributes(const float *pos, const float *vel, float fx, float fy, float fz, float tx, float ty, float tz);
+ AL_API signed char OPENAL_3D_SetAttributes(int channel, const float *pos, const float *vel);
+ AL_API signed char OPENAL_3D_SetAttributes_(int channel, const XYZ &pos, const float *vel);
+ AL_API signed char OPENAL_Init(int mixrate, int maxsoftwarechannels, unsigned int flags);
+ AL_API void OPENAL_Close();
+ AL_API OPENAL_SAMPLE *OPENAL_Sample_Load(int index, const char *name_or_data, unsigned int mode, int offset, int length);
+ AL_API void OPENAL_Sample_Free(OPENAL_SAMPLE *sptr);
+ AL_API signed char OPENAL_SetFrequency(int channel, bool slomo = false);
+ AL_API signed char OPENAL_SetVolume(int channel, int vol);
+ AL_API signed char OPENAL_SetPaused(int channel, signed char paused);
+ AL_API void OPENAL_SetSFXMasterVolume(int volume);
+ AL_API signed char OPENAL_StopSound(int channel);
+ AL_API signed char OPENAL_Stream_SetMode(OPENAL_STREAM *stream, unsigned int mode);
+ AL_API void OPENAL_Update();
+ AL_API signed char OPENAL_SetOutput(int outputtype);
+ void PlaySoundEx(int chan, OPENAL_SAMPLE *sptr, OPENAL_DSPUNIT *dsp, signed char startpaused);
+ void PlayStreamEx(int chan, OPENAL_SAMPLE *sptr, OPENAL_DSPUNIT *dsp, signed char startpaused);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+++ /dev/null
-/*
-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 "Awards.h"
-#include "Person.h"
-#include "Game.h"
-
-int bonus;
-float bonusvalue;
-float bonustotal;
-float startbonustotal;
-float bonustime;
-float bonusnum[100];
-
-const char *bonus_names[bonus_count] = {
-#define DECLARE_BONUS(id, name, ...) name,
-#include "Bonuses.def"
-#undef DECLARE_BONUS
-};
-
-const char *award_names[award_count] = {
-#define DECLARE_AWARD(id, name) name,
-#include "Awards.def"
-#undef DECLARE_AWARD
-};
-
-static const int bonus_values[bonus_count] = {
-#define DECLARE_BONUS(id, name, value) value,
-#include "Bonuses.def"
-#undef DECLARE_BONUS
-};
-
-void
-award_bonus(int playerid, int bonusid, int alt_value)
-{
- if (playerid != 0)
- return;
- bonus = bonusid;
- bonustime = 0;
- bonusvalue = alt_value ? alt_value : bonus_values[bonusid];
-}
-
-// FIXME: make these per-player
-float damagetaken;
-int numfalls;
-int numflipfail;
-int numseen;
-int numresponded;
-int numstaffattack;
-int numswordattack;
-int numknifeattack;
-int numunarmedattack;
-int numescaped;
-int numflipped;
-int numwallflipped;
-int numthrowkill;
-int numafterkill;
-int numreversals;
-int numattacks;
-int maxalarmed;
-
-int award_awards(int *awards)
-{
- int numawards = 0;
- if (damagetaken == 0 && Person::players[0]->bloodloss == 0) {
- awards[numawards] = awardflawless;
- numawards++;
- }
- bool alldead = true;
- for (unsigned i = 1; i < Person::players.size(); i++) {
- if (Person::players[i]->dead != 2)
- alldead = 0;
- }
- if (alldead) {
- awards[numawards] = awardalldead;
- numawards++;
- }
- alldead = 1;
- for (unsigned i = 1; i < Person::players.size(); i++) {
- if (Person::players[i]->dead != 1)
- alldead = 0;
- }
- if (alldead) {
- awards[numawards] = awardnodead;
- numawards++;
- }
- if (numresponded == 0 && !numthrowkill) {
- awards[numawards] = awardstealth;
- numawards++;
- }
- if (numattacks == numstaffattack && numattacks > 0) {
- awards[numawards] = awardbojutsu;
- numawards++;
- }
- if (numattacks == numswordattack && numattacks > 0) {
- awards[numawards] = awardswordsman;
- numawards++;
- }
- if (numattacks == numknifeattack && numattacks > 0) {
- awards[numawards] = awardknifefighter;
- numawards++;
- }
- if (numattacks == numunarmedattack && numthrowkill == 0 && weapons.size() > 0) {
- awards[numawards] = awardkungfu;
- numawards++;
- }
- if (numescaped > 0) {
- awards[numawards] = awardevasion;
- numawards++;
- }
- if (numflipfail == 0 && numflipped + numwallflipped * 2 > 20) {
- awards[numawards] = awardacrobat;
- numawards++;
- }
- if (numthrowkill == (int(Person::players.size()) - 1)) {
- awards[numawards] = awardlongrange;
- numawards++;
- }
- alldead = 1;
- for (unsigned i = 1; i < Person::players.size(); i++) {
- if (Person::players[i]->dead != 2)
- alldead = 0;
- }
- if (numafterkill > 0 && alldead) {
- awards[numawards] = awardbrutal;
- numawards++;
- }
- if (numreversals > ((float)numattacks)*.8 && numreversals > 3) {
- awards[numawards] = awardaikido;
- numawards++;
- }
- if (maxalarmed == 1 && Person::players.size() > 2) {
- awards[numawards] = awardstrategy;
- numawards++;
- }
- if (numflipfail > 3) {
- awards[numawards] = awardklutz;
- numawards++;
- }
- return numawards;
-}
+++ /dev/null
-/*
-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/>.
-*/
-
-DECLARE_AWARD(awardklutz, "Suicidal")
-DECLARE_AWARD(awardflawless, "Flawless!")
-DECLARE_AWARD(awardalldead, "Take no prisoners")
-DECLARE_AWARD(awardnodead, "Merciful")
-DECLARE_AWARD(awardstealth, "One with the shadows!")
-DECLARE_AWARD(awardswordsman, "Swordsman")
-DECLARE_AWARD(awardkungfu, "Unarmed!")
-DECLARE_AWARD(awardknifefighter, "Knife fighter")
-DECLARE_AWARD(awardcoward, "Coward")
-DECLARE_AWARD(awardevasion, "Escape artist")
-DECLARE_AWARD(awardacrobat, "Gymnast")
-DECLARE_AWARD(awardlongrange, "Blade slinger")
-DECLARE_AWARD(awardbrutal, "Brutal")
-DECLARE_AWARD(awardhyper, "Hyper")
-DECLARE_AWARD(awardaikido, "Aikido master!")
-DECLARE_AWARD(awardrambo, "Rambo")
-DECLARE_AWARD(awardfast, "Fast")
-DECLARE_AWARD(awardrealfast, "Real fast")
-DECLARE_AWARD(awarddamnfast, "Damn fast")
-DECLARE_AWARD(awardstrategy, "Divide and conquer")
-DECLARE_AWARD(awardbojutsu, "Bojutsu")
+++ /dev/null
-/*
-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 AWARDS_H
-#define AWARDS_H
-
-enum bonus_types {
-#define DECLARE_BONUS(id, ...) id,
-#include "Bonuses.def"
-#undef DECLARE_BONUS
- bonus_count
-};
-
-extern const char *bonus_names[bonus_count];
-
-extern int bonus;
-extern float bonusvalue;
-extern float bonustotal;
-extern float bonustime;
-extern float startbonustotal;
-extern float bonusnum[100];
-
-extern void award_bonus(int playerid, int bonusid, int alt_value = 0);
-
-enum award_types {
-#define DECLARE_AWARD(id, name) id,
-#include "Awards.def"
-#undef DECLARE_AWARD
- award_count
-};
-
-extern const char *award_names[award_count];
-
-extern int award_awards(int *);
-
-extern float damagetaken;
-extern int numfalls;
-extern int numflipfail;
-extern int numseen;
-extern int numresponded;
-extern int numstaffattack;
-extern int numswordattack;
-extern int numknifeattack;
-extern int numunarmedattack;
-extern int numescaped;
-extern int numflipped;
-extern int numwallflipped;
-extern int numthrowkill;
-extern int numafterkill;
-extern int numreversals;
-extern int numattacks;
-extern int maxalarmed;
-#endif
-
+++ /dev/null
-/*
-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/>.
-*/
-
-DECLARE_BONUS(nobonus, "", 0)
-DECLARE_BONUS(tracheotomy, "Tracheotomy!", 100)
-DECLARE_BONUS(backstab, "Backstabber!", 100)
-DECLARE_BONUS(spinecrusher, "Spinecrusher!", 100)
-DECLARE_BONUS(ninja, "Ninja Bonus!", 60)
-DECLARE_BONUS(style, "Style Bonus!", 150)
-DECLARE_BONUS(cannon, "Leg Cannon!", 100)
-DECLARE_BONUS(aimbonus, "Nice Aim!", 150)
-DECLARE_BONUS(deepimpact, "Heavy Impact!", 50)
-DECLARE_BONUS(touchofdeath, "Touch of Death!", 150)
-DECLARE_BONUS(swordreversebonus, "Sword Disarm!", 100)
-DECLARE_BONUS(staffreversebonus, "Staff Disarm!", 100)
-DECLARE_BONUS(reverseko, "Reversal KO!", 100)
-// The following five should be kept in that order
-DECLARE_BONUS(solidhit, "Solid Hit!", 10)
-DECLARE_BONUS(twoxcombo, "2X Combo!", 20)
-DECLARE_BONUS(threexcombo, "3X Combo!", 40)
-DECLARE_BONUS(fourxcombo, "4X COMBO!", 80)
-DECLARE_BONUS(megacombo, "MEGA COMBO!", 160)
-DECLARE_BONUS(Reversal, "Reversal!", 60)
-DECLARE_BONUS(Stabbonus, "Punctured!", 40)
-DECLARE_BONUS(Slicebonus, "Sliced!", 10)
-DECLARE_BONUS(Bullseyebonus, "Bullseye!", 30)
-DECLARE_BONUS(Slashbonus, "Slashed!", 40)
-DECLARE_BONUS(Wolfbonus, "WOLF SLAYER!", 300)
-DECLARE_BONUS(FinishedBonus, "SLAIN!", 200)
-DECLARE_BONUS(TackleBonus, "Tackle!", 5)
-DECLARE_BONUS(AboveBonus, "Death from Above!", 50)
+++ /dev/null
-/*
-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/>.
-*/
-
-#include "Campaign.h"
-#include "Game.h"
-#include "Utils/Folders.h"
-#include <dirent.h>
-
-using namespace Game;
-
-std::vector<CampaignLevel> campaignlevels;
-
-bool campaign = false;
-
-int actuallevel = 0;
-
-std::vector<std::string> ListCampaigns()
-{
- errno = 0;
- DIR *campaigns = opendir(Folders::getResourcePath("Campaigns").c_str());
- struct dirent *campaign = NULL;
- if (!campaigns) {
- perror(("Problem while loading campaigns from " + Folders::getResourcePath("Campaigns")).c_str());
- exit(EXIT_FAILURE);
- }
- std::vector<std::string> campaignNames;
- while ((campaign = readdir(campaigns)) != NULL) {
- std::string name(campaign->d_name);
- if (name.length() < 5)
- continue;
- if (!name.compare(name.length() - 4, 4, ".txt")) {
- campaignNames.push_back(name.substr(0, name.length() - 4));
- }
- }
- closedir(campaigns);
- return campaignNames;
-}
-
-void LoadCampaign()
-{
- if (!Account::hasActive()) {
- return;
- }
- std::ifstream ipstream(Folders::getResourcePath("Campaigns/" + Account::active().getCurrentCampaign() + ".txt"));
- if (!ipstream.good()) {
- if (Account::active().getCurrentCampaign() == "main") {
- cerr << "Could not found main campaign!" << endl;
- return;
- }
- cerr << "Could not found campaign \"" << Account::active().getCurrentCampaign() << "\", falling back to main." << endl;
- Account::active().setCurrentCampaign("main");
- return LoadCampaign();
- }
- ipstream.ignore(256, ':');
- int numlevels;
- ipstream >> numlevels;
- campaignlevels.clear();
- for (int i = 0; i < numlevels; i++) {
- CampaignLevel cl;
- ipstream >> cl;
- campaignlevels.push_back(cl);
- }
- ipstream.close();
-
- std::ifstream test(Folders::getResourcePath("Textures/" + Account::active().getCurrentCampaign() + "/World.png"));
- if (test.good()) {
- Mainmenuitems[7].load("Textures/" + Account::active().getCurrentCampaign() + "/World.png", 0);
- } else {
- Mainmenuitems[7].load("Textures/World.png", 0);
- }
-
- if (Account::active().getCampaignChoicesMade() == 0) {
- Account::active().setCampaignScore(0);
- Account::active().resetFasttime();
- }
-}
-
-CampaignLevel::CampaignLevel() :
- width(10),
- choosenext(1)
-{
- location.x = 0;
- location.y = 0;
-}
-
-int CampaignLevel::getStartX() {
- return 30 + 120 + location.x * 400 / 512;
-}
-
-int CampaignLevel::getStartY() {
- return 30 + 30 + (512 - location.y) * 400 / 512;
-}
-
-int CampaignLevel::getEndX() {
- return getStartX() + width;
-}
-
-int CampaignLevel::getEndY() {
- return getStartY() + width;
-}
-
-XYZ CampaignLevel::getCenter() {
- XYZ center;
- center.x = getStartX() + width / 2;
- center.y = getStartY() + width / 2;
- return center;
-}
-
-int CampaignLevel::getWidth() {
- return width;
-}
-
-istream& CampaignLevel::operator<< (istream& is) {
- is.ignore(256, ':');
- is.ignore(256, ':');
- is.ignore(256, ' ');
- is >> mapname;
- is.ignore(256, ':');
- is >> description;
- for (size_t pos = description.find('_'); pos != string::npos; pos = description.find('_', pos)) {
- description.replace(pos, 1, 1, ' ');
- }
- is.ignore(256, ':');
- is >> choosenext;
- is.ignore(256, ':');
- int numnext, next;
- is >> numnext;
- for (int j = 0; j < numnext; j++) {
- is.ignore(256, ':');
- is >> next;
- nextlevel.push_back(next - 1);
- }
- is.ignore(256, ':');
- is >> location.x;
- is.ignore(256, ':');
- is >> location.y;
- return is;
-}
+++ /dev/null
-/*
-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/>.
-*/
-
-#include <vector>
-#include <string>
-
-#include "Quaternions.h"
-
-extern bool campaign;
-
-extern int actuallevel;
-
-std::vector<std::string> ListCampaigns();
-void LoadCampaign();
-
-class CampaignLevel
-{
-private:
- int width;
- struct Position {
- int x, y;
- };
-public:
- std::string mapname;
- std::string description;
- int choosenext;
- /*
- 0 = Immediately load next level at the end of this one.
- 1 = Go back to the world map.
- 2 = Don't bring up the Fiery loading screen. Maybe other things, I've not investigated.
- */
- //int numnext; // 0 on final level. As David said: he meant to add story branching, but he eventually hadn't.
- std::vector<int> nextlevel;
- Position location;
- CampaignLevel();
- int getStartX();
- int getStartY();
- int getEndX();
- int getEndY();
- XYZ getCenter();
- int getWidth();
- std::istream& operator<< (std::istream& is);
- friend std::istream& operator>> (std::istream& is, CampaignLevel& cl) {
- return cl << is;
- }
-};
-
-extern std::vector<CampaignLevel> campaignlevels;
+++ /dev/null
-/*
-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/>.
-*/
-
-#include "ConsoleCmds.h"
-#include "Game.h"
-#include "Dialog.h"
-#include "Hotspot.h"
-#include "Utils/Folders.h"
-
-const char *cmd_names[cmd_count] = {
-#define DECLARE_COMMAND(cmd) #cmd,
-#include "ConsoleCmds.def"
-#undef DECLARE_COMMAND
-};
-
-console_handler cmd_handlers[cmd_count] = {
-#define DECLARE_COMMAND(cmd) ch_##cmd,
-#include "ConsoleCmds.def"
-#undef DECLARE_COMMAND
-};
-
-using namespace Game;
-
-/* globals */
-
-extern bool campaign;
-extern bool cellophane;
-extern int editoractive;
-extern int editorpathtype;
-extern int environment;
-extern float fadestart;
-extern float slomospeed;
-extern float slomofreq;
-extern int tutoriallevel;
-extern int hostile;
-extern int maptype;
-extern Objects objects;
-extern int slomo;
-extern float slomodelay;
-extern bool skyboxtexture;
-extern float skyboxr;
-extern float skyboxg;
-extern float skyboxb;
-extern float skyboxlightr;
-extern float skyboxlightg;
-extern float skyboxlightb;
-extern Terrain terrain;
-extern float viewdistance;
-
-/* defined in GameTick.cpp */
-
-extern int whichlevel;
-
-float tintr = 1, tintg = 1, tintb = 1;
-
-/* Helpers used in console commands */
-
-/* Return true if PFX is a prefix of STR (case-insensitive). */
-static bool stripfx(const char *str, const char *pfx)
-{
- return !strncasecmp(str, pfx, strlen(pfx));
-}
-
-static void set_proportion(int pnum, const char *args)
-{
- float headprop, bodyprop, armprop, legprop;
-
- sscanf(args, "%f%f%f%f", &headprop, &bodyprop, &armprop, &legprop);
-
- if (Person::players[pnum]->creature == wolftype) {
- Person::players[pnum]->proportionhead = 1.1 * headprop;
- Person::players[pnum]->proportionbody = 1.1 * bodyprop;
- Person::players[pnum]->proportionarms = 1.1 * armprop;
- Person::players[pnum]->proportionlegs = 1.1 * legprop;
- } else if (Person::players[pnum]->creature == rabbittype) {
- Person::players[pnum]->proportionhead = 1.2 * headprop;
- Person::players[pnum]->proportionbody = 1.05 * bodyprop;
- Person::players[pnum]->proportionarms = 1.00 * armprop;
- Person::players[pnum]->proportionlegs = 1.1 * legprop;
- Person::players[pnum]->proportionlegs.y = 1.05 * legprop;
- }
-}
-
-static void set_protection(int pnum, const char *args)
-{
- float head, high, low;
- sscanf(args, "%f%f%f", &head, &high, &low);
-
- Person::players[pnum]->protectionhead = head;
- Person::players[pnum]->protectionhigh = high;
- Person::players[pnum]->protectionlow = low;
-}
-
-static void set_armor(int pnum, const char *args)
-{
- float head, high, low;
- sscanf(args, "%f%f%f", &head, &high, &low);
-
- Person::players[pnum]->armorhead = head;
- Person::players[pnum]->armorhigh = high;
- Person::players[pnum]->armorlow = low;
-}
-
-static void set_metal(int pnum, const char *args)
-{
- float head, high, low;
- sscanf(args, "%f%f%f", &head, &high, &low);
-
- Person::players[pnum]->metalhead = head;
- Person::players[pnum]->metalhigh = high;
- Person::players[pnum]->metallow = low;
-}
-
-static void set_noclothes(int pnum, const char *args)
-{
- Person::players[pnum]->numclothes = 0;
- Person::players[pnum]->skeleton.drawmodel.textureptr.load(
- creatureskin[Person::players[pnum]->creature][Person::players[pnum]->whichskin], 1,
- &Person::players[pnum]->skeleton.skinText[0], &Person::players[pnum]->skeleton.skinsize);
-}
-
-static void set_clothes(int pnum, const char *args)
-{
- char buf[64];
- snprintf(buf, 63, "Textures/%s.png", args);
-
- int id = Person::players[pnum]->numclothes;
- strcpy(Person::players[pnum]->clothes[id], buf);
- Person::players[pnum]->clothestintr[id] = tintr;
- Person::players[pnum]->clothestintg[id] = tintg;
- Person::players[pnum]->clothestintb[id] = tintb;
- Person::players[pnum]->numclothes++;
-
- if (!Person::players[pnum]->addClothes(id))
- return;
-
- Person::players[pnum]->DoMipmaps();
-}
-
-/* Console commands themselves */
-
-void ch_quit(const char *args)
-{
- tryquit = 1;
-}
-
-void ch_map(const char *args)
-{
- Loadlevel(args);
- whichlevel = -2;
- campaign = 0;
-}
-
-void ch_save(const char *args)
-{
- std::string map_path = Folders::getUserDataPath() + "/Maps/" + args;
-
- int mapvers = 12;
-
- FILE *tfile;
- tfile = fopen( map_path.c_str(), "wb" );
- fpackf(tfile, "Bi", mapvers);
- fpackf(tfile, "Bi", maptype);
- fpackf(tfile, "Bi", hostile);
- fpackf(tfile, "Bf Bf", viewdistance, fadestart);
- fpackf(tfile, "Bb Bf Bf Bf", skyboxtexture, skyboxr, skyboxg, skyboxb);
- fpackf(tfile, "Bf Bf Bf", skyboxlightr, skyboxlightg, skyboxlightb);
- fpackf(tfile, "Bf Bf Bf Bf Bf Bi", Person::players[0]->coords.x, Person::players[0]->coords.y, Person::players[0]->coords.z,
- Person::players[0]->yaw, Person::players[0]->targetyaw, Person::players[0]->num_weapons);
- if (Person::players[0]->num_weapons > 0 && Person::players[0]->num_weapons < 5)
- for (int j = 0; j < Person::players[0]->num_weapons; j++)
- fpackf(tfile, "Bi", weapons[Person::players[0]->weaponids[j]].getType());
-
- fpackf(tfile, "Bf Bf Bf", Person::players[0]->armorhead, Person::players[0]->armorhigh, Person::players[0]->armorlow);
- fpackf(tfile, "Bf Bf Bf", Person::players[0]->protectionhead, Person::players[0]->protectionhigh, Person::players[0]->protectionlow);
- fpackf(tfile, "Bf Bf Bf", Person::players[0]->metalhead, Person::players[0]->metalhigh, Person::players[0]->metallow);
- fpackf(tfile, "Bf Bf", Person::players[0]->power, Person::players[0]->speedmult);
-
- fpackf(tfile, "Bi", Person::players[0]->numclothes);
-
- fpackf(tfile, "Bi Bi", Person::players[0]->whichskin, Person::players[0]->creature);
-
- Dialog::saveDialogs(tfile);
-
- for (int k = 0; k < Person::players[0]->numclothes; k++) {
- int templength = strlen(Person::players[0]->clothes[k]);
- fpackf(tfile, "Bi", templength);
- for (int l = 0; l < templength; l++)
- fpackf(tfile, "Bb", Person::players[0]->clothes[k][l]);
- fpackf(tfile, "Bf Bf Bf", Person::players[0]->clothestintr[k], Person::players[0]->clothestintg[k], Person::players[0]->clothestintb[k]);
- }
-
- fpackf(tfile, "Bi", environment);
-
- fpackf(tfile, "Bi", objects.numobjects);
-
- for (int k = 0; k < objects.numobjects; k++)
- fpackf(tfile, "Bi Bf Bf Bf Bf Bf Bf", objects.type[k], objects.yaw[k], objects.pitch[k],
- objects.position[k].x, objects.position[k].y, objects.position[k].z, objects.scale[k]);
-
- fpackf(tfile, "Bi", Hotspot::hotspots.size());
- for (int i = 0; i < Hotspot::hotspots.size(); i++) {
- fpackf(tfile, "Bi Bf Bf Bf Bf", Hotspot::hotspots[i].type, Hotspot::hotspots[i].size, Hotspot::hotspots[i].position.x, Hotspot::hotspots[i].position.y, Hotspot::hotspots[i].position.z);
- int templength = strlen(Hotspot::hotspots[i].text);
- fpackf(tfile, "Bi", templength);
- for (int l = 0; l < templength; l++)
- fpackf(tfile, "Bb", Hotspot::hotspots[i].text[l]);
- }
-
- fpackf(tfile, "Bi", Person::players.size());
- if (Person::players.size() > maxplayers) {
- cout << "Warning: this level contains more players than allowed" << endl;
- }
- for (unsigned j = 1; j < Person::players.size(); j++) {
- fpackf(tfile, "Bi Bi Bf Bf Bf Bi Bi Bf Bb Bf", Person::players[j]->whichskin, Person::players[j]->creature,
- Person::players[j]->coords.x, Person::players[j]->coords.y, Person::players[j]->coords.z,
- Person::players[j]->num_weapons, Person::players[j]->howactive, Person::players[j]->scale, Person::players[j]->immobile, Person::players[j]->yaw);
- if (Person::players[j]->num_weapons < 5)
- for (int k = 0; k < Person::players[j]->num_weapons; k++)
- fpackf(tfile, "Bi", weapons[Person::players[j]->weaponids[k]].getType());
- if (Person::players[j]->numwaypoints < 30) {
- fpackf(tfile, "Bi", Person::players[j]->numwaypoints);
- for (int k = 0; k < Person::players[j]->numwaypoints; k++) {
- fpackf(tfile, "Bf", Person::players[j]->waypoints[k].x);
- fpackf(tfile, "Bf", Person::players[j]->waypoints[k].y);
- fpackf(tfile, "Bf", Person::players[j]->waypoints[k].z);
- fpackf(tfile, "Bi", Person::players[j]->waypointtype[k]);
- }
- fpackf(tfile, "Bi", Person::players[j]->waypoint);
- } else {
- Person::players[j]->numwaypoints = 0;
- Person::players[j]->waypoint = 0;
- fpackf(tfile, "Bi Bi Bi", Person::players[j]->numwaypoints, Person::players[j]->waypoint, Person::players[j]->waypoint);
- }
-
- fpackf(tfile, "Bf Bf Bf", Person::players[j]->armorhead, Person::players[j]->armorhigh, Person::players[j]->armorlow);
- fpackf(tfile, "Bf Bf Bf", Person::players[j]->protectionhead, Person::players[j]->protectionhigh, Person::players[j]->protectionlow);
- fpackf(tfile, "Bf Bf Bf", Person::players[j]->metalhead, Person::players[j]->metalhigh, Person::players[j]->metallow);
- fpackf(tfile, "Bf Bf", Person::players[j]->power, Person::players[j]->speedmult);
-
- float headprop, bodyprop, armprop, legprop;
- if (Person::players[j]->creature == wolftype) {
- headprop = Person::players[j]->proportionhead.x / 1.1;
- bodyprop = Person::players[j]->proportionbody.x / 1.1;
- armprop = Person::players[j]->proportionarms.x / 1.1;
- legprop = Person::players[j]->proportionlegs.x / 1.1;
- } else if (Person::players[j]->creature == rabbittype) {
- headprop = Person::players[j]->proportionhead.x / 1.2;
- bodyprop = Person::players[j]->proportionbody.x / 1.05;
- armprop = Person::players[j]->proportionarms.x / 1.00;
- legprop = Person::players[j]->proportionlegs.x / 1.1;
- }
-
- fpackf(tfile, "Bf Bf Bf Bf", headprop, bodyprop, armprop, legprop);
-
- fpackf(tfile, "Bi", Person::players[j]->numclothes);
- if (Person::players[j]->numclothes)
- for (int k = 0; k < Person::players[j]->numclothes; k++) {
- int templength;
- templength = strlen(Person::players[j]->clothes[k]);
- fpackf(tfile, "Bi", templength);
- for (int l = 0; l < templength; l++)
- fpackf(tfile, "Bb", Person::players[j]->clothes[k][l]);
- fpackf(tfile, "Bf Bf Bf", Person::players[j]->clothestintr[k], Person::players[j]->clothestintg[k], Person::players[j]->clothestintb[k]);
- }
- }
-
- fpackf(tfile, "Bi", numpathpoints);
- for (int j = 0; j < numpathpoints; j++) {
- fpackf(tfile, "Bf Bf Bf Bi", pathpoint[j].x, pathpoint[j].y, pathpoint[j].z, numpathpointconnect[j]);
- for (int k = 0; k < numpathpointconnect[j]; k++)
- fpackf(tfile, "Bi", pathpointconnect[j][k]);
- }
-
- fpackf(tfile, "Bf Bf Bf Bf", mapcenter.x, mapcenter.y, mapcenter.z, mapradius);
-
- fclose(tfile);
-}
-
-void ch_cellar(const char *args)
-{
- Person::players[0]->skeleton.drawmodel.textureptr.load("Textures/Furdarko.jpg", 1, &Person::players[0]->skeleton.skinText[0], &Person::players[0]->skeleton.skinsize);
-}
-
-void ch_tint(const char *args)
-{
- sscanf(args, "%f%f%f", &tintr, &tintg, &tintb);
-}
-
-void ch_tintr(const char *args)
-{
- tintr = atof(args);
-}
-
-void ch_tintg(const char *args)
-{
- tintg = atof(args);
-}
-
-void ch_tintb(const char *args)
-{
- tintb = atof(args);
-}
-
-void ch_speed(const char *args)
-{
- Person::players[0]->speedmult = atof(args);
-}
-
-void ch_strength(const char *args)
-{
- Person::players[0]->power = atof(args);
-}
-
-void ch_power(const char *args)
-{
- Person::players[0]->power = atof(args);
-}
-
-void ch_size(const char *args)
-{
- Person::players[0]->scale = atof(args) * .2;
-}
-
-void ch_sizenear(const char *args)
-{
- int closest = findClosestPlayer();
- if (closest >= 0)
- Person::players[closest]->scale = atof(args) * .2;
-}
-
-void ch_proportion(const char *args)
-{
- set_proportion(0, args);
-}
-
-void ch_proportionnear(const char *args)
-{
- int closest = findClosestPlayer();
- if (closest >= 0)
- set_proportion(closest, args);
-}
-
-void ch_protection(const char *args)
-{
- set_protection(0, args);
-}
-
-void ch_protectionnear(const char *args)
-{
- int closest = findClosestPlayer();
- if (closest >= 0)
- set_protection(closest, args);
-}
-
-void ch_armor(const char *args)
-{
- set_armor(0, args);
-}
-
-void ch_armornear(const char *args)
-{
- int closest = findClosestPlayer();
- if (closest >= 0)
- set_armor(closest, args);
-}
-
-void ch_protectionreset(const char *args)
-{
- set_protection(0, "1 1 1");
- set_armor(0, "1 1 1");
-}
-
-void ch_metal(const char *args)
-{
- set_metal(0, args);
-}
-
-void ch_noclothes(const char *args)
-{
- set_noclothes(0, args);
-}
-
-void ch_noclothesnear(const char *args)
-{
- int closest = findClosestPlayer();
- if (closest >= 0)
- set_noclothes(closest, args);
-}
-
-void ch_clothes(const char *args)
-{
- set_clothes(0, args);
-}
-
-void ch_clothesnear(const char *args)
-{
- int closest = findClosestPlayer();
- if (closest >= 0)
- set_clothes(closest, args);
-}
-
-void ch_belt(const char *args)
-{
- Person::players[0]->skeleton.clothes = !Person::players[0]->skeleton.clothes;
-}
-
-
-void ch_cellophane(const char *args)
-{
- cellophane = !cellophane;
- float mul = (cellophane ? 0 : 1);
-
- for (auto player : Person::players) {
- player->proportionhead.z = player->proportionhead.x * mul;
- player->proportionbody.z = player->proportionbody.x * mul;
- player->proportionarms.z = player->proportionarms.x * mul;
- player->proportionlegs.z = player->proportionlegs.x * mul;
- }
-}
-
-void ch_funnybunny(const char *args)
-{
- Person::players[0]->creature = rabbittype;
- Person::players[0]->skeletonLoad(true);
- Person::players[0]->scale = .2;
- Person::players[0]->headless = 0;
- Person::players[0]->damagetolerance = 200;
- set_proportion(0, "1 1 1 1");
-}
-
-void ch_wolfie(const char *args)
-{
- Person::players[0]->creature = wolftype;
- Person::players[0]->skeletonLoad();
- Person::players[0]->damagetolerance = 300;
- set_proportion(0, "1 1 1 1");
-}
-
-void ch_wolfieisgod(const char *args)
-{
- ch_wolfie(args);
-}
-
-void ch_wolf(const char *args)
-{
- Person::players[0]->skeleton.drawmodel.textureptr.load("Textures/Wolf.jpg", 1, &Person::players[0]->skeleton.skinText[0], &Person::players[0]->skeleton.skinsize);
-}
-
-void ch_snowwolf(const char *args)
-{
- Person::players[0]->skeleton.drawmodel.textureptr.load("Textures/SnowWolf.jpg", 1, &Person::players[0]->skeleton.skinText[0], &Person::players[0]->skeleton.skinsize);
-}
-
-void ch_darkwolf(const char *args)
-{
- Person::players[0]->skeleton.drawmodel.textureptr.load("Textures/DarkWolf.jpg", 1, &Person::players[0]->skeleton.skinText[0], &Person::players[0]->skeleton.skinsize);
-}
-
-void ch_lizardwolf(const char *args)
-{
- Person::players[0]->skeleton.drawmodel.textureptr.load("Textures/LizardWolf.jpg", 1, &Person::players[0]->skeleton.skinText[0], &Person::players[0]->skeleton.skinsize);
-}
-
-void ch_white(const char *args)
-{
- Person::players[0]->skeleton.drawmodel.textureptr.load("Textures/Fur.jpg", 1, &Person::players[0]->skeleton.skinText[0], &Person::players[0]->skeleton.skinsize);
-}
-
-void ch_brown(const char *args)
-{
- Person::players[0]->skeleton.drawmodel.textureptr.load("Textures/Fur3.jpg", 1, &Person::players[0]->skeleton.skinText[0], &Person::players[0]->skeleton.skinsize);
-}
-
-void ch_black(const char *args)
-{
- Person::players[0]->skeleton.drawmodel.textureptr.load("Textures/Fur2.jpg", 1, &Person::players[0]->skeleton.skinText[0], &Person::players[0]->skeleton.skinsize);
-}
-
-void ch_sizemin(const char *args)
-{
- for (unsigned i = 1; i < Person::players.size(); i++)
- if (Person::players[i]->scale < 0.8 * 0.2)
- Person::players[i]->scale = 0.8 * 0.2;
-}
-
-void ch_tutorial(const char *args)
-{
- tutoriallevel = atoi(args);
-}
-
-void ch_hostile(const char *args)
-{
- hostile = atoi(args);
-}
-
-void ch_type(const char *args)
-{
- int n = sizeof(editortypenames) / sizeof(editortypenames[0]);
- for (int i = 0; i < n; i++)
- if (stripfx(args, editortypenames[i])) {
- editoractive = i;
- break;
- }
-}
-
-void ch_path(const char *args)
-{
- int n = sizeof(pathtypenames) / sizeof(pathtypenames[0]);
- for (int i = 0; i < n; i++)
- if (stripfx(args, pathtypenames[i])) {
- editorpathtype = i;
- break;
- }
-}
-
-void ch_hs(const char *args)
-{
- float size;
- int type, shift;
- sscanf(args, "%f%d %n", &size, &type, &shift);
-
- Hotspot::hotspots.emplace_back(Person::players[0]->coords, type, size);
-
- strcpy(Hotspot::hotspots.back().text, args + shift);
- strcat(Hotspot::hotspots.back().text, "\n");
-}
-
-void ch_dialogue(const char *args)
-{
- int type;
- char buf1[32];
-
- sscanf(args, "%d %31s", &type, buf1);
- std::string filename = std::string("Dialogues/") + buf1 + ".txt";
-
- Dialog::dialogs.push_back(Dialog(type, filename));
-
- Dialog::directing = true;
- Dialog::indialogue = 0;
- Dialog::whichdialogue = Dialog::dialogs.size();
-}
-
-void ch_fixdialogue(const char *args)
-{
- char buf1[32];
- int whichdi;
-
- sscanf(args, "%d %31s", &whichdi, buf1);
- std::string filename = std::string("Dialogues/") + buf1 + ".txt";
-
- Dialog::dialogs[whichdi] = Dialog(Dialog::dialogs[whichdi].type, filename);
-}
-
-void ch_fixtype(const char *args)
-{
- int dlg;
- sscanf(args, "%d", &dlg);
- Dialog::dialogs[0].type = dlg;
-}
-
-void ch_fixrotation(const char *args)
-{
- int playerId = Dialog::currentScene().participantfocus;
- Dialog::currentDialog().participantyaw[playerId] = Person::players[playerId]->yaw;
-}
-
-void ch_ddialogue(const char *args)
-{
- if (!Dialog::dialogs.empty()) {
- Dialog::dialogs.pop_back();
- }
-}
-
-void ch_dhs(const char *args)
-{
- if (!Hotspot::hotspots.empty()) {
- Hotspot::hotspots.pop_back();
- }
-}
-
-void ch_immobile(const char *args)
-{
- Person::players[0]->immobile = 1;
-}
-
-void ch_allimmobile(const char *args)
-{
- for (unsigned i = 1; i < Person::players.size(); i++)
- Person::players[i]->immobile = 1;
-}
-
-void ch_mobile(const char *args)
-{
- Person::players[0]->immobile = 0;
-}
-
-void ch_default(const char *args)
-{
- Person::players[0]->armorhead = 1;
- Person::players[0]->armorhigh = 1;
- Person::players[0]->armorlow = 1;
- Person::players[0]->protectionhead = 1;
- Person::players[0]->protectionhigh = 1;
- Person::players[0]->protectionlow = 1;
- Person::players[0]->metalhead = 1;
- Person::players[0]->metalhigh = 1;
- Person::players[0]->metallow = 1;
- Person::players[0]->power = 1;
- Person::players[0]->speedmult = 1;
- Person::players[0]->scale = 1;
-
- if (Person::players[0]->creature == wolftype) {
- Person::players[0]->proportionhead = 1.1;
- Person::players[0]->proportionbody = 1.1;
- Person::players[0]->proportionarms = 1.1;
- Person::players[0]->proportionlegs = 1.1;
- } else if (Person::players[0]->creature == rabbittype) {
- Person::players[0]->proportionhead = 1.2;
- Person::players[0]->proportionbody = 1.05;
- Person::players[0]->proportionarms = 1.00;
- Person::players[0]->proportionlegs = 1.1;
- Person::players[0]->proportionlegs.y = 1.05;
- }
-
- Person::players[0]->numclothes = 0;
- Person::players[0]->skeleton.drawmodel.textureptr.load(
- creatureskin[Person::players[0]->creature][Person::players[0]->whichskin], 1,
- &Person::players[0]->skeleton.skinText[0], &Person::players[0]->skeleton.skinsize);
-
- editoractive = typeactive;
- Person::players[0]->immobile = 0;
-}
-
-void ch_play(const char *args)
-{
- int dlg;
- sscanf(args, "%d", &dlg);
- Dialog::whichdialogue = dlg;
-
- if (Dialog::whichdialogue >= Dialog::dialogs.size()) {
- return;
- }
-
- Dialog::currentDialog().play();
-}
-
-void ch_mapkilleveryone(const char *args)
-{
- maptype = mapkilleveryone;
-}
-
-void ch_mapkillmost(const char *args)
-{
- maptype = mapkillmost;
-}
-
-void ch_mapkillsomeone(const char *args)
-{
- maptype = mapkillsomeone;
-}
-
-void ch_mapgosomewhere(const char *args)
-{
- maptype = mapgosomewhere;
-}
-
-void ch_viewdistance(const char *args)
-{
- viewdistance = atof(args) * 100;
-}
-
-void ch_fadestart(const char *args)
-{
- fadestart = atof(args);
-}
-
-void ch_slomo(const char *args)
-{
- slomospeed = atof(args);
- slomo = !slomo;
- slomodelay = 1000;
-}
-
-void ch_slofreq(const char *args)
-{
- slomofreq = atof(args);
-}
-
-void ch_skytint(const char *args)
-{
- sscanf(args, "%f%f%f", &skyboxr, &skyboxg, &skyboxb);
-
- skyboxlightr = skyboxr;
- skyboxlightg = skyboxg;
- skyboxlightb = skyboxb;
-
- SetUpLighting();
-
- terrain.DoShadows();
- objects.DoShadows();
-}
-
-void ch_skylight(const char *args)
-{
- sscanf(args, "%f%f%f", &skyboxlightr, &skyboxlightg, &skyboxlightb);
-
- SetUpLighting();
-
- terrain.DoShadows();
- objects.DoShadows();
-}
-
-void ch_skybox(const char *args)
-{
- skyboxtexture = !skyboxtexture;
-
- SetUpLighting();
-
- terrain.DoShadows();
- objects.DoShadows();
-}
+++ /dev/null
-/*
-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/>.
-*/
-
-DECLARE_COMMAND(quit)
-DECLARE_COMMAND(map)
-DECLARE_COMMAND(save)
-
-DECLARE_COMMAND(cellar)
-DECLARE_COMMAND(tint)
-DECLARE_COMMAND(tintr)
-DECLARE_COMMAND(tintg)
-DECLARE_COMMAND(tintb)
-DECLARE_COMMAND(speed)
-DECLARE_COMMAND(strength)
-DECLARE_COMMAND(power)
-DECLARE_COMMAND(size)
-DECLARE_COMMAND(sizenear)
-DECLARE_COMMAND(proportion)
-DECLARE_COMMAND(proportionnear)
-DECLARE_COMMAND(protection)
-DECLARE_COMMAND(protectionnear)
-DECLARE_COMMAND(protectionreset)
-DECLARE_COMMAND(armor)
-DECLARE_COMMAND(armornear)
-DECLARE_COMMAND(metal)
-DECLARE_COMMAND(clothes)
-DECLARE_COMMAND(clothesnear)
-DECLARE_COMMAND(noclothes)
-DECLARE_COMMAND(noclothesnear)
-DECLARE_COMMAND(belt)
-DECLARE_COMMAND(cellophane)
-DECLARE_COMMAND(funnybunny)
-DECLARE_COMMAND(wolfie)
-DECLARE_COMMAND(wolfieisgod)
-DECLARE_COMMAND(wolf)
-DECLARE_COMMAND(snowwolf)
-DECLARE_COMMAND(darkwolf)
-DECLARE_COMMAND(lizardwolf)
-DECLARE_COMMAND(white)
-DECLARE_COMMAND(brown)
-DECLARE_COMMAND(black)
-
-DECLARE_COMMAND(sizemin)
-DECLARE_COMMAND(viewdistance)
-DECLARE_COMMAND(fadestart)
-DECLARE_COMMAND(slomo)
-DECLARE_COMMAND(slofreq)
-
-DECLARE_COMMAND(tutorial)
-DECLARE_COMMAND(hostile)
-DECLARE_COMMAND(type)
-DECLARE_COMMAND(path)
-DECLARE_COMMAND(hs)
-DECLARE_COMMAND(dhs)
-DECLARE_COMMAND(dialogue)
-DECLARE_COMMAND(fixdialogue)
-DECLARE_COMMAND(ddialogue)
-DECLARE_COMMAND(fixtype)
-DECLARE_COMMAND(fixrotation)
-DECLARE_COMMAND(immobile)
-DECLARE_COMMAND(allimmobile)
-DECLARE_COMMAND(mobile)
-DECLARE_COMMAND(default)
-DECLARE_COMMAND(play)
-
-DECLARE_COMMAND(mapkilleveryone)
-DECLARE_COMMAND(mapkillmost)
-DECLARE_COMMAND(mapkillsomeone)
-DECLARE_COMMAND(mapgosomewhere)
-
-DECLARE_COMMAND(skytint)
-DECLARE_COMMAND(skylight)
-DECLARE_COMMAND(skybox)
+++ /dev/null
-/*
-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/>.
-*/
-
-typedef void (*console_handler)(const char *args);
-
-#define DECLARE_COMMAND(cmd) void ch_##cmd(const char *args);
-#include "ConsoleCmds.def"
-#undef DECLARE_COMMAND
-
-/* FIXME - This is only to get cmd_count, not very clean */
-enum console_command {
-#define DECLARE_COMMAND(cmd) cmd_##cmd,
-#include "ConsoleCmds.def"
-#undef DECLARE_COMMAND
- cmd_count
-};
-
-extern const char *cmd_names[cmd_count];
-
-extern console_handler cmd_handlers[cmd_count];
--- /dev/null
+/*
+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/>.
+*/
+
+#include "Game.h"
+#include "Devtools/ConsoleCmds.h"
+#include "Level/Dialog.h"
+#include "Level/Hotspot.h"
+#include "Utils/Folders.h"
+
+const char *cmd_names[cmd_count] = {
+#define DECLARE_COMMAND(cmd) #cmd,
+#include "ConsoleCmds.def"
+#undef DECLARE_COMMAND
+};
+
+console_handler cmd_handlers[cmd_count] = {
+#define DECLARE_COMMAND(cmd) ch_##cmd,
+#include "ConsoleCmds.def"
+#undef DECLARE_COMMAND
+};
+
+using namespace Game;
+
+/* globals */
+
+extern bool campaign;
+extern bool cellophane;
+extern int editoractive;
+extern int editorpathtype;
+extern int environment;
+extern float fadestart;
+extern float slomospeed;
+extern float slomofreq;
+extern int tutoriallevel;
+extern int hostile;
+extern int maptype;
+extern Objects objects;
+extern int slomo;
+extern float slomodelay;
+extern bool skyboxtexture;
+extern float skyboxr;
+extern float skyboxg;
+extern float skyboxb;
+extern float skyboxlightr;
+extern float skyboxlightg;
+extern float skyboxlightb;
+extern Terrain terrain;
+extern float viewdistance;
+
+/* defined in GameTick.cpp */
+
+extern int whichlevel;
+
+float tintr = 1, tintg = 1, tintb = 1;
+
+/* Helpers used in console commands */
+
+/* Return true if PFX is a prefix of STR (case-insensitive). */
+static bool stripfx(const char *str, const char *pfx)
+{
+ return !strncasecmp(str, pfx, strlen(pfx));
+}
+
+static void set_proportion(int pnum, const char *args)
+{
+ float headprop, bodyprop, armprop, legprop;
+
+ sscanf(args, "%f%f%f%f", &headprop, &bodyprop, &armprop, &legprop);
+
+ if (Person::players[pnum]->creature == wolftype) {
+ Person::players[pnum]->proportionhead = 1.1 * headprop;
+ Person::players[pnum]->proportionbody = 1.1 * bodyprop;
+ Person::players[pnum]->proportionarms = 1.1 * armprop;
+ Person::players[pnum]->proportionlegs = 1.1 * legprop;
+ } else if (Person::players[pnum]->creature == rabbittype) {
+ Person::players[pnum]->proportionhead = 1.2 * headprop;
+ Person::players[pnum]->proportionbody = 1.05 * bodyprop;
+ Person::players[pnum]->proportionarms = 1.00 * armprop;
+ Person::players[pnum]->proportionlegs = 1.1 * legprop;
+ Person::players[pnum]->proportionlegs.y = 1.05 * legprop;
+ }
+}
+
+static void set_protection(int pnum, const char *args)
+{
+ float head, high, low;
+ sscanf(args, "%f%f%f", &head, &high, &low);
+
+ Person::players[pnum]->protectionhead = head;
+ Person::players[pnum]->protectionhigh = high;
+ Person::players[pnum]->protectionlow = low;
+}
+
+static void set_armor(int pnum, const char *args)
+{
+ float head, high, low;
+ sscanf(args, "%f%f%f", &head, &high, &low);
+
+ Person::players[pnum]->armorhead = head;
+ Person::players[pnum]->armorhigh = high;
+ Person::players[pnum]->armorlow = low;
+}
+
+static void set_metal(int pnum, const char *args)
+{
+ float head, high, low;
+ sscanf(args, "%f%f%f", &head, &high, &low);
+
+ Person::players[pnum]->metalhead = head;
+ Person::players[pnum]->metalhigh = high;
+ Person::players[pnum]->metallow = low;
+}
+
+static void set_noclothes(int pnum, const char *args)
+{
+ Person::players[pnum]->numclothes = 0;
+ Person::players[pnum]->skeleton.drawmodel.textureptr.load(
+ creatureskin[Person::players[pnum]->creature][Person::players[pnum]->whichskin], 1,
+ &Person::players[pnum]->skeleton.skinText[0], &Person::players[pnum]->skeleton.skinsize);
+}
+
+static void set_clothes(int pnum, const char *args)
+{
+ char buf[64];
+ snprintf(buf, 63, "Textures/%s.png", args);
+
+ int id = Person::players[pnum]->numclothes;
+ strcpy(Person::players[pnum]->clothes[id], buf);
+ Person::players[pnum]->clothestintr[id] = tintr;
+ Person::players[pnum]->clothestintg[id] = tintg;
+ Person::players[pnum]->clothestintb[id] = tintb;
+ Person::players[pnum]->numclothes++;
+
+ if (!Person::players[pnum]->addClothes(id))
+ return;
+
+ Person::players[pnum]->DoMipmaps();
+}
+
+/* Console commands themselves */
+
+void ch_quit(const char *args)
+{
+ tryquit = 1;
+}
+
+void ch_map(const char *args)
+{
+ Loadlevel(args);
+ whichlevel = -2;
+ campaign = 0;
+}
+
+void ch_save(const char *args)
+{
+ std::string map_path = Folders::getUserDataPath() + "/Maps/" + args;
+
+ int mapvers = 12;
+
+ FILE *tfile;
+ tfile = fopen( map_path.c_str(), "wb" );
+ fpackf(tfile, "Bi", mapvers);
+ fpackf(tfile, "Bi", maptype);
+ fpackf(tfile, "Bi", hostile);
+ fpackf(tfile, "Bf Bf", viewdistance, fadestart);
+ fpackf(tfile, "Bb Bf Bf Bf", skyboxtexture, skyboxr, skyboxg, skyboxb);
+ fpackf(tfile, "Bf Bf Bf", skyboxlightr, skyboxlightg, skyboxlightb);
+ fpackf(tfile, "Bf Bf Bf Bf Bf Bi", Person::players[0]->coords.x, Person::players[0]->coords.y, Person::players[0]->coords.z,
+ Person::players[0]->yaw, Person::players[0]->targetyaw, Person::players[0]->num_weapons);
+ if (Person::players[0]->num_weapons > 0 && Person::players[0]->num_weapons < 5)
+ for (int j = 0; j < Person::players[0]->num_weapons; j++)
+ fpackf(tfile, "Bi", weapons[Person::players[0]->weaponids[j]].getType());
+
+ fpackf(tfile, "Bf Bf Bf", Person::players[0]->armorhead, Person::players[0]->armorhigh, Person::players[0]->armorlow);
+ fpackf(tfile, "Bf Bf Bf", Person::players[0]->protectionhead, Person::players[0]->protectionhigh, Person::players[0]->protectionlow);
+ fpackf(tfile, "Bf Bf Bf", Person::players[0]->metalhead, Person::players[0]->metalhigh, Person::players[0]->metallow);
+ fpackf(tfile, "Bf Bf", Person::players[0]->power, Person::players[0]->speedmult);
+
+ fpackf(tfile, "Bi", Person::players[0]->numclothes);
+
+ fpackf(tfile, "Bi Bi", Person::players[0]->whichskin, Person::players[0]->creature);
+
+ Dialog::saveDialogs(tfile);
+
+ for (int k = 0; k < Person::players[0]->numclothes; k++) {
+ int templength = strlen(Person::players[0]->clothes[k]);
+ fpackf(tfile, "Bi", templength);
+ for (int l = 0; l < templength; l++)
+ fpackf(tfile, "Bb", Person::players[0]->clothes[k][l]);
+ fpackf(tfile, "Bf Bf Bf", Person::players[0]->clothestintr[k], Person::players[0]->clothestintg[k], Person::players[0]->clothestintb[k]);
+ }
+
+ fpackf(tfile, "Bi", environment);
+
+ fpackf(tfile, "Bi", objects.numobjects);
+
+ for (int k = 0; k < objects.numobjects; k++)
+ fpackf(tfile, "Bi Bf Bf Bf Bf Bf Bf", objects.type[k], objects.yaw[k], objects.pitch[k],
+ objects.position[k].x, objects.position[k].y, objects.position[k].z, objects.scale[k]);
+
+ fpackf(tfile, "Bi", Hotspot::hotspots.size());
+ for (int i = 0; i < Hotspot::hotspots.size(); i++) {
+ fpackf(tfile, "Bi Bf Bf Bf Bf", Hotspot::hotspots[i].type, Hotspot::hotspots[i].size, Hotspot::hotspots[i].position.x, Hotspot::hotspots[i].position.y, Hotspot::hotspots[i].position.z);
+ int templength = strlen(Hotspot::hotspots[i].text);
+ fpackf(tfile, "Bi", templength);
+ for (int l = 0; l < templength; l++)
+ fpackf(tfile, "Bb", Hotspot::hotspots[i].text[l]);
+ }
+
+ fpackf(tfile, "Bi", Person::players.size());
+ if (Person::players.size() > maxplayers) {
+ cout << "Warning: this level contains more players than allowed" << endl;
+ }
+ for (unsigned j = 1; j < Person::players.size(); j++) {
+ fpackf(tfile, "Bi Bi Bf Bf Bf Bi Bi Bf Bb Bf", Person::players[j]->whichskin, Person::players[j]->creature,
+ Person::players[j]->coords.x, Person::players[j]->coords.y, Person::players[j]->coords.z,
+ Person::players[j]->num_weapons, Person::players[j]->howactive, Person::players[j]->scale, Person::players[j]->immobile, Person::players[j]->yaw);
+ if (Person::players[j]->num_weapons < 5)
+ for (int k = 0; k < Person::players[j]->num_weapons; k++)
+ fpackf(tfile, "Bi", weapons[Person::players[j]->weaponids[k]].getType());
+ if (Person::players[j]->numwaypoints < 30) {
+ fpackf(tfile, "Bi", Person::players[j]->numwaypoints);
+ for (int k = 0; k < Person::players[j]->numwaypoints; k++) {
+ fpackf(tfile, "Bf", Person::players[j]->waypoints[k].x);
+ fpackf(tfile, "Bf", Person::players[j]->waypoints[k].y);
+ fpackf(tfile, "Bf", Person::players[j]->waypoints[k].z);
+ fpackf(tfile, "Bi", Person::players[j]->waypointtype[k]);
+ }
+ fpackf(tfile, "Bi", Person::players[j]->waypoint);
+ } else {
+ Person::players[j]->numwaypoints = 0;
+ Person::players[j]->waypoint = 0;
+ fpackf(tfile, "Bi Bi Bi", Person::players[j]->numwaypoints, Person::players[j]->waypoint, Person::players[j]->waypoint);
+ }
+
+ fpackf(tfile, "Bf Bf Bf", Person::players[j]->armorhead, Person::players[j]->armorhigh, Person::players[j]->armorlow);
+ fpackf(tfile, "Bf Bf Bf", Person::players[j]->protectionhead, Person::players[j]->protectionhigh, Person::players[j]->protectionlow);
+ fpackf(tfile, "Bf Bf Bf", Person::players[j]->metalhead, Person::players[j]->metalhigh, Person::players[j]->metallow);
+ fpackf(tfile, "Bf Bf", Person::players[j]->power, Person::players[j]->speedmult);
+
+ float headprop, bodyprop, armprop, legprop;
+ if (Person::players[j]->creature == wolftype) {
+ headprop = Person::players[j]->proportionhead.x / 1.1;
+ bodyprop = Person::players[j]->proportionbody.x / 1.1;
+ armprop = Person::players[j]->proportionarms.x / 1.1;
+ legprop = Person::players[j]->proportionlegs.x / 1.1;
+ } else if (Person::players[j]->creature == rabbittype) {
+ headprop = Person::players[j]->proportionhead.x / 1.2;
+ bodyprop = Person::players[j]->proportionbody.x / 1.05;
+ armprop = Person::players[j]->proportionarms.x / 1.00;
+ legprop = Person::players[j]->proportionlegs.x / 1.1;
+ }
+
+ fpackf(tfile, "Bf Bf Bf Bf", headprop, bodyprop, armprop, legprop);
+
+ fpackf(tfile, "Bi", Person::players[j]->numclothes);
+ if (Person::players[j]->numclothes)
+ for (int k = 0; k < Person::players[j]->numclothes; k++) {
+ int templength;
+ templength = strlen(Person::players[j]->clothes[k]);
+ fpackf(tfile, "Bi", templength);
+ for (int l = 0; l < templength; l++)
+ fpackf(tfile, "Bb", Person::players[j]->clothes[k][l]);
+ fpackf(tfile, "Bf Bf Bf", Person::players[j]->clothestintr[k], Person::players[j]->clothestintg[k], Person::players[j]->clothestintb[k]);
+ }
+ }
+
+ fpackf(tfile, "Bi", numpathpoints);
+ for (int j = 0; j < numpathpoints; j++) {
+ fpackf(tfile, "Bf Bf Bf Bi", pathpoint[j].x, pathpoint[j].y, pathpoint[j].z, numpathpointconnect[j]);
+ for (int k = 0; k < numpathpointconnect[j]; k++)
+ fpackf(tfile, "Bi", pathpointconnect[j][k]);
+ }
+
+ fpackf(tfile, "Bf Bf Bf Bf", mapcenter.x, mapcenter.y, mapcenter.z, mapradius);
+
+ fclose(tfile);
+}
+
+void ch_cellar(const char *args)
+{
+ Person::players[0]->skeleton.drawmodel.textureptr.load("Textures/Furdarko.jpg", 1, &Person::players[0]->skeleton.skinText[0], &Person::players[0]->skeleton.skinsize);
+}
+
+void ch_tint(const char *args)
+{
+ sscanf(args, "%f%f%f", &tintr, &tintg, &tintb);
+}
+
+void ch_tintr(const char *args)
+{
+ tintr = atof(args);
+}
+
+void ch_tintg(const char *args)
+{
+ tintg = atof(args);
+}
+
+void ch_tintb(const char *args)
+{
+ tintb = atof(args);
+}
+
+void ch_speed(const char *args)
+{
+ Person::players[0]->speedmult = atof(args);
+}
+
+void ch_strength(const char *args)
+{
+ Person::players[0]->power = atof(args);
+}
+
+void ch_power(const char *args)
+{
+ Person::players[0]->power = atof(args);
+}
+
+void ch_size(const char *args)
+{
+ Person::players[0]->scale = atof(args) * .2;
+}
+
+void ch_sizenear(const char *args)
+{
+ int closest = findClosestPlayer();
+ if (closest >= 0)
+ Person::players[closest]->scale = atof(args) * .2;
+}
+
+void ch_proportion(const char *args)
+{
+ set_proportion(0, args);
+}
+
+void ch_proportionnear(const char *args)
+{
+ int closest = findClosestPlayer();
+ if (closest >= 0)
+ set_proportion(closest, args);
+}
+
+void ch_protection(const char *args)
+{
+ set_protection(0, args);
+}
+
+void ch_protectionnear(const char *args)
+{
+ int closest = findClosestPlayer();
+ if (closest >= 0)
+ set_protection(closest, args);
+}
+
+void ch_armor(const char *args)
+{
+ set_armor(0, args);
+}
+
+void ch_armornear(const char *args)
+{
+ int closest = findClosestPlayer();
+ if (closest >= 0)
+ set_armor(closest, args);
+}
+
+void ch_protectionreset(const char *args)
+{
+ set_protection(0, "1 1 1");
+ set_armor(0, "1 1 1");
+}
+
+void ch_metal(const char *args)
+{
+ set_metal(0, args);
+}
+
+void ch_noclothes(const char *args)
+{
+ set_noclothes(0, args);
+}
+
+void ch_noclothesnear(const char *args)
+{
+ int closest = findClosestPlayer();
+ if (closest >= 0)
+ set_noclothes(closest, args);
+}
+
+void ch_clothes(const char *args)
+{
+ set_clothes(0, args);
+}
+
+void ch_clothesnear(const char *args)
+{
+ int closest = findClosestPlayer();
+ if (closest >= 0)
+ set_clothes(closest, args);
+}
+
+void ch_belt(const char *args)
+{
+ Person::players[0]->skeleton.clothes = !Person::players[0]->skeleton.clothes;
+}
+
+
+void ch_cellophane(const char *args)
+{
+ cellophane = !cellophane;
+ float mul = (cellophane ? 0 : 1);
+
+ for (auto player : Person::players) {
+ player->proportionhead.z = player->proportionhead.x * mul;
+ player->proportionbody.z = player->proportionbody.x * mul;
+ player->proportionarms.z = player->proportionarms.x * mul;
+ player->proportionlegs.z = player->proportionlegs.x * mul;
+ }
+}
+
+void ch_funnybunny(const char *args)
+{
+ Person::players[0]->creature = rabbittype;
+ Person::players[0]->skeletonLoad(true);
+ Person::players[0]->scale = .2;
+ Person::players[0]->headless = 0;
+ Person::players[0]->damagetolerance = 200;
+ set_proportion(0, "1 1 1 1");
+}
+
+void ch_wolfie(const char *args)
+{
+ Person::players[0]->creature = wolftype;
+ Person::players[0]->skeletonLoad();
+ Person::players[0]->damagetolerance = 300;
+ set_proportion(0, "1 1 1 1");
+}
+
+void ch_wolfieisgod(const char *args)
+{
+ ch_wolfie(args);
+}
+
+void ch_wolf(const char *args)
+{
+ Person::players[0]->skeleton.drawmodel.textureptr.load("Textures/Wolf.jpg", 1, &Person::players[0]->skeleton.skinText[0], &Person::players[0]->skeleton.skinsize);
+}
+
+void ch_snowwolf(const char *args)
+{
+ Person::players[0]->skeleton.drawmodel.textureptr.load("Textures/SnowWolf.jpg", 1, &Person::players[0]->skeleton.skinText[0], &Person::players[0]->skeleton.skinsize);
+}
+
+void ch_darkwolf(const char *args)
+{
+ Person::players[0]->skeleton.drawmodel.textureptr.load("Textures/DarkWolf.jpg", 1, &Person::players[0]->skeleton.skinText[0], &Person::players[0]->skeleton.skinsize);
+}
+
+void ch_lizardwolf(const char *args)
+{
+ Person::players[0]->skeleton.drawmodel.textureptr.load("Textures/LizardWolf.jpg", 1, &Person::players[0]->skeleton.skinText[0], &Person::players[0]->skeleton.skinsize);
+}
+
+void ch_white(const char *args)
+{
+ Person::players[0]->skeleton.drawmodel.textureptr.load("Textures/Fur.jpg", 1, &Person::players[0]->skeleton.skinText[0], &Person::players[0]->skeleton.skinsize);
+}
+
+void ch_brown(const char *args)
+{
+ Person::players[0]->skeleton.drawmodel.textureptr.load("Textures/Fur3.jpg", 1, &Person::players[0]->skeleton.skinText[0], &Person::players[0]->skeleton.skinsize);
+}
+
+void ch_black(const char *args)
+{
+ Person::players[0]->skeleton.drawmodel.textureptr.load("Textures/Fur2.jpg", 1, &Person::players[0]->skeleton.skinText[0], &Person::players[0]->skeleton.skinsize);
+}
+
+void ch_sizemin(const char *args)
+{
+ for (unsigned i = 1; i < Person::players.size(); i++)
+ if (Person::players[i]->scale < 0.8 * 0.2)
+ Person::players[i]->scale = 0.8 * 0.2;
+}
+
+void ch_tutorial(const char *args)
+{
+ tutoriallevel = atoi(args);
+}
+
+void ch_hostile(const char *args)
+{
+ hostile = atoi(args);
+}
+
+void ch_type(const char *args)
+{
+ int n = sizeof(editortypenames) / sizeof(editortypenames[0]);
+ for (int i = 0; i < n; i++)
+ if (stripfx(args, editortypenames[i])) {
+ editoractive = i;
+ break;
+ }
+}
+
+void ch_path(const char *args)
+{
+ int n = sizeof(pathtypenames) / sizeof(pathtypenames[0]);
+ for (int i = 0; i < n; i++)
+ if (stripfx(args, pathtypenames[i])) {
+ editorpathtype = i;
+ break;
+ }
+}
+
+void ch_hs(const char *args)
+{
+ float size;
+ int type, shift;
+ sscanf(args, "%f%d %n", &size, &type, &shift);
+
+ Hotspot::hotspots.emplace_back(Person::players[0]->coords, type, size);
+
+ strcpy(Hotspot::hotspots.back().text, args + shift);
+ strcat(Hotspot::hotspots.back().text, "\n");
+}
+
+void ch_dialogue(const char *args)
+{
+ int type;
+ char buf1[32];
+
+ sscanf(args, "%d %31s", &type, buf1);
+ std::string filename = std::string("Dialogues/") + buf1 + ".txt";
+
+ Dialog::dialogs.push_back(Dialog(type, filename));
+
+ Dialog::directing = true;
+ Dialog::indialogue = 0;
+ Dialog::whichdialogue = Dialog::dialogs.size();
+}
+
+void ch_fixdialogue(const char *args)
+{
+ char buf1[32];
+ int whichdi;
+
+ sscanf(args, "%d %31s", &whichdi, buf1);
+ std::string filename = std::string("Dialogues/") + buf1 + ".txt";
+
+ Dialog::dialogs[whichdi] = Dialog(Dialog::dialogs[whichdi].type, filename);
+}
+
+void ch_fixtype(const char *args)
+{
+ int dlg;
+ sscanf(args, "%d", &dlg);
+ Dialog::dialogs[0].type = dlg;
+}
+
+void ch_fixrotation(const char *args)
+{
+ int playerId = Dialog::currentScene().participantfocus;
+ Dialog::currentDialog().participantyaw[playerId] = Person::players[playerId]->yaw;
+}
+
+void ch_ddialogue(const char *args)
+{
+ if (!Dialog::dialogs.empty()) {
+ Dialog::dialogs.pop_back();
+ }
+}
+
+void ch_dhs(const char *args)
+{
+ if (!Hotspot::hotspots.empty()) {
+ Hotspot::hotspots.pop_back();
+ }
+}
+
+void ch_immobile(const char *args)
+{
+ Person::players[0]->immobile = 1;
+}
+
+void ch_allimmobile(const char *args)
+{
+ for (unsigned i = 1; i < Person::players.size(); i++)
+ Person::players[i]->immobile = 1;
+}
+
+void ch_mobile(const char *args)
+{
+ Person::players[0]->immobile = 0;
+}
+
+void ch_default(const char *args)
+{
+ Person::players[0]->armorhead = 1;
+ Person::players[0]->armorhigh = 1;
+ Person::players[0]->armorlow = 1;
+ Person::players[0]->protectionhead = 1;
+ Person::players[0]->protectionhigh = 1;
+ Person::players[0]->protectionlow = 1;
+ Person::players[0]->metalhead = 1;
+ Person::players[0]->metalhigh = 1;
+ Person::players[0]->metallow = 1;
+ Person::players[0]->power = 1;
+ Person::players[0]->speedmult = 1;
+ Person::players[0]->scale = 1;
+
+ if (Person::players[0]->creature == wolftype) {
+ Person::players[0]->proportionhead = 1.1;
+ Person::players[0]->proportionbody = 1.1;
+ Person::players[0]->proportionarms = 1.1;
+ Person::players[0]->proportionlegs = 1.1;
+ } else if (Person::players[0]->creature == rabbittype) {
+ Person::players[0]->proportionhead = 1.2;
+ Person::players[0]->proportionbody = 1.05;
+ Person::players[0]->proportionarms = 1.00;
+ Person::players[0]->proportionlegs = 1.1;
+ Person::players[0]->proportionlegs.y = 1.05;
+ }
+
+ Person::players[0]->numclothes = 0;
+ Person::players[0]->skeleton.drawmodel.textureptr.load(
+ creatureskin[Person::players[0]->creature][Person::players[0]->whichskin], 1,
+ &Person::players[0]->skeleton.skinText[0], &Person::players[0]->skeleton.skinsize);
+
+ editoractive = typeactive;
+ Person::players[0]->immobile = 0;
+}
+
+void ch_play(const char *args)
+{
+ int dlg;
+ sscanf(args, "%d", &dlg);
+ Dialog::whichdialogue = dlg;
+
+ if (Dialog::whichdialogue >= Dialog::dialogs.size()) {
+ return;
+ }
+
+ Dialog::currentDialog().play();
+}
+
+void ch_mapkilleveryone(const char *args)
+{
+ maptype = mapkilleveryone;
+}
+
+void ch_mapkillmost(const char *args)
+{
+ maptype = mapkillmost;
+}
+
+void ch_mapkillsomeone(const char *args)
+{
+ maptype = mapkillsomeone;
+}
+
+void ch_mapgosomewhere(const char *args)
+{
+ maptype = mapgosomewhere;
+}
+
+void ch_viewdistance(const char *args)
+{
+ viewdistance = atof(args) * 100;
+}
+
+void ch_fadestart(const char *args)
+{
+ fadestart = atof(args);
+}
+
+void ch_slomo(const char *args)
+{
+ slomospeed = atof(args);
+ slomo = !slomo;
+ slomodelay = 1000;
+}
+
+void ch_slofreq(const char *args)
+{
+ slomofreq = atof(args);
+}
+
+void ch_skytint(const char *args)
+{
+ sscanf(args, "%f%f%f", &skyboxr, &skyboxg, &skyboxb);
+
+ skyboxlightr = skyboxr;
+ skyboxlightg = skyboxg;
+ skyboxlightb = skyboxb;
+
+ SetUpLighting();
+
+ terrain.DoShadows();
+ objects.DoShadows();
+}
+
+void ch_skylight(const char *args)
+{
+ sscanf(args, "%f%f%f", &skyboxlightr, &skyboxlightg, &skyboxlightb);
+
+ SetUpLighting();
+
+ terrain.DoShadows();
+ objects.DoShadows();
+}
+
+void ch_skybox(const char *args)
+{
+ skyboxtexture = !skyboxtexture;
+
+ SetUpLighting();
+
+ terrain.DoShadows();
+ objects.DoShadows();
+}
--- /dev/null
+/*
+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/>.
+*/
+
+DECLARE_COMMAND(quit)
+DECLARE_COMMAND(map)
+DECLARE_COMMAND(save)
+
+DECLARE_COMMAND(cellar)
+DECLARE_COMMAND(tint)
+DECLARE_COMMAND(tintr)
+DECLARE_COMMAND(tintg)
+DECLARE_COMMAND(tintb)
+DECLARE_COMMAND(speed)
+DECLARE_COMMAND(strength)
+DECLARE_COMMAND(power)
+DECLARE_COMMAND(size)
+DECLARE_COMMAND(sizenear)
+DECLARE_COMMAND(proportion)
+DECLARE_COMMAND(proportionnear)
+DECLARE_COMMAND(protection)
+DECLARE_COMMAND(protectionnear)
+DECLARE_COMMAND(protectionreset)
+DECLARE_COMMAND(armor)
+DECLARE_COMMAND(armornear)
+DECLARE_COMMAND(metal)
+DECLARE_COMMAND(clothes)
+DECLARE_COMMAND(clothesnear)
+DECLARE_COMMAND(noclothes)
+DECLARE_COMMAND(noclothesnear)
+DECLARE_COMMAND(belt)
+DECLARE_COMMAND(cellophane)
+DECLARE_COMMAND(funnybunny)
+DECLARE_COMMAND(wolfie)
+DECLARE_COMMAND(wolfieisgod)
+DECLARE_COMMAND(wolf)
+DECLARE_COMMAND(snowwolf)
+DECLARE_COMMAND(darkwolf)
+DECLARE_COMMAND(lizardwolf)
+DECLARE_COMMAND(white)
+DECLARE_COMMAND(brown)
+DECLARE_COMMAND(black)
+
+DECLARE_COMMAND(sizemin)
+DECLARE_COMMAND(viewdistance)
+DECLARE_COMMAND(fadestart)
+DECLARE_COMMAND(slomo)
+DECLARE_COMMAND(slofreq)
+
+DECLARE_COMMAND(tutorial)
+DECLARE_COMMAND(hostile)
+DECLARE_COMMAND(type)
+DECLARE_COMMAND(path)
+DECLARE_COMMAND(hs)
+DECLARE_COMMAND(dhs)
+DECLARE_COMMAND(dialogue)
+DECLARE_COMMAND(fixdialogue)
+DECLARE_COMMAND(ddialogue)
+DECLARE_COMMAND(fixtype)
+DECLARE_COMMAND(fixrotation)
+DECLARE_COMMAND(immobile)
+DECLARE_COMMAND(allimmobile)
+DECLARE_COMMAND(mobile)
+DECLARE_COMMAND(default)
+DECLARE_COMMAND(play)
+
+DECLARE_COMMAND(mapkilleveryone)
+DECLARE_COMMAND(mapkillmost)
+DECLARE_COMMAND(mapkillsomeone)
+DECLARE_COMMAND(mapgosomewhere)
+
+DECLARE_COMMAND(skytint)
+DECLARE_COMMAND(skylight)
+DECLARE_COMMAND(skybox)
--- /dev/null
+/*
+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/>.
+*/
+
+typedef void (*console_handler)(const char *args);
+
+#define DECLARE_COMMAND(cmd) void ch_##cmd(const char *args);
+#include "ConsoleCmds.def"
+#undef DECLARE_COMMAND
+
+/* FIXME - This is only to get cmd_count, not very clean */
+enum console_command {
+#define DECLARE_COMMAND(cmd) cmd_##cmd,
+#include "ConsoleCmds.def"
+#undef DECLARE_COMMAND
+ cmd_count
+};
+
+extern const char *cmd_names[cmd_count];
+
+extern console_handler cmd_handlers[cmd_count];
+++ /dev/null
-/*
-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/>.
-*/
-
-#include "Dialog.h"
-#include "Person.h"
-#include "Input.h"
-#include "Game.h"
-#include "binio.h"
-#include "Utils/Folders.h"
-
-extern int hostile;
-
-int Dialog::indialogue;
-int Dialog::whichdialogue;
-bool Dialog::directing;
-float Dialog::dialoguetime;
-std::vector<Dialog> Dialog::dialogs;
-
-void Dialog::loadDialogs(FILE* tfile)
-{
- int numdialogues;
- funpackf(tfile, "Bi", &numdialogues);
- for (int k = 0; k < numdialogues; k++) {
- dialogs.push_back(Dialog(tfile));
- }
-}
-
-Dialog::Dialog(FILE* tfile) : gonethrough(0)
-{
- int numdialogscenes;
- funpackf(tfile, "Bi", &numdialogscenes);
- funpackf(tfile, "Bi", &type);
- for (int l = 0; l < 10; l++) {
- funpackf(tfile, "Bf Bf Bf", &participantlocation[l].x, &participantlocation[l].y, &participantlocation[l].z);
- funpackf(tfile, "Bf", &participantyaw[l]);
- }
- for (int l = 0; l < numdialogscenes; l++) {
- scenes.push_back(DialogScene(tfile));
- }
-}
-
-std::string funpackf_string(FILE* tfile, int maxlength)
-{
- int templength;
- funpackf(tfile, "Bi", &templength);
- if ((templength > maxlength) || (templength <= 0)) {
- templength = maxlength;
- }
- int m;
- char* text = new char[maxlength];
- for (m = 0; m < templength; m++) {
- funpackf(tfile, "Bb", &text[m]);
- if (text[m] == '\0')
- break;
- }
- text[m] = 0;
- std::string result(text);
- delete[] text;
- return result;
-}
-
-void fpackf_string(FILE* tfile, std::string text)
-{
- fpackf(tfile, "Bi", text.size());
- for (int m = 0; m < text.size(); m++) {
- fpackf(tfile, "Bb", text[m]);
- if (text[m] == '\0')
- break;
- }
-}
-
-DialogScene::DialogScene(FILE* tfile)
-{
- funpackf(tfile, "Bi", &location);
- funpackf(tfile, "Bf", &color[0]);
- funpackf(tfile, "Bf", &color[1]);
- funpackf(tfile, "Bf", &color[2]);
- funpackf(tfile, "Bi", &sound);
-
- text = funpackf_string(tfile, 128);
- name = funpackf_string(tfile, 64);
-
- funpackf(tfile, "Bf Bf Bf", &camera.x, &camera.y, &camera.z);
- funpackf(tfile, "Bi", &participantfocus);
- funpackf(tfile, "Bi", &participantaction);
-
- for (int m = 0; m < 10; m++)
- funpackf(tfile, "Bf Bf Bf", &participantfacing[m].x, &participantfacing[m].y, &participantfacing[m].z);
-
- funpackf(tfile, "Bf Bf", &camerayaw, &camerapitch);
-}
-
-/* Load dialog from txt file, used by console */
-Dialog::Dialog(int type, std::string filename) : type(type)
-{
- ifstream ipstream(Folders::getResourcePath(filename));
- ipstream.ignore(256, ':');
- int numscenes;
- ipstream >> numscenes;
- for (int i = 0; i < numscenes; i++) {
- scenes.push_back(DialogScene(ipstream));
- for (unsigned j = 0; j < Person::players.size(); j++) {
- scenes.back().participantfacing[j] = Person::players[j]->facing;
- }
- }
- ipstream.close();
-}
-
-DialogScene::DialogScene(ifstream &ipstream)
-{
- ipstream.ignore(256, ':');
- ipstream.ignore(256, ':');
- ipstream.ignore(256, ' ');
- ipstream >> location;
- ipstream.ignore(256, ':');
- ipstream >> color[0];
- ipstream >> color[1];
- ipstream >> color[2];
- ipstream.ignore(256, ':');
- getline(ipstream, name);
- ipstream.ignore(256, ':');
- ipstream.ignore(256, ' ');
- getline(ipstream, text);
- for (int j = 0; j < 128; j++) {
- if (text[j] == '\\')
- text[j] = '\n';
- }
- ipstream.ignore(256, ':');
- ipstream >> sound;
-}
-
-void Dialog::tick(int id)
-{
- unsigned playerId = type % 10;
- bool special = (type > 9);
-
- if ((!hostile || (type > 40) && (type < 50)) &&
- (playerId < Person::players.size()) &&
- (playerId > 0) &&
- ((gonethrough == 0) || !special) &&
- (special || Input::isKeyPressed(Game::attackkey))) {
- if ((distsq(&Person::players[0]->coords, &Person::players[playerId]->coords) < 6) ||
- (Person::players[playerId]->howactive >= typedead1) ||
- (type > 40) && (type < 50)) {
- whichdialogue = id;
- play();
- dialoguetime = 0;
- gonethrough++;
- }
- }
-}
-
-void Dialog::play()
-{
- for (int i = 0; i < scenes.size(); i++) {
- int playerId = scenes[i].participantfocus;
- Person::players[playerId]->coords = participantlocation[playerId];
- Person::players[playerId]->yaw = participantyaw[playerId];
- Person::players[playerId]->targetyaw = participantyaw[playerId];
- Person::players[playerId]->velocity = 0;
- Person::players[playerId]->animTarget = Person::players[playerId]->getIdle();
- Person::players[playerId]->frameTarget = 0;
- }
-
- Dialog::directing = false;
- Dialog::indialogue = 0;
-
- if (scenes[indialogue].sound != 0) {
- Game::playdialoguescenesound();
- }
-}
-
-void Dialog::saveDialogs(FILE* tfile)
-{
- fpackf(tfile, "Bi", dialogs.size());
-
- for (int k = 0; k < dialogs.size(); k++) {
- dialogs[k].save(tfile);
- }
-}
-
-void Dialog::save(FILE* tfile)
-{
- fpackf(tfile, "Bi", scenes.size());
- fpackf(tfile, "Bi", type);
- for (int l = 0; l < 10; l++) {
- fpackf(tfile, "Bf Bf Bf", participantlocation[l].x, participantlocation[l].y, participantlocation[l].z);
- fpackf(tfile, "Bf", participantyaw[l]);
- }
- for (int l = 0; l < scenes.size(); l++) {
- scenes[l].save(tfile);
- }
-}
-
-void DialogScene::save(FILE* tfile)
-{
- fpackf(tfile, "Bi", location);
- fpackf(tfile, "Bf", color[0]);
- fpackf(tfile, "Bf", color[1]);
- fpackf(tfile, "Bf", color[2]);
- fpackf(tfile, "Bi", sound);
-
- fpackf_string(tfile, text);
- fpackf_string(tfile, name);
-
- fpackf(tfile, "Bf Bf Bf", camera.x, camera.y, camera.z);
- fpackf(tfile, "Bi", participantfocus);
- fpackf(tfile, "Bi", participantaction);
-
- for (int m = 0; m < 10; m++)
- fpackf(tfile, "Bf Bf Bf", participantfacing[m].x, participantfacing[m].y, participantfacing[m].z);
-
- fpackf(tfile, "Bf Bf", camerayaw, camerapitch);
-}
+++ /dev/null
-/*
-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 _DIALOG_H_
-#define _DIALOG_H_
-
-#include "stdio.h"
-#include "Quaternions.h"
-#include <vector>
-
-class DialogScene
-{
-public:
- DialogScene(FILE* tfile);
- DialogScene(ifstream &ipstream);
- void save(FILE* tfile);
-
- int location;
- float color[3];
- int sound;
- std::string text;
- std::string name;
- XYZ camera;
- float camerayaw;
- float camerapitch;
- int participantfocus;
- int participantaction;
- XYZ participantfacing[10];
-};
-
-class Dialog
-{
-public:
- Dialog(FILE* tfile);
- Dialog(int type, std::string filename);
- void tick(int id);
- void play();
- void save(FILE* tfile);
-
- int type;
- int gonethrough;
- std::vector<DialogScene> scenes;
- XYZ participantlocation[10];
- float participantyaw[10];
-
- static void loadDialogs(FILE*);
- static void saveDialogs(FILE*);
-
- static bool inDialog() { return (indialogue != -1); }
- static Dialog& currentDialog() { return dialogs[whichdialogue]; }
- static DialogScene& currentScene() { return currentDialog().scenes[indialogue]; }
-
- static int indialogue;
- static int whichdialogue;
- static bool directing;
- static float dialoguetime;
- static std::vector<Dialog> dialogs;
-};
-
-#endif /*_DIALOG_H_*/
--- /dev/null
+/*
+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 "Environment/Lights.h"
+
+void SetUpLight(Light* whichsource, int whichlight)
+{
+ static float qattenuation[] = {0.0002f};
+
+ //Initialize lights
+ if (whichlight == 0) {
+ GLfloat LightAmbient[] = { whichsource->ambient[0], whichsource->ambient[1], whichsource->ambient[2], 1.0f};
+ GLfloat LightDiffuse[] = { whichsource->color[0], whichsource->color[1], whichsource->color[2], 1.0f };
+ GLfloat LightPosition[] = { whichsource->location.x, whichsource->location.y, whichsource->location.z, 0.0f };
+
+ glLightfv(GL_LIGHT0, GL_POSITION, LightPosition);
+ glLightfv(GL_LIGHT0, GL_AMBIENT, LightAmbient);
+ glLightfv(GL_LIGHT0, GL_DIFFUSE, LightDiffuse);
+ glEnable(GL_LIGHT0);
+ } else {
+ GLenum lightselect = GL_LIGHT1;
+ switch (whichlight) {
+ case 2:
+ lightselect = GL_LIGHT2;
+ break;
+ case 3:
+ lightselect = GL_LIGHT3;
+ break;
+ case 4:
+ lightselect = GL_LIGHT4;
+ break;
+ case 5:
+ lightselect = GL_LIGHT5;
+ break;
+ case 6:
+ lightselect = GL_LIGHT6;
+ break;
+ case 7:
+ lightselect = GL_LIGHT7;
+ break;
+ }
+
+ GLfloat LightAmbient[] = { 0, 0, 0, 1.0f};
+ GLfloat LightDiffuse[] = { whichsource->color[0], whichsource->color[1], whichsource->color[2], 1.0f };
+ GLfloat LightPosition[] = { whichsource->location.x, whichsource->location.y, whichsource->location.z, 1.0f };
+
+ glLightfv(lightselect, GL_QUADRATIC_ATTENUATION, qattenuation);
+ glLightfv(lightselect, GL_POSITION, LightPosition);
+ glLightfv(lightselect, GL_AMBIENT, LightAmbient);
+ glLightfv(lightselect, GL_DIFFUSE, LightDiffuse);
+ glEnable(lightselect);
+
+ }
+}
--- /dev/null
+/*
+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 _LIGHTS_H_
+#define _LIGHTS_H_
+
+
+/**> HEADER FILES <**/
+#include "Graphic/gamegl.h"
+#include "Math/Quaternions.h"
+
+class Light
+{
+public:
+ GLint type;
+ GLfloat color[3];
+ GLfloat ambient[3];
+ int attach;
+ XYZ location;
+ inline void setColors(GLfloat cr, GLfloat cg, GLfloat cb,
+ GLfloat ar, GLfloat ag, GLfloat ab) {
+ color[0] = cr;
+ color[1] = cg;
+ color[2] = cb;
+ ambient[0] = ar;
+ ambient[1] = ag;
+ ambient[2] = ab;
+ }
+};
+
+void SetUpLight(Light* whichsource, int whichlight);
+
+#endif
--- /dev/null
+/*
+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/>.
+*/
+
+#include "Environment/Skybox.h"
+#include "Game.h"
+
+extern float viewdistance;
+extern float blurness;
+extern int environment;
+extern bool skyboxtexture;
+extern float skyboxr;
+extern float skyboxg;
+extern float skyboxb;
+
+void SkyBox::load (const std::string& ffront, const std::string& fleft, const std::string& fback,
+ const std::string& fright, const std::string& fup, const std::string& fdown)
+{
+ front.load(ffront, true);
+ left.load(fleft, true);
+ back.load(fback, true);
+ right.load(fright, true);
+ up.load(fup, true);
+ down.load(fdown, true);
+}
+
+void SkyBox::draw()
+{
+ static float size = viewdistance / 4;
+ glPushMatrix();
+ static GLfloat M[16];
+ glGetFloatv(GL_MODELVIEW_MATRIX, M);
+ M[12] = 0;
+ M[13] = 0;
+ M[14] = 0;
+ glLoadMatrixf(M);
+ if (environment == desertenvironment) {
+ glScalef(1 + blurness / 1000, 1, 1 + blurness / 1000);
+ glColor3f(1 * skyboxr, .95 * skyboxg, .95 * skyboxb);
+ } else {
+ glColor3f(.85 * skyboxr, .85 * skyboxg, .95 * skyboxb);
+ }
+
+ if (!skyboxtexture) {
+ glDisable(GL_TEXTURE_2D);
+ glColor3f(skyboxr * .8, skyboxg * .8, skyboxb * .8);
+ }
+ glDepthMask(0);
+ glDisable(GL_CULL_FACE);
+ glEnable(GL_BLEND);
+ glDisable(GL_LIGHTING);
+ if (skyboxtexture)
+ glEnable(GL_TEXTURE_2D);
+ glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+ front.bind();
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ glBegin(GL_QUADS);
+ glNormal3f( 0.0f, 0.0f, -1);
+ glTexCoord2f(0, 0);
+ glVertex3f(-size, -size, size);
+ glTexCoord2f(1, 0);
+ glVertex3f( size, -size, size);
+ glTexCoord2f(1, 1);
+ glVertex3f( size, size, size);
+ glTexCoord2f(0, 1);
+ glVertex3f(-size, size, size);
+ glEnd();
+ back.bind();
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ glBegin(GL_QUADS);
+ glNormal3f( 0.0f, 0.0f, 1);
+ glTexCoord2f(1, 0);
+ glVertex3f(-size, -size, -size);
+ glTexCoord2f(1, 1);
+ glVertex3f(-size, size, -size);
+ glTexCoord2f(0, 1);
+ glVertex3f( size, size, -size);
+ glTexCoord2f(0, 0);
+ glVertex3f( size, -size, -size);
+ glEnd();
+ up.bind();
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ glBegin(GL_QUADS);
+ glNormal3f( 0.0f, -1.0f, 0);
+ glTexCoord2f(0, 1);
+ glVertex3f(-size, size, -size);
+ glTexCoord2f(0, 0);
+ glVertex3f(-size, size, size);
+ glTexCoord2f(1, 0);
+ glVertex3f( size, size, size);
+ glTexCoord2f(1, 1);
+ glVertex3f( size, size, -size);
+ glEnd();
+ down.bind();
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ glBegin(GL_QUADS);
+ glNormal3f( 0.0f, 1.0f, 0);
+
+ glTexCoord2f(0, 0);
+ glVertex3f(-size, -size, -size);
+ glTexCoord2f(1, 0);
+ glVertex3f( size, -size, -size);
+ glTexCoord2f(1, 1);
+ glVertex3f( size, -size, size);
+ glTexCoord2f(0, 1);
+ glVertex3f(-size, -size, size);
+ glEnd();
+ right.bind();
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ glBegin(GL_QUADS);
+ glNormal3f( -1.0f, 0.0f, 0);
+ glTexCoord2f(1, 0);
+ glVertex3f( size, -size, -size);
+ glTexCoord2f(1, 1);
+ glVertex3f( size, size, -size);
+ glTexCoord2f(0, 1);
+ glVertex3f( size, size, size);
+ glTexCoord2f(0, 0);
+ glVertex3f( size, -size, size);
+ glEnd();
+ left.bind();
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ glBegin(GL_QUADS);
+ glNormal3f( 1.0f, 0.0f, 0);
+ glTexCoord2f(0, 0);
+ glVertex3f(-size, -size, -size);
+ glTexCoord2f(1, 0);
+ glVertex3f(-size, -size, size);
+ glTexCoord2f(1, 1);
+ glVertex3f(-size, size, size);
+ glTexCoord2f(0, 1);
+ glVertex3f(-size, size, -size);
+ glEnd();
+ glEnable(GL_CULL_FACE);
+ glDepthMask(1);
+ glPopMatrix();
+}
+
+SkyBox::~SkyBox()
+{
+ front.destroy();
+ left.destroy();
+ back.destroy();
+ right.destroy();
+ up.destroy();
+ down.destroy();
+};
+
--- /dev/null
+/*
+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 _SKYBOX_H_
+#define _SKYBOX_H_
+
+#include "Graphic/gamegl.h"
+#include "Graphic/Texture.h"
+#include "Math/Quaternions.h"
+#include "Math/Quaternions.h"
+#include "Utils/ImageIO.h"
+
+class SkyBox
+{
+public:
+ Texture front, left, back, right, up, down;
+
+ void load(const std::string& ffront, const std::string& fleft, const std::string& fback,
+ const std::string& fright, const std::string& fup, const std::string& fdown);
+ void draw();
+
+ SkyBox() {}
+ ~SkyBox();
+};
+
+#endif
--- /dev/null
+/*
+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/>.
+*/
+
+#include "Game.h"
+#include "Environment/Terrain.h"
+#include "Objects/Objects.h"
+#include "Utils/Folders.h"
+
+extern XYZ viewer;
+extern float viewdistance;
+extern float fadestart;
+extern int environment;
+extern float texscale;
+extern Light light;
+extern float multiplier;
+extern FRUSTUM frustum;
+extern float texdetail;
+extern int detail;
+extern bool decals;
+extern float blurness;
+extern float targetblurness;
+extern Objects objects;
+extern bool visibleloading;
+extern bool skyboxtexture;
+extern int tutoriallevel;
+
+//Functions
+
+int Terrain::lineTerrain(XYZ p1, XYZ p2, XYZ *p)
+{
+ static int i, j, k;
+ static float distance;
+ static float olddistance;
+ static int intersecting;
+ static int firstintersecting;
+ static XYZ point;
+ static int startx, starty;
+ static int endx, endy;
+ static float highest, lowest;
+
+ firstintersecting = -1;
+ olddistance = 10000;
+ distance = 1;
+
+ XYZ triangles[3];
+
+ p1 /= scale;
+ p2 /= scale;
+
+ startx = p1.x;
+ starty = p1.z;
+ endx = p2.x;
+ endy = p2.z;
+
+ if (startx > endx) {
+ i = endx;
+ endx = startx;
+ startx = i;
+ }
+ if (starty > endy) {
+ i = endy;
+ endy = starty;
+ starty = i;
+ }
+
+ if (startx < 0)
+ startx = 0;
+ if (starty < 0)
+ starty = 0;
+ if (endx > size - 1)
+ endx = size - 1;
+ if (endy > size - 1)
+ endy = size - 1;
+
+ for (i = startx; i <= endx; i++) {
+ for (j = starty; j <= endy; j++) {
+ highest = -1000;
+ lowest = 1000;
+ for (k = 0; k < 2; k++) {
+ if (heightmap[i + k][j] > highest)
+ highest = heightmap[i + k][j];
+ if (heightmap[i + k][j] < lowest)
+ lowest = heightmap[i + k][j];
+ if (heightmap[i + k][j + 1] > highest)
+ highest = heightmap[i + k][j + 1];
+ if (heightmap[i + k][j + 1] < lowest)
+ lowest = heightmap[i + k][j + 1];
+ }
+ if ((p1.y <= highest || p2.y <= highest) && (p1.y >= lowest || p2.y >= lowest)) {
+ triangles[0].x = i;
+ triangles[0].y = heightmap[i][j];
+ triangles[0].z = j;
+
+ triangles[1].x = i;
+ triangles[1].y = heightmap[i][j + 1];
+ triangles[1].z = j + 1;
+
+ triangles[2].x = i + 1;
+ triangles[2].y = heightmap[i + 1][j];
+ triangles[2].z = j;
+
+ intersecting = LineFacet(p1, p2, triangles[0], triangles[1], triangles[2], &point);
+ distance = distsq(&p1, &point);
+ if ((distance < olddistance || firstintersecting == -1) && intersecting == 1) {
+ olddistance = distance;
+ firstintersecting = 1;
+ *p = point;
+ }
+
+ triangles[0].x = i + 1;
+ triangles[0].y = heightmap[i + 1][j];
+ triangles[0].z = j;
+
+ triangles[1].x = i;
+ triangles[1].y = heightmap[i][j + 1];
+ triangles[1].z = j + 1;
+
+ triangles[2].x = i + 1;
+ triangles[2].y = heightmap[i + 1][j + 1];
+ triangles[2].z = j + 1;
+
+ intersecting = LineFacet(p1, p2, triangles[0], triangles[1], triangles[2], &point);
+ distance = distsq(&p1, &point);
+ if ((distance < olddistance || firstintersecting == -1) && intersecting == 1) {
+ olddistance = distance;
+ firstintersecting = 1;
+ *p = point;
+ }
+ }
+ }
+ }
+ return firstintersecting;
+}
+
+void Terrain::UpdateTransparency(int whichx, int whichy)
+{
+ static XYZ vertex;
+ static int i, j, a, b, c, d, patch_size, stepsize;
+ static float distance;
+
+ static float viewdistsquared;
+
+ viewdistsquared = viewdistance * viewdistance;
+ patch_size = size / subdivision;
+
+ stepsize = 1;
+ c = whichx * patch_elements + whichy * patch_elements * subdivision;
+
+ for (i = patch_size * whichx; i < patch_size * (whichx + 1) + 1; i += stepsize) {
+ for (j = patch_size * whichy; j < patch_size * (whichy + 1) + 1; j += stepsize) {
+ if (i < size && j < size) {
+ vertex.x = i * scale;
+ vertex.z = j * scale;
+ vertex.y = heightmap[i][j] * scale;
+ distance = distsq(&viewer, &vertex);
+ if (distance > viewdistsquared)
+ distance = viewdistsquared;
+ colors[i][j][3] = (viewdistsquared - (distance - (viewdistsquared * fadestart)) * (1 / (1 - fadestart))) / viewdistsquared;
+ }
+ }
+ }
+
+ for (i = patch_size * whichx; i < patch_size * (whichx + 1); i += stepsize) {
+ for (j = patch_size * whichy; j < patch_size * (whichy + 1); j += stepsize) {
+ a = (i - (patch_size * whichx)) / stepsize;
+ b = (j - (patch_size * whichy)) / stepsize;
+ d = (a * 54) + (b * 54 * patch_size / stepsize);
+ vArray[d + c + 6] = colors[i][j][3];
+
+ vArray[d + c + 15] = colors[i][j + stepsize][3];
+
+ vArray[d + c + 24] = colors[i + stepsize][j][3];
+
+ vArray[d + c + 33] = colors[i + stepsize][j][3];
+
+ vArray[d + c + 42] = colors[i][j + stepsize][3];
+
+ vArray[d + c + 51] = colors[i + stepsize][j + stepsize][3];
+ }
+ }
+}
+
+void Terrain::UpdateTransparencyother(int whichx, int whichy)
+{
+ static int i, j, a, b, c, d, patch_size, stepsize;
+
+ patch_size = size / subdivision;
+
+ stepsize = 1;
+ c = whichx * patch_elements + whichy * patch_elements * subdivision;
+
+ for (i = patch_size * whichx; i < patch_size * (whichx + 1); i += stepsize) {
+ for (j = patch_size * whichy; j < patch_size * (whichy + 1); j += stepsize) {
+ a = (i - (patch_size * whichx)) / stepsize;
+ b = (j - (patch_size * whichy)) / stepsize;
+ d = (a * 54) + (b * 54 * patch_size / stepsize);
+ vArray[d + c + 6] = colors[i][j][3] * opacityother[i][j];
+
+ vArray[d + c + 15] = colors[i][j + stepsize][3] * opacityother[i][j + stepsize];
+
+ vArray[d + c + 24] = colors[i + stepsize][j][3] * opacityother[i + stepsize][j];
+
+ vArray[d + c + 33] = colors[i + stepsize][j][3] * opacityother[i + stepsize][j];
+
+ vArray[d + c + 42] = colors[i][j + stepsize][3] * opacityother[i][j + stepsize];
+
+ vArray[d + c + 51] = colors[i + stepsize][j + stepsize][3] * opacityother[i + stepsize][j + stepsize];
+ }
+ }
+}
+
+void Terrain::UpdateTransparencyotherother(int whichx, int whichy)
+{
+ static XYZ vertex;
+ static int i, j, a, b, c, d, patch_size, stepsize;
+ static float distance;
+
+ static float viewdistsquared;
+
+ viewdistsquared = viewdistance * viewdistance;
+ patch_size = size / subdivision;
+
+ stepsize = 1;
+ c = whichx * patch_elements + whichy * patch_elements * subdivision;
+
+ for (i = patch_size * whichx; i < patch_size * (whichx + 1) + 1; i += stepsize) {
+ for (j = patch_size * whichy; j < patch_size * (whichy + 1) + 1; j += stepsize) {
+ if (i < size && j < size) {
+ vertex.x = i * scale;
+ vertex.z = j * scale;
+ vertex.y = heightmap[i][j] * scale;
+ distance = distsq(&viewer, &vertex);
+ if (distance > viewdistsquared)
+ distance = viewdistsquared;
+ colors[i][j][3] = (viewdistsquared - (distance - (viewdistsquared * fadestart)) * (1 / (1 - fadestart))) / viewdistsquared;
+ }
+ }
+ }
+
+ for (i = patch_size * whichx; i < patch_size * (whichx + 1); i += stepsize) {
+ for (j = patch_size * whichy; j < patch_size * (whichy + 1); j += stepsize) {
+ a = (i - (patch_size * whichx)) / stepsize;
+ b = (j - (patch_size * whichy)) / stepsize;
+ d = (a * 54) + (b * 54 * patch_size / stepsize);
+ vArray[d + c + 6] = colors[i][j][3];
+
+ vArray[d + c + 15] = colors[i][j + stepsize][3];
+
+ vArray[d + c + 24] = colors[i + stepsize][j][3];
+
+ vArray[d + c + 33] = colors[i + stepsize][j][3];
+
+ vArray[d + c + 42] = colors[i][j + stepsize][3];
+
+ vArray[d + c + 51] = colors[i + stepsize][j + stepsize][3];
+ }
+ }
+}
+
+void Terrain::UpdateVertexArray(int whichx, int whichy)
+{
+ static int i, j, a, b, c, patch_size, stepsize;
+
+
+ numtris[whichx][whichy] = 0;
+
+ patch_size = size / subdivision;
+
+ stepsize = 1;
+ c = whichx * patch_elements + whichy * patch_elements * subdivision;
+ for (i = patch_size * whichx; i < patch_size * (whichx + 1); i += stepsize) {
+ for (j = patch_size * whichy; j < patch_size * (whichy + 1); j += stepsize) {
+ a = (i - ((float)size / subdivision * (float)whichx)) / stepsize;
+ b = (j - ((float)size / subdivision * (float)whichy)) / stepsize;
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 0] = i * scale;
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 1] = heightmap[i][j] * scale;
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 2] = j * scale;
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 3] = colors[i][j][0];
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 4] = colors[i][j][1];
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 5] = colors[i][j][2];
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 6] = colors[i][j][3];
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 7] = i * scale * texscale + texoffsetx[i][j];
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 8] = j * scale * texscale + texoffsety[i][j];
+
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 9] = i * scale;
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 10] = heightmap[i][j + stepsize] * scale;
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 11] = j * scale + stepsize * scale;
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 12] = colors[i][j + stepsize][0];
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 13] = colors[i][j + stepsize][1];
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 14] = colors[i][j + stepsize][2];
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 15] = colors[i][j + stepsize][3];
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 16] = i * scale * texscale + texoffsetx[i][j + stepsize];
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 17] = j * scale * texscale + stepsize * scale * texscale + texoffsety[i][j + stepsize];
+
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 18] = i * scale + stepsize * scale;
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 19] = heightmap[i + stepsize][j] * scale;
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 20] = j * scale;
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 21] = colors[i + stepsize][j][0];
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 22] = colors[i + stepsize][j][1];
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 23] = colors[i + stepsize][j][2];
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 24] = colors[i + stepsize][j][3];
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 25] = i * scale * texscale + stepsize * scale * texscale + texoffsetx[i + stepsize][j];
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 26] = j * scale * texscale + texoffsety[i + stepsize][j];
+
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 27] = i * scale + stepsize * scale;
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 28] = heightmap[i + stepsize][j] * scale;
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 29] = j * scale;
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 30] = colors[i + stepsize][j][0];
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 31] = colors[i + stepsize][j][1];
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 32] = colors[i + stepsize][j][2];
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 33] = colors[i + stepsize][j][3];
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 34] = i * scale * texscale + stepsize * scale * texscale + texoffsetx[i + stepsize][j];
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 35] = j * scale * texscale + texoffsety[i + stepsize][j];
+
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 36] = i * scale;
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 37] = heightmap[i][j + stepsize] * scale;
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 38] = j * scale + stepsize * scale;
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 39] = colors[i][j + stepsize][0];
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 40] = colors[i][j + stepsize][1];
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 41] = colors[i][j + stepsize][2];
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 42] = colors[i][j + stepsize][3];
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 43] = i * scale * texscale + texoffsetx[i][j + stepsize];
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 44] = j * scale * texscale + stepsize * scale * texscale + texoffsety[i][j + stepsize];
+
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 45] = i * scale + stepsize * scale;
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 46] = heightmap[i + stepsize][j + stepsize] * scale;
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 47] = j * scale + stepsize * scale;
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 48] = colors[i + stepsize][j + stepsize][0];
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 49] = colors[i + stepsize][j + stepsize][1];
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 50] = colors[i + stepsize][j + stepsize][2];
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 51] = colors[i + stepsize][j + stepsize][3];
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 52] = i * scale * texscale + stepsize * scale * texscale + texoffsetx[i + stepsize][j + stepsize];
+ vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 53] = j * scale * texscale + stepsize * scale * texscale + texoffsety[i + stepsize][j + stepsize];
+ numtris[whichx][whichy] += 2;
+ }
+ }
+
+ maxypatch[whichx][whichy] = -10000;
+ minypatch[whichx][whichy] = 10000;
+ for (a = 0; a < size / subdivision; a++) {
+ for (b = 0; b < size / subdivision; b++) {
+ if (heightmap[(size / subdivision)*whichx + a][(size / subdivision)*whichy + b]*scale > maxypatch[whichx][whichy])
+ maxypatch[whichx][whichy] = heightmap[(size / subdivision) * whichx + a][(size / subdivision) * whichy + b] * scale;
+ if (heightmap[(size / subdivision)*whichx + a][(size / subdivision)*whichy + b]*scale < minypatch[whichx][whichy])
+ minypatch[whichx][whichy] = heightmap[(size / subdivision) * whichx + a][(size / subdivision) * whichy + b] * scale;
+ }
+ }
+ heightypatch[whichx][whichy] = (maxypatch[whichx][whichy] - minypatch[whichx][whichy]);
+ if (heightypatch[whichx][whichy] < size / subdivision * scale)
+ heightypatch[whichx][whichy] = size / subdivision * scale;
+ avgypatch[whichx][whichy] = (minypatch[whichx][whichy] + maxypatch[whichx][whichy]) / 2;
+
+ for (i = whichx * size / subdivision; i < (whichx + 1)*size / subdivision - 1; i++) {
+ for (j = whichy * size / subdivision; j < (whichy + 1)*size / subdivision - 1; j++) {
+ triangles[(i * (size - 1) * 2) + (j * 2)][0].x = i * scale;
+ triangles[(i * (size - 1) * 2) + (j * 2)][0].y = heightmap[i][j] * scale;
+ triangles[(i * (size - 1) * 2) + (j * 2)][0].z = j * scale;
+
+ triangles[(i * (size - 1) * 2) + (j * 2)][1].x = i * scale;
+ triangles[(i * (size - 1) * 2) + (j * 2)][1].y = heightmap[i][j + 1] * scale;
+ triangles[(i * (size - 1) * 2) + (j * 2)][1].z = j * scale + scale;
+
+ triangles[(i * (size - 1) * 2) + (j * 2)][2].x = i * scale + 1 * scale;
+ triangles[(i * (size - 1) * 2) + (j * 2)][2].y = heightmap[i + 1][j] * scale;
+ triangles[(i * (size - 1) * 2) + (j * 2)][2].z = j * scale;
+
+ triangles[(i * (size - 1) * 2) + (j * 2) + 1][0].x = i * scale + 1 * scale;
+ triangles[(i * (size - 1) * 2) + (j * 2) + 1][0].y = heightmap[i + 1][j] * scale;
+ triangles[(i * (size - 1) * 2) + (j * 2) + 1][0].z = j * scale;
+
+ triangles[(i * (size - 1) * 2) + (j * 2) + 1][1].x = i * scale;
+ triangles[(i * (size - 1) * 2) + (j * 2) + 1][1].y = heightmap[i][j + 1] * scale;
+ triangles[(i * (size - 1) * 2) + (j * 2) + 1][1].z = j * scale + 1 * scale;
+
+ triangles[(i * (size - 1) * 2) + (j * 2) + 1][2].x = i * scale + 1 * scale;
+ triangles[(i * (size - 1) * 2) + (j * 2) + 1][2].y = heightmap[i + 1][j + 1] * scale;
+ triangles[(i * (size - 1) * 2) + (j * 2) + 1][2].z = j * scale + 1 * scale;
+ }
+ }
+
+}
+
+
+bool Terrain::load(const std::string& fileName)
+{
+ static long i, j;
+ static long x, y;
+ static float patch_size;
+
+ float temptexdetail = texdetail;
+
+ ImageRec texture;
+
+ //Load Image
+ if (!load_image(Folders::getResourcePath(fileName).c_str(), texture)) {
+ return false;
+ }
+
+ //Is it valid?
+ if (texture.bpp > 24) {
+ int bytesPerPixel = texture.bpp / 8;
+
+ int tempnum = 0;
+ for (i = 0; i < (long)(texture.sizeY * texture.sizeX * bytesPerPixel); i++) {
+ if ((i + 1) % 4) {
+ texture.data[tempnum] = texture.data[i];
+ tempnum++;
+ }
+ }
+ }
+ texture.bpp = 24;
+ if (visibleloading)
+ Game::LoadingScreen();
+
+ texdetail = temptexdetail;
+
+ size = texture.sizeX;
+
+ for (i = 0; i < size; i++) {
+ for (j = 0; j < size; j++) {
+ heightmap[size - 1 - i][j] = (float)((texture.data[(i + (j * size)) * texture.bpp / 8])) / 5;
+ }
+ }
+
+ if (visibleloading)
+ Game::LoadingScreen();
+
+ float slopeness;
+
+ for (i = 0; i < subdivision; i++) {
+ for (j = 0; j < subdivision; j++) {
+ textureness[i][j] = -1;
+ }
+ }
+ if (visibleloading)
+ Game::LoadingScreen();
+
+
+ for (i = 0; i < size; i++) {
+ for (j = 0; j < size; j++) {
+ heightmap[i][j] *= .5;
+
+ texoffsetx[i][j] = (float)abs(Random() % 100) / 1200 / scale * 3;
+ texoffsety[i][j] = (float)abs(Random() % 100) / 1200 / scale * 3;
+
+ slopeness = 0;
+ if (environment == snowyenvironment) {
+ if (j != 0 && heightmap[i][j] - heightmap[i][j - 1] > slopeness) {
+ slopeness = heightmap[i][j] - heightmap[i][j - 1];
+ }
+ opacityother[i][j] = slopeness * slopeness * 2;
+ if (opacityother[i][j] > 1)
+ opacityother[i][j] = 1;
+ opacityother[i][j] -= (float)abs(Random() % 100) / 300;
+ }
+ if (environment == desertenvironment) {
+ if (j != 0 && heightmap[i][j] - heightmap[i][j - 1] > slopeness) {
+ slopeness = heightmap[i][j] - heightmap[i][j - 1];
+ }
+ opacityother[i][j] = slopeness * slopeness * 2;
+ if (opacityother[i][j] > 1)
+ opacityother[i][j] = 1;
+ opacityother[i][j] -= (float)abs(Random() % 100) / 300;
+ }
+ if (environment == grassyenvironment) {
+ if (i != 0 && heightmap[i][j] - heightmap[i - 1][j] > slopeness) {
+ slopeness = heightmap[i][j] - heightmap[i - 1][j];
+ }
+ if (j != 0 && heightmap[i][j] - heightmap[i][j - 1] > slopeness) {
+ slopeness = heightmap[i][j] - heightmap[i][j - 1];
+ }
+ if (i < size - 1 && heightmap[i][j] - heightmap[i + 1][j] > slopeness) {
+ slopeness = heightmap[i][j] - heightmap[i + 1][j];
+ }
+ if (j < size - 1 && heightmap[i][j] - heightmap[i][j + 1] > slopeness) {
+ slopeness = heightmap[i][j] - heightmap[i][j + 1];
+ }
+ opacityother[i][j] = slopeness * slopeness * 10;
+ if (opacityother[i][j] > 1)
+ opacityother[i][j] = 1;
+ opacityother[i][j] -= (float)abs(Random() % 100) / 100;
+ }
+ }
+ }
+ if (visibleloading)
+ Game::LoadingScreen();
+
+ for (i = 0; i < size; i++) {
+ for (j = 0; j < size; j++) {
+ if (environment == snowyenvironment) {
+ heightmap[i][j] -= opacityother[i][j];
+ }
+ if (environment == desertenvironment) {
+ heightmap[i][j] -= opacityother[i][j];
+ }
+ }
+ }
+ if (visibleloading)
+ Game::LoadingScreen();
+
+ for (i = 0; i < size; i++) {
+ for (j = 0; j < size; j++) {
+ if (opacityother[i][j] < .1)
+ opacityother[i][j] = 0;
+ if (textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == -1) {
+ if (!opacityother[i][j])
+ textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = allfirst;
+ if (opacityother[i][j] == 1)
+ textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = allsecond;
+ }
+ if (opacityother[i][j] && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allfirst)
+ textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
+ if (opacityother[i][j] != 1 && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allsecond)
+ textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
+
+ x = i;
+ y = j;
+ if (i > 0) {
+ i--;
+ if (opacityother[x][y] && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allfirst)
+ textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
+ if (opacityother[x][y] != 1 && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allsecond)
+ textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
+ if (opacityother[i][j] && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allfirst)
+ textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
+ if (opacityother[i][j] != 1 && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allsecond)
+ textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
+
+ if (j > 0) {
+ j--;
+ if (opacityother[x][y] && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allfirst)
+ textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
+ if (opacityother[x][y] != 1 && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allsecond)
+ textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
+ if (opacityother[i][j] && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allfirst)
+ textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
+ if (opacityother[i][j] != 1 && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allsecond)
+ textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
+ j++;
+ }
+
+ if (j < size - 1) {
+ j++;
+ if (opacityother[x][y] && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allfirst)
+ textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
+ if (opacityother[x][y] != 1 && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allsecond)
+ textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
+ if (opacityother[i][j] && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allfirst)
+ textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
+ if (opacityother[i][j] != 1 && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allsecond)
+ textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
+ j--;
+ }
+ i++;
+ }
+
+ if (i < size - 1) {
+ i++;
+ if (opacityother[x][y] && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allfirst)
+ textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
+ if (opacityother[x][y] != 1 && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allsecond)
+ textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
+ if (opacityother[i][j] && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allfirst)
+ textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
+ if (opacityother[i][j] != 1 && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allsecond)
+ textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
+
+ if (j > 0) {
+ j--;
+ if (opacityother[x][y] && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allfirst)
+ textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
+ if (opacityother[x][y] != 1 && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allsecond)
+ textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
+ if (opacityother[i][j] && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allfirst)
+ textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
+ if (opacityother[i][j] != 1 && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allsecond)
+ textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
+ j++;
+ }
+
+ if (j < size - 1) {
+ j++;
+ if (opacityother[x][y] && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allfirst)
+ textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
+ if (opacityother[x][y] != 1 && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allsecond)
+ textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
+ if (opacityother[i][j] && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allfirst)
+ textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
+ if (opacityother[i][j] != 1 && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allsecond)
+ textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
+ j--;
+ }
+ i--;
+ }
+
+ if (j > 0) {
+ j--;
+ if (opacityother[x][y] && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allfirst)
+ textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
+ if (opacityother[x][y] != 1 && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allsecond)
+ textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
+ if (opacityother[i][j] && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allfirst)
+ textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
+ if (opacityother[i][j] != 1 && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allsecond)
+ textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
+ j++;
+ }
+
+ if (j < size - 1) {
+ j++;
+ if (opacityother[x][y] && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allfirst)
+ textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
+ if (opacityother[x][y] != 1 && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allsecond)
+ textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
+ if (opacityother[i][j] && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allfirst)
+ textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
+ if (opacityother[i][j] != 1 && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allsecond)
+ textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
+ j--;
+
+ }
+ }
+ }
+ if (visibleloading)
+ Game::LoadingScreen();
+
+ patch_size = size / subdivision;
+ patch_elements = (patch_size) * (patch_size) * 54;
+ CalculateNormals();
+
+ return true;
+}
+
+void Terrain::CalculateNormals()
+{
+ static int i, j;
+ static XYZ facenormal;
+ static XYZ p, q, a, b, c;
+
+ for (i = 0; i < size; i++) {
+ for (j = 0; j < size; j++) {
+ normals[i][j].x = 0;
+ normals[i][j].y = 0;
+ normals[i][j].z = 0;
+ }
+ }
+
+ for (i = 0; i < size - 1; i++) {
+ for (j = 0; j < size - 1; j++) {
+ a.x = i;
+ a.y = heightmap[i][j];
+ a.z = j;
+ b.x = i;
+ b.y = heightmap[i][j + 1];
+ b.z = j + 1;
+ c.x = i + 1;
+ c.y = heightmap[i + 1][j];
+ c.z = j;
+
+ p.x = b.x - a.x;
+ p.y = b.y - a.y;
+ p.z = b.z - a.z;
+ q.x = c.x - a.x;
+ q.y = c.y - a.y;
+ q.z = c.z - a.z;
+
+ CrossProduct(&p, &q, &facenormal);
+
+ facenormals[i][j] = facenormal;
+
+ normals[i][j] = normals[i][j] + facenormal;
+ normals[i][j + 1] = normals[i][j + 1] + facenormal;
+ normals[i + 1][j] = normals[i + 1][j] + facenormal;
+
+
+ a.x = i + 1;
+ a.y = heightmap[i + 1][j];
+ a.z = j;
+ b.x = i;
+ b.y = heightmap[i][j + 1];
+ b.z = j + 1;
+ c.x = i + 1;
+ c.y = heightmap[i + 1][j + 1];
+ c.z = j + 1;
+
+ p.x = b.x - a.x;
+ p.y = b.y - a.y;
+ p.z = b.z - a.z;
+ q.x = c.x - a.x;
+ q.y = c.y - a.y;
+ q.z = c.z - a.z;
+
+ CrossProduct(&p, &q, &facenormal);
+
+ normals[i + 1][j + 1] = normals[i + 1][j + 1] + facenormal;
+ normals[i][j + 1] = normals[i][j + 1] + facenormal;
+ normals[i + 1][j] = normals[i + 1][j] + facenormal;
+
+ Normalise(&facenormals[i][j]);
+ }
+ }
+
+ for (i = 0; i < size; i++) {
+ for (j = 0; j < size; j++) {
+ Normalise(&normals[i][j]);
+ }
+ }
+}
+
+void Terrain::drawpatch(int whichx, int whichy, float opacity)
+{
+ if (opacity >= 1)
+ glDisable(GL_BLEND);
+ if (opacity < 1) {
+ glEnable(GL_BLEND);
+ UpdateTransparency(whichx, whichy);
+ }
+ glColor4f(1, 1, 1, 1);
+ //Set up vertex array
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_COLOR_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glVertexPointer(3, GL_FLOAT, 9 * sizeof(GLfloat), &vArray[0 + whichx * patch_elements + whichy * patch_elements * subdivision]);
+ glColorPointer(4, GL_FLOAT, 9 * sizeof(GLfloat), &vArray[3 + whichx * patch_elements + whichy * patch_elements * subdivision]);
+ glTexCoordPointer(2, GL_FLOAT, 9 * sizeof(GLfloat), &vArray[7 + whichx * patch_elements + whichy * patch_elements * subdivision]);
+
+ //Draw
+ glDrawArrays(GL_TRIANGLES, 0, numtris[whichx][whichy] * 3);
+
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+}
+
+void Terrain::drawpatchother(int whichx, int whichy, float opacity)
+{
+ glEnable(GL_BLEND);
+ if (opacity < 1) {
+ UpdateTransparency(whichx, whichy);
+ }
+ UpdateTransparencyother(whichx, whichy);
+ glColor4f(1, 1, 1, 1);
+ //Set up vertex array
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_COLOR_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glVertexPointer(3, GL_FLOAT, 9 * sizeof(GLfloat), &vArray[0 + whichx * patch_elements + whichy * patch_elements * subdivision]);
+ glColorPointer(4, GL_FLOAT, 9 * sizeof(GLfloat), &vArray[3 + whichx * patch_elements + whichy * patch_elements * subdivision]);
+ glTexCoordPointer(2, GL_FLOAT, 9 * sizeof(GLfloat), &vArray[7 + whichx * patch_elements + whichy * patch_elements * subdivision]);
+
+ //Draw
+ glDrawArrays(GL_TRIANGLES, 0, numtris[whichx][whichy] * 3);
+
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+}
+
+void Terrain::drawpatchotherother(int whichx, int whichy, float opacity)
+{
+ glEnable(GL_BLEND);
+ UpdateTransparencyotherother(whichx, whichy);
+
+ glMatrixMode(GL_TEXTURE);
+ glPushMatrix();
+ glScalef(6, 6, 6);
+
+ glColor4f(1, 1, 1, 1);
+
+ //Set up vertex array
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_COLOR_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glVertexPointer(3, GL_FLOAT, 9 * sizeof(GLfloat), &vArray[0 + whichx * patch_elements + whichy * patch_elements * subdivision]);
+ glColorPointer(4, GL_FLOAT, 9 * sizeof(GLfloat), &vArray[3 + whichx * patch_elements + whichy * patch_elements * subdivision]);
+ glTexCoordPointer(2, GL_FLOAT, 9 * sizeof(GLfloat), &vArray[7 + whichx * patch_elements + whichy * patch_elements * subdivision]);
+
+ //Draw
+ glDrawArrays(GL_TRIANGLES, 0, numtris[whichx][whichy] * 3);
+
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+}
+
+
+float Terrain::getHeight(float pointx, float pointz)
+{
+ static int tilex, tiley;
+ static XYZ startpoint, endpoint, intersect, triangle[3];
+
+ pointx /= scale;
+ pointz /= scale;
+
+ if (pointx >= size - 1 || pointz >= size - 1 || pointx <= 0 || pointz <= 0)
+ return 0;
+
+ startpoint.x = pointx;
+ startpoint.y = -1000;
+ startpoint.z = pointz;
+
+ endpoint = startpoint;
+ endpoint.y = 1000;
+
+ tilex = pointx;
+ tiley = pointz;
+
+ triangle[0].x = tilex;
+ triangle[0].z = tiley;
+ triangle[0].y = heightmap[tilex][tiley];
+
+ triangle[1].x = tilex + 1;
+ triangle[1].z = tiley;
+ triangle[1].y = heightmap[tilex + 1][tiley];
+
+ triangle[2].x = tilex;
+ triangle[2].z = tiley + 1;
+ triangle[2].y = heightmap[tilex][tiley + 1];
+
+ if (!LineFacetd(&startpoint, &endpoint, &triangle[0], &triangle[1], &triangle[2], &intersect)) {
+ triangle[0].x = tilex + 1;
+ triangle[0].z = tiley;
+ triangle[0].y = heightmap[tilex + 1][tiley];
+
+ triangle[1].x = tilex + 1;
+ triangle[1].z = tiley + 1;
+ triangle[1].y = heightmap[tilex + 1][tiley + 1];
+
+ triangle[2].x = tilex;
+ triangle[2].z = tiley + 1;
+ triangle[2].y = heightmap[tilex][tiley + 1];
+ LineFacetd(&startpoint, &endpoint, &triangle[0], &triangle[1], &triangle[2], &intersect);
+ }
+ return intersect.y * scale + getOpacity(pointx * scale, pointz * scale) / 8;
+}
+
+float Terrain::getOpacity(float pointx, float pointz)
+{
+ static float height1, height2;
+ static int tilex, tiley;
+
+ pointx /= scale;
+ pointz /= scale;
+
+ if (pointx >= size - 1 || pointz >= size - 1 || pointx <= 0 || pointz <= 0)
+ return 0;
+
+ tilex = pointx;
+ tiley = pointz;
+
+ height1 = opacityother[tilex][tiley] * (1 - (pointx - tilex)) + opacityother[tilex + 1][tiley] * (pointx - tilex);
+ height2 = opacityother[tilex][tiley + 1] * (1 - (pointx - tilex)) + opacityother[tilex + 1][tiley + 1] * (pointx - tilex);
+
+ return height1 * (1 - (pointz - tiley)) + height2 * (pointz - tiley);
+}
+
+XYZ Terrain::getNormal(float pointx, float pointz)
+{
+ static XYZ height1, height2, total;
+ static int tilex, tiley;
+
+ pointx /= scale;
+ pointz /= scale;
+
+ height1 = 0;
+ if (pointx >= size - 1 || pointz >= size - 1 || pointx <= 0 || pointz <= 0)
+ return height1;
+ tilex = pointx;
+ tiley = pointz;
+
+ height1 = normals[tilex][tiley] * (1 - (pointx - tilex)) + normals[tilex + 1][tiley] * (pointx - tilex);
+ height2 = normals[tilex][tiley + 1] * (1 - (pointx - tilex)) + normals[tilex + 1][tiley + 1] * (pointx - tilex);
+ total = height1 * (1 - (pointz - tiley)) + height2 * (pointz - tiley);
+ Normalise(&total);
+ return total;
+}
+
+XYZ Terrain::getLighting(float pointx, float pointz)
+{
+ static XYZ height1, height2;
+ static int tilex, tiley;
+
+ pointx /= scale;
+ pointz /= scale;
+
+ height1 = 0;
+ if (pointx >= size - 1 || pointz >= size - 1 || pointx <= 0 || pointz <= 0)
+ return height1;
+ tilex = pointx;
+ tiley = pointz;
+
+ height1.x = colors[tilex][tiley][0] * (1 - (pointx - tilex)) + colors[tilex + 1][tiley][0] * (pointx - tilex);
+ height1.y = colors[tilex][tiley][1] * (1 - (pointx - tilex)) + colors[tilex + 1][tiley][1] * (pointx - tilex);
+ height1.z = colors[tilex][tiley][2] * (1 - (pointx - tilex)) + colors[tilex + 1][tiley][2] * (pointx - tilex);
+ height2.x = colors[tilex][tiley + 1][0] * (1 - (pointx - tilex)) + colors[tilex + 1][tiley + 1][0] * (pointx - tilex);
+ height2.y = colors[tilex][tiley + 1][1] * (1 - (pointx - tilex)) + colors[tilex + 1][tiley + 1][1] * (pointx - tilex);
+ height2.z = colors[tilex][tiley + 1][2] * (1 - (pointx - tilex)) + colors[tilex + 1][tiley + 1][2] * (pointx - tilex);
+
+ return height1 * (1 - (pointz - tiley)) + height2 * (pointz - tiley);
+}
+
+void Terrain::draw(int layer)
+{
+ static int i, j;
+ static float opacity;
+ static XYZ terrainpoint;
+ static float distance[subdivision][subdivision];
+
+ static int beginx, endx;
+ static int beginz, endz;
+
+ static float patch_size = size / subdivision * scale;
+ static float viewdistsquared;
+
+ viewdistsquared = viewdistance * viewdistance;
+
+ //Only nearby blocks
+ beginx = (viewer.x - viewdistance) / (patch_size) - 1;
+ if (beginx < 0)
+ beginx = 0;
+ beginz = (viewer.z - viewdistance) / (patch_size) - 1;
+ if (beginz < 0)
+ beginz = 0;
+
+ endx = (viewer.x + viewdistance) / (patch_size) + 1;
+ if (endx > subdivision)
+ endx = subdivision;
+ endz = (viewer.z + viewdistance) / (patch_size) + 1;
+ if (endz > subdivision)
+ endz = subdivision;
+
+ if (!layer) {
+ for (i = beginx; i < endx; i++) {
+ for (j = beginz; j < endz; j++) {
+ terrainpoint.x = i * patch_size + (patch_size) / 2;
+ terrainpoint.y = viewer.y; //heightmap[i][j]*scale;
+ terrainpoint.z = j * patch_size + (patch_size) / 2;
+ distance[i][j] = distsq(&viewer, &terrainpoint);
+ }
+ }
+ }
+ for (i = beginx; i < endx; i++) {
+ for (j = beginz; j < endz; j++) {
+ if (distance[i][j] < (viewdistance + patch_size) * (viewdistance + patch_size)) {
+ opacity = 1;
+ if (distance[i][j] > viewdistsquared * fadestart - viewdistsquared)
+ opacity = 0;
+ if (opacity == 1 && i != subdivision)
+ if (distance[i + 1][j] > viewdistsquared * fadestart - viewdistsquared)
+ opacity = 0;
+ if (opacity == 1 && j != subdivision)
+ if (distance[i][j + 1] > viewdistsquared * fadestart - viewdistsquared)
+ opacity = 0;
+ if (opacity == 1 && j != subdivision && i != subdivision)
+ if (distance[i + 1][j + 1] > viewdistsquared * fadestart - viewdistsquared)
+ opacity = 0;
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ if (frustum.CubeInFrustum(i * patch_size + patch_size * .5, avgypatch[i][j], j * patch_size + patch_size * .5, heightypatch[i][j] / 2)) {
+ if (environment == desertenvironment && distance[i][j] > viewdistsquared / 4)
+ glTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, blurness);
+ else if (environment == desertenvironment)
+ glTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0 );
+ if (!layer && textureness[i][j] != allsecond)
+ drawpatch(i, j, opacity);
+ if (layer == 1 && textureness[i][j] != allfirst)
+ drawpatchother(i, j, opacity);
+ if (layer == 2 && textureness[i][j] != allfirst)
+ drawpatchotherother(i, j, opacity);
+ }
+ glPopMatrix();
+ }
+ }
+ }
+ if (environment == desertenvironment)
+ glTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0 );
+}
+
+void Terrain::drawdecals()
+{
+ if (decals) {
+ static int i;
+ static float distancemult;
+ static int lasttype;
+
+ static float viewdistsquared;
+ static bool blend;
+
+ viewdistsquared = viewdistance * viewdistance;
+ blend = 1;
+
+ lasttype = -1;
+ glEnable(GL_BLEND);
+ glDisable(GL_LIGHTING);
+ glDisable(GL_CULL_FACE);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDepthMask(0);
+ for (i = 0; i < numdecals; i++) {
+ if (decaltype[i] == blooddecalfast && decalalivetime[i] < 2)
+ decalalivetime[i] = 2;
+ if ((decaltype[i] == shadowdecal || decaltype[i] == shadowdecalpermanent) && decaltype[i] != lasttype) {
+ shadowtexture.bind();
+ if (!blend) {
+ blend = 1;
+ glAlphaFunc(GL_GREATER, 0.0001);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+ }
+ if (decaltype[i] == footprintdecal && decaltype[i] != lasttype) {
+ footprinttexture.bind();
+ if (!blend) {
+ blend = 1;
+ glAlphaFunc(GL_GREATER, 0.0001);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+ }
+ if (decaltype[i] == bodyprintdecal && decaltype[i] != lasttype) {
+ bodyprinttexture.bind();
+ if (!blend) {
+ blend = 1;
+ glAlphaFunc(GL_GREATER, 0.0001);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+ }
+ if ((decaltype[i] == blooddecal || decaltype[i] == blooddecalslow) && decaltype[i] != lasttype) {
+ bloodtexture.bind();
+ if (blend) {
+ blend = 0;
+ glAlphaFunc(GL_GREATER, 0.15);
+ glBlendFunc(GL_ONE, GL_ZERO);
+ }
+ }
+ if ((decaltype[i] == blooddecalfast) && decaltype[i] != lasttype) {
+ bloodtexture2.bind();
+ if (blend) {
+ blend = 0;
+ glAlphaFunc(GL_GREATER, 0.15);
+ glBlendFunc(GL_ONE, GL_ZERO);
+ }
+ }
+ if (decaltype[i] == shadowdecal || decaltype[i] == shadowdecalpermanent) {
+ distancemult = (viewdistsquared - (distsq(&viewer, &decalposition[i]) - (viewdistsquared * fadestart)) * (1 / (1 - fadestart))) / viewdistsquared;
+ if (distancemult >= 1)
+ glColor4f(1, 1, 1, decalopacity[i]);
+ if (distancemult < 1)
+ glColor4f(1, 1, 1, decalopacity[i]*distancemult);
+ }
+ if (decaltype[i] == footprintdecal || decaltype[i] == bodyprintdecal) {
+ distancemult = (viewdistsquared - (distsq(&viewer, &decalposition[i]) - (viewdistsquared * fadestart)) * (1 / (1 - fadestart))) / viewdistsquared;
+ if (distancemult >= 1) {
+ glColor4f(1, 1, 1, decalopacity[i]);
+ if (decalalivetime[i] > 3)
+ glColor4f(1, 1, 1, decalopacity[i] * (5 - decalalivetime[i]) / 2);
+ }
+ if (distancemult < 1) {
+ glColor4f(1, 1, 1, decalopacity[i]*distancemult);
+ if (decalalivetime[i] > 3)
+ glColor4f(1, 1, 1, decalopacity[i] * (5 - decalalivetime[i]) / 2 * distancemult);
+ }
+ }
+ if ((decaltype[i] == blooddecal || decaltype[i] == blooddecalfast || decaltype[i] == blooddecalslow)) {
+ distancemult = (viewdistsquared - (distsq(&viewer, &decalposition[i]) - (viewdistsquared * fadestart)) * (1 / (1 - fadestart))) / viewdistsquared;
+ if (distancemult >= 1) {
+ glColor4f(decalbrightness[i], decalbrightness[i], decalbrightness[i], decalopacity[i]);
+ if (decalalivetime[i] < 4)
+ glColor4f(decalbrightness[i], decalbrightness[i], decalbrightness[i], decalopacity[i]*decalalivetime[i]*.25);
+ if (decalalivetime[i] > 58)
+ glColor4f(decalbrightness[i], decalbrightness[i], decalbrightness[i], decalopacity[i] * (60 - decalalivetime[i]) / 2);
+ }
+ if (distancemult < 1) {
+ glColor4f(decalbrightness[i], decalbrightness[i], decalbrightness[i], decalopacity[i]*distancemult);
+ if (decalalivetime[i] < 4)
+ glColor4f(decalbrightness[i], decalbrightness[i], decalbrightness[i], decalopacity[i]*decalalivetime[i]*distancemult * .25);
+ if (decalalivetime[i] > 58)
+ glColor4f(decalbrightness[i], decalbrightness[i], decalbrightness[i], decalopacity[i] * (60 - decalalivetime[i]) / 2 * distancemult);
+ }
+ }
+ lasttype = decaltype[i];
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glBegin(GL_TRIANGLES);
+ for (int j = 0; j < 3; j++) {
+ glTexCoord2f(decaltexcoords[i][j][0], decaltexcoords[i][j][1]);
+ glVertex3f(decalvertex[i][j].x, decalvertex[i][j].y, decalvertex[i][j].z);
+ }
+ glEnd();
+ glPopMatrix();
+ }
+ for (i = numdecals - 1; i >= 0; i--) {
+ decalalivetime[i] += multiplier;
+ if (decaltype[i] == blooddecalslow)
+ decalalivetime[i] -= multiplier * 2 / 3;
+ if (decaltype[i] == blooddecalfast)
+ decalalivetime[i] += multiplier * 4;
+ if (decaltype[i] == shadowdecal)
+ DeleteDecal(i);
+ if (decaltype[i] == footprintdecal && decalalivetime[i] >= 5)
+ DeleteDecal(i);
+ if (decaltype[i] == bodyprintdecal && decalalivetime[i] >= 5)
+ DeleteDecal(i);
+ if ((decaltype[i] == blooddecal || decaltype[i] == blooddecalfast || decaltype[i] == blooddecalslow) && decalalivetime[i] >= 60)
+ DeleteDecal(i);
+ }
+ glAlphaFunc(GL_GREATER, 0.0001);
+ }
+}
+
+void Terrain::AddObject(XYZ where, float radius, int id)
+{
+ bool done;
+ int i, j;
+ XYZ points[4];
+ if (id >= 0 && id < 10000)
+ for (i = 0; i < subdivision; i++) {
+ for (j = 0; j < subdivision; j++) {
+ if (patchobjectnum[i][j] < 300 - 1) {
+ done = 0;
+ points[0].x = (size / subdivision) * i;
+ points[0].z = (size / subdivision) * j;
+ points[0].y = heightmap[(int)points[0].x][(int)points[0].z];
+ points[1].x = (size / subdivision) * (i + 1);
+ points[1].z = (size / subdivision) * j;
+ points[1].y = heightmap[(int)points[1].x][(int)points[1].z];
+ points[2].x = (size / subdivision) * (i + 1);
+ points[2].z = (size / subdivision) * (j + 1);
+ points[2].y = heightmap[(int)points[2].x][(int)points[2].z];
+ points[3].x = (size / subdivision) * i;
+ points[3].z = (size / subdivision) * (j + 1);
+ points[3].y = heightmap[(int)points[3].x][(int)points[3].z];
+ points[0] *= scale;
+ points[1] *= scale;
+ points[2] *= scale;
+ points[3] *= scale;
+ if (!done && where.x + radius > points[0].x && where.x - radius < points[2].x && where.z + radius > points[0].z && where.z - radius < points[2].z) {
+ patchobjects[i][j][patchobjectnum[i][j]] = id;
+ patchobjectnum[i][j]++;
+ done = 1;
+ }
+ }
+ }
+ }
+}
+
+void Terrain::DeleteDecal(int which)
+{
+ if (decals) {
+ decaltype[which] = decaltype[numdecals - 1];
+ decalposition[which] = decalposition[numdecals - 1];
+ for (int i = 0; i < 3; i++) {
+ decalvertex[which][i] = decalvertex[numdecals - 1][i];
+ decaltexcoords[which][i][0] = decaltexcoords[numdecals - 1][i][0];
+ decaltexcoords[which][i][1] = decaltexcoords[numdecals - 1][i][1];
+ }
+ decalrotation[which] = decalrotation[numdecals - 1];
+ decalalivetime[which] = decalalivetime[numdecals - 1];
+ decalopacity[which] = decalopacity[numdecals - 1];
+ decalbrightness[which] = decalbrightness[numdecals - 1];
+ numdecals--;
+ }
+}
+
+void Terrain::MakeDecal(int type, XYZ where, float size, float opacity, float rotation)
+{
+ if (decals) {
+ if (opacity > 0 && size > 0) {
+ static int patchx[4];
+ static int patchy[4];
+
+ decaltexcoords[numdecals][0][0] = 1;
+ decaltexcoords[numdecals][0][1] = 0;
+
+ patchx[0] = (where.x + size) / scale;
+ patchx[1] = (where.x - size) / scale;
+ patchx[2] = (where.x - size) / scale;
+ patchx[3] = (where.x + size) / scale;
+
+ patchy[0] = (where.z - size) / scale;
+ patchy[1] = (where.z - size) / scale;
+ patchy[2] = (where.z + size) / scale;
+ patchy[3] = (where.z + size) / scale;
+
+ if ((patchx[0] != patchx[1] || patchy[0] != patchy[1]) && (patchx[0] != patchx[2] || patchy[0] != patchy[2]) && (patchx[0] != patchx[3] || patchy[0] != patchy[3])) {
+ MakeDecalLock(type, where, patchx[0], patchy[0], size, opacity, rotation);
+ }
+
+ if ((patchx[1] != patchx[2] || patchy[1] != patchy[2]) && (patchx[1] != patchx[3] || patchy[1] != patchy[3])) {
+ MakeDecalLock(type, where, patchx[1], patchy[1], size, opacity, rotation);
+ }
+
+ if ((patchx[2] != patchx[3] || patchy[2] != patchy[3])) {
+ MakeDecalLock(type, where, patchx[2], patchy[2], size, opacity, rotation);
+ }
+ MakeDecalLock(type, where, patchx[3], patchy[3], size, opacity, rotation);
+ }
+ }
+ //}
+}
+
+void Terrain::MakeDecalLock(int type, XYZ where, int whichx, int whichy, float size, float opacity, float rotation)
+{
+ if (decals) {
+ static float placex, placez;
+ static XYZ rot;
+
+ float decalbright;
+
+ rot = getLighting(where.x, where.z);
+ decalbrightness[numdecals] = (rot.x + rot.y + rot.z) / 3;
+ if (decalbrightness[numdecals] < .4)
+ decalbrightness[numdecals] = .4;
+
+ if (environment == grassyenvironment) {
+ decalbrightness[numdecals] *= .6;
+ }
+
+ if (decalbrightness[numdecals] > 1)
+ decalbrightness[numdecals] = 1;
+ decalbright = decalbrightness[numdecals];
+
+ decalposition[numdecals] = where;
+ decaltype[numdecals] = type;
+ decalopacity[numdecals] = opacity;
+ decalrotation[numdecals] = rotation;
+ decalalivetime[numdecals] = 0;
+
+ placex = (float)whichx * scale + scale;
+ placez = (float)whichy * scale;
+
+ decaltexcoords[numdecals][0][0] = (placex - where.x) / size / 2 + .5;
+ decaltexcoords[numdecals][0][1] = (placez - where.z) / size / 2 + .5;
+
+ decalvertex[numdecals][0].x = placex;
+ decalvertex[numdecals][0].z = placez;
+ decalvertex[numdecals][0].y = heightmap[whichx + 1][whichy] * scale + .01;
+
+
+ placex = (float)whichx * scale + scale;
+ placez = (float)whichy * scale + scale;
+
+ decaltexcoords[numdecals][1][0] = (placex - where.x) / size / 2 + .5;
+ decaltexcoords[numdecals][1][1] = (placez - where.z) / size / 2 + .5;
+
+ decalvertex[numdecals][1].x = placex;
+ decalvertex[numdecals][1].z = placez;
+ decalvertex[numdecals][1].y = heightmap[whichx + 1][whichy + 1] * scale + .01;
+
+
+ placex = (float)whichx * scale;
+ placez = (float)whichy * scale + scale;
+
+ decaltexcoords[numdecals][2][0] = (placex - where.x) / size / 2 + .5;
+ decaltexcoords[numdecals][2][1] = (placez - where.z) / size / 2 + .5;
+
+ decalvertex[numdecals][2].x = placex;
+ decalvertex[numdecals][2].z = placez;
+ decalvertex[numdecals][2].y = heightmap[whichx][whichy + 1] * scale + .01;
+
+ if (decalrotation[numdecals]) {
+ for (int i = 0; i < 3; i++) {
+ rot.y = 0;
+ rot.x = decaltexcoords[numdecals][i][0] - .5;
+ rot.z = decaltexcoords[numdecals][i][1] - .5;
+ rot = DoRotation(rot, 0, -decalrotation[numdecals], 0);
+ decaltexcoords[numdecals][i][0] = rot.x + .5;
+ decaltexcoords[numdecals][i][1] = rot.z + .5;
+ }
+ }
+
+ if (!(decaltexcoords[numdecals][0][0] < 0 && decaltexcoords[numdecals][1][0] < 0 && decaltexcoords[numdecals][2][0] < 0))
+ if (!(decaltexcoords[numdecals][0][1] < 0 && decaltexcoords[numdecals][1][1] < 0 && decaltexcoords[numdecals][2][1] < 0))
+ if (!(decaltexcoords[numdecals][0][0] > 1 && decaltexcoords[numdecals][1][0] > 1 && decaltexcoords[numdecals][2][0] > 1))
+ if (!(decaltexcoords[numdecals][0][1] > 1 && decaltexcoords[numdecals][1][1] > 1 && decaltexcoords[numdecals][2][1] > 1))
+ if (numdecals < max_decals - 1)
+ numdecals++;
+
+ decalbrightness[numdecals] = decalbright;
+
+ decalposition[numdecals] = where;
+ decaltype[numdecals] = type;
+ decalopacity[numdecals] = opacity;
+ decalrotation[numdecals] = rotation;
+ decalalivetime[numdecals] = 0;
+
+ placex = (float)whichx * scale + scale;
+ placez = (float)whichy * scale;
+
+ decaltexcoords[numdecals][0][0] = (placex - where.x) / size / 2 + .5;
+ decaltexcoords[numdecals][0][1] = (placez - where.z) / size / 2 + .5;
+
+ decalvertex[numdecals][0].x = placex;
+ decalvertex[numdecals][0].z = placez;
+ decalvertex[numdecals][0].y = heightmap[whichx + 1][whichy] * scale + .01;
+
+
+ placex = (float)whichx * scale;
+ placez = (float)whichy * scale;
+
+ decaltexcoords[numdecals][1][0] = (placex - where.x) / size / 2 + .5;
+ decaltexcoords[numdecals][1][1] = (placez - where.z) / size / 2 + .5;
+
+ decalvertex[numdecals][1].x = placex;
+ decalvertex[numdecals][1].z = placez;
+ decalvertex[numdecals][1].y = heightmap[whichx][whichy] * scale + .01;
+
+
+ placex = (float)whichx * scale;
+ placez = (float)whichy * scale + scale;
+
+ decaltexcoords[numdecals][2][0] = (placex - where.x) / size / 2 + .5;
+ decaltexcoords[numdecals][2][1] = (placez - where.z) / size / 2 + .5;
+
+ decalvertex[numdecals][2].x = placex;
+ decalvertex[numdecals][2].z = placez;
+ decalvertex[numdecals][2].y = heightmap[whichx][whichy + 1] * scale + .01;
+
+ if (decalrotation[numdecals]) {
+ for (int i = 0; i < 3; i++) {
+ rot.y = 0;
+ rot.x = decaltexcoords[numdecals][i][0] - .5;
+ rot.z = decaltexcoords[numdecals][i][1] - .5;
+ rot = DoRotation(rot, 0, -decalrotation[numdecals], 0);
+ decaltexcoords[numdecals][i][0] = rot.x + .5;
+ decaltexcoords[numdecals][i][1] = rot.z + .5;
+ }
+ }
+
+ if (!(decaltexcoords[numdecals][0][0] < 0 && decaltexcoords[numdecals][1][0] < 0 && decaltexcoords[numdecals][2][0] < 0))
+ if (!(decaltexcoords[numdecals][0][1] < 0 && decaltexcoords[numdecals][1][1] < 0 && decaltexcoords[numdecals][2][1] < 0))
+ if (!(decaltexcoords[numdecals][0][0] > 1 && decaltexcoords[numdecals][1][0] > 1 && decaltexcoords[numdecals][2][0] > 1))
+ if (!(decaltexcoords[numdecals][0][1] > 1 && decaltexcoords[numdecals][1][1] > 1 && decaltexcoords[numdecals][2][1] > 1))
+ if (numdecals < max_decals - 1)
+ numdecals++;
+ }
+}
+
+void Terrain::DoShadows()
+{
+ static int i, j, k, l, todivide;
+ static float brightness, total;
+ static XYZ testpoint, testpoint2, terrainpoint, lightloc, col;
+ lightloc = light.location;
+ if (!skyboxtexture) {
+ lightloc.x = 0;
+ lightloc.z = 0;
+ }
+ if (skyboxtexture && tutoriallevel) {
+ lightloc.x *= .4;
+ lightloc.z *= .4;
+ }
+ int patchx, patchz;
+ float shadowed;
+ Normalise(&lightloc);
+ //Calculate shadows
+ for (i = 0; i < size; i++) {
+ for (j = 0; j < size; j++) {
+ terrainpoint.x = (float)(i) * scale;
+ terrainpoint.z = (float)(j) * scale;
+ terrainpoint.y = heightmap[i][j] * scale;
+
+ shadowed = 0;
+ patchx = (float)(i) * subdivision / size;
+ patchz = (float)(j) * subdivision / size;
+ if (patchobjectnum[patchx][patchz]) {
+ for (k = 0; k < patchobjectnum[patchx][patchz]; k++) {
+ l = patchobjects[patchx][patchz][k];
+ if (objects.type[l] != treetrunktype) {
+ testpoint = terrainpoint;
+ testpoint2 = terrainpoint + lightloc * 50 * (1 - shadowed);
+ if (objects.model[l].LineCheck(&testpoint, &testpoint2, &col, &objects.position[l], &objects.yaw[l]) != -1) {
+ shadowed = 1 - (findDistance(&terrainpoint, &col) / 50);
+ }
+ }
+ }
+ if (visibleloading)
+ Game::LoadingScreen();
+ }
+ brightness = dotproduct(&lightloc, &normals[i][j]);
+ if (shadowed)
+ brightness *= 1 - shadowed;
+
+ if (brightness > 1)
+ brightness = 1;
+ if (brightness < 0)
+ brightness = 0;
+
+ colors[i][j][0] = light.color[0] * brightness + light.ambient[0];
+ colors[i][j][1] = light.color[1] * brightness + light.ambient[1];
+ colors[i][j][2] = light.color[2] * brightness + light.ambient[2];
+
+ if (colors[i][j][0] > 1) colors[i][j][0] = 1;
+ if (colors[i][j][1] > 1) colors[i][j][1] = 1;
+ if (colors[i][j][2] > 1) colors[i][j][2] = 1;
+ if (colors[i][j][0] < 0) colors[i][j][0] = 0;
+ if (colors[i][j][1] < 0) colors[i][j][1] = 0;
+ if (colors[i][j][2] < 0) colors[i][j][2] = 0;
+ }
+ }
+
+ if (visibleloading)
+ Game::LoadingScreen();
+
+ //Smooth shadows
+ for (i = 0; i < size; i++) {
+ for (j = 0; j < size; j++) {
+ for (k = 0; k < 3; k++) {
+ total = 0;
+ todivide = 0;
+ if (i != 0) {
+ total += colors[j][i - 1][k];
+ todivide++;
+ }
+ if (i != size - 1) {
+ total += colors[j][i + 1][k];
+ todivide++;
+ }
+ if (j != 0) {
+ total += colors[j - 1][i][k];
+ todivide++;
+ }
+ if (j != size - 1) {
+ total += colors[j + 1][i][k];
+ todivide++;
+ }
+ if (i != 0 && j != 0) {
+ total += colors[j - 1][i - 1][k];
+ todivide++;
+ }
+ if (i != size - 1 && j != 0) {
+ total += colors[j - 1][i + 1][k];
+ todivide++;
+ }
+ if (j != size - 1 && i != size - 1) {
+ total += colors[j + 1][i + 1][k];
+ todivide++;
+ }
+ if (j != size - 1 && i != 0) {
+ total += colors[j + 1][i - 1][k];
+ todivide++;
+ }
+ total += colors[j][i][k];
+ todivide++;
+
+ colors[j][i][k] = total / todivide;
+ }
+ }
+ }
+
+ for (i = 0; i < subdivision; i++) {
+ for (j = 0; j < subdivision; j++) {
+ UpdateVertexArray(i, j);
+ }
+ }
+}
+
+Terrain::Terrain()
+{
+ size = 0;
+
+ memset(patchobjectnum, 0, sizeof(patchobjectnum));
+ memset(patchobjects, 0, sizeof(patchobjects));
+
+ scale = 1.0f;
+ type = 0;
+ memset(heightmap, 0, sizeof(heightmap));
+ memset(normals, 0, sizeof(normals));
+ memset(facenormals, 0, sizeof(facenormals));
+ memset(triangles, 0, sizeof(triangles));
+ memset(colors, 0, sizeof(colors));
+ memset(opacityother, 0, sizeof(opacityother));
+ memset(texoffsetx, 0, sizeof(texoffsetx));
+ memset(texoffsety, 0, sizeof(texoffsety));
+ memset(numtris, 0, sizeof(numtris));
+ memset(textureness, 0, sizeof(textureness));
+
+ memset(vArray, 0, sizeof(vArray));
+
+ memset(visible, 0, sizeof(visible));
+ memset(avgypatch, 0, sizeof(avgypatch));
+ memset(maxypatch, 0, sizeof(maxypatch));
+ memset(minypatch, 0, sizeof(minypatch));
+ memset(heightypatch, 0, sizeof(heightypatch));
+
+ patch_elements = 0;
+
+ memset(decaltexcoords, 0, sizeof(decaltexcoords));
+ memset(decalvertex, 0, sizeof(decalvertex));
+ memset(decaltype, 0, sizeof(decaltype));
+ memset(decalopacity, 0, sizeof(decalopacity));
+ memset(decalrotation, 0, sizeof(decalrotation));
+ memset(decalalivetime, 0, sizeof(decalalivetime));
+ memset(decalbrightness, 0, sizeof(decalbrightness));
+ memset(decalposition, 0, sizeof(decalposition));
+ numdecals = 0;
+}
+Terrain::~Terrain()
+{
+ terraintexture.destroy();
+ shadowtexture.destroy();
+ bodyprinttexture.destroy();
+ footprinttexture.destroy();
+ bloodtexture.destroy();
+ bloodtexture2.destroy();
+ breaktexture.destroy();
+}
+
--- /dev/null
+/*
+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 _TERRAIN_H_
+#define _TERRAIN_H_
+
+#include "Environment/Lights.h"
+#include "Graphic/gamegl.h"
+#include "Graphic/Texture.h"
+#include "Math/Frustum.h"
+#include "Math/Quaternions.h"
+#include "Math/Quaternions.h"
+#include "Utils/ImageIO.h"
+
+#define max_terrain_size 256
+#define curr_terrain_size size
+#define subdivision 64
+#define max_patch_elements (max_terrain_size/subdivision)*(max_terrain_size/subdivision)*54
+
+#define allfirst 0
+#define mixed 1
+#define allsecond 2
+
+#define max_decals 1000
+
+#define shadowdecal 0
+#define footprintdecal 1
+#define blooddecal 2
+#define blooddecalfast 3
+#define shadowdecalpermanent 4
+#define breakdecal 5
+#define blooddecalslow 6
+#define bodyprintdecal 7
+
+#define snowyenvironment 0
+#define grassyenvironment 1
+#define desertenvironment 2
+//
+// Model Structures
+//
+
+class Terrain
+{
+public:
+ Texture bloodtexture;
+ Texture bloodtexture2;
+ Texture shadowtexture;
+ Texture footprinttexture;
+ Texture bodyprinttexture;
+ Texture breaktexture;
+ Texture terraintexture;
+ short size;
+
+ int patchobjectnum[subdivision][subdivision];
+ int patchobjects[subdivision][subdivision][300];
+
+ float scale;
+ int type;
+ float heightmap[max_terrain_size + 1][max_terrain_size + 1];
+ XYZ normals[max_terrain_size][max_terrain_size];
+ XYZ facenormals[max_terrain_size][max_terrain_size];
+ XYZ triangles[(max_terrain_size - 1) * (max_terrain_size - 1) * 2][3];
+ float colors[max_terrain_size][max_terrain_size][4];
+ float opacityother[max_terrain_size][max_terrain_size];
+ float texoffsetx[max_terrain_size][max_terrain_size];
+ float texoffsety[max_terrain_size][max_terrain_size];
+ int numtris[subdivision][subdivision];
+ int textureness[subdivision][subdivision];
+
+ GLfloat vArray[(max_patch_elements)*subdivision*subdivision];
+
+ bool visible[subdivision][subdivision];
+ float avgypatch[subdivision][subdivision];
+ float maxypatch[subdivision][subdivision];
+ float minypatch[subdivision][subdivision];
+ float heightypatch[subdivision][subdivision];
+
+ int patch_elements;
+
+ float decaltexcoords[max_decals][3][2];
+ XYZ decalvertex[max_decals][3];
+ int decaltype[max_decals];
+ float decalopacity[max_decals];
+ float decalrotation[max_decals];
+ float decalalivetime[max_decals];
+ float decalbrightness[max_decals];
+ XYZ decalposition[max_decals];
+ int numdecals;
+
+ void AddObject(XYZ where, float radius, int id);
+ void DeleteDecal(int which);
+ void MakeDecal(int type, XYZ where, float size, float opacity, float rotation);
+ void MakeDecalLock(int type, XYZ where, int whichx, int whichy, float size, float opacity, float rotation);
+ int lineTerrain(XYZ p1, XYZ p2, XYZ *p);
+ float getHeight(float pointx, float pointz);
+ float getOpacity(float pointx, float pointz);
+ XYZ getLighting(float pointx, float pointz);
+ XYZ getNormal(float pointx, float pointz);
+ void UpdateVertexArray(int whichx, int whichy);
+ void UpdateTransparency(int whichx, int whichy);
+ void UpdateTransparencyother(int whichx, int whichy);
+ void UpdateTransparencyotherother(int whichx, int whichy);
+ bool load(const std::string& fileName);
+ void CalculateNormals();
+ void drawdecals();
+ void draw(int layer);
+ void drawpatch(int whichx, int whichy, float opacity);
+ void drawpatchother(int whichx, int whichy, float opacity);
+ void drawpatchotherother(int whichx, int whichy, float opacity);
+ void DoShadows();
+
+ Terrain();
+ ~Terrain();
+};
+
+#endif
+++ /dev/null
-/*
-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/>.
-*/
-
-#include "Frustum.h"
-#include <math.h>
-
-#include "gamegl.h"
-
-
-void FRUSTUM::
-GetFrustum()
-{
- static float projmatrix[16];
- static float mvmatrix[16];
- static float clip[16];
-
- glGetFloatv(GL_PROJECTION_MATRIX, projmatrix);
- glGetFloatv(GL_MODELVIEW_MATRIX, mvmatrix);
-
- // Combine the matrices
- clip[0] = mvmatrix[0] * projmatrix[0] + mvmatrix[1] * projmatrix[4] + mvmatrix[2] * projmatrix[8] + mvmatrix[3] * projmatrix[12];
- clip[1] = mvmatrix[0] * projmatrix[1] + mvmatrix[1] * projmatrix[5] + mvmatrix[2] * projmatrix[9] + mvmatrix[3] * projmatrix[13];
- clip[2] = mvmatrix[0] * projmatrix[2] + mvmatrix[1] * projmatrix[6] + mvmatrix[2] * projmatrix[10] + mvmatrix[3] * projmatrix[14];
- clip[3] = mvmatrix[0] * projmatrix[3] + mvmatrix[1] * projmatrix[7] + mvmatrix[2] * projmatrix[11] + mvmatrix[3] * projmatrix[15];
-
- clip[4] = mvmatrix[4] * projmatrix[0] + mvmatrix[5] * projmatrix[4] + mvmatrix[6] * projmatrix[8] + mvmatrix[7] * projmatrix[12];
- clip[5] = mvmatrix[4] * projmatrix[1] + mvmatrix[5] * projmatrix[5] + mvmatrix[6] * projmatrix[9] + mvmatrix[7] * projmatrix[13];
- clip[6] = mvmatrix[4] * projmatrix[2] + mvmatrix[5] * projmatrix[6] + mvmatrix[6] * projmatrix[10] + mvmatrix[7] * projmatrix[14];
- clip[7] = mvmatrix[4] * projmatrix[3] + mvmatrix[5] * projmatrix[7] + mvmatrix[6] * projmatrix[11] + mvmatrix[7] * projmatrix[15];
-
- clip[8] = mvmatrix[8] * projmatrix[0] + mvmatrix[9] * projmatrix[4] + mvmatrix[10] * projmatrix[8] + mvmatrix[11] * projmatrix[12];
- clip[9] = mvmatrix[8] * projmatrix[1] + mvmatrix[9] * projmatrix[5] + mvmatrix[10] * projmatrix[9] + mvmatrix[11] * projmatrix[13];
- clip[10] = mvmatrix[8] * projmatrix[2] + mvmatrix[9] * projmatrix[6] + mvmatrix[10] * projmatrix[10] + mvmatrix[11] * projmatrix[14];
- clip[11] = mvmatrix[8] * projmatrix[3] + mvmatrix[9] * projmatrix[7] + mvmatrix[10] * projmatrix[11] + mvmatrix[11] * projmatrix[15];
-
- clip[12] = mvmatrix[12] * projmatrix[0] + mvmatrix[13] * projmatrix[4] + mvmatrix[14] * projmatrix[8] + mvmatrix[15] * projmatrix[12];
- clip[13] = mvmatrix[12] * projmatrix[1] + mvmatrix[13] * projmatrix[5] + mvmatrix[14] * projmatrix[9] + mvmatrix[15] * projmatrix[13];
- clip[14] = mvmatrix[12] * projmatrix[2] + mvmatrix[13] * projmatrix[6] + mvmatrix[14] * projmatrix[10] + mvmatrix[15] * projmatrix[14];
- clip[15] = mvmatrix[12] * projmatrix[3] + mvmatrix[13] * projmatrix[7] + mvmatrix[14] * projmatrix[11] + mvmatrix[15] * projmatrix[15];
-
- // Right plane
- frustum[0][0] = clip[3] - clip[0];
- frustum[0][1] = clip[7] - clip[4];
- frustum[0][2] = clip[11] - clip[8];
- frustum[0][3] = clip[15] - clip[12];
-
- // Left plane
- frustum[1][0] = clip[3] + clip[0];
- frustum[1][1] = clip[7] + clip[4];
- frustum[1][2] = clip[11] + clip[8];
- frustum[1][3] = clip[15] + clip[12];
-
- // Bottom plane
- frustum[2][0] = clip[3] + clip[1];
- frustum[2][1] = clip[7] + clip[5];
- frustum[2][2] = clip[11] + clip[9];
- frustum[2][3] = clip[15] + clip[13];
-
- // Top plane
- frustum[3][0] = clip[3] - clip[1];
- frustum[3][1] = clip[7] - clip[5];
- frustum[3][2] = clip[11] - clip[9];
- frustum[3][3] = clip[15] - clip[13];
-
- // Far plane
- frustum[4][0] = clip[3] - clip[2];
- frustum[4][1] = clip[7] - clip[6];
- frustum[4][2] = clip[11] - clip[10];
- frustum[4][3] = clip[15] - clip[14];
-
- // Near plane
- frustum[5][0] = clip[3] + clip[2];
- frustum[5][1] = clip[7] + clip[6];
- frustum[5][2] = clip[11] + clip[10];
- frustum[5][3] = clip[15] + clip[14];
-}
-
-int FRUSTUM::
-CubeInFrustum(float x, float y, float z, float size)
-{
- static int c, c2;
-
- for (int i = 0; i < 6; i++) {
- c = 0;
- if (frustum[i][0] * (x - size) + frustum[i][1] * (y - size) + frustum[i][2] * (z - size) + frustum[i][3] > 0)
- c++;
- if (frustum[i][0] * (x + size) + frustum[i][1] * (y - size) + frustum[i][2] * (z - size) + frustum[i][3] > 0)
- c++;
- if (frustum[i][0] * (x - size) + frustum[i][1] * (y + size) + frustum[i][2] * (z - size) + frustum[i][3] > 0)
- c++;
- if (frustum[i][0] * (x + size) + frustum[i][1] * (y + size) + frustum[i][2] * (z - size) + frustum[i][3] > 0)
- c++;
- if (frustum[i][0] * (x - size) + frustum[i][1] * (y - size) + frustum[i][2] * (z + size) + frustum[i][3] > 0)
- c++;
- if (frustum[i][0] * (x + size) + frustum[i][1] * (y - size) + frustum[i][2] * (z + size) + frustum[i][3] > 0)
- c++;
- if (frustum[i][0] * (x - size) + frustum[i][1] * (y + size) + frustum[i][2] * (z + size) + frustum[i][3] > 0)
- c++;
- if (frustum[i][0] * (x + size) + frustum[i][1] * (y + size) + frustum[i][2] * (z + size) + frustum[i][3] > 0)
- c++;
- if (c == 0)
- return 0;
- if (c == 8)
- c2++;
- }
- if (c2 >= 6)
- return 2;
- else
- return 1;
-}
-
-int FRUSTUM::
-CubeInFrustum(float x, float y, float z, float size, float height)
-{
- static int c, c2;
-
- for (int i = 0; i < 6; i++) {
- c = 0;
- if (frustum[i][0] * (x - size) + frustum[i][1] * (y - height) + frustum[i][2] * (z - size) + frustum[i][3] > 0)
- c++;
- if (frustum[i][0] * (x + size) + frustum[i][1] * (y - height) + frustum[i][2] * (z - size) + frustum[i][3] > 0)
- c++;
- if (frustum[i][0] * (x - size) + frustum[i][1] * (y + height) + frustum[i][2] * (z - size) + frustum[i][3] > 0)
- c++;
- if (frustum[i][0] * (x + size) + frustum[i][1] * (y + height) + frustum[i][2] * (z - size) + frustum[i][3] > 0)
- c++;
- if (frustum[i][0] * (x - size) + frustum[i][1] * (y - height) + frustum[i][2] * (z + size) + frustum[i][3] > 0)
- c++;
- if (frustum[i][0] * (x + size) + frustum[i][1] * (y - height) + frustum[i][2] * (z + size) + frustum[i][3] > 0)
- c++;
- if (frustum[i][0] * (x - size) + frustum[i][1] * (y + height) + frustum[i][2] * (z + size) + frustum[i][3] > 0)
- c++;
- if (frustum[i][0] * (x + size) + frustum[i][1] * (y + height) + frustum[i][2] * (z + size) + frustum[i][3] > 0)
- c++;
- if (c == 0)
- return 0;
- if (c == 8)
- c2++;
- }
- if (c2 >= 6)
- return 2;
- else
- return 1;
-}
-
-int FRUSTUM::
-SphereInFrustum(float x, float y, float z, float radius)
-{
- static int c2;
-
- for (int i = 0; i < 6; i++) {
- if (frustum[i][0] * x + frustum[i][1] * y + frustum[i][2] * z + frustum[i][3] > -1 * radius)
- c2++;
- else
- return 0;
- }
- if (c2 >= 6)
- return 2;
- else
- return 1;
-}
+++ /dev/null
-/*
-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 FRUSTUM_H
-#define FRUSTUM_H
-
-class FRUSTUM
-{
-public:
- float frustum[6][4];
- void GetFrustum();
- int CubeInFrustum(float, float, float, float);
- int CubeInFrustum(float, float, float, float, float);
- int SphereInFrustum(float, float, float, float);
-};
-
-#endif
along with Lugaru. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "Game.h"
-#include "openal_wrapper.h"
#include "SDL_thread.h"
-#include "Dialog.h"
+#include "Game.h"
+#include "Audio/openal_wrapper.h"
+#include "Level/Dialog.h"
+
extern int mainmenu;
#include "SDL.h"
-#include "ImageIO.h"
-
-#include "Terrain.h"
-#include "Skybox.h"
#include "Animation/Skeleton.h"
-#include "Models.h"
-#include "Lights.h"
-#include "Person.h"
-#include "Sprite.h"
-#include "Text.h"
-#include "Objects.h"
-#include "Weapons.h"
-#include "binio.h"
+#include "Audio/Sounds.h"
+#include "Environment/Lights.h"
+#include "Environment/Skybox.h"
+#include "Environment/Terrain.h"
+#include "Graphic/gamegl.h"
+#include "Graphic/Models.h"
+#include "Graphic/Sprite.h"
+#include "Graphic/Stereo.h"
+#include "Graphic/Text.h"
+#include "Graphic/Texture.h"
+#include "Objects/Objects.h"
+#include "Objects/Person.h"
+#include "Objects/Weapons.h"
+#include "Thirdparty/optionparser.h"
+#include "User/Account.h"
+#include "Utils/binio.h"
+#include "Utils/ImageIO.h"
+
#include <fstream>
-#include "gamegl.h"
-#include "Stereo.h"
-#include "Account.h"
-#include "Sounds.h"
-#include "Texture.h"
-#include "optionparser.h"
#define NB_CAMPAIGN_MENU_ITEM 7
*/
#include "Game.h"
-#include "openal_wrapper.h"
-#include "Input.h"
-#include "Awards.h"
-#include "Menu.h"
-#include "Dialog.h"
-#include "Hotspot.h"
+#include "Audio/openal_wrapper.h"
+#include "Level/Awards.h"
+#include "Level/Dialog.h"
+#include "Level/Hotspot.h"
+#include "Menu/Menu.h"
+#include "Utils/Input.h"
extern XYZ viewer;
extern int environment;
*/
#include "Game.h"
-#include "openal_wrapper.h"
#include "Animation/Animation.h"
-#include "Texture.h"
+#include "Audio/openal_wrapper.h"
+#include "Graphic/Texture.h"
+#include "Menu/Menu.h"
#include "Utils/Folders.h"
-#include "Menu.h"
extern float screenwidth, screenheight;
extern float viewdistance;
#include <cmath>
#include <dirent.h>
#include "Game.h"
-#include "openal_wrapper.h"
-#include "Settings.h"
-#include "Input.h"
#include "Animation/Animation.h"
-#include "Awards.h"
-#include "Menu.h"
-#include "ConsoleCmds.h"
-#include "Dialog.h"
+#include "Audio/openal_wrapper.h"
+#include "Devtools/ConsoleCmds.h"
+#include "Level/Awards.h"
+#include "Level/Campaign.h"
+#include "Level/Dialog.h"
+#include "Level/Hotspot.h"
+#include "Menu/Menu.h"
+#include "User/Settings.h"
#include "Utils/Folders.h"
-#include "Hotspot.h"
-#include "Campaign.h"
+#include "Utils/Input.h"
#include <algorithm>
#include <set>
#include "SDL.h"
-#include "gamegl.h"
-#include "Quaternions.h"
-#include "Lights.h"
-#include "Animation/Animation.h"
-#include "Animation/Skeleton.h"
-#include "Terrain.h"
-#include "Sprite.h"
-#include "Frustum.h"
-#include "Objects.h"
-#include "Weapons.h"
-#include "Person.h"
-#include "ImageIO.h"
-#include "openal_wrapper.h"
-#include "Stereo.h"
+#include <string>
+#include "Graphic/Stereo.h"
+#include "Math/Quaternions.h"
+#include "Objects/Weapons.h"
bool visibleloading = 0;
--- /dev/null
+/*
+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/>.
+*/
+
+#include "Game.h"
+#include "Graphic/Models.h"
+#include "Utils/Folders.h"
+
+extern float multiplier;
+extern float viewdistance;
+extern XYZ viewer;
+extern float fadestart;
+extern float texdetail;
+extern bool decals;
+
+extern bool visibleloading;
+
+int Model::LineCheck(XYZ *p1, XYZ *p2, XYZ *p, XYZ *move, float *rotate)
+{
+ static int j;
+ static float distance;
+ static float olddistance;
+ static int intersecting;
+ static int firstintersecting;
+ static XYZ point;
+
+ *p1 = *p1 - *move;
+ *p2 = *p2 - *move;
+ if (*rotate)
+ *p1 = DoRotation(*p1, 0, -*rotate, 0);
+ if (*rotate)
+ *p2 = DoRotation(*p2, 0, -*rotate, 0);
+ if (!sphere_line_intersection(p1, p2, &boundingspherecenter, &boundingsphereradius))
+ return -1;
+ firstintersecting = -1;
+
+ for (j = 0; j < TriangleNum; j++) {
+ intersecting = LineFacetd(p1, p2, &vertex[Triangles[j].vertex[0]], &vertex[Triangles[j].vertex[1]], &vertex[Triangles[j].vertex[2]], &facenormals[j], &point);
+ distance = (point.x - p1->x) * (point.x - p1->x) + (point.y - p1->y) * (point.y - p1->y) + (point.z - p1->z) * (point.z - p1->z);
+ if ((distance < olddistance || firstintersecting == -1) && intersecting) {
+ olddistance = distance;
+ firstintersecting = j;
+ *p = point;
+ }
+ }
+
+ if (*rotate)
+ *p = DoRotation(*p, 0, *rotate, 0);
+ *p = *p + *move;
+ return firstintersecting;
+}
+
+int Model::LineCheckPossible(XYZ *p1, XYZ *p2, XYZ *p, XYZ *move, float *rotate)
+{
+ static int j;
+ static float distance;
+ static float olddistance;
+ static int intersecting;
+ static int firstintersecting;
+ static XYZ point;
+
+ *p1 = *p1 - *move;
+ *p2 = *p2 - *move;
+ if (!sphere_line_intersection(p1, p2, &boundingspherecenter, &boundingsphereradius))
+ return -1;
+ firstintersecting = -1;
+ if (*rotate)
+ *p1 = DoRotation(*p1, 0, -*rotate, 0);
+ if (*rotate)
+ *p2 = DoRotation(*p2, 0, -*rotate, 0);
+
+ if (numpossible > 0 && numpossible < TriangleNum)
+ for (j = 0; j < numpossible; j++) {
+ if (possible[j] >= 0 && possible[j] < TriangleNum) {
+ intersecting = LineFacetd(p1, p2, &vertex[Triangles[possible[j]].vertex[0]], &vertex[Triangles[possible[j]].vertex[1]], &vertex[Triangles[possible[j]].vertex[2]], &facenormals[possible[j]], &point);
+ distance = (point.x - p1->x) * (point.x - p1->x) + (point.y - p1->y) * (point.y - p1->y) + (point.z - p1->z) * (point.z - p1->z);
+ if ((distance < olddistance || firstintersecting == -1) && intersecting) {
+ olddistance = distance;
+ firstintersecting = possible[j];
+ *p = point;
+ }
+ }
+ }
+
+ if (*rotate)
+ *p = DoRotation(*p, 0, *rotate, 0);
+ *p = *p + *move;
+ return firstintersecting;
+}
+
+int Model::LineCheckSlidePossible(XYZ *p1, XYZ *p2, XYZ *p, XYZ *move, float *rotate)
+{
+ static int j;
+ static float distance;
+ static float olddistance;
+ static int intersecting;
+ static int firstintersecting;
+ static XYZ point;
+
+ *p1 = *p1 - *move;
+ *p2 = *p2 - *move;
+ if (!sphere_line_intersection(p1, p2, &boundingspherecenter, &boundingsphereradius))
+ return -1;
+ firstintersecting = -1;
+ if (*rotate)
+ *p1 = DoRotation(*p1, 0, -*rotate, 0);
+ if (*rotate)
+ *p2 = DoRotation(*p2, 0, -*rotate, 0);
+
+ if (numpossible)
+ for (j = 0; j < numpossible; j++) {
+ if (possible[j] >= 0 && possible[j] < TriangleNum) {
+ intersecting = LineFacetd(p1, p2, &vertex[Triangles[possible[j]].vertex[0]], &vertex[Triangles[possible[j]].vertex[1]], &vertex[Triangles[possible[j]].vertex[2]], &facenormals[possible[j]], &point);
+ distance = (point.x - p1->x) * (point.x - p1->x) + (point.y - p1->y) * (point.y - p1->y) + (point.z - p1->z) * (point.z - p1->z);
+ if ((distance < olddistance || firstintersecting == -1) && intersecting) {
+ olddistance = distance;
+ firstintersecting = possible[j];
+ }
+ }
+ }
+
+ if (firstintersecting > 0) {
+ distance = abs((facenormals[firstintersecting].x * p2->x) + (facenormals[firstintersecting].y * p2->y) + (facenormals[firstintersecting].z * p2->z) - ((facenormals[firstintersecting].x * vertex[Triangles[firstintersecting].vertex[0]].x) + (facenormals[firstintersecting].y * vertex[Triangles[firstintersecting].vertex[0]].y) + (facenormals[firstintersecting].z * vertex[Triangles[firstintersecting].vertex[0]].z)));
+ *p2 -= facenormals[firstintersecting] * distance;
+ }
+
+ if (*rotate)
+ *p2 = DoRotation(*p2, 0, *rotate, 0);
+ *p2 = *p2 + *move;
+ return firstintersecting;
+}
+
+int Model::SphereCheck(XYZ *p1, float radius, XYZ *p, XYZ *move, float *rotate)
+{
+ static int i, j;
+ static float distance;
+ static float olddistance;
+ static int intersecting;
+ static int firstintersecting;
+ static XYZ point;
+ static XYZ oldp1;
+
+ firstintersecting = -1;
+
+ oldp1 = *p1;
+ *p1 = *p1 - *move;
+ if (*rotate)
+ *p1 = DoRotation(*p1, 0, -*rotate, 0);
+ if (distsq(p1, &boundingspherecenter) > radius * radius + boundingsphereradius * boundingsphereradius)
+ return -1;
+
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < TriangleNum; j++) {
+ intersecting = 0;
+ distance = abs((facenormals[j].x * p1->x) + (facenormals[j].y * p1->y) + (facenormals[j].z * p1->z) - ((facenormals[j].x * vertex[Triangles[j].vertex[0]].x) + (facenormals[j].y * vertex[Triangles[j].vertex[0]].y) + (facenormals[j].z * vertex[Triangles[j].vertex[0]].z)));
+ if (distance < radius) {
+ point = *p1 - facenormals[j] * distance;
+ if (PointInTriangle( &point, facenormals[j], &vertex[Triangles[j].vertex[0]], &vertex[Triangles[j].vertex[1]], &vertex[Triangles[j].vertex[2]]))
+ intersecting = 1;
+ if (!intersecting)
+ intersecting = sphere_line_intersection(&vertex[Triangles[j].vertex[0]], &vertex[Triangles[j].vertex[1]], p1, &radius);
+ if (!intersecting)
+ intersecting = sphere_line_intersection(&vertex[Triangles[j].vertex[1]], &vertex[Triangles[j].vertex[2]], p1, &radius);
+ if (!intersecting)
+ intersecting = sphere_line_intersection(&vertex[Triangles[j].vertex[0]], &vertex[Triangles[j].vertex[2]], p1, &radius);
+ if (intersecting) {
+ *p1 += facenormals[j] * (distance - radius);
+ }
+ }
+ if ((distance < olddistance || firstintersecting == -1) && intersecting) {
+ olddistance = distance;
+ firstintersecting = j;
+ *p = point;
+ }
+ }
+ }
+ if (*rotate)
+ *p = DoRotation(*p, 0, *rotate, 0);
+ *p = *p + *move;
+ if (*rotate)
+ *p1 = DoRotation(*p1, 0, *rotate, 0);
+ *p1 += *move;
+ return firstintersecting;
+}
+
+int Model::SphereCheckPossible(XYZ *p1, float radius, XYZ *move, float *rotate)
+{
+ static int j;
+ static float distance;
+ static float olddistance;
+ static int intersecting;
+ static int firstintersecting;
+ static XYZ point;
+ static XYZ oldp1;
+
+ firstintersecting = -1;
+
+ oldp1 = *p1;
+ *p1 = *p1 - *move;
+
+ numpossible = 0;
+
+ if (*rotate)
+ *p1 = DoRotation(*p1, 0, -*rotate, 0);
+ if (distsq(p1, &boundingspherecenter) > radius * radius + boundingsphereradius * boundingsphereradius) {
+ *p1 = oldp1;
+ return -1;
+ }
+
+ for (j = 0; j < TriangleNum; j++) {
+ intersecting = 0;
+ distance = abs((facenormals[j].x * p1->x) + (facenormals[j].y * p1->y) + (facenormals[j].z * p1->z) - ((facenormals[j].x * vertex[Triangles[j].vertex[0]].x) + (facenormals[j].y * vertex[Triangles[j].vertex[0]].y) + (facenormals[j].z * vertex[Triangles[j].vertex[0]].z)));
+ if (distance < radius) {
+ point = *p1 - facenormals[j] * distance;
+ if (PointInTriangle( &point, facenormals[j], &vertex[Triangles[j].vertex[0]], &vertex[Triangles[j].vertex[1]], &vertex[Triangles[j].vertex[2]]))
+ intersecting = 1;
+ if (!intersecting)
+ intersecting = sphere_line_intersection(&vertex[Triangles[j].vertex[0]], &vertex[Triangles[j].vertex[1]], p1, &radius);
+ if (!intersecting)
+ intersecting = sphere_line_intersection(&vertex[Triangles[j].vertex[1]], &vertex[Triangles[j].vertex[2]], p1, &radius);
+ if (!intersecting)
+ intersecting = sphere_line_intersection(&vertex[Triangles[j].vertex[0]], &vertex[Triangles[j].vertex[2]], p1, &radius);
+ if (intersecting) {
+ possible[numpossible] = j;
+ numpossible++;
+ }
+ }
+ if ((distance < olddistance || firstintersecting == -1) && intersecting) {
+ olddistance = distance;
+ firstintersecting = j;
+ }
+ }
+ if (*rotate)
+ *p1 = DoRotation(*p1, 0, *rotate, 0);
+ *p1 += *move;
+ return firstintersecting;
+}
+
+
+void Model::UpdateVertexArray()
+{
+ if (type != normaltype && type != decalstype)
+ return;
+ static int i;
+ static int j;
+ if (!flat)
+ for (i = 0; i < TriangleNum; i++) {
+ j = i * 24;
+ vArray[j + 0] = Triangles[i].gx[0];
+ vArray[j + 1] = Triangles[i].gy[0];
+ vArray[j + 2] = normals[Triangles[i].vertex[0]].x;
+ vArray[j + 3] = normals[Triangles[i].vertex[0]].y;
+ vArray[j + 4] = normals[Triangles[i].vertex[0]].z;
+ vArray[j + 5] = vertex[Triangles[i].vertex[0]].x;
+ vArray[j + 6] = vertex[Triangles[i].vertex[0]].y;
+ vArray[j + 7] = vertex[Triangles[i].vertex[0]].z;
+
+ vArray[j + 8] = Triangles[i].gx[1];
+ vArray[j + 9] = Triangles[i].gy[1];
+ vArray[j + 10] = normals[Triangles[i].vertex[1]].x;
+ vArray[j + 11] = normals[Triangles[i].vertex[1]].y;
+ vArray[j + 12] = normals[Triangles[i].vertex[1]].z;
+ vArray[j + 13] = vertex[Triangles[i].vertex[1]].x;
+ vArray[j + 14] = vertex[Triangles[i].vertex[1]].y;
+ vArray[j + 15] = vertex[Triangles[i].vertex[1]].z;
+
+ vArray[j + 16] = Triangles[i].gx[2];
+ vArray[j + 17] = Triangles[i].gy[2];
+ vArray[j + 18] = normals[Triangles[i].vertex[2]].x;
+ vArray[j + 19] = normals[Triangles[i].vertex[2]].y;
+ vArray[j + 20] = normals[Triangles[i].vertex[2]].z;
+ vArray[j + 21] = vertex[Triangles[i].vertex[2]].x;
+ vArray[j + 22] = vertex[Triangles[i].vertex[2]].y;
+ vArray[j + 23] = vertex[Triangles[i].vertex[2]].z;
+ }
+ if (flat)
+ for (i = 0; i < TriangleNum; i++) {
+ j = i * 24;
+ vArray[j + 0] = Triangles[i].gx[0];
+ vArray[j + 1] = Triangles[i].gy[0];
+ vArray[j + 2] = facenormals[i].x * -1;
+ vArray[j + 3] = facenormals[i].y * -1;
+ vArray[j + 4] = facenormals[i].z * -1;
+ vArray[j + 5] = vertex[Triangles[i].vertex[0]].x;
+ vArray[j + 6] = vertex[Triangles[i].vertex[0]].y;
+ vArray[j + 7] = vertex[Triangles[i].vertex[0]].z;
+
+ vArray[j + 8] = Triangles[i].gx[1];
+ vArray[j + 9] = Triangles[i].gy[1];
+ vArray[j + 10] = facenormals[i].x * -1;
+ vArray[j + 11] = facenormals[i].y * -1;
+ vArray[j + 12] = facenormals[i].z * -1;
+ vArray[j + 13] = vertex[Triangles[i].vertex[1]].x;
+ vArray[j + 14] = vertex[Triangles[i].vertex[1]].y;
+ vArray[j + 15] = vertex[Triangles[i].vertex[1]].z;
+
+ vArray[j + 16] = Triangles[i].gx[2];
+ vArray[j + 17] = Triangles[i].gy[2];
+ vArray[j + 18] = facenormals[i].x * -1;
+ vArray[j + 19] = facenormals[i].y * -1;
+ vArray[j + 20] = facenormals[i].z * -1;
+ vArray[j + 21] = vertex[Triangles[i].vertex[2]].x;
+ vArray[j + 22] = vertex[Triangles[i].vertex[2]].y;
+ vArray[j + 23] = vertex[Triangles[i].vertex[2]].z;
+
+ }
+}
+
+void Model::UpdateVertexArrayNoTex()
+{
+ if (type != normaltype && type != decalstype)
+ return;
+ static int i;
+ static int j;
+ if (!flat)
+ for (i = 0; i < TriangleNum; i++) {
+ j = i * 24;
+ vArray[j + 2] = normals[Triangles[i].vertex[0]].x;
+ vArray[j + 3] = normals[Triangles[i].vertex[0]].y;
+ vArray[j + 4] = normals[Triangles[i].vertex[0]].z;
+ vArray[j + 5] = vertex[Triangles[i].vertex[0]].x;
+ vArray[j + 6] = vertex[Triangles[i].vertex[0]].y;
+ vArray[j + 7] = vertex[Triangles[i].vertex[0]].z;
+
+ vArray[j + 10] = normals[Triangles[i].vertex[1]].x;
+ vArray[j + 11] = normals[Triangles[i].vertex[1]].y;
+ vArray[j + 12] = normals[Triangles[i].vertex[1]].z;
+ vArray[j + 13] = vertex[Triangles[i].vertex[1]].x;
+ vArray[j + 14] = vertex[Triangles[i].vertex[1]].y;
+ vArray[j + 15] = vertex[Triangles[i].vertex[1]].z;
+
+ vArray[j + 18] = normals[Triangles[i].vertex[2]].x;
+ vArray[j + 19] = normals[Triangles[i].vertex[2]].y;
+ vArray[j + 20] = normals[Triangles[i].vertex[2]].z;
+ vArray[j + 21] = vertex[Triangles[i].vertex[2]].x;
+ vArray[j + 22] = vertex[Triangles[i].vertex[2]].y;
+ vArray[j + 23] = vertex[Triangles[i].vertex[2]].z;
+ }
+ if (flat)
+ for (i = 0; i < TriangleNum; i++) {
+ j = i * 24;
+ vArray[j + 2] = facenormals[i].x * -1;
+ vArray[j + 3] = facenormals[i].y * -1;
+ vArray[j + 4] = facenormals[i].z * -1;
+ vArray[j + 5] = vertex[Triangles[i].vertex[0]].x;
+ vArray[j + 6] = vertex[Triangles[i].vertex[0]].y;
+ vArray[j + 7] = vertex[Triangles[i].vertex[0]].z;
+
+ vArray[j + 10] = facenormals[i].x * -1;
+ vArray[j + 11] = facenormals[i].y * -1;
+ vArray[j + 12] = facenormals[i].z * -1;
+ vArray[j + 13] = vertex[Triangles[i].vertex[1]].x;
+ vArray[j + 14] = vertex[Triangles[i].vertex[1]].y;
+ vArray[j + 15] = vertex[Triangles[i].vertex[1]].z;
+
+ vArray[j + 18] = facenormals[i].x * -1;
+ vArray[j + 19] = facenormals[i].y * -1;
+ vArray[j + 20] = facenormals[i].z * -1;
+ vArray[j + 21] = vertex[Triangles[i].vertex[2]].x;
+ vArray[j + 22] = vertex[Triangles[i].vertex[2]].y;
+ vArray[j + 23] = vertex[Triangles[i].vertex[2]].z;
+ }
+}
+
+void Model::UpdateVertexArrayNoTexNoNorm()
+{
+ if (type != normaltype && type != decalstype)
+ return;
+ static int i;
+ static int j;
+ for (i = 0; i < TriangleNum; i++) {
+ j = i * 24;
+ vArray[j + 5] = vertex[Triangles[i].vertex[0]].x;
+ vArray[j + 6] = vertex[Triangles[i].vertex[0]].y;
+ vArray[j + 7] = vertex[Triangles[i].vertex[0]].z;
+
+ vArray[j + 13] = vertex[Triangles[i].vertex[1]].x;
+ vArray[j + 14] = vertex[Triangles[i].vertex[1]].y;
+ vArray[j + 15] = vertex[Triangles[i].vertex[1]].z;
+
+ vArray[j + 21] = vertex[Triangles[i].vertex[2]].x;
+ vArray[j + 22] = vertex[Triangles[i].vertex[2]].y;
+ vArray[j + 23] = vertex[Triangles[i].vertex[2]].z;
+ }
+}
+
+bool Model::loadnotex(const std::string& filename )
+{
+ FILE *tfile;
+ long i;
+
+ type = notextype;
+ color = 0;
+
+ tfile = Folders::openMandatoryFile( Folders::getResourcePath(filename), "rb" );
+
+ // read model settings
+
+ fseek(tfile, 0, SEEK_SET);
+ funpackf(tfile, "Bs Bs", &vertexNum, &TriangleNum);
+
+ // read the model data
+ deallocate();
+
+ numpossible = 0;
+
+ owner = (int*)malloc(sizeof(int) * vertexNum);
+ possible = (int*)malloc(sizeof(int) * TriangleNum);
+ vertex = (XYZ*)malloc(sizeof(XYZ) * vertexNum);
+ Triangles = (TexturedTriangle*)malloc(sizeof(TexturedTriangle) * TriangleNum);
+ vArray = (GLfloat*)malloc(sizeof(GLfloat) * TriangleNum * 24);
+
+ for (i = 0; i < vertexNum; i++) {
+ funpackf(tfile, "Bf Bf Bf", &vertex[i].x, &vertex[i].y, &vertex[i].z);
+ }
+
+ for (i = 0; i < TriangleNum; i++) {
+ short vertex[ 6];
+ funpackf(tfile, "Bs Bs Bs Bs Bs Bs", &vertex[ 0], &vertex[ 1], &vertex[ 2], &vertex[ 3], &vertex[ 4], &vertex[ 5]);
+ Triangles[i].vertex[ 0] = vertex[ 0];
+ Triangles[i].vertex[ 1] = vertex[ 2];
+ Triangles[i].vertex[ 2] = vertex[ 4];
+ funpackf(tfile, "Bf Bf Bf", &Triangles[i].gx[0], &Triangles[i].gx[1], &Triangles[i].gx[2]);
+ funpackf(tfile, "Bf Bf Bf", &Triangles[i].gy[0], &Triangles[i].gy[1], &Triangles[i].gy[2]);
+ }
+
+ fclose(tfile);
+
+ UpdateVertexArray();
+
+ for (i = 0; i < vertexNum; i++) {
+ owner[i] = -1;
+ }
+
+ static int j;
+ boundingsphereradius = 0;
+ for (i = 0; i < vertexNum; i++) {
+ for (j = 0; j < vertexNum; j++) {
+ if (j != i && distsq(&vertex[j], &vertex[i]) / 2 > boundingsphereradius) {
+ boundingsphereradius = distsq(&vertex[j], &vertex[i]) / 2;
+ boundingspherecenter = (vertex[i] + vertex[j]) / 2;
+ }
+ }
+ }
+ boundingsphereradius = fast_sqrt(boundingsphereradius);
+
+ return true;
+}
+
+
+bool Model::load(const std::string& filename, bool texture )
+{
+ FILE *tfile;
+ long i;
+
+ LOGFUNC;
+
+ LOG(std::string("Loading model...") + filename);
+
+ if (visibleloading)
+ Game::LoadingScreen();
+
+ type = normaltype;
+ color = 0;
+
+ tfile = Folders::openMandatoryFile( Folders::getResourcePath(filename), "rb" );
+
+ // read model settings
+
+ fseek(tfile, 0, SEEK_SET);
+ funpackf(tfile, "Bs Bs", &vertexNum, &TriangleNum);
+
+ // read the model data
+ deallocate();
+
+ numpossible = 0;
+
+ owner = (int*)malloc(sizeof(int) * vertexNum);
+ possible = (int*)malloc(sizeof(int) * TriangleNum);
+ vertex = (XYZ*)malloc(sizeof(XYZ) * vertexNum);
+ normals = (XYZ*)malloc(sizeof(XYZ) * vertexNum);
+ facenormals = (XYZ*)malloc(sizeof(XYZ) * TriangleNum);
+ Triangles = (TexturedTriangle*)malloc(sizeof(TexturedTriangle) * TriangleNum);
+ vArray = (GLfloat*)malloc(sizeof(GLfloat) * TriangleNum * 24);
+
+ for (i = 0; i < vertexNum; i++) {
+ funpackf(tfile, "Bf Bf Bf", &vertex[i].x, &vertex[i].y, &vertex[i].z);
+ }
+
+ for (i = 0; i < TriangleNum; i++) {
+ short vertex[ 6];
+ funpackf(tfile, "Bs Bs Bs Bs Bs Bs", &vertex[ 0], &vertex[ 1], &vertex[ 2], &vertex[ 3], &vertex[ 4], &vertex[ 5]);
+ Triangles[i].vertex[ 0] = vertex[ 0];
+ Triangles[i].vertex[ 1] = vertex[ 2];
+ Triangles[i].vertex[ 2] = vertex[ 4];
+ funpackf(tfile, "Bf Bf Bf", &Triangles[i].gx[0], &Triangles[i].gx[1], &Triangles[i].gx[2]);
+ funpackf(tfile, "Bf Bf Bf", &Triangles[i].gy[0], &Triangles[i].gy[1], &Triangles[i].gy[2]);
+ }
+
+ modelTexture.xsz = 0;
+
+ fclose(tfile);
+
+ UpdateVertexArray();
+
+ for (i = 0; i < vertexNum; i++) {
+ owner[i] = -1;
+ }
+
+ static int j;
+ boundingsphereradius = 0;
+ for (i = 0; i < vertexNum; i++) {
+ for (j = 0; j < vertexNum; j++) {
+ if (j != i && distsq(&vertex[j], &vertex[i]) / 2 > boundingsphereradius) {
+ boundingsphereradius = distsq(&vertex[j], &vertex[i]) / 2;
+ boundingspherecenter = (vertex[i] + vertex[j]) / 2;
+ }
+ }
+ }
+ boundingsphereradius = fast_sqrt(boundingsphereradius);
+
+ return true;
+}
+
+bool Model::loaddecal(const std::string& filename, bool texture )
+{
+ FILE *tfile;
+ long i, j;
+
+ LOGFUNC;
+
+ LOG(std::string("Loading decal...") + Folders::getResourcePath(filename));
+
+ type = decalstype;
+ numdecals = 0;
+ color = 0;
+
+ tfile = Folders::openMandatoryFile( Folders::getResourcePath(filename), "rb" );
+
+ // read model settings
+
+ fseek(tfile, 0, SEEK_SET);
+ funpackf(tfile, "Bs Bs", &vertexNum, &TriangleNum);
+
+ // read the model data
+
+ deallocate();
+
+ numpossible = 0;
+
+ owner = (int*)malloc(sizeof(int) * vertexNum);
+ possible = (int*)malloc(sizeof(int) * TriangleNum);
+ vertex = (XYZ*)malloc(sizeof(XYZ) * vertexNum);
+ normals = (XYZ*)malloc(sizeof(XYZ) * vertexNum);
+ facenormals = (XYZ*)malloc(sizeof(XYZ) * TriangleNum);
+ Triangles = (TexturedTriangle*)malloc(sizeof(TexturedTriangle) * TriangleNum);
+ vArray = (GLfloat*)malloc(sizeof(GLfloat) * TriangleNum * 24);
+
+
+ for (i = 0; i < vertexNum; i++) {
+ funpackf(tfile, "Bf Bf Bf", &vertex[i].x, &vertex[i].y, &vertex[i].z);
+ }
+
+ for (i = 0; i < TriangleNum; i++) {
+ short vertex[ 6];
+ funpackf(tfile, "Bs Bs Bs Bs Bs Bs", &vertex[ 0], &vertex[ 1], &vertex[ 2], &vertex[ 3], &vertex[ 4], &vertex[ 5]);
+ Triangles[i].vertex[ 0] = vertex[ 0];
+ Triangles[i].vertex[ 1] = vertex[ 2];
+ Triangles[i].vertex[ 2] = vertex[ 4];
+ funpackf(tfile, "Bf Bf Bf", &Triangles[i].gx[0], &Triangles[i].gx[1], &Triangles[i].gx[2]);
+ funpackf(tfile, "Bf Bf Bf", &Triangles[i].gy[0], &Triangles[i].gy[1], &Triangles[i].gy[2]);
+ }
+
+
+ modelTexture.xsz = 0;
+
+ fclose(tfile);
+
+ UpdateVertexArray();
+
+ for (i = 0; i < vertexNum; i++) {
+ owner[i] = -1;
+ }
+
+ boundingsphereradius = 0;
+ for (i = 0; i < vertexNum; i++) {
+ for (j = 0; j < vertexNum; j++) {
+ if (j != i && distsq(&vertex[j], &vertex[i]) / 2 > boundingsphereradius) {
+ boundingsphereradius = distsq(&vertex[j], &vertex[i]) / 2;
+ boundingspherecenter = (vertex[i] + vertex[j]) / 2;
+ }
+ }
+ }
+ boundingsphereradius = fast_sqrt(boundingsphereradius);
+
+ //allow decals
+ if (!decaltexcoords) {
+ decaltexcoords = (float***)malloc(sizeof(float**)*max_model_decals);
+ for (i = 0; i < max_model_decals; i++) {
+ decaltexcoords[i] = (float**)malloc(sizeof(float*) * 3);
+ for (j = 0; j < 3; j++) {
+ decaltexcoords[i][j] = (float*)malloc(sizeof(float) * 2);
+ }
+ }
+ decalvertex = (XYZ**)malloc(sizeof(XYZ*)*max_model_decals);
+ for (i = 0; i < max_model_decals; i++) {
+ decalvertex[i] = (XYZ*)malloc(sizeof(XYZ) * 3);
+ }
+
+ decaltype = (int*)malloc(sizeof(int) * max_model_decals);
+ decalopacity = (float*)malloc(sizeof(float) * max_model_decals);
+ decalrotation = (float*)malloc(sizeof(float) * max_model_decals);
+ decalalivetime = (float*)malloc(sizeof(float) * max_model_decals);
+ decalposition = (XYZ*)malloc(sizeof(XYZ) * max_model_decals);
+ }
+
+ return true;
+}
+
+bool Model::loadraw(const std::string& filename)
+{
+ FILE *tfile;
+ long i;
+
+ LOGFUNC;
+
+ LOG(std::string("Loading raw...") + filename);
+
+ type = rawtype;
+ color = 0;
+
+ tfile = Folders::openMandatoryFile( Folders::getResourcePath(filename), "rb" );
+
+ // read model settings
+
+ fseek(tfile, 0, SEEK_SET);
+ funpackf(tfile, "Bs Bs", &vertexNum, &TriangleNum);
+
+ // read the model data
+ deallocate();
+
+ numpossible = 0;
+
+ owner = (int*)malloc(sizeof(int) * vertexNum);
+ possible = (int*)malloc(sizeof(int) * TriangleNum);
+ vertex = (XYZ*)malloc(sizeof(XYZ) * vertexNum);
+ Triangles = (TexturedTriangle*)malloc(sizeof(TexturedTriangle) * TriangleNum);
+ vArray = (GLfloat*)malloc(sizeof(GLfloat) * TriangleNum * 24);
+
+
+ for (i = 0; i < vertexNum; i++) {
+ funpackf(tfile, "Bf Bf Bf", &vertex[i].x, &vertex[i].y, &vertex[i].z);
+ }
+
+ for (i = 0; i < TriangleNum; i++) {
+ short vertex[ 6];
+ funpackf(tfile, "Bs Bs Bs Bs Bs Bs", &vertex[ 0], &vertex[ 1], &vertex[ 2], &vertex[ 3], &vertex[ 4], &vertex[ 5]);
+ Triangles[i].vertex[ 0] = vertex[ 0];
+ Triangles[i].vertex[ 1] = vertex[ 2];
+ Triangles[i].vertex[ 2] = vertex[ 4];
+ funpackf(tfile, "Bf Bf Bf", &Triangles[i].gx[0], &Triangles[i].gx[1], &Triangles[i].gx[2]);
+ funpackf(tfile, "Bf Bf Bf", &Triangles[i].gy[0], &Triangles[i].gy[1], &Triangles[i].gy[2]);
+ }
+
+
+ fclose(tfile);
+
+ for (i = 0; i < vertexNum; i++) {
+ owner[i] = -1;
+ }
+
+ return true;
+}
+
+
+void Model::UniformTexCoords()
+{
+ static int i;
+ for (i = 0; i < TriangleNum; i++) {
+ Triangles[i].gy[0] = vertex[Triangles[i].vertex[0]].y;
+ Triangles[i].gy[1] = vertex[Triangles[i].vertex[1]].y;
+ Triangles[i].gy[2] = vertex[Triangles[i].vertex[2]].y;
+ Triangles[i].gx[0] = vertex[Triangles[i].vertex[0]].x;
+ Triangles[i].gx[1] = vertex[Triangles[i].vertex[1]].x;
+ Triangles[i].gx[2] = vertex[Triangles[i].vertex[2]].x;
+ }
+ UpdateVertexArray();
+}
+
+
+void Model::FlipTexCoords()
+{
+ static int i;
+ for (i = 0; i < TriangleNum; i++) {
+ Triangles[i].gy[0] = -Triangles[i].gy[0];
+ Triangles[i].gy[1] = -Triangles[i].gy[1];
+ Triangles[i].gy[2] = -Triangles[i].gy[2];
+ }
+ UpdateVertexArray();
+}
+
+void Model::ScaleTexCoords(float howmuch)
+{
+ static int i;
+ for (i = 0; i < TriangleNum; i++) {
+ Triangles[i].gx[0] *= howmuch;
+ Triangles[i].gx[1] *= howmuch;
+ Triangles[i].gx[2] *= howmuch;
+ Triangles[i].gy[0] *= howmuch;
+ Triangles[i].gy[1] *= howmuch;
+ Triangles[i].gy[2] *= howmuch;
+ }
+ UpdateVertexArray();
+}
+
+void Model::Scale(float xscale, float yscale, float zscale)
+{
+ static int i;
+ for (i = 0; i < vertexNum; i++) {
+ vertex[i].x *= xscale;
+ vertex[i].y *= yscale;
+ vertex[i].z *= zscale;
+ }
+ UpdateVertexArray();
+
+ static int j;
+
+ boundingsphereradius = 0;
+ for (i = 0; i < vertexNum; i++) {
+ for (j = 0; j < vertexNum; j++) {
+ if (j != i && distsq(&vertex[j], &vertex[i]) / 2 > boundingsphereradius) {
+ boundingsphereradius = distsq(&vertex[j], &vertex[i]) / 2;
+ boundingspherecenter = (vertex[i] + vertex[j]) / 2;
+ }
+ }
+ }
+ boundingsphereradius = fast_sqrt(boundingsphereradius);
+}
+
+void Model::ScaleNormals(float xscale, float yscale, float zscale)
+{
+ if (type != normaltype && type != decalstype)
+ return;
+ static int i;
+ for (i = 0; i < vertexNum; i++) {
+ normals[i].x *= xscale;
+ normals[i].y *= yscale;
+ normals[i].z *= zscale;
+ }
+ for (i = 0; i < TriangleNum; i++) {
+ facenormals[i].x *= xscale;
+ facenormals[i].y *= yscale;
+ facenormals[i].z *= zscale;
+ }
+ UpdateVertexArray();
+}
+
+void Model::Translate(float xtrans, float ytrans, float ztrans)
+{
+ static int i;
+ for (i = 0; i < vertexNum; i++) {
+ vertex[i].x += xtrans;
+ vertex[i].y += ytrans;
+ vertex[i].z += ztrans;
+ }
+ UpdateVertexArray();
+
+ static int j;
+ boundingsphereradius = 0;
+ for (i = 0; i < vertexNum; i++) {
+ for (j = 0; j < vertexNum; j++) {
+ if (j != i && distsq(&vertex[j], &vertex[i]) / 2 > boundingsphereradius) {
+ boundingsphereradius = distsq(&vertex[j], &vertex[i]) / 2;
+ boundingspherecenter = (vertex[i] + vertex[j]) / 2;
+ }
+ }
+ }
+ boundingsphereradius = fast_sqrt(boundingsphereradius);
+}
+
+void Model::Rotate(float xang, float yang, float zang)
+{
+ static int i;
+ for (i = 0; i < vertexNum; i++) {
+ vertex[i] = DoRotation(vertex[i], xang, yang, zang);
+ }
+ UpdateVertexArray();
+
+ static int j;
+ boundingsphereradius = 0;
+ for (i = 0; i < vertexNum; i++) {
+ for (j = 0; j < vertexNum; j++) {
+ if (j != i && distsq(&vertex[j], &vertex[i]) / 2 > boundingsphereradius) {
+ boundingsphereradius = distsq(&vertex[j], &vertex[i]) / 2;
+ boundingspherecenter = (vertex[i] + vertex[j]) / 2;
+ }
+ }
+ }
+ boundingsphereradius = fast_sqrt(boundingsphereradius);
+}
+
+
+void Model::CalculateNormals(bool facenormalise)
+{
+ if (visibleloading)
+ Game::LoadingScreen();
+ static int i;
+ if (type != normaltype && type != decalstype)
+ return;
+
+ for (i = 0; i < vertexNum; i++) {
+ normals[i].x = 0;
+ normals[i].y = 0;
+ normals[i].z = 0;
+ }
+
+ for (i = 0; i < TriangleNum; i++) {
+ CrossProduct(vertex[Triangles[i].vertex[1]] - vertex[Triangles[i].vertex[0]], vertex[Triangles[i].vertex[2]] - vertex[Triangles[i].vertex[0]], &facenormals[i]);
+
+ normals[Triangles[i].vertex[0]].x += facenormals[i].x;
+ normals[Triangles[i].vertex[0]].y += facenormals[i].y;
+ normals[Triangles[i].vertex[0]].z += facenormals[i].z;
+
+ normals[Triangles[i].vertex[1]].x += facenormals[i].x;
+ normals[Triangles[i].vertex[1]].y += facenormals[i].y;
+ normals[Triangles[i].vertex[1]].z += facenormals[i].z;
+
+ normals[Triangles[i].vertex[2]].x += facenormals[i].x;
+ normals[Triangles[i].vertex[2]].y += facenormals[i].y;
+ normals[Triangles[i].vertex[2]].z += facenormals[i].z;
+ if (facenormalise)
+ Normalise(&facenormals[i]);
+ }
+ for (i = 0; i < vertexNum; i++) {
+ Normalise(&normals[i]);
+ normals[i] *= -1;
+ }
+ UpdateVertexArrayNoTex();
+}
+
+void Model::drawimmediate()
+{
+ textureptr.bind();
+ glBegin(GL_TRIANGLES);
+ for (int i = 0; i < TriangleNum; i++) {
+ glTexCoord2f(Triangles[i].gx[0], Triangles[i].gy[0]);
+ if (color)
+ glColor3f(normals[Triangles[i].vertex[0]].x, normals[Triangles[i].vertex[0]].y, normals[Triangles[i].vertex[0]].z);
+ if (!color && !flat)
+ glNormal3f(normals[Triangles[i].vertex[0]].x, normals[Triangles[i].vertex[0]].y, normals[Triangles[i].vertex[0]].z);
+ if (!color && flat)
+ glNormal3f(facenormals[i].x, facenormals[i].y, facenormals[i].y);
+ glVertex3f(vertex[Triangles[i].vertex[0]].x, vertex[Triangles[i].vertex[0]].y, vertex[Triangles[i].vertex[0]].z);
+
+ glTexCoord2f(Triangles[i].gx[1], Triangles[i].gy[1]);
+ if (color)
+ glColor3f(normals[Triangles[i].vertex[1]].x, normals[Triangles[i].vertex[1]].y, normals[Triangles[i].vertex[1]].z);
+ if (!color && !flat)
+ glNormal3f(normals[Triangles[i].vertex[1]].x, normals[Triangles[i].vertex[1]].y, normals[Triangles[i].vertex[1]].z);
+ if (!color && flat)
+ glNormal3f(facenormals[i].x, facenormals[i].y, facenormals[i].y);
+ glVertex3f(vertex[Triangles[i].vertex[1]].x, vertex[Triangles[i].vertex[1]].y, vertex[Triangles[i].vertex[1]].z);
+
+ glTexCoord2f(Triangles[i].gx[2], Triangles[i].gy[2]);
+ if (color)
+ glColor3f(normals[Triangles[i].vertex[2]].x, normals[Triangles[i].vertex[2]].y, normals[Triangles[i].vertex[2]].z);
+ if (!color && !flat)
+ glNormal3f(normals[Triangles[i].vertex[2]].x, normals[Triangles[i].vertex[2]].y, normals[Triangles[i].vertex[2]].z);
+ if (!color && flat)
+ glNormal3f(facenormals[i].x, facenormals[i].y, facenormals[i].y);
+ glVertex3f(vertex[Triangles[i].vertex[2]].x, vertex[Triangles[i].vertex[2]].y, vertex[Triangles[i].vertex[2]].z);
+ }
+ glEnd();
+}
+
+void Model::draw()
+{
+ if (type != normaltype && type != decalstype)
+ return;
+
+ glEnableClientState(GL_NORMAL_ARRAY);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+ if (!color)
+ glInterleavedArrays( GL_T2F_N3F_V3F, 8 * sizeof(GLfloat), &vArray[0]);
+ if (color)
+ glInterleavedArrays( GL_T2F_C3F_V3F, 8 * sizeof(GLfloat), &vArray[0]);
+ textureptr.bind();
+
+ glDrawArrays(GL_TRIANGLES, 0, TriangleNum * 3);
+
+ if (!color)
+ glDisableClientState(GL_NORMAL_ARRAY);
+ if (color)
+ glDisableClientState(GL_COLOR_ARRAY);
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+}
+
+//TODO: phase out in favor of Texture
+void Model::drawdifftex(GLuint texture)
+{
+ glEnableClientState(GL_NORMAL_ARRAY);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ if (!color)
+ glInterleavedArrays( GL_T2F_N3F_V3F, 8 * sizeof(GLfloat), &vArray[0]);
+ if (color)
+ glInterleavedArrays( GL_T2F_C3F_V3F, 8 * sizeof(GLfloat), &vArray[0]);
+
+ glBindTexture(GL_TEXTURE_2D, (unsigned long)texture);
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
+
+
+#ifndef WIN32
+ glLockArraysEXT( 0, TriangleNum * 3);
+#endif
+ glDrawArrays(GL_TRIANGLES, 0, TriangleNum * 3);
+#ifndef WIN32
+ glUnlockArraysEXT();
+#endif
+
+
+ if (!color)
+ glDisableClientState(GL_NORMAL_ARRAY);
+ if (color)
+ glDisableClientState(GL_COLOR_ARRAY);
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+}
+
+void Model::drawdifftex(Texture texture)
+{
+ glEnableClientState(GL_NORMAL_ARRAY);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ if (!color)
+ glInterleavedArrays( GL_T2F_N3F_V3F, 8 * sizeof(GLfloat), &vArray[0]);
+ if (color)
+ glInterleavedArrays( GL_T2F_C3F_V3F, 8 * sizeof(GLfloat), &vArray[0]);
+
+ texture.bind();
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
+
+
+#ifndef WIN32
+ glLockArraysEXT( 0, TriangleNum * 3);
+#endif
+ glDrawArrays(GL_TRIANGLES, 0, TriangleNum * 3);
+#ifndef WIN32
+ glUnlockArraysEXT();
+#endif
+
+
+ if (!color)
+ glDisableClientState(GL_NORMAL_ARRAY);
+ if (color)
+ glDisableClientState(GL_COLOR_ARRAY);
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+}
+
+void Model::drawdecals(Texture shadowtexture, Texture bloodtexture, Texture bloodtexture2, Texture breaktexture)
+{
+ if (decals) {
+ if (type != decalstype)
+ return;
+ static int i;
+ static int lasttype;
+ static bool blend;
+
+ blend = 1;
+
+ lasttype = -1;
+ glEnable(GL_BLEND);
+ glDisable(GL_LIGHTING);
+ glDisable(GL_CULL_FACE);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDepthMask(0);
+ if (numdecals > max_model_decals)
+ numdecals = max_model_decals;
+ for (i = 0; i < numdecals; i++) {
+ if (decaltype[i] == blooddecalfast && decalalivetime[i] < 2)
+ decalalivetime[i] = 2;
+
+ if (decaltype[i] == shadowdecal && decaltype[i] != lasttype) {
+ shadowtexture.bind();
+ if (!blend) {
+ blend = 1;
+ glAlphaFunc(GL_GREATER, 0.0001);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+ }
+ if (decaltype[i] == breakdecal && decaltype[i] != lasttype) {
+ breaktexture.bind();
+ if (!blend) {
+ blend = 1;
+ glAlphaFunc(GL_GREATER, 0.0001);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+ }
+ if ((decaltype[i] == blooddecal || decaltype[i] == blooddecalslow) && decaltype[i] != lasttype) {
+ bloodtexture.bind();
+ if (blend) {
+ blend = 0;
+ glAlphaFunc(GL_GREATER, 0.15);
+ glBlendFunc(GL_ONE, GL_ZERO);
+ }
+ }
+ if ((decaltype[i] == blooddecalfast) && decaltype[i] != lasttype) {
+ bloodtexture2.bind();
+ if (blend) {
+ blend = 0;
+ glAlphaFunc(GL_GREATER, 0.15);
+ glBlendFunc(GL_ONE, GL_ZERO);
+ }
+ }
+ if (decaltype[i] == shadowdecal) {
+ glColor4f(1, 1, 1, decalopacity[i]);
+ }
+ if (decaltype[i] == breakdecal) {
+ glColor4f(1, 1, 1, decalopacity[i]);
+ if (decalalivetime[i] > 58)
+ glColor4f(1, 1, 1, decalopacity[i] * (60 - decalalivetime[i]) / 2);
+ }
+ if ((decaltype[i] == blooddecal || decaltype[i] == blooddecalfast || decaltype[i] == blooddecalslow)) {
+ glColor4f(1, 1, 1, decalopacity[i]);
+ if (decalalivetime[i] < 4)
+ glColor4f(1, 1, 1, decalopacity[i]*decalalivetime[i]*.25);
+ if (decalalivetime[i] > 58)
+ glColor4f(1, 1, 1, decalopacity[i] * (60 - decalalivetime[i]) / 2);
+ }
+ lasttype = decaltype[i];
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glBegin(GL_TRIANGLES);
+ for (int j = 0; j < 3; j++) {
+ glTexCoord2f(decaltexcoords[i][j][0], decaltexcoords[i][j][1]);
+ glVertex3f(decalvertex[i][j].x, decalvertex[i][j].y, decalvertex[i][j].z);
+ }
+ glEnd();
+ glPopMatrix();
+ }
+ for (i = numdecals - 1; i >= 0; i--) {
+ decalalivetime[i] += multiplier;
+ if (decaltype[i] == blooddecalslow)
+ decalalivetime[i] -= multiplier * 2 / 3;
+ if (decaltype[i] == blooddecalfast)
+ decalalivetime[i] += multiplier * 4;
+ if (decaltype[i] == shadowdecal)
+ DeleteDecal(i);
+ if ((decaltype[i] == blooddecal || decaltype[i] == blooddecalfast || decaltype[i] == blooddecalslow) && decalalivetime[i] >= 60)
+ DeleteDecal(i);
+ }
+ glAlphaFunc(GL_GREATER, 0.0001);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+}
+
+void Model::DeleteDecal(int which)
+{
+ if (decals) {
+ if (type != decalstype)
+ return;
+ decaltype[which] = decaltype[numdecals - 1];
+ decalposition[which] = decalposition[numdecals - 1];
+ for (int i = 0; i < 3; i++) {
+ decalvertex[which][i] = decalvertex[numdecals - 1][i];
+ decaltexcoords[which][i][0] = decaltexcoords[numdecals - 1][i][0];
+ decaltexcoords[which][i][1] = decaltexcoords[numdecals - 1][i][1];
+ }
+ decalrotation[which] = decalrotation[numdecals - 1];
+ decalalivetime[which] = decalalivetime[numdecals - 1];
+ decalopacity[which] = decalopacity[numdecals - 1];
+ numdecals--;
+ }
+}
+
+void Model::MakeDecal(int atype, XYZ *where, float *size, float *opacity, float *rotation)
+{
+ if (decals) {
+ if (type != decalstype)
+ return;
+
+ static float placex, placez;
+ static XYZ rot;
+ static float distance;
+ static int i, j;
+
+ if (*opacity > 0)
+ if (distsq(where, &boundingspherecenter) < (boundingsphereradius + *size) * (boundingsphereradius + *size))
+ for (i = 0; i < TriangleNum; i++) {
+ if (facenormals[i].y < -.1 && (vertex[Triangles[i].vertex[0]].y < where->y || vertex[Triangles[i].vertex[1]].y < where->y || vertex[Triangles[i].vertex[2]].y < where->y)) {
+ decalposition[numdecals] = *where;
+ decaltype[numdecals] = atype;
+ decalrotation[numdecals] = *rotation;
+ decalalivetime[numdecals] = 0;
+ distance = abs(((facenormals[i].x * where->x) + (facenormals[i].y * where->y) + (facenormals[i].z * where->z) - ((facenormals[i].x * vertex[Triangles[i].vertex[0]].x) + (facenormals[i].y * vertex[Triangles[i].vertex[0]].y) + (facenormals[i].z * vertex[Triangles[i].vertex[0]].z))) / facenormals[i].y);
+ decalopacity[numdecals] = *opacity - distance / 10;
+
+ if (decalopacity[numdecals > 0]) {
+ placex = vertex[Triangles[i].vertex[0]].x;
+ placez = vertex[Triangles[i].vertex[0]].z;
+
+ decaltexcoords[numdecals][0][0] = (placex - where->x) / (*size) / 2 + .5;
+ decaltexcoords[numdecals][0][1] = (placez - where->z) / (*size) / 2 + .5;
+
+ decalvertex[numdecals][0].x = placex;
+ decalvertex[numdecals][0].z = placez;
+ decalvertex[numdecals][0].y = vertex[Triangles[i].vertex[0]].y;
+
+
+ placex = vertex[Triangles[i].vertex[1]].x;
+ placez = vertex[Triangles[i].vertex[1]].z;
+
+ decaltexcoords[numdecals][1][0] = (placex - where->x) / (*size) / 2 + .5;
+ decaltexcoords[numdecals][1][1] = (placez - where->z) / (*size) / 2 + .5;
+
+ decalvertex[numdecals][1].x = placex;
+ decalvertex[numdecals][1].z = placez;
+ decalvertex[numdecals][1].y = vertex[Triangles[i].vertex[1]].y;
+
+
+ placex = vertex[Triangles[i].vertex[2]].x;
+ placez = vertex[Triangles[i].vertex[2]].z;
+
+ decaltexcoords[numdecals][2][0] = (placex - where->x) / (*size) / 2 + .5;
+ decaltexcoords[numdecals][2][1] = (placez - where->z) / (*size) / 2 + .5;
+
+ decalvertex[numdecals][2].x = placex;
+ decalvertex[numdecals][2].z = placez;
+ decalvertex[numdecals][2].y = vertex[Triangles[i].vertex[2]].y;
+
+ if (!(decaltexcoords[numdecals][0][0] < 0 && decaltexcoords[numdecals][1][0] < 0 && decaltexcoords[numdecals][2][0] < 0))
+ if (!(decaltexcoords[numdecals][0][1] < 0 && decaltexcoords[numdecals][1][1] < 0 && decaltexcoords[numdecals][2][1] < 0))
+ if (!(decaltexcoords[numdecals][0][0] > 1 && decaltexcoords[numdecals][1][0] > 1 && decaltexcoords[numdecals][2][0] > 1))
+ if (!(decaltexcoords[numdecals][0][1] > 1 && decaltexcoords[numdecals][1][1] > 1 && decaltexcoords[numdecals][2][1] > 1)) {
+ if (decalrotation[numdecals]) {
+ for (j = 0; j < 3; j++) {
+ rot.y = 0;
+ rot.x = decaltexcoords[numdecals][j][0] - .5;
+ rot.z = decaltexcoords[numdecals][j][1] - .5;
+ rot = DoRotation(rot, 0, -decalrotation[numdecals], 0);
+ decaltexcoords[numdecals][j][0] = rot.x + .5;
+ decaltexcoords[numdecals][j][1] = rot.z + .5;
+ }
+ }
+ if (numdecals < max_model_decals - 1)
+ numdecals++;
+ }
+ }
+ }
+ }
+ }
+}
+
+void Model::MakeDecal(int atype, XYZ where, float size, float opacity, float rotation)
+{
+ if (decals) {
+ if (type != decalstype)
+ return;
+
+ static float placex, placez;
+ static XYZ rot;
+ static float distance;
+ static int i, j;
+
+ if (opacity > 0)
+ if (distsq(&where, &boundingspherecenter) < (boundingsphereradius + size) * (boundingsphereradius + size))
+ for (i = 0; i < TriangleNum; i++) {
+ distance = abs(((facenormals[i].x * where.x) + (facenormals[i].y * where.y) + (facenormals[i].z * where.z) - ((facenormals[i].x * vertex[Triangles[i].vertex[0]].x) + (facenormals[i].y * vertex[Triangles[i].vertex[0]].y) + (facenormals[i].z * vertex[Triangles[i].vertex[0]].z))));
+ if (distance < .02 && abs(facenormals[i].y) > abs(facenormals[i].x) && abs(facenormals[i].y) > abs(facenormals[i].z)) {
+ decalposition[numdecals] = where;
+ decaltype[numdecals] = atype;
+ decalrotation[numdecals] = rotation;
+ decalalivetime[numdecals] = 0;
+ decalopacity[numdecals] = opacity - distance / 10;
+
+ if (decalopacity[numdecals > 0]) {
+ placex = vertex[Triangles[i].vertex[0]].x;
+ placez = vertex[Triangles[i].vertex[0]].z;
+
+ decaltexcoords[numdecals][0][0] = (placex - where.x) / (size) / 2 + .5;
+ decaltexcoords[numdecals][0][1] = (placez - where.z) / (size) / 2 + .5;
+
+ decalvertex[numdecals][0].x = placex;
+ decalvertex[numdecals][0].z = placez;
+ decalvertex[numdecals][0].y = vertex[Triangles[i].vertex[0]].y;
+
+
+ placex = vertex[Triangles[i].vertex[1]].x;
+ placez = vertex[Triangles[i].vertex[1]].z;
+
+ decaltexcoords[numdecals][1][0] = (placex - where.x) / (size) / 2 + .5;
+ decaltexcoords[numdecals][1][1] = (placez - where.z) / (size) / 2 + .5;
+
+ decalvertex[numdecals][1].x = placex;
+ decalvertex[numdecals][1].z = placez;
+ decalvertex[numdecals][1].y = vertex[Triangles[i].vertex[1]].y;
+
+
+ placex = vertex[Triangles[i].vertex[2]].x;
+ placez = vertex[Triangles[i].vertex[2]].z;
+
+ decaltexcoords[numdecals][2][0] = (placex - where.x) / (size) / 2 + .5;
+ decaltexcoords[numdecals][2][1] = (placez - where.z) / (size) / 2 + .5;
+
+ decalvertex[numdecals][2].x = placex;
+ decalvertex[numdecals][2].z = placez;
+ decalvertex[numdecals][2].y = vertex[Triangles[i].vertex[2]].y;
+
+ if (!(decaltexcoords[numdecals][0][0] < 0 && decaltexcoords[numdecals][1][0] < 0 && decaltexcoords[numdecals][2][0] < 0))
+ if (!(decaltexcoords[numdecals][0][1] < 0 && decaltexcoords[numdecals][1][1] < 0 && decaltexcoords[numdecals][2][1] < 0))
+ if (!(decaltexcoords[numdecals][0][0] > 1 && decaltexcoords[numdecals][1][0] > 1 && decaltexcoords[numdecals][2][0] > 1))
+ if (!(decaltexcoords[numdecals][0][1] > 1 && decaltexcoords[numdecals][1][1] > 1 && decaltexcoords[numdecals][2][1] > 1)) {
+ if (decalrotation[numdecals]) {
+ for (j = 0; j < 3; j++) {
+ rot.y = 0;
+ rot.x = decaltexcoords[numdecals][j][0] - .5;
+ rot.z = decaltexcoords[numdecals][j][1] - .5;
+ rot = DoRotation(rot, 0, -decalrotation[numdecals], 0);
+ decaltexcoords[numdecals][j][0] = rot.x + .5;
+ decaltexcoords[numdecals][j][1] = rot.z + .5;
+ }
+ }
+ if (numdecals < max_model_decals - 1)
+ numdecals++;
+ }
+ }
+ } else if (distance < .02 && abs(facenormals[i].x) > abs(facenormals[i].y) && abs(facenormals[i].x) > abs(facenormals[i].z)) {
+ decalposition[numdecals] = where;
+ decaltype[numdecals] = atype;
+ decalrotation[numdecals] = rotation;
+ decalalivetime[numdecals] = 0;
+ decalopacity[numdecals] = opacity - distance / 10;
+
+ if (decalopacity[numdecals > 0]) {
+ placex = vertex[Triangles[i].vertex[0]].y;
+ placez = vertex[Triangles[i].vertex[0]].z;
+
+ decaltexcoords[numdecals][0][0] = (placex - where.y) / (size) / 2 + .5;
+ decaltexcoords[numdecals][0][1] = (placez - where.z) / (size) / 2 + .5;
+
+ decalvertex[numdecals][0].x = vertex[Triangles[i].vertex[0]].x;
+ decalvertex[numdecals][0].z = placez;
+ decalvertex[numdecals][0].y = placex;
+
+
+ placex = vertex[Triangles[i].vertex[1]].y;
+ placez = vertex[Triangles[i].vertex[1]].z;
+
+ decaltexcoords[numdecals][1][0] = (placex - where.y) / (size) / 2 + .5;
+ decaltexcoords[numdecals][1][1] = (placez - where.z) / (size) / 2 + .5;
+
+ decalvertex[numdecals][1].x = vertex[Triangles[i].vertex[1]].x;
+ decalvertex[numdecals][1].z = placez;
+ decalvertex[numdecals][1].y = placex;
+
+
+ placex = vertex[Triangles[i].vertex[2]].y;
+ placez = vertex[Triangles[i].vertex[2]].z;
+
+ decaltexcoords[numdecals][2][0] = (placex - where.y) / (size) / 2 + .5;
+ decaltexcoords[numdecals][2][1] = (placez - where.z) / (size) / 2 + .5;
+
+ decalvertex[numdecals][2].x = vertex[Triangles[i].vertex[2]].x;
+ decalvertex[numdecals][2].z = placez;
+ decalvertex[numdecals][2].y = placex;
+
+ if (!(decaltexcoords[numdecals][0][0] < 0 && decaltexcoords[numdecals][1][0] < 0 && decaltexcoords[numdecals][2][0] < 0))
+ if (!(decaltexcoords[numdecals][0][1] < 0 && decaltexcoords[numdecals][1][1] < 0 && decaltexcoords[numdecals][2][1] < 0))
+ if (!(decaltexcoords[numdecals][0][0] > 1 && decaltexcoords[numdecals][1][0] > 1 && decaltexcoords[numdecals][2][0] > 1))
+ if (!(decaltexcoords[numdecals][0][1] > 1 && decaltexcoords[numdecals][1][1] > 1 && decaltexcoords[numdecals][2][1] > 1)) {
+ if (decalrotation[numdecals]) {
+ for (j = 0; j < 3; j++) {
+ rot.y = 0;
+ rot.x = decaltexcoords[numdecals][j][0] - .5;
+ rot.z = decaltexcoords[numdecals][j][1] - .5;
+ rot = DoRotation(rot, 0, -decalrotation[numdecals], 0);
+ decaltexcoords[numdecals][j][0] = rot.x + .5;
+ decaltexcoords[numdecals][j][1] = rot.z + .5;
+ }
+ }
+ if (numdecals < max_model_decals - 1)
+ numdecals++;
+ }
+ }
+ } else if (distance < .02 && abs(facenormals[i].z) > abs(facenormals[i].y) && abs(facenormals[i].z) > abs(facenormals[i].x)) {
+ decalposition[numdecals] = where;
+ decaltype[numdecals] = atype;
+ decalrotation[numdecals] = rotation;
+ decalalivetime[numdecals] = 0;
+ decalopacity[numdecals] = opacity - distance / 10;
+
+ if (decalopacity[numdecals > 0]) {
+ placex = vertex[Triangles[i].vertex[0]].x;
+ placez = vertex[Triangles[i].vertex[0]].y;
+
+ decaltexcoords[numdecals][0][0] = (placex - where.x) / (size) / 2 + .5;
+ decaltexcoords[numdecals][0][1] = (placez - where.y) / (size) / 2 + .5;
+
+ decalvertex[numdecals][0].x = placex;
+ decalvertex[numdecals][0].z = vertex[Triangles[i].vertex[0]].z;
+ decalvertex[numdecals][0].y = placez;
+
+
+ placex = vertex[Triangles[i].vertex[1]].x;
+ placez = vertex[Triangles[i].vertex[1]].y;
+
+ decaltexcoords[numdecals][1][0] = (placex - where.x) / (size) / 2 + .5;
+ decaltexcoords[numdecals][1][1] = (placez - where.y) / (size) / 2 + .5;
+
+ decalvertex[numdecals][1].x = placex;
+ decalvertex[numdecals][1].z = vertex[Triangles[i].vertex[1]].z;
+ decalvertex[numdecals][1].y = placez;
+
+
+ placex = vertex[Triangles[i].vertex[2]].x;
+ placez = vertex[Triangles[i].vertex[2]].y;
+
+ decaltexcoords[numdecals][2][0] = (placex - where.x) / (size) / 2 + .5;
+ decaltexcoords[numdecals][2][1] = (placez - where.y) / (size) / 2 + .5;
+
+ decalvertex[numdecals][2].x = placex;
+ decalvertex[numdecals][2].z = vertex[Triangles[i].vertex[2]].z;
+ decalvertex[numdecals][2].y = placez;
+
+ if (!(decaltexcoords[numdecals][0][0] < 0 && decaltexcoords[numdecals][1][0] < 0 && decaltexcoords[numdecals][2][0] < 0))
+ if (!(decaltexcoords[numdecals][0][1] < 0 && decaltexcoords[numdecals][1][1] < 0 && decaltexcoords[numdecals][2][1] < 0))
+ if (!(decaltexcoords[numdecals][0][0] > 1 && decaltexcoords[numdecals][1][0] > 1 && decaltexcoords[numdecals][2][0] > 1))
+ if (!(decaltexcoords[numdecals][0][1] > 1 && decaltexcoords[numdecals][1][1] > 1 && decaltexcoords[numdecals][2][1] > 1)) {
+ if (decalrotation[numdecals]) {
+ for (j = 0; j < 3; j++) {
+ rot.y = 0;
+ rot.x = decaltexcoords[numdecals][j][0] - .5;
+ rot.z = decaltexcoords[numdecals][j][1] - .5;
+ rot = DoRotation(rot, 0, -decalrotation[numdecals], 0);
+ decaltexcoords[numdecals][j][0] = rot.x + .5;
+ decaltexcoords[numdecals][j][1] = rot.z + .5;
+ }
+ }
+ if (numdecals < max_model_decals - 1)
+ numdecals++;
+ }
+ }
+ }
+ }
+ }
+}
+
+Model::~Model()
+{
+ deallocate();
+ textureptr.destroy();
+}
+
+void Model::deallocate()
+{
+ int i = 0, j = 0;
+
+ if (owner)
+ free(owner);
+ owner = 0;
+
+ if (possible)
+ free(possible);
+ possible = 0;
+
+ if (vertex)
+ free(vertex);
+ vertex = 0;
+
+ if (normals)
+ free(normals);
+ normals = 0;
+
+ if (facenormals)
+ free(facenormals);
+ facenormals = 0;
+
+ if (Triangles)
+ free(Triangles);
+ Triangles = 0;
+
+ if (vArray)
+ free(vArray);
+ vArray = 0;
+
+
+ //allow decals
+ if (decaltexcoords) {
+ for (i = 0; i < max_model_decals; i++) {
+ for (j = 0; j < 3; j++) {
+ free(decaltexcoords[i][j]);
+ }
+ free(decaltexcoords[i]);
+ }
+ free(decaltexcoords);
+ }
+ decaltexcoords = 0;
+
+
+ if (decalvertex) {
+ for (i = 0; i < max_model_decals; i++) {
+ free(decalvertex[i]);
+ }
+ free(decalvertex);
+ }
+ decalvertex = 0;
+
+
+ free(decaltype);
+ decaltype = 0;
+
+ free(decalopacity);
+ decalopacity = 0;
+
+ free(decalrotation);
+ decalrotation = 0;
+
+ free(decalalivetime);
+ decalalivetime = 0;
+
+ free(decalposition);
+ decalposition = 0;
+
+};
+
+Model::Model()
+{
+ vertexNum = 0, TriangleNum = 0;
+ hastexture = 0;
+
+ type = 0, oldtype = 0;
+
+ possible = 0;
+ owner = 0;
+ vertex = 0;
+ normals = 0;
+ facenormals = 0;
+ Triangles = 0;
+ vArray = 0;
+
+ memset(&modelTexture, 0, sizeof(modelTexture));
+ numpossible = 0;
+ color = 0;
+
+ boundingspherecenter = 0;
+ boundingsphereradius = 0;
+
+ decaltexcoords = 0;
+ decalvertex = 0;
+ decaltype = 0;
+ decalopacity = 0;
+ decalrotation = 0;
+ decalalivetime = 0;
+ decalposition = 0;
+
+ numdecals = 0;
+
+ flat = 0;
+
+ type = nothing;
+}
+
--- /dev/null
+/*
+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 _MODELS_H_
+#define _MODELS_H_
+
+/**> Model Loading <**/
+//
+// Model Maximums
+//
+#include "Graphic/gamegl.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <vector>
+
+#include "Environment/Terrain.h"
+#include "Graphic/Texture.h"
+#include "Math/Quaternions.h"
+#include "Utils/binio.h"
+
+//
+// Textures List
+//
+typedef struct {
+ long xsz, ysz;
+ GLubyte *txt;
+} ModelTexture;
+
+//
+// Model Structures
+//
+
+class TexturedTriangle
+{
+public:
+ short vertex[3];
+ float gx[3], gy[3];
+};
+
+#define max_model_decals 300
+
+#define nothing 0
+#define normaltype 4
+#define notextype 1
+#define rawtype 2
+#define decalstype 3
+
+class Model
+{
+public:
+ short vertexNum, TriangleNum;
+ bool hastexture;
+
+ int type, oldtype;
+
+ int* possible;
+ int* owner;
+ XYZ* vertex;
+ XYZ* normals;
+ XYZ* facenormals;
+ TexturedTriangle* Triangles;
+ GLfloat* vArray;
+
+ /*int possible[max_model_vertex];
+ int owner[max_textured_triangle];
+ XYZ vertex[max_model_vertex];
+ XYZ normals[max_model_vertex];
+ XYZ facenormals[max_textured_triangle];
+ TexturedTriangle Triangles[max_textured_triangle];
+ GLfloat vArray[max_textured_triangle*24];*/
+
+ Texture textureptr;
+ ModelTexture modelTexture;
+ int numpossible;
+ bool color;
+
+ XYZ boundingspherecenter;
+ float boundingsphereradius;
+
+ float*** decaltexcoords;
+ XYZ** decalvertex;
+ int* decaltype;
+ float* decalopacity;
+ float* decalrotation;
+ float* decalalivetime;
+ XYZ* decalposition;
+
+ /*float decaltexcoords[max_model_decals][3][2];
+ XYZ decalvertex[max_model_decals][3];
+ int decaltype[max_model_decals];
+ float decalopacity[max_model_decals];
+ float decalrotation[max_model_decals];
+ float decalalivetime[max_model_decals];
+ XYZ decalposition[max_model_decals];*/
+
+ int numdecals;
+
+ bool flat;
+
+ void DeleteDecal(int which);
+ void MakeDecal(int atype, XYZ *where, float *size, float *opacity, float *rotation);
+ void MakeDecal(int atype, XYZ where, float size, float opacity, float rotation);
+ void drawdecals(Texture shadowtexture, Texture bloodtexture, Texture bloodtexture2, Texture breaktexture);
+ int SphereCheck(XYZ *p1, float radius, XYZ *p, XYZ *move, float *rotate);
+ int SphereCheckPossible(XYZ *p1, float radius, XYZ *move, float *rotate);
+ int LineCheck(XYZ *p1, XYZ *p2, XYZ *p, XYZ *move, float *rotate);
+ int LineCheckPossible(XYZ *p1, XYZ *p2, XYZ *p, XYZ *move, float *rotate);
+ int LineCheckSlidePossible(XYZ *p1, XYZ *p2, XYZ *p, XYZ *move, float *rotate);
+ void UpdateVertexArray();
+ void UpdateVertexArrayNoTex();
+ void UpdateVertexArrayNoTexNoNorm();
+ bool loadnotex(const std::string& filename);
+ bool loadraw(const std::string& filename);
+ bool load(const std::string& filename, bool texture);
+ bool loaddecal(const std::string& filename, bool texture);
+ void Scale(float xscale, float yscale, float zscale);
+ void FlipTexCoords();
+ void UniformTexCoords();
+ void ScaleTexCoords(float howmuch);
+ void ScaleNormals(float xscale, float yscale, float zscale);
+ void Translate(float xtrans, float ytrans, float ztrans);
+ void CalculateNormals(bool facenormalise);
+ void draw();
+ void drawdifftex(GLuint texture);
+ void drawdifftex(Texture texture);
+ void drawimmediate();
+ void Rotate(float xang, float yang, float zang);
+ ~Model();
+ void deallocate();
+ Model();
+};
+
+#endif
--- /dev/null
+/*
+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/>.
+*/
+
+#include "Game.h"
+#include "Graphic/Sprite.h"
+#include "Objects/Person.h"
+
+extern XYZ viewer;
+extern float viewdistance;
+extern float fadestart;
+extern int environment;
+extern float texscale;
+extern Light light;
+extern float multiplier;
+extern float gravity;
+extern Terrain terrain;
+extern Objects objects;
+extern int detail;
+extern XYZ viewerfacing;
+extern int bloodtoggle;
+extern XYZ windvector;
+
+// init statics
+Texture Sprite::cloudtexture;
+Texture Sprite::cloudimpacttexture;
+Texture Sprite::bloodtexture;
+Texture Sprite::flametexture;
+Texture Sprite::bloodflametexture;
+Texture Sprite::smoketexture;
+Texture Sprite::snowflaketexture;
+Texture Sprite::shinetexture;
+Texture Sprite::splintertexture;
+Texture Sprite::leaftexture;
+Texture Sprite::toothtexture;
+
+float Sprite::checkdelay = 0;
+
+vector<Sprite*> Sprite::sprites = vector<Sprite*>();
+
+//Functions
+void Sprite::Draw()
+{
+ int k;
+ static float M[16];
+ static XYZ point;
+ static float distancemult;
+ static int lasttype;
+ static int lastspecial;
+ static int whichpatchx, whichpatchz;
+ static XYZ start, end, colpoint;
+ static bool check;
+ static bool blend;
+ static float tempmult;
+ static XYZ difference;
+ static float lightcolor[3];
+ static float viewdistsquared = viewdistance * viewdistance;
+ static XYZ tempviewer;
+
+ tempviewer = viewer + viewerfacing * 6;
+ check = 0;
+
+ lightcolor[0] = light.color[0] * .5 + light.ambient[0];
+ lightcolor[1] = light.color[1] * .5 + light.ambient[1];
+ lightcolor[2] = light.color[2] * .5 + light.ambient[2];
+
+ checkdelay -= multiplier * 10;
+
+ if (checkdelay <= 0) {
+ check = 1;
+ checkdelay = 1;
+ }
+
+ lasttype = -1;
+ lastspecial = -1;
+ glEnable(GL_BLEND);
+ glDisable(GL_LIGHTING);
+ glDisable(GL_CULL_FACE);
+ glEnable(GL_TEXTURE_2D);
+ blend = 1;
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDepthMask(0);
+ glAlphaFunc(GL_GREATER, 0.0001);
+ for (unsigned i = 0; i < sprites.size(); i++) {
+ if (lasttype != sprites[i]->type) {
+ switch (sprites[i]->type) {
+ case cloudsprite:
+ cloudtexture.bind();
+ if (!blend) {
+ blend = 1;
+ glAlphaFunc(GL_GREATER, 0.0001);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+ break;
+ case breathsprite:
+ case cloudimpactsprite:
+ cloudimpacttexture.bind();
+ if (!blend) {
+ blend = 1;
+ glAlphaFunc(GL_GREATER, 0.0001);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+ break;
+ case smoketype:
+ smoketexture.bind();
+ if (!blend) {
+ blend = 1;
+ glAlphaFunc(GL_GREATER, 0.0001);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+ break;
+ case bloodsprite:
+ bloodtexture.bind();
+ if (!blend) {
+ blend = 1;
+ glAlphaFunc(GL_GREATER, 0.0001);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+ break;
+ case splintersprite :
+ if (lastspecial != sprites[i]->special) {
+ if (sprites[i]->special == 0)
+ splintertexture.bind();
+ if (sprites[i]->special == 1)
+ leaftexture.bind();
+ if (sprites[i]->special == 2)
+ snowflaketexture.bind();
+ if (sprites[i]->special == 3)
+ toothtexture.bind();
+ if (!blend) {
+ blend = 1;
+ glAlphaFunc(GL_GREATER, 0.0001);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+ }
+ break;
+ case snowsprite:
+ snowflaketexture.bind();
+ if (!blend) {
+ blend = 1;
+ glAlphaFunc(GL_GREATER, 0.0001);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+ break;
+ case weaponshinesprite:
+ shinetexture.bind();
+ if (blend) {
+ blend = 0;
+ glAlphaFunc(GL_GREATER, 0.001);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+ }
+ break;
+ case flamesprite:
+ case weaponflamesprite:
+ flametexture.bind();
+ if (blend || lasttype == bloodflamesprite) {
+ blend = 0;
+ glAlphaFunc(GL_GREATER, 0.3);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+ }
+ break;
+ case bloodflamesprite:
+ bloodflametexture.bind();
+ if (blend) {
+ blend = 0;
+ glAlphaFunc(GL_GREATER, 0.3);
+ glBlendFunc(GL_ONE, GL_ZERO);
+ }
+ break;
+ }
+ }
+ if (sprites[i]->type == snowsprite)
+ distancemult = (144 - (distsq(&tempviewer, &sprites[i]->position) - (144 * fadestart)) * (1 / (1 - fadestart))) / 144;
+ else
+ distancemult = (viewdistsquared - (distsq(&viewer, &sprites[i]->position) - (viewdistsquared * fadestart)) * (1 / (1 - fadestart))) / viewdistsquared;
+ if (sprites[i]->type == flamesprite) {
+ if (distancemult >= 1)
+ glColor4f(sprites[i]->color[0], sprites[i]->color[1], sprites[i]->color[2], sprites[i]->opacity);
+ else
+ glColor4f(sprites[i]->color[0], sprites[i]->color[1], sprites[i]->color[2], sprites[i]->opacity * distancemult);
+ } else {
+ if (distancemult >= 1)
+ glColor4f(sprites[i]->color[0]*lightcolor[0], sprites[i]->color[1]*lightcolor[1], sprites[i]->color[2]*lightcolor[2], sprites[i]->opacity);
+ else
+ glColor4f(sprites[i]->color[0]*lightcolor[0], sprites[i]->color[1]*lightcolor[1], sprites[i]->color[2]*lightcolor[2], sprites[i]->opacity * distancemult);
+ }
+ lasttype = sprites[i]->type;
+ lastspecial = sprites[i]->special;
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glTranslatef(sprites[i]->position.x, sprites[i]->position.y, sprites[i]->position.z);
+ if ((sprites[i]->type == flamesprite || sprites[i]->type == weaponflamesprite || sprites[i]->type == weaponshinesprite)) {
+ difference = viewer - sprites[i]->position;
+ Normalise(&difference);
+ glTranslatef(difference.x * sprites[i]->size / 4, difference.y * sprites[i]->size / 4, difference.z * sprites[i]->size / 4);
+ }
+ if (sprites[i]->type == snowsprite) {
+ glRotatef(sprites[i]->rotation * .2, 0, .3, 1);
+ glTranslatef(1, 0, 0);
+ }
+ glGetFloatv(GL_MODELVIEW_MATRIX, M);
+ point.x = M[12];
+ point.y = M[13];
+ point.z = M[14];
+ glLoadIdentity();
+ glTranslatef(point.x, point.y, point.z);
+
+ glRotatef(sprites[i]->rotation, 0, 0, 1);
+
+ if ((sprites[i]->type == flamesprite || sprites[i]->type == weaponflamesprite || sprites[i]->type == weaponshinesprite || sprites[i]->type == bloodflamesprite)) {
+ if (sprites[i]->alivetime < .14)
+ glScalef(sprites[i]->alivetime / .14, sprites[i]->alivetime / .14, sprites[i]->alivetime / .14);
+ }
+ if (sprites[i]->type == smoketype || sprites[i]->type == snowsprite || sprites[i]->type == weaponshinesprite || sprites[i]->type == breathsprite) {
+ if (sprites[i]->alivetime < .3) {
+ if (distancemult >= 1)
+ glColor4f(sprites[i]->color[0]*lightcolor[0], sprites[i]->color[1]*lightcolor[1], sprites[i]->color[2]*lightcolor[2], sprites[i]->opacity * sprites[i]->alivetime / .3);
+ if (distancemult < 1)
+ glColor4f(sprites[i]->color[0]*lightcolor[0], sprites[i]->color[1]*lightcolor[1], sprites[i]->color[2]*lightcolor[2], sprites[i]->opacity * distancemult * sprites[i]->alivetime / .3);
+ }
+ }
+ if (sprites[i]->type == splintersprite && sprites[i]->special > 0 && sprites[i]->special != 3) {
+ if (sprites[i]->alivetime < .2) {
+ if (distancemult >= 1)
+ glColor4f(sprites[i]->color[0]*lightcolor[0], sprites[i]->color[1]*lightcolor[1], sprites[i]->color[2]*lightcolor[2], sprites[i]->alivetime / .2);
+ else
+ glColor4f(sprites[i]->color[0]*lightcolor[0], sprites[i]->color[1]*lightcolor[1], sprites[i]->color[2]*lightcolor[2], distancemult * sprites[i]->alivetime / .2);
+ } else {
+ if (distancemult >= 1)
+ glColor4f(sprites[i]->color[0]*lightcolor[0], sprites[i]->color[1]*lightcolor[1], sprites[i]->color[2]*lightcolor[2], 1);
+ else
+ glColor4f(sprites[i]->color[0]*lightcolor[0], sprites[i]->color[1]*lightcolor[1], sprites[i]->color[2]*lightcolor[2], 1);
+ }
+ }
+ if (sprites[i]->type == splintersprite && (sprites[i]->special == 0 || sprites[i]->special == 3)) {
+ if (distancemult >= 1)
+ glColor4f(sprites[i]->color[0]*lightcolor[0], sprites[i]->color[1]*lightcolor[1], sprites[i]->color[2]*lightcolor[2], 1);
+ else
+ glColor4f(sprites[i]->color[0]*lightcolor[0], sprites[i]->color[1]*lightcolor[1], sprites[i]->color[2]*lightcolor[2], 1);
+ }
+
+ glBegin(GL_TRIANGLES);
+ glTexCoord2f(1.0f, 1.0f);
+ glVertex3f( .5 * sprites[i]->size, .5 * sprites[i]->size, 0.0f);
+ glTexCoord2f(0.0f, 1.0f);
+ glVertex3f(-.5 * sprites[i]->size, .5 * sprites[i]->size, 0.0f);
+ glTexCoord2f(1.0f, 0.0f);
+ glVertex3f( .5 * sprites[i]->size, -.5 * sprites[i]->size, 0.0f);
+ glTexCoord2f(0.0f, 0.0f);
+ glVertex3f(-.5 * sprites[i]->size, -.5 * sprites[i]->size, 0.0f);
+ glTexCoord2f(1.0f, 0.0f);
+ glVertex3f( .5 * sprites[i]->size, -.5 * sprites[i]->size, 0.0f);
+ glTexCoord2f(0.0f, 1.0f);
+ glVertex3f(-.5 * sprites[i]->size, .5 * sprites[i]->size, 0.0f);
+ glEnd();
+ glPopMatrix();
+ }
+ tempmult = multiplier;
+ for (int i = sprites.size() - 1; i >= 0; i--) {
+ multiplier = tempmult;
+ if (sprites[i]->type != snowsprite) {
+ sprites[i]->position += sprites[i]->velocity * multiplier;
+ sprites[i]->velocity += windvector * multiplier;
+ }
+ if (sprites[i]->type == flamesprite || sprites[i]->type == smoketype)
+ sprites[i]->position += windvector * multiplier / 2;
+ if ((sprites[i]->type == flamesprite || sprites[i]->type == weaponflamesprite || sprites[i]->type == weaponshinesprite || sprites[i]->type == bloodflamesprite))
+ multiplier *= sprites[i]->speed * .7;
+ sprites[i]->alivetime += multiplier;
+
+ if (sprites[i]->type == cloudsprite || sprites[i]->type == cloudimpactsprite) {
+ sprites[i]->opacity -= multiplier / 2;
+ sprites[i]->size += multiplier / 2;
+ sprites[i]->velocity.y += gravity * multiplier * .25;
+ }
+ if (sprites[i]->type == breathsprite) {
+ sprites[i]->opacity -= multiplier / 2;
+ sprites[i]->size += multiplier / 2;
+ if (findLength(&sprites[i]->velocity) <= multiplier) {
+ sprites[i]->velocity = 0;
+ } else {
+ XYZ slowdown;
+ slowdown = sprites[i]->velocity * -1;
+ Normalise(&slowdown);
+ slowdown *= multiplier;
+ sprites[i]->velocity += slowdown;
+ }
+ }
+ if (sprites[i]->type == snowsprite) {
+ sprites[i]->size -= multiplier / 120;
+ sprites[i]->rotation += multiplier * 360;
+ sprites[i]->position.y -= multiplier;
+ sprites[i]->position += windvector * multiplier;
+ if (sprites[i]->position.y < tempviewer.y - 6) sprites[i]->position.y += 12;
+ if (sprites[i]->position.y > tempviewer.y + 6) sprites[i]->position.y -= 12;
+ if (sprites[i]->position.z < tempviewer.z - 6) sprites[i]->position.z += 12;
+ if (sprites[i]->position.z > tempviewer.z + 6) sprites[i]->position.z -= 12;
+ if (sprites[i]->position.x < tempviewer.x - 6) sprites[i]->position.x += 12;
+ if (sprites[i]->position.x > tempviewer.x + 6) sprites[i]->position.x -= 12;
+ }
+ if (sprites[i]->type == bloodsprite) {
+ bool spritehit = 0;
+ sprites[i]->rotation += multiplier * 100;
+ sprites[i]->velocity.y += gravity * multiplier;
+ if (check) {
+ XYZ where, startpoint, endpoint, movepoint, footpoint;
+ float rotationpoint;
+ int whichtri;
+
+ for (unsigned j = 0; j < Person::players.size(); j++) {
+ if (!spritehit && Person::players[j]->dead && sprites[i]->alivetime > .1) {
+ where = sprites[i]->oldposition;
+ where -= Person::players[j]->coords;
+ if (!Person::players[j]->skeleton.free)
+ where = DoRotation(where, 0, -Person::players[j]->yaw, 0);
+ startpoint = where;
+ where = sprites[i]->position;
+ where -= Person::players[j]->coords;
+ if (!Person::players[j]->skeleton.free)
+ where = DoRotation(where, 0, -Person::players[j]->yaw, 0);
+ endpoint = where;
+
+ movepoint = 0;
+ rotationpoint = 0;
+ whichtri = Person::players[j]->skeleton.drawmodel.LineCheck(&startpoint, &endpoint, &footpoint, &movepoint, &rotationpoint);
+ if (whichtri != -1) {
+ spritehit = 1;
+ Person::players[j]->DoBloodBigWhere(0, 160, sprites[i]->oldposition);
+ DeleteSprite(i);
+ }
+ }
+ }
+
+ whichpatchx = sprites[i]->position.x / (terrain.size / subdivision * terrain.scale);
+ whichpatchz = sprites[i]->position.z / (terrain.size / subdivision * terrain.scale);
+ if (whichpatchx > 0 && whichpatchz > 0 && whichpatchx < subdivision && whichpatchz < subdivision)
+ if (terrain.patchobjectnum[whichpatchx][whichpatchz]) {
+ if (!spritehit)
+ for (int j = 0; j < terrain.patchobjectnum[whichpatchx][whichpatchz]; j++) {
+ k = terrain.patchobjects[whichpatchx][whichpatchz][j];
+ start = sprites[i]->oldposition;
+ end = sprites[i]->position;
+ if (!spritehit)
+ if (objects.model[k].LineCheck(&start, &end, &colpoint, &objects.position[k], &objects.yaw[k]) != -1) {
+ if (detail == 2 || (detail == 1 && abs(Random() % 4) == 0) || (detail == 0 && abs(Random() % 8) == 0))
+ objects.model[k].MakeDecal(blooddecalfast, DoRotation(colpoint - objects.position[k], 0, -objects.yaw[k], 0), sprites[i]->size * 1.6, .5, Random() % 360);
+ DeleteSprite(i);
+ spritehit = 1;
+ }
+ }
+ }
+ if (!spritehit)
+ if (sprites[i]->position.y < terrain.getHeight(sprites[i]->position.x, sprites[i]->position.z)) {
+ terrain.MakeDecal(blooddecalfast, sprites[i]->position, sprites[i]->size * 1.6, .6, Random() % 360);
+ DeleteSprite(i);
+ }
+ }
+ }
+ if (sprites[i]->type == splintersprite) {
+ sprites[i]->rotation += sprites[i]->rotatespeed * multiplier;
+ sprites[i]->opacity -= multiplier / 2;
+ if (sprites[i]->special == 0 || sprites[i]->special == 2 || sprites[i]->special == 3)
+ sprites[i]->velocity.y += gravity * multiplier;
+ if (sprites[i]->special == 1)
+ sprites[i]->velocity.y += gravity * multiplier * .5;
+ }
+ if (sprites[i]->type == flamesprite || sprites[i]->type == weaponflamesprite || sprites[i]->type == weaponshinesprite || sprites[i]->type == bloodflamesprite) {
+ sprites[i]->rotation += multiplier * sprites[i]->rotatespeed;
+ sprites[i]->opacity -= multiplier * 5 / 4;
+ if (sprites[i]->type != weaponshinesprite && sprites[i]->type != bloodflamesprite)
+ if (sprites[i]->opacity < .5 && sprites[i]->opacity + multiplier * 5 / 4 >= .5 && (abs(Random() % 4) == 0 || (sprites[i]->initialsize > 2 && Random() % 2 == 0)))
+ MakeSprite(smoketype, sprites[i]->position, sprites[i]->velocity, .9, .9, .6, sprites[i]->size * 1.2, .4);
+ if (sprites[i]->alivetime > .14 && (sprites[i]->type == flamesprite)) {
+ sprites[i]->velocity = 0;
+ sprites[i]->velocity.y = 1.5;
+ }
+ }
+ if (sprites[i]->type == smoketype) {
+ sprites[i]->opacity -= multiplier / 3 / sprites[i]->initialsize;
+ sprites[i]->color[0] -= multiplier;
+ sprites[i]->color[1] -= multiplier;
+ sprites[i]->color[2] -= multiplier;
+ if (sprites[i]->color[0] < .6)
+ sprites[i]->color[0] = .6;
+ if (sprites[i]->color[1] < .6)
+ sprites[i]->color[1] = .6;
+ if (sprites[i]->color[2] < .6)
+ sprites[i]->color[2] = .6;
+ sprites[i]->size += multiplier;
+ sprites[i]->velocity = 0;
+ sprites[i]->velocity.y = 1.5;
+ sprites[i]->rotation += multiplier * sprites[i]->rotatespeed / 5;
+ }
+ if (sprites[i]->opacity <= 0 || sprites[i]->size <= 0)
+ DeleteSprite(i);
+ }
+ if (check)
+ for (int i = sprites.size() - 1; i >= 0; i--) {
+ sprites[i]->oldposition = sprites[i]->position;
+ }
+ glAlphaFunc(GL_GREATER, 0.0001);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+}
+
+void Sprite::DeleteSprite(int i)
+{
+ sprites.erase(sprites.begin() + i);
+}
+
+void Sprite::MakeSprite(int atype, XYZ where, XYZ avelocity, float red, float green, float blue, float asize, float aopacity)
+{
+ if (sprites.size() < max_sprites - 1) {
+ sprites.push_back(new Sprite());
+ if ((atype != bloodsprite && atype != bloodflamesprite) || bloodtoggle) {
+ sprites.back()->special = 0;
+ sprites.back()->type = atype;
+ sprites.back()->position = where;
+ sprites.back()->oldposition = where;
+ sprites.back()->velocity = avelocity;
+ sprites.back()->alivetime = 0;
+ sprites.back()->opacity = aopacity;
+ sprites.back()->size = asize;
+ sprites.back()->initialsize = asize;
+ sprites.back()->color[0] = red;
+ sprites.back()->color[1] = green;
+ sprites.back()->color[2] = blue;
+ sprites.back()->rotatespeed = abs(Random() % 720) - 360;
+ sprites.back()->speed = float(abs(Random() % 100)) / 200 + 1.5;
+ }
+ }
+}
+
+Sprite::Sprite()
+{
+ oldposition = 0;
+ position = 0;
+ velocity = 0;
+ size = 0;
+ initialsize = 0;
+ type = 0;
+ special = 0;
+ memset(color, 0, sizeof(color));
+ opacity = 0;
+ rotation = 0;
+ alivetime = 0;
+ speed = 0;
+ rotatespeed = 0;
+}
+
+void Sprite::clearTextures()
+{
+ toothtexture.destroy();
+ cloudtexture.destroy();
+ cloudimpacttexture.destroy();
+ bloodtexture.destroy();
+ flametexture.destroy();
+ bloodflametexture.destroy();
+ smoketexture.destroy();
+ snowflaketexture.destroy();
+ shinetexture.destroy();
+ splintertexture.destroy();
+ leaftexture.destroy();
+}
+
--- /dev/null
+/*
+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 _SPRITE_H_
+#define _SPRITE_H_
+
+#include "Environment/Lights.h"
+#include "Environment/Terrain.h"
+#include "Graphic/gamegl.h"
+#include "Graphic/Texture.h"
+#include "Math/Frustum.h"
+#include "Math/Quaternions.h"
+#include "Math/Quaternions.h"
+#include "Objects/Objects.h"
+#include "Utils/ImageIO.h"
+
+#include <vector>
+
+#define max_sprites 20000
+
+enum {
+ cloudsprite = 0,
+ bloodsprite,
+ flamesprite,
+ smoketype,
+ weaponflamesprite,
+ cloudimpactsprite,
+ snowsprite,
+ weaponshinesprite,
+ bloodflamesprite,
+ breathsprite,
+ splintersprite,
+ spritenumber
+};
+
+class Sprite
+{
+private:
+ XYZ oldposition;
+ XYZ position;
+ XYZ velocity;
+ float size;
+ float initialsize;
+ int type;
+ int special;
+ float color[3];
+ float opacity;
+ float rotation;
+ float alivetime;
+ float speed;
+ float rotatespeed;
+
+ static float checkdelay;
+
+ static vector<Sprite*> sprites;
+
+public:
+ static void DeleteSprite(int which);
+ static void MakeSprite(int atype, XYZ where, XYZ avelocity, float red, float green, float blue, float asize, float aopacity);
+ static void Draw();
+ static void deleteSprites() {
+ sprites.clear();
+ }
+ static void setLastSpriteSpecial(int s) {
+ sprites.back()->special = s;
+ }
+ static void setLastSpriteSpeed(int s) {
+ sprites.back()->speed = s;
+ }
+ static void setLastSpriteAlivetime(float al) {
+ sprites.back()->alivetime = al;
+ }
+ static void clearTextures();
+
+ static Texture cloudtexture;
+ static Texture bloodtexture;
+ static Texture flametexture;
+ static Texture smoketexture;
+
+ static Texture cloudimpacttexture;
+ static Texture snowflaketexture;
+ static Texture shinetexture;
+ static Texture bloodflametexture;
+
+ static Texture splintertexture;
+
+ static Texture leaftexture;
+ static Texture toothtexture;
+
+ Sprite();
+ ~Sprite();
+};
+
+#endif
--- /dev/null
+/*
+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/>.
+*/
+
+#include "Game.h"
+#include "Graphic/Stereo.h"
+
+
+extern int kContextWidth;
+extern int kContextHeight;
+
+bool CanInitStereo(StereoMode mode)
+{
+ GLint stencilbits = 0;
+
+ switch (mode) {
+ case stereoNone:
+ case stereoAnaglyph:
+ return true;
+ break;
+ case stereoHorizontalInterlaced:
+ case stereoVerticalInterlaced:
+ glGetIntegerv(GL_STENCIL_BITS, &stencilbits);
+ if ( stencilbits < 1 ) {
+ fprintf(stderr, "Failed to get a stencil buffer, interlaced stereo not available.\n");
+ return false;
+ } else {
+ fprintf(stderr, "Stencil buffer has %i bits, good.\n", stencilbits);
+ }
+ return true;
+ break;
+ default:
+ return false;
+ }
+
+}
+
+void InitStereo(StereoMode mode)
+{
+ switch (mode) {
+ default:
+ case stereoNone:
+ case stereoAnaglyph:
+ glDisable(GL_STENCIL_TEST);
+ return;
+ case stereoHorizontalInterlaced:
+ case stereoVerticalInterlaced:
+ fprintf(stderr, "Screen width is %i, height is %i\n", kContextWidth, kContextHeight);
+
+ // Setup stencil buffer
+ glDisable( GL_DEPTH_TEST);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_LIGHTING);
+ glDisable(GL_TEXTURE_2D);
+
+ glEnable( GL_STENCIL_TEST);
+ glClearStencil(0);
+ glClear( GL_STENCIL_BUFFER_BIT );
+ glStencilFunc(GL_ALWAYS, 0x1, 0x1);
+ glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
+
+ // Setup viewport
+ glViewport(0, 0, kContextWidth, kContextHeight);
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ glOrtho((GLdouble)0, (GLdouble)kContextWidth, (GLdouble)kContextHeight, 0, -1, 1);
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+ glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
+ glDisable(GL_LINE_SMOOTH);
+
+ // Add 0.5 to the coordinates, because OpenGL considers a pixel should be
+ // turned on when a line passes through the center of it.
+ if ( mode == stereoHorizontalInterlaced ) {
+ for (int y = 0; y < kContextHeight; y += 2) {
+ glBegin(GL_LINES);
+ glVertex3f(0.5, y + 0.5, 0);
+ glVertex3f(kContextWidth + 0.5, y + 0.5, 0);
+ glEnd();
+ }
+ } else {
+ for (int x = 0; x < kContextWidth; x += 2) {
+ glBegin(GL_LINES);
+ glVertex3f(x + 0.5, 0.5, 0);
+ glVertex3f(x + 0.5, kContextHeight + 0.5, 0);
+ glEnd();
+ }
+ }
+
+ glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
+
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+
+ glStencilFunc(GL_NOTEQUAL, 0x01, 0x01);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+ glEnable( GL_DEPTH_TEST);
+ glEnable(GL_CULL_FACE);
+ glEnable(GL_LIGHTING);
+ glEnable(GL_TEXTURE_2D);
+ }
+
+}
+
+const std::string StereoModeName(StereoMode mode)
+{
+ switch (mode) {
+ case stereoNone:
+ return "None";
+ break;
+ case stereoAnaglyph:
+ return "Anaglyph";
+ break;
+ case stereoHorizontalInterlaced:
+ return "Horizontal interlacing";
+ break;
+ case stereoVerticalInterlaced:
+ return "Vertical interlacing";
+ break;
+ case stereoHorizontalSplit:
+ return "Horizontal split";
+ break;
+ case stereoVerticalSplit:
+ return "Vertical split";
+ break;
+ case stereoOpenGL:
+ return "OpenGL";
+ break;
+ default:
+ return "(error)";
+ break;
+ }
+}
--- /dev/null
+/*
+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 STEREO_H_
+#define STEREO_H_
+
+enum StereoMode {
+ stereoNone,
+ stereoAnaglyph, /* red/cyan */
+ stereoHorizontalInterlaced, /* some 3D monitors */
+ stereoVerticalInterlaced,
+ stereoHorizontalSplit, /* cross-eyed view */
+ stereoVerticalSplit,
+ stereoOpenGL, /* Whatever OpenGL does, if supported */
+ stereoCount /* must be last element */
+};
+
+
+enum StereoSide {
+ // Code multiplies by StereoSide to calculate camera offsets
+ stereoLeft = -1,
+ stereoCenter = 0,
+ stereoRight = 1
+};
+
+extern StereoMode stereomode;
+extern StereoMode newstereomode;
+extern float stereoseparation;
+extern bool stereoreverse;
+
+bool CanInitStereo(StereoMode mode);
+void InitStereo(StereoMode mode);
+const std::string StereoModeName(StereoMode mode);
+
+#endif
--- /dev/null
+/*
+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 "Graphic/Text.h"
+#include "Game.h"
+
+void Text::LoadFontTexture(const std::string& fileName)
+{
+ LOGFUNC;
+
+ LOG(std::string("Loading font texture...") + fileName);
+
+ FontTexture.load(fileName, false);
+ if (base) {
+ glDeleteLists(base, 512);
+ base = 0;
+ }
+}
+
+void Text::BuildFont() // Build Our Font Display List
+{
+ float cx; // Holds Our X Character Coord
+ float cy; // Holds Our Y Character Coord
+ int loop;
+
+ LOGFUNC;
+
+ if (base) {
+ glDeleteLists(base, 512);
+ base = 0;
+ }
+
+ base = glGenLists(512); // Creating 256 Display Lists
+ FontTexture.bind();
+ for (loop = 0; loop < 512; loop++) { // Loop Through All 256 Lists
+ if (loop < 256) {
+ cx = float(loop % 16) / 16.0f; // X Position Of Current Character
+ cy = float(loop / 16) / 16.0f; // Y Position Of Current Character
+ } else {
+ cx = float((loop - 256) % 16) / 16.0f; // X Position Of Current Character
+ cy = float((loop - 256) / 16) / 16.0f; // Y Position Of Current Character
+ }
+ glNewList(base + loop, GL_COMPILE); // Start Building A List
+ glBegin(GL_QUADS); // Use A Quad For Each Character
+ glTexCoord2f(cx, 1 - cy - 0.0625f + .001); // Texture Coord (Bottom Left)
+ glVertex2i(0, 0); // Vertex Coord (Bottom Left)
+ glTexCoord2f(cx + 0.0625f, 1 - cy - 0.0625f + .001); // Texture Coord (Bottom Right)
+ glVertex2i(16, 0); // Vertex Coord (Bottom Right)
+ glTexCoord2f(cx + 0.0625f, 1 - cy - .001); // Texture Coord (Top Right)
+ glVertex2i(16, 16); // Vertex Coord (Top Right)
+ glTexCoord2f(cx, 1 - cy - +.001); // Texture Coord (Top Left)
+ glVertex2i(0, 16); // Vertex Coord (Top Left)
+ glEnd(); // Done Building Our Quad (Character)
+ if (loop < 256)
+ glTranslated(10, 0, 0); // Move To The Right Of The Character
+ else
+ glTranslated(8, 0, 0); // Move To The Right Of The Character
+ glEndList(); // Done Building The Display List
+ } // Loop Until All 256 Are Built
+}
+
+void Text::glPrint(float x, float y, const char *string, int set, float size, float width, float height) // Where The Printing Happens
+{
+ glPrint(x, y, string, set, size, width, height, 0, strlen(string));
+}
+
+void Text::_glPrint(float x, float y, const char *string, int set, float size, float width, float height, int start, int end, int offset) // Where The Printing Happens
+{
+ if (set > 1) {
+ set = 1;
+ }
+ glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+ FontTexture.bind();
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_LIGHTING);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ glOrtho(0, width, 0, height, -100, 100);
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+ glTranslated(x, y, 0);
+ glScalef(size, size, 1);
+ glListBase(base - 32 + (128 * set) + offset); // Choose The Font Set (0 or 1)
+ glCallLists(end - start, GL_BYTE, &string[start]); // Write The Text To The Screen
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ glEnable(GL_DEPTH_TEST);
+ glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+}
+
+void Text::glPrint(float x, float y, const char *string, int set, float size, float width, float height, int start, int end) // Where The Printing Happens
+{
+ _glPrint(x, y, string, set, size, width, height, start, end, 0);
+}
+
+void Text::glPrintOutline(float x, float y, const char *string, int set, float size, float width, float height) // Where The Printing Happens
+{
+ glPrintOutline(x, y, string, set, size, width, height, 0, strlen(string));
+}
+
+void Text::glPrintOutline(float x, float y, const char *string, int set, float size, float width, float height, int start, int end) // Where The Printing Happens
+{
+ _glPrint(x, y, string, set, size, width, height, start, end, 256);
+}
+void Text::glPrintOutlined(float x, float y, const char *string, int set, float size, float width, float height) // Where The Printing Happens
+{
+ glPrintOutlined(1, 1, 1, x, y, string, set, size, width, height);
+}
+
+void Text::glPrintOutlined(float r, float g, float b, float x, float y, const char *string, int set, float size, float width, float height) // Where The Printing Happens
+{
+ glColor4f(0, 0, 0, 1);
+ glPrintOutline( x - 2 * size, y - 2 * size, string, set, size * 2.5 / 2, width, height);
+ glColor4f(r, g, b, 1);
+ glPrint( x, y, string, set, size, width, height);
+}
+
+Text::Text()
+{
+ base = 0;
+}
+Text::~Text()
+{
+ if (base) {
+ glDeleteLists(base, 512);
+ base = 0;
+ }
+ FontTexture.destroy();
+}
+
--- /dev/null
+/*
+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 _TEXT_H_
+#define _TEXT_H_
+
+/**> HEADER FILES <**/
+#include "Graphic/gamegl.h"
+#include "Graphic/Texture.h"
+#include "Math/Quaternions.h"
+#include "Utils/ImageIO.h"
+
+class Text
+{
+public:
+ Texture FontTexture;
+ GLuint base;
+
+ void LoadFontTexture(const std::string& fileName);
+ void BuildFont();
+ void glPrint(float x, float y, const char *string, int set, float size, float width, float height);
+ void glPrintOutline(float x, float y, const char *string, int set, float size, float width, float height);
+ void glPrint(float x, float y, const char *string, int set, float size, float width, float height, int start, int end);
+ void glPrintOutline(float x, float y, const char *string, int set, float size, float width, float height, int start, int end);
+ void glPrintOutlined(float x, float y, const char *string, int set, float size, float width, float height);
+ void glPrintOutlined(float r, float g, float b, float x, float y, const char *string, int set, float size, float width, float height);
+
+ Text();
+ ~Text();
+
+private:
+ void _glPrint(float x, float y, const char *string, int set, float size, float width, float height, int start, int end, int offset);
+};
+
+#endif
--- /dev/null
+/*
+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/>.
+*/
+
+#include "Graphic/gamegl.h"
+#include "Graphic/Texture.h"
+#include "Utils/Folders.h"
+#include "Utils/ImageIO.h"
+
+using namespace std;
+
+extern bool trilinear;
+
+vector<TextureRes*> TextureRes::list;
+
+void TextureRes::load()
+{
+ ImageRec texture;
+
+ //load image into 'texture'
+ if (!load_image(filename.c_str(), texture)) {
+ cerr << "Texture " << filename << " loading failed" << endl;
+ return;
+ }
+
+ skinsize = texture.sizeX;
+ GLuint type = GL_RGBA;
+ if (texture.bpp == 24)
+ type = GL_RGB;
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ glDeleteTextures(1, &id);
+ glGenTextures(1, &id);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+ glBindTexture(GL_TEXTURE_2D, id);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ if (hasMipmap) {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (trilinear ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR_MIPMAP_NEAREST));
+ glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
+ } else {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ }
+
+ if (isSkin) {
+ free(data);
+ const int nb = texture.sizeY * texture.sizeX * (texture.bpp / 8);
+ data = (GLubyte*)malloc(nb * sizeof(GLubyte));
+ datalen = 0;
+ for (int i = 0; i < nb; i++)
+ if ((i + 1) % 4 || type == GL_RGB)
+ data[datalen++] = texture.data[i];
+ glTexImage2D(GL_TEXTURE_2D, 0, type, texture.sizeX, texture.sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
+ } else {
+ glTexImage2D(GL_TEXTURE_2D, 0, type, texture.sizeX, texture.sizeY, 0, type, GL_UNSIGNED_BYTE, texture.data);
+ }
+}
+
+void TextureRes::bind()
+{
+ glBindTexture(GL_TEXTURE_2D, id);
+}
+
+TextureRes::TextureRes(const string& _filename, bool _hasMipmap):
+ id(0), filename(_filename), hasMipmap(_hasMipmap), isSkin(false),
+ skinsize(0), data(NULL), datalen(0)
+{
+ load();
+ list.push_back(this);
+}
+
+TextureRes::TextureRes(const string& _filename, bool _hasMipmap, GLubyte* array, int* skinsizep):
+ id(0), filename(_filename), hasMipmap(_hasMipmap), isSkin(true),
+ skinsize(0), data(NULL), datalen(0)
+{
+ load();
+ *skinsizep = skinsize;
+ for (int i = 0; i < datalen; i++)
+ array[i] = data[i];
+ list.push_back(this);
+}
+
+TextureRes::~TextureRes()
+{
+ free(data);
+ glDeleteTextures(1, &id);
+ for (vector<TextureRes*>::iterator it = list.begin(); it != list.end(); it++)
+ if (*it == this) {
+ list.erase(it);
+ break;
+ }
+}
+
+void Texture::load(const string& filename, bool hasMipmap)
+{
+ destroy();
+ tex = new TextureRes(Folders::getResourcePath(filename), hasMipmap);
+}
+
+void Texture::load(const string& filename, bool hasMipmap, GLubyte* array, int* skinsizep)
+{
+ destroy();
+ tex = new TextureRes(Folders::getResourcePath(filename), hasMipmap, array, skinsizep);
+}
+
+void Texture::destroy()
+{
+ if (tex) {
+ delete tex;
+ tex = NULL;
+ }
+}
+
+void Texture::bind()
+{
+ if (tex)
+ tex->bind();
+ else
+ glBindTexture(GL_TEXTURE_2D, 0);
+}
--- /dev/null
+/*
+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 _TEXTURE_H_
+#define _TEXTURE_H_
+
+#include <map>
+#include <vector>
+#include <string>
+using namespace std;
+
+class TextureRes
+{
+private:
+ static vector<TextureRes*> list;
+
+ GLuint id;
+ string filename;
+ bool hasMipmap;
+ bool isSkin;
+ int skinsize;
+ GLubyte* data;
+ int datalen;
+
+ void load();
+
+public:
+ TextureRes(const string& filename, bool hasMipmap);
+ TextureRes(const string& filename, bool hasMipmap, GLubyte* array, int* skinsize);
+ ~TextureRes();
+ void bind();
+};
+
+class Texture
+{
+private:
+ TextureRes* tex;
+public:
+ inline Texture(): tex(NULL) {}
+ void load(const string& filename, bool hasMipmap);
+ void load(const string& filename, bool hasMipmap, GLubyte* array, int* skinsizep);
+ void destroy();
+ void bind();
+};
+
+#endif
--- /dev/null
+/*
+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 _LUGARU_GL_H_
+#define _LUGARU_GL_H_
+
+
+#include <cstring>
+#include <iostream>
+#include <fstream>
+#include <algorithm>
+#include <map>
+#include <string>
+
+#ifdef WIN32
+ #define WIN32_LEAN_AND_MEAN
+ #define Polygon WinPolygon
+ #include <windows.h>
+ #undef Polygon
+#endif
+
+#define GL_GLEXT_PROTOTYPES 1
+#include "GL/gl.h"
+#include "GL/glu.h"
+#include "GL/glext.h"
+#include "MacCompatibility.h"
+
+using namespace std;
+
+/* !!! FIXME: until we replace logger better. --ryan. */
+#define LOGFUNC
+void LOG(const std::string &fmt, ...);
+
+#endif
+
+
+++ /dev/null
-/*
-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 "Hotspot.h"
-
-std::vector<Hotspot> Hotspot::hotspots;
-int Hotspot::current = 0;
-int Hotspot::killhotspot = 0;
-
-Hotspot::Hotspot() :
- position(),
- type(0),
- size(0)
-{
-}
-
-Hotspot::Hotspot(XYZ p, int t, float s) :
- position(p),
- type(t),
- size(s)
-{
-}
+++ /dev/null
-/*
-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 _HOTSPOT_H_
-#define _HOTSPOT_H_
-
-#include "Quaternions.h"
-#include <vector>
-
-class Hotspot
-{
-public:
- static std::vector<Hotspot> hotspots;
- static int current;
- static int killhotspot;
-
- Hotspot();
- Hotspot(XYZ position, int type, float size);
-
- XYZ position;
- int type;
- float size;
- char text[256] = {0};
-};
-
-#endif
+++ /dev/null
-/*
-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 <stdio.h>
-#include <jpeglib.h>
-#include <png.h>
-#include <zlib.h>
-
-#include "Game.h"
-#include "ImageIO.h"
-#include "Utils/Folders.h"
-
-extern bool visibleloading;
-
-/* These two are needed for screenshot */
-extern int kContextWidth;
-extern int kContextHeight;
-
-static bool load_png(const char * fname, ImageRec & tex);
-static bool load_jpg(const char * fname, ImageRec & tex);
-static bool save_screenshot_png(const char * fname);
-
-ImageRec::ImageRec()
-{
- data = ( GLubyte* )malloc( 1024 * 1024 * 4 );
-}
-
-ImageRec::~ImageRec()
-{
- free(data);
- data = NULL;
-}
-
-bool load_image(const char *file_name, ImageRec &tex)
-{
- if (visibleloading)
- Game::LoadingScreen();
-
- if ( tex.data == NULL )
- return false;
-
- const char *ptr = strrchr((char *)file_name, '.');
- if (ptr) {
- if (strcasecmp(ptr + 1, "png") == 0)
- return load_png(file_name, tex);
- else if (strcasecmp(ptr + 1, "jpg") == 0)
- return load_jpg(file_name, tex);
- }
-
- STUBBED("Unsupported image type");
- return false;
-}
-
-bool save_screenshot(const char *file_name)
-{
- const char *ptr = strrchr((char *)file_name, '.');
- if (ptr) {
- if (strcasecmp(ptr + 1, "png") == 0)
- return save_screenshot_png((Folders::getScreenshotDir() + '/' + file_name).c_str());
- }
-
- STUBBED("Unsupported image type");
- return false;
-}
-
-struct my_error_mgr {
- struct jpeg_error_mgr pub; /* "public" fields */
- jmp_buf setjmp_buffer; /* for return to caller */
-};
-typedef struct my_error_mgr * my_error_ptr;
-
-static void my_error_exit(j_common_ptr cinfo)
-{
- struct my_error_mgr *err = (struct my_error_mgr *)cinfo->err;
- longjmp(err->setjmp_buffer, 1);
-}
-
-/* stolen from public domain example.c code in libjpg distribution. */
-static bool load_jpg(const char *file_name, ImageRec &tex)
-{
- struct jpeg_decompress_struct cinfo;
- struct my_error_mgr jerr;
- JSAMPROW buffer[1]; /* Output row buffer */
- int row_stride; /* physical row width in output buffer */
- FILE *infile = fopen(file_name, "rb");
-
- if (infile == NULL)
- return false;
-
- cinfo.err = jpeg_std_error(&jerr.pub);
- jerr.pub.error_exit = my_error_exit;
- if (setjmp(jerr.setjmp_buffer)) {
- jpeg_destroy_decompress(&cinfo);
- fclose(infile);
- return false;
- }
-
- jpeg_create_decompress(&cinfo);
- jpeg_stdio_src(&cinfo, infile);
- (void) jpeg_read_header(&cinfo, TRUE);
-
- cinfo.out_color_space = JCS_RGB;
- cinfo.quantize_colors = 0;
- (void) jpeg_calc_output_dimensions(&cinfo);
- (void) jpeg_start_decompress(&cinfo);
-
- row_stride = cinfo.output_width * cinfo.output_components;
- tex.sizeX = cinfo.output_width;
- tex.sizeY = cinfo.output_height;
- tex.bpp = 24;
-
- while (cinfo.output_scanline < cinfo.output_height) {
- buffer[0] = (JSAMPROW)(char *)tex.data +
- ((cinfo.output_height - 1) - cinfo.output_scanline) * row_stride;
- (void) jpeg_read_scanlines(&cinfo, buffer, 1);
- }
-
- (void) jpeg_finish_decompress(&cinfo);
- jpeg_destroy_decompress(&cinfo);
- fclose(infile);
-
- return true;
-}
-
-/* stolen from public domain example.c code in libpng distribution. */
-static bool load_png(const char *file_name, ImageRec &tex)
-{
- bool hasalpha = false;
- png_structp png_ptr = NULL;
- png_infop info_ptr = NULL;
- png_uint_32 width, height;
- int bit_depth, color_type, interlace_type;
- bool retval = false;
- png_byte **row_pointers = NULL;
- FILE *fp = fopen(file_name, "rb");
-
- if (fp == NULL) {
- cerr << file_name << " not found" << endl;
- return false;
- }
-
- png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
- if (png_ptr == NULL)
- goto png_done;
-
- info_ptr = png_create_info_struct(png_ptr);
- if (info_ptr == NULL)
- goto png_done;
-
- if (setjmp(png_jmpbuf(png_ptr)))
- goto png_done;
-
- png_init_io(png_ptr, fp);
- png_read_png(png_ptr, info_ptr,
- PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING,
- NULL);
- png_get_IHDR(png_ptr, info_ptr, &width, &height,
- &bit_depth, &color_type, &interlace_type, NULL, NULL);
-
- if (bit_depth != 8) // transform SHOULD handle this...
- goto png_done;
-
- if (color_type & PNG_COLOR_MASK_PALETTE) // !!! FIXME?
- goto png_done;
-
- if ((color_type & PNG_COLOR_MASK_COLOR) == 0) // !!! FIXME?
- goto png_done;
-
- hasalpha = ((color_type & PNG_COLOR_MASK_ALPHA) != 0);
- row_pointers = png_get_rows(png_ptr, info_ptr);
- if (!row_pointers)
- goto png_done;
-
- if (!hasalpha) {
- png_byte *dst = tex.data;
- for (int i = height - 1; i >= 0; i--) {
- png_byte *src = row_pointers[i];
- for (unsigned j = 0; j < width; j++) {
- dst[0] = src[0];
- dst[1] = src[1];
- dst[2] = src[2];
- dst[3] = 0xFF;
- src += 3;
- dst += 4;
- }
- }
- }
-
- else {
- png_byte *dst = tex.data;
- int pitch = width * 4;
- for (int i = height - 1; i >= 0; i--, dst += pitch)
- memcpy(dst, row_pointers[i], pitch);
- }
-
- tex.sizeX = width;
- tex.sizeY = height;
- tex.bpp = 32;
- retval = true;
-
-png_done:
- if (!retval) {
- cerr << "There was a problem loading " << file_name << endl;
- }
- png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
- if (fp)
- fclose(fp);
- return (retval);
-}
-
-static bool save_screenshot_png(const char *file_name)
-{
- FILE *fp = NULL;
- png_structp png_ptr = NULL;
- png_infop info_ptr = NULL;
- bool retval = false;
-
- fp = fopen(file_name, "wb");
- if (fp == NULL)
- return false;
-
- png_bytep *row_pointers = new png_bytep[kContextHeight];
- png_bytep screenshot = new png_byte[kContextWidth * kContextHeight * 3];
- if ((!screenshot) || (!row_pointers))
- goto save_png_done;
-
- glGetError();
- glReadPixels(0, 0, kContextWidth, kContextHeight,
- GL_RGB, GL_UNSIGNED_BYTE, screenshot);
- if (glGetError() != GL_NO_ERROR)
- goto save_png_done;
-
- for (int i = 0; i < kContextHeight; i++)
- row_pointers[i] = screenshot + ((kContextWidth * ((kContextHeight - 1) - i)) * 3);
-
- png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
- if (png_ptr == NULL)
- goto save_png_done;
-
- info_ptr = png_create_info_struct(png_ptr);
- if (info_ptr == NULL)
- goto save_png_done;
-
- if (setjmp(png_jmpbuf(png_ptr)))
- goto save_png_done;
-
- png_init_io(png_ptr, fp);
-
- if (setjmp(png_jmpbuf(png_ptr)))
- goto save_png_done;
-
- png_set_IHDR(png_ptr, info_ptr, kContextWidth, kContextHeight,
- 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
- PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
-
- png_write_info(png_ptr, info_ptr);
-
- if (setjmp(png_jmpbuf(png_ptr)))
- goto save_png_done;
-
- png_write_image(png_ptr, row_pointers);
-
- if (setjmp(png_jmpbuf(png_ptr)))
- goto save_png_done;
-
- png_write_end(png_ptr, NULL);
- retval = true;
-
-save_png_done:
- png_destroy_write_struct(&png_ptr, &info_ptr);
- delete[] screenshot;
- delete[] row_pointers;
- if (fp)
- fclose(fp);
- if (!retval)
- unlink(file_name);
- return retval;
-}
+++ /dev/null
-/*
-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 _IMAGE_IO_H_
-#define _IMAGE_IO_H_
-
-#ifdef _MSC_VER
-#pragma once
-#endif
-
-
-/**> HEADER FILES <**/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#ifdef WIN32
-#define WIN32_LEAN_AND_MEAN
-#define Polygon WinPolygon
-#include <windows.h>
-#undef Polygon
-#include "GL/gl.h"
-#else
-#include "gamegl.h"
-#endif
-
-/**> DATA STRUCTURES <**/
-class ImageRec {
-public:
- GLubyte *data; // Image Data (Up To 32 Bits)
- GLuint bpp; // Image Color Depth In Bits Per Pixel.
- GLuint sizeX;
- GLuint sizeY;
- ImageRec();
- ~ImageRec();
-private:
- /* Make sure this class cannot be copied to avoid memory problems */
- ImageRec(ImageRec const &);
- ImageRec& operator=(ImageRec const &);
-};
-
-bool load_image(const char * fname, ImageRec & tex);
-bool save_screenshot(const char * fname);
-
-#endif
-
+++ /dev/null
-/*
-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 "Input.h"
-
-bool keyDown[SDL_NUM_SCANCODES + 6];
-bool keyPressed[SDL_NUM_SCANCODES + 6];
-
-void Input::Tick()
-{
- SDL_PumpEvents();
- int numkeys;
- const Uint8 *keyState = SDL_GetKeyboardState(&numkeys);
- for (int i = 0; i < numkeys; i++) {
- keyPressed[i] = !keyDown[i] && keyState[i];
- keyDown[i] = keyState[i];
- }
- Uint8 mb = SDL_GetMouseState(NULL, NULL);
- for (int i = 1; i < 6; i++) {
- keyPressed[SDL_NUM_SCANCODES + i] = !keyDown[SDL_NUM_SCANCODES + i] && (mb & SDL_BUTTON(i));
- keyDown[SDL_NUM_SCANCODES + i] = (mb & SDL_BUTTON(i));
- }
-}
-
-bool Input::isKeyDown(int k)
-{
- if (k >= SDL_NUM_SCANCODES + 6) // really useful? check that.
- return false;
- return keyDown[k];
-}
-
-bool Input::isKeyPressed(int k)
-{
- if (k >= SDL_NUM_SCANCODES + 6)
- return false;
- return keyPressed[k];
-}
-
-const char* Input::keyToChar(unsigned short i)
-{
- if (i < SDL_NUM_SCANCODES)
- return SDL_GetScancodeName(SDL_Scancode(i));
- else if (i == MOUSEBUTTON1)
- return "mouse1";
- else if (i == MOUSEBUTTON2)
- return "mouse2";
- else if (i == MOUSEBUTTON3)
- return "mouse3";
- else
- return "unknown";
-}
-
-unsigned short Input::CharToKey(const char* which)
-{
- for (unsigned short i = 0; i < SDL_NUM_SCANCODES; i++) {
- if (!strcasecmp(which, SDL_GetScancodeName(SDL_Scancode(i))))
- return i;
- }
- if (!strcasecmp(which, "mouse1")) {
- return MOUSEBUTTON1;
- }
- if (!strcasecmp(which, "mouse2")) {
- return MOUSEBUTTON2;
- }
- if (!strcasecmp(which, "mouse3")) {
- return MOUSEBUTTON3;
- }
- return SDL_NUM_SCANCODES;
-}
-
-bool Input::MouseClicked()
-{
- return isKeyPressed(SDL_NUM_SCANCODES + SDL_BUTTON_LEFT);
-}
+++ /dev/null
-/*
-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 _Input_H_
-#define _Input_H_
-
-/**> HEADER FILES <**/
-#include "SDL.h"
-#include "Game.h"
-
-/**> CONSTANT DECLARATIONS <**/
-#define MOUSEBUTTON1 (SDL_NUM_SCANCODES + SDL_BUTTON_LEFT)
-#define MOUSEBUTTON2 (SDL_NUM_SCANCODES + SDL_BUTTON_RIGHT)
-#define MOUSEBUTTON3 (SDL_NUM_SCANCODES + SDL_BUTTON_MIDDLE)
-
-/**> FUNCTION PROTOTYPES <**/
-class Input
-{
-public:
- static void Tick();
- static bool isKeyDown(int k);
- static bool isKeyPressed(int k);
- static const char* keyToChar(unsigned short which);
- static unsigned short CharToKey(const char* which);
- static bool MouseClicked();
-};
-
-#endif
--- /dev/null
+/*
+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 "Level/Awards.h"
+#include "Objects/Person.h"
+#include "Game.h"
+
+int bonus;
+float bonusvalue;
+float bonustotal;
+float startbonustotal;
+float bonustime;
+float bonusnum[100];
+
+const char *bonus_names[bonus_count] = {
+#define DECLARE_BONUS(id, name, ...) name,
+#include "Bonuses.def"
+#undef DECLARE_BONUS
+};
+
+const char *award_names[award_count] = {
+#define DECLARE_AWARD(id, name) name,
+#include "Awards.def"
+#undef DECLARE_AWARD
+};
+
+static const int bonus_values[bonus_count] = {
+#define DECLARE_BONUS(id, name, value) value,
+#include "Bonuses.def"
+#undef DECLARE_BONUS
+};
+
+void
+award_bonus(int playerid, int bonusid, int alt_value)
+{
+ if (playerid != 0)
+ return;
+ bonus = bonusid;
+ bonustime = 0;
+ bonusvalue = alt_value ? alt_value : bonus_values[bonusid];
+}
+
+// FIXME: make these per-player
+float damagetaken;
+int numfalls;
+int numflipfail;
+int numseen;
+int numresponded;
+int numstaffattack;
+int numswordattack;
+int numknifeattack;
+int numunarmedattack;
+int numescaped;
+int numflipped;
+int numwallflipped;
+int numthrowkill;
+int numafterkill;
+int numreversals;
+int numattacks;
+int maxalarmed;
+
+int award_awards(int *awards)
+{
+ int numawards = 0;
+ if (damagetaken == 0 && Person::players[0]->bloodloss == 0) {
+ awards[numawards] = awardflawless;
+ numawards++;
+ }
+ bool alldead = true;
+ for (unsigned i = 1; i < Person::players.size(); i++) {
+ if (Person::players[i]->dead != 2)
+ alldead = 0;
+ }
+ if (alldead) {
+ awards[numawards] = awardalldead;
+ numawards++;
+ }
+ alldead = 1;
+ for (unsigned i = 1; i < Person::players.size(); i++) {
+ if (Person::players[i]->dead != 1)
+ alldead = 0;
+ }
+ if (alldead) {
+ awards[numawards] = awardnodead;
+ numawards++;
+ }
+ if (numresponded == 0 && !numthrowkill) {
+ awards[numawards] = awardstealth;
+ numawards++;
+ }
+ if (numattacks == numstaffattack && numattacks > 0) {
+ awards[numawards] = awardbojutsu;
+ numawards++;
+ }
+ if (numattacks == numswordattack && numattacks > 0) {
+ awards[numawards] = awardswordsman;
+ numawards++;
+ }
+ if (numattacks == numknifeattack && numattacks > 0) {
+ awards[numawards] = awardknifefighter;
+ numawards++;
+ }
+ if (numattacks == numunarmedattack && numthrowkill == 0 && weapons.size() > 0) {
+ awards[numawards] = awardkungfu;
+ numawards++;
+ }
+ if (numescaped > 0) {
+ awards[numawards] = awardevasion;
+ numawards++;
+ }
+ if (numflipfail == 0 && numflipped + numwallflipped * 2 > 20) {
+ awards[numawards] = awardacrobat;
+ numawards++;
+ }
+ if (numthrowkill == (int(Person::players.size()) - 1)) {
+ awards[numawards] = awardlongrange;
+ numawards++;
+ }
+ alldead = 1;
+ for (unsigned i = 1; i < Person::players.size(); i++) {
+ if (Person::players[i]->dead != 2)
+ alldead = 0;
+ }
+ if (numafterkill > 0 && alldead) {
+ awards[numawards] = awardbrutal;
+ numawards++;
+ }
+ if (numreversals > ((float)numattacks)*.8 && numreversals > 3) {
+ awards[numawards] = awardaikido;
+ numawards++;
+ }
+ if (maxalarmed == 1 && Person::players.size() > 2) {
+ awards[numawards] = awardstrategy;
+ numawards++;
+ }
+ if (numflipfail > 3) {
+ awards[numawards] = awardklutz;
+ numawards++;
+ }
+ return numawards;
+}
--- /dev/null
+/*
+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/>.
+*/
+
+DECLARE_AWARD(awardklutz, "Suicidal")
+DECLARE_AWARD(awardflawless, "Flawless!")
+DECLARE_AWARD(awardalldead, "Take no prisoners")
+DECLARE_AWARD(awardnodead, "Merciful")
+DECLARE_AWARD(awardstealth, "One with the shadows!")
+DECLARE_AWARD(awardswordsman, "Swordsman")
+DECLARE_AWARD(awardkungfu, "Unarmed!")
+DECLARE_AWARD(awardknifefighter, "Knife fighter")
+DECLARE_AWARD(awardcoward, "Coward")
+DECLARE_AWARD(awardevasion, "Escape artist")
+DECLARE_AWARD(awardacrobat, "Gymnast")
+DECLARE_AWARD(awardlongrange, "Blade slinger")
+DECLARE_AWARD(awardbrutal, "Brutal")
+DECLARE_AWARD(awardhyper, "Hyper")
+DECLARE_AWARD(awardaikido, "Aikido master!")
+DECLARE_AWARD(awardrambo, "Rambo")
+DECLARE_AWARD(awardfast, "Fast")
+DECLARE_AWARD(awardrealfast, "Real fast")
+DECLARE_AWARD(awarddamnfast, "Damn fast")
+DECLARE_AWARD(awardstrategy, "Divide and conquer")
+DECLARE_AWARD(awardbojutsu, "Bojutsu")
--- /dev/null
+/*
+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 AWARDS_H
+#define AWARDS_H
+
+enum bonus_types {
+#define DECLARE_BONUS(id, ...) id,
+#include "Bonuses.def"
+#undef DECLARE_BONUS
+ bonus_count
+};
+
+extern const char *bonus_names[bonus_count];
+
+extern int bonus;
+extern float bonusvalue;
+extern float bonustotal;
+extern float bonustime;
+extern float startbonustotal;
+extern float bonusnum[100];
+
+extern void award_bonus(int playerid, int bonusid, int alt_value = 0);
+
+enum award_types {
+#define DECLARE_AWARD(id, name) id,
+#include "Awards.def"
+#undef DECLARE_AWARD
+ award_count
+};
+
+extern const char *award_names[award_count];
+
+extern int award_awards(int *);
+
+extern float damagetaken;
+extern int numfalls;
+extern int numflipfail;
+extern int numseen;
+extern int numresponded;
+extern int numstaffattack;
+extern int numswordattack;
+extern int numknifeattack;
+extern int numunarmedattack;
+extern int numescaped;
+extern int numflipped;
+extern int numwallflipped;
+extern int numthrowkill;
+extern int numafterkill;
+extern int numreversals;
+extern int numattacks;
+extern int maxalarmed;
+#endif
+
--- /dev/null
+/*
+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/>.
+*/
+
+DECLARE_BONUS(nobonus, "", 0)
+DECLARE_BONUS(tracheotomy, "Tracheotomy!", 100)
+DECLARE_BONUS(backstab, "Backstabber!", 100)
+DECLARE_BONUS(spinecrusher, "Spinecrusher!", 100)
+DECLARE_BONUS(ninja, "Ninja Bonus!", 60)
+DECLARE_BONUS(style, "Style Bonus!", 150)
+DECLARE_BONUS(cannon, "Leg Cannon!", 100)
+DECLARE_BONUS(aimbonus, "Nice Aim!", 150)
+DECLARE_BONUS(deepimpact, "Heavy Impact!", 50)
+DECLARE_BONUS(touchofdeath, "Touch of Death!", 150)
+DECLARE_BONUS(swordreversebonus, "Sword Disarm!", 100)
+DECLARE_BONUS(staffreversebonus, "Staff Disarm!", 100)
+DECLARE_BONUS(reverseko, "Reversal KO!", 100)
+// The following five should be kept in that order
+DECLARE_BONUS(solidhit, "Solid Hit!", 10)
+DECLARE_BONUS(twoxcombo, "2X Combo!", 20)
+DECLARE_BONUS(threexcombo, "3X Combo!", 40)
+DECLARE_BONUS(fourxcombo, "4X COMBO!", 80)
+DECLARE_BONUS(megacombo, "MEGA COMBO!", 160)
+DECLARE_BONUS(Reversal, "Reversal!", 60)
+DECLARE_BONUS(Stabbonus, "Punctured!", 40)
+DECLARE_BONUS(Slicebonus, "Sliced!", 10)
+DECLARE_BONUS(Bullseyebonus, "Bullseye!", 30)
+DECLARE_BONUS(Slashbonus, "Slashed!", 40)
+DECLARE_BONUS(Wolfbonus, "WOLF SLAYER!", 300)
+DECLARE_BONUS(FinishedBonus, "SLAIN!", 200)
+DECLARE_BONUS(TackleBonus, "Tackle!", 5)
+DECLARE_BONUS(AboveBonus, "Death from Above!", 50)
--- /dev/null
+/*
+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/>.
+*/
+
+#include "Game.h"
+#include "Level/Campaign.h"
+#include "Utils/Folders.h"
+
+#include <dirent.h>
+
+using namespace Game;
+
+std::vector<CampaignLevel> campaignlevels;
+
+bool campaign = false;
+
+int actuallevel = 0;
+
+std::vector<std::string> ListCampaigns()
+{
+ errno = 0;
+ DIR *campaigns = opendir(Folders::getResourcePath("Campaigns").c_str());
+ struct dirent *campaign = NULL;
+ if (!campaigns) {
+ perror(("Problem while loading campaigns from " + Folders::getResourcePath("Campaigns")).c_str());
+ exit(EXIT_FAILURE);
+ }
+ std::vector<std::string> campaignNames;
+ while ((campaign = readdir(campaigns)) != NULL) {
+ std::string name(campaign->d_name);
+ if (name.length() < 5)
+ continue;
+ if (!name.compare(name.length() - 4, 4, ".txt")) {
+ campaignNames.push_back(name.substr(0, name.length() - 4));
+ }
+ }
+ closedir(campaigns);
+ return campaignNames;
+}
+
+void LoadCampaign()
+{
+ if (!Account::hasActive()) {
+ return;
+ }
+ std::ifstream ipstream(Folders::getResourcePath("Campaigns/" + Account::active().getCurrentCampaign() + ".txt"));
+ if (!ipstream.good()) {
+ if (Account::active().getCurrentCampaign() == "main") {
+ cerr << "Could not found main campaign!" << endl;
+ return;
+ }
+ cerr << "Could not found campaign \"" << Account::active().getCurrentCampaign() << "\", falling back to main." << endl;
+ Account::active().setCurrentCampaign("main");
+ return LoadCampaign();
+ }
+ ipstream.ignore(256, ':');
+ int numlevels;
+ ipstream >> numlevels;
+ campaignlevels.clear();
+ for (int i = 0; i < numlevels; i++) {
+ CampaignLevel cl;
+ ipstream >> cl;
+ campaignlevels.push_back(cl);
+ }
+ ipstream.close();
+
+ std::ifstream test(Folders::getResourcePath("Textures/" + Account::active().getCurrentCampaign() + "/World.png"));
+ if (test.good()) {
+ Mainmenuitems[7].load("Textures/" + Account::active().getCurrentCampaign() + "/World.png", 0);
+ } else {
+ Mainmenuitems[7].load("Textures/World.png", 0);
+ }
+
+ if (Account::active().getCampaignChoicesMade() == 0) {
+ Account::active().setCampaignScore(0);
+ Account::active().resetFasttime();
+ }
+}
+
+CampaignLevel::CampaignLevel() :
+ width(10),
+ choosenext(1)
+{
+ location.x = 0;
+ location.y = 0;
+}
+
+int CampaignLevel::getStartX() {
+ return 30 + 120 + location.x * 400 / 512;
+}
+
+int CampaignLevel::getStartY() {
+ return 30 + 30 + (512 - location.y) * 400 / 512;
+}
+
+int CampaignLevel::getEndX() {
+ return getStartX() + width;
+}
+
+int CampaignLevel::getEndY() {
+ return getStartY() + width;
+}
+
+XYZ CampaignLevel::getCenter() {
+ XYZ center;
+ center.x = getStartX() + width / 2;
+ center.y = getStartY() + width / 2;
+ return center;
+}
+
+int CampaignLevel::getWidth() {
+ return width;
+}
+
+istream& CampaignLevel::operator<< (istream& is) {
+ is.ignore(256, ':');
+ is.ignore(256, ':');
+ is.ignore(256, ' ');
+ is >> mapname;
+ is.ignore(256, ':');
+ is >> description;
+ for (size_t pos = description.find('_'); pos != string::npos; pos = description.find('_', pos)) {
+ description.replace(pos, 1, 1, ' ');
+ }
+ is.ignore(256, ':');
+ is >> choosenext;
+ is.ignore(256, ':');
+ int numnext, next;
+ is >> numnext;
+ for (int j = 0; j < numnext; j++) {
+ is.ignore(256, ':');
+ is >> next;
+ nextlevel.push_back(next - 1);
+ }
+ is.ignore(256, ':');
+ is >> location.x;
+ is.ignore(256, ':');
+ is >> location.y;
+ return is;
+}
--- /dev/null
+/*
+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/>.
+*/
+
+#include <vector>
+#include <string>
+
+#include "Math/Quaternions.h"
+
+extern bool campaign;
+
+extern int actuallevel;
+
+std::vector<std::string> ListCampaigns();
+void LoadCampaign();
+
+class CampaignLevel
+{
+private:
+ int width;
+ struct Position {
+ int x, y;
+ };
+public:
+ std::string mapname;
+ std::string description;
+ int choosenext;
+ /*
+ 0 = Immediately load next level at the end of this one.
+ 1 = Go back to the world map.
+ 2 = Don't bring up the Fiery loading screen. Maybe other things, I've not investigated.
+ */
+ //int numnext; // 0 on final level. As David said: he meant to add story branching, but he eventually hadn't.
+ std::vector<int> nextlevel;
+ Position location;
+ CampaignLevel();
+ int getStartX();
+ int getStartY();
+ int getEndX();
+ int getEndY();
+ XYZ getCenter();
+ int getWidth();
+ std::istream& operator<< (std::istream& is);
+ friend std::istream& operator>> (std::istream& is, CampaignLevel& cl) {
+ return cl << is;
+ }
+};
+
+extern std::vector<CampaignLevel> campaignlevels;
--- /dev/null
+/*
+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/>.
+*/
+
+#include "Game.h"
+
+#include "Level/Dialog.h"
+#include "Objects/Person.h"
+#include "Utils/binio.h"
+#include "Utils/Folders.h"
+#include "Utils/Input.h"
+
+extern int hostile;
+
+int Dialog::indialogue;
+int Dialog::whichdialogue;
+bool Dialog::directing;
+float Dialog::dialoguetime;
+std::vector<Dialog> Dialog::dialogs;
+
+void Dialog::loadDialogs(FILE* tfile)
+{
+ int numdialogues;
+ funpackf(tfile, "Bi", &numdialogues);
+ for (int k = 0; k < numdialogues; k++) {
+ dialogs.push_back(Dialog(tfile));
+ }
+}
+
+Dialog::Dialog(FILE* tfile) : gonethrough(0)
+{
+ int numdialogscenes;
+ funpackf(tfile, "Bi", &numdialogscenes);
+ funpackf(tfile, "Bi", &type);
+ for (int l = 0; l < 10; l++) {
+ funpackf(tfile, "Bf Bf Bf", &participantlocation[l].x, &participantlocation[l].y, &participantlocation[l].z);
+ funpackf(tfile, "Bf", &participantyaw[l]);
+ }
+ for (int l = 0; l < numdialogscenes; l++) {
+ scenes.push_back(DialogScene(tfile));
+ }
+}
+
+std::string funpackf_string(FILE* tfile, int maxlength)
+{
+ int templength;
+ funpackf(tfile, "Bi", &templength);
+ if ((templength > maxlength) || (templength <= 0)) {
+ templength = maxlength;
+ }
+ int m;
+ char* text = new char[maxlength];
+ for (m = 0; m < templength; m++) {
+ funpackf(tfile, "Bb", &text[m]);
+ if (text[m] == '\0')
+ break;
+ }
+ text[m] = 0;
+ std::string result(text);
+ delete[] text;
+ return result;
+}
+
+void fpackf_string(FILE* tfile, std::string text)
+{
+ fpackf(tfile, "Bi", text.size());
+ for (int m = 0; m < text.size(); m++) {
+ fpackf(tfile, "Bb", text[m]);
+ if (text[m] == '\0')
+ break;
+ }
+}
+
+DialogScene::DialogScene(FILE* tfile)
+{
+ funpackf(tfile, "Bi", &location);
+ funpackf(tfile, "Bf", &color[0]);
+ funpackf(tfile, "Bf", &color[1]);
+ funpackf(tfile, "Bf", &color[2]);
+ funpackf(tfile, "Bi", &sound);
+
+ text = funpackf_string(tfile, 128);
+ name = funpackf_string(tfile, 64);
+
+ funpackf(tfile, "Bf Bf Bf", &camera.x, &camera.y, &camera.z);
+ funpackf(tfile, "Bi", &participantfocus);
+ funpackf(tfile, "Bi", &participantaction);
+
+ for (int m = 0; m < 10; m++)
+ funpackf(tfile, "Bf Bf Bf", &participantfacing[m].x, &participantfacing[m].y, &participantfacing[m].z);
+
+ funpackf(tfile, "Bf Bf", &camerayaw, &camerapitch);
+}
+
+/* Load dialog from txt file, used by console */
+Dialog::Dialog(int type, std::string filename) : type(type)
+{
+ ifstream ipstream(Folders::getResourcePath(filename));
+ ipstream.ignore(256, ':');
+ int numscenes;
+ ipstream >> numscenes;
+ for (int i = 0; i < numscenes; i++) {
+ scenes.push_back(DialogScene(ipstream));
+ for (unsigned j = 0; j < Person::players.size(); j++) {
+ scenes.back().participantfacing[j] = Person::players[j]->facing;
+ }
+ }
+ ipstream.close();
+}
+
+DialogScene::DialogScene(ifstream &ipstream)
+{
+ ipstream.ignore(256, ':');
+ ipstream.ignore(256, ':');
+ ipstream.ignore(256, ' ');
+ ipstream >> location;
+ ipstream.ignore(256, ':');
+ ipstream >> color[0];
+ ipstream >> color[1];
+ ipstream >> color[2];
+ ipstream.ignore(256, ':');
+ getline(ipstream, name);
+ ipstream.ignore(256, ':');
+ ipstream.ignore(256, ' ');
+ getline(ipstream, text);
+ for (int j = 0; j < 128; j++) {
+ if (text[j] == '\\')
+ text[j] = '\n';
+ }
+ ipstream.ignore(256, ':');
+ ipstream >> sound;
+}
+
+void Dialog::tick(int id)
+{
+ unsigned playerId = type % 10;
+ bool special = (type > 9);
+
+ if ((!hostile || (type > 40) && (type < 50)) &&
+ (playerId < Person::players.size()) &&
+ (playerId > 0) &&
+ ((gonethrough == 0) || !special) &&
+ (special || Input::isKeyPressed(Game::attackkey))) {
+ if ((distsq(&Person::players[0]->coords, &Person::players[playerId]->coords) < 6) ||
+ (Person::players[playerId]->howactive >= typedead1) ||
+ (type > 40) && (type < 50)) {
+ whichdialogue = id;
+ play();
+ dialoguetime = 0;
+ gonethrough++;
+ }
+ }
+}
+
+void Dialog::play()
+{
+ for (int i = 0; i < scenes.size(); i++) {
+ int playerId = scenes[i].participantfocus;
+ Person::players[playerId]->coords = participantlocation[playerId];
+ Person::players[playerId]->yaw = participantyaw[playerId];
+ Person::players[playerId]->targetyaw = participantyaw[playerId];
+ Person::players[playerId]->velocity = 0;
+ Person::players[playerId]->animTarget = Person::players[playerId]->getIdle();
+ Person::players[playerId]->frameTarget = 0;
+ }
+
+ Dialog::directing = false;
+ Dialog::indialogue = 0;
+
+ if (scenes[indialogue].sound != 0) {
+ Game::playdialoguescenesound();
+ }
+}
+
+void Dialog::saveDialogs(FILE* tfile)
+{
+ fpackf(tfile, "Bi", dialogs.size());
+
+ for (int k = 0; k < dialogs.size(); k++) {
+ dialogs[k].save(tfile);
+ }
+}
+
+void Dialog::save(FILE* tfile)
+{
+ fpackf(tfile, "Bi", scenes.size());
+ fpackf(tfile, "Bi", type);
+ for (int l = 0; l < 10; l++) {
+ fpackf(tfile, "Bf Bf Bf", participantlocation[l].x, participantlocation[l].y, participantlocation[l].z);
+ fpackf(tfile, "Bf", participantyaw[l]);
+ }
+ for (int l = 0; l < scenes.size(); l++) {
+ scenes[l].save(tfile);
+ }
+}
+
+void DialogScene::save(FILE* tfile)
+{
+ fpackf(tfile, "Bi", location);
+ fpackf(tfile, "Bf", color[0]);
+ fpackf(tfile, "Bf", color[1]);
+ fpackf(tfile, "Bf", color[2]);
+ fpackf(tfile, "Bi", sound);
+
+ fpackf_string(tfile, text);
+ fpackf_string(tfile, name);
+
+ fpackf(tfile, "Bf Bf Bf", camera.x, camera.y, camera.z);
+ fpackf(tfile, "Bi", participantfocus);
+ fpackf(tfile, "Bi", participantaction);
+
+ for (int m = 0; m < 10; m++)
+ fpackf(tfile, "Bf Bf Bf", participantfacing[m].x, participantfacing[m].y, participantfacing[m].z);
+
+ fpackf(tfile, "Bf Bf", camerayaw, camerapitch);
+}
--- /dev/null
+/*
+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 _DIALOG_H_
+#define _DIALOG_H_
+
+#include "stdio.h"
+#include <vector>
+
+#include "Math/Quaternions.h"
+
+class DialogScene
+{
+public:
+ DialogScene(FILE* tfile);
+ DialogScene(ifstream &ipstream);
+ void save(FILE* tfile);
+
+ int location;
+ float color[3];
+ int sound;
+ std::string text;
+ std::string name;
+ XYZ camera;
+ float camerayaw;
+ float camerapitch;
+ int participantfocus;
+ int participantaction;
+ XYZ participantfacing[10];
+};
+
+class Dialog
+{
+public:
+ Dialog(FILE* tfile);
+ Dialog(int type, std::string filename);
+ void tick(int id);
+ void play();
+ void save(FILE* tfile);
+
+ int type;
+ int gonethrough;
+ std::vector<DialogScene> scenes;
+ XYZ participantlocation[10];
+ float participantyaw[10];
+
+ static void loadDialogs(FILE*);
+ static void saveDialogs(FILE*);
+
+ static bool inDialog() { return (indialogue != -1); }
+ static Dialog& currentDialog() { return dialogs[whichdialogue]; }
+ static DialogScene& currentScene() { return currentDialog().scenes[indialogue]; }
+
+ static int indialogue;
+ static int whichdialogue;
+ static bool directing;
+ static float dialoguetime;
+ static std::vector<Dialog> dialogs;
+};
+
+#endif /*_DIALOG_H_*/
--- /dev/null
+/*
+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 "Level/Hotspot.h"
+
+std::vector<Hotspot> Hotspot::hotspots;
+int Hotspot::current = 0;
+int Hotspot::killhotspot = 0;
+
+Hotspot::Hotspot() :
+ position(),
+ type(0),
+ size(0)
+{
+}
+
+Hotspot::Hotspot(XYZ p, int t, float s) :
+ position(p),
+ type(t),
+ size(s)
+{
+}
--- /dev/null
+/*
+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 _HOTSPOT_H_
+#define _HOTSPOT_H_
+
+#include "Math/Quaternions.h"
+#include <vector>
+
+class Hotspot
+{
+public:
+ static std::vector<Hotspot> hotspots;
+ static int current;
+ static int killhotspot;
+
+ Hotspot();
+ Hotspot(XYZ position, int type, float size);
+
+ XYZ position;
+ int type;
+ float size;
+ char text[256] = {0};
+};
+
+#endif
+++ /dev/null
-/*
-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 "Lights.h"
-
-void SetUpLight(Light* whichsource, int whichlight)
-{
- static float qattenuation[] = {0.0002f};
-
- //Initialize lights
- if (whichlight == 0) {
- GLfloat LightAmbient[] = { whichsource->ambient[0], whichsource->ambient[1], whichsource->ambient[2], 1.0f};
- GLfloat LightDiffuse[] = { whichsource->color[0], whichsource->color[1], whichsource->color[2], 1.0f };
- GLfloat LightPosition[] = { whichsource->location.x, whichsource->location.y, whichsource->location.z, 0.0f };
-
- glLightfv(GL_LIGHT0, GL_POSITION, LightPosition);
- glLightfv(GL_LIGHT0, GL_AMBIENT, LightAmbient);
- glLightfv(GL_LIGHT0, GL_DIFFUSE, LightDiffuse);
- glEnable(GL_LIGHT0);
- } else {
- GLenum lightselect = GL_LIGHT1;
- switch (whichlight) {
- case 2:
- lightselect = GL_LIGHT2;
- break;
- case 3:
- lightselect = GL_LIGHT3;
- break;
- case 4:
- lightselect = GL_LIGHT4;
- break;
- case 5:
- lightselect = GL_LIGHT5;
- break;
- case 6:
- lightselect = GL_LIGHT6;
- break;
- case 7:
- lightselect = GL_LIGHT7;
- break;
- }
-
- GLfloat LightAmbient[] = { 0, 0, 0, 1.0f};
- GLfloat LightDiffuse[] = { whichsource->color[0], whichsource->color[1], whichsource->color[2], 1.0f };
- GLfloat LightPosition[] = { whichsource->location.x, whichsource->location.y, whichsource->location.z, 1.0f };
-
- glLightfv(lightselect, GL_QUADRATIC_ATTENUATION, qattenuation);
- glLightfv(lightselect, GL_POSITION, LightPosition);
- glLightfv(lightselect, GL_AMBIENT, LightAmbient);
- glLightfv(lightselect, GL_DIFFUSE, LightDiffuse);
- glEnable(lightselect);
-
- }
-}
+++ /dev/null
-/*
-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 _LIGHTS_H_
-#define _LIGHTS_H_
-
-
-/**> HEADER FILES <**/
-#include "gamegl.h"
-#include "Quaternions.h"
-
-class Light
-{
-public:
- GLint type;
- GLfloat color[3];
- GLfloat ambient[3];
- int attach;
- XYZ location;
- inline void setColors(GLfloat cr, GLfloat cg, GLfloat cb,
- GLfloat ar, GLfloat ag, GLfloat ab) {
- color[0] = cr;
- color[1] = cg;
- color[2] = cb;
- ambient[0] = ar;
- ambient[1] = ag;
- ambient[2] = ab;
- }
-};
-
-void SetUpLight(Light* whichsource, int whichlight);
-
-#endif
typedef unsigned int UInt32;
-#include "Random.h"
+#include "Math/Random.h"
typedef struct AbsoluteTime {
unsigned long hi;
--- /dev/null
+/*
+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/>.
+*/
+
+#include "Math/Frustum.h"
+#include <math.h>
+
+#include "Graphic/gamegl.h"
+
+
+void FRUSTUM::
+GetFrustum()
+{
+ static float projmatrix[16];
+ static float mvmatrix[16];
+ static float clip[16];
+
+ glGetFloatv(GL_PROJECTION_MATRIX, projmatrix);
+ glGetFloatv(GL_MODELVIEW_MATRIX, mvmatrix);
+
+ // Combine the matrices
+ clip[0] = mvmatrix[0] * projmatrix[0] + mvmatrix[1] * projmatrix[4] + mvmatrix[2] * projmatrix[8] + mvmatrix[3] * projmatrix[12];
+ clip[1] = mvmatrix[0] * projmatrix[1] + mvmatrix[1] * projmatrix[5] + mvmatrix[2] * projmatrix[9] + mvmatrix[3] * projmatrix[13];
+ clip[2] = mvmatrix[0] * projmatrix[2] + mvmatrix[1] * projmatrix[6] + mvmatrix[2] * projmatrix[10] + mvmatrix[3] * projmatrix[14];
+ clip[3] = mvmatrix[0] * projmatrix[3] + mvmatrix[1] * projmatrix[7] + mvmatrix[2] * projmatrix[11] + mvmatrix[3] * projmatrix[15];
+
+ clip[4] = mvmatrix[4] * projmatrix[0] + mvmatrix[5] * projmatrix[4] + mvmatrix[6] * projmatrix[8] + mvmatrix[7] * projmatrix[12];
+ clip[5] = mvmatrix[4] * projmatrix[1] + mvmatrix[5] * projmatrix[5] + mvmatrix[6] * projmatrix[9] + mvmatrix[7] * projmatrix[13];
+ clip[6] = mvmatrix[4] * projmatrix[2] + mvmatrix[5] * projmatrix[6] + mvmatrix[6] * projmatrix[10] + mvmatrix[7] * projmatrix[14];
+ clip[7] = mvmatrix[4] * projmatrix[3] + mvmatrix[5] * projmatrix[7] + mvmatrix[6] * projmatrix[11] + mvmatrix[7] * projmatrix[15];
+
+ clip[8] = mvmatrix[8] * projmatrix[0] + mvmatrix[9] * projmatrix[4] + mvmatrix[10] * projmatrix[8] + mvmatrix[11] * projmatrix[12];
+ clip[9] = mvmatrix[8] * projmatrix[1] + mvmatrix[9] * projmatrix[5] + mvmatrix[10] * projmatrix[9] + mvmatrix[11] * projmatrix[13];
+ clip[10] = mvmatrix[8] * projmatrix[2] + mvmatrix[9] * projmatrix[6] + mvmatrix[10] * projmatrix[10] + mvmatrix[11] * projmatrix[14];
+ clip[11] = mvmatrix[8] * projmatrix[3] + mvmatrix[9] * projmatrix[7] + mvmatrix[10] * projmatrix[11] + mvmatrix[11] * projmatrix[15];
+
+ clip[12] = mvmatrix[12] * projmatrix[0] + mvmatrix[13] * projmatrix[4] + mvmatrix[14] * projmatrix[8] + mvmatrix[15] * projmatrix[12];
+ clip[13] = mvmatrix[12] * projmatrix[1] + mvmatrix[13] * projmatrix[5] + mvmatrix[14] * projmatrix[9] + mvmatrix[15] * projmatrix[13];
+ clip[14] = mvmatrix[12] * projmatrix[2] + mvmatrix[13] * projmatrix[6] + mvmatrix[14] * projmatrix[10] + mvmatrix[15] * projmatrix[14];
+ clip[15] = mvmatrix[12] * projmatrix[3] + mvmatrix[13] * projmatrix[7] + mvmatrix[14] * projmatrix[11] + mvmatrix[15] * projmatrix[15];
+
+ // Right plane
+ frustum[0][0] = clip[3] - clip[0];
+ frustum[0][1] = clip[7] - clip[4];
+ frustum[0][2] = clip[11] - clip[8];
+ frustum[0][3] = clip[15] - clip[12];
+
+ // Left plane
+ frustum[1][0] = clip[3] + clip[0];
+ frustum[1][1] = clip[7] + clip[4];
+ frustum[1][2] = clip[11] + clip[8];
+ frustum[1][3] = clip[15] + clip[12];
+
+ // Bottom plane
+ frustum[2][0] = clip[3] + clip[1];
+ frustum[2][1] = clip[7] + clip[5];
+ frustum[2][2] = clip[11] + clip[9];
+ frustum[2][3] = clip[15] + clip[13];
+
+ // Top plane
+ frustum[3][0] = clip[3] - clip[1];
+ frustum[3][1] = clip[7] - clip[5];
+ frustum[3][2] = clip[11] - clip[9];
+ frustum[3][3] = clip[15] - clip[13];
+
+ // Far plane
+ frustum[4][0] = clip[3] - clip[2];
+ frustum[4][1] = clip[7] - clip[6];
+ frustum[4][2] = clip[11] - clip[10];
+ frustum[4][3] = clip[15] - clip[14];
+
+ // Near plane
+ frustum[5][0] = clip[3] + clip[2];
+ frustum[5][1] = clip[7] + clip[6];
+ frustum[5][2] = clip[11] + clip[10];
+ frustum[5][3] = clip[15] + clip[14];
+}
+
+int FRUSTUM::
+CubeInFrustum(float x, float y, float z, float size)
+{
+ static int c, c2;
+
+ for (int i = 0; i < 6; i++) {
+ c = 0;
+ if (frustum[i][0] * (x - size) + frustum[i][1] * (y - size) + frustum[i][2] * (z - size) + frustum[i][3] > 0)
+ c++;
+ if (frustum[i][0] * (x + size) + frustum[i][1] * (y - size) + frustum[i][2] * (z - size) + frustum[i][3] > 0)
+ c++;
+ if (frustum[i][0] * (x - size) + frustum[i][1] * (y + size) + frustum[i][2] * (z - size) + frustum[i][3] > 0)
+ c++;
+ if (frustum[i][0] * (x + size) + frustum[i][1] * (y + size) + frustum[i][2] * (z - size) + frustum[i][3] > 0)
+ c++;
+ if (frustum[i][0] * (x - size) + frustum[i][1] * (y - size) + frustum[i][2] * (z + size) + frustum[i][3] > 0)
+ c++;
+ if (frustum[i][0] * (x + size) + frustum[i][1] * (y - size) + frustum[i][2] * (z + size) + frustum[i][3] > 0)
+ c++;
+ if (frustum[i][0] * (x - size) + frustum[i][1] * (y + size) + frustum[i][2] * (z + size) + frustum[i][3] > 0)
+ c++;
+ if (frustum[i][0] * (x + size) + frustum[i][1] * (y + size) + frustum[i][2] * (z + size) + frustum[i][3] > 0)
+ c++;
+ if (c == 0)
+ return 0;
+ if (c == 8)
+ c2++;
+ }
+ if (c2 >= 6)
+ return 2;
+ else
+ return 1;
+}
+
+int FRUSTUM::
+CubeInFrustum(float x, float y, float z, float size, float height)
+{
+ static int c, c2;
+
+ for (int i = 0; i < 6; i++) {
+ c = 0;
+ if (frustum[i][0] * (x - size) + frustum[i][1] * (y - height) + frustum[i][2] * (z - size) + frustum[i][3] > 0)
+ c++;
+ if (frustum[i][0] * (x + size) + frustum[i][1] * (y - height) + frustum[i][2] * (z - size) + frustum[i][3] > 0)
+ c++;
+ if (frustum[i][0] * (x - size) + frustum[i][1] * (y + height) + frustum[i][2] * (z - size) + frustum[i][3] > 0)
+ c++;
+ if (frustum[i][0] * (x + size) + frustum[i][1] * (y + height) + frustum[i][2] * (z - size) + frustum[i][3] > 0)
+ c++;
+ if (frustum[i][0] * (x - size) + frustum[i][1] * (y - height) + frustum[i][2] * (z + size) + frustum[i][3] > 0)
+ c++;
+ if (frustum[i][0] * (x + size) + frustum[i][1] * (y - height) + frustum[i][2] * (z + size) + frustum[i][3] > 0)
+ c++;
+ if (frustum[i][0] * (x - size) + frustum[i][1] * (y + height) + frustum[i][2] * (z + size) + frustum[i][3] > 0)
+ c++;
+ if (frustum[i][0] * (x + size) + frustum[i][1] * (y + height) + frustum[i][2] * (z + size) + frustum[i][3] > 0)
+ c++;
+ if (c == 0)
+ return 0;
+ if (c == 8)
+ c2++;
+ }
+ if (c2 >= 6)
+ return 2;
+ else
+ return 1;
+}
+
+int FRUSTUM::
+SphereInFrustum(float x, float y, float z, float radius)
+{
+ static int c2;
+
+ for (int i = 0; i < 6; i++) {
+ if (frustum[i][0] * x + frustum[i][1] * y + frustum[i][2] * z + frustum[i][3] > -1 * radius)
+ c2++;
+ else
+ return 0;
+ }
+ if (c2 >= 6)
+ return 2;
+ else
+ return 1;
+}
--- /dev/null
+/*
+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 FRUSTUM_H
+#define FRUSTUM_H
+
+class FRUSTUM
+{
+public:
+ float frustum[6][4];
+ void GetFrustum();
+ int CubeInFrustum(float, float, float, float);
+ int CubeInFrustum(float, float, float, float, float);
+ int SphereInFrustum(float, float, float, float);
+};
+
+#endif
--- /dev/null
+/*
+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 _PHYSICSMATH_H_
+#define _PHYSICSMATH_H_
+
+//#include <Carbon.h>
+
+#include "MacCompatibility.h"
+
+//------------------------------------------------------------------------//
+// Misc. Constants
+//------------------------------------------------------------------------//
+
+float const pi = 3.14159265f;
+float const g = -32.174f; // acceleration due to gravity, ft/s^2
+float const rho = 0.0023769f; // desity of air at sea level, slugs/ft^3
+float const tol = 0.0000000001f; // float type tolerance
+
+
+//------------------------------------------------------------------------//
+// Misc. Functions
+//------------------------------------------------------------------------//
+inline float DegreesToRadians(float deg);
+inline float RadiansToDegrees(float rad);
+
+inline float DegreesToRadians(float deg)
+{
+ return deg * pi / 180.0f;
+}
+
+inline float RadiansToDegrees(float rad)
+{
+ return rad * 180.0f / pi;
+}
+
+//------------------------------------------------------------------------//
+// Vector Class and vector functions
+//------------------------------------------------------------------------//
+class Vector
+{
+public:
+ float x;
+ float y;
+ float z;
+
+ Vector(void);
+ Vector(float xi, float yi, float zi);
+
+ float Magnitude(void);
+ void Normalize(void);
+ void Reverse(void);
+
+ Vector& operator+=(Vector u); // vector addition
+ Vector& operator-=(Vector u); // vector subtraction
+ Vector& operator*=(float s); // scalar multiply
+ Vector& operator/=(float s); // scalar divide
+
+ Vector operator-(void);
+
+};
+
+inline Vector operator+(Vector u, Vector v);
+inline Vector operator-(Vector u, Vector v);
+inline Vector operator^(Vector u, Vector v);
+inline float operator*(Vector u, Vector v);
+inline Vector operator*(float s, Vector u);
+inline Vector operator*(Vector u, float s);
+inline Vector operator/(Vector u, float s);
+inline float TripleScalarProduct(Vector u, Vector v, Vector w);
+/*
+float fast_sqrt2 (register float arg);
+float fast_sqrt2 (register float arg)
+{
+// Can replace with slower return std::sqrt(arg);
+register float result;
+
+if (arg == 0.0) return 0.0;
+
+asm {
+frsqrte result,arg // Calculate Square root
+}
+
+// Newton Rhapson iterations.
+result = result + 0.5 * result * (1.0 - arg * result * result);
+result = result + 0.5 * result * (1.0 - arg * result * result);
+
+return result * arg;
+}
+*/
+inline Vector::Vector(void)
+{
+ x = 0;
+ y = 0;
+ z = 0;
+}
+
+inline Vector::Vector(float xi, float yi, float zi)
+{
+ x = xi;
+ y = yi;
+ z = zi;
+}
+
+inline float Vector::Magnitude(void)
+{
+ return (float) sqrt(x * x + y * y + z * z);
+}
+
+inline void Vector::Normalize(void)
+{
+ float m = (float) sqrt(x * x + y * y + z * z);
+ if (m <= tol)
+ m = 1;
+ x /= m;
+ y /= m;
+ z /= m;
+
+ if (fabs(x) < tol)
+ x = 0.0f;
+ if (fabs(y) < tol)
+ y = 0.0f;
+ if (fabs(z) < tol)
+ z = 0.0f;
+}
+
+inline void Vector::Reverse(void)
+{
+ x = -x;
+ y = -y;
+ z = -z;
+}
+
+inline Vector& Vector::operator+=(Vector u)
+{
+ x += u.x;
+ y += u.y;
+ z += u.z;
+ return *this;
+}
+
+inline Vector& Vector::operator-=(Vector u)
+{
+ x -= u.x;
+ y -= u.y;
+ z -= u.z;
+ return *this;
+}
+
+inline Vector& Vector::operator*=(float s)
+{
+ x *= s;
+ y *= s;
+ z *= s;
+ return *this;
+}
+
+inline Vector& Vector::operator/=(float s)
+{
+ x /= s;
+ y /= s;
+ z /= s;
+ return *this;
+}
+
+inline Vector Vector::operator-(void)
+{
+ return Vector(-x, -y, -z);
+}
+
+
+inline Vector operator+(Vector u, Vector v)
+{
+ return Vector(u.x + v.x, u.y + v.y, u.z + v.z);
+}
+
+inline Vector operator-(Vector u, Vector v)
+{
+ return Vector(u.x - v.x, u.y - v.y, u.z - v.z);
+}
+
+// Vector cross product (u cross v)
+inline Vector operator^(Vector u, Vector v)
+{
+ return Vector( u.y * v.z - u.z * v.y,
+ -u.x * v.z + u.z * v.x,
+ u.x * v.y - u.y * v.x );
+}
+
+// Vector dot product
+inline float operator*(Vector u, Vector v)
+{
+ return (u.x * v.x + u.y * v.y + u.z * v.z);
+}
+
+inline Vector operator*(float s, Vector u)
+{
+ return Vector(u.x * s, u.y * s, u.z * s);
+}
+
+inline Vector operator*(Vector u, float s)
+{
+ return Vector(u.x * s, u.y * s, u.z * s);
+}
+
+inline Vector operator/(Vector u, float s)
+{
+ return Vector(u.x / s, u.y / s, u.z / s);
+}
+
+// triple scalar product (u dot (v cross w))
+inline float TripleScalarProduct(Vector u, Vector v, Vector w)
+{
+ return float( (u.x * (v.y * w.z - v.z * w.y)) +
+ (u.y * (-v.x * w.z + v.z * w.x)) +
+ (u.z * (v.x * w.y - v.y * w.x)) );
+ //return u*(v^w);
+
+}
+
+
+
+//------------------------------------------------------------------------//
+// Matrix Class and matrix functions
+//------------------------------------------------------------------------//
+
+class Matrix3x3
+{
+public:
+ // elements eij: i -> row, j -> column
+ float e11, e12, e13, e21, e22, e23, e31, e32, e33;
+
+ Matrix3x3(void);
+ Matrix3x3( float r1c1, float r1c2, float r1c3,
+ float r2c1, float r2c2, float r2c3,
+ float r3c1, float r3c2, float r3c3 );
+
+ float det(void);
+ Matrix3x3 Transpose(void);
+ Matrix3x3 Inverse(void);
+
+ Matrix3x3& operator+=(Matrix3x3 m);
+ Matrix3x3& operator-=(Matrix3x3 m);
+ Matrix3x3& operator*=(float s);
+ Matrix3x3& operator/=(float s);
+};
+
+inline Matrix3x3 operator+(Matrix3x3 m1, Matrix3x3 m2);
+inline Matrix3x3 operator-(Matrix3x3 m1, Matrix3x3 m2);
+inline Matrix3x3 operator/(Matrix3x3 m, float s);
+inline Matrix3x3 operator*(Matrix3x3 m1, Matrix3x3 m2);
+inline Matrix3x3 operator*(Matrix3x3 m, float s);
+inline Matrix3x3 operator*(float s, Matrix3x3 m);
+inline Vector operator*(Matrix3x3 m, Vector u);
+inline Vector operator*(Vector u, Matrix3x3 m);
+
+
+
+
+
+inline Matrix3x3::Matrix3x3(void)
+{
+ e11 = 0;
+ e12 = 0;
+ e13 = 0;
+ e21 = 0;
+ e22 = 0;
+ e23 = 0;
+ e31 = 0;
+ e32 = 0;
+ e33 = 0;
+}
+
+inline Matrix3x3::Matrix3x3( float r1c1, float r1c2, float r1c3,
+ float r2c1, float r2c2, float r2c3,
+ float r3c1, float r3c2, float r3c3 )
+{
+ e11 = r1c1;
+ e12 = r1c2;
+ e13 = r1c3;
+ e21 = r2c1;
+ e22 = r2c2;
+ e23 = r2c3;
+ e31 = r3c1;
+ e32 = r3c2;
+ e33 = r3c3;
+}
+
+inline float Matrix3x3::det(void)
+{
+ return e11 * e22 * e33 -
+ e11 * e32 * e23 +
+ e21 * e32 * e13 -
+ e21 * e12 * e33 +
+ e31 * e12 * e23 -
+ e31 * e22 * e13;
+}
+
+inline Matrix3x3 Matrix3x3::Transpose(void)
+{
+ return Matrix3x3(e11, e21, e31, e12, e22, e32, e13, e23, e33);
+}
+
+inline Matrix3x3 Matrix3x3::Inverse(void)
+{
+ float d = e11 * e22 * e33 -
+ e11 * e32 * e23 +
+ e21 * e32 * e13 -
+ e21 * e12 * e33 +
+ e31 * e12 * e23 -
+ e31 * e22 * e13;
+
+ if (d == 0)
+ d = 1;
+
+ return Matrix3x3( (e22 * e33 - e23 * e32) / d,
+ -(e12 * e33 - e13 * e32) / d,
+ (e12 * e23 - e13 * e22) / d,
+ -(e21 * e33 - e23 * e31) / d,
+ (e11 * e33 - e13 * e31) / d,
+ -(e11 * e23 - e13 * e21) / d,
+ (e21 * e32 - e22 * e31) / d,
+ -(e11 * e32 - e12 * e31) / d,
+ (e11 * e22 - e12 * e21) / d );
+}
+
+inline Matrix3x3& Matrix3x3::operator+=(Matrix3x3 m)
+{
+ e11 += m.e11;
+ e12 += m.e12;
+ e13 += m.e13;
+ e21 += m.e21;
+ e22 += m.e22;
+ e23 += m.e23;
+ e31 += m.e31;
+ e32 += m.e32;
+ e33 += m.e33;
+ return *this;
+}
+
+inline Matrix3x3& Matrix3x3::operator-=(Matrix3x3 m)
+{
+ e11 -= m.e11;
+ e12 -= m.e12;
+ e13 -= m.e13;
+ e21 -= m.e21;
+ e22 -= m.e22;
+ e23 -= m.e23;
+ e31 -= m.e31;
+ e32 -= m.e32;
+ e33 -= m.e33;
+ return *this;
+}
+
+inline Matrix3x3& Matrix3x3::operator*=(float s)
+{
+ e11 *= s;
+ e12 *= s;
+ e13 *= s;
+ e21 *= s;
+ e22 *= s;
+ e23 *= s;
+ e31 *= s;
+ e32 *= s;
+ e33 *= s;
+ return *this;
+}
+
+inline Matrix3x3& Matrix3x3::operator/=(float s)
+{
+ e11 /= s;
+ e12 /= s;
+ e13 /= s;
+ e21 /= s;
+ e22 /= s;
+ e23 /= s;
+ e31 /= s;
+ e32 /= s;
+ e33 /= s;
+ return *this;
+}
+
+inline Matrix3x3 operator+(Matrix3x3 m1, Matrix3x3 m2)
+{
+ return Matrix3x3( m1.e11 + m2.e11,
+ m1.e12 + m2.e12,
+ m1.e13 + m2.e13,
+ m1.e21 + m2.e21,
+ m1.e22 + m2.e22,
+ m1.e23 + m2.e23,
+ m1.e31 + m2.e31,
+ m1.e32 + m2.e32,
+ m1.e33 + m2.e33);
+}
+
+inline Matrix3x3 operator-(Matrix3x3 m1, Matrix3x3 m2)
+{
+ return Matrix3x3( m1.e11 - m2.e11,
+ m1.e12 - m2.e12,
+ m1.e13 - m2.e13,
+ m1.e21 - m2.e21,
+ m1.e22 - m2.e22,
+ m1.e23 - m2.e23,
+ m1.e31 - m2.e31,
+ m1.e32 - m2.e32,
+ m1.e33 - m2.e33);
+}
+
+inline Matrix3x3 operator/(Matrix3x3 m, float s)
+{
+ return Matrix3x3( m.e11 / s,
+ m.e12 / s,
+ m.e13 / s,
+ m.e21 / s,
+ m.e22 / s,
+ m.e23 / s,
+ m.e31 / s,
+ m.e32 / s,
+ m.e33 / s);
+}
+
+inline Matrix3x3 operator*(Matrix3x3 m1, Matrix3x3 m2)
+{
+ return Matrix3x3( m1.e11 * m2.e11 + m1.e12 * m2.e21 + m1.e13 * m2.e31,
+ m1.e11 * m2.e12 + m1.e12 * m2.e22 + m1.e13 * m2.e32,
+ m1.e11 * m2.e13 + m1.e12 * m2.e23 + m1.e13 * m2.e33,
+ m1.e21 * m2.e11 + m1.e22 * m2.e21 + m1.e23 * m2.e31,
+ m1.e21 * m2.e12 + m1.e22 * m2.e22 + m1.e23 * m2.e32,
+ m1.e21 * m2.e13 + m1.e22 * m2.e23 + m1.e23 * m2.e33,
+ m1.e31 * m2.e11 + m1.e32 * m2.e21 + m1.e33 * m2.e31,
+ m1.e31 * m2.e12 + m1.e32 * m2.e22 + m1.e33 * m2.e32,
+ m1.e31 * m2.e13 + m1.e32 * m2.e23 + m1.e33 * m2.e33 );
+}
+
+inline Matrix3x3 operator*(Matrix3x3 m, float s)
+{
+ return Matrix3x3( m.e11 * s,
+ m.e12 * s,
+ m.e13 * s,
+ m.e21 * s,
+ m.e22 * s,
+ m.e23 * s,
+ m.e31 * s,
+ m.e32 * s,
+ m.e33 * s);
+}
+
+inline Matrix3x3 operator*(float s, Matrix3x3 m)
+{
+ return Matrix3x3( m.e11 * s,
+ m.e12 * s,
+ m.e13 * s,
+ m.e21 * s,
+ m.e22 * s,
+ m.e23 * s,
+ m.e31 * s,
+ m.e32 * s,
+ m.e33 * s);
+}
+
+inline Vector operator*(Matrix3x3 m, Vector u)
+{
+ return Vector( m.e11 * u.x + m.e12 * u.y + m.e13 * u.z,
+ m.e21 * u.x + m.e22 * u.y + m.e23 * u.z,
+ m.e31 * u.x + m.e32 * u.y + m.e33 * u.z);
+}
+
+inline Vector operator*(Vector u, Matrix3x3 m)
+{
+ return Vector( u.x * m.e11 + u.y * m.e21 + u.z * m.e31,
+ u.x * m.e12 + u.y * m.e22 + u.z * m.e32,
+ u.x * m.e13 + u.y * m.e23 + u.z * m.e33);
+}
+
+//------------------------------------------------------------------------//
+// Quaternion Class and Quaternion functions
+//------------------------------------------------------------------------//
+
+class Quaternion
+{
+public:
+ float n; // number (scalar) part
+ Vector v; // vector part: v.x, v.y, v.z
+
+ Quaternion(void);
+ Quaternion(float e0, float e1, float e2, float e3);
+
+ float Magnitude(void);
+ Vector GetVector(void);
+ float GetScalar(void);
+ Quaternion operator+=(Quaternion q);
+ Quaternion operator-=(Quaternion q);
+ Quaternion operator*=(float s);
+ Quaternion operator/=(float s);
+ Quaternion operator~(void) const {
+ return Quaternion(n, -v.x, -v.y, -v.z);
+ }
+};
+
+inline Quaternion operator+(Quaternion q1, Quaternion q2);
+inline Quaternion operator-(Quaternion q1, Quaternion q2);
+inline Quaternion operator*(Quaternion q1, Quaternion q2);
+inline Quaternion operator*(Quaternion q, float s);
+inline Quaternion operator*(float s, Quaternion q);
+inline Quaternion operator*(Quaternion q, Vector v);
+inline Quaternion operator*(Vector v, Quaternion q);
+inline Quaternion operator/(Quaternion q, float s);
+inline float QGetAngle(Quaternion q);
+inline Vector QGetAxis(Quaternion q);
+inline Quaternion QRotate(Quaternion q1, Quaternion q2);
+inline Vector QVRotate(Quaternion q, Vector v);
+inline Quaternion MakeQFromEulerAngles(float x, float y, float z);
+inline Vector MakeEulerAnglesFromQ(Quaternion q);
+
+
+inline Quaternion::Quaternion(void)
+{
+ n = 0;
+ v.x = 0;
+ v.y = 0;
+ v.z = 0;
+}
+
+inline Quaternion::Quaternion(float e0, float e1, float e2, float e3)
+{
+ n = e0;
+ v.x = e1;
+ v.y = e2;
+ v.z = e3;
+}
+
+inline float Quaternion::Magnitude(void)
+{
+ return (float) sqrt(n * n + v.x * v.x + v.y * v.y + v.z * v.z);
+}
+
+inline Vector Quaternion::GetVector(void)
+{
+ return Vector(v.x, v.y, v.z);
+}
+
+inline float Quaternion::GetScalar(void)
+{
+ return n;
+}
+
+inline Quaternion Quaternion::operator+=(Quaternion q)
+{
+ n += q.n;
+ v.x += q.v.x;
+ v.y += q.v.y;
+ v.z += q.v.z;
+ return *this;
+}
+
+inline Quaternion Quaternion::operator-=(Quaternion q)
+{
+ n -= q.n;
+ v.x -= q.v.x;
+ v.y -= q.v.y;
+ v.z -= q.v.z;
+ return *this;
+}
+
+inline Quaternion Quaternion::operator*=(float s)
+{
+ n *= s;
+ v.x *= s;
+ v.y *= s;
+ v.z *= s;
+ return *this;
+}
+
+inline Quaternion Quaternion::operator/=(float s)
+{
+ n /= s;
+ v.x /= s;
+ v.y /= s;
+ v.z /= s;
+ return *this;
+}
+
+/*inline Quaternion Quaternion::operator~()
+{
+return Quaternion(n, -v.x, -v.y, -v.z);
+}*/
+
+inline Quaternion operator+(Quaternion q1, Quaternion q2)
+{
+ return Quaternion( q1.n + q2.n,
+ q1.v.x + q2.v.x,
+ q1.v.y + q2.v.y,
+ q1.v.z + q2.v.z);
+}
+
+inline Quaternion operator-(Quaternion q1, Quaternion q2)
+{
+ return Quaternion( q1.n - q2.n,
+ q1.v.x - q2.v.x,
+ q1.v.y - q2.v.y,
+ q1.v.z - q2.v.z);
+}
+
+inline Quaternion operator*(Quaternion q1, Quaternion q2)
+{
+ return Quaternion( q1.n * q2.n - q1.v.x * q2.v.x - q1.v.y * q2.v.y - q1.v.z * q2.v.z,
+ q1.n * q2.v.x + q1.v.x * q2.n + q1.v.y * q2.v.z - q1.v.z * q2.v.y,
+ q1.n * q2.v.y + q1.v.y * q2.n + q1.v.z * q2.v.x - q1.v.x * q2.v.z,
+ q1.n * q2.v.z + q1.v.z * q2.n + q1.v.x * q2.v.y - q1.v.y * q2.v.x);
+}
+
+inline Quaternion operator*(Quaternion q, float s)
+{
+ return Quaternion(q.n * s, q.v.x * s, q.v.y * s, q.v.z * s);
+}
+
+inline Quaternion operator*(float s, Quaternion q)
+{
+ return Quaternion(q.n * s, q.v.x * s, q.v.y * s, q.v.z * s);
+}
+
+inline Quaternion operator*(Quaternion q, Vector v)
+{
+ return Quaternion( -(q.v.x * v.x + q.v.y * v.y + q.v.z * v.z),
+ q.n * v.x + q.v.y * v.z - q.v.z * v.y,
+ q.n * v.y + q.v.z * v.x - q.v.x * v.z,
+ q.n * v.z + q.v.x * v.y - q.v.y * v.x);
+}
+
+inline Quaternion operator*(Vector v, Quaternion q)
+{
+ return Quaternion( -(q.v.x * v.x + q.v.y * v.y + q.v.z * v.z),
+ q.n * v.x + q.v.z * v.y - q.v.y * v.z,
+ q.n * v.y + q.v.x * v.z - q.v.z * v.x,
+ q.n * v.z + q.v.y * v.x - q.v.x * v.y);
+}
+
+inline Quaternion operator/(Quaternion q, float s)
+{
+ return Quaternion(q.n / s, q.v.x / s, q.v.y / s, q.v.z / s);
+}
+
+inline float QGetAngle(Quaternion q)
+{
+ return (float) (2 * acosf(q.n));
+}
+
+inline Vector QGetAxis(Quaternion q)
+{
+ Vector v;
+ float m;
+
+ v = q.GetVector();
+ m = v.Magnitude();
+
+ if (m <= tol)
+ return Vector();
+ else
+ return v / m;
+}
+
+inline Quaternion QRotate(Quaternion q1, Quaternion q2)
+{
+ return q1 * q2 * (~q1);
+}
+
+inline Vector QVRotate(Quaternion q, Vector v)
+{
+ Quaternion t;
+
+
+ t = q * v * (~q);
+
+ return t.GetVector();
+}
+
+inline Quaternion MakeQFromEulerAngles(float x, float y, float z)
+{
+ Quaternion q;
+ double roll = DegreesToRadians(x);
+ double pitch = DegreesToRadians(y);
+ double yaw = DegreesToRadians(z);
+
+ double cyaw, cpitch, croll, syaw, spitch, sroll;
+ double cyawcpitch, syawspitch, cyawspitch, syawcpitch;
+
+ cyaw = cos(0.5f * yaw);
+ cpitch = cos(0.5f * pitch);
+ croll = cos(0.5f * roll);
+ syaw = sin(0.5f * yaw);
+ spitch = sin(0.5f * pitch);
+ sroll = sin(0.5f * roll);
+
+ cyawcpitch = cyaw * cpitch;
+ syawspitch = syaw * spitch;
+ cyawspitch = cyaw * spitch;
+ syawcpitch = syaw * cpitch;
+
+ q.n = (float) (cyawcpitch * croll + syawspitch * sroll);
+ q.v.x = (float) (cyawcpitch * sroll - syawspitch * croll);
+ q.v.y = (float) (cyawspitch * croll + syawcpitch * sroll);
+ q.v.z = (float) (syawcpitch * croll - cyawspitch * sroll);
+
+ return q;
+}
+
+inline Vector MakeEulerAnglesFromQ(Quaternion q)
+{
+ double r11, r21, r31, r32, r33;
+ double q00, q11, q22, q33;
+ double tmp;
+ Vector u;
+
+ q00 = q.n * q.n;
+ q11 = q.v.x * q.v.x;
+ q22 = q.v.y * q.v.y;
+ q33 = q.v.z * q.v.z;
+
+ r11 = q00 + q11 - q22 - q33;
+ r21 = 2 * (q.v.x * q.v.y + q.n * q.v.z);
+ r31 = 2 * (q.v.x * q.v.z - q.n * q.v.y);
+ r32 = 2 * (q.v.y * q.v.z + q.n * q.v.x);
+ r33 = q00 - q11 - q22 + q33;
+
+ tmp = fabs(r31);
+ if (tmp > 0.999999) {
+ double r12 = 2 * (q.v.x * q.v.y - q.n * q.v.z);
+ double r13 = 2 * (q.v.x * q.v.z + q.n * q.v.y);
+
+ u.x = RadiansToDegrees(0.0f); //roll
+ u.y = RadiansToDegrees((float) (-(pi / 2) * r31 / tmp)); // pitch
+ u.z = RadiansToDegrees((float) atan2(-r12, -r31 * r13)); // yaw
+ return u;
+ }
+
+ u.x = RadiansToDegrees((float) atan2(r32, r33)); // roll
+ u.y = RadiansToDegrees((float) asinf(-r31)); // pitch
+ u.z = RadiansToDegrees((float) atan2(r21, r11)); // yaw
+ return u;
+
+
+}
+
+
+
+
+
+#endif
--- /dev/null
+/*
+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/>.
+*/
+
+#include "Math/Quaternions.h"
+
+// Functions
+quaternion Quat_Mult(quaternion q1, quaternion q2)
+{
+ quaternion QResult;
+ float a, b, c, d, e, f, g, h;
+ a = (q1.w + q1.x) * (q2.w + q2.x);
+ b = (q1.z - q1.y) * (q2.y - q2.z);
+ c = (q1.w - q1.x) * (q2.y + q2.z);
+ d = (q1.y + q1.z) * (q2.w - q2.x);
+ e = (q1.x + q1.z) * (q2.x + q2.y);
+ f = (q1.x - q1.z) * (q2.x - q2.y);
+ g = (q1.w + q1.y) * (q2.w - q2.z);
+ h = (q1.w - q1.y) * (q2.w + q2.z);
+ QResult.w = b + (-e - f + g + h) / 2;
+ QResult.x = a - (e + f + g + h) / 2;
+ QResult.y = c + (e - f + g - h) / 2;
+ QResult.z = d + (e - f - g + h) / 2;
+ return QResult;
+}
+
+
+
+quaternion To_Quat(Matrix_t m)
+{
+ // From Jason Shankel, (C) 2000.
+ static quaternion Quat;
+
+ static double Tr = m[0][0] + m[1][1] + m[2][2] + 1.0, fourD;
+ static double q[4];
+
+ static int i, j, k;
+ if (Tr >= 1.0) {
+ fourD = 2.0 * fast_sqrt(Tr);
+ q[3] = fourD / 4.0;
+ q[0] = (m[2][1] - m[1][2]) / fourD;
+ q[1] = (m[0][2] - m[2][0]) / fourD;
+ q[2] = (m[1][0] - m[0][1]) / fourD;
+ } else {
+ if (m[0][0] > m[1][1]) {
+ i = 0;
+ } else {
+ i = 1;
+ }
+ if (m[2][2] > m[i][i]) {
+ i = 2;
+ }
+ j = (i + 1) % 3;
+ k = (j + 1) % 3;
+ fourD = 2.0 * fast_sqrt(m[i][i] - m[j][j] - m[k][k] + 1.0);
+ q[i] = fourD / 4.0;
+ q[j] = (m[j][i] + m[i][j]) / fourD;
+ q[k] = (m[k][i] + m[i][k]) / fourD;
+ q[3] = (m[j][k] - m[k][j]) / fourD;
+ }
+
+ Quat.x = q[0];
+ Quat.y = q[1];
+ Quat.z = q[2];
+ Quat.w = q[3];
+ return Quat;
+}
+void Quat_2_Matrix(quaternion Quat, Matrix_t m)
+{
+ // From the GLVelocity site (http://glvelocity.gamedev.net)
+ float fW = Quat.w;
+ float fX = Quat.x;
+ float fY = Quat.y;
+ float fZ = Quat.z;
+ float fXX = fX * fX;
+ float fYY = fY * fY;
+ float fZZ = fZ * fZ;
+ m[0][0] = 1.0f - 2.0f * (fYY + fZZ);
+ m[1][0] = 2.0f * (fX * fY + fW * fZ);
+ m[2][0] = 2.0f * (fX * fZ - fW * fY);
+ m[3][0] = 0.0f;
+ m[0][1] = 2.0f * (fX * fY - fW * fZ);
+ m[1][1] = 1.0f - 2.0f * (fXX + fZZ);
+ m[2][1] = 2.0f * (fY * fZ + fW * fX);
+ m[3][1] = 0.0f;
+ m[0][2] = 2.0f * (fX * fZ + fW * fY);
+ m[1][2] = 2.0f * (fX * fZ - fW * fX);
+ m[2][2] = 1.0f - 2.0f * (fXX + fYY);
+ m[3][2] = 0.0f;
+ m[0][3] = 0.0f;
+ m[1][3] = 0.0f;
+ m[2][3] = 0.0f;
+ m[3][3] = 1.0f;
+}
+quaternion To_Quat(angle_axis Ang_Ax)
+{
+ // From the Quaternion Powers article on gamedev.net
+ static quaternion Quat;
+
+ Quat.x = Ang_Ax.x * sin(Ang_Ax.angle / 2);
+ Quat.y = Ang_Ax.y * sin(Ang_Ax.angle / 2);
+ Quat.z = Ang_Ax.z * sin(Ang_Ax.angle / 2);
+ Quat.w = cos(Ang_Ax.angle / 2);
+ return Quat;
+}
+angle_axis Quat_2_AA(quaternion Quat)
+{
+ static angle_axis Ang_Ax;
+ static float scale, tw;
+ tw = (float)acosf(Quat.w) * 2;
+ scale = (float)sin(tw / 2.0);
+ Ang_Ax.x = Quat.x / scale;
+ Ang_Ax.y = Quat.y / scale;
+ Ang_Ax.z = Quat.z / scale;
+
+ Ang_Ax.angle = 2.0 * acosf(Quat.w) / (float)PI * 180;
+ return Ang_Ax;
+}
+
+quaternion To_Quat(int In_Degrees, euler Euler)
+{
+ // From the gamasutra quaternion article
+ static quaternion Quat;
+ static float cr, cp, cy, sr, sp, sy, cpcy, spsy;
+ //If we are in Degree mode, convert to Radians
+ if (In_Degrees) {
+ Euler.x = Euler.x * (float)PI / 180;
+ Euler.y = Euler.y * (float)PI / 180;
+ Euler.z = Euler.z * (float)PI / 180;
+ }
+ //Calculate trig identities
+ //Formerly roll, pitch, yaw
+ cr = float(cos(Euler.x / 2));
+ cp = float(cos(Euler.y / 2));
+ cy = float(cos(Euler.z / 2));
+ sr = float(sin(Euler.x / 2));
+ sp = float(sin(Euler.y / 2));
+ sy = float(sin(Euler.z / 2));
+
+ cpcy = cp * cy;
+ spsy = sp * sy;
+ Quat.w = cr * cpcy + sr * spsy;
+ Quat.x = sr * cpcy - cr * spsy;
+ Quat.y = cr * sp * cy + sr * cp * sy;
+ Quat.z = cr * cp * sy - sr * sp * cy;
+
+ return Quat;
+}
+
+quaternion QNormalize(quaternion Quat)
+{
+ static float norm;
+ norm = Quat.x * Quat.x +
+ Quat.y * Quat.y +
+ Quat.z * Quat.z +
+ Quat.w * Quat.w;
+ Quat.x = float(Quat.x / norm);
+ Quat.y = float(Quat.y / norm);
+ Quat.z = float(Quat.z / norm);
+ Quat.w = float(Quat.w / norm);
+ return Quat;
+}
+
+XYZ Quat2Vector(quaternion Quat)
+{
+ QNormalize(Quat);
+
+ float fW = Quat.w;
+ float fX = Quat.x;
+ float fY = Quat.y;
+ float fZ = Quat.z;
+
+ XYZ tempvec;
+
+ tempvec.x = 2.0f * (fX * fZ - fW * fY);
+ tempvec.y = 2.0f * (fY * fZ + fW * fX);
+ tempvec.z = 1.0f - 2.0f * (fX * fX + fY * fY);
+
+ return tempvec;
+}
+
+bool PointInTriangle(Vector *p, Vector normal, float p11, float p12, float p13, float p21, float p22, float p23, float p31, float p32, float p33)
+{
+ static float u0, u1, u2;
+ static float v0, v1, v2;
+ static float a, b;
+ static float max;
+ static int i, j;
+ static bool bInter;
+ static float pointv[3];
+ static float p1v[3];
+ static float p2v[3];
+ static float p3v[3];
+ static float normalv[3];
+
+ bInter = 0;
+
+ pointv[0] = p->x;
+ pointv[1] = p->y;
+ pointv[2] = p->z;
+
+
+ p1v[0] = p11;
+ p1v[1] = p12;
+ p1v[2] = p13;
+
+ p2v[0] = p21;
+ p2v[1] = p22;
+ p2v[2] = p23;
+
+ p3v[0] = p31;
+ p3v[1] = p32;
+ p3v[2] = p33;
+
+ normalv[0] = normal.x;
+ normalv[1] = normal.y;
+ normalv[2] = normal.z;
+
+#define ABS(X) (((X)<0.f)?-(X):(X) )
+#define MAX(A, B) (((A)<(B))?(B):(A))
+ max = MAX(MAX(ABS(normalv[0]), ABS(normalv[1])), ABS(normalv[2]));
+#undef MAX
+ if (max == ABS(normalv[0])) {
+ i = 1; // y, z
+ j = 2;
+ }
+ if (max == ABS(normalv[1])) {
+ i = 0; // x, z
+ j = 2;
+ }
+ if (max == ABS(normalv[2])) {
+ i = 0; // x, y
+ j = 1;
+ }
+#undef ABS
+
+ u0 = pointv[i] - p1v[i];
+ v0 = pointv[j] - p1v[j];
+ u1 = p2v[i] - p1v[i];
+ v1 = p2v[j] - p1v[j];
+ u2 = p3v[i] - p1v[i];
+ v2 = p3v[j] - p1v[j];
+
+ if (u1 > -1.0e-05f && u1 < 1.0e-05f) { // == 0.0f)
+ b = u0 / u2;
+ if (0.0f <= b && b <= 1.0f) {
+ a = (v0 - b * v2) / v1;
+ if ((a >= 0.0f) && (( a + b ) <= 1.0f))
+ bInter = 1;
+ }
+ } else {
+ b = (v0 * u1 - u0 * v1) / (v2 * u1 - u2 * v1);
+ if (0.0f <= b && b <= 1.0f) {
+ a = (u0 - b * u2) / u1;
+ if ((a >= 0.0f) && (( a + b ) <= 1.0f ))
+ bInter = 1;
+ }
+ }
+
+ return bInter;
+}
+
+bool LineFacet(Vector p1, Vector p2, Vector pa, Vector pb, Vector pc, Vector *p)
+{
+ static float d;
+ static float denom, mu;
+ static Vector n;
+
+ //Calculate the parameters for the plane
+ n.x = (pb.y - pa.y) * (pc.z - pa.z) - (pb.z - pa.z) * (pc.y - pa.y);
+ n.y = (pb.z - pa.z) * (pc.x - pa.x) - (pb.x - pa.x) * (pc.z - pa.z);
+ n.z = (pb.x - pa.x) * (pc.y - pa.y) - (pb.y - pa.y) * (pc.x - pa.x);
+ n.Normalize();
+ d = - n.x * pa.x - n.y * pa.y - n.z * pa.z;
+
+ //Calculate the position on the line that intersects the plane
+ denom = n.x * (p2.x - p1.x) + n.y * (p2.y - p1.y) + n.z * (p2.z - p1.z);
+ if (fabs(denom) < 0.0000001) // Line and plane don't intersect
+ return 0;
+ mu = - (d + n.x * p1.x + n.y * p1.y + n.z * p1.z) / denom;
+ p->x = p1.x + mu * (p2.x - p1.x);
+ p->y = p1.y + mu * (p2.y - p1.y);
+ p->z = p1.z + mu * (p2.z - p1.z);
+ if (mu < 0 || mu > 1) // Intersection not along line segment
+ return 0;
+
+ if (!PointInTriangle( p, n, pa.x, pa.y, pa.z, pb.x, pb.y, pb.z, pc.x, pc.y, pc.z)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+bool PointInTriangle(XYZ *p, XYZ normal, XYZ *p1, XYZ *p2, XYZ *p3)
+{
+ static float u0, u1, u2;
+ static float v0, v1, v2;
+ static float a, b;
+ static float max;
+ static int i, j;
+ static bool bInter = 0;
+ static float pointv[3];
+ static float p1v[3];
+ static float p2v[3];
+ static float p3v[3];
+ static float normalv[3];
+
+ bInter = 0;
+
+ pointv[0] = p->x;
+ pointv[1] = p->y;
+ pointv[2] = p->z;
+
+
+ p1v[0] = p1->x;
+ p1v[1] = p1->y;
+ p1v[2] = p1->z;
+
+ p2v[0] = p2->x;
+ p2v[1] = p2->y;
+ p2v[2] = p2->z;
+
+ p3v[0] = p3->x;
+ p3v[1] = p3->y;
+ p3v[2] = p3->z;
+
+ normalv[0] = normal.x;
+ normalv[1] = normal.y;
+ normalv[2] = normal.z;
+
+#define ABS(X) (((X)<0.f)?-(X):(X) )
+#define MAX(A, B) (((A)<(B))?(B):(A))
+ max = MAX(MAX(ABS(normalv[0]), ABS(normalv[1])), ABS(normalv[2]));
+#undef MAX
+ if (max == ABS(normalv[0])) {
+ i = 1; // y, z
+ j = 2;
+ }
+ if (max == ABS(normalv[1])) {
+ i = 0; // x, z
+ j = 2;
+ }
+ if (max == ABS(normalv[2])) {
+ i = 0; // x, y
+ j = 1;
+ }
+#undef ABS
+
+ u0 = pointv[i] - p1v[i];
+ v0 = pointv[j] - p1v[j];
+ u1 = p2v[i] - p1v[i];
+ v1 = p2v[j] - p1v[j];
+ u2 = p3v[i] - p1v[i];
+ v2 = p3v[j] - p1v[j];
+
+ if (u1 > -1.0e-05f && u1 < 1.0e-05f) { // == 0.0f)
+ b = u0 / u2;
+ if (0.0f <= b && b <= 1.0f) {
+ a = (v0 - b * v2) / v1;
+ if ((a >= 0.0f) && (( a + b ) <= 1.0f))
+ bInter = 1;
+ }
+ } else {
+ b = (v0 * u1 - u0 * v1) / (v2 * u1 - u2 * v1);
+ if (0.0f <= b && b <= 1.0f) {
+ a = (u0 - b * u2) / u1;
+ if ((a >= 0.0f) && (( a + b ) <= 1.0f ))
+ bInter = 1;
+ }
+ }
+
+ return bInter;
+}
+
+bool LineFacet(XYZ p1, XYZ p2, XYZ pa, XYZ pb, XYZ pc, XYZ *p)
+{
+ static float d;
+ static float denom, mu;
+ static XYZ n;
+
+ //Calculate the parameters for the plane
+ n.x = (pb.y - pa.y) * (pc.z - pa.z) - (pb.z - pa.z) * (pc.y - pa.y);
+ n.y = (pb.z - pa.z) * (pc.x - pa.x) - (pb.x - pa.x) * (pc.z - pa.z);
+ n.z = (pb.x - pa.x) * (pc.y - pa.y) - (pb.y - pa.y) * (pc.x - pa.x);
+ Normalise(&n);
+ d = - n.x * pa.x - n.y * pa.y - n.z * pa.z;
+
+ //Calculate the position on the line that intersects the plane
+ denom = n.x * (p2.x - p1.x) + n.y * (p2.y - p1.y) + n.z * (p2.z - p1.z);
+ if (fabs(denom) < 0.0000001) // Line and plane don't intersect
+ return 0;
+ mu = - (d + n.x * p1.x + n.y * p1.y + n.z * p1.z) / denom;
+ p->x = p1.x + mu * (p2.x - p1.x);
+ p->y = p1.y + mu * (p2.y - p1.y);
+ p->z = p1.z + mu * (p2.z - p1.z);
+ if (mu < 0 || mu > 1) // Intersection not along line segment
+ return 0;
+
+ if (!PointInTriangle( p, n, &pa, &pb, &pc)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+float LineFacetd(XYZ p1, XYZ p2, XYZ pa, XYZ pb, XYZ pc, XYZ *p)
+{
+ static float d;
+ static float denom, mu;
+ static XYZ n;
+
+ //Calculate the parameters for the plane
+ n.x = (pb.y - pa.y) * (pc.z - pa.z) - (pb.z - pa.z) * (pc.y - pa.y);
+ n.y = (pb.z - pa.z) * (pc.x - pa.x) - (pb.x - pa.x) * (pc.z - pa.z);
+ n.z = (pb.x - pa.x) * (pc.y - pa.y) - (pb.y - pa.y) * (pc.x - pa.x);
+ Normalise(&n);
+ d = - n.x * pa.x - n.y * pa.y - n.z * pa.z;
+
+ //Calculate the position on the line that intersects the plane
+ denom = n.x * (p2.x - p1.x) + n.y * (p2.y - p1.y) + n.z * (p2.z - p1.z);
+ if (fabs(denom) < 0.0000001) // Line and plane don't intersect
+ return 0;
+ mu = - (d + n.x * p1.x + n.y * p1.y + n.z * p1.z) / denom;
+ p->x = p1.x + mu * (p2.x - p1.x);
+ p->y = p1.y + mu * (p2.y - p1.y);
+ p->z = p1.z + mu * (p2.z - p1.z);
+ if (mu < 0 || mu > 1) // Intersection not along line segment
+ return 0;
+
+ if (!PointInTriangle( p, n, &pa, &pb, &pc)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+float LineFacetd(XYZ p1, XYZ p2, XYZ pa, XYZ pb, XYZ pc, XYZ n, XYZ *p)
+{
+ static float d;
+ static float denom, mu;
+
+ //Calculate the parameters for the plane
+ d = - n.x * pa.x - n.y * pa.y - n.z * pa.z;
+
+ //Calculate the position on the line that intersects the plane
+ denom = n.x * (p2.x - p1.x) + n.y * (p2.y - p1.y) + n.z * (p2.z - p1.z);
+ if (fabs(denom) < 0.0000001) // Line and plane don't intersect
+ return 0;
+ mu = - (d + n.x * p1.x + n.y * p1.y + n.z * p1.z) / denom;
+ p->x = p1.x + mu * (p2.x - p1.x);
+ p->y = p1.y + mu * (p2.y - p1.y);
+ p->z = p1.z + mu * (p2.z - p1.z);
+ if (mu < 0 || mu > 1) // Intersection not along line segment
+ return 0;
+
+ if (!PointInTriangle( p, n, &pa, &pb, &pc)) {
+ return 0;
+ }
+ return 1;
+}
+
+float LineFacetd(XYZ *p1, XYZ *p2, XYZ *pa, XYZ *pb, XYZ *pc, XYZ *p)
+{
+ static float d;
+ static float denom, mu;
+ static XYZ n;
+
+ //Calculate the parameters for the plane
+ n.x = (pb->y - pa->y) * (pc->z - pa->z) - (pb->z - pa->z) * (pc->y - pa->y);
+ n.y = (pb->z - pa->z) * (pc->x - pa->x) - (pb->x - pa->x) * (pc->z - pa->z);
+ n.z = (pb->x - pa->x) * (pc->y - pa->y) - (pb->y - pa->y) * (pc->x - pa->x);
+ Normalise(&n);
+ d = - n.x * pa->x - n.y * pa->y - n.z * pa->z;
+
+
+ //Calculate the position on the line that intersects the plane
+ denom = n.x * (p2->x - p1->x) + n.y * (p2->y - p1->y) + n.z * (p2->z - p1->z);
+ if (fabs(denom) < 0.0000001) // Line and plane don't intersect
+ return 0;
+ mu = - (d + n.x * p1->x + n.y * p1->y + n.z * p1->z) / denom;
+ p->x = p1->x + mu * (p2->x - p1->x);
+ p->y = p1->y + mu * (p2->y - p1->y);
+ p->z = p1->z + mu * (p2->z - p1->z);
+ if (mu < 0 || mu > 1) // Intersection not along line segment
+ return 0;
+
+ if (!PointInTriangle( p, n, pa, pb, pc)) {
+ return 0;
+ }
+ return 1;
+}
+
+float LineFacetd(XYZ *p1, XYZ *p2, XYZ *pa, XYZ *pb, XYZ *pc, XYZ *n, XYZ *p)
+{
+ static float d;
+ static float denom, mu;
+
+ //Calculate the parameters for the plane
+ d = - n->x * pa->x - n->y * pa->y - n->z * pa->z;
+
+ //Calculate the position on the line that intersects the plane
+ denom = n->x * (p2->x - p1->x) + n->y * (p2->y - p1->y) + n->z * (p2->z - p1->z);
+ if (fabs(denom) < 0.0000001) // Line and plane don't intersect
+ return 0;
+ mu = - (d + n->x * p1->x + n->y * p1->y + n->z * p1->z) / denom;
+ p->x = p1->x + mu * (p2->x - p1->x);
+ p->y = p1->y + mu * (p2->y - p1->y);
+ p->z = p1->z + mu * (p2->z - p1->z);
+ if (mu < 0 || mu > 1) // Intersection not along line segment
+ return 0;
+
+ if (!PointInTriangle( p, *n, pa, pb, pc)) {
+ return 0;
+ }
+ return 1;
+}
+
+
--- /dev/null
+/*
+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 _QUATERNIONS_H_
+#define _QUATERNIONS_H_
+
+#include "math.h"
+#include "PhysicsMath.h"
+#include "Graphic/gamegl.h"
+
+/**> Quaternion Structures <**/
+#define PI 3.14159265355555897932384626
+#define RADIANS 0
+#define DEGREES 1
+#define deg2rad .0174532925
+
+//using namespace std;
+typedef float Matrix_t [4][4];
+struct euler {
+ float x, y, z;
+};
+struct angle_axis {
+ float x, y, z, angle;
+};
+struct quaternion {
+ float x, y, z, w;
+};
+
+class XYZ
+{
+public:
+ float x;
+ float y;
+ float z;
+ XYZ() : x(0.0f), y(0.0f), z(0.0f) {}
+ inline XYZ operator+(XYZ add);
+ inline XYZ operator-(XYZ add);
+ inline XYZ operator*(float add);
+ inline XYZ operator*(XYZ add);
+ inline XYZ operator/(float add);
+ inline void operator+=(XYZ add);
+ inline void operator-=(XYZ add);
+ inline void operator*=(float add);
+ inline void operator*=(XYZ add);
+ inline void operator/=(float add);
+ inline void operator=(float add);
+ inline void vec(Vector add);
+ inline bool operator==(XYZ add);
+};
+
+/*********************> Quaternion Function definition <********/
+quaternion To_Quat(int Degree_Flag, euler Euler);
+quaternion To_Quat(angle_axis Ang_Ax);
+quaternion To_Quat(Matrix_t m);
+angle_axis Quat_2_AA(quaternion Quat);
+void Quat_2_Matrix(quaternion Quat, Matrix_t m);
+quaternion Normalize(quaternion Quat);
+quaternion Quat_Mult(quaternion q1, quaternion q2);
+quaternion QNormalize(quaternion Quat);
+XYZ Quat2Vector(quaternion Quat);
+
+inline void CrossProduct(XYZ *P, XYZ *Q, XYZ *V);
+inline void CrossProduct(XYZ P, XYZ Q, XYZ *V);
+inline void Normalise(XYZ *vectory);
+inline float normaldotproduct(XYZ point1, XYZ point2);
+inline float fast_sqrt (register float arg);
+bool PointInTriangle(XYZ *p, XYZ normal, XYZ *p1, XYZ *p2, XYZ *p3);
+bool LineFacet(XYZ p1, XYZ p2, XYZ pa, XYZ pb, XYZ pc, XYZ *p);
+float LineFacetd(XYZ p1, XYZ p2, XYZ pa, XYZ pb, XYZ pc, XYZ *p);
+float LineFacetd(XYZ p1, XYZ p2, XYZ pa, XYZ pb, XYZ pc, XYZ n, XYZ *p);
+float LineFacetd(XYZ *p1, XYZ *p2, XYZ *pa, XYZ *pb, XYZ *pc, XYZ *n, XYZ *p);
+float LineFacetd(XYZ *p1, XYZ *p2, XYZ *pa, XYZ *pb, XYZ *pc, XYZ *p);
+bool PointInTriangle(Vector *p, Vector normal, float p11, float p12, float p13, float p21, float p22, float p23, float p31, float p32, float p33);
+bool LineFacet(Vector p1, Vector p2, Vector pa, Vector pb, Vector pc, Vector *p);
+inline void ReflectVector(XYZ *vel, const XYZ *n);
+inline void ReflectVector(XYZ *vel, const XYZ &n);
+inline XYZ DoRotation(XYZ thePoint, float xang, float yang, float zang);
+inline XYZ DoRotationRadian(XYZ thePoint, float xang, float yang, float zang);
+inline float findDistance(XYZ *point1, XYZ *point2);
+inline float findLength(XYZ *point1);
+inline float findLengthfast(XYZ *point1);
+inline float distsq(XYZ *point1, XYZ *point2);
+inline float distsq(XYZ point1, XYZ point2);
+inline float distsqflat(XYZ *point1, XYZ *point2);
+inline float dotproduct(const XYZ *point1, const XYZ *point2);
+bool sphere_line_intersection (
+ float x1, float y1 , float z1,
+ float x2, float y2 , float z2,
+ float x3, float y3 , float z3, float r );
+bool sphere_line_intersection (
+ XYZ *p1, XYZ *p2, XYZ *p3, float *r );
+inline bool DistancePointLine( XYZ *Point, XYZ *LineStart, XYZ *LineEnd, float *Distance, XYZ *Intersection );
+
+
+inline void Normalise(XYZ *vectory)
+{
+ static float d;
+ d = fast_sqrt(vectory->x * vectory->x + vectory->y * vectory->y + vectory->z * vectory->z);
+ if (d == 0) {
+ return;
+ }
+ vectory->x /= d;
+ vectory->y /= d;
+ vectory->z /= d;
+}
+
+inline XYZ XYZ::operator+(XYZ add)
+{
+ static XYZ ne;
+ ne = add;
+ ne.x += x;
+ ne.y += y;
+ ne.z += z;
+ return ne;
+}
+
+inline XYZ XYZ::operator-(XYZ add)
+{
+ static XYZ ne;
+ ne = add;
+ ne.x = x - ne.x;
+ ne.y = y - ne.y;
+ ne.z = z - ne.z;
+ return ne;
+}
+
+inline XYZ XYZ::operator*(float add)
+{
+ static XYZ ne;
+ ne.x = x * add;
+ ne.y = y * add;
+ ne.z = z * add;
+ return ne;
+}
+
+inline XYZ XYZ::operator*(XYZ add)
+{
+ static XYZ ne;
+ ne.x = x * add.x;
+ ne.y = y * add.y;
+ ne.z = z * add.z;
+ return ne;
+}
+
+inline XYZ XYZ::operator/(float add)
+{
+ static XYZ ne;
+ ne.x = x / add;
+ ne.y = y / add;
+ ne.z = z / add;
+ return ne;
+}
+
+inline void XYZ::operator+=(XYZ add)
+{
+ x += add.x;
+ y += add.y;
+ z += add.z;
+}
+
+inline void XYZ::operator-=(XYZ add)
+{
+ x = x - add.x;
+ y = y - add.y;
+ z = z - add.z;
+}
+
+inline void XYZ::operator*=(float add)
+{
+ x = x * add;
+ y = y * add;
+ z = z * add;
+}
+
+inline void XYZ::operator*=(XYZ add)
+{
+ x = x * add.x;
+ y = y * add.y;
+ z = z * add.z;
+}
+
+inline void XYZ::operator/=(float add)
+{
+ x = x / add;
+ y = y / add;
+ z = z / add;
+}
+
+inline void XYZ::operator=(float add)
+{
+ x = add;
+ y = add;
+ z = add;
+}
+
+inline void XYZ::vec(Vector add)
+{
+ x = add.x;
+ y = add.y;
+ z = add.z;
+}
+
+inline bool XYZ::operator==(XYZ add)
+{
+ if (x == add.x && y == add.y && z == add.z)
+ return 1;
+ return 0;
+}
+
+inline void CrossProduct(XYZ *P, XYZ *Q, XYZ *V)
+{
+ V->x = P->y * Q->z - P->z * Q->y;
+ V->y = P->z * Q->x - P->x * Q->z;
+ V->z = P->x * Q->y - P->y * Q->x;
+}
+
+inline void CrossProduct(XYZ P, XYZ Q, XYZ *V)
+{
+ V->x = P.y * Q.z - P.z * Q.y;
+ V->y = P.z * Q.x - P.x * Q.z;
+ V->z = P.x * Q.y - P.y * Q.x;
+}
+
+inline float fast_sqrt (register float arg)
+{
+ return sqrtf(arg);
+}
+
+inline float normaldotproduct(XYZ point1, XYZ point2)
+{
+ static GLfloat returnvalue;
+ Normalise(&point1);
+ Normalise(&point2);
+ returnvalue = (point1.x * point2.x + point1.y * point2.y + point1.z * point2.z);
+ return returnvalue;
+}
+
+inline void ReflectVector(XYZ *vel, const XYZ *n)
+{
+ ReflectVector(vel, *n);
+}
+
+inline void ReflectVector(XYZ *vel, const XYZ &n)
+{
+ static XYZ vn;
+ static XYZ vt;
+ static float dotprod;
+
+ dotprod = dotproduct(&n, vel);
+ vn.x = n.x * dotprod;
+ vn.y = n.y * dotprod;
+ vn.z = n.z * dotprod;
+
+ vt.x = vel->x - vn.x;
+ vt.y = vel->y - vn.y;
+ vt.z = vel->z - vn.z;
+
+ vel->x = vt.x - vn.x;
+ vel->y = vt.y - vn.y;
+ vel->z = vt.z - vn.z;
+}
+
+inline float dotproduct(const XYZ *point1, const XYZ *point2)
+{
+ static GLfloat returnvalue;
+ returnvalue = (point1->x * point2->x + point1->y * point2->y + point1->z * point2->z);
+ return returnvalue;
+}
+
+inline float findDistance(XYZ *point1, XYZ *point2)
+{
+ return(fast_sqrt((point1->x - point2->x) * (point1->x - point2->x) + (point1->y - point2->y) * (point1->y - point2->y) + (point1->z - point2->z) * (point1->z - point2->z)));
+}
+
+inline float findLength(XYZ *point1)
+{
+ return(fast_sqrt((point1->x) * (point1->x) + (point1->y) * (point1->y) + (point1->z) * (point1->z)));
+}
+
+
+inline float findLengthfast(XYZ *point1)
+{
+ return((point1->x) * (point1->x) + (point1->y) * (point1->y) + (point1->z) * (point1->z));
+}
+
+inline float distsq(XYZ *point1, XYZ *point2)
+{
+ return((point1->x - point2->x) * (point1->x - point2->x) + (point1->y - point2->y) * (point1->y - point2->y) + (point1->z - point2->z) * (point1->z - point2->z));
+}
+
+inline float distsq(XYZ point1, XYZ point2)
+{
+ return((point1.x - point2.x) * (point1.x - point2.x) + (point1.y - point2.y) * (point1.y - point2.y) + (point1.z - point2.z) * (point1.z - point2.z));
+}
+
+inline float distsqflat(XYZ *point1, XYZ *point2)
+{
+ return((point1->x - point2->x) * (point1->x - point2->x) + (point1->z - point2->z) * (point1->z - point2->z));
+}
+
+inline XYZ DoRotation(XYZ thePoint, float xang, float yang, float zang)
+{
+ static XYZ newpoint;
+ if (xang) {
+ xang *= 6.283185f;
+ xang /= 360;
+ }
+ if (yang) {
+ yang *= 6.283185f;
+ yang /= 360;
+ }
+ if (zang) {
+ zang *= 6.283185f;
+ zang /= 360;
+ }
+
+
+ if (yang) {
+ newpoint.z = thePoint.z * cosf(yang) - thePoint.x * sinf(yang);
+ newpoint.x = thePoint.z * sinf(yang) + thePoint.x * cosf(yang);
+ thePoint.z = newpoint.z;
+ thePoint.x = newpoint.x;
+ }
+
+ if (zang) {
+ newpoint.x = thePoint.x * cosf(zang) - thePoint.y * sinf(zang);
+ newpoint.y = thePoint.y * cosf(zang) + thePoint.x * sinf(zang);
+ thePoint.x = newpoint.x;
+ thePoint.y = newpoint.y;
+ }
+
+ if (xang) {
+ newpoint.y = thePoint.y * cosf(xang) - thePoint.z * sinf(xang);
+ newpoint.z = thePoint.y * sinf(xang) + thePoint.z * cosf(xang);
+ thePoint.z = newpoint.z;
+ thePoint.y = newpoint.y;
+ }
+
+ return thePoint;
+}
+
+inline float square( float f )
+{
+ return (f * f) ;
+}
+
+inline bool sphere_line_intersection (
+ float x1, float y1 , float z1,
+ float x2, float y2 , float z2,
+ float x3, float y3 , float z3, float r )
+{
+
+ // x1,y1,z1 P1 coordinates (point of line)
+ // x2,y2,z2 P2 coordinates (point of line)
+ // x3,y3,z3, r P3 coordinates and radius (sphere)
+ // x,y,z intersection coordinates
+ //
+ // This function returns a pointer array which first index indicates
+ // the number of intersection point, followed by coordinate pairs.
+
+ //~ static float x , y , z;
+ static float a, b, c, /*mu,*/ i ;
+
+ if (x1 > x3 + r && x2 > x3 + r) return(0);
+ if (x1 < x3 - r && x2 < x3 - r) return(0);
+ if (y1 > y3 + r && y2 > y3 + r) return(0);
+ if (y1 < y3 - r && y2 < y3 - r) return(0);
+ if (z1 > z3 + r && z2 > z3 + r) return(0);
+ if (z1 < z3 - r && z2 < z3 - r) return(0);
+ a = square(x2 - x1) + square(y2 - y1) + square(z2 - z1);
+ b = 2 * ( (x2 - x1) * (x1 - x3)
+ + (y2 - y1) * (y1 - y3)
+ + (z2 - z1) * (z1 - z3) ) ;
+ c = square(x3) + square(y3) +
+ square(z3) + square(x1) +
+ square(y1) + square(z1) -
+ 2 * ( x3 * x1 + y3 * y1 + z3 * z1 ) - square(r) ;
+ i = b * b - 4 * a * c ;
+
+ if ( i < 0.0 ) {
+ // no intersection
+ return(0);
+ }
+ return(1);
+}
+
+inline bool sphere_line_intersection (
+ XYZ *p1, XYZ *p2, XYZ *p3, float *r )
+{
+
+ // x1,p1->y,p1->z P1 coordinates (point of line)
+ // p2->x,p2->y,p2->z P2 coordinates (point of line)
+ // p3->x,p3->y,p3->z, r P3 coordinates and radius (sphere)
+ // x,y,z intersection coordinates
+ //
+ // This function returns a pointer array which first index indicates
+ // the number of intersection point, followed by coordinate pairs.
+
+ //~ static float x , y , z;
+ static float a, b, c, /*mu,*/ i ;
+
+ if (p1->x > p3->x + *r && p2->x > p3->x + *r) return(0);
+ if (p1->x < p3->x - *r && p2->x < p3->x - *r) return(0);
+ if (p1->y > p3->y + *r && p2->y > p3->y + *r) return(0);
+ if (p1->y < p3->y - *r && p2->y < p3->y - *r) return(0);
+ if (p1->z > p3->z + *r && p2->z > p3->z + *r) return(0);
+ if (p1->z < p3->z - *r && p2->z < p3->z - *r) return(0);
+ a = square(p2->x - p1->x) + square(p2->y - p1->y) + square(p2->z - p1->z);
+ b = 2 * ( (p2->x - p1->x) * (p1->x - p3->x)
+ + (p2->y - p1->y) * (p1->y - p3->y)
+ + (p2->z - p1->z) * (p1->z - p3->z) ) ;
+ c = square(p3->x) + square(p3->y) +
+ square(p3->z) + square(p1->x) +
+ square(p1->y) + square(p1->z) -
+ 2 * ( p3->x * p1->x + p3->y * p1->y + p3->z * p1->z ) - square(*r) ;
+ i = b * b - 4 * a * c ;
+
+ if ( i < 0.0 ) {
+ // no intersection
+ return(0);
+ }
+ return(1);
+}
+
+inline XYZ DoRotationRadian(XYZ thePoint, float xang, float yang, float zang)
+{
+ static XYZ newpoint;
+ static XYZ oldpoint;
+
+ oldpoint = thePoint;
+
+ if (yang != 0) {
+ newpoint.z = oldpoint.z * cosf(yang) - oldpoint.x * sinf(yang);
+ newpoint.x = oldpoint.z * sinf(yang) + oldpoint.x * cosf(yang);
+ oldpoint.z = newpoint.z;
+ oldpoint.x = newpoint.x;
+ }
+
+ if (zang != 0) {
+ newpoint.x = oldpoint.x * cosf(zang) - oldpoint.y * sinf(zang);
+ newpoint.y = oldpoint.y * cosf(zang) + oldpoint.x * sinf(zang);
+ oldpoint.x = newpoint.x;
+ oldpoint.y = newpoint.y;
+ }
+
+ if (xang != 0) {
+ newpoint.y = oldpoint.y * cosf(xang) - oldpoint.z * sinf(xang);
+ newpoint.z = oldpoint.y * sinf(xang) + oldpoint.z * cosf(xang);
+ oldpoint.z = newpoint.z;
+ oldpoint.y = newpoint.y;
+ }
+
+ return oldpoint;
+
+}
+
+inline bool DistancePointLine( XYZ *Point, XYZ *LineStart, XYZ *LineEnd, float *Distance, XYZ *Intersection )
+{
+ float LineMag;
+ float U;
+
+ LineMag = findDistance( LineEnd, LineStart );
+
+ U = ( ( ( Point->x - LineStart->x ) * ( LineEnd->x - LineStart->x ) ) +
+ ( ( Point->y - LineStart->y ) * ( LineEnd->y - LineStart->y ) ) +
+ ( ( Point->z - LineStart->z ) * ( LineEnd->z - LineStart->z ) ) ) /
+ ( LineMag * LineMag );
+
+ if ( U < 0.0f || U > 1.0f )
+ return 0; // closest point does not fall within the line segment
+
+ Intersection->x = LineStart->x + U * ( LineEnd->x - LineStart->x );
+ Intersection->y = LineStart->y + U * ( LineEnd->y - LineStart->y );
+ Intersection->z = LineStart->z + U * ( LineEnd->z - LineStart->z );
+
+ *Distance = findDistance( Point, Intersection );
+
+ return 1;
+}
+
+#endif
--- /dev/null
+/*
+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 _RANDOM_H_
+#define _RANDOM_H_
+
+#include <stdlib.h>
+
+static inline short Random()
+{
+ return rand();
+}
+
+#endif
+++ /dev/null
-/*
-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/>.
-*/
-
-#include <vector>
-#include <string>
-#include <set>
-#include "gamegl.h"
-
-#include "Menu.h"
-#include "Settings.h"
-#include "Input.h"
-#include "Campaign.h"
-
-// Should not be needed, Menu should call methods from other classes to launch maps and challenges and so on
-#include "Awards.h"
-#include "openal_wrapper.h"
-
-using namespace Game;
-
-extern float multiplier;
-extern std::set<std::pair<int,int>> resolutions;
-extern int mainmenu;
-extern std::vector<CampaignLevel> campaignlevels;
-extern float musicvolume[4];
-extern float oldmusicvolume[4];
-extern bool stillloading;
-extern bool visibleloading;
-extern int whichchoice;
-extern int leveltheme;
-
-extern void toggleFullscreen();
-
-int entername = 0;
-
-std::vector<MenuItem> Menu::items;
-
-MenuItem::MenuItem(MenuItemType _type, int _id, const string& _text, Texture _texture,
- int _x, int _y, int _w, int _h, float _r, float _g, float _b,
- float _linestartsize, float _lineendsize):
- type(_type),
- id(_id),
- text(_text),
- texture(_texture),
- x(_x),
- y(_y),
- w(_w),
- h(_h),
- r(_r),
- g(_g),
- b(_b),
- effectfade(0),
- linestartsize(_linestartsize),
- lineendsize(_lineendsize)
-{
- if (type == MenuItem::BUTTON) {
- if (w == -1) {
- w = text.length() * 10;
- }
- if (h == -1) {
- h = 20;
- }
- }
-}
-
-void Menu::clearMenu()
-{
- items.clear();
-}
-
-void Menu::addLabel(int id, const string& text, int x, int y, float r, float g, float b)
-{
- items.emplace_back(MenuItem::LABEL, id, text, Texture(), x, y, -1, -1, r, g, b);
-}
-void Menu::addButton(int id, const string& text, int x, int y, float r, float g, float b)
-{
- items.emplace_back(MenuItem::BUTTON, id, text, Texture(), x, y, -1, -1, r, g, b);
-}
-void Menu::addImage(int id, Texture texture, int x, int y, int w, int h, float r, float g, float b)
-{
- items.emplace_back(MenuItem::IMAGE, id, "", texture, x, y, w, h, r, g, b);
-}
-void Menu::addButtonImage(int id, Texture texture, int x, int y, int w, int h, float r, float g, float b)
-{
- items.emplace_back(MenuItem::IMAGEBUTTON, id, "", texture, x, y, w, h, r, g, b);
-}
-void Menu::addMapLine(int x, int y, int w, int h, float startsize, float endsize, float r, float g, float b)
-{
- items.emplace_back(MenuItem::MAPLINE, -1, "", Texture(), x, y, w, h, r, g, b, startsize, endsize);
-}
-void Menu::addMapMarker(int id, Texture texture, int x, int y, int w, int h, float r, float g, float b)
-{
- items.emplace_back(MenuItem::MAPMARKER, id, "", texture, x, y, w, h, r, g, b);
-}
-void Menu::addMapLabel(int id, const string& text, int x, int y, float r, float g, float b)
-{
- items.emplace_back(MenuItem::MAPLABEL, id, text, Texture(), x, y, -1, -1, r, g, b);
-}
-
-void Menu::setText(int id, const string& text)
-{
- for (vector<MenuItem>::iterator it = items.begin(); it != items.end(); it++)
- if (it->id == id) {
- it->text = text;
- it->w = it->text.length() * 10;
- break;
- }
-}
-
-void Menu::setText(int id, const string& text, int x, int y, int w, int h)
-{
- for (vector<MenuItem>::iterator it = items.begin(); it != items.end(); it++)
- if (it->id == id) {
- it->text = text;
- it->x = x;
- it->y = y;
- if (w == -1)
- it->w = it->text.length() * 10;
- if (h == -1)
- it->h = 20;
- break;
- }
-}
-
-int Menu::getSelected(int mousex, int mousey)
-{
- for (vector<MenuItem>::iterator it = items.begin(); it != items.end(); it++)
- if (it->type == MenuItem::BUTTON || it->type == MenuItem::IMAGEBUTTON || it->type == MenuItem::MAPMARKER) {
- int mx = mousex;
- int my = mousey;
- if (it->type == MenuItem::MAPMARKER) {
- mx -= 1;
- my += 2;
- }
- if (mx >= it->x && mx < it->x + it->w && my >= it->y && my < it->y + it->h)
- return it->id;
- }
- return -1;
-}
-
-void Menu::handleFadeEffect()
-{
- for (vector<MenuItem>::iterator it = items.begin(); it != items.end(); it++) {
- if (it->id == Game::selected) {
- it->effectfade += multiplier * 5;
- if (it->effectfade > 1)
- it->effectfade = 1;
- } else {
- it->effectfade -= multiplier * 5;
- if (it->effectfade < 0)
- it->effectfade = 0;
- }
- }
-}
-
-void Menu::drawItems()
-{
- handleFadeEffect();
- glEnable(GL_TEXTURE_2D);
- glEnable(GL_ALPHA_TEST);
- glEnable(GL_BLEND);
- for (vector<MenuItem>::iterator it = items.begin(); it != items.end(); it++) {
- switch (it->type) {
- case MenuItem::IMAGE:
- case MenuItem::IMAGEBUTTON:
- case MenuItem::MAPMARKER:
- glColor4f(it->r, it->g, it->b, 1);
- glPushMatrix();
- if (it->type == MenuItem::MAPMARKER) {
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glTranslatef(2.5, -4.5, 0); //from old code
- } else {
- glBlendFunc(GL_SRC_ALPHA, GL_ONE);
- }
- it->texture.bind();
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glBegin(GL_QUADS);
- glTexCoord2f(0, 0);
- glVertex3f(it->x, it->y, 0);
- glTexCoord2f(1, 0);
- glVertex3f(it->x + it->w, it->y, 0);
- glTexCoord2f(1, 1);
- glVertex3f(it->x + it->w, it->y + it->h, 0);
- glTexCoord2f(0, 1);
- glVertex3f(it->x, it->y + it->h, 0);
- glEnd();
- if (it->type != MenuItem::IMAGE) {
- //mouseover highlight
- for (int i = 0; i < 10; i++) {
- if (1 - ((float)i) / 10 - (1 - it->effectfade) > 0) {
- glColor4f(it->r, it->g, it->b, (1 - ((float)i) / 10 - (1 - it->effectfade))*.25);
- glBegin(GL_QUADS);
- glTexCoord2f(0, 0);
- glVertex3f(it->x - ((float)i) * 1 / 2, it->y - ((float)i) * 1 / 2, 0);
- glTexCoord2f(1, 0);
- glVertex3f(it->x + it->w + ((float)i) * 1 / 2, it->y - ((float)i) * 1 / 2, 0);
- glTexCoord2f(1, 1);
- glVertex3f(it->x + it->w + ((float)i) * 1 / 2, it->y + it->h + ((float)i) * 1 / 2, 0);
- glTexCoord2f(0, 1);
- glVertex3f(it->x - ((float)i) * 1 / 2, it->y + it->h + ((float)i) * 1 / 2, 0);
- glEnd();
- }
- }
- }
- glPopMatrix();
- break;
- case MenuItem::LABEL:
- case MenuItem::BUTTON:
- glColor4f(it->r, it->g, it->b, 1);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- Game::text->glPrint(it->x, it->y, it->text.c_str(), 0, 1, 640, 480);
- if (it->type != MenuItem::LABEL) {
- //mouseover highlight
- glBlendFunc(GL_SRC_ALPHA, GL_ONE);
- for (int i = 0; i < 15; i++) {
- if (1 - ((float)i) / 15 - (1 - it->effectfade) > 0) {
- glColor4f(it->r, it->g, it->b, (1 - ((float)i) / 10 - (1 - it->effectfade))*.25);
- Game::text->glPrint(it->x - ((float)i), it->y, it->text.c_str(), 0, 1 + ((float)i) / 70, 640, 480);
- }
- }
- }
- break;
- case MenuItem::MAPLABEL:
- Game::text->glPrintOutlined(0.9, 0, 0, it->x, it->y, it->text.c_str(), 0, 0.6, 640, 480);
- break;
- case MenuItem::MAPLINE: {
- XYZ linestart;
- linestart.x = it->x;
- linestart.y = it->y;
- linestart.z = 0;
- XYZ lineend;
- lineend.x = it->x + it->w;
- lineend.y = it->y + it->h;
- lineend.z = 0;
- XYZ offset = lineend - linestart;
- XYZ fac = offset;
- Normalise(&fac);
- offset = DoRotation(offset, 0, 0, 90);
- Normalise(&offset);
-
- linestart += fac * 4 * it->linestartsize;
- lineend -= fac * 4 * it->lineendsize;
-
- glDisable(GL_TEXTURE_2D);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glColor4f(it->r, it->g, it->b, 1);
- glPushMatrix();
- glTranslatef(2, -5, 0); //from old code
- glBegin(GL_QUADS);
- glVertex3f(linestart.x - offset.x * it->linestartsize, linestart.y - offset.y * it->linestartsize, 0.0f);
- glVertex3f(linestart.x + offset.x * it->linestartsize, linestart.y + offset.y * it->linestartsize, 0.0f);
- glVertex3f(lineend.x + offset.x * it->lineendsize, lineend.y + offset.y * it->lineendsize, 0.0f);
- glVertex3f(lineend.x - offset.x * it->lineendsize, lineend.y - offset.y * it->lineendsize, 0.0f);
- glEnd();
- glPopMatrix();
- glEnable(GL_TEXTURE_2D);
- }
- break;
- default:
- case MenuItem::NONE:
- break;
- }
- }
-}
-
-void Menu::updateSettingsMenu()
-{
- std::string sbuf = std::string("Resolution: ") + to_string(newscreenwidth) + "*" + to_string(newscreenheight);
- if (((float)newscreenwidth <= (float)newscreenheight * 1.61) && ((float)newscreenwidth >= (float)newscreenheight * 1.59)) {
- sbuf += " (widescreen)";
- }
- setText(0, sbuf);
- setText(14, fullscreen ? "Fullscreen: On" : "Fullscreen: Off");
- if (newdetail == 0) setText(1, "Detail: Low");
- if (newdetail == 1) setText(1, "Detail: Medium");
- if (newdetail == 2) setText(1, "Detail: High");
- if (bloodtoggle == 0) setText(2, "Blood: Off");
- if (bloodtoggle == 1) setText(2, "Blood: On, low detail");
- if (bloodtoggle == 2) setText(2, "Blood: On, high detail (slower)");
- setText(4, ismotionblur ? "Blur Effects: Enabled (less compatible)" : "Blur Effects: Disabled (more compatible)");
- setText(5, decals ? "Decals: Enabled (slower)" : "Decals: Disabled");
- setText(6, musictoggle ? "Music: Enabled" : "Music: Disabled");
- setText(9, invertmouse ? "Invert mouse: Yes" : "Invert mouse: No");
- setText(10, std::string("Mouse Speed: ") + to_string(int(usermousesensitivity * 5)));
- setText(11, std::string("Volume: ") + to_string(int(volume * 100)) + "%");
- setText(13, showdamagebar ? "Damage Bar: On" : "Damage Bar: Off");
- if ((newdetail == detail) && (newscreenheight == (int)screenheight) && (newscreenwidth == (int)screenwidth)) {
- setText(8, "Back");
- } else {
- setText(8, "Back (some changes take effect next time Lugaru is opened)");
- }
-}
-
-void Menu::updateStereoConfigMenu()
-{
- setText(0, std::string("Stereo mode: ") + StereoModeName(newstereomode));
- setText(1, std::string("Stereo separation: ") + to_string(stereoseparation));
- setText(2, std::string("Reverse stereo: ") + (stereoreverse ? "Yes" : "No"));
-}
-
-void Menu::updateControlsMenu()
-{
- setText(0, (string)"Forwards: " + (keyselect == 0 ? "_" : Input::keyToChar(forwardkey)));
- setText(1, (string)"Back: " + (keyselect == 1 ? "_" : Input::keyToChar(backkey)));
- setText(2, (string)"Left: " + (keyselect == 2 ? "_" : Input::keyToChar(leftkey)));
- setText(3, (string)"Right: " + (keyselect == 3 ? "_" : Input::keyToChar(rightkey)));
- setText(4, (string)"Crouch: " + (keyselect == 4 ? "_" : Input::keyToChar(crouchkey)));
- setText(5, (string)"Jump: " + (keyselect == 5 ? "_" : Input::keyToChar(jumpkey)));
- setText(6, (string)"Draw: " + (keyselect == 6 ? "_" : Input::keyToChar(drawkey)));
- setText(7, (string)"Throw: " + (keyselect == 7 ? "_" : Input::keyToChar(throwkey)));
- setText(8, (string)"Attack: " + (keyselect == 8 ? "_" : Input::keyToChar(attackkey)));
- if (devtools) {
- setText(9, (string)"Console: " + (keyselect == 9 ? "_" : Input::keyToChar(consolekey)));
- }
-}
-
-/*
-Values of mainmenu :
-1 Main menu
-2 Menu pause (resume/end game)
-3 Option menu
-4 Controls configuration menu
-5 Main game menu (choose level or challenge)
-6 Deleting user menu
-7 User managment menu (select/add)
-8 Choose difficulty menu
-9 Challenge level selection menu
-10 End of the campaign congratulation (is that really a menu?)
-11 Same that 9 ??? => unused
-18 stereo configuration
-*/
-
-void Menu::Load()
-{
- clearMenu();
- switch (mainmenu) {
- case 1:
- case 2:
- addImage(0, Mainmenuitems[0], 150, 480 - 128, 256, 128);
- addButtonImage(1, Mainmenuitems[mainmenu == 1 ? 1 : 5], 18, 480 - 152 - 32, 128, 32);
- addButtonImage(2, Mainmenuitems[2], 18, 480 - 228 - 32, 112, 32);
- addButtonImage(3, Mainmenuitems[mainmenu == 1 ? 3 : 6], 18, 480 - 306 - 32, mainmenu == 1 ? 68 : 132, 32);
- break;
- case 3:
- addButton( 0, "", 10 + 20, 440);
- addButton(14, "", 10 + 400, 440);
- addButton( 1, "", 10 + 60, 405);
- addButton( 2, "", 10 + 70, 370);
- addButton( 4, "", 10 , 335);
- addButton( 5, "", 10 + 60, 300);
- addButton( 6, "", 10 + 70, 265);
- addButton( 9, "", 10 , 230);
- addButton(10, "", 20 , 195);
- addButton(11, "", 10 + 60, 160);
- addButton(13, "", 30 , 125);
- addButton( 7, "-Configure Controls-", 10 + 15, 90);
- addButton(12, "-Configure Stereo -", 10 + 15, 55);
- addButton(8, "Back", 10, 10);
- updateSettingsMenu();
- break;
- case 4:
- addButton(0, "", 10 , 400);
- addButton(1, "", 10 + 40, 360);
- addButton(2, "", 10 + 40, 320);
- addButton(3, "", 10 + 30, 280);
- addButton(4, "", 10 + 20, 240);
- addButton(5, "", 10 + 40, 200);
- addButton(6, "", 10 + 40, 160);
- addButton(7, "", 10 + 30, 120);
- addButton(8, "", 10 + 20, 80);
- if (devtools) {
- addButton(9, "", 10 + 10, 40);
- }
- addButton(devtools ? 10 : 9, "Back", 10, 10);
- updateControlsMenu();
- break;
- case 5: {
- LoadCampaign();
- addLabel(-1, Account::active().getName(), 5, 400);
- addButton(1, "Tutorial", 5, 300);
- addButton(2, "Challenge", 5, 240);
- addButton(3, "Delete User", 400, 10);
- addButton(4, "Main Menu", 5, 10);
- addButton(5, "Change User", 5, 180);
- addButton(6, "Campaign : " + Account::active().getCurrentCampaign(), 200, 420);
-
- //show campaign map
- //with (2,-5) offset from old code
- addImage(-1, Mainmenuitems[7], 150 + 2, 60 - 5, 400, 400);
- //show levels
- int numlevels = Account::active().getCampaignChoicesMade();
- numlevels += numlevels > 0 ? campaignlevels[numlevels - 1].nextlevel.size() : 1;
- for (int i = 0; i < numlevels; i++) {
- XYZ midpoint = campaignlevels[i].getCenter();
- float itemsize = campaignlevels[i].getWidth();
- const bool active = (i >= Account::active().getCampaignChoicesMade());
- if (!active) {
- itemsize /= 2;
- }
-
- if (i >= 1) {
- XYZ start = campaignlevels[i - 1].getCenter();
- addMapLine(start.x, start.y, midpoint.x - start.x, midpoint.y - start.y, 0.5, active ? 1 : 0.5, active ? 1 : 0.5, 0, 0);
- }
- addMapMarker(NB_CAMPAIGN_MENU_ITEM + i, Mapcircletexture,
- midpoint.x - itemsize / 2, midpoint.y - itemsize / 2, itemsize, itemsize, active ? 1 : 0.5, 0, 0);
-
- if (active) {
- addMapLabel(-2, campaignlevels[i].description,
- campaignlevels[i].getStartX() + 10,
- campaignlevels[i].getStartY() - 4);
- }
- }
- }
- break;
- case 6:
- addLabel(-1, "Are you sure you want to delete this user?", 10, 400);
- addButton(1, "Yes", 10, 360);
- addButton(2, "No", 10, 320);
- break;
- case 7:
- if (Account::getNbAccounts() < 8)
- addButton(0, "New User", 10, 400);
- else
- addLabel(0, "No More Users", 10, 400);
- addLabel(-2, "", 20, 400);
- addButton(Account::getNbAccounts() + 1, "Back", 10, 10);
- for (int i = 0; i < Account::getNbAccounts(); i++) {
- addButton(i + 1, Account::get(i).getName(), 10, 340 - 20 * (i + 1));
- }
- break;
- case 8:
- addButton(0, "Easier", 10, 400);
- addButton(1, "Difficult", 10, 360);
- addButton(2, "Insane", 10, 320);
- break;
- case 9:
- for (int i = 0; i < numchallengelevels; i++) {
- string name = "Level ";
- name += to_string(i + 1);
- if (name.size() < 17) {
- name.append((17 - name.size()), ' ');
- }
- name += to_string(int(Account::active().getHighScore(i)));
- if (name.size() < 32) {
- name.append((32 - name.size()), ' ');
- }
- int fasttime = (int)round(Account::active().getFastTime(i));
- name += to_string(int((fasttime - fasttime % 60) / 60));
- name += ":";
- if (fasttime % 60 < 10)
- name += "0";
- name += to_string(fasttime % 60);
-
- addButton(i, name, 10, 400 - i * 25, i > Account::active().getProgress() ? 0.5 : 1, 0, 0);
- }
-
- addButton(-1, " High Score Best Time", 10, 440);
- addButton(numchallengelevels, "Back", 10, 10);
- break;
- case 10: {
- addLabel(0, "Congratulations!", 220, 330);
- addLabel(1, "You have avenged your family and", 140, 300);
- addLabel(2, "restored peace to the island of Lugaru.", 110, 270);
- addButton(3, "Back", 10, 10);
- addLabel(4, string("Your score: ") + to_string((int)Account::active().getCampaignScore()), 190, 200);
- addLabel(5, string("Highest score: ") + to_string((int)Account::active().getCampaignHighScore()), 190, 180);
- }
- break;
- case 18:
- addButton(0, "", 70, 400);
- addButton(1, "", 10, 360);
- addButton(2, "", 40, 320);
- addButton(3, "Back", 10, 10);
- updateStereoConfigMenu();
- break;
- }
-}
-
-void Menu::Tick()
-{
- //escape key pressed
- if (Input::isKeyPressed(SDL_SCANCODE_ESCAPE) &&
- (mainmenu >= 3) && (mainmenu != 8) && !((mainmenu == 7) && entername)) {
- selected = -1;
- //finished with settings menu
- if (mainmenu == 3) {
- SaveSettings();
- }
- //effects
- if (mainmenu >= 3 && mainmenu != 8) {
- fireSound();
- flash();
- }
- //go back
- switch (mainmenu) {
- case 3:
- case 5:
- mainmenu = gameon ? 2 : 1;
- break;
- case 4:
- case 18:
- mainmenu = 3;
- break;
- case 6:
- case 7:
- case 9:
- case 10:
- mainmenu = 5;
- break;
- }
- }
-
- //menu buttons
- selected = getSelected(mousecoordh * 640 / screenwidth, 480 - mousecoordv * 480 / screenheight);
-
- // some specific case where we do something even if the left mouse button is not pressed.
- if ((mainmenu == 5) && (endgame == 2)) {
- Account::active().endGame();
- endgame = 0;
- }
- if (mainmenu == 10)
- endgame = 2;
- if (mainmenu == 18 && Input::isKeyPressed(MOUSEBUTTON2) && selected == 1) {
- stereoseparation -= 0.001;
- updateStereoConfigMenu();
- }
-
- static int oldmainmenu = mainmenu;
-
- if (Input::MouseClicked() && (selected >= 0)) { // handling of the left mouse clic in menus
- set<pair<int,int>>::iterator newscreenresolution;
- switch (mainmenu) {
- case 1:
- case 2:
- switch (selected) {
- case 1:
- if (gameon) { //resume
- mainmenu = 0;
- pause_sound(stream_menutheme);
- resume_stream(leveltheme);
- } else { //new game
- fireSound(firestartsound);
- flash();
- mainmenu = (Account::hasActive() ? 5 : 7);
- selected = -1;
- }
- break;
- case 2: //options
- fireSound();
- flash();
- mainmenu = 3;
- if (newdetail > 2)
- newdetail = detail;
- if (newdetail < 0)
- newdetail = detail;
- if (newscreenwidth > 3000)
- newscreenwidth = screenwidth;
- if (newscreenwidth < 0)
- newscreenwidth = screenwidth;
- if (newscreenheight > 3000)
- newscreenheight = screenheight;
- if (newscreenheight < 0)
- newscreenheight = screenheight;
- break;
- case 3:
- fireSound();
- flash();
- if (gameon) { //end game
- gameon = 0;
- mainmenu = 1;
- } else { //quit
- tryquit = 1;
- pause_sound(stream_menutheme);
- }
- break;
- }
- break;
- case 3:
- fireSound();
- switch (selected) {
- case 0:
- newscreenresolution = resolutions.find(make_pair(newscreenwidth, newscreenheight));
- /* Next one (end() + 1 is also end() so the ++ is safe even if it was not found) */
- newscreenresolution++;
- if (newscreenresolution == resolutions.end()) {
- /* It was the last one (or not found), go back to the beginning */
- newscreenresolution = resolutions.begin();
- }
- newscreenwidth = newscreenresolution->first;
- newscreenheight = newscreenresolution->second;
- break;
- case 1:
- newdetail++;
- if (newdetail > 2)
- newdetail = 0;
- break;
- case 2:
- bloodtoggle++;
- if (bloodtoggle > 2)
- bloodtoggle = 0;
- break;
- case 4:
- ismotionblur = !ismotionblur;
- break;
- case 5:
- decals = !decals;
- break;
- case 6:
- musictoggle = !musictoggle;
- if (musictoggle) {
- emit_stream_np(stream_menutheme);
- } else {
- pause_sound(leveltheme);
- pause_sound(stream_fighttheme);
- pause_sound(stream_menutheme);
-
- for (int i = 0; i < 4; i++) {
- oldmusicvolume[i] = 0;
- musicvolume[i] = 0;
- }
- }
- break;
- case 7: // controls
- flash();
- mainmenu = 4;
- selected = -1;
- keyselect = -1;
- break;
- case 8:
- flash();
- SaveSettings();
- mainmenu = gameon ? 2 : 1;
- break;
- case 9:
- invertmouse = !invertmouse;
- break;
- case 10:
- usermousesensitivity += .2;
- if (usermousesensitivity > 2)
- usermousesensitivity = .2;
- break;
- case 11:
- volume += .1f;
- if (volume > 1.0001f)
- volume = 0;
- OPENAL_SetSFXMasterVolume((int)(volume * 255));
- break;
- case 12:
- flash();
- newstereomode = stereomode;
- mainmenu = 18;
- keyselect = -1;
- break;
- case 13:
- showdamagebar = !showdamagebar;
- break;
- case 14:
- toggleFullscreen();
- break;
- }
- updateSettingsMenu();
- break;
- case 4:
- if (!waiting) {
- fireSound();
- if (selected < (devtools ? 10 : 9) && keyselect == -1)
- keyselect = selected;
- if (keyselect != -1)
- setKeySelected();
- if (selected == (devtools ? 10 : 9)) {
- flash();
- mainmenu = 3;
- }
- }
- updateControlsMenu();
- break;
- case 5:
- fireSound();
- flash();
- if ((selected - NB_CAMPAIGN_MENU_ITEM >= Account::active().getCampaignChoicesMade())) {
- startbonustotal = 0;
-
- loading = 2;
- loadtime = 0;
- targetlevel = 7;
- if (firstload)
- TickOnceAfter();
- else
- LoadStuff();
- whichchoice = selected - NB_CAMPAIGN_MENU_ITEM - Account::active().getCampaignChoicesMade();
- actuallevel = (Account::active().getCampaignChoicesMade() > 0 ? campaignlevels[Account::active().getCampaignChoicesMade() - 1].nextlevel[whichchoice] : 0);
- visibleloading = 1;
- stillloading = 1;
- Loadlevel(campaignlevels[actuallevel].mapname.c_str());
- campaign = 1;
- mainmenu = 0;
- gameon = 1;
- pause_sound(stream_menutheme);
- }
- switch (selected) {
- case 1:
- startbonustotal = 0;
-
- loading = 2;
- loadtime = 0;
- targetlevel = -1;
- if (firstload) {
- TickOnceAfter();
- } else
- LoadStuff();
- Loadlevel(-1);
-
- mainmenu = 0;
- gameon = 1;
- pause_sound(stream_menutheme);
- break;
- case 2:
- mainmenu = 9;
- break;
- case 3:
- mainmenu = 6;
- break;
- case 4:
- mainmenu = (gameon ? 2 : 1);
- break;
- case 5:
- mainmenu = 7;
- break;
- case 6:
- vector<string> campaigns = ListCampaigns();
- vector<string>::iterator c;
- if ((c = find(campaigns.begin(), campaigns.end(), Account::active().getCurrentCampaign())) == campaigns.end()) {
- if (!campaigns.empty())
- Account::active().setCurrentCampaign(campaigns.front());
- } else {
- c++;
- if (c == campaigns.end())
- c = campaigns.begin();
- Account::active().setCurrentCampaign(*c);
- }
- Load();
- break;
- }
- break;
- case 6:
- fireSound();
- if (selected == 1) {
- flash();
- Account::destroyActive();
- mainmenu = 7;
- } else if (selected == 2) {
- flash();
- mainmenu = 5;
- }
- break;
- case 7:
- fireSound();
- if (selected == 0 && Account::getNbAccounts() < 8) {
- entername = 1;
- } else if (selected < Account::getNbAccounts() + 1) {
- flash();
- mainmenu = 5;
- Account::setActive(selected - 1);
- } else if (selected == Account::getNbAccounts() + 1) {
- flash();
- if (Account::hasActive()) {
- mainmenu = 5;
- } else {
- mainmenu = 1;
- }
- displaytext[0].clear();
- displayselected = 0;
- entername = 0;
- }
- break;
- case 8:
- fireSound();
- flash();
- if (selected <= 2)
- Account::active().setDifficulty(selected);
- mainmenu = 5;
- break;
- case 9:
- if (selected < numchallengelevels && selected <= Account::active().getProgress()) {
- fireSound();
- flash();
-
- startbonustotal = 0;
-
- loading = 2;
- loadtime = 0;
- targetlevel = selected;
- if (firstload)
- TickOnceAfter();
- else
- LoadStuff();
- Loadlevel(selected);
- campaign = 0;
-
- mainmenu = 0;
- gameon = 1;
- pause_sound(stream_menutheme);
- }
- if (selected == numchallengelevels) {
- fireSound();
- flash();
- mainmenu = 5;
- }
- break;
- case 10:
- if (selected == 3) {
- fireSound();
- flash();
- mainmenu = 5;
- }
- break;
- case 18:
- if (selected == 1)
- stereoseparation += 0.001;
- else {
- fireSound();
- if (selected == 0) {
- newstereomode = (StereoMode)(newstereomode + 1);
- while (!CanInitStereo(newstereomode)) {
- printf("Failed to initialize mode %s (%i)\n", StereoModeName(newstereomode).c_str(), newstereomode);
- newstereomode = (StereoMode)(newstereomode + 1);
- if (newstereomode >= stereoCount)
- newstereomode = stereoNone;
- }
- } else if (selected == 2) {
- stereoreverse = !stereoreverse;
- } else if (selected == 3) {
- flash();
- mainmenu = 3;
-
- stereomode = newstereomode;
- InitStereo(stereomode);
- }
- }
- updateStereoConfigMenu();
- break;
- }
- }
-
- OPENAL_SetFrequency(channels[stream_menutheme]);
-
- if (entername) {
- inputText(displaytext[0], &displayselected);
- if (!waiting) { // the input as finished
- if (!displaytext[0].empty()) { // with enter
- Account::add(string(displaytext[0]));
-
- mainmenu = 8;
-
- flash();
-
- fireSound(firestartsound);
-
- displaytext[0].clear();
-
- displayselected = 0;
- }
- entername = 0;
- Load();
- }
-
- displayblinkdelay -= multiplier;
- if (displayblinkdelay <= 0) {
- displayblinkdelay = .3;
- displayblink = !displayblink;
- }
- }
-
- if (entername) {
- setText(0, displaytext[0], 20, 400, -1, -1);
- setText(-2, displayblink ? "_" : "", 20 + displayselected * 10, 400, -1, -1);
- }
-
- if (oldmainmenu != mainmenu)
- Load();
- oldmainmenu = mainmenu;
-
-}
-
-int setKeySelected_thread(void* data)
-{
- using namespace Game;
- int scancode = -1;
- SDL_Event evenement;
- while (scancode == -1) {
- SDL_WaitEvent(&evenement);
- switch (evenement.type) {
- case SDL_KEYDOWN:
- scancode = evenement.key.keysym.scancode;
- break;
- case SDL_MOUSEBUTTONDOWN:
- scancode = SDL_NUM_SCANCODES + evenement.button.button;
- break;
- default:
- break;
- }
- }
- if (scancode != SDL_SCANCODE_ESCAPE) {
- fireSound();
- switch (keyselect) {
- case 0:
- forwardkey = scancode;
- break;
- case 1:
- backkey = scancode;
- break;
- case 2:
- leftkey = scancode;
- break;
- case 3:
- rightkey = scancode;
- break;
- case 4:
- crouchkey = scancode;
- break;
- case 5:
- jumpkey = scancode;
- break;
- case 6:
- drawkey = scancode;
- break;
- case 7:
- throwkey = scancode;
- break;
- case 8:
- attackkey = scancode;
- break;
- case 9:
- consolekey = scancode;
- break;
- default:
- break;
- }
- }
- keyselect = -1;
- waiting = false;
- Menu::Load();
- return 0;
-}
-
-void Menu::setKeySelected()
-{
- waiting = true;
- printf("launch thread\n");
- SDL_Thread* thread = SDL_CreateThread(setKeySelected_thread, NULL, NULL);
- if ( thread == NULL ) {
- fprintf(stderr, "Unable to create thread: %s\n", SDL_GetError());
- waiting = false;
- return;
- }
-}
+++ /dev/null
-/*
-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 _MENU_H_
-#define _MENU_H_
-
-#include "Game.h"
-
-struct MenuItem {
- enum MenuItemType {NONE, LABEL, BUTTON, IMAGE, IMAGEBUTTON, MAPMARKER, MAPLINE, MAPLABEL} type;
- int id;
- string text;
- Texture texture;
- int x, y, w, h;
- float r, g, b;
- float effectfade;
-
- float linestartsize;
- float lineendsize;
-
- MenuItem(MenuItemType _type, int _id, const string& _text, Texture _texture,
- int _x, int _y, int _w, int _h, float _r, float _g, float _b,
- float _linestartsize = 1, float _lineendsize = 1);
-};
-
-class Menu
-{
-public:
- static void clearMenu();
- static void addLabel(int id, const string& text, int x, int y, float r = 1, float g = 0, float b = 0);
- static void addButton(int id, const string& text, int x, int y, float r = 1, float g = 0, float b = 0);
- static void addImage(int id, Texture texture, int x, int y, int w, int h, float r = 1, float g = 1, float b = 1);
- static void addButtonImage(int id, Texture texture, int x, int y, int w, int h, float r = 1, float g = 1, float b = 1);
- static void addMapLine(int x, int y, int w, int h, float startsize, float endsize, float r, float g, float b);
- static void addMapMarker(int id, Texture texture, int x, int y, int w, int h, float r, float g, float b);
- static void addMapLabel(int id, const string& text, int x, int y, float r = 1, float g = 0, float b = 0);
- static void setText(int id, const string& text);
- static void setText(int id, const string& text, int x, int y, int w, int h);
- static int getSelected(int mousex, int mousey);
- static void drawItems();
-
- static void Load();
- static void Tick();
- static void updateSettingsMenu();
- static void updateStereoConfigMenu();
- static void updateControlsMenu();
- static void setKeySelected();
-
-private:
- static void handleFadeEffect();
-
- static std::vector<MenuItem> items;
-};
-
-#endif
--- /dev/null
+/*
+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/>.
+*/
+
+#include <vector>
+#include <string>
+#include <set>
+
+#include "Graphic/gamegl.h"
+#include "Level/Campaign.h"
+#include "Menu/Menu.h"
+#include "User/Settings.h"
+#include "Utils/Input.h"
+
+// Should not be needed, Menu should call methods from other classes to launch maps and challenges and so on
+#include "Level/Awards.h"
+#include "Audio/openal_wrapper.h"
+
+using namespace Game;
+
+extern float multiplier;
+extern std::set<std::pair<int,int>> resolutions;
+extern int mainmenu;
+extern std::vector<CampaignLevel> campaignlevels;
+extern float musicvolume[4];
+extern float oldmusicvolume[4];
+extern bool stillloading;
+extern bool visibleloading;
+extern int whichchoice;
+extern int leveltheme;
+
+extern void toggleFullscreen();
+
+int entername = 0;
+
+std::vector<MenuItem> Menu::items;
+
+MenuItem::MenuItem(MenuItemType _type, int _id, const string& _text, Texture _texture,
+ int _x, int _y, int _w, int _h, float _r, float _g, float _b,
+ float _linestartsize, float _lineendsize):
+ type(_type),
+ id(_id),
+ text(_text),
+ texture(_texture),
+ x(_x),
+ y(_y),
+ w(_w),
+ h(_h),
+ r(_r),
+ g(_g),
+ b(_b),
+ effectfade(0),
+ linestartsize(_linestartsize),
+ lineendsize(_lineendsize)
+{
+ if (type == MenuItem::BUTTON) {
+ if (w == -1) {
+ w = text.length() * 10;
+ }
+ if (h == -1) {
+ h = 20;
+ }
+ }
+}
+
+void Menu::clearMenu()
+{
+ items.clear();
+}
+
+void Menu::addLabel(int id, const string& text, int x, int y, float r, float g, float b)
+{
+ items.emplace_back(MenuItem::LABEL, id, text, Texture(), x, y, -1, -1, r, g, b);
+}
+void Menu::addButton(int id, const string& text, int x, int y, float r, float g, float b)
+{
+ items.emplace_back(MenuItem::BUTTON, id, text, Texture(), x, y, -1, -1, r, g, b);
+}
+void Menu::addImage(int id, Texture texture, int x, int y, int w, int h, float r, float g, float b)
+{
+ items.emplace_back(MenuItem::IMAGE, id, "", texture, x, y, w, h, r, g, b);
+}
+void Menu::addButtonImage(int id, Texture texture, int x, int y, int w, int h, float r, float g, float b)
+{
+ items.emplace_back(MenuItem::IMAGEBUTTON, id, "", texture, x, y, w, h, r, g, b);
+}
+void Menu::addMapLine(int x, int y, int w, int h, float startsize, float endsize, float r, float g, float b)
+{
+ items.emplace_back(MenuItem::MAPLINE, -1, "", Texture(), x, y, w, h, r, g, b, startsize, endsize);
+}
+void Menu::addMapMarker(int id, Texture texture, int x, int y, int w, int h, float r, float g, float b)
+{
+ items.emplace_back(MenuItem::MAPMARKER, id, "", texture, x, y, w, h, r, g, b);
+}
+void Menu::addMapLabel(int id, const string& text, int x, int y, float r, float g, float b)
+{
+ items.emplace_back(MenuItem::MAPLABEL, id, text, Texture(), x, y, -1, -1, r, g, b);
+}
+
+void Menu::setText(int id, const string& text)
+{
+ for (vector<MenuItem>::iterator it = items.begin(); it != items.end(); it++)
+ if (it->id == id) {
+ it->text = text;
+ it->w = it->text.length() * 10;
+ break;
+ }
+}
+
+void Menu::setText(int id, const string& text, int x, int y, int w, int h)
+{
+ for (vector<MenuItem>::iterator it = items.begin(); it != items.end(); it++)
+ if (it->id == id) {
+ it->text = text;
+ it->x = x;
+ it->y = y;
+ if (w == -1)
+ it->w = it->text.length() * 10;
+ if (h == -1)
+ it->h = 20;
+ break;
+ }
+}
+
+int Menu::getSelected(int mousex, int mousey)
+{
+ for (vector<MenuItem>::iterator it = items.begin(); it != items.end(); it++)
+ if (it->type == MenuItem::BUTTON || it->type == MenuItem::IMAGEBUTTON || it->type == MenuItem::MAPMARKER) {
+ int mx = mousex;
+ int my = mousey;
+ if (it->type == MenuItem::MAPMARKER) {
+ mx -= 1;
+ my += 2;
+ }
+ if (mx >= it->x && mx < it->x + it->w && my >= it->y && my < it->y + it->h)
+ return it->id;
+ }
+ return -1;
+}
+
+void Menu::handleFadeEffect()
+{
+ for (vector<MenuItem>::iterator it = items.begin(); it != items.end(); it++) {
+ if (it->id == Game::selected) {
+ it->effectfade += multiplier * 5;
+ if (it->effectfade > 1)
+ it->effectfade = 1;
+ } else {
+ it->effectfade -= multiplier * 5;
+ if (it->effectfade < 0)
+ it->effectfade = 0;
+ }
+ }
+}
+
+void Menu::drawItems()
+{
+ handleFadeEffect();
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_ALPHA_TEST);
+ glEnable(GL_BLEND);
+ for (vector<MenuItem>::iterator it = items.begin(); it != items.end(); it++) {
+ switch (it->type) {
+ case MenuItem::IMAGE:
+ case MenuItem::IMAGEBUTTON:
+ case MenuItem::MAPMARKER:
+ glColor4f(it->r, it->g, it->b, 1);
+ glPushMatrix();
+ if (it->type == MenuItem::MAPMARKER) {
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glTranslatef(2.5, -4.5, 0); //from old code
+ } else {
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+ }
+ it->texture.bind();
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glBegin(GL_QUADS);
+ glTexCoord2f(0, 0);
+ glVertex3f(it->x, it->y, 0);
+ glTexCoord2f(1, 0);
+ glVertex3f(it->x + it->w, it->y, 0);
+ glTexCoord2f(1, 1);
+ glVertex3f(it->x + it->w, it->y + it->h, 0);
+ glTexCoord2f(0, 1);
+ glVertex3f(it->x, it->y + it->h, 0);
+ glEnd();
+ if (it->type != MenuItem::IMAGE) {
+ //mouseover highlight
+ for (int i = 0; i < 10; i++) {
+ if (1 - ((float)i) / 10 - (1 - it->effectfade) > 0) {
+ glColor4f(it->r, it->g, it->b, (1 - ((float)i) / 10 - (1 - it->effectfade))*.25);
+ glBegin(GL_QUADS);
+ glTexCoord2f(0, 0);
+ glVertex3f(it->x - ((float)i) * 1 / 2, it->y - ((float)i) * 1 / 2, 0);
+ glTexCoord2f(1, 0);
+ glVertex3f(it->x + it->w + ((float)i) * 1 / 2, it->y - ((float)i) * 1 / 2, 0);
+ glTexCoord2f(1, 1);
+ glVertex3f(it->x + it->w + ((float)i) * 1 / 2, it->y + it->h + ((float)i) * 1 / 2, 0);
+ glTexCoord2f(0, 1);
+ glVertex3f(it->x - ((float)i) * 1 / 2, it->y + it->h + ((float)i) * 1 / 2, 0);
+ glEnd();
+ }
+ }
+ }
+ glPopMatrix();
+ break;
+ case MenuItem::LABEL:
+ case MenuItem::BUTTON:
+ glColor4f(it->r, it->g, it->b, 1);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ Game::text->glPrint(it->x, it->y, it->text.c_str(), 0, 1, 640, 480);
+ if (it->type != MenuItem::LABEL) {
+ //mouseover highlight
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+ for (int i = 0; i < 15; i++) {
+ if (1 - ((float)i) / 15 - (1 - it->effectfade) > 0) {
+ glColor4f(it->r, it->g, it->b, (1 - ((float)i) / 10 - (1 - it->effectfade))*.25);
+ Game::text->glPrint(it->x - ((float)i), it->y, it->text.c_str(), 0, 1 + ((float)i) / 70, 640, 480);
+ }
+ }
+ }
+ break;
+ case MenuItem::MAPLABEL:
+ Game::text->glPrintOutlined(0.9, 0, 0, it->x, it->y, it->text.c_str(), 0, 0.6, 640, 480);
+ break;
+ case MenuItem::MAPLINE: {
+ XYZ linestart;
+ linestart.x = it->x;
+ linestart.y = it->y;
+ linestart.z = 0;
+ XYZ lineend;
+ lineend.x = it->x + it->w;
+ lineend.y = it->y + it->h;
+ lineend.z = 0;
+ XYZ offset = lineend - linestart;
+ XYZ fac = offset;
+ Normalise(&fac);
+ offset = DoRotation(offset, 0, 0, 90);
+ Normalise(&offset);
+
+ linestart += fac * 4 * it->linestartsize;
+ lineend -= fac * 4 * it->lineendsize;
+
+ glDisable(GL_TEXTURE_2D);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glColor4f(it->r, it->g, it->b, 1);
+ glPushMatrix();
+ glTranslatef(2, -5, 0); //from old code
+ glBegin(GL_QUADS);
+ glVertex3f(linestart.x - offset.x * it->linestartsize, linestart.y - offset.y * it->linestartsize, 0.0f);
+ glVertex3f(linestart.x + offset.x * it->linestartsize, linestart.y + offset.y * it->linestartsize, 0.0f);
+ glVertex3f(lineend.x + offset.x * it->lineendsize, lineend.y + offset.y * it->lineendsize, 0.0f);
+ glVertex3f(lineend.x - offset.x * it->lineendsize, lineend.y - offset.y * it->lineendsize, 0.0f);
+ glEnd();
+ glPopMatrix();
+ glEnable(GL_TEXTURE_2D);
+ }
+ break;
+ default:
+ case MenuItem::NONE:
+ break;
+ }
+ }
+}
+
+void Menu::updateSettingsMenu()
+{
+ std::string sbuf = std::string("Resolution: ") + to_string(newscreenwidth) + "*" + to_string(newscreenheight);
+ if (((float)newscreenwidth <= (float)newscreenheight * 1.61) && ((float)newscreenwidth >= (float)newscreenheight * 1.59)) {
+ sbuf += " (widescreen)";
+ }
+ setText(0, sbuf);
+ setText(14, fullscreen ? "Fullscreen: On" : "Fullscreen: Off");
+ if (newdetail == 0) setText(1, "Detail: Low");
+ if (newdetail == 1) setText(1, "Detail: Medium");
+ if (newdetail == 2) setText(1, "Detail: High");
+ if (bloodtoggle == 0) setText(2, "Blood: Off");
+ if (bloodtoggle == 1) setText(2, "Blood: On, low detail");
+ if (bloodtoggle == 2) setText(2, "Blood: On, high detail (slower)");
+ setText(4, ismotionblur ? "Blur Effects: Enabled (less compatible)" : "Blur Effects: Disabled (more compatible)");
+ setText(5, decals ? "Decals: Enabled (slower)" : "Decals: Disabled");
+ setText(6, musictoggle ? "Music: Enabled" : "Music: Disabled");
+ setText(9, invertmouse ? "Invert mouse: Yes" : "Invert mouse: No");
+ setText(10, std::string("Mouse Speed: ") + to_string(int(usermousesensitivity * 5)));
+ setText(11, std::string("Volume: ") + to_string(int(volume * 100)) + "%");
+ setText(13, showdamagebar ? "Damage Bar: On" : "Damage Bar: Off");
+ if ((newdetail == detail) && (newscreenheight == (int)screenheight) && (newscreenwidth == (int)screenwidth)) {
+ setText(8, "Back");
+ } else {
+ setText(8, "Back (some changes take effect next time Lugaru is opened)");
+ }
+}
+
+void Menu::updateStereoConfigMenu()
+{
+ setText(0, std::string("Stereo mode: ") + StereoModeName(newstereomode));
+ setText(1, std::string("Stereo separation: ") + to_string(stereoseparation));
+ setText(2, std::string("Reverse stereo: ") + (stereoreverse ? "Yes" : "No"));
+}
+
+void Menu::updateControlsMenu()
+{
+ setText(0, (string)"Forwards: " + (keyselect == 0 ? "_" : Input::keyToChar(forwardkey)));
+ setText(1, (string)"Back: " + (keyselect == 1 ? "_" : Input::keyToChar(backkey)));
+ setText(2, (string)"Left: " + (keyselect == 2 ? "_" : Input::keyToChar(leftkey)));
+ setText(3, (string)"Right: " + (keyselect == 3 ? "_" : Input::keyToChar(rightkey)));
+ setText(4, (string)"Crouch: " + (keyselect == 4 ? "_" : Input::keyToChar(crouchkey)));
+ setText(5, (string)"Jump: " + (keyselect == 5 ? "_" : Input::keyToChar(jumpkey)));
+ setText(6, (string)"Draw: " + (keyselect == 6 ? "_" : Input::keyToChar(drawkey)));
+ setText(7, (string)"Throw: " + (keyselect == 7 ? "_" : Input::keyToChar(throwkey)));
+ setText(8, (string)"Attack: " + (keyselect == 8 ? "_" : Input::keyToChar(attackkey)));
+ if (devtools) {
+ setText(9, (string)"Console: " + (keyselect == 9 ? "_" : Input::keyToChar(consolekey)));
+ }
+}
+
+/*
+Values of mainmenu :
+1 Main menu
+2 Menu pause (resume/end game)
+3 Option menu
+4 Controls configuration menu
+5 Main game menu (choose level or challenge)
+6 Deleting user menu
+7 User managment menu (select/add)
+8 Choose difficulty menu
+9 Challenge level selection menu
+10 End of the campaign congratulation (is that really a menu?)
+11 Same that 9 ??? => unused
+18 stereo configuration
+*/
+
+void Menu::Load()
+{
+ clearMenu();
+ switch (mainmenu) {
+ case 1:
+ case 2:
+ addImage(0, Mainmenuitems[0], 150, 480 - 128, 256, 128);
+ addButtonImage(1, Mainmenuitems[mainmenu == 1 ? 1 : 5], 18, 480 - 152 - 32, 128, 32);
+ addButtonImage(2, Mainmenuitems[2], 18, 480 - 228 - 32, 112, 32);
+ addButtonImage(3, Mainmenuitems[mainmenu == 1 ? 3 : 6], 18, 480 - 306 - 32, mainmenu == 1 ? 68 : 132, 32);
+ break;
+ case 3:
+ addButton( 0, "", 10 + 20, 440);
+ addButton(14, "", 10 + 400, 440);
+ addButton( 1, "", 10 + 60, 405);
+ addButton( 2, "", 10 + 70, 370);
+ addButton( 4, "", 10 , 335);
+ addButton( 5, "", 10 + 60, 300);
+ addButton( 6, "", 10 + 70, 265);
+ addButton( 9, "", 10 , 230);
+ addButton(10, "", 20 , 195);
+ addButton(11, "", 10 + 60, 160);
+ addButton(13, "", 30 , 125);
+ addButton( 7, "-Configure Controls-", 10 + 15, 90);
+ addButton(12, "-Configure Stereo -", 10 + 15, 55);
+ addButton(8, "Back", 10, 10);
+ updateSettingsMenu();
+ break;
+ case 4:
+ addButton(0, "", 10 , 400);
+ addButton(1, "", 10 + 40, 360);
+ addButton(2, "", 10 + 40, 320);
+ addButton(3, "", 10 + 30, 280);
+ addButton(4, "", 10 + 20, 240);
+ addButton(5, "", 10 + 40, 200);
+ addButton(6, "", 10 + 40, 160);
+ addButton(7, "", 10 + 30, 120);
+ addButton(8, "", 10 + 20, 80);
+ if (devtools) {
+ addButton(9, "", 10 + 10, 40);
+ }
+ addButton(devtools ? 10 : 9, "Back", 10, 10);
+ updateControlsMenu();
+ break;
+ case 5: {
+ LoadCampaign();
+ addLabel(-1, Account::active().getName(), 5, 400);
+ addButton(1, "Tutorial", 5, 300);
+ addButton(2, "Challenge", 5, 240);
+ addButton(3, "Delete User", 400, 10);
+ addButton(4, "Main Menu", 5, 10);
+ addButton(5, "Change User", 5, 180);
+ addButton(6, "Campaign : " + Account::active().getCurrentCampaign(), 200, 420);
+
+ //show campaign map
+ //with (2,-5) offset from old code
+ addImage(-1, Mainmenuitems[7], 150 + 2, 60 - 5, 400, 400);
+ //show levels
+ int numlevels = Account::active().getCampaignChoicesMade();
+ numlevels += numlevels > 0 ? campaignlevels[numlevels - 1].nextlevel.size() : 1;
+ for (int i = 0; i < numlevels; i++) {
+ XYZ midpoint = campaignlevels[i].getCenter();
+ float itemsize = campaignlevels[i].getWidth();
+ const bool active = (i >= Account::active().getCampaignChoicesMade());
+ if (!active) {
+ itemsize /= 2;
+ }
+
+ if (i >= 1) {
+ XYZ start = campaignlevels[i - 1].getCenter();
+ addMapLine(start.x, start.y, midpoint.x - start.x, midpoint.y - start.y, 0.5, active ? 1 : 0.5, active ? 1 : 0.5, 0, 0);
+ }
+ addMapMarker(NB_CAMPAIGN_MENU_ITEM + i, Mapcircletexture,
+ midpoint.x - itemsize / 2, midpoint.y - itemsize / 2, itemsize, itemsize, active ? 1 : 0.5, 0, 0);
+
+ if (active) {
+ addMapLabel(-2, campaignlevels[i].description,
+ campaignlevels[i].getStartX() + 10,
+ campaignlevels[i].getStartY() - 4);
+ }
+ }
+ }
+ break;
+ case 6:
+ addLabel(-1, "Are you sure you want to delete this user?", 10, 400);
+ addButton(1, "Yes", 10, 360);
+ addButton(2, "No", 10, 320);
+ break;
+ case 7:
+ if (Account::getNbAccounts() < 8)
+ addButton(0, "New User", 10, 400);
+ else
+ addLabel(0, "No More Users", 10, 400);
+ addLabel(-2, "", 20, 400);
+ addButton(Account::getNbAccounts() + 1, "Back", 10, 10);
+ for (int i = 0; i < Account::getNbAccounts(); i++) {
+ addButton(i + 1, Account::get(i).getName(), 10, 340 - 20 * (i + 1));
+ }
+ break;
+ case 8:
+ addButton(0, "Easier", 10, 400);
+ addButton(1, "Difficult", 10, 360);
+ addButton(2, "Insane", 10, 320);
+ break;
+ case 9:
+ for (int i = 0; i < numchallengelevels; i++) {
+ string name = "Level ";
+ name += to_string(i + 1);
+ if (name.size() < 17) {
+ name.append((17 - name.size()), ' ');
+ }
+ name += to_string(int(Account::active().getHighScore(i)));
+ if (name.size() < 32) {
+ name.append((32 - name.size()), ' ');
+ }
+ int fasttime = (int)round(Account::active().getFastTime(i));
+ name += to_string(int((fasttime - fasttime % 60) / 60));
+ name += ":";
+ if (fasttime % 60 < 10)
+ name += "0";
+ name += to_string(fasttime % 60);
+
+ addButton(i, name, 10, 400 - i * 25, i > Account::active().getProgress() ? 0.5 : 1, 0, 0);
+ }
+
+ addButton(-1, " High Score Best Time", 10, 440);
+ addButton(numchallengelevels, "Back", 10, 10);
+ break;
+ case 10: {
+ addLabel(0, "Congratulations!", 220, 330);
+ addLabel(1, "You have avenged your family and", 140, 300);
+ addLabel(2, "restored peace to the island of Lugaru.", 110, 270);
+ addButton(3, "Back", 10, 10);
+ addLabel(4, string("Your score: ") + to_string((int)Account::active().getCampaignScore()), 190, 200);
+ addLabel(5, string("Highest score: ") + to_string((int)Account::active().getCampaignHighScore()), 190, 180);
+ }
+ break;
+ case 18:
+ addButton(0, "", 70, 400);
+ addButton(1, "", 10, 360);
+ addButton(2, "", 40, 320);
+ addButton(3, "Back", 10, 10);
+ updateStereoConfigMenu();
+ break;
+ }
+}
+
+void Menu::Tick()
+{
+ //escape key pressed
+ if (Input::isKeyPressed(SDL_SCANCODE_ESCAPE) &&
+ (mainmenu >= 3) && (mainmenu != 8) && !((mainmenu == 7) && entername)) {
+ selected = -1;
+ //finished with settings menu
+ if (mainmenu == 3) {
+ SaveSettings();
+ }
+ //effects
+ if (mainmenu >= 3 && mainmenu != 8) {
+ fireSound();
+ flash();
+ }
+ //go back
+ switch (mainmenu) {
+ case 3:
+ case 5:
+ mainmenu = gameon ? 2 : 1;
+ break;
+ case 4:
+ case 18:
+ mainmenu = 3;
+ break;
+ case 6:
+ case 7:
+ case 9:
+ case 10:
+ mainmenu = 5;
+ break;
+ }
+ }
+
+ //menu buttons
+ selected = getSelected(mousecoordh * 640 / screenwidth, 480 - mousecoordv * 480 / screenheight);
+
+ // some specific case where we do something even if the left mouse button is not pressed.
+ if ((mainmenu == 5) && (endgame == 2)) {
+ Account::active().endGame();
+ endgame = 0;
+ }
+ if (mainmenu == 10)
+ endgame = 2;
+ if (mainmenu == 18 && Input::isKeyPressed(MOUSEBUTTON2) && selected == 1) {
+ stereoseparation -= 0.001;
+ updateStereoConfigMenu();
+ }
+
+ static int oldmainmenu = mainmenu;
+
+ if (Input::MouseClicked() && (selected >= 0)) { // handling of the left mouse clic in menus
+ set<pair<int,int>>::iterator newscreenresolution;
+ switch (mainmenu) {
+ case 1:
+ case 2:
+ switch (selected) {
+ case 1:
+ if (gameon) { //resume
+ mainmenu = 0;
+ pause_sound(stream_menutheme);
+ resume_stream(leveltheme);
+ } else { //new game
+ fireSound(firestartsound);
+ flash();
+ mainmenu = (Account::hasActive() ? 5 : 7);
+ selected = -1;
+ }
+ break;
+ case 2: //options
+ fireSound();
+ flash();
+ mainmenu = 3;
+ if (newdetail > 2)
+ newdetail = detail;
+ if (newdetail < 0)
+ newdetail = detail;
+ if (newscreenwidth > 3000)
+ newscreenwidth = screenwidth;
+ if (newscreenwidth < 0)
+ newscreenwidth = screenwidth;
+ if (newscreenheight > 3000)
+ newscreenheight = screenheight;
+ if (newscreenheight < 0)
+ newscreenheight = screenheight;
+ break;
+ case 3:
+ fireSound();
+ flash();
+ if (gameon) { //end game
+ gameon = 0;
+ mainmenu = 1;
+ } else { //quit
+ tryquit = 1;
+ pause_sound(stream_menutheme);
+ }
+ break;
+ }
+ break;
+ case 3:
+ fireSound();
+ switch (selected) {
+ case 0:
+ newscreenresolution = resolutions.find(make_pair(newscreenwidth, newscreenheight));
+ /* Next one (end() + 1 is also end() so the ++ is safe even if it was not found) */
+ newscreenresolution++;
+ if (newscreenresolution == resolutions.end()) {
+ /* It was the last one (or not found), go back to the beginning */
+ newscreenresolution = resolutions.begin();
+ }
+ newscreenwidth = newscreenresolution->first;
+ newscreenheight = newscreenresolution->second;
+ break;
+ case 1:
+ newdetail++;
+ if (newdetail > 2)
+ newdetail = 0;
+ break;
+ case 2:
+ bloodtoggle++;
+ if (bloodtoggle > 2)
+ bloodtoggle = 0;
+ break;
+ case 4:
+ ismotionblur = !ismotionblur;
+ break;
+ case 5:
+ decals = !decals;
+ break;
+ case 6:
+ musictoggle = !musictoggle;
+ if (musictoggle) {
+ emit_stream_np(stream_menutheme);
+ } else {
+ pause_sound(leveltheme);
+ pause_sound(stream_fighttheme);
+ pause_sound(stream_menutheme);
+
+ for (int i = 0; i < 4; i++) {
+ oldmusicvolume[i] = 0;
+ musicvolume[i] = 0;
+ }
+ }
+ break;
+ case 7: // controls
+ flash();
+ mainmenu = 4;
+ selected = -1;
+ keyselect = -1;
+ break;
+ case 8:
+ flash();
+ SaveSettings();
+ mainmenu = gameon ? 2 : 1;
+ break;
+ case 9:
+ invertmouse = !invertmouse;
+ break;
+ case 10:
+ usermousesensitivity += .2;
+ if (usermousesensitivity > 2)
+ usermousesensitivity = .2;
+ break;
+ case 11:
+ volume += .1f;
+ if (volume > 1.0001f)
+ volume = 0;
+ OPENAL_SetSFXMasterVolume((int)(volume * 255));
+ break;
+ case 12:
+ flash();
+ newstereomode = stereomode;
+ mainmenu = 18;
+ keyselect = -1;
+ break;
+ case 13:
+ showdamagebar = !showdamagebar;
+ break;
+ case 14:
+ toggleFullscreen();
+ break;
+ }
+ updateSettingsMenu();
+ break;
+ case 4:
+ if (!waiting) {
+ fireSound();
+ if (selected < (devtools ? 10 : 9) && keyselect == -1)
+ keyselect = selected;
+ if (keyselect != -1)
+ setKeySelected();
+ if (selected == (devtools ? 10 : 9)) {
+ flash();
+ mainmenu = 3;
+ }
+ }
+ updateControlsMenu();
+ break;
+ case 5:
+ fireSound();
+ flash();
+ if ((selected - NB_CAMPAIGN_MENU_ITEM >= Account::active().getCampaignChoicesMade())) {
+ startbonustotal = 0;
+
+ loading = 2;
+ loadtime = 0;
+ targetlevel = 7;
+ if (firstload)
+ TickOnceAfter();
+ else
+ LoadStuff();
+ whichchoice = selected - NB_CAMPAIGN_MENU_ITEM - Account::active().getCampaignChoicesMade();
+ actuallevel = (Account::active().getCampaignChoicesMade() > 0 ? campaignlevels[Account::active().getCampaignChoicesMade() - 1].nextlevel[whichchoice] : 0);
+ visibleloading = 1;
+ stillloading = 1;
+ Loadlevel(campaignlevels[actuallevel].mapname.c_str());
+ campaign = 1;
+ mainmenu = 0;
+ gameon = 1;
+ pause_sound(stream_menutheme);
+ }
+ switch (selected) {
+ case 1:
+ startbonustotal = 0;
+
+ loading = 2;
+ loadtime = 0;
+ targetlevel = -1;
+ if (firstload) {
+ TickOnceAfter();
+ } else
+ LoadStuff();
+ Loadlevel(-1);
+
+ mainmenu = 0;
+ gameon = 1;
+ pause_sound(stream_menutheme);
+ break;
+ case 2:
+ mainmenu = 9;
+ break;
+ case 3:
+ mainmenu = 6;
+ break;
+ case 4:
+ mainmenu = (gameon ? 2 : 1);
+ break;
+ case 5:
+ mainmenu = 7;
+ break;
+ case 6:
+ vector<string> campaigns = ListCampaigns();
+ vector<string>::iterator c;
+ if ((c = find(campaigns.begin(), campaigns.end(), Account::active().getCurrentCampaign())) == campaigns.end()) {
+ if (!campaigns.empty())
+ Account::active().setCurrentCampaign(campaigns.front());
+ } else {
+ c++;
+ if (c == campaigns.end())
+ c = campaigns.begin();
+ Account::active().setCurrentCampaign(*c);
+ }
+ Load();
+ break;
+ }
+ break;
+ case 6:
+ fireSound();
+ if (selected == 1) {
+ flash();
+ Account::destroyActive();
+ mainmenu = 7;
+ } else if (selected == 2) {
+ flash();
+ mainmenu = 5;
+ }
+ break;
+ case 7:
+ fireSound();
+ if (selected == 0 && Account::getNbAccounts() < 8) {
+ entername = 1;
+ } else if (selected < Account::getNbAccounts() + 1) {
+ flash();
+ mainmenu = 5;
+ Account::setActive(selected - 1);
+ } else if (selected == Account::getNbAccounts() + 1) {
+ flash();
+ if (Account::hasActive()) {
+ mainmenu = 5;
+ } else {
+ mainmenu = 1;
+ }
+ displaytext[0].clear();
+ displayselected = 0;
+ entername = 0;
+ }
+ break;
+ case 8:
+ fireSound();
+ flash();
+ if (selected <= 2)
+ Account::active().setDifficulty(selected);
+ mainmenu = 5;
+ break;
+ case 9:
+ if (selected < numchallengelevels && selected <= Account::active().getProgress()) {
+ fireSound();
+ flash();
+
+ startbonustotal = 0;
+
+ loading = 2;
+ loadtime = 0;
+ targetlevel = selected;
+ if (firstload)
+ TickOnceAfter();
+ else
+ LoadStuff();
+ Loadlevel(selected);
+ campaign = 0;
+
+ mainmenu = 0;
+ gameon = 1;
+ pause_sound(stream_menutheme);
+ }
+ if (selected == numchallengelevels) {
+ fireSound();
+ flash();
+ mainmenu = 5;
+ }
+ break;
+ case 10:
+ if (selected == 3) {
+ fireSound();
+ flash();
+ mainmenu = 5;
+ }
+ break;
+ case 18:
+ if (selected == 1)
+ stereoseparation += 0.001;
+ else {
+ fireSound();
+ if (selected == 0) {
+ newstereomode = (StereoMode)(newstereomode + 1);
+ while (!CanInitStereo(newstereomode)) {
+ printf("Failed to initialize mode %s (%i)\n", StereoModeName(newstereomode).c_str(), newstereomode);
+ newstereomode = (StereoMode)(newstereomode + 1);
+ if (newstereomode >= stereoCount)
+ newstereomode = stereoNone;
+ }
+ } else if (selected == 2) {
+ stereoreverse = !stereoreverse;
+ } else if (selected == 3) {
+ flash();
+ mainmenu = 3;
+
+ stereomode = newstereomode;
+ InitStereo(stereomode);
+ }
+ }
+ updateStereoConfigMenu();
+ break;
+ }
+ }
+
+ OPENAL_SetFrequency(channels[stream_menutheme]);
+
+ if (entername) {
+ inputText(displaytext[0], &displayselected);
+ if (!waiting) { // the input as finished
+ if (!displaytext[0].empty()) { // with enter
+ Account::add(string(displaytext[0]));
+
+ mainmenu = 8;
+
+ flash();
+
+ fireSound(firestartsound);
+
+ displaytext[0].clear();
+
+ displayselected = 0;
+ }
+ entername = 0;
+ Load();
+ }
+
+ displayblinkdelay -= multiplier;
+ if (displayblinkdelay <= 0) {
+ displayblinkdelay = .3;
+ displayblink = !displayblink;
+ }
+ }
+
+ if (entername) {
+ setText(0, displaytext[0], 20, 400, -1, -1);
+ setText(-2, displayblink ? "_" : "", 20 + displayselected * 10, 400, -1, -1);
+ }
+
+ if (oldmainmenu != mainmenu)
+ Load();
+ oldmainmenu = mainmenu;
+
+}
+
+int setKeySelected_thread(void* data)
+{
+ using namespace Game;
+ int scancode = -1;
+ SDL_Event evenement;
+ while (scancode == -1) {
+ SDL_WaitEvent(&evenement);
+ switch (evenement.type) {
+ case SDL_KEYDOWN:
+ scancode = evenement.key.keysym.scancode;
+ break;
+ case SDL_MOUSEBUTTONDOWN:
+ scancode = SDL_NUM_SCANCODES + evenement.button.button;
+ break;
+ default:
+ break;
+ }
+ }
+ if (scancode != SDL_SCANCODE_ESCAPE) {
+ fireSound();
+ switch (keyselect) {
+ case 0:
+ forwardkey = scancode;
+ break;
+ case 1:
+ backkey = scancode;
+ break;
+ case 2:
+ leftkey = scancode;
+ break;
+ case 3:
+ rightkey = scancode;
+ break;
+ case 4:
+ crouchkey = scancode;
+ break;
+ case 5:
+ jumpkey = scancode;
+ break;
+ case 6:
+ drawkey = scancode;
+ break;
+ case 7:
+ throwkey = scancode;
+ break;
+ case 8:
+ attackkey = scancode;
+ break;
+ case 9:
+ consolekey = scancode;
+ break;
+ default:
+ break;
+ }
+ }
+ keyselect = -1;
+ waiting = false;
+ Menu::Load();
+ return 0;
+}
+
+void Menu::setKeySelected()
+{
+ waiting = true;
+ printf("launch thread\n");
+ SDL_Thread* thread = SDL_CreateThread(setKeySelected_thread, NULL, NULL);
+ if ( thread == NULL ) {
+ fprintf(stderr, "Unable to create thread: %s\n", SDL_GetError());
+ waiting = false;
+ return;
+ }
+}
--- /dev/null
+/*
+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 _MENU_H_
+#define _MENU_H_
+
+#include "Game.h"
+
+struct MenuItem {
+ enum MenuItemType {NONE, LABEL, BUTTON, IMAGE, IMAGEBUTTON, MAPMARKER, MAPLINE, MAPLABEL} type;
+ int id;
+ string text;
+ Texture texture;
+ int x, y, w, h;
+ float r, g, b;
+ float effectfade;
+
+ float linestartsize;
+ float lineendsize;
+
+ MenuItem(MenuItemType _type, int _id, const string& _text, Texture _texture,
+ int _x, int _y, int _w, int _h, float _r, float _g, float _b,
+ float _linestartsize = 1, float _lineendsize = 1);
+};
+
+class Menu
+{
+public:
+ static void clearMenu();
+ static void addLabel(int id, const string& text, int x, int y, float r = 1, float g = 0, float b = 0);
+ static void addButton(int id, const string& text, int x, int y, float r = 1, float g = 0, float b = 0);
+ static void addImage(int id, Texture texture, int x, int y, int w, int h, float r = 1, float g = 1, float b = 1);
+ static void addButtonImage(int id, Texture texture, int x, int y, int w, int h, float r = 1, float g = 1, float b = 1);
+ static void addMapLine(int x, int y, int w, int h, float startsize, float endsize, float r, float g, float b);
+ static void addMapMarker(int id, Texture texture, int x, int y, int w, int h, float r, float g, float b);
+ static void addMapLabel(int id, const string& text, int x, int y, float r = 1, float g = 0, float b = 0);
+ static void setText(int id, const string& text);
+ static void setText(int id, const string& text, int x, int y, int w, int h);
+ static int getSelected(int mousex, int mousey);
+ static void drawItems();
+
+ static void Load();
+ static void Tick();
+ static void updateSettingsMenu();
+ static void updateStereoConfigMenu();
+ static void updateControlsMenu();
+ static void setKeySelected();
+
+private:
+ static void handleFadeEffect();
+
+ static std::vector<MenuItem> items;
+};
+
+#endif
+++ /dev/null
-/*
-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/>.
-*/
-
-#include "Game.h"
-#include "Models.h"
-#include "Utils/Folders.h"
-
-extern float multiplier;
-extern float viewdistance;
-extern XYZ viewer;
-extern float fadestart;
-extern float texdetail;
-extern bool decals;
-
-extern bool visibleloading;
-
-int Model::LineCheck(XYZ *p1, XYZ *p2, XYZ *p, XYZ *move, float *rotate)
-{
- static int j;
- static float distance;
- static float olddistance;
- static int intersecting;
- static int firstintersecting;
- static XYZ point;
-
- *p1 = *p1 - *move;
- *p2 = *p2 - *move;
- if (*rotate)
- *p1 = DoRotation(*p1, 0, -*rotate, 0);
- if (*rotate)
- *p2 = DoRotation(*p2, 0, -*rotate, 0);
- if (!sphere_line_intersection(p1, p2, &boundingspherecenter, &boundingsphereradius))
- return -1;
- firstintersecting = -1;
-
- for (j = 0; j < TriangleNum; j++) {
- intersecting = LineFacetd(p1, p2, &vertex[Triangles[j].vertex[0]], &vertex[Triangles[j].vertex[1]], &vertex[Triangles[j].vertex[2]], &facenormals[j], &point);
- distance = (point.x - p1->x) * (point.x - p1->x) + (point.y - p1->y) * (point.y - p1->y) + (point.z - p1->z) * (point.z - p1->z);
- if ((distance < olddistance || firstintersecting == -1) && intersecting) {
- olddistance = distance;
- firstintersecting = j;
- *p = point;
- }
- }
-
- if (*rotate)
- *p = DoRotation(*p, 0, *rotate, 0);
- *p = *p + *move;
- return firstintersecting;
-}
-
-int Model::LineCheckPossible(XYZ *p1, XYZ *p2, XYZ *p, XYZ *move, float *rotate)
-{
- static int j;
- static float distance;
- static float olddistance;
- static int intersecting;
- static int firstintersecting;
- static XYZ point;
-
- *p1 = *p1 - *move;
- *p2 = *p2 - *move;
- if (!sphere_line_intersection(p1, p2, &boundingspherecenter, &boundingsphereradius))
- return -1;
- firstintersecting = -1;
- if (*rotate)
- *p1 = DoRotation(*p1, 0, -*rotate, 0);
- if (*rotate)
- *p2 = DoRotation(*p2, 0, -*rotate, 0);
-
- if (numpossible > 0 && numpossible < TriangleNum)
- for (j = 0; j < numpossible; j++) {
- if (possible[j] >= 0 && possible[j] < TriangleNum) {
- intersecting = LineFacetd(p1, p2, &vertex[Triangles[possible[j]].vertex[0]], &vertex[Triangles[possible[j]].vertex[1]], &vertex[Triangles[possible[j]].vertex[2]], &facenormals[possible[j]], &point);
- distance = (point.x - p1->x) * (point.x - p1->x) + (point.y - p1->y) * (point.y - p1->y) + (point.z - p1->z) * (point.z - p1->z);
- if ((distance < olddistance || firstintersecting == -1) && intersecting) {
- olddistance = distance;
- firstintersecting = possible[j];
- *p = point;
- }
- }
- }
-
- if (*rotate)
- *p = DoRotation(*p, 0, *rotate, 0);
- *p = *p + *move;
- return firstintersecting;
-}
-
-int Model::LineCheckSlidePossible(XYZ *p1, XYZ *p2, XYZ *p, XYZ *move, float *rotate)
-{
- static int j;
- static float distance;
- static float olddistance;
- static int intersecting;
- static int firstintersecting;
- static XYZ point;
-
- *p1 = *p1 - *move;
- *p2 = *p2 - *move;
- if (!sphere_line_intersection(p1, p2, &boundingspherecenter, &boundingsphereradius))
- return -1;
- firstintersecting = -1;
- if (*rotate)
- *p1 = DoRotation(*p1, 0, -*rotate, 0);
- if (*rotate)
- *p2 = DoRotation(*p2, 0, -*rotate, 0);
-
- if (numpossible)
- for (j = 0; j < numpossible; j++) {
- if (possible[j] >= 0 && possible[j] < TriangleNum) {
- intersecting = LineFacetd(p1, p2, &vertex[Triangles[possible[j]].vertex[0]], &vertex[Triangles[possible[j]].vertex[1]], &vertex[Triangles[possible[j]].vertex[2]], &facenormals[possible[j]], &point);
- distance = (point.x - p1->x) * (point.x - p1->x) + (point.y - p1->y) * (point.y - p1->y) + (point.z - p1->z) * (point.z - p1->z);
- if ((distance < olddistance || firstintersecting == -1) && intersecting) {
- olddistance = distance;
- firstintersecting = possible[j];
- }
- }
- }
-
- if (firstintersecting > 0) {
- distance = abs((facenormals[firstintersecting].x * p2->x) + (facenormals[firstintersecting].y * p2->y) + (facenormals[firstintersecting].z * p2->z) - ((facenormals[firstintersecting].x * vertex[Triangles[firstintersecting].vertex[0]].x) + (facenormals[firstintersecting].y * vertex[Triangles[firstintersecting].vertex[0]].y) + (facenormals[firstintersecting].z * vertex[Triangles[firstintersecting].vertex[0]].z)));
- *p2 -= facenormals[firstintersecting] * distance;
- }
-
- if (*rotate)
- *p2 = DoRotation(*p2, 0, *rotate, 0);
- *p2 = *p2 + *move;
- return firstintersecting;
-}
-
-int Model::SphereCheck(XYZ *p1, float radius, XYZ *p, XYZ *move, float *rotate)
-{
- static int i, j;
- static float distance;
- static float olddistance;
- static int intersecting;
- static int firstintersecting;
- static XYZ point;
- static XYZ oldp1;
-
- firstintersecting = -1;
-
- oldp1 = *p1;
- *p1 = *p1 - *move;
- if (*rotate)
- *p1 = DoRotation(*p1, 0, -*rotate, 0);
- if (distsq(p1, &boundingspherecenter) > radius * radius + boundingsphereradius * boundingsphereradius)
- return -1;
-
- for (i = 0; i < 4; i++) {
- for (j = 0; j < TriangleNum; j++) {
- intersecting = 0;
- distance = abs((facenormals[j].x * p1->x) + (facenormals[j].y * p1->y) + (facenormals[j].z * p1->z) - ((facenormals[j].x * vertex[Triangles[j].vertex[0]].x) + (facenormals[j].y * vertex[Triangles[j].vertex[0]].y) + (facenormals[j].z * vertex[Triangles[j].vertex[0]].z)));
- if (distance < radius) {
- point = *p1 - facenormals[j] * distance;
- if (PointInTriangle( &point, facenormals[j], &vertex[Triangles[j].vertex[0]], &vertex[Triangles[j].vertex[1]], &vertex[Triangles[j].vertex[2]]))
- intersecting = 1;
- if (!intersecting)
- intersecting = sphere_line_intersection(&vertex[Triangles[j].vertex[0]], &vertex[Triangles[j].vertex[1]], p1, &radius);
- if (!intersecting)
- intersecting = sphere_line_intersection(&vertex[Triangles[j].vertex[1]], &vertex[Triangles[j].vertex[2]], p1, &radius);
- if (!intersecting)
- intersecting = sphere_line_intersection(&vertex[Triangles[j].vertex[0]], &vertex[Triangles[j].vertex[2]], p1, &radius);
- if (intersecting) {
- *p1 += facenormals[j] * (distance - radius);
- }
- }
- if ((distance < olddistance || firstintersecting == -1) && intersecting) {
- olddistance = distance;
- firstintersecting = j;
- *p = point;
- }
- }
- }
- if (*rotate)
- *p = DoRotation(*p, 0, *rotate, 0);
- *p = *p + *move;
- if (*rotate)
- *p1 = DoRotation(*p1, 0, *rotate, 0);
- *p1 += *move;
- return firstintersecting;
-}
-
-int Model::SphereCheckPossible(XYZ *p1, float radius, XYZ *move, float *rotate)
-{
- static int j;
- static float distance;
- static float olddistance;
- static int intersecting;
- static int firstintersecting;
- static XYZ point;
- static XYZ oldp1;
-
- firstintersecting = -1;
-
- oldp1 = *p1;
- *p1 = *p1 - *move;
-
- numpossible = 0;
-
- if (*rotate)
- *p1 = DoRotation(*p1, 0, -*rotate, 0);
- if (distsq(p1, &boundingspherecenter) > radius * radius + boundingsphereradius * boundingsphereradius) {
- *p1 = oldp1;
- return -1;
- }
-
- for (j = 0; j < TriangleNum; j++) {
- intersecting = 0;
- distance = abs((facenormals[j].x * p1->x) + (facenormals[j].y * p1->y) + (facenormals[j].z * p1->z) - ((facenormals[j].x * vertex[Triangles[j].vertex[0]].x) + (facenormals[j].y * vertex[Triangles[j].vertex[0]].y) + (facenormals[j].z * vertex[Triangles[j].vertex[0]].z)));
- if (distance < radius) {
- point = *p1 - facenormals[j] * distance;
- if (PointInTriangle( &point, facenormals[j], &vertex[Triangles[j].vertex[0]], &vertex[Triangles[j].vertex[1]], &vertex[Triangles[j].vertex[2]]))
- intersecting = 1;
- if (!intersecting)
- intersecting = sphere_line_intersection(&vertex[Triangles[j].vertex[0]], &vertex[Triangles[j].vertex[1]], p1, &radius);
- if (!intersecting)
- intersecting = sphere_line_intersection(&vertex[Triangles[j].vertex[1]], &vertex[Triangles[j].vertex[2]], p1, &radius);
- if (!intersecting)
- intersecting = sphere_line_intersection(&vertex[Triangles[j].vertex[0]], &vertex[Triangles[j].vertex[2]], p1, &radius);
- if (intersecting) {
- possible[numpossible] = j;
- numpossible++;
- }
- }
- if ((distance < olddistance || firstintersecting == -1) && intersecting) {
- olddistance = distance;
- firstintersecting = j;
- }
- }
- if (*rotate)
- *p1 = DoRotation(*p1, 0, *rotate, 0);
- *p1 += *move;
- return firstintersecting;
-}
-
-
-void Model::UpdateVertexArray()
-{
- if (type != normaltype && type != decalstype)
- return;
- static int i;
- static int j;
- if (!flat)
- for (i = 0; i < TriangleNum; i++) {
- j = i * 24;
- vArray[j + 0] = Triangles[i].gx[0];
- vArray[j + 1] = Triangles[i].gy[0];
- vArray[j + 2] = normals[Triangles[i].vertex[0]].x;
- vArray[j + 3] = normals[Triangles[i].vertex[0]].y;
- vArray[j + 4] = normals[Triangles[i].vertex[0]].z;
- vArray[j + 5] = vertex[Triangles[i].vertex[0]].x;
- vArray[j + 6] = vertex[Triangles[i].vertex[0]].y;
- vArray[j + 7] = vertex[Triangles[i].vertex[0]].z;
-
- vArray[j + 8] = Triangles[i].gx[1];
- vArray[j + 9] = Triangles[i].gy[1];
- vArray[j + 10] = normals[Triangles[i].vertex[1]].x;
- vArray[j + 11] = normals[Triangles[i].vertex[1]].y;
- vArray[j + 12] = normals[Triangles[i].vertex[1]].z;
- vArray[j + 13] = vertex[Triangles[i].vertex[1]].x;
- vArray[j + 14] = vertex[Triangles[i].vertex[1]].y;
- vArray[j + 15] = vertex[Triangles[i].vertex[1]].z;
-
- vArray[j + 16] = Triangles[i].gx[2];
- vArray[j + 17] = Triangles[i].gy[2];
- vArray[j + 18] = normals[Triangles[i].vertex[2]].x;
- vArray[j + 19] = normals[Triangles[i].vertex[2]].y;
- vArray[j + 20] = normals[Triangles[i].vertex[2]].z;
- vArray[j + 21] = vertex[Triangles[i].vertex[2]].x;
- vArray[j + 22] = vertex[Triangles[i].vertex[2]].y;
- vArray[j + 23] = vertex[Triangles[i].vertex[2]].z;
- }
- if (flat)
- for (i = 0; i < TriangleNum; i++) {
- j = i * 24;
- vArray[j + 0] = Triangles[i].gx[0];
- vArray[j + 1] = Triangles[i].gy[0];
- vArray[j + 2] = facenormals[i].x * -1;
- vArray[j + 3] = facenormals[i].y * -1;
- vArray[j + 4] = facenormals[i].z * -1;
- vArray[j + 5] = vertex[Triangles[i].vertex[0]].x;
- vArray[j + 6] = vertex[Triangles[i].vertex[0]].y;
- vArray[j + 7] = vertex[Triangles[i].vertex[0]].z;
-
- vArray[j + 8] = Triangles[i].gx[1];
- vArray[j + 9] = Triangles[i].gy[1];
- vArray[j + 10] = facenormals[i].x * -1;
- vArray[j + 11] = facenormals[i].y * -1;
- vArray[j + 12] = facenormals[i].z * -1;
- vArray[j + 13] = vertex[Triangles[i].vertex[1]].x;
- vArray[j + 14] = vertex[Triangles[i].vertex[1]].y;
- vArray[j + 15] = vertex[Triangles[i].vertex[1]].z;
-
- vArray[j + 16] = Triangles[i].gx[2];
- vArray[j + 17] = Triangles[i].gy[2];
- vArray[j + 18] = facenormals[i].x * -1;
- vArray[j + 19] = facenormals[i].y * -1;
- vArray[j + 20] = facenormals[i].z * -1;
- vArray[j + 21] = vertex[Triangles[i].vertex[2]].x;
- vArray[j + 22] = vertex[Triangles[i].vertex[2]].y;
- vArray[j + 23] = vertex[Triangles[i].vertex[2]].z;
-
- }
-}
-
-void Model::UpdateVertexArrayNoTex()
-{
- if (type != normaltype && type != decalstype)
- return;
- static int i;
- static int j;
- if (!flat)
- for (i = 0; i < TriangleNum; i++) {
- j = i * 24;
- vArray[j + 2] = normals[Triangles[i].vertex[0]].x;
- vArray[j + 3] = normals[Triangles[i].vertex[0]].y;
- vArray[j + 4] = normals[Triangles[i].vertex[0]].z;
- vArray[j + 5] = vertex[Triangles[i].vertex[0]].x;
- vArray[j + 6] = vertex[Triangles[i].vertex[0]].y;
- vArray[j + 7] = vertex[Triangles[i].vertex[0]].z;
-
- vArray[j + 10] = normals[Triangles[i].vertex[1]].x;
- vArray[j + 11] = normals[Triangles[i].vertex[1]].y;
- vArray[j + 12] = normals[Triangles[i].vertex[1]].z;
- vArray[j + 13] = vertex[Triangles[i].vertex[1]].x;
- vArray[j + 14] = vertex[Triangles[i].vertex[1]].y;
- vArray[j + 15] = vertex[Triangles[i].vertex[1]].z;
-
- vArray[j + 18] = normals[Triangles[i].vertex[2]].x;
- vArray[j + 19] = normals[Triangles[i].vertex[2]].y;
- vArray[j + 20] = normals[Triangles[i].vertex[2]].z;
- vArray[j + 21] = vertex[Triangles[i].vertex[2]].x;
- vArray[j + 22] = vertex[Triangles[i].vertex[2]].y;
- vArray[j + 23] = vertex[Triangles[i].vertex[2]].z;
- }
- if (flat)
- for (i = 0; i < TriangleNum; i++) {
- j = i * 24;
- vArray[j + 2] = facenormals[i].x * -1;
- vArray[j + 3] = facenormals[i].y * -1;
- vArray[j + 4] = facenormals[i].z * -1;
- vArray[j + 5] = vertex[Triangles[i].vertex[0]].x;
- vArray[j + 6] = vertex[Triangles[i].vertex[0]].y;
- vArray[j + 7] = vertex[Triangles[i].vertex[0]].z;
-
- vArray[j + 10] = facenormals[i].x * -1;
- vArray[j + 11] = facenormals[i].y * -1;
- vArray[j + 12] = facenormals[i].z * -1;
- vArray[j + 13] = vertex[Triangles[i].vertex[1]].x;
- vArray[j + 14] = vertex[Triangles[i].vertex[1]].y;
- vArray[j + 15] = vertex[Triangles[i].vertex[1]].z;
-
- vArray[j + 18] = facenormals[i].x * -1;
- vArray[j + 19] = facenormals[i].y * -1;
- vArray[j + 20] = facenormals[i].z * -1;
- vArray[j + 21] = vertex[Triangles[i].vertex[2]].x;
- vArray[j + 22] = vertex[Triangles[i].vertex[2]].y;
- vArray[j + 23] = vertex[Triangles[i].vertex[2]].z;
- }
-}
-
-void Model::UpdateVertexArrayNoTexNoNorm()
-{
- if (type != normaltype && type != decalstype)
- return;
- static int i;
- static int j;
- for (i = 0; i < TriangleNum; i++) {
- j = i * 24;
- vArray[j + 5] = vertex[Triangles[i].vertex[0]].x;
- vArray[j + 6] = vertex[Triangles[i].vertex[0]].y;
- vArray[j + 7] = vertex[Triangles[i].vertex[0]].z;
-
- vArray[j + 13] = vertex[Triangles[i].vertex[1]].x;
- vArray[j + 14] = vertex[Triangles[i].vertex[1]].y;
- vArray[j + 15] = vertex[Triangles[i].vertex[1]].z;
-
- vArray[j + 21] = vertex[Triangles[i].vertex[2]].x;
- vArray[j + 22] = vertex[Triangles[i].vertex[2]].y;
- vArray[j + 23] = vertex[Triangles[i].vertex[2]].z;
- }
-}
-
-bool Model::loadnotex(const std::string& filename )
-{
- FILE *tfile;
- long i;
-
- type = notextype;
- color = 0;
-
- tfile = Folders::openMandatoryFile( Folders::getResourcePath(filename), "rb" );
-
- // read model settings
-
- fseek(tfile, 0, SEEK_SET);
- funpackf(tfile, "Bs Bs", &vertexNum, &TriangleNum);
-
- // read the model data
- deallocate();
-
- numpossible = 0;
-
- owner = (int*)malloc(sizeof(int) * vertexNum);
- possible = (int*)malloc(sizeof(int) * TriangleNum);
- vertex = (XYZ*)malloc(sizeof(XYZ) * vertexNum);
- Triangles = (TexturedTriangle*)malloc(sizeof(TexturedTriangle) * TriangleNum);
- vArray = (GLfloat*)malloc(sizeof(GLfloat) * TriangleNum * 24);
-
- for (i = 0; i < vertexNum; i++) {
- funpackf(tfile, "Bf Bf Bf", &vertex[i].x, &vertex[i].y, &vertex[i].z);
- }
-
- for (i = 0; i < TriangleNum; i++) {
- short vertex[ 6];
- funpackf(tfile, "Bs Bs Bs Bs Bs Bs", &vertex[ 0], &vertex[ 1], &vertex[ 2], &vertex[ 3], &vertex[ 4], &vertex[ 5]);
- Triangles[i].vertex[ 0] = vertex[ 0];
- Triangles[i].vertex[ 1] = vertex[ 2];
- Triangles[i].vertex[ 2] = vertex[ 4];
- funpackf(tfile, "Bf Bf Bf", &Triangles[i].gx[0], &Triangles[i].gx[1], &Triangles[i].gx[2]);
- funpackf(tfile, "Bf Bf Bf", &Triangles[i].gy[0], &Triangles[i].gy[1], &Triangles[i].gy[2]);
- }
-
- fclose(tfile);
-
- UpdateVertexArray();
-
- for (i = 0; i < vertexNum; i++) {
- owner[i] = -1;
- }
-
- static int j;
- boundingsphereradius = 0;
- for (i = 0; i < vertexNum; i++) {
- for (j = 0; j < vertexNum; j++) {
- if (j != i && distsq(&vertex[j], &vertex[i]) / 2 > boundingsphereradius) {
- boundingsphereradius = distsq(&vertex[j], &vertex[i]) / 2;
- boundingspherecenter = (vertex[i] + vertex[j]) / 2;
- }
- }
- }
- boundingsphereradius = fast_sqrt(boundingsphereradius);
-
- return true;
-}
-
-
-bool Model::load(const std::string& filename, bool texture )
-{
- FILE *tfile;
- long i;
-
- LOGFUNC;
-
- LOG(std::string("Loading model...") + filename);
-
- if (visibleloading)
- Game::LoadingScreen();
-
- type = normaltype;
- color = 0;
-
- tfile = Folders::openMandatoryFile( Folders::getResourcePath(filename), "rb" );
-
- // read model settings
-
- fseek(tfile, 0, SEEK_SET);
- funpackf(tfile, "Bs Bs", &vertexNum, &TriangleNum);
-
- // read the model data
- deallocate();
-
- numpossible = 0;
-
- owner = (int*)malloc(sizeof(int) * vertexNum);
- possible = (int*)malloc(sizeof(int) * TriangleNum);
- vertex = (XYZ*)malloc(sizeof(XYZ) * vertexNum);
- normals = (XYZ*)malloc(sizeof(XYZ) * vertexNum);
- facenormals = (XYZ*)malloc(sizeof(XYZ) * TriangleNum);
- Triangles = (TexturedTriangle*)malloc(sizeof(TexturedTriangle) * TriangleNum);
- vArray = (GLfloat*)malloc(sizeof(GLfloat) * TriangleNum * 24);
-
- for (i = 0; i < vertexNum; i++) {
- funpackf(tfile, "Bf Bf Bf", &vertex[i].x, &vertex[i].y, &vertex[i].z);
- }
-
- for (i = 0; i < TriangleNum; i++) {
- short vertex[ 6];
- funpackf(tfile, "Bs Bs Bs Bs Bs Bs", &vertex[ 0], &vertex[ 1], &vertex[ 2], &vertex[ 3], &vertex[ 4], &vertex[ 5]);
- Triangles[i].vertex[ 0] = vertex[ 0];
- Triangles[i].vertex[ 1] = vertex[ 2];
- Triangles[i].vertex[ 2] = vertex[ 4];
- funpackf(tfile, "Bf Bf Bf", &Triangles[i].gx[0], &Triangles[i].gx[1], &Triangles[i].gx[2]);
- funpackf(tfile, "Bf Bf Bf", &Triangles[i].gy[0], &Triangles[i].gy[1], &Triangles[i].gy[2]);
- }
-
- modelTexture.xsz = 0;
-
- fclose(tfile);
-
- UpdateVertexArray();
-
- for (i = 0; i < vertexNum; i++) {
- owner[i] = -1;
- }
-
- static int j;
- boundingsphereradius = 0;
- for (i = 0; i < vertexNum; i++) {
- for (j = 0; j < vertexNum; j++) {
- if (j != i && distsq(&vertex[j], &vertex[i]) / 2 > boundingsphereradius) {
- boundingsphereradius = distsq(&vertex[j], &vertex[i]) / 2;
- boundingspherecenter = (vertex[i] + vertex[j]) / 2;
- }
- }
- }
- boundingsphereradius = fast_sqrt(boundingsphereradius);
-
- return true;
-}
-
-bool Model::loaddecal(const std::string& filename, bool texture )
-{
- FILE *tfile;
- long i, j;
-
- LOGFUNC;
-
- LOG(std::string("Loading decal...") + Folders::getResourcePath(filename));
-
- type = decalstype;
- numdecals = 0;
- color = 0;
-
- tfile = Folders::openMandatoryFile( Folders::getResourcePath(filename), "rb" );
-
- // read model settings
-
- fseek(tfile, 0, SEEK_SET);
- funpackf(tfile, "Bs Bs", &vertexNum, &TriangleNum);
-
- // read the model data
-
- deallocate();
-
- numpossible = 0;
-
- owner = (int*)malloc(sizeof(int) * vertexNum);
- possible = (int*)malloc(sizeof(int) * TriangleNum);
- vertex = (XYZ*)malloc(sizeof(XYZ) * vertexNum);
- normals = (XYZ*)malloc(sizeof(XYZ) * vertexNum);
- facenormals = (XYZ*)malloc(sizeof(XYZ) * TriangleNum);
- Triangles = (TexturedTriangle*)malloc(sizeof(TexturedTriangle) * TriangleNum);
- vArray = (GLfloat*)malloc(sizeof(GLfloat) * TriangleNum * 24);
-
-
- for (i = 0; i < vertexNum; i++) {
- funpackf(tfile, "Bf Bf Bf", &vertex[i].x, &vertex[i].y, &vertex[i].z);
- }
-
- for (i = 0; i < TriangleNum; i++) {
- short vertex[ 6];
- funpackf(tfile, "Bs Bs Bs Bs Bs Bs", &vertex[ 0], &vertex[ 1], &vertex[ 2], &vertex[ 3], &vertex[ 4], &vertex[ 5]);
- Triangles[i].vertex[ 0] = vertex[ 0];
- Triangles[i].vertex[ 1] = vertex[ 2];
- Triangles[i].vertex[ 2] = vertex[ 4];
- funpackf(tfile, "Bf Bf Bf", &Triangles[i].gx[0], &Triangles[i].gx[1], &Triangles[i].gx[2]);
- funpackf(tfile, "Bf Bf Bf", &Triangles[i].gy[0], &Triangles[i].gy[1], &Triangles[i].gy[2]);
- }
-
-
- modelTexture.xsz = 0;
-
- fclose(tfile);
-
- UpdateVertexArray();
-
- for (i = 0; i < vertexNum; i++) {
- owner[i] = -1;
- }
-
- boundingsphereradius = 0;
- for (i = 0; i < vertexNum; i++) {
- for (j = 0; j < vertexNum; j++) {
- if (j != i && distsq(&vertex[j], &vertex[i]) / 2 > boundingsphereradius) {
- boundingsphereradius = distsq(&vertex[j], &vertex[i]) / 2;
- boundingspherecenter = (vertex[i] + vertex[j]) / 2;
- }
- }
- }
- boundingsphereradius = fast_sqrt(boundingsphereradius);
-
- //allow decals
- if (!decaltexcoords) {
- decaltexcoords = (float***)malloc(sizeof(float**)*max_model_decals);
- for (i = 0; i < max_model_decals; i++) {
- decaltexcoords[i] = (float**)malloc(sizeof(float*) * 3);
- for (j = 0; j < 3; j++) {
- decaltexcoords[i][j] = (float*)malloc(sizeof(float) * 2);
- }
- }
- decalvertex = (XYZ**)malloc(sizeof(XYZ*)*max_model_decals);
- for (i = 0; i < max_model_decals; i++) {
- decalvertex[i] = (XYZ*)malloc(sizeof(XYZ) * 3);
- }
-
- decaltype = (int*)malloc(sizeof(int) * max_model_decals);
- decalopacity = (float*)malloc(sizeof(float) * max_model_decals);
- decalrotation = (float*)malloc(sizeof(float) * max_model_decals);
- decalalivetime = (float*)malloc(sizeof(float) * max_model_decals);
- decalposition = (XYZ*)malloc(sizeof(XYZ) * max_model_decals);
- }
-
- return true;
-}
-
-bool Model::loadraw(const std::string& filename)
-{
- FILE *tfile;
- long i;
-
- LOGFUNC;
-
- LOG(std::string("Loading raw...") + filename);
-
- type = rawtype;
- color = 0;
-
- tfile = Folders::openMandatoryFile( Folders::getResourcePath(filename), "rb" );
-
- // read model settings
-
- fseek(tfile, 0, SEEK_SET);
- funpackf(tfile, "Bs Bs", &vertexNum, &TriangleNum);
-
- // read the model data
- deallocate();
-
- numpossible = 0;
-
- owner = (int*)malloc(sizeof(int) * vertexNum);
- possible = (int*)malloc(sizeof(int) * TriangleNum);
- vertex = (XYZ*)malloc(sizeof(XYZ) * vertexNum);
- Triangles = (TexturedTriangle*)malloc(sizeof(TexturedTriangle) * TriangleNum);
- vArray = (GLfloat*)malloc(sizeof(GLfloat) * TriangleNum * 24);
-
-
- for (i = 0; i < vertexNum; i++) {
- funpackf(tfile, "Bf Bf Bf", &vertex[i].x, &vertex[i].y, &vertex[i].z);
- }
-
- for (i = 0; i < TriangleNum; i++) {
- short vertex[ 6];
- funpackf(tfile, "Bs Bs Bs Bs Bs Bs", &vertex[ 0], &vertex[ 1], &vertex[ 2], &vertex[ 3], &vertex[ 4], &vertex[ 5]);
- Triangles[i].vertex[ 0] = vertex[ 0];
- Triangles[i].vertex[ 1] = vertex[ 2];
- Triangles[i].vertex[ 2] = vertex[ 4];
- funpackf(tfile, "Bf Bf Bf", &Triangles[i].gx[0], &Triangles[i].gx[1], &Triangles[i].gx[2]);
- funpackf(tfile, "Bf Bf Bf", &Triangles[i].gy[0], &Triangles[i].gy[1], &Triangles[i].gy[2]);
- }
-
-
- fclose(tfile);
-
- for (i = 0; i < vertexNum; i++) {
- owner[i] = -1;
- }
-
- return true;
-}
-
-
-void Model::UniformTexCoords()
-{
- static int i;
- for (i = 0; i < TriangleNum; i++) {
- Triangles[i].gy[0] = vertex[Triangles[i].vertex[0]].y;
- Triangles[i].gy[1] = vertex[Triangles[i].vertex[1]].y;
- Triangles[i].gy[2] = vertex[Triangles[i].vertex[2]].y;
- Triangles[i].gx[0] = vertex[Triangles[i].vertex[0]].x;
- Triangles[i].gx[1] = vertex[Triangles[i].vertex[1]].x;
- Triangles[i].gx[2] = vertex[Triangles[i].vertex[2]].x;
- }
- UpdateVertexArray();
-}
-
-
-void Model::FlipTexCoords()
-{
- static int i;
- for (i = 0; i < TriangleNum; i++) {
- Triangles[i].gy[0] = -Triangles[i].gy[0];
- Triangles[i].gy[1] = -Triangles[i].gy[1];
- Triangles[i].gy[2] = -Triangles[i].gy[2];
- }
- UpdateVertexArray();
-}
-
-void Model::ScaleTexCoords(float howmuch)
-{
- static int i;
- for (i = 0; i < TriangleNum; i++) {
- Triangles[i].gx[0] *= howmuch;
- Triangles[i].gx[1] *= howmuch;
- Triangles[i].gx[2] *= howmuch;
- Triangles[i].gy[0] *= howmuch;
- Triangles[i].gy[1] *= howmuch;
- Triangles[i].gy[2] *= howmuch;
- }
- UpdateVertexArray();
-}
-
-void Model::Scale(float xscale, float yscale, float zscale)
-{
- static int i;
- for (i = 0; i < vertexNum; i++) {
- vertex[i].x *= xscale;
- vertex[i].y *= yscale;
- vertex[i].z *= zscale;
- }
- UpdateVertexArray();
-
- static int j;
-
- boundingsphereradius = 0;
- for (i = 0; i < vertexNum; i++) {
- for (j = 0; j < vertexNum; j++) {
- if (j != i && distsq(&vertex[j], &vertex[i]) / 2 > boundingsphereradius) {
- boundingsphereradius = distsq(&vertex[j], &vertex[i]) / 2;
- boundingspherecenter = (vertex[i] + vertex[j]) / 2;
- }
- }
- }
- boundingsphereradius = fast_sqrt(boundingsphereradius);
-}
-
-void Model::ScaleNormals(float xscale, float yscale, float zscale)
-{
- if (type != normaltype && type != decalstype)
- return;
- static int i;
- for (i = 0; i < vertexNum; i++) {
- normals[i].x *= xscale;
- normals[i].y *= yscale;
- normals[i].z *= zscale;
- }
- for (i = 0; i < TriangleNum; i++) {
- facenormals[i].x *= xscale;
- facenormals[i].y *= yscale;
- facenormals[i].z *= zscale;
- }
- UpdateVertexArray();
-}
-
-void Model::Translate(float xtrans, float ytrans, float ztrans)
-{
- static int i;
- for (i = 0; i < vertexNum; i++) {
- vertex[i].x += xtrans;
- vertex[i].y += ytrans;
- vertex[i].z += ztrans;
- }
- UpdateVertexArray();
-
- static int j;
- boundingsphereradius = 0;
- for (i = 0; i < vertexNum; i++) {
- for (j = 0; j < vertexNum; j++) {
- if (j != i && distsq(&vertex[j], &vertex[i]) / 2 > boundingsphereradius) {
- boundingsphereradius = distsq(&vertex[j], &vertex[i]) / 2;
- boundingspherecenter = (vertex[i] + vertex[j]) / 2;
- }
- }
- }
- boundingsphereradius = fast_sqrt(boundingsphereradius);
-}
-
-void Model::Rotate(float xang, float yang, float zang)
-{
- static int i;
- for (i = 0; i < vertexNum; i++) {
- vertex[i] = DoRotation(vertex[i], xang, yang, zang);
- }
- UpdateVertexArray();
-
- static int j;
- boundingsphereradius = 0;
- for (i = 0; i < vertexNum; i++) {
- for (j = 0; j < vertexNum; j++) {
- if (j != i && distsq(&vertex[j], &vertex[i]) / 2 > boundingsphereradius) {
- boundingsphereradius = distsq(&vertex[j], &vertex[i]) / 2;
- boundingspherecenter = (vertex[i] + vertex[j]) / 2;
- }
- }
- }
- boundingsphereradius = fast_sqrt(boundingsphereradius);
-}
-
-
-void Model::CalculateNormals(bool facenormalise)
-{
- if (visibleloading)
- Game::LoadingScreen();
- static int i;
- if (type != normaltype && type != decalstype)
- return;
-
- for (i = 0; i < vertexNum; i++) {
- normals[i].x = 0;
- normals[i].y = 0;
- normals[i].z = 0;
- }
-
- for (i = 0; i < TriangleNum; i++) {
- CrossProduct(vertex[Triangles[i].vertex[1]] - vertex[Triangles[i].vertex[0]], vertex[Triangles[i].vertex[2]] - vertex[Triangles[i].vertex[0]], &facenormals[i]);
-
- normals[Triangles[i].vertex[0]].x += facenormals[i].x;
- normals[Triangles[i].vertex[0]].y += facenormals[i].y;
- normals[Triangles[i].vertex[0]].z += facenormals[i].z;
-
- normals[Triangles[i].vertex[1]].x += facenormals[i].x;
- normals[Triangles[i].vertex[1]].y += facenormals[i].y;
- normals[Triangles[i].vertex[1]].z += facenormals[i].z;
-
- normals[Triangles[i].vertex[2]].x += facenormals[i].x;
- normals[Triangles[i].vertex[2]].y += facenormals[i].y;
- normals[Triangles[i].vertex[2]].z += facenormals[i].z;
- if (facenormalise)
- Normalise(&facenormals[i]);
- }
- for (i = 0; i < vertexNum; i++) {
- Normalise(&normals[i]);
- normals[i] *= -1;
- }
- UpdateVertexArrayNoTex();
-}
-
-void Model::drawimmediate()
-{
- textureptr.bind();
- glBegin(GL_TRIANGLES);
- for (int i = 0; i < TriangleNum; i++) {
- glTexCoord2f(Triangles[i].gx[0], Triangles[i].gy[0]);
- if (color)
- glColor3f(normals[Triangles[i].vertex[0]].x, normals[Triangles[i].vertex[0]].y, normals[Triangles[i].vertex[0]].z);
- if (!color && !flat)
- glNormal3f(normals[Triangles[i].vertex[0]].x, normals[Triangles[i].vertex[0]].y, normals[Triangles[i].vertex[0]].z);
- if (!color && flat)
- glNormal3f(facenormals[i].x, facenormals[i].y, facenormals[i].y);
- glVertex3f(vertex[Triangles[i].vertex[0]].x, vertex[Triangles[i].vertex[0]].y, vertex[Triangles[i].vertex[0]].z);
-
- glTexCoord2f(Triangles[i].gx[1], Triangles[i].gy[1]);
- if (color)
- glColor3f(normals[Triangles[i].vertex[1]].x, normals[Triangles[i].vertex[1]].y, normals[Triangles[i].vertex[1]].z);
- if (!color && !flat)
- glNormal3f(normals[Triangles[i].vertex[1]].x, normals[Triangles[i].vertex[1]].y, normals[Triangles[i].vertex[1]].z);
- if (!color && flat)
- glNormal3f(facenormals[i].x, facenormals[i].y, facenormals[i].y);
- glVertex3f(vertex[Triangles[i].vertex[1]].x, vertex[Triangles[i].vertex[1]].y, vertex[Triangles[i].vertex[1]].z);
-
- glTexCoord2f(Triangles[i].gx[2], Triangles[i].gy[2]);
- if (color)
- glColor3f(normals[Triangles[i].vertex[2]].x, normals[Triangles[i].vertex[2]].y, normals[Triangles[i].vertex[2]].z);
- if (!color && !flat)
- glNormal3f(normals[Triangles[i].vertex[2]].x, normals[Triangles[i].vertex[2]].y, normals[Triangles[i].vertex[2]].z);
- if (!color && flat)
- glNormal3f(facenormals[i].x, facenormals[i].y, facenormals[i].y);
- glVertex3f(vertex[Triangles[i].vertex[2]].x, vertex[Triangles[i].vertex[2]].y, vertex[Triangles[i].vertex[2]].z);
- }
- glEnd();
-}
-
-void Model::draw()
-{
- if (type != normaltype && type != decalstype)
- return;
-
- glEnableClientState(GL_NORMAL_ARRAY);
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-
- if (!color)
- glInterleavedArrays( GL_T2F_N3F_V3F, 8 * sizeof(GLfloat), &vArray[0]);
- if (color)
- glInterleavedArrays( GL_T2F_C3F_V3F, 8 * sizeof(GLfloat), &vArray[0]);
- textureptr.bind();
-
- glDrawArrays(GL_TRIANGLES, 0, TriangleNum * 3);
-
- if (!color)
- glDisableClientState(GL_NORMAL_ARRAY);
- if (color)
- glDisableClientState(GL_COLOR_ARRAY);
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-}
-
-//TODO: phase out in favor of Texture
-void Model::drawdifftex(GLuint texture)
-{
- glEnableClientState(GL_NORMAL_ARRAY);
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- if (!color)
- glInterleavedArrays( GL_T2F_N3F_V3F, 8 * sizeof(GLfloat), &vArray[0]);
- if (color)
- glInterleavedArrays( GL_T2F_C3F_V3F, 8 * sizeof(GLfloat), &vArray[0]);
-
- glBindTexture(GL_TEXTURE_2D, (unsigned long)texture);
- glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
- glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
-
-
-#ifndef WIN32
- glLockArraysEXT( 0, TriangleNum * 3);
-#endif
- glDrawArrays(GL_TRIANGLES, 0, TriangleNum * 3);
-#ifndef WIN32
- glUnlockArraysEXT();
-#endif
-
-
- if (!color)
- glDisableClientState(GL_NORMAL_ARRAY);
- if (color)
- glDisableClientState(GL_COLOR_ARRAY);
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-}
-
-void Model::drawdifftex(Texture texture)
-{
- glEnableClientState(GL_NORMAL_ARRAY);
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- if (!color)
- glInterleavedArrays( GL_T2F_N3F_V3F, 8 * sizeof(GLfloat), &vArray[0]);
- if (color)
- glInterleavedArrays( GL_T2F_C3F_V3F, 8 * sizeof(GLfloat), &vArray[0]);
-
- texture.bind();
- glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
- glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
-
-
-#ifndef WIN32
- glLockArraysEXT( 0, TriangleNum * 3);
-#endif
- glDrawArrays(GL_TRIANGLES, 0, TriangleNum * 3);
-#ifndef WIN32
- glUnlockArraysEXT();
-#endif
-
-
- if (!color)
- glDisableClientState(GL_NORMAL_ARRAY);
- if (color)
- glDisableClientState(GL_COLOR_ARRAY);
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-}
-
-void Model::drawdecals(Texture shadowtexture, Texture bloodtexture, Texture bloodtexture2, Texture breaktexture)
-{
- if (decals) {
- if (type != decalstype)
- return;
- static int i;
- static int lasttype;
- static bool blend;
-
- blend = 1;
-
- lasttype = -1;
- glEnable(GL_BLEND);
- glDisable(GL_LIGHTING);
- glDisable(GL_CULL_FACE);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glDepthMask(0);
- if (numdecals > max_model_decals)
- numdecals = max_model_decals;
- for (i = 0; i < numdecals; i++) {
- if (decaltype[i] == blooddecalfast && decalalivetime[i] < 2)
- decalalivetime[i] = 2;
-
- if (decaltype[i] == shadowdecal && decaltype[i] != lasttype) {
- shadowtexture.bind();
- if (!blend) {
- blend = 1;
- glAlphaFunc(GL_GREATER, 0.0001);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- }
- }
- if (decaltype[i] == breakdecal && decaltype[i] != lasttype) {
- breaktexture.bind();
- if (!blend) {
- blend = 1;
- glAlphaFunc(GL_GREATER, 0.0001);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- }
- }
- if ((decaltype[i] == blooddecal || decaltype[i] == blooddecalslow) && decaltype[i] != lasttype) {
- bloodtexture.bind();
- if (blend) {
- blend = 0;
- glAlphaFunc(GL_GREATER, 0.15);
- glBlendFunc(GL_ONE, GL_ZERO);
- }
- }
- if ((decaltype[i] == blooddecalfast) && decaltype[i] != lasttype) {
- bloodtexture2.bind();
- if (blend) {
- blend = 0;
- glAlphaFunc(GL_GREATER, 0.15);
- glBlendFunc(GL_ONE, GL_ZERO);
- }
- }
- if (decaltype[i] == shadowdecal) {
- glColor4f(1, 1, 1, decalopacity[i]);
- }
- if (decaltype[i] == breakdecal) {
- glColor4f(1, 1, 1, decalopacity[i]);
- if (decalalivetime[i] > 58)
- glColor4f(1, 1, 1, decalopacity[i] * (60 - decalalivetime[i]) / 2);
- }
- if ((decaltype[i] == blooddecal || decaltype[i] == blooddecalfast || decaltype[i] == blooddecalslow)) {
- glColor4f(1, 1, 1, decalopacity[i]);
- if (decalalivetime[i] < 4)
- glColor4f(1, 1, 1, decalopacity[i]*decalalivetime[i]*.25);
- if (decalalivetime[i] > 58)
- glColor4f(1, 1, 1, decalopacity[i] * (60 - decalalivetime[i]) / 2);
- }
- lasttype = decaltype[i];
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
-
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glBegin(GL_TRIANGLES);
- for (int j = 0; j < 3; j++) {
- glTexCoord2f(decaltexcoords[i][j][0], decaltexcoords[i][j][1]);
- glVertex3f(decalvertex[i][j].x, decalvertex[i][j].y, decalvertex[i][j].z);
- }
- glEnd();
- glPopMatrix();
- }
- for (i = numdecals - 1; i >= 0; i--) {
- decalalivetime[i] += multiplier;
- if (decaltype[i] == blooddecalslow)
- decalalivetime[i] -= multiplier * 2 / 3;
- if (decaltype[i] == blooddecalfast)
- decalalivetime[i] += multiplier * 4;
- if (decaltype[i] == shadowdecal)
- DeleteDecal(i);
- if ((decaltype[i] == blooddecal || decaltype[i] == blooddecalfast || decaltype[i] == blooddecalslow) && decalalivetime[i] >= 60)
- DeleteDecal(i);
- }
- glAlphaFunc(GL_GREATER, 0.0001);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- }
-}
-
-void Model::DeleteDecal(int which)
-{
- if (decals) {
- if (type != decalstype)
- return;
- decaltype[which] = decaltype[numdecals - 1];
- decalposition[which] = decalposition[numdecals - 1];
- for (int i = 0; i < 3; i++) {
- decalvertex[which][i] = decalvertex[numdecals - 1][i];
- decaltexcoords[which][i][0] = decaltexcoords[numdecals - 1][i][0];
- decaltexcoords[which][i][1] = decaltexcoords[numdecals - 1][i][1];
- }
- decalrotation[which] = decalrotation[numdecals - 1];
- decalalivetime[which] = decalalivetime[numdecals - 1];
- decalopacity[which] = decalopacity[numdecals - 1];
- numdecals--;
- }
-}
-
-void Model::MakeDecal(int atype, XYZ *where, float *size, float *opacity, float *rotation)
-{
- if (decals) {
- if (type != decalstype)
- return;
-
- static float placex, placez;
- static XYZ rot;
- static float distance;
- static int i, j;
-
- if (*opacity > 0)
- if (distsq(where, &boundingspherecenter) < (boundingsphereradius + *size) * (boundingsphereradius + *size))
- for (i = 0; i < TriangleNum; i++) {
- if (facenormals[i].y < -.1 && (vertex[Triangles[i].vertex[0]].y < where->y || vertex[Triangles[i].vertex[1]].y < where->y || vertex[Triangles[i].vertex[2]].y < where->y)) {
- decalposition[numdecals] = *where;
- decaltype[numdecals] = atype;
- decalrotation[numdecals] = *rotation;
- decalalivetime[numdecals] = 0;
- distance = abs(((facenormals[i].x * where->x) + (facenormals[i].y * where->y) + (facenormals[i].z * where->z) - ((facenormals[i].x * vertex[Triangles[i].vertex[0]].x) + (facenormals[i].y * vertex[Triangles[i].vertex[0]].y) + (facenormals[i].z * vertex[Triangles[i].vertex[0]].z))) / facenormals[i].y);
- decalopacity[numdecals] = *opacity - distance / 10;
-
- if (decalopacity[numdecals > 0]) {
- placex = vertex[Triangles[i].vertex[0]].x;
- placez = vertex[Triangles[i].vertex[0]].z;
-
- decaltexcoords[numdecals][0][0] = (placex - where->x) / (*size) / 2 + .5;
- decaltexcoords[numdecals][0][1] = (placez - where->z) / (*size) / 2 + .5;
-
- decalvertex[numdecals][0].x = placex;
- decalvertex[numdecals][0].z = placez;
- decalvertex[numdecals][0].y = vertex[Triangles[i].vertex[0]].y;
-
-
- placex = vertex[Triangles[i].vertex[1]].x;
- placez = vertex[Triangles[i].vertex[1]].z;
-
- decaltexcoords[numdecals][1][0] = (placex - where->x) / (*size) / 2 + .5;
- decaltexcoords[numdecals][1][1] = (placez - where->z) / (*size) / 2 + .5;
-
- decalvertex[numdecals][1].x = placex;
- decalvertex[numdecals][1].z = placez;
- decalvertex[numdecals][1].y = vertex[Triangles[i].vertex[1]].y;
-
-
- placex = vertex[Triangles[i].vertex[2]].x;
- placez = vertex[Triangles[i].vertex[2]].z;
-
- decaltexcoords[numdecals][2][0] = (placex - where->x) / (*size) / 2 + .5;
- decaltexcoords[numdecals][2][1] = (placez - where->z) / (*size) / 2 + .5;
-
- decalvertex[numdecals][2].x = placex;
- decalvertex[numdecals][2].z = placez;
- decalvertex[numdecals][2].y = vertex[Triangles[i].vertex[2]].y;
-
- if (!(decaltexcoords[numdecals][0][0] < 0 && decaltexcoords[numdecals][1][0] < 0 && decaltexcoords[numdecals][2][0] < 0))
- if (!(decaltexcoords[numdecals][0][1] < 0 && decaltexcoords[numdecals][1][1] < 0 && decaltexcoords[numdecals][2][1] < 0))
- if (!(decaltexcoords[numdecals][0][0] > 1 && decaltexcoords[numdecals][1][0] > 1 && decaltexcoords[numdecals][2][0] > 1))
- if (!(decaltexcoords[numdecals][0][1] > 1 && decaltexcoords[numdecals][1][1] > 1 && decaltexcoords[numdecals][2][1] > 1)) {
- if (decalrotation[numdecals]) {
- for (j = 0; j < 3; j++) {
- rot.y = 0;
- rot.x = decaltexcoords[numdecals][j][0] - .5;
- rot.z = decaltexcoords[numdecals][j][1] - .5;
- rot = DoRotation(rot, 0, -decalrotation[numdecals], 0);
- decaltexcoords[numdecals][j][0] = rot.x + .5;
- decaltexcoords[numdecals][j][1] = rot.z + .5;
- }
- }
- if (numdecals < max_model_decals - 1)
- numdecals++;
- }
- }
- }
- }
- }
-}
-
-void Model::MakeDecal(int atype, XYZ where, float size, float opacity, float rotation)
-{
- if (decals) {
- if (type != decalstype)
- return;
-
- static float placex, placez;
- static XYZ rot;
- static float distance;
- static int i, j;
-
- if (opacity > 0)
- if (distsq(&where, &boundingspherecenter) < (boundingsphereradius + size) * (boundingsphereradius + size))
- for (i = 0; i < TriangleNum; i++) {
- distance = abs(((facenormals[i].x * where.x) + (facenormals[i].y * where.y) + (facenormals[i].z * where.z) - ((facenormals[i].x * vertex[Triangles[i].vertex[0]].x) + (facenormals[i].y * vertex[Triangles[i].vertex[0]].y) + (facenormals[i].z * vertex[Triangles[i].vertex[0]].z))));
- if (distance < .02 && abs(facenormals[i].y) > abs(facenormals[i].x) && abs(facenormals[i].y) > abs(facenormals[i].z)) {
- decalposition[numdecals] = where;
- decaltype[numdecals] = atype;
- decalrotation[numdecals] = rotation;
- decalalivetime[numdecals] = 0;
- decalopacity[numdecals] = opacity - distance / 10;
-
- if (decalopacity[numdecals > 0]) {
- placex = vertex[Triangles[i].vertex[0]].x;
- placez = vertex[Triangles[i].vertex[0]].z;
-
- decaltexcoords[numdecals][0][0] = (placex - where.x) / (size) / 2 + .5;
- decaltexcoords[numdecals][0][1] = (placez - where.z) / (size) / 2 + .5;
-
- decalvertex[numdecals][0].x = placex;
- decalvertex[numdecals][0].z = placez;
- decalvertex[numdecals][0].y = vertex[Triangles[i].vertex[0]].y;
-
-
- placex = vertex[Triangles[i].vertex[1]].x;
- placez = vertex[Triangles[i].vertex[1]].z;
-
- decaltexcoords[numdecals][1][0] = (placex - where.x) / (size) / 2 + .5;
- decaltexcoords[numdecals][1][1] = (placez - where.z) / (size) / 2 + .5;
-
- decalvertex[numdecals][1].x = placex;
- decalvertex[numdecals][1].z = placez;
- decalvertex[numdecals][1].y = vertex[Triangles[i].vertex[1]].y;
-
-
- placex = vertex[Triangles[i].vertex[2]].x;
- placez = vertex[Triangles[i].vertex[2]].z;
-
- decaltexcoords[numdecals][2][0] = (placex - where.x) / (size) / 2 + .5;
- decaltexcoords[numdecals][2][1] = (placez - where.z) / (size) / 2 + .5;
-
- decalvertex[numdecals][2].x = placex;
- decalvertex[numdecals][2].z = placez;
- decalvertex[numdecals][2].y = vertex[Triangles[i].vertex[2]].y;
-
- if (!(decaltexcoords[numdecals][0][0] < 0 && decaltexcoords[numdecals][1][0] < 0 && decaltexcoords[numdecals][2][0] < 0))
- if (!(decaltexcoords[numdecals][0][1] < 0 && decaltexcoords[numdecals][1][1] < 0 && decaltexcoords[numdecals][2][1] < 0))
- if (!(decaltexcoords[numdecals][0][0] > 1 && decaltexcoords[numdecals][1][0] > 1 && decaltexcoords[numdecals][2][0] > 1))
- if (!(decaltexcoords[numdecals][0][1] > 1 && decaltexcoords[numdecals][1][1] > 1 && decaltexcoords[numdecals][2][1] > 1)) {
- if (decalrotation[numdecals]) {
- for (j = 0; j < 3; j++) {
- rot.y = 0;
- rot.x = decaltexcoords[numdecals][j][0] - .5;
- rot.z = decaltexcoords[numdecals][j][1] - .5;
- rot = DoRotation(rot, 0, -decalrotation[numdecals], 0);
- decaltexcoords[numdecals][j][0] = rot.x + .5;
- decaltexcoords[numdecals][j][1] = rot.z + .5;
- }
- }
- if (numdecals < max_model_decals - 1)
- numdecals++;
- }
- }
- } else if (distance < .02 && abs(facenormals[i].x) > abs(facenormals[i].y) && abs(facenormals[i].x) > abs(facenormals[i].z)) {
- decalposition[numdecals] = where;
- decaltype[numdecals] = atype;
- decalrotation[numdecals] = rotation;
- decalalivetime[numdecals] = 0;
- decalopacity[numdecals] = opacity - distance / 10;
-
- if (decalopacity[numdecals > 0]) {
- placex = vertex[Triangles[i].vertex[0]].y;
- placez = vertex[Triangles[i].vertex[0]].z;
-
- decaltexcoords[numdecals][0][0] = (placex - where.y) / (size) / 2 + .5;
- decaltexcoords[numdecals][0][1] = (placez - where.z) / (size) / 2 + .5;
-
- decalvertex[numdecals][0].x = vertex[Triangles[i].vertex[0]].x;
- decalvertex[numdecals][0].z = placez;
- decalvertex[numdecals][0].y = placex;
-
-
- placex = vertex[Triangles[i].vertex[1]].y;
- placez = vertex[Triangles[i].vertex[1]].z;
-
- decaltexcoords[numdecals][1][0] = (placex - where.y) / (size) / 2 + .5;
- decaltexcoords[numdecals][1][1] = (placez - where.z) / (size) / 2 + .5;
-
- decalvertex[numdecals][1].x = vertex[Triangles[i].vertex[1]].x;
- decalvertex[numdecals][1].z = placez;
- decalvertex[numdecals][1].y = placex;
-
-
- placex = vertex[Triangles[i].vertex[2]].y;
- placez = vertex[Triangles[i].vertex[2]].z;
-
- decaltexcoords[numdecals][2][0] = (placex - where.y) / (size) / 2 + .5;
- decaltexcoords[numdecals][2][1] = (placez - where.z) / (size) / 2 + .5;
-
- decalvertex[numdecals][2].x = vertex[Triangles[i].vertex[2]].x;
- decalvertex[numdecals][2].z = placez;
- decalvertex[numdecals][2].y = placex;
-
- if (!(decaltexcoords[numdecals][0][0] < 0 && decaltexcoords[numdecals][1][0] < 0 && decaltexcoords[numdecals][2][0] < 0))
- if (!(decaltexcoords[numdecals][0][1] < 0 && decaltexcoords[numdecals][1][1] < 0 && decaltexcoords[numdecals][2][1] < 0))
- if (!(decaltexcoords[numdecals][0][0] > 1 && decaltexcoords[numdecals][1][0] > 1 && decaltexcoords[numdecals][2][0] > 1))
- if (!(decaltexcoords[numdecals][0][1] > 1 && decaltexcoords[numdecals][1][1] > 1 && decaltexcoords[numdecals][2][1] > 1)) {
- if (decalrotation[numdecals]) {
- for (j = 0; j < 3; j++) {
- rot.y = 0;
- rot.x = decaltexcoords[numdecals][j][0] - .5;
- rot.z = decaltexcoords[numdecals][j][1] - .5;
- rot = DoRotation(rot, 0, -decalrotation[numdecals], 0);
- decaltexcoords[numdecals][j][0] = rot.x + .5;
- decaltexcoords[numdecals][j][1] = rot.z + .5;
- }
- }
- if (numdecals < max_model_decals - 1)
- numdecals++;
- }
- }
- } else if (distance < .02 && abs(facenormals[i].z) > abs(facenormals[i].y) && abs(facenormals[i].z) > abs(facenormals[i].x)) {
- decalposition[numdecals] = where;
- decaltype[numdecals] = atype;
- decalrotation[numdecals] = rotation;
- decalalivetime[numdecals] = 0;
- decalopacity[numdecals] = opacity - distance / 10;
-
- if (decalopacity[numdecals > 0]) {
- placex = vertex[Triangles[i].vertex[0]].x;
- placez = vertex[Triangles[i].vertex[0]].y;
-
- decaltexcoords[numdecals][0][0] = (placex - where.x) / (size) / 2 + .5;
- decaltexcoords[numdecals][0][1] = (placez - where.y) / (size) / 2 + .5;
-
- decalvertex[numdecals][0].x = placex;
- decalvertex[numdecals][0].z = vertex[Triangles[i].vertex[0]].z;
- decalvertex[numdecals][0].y = placez;
-
-
- placex = vertex[Triangles[i].vertex[1]].x;
- placez = vertex[Triangles[i].vertex[1]].y;
-
- decaltexcoords[numdecals][1][0] = (placex - where.x) / (size) / 2 + .5;
- decaltexcoords[numdecals][1][1] = (placez - where.y) / (size) / 2 + .5;
-
- decalvertex[numdecals][1].x = placex;
- decalvertex[numdecals][1].z = vertex[Triangles[i].vertex[1]].z;
- decalvertex[numdecals][1].y = placez;
-
-
- placex = vertex[Triangles[i].vertex[2]].x;
- placez = vertex[Triangles[i].vertex[2]].y;
-
- decaltexcoords[numdecals][2][0] = (placex - where.x) / (size) / 2 + .5;
- decaltexcoords[numdecals][2][1] = (placez - where.y) / (size) / 2 + .5;
-
- decalvertex[numdecals][2].x = placex;
- decalvertex[numdecals][2].z = vertex[Triangles[i].vertex[2]].z;
- decalvertex[numdecals][2].y = placez;
-
- if (!(decaltexcoords[numdecals][0][0] < 0 && decaltexcoords[numdecals][1][0] < 0 && decaltexcoords[numdecals][2][0] < 0))
- if (!(decaltexcoords[numdecals][0][1] < 0 && decaltexcoords[numdecals][1][1] < 0 && decaltexcoords[numdecals][2][1] < 0))
- if (!(decaltexcoords[numdecals][0][0] > 1 && decaltexcoords[numdecals][1][0] > 1 && decaltexcoords[numdecals][2][0] > 1))
- if (!(decaltexcoords[numdecals][0][1] > 1 && decaltexcoords[numdecals][1][1] > 1 && decaltexcoords[numdecals][2][1] > 1)) {
- if (decalrotation[numdecals]) {
- for (j = 0; j < 3; j++) {
- rot.y = 0;
- rot.x = decaltexcoords[numdecals][j][0] - .5;
- rot.z = decaltexcoords[numdecals][j][1] - .5;
- rot = DoRotation(rot, 0, -decalrotation[numdecals], 0);
- decaltexcoords[numdecals][j][0] = rot.x + .5;
- decaltexcoords[numdecals][j][1] = rot.z + .5;
- }
- }
- if (numdecals < max_model_decals - 1)
- numdecals++;
- }
- }
- }
- }
- }
-}
-
-Model::~Model()
-{
- deallocate();
- textureptr.destroy();
-}
-
-void Model::deallocate()
-{
- int i = 0, j = 0;
-
- if (owner)
- free(owner);
- owner = 0;
-
- if (possible)
- free(possible);
- possible = 0;
-
- if (vertex)
- free(vertex);
- vertex = 0;
-
- if (normals)
- free(normals);
- normals = 0;
-
- if (facenormals)
- free(facenormals);
- facenormals = 0;
-
- if (Triangles)
- free(Triangles);
- Triangles = 0;
-
- if (vArray)
- free(vArray);
- vArray = 0;
-
-
- //allow decals
- if (decaltexcoords) {
- for (i = 0; i < max_model_decals; i++) {
- for (j = 0; j < 3; j++) {
- free(decaltexcoords[i][j]);
- }
- free(decaltexcoords[i]);
- }
- free(decaltexcoords);
- }
- decaltexcoords = 0;
-
-
- if (decalvertex) {
- for (i = 0; i < max_model_decals; i++) {
- free(decalvertex[i]);
- }
- free(decalvertex);
- }
- decalvertex = 0;
-
-
- free(decaltype);
- decaltype = 0;
-
- free(decalopacity);
- decalopacity = 0;
-
- free(decalrotation);
- decalrotation = 0;
-
- free(decalalivetime);
- decalalivetime = 0;
-
- free(decalposition);
- decalposition = 0;
-
-};
-
-Model::Model()
-{
- vertexNum = 0, TriangleNum = 0;
- hastexture = 0;
-
- type = 0, oldtype = 0;
-
- possible = 0;
- owner = 0;
- vertex = 0;
- normals = 0;
- facenormals = 0;
- Triangles = 0;
- vArray = 0;
-
- memset(&modelTexture, 0, sizeof(modelTexture));
- numpossible = 0;
- color = 0;
-
- boundingspherecenter = 0;
- boundingsphereradius = 0;
-
- decaltexcoords = 0;
- decalvertex = 0;
- decaltype = 0;
- decalopacity = 0;
- decalrotation = 0;
- decalalivetime = 0;
- decalposition = 0;
-
- numdecals = 0;
-
- flat = 0;
-
- type = nothing;
-}
-
+++ /dev/null
-/*
-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 _MODELS_H_
-#define _MODELS_H_
-
-/**> Model Loading <**/
-//
-// Model Maximums
-//
-#include "gamegl.h"
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <vector>
-
-#include "Terrain.h"
-#include "binio.h"
-#include "Quaternions.h"
-#include "Texture.h"
-
-//
-// Textures List
-//
-typedef struct {
- long xsz, ysz;
- GLubyte *txt;
-} ModelTexture;
-
-//
-// Model Structures
-//
-
-class TexturedTriangle
-{
-public:
- short vertex[3];
- float gx[3], gy[3];
-};
-
-#define max_model_decals 300
-
-#define nothing 0
-#define normaltype 4
-#define notextype 1
-#define rawtype 2
-#define decalstype 3
-
-class Model
-{
-public:
- short vertexNum, TriangleNum;
- bool hastexture;
-
- int type, oldtype;
-
- int* possible;
- int* owner;
- XYZ* vertex;
- XYZ* normals;
- XYZ* facenormals;
- TexturedTriangle* Triangles;
- GLfloat* vArray;
-
- /*int possible[max_model_vertex];
- int owner[max_textured_triangle];
- XYZ vertex[max_model_vertex];
- XYZ normals[max_model_vertex];
- XYZ facenormals[max_textured_triangle];
- TexturedTriangle Triangles[max_textured_triangle];
- GLfloat vArray[max_textured_triangle*24];*/
-
- Texture textureptr;
- ModelTexture modelTexture;
- int numpossible;
- bool color;
-
- XYZ boundingspherecenter;
- float boundingsphereradius;
-
- float*** decaltexcoords;
- XYZ** decalvertex;
- int* decaltype;
- float* decalopacity;
- float* decalrotation;
- float* decalalivetime;
- XYZ* decalposition;
-
- /*float decaltexcoords[max_model_decals][3][2];
- XYZ decalvertex[max_model_decals][3];
- int decaltype[max_model_decals];
- float decalopacity[max_model_decals];
- float decalrotation[max_model_decals];
- float decalalivetime[max_model_decals];
- XYZ decalposition[max_model_decals];*/
-
- int numdecals;
-
- bool flat;
-
- void DeleteDecal(int which);
- void MakeDecal(int atype, XYZ *where, float *size, float *opacity, float *rotation);
- void MakeDecal(int atype, XYZ where, float size, float opacity, float rotation);
- void drawdecals(Texture shadowtexture, Texture bloodtexture, Texture bloodtexture2, Texture breaktexture);
- int SphereCheck(XYZ *p1, float radius, XYZ *p, XYZ *move, float *rotate);
- int SphereCheckPossible(XYZ *p1, float radius, XYZ *move, float *rotate);
- int LineCheck(XYZ *p1, XYZ *p2, XYZ *p, XYZ *move, float *rotate);
- int LineCheckPossible(XYZ *p1, XYZ *p2, XYZ *p, XYZ *move, float *rotate);
- int LineCheckSlidePossible(XYZ *p1, XYZ *p2, XYZ *p, XYZ *move, float *rotate);
- void UpdateVertexArray();
- void UpdateVertexArrayNoTex();
- void UpdateVertexArrayNoTexNoNorm();
- bool loadnotex(const std::string& filename);
- bool loadraw(const std::string& filename);
- bool load(const std::string& filename, bool texture);
- bool loaddecal(const std::string& filename, bool texture);
- void Scale(float xscale, float yscale, float zscale);
- void FlipTexCoords();
- void UniformTexCoords();
- void ScaleTexCoords(float howmuch);
- void ScaleNormals(float xscale, float yscale, float zscale);
- void Translate(float xtrans, float ytrans, float ztrans);
- void CalculateNormals(bool facenormalise);
- void draw();
- void drawdifftex(GLuint texture);
- void drawdifftex(Texture texture);
- void drawimmediate();
- void Rotate(float xang, float yang, float zang);
- ~Model();
- void deallocate();
- Model();
-};
-
-#endif
+++ /dev/null
-/*
-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/>.
-*/
-
-#include "Objects.h"
-extern XYZ viewer;
-extern float viewdistance;
-extern float fadestart;
-extern int environment;
-extern float texscale;
-extern Light light;
-extern float multiplier;
-extern float gravity;
-extern FRUSTUM frustum;
-extern Terrain terrain;
-extern bool foliage;
-extern int detail;
-extern float blurness;
-extern float windvar;
-extern float playerdist;
-extern bool skyboxtexture;
-
-//Functions
-
-bool Objects::checkcollide(XYZ startpoint, XYZ endpoint, int which)
-{
- static XYZ colpoint, colviewer, coltarget;
- static int i;
-
- startpoint.y += .1;
- endpoint.y += .1;
- startpoint.y -= .1;
- endpoint.y -= .1;
-
- for (i = 0; i < numobjects; i++) {
- if (type[i] != treeleavestype && type[i] != treetrunktype && type[i] != bushtype && type[i] != firetype && i != which) {
- colviewer = startpoint;
- coltarget = endpoint;
- if (model[i].LineCheck(&colviewer, &coltarget, &colpoint, &position[i], &yaw[i]) != -1)
- return 1;
- }
- }
-
- return 0;
-}
-
-void Objects::SphereCheckPossible(XYZ *p1, float radius)
-{
- static int i, j;
- static int whichpatchx;
- static int whichpatchz;
-
- whichpatchx = p1->x / (terrain.size / subdivision * terrain.scale);
- whichpatchz = p1->z / (terrain.size / subdivision * terrain.scale);
-
- if (whichpatchx >= 0 && whichpatchz >= 0 && whichpatchx < subdivision && whichpatchz < subdivision)
- if (terrain.patchobjectnum[whichpatchx][whichpatchz] > 0 && terrain.patchobjectnum[whichpatchx][whichpatchz] < 500)
- for (j = 0; j < terrain.patchobjectnum[whichpatchx][whichpatchz]; j++) {
- i = terrain.patchobjects[whichpatchx][whichpatchz][j];
- possible[i] = 0;
- if (model[i].SphereCheckPossible(p1, radius, &position[i], &yaw[i]) != -1) {
- possible[i] = 1;
- }
- }
-}
-
-void Objects::Draw()
-{
- static float distance;
- static int i;
- static XYZ moved, terrainlight;
- bool hidden;
-
- for (i = 0; i < numobjects; i++) {
- if (type[i] != firetype) {
- moved = DoRotation(model[i].boundingspherecenter, 0, yaw[i], 0);
- if (type[i] == tunneltype || frustum.SphereInFrustum(position[i].x + moved.x, position[i].y + moved.y, position[i].z + moved.z, model[i].boundingsphereradius)) {
- distance = distsq(&viewer, &position[i]);
- distance *= 1.2;
- hidden = !(distsqflat(&viewer, &position[i]) > playerdist + 3 || (type[i] != bushtype && type[i] != treeleavestype));
- if (!hidden) {
-
- if (detail == 2 && distance > viewdistance * viewdistance / 4 && environment == desertenvironment)
- glTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, blurness );
- else
- glTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0 );
- distance = (viewdistance * viewdistance - (distance - (viewdistance * viewdistance * fadestart)) * (1 / (1 - fadestart))) / viewdistance / viewdistance;
- if (distance > 1)
- distance = 1;
- if (distance > 0) {
-
- if (occluded[i] < 6) {
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- if (!model[i].color)
- glEnable(GL_LIGHTING);
- else
- glDisable(GL_LIGHTING);
- glDepthMask(1);
- glTranslatef(position[i].x, position[i].y, position[i].z);
- if (type[i] == bushtype) {
- messedwith[i] -= multiplier;
- if (rotxvel[i] || rotx[i]) {
- if (rotx[i] > 0) rotxvel[i] -= multiplier * 8 * fabs(rotx[i]);
- if (rotx[i] < 0) rotxvel[i] += multiplier * 8 * fabs(rotx[i]);
- if (rotx[i] > 0) rotxvel[i] -= multiplier * 4;
- if (rotx[i] < 0) rotxvel[i] += multiplier * 4;
- if (rotxvel[i] > 0) rotxvel[i] -= multiplier * 4;
- if (rotxvel[i] < 0) rotxvel[i] += multiplier * 4;
- if (fabs(rotx[i]) < multiplier * 4)
- rotx[i] = 0;
- if (fabs(rotxvel[i]) < multiplier * 4)
- rotxvel[i] = 0;
-
- rotx[i] += rotxvel[i] * multiplier * 4;
- }
- if (rotyvel[i] || roty[i]) {
- if (roty[i] > 0) rotyvel[i] -= multiplier * 8 * fabs(roty[i]);
- if (roty[i] < 0) rotyvel[i] += multiplier * 8 * fabs(roty[i]);
- if (roty[i] > 0) rotyvel[i] -= multiplier * 4;
- if (roty[i] < 0) rotyvel[i] += multiplier * 4;
- if (rotyvel[i] > 0) rotyvel[i] -= multiplier * 4;
- if (rotyvel[i] < 0) rotyvel[i] += multiplier * 4;
- if (fabs(roty[i]) < multiplier * 4)
- roty[i] = 0;
- if (fabs(rotyvel[i]) < multiplier * 4)
- rotyvel[i] = 0;
-
- roty[i] += rotyvel[i] * multiplier * 4;
- }
- if (roty[i]) {
- glRotatef(roty[i], 1, 0, 0);
- }
- if (rotx[i]) {
- glRotatef(-rotx[i], 0, 0, 1);
- }
- if (rotx[i] > 10)
- rotx[i] = 10;
- if (rotx[i] < -10)
- rotx[i] = -10;
- if (roty[i] > 10)
- roty[i] = 10;
- if (roty[i] < -10)
- roty[i] = -10;
- }
- if (type[i] == treetrunktype || type[i] == treeleavestype) {
- if (type[i] == treetrunktype || environment == desertenvironment) {
- messedwith[i] -= multiplier;
- if (rotxvel[i] || rotx[i]) {
- if (rotx[i] > 0) rotxvel[i] -= multiplier * 8 * fabs(rotx[i]);
- if (rotx[i] < 0) rotxvel[i] += multiplier * 8 * fabs(rotx[i]);
- if (rotx[i] > 0) rotxvel[i] -= multiplier * 4;
- if (rotx[i] < 0) rotxvel[i] += multiplier * 4;
- if (rotxvel[i] > 0) rotxvel[i] -= multiplier * 4;
- if (rotxvel[i] < 0) rotxvel[i] += multiplier * 4;
- if (fabs(rotx[i]) < multiplier * 4)
- rotx[i] = 0;
- if (fabs(rotxvel[i]) < multiplier * 4)
- rotxvel[i] = 0;
-
- rotx[i] += rotxvel[i] * multiplier * 4;
- }
- if (rotyvel[i] || roty[i]) {
- if (roty[i] > 0) rotyvel[i] -= multiplier * 8 * fabs(roty[i]);
- if (roty[i] < 0) rotyvel[i] += multiplier * 8 * fabs(roty[i]);
- if (roty[i] > 0) rotyvel[i] -= multiplier * 4;
- if (roty[i] < 0) rotyvel[i] += multiplier * 4;
- if (rotyvel[i] > 0) rotyvel[i] -= multiplier * 4;
- if (rotyvel[i] < 0) rotyvel[i] += multiplier * 4;
- if (fabs(roty[i]) < multiplier * 4)
- roty[i] = 0;
- if (fabs(rotyvel[i]) < multiplier * 4)
- rotyvel[i] = 0;
-
- roty[i] += rotyvel[i] * multiplier * 4;
- }
- if (roty[i]) {
- glRotatef(roty[i] / 6, 1, 0, 0);
- }
- if (rotx[i]) {
- glRotatef(-rotx[i] / 6, 0, 0, 1);
- }
- if (rotx[i] > 10)
- rotx[i] = 10;
- if (rotx[i] < -10)
- rotx[i] = -10;
- if (roty[i] > 10)
- roty[i] = 10;
- if (roty[i] < -10)
- roty[i] = -10;
- } else {
- messedwith[i] -= multiplier;
- if (rotxvel[i] || rotx[i]) {
- if (rotx[i] > 0) rotxvel[i] -= multiplier * 8 * fabs(rotx[i]);
- if (rotx[i] < 0) rotxvel[i] += multiplier * 8 * fabs(rotx[i]);
- if (rotx[i] > 0) rotxvel[i] -= multiplier * 4;
- if (rotx[i] < 0) rotxvel[i] += multiplier * 4;
- if (rotxvel[i] > 0) rotxvel[i] -= multiplier * 4;
- if (rotxvel[i] < 0) rotxvel[i] += multiplier * 4;
- if (fabs(rotx[i]) < multiplier * 4)
- rotx[i] = 0;
- if (fabs(rotxvel[i]) < multiplier * 4)
- rotxvel[i] = 0;
-
- rotx[i] += rotxvel[i] * multiplier * 4;
- }
- if (rotyvel[i] || roty[i]) {
- if (roty[i] > 0) rotyvel[i] -= multiplier * 8 * fabs(roty[i]);
- if (roty[i] < 0) rotyvel[i] += multiplier * 8 * fabs(roty[i]);
- if (roty[i] > 0) rotyvel[i] -= multiplier * 4;
- if (roty[i] < 0) rotyvel[i] += multiplier * 4;
- if (rotyvel[i] > 0) rotyvel[i] -= multiplier * 4;
- if (rotyvel[i] < 0) rotyvel[i] += multiplier * 4;
- if (fabs(roty[i]) < multiplier * 4)
- roty[i] = 0;
- if (fabs(rotyvel[i]) < multiplier * 4)
- rotyvel[i] = 0;
-
- roty[i] += rotyvel[i] * multiplier * 4;
- }
- if (roty[i]) {
- glRotatef(roty[i] / 4, 1, 0, 0);
- }
- if (rotx[i]) {
- glRotatef(-rotx[i] / 4, 0, 0, 1);
- }
- if (rotx[i] > 10)
- rotx[i] = 10;
- if (rotx[i] < -10)
- rotx[i] = -10;
- if (roty[i] > 10)
- roty[i] = 10;
- if (roty[i] < -10)
- roty[i] = -10;
- }
-
- }
- if (/*detail==2&&*/environment == snowyenvironment) {
- if (type[i] == treeleavestype) {
- glRotatef((sin(windvar + position[i].x * .3) + .5) * 1.5 * (sin(windvar * 2 + position[i].x * .3) + 1) / 2, 1, 0, 0);
- }
- if (type[i] == treetrunktype) {
- glRotatef((sin(windvar + position[i].x * .3) + .5)*.5 * (sin(windvar * 2 + position[i].x * .3) + 1) / 2, 1, 0, 0);
- }
- if (type[i] == bushtype) {
- glRotatef((sin(windvar + position[i].x * .3) + .5) * 4 * (sin(windvar * 2 + position[i].x * .3) + 1) / 2, 1, 0, 0);
- }
- }
- if (/*detail==2&&*/environment == grassyenvironment) {
- if (type[i] == treeleavestype) {
- glRotatef((sin(windvar + position[i].x * .3) + .5) * 1.5 * .5 * (sin(windvar * 2 + position[i].x * .3) + 1) / 2, 1, 0, 0);
- }
- if (type[i] == treetrunktype) {
- glRotatef((sin(windvar + position[i].x * .3) + .5)*.5 * .5 * (sin(windvar * 2 + position[i].x * .3) + 1) / 2, 1, 0, 0);
- }
- if (type[i] == bushtype) {
- glRotatef((sin(windvar + position[i].x * .3) + .5) * 4 * .5 * (sin(windvar * 2 + position[i].x * .3) + 1) / 2, 1, 0, 0);
- }
- }
- if (/*detail==2&&*/environment == desertenvironment) {
- if (type[i] == bushtype) {
- glRotatef((sin(windvar + position[i].x * .3) + .5) * 4 * .5 * (sin(windvar * 2 + position[i].x * .3) + 1) / 2, 1, 0, 0);
- }
- }
- glRotatef(yaw[i], 0, 1, 0);
- if (distance > 1)
- distance = 1;
- glColor4f((1 - shadowed[i]) / 2 + .5, (1 - shadowed[i]) / 2 + .5, (1 - shadowed[i]) / 2 + .5, distance);
- if (distance >= 1) {
- glDisable(GL_BLEND);
- glAlphaFunc(GL_GREATER, 0.5);
- }
- if (distance < 1) {
- glEnable(GL_BLEND);
- glAlphaFunc(GL_GREATER, 0.1);
- }
- if (type[i] != treetrunktype && type[i] != treeleavestype && type[i] != bushtype && type[i] != rocktype) {
- glEnable(GL_CULL_FACE);
- glAlphaFunc(GL_GREATER, 0.0001);
- model[i].drawdifftex(boxtextureptr);
- model[i].drawdecals(terrain.shadowtexture, terrain.bloodtexture, terrain.bloodtexture2, terrain.breaktexture);
- }
- if (type[i] == rocktype) {
- glEnable(GL_CULL_FACE);
- glAlphaFunc(GL_GREATER, 0.0001);
- glColor4f((1 - shadowed[i]) / 2 + light.ambient[0], (1 - shadowed[i]) / 2 + light.ambient[1], (1 - shadowed[i]) / 2 + light.ambient[2], distance);
- model[i].drawdifftex(rocktextureptr);
- model[i].drawdecals(terrain.shadowtexture, terrain.bloodtexture, terrain.bloodtexture2, terrain.breaktexture);
- }
- if (type[i] == treeleavestype) {
- glDisable(GL_CULL_FACE);
- glDisable(GL_LIGHTING);
- terrainlight = terrain.getLighting(position[i].x, position[i].z);
- if (!hidden) {
- glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, distance);
- if (distance < 1)
- glAlphaFunc(GL_GREATER, 0.2);
- }
- if (hidden) {
- glDepthMask(0);
- glEnable(GL_BLEND);
- glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, distance / 3);
- glAlphaFunc(GL_GREATER, 0);
- }
- model[i].drawdifftex(treetextureptr);
- }
- if (type[i] == bushtype) {
- glDisable(GL_CULL_FACE);
- glDisable(GL_LIGHTING);
- terrainlight = terrain.getLighting(position[i].x, position[i].z);
- if (!hidden) {
- glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, distance);
- if (distance < 1)
- glAlphaFunc(GL_GREATER, 0.2);
- }
- if (hidden) {
- glDepthMask(0);
- glEnable(GL_BLEND);
- glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, distance / 3);
- glAlphaFunc(GL_GREATER, 0);
- }
- model[i].drawdifftex(bushtextureptr);
- }
- if (type[i] == treetrunktype) {
- glEnable(GL_CULL_FACE);
- terrainlight = terrain.getLighting(position[i].x, position[i].z);
- glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, distance);
- model[i].drawdifftex(treetextureptr);
- }
- glPopMatrix();
- }
- }
- }
- }
- }
- }
-
- glTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0 );
- for (i = 0; i < numobjects; i++) {
- if (type[i] == treeleavestype || type[i] == bushtype) {
- moved = DoRotation(model[i].boundingspherecenter, 0, yaw[i], 0);
- if (frustum.SphereInFrustum(position[i].x + moved.x, position[i].y + moved.y, position[i].z + moved.z, model[i].boundingsphereradius)) {
- hidden = distsqflat(&viewer, &position[i]) <= playerdist + 3;
- if (hidden) {
- distance = 1;
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glEnable(GL_LIGHTING);
- glDepthMask(1);
- glTranslatef(position[i].x, position[i].y, position[i].z);
- if (type[i] == bushtype) {
- messedwith[i] -= multiplier;
- if (rotxvel[i] || rotx[i]) {
- if (rotx[i] > 0) rotxvel[i] -= multiplier * 8 * fabs(rotx[i]);
- if (rotx[i] < 0) rotxvel[i] += multiplier * 8 * fabs(rotx[i]);
- if (rotx[i] > 0) rotxvel[i] -= multiplier * 4;
- if (rotx[i] < 0) rotxvel[i] += multiplier * 4;
- if (rotxvel[i] > 0) rotxvel[i] -= multiplier * 4;
- if (rotxvel[i] < 0) rotxvel[i] += multiplier * 4;
- if (fabs(rotx[i]) < multiplier * 4)
- rotx[i] = 0;
- if (fabs(rotxvel[i]) < multiplier * 4)
- rotxvel[i] = 0;
-
- rotx[i] += rotxvel[i] * multiplier * 4;
- }
- if (rotyvel[i] || roty[i]) {
- if (roty[i] > 0) rotyvel[i] -= multiplier * 8 * fabs(roty[i]);
- if (roty[i] < 0) rotyvel[i] += multiplier * 8 * fabs(roty[i]);
- if (roty[i] > 0) rotyvel[i] -= multiplier * 4;
- if (roty[i] < 0) rotyvel[i] += multiplier * 4;
- if (rotyvel[i] > 0) rotyvel[i] -= multiplier * 4;
- if (rotyvel[i] < 0) rotyvel[i] += multiplier * 4;
- if (fabs(roty[i]) < multiplier * 4)
- roty[i] = 0;
- if (fabs(rotyvel[i]) < multiplier * 4)
- rotyvel[i] = 0;
-
- roty[i] += rotyvel[i] * multiplier * 4;
- }
- if (roty[i]) {
- glRotatef(roty[i], 1, 0, 0);
- }
- if (rotx[i]) {
- glRotatef(-rotx[i], 0, 0, 1);
- }
- if (rotx[i] > 10)
- rotx[i] = 10;
- if (rotx[i] < -10)
- rotx[i] = -10;
- if (roty[i] > 10)
- roty[i] = 10;
- if (roty[i] < -10)
- roty[i] = -10;
- }
- if (type[i] == treetrunktype || type[i] == treeleavestype) {
- messedwith[i] -= multiplier;
- if (rotxvel[i] || rotx[i]) {
- if (rotx[i] > 0) rotxvel[i] -= multiplier * 8 * fabs(rotx[i]);
- if (rotx[i] < 0) rotxvel[i] += multiplier * 8 * fabs(rotx[i]);
- if (rotx[i] > 0) rotxvel[i] -= multiplier * 4;
- if (rotx[i] < 0) rotxvel[i] += multiplier * 4;
- if (rotxvel[i] > 0) rotxvel[i] -= multiplier * 4;
- if (rotxvel[i] < 0) rotxvel[i] += multiplier * 4;
- if (fabs(rotx[i]) < multiplier * 4)
- rotx[i] = 0;
- if (fabs(rotxvel[i]) < multiplier * 4)
- rotxvel[i] = 0;
-
- rotx[i] += rotxvel[i] * multiplier * 4;
- }
- if (rotyvel[i] || roty[i]) {
- if (roty[i] > 0) rotyvel[i] -= multiplier * 8 * fabs(roty[i]);
- if (roty[i] < 0) rotyvel[i] += multiplier * 8 * fabs(roty[i]);
- if (roty[i] > 0) rotyvel[i] -= multiplier * 4;
- if (roty[i] < 0) rotyvel[i] += multiplier * 4;
- if (rotyvel[i] > 0) rotyvel[i] -= multiplier * 4;
- if (rotyvel[i] < 0) rotyvel[i] += multiplier * 4;
- if (fabs(roty[i]) < multiplier * 4)
- roty[i] = 0;
- if (fabs(rotyvel[i]) < multiplier * 4)
- rotyvel[i] = 0;
-
- roty[i] += rotyvel[i] * multiplier * 4;
- }
- if (roty[i]) {
- glRotatef(roty[i] / 2, 1, 0, 0);
- }
- if (rotx[i]) {
- glRotatef(-rotx[i] / 2, 0, 0, 1);
- }
- if (rotx[i] > 10)
- rotx[i] = 10;
- if (rotx[i] < -10)
- rotx[i] = -10;
- if (roty[i] > 10)
- roty[i] = 10;
- if (roty[i] < -10)
- roty[i] = -10;
- }
- if (environment == snowyenvironment) {
- if (type[i] == treeleavestype) {
- glRotatef((sin(windvar + position[i].x * .3) + .5) * 1.5 * (sin(windvar * 2 + position[i].x * .3) + 1) / 2, 1, 0, 0);
- }
- if (type[i] == treetrunktype) {
- glRotatef((sin(windvar + position[i].x * .3) + .5)*.5 * (sin(windvar * 2 + position[i].x * .3) + 1) / 2, 1, 0, 0);
- }
- if (type[i] == bushtype) {
- glRotatef((sin(windvar + position[i].x * .3) + .5) * 4 * (sin(windvar * 2 + position[i].x * .3) + 1) / 2, 1, 0, 0);
- }
- }
- if (environment == grassyenvironment) {
- if (type[i] == treeleavestype) {
- glRotatef((sin(windvar + position[i].x * .3) + .5) * 1.5 * .5 * (sin(windvar * 2 + position[i].x * .3) + 1) / 2, 1, 0, 0);
- }
- if (type[i] == treetrunktype) {
- glRotatef((sin(windvar + position[i].x * .3) + .5)*.5 * .5 * (sin(windvar * 2 + position[i].x * .3) + 1) / 2, 1, 0, 0);
- }
- if (type[i] == bushtype) {
- glRotatef((sin(windvar + position[i].x * .3) + .5) * 4 * .5 * (sin(windvar * 2 + position[i].x * .3) + 1) / 2, 1, 0, 0);
- }
- }
- glRotatef(yaw[i], 0, 1, 0);
- glColor4f(1, 1, 1, distance);
- if (type[i] == treeleavestype) {
- glDisable(GL_CULL_FACE);
- glDisable(GL_LIGHTING);
- terrainlight = terrain.getLighting(position[i].x, position[i].z);
- glDepthMask(0);
- glEnable(GL_BLEND);
- glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, .3);
- glAlphaFunc(GL_GREATER, 0);
- glDisable(GL_ALPHA_TEST);
- model[i].drawdifftex(treetextureptr);
- }
- if (type[i] == bushtype) {
- glDisable(GL_CULL_FACE);
- glDisable(GL_LIGHTING);
- terrainlight = terrain.getLighting(position[i].x, position[i].z);
- glDepthMask(0);
- glEnable(GL_BLEND);
- glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, .3);
- glAlphaFunc(GL_GREATER, 0);
- glDisable(GL_ALPHA_TEST);
- model[i].drawdifftex(bushtextureptr);
- }
- glPopMatrix();
- }
- }
- }
- }
- if (environment == desertenvironment)
- glTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0 );
- glEnable(GL_ALPHA_TEST);
- SetUpLight(&light, 0);
-}
-
-void Objects::DeleteObject(int which)
-{
- type[numobjects - 1] = 0;
- yaw[numobjects - 1] = 0;
- position[numobjects - 1] = 0;
- scale[numobjects - 1] = 0;
- friction[numobjects - 1] = 0;
-
- numobjects--;
-}
-
-void Objects::MakeObject(int atype, XYZ where, float ayaw, float ascale)
-{
- if ((atype != treeleavestype && atype != bushtype) || foliage == 1) {
- scale[numobjects] = ascale;
- if (atype == treeleavestype)
- scale[numobjects] += fabs((float)(Random() % 100) / 900) * ascale;
-
- onfire[numobjects] = 0;
- flamedelay[numobjects] = 0;
- type[numobjects] = atype;
-
- if (atype == firetype)
- onfire[numobjects] = 1;
-
- position[numobjects] = where;
- if (atype == bushtype)
- position[numobjects].y = terrain.getHeight(position[numobjects].x, position[numobjects].z) - .3;
- yaw[numobjects] = ayaw;
-
- rotxvel[numobjects] = 0;
- rotyvel[numobjects] = 0;
- rotx[numobjects] = 0;
- roty[numobjects] = 0;
-
- if (atype == boxtype) model[numobjects].loaddecal("Models/Box.solid", 0);
- if (atype == cooltype) model[numobjects].loaddecal("Models/Cool.solid", 0);
- if (atype == walltype) model[numobjects].loaddecal("Models/Wall.solid", 0);
- if (atype == tunneltype) model[numobjects].loaddecal("Models/Tunnel.solid", 0);
- if (atype == chimneytype) model[numobjects].loaddecal("Models/Chimney.solid", 0);
- if (atype == spiketype) model[numobjects].load("Models/Spike.solid", 0);
- if (atype == weirdtype) model[numobjects].loaddecal("Models/Weird.solid", 0);
- if (atype == rocktype) model[numobjects].loaddecal("Models/Rock.solid", 0);
- if (atype == treetrunktype) model[numobjects].load("Models/TreeTrunk.solid", 0);
- if (atype == treeleavestype) model[numobjects].load("Models/Leaves.solid", 0);
- if (atype == bushtype) model[numobjects].load("Models/Bush.solid", 0);
-
- if (atype == boxtype) friction[numobjects] = 1.5;
- if (atype == cooltype) friction[numobjects] = 1.5;
- if (atype == walltype) friction[numobjects] = 1.5;
- if (atype == platformtype) friction[numobjects] = 1.5;
- if (atype == tunneltype) friction[numobjects] = 1.5;
- if (atype == chimneytype) friction[numobjects] = 1.5;
- if (atype == rocktype) friction[numobjects] = .5;
- if (atype == rocktype && ascale>.5) friction[numobjects] = 1.5;
- if (atype == weirdtype) friction[numobjects] = 1.5;
- if (atype == spiketype) friction[numobjects] = .4;
- if (atype == treetrunktype) friction[numobjects] = .4;
- if (atype == treeleavestype) friction[numobjects] = 0;
-
- if (atype == platformtype) {
- model[numobjects].loaddecal("Models/Platform.solid", 0);
- model[numobjects].Rotate(90, 0, 0);
- }
-
- if (type[numobjects] == boxtype || type[numobjects] == cooltype || type[numobjects] == spiketype || type[numobjects] == weirdtype || type[numobjects] == walltype || type[numobjects] == chimneytype || type[numobjects] == tunneltype || type[numobjects] == platformtype) {
- model[numobjects].ScaleTexCoords(scale[numobjects] * 1.5);
- }
- if (type[numobjects] == rocktype) {
- model[numobjects].ScaleTexCoords(scale[numobjects] * 3);
- }
- model[numobjects].flat = 1;
- if (atype == treetrunktype || atype == treeleavestype || atype == rocktype) {
- model[numobjects].flat = 0;
- }
- model[numobjects].Scale(.3 * scale[numobjects], .3 * scale[numobjects], .3 * scale[numobjects]);
- model[numobjects].Rotate(90, 1, 1);
- if (type[numobjects] == rocktype) {
- model[numobjects].Rotate(ayaw * 5, 1, 1);
- }
- model[numobjects].CalculateNormals(1);
- model[numobjects].ScaleNormals(-1, -1, -1);
-
- if (atype == treetrunktype && position[numobjects].y < terrain.getHeight(position[numobjects].x, position[numobjects].z) + 1) {
- if (detail == 2)
- terrain.MakeDecal(shadowdecalpermanent, position[numobjects], 2, .4, 0);
- }
-
- if (atype == bushtype && position[numobjects].y < terrain.getHeight(position[numobjects].x, position[numobjects].z) + 1) {
- if (detail == 2)
- terrain.MakeDecal(shadowdecalpermanent, position[numobjects], 1, .4, 0);
- }
-
- if (atype != treeleavestype && atype != bushtype && atype != firetype)
- terrain.AddObject(where + DoRotation(model[numobjects].boundingspherecenter, 0, ayaw, 0), model[numobjects].boundingsphereradius, numobjects);
-
- numobjects++;
- }
-}
-
-void Objects::MakeObject(int atype, XYZ where, float ayaw, float apitch, float ascale)
-{
- if ((atype != treeleavestype && atype != bushtype) || foliage == 1) {
- scale[numobjects] = ascale;
- if (atype == treeleavestype)
- scale[numobjects] += fabs((float)(Random() % 100) / 900) * ascale;
-
- onfire[numobjects] = 0;
- flamedelay[numobjects] = 0;
- type[numobjects] = atype;
-
- if (atype == firetype)
- onfire[numobjects] = 1;
-
- position[numobjects] = where;
- if (atype == bushtype)
- position[numobjects].y = terrain.getHeight(position[numobjects].x, position[numobjects].z) - .3;
- yaw[numobjects] = ayaw;
- pitch[numobjects] = apitch;
-
- rotxvel[numobjects] = 0;
- rotyvel[numobjects] = 0;
- rotx[numobjects] = 0;
- roty[numobjects] = 0;
-
- if (atype == boxtype) model[numobjects].loaddecal("Models/Box.solid", 0);
- if (atype == cooltype) model[numobjects].loaddecal("Models/Cool.solid", 0);
- if (atype == walltype) model[numobjects].loaddecal("Models/Wall.solid", 0);
- if (atype == tunneltype) model[numobjects].loaddecal("Models/Tunnel.solid", 0);
- if (atype == chimneytype) model[numobjects].loaddecal("Models/Chimney.solid", 0);
- if (atype == spiketype) model[numobjects].load("Models/Spike.solid", 0);
- if (atype == weirdtype) model[numobjects].loaddecal("Models/Weird.solid", 0);
- if (atype == rocktype) model[numobjects].loaddecal("Models/Rock.solid", 0);
- if (atype == treetrunktype) model[numobjects].load("Models/TreeTrunk.solid", 0);
- if (atype == treeleavestype) model[numobjects].load("Models/Leaves.solid", 0);
- if (atype == bushtype) model[numobjects].load("Models/Bush.solid", 0);
-
- if (atype == boxtype) friction[numobjects] = 1.5;
- if (atype == cooltype) friction[numobjects] = 1.5;
- if (atype == walltype) friction[numobjects] = 1.5;
- if (atype == platformtype) friction[numobjects] = 1.5;
- if (atype == tunneltype) friction[numobjects] = 1.5;
- if (atype == chimneytype) friction[numobjects] = 1.5;
- if (atype == rocktype) friction[numobjects] = .5;
- if (atype == rocktype && ascale>.5) friction[numobjects] = 1.5;
- if (atype == weirdtype) friction[numobjects] = 1.5;
- if (atype == spiketype) friction[numobjects] = .4;
- if (atype == treetrunktype) friction[numobjects] = .4;
- if (atype == treeleavestype) friction[numobjects] = 0;
-
- if (friction[numobjects] == 1.5 && fabs(apitch) > 5)
- friction[numobjects] = .5;
-
- if (atype == platformtype) {
- model[numobjects].loaddecal("Models/Platform.solid", 0);
- model[numobjects].Rotate(90, 0, 0);
- }
-
- if (type[numobjects] == boxtype || type[numobjects] == cooltype || type[numobjects] == spiketype || type[numobjects] == weirdtype || type[numobjects] == walltype || type[numobjects] == chimneytype || type[numobjects] == tunneltype || type[numobjects] == platformtype) {
- model[numobjects].ScaleTexCoords(scale[numobjects] * 1.5);
- }
- if (type[numobjects] == rocktype) {
- model[numobjects].ScaleTexCoords(scale[numobjects] * 3);
- }
- model[numobjects].flat = 1;
- if (atype == treetrunktype || atype == treeleavestype || atype == rocktype) {
- model[numobjects].flat = 0;
- }
- model[numobjects].Scale(.3 * scale[numobjects], .3 * scale[numobjects], .3 * scale[numobjects]);
- model[numobjects].Rotate(90, 1, 1);
- model[numobjects].Rotate(apitch, 0, 0);
- if (type[numobjects] == rocktype) {
- model[numobjects].Rotate(ayaw * 5, 0, 0);
- }
- model[numobjects].CalculateNormals(1);
- model[numobjects].ScaleNormals(-1, -1, -1);
-
- if (atype == treetrunktype && position[numobjects].y < terrain.getHeight(position[numobjects].x, position[numobjects].z) + 1) {
- if (detail == 2)
- terrain.MakeDecal(shadowdecalpermanent, position[numobjects], 2, .4, 0);
- }
-
- if (atype == bushtype && position[numobjects].y < terrain.getHeight(position[numobjects].x, position[numobjects].z) + 1) {
- if (detail == 2)
- terrain.MakeDecal(shadowdecalpermanent, position[numobjects], 1, .4, 0);
- }
-
- if (atype != treeleavestype && atype != bushtype && atype != firetype)
- terrain.AddObject(where + DoRotation(model[numobjects].boundingspherecenter, 0, ayaw, 0), model[numobjects].boundingsphereradius, numobjects);
-
- numobjects++;
- }
-}
-
-void Objects::DoStuff()
-{
- XYZ spawnpoint;
- for (int i = 0; i < numobjects; i++) {
- if (type[i] == firetype)
- onfire[i] = 1;
- if (onfire[i]) {
- if (type[i] == bushtype)
- flamedelay[i] -= multiplier * 3;
- if (type[i] == firetype)
- flamedelay[i] -= multiplier * 3;
- if (type[i] == treeleavestype)
- flamedelay[i] -= multiplier * 4;
- while (flamedelay[i] < 0 && onfire[i]) {
- flamedelay[i] += .006;
- if (type[i] == bushtype || type[i] == firetype) {
- spawnpoint.x = ((float)(Random() % 100)) / 30 * scale[i];
- spawnpoint.y = ((float)(Random() % 100) + 60) / 30 * scale[i];
- spawnpoint.z = 0;
- spawnpoint = DoRotation(spawnpoint, 0, Random() % 360, 0);
- spawnpoint += position[i];
- Sprite::MakeSprite(flamesprite, spawnpoint, spawnpoint * 0, 1, 1, 1, (.6 + (float)abs(Random() % 100) / 200 - .25) * 5 * scale[i], 1);
- }
- if (type[i] == treeleavestype) {
- spawnpoint.x = ((float)(Random() % 100)) / 80 * scale[i];
- spawnpoint.y = ((float)(Random() % 100) + 80) / 12 * scale[i];
- spawnpoint.z = 0;
- spawnpoint = DoRotation(spawnpoint, 0, Random() % 360, 0);
- spawnpoint += position[i];
- Sprite::MakeSprite(flamesprite, spawnpoint, spawnpoint * 0, 1, 1, 1, (.6 + (float)abs(Random() % 100) / 200 - .25) * 6, 1);
- }
- }
-
- }
- }
-}
-
-void Objects::DoShadows()
-{
- int i, j, k, l;
- static XYZ testpoint, testpoint2, terrainpoint, lightloc, col;
- lightloc = light.location;
- if (!skyboxtexture)
- lightloc = 0;
- lightloc.y += 10;
- Normalise(&lightloc);
- int patchx, patchz;
-
- if (numobjects > 0)
- for (i = 0; i < numobjects; i++) {
- if (type[i] != treeleavestype && type[i] != treetrunktype && type[i] != bushtype && type[i] != firetype) {
- for (j = 0; j < model[i].vertexNum; j++) {
- terrainpoint = position[i] + DoRotation(model[i].vertex[j] + model[i].normals[j] * .1, 0, yaw[i], 0);
- //terrainpoint.y+=model[i].boundingsphereradius;
- shadowed[i] = 0;
- patchx = terrainpoint.x / (terrain.size / subdivision * terrain.scale);
- patchz = terrainpoint.z / (terrain.size / subdivision * terrain.scale);
- if (patchx >= 0 && patchz >= 0 && patchx < subdivision && patchz < subdivision)
- if (terrain.patchobjectnum[patchx][patchz])
- for (k = 0; k < terrain.patchobjectnum[patchx][patchz]; k++) {
- l = terrain.patchobjects[patchx][patchz][k];
- if (type[l] != treetrunktype/*&&l!=i*/) {
- testpoint = terrainpoint;
- testpoint2 = terrainpoint + lightloc * 50 * (1 - shadowed[i]);
- if (model[l].LineCheck(&testpoint, &testpoint2, &col, &position[l], &yaw[l]) != -1) {
- shadowed[i] = 1 - (findDistance(&terrainpoint, &col) / 50);
- }
- }
- }
- if (shadowed[i] > 0) {
- col = model[i].normals[j] - DoRotation(lightloc * shadowed[i], 0, -yaw[i], 0);
- Normalise(&col);
- for (k = 0; k < model[i].TriangleNum; k++) {
- if (model[i].Triangles[k].vertex[0] == j) {
- l = k * 24;
- model[i].vArray[l + 2] = col.x;
- model[i].vArray[l + 3] = col.y;
- model[i].vArray[l + 4] = col.z;
- }
- if (model[i].Triangles[k].vertex[1] == j) {
- l = k * 24;
- model[i].vArray[l + 10] = col.x;
- model[i].vArray[l + 11] = col.y;
- model[i].vArray[l + 12] = col.z;
- }
- if (model[i].Triangles[k].vertex[2] == j) {
- l = k * 24;
- model[i].vArray[l + 18] = col.x;
- model[i].vArray[l + 19] = col.y;
- model[i].vArray[l + 20] = col.z;
- }
- }
- }
- }
- }
- shadowed[i] = 0;
- }
-}
-
-Objects::Objects()
-{
- center = 0;
- radius = 0;
- numobjects = 0;
-
- memset(position, 0, sizeof(position));
- memset(type, 0, sizeof(type));
- memset(yaw, 0, sizeof(yaw));
- memset(pitch, 0, sizeof(pitch));
- memset(rotx, 0, sizeof(rotx));
- memset(rotxvel, 0, sizeof(rotxvel));
- memset(roty, 0, sizeof(roty));
- memset(rotyvel, 0, sizeof(rotyvel));
- memset(possible, 0, sizeof(possible));
- memset(model, 0, sizeof(model));
- memset(displaymodel, 0, sizeof(displaymodel));
- memset(friction, 0, sizeof(friction));
- memset(scale, 0, sizeof(scale));
- memset(messedwith, 0, sizeof(messedwith));
- memset(checked, 0, sizeof(checked));
- memset(shadowed, 0, sizeof(shadowed));
- memset(occluded, 0, sizeof(occluded));
- memset(onfire, 0, sizeof(onfire));
- memset(flamedelay, 0, sizeof(flamedelay));
-}
-
-Objects::~Objects()
-{
- boxtextureptr.destroy();
- treetextureptr.destroy();
- bushtextureptr.destroy();
- rocktextureptr.destroy();
-};
-
+++ /dev/null
-/*
-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 _OBJECTS_H_
-#define _OBJECTS_H_
-
-#include "Quaternions.h"
-#include "gamegl.h"
-#include "ImageIO.h"
-#include "Quaternions.h"
-#include "Frustum.h"
-#include "Lights.h"
-#include "Models.h"
-#include "Terrain.h"
-#include "Sprite.h"
-#include "Texture.h"
-#include <vector>
-//
-// Model Structures
-//
-
-#define max_objects 300
-
-#define boxtype 0
-#define weirdtype 1
-#define spiketype 2
-#define treetrunktype 3
-#define treeleavestype 4
-#define bushtype 5
-#define rocktype 6
-#define walltype 7
-#define chimneytype 8
-#define platformtype 9
-#define tunneltype 11
-#define cooltype 12
-#define firetype 13
-
-
-class Objects
-{
-public:
- XYZ center;
- float radius;
- XYZ position[max_objects];
- int type[max_objects];
- float yaw[max_objects];
- float pitch[max_objects];
- float rotx[max_objects];
- float rotxvel[max_objects];
- float roty[max_objects];
- float rotyvel[max_objects];
- int numobjects;
- bool possible[max_objects];
- Model model[max_objects];
- Model displaymodel[max_objects];
- float friction[max_objects];
- float scale[max_objects];
- float messedwith[max_objects];
- float checked[max_objects];
- Texture boxtextureptr;
- Texture treetextureptr;
- Texture bushtextureptr;
- Texture rocktextureptr;
- float shadowed[max_objects];
- float occluded[max_objects];
- bool checkcollide(XYZ startpoint, XYZ endpoint, int which);
- bool onfire[max_objects];
- float flamedelay[max_objects];
-
- void SphereCheckPossible(XYZ *p1, float radius);
- void DeleteObject(int which);
- void MakeObject(int atype, XYZ where, float ayaw, float ascale);
- void MakeObject(int atype, XYZ where, float ayaw, float apitch, float ascale);
- void Draw();
- void DoShadows();
- void DoStuff();
-
- Objects();
- ~Objects();
-};
-
-#endif
-
--- /dev/null
+/*
+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/>.
+*/
+
+#include "Objects/Objects.h"
+
+extern XYZ viewer;
+extern float viewdistance;
+extern float fadestart;
+extern int environment;
+extern float texscale;
+extern Light light;
+extern float multiplier;
+extern float gravity;
+extern FRUSTUM frustum;
+extern Terrain terrain;
+extern bool foliage;
+extern int detail;
+extern float blurness;
+extern float windvar;
+extern float playerdist;
+extern bool skyboxtexture;
+
+//Functions
+
+bool Objects::checkcollide(XYZ startpoint, XYZ endpoint, int which)
+{
+ static XYZ colpoint, colviewer, coltarget;
+ static int i;
+
+ startpoint.y += .1;
+ endpoint.y += .1;
+ startpoint.y -= .1;
+ endpoint.y -= .1;
+
+ for (i = 0; i < numobjects; i++) {
+ if (type[i] != treeleavestype && type[i] != treetrunktype && type[i] != bushtype && type[i] != firetype && i != which) {
+ colviewer = startpoint;
+ coltarget = endpoint;
+ if (model[i].LineCheck(&colviewer, &coltarget, &colpoint, &position[i], &yaw[i]) != -1)
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+void Objects::SphereCheckPossible(XYZ *p1, float radius)
+{
+ static int i, j;
+ static int whichpatchx;
+ static int whichpatchz;
+
+ whichpatchx = p1->x / (terrain.size / subdivision * terrain.scale);
+ whichpatchz = p1->z / (terrain.size / subdivision * terrain.scale);
+
+ if (whichpatchx >= 0 && whichpatchz >= 0 && whichpatchx < subdivision && whichpatchz < subdivision)
+ if (terrain.patchobjectnum[whichpatchx][whichpatchz] > 0 && terrain.patchobjectnum[whichpatchx][whichpatchz] < 500)
+ for (j = 0; j < terrain.patchobjectnum[whichpatchx][whichpatchz]; j++) {
+ i = terrain.patchobjects[whichpatchx][whichpatchz][j];
+ possible[i] = 0;
+ if (model[i].SphereCheckPossible(p1, radius, &position[i], &yaw[i]) != -1) {
+ possible[i] = 1;
+ }
+ }
+}
+
+void Objects::Draw()
+{
+ static float distance;
+ static int i;
+ static XYZ moved, terrainlight;
+ bool hidden;
+
+ for (i = 0; i < numobjects; i++) {
+ if (type[i] != firetype) {
+ moved = DoRotation(model[i].boundingspherecenter, 0, yaw[i], 0);
+ if (type[i] == tunneltype || frustum.SphereInFrustum(position[i].x + moved.x, position[i].y + moved.y, position[i].z + moved.z, model[i].boundingsphereradius)) {
+ distance = distsq(&viewer, &position[i]);
+ distance *= 1.2;
+ hidden = !(distsqflat(&viewer, &position[i]) > playerdist + 3 || (type[i] != bushtype && type[i] != treeleavestype));
+ if (!hidden) {
+
+ if (detail == 2 && distance > viewdistance * viewdistance / 4 && environment == desertenvironment)
+ glTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, blurness );
+ else
+ glTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0 );
+ distance = (viewdistance * viewdistance - (distance - (viewdistance * viewdistance * fadestart)) * (1 / (1 - fadestart))) / viewdistance / viewdistance;
+ if (distance > 1)
+ distance = 1;
+ if (distance > 0) {
+
+ if (occluded[i] < 6) {
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ if (!model[i].color)
+ glEnable(GL_LIGHTING);
+ else
+ glDisable(GL_LIGHTING);
+ glDepthMask(1);
+ glTranslatef(position[i].x, position[i].y, position[i].z);
+ if (type[i] == bushtype) {
+ messedwith[i] -= multiplier;
+ if (rotxvel[i] || rotx[i]) {
+ if (rotx[i] > 0) rotxvel[i] -= multiplier * 8 * fabs(rotx[i]);
+ if (rotx[i] < 0) rotxvel[i] += multiplier * 8 * fabs(rotx[i]);
+ if (rotx[i] > 0) rotxvel[i] -= multiplier * 4;
+ if (rotx[i] < 0) rotxvel[i] += multiplier * 4;
+ if (rotxvel[i] > 0) rotxvel[i] -= multiplier * 4;
+ if (rotxvel[i] < 0) rotxvel[i] += multiplier * 4;
+ if (fabs(rotx[i]) < multiplier * 4)
+ rotx[i] = 0;
+ if (fabs(rotxvel[i]) < multiplier * 4)
+ rotxvel[i] = 0;
+
+ rotx[i] += rotxvel[i] * multiplier * 4;
+ }
+ if (rotyvel[i] || roty[i]) {
+ if (roty[i] > 0) rotyvel[i] -= multiplier * 8 * fabs(roty[i]);
+ if (roty[i] < 0) rotyvel[i] += multiplier * 8 * fabs(roty[i]);
+ if (roty[i] > 0) rotyvel[i] -= multiplier * 4;
+ if (roty[i] < 0) rotyvel[i] += multiplier * 4;
+ if (rotyvel[i] > 0) rotyvel[i] -= multiplier * 4;
+ if (rotyvel[i] < 0) rotyvel[i] += multiplier * 4;
+ if (fabs(roty[i]) < multiplier * 4)
+ roty[i] = 0;
+ if (fabs(rotyvel[i]) < multiplier * 4)
+ rotyvel[i] = 0;
+
+ roty[i] += rotyvel[i] * multiplier * 4;
+ }
+ if (roty[i]) {
+ glRotatef(roty[i], 1, 0, 0);
+ }
+ if (rotx[i]) {
+ glRotatef(-rotx[i], 0, 0, 1);
+ }
+ if (rotx[i] > 10)
+ rotx[i] = 10;
+ if (rotx[i] < -10)
+ rotx[i] = -10;
+ if (roty[i] > 10)
+ roty[i] = 10;
+ if (roty[i] < -10)
+ roty[i] = -10;
+ }
+ if (type[i] == treetrunktype || type[i] == treeleavestype) {
+ if (type[i] == treetrunktype || environment == desertenvironment) {
+ messedwith[i] -= multiplier;
+ if (rotxvel[i] || rotx[i]) {
+ if (rotx[i] > 0) rotxvel[i] -= multiplier * 8 * fabs(rotx[i]);
+ if (rotx[i] < 0) rotxvel[i] += multiplier * 8 * fabs(rotx[i]);
+ if (rotx[i] > 0) rotxvel[i] -= multiplier * 4;
+ if (rotx[i] < 0) rotxvel[i] += multiplier * 4;
+ if (rotxvel[i] > 0) rotxvel[i] -= multiplier * 4;
+ if (rotxvel[i] < 0) rotxvel[i] += multiplier * 4;
+ if (fabs(rotx[i]) < multiplier * 4)
+ rotx[i] = 0;
+ if (fabs(rotxvel[i]) < multiplier * 4)
+ rotxvel[i] = 0;
+
+ rotx[i] += rotxvel[i] * multiplier * 4;
+ }
+ if (rotyvel[i] || roty[i]) {
+ if (roty[i] > 0) rotyvel[i] -= multiplier * 8 * fabs(roty[i]);
+ if (roty[i] < 0) rotyvel[i] += multiplier * 8 * fabs(roty[i]);
+ if (roty[i] > 0) rotyvel[i] -= multiplier * 4;
+ if (roty[i] < 0) rotyvel[i] += multiplier * 4;
+ if (rotyvel[i] > 0) rotyvel[i] -= multiplier * 4;
+ if (rotyvel[i] < 0) rotyvel[i] += multiplier * 4;
+ if (fabs(roty[i]) < multiplier * 4)
+ roty[i] = 0;
+ if (fabs(rotyvel[i]) < multiplier * 4)
+ rotyvel[i] = 0;
+
+ roty[i] += rotyvel[i] * multiplier * 4;
+ }
+ if (roty[i]) {
+ glRotatef(roty[i] / 6, 1, 0, 0);
+ }
+ if (rotx[i]) {
+ glRotatef(-rotx[i] / 6, 0, 0, 1);
+ }
+ if (rotx[i] > 10)
+ rotx[i] = 10;
+ if (rotx[i] < -10)
+ rotx[i] = -10;
+ if (roty[i] > 10)
+ roty[i] = 10;
+ if (roty[i] < -10)
+ roty[i] = -10;
+ } else {
+ messedwith[i] -= multiplier;
+ if (rotxvel[i] || rotx[i]) {
+ if (rotx[i] > 0) rotxvel[i] -= multiplier * 8 * fabs(rotx[i]);
+ if (rotx[i] < 0) rotxvel[i] += multiplier * 8 * fabs(rotx[i]);
+ if (rotx[i] > 0) rotxvel[i] -= multiplier * 4;
+ if (rotx[i] < 0) rotxvel[i] += multiplier * 4;
+ if (rotxvel[i] > 0) rotxvel[i] -= multiplier * 4;
+ if (rotxvel[i] < 0) rotxvel[i] += multiplier * 4;
+ if (fabs(rotx[i]) < multiplier * 4)
+ rotx[i] = 0;
+ if (fabs(rotxvel[i]) < multiplier * 4)
+ rotxvel[i] = 0;
+
+ rotx[i] += rotxvel[i] * multiplier * 4;
+ }
+ if (rotyvel[i] || roty[i]) {
+ if (roty[i] > 0) rotyvel[i] -= multiplier * 8 * fabs(roty[i]);
+ if (roty[i] < 0) rotyvel[i] += multiplier * 8 * fabs(roty[i]);
+ if (roty[i] > 0) rotyvel[i] -= multiplier * 4;
+ if (roty[i] < 0) rotyvel[i] += multiplier * 4;
+ if (rotyvel[i] > 0) rotyvel[i] -= multiplier * 4;
+ if (rotyvel[i] < 0) rotyvel[i] += multiplier * 4;
+ if (fabs(roty[i]) < multiplier * 4)
+ roty[i] = 0;
+ if (fabs(rotyvel[i]) < multiplier * 4)
+ rotyvel[i] = 0;
+
+ roty[i] += rotyvel[i] * multiplier * 4;
+ }
+ if (roty[i]) {
+ glRotatef(roty[i] / 4, 1, 0, 0);
+ }
+ if (rotx[i]) {
+ glRotatef(-rotx[i] / 4, 0, 0, 1);
+ }
+ if (rotx[i] > 10)
+ rotx[i] = 10;
+ if (rotx[i] < -10)
+ rotx[i] = -10;
+ if (roty[i] > 10)
+ roty[i] = 10;
+ if (roty[i] < -10)
+ roty[i] = -10;
+ }
+
+ }
+ if (/*detail==2&&*/environment == snowyenvironment) {
+ if (type[i] == treeleavestype) {
+ glRotatef((sin(windvar + position[i].x * .3) + .5) * 1.5 * (sin(windvar * 2 + position[i].x * .3) + 1) / 2, 1, 0, 0);
+ }
+ if (type[i] == treetrunktype) {
+ glRotatef((sin(windvar + position[i].x * .3) + .5)*.5 * (sin(windvar * 2 + position[i].x * .3) + 1) / 2, 1, 0, 0);
+ }
+ if (type[i] == bushtype) {
+ glRotatef((sin(windvar + position[i].x * .3) + .5) * 4 * (sin(windvar * 2 + position[i].x * .3) + 1) / 2, 1, 0, 0);
+ }
+ }
+ if (/*detail==2&&*/environment == grassyenvironment) {
+ if (type[i] == treeleavestype) {
+ glRotatef((sin(windvar + position[i].x * .3) + .5) * 1.5 * .5 * (sin(windvar * 2 + position[i].x * .3) + 1) / 2, 1, 0, 0);
+ }
+ if (type[i] == treetrunktype) {
+ glRotatef((sin(windvar + position[i].x * .3) + .5)*.5 * .5 * (sin(windvar * 2 + position[i].x * .3) + 1) / 2, 1, 0, 0);
+ }
+ if (type[i] == bushtype) {
+ glRotatef((sin(windvar + position[i].x * .3) + .5) * 4 * .5 * (sin(windvar * 2 + position[i].x * .3) + 1) / 2, 1, 0, 0);
+ }
+ }
+ if (/*detail==2&&*/environment == desertenvironment) {
+ if (type[i] == bushtype) {
+ glRotatef((sin(windvar + position[i].x * .3) + .5) * 4 * .5 * (sin(windvar * 2 + position[i].x * .3) + 1) / 2, 1, 0, 0);
+ }
+ }
+ glRotatef(yaw[i], 0, 1, 0);
+ if (distance > 1)
+ distance = 1;
+ glColor4f((1 - shadowed[i]) / 2 + .5, (1 - shadowed[i]) / 2 + .5, (1 - shadowed[i]) / 2 + .5, distance);
+ if (distance >= 1) {
+ glDisable(GL_BLEND);
+ glAlphaFunc(GL_GREATER, 0.5);
+ }
+ if (distance < 1) {
+ glEnable(GL_BLEND);
+ glAlphaFunc(GL_GREATER, 0.1);
+ }
+ if (type[i] != treetrunktype && type[i] != treeleavestype && type[i] != bushtype && type[i] != rocktype) {
+ glEnable(GL_CULL_FACE);
+ glAlphaFunc(GL_GREATER, 0.0001);
+ model[i].drawdifftex(boxtextureptr);
+ model[i].drawdecals(terrain.shadowtexture, terrain.bloodtexture, terrain.bloodtexture2, terrain.breaktexture);
+ }
+ if (type[i] == rocktype) {
+ glEnable(GL_CULL_FACE);
+ glAlphaFunc(GL_GREATER, 0.0001);
+ glColor4f((1 - shadowed[i]) / 2 + light.ambient[0], (1 - shadowed[i]) / 2 + light.ambient[1], (1 - shadowed[i]) / 2 + light.ambient[2], distance);
+ model[i].drawdifftex(rocktextureptr);
+ model[i].drawdecals(terrain.shadowtexture, terrain.bloodtexture, terrain.bloodtexture2, terrain.breaktexture);
+ }
+ if (type[i] == treeleavestype) {
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_LIGHTING);
+ terrainlight = terrain.getLighting(position[i].x, position[i].z);
+ if (!hidden) {
+ glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, distance);
+ if (distance < 1)
+ glAlphaFunc(GL_GREATER, 0.2);
+ }
+ if (hidden) {
+ glDepthMask(0);
+ glEnable(GL_BLEND);
+ glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, distance / 3);
+ glAlphaFunc(GL_GREATER, 0);
+ }
+ model[i].drawdifftex(treetextureptr);
+ }
+ if (type[i] == bushtype) {
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_LIGHTING);
+ terrainlight = terrain.getLighting(position[i].x, position[i].z);
+ if (!hidden) {
+ glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, distance);
+ if (distance < 1)
+ glAlphaFunc(GL_GREATER, 0.2);
+ }
+ if (hidden) {
+ glDepthMask(0);
+ glEnable(GL_BLEND);
+ glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, distance / 3);
+ glAlphaFunc(GL_GREATER, 0);
+ }
+ model[i].drawdifftex(bushtextureptr);
+ }
+ if (type[i] == treetrunktype) {
+ glEnable(GL_CULL_FACE);
+ terrainlight = terrain.getLighting(position[i].x, position[i].z);
+ glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, distance);
+ model[i].drawdifftex(treetextureptr);
+ }
+ glPopMatrix();
+ }
+ }
+ }
+ }
+ }
+ }
+
+ glTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0 );
+ for (i = 0; i < numobjects; i++) {
+ if (type[i] == treeleavestype || type[i] == bushtype) {
+ moved = DoRotation(model[i].boundingspherecenter, 0, yaw[i], 0);
+ if (frustum.SphereInFrustum(position[i].x + moved.x, position[i].y + moved.y, position[i].z + moved.z, model[i].boundingsphereradius)) {
+ hidden = distsqflat(&viewer, &position[i]) <= playerdist + 3;
+ if (hidden) {
+ distance = 1;
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glEnable(GL_LIGHTING);
+ glDepthMask(1);
+ glTranslatef(position[i].x, position[i].y, position[i].z);
+ if (type[i] == bushtype) {
+ messedwith[i] -= multiplier;
+ if (rotxvel[i] || rotx[i]) {
+ if (rotx[i] > 0) rotxvel[i] -= multiplier * 8 * fabs(rotx[i]);
+ if (rotx[i] < 0) rotxvel[i] += multiplier * 8 * fabs(rotx[i]);
+ if (rotx[i] > 0) rotxvel[i] -= multiplier * 4;
+ if (rotx[i] < 0) rotxvel[i] += multiplier * 4;
+ if (rotxvel[i] > 0) rotxvel[i] -= multiplier * 4;
+ if (rotxvel[i] < 0) rotxvel[i] += multiplier * 4;
+ if (fabs(rotx[i]) < multiplier * 4)
+ rotx[i] = 0;
+ if (fabs(rotxvel[i]) < multiplier * 4)
+ rotxvel[i] = 0;
+
+ rotx[i] += rotxvel[i] * multiplier * 4;
+ }
+ if (rotyvel[i] || roty[i]) {
+ if (roty[i] > 0) rotyvel[i] -= multiplier * 8 * fabs(roty[i]);
+ if (roty[i] < 0) rotyvel[i] += multiplier * 8 * fabs(roty[i]);
+ if (roty[i] > 0) rotyvel[i] -= multiplier * 4;
+ if (roty[i] < 0) rotyvel[i] += multiplier * 4;
+ if (rotyvel[i] > 0) rotyvel[i] -= multiplier * 4;
+ if (rotyvel[i] < 0) rotyvel[i] += multiplier * 4;
+ if (fabs(roty[i]) < multiplier * 4)
+ roty[i] = 0;
+ if (fabs(rotyvel[i]) < multiplier * 4)
+ rotyvel[i] = 0;
+
+ roty[i] += rotyvel[i] * multiplier * 4;
+ }
+ if (roty[i]) {
+ glRotatef(roty[i], 1, 0, 0);
+ }
+ if (rotx[i]) {
+ glRotatef(-rotx[i], 0, 0, 1);
+ }
+ if (rotx[i] > 10)
+ rotx[i] = 10;
+ if (rotx[i] < -10)
+ rotx[i] = -10;
+ if (roty[i] > 10)
+ roty[i] = 10;
+ if (roty[i] < -10)
+ roty[i] = -10;
+ }
+ if (type[i] == treetrunktype || type[i] == treeleavestype) {
+ messedwith[i] -= multiplier;
+ if (rotxvel[i] || rotx[i]) {
+ if (rotx[i] > 0) rotxvel[i] -= multiplier * 8 * fabs(rotx[i]);
+ if (rotx[i] < 0) rotxvel[i] += multiplier * 8 * fabs(rotx[i]);
+ if (rotx[i] > 0) rotxvel[i] -= multiplier * 4;
+ if (rotx[i] < 0) rotxvel[i] += multiplier * 4;
+ if (rotxvel[i] > 0) rotxvel[i] -= multiplier * 4;
+ if (rotxvel[i] < 0) rotxvel[i] += multiplier * 4;
+ if (fabs(rotx[i]) < multiplier * 4)
+ rotx[i] = 0;
+ if (fabs(rotxvel[i]) < multiplier * 4)
+ rotxvel[i] = 0;
+
+ rotx[i] += rotxvel[i] * multiplier * 4;
+ }
+ if (rotyvel[i] || roty[i]) {
+ if (roty[i] > 0) rotyvel[i] -= multiplier * 8 * fabs(roty[i]);
+ if (roty[i] < 0) rotyvel[i] += multiplier * 8 * fabs(roty[i]);
+ if (roty[i] > 0) rotyvel[i] -= multiplier * 4;
+ if (roty[i] < 0) rotyvel[i] += multiplier * 4;
+ if (rotyvel[i] > 0) rotyvel[i] -= multiplier * 4;
+ if (rotyvel[i] < 0) rotyvel[i] += multiplier * 4;
+ if (fabs(roty[i]) < multiplier * 4)
+ roty[i] = 0;
+ if (fabs(rotyvel[i]) < multiplier * 4)
+ rotyvel[i] = 0;
+
+ roty[i] += rotyvel[i] * multiplier * 4;
+ }
+ if (roty[i]) {
+ glRotatef(roty[i] / 2, 1, 0, 0);
+ }
+ if (rotx[i]) {
+ glRotatef(-rotx[i] / 2, 0, 0, 1);
+ }
+ if (rotx[i] > 10)
+ rotx[i] = 10;
+ if (rotx[i] < -10)
+ rotx[i] = -10;
+ if (roty[i] > 10)
+ roty[i] = 10;
+ if (roty[i] < -10)
+ roty[i] = -10;
+ }
+ if (environment == snowyenvironment) {
+ if (type[i] == treeleavestype) {
+ glRotatef((sin(windvar + position[i].x * .3) + .5) * 1.5 * (sin(windvar * 2 + position[i].x * .3) + 1) / 2, 1, 0, 0);
+ }
+ if (type[i] == treetrunktype) {
+ glRotatef((sin(windvar + position[i].x * .3) + .5)*.5 * (sin(windvar * 2 + position[i].x * .3) + 1) / 2, 1, 0, 0);
+ }
+ if (type[i] == bushtype) {
+ glRotatef((sin(windvar + position[i].x * .3) + .5) * 4 * (sin(windvar * 2 + position[i].x * .3) + 1) / 2, 1, 0, 0);
+ }
+ }
+ if (environment == grassyenvironment) {
+ if (type[i] == treeleavestype) {
+ glRotatef((sin(windvar + position[i].x * .3) + .5) * 1.5 * .5 * (sin(windvar * 2 + position[i].x * .3) + 1) / 2, 1, 0, 0);
+ }
+ if (type[i] == treetrunktype) {
+ glRotatef((sin(windvar + position[i].x * .3) + .5)*.5 * .5 * (sin(windvar * 2 + position[i].x * .3) + 1) / 2, 1, 0, 0);
+ }
+ if (type[i] == bushtype) {
+ glRotatef((sin(windvar + position[i].x * .3) + .5) * 4 * .5 * (sin(windvar * 2 + position[i].x * .3) + 1) / 2, 1, 0, 0);
+ }
+ }
+ glRotatef(yaw[i], 0, 1, 0);
+ glColor4f(1, 1, 1, distance);
+ if (type[i] == treeleavestype) {
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_LIGHTING);
+ terrainlight = terrain.getLighting(position[i].x, position[i].z);
+ glDepthMask(0);
+ glEnable(GL_BLEND);
+ glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, .3);
+ glAlphaFunc(GL_GREATER, 0);
+ glDisable(GL_ALPHA_TEST);
+ model[i].drawdifftex(treetextureptr);
+ }
+ if (type[i] == bushtype) {
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_LIGHTING);
+ terrainlight = terrain.getLighting(position[i].x, position[i].z);
+ glDepthMask(0);
+ glEnable(GL_BLEND);
+ glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, .3);
+ glAlphaFunc(GL_GREATER, 0);
+ glDisable(GL_ALPHA_TEST);
+ model[i].drawdifftex(bushtextureptr);
+ }
+ glPopMatrix();
+ }
+ }
+ }
+ }
+ if (environment == desertenvironment)
+ glTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0 );
+ glEnable(GL_ALPHA_TEST);
+ SetUpLight(&light, 0);
+}
+
+void Objects::DeleteObject(int which)
+{
+ type[numobjects - 1] = 0;
+ yaw[numobjects - 1] = 0;
+ position[numobjects - 1] = 0;
+ scale[numobjects - 1] = 0;
+ friction[numobjects - 1] = 0;
+
+ numobjects--;
+}
+
+void Objects::MakeObject(int atype, XYZ where, float ayaw, float ascale)
+{
+ if ((atype != treeleavestype && atype != bushtype) || foliage == 1) {
+ scale[numobjects] = ascale;
+ if (atype == treeleavestype)
+ scale[numobjects] += fabs((float)(Random() % 100) / 900) * ascale;
+
+ onfire[numobjects] = 0;
+ flamedelay[numobjects] = 0;
+ type[numobjects] = atype;
+
+ if (atype == firetype)
+ onfire[numobjects] = 1;
+
+ position[numobjects] = where;
+ if (atype == bushtype)
+ position[numobjects].y = terrain.getHeight(position[numobjects].x, position[numobjects].z) - .3;
+ yaw[numobjects] = ayaw;
+
+ rotxvel[numobjects] = 0;
+ rotyvel[numobjects] = 0;
+ rotx[numobjects] = 0;
+ roty[numobjects] = 0;
+
+ if (atype == boxtype) model[numobjects].loaddecal("Models/Box.solid", 0);
+ if (atype == cooltype) model[numobjects].loaddecal("Models/Cool.solid", 0);
+ if (atype == walltype) model[numobjects].loaddecal("Models/Wall.solid", 0);
+ if (atype == tunneltype) model[numobjects].loaddecal("Models/Tunnel.solid", 0);
+ if (atype == chimneytype) model[numobjects].loaddecal("Models/Chimney.solid", 0);
+ if (atype == spiketype) model[numobjects].load("Models/Spike.solid", 0);
+ if (atype == weirdtype) model[numobjects].loaddecal("Models/Weird.solid", 0);
+ if (atype == rocktype) model[numobjects].loaddecal("Models/Rock.solid", 0);
+ if (atype == treetrunktype) model[numobjects].load("Models/TreeTrunk.solid", 0);
+ if (atype == treeleavestype) model[numobjects].load("Models/Leaves.solid", 0);
+ if (atype == bushtype) model[numobjects].load("Models/Bush.solid", 0);
+
+ if (atype == boxtype) friction[numobjects] = 1.5;
+ if (atype == cooltype) friction[numobjects] = 1.5;
+ if (atype == walltype) friction[numobjects] = 1.5;
+ if (atype == platformtype) friction[numobjects] = 1.5;
+ if (atype == tunneltype) friction[numobjects] = 1.5;
+ if (atype == chimneytype) friction[numobjects] = 1.5;
+ if (atype == rocktype) friction[numobjects] = .5;
+ if (atype == rocktype && ascale>.5) friction[numobjects] = 1.5;
+ if (atype == weirdtype) friction[numobjects] = 1.5;
+ if (atype == spiketype) friction[numobjects] = .4;
+ if (atype == treetrunktype) friction[numobjects] = .4;
+ if (atype == treeleavestype) friction[numobjects] = 0;
+
+ if (atype == platformtype) {
+ model[numobjects].loaddecal("Models/Platform.solid", 0);
+ model[numobjects].Rotate(90, 0, 0);
+ }
+
+ if (type[numobjects] == boxtype || type[numobjects] == cooltype || type[numobjects] == spiketype || type[numobjects] == weirdtype || type[numobjects] == walltype || type[numobjects] == chimneytype || type[numobjects] == tunneltype || type[numobjects] == platformtype) {
+ model[numobjects].ScaleTexCoords(scale[numobjects] * 1.5);
+ }
+ if (type[numobjects] == rocktype) {
+ model[numobjects].ScaleTexCoords(scale[numobjects] * 3);
+ }
+ model[numobjects].flat = 1;
+ if (atype == treetrunktype || atype == treeleavestype || atype == rocktype) {
+ model[numobjects].flat = 0;
+ }
+ model[numobjects].Scale(.3 * scale[numobjects], .3 * scale[numobjects], .3 * scale[numobjects]);
+ model[numobjects].Rotate(90, 1, 1);
+ if (type[numobjects] == rocktype) {
+ model[numobjects].Rotate(ayaw * 5, 1, 1);
+ }
+ model[numobjects].CalculateNormals(1);
+ model[numobjects].ScaleNormals(-1, -1, -1);
+
+ if (atype == treetrunktype && position[numobjects].y < terrain.getHeight(position[numobjects].x, position[numobjects].z) + 1) {
+ if (detail == 2)
+ terrain.MakeDecal(shadowdecalpermanent, position[numobjects], 2, .4, 0);
+ }
+
+ if (atype == bushtype && position[numobjects].y < terrain.getHeight(position[numobjects].x, position[numobjects].z) + 1) {
+ if (detail == 2)
+ terrain.MakeDecal(shadowdecalpermanent, position[numobjects], 1, .4, 0);
+ }
+
+ if (atype != treeleavestype && atype != bushtype && atype != firetype)
+ terrain.AddObject(where + DoRotation(model[numobjects].boundingspherecenter, 0, ayaw, 0), model[numobjects].boundingsphereradius, numobjects);
+
+ numobjects++;
+ }
+}
+
+void Objects::MakeObject(int atype, XYZ where, float ayaw, float apitch, float ascale)
+{
+ if ((atype != treeleavestype && atype != bushtype) || foliage == 1) {
+ scale[numobjects] = ascale;
+ if (atype == treeleavestype)
+ scale[numobjects] += fabs((float)(Random() % 100) / 900) * ascale;
+
+ onfire[numobjects] = 0;
+ flamedelay[numobjects] = 0;
+ type[numobjects] = atype;
+
+ if (atype == firetype)
+ onfire[numobjects] = 1;
+
+ position[numobjects] = where;
+ if (atype == bushtype)
+ position[numobjects].y = terrain.getHeight(position[numobjects].x, position[numobjects].z) - .3;
+ yaw[numobjects] = ayaw;
+ pitch[numobjects] = apitch;
+
+ rotxvel[numobjects] = 0;
+ rotyvel[numobjects] = 0;
+ rotx[numobjects] = 0;
+ roty[numobjects] = 0;
+
+ if (atype == boxtype) model[numobjects].loaddecal("Models/Box.solid", 0);
+ if (atype == cooltype) model[numobjects].loaddecal("Models/Cool.solid", 0);
+ if (atype == walltype) model[numobjects].loaddecal("Models/Wall.solid", 0);
+ if (atype == tunneltype) model[numobjects].loaddecal("Models/Tunnel.solid", 0);
+ if (atype == chimneytype) model[numobjects].loaddecal("Models/Chimney.solid", 0);
+ if (atype == spiketype) model[numobjects].load("Models/Spike.solid", 0);
+ if (atype == weirdtype) model[numobjects].loaddecal("Models/Weird.solid", 0);
+ if (atype == rocktype) model[numobjects].loaddecal("Models/Rock.solid", 0);
+ if (atype == treetrunktype) model[numobjects].load("Models/TreeTrunk.solid", 0);
+ if (atype == treeleavestype) model[numobjects].load("Models/Leaves.solid", 0);
+ if (atype == bushtype) model[numobjects].load("Models/Bush.solid", 0);
+
+ if (atype == boxtype) friction[numobjects] = 1.5;
+ if (atype == cooltype) friction[numobjects] = 1.5;
+ if (atype == walltype) friction[numobjects] = 1.5;
+ if (atype == platformtype) friction[numobjects] = 1.5;
+ if (atype == tunneltype) friction[numobjects] = 1.5;
+ if (atype == chimneytype) friction[numobjects] = 1.5;
+ if (atype == rocktype) friction[numobjects] = .5;
+ if (atype == rocktype && ascale>.5) friction[numobjects] = 1.5;
+ if (atype == weirdtype) friction[numobjects] = 1.5;
+ if (atype == spiketype) friction[numobjects] = .4;
+ if (atype == treetrunktype) friction[numobjects] = .4;
+ if (atype == treeleavestype) friction[numobjects] = 0;
+
+ if (friction[numobjects] == 1.5 && fabs(apitch) > 5)
+ friction[numobjects] = .5;
+
+ if (atype == platformtype) {
+ model[numobjects].loaddecal("Models/Platform.solid", 0);
+ model[numobjects].Rotate(90, 0, 0);
+ }
+
+ if (type[numobjects] == boxtype || type[numobjects] == cooltype || type[numobjects] == spiketype || type[numobjects] == weirdtype || type[numobjects] == walltype || type[numobjects] == chimneytype || type[numobjects] == tunneltype || type[numobjects] == platformtype) {
+ model[numobjects].ScaleTexCoords(scale[numobjects] * 1.5);
+ }
+ if (type[numobjects] == rocktype) {
+ model[numobjects].ScaleTexCoords(scale[numobjects] * 3);
+ }
+ model[numobjects].flat = 1;
+ if (atype == treetrunktype || atype == treeleavestype || atype == rocktype) {
+ model[numobjects].flat = 0;
+ }
+ model[numobjects].Scale(.3 * scale[numobjects], .3 * scale[numobjects], .3 * scale[numobjects]);
+ model[numobjects].Rotate(90, 1, 1);
+ model[numobjects].Rotate(apitch, 0, 0);
+ if (type[numobjects] == rocktype) {
+ model[numobjects].Rotate(ayaw * 5, 0, 0);
+ }
+ model[numobjects].CalculateNormals(1);
+ model[numobjects].ScaleNormals(-1, -1, -1);
+
+ if (atype == treetrunktype && position[numobjects].y < terrain.getHeight(position[numobjects].x, position[numobjects].z) + 1) {
+ if (detail == 2)
+ terrain.MakeDecal(shadowdecalpermanent, position[numobjects], 2, .4, 0);
+ }
+
+ if (atype == bushtype && position[numobjects].y < terrain.getHeight(position[numobjects].x, position[numobjects].z) + 1) {
+ if (detail == 2)
+ terrain.MakeDecal(shadowdecalpermanent, position[numobjects], 1, .4, 0);
+ }
+
+ if (atype != treeleavestype && atype != bushtype && atype != firetype)
+ terrain.AddObject(where + DoRotation(model[numobjects].boundingspherecenter, 0, ayaw, 0), model[numobjects].boundingsphereradius, numobjects);
+
+ numobjects++;
+ }
+}
+
+void Objects::DoStuff()
+{
+ XYZ spawnpoint;
+ for (int i = 0; i < numobjects; i++) {
+ if (type[i] == firetype)
+ onfire[i] = 1;
+ if (onfire[i]) {
+ if (type[i] == bushtype)
+ flamedelay[i] -= multiplier * 3;
+ if (type[i] == firetype)
+ flamedelay[i] -= multiplier * 3;
+ if (type[i] == treeleavestype)
+ flamedelay[i] -= multiplier * 4;
+ while (flamedelay[i] < 0 && onfire[i]) {
+ flamedelay[i] += .006;
+ if (type[i] == bushtype || type[i] == firetype) {
+ spawnpoint.x = ((float)(Random() % 100)) / 30 * scale[i];
+ spawnpoint.y = ((float)(Random() % 100) + 60) / 30 * scale[i];
+ spawnpoint.z = 0;
+ spawnpoint = DoRotation(spawnpoint, 0, Random() % 360, 0);
+ spawnpoint += position[i];
+ Sprite::MakeSprite(flamesprite, spawnpoint, spawnpoint * 0, 1, 1, 1, (.6 + (float)abs(Random() % 100) / 200 - .25) * 5 * scale[i], 1);
+ }
+ if (type[i] == treeleavestype) {
+ spawnpoint.x = ((float)(Random() % 100)) / 80 * scale[i];
+ spawnpoint.y = ((float)(Random() % 100) + 80) / 12 * scale[i];
+ spawnpoint.z = 0;
+ spawnpoint = DoRotation(spawnpoint, 0, Random() % 360, 0);
+ spawnpoint += position[i];
+ Sprite::MakeSprite(flamesprite, spawnpoint, spawnpoint * 0, 1, 1, 1, (.6 + (float)abs(Random() % 100) / 200 - .25) * 6, 1);
+ }
+ }
+
+ }
+ }
+}
+
+void Objects::DoShadows()
+{
+ int i, j, k, l;
+ static XYZ testpoint, testpoint2, terrainpoint, lightloc, col;
+ lightloc = light.location;
+ if (!skyboxtexture)
+ lightloc = 0;
+ lightloc.y += 10;
+ Normalise(&lightloc);
+ int patchx, patchz;
+
+ if (numobjects > 0)
+ for (i = 0; i < numobjects; i++) {
+ if (type[i] != treeleavestype && type[i] != treetrunktype && type[i] != bushtype && type[i] != firetype) {
+ for (j = 0; j < model[i].vertexNum; j++) {
+ terrainpoint = position[i] + DoRotation(model[i].vertex[j] + model[i].normals[j] * .1, 0, yaw[i], 0);
+ //terrainpoint.y+=model[i].boundingsphereradius;
+ shadowed[i] = 0;
+ patchx = terrainpoint.x / (terrain.size / subdivision * terrain.scale);
+ patchz = terrainpoint.z / (terrain.size / subdivision * terrain.scale);
+ if (patchx >= 0 && patchz >= 0 && patchx < subdivision && patchz < subdivision)
+ if (terrain.patchobjectnum[patchx][patchz])
+ for (k = 0; k < terrain.patchobjectnum[patchx][patchz]; k++) {
+ l = terrain.patchobjects[patchx][patchz][k];
+ if (type[l] != treetrunktype/*&&l!=i*/) {
+ testpoint = terrainpoint;
+ testpoint2 = terrainpoint + lightloc * 50 * (1 - shadowed[i]);
+ if (model[l].LineCheck(&testpoint, &testpoint2, &col, &position[l], &yaw[l]) != -1) {
+ shadowed[i] = 1 - (findDistance(&terrainpoint, &col) / 50);
+ }
+ }
+ }
+ if (shadowed[i] > 0) {
+ col = model[i].normals[j] - DoRotation(lightloc * shadowed[i], 0, -yaw[i], 0);
+ Normalise(&col);
+ for (k = 0; k < model[i].TriangleNum; k++) {
+ if (model[i].Triangles[k].vertex[0] == j) {
+ l = k * 24;
+ model[i].vArray[l + 2] = col.x;
+ model[i].vArray[l + 3] = col.y;
+ model[i].vArray[l + 4] = col.z;
+ }
+ if (model[i].Triangles[k].vertex[1] == j) {
+ l = k * 24;
+ model[i].vArray[l + 10] = col.x;
+ model[i].vArray[l + 11] = col.y;
+ model[i].vArray[l + 12] = col.z;
+ }
+ if (model[i].Triangles[k].vertex[2] == j) {
+ l = k * 24;
+ model[i].vArray[l + 18] = col.x;
+ model[i].vArray[l + 19] = col.y;
+ model[i].vArray[l + 20] = col.z;
+ }
+ }
+ }
+ }
+ }
+ shadowed[i] = 0;
+ }
+}
+
+Objects::Objects()
+{
+ center = 0;
+ radius = 0;
+ numobjects = 0;
+
+ memset(position, 0, sizeof(position));
+ memset(type, 0, sizeof(type));
+ memset(yaw, 0, sizeof(yaw));
+ memset(pitch, 0, sizeof(pitch));
+ memset(rotx, 0, sizeof(rotx));
+ memset(rotxvel, 0, sizeof(rotxvel));
+ memset(roty, 0, sizeof(roty));
+ memset(rotyvel, 0, sizeof(rotyvel));
+ memset(possible, 0, sizeof(possible));
+ memset(model, 0, sizeof(model));
+ memset(displaymodel, 0, sizeof(displaymodel));
+ memset(friction, 0, sizeof(friction));
+ memset(scale, 0, sizeof(scale));
+ memset(messedwith, 0, sizeof(messedwith));
+ memset(checked, 0, sizeof(checked));
+ memset(shadowed, 0, sizeof(shadowed));
+ memset(occluded, 0, sizeof(occluded));
+ memset(onfire, 0, sizeof(onfire));
+ memset(flamedelay, 0, sizeof(flamedelay));
+}
+
+Objects::~Objects()
+{
+ boxtextureptr.destroy();
+ treetextureptr.destroy();
+ bushtextureptr.destroy();
+ rocktextureptr.destroy();
+};
+
--- /dev/null
+/*
+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 _OBJECTS_H_
+#define _OBJECTS_H_
+
+#include "Environment/Lights.h"
+#include "Environment/Terrain.h"
+#include "Graphic/gamegl.h"
+#include "Graphic/Models.h"
+#include "Graphic/Sprite.h"
+#include "Graphic/Texture.h"
+#include "Math/Frustum.h"
+#include "Math/Quaternions.h"
+#include "Math/Quaternions.h"
+#include "Utils/ImageIO.h"
+
+#include <vector>
+//
+// Model Structures
+//
+
+#define max_objects 300
+
+#define boxtype 0
+#define weirdtype 1
+#define spiketype 2
+#define treetrunktype 3
+#define treeleavestype 4
+#define bushtype 5
+#define rocktype 6
+#define walltype 7
+#define chimneytype 8
+#define platformtype 9
+#define tunneltype 11
+#define cooltype 12
+#define firetype 13
+
+
+class Objects
+{
+public:
+ XYZ center;
+ float radius;
+ XYZ position[max_objects];
+ int type[max_objects];
+ float yaw[max_objects];
+ float pitch[max_objects];
+ float rotx[max_objects];
+ float rotxvel[max_objects];
+ float roty[max_objects];
+ float rotyvel[max_objects];
+ int numobjects;
+ bool possible[max_objects];
+ Model model[max_objects];
+ Model displaymodel[max_objects];
+ float friction[max_objects];
+ float scale[max_objects];
+ float messedwith[max_objects];
+ float checked[max_objects];
+ Texture boxtextureptr;
+ Texture treetextureptr;
+ Texture bushtextureptr;
+ Texture rocktextureptr;
+ float shadowed[max_objects];
+ float occluded[max_objects];
+ bool checkcollide(XYZ startpoint, XYZ endpoint, int which);
+ bool onfire[max_objects];
+ float flamedelay[max_objects];
+
+ void SphereCheckPossible(XYZ *p1, float radius);
+ void DeleteObject(int which);
+ void MakeObject(int atype, XYZ where, float ayaw, float ascale);
+ void MakeObject(int atype, XYZ where, float ayaw, float apitch, float ascale);
+ void Draw();
+ void DoShadows();
+ void DoStuff();
+
+ Objects();
+ ~Objects();
+};
+
+#endif
+
--- /dev/null
+/*
+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 "Animation/Animation.h"
+#include "Audio/openal_wrapper.h"
+#include "Audio/Sounds.h"
+#include "Level/Awards.h"
+#include "Level/Dialog.h"
+#include "Objects/Person.h"
+#include "Utils/Folders.h"
+
+#include "Game.h"
+
+extern float multiplier;
+extern Terrain terrain;
+extern float gravity;
+extern int environment;
+extern int detail;
+extern FRUSTUM frustum;
+extern XYZ viewer;
+extern float realmultiplier;
+extern int slomo;
+extern float slomodelay;
+extern bool cellophane;
+extern float texdetail;
+extern float realtexdetail;
+extern GLubyte bloodText[512 * 512 * 3];
+extern GLubyte wolfbloodText[512 * 512 * 3];
+extern int bloodtoggle;
+extern Objects objects;
+extern bool autoslomo;
+extern float camerashake;
+extern float woozy;
+extern float viewdistance;
+extern float blackout;
+extern int difficulty;
+extern bool decals;
+extern float fadestart;
+extern bool freeze;
+extern bool winfreeze;
+extern bool showpoints;
+extern bool immediate;
+extern int tutoriallevel;
+extern float smoketex;
+extern int tutorialstage;
+extern bool reversaltrain;
+extern bool canattack;
+extern bool cananger;
+extern float damagedealt;
+extern int hostile;
+extern float hostiletime;
+
+extern bool gamestarted;
+
+std::vector<std::shared_ptr<Person>> Person::players(1, std::shared_ptr<Person>(new Person()));
+
+Person::Person() :
+ whichpatchx(0),
+ whichpatchz(0),
+ animCurrent(bounceidleanim),
+ animTarget(bounceidleanim),
+ frameCurrent(0),
+ frameTarget(1),
+ oldanimCurrent(0),
+ oldanimTarget(0),
+ oldframeCurrent(0),
+ oldframeTarget(0),
+ howactive(typeactive),
+ parriedrecently(0),
+ superruntoggle(false),
+ lastattack(0), lastattack2(0), lastattack3(0),
+ currentoffset(), targetoffset(), offset(),
+ target(0),
+ transspeed(0),
+
+ realoldcoords(),
+ oldcoords(),
+ coords(),
+ velocity(),
+
+ proportionhead(),
+ proportionlegs(),
+ proportionarms(),
+ proportionbody(),
+
+ unconscioustime(0),
+
+ immobile(false),
+
+ velspeed(0),
+ targetyaw(0),
+ targetrot(0),
+ rot(0),
+ oldrot(0),
+ lookyaw(0),
+ lookpitch(0),
+ yaw(0),
+ pitch(0),
+ lowyaw(0),
+ tilt(0),
+ targettilt(0),
+ tilt2(0),
+ targettilt2(0),
+ rabbitkickenabled(false),
+
+ bloodloss(0),
+ bleeddelay(0),
+ skiddelay(0),
+ skiddingdelay(0),
+ deathbleeding(0),
+ tempdeltav(0),
+
+ damagetolerance(200),
+ damage(0),
+ permanentdamage(0),
+ superpermanentdamage(0),
+ lastcollide(0),
+ dead(0),
+
+ jumppower(5),
+ onground(false),
+
+ wentforweapon(0),
+
+ calcrot(false),
+
+ facing(),
+
+ bleeding(0),
+ bleedx(0), bleedy(0),
+ direction(0),
+ texupdatedelay(0),
+
+ headyaw(0), headpitch(0),
+ targetheadyaw(0), targetheadpitch(0),
+
+ onterrain(false),
+ pause(false),
+
+ grabdelay(0),
+
+ victim(nullptr),
+ hasvictim(false),
+
+ updatedelay(0),
+ normalsupdatedelay(0),
+
+ jumpstart(false),
+ forwardkeydown(false),
+ forwardstogglekeydown(false),
+ rightkeydown(false),
+ leftkeydown(false),
+ backkeydown(false),
+ jumpkeydown(false),
+ jumptogglekeydown(false),
+ crouchkeydown(false),
+ crouchtogglekeydown(false),
+ drawkeydown(false),
+ drawtogglekeydown(false),
+ throwkeydown(false),
+ throwtogglekeydown(false),
+ attackkeydown(false),
+ feint(false),
+ lastfeint(false),
+ headless(false),
+
+ crouchkeydowntime(0),
+ jumpkeydowntime(0),
+ freefall(false),
+
+ turnspeed(0),
+
+ aitype(passivetype),
+ aiupdatedelay(0),
+ losupdatedelay(0),
+ ally(0),
+ collide(0),
+ collided(-10),
+ avoidcollided(0),
+ loaded(false),
+ whichdirection(false),
+ whichdirectiondelay(0),
+ avoidsomething(false),
+ avoidwhere(),
+ blooddimamount(0),
+
+ staggerdelay(0),
+ blinkdelay(0),
+ twitchdelay(0),
+ twitchdelay2(0),
+ twitchdelay3(0),
+ lefthandmorphness(0),
+ righthandmorphness(0),
+ headmorphness(0),
+ chestmorphness(0),
+ tailmorphness(0),
+ targetlefthandmorphness(0),
+ targetrighthandmorphness(0),
+ targetheadmorphness(1),
+ targetchestmorphness(0),
+ targettailmorphness(0),
+ lefthandmorphstart(0), lefthandmorphend(0),
+ righthandmorphstart(0), righthandmorphend(0),
+ headmorphstart(0), headmorphend(0),
+ chestmorphstart(0), chestmorphend(0),
+ tailmorphstart(0), tailmorphend(0),
+
+ weaponmissdelay(0),
+ highreversaldelay(0),
+ lowreversaldelay(0),
+
+ creature(rabbittype),
+
+ id(0),
+
+ skeleton(),
+
+ speed(0),
+ scale(-1),
+ power(0),
+ speedmult(0),
+
+ protectionhead(0),
+ protectionhigh(0),
+ protectionlow(0),
+ armorhead(0),
+ armorhigh(0),
+ armorlow(0),
+ metalhead(false),
+ metalhigh(false),
+ metallow(false),
+
+ numclothes(0),
+
+ landhard(false),
+ bled(false),
+ spurt(false),
+ onfire(false),
+ onfiredelay(0),
+ burnt(0),
+
+ flamedelay(0),
+
+ playerdetail(0),
+
+ num_weapons(0),
+ weaponactive(-1),
+ weaponstuck(-1),
+ weaponstuckwhere(0),
+
+ numwaypoints(0),
+ pausetime(0),
+
+ headtarget(),
+ interestdelay(0),
+
+ finalfinaltarget(),
+ finaltarget(),
+ finalpathfindpoint(0),
+ targetpathfindpoint(0),
+ lastpathfindpoint(0),
+ lastpathfindpoint2(0),
+ lastpathfindpoint3(0),
+ lastpathfindpoint4(0),
+
+ waypoint(0),
+
+ lastseen(),
+ lastseentime(0),
+ lastchecktime(0),
+ stunned(0),
+ surprised(0),
+ runninghowlong(0),
+ occluded(0),
+ lastoccluded(0),
+ laststanding(0),
+ escapednum(0),
+
+ speechdelay(0),
+ neckspurtdelay(0),
+ neckspurtparticledelay(0),
+ neckspurtamount(0),
+
+ whichskin(0),
+ rabbitkickragdoll(false),
+
+ tempanimation(),
+
+ jumpclimb(false)
+{
+}
+
+/* Read a person in tfile. Throws an error if it’s not valid */
+Person::Person(FILE *tfile, int mapvers, unsigned i) : Person()
+{
+ id = i;
+ funpackf(tfile, "Bi Bi Bf Bf Bf Bi", &whichskin, &creature, &coords.x, &coords.y, &coords.z, &num_weapons);
+ if (mapvers >= 5) {
+ funpackf(tfile, "Bi", &howactive);
+ } else {
+ howactive = typeactive;
+ }
+ if (mapvers >= 3) {
+ funpackf(tfile, "Bf", &scale);
+ } else {
+ scale = -1;
+ }
+ if (mapvers >= 11) {
+ funpackf(tfile, "Bb", &immobile);
+ } else {
+ immobile = 0;
+ }
+ if (mapvers >= 12) {
+ funpackf(tfile, "Bf", &yaw);
+ } else {
+ yaw = 0;
+ }
+ targetyaw = yaw;
+ if (num_weapons < 0 || num_weapons > 5) {
+ throw InvalidPersonException();
+ }
+ if (num_weapons > 0 && num_weapons < 5) {
+ for (int j = 0; j < num_weapons; j++) {
+ weaponids[j] = weapons.size();
+ int type;
+ funpackf(tfile, "Bi", &type);
+ weapons.push_back(Weapon(type, id));
+ }
+ }
+ funpackf(tfile, "Bi", &numwaypoints);
+ for (int j = 0; j < numwaypoints; j++) {
+ funpackf(tfile, "Bf", &waypoints[j].x);
+ funpackf(tfile, "Bf", &waypoints[j].y);
+ funpackf(tfile, "Bf", &waypoints[j].z);
+ if (mapvers >= 5) {
+ funpackf(tfile, "Bi", &waypointtype[j]);
+ } else {
+ waypointtype[j] = wpkeepwalking;
+ }
+ }
+
+ funpackf(tfile, "Bi", &waypoint);
+ if (waypoint > (numwaypoints - 1)) {
+ waypoint = 0;
+ }
+
+ funpackf(tfile, "Bf Bf Bf", &armorhead, &armorhigh, &armorlow);
+ funpackf(tfile, "Bf Bf Bf", &protectionhead, &protectionhigh, &protectionlow);
+ funpackf(tfile, "Bf Bf Bf", &metalhead, &metalhigh, &metallow);
+ funpackf(tfile, "Bf Bf", &power, &speedmult);
+
+ float headprop, legprop, armprop, bodyprop;
+
+ if (mapvers >= 4) {
+ funpackf(tfile, "Bf Bf Bf Bf", &headprop, &bodyprop, &armprop, &legprop);
+ } else {
+ headprop = 1;
+ bodyprop = 1;
+ armprop = 1;
+ legprop = 1;
+ }
+
+ if (creature == wolftype) {
+ proportionhead = 1.1 * headprop;
+ proportionbody = 1.1 * bodyprop;
+ proportionarms = 1.1 * armprop;
+ proportionlegs = 1.1 * legprop;
+ } else if (creature == rabbittype) {
+ proportionhead = 1.2 * headprop;
+ proportionbody = 1.05 * bodyprop;
+ proportionarms = 1.00 * armprop;
+ proportionlegs = 1.1 * legprop;
+ proportionlegs.y = 1.05 * legprop;
+ }
+
+ funpackf(tfile, "Bi", &numclothes);
+ for (int k = 0; k < numclothes; k++) {
+ int templength;
+ funpackf(tfile, "Bi", &templength);
+ for (int l = 0; l < templength; l++)
+ funpackf(tfile, "Bb", &clothes[k][l]);
+ clothes[k][templength] = '\0';
+ funpackf(tfile, "Bf Bf Bf", &clothestintr[k], &clothestintg[k], &clothestintb[k]);
+ }
+
+ loaded = true;
+
+ if (scale < 0) {
+ if (creature == wolftype) {
+ scale = .23;
+ damagetolerance = 300;
+ } else {
+ scale = .2;
+ }
+ }
+
+ oldcoords = coords;
+ realoldcoords = coords;
+}
+
+void Person::skeletonLoad(bool clothes)
+{
+ skeleton.id = id;
+ if (creature != wolftype) {
+ skeleton.Load(
+ "Skeleton/BasicFigure",
+ "Skeleton/BasicFigureLow",
+ "Skeleton/RabbitBelt",
+ "Models/Body.solid",
+ "Models/Body2.solid",
+ "Models/Body3.solid",
+ "Models/Body4.solid",
+ "Models/Body5.solid",
+ "Models/Body6.solid",
+ "Models/Body7.solid",
+ "Models/BodyLow.solid",
+ "Models/Belt.solid",
+ clothes
+ );
+ } else {
+ skeleton.Load(
+ "Skeleton/BasicFigureWolf",
+ "Skeleton/BasicFigureWolfLow",
+ "Skeleton/RabbitBelt",
+ "Models/Wolf.solid",
+ "Models/Wolf2.solid",
+ "Models/Wolf3.solid",
+ "Models/Wolf4.solid",
+ "Models/Wolf5.solid",
+ "Models/Wolf6.solid",
+ "Models/Wolf7.solid",
+ "Models/WolfLow.solid",
+ "Models/Belt.solid",
+ clothes
+ );
+ }
+
+ skeleton.drawmodel.textureptr.load(creatureskin[creature][whichskin], 1, &skeleton.skinText[0], &skeleton.skinsize);
+}
+
+/* EFFECT
+ *
+ * USES:
+ * GameTick/doPlayerCollisions
+ */
+void Person::CheckKick()
+{
+ if (!(hasvictim
+ && (animTarget == rabbitkickanim
+ && victim
+ && victim != this->shared_from_this()
+ && frameCurrent >= 2
+ && animCurrent == rabbitkickanim)
+ && distsq(&coords, &victim->coords) < 1.2
+ && !victim->skeleton.free))
+ return;
+
+ if (Animation::animations[victim->animTarget].height != lowheight) {
+ float damagemult = (creature == wolftype ? 2.5 : 1.) * power * power;
+ XYZ relative = velocity;
+ relative.y = 0;
+ Normalise(&relative);
+
+ victim->spurt = 1;
+ DoBlood(.2, 250);
+ if (tutoriallevel != 1)
+ emit_sound_at(heavyimpactsound, victim->coords);
+ victim->RagDoll(0);
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velocity += relative * 120 * damagemult;
+ }
+ victim->Puff(neck);
+ victim->DoDamage(100 * damagemult / victim->protectionhigh);
+ if (id == 0)
+ camerashake += .4;
+
+ target = 0;
+ frameCurrent = 3;
+ animTarget = backflipanim;
+ frameTarget = 4;
+ velocity = facing * -10;
+ velocity.y = 5;
+ skeleton.free = 0;
+ if (id == 0)
+ resume_stream(whooshsound);
+
+ award_bonus(id, cannon);
+ } else if (victim->isCrouch()) {
+ animTarget = rabbitkickreversedanim;
+ animCurrent = rabbitkickreversedanim;
+ victim->animCurrent = rabbitkickreversalanim;
+ victim->animTarget = rabbitkickreversalanim;
+ targettilt2 = 0;
+ frameCurrent = 0;
+ frameTarget = 1;
+ target = 0;
+ velocity = 0;
+ victim->oldcoords = victim->coords;
+ coords = victim->coords;
+ victim->targetyaw = targetyaw;
+ victim->victim = this->shared_from_this();
+ }
+}
+
+/* EFFECT
+ *
+ * USES:
+ * GameTick/doPlayerCollisions - spread fire between players
+ * GameTick/doDevKeys - press f to ignite
+ * Person::DoStuff - spread fire from lit campfires and bushes
+ */
+void Person::CatchFire()
+{
+ XYZ flatfacing, flatvelocity;
+ int howmany;
+ for (int i = 0; i < 10; i++) {
+ howmany = abs(Random() % (skeleton.joints.size()));
+ if (skeleton.free) {
+ flatvelocity = skeleton.joints[howmany].velocity;
+ flatfacing = skeleton.joints[howmany].position * scale + coords;
+ } else {
+ flatvelocity = velocity;
+ flatfacing = DoRotation(DoRotation(DoRotation(skeleton.joints[howmany].position, 0, 0, tilt), tilt2, 0, 0), 0, yaw, 0) * scale + coords;
+ }
+ Sprite::MakeSprite(flamesprite, flatfacing, flatvelocity, 1, 1, 1, 2, 1);
+ }
+
+ onfiredelay = 0.5;
+
+ emit_sound_at(firestartsound, coords);
+
+ emit_stream_at(stream_firesound, coords);
+
+ flamedelay = 0;
+
+ onfire = 1;
+}
+
+/* FUNCTION
+ * idle animation for this creature (depending on status)
+ */
+int Person::getIdle()
+{
+ if (Dialog::inDialog() && (howactive == typeactive) && (creature == rabbittype))
+ return talkidleanim;
+ if (hasvictim && (victim != this->shared_from_this())/*||(id==0&&attackkeydown)*/)
+ if (/*(id==0&&attackkeydown)||*/(!victim->dead && victim->aitype != passivetype &&
+ victim->aitype != searchtype && aitype != passivetype && aitype != searchtype &&
+ victim->id < Person::players.size())) {
+ if ((aitype == playercontrolled && stunned <= 0 && weaponactive == -1) || pause) {
+ if (creature == rabbittype)
+ return fightidleanim;
+ if (creature == wolftype)
+ return wolfidle;
+ }
+ if (aitype == playercontrolled && stunned <= 0 && weaponactive != -1) {
+ if (weapons[weaponids[weaponactive]].getType() == knife)
+ return knifefightidleanim;
+ if (weapons[weaponids[weaponactive]].getType() == sword && victim->weaponactive != -1)
+ return swordfightidlebothanim;
+ if (weapons[weaponids[weaponactive]].getType() == sword)
+ return swordfightidleanim;
+ if (weapons[weaponids[weaponactive]].getType() == staff)
+ return swordfightidleanim;
+ }
+ if (aitype != playercontrolled && stunned <= 0 && creature != wolftype && !pause)
+ return fightsidestep;
+ }
+ if ((damage > permanentdamage || damage > damagetolerance * .8 || deathbleeding > 0) && creature != wolftype)
+ return hurtidleanim;
+ if (howactive == typesitting) return sitanim;
+ if (howactive == typesittingwall) return sitwallanim;
+ if (howactive == typesleeping) return sleepanim;
+ if (howactive == typedead1) return dead1anim;
+ if (howactive == typedead2) return dead2anim;
+ if (howactive == typedead3) return dead3anim;
+ if (howactive == typedead4) return dead4anim;
+ if (creature == rabbittype) return bounceidleanim;
+ if (creature == wolftype) return wolfidle;
+ return 0;
+}
+
+/* FUNCTION
+ * crouch animation for this creature
+ */
+int Person::getCrouch()
+{
+ if (creature == rabbittype)
+ return crouchanim;
+ if (creature == wolftype)
+ return wolfcrouchanim;
+ return 0;
+}
+
+/* FUNCTION
+ * running animation for this creature (can be upright or all fours)
+ */
+int Person::getRun()
+{
+ if (creature == rabbittype && (!superruntoggle || weaponactive != -1))
+ return runanim;
+ if (creature == wolftype && (!superruntoggle))
+ return wolfrunanim;
+
+ if (creature == rabbittype && (superruntoggle && weaponactive == -1))
+ return rabbitrunninganim;
+ if (creature == wolftype && (superruntoggle))
+ return wolfrunninganim;
+ return 0;
+}
+
+/* FUNCTION
+ */
+int Person::getStop()
+{
+ if (creature == rabbittype)
+ return stopanim;
+ if (creature == wolftype)
+ return wolfstopanim;
+ return 0;
+}
+
+/* FUNCTION
+ */
+int Person::getLanding()
+{
+ if (creature == rabbittype)
+ return landanim;
+ if (creature == wolftype)
+ return wolflandanim;
+ return 0;
+}
+
+/* FUNCTION
+ */
+int Person::getLandhard()
+{
+ if (creature == rabbittype)
+ return landhardanim;
+ if (creature == wolftype)
+ return wolflandhardanim;
+ return 0;
+}
+
+/* EFFECT
+ *
+ * USES:
+ * Person::DoAnimations
+ */
+static void
+SolidHitBonus(int playerid)
+{
+ if (bonustime < 1.5 && bonus >= solidhit && bonus <= megacombo)
+ award_bonus(playerid, bonus == megacombo ? bonus : bonus + 1);
+ else
+ award_bonus(playerid, solidhit);
+}
+
+/* EFFECT
+ * spawns blood effects
+ */
+void Person::DoBlood(float howmuch, int which)
+{
+ // FIXME: should abstract out inputs
+ static int bleedxint, bleedyint;
+ static XYZ bloodvel;
+ if (bloodtoggle && tutoriallevel != 1) {
+ if (bleeding <= 0 && spurt) {
+ spurt = 0;
+ for (int i = 0; i < 3; i++) {
+ // emit blood particles
+ bloodvel = 0;
+ if (skeleton.free) {
+ bloodvel -= DoRotation(skeleton.forward * 10 * scale, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0);
+ bloodvel += DoRotation(jointVel(head), ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
+ Sprite::MakeSprite(bloodsprite, jointPos(head) * scale + coords, bloodvel, 1, 1, 1, .05, 1);
+ Sprite::MakeSprite(bloodflamesprite, jointPos(head) * scale + coords, bloodvel, 1, 1, 1, .3, 1);
+ } else {
+ bloodvel.z = 10;
+ bloodvel = DoRotation(bloodvel, ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
+ bloodvel += DoRotation(velocity, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0) * scale;
+ Sprite::MakeSprite(bloodsprite, DoRotation((jointPos(head) + jointPos(neck)) / 2, 0, yaw, 0)*scale + coords, bloodvel, 1, 1, 1, .05, 1);
+ Sprite::MakeSprite(bloodflamesprite, DoRotation((jointPos(head) + jointPos(neck)) / 2, 0, yaw, 0)*scale + coords, bloodvel, 1, 1, 1, .3, 1);
+ }
+ }
+ if (Random() % 2 == 0) // 50% chance
+ for (int i = 0; i < 3; i++) {
+ if (Random() % 2 != 0) {
+ // emit teeth particles
+ bloodvel = 0;
+ if (skeleton.free) {
+ bloodvel -= DoRotation(skeleton.forward * 10 * scale, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0);
+ bloodvel += DoRotation(jointVel(head), ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
+ } else {
+ bloodvel.z = 10;
+ bloodvel = DoRotation(bloodvel, ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
+ bloodvel += DoRotation(velocity, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0) * scale;
+ }
+ bloodvel *= .2;
+ if (skeleton.free) {
+ Sprite::MakeSprite(splintersprite, jointPos(head) * scale + coords, bloodvel, 1, 1, 1, .05, 1);
+ } else {
+ Sprite::MakeSprite(splintersprite, DoRotation((jointPos(head) + jointPos(neck)) / 2, 0, yaw, 0)*scale + coords, bloodvel, 1, 1, 1, .05, 1);
+ }
+ Sprite::setLastSpriteSpecial(3); // sets it to teeth
+ }
+ }
+ }
+ if (decals) {
+ // FIXME: manipulating attributes
+ bleeding = howmuch + (float)abs(Random() % 100) / 200 - .25;
+ bleedxint = 0;
+ bleedyint = 0;
+ if (creature == rabbittype)
+ while (bloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] > which + 4 || bloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] < which - 4 || bleedxint < 10 || bleedyint < 10 || bleedxint > 500 || bleedyint > 500) {
+ bleedxint = abs(Random() % 512);
+ bleedyint = abs(Random() % 512);
+ }
+ if (creature == wolftype)
+ while (wolfbloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] > which + 4 || wolfbloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] < which - 4 || bleedxint < 10 || bleedyint < 10 || bleedxint > 500 || bleedyint > 500) {
+ bleedxint = abs(Random() % 512);
+ bleedyint = abs(Random() % 512);
+ }
+ bleedy = bleedxint;
+ bleedx = bleedyint;
+ bleedy /= realtexdetail;
+ bleedx /= realtexdetail;
+ direction = abs(Random() % 2) * 2 - 1;
+ }
+
+ }
+ if (bleeding > 2)
+ bleeding = 2;
+}
+
+/* EFFECT
+ * spawns big blood effects and ???
+ * modifies character's skin texture
+ */
+void Person::DoBloodBig(float howmuch, int which)
+{
+ static int bleedxint, bleedyint, i, j;
+ static XYZ bloodvel;
+ if (howmuch && id == 0)
+ blooddimamount = 1;
+
+ if (tutoriallevel != 1 || id == 0)
+ if (aitype != playercontrolled && howmuch > 0) {
+ // play pain sounds
+ int whichsound = -1;
+
+ if (creature == wolftype) {
+ int i = abs(Random() % 2);
+ if (i == 0)
+ whichsound = snarlsound;
+ if (i == 1)
+ whichsound = snarl2sound;
+ }
+ if (creature == rabbittype) {
+ int i = abs(Random() % 2);
+ if (i == 0)
+ whichsound = rabbitpainsound;
+ if (i == 1 && howmuch >= 2)
+ whichsound = rabbitpain1sound;
+ }
+
+ if (whichsound != -1) {
+ emit_sound_at(whichsound, coords);
+ addEnvSound(coords);
+ }
+ }
+
+ if (id == 0 && howmuch > 0) {
+ Game::flash(.5, 0);
+ }
+
+ if (bloodtoggle && decals && tutoriallevel != 1) {
+ if (bleeding <= 0 && spurt) {
+ spurt = 0;
+ for (int i = 0; i < 3; i++) {
+ // emit blood particles
+ // FIXME: copypaste from above
+ bloodvel = 0;
+ if (skeleton.free) {
+ bloodvel -= DoRotation(skeleton.forward * 10 * scale, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0);
+ bloodvel += DoRotation(jointVel(head), ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
+ Sprite::MakeSprite(bloodsprite, jointPos(head) * scale + coords, bloodvel, 1, 1, 1, .05, 1);
+ Sprite::MakeSprite(bloodflamesprite, jointPos(head) * scale + coords, bloodvel, 1, 1, 1, .3, 1);
+ } else {
+ bloodvel.z = 10;
+ bloodvel = DoRotation(bloodvel, ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
+ bloodvel += DoRotation(velocity, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0) * scale;
+ Sprite::MakeSprite(bloodsprite, DoRotation((jointPos(head) + jointPos(neck)) / 2, 0, yaw, 0)*scale + coords, bloodvel, 1, 1, 1, .05, 1);
+ Sprite::MakeSprite(bloodflamesprite, DoRotation((jointPos(head) + jointPos(neck)) / 2, 0, yaw, 0)*scale + coords, bloodvel, 1, 1, 1, .3, 1);
+ }
+ }
+ }
+
+ // weird texture manipulation code follows.
+ // looks like this is painting blood onto the character's skin texture
+ // FIXME: surely there's a better way
+
+ int offsetx = 0, offsety = 0;
+ if (which == 225) {
+ offsety = Random() % 40;
+ offsetx = abs(Random() % 60);
+ }
+ if (which == 190 || which == 185) {
+ offsety = Random() % 40;
+ offsetx = abs(Random() % 100) - 20;
+ }
+ if (which == 175) {
+ offsety = Random() % 10;
+ offsetx = Random() % 10;
+ }
+ if (which == 170) {
+ offsety = Random() % 20;
+ offsetx = Random() % 20;
+ }
+ if (which == 220 || which == 215) {
+ offsetx = 20;
+ }
+
+
+ int startx = 512;
+ int starty = 512;
+ int endx = 0;
+ int endy = 0;
+ GLubyte color;
+ if (creature == rabbittype)
+ for (i = 0; i < 512; i++) {
+ for (j = 0; j < 512; j++) {
+ if (bloodText[i * 512 * 3 + j * 3 + 0] <= which + 4 && bloodText[i * 512 * 3 + j * 3 + 0] >= which - 4) {
+ if (i < startx) startx = i;
+ if (j < starty) starty = j;
+ if (i > endx) endx = i;
+ if (j > endy) endy = j;
+ }
+ }
+ }
+ if (creature == wolftype)
+ for (i = 0; i < 512; i++) {
+ for (j = 0; j < 512; j++) {
+ if (wolfbloodText[i * 512 * 3 + j * 3 + 0] <= which + 4 && wolfbloodText[i * 512 * 3 + j * 3 + 0] >= which - 4) {
+ if (i < startx) startx = i;
+ if (j < starty) starty = j;
+ if (i > endx) endx = i;
+ if (j > endy) endy = j;
+ }
+ }
+ }
+
+ startx += offsetx;
+ endx += offsetx;
+ starty += offsety;
+ endy += offsety;
+
+ if (startx < 0) startx = 0;
+ if (starty < 0) starty = 0;
+ if (endx > 512 - 1) endx = 512 - 1;
+ if (endy > 512 - 1) endy = 512 - 1;
+ if (endx < startx) endx = startx;
+ if (endy < starty) endy = starty;
+
+ startx /= realtexdetail;
+ starty /= realtexdetail;
+ endx /= realtexdetail;
+ endy /= realtexdetail;
+
+ int texdetailint = realtexdetail;
+ int where;
+ if (creature == rabbittype)
+ for (i = startx; i < endx; i++) {
+ for (j = starty; j < endy; j++) {
+ if (bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] <= which + 4 && bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] >= which - 4) {
+ color = Random() % 85 + 170;
+ where = i * skeleton.skinsize * 3 + j * 3;
+ if (skeleton.skinText[where + 0] > color / 2)
+ skeleton.skinText[where + 0] = color / 2;
+ skeleton.skinText[where + 1] = 0;
+ skeleton.skinText[where + 2] = 0;
+ }
+ }
+ }
+ if (creature == wolftype)
+ for (i = startx; i < endx; i++) {
+ for (j = starty; j < endy; j++) {
+ if (wolfbloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] <= which + 4 && wolfbloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] >= which - 4) {
+ color = Random() % 85 + 170;
+ where = i * skeleton.skinsize * 3 + j * 3;
+ if (skeleton.skinText[where + 0] > color / 2)
+ skeleton.skinText[where + 0] = color / 2;
+ skeleton.skinText[where + 1] = 0;
+ skeleton.skinText[where + 2] = 0;
+ }
+ }
+ }
+ skeleton.drawmodel.textureptr.bind();
+ DoMipmaps();
+
+ bleedxint = 0;
+ bleedyint = 0;
+ if (creature == rabbittype)
+ while (bloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] > which + 4 || bloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] < which - 4 || bleedxint < 10 || bleedyint < 10 || bleedxint > 500 || bleedyint > 500) {
+ bleedxint = abs(Random() % 512);
+ bleedyint = abs(Random() % 512);
+ }
+ if (creature == wolftype)
+ while (wolfbloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] > which + 4 || wolfbloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] < which - 4 || bleedxint < 10 || bleedyint < 10 || bleedxint > 500 || bleedyint > 500) {
+ bleedxint = abs(Random() % 512);
+ bleedyint = abs(Random() % 512);
+ }
+ bleedy = bleedxint + offsetx;
+ bleedx = bleedyint + offsety;
+ bleedy /= realtexdetail;
+ bleedx /= realtexdetail;
+ if (bleedx < 0)
+ bleedx = 0;
+ if (bleedy < 0)
+ bleedy = 0;
+ if (bleedx > skeleton.skinsize - 1)
+ bleedx = skeleton.skinsize - 1;
+ if (bleedy > skeleton.skinsize - 1)
+ bleedy = skeleton.skinsize - 1;
+ direction = abs(Random() % 2) * 2 - 1;
+
+ }
+ bleeding = howmuch + (float)abs(Random() % 100) / 200 - .25;
+ deathbleeding += bleeding;
+ bloodloss += bleeding * 3;
+
+ if (tutoriallevel != 1 && aitype != playercontrolled && bloodloss > damagetolerance * 2 / 3 && bloodloss < damagetolerance && creature == rabbittype) {
+ if (abs(Random() % 2) == 0) {
+ aitype = gethelptype;
+ lastseentime = 12;
+ } else
+ aitype = attacktypecutoff;
+ ally = 0;
+ }
+ if (bleeding > 2)
+ bleeding = 2;
+}
+
+/* EFFECT
+ * similar to DoBloodBig
+ */
+bool Person::DoBloodBigWhere(float howmuch, int which, XYZ where)
+{
+ static int i, j;
+ static XYZ bloodvel;
+ static XYZ startpoint, endpoint, colpoint, movepoint;
+ static float rotationpoint;
+ static int whichtri;
+ static XYZ p1, p2, p3, p0;
+ XYZ bary;
+ XYZ gxx, gyy;
+ float coordsx, coordsy;
+ float total;
+
+ if (bloodtoggle && decals && tutoriallevel != 1) {
+ where -= coords;
+ if (!skeleton.free)
+ where = DoRotation(where, 0, -yaw, 0);
+ //where=scale;
+ startpoint = where;
+ startpoint.y += 100;
+ endpoint = where;
+ endpoint.y -= 100;
+ movepoint = 0;
+ rotationpoint = 0;
+ // ray testing for a tri in the character model
+ whichtri = skeleton.drawmodel.LineCheck(&startpoint, &endpoint, &colpoint, &movepoint, &rotationpoint);
+ if (whichtri != -1) {
+ // low level geometry math
+ p0 = colpoint;
+ p1 = skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[whichtri].vertex[0]];
+ p2 = skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[whichtri].vertex[1]];
+ p3 = skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[whichtri].vertex[2]];
+
+ bary.x = distsq(&p0, &p1);
+ bary.y = distsq(&p0, &p2);
+ bary.z = distsq(&p0, &p3);
+
+ total = bary.x + bary.y + bary.z;
+ bary.x /= total;
+ bary.y /= total;
+ bary.z /= total;
+
+ bary.x = 1 - bary.x;
+ bary.y = 1 - bary.y;
+ bary.z = 1 - bary.z;
+
+ total = bary.x + bary.y + bary.z;
+ bary.x /= total;
+ bary.y /= total;
+ bary.z /= total;
+
+
+ gxx.x = skeleton.drawmodel.Triangles[whichtri].gx[0];
+ gxx.y = skeleton.drawmodel.Triangles[whichtri].gx[1];
+ gxx.z = skeleton.drawmodel.Triangles[whichtri].gx[2];
+ gyy.x = skeleton.drawmodel.Triangles[whichtri].gy[0];
+ gyy.y = skeleton.drawmodel.Triangles[whichtri].gy[1];
+ gyy.z = skeleton.drawmodel.Triangles[whichtri].gy[2];
+ coordsx = skeleton.drawmodel.Triangles[whichtri].gx[0] * bary.x + skeleton.drawmodel.Triangles[whichtri].gx[1] * bary.y + skeleton.drawmodel.Triangles[whichtri].gx[2] * bary.z;
+ coordsy = skeleton.drawmodel.Triangles[whichtri].gy[0] * bary.x + skeleton.drawmodel.Triangles[whichtri].gy[1] * bary.y + skeleton.drawmodel.Triangles[whichtri].gy[2] * bary.z;
+
+ if (bleeding <= 0 && spurt) {
+ spurt = 0;
+ for (int i = 0; i < 3; i++) {
+ // emit blood particles
+ // FIXME: more copypaste code
+ bloodvel = 0;
+ if (skeleton.free) {
+ bloodvel -= DoRotation(skeleton.forward * 10 * scale, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0);
+ bloodvel += DoRotation(jointVel(head), ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
+ Sprite::MakeSprite(bloodsprite, jointPos(head) * scale + coords, bloodvel, 1, 1, 1, .05, 1);
+ Sprite::MakeSprite(bloodflamesprite, jointPos(head) * scale + coords, bloodvel, 1, 1, 1, .3, 1);
+ } else {
+ bloodvel.z = 10;
+ bloodvel = DoRotation(bloodvel, ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
+ bloodvel += DoRotation(velocity, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0) * scale;
+ Sprite::MakeSprite(bloodsprite, DoRotation((jointPos(head) + jointPos(neck)) / 2, 0, yaw, 0)*scale + coords, bloodvel, 1, 1, 1, .05, 1);
+ Sprite::MakeSprite(bloodflamesprite, DoRotation((jointPos(head) + jointPos(neck)) / 2, 0, yaw, 0)*scale + coords, bloodvel, 1, 1, 1, .3, 1);
+ }
+ }
+ }
+
+ // texture manipulation follows
+
+ int offsetx = 0, offsety = 0;
+ offsetx = (1 + coordsy) * 512 - 291;
+ offsety = coordsx * 512 - 437;
+
+ int startx = 512;
+ int starty = 512;
+ int endx = 0;
+ int endy = 0;
+ GLubyte color;
+ if (creature == rabbittype)
+ for (i = 0; i < 512; i++) {
+ for (j = 0; j < 512; j++) {
+ if (bloodText[i * 512 * 3 + j * 3 + 0] <= which + 4 && bloodText[i * 512 * 3 + j * 3 + 0] >= which - 4) {
+ if (i < startx) startx = i;
+ if (j < starty) starty = j;
+ if (i > endx) endx = i;
+ if (j > endy) endy = j;
+ }
+ }
+ }
+ if (creature == wolftype)
+ for (i = 0; i < 512; i++) {
+ for (j = 0; j < 512; j++) {
+ if (wolfbloodText[i * 512 * 3 + j * 3 + 0] <= which + 4 && wolfbloodText[i * 512 * 3 + j * 3 + 0] >= which - 4) {
+ if (i < startx) startx = i;
+ if (j < starty) starty = j;
+ if (i > endx) endx = i;
+ if (j > endy) endy = j;
+ }
+ }
+ }
+ startx += offsetx;
+ endx += offsetx;
+ starty += offsety;
+ endy += offsety;
+
+ if (startx < 0) startx = 0;
+ if (starty < 0) starty = 0;
+ if (endx > 512 - 1) endx = 512 - 1;
+ if (endy > 512 - 1) endy = 512 - 1;
+ if (endx < startx) endx = startx;
+ if (endy < starty) endy = starty;
+
+ startx /= realtexdetail;
+ starty /= realtexdetail;
+ endx /= realtexdetail;
+ endy /= realtexdetail;
+
+ int texdetailint = realtexdetail;
+ int where;
+ if (creature == rabbittype)
+ for (i = startx; i < endx; i++) {
+ for (j = starty; j < endy; j++) {
+ if (bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] <= which + 4 && bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] >= which - 4) {
+ color = Random() % 85 + 170;
+ where = i * skeleton.skinsize * 3 + j * 3;
+ if (skeleton.skinText[where + 0] > color / 2)
+ skeleton.skinText[where + 0] = color / 2;
+ skeleton.skinText[where + 1] = 0;
+ skeleton.skinText[where + 2] = 0;
+ } else if (bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] <= 160 + 4 && bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] >= 160 - 4) {
+ color = Random() % 85 + 170;
+ where = i * skeleton.skinsize * 3 + j * 3;
+ if (skeleton.skinText[where + 0] > color / 2)
+ skeleton.skinText[where + 0] = color / 2;
+ skeleton.skinText[where + 1] = 0;
+ skeleton.skinText[where + 2] = 0;
+ }
+ }
+ }
+ if (creature == wolftype)
+ for (i = startx; i < endx; i++) {
+ for (j = starty; j < endy; j++) {
+ if (wolfbloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] <= which + 4 && wolfbloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] >= which - 4) {
+ color = Random() % 85 + 170;
+ where = i * skeleton.skinsize * 3 + j * 3;
+ if (skeleton.skinText[where + 0] > color / 2)
+ skeleton.skinText[where + 0] = color / 2;
+ skeleton.skinText[where + 1] = 0;
+ skeleton.skinText[where + 2] = 0;
+ } else if (wolfbloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] <= 160 + 4 && wolfbloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] >= 160 - 4) {
+ color = Random() % 85 + 170;
+ where = i * skeleton.skinsize * 3 + j * 3;
+ if (skeleton.skinText[where + 0] > color / 2)
+ skeleton.skinText[where + 0] = color / 2;
+ skeleton.skinText[where + 1] = 0;
+ skeleton.skinText[where + 2] = 0;
+ }
+ }
+ }
+ skeleton.drawmodel.textureptr.bind();
+ DoMipmaps();
+
+ bleedy = (1 + coordsy) * 512;
+ bleedx = coordsx * 512;
+ bleedy /= realtexdetail;
+ bleedx /= realtexdetail;
+ if (bleedx < 0)
+ bleedx = 0;
+ if (bleedy < 0)
+ bleedy = 0;
+ if (bleedx > skeleton.skinsize - 1)
+ bleedx = skeleton.skinsize - 1;
+ if (bleedy > skeleton.skinsize - 1)
+ bleedy = skeleton.skinsize - 1;
+ direction = abs(Random() % 2) * 2 - 1;
+ }
+ if (whichtri == -1)
+ return 0;
+ }
+ bleeding = howmuch + (float)abs(Random() % 100) / 200 - .25;
+ deathbleeding += bleeding;
+ bloodloss += bleeding * 3;
+
+ if (tutoriallevel != 1 && aitype != playercontrolled && bloodloss > damagetolerance * 2 / 3 && bloodloss < damagetolerance && creature == rabbittype) {
+ if (abs(Random() % 2) == 0) {
+ aitype = gethelptype;
+ lastseentime = 12;
+ } else
+ aitype = attacktypecutoff;
+ ally = 0;
+ }
+ if (bleeding > 2)
+ bleeding = 2;
+ return 1;
+}
+
+
+
+/* EFFECT
+ * guessing this performs a reversal
+ */
+void Person::Reverse()
+{
+ if (!((victim->aitype == playercontrolled
+ || hostiletime > 1
+ || staggerdelay <= 0)
+ && victim->animTarget != jumpupanim
+ && victim->animTarget != jumpdownanim
+ && (tutoriallevel != 1 || cananger)
+ && hostile))
+ return;
+
+ if (normaldotproduct (victim->facing, victim->coords - coords) > 0
+ && (victim->id != 0 || difficulty >= 2)
+ && (creature != wolftype || victim->creature == wolftype))
+ return;
+
+ if (animTarget == sweepanim) {
+ animTarget = sweepreversedanim;
+ animCurrent = sweepreversedanim;
+ victim->animCurrent = sweepreversalanim;
+ victim->animTarget = sweepreversalanim;
+ }
+ if (animTarget == spinkickanim) {
+ animTarget = spinkickreversedanim;
+ animCurrent = spinkickreversedanim;
+ victim->animCurrent = spinkickreversalanim;
+ victim->animTarget = spinkickreversalanim;
+ }
+ if (animTarget == upunchanim || animTarget == rabbittacklinganim) {
+ if (animTarget == rabbittacklinganim) {
+ frameCurrent = 6;
+ frameTarget = 7;
+ victim->frameCurrent = 6;
+ victim->frameTarget = 7;
+ }
+ animTarget = upunchreversedanim;
+ animCurrent = upunchreversedanim;
+ victim->animCurrent = upunchreversalanim;
+ victim->animTarget = upunchreversalanim;
+ }
+ if (animTarget == staffhitanim && distsq(&victim->coords, &coords) < 2 && ((victim->id == 0 && victim->crouchkeydown) || Random() % 4 == 0)) {
+ if (victim->weaponactive != -1) {
+ victim->throwtogglekeydown = 1;
+ XYZ tempVelocity = victim->velocity * .2;
+ if (tempVelocity.x == 0)
+ tempVelocity.x = .1;
+ weapons[victim->weaponids[0]].drop(tempVelocity, tempVelocity, false);
+ victim->num_weapons--;
+ if (victim->num_weapons) {
+ victim->weaponids[0] = victim->weaponids[victim->num_weapons];
+ if (victim->weaponstuck == victim->num_weapons)
+ victim->weaponstuck = 0;
+ }
+
+ victim->weaponactive = -1;
+ for (unsigned j = 0; j < Person::players.size(); j++) {
+ Person::players[j]->wentforweapon = 0;
+ }
+ }
+
+ animTarget = staffhitreversedanim;
+ animCurrent = staffhitreversedanim;
+ victim->animCurrent = staffhitreversalanim;
+ victim->animTarget = staffhitreversalanim;
+ }
+ if (animTarget == staffspinhitanim && distsq(&victim->coords, &coords) < 2 && ((victim->id == 0 && victim->crouchkeydown) || Random() % 2 == 0)) {
+ if (victim->weaponactive != -1) {
+ victim->throwtogglekeydown = 1;
+ XYZ tempVelocity = victim->velocity * .2;
+ if (tempVelocity.x == 0)
+ tempVelocity.x = .1;
+ weapons[victim->weaponids[0]].drop(tempVelocity, tempVelocity, false);
+ victim->num_weapons--;
+ if (victim->num_weapons) {
+ victim->weaponids[0] = victim->weaponids[victim->num_weapons];
+ if (victim->weaponstuck == victim->num_weapons)
+ victim->weaponstuck = 0;
+ }
+
+ victim->weaponactive = -1;
+ for (unsigned j = 0; j < Person::players.size(); j++) {
+ Person::players[j]->wentforweapon = 0;
+ }
+ }
+ animTarget = staffspinhitreversedanim;
+ animCurrent = staffspinhitreversedanim;
+ victim->animCurrent = staffspinhitreversalanim;
+ victim->animTarget = staffspinhitreversalanim;
+ }
+ if (animTarget == swordslashanim && distsq(&victim->coords, &coords) < 2 && ((victim->id == 0 && victim->crouchkeydown) || Random() % 4 == 0)) {
+ if (victim->weaponactive != -1) {
+ victim->throwtogglekeydown = 1;
+ XYZ tempVelocity = victim->velocity * .2;
+ if (tempVelocity.x == 0)
+ tempVelocity.x = .1;
+ weapons[victim->weaponids[0]].drop(tempVelocity, tempVelocity, false);
+ victim->num_weapons--;
+ if (victim->num_weapons) {
+ victim->weaponids[0] = victim->weaponids[victim->num_weapons];
+ if (victim->weaponstuck == victim->num_weapons)
+ victim->weaponstuck = 0;
+ }
+
+ victim->weaponactive = -1;
+ for (unsigned j = 0; j < Person::players.size(); j++) {
+ Person::players[j]->wentforweapon = 0;
+ }
+ }
+ animTarget = swordslashreversedanim;
+ animCurrent = swordslashreversedanim;
+ victim->animCurrent = swordslashreversalanim;
+ victim->animTarget = swordslashreversalanim;
+ }
+ if (animTarget == knifeslashstartanim && distsq(&victim->coords, &coords) < 2 && (victim->id == 0 || Random() % 4 == 0)) {
+ if (victim->weaponactive != -1) {
+ victim->throwtogglekeydown = 1;
+ XYZ tempVelocity = victim->velocity * .2;
+ if (tempVelocity.x == 0)
+ tempVelocity.x = .1;
+ weapons[victim->weaponids[0]].drop(tempVelocity, tempVelocity, false);
+ victim->num_weapons--;
+ if (victim->num_weapons) {
+ victim->weaponids[0] = victim->weaponids[victim->num_weapons];
+ if (victim->weaponstuck == victim->num_weapons)
+ victim->weaponstuck = 0;
+ }
+
+ victim->weaponactive = -1;
+ for (unsigned j = 0; j < Person::players.size(); j++) {
+ Person::players[j]->wentforweapon = 0;
+ }
+ }
+ animTarget = knifeslashreversedanim;
+ animCurrent = knifeslashreversedanim;
+ victim->animCurrent = knifeslashreversalanim;
+ victim->animTarget = knifeslashreversalanim;
+ }
+ if (animTarget != knifeslashstartanim && animTarget != staffhitanim && animTarget != staffspinhitanim && animTarget != winduppunchanim && animTarget != wolfslapanim && animTarget != swordslashanim) {
+ victim->targettilt2 = targettilt2;
+ victim->frameCurrent = frameCurrent;
+ victim->frameTarget = frameTarget;
+ victim->target = target;
+ victim->velocity = 0;
+ victim->oldcoords = victim->coords;
+ victim->coords = coords;
+ victim->targetyaw = targetyaw;
+ victim->yaw = targetyaw;
+ victim->victim = this->shared_from_this();
+ }
+ if (animTarget == winduppunchanim) {
+ animTarget = winduppunchblockedanim;
+ victim->animTarget = blockhighleftanim;
+ victim->frameTarget = 1;
+ victim->target = .5;
+ victim->victim = this->shared_from_this();
+ victim->targetyaw = targetyaw + 180;
+ }
+ if (animTarget == wolfslapanim) {
+ animTarget = winduppunchblockedanim;
+ victim->animTarget = blockhighleftanim;
+ victim->frameTarget = 1;
+ victim->target = .5;
+ victim->victim = this->shared_from_this();
+ victim->targetyaw = targetyaw + 180;
+ }
+ if ((animTarget == swordslashanim || animTarget == staffhitanim || animTarget == staffspinhitanim) && victim->weaponactive != -1) {
+ animTarget = swordslashparriedanim;
+ parriedrecently = .4;
+ victim->parriedrecently = 0;
+ victim->animTarget = swordslashparryanim;
+ victim->frameTarget = 1;
+ victim->target = .5;
+ victim->victim = this->shared_from_this();
+ victim->targetyaw = targetyaw + 180;
+
+ if (abs(Random() % 20) == 0 || weapons[victim->weaponids[victim->weaponactive]].getType() == knife) {
+ if (victim->weaponactive != -1) {
+ if (weapons[victim->weaponids[0]].getType() == staff || weapons[weaponids[0]].getType() == staff) {
+ if (weapons[victim->weaponids[0]].getType() == staff)
+ weapons[victim->weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
+ if (weapons[weaponids[0]].getType() == staff)
+ weapons[weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
+ emit_sound_at(swordstaffsound, victim->coords);
+ } else {
+ emit_sound_at(metalhitsound, victim->coords);
+ }
+ }
+ XYZ aim;
+ victim->Puff(righthand);
+ victim->target = 0;
+ victim->frameTarget = 0;
+ victim->animTarget = staggerbackhighanim;
+ victim->targetyaw = targetyaw + 180;
+ victim->target = 0;
+ aim = DoRotation(facing, 0, 90, 0) * 21;
+ aim.y += 7;
+ weapons[victim->weaponids[0]].drop(aim * -.2, aim);
+ victim->num_weapons--;
+ if (victim->num_weapons) {
+ victim->weaponids[0] = victim->weaponids[num_weapons];
+ if (victim->weaponstuck == victim->num_weapons)
+ victim->weaponstuck = 0;
+ }
+ victim->weaponactive = -1;
+ for (unsigned i = 0; i < Person::players.size(); i++) {
+ Person::players[i]->wentforweapon = 0;
+ }
+ }
+
+ if (abs(Random() % 20) == 0) {
+ if (weaponactive != -1) {
+ if (weapons[victim->weaponids[0]].getType() == staff || weapons[weaponids[0]].getType() == staff) {
+ if (weapons[victim->weaponids[0]].getType() == staff)
+ weapons[victim->weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
+ if (weapons[weaponids[0]].getType() == staff)
+ weapons[weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
+
+ emit_sound_at(swordstaffsound, coords);
+ } else {
+ emit_sound_at(metalhitsound, coords);
+ }
+ }
+
+ XYZ aim;
+ Puff(righthand);
+ target = 0;
+ frameTarget = 0;
+ animTarget = staggerbackhighanim;
+ targetyaw = targetyaw + 180;
+ target = 0;
+ aim = DoRotation(facing, 0, 90, 0) * 21;
+ aim.y += 7;
+ weapons[victim->weaponids[0]].drop(aim * -.2, aim);
+ num_weapons--;
+ if (num_weapons) {
+ weaponids[0] = weaponids[num_weapons];
+ if (weaponstuck == num_weapons)
+ weaponstuck = 0;
+ }
+ weaponactive = -1;
+ for (unsigned i = 0; i < Person::players.size(); i++) {
+ Person::players[i]->wentforweapon = 0;
+ }
+
+
+ }
+ }
+ if (hasvictim)
+ if (animTarget == knifeslashstartanim || animTarget == swordslashanim || animTarget == staffhitanim || animTarget == staffspinhitanim) {
+ if ((animTarget != staffhitanim && animTarget != staffspinhitanim) || distsq(&coords, &victim->coords) > .2) {
+ victim->animTarget = dodgebackanim;
+ victim->frameTarget = 0;
+ victim->target = 0;
+
+ XYZ rotatetarget;
+ rotatetarget = coords - victim->coords;
+ Normalise(&rotatetarget);
+ victim->targetyaw = -asin(0 - rotatetarget.x);
+ victim->targetyaw *= 360 / 6.28;
+ if (rotatetarget.z < 0)
+ victim->targetyaw = 180 - victim->targetyaw;
+
+ victim->targettilt2 = -asin(rotatetarget.y) * 360 / 6.28; //*-70;
+
+ victim->lastattack3 = victim->lastattack2;
+ victim->lastattack2 = victim->lastattack;
+ victim->lastattack = victim->animTarget;
+ } else {
+ victim->animTarget = sweepanim;
+ victim->frameTarget = 0;
+ victim->target = 0;
+
+ XYZ rotatetarget;
+ rotatetarget = coords - victim->coords;
+ Normalise(&rotatetarget);
+ victim->targetyaw = -asin(0 - rotatetarget.x);
+ victim->targetyaw *= 360 / 6.28;
+ if (rotatetarget.z < 0)
+ victim->targetyaw = 180 - victim->targetyaw;
+
+ victim->targettilt2 = -asin(rotatetarget.y) * 360 / 6.28; //*-70;
+
+ victim->lastattack3 = victim->lastattack2;
+ victim->lastattack2 = victim->lastattack;
+ victim->lastattack = victim->animTarget;
+ }
+ }
+
+ velocity = 0;
+ victim->velocity = 0;
+
+ if (aitype != playercontrolled) {
+ feint = 0;
+ if (escapednum < 2) {
+ int chances = ((difficulty == 2) ? 3 : ((difficulty == 1) ? 5 : 10));
+ if ((Random() % chances) == 0) {
+ feint = 1;
+ }
+ }
+ }
+
+ if (victim->id == 0 && Animation::animations[victim->animTarget].attack == reversal)
+ numreversals++;
+}
+
+/* EFFECT
+ * get hurt
+ */
+void Person::DoDamage(float howmuch)
+{
+ // subtract health (temporary?)
+ if (tutoriallevel != 1)
+ damage += howmuch / power;
+ // stats?
+ if (id != 0)
+ damagedealt += howmuch / power;
+ if (id == 0)
+ damagetaken += howmuch / power;
+
+ // reset bonuses
+ if (id == 0 && (bonus == solidhit || bonus == twoxcombo || bonus == threexcombo || bonus == fourxcombo || bonus == megacombo))
+ bonus = 0;
+ // subtract health
+ if (tutoriallevel != 1)
+ permanentdamage += howmuch / 2 / power;
+ if (tutoriallevel != 1)
+ superpermanentdamage += howmuch / 4 / power;
+ // visual effects
+ if (permanentdamage > damagetolerance / 2 && permanentdamage - howmuch < damagetolerance / 2 && Random() % 2)
+ DoBlood(1, 255);
+ if ((permanentdamage > damagetolerance * .8 && Random() % 2 && !deathbleeding) || spurt)
+ DoBlood(1, 255);
+ spurt = 0;
+ if (id == 0)
+ camerashake += howmuch / 100;
+ if (id == 0 && ((howmuch > 50 && damage > damagetolerance / 2)))
+ blackout = damage / damagetolerance;
+ if (blackout > 1)
+ blackout = 1;
+
+ // cancel attack?
+ if (aitype == passivetype && damage < damagetolerance && ((tutoriallevel != 1 || cananger) && hostile))
+ aitype = attacktypecutoff;
+ if (tutoriallevel != 1 && aitype != playercontrolled && damage < damagetolerance && damage > damagetolerance * 2 / 3 && creature == rabbittype) {
+ if (abs(Random() % 2) == 0) {
+ aitype = gethelptype;
+ lastseentime = 12;
+ } else
+ aitype = attacktypecutoff;
+ ally = 0;
+ }
+
+ if (howmuch > damagetolerance * 50 && skeleton.free != 2) {
+ XYZ flatvelocity2;
+ XYZ flatfacing2;
+ for (int i = 0; i < skeleton.joints.size(); i++) {
+ if (skeleton.free) {
+ flatvelocity2 = skeleton.joints[i].velocity;
+ flatfacing2 = skeleton.joints[i].position * scale + coords;
+ } else {
+ flatvelocity2 = velocity;
+ flatfacing2 = DoRotation(DoRotation(DoRotation(skeleton.joints[i].position, 0, 0, tilt), tilt2, 0, 0), 0, yaw, 0) * scale + coords;
+ }
+ flatvelocity2.x += (float)(abs(Random() % 100) - 50) / 10;
+ flatvelocity2.y += (float)(abs(Random() % 100) - 50) / 10;
+ flatvelocity2.z += (float)(abs(Random() % 100) - 50) / 10;
+ Sprite::MakeSprite(bloodflamesprite, flatfacing2, flatvelocity2, 1, 1, 1, 3, 1);
+ Sprite::MakeSprite(bloodsprite, flatfacing2, flatvelocity2, 1, 1, 1, .4, 1);
+ Sprite::MakeSprite(cloudsprite, flatfacing2, flatvelocity2 * 0, .6, 0, 0, 1, .5);
+ }
+
+ emit_sound_at(splattersound, coords);
+
+ skeleton.free = 2;
+ DoDamage(10000);
+ RagDoll(0);
+ if (!dead && creature == wolftype) {
+ award_bonus(0, Wolfbonus);
+ }
+ dead = 2;
+ coords = 20;
+ }
+
+ // play sounds
+ if (tutoriallevel != 1 || id == 0)
+ if (speechdelay <= 0 && !dead && aitype != playercontrolled) {
+ int whichsound = -1;
+
+ if (creature == wolftype) {
+ int i = abs(Random() % 2);
+ if (i == 0)
+ whichsound = snarlsound;
+ if (i == 1)
+ whichsound = snarl2sound;
+ }
+ if (creature == rabbittype) {
+ int i = abs(Random() % 2);
+ if (i == 0)
+ whichsound = rabbitpainsound;
+ if (i == 1 && damage > damagetolerance)
+ whichsound = rabbitpain1sound;
+ }
+
+ if (whichsound != -1) {
+ emit_sound_at(whichsound, coords);
+ addEnvSound(coords);
+ }
+ }
+ speechdelay = .3;
+}
+
+/* EFFECT
+ * calculate/animate head facing direction?
+ */
+void Person::DoHead()
+{
+ static XYZ rotatearound;
+ static XYZ facing;
+ static float lookspeed = 500;
+
+ if (!freeze && !winfreeze) {
+
+ //head facing
+ targetheadyaw = (float)((int)((0 - yaw - targetheadyaw + 180) * 100) % 36000) / 100;
+ targetheadpitch = (float)((int)(targetheadpitch * 100) % 36000) / 100;
+
+ while (targetheadyaw > 180)targetheadyaw -= 360;
+ while (targetheadyaw < -180)targetheadyaw += 360;
+
+ if (targetheadyaw > 160)
+ targetheadpitch = targetheadpitch * -1;
+ if (targetheadyaw < -160)
+ targetheadpitch = targetheadpitch * -1;
+ if (targetheadyaw > 160)
+ targetheadyaw = targetheadyaw - 180;
+ if (targetheadyaw < -160)
+ targetheadyaw = targetheadyaw + 180;
+
+ if (targetheadpitch > 120)
+ targetheadpitch = 120;
+ if (targetheadpitch < -120)
+ targetheadpitch = -120;
+ if (targetheadyaw > 120)
+ targetheadyaw = 120;
+ if (targetheadyaw < -120)
+ targetheadyaw = -120;
+
+ if (!isIdle())
+ targetheadpitch = 0;
+ if (isIdle()) {
+ if (targetheadyaw > 80)
+ targetheadyaw = 80;
+ if (targetheadyaw < -80)
+ targetheadyaw = -80;
+ if (targetheadpitch > 50)
+ targetheadpitch = 50;
+ if (targetheadpitch < -50)
+ targetheadpitch = -50;
+ }
+
+ if (abs(headyaw - targetheadyaw) < multiplier * lookspeed)
+ headyaw = targetheadyaw;
+ else if (headyaw > targetheadyaw) {
+ headyaw -= multiplier * lookspeed;
+ } else if (headyaw < targetheadyaw) {
+ headyaw += multiplier * lookspeed;
+ }
+
+ if (abs(headpitch - targetheadpitch) < multiplier * lookspeed / 2)
+ headpitch = targetheadpitch;
+ else if (headpitch > targetheadpitch) {
+ headpitch -= multiplier * lookspeed / 2;
+ } else if (headpitch < targetheadpitch) {
+ headpitch += multiplier * lookspeed / 2;
+ }
+
+ rotatearound = jointPos(neck);
+ jointPos(head) = rotatearound + DoRotation(jointPos(head) - rotatearound, headpitch, 0, 0);
+
+ facing = 0;
+ facing.z = -1;
+ if (animTarget != bounceidleanim && animTarget != fightidleanim && animTarget != wolfidle && animTarget != knifefightidleanim && animTarget != drawrightanim && animTarget != drawleftanim && animTarget != walkanim) {
+ facing = DoRotation(facing, headpitch * .4, 0, 0);
+ facing = DoRotation(facing, 0, headyaw * .4, 0);
+ }
+
+ if (animTarget == bounceidleanim || animTarget == fightidleanim || animTarget == wolfidle || animTarget == knifefightidleanim || animTarget == drawrightanim || animTarget == drawleftanim) {
+ facing = DoRotation(facing, headpitch * .8, 0, 0);
+ facing = DoRotation(facing, 0, headyaw * .8, 0);
+ }
+
+ if (animTarget == walkanim) {
+ facing = DoRotation(facing, headpitch * .6, 0, 0);
+ facing = DoRotation(facing, 0, headyaw * .6, 0);
+ }
+
+ skeleton.specialforward[0] = facing;
+ //skeleton.specialforward[0]=DoRotation(facing,0,yaw,0);
+ for (int i = 0; i < skeleton.muscles.size(); i++) {
+ if (skeleton.muscles[i].visible && (skeleton.muscles[i].parent1->label == head || skeleton.muscles[i].parent2->label == head)) {
+ skeleton.FindRotationMuscle(i, animTarget);
+ }
+ }
+ }
+}
+
+/* EFFECT
+ * ragdolls character?
+ */
+void Person::RagDoll(bool checkcollision)
+{
+ static XYZ change;
+ static int l, i, j;
+ static float speed;
+ if (!skeleton.free) {
+ if (id == 0)
+ numfalls++;
+ if (id == 0 && isFlip())
+ numflipfail++;
+
+ escapednum = 0;
+
+ facing = 0;
+ facing.z = 1;
+ facing = DoRotation(facing, 0, yaw, 0);
+
+ skeleton.freetime = 0;
+
+ skeleton.longdead = 0;
+
+ skeleton.free = 1;
+ skeleton.broken = 0;
+ skeleton.spinny = 1;
+ freefall = 1;
+ skeleton.freefall = 1;
+
+ if (!isnormal(velocity.x)) velocity.x = 0;
+ if (!isnormal(velocity.y)) velocity.y = 0;
+ if (!isnormal(velocity.z)) velocity.z = 0;
+ if (!isnormal(yaw)) yaw = 0;
+ if (!isnormal(coords.x)) coords = 0;
+ if (!isnormal(tilt)) tilt = 0;
+ if (!isnormal(tilt2)) tilt2 = 0;
+
+ for (int i = 0; i < skeleton.joints.size(); i++) {
+ skeleton.joints[i].delay = 0;
+ skeleton.joints[i].locked = 0;
+ skeleton.joints[i].position = DoRotation(DoRotation(DoRotation(skeleton.joints[i].position, 0, 0, tilt), tilt2, 0, 0), 0, yaw, 0);
+ if (!isnormal(skeleton.joints[i].position.x)) skeleton.joints[i].position = DoRotation(skeleton.joints[i].position, 0, yaw, 0);
+ if (!isnormal(skeleton.joints[i].position.x)) skeleton.joints[i].position = coords;
+ skeleton.joints[i].position.y += .1;
+ skeleton.joints[i].oldposition = skeleton.joints[i].position;
+ skeleton.joints[i].realoldposition = skeleton.joints[i].position * scale + coords;
+ }
+
+ for (int i = 0; i < skeleton.joints.size(); i++) {
+ skeleton.joints[i].velocity = 0;
+ skeleton.joints[i].velchange = 0;
+ }
+ skeleton.DoConstraints(&coords, &scale);
+ 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 = targetFrame().speed * 2;
+ if (currentFrame().speed > targetFrame().speed) {
+ speed = currentFrame().speed * 2;
+ }
+ if (transspeed)
+ speed = transspeed * 2;
+
+ speed *= speedmult;
+
+ for (int i = 0; i < skeleton.joints.size(); i++) {
+ 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((targetFrame().joints[i].position - currentFrame().joints[i].position) * 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;
+ change.y = (float)(Random() % 100) / 100;
+ change.z = (float)(Random() % 100) / 100;
+ skeleton.joints[i].velocity += change;
+ skeleton.joints[abs(Random() % skeleton.joints.size())].velocity -= change;
+
+ change.x = (float)(Random() % 100) / 100;
+ change.y = (float)(Random() % 100) / 100;
+ change.z = (float)(Random() % 100) / 100;
+ skeleton.joints[i].velchange += change;
+ skeleton.joints[abs(Random() % skeleton.joints.size())].velchange -= change;
+ }
+
+ if (checkcollision) {
+ XYZ average;
+ XYZ lowpoint;
+ XYZ colpoint;
+ int howmany;
+ average = 0;
+ howmany = 0;
+ for (j = 0; j < skeleton.joints.size(); j++) {
+ average += skeleton.joints[j].position;
+ howmany++;
+ }
+ average /= howmany;
+ coords += average * scale;
+ for (j = 0; j < skeleton.joints.size(); j++) {
+ skeleton.joints[j].position -= average;
+ }
+
+ whichpatchx = coords.x / (terrain.size / subdivision * terrain.scale);
+ whichpatchz = coords.z / (terrain.size / subdivision * terrain.scale);
+ if (terrain.patchobjectnum[whichpatchx][whichpatchz])
+ for (l = 0; l < terrain.patchobjectnum[whichpatchx][whichpatchz]; l++) {
+ i = terrain.patchobjects[whichpatchx][whichpatchz][l];
+ lowpoint = coords;
+ lowpoint.y += 1;
+ if (SphereCheck(&lowpoint, 3, &colpoint, &objects.position[i], &objects.yaw[i], &objects.model[i]) != -1) {
+ coords.x = lowpoint.x;
+ coords.z = lowpoint.z;
+ }
+ }
+ }
+
+ yaw = 0;
+ updatedelay = 0;
+
+ velocity = 0;
+ for (int i = 0; i < skeleton.joints.size(); i++) {
+ velocity += skeleton.joints[i].velocity * scale;
+ }
+ velocity /= skeleton.joints.size();
+
+ // drop weapon
+ if (Random() % 2 == 0) {
+ if (weaponactive != -1 && animTarget != rabbitkickanim && num_weapons > 0) {
+ weapons[weaponids[0]].drop(jointVel(righthand) * scale * -.3, jointVel(righthand) * scale);
+ weapons[weaponids[0]].velocity.x += .01;
+ num_weapons--;
+ if (num_weapons) {
+ weaponids[0] = weaponids[num_weapons];
+ if (weaponstuck == num_weapons)
+ weaponstuck = 0;
+ }
+ weaponactive = -1;
+ for (unsigned i = 0; i < Person::players.size(); i++) {
+ Person::players[i]->wentforweapon = 0;
+ }
+ }
+ }
+
+ animTarget = bounceidleanim;
+ animCurrent = bounceidleanim;
+ frameTarget = 0;
+ frameCurrent = 0;
+ }
+}
+
+
+
+/* EFFECT
+ */
+void Person::FootLand(bodypart whichfoot, float opacity)
+{
+ if ((whichfoot != leftfoot) && (whichfoot != rightfoot)) {
+ cerr << "FootLand called on wrong bodypart" << endl;
+ return;
+ }
+ static XYZ terrainlight;
+ static XYZ footvel, footpoint;
+ if (opacity >= 1 || skiddelay <= 0) {
+ if (opacity > 1) {
+ footvel = 0;
+ footpoint = DoRotation(jointPos(whichfoot), 0, yaw, 0) * scale + coords;
+ if (distsq(&footpoint, &viewer))
+ Sprite::MakeSprite(cloudsprite, footpoint, footvel, 1, 1, 1, .5, .2 * opacity);
+ } else if (onterrain && terrain.getOpacity(coords.x, coords.z) < .2) {
+ footvel = velocity / 5;
+ if (footvel.y < .8)
+ footvel.y = .8;
+ footpoint = DoRotation(jointPos(whichfoot), 0, yaw, 0) * scale + coords;
+ footpoint.y = terrain.getHeight(footpoint.x, footpoint.z);
+ terrainlight = terrain.getLighting(footpoint.x, footpoint.z);
+ if (distsq(&footpoint, &viewer) < viewdistance * viewdistance / 4) {
+ if (environment == snowyenvironment) {
+ Sprite::MakeSprite(cloudsprite, footpoint, footvel * .6, terrainlight.x, terrainlight.y, terrainlight.z, .5, .7 * opacity);
+ if (detail == 2) {
+ terrain.MakeDecal(footprintdecal, footpoint, .2, 1 * opacity, yaw);
+ }
+ } else if (environment == grassyenvironment) {
+ Sprite::MakeSprite(cloudsprite, footpoint, footvel * .6, terrainlight.x * 90 / 255, terrainlight.y * 70 / 255, terrainlight.z * 8 / 255, .5, .5 * opacity);
+ } else if (environment == desertenvironment) {
+ Sprite::MakeSprite(cloudsprite, footpoint, footvel * .6, terrainlight.x * 190 / 255, terrainlight.y * 170 / 255, terrainlight.z * 108 / 255, .5, .7 * opacity);
+ if (detail == 2) {
+ terrain.MakeDecal(footprintdecal, footpoint, .2, .25 * opacity, yaw);
+ }
+ }
+ }
+ } else if (isLanding() || (animTarget == jumpupanim) || isLandhard()) {
+ footvel = velocity / 5;
+ if (footvel.y < .8)
+ footvel.y = .8;
+ footpoint = DoRotation(jointPos(whichfoot), 0, yaw, 0) * scale + coords;
+ if (distsq(&footpoint, &viewer) < viewdistance * viewdistance / 4) {
+ Sprite::MakeSprite(cloudsprite, footpoint, footvel * .6, 1, 1, 1, .5, .2 * opacity);
+ }
+ }
+ }
+}
+
+/* EFFECT
+ * make a puff effect at a body part (dust effect?)
+ */
+void Person::Puff(int whichlabel)
+{
+ static XYZ footvel, footpoint;
+
+ footvel = 0;
+ footpoint = DoRotation(jointPos(whichlabel), 0, yaw, 0) * scale + coords;
+ Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 1, 1, .9, .3);
+}
+
+/* EFFECT
+ * I think I added this in an attempt to clean up code
+ */
+void Person::setAnimation(int animation)
+{
+ animTarget = animation;
+ frameTarget = 0;
+ target = 0;
+}
+
+/* EFFECT
+ * MONSTER
+ * TODO: ???
+ */
+void Person::DoAnimations()
+{
+ if (!skeleton.free) {
+ static float oldtarget;
+
+ if (isIdle() && animCurrent != getIdle())
+ normalsupdatedelay = 0;
+
+ if (animTarget == tempanim || animCurrent == tempanim) {
+ Animation::animations[tempanim] = tempanimation;
+ }
+ if (animTarget == jumpupanim || animTarget == jumpdownanim || isFlip()) {
+ float gLoc[3];
+ float vel[3];
+ gLoc[0] = coords.x;
+ gLoc[1] = coords.y;
+ gLoc[2] = coords.z;
+ vel[0] = velocity.x;
+ vel[1] = velocity.y;
+ vel[2] = velocity.z;
+
+ if (id == 0) {
+ OPENAL_3D_SetAttributes(channels[whooshsound], gLoc, vel);
+ OPENAL_SetVolume(channels[whooshsound], 64 * findLength(&velocity) / 5);
+ }
+ if (((velocity.y < -15) || (crouchkeydown && velocity.y < -8)) && abs(velocity.y) * 4 > fast_sqrt(velocity.x * velocity.x * velocity.z * velocity.z))
+ landhard = 1;
+ if (!crouchkeydown && velocity.y >= -15)
+ landhard = 0;
+ }
+ if ((animCurrent == jumpupanim || animTarget == jumpdownanim)/*&&velocity.y<40*/ && !isFlip() && (!isLanding() && !isLandhard()) && ((crouchkeydown && !crouchtogglekeydown))) {
+ XYZ targfacing;
+ targfacing = 0;
+ targfacing.z = 1;
+
+ targfacing = DoRotation(targfacing, 0, targetyaw, 0);
+
+ if (normaldotproduct(targfacing, velocity) >= -.3)
+ animTarget = flipanim;
+ else
+ animTarget = backflipanim;
+ crouchtogglekeydown = 1;
+ frameTarget = 0;
+ target = 0;
+
+ if (id == 0)
+ numflipped++;
+ }
+
+ 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::animations[animTarget].attack == reversed && aitype == playercontrolled && (escapednum < 2 || reversaltrain))
+ feint = 1;
+ if (!isFlip())
+ crouchtogglekeydown = 1;
+ }
+
+
+ if (Animation::animations[animTarget].attack || animCurrent == getupfrombackanim || animCurrent == getupfromfrontanim) {
+ if (detail)
+ normalsupdatedelay = 0;
+ }
+
+ if (target >= 1) {
+ if (animTarget == rollanim && frameTarget == 3 && onfire) {
+ onfire = 0;
+ emit_sound_at(fireendsound, coords);
+ pause_sound(stream_firesound);
+ deathbleeding = 0;
+ }
+
+ if (animTarget == rabbittacklinganim && frameTarget == 1) {
+ if (victim->aitype == attacktypecutoff && victim->stunned <= 0 && victim->surprised <= 0 && victim->id != 0)
+ Reverse();
+ if (animTarget == rabbittacklinganim && frameTarget == 1 && !victim->isCrouch() && victim->animTarget != backhandspringanim) {
+ if (normaldotproduct(victim->facing, facing) > 0)
+ victim->animTarget = rabbittackledbackanim;
+ else
+ victim->animTarget = rabbittackledfrontanim;
+ victim->frameTarget = 2;
+ victim->target = 0;
+ victim->yaw = yaw;
+ victim->targetyaw = yaw;
+ if (victim->aitype == gethelptype)
+ victim->DoDamage(victim->damagetolerance - victim->damage);
+ //victim->DoDamage(30);
+ if (creature == wolftype) {
+ DoBloodBig(0, 255);
+ emit_sound_at(clawslicesound, victim->coords);
+ victim->spurt = 1;
+ victim->DoBloodBig(1 / victim->armorhead, 210);
+ }
+ award_bonus(id, TackleBonus,
+ victim->aitype == gethelptype ? 50 : 0);
+ }
+ }
+
+ if (!drawtogglekeydown && drawkeydown && (weaponactive == -1 || num_weapons == 1) && (targetFrame().label || (animTarget != animCurrent && animCurrent == rollanim)) && num_weapons > 0 && creature != wolftype) {
+ if (weapons[weaponids[0]].getType() == knife) {
+ if (weaponactive == -1)
+ weaponactive = 0;
+ else if (weaponactive == 0)
+ weaponactive = -1;
+
+ if (weaponactive == -1) {
+ emit_sound_at(knifesheathesound, coords);
+ }
+ if (weaponactive != -1) {
+ emit_sound_at(knifedrawsound, coords, 128);
+ }
+ }
+ drawtogglekeydown = 1;
+ }
+ //Footstep sounds
+ if (tutoriallevel != 1 || id == 0)
+ if ((targetFrame().label && (targetFrame().label < 5 || targetFrame().label == 8))) {
+ int whichsound;
+ if (onterrain) {
+ if (terrain.getOpacity(coords.x, coords.z) < .2) {
+ if (targetFrame().label == 1)
+ whichsound = footstepsound;
+ else
+ whichsound = footstepsound2;
+ if (targetFrame().label == 1)
+ FootLand(leftfoot, 1);
+ if (targetFrame().label == 2)
+ FootLand(rightfoot, 1);
+ if (targetFrame().label == 3 && isRun()) {
+ FootLand(rightfoot, 1);
+ FootLand(leftfoot, 1);
+ }
+
+ }
+ if (terrain.getOpacity(coords.x, coords.z) >= .2) {
+ if (targetFrame().label == 1)
+ whichsound = footstepsound3;
+ else
+ whichsound = footstepsound4;
+ }
+ }
+ if (!onterrain) {
+ if (targetFrame().label == 1)
+ whichsound = footstepsound3;
+ else
+ whichsound = footstepsound4;
+ }
+ if (targetFrame().label == 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;
+ if (r == 1)
+ whichsound = midwhooshsound;
+ if (r == 2)
+ whichsound = highwhooshsound;
+ }
+ if (Animation::animations[animTarget].attack == neutral)
+ whichsound = movewhooshsound;
+ } else if (targetFrame().label == 4)
+ whichsound = knifeswishsound;
+ if (targetFrame().label == 8 && tutoriallevel != 1)
+ whichsound = landsound2;
+
+ emit_sound_at(whichsound, coords, 256.);
+
+ if (id == 0)
+ if (whichsound == footstepsound || whichsound == footstepsound2 || whichsound == footstepsound3 || whichsound == footstepsound4) {
+ if (animTarget == wolfrunninganim || animTarget == rabbitrunninganim) {
+ addEnvSound(coords, 15);
+ } else {
+ addEnvSound(coords, 6);
+ }
+ }
+
+ if (targetFrame().label == 3) {
+ whichsound--;
+ emit_sound_at(whichsound, coords, 128.);
+ }
+ }
+
+ //Combat sounds
+ if (tutoriallevel != 1 || id == 0)
+ if (speechdelay <= 0)
+ if (animTarget != crouchstabanim && animTarget != swordgroundstabanim && animTarget != staffgroundsmashanim)
+ if ((targetFrame().label && (targetFrame().label < 5 || targetFrame().label == 8))) {
+ int whichsound = -1;
+ if (targetFrame().label == 4 && aitype != playercontrolled) {
+ if (Animation::animations[animTarget].attack != neutral) {
+ unsigned r = abs(Random() % 4);
+ if (creature == rabbittype) {
+ if (r == 0) whichsound = rabbitattacksound;
+ if (r == 1) whichsound = rabbitattack2sound;
+ if (r == 2) whichsound = rabbitattack3sound;
+ if (r == 3) whichsound = rabbitattack4sound;
+ }
+ if (creature == wolftype) {
+ if (r == 0) whichsound = barksound;
+ if (r == 1) whichsound = bark2sound;
+ if (r == 2) whichsound = bark3sound;
+ if (r == 3) whichsound = barkgrowlsound;
+ }
+ speechdelay = .3;
+ }
+ }
+
+ if (whichsound != -1) {
+ emit_sound_at(whichsound, coords);
+ }
+ }
+
+
+
+ if ((!wasLanding() && !wasLandhard()) && animCurrent != getIdle() && (isLanding() || isLandhard())) {
+ FootLand(leftfoot, 1);
+ FootLand(rightfoot, 1);
+ }
+
+ transspeed = 0;
+ currentoffset = targetoffset;
+ frameTarget = frameCurrent;
+ animCurrent = animTarget;
+ frameTarget++;
+
+ if (animTarget == removeknifeanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+ for (unsigned i = 0; i < weapons.size(); i++) {
+ if (weapons[i].owner == -1)
+ if (distsqflat(&coords, &weapons[i].position) < 4 && weaponactive == -1) {
+ if (distsq(&coords, &weapons[i].position) >= 1) {
+ if (weapons[i].getType() != staff) {
+ emit_sound_at(knifedrawsound, coords, 128.);
+ }
+
+ takeWeapon(i);
+ }
+ }
+ }
+ }
+
+ if (animTarget == crouchremoveknifeanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+ for (unsigned i = 0; i < weapons.size(); i++) {
+ bool willwork = true;
+ if (weapons[i].owner != -1)
+ if (Person::players[weapons[i].owner]->weaponstuck != -1)
+ if (Person::players[weapons[i].owner]->weaponids[Person::players[weapons[i].owner]->weaponstuck] == int(i))
+ if (Person::players[weapons[i].owner]->num_weapons > 1)
+ willwork = 0;
+ if ((weapons[i].owner == -1) || (hasvictim && (weapons[i].owner == int(victim->id)) && victim->skeleton.free))
+ if (willwork && distsqflat(&coords, &weapons[i].position) < 3 && weaponactive == -1) {
+ if (distsq(&coords, &weapons[i].position) < 1 || hasvictim) {
+ bool fleshstuck = false;
+ if (weapons[i].owner != -1)
+ if (victim->weaponstuck != -1) {
+ if (victim->weaponids[victim->weaponstuck] == int(i)) {
+ fleshstuck = true;
+ }
+ }
+ if (fleshstuck) {
+ emit_sound_at(fleshstabremovesound, coords, 128.);
+ } else {
+ if (weapons[i].getType() != staff) {
+ emit_sound_at(knifedrawsound, coords, 128.);
+ }
+ }
+ if (weapons[i].owner != -1) {
+ victim = Person::players[weapons[i].owner];
+ if (victim->num_weapons == 1)
+ victim->num_weapons = 0;
+ else
+ victim->num_weapons = 1;
+
+ //victim->weaponactive=-1;
+ victim->skeleton.longdead = 0;
+ victim->skeleton.free = 1;
+ victim->skeleton.broken = 0;
+
+ for (int j = 0; j < victim->skeleton.joints.size(); j++) {
+ victim->skeleton.joints[j].velchange = 0;
+ victim->skeleton.joints[j].locked = 0;
+ }
+
+ XYZ relative;
+ relative = 0;
+ relative.y = 10;
+ Normalise(&relative);
+ XYZ footvel, footpoint;
+ footvel = 0;
+ footpoint = weapons[i].position;
+ if (victim->weaponstuck != -1) {
+ if (victim->weaponids[victim->weaponstuck] == int(i)) {
+ if (bloodtoggle)
+ Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .8, .3);
+ weapons[i].bloody = 2;
+ weapons[i].blooddrip = 5;
+ victim->weaponstuck = -1;
+ }
+ }
+ if (victim->num_weapons > 0) {
+ if (victim->weaponstuck != 0 && victim->weaponstuck != -1)
+ victim->weaponstuck = 0;
+ if (victim->weaponids[0] == int(i))
+ victim->weaponids[0] = victim->weaponids[victim->num_weapons];
+ }
+
+ victim->jointVel(abdomen) += relative * 6;
+ victim->jointVel(neck) += relative * 6;
+ victim->jointVel(rightshoulder) += relative * 6;
+ victim->jointVel(leftshoulder) += relative * 6;
+ }
+ takeWeapon(i);
+ }
+ }
+ }
+ }
+
+ if (animCurrent == drawleftanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+ if (weaponactive == -1)
+ weaponactive = 0;
+ else if (weaponactive == 0) {
+ weaponactive = -1;
+ if (num_weapons == 2) {
+ int buffer;
+ buffer = weaponids[0];
+ weaponids[0] = weaponids[1];
+ weaponids[1] = buffer;
+ }
+ }
+ if (weaponactive == -1) {
+ emit_sound_at(knifesheathesound, coords, 128.);
+ }
+ if (weaponactive != -1) {
+ emit_sound_at(knifedrawsound, coords, 128.);
+ }
+ }
+
+
+ if ((animCurrent == walljumprightkickanim && animTarget == walljumprightkickanim) || (animCurrent == walljumpleftkickanim && animTarget == walljumpleftkickanim)) {
+ XYZ rotatetarget = DoRotation(skeleton.forward, 0, yaw, 0);
+ Normalise(&rotatetarget);
+ targetyaw = -asin(0 - rotatetarget.x);
+ targetyaw *= 360 / 6.28;
+ if (rotatetarget.z < 0)
+ targetyaw = 180 - targetyaw;
+
+ if (animTarget == walljumprightkickanim)
+ targetyaw += 40;
+ if (animTarget == walljumpleftkickanim)
+ targetyaw -= 40;
+ }
+
+ bool dojumpattack;
+ dojumpattack = 0;
+ if ((animTarget == rabbitrunninganim || animTarget == wolfrunninganim) && frameTarget == 3 && (jumpkeydown || attackkeydown || id != 0))
+ dojumpattack = 1;
+ if (hasvictim)
+ if (distsq(&victim->coords, &/*Person::players[i]->*/coords) < 5 && victim->aitype == gethelptype && (attackkeydown) && !victim->skeleton.free && victim->isRun() && victim->runninghowlong >= 1)
+ dojumpattack = 1;
+ if (!hostile)
+ dojumpattack = 0;
+ if (dojumpattack) {
+ if ((animTarget == rabbitrunninganim || animTarget == wolfrunninganim) && id == 0) {
+ animTarget = rabbittackleanim;
+ frameTarget = 0;
+ emit_sound_at(jumpsound, coords);
+ }
+
+ float closestdist;
+ closestdist = 0;
+ int closestid;
+ closestid = -1;
+ XYZ targetloc;
+ targetloc = velocity;
+ Normalise(&targetloc);
+ targetloc += coords;
+ for (unsigned i = 0; i < Person::players.size(); i++) {
+ if (i != id)
+ if (distsq(&targetloc, &Person::players[i]->coords) < closestdist || closestdist == 0) {
+ closestdist = distsq(&targetloc, &Person::players[i]->coords);
+ closestid = i;
+ }
+ }
+ if (closestid != -1)
+ 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;
+ animCurrent = rabbittacklinganim;
+ animTarget = rabbittacklinganim;
+ frameCurrent = 0;
+ frameTarget = 1;
+ XYZ rotatetarget;
+ if (coords.z != victim->coords.z || coords.x != victim->coords.x) {
+ rotatetarget = coords - victim->coords;
+ Normalise(&rotatetarget);
+ targetyaw = -asin(0 - rotatetarget.x);
+ targetyaw *= 360 / 6.28;
+ if (rotatetarget.z < 0)
+ targetyaw = 180 - targetyaw;
+ }
+ if (animTarget != rabbitrunninganim) {
+ emit_sound_at(jumpsound, coords, 128.);
+ }
+ }
+ }
+
+ //Move impacts
+ float damagemult = 1 * power;
+ if (creature == wolftype)
+ damagemult = 2.5 * power;
+ if (hasvictim) {
+ damagemult /= victim->damagetolerance / 200;
+ }
+ if ((Animation::animations[animTarget].attack == normalattack || animTarget == walljumprightkickanim || animTarget == walljumpleftkickanim) && (!feint) && (victim->skeleton.free != 2 || animTarget == killanim || animTarget == dropkickanim || animTarget == crouchstabanim || animTarget == swordgroundstabanim || animTarget == staffgroundsmashanim)) {
+ if (animTarget == spinkickanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+ if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && 3 && Animation::animations[victim->animTarget].height != lowheight) {
+ escapednum = 0;
+ if (id == 0)
+ camerashake += .4;
+ if (Random() % 2 || creature == wolftype) {
+ victim->spurt = 1;
+ DoBlood(.2, 250);
+ if (creature == wolftype)
+ DoBloodBig(0, 250);
+ }
+ if (tutoriallevel != 1) {
+ emit_sound_at(heavyimpactsound, victim->coords, 128.);
+ }
+ if (creature == wolftype) {
+ emit_sound_at(clawslicesound, victim->coords, 128.);
+ victim->spurt = 1;
+ victim->DoBloodBig(2 / victim->armorhead, 175);
+ }
+ victim->RagDoll(0);
+ XYZ relative;
+ relative = victim->coords - coords;
+ relative.y = 0;
+ Normalise(&relative);
+ relative = DoRotation(relative, 0, -90, 0);
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velocity += relative * damagemult * 40;
+ }
+ victim->jointVel(head) += relative * damagemult * 200;
+ victim->Puff(head);
+ victim->DoDamage(damagemult * 100 / victim->protectionhead);
+
+ SolidHitBonus(id);
+ }
+ }
+
+ if (animTarget == wolfslapanim && Animation::animations[animTarget].frames[frameCurrent].label == 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;
+ if (Random() % 2 || creature == wolftype) {
+ victim->spurt = 1;
+ if (creature == wolftype)
+ DoBloodBig(0, 235);
+ }
+ emit_sound_at(whooshhitsound, victim->coords);
+ if (creature == wolftype) {
+ emit_sound_at(clawslicesound, victim->coords, 128.);
+ victim->spurt = 1;
+ victim->DoBloodBig(2, 175);
+ }
+ victim->RagDoll(0);
+ XYZ relative;
+ relative = victim->coords - coords;
+ relative.y = 0;
+ Normalise(&relative);
+ relative.y -= 1;
+ Normalise(&relative);
+ relative = DoRotation(relative, 0, 90, 0);
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velocity += relative * damagemult * 20;
+ }
+ victim->jointVel(head) += relative * damagemult * 100;
+ victim->Puff(head);
+ victim->DoDamage(damagemult * 50 / victim->protectionhead);
+ }
+ }
+
+ if (animTarget == walljumprightkickanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+ if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && Animation::animations[victim->animTarget].height != lowheight) {
+ escapednum = 0;
+ if (id == 0)
+ camerashake += .4;
+ victim->spurt = 1;
+ DoBlood(.2, 250);
+ if (tutoriallevel != 1) {
+ emit_sound_at(heavyimpactsound, victim->coords, 160.);
+ }
+ if (creature == wolftype) {
+ emit_sound_at(clawslicesound, victim->coords, 128.);
+ victim->spurt = 1;
+ victim->DoBloodBig(2 / victim->armorhead, 175);
+ }
+ victim->RagDoll(0);
+ XYZ relative;
+ relative = facing;
+ relative.y = 0;
+ Normalise(&relative);
+ relative = DoRotation(relative, 0, -90, 0);
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velocity += relative * damagemult * 40;
+ }
+ victim->jointVel(head) += relative * damagemult * 200;
+ victim->Puff(head);
+ victim->DoDamage(damagemult * 150 / victim->protectionhead);
+
+ if (victim->damage > victim->damagetolerance)
+ award_bonus(id, style);
+ else
+ SolidHitBonus(id);
+ }
+ }
+
+ if (animTarget == walljumpleftkickanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+ if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && Animation::animations[victim->animTarget].height != lowheight) {
+ escapednum = 0;
+ if (id == 0)
+ camerashake += .4;
+ victim->spurt = 1;
+ DoBlood(.2, 250);
+ if (tutoriallevel != 1) {
+ emit_sound_at(heavyimpactsound, victim->coords, 160.);
+ }
+ if (creature == wolftype) {
+ emit_sound_at(clawslicesound, victim->coords, 128.);
+ victim->spurt = 1;
+ victim->DoBloodBig(2 / victim->armorhead, 175);
+ }
+ victim->RagDoll(0);
+ XYZ relative;
+ relative = facing;
+ relative.y = 0;
+ Normalise(&relative);
+ relative = DoRotation(relative, 0, 90, 0);
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velocity += relative * damagemult * 40;
+ }
+ victim->jointVel(head) += relative * damagemult * 200;
+ victim->Puff(head);
+ victim->DoDamage(damagemult * 150 / victim->protectionhead);
+
+ if (victim->damage > victim->damagetolerance)
+ award_bonus(id, style);
+ else
+ SolidHitBonus(id);
+ }
+ }
+
+ if (animTarget == blockhighleftstrikeanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+ if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && Animation::animations[victim->animTarget].height != lowheight) {
+ escapednum = 0;
+ if (id == 0)
+ camerashake += .4;
+ if (Random() % 2) {
+ victim->spurt = 1;
+ DoBlood(.2, 235);
+ }
+ emit_sound_at(whooshhitsound, victim->coords);
+ victim->RagDoll(0);
+ XYZ relative;
+ relative = victim->coords - coords;
+ relative.y = 0;
+ Normalise(&relative);
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velocity += relative * damagemult * 30;
+ }
+ victim->jointVel(head) += relative * damagemult * 100;
+ victim->Puff(head);
+ victim->DoDamage(damagemult * 50 / victim->protectionhead);
+ }
+ }
+
+ if (animTarget == killanim && Animation::animations[animTarget].frames[frameCurrent].label == 8) {
+ if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && victim->dead) {
+ escapednum = 0;
+ if (id == 0)
+ camerashake += .2;
+ emit_sound_at(whooshhitsound, victim->coords, 128.);
+
+ victim->skeleton.longdead = 0;
+ victim->skeleton.free = 1;
+ victim->skeleton.broken = 0;
+ victim->skeleton.spinny = 1;
+
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velchange = 0;
+ victim->skeleton.joints[i].delay = 0;
+ victim->skeleton.joints[i].locked = 0;
+ //victim->skeleton.joints[i].velocity=0;
+ }
+
+ XYZ relative;
+ relative = 0;
+ relative.y = 1;
+ Normalise(&relative);
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velocity.y = relative.y * 10;
+ victim->skeleton.joints[i].position.y += relative.y * .3;
+ victim->skeleton.joints[i].oldposition.y += relative.y * .3;
+ victim->skeleton.joints[i].realoldposition.y += relative.y * .3;
+ }
+ victim->Puff(abdomen);
+ victim->jointVel(abdomen).y = relative.y * 400;
+ }
+ }
+
+ if (animTarget == killanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+ if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 9 && victim->dead) {
+ escapednum = 0;
+ if (id == 0)
+ camerashake += .4;
+ if (tutoriallevel != 1) {
+ emit_sound_at(heavyimpactsound, coords, 128.);
+ }
+ XYZ relative;
+ relative = victim->coords - coords;
+ relative.y = 0;
+ Normalise(&relative);
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velocity += relative * damagemult * 90;
+ }
+ victim->Puff(abdomen);
+ if (victim->dead != 2 && victim->permanentdamage > victim->damagetolerance - 250 && autoslomo) {
+ slomo = 1;
+ slomodelay = .2;
+ }
+ victim->DoDamage(damagemult * 500 / victim->protectionhigh);
+ victim->jointVel(abdomen) += relative * damagemult * 300;
+ }
+ }
+
+ if (animTarget == dropkickanim && Animation::animations[animTarget].frames[frameCurrent].label == 7) {
+ if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 9 && victim->skeleton.free) {
+ escapednum = 0;
+ if (id == 0)
+ camerashake += .4;
+ if (tutoriallevel != 1) {
+ emit_sound_at(thudsound, coords);
+ }
+
+ victim->skeleton.longdead = 0;
+ victim->skeleton.free = 1;
+ victim->skeleton.broken = 0;
+ victim->skeleton.spinny = 1;
+
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velchange = 0;
+ //victim->skeleton.joints[i].delay=0;
+ victim->skeleton.joints[i].locked = 0;
+ }
+ XYZ relative;
+ relative = victim->coords - coords;
+ Normalise(&relative);
+ relative.y += .3;
+ Normalise(&relative);
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velocity += relative * damagemult * 20;
+ }
+ if (!victim->dead)
+ SolidHitBonus(id);
+
+ victim->Puff(abdomen);
+ victim->DoDamage(damagemult * 20 / victim->protectionhigh);
+ victim->jointVel(abdomen) += relative * damagemult * 200;
+ staggerdelay = .5;
+ if (!victim->dead)
+ staggerdelay = 1.2;
+
+
+ }
+ }
+
+ if ((animTarget == crouchstabanim || animTarget == swordgroundstabanim) && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+
+ if (hasvictim)
+ if (!victim->skeleton.free)
+ hasvictim = 0;
+
+ if (!hasvictim) {
+ terrain.MakeDecal(blooddecalfast, (weapons[weaponids[weaponactive]].tippoint * .8 + weapons[weaponids[weaponactive]].position * .2), .08, .6, Random() % 360);
+ emit_sound_at(knifesheathesound, coords, 128.);
+ }
+
+ if (victim && hasvictim) {
+ if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3) {
+
+ XYZ where, startpoint, endpoint, movepoint, colpoint;
+ float rotationpoint;
+ int whichtri;
+ if (weapons[weaponids[weaponactive]].getType() == knife) {
+ where = (weapons[weaponids[weaponactive]].tippoint * .6 + weapons[weaponids[weaponactive]].position * .4);
+ where -= victim->coords;
+ if (!victim->skeleton.free)
+ where = DoRotation(where, 0, -victim->yaw, 0);
+ //where=scale;
+ startpoint = where;
+ startpoint.y += 100;
+ endpoint = where;
+ endpoint.y -= 100;
+ }
+ if (weapons[weaponids[weaponactive]].getType() == sword) {
+ where = weapons[weaponids[weaponactive]].position;
+ where -= victim->coords;
+ if (!victim->skeleton.free)
+ where = DoRotation(where, 0, -victim->yaw, 0);
+ startpoint = where;
+ where = weapons[weaponids[weaponactive]].tippoint;
+ where -= victim->coords;
+ if (!victim->skeleton.free)
+ where = DoRotation(where, 0, -victim->yaw, 0);
+ endpoint = where;
+ }
+ if (weapons[weaponids[weaponactive]].getType() == staff) {
+ where = weapons[weaponids[weaponactive]].position;
+ where -= victim->coords;
+ if (!victim->skeleton.free)
+ where = DoRotation(where, 0, -victim->yaw, 0);
+ startpoint = where;
+ where = weapons[weaponids[weaponactive]].tippoint;
+ where -= victim->coords;
+ if (!victim->skeleton.free)
+ where = DoRotation(where, 0, -victim->yaw, 0);
+ endpoint = where;
+ }
+ movepoint = 0;
+ rotationpoint = 0;
+ whichtri = victim->skeleton.drawmodel.LineCheck(&startpoint, &endpoint, &colpoint, &movepoint, &rotationpoint);
+
+ if (whichtri != -1) {
+ if (victim->dead != 2) {
+ victim->DoDamage(abs((victim->damagetolerance - victim->permanentdamage) * 2));
+ if (!victim->dead)
+ award_bonus(id, FinishedBonus);
+ }
+ if (bloodtoggle)
+ weapons[weaponids[weaponactive]].bloody = 2;
+
+ victim->skeleton.longdead = 0;
+ victim->skeleton.free = 1;
+ victim->skeleton.broken = 0;
+
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velchange = 0;
+ victim->skeleton.joints[i].locked = 0;
+ //victim->skeleton.joints[i].velocity=0;
+ }
+ emit_sound_at(fleshstabsound, coords, 128);
+
+ }
+ if (whichtri != -1 || weapons[weaponids[weaponactive]].bloody) {
+ weapons[weaponids[weaponactive]].blooddrip += 5;
+ weapons[weaponids[weaponactive]].blooddripdelay = 0;
+ }
+ if (whichtri == -1) {
+ hasvictim = 0;
+ emit_sound_at(knifesheathesound, coords, 128.);
+ }
+ }
+ }
+ }
+
+ if ((animTarget == crouchstabanim || animTarget == swordgroundstabanim) && Animation::animations[animTarget].frames[frameCurrent].label == 6) {
+ if (!hasvictim) {
+ emit_sound_at(knifedrawsound, coords, 128);
+ }
+
+ if (victim && hasvictim) {
+ XYZ footvel, footpoint;
+
+ emit_sound_at(fleshstabremovesound, coords, 128.);
+
+ footvel = 0;
+ footpoint = (weapons[weaponids[weaponactive]].tippoint * .8 + weapons[weaponids[weaponactive]].position * .2);
+
+ if (weapons[weaponids[weaponactive]].getType() == sword) {
+ XYZ where, startpoint, endpoint, movepoint;
+ float rotationpoint;
+ int whichtri;
+
+ where = weapons[weaponids[weaponactive]].position;
+ where -= victim->coords;
+ if (!victim->skeleton.free)
+ where = DoRotation(where, 0, -victim->yaw, 0);
+ startpoint = where;
+ where = weapons[weaponids[weaponactive]].tippoint;
+ where -= victim->coords;
+ if (!victim->skeleton.free)
+ where = DoRotation(where, 0, -victim->yaw, 0);
+ endpoint = where;
+
+ movepoint = 0;
+ rotationpoint = 0;
+ whichtri = victim->skeleton.drawmodel.LineCheck(&startpoint, &endpoint, &footpoint, &movepoint, &rotationpoint);
+ footpoint += victim->coords;
+
+ if (whichtri == -1) {
+ footpoint = (weapons[weaponids[weaponactive]].tippoint * .8 + weapons[weaponids[weaponactive]].position * .2);
+ }
+ }
+ if (weapons[weaponids[weaponactive]].getType() == staff) {
+ XYZ where, startpoint, endpoint, movepoint;
+ float rotationpoint;
+ int whichtri;
+
+ where = weapons[weaponids[weaponactive]].position;
+ where -= victim->coords;
+ if (!victim->skeleton.free)
+ where = DoRotation(where, 0, -victim->yaw, 0);
+ startpoint = where;
+ where = weapons[weaponids[weaponactive]].tippoint;
+ where -= victim->coords;
+ if (!victim->skeleton.free)
+ where = DoRotation(where, 0, -victim->yaw, 0);
+ endpoint = where;
+
+ movepoint = 0;
+ rotationpoint = 0;
+ whichtri = victim->skeleton.drawmodel.LineCheck(&startpoint, &endpoint, &footpoint, &movepoint, &rotationpoint);
+ footpoint += victim->coords;
+
+ if (whichtri == -1) {
+ footpoint = (weapons[weaponids[weaponactive]].tippoint * .8 + weapons[weaponids[weaponactive]].position * .2);
+ }
+ }
+ hasvictim = victim->DoBloodBigWhere(2, 220, footpoint);
+ if (hasvictim) {
+ if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3) {
+ victim->skeleton.longdead = 0;
+ victim->skeleton.free = 1;
+ victim->skeleton.broken = 0;
+
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velchange = 0;
+ victim->skeleton.joints[i].locked = 0;
+ //victim->skeleton.joints[i].velocity=0;
+ }
+
+ XYZ relative;
+ relative = 0;
+ relative.y = 10;
+ Normalise(&relative);
+ //victim->Puff(abdomen);
+ if (bloodtoggle)
+ Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .8, .3);
+
+ if (victim->bloodloss < victim->damagetolerance) {
+ victim->bloodloss += 1000;
+ victim->bled = 0;
+ }
+
+ victim->jointVel(abdomen) += relative * damagemult * 20;
+ }
+ }
+ }
+ if (!hasvictim && onterrain) {
+ weapons[weaponids[weaponactive]].bloody = 0;
+ weapons[weaponids[weaponactive]].blooddrip = 0;
+ }
+ }
+
+ if (animTarget == upunchanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+ if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3) {
+ escapednum = 0;
+ if (id == 0)
+ camerashake += .4;
+ if (Random() % 2) {
+ victim->spurt = 1;
+ DoBlood(.2, 235);
+ }
+ if (tutoriallevel != 1) {
+ emit_sound_at(heavyimpactsound, victim->coords, 128);
+ }
+
+ victim->RagDoll(0);
+ XYZ relative;
+ relative = victim->coords - coords;
+ relative.y = 0;
+ Normalise(&relative);
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velocity = relative * 30;
+ }
+ victim->jointVel(head) += relative * damagemult * 150;
+
+ victim->frameTarget = 0;
+ victim->animTarget = staggerbackhardanim;
+ victim->targetyaw = targetyaw + 180;
+ victim->target = 0;
+ victim->stunned = 1;
+
+ victim->Puff(head);
+ victim->Puff(abdomen);
+ victim->DoDamage(damagemult * 60 / victim->protectionhigh);
+
+ SolidHitBonus(id);
+ }
+ }
+
+
+ if (animTarget == winduppunchanim && Animation::animations[animTarget].frames[frameCurrent].label == 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::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::animations[victim->animTarget].height == lowheight) {
+ if (tutoriallevel != 1) {
+ emit_sound_at(whooshhitsound, victim->coords);
+ }
+ } else {
+ if (tutoriallevel != 1) {
+ emit_sound_at(heavyimpactsound, victim->coords);
+ }
+ }
+
+ 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;
+ relative.y = 0;
+ Normalise(&relative);
+ relative.y = .3;
+ Normalise(&relative);
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velocity = relative * 5;
+ }
+ victim->jointVel(abdomen) += relative * damagemult * 400;
+
+ victim->frameTarget = 0;
+ victim->animTarget = staggerbackhardanim;
+ victim->targetyaw = targetyaw + 180;
+ victim->target = 0;
+ victim->stunned = 1;
+
+ victim->Puff(abdomen);
+ victim->DoDamage(damagemult * 60 / victim->protectionhigh);
+
+ SolidHitBonus(id);
+ }
+ }
+
+ if (animTarget == blockhighleftanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+ if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 4) {
+ if (victim->id == 0)
+ camerashake += .4;
+ emit_sound_at(landsound2, victim->coords);
+
+ Puff(righthand);
+ }
+ }
+
+ if (animTarget == swordslashparryanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+ if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 4) {
+ if (victim->id == 0)
+ camerashake += .4;
+
+ if (weaponactive != -1) {
+ if (weapons[victim->weaponids[0]].getType() == staff || weapons[weaponids[0]].getType() == staff) {
+ if (weapons[victim->weaponids[0]].getType() == staff)
+ weapons[victim->weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
+ if (weapons[weaponids[0]].getType() == staff)
+ weapons[weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
+
+ emit_sound_at(swordstaffsound, victim->coords);
+ } else {
+ emit_sound_at(metalhitsound, victim->coords);
+ }
+ }
+
+ //Puff(righthand);
+ }
+ }
+
+ if (animTarget == knifethrowanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+ if (weaponactive != -1) {
+ escapednum = 0;
+ XYZ aim;
+ aim = victim->coords + DoRotation(victim->jointPos(abdomen), 0, victim->yaw, 0) * victim->scale + victim->velocity * findDistance(&victim->coords, &coords) / 50 - (coords + DoRotation(jointPos(righthand), 0, yaw, 0) * scale);
+ Normalise(&aim);
+ weapons[weaponids[0]].thrown(aim * 50);
+ num_weapons--;
+ if (num_weapons) {
+ weaponids[0] = weaponids[num_weapons];
+ }
+ weaponactive = -1;
+ }
+ }
+
+ if (animTarget == knifeslashstartanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+ if (hasvictim)
+ if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 4.5 &&/*Animation::animations[victim->animTarget].height!=lowheight&&*/victim->animTarget != dodgebackanim && victim->animTarget != rollanim) {
+ escapednum = 0;
+ if (tutoriallevel != 1)
+ victim->DoBloodBig(1.5 / victim->armorhigh, 225);
+
+ award_bonus(id, Slicebonus);
+ if (tutoriallevel != 1) {
+ emit_sound_at(knifeslicesound, victim->coords);
+ }
+ //victim->jointVel(abdomen)+=relative*damagemult*200;
+ if (Animation::animations[victim->animTarget].attack && (victim->aitype != playercontrolled || victim->animTarget == knifeslashstartanim) && (victim->creature == rabbittype || victim->deathbleeding <= 0)) {
+ if (victim->id != 0 || difficulty == 2) {
+ victim->frameTarget = 0;
+ victim->animTarget = staggerbackhardanim;
+ victim->targetyaw = targetyaw + 180;
+ victim->target = 0;
+ }
+ }
+ victim->lowreversaldelay = 0;
+ victim->highreversaldelay = 0;
+ if (aitype != playercontrolled)
+ weaponmissdelay = .6;
+
+ if (tutoriallevel != 1)
+ if (bloodtoggle && !weapons[weaponids[weaponactive]].bloody)
+ weapons[weaponids[weaponactive]].bloody = 1;
+ if (tutoriallevel != 1)
+ weapons[weaponids[weaponactive]].blooddrip += 3;
+
+ XYZ footvel, footpoint;
+ footvel = 0;
+ if (skeleton.free) {
+ footpoint = (victim->jointPos(abdomen) + victim->jointPos(neck)) / 2 * victim->scale + victim->coords;
+ } else {
+ footpoint = DoRotation((victim->jointPos(abdomen) + victim->jointPos(neck)) / 2, 0, victim->yaw, 0) * victim->scale + victim->coords;
+ }
+ if (tutoriallevel != 1) {
+ if (bloodtoggle)
+ Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .6, .3);
+ footvel = DoRotation(facing, 0, 90, 0) * .8;
+ //footvel.y-=.3;
+ Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 7, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
+ Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 3, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
+ Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 5, 1, 1, 1, .2, 1);
+ Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 2, 1, 1, 1, .2, 1);
+ }
+ if (tutoriallevel == 1) {
+ Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 1, 1, .6, .3);
+ }
+ victim->DoDamage(damagemult * 0);
+ }
+ }
+ if (animTarget == swordslashanim && Animation::animations[animTarget].frames[frameCurrent].label == 5 && victim->animTarget != rollanim) {
+ if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 6.5 && victim->animTarget != dodgebackanim) {
+ if (victim->weaponactive == -1 || normaldotproduct(victim->facing, victim->coords - coords) > 0 || (Random() % 2 == 0)) {
+ award_bonus(id, Slashbonus);
+ escapednum = 0;
+ if (tutoriallevel != 1) {
+ if (normaldotproduct(victim->facing, victim->coords - coords) < 0)
+ victim->DoBloodBig(2 / victim->armorhigh, 190);
+ else
+ victim->DoBloodBig(2 / victim->armorhigh, 185);
+ victim->deathbleeding = 1;
+ emit_sound_at(swordslicesound, victim->coords);
+ }
+ //victim->jointVel(abdomen)+=relative*damagemult*200;
+ if (tutoriallevel != 1) {
+ victim->frameTarget = 0;
+ victim->animTarget = staggerbackhardanim;
+ victim->targetyaw = targetyaw + 180;
+ victim->target = 0;
+ }
+
+ if (tutoriallevel != 1) {
+ if (bloodtoggle && !weapons[weaponids[weaponactive]].bloody)
+ weapons[weaponids[weaponactive]].bloody = 1;
+ weapons[weaponids[weaponactive]].blooddrip += 3;
+
+ float bloodlossamount;
+ bloodlossamount = 200 + abs((float)(Random() % 40)) - 20;
+ victim->bloodloss += bloodlossamount / victim->armorhigh;
+ //victim->bloodloss+=100*(6.5-distsq(&coords,&victim->coords));
+ victim->DoDamage(damagemult * 0);
+
+ XYZ footvel, footpoint;
+ footvel = 0;
+ if (skeleton.free) {
+ footpoint = (victim->jointPos(abdomen) + victim->jointPos(neck)) / 2 * victim->scale + victim->coords;
+ } else {
+ footpoint = DoRotation((victim->jointPos(abdomen) + victim->jointPos(neck)) / 2, 0, victim->yaw, 0) * victim->scale + victim->coords;
+ }
+ if (bloodtoggle)
+ Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .9, .3);
+ footvel = DoRotation(facing, 0, 90, 0) * .8;
+ footvel.y -= .3;
+ Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 7, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
+ Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 3, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
+ Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 5, 1, 1, 1, .3, 1);
+ Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 2, 1, 1, 1, .3, 1);
+ }
+ } else {
+ if (victim->weaponactive != -1) {
+ if (weapons[victim->weaponids[0]].getType() == staff || weapons[weaponids[0]].getType() == staff) {
+ if (weapons[victim->weaponids[0]].getType() == staff)
+ weapons[victim->weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
+ if (weapons[weaponids[0]].getType() == staff)
+ weapons[weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
+
+ emit_sound_at(swordstaffsound, victim->coords);
+ } else {
+ emit_sound_at(metalhitsound, victim->coords);
+ }
+ }
+
+
+ XYZ aim;
+ victim->Puff(righthand);
+ victim->target = 0;
+ victim->frameTarget = 0;
+ victim->animTarget = staggerbackhighanim;
+ victim->targetyaw = targetyaw + 180;
+ victim->target = 0;
+ aim = DoRotation(facing, 0, 90, 0) * 21;
+ aim.y += 7;
+ weapons[victim->weaponids[0]].drop(aim * -.2, aim);
+ victim->num_weapons--;
+ if (victim->num_weapons) {
+ victim->weaponids[0] = victim->weaponids[num_weapons];
+ if (victim->weaponstuck == victim->num_weapons)
+ victim->weaponstuck = 0;
+ }
+ victim->weaponactive = -1;
+ for (unsigned i = 0; i < Person::players.size(); i++) {
+ Person::players[i]->wentforweapon = 0;
+ }
+
+ }
+ }
+ }
+
+ if (animTarget == staffhitanim && Animation::animations[animTarget].frames[frameCurrent].label == 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;
+ escapednum = 0;
+ if (id == 0)
+ camerashake += .4;
+ if (Random() % 2 || creature == wolftype) {
+ victim->spurt = 1;
+ }
+ emit_sound_at(staffheadsound, victim->coords);
+ }
+ victim->RagDoll(0);
+ XYZ relative;
+ relative = victim->coords - coords;
+ relative.y = 0;
+ Normalise(&relative);
+ relative = DoRotation(relative, 0, 90, 0);
+ relative.y -= 1;
+ Normalise(&relative);
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velocity += relative * damagemult * 60;
+ }
+ victim->jointVel(head) += relative * damagemult * 230;
+ victim->jointVel(neck) += relative * damagemult * 230;
+ victim->Puff(head);
+ if (tutoriallevel != 1) {
+ victim->DoDamage(damagemult * 120 / victim->protectionhigh);
+
+ award_bonus(id, solidhit, 30);
+ }
+ }
+ }
+
+ if (animTarget == staffspinhitanim && Animation::animations[animTarget].frames[frameCurrent].label == 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;
+ escapednum = 0;
+ if (id == 0)
+ camerashake += .4;
+ if (Random() % 2 || creature == wolftype) {
+ victim->spurt = 1;
+ }
+ emit_sound_at(staffheadsound, victim->coords);
+ }
+ victim->RagDoll(0);
+ XYZ relative;
+ relative = victim->coords - coords;
+ relative.y = 0;
+ Normalise(&relative);
+ relative = DoRotation(relative, 0, -90, 0);
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velocity += relative * damagemult * 40;
+ }
+ victim->jointVel(head) += relative * damagemult * 220;
+ victim->jointVel(neck) += relative * damagemult * 220;
+ victim->Puff(head);
+ if (tutoriallevel != 1) {
+ victim->DoDamage(damagemult * 350 / victim->protectionhead);
+
+ award_bonus(id, solidhit, 60);
+ }
+ }
+ }
+
+ if (animTarget == staffgroundsmashanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+ if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 6.5) {
+ escapednum = 0;
+ if (tutoriallevel != 1) {
+ if (!victim->dead)
+ weapons[weaponids[0]].damage += .4 + float(abs(Random() % 100) - 50) / 500;
+ if (id == 0)
+ camerashake += .4;
+ if (Random() % 2 || creature == wolftype) {
+ victim->spurt = 1;
+ }
+ emit_sound_at(staffbodysound, victim->coords);
+ }
+ victim->skeleton.longdead = 0;
+ victim->skeleton.free = 1;
+ victim->skeleton.broken = 0;
+
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velchange = 0;
+ victim->skeleton.joints[i].locked = 0;
+ //victim->skeleton.joints[i].velocity=0;
+ }
+
+ victim->RagDoll(0);
+ XYZ relative;
+ relative = 0;
+ relative.y = -1;
+ Normalise(&relative);
+ if (!victim->dead) {
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velocity = relative * damagemult * 40;
+ }
+ victim->jointVel(abdomen) += relative * damagemult * 40;
+ }
+ if (victim->dead) {
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velocity = relative * damagemult * abs(Random() % 20);
+ }
+ }
+ victim->Puff(abdomen);
+ if (tutoriallevel != 1) {
+ victim->DoDamage(damagemult * 100 / victim->protectionhigh);
+
+ if (!victim->dead) {
+ award_bonus(id, solidhit, 40);
+ }
+ }
+ }
+ }
+
+ if (animTarget == lowkickanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+ if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && Animation::animations[victim->animTarget].height != highheight) {
+ escapednum = 0;
+ if (id == 0)
+ camerashake += .4;
+ XYZ relative;
+ relative = victim->coords - coords;
+ relative.y = 0;
+ Normalise(&relative);
+
+ SolidHitBonus(id);
+
+ if (Animation::animations[victim->animTarget].height == lowheight) {
+ if (Random() % 2) {
+ victim->spurt = 1;
+ DoBlood(.2, 250);
+ }
+ victim->RagDoll(0);
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velocity += relative * damagemult * 40;
+ }
+ victim->jointVel(head) += relative * damagemult * 200;
+ if (tutoriallevel != 1) {
+ emit_sound_at(heavyimpactsound, victim->coords, 128.);
+ }
+ victim->Puff(head);
+ victim->DoDamage(damagemult * 100 / victim->protectionhead);
+ if (victim->howactive == typesleeping)
+ victim->DoDamage(damagemult * 150 / victim->protectionhead);
+ if (creature == wolftype) {
+ emit_sound_at(clawslicesound, victim->coords, 128.);
+ victim->spurt = 1;
+ victim->DoBloodBig(2 / victim->armorhead, 175);
+ }
+ } else {
+ if (victim->damage >= victim->damagetolerance)
+ victim->RagDoll(0);
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velocity += relative * damagemult * 10;
+ }
+ victim->jointVel(abdomen) += relative * damagemult * 200;
+ victim->frameTarget = 0;
+ victim->animTarget = staggerbackhighanim;
+ victim->targetyaw = targetyaw + 180;
+ victim->target = 0;
+ if (tutoriallevel != 1) {
+ emit_sound_at(landsound2, victim->coords, 128.);
+ }
+ victim->Puff(abdomen);
+ victim->DoDamage(damagemult * 30 / victim->protectionhigh);
+ if (creature == wolftype) {
+ emit_sound_at(clawslicesound, victim->coords, 128.);
+ victim->spurt = 1;
+ victim->DoBloodBig(2 / victim->armorhigh, 170);
+ }
+ }
+
+ }
+ }
+
+ if (animTarget == sweepanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+ if ((victim->animTarget != jumpupanim) &&
+ (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3) &&
+ (victim != this->shared_from_this())) {
+ escapednum = 0;
+ if (id == 0)
+ camerashake += .2;
+ if (tutoriallevel != 1) {
+ emit_sound_at(landsound2, victim->coords, 128.);
+ }
+ XYZ relative;
+ relative = victim->coords - coords;
+ relative.y = 0;
+ Normalise(&relative);
+
+ 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.joints.size(); i++) {
+ victim->skeleton.joints[i].velocity += relative * damagemult * 15;
+ }
+ relative = DoRotation(relative, 0, -90, 0);
+ relative.y += .1;
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ if (victim->skeleton.joints[i].label == leftfoot || victim->skeleton.joints[i].label == rightfoot || victim->skeleton.joints[i].label == leftankle || victim->skeleton.joints[i].label == rightankle)
+ victim->skeleton.joints[i].velocity = relative * 80;
+ }
+ victim->Puff(rightankle);
+ victim->Puff(leftankle);
+ victim->DoDamage(damagemult * 40 / victim->protectionlow);
+ } else {
+ if (victim->damage >= victim->damagetolerance)
+ victim->RagDoll(0);
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velocity += relative * damagemult * 10;
+ }
+ relative = DoRotation(relative, 0, -90, 0);
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ if (victim->skeleton.joints[i].label == leftfoot || victim->skeleton.joints[i].label == rightfoot || victim->skeleton.joints[i].label == leftankle || victim->skeleton.joints[i].label == rightankle)
+ victim->skeleton.joints[i].velocity += relative * damagemult * 80;
+ }
+ victim->jointVel(abdomen) += relative * damagemult * 200;
+ victim->frameTarget = 0;
+ victim->animTarget = staggerbackhighanim;
+ victim->targetyaw = targetyaw + 180;
+ victim->target = 0;
+ if (tutoriallevel != 1) {
+ emit_sound_at(landsound2, victim->coords, 128.);
+ }
+ victim->Puff(abdomen);
+ victim->DoDamage(damagemult * 30 / victim->protectionlow);
+ }
+
+ SolidHitBonus(id);
+
+ }
+ }
+ }
+ if (Animation::animations[animTarget].attack == reversal && (!victim->feint || (victim->lastattack == victim->lastattack2 && victim->lastattack2 == victim->lastattack3 && Random() % 2) || animTarget == knifefollowanim)) {
+ if (animTarget == spinkickreversalanim && Animation::animations[animTarget].frames[frameCurrent].label == 7) {
+ escapednum = 0;
+ if (id == 0)
+ camerashake += .4;
+ if (Random() % 2) {
+ victim->spurt = 1;
+ DoBlood(.2, 230);
+ }
+ if (tutoriallevel != 1) {
+ emit_sound_at(heavyimpactsound, victim->coords, 128.);
+ }
+ if (creature == wolftype) {
+ emit_sound_at(clawslicesound, victim->coords, 128);
+ victim->spurt = 1;
+ victim->DoBloodBig(2 / victim->armorhigh, 170);
+ }
+ victim->RagDoll(0);
+ XYZ relative;
+ relative = victim->coords - oldcoords;
+ relative.y = 0;
+ Normalise(&relative);
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velocity += relative * damagemult * 40;
+ }
+ victim->jointVel(abdomen) += relative * damagemult * 200;
+ victim->Puff(abdomen);
+ victim->DoDamage(damagemult * 150 / victim->protectionhigh);
+
+ award_bonus(id, Reversal);
+ }
+
+ if ((animTarget == swordslashreversalanim || animTarget == knifeslashreversalanim || animTarget == staffhitreversalanim || animTarget == staffspinhitreversalanim) && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+ if (victim->weaponactive != -1 && victim->num_weapons > 0) {
+ if (weapons[victim->weaponids[victim->weaponactive]].owner == int(victim->id)) {
+ takeWeapon(victim->weaponids[victim->weaponactive]);
+ victim->num_weapons--;
+ if (victim->num_weapons > 0) {
+ victim->weaponids[victim->weaponactive] = victim->weaponids[victim->num_weapons];
+ }
+ victim->weaponactive = -1;
+ }
+ }
+ }
+
+ if (animTarget == staffhitreversalanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+ escapednum = 0;
+ if (id == 0)
+ camerashake += .4;
+ if (Random() % 2) {
+ victim->spurt = 1;
+ DoBlood(.2, 230);
+ }
+ emit_sound_at(whooshhitsound, victim->coords, 128.);
+ victim->RagDoll(0);
+ XYZ relative;
+ relative = victim->coords - oldcoords;
+ relative.y = 0;
+ Normalise(&relative);
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velocity += relative * damagemult * 30;
+ }
+ victim->jointVel(abdomen) += relative * damagemult * 200;
+ victim->Puff(head);
+ victim->DoDamage(damagemult * 70 / victim->protectionhigh);
+ }
+
+ if (animTarget == staffspinhitreversalanim && Animation::animations[animTarget].frames[frameCurrent].label == 7) {
+ escapednum = 0;
+ if (id == 0)
+ camerashake += .4;
+ if (Random() % 2) {
+ victim->spurt = 1;
+ DoBlood(.2, 230);
+ }
+
+ award_bonus(id, staffreversebonus);
+
+ if (tutoriallevel != 1) {
+ emit_sound_at(heavyimpactsound, victim->coords, 128.);
+ }
+ victim->RagDoll(0);
+ award_bonus(id, staffreversebonus); // Huh, again?
+
+ XYZ relative;
+ relative = victim->coords - oldcoords;
+ relative.y = 0;
+ Normalise(&relative);
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velocity += relative * damagemult * 30;
+ }
+ victim->jointVel(abdomen) += relative * damagemult * 200;
+ victim->Puff(head);
+ victim->DoDamage(damagemult * 70 / victim->protectionhigh);
+ }
+
+ if (animTarget == upunchreversalanim && Animation::animations[animTarget].frames[frameCurrent].label == 7) {
+ escapednum = 0;
+ victim->RagDoll(1);
+ XYZ relative;
+ relative = facing;
+ relative.y = 0;
+ Normalise(&relative);
+ relative.y -= .1;
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velocity += relative * damagemult * 70;
+ }
+ victim->jointVel(lefthand) *= .1;
+ victim->jointVel(leftwrist) *= .2;
+ victim->jointVel(leftelbow) *= .5;
+ victim->jointVel(leftshoulder) *= .7;
+ victim->jointVel(righthand) *= .1;
+ victim->jointVel(rightwrist) *= .2;
+ victim->jointVel(rightelbow) *= .5;
+ victim->jointVel(rightshoulder) *= .7;
+
+ victim->Puff(abdomen);
+ victim->DoDamage(damagemult * 90 / victim->protectionhigh);
+
+ award_bonus(id, Reversal);
+
+ bool doslice;
+ doslice = 0;
+ if (weaponactive != -1 || creature == wolftype)
+ doslice = 1;
+ if (creature == rabbittype && weaponactive != -1)
+ if (weapons[weaponids[0]].getType() == staff)
+ doslice = 0;
+ if (doslice) {
+ if (weaponactive != -1) {
+ victim->DoBloodBig(2 / victim->armorhigh, 225);
+ emit_sound_at(knifeslicesound, victim->coords);
+ if (bloodtoggle && !weapons[weaponids[weaponactive]].bloody)
+ weapons[weaponids[weaponactive]].bloody = 1;
+ weapons[weaponids[weaponactive]].blooddrip += 3;
+ }
+ if (weaponactive == -1 && creature == wolftype) {
+ emit_sound_at(clawslicesound, victim->coords, 128.);
+ victim->spurt = 1;
+ victim->DoBloodBig(2 / victim->armorhigh, 175);
+ }
+ }
+ }
+
+
+
+ if (animTarget == swordslashreversalanim && Animation::animations[animTarget].frames[frameCurrent].label == 7) {
+ escapednum = 0;
+ victim->RagDoll(1);
+ XYZ relative;
+ relative = facing;
+ relative.y = 0;
+ Normalise(&relative);
+ relative.y -= .1;
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velocity += relative * damagemult * 70;
+ }
+ victim->jointVel(lefthand) *= .1 - 1;
+ victim->jointVel(leftwrist) *= .2 - 1;
+ victim->jointVel(leftelbow) *= .5 - 1;
+ victim->jointVel(leftshoulder) *= .7 - 1;
+ victim->jointVel(righthand) *= .1 - 1;
+ victim->jointVel(rightwrist) *= .2 - 1;
+ victim->jointVel(rightelbow) *= .5 - 1;
+ victim->jointVel(rightshoulder) *= .7 - 1;
+
+ award_bonus(id, swordreversebonus);
+ }
+
+ if (hasvictim && animTarget == knifeslashreversalanim && Animation::animations[animTarget].frames[frameCurrent].label == 7) {
+ escapednum = 0;
+ if (id == 0)
+ camerashake += .4;
+ if (Random() % 2) {
+ victim->spurt = 1;
+ DoBlood(.2, 230);
+ }
+ if (tutoriallevel != 1) {
+ emit_sound_at(heavyimpactsound, victim->coords, 128.);
+ }
+ victim->RagDoll(0);
+ XYZ relative;
+ relative = victim->coords - oldcoords;
+ relative.y = 0;
+ Normalise(&relative);
+ relative = DoRotation(relative, 0, -90, 0);
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velocity += relative * damagemult * 40;
+ }
+ victim->jointVel(abdomen) += relative * damagemult * 200;
+ victim->Puff(abdomen);
+ victim->DoDamage(damagemult * 30 / victim->protectionhigh);
+
+ award_bonus(id, Reversal);
+ }
+
+ if (hasvictim && animTarget == sneakattackanim && Animation::animations[animTarget].frames[frameCurrent].label == 7) {
+ escapednum = 0;
+ victim->RagDoll(0);
+ victim->skeleton.spinny = 0;
+ XYZ relative;
+ relative = facing * -1;
+ relative.y = -3;
+ Normalise(&relative);
+ if (victim->id == 0)
+ relative /= 30;
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velocity += relative * damagemult * 40;
+ }
+ victim->damage = victim->damagetolerance;
+ victim->permanentdamage = victim->damagetolerance - 1;
+ bool doslice;
+ doslice = 0;
+ if (weaponactive != -1 || creature == wolftype)
+ doslice = 1;
+ if (creature == rabbittype && weaponactive != -1)
+ if (weapons[weaponids[0]].getType() == staff)
+ doslice = 0;
+ if (doslice) {
+ if (weaponactive != -1) {
+ victim->DoBloodBig(200, 225);
+ emit_sound_at(knifeslicesound, victim->coords);
+ if (bloodtoggle)
+ weapons[weaponids[weaponactive]].bloody = 2;
+ weapons[weaponids[weaponactive]].blooddrip += 5;
+ }
+
+ if (creature == wolftype && weaponactive == -1) {
+ emit_sound_at(clawslicesound, victim->coords, 128.);
+ victim->spurt = 1;
+ victim->DoBloodBig(2, 175);
+ }
+ }
+ award_bonus(id, spinecrusher);
+ }
+
+ if (hasvictim && (animTarget == knifefollowanim || animTarget == knifesneakattackanim) && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+ if (weaponactive != -1 && victim->bloodloss < victim->damagetolerance) {
+ escapednum = 0;
+ if (animTarget == knifefollowanim)
+ victim->DoBloodBig(200, 210);
+ if (animTarget == knifesneakattackanim) {
+ XYZ footvel, footpoint;
+ footvel = 0;
+ footpoint = weapons[weaponids[0]].tippoint;
+ if (bloodtoggle)
+ Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .9, .3);
+ footvel = (weapons[weaponids[0]].tippoint - weapons[weaponids[0]].position);
+ Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 7, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
+ Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 3, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
+ Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 5, 1, 1, 1, .3, 1);
+ Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 2, 1, 1, 1, .3, 1);
+ victim->DoBloodBig(200, 195);
+ award_bonus(id, tracheotomy);
+ }
+ if (animTarget == knifefollowanim) {
+ award_bonus(id, Stabbonus);
+ XYZ footvel, footpoint;
+ footvel = 0;
+ footpoint = weapons[weaponids[0]].tippoint;
+ if (bloodtoggle)
+ Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .9, .3);
+ footvel = (weapons[weaponids[0]].tippoint - weapons[weaponids[0]].position) * -1;
+ Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 7, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
+ Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 3, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
+ Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 5, 1, 1, 1, .2, 1);
+ Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 2, 1, 1, 1, .2, 1);
+
+ }
+ victim->bloodloss += 10000;
+ victim->velocity = 0;
+ emit_sound_at(fleshstabsound, victim->coords);
+ if (bloodtoggle)
+ weapons[weaponids[weaponactive]].bloody = 2;
+ weapons[weaponids[weaponactive]].blooddrip += 5;
+ }
+ }
+
+ if (hasvictim && (animTarget == knifefollowanim || animTarget == knifesneakattackanim) && Animation::animations[animTarget].frames[frameCurrent].label == 6) {
+ escapednum = 0;
+ victim->velocity = 0;
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velocity = 0;
+ }
+ if (animTarget == knifefollowanim) {
+ victim->RagDoll(0);
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velocity = 0;
+ }
+ }
+ if (weaponactive != -1 && Animation::animations[victim->animTarget].attack != reversal) {
+ emit_sound_at(fleshstabremovesound, victim->coords);
+ if (bloodtoggle)
+ weapons[weaponids[weaponactive]].bloody = 2;
+ weapons[weaponids[weaponactive]].blooddrip += 5;
+
+ XYZ footvel, footpoint;
+ footvel = 0;
+ footpoint = weapons[weaponids[0]].tippoint;
+ if (bloodtoggle)
+ Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .9, .3);
+ footvel = (weapons[weaponids[0]].tippoint - weapons[weaponids[0]].position) * -1;
+ Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 7, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
+ Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 3, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
+ Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 5, 1, 1, 1, .3, 1);
+ Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 2, 1, 1, 1, .3, 1);
+ }
+ }
+
+ if (hasvictim && (animTarget == swordsneakattackanim) && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
+ if (weaponactive != -1 && victim->bloodloss < victim->damagetolerance) {
+ award_bonus(id, backstab);
+
+ escapednum = 0;
+
+ XYZ footvel, footpoint;
+ footvel = 0;
+ footpoint = (weapons[weaponids[0]].tippoint + weapons[weaponids[0]].position) / 2;
+ if (bloodtoggle)
+ Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .9, .3);
+ footvel = (weapons[weaponids[0]].tippoint - weapons[weaponids[0]].position);
+ Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 7, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
+ Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 3, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
+ Sprite::MakeSprite(bloodflamesprite, footpoint, DoRotation(footvel * 5, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .3, 1);
+ Sprite::MakeSprite(bloodflamesprite, footpoint, DoRotation(footvel * 3, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .3, 1);
+ victim->DoBloodBig(200, 180);
+ victim->DoBloodBig(200, 215);
+ victim->bloodloss += 10000;
+ victim->velocity = 0;
+ emit_sound_at(fleshstabsound, victim->coords);
+ if (bloodtoggle)
+ weapons[weaponids[weaponactive]].bloody = 2;
+ weapons[weaponids[weaponactive]].blooddrip += 5;
+ }
+ }
+
+ if (hasvictim && animTarget == swordsneakattackanim && Animation::animations[animTarget].frames[frameCurrent].label == 6) {
+ escapednum = 0;
+ victim->velocity = 0;
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velocity = 0;
+ }
+ if (weaponactive != -1) {
+ emit_sound_at(fleshstabremovesound, victim->coords);
+ if (bloodtoggle)
+ weapons[weaponids[weaponactive]].bloody = 2;
+ weapons[weaponids[weaponactive]].blooddrip += 5;
+
+ XYZ footvel, footpoint;
+ footvel = 0;
+ footpoint = weapons[weaponids[0]].tippoint;
+ if (bloodtoggle)
+ Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .9, .3);
+ footvel = (weapons[weaponids[0]].tippoint - weapons[weaponids[0]].position) * -1;
+ Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 7, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
+ Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 3, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
+ Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 5, 1, 1, 1, .3, 1);
+ Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 2, 1, 1, 1, .3, 1);
+ }
+ }
+
+ if (animTarget == sweepreversalanim && Animation::animations[animTarget].frames[frameCurrent].label == 7) {
+ escapednum = 0;
+ if (id == 0)
+ camerashake += .4;
+ if (Random() % 2) {
+ victim->spurt = 1;
+ DoBlood(.2, 240);
+ }
+ if (weaponactive == -1) {
+ if (tutoriallevel != 1) {
+ emit_sound_at(heavyimpactsound, victim->coords, 128.);
+ }
+ }
+ bool doslice;
+ doslice = 0;
+ if (weaponactive != -1 || creature == wolftype)
+ doslice = 1;
+ if (creature == rabbittype && weaponactive != -1)
+ if (weapons[weaponids[0]].getType() == staff)
+ doslice = 0;
+ if (doslice) {
+ if (weaponactive != -1) {
+ victim->DoBloodBig(2 / victim->armorhead, 225);
+ emit_sound_at(knifeslicesound, victim->coords);
+ if (bloodtoggle && !weapons[weaponids[weaponactive]].bloody)
+ weapons[weaponids[weaponactive]].bloody = 1;
+ weapons[weaponids[weaponactive]].blooddrip += 3;
+ }
+ if (weaponactive == -1 && creature == wolftype) {
+ emit_sound_at(clawslicesound, victim->coords, 128.);
+ victim->spurt = 1;
+ victim->DoBloodBig(2 / victim->armorhead, 175);
+ }
+ }
+
+ award_bonus(id, Reversal);
+
+ victim->Puff(neck);
+
+ XYZ relative;
+ relative = facing * -1;
+ relative.y = 0;
+ Normalise(&relative);
+ relative = DoRotation(relative, 0, 90, 0);
+ relative.y = .5;
+ Normalise(&relative);
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velocity += relative * damagemult * 20;
+ }
+ victim->jointVel(head) += relative * damagemult * 200;
+ if (victim->damage < victim->damagetolerance - 100)
+ victim->velocity = relative * 200;
+ victim->DoDamage(damagemult * 100 / victim->protectionhead);
+ victim->velocity = 0;
+ }
+
+ if (animTarget == sweepreversalanim && ((Animation::animations[animTarget].frames[frameCurrent].label == 9 && victim->damage < victim->damagetolerance) || (Animation::animations[animTarget].frames[frameCurrent].label == 7 && victim->damage > victim->damagetolerance))) {
+ escapednum = 0;
+ victim->RagDoll(0);
+ XYZ relative;
+ relative = facing * -1;
+ relative.y = 0;
+ Normalise(&relative);
+ relative = DoRotation(relative, 0, 90, 0);
+ relative.y = .5;
+ Normalise(&relative);
+ for (int i = 0; i < victim->skeleton.joints.size(); i++) {
+ victim->skeleton.joints[i].velocity += relative * damagemult * 20;
+ }
+ victim->jointVel(head) += relative * damagemult * 200;
+ }
+
+ if (hasvictim && (animTarget == spinkickreversalanim || animTarget == sweepreversalanim || animTarget == rabbitkickreversalanim || animTarget == upunchreversalanim || animTarget == jumpreversalanim || animTarget == swordslashreversalanim || animTarget == knifeslashreversalanim || animTarget == rabbittacklereversal || animTarget == wolftacklereversal || animTarget == staffhitreversalanim || animTarget == staffspinhitreversalanim))
+ if (victim->damage > victim->damagetolerance && bonus != reverseko) {
+ award_bonus(id, reverseko);
+ }
+ }
+
+
+ //Animation end
+ if (frameTarget > Animation::animations[animCurrent].frames.size() - 1) {
+ frameTarget = 0;
+ if (wasStop()) {
+ animTarget = getIdle();
+ FootLand(leftfoot, 1);
+ FootLand(rightfoot, 1);
+ }
+ if (animCurrent == rabbittackleanim || animCurrent == rabbittacklinganim) {
+ animTarget = rollanim;
+ frameTarget = 3;
+ emit_sound_at(movewhooshsound, coords, 128.);
+ }
+ if (animCurrent == staggerbackhighanim) {
+ animTarget = getIdle();
+ }
+ if (animCurrent == staggerbackhardanim) {
+ animTarget = getIdle();
+ }
+ if (animCurrent == removeknifeanim) {
+ animTarget = getIdle();
+ }
+ if (animCurrent == crouchremoveknifeanim) {
+ animTarget = getCrouch();
+ }
+ if (animCurrent == backhandspringanim) {
+ animTarget = getIdle();
+ }
+ if (animCurrent == dodgebackanim) {
+ animTarget = getIdle();
+ }
+ if (animCurrent == drawleftanim) {
+ animTarget = getIdle();
+ }
+ if (animCurrent == drawrightanim || animCurrent == crouchdrawrightanim) {
+ animTarget = getIdle();
+ if (animCurrent == crouchdrawrightanim) {
+ animTarget = getCrouch();
+ }
+ if (weaponactive == -1)
+ weaponactive = 0;
+ else if (weaponactive == 0) {
+ weaponactive = -1;
+ if (num_weapons == 2) {
+ int buffer;
+ buffer = weaponids[0];
+ weaponids[0] = weaponids[1];
+ weaponids[1] = buffer;
+ }
+ }
+
+ if (weaponactive == -1) {
+ emit_sound_at(knifesheathesound, coords, 128.);
+ }
+ if (weaponactive != -1) {
+ emit_sound_at(knifedrawsound, coords, 128.);
+ }
+ }
+ if (animCurrent == rollanim) {
+ animTarget = getCrouch();
+ FootLand(leftfoot, 1);
+ FootLand(rightfoot, 1);
+ }
+ if (isFlip()) {
+ if (animTarget == walljumprightkickanim) {
+ targetrot = -190;
+ }
+ if (animTarget == walljumpleftkickanim) {
+ targetrot = 190;
+ }
+ animTarget = jumpdownanim;
+ }
+ if (animCurrent == climbanim) {
+ animTarget = getCrouch();
+ frameTarget = 1;
+ coords += facing * .1;
+ if (!isnormal(coords.x))
+ coords = oldcoords;
+ oldcoords = coords;
+ collided = 0;
+ targetoffset = 0;
+ currentoffset = 0;
+ grabdelay = 1;
+ velocity = 0;
+ collided = 0;
+ avoidcollided = 0;
+ }
+ if (animTarget == rabbitkickreversalanim) {
+ animTarget = getCrouch();
+ lastfeint = 0;
+ }
+ if (animTarget == jumpreversalanim) {
+ animTarget = getCrouch();
+ lastfeint = 0;
+ }
+ if (animTarget == walljumprightanim || animTarget == walljumpbackanim || animTarget == walljumpfrontanim) {
+ if (attackkeydown && animTarget != walljumpfrontanim) {
+ int closest = -1;
+ float closestdist = -1;
+ float distance;
+ if (Person::players.size() > 1)
+ for (unsigned i = 0; i < Person::players.size(); i++) {
+ if (id != i && Person::players[i]->coords.y < coords.y && !Person::players[i]->skeleton.free) {
+ distance = distsq(&Person::players[i]->coords, &coords);
+ if (closestdist == -1 || distance < closestdist) {
+ closestdist = distance;
+ closest = i;
+ }
+ }
+ }
+ if (closestdist > 0 && closest >= 0 && closestdist < 16) {
+ victim = Person::players[closest];
+ animTarget = walljumprightkickanim;
+ frameTarget = 0;
+ XYZ rotatetarget = victim->coords - coords;
+ Normalise(&rotatetarget);
+ yaw = -asin(0 - rotatetarget.x);
+ yaw *= 360 / 6.28;
+ if (rotatetarget.z < 0)
+ yaw = 180 - yaw;
+ targettilt2 = -asin(rotatetarget.y) * 360 / 6.28;
+ velocity = (victim->coords - coords) * 4;
+ velocity.y += 2;
+ transspeed = 40;
+ }
+ }
+ if (animTarget == walljumpbackanim) {
+ animTarget = backflipanim;
+ frameTarget = 3;
+ velocity = facing * -8;
+ velocity.y = 4;
+ if (id == 0)
+ resume_stream(whooshsound);
+ }
+ if (animTarget == walljumprightanim) {
+ animTarget = rightflipanim;
+ frameTarget = 4;
+ targetyaw -= 90;
+ yaw -= 90;
+ velocity = DoRotation(facing, 0, 30, 0) * -8;
+ velocity.y = 4;
+ }
+ if (animTarget == walljumpfrontanim) {
+ animTarget = frontflipanim;
+ frameTarget = 2;
+ //targetyaw-=180;
+ ////yaw-=180;
+ velocity = facing * 8;
+ velocity.y = 4;
+ }
+ if (id == 0)
+ resume_stream(whooshsound);
+ }
+ if (animTarget == walljumpleftanim) {
+ if (attackkeydown) {
+ int closest = -1;
+ float closestdist = -1;
+ float distance;
+ if (Person::players.size() > 1)
+ for (unsigned i = 0; i < Person::players.size(); i++) {
+ if (id != i && Person::players[i]->coords.y < coords.y && !Person::players[i]->skeleton.free) {
+ distance = distsq(&Person::players[i]->coords, &coords);
+ if (closestdist == -1 || distance < closestdist) {
+ closestdist = distance;
+ closest = i;
+ }
+ }
+ }
+ if (closestdist > 0 && closest >= 0 && closestdist < 16) {
+ victim = Person::players[closest];
+ animTarget = walljumpleftkickanim;
+ frameTarget = 0;
+ XYZ rotatetarget = victim->coords - coords;
+ Normalise(&rotatetarget);
+ yaw = -asin(0 - rotatetarget.x);
+ yaw *= 360 / 6.28;
+ if (rotatetarget.z < 0)
+ yaw = 180 - yaw;
+ targettilt2 = -asin(rotatetarget.y) * 360 / 6.28;
+ velocity = (victim->coords - coords) * 4;
+ velocity.y += 2;
+ transspeed = 40;
+ }
+ }
+ if (animTarget != walljumpleftkickanim) {
+ animTarget = leftflipanim;
+ frameTarget = 4;
+ targetyaw += 90;
+ yaw += 90;
+ velocity = DoRotation(facing, 0, -30, 0) * -8;
+ velocity.y = 4;
+ }
+ if (id == 0)
+ resume_stream(whooshsound);
+ }
+ if (animTarget == sneakattackanim) {
+ animCurrent = getCrouch();
+ animTarget = getCrouch();
+ frameTarget = 1;
+ frameCurrent = 0;
+ targetyaw += 180;
+ yaw += 180;
+ targettilt2 *= -1;
+ tilt2 *= -1;
+ transspeed = 1000000;
+ targetheadyaw += 180;
+ coords -= facing * .7;
+ if (onterrain)
+ coords.y = terrain.getHeight(coords.x, coords.z);
+
+ lastfeint = 0;
+ }
+ if (animTarget == knifesneakattackanim || animTarget == swordsneakattackanim) {
+ animTarget = getIdle();
+ frameTarget = 0;
+ if (onterrain)
+ coords.y = terrain.getHeight(coords.x, coords.z);
+
+ lastfeint = 0;
+ }
+ if (animCurrent == knifefollowanim) {
+ animTarget = getIdle();
+ lastfeint = 0;
+ }
+ if (Animation::animations[animTarget].attack == reversal && animCurrent != sneakattackanim && animCurrent != knifesneakattackanim && animCurrent != swordsneakattackanim && animCurrent != knifefollowanim) {
+ float ycoords = oldcoords.y;
+ animTarget = getStop();
+ targetyaw += 180;
+ yaw += 180;
+ targettilt2 *= -1;
+ tilt2 *= -1;
+ transspeed = 1000000;
+ targetheadyaw += 180;
+ if (!isnormal(coords.x))
+ coords = oldcoords;
+ if (animCurrent == spinkickreversalanim || animCurrent == swordslashreversalanim)
+ oldcoords = coords + facing * .5;
+ else if (animCurrent == sweepreversalanim)
+ oldcoords = coords + facing * 1.1;
+ else if (animCurrent == upunchreversalanim) {
+ oldcoords = coords + facing * 1.5;
+ targetyaw += 180;
+ yaw += 180;
+ targetheadyaw += 180;
+ targettilt2 *= -1;
+ tilt2 *= -1;
+ } else if (animCurrent == knifeslashreversalanim) {
+ oldcoords = coords + facing * .5;
+ targetyaw += 90;
+ yaw += 90;
+ targetheadyaw += 90;
+ targettilt2 = 0;
+ tilt2 = 0;
+ } else if (animCurrent == staffspinhitreversalanim) {
+ targetyaw += 180;
+ yaw += 180;
+ targetheadyaw += 180;
+ targettilt2 = 0;
+ tilt2 = 0;
+ }
+ if (onterrain)
+ oldcoords.y = terrain.getHeight(oldcoords.x, oldcoords.z);
+ else
+ oldcoords.y = ycoords;
+ currentoffset = coords - oldcoords;
+ targetoffset = 0;
+ coords = oldcoords;
+
+ lastfeint = 0;
+ }
+ if (animCurrent == knifesneakattackedanim || animCurrent == swordsneakattackedanim) {
+ velocity = 0;
+ velocity.y = -5;
+ RagDoll(0);
+ }
+ if (Animation::animations[animTarget].attack == reversed) {
+ escapednum++;
+ if (animTarget == sweepreversedanim)
+ targetyaw += 90;
+ animTarget = backhandspringanim;
+ frameTarget = 2;
+ emit_sound_at(landsound, coords, 128);
+
+ if (animCurrent == upunchreversedanim || animCurrent == swordslashreversedanim) {
+ animTarget = rollanim;
+ frameTarget = 5;
+ oldcoords = coords;
+ coords += (DoRotation(jointPos(leftfoot), 0, yaw, 0) + DoRotation(jointPos(rightfoot), 0, yaw, 0)) / 2 * scale;
+ coords.y = oldcoords.y;
+ }
+ if (animCurrent == knifeslashreversedanim) {
+ animTarget = rollanim;
+ frameTarget = 0;
+ targetyaw += 90;
+ yaw += 90;
+ oldcoords = coords;
+ coords += (DoRotation(jointPos(leftfoot), 0, yaw, 0) + DoRotation(jointPos(rightfoot), 0, yaw, 0)) / 2 * scale;
+ coords.y = oldcoords.y;
+ }
+ }
+ if (wasFlip()) {
+ animTarget = jumpdownanim;
+ }
+ if (wasLanding())
+ animTarget = getIdle();
+ if (wasLandhard())
+ animTarget = getIdle();
+ if (animCurrent == spinkickanim || animCurrent == getupfrombackanim || animCurrent == getupfromfrontanim || animCurrent == lowkickanim) {
+ animTarget = getIdle();
+ oldcoords = coords;
+ coords += (DoRotation(jointPos(leftfoot), 0, yaw, 0) + DoRotation(jointPos(rightfoot), 0, yaw, 0)) / 2 * scale;
+ coords.y = oldcoords.y;
+ //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::animations[animCurrent].offset * -1, 0, yaw, 0) * scale;
+ currentoffset.y -= (coords.y - targetoffset.y);
+ coords.y = targetoffset.y;
+ targetoffset = 0;
+ normalsupdatedelay = 0;
+ }
+ if (animCurrent == upunchanim) {
+ animTarget = getStop();
+ normalsupdatedelay = 0;
+ lastfeint = 0;
+ }
+ if (animCurrent == rabbitkickanim && animTarget != backflipanim) {
+ targetyaw = yaw;
+ bool hasstaff;
+ hasstaff = 0;
+ if (num_weapons > 0)
+ if (weapons[0].getType() == staff)
+ hasstaff = 1;
+ if (!hasstaff)
+ DoDamage(35);
+ RagDoll(0);
+ lastfeint = 0;
+ rabbitkickragdoll = 1;
+ }
+ if (animCurrent == rabbitkickreversedanim) {
+ if (!feint) {
+ velocity = 0;
+ velocity.y = -10;
+ //DoDamage(100);
+ RagDoll(0);
+ skeleton.spinny = 0;
+ SolidHitBonus(!id); // FIXME: tricky id
+ }
+ if (feint) {
+ escapednum++;
+ animTarget = rollanim;
+ coords += facing;
+ if (id == 0)
+ pause_sound(whooshsound);
+ }
+ lastfeint = 0;
+ }
+ if (animCurrent == rabbittackledbackanim || animCurrent == rabbittackledfrontanim) {
+ velocity = 0;
+ velocity.y = -10;
+ RagDoll(0);
+ skeleton.spinny = 0;
+ }
+ if (animCurrent == jumpreversedanim) {
+ if (!feint) {
+ velocity = 0;
+ velocity.y = -10;
+ //DoDamage(100);
+ RagDoll(0);
+ skeleton.spinny = 0;
+ SolidHitBonus(!id); // FIXME: tricky id
+ }
+ if (feint) {
+ escapednum++;
+ animTarget = rollanim;
+ coords += facing * 2;
+ if (id == 0)
+ pause_sound(whooshsound);
+ }
+ lastfeint = 0;
+ }
+
+ 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::animations[animCurrent].attack == normalattack) {
+ animTarget = getIdle();
+ lastfeint = 0;
+ }
+ if (animCurrent == blockhighleftanim && aitype != playercontrolled) {
+ animTarget = blockhighleftstrikeanim;
+ }
+ if (animCurrent == knifeslashstartanim || animCurrent == knifethrowanim || animCurrent == swordslashanim || animCurrent == staffhitanim || animCurrent == staffgroundsmashanim || animCurrent == staffspinhitanim) {
+ animTarget = getIdle();
+ lastfeint = 0;
+ }
+ if (animCurrent == spinkickanim && victim->skeleton.free) {
+ if (creature == rabbittype)
+ animTarget = fightidleanim;
+ }
+ }
+ target = 0;
+
+ if (isIdle() && !wasIdle())
+ normalsupdatedelay = 0;
+
+ if (animCurrent == jumpupanim && velocity.y < 0 && !isFlip()) {
+ animTarget = jumpdownanim;
+ }
+ }
+ if (!skeleton.free) {
+ oldtarget = target;
+ if (!transspeed && Animation::animations[animTarget].attack != 2 && Animation::animations[animTarget].attack != 3) {
+ if (!isRun() || !wasRun()) {
+ if (targetFrame().speed > currentFrame().speed)
+ target += multiplier * targetFrame().speed * speed * 2;
+ if (targetFrame().speed <= currentFrame().speed)
+ target += multiplier * currentFrame().speed * speed * 2;
+ }
+ if (isRun() && wasRun()) {
+ float tempspeed;
+ tempspeed = velspeed;
+ if (tempspeed < 10 * speedmult)
+ tempspeed = 10 * speedmult;
+ /* FIXME - mixed of target and current here, is that intended? */
+ target += multiplier * Animation::animations[animTarget].frames[frameCurrent].speed * speed * 1.7 * tempspeed / (speed * 45 * scale);
+ }
+ } else if (transspeed)
+ target += multiplier * transspeed * speed * 2;
+ else {
+ if (!isRun() || !wasRun()) {
+ if (targetFrame().speed > currentFrame().speed)
+ target += multiplier * targetFrame().speed * 2;
+ if (targetFrame().speed <= currentFrame().speed)
+ target += multiplier * currentFrame().speed * 2;
+ }
+ }
+
+ if (animCurrent != animTarget)
+ target = (target + oldtarget) / 2;
+
+ if (target > 1) {
+ frameCurrent = frameTarget;
+ target = 1;
+ }
+ oldrot = rot;
+ rot = targetrot * target;
+ yaw += rot - oldrot;
+ if (target == 1) {
+ rot = 0;
+ oldrot = 0;
+ targetrot = 0;
+ }
+ if (frameCurrent >= Animation::animations[animCurrent].frames.size()) {
+ frameCurrent = Animation::animations[animCurrent].frames.size() - 1;
+ }
+ if (animCurrent != oldanimCurrent || animTarget != oldanimTarget || ((frameCurrent != oldframeCurrent || frameTarget != oldframeTarget) && !calcrot)) {
+ //Old rotates
+ for (int i = 0; i < skeleton.joints.size(); i++) {
+ skeleton.joints[i].position = currentFrame().joints[i].position;
+ }
+
+ skeleton.FindForwards();
+
+ for (int i = 0; i < skeleton.muscles.size(); i++) {
+ if (skeleton.muscles[i].visible) {
+ skeleton.FindRotationMuscle(i, animTarget);
+ }
+ }
+ for (int i = 0; i < skeleton.muscles.size(); i++) {
+ if (skeleton.muscles[i].visible) {
+ if (isnormal((float)((int)(skeleton.muscles[i].rotate1 * 100) % 36000) / 100))
+ skeleton.muscles[i].oldrotate1 = (float)((int)(skeleton.muscles[i].rotate1 * 100) % 36000) / 100;
+ if (isnormal((float)((int)(skeleton.muscles[i].rotate2 * 100) % 36000) / 100))
+ skeleton.muscles[i].oldrotate2 = (float)((int)(skeleton.muscles[i].rotate2 * 100) % 36000) / 100;
+ if (isnormal((float)((int)(skeleton.muscles[i].rotate3 * 100) % 36000) / 100))
+ skeleton.muscles[i].oldrotate3 = (float)((int)(skeleton.muscles[i].rotate3 * 100) % 36000) / 100;
+ }
+ }
+
+ //New rotates
+ for (int i = 0; i < skeleton.joints.size(); i++) {
+ skeleton.joints[i].position = targetFrame().joints[i].position;
+ }
+
+ skeleton.FindForwards();
+
+ for (int i = 0; i < skeleton.muscles.size(); i++) {
+ if (skeleton.muscles[i].visible) {
+ skeleton.FindRotationMuscle(i, animTarget);
+ }
+ }
+ for (int i = 0; i < skeleton.muscles.size(); i++) {
+ if (skeleton.muscles[i].visible) {
+ if (isnormal((float)((int)(skeleton.muscles[i].rotate1 * 100) % 36000) / 100))
+ skeleton.muscles[i].newrotate1 = (float)((int)(skeleton.muscles[i].rotate1 * 100) % 36000) / 100;
+ if (isnormal((float)((int)(skeleton.muscles[i].rotate2 * 100) % 36000) / 100))
+ skeleton.muscles[i].newrotate2 = (float)((int)(skeleton.muscles[i].rotate2 * 100) % 36000) / 100;
+ if (isnormal((float)((int)(skeleton.muscles[i].rotate3 * 100) % 36000) / 100))
+ skeleton.muscles[i].newrotate3 = (float)((int)(skeleton.muscles[i].rotate3 * 100) % 36000) / 100;
+ if (skeleton.muscles[i].newrotate3 > skeleton.muscles[i].oldrotate3 + 180) skeleton.muscles[i].newrotate3 -= 360;
+ if (skeleton.muscles[i].newrotate3 < skeleton.muscles[i].oldrotate3 - 180) skeleton.muscles[i].newrotate3 += 360;
+ if (skeleton.muscles[i].newrotate2 > skeleton.muscles[i].oldrotate2 + 180) skeleton.muscles[i].newrotate2 -= 360;
+ if (skeleton.muscles[i].newrotate2 < skeleton.muscles[i].oldrotate2 - 180) skeleton.muscles[i].newrotate2 += 360;
+ if (skeleton.muscles[i].newrotate1 > skeleton.muscles[i].oldrotate1 + 180) skeleton.muscles[i].newrotate1 -= 360;
+ if (skeleton.muscles[i].newrotate1 < skeleton.muscles[i].oldrotate1 - 180) skeleton.muscles[i].newrotate1 += 360;
+ }
+ }
+ }
+
+ oldanimCurrent = animCurrent;
+ oldanimTarget = animTarget;
+ oldframeTarget = frameTarget;
+ oldframeCurrent = frameCurrent;
+
+ for (int i = 0; i < skeleton.joints.size(); i++) {
+ skeleton.joints[i].velocity = (currentFrame().joints[i].position * (1 - target) + targetFrame().joints[i].position * (target) - skeleton.joints[i].position) / multiplier;
+ skeleton.joints[i].position = currentFrame().joints[i].position * (1 - target) + targetFrame().joints[i].position * (target);
+ }
+ offset = currentoffset * (1 - target) + targetoffset * target;
+ for (int i = 0; i < skeleton.muscles.size(); i++) {
+ if (skeleton.muscles[i].visible) {
+ skeleton.muscles[i].rotate1 = skeleton.muscles[i].oldrotate1 * (1 - target) + skeleton.muscles[i].newrotate1 * (target);
+ skeleton.muscles[i].rotate2 = skeleton.muscles[i].oldrotate2 * (1 - target) + skeleton.muscles[i].newrotate2 * (target);
+ skeleton.muscles[i].rotate3 = skeleton.muscles[i].oldrotate3 * (1 - target) + skeleton.muscles[i].newrotate3 * (target);
+ }
+ }
+ }
+
+ if (isLanding() && landhard) {
+ if (id == 0)
+ camerashake += .4;
+ animTarget = getLandhard();
+ frameTarget = 0;
+ target = 0;
+ landhard = 0;
+ transspeed = 15;
+ }
+ }
+}
+
+/* EFFECT
+ * MONSTER
+ * TODO
+ */
+void Person::DoStuff()
+{
+ static XYZ terrainnormal;
+ static XYZ flatfacing;
+ static XYZ flatvelocity;
+ static float flatvelspeed;
+ static int i, j, l;
+ static XYZ average;
+ static int howmany;
+ static int bloodsize;
+ static int startx, starty, endx, endy;
+ static GLubyte color;
+ static XYZ bloodvel;
+
+ onfiredelay -= multiplier;
+ if (onfiredelay < 0 && onfire) {
+ if (Random() % 2 == 0) {
+ crouchkeydown = 1;
+ }
+ onfiredelay = 0.3;
+ }
+
+ crouchkeydowntime += multiplier;
+ if (!crouchkeydown)
+ crouchkeydowntime = 0;
+ jumpkeydowntime += multiplier;
+ if (!jumpkeydown && skeleton.free)
+ jumpkeydowntime = 0;
+
+ if (hostile || damage > 0 || bloodloss > 0)
+ immobile = 0;
+
+ if (isIdle() || isRun())
+ targetoffset = 0;
+
+ if (num_weapons == 1 && weaponactive != -1)
+ weaponstuck = -1;
+
+ if (id == 0)
+ blooddimamount -= multiplier * .3;
+ speechdelay -= multiplier;
+ texupdatedelay -= multiplier;
+ interestdelay -= multiplier;
+ flamedelay -= multiplier;
+ parriedrecently -= multiplier;
+ if (!victim) {
+ victim = this->shared_from_this();
+ hasvictim = 0;
+ }
+
+ if (id == 0)
+ speed = 1.1 * speedmult;
+ else
+ speed = 1.0 * speedmult;
+ if (!skeleton.free)
+ rabbitkickragdoll = 0;
+
+ speed *= speedmult;
+
+ if (id != 0 && (creature == rabbittype || difficulty != 2))
+ superruntoggle = 0;
+ if (id != 0 && creature == wolftype && difficulty == 2) {
+ superruntoggle = 0;
+ if (aitype != passivetype) {
+ superruntoggle = 1;
+ if (aitype == attacktypecutoff && (Person::players[0]->isIdle() || Person::players[0]->isCrouch() || Person::players[0]->skeleton.free || Person::players[0]->animTarget == getupfrombackanim || Person::players[0]->animTarget == getupfromfrontanim || Person::players[0]->animTarget == sneakanim) && distsq(&coords, &Person::players[0]->coords) < 16) {
+ superruntoggle = 0;
+ }
+ }
+ if (scale < 0.2)
+ superruntoggle = 0;
+ if (animTarget == wolfrunninganim && !superruntoggle) {
+ animTarget = getRun();
+ frameTarget = 0;
+ }
+ }
+ if (weaponactive == -1 && num_weapons > 0) {
+ if (weapons[weaponids[0]].getType() == staff) {
+ weaponactive = 0;
+ }
+ }
+
+ if (onfire) {
+ burnt += multiplier;
+ deathbleeding = 1;
+ if (burnt > .6)
+ burnt = .6;
+ OPENAL_SetVolume(channels[stream_firesound], 256 + 256 * findLength(&velocity) / 3);
+
+ if (animTarget == jumpupanim || animTarget == jumpdownanim || isFlip()) {
+ float gLoc[3];
+ float vel[3];
+ gLoc[0] = coords.x;
+ gLoc[1] = coords.y;
+ gLoc[2] = coords.z;
+ vel[0] = velocity.x;
+ vel[1] = velocity.y;
+ vel[2] = velocity.z;
+
+ if (id == 0) {
+ OPENAL_3D_SetAttributes(channels[whooshsound], gLoc, vel);
+ OPENAL_SetVolume(channels[whooshsound], 64 * findLength(&velocity) / 5);
+ }
+ }
+ }
+ while (flamedelay < 0 && onfire) {
+ flamedelay += .006;
+ howmany = abs(Random() % (skeleton.joints.size()));
+ if (skeleton.free) {
+ flatvelocity = skeleton.joints[howmany].velocity * scale / 2;
+ flatfacing = skeleton.joints[howmany].position * scale + coords;
+ } else {
+ flatfacing = DoRotation(DoRotation(DoRotation(skeleton.joints[howmany].position, 0, 0, tilt), tilt2, 0, 0), 0, yaw, 0) * scale + coords;
+ flatvelocity = (coords - oldcoords) / multiplier / 2;
+ }
+ Sprite::MakeSprite(flamesprite, flatfacing, flatvelocity, 1, 1, 1, .6 + (float)abs(Random() % 100) / 200 - .25, 1);
+ }
+
+ while (flamedelay < 0 && !onfire && tutoriallevel == 1 && id != 0) {
+ flamedelay += .05;
+ howmany = abs(Random() % (skeleton.joints.size()));
+ if (skeleton.free) {
+ flatvelocity = skeleton.joints[howmany].velocity * scale / 2;
+ flatfacing = skeleton.joints[howmany].position * scale + coords;
+ } else {
+ flatvelocity = (coords - oldcoords) / multiplier / 2;
+ flatfacing = DoRotation(DoRotation(DoRotation(skeleton.joints[howmany].position, 0, 0, tilt), tilt2, 0, 0), 0, yaw, 0) * scale + coords;
+ }
+ Sprite::MakeSprite(breathsprite, flatfacing, flatvelocity, 1, 1, 1, .6 + (float)abs(Random() % 100) / 200 - .25, .3);
+ }
+
+ if (bleeding > 0) {
+ bleeding -= multiplier * .3;
+ if (bloodtoggle == 2) {
+ skeleton.drawmodel.textureptr.bind();
+ if ((bleeding <= 0) && (detail != 2))
+ DoMipmaps();
+ }
+ }
+
+ if (neckspurtamount > 0) {
+ neckspurtamount -= multiplier;
+ neckspurtdelay -= multiplier * 3;
+ neckspurtparticledelay -= multiplier * 3;
+ if (neckspurtparticledelay < 0 && neckspurtdelay > 2) {
+ spurt = 0;
+ bloodvel = 0;
+ if (skeleton.free) {
+ bloodvel -= DoRotation(skeleton.forward * 10 * scale, ((float)(Random() % 100)) / 40, ((float)(Random() % 100)) / 40, 0);
+ bloodvel += DoRotation(jointVel(head), ((float)(Random() % 100)) / 40, yaw + ((float)(Random() % 100)) / 40, 0) * scale;
+ Sprite::MakeSprite(bloodsprite, (jointPos(neck) + (jointPos(neck) - jointPos(head)) / 5)*scale + coords, bloodvel, 1, 1, 1, .05, .9);
+ } else {
+ bloodvel.z = 5 * neckspurtamount;
+ bloodvel = DoRotation(bloodvel, ((float)(Random() % 100)) / 40, yaw + ((float)(Random() % 100)) / 40, 0) * scale;
+ bloodvel += DoRotation(velocity, ((float)(Random() % 100)) / 40, ((float)(Random() % 100)) / 40, 0) * scale;
+ Sprite::MakeSprite(bloodsprite, DoRotation(jointPos(neck) + (jointPos(neck) - jointPos(head)) / 5, 0, yaw, 0)*scale + coords, bloodvel, 1, 1, 1, .05, .9);
+ }
+ neckspurtparticledelay = .05;
+ }
+ if (neckspurtdelay < 0) {
+ neckspurtdelay = 3;
+ }
+ }
+
+ if (deathbleeding > 0 && dead != 2) {
+ if (deathbleeding < 5)
+ bleeddelay -= deathbleeding * multiplier / 4;
+ else
+ bleeddelay -= 5 * multiplier / 4;
+ if (bleeddelay < 0 && bloodtoggle) {
+ bleeddelay = 1;
+ XYZ bloodvel;
+ if (bloodtoggle) {
+ bloodvel = 0;
+ if (skeleton.free) {
+ bloodvel += DoRotation(jointVel(abdomen), ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
+ Sprite::MakeSprite(bloodsprite, jointPos(abdomen) * scale + coords, bloodvel, 1, 1, 1, .05, 1);
+ } else {
+ bloodvel += DoRotation(velocity, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0) * scale;
+ Sprite::MakeSprite(bloodsprite, DoRotation((jointPos(abdomen) + jointPos(abdomen)) / 2, 0, yaw, 0)*scale + coords, bloodvel, 1, 1, 1, .05, 1);
+ }
+ }
+ }
+ bloodloss += deathbleeding * multiplier * 80;
+ deathbleeding -= multiplier * 1.6;
+ if (deathbleeding < 0)
+ deathbleeding = 0;
+ 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;
+ num_weapons--;
+ if (num_weapons) {
+ weaponids[0] = weaponids[num_weapons];
+ if (weaponstuck == num_weapons)
+ weaponstuck = 0;
+ }
+ weaponactive = -1;
+ for (unsigned i = 0; i < Person::players.size(); i++) {
+ Person::players[i]->wentforweapon = 0;
+ }
+
+ if (id == 0) {
+ Game::flash(.5, 0);
+ }
+ }
+
+ if (!dead && creature == wolftype) {
+ award_bonus(0, Wolfbonus);
+ }
+ dead = 2;
+ if (animTarget == knifefollowedanim && !skeleton.free) {
+ for (int i = 0; i < skeleton.joints.size(); i++) {
+ skeleton.joints[i].velocity = 0;
+ skeleton.joints[i].velocity.y = -2;
+ }
+ }
+ if (id != 0 && unconscioustime > .1) {
+ numafterkill++;
+ }
+
+ RagDoll(0);
+ }
+ }
+
+ if (texupdatedelay < 0 && bleeding > 0 && bloodtoggle == 2 && distsq(&viewer, &coords) < 9) {
+ texupdatedelay = .12;
+
+ bloodsize = 5 - realtexdetail;
+
+ startx = 0;
+ starty = 0;
+ startx = bleedy; //abs(Random()%(skeleton.skinsize-bloodsize-1));
+ starty = bleedx; //abs(Random()%(skeleton.skinsize-bloodsize-1));
+ endx = startx + bloodsize;
+ endy = starty + bloodsize;
+
+ if (startx < 0) {
+ startx = 0;
+ bleeding = 0;
+ }
+ if (starty < 0) {
+ starty = 0;
+ bleeding = 0;
+ }
+ if (endx > skeleton.skinsize - 1) {
+ endx = skeleton.skinsize - 1;
+ bleeding = 0;
+ }
+ if (endy > skeleton.skinsize - 1) {
+ endy = skeleton.skinsize - 1;
+ bleeding = 0;
+ }
+ if (endx < startx)
+ endx = startx;
+ if (endy < starty)
+ endy = starty;
+
+ for (i = startx; i < endx; i++) {
+ for (j = starty; j < endy; j++) {
+ if (Random() % 2 == 0) {
+ color = Random() % 85 + 170;
+ if (skeleton.skinText[i * skeleton.skinsize * 3 + j * 3 + 0] > color / 2)
+ skeleton.skinText[i * skeleton.skinsize * 3 + j * 3 + 0] = color / 2;
+ skeleton.skinText[i * skeleton.skinsize * 3 + j * 3 + 1] = 0;
+ skeleton.skinText[i * skeleton.skinsize * 3 + j * 3 + 2] = 0;
+ }
+ }
+ }
+ if (detail > 1) {
+ skeleton.drawmodel.textureptr.bind();
+ DoMipmaps();
+ }
+
+ if (skeleton.free) {
+ bleedx += 4 * direction / realtexdetail;
+ if (detail == 2)
+ bleedy += (abs(Random() % 3) - 1) * 2 / realtexdetail;
+ else
+ bleedy += (abs(Random() % 3) - 1) * 4 / realtexdetail;
+ } else {
+ bleedy -= 4 / realtexdetail;
+ if (detail == 2)
+ bleedx += (abs(Random() % 3) - 1) * 2 / realtexdetail;
+ else
+ bleedx += (abs(Random() % 3) - 1) * 4 / realtexdetail;
+ }
+ }
+
+ if (abs(righthandmorphness - targetrighthandmorphness) < multiplier * 4) {
+ righthandmorphness = targetrighthandmorphness;
+ righthandmorphstart = righthandmorphend;
+ } else if (righthandmorphness > targetrighthandmorphness) {
+ righthandmorphness -= multiplier * 4;
+ } else if (righthandmorphness < targetrighthandmorphness) {
+ righthandmorphness += multiplier * 4;
+ }
+
+ if (abs(lefthandmorphness - targetlefthandmorphness) < multiplier * 4) {
+ lefthandmorphness = targetlefthandmorphness;
+ lefthandmorphstart = lefthandmorphend;
+ } else if (lefthandmorphness > targetlefthandmorphness) {
+ lefthandmorphness -= multiplier * 4;
+ } else if (lefthandmorphness < targetlefthandmorphness) {
+ lefthandmorphness += multiplier * 4;
+ }
+
+ if (creature == rabbittype || targettailmorphness == 5 || targettailmorphness == 0) {
+ if (abs(tailmorphness - targettailmorphness) < multiplier * 10) {
+ tailmorphness = targettailmorphness;
+ tailmorphstart = tailmorphend;
+ } else if (tailmorphness > targettailmorphness) {
+ tailmorphness -= multiplier * 10;
+ } else if (tailmorphness < targettailmorphness) {
+ tailmorphness += multiplier * 10;
+ }
+ }
+
+ if (creature == wolftype) {
+ if (abs(tailmorphness - targettailmorphness) < multiplier * 4) {
+ tailmorphness = targettailmorphness;
+ tailmorphstart = tailmorphend;
+ } else if (tailmorphness > targettailmorphness) {
+ tailmorphness -= multiplier * 2;
+ } else if (tailmorphness < targettailmorphness) {
+ tailmorphness += multiplier * 2;
+ }
+ }
+
+ if (headmorphend == 3 || headmorphstart == 3) {
+ if (abs(headmorphness - targetheadmorphness) < multiplier * 7) {
+ headmorphness = targetheadmorphness;
+ headmorphstart = headmorphend;
+ } else if (headmorphness > targetheadmorphness) {
+ headmorphness -= multiplier * 7;
+ } else if (headmorphness < targetheadmorphness) {
+ headmorphness += multiplier * 7;
+ }
+ } else if (headmorphend == 5 || headmorphstart == 5) {
+ if (abs(headmorphness - targetheadmorphness) < multiplier * 10) {
+ headmorphness = targetheadmorphness;
+ headmorphstart = headmorphend;
+ } else if (headmorphness > targetheadmorphness) {
+ headmorphness -= multiplier * 10;
+ } else if (headmorphness < targetheadmorphness) {
+ headmorphness += multiplier * 10;
+ }
+ } else {
+ if (abs(headmorphness - targetheadmorphness) < multiplier * 4) {
+ headmorphness = targetheadmorphness;
+ headmorphstart = headmorphend;
+ } else if (headmorphness > targetheadmorphness) {
+ headmorphness -= multiplier * 4;
+ } else if (headmorphness < targetheadmorphness) {
+ headmorphness += multiplier * 4;
+ }
+ }
+
+ if (abs(chestmorphness - targetchestmorphness) < multiplier) {
+ chestmorphness = targetchestmorphness;
+ chestmorphstart = chestmorphend;
+ } else if (chestmorphness > targetchestmorphness) {
+ chestmorphness -= multiplier;
+ } else if (chestmorphness < targetchestmorphness) {
+ chestmorphness += multiplier;
+ }
+
+ if (dead != 2 && howactive <= typesleeping) {
+ if (chestmorphstart == 0 && chestmorphend == 0) {
+ chestmorphness = 0;
+ targetchestmorphness = 1;
+ chestmorphend = 3;
+ }
+ if (chestmorphstart != 0 && chestmorphend != 0) {
+ chestmorphness = 0;
+ targetchestmorphness = 1;
+ chestmorphend = 0;
+ if (environment == snowyenvironment) {
+ XYZ footpoint;
+ XYZ footvel;
+ if (skeleton.free) {
+ footvel = skeleton.specialforward[0] * -1;
+ footpoint = ((jointPos(head) + jointPos(neck)) / 2) * scale + coords;
+ } else {
+ footvel = DoRotation(skeleton.specialforward[0], 0, yaw, 0) * -1;
+ footpoint = DoRotation((jointPos(head) + jointPos(neck)) / 2, 0, yaw, 0) * scale + coords;
+ }
+ if (animTarget == sleepanim)
+ footvel = DoRotation(footvel, 0, 90, 0);
+ Sprite::MakeSprite(breathsprite, footpoint + footvel * .2, footvel * .4, 1, 1, 1, .4, .3);
+ }
+ }
+
+ if (!dead && howactive < typesleeping) {
+ blinkdelay -= multiplier * 2;
+ if (headmorphstart == 0 && headmorphend == 0 && blinkdelay <= 0) {
+ headmorphness = 0;
+ targetheadmorphness = 1;
+ headmorphend = 3;
+ blinkdelay = (float)(abs(Random() % 40)) / 5;
+ }
+ if (headmorphstart == 3 && headmorphend == 3) {
+ headmorphness = 0;
+ targetheadmorphness = 1;
+ headmorphend = 0;
+ }
+ }
+ if (!dead) {
+ twitchdelay -= multiplier * 1.5;
+ if (animTarget != hurtidleanim) {
+ if (headmorphstart == 0 && headmorphend == 0 && twitchdelay <= 0) {
+ headmorphness = 0;
+ targetheadmorphness = 1;
+ headmorphend = 5;
+ twitchdelay = (float)(abs(Random() % 40)) / 5;
+ }
+ if (headmorphstart == 5 && headmorphend == 5) {
+ headmorphness = 0;
+ targetheadmorphness = 1;
+ headmorphend = 0;
+ }
+ }
+ if ((isIdle() || isCrouch()) && animTarget != hurtidleanim) {
+ twitchdelay3 -= multiplier * 1;
+ if (Random() % 2 == 0) {
+ if (righthandmorphstart == 0 && righthandmorphend == 0 && twitchdelay3 <= 0) {
+ righthandmorphness = 0;
+ targetrighthandmorphness = 1;
+ righthandmorphend = 1;
+ if (Random() % 2 == 0)twitchdelay3 = (float)(abs(Random() % 40)) / 5;
+ }
+ if (righthandmorphstart == 1 && righthandmorphend == 1) {
+ righthandmorphness = 0;
+ targetrighthandmorphness = 1;
+ righthandmorphend = 0;
+ }
+ }
+ if (Random() % 2 == 0) {
+ if (lefthandmorphstart == 0 && lefthandmorphend == 0 && twitchdelay3 <= 0) {
+ lefthandmorphness = 0;
+ targetlefthandmorphness = 1;
+ lefthandmorphend = 1;
+ twitchdelay3 = (float)(abs(Random() % 40)) / 5;
+ }
+ if (lefthandmorphstart == 1 && lefthandmorphend == 1) {
+ lefthandmorphness = 0;
+ targetlefthandmorphness = 1;
+ lefthandmorphend = 0;
+ }
+ }
+ }
+ }
+ if (!dead) {
+ if (creature == rabbittype) {
+ if (howactive < typesleeping)
+ twitchdelay2 -= multiplier * 1.5;
+ else
+ twitchdelay2 -= multiplier * 0.5;
+ if (howactive <= typesleeping) {
+ if (tailmorphstart == 0 && tailmorphend == 0 && twitchdelay2 <= 0) {
+ tailmorphness = 0;
+ targettailmorphness = 1;
+ tailmorphend = 1;
+ twitchdelay2 = (float)(abs(Random() % 40)) / 5;
+ }
+ if (tailmorphstart == 1 && tailmorphend == 1) {
+ tailmorphness = 0;
+ targettailmorphness = 1;
+ tailmorphend = 2;
+ }
+ if (tailmorphstart == 2 && tailmorphend == 2) {
+ tailmorphness = 0;
+ targettailmorphness = 1;
+ tailmorphend = 0;
+ }
+ }
+ }
+ }
+ }
+ if (creature == wolftype) {
+ twitchdelay2 -= multiplier * 1.5;
+ if (tailmorphend != 0)
+ if ((isRun() || animTarget == jumpupanim || animTarget == jumpdownanim || animTarget == backflipanim) && !skeleton.free) {
+ tailmorphness = 0;
+ targettailmorphness = 1;
+ tailmorphend = 0;
+ twitchdelay2 = .1;
+ }
+ if (tailmorphend != 5)
+ if (animTarget == flipanim || animTarget == frontflipanim || animTarget == rollanim || skeleton.free) {
+ tailmorphness = 0;
+ targettailmorphness = 1;
+ tailmorphend = 5;
+ twitchdelay2 = .1;
+ }
+ if (twitchdelay2 <= 0) {
+ if (((tailmorphstart == 0 && tailmorphend == 0) || (tailmorphstart == 5 && tailmorphend == 5))) {
+ tailmorphness = 0;
+ targettailmorphness = 1;
+ tailmorphend = 1;
+ }
+ if (tailmorphstart == 1 && tailmorphend == 1) {
+ tailmorphness = 0;
+ targettailmorphness = 1;
+ tailmorphend = 2;
+ }
+ if (tailmorphstart == 2 && tailmorphend == 2) {
+ tailmorphness = 0;
+ targettailmorphness = 1;
+ tailmorphend = 3;
+ }
+ if (tailmorphstart == 3 && tailmorphend == 3) {
+ tailmorphness = 0;
+ targettailmorphness = 1;
+ tailmorphend = 4;
+ }
+ if (tailmorphstart == 4 && tailmorphend == 4) {
+ tailmorphness = 0;
+ targettailmorphness = 1;
+ tailmorphend = 1;
+ }
+ }
+ }
+
+ if (dead != 1)
+ unconscioustime = 0;
+
+ if (dead == 1 || howactive == typesleeping) {
+ unconscioustime += multiplier;
+ //If unconscious, close eyes and mouth
+ if (righthandmorphend != 0)
+ righthandmorphness = 0;
+ righthandmorphend = 0;
+ targetrighthandmorphness = 1;
+
+ if (lefthandmorphend != 0)
+ lefthandmorphness = 0;
+ lefthandmorphend = 0;
+ targetlefthandmorphness = 1;
+
+ if (headmorphend != 3 && headmorphend != 5)
+ headmorphness = 0;
+ headmorphend = 3;
+ targetheadmorphness = 1;
+ }
+
+
+ if (howactive > typesleeping) {
+ XYZ headpoint;
+ headpoint = coords;
+ if (bloodtoggle && !bled) {
+ terrain.MakeDecal(blooddecalslow, headpoint, .8, .5, 0);
+ }
+ if (bloodtoggle && !bled)
+ for (l = 0; l < terrain.patchobjectnum[whichpatchx][whichpatchz]; l++) {
+ j = terrain.patchobjects[whichpatchx][whichpatchz][l];
+ XYZ point = DoRotation(headpoint - objects.position[j], 0, -objects.yaw[j], 0);
+ float size = .8;
+ float opacity = .6;
+ float yaw = 0;
+ objects.model[j].MakeDecal(blooddecalslow, &point, &size, &opacity, &yaw);
+ }
+ bled = 1;
+ }
+
+ if (dead == 2 || howactive > typesleeping) {
+ //If dead, open mouth and hands
+ if (righthandmorphend != 0)
+ righthandmorphness = 0;
+ righthandmorphend = 0;
+ targetrighthandmorphness = 1;
+
+ if (lefthandmorphend != 0)
+ lefthandmorphness = 0;
+ lefthandmorphend = 0;
+ targetlefthandmorphness = 1;
+
+ if (headmorphend != 2)
+ headmorphness = 0;
+ headmorphend = 2;
+ targetheadmorphness = 1;
+ }
+
+ if (stunned > 0 && !dead && headmorphend != 2) {
+ if (headmorphend != 4)
+ headmorphness = 0;
+ headmorphend = 4;
+ targetheadmorphness = 1;
+ }
+
+ if (damage > damagetolerance && !dead) {
+
+ dead = 1;
+ unconscioustime = 0;
+
+ if (creature == wolftype) {
+ award_bonus(0, Wolfbonus);
+ }
+
+ RagDoll(0);
+
+ if (weaponactive != -1) {
+ weapons[weaponids[0]].drop(velocity * scale * -.3, velocity * scale);
+ weapons[weaponids[0]].velocity.x += .01;
+ num_weapons--;
+ if (num_weapons) {
+ weaponids[0] = weaponids[num_weapons];
+ if (weaponstuck == num_weapons)
+ weaponstuck = 0;
+ }
+ weaponactive = -1;
+ for (unsigned i = 0; i < Person::players.size(); i++) {
+ Person::players[i]->wentforweapon = 0;
+ }
+ }
+
+
+
+ if ((id == 0 || distsq(&coords, &viewer) < 50) && autoslomo) {
+ slomo = 1;
+ slomodelay = .2;
+ }
+
+ damage += 20;
+ }
+
+ if (!dead)
+ damage -= multiplier * 13;
+ if (!dead)
+ permanentdamage -= multiplier * 4;
+ if (isIdle() || isCrouch()) {
+ if (!dead)
+ permanentdamage -= multiplier * 4;
+ }
+ if (damage < 0)
+ damage = 0;
+ if (permanentdamage < 0)
+ permanentdamage = 0;
+ if (superpermanentdamage < 0)
+ superpermanentdamage = 0;
+ if (permanentdamage < superpermanentdamage) {
+ permanentdamage = superpermanentdamage;
+ }
+ if (damage < permanentdamage) {
+ damage = permanentdamage;
+ }
+ if (dead == 1 && damage < damagetolerance) {
+ dead = 0;
+ skeleton.free = 1;
+ damage -= 20;
+ for (int i = 0; i < skeleton.joints.size(); i++) {
+ skeleton.joints[i].velocity = 0;
+ }
+ }
+ if (permanentdamage > damagetolerance && dead != 2) {
+ DoBlood(1, 255);
+
+ if (weaponactive != -1) {
+ weapons[weaponids[0]].drop(velocity * scale * -.3, velocity * scale);
+ weapons[weaponids[0]].velocity.x += .01;
+ num_weapons--;
+ if (num_weapons) {
+ weaponids[0] = weaponids[num_weapons];
+ if (weaponstuck == num_weapons)
+ weaponstuck = 0;
+ }
+ weaponactive = -1;
+ for (unsigned i = 0; i < Person::players.size(); i++) {
+ Person::players[i]->wentforweapon = 0;
+ }
+ }
+
+ bled = 0;
+
+ if (!dead && creature == wolftype) {
+ award_bonus(0, Wolfbonus);
+ }
+
+ if (unconscioustime < .1 && (bonus != spinecrusher || bonustime > 1) && (bonus != FinishedBonus || bonustime > 1) && bloodloss < damagetolerance)
+ award_bonus(id, touchofdeath);
+ if (id != 0 && unconscioustime > .1) {
+ numafterkill++;
+ }
+
+ dead = 2;
+
+ skeleton.free = 1;
+
+ emit_sound_at(breaksound, coords);
+ }
+
+ if (skeleton.free == 1) {
+ if (id == 0)
+ pause_sound(whooshsound);
+
+ if (!dead) {
+ //If knocked over, open hands and close mouth
+ if (righthandmorphend != 0)
+ righthandmorphness = 0;
+ righthandmorphend = 0;
+ targetrighthandmorphness = 1;
+
+ if (lefthandmorphend != 0)
+ lefthandmorphness = 0;
+ lefthandmorphend = 0;
+ targetlefthandmorphness = 1;
+
+ if (headmorphend != 3 && headmorphend != 5 && headmorphstart != 3 && headmorphstart != 5) {
+ if (headmorphend != 0)
+ headmorphness = 0;
+ headmorphend = 0;
+ targetheadmorphness = 1;
+ }
+ }
+
+ skeleton.DoGravity(&scale);
+ float damageamount;
+ damageamount = skeleton.DoConstraints(&coords, &scale) * 5;
+ if (damage > damagetolerance - damageamount && !dead && (bonus != spinecrusher || bonustime > 1) && (bonus != style || bonustime > 1) && (bonus != cannon || bonustime > 1))
+ award_bonus(id, deepimpact);
+ DoDamage(damageamount / ((protectionhigh + protectionhead + protectionlow) / 3));
+
+ average = 0;
+ howmany = 0;
+ for (j = 0; j < skeleton.joints.size(); j++) {
+ average += skeleton.joints[j].position;
+ howmany++;
+ }
+ average /= howmany;
+ coords += average * scale;
+ for (j = 0; j < skeleton.joints.size(); j++) {
+ skeleton.joints[j].position -= average;
+ }
+ average /= multiplier;
+
+ velocity = 0;
+ for (int i = 0; i < skeleton.joints.size(); i++) {
+ velocity += skeleton.joints[i].velocity * scale;
+ }
+ velocity /= skeleton.joints.size();
+
+ if (!isnormal(velocity.x) && velocity.x) {
+ velocity = 0;
+ }
+
+ if (findLength(&average) < 10 && dead && skeleton.free) {
+ skeleton.longdead += (2000 - findLength(&average)) * multiplier + multiplier;
+ if (skeleton.longdead > 2000) {
+ if (skeleton.longdead > 6000) {
+ if (id == 0)
+ pause_sound(whooshsound);
+ skeleton.free = 3;
+ DrawSkeleton();
+ skeleton.free = 2;
+ }
+ if (dead == 2 && bloodloss < damagetolerance) {
+ XYZ headpoint;
+ headpoint = (jointPos(head) + jointPos(neck)) / 2 * scale + coords;
+ DoBlood(1, 255);
+ if (bloodtoggle && !bled) {
+ terrain.MakeDecal(blooddecal, headpoint, .2 * 1.2, .5, 0);
+ }
+ if (bloodtoggle && !bled)
+ for (l = 0; l < terrain.patchobjectnum[whichpatchx][whichpatchz]; l++) {
+ j = terrain.patchobjects[whichpatchx][whichpatchz][l];
+ XYZ point = DoRotation(headpoint - objects.position[j], 0, -objects.yaw[j], 0);
+ float size = .2 * 1.2;
+ float opacity = .6;
+ float yaw = 0;
+ objects.model[j].MakeDecal(blooddecal, &point, &size, &opacity, &yaw);
+ }
+ bled = 1;
+ }
+ if (dead == 2 && bloodloss >= damagetolerance) {
+ XYZ headpoint;
+ headpoint = (jointPos(abdomen) + jointPos(neck)) / 2 * scale + coords;
+ if (bleeding <= 0)
+ DoBlood(1, 255);
+ if (bloodtoggle && !bled) {
+ terrain.MakeDecal(blooddecalslow, headpoint, .8, .5, 0);
+ }
+ if (bloodtoggle && !bled)
+ for (l = 0; l < terrain.patchobjectnum[whichpatchx][whichpatchz]; l++) {
+ j = terrain.patchobjects[whichpatchx][whichpatchz][l];
+ XYZ point = DoRotation(headpoint - objects.position[j], 0, -objects.yaw[j], 0);
+ float size = .8;
+ float opacity = .6;
+ float yaw = 0;
+ objects.model[j].MakeDecal(blooddecalslow, &point, &size, &opacity, &yaw);
+ }
+ bled = 1;
+ }
+ }
+ }
+
+ if (!dead && crouchkeydown && skeleton.freetime > .5 && id == 0 && skeleton.free) {
+ bool canrecover = 1;
+ XYZ startpoint, endpoint, colpoint, colviewer, coltarget;
+ startpoint = coords;
+ endpoint = coords;
+ endpoint.y -= .7;
+ if (terrain.lineTerrain(startpoint, endpoint, &colpoint) != -1)
+ canrecover = 0;
+ if (velocity.y < -30)
+ canrecover = 0;
+ for (i = 0; i < objects.numobjects; i++) {
+ if (objects.type[i] != treeleavestype && objects.type[i] != bushtype && objects.type[i] != firetype) {
+ colviewer = startpoint;
+ coltarget = endpoint;
+ if (objects.model[i].LineCheck(&colviewer, &coltarget, &colpoint, &objects.position[i], &objects.yaw[i]) != -1)
+ canrecover = 0;
+ }
+ }
+ if (canrecover) {
+ skeleton.free = 0;
+ XYZ middle;
+ middle = 0;
+
+ terrainnormal = jointPos(groin) - jointPos(abdomen);
+ if (joint(groin).locked && joint(abdomen).locked) {
+ terrainnormal = jointPos(groin) - jointPos(abdomen);
+ middle = (jointPos(groin) + jointPos(abdomen)) / 2;
+ }
+ if (joint(abdomen).locked && joint(neck).locked) {
+ terrainnormal = jointPos(abdomen) - jointPos(neck);
+ middle = (jointPos(neck) + jointPos(abdomen)) / 2;
+ }
+ if (joint(groin).locked && joint(neck).locked) {
+ terrainnormal = jointPos(groin) - jointPos(neck);
+ middle = (jointPos(groin) + jointPos(neck)) / 2;
+ }
+ Normalise(&terrainnormal);
+
+ targetyaw = -asin(0 - terrainnormal.x);
+ targetyaw *= 360 / 6.28;
+ if (terrainnormal.z < 0)
+ targetyaw = 180 - targetyaw;
+ yaw = targetyaw;
+
+ frameTarget = 0;
+ animTarget = flipanim;
+ crouchtogglekeydown = 1;
+ target = 0;
+ tilt2 = 0;
+ targettilt2 = 0;
+
+ animCurrent = tempanim;
+ frameCurrent = 0;
+ target = 0;
+
+ for (int i = 0; i < skeleton.joints.size(); i++) {
+ tempanimation.frames[0].joints[i].position = skeleton.joints[i].position;
+ tempanimation.frames[0].joints[i].position = DoRotation(tempanimation.frames[0].joints[i].position, 0, -yaw, 0);
+ }
+ }
+ }
+
+ if (findLength(&average) < 10 && !dead && skeleton.free) {
+ skeleton.longdead += (2000 - findLength(&average)) * multiplier + multiplier;
+ if (skeleton.longdead > (damage + 500) * 1.5) {
+ if (id == 0)
+ pause_sound(whooshsound);
+ skeleton.free = 0;
+ velocity = 0;
+ XYZ middle;
+ middle = 0;
+
+ terrainnormal = jointPos(groin) - jointPos(abdomen);
+ if (joint(groin).locked && joint(abdomen).locked) {
+ terrainnormal = jointPos(groin) - jointPos(abdomen);
+ middle = (jointPos(groin) + jointPos(abdomen)) / 2;
+ }
+ if (joint(abdomen).locked && joint(neck).locked) {
+ terrainnormal = jointPos(abdomen) - jointPos(neck);
+ middle = (jointPos(neck) + jointPos(abdomen)) / 2;
+ }
+ if (joint(groin).locked && joint(neck).locked) {
+ terrainnormal = jointPos(groin) - jointPos(neck);
+ middle = (jointPos(groin) + jointPos(neck)) / 2;
+ }
+ Normalise(&terrainnormal);
+
+ targetyaw = -asin(0 - terrainnormal.x);
+ targetyaw *= 360 / 6.28;
+ if (terrainnormal.z < 0)
+ targetyaw = 180 - targetyaw;
+ yaw = targetyaw;
+
+ targettilt2 = asin(terrainnormal.y) * 180 / 3.14 * -1;
+
+
+ if (skeleton.forward.y < 0) {
+ animTarget = getupfrombackanim;
+ frameTarget = 0;
+ targettilt2 = 0;
+ }
+ if (skeleton.forward.y > -.3) {
+ animTarget = getupfromfrontanim;
+ yaw += 180;
+ targetyaw += 180;
+ targettilt2 *= -1;
+ frameTarget = 0;
+ targettilt2 = 0;
+ }
+
+ if ((Random() % 8 == 0 && id != 0 && creature == rabbittype) || (Random() % 2 == 0 && id != 0 && creature == wolftype) || (id == 0 && crouchkeydown && (forwardkeydown || backkeydown || leftkeydown || rightkeydown))) {
+ animTarget = rollanim;
+ targetyaw = lookyaw;
+ if (id == 0) {
+ if (rightkeydown) {
+ targetyaw -= 90;
+ if (forwardkeydown)
+ targetyaw += 45;
+ if (backkeydown)
+ targetyaw -= 45;
+ }
+ if (leftkeydown) {
+ targetyaw += 90;
+ if (forwardkeydown)
+ targetyaw -= 45;
+ if (backkeydown)
+ targetyaw += 45;
+ }
+ if (backkeydown) {
+ if ( !leftkeydown && !rightkeydown)
+ targetyaw += 180;
+ }
+ targetyaw += 180;
+ }
+ }
+
+ if (abs(targettilt2) > 50)
+ targettilt2 = 0;
+ animCurrent = tempanim;
+ frameCurrent = 0;
+ target = 0;
+ tilt2 = targettilt2;
+
+ if (middle.y > 0 && animTarget != rollanim)
+ targetoffset.y = middle.y + 1;
+
+ for (int i = 0; i < skeleton.joints.size(); i++) {
+ tempanimation.frames[0].joints[i].position = skeleton.joints[i].position;
+ tempanimation.frames[0].joints[i].position = DoRotation(tempanimation.frames[0].joints[i].position, 0, -yaw, 0);
+ }
+ }
+ }
+
+ bool hasstaff;
+ hasstaff = 0;
+ if (num_weapons > 0)
+ if (weapons[0].getType() == staff)
+ hasstaff = 1;
+ if (!skeleton.freefall && freefall && ((jumpkeydown && jumpkeydowntime < .2) || (hasstaff && rabbitkickragdoll)) && !dead) {
+ if (velocity.y > -30) {
+ XYZ tempvelocity;
+ tempvelocity = velocity;
+ Normalise(&tempvelocity);
+ targetyaw = -asin(0 - tempvelocity.x);
+ targetyaw *= 360 / 6.28;
+ if (velocity.z < 0)
+ targetyaw = 180 - targetyaw;
+ //targetyaw+=180;
+
+ skeleton.free = 0;
+ if (dotproduct(&skeleton.forward, &tempvelocity) < 0) {
+ animTarget = rollanim;
+ frameTarget = 2;
+ } else {
+ animTarget = backhandspringanim;
+ targetyaw += 180;
+ frameTarget = 6;
+ }
+ target = 0;
+
+ emit_sound_at(movewhooshsound, coords, 128.);
+
+ animCurrent = animTarget;
+ frameCurrent = frameTarget - 1;
+ target = 0;
+
+ velocity = 0;
+
+ yaw = targetyaw;
+ tilt = 0;
+ targettilt = 0;
+ tilt2 = 0;
+ targettilt2 = 0;
+ }
+ }
+ if (skeleton.freefall == 0)
+ freefall = 0;
+
+ }
+
+ if (aitype != passivetype || skeleton.free == 1)
+ if (findLengthfast(&velocity) > .1)
+ for (i = 0; i < objects.numobjects; i++) {
+ if (objects.type[i] == firetype)
+ if (distsqflat(&coords, &objects.position[i]) < objects.scale[i]*objects.scale[i] * 12 && distsq(&coords, &objects.position[i]) < objects.scale[i]*objects.scale[i] * 49) {
+ if (onfire) {
+ if (!objects.onfire[i]) {
+ emit_sound_at(firestartsound, objects.position[i]);
+ }
+ objects.onfire[i] = 1;
+ }
+ if (!onfire) {
+ if (objects.onfire[i]) {
+ CatchFire();
+ }
+ }
+ }
+ if (objects.type[i] == bushtype)
+ if (distsqflat(&coords, &objects.position[i]) < objects.scale[i]*objects.scale[i] * 12 && distsq(&coords, &objects.position[i]) < objects.scale[i]*objects.scale[i] * 49) {
+ if (onfire) {
+ if (!objects.onfire[i]) {
+ emit_sound_at(firestartsound, objects.position[i]);
+ }
+ objects.onfire[i] = 1;
+ }
+
+ if (!onfire) {
+ if (objects.onfire[i]) {
+ CatchFire();
+ }
+ }
+ if (objects.messedwith[i] <= 0) {
+ XYZ tempvel;
+ XYZ pos;
+
+ emit_sound_at(bushrustle, coords, 40 * findLength(&velocity));
+
+ if (id == 0) {
+ addEnvSound(coords, 4 * findLength(&velocity));
+ }
+
+ int howmany;
+ if (environment == grassyenvironment)
+ howmany = findLength(&velocity) * 4;
+ if (environment == snowyenvironment)
+ howmany = findLength(&velocity) * 2;
+ if (detail == 2)
+ if (environment != desertenvironment)
+ for (j = 0; j < howmany; j++) {
+ tempvel.x = float(abs(Random() % 100) - 50) / 20;
+ tempvel.y = float(abs(Random() % 100) - 50) / 20;
+ tempvel.z = float(abs(Random() % 100) - 50) / 20;
+ pos = coords;
+ pos.y += 1;
+ pos.x += float(abs(Random() % 100) - 50) / 200;
+ pos.y += float(abs(Random() % 100) - 50) / 200;
+ pos.z += float(abs(Random() % 100) - 50) / 200;
+ Sprite::MakeSprite(splintersprite, pos, tempvel * .5 + velocity * float(abs(Random() % 100)) / 100, 165 / 255 + float(abs(Random() % 100) - 50) / 400, 0, 0, .2 + float(abs(Random() % 100) - 50) / 1300, 1);
+ Sprite::setLastSpriteSpecial(1);
+ }
+ howmany = findLength(&velocity) * 4;
+ if (detail == 2)
+ if (environment == snowyenvironment)
+ for (j = 0; j < howmany; j++) {
+ tempvel.x = float(abs(Random() % 100) - 50) / 20;
+ tempvel.y = float(abs(Random() % 100) - 50) / 20;
+ tempvel.z = float(abs(Random() % 100) - 50) / 20;
+ pos = coords;
+ pos.y += 1;
+ pos.x += float(abs(Random() % 100) - 50) / 200;
+ pos.y += float(abs(Random() % 100) - 50) / 200;
+ pos.z += float(abs(Random() % 100) - 50) / 200;
+ Sprite::MakeSprite(splintersprite, pos, tempvel * .3 + velocity * float(abs(Random() % 100)) / 100 / 2, 1, 1, 1, .1, 1);
+ Sprite::setLastSpriteSpecial(2);
+ }
+ }
+ objects.rotx[i] += velocity.x * multiplier * 6;
+ objects.roty[i] += velocity.z * multiplier * 6;
+ objects.messedwith[i] = .5;
+ }
+ XYZ tempcoord;
+ if (objects.type[i] == treeleavestype && environment != desertenvironment) {
+ if (objects.pitch[i] == 0)
+ tempcoord = coords;
+ else {
+ tempcoord = coords - objects.position[i];
+ tempcoord = DoRotation(tempcoord, 0, -objects.yaw[i], 0);
+ tempcoord = DoRotation(tempcoord, -objects.pitch[i], 0, 0);
+ tempcoord += objects.position[i];
+ }
+ if (distsqflat(&tempcoord, &objects.position[i]) < objects.scale[i]*objects.scale[i] * 8 && distsq(&tempcoord, &objects.position[i]) < objects.scale[i]*objects.scale[i] * 300 && tempcoord.y > objects.position[i].y + 3 * objects.scale[i]) {
+ if (objects.messedwith[i] <= 0) {
+ XYZ tempvel;
+ XYZ pos;
+
+ emit_sound_at(bushrustle, coords, 40 * findLength(&velocity));
+
+ if (id == 0) {
+ addEnvSound(coords, 4 * findLength(&velocity));
+ }
+
+ int howmany;
+ if (environment == grassyenvironment)
+ howmany = findLength(&velocity) * 4;
+ if (environment == snowyenvironment)
+ howmany = findLength(&velocity) * 2;
+ if (detail == 2)
+ if (environment != desertenvironment)
+ for (j = 0; j < howmany; j++) {
+ tempvel.x = float(abs(Random() % 100) - 50) / 20;
+ tempvel.y = float(abs(Random() % 100) - 50) / 20;
+ tempvel.z = float(abs(Random() % 100) - 50) / 20;
+ pos = coords;
+ pos += velocity * .1;
+ pos.y += 1;
+ pos.x += float(abs(Random() % 100) - 50) / 150;
+ pos.y += float(abs(Random() % 100) - 50) / 150;
+ pos.z += float(abs(Random() % 100) - 50) / 150;
+ Sprite::MakeSprite(splintersprite, pos, tempvel * .5 + velocity * float(abs(Random() % 100)) / 100, 165 / 255 + float(abs(Random() % 100) - 50) / 400, 0, 0, .2 + float(abs(Random() % 100) - 50) / 1300, 1);
+ Sprite::setLastSpriteSpecial(1);
+ }
+ howmany = findLength(&velocity) * 4;
+ if (detail == 2)
+ if (environment == snowyenvironment)
+ for (j = 0; j < howmany; j++) {
+ tempvel.x = float(abs(Random() % 100) - 50) / 20;
+ tempvel.y = float(abs(Random() % 100) - 50) / 20;
+ tempvel.z = float(abs(Random() % 100) - 50) / 20;
+ pos = coords;
+ pos += velocity * .1;
+ pos.y += 1;
+ pos.x += float(abs(Random() % 100) - 50) / 150;
+ pos.y += float(abs(Random() % 100) - 50) / 150;
+ pos.z += float(abs(Random() % 100) - 50) / 150;
+ Sprite::MakeSprite(splintersprite, pos, tempvel * .3 + velocity * float(abs(Random() % 100)) / 100 / 2, 1, 1, 1, .1, 1);
+ Sprite::setLastSpriteSpecial(2);
+ }
+ }
+ objects.messedwith[i] = .5;
+ }
+ }
+ }
+
+ if (!skeleton.free) {
+ bool play;
+ play = 0;
+ if ((stunned > 0 || surprised > 0) && Person::players.size() > 2 && aitype != passivetype)
+ play = 1;
+ if (hasvictim)
+ if (aitype != passivetype && victim->skeleton.free && !victim->dead)
+ play = 1;
+ if (tutoriallevel == 1 && id != 0)
+ play = 0;
+ if (play && aitype != playercontrolled) {
+ int whichsound = -1;
+ i = abs(Random() % 4);
+ if (speechdelay <= 0) {
+ if (creature == rabbittype) {
+ if (i == 0)
+ whichsound = rabbitchitter;
+ if (i == 1)
+ whichsound = rabbitchitter2;
+ }
+ if (creature == wolftype) {
+ if (i == 0)
+ whichsound = growlsound;
+ if (i == 1)
+ whichsound = growl2sound;
+ }
+ }
+ speechdelay = .3;
+
+ if (whichsound != -1) {
+ emit_sound_at(whichsound, coords);
+ }
+ }
+
+ if (animTarget == staggerbackhighanim)
+ staggerdelay = 1;
+ if (animTarget == staggerbackhardanim)
+ staggerdelay = 1;
+ staggerdelay -= multiplier;
+ if (animTarget != crouchstabanim && animTarget != swordgroundstabanim && animTarget != staffgroundsmashanim)
+ hasvictim = 1;
+ if (velocity.y < -30 && animTarget == jumpdownanim)
+ RagDoll(0);
+ if (animCurrent != getIdle() && wasIdle() && animTarget != getIdle() && isIdle()) {
+ animTarget = getIdle();
+ frameTarget = 0;
+ target = 0;
+ }
+ weaponmissdelay -= multiplier;
+ highreversaldelay -= multiplier;
+ lowreversaldelay -= multiplier;
+ lastcollide -= multiplier;
+ skiddelay -= multiplier;
+ if (!isnormal(velocity.x) && velocity.x) {
+ velocity = 0;
+ }
+ if (!isnormal(targettilt) && targettilt) {
+ targettilt = 0;
+ }
+ if (!isnormal(targettilt2) && targettilt2) {
+ targettilt2 = 0;
+ }
+ if (!isnormal(targetyaw) && targetyaw) {
+ targetyaw = 0;
+ }
+
+ if (animTarget == bounceidleanim || animTarget == wolfidle || animTarget == walkanim || animTarget == drawrightanim || animTarget == crouchdrawrightanim || animTarget == drawleftanim || animTarget == fightidleanim || animTarget == fightsidestep || animTarget == hanganim || isCrouch() || animTarget == backhandspringanim) {
+ //open hands and close mouth
+ if (righthandmorphend != 0 && righthandmorphness == targetrighthandmorphness) {
+ righthandmorphness = 0;
+ righthandmorphend = 0;
+ targetrighthandmorphness = 1;
+ }
+
+ if (lefthandmorphend != 0 && lefthandmorphness == targetlefthandmorphness) {
+ lefthandmorphness = 0;
+ lefthandmorphend = 0;
+ targetlefthandmorphness = 1;
+ }
+
+ if (headmorphend != 3 && headmorphend != 5 && headmorphstart != 3 && headmorphstart != 5 && headmorphend != 0 && headmorphness == targetheadmorphness) {
+ headmorphness = 0;
+ headmorphend = 0;
+ targetheadmorphness = 1;
+ }
+ }
+
+ if (animTarget == rollanim || animTarget == dodgebackanim || animTarget == removeknifeanim || animTarget == knifefightidleanim || animTarget == swordfightidleanim || animTarget == blockhighleftstrikeanim || animTarget == crouchremoveknifeanim || animTarget == sneakanim || animTarget == sweepanim || animTarget == spinkickreversedanim || animTarget == jumpdownanim || isWallJump() || isFlip() || animTarget == climbanim || isRun() || animTarget == getupfrombackanim || animTarget == getupfromfrontanim) {
+ //open hands and mouth
+ if (righthandmorphend != 0 && righthandmorphness == targetrighthandmorphness) {
+ righthandmorphness = 0;
+ righthandmorphend = 0;
+ targetrighthandmorphness = 1;
+ }
+
+ if (lefthandmorphend != 0 && lefthandmorphness == targetlefthandmorphness) {
+ lefthandmorphness = 0;
+ lefthandmorphend = 0;
+ targetlefthandmorphness = 1;
+ }
+
+ if (headmorphend != 1 && headmorphness == targetheadmorphness) {
+ headmorphness = 0;
+ headmorphend = 1;
+ targetheadmorphness = 1;
+ }
+ }
+
+ if (animTarget == jumpupanim || animTarget == crouchstabanim || animTarget == swordgroundstabanim || animTarget == swordfightidlebothanim || animTarget == blockhighleftanim) {
+ //close hands and mouth
+ if (righthandmorphend != 1 && righthandmorphness == targetrighthandmorphness) {
+ righthandmorphness = 0;
+ righthandmorphend = 1;
+ targetrighthandmorphness = 1;
+ }
+
+ if (lefthandmorphend != 1 && lefthandmorphness == targetlefthandmorphness) {
+ lefthandmorphness = 0;
+ lefthandmorphend = 1;
+ targetlefthandmorphness = 1;
+ }
+
+ if (headmorphend != 0 && headmorphness == targetheadmorphness) {
+ headmorphness = 0;
+ headmorphend = 0;
+ targetheadmorphness = 1;
+ }
+ }
+
+ if (animTarget == spinkickanim || animTarget == staffspinhitreversalanim || animTarget == staffspinhitreversedanim || animTarget == staffhitreversalanim || animTarget == staffhitreversedanim || animTarget == hurtidleanim || animTarget == winduppunchanim || animTarget == swordslashreversalanim || animTarget == swordslashreversedanim || animTarget == knifeslashreversalanim || animTarget == knifeslashreversedanim || animTarget == knifethrowanim || animTarget == knifefollowanim || animTarget == knifefollowedanim || animTarget == killanim || animTarget == dropkickanim || animTarget == upunchanim || animTarget == knifeslashstartanim || animTarget == swordslashanim || animTarget == staffhitanim || animTarget == staffspinhitanim || animTarget == staffgroundsmashanim || animTarget == spinkickreversalanim || animTarget == sweepreversalanim || animTarget == lowkickanim || animTarget == sweepreversedanim || animTarget == rabbitkickreversalanim || animTarget == rabbitkickreversedanim || animTarget == jumpreversalanim || animTarget == jumpreversedanim) {
+ //close hands and yell
+ if (righthandmorphend != 1 && righthandmorphness == targetrighthandmorphness) {
+ righthandmorphness = 0;
+ righthandmorphend = 1;
+ targetrighthandmorphness = 1;
+ }
+
+ if (lefthandmorphend != 1 && lefthandmorphness == targetlefthandmorphness) {
+ lefthandmorphness = 0;
+ lefthandmorphend = 1;
+ targetlefthandmorphness = 1;
+ }
+
+ if (headmorphend != 2 && headmorphness == targetheadmorphness) {
+ headmorphness = 1;
+ headmorphend = 2;
+ targetheadmorphness = 1;
+ }
+ }
+
+ bool behind;
+ behind = 0;
+ if (hasvictim) {
+ if ((victim != this->shared_from_this()) && !victim->dead && (victim->aitype != passivetype) &&
+ (victim->aitype != searchtype) && (aitype != passivetype) &&
+ (aitype != searchtype) && (victim->id < Person::players.size())) {
+ behind = (normaldotproduct(facing, coords - victim->coords) > 0);
+ }
+ }
+
+ if (!dead && animTarget != hurtidleanim)
+ if (behind || animTarget == killanim || animTarget == knifethrowanim || animTarget == knifefollowanim || animTarget == spinkickreversalanim || animTarget == rabbitkickreversedanim || animTarget == jumpreversedanim) {
+ if (headmorphend != 4 || headmorphness == targetheadmorphness) {
+ headmorphend = 4;
+ //headmorphness=1;
+ targetheadmorphness = 1;
+ }
+ }
+
+ if (weaponactive != -1) {
+ if (weapons[weaponids[weaponactive]].getType() != staff) {
+ righthandmorphstart = 1;
+ righthandmorphend = 1;
+ }
+ if (weapons[weaponids[weaponactive]].getType() == staff) {
+ righthandmorphstart = 2;
+ righthandmorphend = 2;
+ }
+ targetrighthandmorphness = 1;
+ }
+
+ terrainnormal = terrain.getNormal(coords.x, coords.z);
+
+ if (Animation::animations[animTarget].attack != reversal) {
+ if (!isnormal(coords.x))
+ coords = oldcoords;
+ oldcoords = coords;
+ }
+
+ flatfacing = 0;
+ flatfacing.z = 1;
+
+ flatfacing = DoRotation(flatfacing, 0, yaw, 0);
+ facing = flatfacing;
+ ReflectVector(&facing, terrainnormal);
+ Normalise(&facing);
+
+ if (isRun() || animTarget == sneakanim || animTarget == rollanim || animTarget == walkanim) {
+ if (onterrain)
+ targettilt2 = -facing.y * 20;
+ else
+ targettilt2 = 0;
+ }
+ onterrain = 0;
+ if (!isRun() && !Animation::animations[animTarget].attack && animTarget != getupfromfrontanim && animTarget != getupfrombackanim && animTarget != sneakanim)
+ targettilt2 = 0;
+ if (animTarget == jumpupanim || animTarget == jumpdownanim || isFlip()) {
+ flatvelocity = velocity;
+ flatvelocity.y = 0;
+ flatvelspeed = findLength(&flatvelocity);
+ targettilt = flatvelspeed * fast_sqrt(abs(velocity.y) * .7) * normaldotproduct(DoRotation(flatfacing, 0, -90, 0), flatvelocity);
+ targettilt2 = flatvelspeed * fast_sqrt(abs(velocity.y) * .7) * normaldotproduct(flatfacing, flatvelocity);
+ if (velocity.y < 0)
+ targettilt2 *= -1;
+ if (velocity.y < 0)
+ targettilt *= -1;
+ if (targettilt > 25)
+ targettilt = 25;
+ if (targettilt < -25)
+ targettilt = -25;
+ }
+
+ if (targettilt2 > 45)
+ targettilt2 = 45;
+ if (targettilt2 < -45)
+ targettilt2 = -45;
+ if (abs(tilt2 - targettilt2) < multiplier * 400)
+ tilt2 = targettilt2;
+ else if (tilt2 > targettilt2) {
+ tilt2 -= multiplier * 400;
+ } else if (tilt2 < targettilt2) {
+ tilt2 += multiplier * 400;
+ }
+ if (!Animation::animations[animTarget].attack && animTarget != getupfrombackanim && animTarget != getupfromfrontanim) {
+ if (tilt2 > 25)
+ tilt2 = 25;
+ if (tilt2 < -25)
+ tilt2 = -25;
+ }
+
+ if (!isnormal(targettilt) && targettilt) {
+ targettilt = 0;
+ }
+ if (!isnormal(targettilt2) && targettilt2) {
+ targettilt2 = 0;
+ }
+
+ //Running velocity
+ if (animTarget == rabbittackleanim) {
+ velocity += facing * multiplier * speed * 700 * scale;
+ velspeed = findLength(&velocity);
+ if (velspeed > speed * 65 * scale) {
+ velocity /= velspeed;
+ velspeed = speed * 65 * scale;
+ velocity *= velspeed;
+ }
+ velocity.y += gravity * multiplier * 20;
+ ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
+ velspeed = findLength(&velocity);
+ velocity = flatfacing * velspeed;
+ }
+ if (animTarget != rabbitrunninganim && animTarget != wolfrunninganim) {
+ if (isRun() || animTarget == rabbitkickanim) {
+ velocity += facing * multiplier * speed * 700 * scale;
+ velspeed = findLength(&velocity);
+ if (velspeed > speed * 45 * scale) {
+ velocity /= velspeed;
+ velspeed = speed * 45 * scale;
+ velocity *= velspeed;
+ }
+ velocity.y += gravity * multiplier * 20;
+ ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
+ velspeed = findLength(&velocity);
+ if (velspeed < speed * 30 * scale)
+ velspeed = speed * 30 * scale;
+ velocity = flatfacing * velspeed;
+ }
+ } else if (isRun()) {
+ velocity += facing * multiplier * speed * 700 * scale;
+ velspeed = findLength(&velocity);
+ if (creature == rabbittype) {
+ if (velspeed > speed * 55 * scale) {
+ velocity /= velspeed;
+ velspeed = speed * 55 * scale;
+ velocity *= velspeed;
+ }
+ }
+ if (creature == wolftype) {
+ if (velspeed > speed * 75 * scale) {
+ velocity /= velspeed;
+ velspeed = speed * 75 * scale;
+ velocity *= velspeed;
+ }
+ }
+ velocity.y += gravity * multiplier * 20;
+ ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
+ velspeed = findLength(&velocity);
+ velocity = flatfacing * velspeed;
+ }
+
+ if (animTarget == rollanim && targetFrame().label != 6) {
+ velocity += facing * multiplier * speed * 700 * scale;
+ velspeed = findLength(&velocity);
+ if (velspeed > speed * 45 * scale) {
+ velocity /= velspeed;
+ velspeed = speed * 45 * scale;
+ velocity *= velspeed;
+ }
+ velocity.y += gravity * multiplier * 20;
+ ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
+ velspeed = findLength(&velocity);
+ velocity = flatfacing * velspeed;
+ }
+
+ if (animTarget == sneakanim || animTarget == walkanim) {
+ velocity += facing * multiplier * speed * 700 * scale;
+ velspeed = findLength(&velocity);
+ if (velspeed > speed * 12 * scale) {
+ velocity /= velspeed;
+ velspeed = speed * 12 * scale;
+ velocity *= velspeed;
+ }
+ velocity.y += gravity * multiplier * 20;
+ ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
+ velspeed = findLength(&velocity);
+ velocity = flatfacing * velspeed;
+ }
+
+ if ((animTarget == fightidleanim || animTarget == knifefightidleanim) && (animCurrent == bounceidleanim || animCurrent == hurtidleanim)) {
+ velocity += facing * multiplier * speed * 700 * scale;
+ velspeed = findLength(&velocity);
+ if (velspeed > speed * 2 * scale) {
+ velocity /= velspeed;
+ velspeed = speed * 2 * scale;
+ velocity *= velspeed;
+ }
+ velocity.y += gravity * multiplier * 20;
+ ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
+ velspeed = findLength(&velocity);
+ velocity = flatfacing * velspeed;
+ }
+
+
+ if ((animTarget == bounceidleanim || animCurrent == hurtidleanim) && (animCurrent == fightidleanim || animCurrent == knifefightidleanim)) {
+ velocity -= facing * multiplier * speed * 700 * scale;
+ velspeed = findLength(&velocity);
+ if (velspeed > speed * 2 * scale) {
+ velocity /= velspeed;
+ velspeed = speed * 2 * scale;
+ velocity *= velspeed;
+ }
+ velocity.y += gravity * multiplier * 20;
+ ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
+ velspeed = findLength(&velocity);
+ velocity = flatfacing * velspeed * -1;
+ }
+
+ if (animTarget == fightsidestep) {
+ velocity += DoRotation(facing * multiplier * speed * 700 * scale, 0, -90, 0);
+ velspeed = findLength(&velocity);
+ if (velspeed > speed * 12 * scale) {
+ velocity /= velspeed;
+ velspeed = speed * 12 * scale;
+ velocity *= velspeed;
+ }
+ velocity.y += gravity * multiplier * 20;
+ ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
+ velspeed = findLength(&velocity);
+ velocity = DoRotation(flatfacing * velspeed, 0, -90, 0);
+ }
+
+ if (animTarget == staggerbackhighanim) {
+ coords -= facing * multiplier * speed * 16 * scale;
+ velocity = 0;
+ }
+ if (animTarget == staggerbackhardanim && Animation::animations[staggerbackhardanim].frames[frameTarget].label != 6) {
+ coords -= facing * multiplier * speed * 20 * scale;
+ velocity = 0;
+ }
+
+ if (animTarget == backhandspringanim) {
+ //coords-=facing*multiplier*50*scale;
+ velocity += facing * multiplier * speed * 700 * scale * -1;
+ velspeed = findLength(&velocity);
+ if (velspeed > speed * 50 * scale) {
+ velocity /= velspeed;
+ velspeed = speed * 50 * scale;
+ velocity *= velspeed;
+ }
+ velocity.y += gravity * multiplier * 20;
+ ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
+ velspeed = findLength(&velocity);
+ velocity = flatfacing * velspeed * -1;
+ }
+ if (animTarget == dodgebackanim) {
+ //coords-=facing*multiplier*50*scale;
+ velocity += facing * multiplier * speed * 700 * scale * -1;
+ velspeed = findLength(&velocity);
+ if (velspeed > speed * 60 * scale) {
+ velocity /= velspeed;
+ velspeed = speed * 60 * scale;
+ velocity *= velspeed;
+ }
+ velocity.y += gravity * multiplier * 20;
+ ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
+ velspeed = findLength(&velocity);
+ velocity = flatfacing * velspeed * -1;
+ }
+
+ if (animTarget == jumpupanim || animTarget == jumpdownanim || isFlip()) {
+ velspeed = findLength(&velocity);
+ }
+
+
+ if (animTarget == jumpupanim || animTarget == jumpdownanim || isFlip()) {
+ velocity.y += gravity * multiplier;
+ }
+
+ if (animTarget != climbanim && animTarget != hanganim && !isWallJump())
+ coords += velocity * multiplier;
+
+ if (coords.y < terrain.getHeight(coords.x, coords.z) && (animTarget == jumpdownanim || animTarget == jumpupanim || isFlip())) {
+ if (isFlip() && targetFrame().label == 7)
+ RagDoll(0);
+
+ if (animTarget == jumpupanim) {
+ jumppower = -4;
+ animTarget = getIdle();
+ }
+ target = 0;
+ frameTarget = 0;
+ onterrain = 1;
+
+ if (id == 0) {
+ pause_sound(whooshsound);
+ OPENAL_SetVolume(channels[whooshsound], 0);
+ }
+
+ if (animTarget == jumpdownanim || isFlip()) {
+ if (isFlip())jumppower = -4;
+ animTarget = getLanding();
+ emit_sound_at(landsound, coords, 128.);
+
+ if (id == 0) {
+ addEnvSound(coords);
+ }
+ }
+ }
+
+ if (animTarget != jumpupanim && animTarget != jumpdownanim && !isFlip() && animTarget != climbanim && animTarget != hanganim && !isWallJump())
+ coords.y += gravity * multiplier * 2;
+ if (animTarget != jumpupanim && animTarget != jumpdownanim && !isFlip() && coords.y < terrain.getHeight(coords.x, coords.z)) {
+ coords.y = terrain.getHeight(coords.x, coords.z);
+ onterrain = 1;
+ }
+
+
+ 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 && targetFrame().label == 6)) {
+ velspeed = findLength(&velocity);
+ velocity.y = 0;
+ if (velspeed < multiplier * 300 * scale) {
+ velocity = 0;
+ } else
+ velocity -= velocity / velspeed * multiplier * 300 * scale;
+ if (velspeed > 5 && (isLanding() || isLandhard())) {
+ skiddingdelay += multiplier;
+ if (skiddelay <= 0) {
+ FootLand(leftfoot, .5);
+ FootLand(rightfoot, .5);
+ skiddelay = .02;
+ }
+ } else
+ skiddingdelay = 0;
+ }
+
+ if (isLandhard()) {
+ velspeed = findLength(&velocity);
+ velocity.y = 0;
+ if (velspeed < multiplier * 600 * scale) {
+ velocity = 0;
+ } else
+ velocity -= velocity / velspeed * multiplier * 600 * scale;
+ velocity = 0;
+ if (velspeed > 5 && (isLanding() || isLandhard())) {
+ skiddingdelay += multiplier;
+ if (skiddelay <= 0) {
+ FootLand(leftfoot, .5);
+ FootLand(rightfoot, .5);
+ skiddelay = .02;
+ }
+ } else
+ skiddingdelay = 0;
+ }
+
+ if (skiddingdelay < 0)
+ skiddingdelay += multiplier;
+ if (skiddingdelay > .02 && !forwardkeydown && !backkeydown && !leftkeydown && !rightkeydown && !jumpkeydown && isLanding() && !landhard) {
+ skiddingdelay = -1;
+ if (!onterrain || environment == grassyenvironment) {
+ emit_sound_at(skidsound, coords, 128 * velspeed / 10);
+ } else {
+ emit_sound_at(snowskidsound, coords, 128 * velspeed / 10);
+ }
+ }
+
+ if (Animation::animations[animTarget].attack == normalattack && animTarget != rabbitkickanim && !victim->skeleton.free) {
+ terrainnormal = victim->coords - coords;
+ Normalise(&terrainnormal);
+ targetyaw = -asin(0 - terrainnormal.x);
+ targetyaw *= 360 / 6.28;
+ if (terrainnormal.z < 0)
+ targetyaw = 180 - targetyaw;
+ targettilt2 = -asin(terrainnormal.y) * 360 / 6.28; //*-70;
+ }
+
+ if (Animation::animations[animTarget].attack == reversal && animTarget != rabbittacklinganim) {
+ targetyaw = victim->targetyaw;
+ }
+ if (animTarget == rabbittacklinganim) {
+ coords = victim->coords;
+ }
+ }
+ skeleton.oldfree = skeleton.free;
+
+ XYZ midterrain;
+ midterrain = 0;
+ midterrain.x = terrain.size * terrain.scale / 2;
+ midterrain.z = terrain.size * terrain.scale / 2;
+ if (distsqflat(&coords, &midterrain) > (terrain.size * terrain.scale / 2 - viewdistance) * (terrain.size * terrain.scale / 2 - viewdistance)) {
+ XYZ tempposit;
+ tempposit = coords - midterrain;
+ tempposit.y = 0;
+ Normalise(&tempposit);
+ tempposit *= (terrain.size * terrain.scale / 2 - viewdistance);
+ coords.x = tempposit.x + midterrain.x;
+ coords.z = tempposit.z + midterrain.z;
+ }
+}
+
+
+/* EFFECT
+ * inverse kinematics helper function
+ */
+void IKHelper(Person *p, float interp)
+{
+ XYZ point, change, change2;
+ float heightleft, heightright;
+
+ // TODO: implement localToWorld and worldToLocal
+ // but keep in mind it won't be the same math if player is ragdolled or something
+ // - localToWorldStanding / worldToLocalStanding (or crouching or...?)
+ // then comb through code for places where to use it
+
+ // point = localToWorld(jointPos(leftfoot))
+ point = DoRotation(p->jointPos(leftfoot), 0, p->yaw, 0) * p->scale + p->coords;
+ // adjust height of foot
+ heightleft = terrain.getHeight(point.x, point.z) + .04;
+ point.y = heightleft;
+ change = p->jointPos(leftankle) - p->jointPos(leftfoot);
+ change2 = p->jointPos(leftknee) - p->jointPos(leftfoot);
+ // jointPos(leftfoot) = interpolate(worldToLocal(point), jointPos(leftfoot), interp)
+ p->jointPos(leftfoot) = DoRotation((point - p->coords) / p->scale, 0, -p->yaw, 0) * interp + p->jointPos(leftfoot) * (1 - interp);
+ // move ankle along with foot
+ p->jointPos(leftankle) = p->jointPos(leftfoot) + change;
+ // average knee pos between old and new pos
+ p->jointPos(leftknee) = (p->jointPos(leftfoot) + change2) / 2 + (p->jointPos(leftknee)) / 2;
+
+ // do same as above for right leg
+ point = DoRotation(p->jointPos(rightfoot), 0, p->yaw, 0) * p->scale + p->coords;
+ heightright = terrain.getHeight(point.x, point.z) + .04;
+ point.y = heightright;
+ change = p->jointPos(rightankle) - p->jointPos(rightfoot);
+ change2 = p->jointPos(rightknee) - p->jointPos(rightfoot);
+ p->jointPos(rightfoot) = DoRotation((point - p->coords) / p->scale, 0, -p->yaw, 0) * interp + p->jointPos(rightfoot) * (1 - interp);
+ p->jointPos(rightankle) = p->jointPos(rightfoot) + change;
+ p->jointPos(rightknee) = (p->jointPos(rightfoot) + change2) / 2 + (p->jointPos(rightknee)) / 2;
+
+ // fix up skeleton now that we've moved body parts?
+ p->skeleton.DoConstraints(&p->coords, &p->scale);
+}
+
+/* EFFECT
+ * MONSTER
+ * TODO: ???
+ */
+int Person::DrawSkeleton()
+{
+ int oldplayerdetail;
+ if ((frustum.SphereInFrustum(coords.x, coords.y + scale * 3, coords.z, scale * 8) && distsq(&viewer, &coords) < viewdistance * viewdistance) || skeleton.free == 3) {
+ if (onterrain && (isIdle() || isCrouch() || wasIdle() || wasCrouch()) && !skeleton.free) {
+ calcrot = 1;
+ }
+
+ if (headless) {
+ headmorphness = 0;
+ headmorphstart = 6;
+ headmorphend = 6;
+ }
+
+ glAlphaFunc(GL_GREATER, 0.0001);
+ XYZ terrainlight;
+ float terrainheight;
+ float distance;
+ if (!isnormal(yaw))
+ yaw = 0;
+ if (!isnormal(tilt))
+ tilt = 0;
+ if (!isnormal(tilt2))
+ tilt2 = 0;
+ oldplayerdetail = playerdetail;
+ playerdetail = 0;
+ if (distsq(&viewer, &coords) < viewdistance * viewdistance / 32 && detail == 2) {
+ playerdetail = 1;
+ }
+ if (distsq(&viewer, &coords) < viewdistance * viewdistance / 128 && detail == 1) {
+ playerdetail = 1;
+ }
+ if (distsq(&viewer, &coords) < viewdistance * viewdistance / 256 && (detail != 1 && detail != 2)) {
+ playerdetail = 1;
+ }
+ if (id == 0)
+ playerdetail = 1;
+ if (playerdetail != oldplayerdetail) {
+ updatedelay = 0;
+ normalsupdatedelay = 0;
+ }
+ static float updatedelaychange;
+ static float morphness;
+ static float framemult;
+ if (calcrot) {
+ skeleton.FindForwards();
+ if (howactive == typesittingwall) {
+ skeleton.specialforward[1] = 0;
+ skeleton.specialforward[1].z = 1;
+ }
+ }
+ static XYZ mid;
+ static float M[16];
+ static int i, j, k;
+ static int weaponattachmuscle;
+ static int weaponrotatemuscle;
+ static XYZ weaponpoint;
+ static int start, endthing;
+ if ((dead != 2 || skeleton.free != 2) && updatedelay <= 0) {
+ if (!isSleeping() && !isSitting()) {
+ // TODO: give these meaningful names
+ const bool cond1 = (isIdle() || isCrouch() || isLanding() || isLandhard()
+ || animTarget == drawrightanim || animTarget == drawleftanim || animTarget == crouchdrawrightanim);
+ const bool cond2 = (wasIdle() || wasCrouch() || wasLanding() || wasLandhard()
+ || animCurrent == drawrightanim || animCurrent == drawleftanim || animCurrent == crouchdrawrightanim);
+
+ if (onterrain && (cond1 && cond2) && !skeleton.free) {
+ IKHelper(this, 1);
+ if (creature == wolftype)
+ IKHelper(this, 1);
+ }
+
+ if (onterrain && (cond1 && !cond2) && !skeleton.free) {
+ IKHelper(this, target);
+ if (creature == wolftype)
+ IKHelper(this, target);
+ }
+
+ if (onterrain && (!cond1 && cond2) && !skeleton.free) {
+ IKHelper(this, 1 - target);
+ if (creature == wolftype)
+ IKHelper(this, 1 - target);
+ }
+ }
+
+ if (!skeleton.free && (!Animation::animations[animTarget].attack && animTarget != getupfrombackanim && ((animTarget != rollanim && !isFlip()) || targetFrame().label == 6) && animTarget != getupfromfrontanim && animTarget != wolfrunninganim && animTarget != rabbitrunninganim && animTarget != backhandspringanim && animTarget != walljumpfrontanim && animTarget != hurtidleanim && !isLandhard() && !isSleeping()))
+ DoHead();
+ else {
+ targetheadyaw = -targetyaw;
+ targetheadpitch = 0;
+ if (Animation::animations[animTarget].attack == 3)
+ targetheadyaw += 180;
+ }
+ for (i = 0; i < skeleton.drawmodel.vertexNum; i++) {
+ skeleton.drawmodel.vertex[i] = 0;
+ skeleton.drawmodel.vertex[i].y = 999;
+ }
+ for (i = 0; i < skeleton.drawmodellow.vertexNum; i++) {
+ skeleton.drawmodellow.vertex[i] = 0;
+ skeleton.drawmodellow.vertex[i].y = 999;
+ }
+ for (i = 0; i < skeleton.drawmodelclothes.vertexNum; i++) {
+ skeleton.drawmodelclothes.vertex[i] = 0;
+ skeleton.drawmodelclothes.vertex[i].y = 999;
+ }
+ for (int i = 0; i < skeleton.muscles.size(); i++) {
+ // convenience renames
+ const int p1 = skeleton.muscles[i].parent1->label;
+ const int p2 = skeleton.muscles[i].parent2->label;
+
+ if ((skeleton.muscles[i].vertices.size() > 0 && playerdetail) || (skeleton.muscles[i].verticeslow.size() > 0 && !playerdetail)) {
+ morphness = 0;
+ start = 0;
+ endthing = 0;
+
+ if (p1 == righthand || p2 == righthand) {
+ morphness = righthandmorphness;
+ start = righthandmorphstart;
+ endthing = righthandmorphend;
+ }
+ if (p1 == lefthand || p2 == lefthand) {
+ morphness = lefthandmorphness;
+ start = lefthandmorphstart;
+ endthing = lefthandmorphend;
+ }
+ if (p1 == head || p2 == head) {
+ morphness = headmorphness;
+ start = headmorphstart;
+ endthing = headmorphend;
+ }
+ if ((p1 == neck && p2 == abdomen) || (p2 == neck && p1 == abdomen)) {
+ morphness = chestmorphness;
+ start = chestmorphstart;
+ endthing = chestmorphend;
+ }
+ if ((p1 == groin && p2 == abdomen) || (p2 == groin && p1 == abdomen)) {
+ morphness = tailmorphness;
+ start = tailmorphstart;
+ endthing = tailmorphend;
+ }
+ if (calcrot)
+ skeleton.FindRotationMuscle(i, animTarget);
+ mid = (skeleton.muscles[i].parent1->position + skeleton.muscles[i].parent2->position) / 2;
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+ if (!skeleton.free)
+ glRotatef(tilt2, 1, 0, 0);
+ if (!skeleton.free)
+ glRotatef(tilt, 0, 0, 1);
+
+
+ glTranslatef(mid.x, mid.y, mid.z);
+
+ skeleton.muscles[i].lastrotate1 = skeleton.muscles[i].rotate1;
+ glRotatef(-skeleton.muscles[i].lastrotate1 + 90, 0, 1, 0);
+
+ skeleton.muscles[i].lastrotate2 = skeleton.muscles[i].rotate2;
+ glRotatef(-skeleton.muscles[i].lastrotate2 + 90, 0, 0, 1);
+
+ skeleton.muscles[i].lastrotate3 = skeleton.muscles[i].rotate3;
+ glRotatef(-skeleton.muscles[i].lastrotate3, 0, 1, 0);
+
+ if (playerdetail || skeleton.free == 3) {
+ for (j = 0; j < skeleton.muscles[i].vertices.size(); j++) {
+ XYZ &v0 = skeleton.model[start].vertex[skeleton.muscles[i].vertices[j]];
+ XYZ &v1 = skeleton.model[endthing].vertex[skeleton.muscles[i].vertices[j]];
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ if (p1 == abdomen || p2 == abdomen)
+ glTranslatef((v0.x * (1 - morphness) + v1.x * morphness) * proportionbody.x,
+ (v0.y * (1 - morphness) + v1.y * morphness) * proportionbody.y,
+ (v0.z * (1 - morphness) + v1.z * morphness) * proportionbody.z);
+ if (p1 == lefthand || p1 == righthand || p1 == leftwrist || p1 == rightwrist || p1 == leftelbow || p1 == rightelbow || p2 == leftelbow || p2 == rightelbow)
+ glTranslatef((v0.x * (1 - morphness) + v1.x * morphness) * proportionarms.x,
+ (v0.y * (1 - morphness) + v1.y * morphness) * proportionarms.y,
+ (v0.z * (1 - morphness) + v1.z * morphness) * proportionarms.z);
+ if (p1 == leftfoot || p1 == rightfoot || p1 == leftankle || p1 == rightankle || p1 == leftknee || p1 == rightknee || p2 == leftknee || p2 == rightknee)
+ glTranslatef((v0.x * (1 - morphness) + v1.x * morphness) * proportionlegs.x,
+ (v0.y * (1 - morphness) + v1.y * morphness) * proportionlegs.y,
+ (v0.z * (1 - morphness) + v1.z * morphness) * proportionlegs.z);
+ if (p1 == head || p2 == head)
+ glTranslatef((v0.x * (1 - morphness) + v1.x * morphness) * proportionhead.x,
+ (v0.y * (1 - morphness) + v1.y * morphness) * proportionhead.y,
+ (v0.z * (1 - morphness) + v1.z * morphness) * proportionhead.z);
+ glGetFloatv(GL_MODELVIEW_MATRIX, M);
+ skeleton.drawmodel.vertex[skeleton.muscles[i].vertices[j]].x = M[12] * scale;
+ skeleton.drawmodel.vertex[skeleton.muscles[i].vertices[j]].y = M[13] * scale;
+ skeleton.drawmodel.vertex[skeleton.muscles[i].vertices[j]].z = M[14] * scale;
+ glPopMatrix();
+ }
+ }
+ if (!playerdetail || skeleton.free == 3) {
+ for (j = 0; j < skeleton.muscles[i].verticeslow.size(); j++) {
+ XYZ &v0 = skeleton.modellow.vertex[skeleton.muscles[i].verticeslow[j]];
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ if (p1 == abdomen || p2 == abdomen)
+ glTranslatef(v0.x * proportionbody.x,
+ v0.y * proportionbody.y,
+ v0.z * proportionbody.z);
+ if (p1 == lefthand || p1 == righthand || p1 == leftwrist || p1 == rightwrist || p1 == leftelbow || p1 == rightelbow || p2 == leftelbow || p2 == rightelbow)
+ glTranslatef(v0.x * proportionarms.x,
+ v0.y * proportionarms.y,
+ v0.z * proportionarms.z);
+ if (p1 == leftfoot || p1 == rightfoot || p1 == leftankle || p1 == rightankle || p1 == leftknee || p1 == rightknee || p2 == leftknee || p2 == rightknee)
+ glTranslatef(v0.x * proportionlegs.x,
+ v0.y * proportionlegs.y,
+ v0.z * proportionlegs.z);
+ if (p1 == head || p2 == head)
+ glTranslatef(v0.x * proportionhead.x,
+ v0.y * proportionhead.y,
+ v0.z * proportionhead.z);
+
+ glGetFloatv(GL_MODELVIEW_MATRIX, M);
+ skeleton.drawmodellow.vertex[skeleton.muscles[i].verticeslow[j]].x = M[12] * scale;
+ skeleton.drawmodellow.vertex[skeleton.muscles[i].verticeslow[j]].y = M[13] * scale;
+ skeleton.drawmodellow.vertex[skeleton.muscles[i].verticeslow[j]].z = M[14] * scale;
+ glPopMatrix();
+ }
+ }
+ glPopMatrix();
+ }
+ if (skeleton.clothes && skeleton.muscles[i].verticesclothes.size() > 0) {
+ mid = (skeleton.muscles[i].parent1->position + skeleton.muscles[i].parent2->position) / 2;
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+ if (!skeleton.free)
+ glRotatef(tilt2, 1, 0, 0);
+ if (!skeleton.free)
+ glRotatef(tilt, 0, 0, 1);
+ glTranslatef(mid.x, mid.y, mid.z);
+ skeleton.muscles[i].lastrotate1 = skeleton.muscles[i].rotate1;
+ glRotatef(-skeleton.muscles[i].lastrotate1 + 90, 0, 1, 0);
+
+ skeleton.muscles[i].lastrotate2 = skeleton.muscles[i].rotate2;
+ glRotatef(-skeleton.muscles[i].lastrotate2 + 90, 0, 0, 1);
+
+ skeleton.muscles[i].lastrotate3 = skeleton.muscles[i].rotate3;
+ glRotatef(-skeleton.muscles[i].lastrotate3, 0, 1, 0);
+
+ for (j = 0; j < skeleton.muscles[i].verticesclothes.size(); j++) {
+ XYZ &v0 = skeleton.modelclothes.vertex[skeleton.muscles[i].verticesclothes[j]];
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ if (p1 == abdomen || p2 == abdomen)
+ glTranslatef(v0.x * proportionbody.x,
+ v0.y * proportionbody.y,
+ v0.z * proportionbody.z);
+ if (p1 == lefthand || p1 == righthand || p1 == leftwrist || p1 == rightwrist || p1 == leftelbow || p1 == rightelbow || p2 == leftelbow || p2 == rightelbow)
+ glTranslatef(v0.x * proportionarms.x,
+ v0.y * proportionarms.y,
+ v0.z * proportionarms.z);
+ if (p1 == leftfoot || p1 == rightfoot || p1 == leftankle || p1 == rightankle || p1 == leftknee || p1 == rightknee || p2 == leftknee || p2 == rightknee)
+ glTranslatef(v0.x * proportionlegs.x,
+ v0.y * proportionlegs.y,
+ v0.z * proportionlegs.z);
+ if (p1 == head || p2 == head)
+ glTranslatef(v0.x * proportionhead.x,
+ v0.y * proportionhead.y,
+ v0.z * proportionhead.z);
+ glGetFloatv(GL_MODELVIEW_MATRIX, M);
+ skeleton.drawmodelclothes.vertex[skeleton.muscles[i].verticesclothes[j]].x = M[12] * scale;
+ skeleton.drawmodelclothes.vertex[skeleton.muscles[i].verticesclothes[j]].y = M[13] * scale;
+ skeleton.drawmodelclothes.vertex[skeleton.muscles[i].verticesclothes[j]].z = M[14] * scale;
+ glPopMatrix();
+ }
+ glPopMatrix();
+ }
+ updatedelay = 1 + (float)(Random() % 100) / 1000;
+ }
+ if (skeleton.free != 2 && (skeleton.free == 1 || skeleton.free == 3 || id == 0 || (normalsupdatedelay <= 0) || animTarget == getupfromfrontanim || animTarget == getupfrombackanim || animCurrent == getupfromfrontanim || animCurrent == getupfrombackanim)) {
+ normalsupdatedelay = 1;
+ if (playerdetail || skeleton.free == 3)
+ skeleton.drawmodel.CalculateNormals(0);
+ if (!playerdetail || skeleton.free == 3)
+ skeleton.drawmodellow.CalculateNormals(0);
+ if (skeleton.clothes)
+ skeleton.drawmodelclothes.CalculateNormals(0);
+ } else {
+ if (playerdetail || skeleton.free == 3)
+ skeleton.drawmodel.UpdateVertexArrayNoTexNoNorm();
+ if (!playerdetail || skeleton.free == 3)
+ skeleton.drawmodellow.UpdateVertexArrayNoTexNoNorm();
+ if (skeleton.clothes) {
+ skeleton.drawmodelclothes.UpdateVertexArrayNoTexNoNorm();
+ }
+ }
+ }
+ framemult = .01;
+ updatedelaychange = -framemult * 4 * (45 - findDistance(&viewer, &coords) * 1);
+ if (updatedelaychange > -realmultiplier * 30)
+ updatedelaychange = -realmultiplier * 30;
+ if (updatedelaychange > -framemult * 4)
+ updatedelaychange = -framemult * 4;
+ if (skeleton.free == 1)
+ updatedelaychange *= 6;
+ if (id == 0)
+ updatedelaychange *= 8;
+ updatedelay += updatedelaychange;
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glTranslatef(coords.x, coords.y - .02, coords.z);
+ if (!skeleton.free) {
+ glTranslatef(offset.x * scale, offset.y * scale, offset.z * scale);
+ glRotatef(yaw, 0, 1, 0);
+ }
+ if (showpoints) {
+ glPointSize(5);
+ glColor4f(.4, 1, .4, 1);
+ glDisable(GL_LIGHTING);
+ glDisable(GL_TEXTURE_2D);
+ glBegin(GL_POINTS);
+ if (playerdetail)
+ for (i = 0; i < skeleton.drawmodel.vertexNum; i++) {
+ XYZ &v0 = skeleton.drawmodel.vertex[i];
+ glVertex3f(v0.x, v0.y, v0.z);
+ }
+ glEnd();
+ glBegin(GL_LINES);
+
+ if (playerdetail)
+ for (i = 0; i < skeleton.drawmodel.TriangleNum; i++) {
+ XYZ &v0 = skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[i].vertex[0]];
+ XYZ &v1 = skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[i].vertex[1]];
+ XYZ &v2 = skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[i].vertex[2]];
+ glVertex3f(v0.x, v0.y, v0.z);
+ glVertex3f(v1.x, v1.y, v1.z);
+ glVertex3f(v1.x, v1.y, v1.z);
+ glVertex3f(v2.x, v2.y, v2.z);
+ glVertex3f(v2.x, v2.y, v2.z);
+ glVertex3f(v0.x, v0.y, v0.z);
+ }
+
+ glEnd();
+ }
+
+ terrainlight = terrain.getLighting(coords.x, coords.z);
+ distance = distsq(&viewer, &coords);
+ distance = (viewdistance * viewdistance - (distance - (viewdistance * viewdistance * fadestart)) * (1 / (1 - fadestart))) / viewdistance / viewdistance;
+ if (distance > 1)
+ distance = 1;
+ if (distance > 0) {
+ terrainheight = (coords.y - terrain.getHeight(coords.x, coords.z)) / 3 + 1;
+ if (terrainheight < 1)
+ terrainheight = 1;
+ if (terrainheight > 1.7)
+ terrainheight = 1.7;
+
+ glColor4f((1 - (1 - terrainlight.x) / terrainheight) - burnt, (1 - (1 - terrainlight.y) / terrainheight) - burnt, (1 - (1 - terrainlight.z) / terrainheight) - burnt, distance);
+ glDisable(GL_BLEND);
+ glAlphaFunc(GL_GREATER, 0.0001);
+ glEnable(GL_TEXTURE_2D);
+ if (cellophane) {
+ glDisable(GL_TEXTURE_2D);
+ glColor4f(.7, .35, 0, .5);
+ glDepthMask(0);
+ glEnable(GL_LIGHTING);
+ glEnable(GL_BLEND);
+ }
+ if (tutoriallevel && id != 0) {
+ glColor4f(.7, .7, .7, 0.6);
+ glDepthMask(0);
+ glEnable(GL_LIGHTING);
+ glEnable(GL_BLEND);
+ if (canattack && cananger)
+ if (Animation::animations[animTarget].attack == normalattack || Animation::animations[animTarget].attack == reversed) {
+ glDisable(GL_TEXTURE_2D);
+ glColor4f(1, 0, 0, 0.8);
+ }
+ glMatrixMode(GL_TEXTURE);
+ glPushMatrix();
+ glTranslatef(0, -smoketex, 0);
+ glTranslatef(-smoketex, 0, 0);
+ }
+ if (playerdetail) {
+ if (!showpoints) {
+ if ((tutoriallevel && id != 0))
+ skeleton.drawmodel.drawdifftex(Sprite::cloudimpacttexture);
+ else
+ skeleton.drawmodel.draw();
+ }
+ }
+ if (!playerdetail) {
+ if ((tutoriallevel && id != 0))
+ skeleton.drawmodellow.drawdifftex(Sprite::cloudimpacttexture);
+ else
+ skeleton.drawmodellow.drawdifftex(skeleton.drawmodel.textureptr);
+ }
+
+ if (!(Animation::animations[animTarget].attack == normalattack || Animation::animations[animTarget].attack == reversed))
+ if (tutoriallevel && id != 0) {
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glEnable(GL_TEXTURE_2D);
+ glColor4f(.7, .7, .7, 0.6);
+ glDepthMask(0);
+ glEnable(GL_LIGHTING);
+ glEnable(GL_BLEND);
+ if (canattack && cananger)
+ if (Animation::animations[animTarget].attack == normalattack || Animation::animations[animTarget].attack == reversed) {
+ glDisable(GL_TEXTURE_2D);
+ glColor4f(1, 0, 0, 0.8);
+ }
+ glMatrixMode(GL_TEXTURE);
+ glPushMatrix();
+ glTranslatef(0, -smoketex * .6, 0);
+ glTranslatef(smoketex * .6, 0, 0);
+ if (playerdetail) {
+ if (!showpoints) {
+ if ((tutoriallevel && id != 0))
+ skeleton.drawmodel.drawdifftex(Sprite::cloudimpacttexture);
+ else
+ skeleton.drawmodel.draw();
+ }
+ }
+ if (!playerdetail) {
+ if ((tutoriallevel && id != 0))
+ skeleton.drawmodellow.drawdifftex(Sprite::cloudimpacttexture);
+ else
+ skeleton.drawmodellow.drawdifftex(skeleton.drawmodel.textureptr);
+ }
+ }
+
+
+ if (tutoriallevel && id != 0) {
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glEnable(GL_TEXTURE_2D);
+ }
+ if (skeleton.clothes) {
+ glDepthMask(0);
+ glEnable(GL_BLEND);
+ if (!immediate)
+ skeleton.drawmodelclothes.draw();
+ if (immediate)
+ skeleton.drawmodelclothes.drawimmediate();
+ glDepthMask(1);
+ }
+ }
+ glPopMatrix();
+
+ if (num_weapons > 0) {
+ for (k = 0; k < num_weapons; k++) {
+ i = weaponids[k];
+ if (weaponactive == k) {
+ if (weapons[i].getType() != staff) {
+ for (j = 0; j < skeleton.muscles.size(); j++) {
+ if ((skeleton.muscles[j].parent1->label == righthand || skeleton.muscles[j].parent2->label == righthand) && skeleton.muscles[j].vertices.size() > 0) {
+ weaponattachmuscle = j;
+ }
+ }
+ for (j = 0; j < skeleton.muscles.size(); j++) {
+ if ((skeleton.muscles[j].parent1->label == rightwrist || skeleton.muscles[j].parent2->label == rightwrist) && (skeleton.muscles[j].parent1->label != righthand && skeleton.muscles[j].parent2->label != righthand) && skeleton.muscles[j].vertices.size() > 0) {
+ weaponrotatemuscle = j;
+ }
+ }
+ weaponpoint = (skeleton.muscles[weaponattachmuscle].parent1->position + skeleton.muscles[weaponattachmuscle].parent2->position) / 2;
+ if (creature == wolftype)
+ weaponpoint = (jointPos(rightwrist) * .7 + jointPos(righthand) * .3);
+ }
+ if (weapons[i].getType() == staff) {
+ for (j = 0; j < skeleton.muscles.size(); j++) {
+ if ((skeleton.muscles[j].parent1->label == righthand || skeleton.muscles[j].parent2->label == righthand) && skeleton.muscles[j].vertices.size() > 0) {
+ weaponattachmuscle = j;
+ }
+ }
+ for (j = 0; j < skeleton.muscles.size(); j++) {
+ if ((skeleton.muscles[j].parent1->label == rightelbow || skeleton.muscles[j].parent2->label == rightelbow) && (skeleton.muscles[j].parent1->label != rightshoulder && skeleton.muscles[j].parent2->label != rightshoulder) && skeleton.muscles[j].vertices.size() > 0) {
+ weaponrotatemuscle = j;
+ }
+ }
+ //weaponpoint=jointPos(rightwrist);
+ weaponpoint = (skeleton.muscles[weaponattachmuscle].parent1->position + skeleton.muscles[weaponattachmuscle].parent2->position) / 2;
+ //weaponpoint+=skeleton.specialforward[1]*.1+(jointPos(rightwrist)-jointPos(rightelbow));
+ XYZ tempnormthing, vec1, vec2;
+ vec1 = (jointPos(rightwrist) - jointPos(rightelbow));
+ vec2 = (jointPos(rightwrist) - jointPos(rightshoulder));
+ CrossProduct(&vec1, &vec2, &tempnormthing);
+ Normalise(&tempnormthing);
+ if (animTarget != staffhitanim && animCurrent != staffhitanim && animTarget != staffgroundsmashanim && animCurrent != staffgroundsmashanim && animTarget != staffspinhitanim && animCurrent != staffspinhitanim)
+ weaponpoint += tempnormthing * .1 - skeleton.specialforward[1] * .3 + (jointPos(rightwrist) - jointPos(rightelbow));
+ }
+ }
+ if (weaponactive != k && weaponstuck != k) {
+ if (weapons[i].getType() == knife)
+ weaponpoint = jointPos(abdomen) + (jointPos(righthip) - jointPos(lefthip)) * .1 + (jointPos(rightshoulder) - jointPos(leftshoulder)) * .35;
+ if (weapons[i].getType() == sword)
+ weaponpoint = jointPos(abdomen) + (jointPos(lefthip) - jointPos(righthip)) * .09 + (jointPos(leftshoulder) - jointPos(rightshoulder)) * .33;
+ if (weapons[i].getType() == staff)
+ weaponpoint = jointPos(abdomen) + (jointPos(lefthip) - jointPos(righthip)) * .09 + (jointPos(leftshoulder) - jointPos(rightshoulder)) * .33;
+ for (j = 0; j < skeleton.muscles.size(); j++) {
+ if ((skeleton.muscles[j].parent1->label == abdomen || skeleton.muscles[j].parent2->label == abdomen) && (skeleton.muscles[j].parent1->label == neck || skeleton.muscles[j].parent2->label == neck) && skeleton.muscles[j].vertices.size() > 0) {
+ weaponrotatemuscle = j;
+ }
+ }
+ }
+ if (weaponstuck == k) {
+ if (weaponstuckwhere == 0)
+ weaponpoint = jointPos(abdomen) * .5 + jointPos(neck) * .5 - skeleton.forward * .8;
+ else
+ weaponpoint = jointPos(abdomen) * .5 + jointPos(neck) * .5 + skeleton.forward * .8;
+ for (j = 0; j < skeleton.muscles.size(); j++) {
+ if ((skeleton.muscles[j].parent1->label == abdomen || skeleton.muscles[j].parent2->label == abdomen) && (skeleton.muscles[j].parent1->label == neck || skeleton.muscles[j].parent2->label == neck) && skeleton.muscles[j].vertices.size() > 0) {
+ weaponrotatemuscle = j;
+ }
+ }
+ }
+ if (skeleton.free) {
+ weapons[i].position = weaponpoint * scale + coords;
+ weapons[i].bigrotation = 0;
+ weapons[i].bigtilt = 0;
+ weapons[i].bigtilt2 = 0;
+ } else {
+ weapons[i].position = DoRotation(DoRotation(DoRotation(weaponpoint, 0, 0, tilt), tilt2, 0, 0), 0, yaw, 0) * scale + coords + currentoffset * (1 - target) * scale + targetoffset * target * scale;
+ weapons[i].bigrotation = yaw;
+ weapons[i].bigtilt = tilt;
+ weapons[i].bigtilt2 = tilt2;
+ }
+ weapons[i].rotation1 = skeleton.muscles[weaponrotatemuscle].lastrotate1;
+ weapons[i].rotation2 = skeleton.muscles[weaponrotatemuscle].lastrotate2;
+ weapons[i].rotation3 = skeleton.muscles[weaponrotatemuscle].lastrotate3;
+ if (weaponactive == k) {
+ if (weapons[i].getType() == knife) {
+ weapons[i].smallrotation = 180;
+ weapons[i].smallrotation2 = 0;
+ if (isCrouch() || wasCrouch()) {
+ weapons[i].smallrotation2 = 20;
+ }
+ if (animTarget == hurtidleanim) {
+ weapons[i].smallrotation2 = 50;
+ }
+ if ((animCurrent == crouchstabanim && animTarget == crouchstabanim) || (animCurrent == backhandspringanim && animTarget == backhandspringanim)) {
+ XYZ temppoint1, temppoint2;
+ float distance;
+
+ temppoint1 = jointPos(righthand);
+ temppoint2 = currentFrame().weapontarget * (1 - target) + targetFrame().weapontarget * (target);
+ distance = findDistance(&temppoint1, &temppoint2);
+ weapons[i].rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
+ weapons[i].rotation2 *= 360 / 6.28;
+ temppoint1.y = 0;
+ temppoint2.y = 0;
+ weapons[i].rotation1 = acos((temppoint1.z - temppoint2.z) / findDistance(&temppoint1, &temppoint2));
+ weapons[i].rotation1 *= 360 / 6.28;
+ weapons[i].rotation3 = 0;
+ weapons[i].smallrotation = -90;
+ weapons[i].smallrotation2 = 0;
+ if (temppoint1.x > temppoint2.x)
+ weapons[i].rotation1 = 360 - weapons[i].rotation1;
+ }
+ if ((animCurrent == knifeslashreversalanim && animTarget == knifeslashreversalanim) || (animCurrent == knifeslashreversedanim && animTarget == knifeslashreversedanim)) {
+ XYZ temppoint1, temppoint2;
+ float distance;
+
+ temppoint1 = jointPos(righthand);
+ temppoint2 = currentFrame().weapontarget * (1 - target) + targetFrame().weapontarget * (target);
+ distance = findDistance(&temppoint1, &temppoint2);
+ weapons[i].rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
+ weapons[i].rotation2 *= 360 / 6.28;
+ temppoint1.y = 0;
+ temppoint2.y = 0;
+ weapons[i].rotation1 = acos((temppoint1.z - temppoint2.z) / findDistance(&temppoint1, &temppoint2));
+ weapons[i].rotation1 *= 360 / 6.28;
+ weapons[i].rotation3 = 0;
+ weapons[i].smallrotation = 90;
+ weapons[i].smallrotation2 = 0;
+ if (temppoint1.x > temppoint2.x)
+ weapons[i].rotation1 = 360 - weapons[i].rotation1;
+ }
+ if (animTarget == knifethrowanim) {
+ weapons[i].smallrotation = 90;
+ //weapons[i].smallrotation2=-90;
+ weapons[i].smallrotation2 = 0;
+ weapons[i].rotation1 = 0;
+ weapons[i].rotation2 = 0;
+ weapons[i].rotation3 = 0;
+ }
+ if (animTarget == knifesneakattackanim && frameTarget < 5) {
+ weapons[i].smallrotation = -90;
+ weapons[i].rotation1 = 0;
+ weapons[i].rotation2 = 0;
+ weapons[i].rotation3 = 0;
+ }
+ }
+ if (weapons[i].getType() == sword) {
+ weapons[i].smallrotation = 0;
+ weapons[i].smallrotation2 = 0;
+ if (animTarget == knifethrowanim) {
+ weapons[i].smallrotation = -90;
+ weapons[i].smallrotation2 = 0;
+ weapons[i].rotation1 = 0;
+ weapons[i].rotation2 = 0;
+ weapons[i].rotation3 = 0;
+ }
+ if ((animTarget == swordgroundstabanim && animCurrent == swordgroundstabanim) || (animTarget == swordsneakattackanim && animCurrent == swordsneakattackanim) || (animTarget == swordslashparryanim && animCurrent == swordslashparryanim) || (animTarget == swordslashparriedanim && animCurrent == swordslashparriedanim) || (animTarget == swordslashreversalanim && animCurrent == swordslashreversalanim) || (animTarget == swordslashreversedanim && animCurrent == swordslashreversedanim) || (animTarget == knifeslashreversalanim && animCurrent == knifeslashreversalanim) || (animTarget == knifeslashreversedanim && animCurrent == knifeslashreversedanim) || (animTarget == swordslashanim && animCurrent == swordslashanim) || (animTarget == drawleftanim && animCurrent == drawleftanim) || (animCurrent == backhandspringanim && animTarget == backhandspringanim)) {
+ XYZ temppoint1, temppoint2;
+ float distance;
+
+ temppoint1 = currentFrame().joints[skeleton.jointlabels[righthand]].position * (1 - target) + targetFrame().joints[skeleton.jointlabels[righthand]].position * (target); //jointPos(righthand);
+ temppoint2 = currentFrame().weapontarget * (1 - target) + targetFrame().weapontarget * (target);
+ distance = findDistance(&temppoint1, &temppoint2);
+ weapons[i].rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
+ weapons[i].rotation2 *= 360 / 6.28;
+ temppoint1.y = 0;
+ temppoint2.y = 0;
+ weapons[i].rotation1 = acos((temppoint1.z - temppoint2.z) / findDistance(&temppoint1, &temppoint2));
+ weapons[i].rotation1 *= 360 / 6.28;
+ weapons[i].rotation3 = 0;
+ weapons[i].smallrotation = 90;
+ weapons[i].smallrotation2 = 0;
+ if (temppoint1.x > temppoint2.x)
+ weapons[i].rotation1 = 360 - weapons[i].rotation1;
+ }
+ }
+ if (weapons[i].getType() == staff) {
+ weapons[i].smallrotation = 100;
+ weapons[i].smallrotation2 = 0;
+ if ((animTarget == staffhitanim && animCurrent == staffhitanim) || (animTarget == staffhitreversedanim && animCurrent == staffhitreversedanim) || (animTarget == staffspinhitreversedanim && animCurrent == staffspinhitreversedanim) || (animTarget == staffgroundsmashanim && animCurrent == staffgroundsmashanim) || (animTarget == staffspinhitanim && animCurrent == staffspinhitanim)) {
+ XYZ temppoint1, temppoint2;
+ float distance;
+
+ temppoint1 = currentFrame().joints[skeleton.jointlabels[righthand]].position * (1 - target) + targetFrame().joints[skeleton.jointlabels[righthand]].position * (target); //jointPos(righthand);
+ temppoint2 = currentFrame().weapontarget * (1 - target) + targetFrame().weapontarget * (target);
+ distance = findDistance(&temppoint1, &temppoint2);
+ weapons[i].rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
+ weapons[i].rotation2 *= 360 / 6.28;
+ temppoint1.y = 0;
+ temppoint2.y = 0;
+ weapons[i].rotation1 = acos((temppoint1.z - temppoint2.z) / findDistance(&temppoint1, &temppoint2));
+ weapons[i].rotation1 *= 360 / 6.28;
+ weapons[i].rotation3 = 0;
+ weapons[i].smallrotation = 90;
+ weapons[i].smallrotation2 = 0;
+ if (temppoint1.x > temppoint2.x)
+ weapons[i].rotation1 = 360 - weapons[i].rotation1;
+ }
+ }
+ }
+ if (weaponactive != k && weaponstuck != k) {
+ if (weapons[i].getType() == knife) {
+ weapons[i].smallrotation = -70;
+ weapons[i].smallrotation2 = 10;
+ }
+ if (weapons[i].getType() == sword) {
+ weapons[i].smallrotation = -100;
+ weapons[i].smallrotation2 = -8;
+ }
+ if (weapons[i].getType() == staff) {
+ weapons[i].smallrotation = -100;
+ weapons[i].smallrotation2 = -8;
+ }
+ }
+ if (weaponstuck == k) {
+ if (weaponstuckwhere == 0)
+ weapons[i].smallrotation = 180;
+ else
+ weapons[i].smallrotation = 0;
+ weapons[i].smallrotation2 = 10;
+ }
+ }
+ }
+ }
+
+ calcrot = 0;
+ if (skeleton.free)
+ calcrot = 1;
+ 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;
+ if (skeleton.free == 2)
+ calcrot = 0;
+
+ return 0;
+}
+
+
+/* FUNCTION?
+ */
+int Person::SphereCheck(XYZ *p1, float radius, XYZ *p, XYZ *move, float *rotate, Model *model)
+{
+ static int i, j;
+ static float distance;
+ static float olddistance;
+ static int intersecting;
+ static int firstintersecting;
+ static XYZ point;
+ static XYZ oldp1;
+ static XYZ start, end;
+ static float slopethreshold = -.4;
+
+ firstintersecting = -1;
+
+ oldp1 = *p1;
+ *p1 = *p1 - *move;
+ if (distsq(p1, &model->boundingspherecenter) > radius * radius + model->boundingsphereradius * model->boundingsphereradius)
+ return -1;
+ if (*rotate)
+ *p1 = DoRotation(*p1, 0, -*rotate, 0);
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < model->TriangleNum; j++) {
+ if (model->facenormals[j].y <= slopethreshold) {
+ intersecting = 0;
+ distance = abs((model->facenormals[j].x * p1->x) + (model->facenormals[j].y * p1->y) + (model->facenormals[j].z * p1->z) - ((model->facenormals[j].x * model->vertex[model->Triangles[j].vertex[0]].x) + (model->facenormals[j].y * model->vertex[model->Triangles[j].vertex[0]].y) + (model->facenormals[j].z * model->vertex[model->Triangles[j].vertex[0]].z)));
+ if (distance < radius) {
+ point = *p1 - model->facenormals[j] * distance;
+ if (PointInTriangle( &point, model->facenormals[j], &model->vertex[model->Triangles[j].vertex[0]], &model->vertex[model->Triangles[j].vertex[1]], &model->vertex[model->Triangles[j].vertex[2]]))
+ intersecting = 1;
+ if (!intersecting)
+ intersecting = sphere_line_intersection(&model->vertex[model->Triangles[j].vertex[0]],
+ &model->vertex[model->Triangles[j].vertex[1]],
+ p1, &radius);
+ if (!intersecting)
+ intersecting = sphere_line_intersection(&model->vertex[model->Triangles[j].vertex[1]],
+ &model->vertex[model->Triangles[j].vertex[2]],
+ p1, &radius);
+ if (!intersecting)
+ intersecting = sphere_line_intersection(&model->vertex[model->Triangles[j].vertex[0]],
+ &model->vertex[model->Triangles[j].vertex[2]],
+ p1, &radius);
+ end = *p1 - point;
+ if (dotproduct(&model->facenormals[j], &end) > 0 && intersecting) {
+ start = *p1;
+ end = *p1;
+ end.y -= radius;
+ 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 || targetFrame().label == 7 || targetFrame().label == 4))
+ RagDoll(0);
+
+ if (animTarget == jumpupanim) {
+ jumppower = -4;
+ animTarget = getIdle();
+ }
+ target = 0;
+ frameTarget = 0;
+ onterrain = 1;
+
+ if (id == 0) {
+ pause_sound(whooshsound);
+ OPENAL_SetVolume(channels[whooshsound], 0);
+ }
+
+ if ((animTarget == jumpdownanim || isFlip()) && !wasLanding() && !wasLandhard()) {
+ if (isFlip())
+ jumppower = -4;
+ animTarget = getLanding();
+ emit_sound_at(landsound, coords, 128.);
+
+ if (id == 0) {
+ addEnvSound(coords);
+ }
+ }
+ }
+ }
+ }
+ }
+ if ((distance < olddistance || firstintersecting == -1) && intersecting) {
+ olddistance = distance;
+ firstintersecting = j;
+ *p = point;
+ }
+ }
+ }
+ for (j = 0; j < model->TriangleNum; j++) {
+ if (model->facenormals[j].y > slopethreshold) {
+ intersecting = 0;
+ start = *p1;
+ start.y -= radius / 4;
+ XYZ &v0 = model->vertex[model->Triangles[j].vertex[0]];
+ XYZ &v1 = model->vertex[model->Triangles[j].vertex[1]];
+ XYZ &v2 = model->vertex[model->Triangles[j].vertex[2]];
+ distance = abs((model->facenormals[j].x * start.x)
+ + (model->facenormals[j].y * start.y)
+ + (model->facenormals[j].z * start.z)
+ - ((model->facenormals[j].x * v0.x)
+ + (model->facenormals[j].y * v0.y)
+ + (model->facenormals[j].z * v0.z)));
+ if (distance < radius * .5) {
+ point = start - model->facenormals[j] * distance;
+ if (PointInTriangle( &point, model->facenormals[j], &v0, &v1, &v2))
+ intersecting = 1;
+ if (!intersecting)
+ intersecting = sphere_line_intersection(v0.x, v0.y, v0.z, v1.x, v1.y, v1.z, p1->x, p1->y, p1->z, radius / 2);
+ if (!intersecting)
+ intersecting = sphere_line_intersection(v1.x, v1.y, v1.z, v2.x, v2.y, v2.z, p1->x, p1->y, p1->z, radius / 2);
+ if (!intersecting)
+ intersecting = sphere_line_intersection(v0.x, v0.y, v0.z, v2.x, v2.y, v2.z, p1->x, p1->y, p1->z, radius / 2);
+ end = *p1 - point;
+ if (dotproduct(&model->facenormals[j], &end) > 0 && intersecting) {
+ if ((animTarget == jumpdownanim || animTarget == jumpupanim || isFlip())) {
+ start = velocity;
+ velocity -= DoRotation(model->facenormals[j], 0, *rotate, 0) * findLength(&velocity) * abs(normaldotproduct(velocity, DoRotation(model->facenormals[j], 0, *rotate, 0))); //(distance-radius*.5)/multiplier;
+ if (findLengthfast(&start) < findLengthfast(&velocity))
+ velocity = start;
+ }
+ *p1 += model->facenormals[j] * (distance - radius * .5);
+ }
+ }
+ if ((distance < olddistance || firstintersecting == -1) && intersecting) {
+ olddistance = distance;
+ firstintersecting = j;
+ *p = point;
+ }
+ }
+ }
+ }
+ if (*rotate)
+ *p = DoRotation(*p, 0, *rotate, 0);
+ *p = *p + *move;
+ if (*rotate)
+ *p1 = DoRotation(*p1, 0, *rotate, 0);
+ *p1 += *move;
+ return firstintersecting;
+}
+
+void Person::takeWeapon(int weaponId)
+{
+ weaponactive = 0;
+ weapons[weaponId].owner = id;
+ if (num_weapons > 0) {
+ weaponids[num_weapons] = weaponids[0];
+ }
+ num_weapons++;
+ weaponids[0] = weaponId;
+}
+
+void Person::addClothes()
+{
+ if (numclothes > 0) {
+ for (int i = 0; i < numclothes; i++) {
+ addClothes(i);
+ }
+ DoMipmaps();
+ }
+}
+
+bool Person::addClothes(const int& clothesId)
+{
+ LOGFUNC;
+ const std::string fileName = clothes[clothesId];
+
+ GLubyte* array = &skeleton.skinText[0];
+
+ //Load Image
+ ImageRec texture;
+ bool opened = load_image(Folders::getResourcePath(fileName).c_str(), texture);
+
+ float alphanum;
+ //Is it valid?
+ if (opened) {
+ float tintr = clothestintr[clothesId];
+ float tintg = clothestintg[clothesId];
+ float tintb = clothestintb[clothesId];
+
+ if (tintr > 1) tintr = 1;
+ if (tintg > 1) tintg = 1;
+ if (tintb > 1) tintb = 1;
+
+ if (tintr < 0) tintr = 0;
+ if (tintg < 0) tintg = 0;
+ if (tintb < 0) tintb = 0;
+
+ int bytesPerPixel = texture.bpp / 8;
+
+ int tempnum = 0;
+ alphanum = 255;
+ for (int i = 0; i < (int)(texture.sizeY * texture.sizeX * bytesPerPixel); i++) {
+ if (bytesPerPixel == 3)
+ alphanum = 255;
+ else if ((i + 1) % 4 == 0)
+ alphanum = texture.data[i];
+ if ((i + 1) % 4 || bytesPerPixel == 3) {
+ if ((i % 4) == 0)
+ texture.data[i] *= tintr;
+ if ((i % 4) == 1)
+ texture.data[i] *= tintg;
+ if ((i % 4) == 2)
+ texture.data[i] *= tintb;
+ array[tempnum] = (float)array[tempnum] * (1 - alphanum / 255) + (float)texture.data[i] * (alphanum / 255);
+ tempnum++;
+ }
+ }
+ return 1;
+ } else {
+ return 0;
+ }
+}
--- /dev/null
+/*
+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 _PERSON_H_
+#define _PERSON_H_
+
+/**> HEADER FILES <**/
+#include "Animation/Animation.h"
+#include "Animation/Skeleton.h"
+#include "Environment/Terrain.h"
+#include "Graphic/gamegl.h"
+#include "Graphic/Models.h"
+#include "Graphic/Sprite.h"
+#include "Math/Quaternions.h"
+#include "Objects/Weapons.h"
+
+#include <memory>
+#include <cmath>
+
+#define passivetype 0
+#define guardtype 1
+#define searchtype 2
+#define attacktype 3
+#define attacktypecutoff 4
+#define playercontrolled 5
+#define gethelptype 6
+#define getweapontype 7
+#define pathfindtype 8
+
+#define rabbittype 0
+#define wolftype 1
+
+struct InvalidPersonException : public exception {
+ const char * what () const throw () {
+ return "Invalid weapon number";
+ }
+};
+
+class Person : public enable_shared_from_this<Person>
+{
+public:
+ static std::vector<std::shared_ptr<Person>> players;
+
+ int whichpatchx;
+ int whichpatchz;
+
+ // animCurrent and animTarget are used to interpolate between different animations
+ // (and for a bunch of other things).
+ // animations interpolate with one another at various speeds.
+ // animTarget seems to determine the combat state?
+ int animCurrent;
+ int animTarget;
+
+ // frameCurrent and frameTarget are used to interpolate between the frames of an animation
+ // (e.g. the crouched animation has only two frames, lerped back and forth slowly).
+ // animations advance at various speeds.
+ int frameCurrent;
+ int frameTarget;
+
+ int oldanimCurrent;
+ int oldanimTarget;
+ int oldframeCurrent;
+ int oldframeTarget;
+
+ int howactive;
+
+ float parriedrecently;
+
+ bool superruntoggle;
+
+ int lastattack, lastattack2, lastattack3;
+
+ XYZ currentoffset, targetoffset, offset;
+ float target;
+ float transspeed;
+
+ XYZ realoldcoords;
+ XYZ oldcoords;
+ XYZ coords;
+ XYZ velocity;
+
+ XYZ proportionhead;
+ XYZ proportionlegs;
+ XYZ proportionarms;
+ XYZ proportionbody;
+
+ float unconscioustime;
+
+ bool immobile;
+
+ float velspeed;
+ float targetyaw;
+ float targetrot;
+ float rot;
+ float oldrot;
+ float lookyaw;
+ float lookpitch;
+ float yaw;
+ float pitch;
+ float lowyaw;
+ float tilt;
+ float targettilt;
+ float tilt2;
+ float targettilt2;
+ bool rabbitkickenabled;
+
+ float bloodloss;
+ float bleeddelay;
+ float skiddelay;
+ float skiddingdelay;
+ float deathbleeding;
+ float tempdeltav;
+
+ float damagetolerance;
+ float damage;
+ float permanentdamage;
+ float superpermanentdamage;
+ float lastcollide;
+ /* Seems to be 0 = alive, 1 = unconscious, 2 = dead */
+ int dead;
+
+ float jumppower;
+ bool onground;
+
+ int wentforweapon;
+
+ bool calcrot;
+
+ XYZ facing;
+
+ float bleeding;
+ float bleedx, bleedy;
+ int direction;
+ float texupdatedelay;
+
+ float headyaw, headpitch;
+ float targetheadyaw, targetheadpitch;
+
+ bool onterrain;
+ bool pause;
+
+ float grabdelay;
+
+ std::shared_ptr<Person> victim;
+ bool hasvictim;
+
+ float updatedelay;
+ float normalsupdatedelay;
+
+ bool jumpstart;
+
+ bool forwardkeydown;
+ bool forwardstogglekeydown;
+ bool rightkeydown;
+ bool leftkeydown;
+ bool backkeydown;
+ bool jumpkeydown;
+ bool jumptogglekeydown;
+ bool crouchkeydown;
+ bool crouchtogglekeydown;
+ bool drawkeydown;
+ bool drawtogglekeydown;
+ bool throwkeydown;
+ bool throwtogglekeydown;
+ bool attackkeydown;
+ bool feint;
+ bool lastfeint;
+ bool headless;
+
+ float crouchkeydowntime;
+ float jumpkeydowntime;
+ bool freefall;
+
+
+ float turnspeed;
+
+ int aitype;
+ float aiupdatedelay;
+ float losupdatedelay;
+ int ally;
+ float collide;
+ float collided;
+ float avoidcollided;
+ bool loaded;
+ bool whichdirection;
+ float whichdirectiondelay;
+ bool avoidsomething;
+ XYZ avoidwhere;
+ float blooddimamount;
+
+ float staggerdelay;
+ float blinkdelay;
+ float twitchdelay;
+ float twitchdelay2;
+ float twitchdelay3;
+ float lefthandmorphness;
+ float righthandmorphness;
+ float headmorphness;
+ float chestmorphness;
+ float tailmorphness;
+ float targetlefthandmorphness;
+ float targetrighthandmorphness;
+ float targetheadmorphness;
+ float targetchestmorphness;
+ float targettailmorphness;
+ int lefthandmorphstart, lefthandmorphend;
+ int righthandmorphstart, righthandmorphend;
+ int headmorphstart, headmorphend;
+ int chestmorphstart, chestmorphend;
+ int tailmorphstart, tailmorphend;
+
+ float weaponmissdelay;
+ float highreversaldelay;
+ float lowreversaldelay;
+
+ int creature;
+
+ unsigned id;
+
+ Skeleton skeleton;
+
+ float speed;
+ float scale;
+ float power;
+ float speedmult;
+
+ float protectionhead;
+ float protectionhigh;
+ float protectionlow;
+ float armorhead;
+ float armorhigh;
+ float armorlow;
+ bool metalhead;
+ bool metalhigh;
+ bool metallow;
+
+ int numclothes;
+ char clothes[10][256];
+ float clothestintr[10];
+ float clothestintg[10];
+ float clothestintb[10];
+
+ bool landhard;
+ bool bled;
+ bool spurt;
+ bool onfire;
+ float onfiredelay;
+ float burnt;
+
+ float flamedelay;
+
+ int playerdetail;
+
+ int num_weapons;
+ int weaponids[4];
+ /* Key of weaponids which is the weapon in hand, if any. -1 otherwise.
+ * Always 0 or -1 as activeweapon is moved to position 0 when taken */
+ int weaponactive;
+ int weaponstuck;
+ /* 0 or 1 to say if weapon is stuck in the front or the back */
+ int weaponstuckwhere;
+
+ int numwaypoints;
+ XYZ waypoints[90];
+ int waypointtype[90];
+ float pausetime;
+
+ XYZ headtarget;
+ float interestdelay;
+
+ XYZ finalfinaltarget;
+ XYZ finaltarget;
+ int finalpathfindpoint;
+ int targetpathfindpoint;
+ int lastpathfindpoint;
+ int lastpathfindpoint2;
+ int lastpathfindpoint3;
+ int lastpathfindpoint4;
+
+ int waypoint;
+
+ XYZ lastseen;
+ float lastseentime;
+ float lastchecktime;
+ float stunned;
+ float surprised;
+ float runninghowlong;
+ int occluded;
+ int lastoccluded;
+ int laststanding;
+ int escapednum;
+
+ float speechdelay;
+ float neckspurtdelay;
+ float neckspurtparticledelay;
+ float neckspurtamount;
+
+ int whichskin;
+ bool rabbitkickragdoll;
+
+ Animation tempanimation;
+
+ bool jumpclimb;
+
+ Person();
+ Person(FILE*, int, unsigned);
+
+ void skeletonLoad(bool clothes = false);
+
+ // convenience functions
+ inline Joint& joint(int bodypart) { return skeleton.joints[skeleton.jointlabels[bodypart]]; }
+ inline XYZ& jointPos(int bodypart) { return joint(bodypart).position; }
+ inline XYZ& jointVel(int bodypart) { return joint(bodypart).velocity; }
+ inline AnimationFrame& currentFrame() { return Animation::animations.at(animCurrent).frames.at(frameCurrent); }
+ inline AnimationFrame& targetFrame() { return Animation::animations.at(animTarget).frames.at(frameTarget); }
+
+
+ void CheckKick();
+ void CatchFire();
+ void DoBlood(float howmuch, int which);
+ void DoBloodBig(float howmuch, int which);
+ bool DoBloodBigWhere(float howmuch, int which, XYZ where);
+
+ bool wasIdle() { return animation_bits[animCurrent] & ab_idle; }
+ bool isIdle() { return animation_bits[animTarget] & ab_idle; }
+ int getIdle();
+
+ bool isSitting() { return animation_bits[animTarget] & ab_sit; }
+
+ bool isSleeping() { return animation_bits[animTarget] & ab_sleep; }
+
+ bool wasCrouch() { return animation_bits[animCurrent] & ab_crouch; }
+ bool isCrouch() { return animation_bits[animTarget] & ab_crouch; }
+ int getCrouch();
+
+ bool wasStop() { return animation_bits[animCurrent] & ab_stop; }
+ bool isStop() { return animation_bits[animTarget] & ab_stop; }
+ int getStop();
+
+ bool wasSneak();
+ bool isSneak();
+ int getSneak();
+
+ bool wasRun() { return animation_bits[animCurrent] & ab_run; }
+ bool isRun() { return animation_bits[animTarget] & ab_run; }
+ int getRun();
+
+ bool wasLanding() { return animation_bits[animCurrent] & ab_land; }
+ bool isLanding() { return animation_bits[animTarget] & ab_land; }
+ int getLanding();
+
+ bool wasLandhard() { return animation_bits[animCurrent] & ab_landhard; }
+ bool isLandhard() { return animation_bits[animTarget] & ab_landhard; }
+ int getLandhard();
+
+ bool wasFlip() { return animation_bits[animCurrent] & ab_flip; }
+ bool isFlip() { return animation_bits[animTarget] & ab_flip; }
+
+ bool isWallJump() { return animation_bits[animTarget] & ab_walljump; }
+ void Reverse();
+ void DoDamage(float howmuch);
+ void DoHead();
+ void DoMipmaps() {
+ skeleton.drawmodel.textureptr.bind();
+ glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, skeleton.skinsize, skeleton.skinsize, 0, GL_RGB, GL_UNSIGNED_BYTE, &skeleton.skinText[0]);
+ }
+
+ int SphereCheck(XYZ *p1, float radius, XYZ *p, XYZ *move, float *rotate, Model *model);
+ int DrawSkeleton();
+ void Puff(int whichlabel);
+ void FootLand(bodypart whichfoot, float opacity);
+ void DoStuff();
+ void setAnimation(int);
+ void DoAnimations();
+ void RagDoll(bool checkcollision);
+
+ void takeWeapon (int weaponId);
+
+ bool addClothes(const int& clothesId);
+ void addClothes();
+};
+
+const int maxplayers = 10;
+
+#endif
--- /dev/null
+/*
+Copyright (C) 2003, 2010 - Wolfire Games
+Copyright (C) 2010-2016 - Lugaru contributors (see AUTHORS file)
+
+This file is part of Lugaru.
+
+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 "Animation/Animation.h"
+#include "Audio/openal_wrapper.h"
+#include "Audio/Sounds.h"
+#include "Level/Awards.h"
+#include "Objects/Weapons.h"
+
+#include "Game.h"
+
+extern float multiplier;
+extern Terrain terrain;
+extern float gravity;
+extern int environment;
+extern int detail;
+extern FRUSTUM frustum;
+extern XYZ viewer;
+extern float realmultiplier;
+extern int slomo;
+extern float slomodelay;
+extern bool cellophane;
+extern float texdetail;
+extern GLubyte bloodText[512 * 512 * 3];
+extern int bloodtoggle;
+extern Objects objects;
+extern bool autoslomo;
+extern float camerashake;
+extern float woozy;
+extern float viewdistance;
+extern float blackout;
+extern bool freeze;
+extern int tutoriallevel;
+extern int numthrowkill;
+
+Model Weapon::throwingknifemodel;
+Texture Weapon::knifetextureptr;
+Texture Weapon::lightbloodknifetextureptr;
+Texture Weapon::bloodknifetextureptr;
+
+Model Weapon::swordmodel;
+Texture Weapon::swordtextureptr;
+Texture Weapon::lightbloodswordtextureptr;
+Texture Weapon::bloodswordtextureptr;
+
+Model Weapon::staffmodel;
+Texture Weapon::stafftextureptr;
+
+Weapon::Weapon(int t, int o) : owner(o)
+{
+ setType(t);
+ bloody = 0;
+ blooddrip = 0;
+ blooddripdelay = 0;
+ onfire = 0;
+ flamedelay = 0;
+ damage = 0;
+ position = -1000;
+ tippoint = -1000;
+}
+
+void Weapon::setType(int t)
+{
+ type = t;
+ if (type == sword) {
+ mass = 1.5;
+ tipmass = 1;
+ length = .8;
+ }
+ if (type == staff) {
+ mass = 2;
+ tipmass = 1;
+ length = 1.5;
+ }
+ if (type == knife) {
+ mass = 1;
+ tipmass = 1.2;
+ length = .25;
+ }
+}
+
+void Weapon::DoStuff(int i)
+{
+ //~ cout << position.x << "," << position.y << "," << position.z << "|" << tippoint.x << "," << tippoint.y << "," << tippoint.z << endl;
+ static int whichpatchx, whichpatchz, whichhit;
+ static XYZ start, end, colpoint, normalrot, footvel, footpoint;
+ static XYZ terrainnormal;
+ static XYZ vel;
+ static XYZ midp;
+ static XYZ newpoint1, newpoint2;
+ static float friction = 3.5;
+ static float elasticity = .4;
+ static XYZ bounceness;
+ static float frictionness;
+ static float closestdistance;
+ static float distance;
+ static XYZ point[3];
+ static XYZ closestpoint;
+ static XYZ closestswordpoint;
+ static float tempmult;
+
+ if (owner != -1) {
+ oldowner = owner;
+ }
+ if (damage >= 2 && type == staff && owner != -1) { // the staff breaks
+ emit_sound_at(staffbreaksound, tippoint);
+ XYZ tempvel;
+ for (int j = 0; j < 40; j++) {
+ tempvel.x = float(abs(Random() % 100) - 50) / 20;
+ tempvel.y = float(abs(Random() % 100) - 50) / 20;
+ tempvel.z = float(abs(Random() % 100) - 50) / 20;
+ Sprite::MakeSprite(splintersprite, position + (tippoint - position) * ((float)j - 8) / 32, tempvel * .5, 115 / 255, 73 / 255, 12 / 255, .1, 1);
+ }
+ if (owner != -1) {
+ Person::players[owner]->weaponactive = -1;
+ Person::players[owner]->num_weapons--;
+ if (Person::players[owner]->num_weapons) {
+ Person::players[owner]->weaponids[0] = Person::players[owner]->weaponids[Person::players[owner]->num_weapons];
+ if (Person::players[owner]->weaponstuck == Person::players[owner]->num_weapons)
+ Person::players[owner]->weaponstuck = 0;
+ }
+ }
+ owner = -1;
+ hitsomething = 0;
+ missed = 1;
+ freetime = 0;
+ firstfree = 1;
+ position = 0;
+ physics = 0;
+ }
+ oldposition = position;
+ oldtippoint = tippoint;
+ if (owner == -1 && (velocity.x || velocity.y || velocity.z) && !physics) { // if the weapon is flying
+ position += velocity * multiplier;
+ tippoint += velocity * multiplier;
+ whichpatchx = position.x / (terrain.size / subdivision * terrain.scale);
+ whichpatchz = position.z / (terrain.size / subdivision * terrain.scale);
+ if (whichpatchx > 0 && whichpatchz > 0 && whichpatchx < subdivision && whichpatchz < subdivision) {
+ if (terrain.patchobjectnum[whichpatchx][whichpatchz]) { // if there are objects where the weapon is
+ for (int j = 0; j < terrain.patchobjectnum[whichpatchx][whichpatchz]; j++) { // check for collision
+ int k = terrain.patchobjects[whichpatchx][whichpatchz][j];
+ start = oldtippoint;
+ end = tippoint;
+ whichhit = objects.model[k].LineCheck(&start, &end, &colpoint, &objects.position[k], &objects.yaw[k]);
+ if (whichhit != -1) {
+ if (objects.type[k] == treetrunktype) {
+ objects.model[k].MakeDecal(breakdecal, DoRotation(colpoint - objects.position[k], 0, -objects.yaw[k], 0), .1, 1, Random() % 360);
+ normalrot = DoRotation(objects.model[k].facenormals[whichhit], 0, objects.yaw[k], 0);
+ velocity = 0;
+ if (type == knife)
+ position = colpoint - normalrot * .1;
+ else if (type == sword)
+ position = colpoint - normalrot * .2;
+ else if (type == staff)
+ position = colpoint - normalrot * .2;
+ XYZ temppoint1, temppoint2;
+ float distance;
+
+ temppoint1 = 0;
+ temppoint2 = normalrot;
+ distance = findDistance(&temppoint1, &temppoint2);
+ rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
+ rotation2 *= 360 / 6.28;
+ temppoint1.y = 0;
+ temppoint2.y = 0;
+ rotation1 = acos((temppoint1.z - temppoint2.z) / findDistance(&temppoint1, &temppoint2));
+ rotation1 *= 360 / 6.28;
+ if (temppoint1.x > temppoint2.x)
+ rotation1 = 360 - rotation1;
+
+ rotation3 = 0;
+ smallrotation = 90;
+ smallrotation2 = 0;
+ bigtilt = 0;
+ bigtilt2 = 0;
+ bigrotation = 0;
+
+ emit_sound_at(knifesheathesound, position, 128.);
+
+ bloody = 0;
+
+ Sprite::MakeSprite(cloudimpactsprite, position, velocity, 1, 1, 1, .8, .3);
+ } else {
+ physics = 1;
+ firstfree = 1;
+ position -= velocity * multiplier;
+ tippoint -= velocity * multiplier;
+ tipvelocity = velocity;
+ }
+ }
+ }
+ }
+ }
+
+ if (velocity.x || velocity.y || velocity.z) {
+ for (unsigned j = 0; j < Person::players.size(); j++) {
+ footvel = 0;
+ footpoint = DoRotation((Person::players[j]->jointPos(abdomen) + Person::players[j]->jointPos(neck)) / 2, 0, Person::players[j]->yaw, 0) * Person::players[j]->scale + Person::players[j]->coords;
+ if (owner == -1 && distsqflat(&position, &Person::players[j]->coords) < 1.5 &&
+ distsq(&position, &Person::players[j]->coords) < 4 && Person::players[j]->weaponstuck == -1 &&
+ !Person::players[j]->skeleton.free && (int(j) != oldowner)) {
+ if ((Person::players[j]->aitype != attacktypecutoff || abs(Random() % 6) == 0 || (Person::players[j]->animTarget != backhandspringanim && Person::players[j]->animTarget != rollanim && Person::players[j]->animTarget != flipanim && Random() % 2 == 0)) && !missed) {
+ if ( (Person::players[j]->creature == wolftype && Random() % 3 != 0 && Person::players[j]->weaponactive == -1 && (Person::players[j]->isIdle() || Person::players[j]->isRun() || Person::players[j]->animTarget == walkanim)) ||
+ (Person::players[j]->creature == rabbittype && Random() % 2 == 0 && Person::players[j]->aitype == attacktypecutoff && Person::players[j]->weaponactive == -1)) {
+ emit_sound_at(knifedrawsound, Person::players[j]->coords, 128.);
+
+ Person::players[j]->animTarget = removeknifeanim;
+ Person::players[j]->frameTarget = 1;
+ Person::players[j]->target = 1;
+ Person::players[j]->takeWeapon(i);
+
+ Person::players[j]->aitype = attacktypecutoff;
+ } else {
+ if (j != 0)
+ numthrowkill++;
+ Person::players[j]->num_weapons++;
+ Person::players[j]->weaponstuck = Person::players[j]->num_weapons - 1;
+ if (normaldotproduct(Person::players[j]->facing, velocity) > 0)
+ Person::players[j]->weaponstuckwhere = 1;
+ else
+ Person::players[j]->weaponstuckwhere = 0;
+
+ Person::players[j]->weaponids[Person::players[j]->num_weapons - 1] = i;
+
+ Person::players[j]->RagDoll(0);
+ Person::players[j]->jointVel(abdomen) += velocity * 2;
+ Person::players[j]->jointVel(neck) += velocity * 2;
+ Person::players[j]->jointVel(rightshoulder) += velocity * 2;
+ Person::players[j]->jointVel(leftshoulder) += velocity * 2;
+ if (bloodtoggle && tutoriallevel != 1)
+ Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .8, .3);
+ if (tutoriallevel == 1)
+ Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 1, 1, .8, .3);
+ footvel = tippoint - position;
+ Normalise(&footvel);
+ if (bloodtoggle && tutoriallevel != 1)
+ Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * -1, 1, 0, 0, .6, 1);
+
+ if (tutoriallevel != 1) {
+ if (Person::players[j]->weaponstuckwhere == 0)
+ Person::players[j]->DoBloodBig(2, 205);
+ if (Person::players[j]->weaponstuckwhere == 1)
+ Person::players[j]->DoBloodBig(2, 200);
+ Person::players[j]->damage += 200 / Person::players[j]->armorhigh;
+ Person::players[j]->deathbleeding = 1;
+ Person::players[j]->bloodloss += (200 + abs((float)(Random() % 40)) - 20) / Person::players[j]->armorhigh;
+ owner = j;
+ bloody = 2;
+ blooddrip = 5;
+ }
+
+ emit_sound_at(fleshstabsound, position, 128.);
+
+ if (Animation::animations[Person::players[0]->animTarget].height == highheight)
+ award_bonus(0, ninja);
+ else
+ award_bonus(0, Bullseyebonus);
+ }
+ } else {
+ missed = 1;
+ }
+ }
+ }
+ }
+ if (position.y < terrain.getHeight(position.x, position.z)) {
+ if (terrain.getOpacity(position.x, position.z) < .2) {
+ velocity = 0;
+ if (terrain.lineTerrain(oldposition, position, &colpoint) != -1) {
+ position = colpoint * terrain.scale;
+ } else {
+ position.y = terrain.getHeight(position.x, position.z);
+ }
+
+ terrain.MakeDecal(shadowdecalpermanent, position, .06, .5, 0);
+ normalrot = terrain.getNormal(position.x, position.z) * -1;
+ velocity = 0;
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ GLfloat M[16];
+ glLoadIdentity();
+ glRotatef(bigrotation, 0, 1, 0);
+ glRotatef(bigtilt2, 1, 0, 0);
+ glRotatef(bigtilt, 0, 0, 1);
+ glRotatef(-rotation1 + 90, 0, 1, 0);
+ glRotatef(-rotation2 + 90, 0, 0, 1);
+ glRotatef(-rotation3, 0, 1, 0);
+ glRotatef(smallrotation, 1, 0, 0);
+ glRotatef(smallrotation2, 0, 1, 0);
+ glTranslatef(0, 0, 1);
+ glGetFloatv(GL_MODELVIEW_MATRIX, M);
+ tippoint.x = M[12];
+ tippoint.y = M[13];
+ tippoint.z = M[14];
+ glPopMatrix();
+ position -= tippoint * .15;
+ XYZ temppoint1, temppoint2;
+
+ rotation3 = 0;
+ smallrotation = 90;
+ smallrotation2 = 0;
+ bigtilt = 0;
+ bigtilt2 = 0;
+ bigrotation = 0;
+
+ emit_sound_at(knifesheathesound, position, 128.);
+
+ XYZ terrainlight;
+ terrainlight = terrain.getLighting(position.x, position.z);
+ if (environment == snowyenvironment) {
+ if (distsq(&position, &viewer) < viewdistance * viewdistance / 4)
+ Sprite::MakeSprite(cloudsprite, position, velocity, terrainlight.x, terrainlight.y, terrainlight.z, .5, .7);
+ } else if (environment == grassyenvironment) {
+ if (distsq(&position, &viewer) < viewdistance * viewdistance / 4)
+ Sprite::MakeSprite(cloudsprite, position, velocity, terrainlight.x * 90 / 255, terrainlight.y * 70 / 255, terrainlight.z * 8 / 255, .5, .5);
+ } else if (environment == desertenvironment) {
+ if (distsq(&position, &viewer) < viewdistance * viewdistance / 4)
+ Sprite::MakeSprite(cloudsprite, position, velocity, terrainlight.x * 190 / 255, terrainlight.y * 170 / 255, terrainlight.z * 108 / 255, .5, .7);
+ }
+
+ bloody = 0;
+ } else {
+ physics = 1;
+ firstfree = 1;
+ position -= velocity * multiplier;
+ tippoint -= velocity * multiplier;
+ tipvelocity = velocity;
+ }
+ }
+ if (velocity.x != 0 || velocity.z != 0 || velocity.y != 0) {
+ velocity.y += gravity * multiplier;
+
+ XYZ temppoint1, temppoint2;
+ float distance;
+
+ temppoint1 = 0;
+ temppoint2 = velocity;
+ distance = findDistance(&temppoint1, &temppoint2);
+ rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
+ rotation2 *= 360 / 6.28;
+ temppoint1.y = 0;
+ temppoint2.y = 0;
+ rotation1 = acos((temppoint1.z - temppoint2.z) / findDistance(&temppoint1, &temppoint2));
+ rotation1 *= 360 / 6.28;
+ rotation3 = 0;
+ smallrotation = 90;
+ smallrotation2 = 0;
+ bigtilt = 0;
+ bigtilt2 = 0;
+ bigrotation = 0;
+ if (temppoint1.x > temppoint2.x)
+ rotation1 = 360 - rotation1;
+ }
+
+ }
+
+ //Sword physics
+ XYZ mid;
+ XYZ oldmid;
+ XYZ oldmid2;
+
+ tempmult = multiplier;
+ multiplier /= 10;
+ for (int l = 0; l < 10; l++) {
+ if (owner == -1 && (velocity.x || velocity.y || velocity.z) && physics) {
+ //move
+ position += velocity * multiplier;
+ tippoint += tipvelocity * multiplier;
+
+ //Length constrain
+ midp = (position * mass + tippoint * tipmass) / (mass + tipmass);
+ vel = tippoint - midp;
+ Normalise(&vel);
+ newpoint1 = midp - vel * length * (tipmass / (mass + tipmass));
+ newpoint2 = midp + vel * length * (mass / (mass + tipmass));
+ if (!freeze) {
+ if (freetime > .04) {
+ velocity = velocity + (newpoint1 - position) / multiplier;
+ tipvelocity = tipvelocity + (newpoint2 - tippoint) / multiplier;
+ }
+ }
+ position = newpoint1;
+ tippoint = newpoint2;
+
+
+ //Object collisions
+ whichpatchx = (position.x) / (terrain.size / subdivision * terrain.scale);
+ whichpatchz = (position.z) / (terrain.size / subdivision * terrain.scale);
+ if (whichpatchx > 0 && whichpatchz > 0 && whichpatchx < subdivision && whichpatchz < subdivision)
+ if (terrain.patchobjectnum[whichpatchx][whichpatchz]) {
+ for (int j = 0; j < terrain.patchobjectnum[whichpatchx][whichpatchz]; j++) {
+ int k = terrain.patchobjects[whichpatchx][whichpatchz][j];
+
+ if (firstfree) {
+ if (type == staff) {
+ start = tippoint - (position - tippoint) / 5;
+ end = position + (position - tippoint) / 30;
+ whichhit = objects.model[k].LineCheck(&start, &end, &colpoint, &objects.position[k], &objects.yaw[k]);
+ if (whichhit != -1) {
+ XYZ diff;
+ diff = (colpoint - position);
+ Normalise(&diff);
+ hitsomething = 1;
+
+ tippoint += (colpoint - position) + diff * .05;
+ position = colpoint + diff * .05;
+ oldtippoint = tippoint;
+ oldposition = tippoint;
+ }
+ } else {
+ start = position - (tippoint - position) / 5;
+ end = tippoint + (tippoint - position) / 30;
+ whichhit = objects.model[k].LineCheck(&start, &end, &colpoint, &objects.position[k], &objects.yaw[k]);
+ if (whichhit != -1) {
+ XYZ diff;
+ diff = (colpoint - tippoint);
+ Normalise(&diff);
+ hitsomething = 1;
+
+ position += (colpoint - tippoint) + diff * .05;
+ tippoint = colpoint + diff * .05;
+ oldposition = position;
+ oldtippoint = tippoint;
+ }
+ }
+ }
+
+ start = oldposition;
+ end = position;
+ whichhit = objects.model[k].LineCheck(&start, &end, &colpoint, &objects.position[k], &objects.yaw[k]);
+ if (whichhit != -1) {
+ hitsomething = 1;
+ position = colpoint;
+ terrainnormal = DoRotation(objects.model[k].facenormals[whichhit], 0, objects.yaw[k], 0) * -1;
+ ReflectVector(&velocity, &terrainnormal);
+ position += terrainnormal * .002;
+
+ bounceness = terrainnormal * findLength(&velocity) * (abs(normaldotproduct(velocity, terrainnormal)));
+ if (findLengthfast(&velocity) < findLengthfast(&bounceness))
+ bounceness = 0;
+ frictionness = abs(normaldotproduct(velocity, terrainnormal));
+ velocity -= bounceness;
+ if (1 - friction * frictionness > 0)
+ velocity *= 1 - friction * frictionness;
+ else
+ velocity = 0;
+ velocity += bounceness * elasticity;
+
+ if (findLengthfast(&bounceness) > 1) {
+ int whichsound;
+ if (type == staff)
+ whichsound = footstepsound3 + abs(Random() % 2);
+ else
+ whichsound = clank1sound + abs(Random() % 4);
+ emit_sound_at(whichsound, position, 128 * findLengthfast(&bounceness));
+ }
+ }
+ start = oldtippoint;
+ end = tippoint;
+ whichhit = objects.model[k].LineCheck(&start, &end, &colpoint, &objects.position[k], &objects.yaw[k]);
+ if (whichhit != -1) {
+ hitsomething = 1;
+ tippoint = colpoint;
+ terrainnormal = DoRotation(objects.model[k].facenormals[whichhit], 0, objects.yaw[k], 0) * -1;
+ ReflectVector(&tipvelocity, &terrainnormal);
+ tippoint += terrainnormal * .002;
+
+ bounceness = terrainnormal * findLength(&tipvelocity) * (abs(normaldotproduct(tipvelocity, terrainnormal)));
+ if (findLengthfast(&tipvelocity) < findLengthfast(&bounceness))
+ bounceness = 0;
+ frictionness = abs(normaldotproduct(tipvelocity, terrainnormal));
+ tipvelocity -= bounceness;
+ if (1 - friction * frictionness > 0)
+ tipvelocity *= 1 - friction * frictionness;
+ else
+ tipvelocity = 0;
+ tipvelocity += bounceness * elasticity;
+
+ if (findLengthfast(&bounceness) > 1) {
+ int whichsound;
+ if (type == staff)
+ whichsound = footstepsound3 + abs(Random() % 2);
+ else
+ whichsound = clank1sound + abs(Random() % 4);
+ emit_sound_at(whichsound, position, 128 * findLengthfast(&bounceness));
+ }
+ }
+
+ if ((objects.type[k] != boxtype && objects.type[k] != platformtype && objects.type[k] != walltype && objects.type[k] != weirdtype) || objects.pitch[k] != 0)
+ for (int m = 0; m < 2; m++) {
+ mid = (position * (21 + (float)m * 10) + tippoint * (19 - (float)m * 10)) / 40;
+ oldmid2 = mid;
+ oldmid = (oldposition * (21 + (float)m * 10) + oldtippoint * (19 - (float)m * 10)) / 40;
+
+ start = oldmid;
+ end = mid;
+ whichhit = objects.model[k].LineCheck(&start, &end, &colpoint, &objects.position[k], &objects.yaw[k]);
+ if (whichhit != -1) {
+ hitsomething = 1;
+ mid = colpoint;
+ terrainnormal = DoRotation(objects.model[k].facenormals[whichhit], 0, objects.yaw[k], 0) * -1;
+ ReflectVector(&velocity, &terrainnormal);
+
+ bounceness = terrainnormal * findLength(&velocity) * (abs(normaldotproduct(velocity, terrainnormal)));
+ if (findLengthfast(&velocity) < findLengthfast(&bounceness))
+ bounceness = 0;
+ frictionness = abs(normaldotproduct(velocity, terrainnormal));
+ velocity -= bounceness;
+ if (1 - friction * frictionness > 0)
+ velocity *= 1 - friction * frictionness;
+ else
+ velocity = 0;
+ velocity += bounceness * elasticity;
+
+ if (findLengthfast(&bounceness) > 1) {
+ int whichsound;
+ if (type == staff)
+ whichsound = footstepsound3 + abs(Random() % 2);
+ else
+ whichsound = clank1sound + abs(Random() % 4);
+ emit_sound_at(whichsound, mid, 128 * findLengthfast(&bounceness));
+ }
+ position += (mid - oldmid2) * (20 / (1 + (float)m * 10));
+ }
+
+ mid = (position * (19 - (float)m * 10) + tippoint * (21 + (float)m * 10)) / 40;
+ oldmid2 = mid;
+ oldmid = (oldposition * (19 - (float)m * 10) + oldtippoint * (21 + (float)m * 10)) / 40;
+
+ start = oldmid;
+ end = mid;
+ whichhit = objects.model[k].LineCheck(&start, &end, &colpoint, &objects.position[k], &objects.yaw[k]);
+ if (whichhit != -1) {
+ hitsomething = 1;
+ mid = colpoint;
+ terrainnormal = DoRotation(objects.model[k].facenormals[whichhit], 0, objects.yaw[k], 0) * -1;
+ ReflectVector(&tipvelocity, &terrainnormal);
+
+ bounceness = terrainnormal * findLength(&tipvelocity) * (abs(normaldotproduct(tipvelocity, terrainnormal)));
+ if (findLengthfast(&tipvelocity) < findLengthfast(&bounceness))
+ bounceness = 0;
+ frictionness = abs(normaldotproduct(tipvelocity, terrainnormal));
+ tipvelocity -= bounceness;
+ if (1 - friction * frictionness > 0)
+ tipvelocity *= 1 - friction * frictionness;
+ else
+ tipvelocity = 0;
+ tipvelocity += bounceness * elasticity;
+
+ if (findLengthfast(&bounceness) > 1) {
+ int whichsound;
+ if (type == staff)
+ whichsound = footstepsound3 + abs(Random() % 2);
+ else
+ whichsound = clank1sound + abs(Random() % 4);
+ emit_sound_at(whichsound, mid, 128 * findLengthfast(&bounceness));
+ }
+ tippoint += (mid - oldmid2) * (20 / (1 + (float)m * 10));
+ }
+ }
+ else {
+ start = position;
+ end = tippoint;
+ whichhit = objects.model[k].LineCheck(&start, &end, &colpoint, &objects.position[k], &objects.yaw[k]);
+ if (whichhit != -1) {
+ hitsomething = 1;
+ closestdistance = -1;
+ closestswordpoint = colpoint; //(position+tippoint)/2;
+ point[0] = DoRotation(objects.model[k].vertex[objects.model[k].Triangles[whichhit].vertex[0]], 0, objects.yaw[k], 0) + objects.position[k];
+ point[1] = DoRotation(objects.model[k].vertex[objects.model[k].Triangles[whichhit].vertex[1]], 0, objects.yaw[k], 0) + objects.position[k];
+ point[2] = DoRotation(objects.model[k].vertex[objects.model[k].Triangles[whichhit].vertex[2]], 0, objects.yaw[k], 0) + objects.position[k];
+ if (DistancePointLine(&closestswordpoint, &point[0], &point[1], &distance, &colpoint )) {
+ if (distance < closestdistance || closestdistance == -1) {
+ closestpoint = colpoint;
+ closestdistance = distance;
+ }
+ }
+ if (DistancePointLine(&closestswordpoint, &point[1], &point[2], &distance, &colpoint )) {
+ if (distance < closestdistance || closestdistance == -1) {
+ closestpoint = colpoint;
+ closestdistance = distance;
+ }
+ }
+ if (DistancePointLine(&closestswordpoint, &point[2], &point[0], &distance, &colpoint )) {
+ if (distance < closestdistance || closestdistance == -1) {
+ closestpoint = colpoint;
+ closestdistance = distance;
+ }
+ }
+ if (closestdistance != -1 && isnormal(closestdistance)) {
+ if (DistancePointLine(&closestpoint, &position, &tippoint, &distance, &colpoint )) {
+ closestswordpoint = colpoint;
+ velocity += (closestpoint - closestswordpoint);
+ tipvelocity += (closestpoint - closestswordpoint);
+ position += (closestpoint - closestswordpoint);
+ tippoint += (closestpoint - closestswordpoint);
+ }
+ }
+ }
+ }
+ }
+ }
+ //Terrain collisions
+ whichhit = terrain.lineTerrain(oldposition, position, &colpoint);
+ if (whichhit != -1 || position.y < terrain.getHeight(position.x, position.z)) {
+ hitsomething = 1;
+ if (whichhit != -1)
+ position = colpoint * terrain.scale;
+ else
+ position.y = terrain.getHeight(position.x, position.z);
+
+ terrainnormal = terrain.getNormal(position.x, position.z);
+ ReflectVector(&velocity, &terrainnormal);
+ position += terrainnormal * .002;
+ bounceness = terrainnormal * findLength(&velocity) * (abs(normaldotproduct(velocity, terrainnormal)));
+ if (findLengthfast(&velocity) < findLengthfast(&bounceness))
+ bounceness = 0;
+ frictionness = abs(normaldotproduct(velocity, terrainnormal));
+ velocity -= bounceness;
+ if (1 - friction * frictionness > 0)
+ velocity *= 1 - friction * frictionness;
+ else
+ velocity = 0;
+ if (terrain.getOpacity(position.x, position.z) < .2)
+ velocity += bounceness * elasticity * .3;
+ else
+ velocity += bounceness * elasticity;
+
+ if (findLengthfast(&bounceness) > 1) {
+ int whichsound;
+ if (terrain.getOpacity(position.x, position.z) > .2) {
+ if (type == staff)
+ whichsound = footstepsound3 + abs(Random() % 2);
+ else
+ whichsound = clank1sound + abs(Random() % 4);
+ } else {
+ whichsound = footstepsound + abs(Random() % 2);
+ }
+ emit_sound_at(whichsound, position,
+ findLengthfast(&bounceness)
+ * (terrain.getOpacity(position.x, position.z) > .2 ? 128. : 32.));
+
+ if (terrain.getOpacity(position.x, position.z) < .2) {
+ XYZ terrainlight;
+ terrainlight = terrain.getLighting(position.x, position.z);
+ if (environment == snowyenvironment) {
+ if (distsq(&position, &viewer) < viewdistance * viewdistance / 4)
+ Sprite::MakeSprite(cloudsprite, position, velocity, terrainlight.x, terrainlight.y, terrainlight.z, .5, .7);
+ } else if (environment == grassyenvironment) {
+ if (distsq(&position, &viewer) < viewdistance * viewdistance / 4)
+ Sprite::MakeSprite(cloudsprite, position, velocity, terrainlight.x * 90 / 255, terrainlight.y * 70 / 255, terrainlight.z * 8 / 255, .5, .5);
+ } else if (environment == desertenvironment) {
+ if (distsq(&position, &viewer) < viewdistance * viewdistance / 4)
+ Sprite::MakeSprite(cloudsprite, position, velocity, terrainlight.x * 190 / 255, terrainlight.y * 170 / 255, terrainlight.z * 108 / 255, .5, .7);
+ }
+ }
+ }
+ }
+ whichhit = terrain.lineTerrain(oldtippoint, tippoint, &colpoint);
+ if (whichhit != -1 || tippoint.y < terrain.getHeight(tippoint.x, tippoint.z)) {
+ if (whichhit != -1)
+ tippoint = colpoint * terrain.scale;
+ else
+ tippoint.y = terrain.getHeight(tippoint.x, tippoint.z);
+
+ terrainnormal = terrain.getNormal(tippoint.x, tippoint.z);
+ ReflectVector(&tipvelocity, &terrainnormal);
+ tippoint += terrainnormal * .002;
+ bounceness = terrainnormal * findLength(&tipvelocity) * (abs(normaldotproduct(tipvelocity, terrainnormal)));
+ if (findLengthfast(&tipvelocity) < findLengthfast(&bounceness))
+ bounceness = 0;
+ frictionness = abs(normaldotproduct(tipvelocity, terrainnormal));
+ tipvelocity -= bounceness;
+ if (1 - friction * frictionness > 0)
+ tipvelocity *= 1 - friction * frictionness;
+ else
+ tipvelocity = 0;
+ if (terrain.getOpacity(tippoint.x, tippoint.z) < .2)
+ tipvelocity += bounceness * elasticity * .3;
+ else
+ tipvelocity += bounceness * elasticity;
+
+ if (findLengthfast(&bounceness) > 1) {
+ int whichsound;
+ if (terrain.getOpacity(tippoint.x, tippoint.z) > .2) {
+ if (type == staff)
+ whichsound = footstepsound3 + abs(Random() % 2);
+ else
+ whichsound = clank1sound + abs(Random() % 4);
+ } else {
+ whichsound = footstepsound + abs(Random() % 2);
+ }
+ emit_sound_at(whichsound, tippoint,
+ findLengthfast(&bounceness)
+ * (terrain.getOpacity(tippoint.x, tippoint.z) > .2 ? 128. : 32.));
+
+ if (terrain.getOpacity(tippoint.x, tippoint.z) < .2) {
+ XYZ terrainlight;
+ terrainlight = terrain.getLighting(tippoint.x, tippoint.z);
+ if (environment == snowyenvironment) {
+ if (distsq(&tippoint, &viewer) < viewdistance * viewdistance / 4)
+ Sprite::MakeSprite(cloudsprite, tippoint, tipvelocity, terrainlight.x, terrainlight.y, terrainlight.z, .5, .7);
+ } else if (environment == grassyenvironment) {
+ if (distsq(&tippoint, &viewer) < viewdistance * viewdistance / 4)
+ Sprite::MakeSprite(cloudsprite, tippoint, tipvelocity, terrainlight.x * 90 / 255, terrainlight.y * 70 / 255, terrainlight.z * 8 / 255, .5, .5);
+ } else if (environment == desertenvironment) {
+ if (distsq(&tippoint, &viewer) < viewdistance * viewdistance / 4)
+ Sprite::MakeSprite(cloudsprite, tippoint, tipvelocity, terrainlight.x * 190 / 255, terrainlight.y * 170 / 255, terrainlight.z * 108 / 255, .5, .7);
+ }
+ }
+ }
+ }
+
+ //Edges
+ mid = position + tippoint;
+ mid /= 2;
+ mid += (position - mid) / 20;
+ oldmid = mid;
+ if (mid.y < terrain.getHeight(mid.x, mid.z)) {
+ hitsomething = 1;
+ mid.y = terrain.getHeight(mid.x, mid.z);
+
+ terrainnormal = terrain.getNormal(mid.x, mid.z);
+ ReflectVector(&velocity, &terrainnormal);
+ //mid+=terrainnormal*.002;
+ bounceness = terrainnormal * findLength(&velocity) * (abs(normaldotproduct(velocity, terrainnormal)));
+ if (findLengthfast(&velocity) < findLengthfast(&bounceness))
+ bounceness = 0;
+ frictionness = abs(normaldotproduct(velocity, terrainnormal));
+ velocity -= bounceness;
+ if (1 - friction * frictionness > 0)
+ velocity *= 1 - friction * frictionness;
+ else
+ velocity = 0;
+ if (terrain.getOpacity(mid.x, mid.z) < .2)
+ velocity += bounceness * elasticity * .3;
+ else
+ velocity += bounceness * elasticity;
+
+ if (findLengthfast(&bounceness) > 1) {
+ int whichsound;
+ if (terrain.getOpacity(mid.x, mid.z) > .2) {
+ if (type == staff)
+ whichsound = footstepsound3 + abs(Random() % 2);
+ if (type != staff)
+ whichsound = clank1sound + abs(Random() % 4);
+ } else {
+ whichsound = footstepsound + abs(Random() % 2);
+ }
+ emit_sound_at(whichsound, mid,
+ findLengthfast(&bounceness)
+ * (terrain.getOpacity(position.x, position.z) > .2
+ ? 128.
+ : 32.));
+ }
+ position += (mid - oldmid) * 20;
+ }
+
+ mid = position + tippoint;
+ mid /= 2;
+ mid += (tippoint - mid) / 20;
+ oldmid = mid;
+ if (mid.y < terrain.getHeight(mid.x, mid.z)) {
+ hitsomething = 1;
+ mid.y = terrain.getHeight(mid.x, mid.z);
+
+ terrainnormal = terrain.getNormal(mid.x, mid.z);
+ ReflectVector(&tipvelocity, &terrainnormal);
+ //mid+=terrainnormal*.002;
+ bounceness = terrainnormal * findLength(&tipvelocity) * (abs(normaldotproduct(tipvelocity, terrainnormal)));
+ if (findLengthfast(&tipvelocity) < findLengthfast(&bounceness))
+ bounceness = 0;
+ frictionness = abs(normaldotproduct(tipvelocity, terrainnormal));
+ tipvelocity -= bounceness;
+ if (1 - friction * frictionness > 0)
+ tipvelocity *= 1 - friction * frictionness;
+ else
+ tipvelocity = 0;
+ if (terrain.getOpacity(mid.x, mid.z) < .2)
+ tipvelocity += bounceness * elasticity * .3;
+ else
+ tipvelocity += bounceness * elasticity;
+
+ if (findLengthfast(&bounceness) > 1) {
+ int whichsound;
+ if (terrain.getOpacity(mid.x, mid.z) > .2) {
+ if (type == staff)
+ whichsound = footstepsound3 + abs(Random() % 2);
+ if (type != staff)
+ whichsound = clank1sound + abs(Random() % 4);
+ } else {
+ whichsound = footstepsound + abs(Random() % 2);
+ }
+ emit_sound_at(whichsound, mid,
+ findLengthfast(&bounceness)
+ * (terrain.getOpacity(position.x, position.z) > .2
+ ? 128.
+ : 32.));
+ }
+ tippoint += (mid - oldmid) * 20;
+ }
+ //Gravity
+ velocity.y += gravity * multiplier;
+ tipvelocity.y += gravity * multiplier;
+
+ //Rotation
+ XYZ temppoint1, temppoint2;
+ float distance;
+
+ temppoint1 = position;
+ temppoint2 = tippoint;
+ distance = findDistance(&temppoint1, &temppoint2);
+ rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
+ rotation2 *= 360 / 6.28;
+ temppoint1.y = 0;
+ temppoint2.y = 0;
+ rotation1 = acos((temppoint1.z - temppoint2.z) / findDistance(&temppoint1, &temppoint2));
+ rotation1 *= 360 / 6.28;
+ rotation3 = 0;
+ smallrotation = 90;
+ smallrotation2 = 0;
+ bigtilt = 0;
+ bigtilt2 = 0;
+ bigrotation = 0;
+ if (temppoint1.x > temppoint2.x)
+ rotation1 = 360 - rotation1;
+
+ //Stop moving
+ if (findLengthfast(&velocity) < .3 && findLengthfast(&tipvelocity) < .3 && hitsomething) {
+ freetime += multiplier;
+ }
+
+ if (freetime > .4) {
+ velocity = 0;
+ tipvelocity = 0;
+ }
+ firstfree = 0;
+ }
+ }
+ multiplier = tempmult;
+ if (blooddrip && bloody) {
+ blooddripdelay -= blooddrip * multiplier / 2;
+ blooddrip -= multiplier;
+ if (blooddrip < 0)
+ blooddrip = 0;
+ if (blooddrip > 5)
+ blooddrip = 5;
+ if (blooddripdelay < 0 && bloodtoggle) {
+ blooddripdelay = 1;
+ XYZ bloodvel;
+ XYZ bloodloc;
+ bloodloc = position + (tippoint - position) * .7;
+ bloodloc.y -= .05;
+ if (bloodtoggle) {
+ bloodvel = 0;
+ Sprite::MakeSprite(bloodsprite, bloodloc, bloodvel, 1, 1, 1, .03, 1);
+ }
+ }
+ }
+ if (onfire) {
+ flamedelay -= multiplier;
+ if (onfire && flamedelay <= 0) {
+ flamedelay = .020;
+ flamedelay -= multiplier;
+ normalrot = 0;
+ if (owner != -1) {
+ normalrot = Person::players[owner]->velocity;
+ }
+ normalrot.y += 1;
+ if (owner != -1) {
+ if (Person::players[owner]->onterrain) {
+ normalrot.y = 1;
+ }
+ }
+ Sprite::MakeSprite(weaponflamesprite, position + tippoint * (((float)abs(Random() % 100)) / 600 + .05), normalrot, 1, 1, 1, (.6 + (float)abs(Random() % 100) / 200 - .25) * 1 / 3, 1);
+ Sprite::setLastSpriteSpeed(4);
+ Sprite::setLastSpriteAlivetime(.3);
+ }
+ }
+
+ if (!onfire && owner == -1 && type != staff) {
+ flamedelay -= multiplier;
+ if (flamedelay <= 0) {
+ flamedelay = .020;
+ flamedelay -= multiplier;
+ normalrot = 0;
+ if (Random() % 50 == 0 && distsq(&position, &viewer) > 80) {
+ XYZ shinepoint;
+ shinepoint = position + (tippoint - position) * (((float)abs(Random() % 100)) / 100);
+ Sprite::MakeSprite(weaponshinesprite, shinepoint, normalrot, 1, 1, 1, (.1 + (float)abs(Random() % 100) / 200 - .25) * 1 / 3 * fast_sqrt(findDistance(&shinepoint, &viewer)), 1);
+ Sprite::setLastSpriteSpeed(4);
+ Sprite::setLastSpriteAlivetime(.3);
+ }
+ }
+ }
+}
+
+void Weapons::DoStuff()
+{
+ //Move
+ int i = 0;
+ for (std::vector<Weapon>::iterator weapon = begin(); weapon != end(); ++weapon) {
+ weapon->DoStuff(i++);
+ }
+}
+
+void Weapon::Draw()
+{
+ static XYZ terrainlight;
+ static GLfloat M[16];
+
+ if ((frustum.SphereInFrustum(position.x, position.y, position.z, 1) &&
+ distsq(&viewer, &position) < viewdistance * viewdistance)) {
+ bool draw = false;
+ if (owner == -1) {
+ draw = true;
+ if (velocity.x && !physics)
+ drawhowmany = 10;
+ else
+ drawhowmany = 1;
+ } else {
+ if (Person::players[owner]->occluded < 25)
+ if ((frustum.SphereInFrustum(Person::players[owner]->coords.x, Person::players[owner]->coords.y + Person::players[owner]->scale * 3, Person::players[owner]->coords.z, Person::players[owner]->scale * 8) && distsq(&viewer, &Person::players[owner]->coords) < viewdistance * viewdistance) || Person::players[owner]->skeleton.free == 3)
+ draw = true;
+ if (
+ (Person::players[owner]->animTarget == knifeslashstartanim ||
+ Person::players[owner]->animTarget == swordsneakattackanim ||
+ (Person::players[owner]->animCurrent == staffhitanim && Person::players[owner]->frameCurrent > 1) ||
+ (Person::players[owner]->animCurrent == staffhitreversedanim && Person::players[owner]->frameCurrent > 1) ||
+ (Person::players[owner]->animCurrent == staffspinhitanim && Person::players[owner]->frameCurrent > 1) ||
+ (Person::players[owner]->animCurrent == staffspinhitreversedanim && Person::players[owner]->frameCurrent > 1) ||
+ (Person::players[owner]->animCurrent == staffgroundsmashanim && Person::players[owner]->frameCurrent > 1) ||
+ (Person::players[owner]->animTarget == swordslashanim && Person::players[owner]->frameTarget < 7) ||
+ Person::players[owner]->animTarget == crouchstabanim ||
+ Person::players[owner]->animTarget == swordslashreversalanim ||
+ Person::players[owner]->animTarget == swordslashreversedanim ||
+ Person::players[owner]->animTarget == knifefollowanim ||
+ Person::players[owner]->animTarget == swordgroundstabanim ||
+ Person::players[owner]->animTarget == knifethrowanim) &&
+ Person::players[owner]->animTarget == lastdrawnanim &&
+ !Person::players[owner]->skeleton.free
+ ) {
+ drawhowmany = 10;
+ } else {
+ drawhowmany = 1;
+ }
+ if (Person::players[owner]->animTarget == swordgroundstabanim) {
+ lastdrawnrotation1 = rotation1;
+ lastdrawnrotation2 = rotation2;
+ lastdrawnrotation3 = rotation3;
+ lastdrawnbigrotation = bigrotation;
+ lastdrawnbigtilt = bigtilt;
+ lastdrawnbigtilt2 = bigtilt2;
+ lastdrawnsmallrotation = smallrotation;
+ lastdrawnsmallrotation2 = smallrotation2;
+ }
+ }
+ if (draw) {
+ terrainlight = terrain.getLighting(position.x, position.z);
+ if (drawhowmany > 0) {
+ glAlphaFunc(GL_GREATER, 0.01);
+ }
+ for (int j = drawhowmany; j > 0; j--) {
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, j / drawhowmany);
+ if (owner == -1)
+ glTranslatef(position.x * (((float)(j)) / drawhowmany) + lastdrawnposition.x * (1 - ((float)(j)) / drawhowmany), position.y * (((float)(j)) / drawhowmany) + lastdrawnposition.y * (1 - ((float)(j)) / drawhowmany), position.z * (((float)(j)) / drawhowmany) + lastdrawnposition.z * (1 - ((float)(j)) / drawhowmany));
+ else
+ glTranslatef(position.x * (((float)(j)) / drawhowmany) + lastdrawnposition.x * (1 - ((float)(j)) / drawhowmany), position.y * (((float)(j)) / drawhowmany) - .02 + lastdrawnposition.y * (1 - ((float)(j)) / drawhowmany), position.z * (((float)(j)) / drawhowmany) + lastdrawnposition.z * (1 - ((float)(j)) / drawhowmany));
+ glRotatef(bigrotation * (((float)(j)) / drawhowmany) + lastdrawnbigrotation * (1 - ((float)(j)) / drawhowmany), 0, 1, 0);
+ glRotatef(bigtilt2 * (((float)(j)) / drawhowmany) + lastdrawnbigtilt2 * (1 - ((float)(j)) / drawhowmany), 1, 0, 0);
+ glRotatef(bigtilt * (((float)(j)) / drawhowmany) + lastdrawnbigtilt * (1 - ((float)(j)) / drawhowmany), 0, 0, 1);
+ glRotatef(-rotation1 * (((float)(j)) / drawhowmany) - lastdrawnrotation1 * (1 - ((float)(j)) / drawhowmany) + 90, 0, 1, 0);
+ glRotatef(-rotation2 * (((float)(j)) / drawhowmany) - lastdrawnrotation2 * (1 - ((float)(j)) / drawhowmany) + 90, 0, 0, 1);
+ glRotatef(-rotation3 * (((float)(j)) / drawhowmany) - lastdrawnrotation3 * (1 - ((float)(j)) / drawhowmany), 0, 1, 0);
+ glRotatef(smallrotation * (((float)(j)) / drawhowmany) + lastdrawnsmallrotation * (1 - ((float)(j)) / drawhowmany), 1, 0, 0);
+ glRotatef(smallrotation2 * (((float)(j)) / drawhowmany) + lastdrawnsmallrotation2 * (1 - ((float)(j)) / drawhowmany), 0, 1, 0);
+
+ if (owner != -1) {
+ if (Person::players[owner]->animTarget == staffhitanim || Person::players[owner]->animCurrent == staffhitanim || Person::players[owner]->animTarget == staffhitreversedanim || Person::players[owner]->animCurrent == staffhitreversedanim) {
+ glTranslatef(0, 0, -.3);
+ }
+ if (Person::players[owner]->animTarget == staffgroundsmashanim || Person::players[owner]->animCurrent == staffgroundsmashanim || Person::players[owner]->animTarget == staffspinhitreversedanim || Person::players[owner]->animCurrent == staffspinhitreversedanim || Person::players[owner]->animTarget == staffspinhitanim || Person::players[owner]->animCurrent == staffspinhitanim) {
+ glTranslatef(0, 0, -.1);
+ }
+ }
+
+ glEnable(GL_LIGHTING);
+ switch (type) {
+ case knife:
+ if (!bloody || !bloodtoggle)
+ throwingknifemodel.drawdifftex(knifetextureptr);
+ if (bloodtoggle) {
+ if (bloody == 1)
+ throwingknifemodel.drawdifftex(lightbloodknifetextureptr);
+ if (bloody == 2)
+ throwingknifemodel.drawdifftex(bloodknifetextureptr);
+ }
+ break;
+ case sword:
+ if (!bloody || !bloodtoggle)
+ swordmodel.drawdifftex(swordtextureptr);
+ if (bloodtoggle) {
+ if (bloody == 1)
+ swordmodel.drawdifftex(lightbloodswordtextureptr);
+ if (bloody == 2)
+ swordmodel.drawdifftex(bloodswordtextureptr);
+ }
+ break;
+ case staff:
+ staffmodel.drawdifftex(stafftextureptr);
+ break;
+ }
+
+ glPopMatrix();
+ }
+
+ lastdrawnposition = position;
+ lastdrawntippoint = tippoint;
+ lastdrawnrotation1 = rotation1;
+ lastdrawnrotation2 = rotation2;
+ lastdrawnrotation3 = rotation3;
+ lastdrawnbigrotation = bigrotation;
+ lastdrawnbigtilt = bigtilt;
+ lastdrawnbigtilt2 = bigtilt2;
+ lastdrawnsmallrotation = smallrotation;
+ lastdrawnsmallrotation2 = smallrotation2;
+ if (owner != -1)
+ lastdrawnanim = Person::players[owner]->animCurrent;
+ }
+ if (owner != -1) {
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+ glTranslatef(position.x, position.y - .02, position.z);
+ glRotatef(bigrotation, 0, 1, 0);
+ glRotatef(bigtilt2, 1, 0, 0);
+ glRotatef(bigtilt, 0, 0, 1);
+ glRotatef(-rotation1 + 90, 0, 1, 0);
+ glRotatef(-rotation2 + 90, 0, 0, 1);
+ glRotatef(-rotation3, 0, 1, 0);
+ glRotatef(smallrotation, 1, 0, 0);
+ glRotatef(smallrotation2, 0, 1, 0);
+ glTranslatef(0, 0, length);
+ glGetFloatv(GL_MODELVIEW_MATRIX, M);
+ tippoint.x = M[12];
+ tippoint.y = M[13];
+ tippoint.z = M[14];
+ glPopMatrix();
+ }
+ }
+}
+
+void Weapon::drop(XYZ v, XYZ tv, bool sethitsomething)
+{
+ owner = -1;
+ velocity = v;
+ tipvelocity = tv;
+ missed = 1;
+ if (sethitsomething) {
+ hitsomething = 0;
+ }
+ freetime = 0;
+ firstfree = 1;
+ physics = 1;
+}
+
+void Weapon::thrown(XYZ v, bool sethitsomething)
+{
+ drop(v, v, sethitsomething);
+ missed = 0;
+ physics = 0;
+}
+
+int Weapons::Draw()
+{
+ glAlphaFunc(GL_GREATER, 0.9);
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_BLEND);
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_FRONT);
+ glDepthMask(1);
+
+ for (std::vector<Weapon>::iterator weapon = begin(); weapon != end(); ++weapon) {
+ weapon->Draw();
+ }
+ return 0;
+}
+
+Weapons::Weapons()
+{
+}
+
+Weapons::~Weapons()
+{
+ Weapon::stafftextureptr.destroy();
+ Weapon::knifetextureptr.destroy();
+ Weapon::lightbloodknifetextureptr.destroy();
+ Weapon::bloodknifetextureptr.destroy();
+ Weapon::swordtextureptr.destroy();
+ Weapon::lightbloodswordtextureptr.destroy();
+ Weapon::bloodswordtextureptr.destroy();
+}
+
--- /dev/null
+/*
+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 _WEAPONS_H_
+#define _WEAPONS_H_
+
+/**> HEADER FILES <**/
+#include "Animation/Skeleton.h"
+#include "Environment/Terrain.h"
+#include "Graphic/gamegl.h"
+#include "Graphic/Models.h"
+#include "Graphic/Sprite.h"
+#include "Graphic/Texture.h"
+#include "Math/Quaternions.h"
+#include "Objects/Person.h"
+
+#include <cmath>
+
+#define max_weapons 30
+#define max_weaponinstances 20
+
+#define knife 1
+#define sword 2
+#define staff 3
+
+class Weapon
+{
+public:
+ Weapon(int type, int owner);
+
+ static Model throwingknifemodel;
+ static Texture knifetextureptr;
+ static Texture lightbloodknifetextureptr;
+ static Texture bloodknifetextureptr;
+
+ static Model swordmodel;
+ static Texture swordtextureptr;
+ static Texture lightbloodswordtextureptr;
+ static Texture bloodswordtextureptr;
+
+ static Model staffmodel;
+ static Texture stafftextureptr;
+
+ void Draw();
+ void DoStuff(int);
+
+ int getType() {
+ return type;
+ }
+ void setType(int);
+
+ void drop(XYZ velocity, XYZ tipvelocity, bool sethitsomething = true);
+ void thrown(XYZ velocity, bool sethitsomething = true);
+
+ int owner;
+ XYZ position;
+ XYZ tippoint;
+ XYZ velocity;
+ XYZ tipvelocity;
+ bool missed;
+ bool hitsomething;
+ float freetime;
+ bool firstfree;
+ bool physics;
+
+ float damage;
+ int bloody;
+ float blooddrip;
+ float blooddripdelay;
+
+ float rotation1;
+ float rotation2;
+ float rotation3;
+ float bigrotation;
+ float bigtilt;
+ float bigtilt2;
+ float smallrotation;
+ float smallrotation2;
+private:
+ int type;
+
+ XYZ oldtippoint;
+ XYZ oldposition;
+ int oldowner;
+ bool onfire;
+ float flamedelay;
+ float mass;
+ float tipmass;
+ float length;
+ float drawhowmany;
+
+ XYZ lastdrawnposition;
+ XYZ lastdrawntippoint;
+ float lastdrawnrotation1;
+ float lastdrawnrotation2;
+ float lastdrawnrotation3;
+ float lastdrawnbigrotation;
+ float lastdrawnbigtilt;
+ float lastdrawnbigtilt2;
+ float lastdrawnsmallrotation;
+ float lastdrawnsmallrotation2;
+ int lastdrawnanim;
+};
+
+class Weapons : public std::vector<Weapon>
+{
+public:
+ Weapons();
+ ~Weapons();
+
+ int Draw();
+ void DoStuff();
+};
+
+extern Weapons weapons;
+#endif
+++ /dev/null
-/*
-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 "Person.h"
-#include "openal_wrapper.h"
-#include "Animation/Animation.h"
-#include "Sounds.h"
-#include "Awards.h"
-#include "Game.h"
-#include "Dialog.h"
-#include "Utils/Folders.h"
-
-extern float multiplier;
-extern Terrain terrain;
-extern float gravity;
-extern int environment;
-extern int detail;
-extern FRUSTUM frustum;
-extern XYZ viewer;
-extern float realmultiplier;
-extern int slomo;
-extern float slomodelay;
-extern bool cellophane;
-extern float texdetail;
-extern float realtexdetail;
-extern GLubyte bloodText[512 * 512 * 3];
-extern GLubyte wolfbloodText[512 * 512 * 3];
-extern int bloodtoggle;
-extern Objects objects;
-extern bool autoslomo;
-extern float camerashake;
-extern float woozy;
-extern float viewdistance;
-extern float blackout;
-extern int difficulty;
-extern bool decals;
-extern float fadestart;
-extern bool freeze;
-extern bool winfreeze;
-extern bool showpoints;
-extern bool immediate;
-extern int tutoriallevel;
-extern float smoketex;
-extern int tutorialstage;
-extern bool reversaltrain;
-extern bool canattack;
-extern bool cananger;
-extern float damagedealt;
-extern int hostile;
-extern float hostiletime;
-
-extern bool gamestarted;
-
-std::vector<std::shared_ptr<Person>> Person::players(1, std::shared_ptr<Person>(new Person()));
-
-Person::Person() :
- whichpatchx(0),
- whichpatchz(0),
- animCurrent(bounceidleanim),
- animTarget(bounceidleanim),
- frameCurrent(0),
- frameTarget(1),
- oldanimCurrent(0),
- oldanimTarget(0),
- oldframeCurrent(0),
- oldframeTarget(0),
- howactive(typeactive),
- parriedrecently(0),
- superruntoggle(false),
- lastattack(0), lastattack2(0), lastattack3(0),
- currentoffset(), targetoffset(), offset(),
- target(0),
- transspeed(0),
-
- realoldcoords(),
- oldcoords(),
- coords(),
- velocity(),
-
- proportionhead(),
- proportionlegs(),
- proportionarms(),
- proportionbody(),
-
- unconscioustime(0),
-
- immobile(false),
-
- velspeed(0),
- targetyaw(0),
- targetrot(0),
- rot(0),
- oldrot(0),
- lookyaw(0),
- lookpitch(0),
- yaw(0),
- pitch(0),
- lowyaw(0),
- tilt(0),
- targettilt(0),
- tilt2(0),
- targettilt2(0),
- rabbitkickenabled(false),
-
- bloodloss(0),
- bleeddelay(0),
- skiddelay(0),
- skiddingdelay(0),
- deathbleeding(0),
- tempdeltav(0),
-
- damagetolerance(200),
- damage(0),
- permanentdamage(0),
- superpermanentdamage(0),
- lastcollide(0),
- dead(0),
-
- jumppower(5),
- onground(false),
-
- wentforweapon(0),
-
- calcrot(false),
-
- facing(),
-
- bleeding(0),
- bleedx(0), bleedy(0),
- direction(0),
- texupdatedelay(0),
-
- headyaw(0), headpitch(0),
- targetheadyaw(0), targetheadpitch(0),
-
- onterrain(false),
- pause(false),
-
- grabdelay(0),
-
- victim(nullptr),
- hasvictim(false),
-
- updatedelay(0),
- normalsupdatedelay(0),
-
- jumpstart(false),
- forwardkeydown(false),
- forwardstogglekeydown(false),
- rightkeydown(false),
- leftkeydown(false),
- backkeydown(false),
- jumpkeydown(false),
- jumptogglekeydown(false),
- crouchkeydown(false),
- crouchtogglekeydown(false),
- drawkeydown(false),
- drawtogglekeydown(false),
- throwkeydown(false),
- throwtogglekeydown(false),
- attackkeydown(false),
- feint(false),
- lastfeint(false),
- headless(false),
-
- crouchkeydowntime(0),
- jumpkeydowntime(0),
- freefall(false),
-
- turnspeed(0),
-
- aitype(passivetype),
- aiupdatedelay(0),
- losupdatedelay(0),
- ally(0),
- collide(0),
- collided(-10),
- avoidcollided(0),
- loaded(false),
- whichdirection(false),
- whichdirectiondelay(0),
- avoidsomething(false),
- avoidwhere(),
- blooddimamount(0),
-
- staggerdelay(0),
- blinkdelay(0),
- twitchdelay(0),
- twitchdelay2(0),
- twitchdelay3(0),
- lefthandmorphness(0),
- righthandmorphness(0),
- headmorphness(0),
- chestmorphness(0),
- tailmorphness(0),
- targetlefthandmorphness(0),
- targetrighthandmorphness(0),
- targetheadmorphness(1),
- targetchestmorphness(0),
- targettailmorphness(0),
- lefthandmorphstart(0), lefthandmorphend(0),
- righthandmorphstart(0), righthandmorphend(0),
- headmorphstart(0), headmorphend(0),
- chestmorphstart(0), chestmorphend(0),
- tailmorphstart(0), tailmorphend(0),
-
- weaponmissdelay(0),
- highreversaldelay(0),
- lowreversaldelay(0),
-
- creature(rabbittype),
-
- id(0),
-
- skeleton(),
-
- speed(0),
- scale(-1),
- power(0),
- speedmult(0),
-
- protectionhead(0),
- protectionhigh(0),
- protectionlow(0),
- armorhead(0),
- armorhigh(0),
- armorlow(0),
- metalhead(false),
- metalhigh(false),
- metallow(false),
-
- numclothes(0),
-
- landhard(false),
- bled(false),
- spurt(false),
- onfire(false),
- onfiredelay(0),
- burnt(0),
-
- flamedelay(0),
-
- playerdetail(0),
-
- num_weapons(0),
- weaponactive(-1),
- weaponstuck(-1),
- weaponstuckwhere(0),
-
- numwaypoints(0),
- pausetime(0),
-
- headtarget(),
- interestdelay(0),
-
- finalfinaltarget(),
- finaltarget(),
- finalpathfindpoint(0),
- targetpathfindpoint(0),
- lastpathfindpoint(0),
- lastpathfindpoint2(0),
- lastpathfindpoint3(0),
- lastpathfindpoint4(0),
-
- waypoint(0),
-
- lastseen(),
- lastseentime(0),
- lastchecktime(0),
- stunned(0),
- surprised(0),
- runninghowlong(0),
- occluded(0),
- lastoccluded(0),
- laststanding(0),
- escapednum(0),
-
- speechdelay(0),
- neckspurtdelay(0),
- neckspurtparticledelay(0),
- neckspurtamount(0),
-
- whichskin(0),
- rabbitkickragdoll(false),
-
- tempanimation(),
-
- jumpclimb(false)
-{
-}
-
-/* Read a person in tfile. Throws an error if it’s not valid */
-Person::Person(FILE *tfile, int mapvers, unsigned i) : Person()
-{
- id = i;
- funpackf(tfile, "Bi Bi Bf Bf Bf Bi", &whichskin, &creature, &coords.x, &coords.y, &coords.z, &num_weapons);
- if (mapvers >= 5) {
- funpackf(tfile, "Bi", &howactive);
- } else {
- howactive = typeactive;
- }
- if (mapvers >= 3) {
- funpackf(tfile, "Bf", &scale);
- } else {
- scale = -1;
- }
- if (mapvers >= 11) {
- funpackf(tfile, "Bb", &immobile);
- } else {
- immobile = 0;
- }
- if (mapvers >= 12) {
- funpackf(tfile, "Bf", &yaw);
- } else {
- yaw = 0;
- }
- targetyaw = yaw;
- if (num_weapons < 0 || num_weapons > 5) {
- throw InvalidPersonException();
- }
- if (num_weapons > 0 && num_weapons < 5) {
- for (int j = 0; j < num_weapons; j++) {
- weaponids[j] = weapons.size();
- int type;
- funpackf(tfile, "Bi", &type);
- weapons.push_back(Weapon(type, id));
- }
- }
- funpackf(tfile, "Bi", &numwaypoints);
- for (int j = 0; j < numwaypoints; j++) {
- funpackf(tfile, "Bf", &waypoints[j].x);
- funpackf(tfile, "Bf", &waypoints[j].y);
- funpackf(tfile, "Bf", &waypoints[j].z);
- if (mapvers >= 5) {
- funpackf(tfile, "Bi", &waypointtype[j]);
- } else {
- waypointtype[j] = wpkeepwalking;
- }
- }
-
- funpackf(tfile, "Bi", &waypoint);
- if (waypoint > (numwaypoints - 1)) {
- waypoint = 0;
- }
-
- funpackf(tfile, "Bf Bf Bf", &armorhead, &armorhigh, &armorlow);
- funpackf(tfile, "Bf Bf Bf", &protectionhead, &protectionhigh, &protectionlow);
- funpackf(tfile, "Bf Bf Bf", &metalhead, &metalhigh, &metallow);
- funpackf(tfile, "Bf Bf", &power, &speedmult);
-
- float headprop, legprop, armprop, bodyprop;
-
- if (mapvers >= 4) {
- funpackf(tfile, "Bf Bf Bf Bf", &headprop, &bodyprop, &armprop, &legprop);
- } else {
- headprop = 1;
- bodyprop = 1;
- armprop = 1;
- legprop = 1;
- }
-
- if (creature == wolftype) {
- proportionhead = 1.1 * headprop;
- proportionbody = 1.1 * bodyprop;
- proportionarms = 1.1 * armprop;
- proportionlegs = 1.1 * legprop;
- } else if (creature == rabbittype) {
- proportionhead = 1.2 * headprop;
- proportionbody = 1.05 * bodyprop;
- proportionarms = 1.00 * armprop;
- proportionlegs = 1.1 * legprop;
- proportionlegs.y = 1.05 * legprop;
- }
-
- funpackf(tfile, "Bi", &numclothes);
- for (int k = 0; k < numclothes; k++) {
- int templength;
- funpackf(tfile, "Bi", &templength);
- for (int l = 0; l < templength; l++)
- funpackf(tfile, "Bb", &clothes[k][l]);
- clothes[k][templength] = '\0';
- funpackf(tfile, "Bf Bf Bf", &clothestintr[k], &clothestintg[k], &clothestintb[k]);
- }
-
- loaded = true;
-
- if (scale < 0) {
- if (creature == wolftype) {
- scale = .23;
- damagetolerance = 300;
- } else {
- scale = .2;
- }
- }
-
- oldcoords = coords;
- realoldcoords = coords;
-}
-
-void Person::skeletonLoad(bool clothes)
-{
- skeleton.id = id;
- if (creature != wolftype) {
- skeleton.Load(
- "Skeleton/BasicFigure",
- "Skeleton/BasicFigureLow",
- "Skeleton/RabbitBelt",
- "Models/Body.solid",
- "Models/Body2.solid",
- "Models/Body3.solid",
- "Models/Body4.solid",
- "Models/Body5.solid",
- "Models/Body6.solid",
- "Models/Body7.solid",
- "Models/BodyLow.solid",
- "Models/Belt.solid",
- clothes
- );
- } else {
- skeleton.Load(
- "Skeleton/BasicFigureWolf",
- "Skeleton/BasicFigureWolfLow",
- "Skeleton/RabbitBelt",
- "Models/Wolf.solid",
- "Models/Wolf2.solid",
- "Models/Wolf3.solid",
- "Models/Wolf4.solid",
- "Models/Wolf5.solid",
- "Models/Wolf6.solid",
- "Models/Wolf7.solid",
- "Models/WolfLow.solid",
- "Models/Belt.solid",
- clothes
- );
- }
-
- skeleton.drawmodel.textureptr.load(creatureskin[creature][whichskin], 1, &skeleton.skinText[0], &skeleton.skinsize);
-}
-
-/* EFFECT
- *
- * USES:
- * GameTick/doPlayerCollisions
- */
-void Person::CheckKick()
-{
- if (!(hasvictim
- && (animTarget == rabbitkickanim
- && victim
- && victim != this->shared_from_this()
- && frameCurrent >= 2
- && animCurrent == rabbitkickanim)
- && distsq(&coords, &victim->coords) < 1.2
- && !victim->skeleton.free))
- return;
-
- if (Animation::animations[victim->animTarget].height != lowheight) {
- float damagemult = (creature == wolftype ? 2.5 : 1.) * power * power;
- XYZ relative = velocity;
- relative.y = 0;
- Normalise(&relative);
-
- victim->spurt = 1;
- DoBlood(.2, 250);
- if (tutoriallevel != 1)
- emit_sound_at(heavyimpactsound, victim->coords);
- victim->RagDoll(0);
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velocity += relative * 120 * damagemult;
- }
- victim->Puff(neck);
- victim->DoDamage(100 * damagemult / victim->protectionhigh);
- if (id == 0)
- camerashake += .4;
-
- target = 0;
- frameCurrent = 3;
- animTarget = backflipanim;
- frameTarget = 4;
- velocity = facing * -10;
- velocity.y = 5;
- skeleton.free = 0;
- if (id == 0)
- resume_stream(whooshsound);
-
- award_bonus(id, cannon);
- } else if (victim->isCrouch()) {
- animTarget = rabbitkickreversedanim;
- animCurrent = rabbitkickreversedanim;
- victim->animCurrent = rabbitkickreversalanim;
- victim->animTarget = rabbitkickreversalanim;
- targettilt2 = 0;
- frameCurrent = 0;
- frameTarget = 1;
- target = 0;
- velocity = 0;
- victim->oldcoords = victim->coords;
- coords = victim->coords;
- victim->targetyaw = targetyaw;
- victim->victim = this->shared_from_this();
- }
-}
-
-/* EFFECT
- *
- * USES:
- * GameTick/doPlayerCollisions - spread fire between players
- * GameTick/doDevKeys - press f to ignite
- * Person::DoStuff - spread fire from lit campfires and bushes
- */
-void Person::CatchFire()
-{
- XYZ flatfacing, flatvelocity;
- int howmany;
- for (int i = 0; i < 10; i++) {
- howmany = abs(Random() % (skeleton.joints.size()));
- if (skeleton.free) {
- flatvelocity = skeleton.joints[howmany].velocity;
- flatfacing = skeleton.joints[howmany].position * scale + coords;
- } else {
- flatvelocity = velocity;
- flatfacing = DoRotation(DoRotation(DoRotation(skeleton.joints[howmany].position, 0, 0, tilt), tilt2, 0, 0), 0, yaw, 0) * scale + coords;
- }
- Sprite::MakeSprite(flamesprite, flatfacing, flatvelocity, 1, 1, 1, 2, 1);
- }
-
- onfiredelay = 0.5;
-
- emit_sound_at(firestartsound, coords);
-
- emit_stream_at(stream_firesound, coords);
-
- flamedelay = 0;
-
- onfire = 1;
-}
-
-/* FUNCTION
- * idle animation for this creature (depending on status)
- */
-int Person::getIdle()
-{
- if (Dialog::inDialog() && (howactive == typeactive) && (creature == rabbittype))
- return talkidleanim;
- if (hasvictim && (victim != this->shared_from_this())/*||(id==0&&attackkeydown)*/)
- if (/*(id==0&&attackkeydown)||*/(!victim->dead && victim->aitype != passivetype &&
- victim->aitype != searchtype && aitype != passivetype && aitype != searchtype &&
- victim->id < Person::players.size())) {
- if ((aitype == playercontrolled && stunned <= 0 && weaponactive == -1) || pause) {
- if (creature == rabbittype)
- return fightidleanim;
- if (creature == wolftype)
- return wolfidle;
- }
- if (aitype == playercontrolled && stunned <= 0 && weaponactive != -1) {
- if (weapons[weaponids[weaponactive]].getType() == knife)
- return knifefightidleanim;
- if (weapons[weaponids[weaponactive]].getType() == sword && victim->weaponactive != -1)
- return swordfightidlebothanim;
- if (weapons[weaponids[weaponactive]].getType() == sword)
- return swordfightidleanim;
- if (weapons[weaponids[weaponactive]].getType() == staff)
- return swordfightidleanim;
- }
- if (aitype != playercontrolled && stunned <= 0 && creature != wolftype && !pause)
- return fightsidestep;
- }
- if ((damage > permanentdamage || damage > damagetolerance * .8 || deathbleeding > 0) && creature != wolftype)
- return hurtidleanim;
- if (howactive == typesitting) return sitanim;
- if (howactive == typesittingwall) return sitwallanim;
- if (howactive == typesleeping) return sleepanim;
- if (howactive == typedead1) return dead1anim;
- if (howactive == typedead2) return dead2anim;
- if (howactive == typedead3) return dead3anim;
- if (howactive == typedead4) return dead4anim;
- if (creature == rabbittype) return bounceidleanim;
- if (creature == wolftype) return wolfidle;
- return 0;
-}
-
-/* FUNCTION
- * crouch animation for this creature
- */
-int Person::getCrouch()
-{
- if (creature == rabbittype)
- return crouchanim;
- if (creature == wolftype)
- return wolfcrouchanim;
- return 0;
-}
-
-/* FUNCTION
- * running animation for this creature (can be upright or all fours)
- */
-int Person::getRun()
-{
- if (creature == rabbittype && (!superruntoggle || weaponactive != -1))
- return runanim;
- if (creature == wolftype && (!superruntoggle))
- return wolfrunanim;
-
- if (creature == rabbittype && (superruntoggle && weaponactive == -1))
- return rabbitrunninganim;
- if (creature == wolftype && (superruntoggle))
- return wolfrunninganim;
- return 0;
-}
-
-/* FUNCTION
- */
-int Person::getStop()
-{
- if (creature == rabbittype)
- return stopanim;
- if (creature == wolftype)
- return wolfstopanim;
- return 0;
-}
-
-/* FUNCTION
- */
-int Person::getLanding()
-{
- if (creature == rabbittype)
- return landanim;
- if (creature == wolftype)
- return wolflandanim;
- return 0;
-}
-
-/* FUNCTION
- */
-int Person::getLandhard()
-{
- if (creature == rabbittype)
- return landhardanim;
- if (creature == wolftype)
- return wolflandhardanim;
- return 0;
-}
-
-/* EFFECT
- *
- * USES:
- * Person::DoAnimations
- */
-static void
-SolidHitBonus(int playerid)
-{
- if (bonustime < 1.5 && bonus >= solidhit && bonus <= megacombo)
- award_bonus(playerid, bonus == megacombo ? bonus : bonus + 1);
- else
- award_bonus(playerid, solidhit);
-}
-
-/* EFFECT
- * spawns blood effects
- */
-void Person::DoBlood(float howmuch, int which)
-{
- // FIXME: should abstract out inputs
- static int bleedxint, bleedyint;
- static XYZ bloodvel;
- if (bloodtoggle && tutoriallevel != 1) {
- if (bleeding <= 0 && spurt) {
- spurt = 0;
- for (int i = 0; i < 3; i++) {
- // emit blood particles
- bloodvel = 0;
- if (skeleton.free) {
- bloodvel -= DoRotation(skeleton.forward * 10 * scale, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0);
- bloodvel += DoRotation(jointVel(head), ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
- Sprite::MakeSprite(bloodsprite, jointPos(head) * scale + coords, bloodvel, 1, 1, 1, .05, 1);
- Sprite::MakeSprite(bloodflamesprite, jointPos(head) * scale + coords, bloodvel, 1, 1, 1, .3, 1);
- } else {
- bloodvel.z = 10;
- bloodvel = DoRotation(bloodvel, ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
- bloodvel += DoRotation(velocity, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0) * scale;
- Sprite::MakeSprite(bloodsprite, DoRotation((jointPos(head) + jointPos(neck)) / 2, 0, yaw, 0)*scale + coords, bloodvel, 1, 1, 1, .05, 1);
- Sprite::MakeSprite(bloodflamesprite, DoRotation((jointPos(head) + jointPos(neck)) / 2, 0, yaw, 0)*scale + coords, bloodvel, 1, 1, 1, .3, 1);
- }
- }
- if (Random() % 2 == 0) // 50% chance
- for (int i = 0; i < 3; i++) {
- if (Random() % 2 != 0) {
- // emit teeth particles
- bloodvel = 0;
- if (skeleton.free) {
- bloodvel -= DoRotation(skeleton.forward * 10 * scale, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0);
- bloodvel += DoRotation(jointVel(head), ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
- } else {
- bloodvel.z = 10;
- bloodvel = DoRotation(bloodvel, ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
- bloodvel += DoRotation(velocity, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0) * scale;
- }
- bloodvel *= .2;
- if (skeleton.free) {
- Sprite::MakeSprite(splintersprite, jointPos(head) * scale + coords, bloodvel, 1, 1, 1, .05, 1);
- } else {
- Sprite::MakeSprite(splintersprite, DoRotation((jointPos(head) + jointPos(neck)) / 2, 0, yaw, 0)*scale + coords, bloodvel, 1, 1, 1, .05, 1);
- }
- Sprite::setLastSpriteSpecial(3); // sets it to teeth
- }
- }
- }
- if (decals) {
- // FIXME: manipulating attributes
- bleeding = howmuch + (float)abs(Random() % 100) / 200 - .25;
- bleedxint = 0;
- bleedyint = 0;
- if (creature == rabbittype)
- while (bloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] > which + 4 || bloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] < which - 4 || bleedxint < 10 || bleedyint < 10 || bleedxint > 500 || bleedyint > 500) {
- bleedxint = abs(Random() % 512);
- bleedyint = abs(Random() % 512);
- }
- if (creature == wolftype)
- while (wolfbloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] > which + 4 || wolfbloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] < which - 4 || bleedxint < 10 || bleedyint < 10 || bleedxint > 500 || bleedyint > 500) {
- bleedxint = abs(Random() % 512);
- bleedyint = abs(Random() % 512);
- }
- bleedy = bleedxint;
- bleedx = bleedyint;
- bleedy /= realtexdetail;
- bleedx /= realtexdetail;
- direction = abs(Random() % 2) * 2 - 1;
- }
-
- }
- if (bleeding > 2)
- bleeding = 2;
-}
-
-/* EFFECT
- * spawns big blood effects and ???
- * modifies character's skin texture
- */
-void Person::DoBloodBig(float howmuch, int which)
-{
- static int bleedxint, bleedyint, i, j;
- static XYZ bloodvel;
- if (howmuch && id == 0)
- blooddimamount = 1;
-
- if (tutoriallevel != 1 || id == 0)
- if (aitype != playercontrolled && howmuch > 0) {
- // play pain sounds
- int whichsound = -1;
-
- if (creature == wolftype) {
- int i = abs(Random() % 2);
- if (i == 0)
- whichsound = snarlsound;
- if (i == 1)
- whichsound = snarl2sound;
- }
- if (creature == rabbittype) {
- int i = abs(Random() % 2);
- if (i == 0)
- whichsound = rabbitpainsound;
- if (i == 1 && howmuch >= 2)
- whichsound = rabbitpain1sound;
- }
-
- if (whichsound != -1) {
- emit_sound_at(whichsound, coords);
- addEnvSound(coords);
- }
- }
-
- if (id == 0 && howmuch > 0) {
- Game::flash(.5, 0);
- }
-
- if (bloodtoggle && decals && tutoriallevel != 1) {
- if (bleeding <= 0 && spurt) {
- spurt = 0;
- for (int i = 0; i < 3; i++) {
- // emit blood particles
- // FIXME: copypaste from above
- bloodvel = 0;
- if (skeleton.free) {
- bloodvel -= DoRotation(skeleton.forward * 10 * scale, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0);
- bloodvel += DoRotation(jointVel(head), ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
- Sprite::MakeSprite(bloodsprite, jointPos(head) * scale + coords, bloodvel, 1, 1, 1, .05, 1);
- Sprite::MakeSprite(bloodflamesprite, jointPos(head) * scale + coords, bloodvel, 1, 1, 1, .3, 1);
- } else {
- bloodvel.z = 10;
- bloodvel = DoRotation(bloodvel, ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
- bloodvel += DoRotation(velocity, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0) * scale;
- Sprite::MakeSprite(bloodsprite, DoRotation((jointPos(head) + jointPos(neck)) / 2, 0, yaw, 0)*scale + coords, bloodvel, 1, 1, 1, .05, 1);
- Sprite::MakeSprite(bloodflamesprite, DoRotation((jointPos(head) + jointPos(neck)) / 2, 0, yaw, 0)*scale + coords, bloodvel, 1, 1, 1, .3, 1);
- }
- }
- }
-
- // weird texture manipulation code follows.
- // looks like this is painting blood onto the character's skin texture
- // FIXME: surely there's a better way
-
- int offsetx = 0, offsety = 0;
- if (which == 225) {
- offsety = Random() % 40;
- offsetx = abs(Random() % 60);
- }
- if (which == 190 || which == 185) {
- offsety = Random() % 40;
- offsetx = abs(Random() % 100) - 20;
- }
- if (which == 175) {
- offsety = Random() % 10;
- offsetx = Random() % 10;
- }
- if (which == 170) {
- offsety = Random() % 20;
- offsetx = Random() % 20;
- }
- if (which == 220 || which == 215) {
- offsetx = 20;
- }
-
-
- int startx = 512;
- int starty = 512;
- int endx = 0;
- int endy = 0;
- GLubyte color;
- if (creature == rabbittype)
- for (i = 0; i < 512; i++) {
- for (j = 0; j < 512; j++) {
- if (bloodText[i * 512 * 3 + j * 3 + 0] <= which + 4 && bloodText[i * 512 * 3 + j * 3 + 0] >= which - 4) {
- if (i < startx) startx = i;
- if (j < starty) starty = j;
- if (i > endx) endx = i;
- if (j > endy) endy = j;
- }
- }
- }
- if (creature == wolftype)
- for (i = 0; i < 512; i++) {
- for (j = 0; j < 512; j++) {
- if (wolfbloodText[i * 512 * 3 + j * 3 + 0] <= which + 4 && wolfbloodText[i * 512 * 3 + j * 3 + 0] >= which - 4) {
- if (i < startx) startx = i;
- if (j < starty) starty = j;
- if (i > endx) endx = i;
- if (j > endy) endy = j;
- }
- }
- }
-
- startx += offsetx;
- endx += offsetx;
- starty += offsety;
- endy += offsety;
-
- if (startx < 0) startx = 0;
- if (starty < 0) starty = 0;
- if (endx > 512 - 1) endx = 512 - 1;
- if (endy > 512 - 1) endy = 512 - 1;
- if (endx < startx) endx = startx;
- if (endy < starty) endy = starty;
-
- startx /= realtexdetail;
- starty /= realtexdetail;
- endx /= realtexdetail;
- endy /= realtexdetail;
-
- int texdetailint = realtexdetail;
- int where;
- if (creature == rabbittype)
- for (i = startx; i < endx; i++) {
- for (j = starty; j < endy; j++) {
- if (bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] <= which + 4 && bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] >= which - 4) {
- color = Random() % 85 + 170;
- where = i * skeleton.skinsize * 3 + j * 3;
- if (skeleton.skinText[where + 0] > color / 2)
- skeleton.skinText[where + 0] = color / 2;
- skeleton.skinText[where + 1] = 0;
- skeleton.skinText[where + 2] = 0;
- }
- }
- }
- if (creature == wolftype)
- for (i = startx; i < endx; i++) {
- for (j = starty; j < endy; j++) {
- if (wolfbloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] <= which + 4 && wolfbloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] >= which - 4) {
- color = Random() % 85 + 170;
- where = i * skeleton.skinsize * 3 + j * 3;
- if (skeleton.skinText[where + 0] > color / 2)
- skeleton.skinText[where + 0] = color / 2;
- skeleton.skinText[where + 1] = 0;
- skeleton.skinText[where + 2] = 0;
- }
- }
- }
- skeleton.drawmodel.textureptr.bind();
- DoMipmaps();
-
- bleedxint = 0;
- bleedyint = 0;
- if (creature == rabbittype)
- while (bloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] > which + 4 || bloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] < which - 4 || bleedxint < 10 || bleedyint < 10 || bleedxint > 500 || bleedyint > 500) {
- bleedxint = abs(Random() % 512);
- bleedyint = abs(Random() % 512);
- }
- if (creature == wolftype)
- while (wolfbloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] > which + 4 || wolfbloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] < which - 4 || bleedxint < 10 || bleedyint < 10 || bleedxint > 500 || bleedyint > 500) {
- bleedxint = abs(Random() % 512);
- bleedyint = abs(Random() % 512);
- }
- bleedy = bleedxint + offsetx;
- bleedx = bleedyint + offsety;
- bleedy /= realtexdetail;
- bleedx /= realtexdetail;
- if (bleedx < 0)
- bleedx = 0;
- if (bleedy < 0)
- bleedy = 0;
- if (bleedx > skeleton.skinsize - 1)
- bleedx = skeleton.skinsize - 1;
- if (bleedy > skeleton.skinsize - 1)
- bleedy = skeleton.skinsize - 1;
- direction = abs(Random() % 2) * 2 - 1;
-
- }
- bleeding = howmuch + (float)abs(Random() % 100) / 200 - .25;
- deathbleeding += bleeding;
- bloodloss += bleeding * 3;
-
- if (tutoriallevel != 1 && aitype != playercontrolled && bloodloss > damagetolerance * 2 / 3 && bloodloss < damagetolerance && creature == rabbittype) {
- if (abs(Random() % 2) == 0) {
- aitype = gethelptype;
- lastseentime = 12;
- } else
- aitype = attacktypecutoff;
- ally = 0;
- }
- if (bleeding > 2)
- bleeding = 2;
-}
-
-/* EFFECT
- * similar to DoBloodBig
- */
-bool Person::DoBloodBigWhere(float howmuch, int which, XYZ where)
-{
- static int i, j;
- static XYZ bloodvel;
- static XYZ startpoint, endpoint, colpoint, movepoint;
- static float rotationpoint;
- static int whichtri;
- static XYZ p1, p2, p3, p0;
- XYZ bary;
- XYZ gxx, gyy;
- float coordsx, coordsy;
- float total;
-
- if (bloodtoggle && decals && tutoriallevel != 1) {
- where -= coords;
- if (!skeleton.free)
- where = DoRotation(where, 0, -yaw, 0);
- //where=scale;
- startpoint = where;
- startpoint.y += 100;
- endpoint = where;
- endpoint.y -= 100;
- movepoint = 0;
- rotationpoint = 0;
- // ray testing for a tri in the character model
- whichtri = skeleton.drawmodel.LineCheck(&startpoint, &endpoint, &colpoint, &movepoint, &rotationpoint);
- if (whichtri != -1) {
- // low level geometry math
- p0 = colpoint;
- p1 = skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[whichtri].vertex[0]];
- p2 = skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[whichtri].vertex[1]];
- p3 = skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[whichtri].vertex[2]];
-
- bary.x = distsq(&p0, &p1);
- bary.y = distsq(&p0, &p2);
- bary.z = distsq(&p0, &p3);
-
- total = bary.x + bary.y + bary.z;
- bary.x /= total;
- bary.y /= total;
- bary.z /= total;
-
- bary.x = 1 - bary.x;
- bary.y = 1 - bary.y;
- bary.z = 1 - bary.z;
-
- total = bary.x + bary.y + bary.z;
- bary.x /= total;
- bary.y /= total;
- bary.z /= total;
-
-
- gxx.x = skeleton.drawmodel.Triangles[whichtri].gx[0];
- gxx.y = skeleton.drawmodel.Triangles[whichtri].gx[1];
- gxx.z = skeleton.drawmodel.Triangles[whichtri].gx[2];
- gyy.x = skeleton.drawmodel.Triangles[whichtri].gy[0];
- gyy.y = skeleton.drawmodel.Triangles[whichtri].gy[1];
- gyy.z = skeleton.drawmodel.Triangles[whichtri].gy[2];
- coordsx = skeleton.drawmodel.Triangles[whichtri].gx[0] * bary.x + skeleton.drawmodel.Triangles[whichtri].gx[1] * bary.y + skeleton.drawmodel.Triangles[whichtri].gx[2] * bary.z;
- coordsy = skeleton.drawmodel.Triangles[whichtri].gy[0] * bary.x + skeleton.drawmodel.Triangles[whichtri].gy[1] * bary.y + skeleton.drawmodel.Triangles[whichtri].gy[2] * bary.z;
-
- if (bleeding <= 0 && spurt) {
- spurt = 0;
- for (int i = 0; i < 3; i++) {
- // emit blood particles
- // FIXME: more copypaste code
- bloodvel = 0;
- if (skeleton.free) {
- bloodvel -= DoRotation(skeleton.forward * 10 * scale, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0);
- bloodvel += DoRotation(jointVel(head), ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
- Sprite::MakeSprite(bloodsprite, jointPos(head) * scale + coords, bloodvel, 1, 1, 1, .05, 1);
- Sprite::MakeSprite(bloodflamesprite, jointPos(head) * scale + coords, bloodvel, 1, 1, 1, .3, 1);
- } else {
- bloodvel.z = 10;
- bloodvel = DoRotation(bloodvel, ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
- bloodvel += DoRotation(velocity, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0) * scale;
- Sprite::MakeSprite(bloodsprite, DoRotation((jointPos(head) + jointPos(neck)) / 2, 0, yaw, 0)*scale + coords, bloodvel, 1, 1, 1, .05, 1);
- Sprite::MakeSprite(bloodflamesprite, DoRotation((jointPos(head) + jointPos(neck)) / 2, 0, yaw, 0)*scale + coords, bloodvel, 1, 1, 1, .3, 1);
- }
- }
- }
-
- // texture manipulation follows
-
- int offsetx = 0, offsety = 0;
- offsetx = (1 + coordsy) * 512 - 291;
- offsety = coordsx * 512 - 437;
-
- int startx = 512;
- int starty = 512;
- int endx = 0;
- int endy = 0;
- GLubyte color;
- if (creature == rabbittype)
- for (i = 0; i < 512; i++) {
- for (j = 0; j < 512; j++) {
- if (bloodText[i * 512 * 3 + j * 3 + 0] <= which + 4 && bloodText[i * 512 * 3 + j * 3 + 0] >= which - 4) {
- if (i < startx) startx = i;
- if (j < starty) starty = j;
- if (i > endx) endx = i;
- if (j > endy) endy = j;
- }
- }
- }
- if (creature == wolftype)
- for (i = 0; i < 512; i++) {
- for (j = 0; j < 512; j++) {
- if (wolfbloodText[i * 512 * 3 + j * 3 + 0] <= which + 4 && wolfbloodText[i * 512 * 3 + j * 3 + 0] >= which - 4) {
- if (i < startx) startx = i;
- if (j < starty) starty = j;
- if (i > endx) endx = i;
- if (j > endy) endy = j;
- }
- }
- }
- startx += offsetx;
- endx += offsetx;
- starty += offsety;
- endy += offsety;
-
- if (startx < 0) startx = 0;
- if (starty < 0) starty = 0;
- if (endx > 512 - 1) endx = 512 - 1;
- if (endy > 512 - 1) endy = 512 - 1;
- if (endx < startx) endx = startx;
- if (endy < starty) endy = starty;
-
- startx /= realtexdetail;
- starty /= realtexdetail;
- endx /= realtexdetail;
- endy /= realtexdetail;
-
- int texdetailint = realtexdetail;
- int where;
- if (creature == rabbittype)
- for (i = startx; i < endx; i++) {
- for (j = starty; j < endy; j++) {
- if (bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] <= which + 4 && bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] >= which - 4) {
- color = Random() % 85 + 170;
- where = i * skeleton.skinsize * 3 + j * 3;
- if (skeleton.skinText[where + 0] > color / 2)
- skeleton.skinText[where + 0] = color / 2;
- skeleton.skinText[where + 1] = 0;
- skeleton.skinText[where + 2] = 0;
- } else if (bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] <= 160 + 4 && bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] >= 160 - 4) {
- color = Random() % 85 + 170;
- where = i * skeleton.skinsize * 3 + j * 3;
- if (skeleton.skinText[where + 0] > color / 2)
- skeleton.skinText[where + 0] = color / 2;
- skeleton.skinText[where + 1] = 0;
- skeleton.skinText[where + 2] = 0;
- }
- }
- }
- if (creature == wolftype)
- for (i = startx; i < endx; i++) {
- for (j = starty; j < endy; j++) {
- if (wolfbloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] <= which + 4 && wolfbloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] >= which - 4) {
- color = Random() % 85 + 170;
- where = i * skeleton.skinsize * 3 + j * 3;
- if (skeleton.skinText[where + 0] > color / 2)
- skeleton.skinText[where + 0] = color / 2;
- skeleton.skinText[where + 1] = 0;
- skeleton.skinText[where + 2] = 0;
- } else if (wolfbloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] <= 160 + 4 && wolfbloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] >= 160 - 4) {
- color = Random() % 85 + 170;
- where = i * skeleton.skinsize * 3 + j * 3;
- if (skeleton.skinText[where + 0] > color / 2)
- skeleton.skinText[where + 0] = color / 2;
- skeleton.skinText[where + 1] = 0;
- skeleton.skinText[where + 2] = 0;
- }
- }
- }
- skeleton.drawmodel.textureptr.bind();
- DoMipmaps();
-
- bleedy = (1 + coordsy) * 512;
- bleedx = coordsx * 512;
- bleedy /= realtexdetail;
- bleedx /= realtexdetail;
- if (bleedx < 0)
- bleedx = 0;
- if (bleedy < 0)
- bleedy = 0;
- if (bleedx > skeleton.skinsize - 1)
- bleedx = skeleton.skinsize - 1;
- if (bleedy > skeleton.skinsize - 1)
- bleedy = skeleton.skinsize - 1;
- direction = abs(Random() % 2) * 2 - 1;
- }
- if (whichtri == -1)
- return 0;
- }
- bleeding = howmuch + (float)abs(Random() % 100) / 200 - .25;
- deathbleeding += bleeding;
- bloodloss += bleeding * 3;
-
- if (tutoriallevel != 1 && aitype != playercontrolled && bloodloss > damagetolerance * 2 / 3 && bloodloss < damagetolerance && creature == rabbittype) {
- if (abs(Random() % 2) == 0) {
- aitype = gethelptype;
- lastseentime = 12;
- } else
- aitype = attacktypecutoff;
- ally = 0;
- }
- if (bleeding > 2)
- bleeding = 2;
- return 1;
-}
-
-
-
-/* EFFECT
- * guessing this performs a reversal
- */
-void Person::Reverse()
-{
- if (!((victim->aitype == playercontrolled
- || hostiletime > 1
- || staggerdelay <= 0)
- && victim->animTarget != jumpupanim
- && victim->animTarget != jumpdownanim
- && (tutoriallevel != 1 || cananger)
- && hostile))
- return;
-
- if (normaldotproduct (victim->facing, victim->coords - coords) > 0
- && (victim->id != 0 || difficulty >= 2)
- && (creature != wolftype || victim->creature == wolftype))
- return;
-
- if (animTarget == sweepanim) {
- animTarget = sweepreversedanim;
- animCurrent = sweepreversedanim;
- victim->animCurrent = sweepreversalanim;
- victim->animTarget = sweepreversalanim;
- }
- if (animTarget == spinkickanim) {
- animTarget = spinkickreversedanim;
- animCurrent = spinkickreversedanim;
- victim->animCurrent = spinkickreversalanim;
- victim->animTarget = spinkickreversalanim;
- }
- if (animTarget == upunchanim || animTarget == rabbittacklinganim) {
- if (animTarget == rabbittacklinganim) {
- frameCurrent = 6;
- frameTarget = 7;
- victim->frameCurrent = 6;
- victim->frameTarget = 7;
- }
- animTarget = upunchreversedanim;
- animCurrent = upunchreversedanim;
- victim->animCurrent = upunchreversalanim;
- victim->animTarget = upunchreversalanim;
- }
- if (animTarget == staffhitanim && distsq(&victim->coords, &coords) < 2 && ((victim->id == 0 && victim->crouchkeydown) || Random() % 4 == 0)) {
- if (victim->weaponactive != -1) {
- victim->throwtogglekeydown = 1;
- XYZ tempVelocity = victim->velocity * .2;
- if (tempVelocity.x == 0)
- tempVelocity.x = .1;
- weapons[victim->weaponids[0]].drop(tempVelocity, tempVelocity, false);
- victim->num_weapons--;
- if (victim->num_weapons) {
- victim->weaponids[0] = victim->weaponids[victim->num_weapons];
- if (victim->weaponstuck == victim->num_weapons)
- victim->weaponstuck = 0;
- }
-
- victim->weaponactive = -1;
- for (unsigned j = 0; j < Person::players.size(); j++) {
- Person::players[j]->wentforweapon = 0;
- }
- }
-
- animTarget = staffhitreversedanim;
- animCurrent = staffhitreversedanim;
- victim->animCurrent = staffhitreversalanim;
- victim->animTarget = staffhitreversalanim;
- }
- if (animTarget == staffspinhitanim && distsq(&victim->coords, &coords) < 2 && ((victim->id == 0 && victim->crouchkeydown) || Random() % 2 == 0)) {
- if (victim->weaponactive != -1) {
- victim->throwtogglekeydown = 1;
- XYZ tempVelocity = victim->velocity * .2;
- if (tempVelocity.x == 0)
- tempVelocity.x = .1;
- weapons[victim->weaponids[0]].drop(tempVelocity, tempVelocity, false);
- victim->num_weapons--;
- if (victim->num_weapons) {
- victim->weaponids[0] = victim->weaponids[victim->num_weapons];
- if (victim->weaponstuck == victim->num_weapons)
- victim->weaponstuck = 0;
- }
-
- victim->weaponactive = -1;
- for (unsigned j = 0; j < Person::players.size(); j++) {
- Person::players[j]->wentforweapon = 0;
- }
- }
- animTarget = staffspinhitreversedanim;
- animCurrent = staffspinhitreversedanim;
- victim->animCurrent = staffspinhitreversalanim;
- victim->animTarget = staffspinhitreversalanim;
- }
- if (animTarget == swordslashanim && distsq(&victim->coords, &coords) < 2 && ((victim->id == 0 && victim->crouchkeydown) || Random() % 4 == 0)) {
- if (victim->weaponactive != -1) {
- victim->throwtogglekeydown = 1;
- XYZ tempVelocity = victim->velocity * .2;
- if (tempVelocity.x == 0)
- tempVelocity.x = .1;
- weapons[victim->weaponids[0]].drop(tempVelocity, tempVelocity, false);
- victim->num_weapons--;
- if (victim->num_weapons) {
- victim->weaponids[0] = victim->weaponids[victim->num_weapons];
- if (victim->weaponstuck == victim->num_weapons)
- victim->weaponstuck = 0;
- }
-
- victim->weaponactive = -1;
- for (unsigned j = 0; j < Person::players.size(); j++) {
- Person::players[j]->wentforweapon = 0;
- }
- }
- animTarget = swordslashreversedanim;
- animCurrent = swordslashreversedanim;
- victim->animCurrent = swordslashreversalanim;
- victim->animTarget = swordslashreversalanim;
- }
- if (animTarget == knifeslashstartanim && distsq(&victim->coords, &coords) < 2 && (victim->id == 0 || Random() % 4 == 0)) {
- if (victim->weaponactive != -1) {
- victim->throwtogglekeydown = 1;
- XYZ tempVelocity = victim->velocity * .2;
- if (tempVelocity.x == 0)
- tempVelocity.x = .1;
- weapons[victim->weaponids[0]].drop(tempVelocity, tempVelocity, false);
- victim->num_weapons--;
- if (victim->num_weapons) {
- victim->weaponids[0] = victim->weaponids[victim->num_weapons];
- if (victim->weaponstuck == victim->num_weapons)
- victim->weaponstuck = 0;
- }
-
- victim->weaponactive = -1;
- for (unsigned j = 0; j < Person::players.size(); j++) {
- Person::players[j]->wentforweapon = 0;
- }
- }
- animTarget = knifeslashreversedanim;
- animCurrent = knifeslashreversedanim;
- victim->animCurrent = knifeslashreversalanim;
- victim->animTarget = knifeslashreversalanim;
- }
- if (animTarget != knifeslashstartanim && animTarget != staffhitanim && animTarget != staffspinhitanim && animTarget != winduppunchanim && animTarget != wolfslapanim && animTarget != swordslashanim) {
- victim->targettilt2 = targettilt2;
- victim->frameCurrent = frameCurrent;
- victim->frameTarget = frameTarget;
- victim->target = target;
- victim->velocity = 0;
- victim->oldcoords = victim->coords;
- victim->coords = coords;
- victim->targetyaw = targetyaw;
- victim->yaw = targetyaw;
- victim->victim = this->shared_from_this();
- }
- if (animTarget == winduppunchanim) {
- animTarget = winduppunchblockedanim;
- victim->animTarget = blockhighleftanim;
- victim->frameTarget = 1;
- victim->target = .5;
- victim->victim = this->shared_from_this();
- victim->targetyaw = targetyaw + 180;
- }
- if (animTarget == wolfslapanim) {
- animTarget = winduppunchblockedanim;
- victim->animTarget = blockhighleftanim;
- victim->frameTarget = 1;
- victim->target = .5;
- victim->victim = this->shared_from_this();
- victim->targetyaw = targetyaw + 180;
- }
- if ((animTarget == swordslashanim || animTarget == staffhitanim || animTarget == staffspinhitanim) && victim->weaponactive != -1) {
- animTarget = swordslashparriedanim;
- parriedrecently = .4;
- victim->parriedrecently = 0;
- victim->animTarget = swordslashparryanim;
- victim->frameTarget = 1;
- victim->target = .5;
- victim->victim = this->shared_from_this();
- victim->targetyaw = targetyaw + 180;
-
- if (abs(Random() % 20) == 0 || weapons[victim->weaponids[victim->weaponactive]].getType() == knife) {
- if (victim->weaponactive != -1) {
- if (weapons[victim->weaponids[0]].getType() == staff || weapons[weaponids[0]].getType() == staff) {
- if (weapons[victim->weaponids[0]].getType() == staff)
- weapons[victim->weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
- if (weapons[weaponids[0]].getType() == staff)
- weapons[weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
- emit_sound_at(swordstaffsound, victim->coords);
- } else {
- emit_sound_at(metalhitsound, victim->coords);
- }
- }
- XYZ aim;
- victim->Puff(righthand);
- victim->target = 0;
- victim->frameTarget = 0;
- victim->animTarget = staggerbackhighanim;
- victim->targetyaw = targetyaw + 180;
- victim->target = 0;
- aim = DoRotation(facing, 0, 90, 0) * 21;
- aim.y += 7;
- weapons[victim->weaponids[0]].drop(aim * -.2, aim);
- victim->num_weapons--;
- if (victim->num_weapons) {
- victim->weaponids[0] = victim->weaponids[num_weapons];
- if (victim->weaponstuck == victim->num_weapons)
- victim->weaponstuck = 0;
- }
- victim->weaponactive = -1;
- for (unsigned i = 0; i < Person::players.size(); i++) {
- Person::players[i]->wentforweapon = 0;
- }
- }
-
- if (abs(Random() % 20) == 0) {
- if (weaponactive != -1) {
- if (weapons[victim->weaponids[0]].getType() == staff || weapons[weaponids[0]].getType() == staff) {
- if (weapons[victim->weaponids[0]].getType() == staff)
- weapons[victim->weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
- if (weapons[weaponids[0]].getType() == staff)
- weapons[weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
-
- emit_sound_at(swordstaffsound, coords);
- } else {
- emit_sound_at(metalhitsound, coords);
- }
- }
-
- XYZ aim;
- Puff(righthand);
- target = 0;
- frameTarget = 0;
- animTarget = staggerbackhighanim;
- targetyaw = targetyaw + 180;
- target = 0;
- aim = DoRotation(facing, 0, 90, 0) * 21;
- aim.y += 7;
- weapons[victim->weaponids[0]].drop(aim * -.2, aim);
- num_weapons--;
- if (num_weapons) {
- weaponids[0] = weaponids[num_weapons];
- if (weaponstuck == num_weapons)
- weaponstuck = 0;
- }
- weaponactive = -1;
- for (unsigned i = 0; i < Person::players.size(); i++) {
- Person::players[i]->wentforweapon = 0;
- }
-
-
- }
- }
- if (hasvictim)
- if (animTarget == knifeslashstartanim || animTarget == swordslashanim || animTarget == staffhitanim || animTarget == staffspinhitanim) {
- if ((animTarget != staffhitanim && animTarget != staffspinhitanim) || distsq(&coords, &victim->coords) > .2) {
- victim->animTarget = dodgebackanim;
- victim->frameTarget = 0;
- victim->target = 0;
-
- XYZ rotatetarget;
- rotatetarget = coords - victim->coords;
- Normalise(&rotatetarget);
- victim->targetyaw = -asin(0 - rotatetarget.x);
- victim->targetyaw *= 360 / 6.28;
- if (rotatetarget.z < 0)
- victim->targetyaw = 180 - victim->targetyaw;
-
- victim->targettilt2 = -asin(rotatetarget.y) * 360 / 6.28; //*-70;
-
- victim->lastattack3 = victim->lastattack2;
- victim->lastattack2 = victim->lastattack;
- victim->lastattack = victim->animTarget;
- } else {
- victim->animTarget = sweepanim;
- victim->frameTarget = 0;
- victim->target = 0;
-
- XYZ rotatetarget;
- rotatetarget = coords - victim->coords;
- Normalise(&rotatetarget);
- victim->targetyaw = -asin(0 - rotatetarget.x);
- victim->targetyaw *= 360 / 6.28;
- if (rotatetarget.z < 0)
- victim->targetyaw = 180 - victim->targetyaw;
-
- victim->targettilt2 = -asin(rotatetarget.y) * 360 / 6.28; //*-70;
-
- victim->lastattack3 = victim->lastattack2;
- victim->lastattack2 = victim->lastattack;
- victim->lastattack = victim->animTarget;
- }
- }
-
- velocity = 0;
- victim->velocity = 0;
-
- if (aitype != playercontrolled) {
- feint = 0;
- if (escapednum < 2) {
- int chances = ((difficulty == 2) ? 3 : ((difficulty == 1) ? 5 : 10));
- if ((Random() % chances) == 0) {
- feint = 1;
- }
- }
- }
-
- if (victim->id == 0 && Animation::animations[victim->animTarget].attack == reversal)
- numreversals++;
-}
-
-/* EFFECT
- * get hurt
- */
-void Person::DoDamage(float howmuch)
-{
- // subtract health (temporary?)
- if (tutoriallevel != 1)
- damage += howmuch / power;
- // stats?
- if (id != 0)
- damagedealt += howmuch / power;
- if (id == 0)
- damagetaken += howmuch / power;
-
- // reset bonuses
- if (id == 0 && (bonus == solidhit || bonus == twoxcombo || bonus == threexcombo || bonus == fourxcombo || bonus == megacombo))
- bonus = 0;
- // subtract health
- if (tutoriallevel != 1)
- permanentdamage += howmuch / 2 / power;
- if (tutoriallevel != 1)
- superpermanentdamage += howmuch / 4 / power;
- // visual effects
- if (permanentdamage > damagetolerance / 2 && permanentdamage - howmuch < damagetolerance / 2 && Random() % 2)
- DoBlood(1, 255);
- if ((permanentdamage > damagetolerance * .8 && Random() % 2 && !deathbleeding) || spurt)
- DoBlood(1, 255);
- spurt = 0;
- if (id == 0)
- camerashake += howmuch / 100;
- if (id == 0 && ((howmuch > 50 && damage > damagetolerance / 2)))
- blackout = damage / damagetolerance;
- if (blackout > 1)
- blackout = 1;
-
- // cancel attack?
- if (aitype == passivetype && damage < damagetolerance && ((tutoriallevel != 1 || cananger) && hostile))
- aitype = attacktypecutoff;
- if (tutoriallevel != 1 && aitype != playercontrolled && damage < damagetolerance && damage > damagetolerance * 2 / 3 && creature == rabbittype) {
- if (abs(Random() % 2) == 0) {
- aitype = gethelptype;
- lastseentime = 12;
- } else
- aitype = attacktypecutoff;
- ally = 0;
- }
-
- if (howmuch > damagetolerance * 50 && skeleton.free != 2) {
- XYZ flatvelocity2;
- XYZ flatfacing2;
- for (int i = 0; i < skeleton.joints.size(); i++) {
- if (skeleton.free) {
- flatvelocity2 = skeleton.joints[i].velocity;
- flatfacing2 = skeleton.joints[i].position * scale + coords;
- } else {
- flatvelocity2 = velocity;
- flatfacing2 = DoRotation(DoRotation(DoRotation(skeleton.joints[i].position, 0, 0, tilt), tilt2, 0, 0), 0, yaw, 0) * scale + coords;
- }
- flatvelocity2.x += (float)(abs(Random() % 100) - 50) / 10;
- flatvelocity2.y += (float)(abs(Random() % 100) - 50) / 10;
- flatvelocity2.z += (float)(abs(Random() % 100) - 50) / 10;
- Sprite::MakeSprite(bloodflamesprite, flatfacing2, flatvelocity2, 1, 1, 1, 3, 1);
- Sprite::MakeSprite(bloodsprite, flatfacing2, flatvelocity2, 1, 1, 1, .4, 1);
- Sprite::MakeSprite(cloudsprite, flatfacing2, flatvelocity2 * 0, .6, 0, 0, 1, .5);
- }
-
- emit_sound_at(splattersound, coords);
-
- skeleton.free = 2;
- DoDamage(10000);
- RagDoll(0);
- if (!dead && creature == wolftype) {
- award_bonus(0, Wolfbonus);
- }
- dead = 2;
- coords = 20;
- }
-
- // play sounds
- if (tutoriallevel != 1 || id == 0)
- if (speechdelay <= 0 && !dead && aitype != playercontrolled) {
- int whichsound = -1;
-
- if (creature == wolftype) {
- int i = abs(Random() % 2);
- if (i == 0)
- whichsound = snarlsound;
- if (i == 1)
- whichsound = snarl2sound;
- }
- if (creature == rabbittype) {
- int i = abs(Random() % 2);
- if (i == 0)
- whichsound = rabbitpainsound;
- if (i == 1 && damage > damagetolerance)
- whichsound = rabbitpain1sound;
- }
-
- if (whichsound != -1) {
- emit_sound_at(whichsound, coords);
- addEnvSound(coords);
- }
- }
- speechdelay = .3;
-}
-
-/* EFFECT
- * calculate/animate head facing direction?
- */
-void Person::DoHead()
-{
- static XYZ rotatearound;
- static XYZ facing;
- static float lookspeed = 500;
-
- if (!freeze && !winfreeze) {
-
- //head facing
- targetheadyaw = (float)((int)((0 - yaw - targetheadyaw + 180) * 100) % 36000) / 100;
- targetheadpitch = (float)((int)(targetheadpitch * 100) % 36000) / 100;
-
- while (targetheadyaw > 180)targetheadyaw -= 360;
- while (targetheadyaw < -180)targetheadyaw += 360;
-
- if (targetheadyaw > 160)
- targetheadpitch = targetheadpitch * -1;
- if (targetheadyaw < -160)
- targetheadpitch = targetheadpitch * -1;
- if (targetheadyaw > 160)
- targetheadyaw = targetheadyaw - 180;
- if (targetheadyaw < -160)
- targetheadyaw = targetheadyaw + 180;
-
- if (targetheadpitch > 120)
- targetheadpitch = 120;
- if (targetheadpitch < -120)
- targetheadpitch = -120;
- if (targetheadyaw > 120)
- targetheadyaw = 120;
- if (targetheadyaw < -120)
- targetheadyaw = -120;
-
- if (!isIdle())
- targetheadpitch = 0;
- if (isIdle()) {
- if (targetheadyaw > 80)
- targetheadyaw = 80;
- if (targetheadyaw < -80)
- targetheadyaw = -80;
- if (targetheadpitch > 50)
- targetheadpitch = 50;
- if (targetheadpitch < -50)
- targetheadpitch = -50;
- }
-
- if (abs(headyaw - targetheadyaw) < multiplier * lookspeed)
- headyaw = targetheadyaw;
- else if (headyaw > targetheadyaw) {
- headyaw -= multiplier * lookspeed;
- } else if (headyaw < targetheadyaw) {
- headyaw += multiplier * lookspeed;
- }
-
- if (abs(headpitch - targetheadpitch) < multiplier * lookspeed / 2)
- headpitch = targetheadpitch;
- else if (headpitch > targetheadpitch) {
- headpitch -= multiplier * lookspeed / 2;
- } else if (headpitch < targetheadpitch) {
- headpitch += multiplier * lookspeed / 2;
- }
-
- rotatearound = jointPos(neck);
- jointPos(head) = rotatearound + DoRotation(jointPos(head) - rotatearound, headpitch, 0, 0);
-
- facing = 0;
- facing.z = -1;
- if (animTarget != bounceidleanim && animTarget != fightidleanim && animTarget != wolfidle && animTarget != knifefightidleanim && animTarget != drawrightanim && animTarget != drawleftanim && animTarget != walkanim) {
- facing = DoRotation(facing, headpitch * .4, 0, 0);
- facing = DoRotation(facing, 0, headyaw * .4, 0);
- }
-
- if (animTarget == bounceidleanim || animTarget == fightidleanim || animTarget == wolfidle || animTarget == knifefightidleanim || animTarget == drawrightanim || animTarget == drawleftanim) {
- facing = DoRotation(facing, headpitch * .8, 0, 0);
- facing = DoRotation(facing, 0, headyaw * .8, 0);
- }
-
- if (animTarget == walkanim) {
- facing = DoRotation(facing, headpitch * .6, 0, 0);
- facing = DoRotation(facing, 0, headyaw * .6, 0);
- }
-
- skeleton.specialforward[0] = facing;
- //skeleton.specialforward[0]=DoRotation(facing,0,yaw,0);
- for (int i = 0; i < skeleton.muscles.size(); i++) {
- if (skeleton.muscles[i].visible && (skeleton.muscles[i].parent1->label == head || skeleton.muscles[i].parent2->label == head)) {
- skeleton.FindRotationMuscle(i, animTarget);
- }
- }
- }
-}
-
-/* EFFECT
- * ragdolls character?
- */
-void Person::RagDoll(bool checkcollision)
-{
- static XYZ change;
- static int l, i, j;
- static float speed;
- if (!skeleton.free) {
- if (id == 0)
- numfalls++;
- if (id == 0 && isFlip())
- numflipfail++;
-
- escapednum = 0;
-
- facing = 0;
- facing.z = 1;
- facing = DoRotation(facing, 0, yaw, 0);
-
- skeleton.freetime = 0;
-
- skeleton.longdead = 0;
-
- skeleton.free = 1;
- skeleton.broken = 0;
- skeleton.spinny = 1;
- freefall = 1;
- skeleton.freefall = 1;
-
- if (!isnormal(velocity.x)) velocity.x = 0;
- if (!isnormal(velocity.y)) velocity.y = 0;
- if (!isnormal(velocity.z)) velocity.z = 0;
- if (!isnormal(yaw)) yaw = 0;
- if (!isnormal(coords.x)) coords = 0;
- if (!isnormal(tilt)) tilt = 0;
- if (!isnormal(tilt2)) tilt2 = 0;
-
- for (int i = 0; i < skeleton.joints.size(); i++) {
- skeleton.joints[i].delay = 0;
- skeleton.joints[i].locked = 0;
- skeleton.joints[i].position = DoRotation(DoRotation(DoRotation(skeleton.joints[i].position, 0, 0, tilt), tilt2, 0, 0), 0, yaw, 0);
- if (!isnormal(skeleton.joints[i].position.x)) skeleton.joints[i].position = DoRotation(skeleton.joints[i].position, 0, yaw, 0);
- if (!isnormal(skeleton.joints[i].position.x)) skeleton.joints[i].position = coords;
- skeleton.joints[i].position.y += .1;
- skeleton.joints[i].oldposition = skeleton.joints[i].position;
- skeleton.joints[i].realoldposition = skeleton.joints[i].position * scale + coords;
- }
-
- for (int i = 0; i < skeleton.joints.size(); i++) {
- skeleton.joints[i].velocity = 0;
- skeleton.joints[i].velchange = 0;
- }
- skeleton.DoConstraints(&coords, &scale);
- 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 = targetFrame().speed * 2;
- if (currentFrame().speed > targetFrame().speed) {
- speed = currentFrame().speed * 2;
- }
- if (transspeed)
- speed = transspeed * 2;
-
- speed *= speedmult;
-
- for (int i = 0; i < skeleton.joints.size(); i++) {
- 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((targetFrame().joints[i].position - currentFrame().joints[i].position) * 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;
- change.y = (float)(Random() % 100) / 100;
- change.z = (float)(Random() % 100) / 100;
- skeleton.joints[i].velocity += change;
- skeleton.joints[abs(Random() % skeleton.joints.size())].velocity -= change;
-
- change.x = (float)(Random() % 100) / 100;
- change.y = (float)(Random() % 100) / 100;
- change.z = (float)(Random() % 100) / 100;
- skeleton.joints[i].velchange += change;
- skeleton.joints[abs(Random() % skeleton.joints.size())].velchange -= change;
- }
-
- if (checkcollision) {
- XYZ average;
- XYZ lowpoint;
- XYZ colpoint;
- int howmany;
- average = 0;
- howmany = 0;
- for (j = 0; j < skeleton.joints.size(); j++) {
- average += skeleton.joints[j].position;
- howmany++;
- }
- average /= howmany;
- coords += average * scale;
- for (j = 0; j < skeleton.joints.size(); j++) {
- skeleton.joints[j].position -= average;
- }
-
- whichpatchx = coords.x / (terrain.size / subdivision * terrain.scale);
- whichpatchz = coords.z / (terrain.size / subdivision * terrain.scale);
- if (terrain.patchobjectnum[whichpatchx][whichpatchz])
- for (l = 0; l < terrain.patchobjectnum[whichpatchx][whichpatchz]; l++) {
- i = terrain.patchobjects[whichpatchx][whichpatchz][l];
- lowpoint = coords;
- lowpoint.y += 1;
- if (SphereCheck(&lowpoint, 3, &colpoint, &objects.position[i], &objects.yaw[i], &objects.model[i]) != -1) {
- coords.x = lowpoint.x;
- coords.z = lowpoint.z;
- }
- }
- }
-
- yaw = 0;
- updatedelay = 0;
-
- velocity = 0;
- for (int i = 0; i < skeleton.joints.size(); i++) {
- velocity += skeleton.joints[i].velocity * scale;
- }
- velocity /= skeleton.joints.size();
-
- // drop weapon
- if (Random() % 2 == 0) {
- if (weaponactive != -1 && animTarget != rabbitkickanim && num_weapons > 0) {
- weapons[weaponids[0]].drop(jointVel(righthand) * scale * -.3, jointVel(righthand) * scale);
- weapons[weaponids[0]].velocity.x += .01;
- num_weapons--;
- if (num_weapons) {
- weaponids[0] = weaponids[num_weapons];
- if (weaponstuck == num_weapons)
- weaponstuck = 0;
- }
- weaponactive = -1;
- for (unsigned i = 0; i < Person::players.size(); i++) {
- Person::players[i]->wentforweapon = 0;
- }
- }
- }
-
- animTarget = bounceidleanim;
- animCurrent = bounceidleanim;
- frameTarget = 0;
- frameCurrent = 0;
- }
-}
-
-
-
-/* EFFECT
- */
-void Person::FootLand(bodypart whichfoot, float opacity)
-{
- if ((whichfoot != leftfoot) && (whichfoot != rightfoot)) {
- cerr << "FootLand called on wrong bodypart" << endl;
- return;
- }
- static XYZ terrainlight;
- static XYZ footvel, footpoint;
- if (opacity >= 1 || skiddelay <= 0) {
- if (opacity > 1) {
- footvel = 0;
- footpoint = DoRotation(jointPos(whichfoot), 0, yaw, 0) * scale + coords;
- if (distsq(&footpoint, &viewer))
- Sprite::MakeSprite(cloudsprite, footpoint, footvel, 1, 1, 1, .5, .2 * opacity);
- } else if (onterrain && terrain.getOpacity(coords.x, coords.z) < .2) {
- footvel = velocity / 5;
- if (footvel.y < .8)
- footvel.y = .8;
- footpoint = DoRotation(jointPos(whichfoot), 0, yaw, 0) * scale + coords;
- footpoint.y = terrain.getHeight(footpoint.x, footpoint.z);
- terrainlight = terrain.getLighting(footpoint.x, footpoint.z);
- if (distsq(&footpoint, &viewer) < viewdistance * viewdistance / 4) {
- if (environment == snowyenvironment) {
- Sprite::MakeSprite(cloudsprite, footpoint, footvel * .6, terrainlight.x, terrainlight.y, terrainlight.z, .5, .7 * opacity);
- if (detail == 2) {
- terrain.MakeDecal(footprintdecal, footpoint, .2, 1 * opacity, yaw);
- }
- } else if (environment == grassyenvironment) {
- Sprite::MakeSprite(cloudsprite, footpoint, footvel * .6, terrainlight.x * 90 / 255, terrainlight.y * 70 / 255, terrainlight.z * 8 / 255, .5, .5 * opacity);
- } else if (environment == desertenvironment) {
- Sprite::MakeSprite(cloudsprite, footpoint, footvel * .6, terrainlight.x * 190 / 255, terrainlight.y * 170 / 255, terrainlight.z * 108 / 255, .5, .7 * opacity);
- if (detail == 2) {
- terrain.MakeDecal(footprintdecal, footpoint, .2, .25 * opacity, yaw);
- }
- }
- }
- } else if (isLanding() || (animTarget == jumpupanim) || isLandhard()) {
- footvel = velocity / 5;
- if (footvel.y < .8)
- footvel.y = .8;
- footpoint = DoRotation(jointPos(whichfoot), 0, yaw, 0) * scale + coords;
- if (distsq(&footpoint, &viewer) < viewdistance * viewdistance / 4) {
- Sprite::MakeSprite(cloudsprite, footpoint, footvel * .6, 1, 1, 1, .5, .2 * opacity);
- }
- }
- }
-}
-
-/* EFFECT
- * make a puff effect at a body part (dust effect?)
- */
-void Person::Puff(int whichlabel)
-{
- static XYZ footvel, footpoint;
-
- footvel = 0;
- footpoint = DoRotation(jointPos(whichlabel), 0, yaw, 0) * scale + coords;
- Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 1, 1, .9, .3);
-}
-
-/* EFFECT
- * I think I added this in an attempt to clean up code
- */
-void Person::setAnimation(int animation)
-{
- animTarget = animation;
- frameTarget = 0;
- target = 0;
-}
-
-/* EFFECT
- * MONSTER
- * TODO: ???
- */
-void Person::DoAnimations()
-{
- if (!skeleton.free) {
- static float oldtarget;
-
- if (isIdle() && animCurrent != getIdle())
- normalsupdatedelay = 0;
-
- if (animTarget == tempanim || animCurrent == tempanim) {
- Animation::animations[tempanim] = tempanimation;
- }
- if (animTarget == jumpupanim || animTarget == jumpdownanim || isFlip()) {
- float gLoc[3];
- float vel[3];
- gLoc[0] = coords.x;
- gLoc[1] = coords.y;
- gLoc[2] = coords.z;
- vel[0] = velocity.x;
- vel[1] = velocity.y;
- vel[2] = velocity.z;
-
- if (id == 0) {
- OPENAL_3D_SetAttributes(channels[whooshsound], gLoc, vel);
- OPENAL_SetVolume(channels[whooshsound], 64 * findLength(&velocity) / 5);
- }
- if (((velocity.y < -15) || (crouchkeydown && velocity.y < -8)) && abs(velocity.y) * 4 > fast_sqrt(velocity.x * velocity.x * velocity.z * velocity.z))
- landhard = 1;
- if (!crouchkeydown && velocity.y >= -15)
- landhard = 0;
- }
- if ((animCurrent == jumpupanim || animTarget == jumpdownanim)/*&&velocity.y<40*/ && !isFlip() && (!isLanding() && !isLandhard()) && ((crouchkeydown && !crouchtogglekeydown))) {
- XYZ targfacing;
- targfacing = 0;
- targfacing.z = 1;
-
- targfacing = DoRotation(targfacing, 0, targetyaw, 0);
-
- if (normaldotproduct(targfacing, velocity) >= -.3)
- animTarget = flipanim;
- else
- animTarget = backflipanim;
- crouchtogglekeydown = 1;
- frameTarget = 0;
- target = 0;
-
- if (id == 0)
- numflipped++;
- }
-
- 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::animations[animTarget].attack == reversed && aitype == playercontrolled && (escapednum < 2 || reversaltrain))
- feint = 1;
- if (!isFlip())
- crouchtogglekeydown = 1;
- }
-
-
- if (Animation::animations[animTarget].attack || animCurrent == getupfrombackanim || animCurrent == getupfromfrontanim) {
- if (detail)
- normalsupdatedelay = 0;
- }
-
- if (target >= 1) {
- if (animTarget == rollanim && frameTarget == 3 && onfire) {
- onfire = 0;
- emit_sound_at(fireendsound, coords);
- pause_sound(stream_firesound);
- deathbleeding = 0;
- }
-
- if (animTarget == rabbittacklinganim && frameTarget == 1) {
- if (victim->aitype == attacktypecutoff && victim->stunned <= 0 && victim->surprised <= 0 && victim->id != 0)
- Reverse();
- if (animTarget == rabbittacklinganim && frameTarget == 1 && !victim->isCrouch() && victim->animTarget != backhandspringanim) {
- if (normaldotproduct(victim->facing, facing) > 0)
- victim->animTarget = rabbittackledbackanim;
- else
- victim->animTarget = rabbittackledfrontanim;
- victim->frameTarget = 2;
- victim->target = 0;
- victim->yaw = yaw;
- victim->targetyaw = yaw;
- if (victim->aitype == gethelptype)
- victim->DoDamage(victim->damagetolerance - victim->damage);
- //victim->DoDamage(30);
- if (creature == wolftype) {
- DoBloodBig(0, 255);
- emit_sound_at(clawslicesound, victim->coords);
- victim->spurt = 1;
- victim->DoBloodBig(1 / victim->armorhead, 210);
- }
- award_bonus(id, TackleBonus,
- victim->aitype == gethelptype ? 50 : 0);
- }
- }
-
- if (!drawtogglekeydown && drawkeydown && (weaponactive == -1 || num_weapons == 1) && (targetFrame().label || (animTarget != animCurrent && animCurrent == rollanim)) && num_weapons > 0 && creature != wolftype) {
- if (weapons[weaponids[0]].getType() == knife) {
- if (weaponactive == -1)
- weaponactive = 0;
- else if (weaponactive == 0)
- weaponactive = -1;
-
- if (weaponactive == -1) {
- emit_sound_at(knifesheathesound, coords);
- }
- if (weaponactive != -1) {
- emit_sound_at(knifedrawsound, coords, 128);
- }
- }
- drawtogglekeydown = 1;
- }
- //Footstep sounds
- if (tutoriallevel != 1 || id == 0)
- if ((targetFrame().label && (targetFrame().label < 5 || targetFrame().label == 8))) {
- int whichsound;
- if (onterrain) {
- if (terrain.getOpacity(coords.x, coords.z) < .2) {
- if (targetFrame().label == 1)
- whichsound = footstepsound;
- else
- whichsound = footstepsound2;
- if (targetFrame().label == 1)
- FootLand(leftfoot, 1);
- if (targetFrame().label == 2)
- FootLand(rightfoot, 1);
- if (targetFrame().label == 3 && isRun()) {
- FootLand(rightfoot, 1);
- FootLand(leftfoot, 1);
- }
-
- }
- if (terrain.getOpacity(coords.x, coords.z) >= .2) {
- if (targetFrame().label == 1)
- whichsound = footstepsound3;
- else
- whichsound = footstepsound4;
- }
- }
- if (!onterrain) {
- if (targetFrame().label == 1)
- whichsound = footstepsound3;
- else
- whichsound = footstepsound4;
- }
- if (targetFrame().label == 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;
- if (r == 1)
- whichsound = midwhooshsound;
- if (r == 2)
- whichsound = highwhooshsound;
- }
- if (Animation::animations[animTarget].attack == neutral)
- whichsound = movewhooshsound;
- } else if (targetFrame().label == 4)
- whichsound = knifeswishsound;
- if (targetFrame().label == 8 && tutoriallevel != 1)
- whichsound = landsound2;
-
- emit_sound_at(whichsound, coords, 256.);
-
- if (id == 0)
- if (whichsound == footstepsound || whichsound == footstepsound2 || whichsound == footstepsound3 || whichsound == footstepsound4) {
- if (animTarget == wolfrunninganim || animTarget == rabbitrunninganim) {
- addEnvSound(coords, 15);
- } else {
- addEnvSound(coords, 6);
- }
- }
-
- if (targetFrame().label == 3) {
- whichsound--;
- emit_sound_at(whichsound, coords, 128.);
- }
- }
-
- //Combat sounds
- if (tutoriallevel != 1 || id == 0)
- if (speechdelay <= 0)
- if (animTarget != crouchstabanim && animTarget != swordgroundstabanim && animTarget != staffgroundsmashanim)
- if ((targetFrame().label && (targetFrame().label < 5 || targetFrame().label == 8))) {
- int whichsound = -1;
- if (targetFrame().label == 4 && aitype != playercontrolled) {
- if (Animation::animations[animTarget].attack != neutral) {
- unsigned r = abs(Random() % 4);
- if (creature == rabbittype) {
- if (r == 0) whichsound = rabbitattacksound;
- if (r == 1) whichsound = rabbitattack2sound;
- if (r == 2) whichsound = rabbitattack3sound;
- if (r == 3) whichsound = rabbitattack4sound;
- }
- if (creature == wolftype) {
- if (r == 0) whichsound = barksound;
- if (r == 1) whichsound = bark2sound;
- if (r == 2) whichsound = bark3sound;
- if (r == 3) whichsound = barkgrowlsound;
- }
- speechdelay = .3;
- }
- }
-
- if (whichsound != -1) {
- emit_sound_at(whichsound, coords);
- }
- }
-
-
-
- if ((!wasLanding() && !wasLandhard()) && animCurrent != getIdle() && (isLanding() || isLandhard())) {
- FootLand(leftfoot, 1);
- FootLand(rightfoot, 1);
- }
-
- transspeed = 0;
- currentoffset = targetoffset;
- frameTarget = frameCurrent;
- animCurrent = animTarget;
- frameTarget++;
-
- if (animTarget == removeknifeanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
- for (unsigned i = 0; i < weapons.size(); i++) {
- if (weapons[i].owner == -1)
- if (distsqflat(&coords, &weapons[i].position) < 4 && weaponactive == -1) {
- if (distsq(&coords, &weapons[i].position) >= 1) {
- if (weapons[i].getType() != staff) {
- emit_sound_at(knifedrawsound, coords, 128.);
- }
-
- takeWeapon(i);
- }
- }
- }
- }
-
- if (animTarget == crouchremoveknifeanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
- for (unsigned i = 0; i < weapons.size(); i++) {
- bool willwork = true;
- if (weapons[i].owner != -1)
- if (Person::players[weapons[i].owner]->weaponstuck != -1)
- if (Person::players[weapons[i].owner]->weaponids[Person::players[weapons[i].owner]->weaponstuck] == int(i))
- if (Person::players[weapons[i].owner]->num_weapons > 1)
- willwork = 0;
- if ((weapons[i].owner == -1) || (hasvictim && (weapons[i].owner == int(victim->id)) && victim->skeleton.free))
- if (willwork && distsqflat(&coords, &weapons[i].position) < 3 && weaponactive == -1) {
- if (distsq(&coords, &weapons[i].position) < 1 || hasvictim) {
- bool fleshstuck = false;
- if (weapons[i].owner != -1)
- if (victim->weaponstuck != -1) {
- if (victim->weaponids[victim->weaponstuck] == int(i)) {
- fleshstuck = true;
- }
- }
- if (fleshstuck) {
- emit_sound_at(fleshstabremovesound, coords, 128.);
- } else {
- if (weapons[i].getType() != staff) {
- emit_sound_at(knifedrawsound, coords, 128.);
- }
- }
- if (weapons[i].owner != -1) {
- victim = Person::players[weapons[i].owner];
- if (victim->num_weapons == 1)
- victim->num_weapons = 0;
- else
- victim->num_weapons = 1;
-
- //victim->weaponactive=-1;
- victim->skeleton.longdead = 0;
- victim->skeleton.free = 1;
- victim->skeleton.broken = 0;
-
- for (int j = 0; j < victim->skeleton.joints.size(); j++) {
- victim->skeleton.joints[j].velchange = 0;
- victim->skeleton.joints[j].locked = 0;
- }
-
- XYZ relative;
- relative = 0;
- relative.y = 10;
- Normalise(&relative);
- XYZ footvel, footpoint;
- footvel = 0;
- footpoint = weapons[i].position;
- if (victim->weaponstuck != -1) {
- if (victim->weaponids[victim->weaponstuck] == int(i)) {
- if (bloodtoggle)
- Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .8, .3);
- weapons[i].bloody = 2;
- weapons[i].blooddrip = 5;
- victim->weaponstuck = -1;
- }
- }
- if (victim->num_weapons > 0) {
- if (victim->weaponstuck != 0 && victim->weaponstuck != -1)
- victim->weaponstuck = 0;
- if (victim->weaponids[0] == int(i))
- victim->weaponids[0] = victim->weaponids[victim->num_weapons];
- }
-
- victim->jointVel(abdomen) += relative * 6;
- victim->jointVel(neck) += relative * 6;
- victim->jointVel(rightshoulder) += relative * 6;
- victim->jointVel(leftshoulder) += relative * 6;
- }
- takeWeapon(i);
- }
- }
- }
- }
-
- if (animCurrent == drawleftanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
- if (weaponactive == -1)
- weaponactive = 0;
- else if (weaponactive == 0) {
- weaponactive = -1;
- if (num_weapons == 2) {
- int buffer;
- buffer = weaponids[0];
- weaponids[0] = weaponids[1];
- weaponids[1] = buffer;
- }
- }
- if (weaponactive == -1) {
- emit_sound_at(knifesheathesound, coords, 128.);
- }
- if (weaponactive != -1) {
- emit_sound_at(knifedrawsound, coords, 128.);
- }
- }
-
-
- if ((animCurrent == walljumprightkickanim && animTarget == walljumprightkickanim) || (animCurrent == walljumpleftkickanim && animTarget == walljumpleftkickanim)) {
- XYZ rotatetarget = DoRotation(skeleton.forward, 0, yaw, 0);
- Normalise(&rotatetarget);
- targetyaw = -asin(0 - rotatetarget.x);
- targetyaw *= 360 / 6.28;
- if (rotatetarget.z < 0)
- targetyaw = 180 - targetyaw;
-
- if (animTarget == walljumprightkickanim)
- targetyaw += 40;
- if (animTarget == walljumpleftkickanim)
- targetyaw -= 40;
- }
-
- bool dojumpattack;
- dojumpattack = 0;
- if ((animTarget == rabbitrunninganim || animTarget == wolfrunninganim) && frameTarget == 3 && (jumpkeydown || attackkeydown || id != 0))
- dojumpattack = 1;
- if (hasvictim)
- if (distsq(&victim->coords, &/*Person::players[i]->*/coords) < 5 && victim->aitype == gethelptype && (attackkeydown) && !victim->skeleton.free && victim->isRun() && victim->runninghowlong >= 1)
- dojumpattack = 1;
- if (!hostile)
- dojumpattack = 0;
- if (dojumpattack) {
- if ((animTarget == rabbitrunninganim || animTarget == wolfrunninganim) && id == 0) {
- animTarget = rabbittackleanim;
- frameTarget = 0;
- emit_sound_at(jumpsound, coords);
- }
-
- float closestdist;
- closestdist = 0;
- int closestid;
- closestid = -1;
- XYZ targetloc;
- targetloc = velocity;
- Normalise(&targetloc);
- targetloc += coords;
- for (unsigned i = 0; i < Person::players.size(); i++) {
- if (i != id)
- if (distsq(&targetloc, &Person::players[i]->coords) < closestdist || closestdist == 0) {
- closestdist = distsq(&targetloc, &Person::players[i]->coords);
- closestid = i;
- }
- }
- if (closestid != -1)
- 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;
- animCurrent = rabbittacklinganim;
- animTarget = rabbittacklinganim;
- frameCurrent = 0;
- frameTarget = 1;
- XYZ rotatetarget;
- if (coords.z != victim->coords.z || coords.x != victim->coords.x) {
- rotatetarget = coords - victim->coords;
- Normalise(&rotatetarget);
- targetyaw = -asin(0 - rotatetarget.x);
- targetyaw *= 360 / 6.28;
- if (rotatetarget.z < 0)
- targetyaw = 180 - targetyaw;
- }
- if (animTarget != rabbitrunninganim) {
- emit_sound_at(jumpsound, coords, 128.);
- }
- }
- }
-
- //Move impacts
- float damagemult = 1 * power;
- if (creature == wolftype)
- damagemult = 2.5 * power;
- if (hasvictim) {
- damagemult /= victim->damagetolerance / 200;
- }
- if ((Animation::animations[animTarget].attack == normalattack || animTarget == walljumprightkickanim || animTarget == walljumpleftkickanim) && (!feint) && (victim->skeleton.free != 2 || animTarget == killanim || animTarget == dropkickanim || animTarget == crouchstabanim || animTarget == swordgroundstabanim || animTarget == staffgroundsmashanim)) {
- if (animTarget == spinkickanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
- if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && 3 && Animation::animations[victim->animTarget].height != lowheight) {
- escapednum = 0;
- if (id == 0)
- camerashake += .4;
- if (Random() % 2 || creature == wolftype) {
- victim->spurt = 1;
- DoBlood(.2, 250);
- if (creature == wolftype)
- DoBloodBig(0, 250);
- }
- if (tutoriallevel != 1) {
- emit_sound_at(heavyimpactsound, victim->coords, 128.);
- }
- if (creature == wolftype) {
- emit_sound_at(clawslicesound, victim->coords, 128.);
- victim->spurt = 1;
- victim->DoBloodBig(2 / victim->armorhead, 175);
- }
- victim->RagDoll(0);
- XYZ relative;
- relative = victim->coords - coords;
- relative.y = 0;
- Normalise(&relative);
- relative = DoRotation(relative, 0, -90, 0);
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velocity += relative * damagemult * 40;
- }
- victim->jointVel(head) += relative * damagemult * 200;
- victim->Puff(head);
- victim->DoDamage(damagemult * 100 / victim->protectionhead);
-
- SolidHitBonus(id);
- }
- }
-
- if (animTarget == wolfslapanim && Animation::animations[animTarget].frames[frameCurrent].label == 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;
- if (Random() % 2 || creature == wolftype) {
- victim->spurt = 1;
- if (creature == wolftype)
- DoBloodBig(0, 235);
- }
- emit_sound_at(whooshhitsound, victim->coords);
- if (creature == wolftype) {
- emit_sound_at(clawslicesound, victim->coords, 128.);
- victim->spurt = 1;
- victim->DoBloodBig(2, 175);
- }
- victim->RagDoll(0);
- XYZ relative;
- relative = victim->coords - coords;
- relative.y = 0;
- Normalise(&relative);
- relative.y -= 1;
- Normalise(&relative);
- relative = DoRotation(relative, 0, 90, 0);
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velocity += relative * damagemult * 20;
- }
- victim->jointVel(head) += relative * damagemult * 100;
- victim->Puff(head);
- victim->DoDamage(damagemult * 50 / victim->protectionhead);
- }
- }
-
- if (animTarget == walljumprightkickanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
- if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && Animation::animations[victim->animTarget].height != lowheight) {
- escapednum = 0;
- if (id == 0)
- camerashake += .4;
- victim->spurt = 1;
- DoBlood(.2, 250);
- if (tutoriallevel != 1) {
- emit_sound_at(heavyimpactsound, victim->coords, 160.);
- }
- if (creature == wolftype) {
- emit_sound_at(clawslicesound, victim->coords, 128.);
- victim->spurt = 1;
- victim->DoBloodBig(2 / victim->armorhead, 175);
- }
- victim->RagDoll(0);
- XYZ relative;
- relative = facing;
- relative.y = 0;
- Normalise(&relative);
- relative = DoRotation(relative, 0, -90, 0);
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velocity += relative * damagemult * 40;
- }
- victim->jointVel(head) += relative * damagemult * 200;
- victim->Puff(head);
- victim->DoDamage(damagemult * 150 / victim->protectionhead);
-
- if (victim->damage > victim->damagetolerance)
- award_bonus(id, style);
- else
- SolidHitBonus(id);
- }
- }
-
- if (animTarget == walljumpleftkickanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
- if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && Animation::animations[victim->animTarget].height != lowheight) {
- escapednum = 0;
- if (id == 0)
- camerashake += .4;
- victim->spurt = 1;
- DoBlood(.2, 250);
- if (tutoriallevel != 1) {
- emit_sound_at(heavyimpactsound, victim->coords, 160.);
- }
- if (creature == wolftype) {
- emit_sound_at(clawslicesound, victim->coords, 128.);
- victim->spurt = 1;
- victim->DoBloodBig(2 / victim->armorhead, 175);
- }
- victim->RagDoll(0);
- XYZ relative;
- relative = facing;
- relative.y = 0;
- Normalise(&relative);
- relative = DoRotation(relative, 0, 90, 0);
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velocity += relative * damagemult * 40;
- }
- victim->jointVel(head) += relative * damagemult * 200;
- victim->Puff(head);
- victim->DoDamage(damagemult * 150 / victim->protectionhead);
-
- if (victim->damage > victim->damagetolerance)
- award_bonus(id, style);
- else
- SolidHitBonus(id);
- }
- }
-
- if (animTarget == blockhighleftstrikeanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
- if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && Animation::animations[victim->animTarget].height != lowheight) {
- escapednum = 0;
- if (id == 0)
- camerashake += .4;
- if (Random() % 2) {
- victim->spurt = 1;
- DoBlood(.2, 235);
- }
- emit_sound_at(whooshhitsound, victim->coords);
- victim->RagDoll(0);
- XYZ relative;
- relative = victim->coords - coords;
- relative.y = 0;
- Normalise(&relative);
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velocity += relative * damagemult * 30;
- }
- victim->jointVel(head) += relative * damagemult * 100;
- victim->Puff(head);
- victim->DoDamage(damagemult * 50 / victim->protectionhead);
- }
- }
-
- if (animTarget == killanim && Animation::animations[animTarget].frames[frameCurrent].label == 8) {
- if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && victim->dead) {
- escapednum = 0;
- if (id == 0)
- camerashake += .2;
- emit_sound_at(whooshhitsound, victim->coords, 128.);
-
- victim->skeleton.longdead = 0;
- victim->skeleton.free = 1;
- victim->skeleton.broken = 0;
- victim->skeleton.spinny = 1;
-
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velchange = 0;
- victim->skeleton.joints[i].delay = 0;
- victim->skeleton.joints[i].locked = 0;
- //victim->skeleton.joints[i].velocity=0;
- }
-
- XYZ relative;
- relative = 0;
- relative.y = 1;
- Normalise(&relative);
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velocity.y = relative.y * 10;
- victim->skeleton.joints[i].position.y += relative.y * .3;
- victim->skeleton.joints[i].oldposition.y += relative.y * .3;
- victim->skeleton.joints[i].realoldposition.y += relative.y * .3;
- }
- victim->Puff(abdomen);
- victim->jointVel(abdomen).y = relative.y * 400;
- }
- }
-
- if (animTarget == killanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
- if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 9 && victim->dead) {
- escapednum = 0;
- if (id == 0)
- camerashake += .4;
- if (tutoriallevel != 1) {
- emit_sound_at(heavyimpactsound, coords, 128.);
- }
- XYZ relative;
- relative = victim->coords - coords;
- relative.y = 0;
- Normalise(&relative);
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velocity += relative * damagemult * 90;
- }
- victim->Puff(abdomen);
- if (victim->dead != 2 && victim->permanentdamage > victim->damagetolerance - 250 && autoslomo) {
- slomo = 1;
- slomodelay = .2;
- }
- victim->DoDamage(damagemult * 500 / victim->protectionhigh);
- victim->jointVel(abdomen) += relative * damagemult * 300;
- }
- }
-
- if (animTarget == dropkickanim && Animation::animations[animTarget].frames[frameCurrent].label == 7) {
- if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 9 && victim->skeleton.free) {
- escapednum = 0;
- if (id == 0)
- camerashake += .4;
- if (tutoriallevel != 1) {
- emit_sound_at(thudsound, coords);
- }
-
- victim->skeleton.longdead = 0;
- victim->skeleton.free = 1;
- victim->skeleton.broken = 0;
- victim->skeleton.spinny = 1;
-
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velchange = 0;
- //victim->skeleton.joints[i].delay=0;
- victim->skeleton.joints[i].locked = 0;
- }
- XYZ relative;
- relative = victim->coords - coords;
- Normalise(&relative);
- relative.y += .3;
- Normalise(&relative);
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velocity += relative * damagemult * 20;
- }
- if (!victim->dead)
- SolidHitBonus(id);
-
- victim->Puff(abdomen);
- victim->DoDamage(damagemult * 20 / victim->protectionhigh);
- victim->jointVel(abdomen) += relative * damagemult * 200;
- staggerdelay = .5;
- if (!victim->dead)
- staggerdelay = 1.2;
-
-
- }
- }
-
- if ((animTarget == crouchstabanim || animTarget == swordgroundstabanim) && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
-
- if (hasvictim)
- if (!victim->skeleton.free)
- hasvictim = 0;
-
- if (!hasvictim) {
- terrain.MakeDecal(blooddecalfast, (weapons[weaponids[weaponactive]].tippoint * .8 + weapons[weaponids[weaponactive]].position * .2), .08, .6, Random() % 360);
- emit_sound_at(knifesheathesound, coords, 128.);
- }
-
- if (victim && hasvictim) {
- if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3) {
-
- XYZ where, startpoint, endpoint, movepoint, colpoint;
- float rotationpoint;
- int whichtri;
- if (weapons[weaponids[weaponactive]].getType() == knife) {
- where = (weapons[weaponids[weaponactive]].tippoint * .6 + weapons[weaponids[weaponactive]].position * .4);
- where -= victim->coords;
- if (!victim->skeleton.free)
- where = DoRotation(where, 0, -victim->yaw, 0);
- //where=scale;
- startpoint = where;
- startpoint.y += 100;
- endpoint = where;
- endpoint.y -= 100;
- }
- if (weapons[weaponids[weaponactive]].getType() == sword) {
- where = weapons[weaponids[weaponactive]].position;
- where -= victim->coords;
- if (!victim->skeleton.free)
- where = DoRotation(where, 0, -victim->yaw, 0);
- startpoint = where;
- where = weapons[weaponids[weaponactive]].tippoint;
- where -= victim->coords;
- if (!victim->skeleton.free)
- where = DoRotation(where, 0, -victim->yaw, 0);
- endpoint = where;
- }
- if (weapons[weaponids[weaponactive]].getType() == staff) {
- where = weapons[weaponids[weaponactive]].position;
- where -= victim->coords;
- if (!victim->skeleton.free)
- where = DoRotation(where, 0, -victim->yaw, 0);
- startpoint = where;
- where = weapons[weaponids[weaponactive]].tippoint;
- where -= victim->coords;
- if (!victim->skeleton.free)
- where = DoRotation(where, 0, -victim->yaw, 0);
- endpoint = where;
- }
- movepoint = 0;
- rotationpoint = 0;
- whichtri = victim->skeleton.drawmodel.LineCheck(&startpoint, &endpoint, &colpoint, &movepoint, &rotationpoint);
-
- if (whichtri != -1) {
- if (victim->dead != 2) {
- victim->DoDamage(abs((victim->damagetolerance - victim->permanentdamage) * 2));
- if (!victim->dead)
- award_bonus(id, FinishedBonus);
- }
- if (bloodtoggle)
- weapons[weaponids[weaponactive]].bloody = 2;
-
- victim->skeleton.longdead = 0;
- victim->skeleton.free = 1;
- victim->skeleton.broken = 0;
-
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velchange = 0;
- victim->skeleton.joints[i].locked = 0;
- //victim->skeleton.joints[i].velocity=0;
- }
- emit_sound_at(fleshstabsound, coords, 128);
-
- }
- if (whichtri != -1 || weapons[weaponids[weaponactive]].bloody) {
- weapons[weaponids[weaponactive]].blooddrip += 5;
- weapons[weaponids[weaponactive]].blooddripdelay = 0;
- }
- if (whichtri == -1) {
- hasvictim = 0;
- emit_sound_at(knifesheathesound, coords, 128.);
- }
- }
- }
- }
-
- if ((animTarget == crouchstabanim || animTarget == swordgroundstabanim) && Animation::animations[animTarget].frames[frameCurrent].label == 6) {
- if (!hasvictim) {
- emit_sound_at(knifedrawsound, coords, 128);
- }
-
- if (victim && hasvictim) {
- XYZ footvel, footpoint;
-
- emit_sound_at(fleshstabremovesound, coords, 128.);
-
- footvel = 0;
- footpoint = (weapons[weaponids[weaponactive]].tippoint * .8 + weapons[weaponids[weaponactive]].position * .2);
-
- if (weapons[weaponids[weaponactive]].getType() == sword) {
- XYZ where, startpoint, endpoint, movepoint;
- float rotationpoint;
- int whichtri;
-
- where = weapons[weaponids[weaponactive]].position;
- where -= victim->coords;
- if (!victim->skeleton.free)
- where = DoRotation(where, 0, -victim->yaw, 0);
- startpoint = where;
- where = weapons[weaponids[weaponactive]].tippoint;
- where -= victim->coords;
- if (!victim->skeleton.free)
- where = DoRotation(where, 0, -victim->yaw, 0);
- endpoint = where;
-
- movepoint = 0;
- rotationpoint = 0;
- whichtri = victim->skeleton.drawmodel.LineCheck(&startpoint, &endpoint, &footpoint, &movepoint, &rotationpoint);
- footpoint += victim->coords;
-
- if (whichtri == -1) {
- footpoint = (weapons[weaponids[weaponactive]].tippoint * .8 + weapons[weaponids[weaponactive]].position * .2);
- }
- }
- if (weapons[weaponids[weaponactive]].getType() == staff) {
- XYZ where, startpoint, endpoint, movepoint;
- float rotationpoint;
- int whichtri;
-
- where = weapons[weaponids[weaponactive]].position;
- where -= victim->coords;
- if (!victim->skeleton.free)
- where = DoRotation(where, 0, -victim->yaw, 0);
- startpoint = where;
- where = weapons[weaponids[weaponactive]].tippoint;
- where -= victim->coords;
- if (!victim->skeleton.free)
- where = DoRotation(where, 0, -victim->yaw, 0);
- endpoint = where;
-
- movepoint = 0;
- rotationpoint = 0;
- whichtri = victim->skeleton.drawmodel.LineCheck(&startpoint, &endpoint, &footpoint, &movepoint, &rotationpoint);
- footpoint += victim->coords;
-
- if (whichtri == -1) {
- footpoint = (weapons[weaponids[weaponactive]].tippoint * .8 + weapons[weaponids[weaponactive]].position * .2);
- }
- }
- hasvictim = victim->DoBloodBigWhere(2, 220, footpoint);
- if (hasvictim) {
- if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3) {
- victim->skeleton.longdead = 0;
- victim->skeleton.free = 1;
- victim->skeleton.broken = 0;
-
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velchange = 0;
- victim->skeleton.joints[i].locked = 0;
- //victim->skeleton.joints[i].velocity=0;
- }
-
- XYZ relative;
- relative = 0;
- relative.y = 10;
- Normalise(&relative);
- //victim->Puff(abdomen);
- if (bloodtoggle)
- Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .8, .3);
-
- if (victim->bloodloss < victim->damagetolerance) {
- victim->bloodloss += 1000;
- victim->bled = 0;
- }
-
- victim->jointVel(abdomen) += relative * damagemult * 20;
- }
- }
- }
- if (!hasvictim && onterrain) {
- weapons[weaponids[weaponactive]].bloody = 0;
- weapons[weaponids[weaponactive]].blooddrip = 0;
- }
- }
-
- if (animTarget == upunchanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
- if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3) {
- escapednum = 0;
- if (id == 0)
- camerashake += .4;
- if (Random() % 2) {
- victim->spurt = 1;
- DoBlood(.2, 235);
- }
- if (tutoriallevel != 1) {
- emit_sound_at(heavyimpactsound, victim->coords, 128);
- }
-
- victim->RagDoll(0);
- XYZ relative;
- relative = victim->coords - coords;
- relative.y = 0;
- Normalise(&relative);
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velocity = relative * 30;
- }
- victim->jointVel(head) += relative * damagemult * 150;
-
- victim->frameTarget = 0;
- victim->animTarget = staggerbackhardanim;
- victim->targetyaw = targetyaw + 180;
- victim->target = 0;
- victim->stunned = 1;
-
- victim->Puff(head);
- victim->Puff(abdomen);
- victim->DoDamage(damagemult * 60 / victim->protectionhigh);
-
- SolidHitBonus(id);
- }
- }
-
-
- if (animTarget == winduppunchanim && Animation::animations[animTarget].frames[frameCurrent].label == 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::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::animations[victim->animTarget].height == lowheight) {
- if (tutoriallevel != 1) {
- emit_sound_at(whooshhitsound, victim->coords);
- }
- } else {
- if (tutoriallevel != 1) {
- emit_sound_at(heavyimpactsound, victim->coords);
- }
- }
-
- 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;
- relative.y = 0;
- Normalise(&relative);
- relative.y = .3;
- Normalise(&relative);
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velocity = relative * 5;
- }
- victim->jointVel(abdomen) += relative * damagemult * 400;
-
- victim->frameTarget = 0;
- victim->animTarget = staggerbackhardanim;
- victim->targetyaw = targetyaw + 180;
- victim->target = 0;
- victim->stunned = 1;
-
- victim->Puff(abdomen);
- victim->DoDamage(damagemult * 60 / victim->protectionhigh);
-
- SolidHitBonus(id);
- }
- }
-
- if (animTarget == blockhighleftanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
- if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 4) {
- if (victim->id == 0)
- camerashake += .4;
- emit_sound_at(landsound2, victim->coords);
-
- Puff(righthand);
- }
- }
-
- if (animTarget == swordslashparryanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
- if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 4) {
- if (victim->id == 0)
- camerashake += .4;
-
- if (weaponactive != -1) {
- if (weapons[victim->weaponids[0]].getType() == staff || weapons[weaponids[0]].getType() == staff) {
- if (weapons[victim->weaponids[0]].getType() == staff)
- weapons[victim->weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
- if (weapons[weaponids[0]].getType() == staff)
- weapons[weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
-
- emit_sound_at(swordstaffsound, victim->coords);
- } else {
- emit_sound_at(metalhitsound, victim->coords);
- }
- }
-
- //Puff(righthand);
- }
- }
-
- if (animTarget == knifethrowanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
- if (weaponactive != -1) {
- escapednum = 0;
- XYZ aim;
- aim = victim->coords + DoRotation(victim->jointPos(abdomen), 0, victim->yaw, 0) * victim->scale + victim->velocity * findDistance(&victim->coords, &coords) / 50 - (coords + DoRotation(jointPos(righthand), 0, yaw, 0) * scale);
- Normalise(&aim);
- weapons[weaponids[0]].thrown(aim * 50);
- num_weapons--;
- if (num_weapons) {
- weaponids[0] = weaponids[num_weapons];
- }
- weaponactive = -1;
- }
- }
-
- if (animTarget == knifeslashstartanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
- if (hasvictim)
- if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 4.5 &&/*Animation::animations[victim->animTarget].height!=lowheight&&*/victim->animTarget != dodgebackanim && victim->animTarget != rollanim) {
- escapednum = 0;
- if (tutoriallevel != 1)
- victim->DoBloodBig(1.5 / victim->armorhigh, 225);
-
- award_bonus(id, Slicebonus);
- if (tutoriallevel != 1) {
- emit_sound_at(knifeslicesound, victim->coords);
- }
- //victim->jointVel(abdomen)+=relative*damagemult*200;
- if (Animation::animations[victim->animTarget].attack && (victim->aitype != playercontrolled || victim->animTarget == knifeslashstartanim) && (victim->creature == rabbittype || victim->deathbleeding <= 0)) {
- if (victim->id != 0 || difficulty == 2) {
- victim->frameTarget = 0;
- victim->animTarget = staggerbackhardanim;
- victim->targetyaw = targetyaw + 180;
- victim->target = 0;
- }
- }
- victim->lowreversaldelay = 0;
- victim->highreversaldelay = 0;
- if (aitype != playercontrolled)
- weaponmissdelay = .6;
-
- if (tutoriallevel != 1)
- if (bloodtoggle && !weapons[weaponids[weaponactive]].bloody)
- weapons[weaponids[weaponactive]].bloody = 1;
- if (tutoriallevel != 1)
- weapons[weaponids[weaponactive]].blooddrip += 3;
-
- XYZ footvel, footpoint;
- footvel = 0;
- if (skeleton.free) {
- footpoint = (victim->jointPos(abdomen) + victim->jointPos(neck)) / 2 * victim->scale + victim->coords;
- } else {
- footpoint = DoRotation((victim->jointPos(abdomen) + victim->jointPos(neck)) / 2, 0, victim->yaw, 0) * victim->scale + victim->coords;
- }
- if (tutoriallevel != 1) {
- if (bloodtoggle)
- Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .6, .3);
- footvel = DoRotation(facing, 0, 90, 0) * .8;
- //footvel.y-=.3;
- Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 7, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
- Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 3, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
- Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 5, 1, 1, 1, .2, 1);
- Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 2, 1, 1, 1, .2, 1);
- }
- if (tutoriallevel == 1) {
- Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 1, 1, .6, .3);
- }
- victim->DoDamage(damagemult * 0);
- }
- }
- if (animTarget == swordslashanim && Animation::animations[animTarget].frames[frameCurrent].label == 5 && victim->animTarget != rollanim) {
- if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 6.5 && victim->animTarget != dodgebackanim) {
- if (victim->weaponactive == -1 || normaldotproduct(victim->facing, victim->coords - coords) > 0 || (Random() % 2 == 0)) {
- award_bonus(id, Slashbonus);
- escapednum = 0;
- if (tutoriallevel != 1) {
- if (normaldotproduct(victim->facing, victim->coords - coords) < 0)
- victim->DoBloodBig(2 / victim->armorhigh, 190);
- else
- victim->DoBloodBig(2 / victim->armorhigh, 185);
- victim->deathbleeding = 1;
- emit_sound_at(swordslicesound, victim->coords);
- }
- //victim->jointVel(abdomen)+=relative*damagemult*200;
- if (tutoriallevel != 1) {
- victim->frameTarget = 0;
- victim->animTarget = staggerbackhardanim;
- victim->targetyaw = targetyaw + 180;
- victim->target = 0;
- }
-
- if (tutoriallevel != 1) {
- if (bloodtoggle && !weapons[weaponids[weaponactive]].bloody)
- weapons[weaponids[weaponactive]].bloody = 1;
- weapons[weaponids[weaponactive]].blooddrip += 3;
-
- float bloodlossamount;
- bloodlossamount = 200 + abs((float)(Random() % 40)) - 20;
- victim->bloodloss += bloodlossamount / victim->armorhigh;
- //victim->bloodloss+=100*(6.5-distsq(&coords,&victim->coords));
- victim->DoDamage(damagemult * 0);
-
- XYZ footvel, footpoint;
- footvel = 0;
- if (skeleton.free) {
- footpoint = (victim->jointPos(abdomen) + victim->jointPos(neck)) / 2 * victim->scale + victim->coords;
- } else {
- footpoint = DoRotation((victim->jointPos(abdomen) + victim->jointPos(neck)) / 2, 0, victim->yaw, 0) * victim->scale + victim->coords;
- }
- if (bloodtoggle)
- Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .9, .3);
- footvel = DoRotation(facing, 0, 90, 0) * .8;
- footvel.y -= .3;
- Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 7, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
- Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 3, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
- Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 5, 1, 1, 1, .3, 1);
- Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 2, 1, 1, 1, .3, 1);
- }
- } else {
- if (victim->weaponactive != -1) {
- if (weapons[victim->weaponids[0]].getType() == staff || weapons[weaponids[0]].getType() == staff) {
- if (weapons[victim->weaponids[0]].getType() == staff)
- weapons[victim->weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
- if (weapons[weaponids[0]].getType() == staff)
- weapons[weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
-
- emit_sound_at(swordstaffsound, victim->coords);
- } else {
- emit_sound_at(metalhitsound, victim->coords);
- }
- }
-
-
- XYZ aim;
- victim->Puff(righthand);
- victim->target = 0;
- victim->frameTarget = 0;
- victim->animTarget = staggerbackhighanim;
- victim->targetyaw = targetyaw + 180;
- victim->target = 0;
- aim = DoRotation(facing, 0, 90, 0) * 21;
- aim.y += 7;
- weapons[victim->weaponids[0]].drop(aim * -.2, aim);
- victim->num_weapons--;
- if (victim->num_weapons) {
- victim->weaponids[0] = victim->weaponids[num_weapons];
- if (victim->weaponstuck == victim->num_weapons)
- victim->weaponstuck = 0;
- }
- victim->weaponactive = -1;
- for (unsigned i = 0; i < Person::players.size(); i++) {
- Person::players[i]->wentforweapon = 0;
- }
-
- }
- }
- }
-
- if (animTarget == staffhitanim && Animation::animations[animTarget].frames[frameCurrent].label == 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;
- escapednum = 0;
- if (id == 0)
- camerashake += .4;
- if (Random() % 2 || creature == wolftype) {
- victim->spurt = 1;
- }
- emit_sound_at(staffheadsound, victim->coords);
- }
- victim->RagDoll(0);
- XYZ relative;
- relative = victim->coords - coords;
- relative.y = 0;
- Normalise(&relative);
- relative = DoRotation(relative, 0, 90, 0);
- relative.y -= 1;
- Normalise(&relative);
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velocity += relative * damagemult * 60;
- }
- victim->jointVel(head) += relative * damagemult * 230;
- victim->jointVel(neck) += relative * damagemult * 230;
- victim->Puff(head);
- if (tutoriallevel != 1) {
- victim->DoDamage(damagemult * 120 / victim->protectionhigh);
-
- award_bonus(id, solidhit, 30);
- }
- }
- }
-
- if (animTarget == staffspinhitanim && Animation::animations[animTarget].frames[frameCurrent].label == 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;
- escapednum = 0;
- if (id == 0)
- camerashake += .4;
- if (Random() % 2 || creature == wolftype) {
- victim->spurt = 1;
- }
- emit_sound_at(staffheadsound, victim->coords);
- }
- victim->RagDoll(0);
- XYZ relative;
- relative = victim->coords - coords;
- relative.y = 0;
- Normalise(&relative);
- relative = DoRotation(relative, 0, -90, 0);
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velocity += relative * damagemult * 40;
- }
- victim->jointVel(head) += relative * damagemult * 220;
- victim->jointVel(neck) += relative * damagemult * 220;
- victim->Puff(head);
- if (tutoriallevel != 1) {
- victim->DoDamage(damagemult * 350 / victim->protectionhead);
-
- award_bonus(id, solidhit, 60);
- }
- }
- }
-
- if (animTarget == staffgroundsmashanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
- if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 6.5) {
- escapednum = 0;
- if (tutoriallevel != 1) {
- if (!victim->dead)
- weapons[weaponids[0]].damage += .4 + float(abs(Random() % 100) - 50) / 500;
- if (id == 0)
- camerashake += .4;
- if (Random() % 2 || creature == wolftype) {
- victim->spurt = 1;
- }
- emit_sound_at(staffbodysound, victim->coords);
- }
- victim->skeleton.longdead = 0;
- victim->skeleton.free = 1;
- victim->skeleton.broken = 0;
-
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velchange = 0;
- victim->skeleton.joints[i].locked = 0;
- //victim->skeleton.joints[i].velocity=0;
- }
-
- victim->RagDoll(0);
- XYZ relative;
- relative = 0;
- relative.y = -1;
- Normalise(&relative);
- if (!victim->dead) {
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velocity = relative * damagemult * 40;
- }
- victim->jointVel(abdomen) += relative * damagemult * 40;
- }
- if (victim->dead) {
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velocity = relative * damagemult * abs(Random() % 20);
- }
- }
- victim->Puff(abdomen);
- if (tutoriallevel != 1) {
- victim->DoDamage(damagemult * 100 / victim->protectionhigh);
-
- if (!victim->dead) {
- award_bonus(id, solidhit, 40);
- }
- }
- }
- }
-
- if (animTarget == lowkickanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
- if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && Animation::animations[victim->animTarget].height != highheight) {
- escapednum = 0;
- if (id == 0)
- camerashake += .4;
- XYZ relative;
- relative = victim->coords - coords;
- relative.y = 0;
- Normalise(&relative);
-
- SolidHitBonus(id);
-
- if (Animation::animations[victim->animTarget].height == lowheight) {
- if (Random() % 2) {
- victim->spurt = 1;
- DoBlood(.2, 250);
- }
- victim->RagDoll(0);
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velocity += relative * damagemult * 40;
- }
- victim->jointVel(head) += relative * damagemult * 200;
- if (tutoriallevel != 1) {
- emit_sound_at(heavyimpactsound, victim->coords, 128.);
- }
- victim->Puff(head);
- victim->DoDamage(damagemult * 100 / victim->protectionhead);
- if (victim->howactive == typesleeping)
- victim->DoDamage(damagemult * 150 / victim->protectionhead);
- if (creature == wolftype) {
- emit_sound_at(clawslicesound, victim->coords, 128.);
- victim->spurt = 1;
- victim->DoBloodBig(2 / victim->armorhead, 175);
- }
- } else {
- if (victim->damage >= victim->damagetolerance)
- victim->RagDoll(0);
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velocity += relative * damagemult * 10;
- }
- victim->jointVel(abdomen) += relative * damagemult * 200;
- victim->frameTarget = 0;
- victim->animTarget = staggerbackhighanim;
- victim->targetyaw = targetyaw + 180;
- victim->target = 0;
- if (tutoriallevel != 1) {
- emit_sound_at(landsound2, victim->coords, 128.);
- }
- victim->Puff(abdomen);
- victim->DoDamage(damagemult * 30 / victim->protectionhigh);
- if (creature == wolftype) {
- emit_sound_at(clawslicesound, victim->coords, 128.);
- victim->spurt = 1;
- victim->DoBloodBig(2 / victim->armorhigh, 170);
- }
- }
-
- }
- }
-
- if (animTarget == sweepanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
- if ((victim->animTarget != jumpupanim) &&
- (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3) &&
- (victim != this->shared_from_this())) {
- escapednum = 0;
- if (id == 0)
- camerashake += .2;
- if (tutoriallevel != 1) {
- emit_sound_at(landsound2, victim->coords, 128.);
- }
- XYZ relative;
- relative = victim->coords - coords;
- relative.y = 0;
- Normalise(&relative);
-
- 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.joints.size(); i++) {
- victim->skeleton.joints[i].velocity += relative * damagemult * 15;
- }
- relative = DoRotation(relative, 0, -90, 0);
- relative.y += .1;
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- if (victim->skeleton.joints[i].label == leftfoot || victim->skeleton.joints[i].label == rightfoot || victim->skeleton.joints[i].label == leftankle || victim->skeleton.joints[i].label == rightankle)
- victim->skeleton.joints[i].velocity = relative * 80;
- }
- victim->Puff(rightankle);
- victim->Puff(leftankle);
- victim->DoDamage(damagemult * 40 / victim->protectionlow);
- } else {
- if (victim->damage >= victim->damagetolerance)
- victim->RagDoll(0);
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velocity += relative * damagemult * 10;
- }
- relative = DoRotation(relative, 0, -90, 0);
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- if (victim->skeleton.joints[i].label == leftfoot || victim->skeleton.joints[i].label == rightfoot || victim->skeleton.joints[i].label == leftankle || victim->skeleton.joints[i].label == rightankle)
- victim->skeleton.joints[i].velocity += relative * damagemult * 80;
- }
- victim->jointVel(abdomen) += relative * damagemult * 200;
- victim->frameTarget = 0;
- victim->animTarget = staggerbackhighanim;
- victim->targetyaw = targetyaw + 180;
- victim->target = 0;
- if (tutoriallevel != 1) {
- emit_sound_at(landsound2, victim->coords, 128.);
- }
- victim->Puff(abdomen);
- victim->DoDamage(damagemult * 30 / victim->protectionlow);
- }
-
- SolidHitBonus(id);
-
- }
- }
- }
- if (Animation::animations[animTarget].attack == reversal && (!victim->feint || (victim->lastattack == victim->lastattack2 && victim->lastattack2 == victim->lastattack3 && Random() % 2) || animTarget == knifefollowanim)) {
- if (animTarget == spinkickreversalanim && Animation::animations[animTarget].frames[frameCurrent].label == 7) {
- escapednum = 0;
- if (id == 0)
- camerashake += .4;
- if (Random() % 2) {
- victim->spurt = 1;
- DoBlood(.2, 230);
- }
- if (tutoriallevel != 1) {
- emit_sound_at(heavyimpactsound, victim->coords, 128.);
- }
- if (creature == wolftype) {
- emit_sound_at(clawslicesound, victim->coords, 128);
- victim->spurt = 1;
- victim->DoBloodBig(2 / victim->armorhigh, 170);
- }
- victim->RagDoll(0);
- XYZ relative;
- relative = victim->coords - oldcoords;
- relative.y = 0;
- Normalise(&relative);
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velocity += relative * damagemult * 40;
- }
- victim->jointVel(abdomen) += relative * damagemult * 200;
- victim->Puff(abdomen);
- victim->DoDamage(damagemult * 150 / victim->protectionhigh);
-
- award_bonus(id, Reversal);
- }
-
- if ((animTarget == swordslashreversalanim || animTarget == knifeslashreversalanim || animTarget == staffhitreversalanim || animTarget == staffspinhitreversalanim) && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
- if (victim->weaponactive != -1 && victim->num_weapons > 0) {
- if (weapons[victim->weaponids[victim->weaponactive]].owner == int(victim->id)) {
- takeWeapon(victim->weaponids[victim->weaponactive]);
- victim->num_weapons--;
- if (victim->num_weapons > 0) {
- victim->weaponids[victim->weaponactive] = victim->weaponids[victim->num_weapons];
- }
- victim->weaponactive = -1;
- }
- }
- }
-
- if (animTarget == staffhitreversalanim && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
- escapednum = 0;
- if (id == 0)
- camerashake += .4;
- if (Random() % 2) {
- victim->spurt = 1;
- DoBlood(.2, 230);
- }
- emit_sound_at(whooshhitsound, victim->coords, 128.);
- victim->RagDoll(0);
- XYZ relative;
- relative = victim->coords - oldcoords;
- relative.y = 0;
- Normalise(&relative);
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velocity += relative * damagemult * 30;
- }
- victim->jointVel(abdomen) += relative * damagemult * 200;
- victim->Puff(head);
- victim->DoDamage(damagemult * 70 / victim->protectionhigh);
- }
-
- if (animTarget == staffspinhitreversalanim && Animation::animations[animTarget].frames[frameCurrent].label == 7) {
- escapednum = 0;
- if (id == 0)
- camerashake += .4;
- if (Random() % 2) {
- victim->spurt = 1;
- DoBlood(.2, 230);
- }
-
- award_bonus(id, staffreversebonus);
-
- if (tutoriallevel != 1) {
- emit_sound_at(heavyimpactsound, victim->coords, 128.);
- }
- victim->RagDoll(0);
- award_bonus(id, staffreversebonus); // Huh, again?
-
- XYZ relative;
- relative = victim->coords - oldcoords;
- relative.y = 0;
- Normalise(&relative);
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velocity += relative * damagemult * 30;
- }
- victim->jointVel(abdomen) += relative * damagemult * 200;
- victim->Puff(head);
- victim->DoDamage(damagemult * 70 / victim->protectionhigh);
- }
-
- if (animTarget == upunchreversalanim && Animation::animations[animTarget].frames[frameCurrent].label == 7) {
- escapednum = 0;
- victim->RagDoll(1);
- XYZ relative;
- relative = facing;
- relative.y = 0;
- Normalise(&relative);
- relative.y -= .1;
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velocity += relative * damagemult * 70;
- }
- victim->jointVel(lefthand) *= .1;
- victim->jointVel(leftwrist) *= .2;
- victim->jointVel(leftelbow) *= .5;
- victim->jointVel(leftshoulder) *= .7;
- victim->jointVel(righthand) *= .1;
- victim->jointVel(rightwrist) *= .2;
- victim->jointVel(rightelbow) *= .5;
- victim->jointVel(rightshoulder) *= .7;
-
- victim->Puff(abdomen);
- victim->DoDamage(damagemult * 90 / victim->protectionhigh);
-
- award_bonus(id, Reversal);
-
- bool doslice;
- doslice = 0;
- if (weaponactive != -1 || creature == wolftype)
- doslice = 1;
- if (creature == rabbittype && weaponactive != -1)
- if (weapons[weaponids[0]].getType() == staff)
- doslice = 0;
- if (doslice) {
- if (weaponactive != -1) {
- victim->DoBloodBig(2 / victim->armorhigh, 225);
- emit_sound_at(knifeslicesound, victim->coords);
- if (bloodtoggle && !weapons[weaponids[weaponactive]].bloody)
- weapons[weaponids[weaponactive]].bloody = 1;
- weapons[weaponids[weaponactive]].blooddrip += 3;
- }
- if (weaponactive == -1 && creature == wolftype) {
- emit_sound_at(clawslicesound, victim->coords, 128.);
- victim->spurt = 1;
- victim->DoBloodBig(2 / victim->armorhigh, 175);
- }
- }
- }
-
-
-
- if (animTarget == swordslashreversalanim && Animation::animations[animTarget].frames[frameCurrent].label == 7) {
- escapednum = 0;
- victim->RagDoll(1);
- XYZ relative;
- relative = facing;
- relative.y = 0;
- Normalise(&relative);
- relative.y -= .1;
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velocity += relative * damagemult * 70;
- }
- victim->jointVel(lefthand) *= .1 - 1;
- victim->jointVel(leftwrist) *= .2 - 1;
- victim->jointVel(leftelbow) *= .5 - 1;
- victim->jointVel(leftshoulder) *= .7 - 1;
- victim->jointVel(righthand) *= .1 - 1;
- victim->jointVel(rightwrist) *= .2 - 1;
- victim->jointVel(rightelbow) *= .5 - 1;
- victim->jointVel(rightshoulder) *= .7 - 1;
-
- award_bonus(id, swordreversebonus);
- }
-
- if (hasvictim && animTarget == knifeslashreversalanim && Animation::animations[animTarget].frames[frameCurrent].label == 7) {
- escapednum = 0;
- if (id == 0)
- camerashake += .4;
- if (Random() % 2) {
- victim->spurt = 1;
- DoBlood(.2, 230);
- }
- if (tutoriallevel != 1) {
- emit_sound_at(heavyimpactsound, victim->coords, 128.);
- }
- victim->RagDoll(0);
- XYZ relative;
- relative = victim->coords - oldcoords;
- relative.y = 0;
- Normalise(&relative);
- relative = DoRotation(relative, 0, -90, 0);
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velocity += relative * damagemult * 40;
- }
- victim->jointVel(abdomen) += relative * damagemult * 200;
- victim->Puff(abdomen);
- victim->DoDamage(damagemult * 30 / victim->protectionhigh);
-
- award_bonus(id, Reversal);
- }
-
- if (hasvictim && animTarget == sneakattackanim && Animation::animations[animTarget].frames[frameCurrent].label == 7) {
- escapednum = 0;
- victim->RagDoll(0);
- victim->skeleton.spinny = 0;
- XYZ relative;
- relative = facing * -1;
- relative.y = -3;
- Normalise(&relative);
- if (victim->id == 0)
- relative /= 30;
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velocity += relative * damagemult * 40;
- }
- victim->damage = victim->damagetolerance;
- victim->permanentdamage = victim->damagetolerance - 1;
- bool doslice;
- doslice = 0;
- if (weaponactive != -1 || creature == wolftype)
- doslice = 1;
- if (creature == rabbittype && weaponactive != -1)
- if (weapons[weaponids[0]].getType() == staff)
- doslice = 0;
- if (doslice) {
- if (weaponactive != -1) {
- victim->DoBloodBig(200, 225);
- emit_sound_at(knifeslicesound, victim->coords);
- if (bloodtoggle)
- weapons[weaponids[weaponactive]].bloody = 2;
- weapons[weaponids[weaponactive]].blooddrip += 5;
- }
-
- if (creature == wolftype && weaponactive == -1) {
- emit_sound_at(clawslicesound, victim->coords, 128.);
- victim->spurt = 1;
- victim->DoBloodBig(2, 175);
- }
- }
- award_bonus(id, spinecrusher);
- }
-
- if (hasvictim && (animTarget == knifefollowanim || animTarget == knifesneakattackanim) && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
- if (weaponactive != -1 && victim->bloodloss < victim->damagetolerance) {
- escapednum = 0;
- if (animTarget == knifefollowanim)
- victim->DoBloodBig(200, 210);
- if (animTarget == knifesneakattackanim) {
- XYZ footvel, footpoint;
- footvel = 0;
- footpoint = weapons[weaponids[0]].tippoint;
- if (bloodtoggle)
- Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .9, .3);
- footvel = (weapons[weaponids[0]].tippoint - weapons[weaponids[0]].position);
- Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 7, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
- Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 3, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
- Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 5, 1, 1, 1, .3, 1);
- Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 2, 1, 1, 1, .3, 1);
- victim->DoBloodBig(200, 195);
- award_bonus(id, tracheotomy);
- }
- if (animTarget == knifefollowanim) {
- award_bonus(id, Stabbonus);
- XYZ footvel, footpoint;
- footvel = 0;
- footpoint = weapons[weaponids[0]].tippoint;
- if (bloodtoggle)
- Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .9, .3);
- footvel = (weapons[weaponids[0]].tippoint - weapons[weaponids[0]].position) * -1;
- Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 7, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
- Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 3, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
- Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 5, 1, 1, 1, .2, 1);
- Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 2, 1, 1, 1, .2, 1);
-
- }
- victim->bloodloss += 10000;
- victim->velocity = 0;
- emit_sound_at(fleshstabsound, victim->coords);
- if (bloodtoggle)
- weapons[weaponids[weaponactive]].bloody = 2;
- weapons[weaponids[weaponactive]].blooddrip += 5;
- }
- }
-
- if (hasvictim && (animTarget == knifefollowanim || animTarget == knifesneakattackanim) && Animation::animations[animTarget].frames[frameCurrent].label == 6) {
- escapednum = 0;
- victim->velocity = 0;
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velocity = 0;
- }
- if (animTarget == knifefollowanim) {
- victim->RagDoll(0);
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velocity = 0;
- }
- }
- if (weaponactive != -1 && Animation::animations[victim->animTarget].attack != reversal) {
- emit_sound_at(fleshstabremovesound, victim->coords);
- if (bloodtoggle)
- weapons[weaponids[weaponactive]].bloody = 2;
- weapons[weaponids[weaponactive]].blooddrip += 5;
-
- XYZ footvel, footpoint;
- footvel = 0;
- footpoint = weapons[weaponids[0]].tippoint;
- if (bloodtoggle)
- Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .9, .3);
- footvel = (weapons[weaponids[0]].tippoint - weapons[weaponids[0]].position) * -1;
- Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 7, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
- Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 3, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
- Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 5, 1, 1, 1, .3, 1);
- Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 2, 1, 1, 1, .3, 1);
- }
- }
-
- if (hasvictim && (animTarget == swordsneakattackanim) && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
- if (weaponactive != -1 && victim->bloodloss < victim->damagetolerance) {
- award_bonus(id, backstab);
-
- escapednum = 0;
-
- XYZ footvel, footpoint;
- footvel = 0;
- footpoint = (weapons[weaponids[0]].tippoint + weapons[weaponids[0]].position) / 2;
- if (bloodtoggle)
- Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .9, .3);
- footvel = (weapons[weaponids[0]].tippoint - weapons[weaponids[0]].position);
- Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 7, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
- Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 3, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
- Sprite::MakeSprite(bloodflamesprite, footpoint, DoRotation(footvel * 5, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .3, 1);
- Sprite::MakeSprite(bloodflamesprite, footpoint, DoRotation(footvel * 3, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .3, 1);
- victim->DoBloodBig(200, 180);
- victim->DoBloodBig(200, 215);
- victim->bloodloss += 10000;
- victim->velocity = 0;
- emit_sound_at(fleshstabsound, victim->coords);
- if (bloodtoggle)
- weapons[weaponids[weaponactive]].bloody = 2;
- weapons[weaponids[weaponactive]].blooddrip += 5;
- }
- }
-
- if (hasvictim && animTarget == swordsneakattackanim && Animation::animations[animTarget].frames[frameCurrent].label == 6) {
- escapednum = 0;
- victim->velocity = 0;
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velocity = 0;
- }
- if (weaponactive != -1) {
- emit_sound_at(fleshstabremovesound, victim->coords);
- if (bloodtoggle)
- weapons[weaponids[weaponactive]].bloody = 2;
- weapons[weaponids[weaponactive]].blooddrip += 5;
-
- XYZ footvel, footpoint;
- footvel = 0;
- footpoint = weapons[weaponids[0]].tippoint;
- if (bloodtoggle)
- Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .9, .3);
- footvel = (weapons[weaponids[0]].tippoint - weapons[weaponids[0]].position) * -1;
- Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 7, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
- Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 3, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
- Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 5, 1, 1, 1, .3, 1);
- Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 2, 1, 1, 1, .3, 1);
- }
- }
-
- if (animTarget == sweepreversalanim && Animation::animations[animTarget].frames[frameCurrent].label == 7) {
- escapednum = 0;
- if (id == 0)
- camerashake += .4;
- if (Random() % 2) {
- victim->spurt = 1;
- DoBlood(.2, 240);
- }
- if (weaponactive == -1) {
- if (tutoriallevel != 1) {
- emit_sound_at(heavyimpactsound, victim->coords, 128.);
- }
- }
- bool doslice;
- doslice = 0;
- if (weaponactive != -1 || creature == wolftype)
- doslice = 1;
- if (creature == rabbittype && weaponactive != -1)
- if (weapons[weaponids[0]].getType() == staff)
- doslice = 0;
- if (doslice) {
- if (weaponactive != -1) {
- victim->DoBloodBig(2 / victim->armorhead, 225);
- emit_sound_at(knifeslicesound, victim->coords);
- if (bloodtoggle && !weapons[weaponids[weaponactive]].bloody)
- weapons[weaponids[weaponactive]].bloody = 1;
- weapons[weaponids[weaponactive]].blooddrip += 3;
- }
- if (weaponactive == -1 && creature == wolftype) {
- emit_sound_at(clawslicesound, victim->coords, 128.);
- victim->spurt = 1;
- victim->DoBloodBig(2 / victim->armorhead, 175);
- }
- }
-
- award_bonus(id, Reversal);
-
- victim->Puff(neck);
-
- XYZ relative;
- relative = facing * -1;
- relative.y = 0;
- Normalise(&relative);
- relative = DoRotation(relative, 0, 90, 0);
- relative.y = .5;
- Normalise(&relative);
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velocity += relative * damagemult * 20;
- }
- victim->jointVel(head) += relative * damagemult * 200;
- if (victim->damage < victim->damagetolerance - 100)
- victim->velocity = relative * 200;
- victim->DoDamage(damagemult * 100 / victim->protectionhead);
- victim->velocity = 0;
- }
-
- if (animTarget == sweepreversalanim && ((Animation::animations[animTarget].frames[frameCurrent].label == 9 && victim->damage < victim->damagetolerance) || (Animation::animations[animTarget].frames[frameCurrent].label == 7 && victim->damage > victim->damagetolerance))) {
- escapednum = 0;
- victim->RagDoll(0);
- XYZ relative;
- relative = facing * -1;
- relative.y = 0;
- Normalise(&relative);
- relative = DoRotation(relative, 0, 90, 0);
- relative.y = .5;
- Normalise(&relative);
- for (int i = 0; i < victim->skeleton.joints.size(); i++) {
- victim->skeleton.joints[i].velocity += relative * damagemult * 20;
- }
- victim->jointVel(head) += relative * damagemult * 200;
- }
-
- if (hasvictim && (animTarget == spinkickreversalanim || animTarget == sweepreversalanim || animTarget == rabbitkickreversalanim || animTarget == upunchreversalanim || animTarget == jumpreversalanim || animTarget == swordslashreversalanim || animTarget == knifeslashreversalanim || animTarget == rabbittacklereversal || animTarget == wolftacklereversal || animTarget == staffhitreversalanim || animTarget == staffspinhitreversalanim))
- if (victim->damage > victim->damagetolerance && bonus != reverseko) {
- award_bonus(id, reverseko);
- }
- }
-
-
- //Animation end
- if (frameTarget > Animation::animations[animCurrent].frames.size() - 1) {
- frameTarget = 0;
- if (wasStop()) {
- animTarget = getIdle();
- FootLand(leftfoot, 1);
- FootLand(rightfoot, 1);
- }
- if (animCurrent == rabbittackleanim || animCurrent == rabbittacklinganim) {
- animTarget = rollanim;
- frameTarget = 3;
- emit_sound_at(movewhooshsound, coords, 128.);
- }
- if (animCurrent == staggerbackhighanim) {
- animTarget = getIdle();
- }
- if (animCurrent == staggerbackhardanim) {
- animTarget = getIdle();
- }
- if (animCurrent == removeknifeanim) {
- animTarget = getIdle();
- }
- if (animCurrent == crouchremoveknifeanim) {
- animTarget = getCrouch();
- }
- if (animCurrent == backhandspringanim) {
- animTarget = getIdle();
- }
- if (animCurrent == dodgebackanim) {
- animTarget = getIdle();
- }
- if (animCurrent == drawleftanim) {
- animTarget = getIdle();
- }
- if (animCurrent == drawrightanim || animCurrent == crouchdrawrightanim) {
- animTarget = getIdle();
- if (animCurrent == crouchdrawrightanim) {
- animTarget = getCrouch();
- }
- if (weaponactive == -1)
- weaponactive = 0;
- else if (weaponactive == 0) {
- weaponactive = -1;
- if (num_weapons == 2) {
- int buffer;
- buffer = weaponids[0];
- weaponids[0] = weaponids[1];
- weaponids[1] = buffer;
- }
- }
-
- if (weaponactive == -1) {
- emit_sound_at(knifesheathesound, coords, 128.);
- }
- if (weaponactive != -1) {
- emit_sound_at(knifedrawsound, coords, 128.);
- }
- }
- if (animCurrent == rollanim) {
- animTarget = getCrouch();
- FootLand(leftfoot, 1);
- FootLand(rightfoot, 1);
- }
- if (isFlip()) {
- if (animTarget == walljumprightkickanim) {
- targetrot = -190;
- }
- if (animTarget == walljumpleftkickanim) {
- targetrot = 190;
- }
- animTarget = jumpdownanim;
- }
- if (animCurrent == climbanim) {
- animTarget = getCrouch();
- frameTarget = 1;
- coords += facing * .1;
- if (!isnormal(coords.x))
- coords = oldcoords;
- oldcoords = coords;
- collided = 0;
- targetoffset = 0;
- currentoffset = 0;
- grabdelay = 1;
- velocity = 0;
- collided = 0;
- avoidcollided = 0;
- }
- if (animTarget == rabbitkickreversalanim) {
- animTarget = getCrouch();
- lastfeint = 0;
- }
- if (animTarget == jumpreversalanim) {
- animTarget = getCrouch();
- lastfeint = 0;
- }
- if (animTarget == walljumprightanim || animTarget == walljumpbackanim || animTarget == walljumpfrontanim) {
- if (attackkeydown && animTarget != walljumpfrontanim) {
- int closest = -1;
- float closestdist = -1;
- float distance;
- if (Person::players.size() > 1)
- for (unsigned i = 0; i < Person::players.size(); i++) {
- if (id != i && Person::players[i]->coords.y < coords.y && !Person::players[i]->skeleton.free) {
- distance = distsq(&Person::players[i]->coords, &coords);
- if (closestdist == -1 || distance < closestdist) {
- closestdist = distance;
- closest = i;
- }
- }
- }
- if (closestdist > 0 && closest >= 0 && closestdist < 16) {
- victim = Person::players[closest];
- animTarget = walljumprightkickanim;
- frameTarget = 0;
- XYZ rotatetarget = victim->coords - coords;
- Normalise(&rotatetarget);
- yaw = -asin(0 - rotatetarget.x);
- yaw *= 360 / 6.28;
- if (rotatetarget.z < 0)
- yaw = 180 - yaw;
- targettilt2 = -asin(rotatetarget.y) * 360 / 6.28;
- velocity = (victim->coords - coords) * 4;
- velocity.y += 2;
- transspeed = 40;
- }
- }
- if (animTarget == walljumpbackanim) {
- animTarget = backflipanim;
- frameTarget = 3;
- velocity = facing * -8;
- velocity.y = 4;
- if (id == 0)
- resume_stream(whooshsound);
- }
- if (animTarget == walljumprightanim) {
- animTarget = rightflipanim;
- frameTarget = 4;
- targetyaw -= 90;
- yaw -= 90;
- velocity = DoRotation(facing, 0, 30, 0) * -8;
- velocity.y = 4;
- }
- if (animTarget == walljumpfrontanim) {
- animTarget = frontflipanim;
- frameTarget = 2;
- //targetyaw-=180;
- ////yaw-=180;
- velocity = facing * 8;
- velocity.y = 4;
- }
- if (id == 0)
- resume_stream(whooshsound);
- }
- if (animTarget == walljumpleftanim) {
- if (attackkeydown) {
- int closest = -1;
- float closestdist = -1;
- float distance;
- if (Person::players.size() > 1)
- for (unsigned i = 0; i < Person::players.size(); i++) {
- if (id != i && Person::players[i]->coords.y < coords.y && !Person::players[i]->skeleton.free) {
- distance = distsq(&Person::players[i]->coords, &coords);
- if (closestdist == -1 || distance < closestdist) {
- closestdist = distance;
- closest = i;
- }
- }
- }
- if (closestdist > 0 && closest >= 0 && closestdist < 16) {
- victim = Person::players[closest];
- animTarget = walljumpleftkickanim;
- frameTarget = 0;
- XYZ rotatetarget = victim->coords - coords;
- Normalise(&rotatetarget);
- yaw = -asin(0 - rotatetarget.x);
- yaw *= 360 / 6.28;
- if (rotatetarget.z < 0)
- yaw = 180 - yaw;
- targettilt2 = -asin(rotatetarget.y) * 360 / 6.28;
- velocity = (victim->coords - coords) * 4;
- velocity.y += 2;
- transspeed = 40;
- }
- }
- if (animTarget != walljumpleftkickanim) {
- animTarget = leftflipanim;
- frameTarget = 4;
- targetyaw += 90;
- yaw += 90;
- velocity = DoRotation(facing, 0, -30, 0) * -8;
- velocity.y = 4;
- }
- if (id == 0)
- resume_stream(whooshsound);
- }
- if (animTarget == sneakattackanim) {
- animCurrent = getCrouch();
- animTarget = getCrouch();
- frameTarget = 1;
- frameCurrent = 0;
- targetyaw += 180;
- yaw += 180;
- targettilt2 *= -1;
- tilt2 *= -1;
- transspeed = 1000000;
- targetheadyaw += 180;
- coords -= facing * .7;
- if (onterrain)
- coords.y = terrain.getHeight(coords.x, coords.z);
-
- lastfeint = 0;
- }
- if (animTarget == knifesneakattackanim || animTarget == swordsneakattackanim) {
- animTarget = getIdle();
- frameTarget = 0;
- if (onterrain)
- coords.y = terrain.getHeight(coords.x, coords.z);
-
- lastfeint = 0;
- }
- if (animCurrent == knifefollowanim) {
- animTarget = getIdle();
- lastfeint = 0;
- }
- if (Animation::animations[animTarget].attack == reversal && animCurrent != sneakattackanim && animCurrent != knifesneakattackanim && animCurrent != swordsneakattackanim && animCurrent != knifefollowanim) {
- float ycoords = oldcoords.y;
- animTarget = getStop();
- targetyaw += 180;
- yaw += 180;
- targettilt2 *= -1;
- tilt2 *= -1;
- transspeed = 1000000;
- targetheadyaw += 180;
- if (!isnormal(coords.x))
- coords = oldcoords;
- if (animCurrent == spinkickreversalanim || animCurrent == swordslashreversalanim)
- oldcoords = coords + facing * .5;
- else if (animCurrent == sweepreversalanim)
- oldcoords = coords + facing * 1.1;
- else if (animCurrent == upunchreversalanim) {
- oldcoords = coords + facing * 1.5;
- targetyaw += 180;
- yaw += 180;
- targetheadyaw += 180;
- targettilt2 *= -1;
- tilt2 *= -1;
- } else if (animCurrent == knifeslashreversalanim) {
- oldcoords = coords + facing * .5;
- targetyaw += 90;
- yaw += 90;
- targetheadyaw += 90;
- targettilt2 = 0;
- tilt2 = 0;
- } else if (animCurrent == staffspinhitreversalanim) {
- targetyaw += 180;
- yaw += 180;
- targetheadyaw += 180;
- targettilt2 = 0;
- tilt2 = 0;
- }
- if (onterrain)
- oldcoords.y = terrain.getHeight(oldcoords.x, oldcoords.z);
- else
- oldcoords.y = ycoords;
- currentoffset = coords - oldcoords;
- targetoffset = 0;
- coords = oldcoords;
-
- lastfeint = 0;
- }
- if (animCurrent == knifesneakattackedanim || animCurrent == swordsneakattackedanim) {
- velocity = 0;
- velocity.y = -5;
- RagDoll(0);
- }
- if (Animation::animations[animTarget].attack == reversed) {
- escapednum++;
- if (animTarget == sweepreversedanim)
- targetyaw += 90;
- animTarget = backhandspringanim;
- frameTarget = 2;
- emit_sound_at(landsound, coords, 128);
-
- if (animCurrent == upunchreversedanim || animCurrent == swordslashreversedanim) {
- animTarget = rollanim;
- frameTarget = 5;
- oldcoords = coords;
- coords += (DoRotation(jointPos(leftfoot), 0, yaw, 0) + DoRotation(jointPos(rightfoot), 0, yaw, 0)) / 2 * scale;
- coords.y = oldcoords.y;
- }
- if (animCurrent == knifeslashreversedanim) {
- animTarget = rollanim;
- frameTarget = 0;
- targetyaw += 90;
- yaw += 90;
- oldcoords = coords;
- coords += (DoRotation(jointPos(leftfoot), 0, yaw, 0) + DoRotation(jointPos(rightfoot), 0, yaw, 0)) / 2 * scale;
- coords.y = oldcoords.y;
- }
- }
- if (wasFlip()) {
- animTarget = jumpdownanim;
- }
- if (wasLanding())
- animTarget = getIdle();
- if (wasLandhard())
- animTarget = getIdle();
- if (animCurrent == spinkickanim || animCurrent == getupfrombackanim || animCurrent == getupfromfrontanim || animCurrent == lowkickanim) {
- animTarget = getIdle();
- oldcoords = coords;
- coords += (DoRotation(jointPos(leftfoot), 0, yaw, 0) + DoRotation(jointPos(rightfoot), 0, yaw, 0)) / 2 * scale;
- coords.y = oldcoords.y;
- //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::animations[animCurrent].offset * -1, 0, yaw, 0) * scale;
- currentoffset.y -= (coords.y - targetoffset.y);
- coords.y = targetoffset.y;
- targetoffset = 0;
- normalsupdatedelay = 0;
- }
- if (animCurrent == upunchanim) {
- animTarget = getStop();
- normalsupdatedelay = 0;
- lastfeint = 0;
- }
- if (animCurrent == rabbitkickanim && animTarget != backflipanim) {
- targetyaw = yaw;
- bool hasstaff;
- hasstaff = 0;
- if (num_weapons > 0)
- if (weapons[0].getType() == staff)
- hasstaff = 1;
- if (!hasstaff)
- DoDamage(35);
- RagDoll(0);
- lastfeint = 0;
- rabbitkickragdoll = 1;
- }
- if (animCurrent == rabbitkickreversedanim) {
- if (!feint) {
- velocity = 0;
- velocity.y = -10;
- //DoDamage(100);
- RagDoll(0);
- skeleton.spinny = 0;
- SolidHitBonus(!id); // FIXME: tricky id
- }
- if (feint) {
- escapednum++;
- animTarget = rollanim;
- coords += facing;
- if (id == 0)
- pause_sound(whooshsound);
- }
- lastfeint = 0;
- }
- if (animCurrent == rabbittackledbackanim || animCurrent == rabbittackledfrontanim) {
- velocity = 0;
- velocity.y = -10;
- RagDoll(0);
- skeleton.spinny = 0;
- }
- if (animCurrent == jumpreversedanim) {
- if (!feint) {
- velocity = 0;
- velocity.y = -10;
- //DoDamage(100);
- RagDoll(0);
- skeleton.spinny = 0;
- SolidHitBonus(!id); // FIXME: tricky id
- }
- if (feint) {
- escapednum++;
- animTarget = rollanim;
- coords += facing * 2;
- if (id == 0)
- pause_sound(whooshsound);
- }
- lastfeint = 0;
- }
-
- 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::animations[animCurrent].attack == normalattack) {
- animTarget = getIdle();
- lastfeint = 0;
- }
- if (animCurrent == blockhighleftanim && aitype != playercontrolled) {
- animTarget = blockhighleftstrikeanim;
- }
- if (animCurrent == knifeslashstartanim || animCurrent == knifethrowanim || animCurrent == swordslashanim || animCurrent == staffhitanim || animCurrent == staffgroundsmashanim || animCurrent == staffspinhitanim) {
- animTarget = getIdle();
- lastfeint = 0;
- }
- if (animCurrent == spinkickanim && victim->skeleton.free) {
- if (creature == rabbittype)
- animTarget = fightidleanim;
- }
- }
- target = 0;
-
- if (isIdle() && !wasIdle())
- normalsupdatedelay = 0;
-
- if (animCurrent == jumpupanim && velocity.y < 0 && !isFlip()) {
- animTarget = jumpdownanim;
- }
- }
- if (!skeleton.free) {
- oldtarget = target;
- if (!transspeed && Animation::animations[animTarget].attack != 2 && Animation::animations[animTarget].attack != 3) {
- if (!isRun() || !wasRun()) {
- if (targetFrame().speed > currentFrame().speed)
- target += multiplier * targetFrame().speed * speed * 2;
- if (targetFrame().speed <= currentFrame().speed)
- target += multiplier * currentFrame().speed * speed * 2;
- }
- if (isRun() && wasRun()) {
- float tempspeed;
- tempspeed = velspeed;
- if (tempspeed < 10 * speedmult)
- tempspeed = 10 * speedmult;
- /* FIXME - mixed of target and current here, is that intended? */
- target += multiplier * Animation::animations[animTarget].frames[frameCurrent].speed * speed * 1.7 * tempspeed / (speed * 45 * scale);
- }
- } else if (transspeed)
- target += multiplier * transspeed * speed * 2;
- else {
- if (!isRun() || !wasRun()) {
- if (targetFrame().speed > currentFrame().speed)
- target += multiplier * targetFrame().speed * 2;
- if (targetFrame().speed <= currentFrame().speed)
- target += multiplier * currentFrame().speed * 2;
- }
- }
-
- if (animCurrent != animTarget)
- target = (target + oldtarget) / 2;
-
- if (target > 1) {
- frameCurrent = frameTarget;
- target = 1;
- }
- oldrot = rot;
- rot = targetrot * target;
- yaw += rot - oldrot;
- if (target == 1) {
- rot = 0;
- oldrot = 0;
- targetrot = 0;
- }
- if (frameCurrent >= Animation::animations[animCurrent].frames.size()) {
- frameCurrent = Animation::animations[animCurrent].frames.size() - 1;
- }
- if (animCurrent != oldanimCurrent || animTarget != oldanimTarget || ((frameCurrent != oldframeCurrent || frameTarget != oldframeTarget) && !calcrot)) {
- //Old rotates
- for (int i = 0; i < skeleton.joints.size(); i++) {
- skeleton.joints[i].position = currentFrame().joints[i].position;
- }
-
- skeleton.FindForwards();
-
- for (int i = 0; i < skeleton.muscles.size(); i++) {
- if (skeleton.muscles[i].visible) {
- skeleton.FindRotationMuscle(i, animTarget);
- }
- }
- for (int i = 0; i < skeleton.muscles.size(); i++) {
- if (skeleton.muscles[i].visible) {
- if (isnormal((float)((int)(skeleton.muscles[i].rotate1 * 100) % 36000) / 100))
- skeleton.muscles[i].oldrotate1 = (float)((int)(skeleton.muscles[i].rotate1 * 100) % 36000) / 100;
- if (isnormal((float)((int)(skeleton.muscles[i].rotate2 * 100) % 36000) / 100))
- skeleton.muscles[i].oldrotate2 = (float)((int)(skeleton.muscles[i].rotate2 * 100) % 36000) / 100;
- if (isnormal((float)((int)(skeleton.muscles[i].rotate3 * 100) % 36000) / 100))
- skeleton.muscles[i].oldrotate3 = (float)((int)(skeleton.muscles[i].rotate3 * 100) % 36000) / 100;
- }
- }
-
- //New rotates
- for (int i = 0; i < skeleton.joints.size(); i++) {
- skeleton.joints[i].position = targetFrame().joints[i].position;
- }
-
- skeleton.FindForwards();
-
- for (int i = 0; i < skeleton.muscles.size(); i++) {
- if (skeleton.muscles[i].visible) {
- skeleton.FindRotationMuscle(i, animTarget);
- }
- }
- for (int i = 0; i < skeleton.muscles.size(); i++) {
- if (skeleton.muscles[i].visible) {
- if (isnormal((float)((int)(skeleton.muscles[i].rotate1 * 100) % 36000) / 100))
- skeleton.muscles[i].newrotate1 = (float)((int)(skeleton.muscles[i].rotate1 * 100) % 36000) / 100;
- if (isnormal((float)((int)(skeleton.muscles[i].rotate2 * 100) % 36000) / 100))
- skeleton.muscles[i].newrotate2 = (float)((int)(skeleton.muscles[i].rotate2 * 100) % 36000) / 100;
- if (isnormal((float)((int)(skeleton.muscles[i].rotate3 * 100) % 36000) / 100))
- skeleton.muscles[i].newrotate3 = (float)((int)(skeleton.muscles[i].rotate3 * 100) % 36000) / 100;
- if (skeleton.muscles[i].newrotate3 > skeleton.muscles[i].oldrotate3 + 180) skeleton.muscles[i].newrotate3 -= 360;
- if (skeleton.muscles[i].newrotate3 < skeleton.muscles[i].oldrotate3 - 180) skeleton.muscles[i].newrotate3 += 360;
- if (skeleton.muscles[i].newrotate2 > skeleton.muscles[i].oldrotate2 + 180) skeleton.muscles[i].newrotate2 -= 360;
- if (skeleton.muscles[i].newrotate2 < skeleton.muscles[i].oldrotate2 - 180) skeleton.muscles[i].newrotate2 += 360;
- if (skeleton.muscles[i].newrotate1 > skeleton.muscles[i].oldrotate1 + 180) skeleton.muscles[i].newrotate1 -= 360;
- if (skeleton.muscles[i].newrotate1 < skeleton.muscles[i].oldrotate1 - 180) skeleton.muscles[i].newrotate1 += 360;
- }
- }
- }
-
- oldanimCurrent = animCurrent;
- oldanimTarget = animTarget;
- oldframeTarget = frameTarget;
- oldframeCurrent = frameCurrent;
-
- for (int i = 0; i < skeleton.joints.size(); i++) {
- skeleton.joints[i].velocity = (currentFrame().joints[i].position * (1 - target) + targetFrame().joints[i].position * (target) - skeleton.joints[i].position) / multiplier;
- skeleton.joints[i].position = currentFrame().joints[i].position * (1 - target) + targetFrame().joints[i].position * (target);
- }
- offset = currentoffset * (1 - target) + targetoffset * target;
- for (int i = 0; i < skeleton.muscles.size(); i++) {
- if (skeleton.muscles[i].visible) {
- skeleton.muscles[i].rotate1 = skeleton.muscles[i].oldrotate1 * (1 - target) + skeleton.muscles[i].newrotate1 * (target);
- skeleton.muscles[i].rotate2 = skeleton.muscles[i].oldrotate2 * (1 - target) + skeleton.muscles[i].newrotate2 * (target);
- skeleton.muscles[i].rotate3 = skeleton.muscles[i].oldrotate3 * (1 - target) + skeleton.muscles[i].newrotate3 * (target);
- }
- }
- }
-
- if (isLanding() && landhard) {
- if (id == 0)
- camerashake += .4;
- animTarget = getLandhard();
- frameTarget = 0;
- target = 0;
- landhard = 0;
- transspeed = 15;
- }
- }
-}
-
-/* EFFECT
- * MONSTER
- * TODO
- */
-void Person::DoStuff()
-{
- static XYZ terrainnormal;
- static XYZ flatfacing;
- static XYZ flatvelocity;
- static float flatvelspeed;
- static int i, j, l;
- static XYZ average;
- static int howmany;
- static int bloodsize;
- static int startx, starty, endx, endy;
- static GLubyte color;
- static XYZ bloodvel;
-
- onfiredelay -= multiplier;
- if (onfiredelay < 0 && onfire) {
- if (Random() % 2 == 0) {
- crouchkeydown = 1;
- }
- onfiredelay = 0.3;
- }
-
- crouchkeydowntime += multiplier;
- if (!crouchkeydown)
- crouchkeydowntime = 0;
- jumpkeydowntime += multiplier;
- if (!jumpkeydown && skeleton.free)
- jumpkeydowntime = 0;
-
- if (hostile || damage > 0 || bloodloss > 0)
- immobile = 0;
-
- if (isIdle() || isRun())
- targetoffset = 0;
-
- if (num_weapons == 1 && weaponactive != -1)
- weaponstuck = -1;
-
- if (id == 0)
- blooddimamount -= multiplier * .3;
- speechdelay -= multiplier;
- texupdatedelay -= multiplier;
- interestdelay -= multiplier;
- flamedelay -= multiplier;
- parriedrecently -= multiplier;
- if (!victim) {
- victim = this->shared_from_this();
- hasvictim = 0;
- }
-
- if (id == 0)
- speed = 1.1 * speedmult;
- else
- speed = 1.0 * speedmult;
- if (!skeleton.free)
- rabbitkickragdoll = 0;
-
- speed *= speedmult;
-
- if (id != 0 && (creature == rabbittype || difficulty != 2))
- superruntoggle = 0;
- if (id != 0 && creature == wolftype && difficulty == 2) {
- superruntoggle = 0;
- if (aitype != passivetype) {
- superruntoggle = 1;
- if (aitype == attacktypecutoff && (Person::players[0]->isIdle() || Person::players[0]->isCrouch() || Person::players[0]->skeleton.free || Person::players[0]->animTarget == getupfrombackanim || Person::players[0]->animTarget == getupfromfrontanim || Person::players[0]->animTarget == sneakanim) && distsq(&coords, &Person::players[0]->coords) < 16) {
- superruntoggle = 0;
- }
- }
- if (scale < 0.2)
- superruntoggle = 0;
- if (animTarget == wolfrunninganim && !superruntoggle) {
- animTarget = getRun();
- frameTarget = 0;
- }
- }
- if (weaponactive == -1 && num_weapons > 0) {
- if (weapons[weaponids[0]].getType() == staff) {
- weaponactive = 0;
- }
- }
-
- if (onfire) {
- burnt += multiplier;
- deathbleeding = 1;
- if (burnt > .6)
- burnt = .6;
- OPENAL_SetVolume(channels[stream_firesound], 256 + 256 * findLength(&velocity) / 3);
-
- if (animTarget == jumpupanim || animTarget == jumpdownanim || isFlip()) {
- float gLoc[3];
- float vel[3];
- gLoc[0] = coords.x;
- gLoc[1] = coords.y;
- gLoc[2] = coords.z;
- vel[0] = velocity.x;
- vel[1] = velocity.y;
- vel[2] = velocity.z;
-
- if (id == 0) {
- OPENAL_3D_SetAttributes(channels[whooshsound], gLoc, vel);
- OPENAL_SetVolume(channels[whooshsound], 64 * findLength(&velocity) / 5);
- }
- }
- }
- while (flamedelay < 0 && onfire) {
- flamedelay += .006;
- howmany = abs(Random() % (skeleton.joints.size()));
- if (skeleton.free) {
- flatvelocity = skeleton.joints[howmany].velocity * scale / 2;
- flatfacing = skeleton.joints[howmany].position * scale + coords;
- } else {
- flatfacing = DoRotation(DoRotation(DoRotation(skeleton.joints[howmany].position, 0, 0, tilt), tilt2, 0, 0), 0, yaw, 0) * scale + coords;
- flatvelocity = (coords - oldcoords) / multiplier / 2;
- }
- Sprite::MakeSprite(flamesprite, flatfacing, flatvelocity, 1, 1, 1, .6 + (float)abs(Random() % 100) / 200 - .25, 1);
- }
-
- while (flamedelay < 0 && !onfire && tutoriallevel == 1 && id != 0) {
- flamedelay += .05;
- howmany = abs(Random() % (skeleton.joints.size()));
- if (skeleton.free) {
- flatvelocity = skeleton.joints[howmany].velocity * scale / 2;
- flatfacing = skeleton.joints[howmany].position * scale + coords;
- } else {
- flatvelocity = (coords - oldcoords) / multiplier / 2;
- flatfacing = DoRotation(DoRotation(DoRotation(skeleton.joints[howmany].position, 0, 0, tilt), tilt2, 0, 0), 0, yaw, 0) * scale + coords;
- }
- Sprite::MakeSprite(breathsprite, flatfacing, flatvelocity, 1, 1, 1, .6 + (float)abs(Random() % 100) / 200 - .25, .3);
- }
-
- if (bleeding > 0) {
- bleeding -= multiplier * .3;
- if (bloodtoggle == 2) {
- skeleton.drawmodel.textureptr.bind();
- if ((bleeding <= 0) && (detail != 2))
- DoMipmaps();
- }
- }
-
- if (neckspurtamount > 0) {
- neckspurtamount -= multiplier;
- neckspurtdelay -= multiplier * 3;
- neckspurtparticledelay -= multiplier * 3;
- if (neckspurtparticledelay < 0 && neckspurtdelay > 2) {
- spurt = 0;
- bloodvel = 0;
- if (skeleton.free) {
- bloodvel -= DoRotation(skeleton.forward * 10 * scale, ((float)(Random() % 100)) / 40, ((float)(Random() % 100)) / 40, 0);
- bloodvel += DoRotation(jointVel(head), ((float)(Random() % 100)) / 40, yaw + ((float)(Random() % 100)) / 40, 0) * scale;
- Sprite::MakeSprite(bloodsprite, (jointPos(neck) + (jointPos(neck) - jointPos(head)) / 5)*scale + coords, bloodvel, 1, 1, 1, .05, .9);
- } else {
- bloodvel.z = 5 * neckspurtamount;
- bloodvel = DoRotation(bloodvel, ((float)(Random() % 100)) / 40, yaw + ((float)(Random() % 100)) / 40, 0) * scale;
- bloodvel += DoRotation(velocity, ((float)(Random() % 100)) / 40, ((float)(Random() % 100)) / 40, 0) * scale;
- Sprite::MakeSprite(bloodsprite, DoRotation(jointPos(neck) + (jointPos(neck) - jointPos(head)) / 5, 0, yaw, 0)*scale + coords, bloodvel, 1, 1, 1, .05, .9);
- }
- neckspurtparticledelay = .05;
- }
- if (neckspurtdelay < 0) {
- neckspurtdelay = 3;
- }
- }
-
- if (deathbleeding > 0 && dead != 2) {
- if (deathbleeding < 5)
- bleeddelay -= deathbleeding * multiplier / 4;
- else
- bleeddelay -= 5 * multiplier / 4;
- if (bleeddelay < 0 && bloodtoggle) {
- bleeddelay = 1;
- XYZ bloodvel;
- if (bloodtoggle) {
- bloodvel = 0;
- if (skeleton.free) {
- bloodvel += DoRotation(jointVel(abdomen), ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
- Sprite::MakeSprite(bloodsprite, jointPos(abdomen) * scale + coords, bloodvel, 1, 1, 1, .05, 1);
- } else {
- bloodvel += DoRotation(velocity, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0) * scale;
- Sprite::MakeSprite(bloodsprite, DoRotation((jointPos(abdomen) + jointPos(abdomen)) / 2, 0, yaw, 0)*scale + coords, bloodvel, 1, 1, 1, .05, 1);
- }
- }
- }
- bloodloss += deathbleeding * multiplier * 80;
- deathbleeding -= multiplier * 1.6;
- if (deathbleeding < 0)
- deathbleeding = 0;
- 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;
- num_weapons--;
- if (num_weapons) {
- weaponids[0] = weaponids[num_weapons];
- if (weaponstuck == num_weapons)
- weaponstuck = 0;
- }
- weaponactive = -1;
- for (unsigned i = 0; i < Person::players.size(); i++) {
- Person::players[i]->wentforweapon = 0;
- }
-
- if (id == 0) {
- Game::flash(.5, 0);
- }
- }
-
- if (!dead && creature == wolftype) {
- award_bonus(0, Wolfbonus);
- }
- dead = 2;
- if (animTarget == knifefollowedanim && !skeleton.free) {
- for (int i = 0; i < skeleton.joints.size(); i++) {
- skeleton.joints[i].velocity = 0;
- skeleton.joints[i].velocity.y = -2;
- }
- }
- if (id != 0 && unconscioustime > .1) {
- numafterkill++;
- }
-
- RagDoll(0);
- }
- }
-
- if (texupdatedelay < 0 && bleeding > 0 && bloodtoggle == 2 && distsq(&viewer, &coords) < 9) {
- texupdatedelay = .12;
-
- bloodsize = 5 - realtexdetail;
-
- startx = 0;
- starty = 0;
- startx = bleedy; //abs(Random()%(skeleton.skinsize-bloodsize-1));
- starty = bleedx; //abs(Random()%(skeleton.skinsize-bloodsize-1));
- endx = startx + bloodsize;
- endy = starty + bloodsize;
-
- if (startx < 0) {
- startx = 0;
- bleeding = 0;
- }
- if (starty < 0) {
- starty = 0;
- bleeding = 0;
- }
- if (endx > skeleton.skinsize - 1) {
- endx = skeleton.skinsize - 1;
- bleeding = 0;
- }
- if (endy > skeleton.skinsize - 1) {
- endy = skeleton.skinsize - 1;
- bleeding = 0;
- }
- if (endx < startx)
- endx = startx;
- if (endy < starty)
- endy = starty;
-
- for (i = startx; i < endx; i++) {
- for (j = starty; j < endy; j++) {
- if (Random() % 2 == 0) {
- color = Random() % 85 + 170;
- if (skeleton.skinText[i * skeleton.skinsize * 3 + j * 3 + 0] > color / 2)
- skeleton.skinText[i * skeleton.skinsize * 3 + j * 3 + 0] = color / 2;
- skeleton.skinText[i * skeleton.skinsize * 3 + j * 3 + 1] = 0;
- skeleton.skinText[i * skeleton.skinsize * 3 + j * 3 + 2] = 0;
- }
- }
- }
- if (detail > 1) {
- skeleton.drawmodel.textureptr.bind();
- DoMipmaps();
- }
-
- if (skeleton.free) {
- bleedx += 4 * direction / realtexdetail;
- if (detail == 2)
- bleedy += (abs(Random() % 3) - 1) * 2 / realtexdetail;
- else
- bleedy += (abs(Random() % 3) - 1) * 4 / realtexdetail;
- } else {
- bleedy -= 4 / realtexdetail;
- if (detail == 2)
- bleedx += (abs(Random() % 3) - 1) * 2 / realtexdetail;
- else
- bleedx += (abs(Random() % 3) - 1) * 4 / realtexdetail;
- }
- }
-
- if (abs(righthandmorphness - targetrighthandmorphness) < multiplier * 4) {
- righthandmorphness = targetrighthandmorphness;
- righthandmorphstart = righthandmorphend;
- } else if (righthandmorphness > targetrighthandmorphness) {
- righthandmorphness -= multiplier * 4;
- } else if (righthandmorphness < targetrighthandmorphness) {
- righthandmorphness += multiplier * 4;
- }
-
- if (abs(lefthandmorphness - targetlefthandmorphness) < multiplier * 4) {
- lefthandmorphness = targetlefthandmorphness;
- lefthandmorphstart = lefthandmorphend;
- } else if (lefthandmorphness > targetlefthandmorphness) {
- lefthandmorphness -= multiplier * 4;
- } else if (lefthandmorphness < targetlefthandmorphness) {
- lefthandmorphness += multiplier * 4;
- }
-
- if (creature == rabbittype || targettailmorphness == 5 || targettailmorphness == 0) {
- if (abs(tailmorphness - targettailmorphness) < multiplier * 10) {
- tailmorphness = targettailmorphness;
- tailmorphstart = tailmorphend;
- } else if (tailmorphness > targettailmorphness) {
- tailmorphness -= multiplier * 10;
- } else if (tailmorphness < targettailmorphness) {
- tailmorphness += multiplier * 10;
- }
- }
-
- if (creature == wolftype) {
- if (abs(tailmorphness - targettailmorphness) < multiplier * 4) {
- tailmorphness = targettailmorphness;
- tailmorphstart = tailmorphend;
- } else if (tailmorphness > targettailmorphness) {
- tailmorphness -= multiplier * 2;
- } else if (tailmorphness < targettailmorphness) {
- tailmorphness += multiplier * 2;
- }
- }
-
- if (headmorphend == 3 || headmorphstart == 3) {
- if (abs(headmorphness - targetheadmorphness) < multiplier * 7) {
- headmorphness = targetheadmorphness;
- headmorphstart = headmorphend;
- } else if (headmorphness > targetheadmorphness) {
- headmorphness -= multiplier * 7;
- } else if (headmorphness < targetheadmorphness) {
- headmorphness += multiplier * 7;
- }
- } else if (headmorphend == 5 || headmorphstart == 5) {
- if (abs(headmorphness - targetheadmorphness) < multiplier * 10) {
- headmorphness = targetheadmorphness;
- headmorphstart = headmorphend;
- } else if (headmorphness > targetheadmorphness) {
- headmorphness -= multiplier * 10;
- } else if (headmorphness < targetheadmorphness) {
- headmorphness += multiplier * 10;
- }
- } else {
- if (abs(headmorphness - targetheadmorphness) < multiplier * 4) {
- headmorphness = targetheadmorphness;
- headmorphstart = headmorphend;
- } else if (headmorphness > targetheadmorphness) {
- headmorphness -= multiplier * 4;
- } else if (headmorphness < targetheadmorphness) {
- headmorphness += multiplier * 4;
- }
- }
-
- if (abs(chestmorphness - targetchestmorphness) < multiplier) {
- chestmorphness = targetchestmorphness;
- chestmorphstart = chestmorphend;
- } else if (chestmorphness > targetchestmorphness) {
- chestmorphness -= multiplier;
- } else if (chestmorphness < targetchestmorphness) {
- chestmorphness += multiplier;
- }
-
- if (dead != 2 && howactive <= typesleeping) {
- if (chestmorphstart == 0 && chestmorphend == 0) {
- chestmorphness = 0;
- targetchestmorphness = 1;
- chestmorphend = 3;
- }
- if (chestmorphstart != 0 && chestmorphend != 0) {
- chestmorphness = 0;
- targetchestmorphness = 1;
- chestmorphend = 0;
- if (environment == snowyenvironment) {
- XYZ footpoint;
- XYZ footvel;
- if (skeleton.free) {
- footvel = skeleton.specialforward[0] * -1;
- footpoint = ((jointPos(head) + jointPos(neck)) / 2) * scale + coords;
- } else {
- footvel = DoRotation(skeleton.specialforward[0], 0, yaw, 0) * -1;
- footpoint = DoRotation((jointPos(head) + jointPos(neck)) / 2, 0, yaw, 0) * scale + coords;
- }
- if (animTarget == sleepanim)
- footvel = DoRotation(footvel, 0, 90, 0);
- Sprite::MakeSprite(breathsprite, footpoint + footvel * .2, footvel * .4, 1, 1, 1, .4, .3);
- }
- }
-
- if (!dead && howactive < typesleeping) {
- blinkdelay -= multiplier * 2;
- if (headmorphstart == 0 && headmorphend == 0 && blinkdelay <= 0) {
- headmorphness = 0;
- targetheadmorphness = 1;
- headmorphend = 3;
- blinkdelay = (float)(abs(Random() % 40)) / 5;
- }
- if (headmorphstart == 3 && headmorphend == 3) {
- headmorphness = 0;
- targetheadmorphness = 1;
- headmorphend = 0;
- }
- }
- if (!dead) {
- twitchdelay -= multiplier * 1.5;
- if (animTarget != hurtidleanim) {
- if (headmorphstart == 0 && headmorphend == 0 && twitchdelay <= 0) {
- headmorphness = 0;
- targetheadmorphness = 1;
- headmorphend = 5;
- twitchdelay = (float)(abs(Random() % 40)) / 5;
- }
- if (headmorphstart == 5 && headmorphend == 5) {
- headmorphness = 0;
- targetheadmorphness = 1;
- headmorphend = 0;
- }
- }
- if ((isIdle() || isCrouch()) && animTarget != hurtidleanim) {
- twitchdelay3 -= multiplier * 1;
- if (Random() % 2 == 0) {
- if (righthandmorphstart == 0 && righthandmorphend == 0 && twitchdelay3 <= 0) {
- righthandmorphness = 0;
- targetrighthandmorphness = 1;
- righthandmorphend = 1;
- if (Random() % 2 == 0)twitchdelay3 = (float)(abs(Random() % 40)) / 5;
- }
- if (righthandmorphstart == 1 && righthandmorphend == 1) {
- righthandmorphness = 0;
- targetrighthandmorphness = 1;
- righthandmorphend = 0;
- }
- }
- if (Random() % 2 == 0) {
- if (lefthandmorphstart == 0 && lefthandmorphend == 0 && twitchdelay3 <= 0) {
- lefthandmorphness = 0;
- targetlefthandmorphness = 1;
- lefthandmorphend = 1;
- twitchdelay3 = (float)(abs(Random() % 40)) / 5;
- }
- if (lefthandmorphstart == 1 && lefthandmorphend == 1) {
- lefthandmorphness = 0;
- targetlefthandmorphness = 1;
- lefthandmorphend = 0;
- }
- }
- }
- }
- if (!dead) {
- if (creature == rabbittype) {
- if (howactive < typesleeping)
- twitchdelay2 -= multiplier * 1.5;
- else
- twitchdelay2 -= multiplier * 0.5;
- if (howactive <= typesleeping) {
- if (tailmorphstart == 0 && tailmorphend == 0 && twitchdelay2 <= 0) {
- tailmorphness = 0;
- targettailmorphness = 1;
- tailmorphend = 1;
- twitchdelay2 = (float)(abs(Random() % 40)) / 5;
- }
- if (tailmorphstart == 1 && tailmorphend == 1) {
- tailmorphness = 0;
- targettailmorphness = 1;
- tailmorphend = 2;
- }
- if (tailmorphstart == 2 && tailmorphend == 2) {
- tailmorphness = 0;
- targettailmorphness = 1;
- tailmorphend = 0;
- }
- }
- }
- }
- }
- if (creature == wolftype) {
- twitchdelay2 -= multiplier * 1.5;
- if (tailmorphend != 0)
- if ((isRun() || animTarget == jumpupanim || animTarget == jumpdownanim || animTarget == backflipanim) && !skeleton.free) {
- tailmorphness = 0;
- targettailmorphness = 1;
- tailmorphend = 0;
- twitchdelay2 = .1;
- }
- if (tailmorphend != 5)
- if (animTarget == flipanim || animTarget == frontflipanim || animTarget == rollanim || skeleton.free) {
- tailmorphness = 0;
- targettailmorphness = 1;
- tailmorphend = 5;
- twitchdelay2 = .1;
- }
- if (twitchdelay2 <= 0) {
- if (((tailmorphstart == 0 && tailmorphend == 0) || (tailmorphstart == 5 && tailmorphend == 5))) {
- tailmorphness = 0;
- targettailmorphness = 1;
- tailmorphend = 1;
- }
- if (tailmorphstart == 1 && tailmorphend == 1) {
- tailmorphness = 0;
- targettailmorphness = 1;
- tailmorphend = 2;
- }
- if (tailmorphstart == 2 && tailmorphend == 2) {
- tailmorphness = 0;
- targettailmorphness = 1;
- tailmorphend = 3;
- }
- if (tailmorphstart == 3 && tailmorphend == 3) {
- tailmorphness = 0;
- targettailmorphness = 1;
- tailmorphend = 4;
- }
- if (tailmorphstart == 4 && tailmorphend == 4) {
- tailmorphness = 0;
- targettailmorphness = 1;
- tailmorphend = 1;
- }
- }
- }
-
- if (dead != 1)
- unconscioustime = 0;
-
- if (dead == 1 || howactive == typesleeping) {
- unconscioustime += multiplier;
- //If unconscious, close eyes and mouth
- if (righthandmorphend != 0)
- righthandmorphness = 0;
- righthandmorphend = 0;
- targetrighthandmorphness = 1;
-
- if (lefthandmorphend != 0)
- lefthandmorphness = 0;
- lefthandmorphend = 0;
- targetlefthandmorphness = 1;
-
- if (headmorphend != 3 && headmorphend != 5)
- headmorphness = 0;
- headmorphend = 3;
- targetheadmorphness = 1;
- }
-
-
- if (howactive > typesleeping) {
- XYZ headpoint;
- headpoint = coords;
- if (bloodtoggle && !bled) {
- terrain.MakeDecal(blooddecalslow, headpoint, .8, .5, 0);
- }
- if (bloodtoggle && !bled)
- for (l = 0; l < terrain.patchobjectnum[whichpatchx][whichpatchz]; l++) {
- j = terrain.patchobjects[whichpatchx][whichpatchz][l];
- XYZ point = DoRotation(headpoint - objects.position[j], 0, -objects.yaw[j], 0);
- float size = .8;
- float opacity = .6;
- float yaw = 0;
- objects.model[j].MakeDecal(blooddecalslow, &point, &size, &opacity, &yaw);
- }
- bled = 1;
- }
-
- if (dead == 2 || howactive > typesleeping) {
- //If dead, open mouth and hands
- if (righthandmorphend != 0)
- righthandmorphness = 0;
- righthandmorphend = 0;
- targetrighthandmorphness = 1;
-
- if (lefthandmorphend != 0)
- lefthandmorphness = 0;
- lefthandmorphend = 0;
- targetlefthandmorphness = 1;
-
- if (headmorphend != 2)
- headmorphness = 0;
- headmorphend = 2;
- targetheadmorphness = 1;
- }
-
- if (stunned > 0 && !dead && headmorphend != 2) {
- if (headmorphend != 4)
- headmorphness = 0;
- headmorphend = 4;
- targetheadmorphness = 1;
- }
-
- if (damage > damagetolerance && !dead) {
-
- dead = 1;
- unconscioustime = 0;
-
- if (creature == wolftype) {
- award_bonus(0, Wolfbonus);
- }
-
- RagDoll(0);
-
- if (weaponactive != -1) {
- weapons[weaponids[0]].drop(velocity * scale * -.3, velocity * scale);
- weapons[weaponids[0]].velocity.x += .01;
- num_weapons--;
- if (num_weapons) {
- weaponids[0] = weaponids[num_weapons];
- if (weaponstuck == num_weapons)
- weaponstuck = 0;
- }
- weaponactive = -1;
- for (unsigned i = 0; i < Person::players.size(); i++) {
- Person::players[i]->wentforweapon = 0;
- }
- }
-
-
-
- if ((id == 0 || distsq(&coords, &viewer) < 50) && autoslomo) {
- slomo = 1;
- slomodelay = .2;
- }
-
- damage += 20;
- }
-
- if (!dead)
- damage -= multiplier * 13;
- if (!dead)
- permanentdamage -= multiplier * 4;
- if (isIdle() || isCrouch()) {
- if (!dead)
- permanentdamage -= multiplier * 4;
- }
- if (damage < 0)
- damage = 0;
- if (permanentdamage < 0)
- permanentdamage = 0;
- if (superpermanentdamage < 0)
- superpermanentdamage = 0;
- if (permanentdamage < superpermanentdamage) {
- permanentdamage = superpermanentdamage;
- }
- if (damage < permanentdamage) {
- damage = permanentdamage;
- }
- if (dead == 1 && damage < damagetolerance) {
- dead = 0;
- skeleton.free = 1;
- damage -= 20;
- for (int i = 0; i < skeleton.joints.size(); i++) {
- skeleton.joints[i].velocity = 0;
- }
- }
- if (permanentdamage > damagetolerance && dead != 2) {
- DoBlood(1, 255);
-
- if (weaponactive != -1) {
- weapons[weaponids[0]].drop(velocity * scale * -.3, velocity * scale);
- weapons[weaponids[0]].velocity.x += .01;
- num_weapons--;
- if (num_weapons) {
- weaponids[0] = weaponids[num_weapons];
- if (weaponstuck == num_weapons)
- weaponstuck = 0;
- }
- weaponactive = -1;
- for (unsigned i = 0; i < Person::players.size(); i++) {
- Person::players[i]->wentforweapon = 0;
- }
- }
-
- bled = 0;
-
- if (!dead && creature == wolftype) {
- award_bonus(0, Wolfbonus);
- }
-
- if (unconscioustime < .1 && (bonus != spinecrusher || bonustime > 1) && (bonus != FinishedBonus || bonustime > 1) && bloodloss < damagetolerance)
- award_bonus(id, touchofdeath);
- if (id != 0 && unconscioustime > .1) {
- numafterkill++;
- }
-
- dead = 2;
-
- skeleton.free = 1;
-
- emit_sound_at(breaksound, coords);
- }
-
- if (skeleton.free == 1) {
- if (id == 0)
- pause_sound(whooshsound);
-
- if (!dead) {
- //If knocked over, open hands and close mouth
- if (righthandmorphend != 0)
- righthandmorphness = 0;
- righthandmorphend = 0;
- targetrighthandmorphness = 1;
-
- if (lefthandmorphend != 0)
- lefthandmorphness = 0;
- lefthandmorphend = 0;
- targetlefthandmorphness = 1;
-
- if (headmorphend != 3 && headmorphend != 5 && headmorphstart != 3 && headmorphstart != 5) {
- if (headmorphend != 0)
- headmorphness = 0;
- headmorphend = 0;
- targetheadmorphness = 1;
- }
- }
-
- skeleton.DoGravity(&scale);
- float damageamount;
- damageamount = skeleton.DoConstraints(&coords, &scale) * 5;
- if (damage > damagetolerance - damageamount && !dead && (bonus != spinecrusher || bonustime > 1) && (bonus != style || bonustime > 1) && (bonus != cannon || bonustime > 1))
- award_bonus(id, deepimpact);
- DoDamage(damageamount / ((protectionhigh + protectionhead + protectionlow) / 3));
-
- average = 0;
- howmany = 0;
- for (j = 0; j < skeleton.joints.size(); j++) {
- average += skeleton.joints[j].position;
- howmany++;
- }
- average /= howmany;
- coords += average * scale;
- for (j = 0; j < skeleton.joints.size(); j++) {
- skeleton.joints[j].position -= average;
- }
- average /= multiplier;
-
- velocity = 0;
- for (int i = 0; i < skeleton.joints.size(); i++) {
- velocity += skeleton.joints[i].velocity * scale;
- }
- velocity /= skeleton.joints.size();
-
- if (!isnormal(velocity.x) && velocity.x) {
- velocity = 0;
- }
-
- if (findLength(&average) < 10 && dead && skeleton.free) {
- skeleton.longdead += (2000 - findLength(&average)) * multiplier + multiplier;
- if (skeleton.longdead > 2000) {
- if (skeleton.longdead > 6000) {
- if (id == 0)
- pause_sound(whooshsound);
- skeleton.free = 3;
- DrawSkeleton();
- skeleton.free = 2;
- }
- if (dead == 2 && bloodloss < damagetolerance) {
- XYZ headpoint;
- headpoint = (jointPos(head) + jointPos(neck)) / 2 * scale + coords;
- DoBlood(1, 255);
- if (bloodtoggle && !bled) {
- terrain.MakeDecal(blooddecal, headpoint, .2 * 1.2, .5, 0);
- }
- if (bloodtoggle && !bled)
- for (l = 0; l < terrain.patchobjectnum[whichpatchx][whichpatchz]; l++) {
- j = terrain.patchobjects[whichpatchx][whichpatchz][l];
- XYZ point = DoRotation(headpoint - objects.position[j], 0, -objects.yaw[j], 0);
- float size = .2 * 1.2;
- float opacity = .6;
- float yaw = 0;
- objects.model[j].MakeDecal(blooddecal, &point, &size, &opacity, &yaw);
- }
- bled = 1;
- }
- if (dead == 2 && bloodloss >= damagetolerance) {
- XYZ headpoint;
- headpoint = (jointPos(abdomen) + jointPos(neck)) / 2 * scale + coords;
- if (bleeding <= 0)
- DoBlood(1, 255);
- if (bloodtoggle && !bled) {
- terrain.MakeDecal(blooddecalslow, headpoint, .8, .5, 0);
- }
- if (bloodtoggle && !bled)
- for (l = 0; l < terrain.patchobjectnum[whichpatchx][whichpatchz]; l++) {
- j = terrain.patchobjects[whichpatchx][whichpatchz][l];
- XYZ point = DoRotation(headpoint - objects.position[j], 0, -objects.yaw[j], 0);
- float size = .8;
- float opacity = .6;
- float yaw = 0;
- objects.model[j].MakeDecal(blooddecalslow, &point, &size, &opacity, &yaw);
- }
- bled = 1;
- }
- }
- }
-
- if (!dead && crouchkeydown && skeleton.freetime > .5 && id == 0 && skeleton.free) {
- bool canrecover = 1;
- XYZ startpoint, endpoint, colpoint, colviewer, coltarget;
- startpoint = coords;
- endpoint = coords;
- endpoint.y -= .7;
- if (terrain.lineTerrain(startpoint, endpoint, &colpoint) != -1)
- canrecover = 0;
- if (velocity.y < -30)
- canrecover = 0;
- for (i = 0; i < objects.numobjects; i++) {
- if (objects.type[i] != treeleavestype && objects.type[i] != bushtype && objects.type[i] != firetype) {
- colviewer = startpoint;
- coltarget = endpoint;
- if (objects.model[i].LineCheck(&colviewer, &coltarget, &colpoint, &objects.position[i], &objects.yaw[i]) != -1)
- canrecover = 0;
- }
- }
- if (canrecover) {
- skeleton.free = 0;
- XYZ middle;
- middle = 0;
-
- terrainnormal = jointPos(groin) - jointPos(abdomen);
- if (joint(groin).locked && joint(abdomen).locked) {
- terrainnormal = jointPos(groin) - jointPos(abdomen);
- middle = (jointPos(groin) + jointPos(abdomen)) / 2;
- }
- if (joint(abdomen).locked && joint(neck).locked) {
- terrainnormal = jointPos(abdomen) - jointPos(neck);
- middle = (jointPos(neck) + jointPos(abdomen)) / 2;
- }
- if (joint(groin).locked && joint(neck).locked) {
- terrainnormal = jointPos(groin) - jointPos(neck);
- middle = (jointPos(groin) + jointPos(neck)) / 2;
- }
- Normalise(&terrainnormal);
-
- targetyaw = -asin(0 - terrainnormal.x);
- targetyaw *= 360 / 6.28;
- if (terrainnormal.z < 0)
- targetyaw = 180 - targetyaw;
- yaw = targetyaw;
-
- frameTarget = 0;
- animTarget = flipanim;
- crouchtogglekeydown = 1;
- target = 0;
- tilt2 = 0;
- targettilt2 = 0;
-
- animCurrent = tempanim;
- frameCurrent = 0;
- target = 0;
-
- for (int i = 0; i < skeleton.joints.size(); i++) {
- tempanimation.frames[0].joints[i].position = skeleton.joints[i].position;
- tempanimation.frames[0].joints[i].position = DoRotation(tempanimation.frames[0].joints[i].position, 0, -yaw, 0);
- }
- }
- }
-
- if (findLength(&average) < 10 && !dead && skeleton.free) {
- skeleton.longdead += (2000 - findLength(&average)) * multiplier + multiplier;
- if (skeleton.longdead > (damage + 500) * 1.5) {
- if (id == 0)
- pause_sound(whooshsound);
- skeleton.free = 0;
- velocity = 0;
- XYZ middle;
- middle = 0;
-
- terrainnormal = jointPos(groin) - jointPos(abdomen);
- if (joint(groin).locked && joint(abdomen).locked) {
- terrainnormal = jointPos(groin) - jointPos(abdomen);
- middle = (jointPos(groin) + jointPos(abdomen)) / 2;
- }
- if (joint(abdomen).locked && joint(neck).locked) {
- terrainnormal = jointPos(abdomen) - jointPos(neck);
- middle = (jointPos(neck) + jointPos(abdomen)) / 2;
- }
- if (joint(groin).locked && joint(neck).locked) {
- terrainnormal = jointPos(groin) - jointPos(neck);
- middle = (jointPos(groin) + jointPos(neck)) / 2;
- }
- Normalise(&terrainnormal);
-
- targetyaw = -asin(0 - terrainnormal.x);
- targetyaw *= 360 / 6.28;
- if (terrainnormal.z < 0)
- targetyaw = 180 - targetyaw;
- yaw = targetyaw;
-
- targettilt2 = asin(terrainnormal.y) * 180 / 3.14 * -1;
-
-
- if (skeleton.forward.y < 0) {
- animTarget = getupfrombackanim;
- frameTarget = 0;
- targettilt2 = 0;
- }
- if (skeleton.forward.y > -.3) {
- animTarget = getupfromfrontanim;
- yaw += 180;
- targetyaw += 180;
- targettilt2 *= -1;
- frameTarget = 0;
- targettilt2 = 0;
- }
-
- if ((Random() % 8 == 0 && id != 0 && creature == rabbittype) || (Random() % 2 == 0 && id != 0 && creature == wolftype) || (id == 0 && crouchkeydown && (forwardkeydown || backkeydown || leftkeydown || rightkeydown))) {
- animTarget = rollanim;
- targetyaw = lookyaw;
- if (id == 0) {
- if (rightkeydown) {
- targetyaw -= 90;
- if (forwardkeydown)
- targetyaw += 45;
- if (backkeydown)
- targetyaw -= 45;
- }
- if (leftkeydown) {
- targetyaw += 90;
- if (forwardkeydown)
- targetyaw -= 45;
- if (backkeydown)
- targetyaw += 45;
- }
- if (backkeydown) {
- if ( !leftkeydown && !rightkeydown)
- targetyaw += 180;
- }
- targetyaw += 180;
- }
- }
-
- if (abs(targettilt2) > 50)
- targettilt2 = 0;
- animCurrent = tempanim;
- frameCurrent = 0;
- target = 0;
- tilt2 = targettilt2;
-
- if (middle.y > 0 && animTarget != rollanim)
- targetoffset.y = middle.y + 1;
-
- for (int i = 0; i < skeleton.joints.size(); i++) {
- tempanimation.frames[0].joints[i].position = skeleton.joints[i].position;
- tempanimation.frames[0].joints[i].position = DoRotation(tempanimation.frames[0].joints[i].position, 0, -yaw, 0);
- }
- }
- }
-
- bool hasstaff;
- hasstaff = 0;
- if (num_weapons > 0)
- if (weapons[0].getType() == staff)
- hasstaff = 1;
- if (!skeleton.freefall && freefall && ((jumpkeydown && jumpkeydowntime < .2) || (hasstaff && rabbitkickragdoll)) && !dead) {
- if (velocity.y > -30) {
- XYZ tempvelocity;
- tempvelocity = velocity;
- Normalise(&tempvelocity);
- targetyaw = -asin(0 - tempvelocity.x);
- targetyaw *= 360 / 6.28;
- if (velocity.z < 0)
- targetyaw = 180 - targetyaw;
- //targetyaw+=180;
-
- skeleton.free = 0;
- if (dotproduct(&skeleton.forward, &tempvelocity) < 0) {
- animTarget = rollanim;
- frameTarget = 2;
- } else {
- animTarget = backhandspringanim;
- targetyaw += 180;
- frameTarget = 6;
- }
- target = 0;
-
- emit_sound_at(movewhooshsound, coords, 128.);
-
- animCurrent = animTarget;
- frameCurrent = frameTarget - 1;
- target = 0;
-
- velocity = 0;
-
- yaw = targetyaw;
- tilt = 0;
- targettilt = 0;
- tilt2 = 0;
- targettilt2 = 0;
- }
- }
- if (skeleton.freefall == 0)
- freefall = 0;
-
- }
-
- if (aitype != passivetype || skeleton.free == 1)
- if (findLengthfast(&velocity) > .1)
- for (i = 0; i < objects.numobjects; i++) {
- if (objects.type[i] == firetype)
- if (distsqflat(&coords, &objects.position[i]) < objects.scale[i]*objects.scale[i] * 12 && distsq(&coords, &objects.position[i]) < objects.scale[i]*objects.scale[i] * 49) {
- if (onfire) {
- if (!objects.onfire[i]) {
- emit_sound_at(firestartsound, objects.position[i]);
- }
- objects.onfire[i] = 1;
- }
- if (!onfire) {
- if (objects.onfire[i]) {
- CatchFire();
- }
- }
- }
- if (objects.type[i] == bushtype)
- if (distsqflat(&coords, &objects.position[i]) < objects.scale[i]*objects.scale[i] * 12 && distsq(&coords, &objects.position[i]) < objects.scale[i]*objects.scale[i] * 49) {
- if (onfire) {
- if (!objects.onfire[i]) {
- emit_sound_at(firestartsound, objects.position[i]);
- }
- objects.onfire[i] = 1;
- }
-
- if (!onfire) {
- if (objects.onfire[i]) {
- CatchFire();
- }
- }
- if (objects.messedwith[i] <= 0) {
- XYZ tempvel;
- XYZ pos;
-
- emit_sound_at(bushrustle, coords, 40 * findLength(&velocity));
-
- if (id == 0) {
- addEnvSound(coords, 4 * findLength(&velocity));
- }
-
- int howmany;
- if (environment == grassyenvironment)
- howmany = findLength(&velocity) * 4;
- if (environment == snowyenvironment)
- howmany = findLength(&velocity) * 2;
- if (detail == 2)
- if (environment != desertenvironment)
- for (j = 0; j < howmany; j++) {
- tempvel.x = float(abs(Random() % 100) - 50) / 20;
- tempvel.y = float(abs(Random() % 100) - 50) / 20;
- tempvel.z = float(abs(Random() % 100) - 50) / 20;
- pos = coords;
- pos.y += 1;
- pos.x += float(abs(Random() % 100) - 50) / 200;
- pos.y += float(abs(Random() % 100) - 50) / 200;
- pos.z += float(abs(Random() % 100) - 50) / 200;
- Sprite::MakeSprite(splintersprite, pos, tempvel * .5 + velocity * float(abs(Random() % 100)) / 100, 165 / 255 + float(abs(Random() % 100) - 50) / 400, 0, 0, .2 + float(abs(Random() % 100) - 50) / 1300, 1);
- Sprite::setLastSpriteSpecial(1);
- }
- howmany = findLength(&velocity) * 4;
- if (detail == 2)
- if (environment == snowyenvironment)
- for (j = 0; j < howmany; j++) {
- tempvel.x = float(abs(Random() % 100) - 50) / 20;
- tempvel.y = float(abs(Random() % 100) - 50) / 20;
- tempvel.z = float(abs(Random() % 100) - 50) / 20;
- pos = coords;
- pos.y += 1;
- pos.x += float(abs(Random() % 100) - 50) / 200;
- pos.y += float(abs(Random() % 100) - 50) / 200;
- pos.z += float(abs(Random() % 100) - 50) / 200;
- Sprite::MakeSprite(splintersprite, pos, tempvel * .3 + velocity * float(abs(Random() % 100)) / 100 / 2, 1, 1, 1, .1, 1);
- Sprite::setLastSpriteSpecial(2);
- }
- }
- objects.rotx[i] += velocity.x * multiplier * 6;
- objects.roty[i] += velocity.z * multiplier * 6;
- objects.messedwith[i] = .5;
- }
- XYZ tempcoord;
- if (objects.type[i] == treeleavestype && environment != desertenvironment) {
- if (objects.pitch[i] == 0)
- tempcoord = coords;
- else {
- tempcoord = coords - objects.position[i];
- tempcoord = DoRotation(tempcoord, 0, -objects.yaw[i], 0);
- tempcoord = DoRotation(tempcoord, -objects.pitch[i], 0, 0);
- tempcoord += objects.position[i];
- }
- if (distsqflat(&tempcoord, &objects.position[i]) < objects.scale[i]*objects.scale[i] * 8 && distsq(&tempcoord, &objects.position[i]) < objects.scale[i]*objects.scale[i] * 300 && tempcoord.y > objects.position[i].y + 3 * objects.scale[i]) {
- if (objects.messedwith[i] <= 0) {
- XYZ tempvel;
- XYZ pos;
-
- emit_sound_at(bushrustle, coords, 40 * findLength(&velocity));
-
- if (id == 0) {
- addEnvSound(coords, 4 * findLength(&velocity));
- }
-
- int howmany;
- if (environment == grassyenvironment)
- howmany = findLength(&velocity) * 4;
- if (environment == snowyenvironment)
- howmany = findLength(&velocity) * 2;
- if (detail == 2)
- if (environment != desertenvironment)
- for (j = 0; j < howmany; j++) {
- tempvel.x = float(abs(Random() % 100) - 50) / 20;
- tempvel.y = float(abs(Random() % 100) - 50) / 20;
- tempvel.z = float(abs(Random() % 100) - 50) / 20;
- pos = coords;
- pos += velocity * .1;
- pos.y += 1;
- pos.x += float(abs(Random() % 100) - 50) / 150;
- pos.y += float(abs(Random() % 100) - 50) / 150;
- pos.z += float(abs(Random() % 100) - 50) / 150;
- Sprite::MakeSprite(splintersprite, pos, tempvel * .5 + velocity * float(abs(Random() % 100)) / 100, 165 / 255 + float(abs(Random() % 100) - 50) / 400, 0, 0, .2 + float(abs(Random() % 100) - 50) / 1300, 1);
- Sprite::setLastSpriteSpecial(1);
- }
- howmany = findLength(&velocity) * 4;
- if (detail == 2)
- if (environment == snowyenvironment)
- for (j = 0; j < howmany; j++) {
- tempvel.x = float(abs(Random() % 100) - 50) / 20;
- tempvel.y = float(abs(Random() % 100) - 50) / 20;
- tempvel.z = float(abs(Random() % 100) - 50) / 20;
- pos = coords;
- pos += velocity * .1;
- pos.y += 1;
- pos.x += float(abs(Random() % 100) - 50) / 150;
- pos.y += float(abs(Random() % 100) - 50) / 150;
- pos.z += float(abs(Random() % 100) - 50) / 150;
- Sprite::MakeSprite(splintersprite, pos, tempvel * .3 + velocity * float(abs(Random() % 100)) / 100 / 2, 1, 1, 1, .1, 1);
- Sprite::setLastSpriteSpecial(2);
- }
- }
- objects.messedwith[i] = .5;
- }
- }
- }
-
- if (!skeleton.free) {
- bool play;
- play = 0;
- if ((stunned > 0 || surprised > 0) && Person::players.size() > 2 && aitype != passivetype)
- play = 1;
- if (hasvictim)
- if (aitype != passivetype && victim->skeleton.free && !victim->dead)
- play = 1;
- if (tutoriallevel == 1 && id != 0)
- play = 0;
- if (play && aitype != playercontrolled) {
- int whichsound = -1;
- i = abs(Random() % 4);
- if (speechdelay <= 0) {
- if (creature == rabbittype) {
- if (i == 0)
- whichsound = rabbitchitter;
- if (i == 1)
- whichsound = rabbitchitter2;
- }
- if (creature == wolftype) {
- if (i == 0)
- whichsound = growlsound;
- if (i == 1)
- whichsound = growl2sound;
- }
- }
- speechdelay = .3;
-
- if (whichsound != -1) {
- emit_sound_at(whichsound, coords);
- }
- }
-
- if (animTarget == staggerbackhighanim)
- staggerdelay = 1;
- if (animTarget == staggerbackhardanim)
- staggerdelay = 1;
- staggerdelay -= multiplier;
- if (animTarget != crouchstabanim && animTarget != swordgroundstabanim && animTarget != staffgroundsmashanim)
- hasvictim = 1;
- if (velocity.y < -30 && animTarget == jumpdownanim)
- RagDoll(0);
- if (animCurrent != getIdle() && wasIdle() && animTarget != getIdle() && isIdle()) {
- animTarget = getIdle();
- frameTarget = 0;
- target = 0;
- }
- weaponmissdelay -= multiplier;
- highreversaldelay -= multiplier;
- lowreversaldelay -= multiplier;
- lastcollide -= multiplier;
- skiddelay -= multiplier;
- if (!isnormal(velocity.x) && velocity.x) {
- velocity = 0;
- }
- if (!isnormal(targettilt) && targettilt) {
- targettilt = 0;
- }
- if (!isnormal(targettilt2) && targettilt2) {
- targettilt2 = 0;
- }
- if (!isnormal(targetyaw) && targetyaw) {
- targetyaw = 0;
- }
-
- if (animTarget == bounceidleanim || animTarget == wolfidle || animTarget == walkanim || animTarget == drawrightanim || animTarget == crouchdrawrightanim || animTarget == drawleftanim || animTarget == fightidleanim || animTarget == fightsidestep || animTarget == hanganim || isCrouch() || animTarget == backhandspringanim) {
- //open hands and close mouth
- if (righthandmorphend != 0 && righthandmorphness == targetrighthandmorphness) {
- righthandmorphness = 0;
- righthandmorphend = 0;
- targetrighthandmorphness = 1;
- }
-
- if (lefthandmorphend != 0 && lefthandmorphness == targetlefthandmorphness) {
- lefthandmorphness = 0;
- lefthandmorphend = 0;
- targetlefthandmorphness = 1;
- }
-
- if (headmorphend != 3 && headmorphend != 5 && headmorphstart != 3 && headmorphstart != 5 && headmorphend != 0 && headmorphness == targetheadmorphness) {
- headmorphness = 0;
- headmorphend = 0;
- targetheadmorphness = 1;
- }
- }
-
- if (animTarget == rollanim || animTarget == dodgebackanim || animTarget == removeknifeanim || animTarget == knifefightidleanim || animTarget == swordfightidleanim || animTarget == blockhighleftstrikeanim || animTarget == crouchremoveknifeanim || animTarget == sneakanim || animTarget == sweepanim || animTarget == spinkickreversedanim || animTarget == jumpdownanim || isWallJump() || isFlip() || animTarget == climbanim || isRun() || animTarget == getupfrombackanim || animTarget == getupfromfrontanim) {
- //open hands and mouth
- if (righthandmorphend != 0 && righthandmorphness == targetrighthandmorphness) {
- righthandmorphness = 0;
- righthandmorphend = 0;
- targetrighthandmorphness = 1;
- }
-
- if (lefthandmorphend != 0 && lefthandmorphness == targetlefthandmorphness) {
- lefthandmorphness = 0;
- lefthandmorphend = 0;
- targetlefthandmorphness = 1;
- }
-
- if (headmorphend != 1 && headmorphness == targetheadmorphness) {
- headmorphness = 0;
- headmorphend = 1;
- targetheadmorphness = 1;
- }
- }
-
- if (animTarget == jumpupanim || animTarget == crouchstabanim || animTarget == swordgroundstabanim || animTarget == swordfightidlebothanim || animTarget == blockhighleftanim) {
- //close hands and mouth
- if (righthandmorphend != 1 && righthandmorphness == targetrighthandmorphness) {
- righthandmorphness = 0;
- righthandmorphend = 1;
- targetrighthandmorphness = 1;
- }
-
- if (lefthandmorphend != 1 && lefthandmorphness == targetlefthandmorphness) {
- lefthandmorphness = 0;
- lefthandmorphend = 1;
- targetlefthandmorphness = 1;
- }
-
- if (headmorphend != 0 && headmorphness == targetheadmorphness) {
- headmorphness = 0;
- headmorphend = 0;
- targetheadmorphness = 1;
- }
- }
-
- if (animTarget == spinkickanim || animTarget == staffspinhitreversalanim || animTarget == staffspinhitreversedanim || animTarget == staffhitreversalanim || animTarget == staffhitreversedanim || animTarget == hurtidleanim || animTarget == winduppunchanim || animTarget == swordslashreversalanim || animTarget == swordslashreversedanim || animTarget == knifeslashreversalanim || animTarget == knifeslashreversedanim || animTarget == knifethrowanim || animTarget == knifefollowanim || animTarget == knifefollowedanim || animTarget == killanim || animTarget == dropkickanim || animTarget == upunchanim || animTarget == knifeslashstartanim || animTarget == swordslashanim || animTarget == staffhitanim || animTarget == staffspinhitanim || animTarget == staffgroundsmashanim || animTarget == spinkickreversalanim || animTarget == sweepreversalanim || animTarget == lowkickanim || animTarget == sweepreversedanim || animTarget == rabbitkickreversalanim || animTarget == rabbitkickreversedanim || animTarget == jumpreversalanim || animTarget == jumpreversedanim) {
- //close hands and yell
- if (righthandmorphend != 1 && righthandmorphness == targetrighthandmorphness) {
- righthandmorphness = 0;
- righthandmorphend = 1;
- targetrighthandmorphness = 1;
- }
-
- if (lefthandmorphend != 1 && lefthandmorphness == targetlefthandmorphness) {
- lefthandmorphness = 0;
- lefthandmorphend = 1;
- targetlefthandmorphness = 1;
- }
-
- if (headmorphend != 2 && headmorphness == targetheadmorphness) {
- headmorphness = 1;
- headmorphend = 2;
- targetheadmorphness = 1;
- }
- }
-
- bool behind;
- behind = 0;
- if (hasvictim) {
- if ((victim != this->shared_from_this()) && !victim->dead && (victim->aitype != passivetype) &&
- (victim->aitype != searchtype) && (aitype != passivetype) &&
- (aitype != searchtype) && (victim->id < Person::players.size())) {
- behind = (normaldotproduct(facing, coords - victim->coords) > 0);
- }
- }
-
- if (!dead && animTarget != hurtidleanim)
- if (behind || animTarget == killanim || animTarget == knifethrowanim || animTarget == knifefollowanim || animTarget == spinkickreversalanim || animTarget == rabbitkickreversedanim || animTarget == jumpreversedanim) {
- if (headmorphend != 4 || headmorphness == targetheadmorphness) {
- headmorphend = 4;
- //headmorphness=1;
- targetheadmorphness = 1;
- }
- }
-
- if (weaponactive != -1) {
- if (weapons[weaponids[weaponactive]].getType() != staff) {
- righthandmorphstart = 1;
- righthandmorphend = 1;
- }
- if (weapons[weaponids[weaponactive]].getType() == staff) {
- righthandmorphstart = 2;
- righthandmorphend = 2;
- }
- targetrighthandmorphness = 1;
- }
-
- terrainnormal = terrain.getNormal(coords.x, coords.z);
-
- if (Animation::animations[animTarget].attack != reversal) {
- if (!isnormal(coords.x))
- coords = oldcoords;
- oldcoords = coords;
- }
-
- flatfacing = 0;
- flatfacing.z = 1;
-
- flatfacing = DoRotation(flatfacing, 0, yaw, 0);
- facing = flatfacing;
- ReflectVector(&facing, terrainnormal);
- Normalise(&facing);
-
- if (isRun() || animTarget == sneakanim || animTarget == rollanim || animTarget == walkanim) {
- if (onterrain)
- targettilt2 = -facing.y * 20;
- else
- targettilt2 = 0;
- }
- onterrain = 0;
- if (!isRun() && !Animation::animations[animTarget].attack && animTarget != getupfromfrontanim && animTarget != getupfrombackanim && animTarget != sneakanim)
- targettilt2 = 0;
- if (animTarget == jumpupanim || animTarget == jumpdownanim || isFlip()) {
- flatvelocity = velocity;
- flatvelocity.y = 0;
- flatvelspeed = findLength(&flatvelocity);
- targettilt = flatvelspeed * fast_sqrt(abs(velocity.y) * .7) * normaldotproduct(DoRotation(flatfacing, 0, -90, 0), flatvelocity);
- targettilt2 = flatvelspeed * fast_sqrt(abs(velocity.y) * .7) * normaldotproduct(flatfacing, flatvelocity);
- if (velocity.y < 0)
- targettilt2 *= -1;
- if (velocity.y < 0)
- targettilt *= -1;
- if (targettilt > 25)
- targettilt = 25;
- if (targettilt < -25)
- targettilt = -25;
- }
-
- if (targettilt2 > 45)
- targettilt2 = 45;
- if (targettilt2 < -45)
- targettilt2 = -45;
- if (abs(tilt2 - targettilt2) < multiplier * 400)
- tilt2 = targettilt2;
- else if (tilt2 > targettilt2) {
- tilt2 -= multiplier * 400;
- } else if (tilt2 < targettilt2) {
- tilt2 += multiplier * 400;
- }
- if (!Animation::animations[animTarget].attack && animTarget != getupfrombackanim && animTarget != getupfromfrontanim) {
- if (tilt2 > 25)
- tilt2 = 25;
- if (tilt2 < -25)
- tilt2 = -25;
- }
-
- if (!isnormal(targettilt) && targettilt) {
- targettilt = 0;
- }
- if (!isnormal(targettilt2) && targettilt2) {
- targettilt2 = 0;
- }
-
- //Running velocity
- if (animTarget == rabbittackleanim) {
- velocity += facing * multiplier * speed * 700 * scale;
- velspeed = findLength(&velocity);
- if (velspeed > speed * 65 * scale) {
- velocity /= velspeed;
- velspeed = speed * 65 * scale;
- velocity *= velspeed;
- }
- velocity.y += gravity * multiplier * 20;
- ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
- velspeed = findLength(&velocity);
- velocity = flatfacing * velspeed;
- }
- if (animTarget != rabbitrunninganim && animTarget != wolfrunninganim) {
- if (isRun() || animTarget == rabbitkickanim) {
- velocity += facing * multiplier * speed * 700 * scale;
- velspeed = findLength(&velocity);
- if (velspeed > speed * 45 * scale) {
- velocity /= velspeed;
- velspeed = speed * 45 * scale;
- velocity *= velspeed;
- }
- velocity.y += gravity * multiplier * 20;
- ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
- velspeed = findLength(&velocity);
- if (velspeed < speed * 30 * scale)
- velspeed = speed * 30 * scale;
- velocity = flatfacing * velspeed;
- }
- } else if (isRun()) {
- velocity += facing * multiplier * speed * 700 * scale;
- velspeed = findLength(&velocity);
- if (creature == rabbittype) {
- if (velspeed > speed * 55 * scale) {
- velocity /= velspeed;
- velspeed = speed * 55 * scale;
- velocity *= velspeed;
- }
- }
- if (creature == wolftype) {
- if (velspeed > speed * 75 * scale) {
- velocity /= velspeed;
- velspeed = speed * 75 * scale;
- velocity *= velspeed;
- }
- }
- velocity.y += gravity * multiplier * 20;
- ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
- velspeed = findLength(&velocity);
- velocity = flatfacing * velspeed;
- }
-
- if (animTarget == rollanim && targetFrame().label != 6) {
- velocity += facing * multiplier * speed * 700 * scale;
- velspeed = findLength(&velocity);
- if (velspeed > speed * 45 * scale) {
- velocity /= velspeed;
- velspeed = speed * 45 * scale;
- velocity *= velspeed;
- }
- velocity.y += gravity * multiplier * 20;
- ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
- velspeed = findLength(&velocity);
- velocity = flatfacing * velspeed;
- }
-
- if (animTarget == sneakanim || animTarget == walkanim) {
- velocity += facing * multiplier * speed * 700 * scale;
- velspeed = findLength(&velocity);
- if (velspeed > speed * 12 * scale) {
- velocity /= velspeed;
- velspeed = speed * 12 * scale;
- velocity *= velspeed;
- }
- velocity.y += gravity * multiplier * 20;
- ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
- velspeed = findLength(&velocity);
- velocity = flatfacing * velspeed;
- }
-
- if ((animTarget == fightidleanim || animTarget == knifefightidleanim) && (animCurrent == bounceidleanim || animCurrent == hurtidleanim)) {
- velocity += facing * multiplier * speed * 700 * scale;
- velspeed = findLength(&velocity);
- if (velspeed > speed * 2 * scale) {
- velocity /= velspeed;
- velspeed = speed * 2 * scale;
- velocity *= velspeed;
- }
- velocity.y += gravity * multiplier * 20;
- ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
- velspeed = findLength(&velocity);
- velocity = flatfacing * velspeed;
- }
-
-
- if ((animTarget == bounceidleanim || animCurrent == hurtidleanim) && (animCurrent == fightidleanim || animCurrent == knifefightidleanim)) {
- velocity -= facing * multiplier * speed * 700 * scale;
- velspeed = findLength(&velocity);
- if (velspeed > speed * 2 * scale) {
- velocity /= velspeed;
- velspeed = speed * 2 * scale;
- velocity *= velspeed;
- }
- velocity.y += gravity * multiplier * 20;
- ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
- velspeed = findLength(&velocity);
- velocity = flatfacing * velspeed * -1;
- }
-
- if (animTarget == fightsidestep) {
- velocity += DoRotation(facing * multiplier * speed * 700 * scale, 0, -90, 0);
- velspeed = findLength(&velocity);
- if (velspeed > speed * 12 * scale) {
- velocity /= velspeed;
- velspeed = speed * 12 * scale;
- velocity *= velspeed;
- }
- velocity.y += gravity * multiplier * 20;
- ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
- velspeed = findLength(&velocity);
- velocity = DoRotation(flatfacing * velspeed, 0, -90, 0);
- }
-
- if (animTarget == staggerbackhighanim) {
- coords -= facing * multiplier * speed * 16 * scale;
- velocity = 0;
- }
- if (animTarget == staggerbackhardanim && Animation::animations[staggerbackhardanim].frames[frameTarget].label != 6) {
- coords -= facing * multiplier * speed * 20 * scale;
- velocity = 0;
- }
-
- if (animTarget == backhandspringanim) {
- //coords-=facing*multiplier*50*scale;
- velocity += facing * multiplier * speed * 700 * scale * -1;
- velspeed = findLength(&velocity);
- if (velspeed > speed * 50 * scale) {
- velocity /= velspeed;
- velspeed = speed * 50 * scale;
- velocity *= velspeed;
- }
- velocity.y += gravity * multiplier * 20;
- ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
- velspeed = findLength(&velocity);
- velocity = flatfacing * velspeed * -1;
- }
- if (animTarget == dodgebackanim) {
- //coords-=facing*multiplier*50*scale;
- velocity += facing * multiplier * speed * 700 * scale * -1;
- velspeed = findLength(&velocity);
- if (velspeed > speed * 60 * scale) {
- velocity /= velspeed;
- velspeed = speed * 60 * scale;
- velocity *= velspeed;
- }
- velocity.y += gravity * multiplier * 20;
- ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
- velspeed = findLength(&velocity);
- velocity = flatfacing * velspeed * -1;
- }
-
- if (animTarget == jumpupanim || animTarget == jumpdownanim || isFlip()) {
- velspeed = findLength(&velocity);
- }
-
-
- if (animTarget == jumpupanim || animTarget == jumpdownanim || isFlip()) {
- velocity.y += gravity * multiplier;
- }
-
- if (animTarget != climbanim && animTarget != hanganim && !isWallJump())
- coords += velocity * multiplier;
-
- if (coords.y < terrain.getHeight(coords.x, coords.z) && (animTarget == jumpdownanim || animTarget == jumpupanim || isFlip())) {
- if (isFlip() && targetFrame().label == 7)
- RagDoll(0);
-
- if (animTarget == jumpupanim) {
- jumppower = -4;
- animTarget = getIdle();
- }
- target = 0;
- frameTarget = 0;
- onterrain = 1;
-
- if (id == 0) {
- pause_sound(whooshsound);
- OPENAL_SetVolume(channels[whooshsound], 0);
- }
-
- if (animTarget == jumpdownanim || isFlip()) {
- if (isFlip())jumppower = -4;
- animTarget = getLanding();
- emit_sound_at(landsound, coords, 128.);
-
- if (id == 0) {
- addEnvSound(coords);
- }
- }
- }
-
- if (animTarget != jumpupanim && animTarget != jumpdownanim && !isFlip() && animTarget != climbanim && animTarget != hanganim && !isWallJump())
- coords.y += gravity * multiplier * 2;
- if (animTarget != jumpupanim && animTarget != jumpdownanim && !isFlip() && coords.y < terrain.getHeight(coords.x, coords.z)) {
- coords.y = terrain.getHeight(coords.x, coords.z);
- onterrain = 1;
- }
-
-
- 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 && targetFrame().label == 6)) {
- velspeed = findLength(&velocity);
- velocity.y = 0;
- if (velspeed < multiplier * 300 * scale) {
- velocity = 0;
- } else
- velocity -= velocity / velspeed * multiplier * 300 * scale;
- if (velspeed > 5 && (isLanding() || isLandhard())) {
- skiddingdelay += multiplier;
- if (skiddelay <= 0) {
- FootLand(leftfoot, .5);
- FootLand(rightfoot, .5);
- skiddelay = .02;
- }
- } else
- skiddingdelay = 0;
- }
-
- if (isLandhard()) {
- velspeed = findLength(&velocity);
- velocity.y = 0;
- if (velspeed < multiplier * 600 * scale) {
- velocity = 0;
- } else
- velocity -= velocity / velspeed * multiplier * 600 * scale;
- velocity = 0;
- if (velspeed > 5 && (isLanding() || isLandhard())) {
- skiddingdelay += multiplier;
- if (skiddelay <= 0) {
- FootLand(leftfoot, .5);
- FootLand(rightfoot, .5);
- skiddelay = .02;
- }
- } else
- skiddingdelay = 0;
- }
-
- if (skiddingdelay < 0)
- skiddingdelay += multiplier;
- if (skiddingdelay > .02 && !forwardkeydown && !backkeydown && !leftkeydown && !rightkeydown && !jumpkeydown && isLanding() && !landhard) {
- skiddingdelay = -1;
- if (!onterrain || environment == grassyenvironment) {
- emit_sound_at(skidsound, coords, 128 * velspeed / 10);
- } else {
- emit_sound_at(snowskidsound, coords, 128 * velspeed / 10);
- }
- }
-
- if (Animation::animations[animTarget].attack == normalattack && animTarget != rabbitkickanim && !victim->skeleton.free) {
- terrainnormal = victim->coords - coords;
- Normalise(&terrainnormal);
- targetyaw = -asin(0 - terrainnormal.x);
- targetyaw *= 360 / 6.28;
- if (terrainnormal.z < 0)
- targetyaw = 180 - targetyaw;
- targettilt2 = -asin(terrainnormal.y) * 360 / 6.28; //*-70;
- }
-
- if (Animation::animations[animTarget].attack == reversal && animTarget != rabbittacklinganim) {
- targetyaw = victim->targetyaw;
- }
- if (animTarget == rabbittacklinganim) {
- coords = victim->coords;
- }
- }
- skeleton.oldfree = skeleton.free;
-
- XYZ midterrain;
- midterrain = 0;
- midterrain.x = terrain.size * terrain.scale / 2;
- midterrain.z = terrain.size * terrain.scale / 2;
- if (distsqflat(&coords, &midterrain) > (terrain.size * terrain.scale / 2 - viewdistance) * (terrain.size * terrain.scale / 2 - viewdistance)) {
- XYZ tempposit;
- tempposit = coords - midterrain;
- tempposit.y = 0;
- Normalise(&tempposit);
- tempposit *= (terrain.size * terrain.scale / 2 - viewdistance);
- coords.x = tempposit.x + midterrain.x;
- coords.z = tempposit.z + midterrain.z;
- }
-}
-
-
-/* EFFECT
- * inverse kinematics helper function
- */
-void IKHelper(Person *p, float interp)
-{
- XYZ point, change, change2;
- float heightleft, heightright;
-
- // TODO: implement localToWorld and worldToLocal
- // but keep in mind it won't be the same math if player is ragdolled or something
- // - localToWorldStanding / worldToLocalStanding (or crouching or...?)
- // then comb through code for places where to use it
-
- // point = localToWorld(jointPos(leftfoot))
- point = DoRotation(p->jointPos(leftfoot), 0, p->yaw, 0) * p->scale + p->coords;
- // adjust height of foot
- heightleft = terrain.getHeight(point.x, point.z) + .04;
- point.y = heightleft;
- change = p->jointPos(leftankle) - p->jointPos(leftfoot);
- change2 = p->jointPos(leftknee) - p->jointPos(leftfoot);
- // jointPos(leftfoot) = interpolate(worldToLocal(point), jointPos(leftfoot), interp)
- p->jointPos(leftfoot) = DoRotation((point - p->coords) / p->scale, 0, -p->yaw, 0) * interp + p->jointPos(leftfoot) * (1 - interp);
- // move ankle along with foot
- p->jointPos(leftankle) = p->jointPos(leftfoot) + change;
- // average knee pos between old and new pos
- p->jointPos(leftknee) = (p->jointPos(leftfoot) + change2) / 2 + (p->jointPos(leftknee)) / 2;
-
- // do same as above for right leg
- point = DoRotation(p->jointPos(rightfoot), 0, p->yaw, 0) * p->scale + p->coords;
- heightright = terrain.getHeight(point.x, point.z) + .04;
- point.y = heightright;
- change = p->jointPos(rightankle) - p->jointPos(rightfoot);
- change2 = p->jointPos(rightknee) - p->jointPos(rightfoot);
- p->jointPos(rightfoot) = DoRotation((point - p->coords) / p->scale, 0, -p->yaw, 0) * interp + p->jointPos(rightfoot) * (1 - interp);
- p->jointPos(rightankle) = p->jointPos(rightfoot) + change;
- p->jointPos(rightknee) = (p->jointPos(rightfoot) + change2) / 2 + (p->jointPos(rightknee)) / 2;
-
- // fix up skeleton now that we've moved body parts?
- p->skeleton.DoConstraints(&p->coords, &p->scale);
-}
-
-/* EFFECT
- * MONSTER
- * TODO: ???
- */
-int Person::DrawSkeleton()
-{
- int oldplayerdetail;
- if ((frustum.SphereInFrustum(coords.x, coords.y + scale * 3, coords.z, scale * 8) && distsq(&viewer, &coords) < viewdistance * viewdistance) || skeleton.free == 3) {
- if (onterrain && (isIdle() || isCrouch() || wasIdle() || wasCrouch()) && !skeleton.free) {
- calcrot = 1;
- }
-
- if (headless) {
- headmorphness = 0;
- headmorphstart = 6;
- headmorphend = 6;
- }
-
- glAlphaFunc(GL_GREATER, 0.0001);
- XYZ terrainlight;
- float terrainheight;
- float distance;
- if (!isnormal(yaw))
- yaw = 0;
- if (!isnormal(tilt))
- tilt = 0;
- if (!isnormal(tilt2))
- tilt2 = 0;
- oldplayerdetail = playerdetail;
- playerdetail = 0;
- if (distsq(&viewer, &coords) < viewdistance * viewdistance / 32 && detail == 2) {
- playerdetail = 1;
- }
- if (distsq(&viewer, &coords) < viewdistance * viewdistance / 128 && detail == 1) {
- playerdetail = 1;
- }
- if (distsq(&viewer, &coords) < viewdistance * viewdistance / 256 && (detail != 1 && detail != 2)) {
- playerdetail = 1;
- }
- if (id == 0)
- playerdetail = 1;
- if (playerdetail != oldplayerdetail) {
- updatedelay = 0;
- normalsupdatedelay = 0;
- }
- static float updatedelaychange;
- static float morphness;
- static float framemult;
- if (calcrot) {
- skeleton.FindForwards();
- if (howactive == typesittingwall) {
- skeleton.specialforward[1] = 0;
- skeleton.specialforward[1].z = 1;
- }
- }
- static XYZ mid;
- static float M[16];
- static int i, j, k;
- static int weaponattachmuscle;
- static int weaponrotatemuscle;
- static XYZ weaponpoint;
- static int start, endthing;
- if ((dead != 2 || skeleton.free != 2) && updatedelay <= 0) {
- if (!isSleeping() && !isSitting()) {
- // TODO: give these meaningful names
- const bool cond1 = (isIdle() || isCrouch() || isLanding() || isLandhard()
- || animTarget == drawrightanim || animTarget == drawleftanim || animTarget == crouchdrawrightanim);
- const bool cond2 = (wasIdle() || wasCrouch() || wasLanding() || wasLandhard()
- || animCurrent == drawrightanim || animCurrent == drawleftanim || animCurrent == crouchdrawrightanim);
-
- if (onterrain && (cond1 && cond2) && !skeleton.free) {
- IKHelper(this, 1);
- if (creature == wolftype)
- IKHelper(this, 1);
- }
-
- if (onterrain && (cond1 && !cond2) && !skeleton.free) {
- IKHelper(this, target);
- if (creature == wolftype)
- IKHelper(this, target);
- }
-
- if (onterrain && (!cond1 && cond2) && !skeleton.free) {
- IKHelper(this, 1 - target);
- if (creature == wolftype)
- IKHelper(this, 1 - target);
- }
- }
-
- if (!skeleton.free && (!Animation::animations[animTarget].attack && animTarget != getupfrombackanim && ((animTarget != rollanim && !isFlip()) || targetFrame().label == 6) && animTarget != getupfromfrontanim && animTarget != wolfrunninganim && animTarget != rabbitrunninganim && animTarget != backhandspringanim && animTarget != walljumpfrontanim && animTarget != hurtidleanim && !isLandhard() && !isSleeping()))
- DoHead();
- else {
- targetheadyaw = -targetyaw;
- targetheadpitch = 0;
- if (Animation::animations[animTarget].attack == 3)
- targetheadyaw += 180;
- }
- for (i = 0; i < skeleton.drawmodel.vertexNum; i++) {
- skeleton.drawmodel.vertex[i] = 0;
- skeleton.drawmodel.vertex[i].y = 999;
- }
- for (i = 0; i < skeleton.drawmodellow.vertexNum; i++) {
- skeleton.drawmodellow.vertex[i] = 0;
- skeleton.drawmodellow.vertex[i].y = 999;
- }
- for (i = 0; i < skeleton.drawmodelclothes.vertexNum; i++) {
- skeleton.drawmodelclothes.vertex[i] = 0;
- skeleton.drawmodelclothes.vertex[i].y = 999;
- }
- for (int i = 0; i < skeleton.muscles.size(); i++) {
- // convenience renames
- const int p1 = skeleton.muscles[i].parent1->label;
- const int p2 = skeleton.muscles[i].parent2->label;
-
- if ((skeleton.muscles[i].vertices.size() > 0 && playerdetail) || (skeleton.muscles[i].verticeslow.size() > 0 && !playerdetail)) {
- morphness = 0;
- start = 0;
- endthing = 0;
-
- if (p1 == righthand || p2 == righthand) {
- morphness = righthandmorphness;
- start = righthandmorphstart;
- endthing = righthandmorphend;
- }
- if (p1 == lefthand || p2 == lefthand) {
- morphness = lefthandmorphness;
- start = lefthandmorphstart;
- endthing = lefthandmorphend;
- }
- if (p1 == head || p2 == head) {
- morphness = headmorphness;
- start = headmorphstart;
- endthing = headmorphend;
- }
- if ((p1 == neck && p2 == abdomen) || (p2 == neck && p1 == abdomen)) {
- morphness = chestmorphness;
- start = chestmorphstart;
- endthing = chestmorphend;
- }
- if ((p1 == groin && p2 == abdomen) || (p2 == groin && p1 == abdomen)) {
- morphness = tailmorphness;
- start = tailmorphstart;
- endthing = tailmorphend;
- }
- if (calcrot)
- skeleton.FindRotationMuscle(i, animTarget);
- mid = (skeleton.muscles[i].parent1->position + skeleton.muscles[i].parent2->position) / 2;
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadIdentity();
- if (!skeleton.free)
- glRotatef(tilt2, 1, 0, 0);
- if (!skeleton.free)
- glRotatef(tilt, 0, 0, 1);
-
-
- glTranslatef(mid.x, mid.y, mid.z);
-
- skeleton.muscles[i].lastrotate1 = skeleton.muscles[i].rotate1;
- glRotatef(-skeleton.muscles[i].lastrotate1 + 90, 0, 1, 0);
-
- skeleton.muscles[i].lastrotate2 = skeleton.muscles[i].rotate2;
- glRotatef(-skeleton.muscles[i].lastrotate2 + 90, 0, 0, 1);
-
- skeleton.muscles[i].lastrotate3 = skeleton.muscles[i].rotate3;
- glRotatef(-skeleton.muscles[i].lastrotate3, 0, 1, 0);
-
- if (playerdetail || skeleton.free == 3) {
- for (j = 0; j < skeleton.muscles[i].vertices.size(); j++) {
- XYZ &v0 = skeleton.model[start].vertex[skeleton.muscles[i].vertices[j]];
- XYZ &v1 = skeleton.model[endthing].vertex[skeleton.muscles[i].vertices[j]];
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- if (p1 == abdomen || p2 == abdomen)
- glTranslatef((v0.x * (1 - morphness) + v1.x * morphness) * proportionbody.x,
- (v0.y * (1 - morphness) + v1.y * morphness) * proportionbody.y,
- (v0.z * (1 - morphness) + v1.z * morphness) * proportionbody.z);
- if (p1 == lefthand || p1 == righthand || p1 == leftwrist || p1 == rightwrist || p1 == leftelbow || p1 == rightelbow || p2 == leftelbow || p2 == rightelbow)
- glTranslatef((v0.x * (1 - morphness) + v1.x * morphness) * proportionarms.x,
- (v0.y * (1 - morphness) + v1.y * morphness) * proportionarms.y,
- (v0.z * (1 - morphness) + v1.z * morphness) * proportionarms.z);
- if (p1 == leftfoot || p1 == rightfoot || p1 == leftankle || p1 == rightankle || p1 == leftknee || p1 == rightknee || p2 == leftknee || p2 == rightknee)
- glTranslatef((v0.x * (1 - morphness) + v1.x * morphness) * proportionlegs.x,
- (v0.y * (1 - morphness) + v1.y * morphness) * proportionlegs.y,
- (v0.z * (1 - morphness) + v1.z * morphness) * proportionlegs.z);
- if (p1 == head || p2 == head)
- glTranslatef((v0.x * (1 - morphness) + v1.x * morphness) * proportionhead.x,
- (v0.y * (1 - morphness) + v1.y * morphness) * proportionhead.y,
- (v0.z * (1 - morphness) + v1.z * morphness) * proportionhead.z);
- glGetFloatv(GL_MODELVIEW_MATRIX, M);
- skeleton.drawmodel.vertex[skeleton.muscles[i].vertices[j]].x = M[12] * scale;
- skeleton.drawmodel.vertex[skeleton.muscles[i].vertices[j]].y = M[13] * scale;
- skeleton.drawmodel.vertex[skeleton.muscles[i].vertices[j]].z = M[14] * scale;
- glPopMatrix();
- }
- }
- if (!playerdetail || skeleton.free == 3) {
- for (j = 0; j < skeleton.muscles[i].verticeslow.size(); j++) {
- XYZ &v0 = skeleton.modellow.vertex[skeleton.muscles[i].verticeslow[j]];
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- if (p1 == abdomen || p2 == abdomen)
- glTranslatef(v0.x * proportionbody.x,
- v0.y * proportionbody.y,
- v0.z * proportionbody.z);
- if (p1 == lefthand || p1 == righthand || p1 == leftwrist || p1 == rightwrist || p1 == leftelbow || p1 == rightelbow || p2 == leftelbow || p2 == rightelbow)
- glTranslatef(v0.x * proportionarms.x,
- v0.y * proportionarms.y,
- v0.z * proportionarms.z);
- if (p1 == leftfoot || p1 == rightfoot || p1 == leftankle || p1 == rightankle || p1 == leftknee || p1 == rightknee || p2 == leftknee || p2 == rightknee)
- glTranslatef(v0.x * proportionlegs.x,
- v0.y * proportionlegs.y,
- v0.z * proportionlegs.z);
- if (p1 == head || p2 == head)
- glTranslatef(v0.x * proportionhead.x,
- v0.y * proportionhead.y,
- v0.z * proportionhead.z);
-
- glGetFloatv(GL_MODELVIEW_MATRIX, M);
- skeleton.drawmodellow.vertex[skeleton.muscles[i].verticeslow[j]].x = M[12] * scale;
- skeleton.drawmodellow.vertex[skeleton.muscles[i].verticeslow[j]].y = M[13] * scale;
- skeleton.drawmodellow.vertex[skeleton.muscles[i].verticeslow[j]].z = M[14] * scale;
- glPopMatrix();
- }
- }
- glPopMatrix();
- }
- if (skeleton.clothes && skeleton.muscles[i].verticesclothes.size() > 0) {
- mid = (skeleton.muscles[i].parent1->position + skeleton.muscles[i].parent2->position) / 2;
-
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadIdentity();
- if (!skeleton.free)
- glRotatef(tilt2, 1, 0, 0);
- if (!skeleton.free)
- glRotatef(tilt, 0, 0, 1);
- glTranslatef(mid.x, mid.y, mid.z);
- skeleton.muscles[i].lastrotate1 = skeleton.muscles[i].rotate1;
- glRotatef(-skeleton.muscles[i].lastrotate1 + 90, 0, 1, 0);
-
- skeleton.muscles[i].lastrotate2 = skeleton.muscles[i].rotate2;
- glRotatef(-skeleton.muscles[i].lastrotate2 + 90, 0, 0, 1);
-
- skeleton.muscles[i].lastrotate3 = skeleton.muscles[i].rotate3;
- glRotatef(-skeleton.muscles[i].lastrotate3, 0, 1, 0);
-
- for (j = 0; j < skeleton.muscles[i].verticesclothes.size(); j++) {
- XYZ &v0 = skeleton.modelclothes.vertex[skeleton.muscles[i].verticesclothes[j]];
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- if (p1 == abdomen || p2 == abdomen)
- glTranslatef(v0.x * proportionbody.x,
- v0.y * proportionbody.y,
- v0.z * proportionbody.z);
- if (p1 == lefthand || p1 == righthand || p1 == leftwrist || p1 == rightwrist || p1 == leftelbow || p1 == rightelbow || p2 == leftelbow || p2 == rightelbow)
- glTranslatef(v0.x * proportionarms.x,
- v0.y * proportionarms.y,
- v0.z * proportionarms.z);
- if (p1 == leftfoot || p1 == rightfoot || p1 == leftankle || p1 == rightankle || p1 == leftknee || p1 == rightknee || p2 == leftknee || p2 == rightknee)
- glTranslatef(v0.x * proportionlegs.x,
- v0.y * proportionlegs.y,
- v0.z * proportionlegs.z);
- if (p1 == head || p2 == head)
- glTranslatef(v0.x * proportionhead.x,
- v0.y * proportionhead.y,
- v0.z * proportionhead.z);
- glGetFloatv(GL_MODELVIEW_MATRIX, M);
- skeleton.drawmodelclothes.vertex[skeleton.muscles[i].verticesclothes[j]].x = M[12] * scale;
- skeleton.drawmodelclothes.vertex[skeleton.muscles[i].verticesclothes[j]].y = M[13] * scale;
- skeleton.drawmodelclothes.vertex[skeleton.muscles[i].verticesclothes[j]].z = M[14] * scale;
- glPopMatrix();
- }
- glPopMatrix();
- }
- updatedelay = 1 + (float)(Random() % 100) / 1000;
- }
- if (skeleton.free != 2 && (skeleton.free == 1 || skeleton.free == 3 || id == 0 || (normalsupdatedelay <= 0) || animTarget == getupfromfrontanim || animTarget == getupfrombackanim || animCurrent == getupfromfrontanim || animCurrent == getupfrombackanim)) {
- normalsupdatedelay = 1;
- if (playerdetail || skeleton.free == 3)
- skeleton.drawmodel.CalculateNormals(0);
- if (!playerdetail || skeleton.free == 3)
- skeleton.drawmodellow.CalculateNormals(0);
- if (skeleton.clothes)
- skeleton.drawmodelclothes.CalculateNormals(0);
- } else {
- if (playerdetail || skeleton.free == 3)
- skeleton.drawmodel.UpdateVertexArrayNoTexNoNorm();
- if (!playerdetail || skeleton.free == 3)
- skeleton.drawmodellow.UpdateVertexArrayNoTexNoNorm();
- if (skeleton.clothes) {
- skeleton.drawmodelclothes.UpdateVertexArrayNoTexNoNorm();
- }
- }
- }
- framemult = .01;
- updatedelaychange = -framemult * 4 * (45 - findDistance(&viewer, &coords) * 1);
- if (updatedelaychange > -realmultiplier * 30)
- updatedelaychange = -realmultiplier * 30;
- if (updatedelaychange > -framemult * 4)
- updatedelaychange = -framemult * 4;
- if (skeleton.free == 1)
- updatedelaychange *= 6;
- if (id == 0)
- updatedelaychange *= 8;
- updatedelay += updatedelaychange;
-
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glTranslatef(coords.x, coords.y - .02, coords.z);
- if (!skeleton.free) {
- glTranslatef(offset.x * scale, offset.y * scale, offset.z * scale);
- glRotatef(yaw, 0, 1, 0);
- }
- if (showpoints) {
- glPointSize(5);
- glColor4f(.4, 1, .4, 1);
- glDisable(GL_LIGHTING);
- glDisable(GL_TEXTURE_2D);
- glBegin(GL_POINTS);
- if (playerdetail)
- for (i = 0; i < skeleton.drawmodel.vertexNum; i++) {
- XYZ &v0 = skeleton.drawmodel.vertex[i];
- glVertex3f(v0.x, v0.y, v0.z);
- }
- glEnd();
- glBegin(GL_LINES);
-
- if (playerdetail)
- for (i = 0; i < skeleton.drawmodel.TriangleNum; i++) {
- XYZ &v0 = skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[i].vertex[0]];
- XYZ &v1 = skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[i].vertex[1]];
- XYZ &v2 = skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[i].vertex[2]];
- glVertex3f(v0.x, v0.y, v0.z);
- glVertex3f(v1.x, v1.y, v1.z);
- glVertex3f(v1.x, v1.y, v1.z);
- glVertex3f(v2.x, v2.y, v2.z);
- glVertex3f(v2.x, v2.y, v2.z);
- glVertex3f(v0.x, v0.y, v0.z);
- }
-
- glEnd();
- }
-
- terrainlight = terrain.getLighting(coords.x, coords.z);
- distance = distsq(&viewer, &coords);
- distance = (viewdistance * viewdistance - (distance - (viewdistance * viewdistance * fadestart)) * (1 / (1 - fadestart))) / viewdistance / viewdistance;
- if (distance > 1)
- distance = 1;
- if (distance > 0) {
- terrainheight = (coords.y - terrain.getHeight(coords.x, coords.z)) / 3 + 1;
- if (terrainheight < 1)
- terrainheight = 1;
- if (terrainheight > 1.7)
- terrainheight = 1.7;
-
- glColor4f((1 - (1 - terrainlight.x) / terrainheight) - burnt, (1 - (1 - terrainlight.y) / terrainheight) - burnt, (1 - (1 - terrainlight.z) / terrainheight) - burnt, distance);
- glDisable(GL_BLEND);
- glAlphaFunc(GL_GREATER, 0.0001);
- glEnable(GL_TEXTURE_2D);
- if (cellophane) {
- glDisable(GL_TEXTURE_2D);
- glColor4f(.7, .35, 0, .5);
- glDepthMask(0);
- glEnable(GL_LIGHTING);
- glEnable(GL_BLEND);
- }
- if (tutoriallevel && id != 0) {
- glColor4f(.7, .7, .7, 0.6);
- glDepthMask(0);
- glEnable(GL_LIGHTING);
- glEnable(GL_BLEND);
- if (canattack && cananger)
- if (Animation::animations[animTarget].attack == normalattack || Animation::animations[animTarget].attack == reversed) {
- glDisable(GL_TEXTURE_2D);
- glColor4f(1, 0, 0, 0.8);
- }
- glMatrixMode(GL_TEXTURE);
- glPushMatrix();
- glTranslatef(0, -smoketex, 0);
- glTranslatef(-smoketex, 0, 0);
- }
- if (playerdetail) {
- if (!showpoints) {
- if ((tutoriallevel && id != 0))
- skeleton.drawmodel.drawdifftex(Sprite::cloudimpacttexture);
- else
- skeleton.drawmodel.draw();
- }
- }
- if (!playerdetail) {
- if ((tutoriallevel && id != 0))
- skeleton.drawmodellow.drawdifftex(Sprite::cloudimpacttexture);
- else
- skeleton.drawmodellow.drawdifftex(skeleton.drawmodel.textureptr);
- }
-
- if (!(Animation::animations[animTarget].attack == normalattack || Animation::animations[animTarget].attack == reversed))
- if (tutoriallevel && id != 0) {
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glEnable(GL_TEXTURE_2D);
- glColor4f(.7, .7, .7, 0.6);
- glDepthMask(0);
- glEnable(GL_LIGHTING);
- glEnable(GL_BLEND);
- if (canattack && cananger)
- if (Animation::animations[animTarget].attack == normalattack || Animation::animations[animTarget].attack == reversed) {
- glDisable(GL_TEXTURE_2D);
- glColor4f(1, 0, 0, 0.8);
- }
- glMatrixMode(GL_TEXTURE);
- glPushMatrix();
- glTranslatef(0, -smoketex * .6, 0);
- glTranslatef(smoketex * .6, 0, 0);
- if (playerdetail) {
- if (!showpoints) {
- if ((tutoriallevel && id != 0))
- skeleton.drawmodel.drawdifftex(Sprite::cloudimpacttexture);
- else
- skeleton.drawmodel.draw();
- }
- }
- if (!playerdetail) {
- if ((tutoriallevel && id != 0))
- skeleton.drawmodellow.drawdifftex(Sprite::cloudimpacttexture);
- else
- skeleton.drawmodellow.drawdifftex(skeleton.drawmodel.textureptr);
- }
- }
-
-
- if (tutoriallevel && id != 0) {
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glEnable(GL_TEXTURE_2D);
- }
- if (skeleton.clothes) {
- glDepthMask(0);
- glEnable(GL_BLEND);
- if (!immediate)
- skeleton.drawmodelclothes.draw();
- if (immediate)
- skeleton.drawmodelclothes.drawimmediate();
- glDepthMask(1);
- }
- }
- glPopMatrix();
-
- if (num_weapons > 0) {
- for (k = 0; k < num_weapons; k++) {
- i = weaponids[k];
- if (weaponactive == k) {
- if (weapons[i].getType() != staff) {
- for (j = 0; j < skeleton.muscles.size(); j++) {
- if ((skeleton.muscles[j].parent1->label == righthand || skeleton.muscles[j].parent2->label == righthand) && skeleton.muscles[j].vertices.size() > 0) {
- weaponattachmuscle = j;
- }
- }
- for (j = 0; j < skeleton.muscles.size(); j++) {
- if ((skeleton.muscles[j].parent1->label == rightwrist || skeleton.muscles[j].parent2->label == rightwrist) && (skeleton.muscles[j].parent1->label != righthand && skeleton.muscles[j].parent2->label != righthand) && skeleton.muscles[j].vertices.size() > 0) {
- weaponrotatemuscle = j;
- }
- }
- weaponpoint = (skeleton.muscles[weaponattachmuscle].parent1->position + skeleton.muscles[weaponattachmuscle].parent2->position) / 2;
- if (creature == wolftype)
- weaponpoint = (jointPos(rightwrist) * .7 + jointPos(righthand) * .3);
- }
- if (weapons[i].getType() == staff) {
- for (j = 0; j < skeleton.muscles.size(); j++) {
- if ((skeleton.muscles[j].parent1->label == righthand || skeleton.muscles[j].parent2->label == righthand) && skeleton.muscles[j].vertices.size() > 0) {
- weaponattachmuscle = j;
- }
- }
- for (j = 0; j < skeleton.muscles.size(); j++) {
- if ((skeleton.muscles[j].parent1->label == rightelbow || skeleton.muscles[j].parent2->label == rightelbow) && (skeleton.muscles[j].parent1->label != rightshoulder && skeleton.muscles[j].parent2->label != rightshoulder) && skeleton.muscles[j].vertices.size() > 0) {
- weaponrotatemuscle = j;
- }
- }
- //weaponpoint=jointPos(rightwrist);
- weaponpoint = (skeleton.muscles[weaponattachmuscle].parent1->position + skeleton.muscles[weaponattachmuscle].parent2->position) / 2;
- //weaponpoint+=skeleton.specialforward[1]*.1+(jointPos(rightwrist)-jointPos(rightelbow));
- XYZ tempnormthing, vec1, vec2;
- vec1 = (jointPos(rightwrist) - jointPos(rightelbow));
- vec2 = (jointPos(rightwrist) - jointPos(rightshoulder));
- CrossProduct(&vec1, &vec2, &tempnormthing);
- Normalise(&tempnormthing);
- if (animTarget != staffhitanim && animCurrent != staffhitanim && animTarget != staffgroundsmashanim && animCurrent != staffgroundsmashanim && animTarget != staffspinhitanim && animCurrent != staffspinhitanim)
- weaponpoint += tempnormthing * .1 - skeleton.specialforward[1] * .3 + (jointPos(rightwrist) - jointPos(rightelbow));
- }
- }
- if (weaponactive != k && weaponstuck != k) {
- if (weapons[i].getType() == knife)
- weaponpoint = jointPos(abdomen) + (jointPos(righthip) - jointPos(lefthip)) * .1 + (jointPos(rightshoulder) - jointPos(leftshoulder)) * .35;
- if (weapons[i].getType() == sword)
- weaponpoint = jointPos(abdomen) + (jointPos(lefthip) - jointPos(righthip)) * .09 + (jointPos(leftshoulder) - jointPos(rightshoulder)) * .33;
- if (weapons[i].getType() == staff)
- weaponpoint = jointPos(abdomen) + (jointPos(lefthip) - jointPos(righthip)) * .09 + (jointPos(leftshoulder) - jointPos(rightshoulder)) * .33;
- for (j = 0; j < skeleton.muscles.size(); j++) {
- if ((skeleton.muscles[j].parent1->label == abdomen || skeleton.muscles[j].parent2->label == abdomen) && (skeleton.muscles[j].parent1->label == neck || skeleton.muscles[j].parent2->label == neck) && skeleton.muscles[j].vertices.size() > 0) {
- weaponrotatemuscle = j;
- }
- }
- }
- if (weaponstuck == k) {
- if (weaponstuckwhere == 0)
- weaponpoint = jointPos(abdomen) * .5 + jointPos(neck) * .5 - skeleton.forward * .8;
- else
- weaponpoint = jointPos(abdomen) * .5 + jointPos(neck) * .5 + skeleton.forward * .8;
- for (j = 0; j < skeleton.muscles.size(); j++) {
- if ((skeleton.muscles[j].parent1->label == abdomen || skeleton.muscles[j].parent2->label == abdomen) && (skeleton.muscles[j].parent1->label == neck || skeleton.muscles[j].parent2->label == neck) && skeleton.muscles[j].vertices.size() > 0) {
- weaponrotatemuscle = j;
- }
- }
- }
- if (skeleton.free) {
- weapons[i].position = weaponpoint * scale + coords;
- weapons[i].bigrotation = 0;
- weapons[i].bigtilt = 0;
- weapons[i].bigtilt2 = 0;
- } else {
- weapons[i].position = DoRotation(DoRotation(DoRotation(weaponpoint, 0, 0, tilt), tilt2, 0, 0), 0, yaw, 0) * scale + coords + currentoffset * (1 - target) * scale + targetoffset * target * scale;
- weapons[i].bigrotation = yaw;
- weapons[i].bigtilt = tilt;
- weapons[i].bigtilt2 = tilt2;
- }
- weapons[i].rotation1 = skeleton.muscles[weaponrotatemuscle].lastrotate1;
- weapons[i].rotation2 = skeleton.muscles[weaponrotatemuscle].lastrotate2;
- weapons[i].rotation3 = skeleton.muscles[weaponrotatemuscle].lastrotate3;
- if (weaponactive == k) {
- if (weapons[i].getType() == knife) {
- weapons[i].smallrotation = 180;
- weapons[i].smallrotation2 = 0;
- if (isCrouch() || wasCrouch()) {
- weapons[i].smallrotation2 = 20;
- }
- if (animTarget == hurtidleanim) {
- weapons[i].smallrotation2 = 50;
- }
- if ((animCurrent == crouchstabanim && animTarget == crouchstabanim) || (animCurrent == backhandspringanim && animTarget == backhandspringanim)) {
- XYZ temppoint1, temppoint2;
- float distance;
-
- temppoint1 = jointPos(righthand);
- temppoint2 = currentFrame().weapontarget * (1 - target) + targetFrame().weapontarget * (target);
- distance = findDistance(&temppoint1, &temppoint2);
- weapons[i].rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
- weapons[i].rotation2 *= 360 / 6.28;
- temppoint1.y = 0;
- temppoint2.y = 0;
- weapons[i].rotation1 = acos((temppoint1.z - temppoint2.z) / findDistance(&temppoint1, &temppoint2));
- weapons[i].rotation1 *= 360 / 6.28;
- weapons[i].rotation3 = 0;
- weapons[i].smallrotation = -90;
- weapons[i].smallrotation2 = 0;
- if (temppoint1.x > temppoint2.x)
- weapons[i].rotation1 = 360 - weapons[i].rotation1;
- }
- if ((animCurrent == knifeslashreversalanim && animTarget == knifeslashreversalanim) || (animCurrent == knifeslashreversedanim && animTarget == knifeslashreversedanim)) {
- XYZ temppoint1, temppoint2;
- float distance;
-
- temppoint1 = jointPos(righthand);
- temppoint2 = currentFrame().weapontarget * (1 - target) + targetFrame().weapontarget * (target);
- distance = findDistance(&temppoint1, &temppoint2);
- weapons[i].rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
- weapons[i].rotation2 *= 360 / 6.28;
- temppoint1.y = 0;
- temppoint2.y = 0;
- weapons[i].rotation1 = acos((temppoint1.z - temppoint2.z) / findDistance(&temppoint1, &temppoint2));
- weapons[i].rotation1 *= 360 / 6.28;
- weapons[i].rotation3 = 0;
- weapons[i].smallrotation = 90;
- weapons[i].smallrotation2 = 0;
- if (temppoint1.x > temppoint2.x)
- weapons[i].rotation1 = 360 - weapons[i].rotation1;
- }
- if (animTarget == knifethrowanim) {
- weapons[i].smallrotation = 90;
- //weapons[i].smallrotation2=-90;
- weapons[i].smallrotation2 = 0;
- weapons[i].rotation1 = 0;
- weapons[i].rotation2 = 0;
- weapons[i].rotation3 = 0;
- }
- if (animTarget == knifesneakattackanim && frameTarget < 5) {
- weapons[i].smallrotation = -90;
- weapons[i].rotation1 = 0;
- weapons[i].rotation2 = 0;
- weapons[i].rotation3 = 0;
- }
- }
- if (weapons[i].getType() == sword) {
- weapons[i].smallrotation = 0;
- weapons[i].smallrotation2 = 0;
- if (animTarget == knifethrowanim) {
- weapons[i].smallrotation = -90;
- weapons[i].smallrotation2 = 0;
- weapons[i].rotation1 = 0;
- weapons[i].rotation2 = 0;
- weapons[i].rotation3 = 0;
- }
- if ((animTarget == swordgroundstabanim && animCurrent == swordgroundstabanim) || (animTarget == swordsneakattackanim && animCurrent == swordsneakattackanim) || (animTarget == swordslashparryanim && animCurrent == swordslashparryanim) || (animTarget == swordslashparriedanim && animCurrent == swordslashparriedanim) || (animTarget == swordslashreversalanim && animCurrent == swordslashreversalanim) || (animTarget == swordslashreversedanim && animCurrent == swordslashreversedanim) || (animTarget == knifeslashreversalanim && animCurrent == knifeslashreversalanim) || (animTarget == knifeslashreversedanim && animCurrent == knifeslashreversedanim) || (animTarget == swordslashanim && animCurrent == swordslashanim) || (animTarget == drawleftanim && animCurrent == drawleftanim) || (animCurrent == backhandspringanim && animTarget == backhandspringanim)) {
- XYZ temppoint1, temppoint2;
- float distance;
-
- temppoint1 = currentFrame().joints[skeleton.jointlabels[righthand]].position * (1 - target) + targetFrame().joints[skeleton.jointlabels[righthand]].position * (target); //jointPos(righthand);
- temppoint2 = currentFrame().weapontarget * (1 - target) + targetFrame().weapontarget * (target);
- distance = findDistance(&temppoint1, &temppoint2);
- weapons[i].rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
- weapons[i].rotation2 *= 360 / 6.28;
- temppoint1.y = 0;
- temppoint2.y = 0;
- weapons[i].rotation1 = acos((temppoint1.z - temppoint2.z) / findDistance(&temppoint1, &temppoint2));
- weapons[i].rotation1 *= 360 / 6.28;
- weapons[i].rotation3 = 0;
- weapons[i].smallrotation = 90;
- weapons[i].smallrotation2 = 0;
- if (temppoint1.x > temppoint2.x)
- weapons[i].rotation1 = 360 - weapons[i].rotation1;
- }
- }
- if (weapons[i].getType() == staff) {
- weapons[i].smallrotation = 100;
- weapons[i].smallrotation2 = 0;
- if ((animTarget == staffhitanim && animCurrent == staffhitanim) || (animTarget == staffhitreversedanim && animCurrent == staffhitreversedanim) || (animTarget == staffspinhitreversedanim && animCurrent == staffspinhitreversedanim) || (animTarget == staffgroundsmashanim && animCurrent == staffgroundsmashanim) || (animTarget == staffspinhitanim && animCurrent == staffspinhitanim)) {
- XYZ temppoint1, temppoint2;
- float distance;
-
- temppoint1 = currentFrame().joints[skeleton.jointlabels[righthand]].position * (1 - target) + targetFrame().joints[skeleton.jointlabels[righthand]].position * (target); //jointPos(righthand);
- temppoint2 = currentFrame().weapontarget * (1 - target) + targetFrame().weapontarget * (target);
- distance = findDistance(&temppoint1, &temppoint2);
- weapons[i].rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
- weapons[i].rotation2 *= 360 / 6.28;
- temppoint1.y = 0;
- temppoint2.y = 0;
- weapons[i].rotation1 = acos((temppoint1.z - temppoint2.z) / findDistance(&temppoint1, &temppoint2));
- weapons[i].rotation1 *= 360 / 6.28;
- weapons[i].rotation3 = 0;
- weapons[i].smallrotation = 90;
- weapons[i].smallrotation2 = 0;
- if (temppoint1.x > temppoint2.x)
- weapons[i].rotation1 = 360 - weapons[i].rotation1;
- }
- }
- }
- if (weaponactive != k && weaponstuck != k) {
- if (weapons[i].getType() == knife) {
- weapons[i].smallrotation = -70;
- weapons[i].smallrotation2 = 10;
- }
- if (weapons[i].getType() == sword) {
- weapons[i].smallrotation = -100;
- weapons[i].smallrotation2 = -8;
- }
- if (weapons[i].getType() == staff) {
- weapons[i].smallrotation = -100;
- weapons[i].smallrotation2 = -8;
- }
- }
- if (weaponstuck == k) {
- if (weaponstuckwhere == 0)
- weapons[i].smallrotation = 180;
- else
- weapons[i].smallrotation = 0;
- weapons[i].smallrotation2 = 10;
- }
- }
- }
- }
-
- calcrot = 0;
- if (skeleton.free)
- calcrot = 1;
- 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;
- if (skeleton.free == 2)
- calcrot = 0;
-
- return 0;
-}
-
-
-/* FUNCTION?
- */
-int Person::SphereCheck(XYZ *p1, float radius, XYZ *p, XYZ *move, float *rotate, Model *model)
-{
- static int i, j;
- static float distance;
- static float olddistance;
- static int intersecting;
- static int firstintersecting;
- static XYZ point;
- static XYZ oldp1;
- static XYZ start, end;
- static float slopethreshold = -.4;
-
- firstintersecting = -1;
-
- oldp1 = *p1;
- *p1 = *p1 - *move;
- if (distsq(p1, &model->boundingspherecenter) > radius * radius + model->boundingsphereradius * model->boundingsphereradius)
- return -1;
- if (*rotate)
- *p1 = DoRotation(*p1, 0, -*rotate, 0);
- for (i = 0; i < 4; i++) {
- for (j = 0; j < model->TriangleNum; j++) {
- if (model->facenormals[j].y <= slopethreshold) {
- intersecting = 0;
- distance = abs((model->facenormals[j].x * p1->x) + (model->facenormals[j].y * p1->y) + (model->facenormals[j].z * p1->z) - ((model->facenormals[j].x * model->vertex[model->Triangles[j].vertex[0]].x) + (model->facenormals[j].y * model->vertex[model->Triangles[j].vertex[0]].y) + (model->facenormals[j].z * model->vertex[model->Triangles[j].vertex[0]].z)));
- if (distance < radius) {
- point = *p1 - model->facenormals[j] * distance;
- if (PointInTriangle( &point, model->facenormals[j], &model->vertex[model->Triangles[j].vertex[0]], &model->vertex[model->Triangles[j].vertex[1]], &model->vertex[model->Triangles[j].vertex[2]]))
- intersecting = 1;
- if (!intersecting)
- intersecting = sphere_line_intersection(&model->vertex[model->Triangles[j].vertex[0]],
- &model->vertex[model->Triangles[j].vertex[1]],
- p1, &radius);
- if (!intersecting)
- intersecting = sphere_line_intersection(&model->vertex[model->Triangles[j].vertex[1]],
- &model->vertex[model->Triangles[j].vertex[2]],
- p1, &radius);
- if (!intersecting)
- intersecting = sphere_line_intersection(&model->vertex[model->Triangles[j].vertex[0]],
- &model->vertex[model->Triangles[j].vertex[2]],
- p1, &radius);
- end = *p1 - point;
- if (dotproduct(&model->facenormals[j], &end) > 0 && intersecting) {
- start = *p1;
- end = *p1;
- end.y -= radius;
- 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 || targetFrame().label == 7 || targetFrame().label == 4))
- RagDoll(0);
-
- if (animTarget == jumpupanim) {
- jumppower = -4;
- animTarget = getIdle();
- }
- target = 0;
- frameTarget = 0;
- onterrain = 1;
-
- if (id == 0) {
- pause_sound(whooshsound);
- OPENAL_SetVolume(channels[whooshsound], 0);
- }
-
- if ((animTarget == jumpdownanim || isFlip()) && !wasLanding() && !wasLandhard()) {
- if (isFlip())
- jumppower = -4;
- animTarget = getLanding();
- emit_sound_at(landsound, coords, 128.);
-
- if (id == 0) {
- addEnvSound(coords);
- }
- }
- }
- }
- }
- }
- if ((distance < olddistance || firstintersecting == -1) && intersecting) {
- olddistance = distance;
- firstintersecting = j;
- *p = point;
- }
- }
- }
- for (j = 0; j < model->TriangleNum; j++) {
- if (model->facenormals[j].y > slopethreshold) {
- intersecting = 0;
- start = *p1;
- start.y -= radius / 4;
- XYZ &v0 = model->vertex[model->Triangles[j].vertex[0]];
- XYZ &v1 = model->vertex[model->Triangles[j].vertex[1]];
- XYZ &v2 = model->vertex[model->Triangles[j].vertex[2]];
- distance = abs((model->facenormals[j].x * start.x)
- + (model->facenormals[j].y * start.y)
- + (model->facenormals[j].z * start.z)
- - ((model->facenormals[j].x * v0.x)
- + (model->facenormals[j].y * v0.y)
- + (model->facenormals[j].z * v0.z)));
- if (distance < radius * .5) {
- point = start - model->facenormals[j] * distance;
- if (PointInTriangle( &point, model->facenormals[j], &v0, &v1, &v2))
- intersecting = 1;
- if (!intersecting)
- intersecting = sphere_line_intersection(v0.x, v0.y, v0.z, v1.x, v1.y, v1.z, p1->x, p1->y, p1->z, radius / 2);
- if (!intersecting)
- intersecting = sphere_line_intersection(v1.x, v1.y, v1.z, v2.x, v2.y, v2.z, p1->x, p1->y, p1->z, radius / 2);
- if (!intersecting)
- intersecting = sphere_line_intersection(v0.x, v0.y, v0.z, v2.x, v2.y, v2.z, p1->x, p1->y, p1->z, radius / 2);
- end = *p1 - point;
- if (dotproduct(&model->facenormals[j], &end) > 0 && intersecting) {
- if ((animTarget == jumpdownanim || animTarget == jumpupanim || isFlip())) {
- start = velocity;
- velocity -= DoRotation(model->facenormals[j], 0, *rotate, 0) * findLength(&velocity) * abs(normaldotproduct(velocity, DoRotation(model->facenormals[j], 0, *rotate, 0))); //(distance-radius*.5)/multiplier;
- if (findLengthfast(&start) < findLengthfast(&velocity))
- velocity = start;
- }
- *p1 += model->facenormals[j] * (distance - radius * .5);
- }
- }
- if ((distance < olddistance || firstintersecting == -1) && intersecting) {
- olddistance = distance;
- firstintersecting = j;
- *p = point;
- }
- }
- }
- }
- if (*rotate)
- *p = DoRotation(*p, 0, *rotate, 0);
- *p = *p + *move;
- if (*rotate)
- *p1 = DoRotation(*p1, 0, *rotate, 0);
- *p1 += *move;
- return firstintersecting;
-}
-
-void Person::takeWeapon(int weaponId)
-{
- weaponactive = 0;
- weapons[weaponId].owner = id;
- if (num_weapons > 0) {
- weaponids[num_weapons] = weaponids[0];
- }
- num_weapons++;
- weaponids[0] = weaponId;
-}
-
-void Person::addClothes()
-{
- if (numclothes > 0) {
- for (int i = 0; i < numclothes; i++) {
- addClothes(i);
- }
- DoMipmaps();
- }
-}
-
-bool Person::addClothes(const int& clothesId)
-{
- LOGFUNC;
- const std::string fileName = clothes[clothesId];
-
- GLubyte* array = &skeleton.skinText[0];
-
- //Load Image
- ImageRec texture;
- bool opened = load_image(Folders::getResourcePath(fileName).c_str(), texture);
-
- float alphanum;
- //Is it valid?
- if (opened) {
- float tintr = clothestintr[clothesId];
- float tintg = clothestintg[clothesId];
- float tintb = clothestintb[clothesId];
-
- if (tintr > 1) tintr = 1;
- if (tintg > 1) tintg = 1;
- if (tintb > 1) tintb = 1;
-
- if (tintr < 0) tintr = 0;
- if (tintg < 0) tintg = 0;
- if (tintb < 0) tintb = 0;
-
- int bytesPerPixel = texture.bpp / 8;
-
- int tempnum = 0;
- alphanum = 255;
- for (int i = 0; i < (int)(texture.sizeY * texture.sizeX * bytesPerPixel); i++) {
- if (bytesPerPixel == 3)
- alphanum = 255;
- else if ((i + 1) % 4 == 0)
- alphanum = texture.data[i];
- if ((i + 1) % 4 || bytesPerPixel == 3) {
- if ((i % 4) == 0)
- texture.data[i] *= tintr;
- if ((i % 4) == 1)
- texture.data[i] *= tintg;
- if ((i % 4) == 2)
- texture.data[i] *= tintb;
- array[tempnum] = (float)array[tempnum] * (1 - alphanum / 255) + (float)texture.data[i] * (alphanum / 255);
- tempnum++;
- }
- }
- return 1;
- } else {
- return 0;
- }
-}
+++ /dev/null
-/*
-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 _PERSON_H_
-#define _PERSON_H_
-
-/**> HEADER FILES <**/
-
-#include "gamegl.h"
-#include "Quaternions.h"
-#include "Animation/Skeleton.h"
-#include "Models.h"
-#include "Terrain.h"
-#include "Sprite.h"
-#include <cmath>
-#include <memory>
-#include "Weapons.h"
-#include "Animation/Animation.h"
-
-#define passivetype 0
-#define guardtype 1
-#define searchtype 2
-#define attacktype 3
-#define attacktypecutoff 4
-#define playercontrolled 5
-#define gethelptype 6
-#define getweapontype 7
-#define pathfindtype 8
-
-#define rabbittype 0
-#define wolftype 1
-
-struct InvalidPersonException : public exception {
- const char * what () const throw () {
- return "Invalid weapon number";
- }
-};
-
-class Person : public enable_shared_from_this<Person>
-{
-public:
- static std::vector<std::shared_ptr<Person>> players;
-
- int whichpatchx;
- int whichpatchz;
-
- // animCurrent and animTarget are used to interpolate between different animations
- // (and for a bunch of other things).
- // animations interpolate with one another at various speeds.
- // animTarget seems to determine the combat state?
- int animCurrent;
- int animTarget;
-
- // frameCurrent and frameTarget are used to interpolate between the frames of an animation
- // (e.g. the crouched animation has only two frames, lerped back and forth slowly).
- // animations advance at various speeds.
- int frameCurrent;
- int frameTarget;
-
- int oldanimCurrent;
- int oldanimTarget;
- int oldframeCurrent;
- int oldframeTarget;
-
- int howactive;
-
- float parriedrecently;
-
- bool superruntoggle;
-
- int lastattack, lastattack2, lastattack3;
-
- XYZ currentoffset, targetoffset, offset;
- float target;
- float transspeed;
-
- XYZ realoldcoords;
- XYZ oldcoords;
- XYZ coords;
- XYZ velocity;
-
- XYZ proportionhead;
- XYZ proportionlegs;
- XYZ proportionarms;
- XYZ proportionbody;
-
- float unconscioustime;
-
- bool immobile;
-
- float velspeed;
- float targetyaw;
- float targetrot;
- float rot;
- float oldrot;
- float lookyaw;
- float lookpitch;
- float yaw;
- float pitch;
- float lowyaw;
- float tilt;
- float targettilt;
- float tilt2;
- float targettilt2;
- bool rabbitkickenabled;
-
- float bloodloss;
- float bleeddelay;
- float skiddelay;
- float skiddingdelay;
- float deathbleeding;
- float tempdeltav;
-
- float damagetolerance;
- float damage;
- float permanentdamage;
- float superpermanentdamage;
- float lastcollide;
- /* Seems to be 0 = alive, 1 = unconscious, 2 = dead */
- int dead;
-
- float jumppower;
- bool onground;
-
- int wentforweapon;
-
- bool calcrot;
-
- XYZ facing;
-
- float bleeding;
- float bleedx, bleedy;
- int direction;
- float texupdatedelay;
-
- float headyaw, headpitch;
- float targetheadyaw, targetheadpitch;
-
- bool onterrain;
- bool pause;
-
- float grabdelay;
-
- std::shared_ptr<Person> victim;
- bool hasvictim;
-
- float updatedelay;
- float normalsupdatedelay;
-
- bool jumpstart;
-
- bool forwardkeydown;
- bool forwardstogglekeydown;
- bool rightkeydown;
- bool leftkeydown;
- bool backkeydown;
- bool jumpkeydown;
- bool jumptogglekeydown;
- bool crouchkeydown;
- bool crouchtogglekeydown;
- bool drawkeydown;
- bool drawtogglekeydown;
- bool throwkeydown;
- bool throwtogglekeydown;
- bool attackkeydown;
- bool feint;
- bool lastfeint;
- bool headless;
-
- float crouchkeydowntime;
- float jumpkeydowntime;
- bool freefall;
-
-
- float turnspeed;
-
- int aitype;
- float aiupdatedelay;
- float losupdatedelay;
- int ally;
- float collide;
- float collided;
- float avoidcollided;
- bool loaded;
- bool whichdirection;
- float whichdirectiondelay;
- bool avoidsomething;
- XYZ avoidwhere;
- float blooddimamount;
-
- float staggerdelay;
- float blinkdelay;
- float twitchdelay;
- float twitchdelay2;
- float twitchdelay3;
- float lefthandmorphness;
- float righthandmorphness;
- float headmorphness;
- float chestmorphness;
- float tailmorphness;
- float targetlefthandmorphness;
- float targetrighthandmorphness;
- float targetheadmorphness;
- float targetchestmorphness;
- float targettailmorphness;
- int lefthandmorphstart, lefthandmorphend;
- int righthandmorphstart, righthandmorphend;
- int headmorphstart, headmorphend;
- int chestmorphstart, chestmorphend;
- int tailmorphstart, tailmorphend;
-
- float weaponmissdelay;
- float highreversaldelay;
- float lowreversaldelay;
-
- int creature;
-
- unsigned id;
-
- Skeleton skeleton;
-
- float speed;
- float scale;
- float power;
- float speedmult;
-
- float protectionhead;
- float protectionhigh;
- float protectionlow;
- float armorhead;
- float armorhigh;
- float armorlow;
- bool metalhead;
- bool metalhigh;
- bool metallow;
-
- int numclothes;
- char clothes[10][256];
- float clothestintr[10];
- float clothestintg[10];
- float clothestintb[10];
-
- bool landhard;
- bool bled;
- bool spurt;
- bool onfire;
- float onfiredelay;
- float burnt;
-
- float flamedelay;
-
- int playerdetail;
-
- int num_weapons;
- int weaponids[4];
- /* Key of weaponids which is the weapon in hand, if any. -1 otherwise.
- * Always 0 or -1 as activeweapon is moved to position 0 when taken */
- int weaponactive;
- int weaponstuck;
- /* 0 or 1 to say if weapon is stuck in the front or the back */
- int weaponstuckwhere;
-
- int numwaypoints;
- XYZ waypoints[90];
- int waypointtype[90];
- float pausetime;
-
- XYZ headtarget;
- float interestdelay;
-
- XYZ finalfinaltarget;
- XYZ finaltarget;
- int finalpathfindpoint;
- int targetpathfindpoint;
- int lastpathfindpoint;
- int lastpathfindpoint2;
- int lastpathfindpoint3;
- int lastpathfindpoint4;
-
- int waypoint;
-
- XYZ lastseen;
- float lastseentime;
- float lastchecktime;
- float stunned;
- float surprised;
- float runninghowlong;
- int occluded;
- int lastoccluded;
- int laststanding;
- int escapednum;
-
- float speechdelay;
- float neckspurtdelay;
- float neckspurtparticledelay;
- float neckspurtamount;
-
- int whichskin;
- bool rabbitkickragdoll;
-
- Animation tempanimation;
-
- bool jumpclimb;
-
- Person();
- Person(FILE*, int, unsigned);
-
- void skeletonLoad(bool clothes = false);
-
- // convenience functions
- inline Joint& joint(int bodypart) { return skeleton.joints[skeleton.jointlabels[bodypart]]; }
- inline XYZ& jointPos(int bodypart) { return joint(bodypart).position; }
- inline XYZ& jointVel(int bodypart) { return joint(bodypart).velocity; }
- inline AnimationFrame& currentFrame() { return Animation::animations.at(animCurrent).frames.at(frameCurrent); }
- inline AnimationFrame& targetFrame() { return Animation::animations.at(animTarget).frames.at(frameTarget); }
-
-
- void CheckKick();
- void CatchFire();
- void DoBlood(float howmuch, int which);
- void DoBloodBig(float howmuch, int which);
- bool DoBloodBigWhere(float howmuch, int which, XYZ where);
-
- bool wasIdle() { return animation_bits[animCurrent] & ab_idle; }
- bool isIdle() { return animation_bits[animTarget] & ab_idle; }
- int getIdle();
-
- bool isSitting() { return animation_bits[animTarget] & ab_sit; }
-
- bool isSleeping() { return animation_bits[animTarget] & ab_sleep; }
-
- bool wasCrouch() { return animation_bits[animCurrent] & ab_crouch; }
- bool isCrouch() { return animation_bits[animTarget] & ab_crouch; }
- int getCrouch();
-
- bool wasStop() { return animation_bits[animCurrent] & ab_stop; }
- bool isStop() { return animation_bits[animTarget] & ab_stop; }
- int getStop();
-
- bool wasSneak();
- bool isSneak();
- int getSneak();
-
- bool wasRun() { return animation_bits[animCurrent] & ab_run; }
- bool isRun() { return animation_bits[animTarget] & ab_run; }
- int getRun();
-
- bool wasLanding() { return animation_bits[animCurrent] & ab_land; }
- bool isLanding() { return animation_bits[animTarget] & ab_land; }
- int getLanding();
-
- bool wasLandhard() { return animation_bits[animCurrent] & ab_landhard; }
- bool isLandhard() { return animation_bits[animTarget] & ab_landhard; }
- int getLandhard();
-
- bool wasFlip() { return animation_bits[animCurrent] & ab_flip; }
- bool isFlip() { return animation_bits[animTarget] & ab_flip; }
-
- bool isWallJump() { return animation_bits[animTarget] & ab_walljump; }
- void Reverse();
- void DoDamage(float howmuch);
- void DoHead();
- void DoMipmaps() {
- skeleton.drawmodel.textureptr.bind();
- glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, skeleton.skinsize, skeleton.skinsize, 0, GL_RGB, GL_UNSIGNED_BYTE, &skeleton.skinText[0]);
- }
-
- int SphereCheck(XYZ *p1, float radius, XYZ *p, XYZ *move, float *rotate, Model *model);
- int DrawSkeleton();
- void Puff(int whichlabel);
- void FootLand(bodypart whichfoot, float opacity);
- void DoStuff();
- void setAnimation(int);
- void DoAnimations();
- void RagDoll(bool checkcollision);
-
- void takeWeapon (int weaponId);
-
- bool addClothes(const int& clothesId);
- void addClothes();
-};
-
-const int maxplayers = 10;
-
-#endif
+++ /dev/null
-/*
-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 _PHYSICSMATH_H_
-#define _PHYSICSMATH_H_
-
-//#include <Carbon.h>
-
-#include "MacCompatibility.h"
-
-//------------------------------------------------------------------------//
-// Misc. Constants
-//------------------------------------------------------------------------//
-
-float const pi = 3.14159265f;
-float const g = -32.174f; // acceleration due to gravity, ft/s^2
-float const rho = 0.0023769f; // desity of air at sea level, slugs/ft^3
-float const tol = 0.0000000001f; // float type tolerance
-
-
-//------------------------------------------------------------------------//
-// Misc. Functions
-//------------------------------------------------------------------------//
-inline float DegreesToRadians(float deg);
-inline float RadiansToDegrees(float rad);
-
-inline float DegreesToRadians(float deg)
-{
- return deg * pi / 180.0f;
-}
-
-inline float RadiansToDegrees(float rad)
-{
- return rad * 180.0f / pi;
-}
-
-//------------------------------------------------------------------------//
-// Vector Class and vector functions
-//------------------------------------------------------------------------//
-class Vector
-{
-public:
- float x;
- float y;
- float z;
-
- Vector(void);
- Vector(float xi, float yi, float zi);
-
- float Magnitude(void);
- void Normalize(void);
- void Reverse(void);
-
- Vector& operator+=(Vector u); // vector addition
- Vector& operator-=(Vector u); // vector subtraction
- Vector& operator*=(float s); // scalar multiply
- Vector& operator/=(float s); // scalar divide
-
- Vector operator-(void);
-
-};
-
-inline Vector operator+(Vector u, Vector v);
-inline Vector operator-(Vector u, Vector v);
-inline Vector operator^(Vector u, Vector v);
-inline float operator*(Vector u, Vector v);
-inline Vector operator*(float s, Vector u);
-inline Vector operator*(Vector u, float s);
-inline Vector operator/(Vector u, float s);
-inline float TripleScalarProduct(Vector u, Vector v, Vector w);
-/*
-float fast_sqrt2 (register float arg);
-float fast_sqrt2 (register float arg)
-{
-// Can replace with slower return std::sqrt(arg);
-register float result;
-
-if (arg == 0.0) return 0.0;
-
-asm {
-frsqrte result,arg // Calculate Square root
-}
-
-// Newton Rhapson iterations.
-result = result + 0.5 * result * (1.0 - arg * result * result);
-result = result + 0.5 * result * (1.0 - arg * result * result);
-
-return result * arg;
-}
-*/
-inline Vector::Vector(void)
-{
- x = 0;
- y = 0;
- z = 0;
-}
-
-inline Vector::Vector(float xi, float yi, float zi)
-{
- x = xi;
- y = yi;
- z = zi;
-}
-
-inline float Vector::Magnitude(void)
-{
- return (float) sqrt(x * x + y * y + z * z);
-}
-
-inline void Vector::Normalize(void)
-{
- float m = (float) sqrt(x * x + y * y + z * z);
- if (m <= tol)
- m = 1;
- x /= m;
- y /= m;
- z /= m;
-
- if (fabs(x) < tol)
- x = 0.0f;
- if (fabs(y) < tol)
- y = 0.0f;
- if (fabs(z) < tol)
- z = 0.0f;
-}
-
-inline void Vector::Reverse(void)
-{
- x = -x;
- y = -y;
- z = -z;
-}
-
-inline Vector& Vector::operator+=(Vector u)
-{
- x += u.x;
- y += u.y;
- z += u.z;
- return *this;
-}
-
-inline Vector& Vector::operator-=(Vector u)
-{
- x -= u.x;
- y -= u.y;
- z -= u.z;
- return *this;
-}
-
-inline Vector& Vector::operator*=(float s)
-{
- x *= s;
- y *= s;
- z *= s;
- return *this;
-}
-
-inline Vector& Vector::operator/=(float s)
-{
- x /= s;
- y /= s;
- z /= s;
- return *this;
-}
-
-inline Vector Vector::operator-(void)
-{
- return Vector(-x, -y, -z);
-}
-
-
-inline Vector operator+(Vector u, Vector v)
-{
- return Vector(u.x + v.x, u.y + v.y, u.z + v.z);
-}
-
-inline Vector operator-(Vector u, Vector v)
-{
- return Vector(u.x - v.x, u.y - v.y, u.z - v.z);
-}
-
-// Vector cross product (u cross v)
-inline Vector operator^(Vector u, Vector v)
-{
- return Vector( u.y * v.z - u.z * v.y,
- -u.x * v.z + u.z * v.x,
- u.x * v.y - u.y * v.x );
-}
-
-// Vector dot product
-inline float operator*(Vector u, Vector v)
-{
- return (u.x * v.x + u.y * v.y + u.z * v.z);
-}
-
-inline Vector operator*(float s, Vector u)
-{
- return Vector(u.x * s, u.y * s, u.z * s);
-}
-
-inline Vector operator*(Vector u, float s)
-{
- return Vector(u.x * s, u.y * s, u.z * s);
-}
-
-inline Vector operator/(Vector u, float s)
-{
- return Vector(u.x / s, u.y / s, u.z / s);
-}
-
-// triple scalar product (u dot (v cross w))
-inline float TripleScalarProduct(Vector u, Vector v, Vector w)
-{
- return float( (u.x * (v.y * w.z - v.z * w.y)) +
- (u.y * (-v.x * w.z + v.z * w.x)) +
- (u.z * (v.x * w.y - v.y * w.x)) );
- //return u*(v^w);
-
-}
-
-
-
-//------------------------------------------------------------------------//
-// Matrix Class and matrix functions
-//------------------------------------------------------------------------//
-
-class Matrix3x3
-{
-public:
- // elements eij: i -> row, j -> column
- float e11, e12, e13, e21, e22, e23, e31, e32, e33;
-
- Matrix3x3(void);
- Matrix3x3( float r1c1, float r1c2, float r1c3,
- float r2c1, float r2c2, float r2c3,
- float r3c1, float r3c2, float r3c3 );
-
- float det(void);
- Matrix3x3 Transpose(void);
- Matrix3x3 Inverse(void);
-
- Matrix3x3& operator+=(Matrix3x3 m);
- Matrix3x3& operator-=(Matrix3x3 m);
- Matrix3x3& operator*=(float s);
- Matrix3x3& operator/=(float s);
-};
-
-inline Matrix3x3 operator+(Matrix3x3 m1, Matrix3x3 m2);
-inline Matrix3x3 operator-(Matrix3x3 m1, Matrix3x3 m2);
-inline Matrix3x3 operator/(Matrix3x3 m, float s);
-inline Matrix3x3 operator*(Matrix3x3 m1, Matrix3x3 m2);
-inline Matrix3x3 operator*(Matrix3x3 m, float s);
-inline Matrix3x3 operator*(float s, Matrix3x3 m);
-inline Vector operator*(Matrix3x3 m, Vector u);
-inline Vector operator*(Vector u, Matrix3x3 m);
-
-
-
-
-
-inline Matrix3x3::Matrix3x3(void)
-{
- e11 = 0;
- e12 = 0;
- e13 = 0;
- e21 = 0;
- e22 = 0;
- e23 = 0;
- e31 = 0;
- e32 = 0;
- e33 = 0;
-}
-
-inline Matrix3x3::Matrix3x3( float r1c1, float r1c2, float r1c3,
- float r2c1, float r2c2, float r2c3,
- float r3c1, float r3c2, float r3c3 )
-{
- e11 = r1c1;
- e12 = r1c2;
- e13 = r1c3;
- e21 = r2c1;
- e22 = r2c2;
- e23 = r2c3;
- e31 = r3c1;
- e32 = r3c2;
- e33 = r3c3;
-}
-
-inline float Matrix3x3::det(void)
-{
- return e11 * e22 * e33 -
- e11 * e32 * e23 +
- e21 * e32 * e13 -
- e21 * e12 * e33 +
- e31 * e12 * e23 -
- e31 * e22 * e13;
-}
-
-inline Matrix3x3 Matrix3x3::Transpose(void)
-{
- return Matrix3x3(e11, e21, e31, e12, e22, e32, e13, e23, e33);
-}
-
-inline Matrix3x3 Matrix3x3::Inverse(void)
-{
- float d = e11 * e22 * e33 -
- e11 * e32 * e23 +
- e21 * e32 * e13 -
- e21 * e12 * e33 +
- e31 * e12 * e23 -
- e31 * e22 * e13;
-
- if (d == 0)
- d = 1;
-
- return Matrix3x3( (e22 * e33 - e23 * e32) / d,
- -(e12 * e33 - e13 * e32) / d,
- (e12 * e23 - e13 * e22) / d,
- -(e21 * e33 - e23 * e31) / d,
- (e11 * e33 - e13 * e31) / d,
- -(e11 * e23 - e13 * e21) / d,
- (e21 * e32 - e22 * e31) / d,
- -(e11 * e32 - e12 * e31) / d,
- (e11 * e22 - e12 * e21) / d );
-}
-
-inline Matrix3x3& Matrix3x3::operator+=(Matrix3x3 m)
-{
- e11 += m.e11;
- e12 += m.e12;
- e13 += m.e13;
- e21 += m.e21;
- e22 += m.e22;
- e23 += m.e23;
- e31 += m.e31;
- e32 += m.e32;
- e33 += m.e33;
- return *this;
-}
-
-inline Matrix3x3& Matrix3x3::operator-=(Matrix3x3 m)
-{
- e11 -= m.e11;
- e12 -= m.e12;
- e13 -= m.e13;
- e21 -= m.e21;
- e22 -= m.e22;
- e23 -= m.e23;
- e31 -= m.e31;
- e32 -= m.e32;
- e33 -= m.e33;
- return *this;
-}
-
-inline Matrix3x3& Matrix3x3::operator*=(float s)
-{
- e11 *= s;
- e12 *= s;
- e13 *= s;
- e21 *= s;
- e22 *= s;
- e23 *= s;
- e31 *= s;
- e32 *= s;
- e33 *= s;
- return *this;
-}
-
-inline Matrix3x3& Matrix3x3::operator/=(float s)
-{
- e11 /= s;
- e12 /= s;
- e13 /= s;
- e21 /= s;
- e22 /= s;
- e23 /= s;
- e31 /= s;
- e32 /= s;
- e33 /= s;
- return *this;
-}
-
-inline Matrix3x3 operator+(Matrix3x3 m1, Matrix3x3 m2)
-{
- return Matrix3x3( m1.e11 + m2.e11,
- m1.e12 + m2.e12,
- m1.e13 + m2.e13,
- m1.e21 + m2.e21,
- m1.e22 + m2.e22,
- m1.e23 + m2.e23,
- m1.e31 + m2.e31,
- m1.e32 + m2.e32,
- m1.e33 + m2.e33);
-}
-
-inline Matrix3x3 operator-(Matrix3x3 m1, Matrix3x3 m2)
-{
- return Matrix3x3( m1.e11 - m2.e11,
- m1.e12 - m2.e12,
- m1.e13 - m2.e13,
- m1.e21 - m2.e21,
- m1.e22 - m2.e22,
- m1.e23 - m2.e23,
- m1.e31 - m2.e31,
- m1.e32 - m2.e32,
- m1.e33 - m2.e33);
-}
-
-inline Matrix3x3 operator/(Matrix3x3 m, float s)
-{
- return Matrix3x3( m.e11 / s,
- m.e12 / s,
- m.e13 / s,
- m.e21 / s,
- m.e22 / s,
- m.e23 / s,
- m.e31 / s,
- m.e32 / s,
- m.e33 / s);
-}
-
-inline Matrix3x3 operator*(Matrix3x3 m1, Matrix3x3 m2)
-{
- return Matrix3x3( m1.e11 * m2.e11 + m1.e12 * m2.e21 + m1.e13 * m2.e31,
- m1.e11 * m2.e12 + m1.e12 * m2.e22 + m1.e13 * m2.e32,
- m1.e11 * m2.e13 + m1.e12 * m2.e23 + m1.e13 * m2.e33,
- m1.e21 * m2.e11 + m1.e22 * m2.e21 + m1.e23 * m2.e31,
- m1.e21 * m2.e12 + m1.e22 * m2.e22 + m1.e23 * m2.e32,
- m1.e21 * m2.e13 + m1.e22 * m2.e23 + m1.e23 * m2.e33,
- m1.e31 * m2.e11 + m1.e32 * m2.e21 + m1.e33 * m2.e31,
- m1.e31 * m2.e12 + m1.e32 * m2.e22 + m1.e33 * m2.e32,
- m1.e31 * m2.e13 + m1.e32 * m2.e23 + m1.e33 * m2.e33 );
-}
-
-inline Matrix3x3 operator*(Matrix3x3 m, float s)
-{
- return Matrix3x3( m.e11 * s,
- m.e12 * s,
- m.e13 * s,
- m.e21 * s,
- m.e22 * s,
- m.e23 * s,
- m.e31 * s,
- m.e32 * s,
- m.e33 * s);
-}
-
-inline Matrix3x3 operator*(float s, Matrix3x3 m)
-{
- return Matrix3x3( m.e11 * s,
- m.e12 * s,
- m.e13 * s,
- m.e21 * s,
- m.e22 * s,
- m.e23 * s,
- m.e31 * s,
- m.e32 * s,
- m.e33 * s);
-}
-
-inline Vector operator*(Matrix3x3 m, Vector u)
-{
- return Vector( m.e11 * u.x + m.e12 * u.y + m.e13 * u.z,
- m.e21 * u.x + m.e22 * u.y + m.e23 * u.z,
- m.e31 * u.x + m.e32 * u.y + m.e33 * u.z);
-}
-
-inline Vector operator*(Vector u, Matrix3x3 m)
-{
- return Vector( u.x * m.e11 + u.y * m.e21 + u.z * m.e31,
- u.x * m.e12 + u.y * m.e22 + u.z * m.e32,
- u.x * m.e13 + u.y * m.e23 + u.z * m.e33);
-}
-
-//------------------------------------------------------------------------//
-// Quaternion Class and Quaternion functions
-//------------------------------------------------------------------------//
-
-class Quaternion
-{
-public:
- float n; // number (scalar) part
- Vector v; // vector part: v.x, v.y, v.z
-
- Quaternion(void);
- Quaternion(float e0, float e1, float e2, float e3);
-
- float Magnitude(void);
- Vector GetVector(void);
- float GetScalar(void);
- Quaternion operator+=(Quaternion q);
- Quaternion operator-=(Quaternion q);
- Quaternion operator*=(float s);
- Quaternion operator/=(float s);
- Quaternion operator~(void) const {
- return Quaternion(n, -v.x, -v.y, -v.z);
- }
-};
-
-inline Quaternion operator+(Quaternion q1, Quaternion q2);
-inline Quaternion operator-(Quaternion q1, Quaternion q2);
-inline Quaternion operator*(Quaternion q1, Quaternion q2);
-inline Quaternion operator*(Quaternion q, float s);
-inline Quaternion operator*(float s, Quaternion q);
-inline Quaternion operator*(Quaternion q, Vector v);
-inline Quaternion operator*(Vector v, Quaternion q);
-inline Quaternion operator/(Quaternion q, float s);
-inline float QGetAngle(Quaternion q);
-inline Vector QGetAxis(Quaternion q);
-inline Quaternion QRotate(Quaternion q1, Quaternion q2);
-inline Vector QVRotate(Quaternion q, Vector v);
-inline Quaternion MakeQFromEulerAngles(float x, float y, float z);
-inline Vector MakeEulerAnglesFromQ(Quaternion q);
-
-
-inline Quaternion::Quaternion(void)
-{
- n = 0;
- v.x = 0;
- v.y = 0;
- v.z = 0;
-}
-
-inline Quaternion::Quaternion(float e0, float e1, float e2, float e3)
-{
- n = e0;
- v.x = e1;
- v.y = e2;
- v.z = e3;
-}
-
-inline float Quaternion::Magnitude(void)
-{
- return (float) sqrt(n * n + v.x * v.x + v.y * v.y + v.z * v.z);
-}
-
-inline Vector Quaternion::GetVector(void)
-{
- return Vector(v.x, v.y, v.z);
-}
-
-inline float Quaternion::GetScalar(void)
-{
- return n;
-}
-
-inline Quaternion Quaternion::operator+=(Quaternion q)
-{
- n += q.n;
- v.x += q.v.x;
- v.y += q.v.y;
- v.z += q.v.z;
- return *this;
-}
-
-inline Quaternion Quaternion::operator-=(Quaternion q)
-{
- n -= q.n;
- v.x -= q.v.x;
- v.y -= q.v.y;
- v.z -= q.v.z;
- return *this;
-}
-
-inline Quaternion Quaternion::operator*=(float s)
-{
- n *= s;
- v.x *= s;
- v.y *= s;
- v.z *= s;
- return *this;
-}
-
-inline Quaternion Quaternion::operator/=(float s)
-{
- n /= s;
- v.x /= s;
- v.y /= s;
- v.z /= s;
- return *this;
-}
-
-/*inline Quaternion Quaternion::operator~()
-{
-return Quaternion(n, -v.x, -v.y, -v.z);
-}*/
-
-inline Quaternion operator+(Quaternion q1, Quaternion q2)
-{
- return Quaternion( q1.n + q2.n,
- q1.v.x + q2.v.x,
- q1.v.y + q2.v.y,
- q1.v.z + q2.v.z);
-}
-
-inline Quaternion operator-(Quaternion q1, Quaternion q2)
-{
- return Quaternion( q1.n - q2.n,
- q1.v.x - q2.v.x,
- q1.v.y - q2.v.y,
- q1.v.z - q2.v.z);
-}
-
-inline Quaternion operator*(Quaternion q1, Quaternion q2)
-{
- return Quaternion( q1.n * q2.n - q1.v.x * q2.v.x - q1.v.y * q2.v.y - q1.v.z * q2.v.z,
- q1.n * q2.v.x + q1.v.x * q2.n + q1.v.y * q2.v.z - q1.v.z * q2.v.y,
- q1.n * q2.v.y + q1.v.y * q2.n + q1.v.z * q2.v.x - q1.v.x * q2.v.z,
- q1.n * q2.v.z + q1.v.z * q2.n + q1.v.x * q2.v.y - q1.v.y * q2.v.x);
-}
-
-inline Quaternion operator*(Quaternion q, float s)
-{
- return Quaternion(q.n * s, q.v.x * s, q.v.y * s, q.v.z * s);
-}
-
-inline Quaternion operator*(float s, Quaternion q)
-{
- return Quaternion(q.n * s, q.v.x * s, q.v.y * s, q.v.z * s);
-}
-
-inline Quaternion operator*(Quaternion q, Vector v)
-{
- return Quaternion( -(q.v.x * v.x + q.v.y * v.y + q.v.z * v.z),
- q.n * v.x + q.v.y * v.z - q.v.z * v.y,
- q.n * v.y + q.v.z * v.x - q.v.x * v.z,
- q.n * v.z + q.v.x * v.y - q.v.y * v.x);
-}
-
-inline Quaternion operator*(Vector v, Quaternion q)
-{
- return Quaternion( -(q.v.x * v.x + q.v.y * v.y + q.v.z * v.z),
- q.n * v.x + q.v.z * v.y - q.v.y * v.z,
- q.n * v.y + q.v.x * v.z - q.v.z * v.x,
- q.n * v.z + q.v.y * v.x - q.v.x * v.y);
-}
-
-inline Quaternion operator/(Quaternion q, float s)
-{
- return Quaternion(q.n / s, q.v.x / s, q.v.y / s, q.v.z / s);
-}
-
-inline float QGetAngle(Quaternion q)
-{
- return (float) (2 * acosf(q.n));
-}
-
-inline Vector QGetAxis(Quaternion q)
-{
- Vector v;
- float m;
-
- v = q.GetVector();
- m = v.Magnitude();
-
- if (m <= tol)
- return Vector();
- else
- return v / m;
-}
-
-inline Quaternion QRotate(Quaternion q1, Quaternion q2)
-{
- return q1 * q2 * (~q1);
-}
-
-inline Vector QVRotate(Quaternion q, Vector v)
-{
- Quaternion t;
-
-
- t = q * v * (~q);
-
- return t.GetVector();
-}
-
-inline Quaternion MakeQFromEulerAngles(float x, float y, float z)
-{
- Quaternion q;
- double roll = DegreesToRadians(x);
- double pitch = DegreesToRadians(y);
- double yaw = DegreesToRadians(z);
-
- double cyaw, cpitch, croll, syaw, spitch, sroll;
- double cyawcpitch, syawspitch, cyawspitch, syawcpitch;
-
- cyaw = cos(0.5f * yaw);
- cpitch = cos(0.5f * pitch);
- croll = cos(0.5f * roll);
- syaw = sin(0.5f * yaw);
- spitch = sin(0.5f * pitch);
- sroll = sin(0.5f * roll);
-
- cyawcpitch = cyaw * cpitch;
- syawspitch = syaw * spitch;
- cyawspitch = cyaw * spitch;
- syawcpitch = syaw * cpitch;
-
- q.n = (float) (cyawcpitch * croll + syawspitch * sroll);
- q.v.x = (float) (cyawcpitch * sroll - syawspitch * croll);
- q.v.y = (float) (cyawspitch * croll + syawcpitch * sroll);
- q.v.z = (float) (syawcpitch * croll - cyawspitch * sroll);
-
- return q;
-}
-
-inline Vector MakeEulerAnglesFromQ(Quaternion q)
-{
- double r11, r21, r31, r32, r33;
- double q00, q11, q22, q33;
- double tmp;
- Vector u;
-
- q00 = q.n * q.n;
- q11 = q.v.x * q.v.x;
- q22 = q.v.y * q.v.y;
- q33 = q.v.z * q.v.z;
-
- r11 = q00 + q11 - q22 - q33;
- r21 = 2 * (q.v.x * q.v.y + q.n * q.v.z);
- r31 = 2 * (q.v.x * q.v.z - q.n * q.v.y);
- r32 = 2 * (q.v.y * q.v.z + q.n * q.v.x);
- r33 = q00 - q11 - q22 + q33;
-
- tmp = fabs(r31);
- if (tmp > 0.999999) {
- double r12 = 2 * (q.v.x * q.v.y - q.n * q.v.z);
- double r13 = 2 * (q.v.x * q.v.z + q.n * q.v.y);
-
- u.x = RadiansToDegrees(0.0f); //roll
- u.y = RadiansToDegrees((float) (-(pi / 2) * r31 / tmp)); // pitch
- u.z = RadiansToDegrees((float) atan2(-r12, -r31 * r13)); // yaw
- return u;
- }
-
- u.x = RadiansToDegrees((float) atan2(r32, r33)); // roll
- u.y = RadiansToDegrees((float) asinf(-r31)); // pitch
- u.z = RadiansToDegrees((float) atan2(r21, r11)); // yaw
- return u;
-
-
-}
-
-
-
-
-
-#endif
+++ /dev/null
-/*
-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/>.
-*/
-
-#include "Quaternions.h"
-
-// Functions
-quaternion Quat_Mult(quaternion q1, quaternion q2)
-{
- quaternion QResult;
- float a, b, c, d, e, f, g, h;
- a = (q1.w + q1.x) * (q2.w + q2.x);
- b = (q1.z - q1.y) * (q2.y - q2.z);
- c = (q1.w - q1.x) * (q2.y + q2.z);
- d = (q1.y + q1.z) * (q2.w - q2.x);
- e = (q1.x + q1.z) * (q2.x + q2.y);
- f = (q1.x - q1.z) * (q2.x - q2.y);
- g = (q1.w + q1.y) * (q2.w - q2.z);
- h = (q1.w - q1.y) * (q2.w + q2.z);
- QResult.w = b + (-e - f + g + h) / 2;
- QResult.x = a - (e + f + g + h) / 2;
- QResult.y = c + (e - f + g - h) / 2;
- QResult.z = d + (e - f - g + h) / 2;
- return QResult;
-}
-
-
-
-quaternion To_Quat(Matrix_t m)
-{
- // From Jason Shankel, (C) 2000.
- static quaternion Quat;
-
- static double Tr = m[0][0] + m[1][1] + m[2][2] + 1.0, fourD;
- static double q[4];
-
- static int i, j, k;
- if (Tr >= 1.0) {
- fourD = 2.0 * fast_sqrt(Tr);
- q[3] = fourD / 4.0;
- q[0] = (m[2][1] - m[1][2]) / fourD;
- q[1] = (m[0][2] - m[2][0]) / fourD;
- q[2] = (m[1][0] - m[0][1]) / fourD;
- } else {
- if (m[0][0] > m[1][1]) {
- i = 0;
- } else {
- i = 1;
- }
- if (m[2][2] > m[i][i]) {
- i = 2;
- }
- j = (i + 1) % 3;
- k = (j + 1) % 3;
- fourD = 2.0 * fast_sqrt(m[i][i] - m[j][j] - m[k][k] + 1.0);
- q[i] = fourD / 4.0;
- q[j] = (m[j][i] + m[i][j]) / fourD;
- q[k] = (m[k][i] + m[i][k]) / fourD;
- q[3] = (m[j][k] - m[k][j]) / fourD;
- }
-
- Quat.x = q[0];
- Quat.y = q[1];
- Quat.z = q[2];
- Quat.w = q[3];
- return Quat;
-}
-void Quat_2_Matrix(quaternion Quat, Matrix_t m)
-{
- // From the GLVelocity site (http://glvelocity.gamedev.net)
- float fW = Quat.w;
- float fX = Quat.x;
- float fY = Quat.y;
- float fZ = Quat.z;
- float fXX = fX * fX;
- float fYY = fY * fY;
- float fZZ = fZ * fZ;
- m[0][0] = 1.0f - 2.0f * (fYY + fZZ);
- m[1][0] = 2.0f * (fX * fY + fW * fZ);
- m[2][0] = 2.0f * (fX * fZ - fW * fY);
- m[3][0] = 0.0f;
- m[0][1] = 2.0f * (fX * fY - fW * fZ);
- m[1][1] = 1.0f - 2.0f * (fXX + fZZ);
- m[2][1] = 2.0f * (fY * fZ + fW * fX);
- m[3][1] = 0.0f;
- m[0][2] = 2.0f * (fX * fZ + fW * fY);
- m[1][2] = 2.0f * (fX * fZ - fW * fX);
- m[2][2] = 1.0f - 2.0f * (fXX + fYY);
- m[3][2] = 0.0f;
- m[0][3] = 0.0f;
- m[1][3] = 0.0f;
- m[2][3] = 0.0f;
- m[3][3] = 1.0f;
-}
-quaternion To_Quat(angle_axis Ang_Ax)
-{
- // From the Quaternion Powers article on gamedev.net
- static quaternion Quat;
-
- Quat.x = Ang_Ax.x * sin(Ang_Ax.angle / 2);
- Quat.y = Ang_Ax.y * sin(Ang_Ax.angle / 2);
- Quat.z = Ang_Ax.z * sin(Ang_Ax.angle / 2);
- Quat.w = cos(Ang_Ax.angle / 2);
- return Quat;
-}
-angle_axis Quat_2_AA(quaternion Quat)
-{
- static angle_axis Ang_Ax;
- static float scale, tw;
- tw = (float)acosf(Quat.w) * 2;
- scale = (float)sin(tw / 2.0);
- Ang_Ax.x = Quat.x / scale;
- Ang_Ax.y = Quat.y / scale;
- Ang_Ax.z = Quat.z / scale;
-
- Ang_Ax.angle = 2.0 * acosf(Quat.w) / (float)PI * 180;
- return Ang_Ax;
-}
-
-quaternion To_Quat(int In_Degrees, euler Euler)
-{
- // From the gamasutra quaternion article
- static quaternion Quat;
- static float cr, cp, cy, sr, sp, sy, cpcy, spsy;
- //If we are in Degree mode, convert to Radians
- if (In_Degrees) {
- Euler.x = Euler.x * (float)PI / 180;
- Euler.y = Euler.y * (float)PI / 180;
- Euler.z = Euler.z * (float)PI / 180;
- }
- //Calculate trig identities
- //Formerly roll, pitch, yaw
- cr = float(cos(Euler.x / 2));
- cp = float(cos(Euler.y / 2));
- cy = float(cos(Euler.z / 2));
- sr = float(sin(Euler.x / 2));
- sp = float(sin(Euler.y / 2));
- sy = float(sin(Euler.z / 2));
-
- cpcy = cp * cy;
- spsy = sp * sy;
- Quat.w = cr * cpcy + sr * spsy;
- Quat.x = sr * cpcy - cr * spsy;
- Quat.y = cr * sp * cy + sr * cp * sy;
- Quat.z = cr * cp * sy - sr * sp * cy;
-
- return Quat;
-}
-
-quaternion QNormalize(quaternion Quat)
-{
- static float norm;
- norm = Quat.x * Quat.x +
- Quat.y * Quat.y +
- Quat.z * Quat.z +
- Quat.w * Quat.w;
- Quat.x = float(Quat.x / norm);
- Quat.y = float(Quat.y / norm);
- Quat.z = float(Quat.z / norm);
- Quat.w = float(Quat.w / norm);
- return Quat;
-}
-
-XYZ Quat2Vector(quaternion Quat)
-{
- QNormalize(Quat);
-
- float fW = Quat.w;
- float fX = Quat.x;
- float fY = Quat.y;
- float fZ = Quat.z;
-
- XYZ tempvec;
-
- tempvec.x = 2.0f * (fX * fZ - fW * fY);
- tempvec.y = 2.0f * (fY * fZ + fW * fX);
- tempvec.z = 1.0f - 2.0f * (fX * fX + fY * fY);
-
- return tempvec;
-}
-
-bool PointInTriangle(Vector *p, Vector normal, float p11, float p12, float p13, float p21, float p22, float p23, float p31, float p32, float p33)
-{
- static float u0, u1, u2;
- static float v0, v1, v2;
- static float a, b;
- static float max;
- static int i, j;
- static bool bInter;
- static float pointv[3];
- static float p1v[3];
- static float p2v[3];
- static float p3v[3];
- static float normalv[3];
-
- bInter = 0;
-
- pointv[0] = p->x;
- pointv[1] = p->y;
- pointv[2] = p->z;
-
-
- p1v[0] = p11;
- p1v[1] = p12;
- p1v[2] = p13;
-
- p2v[0] = p21;
- p2v[1] = p22;
- p2v[2] = p23;
-
- p3v[0] = p31;
- p3v[1] = p32;
- p3v[2] = p33;
-
- normalv[0] = normal.x;
- normalv[1] = normal.y;
- normalv[2] = normal.z;
-
-#define ABS(X) (((X)<0.f)?-(X):(X) )
-#define MAX(A, B) (((A)<(B))?(B):(A))
- max = MAX(MAX(ABS(normalv[0]), ABS(normalv[1])), ABS(normalv[2]));
-#undef MAX
- if (max == ABS(normalv[0])) {
- i = 1; // y, z
- j = 2;
- }
- if (max == ABS(normalv[1])) {
- i = 0; // x, z
- j = 2;
- }
- if (max == ABS(normalv[2])) {
- i = 0; // x, y
- j = 1;
- }
-#undef ABS
-
- u0 = pointv[i] - p1v[i];
- v0 = pointv[j] - p1v[j];
- u1 = p2v[i] - p1v[i];
- v1 = p2v[j] - p1v[j];
- u2 = p3v[i] - p1v[i];
- v2 = p3v[j] - p1v[j];
-
- if (u1 > -1.0e-05f && u1 < 1.0e-05f) { // == 0.0f)
- b = u0 / u2;
- if (0.0f <= b && b <= 1.0f) {
- a = (v0 - b * v2) / v1;
- if ((a >= 0.0f) && (( a + b ) <= 1.0f))
- bInter = 1;
- }
- } else {
- b = (v0 * u1 - u0 * v1) / (v2 * u1 - u2 * v1);
- if (0.0f <= b && b <= 1.0f) {
- a = (u0 - b * u2) / u1;
- if ((a >= 0.0f) && (( a + b ) <= 1.0f ))
- bInter = 1;
- }
- }
-
- return bInter;
-}
-
-bool LineFacet(Vector p1, Vector p2, Vector pa, Vector pb, Vector pc, Vector *p)
-{
- static float d;
- static float denom, mu;
- static Vector n;
-
- //Calculate the parameters for the plane
- n.x = (pb.y - pa.y) * (pc.z - pa.z) - (pb.z - pa.z) * (pc.y - pa.y);
- n.y = (pb.z - pa.z) * (pc.x - pa.x) - (pb.x - pa.x) * (pc.z - pa.z);
- n.z = (pb.x - pa.x) * (pc.y - pa.y) - (pb.y - pa.y) * (pc.x - pa.x);
- n.Normalize();
- d = - n.x * pa.x - n.y * pa.y - n.z * pa.z;
-
- //Calculate the position on the line that intersects the plane
- denom = n.x * (p2.x - p1.x) + n.y * (p2.y - p1.y) + n.z * (p2.z - p1.z);
- if (fabs(denom) < 0.0000001) // Line and plane don't intersect
- return 0;
- mu = - (d + n.x * p1.x + n.y * p1.y + n.z * p1.z) / denom;
- p->x = p1.x + mu * (p2.x - p1.x);
- p->y = p1.y + mu * (p2.y - p1.y);
- p->z = p1.z + mu * (p2.z - p1.z);
- if (mu < 0 || mu > 1) // Intersection not along line segment
- return 0;
-
- if (!PointInTriangle( p, n, pa.x, pa.y, pa.z, pb.x, pb.y, pb.z, pc.x, pc.y, pc.z)) {
- return 0;
- }
-
- return 1;
-}
-
-bool PointInTriangle(XYZ *p, XYZ normal, XYZ *p1, XYZ *p2, XYZ *p3)
-{
- static float u0, u1, u2;
- static float v0, v1, v2;
- static float a, b;
- static float max;
- static int i, j;
- static bool bInter = 0;
- static float pointv[3];
- static float p1v[3];
- static float p2v[3];
- static float p3v[3];
- static float normalv[3];
-
- bInter = 0;
-
- pointv[0] = p->x;
- pointv[1] = p->y;
- pointv[2] = p->z;
-
-
- p1v[0] = p1->x;
- p1v[1] = p1->y;
- p1v[2] = p1->z;
-
- p2v[0] = p2->x;
- p2v[1] = p2->y;
- p2v[2] = p2->z;
-
- p3v[0] = p3->x;
- p3v[1] = p3->y;
- p3v[2] = p3->z;
-
- normalv[0] = normal.x;
- normalv[1] = normal.y;
- normalv[2] = normal.z;
-
-#define ABS(X) (((X)<0.f)?-(X):(X) )
-#define MAX(A, B) (((A)<(B))?(B):(A))
- max = MAX(MAX(ABS(normalv[0]), ABS(normalv[1])), ABS(normalv[2]));
-#undef MAX
- if (max == ABS(normalv[0])) {
- i = 1; // y, z
- j = 2;
- }
- if (max == ABS(normalv[1])) {
- i = 0; // x, z
- j = 2;
- }
- if (max == ABS(normalv[2])) {
- i = 0; // x, y
- j = 1;
- }
-#undef ABS
-
- u0 = pointv[i] - p1v[i];
- v0 = pointv[j] - p1v[j];
- u1 = p2v[i] - p1v[i];
- v1 = p2v[j] - p1v[j];
- u2 = p3v[i] - p1v[i];
- v2 = p3v[j] - p1v[j];
-
- if (u1 > -1.0e-05f && u1 < 1.0e-05f) { // == 0.0f)
- b = u0 / u2;
- if (0.0f <= b && b <= 1.0f) {
- a = (v0 - b * v2) / v1;
- if ((a >= 0.0f) && (( a + b ) <= 1.0f))
- bInter = 1;
- }
- } else {
- b = (v0 * u1 - u0 * v1) / (v2 * u1 - u2 * v1);
- if (0.0f <= b && b <= 1.0f) {
- a = (u0 - b * u2) / u1;
- if ((a >= 0.0f) && (( a + b ) <= 1.0f ))
- bInter = 1;
- }
- }
-
- return bInter;
-}
-
-bool LineFacet(XYZ p1, XYZ p2, XYZ pa, XYZ pb, XYZ pc, XYZ *p)
-{
- static float d;
- static float denom, mu;
- static XYZ n;
-
- //Calculate the parameters for the plane
- n.x = (pb.y - pa.y) * (pc.z - pa.z) - (pb.z - pa.z) * (pc.y - pa.y);
- n.y = (pb.z - pa.z) * (pc.x - pa.x) - (pb.x - pa.x) * (pc.z - pa.z);
- n.z = (pb.x - pa.x) * (pc.y - pa.y) - (pb.y - pa.y) * (pc.x - pa.x);
- Normalise(&n);
- d = - n.x * pa.x - n.y * pa.y - n.z * pa.z;
-
- //Calculate the position on the line that intersects the plane
- denom = n.x * (p2.x - p1.x) + n.y * (p2.y - p1.y) + n.z * (p2.z - p1.z);
- if (fabs(denom) < 0.0000001) // Line and plane don't intersect
- return 0;
- mu = - (d + n.x * p1.x + n.y * p1.y + n.z * p1.z) / denom;
- p->x = p1.x + mu * (p2.x - p1.x);
- p->y = p1.y + mu * (p2.y - p1.y);
- p->z = p1.z + mu * (p2.z - p1.z);
- if (mu < 0 || mu > 1) // Intersection not along line segment
- return 0;
-
- if (!PointInTriangle( p, n, &pa, &pb, &pc)) {
- return 0;
- }
-
- return 1;
-}
-
-float LineFacetd(XYZ p1, XYZ p2, XYZ pa, XYZ pb, XYZ pc, XYZ *p)
-{
- static float d;
- static float denom, mu;
- static XYZ n;
-
- //Calculate the parameters for the plane
- n.x = (pb.y - pa.y) * (pc.z - pa.z) - (pb.z - pa.z) * (pc.y - pa.y);
- n.y = (pb.z - pa.z) * (pc.x - pa.x) - (pb.x - pa.x) * (pc.z - pa.z);
- n.z = (pb.x - pa.x) * (pc.y - pa.y) - (pb.y - pa.y) * (pc.x - pa.x);
- Normalise(&n);
- d = - n.x * pa.x - n.y * pa.y - n.z * pa.z;
-
- //Calculate the position on the line that intersects the plane
- denom = n.x * (p2.x - p1.x) + n.y * (p2.y - p1.y) + n.z * (p2.z - p1.z);
- if (fabs(denom) < 0.0000001) // Line and plane don't intersect
- return 0;
- mu = - (d + n.x * p1.x + n.y * p1.y + n.z * p1.z) / denom;
- p->x = p1.x + mu * (p2.x - p1.x);
- p->y = p1.y + mu * (p2.y - p1.y);
- p->z = p1.z + mu * (p2.z - p1.z);
- if (mu < 0 || mu > 1) // Intersection not along line segment
- return 0;
-
- if (!PointInTriangle( p, n, &pa, &pb, &pc)) {
- return 0;
- }
-
- return 1;
-}
-
-float LineFacetd(XYZ p1, XYZ p2, XYZ pa, XYZ pb, XYZ pc, XYZ n, XYZ *p)
-{
- static float d;
- static float denom, mu;
-
- //Calculate the parameters for the plane
- d = - n.x * pa.x - n.y * pa.y - n.z * pa.z;
-
- //Calculate the position on the line that intersects the plane
- denom = n.x * (p2.x - p1.x) + n.y * (p2.y - p1.y) + n.z * (p2.z - p1.z);
- if (fabs(denom) < 0.0000001) // Line and plane don't intersect
- return 0;
- mu = - (d + n.x * p1.x + n.y * p1.y + n.z * p1.z) / denom;
- p->x = p1.x + mu * (p2.x - p1.x);
- p->y = p1.y + mu * (p2.y - p1.y);
- p->z = p1.z + mu * (p2.z - p1.z);
- if (mu < 0 || mu > 1) // Intersection not along line segment
- return 0;
-
- if (!PointInTriangle( p, n, &pa, &pb, &pc)) {
- return 0;
- }
- return 1;
-}
-
-float LineFacetd(XYZ *p1, XYZ *p2, XYZ *pa, XYZ *pb, XYZ *pc, XYZ *p)
-{
- static float d;
- static float denom, mu;
- static XYZ n;
-
- //Calculate the parameters for the plane
- n.x = (pb->y - pa->y) * (pc->z - pa->z) - (pb->z - pa->z) * (pc->y - pa->y);
- n.y = (pb->z - pa->z) * (pc->x - pa->x) - (pb->x - pa->x) * (pc->z - pa->z);
- n.z = (pb->x - pa->x) * (pc->y - pa->y) - (pb->y - pa->y) * (pc->x - pa->x);
- Normalise(&n);
- d = - n.x * pa->x - n.y * pa->y - n.z * pa->z;
-
-
- //Calculate the position on the line that intersects the plane
- denom = n.x * (p2->x - p1->x) + n.y * (p2->y - p1->y) + n.z * (p2->z - p1->z);
- if (fabs(denom) < 0.0000001) // Line and plane don't intersect
- return 0;
- mu = - (d + n.x * p1->x + n.y * p1->y + n.z * p1->z) / denom;
- p->x = p1->x + mu * (p2->x - p1->x);
- p->y = p1->y + mu * (p2->y - p1->y);
- p->z = p1->z + mu * (p2->z - p1->z);
- if (mu < 0 || mu > 1) // Intersection not along line segment
- return 0;
-
- if (!PointInTriangle( p, n, pa, pb, pc)) {
- return 0;
- }
- return 1;
-}
-
-float LineFacetd(XYZ *p1, XYZ *p2, XYZ *pa, XYZ *pb, XYZ *pc, XYZ *n, XYZ *p)
-{
- static float d;
- static float denom, mu;
-
- //Calculate the parameters for the plane
- d = - n->x * pa->x - n->y * pa->y - n->z * pa->z;
-
- //Calculate the position on the line that intersects the plane
- denom = n->x * (p2->x - p1->x) + n->y * (p2->y - p1->y) + n->z * (p2->z - p1->z);
- if (fabs(denom) < 0.0000001) // Line and plane don't intersect
- return 0;
- mu = - (d + n->x * p1->x + n->y * p1->y + n->z * p1->z) / denom;
- p->x = p1->x + mu * (p2->x - p1->x);
- p->y = p1->y + mu * (p2->y - p1->y);
- p->z = p1->z + mu * (p2->z - p1->z);
- if (mu < 0 || mu > 1) // Intersection not along line segment
- return 0;
-
- if (!PointInTriangle( p, *n, pa, pb, pc)) {
- return 0;
- }
- return 1;
-}
-
-
+++ /dev/null
-/*
-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 _QUATERNIONS_H_
-#define _QUATERNIONS_H_
-
-#include "math.h"
-#include "PhysicsMath.h"
-#include "gamegl.h"
-
-/**> Quaternion Structures <**/
-#define PI 3.14159265355555897932384626
-#define RADIANS 0
-#define DEGREES 1
-#define deg2rad .0174532925
-
-//using namespace std;
-typedef float Matrix_t [4][4];
-struct euler {
- float x, y, z;
-};
-struct angle_axis {
- float x, y, z, angle;
-};
-struct quaternion {
- float x, y, z, w;
-};
-
-class XYZ
-{
-public:
- float x;
- float y;
- float z;
- XYZ() : x(0.0f), y(0.0f), z(0.0f) {}
- inline XYZ operator+(XYZ add);
- inline XYZ operator-(XYZ add);
- inline XYZ operator*(float add);
- inline XYZ operator*(XYZ add);
- inline XYZ operator/(float add);
- inline void operator+=(XYZ add);
- inline void operator-=(XYZ add);
- inline void operator*=(float add);
- inline void operator*=(XYZ add);
- inline void operator/=(float add);
- inline void operator=(float add);
- inline void vec(Vector add);
- inline bool operator==(XYZ add);
-};
-
-/*********************> Quaternion Function definition <********/
-quaternion To_Quat(int Degree_Flag, euler Euler);
-quaternion To_Quat(angle_axis Ang_Ax);
-quaternion To_Quat(Matrix_t m);
-angle_axis Quat_2_AA(quaternion Quat);
-void Quat_2_Matrix(quaternion Quat, Matrix_t m);
-quaternion Normalize(quaternion Quat);
-quaternion Quat_Mult(quaternion q1, quaternion q2);
-quaternion QNormalize(quaternion Quat);
-XYZ Quat2Vector(quaternion Quat);
-
-inline void CrossProduct(XYZ *P, XYZ *Q, XYZ *V);
-inline void CrossProduct(XYZ P, XYZ Q, XYZ *V);
-inline void Normalise(XYZ *vectory);
-inline float normaldotproduct(XYZ point1, XYZ point2);
-inline float fast_sqrt (register float arg);
-bool PointInTriangle(XYZ *p, XYZ normal, XYZ *p1, XYZ *p2, XYZ *p3);
-bool LineFacet(XYZ p1, XYZ p2, XYZ pa, XYZ pb, XYZ pc, XYZ *p);
-float LineFacetd(XYZ p1, XYZ p2, XYZ pa, XYZ pb, XYZ pc, XYZ *p);
-float LineFacetd(XYZ p1, XYZ p2, XYZ pa, XYZ pb, XYZ pc, XYZ n, XYZ *p);
-float LineFacetd(XYZ *p1, XYZ *p2, XYZ *pa, XYZ *pb, XYZ *pc, XYZ *n, XYZ *p);
-float LineFacetd(XYZ *p1, XYZ *p2, XYZ *pa, XYZ *pb, XYZ *pc, XYZ *p);
-bool PointInTriangle(Vector *p, Vector normal, float p11, float p12, float p13, float p21, float p22, float p23, float p31, float p32, float p33);
-bool LineFacet(Vector p1, Vector p2, Vector pa, Vector pb, Vector pc, Vector *p);
-inline void ReflectVector(XYZ *vel, const XYZ *n);
-inline void ReflectVector(XYZ *vel, const XYZ &n);
-inline XYZ DoRotation(XYZ thePoint, float xang, float yang, float zang);
-inline XYZ DoRotationRadian(XYZ thePoint, float xang, float yang, float zang);
-inline float findDistance(XYZ *point1, XYZ *point2);
-inline float findLength(XYZ *point1);
-inline float findLengthfast(XYZ *point1);
-inline float distsq(XYZ *point1, XYZ *point2);
-inline float distsq(XYZ point1, XYZ point2);
-inline float distsqflat(XYZ *point1, XYZ *point2);
-inline float dotproduct(const XYZ *point1, const XYZ *point2);
-bool sphere_line_intersection (
- float x1, float y1 , float z1,
- float x2, float y2 , float z2,
- float x3, float y3 , float z3, float r );
-bool sphere_line_intersection (
- XYZ *p1, XYZ *p2, XYZ *p3, float *r );
-inline bool DistancePointLine( XYZ *Point, XYZ *LineStart, XYZ *LineEnd, float *Distance, XYZ *Intersection );
-
-
-inline void Normalise(XYZ *vectory)
-{
- static float d;
- d = fast_sqrt(vectory->x * vectory->x + vectory->y * vectory->y + vectory->z * vectory->z);
- if (d == 0) {
- return;
- }
- vectory->x /= d;
- vectory->y /= d;
- vectory->z /= d;
-}
-
-inline XYZ XYZ::operator+(XYZ add)
-{
- static XYZ ne;
- ne = add;
- ne.x += x;
- ne.y += y;
- ne.z += z;
- return ne;
-}
-
-inline XYZ XYZ::operator-(XYZ add)
-{
- static XYZ ne;
- ne = add;
- ne.x = x - ne.x;
- ne.y = y - ne.y;
- ne.z = z - ne.z;
- return ne;
-}
-
-inline XYZ XYZ::operator*(float add)
-{
- static XYZ ne;
- ne.x = x * add;
- ne.y = y * add;
- ne.z = z * add;
- return ne;
-}
-
-inline XYZ XYZ::operator*(XYZ add)
-{
- static XYZ ne;
- ne.x = x * add.x;
- ne.y = y * add.y;
- ne.z = z * add.z;
- return ne;
-}
-
-inline XYZ XYZ::operator/(float add)
-{
- static XYZ ne;
- ne.x = x / add;
- ne.y = y / add;
- ne.z = z / add;
- return ne;
-}
-
-inline void XYZ::operator+=(XYZ add)
-{
- x += add.x;
- y += add.y;
- z += add.z;
-}
-
-inline void XYZ::operator-=(XYZ add)
-{
- x = x - add.x;
- y = y - add.y;
- z = z - add.z;
-}
-
-inline void XYZ::operator*=(float add)
-{
- x = x * add;
- y = y * add;
- z = z * add;
-}
-
-inline void XYZ::operator*=(XYZ add)
-{
- x = x * add.x;
- y = y * add.y;
- z = z * add.z;
-}
-
-inline void XYZ::operator/=(float add)
-{
- x = x / add;
- y = y / add;
- z = z / add;
-}
-
-inline void XYZ::operator=(float add)
-{
- x = add;
- y = add;
- z = add;
-}
-
-inline void XYZ::vec(Vector add)
-{
- x = add.x;
- y = add.y;
- z = add.z;
-}
-
-inline bool XYZ::operator==(XYZ add)
-{
- if (x == add.x && y == add.y && z == add.z)
- return 1;
- return 0;
-}
-
-inline void CrossProduct(XYZ *P, XYZ *Q, XYZ *V)
-{
- V->x = P->y * Q->z - P->z * Q->y;
- V->y = P->z * Q->x - P->x * Q->z;
- V->z = P->x * Q->y - P->y * Q->x;
-}
-
-inline void CrossProduct(XYZ P, XYZ Q, XYZ *V)
-{
- V->x = P.y * Q.z - P.z * Q.y;
- V->y = P.z * Q.x - P.x * Q.z;
- V->z = P.x * Q.y - P.y * Q.x;
-}
-
-inline float fast_sqrt (register float arg)
-{
- return sqrtf(arg);
-}
-
-inline float normaldotproduct(XYZ point1, XYZ point2)
-{
- static GLfloat returnvalue;
- Normalise(&point1);
- Normalise(&point2);
- returnvalue = (point1.x * point2.x + point1.y * point2.y + point1.z * point2.z);
- return returnvalue;
-}
-
-inline void ReflectVector(XYZ *vel, const XYZ *n)
-{
- ReflectVector(vel, *n);
-}
-
-inline void ReflectVector(XYZ *vel, const XYZ &n)
-{
- static XYZ vn;
- static XYZ vt;
- static float dotprod;
-
- dotprod = dotproduct(&n, vel);
- vn.x = n.x * dotprod;
- vn.y = n.y * dotprod;
- vn.z = n.z * dotprod;
-
- vt.x = vel->x - vn.x;
- vt.y = vel->y - vn.y;
- vt.z = vel->z - vn.z;
-
- vel->x = vt.x - vn.x;
- vel->y = vt.y - vn.y;
- vel->z = vt.z - vn.z;
-}
-
-inline float dotproduct(const XYZ *point1, const XYZ *point2)
-{
- static GLfloat returnvalue;
- returnvalue = (point1->x * point2->x + point1->y * point2->y + point1->z * point2->z);
- return returnvalue;
-}
-
-inline float findDistance(XYZ *point1, XYZ *point2)
-{
- return(fast_sqrt((point1->x - point2->x) * (point1->x - point2->x) + (point1->y - point2->y) * (point1->y - point2->y) + (point1->z - point2->z) * (point1->z - point2->z)));
-}
-
-inline float findLength(XYZ *point1)
-{
- return(fast_sqrt((point1->x) * (point1->x) + (point1->y) * (point1->y) + (point1->z) * (point1->z)));
-}
-
-
-inline float findLengthfast(XYZ *point1)
-{
- return((point1->x) * (point1->x) + (point1->y) * (point1->y) + (point1->z) * (point1->z));
-}
-
-inline float distsq(XYZ *point1, XYZ *point2)
-{
- return((point1->x - point2->x) * (point1->x - point2->x) + (point1->y - point2->y) * (point1->y - point2->y) + (point1->z - point2->z) * (point1->z - point2->z));
-}
-
-inline float distsq(XYZ point1, XYZ point2)
-{
- return((point1.x - point2.x) * (point1.x - point2.x) + (point1.y - point2.y) * (point1.y - point2.y) + (point1.z - point2.z) * (point1.z - point2.z));
-}
-
-inline float distsqflat(XYZ *point1, XYZ *point2)
-{
- return((point1->x - point2->x) * (point1->x - point2->x) + (point1->z - point2->z) * (point1->z - point2->z));
-}
-
-inline XYZ DoRotation(XYZ thePoint, float xang, float yang, float zang)
-{
- static XYZ newpoint;
- if (xang) {
- xang *= 6.283185f;
- xang /= 360;
- }
- if (yang) {
- yang *= 6.283185f;
- yang /= 360;
- }
- if (zang) {
- zang *= 6.283185f;
- zang /= 360;
- }
-
-
- if (yang) {
- newpoint.z = thePoint.z * cosf(yang) - thePoint.x * sinf(yang);
- newpoint.x = thePoint.z * sinf(yang) + thePoint.x * cosf(yang);
- thePoint.z = newpoint.z;
- thePoint.x = newpoint.x;
- }
-
- if (zang) {
- newpoint.x = thePoint.x * cosf(zang) - thePoint.y * sinf(zang);
- newpoint.y = thePoint.y * cosf(zang) + thePoint.x * sinf(zang);
- thePoint.x = newpoint.x;
- thePoint.y = newpoint.y;
- }
-
- if (xang) {
- newpoint.y = thePoint.y * cosf(xang) - thePoint.z * sinf(xang);
- newpoint.z = thePoint.y * sinf(xang) + thePoint.z * cosf(xang);
- thePoint.z = newpoint.z;
- thePoint.y = newpoint.y;
- }
-
- return thePoint;
-}
-
-inline float square( float f )
-{
- return (f * f) ;
-}
-
-inline bool sphere_line_intersection (
- float x1, float y1 , float z1,
- float x2, float y2 , float z2,
- float x3, float y3 , float z3, float r )
-{
-
- // x1,y1,z1 P1 coordinates (point of line)
- // x2,y2,z2 P2 coordinates (point of line)
- // x3,y3,z3, r P3 coordinates and radius (sphere)
- // x,y,z intersection coordinates
- //
- // This function returns a pointer array which first index indicates
- // the number of intersection point, followed by coordinate pairs.
-
- //~ static float x , y , z;
- static float a, b, c, /*mu,*/ i ;
-
- if (x1 > x3 + r && x2 > x3 + r) return(0);
- if (x1 < x3 - r && x2 < x3 - r) return(0);
- if (y1 > y3 + r && y2 > y3 + r) return(0);
- if (y1 < y3 - r && y2 < y3 - r) return(0);
- if (z1 > z3 + r && z2 > z3 + r) return(0);
- if (z1 < z3 - r && z2 < z3 - r) return(0);
- a = square(x2 - x1) + square(y2 - y1) + square(z2 - z1);
- b = 2 * ( (x2 - x1) * (x1 - x3)
- + (y2 - y1) * (y1 - y3)
- + (z2 - z1) * (z1 - z3) ) ;
- c = square(x3) + square(y3) +
- square(z3) + square(x1) +
- square(y1) + square(z1) -
- 2 * ( x3 * x1 + y3 * y1 + z3 * z1 ) - square(r) ;
- i = b * b - 4 * a * c ;
-
- if ( i < 0.0 ) {
- // no intersection
- return(0);
- }
- return(1);
-}
-
-inline bool sphere_line_intersection (
- XYZ *p1, XYZ *p2, XYZ *p3, float *r )
-{
-
- // x1,p1->y,p1->z P1 coordinates (point of line)
- // p2->x,p2->y,p2->z P2 coordinates (point of line)
- // p3->x,p3->y,p3->z, r P3 coordinates and radius (sphere)
- // x,y,z intersection coordinates
- //
- // This function returns a pointer array which first index indicates
- // the number of intersection point, followed by coordinate pairs.
-
- //~ static float x , y , z;
- static float a, b, c, /*mu,*/ i ;
-
- if (p1->x > p3->x + *r && p2->x > p3->x + *r) return(0);
- if (p1->x < p3->x - *r && p2->x < p3->x - *r) return(0);
- if (p1->y > p3->y + *r && p2->y > p3->y + *r) return(0);
- if (p1->y < p3->y - *r && p2->y < p3->y - *r) return(0);
- if (p1->z > p3->z + *r && p2->z > p3->z + *r) return(0);
- if (p1->z < p3->z - *r && p2->z < p3->z - *r) return(0);
- a = square(p2->x - p1->x) + square(p2->y - p1->y) + square(p2->z - p1->z);
- b = 2 * ( (p2->x - p1->x) * (p1->x - p3->x)
- + (p2->y - p1->y) * (p1->y - p3->y)
- + (p2->z - p1->z) * (p1->z - p3->z) ) ;
- c = square(p3->x) + square(p3->y) +
- square(p3->z) + square(p1->x) +
- square(p1->y) + square(p1->z) -
- 2 * ( p3->x * p1->x + p3->y * p1->y + p3->z * p1->z ) - square(*r) ;
- i = b * b - 4 * a * c ;
-
- if ( i < 0.0 ) {
- // no intersection
- return(0);
- }
- return(1);
-}
-
-inline XYZ DoRotationRadian(XYZ thePoint, float xang, float yang, float zang)
-{
- static XYZ newpoint;
- static XYZ oldpoint;
-
- oldpoint = thePoint;
-
- if (yang != 0) {
- newpoint.z = oldpoint.z * cosf(yang) - oldpoint.x * sinf(yang);
- newpoint.x = oldpoint.z * sinf(yang) + oldpoint.x * cosf(yang);
- oldpoint.z = newpoint.z;
- oldpoint.x = newpoint.x;
- }
-
- if (zang != 0) {
- newpoint.x = oldpoint.x * cosf(zang) - oldpoint.y * sinf(zang);
- newpoint.y = oldpoint.y * cosf(zang) + oldpoint.x * sinf(zang);
- oldpoint.x = newpoint.x;
- oldpoint.y = newpoint.y;
- }
-
- if (xang != 0) {
- newpoint.y = oldpoint.y * cosf(xang) - oldpoint.z * sinf(xang);
- newpoint.z = oldpoint.y * sinf(xang) + oldpoint.z * cosf(xang);
- oldpoint.z = newpoint.z;
- oldpoint.y = newpoint.y;
- }
-
- return oldpoint;
-
-}
-
-inline bool DistancePointLine( XYZ *Point, XYZ *LineStart, XYZ *LineEnd, float *Distance, XYZ *Intersection )
-{
- float LineMag;
- float U;
-
- LineMag = findDistance( LineEnd, LineStart );
-
- U = ( ( ( Point->x - LineStart->x ) * ( LineEnd->x - LineStart->x ) ) +
- ( ( Point->y - LineStart->y ) * ( LineEnd->y - LineStart->y ) ) +
- ( ( Point->z - LineStart->z ) * ( LineEnd->z - LineStart->z ) ) ) /
- ( LineMag * LineMag );
-
- if ( U < 0.0f || U > 1.0f )
- return 0; // closest point does not fall within the line segment
-
- Intersection->x = LineStart->x + U * ( LineEnd->x - LineStart->x );
- Intersection->y = LineStart->y + U * ( LineEnd->y - LineStart->y );
- Intersection->z = LineStart->z + U * ( LineEnd->z - LineStart->z );
-
- *Distance = findDistance( Point, Intersection );
-
- return 1;
-}
-
-#endif
+++ /dev/null
-/*
-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 _RANDOM_H_
-#define _RANDOM_H_
-
-#include <stdlib.h>
-
-static inline short Random()
-{
- return rand();
-}
-
-#endif
+++ /dev/null
-/*
-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/>.
-*/
-
-#include "Settings.h"
-#include "Game.h"
-#include "Input.h"
-#include "Utils/Folders.h"
-
-using namespace Game;
-
-void DefaultSettings()
-{
- detail = 2;
- ismotionblur = 1;
- usermousesensitivity = 1;
- newscreenwidth = kContextWidth = 1024;
- newscreenheight = kContextHeight = 768;
- fullscreen = 0;
- floatjump = 0;
- autoslomo = 1;
- decals = 1;
- invertmouse = 0;
- bloodtoggle = 0;
- foliage = 1;
- musictoggle = 1;
- trilinear = 1;
- gamespeed = 1;
- damageeffects = 0;
- texttoggle = 1;
- alwaysblur = 0;
- showpoints = 0;
- showdamagebar = 0;
- immediate = 0;
- velocityblur = 0;
- volume = 0.8f;
- ambientsound = 1;
- devtools = 0;
-
- crouchkey = SDL_SCANCODE_LSHIFT;
- jumpkey = SDL_SCANCODE_SPACE;
- leftkey = SDL_SCANCODE_A;
- forwardkey = SDL_SCANCODE_W;
- backkey = SDL_SCANCODE_S;
- rightkey = SDL_SCANCODE_D;
- drawkey = SDL_SCANCODE_E;
- throwkey = SDL_SCANCODE_Q;
- attackkey = MOUSEBUTTON1;
- consolekey = SDL_SCANCODE_GRAVE;
-
- newdetail = detail;
-}
-
-void SaveSettings()
-{
- if (newdetail < 0)
- newdetail = 0;
- if (newdetail > 2)
- newdetail = 2;
- if (newscreenwidth > 3000)
- newscreenwidth = screenwidth;
- if (newscreenwidth < 0)
- newscreenwidth = screenwidth;
- if (newscreenheight > 3000)
- newscreenheight = screenheight;
- if (newscreenheight < 0)
- newscreenheight = screenheight;
- errno = 0;
- ofstream opstream(Folders::getConfigFilePath());
- if (opstream.fail()) {
- perror(("Couldn't save config file " + Folders::getConfigFilePath()).c_str());
- return;
- }
- opstream << "Screenwidth:\n";
- opstream << newscreenwidth;
- opstream << "\nScreenheight:\n";
- opstream << newscreenheight;
- opstream << "\nFullscreen:\n";
- opstream << fullscreen;
- opstream << "\nMouse sensitivity:\n";
- opstream << usermousesensitivity;
- opstream << "\nBlur(0,1):\n";
- opstream << ismotionblur;
- opstream << "\nOverall Detail(0,1,2) higher=better:\n";
- opstream << newdetail;
- opstream << "\nFloating jump:\n";
- opstream << floatjump;
- opstream << "\nMouse jump:\n";
- opstream << mousejump;
- opstream << "\nAmbient sound:\n";
- opstream << ambientsound;
- opstream << "\nBlood (0,1,2):\n";
- opstream << bloodtoggle;
- opstream << "\nAuto slomo:\n";
- opstream << autoslomo;
- opstream << "\nFoliage:\n";
- opstream << foliage;
- opstream << "\nMusic:\n";
- opstream << musictoggle;
- opstream << "\nTrilinear:\n";
- opstream << trilinear;
- opstream << "\nDecals(shadows,blood puddles,etc):\n";
- opstream << decals;
- opstream << "\nInvert mouse:\n";
- opstream << invertmouse;
- opstream << "\nGamespeed:\n";
- if (oldgamespeed == 0)
- oldgamespeed = 1;
- opstream << oldgamespeed;
- opstream << "\nDamage effects(blackout, doublevision):\n";
- opstream << damageeffects;
- opstream << "\nText:\n";
- opstream << texttoggle;
- opstream << "\nShow Points:\n";
- opstream << showpoints;
- opstream << "\nAlways Blur:\n";
- opstream << alwaysblur;
- opstream << "\nImmediate mode (turn on on G5):\n";
- opstream << immediate;
- opstream << "\nVelocity blur:\n";
- opstream << velocityblur;
- opstream << "\nVolume:\n";
- opstream << volume;
- opstream << "\nForward key:\n";
- opstream << forwardkey;
- opstream << "\nBack key:\n";
- opstream << backkey;
- opstream << "\nLeft key:\n";
- opstream << leftkey;
- opstream << "\nRight key:\n";
- opstream << rightkey;
- opstream << "\nJump key:\n";
- opstream << jumpkey;
- opstream << "\nCrouch key:\n";
- opstream << crouchkey;
- opstream << "\nDraw key:\n";
- opstream << drawkey;
- opstream << "\nThrow key:\n";
- opstream << throwkey;
- opstream << "\nAttack key:\n";
- opstream << attackkey;
- opstream << "\nConsole key:\n";
- opstream << consolekey;
- opstream << "\nDamage bar:\n";
- opstream << showdamagebar;
- opstream << "\nStereoMode:\n";
- opstream << stereomode;
- opstream << "\nStereoSeparation:\n";
- opstream << stereoseparation;
- opstream << "\nStereoReverse:\n";
- opstream << stereoreverse;
- opstream << "\n";
- opstream.close();
-}
-
-bool LoadSettings()
-{
- errno = 0;
- ifstream ipstream(Folders::getConfigFilePath(), std::ios::in);
- if ( ipstream.fail() ) {
- perror(("Couldn't read config file " + Folders::getConfigFilePath()).c_str());
- return false;
- }
- char setting[256];
- char string[256];
-
- printf("Loading config\n");
- while (!ipstream.eof()) {
- ipstream.getline( setting, sizeof(setting) );
-
- // skip blank lines
- // assume lines starting with spaces are all blank
- if ( strlen(setting) == 0 || setting[0] == ' ' || setting[0] == '\t')
- continue;
- //~ printf("setting : %s\n",setting);
-
- if ( ipstream.eof() || ipstream.fail() ) {
- fprintf(stderr, "Error reading config file: Got setting name '%s', but value can't be read\n", setting);
- ipstream.close();
- return false;
- }
-
-
- if ( !strncmp(setting, "Screenwidth", 11) ) {
- ipstream >> kContextWidth;
- } else if ( !strncmp(setting, "Screenheight", 12) ) {
- ipstream >> kContextHeight;
- } else if ( !strncmp(setting, "Fullscreen", 10) ) {
- ipstream >> fullscreen;
- } else if ( !strncmp(setting, "Mouse sensitivity", 17) ) {
- ipstream >> usermousesensitivity;
- } else if ( !strncmp(setting, "Blur", 4) ) {
- ipstream >> ismotionblur;
- } else if ( !strncmp(setting, "Overall Detail", 14) ) {
- ipstream >> detail;
- } else if ( !strncmp(setting, "Floating jump", 13) ) {
- ipstream >> floatjump;
- } else if ( !strncmp(setting, "Mouse jump", 10) ) {
- ipstream >> mousejump;
- } else if ( !strncmp(setting, "Ambient sound", 13) ) {
- ipstream >> ambientsound;
- } else if ( !strncmp(setting, "Blood ", 6) ) {
- ipstream >> bloodtoggle;
- } else if ( !strncmp(setting, "Auto slomo", 10) ) {
- ipstream >> autoslomo;
- } else if ( !strncmp(setting, "Foliage", 7) ) {
- ipstream >> foliage;
- } else if ( !strncmp(setting, "Music", 5) ) {
- ipstream >> musictoggle;
- } else if ( !strncmp(setting, "Trilinear", 9) ) {
- ipstream >> trilinear;
- } else if ( !strncmp(setting, "Decals", 6) ) {
- ipstream >> decals;
- } else if ( !strncmp(setting, "Invert mouse", 12) ) {
- ipstream >> invertmouse;
- } else if ( !strncmp(setting, "Gamespeed", 9) ) {
- ipstream >> gamespeed;
- oldgamespeed = gamespeed;
- if (oldgamespeed == 0) {
- gamespeed = 1;
- oldgamespeed = 1;
- }
- } else if ( !strncmp(setting, "Damage effects", 14) ) {
- ipstream >> damageeffects;
- } else if ( !strncmp(setting, "Text", 4) ) {
- ipstream >> texttoggle;
- } else if ( !strncmp(setting, "Devtools", 5) ) {
- ipstream >> devtools;
- } else if ( !strncmp(setting, "Show Points", 11) ) {
- ipstream >> showpoints;
- } else if ( !strncmp(setting, "Always Blur", 11) ) {
- ipstream >> alwaysblur;
- } else if ( !strncmp(setting, "Immediate mode ", 15) ) {
- ipstream >> immediate;
- } else if ( !strncmp(setting, "Velocity blur", 13) ) {
- ipstream >> velocityblur;
- } else if ( !strncmp(setting, "Volume", 6) ) {
- ipstream >> volume;
- } else if ( !strncmp(setting, "Forward key", 11) ) {
- ipstream >> forwardkey;
- } else if ( !strncmp(setting, "Back key", 8) ) {
- ipstream >> backkey;
- } else if ( !strncmp(setting, "Left key", 8) ) {
- ipstream >> leftkey;
- } else if ( !strncmp(setting, "Right key", 9) ) {
- ipstream >> rightkey;
- } else if ( !strncmp(setting, "Jump key", 8) ) {
- ipstream >> jumpkey;
- } else if ( !strncmp(setting, "Crouch key", 10) ) {
- ipstream >> crouchkey;
- } else if ( !strncmp(setting, "Draw key", 8) ) {
- ipstream >> drawkey;
- } else if ( !strncmp(setting, "Throw key", 9) ) {
- ipstream >> throwkey;
- } else if ( !strncmp(setting, "Attack key", 10) ) {
- ipstream >> attackkey;
- } else if ( !strncmp(setting, "Console key", 11) ) {
- ipstream >> consolekey;
- } else if ( !strncmp(setting, "Damage bar", 10) ) {
- ipstream >> showdamagebar;
- } else if ( !strncmp(setting, "StereoMode", 10) ) {
- int i;
- ipstream >> i;
- stereomode = (StereoMode)i;
- } else if ( !strncmp(setting, "StereoSeparation", 16) ) {
- ipstream >> stereoseparation;
- } else if ( !strncmp(setting, "StereoReverse", 13) ) {
- ipstream >> stereoreverse;
- } else {
- ipstream >> string;
- fprintf(stderr, "Unknown config option '%s' with value '%s'. Ignoring.\n", setting, string);
- }
-
- if ( ipstream.fail() ) {
- fprintf(stderr, "Error reading config file: EOF reached when trying to read value for setting '%s'.\n", setting);
- ipstream.close();
- return false;
- }
-
- if ( ipstream.bad() ) {
- fprintf(stderr, "Error reading config file: Failed to read value for setting '%s'.\n", setting);
- ipstream.close();
- return false;
- }
- }
-
- ipstream.close();
-
- if (detail > 2)
- detail = 2;
- if (detail < 0)
- detail = 0;
- if (screenwidth < 0)
- screenwidth = 1024;
- if (screenheight < 0)
- screenheight = 768;
-
- newdetail = detail;
- return true;
-}
+++ /dev/null
-/*
-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 SETTINGS_H_
-#define SETTINGS_H_
-
-#include "Game.h"
-
-extern float usermousesensitivity;
-extern bool ismotionblur;
-extern bool floatjump;
-extern bool mousejump;
-extern bool ambientsound;
-extern int bloodtoggle;
-extern bool autoslomo;
-extern bool foliage;
-extern bool musictoggle;
-extern bool trilinear;
-extern bool decals;
-extern bool invertmouse;
-extern float gamespeed;
-extern float oldgamespeed;
-extern bool damageeffects;
-extern bool texttoggle;
-extern bool devtools;
-extern bool showpoints;
-extern bool showdamagebar;
-extern bool alwaysblur;
-extern bool immediate;
-extern bool velocityblur;
-extern float volume;
-extern int detail;
-extern int kContextWidth;
-extern int kContextHeight;
-extern float screenwidth, screenheight;
-extern bool fullscreen;
-
-void DefaultSettings();
-void SaveSettings();
-bool LoadSettings();
-
-
-#endif
+++ /dev/null
-/*
-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/>.
-*/
-
-#include "Skybox.h"
-#include "Game.h"
-
-extern float viewdistance;
-extern float blurness;
-extern int environment;
-extern bool skyboxtexture;
-extern float skyboxr;
-extern float skyboxg;
-extern float skyboxb;
-
-void SkyBox::load (const std::string& ffront, const std::string& fleft, const std::string& fback,
- const std::string& fright, const std::string& fup, const std::string& fdown)
-{
- front.load(ffront, true);
- left.load(fleft, true);
- back.load(fback, true);
- right.load(fright, true);
- up.load(fup, true);
- down.load(fdown, true);
-}
-
-void SkyBox::draw()
-{
- static float size = viewdistance / 4;
- glPushMatrix();
- static GLfloat M[16];
- glGetFloatv(GL_MODELVIEW_MATRIX, M);
- M[12] = 0;
- M[13] = 0;
- M[14] = 0;
- glLoadMatrixf(M);
- if (environment == desertenvironment) {
- glScalef(1 + blurness / 1000, 1, 1 + blurness / 1000);
- glColor3f(1 * skyboxr, .95 * skyboxg, .95 * skyboxb);
- } else {
- glColor3f(.85 * skyboxr, .85 * skyboxg, .95 * skyboxb);
- }
-
- if (!skyboxtexture) {
- glDisable(GL_TEXTURE_2D);
- glColor3f(skyboxr * .8, skyboxg * .8, skyboxb * .8);
- }
- glDepthMask(0);
- glDisable(GL_CULL_FACE);
- glEnable(GL_BLEND);
- glDisable(GL_LIGHTING);
- if (skyboxtexture)
- glEnable(GL_TEXTURE_2D);
- glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
- front.bind();
- glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
- glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
- glBegin(GL_QUADS);
- glNormal3f( 0.0f, 0.0f, -1);
- glTexCoord2f(0, 0);
- glVertex3f(-size, -size, size);
- glTexCoord2f(1, 0);
- glVertex3f( size, -size, size);
- glTexCoord2f(1, 1);
- glVertex3f( size, size, size);
- glTexCoord2f(0, 1);
- glVertex3f(-size, size, size);
- glEnd();
- back.bind();
- glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
- glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
- glBegin(GL_QUADS);
- glNormal3f( 0.0f, 0.0f, 1);
- glTexCoord2f(1, 0);
- glVertex3f(-size, -size, -size);
- glTexCoord2f(1, 1);
- glVertex3f(-size, size, -size);
- glTexCoord2f(0, 1);
- glVertex3f( size, size, -size);
- glTexCoord2f(0, 0);
- glVertex3f( size, -size, -size);
- glEnd();
- up.bind();
- glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
- glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
- glBegin(GL_QUADS);
- glNormal3f( 0.0f, -1.0f, 0);
- glTexCoord2f(0, 1);
- glVertex3f(-size, size, -size);
- glTexCoord2f(0, 0);
- glVertex3f(-size, size, size);
- glTexCoord2f(1, 0);
- glVertex3f( size, size, size);
- glTexCoord2f(1, 1);
- glVertex3f( size, size, -size);
- glEnd();
- down.bind();
- glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
- glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
- glBegin(GL_QUADS);
- glNormal3f( 0.0f, 1.0f, 0);
-
- glTexCoord2f(0, 0);
- glVertex3f(-size, -size, -size);
- glTexCoord2f(1, 0);
- glVertex3f( size, -size, -size);
- glTexCoord2f(1, 1);
- glVertex3f( size, -size, size);
- glTexCoord2f(0, 1);
- glVertex3f(-size, -size, size);
- glEnd();
- right.bind();
- glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
- glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
- glBegin(GL_QUADS);
- glNormal3f( -1.0f, 0.0f, 0);
- glTexCoord2f(1, 0);
- glVertex3f( size, -size, -size);
- glTexCoord2f(1, 1);
- glVertex3f( size, size, -size);
- glTexCoord2f(0, 1);
- glVertex3f( size, size, size);
- glTexCoord2f(0, 0);
- glVertex3f( size, -size, size);
- glEnd();
- left.bind();
- glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
- glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
- glBegin(GL_QUADS);
- glNormal3f( 1.0f, 0.0f, 0);
- glTexCoord2f(0, 0);
- glVertex3f(-size, -size, -size);
- glTexCoord2f(1, 0);
- glVertex3f(-size, -size, size);
- glTexCoord2f(1, 1);
- glVertex3f(-size, size, size);
- glTexCoord2f(0, 1);
- glVertex3f(-size, size, -size);
- glEnd();
- glEnable(GL_CULL_FACE);
- glDepthMask(1);
- glPopMatrix();
-}
-
-SkyBox::~SkyBox()
-{
- front.destroy();
- left.destroy();
- back.destroy();
- right.destroy();
- up.destroy();
- down.destroy();
-};
-
+++ /dev/null
-/*
-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 _SKYBOX_H_
-#define _SKYBOX_H_
-
-#include "Quaternions.h"
-#include "ImageIO.h"
-#include "Quaternions.h"
-#include "gamegl.h"
-#include "Texture.h"
-
-class SkyBox
-{
-public:
- Texture front, left, back, right, up, down;
-
- void load(const std::string& ffront, const std::string& fleft, const std::string& fback,
- const std::string& fright, const std::string& fup, const std::string& fdown);
- void draw();
-
- SkyBox() {}
- ~SkyBox();
-};
-
-#endif
+++ /dev/null
-/*
-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 "Quaternions.h"
-#include "Sounds.h"
-#include "openal_wrapper.h"
-#include "Utils/Folders.h"
-
-struct OPENAL_SAMPLE *samp[sounds_count];
-
-extern XYZ envsound[30];
-extern float envsoundvol[30];
-extern int numenvsounds;
-extern float envsoundlife[30];
-
-int footstepsound, footstepsound2, footstepsound3, footstepsound4;
-
-int channels[100];
-
-static const char *sound_data[sounds_count] = {
-#define DECLARE_SOUND(id, filename) filename,
-#include "Sounds.def"
-#undef DECLARE_SOUND
-};
-
-// FIXME: dimensionality is not a property of the sound sample.
-// This should be decided at the time of playback
-static int snd_mode(int snd)
-{
- switch (snd) {
- case alarmsound:
- case consolefailsound:
- case consolesuccesssound:
- case firestartsound:
- case fireendsound:
- return OPENAL_2D;
- default:
- return OPENAL_HW3D;
- }
-}
-
-void loadAllSounds()
-{
- for (int i = 0; i < sounds_count; i++) {
- std::string buf = std::string("Sounds/") + sound_data[i];
- samp[i] = OPENAL_Sample_Load(OPENAL_FREE,
- Folders::getResourcePath(buf).c_str(),
- snd_mode(i),
- 0, 0);
- }
- footstepsound = footstepsn1;
- footstepsound2 = footstepsn2;
- footstepsound3 = footstepst1;
- footstepsound4 = footstepst2;
- // Huh?
- // OPENAL_Sample_SetMode(samp[whooshsound], OPENAL_LOOP_NORMAL);
- for (int i = stream_firesound; i <= stream_menutheme; i++)
- OPENAL_Stream_SetMode(samp[i], OPENAL_LOOP_NORMAL);
-}
-
-void addEnvSound(XYZ coords, float vol, float life)
-{
- envsound[numenvsounds] = coords;
- envsoundvol[numenvsounds] = vol;
- envsoundlife[numenvsounds] = life;
- numenvsounds++;
-}
-
-void emit_sound_at(int soundid, const XYZ &pos, float vol)
-{
- PlaySoundEx (soundid, samp[soundid], NULL, true);
- OPENAL_3D_SetAttributes_ (channels[soundid], pos, NULL);
- OPENAL_SetVolume (channels[soundid], vol);
- OPENAL_SetPaused (channels[soundid], false);
-}
-
-void emit_sound_np(int soundid, float vol)
-{
- PlaySoundEx (soundid, samp[soundid], NULL, true);
- OPENAL_SetVolume (channels[soundid], vol);
- OPENAL_SetPaused (channels[soundid], false);
-}
-
-void emit_stream_at(int soundid, const XYZ &pos, float vol)
-{
- PlayStreamEx (soundid, samp[soundid], NULL, true);
- OPENAL_3D_SetAttributes_ (channels[soundid], pos, NULL);
- OPENAL_SetVolume (channels[soundid], vol);
- OPENAL_SetPaused (channels[soundid], false);
-}
-
-void emit_stream_np(int soundid, float vol)
-{
- PlayStreamEx (soundid, samp[soundid], NULL, true);
- OPENAL_SetVolume (channels[soundid], vol);
- OPENAL_SetPaused (channels[soundid], false);
-}
-
-void resume_stream(int soundid)
-{
- OPENAL_SetPaused (channels[soundid], false);
-}
-
-void pause_sound(int soundid)
-{
- OPENAL_SetPaused (channels[soundid], true);
-}
+++ /dev/null
-/*
-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/>.
-*/
-
-DECLARE_SOUND(footstepsn1, "FootStepSnow1.ogg")
-DECLARE_SOUND(footstepsn2, "FootStepSnow2.ogg")
-DECLARE_SOUND(footstepst1, "FootStepStone1.ogg")
-DECLARE_SOUND(footstepst2, "FootStepStone2.ogg")
-DECLARE_SOUND(footstepgr1, "FootStepGrass1.ogg")
-DECLARE_SOUND(footstepgr2, "FootStepGrass2.ogg")
-DECLARE_SOUND(landsound, "Land.ogg")
-DECLARE_SOUND(jumpsound, "Jump.ogg")
-DECLARE_SOUND(hawksound, "Hawk.ogg")
-DECLARE_SOUND(whooshsound, "Whoosh.ogg")
-DECLARE_SOUND(landsound1, "Land1.ogg")
-DECLARE_SOUND(landsound2, "Land2.ogg")
-DECLARE_SOUND(breaksound, "Broken.ogg")
-DECLARE_SOUND(lowwhooshsound, "LowWhoosh.ogg")
-DECLARE_SOUND(midwhooshsound, "MidWhoosh.ogg")
-DECLARE_SOUND(highwhooshsound, "HighWhoosh.ogg")
-DECLARE_SOUND(movewhooshsound, "MoveWhoosh.ogg")
-DECLARE_SOUND(heavyimpactsound, "HeavyImpact.ogg")
-DECLARE_SOUND(whooshhitsound, "WhooshHit.ogg")
-DECLARE_SOUND(thudsound, "Thud.ogg")
-DECLARE_SOUND(alarmsound, "Alarm.ogg")
-DECLARE_SOUND(breaksound2, "Break.ogg")
-DECLARE_SOUND(knifedrawsound, "KnifeDraw.ogg")
-DECLARE_SOUND(knifesheathesound, "KnifeSheathe.ogg")
-DECLARE_SOUND(fleshstabsound, "FleshStab.ogg")
-DECLARE_SOUND(fleshstabremovesound, "FleshStabRemove.ogg")
-DECLARE_SOUND(knifeswishsound, "KnifeSwish.ogg")
-DECLARE_SOUND(knifeslicesound, "KnifeSlice.ogg")
-DECLARE_SOUND(swordslicesound, "SwordSlice.ogg")
-DECLARE_SOUND(skidsound, "Skid.ogg")
-DECLARE_SOUND(snowskidsound, "SnowSkid.ogg")
-DECLARE_SOUND(bushrustle, "BushRustle.ogg")
-DECLARE_SOUND(clank1sound, "Clank1.ogg")
-DECLARE_SOUND(clank2sound, "Clank2.ogg")
-DECLARE_SOUND(clank3sound, "Clank3.ogg")
-DECLARE_SOUND(clank4sound, "Clank4.ogg")
-DECLARE_SOUND(consolesuccesssound, "ConsoleSuccess.ogg")
-DECLARE_SOUND(consolefailsound, "ConsoleFail.ogg")
-DECLARE_SOUND(metalhitsound, "MetalHit.ogg")
-DECLARE_SOUND(clawslicesound, "ClawSlice.ogg")
-DECLARE_SOUND(splattersound, "Splatter.ogg")
-DECLARE_SOUND(growlsound, "Growl.ogg")
-DECLARE_SOUND(growl2sound, "Growl2.ogg")
-DECLARE_SOUND(barksound, "Bark.ogg")
-DECLARE_SOUND(bark2sound, "Bark2.ogg")
-DECLARE_SOUND(bark3sound, "Bark3.ogg")
-DECLARE_SOUND(snarlsound, "Snarl.ogg")
-DECLARE_SOUND(snarl2sound, "Snarl2.ogg")
-DECLARE_SOUND(barkgrowlsound, "BarkGrowl.ogg")
-DECLARE_SOUND(rabbitattacksound, "RabbitAttack.ogg")
-DECLARE_SOUND(rabbitattack2sound, "RabbitAttack2.ogg")
-DECLARE_SOUND(rabbitattack3sound, "RabbitAttack3.ogg")
-DECLARE_SOUND(rabbitattack4sound, "RabbitAttack4.ogg")
-DECLARE_SOUND(rabbitpainsound, "RabbitPain.ogg")
-DECLARE_SOUND(rabbitpain1sound, "RabbitPain2.ogg")
-DECLARE_SOUND(rabbitchitter, "RabbitChitter.ogg")
-DECLARE_SOUND(rabbitchitter2, "RabbitChitter2.ogg")
-DECLARE_SOUND(swordstaffsound, "SwordStaff.ogg")
-DECLARE_SOUND(staffbodysound, "StaffBody.ogg")
-DECLARE_SOUND(staffheadsound, "StaffHead.ogg")
-DECLARE_SOUND(staffbreaksound, "StaffBreak.ogg")
-DECLARE_SOUND(firestartsound, "FireStart.ogg")
-DECLARE_SOUND(fireendsound, "FireEnd.ogg")
-DECLARE_SOUND(stream_firesound, "Fire.ogg")
-DECLARE_SOUND(stream_grasstheme, "Music1Grass.ogg")
-DECLARE_SOUND(stream_snowtheme, "Music1Snow.ogg")
-DECLARE_SOUND(stream_deserttheme, "Music1Desert.ogg")
-DECLARE_SOUND(stream_wind, "Wind.ogg")
-DECLARE_SOUND(stream_desertambient, "DesertAmbient.ogg")
-DECLARE_SOUND(stream_fighttheme, "Music2.ogg")
-DECLARE_SOUND(stream_menutheme, "Music3.ogg")
+++ /dev/null
-/*
-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 SOUNDS_H
-#define SOUNDS_H
-
-enum sound_types {
-#define DECLARE_SOUND(id, filename) id,
-#include "Sounds.def"
-#undef DECLARE_SOUND
- sounds_count
-};
-
-extern struct OPENAL_SAMPLE *samp[sounds_count];
-extern int channels[];
-
-extern void loadAllSounds();
-
-extern void addEnvSound(XYZ coords, float vol = 16, float life = .4);
-
-extern void emit_sound_at(int soundid, const XYZ &pos = XYZ(), float vol = 256.f);
-extern void emit_sound_np(int soundid, float vol = 256.f);
-extern void emit_stream_at(int soundid, const XYZ &pos = XYZ(), float vol = 256.f);
-extern void emit_stream_np(int soundid, float vol = 256.f);
-extern void resume_stream(int soundid);
-extern void pause_sound(int soundid);
-
-extern int footstepsound, footstepsound2, footstepsound3, footstepsound4;
-#endif
+++ /dev/null
-/*
-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/>.
-*/
-
-#include "Sprite.h"
-#include "Person.h"
-#include "Game.h"
-extern XYZ viewer;
-extern float viewdistance;
-extern float fadestart;
-extern int environment;
-extern float texscale;
-extern Light light;
-extern float multiplier;
-extern float gravity;
-extern Terrain terrain;
-extern Objects objects;
-extern int detail;
-extern XYZ viewerfacing;
-extern int bloodtoggle;
-extern XYZ windvector;
-
-// init statics
-Texture Sprite::cloudtexture;
-Texture Sprite::cloudimpacttexture;
-Texture Sprite::bloodtexture;
-Texture Sprite::flametexture;
-Texture Sprite::bloodflametexture;
-Texture Sprite::smoketexture;
-Texture Sprite::snowflaketexture;
-Texture Sprite::shinetexture;
-Texture Sprite::splintertexture;
-Texture Sprite::leaftexture;
-Texture Sprite::toothtexture;
-
-float Sprite::checkdelay = 0;
-
-vector<Sprite*> Sprite::sprites = vector<Sprite*>();
-
-//Functions
-void Sprite::Draw()
-{
- int k;
- static float M[16];
- static XYZ point;
- static float distancemult;
- static int lasttype;
- static int lastspecial;
- static int whichpatchx, whichpatchz;
- static XYZ start, end, colpoint;
- static bool check;
- static bool blend;
- static float tempmult;
- static XYZ difference;
- static float lightcolor[3];
- static float viewdistsquared = viewdistance * viewdistance;
- static XYZ tempviewer;
-
- tempviewer = viewer + viewerfacing * 6;
- check = 0;
-
- lightcolor[0] = light.color[0] * .5 + light.ambient[0];
- lightcolor[1] = light.color[1] * .5 + light.ambient[1];
- lightcolor[2] = light.color[2] * .5 + light.ambient[2];
-
- checkdelay -= multiplier * 10;
-
- if (checkdelay <= 0) {
- check = 1;
- checkdelay = 1;
- }
-
- lasttype = -1;
- lastspecial = -1;
- glEnable(GL_BLEND);
- glDisable(GL_LIGHTING);
- glDisable(GL_CULL_FACE);
- glEnable(GL_TEXTURE_2D);
- blend = 1;
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glDepthMask(0);
- glAlphaFunc(GL_GREATER, 0.0001);
- for (unsigned i = 0; i < sprites.size(); i++) {
- if (lasttype != sprites[i]->type) {
- switch (sprites[i]->type) {
- case cloudsprite:
- cloudtexture.bind();
- if (!blend) {
- blend = 1;
- glAlphaFunc(GL_GREATER, 0.0001);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- }
- break;
- case breathsprite:
- case cloudimpactsprite:
- cloudimpacttexture.bind();
- if (!blend) {
- blend = 1;
- glAlphaFunc(GL_GREATER, 0.0001);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- }
- break;
- case smoketype:
- smoketexture.bind();
- if (!blend) {
- blend = 1;
- glAlphaFunc(GL_GREATER, 0.0001);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- }
- break;
- case bloodsprite:
- bloodtexture.bind();
- if (!blend) {
- blend = 1;
- glAlphaFunc(GL_GREATER, 0.0001);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- }
- break;
- case splintersprite :
- if (lastspecial != sprites[i]->special) {
- if (sprites[i]->special == 0)
- splintertexture.bind();
- if (sprites[i]->special == 1)
- leaftexture.bind();
- if (sprites[i]->special == 2)
- snowflaketexture.bind();
- if (sprites[i]->special == 3)
- toothtexture.bind();
- if (!blend) {
- blend = 1;
- glAlphaFunc(GL_GREATER, 0.0001);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- }
- }
- break;
- case snowsprite:
- snowflaketexture.bind();
- if (!blend) {
- blend = 1;
- glAlphaFunc(GL_GREATER, 0.0001);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- }
- break;
- case weaponshinesprite:
- shinetexture.bind();
- if (blend) {
- blend = 0;
- glAlphaFunc(GL_GREATER, 0.001);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE);
- }
- break;
- case flamesprite:
- case weaponflamesprite:
- flametexture.bind();
- if (blend || lasttype == bloodflamesprite) {
- blend = 0;
- glAlphaFunc(GL_GREATER, 0.3);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE);
- }
- break;
- case bloodflamesprite:
- bloodflametexture.bind();
- if (blend) {
- blend = 0;
- glAlphaFunc(GL_GREATER, 0.3);
- glBlendFunc(GL_ONE, GL_ZERO);
- }
- break;
- }
- }
- if (sprites[i]->type == snowsprite)
- distancemult = (144 - (distsq(&tempviewer, &sprites[i]->position) - (144 * fadestart)) * (1 / (1 - fadestart))) / 144;
- else
- distancemult = (viewdistsquared - (distsq(&viewer, &sprites[i]->position) - (viewdistsquared * fadestart)) * (1 / (1 - fadestart))) / viewdistsquared;
- if (sprites[i]->type == flamesprite) {
- if (distancemult >= 1)
- glColor4f(sprites[i]->color[0], sprites[i]->color[1], sprites[i]->color[2], sprites[i]->opacity);
- else
- glColor4f(sprites[i]->color[0], sprites[i]->color[1], sprites[i]->color[2], sprites[i]->opacity * distancemult);
- } else {
- if (distancemult >= 1)
- glColor4f(sprites[i]->color[0]*lightcolor[0], sprites[i]->color[1]*lightcolor[1], sprites[i]->color[2]*lightcolor[2], sprites[i]->opacity);
- else
- glColor4f(sprites[i]->color[0]*lightcolor[0], sprites[i]->color[1]*lightcolor[1], sprites[i]->color[2]*lightcolor[2], sprites[i]->opacity * distancemult);
- }
- lasttype = sprites[i]->type;
- lastspecial = sprites[i]->special;
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glTranslatef(sprites[i]->position.x, sprites[i]->position.y, sprites[i]->position.z);
- if ((sprites[i]->type == flamesprite || sprites[i]->type == weaponflamesprite || sprites[i]->type == weaponshinesprite)) {
- difference = viewer - sprites[i]->position;
- Normalise(&difference);
- glTranslatef(difference.x * sprites[i]->size / 4, difference.y * sprites[i]->size / 4, difference.z * sprites[i]->size / 4);
- }
- if (sprites[i]->type == snowsprite) {
- glRotatef(sprites[i]->rotation * .2, 0, .3, 1);
- glTranslatef(1, 0, 0);
- }
- glGetFloatv(GL_MODELVIEW_MATRIX, M);
- point.x = M[12];
- point.y = M[13];
- point.z = M[14];
- glLoadIdentity();
- glTranslatef(point.x, point.y, point.z);
-
- glRotatef(sprites[i]->rotation, 0, 0, 1);
-
- if ((sprites[i]->type == flamesprite || sprites[i]->type == weaponflamesprite || sprites[i]->type == weaponshinesprite || sprites[i]->type == bloodflamesprite)) {
- if (sprites[i]->alivetime < .14)
- glScalef(sprites[i]->alivetime / .14, sprites[i]->alivetime / .14, sprites[i]->alivetime / .14);
- }
- if (sprites[i]->type == smoketype || sprites[i]->type == snowsprite || sprites[i]->type == weaponshinesprite || sprites[i]->type == breathsprite) {
- if (sprites[i]->alivetime < .3) {
- if (distancemult >= 1)
- glColor4f(sprites[i]->color[0]*lightcolor[0], sprites[i]->color[1]*lightcolor[1], sprites[i]->color[2]*lightcolor[2], sprites[i]->opacity * sprites[i]->alivetime / .3);
- if (distancemult < 1)
- glColor4f(sprites[i]->color[0]*lightcolor[0], sprites[i]->color[1]*lightcolor[1], sprites[i]->color[2]*lightcolor[2], sprites[i]->opacity * distancemult * sprites[i]->alivetime / .3);
- }
- }
- if (sprites[i]->type == splintersprite && sprites[i]->special > 0 && sprites[i]->special != 3) {
- if (sprites[i]->alivetime < .2) {
- if (distancemult >= 1)
- glColor4f(sprites[i]->color[0]*lightcolor[0], sprites[i]->color[1]*lightcolor[1], sprites[i]->color[2]*lightcolor[2], sprites[i]->alivetime / .2);
- else
- glColor4f(sprites[i]->color[0]*lightcolor[0], sprites[i]->color[1]*lightcolor[1], sprites[i]->color[2]*lightcolor[2], distancemult * sprites[i]->alivetime / .2);
- } else {
- if (distancemult >= 1)
- glColor4f(sprites[i]->color[0]*lightcolor[0], sprites[i]->color[1]*lightcolor[1], sprites[i]->color[2]*lightcolor[2], 1);
- else
- glColor4f(sprites[i]->color[0]*lightcolor[0], sprites[i]->color[1]*lightcolor[1], sprites[i]->color[2]*lightcolor[2], 1);
- }
- }
- if (sprites[i]->type == splintersprite && (sprites[i]->special == 0 || sprites[i]->special == 3)) {
- if (distancemult >= 1)
- glColor4f(sprites[i]->color[0]*lightcolor[0], sprites[i]->color[1]*lightcolor[1], sprites[i]->color[2]*lightcolor[2], 1);
- else
- glColor4f(sprites[i]->color[0]*lightcolor[0], sprites[i]->color[1]*lightcolor[1], sprites[i]->color[2]*lightcolor[2], 1);
- }
-
- glBegin(GL_TRIANGLES);
- glTexCoord2f(1.0f, 1.0f);
- glVertex3f( .5 * sprites[i]->size, .5 * sprites[i]->size, 0.0f);
- glTexCoord2f(0.0f, 1.0f);
- glVertex3f(-.5 * sprites[i]->size, .5 * sprites[i]->size, 0.0f);
- glTexCoord2f(1.0f, 0.0f);
- glVertex3f( .5 * sprites[i]->size, -.5 * sprites[i]->size, 0.0f);
- glTexCoord2f(0.0f, 0.0f);
- glVertex3f(-.5 * sprites[i]->size, -.5 * sprites[i]->size, 0.0f);
- glTexCoord2f(1.0f, 0.0f);
- glVertex3f( .5 * sprites[i]->size, -.5 * sprites[i]->size, 0.0f);
- glTexCoord2f(0.0f, 1.0f);
- glVertex3f(-.5 * sprites[i]->size, .5 * sprites[i]->size, 0.0f);
- glEnd();
- glPopMatrix();
- }
- tempmult = multiplier;
- for (int i = sprites.size() - 1; i >= 0; i--) {
- multiplier = tempmult;
- if (sprites[i]->type != snowsprite) {
- sprites[i]->position += sprites[i]->velocity * multiplier;
- sprites[i]->velocity += windvector * multiplier;
- }
- if (sprites[i]->type == flamesprite || sprites[i]->type == smoketype)
- sprites[i]->position += windvector * multiplier / 2;
- if ((sprites[i]->type == flamesprite || sprites[i]->type == weaponflamesprite || sprites[i]->type == weaponshinesprite || sprites[i]->type == bloodflamesprite))
- multiplier *= sprites[i]->speed * .7;
- sprites[i]->alivetime += multiplier;
-
- if (sprites[i]->type == cloudsprite || sprites[i]->type == cloudimpactsprite) {
- sprites[i]->opacity -= multiplier / 2;
- sprites[i]->size += multiplier / 2;
- sprites[i]->velocity.y += gravity * multiplier * .25;
- }
- if (sprites[i]->type == breathsprite) {
- sprites[i]->opacity -= multiplier / 2;
- sprites[i]->size += multiplier / 2;
- if (findLength(&sprites[i]->velocity) <= multiplier) {
- sprites[i]->velocity = 0;
- } else {
- XYZ slowdown;
- slowdown = sprites[i]->velocity * -1;
- Normalise(&slowdown);
- slowdown *= multiplier;
- sprites[i]->velocity += slowdown;
- }
- }
- if (sprites[i]->type == snowsprite) {
- sprites[i]->size -= multiplier / 120;
- sprites[i]->rotation += multiplier * 360;
- sprites[i]->position.y -= multiplier;
- sprites[i]->position += windvector * multiplier;
- if (sprites[i]->position.y < tempviewer.y - 6) sprites[i]->position.y += 12;
- if (sprites[i]->position.y > tempviewer.y + 6) sprites[i]->position.y -= 12;
- if (sprites[i]->position.z < tempviewer.z - 6) sprites[i]->position.z += 12;
- if (sprites[i]->position.z > tempviewer.z + 6) sprites[i]->position.z -= 12;
- if (sprites[i]->position.x < tempviewer.x - 6) sprites[i]->position.x += 12;
- if (sprites[i]->position.x > tempviewer.x + 6) sprites[i]->position.x -= 12;
- }
- if (sprites[i]->type == bloodsprite) {
- bool spritehit = 0;
- sprites[i]->rotation += multiplier * 100;
- sprites[i]->velocity.y += gravity * multiplier;
- if (check) {
- XYZ where, startpoint, endpoint, movepoint, footpoint;
- float rotationpoint;
- int whichtri;
-
- for (unsigned j = 0; j < Person::players.size(); j++) {
- if (!spritehit && Person::players[j]->dead && sprites[i]->alivetime > .1) {
- where = sprites[i]->oldposition;
- where -= Person::players[j]->coords;
- if (!Person::players[j]->skeleton.free)
- where = DoRotation(where, 0, -Person::players[j]->yaw, 0);
- startpoint = where;
- where = sprites[i]->position;
- where -= Person::players[j]->coords;
- if (!Person::players[j]->skeleton.free)
- where = DoRotation(where, 0, -Person::players[j]->yaw, 0);
- endpoint = where;
-
- movepoint = 0;
- rotationpoint = 0;
- whichtri = Person::players[j]->skeleton.drawmodel.LineCheck(&startpoint, &endpoint, &footpoint, &movepoint, &rotationpoint);
- if (whichtri != -1) {
- spritehit = 1;
- Person::players[j]->DoBloodBigWhere(0, 160, sprites[i]->oldposition);
- DeleteSprite(i);
- }
- }
- }
-
- whichpatchx = sprites[i]->position.x / (terrain.size / subdivision * terrain.scale);
- whichpatchz = sprites[i]->position.z / (terrain.size / subdivision * terrain.scale);
- if (whichpatchx > 0 && whichpatchz > 0 && whichpatchx < subdivision && whichpatchz < subdivision)
- if (terrain.patchobjectnum[whichpatchx][whichpatchz]) {
- if (!spritehit)
- for (int j = 0; j < terrain.patchobjectnum[whichpatchx][whichpatchz]; j++) {
- k = terrain.patchobjects[whichpatchx][whichpatchz][j];
- start = sprites[i]->oldposition;
- end = sprites[i]->position;
- if (!spritehit)
- if (objects.model[k].LineCheck(&start, &end, &colpoint, &objects.position[k], &objects.yaw[k]) != -1) {
- if (detail == 2 || (detail == 1 && abs(Random() % 4) == 0) || (detail == 0 && abs(Random() % 8) == 0))
- objects.model[k].MakeDecal(blooddecalfast, DoRotation(colpoint - objects.position[k], 0, -objects.yaw[k], 0), sprites[i]->size * 1.6, .5, Random() % 360);
- DeleteSprite(i);
- spritehit = 1;
- }
- }
- }
- if (!spritehit)
- if (sprites[i]->position.y < terrain.getHeight(sprites[i]->position.x, sprites[i]->position.z)) {
- terrain.MakeDecal(blooddecalfast, sprites[i]->position, sprites[i]->size * 1.6, .6, Random() % 360);
- DeleteSprite(i);
- }
- }
- }
- if (sprites[i]->type == splintersprite) {
- sprites[i]->rotation += sprites[i]->rotatespeed * multiplier;
- sprites[i]->opacity -= multiplier / 2;
- if (sprites[i]->special == 0 || sprites[i]->special == 2 || sprites[i]->special == 3)
- sprites[i]->velocity.y += gravity * multiplier;
- if (sprites[i]->special == 1)
- sprites[i]->velocity.y += gravity * multiplier * .5;
- }
- if (sprites[i]->type == flamesprite || sprites[i]->type == weaponflamesprite || sprites[i]->type == weaponshinesprite || sprites[i]->type == bloodflamesprite) {
- sprites[i]->rotation += multiplier * sprites[i]->rotatespeed;
- sprites[i]->opacity -= multiplier * 5 / 4;
- if (sprites[i]->type != weaponshinesprite && sprites[i]->type != bloodflamesprite)
- if (sprites[i]->opacity < .5 && sprites[i]->opacity + multiplier * 5 / 4 >= .5 && (abs(Random() % 4) == 0 || (sprites[i]->initialsize > 2 && Random() % 2 == 0)))
- MakeSprite(smoketype, sprites[i]->position, sprites[i]->velocity, .9, .9, .6, sprites[i]->size * 1.2, .4);
- if (sprites[i]->alivetime > .14 && (sprites[i]->type == flamesprite)) {
- sprites[i]->velocity = 0;
- sprites[i]->velocity.y = 1.5;
- }
- }
- if (sprites[i]->type == smoketype) {
- sprites[i]->opacity -= multiplier / 3 / sprites[i]->initialsize;
- sprites[i]->color[0] -= multiplier;
- sprites[i]->color[1] -= multiplier;
- sprites[i]->color[2] -= multiplier;
- if (sprites[i]->color[0] < .6)
- sprites[i]->color[0] = .6;
- if (sprites[i]->color[1] < .6)
- sprites[i]->color[1] = .6;
- if (sprites[i]->color[2] < .6)
- sprites[i]->color[2] = .6;
- sprites[i]->size += multiplier;
- sprites[i]->velocity = 0;
- sprites[i]->velocity.y = 1.5;
- sprites[i]->rotation += multiplier * sprites[i]->rotatespeed / 5;
- }
- if (sprites[i]->opacity <= 0 || sprites[i]->size <= 0)
- DeleteSprite(i);
- }
- if (check)
- for (int i = sprites.size() - 1; i >= 0; i--) {
- sprites[i]->oldposition = sprites[i]->position;
- }
- glAlphaFunc(GL_GREATER, 0.0001);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-}
-
-void Sprite::DeleteSprite(int i)
-{
- sprites.erase(sprites.begin() + i);
-}
-
-void Sprite::MakeSprite(int atype, XYZ where, XYZ avelocity, float red, float green, float blue, float asize, float aopacity)
-{
- if (sprites.size() < max_sprites - 1) {
- sprites.push_back(new Sprite());
- if ((atype != bloodsprite && atype != bloodflamesprite) || bloodtoggle) {
- sprites.back()->special = 0;
- sprites.back()->type = atype;
- sprites.back()->position = where;
- sprites.back()->oldposition = where;
- sprites.back()->velocity = avelocity;
- sprites.back()->alivetime = 0;
- sprites.back()->opacity = aopacity;
- sprites.back()->size = asize;
- sprites.back()->initialsize = asize;
- sprites.back()->color[0] = red;
- sprites.back()->color[1] = green;
- sprites.back()->color[2] = blue;
- sprites.back()->rotatespeed = abs(Random() % 720) - 360;
- sprites.back()->speed = float(abs(Random() % 100)) / 200 + 1.5;
- }
- }
-}
-
-Sprite::Sprite()
-{
- oldposition = 0;
- position = 0;
- velocity = 0;
- size = 0;
- initialsize = 0;
- type = 0;
- special = 0;
- memset(color, 0, sizeof(color));
- opacity = 0;
- rotation = 0;
- alivetime = 0;
- speed = 0;
- rotatespeed = 0;
-}
-
-void Sprite::clearTextures()
-{
- toothtexture.destroy();
- cloudtexture.destroy();
- cloudimpacttexture.destroy();
- bloodtexture.destroy();
- flametexture.destroy();
- bloodflametexture.destroy();
- smoketexture.destroy();
- snowflaketexture.destroy();
- shinetexture.destroy();
- splintertexture.destroy();
- leaftexture.destroy();
-}
-
+++ /dev/null
-/*
-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 _SPRITE_H_
-#define _SPRITE_H_
-
-#include "Quaternions.h"
-#include "gamegl.h"
-#include "ImageIO.h"
-#include "Quaternions.h"
-#include "Frustum.h"
-#include "Lights.h"
-#include "Terrain.h"
-#include "Objects.h"
-#include "Texture.h"
-
-#include <vector>
-
-#define max_sprites 20000
-
-enum {
- cloudsprite = 0,
- bloodsprite,
- flamesprite,
- smoketype,
- weaponflamesprite,
- cloudimpactsprite,
- snowsprite,
- weaponshinesprite,
- bloodflamesprite,
- breathsprite,
- splintersprite,
- spritenumber
-};
-
-class Sprite
-{
-private:
- XYZ oldposition;
- XYZ position;
- XYZ velocity;
- float size;
- float initialsize;
- int type;
- int special;
- float color[3];
- float opacity;
- float rotation;
- float alivetime;
- float speed;
- float rotatespeed;
-
- static float checkdelay;
-
- static vector<Sprite*> sprites;
-
-public:
- static void DeleteSprite(int which);
- static void MakeSprite(int atype, XYZ where, XYZ avelocity, float red, float green, float blue, float asize, float aopacity);
- static void Draw();
- static void deleteSprites() {
- sprites.clear();
- }
- static void setLastSpriteSpecial(int s) {
- sprites.back()->special = s;
- }
- static void setLastSpriteSpeed(int s) {
- sprites.back()->speed = s;
- }
- static void setLastSpriteAlivetime(float al) {
- sprites.back()->alivetime = al;
- }
- static void clearTextures();
-
- static Texture cloudtexture;
- static Texture bloodtexture;
- static Texture flametexture;
- static Texture smoketexture;
-
- static Texture cloudimpacttexture;
- static Texture snowflaketexture;
- static Texture shinetexture;
- static Texture bloodflametexture;
-
- static Texture splintertexture;
-
- static Texture leaftexture;
- static Texture toothtexture;
-
- Sprite();
- ~Sprite();
-};
-
-#endif
+++ /dev/null
-/*
-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/>.
-*/
-
-#include "Game.h"
-#include "Stereo.h"
-
-
-extern int kContextWidth;
-extern int kContextHeight;
-
-bool CanInitStereo(StereoMode mode)
-{
- GLint stencilbits = 0;
-
- switch (mode) {
- case stereoNone:
- case stereoAnaglyph:
- return true;
- break;
- case stereoHorizontalInterlaced:
- case stereoVerticalInterlaced:
- glGetIntegerv(GL_STENCIL_BITS, &stencilbits);
- if ( stencilbits < 1 ) {
- fprintf(stderr, "Failed to get a stencil buffer, interlaced stereo not available.\n");
- return false;
- } else {
- fprintf(stderr, "Stencil buffer has %i bits, good.\n", stencilbits);
- }
- return true;
- break;
- default:
- return false;
- }
-
-}
-
-void InitStereo(StereoMode mode)
-{
- switch (mode) {
- default:
- case stereoNone:
- case stereoAnaglyph:
- glDisable(GL_STENCIL_TEST);
- return;
- case stereoHorizontalInterlaced:
- case stereoVerticalInterlaced:
- fprintf(stderr, "Screen width is %i, height is %i\n", kContextWidth, kContextHeight);
-
- // Setup stencil buffer
- glDisable( GL_DEPTH_TEST);
- glDisable(GL_CULL_FACE);
- glDisable(GL_LIGHTING);
- glDisable(GL_TEXTURE_2D);
-
- glEnable( GL_STENCIL_TEST);
- glClearStencil(0);
- glClear( GL_STENCIL_BUFFER_BIT );
- glStencilFunc(GL_ALWAYS, 0x1, 0x1);
- glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
-
- // Setup viewport
- glViewport(0, 0, kContextWidth, kContextHeight);
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
- glOrtho((GLdouble)0, (GLdouble)kContextWidth, (GLdouble)kContextHeight, 0, -1, 1);
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadIdentity();
- glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
- glDisable(GL_LINE_SMOOTH);
-
- // Add 0.5 to the coordinates, because OpenGL considers a pixel should be
- // turned on when a line passes through the center of it.
- if ( mode == stereoHorizontalInterlaced ) {
- for (int y = 0; y < kContextHeight; y += 2) {
- glBegin(GL_LINES);
- glVertex3f(0.5, y + 0.5, 0);
- glVertex3f(kContextWidth + 0.5, y + 0.5, 0);
- glEnd();
- }
- } else {
- for (int x = 0; x < kContextWidth; x += 2) {
- glBegin(GL_LINES);
- glVertex3f(x + 0.5, 0.5, 0);
- glVertex3f(x + 0.5, kContextHeight + 0.5, 0);
- glEnd();
- }
- }
-
- glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
-
- glPopMatrix();
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
-
- glStencilFunc(GL_NOTEQUAL, 0x01, 0x01);
- glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
- glEnable( GL_DEPTH_TEST);
- glEnable(GL_CULL_FACE);
- glEnable(GL_LIGHTING);
- glEnable(GL_TEXTURE_2D);
- }
-
-}
-
-const std::string StereoModeName(StereoMode mode)
-{
- switch (mode) {
- case stereoNone:
- return "None";
- break;
- case stereoAnaglyph:
- return "Anaglyph";
- break;
- case stereoHorizontalInterlaced:
- return "Horizontal interlacing";
- break;
- case stereoVerticalInterlaced:
- return "Vertical interlacing";
- break;
- case stereoHorizontalSplit:
- return "Horizontal split";
- break;
- case stereoVerticalSplit:
- return "Vertical split";
- break;
- case stereoOpenGL:
- return "OpenGL";
- break;
- default:
- return "(error)";
- break;
- }
-}
+++ /dev/null
-/*
-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 STEREO_H_
-#define STEREO_H_
-
-enum StereoMode {
- stereoNone,
- stereoAnaglyph, /* red/cyan */
- stereoHorizontalInterlaced, /* some 3D monitors */
- stereoVerticalInterlaced,
- stereoHorizontalSplit, /* cross-eyed view */
- stereoVerticalSplit,
- stereoOpenGL, /* Whatever OpenGL does, if supported */
- stereoCount /* must be last element */
-};
-
-
-enum StereoSide {
- // Code multiplies by StereoSide to calculate camera offsets
- stereoLeft = -1,
- stereoCenter = 0,
- stereoRight = 1
-};
-
-extern StereoMode stereomode;
-extern StereoMode newstereomode;
-extern float stereoseparation;
-extern bool stereoreverse;
-
-bool CanInitStereo(StereoMode mode);
-void InitStereo(StereoMode mode);
-const std::string StereoModeName(StereoMode mode);
-
-#endif
+++ /dev/null
-/*
-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/>.
-*/
-
-#include "Game.h"
-#include "Terrain.h"
-#include "Objects.h"
-#include "Utils/Folders.h"
-
-extern XYZ viewer;
-extern float viewdistance;
-extern float fadestart;
-extern int environment;
-extern float texscale;
-extern Light light;
-extern float multiplier;
-extern FRUSTUM frustum;
-extern float texdetail;
-extern int detail;
-extern bool decals;
-extern float blurness;
-extern float targetblurness;
-extern Objects objects;
-extern bool visibleloading;
-extern bool skyboxtexture;
-extern int tutoriallevel;
-
-//Functions
-
-int Terrain::lineTerrain(XYZ p1, XYZ p2, XYZ *p)
-{
- static int i, j, k;
- static float distance;
- static float olddistance;
- static int intersecting;
- static int firstintersecting;
- static XYZ point;
- static int startx, starty;
- static int endx, endy;
- static float highest, lowest;
-
- firstintersecting = -1;
- olddistance = 10000;
- distance = 1;
-
- XYZ triangles[3];
-
- p1 /= scale;
- p2 /= scale;
-
- startx = p1.x;
- starty = p1.z;
- endx = p2.x;
- endy = p2.z;
-
- if (startx > endx) {
- i = endx;
- endx = startx;
- startx = i;
- }
- if (starty > endy) {
- i = endy;
- endy = starty;
- starty = i;
- }
-
- if (startx < 0)
- startx = 0;
- if (starty < 0)
- starty = 0;
- if (endx > size - 1)
- endx = size - 1;
- if (endy > size - 1)
- endy = size - 1;
-
- for (i = startx; i <= endx; i++) {
- for (j = starty; j <= endy; j++) {
- highest = -1000;
- lowest = 1000;
- for (k = 0; k < 2; k++) {
- if (heightmap[i + k][j] > highest)
- highest = heightmap[i + k][j];
- if (heightmap[i + k][j] < lowest)
- lowest = heightmap[i + k][j];
- if (heightmap[i + k][j + 1] > highest)
- highest = heightmap[i + k][j + 1];
- if (heightmap[i + k][j + 1] < lowest)
- lowest = heightmap[i + k][j + 1];
- }
- if ((p1.y <= highest || p2.y <= highest) && (p1.y >= lowest || p2.y >= lowest)) {
- triangles[0].x = i;
- triangles[0].y = heightmap[i][j];
- triangles[0].z = j;
-
- triangles[1].x = i;
- triangles[1].y = heightmap[i][j + 1];
- triangles[1].z = j + 1;
-
- triangles[2].x = i + 1;
- triangles[2].y = heightmap[i + 1][j];
- triangles[2].z = j;
-
- intersecting = LineFacet(p1, p2, triangles[0], triangles[1], triangles[2], &point);
- distance = distsq(&p1, &point);
- if ((distance < olddistance || firstintersecting == -1) && intersecting == 1) {
- olddistance = distance;
- firstintersecting = 1;
- *p = point;
- }
-
- triangles[0].x = i + 1;
- triangles[0].y = heightmap[i + 1][j];
- triangles[0].z = j;
-
- triangles[1].x = i;
- triangles[1].y = heightmap[i][j + 1];
- triangles[1].z = j + 1;
-
- triangles[2].x = i + 1;
- triangles[2].y = heightmap[i + 1][j + 1];
- triangles[2].z = j + 1;
-
- intersecting = LineFacet(p1, p2, triangles[0], triangles[1], triangles[2], &point);
- distance = distsq(&p1, &point);
- if ((distance < olddistance || firstintersecting == -1) && intersecting == 1) {
- olddistance = distance;
- firstintersecting = 1;
- *p = point;
- }
- }
- }
- }
- return firstintersecting;
-}
-
-void Terrain::UpdateTransparency(int whichx, int whichy)
-{
- static XYZ vertex;
- static int i, j, a, b, c, d, patch_size, stepsize;
- static float distance;
-
- static float viewdistsquared;
-
- viewdistsquared = viewdistance * viewdistance;
- patch_size = size / subdivision;
-
- stepsize = 1;
- c = whichx * patch_elements + whichy * patch_elements * subdivision;
-
- for (i = patch_size * whichx; i < patch_size * (whichx + 1) + 1; i += stepsize) {
- for (j = patch_size * whichy; j < patch_size * (whichy + 1) + 1; j += stepsize) {
- if (i < size && j < size) {
- vertex.x = i * scale;
- vertex.z = j * scale;
- vertex.y = heightmap[i][j] * scale;
- distance = distsq(&viewer, &vertex);
- if (distance > viewdistsquared)
- distance = viewdistsquared;
- colors[i][j][3] = (viewdistsquared - (distance - (viewdistsquared * fadestart)) * (1 / (1 - fadestart))) / viewdistsquared;
- }
- }
- }
-
- for (i = patch_size * whichx; i < patch_size * (whichx + 1); i += stepsize) {
- for (j = patch_size * whichy; j < patch_size * (whichy + 1); j += stepsize) {
- a = (i - (patch_size * whichx)) / stepsize;
- b = (j - (patch_size * whichy)) / stepsize;
- d = (a * 54) + (b * 54 * patch_size / stepsize);
- vArray[d + c + 6] = colors[i][j][3];
-
- vArray[d + c + 15] = colors[i][j + stepsize][3];
-
- vArray[d + c + 24] = colors[i + stepsize][j][3];
-
- vArray[d + c + 33] = colors[i + stepsize][j][3];
-
- vArray[d + c + 42] = colors[i][j + stepsize][3];
-
- vArray[d + c + 51] = colors[i + stepsize][j + stepsize][3];
- }
- }
-}
-
-void Terrain::UpdateTransparencyother(int whichx, int whichy)
-{
- static int i, j, a, b, c, d, patch_size, stepsize;
-
- patch_size = size / subdivision;
-
- stepsize = 1;
- c = whichx * patch_elements + whichy * patch_elements * subdivision;
-
- for (i = patch_size * whichx; i < patch_size * (whichx + 1); i += stepsize) {
- for (j = patch_size * whichy; j < patch_size * (whichy + 1); j += stepsize) {
- a = (i - (patch_size * whichx)) / stepsize;
- b = (j - (patch_size * whichy)) / stepsize;
- d = (a * 54) + (b * 54 * patch_size / stepsize);
- vArray[d + c + 6] = colors[i][j][3] * opacityother[i][j];
-
- vArray[d + c + 15] = colors[i][j + stepsize][3] * opacityother[i][j + stepsize];
-
- vArray[d + c + 24] = colors[i + stepsize][j][3] * opacityother[i + stepsize][j];
-
- vArray[d + c + 33] = colors[i + stepsize][j][3] * opacityother[i + stepsize][j];
-
- vArray[d + c + 42] = colors[i][j + stepsize][3] * opacityother[i][j + stepsize];
-
- vArray[d + c + 51] = colors[i + stepsize][j + stepsize][3] * opacityother[i + stepsize][j + stepsize];
- }
- }
-}
-
-void Terrain::UpdateTransparencyotherother(int whichx, int whichy)
-{
- static XYZ vertex;
- static int i, j, a, b, c, d, patch_size, stepsize;
- static float distance;
-
- static float viewdistsquared;
-
- viewdistsquared = viewdistance * viewdistance;
- patch_size = size / subdivision;
-
- stepsize = 1;
- c = whichx * patch_elements + whichy * patch_elements * subdivision;
-
- for (i = patch_size * whichx; i < patch_size * (whichx + 1) + 1; i += stepsize) {
- for (j = patch_size * whichy; j < patch_size * (whichy + 1) + 1; j += stepsize) {
- if (i < size && j < size) {
- vertex.x = i * scale;
- vertex.z = j * scale;
- vertex.y = heightmap[i][j] * scale;
- distance = distsq(&viewer, &vertex);
- if (distance > viewdistsquared)
- distance = viewdistsquared;
- colors[i][j][3] = (viewdistsquared - (distance - (viewdistsquared * fadestart)) * (1 / (1 - fadestart))) / viewdistsquared;
- }
- }
- }
-
- for (i = patch_size * whichx; i < patch_size * (whichx + 1); i += stepsize) {
- for (j = patch_size * whichy; j < patch_size * (whichy + 1); j += stepsize) {
- a = (i - (patch_size * whichx)) / stepsize;
- b = (j - (patch_size * whichy)) / stepsize;
- d = (a * 54) + (b * 54 * patch_size / stepsize);
- vArray[d + c + 6] = colors[i][j][3];
-
- vArray[d + c + 15] = colors[i][j + stepsize][3];
-
- vArray[d + c + 24] = colors[i + stepsize][j][3];
-
- vArray[d + c + 33] = colors[i + stepsize][j][3];
-
- vArray[d + c + 42] = colors[i][j + stepsize][3];
-
- vArray[d + c + 51] = colors[i + stepsize][j + stepsize][3];
- }
- }
-}
-
-void Terrain::UpdateVertexArray(int whichx, int whichy)
-{
- static int i, j, a, b, c, patch_size, stepsize;
-
-
- numtris[whichx][whichy] = 0;
-
- patch_size = size / subdivision;
-
- stepsize = 1;
- c = whichx * patch_elements + whichy * patch_elements * subdivision;
- for (i = patch_size * whichx; i < patch_size * (whichx + 1); i += stepsize) {
- for (j = patch_size * whichy; j < patch_size * (whichy + 1); j += stepsize) {
- a = (i - ((float)size / subdivision * (float)whichx)) / stepsize;
- b = (j - ((float)size / subdivision * (float)whichy)) / stepsize;
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 0] = i * scale;
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 1] = heightmap[i][j] * scale;
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 2] = j * scale;
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 3] = colors[i][j][0];
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 4] = colors[i][j][1];
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 5] = colors[i][j][2];
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 6] = colors[i][j][3];
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 7] = i * scale * texscale + texoffsetx[i][j];
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 8] = j * scale * texscale + texoffsety[i][j];
-
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 9] = i * scale;
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 10] = heightmap[i][j + stepsize] * scale;
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 11] = j * scale + stepsize * scale;
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 12] = colors[i][j + stepsize][0];
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 13] = colors[i][j + stepsize][1];
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 14] = colors[i][j + stepsize][2];
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 15] = colors[i][j + stepsize][3];
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 16] = i * scale * texscale + texoffsetx[i][j + stepsize];
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 17] = j * scale * texscale + stepsize * scale * texscale + texoffsety[i][j + stepsize];
-
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 18] = i * scale + stepsize * scale;
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 19] = heightmap[i + stepsize][j] * scale;
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 20] = j * scale;
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 21] = colors[i + stepsize][j][0];
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 22] = colors[i + stepsize][j][1];
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 23] = colors[i + stepsize][j][2];
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 24] = colors[i + stepsize][j][3];
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 25] = i * scale * texscale + stepsize * scale * texscale + texoffsetx[i + stepsize][j];
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 26] = j * scale * texscale + texoffsety[i + stepsize][j];
-
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 27] = i * scale + stepsize * scale;
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 28] = heightmap[i + stepsize][j] * scale;
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 29] = j * scale;
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 30] = colors[i + stepsize][j][0];
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 31] = colors[i + stepsize][j][1];
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 32] = colors[i + stepsize][j][2];
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 33] = colors[i + stepsize][j][3];
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 34] = i * scale * texscale + stepsize * scale * texscale + texoffsetx[i + stepsize][j];
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 35] = j * scale * texscale + texoffsety[i + stepsize][j];
-
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 36] = i * scale;
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 37] = heightmap[i][j + stepsize] * scale;
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 38] = j * scale + stepsize * scale;
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 39] = colors[i][j + stepsize][0];
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 40] = colors[i][j + stepsize][1];
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 41] = colors[i][j + stepsize][2];
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 42] = colors[i][j + stepsize][3];
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 43] = i * scale * texscale + texoffsetx[i][j + stepsize];
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 44] = j * scale * texscale + stepsize * scale * texscale + texoffsety[i][j + stepsize];
-
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 45] = i * scale + stepsize * scale;
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 46] = heightmap[i + stepsize][j + stepsize] * scale;
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 47] = j * scale + stepsize * scale;
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 48] = colors[i + stepsize][j + stepsize][0];
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 49] = colors[i + stepsize][j + stepsize][1];
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 50] = colors[i + stepsize][j + stepsize][2];
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 51] = colors[i + stepsize][j + stepsize][3];
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 52] = i * scale * texscale + stepsize * scale * texscale + texoffsetx[i + stepsize][j + stepsize];
- vArray[(a * 54) + (b * 54 * patch_size / stepsize) + c + 53] = j * scale * texscale + stepsize * scale * texscale + texoffsety[i + stepsize][j + stepsize];
- numtris[whichx][whichy] += 2;
- }
- }
-
- maxypatch[whichx][whichy] = -10000;
- minypatch[whichx][whichy] = 10000;
- for (a = 0; a < size / subdivision; a++) {
- for (b = 0; b < size / subdivision; b++) {
- if (heightmap[(size / subdivision)*whichx + a][(size / subdivision)*whichy + b]*scale > maxypatch[whichx][whichy])
- maxypatch[whichx][whichy] = heightmap[(size / subdivision) * whichx + a][(size / subdivision) * whichy + b] * scale;
- if (heightmap[(size / subdivision)*whichx + a][(size / subdivision)*whichy + b]*scale < minypatch[whichx][whichy])
- minypatch[whichx][whichy] = heightmap[(size / subdivision) * whichx + a][(size / subdivision) * whichy + b] * scale;
- }
- }
- heightypatch[whichx][whichy] = (maxypatch[whichx][whichy] - minypatch[whichx][whichy]);
- if (heightypatch[whichx][whichy] < size / subdivision * scale)
- heightypatch[whichx][whichy] = size / subdivision * scale;
- avgypatch[whichx][whichy] = (minypatch[whichx][whichy] + maxypatch[whichx][whichy]) / 2;
-
- for (i = whichx * size / subdivision; i < (whichx + 1)*size / subdivision - 1; i++) {
- for (j = whichy * size / subdivision; j < (whichy + 1)*size / subdivision - 1; j++) {
- triangles[(i * (size - 1) * 2) + (j * 2)][0].x = i * scale;
- triangles[(i * (size - 1) * 2) + (j * 2)][0].y = heightmap[i][j] * scale;
- triangles[(i * (size - 1) * 2) + (j * 2)][0].z = j * scale;
-
- triangles[(i * (size - 1) * 2) + (j * 2)][1].x = i * scale;
- triangles[(i * (size - 1) * 2) + (j * 2)][1].y = heightmap[i][j + 1] * scale;
- triangles[(i * (size - 1) * 2) + (j * 2)][1].z = j * scale + scale;
-
- triangles[(i * (size - 1) * 2) + (j * 2)][2].x = i * scale + 1 * scale;
- triangles[(i * (size - 1) * 2) + (j * 2)][2].y = heightmap[i + 1][j] * scale;
- triangles[(i * (size - 1) * 2) + (j * 2)][2].z = j * scale;
-
- triangles[(i * (size - 1) * 2) + (j * 2) + 1][0].x = i * scale + 1 * scale;
- triangles[(i * (size - 1) * 2) + (j * 2) + 1][0].y = heightmap[i + 1][j] * scale;
- triangles[(i * (size - 1) * 2) + (j * 2) + 1][0].z = j * scale;
-
- triangles[(i * (size - 1) * 2) + (j * 2) + 1][1].x = i * scale;
- triangles[(i * (size - 1) * 2) + (j * 2) + 1][1].y = heightmap[i][j + 1] * scale;
- triangles[(i * (size - 1) * 2) + (j * 2) + 1][1].z = j * scale + 1 * scale;
-
- triangles[(i * (size - 1) * 2) + (j * 2) + 1][2].x = i * scale + 1 * scale;
- triangles[(i * (size - 1) * 2) + (j * 2) + 1][2].y = heightmap[i + 1][j + 1] * scale;
- triangles[(i * (size - 1) * 2) + (j * 2) + 1][2].z = j * scale + 1 * scale;
- }
- }
-
-}
-
-
-bool Terrain::load(const std::string& fileName)
-{
- static long i, j;
- static long x, y;
- static float patch_size;
-
- float temptexdetail = texdetail;
-
- ImageRec texture;
-
- //Load Image
- if (!load_image(Folders::getResourcePath(fileName).c_str(), texture)) {
- return false;
- }
-
- //Is it valid?
- if (texture.bpp > 24) {
- int bytesPerPixel = texture.bpp / 8;
-
- int tempnum = 0;
- for (i = 0; i < (long)(texture.sizeY * texture.sizeX * bytesPerPixel); i++) {
- if ((i + 1) % 4) {
- texture.data[tempnum] = texture.data[i];
- tempnum++;
- }
- }
- }
- texture.bpp = 24;
- if (visibleloading)
- Game::LoadingScreen();
-
- texdetail = temptexdetail;
-
- size = texture.sizeX;
-
- for (i = 0; i < size; i++) {
- for (j = 0; j < size; j++) {
- heightmap[size - 1 - i][j] = (float)((texture.data[(i + (j * size)) * texture.bpp / 8])) / 5;
- }
- }
-
- if (visibleloading)
- Game::LoadingScreen();
-
- float slopeness;
-
- for (i = 0; i < subdivision; i++) {
- for (j = 0; j < subdivision; j++) {
- textureness[i][j] = -1;
- }
- }
- if (visibleloading)
- Game::LoadingScreen();
-
-
- for (i = 0; i < size; i++) {
- for (j = 0; j < size; j++) {
- heightmap[i][j] *= .5;
-
- texoffsetx[i][j] = (float)abs(Random() % 100) / 1200 / scale * 3;
- texoffsety[i][j] = (float)abs(Random() % 100) / 1200 / scale * 3;
-
- slopeness = 0;
- if (environment == snowyenvironment) {
- if (j != 0 && heightmap[i][j] - heightmap[i][j - 1] > slopeness) {
- slopeness = heightmap[i][j] - heightmap[i][j - 1];
- }
- opacityother[i][j] = slopeness * slopeness * 2;
- if (opacityother[i][j] > 1)
- opacityother[i][j] = 1;
- opacityother[i][j] -= (float)abs(Random() % 100) / 300;
- }
- if (environment == desertenvironment) {
- if (j != 0 && heightmap[i][j] - heightmap[i][j - 1] > slopeness) {
- slopeness = heightmap[i][j] - heightmap[i][j - 1];
- }
- opacityother[i][j] = slopeness * slopeness * 2;
- if (opacityother[i][j] > 1)
- opacityother[i][j] = 1;
- opacityother[i][j] -= (float)abs(Random() % 100) / 300;
- }
- if (environment == grassyenvironment) {
- if (i != 0 && heightmap[i][j] - heightmap[i - 1][j] > slopeness) {
- slopeness = heightmap[i][j] - heightmap[i - 1][j];
- }
- if (j != 0 && heightmap[i][j] - heightmap[i][j - 1] > slopeness) {
- slopeness = heightmap[i][j] - heightmap[i][j - 1];
- }
- if (i < size - 1 && heightmap[i][j] - heightmap[i + 1][j] > slopeness) {
- slopeness = heightmap[i][j] - heightmap[i + 1][j];
- }
- if (j < size - 1 && heightmap[i][j] - heightmap[i][j + 1] > slopeness) {
- slopeness = heightmap[i][j] - heightmap[i][j + 1];
- }
- opacityother[i][j] = slopeness * slopeness * 10;
- if (opacityother[i][j] > 1)
- opacityother[i][j] = 1;
- opacityother[i][j] -= (float)abs(Random() % 100) / 100;
- }
- }
- }
- if (visibleloading)
- Game::LoadingScreen();
-
- for (i = 0; i < size; i++) {
- for (j = 0; j < size; j++) {
- if (environment == snowyenvironment) {
- heightmap[i][j] -= opacityother[i][j];
- }
- if (environment == desertenvironment) {
- heightmap[i][j] -= opacityother[i][j];
- }
- }
- }
- if (visibleloading)
- Game::LoadingScreen();
-
- for (i = 0; i < size; i++) {
- for (j = 0; j < size; j++) {
- if (opacityother[i][j] < .1)
- opacityother[i][j] = 0;
- if (textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == -1) {
- if (!opacityother[i][j])
- textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = allfirst;
- if (opacityother[i][j] == 1)
- textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = allsecond;
- }
- if (opacityother[i][j] && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allfirst)
- textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
- if (opacityother[i][j] != 1 && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allsecond)
- textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
-
- x = i;
- y = j;
- if (i > 0) {
- i--;
- if (opacityother[x][y] && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allfirst)
- textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
- if (opacityother[x][y] != 1 && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allsecond)
- textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
- if (opacityother[i][j] && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allfirst)
- textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
- if (opacityother[i][j] != 1 && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allsecond)
- textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
-
- if (j > 0) {
- j--;
- if (opacityother[x][y] && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allfirst)
- textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
- if (opacityother[x][y] != 1 && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allsecond)
- textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
- if (opacityother[i][j] && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allfirst)
- textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
- if (opacityother[i][j] != 1 && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allsecond)
- textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
- j++;
- }
-
- if (j < size - 1) {
- j++;
- if (opacityother[x][y] && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allfirst)
- textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
- if (opacityother[x][y] != 1 && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allsecond)
- textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
- if (opacityother[i][j] && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allfirst)
- textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
- if (opacityother[i][j] != 1 && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allsecond)
- textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
- j--;
- }
- i++;
- }
-
- if (i < size - 1) {
- i++;
- if (opacityother[x][y] && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allfirst)
- textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
- if (opacityother[x][y] != 1 && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allsecond)
- textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
- if (opacityother[i][j] && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allfirst)
- textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
- if (opacityother[i][j] != 1 && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allsecond)
- textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
-
- if (j > 0) {
- j--;
- if (opacityother[x][y] && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allfirst)
- textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
- if (opacityother[x][y] != 1 && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allsecond)
- textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
- if (opacityother[i][j] && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allfirst)
- textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
- if (opacityother[i][j] != 1 && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allsecond)
- textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
- j++;
- }
-
- if (j < size - 1) {
- j++;
- if (opacityother[x][y] && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allfirst)
- textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
- if (opacityother[x][y] != 1 && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allsecond)
- textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
- if (opacityother[i][j] && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allfirst)
- textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
- if (opacityother[i][j] != 1 && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allsecond)
- textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
- j--;
- }
- i--;
- }
-
- if (j > 0) {
- j--;
- if (opacityother[x][y] && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allfirst)
- textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
- if (opacityother[x][y] != 1 && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allsecond)
- textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
- if (opacityother[i][j] && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allfirst)
- textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
- if (opacityother[i][j] != 1 && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allsecond)
- textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
- j++;
- }
-
- if (j < size - 1) {
- j++;
- if (opacityother[x][y] && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allfirst)
- textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
- if (opacityother[x][y] != 1 && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allsecond)
- textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
- if (opacityother[i][j] && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allfirst)
- textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
- if (opacityother[i][j] != 1 && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allsecond)
- textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
- j--;
-
- }
- }
- }
- if (visibleloading)
- Game::LoadingScreen();
-
- patch_size = size / subdivision;
- patch_elements = (patch_size) * (patch_size) * 54;
- CalculateNormals();
-
- return true;
-}
-
-void Terrain::CalculateNormals()
-{
- static int i, j;
- static XYZ facenormal;
- static XYZ p, q, a, b, c;
-
- for (i = 0; i < size; i++) {
- for (j = 0; j < size; j++) {
- normals[i][j].x = 0;
- normals[i][j].y = 0;
- normals[i][j].z = 0;
- }
- }
-
- for (i = 0; i < size - 1; i++) {
- for (j = 0; j < size - 1; j++) {
- a.x = i;
- a.y = heightmap[i][j];
- a.z = j;
- b.x = i;
- b.y = heightmap[i][j + 1];
- b.z = j + 1;
- c.x = i + 1;
- c.y = heightmap[i + 1][j];
- c.z = j;
-
- p.x = b.x - a.x;
- p.y = b.y - a.y;
- p.z = b.z - a.z;
- q.x = c.x - a.x;
- q.y = c.y - a.y;
- q.z = c.z - a.z;
-
- CrossProduct(&p, &q, &facenormal);
-
- facenormals[i][j] = facenormal;
-
- normals[i][j] = normals[i][j] + facenormal;
- normals[i][j + 1] = normals[i][j + 1] + facenormal;
- normals[i + 1][j] = normals[i + 1][j] + facenormal;
-
-
- a.x = i + 1;
- a.y = heightmap[i + 1][j];
- a.z = j;
- b.x = i;
- b.y = heightmap[i][j + 1];
- b.z = j + 1;
- c.x = i + 1;
- c.y = heightmap[i + 1][j + 1];
- c.z = j + 1;
-
- p.x = b.x - a.x;
- p.y = b.y - a.y;
- p.z = b.z - a.z;
- q.x = c.x - a.x;
- q.y = c.y - a.y;
- q.z = c.z - a.z;
-
- CrossProduct(&p, &q, &facenormal);
-
- normals[i + 1][j + 1] = normals[i + 1][j + 1] + facenormal;
- normals[i][j + 1] = normals[i][j + 1] + facenormal;
- normals[i + 1][j] = normals[i + 1][j] + facenormal;
-
- Normalise(&facenormals[i][j]);
- }
- }
-
- for (i = 0; i < size; i++) {
- for (j = 0; j < size; j++) {
- Normalise(&normals[i][j]);
- }
- }
-}
-
-void Terrain::drawpatch(int whichx, int whichy, float opacity)
-{
- if (opacity >= 1)
- glDisable(GL_BLEND);
- if (opacity < 1) {
- glEnable(GL_BLEND);
- UpdateTransparency(whichx, whichy);
- }
- glColor4f(1, 1, 1, 1);
- //Set up vertex array
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_COLOR_ARRAY);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glVertexPointer(3, GL_FLOAT, 9 * sizeof(GLfloat), &vArray[0 + whichx * patch_elements + whichy * patch_elements * subdivision]);
- glColorPointer(4, GL_FLOAT, 9 * sizeof(GLfloat), &vArray[3 + whichx * patch_elements + whichy * patch_elements * subdivision]);
- glTexCoordPointer(2, GL_FLOAT, 9 * sizeof(GLfloat), &vArray[7 + whichx * patch_elements + whichy * patch_elements * subdivision]);
-
- //Draw
- glDrawArrays(GL_TRIANGLES, 0, numtris[whichx][whichy] * 3);
-
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisableClientState(GL_COLOR_ARRAY);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-}
-
-void Terrain::drawpatchother(int whichx, int whichy, float opacity)
-{
- glEnable(GL_BLEND);
- if (opacity < 1) {
- UpdateTransparency(whichx, whichy);
- }
- UpdateTransparencyother(whichx, whichy);
- glColor4f(1, 1, 1, 1);
- //Set up vertex array
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_COLOR_ARRAY);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glVertexPointer(3, GL_FLOAT, 9 * sizeof(GLfloat), &vArray[0 + whichx * patch_elements + whichy * patch_elements * subdivision]);
- glColorPointer(4, GL_FLOAT, 9 * sizeof(GLfloat), &vArray[3 + whichx * patch_elements + whichy * patch_elements * subdivision]);
- glTexCoordPointer(2, GL_FLOAT, 9 * sizeof(GLfloat), &vArray[7 + whichx * patch_elements + whichy * patch_elements * subdivision]);
-
- //Draw
- glDrawArrays(GL_TRIANGLES, 0, numtris[whichx][whichy] * 3);
-
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisableClientState(GL_COLOR_ARRAY);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-}
-
-void Terrain::drawpatchotherother(int whichx, int whichy, float opacity)
-{
- glEnable(GL_BLEND);
- UpdateTransparencyotherother(whichx, whichy);
-
- glMatrixMode(GL_TEXTURE);
- glPushMatrix();
- glScalef(6, 6, 6);
-
- glColor4f(1, 1, 1, 1);
-
- //Set up vertex array
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_COLOR_ARRAY);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glVertexPointer(3, GL_FLOAT, 9 * sizeof(GLfloat), &vArray[0 + whichx * patch_elements + whichy * patch_elements * subdivision]);
- glColorPointer(4, GL_FLOAT, 9 * sizeof(GLfloat), &vArray[3 + whichx * patch_elements + whichy * patch_elements * subdivision]);
- glTexCoordPointer(2, GL_FLOAT, 9 * sizeof(GLfloat), &vArray[7 + whichx * patch_elements + whichy * patch_elements * subdivision]);
-
- //Draw
- glDrawArrays(GL_TRIANGLES, 0, numtris[whichx][whichy] * 3);
-
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisableClientState(GL_COLOR_ARRAY);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
-}
-
-
-float Terrain::getHeight(float pointx, float pointz)
-{
- static int tilex, tiley;
- static XYZ startpoint, endpoint, intersect, triangle[3];
-
- pointx /= scale;
- pointz /= scale;
-
- if (pointx >= size - 1 || pointz >= size - 1 || pointx <= 0 || pointz <= 0)
- return 0;
-
- startpoint.x = pointx;
- startpoint.y = -1000;
- startpoint.z = pointz;
-
- endpoint = startpoint;
- endpoint.y = 1000;
-
- tilex = pointx;
- tiley = pointz;
-
- triangle[0].x = tilex;
- triangle[0].z = tiley;
- triangle[0].y = heightmap[tilex][tiley];
-
- triangle[1].x = tilex + 1;
- triangle[1].z = tiley;
- triangle[1].y = heightmap[tilex + 1][tiley];
-
- triangle[2].x = tilex;
- triangle[2].z = tiley + 1;
- triangle[2].y = heightmap[tilex][tiley + 1];
-
- if (!LineFacetd(&startpoint, &endpoint, &triangle[0], &triangle[1], &triangle[2], &intersect)) {
- triangle[0].x = tilex + 1;
- triangle[0].z = tiley;
- triangle[0].y = heightmap[tilex + 1][tiley];
-
- triangle[1].x = tilex + 1;
- triangle[1].z = tiley + 1;
- triangle[1].y = heightmap[tilex + 1][tiley + 1];
-
- triangle[2].x = tilex;
- triangle[2].z = tiley + 1;
- triangle[2].y = heightmap[tilex][tiley + 1];
- LineFacetd(&startpoint, &endpoint, &triangle[0], &triangle[1], &triangle[2], &intersect);
- }
- return intersect.y * scale + getOpacity(pointx * scale, pointz * scale) / 8;
-}
-
-float Terrain::getOpacity(float pointx, float pointz)
-{
- static float height1, height2;
- static int tilex, tiley;
-
- pointx /= scale;
- pointz /= scale;
-
- if (pointx >= size - 1 || pointz >= size - 1 || pointx <= 0 || pointz <= 0)
- return 0;
-
- tilex = pointx;
- tiley = pointz;
-
- height1 = opacityother[tilex][tiley] * (1 - (pointx - tilex)) + opacityother[tilex + 1][tiley] * (pointx - tilex);
- height2 = opacityother[tilex][tiley + 1] * (1 - (pointx - tilex)) + opacityother[tilex + 1][tiley + 1] * (pointx - tilex);
-
- return height1 * (1 - (pointz - tiley)) + height2 * (pointz - tiley);
-}
-
-XYZ Terrain::getNormal(float pointx, float pointz)
-{
- static XYZ height1, height2, total;
- static int tilex, tiley;
-
- pointx /= scale;
- pointz /= scale;
-
- height1 = 0;
- if (pointx >= size - 1 || pointz >= size - 1 || pointx <= 0 || pointz <= 0)
- return height1;
- tilex = pointx;
- tiley = pointz;
-
- height1 = normals[tilex][tiley] * (1 - (pointx - tilex)) + normals[tilex + 1][tiley] * (pointx - tilex);
- height2 = normals[tilex][tiley + 1] * (1 - (pointx - tilex)) + normals[tilex + 1][tiley + 1] * (pointx - tilex);
- total = height1 * (1 - (pointz - tiley)) + height2 * (pointz - tiley);
- Normalise(&total);
- return total;
-}
-
-XYZ Terrain::getLighting(float pointx, float pointz)
-{
- static XYZ height1, height2;
- static int tilex, tiley;
-
- pointx /= scale;
- pointz /= scale;
-
- height1 = 0;
- if (pointx >= size - 1 || pointz >= size - 1 || pointx <= 0 || pointz <= 0)
- return height1;
- tilex = pointx;
- tiley = pointz;
-
- height1.x = colors[tilex][tiley][0] * (1 - (pointx - tilex)) + colors[tilex + 1][tiley][0] * (pointx - tilex);
- height1.y = colors[tilex][tiley][1] * (1 - (pointx - tilex)) + colors[tilex + 1][tiley][1] * (pointx - tilex);
- height1.z = colors[tilex][tiley][2] * (1 - (pointx - tilex)) + colors[tilex + 1][tiley][2] * (pointx - tilex);
- height2.x = colors[tilex][tiley + 1][0] * (1 - (pointx - tilex)) + colors[tilex + 1][tiley + 1][0] * (pointx - tilex);
- height2.y = colors[tilex][tiley + 1][1] * (1 - (pointx - tilex)) + colors[tilex + 1][tiley + 1][1] * (pointx - tilex);
- height2.z = colors[tilex][tiley + 1][2] * (1 - (pointx - tilex)) + colors[tilex + 1][tiley + 1][2] * (pointx - tilex);
-
- return height1 * (1 - (pointz - tiley)) + height2 * (pointz - tiley);
-}
-
-void Terrain::draw(int layer)
-{
- static int i, j;
- static float opacity;
- static XYZ terrainpoint;
- static float distance[subdivision][subdivision];
-
- static int beginx, endx;
- static int beginz, endz;
-
- static float patch_size = size / subdivision * scale;
- static float viewdistsquared;
-
- viewdistsquared = viewdistance * viewdistance;
-
- //Only nearby blocks
- beginx = (viewer.x - viewdistance) / (patch_size) - 1;
- if (beginx < 0)
- beginx = 0;
- beginz = (viewer.z - viewdistance) / (patch_size) - 1;
- if (beginz < 0)
- beginz = 0;
-
- endx = (viewer.x + viewdistance) / (patch_size) + 1;
- if (endx > subdivision)
- endx = subdivision;
- endz = (viewer.z + viewdistance) / (patch_size) + 1;
- if (endz > subdivision)
- endz = subdivision;
-
- if (!layer) {
- for (i = beginx; i < endx; i++) {
- for (j = beginz; j < endz; j++) {
- terrainpoint.x = i * patch_size + (patch_size) / 2;
- terrainpoint.y = viewer.y; //heightmap[i][j]*scale;
- terrainpoint.z = j * patch_size + (patch_size) / 2;
- distance[i][j] = distsq(&viewer, &terrainpoint);
- }
- }
- }
- for (i = beginx; i < endx; i++) {
- for (j = beginz; j < endz; j++) {
- if (distance[i][j] < (viewdistance + patch_size) * (viewdistance + patch_size)) {
- opacity = 1;
- if (distance[i][j] > viewdistsquared * fadestart - viewdistsquared)
- opacity = 0;
- if (opacity == 1 && i != subdivision)
- if (distance[i + 1][j] > viewdistsquared * fadestart - viewdistsquared)
- opacity = 0;
- if (opacity == 1 && j != subdivision)
- if (distance[i][j + 1] > viewdistsquared * fadestart - viewdistsquared)
- opacity = 0;
- if (opacity == 1 && j != subdivision && i != subdivision)
- if (distance[i + 1][j + 1] > viewdistsquared * fadestart - viewdistsquared)
- opacity = 0;
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- if (frustum.CubeInFrustum(i * patch_size + patch_size * .5, avgypatch[i][j], j * patch_size + patch_size * .5, heightypatch[i][j] / 2)) {
- if (environment == desertenvironment && distance[i][j] > viewdistsquared / 4)
- glTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, blurness);
- else if (environment == desertenvironment)
- glTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0 );
- if (!layer && textureness[i][j] != allsecond)
- drawpatch(i, j, opacity);
- if (layer == 1 && textureness[i][j] != allfirst)
- drawpatchother(i, j, opacity);
- if (layer == 2 && textureness[i][j] != allfirst)
- drawpatchotherother(i, j, opacity);
- }
- glPopMatrix();
- }
- }
- }
- if (environment == desertenvironment)
- glTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0 );
-}
-
-void Terrain::drawdecals()
-{
- if (decals) {
- static int i;
- static float distancemult;
- static int lasttype;
-
- static float viewdistsquared;
- static bool blend;
-
- viewdistsquared = viewdistance * viewdistance;
- blend = 1;
-
- lasttype = -1;
- glEnable(GL_BLEND);
- glDisable(GL_LIGHTING);
- glDisable(GL_CULL_FACE);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glDepthMask(0);
- for (i = 0; i < numdecals; i++) {
- if (decaltype[i] == blooddecalfast && decalalivetime[i] < 2)
- decalalivetime[i] = 2;
- if ((decaltype[i] == shadowdecal || decaltype[i] == shadowdecalpermanent) && decaltype[i] != lasttype) {
- shadowtexture.bind();
- if (!blend) {
- blend = 1;
- glAlphaFunc(GL_GREATER, 0.0001);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- }
- }
- if (decaltype[i] == footprintdecal && decaltype[i] != lasttype) {
- footprinttexture.bind();
- if (!blend) {
- blend = 1;
- glAlphaFunc(GL_GREATER, 0.0001);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- }
- }
- if (decaltype[i] == bodyprintdecal && decaltype[i] != lasttype) {
- bodyprinttexture.bind();
- if (!blend) {
- blend = 1;
- glAlphaFunc(GL_GREATER, 0.0001);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- }
- }
- if ((decaltype[i] == blooddecal || decaltype[i] == blooddecalslow) && decaltype[i] != lasttype) {
- bloodtexture.bind();
- if (blend) {
- blend = 0;
- glAlphaFunc(GL_GREATER, 0.15);
- glBlendFunc(GL_ONE, GL_ZERO);
- }
- }
- if ((decaltype[i] == blooddecalfast) && decaltype[i] != lasttype) {
- bloodtexture2.bind();
- if (blend) {
- blend = 0;
- glAlphaFunc(GL_GREATER, 0.15);
- glBlendFunc(GL_ONE, GL_ZERO);
- }
- }
- if (decaltype[i] == shadowdecal || decaltype[i] == shadowdecalpermanent) {
- distancemult = (viewdistsquared - (distsq(&viewer, &decalposition[i]) - (viewdistsquared * fadestart)) * (1 / (1 - fadestart))) / viewdistsquared;
- if (distancemult >= 1)
- glColor4f(1, 1, 1, decalopacity[i]);
- if (distancemult < 1)
- glColor4f(1, 1, 1, decalopacity[i]*distancemult);
- }
- if (decaltype[i] == footprintdecal || decaltype[i] == bodyprintdecal) {
- distancemult = (viewdistsquared - (distsq(&viewer, &decalposition[i]) - (viewdistsquared * fadestart)) * (1 / (1 - fadestart))) / viewdistsquared;
- if (distancemult >= 1) {
- glColor4f(1, 1, 1, decalopacity[i]);
- if (decalalivetime[i] > 3)
- glColor4f(1, 1, 1, decalopacity[i] * (5 - decalalivetime[i]) / 2);
- }
- if (distancemult < 1) {
- glColor4f(1, 1, 1, decalopacity[i]*distancemult);
- if (decalalivetime[i] > 3)
- glColor4f(1, 1, 1, decalopacity[i] * (5 - decalalivetime[i]) / 2 * distancemult);
- }
- }
- if ((decaltype[i] == blooddecal || decaltype[i] == blooddecalfast || decaltype[i] == blooddecalslow)) {
- distancemult = (viewdistsquared - (distsq(&viewer, &decalposition[i]) - (viewdistsquared * fadestart)) * (1 / (1 - fadestart))) / viewdistsquared;
- if (distancemult >= 1) {
- glColor4f(decalbrightness[i], decalbrightness[i], decalbrightness[i], decalopacity[i]);
- if (decalalivetime[i] < 4)
- glColor4f(decalbrightness[i], decalbrightness[i], decalbrightness[i], decalopacity[i]*decalalivetime[i]*.25);
- if (decalalivetime[i] > 58)
- glColor4f(decalbrightness[i], decalbrightness[i], decalbrightness[i], decalopacity[i] * (60 - decalalivetime[i]) / 2);
- }
- if (distancemult < 1) {
- glColor4f(decalbrightness[i], decalbrightness[i], decalbrightness[i], decalopacity[i]*distancemult);
- if (decalalivetime[i] < 4)
- glColor4f(decalbrightness[i], decalbrightness[i], decalbrightness[i], decalopacity[i]*decalalivetime[i]*distancemult * .25);
- if (decalalivetime[i] > 58)
- glColor4f(decalbrightness[i], decalbrightness[i], decalbrightness[i], decalopacity[i] * (60 - decalalivetime[i]) / 2 * distancemult);
- }
- }
- lasttype = decaltype[i];
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
-
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glBegin(GL_TRIANGLES);
- for (int j = 0; j < 3; j++) {
- glTexCoord2f(decaltexcoords[i][j][0], decaltexcoords[i][j][1]);
- glVertex3f(decalvertex[i][j].x, decalvertex[i][j].y, decalvertex[i][j].z);
- }
- glEnd();
- glPopMatrix();
- }
- for (i = numdecals - 1; i >= 0; i--) {
- decalalivetime[i] += multiplier;
- if (decaltype[i] == blooddecalslow)
- decalalivetime[i] -= multiplier * 2 / 3;
- if (decaltype[i] == blooddecalfast)
- decalalivetime[i] += multiplier * 4;
- if (decaltype[i] == shadowdecal)
- DeleteDecal(i);
- if (decaltype[i] == footprintdecal && decalalivetime[i] >= 5)
- DeleteDecal(i);
- if (decaltype[i] == bodyprintdecal && decalalivetime[i] >= 5)
- DeleteDecal(i);
- if ((decaltype[i] == blooddecal || decaltype[i] == blooddecalfast || decaltype[i] == blooddecalslow) && decalalivetime[i] >= 60)
- DeleteDecal(i);
- }
- glAlphaFunc(GL_GREATER, 0.0001);
- }
-}
-
-void Terrain::AddObject(XYZ where, float radius, int id)
-{
- bool done;
- int i, j;
- XYZ points[4];
- if (id >= 0 && id < 10000)
- for (i = 0; i < subdivision; i++) {
- for (j = 0; j < subdivision; j++) {
- if (patchobjectnum[i][j] < 300 - 1) {
- done = 0;
- points[0].x = (size / subdivision) * i;
- points[0].z = (size / subdivision) * j;
- points[0].y = heightmap[(int)points[0].x][(int)points[0].z];
- points[1].x = (size / subdivision) * (i + 1);
- points[1].z = (size / subdivision) * j;
- points[1].y = heightmap[(int)points[1].x][(int)points[1].z];
- points[2].x = (size / subdivision) * (i + 1);
- points[2].z = (size / subdivision) * (j + 1);
- points[2].y = heightmap[(int)points[2].x][(int)points[2].z];
- points[3].x = (size / subdivision) * i;
- points[3].z = (size / subdivision) * (j + 1);
- points[3].y = heightmap[(int)points[3].x][(int)points[3].z];
- points[0] *= scale;
- points[1] *= scale;
- points[2] *= scale;
- points[3] *= scale;
- if (!done && where.x + radius > points[0].x && where.x - radius < points[2].x && where.z + radius > points[0].z && where.z - radius < points[2].z) {
- patchobjects[i][j][patchobjectnum[i][j]] = id;
- patchobjectnum[i][j]++;
- done = 1;
- }
- }
- }
- }
-}
-
-void Terrain::DeleteDecal(int which)
-{
- if (decals) {
- decaltype[which] = decaltype[numdecals - 1];
- decalposition[which] = decalposition[numdecals - 1];
- for (int i = 0; i < 3; i++) {
- decalvertex[which][i] = decalvertex[numdecals - 1][i];
- decaltexcoords[which][i][0] = decaltexcoords[numdecals - 1][i][0];
- decaltexcoords[which][i][1] = decaltexcoords[numdecals - 1][i][1];
- }
- decalrotation[which] = decalrotation[numdecals - 1];
- decalalivetime[which] = decalalivetime[numdecals - 1];
- decalopacity[which] = decalopacity[numdecals - 1];
- decalbrightness[which] = decalbrightness[numdecals - 1];
- numdecals--;
- }
-}
-
-void Terrain::MakeDecal(int type, XYZ where, float size, float opacity, float rotation)
-{
- if (decals) {
- if (opacity > 0 && size > 0) {
- static int patchx[4];
- static int patchy[4];
-
- decaltexcoords[numdecals][0][0] = 1;
- decaltexcoords[numdecals][0][1] = 0;
-
- patchx[0] = (where.x + size) / scale;
- patchx[1] = (where.x - size) / scale;
- patchx[2] = (where.x - size) / scale;
- patchx[3] = (where.x + size) / scale;
-
- patchy[0] = (where.z - size) / scale;
- patchy[1] = (where.z - size) / scale;
- patchy[2] = (where.z + size) / scale;
- patchy[3] = (where.z + size) / scale;
-
- if ((patchx[0] != patchx[1] || patchy[0] != patchy[1]) && (patchx[0] != patchx[2] || patchy[0] != patchy[2]) && (patchx[0] != patchx[3] || patchy[0] != patchy[3])) {
- MakeDecalLock(type, where, patchx[0], patchy[0], size, opacity, rotation);
- }
-
- if ((patchx[1] != patchx[2] || patchy[1] != patchy[2]) && (patchx[1] != patchx[3] || patchy[1] != patchy[3])) {
- MakeDecalLock(type, where, patchx[1], patchy[1], size, opacity, rotation);
- }
-
- if ((patchx[2] != patchx[3] || patchy[2] != patchy[3])) {
- MakeDecalLock(type, where, patchx[2], patchy[2], size, opacity, rotation);
- }
- MakeDecalLock(type, where, patchx[3], patchy[3], size, opacity, rotation);
- }
- }
- //}
-}
-
-void Terrain::MakeDecalLock(int type, XYZ where, int whichx, int whichy, float size, float opacity, float rotation)
-{
- if (decals) {
- static float placex, placez;
- static XYZ rot;
-
- float decalbright;
-
- rot = getLighting(where.x, where.z);
- decalbrightness[numdecals] = (rot.x + rot.y + rot.z) / 3;
- if (decalbrightness[numdecals] < .4)
- decalbrightness[numdecals] = .4;
-
- if (environment == grassyenvironment) {
- decalbrightness[numdecals] *= .6;
- }
-
- if (decalbrightness[numdecals] > 1)
- decalbrightness[numdecals] = 1;
- decalbright = decalbrightness[numdecals];
-
- decalposition[numdecals] = where;
- decaltype[numdecals] = type;
- decalopacity[numdecals] = opacity;
- decalrotation[numdecals] = rotation;
- decalalivetime[numdecals] = 0;
-
- placex = (float)whichx * scale + scale;
- placez = (float)whichy * scale;
-
- decaltexcoords[numdecals][0][0] = (placex - where.x) / size / 2 + .5;
- decaltexcoords[numdecals][0][1] = (placez - where.z) / size / 2 + .5;
-
- decalvertex[numdecals][0].x = placex;
- decalvertex[numdecals][0].z = placez;
- decalvertex[numdecals][0].y = heightmap[whichx + 1][whichy] * scale + .01;
-
-
- placex = (float)whichx * scale + scale;
- placez = (float)whichy * scale + scale;
-
- decaltexcoords[numdecals][1][0] = (placex - where.x) / size / 2 + .5;
- decaltexcoords[numdecals][1][1] = (placez - where.z) / size / 2 + .5;
-
- decalvertex[numdecals][1].x = placex;
- decalvertex[numdecals][1].z = placez;
- decalvertex[numdecals][1].y = heightmap[whichx + 1][whichy + 1] * scale + .01;
-
-
- placex = (float)whichx * scale;
- placez = (float)whichy * scale + scale;
-
- decaltexcoords[numdecals][2][0] = (placex - where.x) / size / 2 + .5;
- decaltexcoords[numdecals][2][1] = (placez - where.z) / size / 2 + .5;
-
- decalvertex[numdecals][2].x = placex;
- decalvertex[numdecals][2].z = placez;
- decalvertex[numdecals][2].y = heightmap[whichx][whichy + 1] * scale + .01;
-
- if (decalrotation[numdecals]) {
- for (int i = 0; i < 3; i++) {
- rot.y = 0;
- rot.x = decaltexcoords[numdecals][i][0] - .5;
- rot.z = decaltexcoords[numdecals][i][1] - .5;
- rot = DoRotation(rot, 0, -decalrotation[numdecals], 0);
- decaltexcoords[numdecals][i][0] = rot.x + .5;
- decaltexcoords[numdecals][i][1] = rot.z + .5;
- }
- }
-
- if (!(decaltexcoords[numdecals][0][0] < 0 && decaltexcoords[numdecals][1][0] < 0 && decaltexcoords[numdecals][2][0] < 0))
- if (!(decaltexcoords[numdecals][0][1] < 0 && decaltexcoords[numdecals][1][1] < 0 && decaltexcoords[numdecals][2][1] < 0))
- if (!(decaltexcoords[numdecals][0][0] > 1 && decaltexcoords[numdecals][1][0] > 1 && decaltexcoords[numdecals][2][0] > 1))
- if (!(decaltexcoords[numdecals][0][1] > 1 && decaltexcoords[numdecals][1][1] > 1 && decaltexcoords[numdecals][2][1] > 1))
- if (numdecals < max_decals - 1)
- numdecals++;
-
- decalbrightness[numdecals] = decalbright;
-
- decalposition[numdecals] = where;
- decaltype[numdecals] = type;
- decalopacity[numdecals] = opacity;
- decalrotation[numdecals] = rotation;
- decalalivetime[numdecals] = 0;
-
- placex = (float)whichx * scale + scale;
- placez = (float)whichy * scale;
-
- decaltexcoords[numdecals][0][0] = (placex - where.x) / size / 2 + .5;
- decaltexcoords[numdecals][0][1] = (placez - where.z) / size / 2 + .5;
-
- decalvertex[numdecals][0].x = placex;
- decalvertex[numdecals][0].z = placez;
- decalvertex[numdecals][0].y = heightmap[whichx + 1][whichy] * scale + .01;
-
-
- placex = (float)whichx * scale;
- placez = (float)whichy * scale;
-
- decaltexcoords[numdecals][1][0] = (placex - where.x) / size / 2 + .5;
- decaltexcoords[numdecals][1][1] = (placez - where.z) / size / 2 + .5;
-
- decalvertex[numdecals][1].x = placex;
- decalvertex[numdecals][1].z = placez;
- decalvertex[numdecals][1].y = heightmap[whichx][whichy] * scale + .01;
-
-
- placex = (float)whichx * scale;
- placez = (float)whichy * scale + scale;
-
- decaltexcoords[numdecals][2][0] = (placex - where.x) / size / 2 + .5;
- decaltexcoords[numdecals][2][1] = (placez - where.z) / size / 2 + .5;
-
- decalvertex[numdecals][2].x = placex;
- decalvertex[numdecals][2].z = placez;
- decalvertex[numdecals][2].y = heightmap[whichx][whichy + 1] * scale + .01;
-
- if (decalrotation[numdecals]) {
- for (int i = 0; i < 3; i++) {
- rot.y = 0;
- rot.x = decaltexcoords[numdecals][i][0] - .5;
- rot.z = decaltexcoords[numdecals][i][1] - .5;
- rot = DoRotation(rot, 0, -decalrotation[numdecals], 0);
- decaltexcoords[numdecals][i][0] = rot.x + .5;
- decaltexcoords[numdecals][i][1] = rot.z + .5;
- }
- }
-
- if (!(decaltexcoords[numdecals][0][0] < 0 && decaltexcoords[numdecals][1][0] < 0 && decaltexcoords[numdecals][2][0] < 0))
- if (!(decaltexcoords[numdecals][0][1] < 0 && decaltexcoords[numdecals][1][1] < 0 && decaltexcoords[numdecals][2][1] < 0))
- if (!(decaltexcoords[numdecals][0][0] > 1 && decaltexcoords[numdecals][1][0] > 1 && decaltexcoords[numdecals][2][0] > 1))
- if (!(decaltexcoords[numdecals][0][1] > 1 && decaltexcoords[numdecals][1][1] > 1 && decaltexcoords[numdecals][2][1] > 1))
- if (numdecals < max_decals - 1)
- numdecals++;
- }
-}
-
-void Terrain::DoShadows()
-{
- static int i, j, k, l, todivide;
- static float brightness, total;
- static XYZ testpoint, testpoint2, terrainpoint, lightloc, col;
- lightloc = light.location;
- if (!skyboxtexture) {
- lightloc.x = 0;
- lightloc.z = 0;
- }
- if (skyboxtexture && tutoriallevel) {
- lightloc.x *= .4;
- lightloc.z *= .4;
- }
- int patchx, patchz;
- float shadowed;
- Normalise(&lightloc);
- //Calculate shadows
- for (i = 0; i < size; i++) {
- for (j = 0; j < size; j++) {
- terrainpoint.x = (float)(i) * scale;
- terrainpoint.z = (float)(j) * scale;
- terrainpoint.y = heightmap[i][j] * scale;
-
- shadowed = 0;
- patchx = (float)(i) * subdivision / size;
- patchz = (float)(j) * subdivision / size;
- if (patchobjectnum[patchx][patchz]) {
- for (k = 0; k < patchobjectnum[patchx][patchz]; k++) {
- l = patchobjects[patchx][patchz][k];
- if (objects.type[l] != treetrunktype) {
- testpoint = terrainpoint;
- testpoint2 = terrainpoint + lightloc * 50 * (1 - shadowed);
- if (objects.model[l].LineCheck(&testpoint, &testpoint2, &col, &objects.position[l], &objects.yaw[l]) != -1) {
- shadowed = 1 - (findDistance(&terrainpoint, &col) / 50);
- }
- }
- }
- if (visibleloading)
- Game::LoadingScreen();
- }
- brightness = dotproduct(&lightloc, &normals[i][j]);
- if (shadowed)
- brightness *= 1 - shadowed;
-
- if (brightness > 1)
- brightness = 1;
- if (brightness < 0)
- brightness = 0;
-
- colors[i][j][0] = light.color[0] * brightness + light.ambient[0];
- colors[i][j][1] = light.color[1] * brightness + light.ambient[1];
- colors[i][j][2] = light.color[2] * brightness + light.ambient[2];
-
- if (colors[i][j][0] > 1) colors[i][j][0] = 1;
- if (colors[i][j][1] > 1) colors[i][j][1] = 1;
- if (colors[i][j][2] > 1) colors[i][j][2] = 1;
- if (colors[i][j][0] < 0) colors[i][j][0] = 0;
- if (colors[i][j][1] < 0) colors[i][j][1] = 0;
- if (colors[i][j][2] < 0) colors[i][j][2] = 0;
- }
- }
-
- if (visibleloading)
- Game::LoadingScreen();
-
- //Smooth shadows
- for (i = 0; i < size; i++) {
- for (j = 0; j < size; j++) {
- for (k = 0; k < 3; k++) {
- total = 0;
- todivide = 0;
- if (i != 0) {
- total += colors[j][i - 1][k];
- todivide++;
- }
- if (i != size - 1) {
- total += colors[j][i + 1][k];
- todivide++;
- }
- if (j != 0) {
- total += colors[j - 1][i][k];
- todivide++;
- }
- if (j != size - 1) {
- total += colors[j + 1][i][k];
- todivide++;
- }
- if (i != 0 && j != 0) {
- total += colors[j - 1][i - 1][k];
- todivide++;
- }
- if (i != size - 1 && j != 0) {
- total += colors[j - 1][i + 1][k];
- todivide++;
- }
- if (j != size - 1 && i != size - 1) {
- total += colors[j + 1][i + 1][k];
- todivide++;
- }
- if (j != size - 1 && i != 0) {
- total += colors[j + 1][i - 1][k];
- todivide++;
- }
- total += colors[j][i][k];
- todivide++;
-
- colors[j][i][k] = total / todivide;
- }
- }
- }
-
- for (i = 0; i < subdivision; i++) {
- for (j = 0; j < subdivision; j++) {
- UpdateVertexArray(i, j);
- }
- }
-}
-
-Terrain::Terrain()
-{
- size = 0;
-
- memset(patchobjectnum, 0, sizeof(patchobjectnum));
- memset(patchobjects, 0, sizeof(patchobjects));
-
- scale = 1.0f;
- type = 0;
- memset(heightmap, 0, sizeof(heightmap));
- memset(normals, 0, sizeof(normals));
- memset(facenormals, 0, sizeof(facenormals));
- memset(triangles, 0, sizeof(triangles));
- memset(colors, 0, sizeof(colors));
- memset(opacityother, 0, sizeof(opacityother));
- memset(texoffsetx, 0, sizeof(texoffsetx));
- memset(texoffsety, 0, sizeof(texoffsety));
- memset(numtris, 0, sizeof(numtris));
- memset(textureness, 0, sizeof(textureness));
-
- memset(vArray, 0, sizeof(vArray));
-
- memset(visible, 0, sizeof(visible));
- memset(avgypatch, 0, sizeof(avgypatch));
- memset(maxypatch, 0, sizeof(maxypatch));
- memset(minypatch, 0, sizeof(minypatch));
- memset(heightypatch, 0, sizeof(heightypatch));
-
- patch_elements = 0;
-
- memset(decaltexcoords, 0, sizeof(decaltexcoords));
- memset(decalvertex, 0, sizeof(decalvertex));
- memset(decaltype, 0, sizeof(decaltype));
- memset(decalopacity, 0, sizeof(decalopacity));
- memset(decalrotation, 0, sizeof(decalrotation));
- memset(decalalivetime, 0, sizeof(decalalivetime));
- memset(decalbrightness, 0, sizeof(decalbrightness));
- memset(decalposition, 0, sizeof(decalposition));
- numdecals = 0;
-}
-Terrain::~Terrain()
-{
- terraintexture.destroy();
- shadowtexture.destroy();
- bodyprinttexture.destroy();
- footprinttexture.destroy();
- bloodtexture.destroy();
- bloodtexture2.destroy();
- breaktexture.destroy();
-}
-
+++ /dev/null
-/*
-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 _TERRAIN_H_
-#define _TERRAIN_H_
-
-#include "gamegl.h"
-#include "Frustum.h"
-#include "Lights.h"
-#include "ImageIO.h"
-#include "Quaternions.h"
-#include "Quaternions.h"
-#include "Texture.h"
-
-#define max_terrain_size 256
-#define curr_terrain_size size
-#define subdivision 64
-#define max_patch_elements (max_terrain_size/subdivision)*(max_terrain_size/subdivision)*54
-
-#define allfirst 0
-#define mixed 1
-#define allsecond 2
-
-#define max_decals 1000
-
-#define shadowdecal 0
-#define footprintdecal 1
-#define blooddecal 2
-#define blooddecalfast 3
-#define shadowdecalpermanent 4
-#define breakdecal 5
-#define blooddecalslow 6
-#define bodyprintdecal 7
-
-#define snowyenvironment 0
-#define grassyenvironment 1
-#define desertenvironment 2
-//
-// Model Structures
-//
-
-class Terrain
-{
-public:
- Texture bloodtexture;
- Texture bloodtexture2;
- Texture shadowtexture;
- Texture footprinttexture;
- Texture bodyprinttexture;
- Texture breaktexture;
- Texture terraintexture;
- short size;
-
- int patchobjectnum[subdivision][subdivision];
- int patchobjects[subdivision][subdivision][300];
-
- float scale;
- int type;
- float heightmap[max_terrain_size + 1][max_terrain_size + 1];
- XYZ normals[max_terrain_size][max_terrain_size];
- XYZ facenormals[max_terrain_size][max_terrain_size];
- XYZ triangles[(max_terrain_size - 1) * (max_terrain_size - 1) * 2][3];
- float colors[max_terrain_size][max_terrain_size][4];
- float opacityother[max_terrain_size][max_terrain_size];
- float texoffsetx[max_terrain_size][max_terrain_size];
- float texoffsety[max_terrain_size][max_terrain_size];
- int numtris[subdivision][subdivision];
- int textureness[subdivision][subdivision];
-
- GLfloat vArray[(max_patch_elements)*subdivision*subdivision];
-
- bool visible[subdivision][subdivision];
- float avgypatch[subdivision][subdivision];
- float maxypatch[subdivision][subdivision];
- float minypatch[subdivision][subdivision];
- float heightypatch[subdivision][subdivision];
-
- int patch_elements;
-
- float decaltexcoords[max_decals][3][2];
- XYZ decalvertex[max_decals][3];
- int decaltype[max_decals];
- float decalopacity[max_decals];
- float decalrotation[max_decals];
- float decalalivetime[max_decals];
- float decalbrightness[max_decals];
- XYZ decalposition[max_decals];
- int numdecals;
-
- void AddObject(XYZ where, float radius, int id);
- void DeleteDecal(int which);
- void MakeDecal(int type, XYZ where, float size, float opacity, float rotation);
- void MakeDecalLock(int type, XYZ where, int whichx, int whichy, float size, float opacity, float rotation);
- int lineTerrain(XYZ p1, XYZ p2, XYZ *p);
- float getHeight(float pointx, float pointz);
- float getOpacity(float pointx, float pointz);
- XYZ getLighting(float pointx, float pointz);
- XYZ getNormal(float pointx, float pointz);
- void UpdateVertexArray(int whichx, int whichy);
- void UpdateTransparency(int whichx, int whichy);
- void UpdateTransparencyother(int whichx, int whichy);
- void UpdateTransparencyotherother(int whichx, int whichy);
- bool load(const std::string& fileName);
- void CalculateNormals();
- void drawdecals();
- void draw(int layer);
- void drawpatch(int whichx, int whichy, float opacity);
- void drawpatchother(int whichx, int whichy, float opacity);
- void drawpatchotherother(int whichx, int whichy, float opacity);
- void DoShadows();
-
- Terrain();
- ~Terrain();
-};
-
-#endif
+++ /dev/null
-/*
-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 "Text.h"
-#include "Game.h"
-
-void Text::LoadFontTexture(const std::string& fileName)
-{
- LOGFUNC;
-
- LOG(std::string("Loading font texture...") + fileName);
-
- FontTexture.load(fileName, false);
- if (base) {
- glDeleteLists(base, 512);
- base = 0;
- }
-}
-
-void Text::BuildFont() // Build Our Font Display List
-{
- float cx; // Holds Our X Character Coord
- float cy; // Holds Our Y Character Coord
- int loop;
-
- LOGFUNC;
-
- if (base) {
- glDeleteLists(base, 512);
- base = 0;
- }
-
- base = glGenLists(512); // Creating 256 Display Lists
- FontTexture.bind();
- for (loop = 0; loop < 512; loop++) { // Loop Through All 256 Lists
- if (loop < 256) {
- cx = float(loop % 16) / 16.0f; // X Position Of Current Character
- cy = float(loop / 16) / 16.0f; // Y Position Of Current Character
- } else {
- cx = float((loop - 256) % 16) / 16.0f; // X Position Of Current Character
- cy = float((loop - 256) / 16) / 16.0f; // Y Position Of Current Character
- }
- glNewList(base + loop, GL_COMPILE); // Start Building A List
- glBegin(GL_QUADS); // Use A Quad For Each Character
- glTexCoord2f(cx, 1 - cy - 0.0625f + .001); // Texture Coord (Bottom Left)
- glVertex2i(0, 0); // Vertex Coord (Bottom Left)
- glTexCoord2f(cx + 0.0625f, 1 - cy - 0.0625f + .001); // Texture Coord (Bottom Right)
- glVertex2i(16, 0); // Vertex Coord (Bottom Right)
- glTexCoord2f(cx + 0.0625f, 1 - cy - .001); // Texture Coord (Top Right)
- glVertex2i(16, 16); // Vertex Coord (Top Right)
- glTexCoord2f(cx, 1 - cy - +.001); // Texture Coord (Top Left)
- glVertex2i(0, 16); // Vertex Coord (Top Left)
- glEnd(); // Done Building Our Quad (Character)
- if (loop < 256)
- glTranslated(10, 0, 0); // Move To The Right Of The Character
- else
- glTranslated(8, 0, 0); // Move To The Right Of The Character
- glEndList(); // Done Building The Display List
- } // Loop Until All 256 Are Built
-}
-
-void Text::glPrint(float x, float y, const char *string, int set, float size, float width, float height) // Where The Printing Happens
-{
- glPrint(x, y, string, set, size, width, height, 0, strlen(string));
-}
-
-void Text::_glPrint(float x, float y, const char *string, int set, float size, float width, float height, int start, int end, int offset) // Where The Printing Happens
-{
- if (set > 1) {
- set = 1;
- }
- glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
- FontTexture.bind();
- glDisable(GL_DEPTH_TEST);
- glDisable(GL_LIGHTING);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
- glOrtho(0, width, 0, height, -100, 100);
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadIdentity();
- glTranslated(x, y, 0);
- glScalef(size, size, 1);
- glListBase(base - 32 + (128 * set) + offset); // Choose The Font Set (0 or 1)
- glCallLists(end - start, GL_BYTE, &string[start]); // Write The Text To The Screen
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
- glEnable(GL_DEPTH_TEST);
- glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
-}
-
-void Text::glPrint(float x, float y, const char *string, int set, float size, float width, float height, int start, int end) // Where The Printing Happens
-{
- _glPrint(x, y, string, set, size, width, height, start, end, 0);
-}
-
-void Text::glPrintOutline(float x, float y, const char *string, int set, float size, float width, float height) // Where The Printing Happens
-{
- glPrintOutline(x, y, string, set, size, width, height, 0, strlen(string));
-}
-
-void Text::glPrintOutline(float x, float y, const char *string, int set, float size, float width, float height, int start, int end) // Where The Printing Happens
-{
- _glPrint(x, y, string, set, size, width, height, start, end, 256);
-}
-void Text::glPrintOutlined(float x, float y, const char *string, int set, float size, float width, float height) // Where The Printing Happens
-{
- glPrintOutlined(1, 1, 1, x, y, string, set, size, width, height);
-}
-
-void Text::glPrintOutlined(float r, float g, float b, float x, float y, const char *string, int set, float size, float width, float height) // Where The Printing Happens
-{
- glColor4f(0, 0, 0, 1);
- glPrintOutline( x - 2 * size, y - 2 * size, string, set, size * 2.5 / 2, width, height);
- glColor4f(r, g, b, 1);
- glPrint( x, y, string, set, size, width, height);
-}
-
-Text::Text()
-{
- base = 0;
-}
-Text::~Text()
-{
- if (base) {
- glDeleteLists(base, 512);
- base = 0;
- }
- FontTexture.destroy();
-}
-
+++ /dev/null
-/*
-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 _TEXT_H_
-#define _TEXT_H_
-
-
-/**> HEADER FILES <**/
-#include "Quaternions.h"
-//#include "Files.h"
-#include "Quaternions.h"
-#include "gamegl.h"
-#include "ImageIO.h"
-#include "Texture.h"
-
-class Text
-{
-public:
- Texture FontTexture;
- GLuint base;
-
- void LoadFontTexture(const std::string& fileName);
- void BuildFont();
- void glPrint(float x, float y, const char *string, int set, float size, float width, float height);
- void glPrintOutline(float x, float y, const char *string, int set, float size, float width, float height);
- void glPrint(float x, float y, const char *string, int set, float size, float width, float height, int start, int end);
- void glPrintOutline(float x, float y, const char *string, int set, float size, float width, float height, int start, int end);
- void glPrintOutlined(float x, float y, const char *string, int set, float size, float width, float height);
- void glPrintOutlined(float r, float g, float b, float x, float y, const char *string, int set, float size, float width, float height);
-
- Text();
- ~Text();
-
-private:
- void _glPrint(float x, float y, const char *string, int set, float size, float width, float height, int start, int end, int offset);
-};
-
-#endif
+++ /dev/null
-/*
-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/>.
-*/
-
-#include "gamegl.h"
-#include "Texture.h"
-#include "ImageIO.h"
-#include "Utils/Folders.h"
-
-using namespace std;
-
-extern bool trilinear;
-
-vector<TextureRes*> TextureRes::list;
-
-void TextureRes::load()
-{
- ImageRec texture;
-
- //load image into 'texture'
- if (!load_image(filename.c_str(), texture)) {
- cerr << "Texture " << filename << " loading failed" << endl;
- return;
- }
-
- skinsize = texture.sizeX;
- GLuint type = GL_RGBA;
- if (texture.bpp == 24)
- type = GL_RGB;
-
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-
- glDeleteTextures(1, &id);
- glGenTextures(1, &id);
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-
- glBindTexture(GL_TEXTURE_2D, id);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- if (hasMipmap) {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (trilinear ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR_MIPMAP_NEAREST));
- glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
- } else {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- }
-
- if (isSkin) {
- free(data);
- const int nb = texture.sizeY * texture.sizeX * (texture.bpp / 8);
- data = (GLubyte*)malloc(nb * sizeof(GLubyte));
- datalen = 0;
- for (int i = 0; i < nb; i++)
- if ((i + 1) % 4 || type == GL_RGB)
- data[datalen++] = texture.data[i];
- glTexImage2D(GL_TEXTURE_2D, 0, type, texture.sizeX, texture.sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
- } else {
- glTexImage2D(GL_TEXTURE_2D, 0, type, texture.sizeX, texture.sizeY, 0, type, GL_UNSIGNED_BYTE, texture.data);
- }
-}
-
-void TextureRes::bind()
-{
- glBindTexture(GL_TEXTURE_2D, id);
-}
-
-TextureRes::TextureRes(const string& _filename, bool _hasMipmap):
- id(0), filename(_filename), hasMipmap(_hasMipmap), isSkin(false),
- skinsize(0), data(NULL), datalen(0)
-{
- load();
- list.push_back(this);
-}
-
-TextureRes::TextureRes(const string& _filename, bool _hasMipmap, GLubyte* array, int* skinsizep):
- id(0), filename(_filename), hasMipmap(_hasMipmap), isSkin(true),
- skinsize(0), data(NULL), datalen(0)
-{
- load();
- *skinsizep = skinsize;
- for (int i = 0; i < datalen; i++)
- array[i] = data[i];
- list.push_back(this);
-}
-
-TextureRes::~TextureRes()
-{
- free(data);
- glDeleteTextures(1, &id);
- for (vector<TextureRes*>::iterator it = list.begin(); it != list.end(); it++)
- if (*it == this) {
- list.erase(it);
- break;
- }
-}
-
-void Texture::load(const string& filename, bool hasMipmap)
-{
- destroy();
- tex = new TextureRes(Folders::getResourcePath(filename), hasMipmap);
-}
-
-void Texture::load(const string& filename, bool hasMipmap, GLubyte* array, int* skinsizep)
-{
- destroy();
- tex = new TextureRes(Folders::getResourcePath(filename), hasMipmap, array, skinsizep);
-}
-
-void Texture::destroy()
-{
- if (tex) {
- delete tex;
- tex = NULL;
- }
-}
-
-void Texture::bind()
-{
- if (tex)
- tex->bind();
- else
- glBindTexture(GL_TEXTURE_2D, 0);
-}
+++ /dev/null
-/*
-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 _TEXTURE_H_
-#define _TEXTURE_H_
-
-#include <map>
-#include <vector>
-#include <string>
-using namespace std;
-
-class TextureRes
-{
-private:
- static vector<TextureRes*> list;
-
- GLuint id;
- string filename;
- bool hasMipmap;
- bool isSkin;
- int skinsize;
- GLubyte* data;
- int datalen;
-
- void load();
-
-public:
- TextureRes(const string& filename, bool hasMipmap);
- TextureRes(const string& filename, bool hasMipmap, GLubyte* array, int* skinsize);
- ~TextureRes();
- void bind();
-};
-
-class Texture
-{
-private:
- TextureRes* tex;
-public:
- inline Texture(): tex(NULL) {}
- void load(const string& filename, bool hasMipmap);
- void load(const string& filename, bool hasMipmap, GLubyte* array, int* skinsizep);
- void destroy();
- void bind();
-};
-
-#endif
--- /dev/null
+/*
+ * The Lean Mean C++ Option Parser
+ *
+ * Copyright (C) 2012 Matthias S. Benkmann
+ *
+ * The "Software" in the following 2 paragraphs refers to this file containing
+ * the code to The Lean Mean C++ Option Parser.
+ * The "Software" does NOT refer to any other files which you
+ * may have received alongside this file (e.g. as part of a larger project that
+ * incorporates The Lean Mean C++ Option Parser).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software, to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to permit
+ * persons to whom the Software is furnished to do so, subject to the following
+ * conditions:
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*
+ * NOTE: It is recommended that you read the processed HTML doxygen documentation
+ * rather than this source. If you don't know doxygen, it's like javadoc for C++.
+ * If you don't want to install doxygen you can find a copy of the processed
+ * documentation at
+ *
+ * http://optionparser.sourceforge.net/
+ *
+ */
+
+/**
+ * @file
+ *
+ * @brief This is the only file required to use The Lean Mean C++ Option Parser.
+ * Just \#include it and you're set.
+ *
+ * The Lean Mean C++ Option Parser handles the program's command line arguments
+ * (argc, argv).
+ * It supports the short and long option formats of getopt(), getopt_long()
+ * and getopt_long_only() but has a more convenient interface.
+ * The following features set it apart from other option parsers:
+ *
+ * @par Highlights:
+ * <ul style="padding-left:1em;margin-left:0">
+ * <li> It is a header-only library. Just <code>\#include "Thirdparty/optionparser.h"</code> and you're set.
+ * <li> It is freestanding. There are no dependencies whatsoever, not even the
+ * C or C++ standard library.
+ * <li> It has a usage message formatter that supports column alignment and
+ * line wrapping. This aids localization because it adapts to
+ * translated strings that are shorter or longer (even if they contain
+ * Asian wide characters).
+ * <li> Unlike getopt() and derivatives it doesn't force you to loop through
+ * options sequentially. Instead you can access options directly like this:
+ * <ul style="margin-top:.5em">
+ * <li> Test for presence of a switch in the argument vector:
+ * @code if ( options[QUIET] ) ... @endcode
+ * <li> Evaluate --enable-foo/--disable-foo pair where the last one used wins:
+ * @code if ( options[FOO].last()->type() == DISABLE ) ... @endcode
+ * <li> Cumulative option (-v verbose, -vv more verbose, -vvv even more verbose):
+ * @code int verbosity = options[VERBOSE].count(); @endcode
+ * <li> Iterate over all --file=<fname> arguments:
+ * @code for (Option* opt = options[FILE]; opt; opt = opt->next())
+ * fname = opt->arg; ... @endcode
+ * <li> If you really want to, you can still process all arguments in order:
+ * @code
+ * for (int i = 0; i < p.optionsCount(); ++i) {
+ * Option& opt = buffer[i];
+ * switch(opt.index()) {
+ * case HELP: ...
+ * case VERBOSE: ...
+ * case FILE: fname = opt.arg; ...
+ * case UNKNOWN: ...
+ * @endcode
+ * </ul>
+ * </ul> @n
+ * Despite these features the code size remains tiny.
+ * It is smaller than <a href="http://uclibc.org">uClibc</a>'s GNU getopt() and just a
+ * couple 100 bytes larger than uClibc's SUSv3 getopt(). @n
+ * (This does not include the usage formatter, of course. But you don't have to use that.)
+ *
+ * @par Download:
+ * Tarball with examples and test programs:
+ * <a style="font-size:larger;font-weight:bold" href="http://sourceforge.net/projects/optionparser/files/optionparser-1.4.tar.gz/download">optionparser-1.4.tar.gz</a> @n
+ * Just the header (this is all you really need):
+ * <a style="font-size:larger;font-weight:bold" href="http://optionparser.sourceforge.net/optionparser.h">optionparser.h</a>
+ *
+ * @par Changelog:
+ * <b>Version 1.4:</b> Fixed 2 printUsage() bugs that messed up output with small COLUMNS values @n
+ * <b>Version 1.3:</b> Compatible with Microsoft Visual C++. @n
+ * <b>Version 1.2:</b> Added @ref option::Option::namelen "Option::namelen" and removed the extraction
+ * of short option characters into a special buffer. @n
+ * Changed @ref option::Arg::Optional "Arg::Optional" to accept arguments if they are attached
+ * rather than separate. This is what GNU getopt() does and how POSIX recommends
+ * utilities should interpret their arguments.@n
+ * <b>Version 1.1:</b> Optional mode with argument reordering as done by GNU getopt(), so that
+ * options and non-options can be mixed. See
+ * @ref option::Parser::parse() "Parser::parse()".
+ *
+ * @par Feedback:
+ * Send questions, bug reports, feature requests etc. to: <tt><b>optionparser-feedback<span id="antispam"> (a) </span>lists.sourceforge.net</b></tt>
+ * @htmlonly <script type="text/javascript">document.getElementById("antispam").innerHTML="@"</script> @endhtmlonly
+ *
+ *
+ * @par Example program:
+ * (Note: @c option::* identifiers are links that take you to their documentation.)
+ * @code
+ * #error EXAMPLE SHORTENED FOR READABILITY. BETTER EXAMPLES ARE IN THE .TAR.GZ!
+ * #include <iostream>
+ * #include "Thirdparty/optionparser.h"
+ *
+ * enum optionIndex { UNKNOWN, HELP, PLUS };
+ * const option::Descriptor usage[] =
+ * {
+ * {UNKNOWN, 0,"" , "" ,option::Arg::None, "USAGE: example [options]\n\n"
+ * "Options:" },
+ * {HELP, 0,"" , "help",option::Arg::None, " --help \tPrint usage and exit." },
+ * {PLUS, 0,"p", "plus",option::Arg::None, " --plus, -p \tIncrement count." },
+ * {UNKNOWN, 0,"" , "" ,option::Arg::None, "\nExamples:\n"
+ * " example --unknown -- --this_is_no_option\n"
+ * " example -unk --plus -ppp file1 file2\n" },
+ * {0,0,0,0,0,0}
+ * };
+ *
+ * int main(int argc, char* argv[])
+ * {
+ * argc-=(argc>0); argv+=(argc>0); // skip program name argv[0] if present
+ * option::Stats stats(usage, argc, argv);
+ * option::Option options[stats.options_max], buffer[stats.buffer_max];
+ * option::Parser parse(usage, argc, argv, options, buffer);
+ *
+ * if (parse.error())
+ * return 1;
+ *
+ * if (options[HELP] || argc == 0) {
+ * option::printUsage(std::cout, usage);
+ * return 0;
+ * }
+ *
+ * std::cout << "--plus count: " <<
+ * options[PLUS].count() << "\n";
+ *
+ * for (option::Option* opt = options[UNKNOWN]; opt; opt = opt->next())
+ * std::cout << "Unknown option: " << opt->name << "\n";
+ *
+ * for (int i = 0; i < parse.nonOptionsCount(); ++i)
+ * std::cout << "Non-option #" << i << ": " << parse.nonOption(i) << "\n";
+ * }
+ * @endcode
+ *
+ * @par Option syntax:
+ * @li The Lean Mean C++ Option Parser follows POSIX <code>getopt()</code> conventions and supports
+ * GNU-style <code>getopt_long()</code> long options as well as Perl-style single-minus
+ * long options (<code>getopt_long_only()</code>).
+ * @li short options have the format @c -X where @c X is any character that fits in a char.
+ * @li short options can be grouped, i.e. <code>-X -Y</code> is equivalent to @c -XY.
+ * @li a short option may take an argument either separate (<code>-X foo</code>) or
+ * attached (@c -Xfoo). You can make the parser accept the additional format @c -X=foo by
+ * registering @c X as a long option (in addition to being a short option) and
+ * enabling single-minus long options.
+ * @li an argument-taking short option may be grouped if it is the last in the group, e.g.
+ * @c -ABCXfoo or <code> -ABCX foo </code> (@c foo is the argument to the @c -X option).
+ * @li a lone minus character @c '-' is not treated as an option. It is customarily used where
+ * a file name is expected to refer to stdin or stdout.
+ * @li long options have the format @c --option-name.
+ * @li the option-name of a long option can be anything and include any characters.
+ * Even @c = characters will work, but don't do that.
+ * @li [optional] long options may be abbreviated as long as the abbreviation is unambiguous.
+ * You can set a minimum length for abbreviations.
+ * @li [optional] long options may begin with a single minus. The double minus form is always
+ * accepted, too.
+ * @li a long option may take an argument either separate (<code> --option arg </code>) or
+ * attached (<code> --option=arg </code>). In the attached form the equals sign is mandatory.
+ * @li an empty string can be passed as an attached long option argument: <code> --option-name= </code>.
+ * Note the distinction between an empty string as argument and no argument at all.
+ * @li an empty string is permitted as separate argument to both long and short options.
+ * @li Arguments to both short and long options may start with a @c '-' character. E.g.
+ * <code> -X-X </code>, <code>-X -X</code> or <code> --long-X=-X </code>. If @c -X
+ * and @c --long-X take an argument, that argument will be @c "-X" in all 3 cases.
+ * @li If using the built-in @ref option::Arg::Optional "Arg::Optional", optional arguments must
+ * be attached.
+ * @li the special option @c -- (i.e. without a name) terminates the list of
+ * options. Everything that follows is a non-option argument, even if it starts with
+ * a @c '-' character. The @c -- itself will not appear in the parse results.
+ * @li the first argument that doesn't start with @c '-' or @c '--' and does not belong to
+ * a preceding argument-taking option, will terminate the option list and is the
+ * first non-option argument. All following command line arguments are treated as
+ * non-option arguments, even if they start with @c '-' . @n
+ * NOTE: This behaviour is mandated by POSIX, but GNU getopt() only honours this if it is
+ * explicitly requested (e.g. by setting POSIXLY_CORRECT). @n
+ * You can enable the GNU behaviour by passing @c true as first argument to
+ * e.g. @ref option::Parser::parse() "Parser::parse()".
+ * @li Arguments that look like options (i.e. @c '-' followed by at least 1 character) but
+ * aren't, are NOT treated as non-option arguments. They are treated as unknown options and
+ * are collected into a list of unknown options for error reporting. @n
+ * This means that in order to pass a first non-option
+ * argument beginning with the minus character it is required to use the
+ * @c -- special option, e.g.
+ * @code
+ * program -x -- --strange-filename
+ * @endcode
+ * In this example, @c --strange-filename is a non-option argument. If the @c --
+ * were omitted, it would be treated as an unknown option. @n
+ * See @ref option::Descriptor::longopt for information on how to collect unknown options.
+ *
+ */
+
+#ifndef OPTIONPARSER_H_
+#define OPTIONPARSER_H_
+
+/** @brief The namespace of The Lean Mean C++ Option Parser. */
+namespace option
+{
+
+#ifdef _MSC_VER
+#include <intrin.h>
+#pragma intrinsic(_BitScanReverse)
+struct MSC_Builtin_CLZ
+{
+ static int builtin_clz(unsigned x)
+ {
+ unsigned long index;
+ _BitScanReverse(&index, x);
+ return 32-index; // int is always 32bit on Windows, even for target x64
+ }
+};
+#define __builtin_clz(x) MSC_Builtin_CLZ::builtin_clz(x)
+#endif
+
+class Option;
+
+/**
+ * @brief Possible results when checking if an argument is valid for a certain option.
+ *
+ * In the case that no argument is provided for an option that takes an
+ * optional argument, return codes @c ARG_OK and @c ARG_IGNORE are equivalent.
+ */
+enum ArgStatus
+{
+ //! The option does not take an argument.
+ ARG_NONE,
+ //! The argument is acceptable for the option.
+ ARG_OK,
+ //! The argument is not acceptable but that's non-fatal because the option's argument is optional.
+ ARG_IGNORE,
+ //! The argument is not acceptable and that's fatal.
+ ARG_ILLEGAL
+};
+
+/**
+ * @brief Signature of functions that check if an argument is valid for a certain type of option.
+ *
+ * Every Option has such a function assigned in its Descriptor.
+ * @code
+ * Descriptor usage[] = { {UNKNOWN, 0, "", "", Arg::None, ""}, ... };
+ * @endcode
+ *
+ * A CheckArg function has the following signature:
+ * @code ArgStatus CheckArg(const Option& option, bool msg); @endcode
+ *
+ * It is used to check if a potential argument would be acceptable for the option.
+ * It will even be called if there is no argument. In that case @c option.arg will be @c NULL.
+ *
+ * If @c msg is @c true and the function determines that an argument is not acceptable and
+ * that this is a fatal error, it should output a message to the user before
+ * returning @ref ARG_ILLEGAL. If @c msg is @c false the function should remain silent (or you
+ * will get duplicate messages).
+ *
+ * See @ref ArgStatus for the meaning of the return values.
+ *
+ * While you can provide your own functions,
+ * often the following pre-defined checks (which never return @ref ARG_ILLEGAL) will suffice:
+ *
+ * @li @c Arg::None @copybrief Arg::None
+ * @li @c Arg::Optional @copybrief Arg::Optional
+ *
+ */
+typedef ArgStatus (*CheckArg)(const Option& option, bool msg);
+
+/**
+ * @brief Describes an option, its help text (usage) and how it should be parsed.
+ *
+ * The main input when constructing an option::Parser is an array of Descriptors.
+
+ * @par Example:
+ * @code
+ * enum OptionIndex {CREATE, ...};
+ * enum OptionType {DISABLE, ENABLE, OTHER};
+ *
+ * const option::Descriptor usage[] = {
+ * { CREATE, // index
+ * OTHER, // type
+ * "c", // shortopt
+ * "create", // longopt
+ * Arg::None, // check_arg
+ * "--create Tells the program to create something." // help
+ * }
+ * , ...
+ * };
+ * @endcode
+ */
+struct Descriptor
+{
+ /**
+ * @brief Index of this option's linked list in the array filled in by the parser.
+ *
+ * Command line options whose Descriptors have the same index will end up in the same
+ * linked list in the order in which they appear on the command line. If you have
+ * multiple long option aliases that refer to the same option, give their descriptors
+ * the same @c index.
+ *
+ * If you have options that mean exactly opposite things
+ * (e.g. @c --enable-foo and @c --disable-foo ), you should also give them the same
+ * @c index, but distinguish them through different values for @ref type.
+ * That way they end up in the same list and you can just take the last element of the
+ * list and use its type. This way you get the usual behaviour where switches later
+ * on the command line override earlier ones without having to code it manually.
+ *
+ * @par Tip:
+ * Use an enum rather than plain ints for better readability, as shown in the example
+ * at Descriptor.
+ */
+ const unsigned index;
+
+ /**
+ * @brief Used to distinguish between options with the same @ref index.
+ * See @ref index for details.
+ *
+ * It is recommended that you use an enum rather than a plain int to make your
+ * code more readable.
+ */
+ const int type;
+
+ /**
+ * @brief Each char in this string will be accepted as a short option character.
+ *
+ * The string must not include the minus character @c '-' or you'll get undefined
+ * behaviour.
+ *
+ * If this Descriptor should not have short option characters, use the empty
+ * string "". NULL is not permitted here!
+ *
+ * See @ref longopt for more information.
+ */
+ const char* const shortopt;
+
+ /**
+ * @brief The long option name (without the leading @c -- ).
+ *
+ * If this Descriptor should not have a long option name, use the empty
+ * string "". NULL is not permitted here!
+ *
+ * While @ref shortopt allows multiple short option characters, each
+ * Descriptor can have only a single long option name. If you have multiple
+ * long option names referring to the same option use separate Descriptors
+ * that have the same @ref index and @ref type. You may repeat
+ * short option characters in such an alias Descriptor but there's no need to.
+ *
+ * @par Dummy Descriptors:
+ * You can use dummy Descriptors with an
+ * empty string for both @ref shortopt and @ref longopt to add text to
+ * the usage that is not related to a specific option. See @ref help.
+ * The first dummy Descriptor will be used for unknown options (see below).
+ *
+ * @par Unknown Option Descriptor:
+ * The first dummy Descriptor in the list of Descriptors,
+ * whose @ref shortopt and @ref longopt are both the empty string, will be used
+ * as the Descriptor for unknown options. An unknown option is a string in
+ * the argument vector that is not a lone minus @c '-' but starts with a minus
+ * character and does not match any Descriptor's @ref shortopt or @ref longopt. @n
+ * Note that the dummy descriptor's @ref check_arg function @e will be called and
+ * its return value will be evaluated as usual. I.e. if it returns @ref ARG_ILLEGAL
+ * the parsing will be aborted with <code>Parser::error()==true</code>. @n
+ * if @c check_arg does not return @ref ARG_ILLEGAL the descriptor's
+ * @ref index @e will be used to pick the linked list into which
+ * to put the unknown option. @n
+ * If there is no dummy descriptor, unknown options will be dropped silently.
+ *
+ */
+ const char* const longopt;
+
+ /**
+ * @brief For each option that matches @ref shortopt or @ref longopt this function
+ * will be called to check a potential argument to the option.
+ *
+ * This function will be called even if there is no potential argument. In that case
+ * it will be passed @c NULL as @c arg parameter. Do not confuse this with the empty
+ * string.
+ *
+ * See @ref CheckArg for more information.
+ */
+ const CheckArg check_arg;
+
+ /**
+ * @brief The usage text associated with the options in this Descriptor.
+ *
+ * You can use option::printUsage() to format your usage message based on
+ * the @c help texts. You can use dummy Descriptors where
+ * @ref shortopt and @ref longopt are both the empty string to add text to
+ * the usage that is not related to a specific option.
+ *
+ * See option::printUsage() for special formatting characters you can use in
+ * @c help to get a column layout.
+ *
+ * @attention
+ * Must be UTF-8-encoded. If your compiler supports C++11 you can use the "u8"
+ * prefix to make sure string literals are properly encoded.
+ */
+ const char* help;
+};
+
+/**
+ * @brief A parsed option from the command line together with its argument if it has one.
+ *
+ * The Parser chains all parsed options with the same Descriptor::index together
+ * to form a linked list. This allows you to easily implement all of the common ways
+ * of handling repeated options and enable/disable pairs.
+ *
+ * @li Test for presence of a switch in the argument vector:
+ * @code if ( options[QUIET] ) ... @endcode
+ * @li Evaluate --enable-foo/--disable-foo pair where the last one used wins:
+ * @code if ( options[FOO].last()->type() == DISABLE ) ... @endcode
+ * @li Cumulative option (-v verbose, -vv more verbose, -vvv even more verbose):
+ * @code int verbosity = options[VERBOSE].count(); @endcode
+ * @li Iterate over all --file=<fname> arguments:
+ * @code for (Option* opt = options[FILE]; opt; opt = opt->next())
+ * fname = opt->arg; ... @endcode
+ */
+class Option
+{
+ Option* next_;
+ Option* prev_;
+public:
+ /**
+ * @brief Pointer to this Option's Descriptor.
+ *
+ * Remember that the first dummy descriptor (see @ref Descriptor::longopt) is used
+ * for unknown options.
+ *
+ * @attention
+ * @c desc==NULL signals that this Option is unused. This is the default state of
+ * elements in the result array. You don't need to test @c desc explicitly. You
+ * can simply write something like this:
+ * @code
+ * if (options[CREATE])
+ * {
+ * ...
+ * }
+ * @endcode
+ * This works because of <code> operator const Option*() </code>.
+ */
+ const Descriptor* desc;
+
+ /**
+ * @brief The name of the option as used on the command line.
+ *
+ * The main purpose of this string is to be presented to the user in messages.
+ *
+ * In the case of a long option, this is the actual @c argv pointer, i.e. the first
+ * character is a '-'. In the case of a short option this points to the option
+ * character within the @c argv string.
+ *
+ * Note that in the case of a short option group or an attached option argument, this
+ * string will contain additional characters following the actual name. Use @ref namelen
+ * to filter out the actual option name only.
+ *
+ */
+ const char* name;
+
+ /**
+ * @brief Pointer to this Option's argument (if any).
+ *
+ * NULL if this option has no argument. Do not confuse this with the empty string which
+ * is a valid argument.
+ */
+ const char* arg;
+
+ /**
+ * @brief The length of the option @ref name.
+ *
+ * Because @ref name points into the actual @c argv string, the option name may be
+ * followed by more characters (e.g. other short options in the same short option group).
+ * This value is the number of bytes (not characters!) that are part of the actual name.
+ *
+ * For a short option, this length is always 1. For a long option this length is always
+ * at least 2 if single minus long options are permitted and at least 3 if they are disabled.
+ *
+ * @note
+ * In the pathological case of a minus within a short option group (e.g. @c -xf-z), this
+ * length is incorrect, because this case will be misinterpreted as a long option and the
+ * name will therefore extend to the string's 0-terminator or a following '=" character
+ * if there is one. This is irrelevant for most uses of @ref name and @c namelen. If you
+ * really need to distinguish the case of a long and a short option, compare @ref name to
+ * the @c argv pointers. A long option's @c name is always identical to one of them,
+ * whereas a short option's is never.
+ */
+ int namelen;
+
+ /**
+ * @brief Returns Descriptor::type of this Option's Descriptor, or 0 if this Option
+ * is invalid (unused).
+ *
+ * Because this method (and last(), too) can be used even on unused Options with desc==0, you can (provided
+ * you arrange your types properly) switch on type() without testing validity first.
+ * @code
+ * enum OptionType { UNUSED=0, DISABLED=0, ENABLED=1 };
+ * enum OptionIndex { FOO };
+ * const Descriptor usage[] = {
+ * { FOO, ENABLED, "", "enable-foo", Arg::None, 0 },
+ * { FOO, DISABLED, "", "disable-foo", Arg::None, 0 },
+ * { 0, 0, 0, 0, 0, 0 } };
+ * ...
+ * switch(options[FOO].last()->type()) // no validity check required!
+ * {
+ * case ENABLED: ...
+ * case DISABLED: ... // UNUSED==DISABLED !
+ * }
+ * @endcode
+ */
+ int type() const
+ {
+ return desc == 0 ? 0 : desc->type;
+ }
+
+ /**
+ * @brief Returns Descriptor::index of this Option's Descriptor, or -1 if this Option
+ * is invalid (unused).
+ */
+ int index() const
+ {
+ return desc == 0 ? -1 : (int)desc->index;
+ }
+
+ /**
+ * @brief Returns the number of times this Option (or others with the same Descriptor::index)
+ * occurs in the argument vector.
+ *
+ * This corresponds to the number of elements in the linked list this Option is part of.
+ * It doesn't matter on which element you call count(). The return value is always the same.
+ *
+ * Use this to implement cumulative options, such as -v, -vv, -vvv for
+ * different verbosity levels.
+ *
+ * Returns 0 when called for an unused/invalid option.
+ */
+ int count()
+ {
+ int c = (desc == 0 ? 0 : 1);
+ Option* p = first();
+ while (!p->isLast())
+ {
+ ++c;
+ p = p->next_;
+ };
+ return c;
+ }
+
+ /**
+ * @brief Returns true iff this is the first element of the linked list.
+ *
+ * The first element in the linked list is the first option on the command line
+ * that has the respective Descriptor::index value.
+ *
+ * Returns true for an unused/invalid option.
+ */
+ bool isFirst() const
+ {
+ return isTagged(prev_);
+ }
+
+ /**
+ * @brief Returns true iff this is the last element of the linked list.
+ *
+ * The last element in the linked list is the last option on the command line
+ * that has the respective Descriptor::index value.
+ *
+ * Returns true for an unused/invalid option.
+ */
+ bool isLast() const
+ {
+ return isTagged(next_);
+ }
+
+ /**
+ * @brief Returns a pointer to the first element of the linked list.
+ *
+ * Use this when you want the first occurrence of an option on the command line to
+ * take precedence. Note that this is not the way most programs handle options.
+ * You should probably be using last() instead.
+ *
+ * @note
+ * This method may be called on an unused/invalid option and will return a pointer to the
+ * option itself.
+ */
+ Option* first()
+ {
+ Option* p = this;
+ while (!p->isFirst())
+ p = p->prev_;
+ return p;
+ }
+
+ /**
+ * @brief Returns a pointer to the last element of the linked list.
+ *
+ * Use this when you want the last occurrence of an option on the command line to
+ * take precedence. This is the most common way of handling conflicting options.
+ *
+ * @note
+ * This method may be called on an unused/invalid option and will return a pointer to the
+ * option itself.
+ *
+ * @par Tip:
+ * If you have options with opposite meanings (e.g. @c --enable-foo and @c --disable-foo), you
+ * can assign them the same Descriptor::index to get them into the same list. Distinguish them by
+ * Descriptor::type and all you have to do is check <code> last()->type() </code> to get
+ * the state listed last on the command line.
+ */
+ Option* last()
+ {
+ return first()->prevwrap();
+ }
+
+ /**
+ * @brief Returns a pointer to the previous element of the linked list or NULL if
+ * called on first().
+ *
+ * If called on first() this method returns NULL. Otherwise it will return the
+ * option with the same Descriptor::index that precedes this option on the command
+ * line.
+ */
+ Option* prev()
+ {
+ return isFirst() ? 0 : prev_;
+ }
+
+ /**
+ * @brief Returns a pointer to the previous element of the linked list with wrap-around from
+ * first() to last().
+ *
+ * If called on first() this method returns last(). Otherwise it will return the
+ * option with the same Descriptor::index that precedes this option on the command
+ * line.
+ */
+ Option* prevwrap()
+ {
+ return untag(prev_);
+ }
+
+ /**
+ * @brief Returns a pointer to the next element of the linked list or NULL if called
+ * on last().
+ *
+ * If called on last() this method returns NULL. Otherwise it will return the
+ * option with the same Descriptor::index that follows this option on the command
+ * line.
+ */
+ Option* next()
+ {
+ return isLast() ? 0 : next_;
+ }
+
+ /**
+ * @brief Returns a pointer to the next element of the linked list with wrap-around from
+ * last() to first().
+ *
+ * If called on last() this method returns first(). Otherwise it will return the
+ * option with the same Descriptor::index that follows this option on the command
+ * line.
+ */
+ Option* nextwrap()
+ {
+ return untag(next_);
+ }
+
+ /**
+ * @brief Makes @c new_last the new last() by chaining it into the list after last().
+ *
+ * It doesn't matter which element you call append() on. The new element will always
+ * be appended to last().
+ *
+ * @attention
+ * @c new_last must not yet be part of a list, or that list will become corrupted, because
+ * this method does not unchain @c new_last from an existing list.
+ */
+ void append(Option* new_last)
+ {
+ Option* p = last();
+ Option* f = first();
+ p->next_ = new_last;
+ new_last->prev_ = p;
+ new_last->next_ = tag(f);
+ f->prev_ = tag(new_last);
+ }
+
+ /**
+ * @brief Casts from Option to const Option* but only if this Option is valid.
+ *
+ * If this Option is valid (i.e. @c desc!=NULL), returns this.
+ * Otherwise returns NULL. This allows testing an Option directly
+ * in an if-clause to see if it is used:
+ * @code
+ * if (options[CREATE])
+ * {
+ * ...
+ * }
+ * @endcode
+ * It also allows you to write loops like this:
+ * @code for (Option* opt = options[FILE]; opt; opt = opt->next())
+ * fname = opt->arg; ... @endcode
+ */
+ operator const Option*() const
+ {
+ return desc ? this : 0;
+ }
+
+ /**
+ * @brief Casts from Option to Option* but only if this Option is valid.
+ *
+ * If this Option is valid (i.e. @c desc!=NULL), returns this.
+ * Otherwise returns NULL. This allows testing an Option directly
+ * in an if-clause to see if it is used:
+ * @code
+ * if (options[CREATE])
+ * {
+ * ...
+ * }
+ * @endcode
+ * It also allows you to write loops like this:
+ * @code for (Option* opt = options[FILE]; opt; opt = opt->next())
+ * fname = opt->arg; ... @endcode
+ */
+ operator Option*()
+ {
+ return desc ? this : 0;
+ }
+
+ /**
+ * @brief Creates a new Option that is a one-element linked list and has NULL
+ * @ref desc, @ref name, @ref arg and @ref namelen.
+ */
+ Option() :
+ desc(0), name(0), arg(0), namelen(0)
+ {
+ prev_ = tag(this);
+ next_ = tag(this);
+ }
+
+ /**
+ * @brief Creates a new Option that is a one-element linked list and has the given
+ * values for @ref desc, @ref name and @ref arg.
+ *
+ * If @c name_ points at a character other than '-' it will be assumed to refer to a
+ * short option and @ref namelen will be set to 1. Otherwise the length will extend to
+ * the first '=' character or the string's 0-terminator.
+ */
+ Option(const Descriptor* desc_, const char* name_, const char* arg_)
+ {
+ init(desc_, name_, arg_);
+ }
+
+ /**
+ * @brief Makes @c *this a copy of @c orig except for the linked list pointers.
+ *
+ * After this operation @c *this will be a one-element linked list.
+ */
+ void operator=(const Option& orig)
+ {
+ init(orig.desc, orig.name, orig.arg);
+ }
+
+ /**
+ * @brief Makes @c *this a copy of @c orig except for the linked list pointers.
+ *
+ * After this operation @c *this will be a one-element linked list.
+ */
+ Option(const Option& orig)
+ {
+ init(orig.desc, orig.name, orig.arg);
+ }
+
+private:
+ /**
+ * @internal
+ * @brief Sets the fields of this Option to the given values (extracting @c name if necessary).
+ *
+ * If @c name_ points at a character other than '-' it will be assumed to refer to a
+ * short option and @ref namelen will be set to 1. Otherwise the length will extend to
+ * the first '=' character or the string's 0-terminator.
+ */
+ void init(const Descriptor* desc_, const char* name_, const char* arg_)
+ {
+ desc = desc_;
+ name = name_;
+ arg = arg_;
+ prev_ = tag(this);
+ next_ = tag(this);
+ namelen = 0;
+ if (name == 0)
+ return;
+ namelen = 1;
+ if (name[0] != '-')
+ return;
+ while (name[namelen] != 0 && name[namelen] != '=')
+ ++namelen;
+ }
+
+ static Option* tag(Option* ptr)
+ {
+ return (Option*) ((unsigned long long) ptr | 1);
+ }
+
+ static Option* untag(Option* ptr)
+ {
+ return (Option*) ((unsigned long long) ptr & ~1ull);
+ }
+
+ static bool isTagged(Option* ptr)
+ {
+ return ((unsigned long long) ptr & 1);
+ }
+};
+
+/**
+ * @brief Functions for checking the validity of option arguments.
+ *
+ * @copydetails CheckArg
+ *
+ * The following example code
+ * can serve as starting place for writing your own more complex CheckArg functions:
+ * @code
+ * struct Arg: public option::Arg
+ * {
+ * static void printError(const char* msg1, const option::Option& opt, const char* msg2)
+ * {
+ * fprintf(stderr, "ERROR: %s", msg1);
+ * fwrite(opt.name, opt.namelen, 1, stderr);
+ * fprintf(stderr, "%s", msg2);
+ * }
+ *
+ * static option::ArgStatus Unknown(const option::Option& option, bool msg)
+ * {
+ * if (msg) printError("Unknown option '", option, "'\n");
+ * return option::ARG_ILLEGAL;
+ * }
+ *
+ * static option::ArgStatus Required(const option::Option& option, bool msg)
+ * {
+ * if (option.arg != 0)
+ * return option::ARG_OK;
+ *
+ * if (msg) printError("Option '", option, "' requires an argument\n");
+ * return option::ARG_ILLEGAL;
+ * }
+ *
+ * static option::ArgStatus NonEmpty(const option::Option& option, bool msg)
+ * {
+ * if (option.arg != 0 && option.arg[0] != 0)
+ * return option::ARG_OK;
+ *
+ * if (msg) printError("Option '", option, "' requires a non-empty argument\n");
+ * return option::ARG_ILLEGAL;
+ * }
+ *
+ * static option::ArgStatus Numeric(const option::Option& option, bool msg)
+ * {
+ * char* endptr = 0;
+ * if (option.arg != 0 && strtol(option.arg, &endptr, 10)){};
+ * if (endptr != option.arg && *endptr == 0)
+ * return option::ARG_OK;
+ *
+ * if (msg) printError("Option '", option, "' requires a numeric argument\n");
+ * return option::ARG_ILLEGAL;
+ * }
+ * };
+ * @endcode
+ */
+struct Arg
+{
+ //! @brief For options that don't take an argument: Returns ARG_NONE.
+ static ArgStatus None(const Option&, bool)
+ {
+ return ARG_NONE;
+ }
+
+ //! @brief Returns ARG_OK if the argument is attached and ARG_IGNORE otherwise.
+ static ArgStatus Optional(const Option& option, bool)
+ {
+ if (option.arg && option.name[option.namelen] != 0)
+ return ARG_OK;
+ else
+ return ARG_IGNORE;
+ }
+};
+
+/**
+ * @brief Determines the minimum lengths of the buffer and options arrays used for Parser.
+ *
+ * Because Parser doesn't use dynamic memory its output arrays have to be pre-allocated.
+ * If you don't want to use fixed size arrays (which may turn out too small, causing
+ * command line arguments to be dropped), you can use Stats to determine the correct sizes.
+ * Stats work cumulative. You can first pass in your default options and then the real
+ * options and afterwards the counts will reflect the union.
+ */
+struct Stats
+{
+ /**
+ * @brief Number of elements needed for a @c buffer[] array to be used for
+ * @ref Parser::parse() "parsing" the same argument vectors that were fed
+ * into this Stats object.
+ *
+ * @note
+ * This number is always 1 greater than the actual number needed, to give
+ * you a sentinel element.
+ */
+ unsigned buffer_max;
+
+ /**
+ * @brief Number of elements needed for an @c options[] array to be used for
+ * @ref Parser::parse() "parsing" the same argument vectors that were fed
+ * into this Stats object.
+ *
+ * @note
+ * @li This number is always 1 greater than the actual number needed, to give
+ * you a sentinel element.
+ * @li This number depends only on the @c usage, not the argument vectors, because
+ * the @c options array needs exactly one slot for each possible Descriptor::index.
+ */
+ unsigned options_max;
+
+ /**
+ * @brief Creates a Stats object with counts set to 1 (for the sentinel element).
+ */
+ Stats() :
+ buffer_max(1), options_max(1) // 1 more than necessary as sentinel
+ {
+ }
+
+ /**
+ * @brief Creates a new Stats object and immediately updates it for the
+ * given @c usage and argument vector. You may pass 0 for @c argc and/or @c argv,
+ * if you just want to update @ref options_max.
+ *
+ * @note
+ * The calls to Stats methods must match the later calls to Parser methods.
+ * See Parser::parse() for the meaning of the arguments.
+ */
+ Stats(bool gnu, const Descriptor usage[], int argc, const char** argv, int min_abbr_len = 0, //
+ bool single_minus_longopt = false) :
+ buffer_max(1), options_max(1) // 1 more than necessary as sentinel
+ {
+ add(gnu, usage, argc, argv, min_abbr_len, single_minus_longopt);
+ }
+
+ //! @brief Stats(...) with non-const argv.
+ Stats(bool gnu, const Descriptor usage[], int argc, char** argv, int min_abbr_len = 0, //
+ bool single_minus_longopt = false) :
+ buffer_max(1), options_max(1) // 1 more than necessary as sentinel
+ {
+ add(gnu, usage, argc, (const char**) argv, min_abbr_len, single_minus_longopt);
+ }
+
+ //! @brief POSIX Stats(...) (gnu==false).
+ Stats(const Descriptor usage[], int argc, const char** argv, int min_abbr_len = 0, //
+ bool single_minus_longopt = false) :
+ buffer_max(1), options_max(1) // 1 more than necessary as sentinel
+ {
+ add(false, usage, argc, argv, min_abbr_len, single_minus_longopt);
+ }
+
+ //! @brief POSIX Stats(...) (gnu==false) with non-const argv.
+ Stats(const Descriptor usage[], int argc, char** argv, int min_abbr_len = 0, //
+ bool single_minus_longopt = false) :
+ buffer_max(1), options_max(1) // 1 more than necessary as sentinel
+ {
+ add(false, usage, argc, (const char**) argv, min_abbr_len, single_minus_longopt);
+ }
+
+ /**
+ * @brief Updates this Stats object for the
+ * given @c usage and argument vector. You may pass 0 for @c argc and/or @c argv,
+ * if you just want to update @ref options_max.
+ *
+ * @note
+ * The calls to Stats methods must match the later calls to Parser methods.
+ * See Parser::parse() for the meaning of the arguments.
+ */
+ void add(bool gnu, const Descriptor usage[], int argc, const char** argv, int min_abbr_len = 0, //
+ bool single_minus_longopt = false);
+
+ //! @brief add() with non-const argv.
+ void add(bool gnu, const Descriptor usage[], int argc, char** argv, int min_abbr_len = 0, //
+ bool single_minus_longopt = false)
+ {
+ add(gnu, usage, argc, (const char**) argv, min_abbr_len, single_minus_longopt);
+ }
+
+ //! @brief POSIX add() (gnu==false).
+ void add(const Descriptor usage[], int argc, const char** argv, int min_abbr_len = 0, //
+ bool single_minus_longopt = false)
+ {
+ add(false, usage, argc, argv, min_abbr_len, single_minus_longopt);
+ }
+
+ //! @brief POSIX add() (gnu==false) with non-const argv.
+ void add(const Descriptor usage[], int argc, char** argv, int min_abbr_len = 0, //
+ bool single_minus_longopt = false)
+ {
+ add(false, usage, argc, (const char**) argv, min_abbr_len, single_minus_longopt);
+ }
+private:
+ class CountOptionsAction;
+};
+
+/**
+ * @brief Checks argument vectors for validity and parses them into data
+ * structures that are easier to work with.
+ *
+ * @par Example:
+ * @code
+ * int main(int argc, char* argv[])
+ * {
+ * argc-=(argc>0); argv+=(argc>0); // skip program name argv[0] if present
+ * option::Stats stats(usage, argc, argv);
+ * option::Option options[stats.options_max], buffer[stats.buffer_max];
+ * option::Parser parse(usage, argc, argv, options, buffer);
+ *
+ * if (parse.error())
+ * return 1;
+ *
+ * if (options[HELP])
+ * ...
+ * @endcode
+ */
+class Parser
+{
+ int op_count; //!< @internal @brief see optionsCount()
+ int nonop_count; //!< @internal @brief see nonOptionsCount()
+ const char** nonop_args; //!< @internal @brief see nonOptions()
+ bool err; //!< @internal @brief see error()
+public:
+
+ /**
+ * @brief Creates a new Parser.
+ */
+ Parser() :
+ op_count(0), nonop_count(0), nonop_args(0), err(false)
+ {
+ }
+
+ /**
+ * @brief Creates a new Parser and immediately parses the given argument vector.
+ * @copydetails parse()
+ */
+ Parser(bool gnu, const Descriptor usage[], int argc, const char** argv, Option options[], Option buffer[],
+ int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1) :
+ op_count(0), nonop_count(0), nonop_args(0), err(false)
+ {
+ parse(gnu, usage, argc, argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax);
+ }
+
+ //! @brief Parser(...) with non-const argv.
+ Parser(bool gnu, const Descriptor usage[], int argc, char** argv, Option options[], Option buffer[],
+ int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1) :
+ op_count(0), nonop_count(0), nonop_args(0), err(false)
+ {
+ parse(gnu, usage, argc, (const char**) argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax);
+ }
+
+ //! @brief POSIX Parser(...) (gnu==false).
+ Parser(const Descriptor usage[], int argc, const char** argv, Option options[], Option buffer[], int min_abbr_len = 0,
+ bool single_minus_longopt = false, int bufmax = -1) :
+ op_count(0), nonop_count(0), nonop_args(0), err(false)
+ {
+ parse(false, usage, argc, argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax);
+ }
+
+ //! @brief POSIX Parser(...) (gnu==false) with non-const argv.
+ Parser(const Descriptor usage[], int argc, char** argv, Option options[], Option buffer[], int min_abbr_len = 0,
+ bool single_minus_longopt = false, int bufmax = -1) :
+ op_count(0), nonop_count(0), nonop_args(0), err(false)
+ {
+ parse(false, usage, argc, (const char**) argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax);
+ }
+
+ /**
+ * @brief Parses the given argument vector.
+ *
+ * @param gnu if true, parse() will not stop at the first non-option argument. Instead it will
+ * reorder arguments so that all non-options are at the end. This is the default behaviour
+ * of GNU getopt() but is not conforming to POSIX. @n
+ * Note, that once the argument vector has been reordered, the @c gnu flag will have
+ * no further effect on this argument vector. So it is enough to pass @c gnu==true when
+ * creating Stats.
+ * @param usage Array of Descriptor objects that describe the options to support. The last entry
+ * of this array must have 0 in all fields.
+ * @param argc The number of elements from @c argv that are to be parsed. If you pass -1, the number
+ * will be determined automatically. In that case the @c argv list must end with a NULL
+ * pointer.
+ * @param argv The arguments to be parsed. If you pass -1 as @c argc the last pointer in the @c argv
+ * list must be NULL to mark the end.
+ * @param options Each entry is the first element of a linked list of Options. Each new option
+ * that is parsed will be appended to the list specified by that Option's
+ * Descriptor::index. If an entry is not yet used (i.e. the Option is invalid),
+ * it will be replaced rather than appended to. @n
+ * The minimum length of this array is the greatest Descriptor::index value that
+ * occurs in @c usage @e PLUS ONE.
+ * @param buffer Each argument that is successfully parsed (including unknown arguments, if they
+ * have a Descriptor whose CheckArg does not return @ref ARG_ILLEGAL) will be stored in this
+ * array. parse() scans the array for the first invalid entry and begins writing at that
+ * index. You can pass @c bufmax to limit the number of options stored.
+ * @param min_abbr_len Passing a value <code> min_abbr_len > 0 </code> enables abbreviated long
+ * options. The parser will match a prefix of a long option as if it was
+ * the full long option (e.g. @c --foob=10 will be interpreted as if it was
+ * @c --foobar=10 ), as long as the prefix has at least @c min_abbr_len characters
+ * (not counting the @c -- ) and is unambiguous.
+ * @n Be careful if combining @c min_abbr_len=1 with @c single_minus_longopt=true
+ * because the ambiguity check does not consider short options and abbreviated
+ * single minus long options will take precedence over short options.
+ * @param single_minus_longopt Passing @c true for this option allows long options to begin with
+ * a single minus. The double minus form will still be recognized. Note that
+ * single minus long options take precedence over short options and short option
+ * groups. E.g. @c -file would be interpreted as @c --file and not as
+ * <code> -f -i -l -e </code> (assuming a long option named @c "file" exists).
+ * @param bufmax The greatest index in the @c buffer[] array that parse() will write to is
+ * @c bufmax-1. If there are more options, they will be processed (in particular
+ * their CheckArg will be called) but not stored. @n
+ * If you used Stats::buffer_max to dimension this array, you can pass
+ * -1 (or not pass @c bufmax at all) which tells parse() that the buffer is
+ * "large enough".
+ * @attention
+ * Remember that @c options and @c buffer store Option @e objects, not pointers. Therefore it
+ * is not possible for the same object to be in both arrays. For those options that are found in
+ * both @c buffer[] and @c options[] the respective objects are independent copies. And only the
+ * objects in @c options[] are properly linked via Option::next() and Option::prev().
+ * You can iterate over @c buffer[] to
+ * process all options in the order they appear in the argument vector, but if you want access to
+ * the other Options with the same Descriptor::index, then you @e must access the linked list via
+ * @c options[]. You can get the linked list in options from a buffer object via something like
+ * @c options[buffer[i].index()].
+ */
+ void parse(bool gnu, const Descriptor usage[], int argc, const char** argv, Option options[], Option buffer[],
+ int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1);
+
+ //! @brief parse() with non-const argv.
+ void parse(bool gnu, const Descriptor usage[], int argc, char** argv, Option options[], Option buffer[],
+ int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1)
+ {
+ parse(gnu, usage, argc, (const char**) argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax);
+ }
+
+ //! @brief POSIX parse() (gnu==false).
+ void parse(const Descriptor usage[], int argc, const char** argv, Option options[], Option buffer[],
+ int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1)
+ {
+ parse(false, usage, argc, argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax);
+ }
+
+ //! @brief POSIX parse() (gnu==false) with non-const argv.
+ void parse(const Descriptor usage[], int argc, char** argv, Option options[], Option buffer[], int min_abbr_len = 0,
+ bool single_minus_longopt = false, int bufmax = -1)
+ {
+ parse(false, usage, argc, (const char**) argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax);
+ }
+
+ /**
+ * @brief Returns the number of valid Option objects in @c buffer[].
+ *
+ * @note
+ * @li The returned value always reflects the number of Options in the buffer[] array used for
+ * the most recent call to parse().
+ * @li The count (and the buffer[]) includes unknown options if they are collected
+ * (see Descriptor::longopt).
+ */
+ int optionsCount()
+ {
+ return op_count;
+ }
+
+ /**
+ * @brief Returns the number of non-option arguments that remained at the end of the
+ * most recent parse() that actually encountered non-option arguments.
+ *
+ * @note
+ * A parse() that does not encounter non-option arguments will leave this value
+ * as well as nonOptions() undisturbed. This means you can feed the Parser a
+ * default argument vector that contains non-option arguments (e.g. a default filename).
+ * Then you feed it the actual arguments from the user. If the user has supplied at
+ * least one non-option argument, all of the non-option arguments from the default
+ * disappear and are replaced by the user's non-option arguments. However, if the
+ * user does not supply any non-option arguments the defaults will still be in
+ * effect.
+ */
+ int nonOptionsCount()
+ {
+ return nonop_count;
+ }
+
+ /**
+ * @brief Returns a pointer to an array of non-option arguments (only valid
+ * if <code>nonOptionsCount() >0 </code>).
+ *
+ * @note
+ * @li parse() does not copy arguments, so this pointer points into the actual argument
+ * vector as passed to parse().
+ * @li As explained at nonOptionsCount() this pointer is only changed by parse() calls
+ * that actually encounter non-option arguments. A parse() call that encounters only
+ * options, will not change nonOptions().
+ */
+ const char** nonOptions()
+ {
+ return nonop_args;
+ }
+
+ /**
+ * @brief Returns <b><code>nonOptions()[i]</code></b> (@e without checking if i is in range!).
+ */
+ const char* nonOption(int i)
+ {
+ return nonOptions()[i];
+ }
+
+ /**
+ * @brief Returns @c true if an unrecoverable error occurred while parsing options.
+ *
+ * An illegal argument to an option (i.e. CheckArg returns @ref ARG_ILLEGAL) is an
+ * unrecoverable error that aborts the parse. Unknown options are only an error if
+ * their CheckArg function returns @ref ARG_ILLEGAL. Otherwise they are collected.
+ * In that case if you want to exit the program if either an illegal argument
+ * or an unknown option has been passed, use code like this
+ *
+ * @code
+ * if (parser.error() || options[UNKNOWN])
+ * exit(1);
+ * @endcode
+ *
+ */
+ bool error()
+ {
+ return err;
+ }
+
+private:
+ friend struct Stats;
+ class StoreOptionAction;
+ struct Action;
+
+ /**
+ * @internal
+ * @brief This is the core function that does all the parsing.
+ * @retval false iff an unrecoverable error occurred.
+ */
+ static bool workhorse(bool gnu, const Descriptor usage[], int numargs, const char** args, Action& action,
+ bool single_minus_longopt, bool print_errors, int min_abbr_len);
+
+ /**
+ * @internal
+ * @brief Returns true iff @c st1 is a prefix of @c st2 and
+ * in case @c st2 is longer than @c st1, then
+ * the first additional character is '='.
+ *
+ * @par Examples:
+ * @code
+ * streq("foo", "foo=bar") == true
+ * streq("foo", "foobar") == false
+ * streq("foo", "foo") == true
+ * streq("foo=bar", "foo") == false
+ * @endcode
+ */
+ static bool streq(const char* st1, const char* st2)
+ {
+ while (*st1 != 0)
+ if (*st1++ != *st2++)
+ return false;
+ return (*st2 == 0 || *st2 == '=');
+ }
+
+ /**
+ * @internal
+ * @brief Like streq() but handles abbreviations.
+ *
+ * Returns true iff @c st1 and @c st2 have a common
+ * prefix with the following properties:
+ * @li (if min > 0) its length is at least @c min characters or the same length as @c st1 (whichever is smaller).
+ * @li (if min <= 0) its length is the same as that of @c st1
+ * @li within @c st2 the character following the common prefix is either '=' or end-of-string.
+ *
+ * Examples:
+ * @code
+ * streqabbr("foo", "foo=bar",<anything>) == true
+ * streqabbr("foo", "fo=bar" , 2) == true
+ * streqabbr("foo", "fo" , 2) == true
+ * streqabbr("foo", "fo" , 0) == false
+ * streqabbr("foo", "f=bar" , 2) == false
+ * streqabbr("foo", "f" , 2) == false
+ * streqabbr("fo" , "foo=bar",<anything>) == false
+ * streqabbr("foo", "foobar" ,<anything>) == false
+ * streqabbr("foo", "fobar" ,<anything>) == false
+ * streqabbr("foo", "foo" ,<anything>) == true
+ * @endcode
+ */
+ static bool streqabbr(const char* st1, const char* st2, long long min)
+ {
+ const char* st1start = st1;
+ while (*st1 != 0 && (*st1 == *st2))
+ {
+ ++st1;
+ ++st2;
+ }
+
+ return (*st1 == 0 || (min > 0 && (st1 - st1start) >= min)) && (*st2 == 0 || *st2 == '=');
+ }
+
+ /**
+ * @internal
+ * @brief Returns true iff character @c ch is contained in the string @c st.
+ *
+ * Returns @c true for @c ch==0 .
+ */
+ static bool instr(char ch, const char* st)
+ {
+ while (*st != 0 && *st != ch)
+ ++st;
+ return *st == ch;
+ }
+
+ /**
+ * @internal
+ * @brief Rotates <code>args[-count],...,args[-1],args[0]</code> to become
+ * <code>args[0],args[-count],...,args[-1]</code>.
+ */
+ static void shift(const char** args, int count)
+ {
+ for (int i = 0; i > -count; --i)
+ {
+ const char* temp = args[i];
+ args[i] = args[i - 1];
+ args[i - 1] = temp;
+ }
+ }
+};
+
+/**
+ * @internal
+ * @brief Interface for actions Parser::workhorse() should perform for each Option it
+ * parses.
+ */
+struct Parser::Action
+{
+ /**
+ * @brief Called by Parser::workhorse() for each Option that has been successfully
+ * parsed (including unknown
+ * options if they have a Descriptor whose Descriptor::check_arg does not return
+ * @ref ARG_ILLEGAL.
+ *
+ * Returns @c false iff a fatal error has occured and the parse should be aborted.
+ */
+ virtual bool perform(Option&)
+ {
+ return true;
+ }
+
+ /**
+ * @brief Called by Parser::workhorse() after finishing the parse.
+ * @param numargs the number of non-option arguments remaining
+ * @param args pointer to the first remaining non-option argument (if numargs > 0).
+ *
+ * @return
+ * @c false iff a fatal error has occurred.
+ */
+ virtual bool finished(int numargs, const char** args)
+ {
+ (void) numargs;
+ (void) args;
+ return true;
+ }
+};
+
+/**
+ * @internal
+ * @brief An Action to pass to Parser::workhorse() that will increment a counter for
+ * each parsed Option.
+ */
+class Stats::CountOptionsAction: public Parser::Action
+{
+ unsigned* buffer_max;
+public:
+ /**
+ * Creates a new CountOptionsAction that will increase @c *buffer_max_ for each
+ * parsed Option.
+ */
+ CountOptionsAction(unsigned* buffer_max_) :
+ buffer_max(buffer_max_)
+ {
+ }
+
+ bool perform(Option&)
+ {
+ if (*buffer_max == 0x7fffffff)
+ return false; // overflow protection: don't accept number of options that doesn't fit signed int
+ ++*buffer_max;
+ return true;
+ }
+};
+
+/**
+ * @internal
+ * @brief An Action to pass to Parser::workhorse() that will store each parsed Option in
+ * appropriate arrays (see Parser::parse()).
+ */
+class Parser::StoreOptionAction: public Parser::Action
+{
+ Parser& parser;
+ Option* options;
+ Option* buffer;
+ int bufmax; //! Number of slots in @c buffer. @c -1 means "large enough".
+public:
+ /**
+ * @brief Creates a new StoreOption action.
+ * @param parser_ the parser whose op_count should be updated.
+ * @param options_ each Option @c o is chained into the linked list @c options_[o.desc->index]
+ * @param buffer_ each Option is appended to this array as long as there's a free slot.
+ * @param bufmax_ number of slots in @c buffer_. @c -1 means "large enough".
+ */
+ StoreOptionAction(Parser& parser_, Option options_[], Option buffer_[], int bufmax_) :
+ parser(parser_), options(options_), buffer(buffer_), bufmax(bufmax_)
+ {
+ // find first empty slot in buffer (if any)
+ int bufidx = 0;
+ while ((bufmax < 0 || bufidx < bufmax) && buffer[bufidx])
+ ++bufidx;
+
+ // set parser's optionCount
+ parser.op_count = bufidx;
+ }
+
+ bool perform(Option& option)
+ {
+ if (bufmax < 0 || parser.op_count < bufmax)
+ {
+ if (parser.op_count == 0x7fffffff)
+ return false; // overflow protection: don't accept number of options that doesn't fit signed int
+
+ buffer[parser.op_count] = option;
+ int idx = buffer[parser.op_count].desc->index;
+ if (options[idx])
+ options[idx].append(buffer[parser.op_count]);
+ else
+ options[idx] = buffer[parser.op_count];
+ ++parser.op_count;
+ }
+ return true; // NOTE: an option that is discarded because of a full buffer is not fatal
+ }
+
+ bool finished(int numargs, const char** args)
+ {
+ // only overwrite non-option argument list if there's at least 1
+ // new non-option argument. Otherwise we keep the old list. This
+ // makes it easy to use default non-option arguments.
+ if (numargs > 0)
+ {
+ parser.nonop_count = numargs;
+ parser.nonop_args = args;
+ }
+
+ return true;
+ }
+};
+
+inline void Parser::parse(bool gnu, const Descriptor usage[], int argc, const char** argv, Option options[],
+ Option buffer[], int min_abbr_len, bool single_minus_longopt, int bufmax)
+{
+ StoreOptionAction action(*this, options, buffer, bufmax);
+ err = !workhorse(gnu, usage, argc, argv, action, single_minus_longopt, true, min_abbr_len);
+}
+
+inline void Stats::add(bool gnu, const Descriptor usage[], int argc, const char** argv, int min_abbr_len,
+ bool single_minus_longopt)
+{
+ // determine size of options array. This is the greatest index used in the usage + 1
+ int i = 0;
+ while (usage[i].shortopt != 0)
+ {
+ if (usage[i].index + 1 >= options_max)
+ options_max = (usage[i].index + 1) + 1; // 1 more than necessary as sentinel
+
+ ++i;
+ }
+
+ CountOptionsAction action(&buffer_max);
+ Parser::workhorse(gnu, usage, argc, argv, action, single_minus_longopt, false, min_abbr_len);
+}
+
+inline bool Parser::workhorse(bool gnu, const Descriptor usage[], int numargs, const char** args, Action& action,
+ bool single_minus_longopt, bool print_errors, int min_abbr_len)
+{
+ // protect against NULL pointer
+ if (args == 0)
+ numargs = 0;
+
+ int nonops = 0;
+
+ while (numargs != 0 && *args != 0)
+ {
+ const char* param = *args; // param can be --long-option, -srto or non-option argument
+
+ // in POSIX mode the first non-option argument terminates the option list
+ // a lone minus character is a non-option argument
+ if (param[0] != '-' || param[1] == 0)
+ {
+ if (gnu)
+ {
+ ++nonops;
+ ++args;
+ if (numargs > 0)
+ --numargs;
+ continue;
+ }
+ else
+ break;
+ }
+
+ // -- terminates the option list. The -- itself is skipped.
+ if (param[1] == '-' && param[2] == 0)
+ {
+ shift(args, nonops);
+ ++args;
+ if (numargs > 0)
+ --numargs;
+ break;
+ }
+
+ bool handle_short_options;
+ const char* longopt_name;
+ if (param[1] == '-') // if --long-option
+ {
+ handle_short_options = false;
+ longopt_name = param + 2;
+ }
+ else
+ {
+ handle_short_options = true;
+ longopt_name = param + 1; //for testing a potential -long-option
+ }
+
+ bool try_single_minus_longopt = single_minus_longopt;
+ bool have_more_args = (numargs > 1 || numargs < 0); // is referencing argv[1] valid?
+
+ do // loop over short options in group, for long options the body is executed only once
+ {
+ int idx;
+
+ const char* optarg;
+
+ /******************** long option **********************/
+ if (handle_short_options == false || try_single_minus_longopt)
+ {
+ idx = 0;
+ while (usage[idx].longopt != 0 && !streq(usage[idx].longopt, longopt_name))
+ ++idx;
+
+ if (usage[idx].longopt == 0 && min_abbr_len > 0) // if we should try to match abbreviated long options
+ {
+ int i1 = 0;
+ while (usage[i1].longopt != 0 && !streqabbr(usage[i1].longopt, longopt_name, min_abbr_len))
+ ++i1;
+ if (usage[i1].longopt != 0)
+ { // now test if the match is unambiguous by checking for another match
+ int i2 = i1 + 1;
+ while (usage[i2].longopt != 0 && !streqabbr(usage[i2].longopt, longopt_name, min_abbr_len))
+ ++i2;
+
+ if (usage[i2].longopt == 0) // if there was no second match it's unambiguous, so accept i1 as idx
+ idx = i1;
+ }
+ }
+
+ // if we found something, disable handle_short_options (only relevant if single_minus_longopt)
+ if (usage[idx].longopt != 0)
+ handle_short_options = false;
+
+ try_single_minus_longopt = false; // prevent looking for longopt in the middle of shortopt group
+
+ optarg = longopt_name;
+ while (*optarg != 0 && *optarg != '=')
+ ++optarg;
+ if (*optarg == '=') // attached argument
+ ++optarg;
+ else
+ // possibly detached argument
+ optarg = (have_more_args ? args[1] : 0);
+ }
+
+ /************************ short option ***********************************/
+ if (handle_short_options)
+ {
+ if (*++param == 0) // point at the 1st/next option character
+ break; // end of short option group
+
+ idx = 0;
+ while (usage[idx].shortopt != 0 && !instr(*param, usage[idx].shortopt))
+ ++idx;
+
+ if (param[1] == 0) // if the potential argument is separate
+ optarg = (have_more_args ? args[1] : 0);
+ else
+ // if the potential argument is attached
+ optarg = param + 1;
+ }
+
+ const Descriptor* descriptor = &usage[idx];
+
+ if (descriptor->shortopt == 0) /************** unknown option ********************/
+ {
+ // look for dummy entry (shortopt == "" and longopt == "") to use as Descriptor for unknown options
+ idx = 0;
+ while (usage[idx].shortopt != 0 && (usage[idx].shortopt[0] != 0 || usage[idx].longopt[0] != 0))
+ ++idx;
+ descriptor = (usage[idx].shortopt == 0 ? 0 : &usage[idx]);
+ }
+
+ if (descriptor != 0)
+ {
+ Option option(descriptor, param, optarg);
+ switch (descriptor->check_arg(option, print_errors))
+ {
+ case ARG_ILLEGAL:
+ return false; // fatal
+ case ARG_OK:
+ // skip one element of the argument vector, if it's a separated argument
+ if (optarg != 0 && have_more_args && optarg == args[1])
+ {
+ shift(args, nonops);
+ if (numargs > 0)
+ --numargs;
+ ++args;
+ }
+
+ // No further short options are possible after an argument
+ handle_short_options = false;
+
+ break;
+ case ARG_IGNORE:
+ case ARG_NONE:
+ option.arg = 0;
+ break;
+ }
+
+ if (!action.perform(option))
+ return false;
+ }
+
+ } while (handle_short_options);
+
+ shift(args, nonops);
+ ++args;
+ if (numargs > 0)
+ --numargs;
+
+ } // while
+
+ if (numargs > 0 && *args == 0) // It's a bug in the caller if numargs is greater than the actual number
+ numargs = 0; // of arguments, but as a service to the user we fix this if we spot it.
+
+ if (numargs < 0) // if we don't know the number of remaining non-option arguments
+ { // we need to count them
+ numargs = 0;
+ while (args[numargs] != 0)
+ ++numargs;
+ }
+
+ return action.finished(numargs + nonops, args - nonops);
+}
+
+/**
+ * @internal
+ * @brief The implementation of option::printUsage().
+ */
+struct PrintUsageImplementation
+{
+ /**
+ * @internal
+ * @brief Interface for Functors that write (part of) a string somewhere.
+ */
+ struct IStringWriter
+ {
+ /**
+ * @brief Writes the given number of chars beginning at the given pointer somewhere.
+ */
+ virtual void operator()(const char*, int)
+ {
+ }
+ };
+
+ /**
+ * @internal
+ * @brief Encapsulates a function with signature <code>func(string, size)</code> where
+ * string can be initialized with a const char* and size with an int.
+ */
+ template<typename Function>
+ struct FunctionWriter: public IStringWriter
+ {
+ Function* write;
+
+ virtual void operator()(const char* str, int size)
+ {
+ (*write)(str, size);
+ }
+
+ FunctionWriter(Function* w) :
+ write(w)
+ {
+ }
+ };
+
+ /**
+ * @internal
+ * @brief Encapsulates a reference to an object with a <code>write(string, size)</code>
+ * method like that of @c std::ostream.
+ */
+ template<typename OStream>
+ struct OStreamWriter: public IStringWriter
+ {
+ OStream& ostream;
+
+ virtual void operator()(const char* str, int size)
+ {
+ ostream.write(str, size);
+ }
+
+ OStreamWriter(OStream& o) :
+ ostream(o)
+ {
+ }
+ };
+
+ /**
+ * @internal
+ * @brief Like OStreamWriter but encapsulates a @c const reference, which is
+ * typically a temporary object of a user class.
+ */
+ template<typename Temporary>
+ struct TemporaryWriter: public IStringWriter
+ {
+ const Temporary& userstream;
+
+ virtual void operator()(const char* str, int size)
+ {
+ userstream.write(str, size);
+ }
+
+ TemporaryWriter(const Temporary& u) :
+ userstream(u)
+ {
+ }
+ };
+
+ /**
+ * @internal
+ * @brief Encapsulates a function with the signature <code>func(fd, string, size)</code> (the
+ * signature of the @c write() system call)
+ * where fd can be initialized from an int, string from a const char* and size from an int.
+ */
+ template<typename Syscall>
+ struct SyscallWriter: public IStringWriter
+ {
+ Syscall* write;
+ int fd;
+
+ virtual void operator()(const char* str, int size)
+ {
+ (*write)(fd, str, size);
+ }
+
+ SyscallWriter(Syscall* w, int f) :
+ write(w), fd(f)
+ {
+ }
+ };
+
+ /**
+ * @internal
+ * @brief Encapsulates a function with the same signature as @c std::fwrite().
+ */
+ template<typename Function, typename Stream>
+ struct StreamWriter: public IStringWriter
+ {
+ Function* fwrite;
+ Stream* stream;
+
+ virtual void operator()(const char* str, int size)
+ {
+ (*fwrite)(str, size, 1, stream);
+ }
+
+ StreamWriter(Function* w, Stream* s) :
+ fwrite(w), stream(s)
+ {
+ }
+ };
+
+ /**
+ * @internal
+ * @brief Sets <code> i1 = max(i1, i2) </code>
+ */
+ static void upmax(int& i1, int i2)
+ {
+ i1 = (i1 >= i2 ? i1 : i2);
+ }
+
+ /**
+ * @internal
+ * @brief Moves the "cursor" to column @c want_x assuming it is currently at column @c x
+ * and sets @c x=want_x .
+ * If <code> x > want_x </code>, a line break is output before indenting.
+ *
+ * @param write Spaces and possibly a line break are written via this functor to get
+ * the desired indentation @c want_x .
+ * @param[in,out] x the current indentation. Set to @c want_x by this method.
+ * @param want_x the desired indentation.
+ */
+ static void indent(IStringWriter& write, int& x, int want_x)
+ {
+ int indent = want_x - x;
+ if (indent < 0)
+ {
+ write("\n", 1);
+ indent = want_x;
+ }
+
+ if (indent > 0)
+ {
+ char space = ' ';
+ for (int i = 0; i < indent; ++i)
+ write(&space, 1);
+ x = want_x;
+ }
+ }
+
+ /**
+ * @brief Returns true if ch is the unicode code point of a wide character.
+ *
+ * @note
+ * The following character ranges are treated as wide
+ * @code
+ * 1100..115F
+ * 2329..232A (just 2 characters!)
+ * 2E80..A4C6 except for 303F
+ * A960..A97C
+ * AC00..D7FB
+ * F900..FAFF
+ * FE10..FE6B
+ * FF01..FF60
+ * FFE0..FFE6
+ * 1B000......
+ * @endcode
+ */
+ static bool isWideChar(unsigned ch)
+ {
+ if (ch == 0x303F)
+ return false;
+
+ return ((0x1100 <= ch && ch <= 0x115F) || (0x2329 <= ch && ch <= 0x232A) || (0x2E80 <= ch && ch <= 0xA4C6)
+ || (0xA960 <= ch && ch <= 0xA97C) || (0xAC00 <= ch && ch <= 0xD7FB) || (0xF900 <= ch && ch <= 0xFAFF)
+ || (0xFE10 <= ch && ch <= 0xFE6B) || (0xFF01 <= ch && ch <= 0xFF60) || (0xFFE0 <= ch && ch <= 0xFFE6)
+ || (0x1B000 <= ch));
+ }
+
+ /**
+ * @internal
+ * @brief Splits a @c Descriptor[] array into tables, rows, lines and columns and
+ * iterates over these components.
+ *
+ * The top-level organizational unit is the @e table.
+ * A table begins at a Descriptor with @c help!=NULL and extends up to
+ * a Descriptor with @c help==NULL.
+ *
+ * A table consists of @e rows. Due to line-wrapping and explicit breaks
+ * a row may take multiple lines on screen. Rows within the table are separated
+ * by \\n. They never cross Descriptor boundaries. This means a row ends either
+ * at \\n or the 0 at the end of the help string.
+ *
+ * A row consists of columns/cells. Columns/cells within a row are separated by \\t.
+ * Line breaks within a cell are marked by \\v.
+ *
+ * Rows in the same table need not have the same number of columns/cells. The
+ * extreme case are interjections, which are rows that contain neither \\t nor \\v.
+ * These are NOT treated specially by LinePartIterator, but they are treated
+ * specially by printUsage().
+ *
+ * LinePartIterator iterates through the usage at 3 levels: table, row and part.
+ * Tables and rows are as described above. A @e part is a line within a cell.
+ * LinePartIterator iterates through 1st parts of all cells, then through the 2nd
+ * parts of all cells (if any),... @n
+ * Example: The row <code> "1 \v 3 \t 2 \v 4" </code> has 2 cells/columns and 4 parts.
+ * The parts will be returned in the order 1, 2, 3, 4.
+ *
+ * It is possible that some cells have fewer parts than others. In this case
+ * LinePartIterator will "fill up" these cells with 0-length parts. IOW, LinePartIterator
+ * always returns the same number of parts for each column. Note that this is different
+ * from the way rows and columns are handled. LinePartIterator does @e not guarantee that
+ * the same number of columns will be returned for each row.
+ *
+ */
+ class LinePartIterator
+ {
+ const Descriptor* tablestart; //!< The 1st descriptor of the current table.
+ const Descriptor* rowdesc; //!< The Descriptor that contains the current row.
+ const char* rowstart; //!< Ptr to 1st character of current row within rowdesc->help.
+ const char* ptr; //!< Ptr to current part within the current row.
+ int col; //!< Index of current column.
+ int len; //!< Length of the current part (that ptr points at) in BYTES
+ int screenlen; //!< Length of the current part in screen columns (taking narrow/wide chars into account).
+ int max_line_in_block; //!< Greatest index of a line within the block. This is the number of \\v within the cell with the most \\vs.
+ int line_in_block; //!< Line index within the current cell of the current part.
+ int target_line_in_block; //!< Line index of the parts we should return to the user on this iteration.
+ bool hit_target_line; //!< Flag whether we encountered a part with line index target_line_in_block in the current cell.
+
+ /**
+ * @brief Determines the byte and character lengths of the part at @ref ptr and
+ * stores them in @ref len and @ref screenlen respectively.
+ */
+ void update_length()
+ {
+ screenlen = 0;
+ for (len = 0; ptr[len] != 0 && ptr[len] != '\v' && ptr[len] != '\t' && ptr[len] != '\n'; ++len)
+ {
+ ++screenlen;
+ unsigned ch = (unsigned char) ptr[len];
+ if (ch > 0xC1) // everything <= 0xC1 (yes, even 0xC1 itself) is not a valid UTF-8 start byte
+ {
+ // int __builtin_clz (unsigned int x)
+ // Returns the number of leading 0-bits in x, starting at the most significant bit
+ unsigned mask = (unsigned) -1 >> __builtin_clz(ch ^ 0xff);
+ ch = ch & mask; // mask out length bits, we don't verify their correctness
+ while (((unsigned char) ptr[len + 1] ^ 0x80) <= 0x3F) // while next byte is continuation byte
+ {
+ ch = (ch << 6) ^ (unsigned char) ptr[len + 1] ^ 0x80; // add continuation to char code
+ ++len;
+ }
+ // ch is the decoded unicode code point
+ if (ch >= 0x1100 && isWideChar(ch)) // the test for 0x1100 is here to avoid the function call in the Latin case
+ ++screenlen;
+ }
+ }
+ }
+
+ public:
+ //! @brief Creates an iterator for @c usage.
+ LinePartIterator(const Descriptor usage[]) :
+ tablestart(usage), rowdesc(0), rowstart(0), ptr(0), col(-1), len(0), max_line_in_block(0), line_in_block(0),
+ target_line_in_block(0), hit_target_line(true)
+ {
+ }
+
+ /**
+ * @brief Moves iteration to the next table (if any). Has to be called once on a new
+ * LinePartIterator to move to the 1st table.
+ * @retval false if moving to next table failed because no further table exists.
+ */
+ bool nextTable()
+ {
+ // If this is NOT the first time nextTable() is called after the constructor,
+ // then skip to the next table break (i.e. a Descriptor with help == 0)
+ if (rowdesc != 0)
+ {
+ while (tablestart->help != 0 && tablestart->shortopt != 0)
+ ++tablestart;
+ }
+
+ // Find the next table after the break (if any)
+ while (tablestart->help == 0 && tablestart->shortopt != 0)
+ ++tablestart;
+
+ restartTable();
+ return rowstart != 0;
+ }
+
+ /**
+ * @brief Reset iteration to the beginning of the current table.
+ */
+ void restartTable()
+ {
+ rowdesc = tablestart;
+ rowstart = tablestart->help;
+ ptr = 0;
+ }
+
+ /**
+ * @brief Moves iteration to the next row (if any). Has to be called once after each call to
+ * @ref nextTable() to move to the 1st row of the table.
+ * @retval false if moving to next row failed because no further row exists.
+ */
+ bool nextRow()
+ {
+ if (ptr == 0)
+ {
+ restartRow();
+ return rowstart != 0;
+ }
+
+ while (*ptr != 0 && *ptr != '\n')
+ ++ptr;
+
+ if (*ptr == 0)
+ {
+ if ((rowdesc + 1)->help == 0) // table break
+ return false;
+
+ ++rowdesc;
+ rowstart = rowdesc->help;
+ }
+ else // if (*ptr == '\n')
+ {
+ rowstart = ptr + 1;
+ }
+
+ restartRow();
+ return true;
+ }
+
+ /**
+ * @brief Reset iteration to the beginning of the current row.
+ */
+ void restartRow()
+ {
+ ptr = rowstart;
+ col = -1;
+ len = 0;
+ screenlen = 0;
+ max_line_in_block = 0;
+ line_in_block = 0;
+ target_line_in_block = 0;
+ hit_target_line = true;
+ }
+
+ /**
+ * @brief Moves iteration to the next part (if any). Has to be called once after each call to
+ * @ref nextRow() to move to the 1st part of the row.
+ * @retval false if moving to next part failed because no further part exists.
+ *
+ * See @ref LinePartIterator for details about the iteration.
+ */
+ bool next()
+ {
+ if (ptr == 0)
+ return false;
+
+ if (col == -1)
+ {
+ col = 0;
+ update_length();
+ return true;
+ }
+
+ ptr += len;
+ while (true)
+ {
+ switch (*ptr)
+ {
+ case '\v':
+ upmax(max_line_in_block, ++line_in_block);
+ ++ptr;
+ break;
+ case '\t':
+ if (!hit_target_line) // if previous column did not have the targetline
+ { // then "insert" a 0-length part
+ update_length();
+ hit_target_line = true;
+ return true;
+ }
+
+ hit_target_line = false;
+ line_in_block = 0;
+ ++col;
+ ++ptr;
+ break;
+ case 0:
+ case '\n':
+ if (!hit_target_line) // if previous column did not have the targetline
+ { // then "insert" a 0-length part
+ update_length();
+ hit_target_line = true;
+ return true;
+ }
+
+ if (++target_line_in_block > max_line_in_block)
+ {
+ update_length();
+ return false;
+ }
+
+ hit_target_line = false;
+ line_in_block = 0;
+ col = 0;
+ ptr = rowstart;
+ continue;
+ default:
+ ++ptr;
+ continue;
+ } // switch
+
+ if (line_in_block == target_line_in_block)
+ {
+ update_length();
+ hit_target_line = true;
+ return true;
+ }
+ } // while
+ }
+
+ /**
+ * @brief Returns the index (counting from 0) of the column in which
+ * the part pointed to by @ref data() is located.
+ */
+ int column()
+ {
+ return col;
+ }
+
+ /**
+ * @brief Returns the index (counting from 0) of the line within the current column
+ * this part belongs to.
+ */
+ int line()
+ {
+ return target_line_in_block; // NOT line_in_block !!! It would be wrong if !hit_target_line
+ }
+
+ /**
+ * @brief Returns the length of the part pointed to by @ref data() in raw chars (not UTF-8 characters).
+ */
+ int length()
+ {
+ return len;
+ }
+
+ /**
+ * @brief Returns the width in screen columns of the part pointed to by @ref data().
+ * Takes multi-byte UTF-8 sequences and wide characters into account.
+ */
+ int screenLength()
+ {
+ return screenlen;
+ }
+
+ /**
+ * @brief Returns the current part of the iteration.
+ */
+ const char* data()
+ {
+ return ptr;
+ }
+ };
+
+ /**
+ * @internal
+ * @brief Takes input and line wraps it, writing out one line at a time so that
+ * it can be interleaved with output from other columns.
+ *
+ * The LineWrapper is used to handle the last column of each table as well as interjections.
+ * The LineWrapper is called once for each line of output. If the data given to it fits
+ * into the designated width of the last column it is simply written out. If there
+ * is too much data, an appropriate split point is located and only the data up to this
+ * split point is written out. The rest of the data is queued for the next line.
+ * That way the last column can be line wrapped and interleaved with data from
+ * other columns. The following example makes this clearer:
+ * @code
+ * Column 1,1 Column 2,1 This is a long text
+ * Column 1,2 Column 2,2 that does not fit into
+ * a single line.
+ * @endcode
+ *
+ * The difficulty in producing this output is that the whole string
+ * "This is a long text that does not fit into a single line" is the
+ * 1st and only part of column 3. In order to produce the above
+ * output the string must be output piecemeal, interleaved with
+ * the data from the other columns.
+ */
+ class LineWrapper
+ {
+ static const int bufmask = 15; //!< Must be a power of 2 minus 1.
+ /**
+ * @brief Ring buffer for length component of pair (data, length).
+ */
+ int lenbuf[bufmask + 1];
+ /**
+ * @brief Ring buffer for data component of pair (data, length).
+ */
+ const char* datbuf[bufmask + 1];
+ /**
+ * @brief The indentation of the column to which the LineBuffer outputs. LineBuffer
+ * assumes that the indentation has already been written when @ref process()
+ * is called, so this value is only used when a buffer flush requires writing
+ * additional lines of output.
+ */
+ int x;
+ /**
+ * @brief The width of the column to line wrap.
+ */
+ int width;
+ int head; //!< @brief index for next write
+ int tail; //!< @brief index for next read - 1 (i.e. increment tail BEFORE read)
+
+ /**
+ * @brief Multiple methods of LineWrapper may decide to flush part of the buffer to
+ * free up space. The contract of process() says that only 1 line is output. So
+ * this variable is used to track whether something has output a line. It is
+ * reset at the beginning of process() and checked at the end to decide if
+ * output has already occurred or is still needed.
+ */
+ bool wrote_something;
+
+ bool buf_empty()
+ {
+ return ((tail + 1) & bufmask) == head;
+ }
+
+ bool buf_full()
+ {
+ return tail == head;
+ }
+
+ void buf_store(const char* data, int len)
+ {
+ lenbuf[head] = len;
+ datbuf[head] = data;
+ head = (head + 1) & bufmask;
+ }
+
+ //! @brief Call BEFORE reading ...buf[tail].
+ void buf_next()
+ {
+ tail = (tail + 1) & bufmask;
+ }
+
+ /**
+ * @brief Writes (data,len) into the ring buffer. If the buffer is full, a single line
+ * is flushed out of the buffer into @c write.
+ */
+ void output(IStringWriter& write, const char* data, int len)
+ {
+ if (buf_full())
+ write_one_line(write);
+
+ buf_store(data, len);
+ }
+
+ /**
+ * @brief Writes a single line of output from the buffer to @c write.
+ */
+ void write_one_line(IStringWriter& write)
+ {
+ if (wrote_something) // if we already wrote something, we need to start a new line
+ {
+ write("\n", 1);
+ int _ = 0;
+ indent(write, _, x);
+ }
+
+ if (!buf_empty())
+ {
+ buf_next();
+ write(datbuf[tail], lenbuf[tail]);
+ }
+
+ wrote_something = true;
+ }
+ public:
+
+ /**
+ * @brief Writes out all remaining data from the LineWrapper using @c write.
+ * Unlike @ref process() this method indents all lines including the first and
+ * will output a \\n at the end (but only if something has been written).
+ */
+ void flush(IStringWriter& write)
+ {
+ if (buf_empty())
+ return;
+ int _ = 0;
+ indent(write, _, x);
+ wrote_something = false;
+ while (!buf_empty())
+ write_one_line(write);
+ write("\n", 1);
+ }
+
+ /**
+ * @brief Process, wrap and output the next piece of data.
+ *
+ * process() will output at least one line of output. This is not necessarily
+ * the @c data passed in. It may be data queued from a prior call to process().
+ * If the internal buffer is full, more than 1 line will be output.
+ *
+ * process() assumes that the a proper amount of indentation has already been
+ * output. It won't write any further indentation before the 1st line. If
+ * more than 1 line is written due to buffer constraints, the lines following
+ * the first will be indented by this method, though.
+ *
+ * No \\n is written by this method after the last line that is written.
+ *
+ * @param write where to write the data.
+ * @param data the new chunk of data to write.
+ * @param len the length of the chunk of data to write.
+ */
+ void process(IStringWriter& write, const char* data, int len)
+ {
+ wrote_something = false;
+
+ while (len > 0)
+ {
+ if (len <= width) // quick test that works because utf8width <= len (all wide chars have at least 2 bytes)
+ {
+ output(write, data, len);
+ len = 0;
+ }
+ else // if (len > width) it's possible (but not guaranteed) that utf8len > width
+ {
+ int utf8width = 0;
+ int maxi = 0;
+ while (maxi < len && utf8width < width)
+ {
+ int charbytes = 1;
+ unsigned ch = (unsigned char) data[maxi];
+ if (ch > 0xC1) // everything <= 0xC1 (yes, even 0xC1 itself) is not a valid UTF-8 start byte
+ {
+ // int __builtin_clz (unsigned int x)
+ // Returns the number of leading 0-bits in x, starting at the most significant bit
+ unsigned mask = (unsigned) -1 >> __builtin_clz(ch ^ 0xff);
+ ch = ch & mask; // mask out length bits, we don't verify their correctness
+ while ((maxi + charbytes < len) && //
+ (((unsigned char) data[maxi + charbytes] ^ 0x80) <= 0x3F)) // while next byte is continuation byte
+ {
+ ch = (ch << 6) ^ (unsigned char) data[maxi + charbytes] ^ 0x80; // add continuation to char code
+ ++charbytes;
+ }
+ // ch is the decoded unicode code point
+ if (ch >= 0x1100 && isWideChar(ch)) // the test for 0x1100 is here to avoid the function call in the Latin case
+ {
+ if (utf8width + 2 > width)
+ break;
+ ++utf8width;
+ }
+ }
+ ++utf8width;
+ maxi += charbytes;
+ }
+
+ // data[maxi-1] is the last byte of the UTF-8 sequence of the last character that fits
+ // onto the 1st line. If maxi == len, all characters fit on the line.
+
+ if (maxi == len)
+ {
+ output(write, data, len);
+ len = 0;
+ }
+ else // if (maxi < len) at least 1 character (data[maxi] that is) doesn't fit on the line
+ {
+ int i;
+ for (i = maxi; i >= 0; --i)
+ if (data[i] == ' ')
+ break;
+
+ if (i >= 0)
+ {
+ output(write, data, i);
+ data += i + 1;
+ len -= i + 1;
+ }
+ else // did not find a space to split at => split before data[maxi]
+ { // data[maxi] is always the beginning of a character, never a continuation byte
+ output(write, data, maxi);
+ data += maxi;
+ len -= maxi;
+ }
+ }
+ }
+ }
+ if (!wrote_something) // if we didn't already write something to make space in the buffer
+ write_one_line(write); // write at most one line of actual output
+ }
+
+ /**
+ * @brief Constructs a LineWrapper that wraps its output to fit into
+ * screen columns @c x1 (incl.) to @c x2 (excl.).
+ *
+ * @c x1 gives the indentation LineWrapper uses if it needs to indent.
+ */
+ LineWrapper(int x1, int x2) :
+ x(x1), width(x2 - x1), head(0), tail(bufmask)
+ {
+ if (width < 2) // because of wide characters we need at least width 2 or the code breaks
+ width = 2;
+ }
+ };
+
+ /**
+ * @internal
+ * @brief This is the implementation that is shared between all printUsage() templates.
+ * Because all printUsage() templates share this implementation, there is no template bloat.
+ */
+ static void printUsage(IStringWriter& write, const Descriptor usage[], int width = 80, //
+ int last_column_min_percent = 50, int last_column_own_line_max_percent = 75)
+ {
+ if (width < 1) // protect against nonsense values
+ width = 80;
+
+ if (width > 10000) // protect against overflow in the following computation
+ width = 10000;
+
+ int last_column_min_width = ((width * last_column_min_percent) + 50) / 100;
+ int last_column_own_line_max_width = ((width * last_column_own_line_max_percent) + 50) / 100;
+ if (last_column_own_line_max_width == 0)
+ last_column_own_line_max_width = 1;
+
+ LinePartIterator part(usage);
+ while (part.nextTable())
+ {
+
+ /***************** Determine column widths *******************************/
+
+ const int maxcolumns = 8; // 8 columns are enough for everyone
+ int col_width[maxcolumns];
+ int lastcolumn;
+ int leftwidth;
+ int overlong_column_threshold = 10000;
+ do
+ {
+ lastcolumn = 0;
+ for (int i = 0; i < maxcolumns; ++i)
+ col_width[i] = 0;
+
+ part.restartTable();
+ while (part.nextRow())
+ {
+ while (part.next())
+ {
+ if (part.column() < maxcolumns)
+ {
+ upmax(lastcolumn, part.column());
+ if (part.screenLength() < overlong_column_threshold)
+ // We don't let rows that don't use table separators (\t or \v) influence
+ // the width of column 0. This allows the user to interject section headers
+ // or explanatory paragraphs that do not participate in the table layout.
+ if (part.column() > 0 || part.line() > 0 || part.data()[part.length()] == '\t'
+ || part.data()[part.length()] == '\v')
+ upmax(col_width[part.column()], part.screenLength());
+ }
+ }
+ }
+
+ /*
+ * If the last column doesn't fit on the same
+ * line as the other columns, we can fix that by starting it on its own line.
+ * However we can't do this for any of the columns 0..lastcolumn-1.
+ * If their sum exceeds the maximum width we try to fix this by iteratively
+ * ignoring the widest line parts in the width determination until
+ * we arrive at a series of column widths that fit into one line.
+ * The result is a layout where everything is nicely formatted
+ * except for a few overlong fragments.
+ * */
+
+ leftwidth = 0;
+ overlong_column_threshold = 0;
+ for (int i = 0; i < lastcolumn; ++i)
+ {
+ leftwidth += col_width[i];
+ upmax(overlong_column_threshold, col_width[i]);
+ }
+
+ } while (leftwidth > width);
+
+ /**************** Determine tab stops and last column handling **********************/
+
+ int tabstop[maxcolumns];
+ tabstop[0] = 0;
+ for (int i = 1; i < maxcolumns; ++i)
+ tabstop[i] = tabstop[i - 1] + col_width[i - 1];
+
+ int rightwidth = width - tabstop[lastcolumn];
+ bool print_last_column_on_own_line = false;
+ if (rightwidth < last_column_min_width && // if we don't have the minimum requested width for the last column
+ ( col_width[lastcolumn] == 0 || // and all last columns are > overlong_column_threshold
+ rightwidth < col_width[lastcolumn] // or there is at least one last column that requires more than the space available
+ )
+ )
+ {
+ print_last_column_on_own_line = true;
+ rightwidth = last_column_own_line_max_width;
+ }
+
+ // If lastcolumn == 0 we must disable print_last_column_on_own_line because
+ // otherwise 2 copies of the last (and only) column would be output.
+ // Actually this is just defensive programming. It is currently not
+ // possible that lastcolumn==0 and print_last_column_on_own_line==true
+ // at the same time, because lastcolumn==0 => tabstop[lastcolumn] == 0 =>
+ // rightwidth==width => rightwidth>=last_column_min_width (unless someone passes
+ // a bullshit value >100 for last_column_min_percent) => the above if condition
+ // is false => print_last_column_on_own_line==false
+ if (lastcolumn == 0)
+ print_last_column_on_own_line = false;
+
+ LineWrapper lastColumnLineWrapper(width - rightwidth, width);
+ LineWrapper interjectionLineWrapper(0, width);
+
+ part.restartTable();
+
+ /***************** Print out all rows of the table *************************************/
+
+ while (part.nextRow())
+ {
+ int x = -1;
+ while (part.next())
+ {
+ if (part.column() > lastcolumn)
+ continue; // drop excess columns (can happen if lastcolumn == maxcolumns-1)
+
+ if (part.column() == 0)
+ {
+ if (x >= 0)
+ write("\n", 1);
+ x = 0;
+ }
+
+ indent(write, x, tabstop[part.column()]);
+
+ if ((part.column() < lastcolumn)
+ && (part.column() > 0 || part.line() > 0 || part.data()[part.length()] == '\t'
+ || part.data()[part.length()] == '\v'))
+ {
+ write(part.data(), part.length());
+ x += part.screenLength();
+ }
+ else // either part.column() == lastcolumn or we are in the special case of
+ // an interjection that doesn't contain \v or \t
+ {
+ // NOTE: This code block is not necessarily executed for
+ // each line, because some rows may have fewer columns.
+
+ LineWrapper& lineWrapper = (part.column() == 0) ? interjectionLineWrapper : lastColumnLineWrapper;
+
+ if (!print_last_column_on_own_line || part.column() != lastcolumn)
+ lineWrapper.process(write, part.data(), part.length());
+ }
+ } // while
+
+ if (print_last_column_on_own_line)
+ {
+ part.restartRow();
+ while (part.next())
+ {
+ if (part.column() == lastcolumn)
+ {
+ write("\n", 1);
+ int _ = 0;
+ indent(write, _, width - rightwidth);
+ lastColumnLineWrapper.process(write, part.data(), part.length());
+ }
+ }
+ }
+
+ write("\n", 1);
+ lastColumnLineWrapper.flush(write);
+ interjectionLineWrapper.flush(write);
+ }
+ }
+ }
+
+}
+;
+
+/**
+ * @brief Outputs a nicely formatted usage string with support for multi-column formatting
+ * and line-wrapping.
+ *
+ * printUsage() takes the @c help texts of a Descriptor[] array and formats them into
+ * a usage message, wrapping lines to achieve the desired output width.
+ *
+ * <b>Table formatting:</b>
+ *
+ * Aside from plain strings which are simply line-wrapped, the usage may contain tables. Tables
+ * are used to align elements in the output.
+ *
+ * @code
+ * // Without a table. The explanatory texts are not aligned.
+ * -c, --create |Creates something.
+ * -k, --kill |Destroys something.
+ *
+ * // With table formatting. The explanatory texts are aligned.
+ * -c, --create |Creates something.
+ * -k, --kill |Destroys something.
+ * @endcode
+ *
+ * Table formatting removes the need to pad help texts manually with spaces to achieve
+ * alignment. To create a table, simply insert \\t (tab) characters to separate the cells
+ * within a row.
+ *
+ * @code
+ * const option::Descriptor usage[] = {
+ * {..., "-c, --create \tCreates something." },
+ * {..., "-k, --kill \tDestroys something." }, ...
+ * @endcode
+ *
+ * Note that you must include the minimum amount of space desired between cells yourself.
+ * Table formatting will insert further spaces as needed to achieve alignment.
+ *
+ * You can insert line breaks within cells by using \\v (vertical tab).
+ *
+ * @code
+ * const option::Descriptor usage[] = {
+ * {..., "-c,\v--create \tCreates\vsomething." },
+ * {..., "-k,\v--kill \tDestroys\vsomething." }, ...
+ *
+ * // results in
+ *
+ * -c, Creates
+ * --create something.
+ * -k, Destroys
+ * --kill something.
+ * @endcode
+ *
+ * You can mix lines that do not use \\t or \\v with those that do. The plain
+ * lines will not mess up the table layout. Alignment of the table columns will
+ * be maintained even across these interjections.
+ *
+ * @code
+ * const option::Descriptor usage[] = {
+ * {..., "-c, --create \tCreates something." },
+ * {..., "----------------------------------" },
+ * {..., "-k, --kill \tDestroys something." }, ...
+ *
+ * // results in
+ *
+ * -c, --create Creates something.
+ * ----------------------------------
+ * -k, --kill Destroys something.
+ * @endcode
+ *
+ * You can have multiple tables within the same usage whose columns are
+ * aligned independently. Simply insert a dummy Descriptor with @c help==0.
+ *
+ * @code
+ * const option::Descriptor usage[] = {
+ * {..., "Long options:" },
+ * {..., "--very-long-option \tDoes something long." },
+ * {..., "--ultra-super-mega-long-option \tTakes forever to complete." },
+ * {..., 0 }, // ---------- table break -----------
+ * {..., "Short options:" },
+ * {..., "-s \tShort." },
+ * {..., "-q \tQuick." }, ...
+ *
+ * // results in
+ *
+ * Long options:
+ * --very-long-option Does something long.
+ * --ultra-super-mega-long-option Takes forever to complete.
+ * Short options:
+ * -s Short.
+ * -q Quick.
+ *
+ * // Without the table break it would be
+ *
+ * Long options:
+ * --very-long-option Does something long.
+ * --ultra-super-mega-long-option Takes forever to complete.
+ * Short options:
+ * -s Short.
+ * -q Quick.
+ * @endcode
+ *
+ * <b>Output methods:</b>
+ *
+ * Because TheLeanMeanC++Option parser is freestanding, you have to provide the means for
+ * output in the first argument(s) to printUsage(). Because printUsage() is implemented as
+ * a set of template functions, you have great flexibility in your choice of output
+ * method. The following example demonstrates typical uses. Anything that's similar enough
+ * will work.
+ *
+ * @code
+ * #include <unistd.h> // write()
+ * #include <iostream> // cout
+ * #include <sstream> // ostringstream
+ * #include <cstdio> // fwrite()
+ * using namespace std;
+ *
+ * void my_write(const char* str, int size) {
+ * fwrite(str, size, 1, stdout);
+ * }
+ *
+ * struct MyWriter {
+ * void write(const char* buf, size_t size) const {
+ * fwrite(str, size, 1, stdout);
+ * }
+ * };
+ *
+ * struct MyWriteFunctor {
+ * void operator()(const char* buf, size_t size) {
+ * fwrite(str, size, 1, stdout);
+ * }
+ * };
+ * ...
+ * printUsage(my_write, usage); // custom write function
+ * printUsage(MyWriter(), usage); // temporary of a custom class
+ * MyWriter writer;
+ * printUsage(writer, usage); // custom class object
+ * MyWriteFunctor wfunctor;
+ * printUsage(&wfunctor, usage); // custom functor
+ * printUsage(write, 1, usage); // write() to file descriptor 1
+ * printUsage(cout, usage); // an ostream&
+ * printUsage(fwrite, stdout, usage); // fwrite() to stdout
+ * ostringstream sstr;
+ * printUsage(sstr, usage); // an ostringstream&
+ *
+ * @endcode
+ *
+ * @par Notes:
+ * @li the @c write() method of a class that is to be passed as a temporary
+ * as @c MyWriter() is in the example, must be a @c const method, because
+ * temporary objects are passed as const reference. This only applies to
+ * temporary objects that are created and destroyed in the same statement.
+ * If you create an object like @c writer in the example, this restriction
+ * does not apply.
+ * @li a functor like @c MyWriteFunctor in the example must be passed as a pointer.
+ * This differs from the way functors are passed to e.g. the STL algorithms.
+ * @li All printUsage() templates are tiny wrappers around a shared non-template implementation.
+ * So there's no penalty for using different versions in the same program.
+ * @li printUsage() always interprets Descriptor::help as UTF-8 and always produces UTF-8-encoded
+ * output. If your system uses a different charset, you must do your own conversion. You
+ * may also need to change the font of the console to see non-ASCII characters properly.
+ * This is particularly true for Windows.
+ * @li @b Security @b warning: Do not insert untrusted strings (such as user-supplied arguments)
+ * into the usage. printUsage() has no protection against malicious UTF-8 sequences.
+ *
+ * @param prn The output method to use. See the examples above.
+ * @param usage the Descriptor[] array whose @c help texts will be formatted.
+ * @param width the maximum number of characters per output line. Note that this number is
+ * in actual characters, not bytes. printUsage() supports UTF-8 in @c help and will
+ * count multi-byte UTF-8 sequences properly. Asian wide characters are counted
+ * as 2 characters.
+ * @param last_column_min_percent (0-100) The minimum percentage of @c width that should be available
+ * for the last column (which typically contains the textual explanation of an option).
+ * If less space is available, the last column will be printed on its own line, indented
+ * according to @c last_column_own_line_max_percent.
+ * @param last_column_own_line_max_percent (0-100) If the last column is printed on its own line due to
+ * less than @c last_column_min_percent of the width being available, then only
+ * @c last_column_own_line_max_percent of the extra line(s) will be used for the
+ * last column's text. This ensures an indentation. See example below.
+ *
+ * @code
+ * // width=20, last_column_min_percent=50 (i.e. last col. min. width=10)
+ * --3456789 1234567890
+ * 1234567890
+ *
+ * // width=20, last_column_min_percent=75 (i.e. last col. min. width=15)
+ * // last_column_own_line_max_percent=75
+ * --3456789
+ * 123456789012345
+ * 67890
+ *
+ * // width=20, last_column_min_percent=75 (i.e. last col. min. width=15)
+ * // last_column_own_line_max_percent=33 (i.e. max. 5)
+ * --3456789
+ * 12345
+ * 67890
+ * 12345
+ * 67890
+ * @endcode
+ */
+template<typename OStream>
+void printUsage(OStream& prn, const Descriptor usage[], int width = 80, int last_column_min_percent = 50,
+ int last_column_own_line_max_percent = 75)
+{
+ PrintUsageImplementation::OStreamWriter<OStream> write(prn);
+ PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent);
+}
+
+template<typename Function>
+void printUsage(Function* prn, const Descriptor usage[], int width = 80, int last_column_min_percent = 50,
+ int last_column_own_line_max_percent = 75)
+{
+ PrintUsageImplementation::FunctionWriter<Function> write(prn);
+ PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent);
+}
+
+template<typename Temporary>
+void printUsage(const Temporary& prn, const Descriptor usage[], int width = 80, int last_column_min_percent = 50,
+ int last_column_own_line_max_percent = 75)
+{
+ PrintUsageImplementation::TemporaryWriter<Temporary> write(prn);
+ PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent);
+}
+
+template<typename Syscall>
+void printUsage(Syscall* prn, int fd, const Descriptor usage[], int width = 80, int last_column_min_percent = 50,
+ int last_column_own_line_max_percent = 75)
+{
+ PrintUsageImplementation::SyscallWriter<Syscall> write(prn, fd);
+ PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent);
+}
+
+template<typename Function, typename Stream>
+void printUsage(Function* prn, Stream* stream, const Descriptor usage[], int width = 80, int last_column_min_percent =
+ 50,
+ int last_column_own_line_max_percent = 75)
+{
+ PrintUsageImplementation::StreamWriter<Function, Stream> write(prn, stream);
+ PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent);
+}
+
+}
+// namespace option
+
+#endif /* OPTIONPARSER_H_ */
--- /dev/null
+/*
+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/>.
+*/
+
+#include "User/Account.h"
+#include "Utils/binio.h"
+#include "MacCompatibility.h"
+#include <fstream>
+#include "string.h"
+#include <iostream>
+
+using namespace std;
+
+extern bool devtools;
+
+vector<Account> Account::accounts;
+int Account::i_active = -1;
+
+Account::Account(const string& name) : name(name), campaignProgress()
+{
+ difficulty = 0;
+ progress = 0;
+ points = 0;
+ memset(highscore, 0, sizeof(highscore));
+ memset(fasttime, 0, sizeof(fasttime));
+ memset(unlocked, 0, sizeof(unlocked));
+
+ setCurrentCampaign("main");
+}
+
+Account::Account(FILE* tfile) : Account("")
+{
+ funpackf(tfile, "Bi", &difficulty);
+ funpackf(tfile, "Bi", &progress);
+ int nbCampaigns;
+ funpackf(tfile, "Bi", &nbCampaigns);
+
+ for (int k = 0; k < nbCampaigns; ++k) {
+ string campaignName = "";
+ int t;
+ char c;
+ funpackf(tfile, "Bi", &t);
+ for (int j = 0; j < t; j++) {
+ funpackf(tfile, "Bb", &c);
+ campaignName.append(1, c);
+ }
+ funpackf(tfile, "Bf", &(campaignProgress[campaignName].time));
+ funpackf(tfile, "Bf", &(campaignProgress[campaignName].score));
+ funpackf(tfile, "Bf", &(campaignProgress[campaignName].fasttime));
+ funpackf(tfile, "Bf", &(campaignProgress[campaignName].highscore));
+ int campaignchoicesmade, campaignchoice;
+ funpackf(tfile, "Bi", &campaignchoicesmade);
+ for (int j = 0; j < campaignchoicesmade; j++) {
+ funpackf(tfile, "Bi", &campaignchoice);
+ if (campaignchoice >= 10) { // what is that for?
+ campaignchoice = 0;
+ }
+ campaignProgress[campaignName].choices.push_back(campaignchoice);
+ }
+ }
+
+ currentCampaign = "";
+ int t;
+ char c;
+ funpackf(tfile, "Bi", &t);
+ for (int i = 0; i < t; i++) {
+ funpackf(tfile, "Bb", &c);
+ currentCampaign.append(1, c);
+ }
+
+ funpackf(tfile, "Bf", &points);
+ for (int i = 0; i < 50; i++) {
+ funpackf(tfile, "Bf", &(highscore[i]));
+ funpackf(tfile, "Bf", &(fasttime[i]));
+ }
+ for (int i = 0; i < 60; i++) {
+ funpackf(tfile, "Bb", &(unlocked[i]));
+ }
+ int temp;
+ char ctemp;
+ funpackf(tfile, "Bi", &temp);
+ for (int i = 0; i < temp; i++) {
+ funpackf(tfile, "Bb", &ctemp);
+ name.append(1, ctemp);
+ }
+ if (name.empty()) {
+ name = "Lugaru Player"; // no empty player name security.
+ }
+}
+
+void Account::save(FILE* tfile)
+{
+ fpackf(tfile, "Bi", difficulty);
+ fpackf(tfile, "Bi", progress);
+ fpackf(tfile, "Bi", campaignProgress.size());
+
+ map<string, CampaignProgress>::const_iterator it;
+ for (it = campaignProgress.begin(); it != campaignProgress.end(); ++it) {
+ fpackf(tfile, "Bi", it->first.size());
+ for (unsigned j = 0; j < it->first.size(); j++) {
+ fpackf(tfile, "Bb", it->first[j]);
+ }
+ fpackf(tfile, "Bf", it->second.time);
+ fpackf(tfile, "Bf", it->second.score);
+ fpackf(tfile, "Bf", it->second.fasttime);
+ fpackf(tfile, "Bf", it->second.highscore);
+ fpackf(tfile, "Bi", it->second.choices.size());
+ for (unsigned j = 0; j < it->second.choices.size(); j++) {
+ fpackf(tfile, "Bi", it->second.choices[j]);
+ }
+ }
+
+ fpackf(tfile, "Bi", getCurrentCampaign().size());
+ for (unsigned j = 0; j < getCurrentCampaign().size(); j++) {
+ fpackf(tfile, "Bb", getCurrentCampaign()[j]);
+ }
+
+ fpackf(tfile, "Bf", points);
+ for (unsigned j = 0; j < 50; j++) {
+ fpackf(tfile, "Bf", highscore[j]);
+ fpackf(tfile, "Bf", fasttime[j]);
+ }
+ for (unsigned j = 0; j < 60; j++) {
+ fpackf(tfile, "Bb", unlocked[j]);
+ }
+ fpackf(tfile, "Bi", name.size());
+ for (unsigned j = 0; j < name.size(); j++) {
+ fpackf(tfile, "Bb", name[j]);
+ }
+}
+
+void Account::setCurrentCampaign(const string& name)
+{
+ currentCampaign = name;
+}
+
+void Account::add(const string& name)
+{
+ accounts.emplace_back(name);
+ i_active = accounts.size() - 1;
+}
+
+Account& Account::get(int i)
+{
+ return accounts.at(i);
+}
+
+int Account::getNbAccounts()
+{
+ return accounts.size();
+}
+
+bool Account::hasActive()
+{
+ return (i_active >= 0);
+}
+
+Account& Account::active()
+{
+ return accounts.at(i_active);
+}
+
+void Account::setActive(int i)
+{
+ if ((i >= 0) && (i < int(accounts.size()))) {
+ i_active = i;
+ } else {
+ cerr << "Tried to set active account to " << i << " but there is not such account" << endl;
+ i_active = -1;
+ }
+}
+
+void Account::destroyActive()
+{
+ if ((i_active >= 0) && (i_active < int(accounts.size()))) {
+ accounts.erase(accounts.begin() + i_active);
+ i_active = -1;
+ } else {
+ cerr << "Tried to destroy active account " << i_active << " but there is not such account" << endl;
+ i_active = -1;
+ }
+}
+
+int Account::getDifficulty()
+{
+ return difficulty;
+}
+
+void Account::endGame()
+{
+ campaignProgress[currentCampaign].choices.clear();
+ campaignProgress[currentCampaign].score = 0;
+ campaignProgress[currentCampaign].time = 0;
+}
+
+void Account::winCampaignLevel(int choice, float score, float time)
+{
+ campaignProgress[currentCampaign].choices.push_back(choice);
+ setCampaignScore(campaignProgress[currentCampaign].score + score);
+ campaignProgress[currentCampaign].time = time;
+}
+
+void Account::winLevel(int level, float score, float time)
+{
+ if (!devtools) {
+ if (score > highscore[level])
+ highscore[level] = score;
+ if (time < fasttime[level] || fasttime[level] == 0)
+ fasttime[level] = time;
+ }
+ if (progress < level + 1)
+ progress = level + 1;
+}
+
+void Account::loadFile(string filename)
+{
+ FILE *tfile;
+ int numaccounts;
+ int iactive;
+ errno = 0;
+
+ tfile = fopen(filename.c_str(), "rb" );
+
+ if (tfile) {
+ funpackf(tfile, "Bi", &numaccounts);
+ funpackf(tfile, "Bi", &iactive);
+ printf("Loading %d accounts\n", numaccounts);
+ for (int i = 0; i < numaccounts; i++) {
+ printf("Loading account %d/%d\n", i, numaccounts);
+ accounts.emplace_back(tfile);
+ }
+
+ fclose(tfile);
+ setActive(iactive);
+ } else {
+ perror(("Couldn't load users from " + filename).c_str());
+ i_active = -1;
+ }
+}
+
+void Account::saveFile(string filename)
+{
+ FILE *tfile;
+ errno = 0;
+
+ tfile = fopen(filename.c_str(), "wb" );
+ if (tfile) {
+ fpackf(tfile, "Bi", getNbAccounts());
+ fpackf(tfile, "Bi", i_active);
+
+ for (int i = 0; i < getNbAccounts(); i++) {
+ printf("writing account %d/%d (%s)\n", i + 1, getNbAccounts(), accounts[i].getName().c_str());
+ accounts[i].save(tfile);
+ }
+
+ fclose(tfile);
+ } else {
+ perror(("Couldn't save users in " + filename).c_str());
+ }
+}
--- /dev/null
+/*
+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 _Account_H_
+#define _Account_H_
+
+#include <vector>
+#include <string>
+#include <map>
+#include <fstream>
+
+struct CampaignProgress {
+ float highscore;
+ float fasttime;
+ float score;
+ float time;
+ std::vector<int> choices;
+ CampaignProgress() {
+ highscore = 0;
+ fasttime = 0;
+ score = 0;
+ time = 0;
+ }
+};
+
+class Account
+{
+public:
+ static void destroyActive();
+ static void setActive(int i);
+ static void add(const std::string& name);
+ static Account& get(int i);
+ static void loadFile(std::string filename);
+ static void saveFile(std::string filename);
+ static int getNbAccounts();
+
+ static bool hasActive();
+ static Account& active();
+
+ Account(const std::string& name = "");
+ Account(FILE* tfile);
+
+ void endGame();
+ void winCampaignLevel(int choice, float score, float time);
+ void winLevel(int level, float score, float time);
+
+ // getter and setters
+ int getDifficulty();
+ void setDifficulty(int i) {
+ difficulty = i;
+ };
+ const std::string& getName() {
+ return name;
+ };
+ float getCampaignScore() {
+ return campaignProgress[currentCampaign].score;
+ };
+ int getCampaignChoicesMade() {
+ return campaignProgress[currentCampaign].choices.size();
+ };
+ int getCampaignChoice(int i) {
+ return campaignProgress[currentCampaign].choices[i];
+ };
+ void setCampaignScore(int s) {
+ campaignProgress[currentCampaign].score = s;
+ if (s > campaignProgress[currentCampaign].highscore)
+ campaignProgress[currentCampaign].highscore = s;
+ };
+ void setCampaignFinalTime(float t) {
+ campaignProgress[currentCampaign].time = t;
+ if ((t < campaignProgress[currentCampaign].fasttime) || ((campaignProgress[currentCampaign].fasttime == 0) && (t != 0)))
+ campaignProgress[currentCampaign].fasttime = t;
+ };
+ float getCampaignFasttime() {
+ return campaignProgress[currentCampaign].fasttime;
+ };
+ void resetFasttime() {
+ campaignProgress[currentCampaign].fasttime = 0;
+ };
+ float getCampaignHighScore() {
+ return campaignProgress[currentCampaign].highscore;
+ };
+ float getHighScore(int i) {
+ return highscore[i];
+ };
+ float getFastTime(int i) {
+ return fasttime[i];
+ };
+ int getProgress() {
+ return progress;
+ };
+ std::string getCurrentCampaign() {
+ return currentCampaign;
+ };
+ void setCurrentCampaign(const std::string& name);
+
+private:
+ //statics
+ static std::vector<Account> accounts;
+ static int i_active;
+
+ void save(FILE* tfile);
+
+ int difficulty;
+ int progress; // progress in challenge levels
+ float points;
+ float highscore[50];
+ float fasttime[50];
+ bool unlocked[60];
+ std::string name;
+
+ std::string currentCampaign;
+ std::map<std::string, CampaignProgress> campaignProgress;
+};
+
+#endif
--- /dev/null
+/*
+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/>.
+*/
+
+#include "Game.h"
+#include "User/Settings.h"
+#include "Utils/Folders.h"
+#include "Utils/Input.h"
+
+using namespace Game;
+
+void DefaultSettings()
+{
+ detail = 2;
+ ismotionblur = 1;
+ usermousesensitivity = 1;
+ newscreenwidth = kContextWidth = 1024;
+ newscreenheight = kContextHeight = 768;
+ fullscreen = 0;
+ floatjump = 0;
+ autoslomo = 1;
+ decals = 1;
+ invertmouse = 0;
+ bloodtoggle = 0;
+ foliage = 1;
+ musictoggle = 1;
+ trilinear = 1;
+ gamespeed = 1;
+ damageeffects = 0;
+ texttoggle = 1;
+ alwaysblur = 0;
+ showpoints = 0;
+ showdamagebar = 0;
+ immediate = 0;
+ velocityblur = 0;
+ volume = 0.8f;
+ ambientsound = 1;
+ devtools = 0;
+
+ crouchkey = SDL_SCANCODE_LSHIFT;
+ jumpkey = SDL_SCANCODE_SPACE;
+ leftkey = SDL_SCANCODE_A;
+ forwardkey = SDL_SCANCODE_W;
+ backkey = SDL_SCANCODE_S;
+ rightkey = SDL_SCANCODE_D;
+ drawkey = SDL_SCANCODE_E;
+ throwkey = SDL_SCANCODE_Q;
+ attackkey = MOUSEBUTTON1;
+ consolekey = SDL_SCANCODE_GRAVE;
+
+ newdetail = detail;
+}
+
+void SaveSettings()
+{
+ if (newdetail < 0)
+ newdetail = 0;
+ if (newdetail > 2)
+ newdetail = 2;
+ if (newscreenwidth > 3000)
+ newscreenwidth = screenwidth;
+ if (newscreenwidth < 0)
+ newscreenwidth = screenwidth;
+ if (newscreenheight > 3000)
+ newscreenheight = screenheight;
+ if (newscreenheight < 0)
+ newscreenheight = screenheight;
+ errno = 0;
+ ofstream opstream(Folders::getConfigFilePath());
+ if (opstream.fail()) {
+ perror(("Couldn't save config file " + Folders::getConfigFilePath()).c_str());
+ return;
+ }
+ opstream << "Screenwidth:\n";
+ opstream << newscreenwidth;
+ opstream << "\nScreenheight:\n";
+ opstream << newscreenheight;
+ opstream << "\nFullscreen:\n";
+ opstream << fullscreen;
+ opstream << "\nMouse sensitivity:\n";
+ opstream << usermousesensitivity;
+ opstream << "\nBlur(0,1):\n";
+ opstream << ismotionblur;
+ opstream << "\nOverall Detail(0,1,2) higher=better:\n";
+ opstream << newdetail;
+ opstream << "\nFloating jump:\n";
+ opstream << floatjump;
+ opstream << "\nMouse jump:\n";
+ opstream << mousejump;
+ opstream << "\nAmbient sound:\n";
+ opstream << ambientsound;
+ opstream << "\nBlood (0,1,2):\n";
+ opstream << bloodtoggle;
+ opstream << "\nAuto slomo:\n";
+ opstream << autoslomo;
+ opstream << "\nFoliage:\n";
+ opstream << foliage;
+ opstream << "\nMusic:\n";
+ opstream << musictoggle;
+ opstream << "\nTrilinear:\n";
+ opstream << trilinear;
+ opstream << "\nDecals(shadows,blood puddles,etc):\n";
+ opstream << decals;
+ opstream << "\nInvert mouse:\n";
+ opstream << invertmouse;
+ opstream << "\nGamespeed:\n";
+ if (oldgamespeed == 0)
+ oldgamespeed = 1;
+ opstream << oldgamespeed;
+ opstream << "\nDamage effects(blackout, doublevision):\n";
+ opstream << damageeffects;
+ opstream << "\nText:\n";
+ opstream << texttoggle;
+ opstream << "\nShow Points:\n";
+ opstream << showpoints;
+ opstream << "\nAlways Blur:\n";
+ opstream << alwaysblur;
+ opstream << "\nImmediate mode (turn on on G5):\n";
+ opstream << immediate;
+ opstream << "\nVelocity blur:\n";
+ opstream << velocityblur;
+ opstream << "\nVolume:\n";
+ opstream << volume;
+ opstream << "\nForward key:\n";
+ opstream << forwardkey;
+ opstream << "\nBack key:\n";
+ opstream << backkey;
+ opstream << "\nLeft key:\n";
+ opstream << leftkey;
+ opstream << "\nRight key:\n";
+ opstream << rightkey;
+ opstream << "\nJump key:\n";
+ opstream << jumpkey;
+ opstream << "\nCrouch key:\n";
+ opstream << crouchkey;
+ opstream << "\nDraw key:\n";
+ opstream << drawkey;
+ opstream << "\nThrow key:\n";
+ opstream << throwkey;
+ opstream << "\nAttack key:\n";
+ opstream << attackkey;
+ opstream << "\nConsole key:\n";
+ opstream << consolekey;
+ opstream << "\nDamage bar:\n";
+ opstream << showdamagebar;
+ opstream << "\nStereoMode:\n";
+ opstream << stereomode;
+ opstream << "\nStereoSeparation:\n";
+ opstream << stereoseparation;
+ opstream << "\nStereoReverse:\n";
+ opstream << stereoreverse;
+ opstream << "\n";
+ opstream.close();
+}
+
+bool LoadSettings()
+{
+ errno = 0;
+ ifstream ipstream(Folders::getConfigFilePath(), std::ios::in);
+ if ( ipstream.fail() ) {
+ perror(("Couldn't read config file " + Folders::getConfigFilePath()).c_str());
+ return false;
+ }
+ char setting[256];
+ char string[256];
+
+ printf("Loading config\n");
+ while (!ipstream.eof()) {
+ ipstream.getline( setting, sizeof(setting) );
+
+ // skip blank lines
+ // assume lines starting with spaces are all blank
+ if ( strlen(setting) == 0 || setting[0] == ' ' || setting[0] == '\t')
+ continue;
+ //~ printf("setting : %s\n",setting);
+
+ if ( ipstream.eof() || ipstream.fail() ) {
+ fprintf(stderr, "Error reading config file: Got setting name '%s', but value can't be read\n", setting);
+ ipstream.close();
+ return false;
+ }
+
+
+ if ( !strncmp(setting, "Screenwidth", 11) ) {
+ ipstream >> kContextWidth;
+ } else if ( !strncmp(setting, "Screenheight", 12) ) {
+ ipstream >> kContextHeight;
+ } else if ( !strncmp(setting, "Fullscreen", 10) ) {
+ ipstream >> fullscreen;
+ } else if ( !strncmp(setting, "Mouse sensitivity", 17) ) {
+ ipstream >> usermousesensitivity;
+ } else if ( !strncmp(setting, "Blur", 4) ) {
+ ipstream >> ismotionblur;
+ } else if ( !strncmp(setting, "Overall Detail", 14) ) {
+ ipstream >> detail;
+ } else if ( !strncmp(setting, "Floating jump", 13) ) {
+ ipstream >> floatjump;
+ } else if ( !strncmp(setting, "Mouse jump", 10) ) {
+ ipstream >> mousejump;
+ } else if ( !strncmp(setting, "Ambient sound", 13) ) {
+ ipstream >> ambientsound;
+ } else if ( !strncmp(setting, "Blood ", 6) ) {
+ ipstream >> bloodtoggle;
+ } else if ( !strncmp(setting, "Auto slomo", 10) ) {
+ ipstream >> autoslomo;
+ } else if ( !strncmp(setting, "Foliage", 7) ) {
+ ipstream >> foliage;
+ } else if ( !strncmp(setting, "Music", 5) ) {
+ ipstream >> musictoggle;
+ } else if ( !strncmp(setting, "Trilinear", 9) ) {
+ ipstream >> trilinear;
+ } else if ( !strncmp(setting, "Decals", 6) ) {
+ ipstream >> decals;
+ } else if ( !strncmp(setting, "Invert mouse", 12) ) {
+ ipstream >> invertmouse;
+ } else if ( !strncmp(setting, "Gamespeed", 9) ) {
+ ipstream >> gamespeed;
+ oldgamespeed = gamespeed;
+ if (oldgamespeed == 0) {
+ gamespeed = 1;
+ oldgamespeed = 1;
+ }
+ } else if ( !strncmp(setting, "Damage effects", 14) ) {
+ ipstream >> damageeffects;
+ } else if ( !strncmp(setting, "Text", 4) ) {
+ ipstream >> texttoggle;
+ } else if ( !strncmp(setting, "Devtools", 5) ) {
+ ipstream >> devtools;
+ } else if ( !strncmp(setting, "Show Points", 11) ) {
+ ipstream >> showpoints;
+ } else if ( !strncmp(setting, "Always Blur", 11) ) {
+ ipstream >> alwaysblur;
+ } else if ( !strncmp(setting, "Immediate mode ", 15) ) {
+ ipstream >> immediate;
+ } else if ( !strncmp(setting, "Velocity blur", 13) ) {
+ ipstream >> velocityblur;
+ } else if ( !strncmp(setting, "Volume", 6) ) {
+ ipstream >> volume;
+ } else if ( !strncmp(setting, "Forward key", 11) ) {
+ ipstream >> forwardkey;
+ } else if ( !strncmp(setting, "Back key", 8) ) {
+ ipstream >> backkey;
+ } else if ( !strncmp(setting, "Left key", 8) ) {
+ ipstream >> leftkey;
+ } else if ( !strncmp(setting, "Right key", 9) ) {
+ ipstream >> rightkey;
+ } else if ( !strncmp(setting, "Jump key", 8) ) {
+ ipstream >> jumpkey;
+ } else if ( !strncmp(setting, "Crouch key", 10) ) {
+ ipstream >> crouchkey;
+ } else if ( !strncmp(setting, "Draw key", 8) ) {
+ ipstream >> drawkey;
+ } else if ( !strncmp(setting, "Throw key", 9) ) {
+ ipstream >> throwkey;
+ } else if ( !strncmp(setting, "Attack key", 10) ) {
+ ipstream >> attackkey;
+ } else if ( !strncmp(setting, "Console key", 11) ) {
+ ipstream >> consolekey;
+ } else if ( !strncmp(setting, "Damage bar", 10) ) {
+ ipstream >> showdamagebar;
+ } else if ( !strncmp(setting, "StereoMode", 10) ) {
+ int i;
+ ipstream >> i;
+ stereomode = (StereoMode)i;
+ } else if ( !strncmp(setting, "StereoSeparation", 16) ) {
+ ipstream >> stereoseparation;
+ } else if ( !strncmp(setting, "StereoReverse", 13) ) {
+ ipstream >> stereoreverse;
+ } else {
+ ipstream >> string;
+ fprintf(stderr, "Unknown config option '%s' with value '%s'. Ignoring.\n", setting, string);
+ }
+
+ if ( ipstream.fail() ) {
+ fprintf(stderr, "Error reading config file: EOF reached when trying to read value for setting '%s'.\n", setting);
+ ipstream.close();
+ return false;
+ }
+
+ if ( ipstream.bad() ) {
+ fprintf(stderr, "Error reading config file: Failed to read value for setting '%s'.\n", setting);
+ ipstream.close();
+ return false;
+ }
+ }
+
+ ipstream.close();
+
+ if (detail > 2)
+ detail = 2;
+ if (detail < 0)
+ detail = 0;
+ if (screenwidth < 0)
+ screenwidth = 1024;
+ if (screenheight < 0)
+ screenheight = 768;
+
+ newdetail = detail;
+ return true;
+}
--- /dev/null
+/*
+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 SETTINGS_H_
+#define SETTINGS_H_
+
+#include "Game.h"
+
+extern float usermousesensitivity;
+extern bool ismotionblur;
+extern bool floatjump;
+extern bool mousejump;
+extern bool ambientsound;
+extern int bloodtoggle;
+extern bool autoslomo;
+extern bool foliage;
+extern bool musictoggle;
+extern bool trilinear;
+extern bool decals;
+extern bool invertmouse;
+extern float gamespeed;
+extern float oldgamespeed;
+extern bool damageeffects;
+extern bool texttoggle;
+extern bool devtools;
+extern bool showpoints;
+extern bool showdamagebar;
+extern bool alwaysblur;
+extern bool immediate;
+extern bool velocityblur;
+extern float volume;
+extern int detail;
+extern int kContextWidth;
+extern int kContextHeight;
+extern float screenwidth, screenheight;
+extern bool fullscreen;
+
+void DefaultSettings();
+void SaveSettings();
+bool LoadSettings();
+
+
+#endif
--- /dev/null
+/*
+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 <stdio.h>
+#include <jpeglib.h>
+#include <png.h>
+#include <zlib.h>
+
+#include "Game.h"
+#include "Utils/ImageIO.h"
+#include "Utils/Folders.h"
+
+extern bool visibleloading;
+
+/* These two are needed for screenshot */
+extern int kContextWidth;
+extern int kContextHeight;
+
+static bool load_png(const char * fname, ImageRec & tex);
+static bool load_jpg(const char * fname, ImageRec & tex);
+static bool save_screenshot_png(const char * fname);
+
+ImageRec::ImageRec()
+{
+ data = ( GLubyte* )malloc( 1024 * 1024 * 4 );
+}
+
+ImageRec::~ImageRec()
+{
+ free(data);
+ data = NULL;
+}
+
+bool load_image(const char *file_name, ImageRec &tex)
+{
+ if (visibleloading)
+ Game::LoadingScreen();
+
+ if ( tex.data == NULL )
+ return false;
+
+ const char *ptr = strrchr((char *)file_name, '.');
+ if (ptr) {
+ if (strcasecmp(ptr + 1, "png") == 0)
+ return load_png(file_name, tex);
+ else if (strcasecmp(ptr + 1, "jpg") == 0)
+ return load_jpg(file_name, tex);
+ }
+
+ STUBBED("Unsupported image type");
+ return false;
+}
+
+bool save_screenshot(const char *file_name)
+{
+ const char *ptr = strrchr((char *)file_name, '.');
+ if (ptr) {
+ if (strcasecmp(ptr + 1, "png") == 0)
+ return save_screenshot_png((Folders::getScreenshotDir() + '/' + file_name).c_str());
+ }
+
+ STUBBED("Unsupported image type");
+ return false;
+}
+
+struct my_error_mgr {
+ struct jpeg_error_mgr pub; /* "public" fields */
+ jmp_buf setjmp_buffer; /* for return to caller */
+};
+typedef struct my_error_mgr * my_error_ptr;
+
+static void my_error_exit(j_common_ptr cinfo)
+{
+ struct my_error_mgr *err = (struct my_error_mgr *)cinfo->err;
+ longjmp(err->setjmp_buffer, 1);
+}
+
+/* stolen from public domain example.c code in libjpg distribution. */
+static bool load_jpg(const char *file_name, ImageRec &tex)
+{
+ struct jpeg_decompress_struct cinfo;
+ struct my_error_mgr jerr;
+ JSAMPROW buffer[1]; /* Output row buffer */
+ int row_stride; /* physical row width in output buffer */
+ FILE *infile = fopen(file_name, "rb");
+
+ if (infile == NULL)
+ return false;
+
+ cinfo.err = jpeg_std_error(&jerr.pub);
+ jerr.pub.error_exit = my_error_exit;
+ if (setjmp(jerr.setjmp_buffer)) {
+ jpeg_destroy_decompress(&cinfo);
+ fclose(infile);
+ return false;
+ }
+
+ jpeg_create_decompress(&cinfo);
+ jpeg_stdio_src(&cinfo, infile);
+ (void) jpeg_read_header(&cinfo, TRUE);
+
+ cinfo.out_color_space = JCS_RGB;
+ cinfo.quantize_colors = 0;
+ (void) jpeg_calc_output_dimensions(&cinfo);
+ (void) jpeg_start_decompress(&cinfo);
+
+ row_stride = cinfo.output_width * cinfo.output_components;
+ tex.sizeX = cinfo.output_width;
+ tex.sizeY = cinfo.output_height;
+ tex.bpp = 24;
+
+ while (cinfo.output_scanline < cinfo.output_height) {
+ buffer[0] = (JSAMPROW)(char *)tex.data +
+ ((cinfo.output_height - 1) - cinfo.output_scanline) * row_stride;
+ (void) jpeg_read_scanlines(&cinfo, buffer, 1);
+ }
+
+ (void) jpeg_finish_decompress(&cinfo);
+ jpeg_destroy_decompress(&cinfo);
+ fclose(infile);
+
+ return true;
+}
+
+/* stolen from public domain example.c code in libpng distribution. */
+static bool load_png(const char *file_name, ImageRec &tex)
+{
+ bool hasalpha = false;
+ png_structp png_ptr = NULL;
+ png_infop info_ptr = NULL;
+ png_uint_32 width, height;
+ int bit_depth, color_type, interlace_type;
+ bool retval = false;
+ png_byte **row_pointers = NULL;
+ FILE *fp = fopen(file_name, "rb");
+
+ if (fp == NULL) {
+ cerr << file_name << " not found" << endl;
+ return false;
+ }
+
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (png_ptr == NULL)
+ goto png_done;
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (info_ptr == NULL)
+ goto png_done;
+
+ if (setjmp(png_jmpbuf(png_ptr)))
+ goto png_done;
+
+ png_init_io(png_ptr, fp);
+ png_read_png(png_ptr, info_ptr,
+ PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING,
+ NULL);
+ png_get_IHDR(png_ptr, info_ptr, &width, &height,
+ &bit_depth, &color_type, &interlace_type, NULL, NULL);
+
+ if (bit_depth != 8) // transform SHOULD handle this...
+ goto png_done;
+
+ if (color_type & PNG_COLOR_MASK_PALETTE) // !!! FIXME?
+ goto png_done;
+
+ if ((color_type & PNG_COLOR_MASK_COLOR) == 0) // !!! FIXME?
+ goto png_done;
+
+ hasalpha = ((color_type & PNG_COLOR_MASK_ALPHA) != 0);
+ row_pointers = png_get_rows(png_ptr, info_ptr);
+ if (!row_pointers)
+ goto png_done;
+
+ if (!hasalpha) {
+ png_byte *dst = tex.data;
+ for (int i = height - 1; i >= 0; i--) {
+ png_byte *src = row_pointers[i];
+ for (unsigned j = 0; j < width; j++) {
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst[3] = 0xFF;
+ src += 3;
+ dst += 4;
+ }
+ }
+ }
+
+ else {
+ png_byte *dst = tex.data;
+ int pitch = width * 4;
+ for (int i = height - 1; i >= 0; i--, dst += pitch)
+ memcpy(dst, row_pointers[i], pitch);
+ }
+
+ tex.sizeX = width;
+ tex.sizeY = height;
+ tex.bpp = 32;
+ retval = true;
+
+png_done:
+ if (!retval) {
+ cerr << "There was a problem loading " << file_name << endl;
+ }
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ if (fp)
+ fclose(fp);
+ return (retval);
+}
+
+static bool save_screenshot_png(const char *file_name)
+{
+ FILE *fp = NULL;
+ png_structp png_ptr = NULL;
+ png_infop info_ptr = NULL;
+ bool retval = false;
+
+ fp = fopen(file_name, "wb");
+ if (fp == NULL)
+ return false;
+
+ png_bytep *row_pointers = new png_bytep[kContextHeight];
+ png_bytep screenshot = new png_byte[kContextWidth * kContextHeight * 3];
+ if ((!screenshot) || (!row_pointers))
+ goto save_png_done;
+
+ glGetError();
+ glReadPixels(0, 0, kContextWidth, kContextHeight,
+ GL_RGB, GL_UNSIGNED_BYTE, screenshot);
+ if (glGetError() != GL_NO_ERROR)
+ goto save_png_done;
+
+ for (int i = 0; i < kContextHeight; i++)
+ row_pointers[i] = screenshot + ((kContextWidth * ((kContextHeight - 1) - i)) * 3);
+
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (png_ptr == NULL)
+ goto save_png_done;
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (info_ptr == NULL)
+ goto save_png_done;
+
+ if (setjmp(png_jmpbuf(png_ptr)))
+ goto save_png_done;
+
+ png_init_io(png_ptr, fp);
+
+ if (setjmp(png_jmpbuf(png_ptr)))
+ goto save_png_done;
+
+ png_set_IHDR(png_ptr, info_ptr, kContextWidth, kContextHeight,
+ 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+
+ png_write_info(png_ptr, info_ptr);
+
+ if (setjmp(png_jmpbuf(png_ptr)))
+ goto save_png_done;
+
+ png_write_image(png_ptr, row_pointers);
+
+ if (setjmp(png_jmpbuf(png_ptr)))
+ goto save_png_done;
+
+ png_write_end(png_ptr, NULL);
+ retval = true;
+
+save_png_done:
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ delete[] screenshot;
+ delete[] row_pointers;
+ if (fp)
+ fclose(fp);
+ if (!retval)
+ unlink(file_name);
+ return retval;
+}
--- /dev/null
+/*
+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 _IMAGE_IO_H_
+#define _IMAGE_IO_H_
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+
+/**> HEADER FILES <**/
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#define Polygon WinPolygon
+#include <windows.h>
+#undef Polygon
+#include "GL/gl.h"
+#else
+#include "Graphic/gamegl.h"
+#endif
+
+/**> DATA STRUCTURES <**/
+class ImageRec {
+public:
+ GLubyte *data; // Image Data (Up To 32 Bits)
+ GLuint bpp; // Image Color Depth In Bits Per Pixel.
+ GLuint sizeX;
+ GLuint sizeY;
+ ImageRec();
+ ~ImageRec();
+private:
+ /* Make sure this class cannot be copied to avoid memory problems */
+ ImageRec(ImageRec const &);
+ ImageRec& operator=(ImageRec const &);
+};
+
+bool load_image(const char * fname, ImageRec & tex);
+bool save_screenshot(const char * fname);
+
+#endif
+
--- /dev/null
+/*
+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 "Utils/Input.h"
+
+bool keyDown[SDL_NUM_SCANCODES + 6];
+bool keyPressed[SDL_NUM_SCANCODES + 6];
+
+void Input::Tick()
+{
+ SDL_PumpEvents();
+ int numkeys;
+ const Uint8 *keyState = SDL_GetKeyboardState(&numkeys);
+ for (int i = 0; i < numkeys; i++) {
+ keyPressed[i] = !keyDown[i] && keyState[i];
+ keyDown[i] = keyState[i];
+ }
+ Uint8 mb = SDL_GetMouseState(NULL, NULL);
+ for (int i = 1; i < 6; i++) {
+ keyPressed[SDL_NUM_SCANCODES + i] = !keyDown[SDL_NUM_SCANCODES + i] && (mb & SDL_BUTTON(i));
+ keyDown[SDL_NUM_SCANCODES + i] = (mb & SDL_BUTTON(i));
+ }
+}
+
+bool Input::isKeyDown(int k)
+{
+ if (k >= SDL_NUM_SCANCODES + 6) // really useful? check that.
+ return false;
+ return keyDown[k];
+}
+
+bool Input::isKeyPressed(int k)
+{
+ if (k >= SDL_NUM_SCANCODES + 6)
+ return false;
+ return keyPressed[k];
+}
+
+const char* Input::keyToChar(unsigned short i)
+{
+ if (i < SDL_NUM_SCANCODES)
+ return SDL_GetScancodeName(SDL_Scancode(i));
+ else if (i == MOUSEBUTTON1)
+ return "mouse1";
+ else if (i == MOUSEBUTTON2)
+ return "mouse2";
+ else if (i == MOUSEBUTTON3)
+ return "mouse3";
+ else
+ return "unknown";
+}
+
+unsigned short Input::CharToKey(const char* which)
+{
+ for (unsigned short i = 0; i < SDL_NUM_SCANCODES; i++) {
+ if (!strcasecmp(which, SDL_GetScancodeName(SDL_Scancode(i))))
+ return i;
+ }
+ if (!strcasecmp(which, "mouse1")) {
+ return MOUSEBUTTON1;
+ }
+ if (!strcasecmp(which, "mouse2")) {
+ return MOUSEBUTTON2;
+ }
+ if (!strcasecmp(which, "mouse3")) {
+ return MOUSEBUTTON3;
+ }
+ return SDL_NUM_SCANCODES;
+}
+
+bool Input::MouseClicked()
+{
+ return isKeyPressed(SDL_NUM_SCANCODES + SDL_BUTTON_LEFT);
+}
--- /dev/null
+/*
+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 _Input_H_
+#define _Input_H_
+
+/**> HEADER FILES <**/
+#include "SDL.h"
+#include "Game.h"
+
+/**> CONSTANT DECLARATIONS <**/
+#define MOUSEBUTTON1 (SDL_NUM_SCANCODES + SDL_BUTTON_LEFT)
+#define MOUSEBUTTON2 (SDL_NUM_SCANCODES + SDL_BUTTON_RIGHT)
+#define MOUSEBUTTON3 (SDL_NUM_SCANCODES + SDL_BUTTON_MIDDLE)
+
+/**> FUNCTION PROTOTYPES <**/
+class Input
+{
+public:
+ static void Tick();
+ static bool isKeyDown(int k);
+ static bool isKeyPressed(int k);
+ static const char* keyToChar(unsigned short which);
+ static unsigned short CharToKey(const char* which);
+ static bool MouseClicked();
+};
+
+#endif
--- /dev/null
+/*
+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 binio_h
+#define binio_h
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+ /*
+ Notes on format of format strings:
+ * whitespace is ignored
+ * each "group" consists of an optional count (defaults to 1),
+ an optional byte-order marker (defaults to H, "host-native"),
+ and a data-type specifier.
+ * when unpacking, each variable argument is a pointer to the
+ appropriate number of objects of the appropriate type.
+ * when packing, each variable argument is an object of the
+ appropriate type if the count is omitted, or a pointer to the
+ appropriate number of objects of the appropriate type if the
+ count is specified.
+ * the buffer supplied to pack/unpack must be of sufficient length
+ to hold all the data, or the behavior is unspecified.
+ * the file provided to the "f" versions of the functions must be
+ open in the appropriate mode, or the behavior is unspecified.
+ * the file supplied to funpackf must be of sufficient length to
+ hold all the data, or the behavior is unspecified.
+ * the behavior of all functions is unspecified if the format string
+ is incorrectly-formed.
+
+ Data-type specifiers:
+ x skipped byte; no corresponding argument
+ b byte
+ s two-byte two's-complement integer
+ i four-byte two's-complement integer
+ l eight-byte two's-complement integer
+ f four-byte IEEE754 float
+ d eight-byte IEEE754 double
+
+ Byte-order specifiers:
+ L little-endian
+ B big-endian
+ H host's native byte order
+ N network byte order
+ */
+
+#ifndef ALREADY_DID_BINIO_STDINT
+#define ALREADY_DID_BINIO_STDINT
+#if defined(BinIO_STDINT_HEADER)
+#include BinIO_STDINT_HEADER
+ typedef float float32_t;
+ typedef double float64_t;
+#else
+ typedef unsigned char uint8_t;
+ typedef unsigned short uint16_t;
+ typedef unsigned long uint32_t;
+#ifdef WIN32
+ typedef unsigned __int64 uint64_t;
+#else
+ typedef unsigned long long uint64_t;
+#endif
+ typedef float float32_t;
+ typedef double float64_t;
+#endif
+#endif
+
+ typedef struct {
+ float64_t d;
+ uint64_t l;
+ int i;
+ float32_t f;
+ uint16_t s;
+ uint8_t b;
+ }
+ test_data;
+
+ extern void packf ( const char *format, ...);
+ extern void spackf (void *buffer, const char *format, ...);
+ extern void fpackf (FILE *file, const char *format, ...);
+ extern void vspackf (void *buffer, const char *format, va_list args);
+ extern void vfpackf (FILE *file, const char *format, va_list args);
+
+ extern void unpackf ( const char *format, ...);
+ extern void sunpackf (const void *buffer, const char *format, ...);
+ extern void funpackf (FILE *file, const char *format, ...);
+ extern void vsunpackf(const void *buffer, const char *format, va_list args);
+ extern void vfunpackf(FILE *file, const char *format, va_list args);
+
+#ifdef _MSC_VER
+#ifndef va_copy
+#define va_copy(dest,src) do { dest = src; } while (0)
+#endif
+#endif
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
+
--- /dev/null
+/*
+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/>.
+*/
+
+#include <stdlib.h>
+
+#include "binio.h"
+#include "private.h"
+
+struct BinIOPackContext {
+ uint8_t *buffer;
+ va_list args;
+};
+
+static void BinIOPack(void *context, int type, int byte_order, int count)
+{
+ struct BinIOPackContext *ctx = (struct BinIOPackContext*)context;
+ if (count == -1) {
+ switch (type) {
+ case BinIO_TYPE_IGNORE_BYTE: {
+ ctx->buffer += 1;
+ }
+ break;
+ case BinIO_TYPE_BYTE: {
+ uint8_t value = va_arg(ctx->args, int);
+ BinIOConvert1(BinIO_HOST_BYTE_ORDER, byte_order, (const uint8_t *)&value, ctx->buffer, 1);
+ ctx->buffer += 1;
+ }
+ break;
+ case BinIO_TYPE_INT16: {
+ uint16_t value = va_arg(ctx->args, int);
+ BinIOConvert2(BinIO_HOST_BYTE_ORDER, byte_order, (const uint8_t *)&value, ctx->buffer, 1);
+ ctx->buffer += 2;
+ }
+ break;
+ case BinIO_TYPE_INT32: {
+ int value = va_arg(ctx->args, int);
+ BinIOConvert4(BinIO_HOST_BYTE_ORDER, byte_order, (const uint8_t *)&value, ctx->buffer, 1);
+ ctx->buffer += 4;
+ }
+ break;
+ case BinIO_TYPE_INT64: {
+ uint64_t value = va_arg(ctx->args, uint64_t);
+ BinIOConvert8(BinIO_HOST_BYTE_ORDER, byte_order, (const uint8_t *)&value, ctx->buffer, 1);
+ ctx->buffer += 8;
+ }
+ break;
+ case BinIO_TYPE_FLOAT32: {
+ float32_t value = (float32_t)va_arg(ctx->args, double);
+ BinIOConvert4(BinIO_HOST_BYTE_ORDER, byte_order, (const uint8_t *)&value, ctx->buffer, 1);
+ ctx->buffer += 4;
+ }
+ break;
+ case BinIO_TYPE_FLOAT64: {
+ float64_t value = va_arg(ctx->args, float64_t);
+ BinIOConvert8(BinIO_HOST_BYTE_ORDER, byte_order, (const uint8_t *)&value, ctx->buffer, 1);
+ ctx->buffer += 8;
+ }
+ break;
+ }
+ } else {
+ switch (type) {
+ case BinIO_TYPE_IGNORE_BYTE:
+ ctx->buffer += 1 * count;
+ break;
+ case BinIO_TYPE_BYTE:
+ BinIOConvert1(BinIO_HOST_BYTE_ORDER, byte_order, va_arg(ctx->args, uint8_t *), ctx->buffer, count);
+ ctx->buffer += 1 * count;
+ break;
+ case BinIO_TYPE_INT16:
+ BinIOConvert2(BinIO_HOST_BYTE_ORDER, byte_order, va_arg(ctx->args, uint8_t *), ctx->buffer, count);
+ ctx->buffer += 2 * count;
+ break;
+ case BinIO_TYPE_INT32:
+ BinIOConvert4(BinIO_HOST_BYTE_ORDER, byte_order, va_arg(ctx->args, uint8_t *), ctx->buffer, count);
+ ctx->buffer += 4 * count;
+ break;
+ case BinIO_TYPE_INT64:
+ BinIOConvert8(BinIO_HOST_BYTE_ORDER, byte_order, va_arg(ctx->args, uint8_t *), ctx->buffer, count);
+ ctx->buffer += 8 * count;
+ break;
+ case BinIO_TYPE_FLOAT32:
+ BinIOConvert4(BinIO_HOST_BYTE_ORDER, byte_order, va_arg(ctx->args, uint8_t *), ctx->buffer, count);
+ ctx->buffer += 4 * count;
+ break;
+ case BinIO_TYPE_FLOAT64:
+ BinIOConvert8(BinIO_HOST_BYTE_ORDER, byte_order, va_arg(ctx->args, uint8_t *), ctx->buffer, count);
+ ctx->buffer += 8 * count;
+ break;
+ }
+ }
+}
+
+extern void packf(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ vfpackf(stdout, format, args);
+ va_end(args);
+}
+
+extern void spackf(void *buffer, const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ vspackf(buffer, format, args);
+ va_end(args);
+}
+
+extern void fpackf(FILE *file, const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ vfpackf(file, format, args);
+ va_end(args);
+}
+
+extern void vspackf(void *buffer, const char *format, va_list args)
+{
+ struct BinIOFormatCursor cursor;
+ struct BinIOPackContext context;
+
+ BinIOInitFormatCursor(&cursor, format);
+
+ context.buffer = (unsigned char *)buffer;
+ va_copy(context.args, args);
+
+ while (BinIONextChar(&context, &cursor, BinIOPack)) {}
+
+ va_end(context.args);
+}
+
+extern void vfpackf(FILE *file, const char *format, va_list args)
+{
+ size_t n_bytes = BinIOFormatByteCount(format);
+ void* buffer = malloc(n_bytes);
+
+ vspackf(buffer, format, args);
+
+ fwrite(buffer, n_bytes, 1, file);
+ free(buffer);
+}
--- /dev/null
+/*
+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/>.
+*/
+
+#include <string.h>
+
+#include "private.h"
+
+void BinIOConvert1(int from_byte_order, int to_byte_order,
+ const uint8_t *src, uint8_t *dst,
+ unsigned int count)
+{
+ if (BinIONormalizeByteOrder(from_byte_order) !=
+ BinIONormalizeByteOrder(to_byte_order)) {
+ unsigned int i;
+ for (i = 0; i < count; ++i) {
+ BinIOSwap1(src, dst);
+ src += 1;
+ dst += 1;
+ }
+ } else {
+ memcpy(dst, src, 1 * count);
+ }
+}
+
+void BinIOConvert2(int from_byte_order, int to_byte_order,
+ const uint8_t *src, uint8_t *dst,
+ unsigned int count)
+{
+ if (BinIONormalizeByteOrder(from_byte_order) !=
+ BinIONormalizeByteOrder(to_byte_order)) {
+ unsigned int i;
+ for (i = 0; i < count; ++i) {
+ BinIOSwap2(src, dst);
+ src += 2;
+ dst += 2;
+ }
+ } else {
+ memcpy(dst, src, 2 * count);
+ }
+}
+
+void BinIOConvert4(int from_byte_order, int to_byte_order,
+ const uint8_t *src, uint8_t *dst,
+ unsigned int count)
+{
+ if (BinIONormalizeByteOrder(from_byte_order) !=
+ BinIONormalizeByteOrder(to_byte_order)) {
+ unsigned int i;
+ for (i = 0; i < count; ++i) {
+ BinIOSwap4(src, dst);
+ src += 4;
+ dst += 4;
+ }
+ } else {
+ memcpy(dst, src, 4 * count);
+ }
+}
+
+void BinIOConvert8(int from_byte_order, int to_byte_order,
+ const uint8_t *src, uint8_t *dst,
+ unsigned int count)
+{
+ if (BinIONormalizeByteOrder(from_byte_order) !=
+ BinIONormalizeByteOrder(to_byte_order)) {
+ unsigned int i;
+ for (i = 0; i < count; ++i) {
+ BinIOSwap8(src, dst);
+ src += 8;
+ dst += 8;
+ }
+ } else {
+ memcpy(dst, src, 8 * count);
+ }
+}
+
+void BinIOInitFormatCursor(struct BinIOFormatCursor *cursor,
+ const char *format)
+{
+ cursor->cursor = format;
+ cursor->byte_order = BinIO_HOST_BYTE_ORDER;
+ cursor->count = -1;
+}
+
+int BinIONextChar(void *context,
+ struct BinIOFormatCursor *cursor,
+ BinIOProcessFunction func)
+{
+ int count, value;
+ int c;
+ switch (c = *(cursor->cursor)++) {
+ case BinIO_LITTLE_ENDIAN_BYTE_ORDER:
+ case BinIO_BIG_ENDIAN_BYTE_ORDER:
+ case BinIO_HOST_BYTE_ORDER:
+ case BinIO_NETWORK_BYTE_ORDER:
+ cursor->byte_order = c;
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ count = cursor->count;
+ value = c - '0';
+ if (count == -1) {
+ cursor->count = value;
+ } else {
+ cursor->count = (count * 10) + value;
+ }
+ break;
+
+ case BinIO_TYPE_IGNORE_BYTE:
+ case BinIO_TYPE_BYTE:
+ case BinIO_TYPE_INT16:
+ case BinIO_TYPE_INT32:
+ case BinIO_TYPE_INT64:
+ case BinIO_TYPE_FLOAT32:
+ case BinIO_TYPE_FLOAT64:
+ func(context, c, cursor->byte_order, cursor->count);
+ cursor->byte_order = BinIO_HOST_BYTE_ORDER;
+ cursor->count = -1;
+ break;
+
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+extern void BinIOCountBytes(void *context, int type, int byte_order, int count)
+{
+ size_t type_size = 0;
+
+ if (count == -1) {
+ count = 1;
+ }
+
+ switch (type) {
+ case BinIO_TYPE_IGNORE_BYTE:
+ type_size = 1;
+ break;
+ case BinIO_TYPE_BYTE:
+ type_size = 1;
+ break;
+ case BinIO_TYPE_INT16:
+ type_size = 2;
+ break;
+ case BinIO_TYPE_INT32:
+ type_size = 4;
+ break;
+ case BinIO_TYPE_INT64:
+ type_size = 8;
+ break;
+ case BinIO_TYPE_FLOAT32:
+ type_size = 4;
+ break;
+ case BinIO_TYPE_FLOAT64:
+ type_size = 8;
+ break;
+ }
+
+ *(size_t*)context += type_size * count;
+}
+
+extern size_t BinIOFormatByteCount(const char *format)
+{
+ struct BinIOFormatCursor cursor;
+ size_t n_bytes = 0;
+
+ BinIOInitFormatCursor(&cursor, format);
+
+ while (BinIONextChar(&n_bytes, &cursor, BinIOCountBytes)) {}
+
+ return n_bytes;
+}
--- /dev/null
+/*
+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 private_h
+#define private_h
+
+#include <stdarg.h>
+#include <stddef.h>
+
+#define BinIO_TYPE_IGNORE_BYTE 'x'
+#define BinIO_TYPE_BYTE 'b'
+#define BinIO_TYPE_INT16 's'
+#define BinIO_TYPE_INT32 'i'
+#define BinIO_TYPE_INT64 'l'
+#define BinIO_TYPE_FLOAT32 'f'
+#define BinIO_TYPE_FLOAT64 'd'
+
+#define BinIO_LITTLE_ENDIAN_BYTE_ORDER 'L'
+#define BinIO_BIG_ENDIAN_BYTE_ORDER 'B'
+#define BinIO_HOST_BYTE_ORDER 'H'
+#define BinIO_NETWORK_BYTE_ORDER 'N'
+
+#ifndef ALREADY_DID_BINIO_STDINT
+#define ALREADY_DID_BINIO_STDINT
+#if defined(BinIO_STDINT_HEADER)
+#include BinIO_STDINT_HEADER
+typedef float float32_t;
+typedef double float64_t;
+#else
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned long uint32_t;
+#ifdef WIN32
+typedef unsigned __int64 uint64_t;
+#else
+typedef unsigned long long uint64_t;
+#endif
+typedef float float32_t;
+typedef double float64_t;
+#endif
+#endif
+
+#ifndef BinIO_INLINE
+#if defined(__GNUC__)
+#define BinIO_INLINE static inline
+#else
+#define BinIO_INLINE static
+#endif
+#endif
+
+#ifndef BinIO_BYTE_ORDER
+#if defined(__ppc__) || defined(__POWERPC__)
+#define BinIO_BYTE_ORDER BinIO_BIG_ENDIAN_BYTE_ORDER
+#else
+#define BinIO_BYTE_ORDER BinIO_LITTLE_ENDIAN_BYTE_ORDER
+#endif
+#endif
+
+BinIO_INLINE void BinIOSwap1(const uint8_t *src, uint8_t *dst)
+{
+ *dst = *src;
+}
+
+BinIO_INLINE void BinIOSwap2(const uint8_t *src, uint8_t *dst)
+{
+ *(dst + 1) = *(src + 0);
+ *(dst + 0) = *(src + 1);
+}
+
+BinIO_INLINE void BinIOSwap4(const uint8_t *src, uint8_t *dst)
+{
+ *(dst + 3) = *(src + 0);
+ *(dst + 2) = *(src + 1);
+ *(dst + 1) = *(src + 2);
+ *(dst + 0) = *(src + 3);
+}
+
+BinIO_INLINE void BinIOSwap8(const uint8_t *src, uint8_t *dst)
+{
+ *(dst + 7) = *(src + 0);
+ *(dst + 6) = *(src + 1);
+ *(dst + 5) = *(src + 2);
+ *(dst + 4) = *(src + 3);
+ *(dst + 3) = *(src + 4);
+ *(dst + 2) = *(src + 5);
+ *(dst + 1) = *(src + 6);
+ *(dst + 0) = *(src + 7);
+}
+
+BinIO_INLINE int BinIONormalizeByteOrder(int byte_order)
+{
+ if (byte_order == BinIO_HOST_BYTE_ORDER) {
+ byte_order = BinIO_BYTE_ORDER;
+ } else if (byte_order == BinIO_NETWORK_BYTE_ORDER) {
+ byte_order = BinIO_BIG_ENDIAN_BYTE_ORDER;
+ }
+
+ return byte_order;
+}
+
+extern void BinIOConvert1(int from_byte_order, int to_byte_order,
+ const uint8_t *src, uint8_t *dst,
+ unsigned int count);
+extern void BinIOConvert2(int from_byte_order, int to_byte_order,
+ const uint8_t *src, uint8_t *dst,
+ unsigned int count);
+extern void BinIOConvert4(int from_byte_order, int to_byte_order,
+ const uint8_t *src, uint8_t *dst,
+ unsigned int count);
+extern void BinIOConvert8(int from_byte_order, int to_byte_order,
+ const uint8_t *src, uint8_t *dst,
+ unsigned int count);
+
+struct BinIOFormatCursor {
+ const char *cursor;
+ int byte_order;
+ int count;
+};
+
+typedef void (*BinIOProcessFunction)(void *context,
+ int type,
+ int byte_order,
+ int count);
+
+extern void BinIOInitFormatCursor(struct BinIOFormatCursor *cursor,
+ const char *format);
+
+extern int BinIONextChar(void *context,
+ struct BinIOFormatCursor *cursor,
+ BinIOProcessFunction func);
+
+extern void BinIOCountBytes(void *context, int type, int byte_order, int count);
+
+extern size_t BinIOFormatByteCount(const char *format);
+
+#endif
+
--- /dev/null
+/*
+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/>.
+*/
+
+#include <stdlib.h>
+
+#include "binio.h"
+#include "private.h"
+
+struct BinIOUnpackContext {
+ const uint8_t *data;
+ va_list args;
+};
+
+static void BinIOUnpack(void *context, int type, int byte_order, int count)
+{
+ struct BinIOUnpackContext *ctx = (struct BinIOUnpackContext*)context;
+ if (count == -1) {
+ count = 1;
+ }
+
+ switch (type) {
+ case BinIO_TYPE_IGNORE_BYTE:
+ ctx->data += 1 * count;
+ break;
+ case BinIO_TYPE_BYTE:
+ BinIOConvert1(byte_order, BinIO_HOST_BYTE_ORDER, ctx->data, va_arg(ctx->args, uint8_t *), count);
+ ctx->data += 1 * count;
+ break;
+ case BinIO_TYPE_INT16:
+ BinIOConvert2(byte_order, BinIO_HOST_BYTE_ORDER, ctx->data, va_arg(ctx->args, uint8_t *), count);
+ ctx->data += 2 * count;
+ break;
+ case BinIO_TYPE_INT32:
+ BinIOConvert4(byte_order, BinIO_HOST_BYTE_ORDER, ctx->data, va_arg(ctx->args, uint8_t *), count);
+ ctx->data += 4 * count;
+ break;
+ case BinIO_TYPE_INT64:
+ BinIOConvert8(byte_order, BinIO_HOST_BYTE_ORDER, ctx->data, va_arg(ctx->args, uint8_t *), count);
+ ctx->data += 8 * count;
+ break;
+ case BinIO_TYPE_FLOAT32:
+ BinIOConvert4(byte_order, BinIO_HOST_BYTE_ORDER, ctx->data, va_arg(ctx->args, uint8_t *), count);
+ ctx->data += 4 * count;
+ break;
+ case BinIO_TYPE_FLOAT64:
+ BinIOConvert8(byte_order, BinIO_HOST_BYTE_ORDER, ctx->data, va_arg(ctx->args, uint8_t *), count);
+ ctx->data += 8 * count;
+ break;
+ }
+}
+
+void unpackf(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ vfunpackf(stdin, format, args);
+ va_end(args);
+}
+
+void sunpackf(const void *buffer, const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ vsunpackf(buffer, format, args);
+ va_end(args);
+}
+
+void funpackf(FILE *file, const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ vfunpackf(file, format, args);
+ va_end(args);
+}
+
+void vsunpackf(const void *buffer, const char *format, va_list args)
+{
+ struct BinIOFormatCursor cursor;
+ struct BinIOUnpackContext context;
+
+ BinIOInitFormatCursor(&cursor, format);
+
+ context.data = (const unsigned char*)buffer;
+ va_copy(context.args, args);
+
+ while (BinIONextChar(&context, &cursor, BinIOUnpack)) {}
+
+ va_end(context.args);
+}
+
+void vfunpackf(FILE *file, const char *format, va_list args)
+{
+ size_t n_bytes = BinIOFormatByteCount(format);
+ void* buffer = malloc(n_bytes);
+ fread(buffer, n_bytes, 1, file);
+
+ vsunpackf(buffer, format, args);
+
+ free(buffer);
+}
+++ /dev/null
-/*
-Copyright (C) 2003, 2010 - Wolfire Games
-Copyright (C) 2010-2016 - Lugaru contributors (see AUTHORS file)
-
-This file is part of Lugaru.
-
-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 "Weapons.h"
-#include "openal_wrapper.h"
-#include "Animation/Animation.h"
-#include "Sounds.h"
-#include "Game.h"
-#include "Awards.h"
-
-extern float multiplier;
-extern Terrain terrain;
-extern float gravity;
-extern int environment;
-extern int detail;
-extern FRUSTUM frustum;
-extern XYZ viewer;
-extern float realmultiplier;
-extern int slomo;
-extern float slomodelay;
-extern bool cellophane;
-extern float texdetail;
-extern GLubyte bloodText[512 * 512 * 3];
-extern int bloodtoggle;
-extern Objects objects;
-extern bool autoslomo;
-extern float camerashake;
-extern float woozy;
-extern float viewdistance;
-extern float blackout;
-extern bool freeze;
-extern int tutoriallevel;
-extern int numthrowkill;
-
-Model Weapon::throwingknifemodel;
-Texture Weapon::knifetextureptr;
-Texture Weapon::lightbloodknifetextureptr;
-Texture Weapon::bloodknifetextureptr;
-
-Model Weapon::swordmodel;
-Texture Weapon::swordtextureptr;
-Texture Weapon::lightbloodswordtextureptr;
-Texture Weapon::bloodswordtextureptr;
-
-Model Weapon::staffmodel;
-Texture Weapon::stafftextureptr;
-
-Weapon::Weapon(int t, int o) : owner(o)
-{
- setType(t);
- bloody = 0;
- blooddrip = 0;
- blooddripdelay = 0;
- onfire = 0;
- flamedelay = 0;
- damage = 0;
- position = -1000;
- tippoint = -1000;
-}
-
-void Weapon::setType(int t)
-{
- type = t;
- if (type == sword) {
- mass = 1.5;
- tipmass = 1;
- length = .8;
- }
- if (type == staff) {
- mass = 2;
- tipmass = 1;
- length = 1.5;
- }
- if (type == knife) {
- mass = 1;
- tipmass = 1.2;
- length = .25;
- }
-}
-
-void Weapon::DoStuff(int i)
-{
- //~ cout << position.x << "," << position.y << "," << position.z << "|" << tippoint.x << "," << tippoint.y << "," << tippoint.z << endl;
- static int whichpatchx, whichpatchz, whichhit;
- static XYZ start, end, colpoint, normalrot, footvel, footpoint;
- static XYZ terrainnormal;
- static XYZ vel;
- static XYZ midp;
- static XYZ newpoint1, newpoint2;
- static float friction = 3.5;
- static float elasticity = .4;
- static XYZ bounceness;
- static float frictionness;
- static float closestdistance;
- static float distance;
- static XYZ point[3];
- static XYZ closestpoint;
- static XYZ closestswordpoint;
- static float tempmult;
-
- if (owner != -1) {
- oldowner = owner;
- }
- if (damage >= 2 && type == staff && owner != -1) { // the staff breaks
- emit_sound_at(staffbreaksound, tippoint);
- XYZ tempvel;
- for (int j = 0; j < 40; j++) {
- tempvel.x = float(abs(Random() % 100) - 50) / 20;
- tempvel.y = float(abs(Random() % 100) - 50) / 20;
- tempvel.z = float(abs(Random() % 100) - 50) / 20;
- Sprite::MakeSprite(splintersprite, position + (tippoint - position) * ((float)j - 8) / 32, tempvel * .5, 115 / 255, 73 / 255, 12 / 255, .1, 1);
- }
- if (owner != -1) {
- Person::players[owner]->weaponactive = -1;
- Person::players[owner]->num_weapons--;
- if (Person::players[owner]->num_weapons) {
- Person::players[owner]->weaponids[0] = Person::players[owner]->weaponids[Person::players[owner]->num_weapons];
- if (Person::players[owner]->weaponstuck == Person::players[owner]->num_weapons)
- Person::players[owner]->weaponstuck = 0;
- }
- }
- owner = -1;
- hitsomething = 0;
- missed = 1;
- freetime = 0;
- firstfree = 1;
- position = 0;
- physics = 0;
- }
- oldposition = position;
- oldtippoint = tippoint;
- if (owner == -1 && (velocity.x || velocity.y || velocity.z) && !physics) { // if the weapon is flying
- position += velocity * multiplier;
- tippoint += velocity * multiplier;
- whichpatchx = position.x / (terrain.size / subdivision * terrain.scale);
- whichpatchz = position.z / (terrain.size / subdivision * terrain.scale);
- if (whichpatchx > 0 && whichpatchz > 0 && whichpatchx < subdivision && whichpatchz < subdivision) {
- if (terrain.patchobjectnum[whichpatchx][whichpatchz]) { // if there are objects where the weapon is
- for (int j = 0; j < terrain.patchobjectnum[whichpatchx][whichpatchz]; j++) { // check for collision
- int k = terrain.patchobjects[whichpatchx][whichpatchz][j];
- start = oldtippoint;
- end = tippoint;
- whichhit = objects.model[k].LineCheck(&start, &end, &colpoint, &objects.position[k], &objects.yaw[k]);
- if (whichhit != -1) {
- if (objects.type[k] == treetrunktype) {
- objects.model[k].MakeDecal(breakdecal, DoRotation(colpoint - objects.position[k], 0, -objects.yaw[k], 0), .1, 1, Random() % 360);
- normalrot = DoRotation(objects.model[k].facenormals[whichhit], 0, objects.yaw[k], 0);
- velocity = 0;
- if (type == knife)
- position = colpoint - normalrot * .1;
- else if (type == sword)
- position = colpoint - normalrot * .2;
- else if (type == staff)
- position = colpoint - normalrot * .2;
- XYZ temppoint1, temppoint2;
- float distance;
-
- temppoint1 = 0;
- temppoint2 = normalrot;
- distance = findDistance(&temppoint1, &temppoint2);
- rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
- rotation2 *= 360 / 6.28;
- temppoint1.y = 0;
- temppoint2.y = 0;
- rotation1 = acos((temppoint1.z - temppoint2.z) / findDistance(&temppoint1, &temppoint2));
- rotation1 *= 360 / 6.28;
- if (temppoint1.x > temppoint2.x)
- rotation1 = 360 - rotation1;
-
- rotation3 = 0;
- smallrotation = 90;
- smallrotation2 = 0;
- bigtilt = 0;
- bigtilt2 = 0;
- bigrotation = 0;
-
- emit_sound_at(knifesheathesound, position, 128.);
-
- bloody = 0;
-
- Sprite::MakeSprite(cloudimpactsprite, position, velocity, 1, 1, 1, .8, .3);
- } else {
- physics = 1;
- firstfree = 1;
- position -= velocity * multiplier;
- tippoint -= velocity * multiplier;
- tipvelocity = velocity;
- }
- }
- }
- }
- }
-
- if (velocity.x || velocity.y || velocity.z) {
- for (unsigned j = 0; j < Person::players.size(); j++) {
- footvel = 0;
- footpoint = DoRotation((Person::players[j]->jointPos(abdomen) + Person::players[j]->jointPos(neck)) / 2, 0, Person::players[j]->yaw, 0) * Person::players[j]->scale + Person::players[j]->coords;
- if (owner == -1 && distsqflat(&position, &Person::players[j]->coords) < 1.5 &&
- distsq(&position, &Person::players[j]->coords) < 4 && Person::players[j]->weaponstuck == -1 &&
- !Person::players[j]->skeleton.free && (int(j) != oldowner)) {
- if ((Person::players[j]->aitype != attacktypecutoff || abs(Random() % 6) == 0 || (Person::players[j]->animTarget != backhandspringanim && Person::players[j]->animTarget != rollanim && Person::players[j]->animTarget != flipanim && Random() % 2 == 0)) && !missed) {
- if ( (Person::players[j]->creature == wolftype && Random() % 3 != 0 && Person::players[j]->weaponactive == -1 && (Person::players[j]->isIdle() || Person::players[j]->isRun() || Person::players[j]->animTarget == walkanim)) ||
- (Person::players[j]->creature == rabbittype && Random() % 2 == 0 && Person::players[j]->aitype == attacktypecutoff && Person::players[j]->weaponactive == -1)) {
- emit_sound_at(knifedrawsound, Person::players[j]->coords, 128.);
-
- Person::players[j]->animTarget = removeknifeanim;
- Person::players[j]->frameTarget = 1;
- Person::players[j]->target = 1;
- Person::players[j]->takeWeapon(i);
-
- Person::players[j]->aitype = attacktypecutoff;
- } else {
- if (j != 0)
- numthrowkill++;
- Person::players[j]->num_weapons++;
- Person::players[j]->weaponstuck = Person::players[j]->num_weapons - 1;
- if (normaldotproduct(Person::players[j]->facing, velocity) > 0)
- Person::players[j]->weaponstuckwhere = 1;
- else
- Person::players[j]->weaponstuckwhere = 0;
-
- Person::players[j]->weaponids[Person::players[j]->num_weapons - 1] = i;
-
- Person::players[j]->RagDoll(0);
- Person::players[j]->jointVel(abdomen) += velocity * 2;
- Person::players[j]->jointVel(neck) += velocity * 2;
- Person::players[j]->jointVel(rightshoulder) += velocity * 2;
- Person::players[j]->jointVel(leftshoulder) += velocity * 2;
- if (bloodtoggle && tutoriallevel != 1)
- Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .8, .3);
- if (tutoriallevel == 1)
- Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 1, 1, .8, .3);
- footvel = tippoint - position;
- Normalise(&footvel);
- if (bloodtoggle && tutoriallevel != 1)
- Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * -1, 1, 0, 0, .6, 1);
-
- if (tutoriallevel != 1) {
- if (Person::players[j]->weaponstuckwhere == 0)
- Person::players[j]->DoBloodBig(2, 205);
- if (Person::players[j]->weaponstuckwhere == 1)
- Person::players[j]->DoBloodBig(2, 200);
- Person::players[j]->damage += 200 / Person::players[j]->armorhigh;
- Person::players[j]->deathbleeding = 1;
- Person::players[j]->bloodloss += (200 + abs((float)(Random() % 40)) - 20) / Person::players[j]->armorhigh;
- owner = j;
- bloody = 2;
- blooddrip = 5;
- }
-
- emit_sound_at(fleshstabsound, position, 128.);
-
- if (Animation::animations[Person::players[0]->animTarget].height == highheight)
- award_bonus(0, ninja);
- else
- award_bonus(0, Bullseyebonus);
- }
- } else {
- missed = 1;
- }
- }
- }
- }
- if (position.y < terrain.getHeight(position.x, position.z)) {
- if (terrain.getOpacity(position.x, position.z) < .2) {
- velocity = 0;
- if (terrain.lineTerrain(oldposition, position, &colpoint) != -1) {
- position = colpoint * terrain.scale;
- } else {
- position.y = terrain.getHeight(position.x, position.z);
- }
-
- terrain.MakeDecal(shadowdecalpermanent, position, .06, .5, 0);
- normalrot = terrain.getNormal(position.x, position.z) * -1;
- velocity = 0;
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- GLfloat M[16];
- glLoadIdentity();
- glRotatef(bigrotation, 0, 1, 0);
- glRotatef(bigtilt2, 1, 0, 0);
- glRotatef(bigtilt, 0, 0, 1);
- glRotatef(-rotation1 + 90, 0, 1, 0);
- glRotatef(-rotation2 + 90, 0, 0, 1);
- glRotatef(-rotation3, 0, 1, 0);
- glRotatef(smallrotation, 1, 0, 0);
- glRotatef(smallrotation2, 0, 1, 0);
- glTranslatef(0, 0, 1);
- glGetFloatv(GL_MODELVIEW_MATRIX, M);
- tippoint.x = M[12];
- tippoint.y = M[13];
- tippoint.z = M[14];
- glPopMatrix();
- position -= tippoint * .15;
- XYZ temppoint1, temppoint2;
-
- rotation3 = 0;
- smallrotation = 90;
- smallrotation2 = 0;
- bigtilt = 0;
- bigtilt2 = 0;
- bigrotation = 0;
-
- emit_sound_at(knifesheathesound, position, 128.);
-
- XYZ terrainlight;
- terrainlight = terrain.getLighting(position.x, position.z);
- if (environment == snowyenvironment) {
- if (distsq(&position, &viewer) < viewdistance * viewdistance / 4)
- Sprite::MakeSprite(cloudsprite, position, velocity, terrainlight.x, terrainlight.y, terrainlight.z, .5, .7);
- } else if (environment == grassyenvironment) {
- if (distsq(&position, &viewer) < viewdistance * viewdistance / 4)
- Sprite::MakeSprite(cloudsprite, position, velocity, terrainlight.x * 90 / 255, terrainlight.y * 70 / 255, terrainlight.z * 8 / 255, .5, .5);
- } else if (environment == desertenvironment) {
- if (distsq(&position, &viewer) < viewdistance * viewdistance / 4)
- Sprite::MakeSprite(cloudsprite, position, velocity, terrainlight.x * 190 / 255, terrainlight.y * 170 / 255, terrainlight.z * 108 / 255, .5, .7);
- }
-
- bloody = 0;
- } else {
- physics = 1;
- firstfree = 1;
- position -= velocity * multiplier;
- tippoint -= velocity * multiplier;
- tipvelocity = velocity;
- }
- }
- if (velocity.x != 0 || velocity.z != 0 || velocity.y != 0) {
- velocity.y += gravity * multiplier;
-
- XYZ temppoint1, temppoint2;
- float distance;
-
- temppoint1 = 0;
- temppoint2 = velocity;
- distance = findDistance(&temppoint1, &temppoint2);
- rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
- rotation2 *= 360 / 6.28;
- temppoint1.y = 0;
- temppoint2.y = 0;
- rotation1 = acos((temppoint1.z - temppoint2.z) / findDistance(&temppoint1, &temppoint2));
- rotation1 *= 360 / 6.28;
- rotation3 = 0;
- smallrotation = 90;
- smallrotation2 = 0;
- bigtilt = 0;
- bigtilt2 = 0;
- bigrotation = 0;
- if (temppoint1.x > temppoint2.x)
- rotation1 = 360 - rotation1;
- }
-
- }
-
- //Sword physics
- XYZ mid;
- XYZ oldmid;
- XYZ oldmid2;
-
- tempmult = multiplier;
- multiplier /= 10;
- for (int l = 0; l < 10; l++) {
- if (owner == -1 && (velocity.x || velocity.y || velocity.z) && physics) {
- //move
- position += velocity * multiplier;
- tippoint += tipvelocity * multiplier;
-
- //Length constrain
- midp = (position * mass + tippoint * tipmass) / (mass + tipmass);
- vel = tippoint - midp;
- Normalise(&vel);
- newpoint1 = midp - vel * length * (tipmass / (mass + tipmass));
- newpoint2 = midp + vel * length * (mass / (mass + tipmass));
- if (!freeze) {
- if (freetime > .04) {
- velocity = velocity + (newpoint1 - position) / multiplier;
- tipvelocity = tipvelocity + (newpoint2 - tippoint) / multiplier;
- }
- }
- position = newpoint1;
- tippoint = newpoint2;
-
-
- //Object collisions
- whichpatchx = (position.x) / (terrain.size / subdivision * terrain.scale);
- whichpatchz = (position.z) / (terrain.size / subdivision * terrain.scale);
- if (whichpatchx > 0 && whichpatchz > 0 && whichpatchx < subdivision && whichpatchz < subdivision)
- if (terrain.patchobjectnum[whichpatchx][whichpatchz]) {
- for (int j = 0; j < terrain.patchobjectnum[whichpatchx][whichpatchz]; j++) {
- int k = terrain.patchobjects[whichpatchx][whichpatchz][j];
-
- if (firstfree) {
- if (type == staff) {
- start = tippoint - (position - tippoint) / 5;
- end = position + (position - tippoint) / 30;
- whichhit = objects.model[k].LineCheck(&start, &end, &colpoint, &objects.position[k], &objects.yaw[k]);
- if (whichhit != -1) {
- XYZ diff;
- diff = (colpoint - position);
- Normalise(&diff);
- hitsomething = 1;
-
- tippoint += (colpoint - position) + diff * .05;
- position = colpoint + diff * .05;
- oldtippoint = tippoint;
- oldposition = tippoint;
- }
- } else {
- start = position - (tippoint - position) / 5;
- end = tippoint + (tippoint - position) / 30;
- whichhit = objects.model[k].LineCheck(&start, &end, &colpoint, &objects.position[k], &objects.yaw[k]);
- if (whichhit != -1) {
- XYZ diff;
- diff = (colpoint - tippoint);
- Normalise(&diff);
- hitsomething = 1;
-
- position += (colpoint - tippoint) + diff * .05;
- tippoint = colpoint + diff * .05;
- oldposition = position;
- oldtippoint = tippoint;
- }
- }
- }
-
- start = oldposition;
- end = position;
- whichhit = objects.model[k].LineCheck(&start, &end, &colpoint, &objects.position[k], &objects.yaw[k]);
- if (whichhit != -1) {
- hitsomething = 1;
- position = colpoint;
- terrainnormal = DoRotation(objects.model[k].facenormals[whichhit], 0, objects.yaw[k], 0) * -1;
- ReflectVector(&velocity, &terrainnormal);
- position += terrainnormal * .002;
-
- bounceness = terrainnormal * findLength(&velocity) * (abs(normaldotproduct(velocity, terrainnormal)));
- if (findLengthfast(&velocity) < findLengthfast(&bounceness))
- bounceness = 0;
- frictionness = abs(normaldotproduct(velocity, terrainnormal));
- velocity -= bounceness;
- if (1 - friction * frictionness > 0)
- velocity *= 1 - friction * frictionness;
- else
- velocity = 0;
- velocity += bounceness * elasticity;
-
- if (findLengthfast(&bounceness) > 1) {
- int whichsound;
- if (type == staff)
- whichsound = footstepsound3 + abs(Random() % 2);
- else
- whichsound = clank1sound + abs(Random() % 4);
- emit_sound_at(whichsound, position, 128 * findLengthfast(&bounceness));
- }
- }
- start = oldtippoint;
- end = tippoint;
- whichhit = objects.model[k].LineCheck(&start, &end, &colpoint, &objects.position[k], &objects.yaw[k]);
- if (whichhit != -1) {
- hitsomething = 1;
- tippoint = colpoint;
- terrainnormal = DoRotation(objects.model[k].facenormals[whichhit], 0, objects.yaw[k], 0) * -1;
- ReflectVector(&tipvelocity, &terrainnormal);
- tippoint += terrainnormal * .002;
-
- bounceness = terrainnormal * findLength(&tipvelocity) * (abs(normaldotproduct(tipvelocity, terrainnormal)));
- if (findLengthfast(&tipvelocity) < findLengthfast(&bounceness))
- bounceness = 0;
- frictionness = abs(normaldotproduct(tipvelocity, terrainnormal));
- tipvelocity -= bounceness;
- if (1 - friction * frictionness > 0)
- tipvelocity *= 1 - friction * frictionness;
- else
- tipvelocity = 0;
- tipvelocity += bounceness * elasticity;
-
- if (findLengthfast(&bounceness) > 1) {
- int whichsound;
- if (type == staff)
- whichsound = footstepsound3 + abs(Random() % 2);
- else
- whichsound = clank1sound + abs(Random() % 4);
- emit_sound_at(whichsound, position, 128 * findLengthfast(&bounceness));
- }
- }
-
- if ((objects.type[k] != boxtype && objects.type[k] != platformtype && objects.type[k] != walltype && objects.type[k] != weirdtype) || objects.pitch[k] != 0)
- for (int m = 0; m < 2; m++) {
- mid = (position * (21 + (float)m * 10) + tippoint * (19 - (float)m * 10)) / 40;
- oldmid2 = mid;
- oldmid = (oldposition * (21 + (float)m * 10) + oldtippoint * (19 - (float)m * 10)) / 40;
-
- start = oldmid;
- end = mid;
- whichhit = objects.model[k].LineCheck(&start, &end, &colpoint, &objects.position[k], &objects.yaw[k]);
- if (whichhit != -1) {
- hitsomething = 1;
- mid = colpoint;
- terrainnormal = DoRotation(objects.model[k].facenormals[whichhit], 0, objects.yaw[k], 0) * -1;
- ReflectVector(&velocity, &terrainnormal);
-
- bounceness = terrainnormal * findLength(&velocity) * (abs(normaldotproduct(velocity, terrainnormal)));
- if (findLengthfast(&velocity) < findLengthfast(&bounceness))
- bounceness = 0;
- frictionness = abs(normaldotproduct(velocity, terrainnormal));
- velocity -= bounceness;
- if (1 - friction * frictionness > 0)
- velocity *= 1 - friction * frictionness;
- else
- velocity = 0;
- velocity += bounceness * elasticity;
-
- if (findLengthfast(&bounceness) > 1) {
- int whichsound;
- if (type == staff)
- whichsound = footstepsound3 + abs(Random() % 2);
- else
- whichsound = clank1sound + abs(Random() % 4);
- emit_sound_at(whichsound, mid, 128 * findLengthfast(&bounceness));
- }
- position += (mid - oldmid2) * (20 / (1 + (float)m * 10));
- }
-
- mid = (position * (19 - (float)m * 10) + tippoint * (21 + (float)m * 10)) / 40;
- oldmid2 = mid;
- oldmid = (oldposition * (19 - (float)m * 10) + oldtippoint * (21 + (float)m * 10)) / 40;
-
- start = oldmid;
- end = mid;
- whichhit = objects.model[k].LineCheck(&start, &end, &colpoint, &objects.position[k], &objects.yaw[k]);
- if (whichhit != -1) {
- hitsomething = 1;
- mid = colpoint;
- terrainnormal = DoRotation(objects.model[k].facenormals[whichhit], 0, objects.yaw[k], 0) * -1;
- ReflectVector(&tipvelocity, &terrainnormal);
-
- bounceness = terrainnormal * findLength(&tipvelocity) * (abs(normaldotproduct(tipvelocity, terrainnormal)));
- if (findLengthfast(&tipvelocity) < findLengthfast(&bounceness))
- bounceness = 0;
- frictionness = abs(normaldotproduct(tipvelocity, terrainnormal));
- tipvelocity -= bounceness;
- if (1 - friction * frictionness > 0)
- tipvelocity *= 1 - friction * frictionness;
- else
- tipvelocity = 0;
- tipvelocity += bounceness * elasticity;
-
- if (findLengthfast(&bounceness) > 1) {
- int whichsound;
- if (type == staff)
- whichsound = footstepsound3 + abs(Random() % 2);
- else
- whichsound = clank1sound + abs(Random() % 4);
- emit_sound_at(whichsound, mid, 128 * findLengthfast(&bounceness));
- }
- tippoint += (mid - oldmid2) * (20 / (1 + (float)m * 10));
- }
- }
- else {
- start = position;
- end = tippoint;
- whichhit = objects.model[k].LineCheck(&start, &end, &colpoint, &objects.position[k], &objects.yaw[k]);
- if (whichhit != -1) {
- hitsomething = 1;
- closestdistance = -1;
- closestswordpoint = colpoint; //(position+tippoint)/2;
- point[0] = DoRotation(objects.model[k].vertex[objects.model[k].Triangles[whichhit].vertex[0]], 0, objects.yaw[k], 0) + objects.position[k];
- point[1] = DoRotation(objects.model[k].vertex[objects.model[k].Triangles[whichhit].vertex[1]], 0, objects.yaw[k], 0) + objects.position[k];
- point[2] = DoRotation(objects.model[k].vertex[objects.model[k].Triangles[whichhit].vertex[2]], 0, objects.yaw[k], 0) + objects.position[k];
- if (DistancePointLine(&closestswordpoint, &point[0], &point[1], &distance, &colpoint )) {
- if (distance < closestdistance || closestdistance == -1) {
- closestpoint = colpoint;
- closestdistance = distance;
- }
- }
- if (DistancePointLine(&closestswordpoint, &point[1], &point[2], &distance, &colpoint )) {
- if (distance < closestdistance || closestdistance == -1) {
- closestpoint = colpoint;
- closestdistance = distance;
- }
- }
- if (DistancePointLine(&closestswordpoint, &point[2], &point[0], &distance, &colpoint )) {
- if (distance < closestdistance || closestdistance == -1) {
- closestpoint = colpoint;
- closestdistance = distance;
- }
- }
- if (closestdistance != -1 && isnormal(closestdistance)) {
- if (DistancePointLine(&closestpoint, &position, &tippoint, &distance, &colpoint )) {
- closestswordpoint = colpoint;
- velocity += (closestpoint - closestswordpoint);
- tipvelocity += (closestpoint - closestswordpoint);
- position += (closestpoint - closestswordpoint);
- tippoint += (closestpoint - closestswordpoint);
- }
- }
- }
- }
- }
- }
- //Terrain collisions
- whichhit = terrain.lineTerrain(oldposition, position, &colpoint);
- if (whichhit != -1 || position.y < terrain.getHeight(position.x, position.z)) {
- hitsomething = 1;
- if (whichhit != -1)
- position = colpoint * terrain.scale;
- else
- position.y = terrain.getHeight(position.x, position.z);
-
- terrainnormal = terrain.getNormal(position.x, position.z);
- ReflectVector(&velocity, &terrainnormal);
- position += terrainnormal * .002;
- bounceness = terrainnormal * findLength(&velocity) * (abs(normaldotproduct(velocity, terrainnormal)));
- if (findLengthfast(&velocity) < findLengthfast(&bounceness))
- bounceness = 0;
- frictionness = abs(normaldotproduct(velocity, terrainnormal));
- velocity -= bounceness;
- if (1 - friction * frictionness > 0)
- velocity *= 1 - friction * frictionness;
- else
- velocity = 0;
- if (terrain.getOpacity(position.x, position.z) < .2)
- velocity += bounceness * elasticity * .3;
- else
- velocity += bounceness * elasticity;
-
- if (findLengthfast(&bounceness) > 1) {
- int whichsound;
- if (terrain.getOpacity(position.x, position.z) > .2) {
- if (type == staff)
- whichsound = footstepsound3 + abs(Random() % 2);
- else
- whichsound = clank1sound + abs(Random() % 4);
- } else {
- whichsound = footstepsound + abs(Random() % 2);
- }
- emit_sound_at(whichsound, position,
- findLengthfast(&bounceness)
- * (terrain.getOpacity(position.x, position.z) > .2 ? 128. : 32.));
-
- if (terrain.getOpacity(position.x, position.z) < .2) {
- XYZ terrainlight;
- terrainlight = terrain.getLighting(position.x, position.z);
- if (environment == snowyenvironment) {
- if (distsq(&position, &viewer) < viewdistance * viewdistance / 4)
- Sprite::MakeSprite(cloudsprite, position, velocity, terrainlight.x, terrainlight.y, terrainlight.z, .5, .7);
- } else if (environment == grassyenvironment) {
- if (distsq(&position, &viewer) < viewdistance * viewdistance / 4)
- Sprite::MakeSprite(cloudsprite, position, velocity, terrainlight.x * 90 / 255, terrainlight.y * 70 / 255, terrainlight.z * 8 / 255, .5, .5);
- } else if (environment == desertenvironment) {
- if (distsq(&position, &viewer) < viewdistance * viewdistance / 4)
- Sprite::MakeSprite(cloudsprite, position, velocity, terrainlight.x * 190 / 255, terrainlight.y * 170 / 255, terrainlight.z * 108 / 255, .5, .7);
- }
- }
- }
- }
- whichhit = terrain.lineTerrain(oldtippoint, tippoint, &colpoint);
- if (whichhit != -1 || tippoint.y < terrain.getHeight(tippoint.x, tippoint.z)) {
- if (whichhit != -1)
- tippoint = colpoint * terrain.scale;
- else
- tippoint.y = terrain.getHeight(tippoint.x, tippoint.z);
-
- terrainnormal = terrain.getNormal(tippoint.x, tippoint.z);
- ReflectVector(&tipvelocity, &terrainnormal);
- tippoint += terrainnormal * .002;
- bounceness = terrainnormal * findLength(&tipvelocity) * (abs(normaldotproduct(tipvelocity, terrainnormal)));
- if (findLengthfast(&tipvelocity) < findLengthfast(&bounceness))
- bounceness = 0;
- frictionness = abs(normaldotproduct(tipvelocity, terrainnormal));
- tipvelocity -= bounceness;
- if (1 - friction * frictionness > 0)
- tipvelocity *= 1 - friction * frictionness;
- else
- tipvelocity = 0;
- if (terrain.getOpacity(tippoint.x, tippoint.z) < .2)
- tipvelocity += bounceness * elasticity * .3;
- else
- tipvelocity += bounceness * elasticity;
-
- if (findLengthfast(&bounceness) > 1) {
- int whichsound;
- if (terrain.getOpacity(tippoint.x, tippoint.z) > .2) {
- if (type == staff)
- whichsound = footstepsound3 + abs(Random() % 2);
- else
- whichsound = clank1sound + abs(Random() % 4);
- } else {
- whichsound = footstepsound + abs(Random() % 2);
- }
- emit_sound_at(whichsound, tippoint,
- findLengthfast(&bounceness)
- * (terrain.getOpacity(tippoint.x, tippoint.z) > .2 ? 128. : 32.));
-
- if (terrain.getOpacity(tippoint.x, tippoint.z) < .2) {
- XYZ terrainlight;
- terrainlight = terrain.getLighting(tippoint.x, tippoint.z);
- if (environment == snowyenvironment) {
- if (distsq(&tippoint, &viewer) < viewdistance * viewdistance / 4)
- Sprite::MakeSprite(cloudsprite, tippoint, tipvelocity, terrainlight.x, terrainlight.y, terrainlight.z, .5, .7);
- } else if (environment == grassyenvironment) {
- if (distsq(&tippoint, &viewer) < viewdistance * viewdistance / 4)
- Sprite::MakeSprite(cloudsprite, tippoint, tipvelocity, terrainlight.x * 90 / 255, terrainlight.y * 70 / 255, terrainlight.z * 8 / 255, .5, .5);
- } else if (environment == desertenvironment) {
- if (distsq(&tippoint, &viewer) < viewdistance * viewdistance / 4)
- Sprite::MakeSprite(cloudsprite, tippoint, tipvelocity, terrainlight.x * 190 / 255, terrainlight.y * 170 / 255, terrainlight.z * 108 / 255, .5, .7);
- }
- }
- }
- }
-
- //Edges
- mid = position + tippoint;
- mid /= 2;
- mid += (position - mid) / 20;
- oldmid = mid;
- if (mid.y < terrain.getHeight(mid.x, mid.z)) {
- hitsomething = 1;
- mid.y = terrain.getHeight(mid.x, mid.z);
-
- terrainnormal = terrain.getNormal(mid.x, mid.z);
- ReflectVector(&velocity, &terrainnormal);
- //mid+=terrainnormal*.002;
- bounceness = terrainnormal * findLength(&velocity) * (abs(normaldotproduct(velocity, terrainnormal)));
- if (findLengthfast(&velocity) < findLengthfast(&bounceness))
- bounceness = 0;
- frictionness = abs(normaldotproduct(velocity, terrainnormal));
- velocity -= bounceness;
- if (1 - friction * frictionness > 0)
- velocity *= 1 - friction * frictionness;
- else
- velocity = 0;
- if (terrain.getOpacity(mid.x, mid.z) < .2)
- velocity += bounceness * elasticity * .3;
- else
- velocity += bounceness * elasticity;
-
- if (findLengthfast(&bounceness) > 1) {
- int whichsound;
- if (terrain.getOpacity(mid.x, mid.z) > .2) {
- if (type == staff)
- whichsound = footstepsound3 + abs(Random() % 2);
- if (type != staff)
- whichsound = clank1sound + abs(Random() % 4);
- } else {
- whichsound = footstepsound + abs(Random() % 2);
- }
- emit_sound_at(whichsound, mid,
- findLengthfast(&bounceness)
- * (terrain.getOpacity(position.x, position.z) > .2
- ? 128.
- : 32.));
- }
- position += (mid - oldmid) * 20;
- }
-
- mid = position + tippoint;
- mid /= 2;
- mid += (tippoint - mid) / 20;
- oldmid = mid;
- if (mid.y < terrain.getHeight(mid.x, mid.z)) {
- hitsomething = 1;
- mid.y = terrain.getHeight(mid.x, mid.z);
-
- terrainnormal = terrain.getNormal(mid.x, mid.z);
- ReflectVector(&tipvelocity, &terrainnormal);
- //mid+=terrainnormal*.002;
- bounceness = terrainnormal * findLength(&tipvelocity) * (abs(normaldotproduct(tipvelocity, terrainnormal)));
- if (findLengthfast(&tipvelocity) < findLengthfast(&bounceness))
- bounceness = 0;
- frictionness = abs(normaldotproduct(tipvelocity, terrainnormal));
- tipvelocity -= bounceness;
- if (1 - friction * frictionness > 0)
- tipvelocity *= 1 - friction * frictionness;
- else
- tipvelocity = 0;
- if (terrain.getOpacity(mid.x, mid.z) < .2)
- tipvelocity += bounceness * elasticity * .3;
- else
- tipvelocity += bounceness * elasticity;
-
- if (findLengthfast(&bounceness) > 1) {
- int whichsound;
- if (terrain.getOpacity(mid.x, mid.z) > .2) {
- if (type == staff)
- whichsound = footstepsound3 + abs(Random() % 2);
- if (type != staff)
- whichsound = clank1sound + abs(Random() % 4);
- } else {
- whichsound = footstepsound + abs(Random() % 2);
- }
- emit_sound_at(whichsound, mid,
- findLengthfast(&bounceness)
- * (terrain.getOpacity(position.x, position.z) > .2
- ? 128.
- : 32.));
- }
- tippoint += (mid - oldmid) * 20;
- }
- //Gravity
- velocity.y += gravity * multiplier;
- tipvelocity.y += gravity * multiplier;
-
- //Rotation
- XYZ temppoint1, temppoint2;
- float distance;
-
- temppoint1 = position;
- temppoint2 = tippoint;
- distance = findDistance(&temppoint1, &temppoint2);
- rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
- rotation2 *= 360 / 6.28;
- temppoint1.y = 0;
- temppoint2.y = 0;
- rotation1 = acos((temppoint1.z - temppoint2.z) / findDistance(&temppoint1, &temppoint2));
- rotation1 *= 360 / 6.28;
- rotation3 = 0;
- smallrotation = 90;
- smallrotation2 = 0;
- bigtilt = 0;
- bigtilt2 = 0;
- bigrotation = 0;
- if (temppoint1.x > temppoint2.x)
- rotation1 = 360 - rotation1;
-
- //Stop moving
- if (findLengthfast(&velocity) < .3 && findLengthfast(&tipvelocity) < .3 && hitsomething) {
- freetime += multiplier;
- }
-
- if (freetime > .4) {
- velocity = 0;
- tipvelocity = 0;
- }
- firstfree = 0;
- }
- }
- multiplier = tempmult;
- if (blooddrip && bloody) {
- blooddripdelay -= blooddrip * multiplier / 2;
- blooddrip -= multiplier;
- if (blooddrip < 0)
- blooddrip = 0;
- if (blooddrip > 5)
- blooddrip = 5;
- if (blooddripdelay < 0 && bloodtoggle) {
- blooddripdelay = 1;
- XYZ bloodvel;
- XYZ bloodloc;
- bloodloc = position + (tippoint - position) * .7;
- bloodloc.y -= .05;
- if (bloodtoggle) {
- bloodvel = 0;
- Sprite::MakeSprite(bloodsprite, bloodloc, bloodvel, 1, 1, 1, .03, 1);
- }
- }
- }
- if (onfire) {
- flamedelay -= multiplier;
- if (onfire && flamedelay <= 0) {
- flamedelay = .020;
- flamedelay -= multiplier;
- normalrot = 0;
- if (owner != -1) {
- normalrot = Person::players[owner]->velocity;
- }
- normalrot.y += 1;
- if (owner != -1) {
- if (Person::players[owner]->onterrain) {
- normalrot.y = 1;
- }
- }
- Sprite::MakeSprite(weaponflamesprite, position + tippoint * (((float)abs(Random() % 100)) / 600 + .05), normalrot, 1, 1, 1, (.6 + (float)abs(Random() % 100) / 200 - .25) * 1 / 3, 1);
- Sprite::setLastSpriteSpeed(4);
- Sprite::setLastSpriteAlivetime(.3);
- }
- }
-
- if (!onfire && owner == -1 && type != staff) {
- flamedelay -= multiplier;
- if (flamedelay <= 0) {
- flamedelay = .020;
- flamedelay -= multiplier;
- normalrot = 0;
- if (Random() % 50 == 0 && distsq(&position, &viewer) > 80) {
- XYZ shinepoint;
- shinepoint = position + (tippoint - position) * (((float)abs(Random() % 100)) / 100);
- Sprite::MakeSprite(weaponshinesprite, shinepoint, normalrot, 1, 1, 1, (.1 + (float)abs(Random() % 100) / 200 - .25) * 1 / 3 * fast_sqrt(findDistance(&shinepoint, &viewer)), 1);
- Sprite::setLastSpriteSpeed(4);
- Sprite::setLastSpriteAlivetime(.3);
- }
- }
- }
-}
-
-void Weapons::DoStuff()
-{
- //Move
- int i = 0;
- for (std::vector<Weapon>::iterator weapon = begin(); weapon != end(); ++weapon) {
- weapon->DoStuff(i++);
- }
-}
-
-void Weapon::Draw()
-{
- static XYZ terrainlight;
- static GLfloat M[16];
-
- if ((frustum.SphereInFrustum(position.x, position.y, position.z, 1) &&
- distsq(&viewer, &position) < viewdistance * viewdistance)) {
- bool draw = false;
- if (owner == -1) {
- draw = true;
- if (velocity.x && !physics)
- drawhowmany = 10;
- else
- drawhowmany = 1;
- } else {
- if (Person::players[owner]->occluded < 25)
- if ((frustum.SphereInFrustum(Person::players[owner]->coords.x, Person::players[owner]->coords.y + Person::players[owner]->scale * 3, Person::players[owner]->coords.z, Person::players[owner]->scale * 8) && distsq(&viewer, &Person::players[owner]->coords) < viewdistance * viewdistance) || Person::players[owner]->skeleton.free == 3)
- draw = true;
- if (
- (Person::players[owner]->animTarget == knifeslashstartanim ||
- Person::players[owner]->animTarget == swordsneakattackanim ||
- (Person::players[owner]->animCurrent == staffhitanim && Person::players[owner]->frameCurrent > 1) ||
- (Person::players[owner]->animCurrent == staffhitreversedanim && Person::players[owner]->frameCurrent > 1) ||
- (Person::players[owner]->animCurrent == staffspinhitanim && Person::players[owner]->frameCurrent > 1) ||
- (Person::players[owner]->animCurrent == staffspinhitreversedanim && Person::players[owner]->frameCurrent > 1) ||
- (Person::players[owner]->animCurrent == staffgroundsmashanim && Person::players[owner]->frameCurrent > 1) ||
- (Person::players[owner]->animTarget == swordslashanim && Person::players[owner]->frameTarget < 7) ||
- Person::players[owner]->animTarget == crouchstabanim ||
- Person::players[owner]->animTarget == swordslashreversalanim ||
- Person::players[owner]->animTarget == swordslashreversedanim ||
- Person::players[owner]->animTarget == knifefollowanim ||
- Person::players[owner]->animTarget == swordgroundstabanim ||
- Person::players[owner]->animTarget == knifethrowanim) &&
- Person::players[owner]->animTarget == lastdrawnanim &&
- !Person::players[owner]->skeleton.free
- ) {
- drawhowmany = 10;
- } else {
- drawhowmany = 1;
- }
- if (Person::players[owner]->animTarget == swordgroundstabanim) {
- lastdrawnrotation1 = rotation1;
- lastdrawnrotation2 = rotation2;
- lastdrawnrotation3 = rotation3;
- lastdrawnbigrotation = bigrotation;
- lastdrawnbigtilt = bigtilt;
- lastdrawnbigtilt2 = bigtilt2;
- lastdrawnsmallrotation = smallrotation;
- lastdrawnsmallrotation2 = smallrotation2;
- }
- }
- if (draw) {
- terrainlight = terrain.getLighting(position.x, position.z);
- if (drawhowmany > 0) {
- glAlphaFunc(GL_GREATER, 0.01);
- }
- for (int j = drawhowmany; j > 0; j--) {
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, j / drawhowmany);
- if (owner == -1)
- glTranslatef(position.x * (((float)(j)) / drawhowmany) + lastdrawnposition.x * (1 - ((float)(j)) / drawhowmany), position.y * (((float)(j)) / drawhowmany) + lastdrawnposition.y * (1 - ((float)(j)) / drawhowmany), position.z * (((float)(j)) / drawhowmany) + lastdrawnposition.z * (1 - ((float)(j)) / drawhowmany));
- else
- glTranslatef(position.x * (((float)(j)) / drawhowmany) + lastdrawnposition.x * (1 - ((float)(j)) / drawhowmany), position.y * (((float)(j)) / drawhowmany) - .02 + lastdrawnposition.y * (1 - ((float)(j)) / drawhowmany), position.z * (((float)(j)) / drawhowmany) + lastdrawnposition.z * (1 - ((float)(j)) / drawhowmany));
- glRotatef(bigrotation * (((float)(j)) / drawhowmany) + lastdrawnbigrotation * (1 - ((float)(j)) / drawhowmany), 0, 1, 0);
- glRotatef(bigtilt2 * (((float)(j)) / drawhowmany) + lastdrawnbigtilt2 * (1 - ((float)(j)) / drawhowmany), 1, 0, 0);
- glRotatef(bigtilt * (((float)(j)) / drawhowmany) + lastdrawnbigtilt * (1 - ((float)(j)) / drawhowmany), 0, 0, 1);
- glRotatef(-rotation1 * (((float)(j)) / drawhowmany) - lastdrawnrotation1 * (1 - ((float)(j)) / drawhowmany) + 90, 0, 1, 0);
- glRotatef(-rotation2 * (((float)(j)) / drawhowmany) - lastdrawnrotation2 * (1 - ((float)(j)) / drawhowmany) + 90, 0, 0, 1);
- glRotatef(-rotation3 * (((float)(j)) / drawhowmany) - lastdrawnrotation3 * (1 - ((float)(j)) / drawhowmany), 0, 1, 0);
- glRotatef(smallrotation * (((float)(j)) / drawhowmany) + lastdrawnsmallrotation * (1 - ((float)(j)) / drawhowmany), 1, 0, 0);
- glRotatef(smallrotation2 * (((float)(j)) / drawhowmany) + lastdrawnsmallrotation2 * (1 - ((float)(j)) / drawhowmany), 0, 1, 0);
-
- if (owner != -1) {
- if (Person::players[owner]->animTarget == staffhitanim || Person::players[owner]->animCurrent == staffhitanim || Person::players[owner]->animTarget == staffhitreversedanim || Person::players[owner]->animCurrent == staffhitreversedanim) {
- glTranslatef(0, 0, -.3);
- }
- if (Person::players[owner]->animTarget == staffgroundsmashanim || Person::players[owner]->animCurrent == staffgroundsmashanim || Person::players[owner]->animTarget == staffspinhitreversedanim || Person::players[owner]->animCurrent == staffspinhitreversedanim || Person::players[owner]->animTarget == staffspinhitanim || Person::players[owner]->animCurrent == staffspinhitanim) {
- glTranslatef(0, 0, -.1);
- }
- }
-
- glEnable(GL_LIGHTING);
- switch (type) {
- case knife:
- if (!bloody || !bloodtoggle)
- throwingknifemodel.drawdifftex(knifetextureptr);
- if (bloodtoggle) {
- if (bloody == 1)
- throwingknifemodel.drawdifftex(lightbloodknifetextureptr);
- if (bloody == 2)
- throwingknifemodel.drawdifftex(bloodknifetextureptr);
- }
- break;
- case sword:
- if (!bloody || !bloodtoggle)
- swordmodel.drawdifftex(swordtextureptr);
- if (bloodtoggle) {
- if (bloody == 1)
- swordmodel.drawdifftex(lightbloodswordtextureptr);
- if (bloody == 2)
- swordmodel.drawdifftex(bloodswordtextureptr);
- }
- break;
- case staff:
- staffmodel.drawdifftex(stafftextureptr);
- break;
- }
-
- glPopMatrix();
- }
-
- lastdrawnposition = position;
- lastdrawntippoint = tippoint;
- lastdrawnrotation1 = rotation1;
- lastdrawnrotation2 = rotation2;
- lastdrawnrotation3 = rotation3;
- lastdrawnbigrotation = bigrotation;
- lastdrawnbigtilt = bigtilt;
- lastdrawnbigtilt2 = bigtilt2;
- lastdrawnsmallrotation = smallrotation;
- lastdrawnsmallrotation2 = smallrotation2;
- if (owner != -1)
- lastdrawnanim = Person::players[owner]->animCurrent;
- }
- if (owner != -1) {
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadIdentity();
- glTranslatef(position.x, position.y - .02, position.z);
- glRotatef(bigrotation, 0, 1, 0);
- glRotatef(bigtilt2, 1, 0, 0);
- glRotatef(bigtilt, 0, 0, 1);
- glRotatef(-rotation1 + 90, 0, 1, 0);
- glRotatef(-rotation2 + 90, 0, 0, 1);
- glRotatef(-rotation3, 0, 1, 0);
- glRotatef(smallrotation, 1, 0, 0);
- glRotatef(smallrotation2, 0, 1, 0);
- glTranslatef(0, 0, length);
- glGetFloatv(GL_MODELVIEW_MATRIX, M);
- tippoint.x = M[12];
- tippoint.y = M[13];
- tippoint.z = M[14];
- glPopMatrix();
- }
- }
-}
-
-void Weapon::drop(XYZ v, XYZ tv, bool sethitsomething)
-{
- owner = -1;
- velocity = v;
- tipvelocity = tv;
- missed = 1;
- if (sethitsomething) {
- hitsomething = 0;
- }
- freetime = 0;
- firstfree = 1;
- physics = 1;
-}
-
-void Weapon::thrown(XYZ v, bool sethitsomething)
-{
- drop(v, v, sethitsomething);
- missed = 0;
- physics = 0;
-}
-
-int Weapons::Draw()
-{
- glAlphaFunc(GL_GREATER, 0.9);
- glEnable(GL_TEXTURE_2D);
- glEnable(GL_BLEND);
- glEnable(GL_CULL_FACE);
- glCullFace(GL_FRONT);
- glDepthMask(1);
-
- for (std::vector<Weapon>::iterator weapon = begin(); weapon != end(); ++weapon) {
- weapon->Draw();
- }
- return 0;
-}
-
-Weapons::Weapons()
-{
-}
-
-Weapons::~Weapons()
-{
- Weapon::stafftextureptr.destroy();
- Weapon::knifetextureptr.destroy();
- Weapon::lightbloodknifetextureptr.destroy();
- Weapon::bloodknifetextureptr.destroy();
- Weapon::swordtextureptr.destroy();
- Weapon::lightbloodswordtextureptr.destroy();
- Weapon::bloodswordtextureptr.destroy();
-}
-
+++ /dev/null
-/*
-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 _WEAPONS_H_
-#define _WEAPONS_H_
-
-/**> HEADER FILES <**/
-
-#include "gamegl.h"
-#include "Quaternions.h"
-#include "Animation/Skeleton.h"
-#include "Models.h"
-#include "Terrain.h"
-#include "Sprite.h"
-#include "Person.h"
-#include "Texture.h"
-#include <cmath>
-
-#define max_weapons 30
-#define max_weaponinstances 20
-
-#define knife 1
-#define sword 2
-#define staff 3
-
-class Weapon
-{
-public:
- Weapon(int type, int owner);
-
- static Model throwingknifemodel;
- static Texture knifetextureptr;
- static Texture lightbloodknifetextureptr;
- static Texture bloodknifetextureptr;
-
- static Model swordmodel;
- static Texture swordtextureptr;
- static Texture lightbloodswordtextureptr;
- static Texture bloodswordtextureptr;
-
- static Model staffmodel;
- static Texture stafftextureptr;
-
- void Draw();
- void DoStuff(int);
-
- int getType() {
- return type;
- }
- void setType(int);
-
- void drop(XYZ velocity, XYZ tipvelocity, bool sethitsomething = true);
- void thrown(XYZ velocity, bool sethitsomething = true);
-
- int owner;
- XYZ position;
- XYZ tippoint;
- XYZ velocity;
- XYZ tipvelocity;
- bool missed;
- bool hitsomething;
- float freetime;
- bool firstfree;
- bool physics;
-
- float damage;
- int bloody;
- float blooddrip;
- float blooddripdelay;
-
- float rotation1;
- float rotation2;
- float rotation3;
- float bigrotation;
- float bigtilt;
- float bigtilt2;
- float smallrotation;
- float smallrotation2;
-private:
- int type;
-
- XYZ oldtippoint;
- XYZ oldposition;
- int oldowner;
- bool onfire;
- float flamedelay;
- float mass;
- float tipmass;
- float length;
- float drawhowmany;
-
- XYZ lastdrawnposition;
- XYZ lastdrawntippoint;
- float lastdrawnrotation1;
- float lastdrawnrotation2;
- float lastdrawnrotation3;
- float lastdrawnbigrotation;
- float lastdrawnbigtilt;
- float lastdrawnbigtilt2;
- float lastdrawnsmallrotation;
- float lastdrawnsmallrotation2;
- int lastdrawnanim;
-};
-
-class Weapons : public std::vector<Weapon>
-{
-public:
- Weapons();
- ~Weapons();
-
- int Draw();
- void DoStuff();
-};
-
-extern Weapons weapons;
-#endif
typedef unsigned int UInt32;
-#include "Random.h"
+#include "Math/Random.h"
typedef struct AbsoluteTime {
+++ /dev/null
-/*
-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 binio_h
-#define binio_h
-
-#include <stdarg.h>
-#include <stdio.h>
-
-#if defined(__cplusplus)
-extern "C" {
-#endif
-
- /*
- Notes on format of format strings:
- * whitespace is ignored
- * each "group" consists of an optional count (defaults to 1),
- an optional byte-order marker (defaults to H, "host-native"),
- and a data-type specifier.
- * when unpacking, each variable argument is a pointer to the
- appropriate number of objects of the appropriate type.
- * when packing, each variable argument is an object of the
- appropriate type if the count is omitted, or a pointer to the
- appropriate number of objects of the appropriate type if the
- count is specified.
- * the buffer supplied to pack/unpack must be of sufficient length
- to hold all the data, or the behavior is unspecified.
- * the file provided to the "f" versions of the functions must be
- open in the appropriate mode, or the behavior is unspecified.
- * the file supplied to funpackf must be of sufficient length to
- hold all the data, or the behavior is unspecified.
- * the behavior of all functions is unspecified if the format string
- is incorrectly-formed.
-
- Data-type specifiers:
- x skipped byte; no corresponding argument
- b byte
- s two-byte two's-complement integer
- i four-byte two's-complement integer
- l eight-byte two's-complement integer
- f four-byte IEEE754 float
- d eight-byte IEEE754 double
-
- Byte-order specifiers:
- L little-endian
- B big-endian
- H host's native byte order
- N network byte order
- */
-
-#ifndef ALREADY_DID_BINIO_STDINT
-#define ALREADY_DID_BINIO_STDINT
-#if defined(BinIO_STDINT_HEADER)
-#include BinIO_STDINT_HEADER
- typedef float float32_t;
- typedef double float64_t;
-#else
- typedef unsigned char uint8_t;
- typedef unsigned short uint16_t;
- typedef unsigned long uint32_t;
-#ifdef WIN32
- typedef unsigned __int64 uint64_t;
-#else
- typedef unsigned long long uint64_t;
-#endif
- typedef float float32_t;
- typedef double float64_t;
-#endif
-#endif
-
- typedef struct {
- float64_t d;
- uint64_t l;
- int i;
- float32_t f;
- uint16_t s;
- uint8_t b;
- }
- test_data;
-
- extern void packf ( const char *format, ...);
- extern void spackf (void *buffer, const char *format, ...);
- extern void fpackf (FILE *file, const char *format, ...);
- extern void vspackf (void *buffer, const char *format, va_list args);
- extern void vfpackf (FILE *file, const char *format, va_list args);
-
- extern void unpackf ( const char *format, ...);
- extern void sunpackf (const void *buffer, const char *format, ...);
- extern void funpackf (FILE *file, const char *format, ...);
- extern void vsunpackf(const void *buffer, const char *format, va_list args);
- extern void vfunpackf(FILE *file, const char *format, va_list args);
-
-#ifdef _MSC_VER
-#ifndef va_copy
-#define va_copy(dest,src) do { dest = src; } while (0)
-#endif
-#endif
-
-#if defined(__cplusplus)
-}
-#endif
-
-#endif
-
+++ /dev/null
-/*
-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 _LUGARU_GL_H_
-#define _LUGARU_GL_H_
-
-
-#include <cstring>
-#include <iostream>
-#include <fstream>
-#include <algorithm>
-#include <map>
-#include <string>
-
-#ifdef WIN32
- #define WIN32_LEAN_AND_MEAN
- #define Polygon WinPolygon
- #include <windows.h>
- #undef Polygon
-#endif
-
-#define GL_GLEXT_PROTOTYPES 1
-#include "GL/gl.h"
-#include "GL/glu.h"
-#include "GL/glext.h"
-#include "MacCompatibility.h"
-
-using namespace std;
-
-/* !!! FIXME: until we replace logger better. --ryan. */
-#define LOGFUNC
-void LOG(const std::string &fmt, ...);
-
-#endif
-
-
#include <iostream>
#include <zlib.h>
#include <set>
-#include "gamegl.h"
#include "MacCompatibility.h"
-#include "Settings.h"
+#include "Graphic/gamegl.h"
+#include "User/Settings.h"
#include "Game.h"
using namespace Game;
-#include "openal_wrapper.h"
+#include "Audio/openal_wrapper.h"
#ifdef WIN32
#include <windows.h>
+++ /dev/null
-/*
-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/>.
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "Quaternions.h"
-#include "openal_wrapper.h"
-#include "Sounds.h"
-#include "Game.h"
-
-extern float slomofreq;
-
-// NOTE:
-// FMOD uses a Left Handed Coordinate system, OpenAL uses a Right Handed
-// one...so we just need to flip the sign on the Z axis when appropriate.
-
-typedef struct {
- ALuint sid;
- OPENAL_SAMPLE *sample;
- bool startpaused;
- float position[3];
-} OPENAL_Channels;
-
-typedef struct OPENAL_SAMPLE {
- char *name;
- ALuint bid; // buffer id.
- int mode;
- int is2d;
-} OPENAL_SAMPLE;
-
-static size_t num_channels = 0;
-static OPENAL_Channels *impl_channels = NULL;
-static bool initialized = false;
-static float listener_position[3];
-
-static void set_channel_position(const int channel, const float x,
- const float y, const float z)
-{
- OPENAL_Channels *chan = &impl_channels[channel];
-
- chan->position[0] = x;
- chan->position[1] = y;
- chan->position[2] = z;
-
- OPENAL_SAMPLE *sptr = chan->sample;
- if (sptr == NULL)
- return;
-
- const ALuint sid = chan->sid;
- const bool no_attenuate = sptr->is2d;
-
- if (no_attenuate) {
- alSourcei(sid, AL_SOURCE_RELATIVE, AL_TRUE);
- alSource3f(sid, AL_POSITION, 0.0f, 0.0f, 0.0f);
- } else {
- alSourcei(sid, AL_SOURCE_RELATIVE, AL_FALSE);
- alSource3f(sid, AL_POSITION, x, y, z);
- }
-}
-
-
-AL_API void OPENAL_3D_Listener_SetAttributes(const float *pos, const float *vel, float fx, float fy, float fz, float tx, float ty, float tz)
-{
- if (!initialized)
- return;
- if (pos != NULL) {
- alListener3f(AL_POSITION, pos[0], pos[1], -pos[2]);
- listener_position[0] = pos[0];
- listener_position[1] = pos[1];
- listener_position[2] = -pos[2];
- }
-
- ALfloat vec[6] = { fx, fy, -fz, tz, ty, -tz };
- alListenerfv(AL_ORIENTATION, vec);
-
- // we ignore velocity, since doppler's broken in the Linux AL at the moment...
-
- // adjust existing positions...
- for (int i = 0; i < num_channels; i++) {
- const float *p = impl_channels[i].position;
- set_channel_position(i, p[0], p[1], p[2]);
- }
-}
-
-AL_API signed char OPENAL_3D_SetAttributes(int channel, const float *pos, const float *vel)
-{
- if (!initialized)
- return false;
- if ((channel < 0) || (channel >= num_channels))
- return false;
-
- if (pos != NULL)
- set_channel_position(channel, pos[0], pos[1], -pos[2]);
-
- // we ignore velocity, since doppler's broken in the Linux AL at the moment...
-
- return true;
-}
-
-AL_API signed char OPENAL_3D_SetAttributes_(int channel, const XYZ &pos, const float *vel)
-{
- if (!initialized)
- return false;
- if ((channel < 0) || (channel >= num_channels))
- return false;
-
- set_channel_position(channel, pos.x, pos.y, -pos.z);
-
- return true;
-}
-
-AL_API signed char OPENAL_Init(int mixrate, int maxsoftwarechannels, unsigned int flags)
-{
- if (initialized)
- return false;
- if (maxsoftwarechannels == 0)
- return false;
-
- if (flags != 0) // unsupported.
- return false;
-
- ALCdevice *dev = alcOpenDevice(NULL);
- if (!dev)
- return false;
-
- ALint caps[] = { ALC_FREQUENCY, mixrate, 0 };
- ALCcontext *ctx = alcCreateContext(dev, caps);
- if (!ctx) {
- alcCloseDevice(dev);
- return false;
- }
-
- alcMakeContextCurrent(ctx);
- alcProcessContext(ctx);
-
- if (commandLineOptions[OPENALINFO]) {
- printf("AL_VENDOR: %s\n", (char *) alGetString(AL_VENDOR));
- printf("AL_RENDERER: %s\n", (char *) alGetString(AL_RENDERER));
- printf("AL_VERSION: %s\n", (char *) alGetString(AL_VERSION));
- printf("AL_EXTENSIONS: %s\n", (char *) alGetString(AL_EXTENSIONS));
- }
-
- num_channels = maxsoftwarechannels;
- impl_channels = new OPENAL_Channels[maxsoftwarechannels];
- memset(impl_channels, '\0', sizeof (OPENAL_Channels) * num_channels);
- for (int i = 0; i < num_channels; i++)
- alGenSources(1, &impl_channels[i].sid); // !!! FIXME: verify this didn't fail!
-
- initialized = true;
- return true;
-}
-
-AL_API void OPENAL_Close()
-{
- if (!initialized)
- return;
-
- ALCcontext *ctx = alcGetCurrentContext();
- if (ctx) {
- for (int i = 0; i < num_channels; i++) {
- alSourceStop(impl_channels[i].sid);
- alSourcei(impl_channels[i].sid, AL_BUFFER, 0);
- alDeleteSources(1, &impl_channels[i].sid);
- }
- ALCdevice *dev = alcGetContextsDevice(ctx);
- alcMakeContextCurrent(NULL);
- alcSuspendContext(ctx);
- alcDestroyContext(ctx);
- alcCloseDevice(dev);
- }
-
- num_channels = 0;
- delete[] impl_channels;
- impl_channels = NULL;
-
- initialized = false;
-}
-
-static OPENAL_SAMPLE *OPENAL_GetCurrentSample(int channel)
-{
- if (!initialized)
- return NULL;
- if ((channel < 0) || (channel >= num_channels))
- return NULL;
- return impl_channels[channel].sample;
-}
-
-static signed char OPENAL_GetPaused(int channel)
-{
- if (!initialized)
- return false;
- if ((channel < 0) || (channel >= num_channels))
- return false;
- if (impl_channels[channel].startpaused)
- return(true);
-
- ALint state = 0;
- alGetSourceiv(impl_channels[channel].sid, AL_SOURCE_STATE, &state);
- return((state == AL_PAUSED) ? true : false);
-}
-
-static unsigned int OPENAL_GetLoopMode(int channel)
-{
- if (!initialized)
- return 0;
- if ((channel < 0) || (channel >= num_channels))
- return 0;
- ALint loop = 0;
- alGetSourceiv(impl_channels[channel].sid, AL_LOOPING, &loop);
- if (loop)
- return(OPENAL_LOOP_NORMAL);
- return OPENAL_LOOP_OFF;
-}
-
-static signed char OPENAL_IsPlaying(int channel)
-{
- if (!initialized)
- return false;
- if ((channel < 0) || (channel >= num_channels))
- return false;
- ALint state = 0;
- alGetSourceiv(impl_channels[channel].sid, AL_SOURCE_STATE, &state);
- return((state == AL_PLAYING) ? true : false);
-}
-
-static int OPENAL_PlaySoundEx(int channel, OPENAL_SAMPLE *sptr, OPENAL_DSPUNIT *dsp, signed char startpaused)
-{
- if (!initialized)
- return -1;
- if (sptr == NULL)
- return -1;
- if (dsp != NULL)
- return -1;
- if (channel == OPENAL_FREE) {
- for (int i = 0; i < num_channels; i++) {
- ALint state = 0;
- alGetSourceiv(impl_channels[i].sid, AL_SOURCE_STATE, &state);
- if ((state != AL_PLAYING) && (state != AL_PAUSED)) {
- channel = i;
- break;
- }
- }
- }
-
- if ((channel < 0) || (channel >= num_channels))
- return -1;
- alSourceStop(impl_channels[channel].sid);
- impl_channels[channel].sample = sptr;
- alSourcei(impl_channels[channel].sid, AL_BUFFER, sptr->bid);
- alSourcei(impl_channels[channel].sid, AL_LOOPING, (sptr->mode == OPENAL_LOOP_OFF) ? AL_FALSE : AL_TRUE);
- set_channel_position(channel, 0.0f, 0.0f, 0.0f);
-
- impl_channels[channel].startpaused = ((startpaused) ? true : false);
- if (!startpaused)
- alSourcePlay(impl_channels[channel].sid);
- return channel;
-}
-
-
-static void *decode_to_pcm(const char *_fname, ALenum &format, ALsizei &size, ALuint &freq)
-{
-#ifdef __POWERPC__
- const int bigendian = 1;
-#else
- const int bigendian = 0;
-#endif
-
- // !!! FIXME: if it's not Ogg, we don't have a decoder. I'm lazy. :/
- char *fname = (char *) alloca(strlen(_fname) + 16);
- strcpy(fname, _fname);
- char *ptr = strchr(fname, '.');
- if (ptr)
- *ptr = '\0';
- strcat(fname, ".ogg");
-
- // just in case...
- FILE *io = fopen(fname, "rb");
- if (io == NULL)
- return NULL;
-
- ALubyte *retval = NULL;
-
-#if 0 // untested, so disable this!
- // Can we just feed it to the AL compressed?
- if (alIsExtensionPresent((const ALubyte *) "AL_EXT_vorbis")) {
- format = alGetEnumValue((const ALubyte *) "AL_FORMAT_VORBIS_EXT");
- freq = 44100;
- fseek(io, 0, SEEK_END);
- size = ftell(io);
- fseek(io, 0, SEEK_SET);
- retval = (ALubyte *) malloc(size);
- size_t rc = fread(retval, size, 1, io);
- fclose(io);
- if (rc != 1) {
- free(retval);
- return NULL;
- }
- return retval;
- }
-#endif
-
- // Uncompress and feed to the AL.
- OggVorbis_File vf;
- memset(&vf, '\0', sizeof (vf));
- if (ov_open(io, &vf, NULL, 0) == 0) {
- int bitstream = 0;
- vorbis_info *info = ov_info(&vf, -1);
- size = 0;
- format = (info->channels == 1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
- freq = info->rate;
-
- if ((info->channels != 1) && (info->channels != 2)) {
- ov_clear(&vf);
- return NULL;
- }
-
- char buf[1024 * 16];
- long rc = 0;
- size_t allocated = 64 * 1024;
- retval = (ALubyte *) malloc(allocated);
- while ( (rc = ov_read(&vf, buf, sizeof (buf), bigendian, 2, 1, &bitstream)) != 0 ) {
- if (rc > 0) {
- size += rc;
- if (size >= allocated) {
- allocated *= 2;
- ALubyte *tmp = (ALubyte *) realloc(retval, allocated);
- if (tmp == NULL) {
- free(retval);
- retval = NULL;
- break;
- }
- retval = tmp;
- }
- memcpy(retval + (size - rc), buf, rc);
- }
- }
- ov_clear(&vf);
- return retval;
- }
-
- fclose(io);
- return NULL;
-}
-
-
-AL_API OPENAL_SAMPLE *OPENAL_Sample_Load(int index, const char *name_or_data, unsigned int mode, int offset, int length)
-{
- if (!initialized)
- return NULL;
- if (index != OPENAL_FREE)
- return NULL; // this is all the game does...
- if (offset != 0)
- return NULL; // this is all the game does...
- if (length != 0)
- return NULL; // this is all the game does...
- if ((mode != OPENAL_HW3D) && (mode != OPENAL_2D))
- return NULL; // this is all the game does...
-
- OPENAL_SAMPLE *retval = NULL;
- ALenum format = AL_NONE;
- ALsizei size = 0;
- ALuint frequency = 0;
- void *data = decode_to_pcm(name_or_data, format, size, frequency);
- if (data == NULL)
- return NULL;
-
- ALuint bid = 0;
- alGetError();
- alGenBuffers(1, &bid);
- if (alGetError() == AL_NO_ERROR) {
- alBufferData(bid, format, data, size, frequency);
- retval = new OPENAL_SAMPLE;
- retval->bid = bid;
- retval->mode = OPENAL_LOOP_OFF;
- retval->is2d = (mode == OPENAL_2D);
- retval->name = new char[strlen(name_or_data) + 1];
- if (retval->name)
- strcpy(retval->name, name_or_data);
- }
-
- free(data);
- return(retval);
-}
-
-AL_API void OPENAL_Sample_Free(OPENAL_SAMPLE *sptr)
-{
- if (!initialized)
- return;
- if (sptr) {
- for (int i = 0; i < num_channels; i++) {
- if (impl_channels[i].sample == sptr) {
- alSourceStop(impl_channels[i].sid);
- alSourcei(impl_channels[i].sid, AL_BUFFER, 0);
- impl_channels[i].sample = NULL;
- }
- }
- alDeleteBuffers(1, &sptr->bid);
- delete[] sptr->name;
- delete sptr;
- }
-}
-
-static signed char OPENAL_Sample_SetMode(OPENAL_SAMPLE *sptr, unsigned int mode)
-{
- if (!initialized)
- return false;
- if ((mode != OPENAL_LOOP_NORMAL) && (mode != OPENAL_LOOP_OFF))
- return false;
- if (!sptr)
- return false;
- sptr->mode = mode;
- return true;
-}
-
-AL_API signed char OPENAL_SetFrequency(int channel, bool slomo)
-{
- if (!initialized)
- return false;
- if (channel == OPENAL_ALL) {
- for (int i = 0; i < num_channels; i++)
- OPENAL_SetFrequency(i, slomo);
- return true;
- }
-
- if ((channel < 0) || (channel >= num_channels))
- return false;
- if (slomo)
- alSourcef(impl_channels[channel].sid, AL_PITCH, ((ALfloat) slomofreq) / 44100.0f);
- else
- alSourcef(impl_channels[channel].sid, AL_PITCH, 1.0f);
- return true;
-}
-
-AL_API signed char OPENAL_SetVolume(int channel, int vol)
-{
- if (!initialized)
- return false;
-
- if (channel == OPENAL_ALL) {
- for (int i = 0; i < num_channels; i++)
- OPENAL_SetVolume(i, vol);
- return true;
- }
-
- if ((channel < 0) || (channel >= num_channels))
- return false;
-
- if (vol < 0)
- vol = 0;
- else if (vol > 255)
- vol = 255;
- ALfloat gain = ((ALfloat) vol) / 255.0f;
- alSourcef(impl_channels[channel].sid, AL_GAIN, gain);
- return true;
-}
-
-AL_API signed char OPENAL_SetPaused(int channel, signed char paused)
-{
- if (!initialized)
- return false;
-
- if (channel == OPENAL_ALL) {
- for (int i = 0; i < num_channels; i++)
- OPENAL_SetPaused(i, paused);
- return true;
- }
-
- if ((channel < 0) || (channel >= num_channels))
- return false;
-
- ALint state = 0;
- if (impl_channels[channel].startpaused)
- state = AL_PAUSED;
- else
- alGetSourceiv(impl_channels[channel].sid, AL_SOURCE_STATE, &state);
-
- if ((paused) && (state == AL_PLAYING))
- alSourcePause(impl_channels[channel].sid);
- else if ((!paused) && (state == AL_PAUSED)) {
- alSourcePlay(impl_channels[channel].sid);
- impl_channels[channel].startpaused = false;
- }
- return true;
-}
-
-AL_API void OPENAL_SetSFXMasterVolume(int volume)
-{
- if (!initialized)
- return;
- ALfloat gain = ((ALfloat) volume) / 255.0f;
- alListenerf(AL_GAIN, gain);
-}
-
-AL_API signed char OPENAL_StopSound(int channel)
-{
- if (!initialized)
- return false;
-
- if (channel == OPENAL_ALL) {
- for (int i = 0; i < num_channels; i++)
- OPENAL_StopSound(i);
- return true;
- }
-
- if ((channel < 0) || (channel >= num_channels))
- return false;
- alSourceStop(impl_channels[channel].sid);
- impl_channels[channel].startpaused = false;
- return true;
-}
-
-static OPENAL_SAMPLE *OPENAL_Stream_GetSample(OPENAL_STREAM *stream)
-{
- if (!initialized)
- return NULL;
- return (OPENAL_SAMPLE *) stream;
-}
-
-static int OPENAL_Stream_PlayEx(int channel, OPENAL_STREAM *stream, OPENAL_DSPUNIT *dsp, signed char startpaused)
-{
- return OPENAL_PlaySoundEx(channel, (OPENAL_SAMPLE *) stream, dsp, startpaused);
-}
-
-static signed char OPENAL_Stream_Stop(OPENAL_STREAM *stream)
-{
- if (!initialized)
- return false;
- for (int i = 0; i < num_channels; i++) {
- if (impl_channels[i].sample == (OPENAL_SAMPLE *) stream) {
- alSourceStop(impl_channels[i].sid);
- impl_channels[i].startpaused = false;
- }
- }
- return true;
-}
-
-AL_API signed char OPENAL_Stream_SetMode(OPENAL_STREAM *stream, unsigned int mode)
-{
- return OPENAL_Sample_SetMode((OPENAL_SAMPLE *) stream, mode);
-}
-
-AL_API void OPENAL_Update()
-{
- if (!initialized)
- return;
- alcProcessContext(alcGetCurrentContext());
-}
-
-AL_API signed char OPENAL_SetOutput(int outputtype)
-{
- return true;
-}
-
-extern int channels[];
-
-extern "C" void PlaySoundEx(int chan, OPENAL_SAMPLE *sptr, OPENAL_DSPUNIT *dsp, signed char startpaused)
-{
- const OPENAL_SAMPLE * currSample = OPENAL_GetCurrentSample(channels[chan]);
- if (currSample && currSample == samp[chan]) {
- if (OPENAL_GetPaused(channels[chan])) {
- OPENAL_StopSound(channels[chan]);
- channels[chan] = OPENAL_FREE;
- } else if (OPENAL_IsPlaying(channels[chan])) {
- int loop_mode = OPENAL_GetLoopMode(channels[chan]);
- if (loop_mode & OPENAL_LOOP_OFF) {
- channels[chan] = OPENAL_FREE;
- }
- }
- } else {
- channels[chan] = OPENAL_FREE;
- }
-
- channels[chan] = OPENAL_PlaySoundEx(channels[chan], sptr, dsp, startpaused);
- if (channels[chan] < 0) {
- channels[chan] = OPENAL_PlaySoundEx(OPENAL_FREE, sptr, dsp, startpaused);
- }
-}
-
-extern "C" void PlayStreamEx(int chan, OPENAL_STREAM *sptr, OPENAL_DSPUNIT *dsp, signed char startpaused)
-{
- const OPENAL_SAMPLE * currSample = OPENAL_GetCurrentSample(channels[chan]);
- if (currSample && currSample == OPENAL_Stream_GetSample(sptr)) {
- OPENAL_StopSound(channels[chan]);
- OPENAL_Stream_Stop(sptr);
- } else {
- OPENAL_Stream_Stop(sptr);
- channels[chan] = OPENAL_FREE;
- }
-
- channels[chan] = OPENAL_Stream_PlayEx(channels[chan], sptr, dsp, startpaused);
- if (channels[chan] < 0) {
- channels[chan] = OPENAL_Stream_PlayEx(OPENAL_FREE, sptr, dsp, startpaused);
- }
-}
+++ /dev/null
-/*
-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 OPENAL_WRAPPER_H
-#define OPENAL_WRAPPER_H
-
-#ifdef _WIN32
-#include <malloc.h>
-#endif
-
-#include "AL/al.h"
-#include "AL/alc.h"
-
-#include "ogg/ogg.h"
-#include "vorbis/vorbisfile.h"
-
-#include "MacCompatibility.h"
-
-#if 0 /* this should only be enable if OPENAL doesn't provide AL_API on all platforms */
-#if (!defined(WIN32) && !defined(_WIN32) && !defined(__WIN32__) && !defined(_WIN64) && !defined(_WIN32_WCE) && !defined(_XBOX)) || (defined(__GNUC__) && defined(WIN32))
-#ifndef __cdecl
-#define __cdecl
-#endif
-#ifndef __stdcall
-#define __stdcall
-#endif
-#endif
-
-#if defined(_WIN32_WCE)
-#define AL_API _cdecl
-#define F_CALLBACKAPI _cdecl
-#else
-#define AL_API __stdcall
-#define F_CALLBACKAPI __stdcall
-#endif
-
-#ifdef DLL_EXPORTS
-#define DLL_API __declspec(dllexport)
-#else
-#if defined(__LCC__) || defined(__MINGW32__) || defined(__CYGWIN32__)
-#define DLL_API AL_API
-#else
-#define DLL_API
-#endif /* __LCC__ || __MINGW32__ || __CYGWIN32__ */
-#endif /* DLL_EXPORTS */
-#endif /* if 0 */
-
-
-typedef struct OPENAL_SAMPLE OPENAL_SAMPLE;
-typedef OPENAL_SAMPLE OPENAL_STREAM;
-typedef struct OPENAL_DSPUNIT OPENAL_DSPUNIT;
-
-enum OPENAL_OUTPUTTYPES {
- OPENAL_OUTPUT_NOSOUND, /* NoSound driver, all calls to this succeed but do nothing. */
- OPENAL_OUTPUT_OSS, /* Linux/Unix OSS (Open Sound System) driver, i.e. the kernel sound drivers. */
- OPENAL_OUTPUT_ALSA, /* Linux Alsa driver. */
-};
-
-#define OPENAL_LOOP_OFF 0x00000001 /* For non looping samples. */
-#define OPENAL_LOOP_NORMAL 0x00000002 /* For forward looping samples. */
-#define OPENAL_HW3D 0x00001000 /* Attempts to make samples use 3d hardware acceleration. (if the card supports it) */
-#define OPENAL_2D 0x00002000 /* Tells software (not hardware) based sample not to be included in 3d processing. */
-#define OPENAL_FREE -1 /* value to play on any free channel, or to allocate a sample in a free sample slot. */
-#define OPENAL_ALL -3 /* for a channel index , this flag will affect ALL channels available! Not supported by every function. */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#undef AL_API
-#define AL_API
-
- AL_API void OPENAL_3D_Listener_SetAttributes(const float *pos, const float *vel, float fx, float fy, float fz, float tx, float ty, float tz);
- AL_API signed char OPENAL_3D_SetAttributes(int channel, const float *pos, const float *vel);
- AL_API signed char OPENAL_3D_SetAttributes_(int channel, const XYZ &pos, const float *vel);
- AL_API signed char OPENAL_Init(int mixrate, int maxsoftwarechannels, unsigned int flags);
- AL_API void OPENAL_Close();
- AL_API OPENAL_SAMPLE *OPENAL_Sample_Load(int index, const char *name_or_data, unsigned int mode, int offset, int length);
- AL_API void OPENAL_Sample_Free(OPENAL_SAMPLE *sptr);
- AL_API signed char OPENAL_SetFrequency(int channel, bool slomo = false);
- AL_API signed char OPENAL_SetVolume(int channel, int vol);
- AL_API signed char OPENAL_SetPaused(int channel, signed char paused);
- AL_API void OPENAL_SetSFXMasterVolume(int volume);
- AL_API signed char OPENAL_StopSound(int channel);
- AL_API signed char OPENAL_Stream_SetMode(OPENAL_STREAM *stream, unsigned int mode);
- AL_API void OPENAL_Update();
- AL_API signed char OPENAL_SetOutput(int outputtype);
- void PlaySoundEx(int chan, OPENAL_SAMPLE *sptr, OPENAL_DSPUNIT *dsp, signed char startpaused);
- void PlayStreamEx(int chan, OPENAL_SAMPLE *sptr, OPENAL_DSPUNIT *dsp, signed char startpaused);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
+++ /dev/null
-/*
- * The Lean Mean C++ Option Parser
- *
- * Copyright (C) 2012 Matthias S. Benkmann
- *
- * The "Software" in the following 2 paragraphs refers to this file containing
- * the code to The Lean Mean C++ Option Parser.
- * The "Software" does NOT refer to any other files which you
- * may have received alongside this file (e.g. as part of a larger project that
- * incorporates The Lean Mean C++ Option Parser).
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software, to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to permit
- * persons to whom the Software is furnished to do so, subject to the following
- * conditions:
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/*
- * NOTE: It is recommended that you read the processed HTML doxygen documentation
- * rather than this source. If you don't know doxygen, it's like javadoc for C++.
- * If you don't want to install doxygen you can find a copy of the processed
- * documentation at
- *
- * http://optionparser.sourceforge.net/
- *
- */
-
-/**
- * @file
- *
- * @brief This is the only file required to use The Lean Mean C++ Option Parser.
- * Just \#include it and you're set.
- *
- * The Lean Mean C++ Option Parser handles the program's command line arguments
- * (argc, argv).
- * It supports the short and long option formats of getopt(), getopt_long()
- * and getopt_long_only() but has a more convenient interface.
- * The following features set it apart from other option parsers:
- *
- * @par Highlights:
- * <ul style="padding-left:1em;margin-left:0">
- * <li> It is a header-only library. Just <code>\#include "optionparser.h"</code> and you're set.
- * <li> It is freestanding. There are no dependencies whatsoever, not even the
- * C or C++ standard library.
- * <li> It has a usage message formatter that supports column alignment and
- * line wrapping. This aids localization because it adapts to
- * translated strings that are shorter or longer (even if they contain
- * Asian wide characters).
- * <li> Unlike getopt() and derivatives it doesn't force you to loop through
- * options sequentially. Instead you can access options directly like this:
- * <ul style="margin-top:.5em">
- * <li> Test for presence of a switch in the argument vector:
- * @code if ( options[QUIET] ) ... @endcode
- * <li> Evaluate --enable-foo/--disable-foo pair where the last one used wins:
- * @code if ( options[FOO].last()->type() == DISABLE ) ... @endcode
- * <li> Cumulative option (-v verbose, -vv more verbose, -vvv even more verbose):
- * @code int verbosity = options[VERBOSE].count(); @endcode
- * <li> Iterate over all --file=<fname> arguments:
- * @code for (Option* opt = options[FILE]; opt; opt = opt->next())
- * fname = opt->arg; ... @endcode
- * <li> If you really want to, you can still process all arguments in order:
- * @code
- * for (int i = 0; i < p.optionsCount(); ++i) {
- * Option& opt = buffer[i];
- * switch(opt.index()) {
- * case HELP: ...
- * case VERBOSE: ...
- * case FILE: fname = opt.arg; ...
- * case UNKNOWN: ...
- * @endcode
- * </ul>
- * </ul> @n
- * Despite these features the code size remains tiny.
- * It is smaller than <a href="http://uclibc.org">uClibc</a>'s GNU getopt() and just a
- * couple 100 bytes larger than uClibc's SUSv3 getopt(). @n
- * (This does not include the usage formatter, of course. But you don't have to use that.)
- *
- * @par Download:
- * Tarball with examples and test programs:
- * <a style="font-size:larger;font-weight:bold" href="http://sourceforge.net/projects/optionparser/files/optionparser-1.4.tar.gz/download">optionparser-1.4.tar.gz</a> @n
- * Just the header (this is all you really need):
- * <a style="font-size:larger;font-weight:bold" href="http://optionparser.sourceforge.net/optionparser.h">optionparser.h</a>
- *
- * @par Changelog:
- * <b>Version 1.4:</b> Fixed 2 printUsage() bugs that messed up output with small COLUMNS values @n
- * <b>Version 1.3:</b> Compatible with Microsoft Visual C++. @n
- * <b>Version 1.2:</b> Added @ref option::Option::namelen "Option::namelen" and removed the extraction
- * of short option characters into a special buffer. @n
- * Changed @ref option::Arg::Optional "Arg::Optional" to accept arguments if they are attached
- * rather than separate. This is what GNU getopt() does and how POSIX recommends
- * utilities should interpret their arguments.@n
- * <b>Version 1.1:</b> Optional mode with argument reordering as done by GNU getopt(), so that
- * options and non-options can be mixed. See
- * @ref option::Parser::parse() "Parser::parse()".
- *
- * @par Feedback:
- * Send questions, bug reports, feature requests etc. to: <tt><b>optionparser-feedback<span id="antispam"> (a) </span>lists.sourceforge.net</b></tt>
- * @htmlonly <script type="text/javascript">document.getElementById("antispam").innerHTML="@"</script> @endhtmlonly
- *
- *
- * @par Example program:
- * (Note: @c option::* identifiers are links that take you to their documentation.)
- * @code
- * #error EXAMPLE SHORTENED FOR READABILITY. BETTER EXAMPLES ARE IN THE .TAR.GZ!
- * #include <iostream>
- * #include "optionparser.h"
- *
- * enum optionIndex { UNKNOWN, HELP, PLUS };
- * const option::Descriptor usage[] =
- * {
- * {UNKNOWN, 0,"" , "" ,option::Arg::None, "USAGE: example [options]\n\n"
- * "Options:" },
- * {HELP, 0,"" , "help",option::Arg::None, " --help \tPrint usage and exit." },
- * {PLUS, 0,"p", "plus",option::Arg::None, " --plus, -p \tIncrement count." },
- * {UNKNOWN, 0,"" , "" ,option::Arg::None, "\nExamples:\n"
- * " example --unknown -- --this_is_no_option\n"
- * " example -unk --plus -ppp file1 file2\n" },
- * {0,0,0,0,0,0}
- * };
- *
- * int main(int argc, char* argv[])
- * {
- * argc-=(argc>0); argv+=(argc>0); // skip program name argv[0] if present
- * option::Stats stats(usage, argc, argv);
- * option::Option options[stats.options_max], buffer[stats.buffer_max];
- * option::Parser parse(usage, argc, argv, options, buffer);
- *
- * if (parse.error())
- * return 1;
- *
- * if (options[HELP] || argc == 0) {
- * option::printUsage(std::cout, usage);
- * return 0;
- * }
- *
- * std::cout << "--plus count: " <<
- * options[PLUS].count() << "\n";
- *
- * for (option::Option* opt = options[UNKNOWN]; opt; opt = opt->next())
- * std::cout << "Unknown option: " << opt->name << "\n";
- *
- * for (int i = 0; i < parse.nonOptionsCount(); ++i)
- * std::cout << "Non-option #" << i << ": " << parse.nonOption(i) << "\n";
- * }
- * @endcode
- *
- * @par Option syntax:
- * @li The Lean Mean C++ Option Parser follows POSIX <code>getopt()</code> conventions and supports
- * GNU-style <code>getopt_long()</code> long options as well as Perl-style single-minus
- * long options (<code>getopt_long_only()</code>).
- * @li short options have the format @c -X where @c X is any character that fits in a char.
- * @li short options can be grouped, i.e. <code>-X -Y</code> is equivalent to @c -XY.
- * @li a short option may take an argument either separate (<code>-X foo</code>) or
- * attached (@c -Xfoo). You can make the parser accept the additional format @c -X=foo by
- * registering @c X as a long option (in addition to being a short option) and
- * enabling single-minus long options.
- * @li an argument-taking short option may be grouped if it is the last in the group, e.g.
- * @c -ABCXfoo or <code> -ABCX foo </code> (@c foo is the argument to the @c -X option).
- * @li a lone minus character @c '-' is not treated as an option. It is customarily used where
- * a file name is expected to refer to stdin or stdout.
- * @li long options have the format @c --option-name.
- * @li the option-name of a long option can be anything and include any characters.
- * Even @c = characters will work, but don't do that.
- * @li [optional] long options may be abbreviated as long as the abbreviation is unambiguous.
- * You can set a minimum length for abbreviations.
- * @li [optional] long options may begin with a single minus. The double minus form is always
- * accepted, too.
- * @li a long option may take an argument either separate (<code> --option arg </code>) or
- * attached (<code> --option=arg </code>). In the attached form the equals sign is mandatory.
- * @li an empty string can be passed as an attached long option argument: <code> --option-name= </code>.
- * Note the distinction between an empty string as argument and no argument at all.
- * @li an empty string is permitted as separate argument to both long and short options.
- * @li Arguments to both short and long options may start with a @c '-' character. E.g.
- * <code> -X-X </code>, <code>-X -X</code> or <code> --long-X=-X </code>. If @c -X
- * and @c --long-X take an argument, that argument will be @c "-X" in all 3 cases.
- * @li If using the built-in @ref option::Arg::Optional "Arg::Optional", optional arguments must
- * be attached.
- * @li the special option @c -- (i.e. without a name) terminates the list of
- * options. Everything that follows is a non-option argument, even if it starts with
- * a @c '-' character. The @c -- itself will not appear in the parse results.
- * @li the first argument that doesn't start with @c '-' or @c '--' and does not belong to
- * a preceding argument-taking option, will terminate the option list and is the
- * first non-option argument. All following command line arguments are treated as
- * non-option arguments, even if they start with @c '-' . @n
- * NOTE: This behaviour is mandated by POSIX, but GNU getopt() only honours this if it is
- * explicitly requested (e.g. by setting POSIXLY_CORRECT). @n
- * You can enable the GNU behaviour by passing @c true as first argument to
- * e.g. @ref option::Parser::parse() "Parser::parse()".
- * @li Arguments that look like options (i.e. @c '-' followed by at least 1 character) but
- * aren't, are NOT treated as non-option arguments. They are treated as unknown options and
- * are collected into a list of unknown options for error reporting. @n
- * This means that in order to pass a first non-option
- * argument beginning with the minus character it is required to use the
- * @c -- special option, e.g.
- * @code
- * program -x -- --strange-filename
- * @endcode
- * In this example, @c --strange-filename is a non-option argument. If the @c --
- * were omitted, it would be treated as an unknown option. @n
- * See @ref option::Descriptor::longopt for information on how to collect unknown options.
- *
- */
-
-#ifndef OPTIONPARSER_H_
-#define OPTIONPARSER_H_
-
-/** @brief The namespace of The Lean Mean C++ Option Parser. */
-namespace option
-{
-
-#ifdef _MSC_VER
-#include <intrin.h>
-#pragma intrinsic(_BitScanReverse)
-struct MSC_Builtin_CLZ
-{
- static int builtin_clz(unsigned x)
- {
- unsigned long index;
- _BitScanReverse(&index, x);
- return 32-index; // int is always 32bit on Windows, even for target x64
- }
-};
-#define __builtin_clz(x) MSC_Builtin_CLZ::builtin_clz(x)
-#endif
-
-class Option;
-
-/**
- * @brief Possible results when checking if an argument is valid for a certain option.
- *
- * In the case that no argument is provided for an option that takes an
- * optional argument, return codes @c ARG_OK and @c ARG_IGNORE are equivalent.
- */
-enum ArgStatus
-{
- //! The option does not take an argument.
- ARG_NONE,
- //! The argument is acceptable for the option.
- ARG_OK,
- //! The argument is not acceptable but that's non-fatal because the option's argument is optional.
- ARG_IGNORE,
- //! The argument is not acceptable and that's fatal.
- ARG_ILLEGAL
-};
-
-/**
- * @brief Signature of functions that check if an argument is valid for a certain type of option.
- *
- * Every Option has such a function assigned in its Descriptor.
- * @code
- * Descriptor usage[] = { {UNKNOWN, 0, "", "", Arg::None, ""}, ... };
- * @endcode
- *
- * A CheckArg function has the following signature:
- * @code ArgStatus CheckArg(const Option& option, bool msg); @endcode
- *
- * It is used to check if a potential argument would be acceptable for the option.
- * It will even be called if there is no argument. In that case @c option.arg will be @c NULL.
- *
- * If @c msg is @c true and the function determines that an argument is not acceptable and
- * that this is a fatal error, it should output a message to the user before
- * returning @ref ARG_ILLEGAL. If @c msg is @c false the function should remain silent (or you
- * will get duplicate messages).
- *
- * See @ref ArgStatus for the meaning of the return values.
- *
- * While you can provide your own functions,
- * often the following pre-defined checks (which never return @ref ARG_ILLEGAL) will suffice:
- *
- * @li @c Arg::None @copybrief Arg::None
- * @li @c Arg::Optional @copybrief Arg::Optional
- *
- */
-typedef ArgStatus (*CheckArg)(const Option& option, bool msg);
-
-/**
- * @brief Describes an option, its help text (usage) and how it should be parsed.
- *
- * The main input when constructing an option::Parser is an array of Descriptors.
-
- * @par Example:
- * @code
- * enum OptionIndex {CREATE, ...};
- * enum OptionType {DISABLE, ENABLE, OTHER};
- *
- * const option::Descriptor usage[] = {
- * { CREATE, // index
- * OTHER, // type
- * "c", // shortopt
- * "create", // longopt
- * Arg::None, // check_arg
- * "--create Tells the program to create something." // help
- * }
- * , ...
- * };
- * @endcode
- */
-struct Descriptor
-{
- /**
- * @brief Index of this option's linked list in the array filled in by the parser.
- *
- * Command line options whose Descriptors have the same index will end up in the same
- * linked list in the order in which they appear on the command line. If you have
- * multiple long option aliases that refer to the same option, give their descriptors
- * the same @c index.
- *
- * If you have options that mean exactly opposite things
- * (e.g. @c --enable-foo and @c --disable-foo ), you should also give them the same
- * @c index, but distinguish them through different values for @ref type.
- * That way they end up in the same list and you can just take the last element of the
- * list and use its type. This way you get the usual behaviour where switches later
- * on the command line override earlier ones without having to code it manually.
- *
- * @par Tip:
- * Use an enum rather than plain ints for better readability, as shown in the example
- * at Descriptor.
- */
- const unsigned index;
-
- /**
- * @brief Used to distinguish between options with the same @ref index.
- * See @ref index for details.
- *
- * It is recommended that you use an enum rather than a plain int to make your
- * code more readable.
- */
- const int type;
-
- /**
- * @brief Each char in this string will be accepted as a short option character.
- *
- * The string must not include the minus character @c '-' or you'll get undefined
- * behaviour.
- *
- * If this Descriptor should not have short option characters, use the empty
- * string "". NULL is not permitted here!
- *
- * See @ref longopt for more information.
- */
- const char* const shortopt;
-
- /**
- * @brief The long option name (without the leading @c -- ).
- *
- * If this Descriptor should not have a long option name, use the empty
- * string "". NULL is not permitted here!
- *
- * While @ref shortopt allows multiple short option characters, each
- * Descriptor can have only a single long option name. If you have multiple
- * long option names referring to the same option use separate Descriptors
- * that have the same @ref index and @ref type. You may repeat
- * short option characters in such an alias Descriptor but there's no need to.
- *
- * @par Dummy Descriptors:
- * You can use dummy Descriptors with an
- * empty string for both @ref shortopt and @ref longopt to add text to
- * the usage that is not related to a specific option. See @ref help.
- * The first dummy Descriptor will be used for unknown options (see below).
- *
- * @par Unknown Option Descriptor:
- * The first dummy Descriptor in the list of Descriptors,
- * whose @ref shortopt and @ref longopt are both the empty string, will be used
- * as the Descriptor for unknown options. An unknown option is a string in
- * the argument vector that is not a lone minus @c '-' but starts with a minus
- * character and does not match any Descriptor's @ref shortopt or @ref longopt. @n
- * Note that the dummy descriptor's @ref check_arg function @e will be called and
- * its return value will be evaluated as usual. I.e. if it returns @ref ARG_ILLEGAL
- * the parsing will be aborted with <code>Parser::error()==true</code>. @n
- * if @c check_arg does not return @ref ARG_ILLEGAL the descriptor's
- * @ref index @e will be used to pick the linked list into which
- * to put the unknown option. @n
- * If there is no dummy descriptor, unknown options will be dropped silently.
- *
- */
- const char* const longopt;
-
- /**
- * @brief For each option that matches @ref shortopt or @ref longopt this function
- * will be called to check a potential argument to the option.
- *
- * This function will be called even if there is no potential argument. In that case
- * it will be passed @c NULL as @c arg parameter. Do not confuse this with the empty
- * string.
- *
- * See @ref CheckArg for more information.
- */
- const CheckArg check_arg;
-
- /**
- * @brief The usage text associated with the options in this Descriptor.
- *
- * You can use option::printUsage() to format your usage message based on
- * the @c help texts. You can use dummy Descriptors where
- * @ref shortopt and @ref longopt are both the empty string to add text to
- * the usage that is not related to a specific option.
- *
- * See option::printUsage() for special formatting characters you can use in
- * @c help to get a column layout.
- *
- * @attention
- * Must be UTF-8-encoded. If your compiler supports C++11 you can use the "u8"
- * prefix to make sure string literals are properly encoded.
- */
- const char* help;
-};
-
-/**
- * @brief A parsed option from the command line together with its argument if it has one.
- *
- * The Parser chains all parsed options with the same Descriptor::index together
- * to form a linked list. This allows you to easily implement all of the common ways
- * of handling repeated options and enable/disable pairs.
- *
- * @li Test for presence of a switch in the argument vector:
- * @code if ( options[QUIET] ) ... @endcode
- * @li Evaluate --enable-foo/--disable-foo pair where the last one used wins:
- * @code if ( options[FOO].last()->type() == DISABLE ) ... @endcode
- * @li Cumulative option (-v verbose, -vv more verbose, -vvv even more verbose):
- * @code int verbosity = options[VERBOSE].count(); @endcode
- * @li Iterate over all --file=<fname> arguments:
- * @code for (Option* opt = options[FILE]; opt; opt = opt->next())
- * fname = opt->arg; ... @endcode
- */
-class Option
-{
- Option* next_;
- Option* prev_;
-public:
- /**
- * @brief Pointer to this Option's Descriptor.
- *
- * Remember that the first dummy descriptor (see @ref Descriptor::longopt) is used
- * for unknown options.
- *
- * @attention
- * @c desc==NULL signals that this Option is unused. This is the default state of
- * elements in the result array. You don't need to test @c desc explicitly. You
- * can simply write something like this:
- * @code
- * if (options[CREATE])
- * {
- * ...
- * }
- * @endcode
- * This works because of <code> operator const Option*() </code>.
- */
- const Descriptor* desc;
-
- /**
- * @brief The name of the option as used on the command line.
- *
- * The main purpose of this string is to be presented to the user in messages.
- *
- * In the case of a long option, this is the actual @c argv pointer, i.e. the first
- * character is a '-'. In the case of a short option this points to the option
- * character within the @c argv string.
- *
- * Note that in the case of a short option group or an attached option argument, this
- * string will contain additional characters following the actual name. Use @ref namelen
- * to filter out the actual option name only.
- *
- */
- const char* name;
-
- /**
- * @brief Pointer to this Option's argument (if any).
- *
- * NULL if this option has no argument. Do not confuse this with the empty string which
- * is a valid argument.
- */
- const char* arg;
-
- /**
- * @brief The length of the option @ref name.
- *
- * Because @ref name points into the actual @c argv string, the option name may be
- * followed by more characters (e.g. other short options in the same short option group).
- * This value is the number of bytes (not characters!) that are part of the actual name.
- *
- * For a short option, this length is always 1. For a long option this length is always
- * at least 2 if single minus long options are permitted and at least 3 if they are disabled.
- *
- * @note
- * In the pathological case of a minus within a short option group (e.g. @c -xf-z), this
- * length is incorrect, because this case will be misinterpreted as a long option and the
- * name will therefore extend to the string's 0-terminator or a following '=" character
- * if there is one. This is irrelevant for most uses of @ref name and @c namelen. If you
- * really need to distinguish the case of a long and a short option, compare @ref name to
- * the @c argv pointers. A long option's @c name is always identical to one of them,
- * whereas a short option's is never.
- */
- int namelen;
-
- /**
- * @brief Returns Descriptor::type of this Option's Descriptor, or 0 if this Option
- * is invalid (unused).
- *
- * Because this method (and last(), too) can be used even on unused Options with desc==0, you can (provided
- * you arrange your types properly) switch on type() without testing validity first.
- * @code
- * enum OptionType { UNUSED=0, DISABLED=0, ENABLED=1 };
- * enum OptionIndex { FOO };
- * const Descriptor usage[] = {
- * { FOO, ENABLED, "", "enable-foo", Arg::None, 0 },
- * { FOO, DISABLED, "", "disable-foo", Arg::None, 0 },
- * { 0, 0, 0, 0, 0, 0 } };
- * ...
- * switch(options[FOO].last()->type()) // no validity check required!
- * {
- * case ENABLED: ...
- * case DISABLED: ... // UNUSED==DISABLED !
- * }
- * @endcode
- */
- int type() const
- {
- return desc == 0 ? 0 : desc->type;
- }
-
- /**
- * @brief Returns Descriptor::index of this Option's Descriptor, or -1 if this Option
- * is invalid (unused).
- */
- int index() const
- {
- return desc == 0 ? -1 : (int)desc->index;
- }
-
- /**
- * @brief Returns the number of times this Option (or others with the same Descriptor::index)
- * occurs in the argument vector.
- *
- * This corresponds to the number of elements in the linked list this Option is part of.
- * It doesn't matter on which element you call count(). The return value is always the same.
- *
- * Use this to implement cumulative options, such as -v, -vv, -vvv for
- * different verbosity levels.
- *
- * Returns 0 when called for an unused/invalid option.
- */
- int count()
- {
- int c = (desc == 0 ? 0 : 1);
- Option* p = first();
- while (!p->isLast())
- {
- ++c;
- p = p->next_;
- };
- return c;
- }
-
- /**
- * @brief Returns true iff this is the first element of the linked list.
- *
- * The first element in the linked list is the first option on the command line
- * that has the respective Descriptor::index value.
- *
- * Returns true for an unused/invalid option.
- */
- bool isFirst() const
- {
- return isTagged(prev_);
- }
-
- /**
- * @brief Returns true iff this is the last element of the linked list.
- *
- * The last element in the linked list is the last option on the command line
- * that has the respective Descriptor::index value.
- *
- * Returns true for an unused/invalid option.
- */
- bool isLast() const
- {
- return isTagged(next_);
- }
-
- /**
- * @brief Returns a pointer to the first element of the linked list.
- *
- * Use this when you want the first occurrence of an option on the command line to
- * take precedence. Note that this is not the way most programs handle options.
- * You should probably be using last() instead.
- *
- * @note
- * This method may be called on an unused/invalid option and will return a pointer to the
- * option itself.
- */
- Option* first()
- {
- Option* p = this;
- while (!p->isFirst())
- p = p->prev_;
- return p;
- }
-
- /**
- * @brief Returns a pointer to the last element of the linked list.
- *
- * Use this when you want the last occurrence of an option on the command line to
- * take precedence. This is the most common way of handling conflicting options.
- *
- * @note
- * This method may be called on an unused/invalid option and will return a pointer to the
- * option itself.
- *
- * @par Tip:
- * If you have options with opposite meanings (e.g. @c --enable-foo and @c --disable-foo), you
- * can assign them the same Descriptor::index to get them into the same list. Distinguish them by
- * Descriptor::type and all you have to do is check <code> last()->type() </code> to get
- * the state listed last on the command line.
- */
- Option* last()
- {
- return first()->prevwrap();
- }
-
- /**
- * @brief Returns a pointer to the previous element of the linked list or NULL if
- * called on first().
- *
- * If called on first() this method returns NULL. Otherwise it will return the
- * option with the same Descriptor::index that precedes this option on the command
- * line.
- */
- Option* prev()
- {
- return isFirst() ? 0 : prev_;
- }
-
- /**
- * @brief Returns a pointer to the previous element of the linked list with wrap-around from
- * first() to last().
- *
- * If called on first() this method returns last(). Otherwise it will return the
- * option with the same Descriptor::index that precedes this option on the command
- * line.
- */
- Option* prevwrap()
- {
- return untag(prev_);
- }
-
- /**
- * @brief Returns a pointer to the next element of the linked list or NULL if called
- * on last().
- *
- * If called on last() this method returns NULL. Otherwise it will return the
- * option with the same Descriptor::index that follows this option on the command
- * line.
- */
- Option* next()
- {
- return isLast() ? 0 : next_;
- }
-
- /**
- * @brief Returns a pointer to the next element of the linked list with wrap-around from
- * last() to first().
- *
- * If called on last() this method returns first(). Otherwise it will return the
- * option with the same Descriptor::index that follows this option on the command
- * line.
- */
- Option* nextwrap()
- {
- return untag(next_);
- }
-
- /**
- * @brief Makes @c new_last the new last() by chaining it into the list after last().
- *
- * It doesn't matter which element you call append() on. The new element will always
- * be appended to last().
- *
- * @attention
- * @c new_last must not yet be part of a list, or that list will become corrupted, because
- * this method does not unchain @c new_last from an existing list.
- */
- void append(Option* new_last)
- {
- Option* p = last();
- Option* f = first();
- p->next_ = new_last;
- new_last->prev_ = p;
- new_last->next_ = tag(f);
- f->prev_ = tag(new_last);
- }
-
- /**
- * @brief Casts from Option to const Option* but only if this Option is valid.
- *
- * If this Option is valid (i.e. @c desc!=NULL), returns this.
- * Otherwise returns NULL. This allows testing an Option directly
- * in an if-clause to see if it is used:
- * @code
- * if (options[CREATE])
- * {
- * ...
- * }
- * @endcode
- * It also allows you to write loops like this:
- * @code for (Option* opt = options[FILE]; opt; opt = opt->next())
- * fname = opt->arg; ... @endcode
- */
- operator const Option*() const
- {
- return desc ? this : 0;
- }
-
- /**
- * @brief Casts from Option to Option* but only if this Option is valid.
- *
- * If this Option is valid (i.e. @c desc!=NULL), returns this.
- * Otherwise returns NULL. This allows testing an Option directly
- * in an if-clause to see if it is used:
- * @code
- * if (options[CREATE])
- * {
- * ...
- * }
- * @endcode
- * It also allows you to write loops like this:
- * @code for (Option* opt = options[FILE]; opt; opt = opt->next())
- * fname = opt->arg; ... @endcode
- */
- operator Option*()
- {
- return desc ? this : 0;
- }
-
- /**
- * @brief Creates a new Option that is a one-element linked list and has NULL
- * @ref desc, @ref name, @ref arg and @ref namelen.
- */
- Option() :
- desc(0), name(0), arg(0), namelen(0)
- {
- prev_ = tag(this);
- next_ = tag(this);
- }
-
- /**
- * @brief Creates a new Option that is a one-element linked list and has the given
- * values for @ref desc, @ref name and @ref arg.
- *
- * If @c name_ points at a character other than '-' it will be assumed to refer to a
- * short option and @ref namelen will be set to 1. Otherwise the length will extend to
- * the first '=' character or the string's 0-terminator.
- */
- Option(const Descriptor* desc_, const char* name_, const char* arg_)
- {
- init(desc_, name_, arg_);
- }
-
- /**
- * @brief Makes @c *this a copy of @c orig except for the linked list pointers.
- *
- * After this operation @c *this will be a one-element linked list.
- */
- void operator=(const Option& orig)
- {
- init(orig.desc, orig.name, orig.arg);
- }
-
- /**
- * @brief Makes @c *this a copy of @c orig except for the linked list pointers.
- *
- * After this operation @c *this will be a one-element linked list.
- */
- Option(const Option& orig)
- {
- init(orig.desc, orig.name, orig.arg);
- }
-
-private:
- /**
- * @internal
- * @brief Sets the fields of this Option to the given values (extracting @c name if necessary).
- *
- * If @c name_ points at a character other than '-' it will be assumed to refer to a
- * short option and @ref namelen will be set to 1. Otherwise the length will extend to
- * the first '=' character or the string's 0-terminator.
- */
- void init(const Descriptor* desc_, const char* name_, const char* arg_)
- {
- desc = desc_;
- name = name_;
- arg = arg_;
- prev_ = tag(this);
- next_ = tag(this);
- namelen = 0;
- if (name == 0)
- return;
- namelen = 1;
- if (name[0] != '-')
- return;
- while (name[namelen] != 0 && name[namelen] != '=')
- ++namelen;
- }
-
- static Option* tag(Option* ptr)
- {
- return (Option*) ((unsigned long long) ptr | 1);
- }
-
- static Option* untag(Option* ptr)
- {
- return (Option*) ((unsigned long long) ptr & ~1ull);
- }
-
- static bool isTagged(Option* ptr)
- {
- return ((unsigned long long) ptr & 1);
- }
-};
-
-/**
- * @brief Functions for checking the validity of option arguments.
- *
- * @copydetails CheckArg
- *
- * The following example code
- * can serve as starting place for writing your own more complex CheckArg functions:
- * @code
- * struct Arg: public option::Arg
- * {
- * static void printError(const char* msg1, const option::Option& opt, const char* msg2)
- * {
- * fprintf(stderr, "ERROR: %s", msg1);
- * fwrite(opt.name, opt.namelen, 1, stderr);
- * fprintf(stderr, "%s", msg2);
- * }
- *
- * static option::ArgStatus Unknown(const option::Option& option, bool msg)
- * {
- * if (msg) printError("Unknown option '", option, "'\n");
- * return option::ARG_ILLEGAL;
- * }
- *
- * static option::ArgStatus Required(const option::Option& option, bool msg)
- * {
- * if (option.arg != 0)
- * return option::ARG_OK;
- *
- * if (msg) printError("Option '", option, "' requires an argument\n");
- * return option::ARG_ILLEGAL;
- * }
- *
- * static option::ArgStatus NonEmpty(const option::Option& option, bool msg)
- * {
- * if (option.arg != 0 && option.arg[0] != 0)
- * return option::ARG_OK;
- *
- * if (msg) printError("Option '", option, "' requires a non-empty argument\n");
- * return option::ARG_ILLEGAL;
- * }
- *
- * static option::ArgStatus Numeric(const option::Option& option, bool msg)
- * {
- * char* endptr = 0;
- * if (option.arg != 0 && strtol(option.arg, &endptr, 10)){};
- * if (endptr != option.arg && *endptr == 0)
- * return option::ARG_OK;
- *
- * if (msg) printError("Option '", option, "' requires a numeric argument\n");
- * return option::ARG_ILLEGAL;
- * }
- * };
- * @endcode
- */
-struct Arg
-{
- //! @brief For options that don't take an argument: Returns ARG_NONE.
- static ArgStatus None(const Option&, bool)
- {
- return ARG_NONE;
- }
-
- //! @brief Returns ARG_OK if the argument is attached and ARG_IGNORE otherwise.
- static ArgStatus Optional(const Option& option, bool)
- {
- if (option.arg && option.name[option.namelen] != 0)
- return ARG_OK;
- else
- return ARG_IGNORE;
- }
-};
-
-/**
- * @brief Determines the minimum lengths of the buffer and options arrays used for Parser.
- *
- * Because Parser doesn't use dynamic memory its output arrays have to be pre-allocated.
- * If you don't want to use fixed size arrays (which may turn out too small, causing
- * command line arguments to be dropped), you can use Stats to determine the correct sizes.
- * Stats work cumulative. You can first pass in your default options and then the real
- * options and afterwards the counts will reflect the union.
- */
-struct Stats
-{
- /**
- * @brief Number of elements needed for a @c buffer[] array to be used for
- * @ref Parser::parse() "parsing" the same argument vectors that were fed
- * into this Stats object.
- *
- * @note
- * This number is always 1 greater than the actual number needed, to give
- * you a sentinel element.
- */
- unsigned buffer_max;
-
- /**
- * @brief Number of elements needed for an @c options[] array to be used for
- * @ref Parser::parse() "parsing" the same argument vectors that were fed
- * into this Stats object.
- *
- * @note
- * @li This number is always 1 greater than the actual number needed, to give
- * you a sentinel element.
- * @li This number depends only on the @c usage, not the argument vectors, because
- * the @c options array needs exactly one slot for each possible Descriptor::index.
- */
- unsigned options_max;
-
- /**
- * @brief Creates a Stats object with counts set to 1 (for the sentinel element).
- */
- Stats() :
- buffer_max(1), options_max(1) // 1 more than necessary as sentinel
- {
- }
-
- /**
- * @brief Creates a new Stats object and immediately updates it for the
- * given @c usage and argument vector. You may pass 0 for @c argc and/or @c argv,
- * if you just want to update @ref options_max.
- *
- * @note
- * The calls to Stats methods must match the later calls to Parser methods.
- * See Parser::parse() for the meaning of the arguments.
- */
- Stats(bool gnu, const Descriptor usage[], int argc, const char** argv, int min_abbr_len = 0, //
- bool single_minus_longopt = false) :
- buffer_max(1), options_max(1) // 1 more than necessary as sentinel
- {
- add(gnu, usage, argc, argv, min_abbr_len, single_minus_longopt);
- }
-
- //! @brief Stats(...) with non-const argv.
- Stats(bool gnu, const Descriptor usage[], int argc, char** argv, int min_abbr_len = 0, //
- bool single_minus_longopt = false) :
- buffer_max(1), options_max(1) // 1 more than necessary as sentinel
- {
- add(gnu, usage, argc, (const char**) argv, min_abbr_len, single_minus_longopt);
- }
-
- //! @brief POSIX Stats(...) (gnu==false).
- Stats(const Descriptor usage[], int argc, const char** argv, int min_abbr_len = 0, //
- bool single_minus_longopt = false) :
- buffer_max(1), options_max(1) // 1 more than necessary as sentinel
- {
- add(false, usage, argc, argv, min_abbr_len, single_minus_longopt);
- }
-
- //! @brief POSIX Stats(...) (gnu==false) with non-const argv.
- Stats(const Descriptor usage[], int argc, char** argv, int min_abbr_len = 0, //
- bool single_minus_longopt = false) :
- buffer_max(1), options_max(1) // 1 more than necessary as sentinel
- {
- add(false, usage, argc, (const char**) argv, min_abbr_len, single_minus_longopt);
- }
-
- /**
- * @brief Updates this Stats object for the
- * given @c usage and argument vector. You may pass 0 for @c argc and/or @c argv,
- * if you just want to update @ref options_max.
- *
- * @note
- * The calls to Stats methods must match the later calls to Parser methods.
- * See Parser::parse() for the meaning of the arguments.
- */
- void add(bool gnu, const Descriptor usage[], int argc, const char** argv, int min_abbr_len = 0, //
- bool single_minus_longopt = false);
-
- //! @brief add() with non-const argv.
- void add(bool gnu, const Descriptor usage[], int argc, char** argv, int min_abbr_len = 0, //
- bool single_minus_longopt = false)
- {
- add(gnu, usage, argc, (const char**) argv, min_abbr_len, single_minus_longopt);
- }
-
- //! @brief POSIX add() (gnu==false).
- void add(const Descriptor usage[], int argc, const char** argv, int min_abbr_len = 0, //
- bool single_minus_longopt = false)
- {
- add(false, usage, argc, argv, min_abbr_len, single_minus_longopt);
- }
-
- //! @brief POSIX add() (gnu==false) with non-const argv.
- void add(const Descriptor usage[], int argc, char** argv, int min_abbr_len = 0, //
- bool single_minus_longopt = false)
- {
- add(false, usage, argc, (const char**) argv, min_abbr_len, single_minus_longopt);
- }
-private:
- class CountOptionsAction;
-};
-
-/**
- * @brief Checks argument vectors for validity and parses them into data
- * structures that are easier to work with.
- *
- * @par Example:
- * @code
- * int main(int argc, char* argv[])
- * {
- * argc-=(argc>0); argv+=(argc>0); // skip program name argv[0] if present
- * option::Stats stats(usage, argc, argv);
- * option::Option options[stats.options_max], buffer[stats.buffer_max];
- * option::Parser parse(usage, argc, argv, options, buffer);
- *
- * if (parse.error())
- * return 1;
- *
- * if (options[HELP])
- * ...
- * @endcode
- */
-class Parser
-{
- int op_count; //!< @internal @brief see optionsCount()
- int nonop_count; //!< @internal @brief see nonOptionsCount()
- const char** nonop_args; //!< @internal @brief see nonOptions()
- bool err; //!< @internal @brief see error()
-public:
-
- /**
- * @brief Creates a new Parser.
- */
- Parser() :
- op_count(0), nonop_count(0), nonop_args(0), err(false)
- {
- }
-
- /**
- * @brief Creates a new Parser and immediately parses the given argument vector.
- * @copydetails parse()
- */
- Parser(bool gnu, const Descriptor usage[], int argc, const char** argv, Option options[], Option buffer[],
- int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1) :
- op_count(0), nonop_count(0), nonop_args(0), err(false)
- {
- parse(gnu, usage, argc, argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax);
- }
-
- //! @brief Parser(...) with non-const argv.
- Parser(bool gnu, const Descriptor usage[], int argc, char** argv, Option options[], Option buffer[],
- int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1) :
- op_count(0), nonop_count(0), nonop_args(0), err(false)
- {
- parse(gnu, usage, argc, (const char**) argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax);
- }
-
- //! @brief POSIX Parser(...) (gnu==false).
- Parser(const Descriptor usage[], int argc, const char** argv, Option options[], Option buffer[], int min_abbr_len = 0,
- bool single_minus_longopt = false, int bufmax = -1) :
- op_count(0), nonop_count(0), nonop_args(0), err(false)
- {
- parse(false, usage, argc, argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax);
- }
-
- //! @brief POSIX Parser(...) (gnu==false) with non-const argv.
- Parser(const Descriptor usage[], int argc, char** argv, Option options[], Option buffer[], int min_abbr_len = 0,
- bool single_minus_longopt = false, int bufmax = -1) :
- op_count(0), nonop_count(0), nonop_args(0), err(false)
- {
- parse(false, usage, argc, (const char**) argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax);
- }
-
- /**
- * @brief Parses the given argument vector.
- *
- * @param gnu if true, parse() will not stop at the first non-option argument. Instead it will
- * reorder arguments so that all non-options are at the end. This is the default behaviour
- * of GNU getopt() but is not conforming to POSIX. @n
- * Note, that once the argument vector has been reordered, the @c gnu flag will have
- * no further effect on this argument vector. So it is enough to pass @c gnu==true when
- * creating Stats.
- * @param usage Array of Descriptor objects that describe the options to support. The last entry
- * of this array must have 0 in all fields.
- * @param argc The number of elements from @c argv that are to be parsed. If you pass -1, the number
- * will be determined automatically. In that case the @c argv list must end with a NULL
- * pointer.
- * @param argv The arguments to be parsed. If you pass -1 as @c argc the last pointer in the @c argv
- * list must be NULL to mark the end.
- * @param options Each entry is the first element of a linked list of Options. Each new option
- * that is parsed will be appended to the list specified by that Option's
- * Descriptor::index. If an entry is not yet used (i.e. the Option is invalid),
- * it will be replaced rather than appended to. @n
- * The minimum length of this array is the greatest Descriptor::index value that
- * occurs in @c usage @e PLUS ONE.
- * @param buffer Each argument that is successfully parsed (including unknown arguments, if they
- * have a Descriptor whose CheckArg does not return @ref ARG_ILLEGAL) will be stored in this
- * array. parse() scans the array for the first invalid entry and begins writing at that
- * index. You can pass @c bufmax to limit the number of options stored.
- * @param min_abbr_len Passing a value <code> min_abbr_len > 0 </code> enables abbreviated long
- * options. The parser will match a prefix of a long option as if it was
- * the full long option (e.g. @c --foob=10 will be interpreted as if it was
- * @c --foobar=10 ), as long as the prefix has at least @c min_abbr_len characters
- * (not counting the @c -- ) and is unambiguous.
- * @n Be careful if combining @c min_abbr_len=1 with @c single_minus_longopt=true
- * because the ambiguity check does not consider short options and abbreviated
- * single minus long options will take precedence over short options.
- * @param single_minus_longopt Passing @c true for this option allows long options to begin with
- * a single minus. The double minus form will still be recognized. Note that
- * single minus long options take precedence over short options and short option
- * groups. E.g. @c -file would be interpreted as @c --file and not as
- * <code> -f -i -l -e </code> (assuming a long option named @c "file" exists).
- * @param bufmax The greatest index in the @c buffer[] array that parse() will write to is
- * @c bufmax-1. If there are more options, they will be processed (in particular
- * their CheckArg will be called) but not stored. @n
- * If you used Stats::buffer_max to dimension this array, you can pass
- * -1 (or not pass @c bufmax at all) which tells parse() that the buffer is
- * "large enough".
- * @attention
- * Remember that @c options and @c buffer store Option @e objects, not pointers. Therefore it
- * is not possible for the same object to be in both arrays. For those options that are found in
- * both @c buffer[] and @c options[] the respective objects are independent copies. And only the
- * objects in @c options[] are properly linked via Option::next() and Option::prev().
- * You can iterate over @c buffer[] to
- * process all options in the order they appear in the argument vector, but if you want access to
- * the other Options with the same Descriptor::index, then you @e must access the linked list via
- * @c options[]. You can get the linked list in options from a buffer object via something like
- * @c options[buffer[i].index()].
- */
- void parse(bool gnu, const Descriptor usage[], int argc, const char** argv, Option options[], Option buffer[],
- int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1);
-
- //! @brief parse() with non-const argv.
- void parse(bool gnu, const Descriptor usage[], int argc, char** argv, Option options[], Option buffer[],
- int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1)
- {
- parse(gnu, usage, argc, (const char**) argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax);
- }
-
- //! @brief POSIX parse() (gnu==false).
- void parse(const Descriptor usage[], int argc, const char** argv, Option options[], Option buffer[],
- int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1)
- {
- parse(false, usage, argc, argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax);
- }
-
- //! @brief POSIX parse() (gnu==false) with non-const argv.
- void parse(const Descriptor usage[], int argc, char** argv, Option options[], Option buffer[], int min_abbr_len = 0,
- bool single_minus_longopt = false, int bufmax = -1)
- {
- parse(false, usage, argc, (const char**) argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax);
- }
-
- /**
- * @brief Returns the number of valid Option objects in @c buffer[].
- *
- * @note
- * @li The returned value always reflects the number of Options in the buffer[] array used for
- * the most recent call to parse().
- * @li The count (and the buffer[]) includes unknown options if they are collected
- * (see Descriptor::longopt).
- */
- int optionsCount()
- {
- return op_count;
- }
-
- /**
- * @brief Returns the number of non-option arguments that remained at the end of the
- * most recent parse() that actually encountered non-option arguments.
- *
- * @note
- * A parse() that does not encounter non-option arguments will leave this value
- * as well as nonOptions() undisturbed. This means you can feed the Parser a
- * default argument vector that contains non-option arguments (e.g. a default filename).
- * Then you feed it the actual arguments from the user. If the user has supplied at
- * least one non-option argument, all of the non-option arguments from the default
- * disappear and are replaced by the user's non-option arguments. However, if the
- * user does not supply any non-option arguments the defaults will still be in
- * effect.
- */
- int nonOptionsCount()
- {
- return nonop_count;
- }
-
- /**
- * @brief Returns a pointer to an array of non-option arguments (only valid
- * if <code>nonOptionsCount() >0 </code>).
- *
- * @note
- * @li parse() does not copy arguments, so this pointer points into the actual argument
- * vector as passed to parse().
- * @li As explained at nonOptionsCount() this pointer is only changed by parse() calls
- * that actually encounter non-option arguments. A parse() call that encounters only
- * options, will not change nonOptions().
- */
- const char** nonOptions()
- {
- return nonop_args;
- }
-
- /**
- * @brief Returns <b><code>nonOptions()[i]</code></b> (@e without checking if i is in range!).
- */
- const char* nonOption(int i)
- {
- return nonOptions()[i];
- }
-
- /**
- * @brief Returns @c true if an unrecoverable error occurred while parsing options.
- *
- * An illegal argument to an option (i.e. CheckArg returns @ref ARG_ILLEGAL) is an
- * unrecoverable error that aborts the parse. Unknown options are only an error if
- * their CheckArg function returns @ref ARG_ILLEGAL. Otherwise they are collected.
- * In that case if you want to exit the program if either an illegal argument
- * or an unknown option has been passed, use code like this
- *
- * @code
- * if (parser.error() || options[UNKNOWN])
- * exit(1);
- * @endcode
- *
- */
- bool error()
- {
- return err;
- }
-
-private:
- friend struct Stats;
- class StoreOptionAction;
- struct Action;
-
- /**
- * @internal
- * @brief This is the core function that does all the parsing.
- * @retval false iff an unrecoverable error occurred.
- */
- static bool workhorse(bool gnu, const Descriptor usage[], int numargs, const char** args, Action& action,
- bool single_minus_longopt, bool print_errors, int min_abbr_len);
-
- /**
- * @internal
- * @brief Returns true iff @c st1 is a prefix of @c st2 and
- * in case @c st2 is longer than @c st1, then
- * the first additional character is '='.
- *
- * @par Examples:
- * @code
- * streq("foo", "foo=bar") == true
- * streq("foo", "foobar") == false
- * streq("foo", "foo") == true
- * streq("foo=bar", "foo") == false
- * @endcode
- */
- static bool streq(const char* st1, const char* st2)
- {
- while (*st1 != 0)
- if (*st1++ != *st2++)
- return false;
- return (*st2 == 0 || *st2 == '=');
- }
-
- /**
- * @internal
- * @brief Like streq() but handles abbreviations.
- *
- * Returns true iff @c st1 and @c st2 have a common
- * prefix with the following properties:
- * @li (if min > 0) its length is at least @c min characters or the same length as @c st1 (whichever is smaller).
- * @li (if min <= 0) its length is the same as that of @c st1
- * @li within @c st2 the character following the common prefix is either '=' or end-of-string.
- *
- * Examples:
- * @code
- * streqabbr("foo", "foo=bar",<anything>) == true
- * streqabbr("foo", "fo=bar" , 2) == true
- * streqabbr("foo", "fo" , 2) == true
- * streqabbr("foo", "fo" , 0) == false
- * streqabbr("foo", "f=bar" , 2) == false
- * streqabbr("foo", "f" , 2) == false
- * streqabbr("fo" , "foo=bar",<anything>) == false
- * streqabbr("foo", "foobar" ,<anything>) == false
- * streqabbr("foo", "fobar" ,<anything>) == false
- * streqabbr("foo", "foo" ,<anything>) == true
- * @endcode
- */
- static bool streqabbr(const char* st1, const char* st2, long long min)
- {
- const char* st1start = st1;
- while (*st1 != 0 && (*st1 == *st2))
- {
- ++st1;
- ++st2;
- }
-
- return (*st1 == 0 || (min > 0 && (st1 - st1start) >= min)) && (*st2 == 0 || *st2 == '=');
- }
-
- /**
- * @internal
- * @brief Returns true iff character @c ch is contained in the string @c st.
- *
- * Returns @c true for @c ch==0 .
- */
- static bool instr(char ch, const char* st)
- {
- while (*st != 0 && *st != ch)
- ++st;
- return *st == ch;
- }
-
- /**
- * @internal
- * @brief Rotates <code>args[-count],...,args[-1],args[0]</code> to become
- * <code>args[0],args[-count],...,args[-1]</code>.
- */
- static void shift(const char** args, int count)
- {
- for (int i = 0; i > -count; --i)
- {
- const char* temp = args[i];
- args[i] = args[i - 1];
- args[i - 1] = temp;
- }
- }
-};
-
-/**
- * @internal
- * @brief Interface for actions Parser::workhorse() should perform for each Option it
- * parses.
- */
-struct Parser::Action
-{
- /**
- * @brief Called by Parser::workhorse() for each Option that has been successfully
- * parsed (including unknown
- * options if they have a Descriptor whose Descriptor::check_arg does not return
- * @ref ARG_ILLEGAL.
- *
- * Returns @c false iff a fatal error has occured and the parse should be aborted.
- */
- virtual bool perform(Option&)
- {
- return true;
- }
-
- /**
- * @brief Called by Parser::workhorse() after finishing the parse.
- * @param numargs the number of non-option arguments remaining
- * @param args pointer to the first remaining non-option argument (if numargs > 0).
- *
- * @return
- * @c false iff a fatal error has occurred.
- */
- virtual bool finished(int numargs, const char** args)
- {
- (void) numargs;
- (void) args;
- return true;
- }
-};
-
-/**
- * @internal
- * @brief An Action to pass to Parser::workhorse() that will increment a counter for
- * each parsed Option.
- */
-class Stats::CountOptionsAction: public Parser::Action
-{
- unsigned* buffer_max;
-public:
- /**
- * Creates a new CountOptionsAction that will increase @c *buffer_max_ for each
- * parsed Option.
- */
- CountOptionsAction(unsigned* buffer_max_) :
- buffer_max(buffer_max_)
- {
- }
-
- bool perform(Option&)
- {
- if (*buffer_max == 0x7fffffff)
- return false; // overflow protection: don't accept number of options that doesn't fit signed int
- ++*buffer_max;
- return true;
- }
-};
-
-/**
- * @internal
- * @brief An Action to pass to Parser::workhorse() that will store each parsed Option in
- * appropriate arrays (see Parser::parse()).
- */
-class Parser::StoreOptionAction: public Parser::Action
-{
- Parser& parser;
- Option* options;
- Option* buffer;
- int bufmax; //! Number of slots in @c buffer. @c -1 means "large enough".
-public:
- /**
- * @brief Creates a new StoreOption action.
- * @param parser_ the parser whose op_count should be updated.
- * @param options_ each Option @c o is chained into the linked list @c options_[o.desc->index]
- * @param buffer_ each Option is appended to this array as long as there's a free slot.
- * @param bufmax_ number of slots in @c buffer_. @c -1 means "large enough".
- */
- StoreOptionAction(Parser& parser_, Option options_[], Option buffer_[], int bufmax_) :
- parser(parser_), options(options_), buffer(buffer_), bufmax(bufmax_)
- {
- // find first empty slot in buffer (if any)
- int bufidx = 0;
- while ((bufmax < 0 || bufidx < bufmax) && buffer[bufidx])
- ++bufidx;
-
- // set parser's optionCount
- parser.op_count = bufidx;
- }
-
- bool perform(Option& option)
- {
- if (bufmax < 0 || parser.op_count < bufmax)
- {
- if (parser.op_count == 0x7fffffff)
- return false; // overflow protection: don't accept number of options that doesn't fit signed int
-
- buffer[parser.op_count] = option;
- int idx = buffer[parser.op_count].desc->index;
- if (options[idx])
- options[idx].append(buffer[parser.op_count]);
- else
- options[idx] = buffer[parser.op_count];
- ++parser.op_count;
- }
- return true; // NOTE: an option that is discarded because of a full buffer is not fatal
- }
-
- bool finished(int numargs, const char** args)
- {
- // only overwrite non-option argument list if there's at least 1
- // new non-option argument. Otherwise we keep the old list. This
- // makes it easy to use default non-option arguments.
- if (numargs > 0)
- {
- parser.nonop_count = numargs;
- parser.nonop_args = args;
- }
-
- return true;
- }
-};
-
-inline void Parser::parse(bool gnu, const Descriptor usage[], int argc, const char** argv, Option options[],
- Option buffer[], int min_abbr_len, bool single_minus_longopt, int bufmax)
-{
- StoreOptionAction action(*this, options, buffer, bufmax);
- err = !workhorse(gnu, usage, argc, argv, action, single_minus_longopt, true, min_abbr_len);
-}
-
-inline void Stats::add(bool gnu, const Descriptor usage[], int argc, const char** argv, int min_abbr_len,
- bool single_minus_longopt)
-{
- // determine size of options array. This is the greatest index used in the usage + 1
- int i = 0;
- while (usage[i].shortopt != 0)
- {
- if (usage[i].index + 1 >= options_max)
- options_max = (usage[i].index + 1) + 1; // 1 more than necessary as sentinel
-
- ++i;
- }
-
- CountOptionsAction action(&buffer_max);
- Parser::workhorse(gnu, usage, argc, argv, action, single_minus_longopt, false, min_abbr_len);
-}
-
-inline bool Parser::workhorse(bool gnu, const Descriptor usage[], int numargs, const char** args, Action& action,
- bool single_minus_longopt, bool print_errors, int min_abbr_len)
-{
- // protect against NULL pointer
- if (args == 0)
- numargs = 0;
-
- int nonops = 0;
-
- while (numargs != 0 && *args != 0)
- {
- const char* param = *args; // param can be --long-option, -srto or non-option argument
-
- // in POSIX mode the first non-option argument terminates the option list
- // a lone minus character is a non-option argument
- if (param[0] != '-' || param[1] == 0)
- {
- if (gnu)
- {
- ++nonops;
- ++args;
- if (numargs > 0)
- --numargs;
- continue;
- }
- else
- break;
- }
-
- // -- terminates the option list. The -- itself is skipped.
- if (param[1] == '-' && param[2] == 0)
- {
- shift(args, nonops);
- ++args;
- if (numargs > 0)
- --numargs;
- break;
- }
-
- bool handle_short_options;
- const char* longopt_name;
- if (param[1] == '-') // if --long-option
- {
- handle_short_options = false;
- longopt_name = param + 2;
- }
- else
- {
- handle_short_options = true;
- longopt_name = param + 1; //for testing a potential -long-option
- }
-
- bool try_single_minus_longopt = single_minus_longopt;
- bool have_more_args = (numargs > 1 || numargs < 0); // is referencing argv[1] valid?
-
- do // loop over short options in group, for long options the body is executed only once
- {
- int idx;
-
- const char* optarg;
-
- /******************** long option **********************/
- if (handle_short_options == false || try_single_minus_longopt)
- {
- idx = 0;
- while (usage[idx].longopt != 0 && !streq(usage[idx].longopt, longopt_name))
- ++idx;
-
- if (usage[idx].longopt == 0 && min_abbr_len > 0) // if we should try to match abbreviated long options
- {
- int i1 = 0;
- while (usage[i1].longopt != 0 && !streqabbr(usage[i1].longopt, longopt_name, min_abbr_len))
- ++i1;
- if (usage[i1].longopt != 0)
- { // now test if the match is unambiguous by checking for another match
- int i2 = i1 + 1;
- while (usage[i2].longopt != 0 && !streqabbr(usage[i2].longopt, longopt_name, min_abbr_len))
- ++i2;
-
- if (usage[i2].longopt == 0) // if there was no second match it's unambiguous, so accept i1 as idx
- idx = i1;
- }
- }
-
- // if we found something, disable handle_short_options (only relevant if single_minus_longopt)
- if (usage[idx].longopt != 0)
- handle_short_options = false;
-
- try_single_minus_longopt = false; // prevent looking for longopt in the middle of shortopt group
-
- optarg = longopt_name;
- while (*optarg != 0 && *optarg != '=')
- ++optarg;
- if (*optarg == '=') // attached argument
- ++optarg;
- else
- // possibly detached argument
- optarg = (have_more_args ? args[1] : 0);
- }
-
- /************************ short option ***********************************/
- if (handle_short_options)
- {
- if (*++param == 0) // point at the 1st/next option character
- break; // end of short option group
-
- idx = 0;
- while (usage[idx].shortopt != 0 && !instr(*param, usage[idx].shortopt))
- ++idx;
-
- if (param[1] == 0) // if the potential argument is separate
- optarg = (have_more_args ? args[1] : 0);
- else
- // if the potential argument is attached
- optarg = param + 1;
- }
-
- const Descriptor* descriptor = &usage[idx];
-
- if (descriptor->shortopt == 0) /************** unknown option ********************/
- {
- // look for dummy entry (shortopt == "" and longopt == "") to use as Descriptor for unknown options
- idx = 0;
- while (usage[idx].shortopt != 0 && (usage[idx].shortopt[0] != 0 || usage[idx].longopt[0] != 0))
- ++idx;
- descriptor = (usage[idx].shortopt == 0 ? 0 : &usage[idx]);
- }
-
- if (descriptor != 0)
- {
- Option option(descriptor, param, optarg);
- switch (descriptor->check_arg(option, print_errors))
- {
- case ARG_ILLEGAL:
- return false; // fatal
- case ARG_OK:
- // skip one element of the argument vector, if it's a separated argument
- if (optarg != 0 && have_more_args && optarg == args[1])
- {
- shift(args, nonops);
- if (numargs > 0)
- --numargs;
- ++args;
- }
-
- // No further short options are possible after an argument
- handle_short_options = false;
-
- break;
- case ARG_IGNORE:
- case ARG_NONE:
- option.arg = 0;
- break;
- }
-
- if (!action.perform(option))
- return false;
- }
-
- } while (handle_short_options);
-
- shift(args, nonops);
- ++args;
- if (numargs > 0)
- --numargs;
-
- } // while
-
- if (numargs > 0 && *args == 0) // It's a bug in the caller if numargs is greater than the actual number
- numargs = 0; // of arguments, but as a service to the user we fix this if we spot it.
-
- if (numargs < 0) // if we don't know the number of remaining non-option arguments
- { // we need to count them
- numargs = 0;
- while (args[numargs] != 0)
- ++numargs;
- }
-
- return action.finished(numargs + nonops, args - nonops);
-}
-
-/**
- * @internal
- * @brief The implementation of option::printUsage().
- */
-struct PrintUsageImplementation
-{
- /**
- * @internal
- * @brief Interface for Functors that write (part of) a string somewhere.
- */
- struct IStringWriter
- {
- /**
- * @brief Writes the given number of chars beginning at the given pointer somewhere.
- */
- virtual void operator()(const char*, int)
- {
- }
- };
-
- /**
- * @internal
- * @brief Encapsulates a function with signature <code>func(string, size)</code> where
- * string can be initialized with a const char* and size with an int.
- */
- template<typename Function>
- struct FunctionWriter: public IStringWriter
- {
- Function* write;
-
- virtual void operator()(const char* str, int size)
- {
- (*write)(str, size);
- }
-
- FunctionWriter(Function* w) :
- write(w)
- {
- }
- };
-
- /**
- * @internal
- * @brief Encapsulates a reference to an object with a <code>write(string, size)</code>
- * method like that of @c std::ostream.
- */
- template<typename OStream>
- struct OStreamWriter: public IStringWriter
- {
- OStream& ostream;
-
- virtual void operator()(const char* str, int size)
- {
- ostream.write(str, size);
- }
-
- OStreamWriter(OStream& o) :
- ostream(o)
- {
- }
- };
-
- /**
- * @internal
- * @brief Like OStreamWriter but encapsulates a @c const reference, which is
- * typically a temporary object of a user class.
- */
- template<typename Temporary>
- struct TemporaryWriter: public IStringWriter
- {
- const Temporary& userstream;
-
- virtual void operator()(const char* str, int size)
- {
- userstream.write(str, size);
- }
-
- TemporaryWriter(const Temporary& u) :
- userstream(u)
- {
- }
- };
-
- /**
- * @internal
- * @brief Encapsulates a function with the signature <code>func(fd, string, size)</code> (the
- * signature of the @c write() system call)
- * where fd can be initialized from an int, string from a const char* and size from an int.
- */
- template<typename Syscall>
- struct SyscallWriter: public IStringWriter
- {
- Syscall* write;
- int fd;
-
- virtual void operator()(const char* str, int size)
- {
- (*write)(fd, str, size);
- }
-
- SyscallWriter(Syscall* w, int f) :
- write(w), fd(f)
- {
- }
- };
-
- /**
- * @internal
- * @brief Encapsulates a function with the same signature as @c std::fwrite().
- */
- template<typename Function, typename Stream>
- struct StreamWriter: public IStringWriter
- {
- Function* fwrite;
- Stream* stream;
-
- virtual void operator()(const char* str, int size)
- {
- (*fwrite)(str, size, 1, stream);
- }
-
- StreamWriter(Function* w, Stream* s) :
- fwrite(w), stream(s)
- {
- }
- };
-
- /**
- * @internal
- * @brief Sets <code> i1 = max(i1, i2) </code>
- */
- static void upmax(int& i1, int i2)
- {
- i1 = (i1 >= i2 ? i1 : i2);
- }
-
- /**
- * @internal
- * @brief Moves the "cursor" to column @c want_x assuming it is currently at column @c x
- * and sets @c x=want_x .
- * If <code> x > want_x </code>, a line break is output before indenting.
- *
- * @param write Spaces and possibly a line break are written via this functor to get
- * the desired indentation @c want_x .
- * @param[in,out] x the current indentation. Set to @c want_x by this method.
- * @param want_x the desired indentation.
- */
- static void indent(IStringWriter& write, int& x, int want_x)
- {
- int indent = want_x - x;
- if (indent < 0)
- {
- write("\n", 1);
- indent = want_x;
- }
-
- if (indent > 0)
- {
- char space = ' ';
- for (int i = 0; i < indent; ++i)
- write(&space, 1);
- x = want_x;
- }
- }
-
- /**
- * @brief Returns true if ch is the unicode code point of a wide character.
- *
- * @note
- * The following character ranges are treated as wide
- * @code
- * 1100..115F
- * 2329..232A (just 2 characters!)
- * 2E80..A4C6 except for 303F
- * A960..A97C
- * AC00..D7FB
- * F900..FAFF
- * FE10..FE6B
- * FF01..FF60
- * FFE0..FFE6
- * 1B000......
- * @endcode
- */
- static bool isWideChar(unsigned ch)
- {
- if (ch == 0x303F)
- return false;
-
- return ((0x1100 <= ch && ch <= 0x115F) || (0x2329 <= ch && ch <= 0x232A) || (0x2E80 <= ch && ch <= 0xA4C6)
- || (0xA960 <= ch && ch <= 0xA97C) || (0xAC00 <= ch && ch <= 0xD7FB) || (0xF900 <= ch && ch <= 0xFAFF)
- || (0xFE10 <= ch && ch <= 0xFE6B) || (0xFF01 <= ch && ch <= 0xFF60) || (0xFFE0 <= ch && ch <= 0xFFE6)
- || (0x1B000 <= ch));
- }
-
- /**
- * @internal
- * @brief Splits a @c Descriptor[] array into tables, rows, lines and columns and
- * iterates over these components.
- *
- * The top-level organizational unit is the @e table.
- * A table begins at a Descriptor with @c help!=NULL and extends up to
- * a Descriptor with @c help==NULL.
- *
- * A table consists of @e rows. Due to line-wrapping and explicit breaks
- * a row may take multiple lines on screen. Rows within the table are separated
- * by \\n. They never cross Descriptor boundaries. This means a row ends either
- * at \\n or the 0 at the end of the help string.
- *
- * A row consists of columns/cells. Columns/cells within a row are separated by \\t.
- * Line breaks within a cell are marked by \\v.
- *
- * Rows in the same table need not have the same number of columns/cells. The
- * extreme case are interjections, which are rows that contain neither \\t nor \\v.
- * These are NOT treated specially by LinePartIterator, but they are treated
- * specially by printUsage().
- *
- * LinePartIterator iterates through the usage at 3 levels: table, row and part.
- * Tables and rows are as described above. A @e part is a line within a cell.
- * LinePartIterator iterates through 1st parts of all cells, then through the 2nd
- * parts of all cells (if any),... @n
- * Example: The row <code> "1 \v 3 \t 2 \v 4" </code> has 2 cells/columns and 4 parts.
- * The parts will be returned in the order 1, 2, 3, 4.
- *
- * It is possible that some cells have fewer parts than others. In this case
- * LinePartIterator will "fill up" these cells with 0-length parts. IOW, LinePartIterator
- * always returns the same number of parts for each column. Note that this is different
- * from the way rows and columns are handled. LinePartIterator does @e not guarantee that
- * the same number of columns will be returned for each row.
- *
- */
- class LinePartIterator
- {
- const Descriptor* tablestart; //!< The 1st descriptor of the current table.
- const Descriptor* rowdesc; //!< The Descriptor that contains the current row.
- const char* rowstart; //!< Ptr to 1st character of current row within rowdesc->help.
- const char* ptr; //!< Ptr to current part within the current row.
- int col; //!< Index of current column.
- int len; //!< Length of the current part (that ptr points at) in BYTES
- int screenlen; //!< Length of the current part in screen columns (taking narrow/wide chars into account).
- int max_line_in_block; //!< Greatest index of a line within the block. This is the number of \\v within the cell with the most \\vs.
- int line_in_block; //!< Line index within the current cell of the current part.
- int target_line_in_block; //!< Line index of the parts we should return to the user on this iteration.
- bool hit_target_line; //!< Flag whether we encountered a part with line index target_line_in_block in the current cell.
-
- /**
- * @brief Determines the byte and character lengths of the part at @ref ptr and
- * stores them in @ref len and @ref screenlen respectively.
- */
- void update_length()
- {
- screenlen = 0;
- for (len = 0; ptr[len] != 0 && ptr[len] != '\v' && ptr[len] != '\t' && ptr[len] != '\n'; ++len)
- {
- ++screenlen;
- unsigned ch = (unsigned char) ptr[len];
- if (ch > 0xC1) // everything <= 0xC1 (yes, even 0xC1 itself) is not a valid UTF-8 start byte
- {
- // int __builtin_clz (unsigned int x)
- // Returns the number of leading 0-bits in x, starting at the most significant bit
- unsigned mask = (unsigned) -1 >> __builtin_clz(ch ^ 0xff);
- ch = ch & mask; // mask out length bits, we don't verify their correctness
- while (((unsigned char) ptr[len + 1] ^ 0x80) <= 0x3F) // while next byte is continuation byte
- {
- ch = (ch << 6) ^ (unsigned char) ptr[len + 1] ^ 0x80; // add continuation to char code
- ++len;
- }
- // ch is the decoded unicode code point
- if (ch >= 0x1100 && isWideChar(ch)) // the test for 0x1100 is here to avoid the function call in the Latin case
- ++screenlen;
- }
- }
- }
-
- public:
- //! @brief Creates an iterator for @c usage.
- LinePartIterator(const Descriptor usage[]) :
- tablestart(usage), rowdesc(0), rowstart(0), ptr(0), col(-1), len(0), max_line_in_block(0), line_in_block(0),
- target_line_in_block(0), hit_target_line(true)
- {
- }
-
- /**
- * @brief Moves iteration to the next table (if any). Has to be called once on a new
- * LinePartIterator to move to the 1st table.
- * @retval false if moving to next table failed because no further table exists.
- */
- bool nextTable()
- {
- // If this is NOT the first time nextTable() is called after the constructor,
- // then skip to the next table break (i.e. a Descriptor with help == 0)
- if (rowdesc != 0)
- {
- while (tablestart->help != 0 && tablestart->shortopt != 0)
- ++tablestart;
- }
-
- // Find the next table after the break (if any)
- while (tablestart->help == 0 && tablestart->shortopt != 0)
- ++tablestart;
-
- restartTable();
- return rowstart != 0;
- }
-
- /**
- * @brief Reset iteration to the beginning of the current table.
- */
- void restartTable()
- {
- rowdesc = tablestart;
- rowstart = tablestart->help;
- ptr = 0;
- }
-
- /**
- * @brief Moves iteration to the next row (if any). Has to be called once after each call to
- * @ref nextTable() to move to the 1st row of the table.
- * @retval false if moving to next row failed because no further row exists.
- */
- bool nextRow()
- {
- if (ptr == 0)
- {
- restartRow();
- return rowstart != 0;
- }
-
- while (*ptr != 0 && *ptr != '\n')
- ++ptr;
-
- if (*ptr == 0)
- {
- if ((rowdesc + 1)->help == 0) // table break
- return false;
-
- ++rowdesc;
- rowstart = rowdesc->help;
- }
- else // if (*ptr == '\n')
- {
- rowstart = ptr + 1;
- }
-
- restartRow();
- return true;
- }
-
- /**
- * @brief Reset iteration to the beginning of the current row.
- */
- void restartRow()
- {
- ptr = rowstart;
- col = -1;
- len = 0;
- screenlen = 0;
- max_line_in_block = 0;
- line_in_block = 0;
- target_line_in_block = 0;
- hit_target_line = true;
- }
-
- /**
- * @brief Moves iteration to the next part (if any). Has to be called once after each call to
- * @ref nextRow() to move to the 1st part of the row.
- * @retval false if moving to next part failed because no further part exists.
- *
- * See @ref LinePartIterator for details about the iteration.
- */
- bool next()
- {
- if (ptr == 0)
- return false;
-
- if (col == -1)
- {
- col = 0;
- update_length();
- return true;
- }
-
- ptr += len;
- while (true)
- {
- switch (*ptr)
- {
- case '\v':
- upmax(max_line_in_block, ++line_in_block);
- ++ptr;
- break;
- case '\t':
- if (!hit_target_line) // if previous column did not have the targetline
- { // then "insert" a 0-length part
- update_length();
- hit_target_line = true;
- return true;
- }
-
- hit_target_line = false;
- line_in_block = 0;
- ++col;
- ++ptr;
- break;
- case 0:
- case '\n':
- if (!hit_target_line) // if previous column did not have the targetline
- { // then "insert" a 0-length part
- update_length();
- hit_target_line = true;
- return true;
- }
-
- if (++target_line_in_block > max_line_in_block)
- {
- update_length();
- return false;
- }
-
- hit_target_line = false;
- line_in_block = 0;
- col = 0;
- ptr = rowstart;
- continue;
- default:
- ++ptr;
- continue;
- } // switch
-
- if (line_in_block == target_line_in_block)
- {
- update_length();
- hit_target_line = true;
- return true;
- }
- } // while
- }
-
- /**
- * @brief Returns the index (counting from 0) of the column in which
- * the part pointed to by @ref data() is located.
- */
- int column()
- {
- return col;
- }
-
- /**
- * @brief Returns the index (counting from 0) of the line within the current column
- * this part belongs to.
- */
- int line()
- {
- return target_line_in_block; // NOT line_in_block !!! It would be wrong if !hit_target_line
- }
-
- /**
- * @brief Returns the length of the part pointed to by @ref data() in raw chars (not UTF-8 characters).
- */
- int length()
- {
- return len;
- }
-
- /**
- * @brief Returns the width in screen columns of the part pointed to by @ref data().
- * Takes multi-byte UTF-8 sequences and wide characters into account.
- */
- int screenLength()
- {
- return screenlen;
- }
-
- /**
- * @brief Returns the current part of the iteration.
- */
- const char* data()
- {
- return ptr;
- }
- };
-
- /**
- * @internal
- * @brief Takes input and line wraps it, writing out one line at a time so that
- * it can be interleaved with output from other columns.
- *
- * The LineWrapper is used to handle the last column of each table as well as interjections.
- * The LineWrapper is called once for each line of output. If the data given to it fits
- * into the designated width of the last column it is simply written out. If there
- * is too much data, an appropriate split point is located and only the data up to this
- * split point is written out. The rest of the data is queued for the next line.
- * That way the last column can be line wrapped and interleaved with data from
- * other columns. The following example makes this clearer:
- * @code
- * Column 1,1 Column 2,1 This is a long text
- * Column 1,2 Column 2,2 that does not fit into
- * a single line.
- * @endcode
- *
- * The difficulty in producing this output is that the whole string
- * "This is a long text that does not fit into a single line" is the
- * 1st and only part of column 3. In order to produce the above
- * output the string must be output piecemeal, interleaved with
- * the data from the other columns.
- */
- class LineWrapper
- {
- static const int bufmask = 15; //!< Must be a power of 2 minus 1.
- /**
- * @brief Ring buffer for length component of pair (data, length).
- */
- int lenbuf[bufmask + 1];
- /**
- * @brief Ring buffer for data component of pair (data, length).
- */
- const char* datbuf[bufmask + 1];
- /**
- * @brief The indentation of the column to which the LineBuffer outputs. LineBuffer
- * assumes that the indentation has already been written when @ref process()
- * is called, so this value is only used when a buffer flush requires writing
- * additional lines of output.
- */
- int x;
- /**
- * @brief The width of the column to line wrap.
- */
- int width;
- int head; //!< @brief index for next write
- int tail; //!< @brief index for next read - 1 (i.e. increment tail BEFORE read)
-
- /**
- * @brief Multiple methods of LineWrapper may decide to flush part of the buffer to
- * free up space. The contract of process() says that only 1 line is output. So
- * this variable is used to track whether something has output a line. It is
- * reset at the beginning of process() and checked at the end to decide if
- * output has already occurred or is still needed.
- */
- bool wrote_something;
-
- bool buf_empty()
- {
- return ((tail + 1) & bufmask) == head;
- }
-
- bool buf_full()
- {
- return tail == head;
- }
-
- void buf_store(const char* data, int len)
- {
- lenbuf[head] = len;
- datbuf[head] = data;
- head = (head + 1) & bufmask;
- }
-
- //! @brief Call BEFORE reading ...buf[tail].
- void buf_next()
- {
- tail = (tail + 1) & bufmask;
- }
-
- /**
- * @brief Writes (data,len) into the ring buffer. If the buffer is full, a single line
- * is flushed out of the buffer into @c write.
- */
- void output(IStringWriter& write, const char* data, int len)
- {
- if (buf_full())
- write_one_line(write);
-
- buf_store(data, len);
- }
-
- /**
- * @brief Writes a single line of output from the buffer to @c write.
- */
- void write_one_line(IStringWriter& write)
- {
- if (wrote_something) // if we already wrote something, we need to start a new line
- {
- write("\n", 1);
- int _ = 0;
- indent(write, _, x);
- }
-
- if (!buf_empty())
- {
- buf_next();
- write(datbuf[tail], lenbuf[tail]);
- }
-
- wrote_something = true;
- }
- public:
-
- /**
- * @brief Writes out all remaining data from the LineWrapper using @c write.
- * Unlike @ref process() this method indents all lines including the first and
- * will output a \\n at the end (but only if something has been written).
- */
- void flush(IStringWriter& write)
- {
- if (buf_empty())
- return;
- int _ = 0;
- indent(write, _, x);
- wrote_something = false;
- while (!buf_empty())
- write_one_line(write);
- write("\n", 1);
- }
-
- /**
- * @brief Process, wrap and output the next piece of data.
- *
- * process() will output at least one line of output. This is not necessarily
- * the @c data passed in. It may be data queued from a prior call to process().
- * If the internal buffer is full, more than 1 line will be output.
- *
- * process() assumes that the a proper amount of indentation has already been
- * output. It won't write any further indentation before the 1st line. If
- * more than 1 line is written due to buffer constraints, the lines following
- * the first will be indented by this method, though.
- *
- * No \\n is written by this method after the last line that is written.
- *
- * @param write where to write the data.
- * @param data the new chunk of data to write.
- * @param len the length of the chunk of data to write.
- */
- void process(IStringWriter& write, const char* data, int len)
- {
- wrote_something = false;
-
- while (len > 0)
- {
- if (len <= width) // quick test that works because utf8width <= len (all wide chars have at least 2 bytes)
- {
- output(write, data, len);
- len = 0;
- }
- else // if (len > width) it's possible (but not guaranteed) that utf8len > width
- {
- int utf8width = 0;
- int maxi = 0;
- while (maxi < len && utf8width < width)
- {
- int charbytes = 1;
- unsigned ch = (unsigned char) data[maxi];
- if (ch > 0xC1) // everything <= 0xC1 (yes, even 0xC1 itself) is not a valid UTF-8 start byte
- {
- // int __builtin_clz (unsigned int x)
- // Returns the number of leading 0-bits in x, starting at the most significant bit
- unsigned mask = (unsigned) -1 >> __builtin_clz(ch ^ 0xff);
- ch = ch & mask; // mask out length bits, we don't verify their correctness
- while ((maxi + charbytes < len) && //
- (((unsigned char) data[maxi + charbytes] ^ 0x80) <= 0x3F)) // while next byte is continuation byte
- {
- ch = (ch << 6) ^ (unsigned char) data[maxi + charbytes] ^ 0x80; // add continuation to char code
- ++charbytes;
- }
- // ch is the decoded unicode code point
- if (ch >= 0x1100 && isWideChar(ch)) // the test for 0x1100 is here to avoid the function call in the Latin case
- {
- if (utf8width + 2 > width)
- break;
- ++utf8width;
- }
- }
- ++utf8width;
- maxi += charbytes;
- }
-
- // data[maxi-1] is the last byte of the UTF-8 sequence of the last character that fits
- // onto the 1st line. If maxi == len, all characters fit on the line.
-
- if (maxi == len)
- {
- output(write, data, len);
- len = 0;
- }
- else // if (maxi < len) at least 1 character (data[maxi] that is) doesn't fit on the line
- {
- int i;
- for (i = maxi; i >= 0; --i)
- if (data[i] == ' ')
- break;
-
- if (i >= 0)
- {
- output(write, data, i);
- data += i + 1;
- len -= i + 1;
- }
- else // did not find a space to split at => split before data[maxi]
- { // data[maxi] is always the beginning of a character, never a continuation byte
- output(write, data, maxi);
- data += maxi;
- len -= maxi;
- }
- }
- }
- }
- if (!wrote_something) // if we didn't already write something to make space in the buffer
- write_one_line(write); // write at most one line of actual output
- }
-
- /**
- * @brief Constructs a LineWrapper that wraps its output to fit into
- * screen columns @c x1 (incl.) to @c x2 (excl.).
- *
- * @c x1 gives the indentation LineWrapper uses if it needs to indent.
- */
- LineWrapper(int x1, int x2) :
- x(x1), width(x2 - x1), head(0), tail(bufmask)
- {
- if (width < 2) // because of wide characters we need at least width 2 or the code breaks
- width = 2;
- }
- };
-
- /**
- * @internal
- * @brief This is the implementation that is shared between all printUsage() templates.
- * Because all printUsage() templates share this implementation, there is no template bloat.
- */
- static void printUsage(IStringWriter& write, const Descriptor usage[], int width = 80, //
- int last_column_min_percent = 50, int last_column_own_line_max_percent = 75)
- {
- if (width < 1) // protect against nonsense values
- width = 80;
-
- if (width > 10000) // protect against overflow in the following computation
- width = 10000;
-
- int last_column_min_width = ((width * last_column_min_percent) + 50) / 100;
- int last_column_own_line_max_width = ((width * last_column_own_line_max_percent) + 50) / 100;
- if (last_column_own_line_max_width == 0)
- last_column_own_line_max_width = 1;
-
- LinePartIterator part(usage);
- while (part.nextTable())
- {
-
- /***************** Determine column widths *******************************/
-
- const int maxcolumns = 8; // 8 columns are enough for everyone
- int col_width[maxcolumns];
- int lastcolumn;
- int leftwidth;
- int overlong_column_threshold = 10000;
- do
- {
- lastcolumn = 0;
- for (int i = 0; i < maxcolumns; ++i)
- col_width[i] = 0;
-
- part.restartTable();
- while (part.nextRow())
- {
- while (part.next())
- {
- if (part.column() < maxcolumns)
- {
- upmax(lastcolumn, part.column());
- if (part.screenLength() < overlong_column_threshold)
- // We don't let rows that don't use table separators (\t or \v) influence
- // the width of column 0. This allows the user to interject section headers
- // or explanatory paragraphs that do not participate in the table layout.
- if (part.column() > 0 || part.line() > 0 || part.data()[part.length()] == '\t'
- || part.data()[part.length()] == '\v')
- upmax(col_width[part.column()], part.screenLength());
- }
- }
- }
-
- /*
- * If the last column doesn't fit on the same
- * line as the other columns, we can fix that by starting it on its own line.
- * However we can't do this for any of the columns 0..lastcolumn-1.
- * If their sum exceeds the maximum width we try to fix this by iteratively
- * ignoring the widest line parts in the width determination until
- * we arrive at a series of column widths that fit into one line.
- * The result is a layout where everything is nicely formatted
- * except for a few overlong fragments.
- * */
-
- leftwidth = 0;
- overlong_column_threshold = 0;
- for (int i = 0; i < lastcolumn; ++i)
- {
- leftwidth += col_width[i];
- upmax(overlong_column_threshold, col_width[i]);
- }
-
- } while (leftwidth > width);
-
- /**************** Determine tab stops and last column handling **********************/
-
- int tabstop[maxcolumns];
- tabstop[0] = 0;
- for (int i = 1; i < maxcolumns; ++i)
- tabstop[i] = tabstop[i - 1] + col_width[i - 1];
-
- int rightwidth = width - tabstop[lastcolumn];
- bool print_last_column_on_own_line = false;
- if (rightwidth < last_column_min_width && // if we don't have the minimum requested width for the last column
- ( col_width[lastcolumn] == 0 || // and all last columns are > overlong_column_threshold
- rightwidth < col_width[lastcolumn] // or there is at least one last column that requires more than the space available
- )
- )
- {
- print_last_column_on_own_line = true;
- rightwidth = last_column_own_line_max_width;
- }
-
- // If lastcolumn == 0 we must disable print_last_column_on_own_line because
- // otherwise 2 copies of the last (and only) column would be output.
- // Actually this is just defensive programming. It is currently not
- // possible that lastcolumn==0 and print_last_column_on_own_line==true
- // at the same time, because lastcolumn==0 => tabstop[lastcolumn] == 0 =>
- // rightwidth==width => rightwidth>=last_column_min_width (unless someone passes
- // a bullshit value >100 for last_column_min_percent) => the above if condition
- // is false => print_last_column_on_own_line==false
- if (lastcolumn == 0)
- print_last_column_on_own_line = false;
-
- LineWrapper lastColumnLineWrapper(width - rightwidth, width);
- LineWrapper interjectionLineWrapper(0, width);
-
- part.restartTable();
-
- /***************** Print out all rows of the table *************************************/
-
- while (part.nextRow())
- {
- int x = -1;
- while (part.next())
- {
- if (part.column() > lastcolumn)
- continue; // drop excess columns (can happen if lastcolumn == maxcolumns-1)
-
- if (part.column() == 0)
- {
- if (x >= 0)
- write("\n", 1);
- x = 0;
- }
-
- indent(write, x, tabstop[part.column()]);
-
- if ((part.column() < lastcolumn)
- && (part.column() > 0 || part.line() > 0 || part.data()[part.length()] == '\t'
- || part.data()[part.length()] == '\v'))
- {
- write(part.data(), part.length());
- x += part.screenLength();
- }
- else // either part.column() == lastcolumn or we are in the special case of
- // an interjection that doesn't contain \v or \t
- {
- // NOTE: This code block is not necessarily executed for
- // each line, because some rows may have fewer columns.
-
- LineWrapper& lineWrapper = (part.column() == 0) ? interjectionLineWrapper : lastColumnLineWrapper;
-
- if (!print_last_column_on_own_line || part.column() != lastcolumn)
- lineWrapper.process(write, part.data(), part.length());
- }
- } // while
-
- if (print_last_column_on_own_line)
- {
- part.restartRow();
- while (part.next())
- {
- if (part.column() == lastcolumn)
- {
- write("\n", 1);
- int _ = 0;
- indent(write, _, width - rightwidth);
- lastColumnLineWrapper.process(write, part.data(), part.length());
- }
- }
- }
-
- write("\n", 1);
- lastColumnLineWrapper.flush(write);
- interjectionLineWrapper.flush(write);
- }
- }
- }
-
-}
-;
-
-/**
- * @brief Outputs a nicely formatted usage string with support for multi-column formatting
- * and line-wrapping.
- *
- * printUsage() takes the @c help texts of a Descriptor[] array and formats them into
- * a usage message, wrapping lines to achieve the desired output width.
- *
- * <b>Table formatting:</b>
- *
- * Aside from plain strings which are simply line-wrapped, the usage may contain tables. Tables
- * are used to align elements in the output.
- *
- * @code
- * // Without a table. The explanatory texts are not aligned.
- * -c, --create |Creates something.
- * -k, --kill |Destroys something.
- *
- * // With table formatting. The explanatory texts are aligned.
- * -c, --create |Creates something.
- * -k, --kill |Destroys something.
- * @endcode
- *
- * Table formatting removes the need to pad help texts manually with spaces to achieve
- * alignment. To create a table, simply insert \\t (tab) characters to separate the cells
- * within a row.
- *
- * @code
- * const option::Descriptor usage[] = {
- * {..., "-c, --create \tCreates something." },
- * {..., "-k, --kill \tDestroys something." }, ...
- * @endcode
- *
- * Note that you must include the minimum amount of space desired between cells yourself.
- * Table formatting will insert further spaces as needed to achieve alignment.
- *
- * You can insert line breaks within cells by using \\v (vertical tab).
- *
- * @code
- * const option::Descriptor usage[] = {
- * {..., "-c,\v--create \tCreates\vsomething." },
- * {..., "-k,\v--kill \tDestroys\vsomething." }, ...
- *
- * // results in
- *
- * -c, Creates
- * --create something.
- * -k, Destroys
- * --kill something.
- * @endcode
- *
- * You can mix lines that do not use \\t or \\v with those that do. The plain
- * lines will not mess up the table layout. Alignment of the table columns will
- * be maintained even across these interjections.
- *
- * @code
- * const option::Descriptor usage[] = {
- * {..., "-c, --create \tCreates something." },
- * {..., "----------------------------------" },
- * {..., "-k, --kill \tDestroys something." }, ...
- *
- * // results in
- *
- * -c, --create Creates something.
- * ----------------------------------
- * -k, --kill Destroys something.
- * @endcode
- *
- * You can have multiple tables within the same usage whose columns are
- * aligned independently. Simply insert a dummy Descriptor with @c help==0.
- *
- * @code
- * const option::Descriptor usage[] = {
- * {..., "Long options:" },
- * {..., "--very-long-option \tDoes something long." },
- * {..., "--ultra-super-mega-long-option \tTakes forever to complete." },
- * {..., 0 }, // ---------- table break -----------
- * {..., "Short options:" },
- * {..., "-s \tShort." },
- * {..., "-q \tQuick." }, ...
- *
- * // results in
- *
- * Long options:
- * --very-long-option Does something long.
- * --ultra-super-mega-long-option Takes forever to complete.
- * Short options:
- * -s Short.
- * -q Quick.
- *
- * // Without the table break it would be
- *
- * Long options:
- * --very-long-option Does something long.
- * --ultra-super-mega-long-option Takes forever to complete.
- * Short options:
- * -s Short.
- * -q Quick.
- * @endcode
- *
- * <b>Output methods:</b>
- *
- * Because TheLeanMeanC++Option parser is freestanding, you have to provide the means for
- * output in the first argument(s) to printUsage(). Because printUsage() is implemented as
- * a set of template functions, you have great flexibility in your choice of output
- * method. The following example demonstrates typical uses. Anything that's similar enough
- * will work.
- *
- * @code
- * #include <unistd.h> // write()
- * #include <iostream> // cout
- * #include <sstream> // ostringstream
- * #include <cstdio> // fwrite()
- * using namespace std;
- *
- * void my_write(const char* str, int size) {
- * fwrite(str, size, 1, stdout);
- * }
- *
- * struct MyWriter {
- * void write(const char* buf, size_t size) const {
- * fwrite(str, size, 1, stdout);
- * }
- * };
- *
- * struct MyWriteFunctor {
- * void operator()(const char* buf, size_t size) {
- * fwrite(str, size, 1, stdout);
- * }
- * };
- * ...
- * printUsage(my_write, usage); // custom write function
- * printUsage(MyWriter(), usage); // temporary of a custom class
- * MyWriter writer;
- * printUsage(writer, usage); // custom class object
- * MyWriteFunctor wfunctor;
- * printUsage(&wfunctor, usage); // custom functor
- * printUsage(write, 1, usage); // write() to file descriptor 1
- * printUsage(cout, usage); // an ostream&
- * printUsage(fwrite, stdout, usage); // fwrite() to stdout
- * ostringstream sstr;
- * printUsage(sstr, usage); // an ostringstream&
- *
- * @endcode
- *
- * @par Notes:
- * @li the @c write() method of a class that is to be passed as a temporary
- * as @c MyWriter() is in the example, must be a @c const method, because
- * temporary objects are passed as const reference. This only applies to
- * temporary objects that are created and destroyed in the same statement.
- * If you create an object like @c writer in the example, this restriction
- * does not apply.
- * @li a functor like @c MyWriteFunctor in the example must be passed as a pointer.
- * This differs from the way functors are passed to e.g. the STL algorithms.
- * @li All printUsage() templates are tiny wrappers around a shared non-template implementation.
- * So there's no penalty for using different versions in the same program.
- * @li printUsage() always interprets Descriptor::help as UTF-8 and always produces UTF-8-encoded
- * output. If your system uses a different charset, you must do your own conversion. You
- * may also need to change the font of the console to see non-ASCII characters properly.
- * This is particularly true for Windows.
- * @li @b Security @b warning: Do not insert untrusted strings (such as user-supplied arguments)
- * into the usage. printUsage() has no protection against malicious UTF-8 sequences.
- *
- * @param prn The output method to use. See the examples above.
- * @param usage the Descriptor[] array whose @c help texts will be formatted.
- * @param width the maximum number of characters per output line. Note that this number is
- * in actual characters, not bytes. printUsage() supports UTF-8 in @c help and will
- * count multi-byte UTF-8 sequences properly. Asian wide characters are counted
- * as 2 characters.
- * @param last_column_min_percent (0-100) The minimum percentage of @c width that should be available
- * for the last column (which typically contains the textual explanation of an option).
- * If less space is available, the last column will be printed on its own line, indented
- * according to @c last_column_own_line_max_percent.
- * @param last_column_own_line_max_percent (0-100) If the last column is printed on its own line due to
- * less than @c last_column_min_percent of the width being available, then only
- * @c last_column_own_line_max_percent of the extra line(s) will be used for the
- * last column's text. This ensures an indentation. See example below.
- *
- * @code
- * // width=20, last_column_min_percent=50 (i.e. last col. min. width=10)
- * --3456789 1234567890
- * 1234567890
- *
- * // width=20, last_column_min_percent=75 (i.e. last col. min. width=15)
- * // last_column_own_line_max_percent=75
- * --3456789
- * 123456789012345
- * 67890
- *
- * // width=20, last_column_min_percent=75 (i.e. last col. min. width=15)
- * // last_column_own_line_max_percent=33 (i.e. max. 5)
- * --3456789
- * 12345
- * 67890
- * 12345
- * 67890
- * @endcode
- */
-template<typename OStream>
-void printUsage(OStream& prn, const Descriptor usage[], int width = 80, int last_column_min_percent = 50,
- int last_column_own_line_max_percent = 75)
-{
- PrintUsageImplementation::OStreamWriter<OStream> write(prn);
- PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent);
-}
-
-template<typename Function>
-void printUsage(Function* prn, const Descriptor usage[], int width = 80, int last_column_min_percent = 50,
- int last_column_own_line_max_percent = 75)
-{
- PrintUsageImplementation::FunctionWriter<Function> write(prn);
- PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent);
-}
-
-template<typename Temporary>
-void printUsage(const Temporary& prn, const Descriptor usage[], int width = 80, int last_column_min_percent = 50,
- int last_column_own_line_max_percent = 75)
-{
- PrintUsageImplementation::TemporaryWriter<Temporary> write(prn);
- PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent);
-}
-
-template<typename Syscall>
-void printUsage(Syscall* prn, int fd, const Descriptor usage[], int width = 80, int last_column_min_percent = 50,
- int last_column_own_line_max_percent = 75)
-{
- PrintUsageImplementation::SyscallWriter<Syscall> write(prn, fd);
- PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent);
-}
-
-template<typename Function, typename Stream>
-void printUsage(Function* prn, Stream* stream, const Descriptor usage[], int width = 80, int last_column_min_percent =
- 50,
- int last_column_own_line_max_percent = 75)
-{
- PrintUsageImplementation::StreamWriter<Function, Stream> write(prn, stream);
- PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent);
-}
-
-}
-// namespace option
-
-#endif /* OPTIONPARSER_H_ */
+++ /dev/null
-/*
-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/>.
-*/
-
-#include <stdlib.h>
-
-#include "binio.h"
-#include "private.h"
-
-struct BinIOPackContext {
- uint8_t *buffer;
- va_list args;
-};
-
-static void BinIOPack(void *context, int type, int byte_order, int count)
-{
- struct BinIOPackContext *ctx = (struct BinIOPackContext*)context;
- if (count == -1) {
- switch (type) {
- case BinIO_TYPE_IGNORE_BYTE: {
- ctx->buffer += 1;
- }
- break;
- case BinIO_TYPE_BYTE: {
- uint8_t value = va_arg(ctx->args, int);
- BinIOConvert1(BinIO_HOST_BYTE_ORDER, byte_order, (const uint8_t *)&value, ctx->buffer, 1);
- ctx->buffer += 1;
- }
- break;
- case BinIO_TYPE_INT16: {
- uint16_t value = va_arg(ctx->args, int);
- BinIOConvert2(BinIO_HOST_BYTE_ORDER, byte_order, (const uint8_t *)&value, ctx->buffer, 1);
- ctx->buffer += 2;
- }
- break;
- case BinIO_TYPE_INT32: {
- int value = va_arg(ctx->args, int);
- BinIOConvert4(BinIO_HOST_BYTE_ORDER, byte_order, (const uint8_t *)&value, ctx->buffer, 1);
- ctx->buffer += 4;
- }
- break;
- case BinIO_TYPE_INT64: {
- uint64_t value = va_arg(ctx->args, uint64_t);
- BinIOConvert8(BinIO_HOST_BYTE_ORDER, byte_order, (const uint8_t *)&value, ctx->buffer, 1);
- ctx->buffer += 8;
- }
- break;
- case BinIO_TYPE_FLOAT32: {
- float32_t value = (float32_t)va_arg(ctx->args, double);
- BinIOConvert4(BinIO_HOST_BYTE_ORDER, byte_order, (const uint8_t *)&value, ctx->buffer, 1);
- ctx->buffer += 4;
- }
- break;
- case BinIO_TYPE_FLOAT64: {
- float64_t value = va_arg(ctx->args, float64_t);
- BinIOConvert8(BinIO_HOST_BYTE_ORDER, byte_order, (const uint8_t *)&value, ctx->buffer, 1);
- ctx->buffer += 8;
- }
- break;
- }
- } else {
- switch (type) {
- case BinIO_TYPE_IGNORE_BYTE:
- ctx->buffer += 1 * count;
- break;
- case BinIO_TYPE_BYTE:
- BinIOConvert1(BinIO_HOST_BYTE_ORDER, byte_order, va_arg(ctx->args, uint8_t *), ctx->buffer, count);
- ctx->buffer += 1 * count;
- break;
- case BinIO_TYPE_INT16:
- BinIOConvert2(BinIO_HOST_BYTE_ORDER, byte_order, va_arg(ctx->args, uint8_t *), ctx->buffer, count);
- ctx->buffer += 2 * count;
- break;
- case BinIO_TYPE_INT32:
- BinIOConvert4(BinIO_HOST_BYTE_ORDER, byte_order, va_arg(ctx->args, uint8_t *), ctx->buffer, count);
- ctx->buffer += 4 * count;
- break;
- case BinIO_TYPE_INT64:
- BinIOConvert8(BinIO_HOST_BYTE_ORDER, byte_order, va_arg(ctx->args, uint8_t *), ctx->buffer, count);
- ctx->buffer += 8 * count;
- break;
- case BinIO_TYPE_FLOAT32:
- BinIOConvert4(BinIO_HOST_BYTE_ORDER, byte_order, va_arg(ctx->args, uint8_t *), ctx->buffer, count);
- ctx->buffer += 4 * count;
- break;
- case BinIO_TYPE_FLOAT64:
- BinIOConvert8(BinIO_HOST_BYTE_ORDER, byte_order, va_arg(ctx->args, uint8_t *), ctx->buffer, count);
- ctx->buffer += 8 * count;
- break;
- }
- }
-}
-
-extern void packf(const char *format, ...)
-{
- va_list args;
- va_start(args, format);
- vfpackf(stdout, format, args);
- va_end(args);
-}
-
-extern void spackf(void *buffer, const char *format, ...)
-{
- va_list args;
- va_start(args, format);
- vspackf(buffer, format, args);
- va_end(args);
-}
-
-extern void fpackf(FILE *file, const char *format, ...)
-{
- va_list args;
- va_start(args, format);
- vfpackf(file, format, args);
- va_end(args);
-}
-
-extern void vspackf(void *buffer, const char *format, va_list args)
-{
- struct BinIOFormatCursor cursor;
- struct BinIOPackContext context;
-
- BinIOInitFormatCursor(&cursor, format);
-
- context.buffer = (unsigned char *)buffer;
- va_copy(context.args, args);
-
- while (BinIONextChar(&context, &cursor, BinIOPack)) {}
-
- va_end(context.args);
-}
-
-extern void vfpackf(FILE *file, const char *format, va_list args)
-{
- size_t n_bytes = BinIOFormatByteCount(format);
- void* buffer = malloc(n_bytes);
-
- vspackf(buffer, format, args);
-
- fwrite(buffer, n_bytes, 1, file);
- free(buffer);
-}
+++ /dev/null
-/*
-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/>.
-*/
-
-#include <string.h>
-
-#include "private.h"
-
-void BinIOConvert1(int from_byte_order, int to_byte_order,
- const uint8_t *src, uint8_t *dst,
- unsigned int count)
-{
- if (BinIONormalizeByteOrder(from_byte_order) !=
- BinIONormalizeByteOrder(to_byte_order)) {
- unsigned int i;
- for (i = 0; i < count; ++i) {
- BinIOSwap1(src, dst);
- src += 1;
- dst += 1;
- }
- } else {
- memcpy(dst, src, 1 * count);
- }
-}
-
-void BinIOConvert2(int from_byte_order, int to_byte_order,
- const uint8_t *src, uint8_t *dst,
- unsigned int count)
-{
- if (BinIONormalizeByteOrder(from_byte_order) !=
- BinIONormalizeByteOrder(to_byte_order)) {
- unsigned int i;
- for (i = 0; i < count; ++i) {
- BinIOSwap2(src, dst);
- src += 2;
- dst += 2;
- }
- } else {
- memcpy(dst, src, 2 * count);
- }
-}
-
-void BinIOConvert4(int from_byte_order, int to_byte_order,
- const uint8_t *src, uint8_t *dst,
- unsigned int count)
-{
- if (BinIONormalizeByteOrder(from_byte_order) !=
- BinIONormalizeByteOrder(to_byte_order)) {
- unsigned int i;
- for (i = 0; i < count; ++i) {
- BinIOSwap4(src, dst);
- src += 4;
- dst += 4;
- }
- } else {
- memcpy(dst, src, 4 * count);
- }
-}
-
-void BinIOConvert8(int from_byte_order, int to_byte_order,
- const uint8_t *src, uint8_t *dst,
- unsigned int count)
-{
- if (BinIONormalizeByteOrder(from_byte_order) !=
- BinIONormalizeByteOrder(to_byte_order)) {
- unsigned int i;
- for (i = 0; i < count; ++i) {
- BinIOSwap8(src, dst);
- src += 8;
- dst += 8;
- }
- } else {
- memcpy(dst, src, 8 * count);
- }
-}
-
-void BinIOInitFormatCursor(struct BinIOFormatCursor *cursor,
- const char *format)
-{
- cursor->cursor = format;
- cursor->byte_order = BinIO_HOST_BYTE_ORDER;
- cursor->count = -1;
-}
-
-int BinIONextChar(void *context,
- struct BinIOFormatCursor *cursor,
- BinIOProcessFunction func)
-{
- int count, value;
- int c;
- switch (c = *(cursor->cursor)++) {
- case BinIO_LITTLE_ENDIAN_BYTE_ORDER:
- case BinIO_BIG_ENDIAN_BYTE_ORDER:
- case BinIO_HOST_BYTE_ORDER:
- case BinIO_NETWORK_BYTE_ORDER:
- cursor->byte_order = c;
- break;
-
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- count = cursor->count;
- value = c - '0';
- if (count == -1) {
- cursor->count = value;
- } else {
- cursor->count = (count * 10) + value;
- }
- break;
-
- case BinIO_TYPE_IGNORE_BYTE:
- case BinIO_TYPE_BYTE:
- case BinIO_TYPE_INT16:
- case BinIO_TYPE_INT32:
- case BinIO_TYPE_INT64:
- case BinIO_TYPE_FLOAT32:
- case BinIO_TYPE_FLOAT64:
- func(context, c, cursor->byte_order, cursor->count);
- cursor->byte_order = BinIO_HOST_BYTE_ORDER;
- cursor->count = -1;
- break;
-
- case ' ':
- case '\t':
- case '\r':
- case '\n':
- break;
-
- default:
- return 0;
- }
-
- return 1;
-}
-
-extern void BinIOCountBytes(void *context, int type, int byte_order, int count)
-{
- size_t type_size = 0;
-
- if (count == -1) {
- count = 1;
- }
-
- switch (type) {
- case BinIO_TYPE_IGNORE_BYTE:
- type_size = 1;
- break;
- case BinIO_TYPE_BYTE:
- type_size = 1;
- break;
- case BinIO_TYPE_INT16:
- type_size = 2;
- break;
- case BinIO_TYPE_INT32:
- type_size = 4;
- break;
- case BinIO_TYPE_INT64:
- type_size = 8;
- break;
- case BinIO_TYPE_FLOAT32:
- type_size = 4;
- break;
- case BinIO_TYPE_FLOAT64:
- type_size = 8;
- break;
- }
-
- *(size_t*)context += type_size * count;
-}
-
-extern size_t BinIOFormatByteCount(const char *format)
-{
- struct BinIOFormatCursor cursor;
- size_t n_bytes = 0;
-
- BinIOInitFormatCursor(&cursor, format);
-
- while (BinIONextChar(&n_bytes, &cursor, BinIOCountBytes)) {}
-
- return n_bytes;
-}
+++ /dev/null
-/*
-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 private_h
-#define private_h
-
-#include <stdarg.h>
-#include <stddef.h>
-
-#define BinIO_TYPE_IGNORE_BYTE 'x'
-#define BinIO_TYPE_BYTE 'b'
-#define BinIO_TYPE_INT16 's'
-#define BinIO_TYPE_INT32 'i'
-#define BinIO_TYPE_INT64 'l'
-#define BinIO_TYPE_FLOAT32 'f'
-#define BinIO_TYPE_FLOAT64 'd'
-
-#define BinIO_LITTLE_ENDIAN_BYTE_ORDER 'L'
-#define BinIO_BIG_ENDIAN_BYTE_ORDER 'B'
-#define BinIO_HOST_BYTE_ORDER 'H'
-#define BinIO_NETWORK_BYTE_ORDER 'N'
-
-#ifndef ALREADY_DID_BINIO_STDINT
-#define ALREADY_DID_BINIO_STDINT
-#if defined(BinIO_STDINT_HEADER)
-#include BinIO_STDINT_HEADER
-typedef float float32_t;
-typedef double float64_t;
-#else
-typedef unsigned char uint8_t;
-typedef unsigned short uint16_t;
-typedef unsigned long uint32_t;
-#ifdef WIN32
-typedef unsigned __int64 uint64_t;
-#else
-typedef unsigned long long uint64_t;
-#endif
-typedef float float32_t;
-typedef double float64_t;
-#endif
-#endif
-
-#ifndef BinIO_INLINE
-#if defined(__GNUC__)
-#define BinIO_INLINE static inline
-#else
-#define BinIO_INLINE static
-#endif
-#endif
-
-#ifndef BinIO_BYTE_ORDER
-#if defined(__ppc__) || defined(__POWERPC__)
-#define BinIO_BYTE_ORDER BinIO_BIG_ENDIAN_BYTE_ORDER
-#else
-#define BinIO_BYTE_ORDER BinIO_LITTLE_ENDIAN_BYTE_ORDER
-#endif
-#endif
-
-BinIO_INLINE void BinIOSwap1(const uint8_t *src, uint8_t *dst)
-{
- *dst = *src;
-}
-
-BinIO_INLINE void BinIOSwap2(const uint8_t *src, uint8_t *dst)
-{
- *(dst + 1) = *(src + 0);
- *(dst + 0) = *(src + 1);
-}
-
-BinIO_INLINE void BinIOSwap4(const uint8_t *src, uint8_t *dst)
-{
- *(dst + 3) = *(src + 0);
- *(dst + 2) = *(src + 1);
- *(dst + 1) = *(src + 2);
- *(dst + 0) = *(src + 3);
-}
-
-BinIO_INLINE void BinIOSwap8(const uint8_t *src, uint8_t *dst)
-{
- *(dst + 7) = *(src + 0);
- *(dst + 6) = *(src + 1);
- *(dst + 5) = *(src + 2);
- *(dst + 4) = *(src + 3);
- *(dst + 3) = *(src + 4);
- *(dst + 2) = *(src + 5);
- *(dst + 1) = *(src + 6);
- *(dst + 0) = *(src + 7);
-}
-
-BinIO_INLINE int BinIONormalizeByteOrder(int byte_order)
-{
- if (byte_order == BinIO_HOST_BYTE_ORDER) {
- byte_order = BinIO_BYTE_ORDER;
- } else if (byte_order == BinIO_NETWORK_BYTE_ORDER) {
- byte_order = BinIO_BIG_ENDIAN_BYTE_ORDER;
- }
-
- return byte_order;
-}
-
-extern void BinIOConvert1(int from_byte_order, int to_byte_order,
- const uint8_t *src, uint8_t *dst,
- unsigned int count);
-extern void BinIOConvert2(int from_byte_order, int to_byte_order,
- const uint8_t *src, uint8_t *dst,
- unsigned int count);
-extern void BinIOConvert4(int from_byte_order, int to_byte_order,
- const uint8_t *src, uint8_t *dst,
- unsigned int count);
-extern void BinIOConvert8(int from_byte_order, int to_byte_order,
- const uint8_t *src, uint8_t *dst,
- unsigned int count);
-
-struct BinIOFormatCursor {
- const char *cursor;
- int byte_order;
- int count;
-};
-
-typedef void (*BinIOProcessFunction)(void *context,
- int type,
- int byte_order,
- int count);
-
-extern void BinIOInitFormatCursor(struct BinIOFormatCursor *cursor,
- const char *format);
-
-extern int BinIONextChar(void *context,
- struct BinIOFormatCursor *cursor,
- BinIOProcessFunction func);
-
-extern void BinIOCountBytes(void *context, int type, int byte_order, int count);
-
-extern size_t BinIOFormatByteCount(const char *format);
-
-#endif
-
+++ /dev/null
-/*
-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/>.
-*/
-
-#include <stdlib.h>
-
-#include "binio.h"
-#include "private.h"
-
-struct BinIOUnpackContext {
- const uint8_t *data;
- va_list args;
-};
-
-static void BinIOUnpack(void *context, int type, int byte_order, int count)
-{
- struct BinIOUnpackContext *ctx = (struct BinIOUnpackContext*)context;
- if (count == -1) {
- count = 1;
- }
-
- switch (type) {
- case BinIO_TYPE_IGNORE_BYTE:
- ctx->data += 1 * count;
- break;
- case BinIO_TYPE_BYTE:
- BinIOConvert1(byte_order, BinIO_HOST_BYTE_ORDER, ctx->data, va_arg(ctx->args, uint8_t *), count);
- ctx->data += 1 * count;
- break;
- case BinIO_TYPE_INT16:
- BinIOConvert2(byte_order, BinIO_HOST_BYTE_ORDER, ctx->data, va_arg(ctx->args, uint8_t *), count);
- ctx->data += 2 * count;
- break;
- case BinIO_TYPE_INT32:
- BinIOConvert4(byte_order, BinIO_HOST_BYTE_ORDER, ctx->data, va_arg(ctx->args, uint8_t *), count);
- ctx->data += 4 * count;
- break;
- case BinIO_TYPE_INT64:
- BinIOConvert8(byte_order, BinIO_HOST_BYTE_ORDER, ctx->data, va_arg(ctx->args, uint8_t *), count);
- ctx->data += 8 * count;
- break;
- case BinIO_TYPE_FLOAT32:
- BinIOConvert4(byte_order, BinIO_HOST_BYTE_ORDER, ctx->data, va_arg(ctx->args, uint8_t *), count);
- ctx->data += 4 * count;
- break;
- case BinIO_TYPE_FLOAT64:
- BinIOConvert8(byte_order, BinIO_HOST_BYTE_ORDER, ctx->data, va_arg(ctx->args, uint8_t *), count);
- ctx->data += 8 * count;
- break;
- }
-}
-
-void unpackf(const char *format, ...)
-{
- va_list args;
- va_start(args, format);
- vfunpackf(stdin, format, args);
- va_end(args);
-}
-
-void sunpackf(const void *buffer, const char *format, ...)
-{
- va_list args;
- va_start(args, format);
- vsunpackf(buffer, format, args);
- va_end(args);
-}
-
-void funpackf(FILE *file, const char *format, ...)
-{
- va_list args;
- va_start(args, format);
- vfunpackf(file, format, args);
- va_end(args);
-}
-
-void vsunpackf(const void *buffer, const char *format, va_list args)
-{
- struct BinIOFormatCursor cursor;
- struct BinIOUnpackContext context;
-
- BinIOInitFormatCursor(&cursor, format);
-
- context.data = (const unsigned char*)buffer;
- va_copy(context.args, args);
-
- while (BinIONextChar(&context, &cursor, BinIOUnpack)) {}
-
- va_end(context.args);
-}
-
-void vfunpackf(FILE *file, const char *format, va_list args)
-{
- size_t n_bytes = BinIOFormatByteCount(format);
- void* buffer = malloc(n_bytes);
- fread(buffer, n_bytes, 1, file);
-
- vsunpackf(buffer, format, args);
-
- free(buffer);
-}