From: Côme Chilliet Date: Fri, 16 Dec 2016 04:10:11 +0000 (+0700) Subject: Moved things related to tutorial in new Tutorial class X-Git-Url: https://git.jsancho.org/?a=commitdiff_plain;ds=sidebyside;h=d177a567280631cd91a677debafada8cef7e0413;p=lugaru.git Moved things related to tutorial in new Tutorial class --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 5869354..4b9fb85 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,6 +82,7 @@ set(LUGARU_SRCS ${SRCDIR}/GameInitDispose.cpp ${SRCDIR}/GameTick.cpp ${SRCDIR}/Globals.cpp + ${SRCDIR}/Tutorial.cpp ) @@ -122,6 +123,7 @@ set(LUGARU_H ${SRCDIR}/Utils/Input.hpp ${SRCDIR}/Utils/private.h ${SRCDIR}/Game.hpp + ${SRCDIR}/Tutorial.hpp ) diff --git a/Source/Animation/Skeleton.cpp b/Source/Animation/Skeleton.cpp index 31f9886..a098b1a 100644 --- a/Source/Animation/Skeleton.cpp +++ b/Source/Animation/Skeleton.cpp @@ -24,6 +24,7 @@ along with Lugaru. If not, see . #include "Audio/openal_wrapper.hpp" #include "Game.hpp" #include "Utils/Folders.hpp" +#include "Tutorial.hpp" extern float multiplier; extern float gravity; @@ -32,7 +33,6 @@ extern int environment; extern float camerashake; extern bool freeze; extern int detail; -extern int tutoriallevel; extern int whichjointstartarray[26]; extern int whichjointendarray[26]; @@ -242,7 +242,7 @@ float Skeleton::DoConstraints(XYZ *coords, float *scale) if (joints[i].label == groin && !joints[i].locked && joints[i].delay <= 0) { joints[i].locked = 1; joints[i].delay = 1; - if (tutoriallevel != 1 || id == 0) { + if (!Tutorial::active || id == 0) { emit_sound_at(landsound1, joints[i].position * (*scale) + *coords, 128.); } breaking = true; @@ -251,7 +251,7 @@ float Skeleton::DoConstraints(XYZ *coords, float *scale) if (joints[i].label == head && !joints[i].locked && joints[i].delay <= 0) { joints[i].locked = 1; joints[i].delay = 1; - if (tutoriallevel != 1 || id == 0) { + if (!Tutorial::active || id == 0) { emit_sound_at(landsound2, joints[i].position * (*scale) + *coords, 128.); } } @@ -270,7 +270,7 @@ float Skeleton::DoConstraints(XYZ *coords, float *scale) else joints[i].velocity = 0; - if (tutoriallevel != 1 || id == 0) + if (!Tutorial::active || id == 0) if (findLengthfast(&bounceness) > 8000 && breaking) { // FIXME: this crashes because k is not initialized! // to reproduce, type 'wolfie' in console and play a while @@ -336,7 +336,7 @@ float Skeleton::DoConstraints(XYZ *coords, float *scale) if (joints[i].label == groin && !joints[i].locked && joints[i].delay <= 0) { joints[i].locked = 1; joints[i].delay = 1; - if (tutoriallevel != 1 || id == 0) { + if (!Tutorial::active || id == 0) { emit_sound_at(landsound1, joints[i].position * (*scale) + *coords, 128.); } breaking = true; @@ -345,7 +345,7 @@ float Skeleton::DoConstraints(XYZ *coords, float *scale) if (joints[i].label == head && !joints[i].locked && joints[i].delay <= 0) { joints[i].locked = 1; joints[i].delay = 1; - if (tutoriallevel != 1 || id == 0) { + if (!Tutorial::active || id == 0) { emit_sound_at(landsound2, joints[i].position * (*scale) + *coords, 128.); } } @@ -358,7 +358,7 @@ float Skeleton::DoConstraints(XYZ *coords, float *scale) bounceness = 0; joints[i].velocity = joints[i].oldvelocity; } - if (tutoriallevel != 1 || id == 0) + if (!Tutorial::active || id == 0) if (findLengthfast(&bounceness) > 4000 && breaking) { Object::objects[k]->model.MakeDecal(breakdecal, DoRotation(temp - Object::objects[k]->position, 0, -Object::objects[k]->yaw, 0), .4, .5, Random() % 360); Sprite::MakeSprite(cloudsprite, joints[i].position * (*scale) + *coords, joints[i].velocity * .06, 1, 1, 1, 4, .2); @@ -642,7 +642,7 @@ void Skeleton::Load(const std::string& filename, const std::string& lowfil drawmodel.Rotate(180, 0, 0); drawmodel.Scale(.04, .04, .04); drawmodel.FlipTexCoords(); - if ((tutoriallevel == 1) && (id != 0)) { + if ((Tutorial::active) && (id != 0)) { drawmodel.UniformTexCoords(); drawmodel.ScaleTexCoords(0.1); } @@ -657,9 +657,9 @@ void Skeleton::Load(const std::string& filename, const std::string& lowfil drawmodellow.Rotate(180, 0, 0); drawmodellow.Scale(.04, .04, .04); drawmodellow.FlipTexCoords(); - if (tutoriallevel == 1 && id != 0) + if (Tutorial::active && id != 0) drawmodellow.UniformTexCoords(); - if (tutoriallevel == 1 && id != 0) + if (Tutorial::active && id != 0) drawmodellow.ScaleTexCoords(0.1); drawmodellow.CalculateNormals(0); diff --git a/Source/Devtools/ConsoleCmds.cpp b/Source/Devtools/ConsoleCmds.cpp index baa1463..57e9f4a 100644 --- a/Source/Devtools/ConsoleCmds.cpp +++ b/Source/Devtools/ConsoleCmds.cpp @@ -24,6 +24,7 @@ along with Lugaru. If not, see . #include "Level/Dialog.hpp" #include "Level/Hotspot.hpp" #include "Utils/Folders.hpp" +#include "Tutorial.hpp" const char *cmd_names[cmd_count] = { #define DECLARE_COMMAND(cmd) #cmd, @@ -49,7 +50,6 @@ extern int environment; extern float fadestart; extern float slomospeed; extern float slomofreq; -extern int tutoriallevel; extern int hostile; extern int maptype; extern int slomo; @@ -504,7 +504,7 @@ void ch_sizemin(const char *args) void ch_tutorial(const char *args) { - tutoriallevel = atoi(args); + Tutorial::active = atoi(args); } void ch_hostile(const char *args) diff --git a/Source/Environment/Terrain.cpp b/Source/Environment/Terrain.cpp index 806bb4b..98828fd 100644 --- a/Source/Environment/Terrain.cpp +++ b/Source/Environment/Terrain.cpp @@ -23,6 +23,7 @@ along with Lugaru. If not, see . #include "Game.hpp" #include "Objects/Object.hpp" #include "Utils/Folders.hpp" +#include "Tutorial.hpp" extern XYZ viewer; extern float viewdistance; @@ -39,7 +40,6 @@ extern float blurness; extern float targetblurness; extern bool visibleloading; extern bool skyboxtexture; -extern int tutoriallevel; //Functions @@ -1366,7 +1366,7 @@ void Terrain::DoShadows() lightloc.x = 0; lightloc.z = 0; } - if (skyboxtexture && tutoriallevel) { + if (skyboxtexture && Tutorial::active) { lightloc.x *= .4; lightloc.z *= .4; } diff --git a/Source/Game.hpp b/Source/Game.hpp index 48f51f9..efa119e 100644 --- a/Source/Game.hpp +++ b/Source/Game.hpp @@ -144,7 +144,7 @@ int DrawGLScene(StereoSide side); void playdialoguescenesound(); int findClosestPlayer(); void Loadlevel(int which); -void Loadlevel(const std::string& name); +void Loadlevel(const std::string& name, bool tutorial = false); void Tick(); void TickOnce(); void TickOnceAfter(); diff --git a/Source/GameDraw.cpp b/Source/GameDraw.cpp index fa67948..7ab8565 100644 --- a/Source/GameDraw.cpp +++ b/Source/GameDraw.cpp @@ -26,6 +26,7 @@ along with Lugaru. If not, see . #include "Level/Hotspot.hpp" #include "Menu/Menu.hpp" #include "Utils/Input.hpp" +#include "Tutorial.hpp" extern XYZ viewer; extern int environment; @@ -69,11 +70,7 @@ extern int difficulty; extern bool decals; extern float texdetail; extern bool musictoggle; -extern int tutoriallevel; extern float smoketex; -extern float tutorialstagetime; -extern float tutorialmaxtime; -extern int tutorialstage; extern bool againbonus; extern float damagedealt; extern bool invertmouse; @@ -311,7 +308,7 @@ int Game::DrawGLScene(StereoSide side) point = DoRotation(Person::players[k]->skeleton.joints[i].position, 0, Person::players[k]->yaw, 0) * Person::players[k]->scale + Person::players[k]->coords; size = .4f; opacity = .4 - Person::players[k]->skeleton.joints[i].position.y * Person::players[k]->scale / 5 - (Person::players[k]->coords.y - terrain.getHeight(Person::players[k]->coords.x, Person::players[k]->coords.z)) / 10; - if (k != 0 && tutoriallevel == 1) { + if (k != 0 && Tutorial::active) { opacity = .2 + .2 * sin(smoketex * 6 + i) - Person::players[k]->skeleton.joints[i].position.y * Person::players[k]->scale / 5 - (Person::players[k]->coords.y - terrain.getHeight(Person::players[k]->coords.x, Person::players[k]->coords.z)) / 10; } terrain.MakeDecal(shadowdecal, point, size, opacity, rotation); @@ -321,7 +318,7 @@ int Game::DrawGLScene(StereoSide side) point = DoRotation(DoRotation(Person::players[k]->skeleton.joints[i].position, 0, Person::players[k]->yaw, 0) * Person::players[k]->scale + Person::players[k]->coords - Object::objects[j]->position, 0, -Object::objects[j]->yaw, 0); size = .4f; opacity = .4f; - if (k != 0 && tutoriallevel == 1) { + if (k != 0 && Tutorial::active) { opacity = .2 + .2 * sin(smoketex * 6 + i); } Object::objects[j]->model.MakeDecal(shadowdecal, &point, &size, &opacity, &rotation); @@ -339,7 +336,7 @@ int Game::DrawGLScene(StereoSide side) point = DoRotation(Person::players[k]->skeleton.joints[i].position, 0, Person::players[k]->yaw, 0) * Person::players[k]->scale + Person::players[k]->coords; size = .4f; opacity = .4 - Person::players[k]->skeleton.joints[i].position.y * Person::players[k]->scale / 5 - (Person::players[k]->coords.y - terrain.getHeight(Person::players[k]->coords.x, Person::players[k]->coords.z)) / 5; - if (k != 0 && tutoriallevel == 1) { + if (k != 0 && Tutorial::active) { opacity = .2 + .2 * sin(smoketex * 6 + i) - Person::players[k]->skeleton.joints[i].position.y * Person::players[k]->scale / 5 - (Person::players[k]->coords.y - terrain.getHeight(Person::players[k]->coords.x, Person::players[k]->coords.z)) / 10; } terrain.MakeDecal(shadowdecal, point, size, opacity * .7, rotation); @@ -352,7 +349,7 @@ int Game::DrawGLScene(StereoSide side) point = DoRotation(DoRotation(Person::players[k]->skeleton.joints[i].position, 0, Person::players[k]->yaw, 0) * Person::players[k]->scale + Person::players[k]->coords - Object::objects[j]->position, 0, -Object::objects[j]->yaw, 0); size = .4f; opacity = .4f; - if (k != 0 && tutoriallevel == 1) { + if (k != 0 && Tutorial::active) { opacity = .2 + .2 * sin(smoketex * 6 + i); } Object::objects[j]->model.MakeDecal(shadowdecal, &point, &size, &opacity, &rotation); @@ -407,7 +404,7 @@ int Game::DrawGLScene(StereoSide side) glCullFace(GL_FRONT); glDepthMask(1); for (unsigned k = 0; k < Person::players.size(); k++) { - if (k == 0 || tutoriallevel != 1) { + if (k == 0 || !Tutorial::active) { glEnable(GL_BLEND); glEnable(GL_LIGHTING); terrainlight = terrain.getLighting(Person::players[k]->coords.x, Person::players[k]->coords.z); @@ -472,7 +469,7 @@ int Game::DrawGLScene(StereoSide side) glCullFace(GL_FRONT); glDepthMask(1); for (unsigned k = 0; k < Person::players.size(); k++) { - if (!(k == 0 || tutoriallevel != 1)) { + if (!(k == 0 || !Tutorial::active)) { glEnable(GL_BLEND); glEnable(GL_LIGHTING); terrainlight = terrain.getLighting(Person::players[k]->coords.x, Person::players[k]->coords.z); @@ -563,7 +560,7 @@ int Game::DrawGLScene(StereoSide side) glEnable(GL_TEXTURE_2D); glColor4f(.5, .5, .5, 1); if (!console) { - if (!tutoriallevel) + if (!Tutorial::active) if (bonus > 0 && bonustime < 1 && !winfreeze && !Dialog::inDialog()) { const char *bonus_name; if (bonus < bonus_count) @@ -579,311 +576,12 @@ int Game::DrawGLScene(StereoSide side) glColor4f(.5, .5, .5, 1); } - if (tutoriallevel == 1) { - tutorialopac = tutorialmaxtime - tutorialstagetime; - if (tutorialopac > 1) - tutorialopac = 1; - if (tutorialopac < 0) - tutorialopac = 0; - - string = " "; - string2 = " "; - string3 = " "; - if (tutorialstage == 0) { - string = " "; - string2 = " "; - string3 = " "; - } - if (tutorialstage == 1) { - string = "Welcome to the Lugaru training level!"; - string2 = " "; - string3 = " "; - } - if (tutorialstage == 2) { - string = "BASIC MOVEMENT:"; - string2 = " "; - string3 = " "; - } - if (tutorialstage == 3) { - string = "You can move the mouse to rotate the camera."; - string2 = " "; - string3 = " "; - } - if (tutorialstage == 4) { - string = std::string("Try using the ") + - Input::keyToChar(forwardkey) + ", " + - Input::keyToChar(leftkey) + ", " + - Input::keyToChar(backkey) + " and " + - Input::keyToChar(rightkey) + " keys to move around."; - string2 = "All movement is relative to the camera."; - string3 = " "; - } - if (tutorialstage == 5) { - string = std::string("Please press ") + Input::keyToChar(jumpkey) + " to jump."; - string2 = "You can hold it longer to jump higher."; - string3 = " "; - } - if (tutorialstage == 6) { - string = std::string("You can press ") + Input::keyToChar(crouchkey) + " to crouch."; - string2 = "You can jump higher from a crouching position."; - string3 = " "; - } - if (tutorialstage == 7) { - string = std::string("While running, you can press ") + Input::keyToChar(crouchkey) + " to roll."; - string2 = " "; - string3 = " "; - } - if (tutorialstage == 8) { - string = "While crouching, you can sneak around silently"; - string2 = "using the movement keys."; - string3 = " "; - } - if (tutorialstage == 9) { - string = "Release the crouch key while sneaking and hold the movement keys"; - string2 = "to run animal-style."; - string3 = " "; - } - if (tutorialstage == 10) { - string = "ADVANCED MOVEMENT:"; - string2 = " "; - string3 = " "; - } - if (tutorialstage == 11) { - string = std::string("When you jump at a wall, you can hold ") + Input::keyToChar(jumpkey) + " again"; - string2 = "during impact to perform a walljump."; - string3 = "Be sure to use the movement keys to press against the wall"; - } - if (tutorialstage == 12) { - string = "While in the air, you can press crouch to flip."; - string2 = "Walljumps and flips confuse enemies and give you more control."; - string3 = " "; - } - if (tutorialstage == 13) { - string = "BASIC COMBAT:"; - string2 = " "; - string3 = " "; - } - if (tutorialstage == 14) { - string = "There is now an imaginary enemy"; - string2 = "in the middle of the training area."; - string3 = " "; - } - if (tutorialstage == 15) { - if (attackkey == MOUSEBUTTON1) { - string = "Click to attack when you are near an enemy."; - } else { - string = std::string("Press ") + Input::keyToChar(attackkey) + " to attack when you are near an enemy."; - } - string2 = "You can punch by standing still near an enemy and attacking."; - string3 = " "; - } - if (tutorialstage == 16) { - string = "If you are close, you will perform a weak punch."; - string2 = "The weak punch is excellent for starting attack combinations."; - string3 = " "; - } - if (tutorialstage == 17) { - string = "Attacking while running results in a spin kick."; - string2 = "This is one of your most powerful ground attacks."; - string3 = " "; - } - if (tutorialstage == 18) { - string = "Sweep the enemy's legs out by attacking while crouched."; - string2 = "This is a very fast attack, and easy to follow up."; - string3 = " "; - } - if (tutorialstage == 19) { - string = "When an enemy is on the ground, you can deal some extra"; - string2 = "damage by running up and drop-kicking him."; - string3 = "(Try knocking them down with a sweep first)"; - } - if (tutorialstage == 20) { - string = "Your most powerful individual attack is the rabbit kick."; - if (attackkey == MOUSEBUTTON1) { - string2 = "Run at the enemy while holding the mouse button, and press"; - } else { - string2 = std::string("Run at the enemy while holding ") + Input::keyToChar(attackkey) + ", and press"; - } - string3 = std::string("the jump key (") + Input::keyToChar(jumpkey) + ") to attack."; - } - if (tutorialstage == 21) { - string = "This attack is devastating if timed correctly."; - string2 = "Even if timed incorrectly, it will knock the enemy over."; - if (againbonus) - string3 = "Try rabbit-kicking the imaginary enemy again."; - else - string3 = "Try rabbit-kicking the imaginary enemy."; - } - if (tutorialstage == 22) { - string = "If you sneak behind an enemy unnoticed, you can kill"; - string2 = "him instantly. Move close behind this enemy"; - string3 = "and attack."; - } - if (tutorialstage == 23) { - string = "Another important attack is the wall kick. When an enemy"; - string2 = "is near a wall, perform a walljump nearby and hold"; - string3 = "the attack key during impact with the wall."; - } - if (tutorialstage == 24) { - string = "You can tackle enemies by running at them animal-style"; - if (attackkey == MOUSEBUTTON1) { - string2 = std::string("and pressing jump (") + Input::keyToChar(jumpkey) + ") or attack(mouse button)."; - } else { - string2 = std::string("and pressing jump (") + Input::keyToChar(jumpkey) + ") or attack(" + Input::keyToChar(attackkey) + ")."; - } - string3 = "This is especially useful when they are running away."; - } - if (tutorialstage == 25) { - string = "Dodge by pressing back and attack. Dodging is essential"; - string2 = "against enemies with swords or other long weapons."; - string3 = " "; - } - if (tutorialstage == 26) { - string = "REVERSALS AND COUNTER-REVERSALS"; - string2 = " "; - string3 = " "; - } - if (tutorialstage == 27) { - string = "The enemy can now reverse your attacks."; - string2 = " "; - string3 = " "; - } - if (tutorialstage == 28) { - string = "If you attack, you will notice that the enemy now sometimes"; - string2 = "catches your attack and uses it against you. Hold"; - string3 = std::string("crouch (") + Input::keyToChar(crouchkey) + ") after attacking to escape from reversals."; - } - if (tutorialstage == 29) { - string = "Try escaping from two more reversals in a row."; - string2 = " "; - string3 = " "; - } - if (tutorialstage == 30) { - string = "Good!"; - string2 = " "; - string3 = " "; - } - if (tutorialstage == 31) { - string = std::string("To reverse an attack, you must tap crouch (") + Input::keyToChar(crouchkey) + ") during the"; - string2 = "enemy's attack. You must also be close to the enemy;"; - string3 = "this is especially important against armed opponents."; - } - if (tutorialstage == 32) { - string = "The enemy can attack in " + to_string(int(tutorialmaxtime - tutorialstagetime)) + " seconds."; - string2 = "This imaginary opponents attacks will be highlighted"; - string3 = "to make this easier."; - } - if (tutorialstage == 33) { - string = "Reverse three enemy attacks!"; - string2 = " "; - string3 = " "; - } - if (tutorialstage == 34) { - string = "Reverse two more enemy attacks!"; - string2 = " "; - string3 = " "; - } - if (tutorialstage == 35) { - string = "Reverse one more enemy attack!"; - string2 = " "; - string3 = " "; - } - if (tutorialstage == 36) { - string = "Excellent!"; - string2 = " "; - string3 = " "; - } - if (tutorialstage == 37) { - string = "Now spar with the enemy for " + to_string(int(tutorialmaxtime - tutorialstagetime)) + " more seconds."; - string2 = "Damage dealt: " + to_string(int(damagedealt)); - string3 = "Damage taken: " + to_string(int(damagetaken)); - } - if (tutorialstage == 38) { - string = "WEAPONS:"; - string2 = " "; - string3 = " "; - } - if (tutorialstage == 39) { - string = "There is now an imaginary knife"; - string2 = "in the center of the training area."; - string3 = " "; - } - if (tutorialstage == 40) { - string = "Stand, roll or handspring over the knife"; - string2 = std::string("while pressing ") + Input::keyToChar(throwkey) + " to pick it up."; - string3 = "You can crouch and press the same key to drop it again."; - } - if (tutorialstage == 41) { - string = std::string("You can equip and unequip weapons using the ") + Input::keyToChar(drawkey) + " key."; - string2 = "Sometimes it is best to keep them unequipped to"; - string3 = "prevent enemies from taking them. "; - } - if (tutorialstage == 42) { - string = "The knife is the smallest weapon and the least encumbering."; - string2 = "You can equip or unequip it while standing, crouching,"; - string3 = "running or flipping."; - } - if (tutorialstage == 43) { - string = "You perform weapon attacks the same way as unarmed attacks,"; - string2 = "but sharp weapons cause permanent damage, instead of the"; - string3 = "temporary trauma from blunt weapons, fists and feet."; - } - if (tutorialstage == 44) { - string = "The enemy now has your knife!"; - string2 = "Please reverse two of his knife attacks."; - string3 = " "; - } - if (tutorialstage == 45) { - string = "Please reverse one more of his knife attacks."; - string2 = " "; - string3 = " "; - } - if (tutorialstage == 46) { - string = "Now he has a sword!"; - string2 = "The sword has longer reach than your arms, so you"; - string3 = "must move close to reverse the sword slash."; - } - if (tutorialstage == 47) { - string = "Long weapons like the sword and staff are also useful for defense;"; - string2 = "you can parry enemy weapon attacks by pressing the attack key"; - string3 = "at the right time. Please try parrying the enemy's attacks!"; - } - if (tutorialstage == 48) { - string = "The staff is like the sword, but has two main attacks."; - string2 = "The standing smash is fast and effective, and the running"; - string3 = "spin smash is slower and more powerful."; - } - if (tutorialstage == 49) { - string = std::string("When facing an enemy, you can throw the knife with ") + Input::keyToChar(throwkey) + "."; - string2 = "It is possible to throw the knife while flipping,"; - string3 = "but it is very inaccurate."; - } - if (tutorialstage == 50) { - string = "You now know everything you can learn from training."; - string2 = "Everything else you must learn from experience!"; - string3 = " "; - } - if (tutorialstage == 51) { - string = "Walk out of the training area to return to the main menu."; - string2 = " "; - string3 = " "; - } - - text->glPrintOutlined(1, 1, 1, tutorialopac, screenwidth / 2 - 7.6 * string.size()*screenwidth / 1024, screenheight / 16 + screenheight * 4 / 5, string, 1, 1.5 * screenwidth / 1024, screenwidth, screenheight); - text->glPrintOutlined(1, 1, 1, tutorialopac, screenwidth / 2 - 7.6 * string2.size()*screenwidth / 1024, screenheight / 16 + screenheight * 4 / 5 - 20 * screenwidth / 1024, string2, 1, 1.5 * screenwidth / 1024, screenwidth, screenheight); - text->glPrintOutlined(1, 1, 1, tutorialopac, screenwidth / 2 - 7.6 * string3.size()*screenwidth / 1024, screenheight / 16 + screenheight * 4 / 5 - 40 * screenwidth / 1024, string3, 1, 1.5 * screenwidth / 1024, screenwidth, screenheight); - - string = "Press 'tab' to skip to the next item."; - string2 = "Press escape at any time to"; - string3 = "pause or exit the tutorial."; - - text->glPrintOutlined(0.5, 0.5, 0.5, 1, screenwidth / 2 - 7.6 * string.size()*screenwidth / 1024 * .8, 0 + screenheight * 1 / 10, string, 1, 1.5 * screenwidth / 1024 * .8, screenwidth, screenheight); - text->glPrintOutlined(0.5, 0.5, 0.5, 1, screenwidth / 2 - 7.6 * string2.size()*screenwidth / 1024 * .8, 0 + screenheight * 1 / 10 - 20 * .8 * screenwidth / 1024, string2, 1, 1.5 * screenwidth / 1024 * .8, screenwidth, screenheight); - text->glPrintOutlined(0.5, 0.5, 0.5, 1, screenwidth / 2 - 7.6 * string3.size()*screenwidth / 1024 * .8, 0 + screenheight * 1 / 10 - 40 * .8 * screenwidth / 1024, string3, 1, 1.5 * screenwidth / 1024 * .8, screenwidth, screenheight); + if (Tutorial::active) { + Tutorial::DrawText(); } //Hot spots - if (Hotspot::hotspots.size() && (bonustime >= 1 || bonus <= 0 || bonustime < 0) && !tutoriallevel) { + if (Hotspot::hotspots.size() && (bonustime >= 1 || bonus <= 0 || bonustime < 0) && !Tutorial::active) { float closestdist = -1; float distance = 0; int closest = Hotspot::current; @@ -900,9 +598,9 @@ int Game::DrawGLScene(StereoSide side) Hotspot::current = closest; if (Hotspot::hotspots[closest].type <= 10) { if (distsq(&Person::players[0]->coords, &Hotspot::hotspots[closest].position) < Hotspot::hotspots[closest].size) - tutorialstagetime = 0; - tutorialmaxtime = 1; - tutorialopac = tutorialmaxtime - tutorialstagetime; + Tutorial::stagetime = 0; + Tutorial::maxtime = 1; + tutorialopac = Tutorial::maxtime - Tutorial::stagetime; if (tutorialopac > 1) tutorialopac = 1; if (tutorialopac < 0) @@ -1038,7 +736,7 @@ int Game::DrawGLScene(StereoSide side) } } - if (!tutoriallevel && !winfreeze && !Dialog::inDialog() && !mainmenu) { + if (!Tutorial::active && !winfreeze && !Dialog::inDialog() && !mainmenu) { if (campaign) { if (scoreadded) { string = "Score: " + to_string(int(Account::active().getCampaignScore())); diff --git a/Source/GameTick.cpp b/Source/GameTick.cpp index 0690acd..c8b61ca 100644 --- a/Source/GameTick.cpp +++ b/Source/GameTick.cpp @@ -34,6 +34,7 @@ along with Lugaru. If not, see . #include "User/Settings.hpp" #include "Utils/Folders.hpp" #include "Utils/Input.hpp" +#include "Tutorial.hpp" #if PLATFORM_UNIX #include @@ -112,12 +113,7 @@ extern float skyboxlightb; extern float fadestart; extern float slomospeed; extern float slomofreq; -extern int tutoriallevel; extern float smoketex; -extern float tutorialstagetime; -extern int tutorialstage; -extern float tutorialmaxtime; -extern float tutorialsuccess; extern bool againbonus; extern bool reversaltrain; extern bool canattack; @@ -550,8 +546,7 @@ void Game::Loadlevel(int which) whichlevel = which; if (which == -1) { - tutoriallevel = -1; - Loadlevel("tutorial"); + Loadlevel("tutorial", true); } else if (which >= 0 && which <= 15) { char buf[32]; snprintf(buf, 32, "map%d", which + 1); // challenges @@ -560,7 +555,7 @@ void Game::Loadlevel(int which) Loadlevel("mapsave"); } -void Game::Loadlevel(const std::string& name) +void Game::Loadlevel(const std::string& name, bool tutorial) { int indemo; // FIXME this should be removed int templength; @@ -580,16 +575,14 @@ void Game::Loadlevel(const std::string& name) numenvsounds = 0; - if (tutoriallevel != -1) - tutoriallevel = 0; - else - tutoriallevel = 1; + Tutorial::active = tutorial; - if (tutoriallevel == 1) - tutorialstage = 0; - if (tutorialstage == 0) { - tutorialstagetime = 0; - tutorialmaxtime = 1; + if (Tutorial::active) { + Tutorial::stage = 0; + } + if (Tutorial::stage == 0) { + Tutorial::stagetime = 0; + Tutorial::maxtime = 1; } pause_sound(whooshsound); pause_sound(stream_firesound); @@ -1003,535 +996,6 @@ void Game::Loadlevel(const std::string& name) visibleloading = 0; } -void doTutorial() -{ - if (tutorialstagetime > tutorialmaxtime) { - tutorialstage++; - tutorialsuccess = 0; - if (tutorialstage <= 1) { - canattack = 0; - cananger = 0; - reversaltrain = 0; - } - switch (tutorialstage) { - case 1: - tutorialmaxtime = 5; - break; - case 2: - tutorialmaxtime = 2; - break; - case 3: - tutorialmaxtime = 600; - break; - case 4: - tutorialmaxtime = 1000; - break; - case 5: - tutorialmaxtime = 600; - break; - case 6: - tutorialmaxtime = 600; - break; - case 7: - tutorialmaxtime = 600; - break; - case 8: - tutorialmaxtime = 600; - break; - case 9: - tutorialmaxtime = 600; - break; - case 10: - tutorialmaxtime = 2; - break; - case 11: - tutorialmaxtime = 1000; - break; - case 12: - tutorialmaxtime = 1000; - break; - case 13: - tutorialmaxtime = 2; - break; - case 14: { - tutorialmaxtime = 3; - - XYZ temp, temp2; - - temp.x = 1011; - temp.y = 84; - temp.z = 491; - temp2.x = 1025; - temp2.y = 75; - temp2.z = 447; - - Person::players[1]->coords = (temp + temp2) / 2; - - emit_sound_at(fireendsound, Person::players[1]->coords); - - for (unsigned i = 0; i < Person::players[1]->skeleton.joints.size(); i++) { - if (Random() % 2 == 0) { - if (!Person::players[1]->skeleton.free) - temp2 = (Person::players[1]->coords - Person::players[1]->oldcoords) / multiplier / 2; //velocity/2; - if (Person::players[1]->skeleton.free) - temp2 = Person::players[1]->skeleton.joints[i].velocity * Person::players[1]->scale / 2; - if (!Person::players[1]->skeleton.free) - temp = DoRotation(DoRotation(DoRotation(Person::players[1]->skeleton.joints[i].position, 0, 0, Person::players[1]->tilt), Person::players[1]->tilt2, 0, 0), 0, Person::players[1]->yaw, 0) * Person::players[1]->scale + Person::players[1]->coords; - if (Person::players[1]->skeleton.free) - temp = Person::players[1]->skeleton.joints[i].position * Person::players[1]->scale + Person::players[1]->coords; - Sprite::MakeSprite(breathsprite, temp, temp2, 1, 1, 1, .6 + (float)abs(Random() % 100) / 200 - .25, 1); - } - } - } - break; - case 15: - tutorialmaxtime = 500; - break; - case 16: - tutorialmaxtime = 500; - break; - case 17: - tutorialmaxtime = 500; - break; - case 18: - tutorialmaxtime = 500; - break; - case 19: - tutorialstage = 20; - break; - case 20: - tutorialmaxtime = 500; - break; - case 21: - tutorialmaxtime = 500; - if (bonus == cannon) { - bonus = Slicebonus; - againbonus = 1; - } else - againbonus = 0; - break; - case 22: - tutorialmaxtime = 500; - break; - case 23: - tutorialmaxtime = 500; - break; - case 24: - tutorialmaxtime = 500; - break; - case 25: - tutorialmaxtime = 500; - break; - case 26: - tutorialmaxtime = 2; - break; - case 27: - tutorialmaxtime = 4; - reversaltrain = 1; - cananger = 1; - Person::players[1]->aitype = attacktypecutoff; - break; - case 28: - tutorialmaxtime = 400; - break; - case 29: - tutorialmaxtime = 400; - Person::players[0]->escapednum = 0; - break; - case 30: - tutorialmaxtime = 4; - reversaltrain = 0; - cananger = 0; - Person::players[1]->aitype = passivetype; - break; - case 31: - tutorialmaxtime = 13; - break; - case 32: - tutorialmaxtime = 8; - break; - case 33: - tutorialmaxtime = 400; - cananger = 1; - canattack = 1; - Person::players[1]->aitype = attacktypecutoff; - break; - case 34: - tutorialmaxtime = 400; - break; - case 35: - tutorialmaxtime = 400; - break; - case 36: - tutorialmaxtime = 2; - reversaltrain = 0; - cananger = 0; - Person::players[1]->aitype = passivetype; - break; - case 37: - damagedealt = 0; - damagetaken = 0; - tutorialmaxtime = 50; - cananger = 1; - canattack = 1; - Person::players[1]->aitype = attacktypecutoff; - break; - case 38: - tutorialmaxtime = 4; - canattack = 0; - cananger = 0; - Person::players[1]->aitype = passivetype; - break; - case 39: { - XYZ temp, temp2; - - temp.x = 1011; - temp.y = 84; - temp.z = 491; - temp2.x = 1025; - temp2.y = 75; - temp2.z = 447; - - Weapon w(knife, -1); - w.position = (temp + temp2) / 2; - w.tippoint = (temp + temp2) / 2; - - w.velocity = 0.1; - w.tipvelocity = 0.1; - w.missed = 1; - w.hitsomething = 0; - w.freetime = 0; - w.firstfree = 1; - w.physics = 1; - - weapons.push_back(w); - } - break; - case 40: - tutorialmaxtime = 300; - break; - case 41: - tutorialmaxtime = 300; - break; - case 42: - tutorialmaxtime = 8; - break; - case 43: - tutorialmaxtime = 300; - break; - case 44: - weapons[0].owner = 1; - Person::players[0]->weaponactive = -1; - Person::players[0]->num_weapons = 0; - Person::players[1]->weaponactive = 0; - Person::players[1]->num_weapons = 1; - Person::players[1]->weaponids[0] = 0; - - cananger = 1; - canattack = 1; - Person::players[1]->aitype = attacktypecutoff; - - tutorialmaxtime = 300; - break; - case 45: - weapons[0].owner = 1; - Person::players[0]->weaponactive = -1; - Person::players[0]->num_weapons = 0; - Person::players[1]->weaponactive = 0; - Person::players[1]->num_weapons = 1; - Person::players[1]->weaponids[0] = 0; - - tutorialmaxtime = 300; - break; - case 46: - weapons[0].owner = 1; - Person::players[0]->weaponactive = -1; - Person::players[0]->num_weapons = 0; - Person::players[1]->weaponactive = 0; - Person::players[1]->num_weapons = 1; - Person::players[1]->weaponids[0] = 0; - - weapons[0].setType(sword); - - tutorialmaxtime = 300; - break; - case 47: { - tutorialmaxtime = 10; - - XYZ temp, temp2; - - temp.x = 1011; - temp.y = 84; - temp.z = 491; - temp2.x = 1025; - temp2.y = 75; - temp2.z = 447; - - Weapon w(sword, -1); - w.position = (temp + temp2) / 2; - w.tippoint = (temp + temp2) / 2; - - w.velocity = 0.1; - w.tipvelocity = 0.1; - w.missed = 1; - w.hitsomething = 0; - w.freetime = 0; - w.firstfree = 1; - w.physics = 1; - - weapons.push_back(w); - - weapons[0].owner = 1; - weapons[1].owner = 0; - Person::players[0]->weaponactive = 0; - Person::players[0]->num_weapons = 1; - Person::players[0]->weaponids[0] = 1; - Person::players[1]->weaponactive = 0; - Person::players[1]->num_weapons = 1; - Person::players[1]->weaponids[0] = 0; - - } - break; - case 48: - canattack = 0; - cananger = 0; - Person::players[1]->aitype = passivetype; - - tutorialmaxtime = 15; - - weapons[0].owner = 1; - weapons[1].owner = 0; - Person::players[0]->weaponactive = 0; - Person::players[0]->num_weapons = 1; - Person::players[0]->weaponids[0] = 1; - Person::players[1]->weaponactive = 0; - Person::players[1]->num_weapons = 1; - Person::players[1]->weaponids[0] = 0; - - if (Person::players[0]->weaponactive != -1) - weapons[Person::players[0]->weaponids[Person::players[0]->weaponactive]].setType(staff); - else - weapons[0].setType(staff); - break; - case 49: - canattack = 0; - cananger = 0; - Person::players[1]->aitype = passivetype; - - tutorialmaxtime = 200; - - weapons[1].position = 1000; - weapons[1].tippoint = 1000; - - weapons[0].setType(knife); - - weapons[0].owner = 0; - Person::players[1]->weaponactive = -1; - Person::players[1]->num_weapons = 0; - Person::players[0]->weaponactive = 0; - Person::players[0]->num_weapons = 1; - Person::players[0]->weaponids[0] = 0; - - break; - case 50: { - tutorialmaxtime = 8; - - XYZ temp, temp2; - emit_sound_at(fireendsound, Person::players[1]->coords); - - for (unsigned i = 0; i < Person::players[1]->skeleton.joints.size(); i++) { - if (Random() % 2 == 0) { - if (!Person::players[1]->skeleton.free) - temp2 = (Person::players[1]->coords - Person::players[1]->oldcoords) / multiplier / 2; //velocity/2; - if (Person::players[1]->skeleton.free) - temp2 = Person::players[1]->skeleton.joints[i].velocity * Person::players[1]->scale / 2; - if (!Person::players[1]->skeleton.free) - temp = DoRotation(DoRotation(DoRotation(Person::players[1]->skeleton.joints[i].position, 0, 0, Person::players[1]->tilt), Person::players[1]->tilt2, 0, 0), 0, Person::players[1]->yaw, 0) * Person::players[1]->scale + Person::players[1]->coords; - if (Person::players[1]->skeleton.free) - temp = Person::players[1]->skeleton.joints[i].position * Person::players[1]->scale + Person::players[1]->coords; - Sprite::MakeSprite(breathsprite, temp, temp2, 1, 1, 1, .6 + (float)abs(Random() % 100) / 200 - .25, 1); - } - } - - Person::players[1]->num_weapons = 0; - Person::players[1]->weaponstuck = -1; - Person::players[1]->weaponactive = -1; - - weapons.clear(); - } - break; - case 51: - tutorialmaxtime = 80000; - break; - default: - break; - } - if (tutorialstage <= 51) - tutorialstagetime = 0; - } - - //Tutorial success - if (tutorialstagetime < tutorialmaxtime - 3) { - switch (tutorialstage) { - case 3: - if (deltah || deltav) - tutorialsuccess += multiplier; - break; - case 4: - if (Person::players[0]->forwardkeydown || Person::players[0]->backkeydown || Person::players[0]->leftkeydown || Person::players[0]->rightkeydown) - tutorialsuccess += multiplier; - break; - case 5: - if (Person::players[0]->jumpkeydown) - tutorialsuccess = 1; - break; - case 6: - if (Person::players[0]->isCrouch()) - tutorialsuccess = 1; - break; - case 7: - if (Person::players[0]->animTarget == rollanim) - tutorialsuccess = 1; - break; - case 8: - if (Person::players[0]->animTarget == sneakanim) - tutorialsuccess += multiplier; - break; - case 9: - if (Person::players[0]->animTarget == rabbitrunninganim || Person::players[0]->animTarget == wolfrunninganim) - tutorialsuccess += multiplier; - break; - case 11: - if (Person::players[0]->isWallJump()) - tutorialsuccess = 1; - break; - case 12: - if (Person::players[0]->animTarget == flipanim) - tutorialsuccess = 1; - break; - case 15: - if (Person::players[0]->animTarget == upunchanim || Person::players[0]->animTarget == winduppunchanim) - tutorialsuccess = 1; - break; - case 16: - if (Person::players[0]->animTarget == winduppunchanim) - tutorialsuccess = 1; - break; - case 17: - if (Person::players[0]->animTarget == spinkickanim) - tutorialsuccess = 1; - break; - case 18: - if (Person::players[0]->animTarget == sweepanim) - tutorialsuccess = 1; - break; - case 19: - if (Person::players[0]->animTarget == dropkickanim) - tutorialsuccess = 1; - break; - case 20: - if (Person::players[0]->animTarget == rabbitkickanim) - tutorialsuccess = 1; - break; - case 21: - if (bonus == cannon) - tutorialsuccess = 1; - break; - case 22: - if (bonus == spinecrusher) - tutorialsuccess = 1; - break; - case 23: - if (Person::players[0]->animTarget == walljumprightkickanim || Person::players[0]->animTarget == walljumpleftkickanim) - tutorialsuccess = 1; - break; - case 24: - if (Person::players[0]->animTarget == rabbittacklinganim) - tutorialsuccess = 1; - break; - case 25: - if (Person::players[0]->animTarget == backhandspringanim) - tutorialsuccess = 1; - break; - case 28: - if (Animation::animations[Person::players[0]->animTarget].attack == reversed && Person::players[0]->feint) - tutorialsuccess = 1; - break; - case 29: - if (Person::players[0]->escapednum == 2) { - tutorialsuccess = 1; - reversaltrain = 0; - cananger = 0; - Person::players[1]->aitype = passivetype; - } - break; - case 33: - if (Animation::animations[Person::players[0]->animTarget].attack == reversal) - tutorialsuccess = 1; - break; - case 34: - if (Animation::animations[Person::players[0]->animTarget].attack == reversal) - tutorialsuccess = 1; - break; - case 35: - if (Animation::animations[Person::players[0]->animTarget].attack == reversal) { - tutorialsuccess = 1; - reversaltrain = 0; - cananger = 0; - Person::players[1]->aitype = passivetype; - } - break; - case 40: - if (Person::players[0]->num_weapons > 0) - tutorialsuccess = 1; - break; - case 41: - if (Person::players[0]->weaponactive == -1 && Person::players[0]->num_weapons > 0) - tutorialsuccess = 1; - break; - case 43: - if (Person::players[0]->animTarget == knifeslashstartanim) - tutorialsuccess = 1; - break; - case 44: - if (Animation::animations[Person::players[0]->animTarget].attack == reversal) - tutorialsuccess = 1; - break; - case 45: - if (Animation::animations[Person::players[0]->animTarget].attack == reversal) - tutorialsuccess = 1; - break; - case 46: - if (Animation::animations[Person::players[0]->animTarget].attack == reversal) - tutorialsuccess = 1; - break; - case 49: - if (Person::players[1]->weaponstuck != -1) - tutorialsuccess = 1; - break; - default: - break; - } - if (tutorialsuccess >= 1) - tutorialstagetime = tutorialmaxtime - 3; - - - if (tutorialstagetime == tutorialmaxtime - 3) { - emit_sound_np(consolesuccesssound); - } - - if (tutorialsuccess >= 1) { - if (tutorialstage == 34 || tutorialstage == 35) - tutorialstagetime = tutorialmaxtime - 1; - } - } - - if (tutorialstage < 14 || tutorialstage >= 50) { - Person::players[1]->coords.y = 300; - Person::players[1]->velocity = 0; - } -} - void doDevKeys() { float headprop, bodyprop, armprop, legprop; @@ -2867,7 +2331,7 @@ void doAttacks() } if (attackweapon) { //sweep - if ((tutoriallevel != 1 || !attackweapon) && + if ((!Tutorial::active || !attackweapon) && distance < 2.5 * sq(Person::players[k]->scale * 5) && randattack == 0 && Animation::animations[Person::players[i]->animTarget].height != lowheight) @@ -2901,7 +2365,7 @@ void doAttacks() randattack >= 3) Person::players[k]->animTarget = staffspinhitanim; //spinkick - else if ((tutoriallevel != 1 || !attackweapon) && + else if ((!Tutorial::active || !attackweapon) && distance < 2.5 * sq(Person::players[k]->scale * 5) && randattack == 1 && Animation::animations[Person::players[i]->animTarget].height != lowheight) @@ -2919,7 +2383,7 @@ void doAttacks() Person::players[k]->animTarget = wolfslapanim; } //sneak attacks - if ((k == 0) && (tutoriallevel != 1 || tutorialstage == 22) && + if ((k == 0) && (!Tutorial::active || Tutorial::stage == 22) && Person::players[i]->howactive < typedead1 && distance < 1.5 * sq(Person::players[k]->scale * 5) && !Person::players[i]->skeleton.free && @@ -3040,7 +2504,7 @@ void doAttacks() distance < 1.5 * sq(Person::players[k]->scale * 5)))) { Person::players[k]->victim = Person::players[i]; Person::players[k]->hasvictim = 1; - if (attackweapon && tutoriallevel != 1) { + if (attackweapon && !Tutorial::active) { //crouchstab if (Person::players[k]->crouchkeydown && attackweapon == knife && distance < 1.5 * sq(Person::players[k]->scale * 5)) Person::players[k]->animTarget = crouchstabanim; @@ -3308,7 +2772,7 @@ void doPlayerCollisions() (k != 0 || Person::players[k]->skeleton.free) || (Animation::animations[Person::players[i]->animTarget].height == highheight && Animation::animations[Person::players[k]->animTarget].height == highheight)) { - if (tutoriallevel != 1) { + if (!Tutorial::active) { emit_sound_at(heavyimpactsound, Person::players[i]->coords); } @@ -3552,7 +3016,7 @@ void doAI(unsigned i) if ((Person::players[i]->collided > .8 && Person::players[i]->jumppower >= 5)) Person::players[i]->jumpkeydown = 1; - if ((tutoriallevel != 1 || cananger) && + if ((!Tutorial::active || cananger) && hostile && !Person::players[0]->dead && distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 400 && @@ -3660,7 +3124,7 @@ void doAI(unsigned i) //hearing sounds if (!editorenabled) { if (Person::players[i]->howactive <= typesleeping) - if (numenvsounds > 0 && (tutoriallevel != 1 || cananger) && hostile) + if (numenvsounds > 0 && (!Tutorial::active || cananger) && hostile) for (int j = 0; j < numenvsounds; j++) { float vol = Person::players[i]->howactive == typesleeping ? envsoundvol[j] - 14 : envsoundvol[j]; if (vol > 0 && distsq(&Person::players[i]->coords, &envsound[j]) < @@ -3676,7 +3140,7 @@ void doAI(unsigned i) } if (Person::players[i]->howactive < typesleeping && - ((tutoriallevel != 1 || cananger) && hostile) && + ((!Tutorial::active || cananger) && hostile) && !Person::players[0]->dead && distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 400 && Person::players[i]->occluded < 25) { @@ -3836,7 +3300,7 @@ void doAI(unsigned i) if ((Person::players[i]->collided > .8 && Person::players[i]->jumppower >= 5)) Person::players[i]->jumpkeydown = 1; - if (numenvsounds > 0 && ((tutoriallevel != 1 || cananger) && hostile)) + if (numenvsounds > 0 && ((!Tutorial::active || cananger) && hostile)) for (int k = 0; k < numenvsounds; k++) { if (distsq(&Person::players[i]->coords, &envsound[k]) < 2 * (envsoundvol[k] + envsoundvol[k] * (Person::players[i]->creature == rabbittype) * 3)) { Person::players[i]->aitype = attacktypecutoff; @@ -3847,7 +3311,7 @@ void doAI(unsigned i) Person::players[i]->losupdatedelay < 0 && !editorenabled && Person::players[i]->occluded < 2 && - ((tutoriallevel != 1 || cananger) && hostile)) { + ((!Tutorial::active || cananger) && hostile)) { Person::players[i]->losupdatedelay = .2; if (distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 4 && Animation::animations[Person::players[i]->animTarget].height != lowheight) { Person::players[i]->aitype = attacktypecutoff; @@ -4020,7 +3484,7 @@ void doAI(unsigned i) Person::players[i]->lastseentime = 12; - if (!Person::players[0]->dead && ((tutoriallevel != 1 || cananger) && hostile)) + if (!Person::players[0]->dead && ((!Tutorial::active || cananger) && hostile)) if (Person::players[i]->ally < 0 || Person::players[i]->weaponactive != -1 || Person::players[i]->lastchecktime <= 0) { Person::players[i]->aitype = attacktypecutoff; Person::players[i]->lastseentime = 1; @@ -4255,7 +3719,7 @@ void doAI(unsigned i) for (unsigned j = 0; j < Person::players.size(); j++) if (j != i && !Person::players[j]->skeleton.free && Person::players[j]->hasvictim && - (tutoriallevel == 1 && reversaltrain || + (Tutorial::active && reversaltrain || Random() % 2 == 0 && difficulty == 2 || Random() % 4 == 0 && difficulty == 1 || Random() % 8 == 0 && difficulty == 0 || @@ -4306,7 +3770,7 @@ void doAI(unsigned i) if (Person::players[i]->jumpkeydown) Person::players[i]->attackkeydown = 0; - if (tutoriallevel == 1) + if (Tutorial::active) if (!canattack) Person::players[i]->attackkeydown = 0; @@ -4422,9 +3886,10 @@ void Game::Tick() } - if (Input::isKeyPressed(SDL_SCANCODE_TAB) && tutoriallevel) { - if (tutorialstage != 51) - tutorialstagetime = tutorialmaxtime; + if (Input::isKeyPressed(SDL_SCANCODE_TAB) && Tutorial::active) { + if (Tutorial::stage != 51) { + Tutorial::stagetime = Tutorial::maxtime; + } emit_sound_np(consolefailsound, 128.); } @@ -4579,7 +4044,7 @@ void Game::Tick() windvar += multiplier; smoketex += multiplier; - tutorialstagetime += multiplier; + Tutorial::stagetime += multiplier; //hotspots static float hotspotvisual[40]; @@ -4611,12 +4076,12 @@ void Game::Tick() } //Tutorial - if (tutoriallevel) { - doTutorial(); + if (Tutorial::active) { + Tutorial::Do(multiplier); } //bonuses - if (tutoriallevel != 1) { + if (!Tutorial::active) { if (bonustime == 0 && bonus != solidhit && bonus != spinecrusher && @@ -4637,7 +4102,7 @@ void Game::Tick() bonusnum[bonus]++; else bonusnum[bonus] += 0.15; - if (tutoriallevel) + if (Tutorial::active) bonusvalue = 0; bonusvalue /= bonusnum[bonus]; bonustotal += bonusvalue; @@ -5259,7 +4724,7 @@ void Game::Tick() if (Person::players.size() > 1) for (unsigned j = 0; j < Person::players.size(); j++) { if (i != j) - if (tutoriallevel != 1 || tutorialstage == 49) + if (!Tutorial::active || Tutorial::stage == 49) if (hostile) if (normaldotproduct(Person::players[i]->facing, Person::players[i]->coords - Person::players[j]->coords) < 0 && distsq(&Person::players[i]->coords, &Person::players[j]->coords) < 100 && @@ -5789,79 +5254,8 @@ void Game::Tick() } OPENAL_SetFrequency(OPENAL_ALL, slomo); - if (tutoriallevel == 1) { - XYZ temp; - XYZ temp2; - XYZ temp3; - XYZ oldtemp; - XYZ oldtemp2; - temp.x = 1011; - temp.y = 84; - temp.z = 491; - temp2.x = 1025; - temp2.y = 75; - temp2.z = 447; - temp3.x = 1038; - temp3.y = 76; - temp3.z = 453; - oldtemp = temp; - oldtemp2 = temp2; - if (tutorialstage >= 51) - if (distsq(&temp, &Person::players[0]->coords) >= distsq(&temp, &temp2) - 1 || distsq(&temp3, &Person::players[0]->coords) < 4) { - OPENAL_StopSound(OPENAL_ALL); // hack...OpenAL renderer isn't stopping music after tutorial goes to level menu... - OPENAL_SetFrequency(OPENAL_ALL); - - emit_stream_np(stream_menutheme); - - gameon = 0; - mainmenu = 5; - - fireSound(); - - flash(); - } - if (tutorialstage < 51) - if (distsq(&temp, &Person::players[0]->coords) >= distsq(&temp, &temp2) - 1 || distsq(&temp3, &Person::players[0]->coords) < 4) { - emit_sound_at(fireendsound, Person::players[0]->coords); - - Person::players[0]->coords = (oldtemp + oldtemp2) / 2; - - flash(); - } - if (tutorialstage >= 14 && tutorialstage < 50) - if (distsq(&temp, &Person::players[1]->coords) >= distsq(&temp, &temp2) - 1 || distsq(&temp3, &Person::players[1]->coords) < 4) { - emit_sound_at(fireendsound, Person::players[1]->coords); - - for (unsigned i = 0; i < Person::players[1]->skeleton.joints.size(); i++) { - if (Random() % 2 == 0) { - if (!Person::players[1]->skeleton.free) - temp2 = (Person::players[1]->coords - Person::players[1]->oldcoords) / multiplier / 2; //velocity/2; - if (Person::players[1]->skeleton.free) - temp2 = Person::players[1]->skeleton.joints[i].velocity * Person::players[1]->scale / 2; - if (!Person::players[1]->skeleton.free) - temp = DoRotation(DoRotation(DoRotation(Person::players[1]->skeleton.joints[i].position, 0, 0, Person::players[1]->tilt), Person::players[1]->tilt2, 0, 0), 0, Person::players[1]->yaw, 0) * Person::players[1]->scale + Person::players[1]->coords; - if (Person::players[1]->skeleton.free) - temp = Person::players[1]->skeleton.joints[i].position * Person::players[1]->scale + Person::players[1]->coords; - Sprite::MakeSprite(breathsprite, temp, temp2, 1, 1, 1, .6 + (float)abs(Random() % 100) / 200 - .25, 1); - } - } - - Person::players[1]->coords = (oldtemp + oldtemp2) / 2; - for (unsigned i = 0; i < Person::players[1]->skeleton.joints.size(); i++) { - Person::players[1]->skeleton.joints[i].velocity = 0; - if (Random() % 2 == 0) { - if (!Person::players[1]->skeleton.free) - temp2 = (Person::players[1]->coords - Person::players[1]->oldcoords) / multiplier / 2; //velocity/2; - if (Person::players[1]->skeleton.free) - temp2 = Person::players[1]->skeleton.joints[i].velocity * Person::players[1]->scale / 2; - if (!Person::players[1]->skeleton.free) - temp = DoRotation(DoRotation(DoRotation(Person::players[1]->skeleton.joints[i].position, 0, 0, Person::players[1]->tilt), Person::players[1]->tilt2, 0, 0), 0, Person::players[1]->yaw, 0) * Person::players[1]->scale + Person::players[1]->coords; - if (Person::players[1]->skeleton.free) - temp = Person::players[1]->skeleton.joints[i].position * Person::players[1]->scale + Person::players[1]->coords; - Sprite::MakeSprite(breathsprite, temp, temp2, 1, 1, 1, .6 + (float)abs(Random() % 100) / 200 - .25, 1); - } - } - } + if (Tutorial::active) { + Tutorial::DoStuff(multiplier); } @@ -6081,7 +5475,7 @@ void Game::TickOnceAfter() maxalarmed = numalarmed; } - if (changedelay <= 0 && !loading && !editorenabled && gameon && !tutoriallevel && changedelay != -999 && !won) { + if (changedelay <= 0 && !loading && !editorenabled && gameon && !Tutorial::active && changedelay != -999 && !won) { if (Person::players[0]->dead && changedelay <= 0) { changedelay = 1; targetlevel = whichlevel; diff --git a/Source/Globals.cpp b/Source/Globals.cpp index 074a78f..df62ea9 100644 --- a/Source/Globals.cpp +++ b/Source/Globals.cpp @@ -101,12 +101,6 @@ float smoketex = 0; float slomospeed = 0; float slomofreq = 0; -int tutoriallevel = 0; -int tutorialstage = 0; -float tutorialstagetime = 0; -float tutorialmaxtime = 0; -float tutorialsuccess = 0; - bool againbonus = false; float damagedealt = 0; diff --git a/Source/Objects/Person.cpp b/Source/Objects/Person.cpp index c1b35e4..9969e61 100644 --- a/Source/Objects/Person.cpp +++ b/Source/Objects/Person.cpp @@ -27,6 +27,7 @@ along with Lugaru. If not, see . #include "Level/Awards.hpp" #include "Level/Dialog.hpp" #include "Utils/Folders.hpp" +#include "Tutorial.hpp" extern float multiplier; extern Terrain terrain; @@ -56,9 +57,7 @@ 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; @@ -479,7 +478,7 @@ void Person::CheckKick() victim->spurt = 1; DoBlood(.2, 250); - if (tutoriallevel != 1) + if (!Tutorial::active) emit_sound_at(heavyimpactsound, victim->coords); victim->RagDoll(0); for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) { @@ -680,7 +679,7 @@ void Person::DoBlood(float howmuch, int which) // FIXME: should abstract out inputs static int bleedxint, bleedyint; static XYZ bloodvel; - if (bloodtoggle && tutoriallevel != 1) { + if (bloodtoggle && !Tutorial::active) { if (bleeding <= 0 && spurt) { spurt = 0; for (int i = 0; i < 3; i++) { @@ -760,7 +759,7 @@ void Person::DoBloodBig(float howmuch, int which) if (howmuch && id == 0) blooddimamount = 1; - if (tutoriallevel != 1 || id == 0) + if (!Tutorial::active || id == 0) if (aitype != playercontrolled && howmuch > 0) { // play pain sounds int whichsound = -1; @@ -790,7 +789,7 @@ void Person::DoBloodBig(float howmuch, int which) Game::flash(.5, 0); } - if (bloodtoggle && decals && tutoriallevel != 1) { + if (bloodtoggle && decals && !Tutorial::active) { if (bleeding <= 0 && spurt) { spurt = 0; for (int i = 0; i < 3; i++) { @@ -945,7 +944,7 @@ void Person::DoBloodBig(float howmuch, int which) deathbleeding += bleeding; bloodloss += bleeding * 3; - if (tutoriallevel != 1 && aitype != playercontrolled && bloodloss > damagetolerance * 2 / 3 && bloodloss < damagetolerance && creature == rabbittype) { + if (!Tutorial::active && aitype != playercontrolled && bloodloss > damagetolerance * 2 / 3 && bloodloss < damagetolerance && creature == rabbittype) { if (abs(Random() % 2) == 0) { aitype = gethelptype; lastseentime = 12; @@ -973,7 +972,7 @@ bool Person::DoBloodBigWhere(float howmuch, int which, XYZ where) float coordsx, coordsy; float total; - if (bloodtoggle && decals && tutoriallevel != 1) { + if (bloodtoggle && decals && !Tutorial::active) { where -= coords; if (!skeleton.free) where = DoRotation(where, 0, -yaw, 0); @@ -1158,7 +1157,7 @@ bool Person::DoBloodBigWhere(float howmuch, int which, XYZ where) deathbleeding += bleeding; bloodloss += bleeding * 3; - if (tutoriallevel != 1 && aitype != playercontrolled && bloodloss > damagetolerance * 2 / 3 && bloodloss < damagetolerance && creature == rabbittype) { + if (!Tutorial::active && aitype != playercontrolled && bloodloss > damagetolerance * 2 / 3 && bloodloss < damagetolerance && creature == rabbittype) { if (abs(Random() % 2) == 0) { aitype = gethelptype; lastseentime = 12; @@ -1183,7 +1182,7 @@ void Person::Reverse() || staggerdelay <= 0) && victim->animTarget != jumpupanim && victim->animTarget != jumpdownanim - && (tutoriallevel != 1 || cananger) + && (!Tutorial::active || cananger) && hostile)) return; @@ -1487,7 +1486,7 @@ void Person::Reverse() void Person::DoDamage(float howmuch) { // subtract health (temporary?) - if (tutoriallevel != 1) + if (!Tutorial::active) damage += howmuch / power; // stats? if (id != 0) @@ -1499,9 +1498,9 @@ void Person::DoDamage(float howmuch) if (id == 0 && (bonus == solidhit || bonus == twoxcombo || bonus == threexcombo || bonus == fourxcombo || bonus == megacombo)) bonus = 0; // subtract health - if (tutoriallevel != 1) + if (!Tutorial::active) permanentdamage += howmuch / 2 / power; - if (tutoriallevel != 1) + if (!Tutorial::active) superpermanentdamage += howmuch / 4 / power; // visual effects if (permanentdamage > damagetolerance / 2 && permanentdamage - howmuch < damagetolerance / 2 && Random() % 2) @@ -1517,9 +1516,9 @@ void Person::DoDamage(float howmuch) blackout = 1; // cancel attack? - if (aitype == passivetype && damage < damagetolerance && ((tutoriallevel != 1 || cananger) && hostile)) + if (aitype == passivetype && damage < damagetolerance && ((!Tutorial::active || cananger) && hostile)) aitype = attacktypecutoff; - if (tutoriallevel != 1 && aitype != playercontrolled && damage < damagetolerance && damage > damagetolerance * 2 / 3 && creature == rabbittype) { + if (!Tutorial::active && aitype != playercontrolled && damage < damagetolerance && damage > damagetolerance * 2 / 3 && creature == rabbittype) { if (abs(Random() % 2) == 0) { aitype = gethelptype; lastseentime = 12; @@ -1560,7 +1559,7 @@ void Person::DoDamage(float howmuch) } // play sounds - if (tutoriallevel != 1 || id == 0) + if (!Tutorial::active || id == 0) if (speechdelay <= 0 && !dead && aitype != playercontrolled) { int whichsound = -1; @@ -2031,7 +2030,7 @@ void Person::DoAnimations() drawtogglekeydown = 1; } //Footstep sounds - if (tutoriallevel != 1 || id == 0) + if (!Tutorial::active || id == 0) if ((targetFrame().label && (targetFrame().label < 5 || targetFrame().label == 8))) { int whichsound = -1; if (onterrain) { @@ -2079,7 +2078,7 @@ void Person::DoAnimations() } else if (targetFrame().label == 4) { whichsound = knifeswishsound; } - if (targetFrame().label == 8 && tutoriallevel != 1) { + if (targetFrame().label == 8 && !Tutorial::active) { whichsound = landsound2; } @@ -2104,7 +2103,7 @@ void Person::DoAnimations() } //Combat sounds - if (tutoriallevel != 1 || id == 0) + if (!Tutorial::active || id == 0) if (speechdelay <= 0) if (animTarget != crouchstabanim && animTarget != swordgroundstabanim && animTarget != staffgroundsmashanim) if ((targetFrame().label && (targetFrame().label < 5 || targetFrame().label == 8))) { @@ -2346,7 +2345,7 @@ void Person::DoAnimations() if (creature == wolftype) DoBloodBig(0, 250); } - if (tutoriallevel != 1) { + if (!Tutorial::active) { emit_sound_at(heavyimpactsound, victim->coords, 128.); } if (creature == wolftype) { @@ -2411,7 +2410,7 @@ void Person::DoAnimations() camerashake += .4; victim->spurt = 1; DoBlood(.2, 250); - if (tutoriallevel != 1) { + if (!Tutorial::active) { emit_sound_at(heavyimpactsound, victim->coords, 160.); } if (creature == wolftype) { @@ -2446,7 +2445,7 @@ void Person::DoAnimations() camerashake += .4; victim->spurt = 1; DoBlood(.2, 250); - if (tutoriallevel != 1) { + if (!Tutorial::active) { emit_sound_at(heavyimpactsound, victim->coords, 160.); } if (creature == wolftype) { @@ -2537,7 +2536,7 @@ void Person::DoAnimations() escapednum = 0; if (id == 0) camerashake += .4; - if (tutoriallevel != 1) { + if (!Tutorial::active) { emit_sound_at(heavyimpactsound, coords, 128.); } XYZ relative; @@ -2562,7 +2561,7 @@ void Person::DoAnimations() escapednum = 0; if (id == 0) camerashake += .4; - if (tutoriallevel != 1) { + if (!Tutorial::active) { emit_sound_at(thudsound, coords); } @@ -2795,7 +2794,7 @@ void Person::DoAnimations() victim->spurt = 1; DoBlood(.2, 235); } - if (tutoriallevel != 1) { + if (!Tutorial::active) { emit_sound_at(heavyimpactsound, victim->coords, 128); } @@ -2830,15 +2829,15 @@ void Person::DoAnimations() 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) { + if (!Tutorial::active) { 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) { + if (!Tutorial::active) { emit_sound_at(whooshhitsound, victim->coords); } } else { - if (tutoriallevel != 1) { + if (!Tutorial::active) { emit_sound_at(heavyimpactsound, victim->coords); } } @@ -2920,11 +2919,11 @@ void Person::DoAnimations() 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) + if (!Tutorial::active) victim->DoBloodBig(1.5 / victim->armorhigh, 225); award_bonus(id, Slicebonus); - if (tutoriallevel != 1) { + if (!Tutorial::active) { emit_sound_at(knifeslicesound, victim->coords); } //victim->jointVel(abdomen)+=relative*damagemult*200; @@ -2941,10 +2940,10 @@ void Person::DoAnimations() if (aitype != playercontrolled) weaponmissdelay = .6; - if (tutoriallevel != 1) + if (!Tutorial::active) if (bloodtoggle && !weapons[weaponids[weaponactive]].bloody) weapons[weaponids[weaponactive]].bloody = 1; - if (tutoriallevel != 1) + if (!Tutorial::active) weapons[weaponids[weaponactive]].blooddrip += 3; XYZ footvel, footpoint; @@ -2954,7 +2953,7 @@ void Person::DoAnimations() } else { footpoint = DoRotation((victim->jointPos(abdomen) + victim->jointPos(neck)) / 2, 0, victim->yaw, 0) * victim->scale + victim->coords; } - if (tutoriallevel != 1) { + if (!Tutorial::active) { if (bloodtoggle) Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .6, .3); footvel = DoRotation(facing, 0, 90, 0) * .8; @@ -2964,7 +2963,7 @@ void Person::DoAnimations() 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) { + if (Tutorial::active) { Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 1, 1, .6, .3); } victim->DoDamage(damagemult * 0); @@ -2975,7 +2974,7 @@ void Person::DoAnimations() if (victim->weaponactive == -1 || normaldotproduct(victim->facing, victim->coords - coords) > 0 || (Random() % 2 == 0)) { award_bonus(id, Slashbonus); escapednum = 0; - if (tutoriallevel != 1) { + if (!Tutorial::active) { if (normaldotproduct(victim->facing, victim->coords - coords) < 0) victim->DoBloodBig(2 / victim->armorhigh, 190); else @@ -2984,14 +2983,14 @@ void Person::DoAnimations() emit_sound_at(swordslicesound, victim->coords); } //victim->jointVel(abdomen)+=relative*damagemult*200; - if (tutoriallevel != 1) { + if (!Tutorial::active) { victim->frameTarget = 0; victim->animTarget = staggerbackhardanim; victim->targetyaw = targetyaw + 180; victim->target = 0; } - if (tutoriallevel != 1) { + if (!Tutorial::active) { if (bloodtoggle && !weapons[weaponids[weaponactive]].bloody) weapons[weaponids[weaponactive]].bloody = 1; weapons[weaponids[weaponactive]].blooddrip += 3; @@ -3060,7 +3059,7 @@ void Person::DoAnimations() 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) { + if (!Tutorial::active) { weapons[weaponids[0]].damage += .4 + float(abs(Random() % 100) - 50) / 250; escapednum = 0; if (id == 0) @@ -3084,7 +3083,7 @@ void Person::DoAnimations() victim->jointVel(head) += relative * damagemult * 230; victim->jointVel(neck) += relative * damagemult * 230; victim->Puff(head); - if (tutoriallevel != 1) { + if (!Tutorial::active) { victim->DoDamage(damagemult * 120 / victim->protectionhigh); award_bonus(id, solidhit, 30); @@ -3094,7 +3093,7 @@ void Person::DoAnimations() 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) { + if (!Tutorial::active) { weapons[weaponids[0]].damage += .6 + float(abs(Random() % 100) - 50) / 250; escapednum = 0; if (id == 0) @@ -3116,7 +3115,7 @@ void Person::DoAnimations() victim->jointVel(head) += relative * damagemult * 220; victim->jointVel(neck) += relative * damagemult * 220; victim->Puff(head); - if (tutoriallevel != 1) { + if (!Tutorial::active) { victim->DoDamage(damagemult * 350 / victim->protectionhead); award_bonus(id, solidhit, 60); @@ -3127,7 +3126,7 @@ void Person::DoAnimations() 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 (!Tutorial::active) { if (!victim->dead) weapons[weaponids[0]].damage += .4 + float(abs(Random() % 100) - 50) / 500; if (id == 0) @@ -3164,7 +3163,7 @@ void Person::DoAnimations() } } victim->Puff(abdomen); - if (tutoriallevel != 1) { + if (!Tutorial::active) { victim->DoDamage(damagemult * 100 / victim->protectionhigh); if (!victim->dead) { @@ -3196,7 +3195,7 @@ void Person::DoAnimations() victim->skeleton.joints[i].velocity += relative * damagemult * 40; } victim->jointVel(head) += relative * damagemult * 200; - if (tutoriallevel != 1) { + if (!Tutorial::active) { emit_sound_at(heavyimpactsound, victim->coords, 128.); } victim->Puff(head); @@ -3219,7 +3218,7 @@ void Person::DoAnimations() victim->animTarget = staggerbackhighanim; victim->targetyaw = targetyaw + 180; victim->target = 0; - if (tutoriallevel != 1) { + if (!Tutorial::active) { emit_sound_at(landsound2, victim->coords, 128.); } victim->Puff(abdomen); @@ -3241,7 +3240,7 @@ void Person::DoAnimations() escapednum = 0; if (id == 0) camerashake += .2; - if (tutoriallevel != 1) { + if (!Tutorial::active) { emit_sound_at(landsound2, victim->coords, 128.); } XYZ relative; @@ -3280,7 +3279,7 @@ void Person::DoAnimations() victim->animTarget = staggerbackhighanim; victim->targetyaw = targetyaw + 180; victim->target = 0; - if (tutoriallevel != 1) { + if (!Tutorial::active) { emit_sound_at(landsound2, victim->coords, 128.); } victim->Puff(abdomen); @@ -3301,7 +3300,7 @@ void Person::DoAnimations() victim->spurt = 1; DoBlood(.2, 230); } - if (tutoriallevel != 1) { + if (!Tutorial::active) { emit_sound_at(heavyimpactsound, victim->coords, 128.); } if (creature == wolftype) { @@ -3370,7 +3369,7 @@ void Person::DoAnimations() award_bonus(id, staffreversebonus); - if (tutoriallevel != 1) { + if (!Tutorial::active) { emit_sound_at(heavyimpactsound, victim->coords, 128.); } victim->RagDoll(0); @@ -3469,7 +3468,7 @@ void Person::DoAnimations() victim->spurt = 1; DoBlood(.2, 230); } - if (tutoriallevel != 1) { + if (!Tutorial::active) { emit_sound_at(heavyimpactsound, victim->coords, 128.); } victim->RagDoll(0); @@ -3662,7 +3661,7 @@ void Person::DoAnimations() DoBlood(.2, 240); } if (weaponactive == -1) { - if (tutoriallevel != 1) { + if (!Tutorial::active) { emit_sound_at(heavyimpactsound, victim->coords, 128.); } } @@ -4394,7 +4393,7 @@ void Person::DoStuff() Sprite::MakeSprite(flamesprite, flatfacing, flatvelocity, 1, 1, 1, .6 + (float)abs(Random() % 100) / 200 - .25, 1); } - while (flamedelay < 0 && !onfire && tutoriallevel == 1 && id != 0) { + while (flamedelay < 0 && !onfire && Tutorial::active && id != 0) { flamedelay += .05; int howmany = fabs(Random() % (skeleton.joints.size())); if (skeleton.free) { @@ -5423,7 +5422,7 @@ void Person::DoStuff() if (hasvictim) if (aitype != passivetype && victim->skeleton.free && !victim->dead) play = 1; - if (tutoriallevel == 1 && id != 0) + if (Tutorial::active && id != 0) play = 0; if (play && aitype != playercontrolled) { int whichsound = -1; @@ -6363,7 +6362,7 @@ int Person::DrawSkeleton() glEnable(GL_LIGHTING); glEnable(GL_BLEND); } - if (tutoriallevel && id != 0) { + if (Tutorial::active && id != 0) { glColor4f(.7, .7, .7, 0.6); glDepthMask(0); glEnable(GL_LIGHTING); @@ -6380,21 +6379,21 @@ int Person::DrawSkeleton() } if (playerdetail) { if (!showpoints) { - if ((tutoriallevel && id != 0)) + if (Tutorial::active && (id != 0)) skeleton.drawmodel.drawdifftex(Sprite::cloudimpacttexture); else skeleton.drawmodel.draw(); } } if (!playerdetail) { - if ((tutoriallevel && id != 0)) + if (Tutorial::active && (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) { + if (Tutorial::active && id != 0) { glPopMatrix(); glMatrixMode(GL_MODELVIEW); glEnable(GL_TEXTURE_2D); @@ -6413,14 +6412,14 @@ int Person::DrawSkeleton() glTranslatef(smoketex * .6, 0, 0); if (playerdetail) { if (!showpoints) { - if ((tutoriallevel && id != 0)) + if (Tutorial::active && (id != 0)) skeleton.drawmodel.drawdifftex(Sprite::cloudimpacttexture); else skeleton.drawmodel.draw(); } } if (!playerdetail) { - if ((tutoriallevel && id != 0)) + if (Tutorial::active && (id != 0)) skeleton.drawmodellow.drawdifftex(Sprite::cloudimpacttexture); else skeleton.drawmodellow.drawdifftex(skeleton.drawmodel.textureptr); @@ -6428,7 +6427,7 @@ int Person::DrawSkeleton() } - if (tutoriallevel && id != 0) { + if (Tutorial::active && id != 0) { glPopMatrix(); glMatrixMode(GL_MODELVIEW); glEnable(GL_TEXTURE_2D); diff --git a/Source/Objects/Weapons.cpp b/Source/Objects/Weapons.cpp index d762ddc..38ee55b 100644 --- a/Source/Objects/Weapons.cpp +++ b/Source/Objects/Weapons.cpp @@ -27,6 +27,7 @@ along with Lugaru. If not, see . #include "Audio/Sounds.hpp" #include "Game.hpp" #include "Level/Awards.hpp" +#include "Tutorial.hpp" extern float multiplier; extern Terrain terrain; @@ -48,7 +49,6 @@ extern float woozy; extern float viewdistance; extern float blackout; extern bool freeze; -extern int tutoriallevel; extern int numthrowkill; Model Weapon::throwingknifemodel; @@ -248,16 +248,16 @@ void Weapon::DoStuff(int i) 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) + if (bloodtoggle && !Tutorial::active) Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .8, .3); - if (tutoriallevel == 1) + if (Tutorial::active) Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 1, 1, .8, .3); footvel = tippoint - position; Normalise(&footvel); - if (bloodtoggle && tutoriallevel != 1) + if (bloodtoggle && !Tutorial::active) Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * -1, 1, 0, 0, .6, 1); - if (tutoriallevel != 1) { + if (!Tutorial::active) { if (Person::players[j]->weaponstuckwhere == 0) Person::players[j]->DoBloodBig(2, 205); if (Person::players[j]->weaponstuckwhere == 1) diff --git a/Source/Tutorial.cpp b/Source/Tutorial.cpp new file mode 100644 index 0000000..006da97 --- /dev/null +++ b/Source/Tutorial.cpp @@ -0,0 +1,910 @@ +/* +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 . +*/ + +#include "Tutorial.hpp" +#include "Game.hpp" +#include "Audio/Sounds.hpp" +#include "Audio/openal_wrapper.hpp" +#include "Level/Awards.hpp" +#include "Objects/Person.hpp" +#include "Utils/Input.hpp" + +extern bool reversaltrain; +extern bool canattack; +extern bool cananger; +extern int bonus; +extern float damagedealt; +extern bool againbonus; +extern float screenwidth, screenheight; +extern int mainmenu; + +bool Tutorial::active = false; +int Tutorial::stage = 0; +float Tutorial::stagetime = 0; +float Tutorial::maxtime = 0; +float Tutorial::success = 0; + +void Tutorial::Do(float multiplier) +{ + if (stagetime > maxtime) { + stage++; + success = 0; + if (stage <= 1) { + canattack = 0; + cananger = 0; + reversaltrain = 0; + } + switch (stage) { + case 1: + maxtime = 5; + break; + case 2: + case 10: + case 13: + case 26: + maxtime = 2; + break; + case 3: + case 5: + case 6: + case 7: + case 8: + case 9: + maxtime = 600; + break; + case 4: + case 11: + case 12: + maxtime = 1000; + break; + case 14: { + maxtime = 3; + + XYZ temp, temp2; + + temp.x = 1011; + temp.y = 84; + temp.z = 491; + temp2.x = 1025; + temp2.y = 75; + temp2.z = 447; + + Person::players[1]->coords = (temp + temp2) / 2; + + emit_sound_at(fireendsound, Person::players[1]->coords); + + for (unsigned i = 0; i < Person::players[1]->skeleton.joints.size(); i++) { + if (Random() % 2 == 0) { + if (!Person::players[1]->skeleton.free) + temp2 = (Person::players[1]->coords - Person::players[1]->oldcoords) / multiplier / 2; //velocity/2; + if (Person::players[1]->skeleton.free) + temp2 = Person::players[1]->skeleton.joints[i].velocity * Person::players[1]->scale / 2; + if (!Person::players[1]->skeleton.free) + temp = DoRotation(DoRotation(DoRotation(Person::players[1]->skeleton.joints[i].position, 0, 0, Person::players[1]->tilt), Person::players[1]->tilt2, 0, 0), 0, Person::players[1]->yaw, 0) * Person::players[1]->scale + Person::players[1]->coords; + if (Person::players[1]->skeleton.free) + temp = Person::players[1]->skeleton.joints[i].position * Person::players[1]->scale + Person::players[1]->coords; + Sprite::MakeSprite(breathsprite, temp, temp2, 1, 1, 1, .6 + (float)abs(Random() % 100) / 200 - .25, 1); + } + } + } + break; + case 15: + case 16: + case 17: + case 18: + case 20: + case 22: + case 23: + case 24: + case 25: + maxtime = 500; + break; + case 19: + stage = 20; + break; + case 21: + maxtime = 500; + if (bonus == cannon) { + bonus = Slicebonus; + againbonus = 1; + } else + againbonus = 0; + break; + case 27: + maxtime = 4; + reversaltrain = 1; + cananger = 1; + Person::players[1]->aitype = attacktypecutoff; + break; + case 28: + case 34: + case 35: + maxtime = 400; + break; + case 29: + maxtime = 400; + Person::players[0]->escapednum = 0; + break; + case 30: + maxtime = 4; + reversaltrain = 0; + cananger = 0; + Person::players[1]->aitype = passivetype; + break; + case 31: + maxtime = 13; + break; + case 32: + maxtime = 8; + break; + case 33: + maxtime = 400; + cananger = 1; + canattack = 1; + Person::players[1]->aitype = attacktypecutoff; + break; + case 36: + maxtime = 2; + reversaltrain = 0; + cananger = 0; + Person::players[1]->aitype = passivetype; + break; + case 37: + damagedealt = 0; + damagetaken = 0; + maxtime = 50; + cananger = 1; + canattack = 1; + Person::players[1]->aitype = attacktypecutoff; + break; + case 38: + maxtime = 4; + canattack = 0; + cananger = 0; + Person::players[1]->aitype = passivetype; + break; + case 39: { + XYZ temp, temp2; + + temp.x = 1011; + temp.y = 84; + temp.z = 491; + temp2.x = 1025; + temp2.y = 75; + temp2.z = 447; + + Weapon w(knife, -1); + w.position = (temp + temp2) / 2; + w.tippoint = (temp + temp2) / 2; + + w.velocity = 0.1; + w.tipvelocity = 0.1; + w.missed = 1; + w.hitsomething = 0; + w.freetime = 0; + w.firstfree = 1; + w.physics = 1; + + weapons.push_back(w); + } + break; + case 40: + case 41: + case 43: + maxtime = 300; + break; + case 42: + maxtime = 8; + break; + case 44: + weapons[0].owner = 1; + Person::players[0]->weaponactive = -1; + Person::players[0]->num_weapons = 0; + Person::players[1]->weaponactive = 0; + Person::players[1]->num_weapons = 1; + Person::players[1]->weaponids[0] = 0; + + cananger = 1; + canattack = 1; + Person::players[1]->aitype = attacktypecutoff; + + maxtime = 300; + break; + case 45: + weapons[0].owner = 1; + Person::players[0]->weaponactive = -1; + Person::players[0]->num_weapons = 0; + Person::players[1]->weaponactive = 0; + Person::players[1]->num_weapons = 1; + Person::players[1]->weaponids[0] = 0; + + maxtime = 300; + break; + case 46: + weapons[0].owner = 1; + Person::players[0]->weaponactive = -1; + Person::players[0]->num_weapons = 0; + Person::players[1]->weaponactive = 0; + Person::players[1]->num_weapons = 1; + Person::players[1]->weaponids[0] = 0; + + weapons[0].setType(sword); + + maxtime = 300; + break; + case 47: { + maxtime = 10; + + XYZ temp, temp2; + + temp.x = 1011; + temp.y = 84; + temp.z = 491; + temp2.x = 1025; + temp2.y = 75; + temp2.z = 447; + + Weapon w(sword, -1); + w.position = (temp + temp2) / 2; + w.tippoint = (temp + temp2) / 2; + + w.velocity = 0.1; + w.tipvelocity = 0.1; + w.missed = 1; + w.hitsomething = 0; + w.freetime = 0; + w.firstfree = 1; + w.physics = 1; + + weapons.push_back(w); + + weapons[0].owner = 1; + weapons[1].owner = 0; + Person::players[0]->weaponactive = 0; + Person::players[0]->num_weapons = 1; + Person::players[0]->weaponids[0] = 1; + Person::players[1]->weaponactive = 0; + Person::players[1]->num_weapons = 1; + Person::players[1]->weaponids[0] = 0; + + } + break; + case 48: + canattack = 0; + cananger = 0; + Person::players[1]->aitype = passivetype; + + maxtime = 15; + + weapons[0].owner = 1; + weapons[1].owner = 0; + Person::players[0]->weaponactive = 0; + Person::players[0]->num_weapons = 1; + Person::players[0]->weaponids[0] = 1; + Person::players[1]->weaponactive = 0; + Person::players[1]->num_weapons = 1; + Person::players[1]->weaponids[0] = 0; + + if (Person::players[0]->weaponactive != -1) + weapons[Person::players[0]->weaponids[Person::players[0]->weaponactive]].setType(staff); + else + weapons[0].setType(staff); + break; + case 49: + canattack = 0; + cananger = 0; + Person::players[1]->aitype = passivetype; + + maxtime = 200; + + weapons[1].position = 1000; + weapons[1].tippoint = 1000; + + weapons[0].setType(knife); + + weapons[0].owner = 0; + Person::players[1]->weaponactive = -1; + Person::players[1]->num_weapons = 0; + Person::players[0]->weaponactive = 0; + Person::players[0]->num_weapons = 1; + Person::players[0]->weaponids[0] = 0; + + break; + case 50: { + maxtime = 8; + + XYZ temp, temp2; + emit_sound_at(fireendsound, Person::players[1]->coords); + + for (unsigned i = 0; i < Person::players[1]->skeleton.joints.size(); i++) { + if (Random() % 2 == 0) { + if (!Person::players[1]->skeleton.free) + temp2 = (Person::players[1]->coords - Person::players[1]->oldcoords) / multiplier / 2; //velocity/2; + if (Person::players[1]->skeleton.free) + temp2 = Person::players[1]->skeleton.joints[i].velocity * Person::players[1]->scale / 2; + if (!Person::players[1]->skeleton.free) + temp = DoRotation(DoRotation(DoRotation(Person::players[1]->skeleton.joints[i].position, 0, 0, Person::players[1]->tilt), Person::players[1]->tilt2, 0, 0), 0, Person::players[1]->yaw, 0) * Person::players[1]->scale + Person::players[1]->coords; + if (Person::players[1]->skeleton.free) + temp = Person::players[1]->skeleton.joints[i].position * Person::players[1]->scale + Person::players[1]->coords; + Sprite::MakeSprite(breathsprite, temp, temp2, 1, 1, 1, .6 + (float)abs(Random() % 100) / 200 - .25, 1); + } + } + + Person::players[1]->num_weapons = 0; + Person::players[1]->weaponstuck = -1; + Person::players[1]->weaponactive = -1; + + weapons.clear(); + } + break; + case 51: + maxtime = 80000; + break; + default: + break; + } + if (stage <= 51) + stagetime = 0; + } + + //Tutorial success + if (stagetime < maxtime - 3) { + switch (stage) { + case 3: + if (Game::deltah || Game::deltav) + success += multiplier; + break; + case 4: + if (Person::players[0]->forwardkeydown || Person::players[0]->backkeydown || Person::players[0]->leftkeydown || Person::players[0]->rightkeydown) + success += multiplier; + break; + case 5: + if (Person::players[0]->jumpkeydown) + success = 1; + break; + case 6: + if (Person::players[0]->isCrouch()) + success = 1; + break; + case 7: + if (Person::players[0]->animTarget == rollanim) + success = 1; + break; + case 8: + if (Person::players[0]->animTarget == sneakanim) + success += multiplier; + break; + case 9: + if (Person::players[0]->animTarget == rabbitrunninganim || Person::players[0]->animTarget == wolfrunninganim) + success += multiplier; + break; + case 11: + if (Person::players[0]->isWallJump()) + success = 1; + break; + case 12: + if (Person::players[0]->animTarget == flipanim) + success = 1; + break; + case 15: + if (Person::players[0]->animTarget == upunchanim || Person::players[0]->animTarget == winduppunchanim) + success = 1; + break; + case 16: + if (Person::players[0]->animTarget == winduppunchanim) + success = 1; + break; + case 17: + if (Person::players[0]->animTarget == spinkickanim) + success = 1; + break; + case 18: + if (Person::players[0]->animTarget == sweepanim) + success = 1; + break; + case 19: + if (Person::players[0]->animTarget == dropkickanim) + success = 1; + break; + case 20: + if (Person::players[0]->animTarget == rabbitkickanim) + success = 1; + break; + case 21: + if (bonus == cannon) + success = 1; + break; + case 22: + if (bonus == spinecrusher) + success = 1; + break; + case 23: + if (Person::players[0]->animTarget == walljumprightkickanim || Person::players[0]->animTarget == walljumpleftkickanim) + success = 1; + break; + case 24: + if (Person::players[0]->animTarget == rabbittacklinganim) + success = 1; + break; + case 25: + if (Person::players[0]->animTarget == backhandspringanim) + success = 1; + break; + case 28: + if (Animation::animations[Person::players[0]->animTarget].attack == reversed && Person::players[0]->feint) + success = 1; + break; + case 29: + if (Person::players[0]->escapednum == 2) { + success = 1; + reversaltrain = 0; + cananger = 0; + Person::players[1]->aitype = passivetype; + } + break; + case 33: + case 34: + if (Animation::animations[Person::players[0]->animTarget].attack == reversal) { + success = 1; + } + break; + case 35: + if (Animation::animations[Person::players[0]->animTarget].attack == reversal) { + success = 1; + reversaltrain = 0; + cananger = 0; + Person::players[1]->aitype = passivetype; + } + break; + case 40: + if (Person::players[0]->num_weapons > 0) { + success = 1; + } + break; + case 41: + if (Person::players[0]->weaponactive == -1 && Person::players[0]->num_weapons > 0) { + success = 1; + } + break; + case 43: + if (Person::players[0]->animTarget == knifeslashstartanim) { + success = 1; + } + break; + case 44: + case 45: + case 46: + if (Animation::animations[Person::players[0]->animTarget].attack == reversal) { + success = 1; + } + break; + case 49: + if (Person::players[1]->weaponstuck != -1) { + success = 1; + } + break; + default: + break; + } + if (success >= 1) { + stagetime = maxtime - 3; + } + + if (stagetime == maxtime - 3) { + emit_sound_np(consolesuccesssound); + } + + if (success >= 1) { + if (stage == 34 || stage == 35) { + stagetime = maxtime - 1; + } + } + } + + if (stage < 14 || stage >= 50) { + Person::players[1]->coords.y = 300; + Person::players[1]->velocity = 0; + } +} + +void Tutorial::DrawText() +{ + std::string string; + std::string string2; + std::string string3; + float tutorialopac = maxtime - stagetime; + if (tutorialopac > 1) + tutorialopac = 1; + if (tutorialopac < 0) + tutorialopac = 0; + + string = " "; + string2 = " "; + string3 = " "; + if (stage == 0) { + string = " "; + string2 = " "; + string3 = " "; + } + if (stage == 1) { + string = "Welcome to the Lugaru training level!"; + string2 = " "; + string3 = " "; + } + if (stage == 2) { + string = "BASIC MOVEMENT:"; + string2 = " "; + string3 = " "; + } + if (stage == 3) { + string = "You can move the mouse to rotate the camera."; + string2 = " "; + string3 = " "; + } + if (stage == 4) { + string = std::string("Try using the ") + + Input::keyToChar(Game::forwardkey) + ", " + + Input::keyToChar(Game::leftkey) + ", " + + Input::keyToChar(Game::backkey) + " and " + + Input::keyToChar(Game::rightkey) + " keys to move around."; + string2 = "All movement is relative to the camera."; + string3 = " "; + } + if (stage == 5) { + string = std::string("Please press ") + Input::keyToChar(Game::jumpkey) + " to jump."; + string2 = "You can hold it longer to jump higher."; + string3 = " "; + } + if (stage == 6) { + string = std::string("You can press ") + Input::keyToChar(Game::crouchkey) + " to crouch."; + string2 = "You can jump higher from a crouching position."; + string3 = " "; + } + if (stage == 7) { + string = std::string("While running, you can press ") + Input::keyToChar(Game::crouchkey) + " to roll."; + string2 = " "; + string3 = " "; + } + if (stage == 8) { + string = "While crouching, you can sneak around silently"; + string2 = "using the movement keys."; + string3 = " "; + } + if (stage == 9) { + string = "Release the crouch key while sneaking and hold the movement keys"; + string2 = "to run animal-style."; + string3 = " "; + } + if (stage == 10) { + string = "ADVANCED MOVEMENT:"; + string2 = " "; + string3 = " "; + } + if (stage == 11) { + string = std::string("When you jump at a wall, you can hold ") + Input::keyToChar(Game::jumpkey) + " again"; + string2 = "during impact to perform a walljump."; + string3 = "Be sure to use the movement keys to press against the wall"; + } + if (stage == 12) { + string = "While in the air, you can press crouch to flip."; + string2 = "Walljumps and flips confuse enemies and give you more control."; + string3 = " "; + } + if (stage == 13) { + string = "BASIC COMBAT:"; + string2 = " "; + string3 = " "; + } + if (stage == 14) { + string = "There is now an imaginary enemy"; + string2 = "in the middle of the training area."; + string3 = " "; + } + if (stage == 15) { + if (Game::attackkey == MOUSEBUTTON1) { + string = "Click to attack when you are near an enemy."; + } else { + string = std::string("Press ") + Input::keyToChar(Game::attackkey) + " to attack when you are near an enemy."; + } + string2 = "You can punch by standing still near an enemy and attacking."; + string3 = " "; + } + if (stage == 16) { + string = "If you are close, you will perform a weak punch."; + string2 = "The weak punch is excellent for starting attack combinations."; + string3 = " "; + } + if (stage == 17) { + string = "Attacking while running results in a spin kick."; + string2 = "This is one of your most powerful ground attacks."; + string3 = " "; + } + if (stage == 18) { + string = "Sweep the enemy's legs out by attacking while crouched."; + string2 = "This is a very fast attack, and easy to follow up."; + string3 = " "; + } + if (stage == 19) { + string = "When an enemy is on the ground, you can deal some extra"; + string2 = "damage by running up and drop-kicking him."; + string3 = "(Try knocking them down with a sweep first)"; + } + if (stage == 20) { + string = "Your most powerful individual attack is the rabbit kick."; + if (Game::attackkey == MOUSEBUTTON1) { + string2 = "Run at the enemy while holding the mouse button, and press"; + } else { + string2 = std::string("Run at the enemy while holding ") + Input::keyToChar(Game::attackkey) + ", and press"; + } + string3 = std::string("the jump key (") + Input::keyToChar(Game::jumpkey) + ") to attack."; + } + if (stage == 21) { + string = "This attack is devastating if timed correctly."; + string2 = "Even if timed incorrectly, it will knock the enemy over."; + if (againbonus) + string3 = "Try rabbit-kicking the imaginary enemy again."; + else + string3 = "Try rabbit-kicking the imaginary enemy."; + } + if (stage == 22) { + string = "If you sneak behind an enemy unnoticed, you can kill"; + string2 = "him instantly. Move close behind this enemy"; + string3 = "and attack."; + } + if (stage == 23) { + string = "Another important attack is the wall kick. When an enemy"; + string2 = "is near a wall, perform a walljump nearby and hold"; + string3 = "the attack key during impact with the wall."; + } + if (stage == 24) { + string = "You can tackle enemies by running at them animal-style"; + if (Game::attackkey == MOUSEBUTTON1) { + string2 = std::string("and pressing jump (") + Input::keyToChar(Game::jumpkey) + ") or attack(mouse button)."; + } else { + string2 = std::string("and pressing jump (") + Input::keyToChar(Game::jumpkey) + ") or attack(" + Input::keyToChar(Game::attackkey) + ")."; + } + string3 = "This is especially useful when they are running away."; + } + if (stage == 25) { + string = "Dodge by pressing back and attack. Dodging is essential"; + string2 = "against enemies with swords or other long weapons."; + string3 = " "; + } + if (stage == 26) { + string = "REVERSALS AND COUNTER-REVERSALS"; + string2 = " "; + string3 = " "; + } + if (stage == 27) { + string = "The enemy can now reverse your attacks."; + string2 = " "; + string3 = " "; + } + if (stage == 28) { + string = "If you attack, you will notice that the enemy now sometimes"; + string2 = "catches your attack and uses it against you. Hold"; + string3 = std::string("crouch (") + Input::keyToChar(Game::crouchkey) + ") after attacking to escape from reversals."; + } + if (stage == 29) { + string = "Try escaping from two more reversals in a row."; + string2 = " "; + string3 = " "; + } + if (stage == 30) { + string = "Good!"; + string2 = " "; + string3 = " "; + } + if (stage == 31) { + string = std::string("To reverse an attack, you must tap crouch (") + Input::keyToChar(Game::crouchkey) + ") during the"; + string2 = "enemy's attack. You must also be close to the enemy;"; + string3 = "this is especially important against armed opponents."; + } + if (stage == 32) { + string = "The enemy can attack in " + to_string(int(maxtime - stagetime)) + " seconds."; + string2 = "This imaginary opponents attacks will be highlighted"; + string3 = "to make this easier."; + } + if (stage == 33) { + string = "Reverse three enemy attacks!"; + string2 = " "; + string3 = " "; + } + if (stage == 34) { + string = "Reverse two more enemy attacks!"; + string2 = " "; + string3 = " "; + } + if (stage == 35) { + string = "Reverse one more enemy attack!"; + string2 = " "; + string3 = " "; + } + if (stage == 36) { + string = "Excellent!"; + string2 = " "; + string3 = " "; + } + if (stage == 37) { + string = "Now spar with the enemy for " + to_string(int(maxtime - stagetime)) + " more seconds."; + string2 = "Damage dealt: " + to_string(int(damagedealt)); + string3 = "Damage taken: " + to_string(int(damagetaken)); + } + if (stage == 38) { + string = "WEAPONS:"; + string2 = " "; + string3 = " "; + } + if (stage == 39) { + string = "There is now an imaginary knife"; + string2 = "in the center of the training area."; + string3 = " "; + } + if (stage == 40) { + string = "Stand, roll or handspring over the knife"; + string2 = std::string("while pressing ") + Input::keyToChar(Game::throwkey) + " to pick it up."; + string3 = "You can crouch and press the same key to drop it again."; + } + if (stage == 41) { + string = std::string("You can equip and unequip weapons using the ") + Input::keyToChar(Game::drawkey) + " key."; + string2 = "Sometimes it is best to keep them unequipped to"; + string3 = "prevent enemies from taking them. "; + } + if (stage == 42) { + string = "The knife is the smallest weapon and the least encumbering."; + string2 = "You can equip or unequip it while standing, crouching,"; + string3 = "running or flipping."; + } + if (stage == 43) { + string = "You perform weapon attacks the same way as unarmed attacks,"; + string2 = "but sharp weapons cause permanent damage, instead of the"; + string3 = "temporary trauma from blunt weapons, fists and feet."; + } + if (stage == 44) { + string = "The enemy now has your knife!"; + string2 = "Please reverse two of his knife attacks."; + string3 = " "; + } + if (stage == 45) { + string = "Please reverse one more of his knife attacks."; + string2 = " "; + string3 = " "; + } + if (stage == 46) { + string = "Now he has a sword!"; + string2 = "The sword has longer reach than your arms, so you"; + string3 = "must move close to reverse the sword slash."; + } + if (stage == 47) { + string = "Long weapons like the sword and staff are also useful for defense;"; + string2 = "you can parry enemy weapon attacks by pressing the attack key"; + string3 = "at the right time. Please try parrying the enemy's attacks!"; + } + if (stage == 48) { + string = "The staff is like the sword, but has two main attacks."; + string2 = "The standing smash is fast and effective, and the running"; + string3 = "spin smash is slower and more powerful."; + } + if (stage == 49) { + string = std::string("When facing an enemy, you can throw the knife with ") + Input::keyToChar(Game::throwkey) + "."; + string2 = "It is possible to throw the knife while flipping,"; + string3 = "but it is very inaccurate."; + } + if (stage == 50) { + string = "You now know everything you can learn from training."; + string2 = "Everything else you must learn from experience!"; + string3 = " "; + } + if (stage == 51) { + string = "Walk out of the training area to return to the main menu."; + string2 = " "; + string3 = " "; + } + + Game::text->glPrintOutlined(1, 1, 1, tutorialopac, screenwidth / 2 - 7.6 * string.size()*screenwidth / 1024, screenheight / 16 + screenheight * 4 / 5, string, 1, 1.5 * screenwidth / 1024, screenwidth, screenheight); + Game::text->glPrintOutlined(1, 1, 1, tutorialopac, screenwidth / 2 - 7.6 * string2.size()*screenwidth / 1024, screenheight / 16 + screenheight * 4 / 5 - 20 * screenwidth / 1024, string2, 1, 1.5 * screenwidth / 1024, screenwidth, screenheight); + Game::text->glPrintOutlined(1, 1, 1, tutorialopac, screenwidth / 2 - 7.6 * string3.size()*screenwidth / 1024, screenheight / 16 + screenheight * 4 / 5 - 40 * screenwidth / 1024, string3, 1, 1.5 * screenwidth / 1024, screenwidth, screenheight); + + string = "Press 'tab' to skip to the next item."; + string2 = "Press escape at any time to"; + string3 = "pause or exit the tutorial."; + + Game::text->glPrintOutlined(0.5, 0.5, 0.5, 1, screenwidth / 2 - 7.6 * string.size()*screenwidth / 1024 * .8, 0 + screenheight * 1 / 10, string, 1, 1.5 * screenwidth / 1024 * .8, screenwidth, screenheight); + Game::text->glPrintOutlined(0.5, 0.5, 0.5, 1, screenwidth / 2 - 7.6 * string2.size()*screenwidth / 1024 * .8, 0 + screenheight * 1 / 10 - 20 * .8 * screenwidth / 1024, string2, 1, 1.5 * screenwidth / 1024 * .8, screenwidth, screenheight); + Game::text->glPrintOutlined(0.5, 0.5, 0.5, 1, screenwidth / 2 - 7.6 * string3.size()*screenwidth / 1024 * .8, 0 + screenheight * 1 / 10 - 40 * .8 * screenwidth / 1024, string3, 1, 1.5 * screenwidth / 1024 * .8, screenwidth, screenheight); +} + +void Tutorial::DoStuff(float multiplier) +{ + XYZ temp; + XYZ temp2; + XYZ temp3; + XYZ oldtemp; + XYZ oldtemp2; + temp.x = 1011; + temp.y = 84; + temp.z = 491; + temp2.x = 1025; + temp2.y = 75; + temp2.z = 447; + temp3.x = 1038; + temp3.y = 76; + temp3.z = 453; + oldtemp = temp; + oldtemp2 = temp2; + if (stage >= 51) { + if (distsq(&temp, &Person::players[0]->coords) >= distsq(&temp, &temp2) - 1 || distsq(&temp3, &Person::players[0]->coords) < 4) { + OPENAL_StopSound(OPENAL_ALL); // hack...OpenAL renderer isn't stopping music after tutorial goes to level menu... + OPENAL_SetFrequency(OPENAL_ALL); + + emit_stream_np(stream_menutheme); + + Game::gameon = 0; + mainmenu = 5; + + Game::fireSound(); + + Game::flash(); + } + } else { + if (distsq(&temp, &Person::players[0]->coords) >= distsq(&temp, &temp2) - 1 || distsq(&temp3, &Person::players[0]->coords) < 4) { + emit_sound_at(fireendsound, Person::players[0]->coords); + + Person::players[0]->coords = (oldtemp + oldtemp2) / 2; + + Game::flash(); + } + } + if (stage >= 14 && stage < 50) { + if (distsq(&temp, &Person::players[1]->coords) >= distsq(&temp, &temp2) - 1 || distsq(&temp3, &Person::players[1]->coords) < 4) { + emit_sound_at(fireendsound, Person::players[1]->coords); + + for (unsigned i = 0; i < Person::players[1]->skeleton.joints.size(); i++) { + if (Random() % 2 == 0) { + if (!Person::players[1]->skeleton.free) + temp2 = (Person::players[1]->coords - Person::players[1]->oldcoords) / multiplier / 2; //velocity/2; + if (Person::players[1]->skeleton.free) + temp2 = Person::players[1]->skeleton.joints[i].velocity * Person::players[1]->scale / 2; + if (!Person::players[1]->skeleton.free) + temp = DoRotation(DoRotation(DoRotation(Person::players[1]->skeleton.joints[i].position, 0, 0, Person::players[1]->tilt), Person::players[1]->tilt2, 0, 0), 0, Person::players[1]->yaw, 0) * Person::players[1]->scale + Person::players[1]->coords; + if (Person::players[1]->skeleton.free) + temp = Person::players[1]->skeleton.joints[i].position * Person::players[1]->scale + Person::players[1]->coords; + Sprite::MakeSprite(breathsprite, temp, temp2, 1, 1, 1, .6 + (float)abs(Random() % 100) / 200 - .25, 1); + } + } + + Person::players[1]->coords = (oldtemp + oldtemp2) / 2; + for (unsigned i = 0; i < Person::players[1]->skeleton.joints.size(); i++) { + Person::players[1]->skeleton.joints[i].velocity = 0; + if (Random() % 2 == 0) { + if (!Person::players[1]->skeleton.free) + temp2 = (Person::players[1]->coords - Person::players[1]->oldcoords) / multiplier / 2; //velocity/2; + if (Person::players[1]->skeleton.free) + temp2 = Person::players[1]->skeleton.joints[i].velocity * Person::players[1]->scale / 2; + if (!Person::players[1]->skeleton.free) + temp = DoRotation(DoRotation(DoRotation(Person::players[1]->skeleton.joints[i].position, 0, 0, Person::players[1]->tilt), Person::players[1]->tilt2, 0, 0), 0, Person::players[1]->yaw, 0) * Person::players[1]->scale + Person::players[1]->coords; + if (Person::players[1]->skeleton.free) + temp = Person::players[1]->skeleton.joints[i].position * Person::players[1]->scale + Person::players[1]->coords; + Sprite::MakeSprite(breathsprite, temp, temp2, 1, 1, 1, .6 + (float)abs(Random() % 100) / 200 - .25, 1); + } + } + } + } +} diff --git a/Source/Tutorial.hpp b/Source/Tutorial.hpp new file mode 100644 index 0000000..827ea58 --- /dev/null +++ b/Source/Tutorial.hpp @@ -0,0 +1,40 @@ +/* +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 . +*/ + +#ifndef _TUTORIAL_HPP_ +#define _TUTORIAL_HPP_ + +class Tutorial +{ +public: + static bool active; + static int stage; + static float stagetime; + static float maxtime; + + static void Do(float multiplier); + static void DrawText(); + static void DoStuff(float multiplier); + +private: + static float success; +}; + +#endif