ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/skills.C
(Generate patch)

Comparing deliantra/server/server/skills.C (file contents):
Revision 1.8 by root, Sun Sep 10 15:59:57 2006 UTC vs.
Revision 1.37 by root, Mon Jun 4 13:04:00 2007 UTC

1
2/* 1/*
3 * static char *rcsid_skills_c = 2 * This file is part of Crossfire TRT, the Roguelike Realtime MORPG.
4 * "$Id: skills.C,v 1.8 2006/09/10 15:59:57 root Exp $"; 3 *
5 */ 4 * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Crossfire TRT team
6
7/*
8 CrossFire, A Multiplayer game for X-windows
9
10 Copyright (C) 2003 Mark Wedel & Crossfire Development Team 5 * Copyright (©) 2003,2007 Mark Wedel & Crossfire Development Team
11 Copyright (C) 1992 Frank Tore Johansen 6 * Copyright (©) 1992,2007 Frank Tore Johansen
12 7 *
13 This program is free software; you can redistribute it and/or modify 8 * Crossfire TRT is free software; you can redistribute it and/or modify it
14 it under the terms of the GNU General Public License as published by 9 * under the terms of the GNU General Public License as published by the Free
15 the Free Software Foundation; either version 2 of the License, or 10 * Software Foundation; either version 2 of the License, or (at your option)
16 (at your option) any later version. 11 * any later version.
17 12 *
18 This program is distributed in the hope that it will be useful, 13 * This program is distributed in the hope that it will be useful, but
19 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 GNU General Public License for more details. 16 * for more details.
22 17 *
23 You should have received a copy of the GNU General Public License 18 * You should have received a copy of the GNU General Public License along
24 along with this program; if not, write to the Free Software 19 * with Crossfire TRT; if not, write to the Free Software Foundation, Inc. 51
25 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26 21 *
27 The authors can be reached via e-mail to crossfire-devel@real-time.com 22 * The authors can be reached via e-mail to <crossfire@schmorp.de>
28*/ 23 */
29 24
30#include <global.h> 25#include <global.h>
31#include <object.h> 26#include <object.h>
32#ifndef __CEXTRACT__
33# include <sproto.h> 27#include <sproto.h>
34#endif
35#include <living.h> 28#include <living.h>
36#include <skills.h> 29#include <skills.h>
37#include <spells.h> 30#include <spells.h>
38#include <book.h> 31#include <book.h>
39 32
47 return -1; 40 return -1;
48 41
49 /* Only prohibit stealing if the player does not have a free 42 /* Only prohibit stealing if the player does not have a free
50 * hand available and in fact does have hands. 43 * hand available and in fact does have hands.
51 */ 44 */
52 if (op->type == PLAYER && op->body_used[BODY_ARMS] <= 0 && op->body_info[BODY_ARMS]) 45 if (op->type == PLAYER && op->slot[body_arm].used <= 0 && op->slot[body_arm].info)
53 { 46 {
54 new_draw_info (NDI_UNIQUE, 0, op, "But you have no free hands to steal with!"); 47 new_draw_info (NDI_UNIQUE, 0, op, "But you have no free hands to steal with!");
55 return -1; 48 return -1;
56 } 49 }
57 50
100 * or not. 93 * or not.
101 * op is the target (person being pilfered) 94 * op is the target (person being pilfered)
102 * who is the person doing the stealing. 95 * who is the person doing the stealing.
103 * skill is the skill object (stealing). 96 * skill is the skill object (stealing).
104 */ 97 */
105
106static int 98static int
107attempt_steal (object *op, object *who, object *skill) 99attempt_steal (object *op, object *who, object *skill)
108{ 100{
109 object *success = NULL, *tmp = NULL, *next; 101 object *success = NULL, *tmp = NULL, *next;
110 int roll = 0, chance = 0, stats_value; 102 int roll = 0, chance = 0, stats_value;
128 else /* help npc to detect thief next time by raising its wisdom */ 120 else /* help npc to detect thief next time by raising its wisdom */
129 op->stats.Wis += (op->stats.Int / 5) + 1; 121 op->stats.Wis += (op->stats.Int / 5) + 1;
130 if (op->stats.Wis > MAX_STAT) 122 if (op->stats.Wis > MAX_STAT)
131 op->stats.Wis = MAX_STAT; 123 op->stats.Wis = MAX_STAT;
132 } 124 }
125
133 if (op->type == PLAYER && QUERY_FLAG (op, FLAG_WIZ)) 126 if (op->type == PLAYER && QUERY_FLAG (op, FLAG_WIZ))
134 { 127 {
135 new_draw_info (NDI_UNIQUE, 0, who, "You can't steal from the dungeon master!\n"); 128 new_draw_info (NDI_UNIQUE, 0, who, "You can't steal from the dungeon master!\n");
136 return 0; 129 return 0;
137 } 130 }
138#ifdef PROHIBIT_PLAYERKILL 131
132 // only allow stealing between hostile players (TODO: probably should change)
139 if (op->type == PLAYER && who->type == PLAYER && (who->contr->peaceful || op->contr->peaceful)) 133 if (op->type == PLAYER && who->type == PLAYER && (who->contr->peaceful || op->contr->peaceful))
140 { 134 {
141 new_draw_info (NDI_UNIQUE, 0, who, "You can't steal from other players!\n"); 135 new_draw_info (NDI_UNIQUE, 0, who, "You can't steal from other players!\n");
142 return 0; 136 return 0;
143 } 137 }
144#else
145 if (op->type == PLAYER && who->type == PLAYER && settings.no_player_stealing)
146 {
147 new_draw_info (NDI_UNIQUE, 0, who, "You can't steal from other players!\n");
148 return 0;
149 }
150#endif
151
152 138
153 /* Ok then, go thru their inventory, stealing */ 139 /* Ok then, go thru their inventory, stealing */
154 for (tmp = op->inv; tmp != NULL; tmp = next) 140 for (tmp = op->inv; tmp; tmp = next)
155 { 141 {
156 next = tmp->below; 142 next = tmp->below;
157 143
158 /* you can't steal worn items, starting items, wiz stuff, 144 /* you can't steal worn items, starting items, wiz stuff,
159 * innate abilities, or items w/o a type. Generally 145 * innate abilities, or items w/o a type. Generally
163 * future possible problems. -b.t. 149 * future possible problems. -b.t.
164 * Flesh items generated w/ fix_flesh_item should have FLAG_NO_STEAL 150 * Flesh items generated w/ fix_flesh_item should have FLAG_NO_STEAL
165 * already -b.t. 151 * already -b.t.
166 */ 152 */
167 153
168 if (QUERY_FLAG (tmp, FLAG_WAS_WIZ) || QUERY_FLAG (tmp, FLAG_APPLIED) 154 if (QUERY_FLAG (tmp, FLAG_APPLIED)
169 || !(tmp->type) 155 || !tmp->type
170 || tmp->type == EXPERIENCE || tmp->type == SPELL 156 || tmp->type == SPELL
171 || QUERY_FLAG (tmp, FLAG_STARTEQUIP) || QUERY_FLAG (tmp, FLAG_NO_STEAL) || tmp->invisible) 157 || QUERY_FLAG (tmp, FLAG_STARTEQUIP)
158 || QUERY_FLAG (tmp, FLAG_NO_STEAL)
159 || tmp->invisible)
172 continue; 160 continue;
173 161
174 /* Okay, try stealing this item. Dependent on dexterity of thief, 162 /* Okay, try stealing this item. Dependent on dexterity of thief,
175 * skill level, see the adj_stealroll fctn for more detail. 163 * skill level, see the adj_stealroll fctn for more detail.
176 */ 164 */
179 167
180 if ((chance = adj_stealchance (who, op, (stats_value + skill->level * 10 - op->level * 3))) == -1) 168 if ((chance = adj_stealchance (who, op, (stats_value + skill->level * 10 - op->level * 3))) == -1)
181 return 0; 169 return 0;
182 else if (roll < chance) 170 else if (roll < chance)
183 { 171 {
184 tag_t tmp_count = tmp->count;
185
186 pick_up (who, tmp); 172 pick_up (who, tmp);
187 /* need to see if the player actually stole this item - 173 /* need to see if the player actually stole this item -
188 * if it is in the players inv, assume it is. This prevents 174 * if it is in the players inv, assume it is. This prevents
189 * abuses where the player can not carry the item, so just 175 * abuses where the player can not carry the item, so just
190 * keeps stealing it over and over. 176 * keeps stealing it over and over.
191 */ 177 */
192 if (was_destroyed (tmp, tmp_count) || tmp->env != op) 178 if (tmp->destroyed () || tmp->env != op)
193 { 179 {
194 /* for players, play_sound: steals item */ 180 /* for players, play_sound: steals item */
195 success = tmp; 181 success = tmp;
196 CLEAR_FLAG (tmp, FLAG_INV_LOCKED); 182 CLEAR_FLAG (tmp, FLAG_INV_LOCKED);
197 183
198 /* Don't delete it from target player until we know 184 /* Don't delete it from target player until we know
199 * the thief has picked it up. can't just look at tmp->count, 185 * the thief has picked it up. can't just look at tmp->count,
200 * as it's possible that it got merged when picked up. 186 * as it's possible that it got merged when picked up.
201 */ 187 */
202 if (op->type == PLAYER) 188 if (op->type == PLAYER)
203 esrv_del_item (op->contr, tmp_count); 189 esrv_del_item (op->contr, tmp->count);
204 } 190 }
205 break; 191 break;
206 } 192 }
207 } /* for loop looking for an item */ 193 } /* for loop looking for an item */
208 194
269 /* play_sound("stop! thief!"); kindofthing */ 255 /* play_sound("stop! thief!"); kindofthing */
270 } /* if you weren't 100% successful */ 256 } /* if you weren't 100% successful */
271 return success ? 1 : 0; 257 return success ? 1 : 0;
272} 258}
273 259
274
275int 260int
276steal (object *op, int dir, object *skill) 261steal (object *op, int dir, object *skill)
277{ 262{
278 object *tmp, *next; 263 object *tmp, *next;
279 sint16 x, y; 264 sint16 x, y;
280 mapstruct *m; 265 maptile *m;
281 int mflags; 266 int mflags;
282 267
283 x = op->x + freearr_x[dir]; 268 x = op->x + freearr_x[dir];
284 y = op->y + freearr_y[dir]; 269 y = op->y + freearr_y[dir];
285 270
300 /* If player can't move onto the space, can't steal from it. */ 285 /* If player can't move onto the space, can't steal from it. */
301 if (OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, x, y))) 286 if (OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, x, y)))
302 return 0; 287 return 0;
303 288
304 /* Find the topmost object at this spot */ 289 /* Find the topmost object at this spot */
305 for (tmp = get_map_ob (m, x, y); tmp != NULL && tmp->above != NULL; tmp = tmp->above); 290 for (tmp = GET_MAP_OB (m, x, y); tmp != NULL && tmp->above != NULL; tmp = tmp->above);
306 291
307 /* For all the stacked objects at this point, attempt a steal */ 292 /* For all the stacked objects at this point, attempt a steal */
308 for (; tmp != NULL; tmp = next) 293 for (; tmp != NULL; tmp = next)
309 { 294 {
310 next = tmp->below; 295 next = tmp->below;
326 return 0; 311 return 0;
327 312
328 /* no xp for stealing from pets (of players) */ 313 /* no xp for stealing from pets (of players) */
329 if (QUERY_FLAG (tmp, FLAG_FRIENDLY) && tmp->attack_movement == PETMOVE) 314 if (QUERY_FLAG (tmp, FLAG_FRIENDLY) && tmp->attack_movement == PETMOVE)
330 { 315 {
331 object *owner = get_owner (tmp); 316 object *owner = tmp->owner;
332 317
333 if (owner != NULL && owner->type == PLAYER) 318 if (owner != NULL && owner->type == PLAYER)
334 return 0; 319 return 0;
335 } 320 }
336 321
391 { 376 {
392 new_draw_info (NDI_UNIQUE, 0, pl, "There is no lock there."); 377 new_draw_info (NDI_UNIQUE, 0, pl, "There is no lock there.");
393 return 0; 378 return 0;
394 } 379 }
395 380
396 for (tmp = get_map_ob (pl->map, x, y); tmp; tmp = tmp->above) 381 for (tmp = GET_MAP_OB (pl->map, x, y); tmp; tmp = tmp->above)
397 if (tmp->type == DOOR || tmp->type == LOCKED_DOOR) 382 if (tmp->type == DOOR || tmp->type == LOCKED_DOOR)
398 break; 383 break;
399 384
400 if (!tmp) 385 if (!tmp)
401 { 386 {
423 { 408 {
424 new_draw_info (NDI_UNIQUE, 0, pl, "You fail to pick the lock."); 409 new_draw_info (NDI_UNIQUE, 0, pl, "You fail to pick the lock.");
425 return 0; 410 return 0;
426 } 411 }
427} 412}
428
429 413
430/* HIDE CODE. The user becomes undetectable (not just 'invisible') for 414/* HIDE CODE. The user becomes undetectable (not just 'invisible') for
431 * a short while (success and duration dependant on player SK_level, 415 * a short while (success and duration dependant on player SK_level,
432 * dexterity, charisma, and map difficulty). 416 * dexterity, charisma, and map difficulty).
433 * Players have a good chance of becoming 'unhidden' if they move 417 * Players have a good chance of becoming 'unhidden' if they move
434 * and like invisiblity will be come visible if they attack 418 * and like invisiblity will be come visible if they attack
435 * Implemented by b.t. (thomas@astro.psu.edu) 419 * Implemented by b.t. (thomas@astro.psu.edu)
436 * July 7, 1995 - made hiding possible for monsters. -b.t. 420 * July 7, 1995 - made hiding possible for monsters. -b.t.
437 */ 421 */
438
439static int 422static int
440attempt_hide (object *op, object *skill) 423attempt_hide (object *op, object *skill)
441{ 424{
442 int number, difficulty = op->map->difficulty; 425 int number, difficulty = op->map->difficulty;
443 int terrain = hideability (op); 426 int terrain = hideability (op);
446 return 0; 429 return 0;
447 430
448 /* Hiding success and duration dependant on skill level, 431 /* Hiding success and duration dependant on skill level,
449 * op->stats.Dex, map difficulty and terrain. 432 * op->stats.Dex, map difficulty and terrain.
450 */ 433 */
451
452 number = (die_roll (2, 25, op, PREFER_LOW) - 2) / 2; 434 number = (die_roll (2, 25, op, PREFER_LOW) - 2) / 2;
435
453 if (!stand_near_hostile (op) && (number < (op->stats.Dex + skill->level + terrain - difficulty))) 436 if (!stand_near_hostile (op) && (number < (op->stats.Dex + skill->level + terrain - difficulty)))
454 { 437 {
455 op->invisible += 100; /* set the level of 'hiddeness' */ 438 op->invisible += 100; /* set the level of 'hiddeness' */
439
456 if (op->type == PLAYER) 440 if (op->type == PLAYER)
457 op->contr->tmp_invis = 1; 441 op->contr->tmp_invis = 1;
442
458 op->hide = 1; 443 op->hide = 1;
459 return 1; 444 return 1;
460 } 445 }
446
461 return 0; 447 return 0;
462} 448}
463 449
464/* patched this to take terrain into consideration */ 450/* patched this to take terrain into consideration */
465
466int 451int
467hide (object *op, object *skill) 452hide (object *op, object *skill)
468{ 453{
469
470 /* the preliminaries -- Can we really hide now? */ 454 /* the preliminaries -- Can we really hide now? */
471 /* this keeps monsters from using invisibilty spells and hiding */ 455 /* this keeps monsters from using invisibilty spells and hiding */
472 456
473 if (QUERY_FLAG (op, FLAG_MAKE_INVIS)) 457 if (QUERY_FLAG (op, FLAG_MAKE_INVIS))
474 { 458 {
479 { 463 {
480 new_draw_info (NDI_UNIQUE, 0, op, "Your attempt to hide breaks the invisibility spell!"); 464 new_draw_info (NDI_UNIQUE, 0, op, "Your attempt to hide breaks the invisibility spell!");
481 make_visible (op); 465 make_visible (op);
482 } 466 }
483 467
484 if (op->invisible > (50 * skill->level)) 468 if (op->invisible > 50 * skill->level)
485 { 469 {
486 new_draw_info (NDI_UNIQUE, 0, op, "You are as hidden as you can get."); 470 new_draw_info (NDI_UNIQUE, 0, op, "You are as hidden as you can get.");
487 return 0; 471 return 0;
488 } 472 }
489 473
491 { 475 {
492 new_draw_info (NDI_UNIQUE, 0, op, "You hide in the shadows."); 476 new_draw_info (NDI_UNIQUE, 0, op, "You hide in the shadows.");
493 update_object (op, UP_OBJ_FACE); 477 update_object (op, UP_OBJ_FACE);
494 return calc_skill_exp (op, NULL, skill); 478 return calc_skill_exp (op, NULL, skill);
495 } 479 }
480
496 new_draw_info (NDI_UNIQUE, 0, op, "You fail to conceal yourself."); 481 new_draw_info (NDI_UNIQUE, 0, op, "You fail to conceal yourself.");
497 return 0; 482 return 0;
498} 483}
499
500 484
501/* stop_jump() - End of jump. Clear flags, restore the map, and 485/* stop_jump() - End of jump. Clear flags, restore the map, and
502 * freeze the jumper a while to simulate the exhaustion 486 * freeze the jumper a while to simulate the exhaustion
503 * of jumping. 487 * of jumping.
504 */ 488 */
505static void 489static void
506stop_jump (object *pl, int dist, int spaces) 490stop_jump (object *pl, int dist, int spaces)
507{ 491{
508 fix_player (pl); 492 pl->update_stats ();
509 insert_ob_in_map (pl, pl->map, pl, 0); 493 pl->map->insert (pl, pl->x, pl->y, pl);
510} 494}
511
512 495
513static int 496static int
514attempt_jump (object *pl, int dir, int spaces, object *skill) 497attempt_jump (object *pl, int dir, int spaces, object *skill)
515{ 498{
516 object *tmp; 499 object *tmp;
517 int i, exp = 0, dx = freearr_x[dir], dy = freearr_y[dir], mflags; 500 int i, exp = 0, dx = freearr_x[dir], dy = freearr_y[dir], mflags;
518 sint16 x, y; 501 sint16 x, y;
519 mapstruct *m; 502 maptile *m;
520 503
521 /* Jump loop. Go through spaces opject wants to jump. Halt the 504 /* Jump loop. Go through spaces opject wants to jump. Halt the
522 * jump if a wall or creature is in the way. We set FLAG_FLYING 505 * jump if a wall or creature is in the way. We set FLAG_FLYING
523 * temporarily to allow player to aviod exits/archs that are not 506 * temporarily to allow player to aviod exits/archs that are not
524 * fly_on, fly_off. This will also prevent pickup of objects 507 * fly_on, fly_off. This will also prevent pickup of objects
525 * while jumping over them. 508 * while jumping over them.
526 */ 509 */
527 510
528 remove_ob (pl); 511 pl->remove ();
529 512
530 /* 513 /*
531 * I don't think this is actually needed - all the movement 514 * I don't think this is actually needed - all the movement
532 * code is handled in this function, and I don't see anyplace 515 * code is handled in this function, and I don't see anyplace
533 * that cares about the move_type being flying. 516 * that cares about the move_type being flying.
552 new_draw_info (NDI_UNIQUE, 0, pl, "Your jump is blocked."); 535 new_draw_info (NDI_UNIQUE, 0, pl, "Your jump is blocked.");
553 stop_jump (pl, i, spaces); 536 stop_jump (pl, i, spaces);
554 return 0; 537 return 0;
555 } 538 }
556 539
557 for (tmp = get_map_ob (m, x, y); tmp; tmp = tmp->above) 540 for (tmp = GET_MAP_OB (m, x, y); tmp; tmp = tmp->above)
558 { 541 {
559 /* Jump into creature */ 542 /* Jump into creature */
560 if (QUERY_FLAG (tmp, FLAG_MONSTER) || (tmp->type == PLAYER && (!QUERY_FLAG (tmp, FLAG_WIZ) || !tmp->contr->hidden))) 543 if (QUERY_FLAG (tmp, FLAG_MONSTER) || (tmp->type == PLAYER && (!QUERY_FLAG (tmp, FLAG_WIZ) || !tmp->contr->hidden)))
561 { 544 {
562 new_draw_info_format (NDI_UNIQUE, 0, pl, "You jump into %s%s.", tmp->type == PLAYER ? "" : "the ", &tmp->name); 545 new_draw_info_format (NDI_UNIQUE, 0, pl, "You jump into %s%s.", tmp->type == PLAYER ? "" : "the ", &tmp->name);
647 esrv_update_item (UPD_FLAGS, pl, tmp); 630 esrv_update_item (UPD_FLAGS, pl, tmp);
648 success += calc_skill_exp (pl, tmp, skill); 631 success += calc_skill_exp (pl, tmp, skill);
649 } 632 }
650 633
651 /* Check ground, too, but only objects the player could pick up */ 634 /* Check ground, too, but only objects the player could pick up */
652 for (tmp = get_map_ob (pl->map, pl->x, pl->y); tmp; tmp = tmp->above) 635 for (tmp = GET_MAP_OB (pl->map, pl->x, pl->y); tmp; tmp = tmp->above)
653 if (can_pick (pl, tmp) && 636 if (can_pick (pl, tmp) &&
654 !QUERY_FLAG (tmp, FLAG_IDENTIFIED) && 637 !QUERY_FLAG (tmp, FLAG_IDENTIFIED) &&
655 !QUERY_FLAG (tmp, FLAG_KNOWN_CURSED) 638 !QUERY_FLAG (tmp, FLAG_KNOWN_CURSED)
656 && (QUERY_FLAG (tmp, FLAG_CURSED) || QUERY_FLAG (tmp, FLAG_DAMNED)) && tmp->item_power < skill->level) 639 && (QUERY_FLAG (tmp, FLAG_CURSED) || QUERY_FLAG (tmp, FLAG_DAMNED)) && tmp->item_power < skill->level)
657 { 640 {
678 esrv_update_item (UPD_FLAGS, pl, tmp); 661 esrv_update_item (UPD_FLAGS, pl, tmp);
679 success += calc_skill_exp (pl, tmp, skill); 662 success += calc_skill_exp (pl, tmp, skill);
680 } 663 }
681 664
682 /* Check ground, too, but like above, only if the object can be picked up */ 665 /* Check ground, too, but like above, only if the object can be picked up */
683 for (tmp = get_map_ob (pl->map, pl->x, pl->y); tmp; tmp = tmp->above) 666 for (tmp = GET_MAP_OB (pl->map, pl->x, pl->y); tmp; tmp = tmp->above)
684 if (can_pick (pl, tmp) && 667 if (can_pick (pl, tmp) &&
685 !QUERY_FLAG (tmp, FLAG_IDENTIFIED) && !QUERY_FLAG (tmp, FLAG_KNOWN_MAGICAL) && (is_magical (tmp)) && tmp->item_power < skill->level) 668 !QUERY_FLAG (tmp, FLAG_IDENTIFIED) && !QUERY_FLAG (tmp, FLAG_KNOWN_MAGICAL) && (is_magical (tmp)) && tmp->item_power < skill->level)
686 { 669 {
687 SET_FLAG (tmp, FLAG_KNOWN_MAGICAL); 670 SET_FLAG (tmp, FLAG_KNOWN_MAGICAL);
688 esrv_update_item (UPD_FLAGS, pl, tmp); 671 esrv_update_item (UPD_FLAGS, pl, tmp);
743 726
744 for (tmp = pl->inv; tmp; tmp = tmp->below) 727 for (tmp = pl->inv; tmp; tmp = tmp->below)
745 success += do_skill_ident2 (tmp, pl, obj_class, skill); 728 success += do_skill_ident2 (tmp, pl, obj_class, skill);
746 /* check the ground */ 729 /* check the ground */
747 730
748 for (tmp = get_map_ob (pl->map, pl->x, pl->y); tmp; tmp = tmp->above) 731 for (tmp = GET_MAP_OB (pl->map, pl->x, pl->y); tmp; tmp = tmp->above)
749 success += do_skill_ident2 (tmp, pl, obj_class, skill); 732 success += do_skill_ident2 (tmp, pl, obj_class, skill);
750 733
751 return success; 734 return success;
752} 735}
753 736
817 new_draw_info (NDI_UNIQUE, 0, pl, "...and learn nothing more."); 800 new_draw_info (NDI_UNIQUE, 0, pl, "...and learn nothing more.");
818 } 801 }
819 return success; 802 return success;
820} 803}
821 804
822
823/* players using this skill can 'charm' a monster -- 805/* players using this skill can 'charm' a monster --
824 * into working for them. It can only be used on 806 * into working for them. It can only be used on
825 * non-special (see below) 'neutral' creatures. 807 * non-special (see below) 'neutral' creatures.
826 * -b.t. (thomas@astro.psu.edu) 808 * -b.t. (thomas@astro.psu.edu)
827 */ 809 */
828
829int 810int
830use_oratory (object *pl, int dir, object *skill) 811use_oratory (object *pl, int dir, object *skill)
831{ 812{
832 sint16 x = pl->x + freearr_x[dir], y = pl->y + freearr_y[dir];
833 int mflags, chance;
834 object *tmp;
835 mapstruct *m;
836
837 if (pl->type != PLAYER) 813 if (pl->type != PLAYER)
838 return 0; /* only players use this skill */ 814 return 0; /* only players use this skill */
815
816 sint16 x = pl->x + freearr_x[dir],
817 y = pl->y + freearr_y[dir];
839 m = pl->map; 818 maptile *m = pl->map;
819
840 mflags = get_map_flags (m, &m, x, y, &x, &y); 820 int mflags = get_map_flags (m, &m, x, y, &x, &y);
841 if (mflags & P_OUT_OF_MAP) 821 if (mflags & P_OUT_OF_MAP)
842 return 0; 822 return 0;
843 823
844 /* Save some processing - we have the flag already anyways 824 /* Save some processing - we have the flag already anyways
845 */ 825 */
847 { 827 {
848 new_draw_info (NDI_UNIQUE, 0, pl, "There is nothing to orate to."); 828 new_draw_info (NDI_UNIQUE, 0, pl, "There is nothing to orate to.");
849 return 0; 829 return 0;
850 } 830 }
851 831
832 object *tmp;
852 for (tmp = get_map_ob (m, x, y); tmp; tmp = tmp->above) 833 for (tmp = GET_MAP_OB (m, x, y); tmp; tmp = tmp->above)
853 { 834 {
854 /* can't persuade players - return because there is nothing else 835 /* can't persuade players - return because there is nothing else
855 * on that space to charm. Same for multi space monsters and 836 * on that space to charm. Same for multi space monsters and
856 * special monsters - we don't allow them to be charmed, and there 837 * special monsters - we don't allow them to be charmed, and there
857 * is no reason to do further processing since they should be the 838 * is no reason to do further processing since they should be the
858 * only monster on the space. 839 * only monster on the space.
859 */ 840 */
860 if (tmp->type == PLAYER) 841 if (tmp->type == PLAYER
861 return 0; 842 || tmp->more || tmp->head_ () != tmp
862 if (tmp->more || tmp->head) 843 || tmp->msg)
863 return 0;
864 if (tmp->msg)
865 return 0; 844 return 0;
866 845
867 if (QUERY_FLAG (tmp, FLAG_MONSTER)) 846 if (QUERY_FLAG (tmp, FLAG_MONSTER))
868 break; 847 break;
869 } 848 }
884 new_draw_info_format (NDI_UNIQUE, 0, pl, "Too bad the %s isn't listening!\n", query_name (tmp)); 863 new_draw_info_format (NDI_UNIQUE, 0, pl, "Too bad the %s isn't listening!\n", query_name (tmp));
885 return 0; 864 return 0;
886 } 865 }
887 866
888 /* it's already allied! */ 867 /* it's already allied! */
889 if (QUERY_FLAG (tmp, FLAG_FRIENDLY) && (tmp->attack_movement == PETMOVE)) 868 if (QUERY_FLAG (tmp, FLAG_FRIENDLY) && tmp->attack_movement == PETMOVE)
890 { 869 {
891 if (get_owner (tmp) == pl) 870 if (tmp->owner == pl)
892 { 871 {
893 new_draw_info (NDI_UNIQUE, 0, pl, "Your follower loves your speech.\n"); 872 new_draw_info (NDI_UNIQUE, 0, pl, "Your follower loves your speech.\n");
894 return 0; 873 return 0;
895 } 874 }
896 else if (skill->level > tmp->level) 875 else if (skill->level > tmp->level)
897 { 876 {
898 /* you steal the follower. Perhaps we should really look at the 877 /* you steal the follower. Perhaps we should really look at the
899 * level of the owner above? 878 * level of the owner above?
900 */ 879 */
901 set_owner (tmp, pl); 880 tmp->set_owner (pl);
881 tmp->skill = skill->skill;
882
902 new_draw_info_format (NDI_UNIQUE, 0, pl, "You convince the %s to follow you instead!\n", query_name (tmp)); 883 new_draw_info_format (NDI_UNIQUE, 0, pl, "You convince the %s to follow you instead!\n", query_name (tmp));
903 /* Abuse fix - don't give exp since this can otherwise 884 /* Abuse fix - don't give exp since this can otherwise
904 * be used by a couple players to gets lots of exp. 885 * be used by a couple players to gets lots of exp.
905 */ 886 */
906 return 0; 887 return 0;
910 /* In this case, you can't steal it from the other player */ 891 /* In this case, you can't steal it from the other player */
911 return 0; 892 return 0;
912 } 893 }
913 } /* Creature was already a pet of someone */ 894 } /* Creature was already a pet of someone */
914 895
915 chance = skill->level * 2 + (pl->stats.Cha - 2 * tmp->stats.Int) / 2; 896 int level = skill->level + (pl->stats.Cha - tmp->stats.Int) / 2;
916 897
917 /* Ok, got a 'sucker' lets try to make them a follower */ 898 /* Ok, got a 'sucker' lets try to make them a follower */
918 if (chance > 0 && tmp->level < (random_roll (0, chance - 1, pl, PREFER_HIGH) - 1)) 899 if (level > 0 && tmp->level < (random_roll (0, level - 1, pl, PREFER_HIGH) - 1))
919 { 900 {
920 new_draw_info_format (NDI_UNIQUE, 0, pl, "You convince the %s to become your follower.\n", query_name (tmp)); 901 new_draw_info_format (NDI_UNIQUE, 0, pl, "You convince the %s to become your follower.\n", query_name (tmp));
921 902
922 set_owner (tmp, pl); 903 tmp->set_owner (pl);
904 tmp->skill = skill->skill;
923 tmp->stats.exp = 0; 905 tmp->stats.exp = 0;
924 add_friendly_object (tmp); 906 add_friendly_object (tmp);
925 SET_FLAG (tmp, FLAG_FRIENDLY);
926 tmp->attack_movement = PETMOVE; 907 tmp->attack_movement = PETMOVE;
927 return calc_skill_exp (pl, tmp, skill); 908 return calc_skill_exp (pl, tmp, skill);
928 } 909 }
929 /* Charm failed. Creature may be angry now */ 910 /* Charm failed. Creature may be angry now */
930 else if ((skill->level + ((pl->stats.Cha - 10) / 2)) < random_roll (1, 2 * tmp->level, pl, PREFER_LOW)) 911 else if ((skill->level + ((pl->stats.Cha - 10) / 2)) < random_roll (1, 2 * tmp->level, pl, PREFER_LOW))
934 { 915 {
935 CLEAR_FLAG (tmp, FLAG_FRIENDLY); 916 CLEAR_FLAG (tmp, FLAG_FRIENDLY);
936 remove_friendly_object (tmp); 917 remove_friendly_object (tmp);
937 tmp->attack_movement = 0; /* needed? */ 918 tmp->attack_movement = 0; /* needed? */
938 } 919 }
920
939 CLEAR_FLAG (tmp, FLAG_UNAGGRESSIVE); 921 CLEAR_FLAG (tmp, FLAG_UNAGGRESSIVE);
940 } 922 }
923
941 return 0; /* Fall through - if we get here, we didn't charm anything */ 924 return 0; /* Fall through - if we get here, we didn't charm anything */
942} 925}
943 926
944/* Singing() -this skill allows the player to pacify nearby creatures. 927/* Singing() -this skill allows the player to pacify nearby creatures.
945 * There are few limitations on who/what kind of 928 * There are few limitations on who/what kind of
948 * successfully pacified the creature gets Int=1. Thus, a player 931 * successfully pacified the creature gets Int=1. Thus, a player
949 * may only pacify a creature once. 932 * may only pacify a creature once.
950 * BTW, I appologize for the naming of the skill, I couldnt think 933 * BTW, I appologize for the naming of the skill, I couldnt think
951 * of anything better! -b.t. 934 * of anything better! -b.t.
952 */ 935 */
953
954int 936int
955singing (object *pl, int dir, object *skill) 937singing (object *pl, int dir, object *skill)
956{ 938{
957 int i, exp = 0, chance, mflags; 939 int i, exp = 0;
958 object *tmp; 940 object *tmp;
959 mapstruct *m; 941 maptile *m;
960 sint16 x, y; 942 sint16 x, y;
961 943
962 if (pl->type != PLAYER) 944 if (pl->type != PLAYER)
963 return 0; /* only players use this skill */ 945 return 0; /* only players use this skill */
964 946
967 { 949 {
968 x = pl->x + freearr_x[i]; 950 x = pl->x + freearr_x[i];
969 y = pl->y + freearr_y[i]; 951 y = pl->y + freearr_y[i];
970 m = pl->map; 952 m = pl->map;
971 953
972 mflags = get_map_flags (m, &m, x, y, &x, &y); 954 int mflags = get_map_flags (m, &m, x, y, &x, &y);
973 if (mflags & P_OUT_OF_MAP) 955 if (mflags & P_OUT_OF_MAP)
974 continue; 956 continue;
975 if (!(mflags & P_IS_ALIVE)) 957 if (!(mflags & P_IS_ALIVE))
976 continue; 958 continue;
977 959
978 for (tmp = get_map_ob (m, x, y); tmp; tmp = tmp->above) 960 for (tmp = GET_MAP_OB (m, x, y); tmp; tmp = tmp->above)
979 { 961 {
980 if (QUERY_FLAG (tmp, FLAG_MONSTER)) 962 if (QUERY_FLAG (tmp, FLAG_MONSTER))
981 break; 963 break;
982 /* can't affect players */ 964 /* can't affect players */
983 if (tmp->type == PLAYER) 965 if (tmp->type == PLAYER)
996 978
997 /* stealing isn't really related (although, maybe it should 979 /* stealing isn't really related (although, maybe it should
998 * be). This is mainly to prevent singing to the same monster 980 * be). This is mainly to prevent singing to the same monster
999 * over and over again and getting exp for it. 981 * over and over again and getting exp for it.
1000 */ 982 */
1001 chance = skill->level * 2 + (pl->stats.Cha - 5 - tmp->stats.Int) / 2; 983 int level = skill->level + (pl->stats.Cha - 5 - tmp->stats.Int) / 2;
984
1002 if (chance && tmp->level * 2 < random_roll (0, chance - 1, pl, PREFER_HIGH)) 985 if (level && tmp->level < random_roll (0, level - 1, pl, PREFER_HIGH))
1003 { 986 {
1004 SET_FLAG (tmp, FLAG_UNAGGRESSIVE); 987 SET_FLAG (tmp, FLAG_UNAGGRESSIVE);
1005 new_draw_info_format (NDI_UNIQUE, 0, pl, "You calm down the %s\n", query_name (tmp)); 988 new_draw_info_format (NDI_UNIQUE, 0, pl, "You calm down the %s\n", query_name (tmp));
1006 /* Give exp only if they are not aware */ 989 /* Give exp only if they are not aware */
990
1007 if (!QUERY_FLAG (tmp, FLAG_NO_STEAL)) 991 if (!QUERY_FLAG (tmp, FLAG_NO_STEAL))
1008 exp += calc_skill_exp (pl, tmp, skill); 992 exp += calc_skill_exp (pl, tmp, skill);
993
1009 SET_FLAG (tmp, FLAG_NO_STEAL); 994 SET_FLAG (tmp, FLAG_NO_STEAL);
1010 } 995 }
1011 else 996 else
1012 { 997 {
1013 new_draw_info_format (NDI_UNIQUE, 0, pl, "Too bad the %s isn't listening!\n", query_name (tmp)); 998 new_draw_info_format (NDI_UNIQUE, 0, pl, "Too bad the %s isn't listening!\n", query_name (tmp));
1026find_traps (object *pl, object *skill) 1011find_traps (object *pl, object *skill)
1027{ 1012{
1028 object *tmp, *tmp2; 1013 object *tmp, *tmp2;
1029 int i, expsum = 0, mflags; 1014 int i, expsum = 0, mflags;
1030 sint16 x, y; 1015 sint16 x, y;
1031 mapstruct *m; 1016 maptile *m;
1032 1017
1033 /* First we search all around us for runes and traps, which are 1018 /* First we search all around us for runes and traps, which are
1034 * all type RUNE 1019 * all type RUNE
1035 */ 1020 */
1036 1021
1043 mflags = get_map_flags (m, &m, x, y, &x, &y); 1028 mflags = get_map_flags (m, &m, x, y, &x, &y);
1044 if (mflags & P_OUT_OF_MAP) 1029 if (mflags & P_OUT_OF_MAP)
1045 continue; 1030 continue;
1046 1031
1047 /* Check everything in the square for trapness */ 1032 /* Check everything in the square for trapness */
1048 for (tmp = get_map_ob (m, x, y); tmp != NULL; tmp = tmp->above) 1033 for (tmp = GET_MAP_OB (m, x, y); tmp != NULL; tmp = tmp->above)
1049 { 1034 {
1050 1035
1051 /* And now we'd better do an inventory traversal of each 1036 /* And now we'd better do an inventory traversal of each
1052 * of these objects' inventory 1037 * of these objects' inventory
1053 * We can narrow this down a bit - no reason to search through 1038 * We can narrow this down a bit - no reason to search through
1092int 1077int
1093remove_trap (object *op, int dir, object *skill) 1078remove_trap (object *op, int dir, object *skill)
1094{ 1079{
1095 object *tmp, *tmp2; 1080 object *tmp, *tmp2;
1096 int i, success = 0, mflags; 1081 int i, success = 0, mflags;
1097 mapstruct *m; 1082 maptile *m;
1098 sint16 x, y; 1083 sint16 x, y;
1099 1084
1100 for (i = 0; i < 9; i++) 1085 for (i = 0; i < 9; i++)
1101 { 1086 {
1102 x = op->x + freearr_x[i]; 1087 x = op->x + freearr_x[i];
1106 mflags = get_map_flags (m, &m, x, y, &x, &y); 1091 mflags = get_map_flags (m, &m, x, y, &x, &y);
1107 if (mflags & P_OUT_OF_MAP) 1092 if (mflags & P_OUT_OF_MAP)
1108 continue; 1093 continue;
1109 1094
1110 /* Check everything in the square for trapness */ 1095 /* Check everything in the square for trapness */
1111 for (tmp = get_map_ob (m, x, y); tmp != NULL; tmp = tmp->above) 1096 for (tmp = GET_MAP_OB (m, x, y); tmp != NULL; tmp = tmp->above)
1112 { 1097 {
1113 /* And now we'd better do an inventory traversal of each 1098 /* And now we'd better do an inventory traversal of each
1114 * of these objects inventory. Like above, only 1099 * of these objects inventory. Like above, only
1115 * do this for interesting objects. 1100 * do this for interesting objects.
1116 */ 1101 */
1210 return; 1195 return;
1211 } 1196 }
1212 else 1197 else
1213 { 1198 {
1214 for (tmp = pl->inv; tmp; tmp = tmp->below) 1199 for (tmp = pl->inv; tmp; tmp = tmp->below)
1215 if (((tmp->type == ARMOUR && skill->level < 12) 1200 if (((tmp->type == ARMOUR && skill->level < 12)
1216 || (tmp->type == HELMET && skill->level < 10) 1201 || (tmp->type == HELMET && skill->level < 10)
1217 || (tmp->type == SHIELD && skill->level < 6) 1202 || (tmp->type == SHIELD && skill->level < 6)
1218 || (tmp->type == BOOTS && skill->level < 4) || (tmp->type == GLOVES && skill->level < 2)) && QUERY_FLAG (tmp, FLAG_APPLIED)) 1203 || (tmp->type == BOOTS && skill->level < 4)
1204 || (tmp->type == GLOVES && skill->level < 2))
1205 && QUERY_FLAG (tmp, FLAG_APPLIED))
1219 { 1206 {
1220 new_draw_info (NDI_UNIQUE, 0, pl, "You can't concentrate while wearing so much armour!\n"); 1207 new_draw_info (NDI_UNIQUE, 0, pl, "You can't concentrate while wearing so much armour!\n");
1221 return; 1208 return;
1222 } 1209 }
1223 } 1210 }
1245} 1232}
1246 1233
1247/* write_note() - this routine allows players to inscribe messages in 1234/* write_note() - this routine allows players to inscribe messages in
1248 * ordinary 'books' (anything that is type BOOK). b.t. 1235 * ordinary 'books' (anything that is type BOOK). b.t.
1249 */ 1236 */
1250
1251static int 1237static int
1252write_note (object *pl, object *item, const char *msg, object *skill) 1238write_note (object *pl, object *item, const char *msg, object *skill)
1253{ 1239{
1254 char buf[1024]; 1240 char buf[1024];
1255 object *newBook = NULL; 1241 object *newBook = NULL;
1262 { 1248 {
1263 new_draw_info (NDI_UNIQUE, 0, pl, "No message to write!"); 1249 new_draw_info (NDI_UNIQUE, 0, pl, "No message to write!");
1264 new_draw_info_format (NDI_UNIQUE, 0, pl, "Usage: use_skill %s <message>", &skill->skill); 1250 new_draw_info_format (NDI_UNIQUE, 0, pl, "Usage: use_skill %s <message>", &skill->skill);
1265 return 0; 1251 return 0;
1266 } 1252 }
1253
1267 if (strcasestr_local (msg, "endmsg")) 1254 if (strcasestr_local (msg, "endmsg"))
1268 { 1255 {
1269 new_draw_info (NDI_UNIQUE, 0, pl, "Trying to cheat now are we?"); 1256 new_draw_info (NDI_UNIQUE, 0, pl, "Trying to cheat now are we?");
1270 return 0; 1257 return 0;
1271 } 1258 }
1281 1268
1282 strcat (buf, msg); 1269 strcat (buf, msg);
1283 strcat (buf, "\n"); /* new msg needs a LF */ 1270 strcat (buf, "\n"); /* new msg needs a LF */
1284 if (item->nrof > 1) 1271 if (item->nrof > 1)
1285 { 1272 {
1286 newBook = get_object (); 1273 newBook = item->clone ();
1287 copy_object (item, newBook);
1288 decrease_ob (item); 1274 decrease_ob (item);
1289 esrv_send_item (pl, item); 1275 esrv_send_item (pl, item);
1290 newBook->nrof = 1; 1276 newBook->nrof = 1;
1291 newBook->msg = buf; 1277 newBook->msg = buf;
1292 newBook = insert_ob_in_ob (newBook, pl); 1278 newBook = insert_ob_in_ob (newBook, pl);
1298 /* This shouldn't be necessary - the object hasn't changed in any 1284 /* This shouldn't be necessary - the object hasn't changed in any
1299 * visible way 1285 * visible way
1300 */ 1286 */
1301 /* esrv_send_item(pl, item); */ 1287 /* esrv_send_item(pl, item); */
1302 } 1288 }
1289
1303 new_draw_info_format (NDI_UNIQUE, 0, pl, "You write in the %s.", query_short_name (item)); 1290 new_draw_info_format (NDI_UNIQUE, 0, pl, "You write in the %s.", query_short_name (item));
1304 return strlen (msg); 1291 return strlen (msg);
1305 } 1292 }
1306 else 1293 else
1307 new_draw_info_format (NDI_UNIQUE, 0, pl, "Your message won't fit in the %s!", query_short_name (item)); 1294 new_draw_info_format (NDI_UNIQUE, 0, pl, "Your message won't fit in the %s!", query_short_name (item));
1327 new_draw_info (NDI_UNIQUE, 0, pl, "A spell can only be inscribed into a scroll!"); 1314 new_draw_info (NDI_UNIQUE, 0, pl, "A spell can only be inscribed into a scroll!");
1328 return 0; 1315 return 0;
1329 } 1316 }
1330 1317
1331 /* Check if we are ready to attempt inscription */ 1318 /* Check if we are ready to attempt inscription */
1332 chosen_spell = pl->contr->ranges[range_magic]; 1319 chosen_spell = pl->contr->ranged_ob;
1333 if (!chosen_spell) 1320 if (!chosen_spell || chosen_spell->type != SPELL)
1334 { 1321 {
1335 new_draw_info (NDI_UNIQUE, 0, pl, "You need a spell readied in order to inscribe!"); 1322 new_draw_info (NDI_UNIQUE, 0, pl, "You need a spell readied in order to inscribe!");
1336 return 0; 1323 return 0;
1337 } 1324 }
1325
1338 if (SP_level_spellpoint_cost (pl, chosen_spell, SPELL_GRACE) > pl->stats.grace) 1326 if (SP_level_spellpoint_cost (pl, chosen_spell, SPELL_GRACE) > pl->stats.grace)
1339 { 1327 {
1340 new_draw_info_format (NDI_UNIQUE, 0, pl, "You don't have enough grace to write a scroll of %s.", &chosen_spell->name); 1328 new_draw_info_format (NDI_UNIQUE, 0, pl, "You don't have enough grace to write a scroll of %s.", &chosen_spell->name);
1341 return 0; 1329 return 0;
1342 } 1330 }
1331
1343 if (SP_level_spellpoint_cost (pl, chosen_spell, SPELL_MANA) > pl->stats.sp) 1332 if (SP_level_spellpoint_cost (pl, chosen_spell, SPELL_MANA) > pl->stats.sp)
1344 { 1333 {
1345 new_draw_info_format (NDI_UNIQUE, 0, pl, "You don't have enough mana to write a scroll of %s.", &chosen_spell->name); 1334 new_draw_info_format (NDI_UNIQUE, 0, pl, "You don't have enough mana to write a scroll of %s.", &chosen_spell->name);
1346 return 0; 1335 return 0;
1347 } 1336 }
1367 1356
1368 if (random_roll (0, chosen_spell->level * 4 - 1, pl, PREFER_LOW) < skill->level) 1357 if (random_roll (0, chosen_spell->level * 4 - 1, pl, PREFER_LOW) < skill->level)
1369 { 1358 {
1370 if (scroll->nrof > 1) 1359 if (scroll->nrof > 1)
1371 { 1360 {
1372 newscroll = get_object (); 1361 newscroll = scroll->clone ();
1373 copy_object (scroll, newscroll);
1374 decrease_ob (scroll); 1362 decrease_ob (scroll);
1375 newscroll->nrof = 1; 1363 newscroll->nrof = 1;
1376 } 1364 }
1377 else 1365 else
1378 {
1379 newscroll = scroll; 1366 newscroll = scroll;
1380 }
1381 1367
1382 if (!confused) 1368 if (!confused)
1383 { 1369 {
1384 newscroll->level = MAX (skill->level, chosen_spell->level); 1370 newscroll->level = MAX (skill->level, chosen_spell->level);
1385 new_draw_info (NDI_UNIQUE, 0, pl, "You succeed in writing a new scroll."); 1371 new_draw_info (NDI_UNIQUE, 0, pl, "You succeed in writing a new scroll.");
1393 newscroll->level = MAX (skill->level, chosen_spell->level); 1379 newscroll->level = MAX (skill->level, chosen_spell->level);
1394 new_draw_info (NDI_UNIQUE, 0, pl, "In your confused state, you write down some odd spell."); 1380 new_draw_info (NDI_UNIQUE, 0, pl, "In your confused state, you write down some odd spell.");
1395 } 1381 }
1396 1382
1397 if (newscroll->inv) 1383 if (newscroll->inv)
1398 { 1384 newscroll->inv->destroy ();
1399 object *ninv;
1400 1385
1401 ninv = newscroll->inv; 1386 tmp = chosen_spell->clone ();
1402 remove_ob (ninv);
1403 free_object (ninv);
1404 }
1405 tmp = get_object ();
1406 copy_object (chosen_spell, tmp);
1407 insert_ob_in_ob (tmp, newscroll); 1387 insert_ob_in_ob (tmp, newscroll);
1408 1388
1409 /* Same code as from treasure.c - so they can better merge. 1389 /* Same code as from treasure.c - so they can better merge.
1410 * if players want to sell them, so be it. 1390 * if players want to sell them, so be it.
1411 */ 1391 */
1412 newscroll->value = newscroll->arch->clone.value * newscroll->inv->value * (newscroll->level + 50) / (newscroll->inv->level + 50); 1392 newscroll->value = newscroll->arch->value * newscroll->inv->value * (newscroll->level + 50) / (newscroll->inv->level + 50);
1413 newscroll->stats.exp = newscroll->value / 5; 1393 newscroll->stats.exp = newscroll->value / 5;
1414 1394
1415 /* wait until finished manipulating the scroll before inserting it */ 1395 /* wait until finished manipulating the scroll before inserting it */
1416 if (newscroll == scroll) 1396 if (newscroll == scroll)
1417 { 1397 {
1418 /* Remove to correctly merge with other items which may exist in inventory */ 1398 /* Remove to correctly merge with other items which may exist in inventory */
1419 remove_ob (newscroll); 1399 newscroll->remove ();
1420 esrv_del_item (pl->contr, newscroll->count); 1400 esrv_del_item (pl->contr, newscroll->count);
1421 } 1401 }
1402
1422 newscroll = insert_ob_in_ob (newscroll, pl); 1403 newscroll = insert_ob_in_ob (newscroll, pl);
1423 esrv_send_item (pl, newscroll); 1404 esrv_send_item (pl, newscroll);
1424 success = calc_skill_exp (pl, newscroll, skill); 1405 success = calc_skill_exp (pl, newscroll, skill);
1425 if (!confused) 1406 if (!confused)
1426 success *= 2; 1407 success *= 2;
1433 1414
1434 if (chosen_spell->level > skill->level || confused) 1415 if (chosen_spell->level > skill->level || confused)
1435 { /*backfire! */ 1416 { /*backfire! */
1436 new_draw_info (NDI_UNIQUE, 0, pl, "Ouch! Your attempt to write a new scroll strains your mind!"); 1417 new_draw_info (NDI_UNIQUE, 0, pl, "Ouch! Your attempt to write a new scroll strains your mind!");
1437 if (random_roll (0, 1, pl, PREFER_LOW) == 1) 1418 if (random_roll (0, 1, pl, PREFER_LOW) == 1)
1438 drain_specific_stat (pl, 4); 1419 pl->drain_specific_stat (4);
1439 else 1420 else
1440 { 1421 {
1441 confuse_player (pl, pl, 99); 1422 confuse_player (pl, pl, 99);
1442 return (-30 * chosen_spell->level); 1423 return (-30 * chosen_spell->level);
1443 } 1424 }
1448 confuse_player (pl, pl, 99); 1429 confuse_player (pl, pl, 99);
1449 } 1430 }
1450 else 1431 else
1451 new_draw_info (NDI_UNIQUE, 0, pl, "You fail to write a new scroll."); 1432 new_draw_info (NDI_UNIQUE, 0, pl, "You fail to write a new scroll.");
1452 } 1433 }
1434
1453 return 0; 1435 return 0;
1454} 1436}
1455 1437
1456/* write_on_item() - wrapper for write_note and write_scroll */ 1438/* write_on_item() - wrapper for write_note and write_scroll */
1457int 1439int
1468 if (!params) 1450 if (!params)
1469 { 1451 {
1470 params = ""; 1452 params = "";
1471 string = params; 1453 string = params;
1472 } 1454 }
1455
1473 skat = get_archetype_by_type_subtype (SKILL, SK_LITERACY); 1456 skat = get_archetype_by_type_subtype (SKILL, SK_LITERACY);
1474 1457
1475 /* Need to be able to read before we can write! */ 1458 /* Need to be able to read before we can write! */
1476 if (!find_skill_by_name (pl, skat->clone.skill)) 1459 if (!find_skill_by_name (pl, skat->skill))
1477 { 1460 {
1478 new_draw_info (NDI_UNIQUE, 0, pl, "You must learn to read before you can write!"); 1461 new_draw_info (NDI_UNIQUE, 0, pl, "You must learn to read before you can write!");
1479 return 0; 1462 return 0;
1480 } 1463 }
1481 1464
1501 new_draw_info_format (NDI_UNIQUE, 0, pl, "You have no %s to write on", msgtype == BOOK ? "book" : "scroll"); 1484 new_draw_info_format (NDI_UNIQUE, 0, pl, "You have no %s to write on", msgtype == BOOK ? "book" : "scroll");
1502 return 0; 1485 return 0;
1503 } 1486 }
1504 1487
1505 if (msgtype == SCROLL) 1488 if (msgtype == SCROLL)
1506 {
1507 return write_scroll (pl, item, skill); 1489 return write_scroll (pl, item, skill);
1508 }
1509 else if (msgtype == BOOK) 1490 else if (msgtype == BOOK)
1510 {
1511 return write_note (pl, item, string, skill); 1491 return write_note (pl, item, string, skill);
1512 } 1492
1513 return 0; 1493 return 0;
1514} 1494}
1515
1516
1517 1495
1518/* find_throw_ob() - if we request an object, then 1496/* find_throw_ob() - if we request an object, then
1519 * we search for it in the inventory of the owner (you've 1497 * we search for it in the inventory of the owner (you've
1520 * got to be carrying something in order to throw it!). 1498 * got to be carrying something in order to throw it!).
1521 * If we didnt request an object, then the top object in inventory 1499 * If we didnt request an object, then the top object in inventory
1522 * (that is "throwable", ie no throwing your skills away!) 1500 * (that is "throwable", ie no throwing your skills away!)
1523 * is the object of choice. Also check to see if object is 1501 * is the object of choice. Also check to see if object is
1524 * 'throwable' (ie not applied cursed obj, worn, etc). 1502 * 'throwable' (ie not applied cursed obj, worn, etc).
1525 */ 1503 */
1526
1527static object * 1504static object *
1528find_throw_ob (object *op, const char *request) 1505find_throw_ob (object *op, const char *request)
1529{ 1506{
1530 object *tmp; 1507 object *tmp;
1531 1508
1603 1580
1604/* make_throw_ob() We construct the 'carrier' object in 1581/* make_throw_ob() We construct the 'carrier' object in
1605 * which we will insert the object that is being thrown. 1582 * which we will insert the object that is being thrown.
1606 * This combination becomes the 'thrown object'. -b.t. 1583 * This combination becomes the 'thrown object'. -b.t.
1607 */ 1584 */
1608
1609static object * 1585static object *
1610make_throw_ob (object *orig) 1586make_throw_ob (object *orig)
1611{ 1587{
1612 object *toss_item;
1613
1614 if (!orig) 1588 if (!orig)
1615 return NULL; 1589 return NULL;
1616 1590
1617 toss_item = get_object ();
1618 if (QUERY_FLAG (orig, FLAG_APPLIED)) 1591 if (QUERY_FLAG (orig, FLAG_APPLIED))
1619 { 1592 {
1620 LOG (llevError, "BUG: make_throw_ob(): ob is applied\n"); 1593 LOG (llevError, "BUG: make_throw_ob(): ob is applied\n");
1621 /* insufficient workaround, but better than nothing */ 1594 /* insufficient workaround, but better than nothing */
1622 CLEAR_FLAG (orig, FLAG_APPLIED); 1595 CLEAR_FLAG (orig, FLAG_APPLIED);
1623 } 1596 }
1624 copy_object (orig, toss_item); 1597
1598 object *toss_item = orig->clone ();
1599
1625 toss_item->type = THROWN_OBJ; 1600 toss_item->type = THROWN_OBJ;
1626 CLEAR_FLAG (toss_item, FLAG_CHANGING); 1601 CLEAR_FLAG (toss_item, FLAG_CHANGING);
1627 toss_item->stats.dam = 0; /* default damage */ 1602 toss_item->stats.dam = 0; /* default damage */
1628 insert_ob_in_ob (orig, toss_item); 1603 insert_ob_in_ob (orig, toss_item);
1629 return toss_item; 1604 return toss_item;
1630} 1605}
1631 1606
1632
1633/* do_throw() - op throws any object toss_item. This code 1607/* do_throw() - op throws any object toss_item. This code
1634 * was borrowed from fire_bow. 1608 * was borrowed from fire_bow.
1635 * Returns 1 if skill was successfully used, 0 if not 1609 * Returns 1 if skill was successfully used, 0 if not
1636 */ 1610 */
1637
1638static int 1611static int
1639do_throw (object *op, object *part, object *toss_item, int dir, object *skill) 1612do_throw (object *op, object *part, object *toss_item, int dir, object *skill)
1640{ 1613{
1641 object *throw_ob = toss_item, *left = NULL; 1614 object *throw_ob = toss_item, *left = NULL;
1642 tag_t left_tag;
1643 int eff_str = 0, maxc, str = op->stats.Str, dam = 0; 1615 int eff_str = 0, maxc, str = op->stats.Str, dam = 0;
1644 int pause_f, weight_f = 0, mflags; 1616 int pause_f, weight_f = 0, mflags;
1645 float str_factor = 1.0, load_factor = 1.0, item_factor = 1.0; 1617 float str_factor = 1.0, load_factor = 1.0, item_factor = 1.0;
1646 mapstruct *m; 1618 maptile *m;
1647 sint16 sx, sy; 1619 sint16 sx, sy;
1648 tag_t tag;
1649 1620
1650 if (throw_ob == NULL) 1621 if (throw_ob == NULL)
1651 { 1622 {
1652 if (op->type == PLAYER) 1623 if (op->type == PLAYER)
1653 {
1654 new_draw_info (NDI_UNIQUE, 0, op, "You have nothing to throw."); 1624 new_draw_info (NDI_UNIQUE, 0, op, "You have nothing to throw.");
1655 } 1625
1656 return 0; 1626 return 0;
1657 } 1627 }
1658 if (QUERY_FLAG (throw_ob, FLAG_STARTEQUIP)) 1628 if (QUERY_FLAG (throw_ob, FLAG_STARTEQUIP))
1659 { 1629 {
1660 if (op->type == PLAYER) 1630 if (op->type == PLAYER)
1661 {
1662 new_draw_info (NDI_UNIQUE, 0, op, "The gods won't let you throw that."); 1631 new_draw_info (NDI_UNIQUE, 0, op, "The gods won't let you throw that.");
1663 } 1632
1664 return 0; 1633 return 0;
1665 } 1634 }
1666 1635
1667 /* Because throwing effectiveness must be reduced by the 1636 /* Because throwing effectiveness must be reduced by the
1668 * encumbrance of the thrower and weight of the object. THus, 1637 * encumbrance of the thrower and weight of the object. THus,
1711 */ 1680 */
1712 mflags = get_map_flags (part->map, &m, part->x + freearr_x[dir], part->y + freearr_y[dir], &sx, &sy); 1681 mflags = get_map_flags (part->map, &m, part->x + freearr_x[dir], part->y + freearr_y[dir], &sx, &sy);
1713 1682
1714 if (!dir || (eff_str <= 1) || (mflags & P_OUT_OF_MAP) || (GET_MAP_MOVE_BLOCK (m, sx, sy) & MOVE_FLY_LOW)) 1683 if (!dir || (eff_str <= 1) || (mflags & P_OUT_OF_MAP) || (GET_MAP_MOVE_BLOCK (m, sx, sy) & MOVE_FLY_LOW))
1715 { 1684 {
1716
1717 /* bounces off 'wall', and drops to feet */ 1685 /* bounces off 'wall', and drops to feet */
1718 remove_ob (throw_ob); 1686 throw_ob->insert_at (part, op);
1719 throw_ob->x = part->x; 1687
1720 throw_ob->y = part->y;
1721 insert_ob_in_map (throw_ob, part->map, op, 0);
1722 if (op->type == PLAYER) 1688 if (op->type == PLAYER)
1723 { 1689 {
1724 if (eff_str <= 1) 1690 if (eff_str <= 1)
1725 {
1726 new_draw_info_format (NDI_UNIQUE, 0, op, "Your load is so heavy you drop %s to the ground.", query_name (throw_ob)); 1691 new_draw_info_format (NDI_UNIQUE, 0, op, "Your load is so heavy you drop %s to the ground.", query_name (throw_ob));
1727 }
1728 else if (!dir) 1692 else if (!dir)
1729 {
1730 new_draw_info_format (NDI_UNIQUE, 0, op, "You throw %s at the ground.", query_name (throw_ob)); 1693 new_draw_info_format (NDI_UNIQUE, 0, op, "You throw %s at the ground.", query_name (throw_ob));
1731 }
1732 else 1694 else
1733 new_draw_info (NDI_UNIQUE, 0, op, "Something is in the way."); 1695 new_draw_info (NDI_UNIQUE, 0, op, "Something is in the way.");
1734 } 1696 }
1697
1735 return 0; 1698 return 0;
1736 } /* if object can't be thrown */ 1699 } /* if object can't be thrown */
1737 1700
1738 left = throw_ob; /* these are throwing objects left to the player */ 1701 left = throw_ob; /* these are throwing objects left to the player */
1739 left_tag = left->count;
1740 1702
1741 /* sometimes get_split_ob can't split an object (because op->nrof==0?) 1703 /* sometimes get_split_ob can't split an object (because op->nrof==0?)
1742 * and returns NULL. We must use 'left' then 1704 * and returns NULL. We must use 'left' then
1743 */ 1705 */
1744 1706
1745 if ((throw_ob = get_split_ob (throw_ob, 1)) == NULL) 1707 if ((throw_ob = get_split_ob (throw_ob, 1)) == NULL)
1746 { 1708 {
1747 throw_ob = left; 1709 throw_ob = left;
1748 remove_ob (left); 1710 left->remove ();
1749 if (op->type == PLAYER) 1711 if (op->type == PLAYER)
1750 esrv_del_item (op->contr, left->count); 1712 esrv_del_item (op->contr, left->count);
1751 } 1713 }
1752 else if (op->type == PLAYER) 1714 else if (op->type == PLAYER)
1753 { 1715 {
1754 if (was_destroyed (left, left_tag)) 1716 if (left->destroyed ())
1755 esrv_del_item (op->contr, left_tag); 1717 esrv_del_item (op->contr, left->count);
1756 else 1718 else
1757 esrv_update_item (UPD_NROF, op, left); 1719 esrv_update_item (UPD_NROF, op, left);
1758 } 1720 }
1759 1721
1760 /* special case: throwing powdery substances like dust, dirt */ 1722 /* special case: throwing powdery substances like dust, dirt */
1777 { 1739 {
1778 insert_ob_in_ob (throw_ob, op); 1740 insert_ob_in_ob (throw_ob, op);
1779 return 0; 1741 return 0;
1780 } 1742 }
1781 1743
1782 set_owner (throw_ob, op); 1744 throw_ob->set_owner (op);
1783 /* At some point in the attack code, the actual real object (op->inv) 1745 /* At some point in the attack code, the actual real object (op->inv)
1784 * becomes the hitter. As such, we need to make sure that has a proper 1746 * becomes the hitter. As such, we need to make sure that has a proper
1785 * owner value so exp goes to the right place. 1747 * owner value so exp goes to the right place.
1786 */ 1748 */
1787 set_owner (throw_ob->inv, op); 1749 throw_ob->inv->set_owner (op);
1788 throw_ob->direction = dir; 1750 throw_ob->direction = dir;
1789 throw_ob->x = part->x;
1790 throw_ob->y = part->y;
1791 1751
1792 /* the damage bonus from the force of the throw */ 1752 /* the damage bonus from the force of the throw */
1793 dam = (int) (str_factor * dam_bonus[eff_str]); 1753 dam = (int) (str_factor * dam_bonus[eff_str]);
1794 1754
1795 /* Now, lets adjust the properties of the thrown_ob. */ 1755 /* Now, lets adjust the properties of the thrown_ob. */
1796 1756
1797 /* how far to fly */ 1757 /* how far to fly */
1798 throw_ob->last_sp = (eff_str * 3) / 5; 1758 throw_ob->last_sp = (eff_str * 3) / 5;
1799 1759
1800 /* speed */ 1760 /* speed */
1801 throw_ob->speed = (speed_bonus[eff_str] + 1.0) / 1.5; 1761 throw_ob->set_speed (min (1.0, speed_bonus[eff_str] + 1.0) / 1.5); /* no faster than an arrow! */
1802 throw_ob->speed = MIN (1.0, throw_ob->speed); /* no faster than an arrow! */
1803 1762
1804 /* item damage. Eff_str and item weight influence damage done */ 1763 /* item damage. Eff_str and item weight influence damage done */
1805 weight_f = (throw_ob->weight / 2000) > MAX_STAT ? MAX_STAT : (throw_ob->weight / 2000); 1764 weight_f = (throw_ob->weight / 2000) > MAX_STAT ? MAX_STAT : (throw_ob->weight / 2000);
1806 throw_ob->stats.dam += (dam / 3) + dam_bonus[weight_f] + (throw_ob->weight / 15000) - 2; 1765 throw_ob->stats.dam += (dam / 3) + dam_bonus[weight_f] + (throw_ob->weight / 15000) - 2;
1807 1766
1808 /* chance of breaking. Proportional to force used and weight of item */ 1767 /* chance of breaking. Proportional to force used and weight of item */
1809 throw_ob->stats.food = (dam / 2) + (throw_ob->weight / 60000); 1768 throw_ob->stats.food = (dam / 2) + (throw_ob->weight / 60000);
1810 1769
1811 /* replace 25 with a call to clone.arch wc? messes up w/ NPC */ 1770 /* replace 25 with a call to clone.arch wc? messes up w/ NPC */
1812 throw_ob->stats.wc = 25 - dex_bonus[op->stats.Dex] - thaco_bonus[eff_str] - skill->level; 1771 throw_ob->stats.wc = 25 - dex_bonus[op->stats.Dex] - thaco_bonus[eff_str] - skill->level;
1813
1814 1772
1815 /* the properties of objects which are meant to be thrown (ie dart, 1773 /* the properties of objects which are meant to be thrown (ie dart,
1816 * throwing knife, etc) will differ from ordinary items. Lets tailor 1774 * throwing knife, etc) will differ from ordinary items. Lets tailor
1817 * this stuff in here. 1775 * this stuff in here.
1818 */ 1776 */
1826 if (GET_ANIM_ID (throw_ob) && NUM_ANIMATIONS (throw_ob)) 1784 if (GET_ANIM_ID (throw_ob) && NUM_ANIMATIONS (throw_ob))
1827 SET_ANIMATION (throw_ob, dir); 1785 SET_ANIMATION (throw_ob, dir);
1828 } 1786 }
1829 else 1787 else
1830 { 1788 {
1789 uint16 mat = throw_ob->materials;
1790
1831 /* some materials will adjust properties.. */ 1791 /* some materials will adjust properties.. */
1832 if (throw_ob->material & M_LEATHER) 1792 if (mat & M_LEATHER)
1833 { 1793 {
1834 throw_ob->stats.dam -= 1; 1794 throw_ob->stats.dam -= 1;
1835 throw_ob->stats.food -= 10; 1795 throw_ob->stats.food -= 10;
1836 } 1796 }
1797
1837 if (throw_ob->material & M_GLASS) 1798 if (mat & M_GLASS)
1838 throw_ob->stats.food += 60; 1799 throw_ob->stats.food += 60;
1839 1800
1840 if (throw_ob->material & M_ORGANIC) 1801 if (mat & M_ORGANIC)
1841 { 1802 {
1842 throw_ob->stats.dam -= 3; 1803 throw_ob->stats.dam -= 3;
1843 throw_ob->stats.food += 55; 1804 throw_ob->stats.food += 55;
1844 } 1805 }
1845 if (throw_ob->material & M_PAPER || throw_ob->material & M_CLOTH) 1806
1807 if (mat & M_PAPER || mat & M_CLOTH)
1846 { 1808 {
1847 throw_ob->stats.dam -= 5; 1809 throw_ob->stats.dam -= 5;
1848 throw_ob->speed *= 0.8; 1810 throw_ob->speed *= 0.8;
1849 throw_ob->stats.wc += 3; 1811 throw_ob->stats.wc += 3;
1850 throw_ob->stats.food -= 30; 1812 throw_ob->stats.food -= 30;
1851 } 1813 }
1814
1852 /* light obj have more wind resistance, fly slower */ 1815 /* light obj have more wind resistance, fly slower */
1853 if (throw_ob->weight > 500) 1816 if (throw_ob->weight > 500)
1854 throw_ob->speed *= 0.8; 1817 throw_ob->speed *= 0.8;
1818
1855 if (throw_ob->weight > 50) 1819 if (throw_ob->weight > 50)
1856 throw_ob->speed *= 0.5; 1820 throw_ob->speed *= 0.5;
1857
1858 } /* else tailor thrown object */ 1821 } /* else tailor thrown object */
1859 1822
1860 /* some limits, and safeties (needed?) */ 1823 /* some limits, and safeties (needed?) */
1861 if (throw_ob->stats.dam < 0) 1824 if (throw_ob->stats.dam < 0)
1862 throw_ob->stats.dam = 0; 1825 throw_ob->stats.dam = 0;
1882 * In short summary, a throw can take anywhere between speed 5 and 1845 * In short summary, a throw can take anywhere between speed 5 and
1883 * speed 0.5 1846 * speed 0.5
1884 */ 1847 */
1885 op->speed_left -= 50 / pause_f; 1848 op->speed_left -= 50 / pause_f;
1886 1849
1887 update_ob_speed (throw_ob);
1888 throw_ob->speed_left = 0; 1850 throw_ob->speed_left = 0;
1889 throw_ob->map = part->map; 1851 throw_ob->map = part->map;
1890 1852
1891 throw_ob->move_type = MOVE_FLY_LOW; 1853 throw_ob->move_type = MOVE_FLY_LOW;
1892 throw_ob->move_on = MOVE_FLY_LOW | MOVE_WALK; 1854 throw_ob->move_on = MOVE_FLY_LOW | MOVE_WALK;
1902 LOG (llevDebug, " pause_f=%d \n", pause_f); 1864 LOG (llevDebug, " pause_f=%d \n", pause_f);
1903 LOG (llevDebug, " %s stats: wc=%d dam=%d dist=%d spd=%f break=%d\n", 1865 LOG (llevDebug, " %s stats: wc=%d dam=%d dist=%d spd=%f break=%d\n",
1904 throw_ob->name, throw_ob->stats.wc, throw_ob->stats.dam, throw_ob->last_sp, throw_ob->speed, throw_ob->stats.food); 1866 throw_ob->name, throw_ob->stats.wc, throw_ob->stats.dam, throw_ob->last_sp, throw_ob->speed, throw_ob->stats.food);
1905 LOG (llevDebug, "inserting tossitem (%d) into map\n", throw_ob->count); 1867 LOG (llevDebug, "inserting tossitem (%d) into map\n", throw_ob->count);
1906#endif 1868#endif
1907 tag = throw_ob->count; 1869
1908 insert_ob_in_map (throw_ob, part->map, op, 0); 1870 throw_ob->insert_at (part, op);
1909 if (!was_destroyed (throw_ob, tag)) 1871
1872 if (!throw_ob->destroyed ())
1910 move_arrow (throw_ob); 1873 move_arrow (throw_ob);
1874
1911 return 1; 1875 return 1;
1912} 1876}
1913 1877
1914int 1878int
1915skill_throw (object *op, object *part, int dir, const char *params, object *skill) 1879skill_throw (object *op, object *part, int dir, const char *params, object *skill)

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines