1 | /* |
1 | /* |
2 | * CrossFire, A Multiplayer game |
2 | * This file is part of Crossfire TRT, the Roguelike Realtime MORPG. |
3 | * |
3 | * |
4 | * Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team |
4 | * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Crossfire TRT team |
5 | * Copyright (C) 2003 Mark Wedel & Crossfire Development Team |
5 | * Copyright (©) 2003,2007 Mark Wedel & Crossfire Development Team |
6 | * Copyright (C) 1992 Frank Tore Johansen |
6 | * Copyright (©) 1992,2007 Frank Tore Johansen |
7 | * |
7 | * |
8 | * 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 |
9 | * 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 |
10 | * the Free Software Foundation; either version 2 of the License, or |
10 | * Software Foundation; either version 2 of the License, or (at your option) |
11 | * (at your option) any later version. |
11 | * any later version. |
12 | * |
12 | * |
13 | * 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 |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
16 | * GNU General Public License for more details. |
16 | * for more details. |
17 | * |
17 | * |
18 | * 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 |
19 | * 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 |
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
20 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
21 | * |
21 | * |
22 | * The authors can be reached via e-mail to <crossfire@schmorp.de> |
22 | * The authors can be reached via e-mail to <crossfire@schmorp.de> |
23 | */ |
23 | */ |
24 | |
24 | |
25 | #include <global.h> |
25 | #include <global.h> |
26 | #include <object.h> |
26 | #include <object.h> |
… | |
… | |
409 | 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."); |
410 | return 0; |
410 | return 0; |
411 | } |
411 | } |
412 | } |
412 | } |
413 | |
413 | |
414 | |
|
|
415 | /* HIDE CODE. The user becomes undetectable (not just 'invisible') for |
414 | /* HIDE CODE. The user becomes undetectable (not just 'invisible') for |
416 | * a short while (success and duration dependant on player SK_level, |
415 | * a short while (success and duration dependant on player SK_level, |
417 | * dexterity, charisma, and map difficulty). |
416 | * dexterity, charisma, and map difficulty). |
418 | * Players have a good chance of becoming 'unhidden' if they move |
417 | * Players have a good chance of becoming 'unhidden' if they move |
419 | * and like invisiblity will be come visible if they attack |
418 | * and like invisiblity will be come visible if they attack |
420 | * Implemented by b.t. (thomas@astro.psu.edu) |
419 | * Implemented by b.t. (thomas@astro.psu.edu) |
421 | * July 7, 1995 - made hiding possible for monsters. -b.t. |
420 | * July 7, 1995 - made hiding possible for monsters. -b.t. |
422 | */ |
421 | */ |
423 | |
|
|
424 | static int |
422 | static int |
425 | attempt_hide (object *op, object *skill) |
423 | attempt_hide (object *op, object *skill) |
426 | { |
424 | { |
427 | int number, difficulty = op->map->difficulty; |
425 | int number, difficulty = op->map->difficulty; |
428 | int terrain = hideability (op); |
426 | int terrain = hideability (op); |
… | |
… | |
431 | return 0; |
429 | return 0; |
432 | |
430 | |
433 | /* Hiding success and duration dependant on skill level, |
431 | /* Hiding success and duration dependant on skill level, |
434 | * op->stats.Dex, map difficulty and terrain. |
432 | * op->stats.Dex, map difficulty and terrain. |
435 | */ |
433 | */ |
436 | |
|
|
437 | number = (die_roll (2, 25, op, PREFER_LOW) - 2) / 2; |
434 | number = (die_roll (2, 25, op, PREFER_LOW) - 2) / 2; |
|
|
435 | |
438 | 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))) |
439 | { |
437 | { |
440 | op->invisible += 100; /* set the level of 'hiddeness' */ |
438 | op->invisible += 100; /* set the level of 'hiddeness' */ |
|
|
439 | |
441 | if (op->type == PLAYER) |
440 | if (op->type == PLAYER) |
442 | op->contr->tmp_invis = 1; |
441 | op->contr->tmp_invis = 1; |
|
|
442 | |
443 | op->hide = 1; |
443 | op->hide = 1; |
444 | return 1; |
444 | return 1; |
445 | } |
445 | } |
|
|
446 | |
446 | return 0; |
447 | return 0; |
447 | } |
448 | } |
448 | |
449 | |
449 | /* patched this to take terrain into consideration */ |
450 | /* patched this to take terrain into consideration */ |
450 | int |
451 | int |
451 | hide (object *op, object *skill) |
452 | hide (object *op, object *skill) |
452 | { |
453 | { |
453 | |
|
|
454 | /* the preliminaries -- Can we really hide now? */ |
454 | /* the preliminaries -- Can we really hide now? */ |
455 | /* this keeps monsters from using invisibilty spells and hiding */ |
455 | /* this keeps monsters from using invisibilty spells and hiding */ |
456 | |
456 | |
457 | if (QUERY_FLAG (op, FLAG_MAKE_INVIS)) |
457 | if (QUERY_FLAG (op, FLAG_MAKE_INVIS)) |
458 | { |
458 | { |
… | |
… | |
463 | { |
463 | { |
464 | 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!"); |
465 | make_visible (op); |
465 | make_visible (op); |
466 | } |
466 | } |
467 | |
467 | |
468 | if (op->invisible > (50 * skill->level)) |
468 | if (op->invisible > 50 * skill->level) |
469 | { |
469 | { |
470 | 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."); |
471 | return 0; |
471 | return 0; |
472 | } |
472 | } |
473 | |
473 | |
… | |
… | |
475 | { |
475 | { |
476 | 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."); |
477 | update_object (op, UP_OBJ_FACE); |
477 | update_object (op, UP_OBJ_FACE); |
478 | return calc_skill_exp (op, NULL, skill); |
478 | return calc_skill_exp (op, NULL, skill); |
479 | } |
479 | } |
|
|
480 | |
480 | 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."); |
481 | return 0; |
482 | return 0; |
482 | } |
483 | } |
483 | |
|
|
484 | |
484 | |
485 | /* stop_jump() - End of jump. Clear flags, restore the map, and |
485 | /* stop_jump() - End of jump. Clear flags, restore the map, and |
486 | * freeze the jumper a while to simulate the exhaustion |
486 | * freeze the jumper a while to simulate the exhaustion |
487 | * of jumping. |
487 | * of jumping. |
488 | */ |
488 | */ |
… | |
… | |
808 | * -b.t. (thomas@astro.psu.edu) |
808 | * -b.t. (thomas@astro.psu.edu) |
809 | */ |
809 | */ |
810 | int |
810 | int |
811 | use_oratory (object *pl, int dir, object *skill) |
811 | use_oratory (object *pl, int dir, object *skill) |
812 | { |
812 | { |
813 | sint16 x = pl->x + freearr_x[dir], y = pl->y + freearr_y[dir]; |
|
|
814 | int mflags, chance; |
|
|
815 | object *tmp; |
|
|
816 | maptile *m; |
|
|
817 | |
|
|
818 | if (pl->type != PLAYER) |
813 | if (pl->type != PLAYER) |
819 | 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]; |
820 | m = pl->map; |
818 | maptile *m = pl->map; |
|
|
819 | |
821 | mflags = get_map_flags (m, &m, x, y, &x, &y); |
820 | int mflags = get_map_flags (m, &m, x, y, &x, &y); |
822 | if (mflags & P_OUT_OF_MAP) |
821 | if (mflags & P_OUT_OF_MAP) |
823 | return 0; |
822 | return 0; |
824 | |
823 | |
825 | /* Save some processing - we have the flag already anyways |
824 | /* Save some processing - we have the flag already anyways |
826 | */ |
825 | */ |
… | |
… | |
828 | { |
827 | { |
829 | 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."); |
830 | return 0; |
829 | return 0; |
831 | } |
830 | } |
832 | |
831 | |
|
|
832 | object *tmp; |
833 | 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) |
834 | { |
834 | { |
835 | /* can't persuade players - return because there is nothing else |
835 | /* can't persuade players - return because there is nothing else |
836 | * on that space to charm. Same for multi space monsters and |
836 | * on that space to charm. Same for multi space monsters and |
837 | * 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 |
838 | * 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 |
839 | * only monster on the space. |
839 | * only monster on the space. |
840 | */ |
840 | */ |
841 | if (tmp->type == PLAYER) |
841 | if (tmp->type == PLAYER |
842 | return 0; |
842 | || tmp->more || tmp->head_ () != tmp |
843 | if (tmp->more || tmp->head) |
843 | || tmp->msg) |
844 | return 0; |
|
|
845 | if (tmp->msg) |
|
|
846 | return 0; |
844 | return 0; |
847 | |
845 | |
848 | if (QUERY_FLAG (tmp, FLAG_MONSTER)) |
846 | if (QUERY_FLAG (tmp, FLAG_MONSTER)) |
849 | break; |
847 | break; |
850 | } |
848 | } |
… | |
… | |
865 | 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)); |
866 | return 0; |
864 | return 0; |
867 | } |
865 | } |
868 | |
866 | |
869 | /* it's already allied! */ |
867 | /* it's already allied! */ |
870 | if (QUERY_FLAG (tmp, FLAG_FRIENDLY) && (tmp->attack_movement == PETMOVE)) |
868 | if (QUERY_FLAG (tmp, FLAG_FRIENDLY) && tmp->attack_movement == PETMOVE) |
871 | { |
869 | { |
872 | if (tmp->owner == pl) |
870 | if (tmp->owner == pl) |
873 | { |
871 | { |
874 | 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"); |
875 | return 0; |
873 | return 0; |
… | |
… | |
878 | { |
876 | { |
879 | /* you steal the follower. Perhaps we should really look at the |
877 | /* you steal the follower. Perhaps we should really look at the |
880 | * level of the owner above? |
878 | * level of the owner above? |
881 | */ |
879 | */ |
882 | tmp->set_owner (pl); |
880 | tmp->set_owner (pl); |
|
|
881 | tmp->skill = skill->skill; |
|
|
882 | |
883 | 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)); |
884 | /* Abuse fix - don't give exp since this can otherwise |
884 | /* Abuse fix - don't give exp since this can otherwise |
885 | * be used by a couple players to gets lots of exp. |
885 | * be used by a couple players to gets lots of exp. |
886 | */ |
886 | */ |
887 | return 0; |
887 | return 0; |
… | |
… | |
891 | /* 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 */ |
892 | return 0; |
892 | return 0; |
893 | } |
893 | } |
894 | } /* Creature was already a pet of someone */ |
894 | } /* Creature was already a pet of someone */ |
895 | |
895 | |
896 | chance = skill->level * 2 + (pl->stats.Cha - 2 * tmp->stats.Int) / 2; |
896 | int level = skill->level + (pl->stats.Cha - tmp->stats.Int) / 2; |
897 | |
897 | |
898 | /* Ok, got a 'sucker' lets try to make them a follower */ |
898 | /* Ok, got a 'sucker' lets try to make them a follower */ |
899 | 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)) |
900 | { |
900 | { |
901 | 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)); |
902 | |
902 | |
903 | tmp->set_owner (pl); |
903 | tmp->set_owner (pl); |
|
|
904 | tmp->skill = skill->skill; |
904 | tmp->stats.exp = 0; |
905 | tmp->stats.exp = 0; |
905 | add_friendly_object (tmp); |
906 | add_friendly_object (tmp); |
906 | tmp->attack_movement = PETMOVE; |
907 | tmp->attack_movement = PETMOVE; |
907 | return calc_skill_exp (pl, tmp, skill); |
908 | return calc_skill_exp (pl, tmp, skill); |
908 | } |
909 | } |
909 | |
|
|
910 | /* Charm failed. Creature may be angry now */ |
910 | /* Charm failed. Creature may be angry now */ |
911 | 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)) |
912 | { |
912 | { |
913 | new_draw_info_format (NDI_UNIQUE, 0, pl, "Your speech angers the %s!\n", query_name (tmp)); |
913 | new_draw_info_format (NDI_UNIQUE, 0, pl, "Your speech angers the %s!\n", query_name (tmp)); |
914 | if (QUERY_FLAG (tmp, FLAG_FRIENDLY)) |
914 | if (QUERY_FLAG (tmp, FLAG_FRIENDLY)) |
… | |
… | |
931 | * successfully pacified the creature gets Int=1. Thus, a player |
931 | * successfully pacified the creature gets Int=1. Thus, a player |
932 | * may only pacify a creature once. |
932 | * may only pacify a creature once. |
933 | * 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 |
934 | * of anything better! -b.t. |
934 | * of anything better! -b.t. |
935 | */ |
935 | */ |
936 | |
|
|
937 | int |
936 | int |
938 | singing (object *pl, int dir, object *skill) |
937 | singing (object *pl, int dir, object *skill) |
939 | { |
938 | { |
940 | int i, exp = 0, chance, mflags; |
939 | int i, exp = 0; |
941 | object *tmp; |
940 | object *tmp; |
942 | maptile *m; |
941 | maptile *m; |
943 | sint16 x, y; |
942 | sint16 x, y; |
944 | |
943 | |
945 | if (pl->type != PLAYER) |
944 | if (pl->type != PLAYER) |
… | |
… | |
950 | { |
949 | { |
951 | x = pl->x + freearr_x[i]; |
950 | x = pl->x + freearr_x[i]; |
952 | y = pl->y + freearr_y[i]; |
951 | y = pl->y + freearr_y[i]; |
953 | m = pl->map; |
952 | m = pl->map; |
954 | |
953 | |
955 | mflags = get_map_flags (m, &m, x, y, &x, &y); |
954 | int mflags = get_map_flags (m, &m, x, y, &x, &y); |
956 | if (mflags & P_OUT_OF_MAP) |
955 | if (mflags & P_OUT_OF_MAP) |
957 | continue; |
956 | continue; |
958 | if (!(mflags & P_IS_ALIVE)) |
957 | if (!(mflags & P_IS_ALIVE)) |
959 | continue; |
958 | continue; |
960 | |
959 | |
… | |
… | |
979 | |
978 | |
980 | /* stealing isn't really related (although, maybe it should |
979 | /* stealing isn't really related (although, maybe it should |
981 | * be). This is mainly to prevent singing to the same monster |
980 | * be). This is mainly to prevent singing to the same monster |
982 | * over and over again and getting exp for it. |
981 | * over and over again and getting exp for it. |
983 | */ |
982 | */ |
984 | 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 | |
985 | 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)) |
986 | { |
986 | { |
987 | SET_FLAG (tmp, FLAG_UNAGGRESSIVE); |
987 | SET_FLAG (tmp, FLAG_UNAGGRESSIVE); |
988 | 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)); |
989 | /* Give exp only if they are not aware */ |
989 | /* Give exp only if they are not aware */ |
|
|
990 | |
990 | if (!QUERY_FLAG (tmp, FLAG_NO_STEAL)) |
991 | if (!QUERY_FLAG (tmp, FLAG_NO_STEAL)) |
991 | exp += calc_skill_exp (pl, tmp, skill); |
992 | exp += calc_skill_exp (pl, tmp, skill); |
|
|
993 | |
992 | SET_FLAG (tmp, FLAG_NO_STEAL); |
994 | SET_FLAG (tmp, FLAG_NO_STEAL); |
993 | } |
995 | } |
994 | else |
996 | else |
995 | { |
997 | { |
996 | 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)); |
… | |
… | |
1193 | return; |
1195 | return; |
1194 | } |
1196 | } |
1195 | else |
1197 | else |
1196 | { |
1198 | { |
1197 | for (tmp = pl->inv; tmp; tmp = tmp->below) |
1199 | for (tmp = pl->inv; tmp; tmp = tmp->below) |
1198 | if (((tmp->type == ARMOUR && skill->level < 12) |
1200 | if (((tmp->type == ARMOUR && skill->level < 12) |
1199 | || (tmp->type == HELMET && skill->level < 10) |
1201 | || (tmp->type == HELMET && skill->level < 10) |
1200 | || (tmp->type == SHIELD && skill->level < 6) |
1202 | || (tmp->type == SHIELD && skill->level < 6) |
1201 | || (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)) |
1202 | { |
1206 | { |
1203 | 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"); |
1204 | return; |
1208 | return; |
1205 | } |
1209 | } |
1206 | } |
1210 | } |
… | |
… | |
1383 | insert_ob_in_ob (tmp, newscroll); |
1387 | insert_ob_in_ob (tmp, newscroll); |
1384 | |
1388 | |
1385 | /* Same code as from treasure.c - so they can better merge. |
1389 | /* Same code as from treasure.c - so they can better merge. |
1386 | * if players want to sell them, so be it. |
1390 | * if players want to sell them, so be it. |
1387 | */ |
1391 | */ |
1388 | 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); |
1389 | newscroll->stats.exp = newscroll->value / 5; |
1393 | newscroll->stats.exp = newscroll->value / 5; |
1390 | |
1394 | |
1391 | /* wait until finished manipulating the scroll before inserting it */ |
1395 | /* wait until finished manipulating the scroll before inserting it */ |
1392 | if (newscroll == scroll) |
1396 | if (newscroll == scroll) |
1393 | { |
1397 | { |
… | |
… | |
1450 | } |
1454 | } |
1451 | |
1455 | |
1452 | skat = get_archetype_by_type_subtype (SKILL, SK_LITERACY); |
1456 | skat = get_archetype_by_type_subtype (SKILL, SK_LITERACY); |
1453 | |
1457 | |
1454 | /* Need to be able to read before we can write! */ |
1458 | /* Need to be able to read before we can write! */ |
1455 | if (!find_skill_by_name (pl, skat->clone.skill)) |
1459 | if (!find_skill_by_name (pl, skat->skill)) |
1456 | { |
1460 | { |
1457 | 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!"); |
1458 | return 0; |
1462 | return 0; |
1459 | } |
1463 | } |
1460 | |
1464 | |