rdefeo 1 ano atrás
pai
commit
2c56dcedac
11 arquivos alterados com 130 adições e 41 exclusões
  1. 1 0
      assets/tables/05_Endless.json
  2. BIN
      images/Arcade_I.png
  3. BIN
      images/Arcade_L.png
  4. BIN
      images/Arcade_T.png
  5. 26 0
      notifications.cxx
  6. 2 0
      notifications.h
  7. 80 33
      pinball0.cxx
  8. 2 2
      pinball0.h
  9. 9 1
      table.cxx
  10. 6 5
      table.h
  11. 4 0
      table_parser.cxx

+ 1 - 0
assets/tables/05_Endless.json

@@ -3,6 +3,7 @@
     "lives": {
     "lives": {
         "value": 1
         "value": 1
     },
     },
+    "tilt_detect": false,
     "balls": [
     "balls": [
         {
         {
             "position": [ 600, 510 ],
             "position": [ 600, 510 ],

BIN
images/Arcade_I.png


BIN
images/Arcade_L.png


BIN
images/Arcade_T.png


+ 26 - 0
notifications.cxx

@@ -46,6 +46,32 @@ void notify_table_bump(void* ctx) {
     notification_message(app->notify, &nm_list);
     notification_message(app->notify, &nm_list);
 }
 }
 
 
+void notify_table_tilted(void* ctx) {
+    PinballApp* app = (PinballApp*)ctx;
+    int n = 0;
+
+    for(int i = 0; i < 2; i++) {
+        nm_list[n++] = &message_display_backlight_off;
+        if(app->settings.vibrate_enabled) {
+            nm_list[n++] = &message_vibro_on;
+        }
+        if(app->settings.led_enabled) {
+            nm_list[n++] = &message_red_255;
+        }
+        nm_list[n++] = &message_delay_500;
+
+        nm_list[n++] = &message_display_backlight_on;
+        if(app->settings.vibrate_enabled) {
+            nm_list[n++] = &message_vibro_off;
+        }
+        if(app->settings.led_enabled) {
+            nm_list[n++] = &message_red_0;
+        }
+    }
+    nm_list[n] = NULL;
+    notification_message(app->notify, &nm_list);
+}
+
 void notify_error_message(void* ctx) {
 void notify_error_message(void* ctx) {
     PinballApp* app = (PinballApp*)ctx;
     PinballApp* app = (PinballApp*)ctx;
     int n = 0;
     int n = 0;

+ 2 - 0
notifications.h

@@ -8,6 +8,8 @@
 
 
 void notify_ball_released(void* ctx);
 void notify_ball_released(void* ctx);
 void notify_table_bump(void* ctx);
 void notify_table_bump(void* ctx);
+void notify_table_tilted(void* ctx);
+
 void notify_error_message(void* ctx);
 void notify_error_message(void* ctx);
 void notify_game_over(void* ctx);
 void notify_game_over(void* ctx);
 
 

+ 80 - 33
pinball0.cxx

@@ -18,6 +18,8 @@
 #define GAME_FPS          30
 #define GAME_FPS          30
 #define MANUAL_ADJUSTMENT 20
 #define MANUAL_ADJUSTMENT 20
 #define IDLE_TIMEOUT      120 * 1000 // 120 seconds * 1000 ticks/sec
 #define IDLE_TIMEOUT      120 * 1000 // 120 seconds * 1000 ticks/sec
+#define BUMP_DELAY        2 * 1000 // 2 seconds
+#define BUMP_MAX          3
 
 
 void solve(PinballApp* pb, float dt) {
 void solve(PinballApp* pb, float dt) {
     Table* table = pb->table;
     Table* table = pb->table;
@@ -77,6 +79,9 @@ void solve(PinballApp* pb, float dt) {
         for(auto& b : table->balls) {
         for(auto& b : table->balls) {
             for(auto& o : table->objects) {
             for(auto& o : table->objects) {
                 if(o->physical && o->collide(b)) {
                 if(o->physical && o->collide(b)) {
+                    if(pb->game_mode == GM_Tilted) {
+                        continue;
+                    }
                     if(o->notification) {
                     if(o->notification) {
                         (*o->notification)(pb);
                         (*o->notification)(pb);
                     }
                     }
@@ -87,6 +92,9 @@ void solve(PinballApp* pb, float dt) {
             }
             }
             for(auto& f : table->flippers) {
             for(auto& f : table->flippers) {
                 if(f.collide(b)) {
                 if(f.collide(b)) {
+                    if(pb->game_mode == GM_Tilted) {
+                        continue;
+                    }
                     if(f.notification) {
                     if(f.notification) {
                         (*f.notification)(pb);
                         (*f.notification)(pb);
                     }
                     }
@@ -127,6 +135,9 @@ void solve(PinballApp* pb, float dt) {
             if(table->lives.value > 0) {
             if(table->lives.value > 0) {
                 // Reset our ball to it's starting position
                 // Reset our ball to it's starting position
                 table->balls = table->balls_initial;
                 table->balls = table->balls_initial;
+                if(pb->game_mode == GM_Tilted) {
+                    pb->game_mode = GM_Playing;
+                }
             } else {
             } else {
                 table->game_over = true;
                 table->game_over = true;
             }
             }
@@ -284,6 +295,37 @@ static void pinball_draw_callback(Canvas* const canvas, void* ctx) {
 
 
         pb->table->draw(canvas);
         pb->table->draw(canvas);
     } break;
     } break;
+    case GM_Tilted: {
+        pb->table->draw(canvas);
+
+        const int32_t y = 56;
+        const int border = 8;
+        canvas_set_color(canvas, ColorWhite);
+        canvas_draw_box(canvas, 16 - border, y - border, 32 + border * 2, 8 + border * 2);
+        canvas_set_color(canvas, ColorBlack);
+
+        bool display = furi_get_tick() % 1000 < 500;
+        if(display) {
+            canvas_draw_icon(canvas, 17, y, &I_Arcade_T);
+            canvas_draw_icon(canvas, 25, y, &I_Arcade_I);
+            canvas_draw_icon(canvas, 33, y, &I_Arcade_L);
+            canvas_draw_icon(canvas, 40, y, &I_Arcade_T);
+        }
+
+        int dots = 5;
+        int x_start = 16;
+        int x_gap = (48 - 16) / (dots - 1);
+        for(int x = 0; x < 5; x++, x_start += x_gap) {
+            if(x % 2 != display) {
+                canvas_draw_disc(canvas, x_start, 50, 2);
+                canvas_draw_disc(canvas, x_start, 70, 2);
+            } else {
+                canvas_draw_dot(canvas, x_start, 50);
+                canvas_draw_dot(canvas, x_start, 70);
+            }
+        }
+
+    } break;
     default:
     default:
         FURI_LOG_E(TAG, "Unknown Game Mode");
         FURI_LOG_E(TAG, "Unknown Game Mode");
         break;
         break;
@@ -315,7 +357,6 @@ PinballApp::PinballApp() {
 
 
     table = NULL;
     table = NULL;
     tick = 0;
     tick = 0;
-    gameStarted = false;
 
 
     game_mode = GM_TableSelect;
     game_mode = GM_TableSelect;
     keys[InputKeyUp] = false;
     keys[InputKeyUp] = false;
@@ -385,7 +426,7 @@ extern "C" int32_t pinball0_app(void* p) {
             if(event.type == InputTypePress || event.type == InputTypeLong ||
             if(event.type == InputTypePress || event.type == InputTypeLong ||
                event.type == InputTypeRepeat) {
                event.type == InputTypeRepeat) {
                 switch(event.key) {
                 switch(event.key) {
-                case InputKeyBack:
+                case InputKeyBack: // navigate to previous screen or exit
                     switch(app.game_mode) {
                     switch(app.game_mode) {
                     case GM_TableSelect:
                     case GM_TableSelect:
                         app.processing = false;
                         app.processing = false;
@@ -400,6 +441,10 @@ extern "C" int32_t pinball0_app(void* p) {
                     }
                     }
                     break;
                     break;
                 case InputKeyRight: {
                 case InputKeyRight: {
+                    if(app.game_mode == GM_Tilted) {
+                        break;
+                    }
+
                     app.keys[InputKeyRight] = true;
                     app.keys[InputKeyRight] = true;
 
 
                     if(app.settings.debug_mode && app.table->balls_released == false) {
                     if(app.settings.debug_mode && app.table->balls_released == false) {
@@ -420,6 +465,10 @@ extern "C" int32_t pinball0_app(void* p) {
                     }
                     }
                 } break;
                 } break;
                 case InputKeyLeft: {
                 case InputKeyLeft: {
+                    if(app.game_mode == GM_Tilted) {
+                        break;
+                    }
+
                     app.keys[InputKeyLeft] = true;
                     app.keys[InputKeyLeft] = true;
 
 
                     if(app.settings.debug_mode && app.table->balls_released == false) {
                     if(app.settings.debug_mode && app.table->balls_released == false) {
@@ -442,11 +491,27 @@ extern "C" int32_t pinball0_app(void* p) {
                 case InputKeyUp:
                 case InputKeyUp:
                     switch(app.game_mode) {
                     switch(app.game_mode) {
                     case GM_Playing:
                     case GM_Playing:
+                        app.game_mode = GM_Tilted;
+                        app.table->bump_count = 0;
+                        notify_table_tilted(&app);
+
                         if(event.type == InputTypePress) {
                         if(event.type == InputTypePress) {
-                            // we only set the key if it's a 'press' to ensure
-                            // a single table "bump"
-                            app.keys[InputKeyUp] = true;
-                            notify_table_bump(&app);
+                            // Table bump and Tilt tracking
+                            uint32_t current_tick = furi_get_tick();
+                            if(current_tick - app.table->last_bump >= BUMP_DELAY) {
+                                app.table->bump_count++;
+                                app.table->last_bump = current_tick;
+                                if(!app.table->tilt_detect_enabled ||
+                                   app.table->bump_count < BUMP_MAX) {
+                                    app.keys[InputKeyUp] = true;
+                                    notify_table_bump(&app);
+                                } else {
+                                    FURI_LOG_W(TAG, "TABLE TILTED!");
+                                    app.game_mode = GM_Tilted;
+                                    app.table->bump_count = 0;
+                                    notify_table_tilted(&app);
+                                }
+                            }
                         }
                         }
                         if(app.settings.debug_mode && app.table->balls_released == false) {
                         if(app.settings.debug_mode && app.table->balls_released == false) {
                             app.table->balls[0].p.y -= MANUAL_ADJUSTMENT;
                             app.table->balls[0].p.y -= MANUAL_ADJUSTMENT;
@@ -464,6 +529,7 @@ extern "C" int32_t pinball0_app(void* p) {
                         }
                         }
                         break;
                         break;
                     default:
                     default:
+                        FURI_LOG_W(TAG, "Table tilted, UP does nothing!");
                         break;
                         break;
                     }
                     }
                     break;
                     break;
@@ -494,7 +560,6 @@ extern "C" int32_t pinball0_app(void* p) {
                     switch(app.game_mode) {
                     switch(app.game_mode) {
                     case GM_Playing:
                     case GM_Playing:
                         if(!app.table->balls_released) {
                         if(!app.table->balls_released) {
-                            app.gameStarted = true;
                             app.table->balls_released = true;
                             app.table->balls_released = true;
                             notify_ball_released(&app);
                             notify_ball_released(&app);
                         }
                         }
@@ -538,53 +603,35 @@ extern "C" int32_t pinball0_app(void* p) {
                     break;
                     break;
                 }
                 }
             } else if(event.type == InputTypeRelease) {
             } else if(event.type == InputTypeRelease) {
-                switch(event.key) {
-                case InputKeyLeft: {
-                    app.keys[InputKeyLeft] = false;
+                if(event.key != InputKeyOk && event.key != InputKeyBack) {
+                    app.keys[event.key] = false;
                     for(auto& f : app.table->flippers) {
                     for(auto& f : app.table->flippers) {
-                        if(f.side == Flipper::LEFT) {
+                        if(event.key == InputKeyLeft && f.side == Flipper::LEFT) {
                             f.powered = false;
                             f.powered = false;
-                        }
-                    }
-                    break;
-                }
-                case InputKeyRight: {
-                    app.keys[InputKeyRight] = false;
-                    for(auto& f : app.table->flippers) {
-                        if(f.side == Flipper::RIGHT) {
+                        } else if(event.key == InputKeyRight && f.side == Flipper::RIGHT) {
                             f.powered = false;
                             f.powered = false;
                         }
                         }
                     }
                     }
-                    break;
-                }
-                case InputKeyUp:
-                    app.keys[InputKeyUp] = false;
-                    break;
-                case InputKeyDown:
-                    app.keys[InputKeyDown] = false;
-                    // TODO: release plunger?
-                    break;
-                default:
-                    break;
                 }
                 }
             }
             }
             // a key was pressed, reset idle counter
             // a key was pressed, reset idle counter
             app.idle_start = furi_get_tick();
             app.idle_start = furi_get_tick();
         }
         }
 
 
+        // update physics / motion
         solve(&app, dt);
         solve(&app, dt);
         for(auto& o : app.table->objects) {
         for(auto& o : app.table->objects) {
             o->step_animation();
             o->step_animation();
         }
         }
+
         // check game state
         // check game state
-        // if(app.game_mode == GM_Playing && app.table->lives.value == 0) {
         if(app.game_mode != GM_GameOver && app.table->game_over) {
         if(app.game_mode != GM_GameOver && app.table->game_over) {
-            FURI_LOG_W(TAG, "GAME OVER!");
+            FURI_LOG_I(TAG, "GAME OVER!");
             app.game_mode = GM_GameOver;
             app.game_mode = GM_GameOver;
             notify_game_over(&app);
             notify_game_over(&app);
         }
         }
 
 
-        // no keys pressed - we should clear all input keys?
+        // render
         view_port_update(view_port);
         view_port_update(view_port);
         furi_mutex_release(app.mutex);
         furi_mutex_release(app.mutex);
 
 

+ 2 - 2
pinball0.h

@@ -32,7 +32,8 @@ typedef enum GameMode {
     GM_Playing,
     GM_Playing,
     GM_GameOver,
     GM_GameOver,
     GM_Error,
     GM_Error,
-    GM_Settings
+    GM_Settings,
+    GM_Tilted
 } GameMode;
 } GameMode;
 
 
 class TableList {
 class TableList {
@@ -71,7 +72,6 @@ typedef struct PinballApp {
     Table* table; // data for the current table
     Table* table; // data for the current table
     uint32_t tick;
     uint32_t tick;
 
 
-    bool gameStarted;
     bool keys[4]; // which key was pressed?
     bool keys[4]; // which key was pressed?
     bool processing; // controls game loop and game objects
     bool processing; // controls game loop and game objects
     uint32_t idle_start; // tracks time of last key press
     uint32_t idle_start; // tracks time of last key press

+ 9 - 1
table.cxx

@@ -35,6 +35,15 @@ void Score::draw(Canvas* canvas) {
     }
     }
 }
 }
 
 
+Table::Table()
+    : game_over(false)
+    , balls_released(false)
+    , plunger(nullptr)
+    , tilt_detect_enabled(true)
+    , last_bump(furi_get_tick())
+    , bump_count(0) {
+}
+
 Table::~Table() {
 Table::~Table() {
     for(size_t i = 0; i < objects.size(); i++) {
     for(size_t i = 0; i < objects.size(); i++) {
         delete objects[i];
         delete objects[i];
@@ -216,7 +225,6 @@ bool table_load_table(void* ctx, size_t index) {
         pb->table = nullptr;
         pb->table = nullptr;
     }
     }
 
 
-    pb->gameStarted = false;
     switch(index) {
     switch(index) {
     case TABLE_SELECT:
     case TABLE_SELECT:
         pb->table = table_init_table_select(ctx);
         pb->table = table_init_table_select(ctx);

+ 6 - 5
table.h

@@ -54,11 +54,7 @@ public:
 // TODO: make this better? eh, it works for now...
 // TODO: make this better? eh, it works for now...
 class Table {
 class Table {
 public:
 public:
-    Table()
-        : game_over(false)
-        , balls_released(false)
-        , plunger(nullptr) {
-    }
+    Table();
 
 
     ~Table();
     ~Table();
 
 
@@ -74,6 +70,11 @@ public:
 
 
     Plunger* plunger;
     Plunger* plunger;
 
 
+    // table bump / tilt tracking
+    bool tilt_detect_enabled;
+    uint32_t last_bump;
+    uint32_t bump_count;
+
     void draw(Canvas* canvas);
     void draw(Canvas* canvas);
 };
 };
 
 

+ 4 - 0
table_parser.cxx

@@ -225,6 +225,10 @@ Table* table_load_table_from_file(PinballApp* pb, size_t index) {
                 table->lives.alignment = Lives::Vertical;
                 table->lives.alignment = Lives::Vertical;
             }
             }
         }
         }
+        const nx_json* tilt = nx_json_get(json, "tilt_detect");
+        if(tilt) {
+            table->tilt_detect_enabled = tilt->num.u_value > 0 ? true : false;
+        }
         const nx_json* score = nx_json_get(json, "score");
         const nx_json* score = nx_json_get(json, "score");
         if(score) {
         if(score) {
             table_file_parse_bool(score, "display", table->score.display);
             table_file_parse_bool(score, "display", table->score.display);