1 ////////////////////////////////////////////////////////////////////////////////
2 // Copyright (C) 2014-2016 by Bertram (Valyria Tear)
3 // All Rights Reserved
4 //
5 // This code is licensed under the GNU GPL version 2. It is free software
6 // and you may modify it and/or redistribute it under the terms of this license.
7 // See https://www.gnu.org/copyleft/gpl.html for details.
8 ////////////////////////////////////////////////////////////////////////////////
9
10 /** ****************************************************************************
11 *** \file map_status_effects.cpp
12 *** \author Yohann Ferreira, yohann ferreira orange fr
13 *** \brief Source file for map active status effects handling.
14 *** ***************************************************************************/
15
16 #include "modes/map/map_status_effects.h"
17
18 #include "modes/map/map_mode.h"
19
20 #include "script/script_read.h"
21
22 #include "common/global/global.h"
23 #include "common/global/actors/global_character.h"
24
25 #include "engine/video/video.h"
26
27 using namespace vt_global;
28
29 namespace vt_map
30 {
31
32 namespace private_map
33 {
34
35 //! \brief Gives the X effect position from the given index
_GetEffectXPositionFromCharacterIndex(uint32_t index)36 float _GetEffectXPositionFromCharacterIndex(uint32_t index)
37 {
38 return 90.0f + (float)(index * 130);
39 }
40
41 //! \brief Where on screen (on y-axis) the active status effects icon should be displayed
42 const float EFFECTS_Y_POS = 750.0f;
43
44 ////////////////////////////////////////////////////////////////////////////////
45 // PassiveMapStatusEffect class
46 ////////////////////////////////////////////////////////////////////////////////
47
PassiveMapStatusEffect(vt_global::GlobalCharacter * character,vt_global::GLOBAL_STATUS type,vt_global::GLOBAL_INTENSITY intensity)48 PassiveMapStatusEffect::PassiveMapStatusEffect(vt_global::GlobalCharacter* character,
49 vt_global::GLOBAL_STATUS type,
50 vt_global::GLOBAL_INTENSITY intensity):
51 GlobalStatusEffect(type, intensity),
52 _affected_character(character),
53 _icon_image(nullptr)
54 {
55 // Check that the constructor arguments are valid
56 if((type <= GLOBAL_STATUS_INVALID) || (type >= GLOBAL_STATUS_TOTAL)) {
57 PRINT_WARNING << "The constructor received an invalid type argument: " << type << std::endl;
58 return;
59 }
60 if((intensity <= GLOBAL_INTENSITY_INVALID) || (intensity >= GLOBAL_INTENSITY_TOTAL)) {
61 PRINT_WARNING << "The constructor received an invalid intensity argument: " << intensity << std::endl;
62 return;
63 }
64 if(character == nullptr) {
65 PRINT_WARNING << "The constructor received nullptr character argument" << std::endl;
66 return;
67 }
68
69 // Make sure that a table entry exists for this status element
70 uint32_t table_id = static_cast<uint32_t>(type);
71 vt_script::ReadScriptDescriptor &script_file = vt_global::GlobalManager->GetStatusEffectsScript();
72 if(!script_file.OpenTable(table_id)) {
73 PRINT_WARNING << "Lua definition file contained no entry for status effect: " << table_id << std::endl;
74 return;
75 }
76
77 // Read in the status effect's property data
78 _name = script_file.ReadString("name");
79
80 if(script_file.DoesFunctionExist("MapUpdatePassive")) {
81 _update_passive_function = script_file.ReadFunctionPointer("MapUpdatePassive");
82 } else {
83 PRINT_WARNING << "No MapUpdatePassive() function found in Lua definition file for status: " << table_id << std::endl;
84 }
85
86 script_file.CloseTable(); // table_id
87
88 if(script_file.IsErrorDetected()) {
89 PRINT_WARNING << "one or more errors occurred while reading status effect data - they are listed below"
90 << std::endl << script_file.GetErrorMessages() << std::endl;
91 }
92
93 _icon_image = GlobalManager->Media().GetStatusIcon(_type, _intensity);
94 }
95
96 ////////////////////////////////////////////////////////////////////////////////
97 // ActiveMapStatusEffect class
98 ////////////////////////////////////////////////////////////////////////////////
99
ActiveMapStatusEffect(vt_global::GlobalCharacter * character,vt_global::GLOBAL_STATUS type,vt_global::GLOBAL_INTENSITY intensity,uint32_t duration)100 ActiveMapStatusEffect::ActiveMapStatusEffect(vt_global::GlobalCharacter* character,
101 vt_global::GLOBAL_STATUS type,
102 vt_global::GLOBAL_INTENSITY intensity,
103 uint32_t duration) :
104 GlobalStatusEffect(type, intensity),
105 _affected_character(character),
106 _timer(0),
107 _icon_image(nullptr),
108 _intensity_changed(false)
109 {
110 // Check that the constructor arguments are valid
111 if((type <= GLOBAL_STATUS_INVALID) || (type >= GLOBAL_STATUS_TOTAL)) {
112 PRINT_WARNING << "The constructor received an invalid type argument: " << type << std::endl;
113 return;
114 }
115 if((intensity <= GLOBAL_INTENSITY_INVALID) || (intensity >= GLOBAL_INTENSITY_TOTAL)) {
116 PRINT_WARNING << "The constructor received an invalid intensity argument: " << intensity << std::endl;
117 return;
118 }
119 if(character == nullptr) {
120 PRINT_WARNING << "The constructor received nullptr character argument" << std::endl;
121 return;
122 }
123
124 // Make sure that a table entry exists for this status element
125 uint32_t table_id = static_cast<uint32_t>(type);
126 vt_script::ReadScriptDescriptor &script_file = vt_global::GlobalManager->GetStatusEffectsScript();
127 if(!script_file.OpenTable(table_id)) {
128 PRINT_WARNING << "Lua definition file contained no entry for status effect: " << table_id << std::endl;
129 return;
130 }
131
132 // Read in the status effect's property data
133 _name = script_file.ReadString("name");
134
135 // Read the fall back duration when none is given.
136 if(duration == 0)
137 duration = script_file.ReadUInt("default_duration");
138 _timer.SetDuration(duration);
139
140 if(script_file.DoesFunctionExist("MapApply")) {
141 _apply_function = script_file.ReadFunctionPointer("MapApply");
142 } else {
143 PRINT_WARNING << "No MapApply() function found in Lua definition file for status: " << table_id << std::endl;
144 }
145
146 if(script_file.DoesFunctionExist("MapUpdate")) {
147 _update_function = script_file.ReadFunctionPointer("MapUpdate");
148 } else {
149 PRINT_WARNING << "No MapUpdate() function found in Lua definition file for status: " << table_id << std::endl;
150 }
151
152 if(script_file.DoesFunctionExist("MapRemove")) {
153 _remove_function = script_file.ReadFunctionPointer("MapRemove");
154 } else {
155 PRINT_WARNING << "No MapRemove() function found in Lua definition file for status: " << table_id << std::endl;
156 }
157 script_file.CloseTable(); // table_id
158
159 if(script_file.IsErrorDetected()) {
160 PRINT_WARNING << "one or more errors occurred while reading status effect data - they are listed below"
161 << std::endl << script_file.GetErrorMessages() << std::endl;
162 }
163
164 // Init the effect timer
165 _timer.EnableManualUpdate();
166 _timer.Reset();
167 _timer.Run();
168
169 _icon_image = GlobalManager->Media().GetStatusIcon(_type, _intensity);
170 }
171
SetIntensity(vt_global::GLOBAL_INTENSITY intensity)172 void ActiveMapStatusEffect::SetIntensity(vt_global::GLOBAL_INTENSITY intensity)
173 {
174 if((intensity <= GLOBAL_INTENSITY_INVALID) || (intensity >= GLOBAL_INTENSITY_TOTAL)) {
175 PRINT_WARNING << "Attempted to set status effect to invalid intensity: " << intensity << std::endl;
176 return;
177 }
178
179 bool no_intensity_change = (_intensity == intensity);
180 _intensity = intensity;
181 _ProcessIntensityChange(no_intensity_change);
182 }
183
IncrementIntensity(uint8_t amount)184 bool ActiveMapStatusEffect::IncrementIntensity(uint8_t amount)
185 {
186 bool change = GlobalStatusEffect::IncrementIntensity(amount);
187 _ProcessIntensityChange(!change);
188 return change;
189 }
190
DecrementIntensity(uint8_t amount)191 bool ActiveMapStatusEffect::DecrementIntensity(uint8_t amount)
192 {
193 bool change = GlobalStatusEffect::DecrementIntensity(amount);
194 _ProcessIntensityChange(!change);
195 return change;
196 }
197
_ProcessIntensityChange(bool reset_timer_only)198 void ActiveMapStatusEffect::_ProcessIntensityChange(bool reset_timer_only)
199 {
200 _timer.Reset();
201 _timer.Run();
202
203 if(reset_timer_only)
204 return;
205
206 _intensity_changed = true;
207 _icon_image = vt_global::GlobalManager->Media().GetStatusIcon(_type, _intensity);
208 }
209
210 ////////////////////////////////////////////////////////////////////////////////
211 // CharacterIndication class
212 ////////////////////////////////////////////////////////////////////////////////
213
CharacterIndication(vt_global::GlobalCharacter * character,float x_position,float y_position)214 CharacterIndication::CharacterIndication(vt_global::GlobalCharacter* character,
215 float x_position, float y_position):
216 _position(x_position, y_position),
217 _image_alpha(0.0f),
218 _fade_in(false),
219 _fade_out(false),
220 _display_time(0),
221 _global_character(character)
222 {
223 // Loads a copy of the portrait.
224 if (character)
225 _portrait.Load(character->GetPortrait().GetFilename());
226
227 if (!_portrait.GetFilename().empty())
228 _portrait.SetHeightKeepRatio(65.0f);
229 }
230
Update()231 void CharacterIndication::Update()
232 {
233 uint32_t elapsed_time = vt_system::SystemManager->GetUpdateTime();
234 // Apply fading
235 if (_fade_out) {
236 _image_alpha -= 0.005f * (float)elapsed_time;
237 if (_image_alpha <= 0.0f) {
238 _image_alpha = 0.0f;
239 _fade_out = false;
240 }
241 }
242 else if (_fade_in) {
243 _image_alpha += 0.005f * (float)elapsed_time;
244 if (_image_alpha >= 1.0f) {
245 _image_alpha = 1.0f;
246 _fade_in = false;
247 }
248 }
249
250 // Check time limit
251 if (_display_time <= 0) {
252 _display_time = 0;
253 FadeOut();
254 return;
255 }
256
257 // Update display time otherwise
258 _display_time -= (int32_t)elapsed_time;
259 }
260
Draw()261 void CharacterIndication::Draw() {
262 if (_image_alpha <= 0.0f)
263 return;
264
265 vt_video::VideoManager->SetDrawFlags(vt_video::VIDEO_X_RIGHT, vt_video::VIDEO_Y_BOTTOM, vt_video::VIDEO_BLEND, 0);
266 vt_video::VideoManager->Move(_position.x, _position.y);
267
268 _portrait.Draw(vt_video::Color(1.0f, 1.0f, 1.0f, _image_alpha));
269 }
270
271 ////////////////////////////////////////////////////////////////////////////////
272 // MapStatusEffectsSupervisor class
273 ////////////////////////////////////////////////////////////////////////////////
274
MapStatusEffectsSupervisor()275 MapStatusEffectsSupervisor::MapStatusEffectsSupervisor()
276 {
277 LoadStatusEffects();
278 }
279
~MapStatusEffectsSupervisor()280 MapStatusEffectsSupervisor::~MapStatusEffectsSupervisor()
281 {
282 SaveActiveStatusEffects();
283 }
284
LoadStatusEffects()285 void MapStatusEffectsSupervisor::LoadStatusEffects()
286 {
287 // First, wipe out every old data
288 _active_status_effects.clear();
289 _equipment_status_effects.clear();
290 _characters_portraits.clear();
291
292 std::vector<GlobalCharacter*>* characters = GlobalManager->GetCharacterHandler().GetOrderedCharacters();
293 if (!characters)
294 return;
295
296 // For each character, we load the status effects data
297 for (uint32_t i = 0; i < characters->size(); ++i) {
298 GlobalCharacter* character = (*characters)[i];
299
300 if (!character)
301 continue;
302
303 // Loads or reloads the Character portraits positions (in case the party order has changed)
304 float x_pos = _GetEffectXPositionFromCharacterIndex(i);
305 _characters_portraits.push_back(CharacterIndication(character, x_pos, EFFECTS_Y_POS));
306
307 // passive effects
308 const std::vector<GLOBAL_INTENSITY>& passives = character->GetEquipementStatusEffects();
309 for (uint32_t j = 0; j < passives.size(); ++j) {
310 GLOBAL_STATUS status = (vt_global::GLOBAL_STATUS)j;
311 GLOBAL_INTENSITY intensity = passives.at(j);
312
313 if (status < GLOBAL_STATUS_TOTAL
314 && intensity != GLOBAL_INTENSITY_INVALID
315 && intensity != GLOBAL_INTENSITY_NEUTRAL) {
316 _AddPassiveStatusEffect(character, status, intensity);
317 }
318 }
319
320 // active effects
321 const std::vector<ActiveStatusEffect>& actives = character->GetActiveStatusEffects();
322 for (uint32_t j = 0; j < actives.size(); ++j) {
323 GLOBAL_STATUS status = actives.at(j).GetEffect();
324 GLOBAL_INTENSITY intensity = actives.at(j).GetIntensity();
325
326 if (status < GLOBAL_STATUS_TOTAL
327 && intensity != GLOBAL_INTENSITY_INVALID
328 && intensity != GLOBAL_INTENSITY_NEUTRAL) {
329 _AddActiveStatusEffect(character, status, intensity,
330 actives.at(j).GetEffectTime(),
331 actives.at(j).GetElapsedTime());
332 }
333 }
334 }
335 }
336
SaveActiveStatusEffects()337 void MapStatusEffectsSupervisor::SaveActiveStatusEffects()
338 {
339 // first, we clear the old data from the characters
340 std::vector<GlobalCharacter*>* characters = GlobalManager->GetCharacterHandler().GetOrderedCharacters();
341 if (!characters)
342 return;
343
344 for (uint32_t i = 0; i < characters->size(); ++i) {
345 GlobalCharacter* character = (*characters)[i];
346
347 if (!character)
348 continue;
349
350 character->ResetActiveStatusEffects();
351 }
352
353 // Then, we copy every active status effects back to the affected character.
354 for (uint32_t i = 0; i < _active_status_effects.size(); ++i) {
355 ActiveMapStatusEffect& effect = _active_status_effects[i];
356 if (effect.GetType() == GLOBAL_STATUS_INVALID)
357 continue;
358
359 GlobalCharacter* character = effect.GetAffectedCharacter();
360 if (!character)
361 continue;
362
363 vt_system::SystemTimer* timer = effect.GetTimer();
364 character->SetActiveStatusEffect(effect.GetType(), effect.GetIntensity(),
365 timer->GetDuration(), timer->GetTimeExpired());
366 }
367 }
368
_UpdatePassive()369 void MapStatusEffectsSupervisor::_UpdatePassive()
370 {
371 for(uint32_t i = 0; i < _equipment_status_effects.size(); ++i) {
372 PassiveMapStatusEffect& effect = _equipment_status_effects.at(i);
373
374 if (!effect.GetUpdatePassiveFunction().is_valid())
375 continue;
376
377 // Update the update timer if it is running
378 vt_system::SystemTimer *update_timer = effect.GetUpdateTimer();
379 bool use_update_timer = effect.IsUsingUpdateTimer();
380 if (use_update_timer) {
381 uint32_t update_time = vt_system::SystemManager->GetUpdateTime();
382 update_timer->Update(update_time);
383 }
384
385 if (!use_update_timer || update_timer->IsFinished()) {
386
387 // Call the update passive function
388 try {
389 luabind::call_function<void>(effect.GetUpdatePassiveFunction(), effect.GetAffectedCharacter(), effect.GetIntensity());
390 } catch(const luabind::error& e) {
391 PRINT_ERROR << "Error while loading status effect MapUpdatePassive() function" << std::endl;
392 vt_script::ScriptManager->HandleLuaError(e);
393 } catch(const luabind::cast_failed& e) {
394 PRINT_ERROR << "Error while loading status effect MapUpdatePassive() function" << std::endl;
395 vt_script::ScriptManager->HandleCastError(e);
396 }
397
398 // Restart the update timer when needed
399 if (use_update_timer) {
400 update_timer->Reset();
401 update_timer->Run();
402 }
403 }
404 }
405 }
406
UpdateEffects()407 void MapStatusEffectsSupervisor::UpdateEffects()
408 {
409 // Update the timers and state for all active status effects
410 std::vector<ActiveMapStatusEffect>::iterator it = _active_status_effects.begin();
411 for(; it != _active_status_effects.end();) {
412 ActiveMapStatusEffect& effect = *it;
413 if(!effect.IsActive()) {
414 // Remove from loop
415 it = _active_status_effects.erase(it);
416 continue;
417 }
418
419 bool effect_removed = false;
420
421 vt_system::SystemTimer* effect_timer = effect.GetTimer();
422 vt_system::SystemTimer* update_timer = effect.GetUpdateTimer();
423
424 // Update the effect time while taking in account the battle speed
425 uint32_t update_time = vt_system::SystemManager->GetUpdateTime();
426 effect_timer->Update(update_time);
427
428 // Update the update timer if it is running
429 bool use_update_timer = effect.IsUsingUpdateTimer();
430 if (use_update_timer)
431 update_timer->Update(update_time);
432
433 // Decrease the intensity of the status by one level when its timer expires. This may result in
434 // the status effect being removed from the actor if its intensity changes to the neutral level.
435 if(effect_timer->IsFinished()) {
436 // If the intensity of the effect is at its weakest, the call that follows will remove the effect from the actor
437 effect_removed = (effect.GetIntensity() == GLOBAL_INTENSITY_POS_LESSER
438 || effect.GetIntensity() == GLOBAL_INTENSITY_NEG_LESSER);
439
440 // As the effect is fading, we divide the effect duration time per 2, with at least 1 second of duration.
441 // This is done to give more a fading out style onto the effect and not to advantage/disadvantage the target
442 // too much.
443 uint32_t duration = effect_timer->GetDuration() / 2;
444 effect_timer->SetDuration(duration < 1000 ? 1000 : duration);
445
446 if (effect.GetIntensity() > GLOBAL_INTENSITY_NEUTRAL) {
447 ChangeActiveStatusEffect(effect, GLOBAL_INTENSITY_NEG_LESSER, duration);
448 }
449 else {
450 ChangeActiveStatusEffect(effect, GLOBAL_INTENSITY_POS_LESSER, duration);
451 }
452 }
453
454 if (effect_removed) {
455 // Remove from loop
456 it = _active_status_effects.erase(it);
457 continue;
458 }
459
460 // Update the effect according to the script function
461 if (!use_update_timer || update_timer->IsFinished()) {
462 if (effect.GetUpdateFunction().is_valid()) {
463
464 try {
465 luabind::call_function<void>(effect.GetUpdateFunction(), effect);
466 } catch(const luabind::error& e) {
467 PRINT_ERROR << "Error while loading status effect Update function" << std::endl;
468 vt_script::ScriptManager->HandleLuaError(e);
469 } catch(const luabind::cast_failed& e) {
470 PRINT_ERROR << "Error while loading status effect Update function" << std::endl;
471 vt_script::ScriptManager->HandleCastError(e);
472 }
473 }
474 else {
475 PRINT_WARNING << "No status effect Update function defined." << std::endl;
476 }
477 // If the character has his effects removed because of the effect update (when dying)
478 // The effect doesn't exist anymore, so we have to check this here.
479 if(!effect.IsActive()) {
480 // Remove from loop
481 it = _active_status_effects.erase(it);
482 continue;
483 }
484
485 effect.ResetIntensityChanged();
486
487 // Restart the update timer when needed
488 if (use_update_timer) {
489 update_timer->Reset();
490 update_timer->Run();
491 }
492 }
493
494 ++it;
495 }
496
497 _UpdatePassive();
498 }
499
UpdatePortraits()500 void MapStatusEffectsSupervisor::UpdatePortraits()
501 {
502 // Update portrait indicators
503 for (uint32_t i = 0; i < _characters_portraits.size(); ++i)
504 _characters_portraits[i].Update();
505 }
506
Draw()507 void MapStatusEffectsSupervisor::Draw()
508 {
509 // Draw character portraits shown when effects changes are triggered.
510 for (uint32_t i = 0; i < _characters_portraits.size(); ++i)
511 _characters_portraits[i].Draw();
512 }
513
ChangeActiveStatusEffect(GlobalCharacter * character,vt_global::GLOBAL_STATUS status_type,vt_global::GLOBAL_INTENSITY intensity,uint32_t duration,uint32_t elapsed_time,bool display_change)514 bool MapStatusEffectsSupervisor::ChangeActiveStatusEffect(GlobalCharacter* character,
515 vt_global::GLOBAL_STATUS status_type,
516 vt_global::GLOBAL_INTENSITY intensity,
517 uint32_t duration, uint32_t elapsed_time,
518 bool display_change)
519 {
520 if (!character)
521 return false;
522
523 if (intensity == GLOBAL_INTENSITY_NEUTRAL
524 || intensity <= GLOBAL_INTENSITY_INVALID
525 || intensity >= GLOBAL_INTENSITY_TOTAL)
526 return false;
527
528 for (uint32_t i = 0; i < _active_status_effects.size(); ++i) {
529 ActiveMapStatusEffect& active_effect = _active_status_effects[i];
530
531 if (active_effect.GetType() != status_type)
532 continue;
533 if (active_effect.GetAffectedCharacter() != character)
534 continue;
535
536 // If the effect is found, we apply the new change on it.
537 return ChangeActiveStatusEffect(active_effect, intensity, duration, elapsed_time, display_change);
538 }
539
540 // Add a new status effect
541 _AddActiveStatusEffect(character, status_type, intensity, duration);
542
543 if (!display_change)
544 return true;
545
546 vt_mode_manager::IndicatorSupervisor& indicator = MapMode::CurrentInstance()->GetIndicatorSupervisor();
547 indicator.AddStatusIndicator(_GetEffectAnimationXPosition(character), EFFECTS_Y_POS,
548 status_type, GLOBAL_INTENSITY_NEUTRAL, intensity);
549 _MakeCharacterPortraitAppear(character, vt_mode_manager::INDICATOR_TIME); // default time in milliseconds
550 return true;
551 }
552
ChangeActiveStatusEffect(ActiveMapStatusEffect & active_effect,GLOBAL_INTENSITY intensity,uint32_t duration,uint32_t elapsed_time,bool display_change)553 bool MapStatusEffectsSupervisor::ChangeActiveStatusEffect(ActiveMapStatusEffect& active_effect,
554 GLOBAL_INTENSITY intensity,
555 uint32_t duration, uint32_t elapsed_time,
556 bool display_change)
557 {
558 if (!active_effect.IsActive())
559 return false;
560
561 // Determine if we are attempting to increment or decrement the intensity of this status
562 bool increase_intensity = false;
563 if((intensity <= GLOBAL_INTENSITY_POS_EXTREME) && (intensity > GLOBAL_INTENSITY_NEUTRAL))
564 increase_intensity = true;
565
566 // Holds the unsigned amount of change in intensity in either a positive or negative degree
567 uint8_t intensity_change = abs(static_cast<int8_t>(intensity));
568
569 // Used to determine the intensity change of the effect.
570 GLOBAL_INTENSITY new_intensity = GLOBAL_INTENSITY_INVALID;
571
572 // Set the previous status and intensity return values to match the active effect, if one was found to exist
573 GLOBAL_INTENSITY previous_intensity = active_effect.GetIntensity();
574
575 // Set the coordinates of the status effect next to the corresponding portrait
576 vt_mode_manager::IndicatorSupervisor& indicator = MapMode::CurrentInstance()->GetIndicatorSupervisor();
577 vt_global::GlobalCharacter* character = active_effect.GetAffectedCharacter();
578 float x_pos = _GetEffectAnimationXPosition(character);
579
580 // Perform status changes according to the previously determined information
581 if(active_effect.IsActive()) {
582 if (increase_intensity)
583 active_effect.IncrementIntensity(intensity_change);
584 else
585 active_effect.DecrementIntensity(intensity_change);
586
587 new_intensity = active_effect.GetIntensity();
588
589 // If the status was decremented to the neutral level, this means it is no longer active and should be removed
590 // NOTE: The actual removal of the effect will be done in the Update() loop.
591 if(new_intensity == GLOBAL_INTENSITY_NEUTRAL)
592 _RemoveActiveStatusEffect(active_effect);
593
594 if (!display_change)
595 return true;
596
597 indicator.AddStatusIndicator(x_pos, EFFECTS_Y_POS, active_effect.GetType(), previous_intensity, new_intensity);
598 _MakeCharacterPortraitAppear(character, vt_mode_manager::INDICATOR_TIME);
599 return true;
600 }
601 else {
602 _AddActiveStatusEffect(active_effect.GetAffectedCharacter(), active_effect.GetType(), intensity, duration, elapsed_time);
603 new_intensity = intensity;
604
605 if (!display_change)
606 return true;
607
608 indicator.AddStatusIndicator(x_pos, EFFECTS_Y_POS, active_effect.GetType(), previous_intensity, new_intensity);
609 _MakeCharacterPortraitAppear(character, vt_mode_manager::INDICATOR_TIME);
610 return true;
611 }
612
613 return false;
614 } // bool MapStatusEffectsSupervisor::ChangeActiveStatusEffect( ... )
615
GetActiveStatusEffectIntensity(GlobalCharacter * character,GLOBAL_STATUS status_type) const616 GLOBAL_INTENSITY MapStatusEffectsSupervisor::GetActiveStatusEffectIntensity(GlobalCharacter* character,
617 GLOBAL_STATUS status_type) const
618 {
619 if (character == nullptr)
620 return GLOBAL_INTENSITY_INVALID;
621
622 if (status_type == GLOBAL_STATUS_INVALID || status_type == GLOBAL_STATUS_TOTAL)
623 return GLOBAL_INTENSITY_INVALID;
624
625 for (uint32_t i = 0; i < _active_status_effects.size(); ++i) {
626 const ActiveMapStatusEffect& effect = _active_status_effects[i];
627 if (effect.GetType() != status_type)
628 continue;
629
630 if (effect.GetAffectedCharacter() != character)
631 continue;
632
633 return effect.GetIntensity();
634 }
635
636 return GLOBAL_INTENSITY_NEUTRAL;
637 }
638
RemoveNegativeActiveStatusEffects()639 void MapStatusEffectsSupervisor::RemoveNegativeActiveStatusEffects()
640 {
641 for (uint32_t i = 0; i < _active_status_effects.size(); ++i) {
642 ActiveMapStatusEffect& effect = _active_status_effects[i];
643
644 if (effect.GetIntensity() <= GLOBAL_INTENSITY_NEUTRAL)
645 effect.Disable();
646 }
647 }
648
_AddActiveStatusEffect(GlobalCharacter * character,GLOBAL_STATUS status,GLOBAL_INTENSITY intensity,uint32_t duration,uint32_t elapsed_time)649 void MapStatusEffectsSupervisor::_AddActiveStatusEffect(GlobalCharacter* character,
650 GLOBAL_STATUS status, GLOBAL_INTENSITY intensity,
651 uint32_t duration, uint32_t elapsed_time)
652 {
653 if((status <= GLOBAL_STATUS_INVALID) || (status >= GLOBAL_STATUS_TOTAL)) {
654 PRINT_WARNING << "Function received invalid status argument: " << status << std::endl;
655 return;
656 }
657
658 if((intensity <= GLOBAL_INTENSITY_INVALID) || (intensity >= GLOBAL_INTENSITY_TOTAL)) {
659 PRINT_WARNING << "Function received invalid intensity argument: " << intensity << std::endl;
660 return;
661 }
662
663 _active_status_effects.push_back(ActiveMapStatusEffect(character, status, intensity, duration));
664 ActiveMapStatusEffect& new_effect = _active_status_effects.back();
665
666 // If there is already some elapsed time, we restore it
667 if (elapsed_time > 0 && elapsed_time <= duration)
668 new_effect.GetTimer()->SetTimeExpired(elapsed_time);
669
670 if (!new_effect.GetApplyFunction().is_valid()) {
671 PRINT_WARNING << "No valid status effect Apply function to call" << std::endl;
672 return;
673 }
674
675 // Call the apply script function now that this new status is active on the actor
676 try {
677 luabind::call_function<void>(new_effect.GetApplyFunction(), new_effect);
678 } catch(const luabind::error& e) {
679 PRINT_ERROR << "Error while loading status effect Apply function" << std::endl;
680 vt_script::ScriptManager->HandleLuaError(e);
681 } catch(const luabind::cast_failed& e) {
682 PRINT_ERROR << "Error while loading status effect Apply function" << std::endl;
683 vt_script::ScriptManager->HandleCastError(e);
684 }
685 }
686
_RemoveActiveStatusEffect(ActiveMapStatusEffect & status_effect)687 void MapStatusEffectsSupervisor::_RemoveActiveStatusEffect(ActiveMapStatusEffect& status_effect)
688 {
689 if(!status_effect.IsActive())
690 return;
691
692 // Remove the status effect from the active effects list if it registered there.
693 if (status_effect.GetRemoveFunction().is_valid()) {
694 try {
695 luabind::call_function<void>(status_effect.GetRemoveFunction(), status_effect);
696 } catch(const luabind::error& e) {
697 PRINT_ERROR << "Error while loading status effect Remove function" << std::endl;
698 vt_script::ScriptManager->HandleLuaError(e);
699 } catch(const luabind::cast_failed& e) {
700 PRINT_ERROR << "Error while loading status effect Remove function" << std::endl;
701 vt_script::ScriptManager->HandleCastError(e);
702 }
703 }
704 else {
705 PRINT_WARNING << "No status effect Remove function defined." << std::endl;
706 }
707
708 status_effect.Disable();
709
710 }
711
_SetActiveStatusEffects(GlobalCharacter * character)712 void MapStatusEffectsSupervisor::_SetActiveStatusEffects(GlobalCharacter* character)
713 {
714 if (!character)
715 return;
716
717 character->ResetActiveStatusEffects();
718 for(std::vector<ActiveMapStatusEffect>::iterator it = _active_status_effects.begin();
719 it != _active_status_effects.end(); ++it) {
720 ActiveMapStatusEffect& effect = (*it);
721 if (!effect.IsActive())
722 continue;
723
724 // Copy the active status effect state
725 vt_system::SystemTimer* timer = effect.GetTimer();
726 character->SetActiveStatusEffect(effect.GetType(), effect.GetIntensity(),
727 timer->GetDuration(), timer->GetTimeExpired());
728 }
729 }
730
_AddPassiveStatusEffect(vt_global::GlobalCharacter * character,vt_global::GLOBAL_STATUS status_effect,vt_global::GLOBAL_INTENSITY intensity)731 void MapStatusEffectsSupervisor::_AddPassiveStatusEffect(vt_global::GlobalCharacter* character,
732 vt_global::GLOBAL_STATUS status_effect,
733 vt_global::GLOBAL_INTENSITY intensity)
734 {
735 PassiveMapStatusEffect effect(character, status_effect, intensity);
736 _equipment_status_effects.push_back(effect);
737 }
738
_MakeCharacterPortraitAppear(vt_global::GlobalCharacter * character,uint32_t time)739 void MapStatusEffectsSupervisor::_MakeCharacterPortraitAppear(vt_global::GlobalCharacter* character, uint32_t time)
740 {
741 for (uint32_t i = 0; i < _characters_portraits.size(); ++i) {
742 if (_characters_portraits[i].GetCharacter() == character) {
743 _characters_portraits[i].FadeIn(time);
744 return;
745 }
746 }
747 }
748
_GetEffectAnimationXPosition(vt_global::GlobalCharacter * character)749 float MapStatusEffectsSupervisor::_GetEffectAnimationXPosition(vt_global::GlobalCharacter* character)
750 {
751 float x_pos = 90.0; // default position.
752 for (uint32_t i = 0; i < _characters_portraits.size(); ++i) {
753 if (_characters_portraits[i].GetCharacter() == character) {
754 x_pos = _GetEffectXPositionFromCharacterIndex(i) + 5.0f; // We add an offset to avoid cluttering
755 break;
756 }
757 }
758 return x_pos;
759 }
760
761 } // namespace private_map
762
763 } // namespace vt_map
764