EntityManager.cpp 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179
  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 <OgreEntity.h>
  18. #include <OgreRoot.h>
  19. #include <OgreViewport.h>
  20. #include "core/CameraManager.h"
  21. #include "core/ConfigVar.h"
  22. #include "core/DebugDraw.h"
  23. #include "core/EntityManager.h"
  24. #include "core/EntityModel.h"
  25. #include "core/InputManager.h"
  26. #include "core/Logger.h"
  27. #include "core/ScriptManager.h"
  28. #include "core/Timer.h"
  29. #include "core/DialogsManager.h"
  30. /**
  31. * Entity manager singleton.
  32. */
  33. template<>EntityManager *Ogre::Singleton<EntityManager>::msSingleton = nullptr;
  34. ConfigVar cv_debug_grid("debug_grid", "Draw debug grid", "false");
  35. ConfigVar cv_debug_axis("debug_axis", "Draw debug axis", "false");
  36. float EntityManager::PointElevation(
  37. const Ogre::Vector2& point, const Ogre::Vector3& a, const Ogre::Vector3& b, const Ogre::Vector3& c
  38. ){
  39. float _a = a.z * (b.y - c.y) + b.z * (c.y - a.y) + c.z * (a.y - b.y);
  40. float _b = a.y * (b.x - c.x) + b.y * (c.x - a.x) + c.y * (a.x - b.x);
  41. float _c = a.x * (b.z - c.z) + b.x * (c.z - a.z) + c.x * (a.z - b.z);
  42. float _d
  43. = a.x * (b.z * c.y - c.z * b.y) + b.x * (c.z * a.y - a.z * c.y)
  44. + c.x * (a.z * b.y - b.z * a.y);
  45. return (_d - _c * point.y - _a * point.x) / _b;
  46. }
  47. float EntityManager::SideOfVector(
  48. const Ogre::Vector2& point, const Ogre::Vector2& p1, const Ogre::Vector2& p2
  49. ){
  50. Ogre::Vector2 AB = p2 - p1;
  51. Ogre::Vector2 AP = point - p1;
  52. return AB.x * AP.y - AB.y * AP.x;
  53. }
  54. float EntityManager::SquareDistanceToLine(
  55. const Ogre::Vector3& point, const Ogre::Vector3& point_a, const Ogre::Vector3& point_b,
  56. Ogre::Vector3& proj
  57. ){
  58. float temp =
  59. -((point_a.x - point.x) * (point_b.x - point_a.x) + (point_a.y - point.y)
  60. * (point_b.y - point_a.y) + (point_a.z - point.z) * (point_b.z - point_a.z))
  61. / ((point_b.x - point_a.x) * (point_b.x - point_a.x) + (point_b.y - point_a.y)
  62. * (point_b.y - point_a.y) + (point_b.z - point_a.z) * (point_b.z - point_a.z));
  63. proj.x = temp * (point_b.x - point_a.x) + point_a.x;
  64. proj.y = temp * (point_b.y - point_a.y) + point_a.y;
  65. proj.z = temp * (point_b.z - point_a.z) + point_a.z;
  66. if (
  67. ((point_a.x >= proj.x && point_b.x <= proj.x) || (point_a.x < proj.x && point_b.x >= proj.x))
  68. && (
  69. (point_a.y >= proj.y && point_b.y <= proj.y) || (point_a.y < proj.y && point_b.y >= proj.y)
  70. )
  71. ){
  72. return (proj.x - point.x) * (proj.x - point.x) + (proj.y - point.y)
  73. * (proj.y - point.y) + (proj.z - point.z) * (proj.z - point.z);
  74. }
  75. return -1;
  76. }
  77. Ogre::Degree EntityManager::GetDirectionToPoint(
  78. const Ogre::Vector3& current_point, const Ogre::Vector3& direction_point
  79. ){
  80. // TODO: Declare function in header file.
  81. Ogre::Vector2 up(0.0f, -1.0f);
  82. Ogre::Vector2 dir(direction_point.x - current_point.x, direction_point.y - current_point.y);
  83. // Angle between vectors
  84. Ogre::Degree angle(Ogre::Radian(acosf(dir.dotProduct(up) / (dir.length() * up.length()))));
  85. return (dir.x < 0) ? Ogre::Degree(360) - angle : angle;
  86. }
  87. EntityManager::EntityManager():
  88. paused_(false),
  89. player_entity_(nullptr),
  90. player_move_(Ogre::Vector3::ZERO),
  91. player_move_rotation_(0),
  92. player_lock_(false),
  93. player_run_(false),
  94. random_encounters_(false),
  95. encounter_rate_(0)
  96. {
  97. LOG_TRIVIAL("EntityManager created.");
  98. scene_node_ = Ogre::Root::getSingleton().getSceneManager("Scene")
  99. ->getRootSceneNode()->createChildSceneNode("EntityManager");
  100. //grid_ = Ogre::Root::getSingleton().getSceneManager("Scene")
  101. // ->createEntity("Grid", "system/grid.mesh");
  102. grid_ = Ogre::Root::getSingleton().getSceneManager("Scene")->createEntity("Grid", "grid.mesh");
  103. scene_node_->attachObject(grid_);
  104. //axis_ = Ogre::Root::getSingleton().getSceneManager("Scene")
  105. // ->createEntity("Axis", "system/axis.mesh");
  106. axis_ = Ogre::Root::getSingleton().getSceneManager("Scene")->createEntity("Axis", "axis.mesh");
  107. scene_node_->attachObject(axis_);
  108. }
  109. EntityManager::~EntityManager(){
  110. if (grid_ != nullptr) Ogre::Root::getSingleton().getSceneManager("Scene")->destroyEntity(grid_);
  111. if (axis_ != nullptr) Ogre::Root::getSingleton().getSceneManager("Scene")->destroyEntity(axis_);
  112. Clear();
  113. Ogre::Root::getSingleton().getSceneManager("Scene")->getRootSceneNode()->removeAndDestroyChild(
  114. "EntityManager"
  115. );
  116. LOG_TRIVIAL("EntityManager destroyed.");
  117. }
  118. void EntityManager::Input(const VGears::Event& event){
  119. background_2d_.InputDebug(event);
  120. if (paused_ == true) return;
  121. if (player_entity_ != NULL && player_lock_ == false){
  122. if (event.type == VGears::ET_KEY_REPEAT && event.event == "walk_left") player_move_.x = -1;
  123. else if (event.type == VGears::ET_KEY_REPEAT && event.event == "walk_right")
  124. player_move_.x = 1;
  125. if (event.type == VGears::ET_KEY_REPEAT && event.event == "walk_down") player_move_.y = -1;
  126. else if (event.type == VGears::ET_KEY_REPEAT && event.event == "walk_up")
  127. player_move_.y = 1;
  128. if (event.type == VGears::ET_KEY_REPEAT && event.event == "run") player_run_ = true;
  129. if (event.type == VGears::ET_KEY_PRESS && event.event == "interact"){
  130. CheckEntityInteract();
  131. for (unsigned int i = 0; i < entity_triggers_.size(); ++ i){
  132. if (
  133. entity_triggers_[i]->IsEnabled() == true
  134. && entity_triggers_[i]->CheckApproached() == true
  135. ){
  136. ScriptEntity* scr_entity = ScriptManager::getSingleton().GetScriptEntityByName(
  137. ScriptManager::ENTITY, entity_triggers_[i]->GetName()
  138. );
  139. bool added = ScriptManager::getSingleton().ScriptRequest(
  140. scr_entity, "on_interact", 1, "", "", false, false
  141. );
  142. if (added == false){
  143. LOG_WARNING(
  144. "Script 'on_interact' for entity '" + entity_triggers_[i]->GetName()
  145. + "' doesn't exist."
  146. );
  147. }
  148. }
  149. }
  150. }
  151. // Rotate move vector to field move rotation
  152. Ogre::Quaternion q1;
  153. q1.FromAngleAxis(player_move_rotation_, Ogre::Vector3::UNIT_Z);
  154. player_move_ = q1 * player_move_;
  155. }
  156. }
  157. void EntityManager::Update(){
  158. UpdateDebug();
  159. if (paused_ == true) return;
  160. // Update all entity scripts
  161. ScriptManager::getSingleton().Update(ScriptManager::ENTITY);
  162. // Set move point for player entity
  163. if (player_entity_ != nullptr && player_move_ != Ogre::Vector3::ZERO){
  164. Entity::State state = player_entity_->GetState();
  165. if (state == Entity::WALKMESH || state == Entity::NONE){
  166. player_move_
  167. *= player_entity_->GetMoveWalkSpeed() * Timer::getSingleton().GetGameTimeDelta();
  168. player_entity_->SetMovePosition(player_entity_->GetPosition() + player_move_);
  169. player_entity_->SetState(Entity::WALKMESH);
  170. }
  171. // HACK: If manually moving, make playable entity solid.
  172. // Some scripts 'forget' to make the playable entity solid at the end
  173. // of them, and if it remains non-solid, it can't interact with lines
  174. // (i.e. it cant' use gateways).
  175. player_entity_->SetSolid(true);
  176. }
  177. for (unsigned int i = 0; i < entity_.size(); ++ i){
  178. entity_[i]->Update();
  179. // It's not needed to update movements it delta time == 0 (for example
  180. // if time is stopped)
  181. if (Timer::getSingleton().GetGameTimeDelta() == 0) continue;
  182. // Update screen scroll.
  183. Entity* scroll_entity = background_2d_.GetAutoScrollEntity();
  184. if (scroll_entity == entity_[i]){
  185. CameraManager &camera_manager(CameraManager::getSingleton());
  186. Ogre::Vector3 view = camera_manager.ProjectPointToScreen(scroll_entity->GetPosition());
  187. Ogre::Vector2 pos = background_2d_.GetScreenScroll();
  188. Ogre::Viewport *viewport(camera_manager.getViewport());
  189. float width = float(viewport->getActualWidth());
  190. float height = float(viewport->getActualHeight());
  191. view.x = view.x - width / 2 - pos.x;
  192. view.y = view.y - height / 2 - pos.y;
  193. background_2d_.SetScreenScroll(Ogre::Vector2(-view.x, -view.y));
  194. }
  195. // Update offset.
  196. if (entity_[i]->GetOffsetType() != AT_NONE) SetNextOffsetStep(entity_[i]);
  197. // Update turn.
  198. if (entity_[i]->GetTurnType() != AT_NONE) SetNextTurnStep(entity_[i]);
  199. // Update movement.
  200. switch(entity_[i]->GetState()){
  201. case Entity::WALKMESH:
  202. {
  203. // Try set entity on walkmesh if it's still don't has triangle.
  204. if (entity_[i]->GetMoveTriangleId() == -1){
  205. if (SetEntityOnWalkmesh(entity_[i]) == false){
  206. LOG_TRIVIAL(
  207. "Can't set entity '" + entity_[i]->GetName()
  208. + "' on walkmesh. Finish move."
  209. );
  210. entity_[i]->UnsetMove();
  211. }
  212. }
  213. // Perform move
  214. if (entity_[i]->GetState() == Entity::WALKMESH){
  215. float speed = 0;
  216. if (player_lock_ == false && player_entity_ == entity_[i]){
  217. speed = entity_[i]->GetMoveWalkSpeed();
  218. // TODO: Set as a constant.
  219. // Or even better, as a configurable variable.
  220. if (player_run_ == true) speed *= 4;
  221. }
  222. else speed = entity_[i]->GetMoveAutoSpeed();
  223. bool is_move = PerformWalkmeshMove(entity_[i], speed);
  224. if (entity_[i]->GetMoveAutoAnimation() == true){
  225. if (is_move == true){
  226. if (speed >= entity_[i]->GetMoveRunSpeed()){
  227. entity_[i]->PlayAnimationContinue(
  228. entity_[i]->GetMoveAnimationRunName()
  229. );
  230. }
  231. else{
  232. entity_[i]->PlayAnimationContinue(
  233. entity_[i]->GetMoveAnimationWalkName()
  234. );
  235. }
  236. }
  237. else if (
  238. entity_[i]->GetAnimationState() != Entity::REQUESTED_ANIMATION
  239. ){
  240. entity_[i]->PlayAnimationContinue(
  241. entity_[i]->GetDefaultAnimationName()
  242. );
  243. }
  244. }
  245. }
  246. }
  247. break;
  248. case Entity::LINEAR:
  249. CheckTriggers(entity_[i], entity_[i]->GetPosition());
  250. SetNextLinearStep(entity_[i]);
  251. break;
  252. case Entity::JUMP:
  253. SetNextJumpStep(entity_[i]);
  254. break;
  255. case Entity::NEEDS_TO_REATTACH:
  256. if (SetEntityOnWalkmesh(entity_[i])) entity_[i]->SetState(Entity::WALKMESH);
  257. else entity_[i]->SetState(Entity::NONE);
  258. case Entity::NONE:
  259. CheckTriggers(entity_[i], entity_[i]->GetPosition());
  260. if (entity_[i]->GetAnimationState() != Entity::REQUESTED_ANIMATION)
  261. entity_[i]->PlayAnimationContinue(entity_[i]->GetDefaultAnimationName());
  262. break;
  263. }
  264. }
  265. // Reset player move. It already must be handled in update
  266. player_move_ = Ogre::Vector3::ZERO;
  267. player_run_ = false;
  268. if (background_2d_.GetScrollType() != Background2D::NONE) SetNextScrollStep();
  269. background_2d_.Update();
  270. }
  271. void EntityManager::UpdateDebug(){
  272. grid_->setVisible(cv_debug_grid.GetB());
  273. axis_->setVisible(cv_debug_axis.GetB());
  274. for (unsigned int i = 0; i < entity_.size(); ++ i) entity_[i]->UpdateDebug();
  275. for (unsigned int i = 0; i < entity_triggers_.size(); ++ i) entity_triggers_[i]->UpdateDebug();
  276. for (unsigned int i = 0; i < entity_points_.size(); ++ i) entity_points_[i]->UpdateDebug();
  277. walkmesh_.UpdateDebug();
  278. background_2d_.UpdateDebug();
  279. }
  280. void EntityManager::OnResize(){background_2d_.OnResize();}
  281. void EntityManager::Clear(){
  282. walkmesh_.Clear();
  283. background_2d_.Clear();
  284. DialogsManager::getSingleton().Clear();
  285. for (unsigned int i = 0; i < entity_.size(); ++ i){
  286. ScriptManager::getSingleton().RemoveEntity(ScriptManager::ENTITY, entity_[i]->GetName());
  287. delete entity_[i];
  288. }
  289. entity_.clear();
  290. player_entity_ = nullptr;
  291. player_move_ = Ogre::Vector3::ZERO;
  292. player_move_rotation_ = 0;
  293. player_lock_ = false;
  294. for (unsigned int i = 0; i < entity_triggers_.size(); ++ i){
  295. ScriptManager::getSingleton().RemoveEntity(
  296. ScriptManager::ENTITY, entity_triggers_[i]->GetName()
  297. );
  298. delete entity_triggers_[i];
  299. }
  300. entity_triggers_.clear();
  301. for (unsigned int i = 0; i < entity_points_.size(); ++ i) delete entity_points_[i];
  302. entity_points_.clear();
  303. for (unsigned int i = 0; i < entity_scripts_.size(); ++ i)
  304. ScriptManager::getSingleton().RemoveEntity(ScriptManager::ENTITY, entity_scripts_[i]);
  305. scene_node_->removeAndDestroyAllChildren();
  306. }
  307. void EntityManager::ScriptSetPaused(const bool paused){paused_ = paused;}
  308. Walkmesh* EntityManager::GetWalkmesh(){return &walkmesh_;}
  309. Background2D* EntityManager::GetBackground2D(){return &background_2d_;}
  310. void EntityManager::AddEntity(
  311. const Ogre::String& name, const Ogre::String& file_name,
  312. const Ogre::Vector3& position, const Ogre::Degree& rotation, int index
  313. ){
  314. AddEntity(
  315. name, file_name, position, rotation,
  316. Ogre::Vector3::UNIT_SCALE, Ogre::Quaternion::IDENTITY, index
  317. );
  318. }
  319. void EntityManager::AddEntity(
  320. const Ogre::String& name, const Ogre::String& file_name, const Ogre::Vector3& position,
  321. const Ogre::Degree& rotation, const Ogre::Vector3& scale,
  322. const Ogre::Quaternion& root_orientation, int index
  323. ){
  324. Ogre::SceneNode* node = scene_node_->createChildSceneNode("Model_" + name);
  325. EntityModel* entity = new EntityModel(name, file_name, node);
  326. entity->SetPosition(position);
  327. entity->SetRotation(rotation);
  328. entity->setScale(scale);
  329. entity->SetIndex(index);
  330. entity->setRootOrientation(root_orientation);
  331. entity_.push_back(entity);
  332. ScriptManager::getSingleton().AddEntity(ScriptManager::ENTITY, entity->GetName(), entity);
  333. }
  334. void EntityManager::ScriptAddEntity(
  335. const char* name, const char* file_name,
  336. const float x, const float y, const float z, const float rotation, int index
  337. ){AddEntity(name, file_name, Ogre::Vector3(x, y, z), Ogre::Degree(rotation), index);}
  338. void EntityManager::AddEntityTrigger(
  339. const Ogre::String& name,
  340. const Ogre::Vector3& point1, const Ogre::Vector3& point2, const bool enabled
  341. ){
  342. EntityTrigger* trigger = new EntityTrigger(name);
  343. trigger->SetPoints(point1, point2);
  344. trigger->SetEnabled(enabled);
  345. entity_triggers_.push_back(trigger);
  346. ScriptManager::getSingleton().AddEntity(ScriptManager::ENTITY, trigger->GetName(), nullptr);
  347. }
  348. void EntityManager::AddEntityPoint(
  349. const Ogre::String& name, const Ogre::Vector3& position, const float rotation
  350. ){
  351. EntityPoint* entity_point = new EntityPoint(name);
  352. entity_point->SetPosition(position);
  353. entity_point->SetRotation(rotation);
  354. entity_points_.push_back(entity_point);
  355. }
  356. void EntityManager::AddEntityScript(const Ogre::String& name){
  357. entity_scripts_.push_back(name);
  358. ScriptManager::getSingleton().AddEntity(ScriptManager::ENTITY, name, nullptr);
  359. }
  360. void EntityManager::ScriptAddEntityScript(const char* name){AddEntityScript(name);}
  361. Entity* EntityManager::GetEntity(const Ogre::String& name) const{
  362. for (unsigned int i = 0; i < entity_.size(); ++ i)
  363. if (entity_[i]->GetName() == name) return entity_[i];
  364. return nullptr;
  365. }
  366. Entity* EntityManager::GetEntityFromIndex(const int index) const{
  367. for (unsigned int i = 0; i < entity_.size(); ++ i)
  368. if (entity_[i]->GetIndex() == index) return entity_[i];
  369. return nullptr;
  370. }
  371. Entity* EntityManager::GetEntityFromCharacterId(const int id) const{
  372. for (unsigned int i = 0; i < entity_.size(); ++ i)
  373. if (entity_[i]->IsCharacter() && entity_[i]->GetCharacterId() == id) return entity_[i];
  374. return nullptr;
  375. }
  376. Entity* EntityManager::ScriptGetEntity(const char* name) const{
  377. return GetEntity(Ogre::String(name));
  378. }
  379. EntityPoint* EntityManager::ScriptGetEntityPoint(const char* name) const{
  380. for (unsigned int i = 0; i < entity_points_.size(); ++ i)
  381. if (entity_points_[i]->GetName() == name) return entity_points_[i];
  382. return nullptr;
  383. }
  384. void EntityManager::ScriptSetPlayerEntity(const char* name){
  385. for (unsigned int i = 0; i < entity_.size(); ++ i){
  386. if (entity_[i]->GetName() == name){
  387. player_entity_ = entity_[i];
  388. // Also, make is solid, visible, and non-talkable.
  389. entity_[i]->SetSolid(true);
  390. entity_[i]->SetVisible(true);
  391. entity_[i]->SetTalkable(false);
  392. }
  393. }
  394. }
  395. Entity* EntityManager::ScriptGetPlayerEntity() const{return player_entity_;}
  396. void EntityManager::ScriptUnsetPlayerEntity(){player_entity_ = nullptr;}
  397. void EntityManager::ScriptPlayerLock(const bool lock){
  398. player_lock_ = lock;
  399. if (lock == true) player_move_ = Ogre::Vector3::ZERO;
  400. }
  401. void EntityManager::SetPlayerMoveRotation(const Ogre::Radian rotation){
  402. player_move_rotation_ = rotation;
  403. }
  404. bool EntityManager::GetRandomEncounters(){return random_encounters_;}
  405. void EntityManager::SetRandomEncounters(bool active){random_encounters_ = active;}
  406. float EntityManager::GetEncounterRate(){return encounter_rate_;}
  407. void EntityManager::SetEncounterRate(float rate){
  408. if (rate >= 1.0f) encounter_rate_ = 1.0f;
  409. else if (rate <= 0.0f) encounter_rate_ = 0.0f;
  410. else encounter_rate_ = rate;
  411. }
  412. bool EntityManager::StartBattleForResult(unsigned int formation){
  413. std::cout << "[BATTLE] Start battle for result ID " << formation << "\n";
  414. return true;
  415. }
  416. void EntityManager::StartBattle(unsigned int formation){
  417. std::cout << "[BATTLE] Start battle ID " << formation << "\n";
  418. }
  419. bool EntityManager::IsKeyOn(unsigned int key_code){
  420. // If the player is locked, always false.
  421. // TODO: Maybe this will interfere with something down the road?
  422. // Some scene where the player can't move but must press a button?
  423. if (player_lock_) return false;
  424. unsigned int code = key_code;
  425. // Translate keycodes to game key codes.
  426. // For example 32 is standard for "Enter", but in game is "Circle/Action".
  427. // TODO: Finish this list.
  428. switch (key_code){
  429. case 32: code = OIS::KC_SPACE; break;
  430. }
  431. bool pressed = InputManager::getSingleton().IsButtonPressed(code);
  432. return pressed;
  433. }
  434. bool EntityManager::IsKeyOff(unsigned int key_code){return !IsKeyOn(key_code);}
  435. void EntityManager::SetEntityToCharacter(const char* entity_name, unsigned int char_id){
  436. for (unsigned int i = 0; i < entity_.size(); ++ i)
  437. if (entity_[i]->GetName() == entity_name) entity_[i]->SetCharacter(char_id);
  438. }
  439. void EntityManager::AddTrack(const int id, const int track_id){
  440. if (id >= 0 && id < 255) tracks_[id] = track_id;
  441. }
  442. int EntityManager::GetTrack(const int id){
  443. if (tracks_.count(id) == 0) return -1;
  444. else return tracks_[id];
  445. }
  446. bool EntityManager::SetEntityOnWalkmesh(Entity* entity){
  447. Ogre::Vector3 position3 = entity->GetPosition();
  448. Ogre::Vector2 position2;
  449. position2.x = position3.x;
  450. position2.y = position3.y;
  451. std::vector<std::pair<int, float>> triangles;
  452. // Search for possible triangles.
  453. for (int i = 0; i < walkmesh_.GetNumberOfTriangles(); ++ i){
  454. Ogre::Vector3 A3 = walkmesh_.GetA(i);
  455. Ogre::Vector3 B3 = walkmesh_.GetB(i);
  456. Ogre::Vector3 C3 = walkmesh_.GetC(i);
  457. Ogre::Vector2 A2(A3.x, A3.y);
  458. Ogre::Vector2 B2(B3.x, B3.y);
  459. Ogre::Vector2 C2(C3.x, C3.y);
  460. if (Ogre::Math::pointInTri2D(position2, A2, B2, C2) == true){
  461. triangles.push_back(std::make_pair(i, PointElevation(
  462. position2, walkmesh_.GetA(i), walkmesh_.GetB(i), walkmesh_.GetC(i)
  463. )));
  464. }
  465. }
  466. // If the coordinates doesn't match any triangle, exit.
  467. if (triangles.size() == 0 && entity == player_entity_){
  468. LOG_ERROR(
  469. "Can't find any triangle to place entity '" + entity->GetName() + "' on walkmesh."
  470. );
  471. return false;
  472. }
  473. // From the possible triangles, select the closest one (on the Z edge).
  474. int closest_z_triangle = -1;
  475. float closest_z_distance = 9999.0f;
  476. float pos_z = position3.z;
  477. for (size_t i = 0; i < triangles.size(); ++ i){
  478. if (std::abs(pos_z - triangles[i].second) < closest_z_distance){
  479. closest_z_triangle = triangles[i].first;
  480. closest_z_distance = std::abs(pos_z - triangles[i].second);
  481. }
  482. }
  483. if (closest_z_triangle == -1 && entity == player_entity_){
  484. LOG_ERROR(
  485. "Can't find nearby triangle to place entity '" + entity->GetName() + "' on walkmesh."
  486. );
  487. return false;
  488. }
  489. entity->SetPosition(Ogre::Vector3(position2.x, position2.y, pos_z));
  490. entity->SetMoveTriangleId(closest_z_triangle);
  491. return true;
  492. }
  493. bool EntityManager::PerformWalkmeshMove(Entity* entity, const float speed){
  494. Ogre::Vector3 start_point = entity->GetPosition();
  495. Ogre::Vector3 move_vector = entity->GetMovePosition() - start_point;
  496. Ogre::Vector2 direction(move_vector.x, move_vector.y);
  497. direction.normalise();
  498. direction *= Timer::getSingleton().GetGameTimeDelta();
  499. direction *= speed;
  500. // If movement is still needed but speed or time don't allow it, just return for now.
  501. if (direction.isZeroLength() == true){
  502. if (player_entity_ == entity) CheckTriggers(entity, entity->GetPosition());
  503. return false;
  504. }
  505. int current_triangle = entity->GetMoveTriangleId();
  506. if (current_triangle == -1){
  507. LOG_ERROR("Entity '" + entity->GetName() + "' not placed on walkmesh and can't move.");
  508. return false;
  509. }
  510. Ogre::Vector3 rotation(0.0f, 0.0f, 0.0f);
  511. Ogre::Quaternion q1(0.0f, 0.0f, 0.0f, 1.0f);
  512. Ogre::Vector3 end_point(0.0f, 0.0f, 0.0f);
  513. Ogre::Vector3 end_point2(0.0f, 0.0f, 0.0f);
  514. bool first_triangle_check = false;
  515. bool second_triangle_check = false;
  516. bool third_triangle_check = false;
  517. bool last_triangle_check = false;
  518. bool first_entity_check = false;
  519. bool second_entity_check = false;
  520. bool third_entity_check = false;
  521. // Shorten move vector by triangle angle
  522. end_point.x = start_point.x + direction.x;
  523. end_point.y = start_point.y + direction.y;
  524. Ogre::Vector3 A3 = walkmesh_.GetA(current_triangle);
  525. Ogre::Vector3 B3 = walkmesh_.GetB(current_triangle);
  526. Ogre::Vector3 C3 = walkmesh_.GetC(current_triangle);
  527. end_point.z = PointElevation(Ogre::Vector2(end_point.x, end_point.y), A3, B3, C3);
  528. Ogre::Vector3 temp = end_point - start_point;
  529. temp.normalise();
  530. temp = temp * direction.length();
  531. direction.x = temp.x;
  532. direction.y = temp.y;
  533. // Set the direction for the entity if it has to move.
  534. if (entity->GetMoveAutoRotation() == true){
  535. Ogre::Vector2 up(0.0f, -1.0f);
  536. // Angle between vectors
  537. Ogre::Degree angle(Ogre::Radian(acosf(
  538. direction.dotProduct(up) / (direction.length() * up.length())
  539. )));
  540. angle = (direction.x < 0) ? Ogre::Degree(360) - angle : angle;
  541. entity->SetRotation(Ogre::Degree(angle));
  542. }
  543. float solid = (entity->IsSolid() == true) ? entity->GetSolidRadius() : 0.01f;
  544. // For not playable entities, be a bit more lenient with solid collisions.
  545. // Don't use the solid radius.
  546. if (entity != player_entity_) solid /= 10;
  547. // Get ending point.
  548. end_point.z = start_point.z;
  549. for (
  550. int i = 0;
  551. (entity == player_entity_ && i < 16)
  552. || (entity == player_entity_ && i < 3)
  553. || (entity != player_entity_ && i <= 16);
  554. ++ i
  555. ){
  556. end_point = Ogre::Vector3(
  557. start_point.x + direction.x, start_point.y + direction.y, start_point.z
  558. );
  559. // 1st check.
  560. // Rotate move_vector +45.
  561. q1.FromAngleAxis(Ogre::Radian(Ogre::Degree(45)), Ogre::Vector3::UNIT_Z);
  562. rotation.x = direction.x;
  563. rotation.y = direction.y;
  564. rotation.z = 0;
  565. rotation.normalise();
  566. rotation = q1 * rotation;
  567. // Multiply move_vector by solid range
  568. rotation = rotation * solid;
  569. end_point2.x = end_point.x + rotation.x;
  570. end_point2.y = end_point.y + rotation.y;
  571. // Check_triangle.
  572. first_triangle_check = WalkmeshBorderCross(entity, end_point2, direction);
  573. entity->SetMoveTriangleId(current_triangle);
  574. // Model check.
  575. first_entity_check = CheckSolidCollisions(entity, end_point2);
  576. // 2nd check.
  577. // Rotate move_vector +45.
  578. q1.FromAngleAxis(Ogre::Radian(Ogre::Degree(-45)), Ogre::Vector3::UNIT_Z);
  579. rotation.x = direction.x;
  580. rotation.y = direction.y;
  581. rotation.z = 0;
  582. rotation.normalise();
  583. rotation = q1 * rotation;
  584. // Multiply move_vector by solid range.
  585. rotation = rotation * solid;
  586. end_point2.x = end_point.x + rotation.x;
  587. end_point2.y = end_point.y + rotation.y;
  588. // Check triangle.
  589. second_triangle_check = WalkmeshBorderCross(entity, end_point2, direction);
  590. entity->SetMoveTriangleId(current_triangle);
  591. // Model check.
  592. second_entity_check = CheckSolidCollisions(entity, end_point2);
  593. // 3rd check.
  594. rotation.x = direction.x;
  595. rotation.y = direction.y;
  596. rotation.z = 0;
  597. rotation.normalise();
  598. rotation = rotation * solid;
  599. end_point2.x = end_point.x + rotation.x;
  600. end_point2.y = end_point.y + rotation.y;
  601. // Check triangle.
  602. third_triangle_check = WalkmeshBorderCross(entity, end_point2, direction);
  603. entity->SetMoveTriangleId(current_triangle);
  604. // Model check.
  605. third_entity_check = CheckSolidCollisions(entity, end_point2);
  606. // Check condition and modify move_vector.
  607. if (
  608. first_triangle_check != false || second_triangle_check != false
  609. || third_triangle_check != false || first_entity_check != false
  610. || second_entity_check != false || third_entity_check != false
  611. ){
  612. // Only for NPC.
  613. if (entity != player_entity_){
  614. // If the entity collides only directly into a triangle border.
  615. if (
  616. first_triangle_check == false
  617. && second_triangle_check == false
  618. && third_triangle_check != false
  619. ){
  620. q1.FromAngleAxis(Ogre::Radian(Ogre::Degree(-7)), Ogre::Vector3::UNIT_Z);
  621. rotation.x = direction.x;
  622. rotation.y = direction.y;
  623. rotation = q1 * rotation;
  624. direction.x = rotation.x;
  625. direction.y = rotation.y;
  626. }
  627. // Or if the entity only collides into other entity directly.
  628. else if (
  629. first_entity_check == false && second_entity_check == false
  630. && third_entity_check != false
  631. ){
  632. q1.FromAngleAxis(Ogre::Radian(Ogre::Degree(-11.25f)), Ogre::Vector3::UNIT_Z);
  633. rotation.x = direction.x;
  634. rotation.y = direction.y;
  635. rotation = q1 * rotation;
  636. direction.x = rotation.x;
  637. direction.y = rotation.y;
  638. }
  639. // If not both left and right check failed.
  640. if (first_triangle_check == false || second_triangle_check == false){
  641. if (
  642. (first_triangle_check == false && first_entity_check != false)
  643. || (first_triangle_check != false && second_triangle_check == false)
  644. ){
  645. q1.FromAngleAxis(
  646. Ogre::Radian(Ogre::Degree(-11.25f)), Ogre::Vector3::UNIT_Z
  647. );
  648. rotation.x = direction.x;
  649. rotation.y = direction.y;
  650. rotation = q1 * rotation;
  651. direction.x = rotation.x;
  652. direction.y = rotation.y;
  653. }
  654. if (
  655. first_triangle_check == false
  656. && first_entity_check == false
  657. && (second_triangle_check != false || second_entity_check != false
  658. )
  659. ){
  660. q1.FromAngleAxis(Ogre::Radian(Ogre::Degree(11.25f)), Ogre::Vector3::UNIT_Z);
  661. rotation.x = direction.x;
  662. rotation.y = direction.y;
  663. rotation = q1 * rotation;
  664. direction.x = rotation.x;
  665. direction.y = rotation.y;
  666. }
  667. continue;
  668. }
  669. break;
  670. }
  671. // Only for playable character.
  672. else{
  673. if (
  674. first_entity_check == false
  675. && second_entity_check == false
  676. && third_entity_check == false
  677. ){
  678. // If not both left and right check failed
  679. if (first_triangle_check == false || second_triangle_check == false){
  680. if (first_triangle_check != false && second_triangle_check == false){
  681. q1.FromAngleAxis(
  682. Ogre::Radian(Ogre::Degree(-11.25f)), Ogre::Vector3::UNIT_Z
  683. );
  684. rotation.x = direction.x;
  685. rotation.y = direction.y;
  686. rotation = q1 * rotation;
  687. direction.x = rotation.x;
  688. direction.y = rotation.y;
  689. }
  690. if (first_triangle_check == false && second_triangle_check != false){
  691. q1.FromAngleAxis(
  692. Ogre::Radian(Ogre::Degree(11.25f)), Ogre::Vector3::UNIT_Z
  693. );
  694. rotation.x = direction.x;
  695. rotation.y = direction.y;
  696. rotation = q1 * rotation;
  697. direction.x = rotation.x;
  698. direction.y = rotation.y;
  699. }
  700. continue;
  701. }
  702. break;
  703. }
  704. }
  705. }
  706. }
  707. // Set new X, Y and Z
  708. last_triangle_check = WalkmeshBorderCross(entity, end_point, direction);
  709. if (
  710. first_triangle_check != false || second_triangle_check != false
  711. || third_triangle_check != false || last_triangle_check != false
  712. || first_entity_check != false || second_entity_check != false
  713. || third_entity_check != false
  714. ){
  715. // Event if the entity can't move, check for triggers, but use current position.
  716. if (player_entity_ == entity) CheckTriggers(entity, entity->GetPosition());
  717. return false;
  718. }
  719. // Check triggers before set entity position because move line is checked.
  720. if (player_entity_ == entity) CheckTriggers(entity, end_point);
  721. entity->SetPosition(end_point);
  722. // If the entity has come to destination point, finish movement.
  723. Ogre::Vector3 final = entity->GetMovePosition() - end_point;
  724. if (Ogre::Vector2(final.x, final.y).length() <= entity->GetMoveStopDistance() + speed / 10)
  725. entity->UnsetMove();
  726. return true;
  727. }
  728. bool EntityManager::WalkmeshBorderCross(
  729. Entity* entity, Ogre::Vector3& position, const Ogre::Vector2& move_vector
  730. ){
  731. int current_triangle = entity->GetMoveTriangleId();
  732. if (current_triangle == -1) return true;
  733. Ogre::Vector2 pos = Ogre::Vector2(position.x, position.y);
  734. for (;;){
  735. Ogre::Vector3 A3 = walkmesh_.GetA(current_triangle);
  736. Ogre::Vector3 B3 = walkmesh_.GetB(current_triangle);
  737. Ogre::Vector3 C3 = walkmesh_.GetC(current_triangle);
  738. Ogre::Vector2 A(A3.x, A3.y);
  739. Ogre::Vector2 B(B3.x, B3.y);
  740. Ogre::Vector2 C(C3.x, C3.y);
  741. float sign1 = SideOfVector(pos, B, A);
  742. float sign2 = SideOfVector(pos, C, B);
  743. float sign3 = SideOfVector(pos, A, C);
  744. int next_triangle = -1;
  745. if (sign1 < 0) next_triangle = walkmesh_.GetAccessSide(current_triangle, 0);
  746. else if (sign2 < 0) next_triangle = walkmesh_.GetAccessSide(current_triangle, 1);
  747. else if (sign3 < 0) next_triangle = walkmesh_.GetAccessSide(current_triangle, 2);
  748. else{
  749. position.z = PointElevation(pos, A3, B3, C3);
  750. entity->SetMoveTriangleId(current_triangle);
  751. return false;
  752. }
  753. if (next_triangle >= 0){
  754. bool lock = walkmesh_.IsLocked(next_triangle);
  755. if (lock == false){
  756. current_triangle = next_triangle;
  757. continue;
  758. }
  759. }
  760. position.z = PointElevation(pos, A3, B3, C3);
  761. entity->SetMoveTriangleId(current_triangle);
  762. return true;
  763. }
  764. }
  765. bool EntityManager::CheckSolidCollisions(Entity* entity, Ogre::Vector3& position){
  766. if (entity->IsSolid() == false) return false;
  767. for (size_t i = 0; i < entity_.size(); ++ i){
  768. if (entity_[i]->IsSolid() == false) continue;
  769. if (entity_[i] == entity) continue;
  770. Ogre::Vector3 pos1 = entity_[i]->GetPosition();
  771. float solid_range = entity_[i]->GetSolidRadius();
  772. solid_range *= solid_range;
  773. float height = (pos1.z < position.z) ? entity_[i]->GetHeight() : entity->GetHeight();
  774. if (
  775. ((pos1.z - position.z + height) < (height * 2)) && ((pos1.z - position.z + height) >= 0)
  776. ){
  777. float distance
  778. = (pos1.x - position.x) * (pos1.x - position.x)
  779. + (pos1.y - position.y) * (pos1.y - position.y);
  780. if (distance < solid_range) return true;
  781. }
  782. }
  783. return false;
  784. }
  785. void EntityManager::CheckTriggers(Entity* entity, const Ogre::Vector3& position){
  786. if (entity->IsSolid() == false) return;
  787. if (player_entity_ != entity) return;
  788. if (player_entity_->IsSolid() == false) return;
  789. if (player_lock_) return;
  790. bool is_moving = true;
  791. if (
  792. std::fabs(entity->GetPosition().x - position.x) < 0.005f
  793. && std::fabs(entity->GetPosition().y - position.y) < 0.005f
  794. && std::fabs(entity->GetPosition().z - position.z) < 0.005f
  795. ){
  796. is_moving = false;
  797. }
  798. for (unsigned int i = 0; i < entity_triggers_.size(); ++ i){
  799. ScriptEntity* trigger = ScriptManager::getSingleton().GetScriptEntityByName(
  800. ScriptManager::ENTITY, entity_triggers_[i]->GetName()
  801. );
  802. if (trigger != nullptr && entity_triggers_[i]->IsEnabled() == true){
  803. Ogre::Vector3 point_a = entity_triggers_[i]->GetPoint1();
  804. Ogre::Vector3 point_b = entity_triggers_[i]->GetPoint2();
  805. Ogre::Vector3 entity_position = entity->GetPosition();
  806. Ogre::Vector3 proj;
  807. // Calculate distance
  808. float square_dist = SquareDistanceToLine(entity_position, point_a, point_b, proj);
  809. float solid_radius = entity->GetSolidRadius();
  810. // Calculate direction.
  811. const Ogre::Degree direction_to_line = GetDirectionToPoint(entity_position, proj);
  812. const Ogre::Degree destination_direction_to_line = GetDirectionToPoint(position, proj);
  813. const Ogre::Degree movement_direction = entity->GetRotation();
  814. Ogre::Degree angle = direction_to_line - movement_direction + Ogre::Degree(90);
  815. angle = (angle > Ogre::Degree(360)) ? angle - Ogre::Degree(360) : angle;
  816. // Check on enter line.
  817. // Must happen only once when the solid radius touches the line, while facing the line,
  818. // while the entity is manually moving, and only if not already triggered.
  819. if (
  820. square_dist != -1 && square_dist <= solid_radius * solid_radius
  821. && angle < Ogre::Degree(180) && angle > Ogre::Degree(0)
  822. && entity_triggers_[i]->CheckApproached() == false
  823. && is_moving
  824. ){
  825. entity_triggers_[i]->SetApproached(true);
  826. //std::cout << " [TRIGGER] " << entity->GetName() << " on_approach "
  827. // << entity_triggers_[i]->GetName() << std::endl;
  828. ScriptManager::getSingleton().ScriptRequest(
  829. trigger, "on_approach", 1, entity->GetName(), "", false, false
  830. );
  831. }
  832. // Check on move to line.
  833. // Must happen only once when the entity center touches the line, if the entity has
  834. // previously entered the line.
  835. if (
  836. square_dist != -1 && square_dist < 1
  837. && entity_triggers_[i]->CheckCrossed() == false
  838. && entity_triggers_[i]->CheckApproached() == true
  839. ){
  840. entity_triggers_[i]->SetCrossed(true);
  841. //std::cout << " [TRIGGER] " << entity->GetName() << " on_cross "
  842. // << entity_triggers_[i]->GetName() << std::endl;
  843. ScriptManager::getSingleton().ScriptRequest(
  844. trigger, "on_cross", 1, entity->GetName(), "", false, false
  845. );
  846. }
  847. // Check on cross line.
  848. // Must happen on every frame while the entity solid radius collides with the line, if
  849. // the entity has previously entered the line.
  850. if (
  851. square_dist != -1 && square_dist <= solid_radius * solid_radius
  852. && entity_triggers_[i]->CheckApproached() == true
  853. ){
  854. // TODO: Fix this hack.
  855. // After the on_near script is run, set a cooltime of 5 frames before running
  856. // it again. This is because most of the time this trigger checks for a key, and
  857. // if its pressed, is run multiple times.
  858. if (entity_triggers_[i]->GetNearEventCooldown() == 0){
  859. //std::cout << " [TRIGGER] " << entity->GetName()
  860. // << " on_near " << entity_triggers_[i]->GetName() << std::endl;
  861. ScriptManager::getSingleton().ScriptRequest(
  862. trigger, "on_near", 1, entity->GetName(), "", true, true
  863. );
  864. entity_triggers_[i]->ResetNearEventCooldown();
  865. }
  866. else entity_triggers_[i]->DecreaseNearEventCooldown();
  867. }
  868. // Check on cross line once.
  869. // The same as on cross line, but only once.
  870. if (
  871. square_dist != -1 && square_dist < solid_radius * solid_radius
  872. && entity_triggers_[i]->CheckNearSingleEventTriggered() == false
  873. && entity_triggers_[i]->CheckApproached() == true
  874. ){
  875. entity_triggers_[i]->SetNearSingleEventTriggered(true);
  876. //std::cout << " [TRIGGER] " << entity->GetName()
  877. // << " on_near_once " << entity_triggers_[i]->GetName() << std::endl;
  878. ScriptManager::getSingleton().ScriptRequest(
  879. trigger, "on_near_once", 1, entity->GetName(), "", false, false
  880. );
  881. }
  882. // Check on leave line.
  883. // Must be triggered once when the line is not in the entity solid radius, but only if
  884. // on enter script has been triggered previously.
  885. if (
  886. square_dist != -1 && square_dist > solid_radius * solid_radius
  887. && entity_triggers_[i]->CheckApproached()
  888. ){
  889. //std::cout << " [TRIGGER] " << entity->GetName() << " on_leave "
  890. // << entity_triggers_[i]->GetName() << std::endl;
  891. ScriptManager::getSingleton().ScriptRequest(
  892. trigger, "on_leave", 1, entity->GetName(), "", false, false
  893. );
  894. }
  895. // If the entity is far enough from the line, mark every trigger as inactive
  896. if (square_dist == -1 || square_dist > solid_radius * solid_radius){
  897. entity_triggers_[i]->Clear();
  898. //std::cout << " [TRIGGER] " << entity->GetName() << " clear of "
  899. // << entity_triggers_[i]->GetName() << std::endl;
  900. }
  901. }
  902. }
  903. }
  904. void EntityManager::CheckEntityInteract(){
  905. if (player_entity_ == NULL || player_lock_ == true || player_entity_->IsSolid() == false)
  906. return;
  907. Ogre::Degree angle_pc = player_entity_->GetRotation();
  908. Entity* entity_to_interact = NULL;
  909. Ogre::Degree less_angle(90);
  910. for (unsigned int i = 0; i < entity_.size(); ++ i){
  911. if (entity_[i]->IsTalkable() == false) continue;
  912. if (entity_[i] == player_entity_) continue;
  913. Ogre::Vector3 pos1 = entity_[i]->GetPosition();
  914. float interact_range = entity_[i]->GetTalkRadius();
  915. Ogre::Vector3 pos2 = player_entity_->GetPosition();
  916. float solid_range = player_entity_->GetSolidRadius();
  917. int height = (pos1.z < pos2.z) ? entity_[i]->GetHeight() : player_entity_->GetHeight();
  918. if (((pos1.z - pos2.z + height) < (height * 2)) && ((pos1.z - pos2.z + height) >= 0)){
  919. interact_range = (interact_range + solid_range) * (interact_range + solid_range);
  920. float distance
  921. = (pos1.x - pos2.x) * (pos1.x - pos2.x) + (pos1.y - pos2.y) * (pos1.y - pos2.y);
  922. if (distance < interact_range + solid_range){
  923. Ogre::Degree angle_to_model = GetDirectionToPoint(pos2, pos1);
  924. Ogre::Degree angle = angle_pc - angle_to_model;
  925. angle = (angle < Ogre::Degree(0)) ? -angle : angle;
  926. angle = (angle >= Ogre::Degree(180)) ? Ogre::Degree(360) - angle : angle;
  927. if (angle < less_angle){
  928. angle = less_angle;
  929. entity_to_interact = entity_[i];
  930. }
  931. }
  932. }
  933. }
  934. if (entity_to_interact != NULL && entity_to_interact->IsLine() == false){
  935. Ogre::String name = entity_to_interact->GetName();
  936. ScriptEntity* scr_entity = ScriptManager::getSingleton().GetScriptEntityByName(
  937. ScriptManager::ENTITY, name
  938. );
  939. bool added = ScriptManager::getSingleton().ScriptRequest(
  940. scr_entity, "on_interact", 1, "", "", false, false
  941. );
  942. if (added == false){
  943. LOG_WARNING("Script 'on_interact' for entity '" + name + "' doesn't exist.");
  944. }
  945. }
  946. }
  947. void EntityManager::SetNextOffsetStep(Entity* entity){
  948. ActionType type = entity->GetOffsetType();
  949. float total = entity->GetOffsetSeconds();
  950. float current = entity->GetOffsetCurrentSeconds();
  951. current += Timer::getSingleton().GetGameTimeDelta();
  952. current = (current > total) ? total : current;
  953. Ogre::Vector3 start = entity->GetOffsetPositionStart();
  954. Ogre::Vector3 end = entity->GetOffsetPositionEnd();
  955. // TODO: Prevent division by 0:
  956. float x = current / total;
  957. if (std::isnan(x)) x = 0.0f;
  958. float smooth_modifier = (type == AT_SMOOTH) ? -2 * x * x * x + 3 * x * x : x;
  959. Ogre::Vector3 offset = start + (end - start) * smooth_modifier;
  960. entity->SetOffset(offset);
  961. if (current == total) entity->UnsetOffset();
  962. else entity->SetOffsetCurrentSeconds(current);
  963. }
  964. void EntityManager::SetNextTurnStep(Entity* entity){
  965. ActionType type = entity->GetTurnType();
  966. float total = entity->GetTurnSeconds();
  967. float current = entity->GetTurnCurrentSeconds();
  968. current += Timer::getSingleton().GetGameTimeDelta();
  969. current = (current > total) ? total : current;
  970. Ogre::Degree start = entity->GetTurnDirectionStart();
  971. Ogre::Degree end = entity->GetTurnDirectionEnd();
  972. // TODO: Prevent division by 0:
  973. float x = current / total;
  974. float smooth_modifier = (type == AT_SMOOTH) ? -2 * x * x * x + 3 * x * x : x;
  975. Ogre::Degree rotation = start + (end - start) * smooth_modifier;
  976. entity->SetRotation(rotation);
  977. if (current == total) entity->UnsetTurn();
  978. else entity->SetTurnCurrentSeconds(current);
  979. }
  980. void EntityManager::SetNextLinearStep(Entity* entity){
  981. bool to_end = true;
  982. bool is_move = false;
  983. Ogre::Vector3 start = entity->GetLinearStart();
  984. Ogre::Vector3 end = entity->GetLinearEnd();
  985. Ogre::Vector3 current = entity->GetPosition();
  986. float delta = Timer::getSingleton().GetGameTimeDelta();
  987. if (entity == player_entity_){
  988. LinearMovement move = entity->GetLinearMovement();
  989. if (move == LM_DOWN_TO_UP || move == LM_UP_TO_DOWN){
  990. if (player_move_.y > 0){ // move up
  991. to_end = (move == LM_DOWN_TO_UP) ? true : false;
  992. is_move = true;
  993. }
  994. else if (player_move_.y < 0){ // move down
  995. to_end = (move == LM_DOWN_TO_UP) ? false : true;
  996. is_move = true;
  997. }
  998. }
  999. else if (move == LM_LEFT_TO_RIGHT || move == LM_RIGHT_TO_LEFT){
  1000. if (player_move_.x > 0){ // move right
  1001. to_end = (move == LM_LEFT_TO_RIGHT) ? true : false;
  1002. is_move = true;
  1003. }
  1004. else if (player_move_.x < 0){ // move left
  1005. to_end = (move == LM_LEFT_TO_RIGHT) ? false : true;
  1006. is_move = true;
  1007. }
  1008. }
  1009. }
  1010. else is_move = true;
  1011. if (is_move == true){
  1012. Ogre::Vector3 position;
  1013. if (to_end == true){
  1014. Ogre::Vector3 end_start = end - start;
  1015. // Move across the whole line by this number of seconds.
  1016. float time = end_start.length() / 1.2f;
  1017. position.x = current.x + (end_start.x / time) * delta;
  1018. position.y = current.y + (end_start.y / time) * delta;
  1019. position.z = current.z + (end_start.z / time) * delta;
  1020. position.x = (end_start.x < 0)
  1021. ? std::max(position.x, end.x) : std::min(position.x, end.x);
  1022. position.y = (end_start.y < 0)
  1023. ? std::max(position.y, end.y) : std::min(position.y, end.y);
  1024. position.z = (end_start.z < 0)
  1025. ? std::max(position.z, end.z) : std::min(position.z, end.z);
  1026. if (position == end){
  1027. entity->UnsetLinear();
  1028. entity->SetMoveTriangleId(entity->GetLinearDestTriangle());
  1029. SetEntityOnWalkmesh(entity);
  1030. }
  1031. }
  1032. else{
  1033. Ogre::Vector3 end_start = start - end;
  1034. // Move across the whole line by this number of seconds.
  1035. float time = end_start.length() / 1.2f;
  1036. position.x = current.x + (end_start.x / time) * delta;
  1037. position.y = current.y + (end_start.y / time) * delta;
  1038. position.z = current.z + (end_start.z / time) * delta;
  1039. position.x = (end_start.x < 0)
  1040. ? std::max(position.x, start.x) : std::min(position.x, start.x);
  1041. position.y = (end_start.y < 0)
  1042. ? std::max(position.y, start.y) : std::min(position.y, start.y);
  1043. position.z = (end_start.z < 0)
  1044. ? std::max(position.z, start.z) : std::min(position.z, start.z);
  1045. if (position == start){
  1046. entity->UnsetLinear();
  1047. SetEntityOnWalkmesh(entity);
  1048. }
  1049. }
  1050. entity->SetPosition(position);
  1051. entity->UpdateAnimation((to_end == true) ? delta : -delta);
  1052. }
  1053. }
  1054. void EntityManager::SetNextJumpStep(Entity* entity){
  1055. float total = entity->GetJumpSeconds();
  1056. float current = entity->GetJumpCurrentSeconds();
  1057. current += Timer::getSingleton().GetGameTimeDelta();
  1058. current = (current > total) ? total : current;
  1059. Ogre::Vector3 start_position = entity->GetJumpStart();
  1060. Ogre::Vector3 end_position = entity->GetJumpEnd();
  1061. Ogre::Vector3 position;
  1062. position.x = start_position.x + ((end_position.x - start_position.x) / total) * current;
  1063. position.y = start_position.y + ((end_position.y - start_position.y) / total) * current;
  1064. position.z = current * current * -1.0f + current
  1065. * ((end_position.z - start_position.z) / total + total * 1.0f) + start_position.z;
  1066. entity->SetPosition(position);
  1067. if (total == current){
  1068. entity->UnsetJump();
  1069. entity->SetMoveTriangleId(entity->GetJumpDestTriangle());
  1070. SetEntityOnWalkmesh(entity);
  1071. }
  1072. else entity->SetJumpCurrentSeconds(current);
  1073. }
  1074. void EntityManager::SetNextScrollStep(){
  1075. Background2D::SCROLL_TYPE type = background_2d_.GetScrollType();
  1076. float total = background_2d_.GetScrollSeconds();
  1077. float current = background_2d_.GetScrollCurrentSeconds();
  1078. current += Timer::getSingleton().GetGameTimeDelta();
  1079. current = (current > total) ? total : current;
  1080. Ogre::Vector2 start = background_2d_.GetScrollPositionStart();
  1081. Ogre::Vector2 end = background_2d_.GetScrollPositionEnd();
  1082. float x = current / total;
  1083. float smooth_modifier = (type == Background2D::SMOOTH) ? -2 * x * x * x + 3 * x * x : x;
  1084. Ogre::Vector2 scroll = start + (end - start) * smooth_modifier;
  1085. background_2d_.SetScroll(scroll);
  1086. if (current == total) background_2d_.UnsetScroll();
  1087. else background_2d_.SetScrollCurrentSeconds(current);
  1088. }