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 (©) 2005,2006,2007,2008,2009,2010 Marc Alexander Lehmann / Robin Redeker / the Deliantra team |
4 | * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012 Marc Alexander Lehmann / Robin Redeker / the Deliantra team |
5 | * Copyright (©) 2003 Mark Wedel & Crossfire Development Team |
5 | * Copyright (©) 2003 Mark Wedel & Crossfire Development Team |
6 | * Copyright (©) 1992 Frank Tore Johansen |
6 | * Copyright (©) 1992 Frank Tore Johansen |
7 | * |
7 | * |
8 | * Deliantra is free software: you can redistribute it and/or modify it under |
8 | * 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 |
9 | * the terms of the Affero GNU General Public License as published by the |
10 | * Free Software Foundation, either version 3 of the License, or (at your |
10 | * Free Software Foundation, either version 3 of the License, or (at your |
11 | * option) any later version. |
11 | * 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 Affero GNU General Public License |
18 | * You should have received a copy of the Affero GNU General Public License |
19 | * and the GNU General Public License along with this program. If not, see |
19 | * and the GNU General Public License along with this program. If not, see |
20 | * <http://www.gnu.org/licenses/>. |
20 | * <http://www.gnu.org/licenses/>. |
21 | * |
21 | * |
22 | * The authors can be reached via e-mail to <support@deliantra.net> |
22 | * The authors can be reached via e-mail to <support@deliantra.net> |
23 | */ |
23 | */ |
24 | |
24 | |
25 | #include <global.h> |
25 | #include <global.h> |
26 | #include <object.h> |
26 | #include <object.h> |
… | |
… | |
281 | |
281 | |
282 | /* For all the stacked objects at this point, attempt a steal */ |
282 | /* For all the stacked objects at this point, attempt a steal */ |
283 | for (; tmp; tmp = next) |
283 | for (; tmp; tmp = next) |
284 | { |
284 | { |
285 | next = tmp->below; |
285 | next = tmp->below; |
286 | /* Minor hack--for multi square beings - make sure we get |
286 | /* Minor hack--for multi square beings - make sure we get |
287 | * the 'head' coz 'tail' objects have no inventory! - b.t. |
287 | * the 'head' coz 'tail' objects have no inventory! - b.t. |
288 | */ |
288 | */ |
289 | if (tmp->head) |
289 | if (tmp->head) |
290 | tmp = tmp->head; |
290 | tmp = tmp->head; |
291 | |
291 | |
292 | if (tmp->type != PLAYER && !tmp->flag [FLAG_MONSTER]) |
292 | if (tmp->type != PLAYER && !tmp->flag [FLAG_MONSTER]) |
293 | continue; |
|
|
294 | |
|
|
295 | /* do not reveal hidden DMs */ |
|
|
296 | if (tmp->type == PLAYER && tmp->flag [FLAG_WIZ] && tmp->contr->hidden) |
|
|
297 | continue; |
293 | continue; |
298 | |
294 | |
299 | if (attempt_steal (tmp, op, skill)) |
295 | if (attempt_steal (tmp, op, skill)) |
300 | { |
296 | { |
301 | if (tmp->type == PLAYER) /* no xp for stealing from another player */ |
297 | if (tmp->type == PLAYER) /* no xp for stealing from another player */ |
… | |
… | |
355 | |
351 | |
356 | int |
352 | int |
357 | pick_lock (object *pl, int dir, object *skill) |
353 | pick_lock (object *pl, int dir, object *skill) |
358 | { |
354 | { |
359 | object *tmp; |
355 | object *tmp; |
360 | int x = pl->x + freearr_x[dir]; |
|
|
361 | int y = pl->y + freearr_y[dir]; |
|
|
362 | |
356 | |
363 | if (!dir) |
357 | if (!dir) |
364 | dir = pl->facing; |
358 | dir = pl->facing; |
365 | |
359 | |
|
|
360 | mapxy pos (pl); pos.move (dir); |
|
|
361 | |
366 | /* For all the stacked objects at this point find a door */ |
362 | /* For all the stacked objects at this point find a door */ |
367 | if (out_of_map (pl->map, x, y)) |
363 | if (!pos.normalise ()) |
368 | { |
364 | { |
369 | pl->failmsg ("There is no lock there."); |
365 | pl->failmsg ("There is no lock there."); |
370 | return 0; |
366 | return 0; |
371 | } |
367 | } |
372 | |
368 | |
373 | for (tmp = GET_MAP_OB (pl->map, x, y); tmp; tmp = tmp->above) |
369 | for (tmp = pos->bot; tmp; tmp = tmp->above) |
374 | if (tmp->type == DOOR || tmp->type == LOCKED_DOOR) |
370 | if (tmp->type == DOOR || tmp->type == LOCKED_DOOR) |
375 | break; |
371 | break; |
376 | |
372 | |
377 | if (!tmp) |
373 | if (!tmp) |
378 | { |
374 | { |
… | |
… | |
519 | } |
515 | } |
520 | |
516 | |
521 | for (tmp = GET_MAP_OB (m, x, y); tmp; tmp = tmp->above) |
517 | for (tmp = GET_MAP_OB (m, x, y); tmp; tmp = tmp->above) |
522 | { |
518 | { |
523 | /* Jump into creature */ |
519 | /* Jump into creature */ |
524 | if (tmp->flag [FLAG_MONSTER] |
520 | if (tmp->flag [FLAG_MONSTER] || tmp->type == PLAYER) |
525 | || (tmp->type == PLAYER && (!tmp->flag [FLAG_WIZ] || !tmp->contr->hidden))) |
|
|
526 | { |
521 | { |
527 | new_draw_info_format (NDI_UNIQUE, 0, pl, "You jump into %s%s.", tmp->type == PLAYER ? "" : "the ", &tmp->name); |
522 | new_draw_info_format (NDI_UNIQUE, 0, pl, "You jump into %s%s.", tmp->type == PLAYER ? "" : "the ", &tmp->name); |
528 | |
523 | |
529 | stop_jump (pl, i, spaces); |
524 | stop_jump (pl, i, spaces); |
530 | |
525 | |
… | |
… | |
587 | } |
582 | } |
588 | |
583 | |
589 | return attempt_jump (pl, dir, spaces, skill); |
584 | return attempt_jump (pl, dir, spaces, skill); |
590 | } |
585 | } |
591 | |
586 | |
592 | /* skill_ident() - this code is supposed to allow players to identify |
587 | /* skill_ident() - this code is supposed to allow players to identify |
593 | * classes of objects with the various "auto-ident" skills. Player must |
588 | * classes of objects with the various "auto-ident" skills. Player must |
594 | * have unidentified objects of the right type in order for the skill |
589 | * have unidentified objects of the right type in order for the skill |
595 | * to work. While multiple classes of objects may be identified, |
590 | * to work. While multiple classes of objects may be identified, |
596 | * this code is kind of yucky -- it would be nice to make it a bit |
591 | * this code is kind of yucky -- it would be nice to make it a bit |
597 | * more generalized. Right now, skill indices are embedded in this routine. |
592 | * more generalized. Right now, skill indices are embedded in this routine. |
598 | * Returns amount of experience gained (on successful ident). |
593 | * Returns amount of experience gained (on successful ident). |
599 | * - b.t. (thomas@astro.psu.edu) |
594 | * - b.t. (thomas@astro.psu.edu) |
600 | */ |
595 | */ |
601 | static int |
596 | static int |
602 | do_skill_detect_curse (object *pl, object *skill) |
597 | do_skill_detect_curse (object *pl, object *skill) |
603 | { |
598 | { |
604 | int success = 0; |
599 | int success = 0; |
… | |
… | |
930 | * of anything better! -b.t. |
925 | * of anything better! -b.t. |
931 | */ |
926 | */ |
932 | int |
927 | int |
933 | singing (object *pl, int dir, object *skill) |
928 | singing (object *pl, int dir, object *skill) |
934 | { |
929 | { |
935 | int i, exp = 0; |
930 | int exp = 0; |
936 | object *tmp; |
931 | object *tmp; |
937 | maptile *m; |
932 | maptile *m; |
938 | sint16 x, y; |
933 | sint16 x, y; |
939 | |
934 | |
940 | if (pl->type != PLAYER) |
935 | if (pl->type != PLAYER) |
… | |
… | |
1213 | |
1208 | |
1214 | /* ok let's meditate! Spell points are regained first, then once |
1209 | /* ok let's meditate! Spell points are regained first, then once |
1215 | * they are maxed we get back hp. Actual incrementing of values |
1210 | * they are maxed we get back hp. Actual incrementing of values |
1216 | * is handled by the do_some_living() (in player.c). This way magical |
1211 | * is handled by the do_some_living() (in player.c). This way magical |
1217 | * bonuses for healing/sp regeneration are included properly |
1212 | * bonuses for healing/sp regeneration are included properly |
1218 | * No matter what, we will eat up some playing time trying to |
1213 | * No matter what, we will eat up some playing time trying to |
1219 | * meditate. (see 'factor' variable for what sets the amount of time) |
1214 | * meditate. (see 'factor' variable for what sets the amount of time) |
1220 | */ |
1215 | */ |
1221 | |
1216 | |
1222 | new_draw_info (NDI_BLACK, 0, pl, "You meditate."); |
1217 | new_draw_info (NDI_BLACK, 0, pl, "You meditate."); |
1223 | |
1218 | |
1224 | if (pl->stats.sp < pl->stats.maxsp) |
1219 | if (pl->stats.sp < pl->stats.maxsp) |
… | |
… | |
1231 | pl->stats.hp++; |
1226 | pl->stats.hp++; |
1232 | pl->last_heal = -1; |
1227 | pl->last_heal = -1; |
1233 | } |
1228 | } |
1234 | } |
1229 | } |
1235 | |
1230 | |
1236 | /* write_note() - this routine allows players to inscribe messages in |
1231 | /* write_note() - this routine allows players to inscribe messages in |
1237 | * ordinary inscribable 'books' (anything that is not a SPELL). b.t. |
1232 | * ordinary inscribable 'books' (anything that is not a SPELL). b.t. |
1238 | */ |
1233 | */ |
1239 | static int |
1234 | static int |
1240 | write_note (object *pl, object *item, const char *msg, object *skill) |
1235 | write_note (object *pl, object *item, const char *msg, object *skill) |
1241 | { |
1236 | { |
… | |
… | |
1286 | return 0; |
1281 | return 0; |
1287 | } |
1282 | } |
1288 | |
1283 | |
1289 | /* write_scroll() - this routine allows players to inscribe spell scrolls |
1284 | /* write_scroll() - this routine allows players to inscribe spell scrolls |
1290 | * of spells which they know. Backfire effects are possible with the |
1285 | * of spells which they know. Backfire effects are possible with the |
1291 | * severity of the backlash correlated with the difficulty of the scroll |
1286 | * severity of the backlash correlated with the difficulty of the scroll |
1292 | * that is attempted. -b.t. thomas@astro.psu.edu |
1287 | * that is attempted. -b.t. thomas@astro.psu.edu |
1293 | */ |
1288 | */ |
1294 | static int |
1289 | static int |
1295 | write_scroll (object *pl, object *scroll, object *skill) |
1290 | write_scroll (object *pl, object *scroll, object *skill) |
1296 | { |
1291 | { |
… | |
… | |
1328 | if (random_roll (0, chosen_spell->level * 4 - 1, pl, PREFER_LOW) < skill->level) |
1323 | if (random_roll (0, chosen_spell->level * 4 - 1, pl, PREFER_LOW) < skill->level) |
1329 | { |
1324 | { |
1330 | object *newscroll = scroll->other_arch->instance (); |
1325 | object *newscroll = scroll->other_arch->instance (); |
1331 | scroll->decrease (); |
1326 | scroll->decrease (); |
1332 | newscroll->nrof = 1; |
1327 | newscroll->nrof = 1; |
|
|
1328 | newscroll->randomitems = 0; // make sure randomitems doesn't destroy the scroll |
1333 | |
1329 | |
1334 | pl->contr->play_sound (sound_find ("inscribe_success")); |
1330 | pl->contr->play_sound (sound_find ("inscribe_success")); |
1335 | |
1331 | |
1336 | if (!confused) |
1332 | if (!confused) |
1337 | { |
1333 | { |
… | |
… | |
1348 | newscroll->level = max (skill->level, chosen_spell->level); |
1344 | newscroll->level = max (skill->level, chosen_spell->level); |
1349 | new_draw_info (NDI_UNIQUE, 0, pl, "In your confused state, you write down some odd spell."); |
1345 | new_draw_info (NDI_UNIQUE, 0, pl, "In your confused state, you write down some odd spell."); |
1350 | } |
1346 | } |
1351 | |
1347 | |
1352 | object *tmp = chosen_spell->clone (); |
1348 | object *tmp = chosen_spell->clone (); |
|
|
1349 | tmp->flag [FLAG_APPLIED] = false; |
1353 | insert_ob_in_ob (tmp, newscroll); |
1350 | insert_ob_in_ob (tmp, newscroll); |
1354 | |
1351 | |
1355 | /* Same code as from treasure.C - so they can better merge. |
1352 | /* Same code as from treasure.C - so they can better merge. |
1356 | * if players want to sell them, so be it. |
1353 | * if players want to sell them, so be it. |
1357 | */ |
1354 | */ |
… | |
… | |
1829 | throw_ob = find_mon_throw_ob (op); |
1826 | throw_ob = find_mon_throw_ob (op); |
1830 | |
1827 | |
1831 | return do_throw (op, part, throw_ob, dir, skill); |
1828 | return do_throw (op, part, throw_ob, dir, skill); |
1832 | } |
1829 | } |
1833 | |
1830 | |
|
|
1831 | static void |
|
|
1832 | give_player_quad_material_for (object *pl, object *ob) |
|
|
1833 | { |
|
|
1834 | if (!ob->flag [FLAG_IS_QUAD] || !ob->other_arch) |
|
|
1835 | return; |
|
|
1836 | |
|
|
1837 | object *t = ob->other_arch->instance (); |
|
|
1838 | pl->insert (t); |
|
|
1839 | } |
|
|
1840 | |
1834 | bool |
1841 | bool |
1835 | skill_mining (object *who, object *tool, object *skill, int dir, const char *string) |
1842 | skill_mining (object *who, object *tool, object *skill, int dir, const char *string) |
1836 | { |
1843 | { |
1837 | if (!who->is_player ()) |
1844 | if (!who->is_player ()) |
1838 | return 0; |
1845 | return 0; |
… | |
… | |
1855 | return 0; |
1862 | return 0; |
1856 | } |
1863 | } |
1857 | |
1864 | |
1858 | mapspace &ms = pos.ms (); |
1865 | mapspace &ms = pos.ms (); |
1859 | |
1866 | |
1860 | for (object *vein = pos.ms ().top; vein; vein = vein->below) |
1867 | for (object *mine_obj = pos.ms ().top; mine_obj; mine_obj = mine_obj->below) |
1861 | if (vein->type == VEIN) |
1868 | if (mine_obj->type == VEIN) |
1862 | { |
1869 | { |
1863 | who->speed_left -= who->speed / tool->speed; |
1870 | who->speed_left -= who->speed / tool->speed; |
1864 | |
1871 | |
1865 | who->play_sound (tool->sound); |
1872 | who->play_sound (tool->sound); |
1866 | |
1873 | |
1867 | if (rndm (100 - vein->stats.ac) > rndm (tool->stats.wc)) |
1874 | if (rndm (100 - mine_obj->stats.ac) > rndm (tool->stats.wc)) |
1868 | who->failmsgf ( |
1875 | who->failmsgf ( |
1869 | "You use your %s.... nothing. " |
1876 | "You use your %s.... nothing. " |
1870 | "H<Try again, perhaps?>", |
1877 | "H<Try again, perhaps?>", |
1871 | &tool->name |
1878 | &tool->name |
1872 | ); |
1879 | ); |
1873 | else if (vein->race != tool->race) |
1880 | else if (mine_obj->race != tool->race) |
1874 | who->failmsgf ( |
1881 | who->failmsgf ( |
1875 | "You use your %s.... but it doesn't work. " |
1882 | "You use your %s.... but it doesn't work. " |
1876 | "H<Maybe you are using the wrong tool?>", |
1883 | "H<Maybe you are using the wrong tool?>", |
1877 | &tool->name |
1884 | &tool->name |
1878 | ); |
1885 | ); |
1879 | else if (!vein->stats.food) |
1886 | else if (!mine_obj->stats.food) |
1880 | who->failmsgf ( |
1887 | who->failmsgf ( |
1881 | "You use your %s.... but there is nothing. " |
1888 | "You use your %s.... but there is nothing. " |
1882 | "H<This space is exhausted, you should try somewhere else.>", |
1889 | "H<This space is exhausted, you should try somewhere else.>", |
1883 | &tool->name |
1890 | &tool->name |
1884 | ); |
1891 | ); |
1885 | else |
1892 | else |
1886 | { |
1893 | { |
1887 | --vein->stats.food; |
1894 | --mine_obj->stats.food; |
1888 | |
1895 | |
1889 | object *ore = vein->other_arch->instance (); |
1896 | object *ore = mine_obj->other_arch->instance (); |
1890 | |
1897 | |
1891 | who->statusmsg (format ( |
1898 | who->statusmsg (format ( |
1892 | "You use your %s.... and find some %s!", |
1899 | "You use your %s.... and find some %s!", |
1893 | &tool->name, &ore->name |
1900 | &tool->name, &ore->name |
1894 | )); |
1901 | )); |
… | |
… | |
1896 | ore->insert_at (who); |
1903 | ore->insert_at (who); |
1897 | |
1904 | |
1898 | return true; |
1905 | return true; |
1899 | } |
1906 | } |
1900 | } |
1907 | } |
|
|
1908 | else if (mine_obj->flag [FLAG_IS_QUAD]) |
|
|
1909 | { |
|
|
1910 | if (mine_obj->flag [FLAG_IS_FLOOR]) |
|
|
1911 | { |
|
|
1912 | maptile *lower_floor = pos.m->tile_available (TILE_DOWN); |
|
|
1913 | |
|
|
1914 | if (!lower_floor) |
|
|
1915 | { |
|
|
1916 | who->failmsgf ( |
|
|
1917 | "Whoops, you failed to remove the %s. H<You may try again.>", |
|
|
1918 | &mine_obj->name |
|
|
1919 | ); |
|
|
1920 | return false; |
|
|
1921 | } |
|
|
1922 | |
|
|
1923 | mapxy below_pos (lower_floor, pos.x, pos.y); |
|
|
1924 | |
|
|
1925 | if (!below_pos.normalise ()) |
|
|
1926 | { |
|
|
1927 | who->failmsgf ( |
|
|
1928 | "Whoops, you failed to remove the %s. H<You may try again.>", |
|
|
1929 | &mine_obj->name |
|
|
1930 | ); |
|
|
1931 | return false; |
|
|
1932 | } |
|
|
1933 | |
|
|
1934 | // first insert open space here: |
|
|
1935 | object *open_space_floor = archetype::get (shstr_quad_open_space); |
|
|
1936 | open_space_floor->stats.hp = pos.x; |
|
|
1937 | open_space_floor->stats.sp = pos.y; |
|
|
1938 | insert_ob_in_map_at (open_space_floor, pos.m, mine_obj, |
|
|
1939 | INS_BELOW_ORIGINATOR, pos.x, pos.y); |
|
|
1940 | |
|
|
1941 | // next we will remove the wall in the lower layer: |
|
|
1942 | mapspace &below_ms = below_pos.ms (); |
|
|
1943 | for (object *quad_obj = below_ms.top; quad_obj; quad_obj = quad_obj->below) |
|
|
1944 | { |
|
|
1945 | if (quad_obj->flag [FLAG_IS_FLOOR]) |
|
|
1946 | break; |
|
|
1947 | |
|
|
1948 | if (quad_obj->flag [FLAG_IS_QUAD]) |
|
|
1949 | { |
|
|
1950 | quad_obj->map->queue_physics_at (quad_obj->x, quad_obj->y); |
|
|
1951 | give_player_quad_material_for (who, quad_obj); |
|
|
1952 | quad_obj->destroy (); |
|
|
1953 | break; |
|
|
1954 | } |
|
|
1955 | } |
|
|
1956 | } |
|
|
1957 | |
|
|
1958 | mine_obj->map->queue_physics_at (mine_obj->x, mine_obj->y); |
|
|
1959 | |
|
|
1960 | // FIXME: there should be chance assigned, like above with veins! |
|
|
1961 | who->play_sound (tool->sound); |
|
|
1962 | give_player_quad_material_for (who, mine_obj); |
|
|
1963 | mine_obj->destroy (); |
|
|
1964 | who->contr->fire_on = 0; // TODO: stopgap, do not remove more than one per keypress |
|
|
1965 | return true; |
|
|
1966 | } |
1901 | |
1967 | |
1902 | return false; |
1968 | return false; |
1903 | } |
1969 | } |
1904 | |
1970 | |