… | |
… | |
1341 | |
1341 | |
1342 | recursion_depth++; |
1342 | recursion_depth++; |
1343 | if (trap->head) |
1343 | if (trap->head) |
1344 | trap = trap->head; |
1344 | trap = trap->head; |
1345 | |
1345 | |
1346 | if (INVOKE_OBJECT (MOVE_TRIGGER, trap, ARG_OBJECT (victim), ARG_OBJECT (originator))) |
1346 | if (!INVOKE_OBJECT (MOVE_TRIGGER, trap, ARG_OBJECT (victim), ARG_OBJECT (originator))) |
1347 | goto leave; |
|
|
1348 | |
|
|
1349 | switch (trap->type) |
1347 | switch (trap->type) |
1350 | { |
1348 | { |
1351 | case PLAYERMOVER: |
1349 | case PLAYERMOVER: |
1352 | if (trap->attacktype && (trap->level || victim->type != PLAYER) && !should_director_abort (trap, victim)) |
1350 | if (trap->attacktype && (trap->level || victim->type != PLAYER) && !should_director_abort (trap, victim)) |
|
|
1351 | { |
|
|
1352 | if (!trap->stats.maxsp) |
|
|
1353 | trap->stats.maxsp = 2; |
|
|
1354 | |
|
|
1355 | /* Is this correct? From the docs, it doesn't look like it |
|
|
1356 | * should be divided by trap->speed |
|
|
1357 | */ |
|
|
1358 | victim->speed_left = -FABS (trap->stats.maxsp * victim->speed / trap->speed); |
|
|
1359 | |
|
|
1360 | /* Just put in some sanity check. I think there is a bug in the |
|
|
1361 | * above with some objects have zero speed, and thus the player |
|
|
1362 | * getting permanently paralyzed. |
|
|
1363 | */ |
|
|
1364 | if (victim->speed_left < -50.f) |
|
|
1365 | victim->speed_left = -50.f; |
|
|
1366 | /* LOG(llevDebug, "apply, playermove, player speed_left=%f\n", victim->speed_left); */ |
|
|
1367 | } |
|
|
1368 | break; |
|
|
1369 | |
|
|
1370 | case SPINNER: |
|
|
1371 | if (victim->direction) |
|
|
1372 | { |
|
|
1373 | victim->direction = absdir (victim->direction - trap->stats.sp); |
|
|
1374 | update_turn_face (victim); |
|
|
1375 | } |
|
|
1376 | break; |
|
|
1377 | |
|
|
1378 | case DIRECTOR: |
|
|
1379 | if (victim->direction && !should_director_abort (trap, victim)) |
|
|
1380 | { |
|
|
1381 | victim->direction = trap->stats.sp; |
|
|
1382 | update_turn_face (victim); |
|
|
1383 | } |
|
|
1384 | break; |
|
|
1385 | |
|
|
1386 | case BUTTON: |
|
|
1387 | case PEDESTAL: |
|
|
1388 | update_button (trap, originator); |
|
|
1389 | break; |
|
|
1390 | |
|
|
1391 | case ALTAR: |
|
|
1392 | /* sacrifice victim on trap */ |
|
|
1393 | apply_altar (trap, victim, originator); |
|
|
1394 | break; |
|
|
1395 | |
|
|
1396 | case THROWN_OBJ: |
|
|
1397 | if (trap->inv == NULL) |
|
|
1398 | break; |
|
|
1399 | /* fallthrough */ |
|
|
1400 | |
|
|
1401 | case ARROW: |
|
|
1402 | /* bad bug: monster throw a object, make a step forwards, step on object , |
|
|
1403 | * trigger this here and get hit by own missile - and will be own enemy. |
|
|
1404 | * Victim then is his own enemy and will start to kill herself (this is |
|
|
1405 | * removed) but we have not synced victim and his missile. To avoid senseless |
|
|
1406 | * action, we avoid hits here |
|
|
1407 | */ |
|
|
1408 | if ((QUERY_FLAG (victim, FLAG_ALIVE) && trap->speed) && trap->owner != victim) |
|
|
1409 | hit_with_arrow (trap, victim); |
|
|
1410 | break; |
|
|
1411 | |
|
|
1412 | case SPELL_EFFECT: |
|
|
1413 | apply_spell_effect (trap, victim); |
|
|
1414 | break; |
|
|
1415 | |
|
|
1416 | case TRAPDOOR: |
1353 | { |
1417 | { |
|
|
1418 | int max, sound_was_played; |
|
|
1419 | object *ab, *ab_next; |
|
|
1420 | |
1354 | if (!trap->stats.maxsp) |
1421 | if (!trap->value) |
1355 | trap->stats.maxsp = 2; |
1422 | { |
|
|
1423 | int tot; |
1356 | |
1424 | |
1357 | /* Is this correct? From the docs, it doesn't look like it |
1425 | for (ab = trap->above, tot = 0; ab; ab = ab->above) |
1358 | * should be divided by trap->speed |
1426 | if ((ab->move_type && trap->move_on) || ab->move_type == 0) |
|
|
1427 | tot += ab->head_ ()->total_weight (); |
|
|
1428 | |
|
|
1429 | if (!(trap->value = (tot > trap->weight) ? 1 : 0)) |
|
|
1430 | break; |
|
|
1431 | |
|
|
1432 | SET_ANIMATION (trap, trap->value); |
|
|
1433 | update_object (trap, UP_OBJ_FACE); |
|
|
1434 | } |
|
|
1435 | |
|
|
1436 | for (ab = trap->above, max = 100, sound_was_played = 0; --max && ab; ab = ab_next) |
|
|
1437 | { |
|
|
1438 | /* need to set this up, since if we do transfer the object, |
|
|
1439 | * ab->above would be bogus |
1359 | */ |
1440 | */ |
1360 | victim->speed_left = -FABS (trap->stats.maxsp * victim->speed / trap->speed); |
1441 | ab_next = ab->above; |
1361 | |
1442 | |
1362 | /* Just put in some sanity check. I think there is a bug in the |
1443 | if ((ab->move_type && trap->move_on) || ab->move_type == 0) |
1363 | * above with some objects have zero speed, and thus the player |
1444 | { |
1364 | * getting permanently paralyzed. |
1445 | if (!sound_was_played) |
|
|
1446 | { |
|
|
1447 | trap->play_sound (trap->sound ? trap->sound : sound_find ("fall_hole")); |
|
|
1448 | sound_was_played = 1; |
|
|
1449 | } |
|
|
1450 | |
|
|
1451 | ab->statusmsg ("You fall into a trapdoor!", NDI_RED); |
|
|
1452 | transfer_ob (ab, EXIT_X (trap), EXIT_Y (trap), 0, ab); |
|
|
1453 | } |
1365 | */ |
1454 | } |
1366 | if (victim->speed_left < -50.f) |
1455 | break; |
1367 | victim->speed_left = -50.f; |
|
|
1368 | /* LOG(llevDebug, "apply, playermove, player speed_left=%f\n", victim->speed_left); */ |
|
|
1369 | } |
1456 | } |
1370 | goto leave; |
|
|
1371 | |
1457 | |
1372 | case SPINNER: |
1458 | case CONVERTER: |
1373 | if (victim->direction) |
1459 | if (convert_item (victim, trap) < 0) |
1374 | { |
|
|
1375 | victim->direction = absdir (victim->direction - trap->stats.sp); |
|
|
1376 | update_turn_face (victim); |
|
|
1377 | } |
|
|
1378 | goto leave; |
|
|
1379 | |
|
|
1380 | case DIRECTOR: |
|
|
1381 | if (victim->direction && !should_director_abort (trap, victim)) |
|
|
1382 | { |
|
|
1383 | victim->direction = trap->stats.sp; |
|
|
1384 | update_turn_face (victim); |
|
|
1385 | } |
|
|
1386 | goto leave; |
|
|
1387 | |
|
|
1388 | case BUTTON: |
|
|
1389 | case PEDESTAL: |
|
|
1390 | update_button (trap, originator); |
|
|
1391 | goto leave; |
|
|
1392 | |
|
|
1393 | case ALTAR: |
|
|
1394 | /* sacrifice victim on trap */ |
|
|
1395 | apply_altar (trap, victim, originator); |
|
|
1396 | goto leave; |
|
|
1397 | |
|
|
1398 | case THROWN_OBJ: |
|
|
1399 | if (trap->inv == NULL) |
|
|
1400 | goto leave; |
|
|
1401 | /* fallthrough */ |
|
|
1402 | |
|
|
1403 | case ARROW: |
|
|
1404 | /* bad bug: monster throw a object, make a step forwards, step on object , |
|
|
1405 | * trigger this here and get hit by own missile - and will be own enemy. |
|
|
1406 | * Victim then is his own enemy and will start to kill herself (this is |
|
|
1407 | * removed) but we have not synced victim and his missile. To avoid senseless |
|
|
1408 | * action, we avoid hits here |
|
|
1409 | */ |
|
|
1410 | if ((QUERY_FLAG (victim, FLAG_ALIVE) && trap->speed) && trap->owner != victim) |
|
|
1411 | hit_with_arrow (trap, victim); |
|
|
1412 | goto leave; |
|
|
1413 | |
|
|
1414 | case SPELL_EFFECT: |
|
|
1415 | apply_spell_effect (trap, victim); |
|
|
1416 | goto leave; |
|
|
1417 | |
|
|
1418 | case TRAPDOOR: |
|
|
1419 | { |
|
|
1420 | int max, sound_was_played; |
|
|
1421 | object *ab, *ab_next; |
|
|
1422 | |
|
|
1423 | if (!trap->value) |
|
|
1424 | { |
1460 | { |
1425 | int tot; |
1461 | originator->failmsg (format ("The %s seems to be broken!", query_name (trap))); |
1426 | |
1462 | archetype::get (shstr_burnout)->insert_at (trap, trap); |
1427 | for (ab = trap->above, tot = 0; ab; ab = ab->above) |
|
|
1428 | if ((ab->move_type && trap->move_on) || ab->move_type == 0) |
|
|
1429 | tot += ab->head_ ()->total_weight (); |
|
|
1430 | |
|
|
1431 | if (!(trap->value = (tot > trap->weight) ? 1 : 0)) |
|
|
1432 | goto leave; |
|
|
1433 | |
|
|
1434 | SET_ANIMATION (trap, trap->value); |
|
|
1435 | update_object (trap, UP_OBJ_FACE); |
|
|
1436 | } |
1463 | } |
1437 | |
1464 | |
1438 | for (ab = trap->above, max = 100, sound_was_played = 0; --max && ab; ab = ab_next) |
1465 | break; |
|
|
1466 | |
|
|
1467 | case TRIGGER_BUTTON: |
|
|
1468 | case TRIGGER_PEDESTAL: |
|
|
1469 | case TRIGGER_ALTAR: |
|
|
1470 | check_trigger (trap, victim); |
|
|
1471 | break; |
|
|
1472 | |
|
|
1473 | case DEEP_SWAMP: |
|
|
1474 | walk_on_deep_swamp (trap, victim); |
|
|
1475 | break; |
|
|
1476 | |
|
|
1477 | case CHECK_INV: |
|
|
1478 | check_inv (victim, trap); |
|
|
1479 | break; |
|
|
1480 | |
|
|
1481 | case HOLE: |
|
|
1482 | move_apply_hole (trap, victim); |
|
|
1483 | break; |
|
|
1484 | |
|
|
1485 | case EXIT: |
|
|
1486 | if (victim->type == PLAYER && EXIT_PATH (trap)) |
1439 | { |
1487 | { |
1440 | /* need to set this up, since if we do transfer the object, |
1488 | /* Basically, don't show exits leading to random maps the |
1441 | * ab->above would be bogus |
1489 | * players output. |
1442 | */ |
1490 | */ |
1443 | ab_next = ab->above; |
1491 | if (trap->msg && !EXIT_PATH (trap).starts_with ("/!")) |
|
|
1492 | victim->statusmsg (trap->msg, NDI_NAVY); |
1444 | |
1493 | |
1445 | if ((ab->move_type && trap->move_on) || ab->move_type == 0) |
1494 | trap->play_sound (trap->sound); |
1446 | { |
1495 | victim->enter_exit (trap); |
1447 | if (!sound_was_played) |
|
|
1448 | { |
|
|
1449 | trap->play_sound (trap->sound ? trap->sound : sound_find ("fall_hole")); |
|
|
1450 | sound_was_played = 1; |
|
|
1451 | } |
|
|
1452 | |
|
|
1453 | ab->statusmsg ("You fall into a trapdoor!", NDI_RED); |
|
|
1454 | transfer_ob (ab, EXIT_X (trap), EXIT_Y (trap), 0, ab); |
|
|
1455 | } |
|
|
1456 | } |
1496 | } |
1457 | goto leave; |
1497 | break; |
1458 | } |
|
|
1459 | |
1498 | |
1460 | case CONVERTER: |
|
|
1461 | if (convert_item (victim, trap) < 0) |
|
|
1462 | { |
|
|
1463 | originator->failmsg (format ("The %s seems to be broken!", query_name (trap))); |
|
|
1464 | archetype::get (shstr_burnout)->insert_at (trap, trap); |
|
|
1465 | } |
|
|
1466 | |
|
|
1467 | goto leave; |
|
|
1468 | |
|
|
1469 | case TRIGGER_BUTTON: |
|
|
1470 | case TRIGGER_PEDESTAL: |
|
|
1471 | case TRIGGER_ALTAR: |
|
|
1472 | check_trigger (trap, victim); |
|
|
1473 | goto leave; |
|
|
1474 | |
|
|
1475 | case DEEP_SWAMP: |
|
|
1476 | walk_on_deep_swamp (trap, victim); |
|
|
1477 | goto leave; |
|
|
1478 | |
|
|
1479 | case CHECK_INV: |
|
|
1480 | check_inv (victim, trap); |
|
|
1481 | goto leave; |
|
|
1482 | |
|
|
1483 | case HOLE: |
|
|
1484 | move_apply_hole (trap, victim); |
|
|
1485 | goto leave; |
|
|
1486 | |
|
|
1487 | case EXIT: |
|
|
1488 | if (victim->type == PLAYER && EXIT_PATH (trap)) |
|
|
1489 | { |
|
|
1490 | /* Basically, don't show exits leading to random maps the |
|
|
1491 | * players output. |
|
|
1492 | */ |
|
|
1493 | if (trap->msg && !EXIT_PATH (trap).starts_with ("/!")) |
|
|
1494 | victim->statusmsg (trap->msg, NDI_NAVY); |
|
|
1495 | |
|
|
1496 | trap->play_sound (trap->sound); |
|
|
1497 | victim->enter_exit (trap); |
|
|
1498 | } |
|
|
1499 | goto leave; |
|
|
1500 | |
|
|
1501 | case ENCOUNTER: |
1499 | case ENCOUNTER: |
1502 | /* may be some leftovers on this */ |
1500 | /* may be some leftovers on this */ |
1503 | goto leave; |
1501 | break; |
1504 | |
1502 | |
1505 | case SHOP_MAT: |
1503 | case SHOP_MAT: |
1506 | apply_shop_mat (trap, victim); |
1504 | apply_shop_mat (trap, victim); |
1507 | goto leave; |
1505 | break; |
1508 | |
1506 | |
1509 | /* Drop a certain amount of gold, and have one item identified */ |
1507 | /* Drop a certain amount of gold, and have one item identified */ |
1510 | case IDENTIFY_ALTAR: |
1508 | case IDENTIFY_ALTAR: |
1511 | apply_id_altar (victim, trap, originator); |
1509 | apply_id_altar (victim, trap, originator); |
1512 | goto leave; |
1510 | break; |
1513 | |
1511 | |
1514 | case SIGN: |
1512 | case SIGN: |
1515 | if (victim->type != PLAYER && trap->stats.food > 0) |
1513 | if (victim->type != PLAYER && trap->stats.food > 0) |
1516 | goto leave; /* monsters musn't apply magic_mouths with counters */ |
1514 | break; /* monsters musn't apply magic_mouths with counters */ |
1517 | |
1515 | |
1518 | apply_sign (victim, trap, 1); |
1516 | apply_sign (victim, trap, 1); |
1519 | goto leave; |
1517 | break; |
1520 | |
1518 | |
1521 | case CONTAINER: |
1519 | case CONTAINER: |
1522 | apply_container (victim, trap); |
1520 | apply_container (victim, trap); |
1523 | goto leave; |
1521 | break; |
1524 | |
1522 | |
1525 | case RUNE: |
1523 | case RUNE: |
1526 | case TRAP: |
1524 | case TRAP: |
1527 | if (trap->level && QUERY_FLAG (victim, FLAG_ALIVE)) |
1525 | if (trap->level && QUERY_FLAG (victim, FLAG_ALIVE)) |
1528 | spring_trap (trap, victim); |
1526 | spring_trap (trap, victim); |
1529 | goto leave; |
1527 | break; |
1530 | |
1528 | |
1531 | default: |
1529 | default: |
1532 | LOG (llevDebug, "name %s, arch %s, type %d with fly/walk on/off not " |
1530 | LOG (llevDebug, "name %s, arch %s, type %d with fly/walk on/off not " |
1533 | "handled in move_apply()\n", &trap->name, &trap->arch->archname, trap->type); |
1531 | "handled in move_apply()\n", &trap->name, &trap->arch->archname, trap->type); |
1534 | goto leave; |
1532 | break; |
1535 | } |
1533 | } |
1536 | |
1534 | |
1537 | leave: |
|
|
1538 | recursion_depth--; |
1535 | recursion_depth--; |
1539 | } |
1536 | } |
1540 | |
1537 | |
1541 | /** |
1538 | /** |
1542 | * Handles reading a regular (ie not containing a spell) book. |
1539 | * Handles reading a regular (ie not containing a spell) book. |