1 | |
1 | |
2 | /* |
2 | /* |
3 | * static char *rcsid_apply_c = |
3 | * static char *rcsid_apply_c = |
4 | * "$Id: apply.C,v 1.22 2006/09/10 15:59:57 root Exp $"; |
4 | * "$Id: apply.C,v 1.23 2006/09/11 11:46:52 root Exp $"; |
5 | */ |
5 | */ |
6 | |
6 | |
7 | /* |
7 | /* |
8 | CrossFire, A Multiplayer game for X-windows |
8 | CrossFire, A Multiplayer game for X-windows |
9 | |
9 | |
… | |
… | |
1524 | if (INVOKE_OBJECT (MOVE_TRIGGER, trap, ARG_OBJECT (victim), ARG_OBJECT (originator))) |
1524 | if (INVOKE_OBJECT (MOVE_TRIGGER, trap, ARG_OBJECT (victim), ARG_OBJECT (originator))) |
1525 | goto leave; |
1525 | goto leave; |
1526 | |
1526 | |
1527 | switch (trap->type) |
1527 | switch (trap->type) |
1528 | { |
1528 | { |
1529 | case PLAYERMOVER: |
1529 | case PLAYERMOVER: |
1530 | if (trap->attacktype && (trap->level || victim->type != PLAYER) && !should_director_abort (trap, victim)) |
1530 | if (trap->attacktype && (trap->level || victim->type != PLAYER) && !should_director_abort (trap, victim)) |
1531 | { |
1531 | { |
1532 | if (!trap->stats.maxsp) |
1532 | if (!trap->stats.maxsp) |
1533 | trap->stats.maxsp = 2; |
1533 | trap->stats.maxsp = 2; |
1534 | |
1534 | |
1535 | /* Is this correct? From the docs, it doesn't look like it |
1535 | /* Is this correct? From the docs, it doesn't look like it |
1536 | * should be divided by trap->speed |
1536 | * should be divided by trap->speed |
|
|
1537 | */ |
|
|
1538 | victim->speed_left = -FABS (trap->stats.maxsp * victim->speed / trap->speed); |
|
|
1539 | |
|
|
1540 | /* Just put in some sanity check. I think there is a bug in the |
|
|
1541 | * above with some objects have zero speed, and thus the player |
|
|
1542 | * getting permanently paralyzed. |
|
|
1543 | */ |
|
|
1544 | if (victim->speed_left < -50.0) |
|
|
1545 | victim->speed_left = -50.0; |
|
|
1546 | /* LOG(llevDebug, "apply, playermove, player speed_left=%f\n", victim->speed_left); */ |
|
|
1547 | } |
|
|
1548 | goto leave; |
|
|
1549 | |
|
|
1550 | case SPINNER: |
|
|
1551 | if (victim->direction) |
|
|
1552 | { |
|
|
1553 | victim->direction = absdir (victim->direction - trap->stats.sp); |
|
|
1554 | update_turn_face (victim); |
|
|
1555 | } |
|
|
1556 | goto leave; |
|
|
1557 | |
|
|
1558 | case DIRECTOR: |
|
|
1559 | if (victim->direction && !should_director_abort (trap, victim)) |
|
|
1560 | { |
|
|
1561 | victim->direction = trap->stats.sp; |
|
|
1562 | update_turn_face (victim); |
|
|
1563 | } |
|
|
1564 | goto leave; |
|
|
1565 | |
|
|
1566 | case BUTTON: |
|
|
1567 | case PEDESTAL: |
|
|
1568 | update_button (trap); |
|
|
1569 | goto leave; |
|
|
1570 | |
|
|
1571 | case ALTAR: |
|
|
1572 | /* sacrifice victim on trap */ |
|
|
1573 | apply_altar (trap, victim, originator); |
|
|
1574 | goto leave; |
|
|
1575 | |
|
|
1576 | case THROWN_OBJ: |
|
|
1577 | if (trap->inv == NULL) |
|
|
1578 | goto leave; |
|
|
1579 | /* fallthrough */ |
|
|
1580 | |
|
|
1581 | case ARROW: |
|
|
1582 | /* bad bug: monster throw a object, make a step forwards, step on object , |
|
|
1583 | * trigger this here and get hit by own missile - and will be own enemy. |
|
|
1584 | * Victim then is his own enemy and will start to kill herself (this is |
|
|
1585 | * removed) but we have not synced victim and his missile. To avoid senseless |
|
|
1586 | * action, we avoid hits here |
|
|
1587 | */ |
|
|
1588 | if ((QUERY_FLAG (victim, FLAG_ALIVE) && trap->speed) && trap->owner != victim) |
|
|
1589 | hit_with_arrow (trap, victim); |
|
|
1590 | goto leave; |
|
|
1591 | |
|
|
1592 | case SPELL_EFFECT: |
|
|
1593 | apply_spell_effect (trap, victim); |
|
|
1594 | goto leave; |
|
|
1595 | |
|
|
1596 | case TRAPDOOR: |
|
|
1597 | { |
|
|
1598 | int max, sound_was_played; |
|
|
1599 | object *ab, *ab_next; |
|
|
1600 | |
|
|
1601 | if (!trap->value) |
|
|
1602 | { |
|
|
1603 | int tot; |
|
|
1604 | |
|
|
1605 | for (ab = trap->above, tot = 0; ab != NULL; ab = ab->above) |
|
|
1606 | if ((ab->move_type && trap->move_on) || ab->move_type == 0) |
|
|
1607 | tot += (ab->nrof ? ab->nrof : 1) * ab->weight + ab->carrying; |
|
|
1608 | |
|
|
1609 | if (!(trap->value = (tot > trap->weight) ? 1 : 0)) |
|
|
1610 | goto leave; |
|
|
1611 | |
|
|
1612 | SET_ANIMATION (trap, trap->value); |
|
|
1613 | update_object (trap, UP_OBJ_FACE); |
|
|
1614 | } |
|
|
1615 | |
|
|
1616 | for (ab = trap->above, max = 100, sound_was_played = 0; --max && ab; ab = ab_next) |
|
|
1617 | { |
|
|
1618 | /* need to set this up, since if we do transfer the object, |
|
|
1619 | * ab->above would be bogus |
1537 | */ |
1620 | */ |
1538 | victim->speed_left = -FABS (trap->stats.maxsp * victim->speed / trap->speed); |
1621 | ab_next = ab->above; |
1539 | |
1622 | |
1540 | /* Just put in some sanity check. I think there is a bug in the |
1623 | if ((ab->move_type && trap->move_on) || ab->move_type == 0) |
1541 | * above with some objects have zero speed, and thus the player |
|
|
1542 | * getting permanently paralyzed. |
|
|
1543 | */ |
1624 | { |
1544 | if (victim->speed_left < -50.0) |
1625 | if (!sound_was_played) |
1545 | victim->speed_left = -50.0; |
1626 | { |
1546 | /* LOG(llevDebug, "apply, playermove, player speed_left=%f\n", victim->speed_left); */ |
1627 | play_sound_map (trap->map, trap->x, trap->y, SOUND_FALL_HOLE); |
|
|
1628 | sound_was_played = 1; |
|
|
1629 | } |
|
|
1630 | new_draw_info (NDI_UNIQUE, 0, ab, "You fall into a trapdoor!"); |
|
|
1631 | transfer_ob (ab, (int) EXIT_X (trap), (int) EXIT_Y (trap), 0, ab); |
|
|
1632 | } |
1547 | } |
1633 | } |
1548 | goto leave; |
1634 | goto leave; |
|
|
1635 | } |
1549 | |
1636 | |
1550 | case SPINNER: |
1637 | |
1551 | if (victim->direction) |
1638 | case CONVERTER: |
|
|
1639 | if (convert_item (victim, trap) < 0) |
|
|
1640 | { |
|
|
1641 | object *op; |
|
|
1642 | |
|
|
1643 | new_draw_info_format (NDI_UNIQUE, 0, originator, "The %s seems to be broken!", query_name (trap)); |
|
|
1644 | |
|
|
1645 | op = get_archetype ("burnout"); |
|
|
1646 | if (op != NULL) |
1552 | { |
1647 | { |
1553 | victim->direction = absdir (victim->direction - trap->stats.sp); |
1648 | op->x = trap->x; |
1554 | update_turn_face (victim); |
1649 | op->y = trap->y; |
|
|
1650 | insert_ob_in_map (op, trap->map, trap, 0); |
1555 | } |
1651 | } |
|
|
1652 | } |
|
|
1653 | goto leave; |
|
|
1654 | |
|
|
1655 | case TRIGGER_BUTTON: |
|
|
1656 | case TRIGGER_PEDESTAL: |
|
|
1657 | case TRIGGER_ALTAR: |
|
|
1658 | check_trigger (trap, victim); |
|
|
1659 | goto leave; |
|
|
1660 | |
|
|
1661 | case DEEP_SWAMP: |
|
|
1662 | walk_on_deep_swamp (trap, victim); |
|
|
1663 | goto leave; |
|
|
1664 | |
|
|
1665 | case CHECK_INV: |
|
|
1666 | check_inv (victim, trap); |
|
|
1667 | goto leave; |
|
|
1668 | |
|
|
1669 | case HOLE: |
|
|
1670 | /* Hole not open? */ |
|
|
1671 | if (trap->stats.wc > 0) |
1556 | goto leave; |
1672 | goto leave; |
1557 | |
1673 | |
1558 | case DIRECTOR: |
1674 | /* Is this a multipart monster and not the head? If so, return. |
1559 | if (victim->direction && !should_director_abort (trap, victim)) |
1675 | * Processing will happen if the head runs into the pit |
1560 | { |
1676 | */ |
1561 | victim->direction = trap->stats.sp; |
1677 | if (victim->head) |
1562 | update_turn_face (victim); |
|
|
1563 | } |
|
|
1564 | goto leave; |
1678 | goto leave; |
1565 | |
1679 | |
1566 | case BUTTON: |
1680 | play_sound_map (victim->map, victim->x, victim->y, SOUND_FALL_HOLE); |
1567 | case PEDESTAL: |
1681 | new_draw_info (NDI_UNIQUE, 0, victim, "You fall through the hole!\n"); |
1568 | update_button (trap); |
1682 | transfer_ob (victim, EXIT_X (trap), EXIT_Y (trap), 1, victim); |
1569 | goto leave; |
1683 | goto leave; |
1570 | |
1684 | |
1571 | case ALTAR: |
1685 | case EXIT: |
1572 | /* sacrifice victim on trap */ |
1686 | if (victim->type == PLAYER && EXIT_PATH (trap)) |
1573 | apply_altar (trap, victim, originator); |
|
|
1574 | goto leave; |
|
|
1575 | |
|
|
1576 | case THROWN_OBJ: |
|
|
1577 | if (trap->inv == NULL) |
|
|
1578 | goto leave; |
|
|
1579 | /* fallthrough */ |
|
|
1580 | |
|
|
1581 | case ARROW: |
|
|
1582 | |
|
|
1583 | /* bad bug: monster throw a object, make a step forwards, step on object , |
|
|
1584 | * trigger this here and get hit by own missile - and will be own enemy. |
|
|
1585 | * Victim then is his own enemy and will start to kill herself (this is |
|
|
1586 | * removed) but we have not synced victim and his missile. To avoid senseless |
|
|
1587 | * action, we avoid hits here |
|
|
1588 | */ |
|
|
1589 | if ((QUERY_FLAG (victim, FLAG_ALIVE) && trap->speed) && trap->owner != victim) |
|
|
1590 | hit_with_arrow (trap, victim); |
|
|
1591 | goto leave; |
|
|
1592 | |
|
|
1593 | case SPELL_EFFECT: |
|
|
1594 | apply_spell_effect (trap, victim); |
|
|
1595 | goto leave; |
|
|
1596 | |
|
|
1597 | case TRAPDOOR: |
|
|
1598 | { |
1687 | { |
1599 | int max, sound_was_played; |
1688 | /* Basically, don't show exits leading to random maps the |
1600 | object *ab, *ab_next; |
1689 | * players output. |
1601 | |
|
|
1602 | if (!trap->value) |
|
|
1603 | { |
|
|
1604 | int tot; |
|
|
1605 | |
|
|
1606 | for (ab = trap->above, tot = 0; ab != NULL; ab = ab->above) |
|
|
1607 | if ((ab->move_type && trap->move_on) || ab->move_type == 0) |
|
|
1608 | tot += (ab->nrof ? ab->nrof : 1) * ab->weight + ab->carrying; |
|
|
1609 | |
|
|
1610 | if (!(trap->value = (tot > trap->weight) ? 1 : 0)) |
|
|
1611 | goto leave; |
|
|
1612 | |
|
|
1613 | SET_ANIMATION (trap, trap->value); |
|
|
1614 | update_object (trap, UP_OBJ_FACE); |
|
|
1615 | } |
|
|
1616 | |
|
|
1617 | for (ab = trap->above, max = 100, sound_was_played = 0; --max && ab; ab = ab_next) |
|
|
1618 | { |
|
|
1619 | /* need to set this up, since if we do transfer the object, |
|
|
1620 | * ab->above would be bogus |
|
|
1621 | */ |
1690 | */ |
1622 | ab_next = ab->above; |
1691 | if (trap->msg && strncmp (EXIT_PATH (trap), "/!", 2) && strncmp (EXIT_PATH (trap), "/random/", 8)) |
1623 | |
1692 | new_draw_info (NDI_NAVY, 0, victim, trap->msg); |
1624 | if ((ab->move_type && trap->move_on) || ab->move_type == 0) |
1693 | enter_exit (victim, trap); |
1625 | { |
|
|
1626 | if (!sound_was_played) |
|
|
1627 | { |
|
|
1628 | play_sound_map (trap->map, trap->x, trap->y, SOUND_FALL_HOLE); |
|
|
1629 | sound_was_played = 1; |
|
|
1630 | } |
|
|
1631 | new_draw_info (NDI_UNIQUE, 0, ab, "You fall into a trapdoor!"); |
|
|
1632 | transfer_ob (ab, (int) EXIT_X (trap), (int) EXIT_Y (trap), 0, ab); |
|
|
1633 | } |
|
|
1634 | } |
|
|
1635 | goto leave; |
|
|
1636 | } |
1694 | } |
1637 | |
|
|
1638 | |
|
|
1639 | case CONVERTER: |
|
|
1640 | if (convert_item (victim, trap) < 0) |
|
|
1641 | { |
|
|
1642 | object *op; |
|
|
1643 | |
|
|
1644 | new_draw_info_format (NDI_UNIQUE, 0, originator, "The %s seems to be broken!", query_name (trap)); |
|
|
1645 | |
|
|
1646 | op = get_archetype ("burnout"); |
|
|
1647 | if (op != NULL) |
|
|
1648 | { |
|
|
1649 | op->x = trap->x; |
|
|
1650 | op->y = trap->y; |
|
|
1651 | insert_ob_in_map (op, trap->map, trap, 0); |
|
|
1652 | } |
|
|
1653 | } |
|
|
1654 | goto leave; |
1695 | goto leave; |
1655 | |
1696 | |
1656 | case TRIGGER_BUTTON: |
|
|
1657 | case TRIGGER_PEDESTAL: |
|
|
1658 | case TRIGGER_ALTAR: |
|
|
1659 | check_trigger (trap, victim); |
|
|
1660 | goto leave; |
|
|
1661 | |
|
|
1662 | case DEEP_SWAMP: |
|
|
1663 | walk_on_deep_swamp (trap, victim); |
|
|
1664 | goto leave; |
|
|
1665 | |
|
|
1666 | case CHECK_INV: |
|
|
1667 | check_inv (victim, trap); |
|
|
1668 | goto leave; |
|
|
1669 | |
|
|
1670 | case HOLE: |
|
|
1671 | /* Hole not open? */ |
|
|
1672 | if (trap->stats.wc > 0) |
|
|
1673 | goto leave; |
|
|
1674 | |
|
|
1675 | /* Is this a multipart monster and not the head? If so, return. |
|
|
1676 | * Processing will happen if the head runs into the pit |
|
|
1677 | */ |
|
|
1678 | if (victim->head) |
|
|
1679 | goto leave; |
|
|
1680 | |
|
|
1681 | play_sound_map (victim->map, victim->x, victim->y, SOUND_FALL_HOLE); |
|
|
1682 | new_draw_info (NDI_UNIQUE, 0, victim, "You fall through the hole!\n"); |
|
|
1683 | transfer_ob (victim, EXIT_X (trap), EXIT_Y (trap), 1, victim); |
|
|
1684 | goto leave; |
|
|
1685 | |
|
|
1686 | case EXIT: |
|
|
1687 | if (victim->type == PLAYER && EXIT_PATH (trap)) |
|
|
1688 | { |
|
|
1689 | /* Basically, don't show exits leading to random maps the |
|
|
1690 | * players output. |
|
|
1691 | */ |
|
|
1692 | if (trap->msg && strncmp (EXIT_PATH (trap), "/!", 2) && strncmp (EXIT_PATH (trap), "/random/", 8)) |
|
|
1693 | new_draw_info (NDI_NAVY, 0, victim, trap->msg); |
|
|
1694 | enter_exit (victim, trap); |
|
|
1695 | } |
|
|
1696 | goto leave; |
|
|
1697 | |
|
|
1698 | case ENCOUNTER: |
1697 | case ENCOUNTER: |
1699 | /* may be some leftovers on this */ |
1698 | /* may be some leftovers on this */ |
1700 | goto leave; |
1699 | goto leave; |
1701 | |
1700 | |
1702 | case SHOP_MAT: |
1701 | case SHOP_MAT: |
1703 | apply_shop_mat (trap, victim); |
1702 | apply_shop_mat (trap, victim); |
1704 | goto leave; |
1703 | goto leave; |
1705 | |
1704 | |
1706 | /* Drop a certain amount of gold, and have one item identified */ |
1705 | /* Drop a certain amount of gold, and have one item identified */ |
1707 | case IDENTIFY_ALTAR: |
1706 | case IDENTIFY_ALTAR: |
1708 | apply_id_altar (victim, trap, originator); |
1707 | apply_id_altar (victim, trap, originator); |
1709 | goto leave; |
1708 | goto leave; |
1710 | |
1709 | |
1711 | case SIGN: |
1710 | case SIGN: |
1712 | if (victim->type != PLAYER && trap->stats.food > 0) |
1711 | if (victim->type != PLAYER && trap->stats.food > 0) |
1713 | goto leave; /* monsters musn't apply magic_mouths with counters */ |
1712 | goto leave; /* monsters musn't apply magic_mouths with counters */ |
1714 | |
1713 | |
1715 | apply_sign (victim, trap, 1); |
1714 | apply_sign (victim, trap, 1); |
1716 | goto leave; |
1715 | goto leave; |
1717 | |
1716 | |
1718 | case CONTAINER: |
1717 | case CONTAINER: |
1719 | if (victim->type == PLAYER) |
1718 | if (victim->type == PLAYER) |
1720 | (void) esrv_apply_container (victim, trap); |
1719 | (void) esrv_apply_container (victim, trap); |
1721 | else |
1720 | else |
1722 | (void) apply_container (victim, trap); |
1721 | (void) apply_container (victim, trap); |
1723 | goto leave; |
1722 | goto leave; |
1724 | |
1723 | |
1725 | case RUNE: |
1724 | case RUNE: |
1726 | case TRAP: |
1725 | case TRAP: |
1727 | if (trap->level && QUERY_FLAG (victim, FLAG_ALIVE)) |
1726 | if (trap->level && QUERY_FLAG (victim, FLAG_ALIVE)) |
1728 | { |
1727 | { |
1729 | spring_trap (trap, victim); |
1728 | spring_trap (trap, victim); |
1730 | } |
1729 | } |
1731 | goto leave; |
1730 | goto leave; |
1732 | |
1731 | |
1733 | default: |
1732 | default: |
1734 | LOG (llevDebug, "name %s, arch %s, type %d with fly/walk on/off not " |
1733 | LOG (llevDebug, "name %s, arch %s, type %d with fly/walk on/off not " |
1735 | "handled in move_apply()\n", &trap->name, &trap->arch->name, trap->type); |
1734 | "handled in move_apply()\n", &trap->name, &trap->arch->name, trap->type); |
1736 | goto leave; |
1735 | goto leave; |
1737 | } |
1736 | } |
1738 | |
1737 | |
1739 | leave: |
1738 | leave: |
1740 | recursion_depth--; |
1739 | recursion_depth--; |
1741 | } |
1740 | } |