From: Matthias Braun Date: Sun, 9 Jul 2006 10:32:59 +0000 (+0000) Subject: merged new collision detection branch back into mainline X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=2892ebda09d24c977547159e34abf0244884b89e;p=supertux.git merged new collision detection branch back into mainline SVN-Revision: 3962 --- diff --git a/data/images/objects/bullets/firebullet.sprite b/data/images/objects/bullets/firebullet.sprite index c4381ecbd..dafa1f746 100644 --- a/data/images/objects/bullets/firebullet.sprite +++ b/data/images/objects/bullets/firebullet.sprite @@ -1,6 +1,6 @@ (supertux-sprite (action - (hitbox 12 12 0 0) + (hitbox 2 2 12 12) (fps 20) (images "fire_bullet-0.png" "fire_bullet-1.png" diff --git a/data/levels/test/simple.stl b/data/levels/test/simple.stl index c7f720d23..29d20c221 100644 --- a/data/levels/test/simple.stl +++ b/data/levels/test/simple.stl @@ -30,7 +30,7 @@ (speed 1) (width 100) (height 35) - (tiles 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 28 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 28 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 28 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 28 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 0 28 0 28 0 28 0 28 0 28 0 0 28 0 28 0 28 28 28 28 28 28 28 28 28 28 28 28 28 28 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 28 0 0 0 0 0 0 0 0 28 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 28 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) + (tiles 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 28 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 28 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 28 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 28 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 0 28 0 28 0 28 0 28 0 28 0 0 28 0 28 0 28 28 28 28 28 28 28 28 28 28 28 28 28 28 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 28 0 0 0 0 0 0 0 0 28 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 48 48 48 48 48 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 28 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 48 0 0 0 0 48 0 0 0 0 0 0 0 0 0 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 48 0 0 0 0 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 48 0 102 0 0 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 48 48 48 48 48 48 48 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 0 0 0 0 0 0 0 0 0 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 48 0 0 0 0 0 0 0 48 0 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 48 0 0 0 0 0 0 0 0 0 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 48 0 0 0 0 0 0 0 0 0 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 48 48 48 48 48 48 48 48 48 48 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) ) (tilemap (z-pos 100) diff --git a/data/levels/test/slopes.stl b/data/levels/test/slopes.stl index c7789c230..fb1716425 100644 --- a/data/levels/test/slopes.stl +++ b/data/levels/test/slopes.stl @@ -30,7 +30,7 @@ (speed 1) (width 150) (height 35) - (tiles 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1051 1001 1002 1001 1002 1001 1002 1052 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1053 1005 1006 1005 1006 1005 1006 1054 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1051 1055 1009 1009 1009 1009 1009 1009 1056 1052 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1053 1057 1009 1009 1009 1009 1009 1009 1058 1054 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1051 1055 1009 1009 1009 1009 1009 1009 1009 1009 1056 1052 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1053 1057 1009 1009 1009 1009 1009 1009 1009 1009 1058 1054 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1051 1001 1002 1001 1003 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1045 1055 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1056 1046 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1053 1005 1006 1005 1007 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1045 1047 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1058 1048 1046 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1051 1055 1013 1013 1013 1011 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1045 1047 1049 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1050 1048 1046 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1060 1001 1002 1001 1003 0 0 0 0 0 0 0 0 0 0 0 0 1001 1002 1001 1003 0 0 0 0 0 0 0 0 0 0 0 0 1053 1057 1013 1013 1013 1011 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1045 1047 1049 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1050 1048 1061 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1060 1063 1064 1005 1006 1005 1007 0 0 0 0 0 0 0 0 0 0 1045 1047 1005 1006 1005 1007 0 0 0 0 0 1051 1052 0 0 0 0 1051 1055 1013 1013 1013 1013 1011 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1060 1047 1049 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1050 1065 1066 1061 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1060 1061 0 0 0 0 1060 1063 1064 1013 1013 1013 1013 1013 1011 0 0 0 0 0 1045 1046 0 0 1045 1047 1049 1013 1013 1013 1011 0 0 0 0 0 1053 1054 0 0 0 0 1053 1057 1013 1013 1013 1013 1011 0 0 0 0 0 0 0 0 0 0 0 0 0 1060 1063 1064 1049 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1069 1070 1065 1066 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1001 1002 1001 1002 1001 1002 1001 1063 1064 1065 1066 1002 1001 1063 1064 1067 1013 1013 1013 1013 1013 1013 1035 1001 1002 1001 1002 1001 1047 1048 1001 1002 1047 1049 1013 1013 1013 1013 1035 1001 1002 1001 1002 1001 1055 1056 1002 1001 1002 1001 1055 1013 1013 1013 1013 1013 1035 1002 1001 1002 1001 1002 1001 1002 1001 1002 1001 1002 1001 1063 1064 1067 1068 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1070 1065 1066 1002 1001 1002 1001 1002 1001 1002 1001 1002 1001 1002 1001 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1005 1006 1005 1006 1005 1006 1005 1067 1068 1069 1070 1006 1005 1067 1068 1069 1013 1013 1013 1013 1013 1013 1043 1005 1006 1005 1006 1005 1049 1050 1005 1006 1049 1013 1013 1013 1013 1013 1043 1005 1006 1005 1006 1005 1057 1058 1006 1005 1006 1005 1057 1013 1013 1013 1013 1013 1043 1006 1005 1006 1005 1006 1005 1006 1005 1006 1005 1006 1005 1067 1068 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1069 1070 1006 1005 1006 1005 1006 1005 1006 1005 1006 1005 1006 1005 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1013 1013 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1009 1009 1009 1009 1009 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1013 1013 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1009 1009 1009 1009 1009 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1013 1013 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1009 1009 1009 1009 1009 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1060 1061 0 1013 1013 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1009 1009 1009 1009 1035 1061 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1060 1063 1064 1065 1066 1013 1013 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1009 1009 1009 1009 1043 1065 1066 1061 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1060 1063 1064 1013 1013 1013 1013 1013 1013 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1009 1009 1009 1009 1009 1069 1070 1065 1066 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1001 1002 1001 1002 1001 1001 1002 1001 1002 1001 1063 1064 1013 1013 1013 1013 1013 1013 1013 1013 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1009 1009 1009 1009 1009 1009 1009 1009 1070 1065 1066 1002 1002 1001 1002 1001 1002 1001 1002 1001 1002 1001 1002 1001 1002 1001 1002 1001 1002 1001 1002 1001 1002 1001 1002 1001 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1005 1006 1005 1006 1005 1005 1006 1005 1006 1005 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1009 1009 1009 1009 1009 1009 1009 1009 1009 1069 1070 1006 1006 1005 1006 1005 1006 1005 1006 1005 1006 1005 1006 1005 1006 1005 1006 1005 1006 1005 1006 1005 1006 1005 1006 1005 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) + (tiles 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1051 1001 1002 1001 1002 1001 1002 1052 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1053 1005 1006 1005 1006 1005 1006 1054 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1051 1055 1009 1009 1009 1009 1009 1009 1056 1052 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1053 1057 1009 1009 1009 1009 1009 1009 1058 1054 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1051 1055 1009 1009 1009 1009 1009 1009 1009 1009 1056 1052 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1053 1057 1009 1009 1009 1009 1009 1009 1009 1009 1058 1054 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1051 1001 1002 1001 1003 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1045 1055 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1056 1046 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1053 1005 1006 1005 1007 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1045 1047 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1058 1048 1046 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1051 1055 1013 1013 1013 1011 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1045 1047 1049 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1050 1048 1046 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1060 1001 1002 1001 1003 0 0 0 0 0 0 0 0 0 0 0 0 1001 1002 1001 1003 0 0 0 0 0 0 0 0 0 0 0 0 1053 1057 1013 1013 1013 1011 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1045 1047 1049 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1050 1048 1061 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1060 1063 1064 1005 1006 1005 1007 0 0 0 0 0 0 0 0 0 0 1045 1047 1005 1006 1005 1007 0 0 0 0 0 1051 1052 0 0 0 0 1051 1055 1013 1013 1013 1013 1011 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1060 1047 1049 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1050 1065 1066 1061 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1060 1061 0 0 0 0 1060 1063 1064 1013 1013 1013 1013 1013 1011 0 0 0 0 0 1045 1046 0 0 1045 1047 1049 1013 1013 1013 1011 0 0 0 0 0 1053 1054 0 0 0 0 1053 1057 1013 1013 1013 1013 1011 0 0 0 0 0 0 0 0 0 0 0 0 0 1060 1063 1064 1049 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1069 1070 1065 1066 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1001 1002 1001 1002 1001 1002 1001 1063 1064 1065 1066 1002 1001 1063 1064 1067 1013 1013 1013 1013 1013 1013 1035 1001 1002 1001 1002 1001 1047 1048 1001 1002 1047 1049 1013 1013 1013 1013 1035 1001 1002 1001 1002 1001 1055 1056 1002 1001 1002 1001 1055 1013 1013 1013 1013 1013 1035 1002 1001 1002 1001 1002 1001 1002 1001 1002 1001 1002 1001 1063 1064 1067 1068 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1070 1065 1066 1002 1001 1002 1001 1002 1001 1002 1001 1002 1001 1002 1001 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1005 1006 1005 1006 1005 1006 1005 1067 1068 1069 1070 1006 1005 1067 1068 1069 1013 1013 1013 1013 1013 1013 1043 1005 1006 1005 1006 1005 1049 1050 1005 1006 1049 1013 1013 1013 1013 1013 1043 1006 1006 1005 1006 1005 1057 1058 1006 1005 1006 1005 1057 1013 1013 1013 1013 1013 1043 1006 1005 1006 1005 1006 1005 1006 1005 1006 1005 1006 1005 1067 1068 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1009 1069 1070 1006 1005 1006 1005 1006 1005 1006 1005 1006 1005 1006 1005 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1013 1013 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1060 1063 1064 1013 1013 1013 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1009 1009 1009 1009 1009 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1060 1063 1064 1013 1013 1013 1013 1013 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1009 1009 1009 1009 1009 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1060 1063 1064 1013 1013 1013 1013 1013 1013 1013 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1009 1009 1009 1009 1009 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1060 1061 0 1013 1013 0 0 0 0 0 1060 1061 0 0 0 0 0 0 1060 1063 1064 1013 1013 1013 1013 1013 1013 1013 1013 1013 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1009 1009 1009 1009 1035 1061 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1060 1063 1064 1065 1066 1013 1013 0 0 0 1060 1063 1064 1065 1066 1061 0 0 1060 1063 1064 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1009 1009 1009 1009 1043 1065 1066 1061 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1060 1063 1064 1013 1013 1013 1013 1013 1013 0 1060 1063 1064 1013 1013 1013 1013 1065 1066 1063 1064 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1009 1009 1009 1009 1009 1069 1070 1065 1066 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1001 1002 1001 1002 1001 1001 1002 1001 1002 1001 1063 1064 1013 1013 1013 1013 1013 1013 1013 1013 1063 1064 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1009 1009 1009 1009 1009 1009 1009 1009 1070 1065 1066 1002 1002 1001 1002 1001 1002 1001 1002 1001 1002 1001 1002 1001 1002 1001 1002 1001 1002 1001 1002 1001 1002 1001 1002 1001 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1005 1006 1005 1006 1005 1005 1006 1005 1006 1005 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 1013 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1009 1009 1009 1009 1009 1009 1009 1009 1009 1069 1070 1006 1006 1005 1006 1005 1006 1005 1006 1005 1006 1005 1006 1005 1006 1005 1006 1005 1006 1005 1006 1005 1006 1005 1006 1005 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) ) (tilemap (z-pos 100) diff --git a/src/badguy/angrystone.cpp b/src/badguy/angrystone.cpp index 010230c19..bcf6d90f8 100644 --- a/src/badguy/angrystone.cpp +++ b/src/badguy/angrystone.cpp @@ -53,10 +53,14 @@ AngryStone::activate() sprite->set_action("idle"); } -HitResponse -AngryStone::collision_solid(GameObject& , const CollisionHit& hit) +void +AngryStone::collision_solid(const CollisionHit& hit) { - if ((state == ATTACKING) && (hit.normal.x == -attackDirection.x) && (hit.normal.y == attackDirection.y)) { + // TODO + (void) hit; +#if 0 + if ((state == ATTACKING) && + (hit.normal.x == -attackDirection.x) && (hit.normal.y == attackDirection.y)) { state = IDLE; sprite->set_action("idle"); physic.set_velocity_x(0); @@ -65,8 +69,7 @@ AngryStone::collision_solid(GameObject& , const CollisionHit& hit) oldWallDirection.x = attackDirection.x; oldWallDirection.y = attackDirection.y; } - - return CONTINUE; +#endif } void diff --git a/src/badguy/angrystone.hpp b/src/badguy/angrystone.hpp index 0b7dbf788..3b1c97467 100644 --- a/src/badguy/angrystone.hpp +++ b/src/badguy/angrystone.hpp @@ -30,7 +30,7 @@ public: void activate(); void write(lisp::Writer& writer); - HitResponse collision_solid(GameObject& other, const CollisionHit& hit); + void collision_solid(const CollisionHit& hit); HitResponse collision_badguy(BadGuy& badguy, const CollisionHit& hit); void active_update(float elapsed_time); void kill_fall(); diff --git a/src/badguy/badguy.cpp b/src/badguy/badguy.cpp index 3c1595f21..26db65d46 100644 --- a/src/badguy/badguy.cpp +++ b/src/badguy/badguy.cpp @@ -144,7 +144,7 @@ BadGuy::deactivate() void BadGuy::save(lisp::Writer& ) { - log_warning << "tried to write out a generic badguy" << std::endl; + log_warning << "tried to write out a generic badguy" << std::endl; } void @@ -173,9 +173,6 @@ BadGuy::collision(GameObject& other, const CollisionHit& hit) case STATE_INACTIVE: return ABORT_MOVE; case STATE_ACTIVE: { - if(other.get_flags() & FLAG_SOLID) - return collision_solid(other, hit); - BadGuy* badguy = dynamic_cast (&other); if(badguy && badguy->state == STATE_ACTIVE && badguy->get_group() == COLGROUP_MOVING) return collision_badguy(*badguy, hit); @@ -191,8 +188,6 @@ BadGuy::collision(GameObject& other, const CollisionHit& hit) return FORCE_MOVE; } case STATE_SQUISHED: - if(other.get_flags() & FLAG_SOLID) - return CONTINUE; return FORCE_MOVE; case STATE_FALLING: return FORCE_MOVE; @@ -201,28 +196,20 @@ BadGuy::collision(GameObject& other, const CollisionHit& hit) return ABORT_MOVE; } -HitResponse -BadGuy::collision_solid(GameObject& , const CollisionHit& ) +void +BadGuy::collision_solid(const CollisionHit& ) { - return FORCE_MOVE; } HitResponse BadGuy::collision_player(Player& player, const CollisionHit& ) { - /* - printf("PlayerHit: GT %3.1f PM: %3.1f %3.1f BM: %3.1f %3.1f Hit: %3.1f %3.1f\n", - game_time, - player.get_movement().x, player.get_movement().y, - get_movement().x, get_movement().y, - hit.normal.x, hit.normal.y); - */ - // hit from above? if(player.get_bbox().p2.y < (bbox.p1.y + 16)) { // if it's not possible to squish us, then this will hurt - if(collision_squished(player)) + if(collision_squished(player)) { return ABORT_MOVE; + } } if(player.is_invincible()) { diff --git a/src/badguy/badguy.hpp b/src/badguy/badguy.hpp index 0b8d8de16..797cd44bf 100644 --- a/src/badguy/badguy.hpp +++ b/src/badguy/badguy.hpp @@ -57,8 +57,7 @@ public: * implemetnation calls collision_player, collision_solid, collision_badguy * and collision_squished */ - virtual HitResponse collision(GameObject& other, - const CollisionHit& hit); + virtual HitResponse collision(GameObject& other, const CollisionHit& hit); /** Called when a collision with tile with special attributes occured */ virtual void collision_tile(uint32_t tile_attributes); @@ -96,14 +95,11 @@ protected: }; /** Called when the badguy collided with a player */ - virtual HitResponse collision_player(Player& player, - const CollisionHit& hit); + virtual HitResponse collision_player(Player& player, const CollisionHit& hit); /** Called when the badguy collided with solid ground */ - virtual HitResponse collision_solid(GameObject& other, - const CollisionHit& hit); + virtual void collision_solid(const CollisionHit& hit); /** Called when the badguy collided with another badguy */ - virtual HitResponse collision_badguy(BadGuy& other, - const CollisionHit& hit); + virtual HitResponse collision_badguy(BadGuy& other, const CollisionHit& hit); /** Called when the player hit the badguy from above. You should return true * if the badguy was squished, false if squishing wasn't possible @@ -111,8 +107,7 @@ protected: virtual bool collision_squished(Player& player); /** Called when the badguy collided with a bullet */ - virtual HitResponse collision_bullet(Bullet& bullet, - const CollisionHit& hit); + virtual HitResponse collision_bullet(Bullet& bullet, const CollisionHit& hit); /** called each frame when the badguy is activated. */ virtual void active_update(float elapsed_time); diff --git a/src/badguy/bomb.cpp b/src/badguy/bomb.cpp index 045953196..c9e2c8a61 100644 --- a/src/badguy/bomb.cpp +++ b/src/badguy/bomb.cpp @@ -57,13 +57,11 @@ Bomb::write(lisp::Writer& ) // bombs are only temporarily so don't write them out... } -HitResponse -Bomb::collision_solid(GameObject& , const CollisionHit& hit) +void +Bomb::collision_solid(const CollisionHit& hit) { - if(fabsf(hit.normal.y) > .5) + if(hit.bottom) physic.set_velocity_y(0); - - return CONTINUE; } HitResponse diff --git a/src/badguy/bomb.hpp b/src/badguy/bomb.hpp index 94d7159ef..40b29d08d 100644 --- a/src/badguy/bomb.hpp +++ b/src/badguy/bomb.hpp @@ -29,15 +29,13 @@ public: Bomb(const Bomb& bomb); void write(lisp::Writer& writer); - HitResponse collision_solid(GameObject& other, const CollisionHit& hit); + void collision_solid(const CollisionHit& hit); HitResponse collision_player(Player& player, const CollisionHit& hit); HitResponse collision_badguy(BadGuy& badguy, const CollisionHit& hit); void active_update(float elapsed_time); void kill_fall(); void explode(); - virtual Bomb* clone() const { return new Bomb(*this); } - private: enum State { STATE_TICKING, @@ -47,7 +45,6 @@ private: State state; std::auto_ptr ticking; - }; #endif diff --git a/src/badguy/bouncing_snowball.cpp b/src/badguy/bouncing_snowball.cpp index c0af31d9c..9e73ee3e9 100644 --- a/src/badguy/bouncing_snowball.cpp +++ b/src/badguy/bouncing_snowball.cpp @@ -60,33 +60,30 @@ BouncingSnowball::collision_squished(Player& player) return true; } -HitResponse -BouncingSnowball::collision_solid(GameObject& , const CollisionHit& hit) +void +BouncingSnowball::collision_solid(const CollisionHit& hit) { - if(hit.normal.y < -.5) { // hit floor - physic.set_velocity_y(JUMPSPEED); - } else if(hit.normal.y > .5) { // bumped on roof + if(hit.bottom) { + if(get_state() == STATE_ACTIVE) { + physic.set_velocity_y(JUMPSPEED); + } else { + physic.set_velocity_y(0); + } + } else if(hit.top) { physic.set_velocity_y(0); - } else { // left or right collision + } + + if(hit.left || hit.right) { // left or right collision dir = dir == LEFT ? RIGHT : LEFT; sprite->set_action(dir == LEFT ? "left" : "right"); physic.set_velocity_x(-physic.get_velocity_x()); } - - return CONTINUE; } HitResponse BouncingSnowball::collision_badguy(BadGuy& , const CollisionHit& hit) { - if(fabsf(hit.normal.x) > .8) { // left/right? - dir = dir == LEFT ? RIGHT : LEFT; - sprite->set_action(dir == LEFT ? "left" : "right"); - physic.set_velocity_x(-physic.get_velocity_x()); - } else if(hit.normal.y < -.8) { // grounf - physic.set_velocity_y(JUMPSPEED); - } - + collision_solid(hit); return CONTINUE; } diff --git a/src/badguy/bouncing_snowball.hpp b/src/badguy/bouncing_snowball.hpp index 1bcb8ab53..b2265909c 100644 --- a/src/badguy/bouncing_snowball.hpp +++ b/src/badguy/bouncing_snowball.hpp @@ -30,7 +30,7 @@ public: void activate(); void write(lisp::Writer& writer); - HitResponse collision_solid(GameObject& other, const CollisionHit& hit); + void collision_solid(const CollisionHit& hit); HitResponse collision_badguy(BadGuy& badguy, const CollisionHit& hit); virtual BouncingSnowball* clone() const { return new BouncingSnowball(*this); } diff --git a/src/badguy/dart.cpp b/src/badguy/dart.cpp index cd251c820..992d7749c 100644 --- a/src/badguy/dart.cpp +++ b/src/badguy/dart.cpp @@ -105,13 +105,11 @@ Dart::active_update(float elapsed_time) sound_source->set_position(get_pos()); } - -HitResponse -Dart::collision_solid(GameObject& , const CollisionHit& ) +void +Dart::collision_solid(const CollisionHit& ) { sound_manager->play("sounds/darthit.wav", get_pos()); remove_me(); - return ABORT_MOVE; } HitResponse diff --git a/src/badguy/dart.hpp b/src/badguy/dart.hpp index 670a0d6c0..bfed41fe2 100644 --- a/src/badguy/dart.hpp +++ b/src/badguy/dart.hpp @@ -40,7 +40,7 @@ public: void active_update(float elapsed_time); - HitResponse collision_solid(GameObject& object, const CollisionHit& hit); + void collision_solid(const CollisionHit& hit); HitResponse collision_badguy(BadGuy& badguy, const CollisionHit& hit); HitResponse collision_player(Player& player, const CollisionHit& hit); diff --git a/src/badguy/fish.cpp b/src/badguy/fish.cpp index 4c6817a44..4f2377843 100644 --- a/src/badguy/fish.cpp +++ b/src/badguy/fish.cpp @@ -50,10 +50,10 @@ Fish::write(lisp::Writer& writer) writer.end_list("fish"); } -HitResponse -Fish::collision_solid(GameObject& , const CollisionHit& chit) +void +Fish::collision_solid(const CollisionHit& chit) { - return hit(chit); + hit(chit); } HitResponse @@ -72,9 +72,9 @@ Fish::draw(DrawingContext& context) } HitResponse -Fish::hit(const CollisionHit& chit) +Fish::hit(const CollisionHit& hit) { - if(chit.normal.y < .5) { // hit ceiling + if(hit.top) { physic.set_velocity_y(0); } diff --git a/src/badguy/fish.hpp b/src/badguy/fish.hpp index e1e99200f..117d1d513 100644 --- a/src/badguy/fish.hpp +++ b/src/badguy/fish.hpp @@ -30,7 +30,7 @@ public: void draw(DrawingContext& context); - HitResponse collision_solid(GameObject& , const CollisionHit& ); + void collision_solid(const CollisionHit& hit); HitResponse collision_badguy(BadGuy& , const CollisionHit& ); void collision_tile(uint32_t tile_attributes); diff --git a/src/badguy/flyingsnowball.cpp b/src/badguy/flyingsnowball.cpp index 12dfefc80..66a2db504 100644 --- a/src/badguy/flyingsnowball.cpp +++ b/src/badguy/flyingsnowball.cpp @@ -75,14 +75,12 @@ FlyingSnowBall::collision_squished(Player& player) return true; } -HitResponse -FlyingSnowBall::collision_solid(GameObject& , const CollisionHit& hit) +void +FlyingSnowBall::collision_solid(const CollisionHit& hit) { - if(fabsf(hit.normal.y) > .5) { // hit floor or roof? + if(hit.top || hit.bottom) { physic.set_velocity_y(0); } - - return CONTINUE; } void diff --git a/src/badguy/flyingsnowball.hpp b/src/badguy/flyingsnowball.hpp index d9f8e9140..7e78c5266 100644 --- a/src/badguy/flyingsnowball.hpp +++ b/src/badguy/flyingsnowball.hpp @@ -31,7 +31,7 @@ public: void activate(); void write(lisp::Writer& writer); void active_update(float elapsed_time); - HitResponse collision_solid(GameObject& other, const CollisionHit& hit); + void collision_solid(const CollisionHit& hit); virtual FlyingSnowBall* clone() const { return new FlyingSnowBall(*this); } diff --git a/src/badguy/igel.cpp b/src/badguy/igel.cpp index f7d5e1daf..02b716342 100644 --- a/src/badguy/igel.cpp +++ b/src/badguy/igel.cpp @@ -115,30 +115,26 @@ Igel::active_update(float elapsed_time) BadGuy::active_update(elapsed_time); } -HitResponse -Igel::collision_solid(GameObject& , const CollisionHit& hit) +void +Igel::collision_solid(const CollisionHit& hit) { - if(fabsf(hit.normal.y) > .5) { // floor or roof + if(hit.top || hit.bottom) { // floor or roof physic.set_velocity_y(0); - return CONTINUE; + return; } // hit left or right switch(state) { - case STATE_NORMAL: turn_around(); break; - } - - return CONTINUE; } HitResponse Igel::collision_badguy(BadGuy& , const CollisionHit& hit) { - if(fabsf(hit.normal.y) > .5) { // floor or roof + if(hit.top || hit.bottom) { // floor or roof physic.set_velocity_y(0); return CONTINUE; } @@ -159,7 +155,7 @@ HitResponse Igel::collision_bullet(Bullet& , const CollisionHit& hit) { // die if hit on front side - if (((dir == LEFT) && (hit.normal.x > 0)) || ((dir == RIGHT) && (hit.normal.x < 0))) { + if (((dir == LEFT) && hit.left) || ((dir == RIGHT) && hit.right)) { kill_fall(); return ABORT_MOVE; } diff --git a/src/badguy/igel.hpp b/src/badguy/igel.hpp index a824620df..e368f1f05 100644 --- a/src/badguy/igel.hpp +++ b/src/badguy/igel.hpp @@ -34,7 +34,7 @@ public: void activate(); void write(lisp::Writer& writer); - HitResponse collision_solid(GameObject& object, const CollisionHit& hit); + void collision_solid(const CollisionHit& hit); HitResponse collision_badguy(BadGuy& badguy, const CollisionHit& hit); HitResponse collision_bullet(Bullet& bullet, const CollisionHit& hit); diff --git a/src/badguy/jumpy.cpp b/src/badguy/jumpy.cpp index 02ceeb1bb..233a672ac 100644 --- a/src/badguy/jumpy.cpp +++ b/src/badguy/jumpy.cpp @@ -41,10 +41,10 @@ Jumpy::write(lisp::Writer& writer) writer.end_list("jumpy"); } -HitResponse -Jumpy::collision_solid(GameObject& , const CollisionHit& chit) +void +Jumpy::collision_solid(const CollisionHit& chit) { - return hit(chit); + hit(chit); } HitResponse @@ -56,8 +56,7 @@ Jumpy::collision_badguy(BadGuy& , const CollisionHit& chit) HitResponse Jumpy::hit(const CollisionHit& chit) { - // hit floor? - if(chit.normal.y < -.5) { + if(chit.bottom) { if (!groundhit_pos_set) { pos_groundhit = get_pos(); @@ -67,7 +66,7 @@ Jumpy::hit(const CollisionHit& chit) physic.set_velocity_y(JUMPSPEED); // TODO create a nice sound for this... //sound_manager->play("sounds/skid.wav"); - } else if(chit.normal.y < .5) { // bumped on roof + } else if(chit.top) { physic.set_velocity_y(0); } diff --git a/src/badguy/jumpy.hpp b/src/badguy/jumpy.hpp index 9304a42b7..494559b4a 100644 --- a/src/badguy/jumpy.hpp +++ b/src/badguy/jumpy.hpp @@ -27,7 +27,7 @@ class Jumpy : public BadGuy public: Jumpy(const lisp::Lisp& reader); - HitResponse collision_solid(GameObject& other, const CollisionHit& hit); + void collision_solid(const CollisionHit& hit); HitResponse collision_badguy(BadGuy& other, const CollisionHit& hit); void write(lisp::Writer& writer); diff --git a/src/badguy/kugelblitz.cpp b/src/badguy/kugelblitz.cpp index f8ecf1703..68fc066d9 100644 --- a/src/badguy/kugelblitz.cpp +++ b/src/badguy/kugelblitz.cpp @@ -60,10 +60,10 @@ Kugelblitz::activate() dying = false; } -HitResponse -Kugelblitz::collision_solid(GameObject& , const CollisionHit& chit) +void +Kugelblitz::collision_solid(const CollisionHit& chit) { - return hit(chit); + hit(chit); } HitResponse @@ -97,10 +97,10 @@ Kugelblitz::collision_badguy(BadGuy& other , const CollisionHit& chit) } HitResponse -Kugelblitz::hit(const CollisionHit& chit) +Kugelblitz::hit(const CollisionHit& hit) { // hit floor? - if(chit.normal.y < -.5) { + if(hit.bottom) { if (!groundhit_pos_set) { pos_groundhit = get_pos(); @@ -115,7 +115,7 @@ Kugelblitz::hit(const CollisionHit& chit) movement_timer.start(MOVETIME); lifetime.start(LIFETIME); - } else if(chit.normal.y < .5) { // bumped on roof + } else if(hit.top) { // bumped on roof physic.set_velocity_y(0); } diff --git a/src/badguy/kugelblitz.hpp b/src/badguy/kugelblitz.hpp index a9c64bafa..2e7b3ee71 100644 --- a/src/badguy/kugelblitz.hpp +++ b/src/badguy/kugelblitz.hpp @@ -31,7 +31,7 @@ public: void activate(); HitResponse collision_badguy(BadGuy& other, const CollisionHit& hit); - HitResponse collision_solid(GameObject& other, const CollisionHit& hit); + void collision_solid(const CollisionHit& hit); HitResponse collision_player(Player& player, const CollisionHit& hit); void write(lisp::Writer& writer); diff --git a/src/badguy/mrbomb.cpp b/src/badguy/mrbomb.cpp index 9cb02f58d..15ab8f531 100644 --- a/src/badguy/mrbomb.cpp +++ b/src/badguy/mrbomb.cpp @@ -87,28 +87,29 @@ MrBomb::collision_squished(Player& player) return true; } -HitResponse -MrBomb::collision_solid(GameObject& , const CollisionHit& hit) +void +MrBomb::collision_solid(const CollisionHit& hit) { - if(fabsf(hit.normal.y) > .5) { // hit floor or roof? + if(hit.bottom || hit.top) { physic.set_velocity_y(0); - } else { // hit right or left + } + if(hit.left || hit.right) { dir = dir == LEFT ? RIGHT : LEFT; sprite->set_action(dir == LEFT ? "left" : "right"); physic.set_velocity_x(-physic.get_velocity_x()); } - - return CONTINUE; } HitResponse -MrBomb::collision_badguy(BadGuy& , const CollisionHit& hit) +MrBomb::collision_badguy(BadGuy& ) { +#if 0 if(fabsf(hit.normal.x) > .8) { // left or right dir = dir == LEFT ? RIGHT : LEFT; sprite->set_action(dir == LEFT ? "left" : "right"); physic.set_velocity_x(-physic.get_velocity_x()); } +#endif return CONTINUE; } diff --git a/src/badguy/mrbomb.hpp b/src/badguy/mrbomb.hpp index 6e49d0b10..5aa053ade 100644 --- a/src/badguy/mrbomb.hpp +++ b/src/badguy/mrbomb.hpp @@ -31,8 +31,8 @@ public: void activate(); void active_update(float elapsed_time); void write(lisp::Writer& writer); - HitResponse collision_solid(GameObject& other, const CollisionHit& hit); - HitResponse collision_badguy(BadGuy& badguy, const CollisionHit& hit); + void collision_solid(const CollisionHit& hit); + HitResponse collision_badguy(BadGuy& badguy); void kill_fall(); virtual MrBomb* clone() const { return new MrBomb(*this); } diff --git a/src/badguy/mriceblock.cpp b/src/badguy/mriceblock.cpp index 95fd17f3a..85f3f941e 100644 --- a/src/badguy/mriceblock.cpp +++ b/src/badguy/mriceblock.cpp @@ -83,13 +83,14 @@ MrIceBlock::active_update(float elapsed_time) BadGuy::active_update(elapsed_time); } -HitResponse -MrIceBlock::collision_solid(GameObject& object, const CollisionHit& hit) +void +MrIceBlock::collision_solid(const CollisionHit& hit) { - if(fabsf(hit.normal.y) > .5) { // floor or roof + if(hit.top || hit.bottom) { // floor or roof physic.set_velocity_y(0); - return CONTINUE; + return; } + // hit left or right switch(ice_state) { case ICESTATE_NORMAL: @@ -98,6 +99,8 @@ MrIceBlock::collision_solid(GameObject& object, const CollisionHit& hit) physic.set_velocity_x(-physic.get_velocity_x()); break; case ICESTATE_KICKED: { +#if 0 + // TODO move these into bonusblock class BonusBlock* bonusblock = dynamic_cast (&object); if(bonusblock) { bonusblock->try_open(); @@ -106,6 +109,7 @@ MrIceBlock::collision_solid(GameObject& object, const CollisionHit& hit) if(brick) { brick->try_break(); } +#endif dir = dir == LEFT ? RIGHT : LEFT; sprite->set_action(dir == LEFT ? "flat-left" : "flat-right"); @@ -117,10 +121,8 @@ MrIceBlock::collision_solid(GameObject& object, const CollisionHit& hit) physic.set_velocity_x(0); break; case ICESTATE_GRABBED: - return FORCE_MOVE; + break; } - - return CONTINUE; } HitResponse @@ -140,13 +142,12 @@ MrIceBlock::collision_player(Player& player, const CollisionHit& hit) // handle kicks from left or right side if(ice_state == ICESTATE_FLAT && get_state() == STATE_ACTIVE) { - // hit from left side - if(hit.normal.x > 0.7) { + if(hit.left) { dir = RIGHT; player.kick(); set_state(ICESTATE_KICKED); return FORCE_MOVE; - } else if(hit.normal.x < -0.7) { + } else if(hit.right) { dir = LEFT; player.kick(); set_state(ICESTATE_KICKED); @@ -162,7 +163,7 @@ MrIceBlock::collision_badguy(BadGuy& badguy, const CollisionHit& hit) { switch(ice_state) { case ICESTATE_NORMAL: - if(fabsf(hit.normal.x) > .8) { + if(hit.left || hit.right) { dir = dir == LEFT ? RIGHT : LEFT; sprite->set_action(dir == LEFT ? "left" : "right"); physic.set_velocity_x(-physic.get_velocity_x()); diff --git a/src/badguy/mriceblock.hpp b/src/badguy/mriceblock.hpp index ea5506560..01e693a65 100644 --- a/src/badguy/mriceblock.hpp +++ b/src/badguy/mriceblock.hpp @@ -32,7 +32,7 @@ public: void activate(); void write(lisp::Writer& writer); HitResponse collision(GameObject& object, const CollisionHit& hit); - HitResponse collision_solid(GameObject& object, const CollisionHit& hit); + void collision_solid(const CollisionHit& hit); HitResponse collision_badguy(BadGuy& badguy, const CollisionHit& hit); HitResponse collision_player(Player& player, const CollisionHit& hit); diff --git a/src/badguy/mrrocket.cpp b/src/badguy/mrrocket.cpp index cfa4faf50..cbf5d3126 100644 --- a/src/badguy/mrrocket.cpp +++ b/src/badguy/mrrocket.cpp @@ -74,18 +74,16 @@ MrRocket::collision_squished(Player& player) return true; } -HitResponse -MrRocket::collision_solid(GameObject& , const CollisionHit& hit) +void +MrRocket::collision_solid(const CollisionHit& hit) { - if(fabsf(hit.normal.y) > .5) { // hit floor or roof? + if(hit.top || hit.bottom) { physic.set_velocity_y(0); - } else { // hit right or left + } else if(hit.left || hit.right) { sprite->set_action(dir == LEFT ? "collision-left" : "collision-right"); physic.set_velocity_x(0); collision_timer.start(0.2, true); } - - return CONTINUE; } IMPLEMENT_FACTORY(MrRocket, "mrrocket") diff --git a/src/badguy/mrrocket.hpp b/src/badguy/mrrocket.hpp index f756d020a..77a7634c4 100644 --- a/src/badguy/mrrocket.hpp +++ b/src/badguy/mrrocket.hpp @@ -33,7 +33,7 @@ public: void activate(); void active_update(float elapsed_time); void write(lisp::Writer& writer); - HitResponse collision_solid(GameObject& other, const CollisionHit& hit); + void collision_solid(const CollisionHit& hit); virtual MrRocket* clone() const { return new MrRocket(*this); } diff --git a/src/badguy/mrtree.cpp b/src/badguy/mrtree.cpp index 14062c2a2..9c4a0fa60 100644 --- a/src/badguy/mrtree.cpp +++ b/src/badguy/mrtree.cpp @@ -171,27 +171,24 @@ MrTree::collision_squished(Player& player) return true; } -HitResponse -MrTree::collision_solid(GameObject& , const CollisionHit& hit) +void +MrTree::collision_solid(const CollisionHit& hit) { - if(fabsf(hit.normal.y) > .5) { + if(hit.top || hit.bottom) { physic.set_velocity_y(0); } else { dir = dir == LEFT ? RIGHT : LEFT; activate(); } - - return CONTINUE; } HitResponse MrTree::collision_badguy(BadGuy& , const CollisionHit& hit) { - if(fabsf(hit.normal.x) > .8) { // left or right hit + if(hit.left || hit.right) { dir = dir == LEFT ? RIGHT : LEFT; activate(); } - return CONTINUE; } diff --git a/src/badguy/mrtree.hpp b/src/badguy/mrtree.hpp index 652a00e6b..02a433d83 100644 --- a/src/badguy/mrtree.hpp +++ b/src/badguy/mrtree.hpp @@ -30,7 +30,7 @@ public: void activate(); void active_update(float elapsed_time); void write(lisp::Writer& writer); - HitResponse collision_solid(GameObject& other, const CollisionHit& hit); + void collision_solid(const CollisionHit& hit); HitResponse collision_badguy(BadGuy& badguy, const CollisionHit& hit); virtual MrTree* clone() const { return new MrTree(*this); } diff --git a/src/badguy/nolok_01.cpp b/src/badguy/nolok_01.cpp deleted file mode 100644 index b1e7c777d..000000000 --- a/src/badguy/nolok_01.cpp +++ /dev/null @@ -1,153 +0,0 @@ -// $Id$ -// -// SuperTux -// Copyright (C) 2006 Matthias Braun -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#include - -#include "nolok_01.hpp" -#include "badguy/snail.hpp" -#include "trigger/door.hpp" - -#define WALK_TIME 2.5 -#define SHOOT_TIME 0.4 -#define JUMP_TIME 0.5 -#define INITIAL_HITPOINTS 3 -#define INITIAL_BULLET_HP 10 - -static const float WALKSPEED = 90; - -//TODO: Create sprite, limit max number of snowballs -Nolok_01::Nolok_01(const lisp::Lisp& reader) - : BadGuy(reader, "images/creatures/nolok/nolok.sprite") -{ - countMe = false; -} - -Nolok_01::Nolok_01(const Vector& pos) - : BadGuy(pos, "images/creatures/nolok/nolok.sprite") -{ - countMe = false; -} - -void -Nolok_01::write(lisp::Writer& writer) -{ - writer.start_list("nolok_01"); - - writer.write_float("x", start_position.x); - writer.write_float("y", start_position.y); - - writer.end_list("nolok_01"); -} - -void -Nolok_01::activate() -{ - //hitpoints = INITIAL_HITPOINTS; - //bullet_hitpoints = INITIAL_BULLET_HP; - physic.set_velocity_x(dir == LEFT ? -WALKSPEED : WALKSPEED); - sprite->set_action(dir == LEFT ? "left" : "right"); - action = WALKING; - action_timer.start(WALK_TIME); -} - -void -Nolok_01::active_update(float elapsed_time) -{ - if (action_timer.check()) { - switch (action) { - case WALKING: - { - sprite->set_action("jump"); - physic.set_velocity_y(-700); - action = JUMPING; - action_timer.start(JUMP_TIME); - break; - } - case JUMPING: - { - sprite->set_action("throw"); - action = SHOOTING; - action_timer.start(SHOOT_TIME); - break; - } - case SHOOTING: - { - Sector::current()->add_object(new Snail(Vector(get_pos().x - 64, get_pos().y), LEFT)); - Sector::current()->add_object(new Snail(Vector(get_pos().x + 64, get_pos().y), RIGHT)); - physic.set_velocity_x(dir == LEFT ? -WALKSPEED : WALKSPEED); - sprite->set_action(dir == LEFT ? "left" : "right"); - action = WALKING; - action_timer.start(WALK_TIME); - break; - } - } - } - movement = physic.get_movement(elapsed_time); -} - -bool -Nolok_01::collision_squished(Player& player) -{ - bool result = false; - player.bounce(*this); -#if 0 - if (hitpoints <= 0) { - bullet_hitpoints = 0; - sprite->set_action("dead"); - kill_squished(player); - Sector::current()->add_object(new Door((int)get_pos().x+32, 512, "sector1", "main2")); - result = true; - } -#endif - return result; -} - -HitResponse -Nolok_01::collision_solid(GameObject& , const CollisionHit& hit) -{ - if(fabsf(hit.normal.y) > .5){ // hit floor or roof? - if (action != JUMPING) physic.set_velocity_y(0); - } else { // hit right or left - dir = dir == LEFT ? RIGHT : LEFT; - sprite->set_action(dir == LEFT ? "left" : "right"); - physic.set_velocity_x(-physic.get_velocity_x()); - } - - return CONTINUE; -} - -//TODO: Hitpoint count incorrect when combining squishing and shooting -void -Nolok_01::kill_fall() -{ -#if 0 - bullet_hitpoints--; - if (bullet_hitpoints <= 0) { - hitpoints = 0; - sound_manager->play("sounds/fall.wav", this, - this->get_pos()); - physic.set_velocity_y(0); - physic.enable_gravity(true); - set_state(STATE_FALLING); - Sector::current()->add_object(new Door((int)get_pos().x+32, 512, "sector1", "main2")); - } -#endif -} - -IMPLEMENT_FACTORY(Nolok_01, "nolok_01") diff --git a/src/badguy/nolok_01.hpp b/src/badguy/nolok_01.hpp deleted file mode 100644 index 460d05e93..000000000 --- a/src/badguy/nolok_01.hpp +++ /dev/null @@ -1,48 +0,0 @@ -// $Id$ -// -// SuperTux -// Copyright (C) 2006 Matthias Braun -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#ifndef __NOLOK01_H__ -#define __NOLOK01_H__ - -#include "badguy.hpp" -#include "timer.hpp" - -class Nolok_01 : public BadGuy -{ -public: - Nolok_01(const lisp::Lisp& reader); - Nolok_01(const Vector& pos); - - void activate(); - void write(lisp::Writer& writer); - void active_update(float elapsed_time); - void kill_fall(); - HitResponse collision_solid(GameObject& other, const CollisionHit& hit); - - virtual Nolok_01* clone() const { return new Nolok_01(*this); } - -protected: - bool collision_squished(Player& player); - Timer action_timer; - enum Actions { WALKING, JUMPING, SHOOTING }; - Actions action; -}; - -#endif - diff --git a/src/badguy/plant.cpp b/src/badguy/plant.cpp index d45200855..91cb1c92b 100644 --- a/src/badguy/plant.cpp +++ b/src/badguy/plant.cpp @@ -52,18 +52,16 @@ Plant::activate() sprite->set_action(dir == LEFT ? "sleeping-left" : "sleeping-right"); } -HitResponse -Plant::collision_solid(GameObject& , const CollisionHit& hit) +void +Plant::collision_solid(const CollisionHit& hit) { - if(fabsf(hit.normal.y) > .5) { // hit floor or roof? + if(hit.top || hit.bottom) { physic.set_velocity_y(0); - } else { // hit right or left + } else if(hit.left || hit.right) { dir = dir == LEFT ? RIGHT : LEFT; sprite->set_action(dir == LEFT ? "left" : "right"); physic.set_velocity_x(-physic.get_velocity_x()); } - - return CONTINUE; } HitResponse @@ -71,7 +69,7 @@ Plant::collision_badguy(BadGuy& , const CollisionHit& hit) { if(state != PLANT_WALKING) return CONTINUE; - if(fabsf(hit.normal.x) > .8) { // left or right + if(hit.left || hit.right) { dir = dir == LEFT ? RIGHT : LEFT; sprite->set_action(dir == LEFT ? "left" : "right"); physic.set_velocity_x(-physic.get_velocity_x()); diff --git a/src/badguy/plant.hpp b/src/badguy/plant.hpp index ab0dfd5bb..75d77e300 100644 --- a/src/badguy/plant.hpp +++ b/src/badguy/plant.hpp @@ -29,7 +29,7 @@ public: void activate(); void write(lisp::Writer& writer); - HitResponse collision_solid(GameObject& other, const CollisionHit& hit); + void collision_solid(const CollisionHit& hit); HitResponse collision_badguy(BadGuy& badguy, const CollisionHit& hit); void active_update(float elapsed_time); diff --git a/src/badguy/poisonivy.cpp b/src/badguy/poisonivy.cpp index ae118276c..34d4ed897 100644 --- a/src/badguy/poisonivy.cpp +++ b/src/badguy/poisonivy.cpp @@ -73,24 +73,22 @@ PoisonIvy::collision_squished(Player& player) return true; } -HitResponse -PoisonIvy::collision_solid(GameObject& , const CollisionHit& hit) +void +PoisonIvy::collision_solid(const CollisionHit& hit) { - if(fabsf(hit.normal.y) > .5) { // hit floor or roof? + if(hit.top || hit.bottom) { physic.set_velocity_y(0); - } else { // hit right or left + } else if(hit.left || hit.right) { dir = dir == LEFT ? RIGHT : LEFT; sprite->set_action(dir == LEFT ? "left" : "right"); physic.set_velocity_x(-physic.get_velocity_x()); } - - return CONTINUE; } HitResponse PoisonIvy::collision_badguy(BadGuy& , const CollisionHit& hit) { - if(fabsf(hit.normal.x) > .8) { // left or right hit + if(hit.left || hit.right) { dir = dir == LEFT ? RIGHT : LEFT; sprite->set_action(dir == LEFT ? "left" : "right"); physic.set_velocity_x(-physic.get_velocity_x()); diff --git a/src/badguy/poisonivy.hpp b/src/badguy/poisonivy.hpp index 09b6af643..fd77d0574 100644 --- a/src/badguy/poisonivy.hpp +++ b/src/badguy/poisonivy.hpp @@ -30,7 +30,7 @@ public: void activate(); void write(lisp::Writer& writer); - HitResponse collision_solid(GameObject& other, const CollisionHit& hit); + void collision_solid(const CollisionHit& hit); HitResponse collision_badguy(BadGuy& other, const CollisionHit& hit); virtual PoisonIvy* clone() const { return new PoisonIvy(*this); } diff --git a/src/badguy/rocketexplosion.cpp b/src/badguy/rocketexplosion.cpp index a1497ee93..4e0520c2f 100644 --- a/src/badguy/rocketexplosion.cpp +++ b/src/badguy/rocketexplosion.cpp @@ -37,15 +37,6 @@ RocketExplosion::write(lisp::Writer& ) } HitResponse -RocketExplosion::collision_solid(GameObject& , const CollisionHit& hit) -{ - if(fabsf(hit.normal.y) > .5) - physic.set_velocity_y(0); - - return CONTINUE; -} - -HitResponse RocketExplosion::collision_player(Player& player, const CollisionHit& ) { player.kill(false); diff --git a/src/badguy/rocketexplosion.hpp b/src/badguy/rocketexplosion.hpp index c76a6b8f0..ef09d1758 100644 --- a/src/badguy/rocketexplosion.hpp +++ b/src/badguy/rocketexplosion.hpp @@ -28,7 +28,6 @@ public: RocketExplosion(const Vector& pos, Direction dir); void write(lisp::Writer& writer); - HitResponse collision_solid(GameObject& other, const CollisionHit& hit); HitResponse collision_player(Player& player, const CollisionHit& hit); HitResponse collision_badguy(BadGuy& badguy, const CollisionHit& hit); void active_update(float elapsed_time); diff --git a/src/badguy/skullyhop.cpp b/src/badguy/skullyhop.cpp index a5ba2caf0..d9b954e8e 100644 --- a/src/badguy/skullyhop.cpp +++ b/src/badguy/skullyhop.cpp @@ -87,37 +87,37 @@ SkullyHop::collision_squished(Player& player) return true; } -HitResponse -SkullyHop::collision_solid(GameObject& , const CollisionHit& hit) +void +SkullyHop::collision_solid(const CollisionHit& hit) { // ignore collisions while standing still - if(state != JUMPING) return CONTINUE; + if(state != JUMPING) + return; // check if we hit the floor while falling - if ((hit.normal.y < 0) && (physic.get_velocity_y() > 0)) { + if(hit.bottom) { set_state(STANDING); } - // check if we hit the roof while climbing - if ((hit.normal.y > 0) && (physic.get_velocity_y() < 0)) { + if(hit.top) { physic.set_velocity_y(0); } // check if we hit left or right while moving in either direction - if ((hit.normal.x != 0) && (physic.get_velocity_x() != 0)) { + if(hit.left || hit.right) { dir = dir == LEFT ? RIGHT : LEFT; sprite->set_action(dir == LEFT ? "jumping-left" : "jumping-right"); physic.set_velocity_x(-0.25*physic.get_velocity_x()); } - - return CONTINUE; } HitResponse -SkullyHop::collision_badguy(BadGuy& badguy, const CollisionHit& hit) +SkullyHop::collision_badguy(BadGuy& , const CollisionHit& hit) { // behaviour for badguy collisions is the same as for collisions with solids - return collision_solid(badguy, hit); + collision_solid(hit); + + return CONTINUE; } void diff --git a/src/badguy/skullyhop.hpp b/src/badguy/skullyhop.hpp index c12962c62..805cf3541 100644 --- a/src/badguy/skullyhop.hpp +++ b/src/badguy/skullyhop.hpp @@ -34,7 +34,7 @@ public: void activate(); void write(lisp::Writer& writer); - HitResponse collision_solid(GameObject& other, const CollisionHit& hit); + void collision_solid(const CollisionHit& hit); HitResponse collision_badguy(BadGuy& badguy, const CollisionHit& hit); bool collision_squished(Player& player); void active_update(float elapsed_time); diff --git a/src/badguy/snail.cpp b/src/badguy/snail.cpp index 6f1e1e94c..5df4e0e68 100644 --- a/src/badguy/snail.cpp +++ b/src/badguy/snail.cpp @@ -138,10 +138,10 @@ Snail::active_update(float elapsed_time) BadGuy::active_update(elapsed_time); } -HitResponse -Snail::collision_solid(GameObject& object, const CollisionHit& hit) +void +Snail::collision_solid(const CollisionHit& hit) { - if(fabsf(hit.normal.y) > .5) { // floor or roof + if(hit.top || hit.bottom) { // floor or roof physic.set_velocity_y(0); switch (state) { @@ -153,7 +153,7 @@ Snail::collision_solid(GameObject& object, const CollisionHit& hit) break; } - return CONTINUE; + return; } // hit left or right switch(state) { @@ -171,7 +171,9 @@ Snail::collision_solid(GameObject& object, const CollisionHit& hit) case STATE_KICKED: { sound_manager->play("sounds/iceblock_bump.wav", get_pos()); - + +#if 0 + // TODO move this into BonusBlock code // open bonusblocks, crash bricks BonusBlock* bonusblock = dynamic_cast (&object); if(bonusblock) { @@ -181,6 +183,7 @@ Snail::collision_solid(GameObject& object, const CollisionHit& hit) if(brick) { brick->try_break(); } +#endif dir = (dir == LEFT) ? RIGHT : LEFT; sprite->set_action(dir == LEFT ? "flat-left" : "flat-right"); @@ -191,8 +194,6 @@ Snail::collision_solid(GameObject& object, const CollisionHit& hit) } } - - return CONTINUE; } HitResponse @@ -200,7 +201,7 @@ Snail::collision_badguy(BadGuy& badguy, const CollisionHit& hit) { switch(state) { case STATE_NORMAL: - if(fabsf(hit.normal.x) > .5) { + if(hit.left || hit.right) { dir = (dir == LEFT) ? RIGHT : LEFT; sprite->set_action(dir == LEFT ? "left" : "right"); physic.set_velocity_x(-physic.get_velocity_x()); diff --git a/src/badguy/snail.hpp b/src/badguy/snail.hpp index 5d259f002..35802b022 100644 --- a/src/badguy/snail.hpp +++ b/src/badguy/snail.hpp @@ -33,7 +33,7 @@ public: void activate(); void write(lisp::Writer& writer); - HitResponse collision_solid(GameObject& object, const CollisionHit& hit); + void collision_solid(const CollisionHit& hit); HitResponse collision_badguy(BadGuy& badguy, const CollisionHit& hit); void active_update(float elapsed_time); diff --git a/src/badguy/snowball.cpp b/src/badguy/snowball.cpp index 889578e3e..57db13a21 100644 --- a/src/badguy/snowball.cpp +++ b/src/badguy/snowball.cpp @@ -24,12 +24,12 @@ static const float WALKSPEED = 80; SnowBall::SnowBall(const lisp::Lisp& reader) - : BadGuy(reader, "images/creatures/snowball/snowball.sprite") + : BadGuy(reader, "images/creatures/snowball/snowball.sprite") { } SnowBall::SnowBall(const Vector& pos, Direction d) - : BadGuy(pos, d, "images/creatures/snowball/snowball.sprite") + : BadGuy(pos, d, "images/creatures/snowball/snowball.sprite") { } @@ -37,14 +37,8 @@ void SnowBall::write(lisp::Writer& writer) { writer.start_list("snowball"); - writer.write_float("x", start_position.x); writer.write_float("y", start_position.y); - /* - if (fluffy) { // don't give us away at every snowball - writer.write_bool("fluffy", true); - } - */ writer.end_list("snowball"); } @@ -63,24 +57,26 @@ SnowBall::collision_squished(Player& player) return true; } -HitResponse -SnowBall::collision_solid(GameObject& , const CollisionHit& hit) +void +SnowBall::collision_solid(const CollisionHit& hit) { - if(fabsf(hit.normal.y) > .5) { // hit floor or roof? + if(hit.top || hit.bottom) { physic.set_velocity_y(0); - } else { // hit right or left + } + if(hit.left || hit.right) { dir = dir == LEFT ? RIGHT : LEFT; sprite->set_action(dir == LEFT ? "left" : "right"); physic.set_velocity_x(-physic.get_velocity_x()); } - - return CONTINUE; } HitResponse SnowBall::collision_badguy(BadGuy& , const CollisionHit& hit) { - if(fabsf(hit.normal.x) > .8) { // left or right hit + if(hit.top || hit.bottom) { + physic.set_velocity_y(0); + } + if(hit.left || hit.right) { dir = dir == LEFT ? RIGHT : LEFT; sprite->set_action(dir == LEFT ? "left" : "right"); physic.set_velocity_x(-physic.get_velocity_x()); diff --git a/src/badguy/snowball.hpp b/src/badguy/snowball.hpp index 49bfa9f94..e7387ef51 100644 --- a/src/badguy/snowball.hpp +++ b/src/badguy/snowball.hpp @@ -30,7 +30,7 @@ public: void activate(); void write(lisp::Writer& writer); - HitResponse collision_solid(GameObject& other, const CollisionHit& hit); + void collision_solid(const CollisionHit& hit); HitResponse collision_badguy(BadGuy& other, const CollisionHit& hit); virtual SnowBall* clone() const { return new SnowBall(*this); } diff --git a/src/badguy/spidermite.cpp b/src/badguy/spidermite.cpp index 41ccb2e34..70feda769 100644 --- a/src/badguy/spidermite.cpp +++ b/src/badguy/spidermite.cpp @@ -65,14 +65,12 @@ SpiderMite::collision_squished(Player& player) return true; } -HitResponse -SpiderMite::collision_solid(GameObject& , const CollisionHit& hit) +void +SpiderMite::collision_solid(const CollisionHit& hit) { - if(fabsf(hit.normal.y) > 1.5) { // hit floor or roof? + if(hit.top || hit.bottom) { // hit floor or roof? physic.set_velocity_y(0); } - - return CONTINUE; } void diff --git a/src/badguy/spidermite.hpp b/src/badguy/spidermite.hpp index 5c1bd5e2a..84f313d51 100644 --- a/src/badguy/spidermite.hpp +++ b/src/badguy/spidermite.hpp @@ -31,7 +31,7 @@ public: void activate(); void write(lisp::Writer& writer); void active_update(float elapsed_time); - HitResponse collision_solid(GameObject& other, const CollisionHit& hit); + void collision_solid(const CollisionHit& hit); virtual SpiderMite* clone() const { return new SpiderMite(*this); } diff --git a/src/badguy/spiky.cpp b/src/badguy/spiky.cpp index fbe27eee8..befbd0531 100644 --- a/src/badguy/spiky.cpp +++ b/src/badguy/spiky.cpp @@ -59,24 +59,22 @@ Spiky::active_update(float elapsed_time) } } -HitResponse -Spiky::collision_solid(GameObject& , const CollisionHit& hit) +void +Spiky::collision_solid(const CollisionHit& hit) { - if(fabsf(hit.normal.y) > .5) { // hit floor or roof? + if(hit.top || hit.bottom) { // hit floor or roof? physic.set_velocity_y(0); } else { // hit right or left dir = dir == LEFT ? RIGHT : LEFT; sprite->set_action(dir == LEFT ? "left" : "right"); physic.set_velocity_x(-physic.get_velocity_x()); } - - return CONTINUE; } HitResponse Spiky::collision_badguy(BadGuy& , const CollisionHit& hit) { - if(fabsf(hit.normal.x) > .8) { // left or right + if(hit.left || hit.right) { dir = dir == LEFT ? RIGHT : LEFT; sprite->set_action(dir == LEFT ? "left" : "right"); physic.set_velocity_x(-physic.get_velocity_x()); diff --git a/src/badguy/spiky.hpp b/src/badguy/spiky.hpp index fd86096d3..c0e448e18 100644 --- a/src/badguy/spiky.hpp +++ b/src/badguy/spiky.hpp @@ -30,7 +30,7 @@ public: void activate(); void write(lisp::Writer& writer); void active_update(float elapsed_time); - HitResponse collision_solid(GameObject& other, const CollisionHit& hit); + void collision_solid(const CollisionHit& hit); HitResponse collision_badguy(BadGuy& badguy, const CollisionHit& hit); virtual Spiky* clone() const { return new Spiky(*this); } diff --git a/src/badguy/sspiky.cpp b/src/badguy/sspiky.cpp index 3827ae26b..2999535b6 100644 --- a/src/badguy/sspiky.cpp +++ b/src/badguy/sspiky.cpp @@ -48,28 +48,25 @@ SSpiky::activate() sprite->set_action(dir == LEFT ? "sleeping-left" : "sleeping-right"); } - - -HitResponse -SSpiky::collision_solid(GameObject& , const CollisionHit& hit) +void +SSpiky::collision_solid(const CollisionHit& hit) { - if(fabsf(hit.normal.y) > .5) { // hit floor or roof? + if(hit.top || hit.bottom) { // hit floor or roof? physic.set_velocity_y(0); } else { // hit right or left dir = dir == LEFT ? RIGHT : LEFT; sprite->set_action(dir == LEFT ? "left" : "right"); physic.set_velocity_x(-physic.get_velocity_x()); } - - return CONTINUE; } HitResponse SSpiky::collision_badguy(BadGuy& , const CollisionHit& hit) { - if(state != SSPIKY_WALKING) return CONTINUE; + if(state != SSPIKY_WALKING) + return CONTINUE; - if(fabsf(hit.normal.x) > .8) { // left or right + if(hit.left || hit.right) { dir = dir == LEFT ? RIGHT : LEFT; sprite->set_action(dir == LEFT ? "left" : "right"); physic.set_velocity_x(-physic.get_velocity_x()); diff --git a/src/badguy/sspiky.hpp b/src/badguy/sspiky.hpp index bb7741930..81322f73d 100644 --- a/src/badguy/sspiky.hpp +++ b/src/badguy/sspiky.hpp @@ -29,7 +29,7 @@ public: void activate(); void write(lisp::Writer& writer); - HitResponse collision_solid(GameObject& other, const CollisionHit& hit); + void collision_solid(const CollisionHit& hit); HitResponse collision_badguy(BadGuy& badguy, const CollisionHit& hit); void active_update(float elapsed_time); diff --git a/src/badguy/stalactite.cpp b/src/badguy/stalactite.cpp index f53a94409..289135b60 100644 --- a/src/badguy/stalactite.cpp +++ b/src/badguy/stalactite.cpp @@ -68,13 +68,13 @@ Stalactite::active_update(float elapsed_time) } } -HitResponse -Stalactite::collision_solid(GameObject& , const CollisionHit& hit) +void +Stalactite::collision_solid(const CollisionHit& hit) { if(state != STALACTITE_FALLING && state != STALACTITE_SQUISHED) - return FORCE_MOVE; + return; - if(hit.normal.y < .9) { // hit floor? + if(hit.bottom) { // hit floor? state = STALACTITE_SQUISHED; set_group(COLGROUP_MOVING_ONLY_STATIC); physic.set_velocity_y(0); @@ -82,12 +82,10 @@ Stalactite::collision_solid(GameObject& , const CollisionHit& hit) if(!timer.started()) timer.start(SQUISH_TIME); } - - return CONTINUE; } HitResponse -Stalactite::collision_player(Player& player, const CollisionHit& ) +Stalactite::collision_player(Player& player) { if(state != STALACTITE_SQUISHED) { player.kill(false); diff --git a/src/badguy/stalactite.hpp b/src/badguy/stalactite.hpp index 9619f6127..74803c284 100644 --- a/src/badguy/stalactite.hpp +++ b/src/badguy/stalactite.hpp @@ -29,8 +29,8 @@ public: void active_update(float elapsed_time); void write(lisp::Writer& writer); - HitResponse collision_solid(GameObject& other, const CollisionHit& hit); - HitResponse collision_player(Player& player, const CollisionHit& hit); + void collision_solid(const CollisionHit& hit); + HitResponse collision_player(Player& player); void kill_fall(); void draw(DrawingContext& context); diff --git a/src/badguy/totem.cpp b/src/badguy/totem.cpp index 825ed8143..2ee60f16a 100644 --- a/src/badguy/totem.cpp +++ b/src/badguy/totem.cpp @@ -151,31 +151,29 @@ Totem::collision_squished(Player& player) return true; } -HitResponse -Totem::collision_solid(GameObject& object, const CollisionHit& hit) +void +Totem::collision_solid(const CollisionHit& hit) { // if we are being carried around, pass event to bottom of stack and ignore it if (carried_by) { - carried_by->collision_solid(object, hit); - return CONTINUE; + carried_by->collision_solid(hit); + return; } // If we hit something from above or below: stop moving in this direction - if (hit.normal.y != 0) { + if (hit.top || hit.bottom) { physic.set_velocity_y(0); } // If we are hit from the direction we are facing: turn around - if ((hit.normal.x > .8) && (dir == LEFT)) { + if (hit.left && (dir == LEFT)) { dir = RIGHT; activate(); } - if ((hit.normal.x < -.8) && (dir == RIGHT)) { + if (hit.right && (dir == RIGHT)) { dir = LEFT; activate(); } - - return CONTINUE; } HitResponse @@ -199,11 +197,11 @@ Totem::collision_badguy(BadGuy& badguy, const CollisionHit& hit) } // If we are hit from the direction we are facing: turn around - if ((hit.normal.x > .8) && (dir == LEFT)) { + if(hit.left && (dir == LEFT)) { dir = RIGHT; activate(); } - if ((hit.normal.x < -.8) && (dir == RIGHT)) { + if(hit.right && (dir == RIGHT)) { dir = LEFT; activate(); } diff --git a/src/badguy/totem.hpp b/src/badguy/totem.hpp index 874202514..044c000c0 100644 --- a/src/badguy/totem.hpp +++ b/src/badguy/totem.hpp @@ -36,7 +36,7 @@ public: void activate(); void active_update(float elapsed_time); void write(lisp::Writer& writer); - HitResponse collision_solid(GameObject& other, const CollisionHit& hit); + void collision_solid(const CollisionHit& hit); HitResponse collision_badguy(BadGuy& badguy, const CollisionHit& hit); virtual Totem* clone() const { return new Totem(*this); } diff --git a/src/badguy/yeti.cpp b/src/badguy/yeti.cpp index 8528e828d..909fbe22c 100644 --- a/src/badguy/yeti.cpp +++ b/src/badguy/yeti.cpp @@ -262,10 +262,10 @@ Yeti::drop_stalactite() nearest->start_shaking(); } -HitResponse -Yeti::collision_solid(GameObject& , const CollisionHit& hit) +void +Yeti::collision_solid(const CollisionHit& hit) { - if(fabsf(hit.normal.y) > .5) { + if(hit.top || hit.bottom) { // hit floor or roof physic.set_velocity_y(0); switch (state) { @@ -295,13 +295,10 @@ Yeti::collision_solid(GameObject& , const CollisionHit& hit) case SQUISHED: break; } - } else - if(fabsf(hit.normal.x) > .5) { + } else if(hit.left || hit.right) { // hit wall jump_up(); } - - return CONTINUE; } IMPLEMENT_FACTORY(Yeti, "yeti") diff --git a/src/badguy/yeti.hpp b/src/badguy/yeti.hpp index 30a6744c3..74d8b1957 100644 --- a/src/badguy/yeti.hpp +++ b/src/badguy/yeti.hpp @@ -33,7 +33,7 @@ public: void write(lisp::Writer& writer); void activate(); void active_update(float elapsed_time); - HitResponse collision_solid(GameObject& object, const CollisionHit& hit); + void collision_solid(const CollisionHit& hit); bool collision_squished(Player& player); void kill_squished(Player& player); void kill_fall(); diff --git a/src/badguy/zeekling.cpp b/src/badguy/zeekling.cpp index 3d3a539e0..4d7894331 100644 --- a/src/badguy/zeekling.cpp +++ b/src/badguy/zeekling.cpp @@ -84,6 +84,8 @@ Zeekling::onBumpHorizontal() { dir = (dir == LEFT ? RIGHT : LEFT); sprite->set_action(dir == LEFT ? "left" : "right"); physic.set_velocity_x(dir == LEFT ? -speed : speed); + } else { + assert(false); } } @@ -103,16 +105,14 @@ Zeekling::onBumpVertical() { } } -HitResponse -Zeekling::collision_solid(GameObject& , const CollisionHit& hit) +void +Zeekling::collision_solid(const CollisionHit& hit) { - if(fabsf(hit.normal.y) > .5) { + if(hit.top || hit.bottom) { onBumpVertical(); - } else { + } else if(hit.left || hit.right) { onBumpHorizontal(); } - - return CONTINUE; } /** @@ -159,30 +159,28 @@ Zeekling::should_we_dive() { void Zeekling::active_update(float elapsed_time) { - BadGuy::active_update(elapsed_time); - if (state == FLYING) { if (should_we_dive()) { state = DIVING; physic.set_velocity_y(2*fabsf(physic.get_velocity_x())); sprite->set_action(dir == LEFT ? "diving-left" : "diving-right"); } + BadGuy::active_update(elapsed_time); return; - } - - if (state == DIVING) { + } else if (state == DIVING) { + BadGuy::active_update(elapsed_time); return; - } - - if (state == CLIMBING) { + } else if (state == CLIMBING) { // stop climbing when we're back at initial height if (get_pos().y <= start_position.y) { state = FLYING; physic.set_velocity_y(0); } + BadGuy::active_update(elapsed_time); return; + } else { + assert(false); } - } IMPLEMENT_FACTORY(Zeekling, "zeekling") diff --git a/src/badguy/zeekling.hpp b/src/badguy/zeekling.hpp index fd6b5191a..178423703 100644 --- a/src/badguy/zeekling.hpp +++ b/src/badguy/zeekling.hpp @@ -32,7 +32,7 @@ public: void activate(); void write(lisp::Writer& writer); - HitResponse collision_solid(GameObject& other, const CollisionHit& hit); + void collision_solid(const CollisionHit& hit); void active_update(float elapsed_time); virtual Zeekling* clone() const { return new Zeekling(*this); } diff --git a/src/collision.cpp b/src/collision.cpp index bc38f8389..8ae5e91bf 100644 --- a/src/collision.cpp +++ b/src/collision.cpp @@ -30,115 +30,66 @@ #include "math/aatriangle.hpp" #include "math/rect.hpp" #include "collision_hit.hpp" +#include "log.hpp" -static const float DELTA = .0001; - -bool -Collision::intersects(const Rect& r1, const Rect& r2) +namespace collision { - if(r1.p2.x < r2.p1.x || r1.p1.x > r2.p2.x) - return false; - if(r1.p2.y < r2.p1.y || r1.p1.y > r2.p2.y) - return false; - return true; -} - -bool -Collision::rectangle_rectangle(CollisionHit& hit, const Rect& r1, - const Vector& movement, const Rect& r2) +bool intersects(const Rect& r1, const Rect& r2) { if(r1.p2.x < r2.p1.x || r1.p1.x > r2.p2.x) return false; if(r1.p2.y < r2.p1.y || r1.p1.y > r2.p2.y) return false; - if(movement.x > DELTA) { - hit.depth = r1.p2.x - r2.p1.x; - hit.time = hit.depth / movement.x; - hit.normal.x = -1; - hit.normal.y = 0; - } else if(movement.x < -DELTA) { - hit.depth = r2.p2.x - r1.p1.x; - hit.time = hit.depth / -movement.x; - hit.normal.x = 1; - hit.normal.y = 0; - } else { - if(movement.y > -DELTA && movement.y < DELTA) { - hit.time = 0; - hit.depth = 0; - hit.normal.x = 1; - hit.normal.y = 0; - return true; - } - hit.time = FLT_MAX; - } - - if(movement.y > DELTA) { - float ydepth = r1.p2.y - r2.p1.y; - float yt = ydepth / movement.y; - if(yt < hit.time) { - hit.depth = ydepth; - hit.time = yt; - hit.normal.x = 0; - hit.normal.y = -1; - } - } else if(movement.y < -DELTA) { - float ydepth = r2.p2.y - r1.p1.y; - float yt = ydepth / -movement.y; - if(yt < hit.time) { - hit.depth = ydepth; - hit.time = yt; - hit.normal.x = 0; - hit.normal.y = 1; - } - } - return true; } //--------------------------------------------------------------------------- -static void makePlane(const Vector& p1, const Vector& p2, Vector& n, float& c) -{ - n = Vector(p2.y-p1.y, p1.x-p2.x); - c = -(p2 * n); - float nval = n.norm(); - n /= nval; - c /= nval; +namespace { + inline void makePlane(const Vector& p1, const Vector& p2, Vector& n, float& c) + { + n = Vector(p2.y-p1.y, p1.x-p2.x); + c = -(p2 * n); + float nval = n.norm(); + n /= nval; + c /= nval; + } + + static const float DELTA = .0001; } -bool -Collision::rectangle_aatriangle(CollisionHit& hit, const Rect& rect, - const Vector& movement, const AATriangle& triangle) +bool rectangle_aatriangle(Constraints* constraints, const Rect& rect, + const AATriangle& triangle) { - if(!rectangle_rectangle(hit, rect, movement, (const Rect&) triangle)) + if(!intersects(rect, (const Rect&) triangle)) return false; Vector normal; float c; Vector p1; - Vector tp1, tp2; + Rect area; switch(triangle.dir & AATriangle::DEFORM_MASK) { case 0: - tp1 = triangle.p1; - tp2 = triangle.p2; + area.p1 = triangle.p1; + area.p2 = triangle.p2; break; case AATriangle::DEFORM1: - tp1 = Vector(triangle.p1.x, triangle.p1.y + triangle.get_height()/2); - tp2 = triangle.p2; + area.p1 = Vector(triangle.p1.x, triangle.p1.y + triangle.get_height()/2); + area.p2 = triangle.p2; break; case AATriangle::DEFORM2: - tp1 = triangle.p1; - tp2 = Vector(triangle.p2.x, triangle.p1.y + triangle.get_height()/2); + area.p1 = triangle.p1; + area.p2 = Vector(triangle.p2.x, triangle.p1.y + triangle.get_height()/2); break; case AATriangle::DEFORM3: - tp1 = triangle.p1; - tp2 = Vector(triangle.p1.x + triangle.get_width()/2, triangle.p2.y); + area.p1 = triangle.p1; + area.p2 = Vector(triangle.p1.x + triangle.get_width()/2, triangle.p2.y); break; case AATriangle::DEFORM4: - tp1 = Vector(triangle.p1.x + triangle.get_width()/2, triangle.p1.y); - tp2 = triangle.p2; + area.p1 = Vector(triangle.p1.x + triangle.get_width()/2, triangle.p1.y); + area.p2 = triangle.p2; break; default: assert(false); @@ -147,21 +98,21 @@ Collision::rectangle_aatriangle(CollisionHit& hit, const Rect& rect, switch(triangle.dir & AATriangle::DIRECTION_MASK) { case AATriangle::SOUTHWEST: p1 = Vector(rect.p1.x, rect.p2.y); - makePlane(tp1, tp2, normal, c); + makePlane(area.p1, area.p2, normal, c); break; case AATriangle::NORTHEAST: p1 = Vector(rect.p2.x, rect.p1.y); - makePlane(tp2, tp1, normal, c); + makePlane(area.p2, area.p1, normal, c); break; case AATriangle::SOUTHEAST: p1 = rect.p2; - makePlane(Vector(tp1.x, tp2.y), - Vector(tp2.x, tp1.y), normal, c); + makePlane(Vector(area.p1.x, area.p2.y), + Vector(area.p2.x, area.p1.y), normal, c); break; case AATriangle::NORTHWEST: p1 = rect.p1; - makePlane(Vector(tp2.x, tp1.y), - Vector(tp1.x, tp2.y), normal, c); + makePlane(Vector(area.p2.x, area.p1.y), + Vector(area.p1.x, area.p2.y), normal, c); break; default: assert(false); @@ -171,13 +122,67 @@ Collision::rectangle_aatriangle(CollisionHit& hit, const Rect& rect, float depth = n_p1 - c; if(depth < 0) return false; - float time = depth / -(normal * movement); - if(time < hit.time) { - hit.depth = depth; - hit.time = time; - hit.normal = normal; - } +#if 0 + std::cout << "R: " << rect << " Tri: " << triangle << "\n"; + std::cout << "Norm: " << normal << " Depth: " << depth << "\n"; +#endif + + Vector outvec = normal * (depth + 0.2); + + const float RDELTA = 3; + if(p1.x < area.p1.x - RDELTA || p1.x > area.p2.x + RDELTA + || p1.y < area.p1.y - RDELTA || p1.y > area.p2.y + RDELTA) { + set_rectangle_rectangle_constraints(constraints, rect, area); + constraints->hit.left = false; + constraints->hit.right = false; + } else { + if(outvec.x < 0) { + constraints->right = rect.get_right() + outvec.x; + } else { + constraints->left = rect.get_left() + outvec.x; + } + + if(outvec.y < 0) { + constraints->bottom = rect.get_bottom() + outvec.y; + constraints->hit.bottom = true; + } else { + constraints->top = rect.get_top() + outvec.y; + constraints->hit.top = true; + } + constraints->hit.slope_normal = normal; + } + return true; } +void set_rectangle_rectangle_constraints(Constraints* constraints, + const Rect& r1, const Rect& r2) +{ + float itop = r1.get_bottom() - r2.get_top(); + float ibottom = r2.get_bottom() - r1.get_top(); + float ileft = r1.get_right() - r2.get_left(); + float iright = r2.get_right() - r1.get_left(); + + float vert_penetration = std::min(itop, ibottom); + float horiz_penetration = std::min(ileft, iright); + if(vert_penetration < horiz_penetration) { + if(itop < ibottom) { + constraints->bottom = std::min(constraints->bottom, r2.get_top()); + constraints->hit.bottom = true; + } else { + constraints->top = std::max(constraints->top, r2.get_bottom()); + constraints->hit.top = true; + } + } else { + if(ileft < iright) { + constraints->right = std::min(constraints->right, r2.get_left()); + constraints->hit.right = true; + } else { + constraints->left = std::max(constraints->left, r2.get_right()); + constraints->hit.left = true; + } + } +} + +} diff --git a/src/collision.hpp b/src/collision.hpp index 62f2145df..cc5bcd0cc 100644 --- a/src/collision.hpp +++ b/src/collision.hpp @@ -20,29 +20,52 @@ #ifndef __COLLISION_H__ #define __COLLISION_H__ +#include +#include "collision_hit.hpp" + class Vector; class Rect; class AATriangle; -class CollisionHit; -class Collision +namespace collision +{ + +class Constraints { public: - /** checks if 2 rectangle intersect each other */ - static bool intersects(const Rect& r1, const Rect& r2); - - /** does collision detection between 2 rectangles. Returns true in case of - * collision and fills in the hit structure then. - */ - static bool rectangle_rectangle(CollisionHit& hit, const Rect& r1, - const Vector& movement, const Rect& r2); - - /** does collision detection between a rectangle and an axis aligned triangle - * Returns true in case of a collision and fills in the hit structure then. - */ - static bool rectangle_aatriangle(CollisionHit& hit, const Rect& rect, - const Vector& movement, const AATriangle& triangle); + Constraints() { + left = -INFINITY; + right = INFINITY; + top = -INFINITY; + bottom = INFINITY; + } + + bool has_constraints() const { + return left > -INFINITY || right < INFINITY + || top > -INFINITY || bottom < INFINITY; + } + + float left; + float right; + float top; + float bottom; + Vector ground_movement; + CollisionHit hit; }; +/** checks if 2 rectangle intersect each other */ +bool intersects(const Rect& r1, const Rect& r2); + +/** does collision detection between a rectangle and an axis aligned triangle + * Returns true in case of a collision and fills in the hit structure then. + */ +bool rectangle_aatriangle(Constraints* constraints, const Rect& rect, + const AATriangle& triangle); + +void set_rectangle_rectangle_constraints(Constraints* constraints, + const Rect& r1, const Rect& r2); + +} + #endif diff --git a/src/collision_grid.cpp b/src/collision_grid.cpp deleted file mode 100644 index e53d18ab8..000000000 --- a/src/collision_grid.cpp +++ /dev/null @@ -1,296 +0,0 @@ -// $Id$ -// -// SuperTux -// Copyright (C) 2006 Matthias Braun -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -// 02111-1307, USA. -#include - -#include -#include "collision_grid.hpp" -#include "log.hpp" -#include "collision.hpp" -#include "sector.hpp" -#include "collision_grid_iterator.hpp" - -static const float DELTA = .001; - -CollisionGrid::CollisionGrid(float newwidth, float newheight) - : width(newwidth), height(newheight), cell_width(128), cell_height(128), - iterator_timestamp(0) -{ - cells_x = size_t(width / cell_width) + 1; - cells_y = size_t(height / cell_height) + 1; - grid.resize(cells_x * cells_y); -} - -CollisionGrid::~CollisionGrid() -{ - for(GridEntries::iterator i = grid.begin(); i != grid.end(); ++i) { - GridEntry* entry = *i; - while(entry) { - GridEntry* nextentry = entry->next; - delete entry; - entry = nextentry; - } - } -} - -void -CollisionGrid::add_object(MovingObject* object) -{ -#ifdef DEBUG - // make sure the object isn't already in the grid - for(Objects::iterator i = objects.begin(); i != objects.end(); ++i) { - ObjectWrapper* wrapper = *i; - if(wrapper->object == object) - assert(false); - } - assert(object != 0); -#endif - - ObjectWrapper* wrapper = new ObjectWrapper; - wrapper->object = object; - wrapper->timestamp = 0; - wrapper->dest = object->bbox; - objects.push_back(wrapper); - wrapper->id = objects.size()-1; - - const Rect& bbox = object->bbox; - for(float y = bbox.p1.y; y < bbox.p2.y; y += cell_height) { - for(float x = bbox.p1.x; x < bbox.p2.x; x += cell_width) { - int gridx = int(x / cell_width); - int gridy = int(y / cell_height); - if(gridx < 0 || gridy < 0 - || gridx >= int(cells_x) || gridy >= int(cells_y)) { - log_warning << "Object out of range: " << gridx << ", " << gridy << std::endl; - continue; - } - GridEntry* entry = new GridEntry; - entry->object_wrapper = wrapper; - entry->next = grid[gridy*cells_x + gridx]; - grid[gridy*cells_x + gridx] = entry; - } - } -} - -void -CollisionGrid::remove_object(MovingObject* object) -{ - ObjectWrapper* wrapper = 0; - for(Objects::iterator i = objects.begin(); i != objects.end(); ++i) { - if((*i)->object == object) { - wrapper = *i; - objects.erase(i); - break; - } - } -#ifdef DEBUG - assert(wrapper != 0); -#else - if(wrapper == 0) { - log_warning << "Tried to remove nonexistant object" << std::endl; - return; - } -#endif - - const Rect& bbox = wrapper->dest; - for(float y = bbox.p1.y; y < bbox.p2.y; y += cell_height) { - for(float x = bbox.p1.x; x < bbox.p2.x; x += cell_width) { - int gridx = int(x / cell_width); - int gridy = int(y / cell_height); - if(gridx < 0 || gridy < 0 - || gridx >= int(cells_x) || gridy >= int(cells_y)) { - log_warning << "Object out of range: " << gridx << ", " << gridy << std::endl; - continue; - } - remove_object_from_gridcell(gridy*cells_x + gridx, wrapper); - } - } - - delete wrapper; -} - -void -CollisionGrid::move_object(ObjectWrapper* wrapper) -{ - // FIXME not optimal yet... should leave the gridcells untouched that don't - // need to be changed. - const Rect& obbox = wrapper->dest; - for(float y = obbox.p1.y; y < obbox.p2.y; y += cell_height) { - for(float x = obbox.p1.x; x < obbox.p2.x; x += cell_width) { - int gridx = int(x / cell_width); - int gridy = int(y / cell_height); - if(gridx < 0 || gridy < 0 || - gridx >= int(cells_x) || gridy >= int(cells_y)) { - log_warning << "Object out of range: " << gridx << ", " << gridy << std::endl; - continue; - } - remove_object_from_gridcell(gridy*cells_x + gridx, wrapper); - } - } - - const Rect& nbbox = wrapper->object->bbox; - for(float y = nbbox.p1.y; y < nbbox.p2.y; y += cell_height) { - for(float x = nbbox.p1.x; x < nbbox.p2.x; x += cell_width) { - int gridx = int(x / cell_width); - int gridy = int(y / cell_height); - if(gridx < 0 || gridy < 0 - || gridx >= int(cells_x) || gridy >= int(cells_y)) { - log_warning << "Object out of range: " << gridx << ", " << gridy << std::endl; - continue; - } - - GridEntry* entry = new GridEntry; - entry->object_wrapper = wrapper; - entry->next = grid[gridy*cells_x + gridx]; - grid[gridy*cells_x + gridx] = entry; - } - } - - wrapper->dest = nbbox; -} - -void -CollisionGrid::check_collisions() -{ - std::vector moved_objects; - -#if 0 - CollisionGridIterator iter(*this, Sector::current()->get_active_region()); - while(ObjectWrapper* wrapper = iter.next_wrapper()) { - MovingObject* object = wrapper->object; - if(!object->is_valid()) - continue; - if(object->get_group() == COLGROUP_DISABLED) { - object->bbox.move(object->movement); - object->movement = Vector(0, 0); - moved_objects.push_back(wrapper); - continue; - } - - // hack for now... - Sector::current()->collision_tilemap(object, 0); - - collide_object(wrapper); - - if(object->movement != Vector(0, 0)) { - object->bbox.move(object->movement); - object->movement = Vector(0, 0); - moved_objects.push_back(wrapper); - } - } -#endif - - for(std::vector::iterator i = moved_objects.begin(); - i != moved_objects.end(); ++i) { - move_object(*i); - } -} - -void -CollisionGrid::collide_object(ObjectWrapper* wrapper) -{ - iterator_timestamp++; - - const Rect& bbox = wrapper->object->bbox; - for(float y = bbox.p1.y - cell_height; y < bbox.p2.y + cell_height; y += cell_height) { - for(float x = bbox.p1.x - cell_width; x < bbox.p2.x + cell_width; x += cell_width) { - int gridx = int(x / cell_width); - int gridy = int(y / cell_height); - if(gridx < 0 || gridy < 0 - || gridx >= int(cells_x) || gridy >= int(cells_y)) { - //log_warning << "Object out of range: " << gridx << ", " << gridy << std::endl; - continue; - } - - for(GridEntry* entry = grid[gridy*cells_x + gridx]; entry; - entry = entry->next) { - ObjectWrapper* wrapper2 = entry->object_wrapper; - // only check each object once (even if it is in multiple cells) - if(wrapper2->timestamp == iterator_timestamp) - continue; - // don't collide with objects we already collided with - if(wrapper2->id <= wrapper->id) - continue; - - wrapper->timestamp = iterator_timestamp; - collide_object_object(wrapper, wrapper2); - } - } - } -} - -void -CollisionGrid::collide_object_object(ObjectWrapper* wrapper, - ObjectWrapper* wrapper2) -{ - CollisionHit hit; - MovingObject* object1 = wrapper->object; - MovingObject* object2 = wrapper2->object; - - Rect dest1 = object1->get_bbox(); - dest1.move(object1->get_movement()); - Rect dest2 = object2->get_bbox(); - dest2.move(object2->get_movement()); - - Vector movement = object1->get_movement() - object2->get_movement(); - if(Collision::rectangle_rectangle(hit, dest1, movement, dest2)) { - HitResponse response1 = object1->collision(*object2, hit); - hit.normal *= -1; - HitResponse response2 = object2->collision(*object1, hit); - - if(response1 != CONTINUE) { - if(response1 == ABORT_MOVE) - object1->movement = Vector(0, 0); - if(response2 == CONTINUE) - object2->movement += hit.normal * (hit.depth + DELTA); - } else if(response2 != CONTINUE) { - if(response2 == ABORT_MOVE) - object2->movement = Vector(0, 0); - if(response1 == CONTINUE) - object1->movement += -hit.normal * (hit.depth + DELTA); - } else { - object1->movement += -hit.normal * (hit.depth/2 + DELTA); - object2->movement += hit.normal * (hit.depth/2 + DELTA); - } - } -} - -void -CollisionGrid::remove_object_from_gridcell(int gridcell, ObjectWrapper* wrapper) -{ - GridEntry* lastentry = 0; - GridEntry* entry = grid[gridcell]; - - while(entry) { - if(entry->object_wrapper == wrapper) { - if(lastentry == 0) { - grid[gridcell] = entry->next; - } else { - lastentry->next = entry->next; - } - delete entry; - return; - } - - lastentry = entry; - entry = entry->next; - }; - - log_warning << "Couldn't find object in cell" << std::endl; -} - diff --git a/src/collision_grid.hpp b/src/collision_grid.hpp deleted file mode 100644 index 9820b0d94..000000000 --- a/src/collision_grid.hpp +++ /dev/null @@ -1,86 +0,0 @@ -// $Id$ -// -// SuperTux -// Copyright (C) 2006 Matthias Braun -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -// 02111-1307, USA. -#ifndef __COLLISION_GRID_H__ -#define __COLLISION_GRID_H__ - -#include -#include "moving_object.hpp" - -class CollisionGridIterator; - -/** - * A rectangular grid to keep track of all moving game objects. It allows fast - * queries for all objects in a rectangular area. - */ -class CollisionGrid -{ -public: - CollisionGrid(float width, float height); - ~CollisionGrid(); - - void add_object(MovingObject* object); - void remove_object(MovingObject* object); - - void check_collisions(); - -private: - friend class CollisionGridIterator; - - struct ObjectWrapper - { - MovingObject* object; - Rect dest; - /** (pseudo) timestamp. When reading from the grid the timestamp is - * changed so that you can easily avoid reading an object multiple times - * when it is in several cells that you check. - */ - int timestamp; - /// index in the objects vector - int id; - }; - - /** Element for the single linked list in each grid cell */ - struct GridEntry - { - GridEntry* next; - ObjectWrapper* object_wrapper; - }; - - void remove_object_from_gridcell(int gridcell, ObjectWrapper* wrapper); - void collide_object(ObjectWrapper* wrapper); - void collide_object_object(ObjectWrapper* wrapper, ObjectWrapper* wrapper2); - void move_object(ObjectWrapper* wrapper); - - typedef std::vector GridEntries; - GridEntries grid; - typedef std::vector Objects; - Objects objects; - size_t cells_x, cells_y; - float width; - float height; - float cell_width; - float cell_height; - int iterator_timestamp; -}; - -extern CollisionGrid* bla; - -#endif - diff --git a/src/collision_grid_iterator.hpp b/src/collision_grid_iterator.hpp deleted file mode 100644 index c73a533d1..000000000 --- a/src/collision_grid_iterator.hpp +++ /dev/null @@ -1,108 +0,0 @@ -// $Id$ -// -// SuperTux -// Copyright (C) 2006 Matthias Braun -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -// 02111-1307, USA. -#ifndef __COLLISION_GRID_ITERATOR_H__ -#define __COLLISION_GRID_ITERATOR_H__ - -#include "math/rect.hpp" -#include "log.hpp" - -class CollisionGrid; - -class CollisionGridIterator -{ -public: - CollisionGridIterator(CollisionGrid& newgrid, const Rect& bbox) - : grid(newgrid) - { - start_x = int(bbox.p1.x / grid.cell_width) - 2; - if(start_x < 0) - start_x = 0; - x = start_x; - - y = int(bbox.p1.y / grid.cell_height) - 2; - if(y < 0) - y = 0; - - end_x = int(bbox.p2.x / grid.cell_width) + 2; - if(end_x > (int) grid.cells_x) - end_x = grid.cells_x; - - end_y = int(bbox.p2.y / grid.cell_height) + 2; - if(end_y > (int) grid.cells_y) - end_y = grid.cells_y; - - timestamp = grid.iterator_timestamp++; - entry = 0; - - if(start_x >= end_x) { - log_debug << "bad region" << std::endl; - y = 0; - end_y = 0; - return; - } - } - - MovingObject* next() - { - CollisionGrid::ObjectWrapper* wrapper = next_wrapper(); - if(wrapper == 0) - return 0; - - return wrapper->object; - } - -private: - friend class CollisionGrid; - - CollisionGrid::ObjectWrapper* next_wrapper() - { - CollisionGrid::ObjectWrapper* wrapper; - - do { - while(entry == 0) { - if(y >= end_y) - return 0; - - entry = grid.grid[y*grid.cells_x + x]; - x++; - if(x >= end_x) { - x = start_x; - y++; - } - } - - wrapper = entry->object_wrapper; - entry = entry->next; - } while(wrapper->timestamp == timestamp); - - wrapper->timestamp = timestamp; - - return wrapper; - } - - CollisionGrid& grid; - CollisionGrid::GridEntry* entry; - int x, y; - int start_x, end_x, end_y; - int timestamp; -}; - -#endif - diff --git a/src/collision_hit.hpp b/src/collision_hit.hpp index b9ed4d522..ba29e9f82 100644 --- a/src/collision_hit.hpp +++ b/src/collision_hit.hpp @@ -19,6 +19,8 @@ #ifndef SUPERTUX_COLLISION_HIT_H #define SUPERTUX_COLLISION_HIT_H +#include +#include #include "math/vector.hpp" /** @@ -35,7 +37,12 @@ enum HitResponse /// do the move ignoring the collision FORCE_MOVE, /// passes movement to collided object - PASS_MOVEMENT + PASS_MOVEMENT, + + /// the object should not appear solid + PASSTHROUGH, + /// the object should appear solid + SOLID, }; /** @@ -44,12 +51,19 @@ enum HitResponse class CollisionHit { public: - /// penetration depth - float depth; - /// time of the collision (between 0 and 1 in relation to movement) - float time; - /// The normal of the side we collided with - Vector normal; + CollisionHit() { + left = false; + right = false; + top = false; + bottom = false; + crush = false; + } + + bool left, right; + bool top, bottom; + bool crush; + + Vector slope_normal; }; #endif diff --git a/src/log.cpp b/src/log.cpp index 086cfabd0..9b03ff834 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -21,10 +21,18 @@ #include "log.hpp" #include "math/vector.hpp" +#include "math/rect.hpp" std::ostream& operator<<(std::ostream& out, const Vector& vector) { - out << '[' << vector.x << ',' << vector.y << ']'; - return out; + out << '[' << vector.x << ',' << vector.y << ']'; + return out; +} + +std::ostream& operator<<(std::ostream& out, const Rect& rect) +{ + out << "[" << rect.get_left() << "," << rect.get_top() << " " + << rect.get_right() << "," << rect.get_bottom() << "]"; + return out; } diff --git a/src/log.hpp b/src/log.hpp index b26960a16..4d4b74b98 100644 --- a/src/log.hpp +++ b/src/log.hpp @@ -81,6 +81,8 @@ inline std::ostream& log_fatal_f() { class Vector; std::ostream& operator<< (std::ostream& str, const Vector& vector); +class Rect; +std::ostream& operator<< (std::ostream& str, const Rect& rect); #endif diff --git a/src/math/rect.hpp b/src/math/rect.hpp index 2a50dd955..79e422af0 100644 --- a/src/math/rect.hpp +++ b/src/math/rect.hpp @@ -95,11 +95,11 @@ public: p2 += v; } - bool inside(const Vector& v) const + bool contains(const Vector& v) const { return v.x >= p1.x && v.y >= p1.y && v.x < p2.x && v.y < p2.y; } - bool inside(const Rect& other) const + bool contains(const Rect& other) const { if(p1.x >= other.p2.x || other.p1.x >= p2.x) return false; diff --git a/src/moving_object.hpp b/src/moving_object.hpp index e6ae48343..46abffbbe 100644 --- a/src/moving_object.hpp +++ b/src/moving_object.hpp @@ -79,11 +79,14 @@ class MovingObject : public GameObject public: MovingObject(); virtual ~MovingObject(); - - /** this function is called when the object collided with any other object - */ - virtual HitResponse collision(GameObject& other, - const CollisionHit& hit) = 0; + + /** this function is called when the object collided with something solid */ + virtual void collision_solid(const CollisionHit& hit) + { + (void) hit; + } + /** this function is called when the object collided with any other object */ + virtual HitResponse collision(GameObject& other, const CollisionHit& hit) = 0; /** called when tiles with special attributes have been touched */ virtual void collision_tile(uint32_t tile_attributes) { diff --git a/src/object/block.cpp b/src/object/block.cpp index 3ab0d1bd0..95520d615 100644 --- a/src/object/block.cpp +++ b/src/object/block.cpp @@ -64,12 +64,11 @@ Block::~Block() } HitResponse -Block::collision(GameObject& other, const CollisionHit& hitdata) +Block::collision(GameObject& other, const CollisionHit& ) { Player* player = dynamic_cast (&other); if(player) { - // collided from below? - if(hitdata.normal.x == 0 && hitdata.normal.y < 0) { + if(player->get_bbox().get_top() > get_bbox().get_bottom() - 7.0) { hit(*player); } } @@ -85,7 +84,7 @@ Block::collision(GameObject& other, const CollisionHit& hitdata) } } - return FORCE_MOVE; + return SOLID; } void @@ -225,7 +224,7 @@ BonusBlock::try_open() sector->add_object(riser); } else { SpecialRiser* riser = new SpecialRiser( - get_pos(), new Flower(Flower::FIREFLOWER)); + get_pos(), new Flower(FIRE_BONUS)); sector->add_object(riser); } sound_manager->play("sounds/upgrade.wav"); @@ -237,7 +236,7 @@ BonusBlock::try_open() sector->add_object(riser); } else { SpecialRiser* riser = new SpecialRiser( - get_pos(), new Flower(Flower::ICEFLOWER)); + get_pos(), new Flower(ICE_BONUS)); sector->add_object(riser); } sound_manager->play("sounds/upgrade.wav"); @@ -257,9 +256,6 @@ BonusBlock::try_open() sector->add_object(riser); sound_manager->play("sounds/upgrade.wav"); break; - - //default: - //assert(false); } start_bounce(); diff --git a/src/object/bullet.cpp b/src/object/bullet.cpp index a8b7cef9d..ef7b52f17 100644 --- a/src/object/bullet.cpp +++ b/src/object/bullet.cpp @@ -28,39 +28,34 @@ #include "badguy/badguy.hpp" #include "main.hpp" -static const float BULLET_XM = 600; -static const float BULLET_STARTING_YM = 0; +namespace { + const float BULLET_XM = 600; + const float BULLET_STARTING_YM = 0; +} -Bullet::Bullet(const Vector& pos, float xm, int dir, int kind_) - : kind(kind_), life_count(3), sprite(0) +Bullet::Bullet(const Vector& pos, float xm, int dir) + : life_count(3) { + sprite.reset(sprite_manager->create("images/objects/bullets/firebullet.sprite")); + bbox.set_pos(pos); - bbox.set_size(4, 4); + bbox.set_size(sprite->get_current_hitbox_width(), sprite->get_current_hitbox_height()); float speed = dir == RIGHT ? BULLET_XM : -BULLET_XM; physic.set_velocity_x(speed + xm); physic.set_velocity_y(BULLET_STARTING_YM); - - if (kind == ICE_BULLET) { - life_count = 6; //ice-bullets get "extra lives" for bumping off walls - sprite = sprite_manager->create("images/objects/bullets/icebullet.sprite"); - } else if(kind == FIRE_BULLET) { - sprite = sprite_manager->create("images/objects/bullets/firebullet.sprite"); - } } Bullet::~Bullet() { - delete sprite; } void Bullet::update(float elapsed_time) { - if(kind == FIRE_BULLET) { - // @not completely framerate independant :-/ - physic.set_velocity_y(physic.get_velocity_y() + 50 * elapsed_time); - } + // @not completely framerate independant :-/ + physic.set_velocity_y(physic.get_velocity_y() + 50 * elapsed_time); + if(physic.get_velocity_y() > 900) physic.set_velocity_y(900); else if(physic.get_velocity_y() < -900) @@ -88,30 +83,20 @@ Bullet::draw(DrawingContext& context) sprite->draw(context, get_pos(), LAYER_OBJECTS); } -HitResponse -Bullet::collision(GameObject& other, const CollisionHit& hit) +void +Bullet::collision_solid(const CollisionHit& hit) { - if(other.get_flags() & FLAG_SOLID) { - if(fabsf(hit.normal.y) > .5) { // roof or floor bump - physic.set_velocity_y(-physic.get_velocity_y()); - life_count -= 1; - } else { // bumped left or right - if(kind == FIRE_BULLET) - remove_me(); - else - physic.set_velocity_x(-physic.get_velocity_x()); - } - - return CONTINUE; - } - - // hit a Badguy - BadGuy* badguy = dynamic_cast (&other); - if(badguy) { + if(hit.top || hit.bottom) { + physic.set_velocity_y(-physic.get_velocity_y()); + life_count--; + } else if(hit.left || hit.right) { remove_me(); - return FORCE_MOVE; } - +} + +HitResponse +Bullet::collision(GameObject& , const CollisionHit& ) +{ return FORCE_MOVE; } diff --git a/src/object/bullet.hpp b/src/object/bullet.hpp index 52becdda4..3664f33aa 100644 --- a/src/object/bullet.hpp +++ b/src/object/bullet.hpp @@ -24,27 +24,21 @@ #include "physic.hpp" #include "sprite/sprite.hpp" -enum BulletsKind { - FIRE_BULLET, - ICE_BULLET -}; - class Bullet : public MovingObject { public: - Bullet(const Vector& pos, float xm, int dir, int kind); + Bullet(const Vector& pos, float xm, int dir); ~Bullet(); void update(float elapsed_time); void draw(DrawingContext& context); + void collision_solid(const CollisionHit& hit); HitResponse collision(GameObject& other, const CollisionHit& hit); - int kind; - private: int life_count; Physic physic; - Sprite* sprite; + std::auto_ptr sprite; }; #endif diff --git a/src/object/candle.cpp b/src/object/candle.cpp index e11bcb61b..0279167ab 100644 --- a/src/object/candle.cpp +++ b/src/object/candle.cpp @@ -40,7 +40,7 @@ Candle::Candle(const lisp::Lisp& lisp) } HitResponse -Candle::collision(GameObject& , const CollisionHit& ) +Candle::collision(GameObject&, const CollisionHit& ) { return FORCE_MOVE; } diff --git a/src/object/coin.cpp b/src/object/coin.cpp index 2684bcd2a..e9e0a0d2c 100644 --- a/src/object/coin.cpp +++ b/src/object/coin.cpp @@ -38,11 +38,13 @@ Coin::Coin(const Vector& pos) : MovingSprite(pos, "images/objects/coin/coin.sprite", LAYER_TILES, COLGROUP_TOUCHABLE) { + sound_manager->preload("sounds/coin.wav"); } Coin::Coin(const lisp::Lisp& reader) : MovingSprite(reader, "images/objects/coin/coin.sprite", LAYER_TILES, COLGROUP_TOUCHABLE) { + sound_manager->preload("sounds/coin.wav"); } void diff --git a/src/object/coin.hpp b/src/object/coin.hpp index c59586541..9c3106f0c 100644 --- a/src/object/coin.hpp +++ b/src/object/coin.hpp @@ -28,7 +28,6 @@ class Coin : public MovingSprite public: Coin(const Vector& pos); Coin(const lisp::Lisp& reader); - virtual Coin* clone() const { return new Coin(*this); } HitResponse collision(GameObject& other, const CollisionHit& hit); diff --git a/src/object/flower.cpp b/src/object/flower.cpp index 4e4c87876..b5830e0a9 100644 --- a/src/object/flower.cpp +++ b/src/object/flower.cpp @@ -20,6 +20,7 @@ #include #include +#include #include "flower.hpp" #include "resources.hpp" #include "camera.hpp" @@ -28,17 +29,20 @@ #include "audio/sound_manager.hpp" #include "sprite/sprite_manager.hpp" -Flower::Flower(Type _type) +Flower::Flower(BonusType _type) : type(_type) { bbox.set_size(32, 32); - if(_type == FIREFLOWER){ + if(type == FIRE_BONUS) { sprite = sprite_manager->create("images/powerups/fireflower/fireflower.sprite"); sound_manager->preload("sounds/fire-flower.wav"); } - else + else if(type == ICE_BONUS) { sprite = sprite_manager->create("images/powerups/iceflower/iceflower.sprite"); + } else { + assert(false); + } set_group(COLGROUP_TOUCHABLE); } @@ -66,10 +70,8 @@ Flower::collision(GameObject& other, const CollisionHit& ) if(!player) return ABORT_MOVE; - if(type == FIREFLOWER) - player->add_bonus(FIRE_BONUS, true); - else - player->add_bonus(ICE_BONUS, true); + if(!player->add_bonus(type, true)) + return FORCE_MOVE; sound_manager->play("sounds/fire-flower.wav"); remove_me(); diff --git a/src/object/flower.hpp b/src/object/flower.hpp index 637f1a98d..4411ef9db 100644 --- a/src/object/flower.hpp +++ b/src/object/flower.hpp @@ -23,14 +23,12 @@ #include "moving_object.hpp" #include "sprite/sprite.hpp" #include "physic.hpp" +#include "player_status.hpp" class Flower : public MovingObject { public: - enum Type { - FIREFLOWER, ICEFLOWER - }; - Flower(Type type); + Flower(BonusType type); ~Flower(); virtual void update(float elapsed_time); @@ -38,7 +36,7 @@ public: virtual HitResponse collision(GameObject& other, const CollisionHit& hit); private: - Type type; + BonusType type; Sprite* sprite; }; diff --git a/src/object/growup.cpp b/src/object/growup.cpp index 32e3674e5..3a32bcfdf 100644 --- a/src/object/growup.cpp +++ b/src/object/growup.cpp @@ -41,22 +41,23 @@ GrowUp::update(float elapsed_time) movement = physic.get_movement(elapsed_time); } -HitResponse -GrowUp::collision(GameObject& other, const CollisionHit& hit) +void +GrowUp::collision_solid(const CollisionHit& hit) { - if(other.get_flags() & FLAG_SOLID) { - if(fabsf(hit.normal.y) > .5) { // roof or ground - physic.set_velocity_y(0); - } else { // bumped left or right - physic.set_velocity_x(-physic.get_velocity_x()); - } + if(hit.top || hit.bottom) + physic.set_velocity_y(0); + if(hit.left || hit.right) + physic.set_velocity_x(-physic.get_velocity_x()); +} - return CONTINUE; - } - +HitResponse +GrowUp::collision(GameObject& other, const CollisionHit& ) +{ Player* player = dynamic_cast(&other); if(player != 0) { - player->add_bonus(GROWUP_BONUS, true); + if(!player->add_bonus(GROWUP_BONUS, true)) + return FORCE_MOVE; + sound_manager->play("sounds/grow.wav"); remove_me(); diff --git a/src/object/growup.hpp b/src/object/growup.hpp index 240591493..cad747b32 100644 --- a/src/object/growup.hpp +++ b/src/object/growup.hpp @@ -30,6 +30,7 @@ public: virtual GrowUp* clone() const { return new GrowUp(*this); } virtual void update(float elapsed_time); + virtual void collision_solid(const CollisionHit& hit); virtual HitResponse collision(GameObject& other, const CollisionHit& hit); private: diff --git a/src/object/hurting_platform.cpp b/src/object/hurting_platform.cpp index c730e182f..59cbfdf80 100644 --- a/src/object/hurting_platform.cpp +++ b/src/object/hurting_platform.cpp @@ -1,4 +1,4 @@ -// $Id: hurtingplatform.cpp 3506 2006-05-12 01:41:09Z sommer $ +// $Id$ // // SuperTux - Hurting Platform // Copyright (C) 2006 Christoph Sommer @@ -30,10 +30,11 @@ HurtingPlatform::HurtingPlatform(const lisp::Lisp& reader) : Platform(reader) { + set_group(COLGROUP_TOUCHABLE); } HitResponse -HurtingPlatform::collision(GameObject& other, const CollisionHit& hit) +HurtingPlatform::collision(GameObject& other, const CollisionHit& ) { Player* player = dynamic_cast(&other); if (player) { @@ -43,7 +44,8 @@ HurtingPlatform::collision(GameObject& other, const CollisionHit& hit) if (badguy) { badguy->kill_fall(); } - return Platform::collision(other, hit); + + return FORCE_MOVE; } IMPLEMENT_FACTORY(HurtingPlatform, "hurting_platform"); diff --git a/src/object/invisible_block.cpp b/src/object/invisible_block.cpp index d914b2bae..fe17ba651 100644 --- a/src/object/invisible_block.cpp +++ b/src/object/invisible_block.cpp @@ -26,13 +26,13 @@ #include "video/drawing_context.hpp" #include "audio/sound_manager.hpp" #include "object_factory.hpp" +#include "object/player.hpp" InvisibleBlock::InvisibleBlock(const Vector& pos) : Block(sprite_manager->create("images/objects/bonus_block/invisibleblock.sprite")), visible(false) { bbox.set_pos(pos); - flags &= ~FLAG_SOLID; - set_group(COLGROUP_MOVING); + sound_manager->preload("sounds/brick.wav"); sound_manager->preload("sounds/brick.wav"); } @@ -43,14 +43,31 @@ InvisibleBlock::draw(DrawingContext& context) sprite->draw(context, get_pos(), LAYER_OBJECTS); } +HitResponse +InvisibleBlock::collision(GameObject& other, const CollisionHit& hit) +{ + if(!visible) { + Player* player = dynamic_cast (&other); + if(player) { + if(player->get_movement().y > 0 || + player->get_bbox().get_top() <= get_bbox().get_bottom() - 7.0) { + return PASSTHROUGH; + } + } + } + + return Block::collision(other, hit); +} + void InvisibleBlock::hit(Player& ) { + sound_manager->play("sounds/brick.wav"); + if(visible) return; sprite->set_action("empty"); - sound_manager->play("sounds/brick.wav"); start_bounce(); flags |= FLAG_SOLID; set_group(COLGROUP_STATIC); diff --git a/src/object/invisible_block.hpp b/src/object/invisible_block.hpp index bada73ce2..560730208 100644 --- a/src/object/invisible_block.hpp +++ b/src/object/invisible_block.hpp @@ -28,6 +28,7 @@ public: InvisibleBlock(const Vector& pos); virtual void draw(DrawingContext& context); + virtual HitResponse collision(GameObject& other, const CollisionHit& hit); protected: virtual void hit(Player& player); diff --git a/src/object/particlesystem_interactive.cpp b/src/object/particlesystem_interactive.cpp index 0a9228abc..e253a4362 100644 --- a/src/object/particlesystem_interactive.cpp +++ b/src/object/particlesystem_interactive.cpp @@ -74,6 +74,8 @@ void ParticleSystem_Interactive::draw(DrawingContext& context) int ParticleSystem_Interactive::collision(Particle* object, Vector movement) { + using namespace collision; + TileMap* solids = Sector::current()->solids; // calculate rectangle where the object will move float x1, x2; @@ -90,19 +92,16 @@ ParticleSystem_Interactive::collision(Particle* object, Vector movement) int max_x = int(x2+1); int max_y = int(y2+1); - CollisionHit temphit, hit; Rect dest = Rect(x1, y1, x2, y2); dest.move(movement); - hit.time = -1; // represents an invalid value + Constraints constraints; for(int x = starttilex; x*32 < max_x; ++x) { for(int y = starttiley; y*32 < max_y; ++y) { const Tile* tile = solids->get_tile(x, y); if(!tile) continue; // skip non-solid tiles, except water - if (tile->getAttributes() & Tile::WATER) - water = true; - if(!water && !(tile->getAttributes() & Tile::SOLID)) + if(! (tile->getAttributes() & (Tile::WATER | Tile::SOLID))) continue; if(tile->getAttributes() & Tile::SLOPE) { // slope tile @@ -111,35 +110,39 @@ ParticleSystem_Interactive::collision(Particle* object, Vector movement) Vector p2((x+1)*32, (y+1)*32); triangle = AATriangle(p1, p2, tile->getData()); - if(Collision::rectangle_aatriangle(temphit, dest, movement, - triangle)) { - if(temphit.time > hit.time) - hit = temphit; + if(rectangle_aatriangle(&constraints, dest, triangle)) { + if(tile->getAttributes() & Tile::WATER) + water = true; } } else { // normal rectangular tile Rect rect(x*32, y*32, (x+1)*32, (y+1)*32); - if(Collision::rectangle_rectangle(temphit, dest, - movement, rect)) { - if(temphit.time > hit.time) - hit = temphit; + if(intersects(dest, rect)) { + if(tile->getAttributes() & Tile::WATER) + water = true; + set_rectangle_rectangle_constraints(&constraints, dest, rect); } } } } + + // TODO don't use magic numbers here... // did we collide at all? - if(hit.time < 0) { - return -1; //no collision - } - else { - if (water) - return 0; //collision with water tile - don't draw splash - else { - if ((hit.normal.x == 1) && (hit.normal.y == 0)) - return 2; //collision from right - else return 1; //collision from above + if(!constraints.has_constraints()) + return -1; + + const CollisionHit& hit = constraints.hit; + if (water) { + return 0; //collision with water tile - don't draw splash + } else { + if (hit.right || hit.left) { + return 2; //collision from right + } else { + return 1; //collision from above } } + + return 0; } RainParticleSystem::RainParticleSystem() @@ -270,6 +273,8 @@ CometParticleSystem::~CometParticleSystem() void CometParticleSystem::update(float elapsed_time) { + (void) elapsed_time; +#if 0 std::vector::iterator i; for( i = particles.begin(); i != particles.end(); ++i) { @@ -291,4 +296,5 @@ void CometParticleSystem::update(float elapsed_time) particle->pos.y = new_y; } } +#endif } diff --git a/src/object/platform.cpp b/src/object/platform.cpp index 333fd0714..08469b655 100644 --- a/src/object/platform.cpp +++ b/src/object/platform.cpp @@ -59,24 +59,9 @@ Platform::Platform(const Platform& other) walker->path = &*path; } -//TODO: Squish Tux when standing between platform and solid tile/object -// Improve collision handling -// Move all MovingObjects lying on the platform instead of only the player HitResponse -Platform::collision(GameObject& other, const CollisionHit& hit) +Platform::collision(GameObject& , const CollisionHit& ) { - if (typeid(other) == typeid(Player)) { - if (hit.normal.y >= 0.9) { - //Tux is standing on the platform - //Player* player = (Player*) &other; - //player->add_velocity(speed * 1.5); - return PASS_MOVEMENT; - } - } - if(other.get_flags() & FLAG_SOLID) { - //Collision with a solid tile - return ABORT_MOVE; - } return FORCE_MOVE; } diff --git a/src/object/player.cpp b/src/object/player.cpp index 4aab47f4a..8d81ec443 100644 --- a/src/object/player.cpp +++ b/src/object/player.cpp @@ -158,8 +158,6 @@ Player::init() on_ground_flag = false; grabbed_object = NULL; - floor_normal = Vector(0,-1); - physic.reset(); } @@ -188,7 +186,9 @@ Player::adjust_height(float new_height) Rect bbox2 = bbox; bbox2.move(Vector(0, bbox.get_height() - new_height)); bbox2.set_height(new_height); - if (!Sector::current()->is_free_space(bbox2)) return false; + if (!Sector::current()->is_free_space(bbox2)) + return false; + // adjust bbox accordingly // note that we use members of moving_object for this, so we can run this during CD, too set_pos(bbox2.p1); @@ -218,12 +218,11 @@ Player::update(float elapsed_time) set_width(31.8); } - // on downward slopes, adjust vertical velocity to match slope angle + // on downward slopes, adjust vertical velocity so tux walks smoothly down if (on_ground()) { - if (floor_normal.y != 0) { - if ((floor_normal.x * physic.get_velocity_x()) > 0) { - // we overdo it a little, just to be on the safe side - physic.set_velocity_y(-physic.get_velocity_x() * (floor_normal.x / floor_normal.y) * 2); + if(floor_normal.y != 0) { + if ((floor_normal.x * physic.get_velocity_x()) >= 0) { + physic.set_velocity_y(250); } } } @@ -569,25 +568,8 @@ Player::handle_vertical_input() } /* When Down is not held anymore, disable butt jump */ - if(butt_jump && !controller->hold(Controller::DOWN)) butt_jump = false; - - /** jumping is only allowed if we're about to touch ground soon and if the - * button has been up in between the last jump - */ - // FIXME -#if 0 - if ( (issolid(get_pos().x + bbox.get_width() / 2, - get_pos().y + bbox.get_height() + 64) || - issolid(get_pos().x + 1, get_pos().y + bbox.get_height() + 64) || - issolid(get_pos().x + bbox.get_width() - 1, - get_pos().y + bbox.get_height() + 64)) - && jumping == false - && can_jump == false - && input.jump && !input.old_jump) - { - can_jump = true; - } -#endif + if(butt_jump && !controller->hold(Controller::DOWN)) + butt_jump = false; } void @@ -686,47 +668,57 @@ Player::add_coins(int count) player_status->add_coins(count); } -void +bool Player::add_bonus(const std::string& bonustype) { + BonusType type = NO_BONUS; + if(bonustype == "grow") { - add_bonus(GROWUP_BONUS); + type = GROWUP_BONUS; } else if(bonustype == "fireflower") { - add_bonus(FIRE_BONUS); + type = FIRE_BONUS; } else if(bonustype == "iceflower") { - add_bonus(ICE_BONUS); + type = ICE_BONUS; } else if(bonustype == "none") { - add_bonus(NO_BONUS); + type = NO_BONUS; } else { std::ostringstream msg; msg << "Unknown bonus type " << bonustype; throw std::runtime_error(msg.str()); } + + return add_bonus(type); } -void +bool Player::add_bonus(BonusType type, bool animate) { // always ignore NO_BONUS if (type == NO_BONUS) { - return; + return true; } // ignore GROWUP_BONUS if we're already big if (type == GROWUP_BONUS) { - if (player_status->bonus == GROWUP_BONUS) return; - if (player_status->bonus == FIRE_BONUS) return; - if (player_status->bonus == ICE_BONUS) return; + if (player_status->bonus == GROWUP_BONUS) + return true; + if (player_status->bonus == FIRE_BONUS) + return true; + if (player_status->bonus == ICE_BONUS) + return true; } - set_bonus(type, animate); + return set_bonus(type, animate); } -void +bool Player::set_bonus(BonusType type, bool animate) { if(player_status->bonus == NO_BONUS) { - if (!adjust_height(62.8)) return; + if (!adjust_height(62.8)) { + printf("can't adjust\n"); + return false; + } if(animate) growing_timer.start(GROWING_TIME); } @@ -747,6 +739,7 @@ Player::set_bonus(BonusType type, bool animate) if (type == ICE_BONUS) player_status->max_ice_bullets++; player_status->bonus = type; + return true; } void @@ -910,8 +903,36 @@ Player::collision_tile(uint32_t tile_attributes) kill(false); } +void +Player::collision_solid(const CollisionHit& hit) +{ + if(hit.bottom) { + if(physic.get_velocity_y() > 0) + physic.set_velocity_y(0); + + on_ground_flag = true; + floor_normal = hit.slope_normal; + } else if(hit.top) { + if(physic.get_velocity_y() < 0) + physic.set_velocity_y(.2); + } + + if(hit.left || hit.right) { + physic.set_velocity_x(0); + } + + // crushed? + if(hit.crush) { + if(hit.left || hit.right) { + kill(true); + } else if(hit.top || hit.bottom) { + kill(false); + } + } +} + HitResponse -Player::collision(GameObject& other, const CollisionHit& hit) +Player::collision(GameObject& other, const CollisionHit& ) { Bullet* bullet = dynamic_cast (&other); if(bullet) { @@ -923,76 +944,12 @@ Player::collision(GameObject& other, const CollisionHit& hit) assert(portable != NULL); if(portable && grabbed_object == NULL && controller->hold(Controller::ACTION) - && fabsf(hit.normal.x) > .9) { + /*&& fabsf(hit.normal.x) > .9*/) { grabbed_object = portable; grabbed_object->grab(*this, get_pos(), dir); return CONTINUE; } } - - if(other.get_flags() & FLAG_SOLID) { - /* - printf("Col %p: HN: %3.1f %3.1f D %.1f P: %3.1f %3.1f M: %3.1f %3.1f\n", - &other, - hit.normal.x, hit.normal.y, hit.depth, - get_pos().x, get_pos().y, - movement.x, movement.y); - */ - - if(hit.normal.y < 0) { // landed on floor? - if(physic.get_velocity_y() > 0) - physic.set_velocity_y(0); - - on_ground_flag = true; - - // remember normal of this tile - if (hit.normal.y > -0.9) { - floor_normal.x = hit.normal.x; - floor_normal.y = hit.normal.y; - } else { - // slowly adjust to unisolid tiles. - // Necessary because our bounding box sometimes reaches through slopes and thus hits unisolid tiles - floor_normal.x = (floor_normal.x * 0.9) + (hit.normal.x * 0.1); - floor_normal.y = (floor_normal.y * 0.9) + (hit.normal.y * 0.1); - } - - // hack platforms so that we stand normally on them when going down... - Platform* platform = dynamic_cast (&other); - if(platform != NULL) { - if(platform->get_speed().y > 0) - physic.set_velocity_y(platform->get_speed().y); - //physic.set_velocity_x(platform->get_speed().x); - } - } else if(hit.normal.y > 0) { // bumped against the roof - physic.set_velocity_y(-.1); - - // hack platform so that we are not glued to it from below - Platform* platform = dynamic_cast (&other); - if(platform != NULL) { - physic.set_velocity_y(platform->get_speed().y); - } - } - - if(fabsf(hit.normal.x) > .9) { // hit on the side? - physic.set_velocity_x(0); - } - - MovingObject* omov = dynamic_cast (&other); - if(omov != NULL) { - Vector mov = movement - omov->get_movement(); - /* - printf("W %p - HITN: %3.1f %3.1f D:%3.1f TM: %3.1f %3.1f TD: %3.1f %3.1f PM: %3.2f %3.1f\n", - omov, - hit.normal.x, hit.normal.y, - hit.depth, - movement.x, movement.y, - dest.p1.x, dest.p1.y, - omov->get_movement().x, omov->get_movement().y); - */ - } - - return CONTINUE; - } #ifdef DEBUG assert(dynamic_cast (&other) != NULL); diff --git a/src/object/player.hpp b/src/object/player.hpp index b7fb3ac26..bab2bc544 100644 --- a/src/object/player.hpp +++ b/src/object/player.hpp @@ -135,6 +135,7 @@ public: virtual void update(float elapsed_time); virtual void draw(DrawingContext& context); + virtual void collision_solid(const CollisionHit& hit); virtual HitResponse collision(GameObject& other, const CollisionHit& hit); virtual void collision_tile(uint32_t tile_attributes); @@ -156,10 +157,21 @@ public: void check_bounds(Camera* camera); void move(const Vector& vector); - virtual void add_bonus(const std::string& bonus); + virtual bool add_bonus(const std::string& bonus); virtual void add_coins(int count); - void add_bonus(BonusType type, bool animate = false); /**< picks up a bonus, taking care not to pick up lesser bonus items than we already have */ - void set_bonus(BonusType type, bool animate = false); /**< like add_bonus, but can also downgrade the bonus items carried */ + + /** + * picks up a bonus, taking care not to pick up lesser bonus items than we already have + * + * @returns true if the bonus has been set (or was already good enough) + * false if the bonus could not be set (for example no space for big tux) + */ + bool add_bonus(BonusType type, bool animate = false); + /** + * like add_bonus, but can also downgrade the bonus items carried + */ + bool set_bonus(BonusType type, bool animate = false); + PlayerStatus* get_status() { return player_status; @@ -264,6 +276,7 @@ private: Sprite* smalltux_gameover; Sprite* smalltux_star; Sprite* bigtux_star; + Vector floor_normal; bool ghost_mode; /**< indicates if Tux should float around and through solid objects */ diff --git a/src/object/powerup.cpp b/src/object/powerup.cpp index ebced415c..b865ba81b 100644 --- a/src/object/powerup.cpp +++ b/src/object/powerup.cpp @@ -31,7 +31,7 @@ #include "log.hpp" PowerUp::PowerUp(const lisp::Lisp& lisp) - : MovingSprite(lisp, LAYER_OBJECTS, COLGROUP_MOVING) + : MovingSprite(lisp, LAYER_OBJECTS, COLGROUP_MOVING) { lisp.get("script", script); no_physics = false; @@ -41,43 +41,47 @@ PowerUp::PowerUp(const lisp::Lisp& lisp) sound_manager->preload("sounds/fire-flower.wav"); } -HitResponse -PowerUp::collision(GameObject& other, const CollisionHit& hit) +void +PowerUp::collision_solid(const CollisionHit& hit) { - if(other.get_flags() & FLAG_SOLID) { - if(fabsf(hit.normal.y) > .5) { // roof or ground - physic.set_velocity_y(0); - } else { // bumped left or right - physic.set_velocity_x(-physic.get_velocity_x()); - } - - return CONTINUE; + if(hit.bottom) { + physic.set_velocity_y(0); } - + if(hit.right || hit.left) { + physic.set_velocity_x(-physic.get_velocity_x()); + } +} + +HitResponse +PowerUp::collision(GameObject& other, const CollisionHit&) +{ Player* player = dynamic_cast(&other); if(player == 0) return FORCE_MOVE; - remove_me(); - if (script != "") { std::istringstream stream(script); Sector::current()->run_script(stream, "powerup-script"); + remove_me(); return ABORT_MOVE; } // some defaults if no script has been set if (sprite_name == "images/powerups/egg/egg.sprite") { - player->add_bonus(GROWUP_BONUS, true); + if(!player->add_bonus(GROWUP_BONUS, true)) + return FORCE_MOVE; sound_manager->play("sounds/grow.wav"); } else if (sprite_name == "images/powerups/fireflower/fireflower.sprite") { - player->add_bonus(FIRE_BONUS, true); + if(!player->add_bonus(FIRE_BONUS, true)) + return FORCE_MOVE; sound_manager->play("sounds/fire-flower.wav"); } else if (sprite_name == "images/powerups/star/star.sprite") { player->make_invincible(); } else if (sprite_name == "images/powerups/1up/1up.sprite") { player->get_status()->add_coins(100); } + + remove_me(); return ABORT_MOVE; } diff --git a/src/object/powerup.hpp b/src/object/powerup.hpp index 59922a722..04ccb35c7 100644 --- a/src/object/powerup.hpp +++ b/src/object/powerup.hpp @@ -29,9 +29,9 @@ class PowerUp : public MovingSprite { public: PowerUp(const lisp::Lisp& lisp); - virtual PowerUp* clone() const { return new PowerUp(*this); } virtual void update(float elapsed_time); + virtual void collision_solid(const CollisionHit& hit); virtual HitResponse collision(GameObject& other, const CollisionHit& hit); private: diff --git a/src/object/rock.cpp b/src/object/rock.cpp index 6ba11fcfd..1ffa23167 100644 --- a/src/object/rock.cpp +++ b/src/object/rock.cpp @@ -26,7 +26,7 @@ #include "object_factory.hpp" Rock::Rock(const lisp::Lisp& reader) - : MovingSprite(reader, "images/objects/rock/rock.sprite", LAYER_OBJECTS+1, COLGROUP_MOVING) + : MovingSprite(reader, "images/objects/rock/rock.sprite", LAYER_OBJECTS+1, COLGROUP_STATIC) { grabbed = false; flags |= FLAG_SOLID | FLAG_PORTABLE; @@ -48,7 +48,7 @@ Rock::update(float elapsed_time) { if(!grabbed) { flags |= FLAG_SOLID; - set_group(COLGROUP_MOVING); + set_group(COLGROUP_STATIC); movement = physic.get_movement(elapsed_time); } else { physic.set_velocity(0, 0); @@ -64,19 +64,20 @@ Rock::update(float elapsed_time) */ } +void +Rock::collision_solid(const CollisionHit& ) +{ + physic.set_velocity(0, 0); +} + HitResponse -Rock::collision(GameObject& object, const CollisionHit& ) +Rock::collision(GameObject& , const CollisionHit& ) { if(grabbed) { - return FORCE_MOVE; - } - - if(object.get_flags() & FLAG_SOLID) { - physic.set_velocity(0, 0); - return CONTINUE; + return PASSTHROUGH; } - return FORCE_MOVE; + return SOLID; } void diff --git a/src/object/rock.hpp b/src/object/rock.hpp index ad4bebc08..207095e78 100644 --- a/src/object/rock.hpp +++ b/src/object/rock.hpp @@ -34,6 +34,7 @@ public: Rock(const lisp::Lisp& reader); virtual Rock* clone() const { return new Rock(*this); } + void collision_solid(const CollisionHit& hit); HitResponse collision(GameObject& other, const CollisionHit& hit); void update(float elapsed_time); void write(lisp::Writer& writer); diff --git a/src/object/scripted_object.cpp b/src/object/scripted_object.cpp index ba0d114c4..90875f2c9 100644 --- a/src/object/scripted_object.cpp +++ b/src/object/scripted_object.cpp @@ -16,7 +16,6 @@ // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - #include #include @@ -179,30 +178,27 @@ ScriptedObject::draw(DrawingContext& context) sprite->draw(context, get_pos(), layer); } -HitResponse -ScriptedObject::collision(GameObject& other, const CollisionHit& hit) +void +ScriptedObject::collision_solid(const CollisionHit& hit) { if(!physic_enabled) - return FORCE_MOVE; - - if(!(other.get_flags() & FLAG_SOLID)) - return FORCE_MOVE; - - if(other.get_flags() & FLAG_SOLID) { - if(hit.normal.y < 0) { // landed on floor - if(physic.get_velocity_y() > 0) - physic.set_velocity_y(0); - } else if(hit.normal.y > 0) { // bumped against roof - physic.set_velocity_y(.1); - } - - if(fabsf(hit.normal.x) > .9) { // hit on side? - physic.set_velocity_x(0); - } - - return CONTINUE; + return; + + if(hit.bottom) { + if(physic.get_velocity_y() > 0) + physic.set_velocity_y(0); + } else if(hit.top) { + physic.set_velocity_y(.1); } + if(hit.left || hit.right) { + physic.set_velocity_x(0); + } +} + +HitResponse +ScriptedObject::collision(GameObject& , const CollisionHit& ) +{ return FORCE_MOVE; } diff --git a/src/object/scripted_object.hpp b/src/object/scripted_object.hpp index 2243e3e43..7231d3d24 100644 --- a/src/object/scripted_object.hpp +++ b/src/object/scripted_object.hpp @@ -39,6 +39,8 @@ public: void update(float elapsed_time); void draw(DrawingContext& context); + + void collision_solid(const CollisionHit& hit); HitResponse collision(GameObject& other, const CollisionHit& hit); // --- Scripting Interface stuff --- diff --git a/src/object/skull_tile.cpp b/src/object/skull_tile.cpp index c4c36b146..abbddd816 100644 --- a/src/object/skull_tile.cpp +++ b/src/object/skull_tile.cpp @@ -38,11 +38,8 @@ SkullTile::SkullTile(const lisp::Lisp& lisp) } HitResponse -SkullTile::collision(GameObject& other, const CollisionHit& hitdata) +SkullTile::collision(GameObject& other, const CollisionHit& ) { - if(hitdata.normal.y < 0.8) - return FORCE_MOVE; - Player* player = dynamic_cast (&other); if(player) hit = true; diff --git a/src/object/star.cpp b/src/object/star.cpp index e6ef93461..e6fff5d3f 100644 --- a/src/object/star.cpp +++ b/src/object/star.cpp @@ -42,21 +42,21 @@ Star::update(float elapsed_time) movement = physic.get_movement(elapsed_time); } -HitResponse -Star::collision(GameObject& other, const CollisionHit& hit) +void +Star::collision_solid(const CollisionHit& hit) { - if(other.get_flags() & FLAG_SOLID) { - if(hit.normal.y < -.5) { // ground - physic.set_velocity_y(JUMPSPEED); - } else if(hit.normal.y > .5) { // roof - physic.set_velocity_y(0); - } else { // bumped left or right - physic.set_velocity_x(-physic.get_velocity_x()); - } - - return CONTINUE; + if(hit.bottom) { + physic.set_velocity_y(JUMPSPEED); + } else if(hit.top) { + physic.set_velocity_y(0); + } else if(hit.left || hit.right) { + physic.set_velocity_x(-physic.get_velocity_x()); } - +} + +HitResponse +Star::collision(GameObject& other, const CollisionHit& ) +{ Player* player = dynamic_cast (&other); if(player) { player->make_invincible(); diff --git a/src/object/star.hpp b/src/object/star.hpp index d0eed7c53..fc01922b1 100644 --- a/src/object/star.hpp +++ b/src/object/star.hpp @@ -30,6 +30,7 @@ public: virtual Star* clone() const { return new Star(*this); } virtual void update(float elapsed_time); + virtual void collision_solid(const CollisionHit& hit); virtual HitResponse collision(GameObject& other, const CollisionHit& hit); private: diff --git a/src/object/unstable_tile.cpp b/src/object/unstable_tile.cpp index 1d0895846..9780c7395 100644 --- a/src/object/unstable_tile.cpp +++ b/src/object/unstable_tile.cpp @@ -34,35 +34,20 @@ UnstableTile::UnstableTile(const lisp::Lisp& lisp) : MovingSprite(lisp, LAYER_TILES, COLGROUP_STATIC), state(STATE_NORMAL) { sprite->set_action("normal"); - flags |= FLAG_SOLID; } HitResponse -UnstableTile::collision(GameObject& other, const CollisionHit& hit) +UnstableTile::collision(GameObject& other, const CollisionHit& ) { - switch (state) { - - case STATE_NORMAL: - if ((hit.normal.y >= 0.8 ) && (dynamic_cast(&other))) { - state = STATE_CRUMBLING; - sprite->set_action("crumbling", 1); - return FORCE_MOVE; - } - return FORCE_MOVE; - break; - - case STATE_CRUMBLING: - return FORCE_MOVE; - break; - - case STATE_DISINTEGRATING: - return FORCE_MOVE; - break; - + if(state == STATE_NORMAL) { + Player* player = dynamic_cast (&other); + if(player != NULL && + player->get_bbox().get_bottom() < get_bbox().get_top() + 7.0) { + state = STATE_CRUMBLING; + sprite->set_action("crumbling", 1); + } } - - log_debug << "unhandled state" << std::endl; - return FORCE_MOVE; + return SOLID; } void @@ -90,7 +75,6 @@ UnstableTile::update(float elapsed_time) return; } break; - } } diff --git a/src/object/weak_block.hpp b/src/object/weak_block.hpp index 2a081795f..0ff0b91d9 100644 --- a/src/object/weak_block.hpp +++ b/src/object/weak_block.hpp @@ -1,4 +1,4 @@ -// $Id: weak_block.hpp 3327 2006-04-13 15:02:40Z ravu_al_hemio $ +// $Id$ // // SuperTux - Weak Block // Copyright (C) 2006 Matthias Braun @@ -33,7 +33,6 @@ class WeakBlock : public MovingSprite { public: WeakBlock(const lisp::Lisp& lisp); - virtual WeakBlock* clone() const { return new WeakBlock(*this); } HitResponse collision(GameObject& other, const CollisionHit& hit); void update(float elapsed_time); diff --git a/src/scripting/player.hpp b/src/scripting/player.hpp index 45f3d849d..d90784c16 100644 --- a/src/scripting/player.hpp +++ b/src/scripting/player.hpp @@ -35,7 +35,7 @@ public: * Set tux bonus. * This can be "grow", "fireflower" or "iceflower" at the moment */ - virtual void add_bonus(const std::string& bonus) = 0; + virtual bool add_bonus(const std::string& bonus) = 0; /** * Give tux more coins */ diff --git a/src/scripting/wrapper.cpp b/src/scripting/wrapper.cpp index 529d8897d..a175623f7 100644 --- a/src/scripting/wrapper.cpp +++ b/src/scripting/wrapper.cpp @@ -1060,9 +1060,10 @@ static SQInteger Player_add_bonus_wrapper(HSQUIRRELVM vm) } try { - _this->add_bonus(arg0); + bool return_value = _this->add_bonus(arg0); - return 0; + sq_pushbool(vm, return_value); + return 1; } catch(std::exception& e) { sq_throwerror(vm, e.what()); diff --git a/src/sector.cpp b/src/sector.cpp index f0463d80a..6a152e6b0 100644 --- a/src/sector.cpp +++ b/src/sector.cpp @@ -26,9 +26,10 @@ #include #include #include +#include #include "sector.hpp" -#include "player_status.hpp" +#include "object/player.hpp" #include "object/gameobjs.hpp" #include "object/camera.hpp" #include "object/background.hpp" @@ -45,8 +46,6 @@ #include "game_session.hpp" #include "resources.hpp" #include "statistics.hpp" -#include "collision_grid.hpp" -#include "collision_grid_iterator.hpp" #include "object_factory.hpp" #include "collision.hpp" #include "spawn_point.hpp" @@ -77,10 +76,6 @@ Sector::Sector(Level* parent) add_object(new DisplayEffect()); add_object(new TextObject()); -#ifdef USE_GRID - grid.reset(new CollisionGrid(32000, 32000)); -#endif - // create a new squirrel table for the sector using namespace Scripting; @@ -555,15 +550,6 @@ Sector::update(float elapsed_time) { player->check_bounds(camera); -#if 0 - CollisionGridIterator iter(*grid, get_active_region()); - while(MovingObject* object = iter.next()) { - if(!object->is_valid()) - continue; - - object->update(elapsed_time); - } -#else /* update objects */ for(GameObjects::iterator i = gameobjects.begin(); i != gameobjects.end(); ++i) { @@ -573,7 +559,6 @@ Sector::update(float elapsed_time) object->update(elapsed_time); } -#endif /* Handle all possible collisions. */ handle_collisions(); @@ -602,10 +587,6 @@ Sector::update_game_objects() continue; } -#ifdef USE_GRID - grid->remove_object(moving_object); -#endif - i = moving_objects.erase(i); } for(std::vector::iterator i = gameobjects.begin(); @@ -646,9 +627,6 @@ Sector::before_object_add(GameObject* object) MovingObject* movingobject = dynamic_cast (object); if(movingobject) { moving_objects.push_back(movingobject); -#ifdef USE_GRID - grid->add_object(movingobject); -#endif } TileMap* tilemap = dynamic_cast (object); @@ -757,11 +735,82 @@ Sector::draw(DrawingContext& context) context.pop_transform(); } +/*------------------------------------------------------------------------- + * Collision Detection + *-------------------------------------------------------------------------*/ + +static const float SHIFT_DELTA = 7.0f; + +/** r1 is supposed to be moving, r2 a solid object */ +void check_collisions(collision::Constraints* constraints, + const Vector& movement, const Rect& r1, const Rect& r2, + GameObject* object = NULL, MovingObject* other = NULL) +{ + if(!collision::intersects(r1, r2)) + return; + + // calculate intersection + float itop = r1.get_bottom() - r2.get_top(); + float ibottom = r2.get_bottom() - r1.get_top(); + float ileft = r1.get_right() - r2.get_left(); + float iright = r2.get_right() - r1.get_left(); + + if(fabsf(movement.y) > fabsf(movement.x)) { + if(ileft < SHIFT_DELTA) { + constraints->right = std::min(constraints->right, r2.get_left()); + return; + } else if(iright < SHIFT_DELTA) { + constraints->left = std::max(constraints->left, r2.get_right()); + return; + } + } else { + // shiftout bottom/top + if(itop < SHIFT_DELTA) { + constraints->bottom = std::min(constraints->bottom, r2.get_top()); + return; + } else if(ibottom < SHIFT_DELTA) { + constraints->top = std::max(constraints->top, r2.get_bottom()); + return; + } + } + + if(other != NULL) { + CollisionHit dummy; + HitResponse response = other->collision(*object, dummy); + if(response == PASSTHROUGH) + return; + if(other->get_movement() != Vector(0, 0)) { + // TODO what todo when we collide with 2 moving objects?!? + constraints->ground_movement = other->get_movement(); + } + } + + float vert_penetration = std::min(itop, ibottom); + float horiz_penetration = std::min(ileft, iright); + if(vert_penetration < horiz_penetration) { + if(itop < ibottom) { + constraints->bottom = std::min(constraints->bottom, r2.get_top()); + constraints->hit.bottom = true; + } else { + constraints->top = std::max(constraints->top, r2.get_bottom()); + constraints->hit.top = true; + } + } else { + if(ileft < iright) { + constraints->right = std::min(constraints->right, r2.get_left()); + constraints->hit.right = true; + } else { + constraints->left = std::max(constraints->left, r2.get_right()); + constraints->hit.left = true; + } + } +} + static const float DELTA = .001; void -Sector::collision_tilemap(const Rect& dest, const Vector& movement, - CollisionHit& hit) const +Sector::collision_tilemap(collision::Constraints* constraints, + const Vector& movement, const Rect& dest) const { // calculate rectangle where the object will move float x1 = dest.get_left(); @@ -772,22 +821,21 @@ Sector::collision_tilemap(const Rect& dest, const Vector& movement, // test with all tiles in this rectangle int starttilex = int(x1) / 32; int starttiley = int(y1) / 32; - int max_x = int(x2 + (1 - DELTA)); - int max_y = int(y2 + (1 - DELTA)); + int max_x = int(x2); + int max_y = int(y2+1); - CollisionHit temphit; for(int x = starttilex; x*32 < max_x; ++x) { for(int y = starttiley; y*32 < max_y; ++y) { const Tile* tile = solids->get_tile(x, y); if(!tile) continue; // skip non-solid tiles - if(tile->getAttributes() == 0) + if((tile->getAttributes() & Tile::SOLID) == 0) continue; // only handle unisolid when the player is falling down and when he was // above the tile before if(tile->getAttributes() & Tile::UNISOLID) { - if(movement.y <= 0 || dest.get_top() - movement.y > y*32) + if(movement.y <= 0 || dest.get_bottom() - movement.y - SHIFT_DELTA > y*32) continue; } @@ -797,19 +845,10 @@ Sector::collision_tilemap(const Rect& dest, const Vector& movement, Vector p2((x+1)*32, (y+1)*32); triangle = AATriangle(p1, p2, tile->getData()); - if(Collision::rectangle_aatriangle(temphit, dest, movement, - triangle)) { - if(temphit.time > hit.time && (tile->getAttributes() & Tile::SOLID)) { - hit = temphit; - } - } + collision::rectangle_aatriangle(constraints, dest, triangle); } else { // normal rectangular tile Rect rect(x*32, y*32, (x+1)*32, (y+1)*32); - if(Collision::rectangle_rectangle(temphit, dest, movement, rect)) { - if(temphit.time > hit.time && (tile->getAttributes() & Tile::SOLID)) { - hit = temphit; - } - } + check_collisions(constraints, movement, dest, rect); } } } @@ -842,99 +881,84 @@ Sector::collision_tile_attributes(const Rect& dest) const return result; } +/** fills in CollisionHit and Normal vector of 2 intersecting rectangle */ +static void get_hit_normal(const Rect& r1, const Rect& r2, CollisionHit& hit, + Vector& normal) +{ + float itop = r1.get_bottom() - r2.get_top(); + float ibottom = r2.get_bottom() - r1.get_top(); + float ileft = r1.get_right() - r2.get_left(); + float iright = r2.get_right() - r1.get_left(); + + float vert_penetration = std::min(itop, ibottom); + float horiz_penetration = std::min(ileft, iright); + if(vert_penetration < horiz_penetration) { + if(itop < ibottom) { + hit.bottom = true; + normal.y = vert_penetration; + } else { + hit.top = true; + normal.y = -vert_penetration; + } + } else { + if(ileft < iright) { + hit.right = true; + normal.x = horiz_penetration; + } else { + hit.left = true; + normal.x = -horiz_penetration; + } + } +} + void Sector::collision_object(MovingObject* object1, MovingObject* object2) const { + using namespace collision; + + const Rect& r1 = object1->dest; + const Rect& r2 = object2->dest; + CollisionHit hit; + if(intersects(object1->dest, object2->dest)) { + Vector normal; + get_hit_normal(r1, r2, hit, normal); - Vector movement = object1->get_movement() - object2->get_movement(); - if(Collision::rectangle_rectangle(hit, object1->dest, movement, object2->dest)) { HitResponse response1 = object1->collision(*object2, hit); - hit.normal *= -1; HitResponse response2 = object2->collision(*object1, hit); - - if(response1 != CONTINUE) { - if(response1 == ABORT_MOVE) - object1->dest = object1->get_bbox(); - if(response2 == CONTINUE) - object2->dest.move(hit.normal * (hit.depth + DELTA)); - } else if(response2 != CONTINUE) { - if(response2 == ABORT_MOVE) - object2->dest = object2->get_bbox(); - if(response1 == CONTINUE) - object1->dest.move(-hit.normal * (hit.depth + DELTA)); - } else { - object1->dest.move(-hit.normal * (hit.depth/2 + DELTA)); - object2->dest.move(hit.normal * (hit.depth/2 + DELTA)); + if(response1 == CONTINUE || response2 == CONTINUE) { + normal *= (0.5 + DELTA); + object1->dest.move(-normal); + object2->dest.move(normal); } } } -bool -Sector::collision_static(MovingObject* object, const Vector& movement) +void +Sector::collision_static(collision::Constraints* constraints, + const Vector& movement, const Rect& dest, + GameObject& object) { - GameObject* collided_with = solids; - CollisionHit hit; - hit.time = -1; - - collision_tilemap(object->dest, movement, hit); + collision_tilemap(constraints, movement, dest); // collision with other (static) objects - CollisionHit temphit; - for(MovingObjects::iterator i2 = moving_objects.begin(); - i2 != moving_objects.end(); ++i2) { - MovingObject* moving_object_2 = *i2; - if(moving_object_2->get_group() != COLGROUP_STATIC - || !moving_object_2->is_valid()) + for(MovingObjects::iterator i = moving_objects.begin(); + i != moving_objects.end(); ++i) { + MovingObject* moving_object = *i; + if(moving_object->get_group() != COLGROUP_STATIC + || !moving_object->is_valid()) continue; - - Rect dest = moving_object_2->dest; - - Vector rel_movement - = movement - moving_object_2->get_movement(); - - if(Collision::rectangle_rectangle(temphit, object->dest, rel_movement, dest) - && temphit.time > hit.time) { - hit = temphit; - collided_with = moving_object_2; - } - } - - if(hit.time < 0) - return true; - - HitResponse response = object->collision(*collided_with, hit); - hit.normal *= -1; - if(collided_with != solids) { - MovingObject* moving_object = (MovingObject*) collided_with; - HitResponse other_response = moving_object->collision(*object, hit); - if(other_response == ABORT_MOVE) { - moving_object->dest = moving_object->get_bbox(); - } else if(other_response == FORCE_MOVE) { - // the static object "wins" move tux out of the collision - object->dest.move(-hit.normal * (hit.depth + DELTA)); - return false; - } else if(other_response == PASS_MOVEMENT) { - object->dest.move(moving_object->get_movement()); - //object->movement += moving_object->get_movement(); - } - } - - if(response == CONTINUE) { - object->dest.move(-hit.normal * (hit.depth + DELTA)); - return false; - } else if(response == ABORT_MOVE) { - object->dest = object->get_bbox(); - return true; - } - // force move - return false; + check_collisions(constraints, movement, dest, moving_object->dest, + &object, moving_object); + } } void Sector::handle_collisions() { + using namespace collision; + // calculate destination positions of the objects for(MovingObjects::iterator i = moving_objects.begin(); i != moving_objects.end(); ++i) { @@ -945,8 +969,6 @@ Sector::handle_collisions() } // part1: COLGROUP_MOVING vs COLGROUP_STATIC and tilemap - // we do this up to 4 times and have to sort all results for the smallest - // one before we can continue here for(MovingObjects::iterator i = moving_objects.begin(); i != moving_objects.end(); ++i) { MovingObject* moving_object = *i; @@ -955,39 +977,86 @@ Sector::handle_collisions() || !moving_object->is_valid()) continue; + Constraints constraints; Vector movement = moving_object->get_movement(); - - // test if x or y movement is dominant - if(fabsf(moving_object->get_movement().x) < fabsf(moving_object->get_movement().y)) { - - // test in x direction first, then y direction - moving_object->dest.move(Vector(0, -movement.y)); - for(int i = 0; i < 2; ++i) { - bool res = collision_static(moving_object, Vector(movement.x, 0)); - if(res) - break; + Rect& dest = moving_object->dest; + float owidth = moving_object->get_bbox().get_width(); + float oheight = moving_object->get_bbox().get_height(); + + for(int i = 0; i < 2; ++i) { + collision_static(&constraints, Vector(0, movement.y), dest, *moving_object); + if(!constraints.has_constraints()) + break; + + // apply calculated horizontal constraints + if(constraints.bottom < INFINITY) { + float height = constraints.bottom - constraints.top; + if(height < oheight) { + // we're crushed, but ignore this for now, we'll get this again + // later if we're really crushed or things will solve itself when + // looking at the vertical constraints + } + dest.p2.y = constraints.bottom - DELTA; + dest.p1.y = dest.p2.y - oheight; + } else if(constraints.top > -INFINITY) { + dest.p1.y = constraints.top + DELTA; + dest.p2.y = dest.p1.y + oheight; } - moving_object->dest.move(Vector(0, movement.y)); - for(int i = 0; i < 2; ++i) { - bool res = collision_static(moving_object, Vector(0, movement.y)); - if(res) - break; + } + if(constraints.has_constraints()) { + if(constraints.hit.bottom) { + dest.move(constraints.ground_movement); } - - } else { + if(constraints.hit.top || constraints.hit.bottom) { + constraints.hit.left = false; + constraints.hit.right = false; + moving_object->collision_solid(constraints.hit); + } + } - // test in y direction first, then x direction - moving_object->dest.move(Vector(-movement.x, 0)); - for(int i = 0; i < 2; ++i) { - bool res = collision_static(moving_object, Vector(0, movement.y)); - if(res) - break; + constraints = Constraints(); + for(int i = 0; i < 2; ++i) { + collision_static(&constraints, movement, dest, *moving_object); + if(!constraints.has_constraints()) + break; + + // apply calculated vertical constraints + if(constraints.right < INFINITY) { + float width = constraints.right - constraints.left; + if(width + SHIFT_DELTA < owidth) { + printf("Object %p crushed horizontally... L:%f R:%f\n", moving_object, + constraints.left, constraints.right); + CollisionHit h; + h.left = true; + h.right = true; + h.crush = true; + moving_object->collision_solid(h); + } else { + dest.p2.x = constraints.right - DELTA; + dest.p1.x = dest.p2.x - owidth; + } + } else if(constraints.left > -INFINITY) { + dest.p1.x = constraints.left + DELTA; + dest.p2.x = dest.p1.x + owidth; } - moving_object->dest.move(Vector(movement.x, 0)); - for(int i = 0; i < 2; ++i) { - bool res = collision_static(moving_object, Vector(movement.x, 0)); - if(res) - break; + } + + if(constraints.has_constraints()) { + moving_object->collision_solid(constraints.hit); + } + + // an extra pass to make sure we're not crushed horizontally + constraints = Constraints(); + collision_static(&constraints, movement, dest, *moving_object); + if(constraints.bottom < INFINITY) { + float height = constraints.bottom - constraints.top; + if(height + SHIFT_DELTA < oheight) { + printf("Object %p crushed vertically...\n", moving_object); + CollisionHit h; + h.top = true; + h.bottom = true; + h.crush = true; + moving_object->collision_solid(h); } } } @@ -1022,7 +1091,14 @@ Sector::handle_collisions() || !moving_object_2->is_valid()) continue; - collision_object(moving_object, moving_object_2); + if(intersects(moving_object->dest, moving_object_2->dest)) { + Vector normal; + CollisionHit hit; + get_hit_normal(moving_object->dest, moving_object_2->dest, + hit, normal); + moving_object->collision(*moving_object_2, hit); + moving_object_2->collision(*moving_object, hit); + } } } @@ -1059,6 +1135,8 @@ Sector::handle_collisions() bool Sector::is_free_space(const Rect& rect) const { + using namespace collision; + // test with all tiles in this rectangle int starttilex = int(rect.p1.x) / 32; int starttiley = int(rect.p1.y) / 32; @@ -1082,7 +1160,7 @@ Sector::is_free_space(const Rect& rect) const || !moving_object->is_valid()) continue; - if(Collision::intersects(rect, moving_object->get_bbox())) + if(intersects(rect, moving_object->get_bbox())) return false; } @@ -1095,17 +1173,9 @@ Sector::add_bullet(const Vector& pos, float xm, Direction dir) // TODO remove this function and move these checks elsewhere... Bullet* new_bullet = 0; - if(player_status->bonus == FIRE_BONUS) { - if((int)bullets.size() >= player_status->max_fire_bullets) - return false; - new_bullet = new Bullet(pos, xm, dir, FIRE_BULLET); - } else if(player_status->bonus == ICE_BONUS) { - if((int)bullets.size() >= player_status->max_ice_bullets) - return false; - new_bullet = new Bullet(pos, xm, dir, ICE_BULLET); - } else { + if((int)bullets.size() >= player_status->max_fire_bullets) return false; - } + new_bullet = new Bullet(pos, xm, dir); add_object(new_bullet); sound_manager->play("sounds/shoot.wav"); @@ -1121,12 +1191,6 @@ Sector::add_smoke_cloud(const Vector& pos) } void -Sector::add_floating_text(const Vector& pos, const std::string& text) -{ - add_object(new FloatingText(pos, text)); -} - -void Sector::play_music(MusicType type) { currentmusic = type; diff --git a/src/sector.hpp b/src/sector.hpp index b2ee2199e..0ed2f4c17 100644 --- a/src/sector.hpp +++ b/src/sector.hpp @@ -32,6 +32,9 @@ namespace lisp { class Lisp; class Writer; } +namespace collision { +class Constraints; +} class Rect; class Sprite; @@ -40,7 +43,6 @@ class Player; class Camera; class TileMap; class Bullet; -class CollisionGrid; class ScriptInterpreter; class SpawnPoint; class MovingObject; @@ -107,8 +109,7 @@ public: bool add_bullet(const Vector& pos, float xm, Direction dir); bool add_smoke_cloud(const Vector& pos); - void add_floating_text(const Vector& pos, const std::string& text); - + /** get currently activated sector. */ static Sector* current() { return _current; } @@ -126,7 +127,8 @@ public: return total; } - void collision_tilemap(const Rect& dest, const Vector& movement, CollisionHit& hit) const; + void collision_tilemap(collision::Constraints* constraints, + const Vector& movement, const Rect& dest) const; /** Checks if at the specified rectangle are gameobjects with STATIC flag set * (or solid tiles from the tilemap). @@ -177,8 +179,8 @@ private: * returns true if the collision detection should be aborted for this object * (because of ABORT_MOVE in the collision response or no collisions) */ - bool collision_static(MovingObject* object, const Vector& movement); - + void collision_static(collision::Constraints* constraints, + const Vector& movement, const Rect& dest, GameObject& object); GameObject* parse_object(const std::string& name, const lisp::Lisp& lisp); @@ -197,8 +199,6 @@ private: MusicType currentmusic; - std::auto_ptr grid; - HSQOBJECT sector_table; /// sector scripts typedef std::vector ScriptList;