1 /*
2 * Copyright (C) 2002 The Exult Team
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 #include <cstdio>
24
25 #include "objs.h"
26 #include "game.h"
27 #include "items.h"
28 #include "gamewin.h"
29 #include "actors.h"
30 #include "shapeinf.h"
31 #include "frnameinf.h"
32
33 #ifndef ATTR_PRINTF
34 #ifdef __GNUC__
35 #define ATTR_PRINTF(x,y) __attribute__((format(printf, (x), (y))))
36 #else
37 #define ATTR_PRINTF(x,y)
38 #endif
39 #endif
40
41 using std::string;
42 using std::strchr;
43
44 /*
45 * For objects that can have a quantity, the name is in the format:
46 * %1/%2/%3/%4
47 * Where
48 * %1 : singular prefix (e.g. "a")
49 * %2 : main part of name
50 * %3 : singular suffix
51 * %4 : plural suffix (e.g. "s")
52 */
53
54 /*
55 * Extracts the first, second and third parts of the name string
56 */
get_singular_name(const char * name,string & output_name)57 static void get_singular_name(
58 const char *name, // Raw name string from TEXT.FLX
59 string &output_name // Output string
60 ) {
61 if (*name != '/') { // Output the first part
62 do
63 output_name += *name++;
64 while (*name != '/' && *name != '\0');
65 if (*name == '\0') { // should not happen
66 output_name = "?";
67 return;
68 }
69 // If there is a first part it is followed by a space
70 output_name += ' ';
71 }
72 name++;
73
74 // Output the second part
75 while (*name != '/' && *name != '\0')
76 output_name += *name++;
77 if (*name == '\0') { // should not happen
78 output_name = "?";
79 return;
80 }
81 name++;
82
83 // Output the third part
84 while (*name != '/' && *name != '\0')
85 output_name += *name++;
86 if (*name == '\0') { // should not happen
87 output_name = "?";
88 return;
89 }
90 name++;
91 }
92
93 /*
94 * Extracts the second and fourth parts of the name string
95 */
get_plural_name(const char * name,int quantity,string & output_name)96 static void get_plural_name(
97 const char *name,
98 int quantity,
99 string &output_name
100 ) {
101 char buf[20];
102
103 snprintf(buf, 20, "%d ", quantity); // Output the quantity
104 output_name = buf;
105
106 // Skip the first part
107 while (*name != '/' && *name != '\0')
108 name++;
109 if (*name == '\0') { // should not happen
110 output_name = "?";
111 return;
112 }
113 name++;
114 // Output the second part
115 while (*name != '/' && *name != '\0')
116 output_name += *name++;
117 if (*name == '\0') { // should not happen
118 output_name = "?";
119 return;
120 }
121 name++;
122 // Skip the third part
123 while (*name != '/' && *name != '\0')
124 name++;
125 if (*name == '\0') { // should not happen
126 output_name = "?";
127 return;
128 }
129 name++;
130 while (*name != '\0') // Output the last part
131 output_name += *name++;
132 }
133
134 /*
135 * Returns the string to be displayed when the item is clicked on
136 */
get_name() const137 string Game_object::get_name(
138 ) const {
139 const Shape_info &info = get_info();
140 int qual = info.has_quality() && !info.is_npc() ? get_quality() : -1;
141 const Frame_name_info *nminf = info.get_frame_name(get_framenum(), qual);
142 int shnum = get_shapenum();
143 const char *name;
144 const char *shpname = (shnum >= 0 && shnum < get_num_item_names()) ?
145 get_item_name(shnum) : nullptr;
146 int type = nminf ? nminf->get_type() : -255;
147 int msgid;
148 if (type < 0 && type != -255) // This is a "catch all" default.
149 return ""; // None.
150 else if (type == -255 || (msgid = nminf->get_msgid()) >= get_num_misc_names())
151 name = shpname;
152 else if (!type)
153 name = get_misc_name(msgid);
154 else if (!info.has_quality() && !info.is_body_shape())
155 name = shpname; // Use default name for these.
156 else {
157 int othermsg = nminf->get_othermsg();
158 bool defname = false;
159 string msg;
160 string other;
161 if (type >= 3) {
162 // Special names (in SI, corpse, urn).
163 int npcnum = -1;
164 if (!info.is_body_shape())
165 npcnum = get_quality();
166 else if (qual == 1)
167 npcnum = get_live_npc_num();
168 Actor *npc = gwin->get_npc(npcnum);
169 if (npc && !npc->is_unused() &&
170 (!info.is_body_shape() || npc->get_flag(Obj_flags::met))) {
171 other = npc->get_npc_name_string();
172 if (other.empty()) // No name.
173 defname = true;
174 else
175 msg = get_misc_name(msgid);
176 } else // Default name.
177 defname = true;
178 } else {
179 msg = get_misc_name(msgid);
180 other = (othermsg >= 0 && othermsg < get_num_misc_names()) ?
181 get_misc_name(othermsg) : (shpname ? shpname : "");
182 }
183 if (defname) {
184 if (othermsg >= 0 && othermsg < get_num_misc_names())
185 name = get_misc_name(othermsg);
186 else if (othermsg < 0 && othermsg != -255) // None.
187 return "";
188 else // Use shape's.
189 name = shpname;
190 } else if (type & 1)
191 return other + msg;
192 else
193 return msg + other;
194 }
195 int quantity;
196 string display_name;
197 if (name == nullptr)
198 return "";
199
200 if (ShapeID::get_info(shnum).has_quantity())
201 quantity = quality & 0x7f;
202 else
203 quantity = 1;
204
205 // If there are no slashes then it is simpler
206 if (strchr(name, '/') == nullptr) {
207 if (quantity <= 1)
208 display_name = name;
209 else {
210 char buf[50];
211
212 snprintf(buf, 50, "%d %s", quantity, name);
213 display_name = buf;
214 }
215 } else if (quantity <= 1) // quantity might be zero?
216 get_singular_name(name, display_name);
217 else
218 get_plural_name(name, quantity, display_name);
219 return display_name;
220 }
221