int64_t az_baddie_point_value(az_baddie_kind_t kind) { assert(kind != AZ_BAD_NOTHING); switch (kind) { case AZ_BAD_NOTHING: AZ_ASSERT_UNREACHABLE(); case AZ_BAD_BASILISK: return 500; case AZ_BAD_FAKER: return 750; case AZ_BAD_FORCER: return 1000; case AZ_BAD_GHOST: return 450; case AZ_BAD_GUARD: return 400; case AZ_BAD_TANK: return 300; } AZ_ASSERT_UNREACHABLE(); }
static int baddie_hitpoints(az_baddie_kind_t kind) { assert(kind != AZ_BAD_NOTHING); switch (kind) { case AZ_BAD_NOTHING: AZ_ASSERT_UNREACHABLE(); case AZ_BAD_BASILISK: return 2; case AZ_BAD_FAKER: return 3; case AZ_BAD_FORCER: return 2; case AZ_BAD_GHOST: return 1; case AZ_BAD_GUARD: return 4; case AZ_BAD_TANK: return 1; } AZ_ASSERT_UNREACHABLE(); }
static bool parse_directive(az_load_planet_t *loader) { switch (az_rgetc(loader->reader)) { case 'H': parse_hint_directive(loader); return true; case 'T': parse_paragraph_directive(loader); return true; case 'Z': parse_zone_directive(loader); return true; case EOF: return false; default: FAIL(); } AZ_ASSERT_UNREACHABLE(); }
static void draw_baddie_internal(const az_baddie_t *baddie, az_clock_t clock) { const float flare = baddie->armor_flare; const float frozen = (baddie->frozen <= 0.0 ? 0.0 : baddie->frozen >= 0.2 ? 0.5 + 0.5 * baddie->frozen : az_clock_mod(3, 2, clock) < 2 ? 0.6 : 0.0); if (baddie->frozen > 0.0) clock = 0; switch (baddie->kind) { case AZ_BAD_NOTHING: AZ_ASSERT_UNREACHABLE(); case AZ_BAD_MARKER: glColor3f(1, 0, 1); // magenta glBegin(GL_LINE_STRIP); { glVertex2f(-20, 0); glVertex2f(20, 0); glVertex2f(0, 20); glVertex2f(0, -20); glVertex2f(20, 0); } glEnd(); break; case AZ_BAD_NORMAL_TURRET: az_draw_bad_normal_turret(baddie, frozen, clock); break; case AZ_BAD_ZIPPER: az_draw_bad_zipper(baddie, frozen, clock); break; case AZ_BAD_BOUNCER: az_draw_bad_bouncer(baddie, frozen, clock); break; case AZ_BAD_ATOM: az_draw_bad_atom(baddie, frozen, clock); break; case AZ_BAD_SPINER: az_draw_bad_spiner(baddie, frozen, clock); break; case AZ_BAD_BOX: assert(frozen == 0.0); draw_box(baddie, false, flare); break; case AZ_BAD_ARMORED_BOX: assert(frozen == 0.0); draw_box(baddie, true, flare); break; case AZ_BAD_CLAM: az_draw_bad_clam(baddie, frozen, clock); break; case AZ_BAD_NIGHTBUG: az_draw_bad_nightbug(baddie, frozen, clock); break; case AZ_BAD_SPINE_MINE: az_draw_bad_spine_mine(baddie, frozen, clock); break; case AZ_BAD_BROKEN_TURRET: az_draw_bad_broken_turret(baddie, frozen, clock); break; case AZ_BAD_ZENITH_CORE: az_draw_bad_zenith_core(baddie, clock); break; case AZ_BAD_ARMORED_TURRET: az_draw_bad_armored_turret(baddie, frozen, clock); break; case AZ_BAD_DRAGONFLY: az_draw_bad_dragonfly(baddie, frozen, clock); break; case AZ_BAD_CAVE_CRAWLER: az_draw_bad_cave_crawler(baddie, frozen, clock); break; case AZ_BAD_CRAWLING_TURRET: az_draw_bad_crawling_turret(baddie, frozen, clock); break; case AZ_BAD_HORNET: az_draw_bad_hornet(baddie, frozen, clock); break; case AZ_BAD_BEAM_SENSOR: az_draw_bad_beam_sensor(baddie, frozen, clock); break; case AZ_BAD_BEAM_SENSOR_INV: az_draw_bad_beam_sensor_inv(baddie, frozen, clock); break; case AZ_BAD_ROCKWYRM: az_draw_bad_rockwyrm(baddie); break; case AZ_BAD_WYRM_EGG: az_draw_bad_wyrm_egg(baddie, frozen, clock); break; case AZ_BAD_WYRMLING: az_draw_bad_wyrmling(baddie, frozen); break; case AZ_BAD_TRAPDOOR: glBegin(GL_TRIANGLE_FAN); { glColor3f(0.8f - 0.8f * frozen, 0.5, 0.5f + 0.5f * frozen); glVertex2f(0, 0); glColor3f(0.4f - 0.4f * frozen, 0.2, 0.2f + 0.3f * frozen); const az_polygon_t polygon = baddie->data->main_body.polygon; for (int i = polygon.num_vertices - 1, j = 0; i < polygon.num_vertices; i = j++) { glVertex2d(polygon.vertices[i].x, polygon.vertices[i].y); } } glEnd(); glPushMatrix(); { assert(!az_vnonzero(baddie->components[0].position)); glRotated(AZ_RAD2DEG(baddie->components[0].angle), 0, 0, 1); glBegin(GL_POLYGON); { const az_component_data_t *data = &baddie->data->components[0]; glColor3f(0.5f - 0.1f * frozen, 0.5, 0.5f + 0.1f * frozen); for (int i = 0; i < data->polygon.num_vertices; ++i) { if (i == 2) glColor3f(0.4f - 0.1f * frozen, 0.3, 0.3f + 0.1f * frozen); glVertex2d(data->polygon.vertices[i].x, data->polygon.vertices[i].y); } } glEnd(); } glPopMatrix(); break; case AZ_BAD_CAVE_SWOOPER: az_draw_bad_cave_swooper(baddie, frozen, clock); break; case AZ_BAD_ICE_CRAWLER: az_draw_bad_ice_crawler(baddie, frozen, clock); break; case AZ_BAD_BEAM_TURRET: az_draw_bad_beam_turret(baddie, frozen, clock); break; case AZ_BAD_OTH_CRAB_1: case AZ_BAD_OTH_CRAB_2: az_draw_bad_oth_crab(baddie, frozen, clock); break; case AZ_BAD_OTH_ORB_1: case AZ_BAD_OTH_ORB_2: az_draw_bad_oth_orb(baddie, frozen, clock); break; case AZ_BAD_OTH_SNAPDRAGON: az_draw_bad_oth_snapdragon(baddie, frozen, clock); break; case AZ_BAD_OTH_RAZOR_1: az_draw_bad_oth_razor_1(baddie, frozen, clock); break; case AZ_BAD_GUN_SENSOR: az_draw_bad_gun_sensor(baddie, frozen, clock); break; case AZ_BAD_SECURITY_DRONE: az_draw_bad_security_drone(baddie, frozen, clock); break; case AZ_BAD_SMALL_TRUCK: az_draw_bad_small_truck(baddie, frozen, clock); break; case AZ_BAD_HEAT_RAY: az_draw_bad_heat_ray(baddie, frozen, clock); break; case AZ_BAD_NUCLEAR_MINE: draw_mine_arms(18, flare, frozen); // Body: glBegin(GL_POLYGON); { glColor3f(0.65 + 0.3 * flare - 0.3 * frozen, 0.65 - 0.3 * flare, 0.5 - 0.3 * flare + 0.5 * frozen); for (int i = 0; i <= 360; i += 60) { glVertex2d(8 * cos(AZ_DEG2RAD(i)), 8 * sin(AZ_DEG2RAD(i))); } } glEnd(); glBegin(GL_QUAD_STRIP); { for (int i = 0; i <= 360; i += 60) { glColor3f(0.65 + 0.3 * flare - 0.3 * frozen, 0.65 - 0.3 * flare, 0.5 - 0.3 * flare + 0.5 * frozen); glVertex2d(8 * cos(AZ_DEG2RAD(i)), 8 * sin(AZ_DEG2RAD(i))); glColor3f(0.35f + 0.3f * flare, 0.35f, 0.15f + 0.3f * frozen); glVertex2d(12 * cos(AZ_DEG2RAD(i)), 12 * sin(AZ_DEG2RAD(i))); } } glEnd(); // Radiation symbol: if (baddie->state == 1 && az_clock_mod(2, 3, clock)) glColor3f(1, 0, 0); else glColor3f(0, 0, 0.5f * frozen); glBegin(GL_TRIANGLE_FAN); { glVertex2d(0, 0); for (int i = 0; i <= 360; i += 30) { glVertex2d(1.5 * cos(AZ_DEG2RAD(i)), 1.5 * sin(AZ_DEG2RAD(i))); } } glEnd(); for (int j = 60; j < 420; j += 120) { glBegin(GL_QUAD_STRIP); { for (int i = j - 30; i <= j + 30; i += 10) { glVertex2d(3 * cos(AZ_DEG2RAD(i)), 3 * sin(AZ_DEG2RAD(i))); glVertex2d(8 * cos(AZ_DEG2RAD(i)), 8 * sin(AZ_DEG2RAD(i))); } } glEnd(); } break; case AZ_BAD_BEAM_WALL: glBegin(GL_QUADS); { // Interior: glColor3f(0.3, 0.3, 0.3); glVertex2f(50, 15); glVertex2f(-50, 15); glVertex2f(-50, -15); glVertex2f(50, -15); // Diagonal struts: for (int i = 0; i < 3; ++i) { const float x = -50 + 32 * i; for (int j = 0; j < 2; ++j) { const float y = (j ? -12 : 12); glColor3f(0.75 + 0.25 * flare, 0.75, 0.75); glVertex2f(x, y); glVertex2f(x + 32, -y); glColor3f(0.35 + 0.35 * flare, 0.4, 0.35); glVertex2f(x + 32 + 4, -y); glVertex2f(x + 4, y); } } // Top and bottom struts: for (int y = -10; y <= 15; y += 25) { glColor3f(0.75 + 0.25 * flare, 0.75, 0.75); glVertex2f(52, y); glVertex2f(-52, y); glColor3f(0.35 + 0.35 * flare, 0.4, 0.35); glVertex2f(-52, y - 5); glVertex2f(52, y - 5); } } glEnd(); break; case AZ_BAD_SPARK: glBegin(GL_TRIANGLE_FAN); { glColor4f(1, 1, 1, 0.8); glVertex2f(0, 0); glColor4f(0, 1, 0, 0); for (int i = 0; i <= 360; i += 45) { const double radius = (i % 2 ? 1.0 : 0.5) * (8.0 + 0.25 * az_clock_zigzag(8, 3, clock)); const double theta = AZ_DEG2RAD(i + 7 * az_clock_mod(360, 1, clock)); glVertex2d(radius * cos(theta), radius * sin(theta)); } } glEnd(); break; case AZ_BAD_MOSQUITO: az_draw_bad_mosquito(baddie, frozen, clock); break; case AZ_BAD_ARMORED_ZIPPER: az_draw_bad_armored_zipper(baddie, frozen, clock); break; case AZ_BAD_FORCEFIEND: az_draw_bad_forcefiend(baddie); break; case AZ_BAD_CHOMPER_PLANT: az_draw_bad_chomper_plant(baddie, frozen, clock); break; case AZ_BAD_COPTER_HORZ: case AZ_BAD_COPTER_VERT: az_draw_bad_copter(baddie, frozen, clock); break; case AZ_BAD_URCHIN: az_draw_bad_urchin(baddie, frozen, clock); break; case AZ_BAD_BOSS_DOOR: az_draw_bad_boss_door(baddie, frozen, clock); break; case AZ_BAD_ROCKET_TURRET: az_draw_bad_rocket_turret(baddie, frozen, clock); break; case AZ_BAD_MINI_ARMORED_ZIPPER: az_draw_bad_mini_armored_zipper(baddie, frozen, clock); break; case AZ_BAD_SPINED_CRAWLER: az_draw_bad_spined_crawler(baddie, frozen, clock); break; case AZ_BAD_DEATH_RAY: az_draw_bad_death_ray(baddie, frozen, clock); break; case AZ_BAD_OTH_GUNSHIP: az_draw_bad_oth_gunship(baddie, frozen, clock); break; case AZ_BAD_FIREBALL_MINE: glPushMatrix(); { glScalef(1, 1.07, 1); const GLfloat blink = fmax(flare, (baddie->state == 1 && az_clock_mod(2, 4, clock) == 0 ? 0.5 : 0.0)); const double radius = baddie->data->main_body.bounding_radius; glBegin(GL_TRIANGLE_FAN); { glColor3f(0.6f + 0.4f * blink, 0.6f, 0.6f); glVertex2d(-0.15 * radius, 0.2 * radius); glColor3f(0.2f + 0.3f * blink, 0.2f, 0.2f); for (int i = 0; i <= 360; i += 15) { glVertex2d(radius * cos(AZ_DEG2RAD(i)), radius * sin(AZ_DEG2RAD(i))); } } glEnd(); const double hurt = (baddie->data->max_health - baddie->health) / baddie->data->max_health; for (int i = 0; i < 5; ++i) { const double angle = AZ_DEG2RAD(20) + i * AZ_DEG2RAD(72); az_draw_cracks(az_vpolar(-radius, angle), angle, 5 * hurt * (1.5 - 0.33 * ((3 * i) % 5))); } for (int i = 0; i < 10; ++i) { glBegin(GL_TRIANGLE_FAN); { glColor3f(0.4f + 0.3f * blink, 0.4f, 0.4f); glVertex2d(radius - 4, 0); glColor3f(0.2f + 0.3f * blink, 0.2f, 0.2f); glVertex2d(radius - 1, 2); glVertex2d(radius + 6, 0); glVertex2d(radius - 1, -2); } glEnd(); glRotatef(36, 0, 0, 1); } glRotatef(18, 0, 0, 1); for (int i = 0; i < 5; ++i) { glBegin(GL_TRIANGLE_FAN); { glColor3f(0.6f + 0.4f * blink, 0.6f, 0.6f); glVertex2d(radius - 9, 0); glColor3f(0.4f + 0.3f * blink, 0.4f, 0.4f); glVertex2d(radius - 8, 2); glVertex2d(radius - 3, 0); glVertex2d(radius - 8, -2); } glEnd(); glRotatef(72, 0, 0, 1); } } glPopMatrix(); break; case AZ_BAD_LEAPER: { const double tilt_degrees = (baddie->state != 0 ? 0.0 : (1.0 - fmin(baddie->cooldown / 0.5, 1.0)) * 10.0 + az_clock_zigzag(3, 8, clock)); // Legs: for (int flip = 0; flip < 2; ++flip) { glPushMatrix(); { if (flip) glScalef(1, -1, 1); // Upper leg: glPushMatrix(); { glTranslated(-0.5 * tilt_degrees, 0, 0); if (baddie->state == 0) glRotatef(48 - tilt_degrees, 0, 0, 1); else glRotatef(70, 0, 0, 1); glBegin(GL_QUAD_STRIP); { glColor3f(0, 0.2, 0.1); glVertex2d(0, 5); glVertex2d(21, 2); glColor3f(0, 0.3, 0.2); glVertex2d(0, 0); glVertex2d(23, 0); glColor3f(0, 0.2, 0.1); glVertex2d(0, -4); glVertex2d(21, -3); } glEnd(); } glPopMatrix(); // Lower leg: if (baddie->state == 0) { glTranslated(-20, 20 + az_clock_zigzag(3, 8, clock), 0); glRotated(-tilt_degrees, 0, 0, 1); } else { glTranslated(-30, 18, 0); glRotated(5, 0, 0, 1); } glBegin(GL_QUAD_STRIP); { glColor3f(0, 0.25, 0.1); glVertex2d(2, 5); glColor3f(0.25, 0.15, 0); glVertex2d(35, 4); glColor3f(0.5f * flare, 0.6, 0.4f + 0.6f * frozen); glVertex2d(0, 0); glColor3f(0.3f + 0.3f * flare, 0.2, frozen); glVertex2d(35, 0); glColor3f(0, 0.25, 0.1); glVertex2d(2, -6); glColor3f(0.25, 0.15, 0); glVertex2d(35, -4); } glEnd(); glBegin(GL_QUAD_STRIP); { glColor3f(0, 0.25, 0.1); glVertex2d(18, 6); glVertex2d(35, 4); glColor3f(0.5f * flare, 0.6f + 0.4f * flare, 0.4f + 0.6f * frozen); glVertex2d(16, 0); glVertex2d(35, 0); glColor3f(0, 0.25, 0.1); glVertex2d(18, -6); glVertex2d(35, -4); } glEnd(); // Foot: glBegin(GL_TRIANGLE_FAN); { glColor3f(0.5, 0.5, 0.5); glVertex2d(0, -1); glColor3f(0.2, 0.3, 0.3); for (int i = -105; i <= 105; i += 30) { glVertex2d(5 * cos(AZ_DEG2RAD(i)), 7 * sin(AZ_DEG2RAD(i)) - 1); } } glEnd(); // Knee knob: glTranslatef(35, 0, 0); glBegin(GL_TRIANGLE_FAN); { glColor3f(0.5f * flare, 0.6, 0.4 + 0.6f * frozen); glVertex2d(0, 0); glColor3f(0, 0.25, 0.1); for (int i = -135; i <= 135; i += 30) { glVertex2d(6 * cos(AZ_DEG2RAD(i)), 5 * sin(AZ_DEG2RAD(i))); } } glEnd(); // Knee spike: glBegin(GL_TRIANGLE_FAN); { glColor3f(0.5, 0.5, 0.5); glVertex2f(4, 0); glColor3f(0.25, 0.25, 0.25); glVertex2f(5, 2); glVertex2f(10, 0); glVertex2f(5, -2); } glEnd(); } glPopMatrix(); } glPushMatrix(); { glTranslated(-0.5 * tilt_degrees, 0, 0); // Teeth: const int x = (baddie->state == 0 ? 0 : 3); for (int y = -2; y <= 2; y += 4) { glBegin(GL_TRIANGLE_FAN); { glColor3f(0.5, 0.5, 0.5); glVertex2i(8 + x, y); glColor3f(0.25, 0.25, 0.25); glVertex2i(9 + x, 2 + y); glVertex2i(15 + x, y); glVertex2i(9 + x, -2 + y); } glEnd(); } // Body: glBegin(GL_TRIANGLE_FAN); { glColor3f(flare, 0.9, 0.5f + 0.5f * frozen); glVertex2d(-3, 0); glColor3f(0.5f * flare, 0.25, 0.1f + 0.9f * frozen); glVertex2d(-10, 0); for (int i = -135; i <= 135; i += 30) { glVertex2d(12 * cos(AZ_DEG2RAD(i)), 9 * sin(AZ_DEG2RAD(i))); } glVertex2d(-10, 0); } glEnd(); // Eye: glBegin(GL_POLYGON); { glColor4f(1, 0, 0, 0.4); glVertex2f(10, 1); glVertex2f(9, 2); glVertex2f(7, 0); glVertex2f(9, -2), glVertex2f(10, -1); } glEnd(); } glPopMatrix(); } break; case AZ_BAD_BOUNCER_90: az_draw_bad_bouncer_90(baddie, frozen, clock); break; case AZ_BAD_PISTON: az_draw_bad_piston(baddie, frozen, clock); break; case AZ_BAD_ARMORED_PISTON: case AZ_BAD_ARMORED_PISTON_EXT: az_draw_bad_armored_piston(baddie, frozen, clock); break; case AZ_BAD_INCORPOREAL_PISTON: case AZ_BAD_INCORPOREAL_PISTON_EXT: az_draw_bad_incorporeal_piston(baddie, frozen, clock); break; case AZ_BAD_CRAWLING_MORTAR: az_draw_bad_crawling_mortar(baddie, frozen, clock); break; case AZ_BAD_FIRE_ZIPPER: az_draw_bad_fire_zipper(baddie, frozen, clock); break; case AZ_BAD_SUPER_SPINER: az_draw_bad_super_spiner(baddie, frozen, clock); break; case AZ_BAD_HEAVY_TURRET: az_draw_bad_heavy_turret(baddie, frozen, clock); break; case AZ_BAD_ECHO_SWOOPER: az_draw_bad_echo_swooper(baddie, frozen, clock); break; case AZ_BAD_SUPER_HORNET: az_draw_bad_super_hornet(baddie, frozen, clock); break; case AZ_BAD_KILOFUGE: az_draw_bad_kilofuge(baddie, clock); break; case AZ_BAD_ICE_CRYSTAL: az_draw_bad_ice_crystal(baddie); break; case AZ_BAD_SWITCHER: az_draw_bad_switcher(baddie, frozen, clock); break; case AZ_BAD_FAST_BOUNCER: az_draw_bad_fast_bouncer(baddie, frozen, clock); break; case AZ_BAD_PROXY_MINE: draw_mine_arms(15, flare, frozen); // Body: glBegin(GL_TRIANGLE_FAN); { glColor3f(0.65 + 0.35 * flare - 0.3 * frozen, 0.65 - 0.3 * flare, 0.65 - 0.3 * flare + 0.35 * frozen); glVertex2f(0, 0); glColor3f(0.35 + 0.3 * flare - 0.15 * frozen, 0.35 - 0.15 * flare, 0.35 - 0.15 * flare + 0.3 * frozen); for (int i = 0; i <= 360; i += 15) { glVertex2d(7 * cos(AZ_DEG2RAD(i)), 7 * sin(AZ_DEG2RAD(i))); } } glEnd(); // Light bulb: glBegin(GL_TRIANGLE_FAN); { if (baddie->state == 1 && az_clock_mod(2, 3, clock)) { glColor3f(1, 0.6, 0.5); } else glColor3f(0.2, 0.2, 0.2); glVertex2f(0, 0); glColor3f(0, 0, 0); for (int i = 0; i <= 360; i += 20) { glVertex2d(3 * cos(AZ_DEG2RAD(i)), 3 * sin(AZ_DEG2RAD(i))); } } glEnd(); break; case AZ_BAD_NIGHTSHADE: az_draw_bad_nightshade(baddie, frozen, clock); break; case AZ_BAD_AQUATIC_CHOMPER: az_draw_bad_aquatic_chomper(baddie, frozen, clock); break; case AZ_BAD_SMALL_FISH: az_draw_bad_small_fish(baddie, frozen, clock); break; case AZ_BAD_NOCTURNE: az_draw_bad_nocturne(baddie, clock); break; case AZ_BAD_MYCOFLAKKER: az_draw_bad_mycoflakker(baddie, frozen, clock); break; case AZ_BAD_MYCOSTALKER: az_draw_bad_mycostalker(baddie, frozen, clock); break; case AZ_BAD_OTH_CRAWLER: az_draw_bad_oth_crawler(baddie, frozen, clock); break; case AZ_BAD_FIRE_CRAWLER: az_draw_bad_fire_crawler(baddie, frozen, clock); break; case AZ_BAD_JUNGLE_CRAWLER: az_draw_bad_jungle_crawler(baddie, frozen, clock); break; case AZ_BAD_FORCE_EGG: az_draw_bad_force_egg(baddie); break; case AZ_BAD_FORCELING: az_draw_bad_forceling(baddie, frozen, clock); break; case AZ_BAD_JUNGLE_CHOMPER: az_draw_bad_jungle_chomper(baddie, frozen, clock); break; case AZ_BAD_SMALL_AUV: az_draw_bad_small_auv(baddie, frozen, clock); break; case AZ_BAD_SENSOR_LASER: az_draw_bad_sensor_laser(baddie, frozen, clock); break; case AZ_BAD_ERUPTION: draw_eruption_bubble(10.0, 47, clock); glPushMatrix(); { glTranslatef(0, -9, 0); draw_eruption_bubble(5.0, 23, clock); } glPopMatrix(); glPushMatrix(); { glTranslatef(0, 8, 0); draw_eruption_bubble(6.0, 27, clock); } glPopMatrix(); break; case AZ_BAD_PYROFLAKKER: az_draw_bad_pyroflakker(baddie, frozen, clock); break; case AZ_BAD_PYROSTALKER: az_draw_bad_pyrostalker(baddie, frozen, clock); break; case AZ_BAD_DEMON_SWOOPER: az_draw_bad_demon_swooper(baddie, frozen, clock); break; case AZ_BAD_FIRE_CHOMPER: az_draw_bad_fire_chomper(baddie, frozen, clock); break; case AZ_BAD_GRABBER_PLANT: az_draw_bad_grabber_plant(baddie, frozen, clock); break; case AZ_BAD_POP_OPEN_TURRET: az_draw_bad_pop_open_turret(baddie, frozen, clock); break; case AZ_BAD_GNAT: az_draw_bad_gnat(baddie, frozen, clock); break; case AZ_BAD_CREEPY_EYE: az_draw_bad_creepy_eye(baddie, frozen, clock); break; case AZ_BAD_BOMB_SENSOR: az_draw_bad_bomb_sensor(baddie, frozen, clock); break; case AZ_BAD_ROCKET_SENSOR: az_draw_bad_rocket_sensor(baddie, frozen, clock); break; case AZ_BAD_SPIKED_VINE: az_draw_bad_spiked_vine(baddie, frozen, clock); break; case AZ_BAD_MAGBEEST_HEAD: az_draw_bad_magbeest_head(baddie, clock); break; case AZ_BAD_MAGBEEST_LEGS_L: az_draw_bad_magbeest_legs_l(baddie, clock); break; case AZ_BAD_MAGBEEST_LEGS_R: az_draw_bad_magbeest_legs_r(baddie, clock); break; case AZ_BAD_MAGMA_BOMB: az_draw_bad_magma_bomb(baddie, clock); break; case AZ_BAD_OTH_BRAWLER: az_draw_bad_oth_brawler(baddie, frozen, clock); break; case AZ_BAD_LARGE_FISH: az_draw_bad_large_fish(baddie, frozen, clock); break; case AZ_BAD_CRAB_CRAWLER: az_draw_bad_crab_crawler(baddie, frozen, clock); break; case AZ_BAD_SCRAP_METAL: az_draw_bad_scrap_metal(baddie); break; case AZ_BAD_RED_ATOM: az_draw_bad_red_atom(baddie, frozen, clock); break; case AZ_BAD_REFLECTION: az_draw_bad_reflection(baddie, clock); break; case AZ_BAD_OTH_MINICRAB: az_draw_bad_oth_minicrab(baddie, frozen, clock); break; case AZ_BAD_OTH_RAZOR_2: az_draw_bad_oth_razor_2(baddie, frozen, clock); break; case AZ_BAD_OTH_SUPERGUNSHIP: case AZ_BAD_OTH_DECOY: az_draw_bad_oth_supergunship(baddie, frozen, clock); break; case AZ_BAD_CENTRAL_NETWORK_NODE: az_draw_bad_central_network_node(baddie, clock); break; case AZ_BAD_OTH_TENTACLE: az_draw_bad_oth_tentacle(baddie, frozen, clock); break; } }
void az_draw_particle(const az_particle_t *particle, az_clock_t clock) { assert(particle->kind != AZ_PAR_NOTHING); assert(particle->age <= particle->lifetime); switch (particle->kind) { case AZ_PAR_NOTHING: AZ_ASSERT_UNREACHABLE(); case AZ_PAR_BOOM: glBegin(GL_TRIANGLE_FAN); { with_color_alpha(particle->color, 0); glVertex2d(0, 0); const double ratio = particle->age / particle->lifetime; with_color_alpha(particle->color, 1 - ratio * ratio); const double radius = particle->param1 * ratio; for (int i = 0; i <= 16; ++i) { glVertex2d(radius * cos(i * AZ_PI_EIGHTHS), radius * sin(i * AZ_PI_EIGHTHS)); } } glEnd(); break; case AZ_PAR_BEAM: { const double alpha = (particle->lifetime <= 0.0 ? 1.0 : 1.0 - particle->age / particle->lifetime); glBegin(GL_QUAD_STRIP); { with_color_alpha(particle->color, 0); glVertex2d(0, particle->param2); glVertex2d(particle->param1, particle->param2); with_color_alpha(particle->color, alpha); glVertex2d(0, 0); glVertex2d(particle->param1, 0); with_color_alpha(particle->color, 0); glVertex2d(0, -particle->param2); glVertex2d(particle->param1, -particle->param2); } glEnd(); glBegin(GL_TRIANGLE_FAN); { with_color_alpha(particle->color, alpha); glVertex2d(particle->param1, 0); with_color_alpha(particle->color, 0); for (int i = -90; i <= 90; i += 30) { glVertex2d(particle->param1 + particle->param2 * cos(AZ_DEG2RAD(i)) * 0.75, particle->param2 * sin(AZ_DEG2RAD(i))); } } glEnd(); } break; case AZ_PAR_CHARGED_BOOM: { const double factor = particle->age / particle->lifetime; const double major = sqrt(factor) * particle->param1; const double minor = (1 - factor) * particle->param2; const double alpha = 1 - factor; glBegin(GL_QUAD_STRIP); { const double outer = major + minor; for (int i = 0; i <= 360; i += 20) { with_color_alpha(particle->color, 0); glVertex2d(outer * cos(AZ_DEG2RAD(i)), outer * sin(AZ_DEG2RAD(i))); with_color_alpha(particle->color, alpha); glVertex2d(major * cos(AZ_DEG2RAD(i)), major * sin(AZ_DEG2RAD(i))); } } glEnd(); glBegin(GL_QUAD_STRIP); { const double inner = fmax(0, major - minor); const double beta = alpha * (1 - fmin(major, minor) / minor); for (int i = 0; i <= 360; i += 20) { with_color_alpha(particle->color, alpha); glVertex2d(major * cos(AZ_DEG2RAD(i)), major * sin(AZ_DEG2RAD(i))); with_color_alpha(particle->color, beta); glVertex2d(inner * cos(AZ_DEG2RAD(i)), inner * sin(AZ_DEG2RAD(i))); } } glEnd(); } break; case AZ_PAR_EMBER: glBegin(GL_TRIANGLE_FAN); { with_color_alpha(particle->color, 1); glVertex2f(0, 0); with_color_alpha(particle->color, 0); const double radius = particle->param1 * (1.0 - particle->age / particle->lifetime); for (int i = 0; i <= 360; i += 30) { glVertex2d(radius * cos(AZ_DEG2RAD(i)), radius * sin(AZ_DEG2RAD(i))); } } glEnd(); break; case AZ_PAR_EXPLOSION: glBegin(GL_QUAD_STRIP); { const double tt = 1.0 - particle->age / particle->lifetime; const double inner_alpha = tt * tt; const double outer_alpha = tt; const double inner_radius = particle->param1 * (1.0 - tt * tt * tt); const double outer_radius = particle->param1; for (int i = 0; i <= 360; i += 6) { const double c = cos(AZ_DEG2RAD(i)), s = sin(AZ_DEG2RAD(i)); with_color_alpha(particle->color, inner_alpha); glVertex2d(inner_radius * c, inner_radius * s); with_color_alpha(particle->color, outer_alpha); glVertex2d(outer_radius * c, outer_radius * s); } } glEnd(); break; case AZ_PAR_FIRE_BOOM: { const int i_step = 10; const double liveness = 1.0 - particle->age / particle->lifetime; const double x_radius = particle->param1; const double y_radius = particle->param1 * liveness; for (int i = 0; i < 180; i += i_step) { glBegin(GL_TRIANGLE_STRIP); { const int limit = 180 * liveness; for (int j = 0; j < limit; j += 20) { glColor4f(1.0, 0.75 * j / limit, 0.0, 0.35 + 0.25 * sin(AZ_DEG2RAD(i)) * sin(AZ_DEG2RAD(j)) - 0.35 * j / limit); const double x = x_radius * cos(AZ_DEG2RAD(j)); glVertex2d(x, y_radius * cos(AZ_DEG2RAD(i)) * sin(AZ_DEG2RAD(j))); glVertex2d(x, y_radius * cos(AZ_DEG2RAD(i + i_step)) * sin(AZ_DEG2RAD(j))); } glVertex2d(x_radius * cos(AZ_DEG2RAD(limit)), y_radius * cos(AZ_DEG2RAD(i + i_step/2)) * sin(AZ_DEG2RAD(limit))); } glEnd(); } } break; case AZ_PAR_ICE_BOOM: { const double t0 = particle->age / particle->lifetime; const double t1 = 1.0 - t0; glBegin(GL_TRIANGLE_FAN); { with_color_alpha(particle->color, 0); glVertex2f(0, 0); with_color_alpha(particle->color, t1 * t1 * t1); for (int i = 0; i <= 360; i += 6) { glVertex2d(particle->param1 * cos(AZ_DEG2RAD(i)), particle->param1 * sin(AZ_DEG2RAD(i))); } } glEnd(); glPushMatrix(); { const double rx = 0.65 * particle->param1; const double ry = sqrt(3.0) * rx / 3.0; const double cx = fmin(1, 4 * t0) * rx; for (int i = 0; i < 6; ++i) { glBegin(GL_TRIANGLE_FAN); { with_color_alpha(particle->color, t1); glVertex2d(cx, 0); with_color_alpha(particle->color, t1 * t1); glVertex2d(cx + rx, 0); glVertex2d(cx, ry); glVertex2d(cx - rx, 0); glVertex2d(cx, -ry); glVertex2d(cx + rx, 0); } glEnd(); glRotatef(60, 0, 0, 1); } } glPopMatrix(); } break; case AZ_PAR_LIGHTNING_BOLT: if (particle->age >= particle->param2) { const int num_steps = az_imax(2, round(particle->param1 / 10.0)); const double step = particle->param1 / num_steps; az_random_seed_t seed = { clock / 5, 194821.0 * particle->angle }; az_vector_t prev = {0, 0}; for (int i = 1; i <= num_steps; ++i) { const az_vector_t next = (i == num_steps ? (az_vector_t){particle->param1, 0} : (az_vector_t){3.0 * az_rand_sdouble(&seed) + i * step, 10.0 * az_rand_sdouble(&seed)}); const az_vector_t side = az_vwithlen(az_vrot90ccw(az_vsub(next, prev)), 4); glBegin(GL_TRIANGLE_STRIP); { with_color_alpha(particle->color, 0); az_gl_vertex(az_vadd(prev, side)); az_gl_vertex(az_vadd(next, side)); glColor4f(1, 1, 1, 0.5); az_gl_vertex(prev); az_gl_vertex(next); with_color_alpha(particle->color, 0); az_gl_vertex(az_vsub(prev, side)); az_gl_vertex(az_vsub(next, side)); } glEnd(); prev = next; } draw_bolt_glowball(particle->color, particle->param1, clock); } draw_bolt_glowball(particle->color, 0, clock); break; case AZ_PAR_OTH_FRAGMENT: glRotated(particle->age * AZ_RAD2DEG(particle->param2), 0, 0, 1); glBegin(GL_TRIANGLES); { const double radius = (particle->param1 >= 0.0 ? particle->param1 * (1.0 - particle->age / particle->lifetime) : -particle->param1 * (particle->age / particle->lifetime)); const az_color_t color = particle->color; for (int i = 0; i < 3; ++i) { const az_clock_t clk = clock + 2 * i; glColor4ub((az_clock_mod(6, 1, clk) < 3 ? color.r : color.r / 4), (az_clock_mod(6, 1, clk + 2) < 3 ? color.g : color.g / 4), (az_clock_mod(6, 1, clk + 4) < 3 ? color.b : color.b / 4), color.a); glVertex2d(radius * cos(AZ_DEG2RAD(i * 120)), radius * sin(AZ_DEG2RAD(i * 120))); } } glEnd(); break; case AZ_PAR_NPS_PORTAL: { const double progress = particle->age / particle->lifetime; const double scale = 1 - 2 * fabs(progress - 0.5); const double tscale = fmax(0, 1 - pow(2.25 * progress - 1.25, 2)); // Tendrils: for (int i = 0; i < 10; ++i) { const double theta = AZ_DEG2RAD(i * 36); const az_vector_t tip = az_vadd(az_vpolar(1.1 * particle->param1 * tscale, theta), az_vpolar(15 * tscale, particle->age * AZ_DEG2RAD(180) * ((i % 3) + 1))); const az_vector_t ctrl1 = az_vadd(az_vpolar(0.8 * particle->param1 * tscale, theta), az_vpolar(10 * sin(particle->age * AZ_DEG2RAD(400)), theta + AZ_HALF_PI)); const az_vector_t ctrl2 = az_vadd(az_vpolar(0.4 * particle->param1 * tscale, theta), az_vpolar(10 * cos(particle->age * AZ_DEG2RAD(400)), theta + AZ_HALF_PI)); az_draw_oth_tendril(AZ_VZERO, ctrl1, ctrl2, tip, 5 * tscale, 1.0f, clock); } // Portal: glBegin(GL_TRIANGLE_FAN); { const GLfloat r = (az_clock_mod(6, 1, clock) < 3 ? 1.0f : 0.25f); const GLfloat g = (az_clock_mod(6, 1, clock + 2) < 3 ? 1.0f : 0.25f); const GLfloat b = (az_clock_mod(6, 1, clock + 4) < 3 ? 1.0f : 0.75f); glColor4f(r, g, b, 1.0f); glVertex2f(0, 0); glColor4f(r, g, b, 0.15f); const double radius = particle->param1 * scale; for (int i = 0; i <= 360; i += 10) { glVertex2d(radius * cos(AZ_DEG2RAD(i)), radius * sin(AZ_DEG2RAD(i))); } } glEnd(); } break; case AZ_PAR_ROCK: glScaled(particle->param1, particle->param1, 1); glRotated(particle->age * AZ_RAD2DEG(particle->param2), 0, 0, 1); glBegin(GL_TRIANGLE_FAN); { const double progress = particle->age / particle->lifetime; const az_color_t black = {0, 0, 0, 255}; az_gl_color(az_transition_color(particle->color, black, progress)); glVertex2f(0, 0); az_gl_color(az_transition_color(particle->color, black, 0.7 + 0.3 * progress)); glVertex2f(4, 0); glVertex2f(1, 4); glVertex2f(-1, 5); glVertex2f(-2, 0); glVertex2f(-1, -2); glVertex2f(1, -3); glVertex2f(4, 0); } glEnd(); break; case AZ_PAR_SHARD: glScaled(particle->param1, particle->param1, 1); glRotated(particle->age * AZ_RAD2DEG(particle->param2), 0, 0, 1); glBegin(GL_TRIANGLES); { az_color_t color = particle->color; const double alpha = 1.0 - particle->age / particle->lifetime; with_color_alpha(color, alpha); glVertex2f(2, 3); color.r *= 0.6; color.g *= 0.6; color.b *= 0.6; with_color_alpha(color, alpha); glVertex2f(-2, 4); color.r *= 0.6; color.g *= 0.6; color.b *= 0.6; with_color_alpha(color, alpha); glVertex2f(0, -4); } glEnd(); break; case AZ_PAR_SPARK: glBegin(GL_TRIANGLE_FAN); { glColor4f(1, 1, 1, 0.8); glVertex2f(0, 0); with_color_alpha(particle->color, 0); const double radius = particle->param1 * (1.0 - particle->age / particle->lifetime); const double theta_offset = particle->param2 * particle->age; for (int i = 0; i <= 360; i += 45) { const double rho = (i % 2 ? 1.0 : 0.5) * radius; const double theta = AZ_DEG2RAD(i) + theta_offset; glVertex2d(rho * cos(theta), rho * sin(theta)); } } glEnd(); break; case AZ_PAR_SPLOOSH: glBegin(GL_TRIANGLE_FAN); { with_color_alpha(particle->color, 1); glVertex2f(0, 0); with_color_alpha(particle->color, 0); const GLfloat height = particle->param1 * sin(AZ_PI * particle->age / particle->lifetime); const GLfloat semiwidth = particle->param2; glVertex2f(0, semiwidth); glVertex2f(0.3f * height, 0.5f * semiwidth); glVertex2f(height, 0); glVertex2f(0.3f * height, -0.5f * semiwidth); glVertex2f(0, -semiwidth); glVertex2f(-0.05f * height, 0); glVertex2f(0, semiwidth); } glEnd(); break; case AZ_PAR_TRAIL: { const double scale = 1.0 - particle->age / particle->lifetime; const double alpha = scale * scale * scale; const double semiwidth = alpha * particle->param2; glBegin(GL_TRIANGLE_STRIP); { with_color_alpha(particle->color, 0); glVertex2d(0, semiwidth); glVertex2d(particle->param1, semiwidth); with_color_alpha(particle->color, alpha); glVertex2d(0, 0); glVertex2d(particle->param1, 0); with_color_alpha(particle->color, 0); glVertex2d(0, -semiwidth); glVertex2d(particle->param1, -semiwidth); } glEnd(); } break; } }
int main(int argc, char **argv) { az_init_sound_datas(); az_init_baddie_datas(); az_init_wall_datas(); az_register_gl_init_func(az_init_portrait_drawing); az_register_gl_init_func(az_init_wall_drawing); if (!load_scenario()) { printf("Failed to load scenario.\n"); return EXIT_FAILURE; } az_load_preferences(&preferences); az_load_saved_games(&planet, &saved_games); az_init_gui(preferences.fullscreen_on_startup, true); az_set_global_music_volume(preferences.music_volume); az_set_global_sound_volume(preferences.sound_volume); az_controller_t controller = AZ_CONTROLLER_TITLE; az_title_intro_t title_intro = AZ_TI_SHOW_INTRO; int saved_game_slot_index = 0; while (true) { switch (controller) { case AZ_CONTROLLER_TITLE: { const az_title_action_t action = az_title_event_loop(&planet, &saved_games, &preferences, title_intro); switch (action.kind) { case AZ_TA_QUIT: return EXIT_SUCCESS; case AZ_TA_START_GAME: controller = AZ_CONTROLLER_SPACE; saved_game_slot_index = action.slot_index; break; } } break; case AZ_CONTROLLER_SPACE: switch (az_space_event_loop(&planet, &saved_games, &preferences, saved_game_slot_index)) { case AZ_SA_EXIT_TO_TITLE: controller = AZ_CONTROLLER_TITLE; title_intro = AZ_TI_SKIP_INTRO; break; case AZ_SA_GAME_OVER: controller = AZ_CONTROLLER_GAME_OVER; break; case AZ_SA_VICTORY: controller = AZ_CONTROLLER_TITLE; title_intro = AZ_TI_PLANET_DEBRIS; break; } break; case AZ_CONTROLLER_GAME_OVER: switch (az_gameover_event_loop()) { case AZ_GOA_TRY_AGAIN: controller = AZ_CONTROLLER_SPACE; break; case AZ_GOA_RETURN_TO_TITLE: controller = AZ_CONTROLLER_TITLE; title_intro = AZ_TI_SKIP_INTRO; break; case AZ_GOA_QUIT: return EXIT_SUCCESS; } break; } } AZ_ASSERT_UNREACHABLE(); }