| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589 |
- /*
- * Copyright (C) 2022 The V-Gears Team
- *
- * This file is part of V-Gears
- *
- * V-Gears is free software: you can redistribute it and/or modify it under
- * terms of the GNU General Public License as published by the Free Software
- * Foundation, version 3.0 (GPLv3) of the License.
- *
- * V-Gears 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.
- */
- #include <iostream>
- #include <cmath>
- #include <limits>
- #include <OgreEntity.h>
- #include <OgreRoot.h>
- #include <OgreViewport.h>
- #include "core/CameraManager.h"
- #include "core/ConfigVar.h"
- #include "core/DebugDraw.h"
- #include "core/EntityManager.h"
- #include "core/EntityModel.h"
- #include "core/InputManager.h"
- #include "core/Logger.h"
- #include "core/ScriptManager.h"
- #include "core/Timer.h"
- #include "core/DialogsManager.h"
- /**
- * Entity manager singleton.
- */
- template<>EntityManager *Ogre::Singleton<EntityManager>::msSingleton = nullptr;
- ConfigVar cv_debug_grid("debug_grid", "Draw debug grid", "false");
- ConfigVar cv_debug_axis("debug_axis", "Draw debug axis", "false");
- const float EntityManager::SCENE_SCALE = 0.003f;
- const unsigned int EntityManager::BATTLE_BACKGROUND_ID = 1000;
- const unsigned int EntityManager::WORLD_MAP_BACKGROUND_ID = 1001;
- float EntityManager::PointElevation(
- const Ogre::Vector2& point, const Ogre::Vector3& a, const Ogre::Vector3& b, const Ogre::Vector3& c
- ){
- float _a = a.z * (b.y - c.y) + b.z * (c.y - a.y) + c.z * (a.y - b.y);
- float _b = a.y * (b.x - c.x) + b.y * (c.x - a.x) + c.y * (a.x - b.x);
- float _c = a.x * (b.z - c.z) + b.x * (c.z - a.z) + c.x * (a.z - b.z);
- float _d
- = a.x * (b.z * c.y - c.z * b.y) + b.x * (c.z * a.y - a.z * c.y)
- + c.x * (a.z * b.y - b.z * a.y);
- return (_d - _c * point.y - _a * point.x) / _b;
- }
- float EntityManager::SideOfVector(
- const Ogre::Vector2& point, const Ogre::Vector2& p1, const Ogre::Vector2& p2
- ){
- Ogre::Vector2 AB = p2 - p1;
- Ogre::Vector2 AP = point - p1;
- return AB.x * AP.y - AB.y * AP.x;
- }
- float EntityManager::SquareDistanceToLine(
- const Ogre::Vector3& point, const Ogre::Vector3& point_a, const Ogre::Vector3& point_b,
- Ogre::Vector3& proj
- ){
- float temp =
- -((point_a.x - point.x) * (point_b.x - point_a.x) + (point_a.y - point.y)
- * (point_b.y - point_a.y) + (point_a.z - point.z) * (point_b.z - point_a.z))
- / ((point_b.x - point_a.x) * (point_b.x - point_a.x) + (point_b.y - point_a.y)
- * (point_b.y - point_a.y) + (point_b.z - point_a.z) * (point_b.z - point_a.z));
- proj.x = temp * (point_b.x - point_a.x) + point_a.x;
- proj.y = temp * (point_b.y - point_a.y) + point_a.y;
- proj.z = temp * (point_b.z - point_a.z) + point_a.z;
- if (
- ((point_a.x >= proj.x && point_b.x <= proj.x) || (point_a.x < proj.x && point_b.x >= proj.x))
- && (
- (point_a.y >= proj.y && point_b.y <= proj.y) || (point_a.y < proj.y && point_b.y >= proj.y)
- )
- ){
- return (proj.x - point.x) * (proj.x - point.x) + (proj.y - point.y)
- * (proj.y - point.y) + (proj.z - point.z) * (proj.z - point.z);
- }
- return -1;
- }
- Ogre::Degree EntityManager::GetDirectionToPoint(
- const Ogre::Vector3& current_point, const Ogre::Vector3& direction_point
- ){
- // TODO: Declare function in header file.
- Ogre::Vector2 up(0.0f, -1.0f);
- Ogre::Vector2 dir(direction_point.x - current_point.x, direction_point.y - current_point.y);
- // Angle between vectors
- Ogre::Degree angle(Ogre::Radian(acosf(dir.dotProduct(up) / (dir.length() * up.length()))));
- return (dir.x < 0) ? Ogre::Degree(360) - angle : angle;
- }
- EntityManager::EntityManager():
- background_3d_(nullptr),
- player_entity_(nullptr),
- player_move_(Ogre::Vector3::ZERO),
- player_move_rotation_(0),
- player_lock_(false),
- player_run_(false),
- random_encounters_(false),
- encounter_rate_(0)
- {
- LOG_TRIVIAL("EntityManager created.");
- scene_node_ = Ogre::Root::getSingleton().getSceneManager("Scene")
- ->getRootSceneNode()->createChildSceneNode("EntityManager");
- //grid_ = Ogre::Root::getSingleton().getSceneManager("Scene")
- // ->createEntity("Grid", "system/grid.mesh");
- grid_ = Ogre::Root::getSingleton().getSceneManager("Scene")->createEntity("Grid", "grid.mesh");
- scene_node_->attachObject(grid_);
- //axis_ = Ogre::Root::getSingleton().getSceneManager("Scene")
- // ->createEntity("Axis", "system/axis.mesh");
- axis_ = Ogre::Root::getSingleton().getSceneManager("Scene")->createEntity("Axis", "axis.mesh");
- scene_node_->attachObject(axis_);
- }
- EntityManager::~EntityManager(){
- if (grid_ != nullptr) Ogre::Root::getSingleton().getSceneManager("Scene")->destroyEntity(grid_);
- if (axis_ != nullptr) Ogre::Root::getSingleton().getSceneManager("Scene")->destroyEntity(axis_);
- Clear();
- Ogre::Root::getSingleton().getSceneManager("Scene")->getRootSceneNode()->removeAndDestroyChild(
- "EntityManager"
- );
- LOG_TRIVIAL("EntityManager destroyed.");
- }
- void EntityManager::Input(const VGears::Event& event){
- background_2d_.InputDebug(event);
- if (paused_ == true) return;
- if (player_entity_ != NULL && player_lock_ == false){
- if (event.type == VGears::ET_KEY_REPEAT && event.event == "walk_left") player_move_.x = -1;
- else if (event.type == VGears::ET_KEY_REPEAT && event.event == "walk_right")
- player_move_.x = 1;
- if (event.type == VGears::ET_KEY_REPEAT && event.event == "walk_down") player_move_.y = -1;
- else if (event.type == VGears::ET_KEY_REPEAT && event.event == "walk_up")
- player_move_.y = 1;
- if (event.type == VGears::ET_KEY_REPEAT && event.event == "run") player_run_ = true;
- if (event.type == VGears::ET_KEY_PRESS && event.event == "CONFIRM"){
- CheckEntityInteract();
- for (unsigned int i = 0; i < entity_triggers_.size(); ++ i){
- if (
- entity_triggers_[i]->IsEnabled() == true
- && entity_triggers_[i]->CheckApproached() == true
- ){
- ScriptEntity* scr_entity = ScriptManager::getSingleton().GetScriptEntityByName(
- ScriptManager::ENTITY, entity_triggers_[i]->GetName()
- );
- bool added = ScriptManager::getSingleton().ScriptRequest(
- scr_entity, "on_interact", 1, "", "", false, false
- );
- if (added == false){
- LOG_WARNING(
- "Script 'on_interact' for entity '" + entity_triggers_[i]->GetName()
- + "' doesn't exist."
- );
- }
- }
- }
- }
- // Rotate move vector to field move rotation
- Ogre::Quaternion q1;
- q1.FromAngleAxis(player_move_rotation_, Ogre::Vector3::UNIT_Z);
- player_move_ = q1 * player_move_;
- }
- }
- void EntityManager::UpdateField(){
- // Update all entity scripts
- ScriptManager::getSingleton().Update(ScriptManager::ENTITY);
- // Set move point for player entity
- if (player_entity_ != nullptr && player_move_ != Ogre::Vector3::ZERO){
- Entity::State state = player_entity_->GetState();
- if (state == Entity::WALKMESH || state == Entity::NONE){
- player_move_
- *= player_entity_->GetMoveWalkSpeed() * Timer::getSingleton().GetGameTimeDelta();
- player_entity_->SetMovePosition(player_entity_->GetPosition() + player_move_);
- player_entity_->SetState(Entity::WALKMESH);
- }
- // HACK: If manually moving, make playable entity solid.
- // Some scripts 'forget' to make the playable entity solid at the end
- // of them, and if it remains non-solid, it can't interact with lines
- // (i.e. it cant' use gateways).
- player_entity_->SetSolid(true);
- }
- for (unsigned int i = 0; i < entity_.size(); ++ i){
- entity_[i]->Update();
- // It's not needed to update movements it delta time == 0 (for example
- // if time is stopped)
- if (Timer::getSingleton().GetGameTimeDelta() == 0) continue;
- // Update screen scroll.
- Entity* scroll_entity = background_2d_.GetAutoScrollEntity();
- if (scroll_entity == entity_[i])
- background_2d_.SetScroll(background_2d_.GetEntityScroll(scroll_entity));
- // Update offset.
- if (entity_[i]->GetOffsetType() != AT_NONE) SetNextOffsetStep(entity_[i]);
- // Update turn.
- if (entity_[i]->GetTurnType() != AT_NONE) SetNextTurnStep(entity_[i]);
- // Update movement.
- switch(entity_[i]->GetState()){
- case Entity::WALKMESH:
- {
- // Try set entity on walkmesh if it's still don't has triangle.
- if (entity_[i]->GetMoveTriangleId() == -1){
- if (SetEntityOnWalkmesh(entity_[i]) == false){
- LOG_TRIVIAL(
- "Can't set entity '" + entity_[i]->GetName()
- + "' on walkmesh. Finish move."
- );
- entity_[i]->UnsetMove();
- }
- }
- // Perform move
- if (entity_[i]->GetState() == Entity::WALKMESH){
- float speed = 0;
- if (player_lock_ == false && player_entity_ == entity_[i]){
- speed = entity_[i]->GetMoveWalkSpeed();
- // TODO: Set as a constant.
- // Or even better, as a configurable variable.
- if (player_run_ == true) speed *= 4;
- }
- else speed = entity_[i]->GetMoveAutoSpeed();
- float remaining_time = Timer::getSingleton().GetGameTimeDelta();
- bool is_move = false;
- if (entity_[i]->IsScriptedMove() && speed > 0.0f){
- const float max_step_time = 0.2f / speed;
- while (remaining_time > 0.0f && entity_[i]->GetState() == Entity::WALKMESH){
- const float step_time = std::min(remaining_time, max_step_time);
- const bool moved = PerformWalkmeshMove(entity_[i], speed, step_time);
- is_move = is_move || moved;
- if (!moved) break;
- remaining_time -= step_time;
- }
- }
- else is_move = PerformWalkmeshMove(entity_[i], speed, remaining_time);
- if (entity_[i]->GetMoveAutoAnimation() == true){
- if (is_move == true){
- if (speed >= entity_[i]->GetMoveRunSpeed()){
- entity_[i]->PlayAnimationContinue(
- entity_[i]->GetMoveAnimationRunName()
- );
- }
- else{
- entity_[i]->PlayAnimationContinue(
- entity_[i]->GetMoveAnimationWalkName()
- );
- }
- }
- else if (
- entity_[i]->GetAnimationState() != Entity::REQUESTED_ANIMATION
- ){
- entity_[i]->PlayAnimationContinue(
- entity_[i]->GetDefaultAnimationName()
- );
- }
- }
- }
- }
- break;
- case Entity::LINEAR:
- CheckTriggers(entity_[i], entity_[i]->GetPosition());
- SetNextLinearStep(entity_[i]);
- break;
- case Entity::JUMP:
- SetNextJumpStep(entity_[i]);
- break;
- case Entity::NEEDS_TO_REATTACH:
- if (SetEntityOnWalkmesh(entity_[i])) entity_[i]->SetState(Entity::WALKMESH);
- else entity_[i]->SetState(Entity::NONE);
- case Entity::NONE:
- CheckTriggers(entity_[i], entity_[i]->GetPosition());
- if (entity_[i]->GetAnimationState() != Entity::REQUESTED_ANIMATION)
- entity_[i]->PlayAnimationContinue(entity_[i]->GetDefaultAnimationName());
- break;
- }
- }
- // Reset player move. It already must be handled in update
- player_move_ = Ogre::Vector3::ZERO;
- player_run_ = false;
- if (background_2d_.GetScrollType() != Background2D::NONE) SetNextScrollStep();
- background_2d_.Update();
- screen_fade_.Update(Timer::getSingleton().GetGameTimeDelta());
- }
- void EntityManager::UpdateBattle(){
- ScriptManager::getSingleton().Update(ScriptManager::BATTLE);
- if (background_3d_ != nullptr){
- background_3d_->Update();
- background_3d_->PlayAnimationContinue(background_3d_->GetDefaultAnimationName());
- }
- for (unsigned int i = 0; i < battle_entity_.size(); ++ i){
- battle_entity_[i]->Update();
- battle_entity_[i]->PlayAnimationContinue(battle_entity_[i]->GetDefaultAnimationName());
- }
- //CameraManager::getSingleton().GetCurrentCamera()->roll(Ogre::Radian(0.01));
- }
- void EntityManager::UpdateWorld(){
- ScriptManager::getSingleton().Update(ScriptManager::ENTITY);
- for (Entity* entity : entity_){
- entity->Update();
- }
- player_move_ = Ogre::Vector3::ZERO;
- player_run_ = false;
- }
- void EntityManager::AddFieldOrWorldMapEntity(
- const Ogre::String& name, const Ogre::String& file_name, const Ogre::Vector3& position,
- const Ogre::Degree& rotation, const Ogre::Vector3& scale,
- const Ogre::Quaternion& root_orientation, const int index
- ){
- if (module_ != Module::FIELD){
- LOG_ERROR("Tried to add field or world Entity but the EntityManager is in battle mode.");
- return;
- }
- Ogre::SceneNode* node = scene_node_->createChildSceneNode("Model_" + name);
- EntityModel* entity = new EntityModel(name, file_name, node);
- entity->SetPosition(position);
- entity->SetRotation(rotation);
- entity->setScale(scale);
- entity->SetIndex(index);
- entity->setRootOrientation(root_orientation);
- entity_.push_back(entity);
- ScriptManager::getSingleton().AddEntity(ScriptManager::ENTITY, entity->GetName(), entity);
- }
- EntityModel* EntityManager::AddWorldMapEntity(
- const Ogre::String& name, const Ogre::String& file_name,
- const Ogre::Vector3& position, const Ogre::Degree& rotation,
- const Ogre::Vector3& scale, const Ogre::String& resource_group
- ){
- if (!IsWorldModule()){
- LOG_ERROR("Tried to add a world-map entity outside world-map mode.");
- return nullptr;
- }
- if (GetEntity(name) != nullptr){
- LOG_ERROR("Tried to add duplicate world-map entity '" + name + "'.");
- return nullptr;
- }
- Ogre::SceneNode* node = scene_node_->createChildSceneNode("Model_" + name);
- EntityModel* entity = new EntityModel(name, file_name, node, resource_group);
- entity->SetPosition(position);
- entity->SetRotation(rotation);
- entity->setScale(scale);
- entity->SetVisible(true);
- entity_.push_back(entity);
- ScriptManager::getSingleton().AddEntity(ScriptManager::ENTITY, entity->GetName(), entity);
- return entity;
- }
- void EntityManager::AddBattleEntity(
- const Ogre::String& name, const Ogre::String& file_name, const Ogre::Vector3& position,
- const Ogre::Degree& rotation, const Ogre::Vector3& scale,
- const Ogre::Quaternion& root_orientation, const int index
- ){
- if (module_ != Module::BATTLE){
- LOG_ERROR("Tried to add battle Entity but the EntityManager is not in battle mode.");
- return;
- }
- Ogre::SceneNode* node = scene_node_->createChildSceneNode("Battle_" + name);
- // Battle models must be reoriented.
- node->setOrientation(root_orientation);
- EntityModel* entity = new EntityModel(name, file_name, node);
- entity->SetPosition(position);
- entity->SetRotation(rotation);
- entity->setScale(scale);
- entity->SetIndex(index);
- entity->SetVisible(true);
- battle_entity_.push_back(entity);
- ScriptManager::getSingleton().AddEntity(ScriptManager::BATTLE, entity->GetName(), entity);
- /*std::cout << "BATTLE ANIMATIONS FOR " << name << std::endl;
- const std::map<Ogre::String, Ogre::AnimationState*>& anims
- = entity->GetModel()->getAllAnimationStates()->getAnimationStates();
- int size = anims.size();
- std::cout << " " << std::to_string(size) << " TOTAL " << std::endl;
- for (auto anim = anims.begin(); anim != anims.end(); ++ anim){
- std::cout << " - " << anim->first << ", " << anim->second << std::endl;
- }*/
- /* Animations have the following names:
- * XX_00,
- * XX_01,
- * XX_02,
- * ...
- * where XX is the first two characters of file_name, without the path.
- */
- Ogre::String anim = file_name.substr(file_name.find_last_of("/\\") + 1).substr(0, 2) + "_00";
- //std::cout << " Playing " << anim << std::endl;
- entity->ScriptSetDefaultAnimation(anim.c_str());
- }
- Entity* EntityManager::GetBackground3D() const{
- if (IsFieldModule()){
- LOG_WARNING("Tried to retrieve a 3D background while the EntityManager is in field mode.");
- return nullptr;
- }
- return background_3d_;
- }
- void EntityManager::SetBackground3D(const Ogre::String& name, const Ogre::String& file_name){
- if (IsFieldModule()){
- LOG_ERROR("Tried to add a 3D background while the EntityManager is in field mode.");
- return;
- }
- Ogre::SceneNode* node = scene_node_->createChildSceneNode("bg_" + name);
- background_3d_ = new EntityModel(name, file_name, node);
- background_3d_->SetPosition(Ogre::Vector3(0, 0, 0));
- background_3d_->SetRotation(Ogre::Degree(0));
- background_3d_->setScale(Ogre::Vector3(SCENE_SCALE, SCENE_SCALE, SCENE_SCALE));
- background_3d_->SetIndex(IsBattleModule() ? BATTLE_BACKGROUND_ID : WORLD_MAP_BACKGROUND_ID);
- background_3d_->SetVisible(true);
- // Backgrounds must be reoriented.
- node->setOrientation(1, 1, 0, 0);
- // Probably don't need a script for the 3d background.
- /*ScriptManager::getSingleton().AddEntity(
- ScriptManager::BATTLE, background_3d_->GetName(), background_3d_
- );*/
- }
- void EntityManager::UpdateDebug(){
- grid_->setVisible(cv_debug_grid.GetB());
- axis_->setVisible(cv_debug_axis.GetB());
- if (module_ == Module::BATTLE){
- if (background_3d_ != nullptr) background_3d_->UpdateDebug();
- for (unsigned int i = 0; i < battle_entity_.size(); ++ i) battle_entity_[i]->UpdateDebug();
- }
- else{
- for (unsigned int i = 0; i < entity_.size(); ++ i) entity_[i]->UpdateDebug();
- for (unsigned int i = 0; i < entity_triggers_.size(); ++ i)
- entity_triggers_[i]->UpdateDebug();
- for (unsigned int i = 0; i < entity_points_.size(); ++ i) entity_points_[i]->UpdateDebug();
- walkmesh_.UpdateDebug();
- background_2d_.UpdateDebug();
- }
- }
- void EntityManager::OnResize(){background_2d_.OnResize();}
- void EntityManager::ClearField(){
- walkmesh_.Clear();
- background_2d_.Clear();
- screen_fade_.Clear();
- DialogsManager::getSingleton().Clear();
- for (unsigned int i = 0; i < entity_.size(); ++ i){
- ScriptManager::getSingleton().RemoveEntity(ScriptManager::ENTITY, entity_[i]->GetName());
- delete entity_[i];
- }
- entity_.clear();
- player_entity_ = nullptr;
- player_move_ = Ogre::Vector3::ZERO;
- player_move_rotation_ = 0;
- player_lock_ = false;
- for (unsigned int i = 0; i < entity_triggers_.size(); ++ i){
- ScriptManager::getSingleton().RemoveEntity(
- ScriptManager::ENTITY, entity_triggers_[i]->GetName()
- );
- delete entity_triggers_[i];
- }
- entity_triggers_.clear();
- for (unsigned int i = 0; i < entity_points_.size(); ++ i) delete entity_points_[i];
- entity_points_.clear();
- for (unsigned int i = 0; i < entity_scripts_.size(); ++ i)
- ScriptManager::getSingleton().RemoveEntity(ScriptManager::ENTITY, entity_scripts_[i]);
- scene_node_->removeAndDestroyAllChildren();
- }
- void EntityManager::ClearBattle(){
- for (unsigned int i = 0; i < battle_entity_.size(); ++ i){
- ScriptManager::getSingleton().RemoveEntity(
- ScriptManager::ENTITY, battle_entity_[i]->GetName()
- );
- Ogre::Root::getSingleton().getSceneManager("Scene")->destroyEntity(
- battle_entity_[i]->GetName()
- );
- scene_node_->removeAndDestroyChild("Battle_" + battle_entity_[i]->GetName());
- }
- battle_entity_.clear();
- if (background_3d_ != nullptr){
- Ogre::Root::getSingleton().getSceneManager("Scene")->destroyEntity(
- "bg_" + background_3d_->GetName()
- );
- /*ScriptManager::getSingleton().RemoveEntity(
- ScriptManager::ENTITY, background_3d_->GetName()
- );*/
- scene_node_->getChild("bg_" + background_3d_->GetName())->removeAllChildren();
- scene_node_->removeAndDestroyChild("bg_" + background_3d_->GetName());
- Ogre::Root::getSingleton().getSceneManager("Scene")->destroyEntity(
- background_3d_->GetName()
- );
- background_3d_ = nullptr;
- }
- }
- void EntityManager::ClearWorld(){
- walkmesh_.Clear();
- for (Entity* entity : entity_){
- ScriptManager::getSingleton().RemoveEntity(ScriptManager::ENTITY, entity->GetName());
- delete entity;
- }
- entity_.clear();
- player_entity_ = nullptr;
- player_move_ = Ogre::Vector3::ZERO;
- player_move_rotation_ = 0;
- player_lock_ = false;
- player_run_ = false;
- for (EntityTrigger* trigger : entity_triggers_){
- ScriptManager::getSingleton().RemoveEntity(ScriptManager::ENTITY, trigger->GetName());
- delete trigger;
- }
- entity_triggers_.clear();
- for (EntityPoint* point : entity_points_) delete point;
- entity_points_.clear();
- for (const Ogre::String& script : entity_scripts_){
- ScriptManager::getSingleton().RemoveEntity(ScriptManager::ENTITY, script);
- }
- entity_scripts_.clear();
- scene_node_->removeAndDestroyAllChildren();
- }
- Walkmesh* EntityManager::GetWalkmesh(){return &walkmesh_;}
- bool EntityManager::IsWorldPositionBlocked(
- const Entity* moving_entity, const Ogre::Vector3& position
- ) const{
- if (!IsWorldModule() || moving_entity == nullptr) return false;
- for (const Entity* other : entity_){
- if (other == moving_entity || !other->IsSolid()) continue;
- const Ogre::Vector3 other_position = other->GetPosition();
- const Ogre::Real dx = position.x - other_position.x;
- const Ogre::Real dz = position.z - other_position.z;
- const Ogre::Real radius = moving_entity->GetSolidRadius() + other->GetSolidRadius();
- if (dx * dx + dz * dz >= radius * radius) continue;
- const Ogre::Real moving_top = position.y + moving_entity->GetHeight();
- const Ogre::Real other_top = other_position.y + other->GetHeight();
- if (position.y < other_top && other_position.y < moving_top) return true;
- }
- return false;
- }
- Background2D* EntityManager::GetBackground2D(){return &background_2d_;}
- ScreenFade* EntityManager::GetScreenFade(){return &screen_fade_;}
- void EntityManager::AddEntity(
- const Ogre::String& name, const Ogre::String& file_name,
- const Ogre::Vector3& position, const Ogre::Degree& rotation, int index
- ){
- AddEntity(
- name, file_name, position, rotation,
- Ogre::Vector3::UNIT_SCALE, Ogre::Quaternion::IDENTITY, index
- );
- }
- void EntityManager::AddEntity(
- const Ogre::String& name, const Ogre::String& file_name, const Ogre::Vector3& position,
- const Ogre::Degree& rotation, const Ogre::Vector3& scale,
- const Ogre::Quaternion& root_orientation, const int index
- ){
- if (IsBattleModule())
- AddBattleEntity(name, file_name, position, rotation, scale, root_orientation, index);
- else
- AddFieldOrWorldMapEntity(
- name, file_name, position, rotation, scale, root_orientation, index
- );
- }
- void EntityManager::ScriptAddEntity(
- const char* name, const char* file_name,
- const float x, const float y, const float z, const float rotation, int index
- ){AddEntity(name, file_name, Ogre::Vector3(x, y, z), Ogre::Degree(rotation), index);}
- void EntityManager::AddEntityTrigger(
- const Ogre::String& name,
- const Ogre::Vector3& point1, const Ogre::Vector3& point2, const bool enabled
- ){
- if (IsBattleModule()){
- LOG_WARNING("Tried to add an entity trigger but the EntityManager is in battle mode.");
- return;
- }
- EntityTrigger* trigger = new EntityTrigger(name);
- trigger->SetPoints(point1, point2);
- trigger->SetEnabled(enabled);
- entity_triggers_.push_back(trigger);
- ScriptManager::getSingleton().AddEntity(ScriptManager::ENTITY, trigger->GetName(), nullptr);
- }
- void EntityManager::AddEntityPoint(
- const Ogre::String& name, const Ogre::Vector3& position, const float rotation
- ){
- if (IsBattleModule()){
- LOG_WARNING("Tried to add an entity point but the EntityManager is in battle mode.");
- return;
- }
- EntityPoint* entity_point = new EntityPoint(name);
- entity_point->SetPosition(position);
- entity_point->SetRotation(rotation);
- entity_points_.push_back(entity_point);
- }
- void EntityManager::AddEntityScript(const Ogre::String& name){
- // TODO: Should call to this be prevented while in battle mode?
- entity_scripts_.push_back(name);
- ScriptManager::getSingleton().AddEntity(ScriptManager::ENTITY, name, nullptr);
- }
- void EntityManager::ScriptAddEntityScript(const char* name){AddEntityScript(name);}
- Entity* EntityManager::GetEntity(const Ogre::String& name) const{
- if (IsBattleModule()){
- for (unsigned int i = 0; i < battle_entity_.size(); ++ i)
- if (battle_entity_[i]->GetName() == name) return battle_entity_[i];
- }
- else{
- for (unsigned int i = 0; i < entity_.size(); ++ i)
- if (entity_[i]->GetName() == name) return entity_[i];
- }
- return nullptr;
- }
- Entity* EntityManager::GetEntityFromIndex(const int index) const{
- if (IsBattleModule()){
- if (background_3d_ != nullptr && background_3d_->GetIndex() == index)
- return background_3d_;
- for (unsigned int i = 0; i < battle_entity_.size(); ++ i)
- if (battle_entity_[i]->GetIndex() == index) return battle_entity_[i];
- }
- else{
- for (unsigned int i = 0; i < entity_.size(); ++ i)
- if (entity_[i]->GetIndex() == index) return entity_[i];
- }
- return nullptr;
- }
- Entity* EntityManager::GetEntityFromCharacterId(const int id) const{
- if (IsBattleModule()){
- for (unsigned int i = 0; i < battle_entity_.size(); ++ i)
- if (battle_entity_[i]->IsCharacter() && battle_entity_[i]->GetCharacterId() == id)
- return battle_entity_[i];
- }
- else{
- for (unsigned int i = 0; i < entity_.size(); ++ i)
- if (entity_[i]->IsCharacter() && entity_[i]->GetCharacterId() == id) return entity_[i];
- }
- return nullptr;
- }
- Entity* EntityManager::ScriptGetEntity(const char* name) const{
- return GetEntity(Ogre::String(name));
- }
- EntityPoint* EntityManager::ScriptGetEntityPoint(const char* name) const{
- for (unsigned int i = 0; i < entity_points_.size(); ++ i)
- if (entity_points_[i]->GetName() == name) return entity_points_[i];
- return nullptr;
- }
- void EntityManager::ScriptSetPlayerEntity(const char* name){
- if (IsBattleModule()){
- LOG_WARNING("Tried to set a player entity but the EntityManager is in battle mode.");
- return;
- }
- for (unsigned int i = 0; i < entity_.size(); ++ i){
- if (entity_[i]->GetName() == name){
- player_entity_ = entity_[i];
- // Also, make is solid, visible, and non-talkable.
- entity_[i]->SetSolid(true);
- entity_[i]->SetVisible(true);
- entity_[i]->SetTalkable(false);
- }
- }
- }
- void EntityManager::ScriptPlacePlayerAtFieldEntry(
- const float x, const float y, const int triangle_id, const float direction
- ){
- if (player_entity_ == nullptr || walkmesh_.GetNumberOfTriangles() <= 0) return;
- int safe_triangle_id = triangle_id;
- if (safe_triangle_id < 0 || safe_triangle_id >= walkmesh_.GetNumberOfTriangles()){
- LOG_WARNING("World-map field entry has an invalid walkmesh triangle; using triangle 0.");
- safe_triangle_id = 0;
- }
- player_entity_->SetPosition(Ogre::Vector3(
- x, y, walkmesh_.GetA(static_cast<unsigned int>(safe_triangle_id)).z
- ));
- player_entity_->SetRotation(Ogre::Degree(direction));
- player_entity_->SetMoveTriangleId(safe_triangle_id);
- player_entity_->SetState(Entity::WALKMESH);
- }
- Entity* EntityManager::ScriptGetPlayerEntity() const{
- if (IsBattleModule()){
- LOG_WARNING("Tried to set a player entity but the EntityManager is in battle mode.");
- return nullptr;
- }
- return player_entity_;
- }
- void EntityManager::ScriptUnsetPlayerEntity(){
- if (IsBattleModule()){
- LOG_WARNING("Tried to unset a player entity but the EntityManager is in battle mode.");
- return;
- }
- player_entity_ = nullptr;
- }
- void EntityManager::ScriptPlayerLock(const bool lock){
- if (IsBattleModule()){
- LOG_WARNING("Tried to set player lock but the EntityManager is in battle mode.");
- return;
- }
- player_lock_ = lock;
- if (lock == true) player_move_ = Ogre::Vector3::ZERO;
- }
- void EntityManager::SetPlayerMoveRotation(const Ogre::Radian rotation){
- if (IsBattleModule()){
- LOG_WARNING("Tried to set player move rotation the EntityManager is in battle mode.");
- return;
- }
- player_move_rotation_ = rotation;
- }
- bool EntityManager::GetRandomEncounters(){return random_encounters_;}
- void EntityManager::SetRandomEncounters(bool active){random_encounters_ = active;}
- float EntityManager::GetEncounterRate(){return encounter_rate_;}
- void EntityManager::SetEncounterRate(float rate){
- if (rate >= 1.0f) encounter_rate_ = 1.0f;
- else if (rate <= 0.0f) encounter_rate_ = 0.0f;
- else encounter_rate_ = rate;
- }
- bool EntityManager::IsKeyOn(unsigned int key_code){
- // If the player is locked, always false.
- // TODO: Maybe this will interfere with something down the road?
- // Some scene where the player can't move but must press a button?
- if (player_lock_) return false;
- // The key code of the scripts is a mask of the pad buttons, and the check is true if any of
- // them is pressed. Translate each to its key. For example 32 is "Circle/Action", the space bar.
- // TODO: Get values from config.lua
- static const struct{unsigned int mask; int key;} KEYS[] = {
- {4, OIS::KC_PGUP}, {8, OIS::KC_PGDOWN}, {32, OIS::KC_SPACE}, {64, OIS::KC_ESCAPE},
- {4096, OIS::KC_UP}, {8192, OIS::KC_RIGHT}, {16384, OIS::KC_DOWN}, {32768, OIS::KC_LEFT}
- };
- for (const auto& entry : KEYS)
- if ((key_code & entry.mask) && InputManager::getSingleton().IsButtonPressed(entry.key))
- return true;
- return false;
- }
- bool EntityManager::IsKeyOff(unsigned int key_code){return !IsKeyOn(key_code);}
- void EntityManager::SetEntityToCharacter(const char* entity_name, unsigned int char_id){
- if (IsBattleModule()){
- for (unsigned int i = 0; i < battle_entity_.size(); ++ i){
- if (battle_entity_[i]->GetName() == entity_name){
- battle_entity_[i]->SetCharacter(char_id);
- return;
- }
- }
- }
- else{
- for (unsigned int i = 0; i < entity_.size(); ++ i){
- if (entity_[i]->GetName() == entity_name){
- entity_[i]->SetCharacter(char_id);
- return;
- }
- }
- }
- LOG_WARNING(
- "Unabe to assigne character ID " + std::to_string(char_id) + " to entity '" + entity_name
- + "'. No entity by that name exists."
- );
- }
- bool EntityManager::SetEntityOnWalkmesh(Entity* entity){
- if (IsBattleModule()){
- LOG_WARNING("Tried to set entity on the walkmesh, but the EntityManager is in battle mode");
- return false;
- }
- Ogre::Vector3 position3 = entity->GetPosition();
- Ogre::Vector2 position2;
- position2.x = position3.x;
- position2.y = position3.y;
- std::vector<std::pair<int, float>> triangles;
- // Search for possible triangles.
- for (int i = 0; i < walkmesh_.GetNumberOfTriangles(); ++ i){
- Ogre::Vector3 A3 = walkmesh_.GetA(i);
- Ogre::Vector3 B3 = walkmesh_.GetB(i);
- Ogre::Vector3 C3 = walkmesh_.GetC(i);
- Ogre::Vector2 A2(A3.x, A3.y);
- Ogre::Vector2 B2(B3.x, B3.y);
- Ogre::Vector2 C2(C3.x, C3.y);
- if (Ogre::Math::pointInTri2D(position2, A2, B2, C2) == true){
- triangles.push_back(std::make_pair(i, PointElevation(
- position2, walkmesh_.GetA(i), walkmesh_.GetB(i), walkmesh_.GetC(i)
- )));
- }
- }
- // If the coordinates doesn't match any triangle, exit.
- if (triangles.size() == 0 && entity == player_entity_){
- LOG_ERROR(
- "Can't find any triangle to place entity '" + entity->GetName() + "' on walkmesh."
- );
- return false;
- }
- // From the possible triangles, select the closest one (on the Z edge).
- int closest_z_triangle = -1;
- float closest_z_distance = 9999.0f;
- float pos_z = position3.z;
- for (size_t i = 0; i < triangles.size(); ++ i){
- if (std::abs(pos_z - triangles[i].second) < closest_z_distance){
- closest_z_triangle = triangles[i].first;
- closest_z_distance = std::abs(pos_z - triangles[i].second);
- }
- }
- if (closest_z_triangle == -1 && entity == player_entity_){
- LOG_ERROR(
- "Can't find nearby triangle to place entity '" + entity->GetName() + "' on walkmesh."
- );
- return false;
- }
- entity->SetPosition(Ogre::Vector3(position2.x, position2.y, pos_z));
- entity->SetMoveTriangleId(closest_z_triangle);
- return true;
- }
- float EntityManager::TriggerReach(float solid_radius){
- // The radius an entity has when a script doesn't change it.
- const float default_radius = 0.21f;
- return solid_radius < 0.01f ? default_radius : solid_radius;
- }
- bool EntityManager::WalkmeshEdgeBlocks(bool is_player, bool scripted_move){
- return is_player || !scripted_move;
- }
- bool EntityManager::IsBetterInteractionTarget(
- float angle, float distance, float best_angle, float best_distance
- ){
- const float same_angle = 0.001f;
- if (angle < best_angle - same_angle) return true;
- return std::fabs(angle - best_angle) <= same_angle && distance < best_distance;
- }
- float EntityManager::ScriptedMoveStep(float distance, float stop_distance, float max_step){
- return std::min(max_step, std::max(0.0f, distance - stop_distance));
- }
- bool EntityManager::PerformWalkmeshMove(Entity* entity, const float speed, const float delta_time){
- if (IsBattleModule()){
- LOG_WARNING("Tried to perform a walkmesh move, but the EntityManager is in battle mode");
- return false;
- }
- Ogre::Vector3 start_point = entity->GetPosition();
- Ogre::Vector3 move_vector = entity->GetMovePosition() - start_point;
- Ogre::Vector2 direction(move_vector.x, move_vector.y);
- const float distance_to_target = direction.length();
- const bool scripted_move = entity->IsScriptedMove();
- const float stop_distance = entity->GetMoveStopDistance();
- if (scripted_move && distance_to_target <= stop_distance + 0.0001f){
- entity->UnsetMove();
- return false;
- }
- direction.normalise();
- direction *= delta_time;
- direction *= speed;
- if (scripted_move && !direction.isZeroLength()){
- direction.normalise();
- direction *= ScriptedMoveStep(
- distance_to_target, stop_distance, speed * delta_time
- );
- }
- // If movement is still needed but speed or time don't allow it, just return for now.
- if (direction.isZeroLength() == true){
- if (player_entity_ == entity) CheckTriggers(entity, entity->GetPosition());
- return false;
- }
- int current_triangle = entity->GetMoveTriangleId();
- if (current_triangle == -1){
- LOG_ERROR("Entity '" + entity->GetName() + "' not placed on walkmesh and can't move.");
- return false;
- }
- Ogre::Vector3 rotation(0.0f, 0.0f, 0.0f);
- Ogre::Quaternion q1(0.0f, 0.0f, 0.0f, 1.0f);
- Ogre::Vector3 end_point(0.0f, 0.0f, 0.0f);
- Ogre::Vector3 end_point2(0.0f, 0.0f, 0.0f);
- bool first_triangle_check = false;
- bool second_triangle_check = false;
- bool third_triangle_check = false;
- bool last_triangle_check = false;
- bool first_entity_check = false;
- bool second_entity_check = false;
- bool third_entity_check = false;
- // Shorten move vector by triangle angle
- end_point.x = start_point.x + direction.x;
- end_point.y = start_point.y + direction.y;
- Ogre::Vector3 A3 = walkmesh_.GetA(current_triangle);
- Ogre::Vector3 B3 = walkmesh_.GetB(current_triangle);
- Ogre::Vector3 C3 = walkmesh_.GetC(current_triangle);
- end_point.z = PointElevation(Ogre::Vector2(end_point.x, end_point.y), A3, B3, C3);
- Ogre::Vector3 temp = end_point - start_point;
- temp.normalise();
- temp = temp * direction.length();
- direction.x = temp.x;
- direction.y = temp.y;
- // Set the direction for the entity if it has to move.
- if (entity->GetMoveAutoRotation() == true){
- Ogre::Vector2 up(0.0f, -1.0f);
- // Angle between vectors
- Ogre::Degree angle(Ogre::Radian(acosf(
- direction.dotProduct(up) / (direction.length() * up.length())
- )));
- angle = (direction.x < 0) ? Ogre::Degree(360) - angle : angle;
- entity->SetRotation(Ogre::Degree(angle));
- }
- float solid = (entity->IsSolid() == true) ? entity->GetSolidRadius() : 0.01f;
- // For not playable entities, be a bit more lenient with solid collisions.
- // Don't use the solid radius.
- if (entity != player_entity_) solid /= 10;
- // Get ending point.
- end_point.z = start_point.z;
- for (
- int i = 0;
- (entity == player_entity_ && i < 16)
- || (entity == player_entity_ && i < 3)
- || (entity != player_entity_ && i <= 16);
- ++ i
- ){
- end_point = Ogre::Vector3(
- start_point.x + direction.x, start_point.y + direction.y, start_point.z
- );
- // 1st check.
- // Rotate move_vector +45.
- q1.FromAngleAxis(Ogre::Radian(Ogre::Degree(45)), Ogre::Vector3::UNIT_Z);
- rotation.x = direction.x;
- rotation.y = direction.y;
- rotation.z = 0;
- rotation.normalise();
- rotation = q1 * rotation;
- // Multiply move_vector by solid range
- rotation = rotation * solid;
- end_point2.x = end_point.x + rotation.x;
- end_point2.y = end_point.y + rotation.y;
- // Check_triangle.
- first_triangle_check = WalkmeshBorderCross(entity, end_point2, direction);
- entity->SetMoveTriangleId(current_triangle);
- // Model check.
- first_entity_check = CheckSolidCollisions(entity, end_point2);
- // 2nd check.
- // Rotate move_vector +45.
- q1.FromAngleAxis(Ogre::Radian(Ogre::Degree(-45)), Ogre::Vector3::UNIT_Z);
- rotation.x = direction.x;
- rotation.y = direction.y;
- rotation.z = 0;
- rotation.normalise();
- rotation = q1 * rotation;
- // Multiply move_vector by solid range.
- rotation = rotation * solid;
- end_point2.x = end_point.x + rotation.x;
- end_point2.y = end_point.y + rotation.y;
- // Check triangle.
- second_triangle_check = WalkmeshBorderCross(entity, end_point2, direction);
- entity->SetMoveTriangleId(current_triangle);
- // Model check.
- second_entity_check = CheckSolidCollisions(entity, end_point2);
- // 3rd check.
- rotation.x = direction.x;
- rotation.y = direction.y;
- rotation.z = 0;
- rotation.normalise();
- rotation = rotation * solid;
- end_point2.x = end_point.x + rotation.x;
- end_point2.y = end_point.y + rotation.y;
- // Check triangle.
- third_triangle_check = WalkmeshBorderCross(entity, end_point2, direction);
- entity->SetMoveTriangleId(current_triangle);
- // Model check.
- third_entity_check = CheckSolidCollisions(entity, end_point2);
- // Check condition and modify move_vector.
- if (
- first_triangle_check != false || second_triangle_check != false
- || third_triangle_check != false || first_entity_check != false
- || second_entity_check != false || third_entity_check != false
- ){
- // Only for NPC.
- if (entity != player_entity_){
- // If the entity collides only directly into a triangle border.
- if (
- first_triangle_check == false
- && second_triangle_check == false
- && third_triangle_check != false
- ){
- q1.FromAngleAxis(Ogre::Radian(Ogre::Degree(-7)), Ogre::Vector3::UNIT_Z);
- rotation.x = direction.x;
- rotation.y = direction.y;
- rotation = q1 * rotation;
- direction.x = rotation.x;
- direction.y = rotation.y;
- }
- // Or if the entity only collides into other entity directly.
- else if (
- first_entity_check == false && second_entity_check == false
- && third_entity_check != false
- ){
- q1.FromAngleAxis(Ogre::Radian(Ogre::Degree(-11.25f)), Ogre::Vector3::UNIT_Z);
- rotation.x = direction.x;
- rotation.y = direction.y;
- rotation = q1 * rotation;
- direction.x = rotation.x;
- direction.y = rotation.y;
- }
- // If not both left and right check failed.
- if (first_triangle_check == false || second_triangle_check == false){
- if (
- (first_triangle_check == false && first_entity_check != false)
- || (first_triangle_check != false && second_triangle_check == false)
- ){
- q1.FromAngleAxis(
- Ogre::Radian(Ogre::Degree(-11.25f)), Ogre::Vector3::UNIT_Z
- );
- rotation.x = direction.x;
- rotation.y = direction.y;
- rotation = q1 * rotation;
- direction.x = rotation.x;
- direction.y = rotation.y;
- }
- if (
- first_triangle_check == false
- && first_entity_check == false
- && (second_triangle_check != false || second_entity_check != false
- )
- ){
- q1.FromAngleAxis(Ogre::Radian(Ogre::Degree(11.25f)), Ogre::Vector3::UNIT_Z);
- rotation.x = direction.x;
- rotation.y = direction.y;
- rotation = q1 * rotation;
- direction.x = rotation.x;
- direction.y = rotation.y;
- }
- continue;
- }
- break;
- }
- // Only for playable character.
- else{
- if (
- first_entity_check == false
- && second_entity_check == false
- && third_entity_check == false
- ){
- // If not both left and right check failed
- if (first_triangle_check == false || second_triangle_check == false){
- if (first_triangle_check != false && second_triangle_check == false){
- q1.FromAngleAxis(
- Ogre::Radian(Ogre::Degree(-11.25f)), Ogre::Vector3::UNIT_Z
- );
- rotation.x = direction.x;
- rotation.y = direction.y;
- rotation = q1 * rotation;
- direction.x = rotation.x;
- direction.y = rotation.y;
- }
- if (first_triangle_check == false && second_triangle_check != false){
- q1.FromAngleAxis(
- Ogre::Radian(Ogre::Degree(11.25f)), Ogre::Vector3::UNIT_Z
- );
- rotation.x = direction.x;
- rotation.y = direction.y;
- rotation = q1 * rotation;
- direction.x = rotation.x;
- direction.y = rotation.y;
- }
- continue;
- }
- break;
- }
- }
- }
- }
- // Set new X, Y and Z
- last_triangle_check = WalkmeshBorderCross(entity, end_point, direction);
- if (
- first_triangle_check != false || second_triangle_check != false
- || third_triangle_check != false || last_triangle_check != false
- || first_entity_check != false || second_entity_check != false
- || third_entity_check != false
- ){
- // Event if the entity can't move, check for triggers, but use current position.
- if (player_entity_ == entity) CheckTriggers(entity, entity->GetPosition());
- return false;
- }
- // Check triggers before set entity position because move line is checked.
- if (player_entity_ == entity) CheckTriggers(entity, end_point);
- entity->SetPosition(end_point);
- // If the entity has come to destination point, finish movement.
- Ogre::Vector3 final = entity->GetMovePosition() - end_point;
- const float tolerance = scripted_move ? 0.0001f : speed / 10;
- if (Ogre::Vector2(final.x, final.y).length() <= stop_distance + tolerance)
- entity->UnsetMove();
- return true;
- }
- bool EntityManager::WalkmeshBorderCross(
- Entity* entity, Ogre::Vector3& position, const Ogre::Vector2& move_vector
- ){
- if (IsBattleModule()){
- LOG_WARNING("Tried to check for walkmesh cross, but the EntityManager is in battle mode");
- return false;
- }
- int current_triangle = entity->GetMoveTriangleId();
- if (current_triangle == -1) return true;
- const bool free_walk = !WalkmeshEdgeBlocks(entity == player_entity_, entity->IsScriptedMove());
- Ogre::Vector2 pos = Ogre::Vector2(position.x, position.y);
- for (;;){
- Ogre::Vector3 A3 = walkmesh_.GetA(current_triangle);
- Ogre::Vector3 B3 = walkmesh_.GetB(current_triangle);
- Ogre::Vector3 C3 = walkmesh_.GetC(current_triangle);
- Ogre::Vector2 A(A3.x, A3.y);
- Ogre::Vector2 B(B3.x, B3.y);
- Ogre::Vector2 C(C3.x, C3.y);
- float sign1 = SideOfVector(pos, B, A);
- float sign2 = SideOfVector(pos, C, B);
- float sign3 = SideOfVector(pos, A, C);
- int next_triangle = -1;
- if (sign1 < 0) next_triangle = walkmesh_.GetAccessSide(current_triangle, 0);
- else if (sign2 < 0) next_triangle = walkmesh_.GetAccessSide(current_triangle, 1);
- else if (sign3 < 0) next_triangle = walkmesh_.GetAccessSide(current_triangle, 2);
- else{
- position.z = PointElevation(pos, A3, B3, C3);
- entity->SetMoveTriangleId(current_triangle);
- return false;
- }
- if (next_triangle >= 0){
- bool lock = walkmesh_.IsLocked(next_triangle);
- if (lock == false || free_walk){
- current_triangle = next_triangle;
- continue;
- }
- }
- position.z = PointElevation(pos, A3, B3, C3);
- entity->SetMoveTriangleId(current_triangle);
- // A walk of a script goes on over the edge, keeping the last triangle.
- return !free_walk;
- }
- }
- bool EntityManager::CheckSolidCollisions(Entity* entity, Ogre::Vector3& position){
- if (IsBattleModule()){
- LOG_WARNING("Tried to check for solid collisions, but the EntityManager is in battle mode");
- return false;
- }
- if (entity->IsSolid() == false) return false;
- for (size_t i = 0; i < entity_.size(); ++ i){
- if (entity_[i]->IsSolid() == false) continue;
- if (entity_[i] == entity) continue;
- Ogre::Vector3 pos1 = entity_[i]->GetPosition();
- float solid_range = entity_[i]->GetSolidRadius();
- solid_range *= solid_range;
- float height = (pos1.z < position.z) ? entity_[i]->GetHeight() : entity->GetHeight();
- if (
- ((pos1.z - position.z + height) < (height * 2)) && ((pos1.z - position.z + height) >= 0)
- ){
- float distance
- = (pos1.x - position.x) * (pos1.x - position.x)
- + (pos1.y - position.y) * (pos1.y - position.y);
- if (distance < solid_range) return true;
- }
- }
- return false;
- }
- void EntityManager::CheckTriggers(Entity* entity, const Ogre::Vector3& position){
- if (IsBattleModule()){
- LOG_WARNING("Tried to check for triggers, but the EntityManager is in battle mode");
- return;
- }
- if (entity->IsSolid() == false) return;
- if (player_entity_ != entity) return;
- if (player_entity_->IsSolid() == false) return;
- if (player_lock_) return;
- bool is_moving = true;
- if (
- std::fabs(entity->GetPosition().x - position.x) < 0.005f
- && std::fabs(entity->GetPosition().y - position.y) < 0.005f
- && std::fabs(entity->GetPosition().z - position.z) < 0.005f
- ){
- is_moving = false;
- }
- for (unsigned int i = 0; i < entity_triggers_.size(); ++ i){
- ScriptEntity* trigger = ScriptManager::getSingleton().GetScriptEntityByName(
- ScriptManager::ENTITY, entity_triggers_[i]->GetName()
- );
- if (trigger != nullptr && entity_triggers_[i]->IsEnabled() == true){
- Ogre::Vector3 point_a = entity_triggers_[i]->GetPoint1();
- Ogre::Vector3 point_b = entity_triggers_[i]->GetPoint2();
- Ogre::Vector3 entity_position = entity->GetPosition();
- Ogre::Vector3 proj;
- // Calculate distance
- float square_dist = SquareDistanceToLine(entity_position, point_a, point_b, proj);
- float solid_radius = TriggerReach(entity->GetSolidRadius());
- // Calculate direction.
- const Ogre::Degree direction_to_line = GetDirectionToPoint(entity_position, proj);
- const Ogre::Degree destination_direction_to_line = GetDirectionToPoint(position, proj);
- const Ogre::Degree movement_direction = entity->GetRotation();
- Ogre::Degree angle = direction_to_line - movement_direction + Ogre::Degree(90);
- angle = (angle > Ogre::Degree(360)) ? angle - Ogre::Degree(360) : angle;
- // Check on enter line.
- // Must happen only once when the solid radius touches the line, while facing the line,
- // while the entity is manually moving, and only if not already triggered.
- if (
- square_dist != -1 && square_dist <= solid_radius * solid_radius
- && angle < Ogre::Degree(180) && angle > Ogre::Degree(0)
- && entity_triggers_[i]->CheckApproached() == false
- && is_moving
- ){
- entity_triggers_[i]->SetApproached(true);
- //std::cout << " [TRIGGER] " << entity->GetName() << " on_approach "
- // << entity_triggers_[i]->GetName() << std::endl;
- ScriptManager::getSingleton().ScriptRequest(
- trigger, "on_approach", 1, entity->GetName(), "", false, false
- );
- }
- // Check on move to line.
- // Must happen only once when the entity center touches the line, if the entity has
- // previously entered the line.
- if (
- square_dist != -1 && square_dist < 1
- && entity_triggers_[i]->CheckCrossed() == false
- && entity_triggers_[i]->CheckApproached() == true
- ){
- entity_triggers_[i]->SetCrossed(true);
- //std::cout << " [TRIGGER] " << entity->GetName() << " on_cross "
- // << entity_triggers_[i]->GetName() << std::endl;
- ScriptManager::getSingleton().ScriptRequest(
- trigger, "on_cross", 1, entity->GetName(), "", false, false
- );
- }
- // Check on cross line.
- // Must happen on every frame while the entity solid radius collides with the line, if
- // the entity has previously entered the line.
- if (
- square_dist != -1 && square_dist <= solid_radius * solid_radius
- && entity_triggers_[i]->CheckApproached() == true
- ){
- // TODO: Fix this hack.
- // After the on_near script is run, set a cooltime of 5 frames before running
- // it again. This is because most of the time this trigger checks for a key, and
- // if its pressed, is run multiple times.
- if (entity_triggers_[i]->GetNearEventCooldown() == 0){
- //std::cout << " [TRIGGER] " << entity->GetName()
- // << " on_near " << entity_triggers_[i]->GetName() << std::endl;
- ScriptManager::getSingleton().ScriptRequest(
- trigger, "on_near", 1, entity->GetName(), "", true, true
- );
- entity_triggers_[i]->ResetNearEventCooldown();
- }
- else entity_triggers_[i]->DecreaseNearEventCooldown();
- }
- // Check on cross line once.
- // The same as on cross line, but only once.
- if (
- square_dist != -1 && square_dist < solid_radius * solid_radius
- && entity_triggers_[i]->CheckNearSingleEventTriggered() == false
- && entity_triggers_[i]->CheckApproached() == true
- ){
- entity_triggers_[i]->SetNearSingleEventTriggered(true);
- //std::cout << " [TRIGGER] " << entity->GetName()
- // << " on_near_once " << entity_triggers_[i]->GetName() << std::endl;
- ScriptManager::getSingleton().ScriptRequest(
- trigger, "on_near_once", 1, entity->GetName(), "", false, false
- );
- }
- // Check on leave line.
- // Must be triggered once when the line is not in the entity solid radius, but only if
- // on enter script has been triggered previously.
- if (
- square_dist != -1 && square_dist > solid_radius * solid_radius
- && entity_triggers_[i]->CheckApproached()
- ){
- //std::cout << " [TRIGGER] " << entity->GetName() << " on_leave "
- // << entity_triggers_[i]->GetName() << std::endl;
- ScriptManager::getSingleton().ScriptRequest(
- trigger, "on_leave", 1, entity->GetName(), "", false, false
- );
- }
- // If the entity is far enough from the line, mark every trigger as inactive
- if (square_dist == -1 || square_dist > solid_radius * solid_radius){
- entity_triggers_[i]->Clear();
- //std::cout << " [TRIGGER] " << entity->GetName() << " clear of "
- // << entity_triggers_[i]->GetName() << std::endl;
- }
- }
- }
- }
- void EntityManager::CheckEntityInteract(){
- if (IsBattleModule()){
- LOG_WARNING(
- "Tried to check for entity interaction, but the EntityManager is in battle mode"
- );
- return;
- }
- if (player_entity_ == NULL || player_lock_ == true || player_entity_->IsSolid() == false)
- return;
- Ogre::Degree angle_pc = player_entity_->GetRotation();
- Entity* entity_to_interact = NULL;
- Ogre::Degree less_angle(90);
- float best_distance = std::numeric_limits<float>::max();
- Ogre::Real nearest_worldmap_distance = -1.0f;
- for (unsigned int i = 0; i < entity_.size(); ++ i){
- if (entity_[i]->IsTalkable() == false) continue;
- if (entity_[i] == player_entity_) continue;
- Ogre::Vector3 pos1 = entity_[i]->GetPosition();
- float interact_range = entity_[i]->GetTalkRadius();
- Ogre::Vector3 pos2 = player_entity_->GetPosition();
- float solid_range = player_entity_->GetSolidRadius();
- if (IsWorldModule()){
- const Ogre::Real target_bottom = pos1.y;
- const Ogre::Real player_bottom = pos2.y;
- const Ogre::Real talk_range
- = interact_range + solid_range + 0.05f;
- const Ogre::Real distance
- = (pos1.x - pos2.x) * (pos1.x - pos2.x)
- + (pos1.z - pos2.z) * (pos1.z - pos2.z);
- const bool height_overlap
- = player_bottom <= target_bottom + entity_[i]->GetHeight()
- && player_bottom + player_entity_->GetHeight() >= target_bottom;
- if (
- height_overlap && distance <= talk_range * talk_range
- && (nearest_worldmap_distance < 0 || distance < nearest_worldmap_distance)
- ){
- entity_to_interact = entity_[i];
- nearest_worldmap_distance = distance;
- }
- continue;
- }
- int height = (pos1.z < pos2.z) ? entity_[i]->GetHeight() : player_entity_->GetHeight();
- if (((pos1.z - pos2.z + height) < (height * 2)) && ((pos1.z - pos2.z + height) >= 0)){
- interact_range = (interact_range + solid_range) * (interact_range + solid_range);
- float distance
- = (pos1.x - pos2.x) * (pos1.x - pos2.x) + (pos1.y - pos2.y) * (pos1.y - pos2.y);
- if (distance < interact_range + solid_range){
- Ogre::Degree angle_to_model = GetDirectionToPoint(pos2, pos1);
- Ogre::Degree angle = angle_pc - angle_to_model;
- angle = (angle < Ogre::Degree(0)) ? -angle : angle;
- angle = (angle >= Ogre::Degree(180)) ? Ogre::Degree(360) - angle : angle;
- // With several entities in range, interact with the one the player faces most.
- // Nobody 90 degrees or more away from where the player faces is considered.
- if (
- angle < Ogre::Degree(90) && IsBetterInteractionTarget(
- angle.valueDegrees(), distance, less_angle.valueDegrees(), best_distance
- )
- ){
- less_angle = angle;
- best_distance = distance;
- entity_to_interact = entity_[i];
- }
- }
- }
- }
- if (entity_to_interact != NULL && entity_to_interact->IsLine() == false){
- Ogre::String name = entity_to_interact->GetName();
- ScriptEntity* scr_entity = ScriptManager::getSingleton().GetScriptEntityByName(
- ScriptManager::ENTITY, name
- );
- bool added = ScriptManager::getSingleton().ScriptRequest(
- scr_entity, "on_interact", 1, "", "", false, false
- );
- if (added == false){
- LOG_WARNING("Script 'on_interact' for entity '" + name + "' doesn't exist.");
- }
- }
- }
- void EntityManager::SetNextOffsetStep(Entity* entity){
- // TODO: Allow this while on battle mode?
- ActionType type = entity->GetOffsetType();
- float total = entity->GetOffsetSeconds();
- float current = entity->GetOffsetCurrentSeconds();
- current += Timer::getSingleton().GetGameTimeDelta();
- current = (current > total) ? total : current;
- Ogre::Vector3 start = entity->GetOffsetPositionStart();
- Ogre::Vector3 end = entity->GetOffsetPositionEnd();
- // TODO: Prevent division by 0:
- float x = current / total;
- if (std::isnan(x)) x = 0.0f;
- float smooth_modifier = (type == AT_SMOOTH) ? -2 * x * x * x + 3 * x * x : x;
- Ogre::Vector3 offset = start + (end - start) * smooth_modifier;
- entity->SetOffset(offset);
- if (current == total) entity->UnsetOffset();
- else entity->SetOffsetCurrentSeconds(current);
- }
- void EntityManager::SetNextTurnStep(Entity* entity){
- // TODO: Allow this while on battle mode?
- ActionType type = entity->GetTurnType();
- float total = entity->GetTurnSeconds();
- float current = entity->GetTurnCurrentSeconds();
- current += Timer::getSingleton().GetGameTimeDelta();
- current = (current > total) ? total : current;
- Ogre::Degree start = entity->GetTurnDirectionStart();
- Ogre::Degree end = entity->GetTurnDirectionEnd();
- // TODO: Prevent division by 0:
- float x = current / total;
- float smooth_modifier = (type == AT_SMOOTH) ? -2 * x * x * x + 3 * x * x : x;
- Ogre::Degree rotation = start + (end - start) * smooth_modifier;
- entity->SetRotation(rotation);
- if (current == total) entity->UnsetTurn();
- else entity->SetTurnCurrentSeconds(current);
- }
- void EntityManager::SetNextLinearStep(Entity* entity){
- if (IsBattleModule()){
- LOG_WARNING("Tried to set next linear step, but the EntityManager is in battle mode");
- return;
- }
- bool to_end = true;
- bool is_move = false;
- Ogre::Vector3 start = entity->GetLinearStart();
- Ogre::Vector3 end = entity->GetLinearEnd();
- Ogre::Vector3 current = entity->GetPosition();
- float delta = Timer::getSingleton().GetGameTimeDelta();
- // The player climbs a ladder with the directional keys. While a scene has the player locked
- // the keys have no effect, and the scene makes the player move on its own, as with any other
- // entity.
- if (entity == player_entity_ && !player_lock_){
- LinearMovement move = entity->GetLinearMovement();
- if (move == LM_DOWN_TO_UP || move == LM_UP_TO_DOWN){
- if (player_move_.y > 0){ // move up
- to_end = (move == LM_DOWN_TO_UP) ? true : false;
- is_move = true;
- }
- else if (player_move_.y < 0){ // move down
- to_end = (move == LM_DOWN_TO_UP) ? false : true;
- is_move = true;
- }
- }
- else if (move == LM_LEFT_TO_RIGHT || move == LM_RIGHT_TO_LEFT){
- if (player_move_.x > 0){ // move right
- to_end = (move == LM_LEFT_TO_RIGHT) ? true : false;
- is_move = true;
- }
- else if (player_move_.x < 0){ // move left
- to_end = (move == LM_LEFT_TO_RIGHT) ? false : true;
- is_move = true;
- }
- }
- }
- else is_move = true;
- if (is_move == true){
- Ogre::Vector3 position;
- if (to_end == true){
- Ogre::Vector3 end_start = end - start;
- // Move across the whole line by this number of seconds.
- float time = end_start.length() / 1.2f;
- position.x = current.x + (end_start.x / time) * delta;
- position.y = current.y + (end_start.y / time) * delta;
- position.z = current.z + (end_start.z / time) * delta;
- position.x = (end_start.x < 0)
- ? std::max(position.x, end.x) : std::min(position.x, end.x);
- position.y = (end_start.y < 0)
- ? std::max(position.y, end.y) : std::min(position.y, end.y);
- position.z = (end_start.z < 0)
- ? std::max(position.z, end.z) : std::min(position.z, end.z);
- if (position == end){
- entity->UnsetLinear();
- entity->SetMoveTriangleId(entity->GetLinearDestTriangle());
- SetEntityOnWalkmesh(entity);
- }
- }
- else{
- Ogre::Vector3 end_start = start - end;
- // Move across the whole line by this number of seconds.
- float time = end_start.length() / 1.2f;
- position.x = current.x + (end_start.x / time) * delta;
- position.y = current.y + (end_start.y / time) * delta;
- position.z = current.z + (end_start.z / time) * delta;
- position.x = (end_start.x < 0)
- ? std::max(position.x, start.x) : std::min(position.x, start.x);
- position.y = (end_start.y < 0)
- ? std::max(position.y, start.y) : std::min(position.y, start.y);
- position.z = (end_start.z < 0)
- ? std::max(position.z, start.z) : std::min(position.z, start.z);
- if (position == start){
- entity->UnsetLinear();
- SetEntityOnWalkmesh(entity);
- }
- }
- entity->SetPosition(position);
- entity->UpdateAnimation((to_end == true) ? delta : -delta);
- }
- }
- void EntityManager::SetNextJumpStep(Entity* entity){
- if (IsBattleModule()){
- LOG_WARNING("Tried to set next jump step, but the EntityManager is in battle mode");
- return;
- }
- float total = entity->GetJumpSeconds();
- float current = entity->GetJumpCurrentSeconds();
- current += Timer::getSingleton().GetGameTimeDelta();
- current = (current > total) ? total : current;
- Ogre::Vector3 start_position = entity->GetJumpStart();
- Ogre::Vector3 end_position = entity->GetJumpEnd();
- Ogre::Vector3 position;
- position.x = start_position.x + ((end_position.x - start_position.x) / total) * current;
- position.y = start_position.y + ((end_position.y - start_position.y) / total) * current;
- position.z = current * current * -1.0f + current
- * ((end_position.z - start_position.z) / total + total * 1.0f) + start_position.z;
- entity->SetPosition(position);
- if (total == current){
- entity->UnsetJump();
- entity->SetMoveTriangleId(entity->GetJumpDestTriangle());
- SetEntityOnWalkmesh(entity);
- }
- else entity->SetJumpCurrentSeconds(current);
- }
- void EntityManager::SetNextScrollStep(){
- // TODO: Allow this on battle mode?
- background_2d_.UpdateScrollTarget();
- Background2D::SCROLL_TYPE type = background_2d_.GetScrollType();
- float total = background_2d_.GetScrollSeconds();
- float current = background_2d_.GetScrollCurrentSeconds();
- current += Timer::getSingleton().GetGameTimeDelta();
- current = (current > total) ? total : current;
- Ogre::Vector2 start = background_2d_.GetScrollPositionStart();
- Ogre::Vector2 end = background_2d_.GetScrollPositionEnd();
- float x = current / total;
- float smooth_modifier = (type == Background2D::SMOOTH) ? -2 * x * x * x + 3 * x * x : x;
- Ogre::Vector2 scroll = start + (end - start) * smooth_modifier;
- background_2d_.SetScroll(scroll);
- if (current == total) background_2d_.UnsetScroll();
- else background_2d_.SetScrollCurrentSeconds(current);
- }
|