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 Marc Alexander Lehmann / Robin Redeker / the Deliantra team |
4 | * Copyright (©) 2005,2006,2007,2008,2009,2010 Marc Alexander Lehmann / Robin Redeker / the Deliantra team |
5 | * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team |
5 | * Copyright (©) 2002 Mark Wedel & Crossfire Development Team |
6 | * Copyright (©) 1992,2007 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. |
… | |
… | |
277 | static int |
277 | static int |
278 | move_randomly (object *op) |
278 | move_randomly (object *op) |
279 | { |
279 | { |
280 | /* Give up to 15 chances for a monster to move randomly */ |
280 | /* Give up to 15 chances for a monster to move randomly */ |
281 | for (int i = 0; i < 15; i++) |
281 | for (int i = 0; i < 15; i++) |
282 | if (move_object (op, rndm (8) + 1)) |
282 | if (op->move (rndm (8) + 1)) |
283 | return 1; |
283 | return 1; |
284 | |
284 | |
285 | return 0; |
285 | return 0; |
286 | } |
286 | } |
287 | |
287 | |
… | |
… | |
433 | switch (tmp->type) |
433 | switch (tmp->type) |
434 | { |
434 | { |
435 | case T_HANDLE: |
435 | case T_HANDLE: |
436 | case TRIGGER: |
436 | case TRIGGER: |
437 | if (monster->will_apply & 1) |
437 | if (monster->will_apply & 1) |
438 | manual_apply (monster, tmp, 0); |
438 | monster->apply (tmp); |
439 | break; |
439 | break; |
440 | |
440 | |
441 | case TREASURE: |
441 | case TREASURE: |
442 | if (monster->will_apply & 2) |
442 | if (monster->will_apply & 2) |
443 | manual_apply (monster, tmp, 0); |
443 | monster->apply (tmp); |
444 | break; |
444 | break; |
445 | |
445 | |
446 | } |
446 | } |
447 | if (QUERY_FLAG (tmp, FLAG_IS_FLOOR)) |
447 | if (QUERY_FLAG (tmp, FLAG_IS_FLOOR)) |
448 | break; |
448 | break; |
… | |
… | |
670 | |
670 | |
671 | /* should only be applying this item, not unapplying it. |
671 | /* should only be applying this item, not unapplying it. |
672 | * also, ignore status of curse so they can take off old armour. |
672 | * also, ignore status of curse so they can take off old armour. |
673 | * monsters have some advantages after all. |
673 | * monsters have some advantages after all. |
674 | */ |
674 | */ |
675 | manual_apply (mon, item, AP_APPLY | AP_IGNORE_CURSE); |
675 | mon->apply (item, AP_APPLY | AP_IGNORE_CURSE); |
676 | } |
676 | } |
677 | |
677 | |
678 | static int |
678 | static int |
679 | can_hit (object *ob1, object *ob2, rv_vector * rv) |
679 | can_hit (object *ob1, object *ob2, rv_vector * rv) |
680 | { |
680 | { |
… | |
… | |
786 | static int circle[12] = { 3, 3, 4, 5, 5, 6, 7, 7, 8, 1, 1, 2 }; |
786 | static int circle[12] = { 3, 3, 4, 5, 5, 6, 7, 7, 8, 1, 1, 2 }; |
787 | |
787 | |
788 | if (++ob->move_status > 11) |
788 | if (++ob->move_status > 11) |
789 | ob->move_status = 0; |
789 | ob->move_status = 0; |
790 | |
790 | |
791 | if (!(move_object (ob, circle[ob->move_status]))) |
791 | if (!(ob->move (circle[ob->move_status]))) |
792 | move_object (ob, rndm (8) + 1); |
792 | ob->move (rndm (8) + 1); |
793 | } |
793 | } |
794 | |
794 | |
795 | static void |
795 | static void |
796 | circ2_move (object *ob) |
796 | circ2_move (object *ob) |
797 | { |
797 | { |
798 | static int circle[20] = { 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7, 7, 8, 8, 1, 1, 1, 2, 2 }; |
798 | static int circle[20] = { 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7, 7, 8, 8, 1, 1, 1, 2, 2 }; |
799 | |
799 | |
800 | if (++ob->move_status > 19) |
800 | if (++ob->move_status > 19) |
801 | ob->move_status = 0; |
801 | ob->move_status = 0; |
802 | |
802 | |
803 | if (!(move_object (ob, circle[ob->move_status]))) |
803 | if (!(ob->move (circle[ob->move_status]))) |
804 | move_object (ob, rndm (8) + 1); |
804 | ob->move (rndm (8) + 1); |
805 | } |
805 | } |
806 | |
806 | |
807 | static void |
807 | static void |
808 | pace_movev (object *ob) |
808 | pace_movev (object *ob) |
809 | { |
809 | { |
810 | if (ob->move_status++ > 6) |
810 | if (ob->move_status++ > 6) |
811 | ob->move_status = 0; |
811 | ob->move_status = 0; |
812 | |
812 | |
813 | if (ob->move_status < 4) |
813 | if (ob->move_status < 4) |
814 | move_object (ob, 5); |
814 | ob->move (5); |
815 | else |
815 | else |
816 | move_object (ob, 1); |
816 | ob->move (1); |
817 | } |
817 | } |
818 | |
818 | |
819 | static void |
819 | static void |
820 | pace_moveh (object *ob) |
820 | pace_moveh (object *ob) |
821 | { |
821 | { |
822 | if (ob->move_status++ > 6) |
822 | if (ob->move_status++ > 6) |
823 | ob->move_status = 0; |
823 | ob->move_status = 0; |
824 | |
824 | |
825 | if (ob->move_status < 4) |
825 | if (ob->move_status < 4) |
826 | move_object (ob, 3); |
826 | ob->move (3); |
827 | else |
827 | else |
828 | move_object (ob, 7); |
828 | ob->move (7); |
829 | } |
829 | } |
830 | |
830 | |
831 | static void |
831 | static void |
832 | pace2_movev (object *ob) |
832 | pace2_movev (object *ob) |
833 | { |
833 | { |
834 | if (ob->move_status++ > 16) |
834 | if (ob->move_status++ > 16) |
835 | ob->move_status = 0; |
835 | ob->move_status = 0; |
836 | |
836 | |
837 | if (ob->move_status < 6) |
837 | if (ob->move_status < 6) |
838 | move_object (ob, 5); |
838 | ob->move (5); |
839 | else if (ob->move_status < 8) |
839 | else if (ob->move_status < 8) |
840 | return; |
840 | return; |
841 | else if (ob->move_status < 13) |
841 | else if (ob->move_status < 13) |
842 | move_object (ob, 1); |
842 | ob->move (1); |
843 | else |
843 | else |
844 | return; |
844 | return; |
845 | } |
845 | } |
846 | |
846 | |
847 | static void |
847 | static void |
… | |
… | |
849 | { |
849 | { |
850 | if (ob->move_status++ > 16) |
850 | if (ob->move_status++ > 16) |
851 | ob->move_status = 0; |
851 | ob->move_status = 0; |
852 | |
852 | |
853 | if (ob->move_status < 6) |
853 | if (ob->move_status < 6) |
854 | move_object (ob, 3); |
854 | ob->move (3); |
855 | else if (ob->move_status < 8) |
855 | else if (ob->move_status < 8) |
856 | return; |
856 | return; |
857 | else if (ob->move_status < 13) |
857 | else if (ob->move_status < 13) |
858 | move_object (ob, 7); |
858 | ob->move (7); |
859 | else |
859 | else |
860 | return; |
860 | return; |
861 | } |
861 | } |
862 | |
862 | |
863 | static void |
863 | static void |
864 | rand_move (object *ob) |
864 | rand_move (object *ob) |
865 | { |
865 | { |
866 | if (ob->move_status < 1 || ob->move_status > 8 || !(move_object (ob, ob->move_status || !(rndm (9))))) |
866 | if (ob->move_status < 1 || ob->move_status > 8 || !(ob->move (ob->move_status || !(rndm (9))))) |
867 | for (int i = 0; i < 5; i++) |
867 | for (int i = 0; i < 5; i++) |
868 | if (move_object (ob, ob->move_status = rndm (8) + 1)) |
868 | if (ob->move (ob->move_status = rndm (8) + 1)) |
869 | return; |
869 | return; |
870 | } |
870 | } |
871 | |
871 | |
872 | #define MAX_KNOWN_SPELLS 20 |
872 | #define MAX_KNOWN_SPELLS 20 |
873 | |
873 | |
… | |
… | |
1060 | } |
1060 | } |
1061 | |
1061 | |
1062 | if (QUERY_FLAG (head, FLAG_CONFUSED)) |
1062 | if (QUERY_FLAG (head, FLAG_CONFUSED)) |
1063 | dir = absdir (dir + rndm (3) + rndm (3) - 2); |
1063 | dir = absdir (dir + rndm (3) + rndm (3) - 2); |
1064 | |
1064 | |
|
|
1065 | object *new_skill = 0; |
|
|
1066 | |
1065 | /* skill selection - monster will use the next unused skill. |
1067 | // skill selection - monster will use the last unused skill |
1066 | * well...the following scenario will allow the monster to |
1068 | // and rotate, eventually cycling through all skills. |
1067 | * toggle between 2 skills. One day it would be nice to make |
|
|
1068 | * more skills available to monsters. |
|
|
1069 | */ |
|
|
1070 | for (skill = head->inv; skill; skill = skill->below) |
1069 | for (skill = head->inv; skill; skill = skill->below) |
1071 | if (skill->type == SKILL && skill != head->chosen_skill) |
1070 | if (skill->type == SKILL && skill != head->chosen_skill) |
1072 | { |
1071 | new_skill = skill; |
|
|
1072 | |
|
|
1073 | if (new_skill) |
1073 | head->chosen_skill = skill; |
1074 | splay (head->chosen_skill = new_skill); |
1074 | break; |
|
|
1075 | } |
|
|
1076 | |
|
|
1077 | if (!skill && !head->chosen_skill) |
1075 | else if (!head->chosen_skill) |
1078 | { |
1076 | { |
1079 | LOG (llevDebug, "Error: Monster %s (%d) has FLAG_READY_SKILL without skill.\n", &head->name, head->count); |
1077 | LOG (llevDebug, "Error: Monster %s (%d) has FLAG_READY_SKILL without skill.\n", &head->name, head->count); |
1080 | CLEAR_FLAG (head, FLAG_READY_SKILL); |
1078 | CLEAR_FLAG (head, FLAG_READY_SKILL); |
1081 | return 0; |
1079 | return 0; |
1082 | } |
1080 | } |
… | |
… | |
1288 | { |
1286 | { |
1289 | /* last heal is in funny units. Dividing by speed puts |
1287 | /* last heal is in funny units. Dividing by speed puts |
1290 | * the regeneration rate on a basis of time instead of |
1288 | * the regeneration rate on a basis of time instead of |
1291 | * #moves the monster makes. The scaling by 8 is |
1289 | * #moves the monster makes. The scaling by 8 is |
1292 | * to capture 8th's of a hp fraction regens |
1290 | * to capture 8th's of a hp fraction regens |
1293 | * |
|
|
1294 | * Cast to sint32 before comparing to maxhp since otherwise an (sint16) |
|
|
1295 | * overflow might produce monsters with negative hp. |
|
|
1296 | */ |
1291 | */ |
1297 | |
1292 | uint32_t last_heal = op->last_heal + op->stats.Con * 8 / op->speed; |
1298 | op->last_heal += (int) ((float) (8 * op->stats.Con) / op->speed); |
|
|
1299 | op->stats.hp = min ((sint32) op->stats.hp + op->last_heal / 32, op->stats.maxhp); /* causes Con/4 hp/tick */ |
1293 | op->stats.hp = min (op->stats.hp + last_heal / 32, op->stats.maxhp); /* causes Con/4 hp/tick */ |
1300 | op->last_heal %= 32; |
1294 | op->last_heal = last_heal % 32; |
1301 | |
1295 | |
1302 | /* So if the monster has gained enough HP that they are no longer afraid */ |
1296 | /* So if the monster has gained enough HP that they are no longer afraid */ |
1303 | if (QUERY_FLAG (op, FLAG_RUN_AWAY) && op->stats.hp >= (signed short)(((float)op->run_away / 100.f) * (float)op->stats.maxhp)) |
1297 | if (op->flag [FLAG_RUN_AWAY] && op->stats.hp * 100 >= op->stats.maxhp * op->run_away) |
1304 | CLEAR_FLAG (op, FLAG_RUN_AWAY); |
1298 | op->flag [FLAG_RUN_AWAY] = false; |
1305 | |
|
|
1306 | if (op->stats.hp > op->stats.maxhp) |
|
|
1307 | op->stats.hp = op->stats.maxhp; |
|
|
1308 | } |
1299 | } |
1309 | |
1300 | |
1310 | /* generate sp, if applicable */ |
1301 | /* generate sp, if applicable */ |
1311 | if (op->stats.Pow > 0 && op->stats.sp < op->stats.maxsp) |
1302 | if (op->stats.Pow > 0 && op->stats.sp < op->stats.maxsp) |
1312 | { |
1303 | { |
1313 | /* last_sp is in funny units. Dividing by speed puts |
1304 | /* last_sp is in funny units. Dividing by speed puts |
1314 | * the regeneration rate on a basis of time instead of |
1305 | * the regeneration rate on a basis of time instead of |
1315 | * #moves the monster makes. The scaling by 8 is |
1306 | * #moves the monster makes. The scaling by 8 is |
1316 | * to capture 8th's of a sp fraction regens |
1307 | * to capture 8th's of a sp fraction regens |
1317 | * |
|
|
1318 | * Cast to sint32 before comparing to maxhp since otherwise an (sint16) |
|
|
1319 | * overflow might produce monsters with negative sp. |
|
|
1320 | */ |
1308 | */ |
1321 | |
1309 | |
1322 | op->last_sp += (int) ((float) (8 * op->stats.Pow) / op->speed); |
1310 | uint32_t last_sp = op->last_sp + op->stats.Pow * 8 / op->speed; |
1323 | op->stats.sp = min (op->stats.sp + op->last_sp / 128, op->stats.maxsp); /* causes Pow/16 sp/tick */ |
1311 | op->stats.sp = min (op->stats.sp + last_sp / 128, op->stats.maxsp); /* causes Pow/16 sp/tick */ |
1324 | op->last_sp %= 128; |
1312 | op->last_sp = last_sp % 128; |
1325 | } |
1313 | } |
1326 | |
1314 | |
1327 | /* this should probably get modified by many more values. |
1315 | /* this should probably get modified by many more values. |
1328 | * (eg, creatures resistance to fear, level, etc. ) |
1316 | * (eg, creatures resistance to fear, level, etc. ) |
1329 | */ |
1317 | */ |
… | |
… | |
1580 | if (!dir) |
1568 | if (!dir) |
1581 | return 0; |
1569 | return 0; |
1582 | |
1570 | |
1583 | if (!QUERY_FLAG (op, FLAG_STAND_STILL)) |
1571 | if (!QUERY_FLAG (op, FLAG_STAND_STILL)) |
1584 | { |
1572 | { |
1585 | if (move_object (op, dir)) /* Can the monster move directly toward player? */ |
1573 | if (op->move (dir)) /* Can the monster move directly toward player? */ |
1586 | { |
1574 | { |
1587 | /* elmex: Turn our monster after it moved if it has DISTATT attack */ |
1575 | /* elmex: Turn our monster after it moved if it has DISTATT attack */ |
1588 | if ((op->attack_movement & LO4) == DISTATT) |
1576 | if ((op->attack_movement & LO4) == DISTATT) |
1589 | op->direction = pre_att_dir; |
1577 | op->direction = pre_att_dir; |
1590 | |
1578 | |
… | |
… | |
1599 | for (diff = 1; diff <= maxdiff; diff++) |
1587 | for (diff = 1; diff <= maxdiff; diff++) |
1600 | { |
1588 | { |
1601 | /* try different detours */ |
1589 | /* try different detours */ |
1602 | int m = 1 - rndm (2) * 2; /* Try left or right first? */ |
1590 | int m = 1 - rndm (2) * 2; /* Try left or right first? */ |
1603 | |
1591 | |
1604 | if (move_object (op, absdir (dir + diff * m)) || move_object (op, absdir (dir - diff * m))) |
1592 | if (op->move (absdir (dir + diff * m)) || op->move (absdir (dir - diff * m))) |
1605 | return 0; |
1593 | return 0; |
1606 | } |
1594 | } |
1607 | } |
1595 | } |
1608 | } /* if monster is not standing still */ |
1596 | } /* if monster is not standing still */ |
1609 | |
1597 | |