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.11 by root, Sat Sep 16 22:24:13 2006 UTC vs.
Revision 1.38 by root, Sun Jul 1 05:00:20 2007 UTC

1/* 1/*
2 CrossFire, A Multiplayer game for X-windows 2 * This file is part of Crossfire TRT, the Roguelike Realtime MORPG.
3 3 *
4 * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Crossfire TRT team
4 Copyright (C) 2003 Mark Wedel & Crossfire Development Team 5 * Copyright (©) 2003,2007 Mark Wedel & Crossfire Development Team
5 Copyright (C) 1992 Frank Tore Johansen 6 * Copyright (©) 1992,2007 Frank Tore Johansen
6 7 *
7 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
8 it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or 10 * the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version. 11 * (at your option) any later version.
11 12 *
12 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,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details. 16 * GNU General Public License for more details.
16 17 *
17 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
18 along with this program; if not, write to the Free Software 19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 *
20
21 The authors can be reached via e-mail to <crossfire@schmorp.de> 21 * The authors can be reached via e-mail to <crossfire@schmorp.de>
22*/ 22 */
23 23
24#include <global.h> 24#include <global.h>
25#include <object.h> 25#include <object.h>
26#ifndef __CEXTRACT__
27# include <sproto.h> 26#include <sproto.h>
28#endif
29#include <living.h> 27#include <living.h>
30#include <skills.h> 28#include <skills.h>
31#include <spells.h> 29#include <spells.h>
32#include <book.h> 30#include <book.h>
33 31
41 return -1; 39 return -1;
42 40
43 /* Only prohibit stealing if the player does not have a free 41 /* Only prohibit stealing if the player does not have a free
44 * hand available and in fact does have hands. 42 * hand available and in fact does have hands.
45 */ 43 */
46 if (op->type == PLAYER && op->body_used[BODY_ARMS] <= 0 && op->body_info[BODY_ARMS]) 44 if (op->type == PLAYER && op->slot[body_arm].used <= 0 && op->slot[body_arm].info)
47 { 45 {
48 new_draw_info (NDI_UNIQUE, 0, op, "But you have no free hands to steal with!"); 46 new_draw_info (NDI_UNIQUE, 0, op, "But you have no free hands to steal with!");
49 return -1; 47 return -1;
50 } 48 }
51 49
94 * or not. 92 * or not.
95 * op is the target (person being pilfered) 93 * op is the target (person being pilfered)
96 * who is the person doing the stealing. 94 * who is the person doing the stealing.
97 * skill is the skill object (stealing). 95 * skill is the skill object (stealing).
98 */ 96 */
99
100static int 97static int
101attempt_steal (object *op, object *who, object *skill) 98attempt_steal (object *op, object *who, object *skill)
102{ 99{
103 object *success = NULL, *tmp = NULL, *next; 100 object *success = NULL, *tmp = NULL, *next;
104 int roll = 0, chance = 0, stats_value; 101 int roll = 0, chance = 0, stats_value;
122 else /* help npc to detect thief next time by raising its wisdom */ 119 else /* help npc to detect thief next time by raising its wisdom */
123 op->stats.Wis += (op->stats.Int / 5) + 1; 120 op->stats.Wis += (op->stats.Int / 5) + 1;
124 if (op->stats.Wis > MAX_STAT) 121 if (op->stats.Wis > MAX_STAT)
125 op->stats.Wis = MAX_STAT; 122 op->stats.Wis = MAX_STAT;
126 } 123 }
124
127 if (op->type == PLAYER && QUERY_FLAG (op, FLAG_WIZ)) 125 if (op->type == PLAYER && QUERY_FLAG (op, FLAG_WIZ))
128 { 126 {
129 new_draw_info (NDI_UNIQUE, 0, who, "You can't steal from the dungeon master!\n"); 127 new_draw_info (NDI_UNIQUE, 0, who, "You can't steal from the dungeon master!\n");
130 return 0; 128 return 0;
131 } 129 }
132#ifdef PROHIBIT_PLAYERKILL 130
131 // only allow stealing between hostile players (TODO: probably should change)
133 if (op->type == PLAYER && who->type == PLAYER && (who->contr->peaceful || op->contr->peaceful)) 132 if (op->type == PLAYER && who->type == PLAYER && (who->contr->peaceful || op->contr->peaceful))
134 { 133 {
135 new_draw_info (NDI_UNIQUE, 0, who, "You can't steal from other players!\n"); 134 new_draw_info (NDI_UNIQUE, 0, who, "You can't steal from other players!\n");
136 return 0; 135 return 0;
137 } 136 }
138#else
139 if (op->type == PLAYER && who->type == PLAYER && settings.no_player_stealing)
140 {
141 new_draw_info (NDI_UNIQUE, 0, who, "You can't steal from other players!\n");
142 return 0;
143 }
144#endif
145
146 137
147 /* Ok then, go thru their inventory, stealing */ 138 /* Ok then, go thru their inventory, stealing */
148 for (tmp = op->inv; tmp != NULL; tmp = next) 139 for (tmp = op->inv; tmp; tmp = next)
149 { 140 {
150 next = tmp->below; 141 next = tmp->below;
151 142
152 /* you can't steal worn items, starting items, wiz stuff, 143 /* you can't steal worn items, starting items, wiz stuff,
153 * innate abilities, or items w/o a type. Generally 144 * innate abilities, or items w/o a type. Generally
157 * future possible problems. -b.t. 148 * future possible problems. -b.t.
158 * Flesh items generated w/ fix_flesh_item should have FLAG_NO_STEAL 149 * Flesh items generated w/ fix_flesh_item should have FLAG_NO_STEAL
159 * already -b.t. 150 * already -b.t.
160 */ 151 */
161 152
162 if (QUERY_FLAG (tmp, FLAG_WAS_WIZ) || QUERY_FLAG (tmp, FLAG_APPLIED) 153 if (QUERY_FLAG (tmp, FLAG_APPLIED)
163 || !(tmp->type) 154 || !tmp->type
164 || tmp->type == EXPERIENCE || tmp->type == SPELL 155 || tmp->type == SPELL
165 || QUERY_FLAG (tmp, FLAG_STARTEQUIP) || QUERY_FLAG (tmp, FLAG_NO_STEAL) || tmp->invisible) 156 || QUERY_FLAG (tmp, FLAG_STARTEQUIP)
157 || QUERY_FLAG (tmp, FLAG_NO_STEAL)
158 || tmp->invisible)
166 continue; 159 continue;
167 160
168 /* Okay, try stealing this item. Dependent on dexterity of thief, 161 /* Okay, try stealing this item. Dependent on dexterity of thief,
169 * skill level, see the adj_stealroll fctn for more detail. 162 * skill level, see the adj_stealroll fctn for more detail.
170 */ 163 */
261 /* play_sound("stop! thief!"); kindofthing */ 254 /* play_sound("stop! thief!"); kindofthing */
262 } /* if you weren't 100% successful */ 255 } /* if you weren't 100% successful */
263 return success ? 1 : 0; 256 return success ? 1 : 0;
264} 257}
265 258
266
267int 259int
268steal (object *op, int dir, object *skill) 260steal (object *op, int dir, object *skill)
269{ 261{
270 object *tmp, *next; 262 object *tmp, *next;
271 sint16 x, y; 263 sint16 x, y;
292 /* If player can't move onto the space, can't steal from it. */ 284 /* If player can't move onto the space, can't steal from it. */
293 if (OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, x, y))) 285 if (OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, x, y)))
294 return 0; 286 return 0;
295 287
296 /* Find the topmost object at this spot */ 288 /* Find the topmost object at this spot */
297 for (tmp = get_map_ob (m, x, y); tmp != NULL && tmp->above != NULL; tmp = tmp->above); 289 for (tmp = GET_MAP_OB (m, x, y); tmp != NULL && tmp->above != NULL; tmp = tmp->above);
298 290
299 /* For all the stacked objects at this point, attempt a steal */ 291 /* For all the stacked objects at this point, attempt a steal */
300 for (; tmp != NULL; tmp = next) 292 for (; tmp != NULL; tmp = next)
301 { 293 {
302 next = tmp->below; 294 next = tmp->below;
318 return 0; 310 return 0;
319 311
320 /* no xp for stealing from pets (of players) */ 312 /* no xp for stealing from pets (of players) */
321 if (QUERY_FLAG (tmp, FLAG_FRIENDLY) && tmp->attack_movement == PETMOVE) 313 if (QUERY_FLAG (tmp, FLAG_FRIENDLY) && tmp->attack_movement == PETMOVE)
322 { 314 {
323 object *owner = get_owner (tmp); 315 object *owner = tmp->owner;
324 316
325 if (owner != NULL && owner->type == PLAYER) 317 if (owner != NULL && owner->type == PLAYER)
326 return 0; 318 return 0;
327 } 319 }
328 320
383 { 375 {
384 new_draw_info (NDI_UNIQUE, 0, pl, "There is no lock there."); 376 new_draw_info (NDI_UNIQUE, 0, pl, "There is no lock there.");
385 return 0; 377 return 0;
386 } 378 }
387 379
388 for (tmp = get_map_ob (pl->map, x, y); tmp; tmp = tmp->above) 380 for (tmp = GET_MAP_OB (pl->map, x, y); tmp; tmp = tmp->above)
389 if (tmp->type == DOOR || tmp->type == LOCKED_DOOR) 381 if (tmp->type == DOOR || tmp->type == LOCKED_DOOR)
390 break; 382 break;
391 383
392 if (!tmp) 384 if (!tmp)
393 { 385 {
415 { 407 {
416 new_draw_info (NDI_UNIQUE, 0, pl, "You fail to pick the lock."); 408 new_draw_info (NDI_UNIQUE, 0, pl, "You fail to pick the lock.");
417 return 0; 409 return 0;
418 } 410 }
419} 411}
420
421 412
422/* HIDE CODE. The user becomes undetectable (not just 'invisible') for 413/* HIDE CODE. The user becomes undetectable (not just 'invisible') for
423 * a short while (success and duration dependant on player SK_level, 414 * a short while (success and duration dependant on player SK_level,
424 * dexterity, charisma, and map difficulty). 415 * dexterity, charisma, and map difficulty).
425 * Players have a good chance of becoming 'unhidden' if they move 416 * Players have a good chance of becoming 'unhidden' if they move
426 * and like invisiblity will be come visible if they attack 417 * and like invisiblity will be come visible if they attack
427 * Implemented by b.t. (thomas@astro.psu.edu) 418 * Implemented by b.t. (thomas@astro.psu.edu)
428 * July 7, 1995 - made hiding possible for monsters. -b.t. 419 * July 7, 1995 - made hiding possible for monsters. -b.t.
429 */ 420 */
430
431static int 421static int
432attempt_hide (object *op, object *skill) 422attempt_hide (object *op, object *skill)
433{ 423{
434 int number, difficulty = op->map->difficulty; 424 int number, difficulty = op->map->difficulty;
435 int terrain = hideability (op); 425 int terrain = hideability (op);
438 return 0; 428 return 0;
439 429
440 /* Hiding success and duration dependant on skill level, 430 /* Hiding success and duration dependant on skill level,
441 * op->stats.Dex, map difficulty and terrain. 431 * op->stats.Dex, map difficulty and terrain.
442 */ 432 */
443
444 number = (die_roll (2, 25, op, PREFER_LOW) - 2) / 2; 433 number = (die_roll (2, 25, op, PREFER_LOW) - 2) / 2;
434
445 if (!stand_near_hostile (op) && (number < (op->stats.Dex + skill->level + terrain - difficulty))) 435 if (!stand_near_hostile (op) && (number < (op->stats.Dex + skill->level + terrain - difficulty)))
446 { 436 {
447 op->invisible += 100; /* set the level of 'hiddeness' */ 437 op->invisible += 100; /* set the level of 'hiddeness' */
438
448 if (op->type == PLAYER) 439 if (op->type == PLAYER)
449 op->contr->tmp_invis = 1; 440 op->contr->tmp_invis = 1;
441
450 op->hide = 1; 442 op->hide = 1;
451 return 1; 443 return 1;
452 } 444 }
445
453 return 0; 446 return 0;
454} 447}
455 448
456/* patched this to take terrain into consideration */ 449/* patched this to take terrain into consideration */
457int 450int
458hide (object *op, object *skill) 451hide (object *op, object *skill)
459{ 452{
460
461 /* the preliminaries -- Can we really hide now? */ 453 /* the preliminaries -- Can we really hide now? */
462 /* this keeps monsters from using invisibilty spells and hiding */ 454 /* this keeps monsters from using invisibilty spells and hiding */
463 455
464 if (QUERY_FLAG (op, FLAG_MAKE_INVIS)) 456 if (QUERY_FLAG (op, FLAG_MAKE_INVIS))
465 { 457 {
470 { 462 {
471 new_draw_info (NDI_UNIQUE, 0, op, "Your attempt to hide breaks the invisibility spell!"); 463 new_draw_info (NDI_UNIQUE, 0, op, "Your attempt to hide breaks the invisibility spell!");
472 make_visible (op); 464 make_visible (op);
473 } 465 }
474 466
475 if (op->invisible > (50 * skill->level)) 467 if (op->invisible > 50 * skill->level)
476 { 468 {
477 new_draw_info (NDI_UNIQUE, 0, op, "You are as hidden as you can get."); 469 new_draw_info (NDI_UNIQUE, 0, op, "You are as hidden as you can get.");
478 return 0; 470 return 0;
479 } 471 }
480 472
482 { 474 {
483 new_draw_info (NDI_UNIQUE, 0, op, "You hide in the shadows."); 475 new_draw_info (NDI_UNIQUE, 0, op, "You hide in the shadows.");
484 update_object (op, UP_OBJ_FACE); 476 update_object (op, UP_OBJ_FACE);
485 return calc_skill_exp (op, NULL, skill); 477 return calc_skill_exp (op, NULL, skill);
486 } 478 }
479
487 new_draw_info (NDI_UNIQUE, 0, op, "You fail to conceal yourself."); 480 new_draw_info (NDI_UNIQUE, 0, op, "You fail to conceal yourself.");
488 return 0; 481 return 0;
489} 482}
490
491 483
492/* stop_jump() - End of jump. Clear flags, restore the map, and 484/* stop_jump() - End of jump. Clear flags, restore the map, and
493 * freeze the jumper a while to simulate the exhaustion 485 * freeze the jumper a while to simulate the exhaustion
494 * of jumping. 486 * of jumping.
495 */ 487 */
496static void 488static void
497stop_jump (object *pl, int dist, int spaces) 489stop_jump (object *pl, int dist, int spaces)
498{ 490{
499 fix_player (pl); 491 pl->update_stats ();
500 insert_ob_in_map (pl, pl->map, pl, 0); 492 pl->map->insert (pl, pl->x, pl->y, pl);
501} 493}
502
503 494
504static int 495static int
505attempt_jump (object *pl, int dir, int spaces, object *skill) 496attempt_jump (object *pl, int dir, int spaces, object *skill)
506{ 497{
507 object *tmp; 498 object *tmp;
514 * temporarily to allow player to aviod exits/archs that are not 505 * temporarily to allow player to aviod exits/archs that are not
515 * fly_on, fly_off. This will also prevent pickup of objects 506 * fly_on, fly_off. This will also prevent pickup of objects
516 * while jumping over them. 507 * while jumping over them.
517 */ 508 */
518 509
519 remove_ob (pl); 510 pl->remove ();
520 511
521 /* 512 /*
522 * I don't think this is actually needed - all the movement 513 * I don't think this is actually needed - all the movement
523 * code is handled in this function, and I don't see anyplace 514 * code is handled in this function, and I don't see anyplace
524 * that cares about the move_type being flying. 515 * that cares about the move_type being flying.
543 new_draw_info (NDI_UNIQUE, 0, pl, "Your jump is blocked."); 534 new_draw_info (NDI_UNIQUE, 0, pl, "Your jump is blocked.");
544 stop_jump (pl, i, spaces); 535 stop_jump (pl, i, spaces);
545 return 0; 536 return 0;
546 } 537 }
547 538
548 for (tmp = get_map_ob (m, x, y); tmp; tmp = tmp->above) 539 for (tmp = GET_MAP_OB (m, x, y); tmp; tmp = tmp->above)
549 { 540 {
550 /* Jump into creature */ 541 /* Jump into creature */
551 if (QUERY_FLAG (tmp, FLAG_MONSTER) || (tmp->type == PLAYER && (!QUERY_FLAG (tmp, FLAG_WIZ) || !tmp->contr->hidden))) 542 if (QUERY_FLAG (tmp, FLAG_MONSTER) || (tmp->type == PLAYER && (!QUERY_FLAG (tmp, FLAG_WIZ) || !tmp->contr->hidden)))
552 { 543 {
553 new_draw_info_format (NDI_UNIQUE, 0, pl, "You jump into %s%s.", tmp->type == PLAYER ? "" : "the ", &tmp->name); 544 new_draw_info_format (NDI_UNIQUE, 0, pl, "You jump into %s%s.", tmp->type == PLAYER ? "" : "the ", &tmp->name);
638 esrv_update_item (UPD_FLAGS, pl, tmp); 629 esrv_update_item (UPD_FLAGS, pl, tmp);
639 success += calc_skill_exp (pl, tmp, skill); 630 success += calc_skill_exp (pl, tmp, skill);
640 } 631 }
641 632
642 /* Check ground, too, but only objects the player could pick up */ 633 /* Check ground, too, but only objects the player could pick up */
643 for (tmp = get_map_ob (pl->map, pl->x, pl->y); tmp; tmp = tmp->above) 634 for (tmp = GET_MAP_OB (pl->map, pl->x, pl->y); tmp; tmp = tmp->above)
644 if (can_pick (pl, tmp) && 635 if (can_pick (pl, tmp) &&
645 !QUERY_FLAG (tmp, FLAG_IDENTIFIED) && 636 !QUERY_FLAG (tmp, FLAG_IDENTIFIED) &&
646 !QUERY_FLAG (tmp, FLAG_KNOWN_CURSED) 637 !QUERY_FLAG (tmp, FLAG_KNOWN_CURSED)
647 && (QUERY_FLAG (tmp, FLAG_CURSED) || QUERY_FLAG (tmp, FLAG_DAMNED)) && tmp->item_power < skill->level) 638 && (QUERY_FLAG (tmp, FLAG_CURSED) || QUERY_FLAG (tmp, FLAG_DAMNED)) && tmp->item_power < skill->level)
648 { 639 {
669 esrv_update_item (UPD_FLAGS, pl, tmp); 660 esrv_update_item (UPD_FLAGS, pl, tmp);
670 success += calc_skill_exp (pl, tmp, skill); 661 success += calc_skill_exp (pl, tmp, skill);
671 } 662 }
672 663
673 /* Check ground, too, but like above, only if the object can be picked up */ 664 /* Check ground, too, but like above, only if the object can be picked up */
674 for (tmp = get_map_ob (pl->map, pl->x, pl->y); tmp; tmp = tmp->above) 665 for (tmp = GET_MAP_OB (pl->map, pl->x, pl->y); tmp; tmp = tmp->above)
675 if (can_pick (pl, tmp) && 666 if (can_pick (pl, tmp) &&
676 !QUERY_FLAG (tmp, FLAG_IDENTIFIED) && !QUERY_FLAG (tmp, FLAG_KNOWN_MAGICAL) && (is_magical (tmp)) && tmp->item_power < skill->level) 667 !QUERY_FLAG (tmp, FLAG_IDENTIFIED) && !QUERY_FLAG (tmp, FLAG_KNOWN_MAGICAL) && (is_magical (tmp)) && tmp->item_power < skill->level)
677 { 668 {
678 SET_FLAG (tmp, FLAG_KNOWN_MAGICAL); 669 SET_FLAG (tmp, FLAG_KNOWN_MAGICAL);
679 esrv_update_item (UPD_FLAGS, pl, tmp); 670 esrv_update_item (UPD_FLAGS, pl, tmp);
734 725
735 for (tmp = pl->inv; tmp; tmp = tmp->below) 726 for (tmp = pl->inv; tmp; tmp = tmp->below)
736 success += do_skill_ident2 (tmp, pl, obj_class, skill); 727 success += do_skill_ident2 (tmp, pl, obj_class, skill);
737 /* check the ground */ 728 /* check the ground */
738 729
739 for (tmp = get_map_ob (pl->map, pl->x, pl->y); tmp; tmp = tmp->above) 730 for (tmp = GET_MAP_OB (pl->map, pl->x, pl->y); tmp; tmp = tmp->above)
740 success += do_skill_ident2 (tmp, pl, obj_class, skill); 731 success += do_skill_ident2 (tmp, pl, obj_class, skill);
741 732
742 return success; 733 return success;
743} 734}
744 735
808 new_draw_info (NDI_UNIQUE, 0, pl, "...and learn nothing more."); 799 new_draw_info (NDI_UNIQUE, 0, pl, "...and learn nothing more.");
809 } 800 }
810 return success; 801 return success;
811} 802}
812 803
813
814/* players using this skill can 'charm' a monster -- 804/* players using this skill can 'charm' a monster --
815 * into working for them. It can only be used on 805 * into working for them. It can only be used on
816 * non-special (see below) 'neutral' creatures. 806 * non-special (see below) 'neutral' creatures.
817 * -b.t. (thomas@astro.psu.edu) 807 * -b.t. (thomas@astro.psu.edu)
818 */ 808 */
819
820int 809int
821use_oratory (object *pl, int dir, object *skill) 810use_oratory (object *pl, int dir, object *skill)
822{ 811{
823 sint16 x = pl->x + freearr_x[dir], y = pl->y + freearr_y[dir];
824 int mflags, chance;
825 object *tmp;
826 maptile *m;
827
828 if (pl->type != PLAYER) 812 if (pl->type != PLAYER)
829 return 0; /* only players use this skill */ 813 return 0; /* only players use this skill */
814
815 sint16 x = pl->x + freearr_x[dir],
816 y = pl->y + freearr_y[dir];
830 m = pl->map; 817 maptile *m = pl->map;
818
831 mflags = get_map_flags (m, &m, x, y, &x, &y); 819 int mflags = get_map_flags (m, &m, x, y, &x, &y);
832 if (mflags & P_OUT_OF_MAP) 820 if (mflags & P_OUT_OF_MAP)
833 return 0; 821 return 0;
834 822
835 /* Save some processing - we have the flag already anyways 823 /* Save some processing - we have the flag already anyways
836 */ 824 */
838 { 826 {
839 new_draw_info (NDI_UNIQUE, 0, pl, "There is nothing to orate to."); 827 new_draw_info (NDI_UNIQUE, 0, pl, "There is nothing to orate to.");
840 return 0; 828 return 0;
841 } 829 }
842 830
831 object *tmp;
843 for (tmp = get_map_ob (m, x, y); tmp; tmp = tmp->above) 832 for (tmp = GET_MAP_OB (m, x, y); tmp; tmp = tmp->above)
844 { 833 {
845 /* can't persuade players - return because there is nothing else 834 /* can't persuade players - return because there is nothing else
846 * on that space to charm. Same for multi space monsters and 835 * on that space to charm. Same for multi space monsters and
847 * special monsters - we don't allow them to be charmed, and there 836 * special monsters - we don't allow them to be charmed, and there
848 * is no reason to do further processing since they should be the 837 * is no reason to do further processing since they should be the
849 * only monster on the space. 838 * only monster on the space.
850 */ 839 */
851 if (tmp->type == PLAYER) 840 if (tmp->type == PLAYER
852 return 0; 841 || tmp->more || tmp->head_ () != tmp
853 if (tmp->more || tmp->head) 842 || tmp->msg)
854 return 0;
855 if (tmp->msg)
856 return 0; 843 return 0;
857 844
858 if (QUERY_FLAG (tmp, FLAG_MONSTER)) 845 if (QUERY_FLAG (tmp, FLAG_MONSTER))
859 break; 846 break;
860 } 847 }
875 new_draw_info_format (NDI_UNIQUE, 0, pl, "Too bad the %s isn't listening!\n", query_name (tmp)); 862 new_draw_info_format (NDI_UNIQUE, 0, pl, "Too bad the %s isn't listening!\n", query_name (tmp));
876 return 0; 863 return 0;
877 } 864 }
878 865
879 /* it's already allied! */ 866 /* it's already allied! */
880 if (QUERY_FLAG (tmp, FLAG_FRIENDLY) && (tmp->attack_movement == PETMOVE)) 867 if (QUERY_FLAG (tmp, FLAG_FRIENDLY) && tmp->attack_movement == PETMOVE)
881 { 868 {
882 if (get_owner (tmp) == pl) 869 if (tmp->owner == pl)
883 { 870 {
884 new_draw_info (NDI_UNIQUE, 0, pl, "Your follower loves your speech.\n"); 871 new_draw_info (NDI_UNIQUE, 0, pl, "Your follower loves your speech.\n");
885 return 0; 872 return 0;
886 } 873 }
887 else if (skill->level > tmp->level) 874 else if (skill->level > tmp->level)
888 { 875 {
889 /* you steal the follower. Perhaps we should really look at the 876 /* you steal the follower. Perhaps we should really look at the
890 * level of the owner above? 877 * level of the owner above?
891 */ 878 */
892 set_owner (tmp, pl); 879 tmp->set_owner (pl);
880 tmp->skill = skill->skill;
881
893 new_draw_info_format (NDI_UNIQUE, 0, pl, "You convince the %s to follow you instead!\n", query_name (tmp)); 882 new_draw_info_format (NDI_UNIQUE, 0, pl, "You convince the %s to follow you instead!\n", query_name (tmp));
894 /* Abuse fix - don't give exp since this can otherwise 883 /* Abuse fix - don't give exp since this can otherwise
895 * be used by a couple players to gets lots of exp. 884 * be used by a couple players to gets lots of exp.
896 */ 885 */
897 return 0; 886 return 0;
901 /* In this case, you can't steal it from the other player */ 890 /* In this case, you can't steal it from the other player */
902 return 0; 891 return 0;
903 } 892 }
904 } /* Creature was already a pet of someone */ 893 } /* Creature was already a pet of someone */
905 894
906 chance = skill->level * 2 + (pl->stats.Cha - 2 * tmp->stats.Int) / 2; 895 int level = skill->level + (pl->stats.Cha - tmp->stats.Int) / 2;
907 896
908 /* Ok, got a 'sucker' lets try to make them a follower */ 897 /* Ok, got a 'sucker' lets try to make them a follower */
909 if (chance > 0 && tmp->level < (random_roll (0, chance - 1, pl, PREFER_HIGH) - 1)) 898 if (level > 0 && tmp->level < (random_roll (0, level - 1, pl, PREFER_HIGH) - 1))
910 { 899 {
911 new_draw_info_format (NDI_UNIQUE, 0, pl, "You convince the %s to become your follower.\n", query_name (tmp)); 900 new_draw_info_format (NDI_UNIQUE, 0, pl, "You convince the %s to become your follower.\n", query_name (tmp));
912 901
913 set_owner (tmp, pl); 902 tmp->set_owner (pl);
903 tmp->skill = skill->skill;
914 tmp->stats.exp = 0; 904 tmp->stats.exp = 0;
915 add_friendly_object (tmp); 905 add_friendly_object (tmp);
916 SET_FLAG (tmp, FLAG_FRIENDLY);
917 tmp->attack_movement = PETMOVE; 906 tmp->attack_movement = PETMOVE;
918 return calc_skill_exp (pl, tmp, skill); 907 return calc_skill_exp (pl, tmp, skill);
919 } 908 }
920 /* Charm failed. Creature may be angry now */ 909 /* Charm failed. Creature may be angry now */
921 else if ((skill->level + ((pl->stats.Cha - 10) / 2)) < random_roll (1, 2 * tmp->level, pl, PREFER_LOW)) 910 else if ((skill->level + ((pl->stats.Cha - 10) / 2)) < random_roll (1, 2 * tmp->level, pl, PREFER_LOW))
925 { 914 {
926 CLEAR_FLAG (tmp, FLAG_FRIENDLY); 915 CLEAR_FLAG (tmp, FLAG_FRIENDLY);
927 remove_friendly_object (tmp); 916 remove_friendly_object (tmp);
928 tmp->attack_movement = 0; /* needed? */ 917 tmp->attack_movement = 0; /* needed? */
929 } 918 }
919
930 CLEAR_FLAG (tmp, FLAG_UNAGGRESSIVE); 920 CLEAR_FLAG (tmp, FLAG_UNAGGRESSIVE);
931 } 921 }
922
932 return 0; /* Fall through - if we get here, we didn't charm anything */ 923 return 0; /* Fall through - if we get here, we didn't charm anything */
933} 924}
934 925
935/* Singing() -this skill allows the player to pacify nearby creatures. 926/* Singing() -this skill allows the player to pacify nearby creatures.
936 * There are few limitations on who/what kind of 927 * There are few limitations on who/what kind of
939 * successfully pacified the creature gets Int=1. Thus, a player 930 * successfully pacified the creature gets Int=1. Thus, a player
940 * may only pacify a creature once. 931 * may only pacify a creature once.
941 * BTW, I appologize for the naming of the skill, I couldnt think 932 * BTW, I appologize for the naming of the skill, I couldnt think
942 * of anything better! -b.t. 933 * of anything better! -b.t.
943 */ 934 */
944
945int 935int
946singing (object *pl, int dir, object *skill) 936singing (object *pl, int dir, object *skill)
947{ 937{
948 int i, exp = 0, chance, mflags; 938 int i, exp = 0;
949 object *tmp; 939 object *tmp;
950 maptile *m; 940 maptile *m;
951 sint16 x, y; 941 sint16 x, y;
952 942
953 if (pl->type != PLAYER) 943 if (pl->type != PLAYER)
958 { 948 {
959 x = pl->x + freearr_x[i]; 949 x = pl->x + freearr_x[i];
960 y = pl->y + freearr_y[i]; 950 y = pl->y + freearr_y[i];
961 m = pl->map; 951 m = pl->map;
962 952
963 mflags = get_map_flags (m, &m, x, y, &x, &y); 953 int mflags = get_map_flags (m, &m, x, y, &x, &y);
964 if (mflags & P_OUT_OF_MAP) 954 if (mflags & P_OUT_OF_MAP)
965 continue; 955 continue;
966 if (!(mflags & P_IS_ALIVE)) 956 if (!(mflags & P_IS_ALIVE))
967 continue; 957 continue;
968 958
969 for (tmp = get_map_ob (m, x, y); tmp; tmp = tmp->above) 959 for (tmp = GET_MAP_OB (m, x, y); tmp; tmp = tmp->above)
970 { 960 {
971 if (QUERY_FLAG (tmp, FLAG_MONSTER)) 961 if (QUERY_FLAG (tmp, FLAG_MONSTER))
972 break; 962 break;
973 /* can't affect players */ 963 /* can't affect players */
974 if (tmp->type == PLAYER) 964 if (tmp->type == PLAYER)
987 977
988 /* stealing isn't really related (although, maybe it should 978 /* stealing isn't really related (although, maybe it should
989 * be). This is mainly to prevent singing to the same monster 979 * be). This is mainly to prevent singing to the same monster
990 * over and over again and getting exp for it. 980 * over and over again and getting exp for it.
991 */ 981 */
992 chance = skill->level * 2 + (pl->stats.Cha - 5 - tmp->stats.Int) / 2; 982 int level = skill->level + (pl->stats.Cha - 5 - tmp->stats.Int) / 2;
983
993 if (chance && tmp->level * 2 < random_roll (0, chance - 1, pl, PREFER_HIGH)) 984 if (level && tmp->level < random_roll (0, level - 1, pl, PREFER_HIGH))
994 { 985 {
995 SET_FLAG (tmp, FLAG_UNAGGRESSIVE); 986 SET_FLAG (tmp, FLAG_UNAGGRESSIVE);
996 new_draw_info_format (NDI_UNIQUE, 0, pl, "You calm down the %s\n", query_name (tmp)); 987 new_draw_info_format (NDI_UNIQUE, 0, pl, "You calm down the %s\n", query_name (tmp));
997 /* Give exp only if they are not aware */ 988 /* Give exp only if they are not aware */
989
998 if (!QUERY_FLAG (tmp, FLAG_NO_STEAL)) 990 if (!QUERY_FLAG (tmp, FLAG_NO_STEAL))
999 exp += calc_skill_exp (pl, tmp, skill); 991 exp += calc_skill_exp (pl, tmp, skill);
992
1000 SET_FLAG (tmp, FLAG_NO_STEAL); 993 SET_FLAG (tmp, FLAG_NO_STEAL);
1001 } 994 }
1002 else 995 else
1003 { 996 {
1004 new_draw_info_format (NDI_UNIQUE, 0, pl, "Too bad the %s isn't listening!\n", query_name (tmp)); 997 new_draw_info_format (NDI_UNIQUE, 0, pl, "Too bad the %s isn't listening!\n", query_name (tmp));
1034 mflags = get_map_flags (m, &m, x, y, &x, &y); 1027 mflags = get_map_flags (m, &m, x, y, &x, &y);
1035 if (mflags & P_OUT_OF_MAP) 1028 if (mflags & P_OUT_OF_MAP)
1036 continue; 1029 continue;
1037 1030
1038 /* Check everything in the square for trapness */ 1031 /* Check everything in the square for trapness */
1039 for (tmp = get_map_ob (m, x, y); tmp != NULL; tmp = tmp->above) 1032 for (tmp = GET_MAP_OB (m, x, y); tmp != NULL; tmp = tmp->above)
1040 { 1033 {
1041 1034
1042 /* And now we'd better do an inventory traversal of each 1035 /* And now we'd better do an inventory traversal of each
1043 * of these objects' inventory 1036 * of these objects' inventory
1044 * We can narrow this down a bit - no reason to search through 1037 * We can narrow this down a bit - no reason to search through
1097 mflags = get_map_flags (m, &m, x, y, &x, &y); 1090 mflags = get_map_flags (m, &m, x, y, &x, &y);
1098 if (mflags & P_OUT_OF_MAP) 1091 if (mflags & P_OUT_OF_MAP)
1099 continue; 1092 continue;
1100 1093
1101 /* Check everything in the square for trapness */ 1094 /* Check everything in the square for trapness */
1102 for (tmp = get_map_ob (m, x, y); tmp != NULL; tmp = tmp->above) 1095 for (tmp = GET_MAP_OB (m, x, y); tmp != NULL; tmp = tmp->above)
1103 { 1096 {
1104 /* And now we'd better do an inventory traversal of each 1097 /* And now we'd better do an inventory traversal of each
1105 * of these objects inventory. Like above, only 1098 * of these objects inventory. Like above, only
1106 * do this for interesting objects. 1099 * do this for interesting objects.
1107 */ 1100 */
1201 return; 1194 return;
1202 } 1195 }
1203 else 1196 else
1204 { 1197 {
1205 for (tmp = pl->inv; tmp; tmp = tmp->below) 1198 for (tmp = pl->inv; tmp; tmp = tmp->below)
1206 if (((tmp->type == ARMOUR && skill->level < 12) 1199 if (((tmp->type == ARMOUR && skill->level < 12)
1207 || (tmp->type == HELMET && skill->level < 10) 1200 || (tmp->type == HELMET && skill->level < 10)
1208 || (tmp->type == SHIELD && skill->level < 6) 1201 || (tmp->type == SHIELD && skill->level < 6)
1209 || (tmp->type == BOOTS && skill->level < 4) || (tmp->type == GLOVES && skill->level < 2)) && QUERY_FLAG (tmp, FLAG_APPLIED)) 1202 || (tmp->type == BOOTS && skill->level < 4)
1203 || (tmp->type == GLOVES && skill->level < 2))
1204 && QUERY_FLAG (tmp, FLAG_APPLIED))
1210 { 1205 {
1211 new_draw_info (NDI_UNIQUE, 0, pl, "You can't concentrate while wearing so much armour!\n"); 1206 new_draw_info (NDI_UNIQUE, 0, pl, "You can't concentrate while wearing so much armour!\n");
1212 return; 1207 return;
1213 } 1208 }
1214 } 1209 }
1236} 1231}
1237 1232
1238/* write_note() - this routine allows players to inscribe messages in 1233/* write_note() - this routine allows players to inscribe messages in
1239 * ordinary 'books' (anything that is type BOOK). b.t. 1234 * ordinary 'books' (anything that is type BOOK). b.t.
1240 */ 1235 */
1241
1242static int 1236static int
1243write_note (object *pl, object *item, const char *msg, object *skill) 1237write_note (object *pl, object *item, const char *msg, object *skill)
1244{ 1238{
1245 char buf[1024]; 1239 char buf[1024];
1246 object *newBook = NULL; 1240 object *newBook = NULL;
1253 { 1247 {
1254 new_draw_info (NDI_UNIQUE, 0, pl, "No message to write!"); 1248 new_draw_info (NDI_UNIQUE, 0, pl, "No message to write!");
1255 new_draw_info_format (NDI_UNIQUE, 0, pl, "Usage: use_skill %s <message>", &skill->skill); 1249 new_draw_info_format (NDI_UNIQUE, 0, pl, "Usage: use_skill %s <message>", &skill->skill);
1256 return 0; 1250 return 0;
1257 } 1251 }
1252
1258 if (strcasestr_local (msg, "endmsg")) 1253 if (strcasestr_local (msg, "endmsg"))
1259 { 1254 {
1260 new_draw_info (NDI_UNIQUE, 0, pl, "Trying to cheat now are we?"); 1255 new_draw_info (NDI_UNIQUE, 0, pl, "Trying to cheat now are we?");
1261 return 0; 1256 return 0;
1262 } 1257 }
1272 1267
1273 strcat (buf, msg); 1268 strcat (buf, msg);
1274 strcat (buf, "\n"); /* new msg needs a LF */ 1269 strcat (buf, "\n"); /* new msg needs a LF */
1275 if (item->nrof > 1) 1270 if (item->nrof > 1)
1276 { 1271 {
1277 newBook = get_object (); 1272 newBook = item->clone ();
1278 copy_object (item, newBook);
1279 decrease_ob (item); 1273 decrease_ob (item);
1280 esrv_send_item (pl, item); 1274 esrv_send_item (pl, item);
1281 newBook->nrof = 1; 1275 newBook->nrof = 1;
1282 newBook->msg = buf; 1276 newBook->msg = buf;
1283 newBook = insert_ob_in_ob (newBook, pl); 1277 newBook = insert_ob_in_ob (newBook, pl);
1289 /* This shouldn't be necessary - the object hasn't changed in any 1283 /* This shouldn't be necessary - the object hasn't changed in any
1290 * visible way 1284 * visible way
1291 */ 1285 */
1292 /* esrv_send_item(pl, item); */ 1286 /* esrv_send_item(pl, item); */
1293 } 1287 }
1288
1294 new_draw_info_format (NDI_UNIQUE, 0, pl, "You write in the %s.", query_short_name (item)); 1289 new_draw_info_format (NDI_UNIQUE, 0, pl, "You write in the %s.", query_short_name (item));
1295 return strlen (msg); 1290 return strlen (msg);
1296 } 1291 }
1297 else 1292 else
1298 new_draw_info_format (NDI_UNIQUE, 0, pl, "Your message won't fit in the %s!", query_short_name (item)); 1293 new_draw_info_format (NDI_UNIQUE, 0, pl, "Your message won't fit in the %s!", query_short_name (item));
1318 new_draw_info (NDI_UNIQUE, 0, pl, "A spell can only be inscribed into a scroll!"); 1313 new_draw_info (NDI_UNIQUE, 0, pl, "A spell can only be inscribed into a scroll!");
1319 return 0; 1314 return 0;
1320 } 1315 }
1321 1316
1322 /* Check if we are ready to attempt inscription */ 1317 /* Check if we are ready to attempt inscription */
1323 chosen_spell = pl->contr->ranges[range_magic]; 1318 chosen_spell = pl->contr->ranged_ob;
1324 if (!chosen_spell) 1319 if (!chosen_spell || chosen_spell->type != SPELL)
1325 { 1320 {
1326 new_draw_info (NDI_UNIQUE, 0, pl, "You need a spell readied in order to inscribe!"); 1321 new_draw_info (NDI_UNIQUE, 0, pl, "You need a spell readied in order to inscribe!");
1327 return 0; 1322 return 0;
1328 } 1323 }
1324
1329 if (SP_level_spellpoint_cost (pl, chosen_spell, SPELL_GRACE) > pl->stats.grace) 1325 if (SP_level_spellpoint_cost (pl, chosen_spell, SPELL_GRACE) > pl->stats.grace)
1330 { 1326 {
1331 new_draw_info_format (NDI_UNIQUE, 0, pl, "You don't have enough grace to write a scroll of %s.", &chosen_spell->name); 1327 new_draw_info_format (NDI_UNIQUE, 0, pl, "You don't have enough grace to write a scroll of %s.", &chosen_spell->name);
1332 return 0; 1328 return 0;
1333 } 1329 }
1330
1334 if (SP_level_spellpoint_cost (pl, chosen_spell, SPELL_MANA) > pl->stats.sp) 1331 if (SP_level_spellpoint_cost (pl, chosen_spell, SPELL_MANA) > pl->stats.sp)
1335 { 1332 {
1336 new_draw_info_format (NDI_UNIQUE, 0, pl, "You don't have enough mana to write a scroll of %s.", &chosen_spell->name); 1333 new_draw_info_format (NDI_UNIQUE, 0, pl, "You don't have enough mana to write a scroll of %s.", &chosen_spell->name);
1337 return 0; 1334 return 0;
1338 } 1335 }
1358 1355
1359 if (random_roll (0, chosen_spell->level * 4 - 1, pl, PREFER_LOW) < skill->level) 1356 if (random_roll (0, chosen_spell->level * 4 - 1, pl, PREFER_LOW) < skill->level)
1360 { 1357 {
1361 if (scroll->nrof > 1) 1358 if (scroll->nrof > 1)
1362 { 1359 {
1363 newscroll = get_object (); 1360 newscroll = scroll->clone ();
1364 copy_object (scroll, newscroll);
1365 decrease_ob (scroll); 1361 decrease_ob (scroll);
1366 newscroll->nrof = 1; 1362 newscroll->nrof = 1;
1367 } 1363 }
1368 else 1364 else
1369 {
1370 newscroll = scroll; 1365 newscroll = scroll;
1371 }
1372 1366
1373 if (!confused) 1367 if (!confused)
1374 { 1368 {
1375 newscroll->level = MAX (skill->level, chosen_spell->level); 1369 newscroll->level = MAX (skill->level, chosen_spell->level);
1376 new_draw_info (NDI_UNIQUE, 0, pl, "You succeed in writing a new scroll."); 1370 new_draw_info (NDI_UNIQUE, 0, pl, "You succeed in writing a new scroll.");
1384 newscroll->level = MAX (skill->level, chosen_spell->level); 1378 newscroll->level = MAX (skill->level, chosen_spell->level);
1385 new_draw_info (NDI_UNIQUE, 0, pl, "In your confused state, you write down some odd spell."); 1379 new_draw_info (NDI_UNIQUE, 0, pl, "In your confused state, you write down some odd spell.");
1386 } 1380 }
1387 1381
1388 if (newscroll->inv) 1382 if (newscroll->inv)
1389 { 1383 newscroll->inv->destroy ();
1390 object *ninv;
1391 1384
1392 ninv = newscroll->inv; 1385 tmp = chosen_spell->clone ();
1393 remove_ob (ninv);
1394 free_object (ninv);
1395 }
1396 tmp = get_object ();
1397 copy_object (chosen_spell, tmp);
1398 insert_ob_in_ob (tmp, newscroll); 1386 insert_ob_in_ob (tmp, newscroll);
1399 1387
1400 /* Same code as from treasure.c - so they can better merge. 1388 /* Same code as from treasure.c - so they can better merge.
1401 * if players want to sell them, so be it. 1389 * if players want to sell them, so be it.
1402 */ 1390 */
1403 newscroll->value = newscroll->arch->clone.value * newscroll->inv->value * (newscroll->level + 50) / (newscroll->inv->level + 50); 1391 newscroll->value = newscroll->arch->value * newscroll->inv->value * (newscroll->level + 50) / (newscroll->inv->level + 50);
1404 newscroll->stats.exp = newscroll->value / 5; 1392 newscroll->stats.exp = newscroll->value / 5;
1405 1393
1406 /* wait until finished manipulating the scroll before inserting it */ 1394 /* wait until finished manipulating the scroll before inserting it */
1407 if (newscroll == scroll) 1395 if (newscroll == scroll)
1408 { 1396 {
1409 /* Remove to correctly merge with other items which may exist in inventory */ 1397 /* Remove to correctly merge with other items which may exist in inventory */
1410 remove_ob (newscroll); 1398 newscroll->remove ();
1411 esrv_del_item (pl->contr, newscroll->count); 1399 esrv_del_item (pl->contr, newscroll->count);
1412 } 1400 }
1401
1413 newscroll = insert_ob_in_ob (newscroll, pl); 1402 newscroll = insert_ob_in_ob (newscroll, pl);
1414 esrv_send_item (pl, newscroll); 1403 esrv_send_item (pl, newscroll);
1415 success = calc_skill_exp (pl, newscroll, skill); 1404 success = calc_skill_exp (pl, newscroll, skill);
1416 if (!confused) 1405 if (!confused)
1417 success *= 2; 1406 success *= 2;
1424 1413
1425 if (chosen_spell->level > skill->level || confused) 1414 if (chosen_spell->level > skill->level || confused)
1426 { /*backfire! */ 1415 { /*backfire! */
1427 new_draw_info (NDI_UNIQUE, 0, pl, "Ouch! Your attempt to write a new scroll strains your mind!"); 1416 new_draw_info (NDI_UNIQUE, 0, pl, "Ouch! Your attempt to write a new scroll strains your mind!");
1428 if (random_roll (0, 1, pl, PREFER_LOW) == 1) 1417 if (random_roll (0, 1, pl, PREFER_LOW) == 1)
1429 drain_specific_stat (pl, 4); 1418 pl->drain_specific_stat (4);
1430 else 1419 else
1431 { 1420 {
1432 confuse_player (pl, pl, 99); 1421 confuse_player (pl, pl, 99);
1433 return (-30 * chosen_spell->level); 1422 return (-30 * chosen_spell->level);
1434 } 1423 }
1439 confuse_player (pl, pl, 99); 1428 confuse_player (pl, pl, 99);
1440 } 1429 }
1441 else 1430 else
1442 new_draw_info (NDI_UNIQUE, 0, pl, "You fail to write a new scroll."); 1431 new_draw_info (NDI_UNIQUE, 0, pl, "You fail to write a new scroll.");
1443 } 1432 }
1433
1444 return 0; 1434 return 0;
1445} 1435}
1446 1436
1447/* write_on_item() - wrapper for write_note and write_scroll */ 1437/* write_on_item() - wrapper for write_note and write_scroll */
1448int 1438int
1459 if (!params) 1449 if (!params)
1460 { 1450 {
1461 params = ""; 1451 params = "";
1462 string = params; 1452 string = params;
1463 } 1453 }
1454
1464 skat = get_archetype_by_type_subtype (SKILL, SK_LITERACY); 1455 skat = get_archetype_by_type_subtype (SKILL, SK_LITERACY);
1465 1456
1466 /* Need to be able to read before we can write! */ 1457 /* Need to be able to read before we can write! */
1467 if (!find_skill_by_name (pl, skat->clone.skill)) 1458 if (!find_skill_by_name (pl, skat->skill))
1468 { 1459 {
1469 new_draw_info (NDI_UNIQUE, 0, pl, "You must learn to read before you can write!"); 1460 new_draw_info (NDI_UNIQUE, 0, pl, "You must learn to read before you can write!");
1470 return 0; 1461 return 0;
1471 } 1462 }
1472 1463
1492 new_draw_info_format (NDI_UNIQUE, 0, pl, "You have no %s to write on", msgtype == BOOK ? "book" : "scroll"); 1483 new_draw_info_format (NDI_UNIQUE, 0, pl, "You have no %s to write on", msgtype == BOOK ? "book" : "scroll");
1493 return 0; 1484 return 0;
1494 } 1485 }
1495 1486
1496 if (msgtype == SCROLL) 1487 if (msgtype == SCROLL)
1497 {
1498 return write_scroll (pl, item, skill); 1488 return write_scroll (pl, item, skill);
1499 }
1500 else if (msgtype == BOOK) 1489 else if (msgtype == BOOK)
1501 {
1502 return write_note (pl, item, string, skill); 1490 return write_note (pl, item, string, skill);
1503 } 1491
1504 return 0; 1492 return 0;
1505} 1493}
1506
1507
1508 1494
1509/* find_throw_ob() - if we request an object, then 1495/* find_throw_ob() - if we request an object, then
1510 * we search for it in the inventory of the owner (you've 1496 * we search for it in the inventory of the owner (you've
1511 * got to be carrying something in order to throw it!). 1497 * got to be carrying something in order to throw it!).
1512 * If we didnt request an object, then the top object in inventory 1498 * If we didnt request an object, then the top object in inventory
1513 * (that is "throwable", ie no throwing your skills away!) 1499 * (that is "throwable", ie no throwing your skills away!)
1514 * is the object of choice. Also check to see if object is 1500 * is the object of choice. Also check to see if object is
1515 * 'throwable' (ie not applied cursed obj, worn, etc). 1501 * 'throwable' (ie not applied cursed obj, worn, etc).
1516 */ 1502 */
1517
1518static object * 1503static object *
1519find_throw_ob (object *op, const char *request) 1504find_throw_ob (object *op, const char *request)
1520{ 1505{
1521 object *tmp; 1506 object *tmp;
1522 1507
1594 1579
1595/* make_throw_ob() We construct the 'carrier' object in 1580/* make_throw_ob() We construct the 'carrier' object in
1596 * which we will insert the object that is being thrown. 1581 * which we will insert the object that is being thrown.
1597 * This combination becomes the 'thrown object'. -b.t. 1582 * This combination becomes the 'thrown object'. -b.t.
1598 */ 1583 */
1599
1600static object * 1584static object *
1601make_throw_ob (object *orig) 1585make_throw_ob (object *orig)
1602{ 1586{
1603 object *toss_item;
1604
1605 if (!orig) 1587 if (!orig)
1606 return NULL; 1588 return NULL;
1607 1589
1608 toss_item = get_object ();
1609 if (QUERY_FLAG (orig, FLAG_APPLIED)) 1590 if (QUERY_FLAG (orig, FLAG_APPLIED))
1610 { 1591 {
1611 LOG (llevError, "BUG: make_throw_ob(): ob is applied\n"); 1592 LOG (llevError, "BUG: make_throw_ob(): ob is applied\n");
1612 /* insufficient workaround, but better than nothing */ 1593 /* insufficient workaround, but better than nothing */
1613 CLEAR_FLAG (orig, FLAG_APPLIED); 1594 CLEAR_FLAG (orig, FLAG_APPLIED);
1614 } 1595 }
1615 copy_object (orig, toss_item); 1596
1597 object *toss_item = orig->clone ();
1598
1616 toss_item->type = THROWN_OBJ; 1599 toss_item->type = THROWN_OBJ;
1617 CLEAR_FLAG (toss_item, FLAG_CHANGING); 1600 CLEAR_FLAG (toss_item, FLAG_CHANGING);
1618 toss_item->stats.dam = 0; /* default damage */ 1601 toss_item->stats.dam = 0; /* default damage */
1619 insert_ob_in_ob (orig, toss_item); 1602 insert_ob_in_ob (orig, toss_item);
1620 return toss_item; 1603 return toss_item;
1621} 1604}
1622 1605
1623
1624/* do_throw() - op throws any object toss_item. This code 1606/* do_throw() - op throws any object toss_item. This code
1625 * was borrowed from fire_bow. 1607 * was borrowed from fire_bow.
1626 * Returns 1 if skill was successfully used, 0 if not 1608 * Returns 1 if skill was successfully used, 0 if not
1627 */ 1609 */
1628
1629static int 1610static int
1630do_throw (object *op, object *part, object *toss_item, int dir, object *skill) 1611do_throw (object *op, object *part, object *toss_item, int dir, object *skill)
1631{ 1612{
1632 object *throw_ob = toss_item, *left = NULL; 1613 object *throw_ob = toss_item, *left = NULL;
1633 int eff_str = 0, maxc, str = op->stats.Str, dam = 0; 1614 int eff_str = 0, maxc, str = op->stats.Str, dam = 0;
1698 */ 1679 */
1699 mflags = get_map_flags (part->map, &m, part->x + freearr_x[dir], part->y + freearr_y[dir], &sx, &sy); 1680 mflags = get_map_flags (part->map, &m, part->x + freearr_x[dir], part->y + freearr_y[dir], &sx, &sy);
1700 1681
1701 if (!dir || (eff_str <= 1) || (mflags & P_OUT_OF_MAP) || (GET_MAP_MOVE_BLOCK (m, sx, sy) & MOVE_FLY_LOW)) 1682 if (!dir || (eff_str <= 1) || (mflags & P_OUT_OF_MAP) || (GET_MAP_MOVE_BLOCK (m, sx, sy) & MOVE_FLY_LOW))
1702 { 1683 {
1703
1704 /* bounces off 'wall', and drops to feet */ 1684 /* bounces off 'wall', and drops to feet */
1705 remove_ob (throw_ob); 1685 throw_ob->insert_at (part, op);
1706 throw_ob->x = part->x; 1686
1707 throw_ob->y = part->y;
1708 insert_ob_in_map (throw_ob, part->map, op, 0);
1709 if (op->type == PLAYER) 1687 if (op->type == PLAYER)
1710 { 1688 {
1711 if (eff_str <= 1) 1689 if (eff_str <= 1)
1712 {
1713 new_draw_info_format (NDI_UNIQUE, 0, op, "Your load is so heavy you drop %s to the ground.", query_name (throw_ob)); 1690 new_draw_info_format (NDI_UNIQUE, 0, op, "Your load is so heavy you drop %s to the ground.", query_name (throw_ob));
1714 }
1715 else if (!dir) 1691 else if (!dir)
1716 {
1717 new_draw_info_format (NDI_UNIQUE, 0, op, "You throw %s at the ground.", query_name (throw_ob)); 1692 new_draw_info_format (NDI_UNIQUE, 0, op, "You throw %s at the ground.", query_name (throw_ob));
1718 }
1719 else 1693 else
1720 new_draw_info (NDI_UNIQUE, 0, op, "Something is in the way."); 1694 new_draw_info (NDI_UNIQUE, 0, op, "Something is in the way.");
1721 } 1695 }
1696
1722 return 0; 1697 return 0;
1723 } /* if object can't be thrown */ 1698 } /* if object can't be thrown */
1724 1699
1725 left = throw_ob; /* these are throwing objects left to the player */ 1700 left = throw_ob; /* these are throwing objects left to the player */
1726 1701
1729 */ 1704 */
1730 1705
1731 if ((throw_ob = get_split_ob (throw_ob, 1)) == NULL) 1706 if ((throw_ob = get_split_ob (throw_ob, 1)) == NULL)
1732 { 1707 {
1733 throw_ob = left; 1708 throw_ob = left;
1734 remove_ob (left); 1709 left->remove ();
1735 if (op->type == PLAYER) 1710 if (op->type == PLAYER)
1736 esrv_del_item (op->contr, left->count); 1711 esrv_del_item (op->contr, left->count);
1737 } 1712 }
1738 else if (op->type == PLAYER) 1713 else if (op->type == PLAYER)
1739 { 1714 {
1763 { 1738 {
1764 insert_ob_in_ob (throw_ob, op); 1739 insert_ob_in_ob (throw_ob, op);
1765 return 0; 1740 return 0;
1766 } 1741 }
1767 1742
1768 set_owner (throw_ob, op); 1743 throw_ob->set_owner (op);
1769 /* At some point in the attack code, the actual real object (op->inv) 1744 /* At some point in the attack code, the actual real object (op->inv)
1770 * becomes the hitter. As such, we need to make sure that has a proper 1745 * becomes the hitter. As such, we need to make sure that has a proper
1771 * owner value so exp goes to the right place. 1746 * owner value so exp goes to the right place.
1772 */ 1747 */
1773 set_owner (throw_ob->inv, op); 1748 throw_ob->inv->set_owner (op);
1774 throw_ob->direction = dir; 1749 throw_ob->direction = dir;
1775 throw_ob->x = part->x;
1776 throw_ob->y = part->y;
1777 1750
1778 /* the damage bonus from the force of the throw */ 1751 /* the damage bonus from the force of the throw */
1779 dam = (int) (str_factor * dam_bonus[eff_str]); 1752 dam = (int) (str_factor * dam_bonus[eff_str]);
1780 1753
1781 /* Now, lets adjust the properties of the thrown_ob. */ 1754 /* Now, lets adjust the properties of the thrown_ob. */
1782 1755
1783 /* how far to fly */ 1756 /* how far to fly */
1784 throw_ob->last_sp = (eff_str * 3) / 5; 1757 throw_ob->last_sp = (eff_str * 3) / 5;
1785 1758
1786 /* speed */ 1759 /* speed */
1787 throw_ob->speed = (speed_bonus[eff_str] + 1.0) / 1.5; 1760 throw_ob->set_speed (min (1.0, speed_bonus[eff_str] + 1.0) / 1.5); /* no faster than an arrow! */
1788 throw_ob->speed = MIN (1.0, throw_ob->speed); /* no faster than an arrow! */
1789 1761
1790 /* item damage. Eff_str and item weight influence damage done */ 1762 /* item damage. Eff_str and item weight influence damage done */
1791 weight_f = (throw_ob->weight / 2000) > MAX_STAT ? MAX_STAT : (throw_ob->weight / 2000); 1763 weight_f = (throw_ob->weight / 2000) > MAX_STAT ? MAX_STAT : (throw_ob->weight / 2000);
1792 throw_ob->stats.dam += (dam / 3) + dam_bonus[weight_f] + (throw_ob->weight / 15000) - 2; 1764 throw_ob->stats.dam += (dam / 3) + dam_bonus[weight_f] + (throw_ob->weight / 15000) - 2;
1793 1765
1794 /* chance of breaking. Proportional to force used and weight of item */ 1766 /* chance of breaking. Proportional to force used and weight of item */
1795 throw_ob->stats.food = (dam / 2) + (throw_ob->weight / 60000); 1767 throw_ob->stats.food = (dam / 2) + (throw_ob->weight / 60000);
1796 1768
1797 /* replace 25 with a call to clone.arch wc? messes up w/ NPC */ 1769 /* replace 25 with a call to clone.arch wc? messes up w/ NPC */
1798 throw_ob->stats.wc = 25 - dex_bonus[op->stats.Dex] - thaco_bonus[eff_str] - skill->level; 1770 throw_ob->stats.wc = 25 - dex_bonus[op->stats.Dex] - thaco_bonus[eff_str] - skill->level;
1799
1800 1771
1801 /* the properties of objects which are meant to be thrown (ie dart, 1772 /* the properties of objects which are meant to be thrown (ie dart,
1802 * throwing knife, etc) will differ from ordinary items. Lets tailor 1773 * throwing knife, etc) will differ from ordinary items. Lets tailor
1803 * this stuff in here. 1774 * this stuff in here.
1804 */ 1775 */
1812 if (GET_ANIM_ID (throw_ob) && NUM_ANIMATIONS (throw_ob)) 1783 if (GET_ANIM_ID (throw_ob) && NUM_ANIMATIONS (throw_ob))
1813 SET_ANIMATION (throw_ob, dir); 1784 SET_ANIMATION (throw_ob, dir);
1814 } 1785 }
1815 else 1786 else
1816 { 1787 {
1788 uint16 mat = throw_ob->materials;
1789
1817 /* some materials will adjust properties.. */ 1790 /* some materials will adjust properties.. */
1818 if (throw_ob->material & M_LEATHER) 1791 if (mat & M_LEATHER)
1819 { 1792 {
1820 throw_ob->stats.dam -= 1; 1793 throw_ob->stats.dam -= 1;
1821 throw_ob->stats.food -= 10; 1794 throw_ob->stats.food -= 10;
1822 } 1795 }
1796
1823 if (throw_ob->material & M_GLASS) 1797 if (mat & M_GLASS)
1824 throw_ob->stats.food += 60; 1798 throw_ob->stats.food += 60;
1825 1799
1826 if (throw_ob->material & M_ORGANIC) 1800 if (mat & M_ORGANIC)
1827 { 1801 {
1828 throw_ob->stats.dam -= 3; 1802 throw_ob->stats.dam -= 3;
1829 throw_ob->stats.food += 55; 1803 throw_ob->stats.food += 55;
1830 } 1804 }
1831 if (throw_ob->material & M_PAPER || throw_ob->material & M_CLOTH) 1805
1806 if (mat & M_PAPER || mat & M_CLOTH)
1832 { 1807 {
1833 throw_ob->stats.dam -= 5; 1808 throw_ob->stats.dam -= 5;
1834 throw_ob->speed *= 0.8; 1809 throw_ob->speed *= 0.8;
1835 throw_ob->stats.wc += 3; 1810 throw_ob->stats.wc += 3;
1836 throw_ob->stats.food -= 30; 1811 throw_ob->stats.food -= 30;
1837 } 1812 }
1813
1838 /* light obj have more wind resistance, fly slower */ 1814 /* light obj have more wind resistance, fly slower */
1839 if (throw_ob->weight > 500) 1815 if (throw_ob->weight > 500)
1840 throw_ob->speed *= 0.8; 1816 throw_ob->speed *= 0.8;
1817
1841 if (throw_ob->weight > 50) 1818 if (throw_ob->weight > 50)
1842 throw_ob->speed *= 0.5; 1819 throw_ob->speed *= 0.5;
1843
1844 } /* else tailor thrown object */ 1820 } /* else tailor thrown object */
1845 1821
1846 /* some limits, and safeties (needed?) */ 1822 /* some limits, and safeties (needed?) */
1847 if (throw_ob->stats.dam < 0) 1823 if (throw_ob->stats.dam < 0)
1848 throw_ob->stats.dam = 0; 1824 throw_ob->stats.dam = 0;
1868 * In short summary, a throw can take anywhere between speed 5 and 1844 * In short summary, a throw can take anywhere between speed 5 and
1869 * speed 0.5 1845 * speed 0.5
1870 */ 1846 */
1871 op->speed_left -= 50 / pause_f; 1847 op->speed_left -= 50 / pause_f;
1872 1848
1873 update_ob_speed (throw_ob);
1874 throw_ob->speed_left = 0; 1849 throw_ob->speed_left = 0;
1875 throw_ob->map = part->map; 1850 throw_ob->map = part->map;
1876 1851
1877 throw_ob->move_type = MOVE_FLY_LOW; 1852 throw_ob->move_type = MOVE_FLY_LOW;
1878 throw_ob->move_on = MOVE_FLY_LOW | MOVE_WALK; 1853 throw_ob->move_on = MOVE_FLY_LOW | MOVE_WALK;
1888 LOG (llevDebug, " pause_f=%d \n", pause_f); 1863 LOG (llevDebug, " pause_f=%d \n", pause_f);
1889 LOG (llevDebug, " %s stats: wc=%d dam=%d dist=%d spd=%f break=%d\n", 1864 LOG (llevDebug, " %s stats: wc=%d dam=%d dist=%d spd=%f break=%d\n",
1890 throw_ob->name, throw_ob->stats.wc, throw_ob->stats.dam, throw_ob->last_sp, throw_ob->speed, throw_ob->stats.food); 1865 throw_ob->name, throw_ob->stats.wc, throw_ob->stats.dam, throw_ob->last_sp, throw_ob->speed, throw_ob->stats.food);
1891 LOG (llevDebug, "inserting tossitem (%d) into map\n", throw_ob->count); 1866 LOG (llevDebug, "inserting tossitem (%d) into map\n", throw_ob->count);
1892#endif 1867#endif
1893 insert_ob_in_map (throw_ob, part->map, op, 0); 1868
1869 throw_ob->insert_at (part, op);
1894 1870
1895 if (!throw_ob->destroyed ()) 1871 if (!throw_ob->destroyed ())
1896 move_arrow (throw_ob); 1872 move_arrow (throw_ob);
1897 1873
1898 return 1; 1874 return 1;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines