1 ///////////////////////////////////////////////////////////////////////////////
2 //            Copyright (C) 2004-2011 by The Allacrost Project
3 //            Copyright (C) 2012-2019 by Bertram (Valyria Tear)
4 //                         All Rights Reserved
5 //
6 // This code is licensed under the GNU GPL version 2. It is free software
7 // and you may modify it and/or redistribute it under the terms of this license.
8 // See https://www.gnu.org/copyleft/gpl.html for details.
9 ///////////////////////////////////////////////////////////////////////////////
10 
11 #include "character_window.h"
12 
13 #include "common/global/global.h"
14 #include "common/global/actors/global_character.h"
15 
16 #include "engine/video/video.h"
17 #include "utils/ustring.h"
18 
19 using namespace vt_global;
20 using namespace vt_video;
21 using namespace vt_utils;
22 using namespace vt_system;
23 
24 namespace vt_common
25 {
26 
27 // HP / SP bars
28 const float BAR_BASE_SIZE_X = 100.0f;
29 const float BAR_BASE_SIZE_Y = 5.0f;
30 
CharacterWindow()31 CharacterWindow::CharacterWindow():
32     _char_id(vt_global::GLOBAL_CHARACTER_INVALID),
33     _hp_ratio(0.0f),
34     _sp_ratio(0.0f)
35 {
36     // Loads HP/SP icons
37     vt_global::GlobalMedia& media = vt_global::GlobalManager->Media();
38     _hp_icon = media.GetStatusIcon(vt_global::GLOBAL_STATUS_HP,
39                                    vt_global::GLOBAL_INTENSITY_NEUTRAL);
40     _sp_icon = media.GetStatusIcon(vt_global::GLOBAL_STATUS_SP,
41                                    vt_global::GLOBAL_INTENSITY_NEUTRAL);
42 }
43 
SetCharacter(vt_global::GlobalCharacter * character)44 void CharacterWindow::SetCharacter(vt_global::GlobalCharacter* character)
45 {
46     if(!character || character->GetID() == vt_global::GLOBAL_CHARACTER_INVALID) {
47         _character_name.Clear();
48         _character_data.Clear();
49         _portrait = StillImage();
50         _char_id = vt_global::GLOBAL_CHARACTER_INVALID;
51         _hp_ratio = 0.0f;
52         _sp_ratio = 0.0f;
53         _UpdateActiveStatusEffects(nullptr);
54         return;
55     }
56 
57     _char_id = character->GetID();
58 
59     _portrait = character->GetPortrait();
60     // Only size up valid portraits
61     if(!_portrait.GetFilename().empty())
62         _portrait.SetDimensions(100.0f, 100.0f);
63 
64     // the characters' name is already translated.
65     _character_name.SetText(character->GetName(), TextStyle("title22"));
66 
67     // And the rest of the data
68     /// tr: level
69     ustring char_data = UTranslate("Lv: ") + MakeUnicodeString(NumberToString(character->GetExperienceLevel()) + " / ");
70     char_data += UTranslate("Next: ") + MakeUnicodeString(NumberToString(character->GetExperienceForNextLevel()) + "\n");
71     char_data += MakeUnicodeString("      " + NumberToString(character->GetHitPoints()) +
72                  " / " + NumberToString(character->GetMaxHitPoints()) + "\n");
73     char_data += MakeUnicodeString("      " + NumberToString(character->GetSkillPoints()) +
74                  " / " + NumberToString(character->GetMaxSkillPoints()) + "\n");
75     /// tr: experience points to be spent for skills
76     char_data += UTranslate("XP for skills: ") + MakeUnicodeString(NumberToString(character->GetUnspentExperiencePoints()));
77 
78     _character_data.SetText(char_data, TextStyle("text20"));
79 
80     _hp_ratio = static_cast<float>(character->GetHitPoints()) / static_cast<float>(character->GetMaxHitPoints());
81     _sp_ratio = static_cast<float>(character->GetSkillPoints()) / static_cast<float>(character->GetMaxSkillPoints());
82 
83     _UpdateActiveStatusEffects(character);
84 }
85 
Draw()86 void CharacterWindow::Draw()
87 {
88     // Call parent Draw method, if failed pass on fail result
89     MenuWindow::Draw();
90 
91     VideoManager->SetDrawFlags(VIDEO_X_LEFT, VIDEO_Y_TOP, 0);
92 
93     // Get the window metrics
94     Position2D pos = GetPosition();
95     // Adjust the current position to make it look better
96     pos.y += 5;
97 
98     // Draw character portrait
99     VideoManager->Move(pos.x + 12.0f, pos.y + 8.0f);
100     _portrait.Draw();
101 
102     // Write character name
103     VideoManager->MoveRelative(150.0f, -5.0f);
104     _character_name.Draw();
105 
106     if (_hp_ratio > 0.0f) {
107         VideoManager->MoveRelative(30.0f, 55.0f);
108         // HP
109         VideoManager->MoveRelative(0.0f, BAR_BASE_SIZE_Y - 2.0f);
110         VideoManager->DrawRectangle(BAR_BASE_SIZE_X, 2.0f, Color::white);
111         VideoManager->MoveRelative(0.0f, -BAR_BASE_SIZE_Y + 2.0f);
112         if (_hp_ratio < 0.25f) {
113             VideoManager->DrawRectangle(BAR_BASE_SIZE_X * _hp_ratio, BAR_BASE_SIZE_Y, Color::orange);
114         }
115         else {
116             VideoManager->DrawRectangle(BAR_BASE_SIZE_X * _hp_ratio, BAR_BASE_SIZE_Y, Color::green_hp);
117         }
118         // SP
119         VideoManager->MoveRelative(0.0f, 22.0f);
120         VideoManager->MoveRelative(0.0f, BAR_BASE_SIZE_Y - 2.0f);
121         VideoManager->DrawRectangle(BAR_BASE_SIZE_X, 2.0f, Color::white);
122         VideoManager->MoveRelative(0.0f, -BAR_BASE_SIZE_Y + 2.0f);
123         VideoManager->DrawRectangle(BAR_BASE_SIZE_X * _sp_ratio, BAR_BASE_SIZE_Y, Color::blue_sp);
124 
125         VideoManager->MoveRelative(-30.0f, -77.0f);
126     }
127 
128     // Level, HP, SP, XP to Next Lvl
129     VideoManager->MoveRelative(0.0f, 19.0f);
130     _character_data.Draw();
131 
132     // HP/SP Icons
133     if(_char_id != vt_global::GLOBAL_CHARACTER_INVALID) {
134         VideoManager->MoveRelative(0.0f, 20.0f);
135         _hp_icon->Draw();
136         VideoManager->MoveRelative(0.0f, 20.0f);
137         _sp_icon->Draw();
138         VideoManager->MoveRelative(0.0f, -40.0f);
139     }
140 
141     // Active status effects
142     VideoManager->MoveRelative(-30.0f, -17.0f);
143     uint32_t nb_effects = _active_status_effects.size();
144     for (uint32_t i = 0; i < nb_effects && i < 6; ++i) {
145         if (_active_status_effects[i])
146             _active_status_effects[i]->Draw();
147         VideoManager->MoveRelative(0.0f, 15.0f);
148     }
149 
150     if (nb_effects < 6)
151         return;
152 
153     // Show a second column when there are more than 6 active status effects
154     VideoManager->MoveRelative(-15.0f, -6.0f * 15.0f);
155     for (uint32_t i = 6; i < nb_effects && i < 12; ++i) {
156         if (_active_status_effects[i])
157             _active_status_effects[i]->Draw();
158         VideoManager->MoveRelative(0.0f, 15.0f);
159     }
160 
161     if (nb_effects < 12)
162         return;
163 
164     // Show a third column when there are more than 12 active status effects
165     // (maximum 15)
166     VideoManager->MoveRelative(-15.0f, -6.0f * 15.0f);
167     for (uint32_t i = 12; i < nb_effects; ++i) {
168         if (_active_status_effects[i])
169             _active_status_effects[i]->Draw();
170         VideoManager->MoveRelative(0.0f, 15.0f);
171     }
172 }
173 
_UpdateActiveStatusEffects(vt_global::GlobalCharacter * character)174 void CharacterWindow::_UpdateActiveStatusEffects(vt_global::GlobalCharacter* character)
175 {
176     _active_status_effects.clear();
177     if (!character)
178         return;
179 
180     GlobalMedia& media = GlobalManager->Media();
181 
182     const std::vector<ActiveStatusEffect> effects =
183         character->GetActiveStatusEffects();
184     for (uint32_t i = 0; i < effects.size(); ++i) {
185         GLOBAL_STATUS status = effects[i].GetEffect();
186         GLOBAL_INTENSITY intensity = effects[i].GetIntensity();
187         if (status != GLOBAL_STATUS_INVALID &&
188                 intensity != GLOBAL_INTENSITY_NEUTRAL) {
189             StillImage* image = media.GetStatusIcon(status, intensity);
190             if (image)
191                 _active_status_effects.push_back(image);
192         }
193     }
194 }
195 
196 } // namespace vt_common
197