536 |
return "st-stone"; |
return "st-stone"; |
537 |
} |
} |
538 |
|
|
539 |
|
bool Stone::move_stone(Direction dir) { |
540 |
|
GridPos p = get_pos(); |
541 |
|
GridPos newPos = move(p, dir); |
542 |
|
|
543 |
|
if (!GetStone(newPos)) { |
544 |
|
play_sound("st-move"); |
545 |
|
SetStone(newPos, YieldStone(p)); |
546 |
|
on_move(); |
547 |
|
if (Item *it = GetItem(newPos)) it->on_stonehit(this); |
548 |
|
|
549 |
|
return true; |
550 |
|
} |
551 |
|
return false; |
552 |
|
} |
553 |
|
|
554 |
|
|
555 |
//---------------------------------------- |
//---------------------------------------- |
556 |
// SimpleStone |
// SimpleStone |
557 |
// |
// |
1568 |
|
|
1569 |
void alarm() { |
void alarm() { |
1570 |
state = MOVING; |
state = MOVING; |
1571 |
GridPos p = get_pos(); |
GridPos p = get_pos(); |
1572 |
|
#if defined(USE_IMPULSES) |
1573 |
|
if (move_stone(get_dir())) { |
1574 |
|
#else |
1575 |
if (world::MaybeMoveStone(p, get_dir())) { |
if (world::MaybeMoveStone(p, get_dir())) { |
1576 |
|
#endif // USE_IMPULSES |
1577 |
// send a message to the stone that's blocking our way |
// send a message to the stone that's blocking our way |
1578 |
Stone *st = GetStone(move(move(p,get_dir()),get_dir())); |
Stone *st = GetStone(move(move(p,get_dir()),get_dir())); |
1579 |
if( st) |
if( st) SendMessage(st, "trigger"); |
|
SendMessage(st, "trigger"); |
|
1580 |
} |
} |
1581 |
state = IDLE; |
state = IDLE; |
1582 |
} |
} |
1696 |
bool on_laserhit(Direction dir) { |
bool on_laserhit(Direction dir) { |
1697 |
return get_connections() == 0; |
return get_connections() == 0; |
1698 |
} |
} |
1699 |
|
#if defined(USE_IMPULSES) |
1700 |
|
virtual void on_impulse(Direction dir); |
1701 |
|
#endif // USE_IMPULSES |
1702 |
|
|
1703 |
void init_model(); |
void init_model(); |
1704 |
StoneResponse collision_response(const StoneContact &sc); |
StoneResponse collision_response(const StoneContact &sc); |
1898 |
return STONE_REBOUND; |
return STONE_REBOUND; |
1899 |
} |
} |
1900 |
|
|
1901 |
|
#if defined(USE_IMPULSES) |
1902 |
|
void |
1903 |
|
PuzzleStone::on_impulse(Direction dir) { |
1904 |
|
// fprintf(stderr, "PuzzleStone::on_impulse(%s)\n", to_suffix(dir).c_str()); |
1905 |
|
Cluster c; |
1906 |
|
bool is_complete = find_cluster(c); |
1907 |
|
maybe_move_cluster(c, is_complete, dir); |
1908 |
|
} |
1909 |
|
|
1910 |
|
void |
1911 |
|
PuzzleStone::actor_hit(const StoneContact &sc) |
1912 |
|
{ |
1913 |
|
if (get_connections() == NODIRBIT) |
1914 |
|
return; |
1915 |
|
|
1916 |
|
Actor *a = sc.actor; |
1917 |
|
|
1918 |
|
bool move_impulse= (a->get_vel()*sc.normal < -4); |
1919 |
|
Direction hit_dir=reverse(contact_face(sc)); |
1920 |
|
|
1921 |
|
if (wielded_item_is(a, "it-magicwand")) { |
1922 |
|
if (cluster_complete()) { |
1923 |
|
// make all cluster stones explode |
1924 |
|
return; |
1925 |
|
} |
1926 |
|
else if (hit_dir != NODIR) { |
1927 |
|
Cluster c; |
1928 |
|
find_row_or_column_cluster(c, get_pos(), hit_dir); |
1929 |
|
|
1930 |
|
bool is_complete = false; |
1931 |
|
|
1932 |
|
if (move_impulse) |
1933 |
|
maybe_move_cluster(c, is_complete, hit_dir); |
1934 |
|
else |
1935 |
|
rotate_cluster(c); |
1936 |
|
} |
1937 |
|
} |
1938 |
|
else if (move_impulse && hit_dir != NODIR) { |
1939 |
|
SendImpulse(get_pos(), hit_dir); |
1940 |
|
} |
1941 |
|
} |
1942 |
|
#else |
1943 |
void |
void |
1944 |
PuzzleStone::actor_hit(const StoneContact &sc) |
PuzzleStone::actor_hit(const StoneContact &sc) |
1945 |
{ |
{ |
1974 |
maybe_move_cluster(c, is_complete, hit_dir); |
maybe_move_cluster(c, is_complete, hit_dir); |
1975 |
} |
} |
1976 |
} |
} |
1977 |
|
#endif // USE_IMPULSES |
1978 |
|
|
1979 |
|
|
1980 |
//---------------------------------------- |
//---------------------------------------- |
2574 |
notify_item(false); |
notify_item(false); |
2575 |
} |
} |
2576 |
|
|
2577 |
|
#if defined(USE_IMPULSES) |
2578 |
|
void on_impulse(Direction dir); |
2579 |
|
#endif // USE_IMPULSES |
2580 |
|
|
2581 |
void init_model() { |
void init_model() { |
2582 |
char x[20]; |
char x[20]; |
2583 |
sprintf(x, "st-shogun%d", int(get_holes())); |
sprintf(x, "st-shogun%d", int(get_holes())); |
2700 |
return nh; |
return nh; |
2701 |
} |
} |
2702 |
|
|
2703 |
|
#if defined(USE_IMPULSES) |
2704 |
|
void |
2705 |
|
ShogunStone::actor_hit(const StoneContact &sc) |
2706 |
|
{ |
2707 |
|
Actor *a = sc.actor; |
2708 |
|
bool move_impulse = (a->get_vel()*sc.normal < -4); |
2709 |
|
Direction hit_dir = reverse(contact_face(sc)); |
2710 |
|
|
2711 |
|
if (hit_dir == NODIR || !move_impulse) |
2712 |
|
return; |
2713 |
|
|
2714 |
|
SendImpulse(get_pos(), hit_dir); |
2715 |
|
} |
2716 |
|
|
2717 |
|
void |
2718 |
|
ShogunStone::on_impulse(Direction dir) { |
2719 |
|
// fprintf(stderr, "ShogunStone::on_impulse(%s)\n", to_suffix(dir).c_str()); |
2720 |
|
Holes holes = get_holes(); |
2721 |
|
Holes newholes = transfer_smallest_hole(move(get_pos(), dir)); |
2722 |
|
|
2723 |
|
if (newholes != holes) { |
2724 |
|
play_sound("st-move"); |
2725 |
|
} |
2726 |
|
} |
2727 |
|
|
2728 |
|
#else |
2729 |
void |
void |
2730 |
ShogunStone::actor_hit(const StoneContact &sc) |
ShogunStone::actor_hit(const StoneContact &sc) |
2731 |
{ |
{ |
2743 |
play_sound("st-move"); |
play_sound("st-move"); |
2744 |
} |
} |
2745 |
} |
} |
2746 |
|
#endif // USE_IMPULSES |
2747 |
|
|
2748 |
|
|
2749 |
//---------------------------------------- |
//---------------------------------------- |
2950 |
else if (state == CLOSING) |
else if (state == CLOSING) |
2951 |
change_state (IDLE); |
change_state (IDLE); |
2952 |
} |
} |
2953 |
|
|
2954 |
|
#if defined(USE_IMPULSES) |
2955 |
|
virtual void on_impulse(Direction dir) { |
2956 |
|
// fprintf(stderr, "StoneImpulse_Base::on_impulse(%s)\n", to_suffix(dir).c_str()); |
2957 |
|
change_state(PULSING); |
2958 |
|
} |
2959 |
|
#endif // USE_IMPULSES |
2960 |
}; |
}; |
2961 |
|
|
2962 |
} |
} |
2970 |
switch (st) { |
switch (st) { |
2971 |
case PULSING: |
case PULSING: |
2972 |
if (state != IDLE) |
if (state != IDLE) |
2973 |
return; // do not set new state |
return; // do not set new state |
2974 |
play_sound("impulse"); |
play_sound("impulse"); |
2975 |
break; |
break; |
2976 |
case CLOSING: |
case CLOSING: |
2977 |
MaybeMoveStone( move( p, NORTH), NORTH); |
{ |
2978 |
MaybeMoveStone( move( p, EAST), EAST); |
#if defined(USE_IMPULSES) |
2979 |
MaybeMoveStone( move( p, SOUTH), SOUTH); |
|
2980 |
MaybeMoveStone( move( p, WEST), WEST); |
// @@@ FIXME: Send impulses in a defined order depending |
2981 |
SendMessage (GetStone(move(p, NORTH)), "stoneimpulse"); |
// on the direction of the initial impulse |
2982 |
SendMessage (GetStone(move(p, EAST)), "stoneimpulse"); |
|
2983 |
SendMessage (GetStone(move(p, SOUTH)), "stoneimpulse"); |
GridPos targetpos[4]; |
2984 |
SendMessage (GetStone(move(p, WEST)), "stoneimpulse"); |
bool haveStone[4]; |
2985 |
break; |
|
2986 |
|
for (int d = 0; d < 4; ++d) { |
2987 |
|
targetpos[d] = move(p, Direction(d)); |
2988 |
|
haveStone[d] = GetStone(targetpos[d]) != 0; |
2989 |
|
} |
2990 |
|
|
2991 |
|
for (int d = 0; d < 4; ++d) { |
2992 |
|
if (haveStone[d]) { |
2993 |
|
SendImpulse(targetpos[d], Direction(d)); |
2994 |
|
} |
2995 |
|
} |
2996 |
|
// SendImpulse(move(p, NORTH), NORTH); |
2997 |
|
// SendImpulse(move(p, EAST), EAST); |
2998 |
|
// SendImpulse(move(p, SOUTH), SOUTH); |
2999 |
|
// SendImpulse(move(p, WEST), WEST); |
3000 |
|
#else |
3001 |
|
MaybeMoveStone( move( p, NORTH), NORTH); |
3002 |
|
MaybeMoveStone( move( p, EAST), EAST); |
3003 |
|
MaybeMoveStone( move( p, SOUTH), SOUTH); |
3004 |
|
MaybeMoveStone( move( p, WEST), WEST); |
3005 |
|
SendMessage (GetStone(move(p, NORTH)), "stoneimpulse"); |
3006 |
|
SendMessage (GetStone(move(p, EAST)), "stoneimpulse"); |
3007 |
|
SendMessage (GetStone(move(p, SOUTH)), "stoneimpulse"); |
3008 |
|
SendMessage (GetStone(move(p, WEST)), "stoneimpulse"); |
3009 |
|
#endif // USE_IMPULSES |
3010 |
|
break; |
3011 |
|
} |
3012 |
case IDLE: |
case IDLE: |
3013 |
init_model(); |
init_model(); |
3014 |
break; |
break; |
3109 |
|
|
3110 |
// Stone interface: |
// Stone interface: |
3111 |
|
|
3112 |
|
#if defined(USE_IMPULSES) |
3113 |
|
void on_impulse(Direction dir) { |
3114 |
|
// fprintf(stderr, "MovableImpulseStone::on_impulse(%s)\n", to_suffix(dir).c_str()); |
3115 |
|
if (!move_stone(dir)) { |
3116 |
|
change_state(PULSING); |
3117 |
|
} |
3118 |
|
// otherwise on_move changes state to PULSING |
3119 |
|
} |
3120 |
|
void actor_hit(const StoneContact &sc) { |
3121 |
|
ActorInfo *ai = sc.actor->get_actorinfo(); |
3122 |
|
Direction dir = contact_face(sc); |
3123 |
|
|
3124 |
|
if (dir!=enigma::NODIR && ai->vel * sc.normal < -4) { |
3125 |
|
SendImpulse(get_pos(), reverse(dir)); |
3126 |
|
} |
3127 |
|
else { |
3128 |
|
change_state(PULSING); |
3129 |
|
} |
3130 |
|
} |
3131 |
|
|
3132 |
|
#else |
3133 |
void actor_hit(const StoneContact &sc) |
void actor_hit(const StoneContact &sc) |
3134 |
{ |
{ |
3135 |
ActorInfo *ai = sc.actor->get_actorinfo(); |
ActorInfo *ai = sc.actor->get_actorinfo(); |
3150 |
if (!moved) change_state(PULSING); |
if (!moved) change_state(PULSING); |
3151 |
} |
} |
3152 |
|
|
3153 |
|
#endif // USE_IMPULSES |
3154 |
|
|
3155 |
void on_move() { |
void on_move() { |
3156 |
if (state != IDLE) change_state(IDLE); |
if (state != IDLE) change_state(IDLE); |
3157 |
if (state == IDLE) change_state(PULSING); |
if (state == IDLE) change_state(PULSING); |
3933 |
void animcb() { |
void animcb() { |
3934 |
set_model("st-turnstile"); |
set_model("st-turnstile"); |
3935 |
} |
} |
3936 |
|
|
3937 |
|
void warpItemsInRange(bool clockwise); |
3938 |
}; |
}; |
3939 |
|
|
3940 |
/* |
/* |
3944 |
virtual Direction get_dir() const = 0; |
virtual Direction get_dir() const = 0; |
3945 |
|
|
3946 |
void actor_hit(const StoneContact &sc); |
void actor_hit(const StoneContact &sc); |
3947 |
|
#if defined(USE_IMPULSES ) |
3948 |
|
void on_impulse(Direction dir); |
3949 |
|
#endif // USE_IMPULSES |
3950 |
|
|
3951 |
Turnstile_Pivot *get_pivot() |
Turnstile_Pivot *get_pivot() |
3952 |
{ |
{ |
4004 |
}; |
}; |
4005 |
} |
} |
4006 |
|
|
4007 |
|
#if defined(USE_IMPULSES) |
4008 |
|
|
4009 |
|
void |
4010 |
|
Turnstile_Pivot::warpItemsInRange(bool clockwise) { |
4011 |
|
GridPos pv_pos = get_pos(); |
4012 |
|
V2 pv_center(pv_pos.x+.5, pv_pos.y+.5); |
4013 |
|
vector<Actor*> actorsInRange; |
4014 |
|
|
4015 |
|
if (GetActorsInRange(pv_center, 2.0, actorsInRange)) { |
4016 |
|
for (vector<Actor*>::iterator ac = actorsInRange.begin(); ac != actorsInRange.end(); ++ac) { |
4017 |
|
const V2& ac_center = (*ac)->get_pos(); |
4018 |
|
GridPos ac_pos(ac_center); |
4019 |
|
|
4020 |
|
// fprintf(stderr, "actor detected on position %i/%i\n", ac_pos.x, ac_pos.y); |
4021 |
|
|
4022 |
|
// int x = acpos.x-pvpos.x; |
4023 |
|
// int y = acpos.y-pvpos.y; |
4024 |
|
|
4025 |
|
// int xd = -y; // clockwise |
4026 |
|
// int yd = x; |
4027 |
|
|
4028 |
|
V2 to_actor = ac_center-pv_center; |
4029 |
|
V2 to_newactor = clockwise |
4030 |
|
? V2(-to_actor[1], to_actor[0]) |
4031 |
|
: V2(to_actor[1], -to_actor[0]); |
4032 |
|
|
4033 |
|
V2 new_actor = pv_center+to_newactor; |
4034 |
|
|
4035 |
|
world::WarpActor(*ac, new_actor[0], new_actor[1]); |
4036 |
|
} |
4037 |
|
} |
4038 |
|
|
4039 |
|
// @@@ FIXME: warp items ? |
4040 |
|
} |
4041 |
|
|
4042 |
|
void |
4043 |
|
Turnstile_Arm::on_impulse(Direction dir) { |
4044 |
|
enum Action { ROTL, ROTR, NOTHING }; |
4045 |
|
static Action actions[4][4] = { |
4046 |
|
{ NOTHING, ROTL, NOTHING, ROTR }, // west arm |
4047 |
|
{ ROTR, NOTHING, ROTL, NOTHING }, // south arm |
4048 |
|
{ NOTHING, ROTR, NOTHING, ROTL }, // east arm |
4049 |
|
{ ROTL, NOTHING, ROTR, NOTHING } // north arm |
4050 |
|
}; |
4051 |
|
|
4052 |
|
Turnstile_Pivot *pivot = get_pivot(); |
4053 |
|
|
4054 |
|
if (pivot) { |
4055 |
|
Action a = actions[get_dir()][dir]; |
4056 |
|
GridPos pos = move(get_pos(), dir); |
4057 |
|
V2 destpos (pos.x + 0.5, pos.y + 0.5); |
4058 |
|
if (a == ROTL) { |
4059 |
|
if (pivot->rotate_left ()) { |
4060 |
|
// fprintf(stderr, "rotate-left (actor-warp currently inactive)\n"); |
4061 |
|
// world::WarpActor (sc.actor, destpos[0], destpos[1]); |
4062 |
|
} |
4063 |
|
} |
4064 |
|
else if (a == ROTR) { |
4065 |
|
if (pivot->rotate_right ()) { |
4066 |
|
// fprintf(stderr, "rotate-right (actor-warp currently inactive)\n"); |
4067 |
|
// world::WarpActor (sc.actor, destpos[0], destpos[1]); |
4068 |
|
} |
4069 |
|
} |
4070 |
|
} |
4071 |
|
else { |
4072 |
|
// Move arms not attached to a pivot individually |
4073 |
|
move_stone(dir); |
4074 |
|
} |
4075 |
|
} |
4076 |
|
|
4077 |
|
void |
4078 |
|
Turnstile_Arm::actor_hit(const StoneContact &sc) |
4079 |
|
{ |
4080 |
|
ActorInfo *ai = sc.actor->get_actorinfo(); |
4081 |
|
Direction dir = reverse(contact_face(sc)); |
4082 |
|
if (dir!=enigma::NODIR && ai->vel * sc.normal < -4) |
4083 |
|
{ |
4084 |
|
SendImpulse(get_pos(), dir); |
4085 |
|
} |
4086 |
|
} |
4087 |
|
|
4088 |
|
#else |
4089 |
|
|
4090 |
void |
void |
4091 |
Turnstile_Arm::actor_hit(const StoneContact &sc) |
Turnstile_Arm::actor_hit(const StoneContact &sc) |
4092 |
{ |
{ |
4124 |
} |
} |
4125 |
} |
} |
4126 |
|
|
4127 |
|
#endif // USE_IMPULSES |
4128 |
|
|
4129 |
// void |
// void |
4130 |
// Turnstile_Pivot::animcb() |
// Turnstile_Pivot::animcb() |
4220 |
if (arms & EASTBIT) set_arm (NORTH); |
if (arms & EASTBIT) set_arm (NORTH); |
4221 |
if (arms & SOUTHBIT) set_arm (EAST); |
if (arms & SOUTHBIT) set_arm (EAST); |
4222 |
if (arms & WESTBIT) set_arm (SOUTH); |
if (arms & WESTBIT) set_arm (SOUTH); |
4223 |
|
|
4224 |
|
#if defined(USE_IMPULSES) |
4225 |
|
warpItemsInRange(false); |
4226 |
|
#endif // USE_IMPULSES |
4227 |
} |
} |
4228 |
return can_rotate; |
return can_rotate; |
4229 |
} |
} |
4264 |
if (arms & EASTBIT) set_arm (SOUTH); |
if (arms & EASTBIT) set_arm (SOUTH); |
4265 |
if (arms & SOUTHBIT) set_arm (WEST); |
if (arms & SOUTHBIT) set_arm (WEST); |
4266 |
if (arms & WESTBIT) set_arm (NORTH); |
if (arms & WESTBIT) set_arm (NORTH); |
4267 |
|
|
4268 |
|
#if defined(USE_IMPULSES) |
4269 |
|
warpItemsInRange(true); |
4270 |
|
#endif // USE_IMPULSES |
4271 |
} |
} |
4272 |
return can_rotate; |
return can_rotate; |
4273 |
} |
} |