1 | /* |
1 | /* |
2 | * This file is part of Deliantra, the Roguelike Realtime MMORPG. |
2 | * This file is part of Deliantra, the Roguelike Realtime MMORPG. |
3 | * |
3 | * |
|
|
4 | * Copyright (©) 2017,2018 Marc Alexander Lehmann / the Deliantra team |
4 | * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012 Marc Alexander Lehmann / Robin Redeker / the Deliantra team |
5 | * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016 Marc Alexander Lehmann / Robin Redeker / the Deliantra team |
5 | * Copyright (©) 2002 Mark Wedel & Crossfire Development Team |
6 | * Copyright (©) 2002 Mark Wedel & Crossfire Development Team |
6 | * Copyright (©) 1992 Frank Tore Johansen |
7 | * Copyright (©) 1992 Frank Tore Johansen |
7 | * |
8 | * |
8 | * Deliantra is free software: you can redistribute it and/or modify it under |
9 | * Deliantra is free software: you can redistribute it and/or modify it under |
9 | * the terms of the Affero GNU General Public License as published by the |
10 | * the terms of the Affero GNU General Public License as published by the |
… | |
… | |
137 | |
138 | |
138 | op = stop_item (op); |
139 | op = stop_item (op); |
139 | if (!op) |
140 | if (!op) |
140 | return; |
141 | return; |
141 | |
142 | |
142 | /* Hacked the following so that type LIGHTER will work. |
143 | /* Hacked the following so that type LIGHTER will work. |
143 | * Also, objects which are potential "lights" that are hit by |
144 | * Also, objects which are potential "lights" that are hit by |
144 | * flame/elect attacks will be set to glow. "lights" are any |
145 | * flame/elect attacks will be set to glow. "lights" are any |
145 | * object with +/- glow_radius and an "other_arch" to change to. |
146 | * object with +/- glow_radius and an "other_arch" to change to. |
146 | * (and please note that we cant fail our save and reach this |
147 | * (and please note that we cant fail our save and reach this |
147 | * function if the object doesnt contain a material that can burn. |
148 | * function if the object doesnt contain a material that can burn. |
148 | * So forget lighting magical swords on fire with this!) -b.t. |
149 | * So forget lighting magical swords on fire with this!) -b.t. |
149 | */ |
150 | */ |
150 | if (type & (AT_FIRE | AT_ELECTRICITY)) |
151 | if (type & (AT_FIRE | AT_ELECTRICITY)) |
151 | { |
152 | { |
152 | // seems LAMPs and TORCHes are always IS_LIGHTABLE? |
153 | // seems LAMPs and TORCHes are always IS_LIGHTABLE? |
… | |
… | |
340 | |
341 | |
341 | if (op->destroyed ()) |
342 | if (op->destroyed ()) |
342 | break; |
343 | break; |
343 | } |
344 | } |
344 | /* Here we are potentially destroying an object. If the object has |
345 | /* Here we are potentially destroying an object. If the object has |
345 | * NO_PASS set, it is also immune - you can't destroy walls. Note |
346 | * NO_PASS set, it is also immune - you can't destroy walls. Note |
346 | * that weak walls have is_alive set, which prevent objects from |
347 | * that weak walls have is_alive set, which prevent objects from |
347 | * passing over/through them. We don't care what type of movement |
348 | * passing over/through them. We don't care what type of movement |
348 | * the wall blocks - if it blocks any type of movement, can't be |
349 | * the wall blocks - if it blocks any type of movement, can't be |
349 | * destroyed right now. |
350 | * destroyed right now. |
350 | * Without the material check the server completely fails to work, |
351 | * Without the material check the server completely fails to work, |
… | |
… | |
566 | return; |
567 | return; |
567 | |
568 | |
568 | /* Did a player hurt another player? Inform both! */ |
569 | /* Did a player hurt another player? Inform both! */ |
569 | if (op->type == PLAYER && (hitter->owner == NULL ? hitter->type : hitter->owner->type) == PLAYER) |
570 | if (op->type == PLAYER && (hitter->owner == NULL ? hitter->type : hitter->owner->type) == PLAYER) |
570 | { |
571 | { |
571 | if (hitter->owner != NULL) |
572 | if (hitter->owner) |
572 | sprintf (buf, "%s's %s%s you.", &hitter->owner->name, &hitter->name, buf2); |
573 | sprintf (buf, "%s's %s%s you.", &hitter->owner->name, &hitter->name, buf2); |
573 | else |
574 | else |
574 | { |
575 | { |
575 | sprintf (buf, "%s%s you.", &hitter->name, buf2); |
576 | sprintf (buf, "%s%s you.", &hitter->name, buf2); |
576 | |
577 | |
… | |
… | |
701 | static void |
702 | static void |
702 | thrown_item_effect (object *hitter, object *victim) |
703 | thrown_item_effect (object *hitter, object *victim) |
703 | { |
704 | { |
704 | if (!hitter->flag [FLAG_ALIVE]) |
705 | if (!hitter->flag [FLAG_ALIVE]) |
705 | { |
706 | { |
706 | /* May not need a switch for just 2 types, but this makes it |
707 | /* May not need a switch for just 2 types, but this makes it |
707 | * easier for expansion. |
708 | * easier for expansion. |
708 | */ |
709 | */ |
709 | switch (hitter->type) |
710 | switch (hitter->type) |
710 | { |
711 | { |
711 | case POTION: |
712 | case POTION: |
… | |
… | |
770 | attacker = hitter; |
771 | attacker = hitter; |
771 | } |
772 | } |
772 | else if (!hitter->flag [FLAG_ALIVE]) |
773 | else if (!hitter->flag [FLAG_ALIVE]) |
773 | return 0; |
774 | return 0; |
774 | |
775 | |
775 | /* determine the condtions under which we make an attack. |
776 | /* determine the condtions under which we make an attack. |
776 | * Add more cases, as the need occurs. */ |
777 | * Add more cases, as the need occurs. */ |
777 | |
778 | |
778 | if (!can_see_enemy (attacker, target)) |
779 | if (!can_see_enemy (attacker, target)) |
779 | { |
780 | { |
780 | /* target is unseen */ |
781 | /* target is unseen */ |
… | |
… | |
868 | int hitdam = base_dam; |
869 | int hitdam = base_dam; |
869 | |
870 | |
870 | if (!simple_attack) |
871 | if (!simple_attack) |
871 | { |
872 | { |
872 | /* If you hit something, the victim should *always* wake up. |
873 | /* If you hit something, the victim should *always* wake up. |
873 | * Before, invisible hitters could avoid doing this. |
874 | * Before, invisible hitters could avoid doing this. |
874 | * -b.t. */ |
875 | * -b.t. */ |
875 | if (op->flag [FLAG_SLEEP]) |
876 | if (op->flag [FLAG_SLEEP]) |
876 | op->clr_flag (FLAG_SLEEP); |
877 | op->clr_flag (FLAG_SLEEP); |
877 | |
878 | |
878 | /* If the victim can't see the attacker, it may alert others |
879 | /* If the victim can't see the attacker, it may alert others |
… | |
… | |
909 | |
910 | |
910 | /* Ok, because some of the brainfucks of the good *sigh* old *sigh* |
911 | /* Ok, because some of the brainfucks of the good *sigh* old *sigh* |
911 | * Crossfire we have to default the attacktype here to AT_PHYSICAL. |
912 | * Crossfire we have to default the attacktype here to AT_PHYSICAL. |
912 | * This check is important for the most simple monsters out there in the |
913 | * This check is important for the most simple monsters out there in the |
913 | * game content (maps, archs). For example orcs: They would have |
914 | * game content (maps, archs). For example orcs: They would have |
914 | * no attacktype at all. |
915 | * no attacktype at all. |
915 | * |
916 | * |
916 | * Some time in the future someone should just go into the game data |
917 | * Some time in the future someone should just go into the game data |
917 | * and fix every monster out there ;-/ Until then we will kill some |
918 | * and fix every monster out there ;-/ Until then we will kill some |
918 | * more trees in the african rain forests with this check. |
919 | * more trees in the african rain forests with this check. |
919 | */ |
920 | */ |
… | |
… | |
1018 | * arrow, move_apply() calls this function, arrow sticks in demon, |
1019 | * arrow, move_apply() calls this function, arrow sticks in demon, |
1019 | * attack_ob_simple() returns, and we've got an arrow that still exists |
1020 | * attack_ob_simple() returns, and we've got an arrow that still exists |
1020 | * but is no longer on the map. Ugh. (Beware: Such things can happen at |
1021 | * but is no longer on the map. Ugh. (Beware: Such things can happen at |
1021 | * other places as well!) |
1022 | * other places as well!) |
1022 | */ |
1023 | */ |
1023 | if (hitter->destroyed () || hitter->env != NULL) |
1024 | if (hitter->destroyed () || hitter->env) |
1024 | { |
1025 | { |
1025 | if (container) |
1026 | if (container) |
1026 | container->destroy (); |
1027 | container->destroy (); |
1027 | |
1028 | |
1028 | return 0; |
1029 | return 0; |
1029 | } |
1030 | } |
1030 | |
1031 | |
1031 | /* Missile hit victim */ |
1032 | /* Missile hit victim */ |
1032 | /* if the speed is > 10, then this is a fast moving arrow, we go straight |
1033 | /* if the speed is >= 10, then this is a fast moving arrow, we go straight |
1033 | * through the target |
1034 | * through the target |
1034 | */ |
1035 | */ |
1035 | if (hit_something && op->speed <= 10.0) |
1036 | if (hit_something) |
|
|
1037 | if (op->speed < 10.0) |
1036 | { |
1038 | { |
1037 | /* Stop arrow */ |
1039 | /* Stop arrow */ |
1038 | if (!container) |
1040 | if (container) |
|
|
1041 | container->destroy (); |
|
|
1042 | else |
1039 | { |
1043 | { |
1040 | hitter = fix_stopped_arrow (hitter); |
1044 | hitter = fix_stopped_arrow (hitter); |
1041 | if (!hitter) |
1045 | if (!hitter) |
1042 | return 0; |
1046 | return 0; |
1043 | } |
1047 | } |
1044 | else |
|
|
1045 | container->destroy (); |
|
|
1046 | |
1048 | |
1047 | /* Try to stick arrow into victim */ |
1049 | /* Try to stick arrow into victim */ |
1048 | if (!victim->destroyed () && stick_arrow (hitter, victim)) |
1050 | if (!victim->destroyed () && stick_arrow (hitter, victim)) |
|
|
1051 | return 0; |
|
|
1052 | |
|
|
1053 | /* Else try to put arrow on victim's map square |
|
|
1054 | * remove check for P_WALL here. If the arrow got to this |
|
|
1055 | * space, that is good enough - with the new movement code, |
|
|
1056 | * there is now the potential for lots of spaces where something |
|
|
1057 | * can fly over but not otherwise move over. What is the correct |
|
|
1058 | * way to handle those otherwise? |
|
|
1059 | */ |
|
|
1060 | if (victim->x != hitter->x || victim->y != hitter->y) |
|
|
1061 | { |
|
|
1062 | if (victim->destroyed ()) |
|
|
1063 | hitter->destroy (); |
|
|
1064 | else |
|
|
1065 | { |
|
|
1066 | hitter->remove (); |
|
|
1067 | hitter->x = victim->x; |
|
|
1068 | hitter->y = victim->y; |
|
|
1069 | insert_ob_in_map (hitter, victim->map, hitter, 0); |
|
|
1070 | } |
|
|
1071 | } |
|
|
1072 | else |
|
|
1073 | /* Else leave arrow where it is */ |
|
|
1074 | merge_ob (hitter, NULL); |
|
|
1075 | |
1049 | return 0; |
1076 | return 0; |
1050 | |
|
|
1051 | /* Else try to put arrow on victim's map square |
|
|
1052 | * remove check for P_WALL here. If the arrow got to this |
|
|
1053 | * space, that is good enough - with the new movement code, |
|
|
1054 | * there is now the potential for lots of spaces where something |
|
|
1055 | * can fly over but not otherwise move over. What is the correct |
|
|
1056 | * way to handle those otherwise? |
|
|
1057 | */ |
|
|
1058 | if (victim->x != hitter->x || victim->y != hitter->y) |
|
|
1059 | { |
|
|
1060 | if (victim->destroyed ()) |
|
|
1061 | hitter->destroy (); |
|
|
1062 | else |
|
|
1063 | { |
|
|
1064 | hitter->remove (); |
|
|
1065 | hitter->x = victim->x; |
|
|
1066 | hitter->y = victim->y; |
|
|
1067 | insert_ob_in_map (hitter, victim->map, hitter, 0); |
|
|
1068 | } |
|
|
1069 | } |
1077 | } |
1070 | else |
1078 | else |
1071 | /* Else leave arrow where it is */ |
|
|
1072 | merge_ob (hitter, NULL); |
|
|
1073 | |
|
|
1074 | return 0; |
|
|
1075 | } |
|
|
1076 | |
|
|
1077 | if (hit_something && op->speed >= 10.0) |
|
|
1078 | op->set_speed (op->speed - 1.f); |
1079 | op->set_speed (op->speed - 1.f); |
1079 | |
1080 | |
1080 | /* Missile missed victim - reassemble missile */ |
1081 | /* Missile missed victim - reassemble missile */ |
1081 | if (container) |
1082 | if (container) |
1082 | { |
1083 | { |
1083 | hitter->remove (); |
1084 | hitter->remove (); |
… | |
… | |
1237 | owner->play_sound (sound_find ("player_kills")); |
1238 | owner->play_sound (sound_find ("player_kills")); |
1238 | } |
1239 | } |
1239 | |
1240 | |
1240 | /* If a player kills another player, not on |
1241 | /* If a player kills another player, not on |
1241 | * battleground, the "killer" looses 1 luck. Since this is |
1242 | * battleground, the "killer" looses 1 luck. Since this is |
1242 | * not reversible, it's actually quite a pain IMHO. -AV |
1243 | * not reversible, it's actually quite a pain IMHO. -AV |
1243 | * Fix bug in that we were changing the luck of the hitter, not |
1244 | * Fix bug in that we were changing the luck of the hitter, not |
1244 | * player that the object belonged to - so if you killed another player |
1245 | * player that the object belonged to - so if you killed another player |
1245 | * with spells, pets, whatever, there was no penalty. |
1246 | * with spells, pets, whatever, there was no penalty. |
1246 | * Changed to make luck penalty configurable in settings. |
1247 | * Changed to make luck penalty configurable in settings. |
1247 | */ |
1248 | */ |
… | |
… | |
1377 | * continues in the calling function. |
1378 | * continues in the calling function. |
1378 | */ |
1379 | */ |
1379 | return maxdam; |
1380 | return maxdam; |
1380 | } |
1381 | } |
1381 | |
1382 | |
1382 | /* Find out if this is friendly fire (PVP and attacker is peaceful) or not |
1383 | /* Find out if this is friendly fire (PVP and attacker is peaceful) or not |
1383 | * Returns 0 this is not friendly fire |
1384 | * Returns 0 this is not friendly fire |
1384 | */ |
1385 | */ |
1385 | int |
1386 | int |
1386 | friendly_fire (object *op, object *hitter) |
1387 | friendly_fire (object *op, object *hitter) |
1387 | { |
1388 | { |
… | |
… | |
1708 | |
1709 | |
1709 | if (j == -1) /* No spot to put this monster */ |
1710 | if (j == -1) /* No spot to put this monster */ |
1710 | tmp->destroy (); |
1711 | tmp->destroy (); |
1711 | else |
1712 | else |
1712 | { |
1713 | { |
1713 | tmp->x = op->x + freearr_x[j], tmp->y = op->y + freearr_y[j]; |
1714 | tmp->x = op->x + DIRX (j), tmp->y = op->y + DIRY (j); |
1714 | insert_ob_in_map (tmp, op->map, NULL, 0); |
1715 | insert_ob_in_map (tmp, op->map, NULL, 0); |
1715 | } |
1716 | } |
1716 | } |
1717 | } |
1717 | |
1718 | |
1718 | op->destroy (); |
1719 | op->destroy (); |
… | |
… | |
1735 | /* peterm: give poisoning some teeth. It should |
1736 | /* peterm: give poisoning some teeth. It should |
1736 | * be able to kill things better than it does: |
1737 | * be able to kill things better than it does: |
1737 | * damage should be dependent something--I choose to |
1738 | * damage should be dependent something--I choose to |
1738 | * do this: if it's a monster, the damage from the |
1739 | * do this: if it's a monster, the damage from the |
1739 | * poisoning goes as the level of the monster/2. |
1740 | * poisoning goes as the level of the monster/2. |
1740 | * If anything else, goes as damage. |
1741 | * If anything else, goes as damage. |
1741 | */ |
1742 | */ |
1742 | |
1743 | |
1743 | if (hitter->flag [FLAG_ALIVE]) |
1744 | if (hitter->flag [FLAG_ALIVE]) |
1744 | tmp->stats.dam += hitter->level / 2; |
1745 | tmp->stats.dam += hitter->level / 2; |
1745 | else |
1746 | else |
… | |
… | |
1810 | tmp = archetype::get (FORCE_NAME); |
1811 | tmp = archetype::get (FORCE_NAME); |
1811 | tmp = insert_ob_in_ob (tmp, op); |
1812 | tmp = insert_ob_in_ob (tmp, op); |
1812 | } |
1813 | } |
1813 | |
1814 | |
1814 | /* Duration added per hit and max. duration of confusion both depend |
1815 | /* Duration added per hit and max. duration of confusion both depend |
1815 | * on the player's resistance |
1816 | * on the player's resistance |
1816 | */ |
1817 | */ |
1817 | tmp->set_speed (0.05); |
1818 | tmp->set_speed (0.05); |
1818 | tmp->subtype = FORCE_CONFUSION; |
1819 | tmp->subtype = FORCE_CONFUSION; |
1819 | tmp->duration = 8 + max (1, 5 * (100 - op->resist[ATNR_CONFUSION]) / 100); |
1820 | tmp->duration = 8 + max (1, 5 * (100 - op->resist[ATNR_CONFUSION]) / 100); |
1820 | tmp->name = shstr_confusion; |
1821 | tmp->name = shstr_confusion; |
… | |
… | |
1858 | |
1859 | |
1859 | void |
1860 | void |
1860 | paralyze_player (object *op, object *hitter, int dam) |
1861 | paralyze_player (object *op, object *hitter, int dam) |
1861 | { |
1862 | { |
1862 | /* This is strange stuff... someone knows for what this is |
1863 | /* This is strange stuff... someone knows for what this is |
1863 | * written? Well, i think this can and should be removed |
1864 | * written? Well, i think this can and should be removed |
1864 | */ |
1865 | */ |
1865 | |
1866 | |
1866 | /* |
1867 | /* |
1867 | if((tmp=present(PARAIMAGE,op->map,op->x,op->y))==NULL) { |
1868 | if((tmp=present(PARAIMAGE,op->map,op->x,op->y))==NULL) { |
1868 | tmp=clone_arch(PARAIMAGE); |
1869 | tmp=clone_arch(PARAIMAGE); |
… | |
… | |
1927 | * redone. |
1928 | * redone. |
1928 | */ |
1929 | */ |
1929 | if (kill_lev >= def_lev) |
1930 | if (kill_lev >= def_lev) |
1930 | { |
1931 | { |
1931 | *dam = op->stats.hp + 10; /* take all hp. they can still save for 1/2 */ |
1932 | *dam = op->stats.hp + 10; /* take all hp. they can still save for 1/2 */ |
1932 | /* I think this doesn't really do much. Because of |
1933 | /* I think this doesn't really do much. Because of |
1933 | * integer rounding, this only makes any difference if the |
1934 | * integer rounding, this only makes any difference if the |
1934 | * attack level is double the defender level. |
1935 | * attack level is double the defender level. |
1935 | */ |
1936 | */ |
1936 | *dam *= kill_lev / def_lev; |
1937 | *dam *= kill_lev / def_lev; |
1937 | } |
1938 | } |
1938 | } |
1939 | } |
… | |
… | |
2010 | /* here also check for diseases */ |
2011 | /* here also check for diseases */ |
2011 | check_physically_infect (op, hitter); |
2012 | check_physically_infect (op, hitter); |
2012 | break; |
2013 | break; |
2013 | |
2014 | |
2014 | /* Don't need to do anything for: |
2015 | /* Don't need to do anything for: |
2015 | magic, |
2016 | magic, |
2016 | fire, |
2017 | fire, |
2017 | electricity, |
2018 | electricity, |
2018 | cold */ |
2019 | cold */ |
2019 | |
2020 | |
2020 | case ATNR_CONFUSION: |
2021 | case ATNR_CONFUSION: |
2021 | case ATNR_POISON: |
2022 | case ATNR_POISON: |
… | |
… | |
2025 | case ATNR_CANCELLATION: |
2026 | case ATNR_CANCELLATION: |
2026 | case ATNR_DEPLETE: |
2027 | case ATNR_DEPLETE: |
2027 | case ATNR_BLIND: |
2028 | case ATNR_BLIND: |
2028 | { |
2029 | { |
2029 | /* chance for inflicting a special attack depends on the |
2030 | /* chance for inflicting a special attack depends on the |
2030 | * difference between attacker's and defender's level |
2031 | * difference between attacker's and defender's level |
2031 | */ |
2032 | */ |
2032 | int level_diff = min (110, max (0, op->level - hitter->level)); |
2033 | int level_diff = min (110, max (0, op->level - hitter->level)); |
2033 | |
2034 | |
2034 | /* First, only creatures/players with speed can be affected. |
2035 | /* First, only creatures/players with speed can be affected. |
2035 | * Second, just getting hit doesn't mean it always affects |
2036 | * Second, just getting hit doesn't mean it always affects |
2036 | * you. Third, you still get a saving through against the |
2037 | * you. Third, you still get a saving through against the |
2037 | * effect. |
2038 | * effect. |
2038 | */ |
2039 | */ |
2039 | if (op->has_active_speed () |
2040 | if (op->has_active_speed () |
2040 | && (op->flag [FLAG_MONSTER] || op->type == PLAYER) |
2041 | && (op->flag [FLAG_MONSTER] || op->type == PLAYER) |
2041 | && !(rndm (0, (attacknum == ATNR_SLOW ? 6 : 3) - 1)) |
2042 | && !(rndm (0, (attacknum == ATNR_SLOW ? 6 : 3) - 1)) |
2042 | && !did_make_save (op, level_diff, op->resist[attacknum] / 10)) |
2043 | && !did_make_save (op, level_diff, op->resist[attacknum] / 10)) |
… | |
… | |
2217 | * does no damage. */ |
2218 | * does no damage. */ |
2218 | break; |
2219 | break; |
2219 | |
2220 | |
2220 | case ATNR_HOLYWORD: |
2221 | case ATNR_HOLYWORD: |
2221 | { |
2222 | { |
2222 | /* This has already been handled by hit_player, |
2223 | /* This has already been handled by hit_player, |
2223 | * no need to check twice -- DAMN */ |
2224 | * no need to check twice -- DAMN */ |
2224 | object *owner = hitter->owner ? (object *)hitter->owner : hitter; |
2225 | object *owner = hitter->owner ? (object *)hitter->owner : hitter; |
2225 | |
2226 | |
2226 | /* As with turn undead above, give a bonus on the saving throw */ |
2227 | /* As with turn undead above, give a bonus on the saving throw */ |
2227 | if ((op->level + (op->resist[ATNR_HOLYWORD] / 100)) < owner->level + turn_bonus[owner->stats.Wis]) |
2228 | if ((op->level + (op->resist[ATNR_HOLYWORD] / 100)) < owner->level + turn_bonus[owner->stats.Wis]) |