Strawboxes glow when burning in the dark
[supertux.git] / src / object / weak_block.cpp
1 //  SuperTux - Weak Block
2 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
3 //  Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.de>
4 //
5 //  This program is free software: you can redistribute it and/or modify
6 //  it under the terms of the GNU General Public License as published by
7 //  the Free Software Foundation, either version 3 of the License, or
8 //  (at your option) any later version.
9 //
10 //  This program is distributed in the hope that it will be useful,
11 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //  GNU General Public License for more details.
14 //
15 //  You should have received a copy of the GNU General Public License
16 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18 #include "object/weak_block.hpp"
19
20 #include "math/random_generator.hpp"
21 #include "object/bullet.hpp"
22 #include "object/explosion.hpp"
23 #include "supertux/object_factory.hpp"
24 #include "supertux/sector.hpp"
25 #include "sprite/sprite.hpp"
26 #include "sprite/sprite_manager.hpp"
27 #include "util/reader.hpp"
28
29 #include <math.h>
30
31 WeakBlock::WeakBlock(const Reader& lisp)
32 : MovingSprite(lisp, "images/objects/weak_block/strawbox.sprite", LAYER_TILES, COLGROUP_STATIC), state(STATE_NORMAL),
33   linked(true),
34   light(0.0f,0.0f,0.0f),
35   lightsprite(sprite_manager->create("images/objects/lightmap_light/lightmap_light-small.sprite"))
36 {
37   sprite->set_action("normal");
38   //Check if this weakblock destroys adjacent weakblocks
39   if(lisp.get("linked", linked)){
40     if(! linked){
41       sprite_name = "images/objects/weak_block/meltbox.sprite";
42       sprite = sprite_manager->create(sprite_name);
43       sprite->set_action("normal");
44     }
45   }
46   lightsprite->set_blend(Blend(GL_SRC_ALPHA, GL_ONE));
47   lightsprite->set_color(Color(0.3f, 0.2f, 0.1f));
48 }
49
50 HitResponse
51 WeakBlock::collision_bullet(Bullet& bullet, const CollisionHit& hit)
52 {
53   switch (state) {
54                         
55     case STATE_NORMAL:
56       //Ensure only fire destroys weakblock
57       if(bullet.get_type() == FIRE_BONUS) {
58         startBurning();
59         bullet.remove_me();
60       }
61       //Other bullets ricochet
62       else {
63         bullet.ricochet(*this, hit);
64       }
65     break;
66                         
67     case STATE_BURNING:
68     case STATE_DISINTEGRATING:
69       break;
70                         
71     default:
72       log_debug << "unhandled state" << std::endl;
73       break;
74         }
75         
76         return FORCE_MOVE;
77 }
78
79 HitResponse
80 WeakBlock::collision(GameObject& other, const CollisionHit& hit)
81 {
82   switch (state) {
83                                 
84       case STATE_NORMAL:
85         if (Bullet* bullet = dynamic_cast<Bullet*> (&other)) {
86           return collision_bullet(*bullet, hit);
87         }
88         //Explosions destroy weakblocks as well
89         if (dynamic_cast<Explosion*> (&other)) {
90           startBurning();
91         }
92         break;
93                                 
94       case STATE_BURNING:
95       case STATE_DISINTEGRATING:
96         break;
97                                 
98       default:
99         log_debug << "unhandled state" << std::endl;
100         break;
101   }
102         
103   return FORCE_MOVE;
104 }
105
106 void
107 WeakBlock::update(float )
108 {
109   switch (state) {
110                                 
111       case STATE_NORMAL:
112         break;
113                                 
114       case STATE_BURNING:
115         // cause burn light to flicker randomly
116         if (linked) {
117           if(gameRandom.rand(10) >= 7) {
118             lightsprite->set_color(Color(0.2f + gameRandom.rand(20)/100.0f, 0.1f + gameRandom.rand(20)/100.0f, 0.1f));
119           } else
120             lightsprite->set_color(Color(0.3f, 0.2f, 0.1f));
121         }
122       
123         if (sprite->animation_done()) {
124           state = STATE_DISINTEGRATING;
125           sprite->set_action("disintegrating", 1);
126           spreadHit();
127           set_group(COLGROUP_DISABLED);
128           lightsprite = sprite_manager->create("images/objects/lightmap_light/lightmap_light-tiny.sprite");
129           lightsprite->set_blend(Blend(GL_SRC_ALPHA, GL_ONE));
130           lightsprite->set_color(Color(0.3f, 0.2f, 0.1f));
131         }
132         break;
133                                 
134       case STATE_DISINTEGRATING:
135         if (sprite->animation_done()) {
136           remove_me();
137           return;
138         }
139         break;
140                                 
141   }
142 }
143
144 void
145 WeakBlock::draw(DrawingContext& context)
146 {
147   //Draw the Sprite.
148   sprite->draw(context, get_pos(), LAYER_OBJECTS);
149   //Draw the light if burning and dark
150   if(linked && (state != STATE_NORMAL)){
151     context.get_light( get_bbox().get_middle(), &light );
152     if (light.red + light.green + light.blue < 3.0){
153       context.push_target();
154       context.set_target(DrawingContext::LIGHTMAP);
155       sprite->draw(context, get_pos(), LAYER_OBJECTS);
156       lightsprite->draw(context, get_bbox().get_middle(), 0);
157       context.pop_target();
158     }
159   }
160 }
161                                  
162 void
163 WeakBlock::startBurning()
164 {
165   if (state != STATE_NORMAL) return;
166   state = STATE_BURNING;
167   sprite->set_action("burning", 1);
168 }
169
170 void
171 WeakBlock::spreadHit()
172 {
173   //Destroy adjacent weakblocks if applicable
174   if(linked) {
175     Sector* sector = Sector::current();
176     if (!sector) {
177       log_debug << "no current sector" << std::endl;
178       return;
179     }
180     for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i != sector->gameobjects.end(); ++i) {
181       WeakBlock* wb = dynamic_cast<WeakBlock*>(*i);
182       if (!wb) continue;
183       if (wb == this) continue;
184       if (wb->state != STATE_NORMAL) continue;
185       float dx = fabsf(wb->get_pos().x - this->get_pos().x);
186       float dy = fabsf(wb->get_pos().y - this->get_pos().y);
187       if ((dx <= 32.5) && (dy <= 32.5)) wb->startBurning();
188     }
189   }
190 }
191
192
193 /* EOF */