]> git.mcshandy.xyz Git - assteroids/commitdiff
some adjustments
authorrandy <randy@mcshandy.xyz>
Sun, 3 Apr 2022 20:42:12 +0000 (16:42 -0400)
committerrandy <randy@mcshandy.xyz>
Sun, 3 Apr 2022 20:42:12 +0000 (16:42 -0400)
Makefile
game.cpp

index 47bb147fd82162f93e38505cf5df6f1c0fe060ae..de14bc89e78ab2b7b1258c4b942a0057387dcdfc 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,8 @@
-LIBS = -lraylib -lgdi32 -lwinmm
+LIBS = -lraylib
+WINLIBS = -lraylib -lgdi32 -lwinmm
 
 game: game.cpp
-       $(CXX) -static game.cpp $(LIBS) -o $@ 
+       $(CXX) -static game.cpp $(LIBS) -o assteroids
+
+win_game: game.cpp
+       $(CXX) -static game.cpp $(WINLIBS) -o assteroids.exe
index 10e7509dbb8f48366cdac8c2e27bb3bb5ca12635..3c9f704df815d36b6c037eefc1aa2c8b192b1de2 100644 (file)
--- a/game.cpp
+++ b/game.cpp
-#include <cstring>
-#include <math.h>
-#include <unistd.h>
-#include "assteroids.h"
-#include "powerups.hpp"
-#include "vectormath.hpp"
-
-void show_death_stats();
-void show_instructions();
-
-Vector2 flatten(Vector4 pV){
-    Vector2 stan = {pV.x, pV.y};
-    return stan;
-}
-
-Vector4 translate(Vector4 v1, Vector4 v2) {
-    Vector4 translation = {v1.x+v2.x, v1.y+v2.y, v1.y+v2.y, v1.z+v2.z};
-    return translation;
-}
-
-bool onscreen(Vector2 v) {
-    // Ensure v is still onscreen
-    return CheckCollisionPointRec(v, screenspace); 
-}
-
-void init_ship(){
-    ship_alive = true;
-    throttle = false;
-    score = 0;
-    nose.z = 270;
-    port.z = 55;
-    starboard.z = 125;
-    active_powerups = 0;
-    
-    nose.x = 0; nose.y = -15;
-    port.x = -10; port.y = 15;
-    starboard.x = 10; starboard.y = 15;
-    center.x = scrW/2; center.y = scrH/2;
-    ship_bearing = 0;
-    
-    memset(bullets, 0, sizeof(Vector4) * MAX_BULLETS);
-    memset(asteroids, 0, sizeof(Vector4) * MAX_ASTEROIDS);
-    memset(dead_ship, 0, sizeof(Vector4) * SHIP_DEBRIS);    
-    init_shotgun();
-    memset(&shotgun_box, 0, sizeof(Vector4));
-    memset(dead_astr, 0, sizeof(Vector4) * SHIP_DEBRIS * MAX_ASTEROIDS);
-    memset(&shield_pickup, 0, sizeof(Vector4));
-    memset(&bomb_proj, 0, sizeof(Vector4));
-    bomb_proj.w = -1;
-
-    bomb_kills = shotgun_kills = deaths_avoided = time_alive = 0;
-}
-
-void die(){
-    ship_alive = false;
-    disable_shield();
-    for(int i = 0; i < SHIP_DEBRIS; i++) {
-        if (!onscreen(flatten(dead_ship[i])))
-            continue;
-        dead_ship[i].x = center.x; dead_ship[i].y = center.y;
-        dead_ship[i].z = (360/SHIP_DEBRIS) * (i + 1);
-        dead_ship[i].w = 6;
-    }
-    disable_shotgun();
-    
-}
-
-void spin_ship(int az_delta){
-    nose.z += az_delta; port.z += az_delta; starboard.z += az_delta;
-    nose.x = cos(nose.z * (PI/180)) * 15;
-    nose.y = sin(nose.z * (PI/180)) * 15;
-
-    port.x = cos(port.z * (PI/180)) * 15;
-    port.y = sin(port.z * (PI/180)) * 15;
-    
-    starboard.x = cos(starboard.z * (PI/180)) * 15;
-    starboard.y = sin(starboard.z * (PI/180)) * 15;
-
-}
-
-void update_v4(Vector4* origin, Vector4* v_body, int speed){
-    Vector2 heading = v2_normal(flatten(*origin));
-    v_body->x += heading.x * (speed*throttle); 
-    v_body->y += heading.y * (speed*throttle);
-}
-
-void shoot(){
-    if(time(NULL) <= last_fire)
-        return;
-    for(int s = 0; s < 1 + (4 * (active_powerups & SHOTGUN)); s++) {
-        for(int i = 0; i < MAX_BULLETS; i++){
-            // find available bullet
-            if(bullets[i].w == 0) {
-                bullets[i].x = center.x;
-                bullets[i].y = center.y;
-                bullets[i].z = nose.z + bullet_offsets[s];
-                bullets[i].w = 1; 
-                PlaySound(sfx_shoot);
-                break;
-            }
-        }
-    }
-    if(active_powerups & SHOTGUN)
-        shotgun_blasts--;
-    if(shotgun_blasts == 0 && active_powerups & SHOTGUN)
-        disable_shotgun();
-    time(&last_fire);
-}
-
-void update_bullets(){
-    Vector4* b;
-    for(int i = 0; i < MAX_BULLETS; i++){
-        if(!onscreen(flatten(bullets[i])))
-            bullets[i].w = 0;
-        
-        if(bullets[i].w == 1) {
-            b = &bullets[i];
-            b->x += cos(b->z * (PI/180)) * 15;
-            b->y += sin(b->z * (PI/180)) * 15;
-            DrawCircleV(flatten(bullets[i]), 2, WHITE);
-            for(int a = 0; a < MAX_ASTEROIDS; a++) {
-                if(CheckCollisionPointCircle(flatten(bullets[i]), flatten(asteroids[a]), asteroids[a].w)) {
-                    asteroids[a].w = 0;
-                    bullets[i].w = 0;
-                    score++;
-                    explode_asteroid(&asteroids[a]);
-                    if((score%15 == 0) && score > 0 && bomb_proj.w == -1) {
-                        active_powerups |= BOMB;
-                    }
-                    if(active_powerups & SHOTGUN) {
-                        shotgun_kills++;
-                    }
-                    break;
-                }
-            } 
-        }
-    }
-}
-
-void spawn_astr() {
-    int heading = rand() % 360;
-    for(int i = 0; i < MAX_ASTEROIDS; i++){
-        // find available asteroid
-        // no size means you're fuckin dead, gyro
-        if(asteroids[i].w == 0) {
-            asteroids[i].z = heading; 
-            asteroids[i].w = rand() % 34 + 30; 
-            asteroids[i].x = (heading > 90 && heading < 270) ? scrW : 0; 
-            asteroids[i].y = (heading > 180 && heading < 360) ? scrH : 0; 
-            break;
-        }
-    }
-}
-
-void explode_ship() {
-    for (int i = 0; i < SHIP_DEBRIS; i++) {
-        DrawCircleLines(dead_ship[i].x, dead_ship[i].y, dead_ship[i].w, RED);
-        dead_ship[i].x += cos(dead_ship[i].z * (PI/180)) *3;
-        dead_ship[i].y += sin(dead_ship[i].z * (PI/180)) *3;
-    }
-}
-
-bool ship_collision(Vector4* body) {
-    return (
-            CheckCollisionPointCircle(flatten(translate(nose, center)), flatten(*body), body->w * 0.9f) ||
-            CheckCollisionPointCircle(flatten(translate(port, center)), flatten(*body), body->w * 0.9f) ||
-            CheckCollisionPointCircle(flatten(translate(starboard, center)), flatten(*body), body->w * 0.9f)
-            );
-
-}
-
-void update_astrs() {
-    Vector4* astr;
-    for(int i = 0; i < MAX_ASTEROIDS; i++) {
-        astr = &asteroids[i];
-        if(astr->w != 0) {
-            astr->x += cos(astr->z * (PI/180)) *3;
-            astr->y += sin(astr->z * (PI/180)) *3;
-            DrawPolyLines(flatten(*astr), 7, astr->w, 0, RAYWHITE);
-        }
-        if(!onscreen(flatten(*astr))) {
-            astr->w = 0;
-        }
-        if(CheckCollisionCircles(flatten(*astr), astr->w, flatten(bomb_proj), bomb_proj.w) && bomb_proj.w >= 16 && astr->w != 0 && ship_alive) {
-            astr->w = 0;
-            bomb_proj.z = -1; //stop moving the bomb and explode
-            bomb_proj.w +=16;
-            explode_asteroid(astr);
-            bomb_kills++;
-        }
-
-        if(ship_collision(astr) && ship_alive){
-            if((active_powerups & GOD) || debug_nodie) {
-                deaths_avoided++;
-                continue;
-            }
-            die();
-        }
-    }
-
-}
-
-int main(int argc, char** argv) {
-    int opts;
-
-    while((opts = getopt(argc, argv, "fsgb")) != -1) {
-        switch(opts) {
-            case 'f':
-                printf("turned on fps counter\n");
-                enable_fps = true;
-                break;
-            case 's':
-                debug_nodie = true;
-                break;
-            case 'g':
-                debug_shotgun = true;
-                break;
-            case 'b':
-                debug_bomb = true;
-                break;
-            case '?':
-            default:
-                break;
-        }
-
-    }
-
-    InitAudioDevice();
-    if(IsAudioDeviceReady()) {
-        sfx_shoot = LoadSound(SFX_SHOOT_FILE);
-        sfx_music = LoadSound(SFX_BGM_FILE);
-    }
-    asteroids = (Vector4*)malloc(sizeof(Vector4)*MAX_ASTEROIDS);
-    bullets = (Vector4*)malloc(sizeof(Vector4)*MAX_BULLETS);
-    dead_ship = (Vector4*)malloc(sizeof(Vector4) * SHIP_DEBRIS);
-
-    srand(time(NULL));
-    InitWindow(scrW, scrH, "Randy's Rowdy Rocket Roundup");
-    SetTargetFPS(50);
-    init_ship();
-    spin_ship(0);
-    while(!WindowShouldClose()){
-        BeginDrawing();
-        ClearBackground(Space);
-
-        if(IsKeyPressed('H')) {
-            paused = !paused;
-        }
-        if(paused) {
-            show_instructions();
-            PauseSound(sfx_music);
-            EndDrawing();
-            continue;
-        }
-
-        if((IsKeyDown('J') || IsKeyDown(KEY_LEFT)) && ship_alive) {
-            spin_ship(-4);
-        }
-        if((IsKeyDown('L') || IsKeyDown(KEY_RIGHT)) && ship_alive) {
-            spin_ship(4);
-        }
-        if((IsKeyPressed('I') || IsKeyPressed(KEY_UP)) && ship_alive) {
-            throttle = true;
-            SetSoundVolume(sfx_music, 0.5f);
-        }
-        if(IsKeyPressed('S') && ship_alive) {
-            shoot();
-        }
-        if(IsKeyPressed('R') && !ship_alive) {
-            init_ship();
-            spin_ship(0);
-            StopSound(sfx_music);
-        }
-        if(IsKeyPressed('A') && ((active_powerups & BOMB) || debug_bomb)) {
-            active_powerups ^= BOMB;
-            launch_bomb();
-        }
-
-        if(!onscreen(flatten(center)) && ship_alive)
-            die();
-
-        if(ship_alive) {
-            time_alive++;
-            update_v4(&nose, &center, 3);
-            DrawTriangleLines(
-                flatten(translate(nose, center)),
-                flatten(translate(port, center)),
-                flatten(translate(starboard, center)),
-                RAYWHITE);
-            astr_spawner = rand() & 1000 + 1;
-            if(active_powerups & GOD) {
-                DrawCircleSectorLines(flatten(center), 3*shield_hp, 0, 360, 6, SKYBLUE);
-                DrawCircleSectorLines(flatten(center), 2*shield_hp, 0, 360, 6, SKYBLUE);
-                if(time(NULL) > shield_spawn_time) {
-                    time(&shield_spawn_time);
-                    shield_hp--;
-                }
-                if(shield_hp <= 0)
-                    disable_shield();
-            }
-            if(bomb_proj.w >= 0)
-                update_bomb();
-            if(!throttle) {
-                DrawText("KILL TO LIVE", (scrW/2)-(MeasureText("KILL TO LIVE", 64)/2), (scrH/2)-128, 64, RED);
-                DrawText("LAUNCH TO START", (scrW/2)-(MeasureText("LAUNCH TO START", 32)/2), (scrH/2)+64, 32, RED);
-            }
-            if(active_powerups & BOMB && bomb_proj.w == -1) 
-                DrawCircleSectorLines(flatten(translate(nose, center)), 4.0f, 0, 360, 360, RED);
-            if(debug_shotgun)
-                enable_shotgun();
-        } else if(!(active_powerups & GOD)) {
-            DrawText("YOU DIED", (scrW/2)-(MeasureText("YOU DIED", 64)/2), (scrH/2)-64, 64, RED);
-            DrawText("FUCK YOU", (scrW/2)-(MeasureText("FUCK YOU", 16)/2), (scrH/2)-8, 16, RED);
-            explode_ship();
-            SetSoundVolume(sfx_music, .1);
-            show_death_stats();
-        }
-        if(throttle && astr_spawner > 989) {
-            spawn_astr();
-        }
-        update_bullets();
-        update_astrs();
-        update_explosions();
-        if(ship_alive && throttle && shotgun_box.w == 0 && (rand() % 10000) < 8 && !active_powerups & SHOTGUN)
-            init_shotgun(); //a little treat
-        if(shotgun_box.w == 1)
-            draw_shotgun();
-        if(shield_pickup.w > 0)
-            draw_shield_pickup();
-        DrawText("[H]elp", (scrW-MeasureText("[H]elp", 32)-32), scrH-34, 32, WHITE); 
-        DrawText(TextFormat("%d", score), 4, scrH-34, 32, WHITE);
-        if(enable_fps)
-            DrawFPS(0, 0);
-        EndDrawing();
-        if(throttle && !IsSoundPlaying(sfx_music)) {
-            PlaySound(sfx_music);
-        }
-
-    }
-    UnloadSound(sfx_shoot);
-    UnloadSound(sfx_music);
-
-    CloseAudioDevice();
-    CloseWindow();
-    free(bullets);
-    free(asteroids);
-    free(dead_ship);
-    
-    return 0;
-}
-
-//spawn a shield pickup at a dead asteroid
-void init_shield(Vector4* v) {
-    shield_pickup.x = v->x;
-    shield_pickup.y = v->y;
-    shield_pickup.w = 16;
-}
-void draw_shield_pickup() {
-    DrawRingLines(flatten(shield_pickup), shield_pickup.w, shield_pickup.w * 1.3, 0, 360, 6, SKYBLUE);
-    DrawRingLines(flatten(shield_pickup), shield_pickup.w/3, shield_pickup.w * 0.66, 0, 360, 6, SKYBLUE);
-    if(CheckCollisionPointCircle(flatten(center), flatten(shield_pickup), shield_pickup.w)) {
-        shield_pickup.w = 0;
-        enable_shield();
-    }
-}
-
-void enable_shield() {
-    memset(&shield_pickup, 0, sizeof(Vector4));
-    shield_hp = 9;
-    active_powerups |= GOD;
-    time(&shield_spawn_time);
-}
-
-void disable_shield() {
-    active_powerups ^= GOD;
-    shield_hp = 9;
-}
-
-void explode_asteroid(Vector4* astr) {
-    for(int i = 0; i < MAX_ASTEROIDS; i++) {
-        if(dead_astr[i][0].w == 0) {
-            for (int a = 0; a < SHIP_DEBRIS; a++) {
-                dead_astr[i][a].x = astr->x;
-                dead_astr[i][a].y = astr->y;
-                dead_astr[i][a].z = ((360/SHIP_DEBRIS) * a) + (360/(SHIP_DEBRIS*3));
-                dead_astr[i][a].w = 1;
-            }
-            if(shield_pickup.w == 0 && rand() % 30 < 2)
-                init_shield(astr);
-            break;
-        }
-    }
-}
-
-void update_explosions() {
-    int offscreen_bubbles = 0;
-    for(int i = 0; i < MAX_ASTEROIDS; i++) {
-        if(dead_astr[i][0].w == 1) {
-            for (int a = 0; a < SHIP_DEBRIS; a++) {
-                dead_astr[i][a].x += cos(dead_astr[i][a].z * (PI/180)) * 5;
-                dead_astr[i][a].y += sin(dead_astr[i][a].z * (PI/180)) * 5;
-                DrawCircleLines(dead_astr[i][a].x, dead_astr[i][a].y, 8, RAYWHITE);
-                if(!onscreen(flatten(dead_astr[i][a])))
-                    offscreen_bubbles++;
-                if(offscreen_bubbles == SHIP_DEBRIS-1)
-                    memset(&dead_astr[i], 0, sizeof(Vector4) * SHIP_DEBRIS);
-            }
-        }
-        offscreen_bubbles=0;
-    }
-    
-}
-
-void init_shotgun() {
-    int heading = rand() % 360;
-    shotgun_box.z = heading; 
-    shotgun_box.w = 1; 
-    shotgun_box.x = (heading > 90 && heading < 270) ? scrW : 0; 
-    shotgun_box.y = (heading > 180 && heading < 360) ? scrH : 0; 
-
-    memcpy(s_top_box, master_s_top_box, sizeof(Vector2)*4); memcpy(s_bot_box, master_s_bot_box, sizeof(Vector2)*4);
-    for(int i = 0; i < 4; i++) {
-        s_top_box[i].x += shotgun_box.x;
-        s_top_box[i].y += shotgun_box.y;
-        s_bot_box[i].x += shotgun_box.x;
-        s_bot_box[i].y += shotgun_box.y;
-    }
-}
-
-void update_shotgun() {
-    float xd = cos(shotgun_box.z * (PI/180)) *2;
-    float yd = sin(shotgun_box.z * (PI/180)) *2;
-    shotgun_box.x += xd;
-    shotgun_box.y += yd;
-
-    for(int i = 0; i < 4; i++) {
-        s_top_box[i].x += xd;
-        s_top_box[i].y += yd;
-        s_bot_box[i].x += xd;
-        s_bot_box[i].y += yd;
-    }
-
-    if(!onscreen(flatten(shotgun_box)))
-        shotgun_box.w = 0;
-    if(CheckCollisionPointCircle(flatten(center), flatten(shotgun_box), 32)) {
-        enable_shotgun();
-        shotgun_box.w = 0;
-    }
-}
-
-void draw_shotgun() {
-    update_shotgun();
-    DrawLineStrip(s_top_box, 4, WHITE);
-    DrawLineStrip(s_bot_box, 4, WHITE);
-    DrawText("S", shotgun_box.x-6, shotgun_box.y-8, 20, GOLD);
-}
-
-void launch_bomb() {
-    bomb_proj.x = flatten(translate(nose, center)).x;
-    bomb_proj.y = flatten(translate(nose, center)).y;
-    bomb_proj.z = nose.z; 
-    bomb_proj.w = 16;
-}
-
-void update_bomb() {
-    if(bomb_proj.z != -1) {
-        bomb_proj.x += cos(bomb_proj.z * (PI/180)) *6;
-        bomb_proj.y += sin(bomb_proj.z * (PI/180)) *6;
-    }
-    if(bomb_proj.w < 128) {
-        DrawPolyLines(flatten(bomb_proj), 8, bomb_proj.w, whrot, DARKPURPLE);
-        DrawPolyLines(flatten(bomb_proj), 8, bomb_proj.w * .8, -whrot, DARKPURPLE);
-        DrawPolyLines(flatten(bomb_proj), 8, bomb_proj.w * .5, whrot, DARKPURPLE);
-        whrot++;
-    } else if (bomb_proj.w >= 128 || (!onscreen(flatten(bomb_proj)) && bomb_proj.w != -1)) {
-        active_powerups ^= BOMB;
-        memset(&bomb_proj, 0, sizeof(Vector4));
-        bomb_proj.w = -1;
-    }
-    if (!onscreen(flatten(bomb_proj))) {
-        bomb_proj.w = -1;
-    }
-}
-
-void show_instructions() {
-    DrawText("I/UP : START", scrW/4, (scrH/2)-256, 32, RED);
-    DrawText("J/LEFT : TURN PORT", scrW/4, (scrH/2)-206, 32, RED);
-    DrawText("L/RIGHT : TURN STARBOARD", scrW/4, (scrH/2)-156, 32, RED);
-    DrawText("S : SHOOT", scrW/4, (scrH/2)-106, 32, RED);
-    DrawText("R : RESPAWN", scrW/4, (scrH/2)-56, 32, RED);
-    DrawText("A : WORMHOLE", scrW/4, (scrH/2)-6, 32, RED);
-    DrawText("H : UN/PAUSE", scrW/4, (scrH/2)+50, 32, RED);
-    
-    DrawText("Thanks raysan for Raylib", scrW/4, (scrH)-34, 16, WHITE);
-}
-
-void show_death_stats() {
-    DrawText(TextFormat("KILLS : %d", score), scrW/4, (scrH/2)+64, 24, RED);
-    DrawText(TextFormat("SHOTGUN KILLS : %d", shotgun_kills), scrW/4, (scrH/2)+96, 24, RED);
-    DrawText(TextFormat("WORMHOLE KILLS : %d", bomb_kills), scrW/4, (scrH/2)+128, 24, RED);
-    DrawText(TextFormat("DEATHS NOT DIED : %d", deaths_avoided), scrW/4, (scrH/2)+160, 24, RED);
-    DrawText(TextFormat("TIME ALIVE : %d SECONDS", time_alive/60), scrW/4, (scrH/2)+ 192, 24, RED);
-    DrawText(TextFormat("SUCKS : FUCKED"), scrW/4, (scrH/2)+224, 24, RED);
-    DrawText("[R] TO LIVE AND KILL AGAIN", (scrW/2)-MeasureText("[R] TO LIVE AND KILL AGAIN", 32)/2, (scrH/2)+266, 32, RED);
-}
+#include <cstring>\r
+#include <math.h>\r
+#include <unistd.h>\r
+#include "assteroids.h"\r
+#include "powerups.hpp"\r
+#include "vectormath.hpp"\r
+\r
+void show_death_stats();\r
+void show_instructions();\r
+\r
+Vector2 flatten(Vector4 pV){\r
+    Vector2 stan = {pV.x, pV.y};\r
+    return stan;\r
+}\r
+\r
+Vector4 translate(Vector4 v1, Vector4 v2) {\r
+    Vector4 translation = {v1.x+v2.x, v1.y+v2.y, v1.y+v2.y, v1.z+v2.z};\r
+    return translation;\r
+}\r
+\r
+bool onscreen(Vector2 v) {\r
+    // Ensure v is still onscreen\r
+    return CheckCollisionPointRec(v, screenspace);\r
+}\r
+\r
+void init_ship(){\r
+    ship_alive = true;\r
+    throttle = false;\r
+    score = 0;\r
+    nose.z = 270;\r
+    port.z = 55;\r
+    starboard.z = 125;\r
+    active_powerups = 0;\r
+\r
+    nose.x = 0; nose.y = -15;\r
+    port.x = -10; port.y = 15;\r
+    starboard.x = 10; starboard.y = 15;\r
+    center.x = scrW/2; center.y = scrH/2;\r
+    ship_bearing = 0;\r
+\r
+    memset(bullets, 0, sizeof(Vector4) * MAX_BULLETS);\r
+    memset(asteroids, 0, sizeof(Vector4) * MAX_ASTEROIDS);\r
+    memset(dead_ship, 0, sizeof(Vector4) * SHIP_DEBRIS);\r
+    init_shotgun();\r
+    memset(&shotgun_box, 0, sizeof(Vector4));\r
+    memset(dead_astr, 0, sizeof(Vector4) * SHIP_DEBRIS * MAX_ASTEROIDS);\r
+    memset(&shield_pickup, 0, sizeof(Vector4));\r
+    memset(&bomb_proj, 0, sizeof(Vector4));\r
+    bomb_proj.w = -1;\r
+\r
+    bomb_kills = shotgun_kills = deaths_avoided = time_alive = 0;\r
+}\r
+\r
+void die(){\r
+    ship_alive = false;\r
+    disable_shield();\r
+    for(int i = 0; i < SHIP_DEBRIS; i++) {\r
+        if (!onscreen(flatten(dead_ship[i])))\r
+            continue;\r
+        dead_ship[i].x = center.x; dead_ship[i].y = center.y;\r
+        dead_ship[i].z = (360/SHIP_DEBRIS) * (i + 1);\r
+        dead_ship[i].w = 6;\r
+    }\r
+    disable_shotgun();\r
+\r
+}\r
+\r
+void spin_ship(int az_delta){\r
+    nose.z += az_delta; port.z += az_delta; starboard.z += az_delta;\r
+    nose.x = cos(nose.z * (PI/180)) * 15;\r
+    nose.y = sin(nose.z * (PI/180)) * 15;\r
+\r
+    port.x = cos(port.z * (PI/180)) * 15;\r
+    port.y = sin(port.z * (PI/180)) * 15;\r
+\r
+    starboard.x = cos(starboard.z * (PI/180)) * 15;\r
+    starboard.y = sin(starboard.z * (PI/180)) * 15;\r
+\r
+}\r
+\r
+void update_v4(Vector4* origin, Vector4* v_body, int speed){\r
+    Vector2 heading = v2_normal(flatten(*origin));\r
+    v_body->x += heading.x * (speed*throttle);\r
+    v_body->y += heading.y * (speed*throttle);\r
+}\r
+\r
+void shoot(){\r
+    if(time(NULL) <= last_fire)\r
+        return;\r
+    for(int s = 0; s < 1 + (4 * (active_powerups & SHOTGUN)); s++) {\r
+        for(int i = 0; i < MAX_BULLETS; i++){\r
+            // find available bullet\r
+            if(bullets[i].w == 0) {\r
+                bullets[i].x = center.x;\r
+                bullets[i].y = center.y;\r
+                bullets[i].z = nose.z + bullet_offsets[s];\r
+                bullets[i].w = 1;\r
+                PlaySound(sfx_shoot);\r
+                break;\r
+            }\r
+        }\r
+    }\r
+    if(active_powerups & SHOTGUN)\r
+        shotgun_blasts--;\r
+    if(shotgun_blasts == 0 && active_powerups & SHOTGUN)\r
+        disable_shotgun();\r
+    time(&last_fire);\r
+}\r
+\r
+void update_bullets(){\r
+    Vector4* b;\r
+    for(int i = 0; i < MAX_BULLETS; i++){\r
+        if(!onscreen(flatten(bullets[i])))\r
+            bullets[i].w = 0;\r
+\r
+        if(bullets[i].w == 1) {\r
+            b = &bullets[i];\r
+            b->x += cos(b->z * (PI/180)) * 15;\r
+            b->y += sin(b->z * (PI/180)) * 15;\r
+            DrawCircleV(flatten(bullets[i]), 2, WHITE);\r
+            for(int a = 0; a < MAX_ASTEROIDS; a++) {\r
+                if(CheckCollisionPointCircle(flatten(bullets[i]), flatten(asteroids[a]), asteroids[a].w)) {\r
+                    asteroids[a].w = 0;\r
+                    bullets[i].w = 0;\r
+                    score++;\r
+                    explode_asteroid(&asteroids[a]);\r
+                    if((score%15 == 0) && score > 0 && bomb_proj.w == -1) {\r
+                        active_powerups |= BOMB;\r
+                    }\r
+                    if(active_powerups & SHOTGUN) {\r
+                        shotgun_kills++;\r
+                    }\r
+                    break;\r
+                }\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+void spawn_astr() {\r
+    int heading = rand() % 360;\r
+    for(int i = 0; i < MAX_ASTEROIDS; i++){\r
+        // find available asteroid\r
+        // no size means you're fuckin dead, gyro\r
+        if(asteroids[i].w == 0) {\r
+            asteroids[i].z = heading;\r
+            asteroids[i].w = rand() % 34 + 30;\r
+            asteroids[i].x = (heading > 90 && heading < 270) ? scrW : 0;\r
+            asteroids[i].y = (heading > 180 && heading < 360) ? scrH : 0;\r
+            break;\r
+        }\r
+    }\r
+}\r
+\r
+void explode_ship() {\r
+    for (int i = 0; i < SHIP_DEBRIS; i++) {\r
+        DrawCircleLines(dead_ship[i].x, dead_ship[i].y, dead_ship[i].w, RED);\r
+        dead_ship[i].x += cos(dead_ship[i].z * (PI/180)) *3;\r
+        dead_ship[i].y += sin(dead_ship[i].z * (PI/180)) *3;\r
+    }\r
+}\r
+\r
+bool ship_collision(Vector4* body) {\r
+    return (\r
+            CheckCollisionPointCircle(flatten(translate(nose, center)), flatten(*body), body->w * 0.9f) ||\r
+            CheckCollisionPointCircle(flatten(translate(port, center)), flatten(*body), body->w * 0.9f) ||\r
+            CheckCollisionPointCircle(flatten(translate(starboard, center)), flatten(*body), body->w * 0.9f)\r
+            );\r
+\r
+}\r
+\r
+void update_astrs() {\r
+    Vector4* astr;\r
+    for(int i = 0; i < MAX_ASTEROIDS; i++) {\r
+        astr = &asteroids[i];\r
+        if(astr->w != 0) {\r
+            astr->x += cos(astr->z * (PI/180)) *3;\r
+            astr->y += sin(astr->z * (PI/180)) *3;\r
+            DrawPolyLines(flatten(*astr), 7, astr->w, 0, RAYWHITE);\r
+        }\r
+        if(!onscreen(flatten(*astr))) {\r
+            astr->w = 0;\r
+        }\r
+        if(CheckCollisionCircles(flatten(*astr), astr->w, flatten(bomb_proj), bomb_proj.w) && bomb_proj.w >= 16 && astr->w != 0 && ship_alive) {\r
+            astr->w = 0;\r
+            bomb_proj.z = -1; //stop moving the bomb and explode\r
+            bomb_proj.w +=16;\r
+            explode_asteroid(astr);\r
+            bomb_kills++;\r
+        }\r
+\r
+        if(ship_collision(astr) && ship_alive){\r
+            if((active_powerups & GOD) || debug_nodie) {\r
+                deaths_avoided++;\r
+                continue;\r
+            }\r
+            die();\r
+        }\r
+    }\r
+\r
+}\r
+\r
+int main(int argc, char** argv) {\r
+    int opts;\r
+\r
+    while((opts = getopt(argc, argv, "fsgb")) != -1) {\r
+        switch(opts) {\r
+            case 'f':\r
+                printf("turned on fps counter\n");\r
+                enable_fps = true;\r
+                break;\r
+            case 's':\r
+                debug_nodie = true;\r
+                break;\r
+            case 'g':\r
+                debug_shotgun = true;\r
+                break;\r
+            case 'b':\r
+                debug_bomb = true;\r
+                break;\r
+            case '?':\r
+            default:\r
+                break;\r
+        }\r
+\r
+    }\r
+\r
+    InitAudioDevice();\r
+    if(IsAudioDeviceReady()) {\r
+        sfx_shoot = LoadSound(SFX_SHOOT_FILE);\r
+        sfx_music = LoadSound(SFX_BGM_FILE);\r
+    }\r
+    asteroids = (Vector4*)malloc(sizeof(Vector4)*MAX_ASTEROIDS);\r
+    bullets = (Vector4*)malloc(sizeof(Vector4)*MAX_BULLETS);\r
+    dead_ship = (Vector4*)malloc(sizeof(Vector4) * SHIP_DEBRIS);\r
+\r
+    srand(time(NULL));\r
+    InitWindow(scrW, scrH, "Randy's Rowdy Rocket Roundup");\r
+    SetTargetFPS(50);\r
+    init_ship();\r
+    spin_ship(0);\r
+    while(!WindowShouldClose()){\r
+        BeginDrawing();\r
+        ClearBackground(Space);\r
+\r
+        if(IsKeyPressed('H')) {\r
+            paused = !paused;\r
+        }\r
+        if(paused) {\r
+            show_instructions();\r
+            PauseSound(sfx_music);\r
+            EndDrawing();\r
+            continue;\r
+        }\r
+\r
+        if((IsKeyDown('J') || IsKeyDown(KEY_LEFT)) && ship_alive) {\r
+            spin_ship(-6);\r
+        }\r
+        if((IsKeyDown('L') || IsKeyDown(KEY_RIGHT)) && ship_alive) {\r
+            spin_ship(6);\r
+        }\r
+        if((IsKeyPressed('I') || IsKeyPressed(KEY_UP)) && ship_alive) {\r
+            throttle = true;\r
+            SetSoundVolume(sfx_music, 0.5f);\r
+        }\r
+        if(IsKeyPressed('S') && ship_alive) {\r
+            shoot();\r
+        }\r
+        if(IsKeyPressed('R') && !ship_alive) {\r
+            init_ship();\r
+            spin_ship(0);\r
+            StopSound(sfx_music);\r
+        }\r
+        if(IsKeyPressed('A') && ((active_powerups & BOMB) || debug_bomb)) {\r
+            active_powerups ^= BOMB;\r
+            launch_bomb();\r
+        }\r
+\r
+        if(!onscreen(flatten(center)) && ship_alive)\r
+            die();\r
+\r
+        if(ship_alive) {\r
+            time_alive++;\r
+            update_v4(&nose, &center, 4);\r
+            DrawTriangleLines(\r
+                flatten(translate(nose, center)),\r
+                flatten(translate(port, center)),\r
+                flatten(translate(starboard, center)),\r
+                RAYWHITE);\r
+            astr_spawner = rand() & 1000 + 1;\r
+            if(active_powerups & GOD) {\r
+                DrawCircleSectorLines(flatten(center), 3*shield_hp, 0, 360, 6, SKYBLUE);\r
+                DrawCircleSectorLines(flatten(center), 2*shield_hp, 0, 360, 6, SKYBLUE);\r
+                if(time(NULL) > shield_spawn_time) {\r
+                    time(&shield_spawn_time);\r
+                    shield_hp--;\r
+                }\r
+                if(shield_hp <= 0)\r
+                    disable_shield();\r
+            }\r
+            if(bomb_proj.w >= 0)\r
+                update_bomb();\r
+            if(!throttle) {\r
+                DrawText("KILL TO LIVE", (scrW/2)-(MeasureText("KILL TO LIVE", 64)/2), (scrH/2)-128, 64, RED);\r
+                DrawText("LAUNCH TO START", (scrW/2)-(MeasureText("LAUNCH TO START", 32)/2), (scrH/2)+64, 32, RED);\r
+            }\r
+            if(active_powerups & BOMB && bomb_proj.w == -1)\r
+                DrawCircleSectorLines(flatten(translate(nose, center)), 4.0f, 0, 360, 360, RED);\r
+            if(debug_shotgun)\r
+                enable_shotgun();\r
+        } else if(!(active_powerups & GOD)) {\r
+            DrawText("YOU DIED", (scrW/2)-(MeasureText("YOU DIED", 64)/2), (scrH/2)-64, 64, RED);\r
+            DrawText("FUCK YOU", (scrW/2)-(MeasureText("FUCK YOU", 16)/2), (scrH/2)-8, 16, RED);\r
+            explode_ship();\r
+            SetSoundVolume(sfx_music, .1);\r
+            show_death_stats();\r
+        }\r
+        if(throttle && astr_spawner > 989) {\r
+            spawn_astr();\r
+        }\r
+        update_bullets();\r
+        update_astrs();\r
+        update_explosions();\r
+        if(ship_alive && throttle && shotgun_box.w == 0 && (rand() % 10000) < 8 && !active_powerups & SHOTGUN)\r
+            init_shotgun(); //a little treat\r
+        if(shotgun_box.w == 1)\r
+            draw_shotgun();\r
+        if(shield_pickup.w > 0)\r
+            draw_shield_pickup();\r
+        DrawText("[H]elp", (scrW-MeasureText("[H]elp", 32)-32), scrH-34, 32, WHITE);\r
+        DrawText(TextFormat("%d", score), 4, scrH-34, 32, WHITE);\r
+        if(enable_fps)\r
+            DrawFPS(0, 0);\r
+        EndDrawing();\r
+        if(throttle && !IsSoundPlaying(sfx_music)) {\r
+            PlaySound(sfx_music);\r
+        }\r
+\r
+    }\r
+    UnloadSound(sfx_shoot);\r
+    UnloadSound(sfx_music);\r
+\r
+    CloseAudioDevice();\r
+    CloseWindow();\r
+    free(bullets);\r
+    free(asteroids);\r
+    free(dead_ship);\r
+\r
+    return 0;\r
+}\r
+\r
+//spawn a shield pickup at a dead asteroid\r
+void init_shield(Vector4* v) {\r
+    shield_pickup.x = v->x;\r
+    shield_pickup.y = v->y;\r
+    shield_pickup.w = 16;\r
+}\r
+void draw_shield_pickup() {\r
+    DrawRingLines(flatten(shield_pickup), shield_pickup.w, shield_pickup.w * 1.3, 0, 360, 6, SKYBLUE);\r
+    DrawRingLines(flatten(shield_pickup), shield_pickup.w/3, shield_pickup.w * 0.66, 0, 360, 6, SKYBLUE);\r
+    if(CheckCollisionPointCircle(flatten(center), flatten(shield_pickup), shield_pickup.w)) {\r
+        shield_pickup.w = 0;\r
+        enable_shield();\r
+    }\r
+}\r
+\r
+void enable_shield() {\r
+    memset(&shield_pickup, 0, sizeof(Vector4));\r
+    shield_hp = 9;\r
+    active_powerups |= GOD;\r
+    time(&shield_spawn_time);\r
+}\r
+\r
+void disable_shield() {\r
+    active_powerups ^= GOD;\r
+    shield_hp = 9;\r
+}\r
+\r
+void explode_asteroid(Vector4* astr) {\r
+    for(int i = 0; i < MAX_ASTEROIDS; i++) {\r
+        if(dead_astr[i][0].w == 0) {\r
+            for (int a = 0; a < SHIP_DEBRIS; a++) {\r
+                dead_astr[i][a].x = astr->x;\r
+                dead_astr[i][a].y = astr->y;\r
+                dead_astr[i][a].z = ((360/SHIP_DEBRIS) * a) + (360/(SHIP_DEBRIS*3));\r
+                dead_astr[i][a].w = 1;\r
+            }\r
+            if(shield_pickup.w == 0 && rand() % 30 < 2)\r
+                init_shield(astr);\r
+            break;\r
+        }\r
+    }\r
+}\r
+\r
+void update_explosions() {\r
+    int offscreen_bubbles = 0;\r
+    for(int i = 0; i < MAX_ASTEROIDS; i++) {\r
+        if(dead_astr[i][0].w == 1) {\r
+            for (int a = 0; a < SHIP_DEBRIS; a++) {\r
+                dead_astr[i][a].x += cos(dead_astr[i][a].z * (PI/180)) * 5;\r
+                dead_astr[i][a].y += sin(dead_astr[i][a].z * (PI/180)) * 5;\r
+                DrawCircleLines(dead_astr[i][a].x, dead_astr[i][a].y, 8, RAYWHITE);\r
+                if(!onscreen(flatten(dead_astr[i][a])))\r
+                    offscreen_bubbles++;\r
+                if(offscreen_bubbles == SHIP_DEBRIS-1)\r
+                    memset(&dead_astr[i], 0, sizeof(Vector4) * SHIP_DEBRIS);\r
+            }\r
+        }\r
+        offscreen_bubbles=0;\r
+    }\r
+\r
+}\r
+\r
+void init_shotgun() {\r
+    int heading = rand() % 360;\r
+    shotgun_box.z = heading;\r
+    shotgun_box.w = 1;\r
+    shotgun_box.x = (heading > 90 && heading < 270) ? scrW : 0;\r
+    shotgun_box.y = (heading > 180 && heading < 360) ? scrH : 0;\r
+\r
+    memcpy(s_top_box, master_s_top_box, sizeof(Vector2)*4); memcpy(s_bot_box, master_s_bot_box, sizeof(Vector2)*4);\r
+    for(int i = 0; i < 4; i++) {\r
+        s_top_box[i].x += shotgun_box.x;\r
+        s_top_box[i].y += shotgun_box.y;\r
+        s_bot_box[i].x += shotgun_box.x;\r
+        s_bot_box[i].y += shotgun_box.y;\r
+    }\r
+}\r
+\r
+void update_shotgun() {\r
+    float xd = cos(shotgun_box.z * (PI/180)) *2;\r
+    float yd = sin(shotgun_box.z * (PI/180)) *2;\r
+    shotgun_box.x += xd;\r
+    shotgun_box.y += yd;\r
+\r
+    for(int i = 0; i < 4; i++) {\r
+        s_top_box[i].x += xd;\r
+        s_top_box[i].y += yd;\r
+        s_bot_box[i].x += xd;\r
+        s_bot_box[i].y += yd;\r
+    }\r
+\r
+    if(!onscreen(flatten(shotgun_box)))\r
+        shotgun_box.w = 0;\r
+    if(CheckCollisionPointCircle(flatten(center), flatten(shotgun_box), 32)) {\r
+        enable_shotgun();\r
+        shotgun_box.w = 0;\r
+    }\r
+}\r
+\r
+void draw_shotgun() {\r
+    update_shotgun();\r
+    DrawLineStrip(s_top_box, 4, WHITE);\r
+    DrawLineStrip(s_bot_box, 4, WHITE);\r
+    DrawText("S", shotgun_box.x-6, shotgun_box.y-8, 20, GOLD);\r
+}\r
+\r
+void launch_bomb() {\r
+    bomb_proj.x = flatten(translate(nose, center)).x;\r
+    bomb_proj.y = flatten(translate(nose, center)).y;\r
+    bomb_proj.z = nose.z;\r
+    bomb_proj.w = 16;\r
+}\r
+\r
+void update_bomb() {\r
+    if(bomb_proj.z != -1) {\r
+        bomb_proj.x += cos(bomb_proj.z * (PI/180)) *6;\r
+        bomb_proj.y += sin(bomb_proj.z * (PI/180)) *6;\r
+    }\r
+    if(bomb_proj.w < 128) {\r
+        DrawPolyLines(flatten(bomb_proj), 8, bomb_proj.w, whrot, DARKPURPLE);\r
+        DrawPolyLines(flatten(bomb_proj), 8, bomb_proj.w * .8, -whrot, DARKPURPLE);\r
+        DrawPolyLines(flatten(bomb_proj), 8, bomb_proj.w * .5, whrot, DARKPURPLE);\r
+        whrot++;\r
+    } else if (bomb_proj.w >= 128 || (!onscreen(flatten(bomb_proj)) && bomb_proj.w != -1)) {\r
+        active_powerups ^= BOMB;\r
+        memset(&bomb_proj, 0, sizeof(Vector4));\r
+        bomb_proj.w = -1;\r
+    }\r
+    if (!onscreen(flatten(bomb_proj))) {\r
+        bomb_proj.w = -1;\r
+    }\r
+}\r
+\r
+void show_instructions() {\r
+    DrawText("I/UP : START", scrW/4, (scrH/2)-256, 32, RED);\r
+    DrawText("J/LEFT : TURN PORT", scrW/4, (scrH/2)-206, 32, RED);\r
+    DrawText("L/RIGHT : TURN STARBOARD", scrW/4, (scrH/2)-156, 32, RED);\r
+    DrawText("S : SHOOT", scrW/4, (scrH/2)-106, 32, RED);\r
+    DrawText("R : RESPAWN", scrW/4, (scrH/2)-56, 32, RED);\r
+    DrawText("A : WORMHOLE", scrW/4, (scrH/2)-6, 32, RED);\r
+    DrawText("H : UN/PAUSE", scrW/4, (scrH/2)+50, 32, RED);\r
+\r
+    DrawText("Thanks raysan for Raylib", scrW/4, (scrH)-34, 16, WHITE);\r
+}\r
+\r
+void show_death_stats() {\r
+    DrawText(TextFormat("KILLS : %d", score), scrW/4, (scrH/2)+64, 24, RED);\r
+    DrawText(TextFormat("SHOTGUN KILLS : %d", shotgun_kills), scrW/4, (scrH/2)+96, 24, RED);\r
+    DrawText(TextFormat("WORMHOLE KILLS : %d", bomb_kills), scrW/4, (scrH/2)+128, 24, RED);\r
+    DrawText(TextFormat("DEATHS NOT DIED : %d", deaths_avoided), scrW/4, (scrH/2)+160, 24, RED);\r
+    DrawText(TextFormat("TIME ALIVE : %d SECONDS", time_alive/60), scrW/4, (scrH/2)+ 192, 24, RED);\r
+    DrawText(TextFormat("SUCKS : FUCKED"), scrW/4, (scrH/2)+224, 24, RED);\r
+    DrawText("[R] TO LIVE AND KILL AGAIN", (scrW/2)-MeasureText("[R] TO LIVE AND KILL AGAIN", 32)/2, (scrH/2)+266, 32, RED);\r
+}\r