forked from raduprv/Eternal-Lands
/
item_info.cpp
285 lines (252 loc) · 8.4 KB
/
item_info.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
/*
Provide item description and emu lookup from a data file.
Using the file from http://el.other-life.com/downloads/item_info.txt
The file should be stored in the datadir or updates directory and is
read when first needed.
Functions provide descriptions and emu for items based on their image
and unique id. If unique id are not enabled (#item_uid) and so only
image id are used then the values may not be unique. The get_item_count()
function allows you to check for uniqueness.
The description, emu and count functions all cached last result to speed
up the look-up, otherwise, the return time is dependant on the position
in the list (but still not that slow).
Author bluap/pjbroad February 2013
*/
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
#include <map>
#include <algorithm>
#include <SDL/SDL_types.h>
#include "client_serv.h"
#include "init.h"
#include "items.h"
#include "io/elpathwrapper.h"
#include "text.h"
#include "url.h"
namespace Item_Info
{
// Class for a single item, holding ids, emu and description
//
class Item
{
public:
Item(const std::string &text);
~Item(void) {}
bool is_valid(void) const { return valid; }
const std::string &get_description(void) const { return description; }
int get_emu(void) const { return emu; }
const bool compare(Uint16 the_item_id, int the_image_id) const;
private:
Uint16 item_id;
int image_id;
int emu;
std::string description;
bool valid;
};
// Construct the item by parsing the line from the item_info.txt file
//
Item::Item(const std::string &text)
: valid(false)
{
std::stringstream ss(text);
std::vector<std::string> fields;
std::string field;
while(std::getline(ss, field, '|'))
fields.push_back(field);
if (fields.size() != 4)
return;
item_id = atoi(fields[0].c_str());
image_id = atoi(fields[1].c_str());
emu = atoi(fields[2].c_str());
description = fields[3];
// thanks http://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring
description.erase(description.begin(), std::find_if(description.begin(), description.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));
description.erase(std::find_if(description.rbegin(), description.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), description.end());
if (description.empty())
return;
valid = true;
}
// Return true of the item matches the ids, allowing for unset unique ids
//
const bool Item::compare(Uint16 the_item_id, int the_image_id) const
{
if ((the_item_id == unset_item_uid) && (the_image_id == image_id))
return true;
if ((the_item_id == item_id) && (the_image_id == image_id))
return true;
return false;
}
// Class to hold the list of items
//
class List
{
public:
List(void) : load_tried(false), shown_help(false), last_item(0) {}
~List(void);
const std::string &get_description(Uint16 item_id, int image_id);
int get_emu(Uint16 item_id, int image_id);
int get_count(Uint16 item_id, int image_id);
bool info_available(void) { if (!load_tried) load(); return !the_list.empty(); }
void help_if_needed(void);
void filter_by_description(Uint8 *storage_items_filter, const ground_item *storage_items, const char *filter_item_text, int no_storage);
private:
Item *get_item(Uint16 item_id, int image_id);
void load(void);
std::vector<Item *> the_list;
static std::string empty_str;
bool load_tried, shown_help;
Item *last_item;
class Count
{
public:
Count(void) : count(-1) {}
bool matches(Uint16 item_id, int image_id) const
{ return ((count >= 0) && (this->item_id == item_id) && (this->image_id == image_id)); }
int get_count(void) const { return count; }
void set(Uint16 item_id, int image_id, int count)
{ this->item_id = item_id; this->image_id = image_id; this->count = count; }
private:
Uint16 item_id; int image_id; int count;
};
Count last_count;
};
std::string List::empty_str;
// Clean up memory on exit
//
List::~List(void)
{
for (size_t i=0; i<the_list.size(); ++i)
delete the_list[i];
the_list.clear();
}
// Find and item by the ids
//
Item *List::get_item(Uint16 item_id, int image_id)
{
info_available();
if (last_item && last_item->compare(item_id, image_id))
return last_item;
for (size_t i=0; i<the_list.size(); ++i)
if (the_list[i]->compare(item_id, image_id))
{
last_item = the_list[i];
return last_item;
}
return 0;
}
// Get the description for the specified ids, or return an empty string
//
const std::string & List::get_description(Uint16 item_id, int image_id)
{
Item *matching_item = get_item(item_id, image_id);
if (matching_item)
return matching_item->get_description();
return empty_str;
}
// Get the emu for the specified ids, or return -1
//
int List::get_emu(Uint16 item_id, int image_id)
{
Item *matching_item = get_item(item_id, image_id);
if (matching_item)
return matching_item->get_emu();
return -1;
}
// Return the number of unique items matching the ids
//
int List::get_count(Uint16 item_id, int image_id)
{
info_available();
if (last_count.matches(item_id, image_id))
return last_count.get_count();
int match_count = 0;
for (size_t i=0; i<the_list.size(); ++i)
if (the_list[i]->compare(item_id, image_id))
match_count++;
last_count.set(item_id, image_id, match_count);
return last_count.get_count();
}
// Match passed string against specified item descriptions and return details for matches
// Element in results array set to zero if their description matches the passed string
//
void List::filter_by_description(Uint8 *storage_items_filter, const ground_item *storage_items, const char *filter_item_text, int no_storage)
{
if (!info_available() || (no_storage<=0) || !storage_items_filter || !storage_items)
return;
std::string needle(filter_item_text);
std::transform(needle.begin(), needle.end(), needle.begin(), tolower);
for (size_t i=0; i<static_cast<size_t>(no_storage); i++)
{
storage_items_filter[i] = 1;
Item *item = get_item(storage_items[i].id, storage_items[i].image_id);
if (item)
{
std::string haystack(item->get_description());
std::transform(haystack.begin(), haystack.end(), haystack.begin(), tolower);
if (haystack.find(needle) != std::string::npos)
storage_items_filter[i] = 0;
}
}
}
// Read lines from the item_info.txt file and create item objects
//
void List::load(void)
{
load_tried = true;
std::ifstream in;
std::string fname = std::string(get_path_updates()) + std::string("item_info.txt");
in.open(fname.c_str());
if (!in)
{
fname = std::string(datadir) + std::string("item_info.txt");
in.clear();
in.open(fname.c_str());
if (!in)
return;
}
std::string line;
while (std::getline(in, line))
{
Item *new_item = new Item(line);
if (new_item->is_valid())
the_list.push_back(new_item);
else
delete new_item;
}
}
// If the item_info file is missing or item_uid not enabled, show one time help
//
void List::help_if_needed(void)
{
if (shown_help)
return;
if (!info_available())
{
std::string url("Download from: http://el.other-life.com/downloads/item_info.txt");
find_all_url(url.c_str(), url.size());
LOG_TO_CONSOLE(c_red1, "Could not load the item information file.");
LOG_TO_CONSOLE(c_red1, url.c_str());
LOG_TO_CONSOLE(c_red1, "Save the file in the data or updates/x_y_z directory then restart.");
}
if (!item_uid_enabled)
LOG_TO_CONSOLE(c_red1, "Use #item_uid (set to 1) to enable unique item information.");
shown_help = true;
}
} // end Item_Info namespace
// Holds all the item information
static Item_Info::List the_list;
// The external interface
extern "C"
{
int show_item_desc_text = 1;
const char *get_item_description(Uint16 item_id, int image_id) { return the_list.get_description(item_id, image_id).c_str(); }
void filter_items_by_description(Uint8 *storage_items_filter, const ground_item *storage_items, const char *filter_item_text, int no_storage)
{ the_list.filter_by_description(storage_items_filter, storage_items, filter_item_text, no_storage); }
int get_item_emu(Uint16 item_id, int image_id) { return the_list.get_emu(item_id, image_id); }
int get_item_count(Uint16 item_id, int image_id) { return the_list.get_count(item_id, image_id); }
int item_info_available(void) { return ((the_list.info_available()) ?1: 0); }
void item_info_help_if_needed(void) { the_list.help_if_needed(); }
}