// xsc: Copyright (c) 1993-2005 by Mark B. Hanson (mbh@panix.com). static const char *const file_id = "@(#)$Id: castle.C,v 3.13 2005/01/02 19:11:17 mark Exp $"; #include "global.h" #include "timing.h" #include "util.h" #include "xsc.h" #include "castle.h" namespace { const int nrings = 3; const unsigned int values[nrings] = { 10, 20, 30 }; const float scales[nrings] = { 3.65, 5, 8 }; const float dthetas[nrings] = { -45.0, 90.0, -90.0 }; const int ringstates = 3; const gc_token ringctoks[nrings][ringstates] = { { GC_DULL_RED, GC_BRIGHT_RED, GC_DULL_GREY }, { GC_DULL_ORANGE, GC_BRIGHT_ORANGE, GC_BLACK }, { GC_DULL_YELLOW, GC_BRIGHT_YELLOW, GC_BLACK }, }; } // namespace Castle::Castle(void) { //fprintf(stderr, "Castle::Castle()\n"); numrings = nrings; rings = new Ring *[numrings]; state = CASTLE_STATE_NORMAL; GC gcs[ringstates]; for (int i = 0; i < numrings; i++) { for (int j = 0; j < ringstates; j++) { gcs[j] = fetch_gc(ringctoks[i][j]); } rings[i] = new Ring(scales[i], (dthetas[i] / args.fps), values[i], gcs, ringstates); } } // Castle::Castle Castle::~Castle(void) { //fprintf(stderr, "Castle::~Castle()\n"); for (int i = 0; i < numrings; i++) { delete rings[i]; } delete[] rings; } // Castle::~Castle void Castle::render(const bool ink) { for (int i = 0; i < numrings; i++) { rings[i]->render(ink); } } // Castle::render void Castle::turn(Minefield *minefield, King *king) { int i, j; bool go_again; for (i = 0; i < numrings; i++) { rings[i]->turn(); } if (state == CASTLE_STATE_REGENERATING) { // if currently regenerating, slowly increase the size of the rings go_again = false; for (i = 0; i < numrings; i++) { float tmp = rings[i]->get_scale(); if (tmp > scales[i]) { rings[i]->set_scale(tmp - (((tmp - scales[i]) * 4.0) / args.fps)); } // close enough if (rings[i]->get_scale() - scales[i] < 0.01) { rings[i]->set_scale(scales[i]); } else { go_again = true; } } if (!go_again) { state = CASTLE_STATE_NORMAL; } } else if (state == CASTLE_STATE_COLLAPSING) { // collapse the rings inward go_again = false; for (i = 0; i < numrings; i++) { float tmp = rings[i]->get_scale(); if (tmp < 1000.0) { rings[i]->set_scale(tmp + (tmp * 8.0) / args.fps); } // close enough if (1000.0 - rings[i]->get_scale() < 0.01) { rings[i]->set_scale(1000.0); } else { go_again = true; } } if (!go_again) { state = CASTLE_STATE_EXPLODING; for (i = 0; i < numrings; i++) { rings[i]->set_scale(scales[i] * 100.0); } } } else if (state == CASTLE_STATE_EXPLODING) { // expand rings beyond the edge of the screen go_again = false; for (i = 0; i < numrings; i++) { float tmp = rings[i]->get_scale(); if (tmp > 0.5) { rings[i]->set_scale(tmp - (((tmp - 0.5) * 12.0) / args.fps)); } // close enough if (rings[i]->get_scale() - 0.5 < 0.01) { rings[i]->set_scale(0.5); } else { go_again = true; } } if (!go_again) { state = CASTLE_STATE_RESTING; time_of_death = time_now; pause_sum = 0; } } else if (state == CASTLE_STATE_RESTING) { // rest a bit before reincarnating if ((time_now - time_of_death) - pause_sum > 2000000L) { state = CASTLE_STATE_REGENERATING; for (i = 0; i < numrings; i++) { if (i == numrings - 1) { rings[i]->set_scale(13); } else { rings[i]->set_scale(scales[i + 1]); } rings[i]->refresh(); } king->reincarnate(); } } else if (!rings[0]->remaining()) { // enemy has destroyed entire outer ring Ring *tmpwall = rings[0]; for (i = 0; i < numrings - 1; i++) { rings[i] = rings[i + 1]; } rings[numrings - 1] = tmpwall; rings[numrings - 1]->set_scale(13); rings[numrings - 1]->refresh(); for (i = 0; i < numrings; i++) { rings[i]->set_value(values[i]); for (j = 0; j < ringstates; j++) { rings[i]->set_gc(j, fetch_gc(ringctoks[i][j])); } rings[i]->set_dtheta(dthetas[i] / args.fps); } state = CASTLE_STATE_REGENERATING; minefield->upgrade(this); } } // Castle::turn void Castle::resize(const int nwidth, const int nheight) { for (int i = 0; i < numrings; i++) { rings[i]->resize(nwidth, nheight); } } // Castle::resize bool Castle::collision(Laser *laser, Stats *stats) { for (int i = 0; i < numrings; i++) { if (within(laser->get_radius(), (rings[i]->get_size() / 2.0), 1.5)) { if (rings[i]->hit(laser, stats)) { return true; } } } return false; } // Castle::collision bool Castle::opening(const float degrees) const { for (int i = 0; i < numrings; i++) { if (!rings[i]->hole(degrees)) { return false; } } return true; } // Castle::opening bool Castle::hole(const int whichring, const float degrees) const { return rings[whichring]->hole(degrees); } // Castle::hole float Castle::ring_size(const int wallnum) const { return rings[wallnum]->get_size(); } // Castle::ring_size void Castle::seg_center(const int wallnum, /*const*/ float degrees, float * /*const*/ xptr, float * /*const*/ yptr) { rings[wallnum]->seg_center(degrees, xptr, yptr); } // Castle::seg_center void Castle::explode(Stats *stats) { XBell(display, 100); for (int i = 0; i < numrings; i++) { stats->score += (rings[i]->remaining() * rings[i]->get_value()); } state = CASTLE_STATE_COLLAPSING; } // Castle::explode GC Castle::get_gc(const int wallnum) const { return fetch_gc(ringctoks[wallnum][1]); } // Castle::get_gc void Castle::refresh(void) const { for (int i = 0; i < numrings; i++) { rings[i]->refresh(); } } // Castle::refresh