1 | |
1 | |
2 | /* |
2 | /* |
3 | * static char *rcsid_object_c = |
3 | * static char *rcsid_object_c = |
4 | * "$Id: object.C,v 1.24 2006/09/10 16:00:23 root Exp $"; |
4 | * "$Id: object.C,v 1.25 2006/09/11 01:16:20 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 | |
… | |
… | |
507 | |
507 | |
508 | op->owner = owner; |
508 | op->owner = owner; |
509 | |
509 | |
510 | op->ownercount = owner->count; |
510 | op->ownercount = owner->count; |
511 | owner->refcount++; |
511 | owner->refcount++; |
512 | |
|
|
513 | } |
512 | } |
514 | |
513 | |
515 | /* Set the owner to clone's current owner and set the skill and experience |
514 | /* Set the owner to clone's current owner and set the skill and experience |
516 | * objects to clone's objects (typically those objects that where the owner's |
515 | * objects to clone's objects (typically those objects that where the owner's |
517 | * current skill and experience objects at the time when clone's owner was |
516 | * current skill and experience objects at the time when clone's owner was |
… | |
… | |
535 | if (clone->type == PLAYER) |
534 | if (clone->type == PLAYER) |
536 | owner = clone; |
535 | owner = clone; |
537 | else |
536 | else |
538 | return; |
537 | return; |
539 | } |
538 | } |
|
|
539 | |
540 | set_owner (op, owner); |
540 | set_owner (op, owner); |
541 | |
|
|
542 | } |
541 | } |
543 | |
542 | |
544 | /* Zero the key_values on op, decrementing the shared-string |
543 | /* Zero the key_values on op, decrementing the shared-string |
545 | * refcounts and freeing the links. |
544 | * refcounts and freeing the links. |
546 | */ |
545 | */ |
… | |
… | |
561 | void object::clear () |
560 | void object::clear () |
562 | { |
561 | { |
563 | attachable_base::clear (); |
562 | attachable_base::clear (); |
564 | |
563 | |
565 | free_key_values (this); |
564 | free_key_values (this); |
|
|
565 | |
|
|
566 | clear_owner (this); |
566 | |
567 | |
567 | name = 0; |
568 | name = 0; |
568 | name_pl = 0; |
569 | name_pl = 0; |
569 | title = 0; |
570 | title = 0; |
570 | race = 0; |
571 | race = 0; |
… | |
… | |
912 | |
913 | |
913 | if (op->more != NULL) |
914 | if (op->more != NULL) |
914 | update_object (op->more, action); |
915 | update_object (op->more, action); |
915 | } |
916 | } |
916 | |
917 | |
917 | static |
918 | static unordered_vector<object *> mortals; |
918 | std::vector < object *> |
919 | static std::vector<object *> freed; |
919 | mortals; |
|
|
920 | |
920 | |
921 | void object::free_mortals () |
921 | void object::free_mortals () |
922 | { |
922 | { |
923 | for (std::vector < object *>::iterator i = mortals.begin (); i != mortals.end (); ++i) |
923 | for (unordered_vector<object *>::iterator i = mortals.begin (); i != mortals.end (); ) |
924 | delete * |
924 | if (!(*i)->refcount) |
|
|
925 | { |
|
|
926 | freed.push_back (*i); |
|
|
927 | mortals.erase (i); |
|
|
928 | } |
|
|
929 | else |
925 | i; |
930 | ++i; |
926 | |
|
|
927 | mortals.clear (); |
|
|
928 | } |
931 | } |
929 | |
932 | |
930 | object::object () |
933 | object::object () |
931 | { |
934 | { |
932 | SET_FLAG (this, FLAG_REMOVED); |
935 | SET_FLAG (this, FLAG_REMOVED); |
… | |
… | |
958 | { |
961 | { |
959 | count = 0; |
962 | count = 0; |
960 | |
963 | |
961 | /* Remove this object from the list of used objects */ |
964 | /* Remove this object from the list of used objects */ |
962 | if (prev) |
965 | if (prev) |
|
|
966 | { |
963 | prev->next = next; |
967 | prev->next = next; |
|
|
968 | prev = 0; |
|
|
969 | } |
|
|
970 | |
964 | if (next) |
971 | if (next) |
|
|
972 | { |
965 | next->prev = prev; |
973 | next->prev = prev; |
|
|
974 | next = 0; |
|
|
975 | } |
|
|
976 | |
966 | if (this == objects) |
977 | if (this == objects) |
967 | objects = next; |
978 | objects = next; |
968 | } |
979 | } |
969 | |
980 | |
970 | object *object::create () |
981 | object *object::create () |
971 | { |
982 | { |
972 | object * |
983 | object *op; |
|
|
984 | |
|
|
985 | if (freed.empty ()) |
973 | op = new object; |
986 | op = new object; |
|
|
987 | else |
|
|
988 | { |
|
|
989 | // highly annoying, but the only way to get it stable right now |
|
|
990 | op = freed.back (); freed.pop_back (); |
|
|
991 | op->~object (); |
|
|
992 | new ((void *)op) object; |
|
|
993 | } |
974 | |
994 | |
975 | op->link (); |
995 | op->link (); |
976 | return op; |
996 | return op; |
977 | } |
997 | } |
978 | |
998 | |
… | |
… | |
1061 | |
1081 | |
1062 | op = tmp; |
1082 | op = tmp; |
1063 | } |
1083 | } |
1064 | } |
1084 | } |
1065 | } |
1085 | } |
|
|
1086 | |
|
|
1087 | clear_owner (this); |
1066 | |
1088 | |
1067 | /* Remove object from the active list */ |
1089 | /* Remove object from the active list */ |
1068 | speed = 0; |
1090 | speed = 0; |
1069 | update_ob_speed (this); |
1091 | update_ob_speed (this); |
1070 | |
1092 | |
… | |
… | |
1375 | */ |
1397 | */ |
1376 | |
1398 | |
1377 | object * |
1399 | object * |
1378 | insert_ob_in_map (object *op, mapstruct *m, object *originator, int flag) |
1400 | insert_ob_in_map (object *op, mapstruct *m, object *originator, int flag) |
1379 | { |
1401 | { |
1380 | object * |
1402 | object *tmp, *top, *floor = NULL; |
1381 | tmp, * |
1403 | sint16 x, y; |
1382 | top, * |
|
|
1383 | floor = NULL; |
|
|
1384 | sint16 |
|
|
1385 | x, |
|
|
1386 | y; |
|
|
1387 | |
1404 | |
1388 | if (QUERY_FLAG (op, FLAG_FREED)) |
1405 | if (QUERY_FLAG (op, FLAG_FREED)) |
1389 | { |
1406 | { |
1390 | LOG (llevError, "Trying to insert freed object!\n"); |
1407 | LOG (llevError, "Trying to insert freed object!\n"); |
1391 | return NULL; |
1408 | return NULL; |
1392 | } |
1409 | } |
|
|
1410 | |
1393 | if (m == NULL) |
1411 | if (m == NULL) |
1394 | { |
1412 | { |
1395 | dump_object (op); |
1413 | dump_object (op); |
1396 | LOG (llevError, "Trying to insert in null-map!\n%s\n", errmsg); |
1414 | LOG (llevError, "Trying to insert in null-map!\n%s\n", errmsg); |
1397 | return op; |
1415 | return op; |
1398 | } |
1416 | } |
|
|
1417 | |
1399 | if (out_of_map (m, op->x, op->y)) |
1418 | if (out_of_map (m, op->x, op->y)) |
1400 | { |
1419 | { |
1401 | dump_object (op); |
1420 | dump_object (op); |
1402 | LOG (llevError, "Trying to insert object outside the map.\n%s\n", errmsg); |
1421 | LOG (llevError, "Trying to insert object outside the map.\n%s\n", errmsg); |
1403 | #ifdef MANY_CORES |
1422 | #ifdef MANY_CORES |
… | |
… | |
1407 | */ |
1426 | */ |
1408 | abort (); |
1427 | abort (); |
1409 | #endif |
1428 | #endif |
1410 | return op; |
1429 | return op; |
1411 | } |
1430 | } |
|
|
1431 | |
1412 | if (!QUERY_FLAG (op, FLAG_REMOVED)) |
1432 | if (!QUERY_FLAG (op, FLAG_REMOVED)) |
1413 | { |
1433 | { |
1414 | dump_object (op); |
1434 | dump_object (op); |
1415 | LOG (llevError, "Trying to insert (map) inserted object.\n%s\n", errmsg); |
1435 | LOG (llevError, "Trying to insert (map) inserted object.\n%s\n", errmsg); |
1416 | return op; |
1436 | return op; |
1417 | } |
1437 | } |
|
|
1438 | |
1418 | if (op->more != NULL) |
1439 | if (op->more != NULL) |
1419 | { |
1440 | { |
1420 | /* The part may be on a different map. */ |
1441 | /* The part may be on a different map. */ |
1421 | |
1442 | |
1422 | object * |
1443 | object * |
… | |
… | |
1444 | if (!op->head) |
1465 | if (!op->head) |
1445 | LOG (llevError, "BUG: insert_ob_in_map(): inserting op->more killed op\n"); |
1466 | LOG (llevError, "BUG: insert_ob_in_map(): inserting op->more killed op\n"); |
1446 | return NULL; |
1467 | return NULL; |
1447 | } |
1468 | } |
1448 | } |
1469 | } |
|
|
1470 | |
1449 | CLEAR_FLAG (op, FLAG_REMOVED); |
1471 | CLEAR_FLAG (op, FLAG_REMOVED); |
1450 | |
1472 | |
1451 | /* Ideally, the caller figures this out. However, it complicates a lot |
1473 | /* Ideally, the caller figures this out. However, it complicates a lot |
1452 | * of areas of callers (eg, anything that uses find_free_spot would now |
1474 | * of areas of callers (eg, anything that uses find_free_spot would now |
1453 | * need extra work |
1475 | * need extra work |
… | |
… | |
1457 | y = op->y; |
1479 | y = op->y; |
1458 | |
1480 | |
1459 | /* this has to be done after we translate the coordinates. |
1481 | /* this has to be done after we translate the coordinates. |
1460 | */ |
1482 | */ |
1461 | if (op->nrof && !(flag & INS_NO_MERGE)) |
1483 | if (op->nrof && !(flag & INS_NO_MERGE)) |
1462 | { |
|
|
1463 | for (tmp = GET_MAP_OB (op->map, x, y); tmp != NULL; tmp = tmp->above) |
1484 | for (tmp = GET_MAP_OB (op->map, x, y); tmp != NULL; tmp = tmp->above) |
1464 | if (CAN_MERGE (op, tmp)) |
1485 | if (CAN_MERGE (op, tmp)) |
1465 | { |
1486 | { |
1466 | op->nrof += tmp->nrof; |
1487 | op->nrof += tmp->nrof; |
1467 | remove_ob (tmp); |
1488 | remove_ob (tmp); |
1468 | free_object (tmp); |
1489 | free_object (tmp); |
1469 | } |
1490 | } |
1470 | } |
|
|
1471 | |
1491 | |
1472 | CLEAR_FLAG (op, FLAG_APPLIED); /* hack for fixing F_APPLIED in items of dead people */ |
1492 | CLEAR_FLAG (op, FLAG_APPLIED); /* hack for fixing F_APPLIED in items of dead people */ |
1473 | CLEAR_FLAG (op, FLAG_INV_LOCKED); |
1493 | CLEAR_FLAG (op, FLAG_INV_LOCKED); |
|
|
1494 | |
1474 | if (!QUERY_FLAG (op, FLAG_ALIVE)) |
1495 | if (!QUERY_FLAG (op, FLAG_ALIVE)) |
1475 | CLEAR_FLAG (op, FLAG_NO_STEAL); |
1496 | CLEAR_FLAG (op, FLAG_NO_STEAL); |
1476 | |
1497 | |
1477 | if (flag & INS_BELOW_ORIGINATOR) |
1498 | if (flag & INS_BELOW_ORIGINATOR) |
1478 | { |
1499 | { |
1479 | if (originator->map != op->map || originator->x != op->x || originator->y != op->y) |
1500 | if (originator->map != op->map || originator->x != op->x || originator->y != op->y) |
1480 | { |
1501 | { |
1481 | LOG (llevError, "insert_ob_in_map called with INS_BELOW_ORIGINATOR when originator not on same space!\n"); |
1502 | LOG (llevError, "insert_ob_in_map called with INS_BELOW_ORIGINATOR when originator not on same space!\n"); |
1482 | abort (); |
1503 | abort (); |
1483 | } |
1504 | } |
|
|
1505 | |
1484 | op->above = originator; |
1506 | op->above = originator; |
1485 | op->below = originator->below; |
1507 | op->below = originator->below; |
|
|
1508 | |
1486 | if (op->below) |
1509 | if (op->below) |
1487 | op->below->above = op; |
1510 | op->below->above = op; |
1488 | else |
1511 | else |
1489 | SET_MAP_OB (op->map, op->x, op->y, op); |
1512 | SET_MAP_OB (op->map, op->x, op->y, op); |
|
|
1513 | |
1490 | /* since *below* originator, no need to update top */ |
1514 | /* since *below* originator, no need to update top */ |
1491 | originator->below = op; |
1515 | originator->below = op; |
1492 | } |
1516 | } |
1493 | else |
1517 | else |
1494 | { |
1518 | { |
1495 | /* If there are other objects, then */ |
1519 | /* If there are other objects, then */ |
1496 | if ((!(flag & INS_MAP_LOAD)) && ((top = GET_MAP_OB (op->map, op->x, op->y)) != NULL)) |
1520 | if ((!(flag & INS_MAP_LOAD)) && ((top = GET_MAP_OB (op->map, op->x, op->y)) != NULL)) |
1497 | { |
1521 | { |
1498 | object * |
|
|
1499 | last = NULL; |
1522 | object *last = NULL; |
1500 | |
1523 | |
1501 | /* |
1524 | /* |
1502 | * If there are multiple objects on this space, we do some trickier handling. |
1525 | * If there are multiple objects on this space, we do some trickier handling. |
1503 | * We've already dealt with merging if appropriate. |
1526 | * We've already dealt with merging if appropriate. |
1504 | * Generally, we want to put the new object on top. But if |
1527 | * Generally, we want to put the new object on top. But if |
… | |
… | |
1551 | */ |
1574 | */ |
1552 | if (last && last->below && last != floor) |
1575 | if (last && last->below && last != floor) |
1553 | top = last->below; |
1576 | top = last->below; |
1554 | } |
1577 | } |
1555 | } /* If objects on this space */ |
1578 | } /* If objects on this space */ |
|
|
1579 | |
1556 | if (flag & INS_MAP_LOAD) |
1580 | if (flag & INS_MAP_LOAD) |
1557 | top = GET_MAP_TOP (op->map, op->x, op->y); |
1581 | top = GET_MAP_TOP (op->map, op->x, op->y); |
|
|
1582 | |
1558 | if (flag & INS_ABOVE_FLOOR_ONLY) |
1583 | if (flag & INS_ABOVE_FLOOR_ONLY) |
1559 | top = floor; |
1584 | top = floor; |
1560 | |
1585 | |
1561 | /* Top is the object that our object (op) is going to get inserted above. |
1586 | /* Top is the object that our object (op) is going to get inserted above. |
1562 | */ |
1587 | */ |
1563 | |
1588 | |
1564 | /* First object on this space */ |
1589 | /* First object on this space */ |
1565 | if (!top) |
1590 | if (!top) |
1566 | { |
1591 | { |
1567 | op->above = GET_MAP_OB (op->map, op->x, op->y); |
1592 | op->above = GET_MAP_OB (op->map, op->x, op->y); |
|
|
1593 | |
1568 | if (op->above) |
1594 | if (op->above) |
1569 | op->above->below = op; |
1595 | op->above->below = op; |
|
|
1596 | |
1570 | op->below = NULL; |
1597 | op->below = NULL; |
1571 | SET_MAP_OB (op->map, op->x, op->y, op); |
1598 | SET_MAP_OB (op->map, op->x, op->y, op); |
1572 | } |
1599 | } |
1573 | else |
1600 | else |
1574 | { /* get inserted into the stack above top */ |
1601 | { /* get inserted into the stack above top */ |
1575 | op->above = top->above; |
1602 | op->above = top->above; |
|
|
1603 | |
1576 | if (op->above) |
1604 | if (op->above) |
1577 | op->above->below = op; |
1605 | op->above->below = op; |
|
|
1606 | |
1578 | op->below = top; |
1607 | op->below = top; |
1579 | top->above = op; |
1608 | top->above = op; |
1580 | } |
1609 | } |
|
|
1610 | |
1581 | if (op->above == NULL) |
1611 | if (op->above == NULL) |
1582 | SET_MAP_TOP (op->map, op->x, op->y, op); |
1612 | SET_MAP_TOP (op->map, op->x, op->y, op); |
1583 | } /* else not INS_BELOW_ORIGINATOR */ |
1613 | } /* else not INS_BELOW_ORIGINATOR */ |
1584 | |
1614 | |
1585 | if (op->type == PLAYER) |
1615 | if (op->type == PLAYER) |
… | |
… | |
1588 | /* If we have a floor, we know the player, if any, will be above |
1618 | /* If we have a floor, we know the player, if any, will be above |
1589 | * it, so save a few ticks and start from there. |
1619 | * it, so save a few ticks and start from there. |
1590 | */ |
1620 | */ |
1591 | if (!(flag & INS_MAP_LOAD)) |
1621 | if (!(flag & INS_MAP_LOAD)) |
1592 | for (tmp = floor ? floor : GET_MAP_OB (op->map, op->x, op->y); tmp != NULL; tmp = tmp->above) |
1622 | for (tmp = floor ? floor : GET_MAP_OB (op->map, op->x, op->y); tmp != NULL; tmp = tmp->above) |
1593 | { |
|
|
1594 | if (tmp->type == PLAYER) |
1623 | if (tmp->type == PLAYER) |
1595 | tmp->contr->socket.update_look = 1; |
1624 | tmp->contr->socket.update_look = 1; |
1596 | } |
|
|
1597 | |
1625 | |
1598 | /* If this object glows, it may affect lighting conditions that are |
1626 | /* If this object glows, it may affect lighting conditions that are |
1599 | * visible to others on this map. But update_all_los is really |
1627 | * visible to others on this map. But update_all_los is really |
1600 | * an inefficient way to do this, as it means los for all players |
1628 | * an inefficient way to do this, as it means los for all players |
1601 | * on the map will get recalculated. The players could very well |
1629 | * on the map will get recalculated. The players could very well |
… | |
… | |
1620 | * blocked() and wall() work properly), and these flags are updated by |
1648 | * blocked() and wall() work properly), and these flags are updated by |
1621 | * update_object(). |
1649 | * update_object(). |
1622 | */ |
1650 | */ |
1623 | |
1651 | |
1624 | /* if this is not the head or flag has been passed, don't check walk on status */ |
1652 | /* if this is not the head or flag has been passed, don't check walk on status */ |
1625 | |
|
|
1626 | if (!(flag & INS_NO_WALK_ON) && !op->head) |
1653 | if (!(flag & INS_NO_WALK_ON) && !op->head) |
1627 | { |
1654 | { |
1628 | if (check_move_on (op, originator)) |
1655 | if (check_move_on (op, originator)) |
1629 | return NULL; |
1656 | return NULL; |
1630 | |
1657 | |
… | |
… | |
1633 | */ |
1660 | */ |
1634 | for (tmp = op->more; tmp != NULL; tmp = tmp->more) |
1661 | for (tmp = op->more; tmp != NULL; tmp = tmp->more) |
1635 | if (check_move_on (tmp, originator)) |
1662 | if (check_move_on (tmp, originator)) |
1636 | return NULL; |
1663 | return NULL; |
1637 | } |
1664 | } |
|
|
1665 | |
1638 | return op; |
1666 | return op; |
1639 | } |
1667 | } |
1640 | |
1668 | |
1641 | /* this function inserts an object in the map, but if it |
1669 | /* this function inserts an object in the map, but if it |
1642 | * finds an object of its own type, it'll remove that one first. |
1670 | * finds an object of its own type, it'll remove that one first. |
1643 | * op is the object to insert it under: supplies x and the map. |
1671 | * op is the object to insert it under: supplies x and the map. |
1644 | */ |
1672 | */ |
1645 | void |
1673 | void |
1646 | replace_insert_ob_in_map (const char *arch_string, object *op) |
1674 | replace_insert_ob_in_map (const char *arch_string, object *op) |
1647 | { |
1675 | { |
1648 | object * |
1676 | object *tmp; |
1649 | tmp; |
|
|
1650 | object * |
1677 | object *tmp1; |
1651 | tmp1; |
|
|
1652 | |
1678 | |
1653 | /* first search for itself and remove any old instances */ |
1679 | /* first search for itself and remove any old instances */ |
1654 | |
1680 | |
1655 | for (tmp = GET_MAP_OB (op->map, op->x, op->y); tmp != NULL; tmp = tmp->above) |
1681 | for (tmp = GET_MAP_OB (op->map, op->x, op->y); tmp != NULL; tmp = tmp->above) |
1656 | { |
1682 | { |
… | |
… | |
1660 | free_object (tmp); |
1686 | free_object (tmp); |
1661 | } |
1687 | } |
1662 | } |
1688 | } |
1663 | |
1689 | |
1664 | tmp1 = arch_to_object (find_archetype (arch_string)); |
1690 | tmp1 = arch_to_object (find_archetype (arch_string)); |
1665 | |
|
|
1666 | |
1691 | |
1667 | tmp1->x = op->x; |
1692 | tmp1->x = op->x; |
1668 | tmp1->y = op->y; |
1693 | tmp1->y = op->y; |
1669 | insert_ob_in_map (tmp1, op->map, op, 0); |
1694 | insert_ob_in_map (tmp1, op->map, op, 0); |
1670 | } |
1695 | } |