1 | /* |
1 | /* |
2 | CrossFire, A Multiplayer game for X-windows |
2 | * CrossFire, A Multiplayer game |
3 | |
3 | * |
4 | Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team |
4 | * Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team |
5 | Copyright (C) 2003 Mark Wedel & Crossfire Development Team |
5 | * Copyright (C) 2003 Mark Wedel & Crossfire Development Team |
6 | Copyright (C) 1992 Frank Tore Johansen |
6 | * Copyright (C) 1992 Frank Tore Johansen |
7 | |
7 | * |
8 | This program is free software; you can redistribute it and/or modify |
8 | * This program is free software; you can redistribute it and/or modify |
9 | 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 |
10 | the Free Software Foundation; either version 2 of the License, or |
10 | * the Free Software Foundation; either version 2 of the License, or |
11 | (at your option) any later version. |
11 | * (at your option) 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, |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | GNU General Public License for more details. |
16 | * GNU General Public License 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 |
19 | along with this program; if not, write to the Free Software |
19 | * along with this program; if not, write to the Free Software |
20 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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> |
27 | #ifndef __CEXTRACT__ |
|
|
28 | # include <sproto.h> |
27 | #include <sproto.h> |
29 | #endif |
|
|
30 | #include <living.h> |
28 | #include <living.h> |
31 | #include <skills.h> |
29 | #include <skills.h> |
32 | #include <spells.h> |
30 | #include <spells.h> |
33 | #include <book.h> |
31 | #include <book.h> |
34 | |
32 | |
… | |
… | |
42 | return -1; |
40 | return -1; |
43 | |
41 | |
44 | /* Only prohibit stealing if the player does not have a free |
42 | /* Only prohibit stealing if the player does not have a free |
45 | * hand available and in fact does have hands. |
43 | * hand available and in fact does have hands. |
46 | */ |
44 | */ |
47 | if (op->type == PLAYER && op->body_used[BODY_ARMS] <= 0 && op->body_info[BODY_ARMS]) |
45 | if (op->type == PLAYER && op->slot[body_arm].used <= 0 && op->slot[body_arm].info) |
48 | { |
46 | { |
49 | new_draw_info (NDI_UNIQUE, 0, op, "But you have no free hands to steal with!"); |
47 | new_draw_info (NDI_UNIQUE, 0, op, "But you have no free hands to steal with!"); |
50 | return -1; |
48 | return -1; |
51 | } |
49 | } |
52 | |
50 | |
… | |
… | |
262 | /* play_sound("stop! thief!"); kindofthing */ |
260 | /* play_sound("stop! thief!"); kindofthing */ |
263 | } /* if you weren't 100% successful */ |
261 | } /* if you weren't 100% successful */ |
264 | return success ? 1 : 0; |
262 | return success ? 1 : 0; |
265 | } |
263 | } |
266 | |
264 | |
267 | |
|
|
268 | int |
265 | int |
269 | steal (object *op, int dir, object *skill) |
266 | steal (object *op, int dir, object *skill) |
270 | { |
267 | { |
271 | object *tmp, *next; |
268 | object *tmp, *next; |
272 | sint16 x, y; |
269 | sint16 x, y; |
… | |
… | |
808 | new_draw_info (NDI_UNIQUE, 0, pl, "...and learn nothing more."); |
805 | new_draw_info (NDI_UNIQUE, 0, pl, "...and learn nothing more."); |
809 | } |
806 | } |
810 | return success; |
807 | return success; |
811 | } |
808 | } |
812 | |
809 | |
813 | |
|
|
814 | /* players using this skill can 'charm' a monster -- |
810 | /* players using this skill can 'charm' a monster -- |
815 | * into working for them. It can only be used on |
811 | * into working for them. It can only be used on |
816 | * non-special (see below) 'neutral' creatures. |
812 | * non-special (see below) 'neutral' creatures. |
817 | * -b.t. (thomas@astro.psu.edu) |
813 | * -b.t. (thomas@astro.psu.edu) |
818 | */ |
814 | */ |
819 | |
|
|
820 | int |
815 | int |
821 | use_oratory (object *pl, int dir, object *skill) |
816 | use_oratory (object *pl, int dir, object *skill) |
822 | { |
817 | { |
823 | sint16 x = pl->x + freearr_x[dir], y = pl->y + freearr_y[dir]; |
818 | sint16 x = pl->x + freearr_x[dir], y = pl->y + freearr_y[dir]; |
824 | int mflags, chance; |
819 | int mflags, chance; |
… | |
… | |
914 | tmp->stats.exp = 0; |
909 | tmp->stats.exp = 0; |
915 | add_friendly_object (tmp); |
910 | add_friendly_object (tmp); |
916 | tmp->attack_movement = PETMOVE; |
911 | tmp->attack_movement = PETMOVE; |
917 | return calc_skill_exp (pl, tmp, skill); |
912 | return calc_skill_exp (pl, tmp, skill); |
918 | } |
913 | } |
|
|
914 | |
919 | /* Charm failed. Creature may be angry now */ |
915 | /* Charm failed. Creature may be angry now */ |
920 | else if ((skill->level + ((pl->stats.Cha - 10) / 2)) < random_roll (1, 2 * tmp->level, pl, PREFER_LOW)) |
916 | else if ((skill->level + ((pl->stats.Cha - 10) / 2)) < random_roll (1, 2 * tmp->level, pl, PREFER_LOW)) |
921 | { |
917 | { |
922 | new_draw_info_format (NDI_UNIQUE, 0, pl, "Your speech angers the %s!\n", query_name (tmp)); |
918 | new_draw_info_format (NDI_UNIQUE, 0, pl, "Your speech angers the %s!\n", query_name (tmp)); |
923 | if (QUERY_FLAG (tmp, FLAG_FRIENDLY)) |
919 | if (QUERY_FLAG (tmp, FLAG_FRIENDLY)) |
924 | { |
920 | { |
925 | CLEAR_FLAG (tmp, FLAG_FRIENDLY); |
921 | CLEAR_FLAG (tmp, FLAG_FRIENDLY); |
926 | remove_friendly_object (tmp); |
922 | remove_friendly_object (tmp); |
927 | tmp->attack_movement = 0; /* needed? */ |
923 | tmp->attack_movement = 0; /* needed? */ |
928 | } |
924 | } |
|
|
925 | |
929 | CLEAR_FLAG (tmp, FLAG_UNAGGRESSIVE); |
926 | CLEAR_FLAG (tmp, FLAG_UNAGGRESSIVE); |
930 | } |
927 | } |
|
|
928 | |
931 | return 0; /* Fall through - if we get here, we didn't charm anything */ |
929 | return 0; /* Fall through - if we get here, we didn't charm anything */ |
932 | } |
930 | } |
933 | |
931 | |
934 | /* Singing() -this skill allows the player to pacify nearby creatures. |
932 | /* Singing() -this skill allows the player to pacify nearby creatures. |
935 | * There are few limitations on who/what kind of |
933 | * There are few limitations on who/what kind of |
… | |
… | |
1235 | } |
1233 | } |
1236 | |
1234 | |
1237 | /* write_note() - this routine allows players to inscribe messages in |
1235 | /* write_note() - this routine allows players to inscribe messages in |
1238 | * ordinary 'books' (anything that is type BOOK). b.t. |
1236 | * ordinary 'books' (anything that is type BOOK). b.t. |
1239 | */ |
1237 | */ |
1240 | |
|
|
1241 | static int |
1238 | static int |
1242 | write_note (object *pl, object *item, const char *msg, object *skill) |
1239 | write_note (object *pl, object *item, const char *msg, object *skill) |
1243 | { |
1240 | { |
1244 | char buf[1024]; |
1241 | char buf[1024]; |
1245 | object *newBook = NULL; |
1242 | object *newBook = NULL; |
… | |
… | |
1252 | { |
1249 | { |
1253 | new_draw_info (NDI_UNIQUE, 0, pl, "No message to write!"); |
1250 | new_draw_info (NDI_UNIQUE, 0, pl, "No message to write!"); |
1254 | new_draw_info_format (NDI_UNIQUE, 0, pl, "Usage: use_skill %s <message>", &skill->skill); |
1251 | new_draw_info_format (NDI_UNIQUE, 0, pl, "Usage: use_skill %s <message>", &skill->skill); |
1255 | return 0; |
1252 | return 0; |
1256 | } |
1253 | } |
|
|
1254 | |
1257 | if (strcasestr_local (msg, "endmsg")) |
1255 | if (strcasestr_local (msg, "endmsg")) |
1258 | { |
1256 | { |
1259 | new_draw_info (NDI_UNIQUE, 0, pl, "Trying to cheat now are we?"); |
1257 | new_draw_info (NDI_UNIQUE, 0, pl, "Trying to cheat now are we?"); |
1260 | return 0; |
1258 | return 0; |
1261 | } |
1259 | } |
… | |
… | |
1287 | /* This shouldn't be necessary - the object hasn't changed in any |
1285 | /* This shouldn't be necessary - the object hasn't changed in any |
1288 | * visible way |
1286 | * visible way |
1289 | */ |
1287 | */ |
1290 | /* esrv_send_item(pl, item); */ |
1288 | /* esrv_send_item(pl, item); */ |
1291 | } |
1289 | } |
|
|
1290 | |
1292 | new_draw_info_format (NDI_UNIQUE, 0, pl, "You write in the %s.", query_short_name (item)); |
1291 | new_draw_info_format (NDI_UNIQUE, 0, pl, "You write in the %s.", query_short_name (item)); |
1293 | return strlen (msg); |
1292 | return strlen (msg); |
1294 | } |
1293 | } |
1295 | else |
1294 | else |
1296 | new_draw_info_format (NDI_UNIQUE, 0, pl, "Your message won't fit in the %s!", query_short_name (item)); |
1295 | new_draw_info_format (NDI_UNIQUE, 0, pl, "Your message won't fit in the %s!", query_short_name (item)); |
… | |
… | |
1316 | new_draw_info (NDI_UNIQUE, 0, pl, "A spell can only be inscribed into a scroll!"); |
1315 | new_draw_info (NDI_UNIQUE, 0, pl, "A spell can only be inscribed into a scroll!"); |
1317 | return 0; |
1316 | return 0; |
1318 | } |
1317 | } |
1319 | |
1318 | |
1320 | /* Check if we are ready to attempt inscription */ |
1319 | /* Check if we are ready to attempt inscription */ |
1321 | chosen_spell = pl->contr->ranges[range_magic]; |
1320 | chosen_spell = pl->contr->ranged_ob; |
1322 | if (!chosen_spell) |
1321 | if (!chosen_spell || chosen_spell->type != SPELL) |
1323 | { |
1322 | { |
1324 | new_draw_info (NDI_UNIQUE, 0, pl, "You need a spell readied in order to inscribe!"); |
1323 | new_draw_info (NDI_UNIQUE, 0, pl, "You need a spell readied in order to inscribe!"); |
1325 | return 0; |
1324 | return 0; |
1326 | } |
1325 | } |
|
|
1326 | |
1327 | if (SP_level_spellpoint_cost (pl, chosen_spell, SPELL_GRACE) > pl->stats.grace) |
1327 | if (SP_level_spellpoint_cost (pl, chosen_spell, SPELL_GRACE) > pl->stats.grace) |
1328 | { |
1328 | { |
1329 | new_draw_info_format (NDI_UNIQUE, 0, pl, "You don't have enough grace to write a scroll of %s.", &chosen_spell->name); |
1329 | new_draw_info_format (NDI_UNIQUE, 0, pl, "You don't have enough grace to write a scroll of %s.", &chosen_spell->name); |
1330 | return 0; |
1330 | return 0; |
1331 | } |
1331 | } |
|
|
1332 | |
1332 | if (SP_level_spellpoint_cost (pl, chosen_spell, SPELL_MANA) > pl->stats.sp) |
1333 | if (SP_level_spellpoint_cost (pl, chosen_spell, SPELL_MANA) > pl->stats.sp) |
1333 | { |
1334 | { |
1334 | new_draw_info_format (NDI_UNIQUE, 0, pl, "You don't have enough mana to write a scroll of %s.", &chosen_spell->name); |
1335 | new_draw_info_format (NDI_UNIQUE, 0, pl, "You don't have enough mana to write a scroll of %s.", &chosen_spell->name); |
1335 | return 0; |
1336 | return 0; |
1336 | } |
1337 | } |
… | |
… | |
1361 | newscroll = scroll->clone (); |
1362 | newscroll = scroll->clone (); |
1362 | decrease_ob (scroll); |
1363 | decrease_ob (scroll); |
1363 | newscroll->nrof = 1; |
1364 | newscroll->nrof = 1; |
1364 | } |
1365 | } |
1365 | else |
1366 | else |
1366 | { |
|
|
1367 | newscroll = scroll; |
1367 | newscroll = scroll; |
1368 | } |
|
|
1369 | |
1368 | |
1370 | if (!confused) |
1369 | if (!confused) |
1371 | { |
1370 | { |
1372 | newscroll->level = MAX (skill->level, chosen_spell->level); |
1371 | newscroll->level = MAX (skill->level, chosen_spell->level); |
1373 | new_draw_info (NDI_UNIQUE, 0, pl, "You succeed in writing a new scroll."); |
1372 | new_draw_info (NDI_UNIQUE, 0, pl, "You succeed in writing a new scroll."); |
… | |
… | |
1399 | { |
1398 | { |
1400 | /* Remove to correctly merge with other items which may exist in inventory */ |
1399 | /* Remove to correctly merge with other items which may exist in inventory */ |
1401 | newscroll->remove (); |
1400 | newscroll->remove (); |
1402 | esrv_del_item (pl->contr, newscroll->count); |
1401 | esrv_del_item (pl->contr, newscroll->count); |
1403 | } |
1402 | } |
|
|
1403 | |
1404 | newscroll = insert_ob_in_ob (newscroll, pl); |
1404 | newscroll = insert_ob_in_ob (newscroll, pl); |
1405 | esrv_send_item (pl, newscroll); |
1405 | esrv_send_item (pl, newscroll); |
1406 | success = calc_skill_exp (pl, newscroll, skill); |
1406 | success = calc_skill_exp (pl, newscroll, skill); |
1407 | if (!confused) |
1407 | if (!confused) |
1408 | success *= 2; |
1408 | success *= 2; |
… | |
… | |
1451 | if (!params) |
1451 | if (!params) |
1452 | { |
1452 | { |
1453 | params = ""; |
1453 | params = ""; |
1454 | string = params; |
1454 | string = params; |
1455 | } |
1455 | } |
|
|
1456 | |
1456 | skat = get_archetype_by_type_subtype (SKILL, SK_LITERACY); |
1457 | skat = get_archetype_by_type_subtype (SKILL, SK_LITERACY); |
1457 | |
1458 | |
1458 | /* Need to be able to read before we can write! */ |
1459 | /* Need to be able to read before we can write! */ |
1459 | if (!find_skill_by_name (pl, skat->clone.skill)) |
1460 | if (!find_skill_by_name (pl, skat->clone.skill)) |
1460 | { |
1461 | { |
… | |
… | |
1484 | new_draw_info_format (NDI_UNIQUE, 0, pl, "You have no %s to write on", msgtype == BOOK ? "book" : "scroll"); |
1485 | new_draw_info_format (NDI_UNIQUE, 0, pl, "You have no %s to write on", msgtype == BOOK ? "book" : "scroll"); |
1485 | return 0; |
1486 | return 0; |
1486 | } |
1487 | } |
1487 | |
1488 | |
1488 | if (msgtype == SCROLL) |
1489 | if (msgtype == SCROLL) |
1489 | { |
|
|
1490 | return write_scroll (pl, item, skill); |
1490 | return write_scroll (pl, item, skill); |
1491 | } |
|
|
1492 | else if (msgtype == BOOK) |
1491 | else if (msgtype == BOOK) |
1493 | { |
|
|
1494 | return write_note (pl, item, string, skill); |
1492 | return write_note (pl, item, string, skill); |
1495 | } |
1493 | |
1496 | return 0; |
1494 | return 0; |
1497 | } |
1495 | } |
1498 | |
|
|
1499 | |
|
|
1500 | |
1496 | |
1501 | /* find_throw_ob() - if we request an object, then |
1497 | /* find_throw_ob() - if we request an object, then |
1502 | * we search for it in the inventory of the owner (you've |
1498 | * we search for it in the inventory of the owner (you've |
1503 | * got to be carrying something in order to throw it!). |
1499 | * got to be carrying something in order to throw it!). |
1504 | * If we didnt request an object, then the top object in inventory |
1500 | * If we didnt request an object, then the top object in inventory |
1505 | * (that is "throwable", ie no throwing your skills away!) |
1501 | * (that is "throwable", ie no throwing your skills away!) |
1506 | * is the object of choice. Also check to see if object is |
1502 | * is the object of choice. Also check to see if object is |
1507 | * 'throwable' (ie not applied cursed obj, worn, etc). |
1503 | * 'throwable' (ie not applied cursed obj, worn, etc). |
1508 | */ |
1504 | */ |
1509 | |
|
|
1510 | static object * |
1505 | static object * |
1511 | find_throw_ob (object *op, const char *request) |
1506 | find_throw_ob (object *op, const char *request) |
1512 | { |
1507 | { |
1513 | object *tmp; |
1508 | object *tmp; |
1514 | |
1509 | |
… | |
… | |
1586 | |
1581 | |
1587 | /* make_throw_ob() We construct the 'carrier' object in |
1582 | /* make_throw_ob() We construct the 'carrier' object in |
1588 | * which we will insert the object that is being thrown. |
1583 | * which we will insert the object that is being thrown. |
1589 | * This combination becomes the 'thrown object'. -b.t. |
1584 | * This combination becomes the 'thrown object'. -b.t. |
1590 | */ |
1585 | */ |
1591 | |
|
|
1592 | static object * |
1586 | static object * |
1593 | make_throw_ob (object *orig) |
1587 | make_throw_ob (object *orig) |
1594 | { |
1588 | { |
1595 | if (!orig) |
1589 | if (!orig) |
1596 | return NULL; |
1590 | return NULL; |
… | |
… | |
1609 | toss_item->stats.dam = 0; /* default damage */ |
1603 | toss_item->stats.dam = 0; /* default damage */ |
1610 | insert_ob_in_ob (orig, toss_item); |
1604 | insert_ob_in_ob (orig, toss_item); |
1611 | return toss_item; |
1605 | return toss_item; |
1612 | } |
1606 | } |
1613 | |
1607 | |
1614 | |
|
|
1615 | /* do_throw() - op throws any object toss_item. This code |
1608 | /* do_throw() - op throws any object toss_item. This code |
1616 | * was borrowed from fire_bow. |
1609 | * was borrowed from fire_bow. |
1617 | * Returns 1 if skill was successfully used, 0 if not |
1610 | * Returns 1 if skill was successfully used, 0 if not |
1618 | */ |
1611 | */ |
1619 | |
|
|
1620 | static int |
1612 | static int |
1621 | do_throw (object *op, object *part, object *toss_item, int dir, object *skill) |
1613 | do_throw (object *op, object *part, object *toss_item, int dir, object *skill) |
1622 | { |
1614 | { |
1623 | object *throw_ob = toss_item, *left = NULL; |
1615 | object *throw_ob = toss_item, *left = NULL; |
1624 | int eff_str = 0, maxc, str = op->stats.Str, dam = 0; |
1616 | int eff_str = 0, maxc, str = op->stats.Str, dam = 0; |
… | |
… | |
1793 | if (GET_ANIM_ID (throw_ob) && NUM_ANIMATIONS (throw_ob)) |
1785 | if (GET_ANIM_ID (throw_ob) && NUM_ANIMATIONS (throw_ob)) |
1794 | SET_ANIMATION (throw_ob, dir); |
1786 | SET_ANIMATION (throw_ob, dir); |
1795 | } |
1787 | } |
1796 | else |
1788 | else |
1797 | { |
1789 | { |
|
|
1790 | uint16 mat = throw_ob->materials; |
|
|
1791 | |
1798 | /* some materials will adjust properties.. */ |
1792 | /* some materials will adjust properties.. */ |
1799 | if (throw_ob->material & M_LEATHER) |
1793 | if (mat & M_LEATHER) |
1800 | { |
1794 | { |
1801 | throw_ob->stats.dam -= 1; |
1795 | throw_ob->stats.dam -= 1; |
1802 | throw_ob->stats.food -= 10; |
1796 | throw_ob->stats.food -= 10; |
1803 | } |
1797 | } |
1804 | |
1798 | |
1805 | if (throw_ob->material & M_GLASS) |
1799 | if (mat & M_GLASS) |
1806 | throw_ob->stats.food += 60; |
1800 | throw_ob->stats.food += 60; |
1807 | |
1801 | |
1808 | if (throw_ob->material & M_ORGANIC) |
1802 | if (mat & M_ORGANIC) |
1809 | { |
1803 | { |
1810 | throw_ob->stats.dam -= 3; |
1804 | throw_ob->stats.dam -= 3; |
1811 | throw_ob->stats.food += 55; |
1805 | throw_ob->stats.food += 55; |
1812 | } |
1806 | } |
1813 | |
1807 | |
1814 | if (throw_ob->material & M_PAPER || throw_ob->material & M_CLOTH) |
1808 | if (mat & M_PAPER || mat & M_CLOTH) |
1815 | { |
1809 | { |
1816 | throw_ob->stats.dam -= 5; |
1810 | throw_ob->stats.dam -= 5; |
1817 | throw_ob->speed *= 0.8; |
1811 | throw_ob->speed *= 0.8; |
1818 | throw_ob->stats.wc += 3; |
1812 | throw_ob->stats.wc += 3; |
1819 | throw_ob->stats.food -= 30; |
1813 | throw_ob->stats.food -= 30; |