EntityManager.cpp 66 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589
  1. /*
  2. * Copyright (C) 2022 The V-Gears Team
  3. *
  4. * This file is part of V-Gears
  5. *
  6. * V-Gears is free software: you can redistribute it and/or modify it under
  7. * terms of the GNU General Public License as published by the Free Software
  8. * Foundation, version 3.0 (GPLv3) of the License.
  9. *
  10. * V-Gears is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. */
  15. #include <iostream>
  16. #include <cmath>
  17. #include <limits>
  18. #include <OgreEntity.h>
  19. #include <OgreRoot.h>
  20. #include <OgreViewport.h>
  21. #include "core/CameraManager.h"
  22. #include "core/ConfigVar.h"
  23. #include "core/DebugDraw.h"
  24. #include "core/EntityManager.h"
  25. #include "core/EntityModel.h"
  26. #include "core/InputManager.h"
  27. #include "core/Logger.h"
  28. #include "core/ScriptManager.h"
  29. #include "core/Timer.h"
  30. #include "core/DialogsManager.h"
  31. /**
  32. * Entity manager singleton.
  33. */
  34. template<>EntityManager *Ogre::Singleton<EntityManager>::msSingleton = nullptr;
  35. ConfigVar cv_debug_grid("debug_grid", "Draw debug grid", "false");
  36. ConfigVar cv_debug_axis("debug_axis", "Draw debug axis", "false");
  37. const float EntityManager::SCENE_SCALE = 0.003f;
  38. const unsigned int EntityManager::BATTLE_BACKGROUND_ID = 1000;
  39. const unsigned int EntityManager::WORLD_MAP_BACKGROUND_ID = 1001;
  40. float EntityManager::PointElevation(
  41. const Ogre::Vector2& point, const Ogre::Vector3& a, const Ogre::Vector3& b, const Ogre::Vector3& c
  42. ){
  43. float _a = a.z * (b.y - c.y) + b.z * (c.y - a.y) + c.z * (a.y - b.y);
  44. float _b = a.y * (b.x - c.x) + b.y * (c.x - a.x) + c.y * (a.x - b.x);
  45. float _c = a.x * (b.z - c.z) + b.x * (c.z - a.z) + c.x * (a.z - b.z);
  46. float _d
  47. = a.x * (b.z * c.y - c.z * b.y) + b.x * (c.z * a.y - a.z * c.y)
  48. + c.x * (a.z * b.y - b.z * a.y);
  49. return (_d - _c * point.y - _a * point.x) / _b;
  50. }
  51. float EntityManager::SideOfVector(
  52. const Ogre::Vector2& point, const Ogre::Vector2& p1, const Ogre::Vector2& p2
  53. ){
  54. Ogre::Vector2 AB = p2 - p1;
  55. Ogre::Vector2 AP = point - p1;
  56. return AB.x * AP.y - AB.y * AP.x;
  57. }
  58. float EntityManager::SquareDistanceToLine(
  59. const Ogre::Vector3& point, const Ogre::Vector3& point_a, const Ogre::Vector3& point_b,
  60. Ogre::Vector3& proj
  61. ){
  62. float temp =
  63. -((point_a.x - point.x) * (point_b.x - point_a.x) + (point_a.y - point.y)
  64. * (point_b.y - point_a.y) + (point_a.z - point.z) * (point_b.z - point_a.z))
  65. / ((point_b.x - point_a.x) * (point_b.x - point_a.x) + (point_b.y - point_a.y)
  66. * (point_b.y - point_a.y) + (point_b.z - point_a.z) * (point_b.z - point_a.z));
  67. proj.x = temp * (point_b.x - point_a.x) + point_a.x;
  68. proj.y = temp * (point_b.y - point_a.y) + point_a.y;
  69. proj.z = temp * (point_b.z - point_a.z) + point_a.z;
  70. if (
  71. ((point_a.x >= proj.x && point_b.x <= proj.x) || (point_a.x < proj.x && point_b.x >= proj.x))
  72. && (
  73. (point_a.y >= proj.y && point_b.y <= proj.y) || (point_a.y < proj.y && point_b.y >= proj.y)
  74. )
  75. ){
  76. return (proj.x - point.x) * (proj.x - point.x) + (proj.y - point.y)
  77. * (proj.y - point.y) + (proj.z - point.z) * (proj.z - point.z);
  78. }
  79. return -1;
  80. }
  81. Ogre::Degree EntityManager::GetDirectionToPoint(
  82. const Ogre::Vector3& current_point, const Ogre::Vector3& direction_point
  83. ){
  84. // TODO: Declare function in header file.
  85. Ogre::Vector2 up(0.0f, -1.0f);
  86. Ogre::Vector2 dir(direction_point.x - current_point.x, direction_point.y - current_point.y);
  87. // Angle between vectors
  88. Ogre::Degree angle(Ogre::Radian(acosf(dir.dotProduct(up) / (dir.length() * up.length()))));
  89. return (dir.x < 0) ? Ogre::Degree(360) - angle : angle;
  90. }
  91. EntityManager::EntityManager():
  92. background_3d_(nullptr),
  93. player_entity_(nullptr),
  94. player_move_(Ogre::Vector3::ZERO),
  95. player_move_rotation_(0),
  96. player_lock_(false),
  97. player_run_(false),
  98. random_encounters_(false),
  99. encounter_rate_(0)
  100. {
  101. LOG_TRIVIAL("EntityManager created.");
  102. scene_node_ = Ogre::Root::getSingleton().getSceneManager("Scene")
  103. ->getRootSceneNode()->createChildSceneNode("EntityManager");
  104. //grid_ = Ogre::Root::getSingleton().getSceneManager("Scene")
  105. // ->createEntity("Grid", "system/grid.mesh");
  106. grid_ = Ogre::Root::getSingleton().getSceneManager("Scene")->createEntity("Grid", "grid.mesh");
  107. scene_node_->attachObject(grid_);
  108. //axis_ = Ogre::Root::getSingleton().getSceneManager("Scene")
  109. // ->createEntity("Axis", "system/axis.mesh");
  110. axis_ = Ogre::Root::getSingleton().getSceneManager("Scene")->createEntity("Axis", "axis.mesh");
  111. scene_node_->attachObject(axis_);
  112. }
  113. EntityManager::~EntityManager(){
  114. if (grid_ != nullptr) Ogre::Root::getSingleton().getSceneManager("Scene")->destroyEntity(grid_);
  115. if (axis_ != nullptr) Ogre::Root::getSingleton().getSceneManager("Scene")->destroyEntity(axis_);
  116. Clear();
  117. Ogre::Root::getSingleton().getSceneManager("Scene")->getRootSceneNode()->removeAndDestroyChild(
  118. "EntityManager"
  119. );
  120. LOG_TRIVIAL("EntityManager destroyed.");
  121. }
  122. void EntityManager::Input(const VGears::Event& event){
  123. background_2d_.InputDebug(event);
  124. if (paused_ == true) return;
  125. if (player_entity_ != NULL && player_lock_ == false){
  126. if (event.type == VGears::ET_KEY_REPEAT && event.event == "walk_left") player_move_.x = -1;
  127. else if (event.type == VGears::ET_KEY_REPEAT && event.event == "walk_right")
  128. player_move_.x = 1;
  129. if (event.type == VGears::ET_KEY_REPEAT && event.event == "walk_down") player_move_.y = -1;
  130. else if (event.type == VGears::ET_KEY_REPEAT && event.event == "walk_up")
  131. player_move_.y = 1;
  132. if (event.type == VGears::ET_KEY_REPEAT && event.event == "run") player_run_ = true;
  133. if (event.type == VGears::ET_KEY_PRESS && event.event == "CONFIRM"){
  134. CheckEntityInteract();
  135. for (unsigned int i = 0; i < entity_triggers_.size(); ++ i){
  136. if (
  137. entity_triggers_[i]->IsEnabled() == true
  138. && entity_triggers_[i]->CheckApproached() == true
  139. ){
  140. ScriptEntity* scr_entity = ScriptManager::getSingleton().GetScriptEntityByName(
  141. ScriptManager::ENTITY, entity_triggers_[i]->GetName()
  142. );
  143. bool added = ScriptManager::getSingleton().ScriptRequest(
  144. scr_entity, "on_interact", 1, "", "", false, false
  145. );
  146. if (added == false){
  147. LOG_WARNING(
  148. "Script 'on_interact' for entity '" + entity_triggers_[i]->GetName()
  149. + "' doesn't exist."
  150. );
  151. }
  152. }
  153. }
  154. }
  155. // Rotate move vector to field move rotation
  156. Ogre::Quaternion q1;
  157. q1.FromAngleAxis(player_move_rotation_, Ogre::Vector3::UNIT_Z);
  158. player_move_ = q1 * player_move_;
  159. }
  160. }
  161. void EntityManager::UpdateField(){
  162. // Update all entity scripts
  163. ScriptManager::getSingleton().Update(ScriptManager::ENTITY);
  164. // Set move point for player entity
  165. if (player_entity_ != nullptr && player_move_ != Ogre::Vector3::ZERO){
  166. Entity::State state = player_entity_->GetState();
  167. if (state == Entity::WALKMESH || state == Entity::NONE){
  168. player_move_
  169. *= player_entity_->GetMoveWalkSpeed() * Timer::getSingleton().GetGameTimeDelta();
  170. player_entity_->SetMovePosition(player_entity_->GetPosition() + player_move_);
  171. player_entity_->SetState(Entity::WALKMESH);
  172. }
  173. // HACK: If manually moving, make playable entity solid.
  174. // Some scripts 'forget' to make the playable entity solid at the end
  175. // of them, and if it remains non-solid, it can't interact with lines
  176. // (i.e. it cant' use gateways).
  177. player_entity_->SetSolid(true);
  178. }
  179. for (unsigned int i = 0; i < entity_.size(); ++ i){
  180. entity_[i]->Update();
  181. // It's not needed to update movements it delta time == 0 (for example
  182. // if time is stopped)
  183. if (Timer::getSingleton().GetGameTimeDelta() == 0) continue;
  184. // Update screen scroll.
  185. Entity* scroll_entity = background_2d_.GetAutoScrollEntity();
  186. if (scroll_entity == entity_[i])
  187. background_2d_.SetScroll(background_2d_.GetEntityScroll(scroll_entity));
  188. // Update offset.
  189. if (entity_[i]->GetOffsetType() != AT_NONE) SetNextOffsetStep(entity_[i]);
  190. // Update turn.
  191. if (entity_[i]->GetTurnType() != AT_NONE) SetNextTurnStep(entity_[i]);
  192. // Update movement.
  193. switch(entity_[i]->GetState()){
  194. case Entity::WALKMESH:
  195. {
  196. // Try set entity on walkmesh if it's still don't has triangle.
  197. if (entity_[i]->GetMoveTriangleId() == -1){
  198. if (SetEntityOnWalkmesh(entity_[i]) == false){
  199. LOG_TRIVIAL(
  200. "Can't set entity '" + entity_[i]->GetName()
  201. + "' on walkmesh. Finish move."
  202. );
  203. entity_[i]->UnsetMove();
  204. }
  205. }
  206. // Perform move
  207. if (entity_[i]->GetState() == Entity::WALKMESH){
  208. float speed = 0;
  209. if (player_lock_ == false && player_entity_ == entity_[i]){
  210. speed = entity_[i]->GetMoveWalkSpeed();
  211. // TODO: Set as a constant.
  212. // Or even better, as a configurable variable.
  213. if (player_run_ == true) speed *= 4;
  214. }
  215. else speed = entity_[i]->GetMoveAutoSpeed();
  216. float remaining_time = Timer::getSingleton().GetGameTimeDelta();
  217. bool is_move = false;
  218. if (entity_[i]->IsScriptedMove() && speed > 0.0f){
  219. const float max_step_time = 0.2f / speed;
  220. while (remaining_time > 0.0f && entity_[i]->GetState() == Entity::WALKMESH){
  221. const float step_time = std::min(remaining_time, max_step_time);
  222. const bool moved = PerformWalkmeshMove(entity_[i], speed, step_time);
  223. is_move = is_move || moved;
  224. if (!moved) break;
  225. remaining_time -= step_time;
  226. }
  227. }
  228. else is_move = PerformWalkmeshMove(entity_[i], speed, remaining_time);
  229. if (entity_[i]->GetMoveAutoAnimation() == true){
  230. if (is_move == true){
  231. if (speed >= entity_[i]->GetMoveRunSpeed()){
  232. entity_[i]->PlayAnimationContinue(
  233. entity_[i]->GetMoveAnimationRunName()
  234. );
  235. }
  236. else{
  237. entity_[i]->PlayAnimationContinue(
  238. entity_[i]->GetMoveAnimationWalkName()
  239. );
  240. }
  241. }
  242. else if (
  243. entity_[i]->GetAnimationState() != Entity::REQUESTED_ANIMATION
  244. ){
  245. entity_[i]->PlayAnimationContinue(
  246. entity_[i]->GetDefaultAnimationName()
  247. );
  248. }
  249. }
  250. }
  251. }
  252. break;
  253. case Entity::LINEAR:
  254. CheckTriggers(entity_[i], entity_[i]->GetPosition());
  255. SetNextLinearStep(entity_[i]);
  256. break;
  257. case Entity::JUMP:
  258. SetNextJumpStep(entity_[i]);
  259. break;
  260. case Entity::NEEDS_TO_REATTACH:
  261. if (SetEntityOnWalkmesh(entity_[i])) entity_[i]->SetState(Entity::WALKMESH);
  262. else entity_[i]->SetState(Entity::NONE);
  263. case Entity::NONE:
  264. CheckTriggers(entity_[i], entity_[i]->GetPosition());
  265. if (entity_[i]->GetAnimationState() != Entity::REQUESTED_ANIMATION)
  266. entity_[i]->PlayAnimationContinue(entity_[i]->GetDefaultAnimationName());
  267. break;
  268. }
  269. }
  270. // Reset player move. It already must be handled in update
  271. player_move_ = Ogre::Vector3::ZERO;
  272. player_run_ = false;
  273. if (background_2d_.GetScrollType() != Background2D::NONE) SetNextScrollStep();
  274. background_2d_.Update();
  275. screen_fade_.Update(Timer::getSingleton().GetGameTimeDelta());
  276. }
  277. void EntityManager::UpdateBattle(){
  278. ScriptManager::getSingleton().Update(ScriptManager::BATTLE);
  279. if (background_3d_ != nullptr){
  280. background_3d_->Update();
  281. background_3d_->PlayAnimationContinue(background_3d_->GetDefaultAnimationName());
  282. }
  283. for (unsigned int i = 0; i < battle_entity_.size(); ++ i){
  284. battle_entity_[i]->Update();
  285. battle_entity_[i]->PlayAnimationContinue(battle_entity_[i]->GetDefaultAnimationName());
  286. }
  287. //CameraManager::getSingleton().GetCurrentCamera()->roll(Ogre::Radian(0.01));
  288. }
  289. void EntityManager::UpdateWorld(){
  290. ScriptManager::getSingleton().Update(ScriptManager::ENTITY);
  291. for (Entity* entity : entity_){
  292. entity->Update();
  293. }
  294. player_move_ = Ogre::Vector3::ZERO;
  295. player_run_ = false;
  296. }
  297. void EntityManager::AddFieldOrWorldMapEntity(
  298. const Ogre::String& name, const Ogre::String& file_name, const Ogre::Vector3& position,
  299. const Ogre::Degree& rotation, const Ogre::Vector3& scale,
  300. const Ogre::Quaternion& root_orientation, const int index
  301. ){
  302. if (module_ != Module::FIELD){
  303. LOG_ERROR("Tried to add field or world Entity but the EntityManager is in battle mode.");
  304. return;
  305. }
  306. Ogre::SceneNode* node = scene_node_->createChildSceneNode("Model_" + name);
  307. EntityModel* entity = new EntityModel(name, file_name, node);
  308. entity->SetPosition(position);
  309. entity->SetRotation(rotation);
  310. entity->setScale(scale);
  311. entity->SetIndex(index);
  312. entity->setRootOrientation(root_orientation);
  313. entity_.push_back(entity);
  314. ScriptManager::getSingleton().AddEntity(ScriptManager::ENTITY, entity->GetName(), entity);
  315. }
  316. EntityModel* EntityManager::AddWorldMapEntity(
  317. const Ogre::String& name, const Ogre::String& file_name,
  318. const Ogre::Vector3& position, const Ogre::Degree& rotation,
  319. const Ogre::Vector3& scale, const Ogre::String& resource_group
  320. ){
  321. if (!IsWorldModule()){
  322. LOG_ERROR("Tried to add a world-map entity outside world-map mode.");
  323. return nullptr;
  324. }
  325. if (GetEntity(name) != nullptr){
  326. LOG_ERROR("Tried to add duplicate world-map entity '" + name + "'.");
  327. return nullptr;
  328. }
  329. Ogre::SceneNode* node = scene_node_->createChildSceneNode("Model_" + name);
  330. EntityModel* entity = new EntityModel(name, file_name, node, resource_group);
  331. entity->SetPosition(position);
  332. entity->SetRotation(rotation);
  333. entity->setScale(scale);
  334. entity->SetVisible(true);
  335. entity_.push_back(entity);
  336. ScriptManager::getSingleton().AddEntity(ScriptManager::ENTITY, entity->GetName(), entity);
  337. return entity;
  338. }
  339. void EntityManager::AddBattleEntity(
  340. const Ogre::String& name, const Ogre::String& file_name, const Ogre::Vector3& position,
  341. const Ogre::Degree& rotation, const Ogre::Vector3& scale,
  342. const Ogre::Quaternion& root_orientation, const int index
  343. ){
  344. if (module_ != Module::BATTLE){
  345. LOG_ERROR("Tried to add battle Entity but the EntityManager is not in battle mode.");
  346. return;
  347. }
  348. Ogre::SceneNode* node = scene_node_->createChildSceneNode("Battle_" + name);
  349. // Battle models must be reoriented.
  350. node->setOrientation(root_orientation);
  351. EntityModel* entity = new EntityModel(name, file_name, node);
  352. entity->SetPosition(position);
  353. entity->SetRotation(rotation);
  354. entity->setScale(scale);
  355. entity->SetIndex(index);
  356. entity->SetVisible(true);
  357. battle_entity_.push_back(entity);
  358. ScriptManager::getSingleton().AddEntity(ScriptManager::BATTLE, entity->GetName(), entity);
  359. /*std::cout << "BATTLE ANIMATIONS FOR " << name << std::endl;
  360. const std::map<Ogre::String, Ogre::AnimationState*>& anims
  361. = entity->GetModel()->getAllAnimationStates()->getAnimationStates();
  362. int size = anims.size();
  363. std::cout << " " << std::to_string(size) << " TOTAL " << std::endl;
  364. for (auto anim = anims.begin(); anim != anims.end(); ++ anim){
  365. std::cout << " - " << anim->first << ", " << anim->second << std::endl;
  366. }*/
  367. /* Animations have the following names:
  368. * XX_00,
  369. * XX_01,
  370. * XX_02,
  371. * ...
  372. * where XX is the first two characters of file_name, without the path.
  373. */
  374. Ogre::String anim = file_name.substr(file_name.find_last_of("/\\") + 1).substr(0, 2) + "_00";
  375. //std::cout << " Playing " << anim << std::endl;
  376. entity->ScriptSetDefaultAnimation(anim.c_str());
  377. }
  378. Entity* EntityManager::GetBackground3D() const{
  379. if (IsFieldModule()){
  380. LOG_WARNING("Tried to retrieve a 3D background while the EntityManager is in field mode.");
  381. return nullptr;
  382. }
  383. return background_3d_;
  384. }
  385. void EntityManager::SetBackground3D(const Ogre::String& name, const Ogre::String& file_name){
  386. if (IsFieldModule()){
  387. LOG_ERROR("Tried to add a 3D background while the EntityManager is in field mode.");
  388. return;
  389. }
  390. Ogre::SceneNode* node = scene_node_->createChildSceneNode("bg_" + name);
  391. background_3d_ = new EntityModel(name, file_name, node);
  392. background_3d_->SetPosition(Ogre::Vector3(0, 0, 0));
  393. background_3d_->SetRotation(Ogre::Degree(0));
  394. background_3d_->setScale(Ogre::Vector3(SCENE_SCALE, SCENE_SCALE, SCENE_SCALE));
  395. background_3d_->SetIndex(IsBattleModule() ? BATTLE_BACKGROUND_ID : WORLD_MAP_BACKGROUND_ID);
  396. background_3d_->SetVisible(true);
  397. // Backgrounds must be reoriented.
  398. node->setOrientation(1, 1, 0, 0);
  399. // Probably don't need a script for the 3d background.
  400. /*ScriptManager::getSingleton().AddEntity(
  401. ScriptManager::BATTLE, background_3d_->GetName(), background_3d_
  402. );*/
  403. }
  404. void EntityManager::UpdateDebug(){
  405. grid_->setVisible(cv_debug_grid.GetB());
  406. axis_->setVisible(cv_debug_axis.GetB());
  407. if (module_ == Module::BATTLE){
  408. if (background_3d_ != nullptr) background_3d_->UpdateDebug();
  409. for (unsigned int i = 0; i < battle_entity_.size(); ++ i) battle_entity_[i]->UpdateDebug();
  410. }
  411. else{
  412. for (unsigned int i = 0; i < entity_.size(); ++ i) entity_[i]->UpdateDebug();
  413. for (unsigned int i = 0; i < entity_triggers_.size(); ++ i)
  414. entity_triggers_[i]->UpdateDebug();
  415. for (unsigned int i = 0; i < entity_points_.size(); ++ i) entity_points_[i]->UpdateDebug();
  416. walkmesh_.UpdateDebug();
  417. background_2d_.UpdateDebug();
  418. }
  419. }
  420. void EntityManager::OnResize(){background_2d_.OnResize();}
  421. void EntityManager::ClearField(){
  422. walkmesh_.Clear();
  423. background_2d_.Clear();
  424. screen_fade_.Clear();
  425. DialogsManager::getSingleton().Clear();
  426. for (unsigned int i = 0; i < entity_.size(); ++ i){
  427. ScriptManager::getSingleton().RemoveEntity(ScriptManager::ENTITY, entity_[i]->GetName());
  428. delete entity_[i];
  429. }
  430. entity_.clear();
  431. player_entity_ = nullptr;
  432. player_move_ = Ogre::Vector3::ZERO;
  433. player_move_rotation_ = 0;
  434. player_lock_ = false;
  435. for (unsigned int i = 0; i < entity_triggers_.size(); ++ i){
  436. ScriptManager::getSingleton().RemoveEntity(
  437. ScriptManager::ENTITY, entity_triggers_[i]->GetName()
  438. );
  439. delete entity_triggers_[i];
  440. }
  441. entity_triggers_.clear();
  442. for (unsigned int i = 0; i < entity_points_.size(); ++ i) delete entity_points_[i];
  443. entity_points_.clear();
  444. for (unsigned int i = 0; i < entity_scripts_.size(); ++ i)
  445. ScriptManager::getSingleton().RemoveEntity(ScriptManager::ENTITY, entity_scripts_[i]);
  446. scene_node_->removeAndDestroyAllChildren();
  447. }
  448. void EntityManager::ClearBattle(){
  449. for (unsigned int i = 0; i < battle_entity_.size(); ++ i){
  450. ScriptManager::getSingleton().RemoveEntity(
  451. ScriptManager::ENTITY, battle_entity_[i]->GetName()
  452. );
  453. Ogre::Root::getSingleton().getSceneManager("Scene")->destroyEntity(
  454. battle_entity_[i]->GetName()
  455. );
  456. scene_node_->removeAndDestroyChild("Battle_" + battle_entity_[i]->GetName());
  457. }
  458. battle_entity_.clear();
  459. if (background_3d_ != nullptr){
  460. Ogre::Root::getSingleton().getSceneManager("Scene")->destroyEntity(
  461. "bg_" + background_3d_->GetName()
  462. );
  463. /*ScriptManager::getSingleton().RemoveEntity(
  464. ScriptManager::ENTITY, background_3d_->GetName()
  465. );*/
  466. scene_node_->getChild("bg_" + background_3d_->GetName())->removeAllChildren();
  467. scene_node_->removeAndDestroyChild("bg_" + background_3d_->GetName());
  468. Ogre::Root::getSingleton().getSceneManager("Scene")->destroyEntity(
  469. background_3d_->GetName()
  470. );
  471. background_3d_ = nullptr;
  472. }
  473. }
  474. void EntityManager::ClearWorld(){
  475. walkmesh_.Clear();
  476. for (Entity* entity : entity_){
  477. ScriptManager::getSingleton().RemoveEntity(ScriptManager::ENTITY, entity->GetName());
  478. delete entity;
  479. }
  480. entity_.clear();
  481. player_entity_ = nullptr;
  482. player_move_ = Ogre::Vector3::ZERO;
  483. player_move_rotation_ = 0;
  484. player_lock_ = false;
  485. player_run_ = false;
  486. for (EntityTrigger* trigger : entity_triggers_){
  487. ScriptManager::getSingleton().RemoveEntity(ScriptManager::ENTITY, trigger->GetName());
  488. delete trigger;
  489. }
  490. entity_triggers_.clear();
  491. for (EntityPoint* point : entity_points_) delete point;
  492. entity_points_.clear();
  493. for (const Ogre::String& script : entity_scripts_){
  494. ScriptManager::getSingleton().RemoveEntity(ScriptManager::ENTITY, script);
  495. }
  496. entity_scripts_.clear();
  497. scene_node_->removeAndDestroyAllChildren();
  498. }
  499. Walkmesh* EntityManager::GetWalkmesh(){return &walkmesh_;}
  500. bool EntityManager::IsWorldPositionBlocked(
  501. const Entity* moving_entity, const Ogre::Vector3& position
  502. ) const{
  503. if (!IsWorldModule() || moving_entity == nullptr) return false;
  504. for (const Entity* other : entity_){
  505. if (other == moving_entity || !other->IsSolid()) continue;
  506. const Ogre::Vector3 other_position = other->GetPosition();
  507. const Ogre::Real dx = position.x - other_position.x;
  508. const Ogre::Real dz = position.z - other_position.z;
  509. const Ogre::Real radius = moving_entity->GetSolidRadius() + other->GetSolidRadius();
  510. if (dx * dx + dz * dz >= radius * radius) continue;
  511. const Ogre::Real moving_top = position.y + moving_entity->GetHeight();
  512. const Ogre::Real other_top = other_position.y + other->GetHeight();
  513. if (position.y < other_top && other_position.y < moving_top) return true;
  514. }
  515. return false;
  516. }
  517. Background2D* EntityManager::GetBackground2D(){return &background_2d_;}
  518. ScreenFade* EntityManager::GetScreenFade(){return &screen_fade_;}
  519. void EntityManager::AddEntity(
  520. const Ogre::String& name, const Ogre::String& file_name,
  521. const Ogre::Vector3& position, const Ogre::Degree& rotation, int index
  522. ){
  523. AddEntity(
  524. name, file_name, position, rotation,
  525. Ogre::Vector3::UNIT_SCALE, Ogre::Quaternion::IDENTITY, index
  526. );
  527. }
  528. void EntityManager::AddEntity(
  529. const Ogre::String& name, const Ogre::String& file_name, const Ogre::Vector3& position,
  530. const Ogre::Degree& rotation, const Ogre::Vector3& scale,
  531. const Ogre::Quaternion& root_orientation, const int index
  532. ){
  533. if (IsBattleModule())
  534. AddBattleEntity(name, file_name, position, rotation, scale, root_orientation, index);
  535. else
  536. AddFieldOrWorldMapEntity(
  537. name, file_name, position, rotation, scale, root_orientation, index
  538. );
  539. }
  540. void EntityManager::ScriptAddEntity(
  541. const char* name, const char* file_name,
  542. const float x, const float y, const float z, const float rotation, int index
  543. ){AddEntity(name, file_name, Ogre::Vector3(x, y, z), Ogre::Degree(rotation), index);}
  544. void EntityManager::AddEntityTrigger(
  545. const Ogre::String& name,
  546. const Ogre::Vector3& point1, const Ogre::Vector3& point2, const bool enabled
  547. ){
  548. if (IsBattleModule()){
  549. LOG_WARNING("Tried to add an entity trigger but the EntityManager is in battle mode.");
  550. return;
  551. }
  552. EntityTrigger* trigger = new EntityTrigger(name);
  553. trigger->SetPoints(point1, point2);
  554. trigger->SetEnabled(enabled);
  555. entity_triggers_.push_back(trigger);
  556. ScriptManager::getSingleton().AddEntity(ScriptManager::ENTITY, trigger->GetName(), nullptr);
  557. }
  558. void EntityManager::AddEntityPoint(
  559. const Ogre::String& name, const Ogre::Vector3& position, const float rotation
  560. ){
  561. if (IsBattleModule()){
  562. LOG_WARNING("Tried to add an entity point but the EntityManager is in battle mode.");
  563. return;
  564. }
  565. EntityPoint* entity_point = new EntityPoint(name);
  566. entity_point->SetPosition(position);
  567. entity_point->SetRotation(rotation);
  568. entity_points_.push_back(entity_point);
  569. }
  570. void EntityManager::AddEntityScript(const Ogre::String& name){
  571. // TODO: Should call to this be prevented while in battle mode?
  572. entity_scripts_.push_back(name);
  573. ScriptManager::getSingleton().AddEntity(ScriptManager::ENTITY, name, nullptr);
  574. }
  575. void EntityManager::ScriptAddEntityScript(const char* name){AddEntityScript(name);}
  576. Entity* EntityManager::GetEntity(const Ogre::String& name) const{
  577. if (IsBattleModule()){
  578. for (unsigned int i = 0; i < battle_entity_.size(); ++ i)
  579. if (battle_entity_[i]->GetName() == name) return battle_entity_[i];
  580. }
  581. else{
  582. for (unsigned int i = 0; i < entity_.size(); ++ i)
  583. if (entity_[i]->GetName() == name) return entity_[i];
  584. }
  585. return nullptr;
  586. }
  587. Entity* EntityManager::GetEntityFromIndex(const int index) const{
  588. if (IsBattleModule()){
  589. if (background_3d_ != nullptr && background_3d_->GetIndex() == index)
  590. return background_3d_;
  591. for (unsigned int i = 0; i < battle_entity_.size(); ++ i)
  592. if (battle_entity_[i]->GetIndex() == index) return battle_entity_[i];
  593. }
  594. else{
  595. for (unsigned int i = 0; i < entity_.size(); ++ i)
  596. if (entity_[i]->GetIndex() == index) return entity_[i];
  597. }
  598. return nullptr;
  599. }
  600. Entity* EntityManager::GetEntityFromCharacterId(const int id) const{
  601. if (IsBattleModule()){
  602. for (unsigned int i = 0; i < battle_entity_.size(); ++ i)
  603. if (battle_entity_[i]->IsCharacter() && battle_entity_[i]->GetCharacterId() == id)
  604. return battle_entity_[i];
  605. }
  606. else{
  607. for (unsigned int i = 0; i < entity_.size(); ++ i)
  608. if (entity_[i]->IsCharacter() && entity_[i]->GetCharacterId() == id) return entity_[i];
  609. }
  610. return nullptr;
  611. }
  612. Entity* EntityManager::ScriptGetEntity(const char* name) const{
  613. return GetEntity(Ogre::String(name));
  614. }
  615. EntityPoint* EntityManager::ScriptGetEntityPoint(const char* name) const{
  616. for (unsigned int i = 0; i < entity_points_.size(); ++ i)
  617. if (entity_points_[i]->GetName() == name) return entity_points_[i];
  618. return nullptr;
  619. }
  620. void EntityManager::ScriptSetPlayerEntity(const char* name){
  621. if (IsBattleModule()){
  622. LOG_WARNING("Tried to set a player entity but the EntityManager is in battle mode.");
  623. return;
  624. }
  625. for (unsigned int i = 0; i < entity_.size(); ++ i){
  626. if (entity_[i]->GetName() == name){
  627. player_entity_ = entity_[i];
  628. // Also, make is solid, visible, and non-talkable.
  629. entity_[i]->SetSolid(true);
  630. entity_[i]->SetVisible(true);
  631. entity_[i]->SetTalkable(false);
  632. }
  633. }
  634. }
  635. void EntityManager::ScriptPlacePlayerAtFieldEntry(
  636. const float x, const float y, const int triangle_id, const float direction
  637. ){
  638. if (player_entity_ == nullptr || walkmesh_.GetNumberOfTriangles() <= 0) return;
  639. int safe_triangle_id = triangle_id;
  640. if (safe_triangle_id < 0 || safe_triangle_id >= walkmesh_.GetNumberOfTriangles()){
  641. LOG_WARNING("World-map field entry has an invalid walkmesh triangle; using triangle 0.");
  642. safe_triangle_id = 0;
  643. }
  644. player_entity_->SetPosition(Ogre::Vector3(
  645. x, y, walkmesh_.GetA(static_cast<unsigned int>(safe_triangle_id)).z
  646. ));
  647. player_entity_->SetRotation(Ogre::Degree(direction));
  648. player_entity_->SetMoveTriangleId(safe_triangle_id);
  649. player_entity_->SetState(Entity::WALKMESH);
  650. }
  651. Entity* EntityManager::ScriptGetPlayerEntity() const{
  652. if (IsBattleModule()){
  653. LOG_WARNING("Tried to set a player entity but the EntityManager is in battle mode.");
  654. return nullptr;
  655. }
  656. return player_entity_;
  657. }
  658. void EntityManager::ScriptUnsetPlayerEntity(){
  659. if (IsBattleModule()){
  660. LOG_WARNING("Tried to unset a player entity but the EntityManager is in battle mode.");
  661. return;
  662. }
  663. player_entity_ = nullptr;
  664. }
  665. void EntityManager::ScriptPlayerLock(const bool lock){
  666. if (IsBattleModule()){
  667. LOG_WARNING("Tried to set player lock but the EntityManager is in battle mode.");
  668. return;
  669. }
  670. player_lock_ = lock;
  671. if (lock == true) player_move_ = Ogre::Vector3::ZERO;
  672. }
  673. void EntityManager::SetPlayerMoveRotation(const Ogre::Radian rotation){
  674. if (IsBattleModule()){
  675. LOG_WARNING("Tried to set player move rotation the EntityManager is in battle mode.");
  676. return;
  677. }
  678. player_move_rotation_ = rotation;
  679. }
  680. bool EntityManager::GetRandomEncounters(){return random_encounters_;}
  681. void EntityManager::SetRandomEncounters(bool active){random_encounters_ = active;}
  682. float EntityManager::GetEncounterRate(){return encounter_rate_;}
  683. void EntityManager::SetEncounterRate(float rate){
  684. if (rate >= 1.0f) encounter_rate_ = 1.0f;
  685. else if (rate <= 0.0f) encounter_rate_ = 0.0f;
  686. else encounter_rate_ = rate;
  687. }
  688. bool EntityManager::IsKeyOn(unsigned int key_code){
  689. // If the player is locked, always false.
  690. // TODO: Maybe this will interfere with something down the road?
  691. // Some scene where the player can't move but must press a button?
  692. if (player_lock_) return false;
  693. // The key code of the scripts is a mask of the pad buttons, and the check is true if any of
  694. // them is pressed. Translate each to its key. For example 32 is "Circle/Action", the space bar.
  695. // TODO: Get values from config.lua
  696. static const struct{unsigned int mask; int key;} KEYS[] = {
  697. {4, OIS::KC_PGUP}, {8, OIS::KC_PGDOWN}, {32, OIS::KC_SPACE}, {64, OIS::KC_ESCAPE},
  698. {4096, OIS::KC_UP}, {8192, OIS::KC_RIGHT}, {16384, OIS::KC_DOWN}, {32768, OIS::KC_LEFT}
  699. };
  700. for (const auto& entry : KEYS)
  701. if ((key_code & entry.mask) && InputManager::getSingleton().IsButtonPressed(entry.key))
  702. return true;
  703. return false;
  704. }
  705. bool EntityManager::IsKeyOff(unsigned int key_code){return !IsKeyOn(key_code);}
  706. void EntityManager::SetEntityToCharacter(const char* entity_name, unsigned int char_id){
  707. if (IsBattleModule()){
  708. for (unsigned int i = 0; i < battle_entity_.size(); ++ i){
  709. if (battle_entity_[i]->GetName() == entity_name){
  710. battle_entity_[i]->SetCharacter(char_id);
  711. return;
  712. }
  713. }
  714. }
  715. else{
  716. for (unsigned int i = 0; i < entity_.size(); ++ i){
  717. if (entity_[i]->GetName() == entity_name){
  718. entity_[i]->SetCharacter(char_id);
  719. return;
  720. }
  721. }
  722. }
  723. LOG_WARNING(
  724. "Unabe to assigne character ID " + std::to_string(char_id) + " to entity '" + entity_name
  725. + "'. No entity by that name exists."
  726. );
  727. }
  728. bool EntityManager::SetEntityOnWalkmesh(Entity* entity){
  729. if (IsBattleModule()){
  730. LOG_WARNING("Tried to set entity on the walkmesh, but the EntityManager is in battle mode");
  731. return false;
  732. }
  733. Ogre::Vector3 position3 = entity->GetPosition();
  734. Ogre::Vector2 position2;
  735. position2.x = position3.x;
  736. position2.y = position3.y;
  737. std::vector<std::pair<int, float>> triangles;
  738. // Search for possible triangles.
  739. for (int i = 0; i < walkmesh_.GetNumberOfTriangles(); ++ i){
  740. Ogre::Vector3 A3 = walkmesh_.GetA(i);
  741. Ogre::Vector3 B3 = walkmesh_.GetB(i);
  742. Ogre::Vector3 C3 = walkmesh_.GetC(i);
  743. Ogre::Vector2 A2(A3.x, A3.y);
  744. Ogre::Vector2 B2(B3.x, B3.y);
  745. Ogre::Vector2 C2(C3.x, C3.y);
  746. if (Ogre::Math::pointInTri2D(position2, A2, B2, C2) == true){
  747. triangles.push_back(std::make_pair(i, PointElevation(
  748. position2, walkmesh_.GetA(i), walkmesh_.GetB(i), walkmesh_.GetC(i)
  749. )));
  750. }
  751. }
  752. // If the coordinates doesn't match any triangle, exit.
  753. if (triangles.size() == 0 && entity == player_entity_){
  754. LOG_ERROR(
  755. "Can't find any triangle to place entity '" + entity->GetName() + "' on walkmesh."
  756. );
  757. return false;
  758. }
  759. // From the possible triangles, select the closest one (on the Z edge).
  760. int closest_z_triangle = -1;
  761. float closest_z_distance = 9999.0f;
  762. float pos_z = position3.z;
  763. for (size_t i = 0; i < triangles.size(); ++ i){
  764. if (std::abs(pos_z - triangles[i].second) < closest_z_distance){
  765. closest_z_triangle = triangles[i].first;
  766. closest_z_distance = std::abs(pos_z - triangles[i].second);
  767. }
  768. }
  769. if (closest_z_triangle == -1 && entity == player_entity_){
  770. LOG_ERROR(
  771. "Can't find nearby triangle to place entity '" + entity->GetName() + "' on walkmesh."
  772. );
  773. return false;
  774. }
  775. entity->SetPosition(Ogre::Vector3(position2.x, position2.y, pos_z));
  776. entity->SetMoveTriangleId(closest_z_triangle);
  777. return true;
  778. }
  779. float EntityManager::TriggerReach(float solid_radius){
  780. // The radius an entity has when a script doesn't change it.
  781. const float default_radius = 0.21f;
  782. return solid_radius < 0.01f ? default_radius : solid_radius;
  783. }
  784. bool EntityManager::WalkmeshEdgeBlocks(bool is_player, bool scripted_move){
  785. return is_player || !scripted_move;
  786. }
  787. bool EntityManager::IsBetterInteractionTarget(
  788. float angle, float distance, float best_angle, float best_distance
  789. ){
  790. const float same_angle = 0.001f;
  791. if (angle < best_angle - same_angle) return true;
  792. return std::fabs(angle - best_angle) <= same_angle && distance < best_distance;
  793. }
  794. float EntityManager::ScriptedMoveStep(float distance, float stop_distance, float max_step){
  795. return std::min(max_step, std::max(0.0f, distance - stop_distance));
  796. }
  797. bool EntityManager::PerformWalkmeshMove(Entity* entity, const float speed, const float delta_time){
  798. if (IsBattleModule()){
  799. LOG_WARNING("Tried to perform a walkmesh move, but the EntityManager is in battle mode");
  800. return false;
  801. }
  802. Ogre::Vector3 start_point = entity->GetPosition();
  803. Ogre::Vector3 move_vector = entity->GetMovePosition() - start_point;
  804. Ogre::Vector2 direction(move_vector.x, move_vector.y);
  805. const float distance_to_target = direction.length();
  806. const bool scripted_move = entity->IsScriptedMove();
  807. const float stop_distance = entity->GetMoveStopDistance();
  808. if (scripted_move && distance_to_target <= stop_distance + 0.0001f){
  809. entity->UnsetMove();
  810. return false;
  811. }
  812. direction.normalise();
  813. direction *= delta_time;
  814. direction *= speed;
  815. if (scripted_move && !direction.isZeroLength()){
  816. direction.normalise();
  817. direction *= ScriptedMoveStep(
  818. distance_to_target, stop_distance, speed * delta_time
  819. );
  820. }
  821. // If movement is still needed but speed or time don't allow it, just return for now.
  822. if (direction.isZeroLength() == true){
  823. if (player_entity_ == entity) CheckTriggers(entity, entity->GetPosition());
  824. return false;
  825. }
  826. int current_triangle = entity->GetMoveTriangleId();
  827. if (current_triangle == -1){
  828. LOG_ERROR("Entity '" + entity->GetName() + "' not placed on walkmesh and can't move.");
  829. return false;
  830. }
  831. Ogre::Vector3 rotation(0.0f, 0.0f, 0.0f);
  832. Ogre::Quaternion q1(0.0f, 0.0f, 0.0f, 1.0f);
  833. Ogre::Vector3 end_point(0.0f, 0.0f, 0.0f);
  834. Ogre::Vector3 end_point2(0.0f, 0.0f, 0.0f);
  835. bool first_triangle_check = false;
  836. bool second_triangle_check = false;
  837. bool third_triangle_check = false;
  838. bool last_triangle_check = false;
  839. bool first_entity_check = false;
  840. bool second_entity_check = false;
  841. bool third_entity_check = false;
  842. // Shorten move vector by triangle angle
  843. end_point.x = start_point.x + direction.x;
  844. end_point.y = start_point.y + direction.y;
  845. Ogre::Vector3 A3 = walkmesh_.GetA(current_triangle);
  846. Ogre::Vector3 B3 = walkmesh_.GetB(current_triangle);
  847. Ogre::Vector3 C3 = walkmesh_.GetC(current_triangle);
  848. end_point.z = PointElevation(Ogre::Vector2(end_point.x, end_point.y), A3, B3, C3);
  849. Ogre::Vector3 temp = end_point - start_point;
  850. temp.normalise();
  851. temp = temp * direction.length();
  852. direction.x = temp.x;
  853. direction.y = temp.y;
  854. // Set the direction for the entity if it has to move.
  855. if (entity->GetMoveAutoRotation() == true){
  856. Ogre::Vector2 up(0.0f, -1.0f);
  857. // Angle between vectors
  858. Ogre::Degree angle(Ogre::Radian(acosf(
  859. direction.dotProduct(up) / (direction.length() * up.length())
  860. )));
  861. angle = (direction.x < 0) ? Ogre::Degree(360) - angle : angle;
  862. entity->SetRotation(Ogre::Degree(angle));
  863. }
  864. float solid = (entity->IsSolid() == true) ? entity->GetSolidRadius() : 0.01f;
  865. // For not playable entities, be a bit more lenient with solid collisions.
  866. // Don't use the solid radius.
  867. if (entity != player_entity_) solid /= 10;
  868. // Get ending point.
  869. end_point.z = start_point.z;
  870. for (
  871. int i = 0;
  872. (entity == player_entity_ && i < 16)
  873. || (entity == player_entity_ && i < 3)
  874. || (entity != player_entity_ && i <= 16);
  875. ++ i
  876. ){
  877. end_point = Ogre::Vector3(
  878. start_point.x + direction.x, start_point.y + direction.y, start_point.z
  879. );
  880. // 1st check.
  881. // Rotate move_vector +45.
  882. q1.FromAngleAxis(Ogre::Radian(Ogre::Degree(45)), Ogre::Vector3::UNIT_Z);
  883. rotation.x = direction.x;
  884. rotation.y = direction.y;
  885. rotation.z = 0;
  886. rotation.normalise();
  887. rotation = q1 * rotation;
  888. // Multiply move_vector by solid range
  889. rotation = rotation * solid;
  890. end_point2.x = end_point.x + rotation.x;
  891. end_point2.y = end_point.y + rotation.y;
  892. // Check_triangle.
  893. first_triangle_check = WalkmeshBorderCross(entity, end_point2, direction);
  894. entity->SetMoveTriangleId(current_triangle);
  895. // Model check.
  896. first_entity_check = CheckSolidCollisions(entity, end_point2);
  897. // 2nd check.
  898. // Rotate move_vector +45.
  899. q1.FromAngleAxis(Ogre::Radian(Ogre::Degree(-45)), Ogre::Vector3::UNIT_Z);
  900. rotation.x = direction.x;
  901. rotation.y = direction.y;
  902. rotation.z = 0;
  903. rotation.normalise();
  904. rotation = q1 * rotation;
  905. // Multiply move_vector by solid range.
  906. rotation = rotation * solid;
  907. end_point2.x = end_point.x + rotation.x;
  908. end_point2.y = end_point.y + rotation.y;
  909. // Check triangle.
  910. second_triangle_check = WalkmeshBorderCross(entity, end_point2, direction);
  911. entity->SetMoveTriangleId(current_triangle);
  912. // Model check.
  913. second_entity_check = CheckSolidCollisions(entity, end_point2);
  914. // 3rd check.
  915. rotation.x = direction.x;
  916. rotation.y = direction.y;
  917. rotation.z = 0;
  918. rotation.normalise();
  919. rotation = rotation * solid;
  920. end_point2.x = end_point.x + rotation.x;
  921. end_point2.y = end_point.y + rotation.y;
  922. // Check triangle.
  923. third_triangle_check = WalkmeshBorderCross(entity, end_point2, direction);
  924. entity->SetMoveTriangleId(current_triangle);
  925. // Model check.
  926. third_entity_check = CheckSolidCollisions(entity, end_point2);
  927. // Check condition and modify move_vector.
  928. if (
  929. first_triangle_check != false || second_triangle_check != false
  930. || third_triangle_check != false || first_entity_check != false
  931. || second_entity_check != false || third_entity_check != false
  932. ){
  933. // Only for NPC.
  934. if (entity != player_entity_){
  935. // If the entity collides only directly into a triangle border.
  936. if (
  937. first_triangle_check == false
  938. && second_triangle_check == false
  939. && third_triangle_check != false
  940. ){
  941. q1.FromAngleAxis(Ogre::Radian(Ogre::Degree(-7)), Ogre::Vector3::UNIT_Z);
  942. rotation.x = direction.x;
  943. rotation.y = direction.y;
  944. rotation = q1 * rotation;
  945. direction.x = rotation.x;
  946. direction.y = rotation.y;
  947. }
  948. // Or if the entity only collides into other entity directly.
  949. else if (
  950. first_entity_check == false && second_entity_check == false
  951. && third_entity_check != false
  952. ){
  953. q1.FromAngleAxis(Ogre::Radian(Ogre::Degree(-11.25f)), Ogre::Vector3::UNIT_Z);
  954. rotation.x = direction.x;
  955. rotation.y = direction.y;
  956. rotation = q1 * rotation;
  957. direction.x = rotation.x;
  958. direction.y = rotation.y;
  959. }
  960. // If not both left and right check failed.
  961. if (first_triangle_check == false || second_triangle_check == false){
  962. if (
  963. (first_triangle_check == false && first_entity_check != false)
  964. || (first_triangle_check != false && second_triangle_check == false)
  965. ){
  966. q1.FromAngleAxis(
  967. Ogre::Radian(Ogre::Degree(-11.25f)), Ogre::Vector3::UNIT_Z
  968. );
  969. rotation.x = direction.x;
  970. rotation.y = direction.y;
  971. rotation = q1 * rotation;
  972. direction.x = rotation.x;
  973. direction.y = rotation.y;
  974. }
  975. if (
  976. first_triangle_check == false
  977. && first_entity_check == false
  978. && (second_triangle_check != false || second_entity_check != false
  979. )
  980. ){
  981. q1.FromAngleAxis(Ogre::Radian(Ogre::Degree(11.25f)), Ogre::Vector3::UNIT_Z);
  982. rotation.x = direction.x;
  983. rotation.y = direction.y;
  984. rotation = q1 * rotation;
  985. direction.x = rotation.x;
  986. direction.y = rotation.y;
  987. }
  988. continue;
  989. }
  990. break;
  991. }
  992. // Only for playable character.
  993. else{
  994. if (
  995. first_entity_check == false
  996. && second_entity_check == false
  997. && third_entity_check == false
  998. ){
  999. // If not both left and right check failed
  1000. if (first_triangle_check == false || second_triangle_check == false){
  1001. if (first_triangle_check != false && second_triangle_check == false){
  1002. q1.FromAngleAxis(
  1003. Ogre::Radian(Ogre::Degree(-11.25f)), Ogre::Vector3::UNIT_Z
  1004. );
  1005. rotation.x = direction.x;
  1006. rotation.y = direction.y;
  1007. rotation = q1 * rotation;
  1008. direction.x = rotation.x;
  1009. direction.y = rotation.y;
  1010. }
  1011. if (first_triangle_check == false && second_triangle_check != false){
  1012. q1.FromAngleAxis(
  1013. Ogre::Radian(Ogre::Degree(11.25f)), Ogre::Vector3::UNIT_Z
  1014. );
  1015. rotation.x = direction.x;
  1016. rotation.y = direction.y;
  1017. rotation = q1 * rotation;
  1018. direction.x = rotation.x;
  1019. direction.y = rotation.y;
  1020. }
  1021. continue;
  1022. }
  1023. break;
  1024. }
  1025. }
  1026. }
  1027. }
  1028. // Set new X, Y and Z
  1029. last_triangle_check = WalkmeshBorderCross(entity, end_point, direction);
  1030. if (
  1031. first_triangle_check != false || second_triangle_check != false
  1032. || third_triangle_check != false || last_triangle_check != false
  1033. || first_entity_check != false || second_entity_check != false
  1034. || third_entity_check != false
  1035. ){
  1036. // Event if the entity can't move, check for triggers, but use current position.
  1037. if (player_entity_ == entity) CheckTriggers(entity, entity->GetPosition());
  1038. return false;
  1039. }
  1040. // Check triggers before set entity position because move line is checked.
  1041. if (player_entity_ == entity) CheckTriggers(entity, end_point);
  1042. entity->SetPosition(end_point);
  1043. // If the entity has come to destination point, finish movement.
  1044. Ogre::Vector3 final = entity->GetMovePosition() - end_point;
  1045. const float tolerance = scripted_move ? 0.0001f : speed / 10;
  1046. if (Ogre::Vector2(final.x, final.y).length() <= stop_distance + tolerance)
  1047. entity->UnsetMove();
  1048. return true;
  1049. }
  1050. bool EntityManager::WalkmeshBorderCross(
  1051. Entity* entity, Ogre::Vector3& position, const Ogre::Vector2& move_vector
  1052. ){
  1053. if (IsBattleModule()){
  1054. LOG_WARNING("Tried to check for walkmesh cross, but the EntityManager is in battle mode");
  1055. return false;
  1056. }
  1057. int current_triangle = entity->GetMoveTriangleId();
  1058. if (current_triangle == -1) return true;
  1059. const bool free_walk = !WalkmeshEdgeBlocks(entity == player_entity_, entity->IsScriptedMove());
  1060. Ogre::Vector2 pos = Ogre::Vector2(position.x, position.y);
  1061. for (;;){
  1062. Ogre::Vector3 A3 = walkmesh_.GetA(current_triangle);
  1063. Ogre::Vector3 B3 = walkmesh_.GetB(current_triangle);
  1064. Ogre::Vector3 C3 = walkmesh_.GetC(current_triangle);
  1065. Ogre::Vector2 A(A3.x, A3.y);
  1066. Ogre::Vector2 B(B3.x, B3.y);
  1067. Ogre::Vector2 C(C3.x, C3.y);
  1068. float sign1 = SideOfVector(pos, B, A);
  1069. float sign2 = SideOfVector(pos, C, B);
  1070. float sign3 = SideOfVector(pos, A, C);
  1071. int next_triangle = -1;
  1072. if (sign1 < 0) next_triangle = walkmesh_.GetAccessSide(current_triangle, 0);
  1073. else if (sign2 < 0) next_triangle = walkmesh_.GetAccessSide(current_triangle, 1);
  1074. else if (sign3 < 0) next_triangle = walkmesh_.GetAccessSide(current_triangle, 2);
  1075. else{
  1076. position.z = PointElevation(pos, A3, B3, C3);
  1077. entity->SetMoveTriangleId(current_triangle);
  1078. return false;
  1079. }
  1080. if (next_triangle >= 0){
  1081. bool lock = walkmesh_.IsLocked(next_triangle);
  1082. if (lock == false || free_walk){
  1083. current_triangle = next_triangle;
  1084. continue;
  1085. }
  1086. }
  1087. position.z = PointElevation(pos, A3, B3, C3);
  1088. entity->SetMoveTriangleId(current_triangle);
  1089. // A walk of a script goes on over the edge, keeping the last triangle.
  1090. return !free_walk;
  1091. }
  1092. }
  1093. bool EntityManager::CheckSolidCollisions(Entity* entity, Ogre::Vector3& position){
  1094. if (IsBattleModule()){
  1095. LOG_WARNING("Tried to check for solid collisions, but the EntityManager is in battle mode");
  1096. return false;
  1097. }
  1098. if (entity->IsSolid() == false) return false;
  1099. for (size_t i = 0; i < entity_.size(); ++ i){
  1100. if (entity_[i]->IsSolid() == false) continue;
  1101. if (entity_[i] == entity) continue;
  1102. Ogre::Vector3 pos1 = entity_[i]->GetPosition();
  1103. float solid_range = entity_[i]->GetSolidRadius();
  1104. solid_range *= solid_range;
  1105. float height = (pos1.z < position.z) ? entity_[i]->GetHeight() : entity->GetHeight();
  1106. if (
  1107. ((pos1.z - position.z + height) < (height * 2)) && ((pos1.z - position.z + height) >= 0)
  1108. ){
  1109. float distance
  1110. = (pos1.x - position.x) * (pos1.x - position.x)
  1111. + (pos1.y - position.y) * (pos1.y - position.y);
  1112. if (distance < solid_range) return true;
  1113. }
  1114. }
  1115. return false;
  1116. }
  1117. void EntityManager::CheckTriggers(Entity* entity, const Ogre::Vector3& position){
  1118. if (IsBattleModule()){
  1119. LOG_WARNING("Tried to check for triggers, but the EntityManager is in battle mode");
  1120. return;
  1121. }
  1122. if (entity->IsSolid() == false) return;
  1123. if (player_entity_ != entity) return;
  1124. if (player_entity_->IsSolid() == false) return;
  1125. if (player_lock_) return;
  1126. bool is_moving = true;
  1127. if (
  1128. std::fabs(entity->GetPosition().x - position.x) < 0.005f
  1129. && std::fabs(entity->GetPosition().y - position.y) < 0.005f
  1130. && std::fabs(entity->GetPosition().z - position.z) < 0.005f
  1131. ){
  1132. is_moving = false;
  1133. }
  1134. for (unsigned int i = 0; i < entity_triggers_.size(); ++ i){
  1135. ScriptEntity* trigger = ScriptManager::getSingleton().GetScriptEntityByName(
  1136. ScriptManager::ENTITY, entity_triggers_[i]->GetName()
  1137. );
  1138. if (trigger != nullptr && entity_triggers_[i]->IsEnabled() == true){
  1139. Ogre::Vector3 point_a = entity_triggers_[i]->GetPoint1();
  1140. Ogre::Vector3 point_b = entity_triggers_[i]->GetPoint2();
  1141. Ogre::Vector3 entity_position = entity->GetPosition();
  1142. Ogre::Vector3 proj;
  1143. // Calculate distance
  1144. float square_dist = SquareDistanceToLine(entity_position, point_a, point_b, proj);
  1145. float solid_radius = TriggerReach(entity->GetSolidRadius());
  1146. // Calculate direction.
  1147. const Ogre::Degree direction_to_line = GetDirectionToPoint(entity_position, proj);
  1148. const Ogre::Degree destination_direction_to_line = GetDirectionToPoint(position, proj);
  1149. const Ogre::Degree movement_direction = entity->GetRotation();
  1150. Ogre::Degree angle = direction_to_line - movement_direction + Ogre::Degree(90);
  1151. angle = (angle > Ogre::Degree(360)) ? angle - Ogre::Degree(360) : angle;
  1152. // Check on enter line.
  1153. // Must happen only once when the solid radius touches the line, while facing the line,
  1154. // while the entity is manually moving, and only if not already triggered.
  1155. if (
  1156. square_dist != -1 && square_dist <= solid_radius * solid_radius
  1157. && angle < Ogre::Degree(180) && angle > Ogre::Degree(0)
  1158. && entity_triggers_[i]->CheckApproached() == false
  1159. && is_moving
  1160. ){
  1161. entity_triggers_[i]->SetApproached(true);
  1162. //std::cout << " [TRIGGER] " << entity->GetName() << " on_approach "
  1163. // << entity_triggers_[i]->GetName() << std::endl;
  1164. ScriptManager::getSingleton().ScriptRequest(
  1165. trigger, "on_approach", 1, entity->GetName(), "", false, false
  1166. );
  1167. }
  1168. // Check on move to line.
  1169. // Must happen only once when the entity center touches the line, if the entity has
  1170. // previously entered the line.
  1171. if (
  1172. square_dist != -1 && square_dist < 1
  1173. && entity_triggers_[i]->CheckCrossed() == false
  1174. && entity_triggers_[i]->CheckApproached() == true
  1175. ){
  1176. entity_triggers_[i]->SetCrossed(true);
  1177. //std::cout << " [TRIGGER] " << entity->GetName() << " on_cross "
  1178. // << entity_triggers_[i]->GetName() << std::endl;
  1179. ScriptManager::getSingleton().ScriptRequest(
  1180. trigger, "on_cross", 1, entity->GetName(), "", false, false
  1181. );
  1182. }
  1183. // Check on cross line.
  1184. // Must happen on every frame while the entity solid radius collides with the line, if
  1185. // the entity has previously entered the line.
  1186. if (
  1187. square_dist != -1 && square_dist <= solid_radius * solid_radius
  1188. && entity_triggers_[i]->CheckApproached() == true
  1189. ){
  1190. // TODO: Fix this hack.
  1191. // After the on_near script is run, set a cooltime of 5 frames before running
  1192. // it again. This is because most of the time this trigger checks for a key, and
  1193. // if its pressed, is run multiple times.
  1194. if (entity_triggers_[i]->GetNearEventCooldown() == 0){
  1195. //std::cout << " [TRIGGER] " << entity->GetName()
  1196. // << " on_near " << entity_triggers_[i]->GetName() << std::endl;
  1197. ScriptManager::getSingleton().ScriptRequest(
  1198. trigger, "on_near", 1, entity->GetName(), "", true, true
  1199. );
  1200. entity_triggers_[i]->ResetNearEventCooldown();
  1201. }
  1202. else entity_triggers_[i]->DecreaseNearEventCooldown();
  1203. }
  1204. // Check on cross line once.
  1205. // The same as on cross line, but only once.
  1206. if (
  1207. square_dist != -1 && square_dist < solid_radius * solid_radius
  1208. && entity_triggers_[i]->CheckNearSingleEventTriggered() == false
  1209. && entity_triggers_[i]->CheckApproached() == true
  1210. ){
  1211. entity_triggers_[i]->SetNearSingleEventTriggered(true);
  1212. //std::cout << " [TRIGGER] " << entity->GetName()
  1213. // << " on_near_once " << entity_triggers_[i]->GetName() << std::endl;
  1214. ScriptManager::getSingleton().ScriptRequest(
  1215. trigger, "on_near_once", 1, entity->GetName(), "", false, false
  1216. );
  1217. }
  1218. // Check on leave line.
  1219. // Must be triggered once when the line is not in the entity solid radius, but only if
  1220. // on enter script has been triggered previously.
  1221. if (
  1222. square_dist != -1 && square_dist > solid_radius * solid_radius
  1223. && entity_triggers_[i]->CheckApproached()
  1224. ){
  1225. //std::cout << " [TRIGGER] " << entity->GetName() << " on_leave "
  1226. // << entity_triggers_[i]->GetName() << std::endl;
  1227. ScriptManager::getSingleton().ScriptRequest(
  1228. trigger, "on_leave", 1, entity->GetName(), "", false, false
  1229. );
  1230. }
  1231. // If the entity is far enough from the line, mark every trigger as inactive
  1232. if (square_dist == -1 || square_dist > solid_radius * solid_radius){
  1233. entity_triggers_[i]->Clear();
  1234. //std::cout << " [TRIGGER] " << entity->GetName() << " clear of "
  1235. // << entity_triggers_[i]->GetName() << std::endl;
  1236. }
  1237. }
  1238. }
  1239. }
  1240. void EntityManager::CheckEntityInteract(){
  1241. if (IsBattleModule()){
  1242. LOG_WARNING(
  1243. "Tried to check for entity interaction, but the EntityManager is in battle mode"
  1244. );
  1245. return;
  1246. }
  1247. if (player_entity_ == NULL || player_lock_ == true || player_entity_->IsSolid() == false)
  1248. return;
  1249. Ogre::Degree angle_pc = player_entity_->GetRotation();
  1250. Entity* entity_to_interact = NULL;
  1251. Ogre::Degree less_angle(90);
  1252. float best_distance = std::numeric_limits<float>::max();
  1253. Ogre::Real nearest_worldmap_distance = -1.0f;
  1254. for (unsigned int i = 0; i < entity_.size(); ++ i){
  1255. if (entity_[i]->IsTalkable() == false) continue;
  1256. if (entity_[i] == player_entity_) continue;
  1257. Ogre::Vector3 pos1 = entity_[i]->GetPosition();
  1258. float interact_range = entity_[i]->GetTalkRadius();
  1259. Ogre::Vector3 pos2 = player_entity_->GetPosition();
  1260. float solid_range = player_entity_->GetSolidRadius();
  1261. if (IsWorldModule()){
  1262. const Ogre::Real target_bottom = pos1.y;
  1263. const Ogre::Real player_bottom = pos2.y;
  1264. const Ogre::Real talk_range
  1265. = interact_range + solid_range + 0.05f;
  1266. const Ogre::Real distance
  1267. = (pos1.x - pos2.x) * (pos1.x - pos2.x)
  1268. + (pos1.z - pos2.z) * (pos1.z - pos2.z);
  1269. const bool height_overlap
  1270. = player_bottom <= target_bottom + entity_[i]->GetHeight()
  1271. && player_bottom + player_entity_->GetHeight() >= target_bottom;
  1272. if (
  1273. height_overlap && distance <= talk_range * talk_range
  1274. && (nearest_worldmap_distance < 0 || distance < nearest_worldmap_distance)
  1275. ){
  1276. entity_to_interact = entity_[i];
  1277. nearest_worldmap_distance = distance;
  1278. }
  1279. continue;
  1280. }
  1281. int height = (pos1.z < pos2.z) ? entity_[i]->GetHeight() : player_entity_->GetHeight();
  1282. if (((pos1.z - pos2.z + height) < (height * 2)) && ((pos1.z - pos2.z + height) >= 0)){
  1283. interact_range = (interact_range + solid_range) * (interact_range + solid_range);
  1284. float distance
  1285. = (pos1.x - pos2.x) * (pos1.x - pos2.x) + (pos1.y - pos2.y) * (pos1.y - pos2.y);
  1286. if (distance < interact_range + solid_range){
  1287. Ogre::Degree angle_to_model = GetDirectionToPoint(pos2, pos1);
  1288. Ogre::Degree angle = angle_pc - angle_to_model;
  1289. angle = (angle < Ogre::Degree(0)) ? -angle : angle;
  1290. angle = (angle >= Ogre::Degree(180)) ? Ogre::Degree(360) - angle : angle;
  1291. // With several entities in range, interact with the one the player faces most.
  1292. // Nobody 90 degrees or more away from where the player faces is considered.
  1293. if (
  1294. angle < Ogre::Degree(90) && IsBetterInteractionTarget(
  1295. angle.valueDegrees(), distance, less_angle.valueDegrees(), best_distance
  1296. )
  1297. ){
  1298. less_angle = angle;
  1299. best_distance = distance;
  1300. entity_to_interact = entity_[i];
  1301. }
  1302. }
  1303. }
  1304. }
  1305. if (entity_to_interact != NULL && entity_to_interact->IsLine() == false){
  1306. Ogre::String name = entity_to_interact->GetName();
  1307. ScriptEntity* scr_entity = ScriptManager::getSingleton().GetScriptEntityByName(
  1308. ScriptManager::ENTITY, name
  1309. );
  1310. bool added = ScriptManager::getSingleton().ScriptRequest(
  1311. scr_entity, "on_interact", 1, "", "", false, false
  1312. );
  1313. if (added == false){
  1314. LOG_WARNING("Script 'on_interact' for entity '" + name + "' doesn't exist.");
  1315. }
  1316. }
  1317. }
  1318. void EntityManager::SetNextOffsetStep(Entity* entity){
  1319. // TODO: Allow this while on battle mode?
  1320. ActionType type = entity->GetOffsetType();
  1321. float total = entity->GetOffsetSeconds();
  1322. float current = entity->GetOffsetCurrentSeconds();
  1323. current += Timer::getSingleton().GetGameTimeDelta();
  1324. current = (current > total) ? total : current;
  1325. Ogre::Vector3 start = entity->GetOffsetPositionStart();
  1326. Ogre::Vector3 end = entity->GetOffsetPositionEnd();
  1327. // TODO: Prevent division by 0:
  1328. float x = current / total;
  1329. if (std::isnan(x)) x = 0.0f;
  1330. float smooth_modifier = (type == AT_SMOOTH) ? -2 * x * x * x + 3 * x * x : x;
  1331. Ogre::Vector3 offset = start + (end - start) * smooth_modifier;
  1332. entity->SetOffset(offset);
  1333. if (current == total) entity->UnsetOffset();
  1334. else entity->SetOffsetCurrentSeconds(current);
  1335. }
  1336. void EntityManager::SetNextTurnStep(Entity* entity){
  1337. // TODO: Allow this while on battle mode?
  1338. ActionType type = entity->GetTurnType();
  1339. float total = entity->GetTurnSeconds();
  1340. float current = entity->GetTurnCurrentSeconds();
  1341. current += Timer::getSingleton().GetGameTimeDelta();
  1342. current = (current > total) ? total : current;
  1343. Ogre::Degree start = entity->GetTurnDirectionStart();
  1344. Ogre::Degree end = entity->GetTurnDirectionEnd();
  1345. // TODO: Prevent division by 0:
  1346. float x = current / total;
  1347. float smooth_modifier = (type == AT_SMOOTH) ? -2 * x * x * x + 3 * x * x : x;
  1348. Ogre::Degree rotation = start + (end - start) * smooth_modifier;
  1349. entity->SetRotation(rotation);
  1350. if (current == total) entity->UnsetTurn();
  1351. else entity->SetTurnCurrentSeconds(current);
  1352. }
  1353. void EntityManager::SetNextLinearStep(Entity* entity){
  1354. if (IsBattleModule()){
  1355. LOG_WARNING("Tried to set next linear step, but the EntityManager is in battle mode");
  1356. return;
  1357. }
  1358. bool to_end = true;
  1359. bool is_move = false;
  1360. Ogre::Vector3 start = entity->GetLinearStart();
  1361. Ogre::Vector3 end = entity->GetLinearEnd();
  1362. Ogre::Vector3 current = entity->GetPosition();
  1363. float delta = Timer::getSingleton().GetGameTimeDelta();
  1364. // The player climbs a ladder with the directional keys. While a scene has the player locked
  1365. // the keys have no effect, and the scene makes the player move on its own, as with any other
  1366. // entity.
  1367. if (entity == player_entity_ && !player_lock_){
  1368. LinearMovement move = entity->GetLinearMovement();
  1369. if (move == LM_DOWN_TO_UP || move == LM_UP_TO_DOWN){
  1370. if (player_move_.y > 0){ // move up
  1371. to_end = (move == LM_DOWN_TO_UP) ? true : false;
  1372. is_move = true;
  1373. }
  1374. else if (player_move_.y < 0){ // move down
  1375. to_end = (move == LM_DOWN_TO_UP) ? false : true;
  1376. is_move = true;
  1377. }
  1378. }
  1379. else if (move == LM_LEFT_TO_RIGHT || move == LM_RIGHT_TO_LEFT){
  1380. if (player_move_.x > 0){ // move right
  1381. to_end = (move == LM_LEFT_TO_RIGHT) ? true : false;
  1382. is_move = true;
  1383. }
  1384. else if (player_move_.x < 0){ // move left
  1385. to_end = (move == LM_LEFT_TO_RIGHT) ? false : true;
  1386. is_move = true;
  1387. }
  1388. }
  1389. }
  1390. else is_move = true;
  1391. if (is_move == true){
  1392. Ogre::Vector3 position;
  1393. if (to_end == true){
  1394. Ogre::Vector3 end_start = end - start;
  1395. // Move across the whole line by this number of seconds.
  1396. float time = end_start.length() / 1.2f;
  1397. position.x = current.x + (end_start.x / time) * delta;
  1398. position.y = current.y + (end_start.y / time) * delta;
  1399. position.z = current.z + (end_start.z / time) * delta;
  1400. position.x = (end_start.x < 0)
  1401. ? std::max(position.x, end.x) : std::min(position.x, end.x);
  1402. position.y = (end_start.y < 0)
  1403. ? std::max(position.y, end.y) : std::min(position.y, end.y);
  1404. position.z = (end_start.z < 0)
  1405. ? std::max(position.z, end.z) : std::min(position.z, end.z);
  1406. if (position == end){
  1407. entity->UnsetLinear();
  1408. entity->SetMoveTriangleId(entity->GetLinearDestTriangle());
  1409. SetEntityOnWalkmesh(entity);
  1410. }
  1411. }
  1412. else{
  1413. Ogre::Vector3 end_start = start - end;
  1414. // Move across the whole line by this number of seconds.
  1415. float time = end_start.length() / 1.2f;
  1416. position.x = current.x + (end_start.x / time) * delta;
  1417. position.y = current.y + (end_start.y / time) * delta;
  1418. position.z = current.z + (end_start.z / time) * delta;
  1419. position.x = (end_start.x < 0)
  1420. ? std::max(position.x, start.x) : std::min(position.x, start.x);
  1421. position.y = (end_start.y < 0)
  1422. ? std::max(position.y, start.y) : std::min(position.y, start.y);
  1423. position.z = (end_start.z < 0)
  1424. ? std::max(position.z, start.z) : std::min(position.z, start.z);
  1425. if (position == start){
  1426. entity->UnsetLinear();
  1427. SetEntityOnWalkmesh(entity);
  1428. }
  1429. }
  1430. entity->SetPosition(position);
  1431. entity->UpdateAnimation((to_end == true) ? delta : -delta);
  1432. }
  1433. }
  1434. void EntityManager::SetNextJumpStep(Entity* entity){
  1435. if (IsBattleModule()){
  1436. LOG_WARNING("Tried to set next jump step, but the EntityManager is in battle mode");
  1437. return;
  1438. }
  1439. float total = entity->GetJumpSeconds();
  1440. float current = entity->GetJumpCurrentSeconds();
  1441. current += Timer::getSingleton().GetGameTimeDelta();
  1442. current = (current > total) ? total : current;
  1443. Ogre::Vector3 start_position = entity->GetJumpStart();
  1444. Ogre::Vector3 end_position = entity->GetJumpEnd();
  1445. Ogre::Vector3 position;
  1446. position.x = start_position.x + ((end_position.x - start_position.x) / total) * current;
  1447. position.y = start_position.y + ((end_position.y - start_position.y) / total) * current;
  1448. position.z = current * current * -1.0f + current
  1449. * ((end_position.z - start_position.z) / total + total * 1.0f) + start_position.z;
  1450. entity->SetPosition(position);
  1451. if (total == current){
  1452. entity->UnsetJump();
  1453. entity->SetMoveTriangleId(entity->GetJumpDestTriangle());
  1454. SetEntityOnWalkmesh(entity);
  1455. }
  1456. else entity->SetJumpCurrentSeconds(current);
  1457. }
  1458. void EntityManager::SetNextScrollStep(){
  1459. // TODO: Allow this on battle mode?
  1460. background_2d_.UpdateScrollTarget();
  1461. Background2D::SCROLL_TYPE type = background_2d_.GetScrollType();
  1462. float total = background_2d_.GetScrollSeconds();
  1463. float current = background_2d_.GetScrollCurrentSeconds();
  1464. current += Timer::getSingleton().GetGameTimeDelta();
  1465. current = (current > total) ? total : current;
  1466. Ogre::Vector2 start = background_2d_.GetScrollPositionStart();
  1467. Ogre::Vector2 end = background_2d_.GetScrollPositionEnd();
  1468. float x = current / total;
  1469. float smooth_modifier = (type == Background2D::SMOOTH) ? -2 * x * x * x + 3 * x * x : x;
  1470. Ogre::Vector2 scroll = start + (end - start) * smooth_modifier;
  1471. background_2d_.SetScroll(scroll);
  1472. if (current == total) background_2d_.UnsetScroll();
  1473. else background_2d_.SetScrollCurrentSeconds(current);
  1474. }