182 |
//====================================================================== |
//====================================================================== |
183 |
|
|
184 |
Floor::Floor(const char *kind, double friction, double mfactor) |
Floor::Floor(const char *kind, double friction, double mfactor) |
185 |
: TGridObject<GRID_FLOOR>(kind), |
: TGridObject<GRID_FLOOR>(kind), |
186 |
traits (kind, friction, mfactor, FLOOR_Normal) |
traits (kind, friction, mfactor, FLOOR_Normal) |
187 |
{ |
{ |
188 |
} |
} |
1575 |
void alarm() { |
void alarm() { |
1576 |
state = MOVING; |
state = MOVING; |
1577 |
GridPos p = get_pos(); |
GridPos p = get_pos(); |
|
#if defined(USE_IMPULSES) |
|
1578 |
if (move_stone(get_dir())) { |
if (move_stone(get_dir())) { |
|
#else |
|
|
if (world::MaybeMoveStone(p, get_dir())) { |
|
|
#endif // USE_IMPULSES |
|
1579 |
// send a message to the stone that's blocking our way |
// send a message to the stone that's blocking our way |
1580 |
Stone *st = GetStone(move(move(p,get_dir()),get_dir())); |
Stone *st = GetStone(move(move(p,get_dir()),get_dir())); |
1581 |
if( st) SendMessage(st, "trigger", Value(get_dir())); |
if( st) SendMessage(st, "trigger", Value(get_dir())); |
1698 |
bool on_laserhit(Direction dir) { |
bool on_laserhit(Direction dir) { |
1699 |
return get_connections() == 0; |
return get_connections() == 0; |
1700 |
} |
} |
1701 |
#if defined(USE_IMPULSES) |
|
1702 |
virtual void on_impulse(Direction dir); |
virtual void on_impulse(Direction dir); |
|
#endif // USE_IMPULSES |
|
1703 |
|
|
1704 |
void init_model(); |
void init_model(); |
1705 |
StoneResponse collision_response(const StoneContact &sc); |
StoneResponse collision_response(const StoneContact &sc); |
1901 |
return STONE_REBOUND; |
return STONE_REBOUND; |
1902 |
} |
} |
1903 |
|
|
|
#if defined(USE_IMPULSES) |
|
1904 |
void |
void |
1905 |
PuzzleStone::on_impulse(Direction dir) { |
PuzzleStone::on_impulse(Direction dir) { |
|
// fprintf(stderr, "PuzzleStone::on_impulse(%s)\n", to_suffix(dir).c_str()); |
|
1906 |
Cluster c; |
Cluster c; |
1907 |
bool is_complete = find_cluster(c); |
bool is_complete = find_cluster(c); |
1908 |
maybe_move_cluster(c, is_complete, dir); |
maybe_move_cluster(c, is_complete, dir); |
1937 |
} |
} |
1938 |
} |
} |
1939 |
else if (move_impulse && hit_dir != NODIR) { |
else if (move_impulse && hit_dir != NODIR) { |
1940 |
SendImpulse(get_pos(), hit_dir); |
SendImpulse(get_pos(), hit_dir, a); |
1941 |
} |
} |
1942 |
} |
} |
|
#else |
|
|
void |
|
|
PuzzleStone::actor_hit(const StoneContact &sc) |
|
|
{ |
|
|
if (get_connections() == NODIRBIT) |
|
|
return; |
|
|
|
|
|
Actor *a = sc.actor; |
|
|
|
|
|
bool move_impulse= (a->get_vel()*sc.normal < -4); |
|
|
Direction hit_dir=reverse(contact_face(sc)); |
|
|
|
|
|
if (wielded_item_is(a, "it-magicwand")) { |
|
|
if (cluster_complete()) { |
|
|
// make all cluster stones explode |
|
|
return; |
|
|
} |
|
|
else if (hit_dir != NODIR) { |
|
|
Cluster c; |
|
|
find_row_or_column_cluster(c, get_pos(), hit_dir); |
|
|
|
|
|
bool is_complete = false; |
|
|
|
|
|
if (move_impulse) |
|
|
maybe_move_cluster(c, is_complete, hit_dir); |
|
|
else |
|
|
rotate_cluster(c); |
|
|
} |
|
|
} |
|
|
else if (move_impulse && hit_dir != NODIR) { |
|
|
Cluster c; |
|
|
bool is_complete = find_cluster(c); |
|
|
maybe_move_cluster(c, is_complete, hit_dir); |
|
|
} |
|
|
} |
|
|
#endif // USE_IMPULSES |
|
|
|
|
1943 |
|
|
1944 |
//---------------------------------------- |
//---------------------------------------- |
1945 |
// DoorBase |
// DoorBase |
2538 |
notify_item(false); |
notify_item(false); |
2539 |
} |
} |
2540 |
|
|
|
#if defined(USE_IMPULSES) |
|
2541 |
void on_impulse(Direction dir); |
void on_impulse(Direction dir); |
|
#endif // USE_IMPULSES |
|
2542 |
|
|
2543 |
void init_model() { |
void init_model() { |
2544 |
char x[20]; |
char x[20]; |
2662 |
return nh; |
return nh; |
2663 |
} |
} |
2664 |
|
|
|
#if defined(USE_IMPULSES) |
|
2665 |
void |
void |
2666 |
ShogunStone::actor_hit(const StoneContact &sc) |
ShogunStone::actor_hit(const StoneContact &sc) |
2667 |
{ |
{ |
2672 |
if (hit_dir == NODIR || !move_impulse) |
if (hit_dir == NODIR || !move_impulse) |
2673 |
return; |
return; |
2674 |
|
|
2675 |
SendImpulse(get_pos(), hit_dir); |
SendImpulse(get_pos(), hit_dir, a); |
2676 |
} |
} |
2677 |
|
|
2678 |
void |
void |
2686 |
} |
} |
2687 |
} |
} |
2688 |
|
|
|
#else |
|
|
void |
|
|
ShogunStone::actor_hit(const StoneContact &sc) |
|
|
{ |
|
|
Actor *a = sc.actor; |
|
|
bool move_impulse = (a->get_vel()*sc.normal < -4); |
|
|
Direction hit_dir = reverse(contact_face(sc)); |
|
|
|
|
|
if (hit_dir == NODIR || !move_impulse) |
|
|
return; |
|
|
|
|
|
Holes holes = get_holes(); |
|
|
Holes newholes = transfer_smallest_hole(move(get_pos(), hit_dir)); |
|
|
|
|
|
if (newholes != holes) { |
|
|
play_sound("st-move"); |
|
|
} |
|
|
} |
|
|
#endif // USE_IMPULSES |
|
|
|
|
|
|
|
2689 |
//---------------------------------------- |
//---------------------------------------- |
2690 |
// FartStone |
// FartStone |
2691 |
//---------------------------------------- |
//---------------------------------------- |
2876 |
|
|
2877 |
void change_state(State st); |
void change_state(State st); |
2878 |
|
|
|
#if defined(USE_IMPULSES) |
|
2879 |
virtual void on_impulse(Direction dir) { |
virtual void on_impulse(Direction dir) { |
|
// fprintf(stderr, "StoneImpulse_Base::on_impulse(%s)\n", to_suffix(dir).c_str()); |
|
2880 |
incoming = dir; |
incoming = dir; |
2881 |
change_state(PULSING); |
change_state(PULSING); |
2882 |
} |
} |
|
#endif // USE_IMPULSES |
|
2883 |
|
|
2884 |
private: |
private: |
2885 |
|
|
2886 |
virtual void notify_state(State st) = 0; |
virtual void notify_state(State st) = 0; |
2887 |
|
|
2888 |
void message(const string &m, const Value &value) { |
void message(const string &m, const Value &value) { |
|
#if defined(USE_IMPULSES) |
|
2889 |
if (m=="trigger") { |
if (m=="trigger") { |
2890 |
incoming = (value.get_type() == Value::DOUBLE) |
incoming = (value.get_type() == Value::DOUBLE) |
2891 |
? Direction(value.get_double()+0.1) |
? Direction(value.get_double()+0.1) |
2893 |
|
|
2894 |
change_state(PULSING); |
change_state(PULSING); |
2895 |
} |
} |
|
#else |
|
|
if (m=="trigger" || m=="stoneimpulse") |
|
|
change_state(PULSING); |
|
|
#endif // USE_IMPULSES |
|
2896 |
} |
} |
2897 |
|
|
2898 |
void animcb() { |
void animcb() { |
2925 |
break; |
break; |
2926 |
case CLOSING: |
case CLOSING: |
2927 |
{ |
{ |
|
#if defined(USE_IMPULSES) |
|
|
|
|
|
// fprintf(stderr, "Sending impulses (incoming = %s)\n", to_suffix(incoming).c_str()); |
|
|
|
|
2928 |
GridPos targetpos[4]; |
GridPos targetpos[4]; |
2929 |
bool haveStone[4]; |
bool haveStone[4]; |
2930 |
|
|
2936 |
for (int d = int(incoming)+1; d <= int(incoming)+4; ++d) { |
for (int d = int(incoming)+1; d <= int(incoming)+4; ++d) { |
2937 |
int D = d%4; |
int D = d%4; |
2938 |
if (haveStone[D]) { |
if (haveStone[D]) { |
2939 |
SendImpulse(targetpos[D], Direction(D)); |
SendImpulse(targetpos[D], Direction(D), this); |
2940 |
} |
} |
2941 |
} |
} |
2942 |
|
|
2943 |
incoming = NODIR; // forget impulse direction |
incoming = NODIR; // forget impulse direction |
|
#else |
|
|
MaybeMoveStone( move( p, NORTH), NORTH); |
|
|
MaybeMoveStone( move( p, EAST), EAST); |
|
|
MaybeMoveStone( move( p, SOUTH), SOUTH); |
|
|
MaybeMoveStone( move( p, WEST), WEST); |
|
|
SendMessage (GetStone(move(p, NORTH)), "stoneimpulse"); |
|
|
SendMessage (GetStone(move(p, EAST)), "stoneimpulse"); |
|
|
SendMessage (GetStone(move(p, SOUTH)), "stoneimpulse"); |
|
|
SendMessage (GetStone(move(p, WEST)), "stoneimpulse"); |
|
|
#endif // USE_IMPULSES |
|
2944 |
break; |
break; |
2945 |
} |
} |
2946 |
case IDLE: |
case IDLE: |
3034 |
|
|
3035 |
// Stone interface: |
// Stone interface: |
3036 |
|
|
|
#if defined(USE_IMPULSES) |
|
3037 |
void on_impulse(Direction dir) { |
void on_impulse(Direction dir) { |
|
// fprintf(stderr, "MovableImpulseStone::on_impulse(%s)\n", to_suffix(dir).c_str()); |
|
3038 |
if (move_stone(dir)) { |
if (move_stone(dir)) { |
3039 |
// on_move changes state to PULSING |
// on_move changes state to PULSING |
3040 |
incoming = dir; |
incoming = dir; |
3043 |
StoneImpulse_Base::on_impulse(dir); |
StoneImpulse_Base::on_impulse(dir); |
3044 |
} |
} |
3045 |
} |
} |
3046 |
|
|
3047 |
void actor_hit(const StoneContact &sc) { |
void actor_hit(const StoneContact &sc) { |
3048 |
ActorInfo *ai = sc.actor->get_actorinfo(); |
ActorInfo *ai = sc.actor->get_actorinfo(); |
3049 |
Direction dir = contact_face(sc); |
Direction dir = contact_face(sc); |
3050 |
|
|
3051 |
|
// If the speed component towards the face of the stone is large |
3052 |
|
// enough (and actually pointing towards the stone), consider |
3053 |
|
// moving the stone. |
3054 |
if (dir!=enigma::NODIR && ai->vel * sc.normal < -4) { |
if (dir!=enigma::NODIR && ai->vel * sc.normal < -4) { |
3055 |
SendImpulse(get_pos(), reverse(dir)); |
SendImpulse(get_pos(), reverse(dir), sc.actor); |
3056 |
} |
} |
3057 |
else { |
else { |
3058 |
incoming = NODIR; // @@@ problem! |
incoming = NODIR; // @@@ problem! |
3060 |
} |
} |
3061 |
} |
} |
3062 |
|
|
|
#else |
|
|
void actor_hit(const StoneContact &sc) |
|
|
{ |
|
|
ActorInfo *ai = sc.actor->get_actorinfo(); |
|
|
|
|
|
// If the speed component towards the face of the stone is large |
|
|
// enough (and actually pointing towards the stone), consider |
|
|
// moving the stone. |
|
|
|
|
|
Direction dir = contact_face(sc); |
|
|
bool moved = false; |
|
|
|
|
|
if (dir!=enigma::NODIR && ai->vel * sc.normal < -4) { |
|
|
moved = MaybeMoveStone(get_pos(), reverse(dir)); |
|
|
} |
|
|
|
|
|
// if the stone moves the state is changed to PULSING by on_move(), |
|
|
// otherwise do it here |
|
|
if (!moved) change_state(PULSING); |
|
|
} |
|
|
|
|
|
#endif // USE_IMPULSES |
|
|
|
|
3063 |
void on_move() { |
void on_move() { |
3064 |
if (state != IDLE) change_state(IDLE); |
if (state != IDLE) change_state(IDLE); |
3065 |
if (state == IDLE) change_state(PULSING); |
if (state == IDLE) change_state(PULSING); |
3823 |
/* |
/* |
3824 |
** The stone at the center of a turnstile |
** The stone at the center of a turnstile |
3825 |
*/ |
*/ |
3826 |
class Turnstile_Pivot : public Stone { |
class Turnstile_Pivot_Base : public Stone { |
|
CLONEOBJ(Turnstile_Pivot); |
|
|
|
|
|
DirectionBits arms_present(); |
|
|
bool no_stone (int xoff, int yoff); |
|
|
void remove_arms (DirectionBits arms); |
|
|
void set_arm (Direction dir); |
|
3827 |
public: |
public: |
3828 |
Turnstile_Pivot() : Stone ("st-turnstile") {} |
Turnstile_Pivot_Base(const char *kind) : Stone (kind) {} |
3829 |
|
|
3830 |
bool rotate_right(); |
bool rotate_right(); |
3831 |
bool rotate_left(); |
bool rotate_left(); |
3832 |
|
|
3833 |
private: |
private: |
3834 |
void can_rotate() { |
DirectionBits arms_present(); |
3835 |
set_anim("st-turnstile-anim"); |
bool no_stone (int xoff, int yoff); |
|
} |
|
|
void animcb() { |
|
|
set_model("st-turnstile"); |
|
|
} |
|
3836 |
|
|
3837 |
|
void set_arm (Direction dir); |
3838 |
|
void set_arms (DirectionBits arms); |
3839 |
|
void remove_arms (DirectionBits arms); |
3840 |
|
|
3841 |
|
void animcb() { set_model(model()); } |
3842 |
void warpActorsInRange(bool clockwise); |
void warpActorsInRange(bool clockwise); |
3843 |
|
|
3844 |
|
virtual const char *model() const = 0; |
3845 |
|
virtual const char *anim() const = 0; |
3846 |
|
virtual bool oxyd_compatible() const = 0; |
3847 |
|
}; |
3848 |
|
|
3849 |
|
class Turnstile_Pivot : public Turnstile_Pivot_Base { |
3850 |
|
CLONEOBJ(Turnstile_Pivot); |
3851 |
|
public: |
3852 |
|
Turnstile_Pivot() : Turnstile_Pivot_Base(model()) {} |
3853 |
|
|
3854 |
|
const char *model() const { return "st-turnstile"; } |
3855 |
|
const char *anim() const { return "st-turnstile-anim"; } |
3856 |
|
bool oxyd_compatible() const { return true; } |
3857 |
|
}; |
3858 |
|
|
3859 |
|
class Turnstile_Pivot_Green : public Turnstile_Pivot_Base { |
3860 |
|
CLONEOBJ(Turnstile_Pivot_Green); |
3861 |
|
public: |
3862 |
|
Turnstile_Pivot_Green() : Turnstile_Pivot_Base(model()) {} |
3863 |
|
|
3864 |
|
const char *model() const { return "st-turnstile-green"; } |
3865 |
|
const char *anim() const { return "st-turnstile-green-anim"; } |
3866 |
|
bool oxyd_compatible() const { return false; } |
3867 |
}; |
}; |
3868 |
|
|
3869 |
/* |
/* |
3873 |
virtual Direction get_dir() const = 0; |
virtual Direction get_dir() const = 0; |
3874 |
|
|
3875 |
void actor_hit(const StoneContact &sc); |
void actor_hit(const StoneContact &sc); |
|
#if defined(USE_IMPULSES ) |
|
3876 |
void on_impulse(Direction dir); |
void on_impulse(Direction dir); |
|
#endif // USE_IMPULSES |
|
3877 |
|
|
3878 |
Turnstile_Pivot *get_pivot() |
Turnstile_Pivot_Base *get_pivot() { |
|
{ |
|
3879 |
Stone *st = GetStone (move (get_pos(), reverse(get_dir()))); |
Stone *st = GetStone (move (get_pos(), reverse(get_dir()))); |
3880 |
return dynamic_cast<Turnstile_Pivot*>(st); |
return dynamic_cast<Turnstile_Pivot_Base*>(st); |
3881 |
} |
} |
3882 |
protected: |
protected: |
3883 |
Turnstile_Arm (const char *kind) : Stone(kind) |
Turnstile_Arm (const char *kind) : Stone(kind) |
3930 |
}; |
}; |
3931 |
} |
} |
3932 |
|
|
|
#if defined(USE_IMPULSES) |
|
|
|
|
3933 |
void |
void |
3934 |
Turnstile_Pivot::warpActorsInRange(bool clockwise) { |
Turnstile_Pivot_Base::warpActorsInRange(bool clockwise) { |
3935 |
// the turnstile itself already has been rotated |
// the turnstile itself already has been rotated |
3936 |
// now handle all actors in Range |
// now handle all actors in Range |
3937 |
|
|
3938 |
GridPos pv_pos = get_pos(); |
GridPos pv_pos = get_pos(); |
3939 |
V2 pv_center(pv_pos.x+.5, pv_pos.y+.5); |
V2 pv_center(pv_pos.x+.5, pv_pos.y+.5); |
3940 |
|
|
3941 |
|
const int to_index[3][3] = { |
3942 |
|
{ 0, 7, 6 }, // x == 0 |
3943 |
|
{ 1,-1, 5 }, // x == 1 |
3944 |
|
{ 2, 3, 4 } // x == 2 |
3945 |
|
}; |
3946 |
|
|
3947 |
|
// for each field calculate whether an arm has passed by: |
3948 |
|
bool arm_seen[8]; |
3949 |
|
{ |
3950 |
|
const DirectionBits neededArm[2][8] = { |
3951 |
|
// anticlockwise : |
3952 |
|
{ WESTBIT, NORTHBIT, NORTHBIT, EASTBIT, EASTBIT, SOUTHBIT, SOUTHBIT, WESTBIT }, |
3953 |
|
// clockwise : |
3954 |
|
{ NORTHBIT, NORTHBIT, EASTBIT, EASTBIT, SOUTHBIT, SOUTHBIT, WESTBIT, WESTBIT } |
3955 |
|
}; |
3956 |
|
DirectionBits arms = arms_present(); // already the rotated state |
3957 |
|
assert(arms); // pivots w/o arms should not rotate |
3958 |
|
|
3959 |
|
for (int i = 0; i<8; ++i) { |
3960 |
|
arm_seen[i] = arms & neededArm[clockwise][i]; |
3961 |
|
} |
3962 |
|
} |
3963 |
|
|
3964 |
vector<Actor*> actorsInRange; |
vector<Actor*> actorsInRange; |
3965 |
|
|
3966 |
// tested range is sqrt(sqr(1.5)+sqr(0.5)) ( = radius hit by turnstile) + 19/64 ( = max. actor radius) |
// tested range is sqrt(sqr(1.5)+sqr(0.5)) ( = radius hit by turnstile) + 19/64 ( = max. actor radius) |
3975 |
// @@@ FIXME: test if actor was hit by turnstile -> set actor speed |
// @@@ FIXME: test if actor was hit by turnstile -> set actor speed |
3976 |
} |
} |
3977 |
else { // actor is inside the turnstile |
else { // actor is inside the turnstile |
|
const int to_index[3][3] = { |
|
|
{ 0, 7, 6 }, // x == 0 |
|
|
{ 1,-1, 5 }, // x == 1 |
|
|
{ 2, 3, 4 } // x == 2 |
|
|
}; |
|
3978 |
const int to_x[8] = { -1, 0, 1, 1, 1, 0, -1, -1 }; |
const int to_x[8] = { -1, 0, 1, 1, 1, 0, -1, -1 }; |
3979 |
const int to_y[8] = { -1, -1, -1, 0, 1, 1, 1, 0 }; |
const int to_y[8] = { -1, -1, -1, 0, 1, 1, 1, 0 }; |
3980 |
|
|
3981 |
int idx_source = to_index[dx+1][dy+1]; |
int idx_source = to_index[dx+1][dy+1]; |
3982 |
if (idx_source == -1) continue; |
assert(idx_source != -1); // actor inside pivot -- impossible |
3983 |
|
|
3984 |
#define OXYD_COMPATIBLE |
const int rot_index[4][8] = { |
3985 |
#ifdef OXYD_COMPATIBLE |
{ 6, 0, 0, 2, 2, 4, 4, 6 }, // anticlockwise |
3986 |
const int rot_index[2][8] = { |
{ 2, 2, 4, 4, 6, 6, 0, 0 }, // clockwise |
3987 |
{ 6, -1, 0, -1, 2, -1, 4, -1 }, // anticlockwise |
{ 6, -1, 0, -1, 2, -1, 4, -1 }, // anticlockwise (oxyd-compatible) |
3988 |
{ 2, -1, 4, -1, 6, -1, 0, -1 } // clockwise |
{ 2, -1, 4, -1, 6, -1, 0, -1 }, // clockwise (oxyd-compatible) |
3989 |
}; |
}; |
3990 |
|
|
3991 |
int idx_target = rot_index[clockwise][idx_source]; |
bool compatible = oxyd_compatible(); |
3992 |
assert(idx_target >= -1 && idx_target < 8 && (idx_target%2) == 0); |
int idx_target = rot_index[clockwise+2*compatible][idx_source]; // destination index |
3993 |
|
|
3994 |
GridPos ac_target_pos(pv_pos.x+to_x[idx_target], pv_pos.y+to_y[idx_target]); |
enum { STAY, WARP, SHATTER } action = STAY; |
|
world::WarpActor(*ac, ac_target_pos.x+.5, ac_target_pos.y+.5); |
|
3995 |
|
|
3996 |
#else |
if (compatible) { |
3997 |
const int rot_index[2][8] = { |
bool is_impulse_sender = (*ac == dynamic_cast<Actor*>(ImpulseSender())); |
|
{ 6, 0, 0, 2, 2, 4, 4, 6 }, // anticlockwise |
|
|
{ 2, 2, 4, 4, 6, 6, 0, 0 } // clockwise |
|
|
}; |
|
|
|
|
|
const DirectionBits neededArm[2][8] = { |
|
|
// anticlockwise |
|
|
{ WESTBIT, NORTHBIT, NORTHBIT, EASTBIT, EASTBIT, SOUTHBIT, SOUTHBIT, WESTBIT }, |
|
|
// clockwise |
|
|
{ NORTHBIT, NORTHBIT, EASTBIT, EASTBIT, SOUTHBIT, SOUTHBIT, WESTBIT, WESTBIT } |
|
|
}; |
|
3998 |
|
|
3999 |
DirectionBits arms = arms_present(); // already the rotated state |
if (is_impulse_sender) { |
4000 |
|
action = WARP; |
4001 |
|
} |
4002 |
|
else { // other actors |
4003 |
|
if (arm_seen[idx_source]) { // this actor has been hit by an arm |
4004 |
|
action = SHATTER; |
4005 |
|
} |
4006 |
|
} |
4007 |
|
} |
4008 |
|
else { // not oxyd-compatible |
4009 |
|
if (arm_seen[idx_source]) { |
4010 |
|
action = WARP; |
4011 |
|
} |
4012 |
|
// @@@ FIXME: shattered actors are warped |
4013 |
|
} |
4014 |
|
|
4015 |
if (arms & neededArm[clockwise][idx_source]) { // does an arm exist, which might move the actor? |
switch (action) { |
4016 |
int idx_target = rot_index[clockwise][idx_source]; |
case WARP: { |
4017 |
assert(idx_target >= 0 && idx_target < 8); |
GridPos ac_target_pos(pv_pos.x+to_x[idx_target], pv_pos.y+to_y[idx_target]); |
4018 |
|
world::WarpActor(*ac, ac_target_pos.x+.5, ac_target_pos.y+.5); |
4019 |
|
|
4020 |
GridPos ac_target_pos(pv_pos.x+to_x[idx_target], pv_pos.y+to_y[idx_target]); |
Stone *st = GetStone(ac_target_pos); |
4021 |
world::WarpActor(*ac, ac_target_pos.x+.5, ac_target_pos.y+.5); |
if (!st) break; |
4022 |
|
|
4023 |
if (Stone *st = GetStone(ac_target_pos)) { // destination is blocked |
// destination is blocked |
|
Turnstile_Arm *arm = dynamic_cast<Turnstile_Arm*>(st); |
|
|
bool shatter = true; |
|
4024 |
|
|
4025 |
if (arm) { // if stone is turnstile arm -> hit it! |
Turnstile_Arm *arm = dynamic_cast<Turnstile_Arm*>(st); |
4026 |
|
if (arm && !compatible) { // if blocking stone is turnstile arm -> hit it! |
4027 |
const int impulse_dir[2][8] = { |
const int impulse_dir[2][8] = { |
4028 |
// anticlockwise |
// anticlockwise |
4029 |
{ SOUTHBIT|WESTBIT, WESTBIT, NORTHBIT|WESTBIT, NORTHBIT, |
{ SOUTHBIT|WESTBIT, WESTBIT, NORTHBIT|WESTBIT, NORTHBIT, |
4033 |
SOUTHBIT|WESTBIT, WESTBIT, NORTHBIT|WESTBIT, NORTHBIT } |
SOUTHBIT|WESTBIT, WESTBIT, NORTHBIT|WESTBIT, NORTHBIT } |
4034 |
}; |
}; |
4035 |
|
|
4036 |
DirectionBits possible_impulses = |
DirectionBits possible_impulses = |
4037 |
static_cast<DirectionBits>(impulse_dir[clockwise][idx_target]); |
static_cast<DirectionBits>(impulse_dir[clockwise][idx_target]); |
4038 |
|
|
4039 |
for (int d = 0; d<4; ++d) { |
for (int d = 0; d<4; ++d) { |
4040 |
if (has_dir(possible_impulses, Direction(d))) { |
if (has_dir(possible_impulses, Direction(d))) { |
4041 |
SendImpulse(ac_target_pos, Direction(d)); |
SendImpulse(ac_target_pos, Direction(d), *ac); |
4042 |
} |
} |
4043 |
} |
} |
4044 |
|
|
4045 |
if (GetStone(ac_target_pos) == 0) { |
if (GetStone(ac_target_pos) == 0) { // arm disappeared |
4046 |
shatter = false; |
break; |
4047 |
} |
} |
4048 |
} |
} |
4049 |
|
// fall-through (if arm didn't rotate or other stone was blocking) |
4050 |
if (shatter) SendMessage(*ac, "shatter"); |
} |
4051 |
|
case SHATTER: { |
4052 |
|
SendMessage(*ac, "shatter"); |
4053 |
|
break; |
4054 |
} |
} |
4055 |
} |
} |
4056 |
|
|
4057 |
// @@@ 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. |
4058 |
// In that case the second actor is put on top of the first actor |
// In that case the second actor is put on top of the first actor |
4059 |
// (happens only with three balls or pullers/impulsestones) |
// (happens only in non-oxyd-compat-mode with three balls or pullers/impulsestones) |
4060 |
// |
// |
4061 |
// Note: With black and whiteball it's normally no problem, |
// Note: With black and whiteball it's normally no problem, |
4062 |
// because when one of the actors was moving, it's looking natural. |
// because when one of the actors was moving, it's looking natural. |
4063 |
// Problems occur when small balls come into play. |
// Problems occur when small balls come into play. |
|
#endif |
|
|
|
|
|
// @@@ FIXME: shattered actors are warped |
|
4064 |
} |
} |
4065 |
} |
} |
4066 |
} |
} |
4067 |
|
|
4068 |
// @@@ FIXME: should some items warp ? |
// @@@ FIXME: handle items in range (using on_stonehit()) |
4069 |
} |
} |
4070 |
|
|
4071 |
void |
void |
4078 |
{ ROTL, stay, ROTR, stay } // north arm |
{ ROTL, stay, ROTR, stay } // north arm |
4079 |
}; |
}; |
4080 |
|
|
4081 |
Turnstile_Pivot *pivot = get_pivot(); |
Turnstile_Pivot_Base *pivot = get_pivot(); |
4082 |
|
|
4083 |
if (pivot) { |
if (pivot) { |
4084 |
Action a = actions[get_dir()][dir]; |
Action a = actions[get_dir()][dir]; |
4099 |
Direction dir = reverse(contact_face(sc)); |
Direction dir = reverse(contact_face(sc)); |
4100 |
if (dir!=enigma::NODIR && ai->vel * sc.normal < -4) |
if (dir!=enigma::NODIR && ai->vel * sc.normal < -4) |
4101 |
{ |
{ |
4102 |
SendImpulse(get_pos(), dir); |
SendImpulse(get_pos(), dir, sc.actor); |
4103 |
} |
} |
4104 |
} |
} |
4105 |
|
|
4106 |
#else |
#if 0 // old code : |
4107 |
|
|
4108 |
void |
void |
4109 |
Turnstile_Arm::actor_hit(const StoneContact &sc) |
Turnstile_Arm::actor_hit(const StoneContact &sc) |
4110 |
{ |
{ |
4111 |
Turnstile_Pivot *pivot = get_pivot(); |
Turnstile_Pivot_Base *pivot = get_pivot(); |
4112 |
|
|
4113 |
enum Action { ROTL, ROTR, stay }; |
enum Action { ROTL, ROTR, stay }; |
4114 |
static Action actions[4][4] = { |
static Action actions[4][4] = { |
4142 |
} |
} |
4143 |
} |
} |
4144 |
|
|
4145 |
#endif // USE_IMPULSES |
#endif // old code |
|
|
|
|
// void |
|
|
// Turnstile_Pivot::animcb() |
|
|
// { |
|
|
// Stone::init_model(); |
|
|
// } |
|
|
|
|
4146 |
|
|
4147 |
DirectionBits |
DirectionBits |
4148 |
Turnstile_Pivot::arms_present() |
Turnstile_Pivot_Base::arms_present() |
4149 |
{ |
{ |
4150 |
DirectionBits arms = NODIRBIT; |
DirectionBits arms = NODIRBIT; |
4151 |
GridPos p = get_pos(); |
GridPos p = get_pos(); |
4161 |
} |
} |
4162 |
|
|
4163 |
bool |
bool |
4164 |
Turnstile_Pivot::no_stone (int xoff, int yoff) |
Turnstile_Pivot_Base::no_stone (int xoff, int yoff) |
4165 |
{ |
{ |
4166 |
GridPos p = get_pos(); |
GridPos p = get_pos(); |
4167 |
p.x += xoff; |
p.x += xoff; |
4170 |
} |
} |
4171 |
|
|
4172 |
void |
void |
4173 |
Turnstile_Pivot::remove_arms (DirectionBits arms) |
Turnstile_Pivot_Base::remove_arms (DirectionBits arms) |
4174 |
{ |
{ |
4175 |
GridPos p = get_pos(); |
GridPos p = get_pos(); |
4176 |
if (arms & NORTHBIT) KillStone (move (p, NORTH)); |
if (arms & NORTHBIT) KillStone (move (p, NORTH)); |
4180 |
} |
} |
4181 |
|
|
4182 |
void |
void |
4183 |
Turnstile_Pivot::set_arm (Direction dir) |
Turnstile_Pivot_Base::set_arms (DirectionBits arms) |
4184 |
|
{ |
4185 |
|
GridPos p = get_pos(); |
4186 |
|
if (arms & NORTHBIT) set_arm(NORTH); |
4187 |
|
if (arms & EASTBIT) set_arm(EAST); |
4188 |
|
if (arms & SOUTHBIT) set_arm(SOUTH); |
4189 |
|
if (arms & WESTBIT) set_arm(WEST); |
4190 |
|
} |
4191 |
|
|
4192 |
|
void |
4193 |
|
Turnstile_Pivot_Base::set_arm (Direction dir) |
4194 |
{ |
{ |
4195 |
char *names[4] = { "st-turnstile-w", |
char *names[4] = { "st-turnstile-w", |
4196 |
"st-turnstile-s", |
"st-turnstile-s", |
4206 |
} |
} |
4207 |
|
|
4208 |
bool |
bool |
4209 |
Turnstile_Pivot::rotate_left() |
Turnstile_Pivot_Base::rotate_left() |
4210 |
{ |
{ |
4211 |
DirectionBits arms = arms_present(); |
DirectionBits arms = arms_present(); |
4212 |
bool can_rotate = true; |
bool can_rotate = true; |
4213 |
|
|
4214 |
if (arms & NORTHBIT) { |
if (arms & NORTHBIT) { |
4215 |
can_rotate &= no_stone(-1,-1); |
can_rotate &= no_stone(-1,-1); |
4216 |
if (! (arms & WESTBIT)) |
if (! (arms & WESTBIT)) can_rotate &= no_stone(-1,0); |
|
can_rotate &= no_stone(-1,0); |
|
4217 |
} |
} |
4218 |
if (arms & WESTBIT) { |
if (arms & WESTBIT) { |
4219 |
can_rotate &= no_stone(-1,+1); |
can_rotate &= no_stone(-1,+1); |
4220 |
if (! (arms & SOUTHBIT)) |
if (! (arms & SOUTHBIT)) can_rotate &= no_stone(0,+1); |
|
can_rotate &= no_stone(0,+1); |
|
4221 |
} |
} |
4222 |
if (arms & SOUTHBIT) { |
if (arms & SOUTHBIT) { |
4223 |
can_rotate &= no_stone(+1,+1); |
can_rotate &= no_stone(+1,+1); |
4224 |
if (! (arms & EASTBIT)) |
if (! (arms & EASTBIT)) can_rotate &= no_stone(+1,0); |
|
can_rotate &= no_stone(+1,0); |
|
4225 |
} |
} |
4226 |
if (arms & EASTBIT) { |
if (arms & EASTBIT) { |
4227 |
can_rotate &= no_stone(+1,-1); |
can_rotate &= no_stone(+1,-1); |
4228 |
if (! (arms & NORTHBIT)) |
if (! (arms & NORTHBIT)) can_rotate &= no_stone(0,-1); |
|
can_rotate &= no_stone(0,-1); |
|
4229 |
} |
} |
4230 |
|
|
4231 |
if (can_rotate) { |
if (can_rotate) { |
4232 |
// play_sound("rotate-left"); |
// play_sound("rotate-left"); |
4233 |
play_sound("st-magic"); |
play_sound("st-magic"); |
4234 |
set_anim("st-turnstile-anim"); |
// set_anim("st-turnstile-anim"); |
4235 |
remove_arms(arms); |
set_anim(anim()); |
|
if (arms & NORTHBIT) set_arm (WEST); |
|
|
if (arms & EASTBIT) set_arm (NORTH); |
|
|
if (arms & SOUTHBIT) set_arm (EAST); |
|
|
if (arms & WESTBIT) set_arm (SOUTH); |
|
4236 |
|
|
4237 |
#if defined(USE_IMPULSES) |
remove_arms(arms); |
4238 |
|
set_arms(rotate(arms, false)); |
4239 |
warpActorsInRange(false); |
warpActorsInRange(false); |
|
#endif // USE_IMPULSES |
|
4240 |
|
|
4241 |
display::GetStatusBar()->set_counter(player::IncMoveCounter()); |
display::GetStatusBar()->set_counter(player::IncMoveCounter()); |
4242 |
} |
} |
4244 |
} |
} |
4245 |
|
|
4246 |
bool |
bool |
4247 |
Turnstile_Pivot::rotate_right() |
Turnstile_Pivot_Base::rotate_right() |
4248 |
{ |
{ |
4249 |
DirectionBits arms = arms_present(); |
DirectionBits arms = arms_present(); |
4250 |
bool can_rotate = true; |
bool can_rotate = true; |
4251 |
|
|
4252 |
if (arms & NORTHBIT) { |
if (arms & NORTHBIT) { |
4253 |
can_rotate &= no_stone(+1,-1); |
can_rotate &= no_stone(+1,-1); |
4254 |
if (! (arms & EASTBIT)) |
if (! (arms & EASTBIT)) can_rotate &= no_stone(+1,0); |
|
can_rotate &= no_stone(+1,0); |
|
4255 |
} |
} |
4256 |
if (arms & WESTBIT) { |
if (arms & WESTBIT) { |
4257 |
can_rotate &= no_stone(-1,-1); |
can_rotate &= no_stone(-1,-1); |
4258 |
if (! (arms & NORTHBIT)) |
if (! (arms & NORTHBIT)) can_rotate &= no_stone(0,-1); |
|
can_rotate &= no_stone(0,-1); |
|
4259 |
} |
} |
4260 |
if (arms & SOUTHBIT) { |
if (arms & SOUTHBIT) { |
4261 |
can_rotate &= no_stone(-1,+1); |
can_rotate &= no_stone(-1,+1); |
4262 |
if (! (arms & WESTBIT)) |
if (! (arms & WESTBIT)) can_rotate &= no_stone(-1,0); |
|
can_rotate &= no_stone(-1,0); |
|
4263 |
} |
} |
4264 |
if (arms & EASTBIT) { |
if (arms & EASTBIT) { |
4265 |
can_rotate &= no_stone(+1,+1); |
can_rotate &= no_stone(+1,+1); |
4266 |
if (! (arms & SOUTHBIT)) |
if (! (arms & SOUTHBIT)) can_rotate &= no_stone(0,+1); |
|
can_rotate &= no_stone(0,+1); |
|
4267 |
} |
} |
4268 |
|
|
4269 |
if (can_rotate) { |
if (can_rotate) { |
4270 |
// play_sound("rotate-right"); |
// play_sound("rotate-right"); |
4271 |
play_sound("st-magic"); |
play_sound("st-magic"); |
4272 |
set_anim("st-turnstile-anim"); |
// set_anim("st-turnstile-anim"); |
4273 |
remove_arms(arms); |
set_anim(anim()); |
|
if (arms & NORTHBIT) set_arm (EAST); |
|
|
if (arms & EASTBIT) set_arm (SOUTH); |
|
|
if (arms & SOUTHBIT) set_arm (WEST); |
|
|
if (arms & WESTBIT) set_arm (NORTH); |
|
4274 |
|
|
4275 |
#if defined(USE_IMPULSES) |
remove_arms(arms); |
4276 |
|
set_arms(rotate(arms, true)); |
4277 |
warpActorsInRange(true); |
warpActorsInRange(true); |
|
#endif // USE_IMPULSES |
|
4278 |
|
|
4279 |
display::GetStatusBar()->set_counter(player::IncMoveCounter()); |
display::GetStatusBar()->set_counter(player::IncMoveCounter()); |
4280 |
} |
} |
4430 |
add_templ(new ThiefStone); |
add_templ(new ThiefStone); |
4431 |
add_templ(new TimerStone); |
add_templ(new TimerStone); |
4432 |
|
|
4433 |
add_templ (new Turnstile_Pivot); |
add_templ (new Turnstile_Pivot); // oxyd-comaptible |
4434 |
|
add_templ (new Turnstile_Pivot_Green); // not oxyd-comaptible |
4435 |
add_templ (new Turnstile_N); |
add_templ (new Turnstile_N); |
4436 |
add_templ (new Turnstile_S); |
add_templ (new Turnstile_S); |
4437 |
add_templ (new Turnstile_E); |
add_templ (new Turnstile_E); |