ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/monster.C
(Generate patch)

Comparing deliantra/server/server/monster.C (file contents):
Revision 1.47 by root, Thu Dec 18 02:49:22 2008 UTC vs.
Revision 1.55 by root, Sat Dec 27 07:50:05 2008 UTC

35 * set to sane values. 35 * set to sane values.
36 */ 36 */
37object * 37object *
38check_enemy (object *npc, rv_vector * rv) 38check_enemy (object *npc, rv_vector * rv)
39{ 39{
40
41 /* if this is pet, let him attack the same enemy as his owner 40 /* if this is pet, let him attack the same enemy as his owner
42 * TODO: when there is no ower enemy, try to find a target, 41 * TODO: when there is no ower enemy, try to find a target,
43 * which CAN attack the owner. */ 42 * which CAN attack the owner. */
44 if ((npc->attack_movement & HI4) == PETMOVE) 43 if ((npc->attack_movement & HI4) == PETMOVE)
45 { 44 {
197 /* we check our old enemy. */ 196 /* we check our old enemy. */
198 if (!(tmp = check_enemy (npc, rv))) 197 if (!(tmp = check_enemy (npc, rv)))
199 { 198 {
200 if (attacker) /* if we have an attacker, check him */ 199 if (attacker) /* if we have an attacker, check him */
201 { 200 {
202 /* TODO: thats not finished */ 201 /* TODO: that's not finished */
203 /* we don't want a fight evil vs evil or good against non evil */ 202 /* we don't want a fight evil vs evil or good against non evil */
204 203
205 if (QUERY_FLAG (npc, FLAG_NEUTRAL) || QUERY_FLAG (attacker, FLAG_NEUTRAL) || /* neutral */ 204 if (QUERY_FLAG (npc, FLAG_NEUTRAL) || QUERY_FLAG (attacker, FLAG_NEUTRAL) || /* neutral */
206 (QUERY_FLAG (npc, FLAG_FRIENDLY) && QUERY_FLAG (attacker, FLAG_FRIENDLY)) || 205 (QUERY_FLAG (npc, FLAG_FRIENDLY) && QUERY_FLAG (attacker, FLAG_FRIENDLY)) ||
207 (!QUERY_FLAG (npc, FLAG_FRIENDLY) && (!QUERY_FLAG (attacker, FLAG_FRIENDLY) && attacker->type != PLAYER))) 206 (!QUERY_FLAG (npc, FLAG_FRIENDLY) && (!QUERY_FLAG (attacker, FLAG_FRIENDLY) && attacker->type != PLAYER)))
208 CLEAR_FLAG (npc, FLAG_SLEEP); /* skip it, but lets wakeup */ 207 CLEAR_FLAG (npc, FLAG_SLEEP); /* skip it, but lets wakeup */
209 else if (on_same_map (npc, attacker)) /* thats the only thing we must know... */ 208 else if (on_same_map (npc, attacker)) /* that's the only thing we must know... */
210 { 209 {
211 CLEAR_FLAG (npc, FLAG_SLEEP); /* well, NOW we really should wake up! */ 210 CLEAR_FLAG (npc, FLAG_SLEEP); /* well, NOW we really should wake up! */
212 npc->enemy = attacker; 211 npc->enemy = attacker;
213 return attacker; /* yes, we face our attacker! */ 212 return attacker; /* yes, we face our attacker! */
214 } 213 }
231 * Currently, this is only called from move_monster, and 230 * Currently, this is only called from move_monster, and
232 * if enemy is set, then so should be rv. 231 * if enemy is set, then so should be rv.
233 * returns 1 if the monster should wake up, 0 otherwise. 232 * returns 1 if the monster should wake up, 0 otherwise.
234 */ 233 */
235int 234int
236check_wakeup (object *op, object *enemy, rv_vector * rv) 235check_wakeup (object *op, object *enemy, rv_vector *rv)
237{ 236{
238 int radius = op->stats.Wis > MIN_MON_RADIUS ? op->stats.Wis : MIN_MON_RADIUS;
239
240 /* Trim work - if no enemy, no need to do anything below */ 237 /* Trim work - if no enemy, no need to do anything below */
241 if (!enemy) 238 if (!enemy)
242 return 0; 239 return 0;
243 240
241 int radius = max (op->stats.Wis, MIN_MON_RADIUS);
242
243 if (op->flag [FLAG_BLIND])
244 /* blinded monsters can only find nearby objects to attack */ 244 /* blinded monsters can only find nearby objects to attack */
245 if (QUERY_FLAG (op, FLAG_BLIND))
246 radius = MIN_MON_RADIUS; 245 radius = MIN_MON_RADIUS;
247 246 else if (op->map
247 && !enemy->invisible
248 && !stand_in_light (enemy)
249 && (!op->flag[FLAG_SEE_IN_DARK] || !op->flag [FLAG_SEE_INVISIBLE]))
248 /* This covers the situation where the monster is in the dark 250 /* This covers the situation where the monster is in the dark
249 * and has an enemy. If the enemy has no carried light (or isnt 251 * and has an enemy. If the enemy has no carried light (or isnt
250 * glowing!) then the monster has trouble finding the enemy. 252 * glowing!) then the monster has trouble finding the enemy.
251 * Remember we already checked to see if the monster can see in 253 * Remember we already checked to see if the monster can see in
252 * the dark. */ 254 * the dark. */
253 255 radius = min (radius, MIN_MON_RADIUS + MAX_DARKNESS - op->map->darklevel ());
254 else if (op->map && op->map->darkness > 0 && enemy && !enemy->invisible && 256 else if (!op->flag [FLAG_SLEEP])
255 !stand_in_light (enemy) && (!QUERY_FLAG (op, FLAG_SEE_IN_DARK) || !QUERY_FLAG (op, FLAG_SEE_INVISIBLE)))
256 {
257 int dark = radius / (op->map->darkness);
258
259 radius = (dark > MIN_MON_RADIUS) ? (dark + 1) : MIN_MON_RADIUS;
260 }
261 else if (!QUERY_FLAG (op, FLAG_SLEEP))
262 return 1; 257 return 1;
258
259 if (enemy->flag [FLAG_STEALTH])
260 radius = radius / 2 + 1;
263 261
264 /* enemy should already be on this map, so don't really need to check 262 /* enemy should already be on this map, so don't really need to check
265 * for that. 263 * for that.
266 */ 264 */
267 if (rv->distance < (unsigned int) (QUERY_FLAG (enemy, FLAG_STEALTH) ? (radius / 2) + 1 : radius)) 265 if (rv->distance <= radius)
268 { 266 {
269 CLEAR_FLAG (op, FLAG_SLEEP); 267 CLEAR_FLAG (op, FLAG_SLEEP);
270 return 1; 268 return 1;
271 } 269 }
270
272 return 0; 271 return 0;
273} 272}
274 273
275int 274int
276move_randomly (object *op) 275move_randomly (object *op)
324 op->last_heal += (int) ((float) (8 * op->stats.Con) / FABS (op->speed)); 323 op->last_heal += (int) ((float) (8 * op->stats.Con) / FABS (op->speed));
325 op->stats.hp = MIN ((sint32) op->stats.hp + op->last_heal / 32, op->stats.maxhp); /* causes Con/4 hp/tick */ 324 op->stats.hp = MIN ((sint32) op->stats.hp + op->last_heal / 32, op->stats.maxhp); /* causes Con/4 hp/tick */
326 op->last_heal %= 32; 325 op->last_heal %= 32;
327 326
328 /* So if the monster has gained enough HP that they are no longer afraid */ 327 /* So if the monster has gained enough HP that they are no longer afraid */
329 if (QUERY_FLAG (op, FLAG_RUN_AWAY) && op->stats.hp >= (signed short) (((float) op->run_away / (float) 100) * (float) op->stats.maxhp)) 328 if (QUERY_FLAG (op, FLAG_RUN_AWAY) && op->stats.hp >= (signed short)(((float)op->run_away / 100.f) * (float)op->stats.maxhp))
330 CLEAR_FLAG (op, FLAG_RUN_AWAY); 329 CLEAR_FLAG (op, FLAG_RUN_AWAY);
331 330
332 if (op->stats.hp > op->stats.maxhp) 331 if (op->stats.hp > op->stats.maxhp)
333 op->stats.hp = op->stats.maxhp; 332 op->stats.hp = op->stats.maxhp;
334 } 333 }
335 334
336 /* generate sp, if applicable */ 335 /* generate sp, if applicable */
337 if (op->stats.Pow > 0 && op->stats.sp < op->stats.maxsp) 336 if (op->stats.Pow > 0 && op->stats.sp < op->stats.maxsp)
338 { 337 {
339 /* last_sp is in funny units. Dividing by speed puts 338 /* last_sp is in funny units. Dividing by speed puts
340 * the regeneration rate on a basis of time instead of 339 * the regeneration rate on a basis of time instead of
341 * #moves the monster makes. The scaling by 8 is 340 * #moves the monster makes. The scaling by 8 is
342 * to capture 8th's of a sp fraction regens 341 * to capture 8th's of a sp fraction regens
343 * 342 *
344 * Cast to sint32 before comparing to maxhp since otherwise an (sint16) 343 * Cast to sint32 before comparing to maxhp since otherwise an (sint16)
345 * overflow might produce monsters with negative sp. 344 * overflow might produce monsters with negative sp.
346 */ 345 */
347 346
348 op->last_sp += (int) ((float) (8 * op->stats.Pow) / FABS (op->speed)); 347 op->last_sp += (int) ((float) (8 * op->stats.Pow) / fabsf (op->speed));
349 op->stats.sp = MIN (op->stats.sp + op->last_sp / 128, op->stats.maxsp); /* causes Pow/16 sp/tick */ 348 op->stats.sp = min (op->stats.sp + op->last_sp / 128, op->stats.maxsp); /* causes Pow/16 sp/tick */
350 op->last_sp %= 128; 349 op->last_sp %= 128;
351 } 350 }
352 351
353 /* this should probably get modified by many more values. 352 /* this should probably get modified by many more values.
354 * (eg, creatures resistance to fear, level, etc. ) 353 * (eg, creatures resistance to fear, level, etc. )
358 357
359 if (INVOKE_OBJECT (MONSTER_MOVE, op, ARG_OBJECT (op->enemy))) 358 if (INVOKE_OBJECT (MONSTER_MOVE, op, ARG_OBJECT (op->enemy)))
360 return QUERY_FLAG (op, FLAG_FREED); 359 return QUERY_FLAG (op, FLAG_FREED);
361 360
362 if (QUERY_FLAG (op, FLAG_SLEEP) || QUERY_FLAG (op, FLAG_BLIND) || 361 if (QUERY_FLAG (op, FLAG_SLEEP) || QUERY_FLAG (op, FLAG_BLIND) ||
363 ((op->map->darkness > 0) && !QUERY_FLAG (op, FLAG_SEE_IN_DARK) && !QUERY_FLAG (op, FLAG_SEE_INVISIBLE))) 362 ((op->map->darklevel () > 0) && !QUERY_FLAG (op, FLAG_SEE_IN_DARK) && !QUERY_FLAG (op, FLAG_SEE_INVISIBLE)))
364 if (!check_wakeup (op, enemy, &rv)) 363 if (!check_wakeup (op, enemy, &rv))
365 return 0; 364 return 0;
366 365
367 /* check if monster pops out of hidden spot */ 366 /* check if monster pops out of hidden spot */
368 if (op->flag [FLAG_HIDDEN]) 367 if (op->flag [FLAG_HIDDEN])
444 && !on_same_map (op, owner) 443 && !on_same_map (op, owner)
445 && !owner->flag [FLAG_REMOVED]) 444 && !owner->flag [FLAG_REMOVED])
446 return follow_owner (op, owner); 445 return follow_owner (op, owner);
447 446
448 /* doppleganger code to change monster facing to that of the nearest 447 /* doppleganger code to change monster facing to that of the nearest
449 * player. Hmm. The code is here, but no monster in the current 448 * player. Hmm. The code is here, but no monster in the current
450 * arch set uses it. 449 * arch set uses it.
451 */ 450 */
452 if ((op->race != NULL) && strcmp (op->race, "doppleganger") == 0) 451 if (op->race && strcmp (op->race, "doppleganger") == 0)
453 { 452 {
454 op->face = enemy->face; 453 op->face = enemy->face;
455 op->name = enemy->name; 454 op->name = enemy->name;
456 } 455 }
457 456
505 if (monster_use_bow (op, part, enemy, dir)) 504 if (monster_use_bow (op, part, enemy, dir))
506 return 0; 505 return 0;
507 } /* for processing of all parts */ 506 } /* for processing of all parts */
508 } /* If not scared */ 507 } /* If not scared */
509 508
510
511 part = rv.part; 509 part = rv.part;
512 dir = rv.direction; 510 dir = rv.direction;
511
512#if DEVEL
513 int sdir = 0;
514
515 for (int dir = 1; dir <= 8; ++dir)
516 {
517 mapxy pos (op); pos.move (dir);
518 if (pos.normalise ())
519 {
520 mapspace &ms = pos.ms ();
521
522 if (ms.smell > op->ms ().smell)
523 {
524 printf ("%s: found smell, following it, apparently (%d, %d)\n",& op->name,op->ms().smell,ms.smell);//D
525 op->ms ().smell = ms.smell - 1;
526 sdir = dir;
527
528 // perturbing the path might let the monster lose track,
529 // but it will also wide the actual path, spreading information
530 if (!rndm (20))
531 sdir += absdir (1 - rndm (2) * 2);
532 }
533 }
534 }
535
536 if (sdir)
537 dir = sdir;
538 else
539 // no better smell found, so assume the player jumped, and erase this smell
540 {if (op->ms ().smell) printf ("erasing smell %d\n", op->ms ().smell);//D
541 ordered_mapwalk_begin (op, -1, -1, 1, 1)
542 if (m)
543 m->at (nx, ny).smell = 0;
544 ordered_mapwalk_end
545 }//D
546
547#endif
513 548
514 if (QUERY_FLAG (op, FLAG_SCARED) || QUERY_FLAG (op, FLAG_RUN_AWAY)) 549 if (QUERY_FLAG (op, FLAG_SCARED) || QUERY_FLAG (op, FLAG_RUN_AWAY))
515 dir = absdir (dir + 4); 550 dir = absdir (dir + 4);
516 551
517 if (QUERY_FLAG (op, FLAG_CONFUSED)) 552 if (QUERY_FLAG (op, FLAG_CONFUSED))
571 } 606 }
572 607
573 if (QUERY_FLAG (op, FLAG_SCARED) || !can_hit (part, enemy, &rv) || QUERY_FLAG (op, FLAG_RUN_AWAY)) 608 if (QUERY_FLAG (op, FLAG_SCARED) || !can_hit (part, enemy, &rv) || QUERY_FLAG (op, FLAG_RUN_AWAY))
574 { 609 {
575 /* Try move around corners if !close */ 610 /* Try move around corners if !close */
576 int maxdiff = (QUERY_FLAG (op, FLAG_ONLY_ATTACK) || RANDOM () & 1) ? 1 : 2; 611 int maxdiff = (QUERY_FLAG (op, FLAG_ONLY_ATTACK) || rndm (2)) ? 1 : 2;
577 612
578 for (diff = 1; diff <= maxdiff; diff++) 613 for (diff = 1; diff <= maxdiff; diff++)
579 { 614 {
580 /* try different detours */ 615 /* try different detours */
581 int m = 1 - (RANDOM () & 2); /* Try left or right first? */ 616 int m = 1 - rndm (2) * 2; /* Try left or right first? */
582 617
583 if (move_object (op, absdir (dir + diff * m)) || move_object (op, absdir (dir - diff * m))) 618 if (move_object (op, absdir (dir + diff * m)) || move_object (op, absdir (dir - diff * m)))
584 return 0; 619 return 0;
585 } 620 }
586 } 621 }
613 { 648 {
614 object *nearest_player = get_nearest_player (op); 649 object *nearest_player = get_nearest_player (op);
615 650
616 if (nearest_player && nearest_player != enemy && !can_hit (part, enemy, &rv)) 651 if (nearest_player && nearest_player != enemy && !can_hit (part, enemy, &rv))
617 { 652 {
618 op->enemy = NULL; 653 op->enemy = 0;
619 enemy = nearest_player; 654 enemy = nearest_player;
620 } 655 }
621 } 656 }
622 657
623 if (!QUERY_FLAG (op, FLAG_SCARED) && can_hit (part, enemy, &rv)) 658 if (!QUERY_FLAG (op, FLAG_SCARED) && can_hit (part, enemy, &rv))
1689 radius = max (MIN_MON_RADIUS, op->stats.Wis / 5 + 1); 1724 radius = max (MIN_MON_RADIUS, op->stats.Wis / 5 + 1);
1690 else 1725 else
1691 { /* a level/INT/Dex adjustment for hiding */ 1726 { /* a level/INT/Dex adjustment for hiding */
1692 int bonus = op->level / 2 + op->stats.Int / 5; 1727 int bonus = op->level / 2 + op->stats.Int / 5;
1693 1728
1694 if (enemy->type == PLAYER) 1729 if (enemy->is_player ())
1695 { 1730 {
1696 if (object *sk_hide = find_skill_by_number (enemy, SK_HIDING)) 1731 if (object *sk_hide = find_skill_by_number (enemy, SK_HIDING))
1697 bonus -= sk_hide->level; 1732 bonus -= sk_hide->level;
1698 else 1733 else
1699 { 1734 {
1716 radius /= 2; 1751 radius /= 2;
1717 hide_discovery /= 3; 1752 hide_discovery /= 3;
1718 } 1753 }
1719 1754
1720 /* Radii adjustment for enemy standing in the dark */ 1755 /* Radii adjustment for enemy standing in the dark */
1721 if (op->map->darkness > 0 && !stand_in_light (enemy)) 1756 if (op->map->darklevel () > 0 && !stand_in_light (enemy))
1722 { 1757 {
1723 /* on dark maps body heat can help indicate location with infravision 1758 /* on dark maps body heat can help indicate location with infravision
1724 * undead don't have body heat, so no benefit detecting them. 1759 * undead don't have body heat, so no benefit detecting them.
1725 */ 1760 */
1726 if (QUERY_FLAG (op, FLAG_SEE_IN_DARK) && !is_true_undead (enemy)) 1761 if (QUERY_FLAG (op, FLAG_SEE_IN_DARK) && !is_true_undead (enemy))
1727 radius += op->map->darkness / 2; 1762 radius += op->map->darklevel () / 2;
1728 else 1763 else
1729 radius -= op->map->darkness / 2; 1764 radius -= op->map->darklevel () / 2;
1730 1765
1731 /* op next to a monster (and not in complete darkness) 1766 /* op next to a monster (and not in complete darkness)
1732 * the monster should have a chance to see you. 1767 * the monster should have a chance to see you.
1733 */ 1768 */
1734 if (radius < MIN_MON_RADIUS && op->map->darkness < 5 && rv->distance <= 1) 1769 if (radius < MIN_MON_RADIUS && op->map->darklevel () < 5 && rv->distance <= 1)
1735 radius = MIN_MON_RADIUS; 1770 radius = MIN_MON_RADIUS;
1736 } /* if on dark map */ 1771 } /* if on dark map */
1737 1772
1738 /* Lets not worry about monsters that have incredible detection 1773 /* Lets not worry about monsters that have incredible detection
1739 * radii, we only need to worry here about things the player can 1774 * radii, we only need to worry here about things the player can
1794 * other side of a wall (!). 1829 * other side of a wall (!).
1795 */ 1830 */
1796int 1831int
1797stand_in_light (object *op) 1832stand_in_light (object *op)
1798{ 1833{
1799 if (!op) 1834 if (op)
1800 return 0; 1835 {
1801
1802 if (op->glow_radius > 0) 1836 if (op->glow_radius > 0)
1803 return 1; 1837 return 1;
1804 1838
1805 if (op->map) 1839 if (op->map)
1806 { 1840 unordered_mapwalk (op, -MAX_LIGHT_RADIUS, -MAX_LIGHT_RADIUS, MAX_LIGHT_RADIUS, MAX_LIGHT_RADIUS)
1841 {
1807 /* Check the spaces with the max light radius to see if any of them 1842 /* Check the spaces with the max light radius to see if any of them
1808 * have lights, and if any of them light the player enough, then return 1. 1843 * have lights, and if any of them light the player enough, then return 1.
1809 */
1810 for (int x = op->x - MAX_LIGHT_RADIUS; x <= op->x + MAX_LIGHT_RADIUS; x++)
1811 {
1812 for (int y = op->y - MAX_LIGHT_RADIUS; y <= op->y + MAX_LIGHT_RADIUS; y++)
1813 { 1844 */
1814 maptile *m = op->map; 1845 int light = m->at (nx, ny).light;
1815 sint16 nx = x;
1816 sint16 ny = y;
1817 1846
1818 if (xy_normalise (m, nx, ny)) 1847 if (expect_false (light > 0) && idistance (dx, dy) <= light)
1819 if (idistance (x - op->x, y - op->y) < m->at (nx, ny).light)
1820 return 1; 1848 return 1;
1821 } 1849 }
1822 }
1823 } 1850 }
1824 1851
1825 return 0; 1852 return 0;
1826} 1853}
1827 1854
1864 return 1; 1891 return 1;
1865 } 1892 }
1866 else if (enemy->flag [FLAG_HIDDEN]) 1893 else if (enemy->flag [FLAG_HIDDEN])
1867 return 0; 1894 return 0;
1868 1895
1869 /* Invisible enemy. Break apart the check for invis undead/invis looker 1896 /* Invisible enemy. Break apart the check for invis undead/invis looker
1870 * into more simple checks - the QUERY_FLAG doesn't return 1/0 values, 1897 * into more simple checks - the QUERY_FLAG doesn't return 1/0 values,
1871 * and making it a conditional makes the code pretty ugly. 1898 * and making it a conditional makes the code pretty ugly.
1872 */ 1899 */
1873 if (!QUERY_FLAG (looker, FLAG_SEE_INVISIBLE)) 1900 if (!QUERY_FLAG (looker, FLAG_SEE_INVISIBLE))
1874 if (makes_invisible_to (enemy, looker)) 1901 if (makes_invisible_to (enemy, looker))
1875 return 0; 1902 return 0;
1876 } 1903 }
1877 else if (looker->type == PLAYER) /* for players, a (possible) shortcut */ 1904 else if (looker->is_player ()) /* for players, a (possible) shortcut */
1878 if (player_can_view (looker, enemy)) 1905 if (player_can_view (looker, enemy))
1879 return 1; 1906 return 1;
1880 1907
1881 /* ENEMY IN DARK MAP. Without infravision, the enemy is not seen 1908 /* ENEMY IN DARK MAP. Without infravision, the enemy is not seen
1882 * unless they carry a light or stand in light. Darkness doesnt 1909 * unless they carry a light or stand in light. Darkness doesnt
1885 * we care about the enemy maps status, not the looker. 1912 * we care about the enemy maps status, not the looker.
1886 * only relevant for tiled maps, but it is possible that the 1913 * only relevant for tiled maps, but it is possible that the
1887 * enemy is on a bright map and the looker on a dark - in that 1914 * enemy is on a bright map and the looker on a dark - in that
1888 * case, the looker can still see the enemy 1915 * case, the looker can still see the enemy
1889 */ 1916 */
1890 if (enemy->map->darkness > 0 && !stand_in_light (enemy) 1917 if (enemy->map->darklevel () > 0
1918 && !stand_in_light (enemy)
1891 && (!QUERY_FLAG (looker, FLAG_SEE_IN_DARK) || !is_true_undead (looker) || !QUERY_FLAG (looker, FLAG_XRAYS))) 1919 && (!QUERY_FLAG (looker, FLAG_SEE_IN_DARK) || !is_true_undead (looker) || !QUERY_FLAG (looker, FLAG_XRAYS)))
1892 return 0; 1920 return 0;
1893 1921
1894 return 1; 1922 return 1;
1895} 1923}

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines