5 |
* modify it under the terms of the GNU General Public License |
* modify it under the terms of the GNU General Public License |
6 |
* as published by the Free Software Foundation; either version 2 |
* as published by the Free Software Foundation; either version 2 |
7 |
* of the License, or (at your option) any later version. |
* of the License, or (at your option) any later version. |
8 |
* |
* |
9 |
* This program is distributed in the hope that it will be useful, |
* This program is distributed in the hope that it will be useful, |
10 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
38 |
public: |
public: |
39 |
static void emit_from(GridPos p, Direction d); |
static void emit_from(GridPos p, Direction d); |
40 |
static void kill_all(); |
static void kill_all(); |
41 |
|
|
42 |
// LaserEmitter interface |
// LaserEmitter interface |
43 |
DirectionBits emission_directions() const { return directions; } |
DirectionBits emission_directions() const { return directions; } |
44 |
private: |
private: |
54 |
|
|
55 |
Object *clone() { |
Object *clone() { |
56 |
// new LaserBeams may only created inside `emit_from'. |
// new LaserBeams may only created inside `emit_from'. |
57 |
assert(0); |
assert(0); |
58 |
return 0; |
return 0; |
59 |
} |
} |
60 |
void dispose(); |
void dispose(); |
61 |
|
|
78 |
\subsection lasera Attributes |
\subsection lasera Attributes |
79 |
|
|
80 |
- \b on: 1 if laser in active, 0 if not |
- \b on: 1 if laser in active, 0 if not |
81 |
- \b dir: the Direction in which light is emitted |
- \b dir: the Direction in which light is emitted |
82 |
(NORTH, EAST, SOUTH, WEST) |
(NORTH, EAST, SOUTH, WEST) |
83 |
|
|
84 |
\subsection laserm Messages |
\subsection laserm Messages |
101 |
private: |
private: |
102 |
// LaserEmitter interface |
// LaserEmitter interface |
103 |
DirectionBits emission_directions() const { |
DirectionBits emission_directions() const { |
104 |
return to_bits(get_dir()); |
if (is_on()) { |
105 |
|
return to_bits(get_dir()); |
106 |
|
} |
107 |
|
return NODIRBIT; |
108 |
} |
} |
109 |
|
|
110 |
// OnOffStone interface. |
// OnOffStone interface. |
127 |
vector<void*> PhotoCell::instances; |
vector<void*> PhotoCell::instances; |
128 |
|
|
129 |
void |
void |
130 |
PhotoCell::notify_start() |
PhotoCell::notify_start() |
131 |
{ |
{ |
132 |
for(unsigned i=0; i<instances.size(); ++i) |
for(unsigned i=0; i<instances.size(); ++i) |
133 |
{ |
{ |
137 |
} |
} |
138 |
|
|
139 |
void |
void |
140 |
PhotoCell::notify_finish() |
PhotoCell::notify_finish() |
141 |
{ |
{ |
142 |
for(unsigned i=0; i<instances.size(); ++i) |
for(unsigned i=0; i<instances.size(); ++i) |
143 |
{ |
{ |
146 |
} |
} |
147 |
} |
} |
148 |
|
|
149 |
void |
void |
150 |
PhotoCell::photo_activate() |
PhotoCell::photo_activate() |
151 |
{ |
{ |
152 |
vector<void*>::iterator i; |
vector<void*>::iterator i; |
153 |
i = std::find(instances.begin(), instances.end(), this); |
i = std::find(instances.begin(), instances.end(), this); |
154 |
if (i != instances.end()) |
if (i != instances.end()) |
155 |
assert(0 || "Photocell activated twice\n"); |
assert(0 || "Photocell activated twice\n"); |
156 |
else |
else |
157 |
instances.push_back(this); |
instances.push_back(this); |
158 |
} |
} |
159 |
|
|
160 |
void |
void |
161 |
PhotoCell::photo_deactivate() |
PhotoCell::photo_deactivate() |
162 |
{ |
{ |
163 |
vector<void*>::iterator i; |
vector<void*>::iterator i; |
164 |
i = std::find(instances.begin(), instances.end(), this); |
i = std::find(instances.begin(), instances.end(), this); |
169 |
//---------------------------------------- |
//---------------------------------------- |
170 |
// PhotoStone |
// PhotoStone |
171 |
//---------------------------------------- |
//---------------------------------------- |
172 |
void |
void |
173 |
PhotoStone::check_state() |
PhotoStone::check_state() |
174 |
{ |
{ |
175 |
GridPos p = get_pos(); |
GridPos p = get_pos(); |
176 |
bool illu = (LightFrom(p, NORTH) || LightFrom(p, EAST) |
bool illu = (LightFrom(p, NORTH) || LightFrom(p, EAST) |
177 |
|| LightFrom(p, WEST) || LightFrom(p, SOUTH)); |
|| LightFrom(p, WEST) || LightFrom(p, SOUTH)); |
178 |
|
|
179 |
if (illu != illuminated) { |
if (illu != illuminated) { |
180 |
if (illu) |
if (illu) { |
181 |
notify_laseron(); |
notify_laseron(); |
182 |
else |
} |
183 |
|
else { |
184 |
notify_laseroff(); |
notify_laseroff(); |
185 |
|
} |
186 |
illuminated = illu; |
illuminated = illu; |
187 |
} |
} |
188 |
} |
} |
190 |
|
|
191 |
//---------------------------------------- |
//---------------------------------------- |
192 |
// LaserBeam |
// LaserBeam |
193 |
// |
// |
194 |
// The implementation of laser beams is a little tricky because, in |
// The implementation of laser beams is a little tricky because, in |
195 |
// spite of being implemented as Items, lasers aren't localized and |
// spite of being implemented as Items, lasers aren't localized and |
196 |
// changes to any part of the beam can affect the beam elsewhere. A |
// changes to any part of the beam can affect the beam elsewhere. A |
202 |
// |
// |
203 |
// - Laser beams are static. Once calculated they do not change until |
// - Laser beams are static. Once calculated they do not change until |
204 |
// they are completely recalculated |
// they are completely recalculated |
205 |
// |
// |
206 |
// - LaserBeam::emit_from() is the only way to emit laser beams. A new |
// - LaserBeam::emit_from() is the only way to emit laser beams. A new |
207 |
// beam will propagate automatically and stops only if it comes |
// beam will propagate automatically and stops only if it comes |
208 |
// across a stone or or item that returns `false' from |
// across a stone or or item that returns `false' from |
219 |
|
|
220 |
vector<void*> LaserBeam::instances; |
vector<void*> LaserBeam::instances; |
221 |
|
|
222 |
void |
void |
223 |
LaserBeam::init_model() |
LaserBeam::init_model() |
224 |
{ |
{ |
225 |
if (directions & (EASTBIT | WESTBIT)) { |
if (directions & (EASTBIT | WESTBIT)) { |
226 |
if (directions & (NORTHBIT | SOUTHBIT)) |
if (directions & (NORTHBIT | SOUTHBIT)) |
232 |
set_model("it-laserv"); |
set_model("it-laserv"); |
233 |
} |
} |
234 |
|
|
235 |
bool |
bool |
236 |
LaserBeam::on_laserhit(Direction dir) |
LaserBeam::on_laserhit(Direction dir) |
237 |
{ |
{ |
238 |
DirectionBits dirbit = to_bits(dir); |
DirectionBits dirbit = to_bits(dir); |
239 |
if (!(directions & dirbit)) { |
if (!(directions & dirbit)) { |
245 |
return false; |
return false; |
246 |
} |
} |
247 |
|
|
248 |
void |
void |
249 |
LaserBeam::on_creation() |
LaserBeam::on_creation() |
250 |
{ |
{ |
251 |
if (directions & EASTBIT) emit_from(get_pos(), EAST); |
if (directions & EASTBIT) emit_from(get_pos(), EAST); |
252 |
if (directions & WESTBIT) emit_from(get_pos(), WEST); |
if (directions & WESTBIT) emit_from(get_pos(), WEST); |
253 |
if (directions &NORTHBIT) emit_from(get_pos(), NORTH); |
if (directions &NORTHBIT) emit_from(get_pos(), NORTH); |
254 |
if (directions &SOUTHBIT) emit_from(get_pos(), SOUTH); |
if (directions &SOUTHBIT) emit_from(get_pos(), SOUTH); |
255 |
init_model(); |
init_model(); |
256 |
} |
} |
257 |
|
|
258 |
void |
void |
259 |
LaserBeam::emit_from(GridPos p, Direction d) |
LaserBeam::emit_from(GridPos p, Direction d) |
260 |
{ |
{ |
261 |
bool may_pass = true; |
bool may_pass = true; |
262 |
|
|
275 |
} |
} |
276 |
} |
} |
277 |
|
|
278 |
bool |
bool |
279 |
LaserBeam::actor_hit(Actor *actor) |
LaserBeam::actor_hit(Actor *actor) |
280 |
{ |
{ |
281 |
double r = actor->get_radius(); |
double r = actor->get_radius(); |
305 |
} |
} |
306 |
} |
} |
307 |
|
|
308 |
void |
void |
309 |
LaserBeam::dispose() |
LaserBeam::dispose() |
310 |
{ |
{ |
311 |
instances.erase(std::find(instances.begin(), instances.end(), this)); |
instances.erase(std::find(instances.begin(), instances.end(), this)); |
312 |
delete this; |
delete this; |
328 |
} |
} |
329 |
} |
} |
330 |
|
|
331 |
void |
void |
332 |
LaserStone::notify_onoff(bool on) |
LaserStone::notify_onoff(bool on) |
333 |
{ |
{ |
334 |
RecalcLight(); |
RecalcLight(); |
335 |
if (on) |
if (on) |
336 |
sound::PlaySound("st-laseron"); |
sound::PlaySound("st-laseron"); |
337 |
} |
} |
338 |
|
|
339 |
void |
void |
340 |
LaserStone::emit_light() |
LaserStone::emit_light() |
341 |
{ |
{ |
342 |
if (is_on()) |
if (is_on()) |
344 |
} |
} |
345 |
|
|
346 |
/* */ |
/* */ |
347 |
void |
void |
348 |
LaserStone::on_creation() |
LaserStone::on_creation() |
349 |
{ |
{ |
350 |
if (is_on()) |
if (is_on()) |
351 |
RecalcLight(); //LaserBeam::emit_from(get_pos(), get_dir()); |
RecalcLight(); //LaserBeam::emit_from(get_pos(), get_dir()); |
352 |
Stone::on_creation(); |
Stone::on_creation(); |
353 |
} |
} |
354 |
|
|
355 |
void |
void |
356 |
LaserStone::init_model() |
LaserStone::init_model() |
357 |
{ |
{ |
358 |
string mname = is_on() ? "st-laseron" : "st-laser"; |
string mname = is_on() ? "st-laseron" : "st-laser"; |
359 |
mname += to_suffix(get_dir()); |
mname += to_suffix(get_dir()); |
365 |
//---------------------------------------- |
//---------------------------------------- |
366 |
namespace |
namespace |
367 |
{ |
{ |
368 |
class MirrorStone |
class MirrorStone |
369 |
: public MovableStone, public LaserEmitter, public PhotoCell |
: public MovableStone, public LaserEmitter, public PhotoCell |
370 |
{ |
{ |
371 |
protected: |
protected: |
389 |
private: |
private: |
390 |
// Object interface. |
// Object interface. |
391 |
void message(const string &m, const Value &); |
void message(const string &m, const Value &); |
392 |
|
|
393 |
// LaserEmitter interface |
// LaserEmitter interface |
394 |
DirectionBits emission_directions() const { |
DirectionBits emission_directions() const { |
395 |
return outdirs; |
return outdirs; |
412 |
}; |
}; |
413 |
} |
} |
414 |
|
|
415 |
MirrorStone::MirrorStone(const char *name) |
MirrorStone::MirrorStone(const char *name) |
416 |
: MovableStone(name) |
: MovableStone(name) |
417 |
{ |
{ |
418 |
set_attrib("transparent", Value()); |
set_attrib("transparent", Value()); |
420 |
set_attrib("orientation", Value(1)); |
set_attrib("orientation", Value(1)); |
421 |
} |
} |
422 |
|
|
423 |
void |
void |
424 |
MirrorStone::init_model() |
MirrorStone::init_model() |
425 |
{ |
{ |
426 |
string mname = get_kind(); |
string mname = get_kind(); |
427 |
mname += is_movable() ? "-m" : "-s"; |
mname += is_movable() ? "-m" : "-s"; |
430 |
set_model(mname); |
set_model(mname); |
431 |
} |
} |
432 |
|
|
433 |
void |
void |
434 |
MirrorStone::message(const string &m, const Value &) |
MirrorStone::message(const string &m, const Value &) |
435 |
{ |
{ |
436 |
if (m == "trigger" || m=="turn") { |
if (m == "trigger" || m=="turn") { |
440 |
|
|
441 |
|
|
442 |
void |
void |
443 |
MirrorStone::actor_hit(const StoneContact &sc) |
MirrorStone::actor_hit(const StoneContact &sc) |
444 |
{ |
{ |
445 |
if (is_movable()) |
if (is_movable()) |
446 |
MovableStone::actor_hit(sc); |
MovableStone::actor_hit(sc); |
447 |
rotate_right(); |
rotate_right(); |
448 |
} |
} |
449 |
|
|
450 |
void |
void |
451 |
MirrorStone::on_creation() |
MirrorStone::on_creation() |
452 |
{ |
{ |
453 |
photo_activate(); |
photo_activate(); |
454 |
Stone::on_creation(); |
Stone::on_creation(); |
455 |
} |
} |
456 |
|
|
457 |
void |
void |
458 |
MirrorStone::on_removal() |
MirrorStone::on_removal() |
459 |
{ |
{ |
460 |
photo_deactivate(); |
photo_deactivate(); |
461 |
Stone::on_removal(); |
Stone::on_removal(); |
462 |
} |
} |
463 |
|
|
464 |
void |
void |
465 |
MirrorStone::rotate_right() |
MirrorStone::rotate_right() |
466 |
{ |
{ |
467 |
set_orientation(1+(get_orientation() % 4)); |
set_orientation(1+(get_orientation() % 4)); |
468 |
init_model(); |
init_model(); |
499 |
}; |
}; |
500 |
} |
} |
501 |
|
|
502 |
bool |
bool |
503 |
PlaneMirror::on_laserhit(Direction dir) |
PlaneMirror::on_laserhit(Direction dir) |
504 |
{ |
{ |
505 |
switch (get_orientation()) { |
switch (get_orientation()) { |
507 |
if (dir==EAST || dir==WEST) |
if (dir==EAST || dir==WEST) |
508 |
emit_light(reverse(dir)); |
emit_light(reverse(dir)); |
509 |
break; |
break; |
510 |
case '-': |
case '-': |
511 |
if (dir==NORTH || dir==SOUTH) |
if (dir==NORTH || dir==SOUTH) |
512 |
emit_light(reverse(dir)); |
emit_light(reverse(dir)); |
513 |
break; |
break; |
514 |
case '/': |
case '/': |
515 |
switch(dir) { |
switch(dir) { |
516 |
case EAST: emit_light(NORTH); break; |
case EAST: emit_light(NORTH); break; |
517 |
case SOUTH: emit_light(WEST); break; |
case SOUTH: emit_light(WEST); break; |
520 |
case NODIR: break; |
case NODIR: break; |
521 |
} |
} |
522 |
break; |
break; |
523 |
case '\\': |
case '\\': |
524 |
switch(dir) { |
switch(dir) { |
525 |
case EAST: emit_light(SOUTH); break; |
case EAST: emit_light(SOUTH); break; |
526 |
case SOUTH: emit_light(EAST); break; |
case SOUTH: emit_light(EAST); break; |
551 |
TriangleMirror() : MirrorStone("st-3mirror") {} |
TriangleMirror() : MirrorStone("st-3mirror") {} |
552 |
private: |
private: |
553 |
|
|
554 |
Direction get_orientation() |
Direction get_orientation() |
555 |
{ |
{ |
556 |
Direction a[] = {NODIR, SOUTH, WEST, NORTH, EAST}; |
Direction a[] = {NODIR, SOUTH, WEST, NORTH, EAST}; |
557 |
return a[MirrorStone::get_orientation()]; |
return a[MirrorStone::get_orientation()]; |
560 |
}; |
}; |
561 |
} |
} |
562 |
|
|
563 |
bool |
bool |
564 |
TriangleMirror::on_laserhit(Direction dir) |
TriangleMirror::on_laserhit(Direction dir) |
565 |
{ |
{ |
566 |
Direction orient = get_orientation(); |
Direction orient = get_orientation(); |
567 |
|
|
568 |
if (dir == orient) |
if (dir == orient) |
569 |
emit_light(reverse(dir)); |
emit_light(reverse(dir)); |
570 |
else if (dir == reverse(orient)) { |
else if (dir == reverse(orient)) { |
571 |
// this is the "complicated" case where the light falls |
// this is the "complicated" case where the light falls |
572 |
// on the tip of the triangle |
// on the tip of the triangle |
573 |
switch (dir) { |
switch (dir) { |
574 |
case SOUTH: case NORTH: |
case SOUTH: case NORTH: |
575 |
emit_light(EAST); emit_light(WEST); break; |
emit_light(EAST); emit_light(WEST); break; |
576 |
case WEST: case EAST: |
case WEST: case EAST: |
577 |
emit_light(SOUTH); emit_light(NORTH); break; |
emit_light(SOUTH); emit_light(NORTH); break; |
578 |
case NODIR: break; |
case NODIR: break; |
579 |
} |
} |
580 |
} else |
} else |
581 |
emit_light(orient); |
emit_light(orient); |
582 |
if (is_transparent()) |
if (is_transparent()) |
583 |
emit_light(dir); |
emit_light(dir); |
594 |
bool light_recalc_scheduled = false; |
bool light_recalc_scheduled = false; |
595 |
} |
} |
596 |
|
|
597 |
void |
void |
598 |
world::laser::Init() |
world::laser::Init() |
599 |
{ |
{ |
600 |
Register(new LaserStone); |
Register(new LaserStone); |
603 |
} |
} |
604 |
|
|
605 |
|
|
606 |
void |
void |
607 |
world::laser::MaybeRecalcLight(GridPos p) |
world::laser::MaybeRecalcLight(GridPos p) |
608 |
{ |
{ |
609 |
light_recalc_scheduled |= |
light_recalc_scheduled |= |
610 |
(LightFrom(p, NORTH) || LightFrom(p, SOUTH) || |
(LightFrom(p, NORTH) || LightFrom(p, SOUTH) || |
611 |
LightFrom(p, WEST) || LightFrom(p, EAST)); |
LightFrom(p, WEST) || LightFrom(p, EAST)); |
612 |
} |
} |
613 |
|
|
614 |
void |
void |
615 |
world::laser::RecalcLight() |
world::laser::RecalcLight() |
616 |
{ |
{ |
617 |
light_recalc_scheduled = true; |
light_recalc_scheduled = true; |