Mana
Loading...
Searching...
No Matches
units.cpp
Go to the documentation of this file.
1/*
2 * Support for custom units
3 * Copyright (C) 2009 The Mana World Development Team
4 * Copyright (C) 2009-2012 The Mana Developers
5 *
6 * This file is part of The Mana Client.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#include "units.h"
23
24#include "log.h"
25
26#include "utils/stringutils.h"
27#include "utils/xml.h"
28
29#include <climits>
30#include <vector>
31
32struct UnitLevel {
33 std::string symbol;
34 int count;
35 int round;
36};
37
39 std::vector<UnitLevel> levels;
40 double conversion;
41 bool mix;
42};
43
49
51
52
54{
55 { // Setup default weight
57
58 ud.conversion = 1.0;
59 ud.mix = false;
60
61 UnitLevel bu;
62 bu.symbol = "g";
63 bu.count = 1;
64 bu.round = 0;
65
66 ud.levels.push_back(bu);
67
68 UnitLevel ul;
69 ul.symbol = "kg";
70 ul.count = 1000;
71 ul.round = 2;
72
73 ud.levels.push_back(ul);
74
75 units[UNIT_WEIGHT] = ud;
76 }
77
78 { // Setup default currency
80
81 ud.conversion = 1.0;
82 ud.mix = false;
83
84 UnitLevel bu;
85 bu.symbol = "¤";
86 bu.count = 1;
87 bu.round = 0;
88
89 ud.levels.push_back(bu);
90
91 units[UNIT_CURRENCY] = ud;
92 }
93}
94
95void Units::readUnitNode(XML::Node node, const std::string &filename)
96{
98 int level = 1;
99 const std::string type = node.getProperty("type", "");
100 ud.conversion = node.getProperty("conversion", 1);
101 ud.mix = node.getProperty("mix", "no") == "yes";
102
103 UnitLevel bu;
104 bu.symbol = node.getProperty("base", "¤");
105 bu.count = 1;
106 bu.round = node.getProperty("round", 2);
107
108 ud.levels.push_back(bu);
109
110 for (auto uLevel : node.children())
111 {
112 if (uLevel.name() == "level")
113 {
114 UnitLevel ul;
115 ul.symbol = uLevel.getProperty("symbol", strprintf("¤%d", level));
116 ul.count = uLevel.getProperty("count", -1);
117 ul.round = uLevel.getProperty("round", bu.round);
118
119 if (ul.count > 0)
120 {
121 ud.levels.push_back(ul);
122 level++;
123 }
124 else
125 {
126 Log::info("Error bad unit count: %d for %s in %s",
127 ul.count, ul.symbol.c_str(), bu.symbol.c_str());
128 }
129 }
130 }
131
132 // Add one more level for saftey
133 UnitLevel &ll = ud.levels.emplace_back();
134 ll.count = INT_MAX;
135 ll.round = 0;
136
137 if (type == "weight")
138 units[UNIT_WEIGHT] = ud;
139 else if (type == "currency")
140 units[UNIT_CURRENCY] = ud;
141 else
142 Log::info("Error unknown unit type: %s in %s", type.c_str(), filename.c_str());
143
144}
145
147{
148}
149
150std::string formatUnit(int value, int type)
151{
152 UnitDescription ud = units[type];
153 UnitLevel ul;
154
155 // Shortcut for 0; do the same for values less than 0 (for now)
156 if (value <= 0)
157 {
158 ul = ud.levels[0];
159 return strprintf("0%s", ul.symbol.c_str());
160 }
161
162 double amount = ud.conversion * value;
163
164 // If only the first level is needed, act like mix if false
165 if (ud.mix && !ud.levels.empty() && ud.levels[1].count < amount)
166 {
167 std::string output;
168 UnitLevel pl = ud.levels[0];
169 ul = ud.levels[1];
170 int levelAmount = (int) amount;
171 int nextAmount;
172
173 levelAmount /= ul.count;
174
175 amount -= levelAmount * ul.count;
176
177 if (amount > 0)
178 {
179 output = strprintf("%.*f%s", pl.round, amount,
180 pl.symbol.c_str());
181 }
182
183 for (unsigned int i = 2; i < ud.levels.size(); i++)
184 {
185 pl = ul;
186 ul = ud.levels[i];
187
188 nextAmount = levelAmount / ul.count;
189 levelAmount %= ul.count;
190
191 if (levelAmount > 0) output = strprintf("%d%s",
192 levelAmount, pl.symbol.c_str()) + output;
193
194 if (!nextAmount)
195 break;
196 levelAmount = nextAmount;
197 }
198
199 return output;
200 }
201
202 for (unsigned int i = 0; i < ud.levels.size(); i++)
203 {
204 ul = ud.levels[i];
205 if (amount < ul.count && ul.count > 0)
206 {
207 ul = ud.levels[i - 1];
208 break;
209 }
210 amount /= ul.count;
211 }
212
213 return strprintf("%.*f%s", ul.round, amount, ul.symbol.c_str());
214}
215
216std::string Units::formatCurrency(int value)
217{
218 return formatUnit(value, UNIT_CURRENCY);
219}
220
221std::string Units::formatWeight(int value)
222{
223 return formatUnit(value, UNIT_WEIGHT);
224}
static std::string formatCurrency(int value)
Formats the given number in the correct currency format.
Definition units.cpp:216
static void init()
Definition units.cpp:53
static void readUnitNode(XML::Node node, const std::string &filename)
Definition units.cpp:95
static std::string formatWeight(int value)
Formats the given number in the correct weight/mass format.
Definition units.cpp:221
static void checkStatus()
Definition units.cpp:146
int getProperty(const char *name, int def) const
Definition xml.h:144
Children children() const
Definition xml.h:97
void info(const char *log_text,...) LOG_PRINTF_ATTR
std::string strprintf(char const *format,...)
A safe version of sprintf that returns a std::string of the result.
std::vector< UnitLevel > levels
Definition units.cpp:39
double conversion
Definition units.cpp:40
int round
Definition units.cpp:35
std::string symbol
Definition units.cpp:33
int count
Definition units.cpp:34
UnitType
Definition units.cpp:44
@ UNIT_CURRENCY
Definition units.cpp:46
@ UNIT_WEIGHT
Definition units.cpp:45
@ UNIT_END
Definition units.cpp:47
std::string formatUnit(int value, int type)
Definition units.cpp:150
UnitDescription units[UNIT_END]
Definition units.cpp:50