172 |
return false; |
return false; |
173 |
} |
} |
174 |
|
|
175 |
|
// Send an impulse to position 'dest' into direction dir. |
176 |
|
// If 'dest' contains a stone, on_impulse() is called for that stone |
177 |
|
|
178 |
|
void |
179 |
|
Object::send_impulse(const GridPos& dest, Direction dir) |
180 |
|
{ |
181 |
|
if (Stone *st = GetStone(dest)) { |
182 |
|
Impulse impulse(this, dest, dir); |
183 |
|
st->on_impulse(impulse); |
184 |
|
} |
185 |
|
} |
186 |
|
|
187 |
namespace { |
namespace { |
188 |
const char *vstrf(const char *format, va_list argPtr) { |
const char *vstrf(const char *format, va_list argPtr) { |
189 |
static size_t buf_size = 256; |
static size_t buf_size = 256; |
669 |
{ |
{ |
670 |
Direction dir = get_push_direction(sc); |
Direction dir = get_push_direction(sc); |
671 |
if (dir != enigma::NODIR) { |
if (dir != enigma::NODIR) { |
672 |
SendImpulse(sc.stonepos, dir, sc.actor); |
sc.actor->send_impulse(sc.stonepos, dir); |
673 |
return true; |
return GetStone(sc.stonepos) == 0; // return true only if stone vanished |
674 |
} |
} |
675 |
return false; |
return false; |
676 |
} |
} |
1728 |
return false; |
return false; |
1729 |
} |
} |
1730 |
|
|
1731 |
void on_impulse (Direction dir) { |
void on_impulse (const Impulse& impulse) { |
1732 |
move_stone(dir); |
move_stone(impulse.dir); |
1733 |
Object *sender = ImpulseSender(); |
if (impulse.sender && 0 == strncmp(impulse.sender->get_kind(), "st-rotator-", 11)) { |
1734 |
if (sender && 0 == strncmp(sender->get_kind(), "st-rotator-", 11)) { |
set_dir(impulse.dir); |
|
set_dir(dir); |
|
1735 |
} |
} |
1736 |
init_model(); |
init_model(); |
1737 |
} |
} |
1903 |
return get_connections() == 0; |
return get_connections() == 0; |
1904 |
} |
} |
1905 |
|
|
1906 |
virtual void on_impulse(Direction dir); |
virtual void on_impulse(const Impulse& impulse); |
1907 |
|
|
1908 |
void init_model(); |
void init_model(); |
1909 |
StoneResponse collision_response(const StoneContact &sc); |
StoneResponse collision_response(const StoneContact &sc); |
2111 |
} |
} |
2112 |
|
|
2113 |
void |
void |
2114 |
PuzzleStone::on_impulse(Direction dir) |
PuzzleStone::on_impulse(const Impulse& impulse) |
2115 |
{ |
{ |
2116 |
Cluster c; |
Cluster c; |
2117 |
bool is_complete = find_cluster(c); |
bool is_complete = find_cluster(c); |
2118 |
maybe_move_cluster(c, is_complete, dir); |
maybe_move_cluster(c, is_complete, impulse.dir); |
2119 |
} |
} |
2120 |
|
|
2121 |
|
|
2144 |
} |
} |
2145 |
} |
} |
2146 |
else if (move_dir != NODIR) { |
else if (move_dir != NODIR) { |
2147 |
SendImpulse(get_pos(), move_dir, sc.actor); |
sc.actor->send_impulse(get_pos(), move_dir); |
2148 |
} |
} |
2149 |
} |
} |
2150 |
|
|
2738 |
notify_item(); |
notify_item(); |
2739 |
} |
} |
2740 |
|
|
2741 |
void on_impulse(Direction dir); |
void on_impulse(const Impulse& impulse); |
2742 |
|
|
2743 |
void init_model() { |
void init_model() { |
2744 |
char x[20]; |
char x[20]; |
2791 |
} |
} |
2792 |
|
|
2793 |
void |
void |
2794 |
ShogunStone::on_impulse(Direction dir) |
ShogunStone::on_impulse(const Impulse& impulse) |
2795 |
{ |
{ |
2796 |
GridPos destpos = move(get_pos(), dir); |
GridPos destpos = move(get_pos(), impulse.dir); |
2797 |
Holes holes = get_holes(); |
Holes holes = get_holes(); |
2798 |
Holes smallest = smallest_hole(holes); |
Holes smallest = smallest_hole(holes); |
2799 |
ShogunStone *target = 0; |
ShogunStone *target = 0; |
3025 |
|
|
3026 |
void change_state(State st); |
void change_state(State st); |
3027 |
|
|
3028 |
virtual void on_impulse(Direction dir) { |
virtual void on_impulse(const Impulse& impulse) { |
3029 |
incoming = dir; |
incoming = impulse.dir; |
3030 |
change_state(PULSING); |
change_state(PULSING); |
3031 |
} |
} |
3032 |
|
|
3063 |
void |
void |
3064 |
StoneImpulse_Base::change_state(State st) |
StoneImpulse_Base::change_state(State st) |
3065 |
{ |
{ |
3066 |
|
// warning("StoneImpulse_Base changes State %i -> %i", (int)state, (int)st); |
3067 |
if (st == state) return; |
if (st == state) return; |
3068 |
|
|
3069 |
GridPos p = get_pos(); |
GridPos p = get_pos(); |
3070 |
switch (st) { |
switch (st) { |
3071 |
case PULSING: |
case IDLE: { |
3072 |
if (state != IDLE) |
init_model(); |
3073 |
return; // do not set new state |
break; |
3074 |
play_sound("impulse"); |
} |
3075 |
break; |
case PULSING: |
3076 |
case CLOSING: |
if (state != IDLE) { |
3077 |
{ |
return; // do not set new state |
3078 |
|
} |
3079 |
|
play_sound("impulse"); |
3080 |
|
break; |
3081 |
|
case CLOSING: { |
3082 |
GridPos targetpos[4]; |
GridPos targetpos[4]; |
3083 |
bool haveStone[4]; |
bool haveStone[4]; |
3084 |
|
|
3090 |
for (int d = int(incoming)+1; d <= int(incoming)+4; ++d) { |
for (int d = int(incoming)+1; d <= int(incoming)+4; ++d) { |
3091 |
int D = d%4; |
int D = d%4; |
3092 |
if (haveStone[D]) { |
if (haveStone[D]) { |
3093 |
SendImpulse(targetpos[D], Direction(D), this); |
send_impulse(targetpos[D], Direction(D)); |
3094 |
} |
} |
3095 |
} |
} |
3096 |
|
|
3097 |
incoming = NODIR; // forget impulse direction |
incoming = NODIR; // forget impulse direction |
3098 |
break; |
break; |
3099 |
} |
} |
|
case IDLE: |
|
|
init_model(); |
|
|
break; |
|
3100 |
} |
} |
3101 |
state = st; |
state = st; |
3102 |
|
|
3192 |
} |
} |
3193 |
} |
} |
3194 |
|
|
3195 |
void on_impulse(Direction dir) { |
void on_impulse(const Impulse& impulse) { |
3196 |
if (move_stone(dir)) { |
if (move_stone(impulse.dir)) { |
3197 |
// on_move changes state to PULSING |
Actor *hitman = dynamic_cast<Actor*>(impulse.sender); |
3198 |
incoming = dir; |
if (hitman && wielded_item_is(hitman, "it-magicwand")) { |
3199 |
} |
return; // do not change state to PULSING |
3200 |
else { |
} |
|
StoneImpulse_Base::on_impulse(dir); |
|
3201 |
} |
} |
3202 |
|
StoneImpulse_Base::on_impulse(impulse); |
3203 |
} |
} |
3204 |
|
|
3205 |
void on_move() { |
void on_move() { |
3206 |
Actor *hitman = dynamic_cast<Actor*>(ImpulseSender()); |
// when moved, animation seems to be restarted |
3207 |
if (hitman && wielded_item_is(hitman, "it-magicwand")) { |
// and animcb never sets state to IDLE |
3208 |
// move was initiated by actor with magicwand |
change_state(IDLE); |
|
return; // dont pulse! |
|
|
} |
|
|
|
|
|
if (state != IDLE) change_state(IDLE); |
|
|
change_state(PULSING); |
|
3209 |
} |
} |
3210 |
|
|
3211 |
bool is_movable() { |
bool is_movable() { |
3212 |
if (state != IDLE) |
return true; |
|
change_state(IDLE); |
|
|
return state == IDLE; |
|
3213 |
} |
} |
3214 |
}; |
}; |
3215 |
} |
} |
3924 |
Turnstile_Pivot_Base(const char *kind) : Stone (kind) {} |
Turnstile_Pivot_Base(const char *kind) : Stone (kind) {} |
3925 |
|
|
3926 |
protected: |
protected: |
3927 |
bool rotate(bool clockwise); |
bool rotate(bool clockwise, Object *impulse_sender); |
3928 |
|
|
3929 |
friend class Turnstile_Arm; // uses rotate |
friend class Turnstile_Arm; // uses rotate |
3930 |
|
|
3938 |
|
|
3939 |
void animcb() { set_model(model()); } |
void animcb() { set_model(model()); } |
3940 |
|
|
3941 |
void handleActorsAndItems(bool clockwise); |
void handleActorsAndItems(bool clockwise, Object *impulse_sender); |
3942 |
|
|
3943 |
virtual const char *model() const = 0; |
virtual const char *model() const = 0; |
3944 |
virtual const char *anim() const = 0; |
virtual const char *anim() const = 0; |
3973 |
virtual Direction get_dir() const = 0; |
virtual Direction get_dir() const = 0; |
3974 |
|
|
3975 |
void actor_hit(const StoneContact &sc); |
void actor_hit(const StoneContact &sc); |
3976 |
void on_impulse(Direction dir); |
void on_impulse(const Impulse& impulse); |
3977 |
|
|
3978 |
Turnstile_Pivot_Base *get_pivot() { |
Turnstile_Pivot_Base *get_pivot() { |
3979 |
Stone *st = GetStone (move (get_pos(), reverse(get_dir()))); |
Stone *st = GetStone (move (get_pos(), reverse(get_dir()))); |
4035 |
// ------------------------------------- |
// ------------------------------------- |
4036 |
|
|
4037 |
void |
void |
4038 |
Turnstile_Arm::on_impulse(Direction dir) { |
Turnstile_Arm::on_impulse(const Impulse& impulse) { |
4039 |
enum Action { ROTL, ROTR, stay }; |
enum Action { ROTL, ROTR, stay }; |
4040 |
static Action actions[4][4] = { |
static Action actions[4][4] = { |
4041 |
{ stay, ROTL, stay, ROTR }, // west arm |
{ stay, ROTL, stay, ROTR }, // west arm |
4047 |
Turnstile_Pivot_Base *pivot = get_pivot(); |
Turnstile_Pivot_Base *pivot = get_pivot(); |
4048 |
|
|
4049 |
if (pivot) { |
if (pivot) { |
4050 |
Action a = actions[get_dir()][dir]; |
Action a = actions[get_dir()][impulse.dir]; |
4051 |
if (a != stay) { |
if (a != stay) { |
4052 |
pivot->rotate(a == ROTR); // ROTR is clockwise |
pivot->rotate(a == ROTR, impulse.sender); // ROTR is clockwise |
4053 |
} |
} |
4054 |
} |
} |
4055 |
else { |
else { |
4056 |
// Move arms not attached to a pivot individually |
// Move arms not attached to a pivot individually |
4057 |
move_stone(dir); |
move_stone(impulse.dir); |
4058 |
} |
} |
4059 |
} |
} |
4060 |
|
|
4129 |
} |
} |
4130 |
|
|
4131 |
bool |
bool |
4132 |
Turnstile_Pivot_Base::rotate(bool clockwise) |
Turnstile_Pivot_Base::rotate(bool clockwise, Object *impulse_sender) |
4133 |
{ |
{ |
4134 |
DirectionBits arms = arms_present(); |
DirectionBits arms = arms_present(); |
4135 |
bool can_rotate = true; |
bool can_rotate = true; |
4172 |
} |
} |
4173 |
|
|
4174 |
if (can_rotate) { |
if (can_rotate) { |
4175 |
if (dynamic_cast<Actor*>(ImpulseSender())) |
if (dynamic_cast<Actor*>(impulse_sender)) |
4176 |
play_sound("st-magic"); |
play_sound("st-magic"); |
4177 |
play_sound("st-move"); |
play_sound("st-move"); |
4178 |
|
|
4180 |
|
|
4181 |
remove_arms(arms); |
remove_arms(arms); |
4182 |
set_arms(enigma::rotate(arms, clockwise)); |
set_arms(enigma::rotate(arms, clockwise)); |
4183 |
handleActorsAndItems(clockwise); |
handleActorsAndItems(clockwise, impulse_sender); |
4184 |
|
|
4185 |
player::IncMoveCounter(); |
player::IncMoveCounter(); |
4186 |
} |
} |
4188 |
} |
} |
4189 |
|
|
4190 |
void |
void |
4191 |
Turnstile_Pivot_Base::handleActorsAndItems(bool clockwise) { |
Turnstile_Pivot_Base::handleActorsAndItems(bool clockwise, Object *impulse_sender) { |
4192 |
GridPos pv_pos = get_pos(); |
GridPos pv_pos = get_pos(); |
4193 |
V2 pv_center(pv_pos.x+.5, pv_pos.y+.5); |
V2 pv_center(pv_pos.x+.5, pv_pos.y+.5); |
4194 |
|
|
4258 |
enum { STAY, WARP, SHATTER } action = STAY; |
enum { STAY, WARP, SHATTER } action = STAY; |
4259 |
|
|
4260 |
if (compatible) { |
if (compatible) { |
4261 |
bool is_impulse_sender = (*ac == dynamic_cast<Actor*>(ImpulseSender())); |
bool is_impulse_sender = (*ac == dynamic_cast<Actor*>(impulse_sender)); |
4262 |
|
|
4263 |
if (is_impulse_sender) { |
if (is_impulse_sender) { |
4264 |
action = WARP; |
action = WARP; |
4302 |
|
|
4303 |
for (int d = 0; d<4; ++d) { |
for (int d = 0; d<4; ++d) { |
4304 |
if (has_dir(possible_impulses, Direction(d))) { |
if (has_dir(possible_impulses, Direction(d))) { |
4305 |
SendImpulse(ac_target_pos, Direction(d), *ac); |
(*ac)->send_impulse(ac_target_pos, Direction(d)); |
4306 |
} |
} |
4307 |
} |
} |
4308 |
|
|