230 |
SINKING, |
SINKING, |
231 |
DROWNING, |
DROWNING, |
232 |
BUBBLING, |
BUBBLING, |
233 |
FALLING, |
FALLING, // falling into abyss |
234 |
JUMPING, |
JUMPING, |
235 |
DEAD, // marble is dead |
DEAD, // marble is dead |
236 |
RESURRECTED, // has been resurrected; about to respawn |
RESURRECTED, // has been resurrected; about to respawn |
237 |
APPEARING, |
APPEARING, |
|
RISING, // appear in vortex |
|
238 |
DISAPPEARING, |
DISAPPEARING, |
239 |
|
FALLING_VORTEX, // falling into vortex |
240 |
|
RISING_VORTEX, // appear in vortex |
241 |
|
JUMP_VORTEX, // jump out of vortex (here player controls actor) |
242 |
}; |
}; |
243 |
State state; |
State state; |
244 |
|
|
|
double sinkDepth; // how deep actor has sunk |
|
245 |
static const int minSinkDepth = 0; // normal level |
static const int minSinkDepth = 0; // normal level |
246 |
static const int maxSinkDepth = 7; // at that level he dies |
static const int maxSinkDepth = 7; // at that level the actor dies |
|
int sinkModel; // current model |
|
247 |
|
|
248 |
|
union { |
249 |
|
struct { |
250 |
|
double sinkDepth; // how deep actor has sunk |
251 |
|
int sinkModel; // current model |
252 |
|
} sink; |
253 |
|
struct { |
254 |
|
double normal_time; // while jumping out of vortex: time at normal level |
255 |
|
} vortex; |
256 |
|
} shared; |
257 |
|
|
258 |
void set_model_cb(const string &m) { |
void set_model_cb(const string &m) { |
259 |
set_model(m.c_str()); |
set_model(m.c_str()); |
285 |
|
|
286 |
bool is_dead() { return state == DEAD; } |
bool is_dead() { return state == DEAD; } |
287 |
bool is_flying() { return state == JUMPING; } |
bool is_flying() { return state == JUMPING; } |
288 |
bool is_on_floor() { return state == NORMAL || state == SINKING; } |
bool is_on_floor() { return state == NORMAL || state == SINKING || state == JUMP_VORTEX; } |
289 |
bool can_drop_items() { return state==NORMAL || state==JUMPING; } |
bool can_drop_items() { return state == NORMAL || state==JUMPING || state == JUMP_VORTEX; } |
290 |
bool can_pickup_items() { return state==NORMAL; } |
bool can_pickup_items() { return state == NORMAL || state == JUMP_VORTEX; } |
291 |
|
|
292 |
// Object interface. |
// Object interface. |
293 |
void message(const string &m, const Value &); |
void message(const string &m, const Value &); |
295 |
} |
} |
296 |
|
|
297 |
BasicBall::BasicBall(const char *kind, double radius, double mass) |
BasicBall::BasicBall(const char *kind, double radius, double mass) |
298 |
: Actor(kind, V2()), state(NO_STATE), |
: Actor(kind, V2()), state(NO_STATE) |
299 |
sinkDepth (0), sinkModel(-1) |
//, sinkDepth (0), sinkModel(-1) |
300 |
{ |
{ |
301 |
world::ActorInfo *ai = get_actorinfo(); |
world::ActorInfo *ai = get_actorinfo(); |
302 |
ai->radius = radius; |
ai->radius = radius; |
305 |
|
|
306 |
void BasicBall::message(const string &m, const Value &) |
void BasicBall::message(const string &m, const Value &) |
307 |
{ |
{ |
308 |
if (state == NORMAL) { |
switch (state) { |
309 |
if (m == "shatter") change_state(SHATTERING); |
case NORMAL: |
310 |
else if (m == "laserhit") change_state(SHATTERING); |
if (m == "shatter") change_state(SHATTERING); |
311 |
else if (m == "sink") change_state(SINKING); |
else if (m == "laserhit") change_state(SHATTERING); |
312 |
else if (m == "drown") change_state(DROWNING); |
else if (m == "sink") change_state(SINKING); |
313 |
else if (m == "fall") change_state(FALLING); |
else if (m == "drown") change_state(DROWNING); |
314 |
else if (m == "jump") change_state(JUMPING); |
else if (m == "fall") change_state(FALLING); |
315 |
else if (m == "appear") change_state(APPEARING); |
else if (m == "fallvortex") change_state(FALLING_VORTEX); |
316 |
else if (m == "disappear") change_state(DISAPPEARING); |
else if (m == "jump") change_state(JUMPING); |
317 |
} |
else if (m == "appear") change_state(APPEARING); |
318 |
else if (state == JUMPING) { |
else if (m == "disappear") change_state(DISAPPEARING); |
319 |
if (m == "shatter") change_state(SHATTERING); |
break; |
320 |
else if (m == "disappear") change_state(DISAPPEARING); |
case JUMPING: |
321 |
} |
if (m == "shatter") change_state(SHATTERING); |
322 |
else if (state == DEAD) { |
else if (m == "disappear") change_state(DISAPPEARING); |
323 |
if (m == "resurrect") change_state(RESURRECTED); |
break; |
324 |
} |
case DEAD: |
325 |
else if (state == SINKING) { |
if (m == "resurrect") change_state(RESURRECTED); |
326 |
if (m == "getout") change_state(NORMAL); |
break; |
327 |
} |
case SINKING: |
328 |
else if (state == FALLING) { |
if (m == "getout") change_state(NORMAL); |
329 |
if (m == "rise") change_state(RISING); |
break; |
330 |
|
case FALLING_VORTEX: |
331 |
|
if (m == "rise") change_state(RISING_VORTEX); // vortex->vortex teleportation |
332 |
|
else if (m == "appear") change_state(APPEARING); // vortex->non-vortex teleportation |
333 |
|
break; |
334 |
|
case JUMP_VORTEX: |
335 |
|
if (m == "laserhit") change_state(SHATTERING); |
336 |
|
break; |
337 |
|
|
338 |
|
default: |
339 |
|
break; |
340 |
} |
} |
341 |
} |
} |
342 |
|
|
351 |
bool shinep = (xpos + ypos) % 2; |
bool shinep = (xpos + ypos) % 2; |
352 |
set_shine_model (shinep); |
set_shine_model (shinep); |
353 |
} |
} |
354 |
if (state == SINKING) { |
else if (state == SINKING) { |
355 |
const double defaultSinkSpeed = 4.0; // 10.0 means : sink in 1 second (if absVelocity == 0) |
const double defaultSinkSpeed = 4.0; // 10.0 means : sink in 1 second (if absVelocity == 0) |
356 |
const double nonSinkVelocity = 6.0; // at this velocity don't sink; above: raise |
const double nonSinkVelocity = 6.0; // at this velocity don't sink; above: raise |
357 |
|
|
358 |
double sinkSpeed = defaultSinkSpeed * (1 - length(ai->vel) / nonSinkVelocity); |
double sinkSpeed = defaultSinkSpeed * (1 - length(ai->vel) / nonSinkVelocity); |
359 |
sinkDepth += sinkSpeed*dtime; |
shared.sink.sinkDepth += sinkSpeed*dtime; |
360 |
|
|
361 |
if (sinkDepth >= maxSinkDepth) { |
if (shared.sink.sinkDepth >= maxSinkDepth) { |
362 |
set_model(string(get_kind())+"-sunk"); |
set_model(string(get_kind())+"-sunk"); |
363 |
ai->vel = V2(); // stop! |
ai->vel = V2(); // stop! |
364 |
sound::PlaySound("swamped"); |
sound::PlaySound("swamped"); |
365 |
change_state(BUBBLING); |
change_state(BUBBLING); |
366 |
} |
} |
367 |
else { |
else { |
368 |
if (sinkDepth < minSinkDepth) sinkDepth = minSinkDepth; |
if (shared.sink.sinkDepth < minSinkDepth) shared.sink.sinkDepth = minSinkDepth; |
369 |
set_sink_model(get_kind()); |
set_sink_model(get_kind()); |
370 |
} |
} |
371 |
} |
} |
372 |
|
else if (state == JUMP_VORTEX) { |
373 |
|
shared.vortex.normal_time += dtime; |
374 |
|
if (shared.vortex.normal_time > 0.025) // same time as appear animation |
375 |
|
if (shared.vortex.normal_time > dtime) // ensure min. one tick in state JUMP_VORTEX! |
376 |
|
change_state(JUMPING); // end of short control over actor |
377 |
|
} |
378 |
} |
} |
379 |
|
|
380 |
void BasicBall::set_sink_model(const string &m) |
void BasicBall::set_sink_model(const string &m) |
381 |
{ |
{ |
382 |
int modelnum = static_cast<int>(sinkDepth); |
int modelnum = static_cast<int>(shared.sink.sinkDepth); |
383 |
|
|
384 |
if (modelnum != sinkModel) { |
if (modelnum != shared.sink.sinkModel) { |
385 |
assert(modelnum >= minSinkDepth && modelnum < maxSinkDepth); |
assert(modelnum >= minSinkDepth && modelnum < maxSinkDepth); |
386 |
|
|
387 |
string img = m+"-sink"; |
string img = m+"-sink"; |
388 |
img.append(1, static_cast<char>('0'+modelnum)); |
img.append(1, static_cast<char>('0'+modelnum)); |
389 |
set_model(img); |
set_model(img); |
390 |
|
|
391 |
sinkModel = modelnum; |
shared.sink.sinkModel = modelnum; |
392 |
} |
} |
393 |
} |
} |
394 |
|
|
417 |
set_model("invisible"); |
set_model("invisible"); |
418 |
change_state(DEAD); |
change_state(DEAD); |
419 |
break; |
break; |
420 |
case FALLING: { |
case FALLING: |
421 |
set_model(kind+"-fallen"); // invisible |
set_model(kind+"-fallen"); // invisible |
422 |
Item *it = GetItem(GridPos(get_pos())); |
sound::PlaySound("shatter"); |
423 |
if (it && it->is_kind("it-vortex")) { |
change_state(DEAD); |
|
SendMessage(it, "warp"); |
|
|
} |
|
|
else { |
|
|
sound::PlaySound("shatter"); |
|
|
change_state(DEAD); |
|
|
} |
|
424 |
break; |
break; |
|
} |
|
425 |
case JUMPING: |
case JUMPING: |
426 |
set_model(kind); |
set_model(kind); |
427 |
change_state(NORMAL); |
change_state(NORMAL); |
430 |
set_model(kind); |
set_model(kind); |
431 |
change_state(NORMAL); |
change_state(NORMAL); |
432 |
break; |
break; |
433 |
case RISING: { |
case DISAPPEARING: |
434 |
set_model(kind); |
set_model("ring-anim"); |
435 |
|
break; |
436 |
|
case FALLING_VORTEX: { |
437 |
|
set_model(kind+"-fallen"); // invisible |
438 |
Item *it = GetItem(GridPos(get_pos())); |
Item *it = GetItem(GridPos(get_pos())); |
439 |
if (it && it->is_kind("it-vortex")) { |
if (it && it->is_kind("it-vortex")) { |
440 |
SendMessage(it, "arrival"); |
SendMessage(it, "warp"); |
441 |
} |
} |
|
|
|
|
// @@@ FIXME: in this moment the actor should be controllable by mouse |
|
|
|
|
|
change_state(JUMPING); |
|
442 |
break; |
break; |
443 |
} |
} |
444 |
case DISAPPEARING: |
case RISING_VORTEX: { |
445 |
set_model("ring-anim"); |
set_model(kind); |
446 |
|
Item *it = GetItem(GridPos(get_pos())); |
447 |
|
if (it && it->is_kind("it-vortex")) { |
448 |
|
SendMessage(it, "arrival"); // closes some vortex |
449 |
|
} |
450 |
|
change_state(JUMP_VORTEX); |
451 |
break; |
break; |
452 |
|
} |
453 |
default: |
default: |
454 |
break; |
break; |
455 |
} |
} |
484 |
case SINKING: |
case SINKING: |
485 |
if (oldstate != SINKING) { |
if (oldstate != SINKING) { |
486 |
world::ReleaseActor(this); |
world::ReleaseActor(this); |
487 |
sinkDepth = minSinkDepth; |
shared.sink.sinkDepth = minSinkDepth; |
488 |
|
shared.sink.sinkModel = -1; |
489 |
set_sink_model(kind); |
set_sink_model(kind); |
490 |
} |
} |
491 |
break; |
break; |
503 |
set_model_cb("ac-drowned"); |
set_model_cb("ac-drowned"); |
504 |
break; |
break; |
505 |
case FALLING: |
case FALLING: |
506 |
|
case FALLING_VORTEX: |
507 |
world::GrabActor(this); |
world::GrabActor(this); |
508 |
set_model_cb(kind+"-fall"); |
set_model_cb(kind+"-fall"); |
509 |
break; |
break; |
513 |
set_model_cb(kind+"-jump"); |
set_model_cb(kind+"-jump"); |
514 |
break; |
break; |
515 |
case APPEARING: |
case APPEARING: |
516 |
case RISING: |
case RISING_VORTEX: |
517 |
set_model_cb(kind+"-appear"); |
set_model_cb(kind+"-appear"); |
518 |
world::GrabActor(this); |
world::GrabActor(this); |
519 |
break; |
break; |
520 |
|
case JUMP_VORTEX: |
521 |
|
assert(oldstate == RISING_VORTEX); |
522 |
|
shared.vortex.normal_time = 0; |
523 |
|
set_model(kind); |
524 |
|
world::ReleaseActor(this); |
525 |
|
break; |
526 |
case DISAPPEARING: |
case DISAPPEARING: |
527 |
world::GrabActor(this); |
world::GrabActor(this); |
528 |
set_model_cb(kind+"-disappear"); |
set_model_cb(kind+"-disappear"); |