547 |
if (!GetStone(newPos)) { |
if (!GetStone(newPos)) { |
548 |
play_sound("st-move"); |
play_sound("st-move"); |
549 |
SetStone(newPos, YieldStone(p)); |
SetStone(newPos, YieldStone(p)); |
550 |
display::GetStatusBar()->set_counter(player::IncMoveCounter()); |
player::IncMoveCounter(); |
551 |
|
|
552 |
on_move(); |
on_move(); |
553 |
if (Item *it = GetItem(newPos)) it->on_stonehit(this); |
if (Item *it = GetItem(newPos)) it->on_stonehit(this); |
1855 |
SetStone(mc[i], clusterstones[i]); |
SetStone(mc[i], clusterstones[i]); |
1856 |
} |
} |
1857 |
|
|
1858 |
display::GetStatusBar()->set_counter(player::IncMoveCounter(c.size())); |
player::IncMoveCounter(c.size()); |
1859 |
} |
} |
1860 |
|
|
1861 |
bool |
bool |
2282 |
} |
} |
2283 |
|
|
2284 |
void actor_hit(const StoneContact &sc) |
void actor_hit(const StoneContact &sc) |
|
|
|
2285 |
{ |
{ |
2286 |
if (sc.actor->get_attrib("blackball")) |
if (sc.actor->get_attrib("blackball")) |
2287 |
set_on(!is_on()); |
set_on(!is_on()); |
2288 |
PerformAction(this, is_on()); |
PerformAction(this, is_on()); |
2289 |
play_sound("st-switch"); |
play_sound("st-switch"); |
2290 |
} |
} |
2316 |
} |
} |
2317 |
|
|
2318 |
void actor_hit(const StoneContact &sc) |
void actor_hit(const StoneContact &sc) |
|
|
|
2319 |
{ |
{ |
2320 |
if (sc.actor->get_attrib("whiteball")) |
if (sc.actor->get_attrib("whiteball")) |
2321 |
set_on(!is_on()); |
set_on(!is_on()); |
2322 |
PerformAction(this, is_on()); |
PerformAction(this, is_on()); |
2323 |
play_sound("st-switch"); |
play_sound("st-switch"); |
2324 |
} |
} |
2507 |
{ |
{ |
2508 |
class ShogunStone : public MovableStone { |
class ShogunStone : public MovableStone { |
2509 |
CLONEOBJ(ShogunStone); |
CLONEOBJ(ShogunStone); |
|
public: |
|
|
ShogunStone(const char *kind="st-shogun") : MovableStone(kind) { |
|
|
set_holes(SMALL); |
|
|
} |
|
|
protected: |
|
|
enum Holes { SMALL = 1, MEDIUM = 2, LARGE = 4}; |
|
2510 |
|
|
2511 |
|
enum Holes { SMALL = 1, MEDIUM = 2, LARGE = 4}; |
2512 |
void set_holes(Holes h) { set_attrib("holes", h); } |
void set_holes(Holes h) { set_attrib("holes", h); } |
2513 |
|
public: |
2514 |
|
ShogunStone(int holes=SMALL) : MovableStone("st-shogun") { |
2515 |
|
set_holes(static_cast<Holes>(holes)); |
2516 |
|
} |
2517 |
private: |
private: |
2518 |
Holes get_holes() const; |
Holes get_holes() const; |
2519 |
void notify_item(bool disappearing); |
void notify_item(bool disappearing); |
2545 |
|
|
2546 |
static Holes smallest_hole(Holes s); |
static Holes smallest_hole(Holes s); |
2547 |
|
|
2548 |
Holes transfer_smallest_hole(GridPos p); |
bool transfer_smallest_hole(GridPos p); |
2549 |
void actor_hit(const StoneContact &sc); |
void actor_hit(const StoneContact &sc); |
2550 |
}; |
}; |
|
|
|
|
#define DEFSHOGUN(CLASSNAME, KIND, HOLES) \ |
|
|
class CLASSNAME : public ShogunStone { \ |
|
|
CLONEOBJ(CLASSNAME); \ |
|
|
public: \ |
|
|
CLASSNAME() : ShogunStone(KIND) { \ |
|
|
set_holes (static_cast<Holes>(HOLES)); \ |
|
|
} \ |
|
|
}; |
|
|
|
|
|
DEFSHOGUN(Shogun_S, "st-shogun-s", 1); |
|
|
DEFSHOGUN(Shogun_M, "st-shogun-m", 2); |
|
|
DEFSHOGUN(Shogun_SM, "st-shogun-sm", 3); |
|
|
DEFSHOGUN(Shogun_L, "st-shogun-l", 4); |
|
|
DEFSHOGUN(Shogun_SL, "st-shogun-sl", 5); |
|
|
DEFSHOGUN(Shogun_ML, "st-shogun-ml", 6); |
|
|
DEFSHOGUN(Shogun_SML, "st-shogun-sml", 7); |
|
2551 |
} |
} |
2552 |
|
|
2553 |
ShogunStone::Holes |
ShogunStone::Holes |
2580 |
} |
} |
2581 |
else { |
else { |
2582 |
switch (get_holes()) { |
switch (get_holes()) { |
2583 |
case SMALL: SendMessage(it,"shogun1"); break; |
case SMALL: SendMessage(it,"shogun1"); break; |
2584 |
case (MEDIUM | SMALL): SendMessage(it,"shogun2"); break; |
case (MEDIUM | SMALL): SendMessage(it,"shogun2"); break; |
2585 |
case (LARGE | MEDIUM | SMALL): SendMessage(it,"shogun3"); break; |
case (LARGE | MEDIUM | SMALL): SendMessage(it,"shogun3"); break; |
2586 |
default: SendMessage(it, "noshogun"); break; |
default: SendMessage(it, "noshogun"); break; |
2587 |
} |
} |
2588 |
} |
} |
2589 |
} |
} |
2590 |
} |
} |
2591 |
|
|
2592 |
ShogunStone::Holes |
bool |
2593 |
ShogunStone::transfer_smallest_hole(GridPos p) |
ShogunStone::transfer_smallest_hole(GridPos p) |
2594 |
{ |
{ |
2595 |
Holes h = get_holes(); |
Holes h = get_holes(); |
2596 |
Holes sh = smallest_hole(h); |
Holes sh = smallest_hole(h); |
2597 |
Holes nh = h; // predicted hole-state |
Holes nh = h; // predicted hole-state |
2598 |
ShogunStone *sst = 0; |
|
2599 |
bool add2existing = false; |
ShogunStone *target = 0; |
2600 |
|
if (Stone *st = GetStone(p)) { |
2601 |
if (Stone *st=GetStone(p)) { |
target = dynamic_cast<ShogunStone*>(GetStone(p)); |
2602 |
if ((sst = dynamic_cast<ShogunStone*>(st))) { |
|
2603 |
add2existing = true; |
/* If the stone at `p' is not a shogun stone or if smallest hole |
2604 |
if (sh >= smallest_hole(sst->get_holes())) { // smallest hole does not fit into target |
does not fit into target, do not transfer the smallest hole. */ |
2605 |
sst = 0; |
if (!target || sh >= smallest_hole(target->get_holes())) |
2606 |
} |
return false; |
2607 |
} |
} |
2608 |
|
|
2609 |
|
// It's important, to remove the old stone before setting the |
2610 |
|
// new, (otherwise it is possible to activate two triggers |
2611 |
|
// with one shogun stone |
2612 |
|
// when shifting from one shogun target to a second adjacent shogun target) |
2613 |
|
|
2614 |
|
// remove/modify source stone: |
2615 |
|
nh = Holes(nh & ~sh); |
2616 |
|
if (nh) { |
2617 |
|
set_holes(nh); |
2618 |
|
notify_item(false); |
2619 |
|
init_model(); |
2620 |
} |
} |
2621 |
else { |
else { |
2622 |
sst = new ShogunStone(); |
notify_item(true); |
2623 |
|
KillStone(get_pos()); |
2624 |
} |
} |
2625 |
|
|
2626 |
if (sst) { // perform move ? |
// set/modify target stone: |
2627 |
|
if (target) { // add to existing |
2628 |
// it's important, to remove the old stone before setting the new, |
target->add_hole(sh); |
2629 |
// (otherwise it is possible to activate two triggers with one shogun stone |
play_sound("st-magic"); |
|
// when shifting from one shogun target to a second adjacent shogun target) |
|
|
|
|
|
// remove/modify source stone: |
|
|
nh = Holes(nh & ~sh); |
|
|
if (nh) { |
|
|
set_holes(nh); |
|
|
notify_item(false); |
|
|
init_model(); |
|
|
} |
|
|
else { |
|
|
notify_item(true); |
|
|
KillStone(get_pos()); |
|
|
} |
|
|
|
|
|
// set/modify target stone: |
|
|
if (add2existing) { // add to existing |
|
|
sst->add_hole(sh); |
|
|
play_sound("st-magic"); |
|
|
} |
|
|
else { // create new |
|
|
sst->set_holes(sh); |
|
|
SetStone(p, sst); |
|
|
} |
|
|
|
|
|
display::GetStatusBar()->set_counter(player::IncMoveCounter()); |
|
2630 |
} |
} |
2631 |
|
else // create new |
2632 |
|
SetStone(p, new ShogunStone(sh)); |
2633 |
|
|
2634 |
return nh; |
player::IncMoveCounter(); |
2635 |
|
|
2636 |
|
return true; |
2637 |
} |
} |
2638 |
|
|
2639 |
void |
void |
2650 |
} |
} |
2651 |
|
|
2652 |
void |
void |
2653 |
ShogunStone::on_impulse(Direction dir) { |
ShogunStone::on_impulse(Direction dir) |
2654 |
// fprintf(stderr, "ShogunStone::on_impulse(%s)\n", to_suffix(dir).c_str()); |
{ |
2655 |
Holes holes = get_holes(); |
if (transfer_smallest_hole(move(get_pos(), dir))) |
|
Holes newholes = transfer_smallest_hole(move(get_pos(), dir)); |
|
|
|
|
|
if (newholes != holes) { |
|
2656 |
play_sound("st-move"); |
play_sound("st-move"); |
|
} |
|
2657 |
} |
} |
2658 |
|
|
2659 |
//---------------------------------------- |
//---------------------------------------- |
3983 |
} |
} |
3984 |
|
|
3985 |
switch (action) { |
switch (action) { |
3986 |
case WARP: { |
case WARP: { |
3987 |
GridPos ac_target_pos(pv_pos.x+to_x[idx_target], pv_pos.y+to_y[idx_target]); |
GridPos ac_target_pos(pv_pos.x+to_x[idx_target], pv_pos.y+to_y[idx_target]); |
3988 |
world::WarpActor(*ac, ac_target_pos.x+.5, ac_target_pos.y+.5); |
world::WarpActor(*ac, ac_target_pos.x+.5, ac_target_pos.y+.5); |
3989 |
|
|
3990 |
Stone *st = GetStone(ac_target_pos); |
Stone *st = GetStone(ac_target_pos); |
3991 |
if (!st) break; |
if (!st) break; |
3992 |
|
|
3993 |
// destination is blocked |
// destination is blocked |
3994 |
|
|
3995 |
Turnstile_Arm *arm = dynamic_cast<Turnstile_Arm*>(st); |
Turnstile_Arm *arm = dynamic_cast<Turnstile_Arm*>(st); |
3996 |
if (arm && !compatible) { // if blocking stone is turnstile arm -> hit it! |
if (arm && !compatible) { // if blocking stone is turnstile arm -> hit it! |
3997 |
const int impulse_dir[2][8] = { |
const int impulse_dir[2][8] = { |
3998 |
// anticlockwise |
// anticlockwise |
3999 |
{ SOUTHBIT|WESTBIT, WESTBIT, NORTHBIT|WESTBIT, NORTHBIT, |
{ SOUTHBIT|WESTBIT, WESTBIT, NORTHBIT|WESTBIT, NORTHBIT, |
4000 |
NORTHBIT|EASTBIT, EASTBIT, SOUTHBIT|EASTBIT, SOUTHBIT }, |
NORTHBIT|EASTBIT, EASTBIT, SOUTHBIT|EASTBIT, SOUTHBIT }, |
4001 |
// clockwise |
// clockwise |
4002 |
{ NORTHBIT|EASTBIT, EASTBIT, SOUTHBIT|EASTBIT, SOUTHBIT, |
{ NORTHBIT|EASTBIT, EASTBIT, SOUTHBIT|EASTBIT, SOUTHBIT, |
4003 |
SOUTHBIT|WESTBIT, WESTBIT, NORTHBIT|WESTBIT, NORTHBIT } |
SOUTHBIT|WESTBIT, WESTBIT, NORTHBIT|WESTBIT, NORTHBIT } |
4004 |
}; |
}; |
4005 |
|
|
4006 |
DirectionBits possible_impulses = |
DirectionBits possible_impulses = |
4007 |
static_cast<DirectionBits>(impulse_dir[clockwise][idx_target]); |
static_cast<DirectionBits>(impulse_dir[clockwise][idx_target]); |
4008 |
|
|
4009 |
for (int d = 0; d<4; ++d) { |
for (int d = 0; d<4; ++d) { |
4010 |
if (has_dir(possible_impulses, Direction(d))) { |
if (has_dir(possible_impulses, Direction(d))) { |
4011 |
SendImpulse(ac_target_pos, Direction(d), *ac); |
SendImpulse(ac_target_pos, Direction(d), *ac); |
|
} |
|
4012 |
} |
} |
4013 |
|
} |
4014 |
|
|
4015 |
if (GetStone(ac_target_pos) == 0) { // arm disappeared |
if (GetStone(ac_target_pos) == 0) { // arm disappeared |
4016 |
break; |
break; |
|
} |
|
4017 |
} |
} |
|
// fall-through (if arm didn't rotate or other stone was blocking) |
|
|
} |
|
|
case SHATTER: { |
|
|
SendMessage(*ac, "shatter"); |
|
|
break; |
|
4018 |
} |
} |
4019 |
|
// fall-through (if arm didn't rotate or other stone was blocking) |
4020 |
|
} |
4021 |
|
case SHATTER: |
4022 |
|
SendMessage(*ac, "shatter"); |
4023 |
|
break; |
4024 |
} |
} |
4025 |
|
|
4026 |
// @@@ FIXME: it's possible that two actors are moved to the same destination field. |
// @@@ FIXME: it's possible that two actors are moved to the same destination field. |
4151 |
void |
void |
4152 |
Turnstile_Pivot_Base::set_arms (DirectionBits arms) |
Turnstile_Pivot_Base::set_arms (DirectionBits arms) |
4153 |
{ |
{ |
|
GridPos p = get_pos(); |
|
4154 |
if (arms & NORTHBIT) set_arm(NORTH); |
if (arms & NORTHBIT) set_arm(NORTH); |
4155 |
if (arms & EASTBIT) set_arm(EAST); |
if (arms & EASTBIT) set_arm(EAST); |
4156 |
if (arms & SOUTHBIT) set_arm(SOUTH); |
if (arms & SOUTHBIT) set_arm(SOUTH); |
4206 |
set_arms(rotate(arms, false)); |
set_arms(rotate(arms, false)); |
4207 |
warpActorsInRange(false); |
warpActorsInRange(false); |
4208 |
|
|
4209 |
display::GetStatusBar()->set_counter(player::IncMoveCounter()); |
player::IncMoveCounter(); |
4210 |
} |
} |
4211 |
return can_rotate; |
return can_rotate; |
4212 |
} |
} |
4244 |
set_arms(rotate(arms, true)); |
set_arms(rotate(arms, true)); |
4245 |
warpActorsInRange(true); |
warpActorsInRange(true); |
4246 |
|
|
4247 |
display::GetStatusBar()->set_counter(player::IncMoveCounter()); |
player::IncMoveCounter(); |
4248 |
} |
} |
4249 |
return can_rotate; |
return can_rotate; |
4250 |
} |
} |
4376 |
add_templ(new RubberBandStone); |
add_templ(new RubberBandStone); |
4377 |
|
|
4378 |
add_templ(new ShogunStone); |
add_templ(new ShogunStone); |
4379 |
add_templ(new Shogun_S); |
add_templ("st-shogun-s", new ShogunStone(1)); |
4380 |
add_templ(new Shogun_M); |
add_templ("st-shogun-m", new ShogunStone(2)); |
4381 |
add_templ(new Shogun_SM); |
add_templ("st-shogun-sm", new ShogunStone(3)); |
4382 |
add_templ(new Shogun_L); |
add_templ("st-shogun-l", new ShogunStone(4)); |
4383 |
add_templ(new Shogun_SL); |
add_templ("st-shogun-sl", new ShogunStone(5)); |
4384 |
add_templ(new Shogun_ML); |
add_templ("st-shogun-ml", new ShogunStone(6)); |
4385 |
add_templ(new Shogun_SML); |
add_templ("st-shogun-sml", new ShogunStone(7)); |
4386 |
|
|
4387 |
add_templ(new ActorImpulseStone); |
add_templ(new ActorImpulseStone); |
4388 |
add_templ(new ActorImpulseStoneInvisible); |
add_templ(new ActorImpulseStoneInvisible); |