5 |
* modify it under the terms of the GNU General Public License |
* modify it under the terms of the GNU General Public License |
6 |
* as published by the Free Software Foundation; either version 2 |
* as published by the Free Software Foundation; either version 2 |
7 |
* of the License, or (at your option) any later version. |
* of the License, or (at your option) any later version. |
8 |
* |
* |
9 |
* This program is distributed in the hope that it will be useful, |
* This program is distributed in the hope that it will be useful, |
10 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 |
* GNU General Public License for more details. |
* GNU General Public License for more details. |
13 |
* |
* |
14 |
* You should have received a copy of the GNU General Public License along |
* You should have received a copy of the GNU General Public License along |
15 |
* with this program; if not, write to the Free Software Foundation, Inc., |
* with this program; if not, write to the Free Software Foundation, Inc., |
16 |
* 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. |
* 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. |
34 |
//---------------------------------------- |
//---------------------------------------- |
35 |
// Item implementation |
// Item implementation |
36 |
//---------------------------------------- |
//---------------------------------------- |
37 |
Item::Item(const char *name) |
Item::Item(const char *name) |
38 |
: TGridObject<GRID_ITEMS>(name) |
: TGridObject<GRID_ITEMS>(name) |
39 |
{} |
{} |
40 |
|
|
41 |
string |
string |
42 |
Item::get_inventory_model() |
Item::get_inventory_model() |
43 |
{ |
{ |
44 |
return get_kind(); |
return get_kind(); |
45 |
} |
} |
56 |
px::V2 Item::get_force(Actor *a) |
px::V2 Item::get_force(Actor *a) |
57 |
{ return px::V2(); } |
{ return px::V2(); } |
58 |
|
|
59 |
bool |
bool |
60 |
Item::actor_hit(Actor *actor) |
Item::actor_hit(Actor *actor) |
61 |
{ |
{ |
62 |
const double ITEM_RADIUS = 0.3; |
const double ITEM_RADIUS = 0.3; |
87 |
bool on_laserhit(Direction d) { |
bool on_laserhit(Direction d) { |
88 |
play_sound("st-magic"); |
play_sound("st-magic"); |
89 |
world::SetItem(get_pos(), MakeItem("it-hammer")); |
world::SetItem(get_pos(), MakeItem("it-hammer")); |
90 |
return false; |
return false; |
91 |
} |
} |
92 |
public: |
public: |
93 |
Sword() : Item("it-sword") {} |
Sword() : Item("it-sword") {} |
98 |
bool on_laserhit(Direction d) { |
bool on_laserhit(Direction d) { |
99 |
play_sound("st-magic"); |
play_sound("st-magic"); |
100 |
world::SetItem(get_pos(), MakeItem("it-sword")); |
world::SetItem(get_pos(), MakeItem("it-sword")); |
101 |
return false; |
return false; |
102 |
} |
} |
103 |
public: |
public: |
104 |
Hammer() : Item("it-hammer") {} |
Hammer() : Item("it-hammer") {} |
106 |
|
|
107 |
class ExtraLife : public Item { |
class ExtraLife : public Item { |
108 |
CLONEOBJ(ExtraLife); |
CLONEOBJ(ExtraLife); |
109 |
std::string get_inventory_model() { |
std::string get_inventory_model() { |
110 |
if (player::CurrentPlayer()==0) |
if (player::CurrentPlayer()==0) |
111 |
return "inv-blackball"; |
return "inv-blackball"; |
112 |
else |
else |
171 |
} |
} |
172 |
} |
} |
173 |
|
|
174 |
string get_inventory_model() |
string get_inventory_model() |
175 |
{ |
{ |
176 |
switch(get_value()) { |
switch(get_value()) { |
177 |
case 1: return "it-coin1"; |
case 1: return "it-coin1"; |
180 |
} |
} |
181 |
} |
} |
182 |
|
|
183 |
int get_value() { |
int get_value() { |
184 |
int value = int_attrib("value"); |
int value = int_attrib("value"); |
185 |
// assert (value==1 || value==2 || value==4); |
// assert (value==1 || value==2 || value==4); |
186 |
return value; |
return value; |
187 |
} |
} |
208 |
class HillHollow : public Item { |
class HillHollow : public Item { |
209 |
protected: |
protected: |
210 |
enum Type { HILL, HOLLOW, TINYHILL, TINYHOLLOW }; |
enum Type { HILL, HOLLOW, TINYHILL, TINYHOLLOW }; |
211 |
|
|
212 |
HillHollow(const char *name, Type t); |
HillHollow(const char *name, Type t); |
213 |
|
|
214 |
void transmute(Type newtype); |
void transmute(Type newtype); |
218 |
private: |
private: |
219 |
double get_forcefac() const { return m_forcefac[m_type]; } |
double get_forcefac() const { return m_forcefac[m_type]; } |
220 |
void shovel(); |
void shovel(); |
221 |
|
|
222 |
// Item interface |
// Item interface |
223 |
px::V2 get_force(Actor *a); |
px::V2 get_force(Actor *a); |
224 |
bool actor_hit(Actor *a) { return false; } |
bool actor_hit(Actor *a) { return false; } |
237 |
double HillHollow::m_forcefac[4] = {90,-90, 90, -90}; |
double HillHollow::m_forcefac[4] = {90,-90, 90, -90}; |
238 |
|
|
239 |
|
|
240 |
HillHollow::HillHollow(const char *name, Type t) |
HillHollow::HillHollow(const char *name, Type t) |
241 |
: Item(name), m_type(t) |
: Item(name), m_type(t) |
242 |
{} |
{} |
243 |
|
|
244 |
void HillHollow::on_stonehit(Stone *st) |
void HillHollow::on_stonehit(Stone *st) |
248 |
|
|
249 |
void HillHollow::shovel() |
void HillHollow::shovel() |
250 |
{ |
{ |
251 |
if (m_type==HOLLOW) |
if (m_type==HOLLOW) |
252 |
transmute (TINYHOLLOW); |
transmute (TINYHOLLOW); |
253 |
else if (m_type==HILL) |
else if (m_type==HILL) |
254 |
transmute (TINYHILL); |
transmute (TINYHILL); |
255 |
else |
else |
256 |
KillItem(get_pos()); |
KillItem(get_pos()); |
263 |
Type flippedkind[] = {HOLLOW,HILL, TINYHOLLOW,TINYHILL}; |
Type flippedkind[] = {HOLLOW,HILL, TINYHOLLOW,TINYHILL}; |
264 |
transmute(flippedkind[m_type]); |
transmute(flippedkind[m_type]); |
265 |
} |
} |
266 |
else if (m=="shovel") |
else if (m=="shovel") |
267 |
shovel(); |
shovel(); |
268 |
} |
} |
269 |
|
|
273 |
return v - V2(p.x+0.5, p.y+0.5); |
return v - V2(p.x+0.5, p.y+0.5); |
274 |
} |
} |
275 |
|
|
276 |
V2 HillHollow::get_force(Actor *a) |
V2 HillHollow::get_force(Actor *a) |
277 |
{ |
{ |
278 |
V2 v = vec_to_center(a->get_pos()); |
V2 v = vec_to_center(a->get_pos()); |
279 |
if (length(v) <= get_radius()) |
if (length(v) <= get_radius()) |
280 |
return get_forcefac()*v; |
return get_forcefac()*v; |
281 |
else |
else |
282 |
return px::V2(); |
return px::V2(); |
283 |
} |
} |
284 |
|
|
285 |
void HillHollow::transmute(Type newtype) |
void HillHollow::transmute(Type newtype) |
317 |
INSTANCELISTOBJ(Hollow); |
INSTANCELISTOBJ(Hollow); |
318 |
public: |
public: |
319 |
Hollow(); |
Hollow(); |
320 |
private: |
private: |
321 |
// Item interface. |
// Item interface. |
322 |
bool actor_hit(Actor *a); |
bool actor_hit(Actor *a); |
323 |
|
|
324 |
// Functions. |
// Functions. |
325 |
bool near_center_p (Actor *a); |
bool near_center_p (Actor *a); |
326 |
void check_if_level_finished(); |
void check_if_level_finished(); |
327 |
|
|
328 |
// Variables. |
// Variables. |
329 |
Actor *whiteball; // The small white ball that is currently being tracked |
Actor *whiteball; // The small white ball that is currently being tracked |
330 |
Uint32 enter_time; // ... when did it enter the hollow? |
Uint32 enter_time; // ... when did it enter the hollow? |
333 |
|
|
334 |
Hollow::InstanceList Hollow::instances; |
Hollow::InstanceList Hollow::instances; |
335 |
|
|
336 |
Hollow::Hollow() : HillHollow("it-hollow", HOLLOW), whiteball(0) |
Hollow::Hollow() : HillHollow("it-hollow", HOLLOW), whiteball(0) |
337 |
{} |
{} |
338 |
|
|
339 |
bool |
bool |
340 |
Hollow::near_center_p (Actor *a) |
Hollow::near_center_p (Actor *a) |
341 |
{ |
{ |
342 |
return (length(vec_to_center(a->get_pos())) < get_radius()/2); |
return (length(vec_to_center(a->get_pos())) < get_radius()/2); |
343 |
} |
} |
344 |
|
|
345 |
bool |
bool |
346 |
Hollow::actor_hit(Actor *a) |
Hollow::actor_hit(Actor *a) |
347 |
{ |
{ |
348 |
if (whiteball==0 && 0==strcmp(a->get_kind(),"ac-whiteball-small") |
if (whiteball==0 && 0==strcmp(a->get_kind(),"ac-whiteball-small") |
364 |
/* If every hollow in the level (a) contains a small white ball and |
/* If every hollow in the level (a) contains a small white ball and |
365 |
(b) this ball has been inside the hollow for at least MINTIME |
(b) this ball has been inside the hollow for at least MINTIME |
366 |
milliseconds, finish the level. */ |
milliseconds, finish the level. */ |
367 |
void |
void |
368 |
Hollow::check_if_level_finished() |
Hollow::check_if_level_finished() |
369 |
{ |
{ |
370 |
const unsigned MINTIME=1000; |
const unsigned MINTIME=1000; |
371 |
for (unsigned i=0; i<instances.size(); ++i) { |
for (unsigned i=0; i<instances.size(); ++i) { |
372 |
Hollow *h=(Hollow*) instances[i]; |
Hollow *h=(Hollow*) instances[i]; |
373 |
if (!h->whiteball || SDL_GetTicks() - h->enter_time < MINTIME) |
if (!h->whiteball || SDL_GetTicks() - h->enter_time < MINTIME) |
425 |
class Explosion : public Item { |
class Explosion : public Item { |
426 |
CLONEOBJ(Explosion); |
CLONEOBJ(Explosion); |
427 |
public: |
public: |
428 |
enum Strength { |
enum Strength { |
429 |
WEAK, // Explode but do nothing else. |
WEAK, // Explode but do nothing else. |
430 |
MEDIUM, // Explode and leave a hole in the ground. |
MEDIUM, // Explode and leave a hole in the ground. |
431 |
STRONG // Explode and shatter the floor. |
STRONG // Explode and shatter the floor. |
445 |
}; |
}; |
446 |
} |
} |
447 |
|
|
448 |
Explosion::Explosion(Strength st) |
Explosion::Explosion(Strength st) |
449 |
: Item("it-explosion"), strength(st) |
: Item("it-explosion"), strength(st) |
450 |
{} |
{} |
451 |
|
|
452 |
|
|
453 |
void |
void |
454 |
Explosion::animcb() |
Explosion::animcb() |
455 |
{ |
{ |
456 |
switch (strength) { |
switch (strength) { |
457 |
case WEAK: |
case WEAK: |
477 |
|
|
478 |
This item looks like a piece of paper and contains text messages |
This item looks like a piece of paper and contains text messages |
479 |
that can be displayed by activating the item. |
that can be displayed by activating the item. |
480 |
|
|
481 |
\subsection documenta Attributes |
\subsection documenta Attributes |
482 |
|
|
483 |
\b text: The message to be displayed. |
\b text: The message to be displayed. |
484 |
|
|
485 |
\subsection documente Example |
\subsection documente Example |
486 |
\verbatim |
\verbatim |
487 |
set_item("it-document", 1,1, {text="Hello World!"}) |
set_item("it-document", 1,1, {text="Hello World!"}) |
556 |
|
|
557 |
bool actor_hit(Actor *a) { |
bool actor_hit(Actor *a) { |
558 |
// don't pick up burning dynamite |
// don't pick up burning dynamite |
559 |
return (state == IDLE); |
return (state == IDLE); |
560 |
} |
} |
561 |
}; |
}; |
562 |
} |
} |
563 |
|
|
564 |
void |
void |
565 |
Dynamite::explode() |
Dynamite::explode() |
566 |
{ |
{ |
567 |
GridPos p = get_pos(); |
GridPos p = get_pos(); |
568 |
|
|
626 |
}; |
}; |
627 |
} |
} |
628 |
|
|
629 |
void |
void |
630 |
BlackBomb::explode() |
BlackBomb::explode() |
631 |
{ |
{ |
632 |
GridPos p = get_pos(); |
GridPos p = get_pos(); |
633 |
SendMessage(GetItem(move(p,enigma::NORTH)), "ignite"); |
SendMessage(GetItem(move(p,enigma::NORTH)), "ignite"); |
701 |
}; |
}; |
702 |
} |
} |
703 |
|
|
704 |
void |
void |
705 |
Trigger::stone_change(Stone *st) |
Trigger::stone_change(Stone *st) |
706 |
{ |
{ |
707 |
if (st == 0 && have_stone){ |
if (st == 0 && have_stone){ |
708 |
have_stone=false; |
have_stone=false; |
709 |
remove_object(); |
remove_object(); |
710 |
} |
} |
711 |
|
|
712 |
if (st != 0 && !have_stone){ |
if (st != 0 && !have_stone){ |
713 |
have_stone=true; |
have_stone=true; |
714 |
add_object(); |
add_object(); |
727 |
bool actor_hit(Actor *a) { return state==IDLE; } |
bool actor_hit(Actor *a) { return state==IDLE; } |
728 |
void on_drop(Actor *a) { start_growing(); } |
void on_drop(Actor *a) { start_growing(); } |
729 |
void on_stonehit(Stone *) { start_growing(); } |
void on_stonehit(Stone *) { start_growing(); } |
730 |
|
|
731 |
void start_growing() { |
void start_growing() { |
732 |
state=GROWING; |
state=GROWING; |
733 |
set_anim("it-seed-growing"); |
set_anim("it-seed-growing"); |
734 |
} |
} |
735 |
|
|
777 |
}; |
}; |
778 |
} |
} |
779 |
|
|
780 |
ShogunDot::ShogunDot() |
ShogunDot::ShogunDot() |
781 |
: Item("it-shogun"), activated(false) |
: Item("it-shogun"), activated(false) |
782 |
{ |
{ |
783 |
set_size(1); |
set_size(1); |
784 |
} |
} |
785 |
|
|
786 |
int |
int |
787 |
ShogunDot::get_size() const |
ShogunDot::get_size() const |
788 |
{ |
{ |
789 |
int size = int_attrib("size"); |
int size = int_attrib("size"); |
790 |
assert(1<=size && size<=3); |
assert(1<=size && size<=3); |
791 |
return size; |
return size; |
792 |
} |
} |
793 |
|
|
794 |
void |
void |
795 |
ShogunDot::init_model() |
ShogunDot::init_model() |
796 |
{ |
{ |
797 |
char *models[] = {"it-shogun1", "it-shogun2", "it-shogun3"}; |
char *models[] = {"it-shogun1", "it-shogun2", "it-shogun3"}; |
798 |
set_model(models[get_size()-1]); |
set_model(models[get_size()-1]); |
799 |
} |
} |
800 |
|
|
801 |
void |
void |
802 |
ShogunDot::stone_change(Stone *st) |
ShogunDot::stone_change(Stone *st) |
803 |
{ |
{ |
804 |
if (activated && st == 0) { |
if (activated && st == 0) { |
805 |
activated = false; |
assert(0); // no proper message was sent to ShogunDot |
806 |
world::PerformAction(this, false); |
} |
|
} |
|
807 |
} |
} |
808 |
|
|
809 |
#define streq(a,b) (strcmp((a), (b))==0) |
#define streq(a,b) (strcmp((a), (b))==0) |
810 |
void |
void |
811 |
ShogunDot::message(const string &str, const Value &v) |
ShogunDot::message(const string &str, const Value &v) |
812 |
{ |
{ |
813 |
int size=get_size(); |
int size = get_size(); |
814 |
const char *s = str.c_str(); |
const char *s = str.c_str(); |
815 |
|
|
816 |
if (activated && streq(s, "noshogun")) { |
if (activated && streq(s, "noshogun")) { |
817 |
activated=false; |
activated = false; |
818 |
world::PerformAction(this, false); |
world::PerformAction(this, false); |
819 |
} |
} |
820 |
else if ((size==1 && streq(s,"shogun1")) || |
else { |
821 |
(size==2 && streq(s,"shogun2")) || |
bool size_matches = |
822 |
(size==3 && streq(s,"shogun3"))) |
(strncmp(s, "shogun", 6) == 0) && |
823 |
{ |
((s[6]-'0') == size) && |
824 |
activated=true; |
(s[7] == 0); |
825 |
world::PerformAction(this, true); |
|
826 |
|
if (size_matches != activated) { |
827 |
|
activated = size_matches; |
828 |
|
world::PerformAction(this, activated); |
829 |
|
} |
830 |
} |
} |
831 |
} |
} |
832 |
|
|
833 |
|
#undef streq |
834 |
|
|
835 |
//---------------------------------------- |
//---------------------------------------- |
836 |
// Magnet |
// Magnet |
837 |
//---------------------------------------- |
//---------------------------------------- |
845 |
|
|
846 |
void set_pos(GridPos p) { center = to_vec(p) + V2(0.5,0.5); } |
void set_pos(GridPos p) { center = to_vec(p) + V2(0.5,0.5); } |
847 |
|
|
848 |
V2 get_force(Actor *a, V2 x, V2 v, double time) |
V2 get_force(Actor *a, V2 x, V2 v, double time) |
849 |
{ |
{ |
850 |
if (!m_active) |
if (!m_active) |
851 |
return V2(); |
return V2(); |
862 |
double strength; |
double strength; |
863 |
}; |
}; |
864 |
|
|
865 |
|
|
866 |
CLONEOBJ(Magnet); |
CLONEOBJ(Magnet); |
867 |
public: |
public: |
868 |
Magnet() : OnOffItem ("it-magnet") { |
Magnet() : OnOffItem ("it-magnet") { |
891 |
ff.m_active = on; |
ff.m_active = on; |
892 |
} |
} |
893 |
|
|
894 |
|
|
895 |
Magnet_FF ff; |
Magnet_FF ff; |
896 |
}; |
}; |
897 |
} |
} |
925 |
|
|
926 |
void set_pos(GridPos p) { center = to_vec(p) + V2(0.5,0.5); } |
void set_pos(GridPos p) { center = to_vec(p) + V2(0.5,0.5); } |
927 |
|
|
928 |
V2 get_force(Actor *a, V2 x, V2 v, double time) |
V2 get_force(Actor *a, V2 x, V2 v, double time) |
929 |
{ |
{ |
930 |
V2 b = center - x; |
V2 b = center - x; |
931 |
double bb = length(b); |
double bb = length(b); |
940 |
double range; // Range of the force |
double range; // Range of the force |
941 |
}; |
}; |
942 |
|
|
943 |
class WormHole : public Item, public enigma::TimeHandler |
class WormHole : public Item, public enigma::TimeHandler |
944 |
{ |
{ |
945 |
CLONEOBJ(WormHole); |
CLONEOBJ(WormHole); |
946 |
public: |
public: |
974 |
bool near_center_p (Actor *a) { |
bool near_center_p (Actor *a) { |
975 |
return (length(vec_to_center(a->get_pos())) < 0.5/4); |
return (length(vec_to_center(a->get_pos())) < 0.5/4); |
976 |
} |
} |
977 |
|
|
978 |
// Variables. |
// Variables. |
979 |
WormHole_FF ff; |
WormHole_FF ff; |
980 |
}; |
}; |
981 |
} |
} |
982 |
|
|
983 |
bool |
bool |
984 |
WormHole::actor_hit(Actor *actor) |
WormHole::actor_hit(Actor *actor) |
985 |
{ |
{ |
986 |
if (near_center_p(actor)) { |
if (near_center_p(actor)) { |
1004 |
CLONEOBJ(YinYang); |
CLONEOBJ(YinYang); |
1005 |
public: |
public: |
1006 |
YinYang() : Item("it-yinyang") {} |
YinYang() : Item("it-yinyang") {} |
1007 |
|
|
1008 |
string get_inventory_model() { |
string get_inventory_model() { |
1009 |
if (player::CurrentPlayer()==0) |
if (player::CurrentPlayer()==0) |
1010 |
return "it-yinyang"; |
return "it-yinyang"; |
1013 |
} |
} |
1014 |
|
|
1015 |
ItemAction activate(Actor *a, GridPos) { |
ItemAction activate(Actor *a, GridPos) { |
1016 |
// Switch to other marble |
// Switch to other marble |
1017 |
player::SwapPlayers(); |
player::SwapPlayers(); |
1018 |
sound::PlaySound ("switch"); |
sound::PlaySound ("switch"); |
1019 |
return ITEM_KEEP; |
return ITEM_KEEP; |
1050 |
CLONEOBJ(Pipe); |
CLONEOBJ(Pipe); |
1051 |
public: |
public: |
1052 |
Pipe() : Item("it-pipe") {set_attrib("type", 1);} |
Pipe() : Item("it-pipe") {set_attrib("type", 1);} |
1053 |
|
|
1054 |
string get_inventory_model() { |
string get_inventory_model() { |
1055 |
char modelname[20]; |
char modelname[20]; |
1056 |
sprintf(modelname, "it-pipe%d", int_attrib("type")); |
sprintf(modelname, "it-pipe%d", int_attrib("type")); |