146 |
return V3(); |
return V3(); |
147 |
|
|
148 |
if (a->int_attrib("mouseforce")) |
if (a->int_attrib("mouseforce")) |
149 |
return force*exp(-time*options::MouseDamping); |
return force; //*exp(-time*options::MouseDamping); |
150 |
else |
else |
151 |
return V3(); |
return V3(); |
152 |
} |
} |
153 |
|
|
154 |
void tick(double dtime) { |
void tick(double dtime) { |
155 |
|
|
156 |
double damping=options::MouseDamping; |
double damping=options::MouseDamping; |
157 |
force *= exp(-dtime*damping); |
force *= exp(-dtime*damping); |
158 |
|
|
159 |
|
force=V3(); |
160 |
// if (length(force) < 0.01) |
// if (length(force) < 0.01) |
161 |
// force = V3(); |
// force = V3(); |
162 |
} |
} |
237 |
ForceList forces; |
ForceList forces; |
238 |
MouseForce *mouseforce; |
MouseForce *mouseforce; |
239 |
|
|
|
FieldArray *fields; // the grid of static objects |
|
240 |
ActorList actorlist; // list of movable, dynamic objects |
ActorList actorlist; // list of movable, dynamic objects |
|
} |
|
241 |
|
|
242 |
tools::Timer world::g_timer; |
class Level { |
243 |
|
public: |
244 |
|
Level(int ww, int hh) : fields(ww,hh) { |
245 |
|
w = ww; |
246 |
|
h = hh; |
247 |
|
} |
248 |
|
|
249 |
|
bool contains (GridPos p) { |
250 |
|
return (p.x>=0 && p.y>=0 && p.x<w && p.y<h); |
251 |
|
} |
252 |
|
|
253 |
static bool |
Field *get_field (GridPos p) { |
254 |
level_contains(GridPos p) |
if (this->contains(p)) |
255 |
{ |
return &fields(p.x,p.y); |
256 |
return (p.x >= 0 && p.y >= 0 && |
else |
257 |
p.x < int(fields->width()) && p.y < int(fields->height())); |
return 0; |
258 |
|
} |
259 |
|
|
260 |
|
|
261 |
|
// Variables. |
262 |
|
FieldArray fields; // Contains floors, items, etc. |
263 |
|
int w, h; // Width and height of the level |
264 |
|
}; |
265 |
|
|
266 |
|
Level *level; |
267 |
} |
} |
268 |
|
|
269 |
|
tools::Timer world::g_timer; |
270 |
|
|
271 |
|
|
272 |
//====================================================================== |
//====================================================================== |
273 |
// PHYSICS SIMULATION |
// PHYSICS SIMULATION |
466 |
} |
} |
467 |
|
|
468 |
static void |
static void |
469 |
find_stone_contacts(Actor *a, StoneContactList &cl) |
find_stone_contacts (Actor *a, StoneContactList &cl) |
470 |
{ |
{ |
471 |
ActorInfo &ai = *a->get_actorinfo(); |
ActorInfo &ai = *a->get_actorinfo(); |
472 |
px::Rect r(int(ai.pos[0]-0.5), int(ai.pos[1]-0.5), |
px::Rect r(int(ai.pos[0]-0.5), int(ai.pos[1]-0.5), |
492 |
cl.push_back(contacts[i][j]); |
cl.push_back(contacts[i][j]); |
493 |
} |
} |
494 |
|
|
495 |
|
|
496 |
|
/* |
497 |
|
This function is called for every contact between an actor and a |
498 |
|
stone. It is here that the stones are informed about that event. Note |
499 |
|
that a stone may kill itself during a call to actor_hit() or |
500 |
|
actor_contact() so we must not refer to it after having called these |
501 |
|
functions. (Incidentally, this is why StoneContact only contains a |
502 |
|
'stonepos' and no 'stone' entry. |
503 |
|
*/ |
504 |
static V3 |
static V3 |
505 |
handle_stone_contact(V3 normal, StoneContact &sc) |
handle_stone_contact(V3 normal, StoneContact &sc) |
506 |
{ |
{ |
508 |
ActorInfo *ai = a->get_actorinfo(); |
ActorInfo *ai = a->get_actorinfo(); |
509 |
|
|
510 |
if (sc.is_collision) { |
if (sc.is_collision) { |
|
// The stone may kill itself during a call to actor_hit(), so |
|
|
// extract all relevant data before invoking this method! |
|
|
// GridPos stone_pos = sc.stone->get_pos(); |
|
511 |
if (Stone *stone = world::GetStone(sc.stonepos)) |
if (Stone *stone = world::GetStone(sc.stonepos)) |
512 |
stone->actor_hit(sc); |
stone->actor_hit(sc); |
513 |
if (!sc.fake_collision && sc.response != STONE_PASS) { |
if (!sc.fake_collision && sc.response != STONE_PASS) { |
514 |
normal += sc.normal; |
normal += sc.normal; |
515 |
normal /= length(normal); |
normal /= length(normal); |
516 |
|
|
517 |
if (length(ai->vel) > 0.1) |
if (length(ai->vel) > 0.1) { |
|
{ |
|
518 |
AddSprite(display::SPRITE_EFFECT, sc.contact_point, "ring-anim"); |
AddSprite(display::SPRITE_EFFECT, sc.contact_point, "ring-anim"); |
519 |
sound::PlaySound(sc.sound.c_str()); //collision_sound.c_str()); |
sound::PlaySound(sc.sound.c_str()); |
520 |
} |
} |
521 |
} |
} |
522 |
} |
} |
637 |
static void |
static void |
638 |
clear_world() |
clear_world() |
639 |
{ |
{ |
640 |
delete fields; |
delete level; |
641 |
|
level = 0; |
642 |
delete mouseforce; |
delete mouseforce; |
|
fields=0; |
|
643 |
mouseforce=0; |
mouseforce=0; |
644 |
px::delete_sequence(forces.begin(), forces.end()); |
px::delete_sequence(forces.begin(), forces.end()); |
645 |
forces.clear(); |
forces.clear(); |
652 |
world::Create(int w, int h) |
world::Create(int w, int h) |
653 |
{ |
{ |
654 |
clear_world(); |
clear_world(); |
655 |
fields = new FieldArray(w,h); |
level = new Level(w,h); |
656 |
mouseforce = new MouseForce; |
mouseforce = new MouseForce; |
657 |
display::NewWorld(w, h); |
display::NewWorld(w, h); |
658 |
player::NewWorld(); |
player::NewWorld(); |
739 |
forces.erase(i); |
forces.erase(i); |
740 |
} |
} |
741 |
|
|
|
|
|
|
|
|
|
namespace |
|
|
{ |
|
|
Field &get_field(GridPos p) { |
|
|
return fields->get(p.x, p.y); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
742 |
//---------------------------------------- |
//---------------------------------------- |
743 |
// Layer |
// Layer |
744 |
// |
// |
751 |
public: |
public: |
752 |
Layer(T* deflt = 0) : defaultval(deflt) {} |
Layer(T* deflt = 0) : defaultval(deflt) {} |
753 |
T *get(GridPos p) { |
T *get(GridPos p) { |
754 |
return (level_contains(p)) ? raw_get(p) : defaultval; |
if (Field *f=level->get_field(p)) |
755 |
|
return raw_get(*f); |
756 |
|
else |
757 |
|
return defaultval; |
758 |
} |
} |
759 |
|
|
760 |
T *yield(GridPos p) { |
T *yield(GridPos p) { |
761 |
if (level_contains(p)) { |
if (Field *f=level->get_field(p)) { |
762 |
T *x = raw_get(p); |
T *x = raw_get(*f); |
763 |
if (x) { |
if (x) { |
764 |
raw_set(p, 0); |
raw_set(*f, 0); |
765 |
x->removal(); |
x->removal(); |
766 |
} |
} |
767 |
return x; |
return x; |
770 |
} |
} |
771 |
|
|
772 |
void set(GridPos p, T *x) { |
void set(GridPos p, T *x) { |
773 |
if (x && level_contains(p)) { |
if (x) { |
774 |
dispose(raw_get(p)); |
if (Field *f=level->get_field(p)) { |
775 |
raw_set(p, x); |
dispose(raw_get(*f)); |
776 |
x->creation(p); |
raw_set(*f, x); |
777 |
|
x->creation(p); |
778 |
|
} |
779 |
|
else |
780 |
|
dispose(x); |
781 |
} |
} |
|
else |
|
|
dispose(x); |
|
782 |
} |
} |
783 |
void kill(GridPos p) { dispose(yield(p)); } |
void kill(GridPos p) { dispose(yield(p)); } |
784 |
|
|
785 |
virtual T* raw_get(GridPos) = 0; |
virtual T* raw_get (Field &) = 0; |
786 |
virtual void raw_set(GridPos, T *) = 0; |
virtual void raw_set (Field &, T *) = 0; |
787 |
|
|
788 |
private: |
private: |
789 |
void dispose(T *x) { DisposeObject(x); } |
void dispose(T *x) { if (x) DisposeObject(x); } |
790 |
}; |
}; |
791 |
|
|
792 |
//---------------------------------------- |
//---------------------------------------- |
797 |
{ |
{ |
798 |
class FloorLayer : public Layer<Floor> { |
class FloorLayer : public Layer<Floor> { |
799 |
private: |
private: |
800 |
Floor *raw_get(GridPos p) { return get_field(p).floor; } |
Floor *raw_get (Field &f) { return f.floor; } |
801 |
void raw_set(GridPos p, Floor *x) {get_field(p).floor = x;} |
void raw_set (Field &f, Floor *x) { f.floor = x;} |
802 |
}; |
}; |
803 |
FloorLayer fl_layer; |
FloorLayer fl_layer; |
804 |
} |
} |
830 |
public: |
public: |
831 |
StoneLayer() : Layer<Stone>(&borderstone) {} |
StoneLayer() : Layer<Stone>(&borderstone) {} |
832 |
private: |
private: |
833 |
Stone *raw_get(GridPos p) { return get_field(p).stone; } |
Stone *raw_get (Field &f) { return f.stone; } |
834 |
void raw_set(GridPos p, Stone *st) {get_field(p).stone = st;} |
void raw_set (Field &f, Stone *st) { f.stone = st;} |
835 |
}; |
}; |
836 |
|
|
837 |
StoneLayer st_layer; |
StoneLayer st_layer; |
912 |
{ |
{ |
913 |
class ItemLayer : public Layer<Item> { |
class ItemLayer : public Layer<Item> { |
914 |
private: |
private: |
915 |
Item *raw_get(GridPos p) { return get_field(p).item; } |
Item *raw_get (Field &f) { return f.item; } |
916 |
void raw_set(GridPos p, Item *x) {get_field(p).item = x;} |
void raw_set (Field &f, Item *x) { f.item = x;} |
917 |
}; |
}; |
918 |
ItemLayer it_layer; |
ItemLayer it_layer; |
919 |
} |
} |
920 |
|
|
921 |
void world::KillItem(GridPos p) {it_layer.kill(p);} |
void world::KillItem(GridPos p) {it_layer.kill(p);} |
922 |
Item *world::GetItem(GridPos p) {return it_layer.get(p);} |
Item *world::GetItem(GridPos p) {return it_layer.get(p);} |
923 |
Item *world::YieldItem(GridPos p) {return it_layer.yield(p);} |
Item *world::YieldItem(GridPos p) { |
924 |
|
laser::MaybeRecalcLight(p); |
925 |
|
return it_layer.yield(p); |
926 |
|
} |
927 |
void world::SetItem(GridPos p, Item* st) {it_layer.set(p,st);} |
void world::SetItem(GridPos p, Item* st) {it_layer.set(p,st);} |
928 |
|
|
929 |
//---------------------------------------- |
//---------------------------------------- |