1 | /* |
1 | /* |
2 | * static char *rcsid_c_object_c = |
2 | * static char *rcsid_c_object_c = |
3 | * "$Id: c_object.C,v 1.5 2006/08/20 21:26:03 elmex Exp $"; |
3 | * "$Id: c_object.C,v 1.7 2006/08/27 15:24:22 root Exp $"; |
4 | */ |
4 | */ |
5 | /* |
5 | /* |
6 | CrossFire, A Multiplayer game for X-windows |
6 | CrossFire, A Multiplayer game for X-windows |
7 | |
7 | |
8 | Copyright (C) 2002 Mark Wedel & Crossfire Development Team |
8 | Copyright (C) 2002 Mark Wedel & Crossfire Development Team |
… | |
… | |
83 | **/ |
83 | **/ |
84 | object *find_best_object_match(object *pl, const char *params) |
84 | object *find_best_object_match(object *pl, const char *params) |
85 | { |
85 | { |
86 | return find_best_apply_object_match(pl, params, AP_NULL); |
86 | return find_best_apply_object_match(pl, params, AP_NULL); |
87 | } |
87 | } |
88 | |
|
|
89 | /* |
|
|
90 | * Notes about item creation: |
|
|
91 | * 1) It is similar in syntax to the dm create command. |
|
|
92 | * 2) It requires a player to have a buildfacility below him, a tool in his |
|
|
93 | * possesion, and materials to build with. |
|
|
94 | * 3) The random roll is done in a loop, so if the player tries to make 100, |
|
|
95 | * he makes 100 checks. |
|
|
96 | * 4) Exp is given only on succ. creations, but materials are used regardless. |
|
|
97 | * 5) The properties of the tool are stored in tooltype and weapontype. |
|
|
98 | * 6) The properties of the buildfacilities are stored in tooltype. |
|
|
99 | * 7) For now, all ingredients must be type 73 INORGANIC. |
|
|
100 | * 8) The player can attempt to create any arch, but item_power and value |
|
|
101 | * will prevent most artifacts from being built. |
|
|
102 | * 9) The code allows magic bonuses up to +5. It is not trivial to make a +5 |
|
|
103 | * item. |
|
|
104 | *10) If you ever extend it beyond +5, add more gemtypes. Currently the code |
|
|
105 | * looks for gemcost gems per item, per plus. So a +5 item requires |
|
|
106 | * gemcost pearls,rubies,emeralds,sapphires and diamonds. Not cheap. |
|
|
107 | *11) There are a zillion if statements in this code. Alot of checking takes |
|
|
108 | * place here. All of them are needed. |
|
|
109 | */ |
|
|
110 | |
|
|
111 | int command_build (object *pl, char *params) { |
|
|
112 | return 0; |
|
|
113 | #if 0 |
|
|
114 | object *marked, *facility, *tool, *newobj, *tmp; |
|
|
115 | archetype *at; |
|
|
116 | int skillnr, obpow, number, bonus, mneed, nrof, magic, i, nummade, found; |
|
|
117 | int gemcost; |
|
|
118 | char *bp; |
|
|
119 | materialtype_t *mt; |
|
|
120 | |
|
|
121 | /* NOTE THIS FUNCTION IS CURRENTLY DISABLED */ |
|
|
122 | |
|
|
123 | /* Given this is currently disabled, I'm not going to bother updating |
|
|
124 | * it with the new skill system. IT really needs to get the skill object |
|
|
125 | * pointer in a better fashion than it is currently doing. |
|
|
126 | */ |
|
|
127 | if (!params) { |
|
|
128 | new_draw_info(NDI_UNIQUE, 0, pl, "Usage:build [nr] [+magic] <object>"); |
|
|
129 | return 0; |
|
|
130 | } |
|
|
131 | marked = find_marked_object(pl); |
|
|
132 | if (marked == NULL || !marked->material || marked->materialname == NULL || |
|
|
133 | marked->type != INORGANIC) { |
|
|
134 | new_draw_info(NDI_UNIQUE, 0, pl, "You must mark some ingredients."); |
|
|
135 | return 0; |
|
|
136 | } |
|
|
137 | while (*params==' ') |
|
|
138 | params++; |
|
|
139 | bp = params; |
|
|
140 | nrof = 1; |
|
|
141 | magic = 0; |
|
|
142 | |
|
|
143 | if (sscanf(bp, "%d ", &nrof)) { |
|
|
144 | if ((bp = strchr(params, ' ')) == NULL) { |
|
|
145 | new_draw_info(NDI_UNIQUE, 0, pl, |
|
|
146 | "Usage: build [nr] [+magic] <object>"); |
|
|
147 | return 0; |
|
|
148 | } |
|
|
149 | bp++; |
|
|
150 | } |
|
|
151 | if (sscanf(bp, "+%d ", &magic)) { |
|
|
152 | if ((bp = strchr(bp, ' ')) == NULL) { |
|
|
153 | new_draw_info(NDI_UNIQUE, 0, pl, |
|
|
154 | "Usage: build [nr] [+magic] <object>"); |
|
|
155 | return 0; |
|
|
156 | } |
|
|
157 | bp++; |
|
|
158 | } |
|
|
159 | while (*bp==' ') |
|
|
160 | bp++; |
|
|
161 | at=find_archetype_by_object_name(bp); |
|
|
162 | if (at == NULL) { |
|
|
163 | new_draw_info_format(NDI_UNIQUE, 0, pl, |
|
|
164 | "You don't know how to make a %s.", bp); |
|
|
165 | return 0; |
|
|
166 | } |
|
|
167 | newobj = get_object(); |
|
|
168 | copy_object(&at->clone, newobj); |
|
|
169 | |
|
|
170 | skillnr = -1; |
|
|
171 | |
|
|
172 | if ((IS_ARMOR(newobj) && newobj->material != M_LEATHER) || |
|
|
173 | newobj->type == WEAPON) |
|
|
174 | skillnr = SK_SMITH; |
|
|
175 | |
|
|
176 | if (IS_ARMOR(newobj) && newobj->material == M_LEATHER) |
|
|
177 | skillnr = SK_WOODSMAN; |
|
|
178 | |
|
|
179 | if (newobj->type == BOW || newobj->type == ARROW) |
|
|
180 | skillnr = SK_BOWYER; |
|
|
181 | |
|
|
182 | if (skillnr == -1) { |
|
|
183 | new_draw_info(NDI_UNIQUE, 0, pl, "You don't know how to create that."); |
|
|
184 | return 0; |
|
|
185 | } |
|
|
186 | |
|
|
187 | if (!change_skill(pl, skillnr, 0)) { |
|
|
188 | new_draw_info(NDI_UNIQUE, 0, pl, |
|
|
189 | "You lack the needed skill to make that item."); |
|
|
190 | return 0; |
|
|
191 | } |
|
|
192 | facility = NULL; |
|
|
193 | for (tmp=GET_MAP_OB(pl->map, pl->x, pl->y); tmp; tmp=tmp->above) |
|
|
194 | if (tmp->type == BUILDFAC && tmp->tooltype == newobj->type) |
|
|
195 | facility=tmp; |
|
|
196 | if (facility == NULL) { |
|
|
197 | new_draw_info(NDI_UNIQUE, 0, pl, "You lack a suitable workspace."); |
|
|
198 | return 0; |
|
|
199 | } |
|
|
200 | if (magic && !(IS_ARMOR(newobj) || IS_WEAPON(newobj))) { |
|
|
201 | new_draw_info(NDI_UNIQUE, 0, pl, "A magical bonus is only valid with " |
|
|
202 | "armour and weapons."); |
|
|
203 | return 0; |
|
|
204 | } |
|
|
205 | |
|
|
206 | /* use newobj->weapontype == tool->weapontype for building weapons */ |
|
|
207 | /* use newobj->material == tool->weapontype for building armour */ |
|
|
208 | /* newobj->type == tool->tooltype */ |
|
|
209 | tool = NULL; |
|
|
210 | for (tmp=pl->inv; tmp; tmp=tmp->below) { |
|
|
211 | if (tmp->type != TOOL) |
|
|
212 | continue; |
|
|
213 | if (IS_ARMOR(newobj) && (newobj->material & tmp->weapontype) && |
|
|
214 | newobj->type == tmp->tooltype) { |
|
|
215 | if (tool == NULL || |
|
|
216 | (tool->level + tool->magic) < (tmp->level + tmp->magic)) |
|
|
217 | tool = tmp; |
|
|
218 | } else if (IS_WEAPON(newobj) && (newobj->weapontype&tmp->weapontype) && |
|
|
219 | newobj->type == tmp->tooltype) { |
|
|
220 | if (tool == NULL || |
|
|
221 | (tool->level + tool->magic) < (tmp->level + tmp->magic)) |
|
|
222 | tool = tmp; |
|
|
223 | } |
|
|
224 | /* should split off bows arrows and probably bolts around here */ |
|
|
225 | } |
|
|
226 | if (tool == NULL) { |
|
|
227 | new_draw_info(NDI_UNIQUE, 0, pl, "You lack the required tools."); |
|
|
228 | return 0; |
|
|
229 | } |
|
|
230 | |
|
|
231 | mt = name_to_material(marked->materialname); |
|
|
232 | if (mt == NULL) { |
|
|
233 | new_draw_info(NDI_UNIQUE, 0, pl, "Your raw materials are garbage."); |
|
|
234 | return 0; |
|
|
235 | } |
|
|
236 | if (magic < 0) { |
|
|
237 | new_draw_info(NDI_UNIQUE, 0, pl, "You cannot create cursed objects."); |
|
|
238 | return 0; |
|
|
239 | } |
|
|
240 | if (magic > 0 && SK_level(pl)/20 < magic) { |
|
|
241 | new_draw_info(NDI_UNIQUE, 0, pl, "You are not powerful enough to " |
|
|
242 | "create such a magical item."); |
|
|
243 | return 0; |
|
|
244 | } |
|
|
245 | |
|
|
246 | gemcost = 100; |
|
|
247 | if (newobj->type == ARROW) |
|
|
248 | gemcost = 1; |
|
|
249 | if (magic > 0) { |
|
|
250 | found = 0; |
|
|
251 | for (tmp=GET_MAP_OB(pl->map, pl->x, pl->y); tmp; tmp=tmp->above) |
|
|
252 | if (tmp->type == GEM && !strcmp(tmp->arch->name, "pearl") && |
|
|
253 | tmp->nrof >= gemcost*nrof*mt->value/100) |
|
|
254 | found++; |
|
|
255 | if (magic > 1) |
|
|
256 | for (tmp=GET_MAP_OB(pl->map, pl->x, pl->y); tmp; tmp=tmp->above) |
|
|
257 | if (tmp->type == GEM && !strcmp(tmp->arch->name, "emerald") && |
|
|
258 | tmp->nrof >= gemcost*nrof*mt->value/100) |
|
|
259 | found++; |
|
|
260 | if (magic > 2) |
|
|
261 | for (tmp=GET_MAP_OB(pl->map, pl->x, pl->y); tmp; tmp=tmp->above) |
|
|
262 | if (tmp->type == GEM && !strcmp(tmp->arch->name, "sapphire") && |
|
|
263 | tmp->nrof >= gemcost*nrof*mt->value/100) |
|
|
264 | found++; |
|
|
265 | if (magic > 3) |
|
|
266 | for (tmp=GET_MAP_OB(pl->map, pl->x, pl->y); tmp; tmp=tmp->above) |
|
|
267 | if (tmp->type == GEM && !strcmp(tmp->arch->name, "ruby") && |
|
|
268 | tmp->nrof >= gemcost*nrof*mt->value/100) |
|
|
269 | found++; |
|
|
270 | if (magic > 4) |
|
|
271 | for (tmp=GET_MAP_OB(pl->map, pl->x, pl->y); tmp; tmp=tmp->above) |
|
|
272 | if (tmp->type == GEM && !strcmp(tmp->arch->name, "diamond") && |
|
|
273 | tmp->nrof >= gemcost*nrof*mt->value/100) |
|
|
274 | found++; |
|
|
275 | if (found < magic) { |
|
|
276 | new_draw_info(NDI_UNIQUE, 0, pl, "You did not provide a suitable " |
|
|
277 | "sacrifice of gems on the ground to add this much magic."); |
|
|
278 | return 0; |
|
|
279 | } |
|
|
280 | if (25*pow(3, magic)*mt->value/100 > pl->stats.sp) { |
|
|
281 | new_draw_info(NDI_UNIQUE, 0, pl, "You do not have enough mana " |
|
|
282 | "to create this object."); |
|
|
283 | return 0; |
|
|
284 | } |
|
|
285 | } |
|
|
286 | |
|
|
287 | /* good lord. Now we have a tool, facilites, materials (marked) and an |
|
|
288 | object we want to create. Thats alot of if's */ |
|
|
289 | |
|
|
290 | obpow = (newobj->item_power + newobj->value/1000 + 1)*mt->value/100; |
|
|
291 | mneed = nrof*((newobj->weight * mt->weight)/80); |
|
|
292 | /* cost can be balanced out by cost to disassemble items for materials */ |
|
|
293 | if ((marked->weight * MAX(1, marked->nrof)) < mneed) { |
|
|
294 | new_draw_info_format(NDI_UNIQUE, 0, pl, "You do not have enough %s.", |
|
|
295 | marked->name); |
|
|
296 | return 0; |
|
|
297 | } |
|
|
298 | if (obpow > (tool->level+tool->magic)) { |
|
|
299 | new_draw_info_format(NDI_UNIQUE, 0, pl, "Your %s is not capable of " |
|
|
300 | "crafting such a complex item.", tool->name); |
|
|
301 | return 0; |
|
|
302 | } |
|
|
303 | set_abs_magic(newobj, magic); |
|
|
304 | set_materialname(newobj, 1, mt); |
|
|
305 | for (i=0, nummade=0; i< nrof; i++) { |
|
|
306 | bonus = tool->level+tool->magic - obpow; |
|
|
307 | number = rndm(1, 3*obpow*magic); |
|
|
308 | LOG(llevDebug, "command_build: skill:%d obpow:%d rndm:%d tool:%s " |
|
|
309 | "newobj:%s marked:%s magic:%d\n", SK_level(pl)+bonus, obpow, |
|
|
310 | number, tool->name, newobj->name, marked->name, magic); |
|
|
311 | if (SK_level(pl)+bonus > number) { |
|
|
312 | /* wow, we actually created something */ |
|
|
313 | newobj->x = pl->x; |
|
|
314 | newobj->y = pl->y; |
|
|
315 | newobj->map = pl->map; |
|
|
316 | SET_FLAG(newobj, FLAG_IDENTIFIED); |
|
|
317 | if (i == 0) |
|
|
318 | newobj = insert_ob_in_ob(newobj, pl); |
|
|
319 | else |
|
|
320 | newobj->nrof++; |
|
|
321 | esrv_send_item(pl, newobj); |
|
|
322 | nummade++; |
|
|
323 | } else { |
|
|
324 | free_object(newobj); |
|
|
325 | if (bonus < rndm(1, number-SK_level(pl)+bonus)) { |
|
|
326 | new_draw_info_format(NDI_UNIQUE, 0, pl, |
|
|
327 | "You broke your %s!\n", tool->name); |
|
|
328 | esrv_del_item(pl->contr, tool->count); |
|
|
329 | remove_ob(tool); |
|
|
330 | free_object(tool); |
|
|
331 | break; |
|
|
332 | } |
|
|
333 | } |
|
|
334 | /* take away materials too */ |
|
|
335 | tmp = get_split_ob(marked, MAX(1, mneed/marked->weight)); |
|
|
336 | if (tmp) |
|
|
337 | free_object(tmp); |
|
|
338 | if (marked->nrof < 1) |
|
|
339 | esrv_del_item(pl->contr, marked->count); |
|
|
340 | else |
|
|
341 | esrv_send_item(pl, marked); |
|
|
342 | } |
|
|
343 | if (magic) |
|
|
344 | for (tmp=GET_MAP_OB(pl->map, pl->x, pl->y); tmp; tmp=tmp->above) |
|
|
345 | if (tmp->type == GEM && !strcmp(tmp->arch->name, "pearl") && |
|
|
346 | tmp->nrof >= gemcost*nrof*mt->value/100) |
|
|
347 | tmp->nrof -= gemcost*nrof*mt->value/100; |
|
|
348 | if (magic > 1) |
|
|
349 | for (tmp=GET_MAP_OB(pl->map, pl->x, pl->y); tmp; tmp=tmp->above) |
|
|
350 | if (tmp->type == GEM && !strcmp(tmp->arch->name, "emerald") && |
|
|
351 | tmp->nrof >= gemcost*nrof*mt->value/100) |
|
|
352 | tmp->nrof -= gemcost*nrof*mt->value/100; |
|
|
353 | if (magic > 2) |
|
|
354 | for (tmp=GET_MAP_OB(pl->map, pl->x, pl->y); tmp; tmp=tmp->above) |
|
|
355 | if (tmp->type == GEM && !strcmp(tmp->arch->name, "sapphire") && |
|
|
356 | tmp->nrof >= gemcost*nrof*mt->value/100) |
|
|
357 | tmp->nrof -= gemcost*nrof*mt->value/100; |
|
|
358 | if (magic > 3) |
|
|
359 | for (tmp=GET_MAP_OB(pl->map, pl->x, pl->y); tmp; tmp=tmp->above) |
|
|
360 | if (tmp->type == GEM && !strcmp(tmp->arch->name, "ruby") && |
|
|
361 | tmp->nrof >= gemcost*nrof*mt->value/100) |
|
|
362 | tmp->nrof -= gemcost*nrof*mt->value/100; |
|
|
363 | if (magic > 4) |
|
|
364 | for (tmp=GET_MAP_OB(pl->map, pl->x, pl->y); tmp; tmp=tmp->above) |
|
|
365 | if (tmp->type == GEM && !strcmp(tmp->arch->name, "diamond") && |
|
|
366 | tmp->nrof >= gemcost*nrof*mt->value/100) |
|
|
367 | tmp->nrof -= gemcost*nrof*mt->value/100; |
|
|
368 | if (magic) |
|
|
369 | for (tmp=GET_MAP_OB(pl->map, pl->x, pl->y); tmp; tmp=tmp->above) |
|
|
370 | if (tmp->type == GEM && |
|
|
371 | (!strcmp(tmp->arch->name, "diamond") || |
|
|
372 | !strcmp(tmp->arch->name, "ruby") || |
|
|
373 | !strcmp(tmp->arch->name, "sapphire") || |
|
|
374 | !strcmp(tmp->arch->name, "emerald") || |
|
|
375 | !strcmp(tmp->arch->name, "pearl"))) { |
|
|
376 | if (tmp->nrof == 0) { |
|
|
377 | remove_ob(tmp); |
|
|
378 | free_object(tmp); |
|
|
379 | } |
|
|
380 | if (pl->contr) |
|
|
381 | pl->contr->socket.update_look=1; |
|
|
382 | } |
|
|
383 | pl->stats.sp -= 25*pow(3, magic)*mt->value/100; |
|
|
384 | fix_player(pl); |
|
|
385 | if (nummade > 1) { |
|
|
386 | new_draw_info_format(NDI_UNIQUE, 0, pl, "You have created %d %s.", |
|
|
387 | nummade, query_base_name(newobj, 1)); |
|
|
388 | } else if (nummade == 1) { |
|
|
389 | new_draw_info_format(NDI_UNIQUE, 0, pl, "You have created a %s.", |
|
|
390 | query_base_name(newobj, 0)); |
|
|
391 | } else { |
|
|
392 | new_draw_info_format(NDI_UNIQUE, 0, pl, |
|
|
393 | "You have failed to craft a %s.", query_base_name(newobj, 0)); |
|
|
394 | return 0; |
|
|
395 | } |
|
|
396 | if (skills[skillnr].category != EXP_NONE) |
|
|
397 | add_exp(pl, obpow*nummade); |
|
|
398 | return 1; |
|
|
399 | #endif |
|
|
400 | } |
|
|
401 | |
|
|
402 | |
|
|
403 | |
88 | |
404 | int command_uskill ( object *pl, char *params) { |
89 | int command_uskill ( object *pl, char *params) { |
405 | if (!params) { |
90 | if (!params) { |
406 | new_draw_info(NDI_UNIQUE, 0, pl, "Usage: use_skill <skill name>"); |
91 | new_draw_info(NDI_UNIQUE, 0, pl, "Usage: use_skill <skill name>"); |
407 | return 0; |
92 | return 0; |
… | |
… | |
951 | } |
636 | } |
952 | } |
637 | } |
953 | else |
638 | else |
954 | remove_ob (tmp); |
639 | remove_ob (tmp); |
955 | |
640 | |
956 | /* Lauwenmark: Handle for plugin drop event */ |
641 | if (INVOKE_OBJECT (DROP, tmp, ARG_OBJECT (op))) |
957 | if (execute_event (tmp, EVENT_DROP, op, NULL, NULL, SCRIPT_FIX_ALL) != 0) |
|
|
958 | return; |
642 | return; |
959 | |
643 | |
960 | if (QUERY_FLAG (tmp, FLAG_STARTEQUIP)) |
644 | if (QUERY_FLAG (tmp, FLAG_STARTEQUIP)) |
961 | { |
645 | { |
962 | sprintf (buf, "You drop the %s.", query_name (tmp)); |
646 | sprintf (buf, "You drop the %s.", query_name (tmp)); |
… | |
… | |
1002 | /* Need to update the weight for the player */ |
686 | /* Need to update the weight for the player */ |
1003 | esrv_send_item (op, op); |
687 | esrv_send_item (op, op); |
1004 | } |
688 | } |
1005 | |
689 | |
1006 | for (floor = get_map_ob (op->map, op->x, op->y); floor; floor = floor->above) |
690 | for (floor = get_map_ob (op->map, op->x, op->y); floor; floor = floor->above) |
1007 | if (execute_event (floor, EVENT_DROP_ON, op, tmp, NULL, SCRIPT_FIX_ALL)) |
691 | if (INVOKE_OBJECT (DROP_ON, floor, ARG_OBJECT (tmp), ARG_OBJECT (op))) |
1008 | return; |
692 | return; |
1009 | |
693 | |
1010 | if (floor |
694 | if (floor |
1011 | && floor->type == SHOP_FLOOR |
695 | && floor->type == SHOP_FLOOR |
1012 | && !QUERY_FLAG (tmp, FLAG_UNPAID) |
696 | && !QUERY_FLAG (tmp, FLAG_UNPAID) |