… | |
… | |
24 | #include <assert.h> |
24 | #include <assert.h> |
25 | #include <global.h> |
25 | #include <global.h> |
26 | #include <living.h> |
26 | #include <living.h> |
27 | #include <material.h> |
27 | #include <material.h> |
28 | #include <skills.h> |
28 | #include <skills.h> |
29 | |
|
|
30 | #ifndef __CEXTRACT__ |
|
|
31 | # include <sproto.h> |
|
|
32 | #endif |
|
|
33 | |
|
|
34 | #include <sounds.h> |
29 | #include <sounds.h> |
|
|
30 | #include <sproto.h> |
35 | |
31 | |
36 | typedef struct att_msg_str |
32 | typedef struct att_msg_str |
37 | { |
33 | { |
38 | char *msg1; |
34 | char *msg1; |
39 | char *msg2; |
35 | char *msg2; |
… | |
… | |
84 | materialtype_t *mt; |
80 | materialtype_t *mt; |
85 | |
81 | |
86 | if (op->materialname == NULL) |
82 | if (op->materialname == NULL) |
87 | { |
83 | { |
88 | for (mt = materialt; mt != NULL && mt->next != NULL; mt = mt->next) |
84 | for (mt = materialt; mt != NULL && mt->next != NULL; mt = mt->next) |
89 | if (op->material & mt->material) |
85 | if (op->materials & mt->material) |
90 | break; |
86 | break; |
91 | } |
87 | } |
92 | else |
88 | else |
93 | mt = name_to_material (op->materialname); |
89 | mt = name_to_material (op->materialname); |
94 | |
90 | |
… | |
… | |
375 | * that weak walls have is_alive set, which prevent objects from |
371 | * that weak walls have is_alive set, which prevent objects from |
376 | * passing over/through them. We don't care what type of movement |
372 | * passing over/through them. We don't care what type of movement |
377 | * the wall blocks - if it blocks any type of movement, can't be |
373 | * the wall blocks - if it blocks any type of movement, can't be |
378 | * destroyed right now. |
374 | * destroyed right now. |
379 | */ |
375 | */ |
380 | else if ((tmp->material || tmp->materialname) && op->stats.dam > 0 && !tmp->move_block) |
376 | else if (tmp->materialname && op->stats.dam > 0 && !tmp->move_block) |
381 | { |
377 | { |
382 | save_throw_object (tmp, type, op); |
378 | save_throw_object (tmp, type, op); |
383 | |
379 | |
384 | if (op->destroyed ()) |
380 | if (op->destroyed ()) |
385 | break; |
381 | break; |
… | |
… | |
654 | { |
650 | { |
655 | i = 4; |
651 | i = 4; |
656 | map = hitter->map; |
652 | map = hitter->map; |
657 | if (out_of_map (map, hitter->x, hitter->y)) |
653 | if (out_of_map (map, hitter->x, hitter->y)) |
658 | return; |
654 | return; |
|
|
655 | |
659 | next = GET_MAP_OB (map, hitter->x, hitter->y); |
656 | next = GET_MAP_OB (map, hitter->x, hitter->y); |
660 | if (next) |
657 | if (next) |
661 | while (next) |
658 | while (next) |
662 | { |
659 | { |
663 | if (next->type == SPELL_EFFECT && (next->subtype == SP_EXPLOSION || next->subtype == SP_BULLET || next->subtype == SP_CONE)) |
660 | if (next->type == SPELL_EFFECT && (next->subtype == SP_EXPLOSION || next->subtype == SP_BULLET || next->subtype == SP_CONE)) |
664 | i *= 3; |
661 | i *= 3; |
665 | tmp = next; |
662 | tmp = next; |
666 | next = tmp->above; |
663 | next = tmp->above; |
667 | } |
664 | } |
|
|
665 | |
668 | if (i < 0) |
666 | if (i < 0) |
669 | return; |
667 | return; |
|
|
668 | |
670 | if (rndm (0, i) != 0) |
669 | if (rndm (0, i) != 0) |
671 | return; |
670 | return; |
672 | } |
671 | } |
673 | else if (rndm (0, 5) != 0) |
672 | else if (rndm (0, 5) != 0) |
674 | return; |
673 | return; |
|
|
674 | |
675 | sprintf (buf, "Your %s%s %s.", &hitter->name, buf2, &op->name); |
675 | sprintf (buf, "Your %s%s %s.", &hitter->name, buf2, &op->name); |
676 | play_sound_map (op->map, op->x, op->y, SOUND_PLAYER_HITS4); |
676 | play_sound_map (op->map, op->x, op->y, SOUND_PLAYER_HITS4); |
677 | new_draw_info (NDI_BLACK, 0, hitter->owner, buf); |
677 | new_draw_info (NDI_BLACK, 0, hitter->owner, buf); |
678 | } |
678 | } |
679 | } |
679 | } |
… | |
… | |
779 | if ((hitter->type == PLAYER) && (hitter->casting_time > -1)) |
779 | if ((hitter->type == PLAYER) && (hitter->casting_time > -1)) |
780 | { |
780 | { |
781 | hitter->casting_time = -1; |
781 | hitter->casting_time = -1; |
782 | new_draw_info (NDI_UNIQUE, 0, hitter, "You attacked and lost your spell!"); |
782 | new_draw_info (NDI_UNIQUE, 0, hitter, "You attacked and lost your spell!"); |
783 | } |
783 | } |
|
|
784 | |
784 | if ((op->casting_time > -1) && (hitdam > 0)) |
785 | if ((op->casting_time > -1) && (hitdam > 0)) |
785 | { |
786 | { |
786 | op->casting_time = -1; |
787 | op->casting_time = -1; |
787 | if (op->type == PLAYER) |
788 | if (op->type == PLAYER) |
788 | { |
789 | { |
789 | new_draw_info (NDI_UNIQUE, 0, op, "You were hit and lost your spell!"); |
790 | new_draw_info (NDI_UNIQUE, 0, op, "You were hit and lost your spell!"); |
790 | new_draw_info_format (NDI_ALL | NDI_UNIQUE, 5, NULL, "%s was hit by %s and lost a spell.", &op_name, &hitter->name); |
791 | new_draw_info_format (NDI_ALL | NDI_UNIQUE, 5, NULL, "%s was hit by %s and lost a spell.", &op_name, &hitter->name); |
791 | } |
792 | } |
792 | } |
793 | } |
793 | } |
794 | } |
|
|
795 | |
794 | if (!simple_attack) |
796 | if (!simple_attack) |
795 | { |
797 | { |
796 | /* If you hit something, the victim should *always* wake up. |
798 | /* If you hit something, the victim should *always* wake up. |
797 | * Before, invisible hitters could avoid doing this. |
799 | * Before, invisible hitters could avoid doing this. |
798 | * -b.t. */ |
800 | * -b.t. */ |
… | |
… | |
869 | } |
871 | } |
870 | |
872 | |
871 | int |
873 | int |
872 | attack_ob (object *op, object *hitter) |
874 | attack_ob (object *op, object *hitter) |
873 | { |
875 | { |
874 | |
|
|
875 | if (hitter->head) |
|
|
876 | hitter = hitter->head; |
876 | hitter = hitter->head_ (); |
|
|
877 | |
877 | return attack_ob_simple (op, hitter, hitter->stats.dam, hitter->stats.wc); |
878 | return attack_ob_simple (op, hitter, hitter->stats.dam, hitter->stats.wc); |
878 | } |
879 | } |
879 | |
880 | |
880 | /* op is the arrow, tmp is what is stopping the arrow. |
881 | /* op is the arrow, tmp is what is stopping the arrow. |
881 | * |
882 | * |
… | |
… | |
1008 | insert_ob_in_ob (hitter, container); |
1009 | insert_ob_in_ob (hitter, container); |
1009 | } |
1010 | } |
1010 | |
1011 | |
1011 | return op; |
1012 | return op; |
1012 | } |
1013 | } |
1013 | |
|
|
1014 | |
1014 | |
1015 | void |
1015 | void |
1016 | tear_down_wall (object *op) |
1016 | tear_down_wall (object *op) |
1017 | { |
1017 | { |
1018 | int perc = 0; |
1018 | int perc = 0; |
… | |
… | |
1203 | if (tmp->invisible) |
1203 | if (tmp->invisible) |
1204 | continue; |
1204 | continue; |
1205 | if (!QUERY_FLAG (tmp, FLAG_APPLIED) || (tmp->resist[ATNR_ACID] >= 10)) |
1205 | if (!QUERY_FLAG (tmp, FLAG_APPLIED) || (tmp->resist[ATNR_ACID] >= 10)) |
1206 | /* >= 10% acid res. on items will protect these */ |
1206 | /* >= 10% acid res. on items will protect these */ |
1207 | continue; |
1207 | continue; |
1208 | if (!(tmp->material & M_IRON)) |
1208 | if (!(tmp->materials & M_IRON)) |
1209 | continue; |
1209 | continue; |
1210 | if (tmp->magic < -4) /* Let's stop at -5 */ |
1210 | if (tmp->magic < -4) /* Let's stop at -5 */ |
1211 | continue; |
1211 | continue; |
1212 | if (tmp->type == RING |
1212 | if (tmp->type == RING |
1213 | /* removed boots and gloves from exclusion list in PR */ |
1213 | /* removed boots and gloves from exclusion list in PR */ |
… | |
… | |
1438 | return maxdam; |
1438 | return maxdam; |
1439 | } |
1439 | } |
1440 | |
1440 | |
1441 | if (QUERY_FLAG (op, FLAG_FRIENDLY) && op->type != PLAYER) |
1441 | if (QUERY_FLAG (op, FLAG_FRIENDLY) && op->type != PLAYER) |
1442 | { |
1442 | { |
1443 | remove_friendly_object (op); |
|
|
1444 | |
|
|
1445 | if (op->owner && op->owner->type == PLAYER && op->owner->contr->ranges[range_golem] == op) |
|
|
1446 | op->owner->contr->ranges[range_golem] = 0; |
|
|
1447 | |
|
|
1448 | op->destroy (); |
1443 | op->destroy (); |
1449 | return maxdam; |
1444 | return maxdam; |
1450 | } |
1445 | } |
1451 | |
1446 | |
1452 | /* Now lets start dealing with experience we get for killing something */ |
1447 | /* Now lets start dealing with experience we get for killing something */ |
… | |
… | |
1529 | skill = owner->current_weapon->skill; |
1524 | skill = owner->current_weapon->skill; |
1530 | else |
1525 | else |
1531 | LOG (llevError, "kill_object - unable to find skill that killed monster\n"); |
1526 | LOG (llevError, "kill_object - unable to find skill that killed monster\n"); |
1532 | |
1527 | |
1533 | /* We have the skill we want to credit to - now find the object this goes |
1528 | /* We have the skill we want to credit to - now find the object this goes |
1534 | * to. Make sure skop is an actual skill, and not a skill tool! |
1529 | * to. Make sure skop is an actual skill, and not a skill tool! |
1535 | */ |
1530 | */ |
1536 | if ((!skop || skop->type != SKILL) && skill) |
1531 | if ((!skop || skop->type != SKILL) && skill) |
1537 | { |
1532 | { |
1538 | int i; |
1533 | int i; |
1539 | |
1534 | |
… | |
… | |
1602 | if (owner->type != PLAYER || owner->contr->party == NULL) |
1597 | if (owner->type != PLAYER || owner->contr->party == NULL) |
1603 | change_exp (owner, exp, skill, 0); |
1598 | change_exp (owner, exp, skill, 0); |
1604 | else |
1599 | else |
1605 | { |
1600 | { |
1606 | int shares = 0, count = 0; |
1601 | int shares = 0, count = 0; |
1607 | player *pl; |
|
|
1608 | partylist *party = owner->contr->party; |
1602 | partylist *party = owner->contr->party; |
1609 | |
1603 | |
1610 | add_kill_to_party (party, query_name (owner), query_name (op), exp); |
1604 | add_kill_to_party (party, query_name (owner), query_name (op), exp); |
1611 | |
1605 | |
1612 | for_all_players (pl) |
1606 | for_all_players (pl) |
… | |
… | |
1671 | } |
1665 | } |
1672 | |
1666 | |
1673 | /* Find out if this is friendly fire (PVP and attacker is peaceful) or not |
1667 | /* Find out if this is friendly fire (PVP and attacker is peaceful) or not |
1674 | * Returns 0 this is not friendly fire |
1668 | * Returns 0 this is not friendly fire |
1675 | */ |
1669 | */ |
1676 | |
|
|
1677 | int |
1670 | int |
1678 | friendly_fire (object *op, object *hitter) |
1671 | friendly_fire (object *op, object *hitter) |
1679 | { |
1672 | { |
1680 | object *owner; |
1673 | object *owner; |
1681 | int friendlyfire; |
1674 | int friendlyfire; |
… | |
… | |
1738 | object *owner = hitter->owner; |
1731 | object *owner = hitter->owner; |
1739 | |
1732 | |
1740 | if (!owner) |
1733 | if (!owner) |
1741 | owner = hitter; |
1734 | owner = hitter; |
1742 | |
1735 | |
1743 | if (owner->type == PLAYER && (!op_on_battleground (op, 0, 0) && (op->contr->peaceful || owner->contr->peaceful)) && op != owner) |
1736 | if (owner->type == PLAYER |
|
|
1737 | && (!op_on_battleground (op, 0, 0) |
|
|
1738 | && (op->contr->peaceful || owner->contr->peaceful)) |
|
|
1739 | && op != owner) |
1744 | return 0; |
1740 | return 0; |
1745 | } |
1741 | } |
1746 | #endif |
1742 | #endif |
1747 | |
1743 | |
1748 | if (body_attack) |
1744 | if (body_attack) |
… | |
… | |
1782 | if (!QUERY_FLAG (op, FLAG_ALIVE) || op->stats.hp < 0) |
1778 | if (!QUERY_FLAG (op, FLAG_ALIVE) || op->stats.hp < 0) |
1783 | { |
1779 | { |
1784 | /* FIXME: If a player is killed by a rune in a door, the |
1780 | /* FIXME: If a player is killed by a rune in a door, the |
1785 | * destroyed() check above doesn't return, and might get here. |
1781 | * destroyed() check above doesn't return, and might get here. |
1786 | */ |
1782 | */ |
|
|
1783 | |
|
|
1784 | /* FIXME: This for example happens when a dead door is on a mover and |
|
|
1785 | gets it's speed_left raised on each mover-tick. |
|
|
1786 | Doors are removed in a kinda funny way by giving them speed and speed_left |
|
|
1787 | and waiting for that to run out. |
|
|
1788 | */ |
1787 | LOG (llevDebug, "victim %s already dead in hit_player()\n", op->debug_desc ()); |
1789 | LOG (llevDebug, "victim %s (%d) already dead in hit_player()\n", op->debug_desc (), op->stats.hp); |
1788 | return 0; |
1790 | return 0; |
1789 | } |
1791 | } |
1790 | |
1792 | |
1791 | #ifdef ATTACK_DEBUG |
1793 | #ifdef ATTACK_DEBUG |
1792 | LOG (llevDebug, "hit player: attacktype %d, dam %d\n", type, dam); |
1794 | LOG (llevDebug, "hit player: attacktype %d, dam %d\n", type, dam); |
… | |
… | |
1899 | |
1901 | |
1900 | #ifdef ATTACK_DEBUG |
1902 | #ifdef ATTACK_DEBUG |
1901 | LOG (llevDebug, "Attacktype %d did %d damage\n", type, maxdam); |
1903 | LOG (llevDebug, "Attacktype %d did %d damage\n", type, maxdam); |
1902 | #endif |
1904 | #endif |
1903 | |
1905 | |
|
|
1906 | // for now, only do this for active objects, otherwise they |
|
|
1907 | // keep a refcount for a long time and I see no usefulness |
|
|
1908 | // for an non-active objetc to know its enemy. |
|
|
1909 | if (op->active) |
1904 | if (hitter->owner) |
1910 | if (hitter->owner) |
1905 | op->enemy = hitter->owner; |
1911 | op->enemy = hitter->owner; |
1906 | else if (QUERY_FLAG (hitter, FLAG_ALIVE)) |
1912 | else if (QUERY_FLAG (hitter, FLAG_ALIVE)) |
1907 | op->enemy = hitter; |
1913 | op->enemy = hitter; |
1908 | |
1914 | |
1909 | if (QUERY_FLAG (op, FLAG_UNAGGRESSIVE) && op->type != PLAYER) |
1915 | if (QUERY_FLAG (op, FLAG_UNAGGRESSIVE) && op->type != PLAYER) |
1910 | { |
1916 | { |
1911 | /* The unaggressives look after themselves 8) */ |
1917 | /* The unaggressives look after themselves 8) */ |
1912 | CLEAR_FLAG (op, FLAG_UNAGGRESSIVE); |
1918 | CLEAR_FLAG (op, FLAG_UNAGGRESSIVE); |
… | |
… | |
1949 | /* Used to be ghosthit removal - we now use the ONE_HIT flag. Note |
1955 | /* Used to be ghosthit removal - we now use the ONE_HIT flag. Note |
1950 | * that before if the player was immune to ghosthit, the monster |
1956 | * that before if the player was immune to ghosthit, the monster |
1951 | * remained - that is no longer the case. |
1957 | * remained - that is no longer the case. |
1952 | */ |
1958 | */ |
1953 | if (QUERY_FLAG (hitter, FLAG_ONE_HIT)) |
1959 | if (QUERY_FLAG (hitter, FLAG_ONE_HIT)) |
1954 | { |
|
|
1955 | if (QUERY_FLAG (hitter, FLAG_FRIENDLY)) |
|
|
1956 | remove_friendly_object (hitter); |
|
|
1957 | |
|
|
1958 | hitter->destroy (); |
1960 | hitter->destroy (); |
1959 | } |
1961 | |
1960 | /* Lets handle creatures that are splitting now */ |
1962 | /* Lets handle creatures that are splitting now */ |
1961 | else if (type & AT_PHYSICAL && !QUERY_FLAG (op, FLAG_FREED) && QUERY_FLAG (op, FLAG_SPLITTING)) |
1963 | else if (type & AT_PHYSICAL && !QUERY_FLAG (op, FLAG_FREED) && QUERY_FLAG (op, FLAG_SPLITTING)) |
1962 | { |
1964 | { |
1963 | int i; |
1965 | int i; |
1964 | int friendly = QUERY_FLAG (op, FLAG_FRIENDLY); |
1966 | int friendly = QUERY_FLAG (op, FLAG_FRIENDLY); |
… | |
… | |
2190 | op->speed_left = (float) -(FABS (op->speed) * max); |
2192 | op->speed_left = (float) -(FABS (op->speed) * max); |
2191 | |
2193 | |
2192 | /* tmp->stats.food = (signed short) (max/FABS(op->speed)); */ |
2194 | /* tmp->stats.food = (signed short) (max/FABS(op->speed)); */ |
2193 | } |
2195 | } |
2194 | |
2196 | |
2195 | |
|
|
2196 | /* Attempts to kill 'op'. hitter is the attack object, dam is |
2197 | /* Attempts to kill 'op'. hitter is the attack object, dam is |
2197 | * the computed damaged. |
2198 | * the computed damaged. |
2198 | */ |
2199 | */ |
2199 | void |
2200 | void |
2200 | deathstrike_player (object *op, object *hitter, int *dam) |
2201 | deathstrike_player (object *op, object *hitter, int *dam) |
… | |
… | |
2217 | if (def_lev < 1) |
2218 | if (def_lev < 1) |
2218 | { |
2219 | { |
2219 | LOG (llevError, "BUG: arch %s, name %s with level < 1\n", &op->arch->name, &op->name); |
2220 | LOG (llevError, "BUG: arch %s, name %s with level < 1\n", &op->arch->name, &op->name); |
2220 | def_lev = 1; |
2221 | def_lev = 1; |
2221 | } |
2222 | } |
|
|
2223 | |
2222 | atk_lev = (hitter->chosen_skill ? hitter->chosen_skill->level : hitter->level) / 2; |
2224 | atk_lev = (hitter->chosen_skill ? hitter->chosen_skill->level : hitter->level) / 2; |
2223 | /* LOG(llevDebug,"Deathstrike - attack level %d, defender level %d\n", |
2225 | /* LOG(llevDebug,"Deathstrike - attack level %d, defender level %d\n", |
2224 | atk_lev, def_lev); */ |
2226 | atk_lev, def_lev); */ |
2225 | |
2227 | |
2226 | if (atk_lev >= def_lev) |
2228 | if (atk_lev >= def_lev) |
… | |
… | |
2241 | */ |
2243 | */ |
2242 | *dam *= kill_lev / def_lev; |
2244 | *dam *= kill_lev / def_lev; |
2243 | } |
2245 | } |
2244 | } |
2246 | } |
2245 | else |
2247 | else |
2246 | { |
|
|
2247 | *dam = 0; /* no harm done */ |
2248 | *dam = 0; /* no harm done */ |
2248 | } |
|
|
2249 | } |
2249 | } |
2250 | |
2250 | |
2251 | /* thrown_item_effect() - handles any special effects of thrown |
2251 | /* thrown_item_effect() - handles any special effects of thrown |
2252 | * items (like attacking living creatures--a potion thrown at a |
2252 | * items (like attacking living creatures--a potion thrown at a |
2253 | * monster). |
2253 | * monster). |
… | |
… | |
2357 | #endif |
2357 | #endif |
2358 | |
2358 | |
2359 | return adjust; |
2359 | return adjust; |
2360 | } |
2360 | } |
2361 | |
2361 | |
2362 | |
|
|
2363 | /* determine if the object is an 'aimed' missile */ |
2362 | /* determine if the object is an 'aimed' missile */ |
2364 | int |
2363 | int |
2365 | is_aimed_missile (object *op) |
2364 | is_aimed_missile (object *op) |
2366 | { |
2365 | { |
2367 | |
2366 | |
… | |
… | |
2373 | if (op->type == ARROW || op->type == THROWN_OBJ) |
2372 | if (op->type == ARROW || op->type == THROWN_OBJ) |
2374 | return 1; |
2373 | return 1; |
2375 | else if (op->type == SPELL_EFFECT && (op->subtype == SP_BULLET || op->subtype == SP_EXPLOSION)) |
2374 | else if (op->type == SPELL_EFFECT && (op->subtype == SP_BULLET || op->subtype == SP_EXPLOSION)) |
2376 | return 1; |
2375 | return 1; |
2377 | } |
2376 | } |
|
|
2377 | |
2378 | return 0; |
2378 | return 0; |
2379 | } |
2379 | } |