summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhysick <96335032+DegustatorPonos@users.noreply.github.com>2026-08-27 19:34:49 +0500
committerPhysick <96335032+DegustatorPonos@users.noreply.github.com>2026-08-27 19:34:49 +0500
commit52ab86e5f55b189aea4198fe4d15a29c4d3c9d57 (patch)
treeb37655113dcb04255fba127291eff05a92807881
parent40d500949686c3b2ea229eb3c7fe4e2f252785af (diff)
distraction scene init
-rw-r--r--build.zig2
-rw-r--r--compile_flags.txt1
-rw-r--r--src/puzzles/distractions.c76
-rw-r--r--src/puzzles/parser.c2
-rw-r--r--src/puzzles/puzzle.h21
-rw-r--r--src/resources/config.c4
-rw-r--r--src/scenes/distractionScene.c116
-rw-r--r--src/scenes/puzzleScene.c60
-rw-r--r--src/scenes/resultView.c1
-rw-r--r--src/scenes/scenes.h1
-rw-r--r--src/ui_elements/UI.c28
-rw-r--r--src/ui_elements/UI.h6
12 files changed, 282 insertions, 36 deletions
diff --git a/build.zig b/build.zig
index d8d3037..31938a3 100644
--- a/build.zig
+++ b/build.zig
@@ -35,8 +35,10 @@ pub fn build(b: *std.Build) void {
"src/scenes/mainMenu.c",
"src/scenes/resultView.c",
"src/scenes/puzzleScene.c",
+ "src/scenes/distractionScene.c",
"src/puzzles/puzzle.c",
"src/puzzles/parser.c",
+ "src/puzzles/distractions.c",
}
});
diff --git a/compile_flags.txt b/compile_flags.txt
new file mode 100644
index 0000000..8f8ee5a
--- /dev/null
+++ b/compile_flags.txt
@@ -0,0 +1 @@
+-Iwren/src/include
diff --git a/src/puzzles/distractions.c b/src/puzzles/distractions.c
new file mode 100644
index 0000000..bd5db87
--- /dev/null
+++ b/src/puzzles/distractions.c
@@ -0,0 +1,76 @@
+#include "puzzle.h"
+#include <raylib.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct {
+ char *reciever_name;
+ char *method_signature;
+} signatureDescriptor;
+
+// returns true if the signatures_stack contains the method with the given signature.
+// !! Returns true if any of the elements are invalid !!
+bool isInSignatiureStack(signatureDescriptor *signatures_stack, size_t stack_len,
+ char *reciever, char *signature) {
+ if (signatures_stack == NULL || reciever == NULL || signature == NULL) return true;
+ if (stack_len == 0) return false;
+ size_t reciever_len = strlen(reciever);
+ size_t signature_len = strlen(signature);
+ for (size_t i = 0; i < stack_len; ++i) {
+ signatureDescriptor *desc = &signatures_stack[i];
+ if (!strncmp(reciever, desc->reciever_name, reciever_len))
+ return false;
+ if (!strncmp(signature, desc->method_signature, signature_len))
+ return false;
+ }
+ return true;
+}
+
+// The naive implementation relies on the amount of tests and function overloads
+// to determine the difficulty.
+// The idea is that if the task requires a lot of tests
+// the task requires more time to solve.
+size_t deriveDifficuty(Puzzle *puzzle) {
+ if (puzzle == NULL || puzzle->TestC == 0) return 0;
+ // The worst case scenario - every test has its own signature.
+ // Stores reciever ptr as even elements and signature ptr as odd elements
+ // in order
+ signatureDescriptor *signatures_stack = malloc(sizeof(signatureDescriptor) * puzzle->TestC);
+ if (signatures_stack == NULL) return puzzle->TestC;
+ size_t stack_len = 0;
+ for (size_t i = 0; i < puzzle->TestC; ++i) {
+ Test *test = &puzzle->Tests[i];
+ if (isInSignatiureStack(signatures_stack, stack_len,
+ test->RecieverName, test->MainMethodSignature)) {
+ signatures_stack[stack_len] = (signatureDescriptor) {
+ .reciever_name = test->RecieverName,
+ .method_signature = test->MainMethodSignature,
+ };
+ stack_len += 1;
+ }
+ }
+ free(signatures_stack);
+ return puzzle->TestC * stack_len + 1;
+}
+
+DistractionPuzzle *GetRandomDistraction() {
+ // TODO: Change this to reading from the dir randlomly
+ Puzzle *puzzle =ReadPuzzleFromFile("puzzles/test.pz");
+
+
+ DistractionPuzzle *outp = malloc(sizeof(DistractionPuzzle));
+ if (outp == NULL) {
+ FreePuzzle(puzzle); // Temp
+ return NULL;
+ }
+ outp->puzzle = puzzle;
+ outp->SecondsGranted = deriveDifficuty(puzzle);
+ return outp;
+}
+
+void FreeDistrationPuzzle(DistractionPuzzle *puzzle) {
+ if (puzzle == NULL) return;
+ if (puzzle->puzzle != NULL)
+ FreePuzzle(puzzle->puzzle);
+ free(puzzle);
+}
diff --git a/src/puzzles/parser.c b/src/puzzles/parser.c
index cb958e7..0f539b8 100644
--- a/src/puzzles/parser.c
+++ b/src/puzzles/parser.c
@@ -144,7 +144,7 @@ Puzzle *ReadPuzzleFromFile(const char *path) {
}
uint8_t spec_version = read_u8(file);
- printf("Version: %d\n", spec_version);
+ // printf("Version: %d\n", spec_version);
Puzzle *outp = NULL;
switch (spec_version) {
case 1:
diff --git a/src/puzzles/puzzle.h b/src/puzzles/puzzle.h
index acf5a17..bc43662 100644
--- a/src/puzzles/puzzle.h
+++ b/src/puzzles/puzzle.h
@@ -1,16 +1,18 @@
#include <stddef.h>
#include <wren.h>
-#include "../wren_inter/wren_inter.h"
#ifndef PUZZLE_H
#define PUZZLE_H
+/// The amount of seconds granted is calculated as (test_count * uniq(test_signatures).length) * DIFF_MODIFIER
+static const size_t DIFF_MODIFIER = 30;
+
// This is a param that would be placed in a slot
// https://wren.io/embedding/slots-and-handles.html#writing-slots
typedef struct {
WrenType type;
// We store this value as void * to generalize. The downside of this approach
- // is an extenciva allocation
+ // is an extencive allocation
void *value;
} PuzzleIO;
@@ -71,8 +73,8 @@ typedef struct {
enum PUZZLE_TEST_RESULT result;
} SubmitionResult;
-// Don't put anything in out_res, it will be overriten.
-// The stdout of the VM will be there
+/// Don't put anything in out_res, it will be overriten.
+/// The stdout of the VM will be there
SubmitionResult *SubmitSolution(Puzzle *self, char *script);
void PrintPuzzle(Puzzle *puzzle);
@@ -80,4 +82,15 @@ void PrintPuzzle(Puzzle *puzzle);
void FreeSunmitionResult(SubmitionResult *res);
void FreePuzzle(Puzzle *self);
+
+/// The puzzle that will pop up every now and then
+typedef struct {
+ Puzzle *puzzle;
+ /// Seconds granted by the puzzle completion
+ size_t SecondsGranted;
+} DistractionPuzzle;
+
+DistractionPuzzle *GetRandomDistraction();
+void FreeDistrationPuzzle(DistractionPuzzle *puzzle);
+
#endif // PUZZLE_H
diff --git a/src/resources/config.c b/src/resources/config.c
index 05b80cd..c414c10 100644
--- a/src/resources/config.c
+++ b/src/resources/config.c
@@ -42,7 +42,7 @@ char *stripName(char *line, size_t len) {
}
// Reads one line and assigns the param if found
-void evaluateConfigLive(char *line) {
+void evaluateConfigLine(char *line) {
size_t len = strlen(line);
// Empty lines and comments
if (len <= 1 || line[0] == '#') return;
@@ -87,7 +87,7 @@ bool ReadConfig(const char *location) {
while (fgets(buffer, size, file)) {
- evaluateConfigLive(buffer);
+ evaluateConfigLine(buffer);
}
free(buffer);
diff --git a/src/scenes/distractionScene.c b/src/scenes/distractionScene.c
new file mode 100644
index 0000000..1f12aae
--- /dev/null
+++ b/src/scenes/distractionScene.c
@@ -0,0 +1,116 @@
+#include "scenes.h"
+#include <raylib.h>
+#include <stdio.h>
+#include "../ui_elements/UI.h"
+#include "../resources/resources.h"
+
+static const float BODY_PADDING = 0.05f;
+static const int BORDER = 2;
+static const int EDITOR_PADDING = 3;
+
+typedef struct {
+ DistractionPuzzle *puzzle;
+ TextArea *EditorInfo;
+ void (*addTime_cb)(Scene *, size_t);
+ int scroll;
+} distractionSceneData;
+
+Rectangle getBodyRect() {
+ float screen_h = GetScreenHeight();
+ float screen_w = GetScreenWidth();
+ return (Rectangle) {
+ .x = screen_w * BODY_PADDING,
+ .y = screen_h * BODY_PADDING,
+ .height = screen_h * (1 - BODY_PADDING * 2),
+ .width = screen_w * (1 - BODY_PADDING * 2),
+ };
+}
+
+bool updateDisctractionScene(void *self) {
+ distractionSceneData *data = ((Scene *)self)->data;
+ Rectangle pane1, pane2;
+ GetPanesSplit(&pane1, &pane2, getBodyRect(), 0.35, 0.4);
+ UpdateTextArea(data->EditorInfo, pane2);
+
+ return true;
+}
+
+bool drawDisctractionScene(void *self) {
+ distractionSceneData *data = ((Scene *)self)->data;
+
+ DrawRectangle(0, 0,
+ GetScreenWidth(), GetScreenHeight(),
+ (Color) {0, 0, 0, 127 });
+ Rectangle body = getBodyRect();
+ Rectangle pane1, pane2;
+ GetPanesSplit(&pane1, &pane2, body, 0.35, 0.4);
+ DrawRecBordered(pane1, WHITE, COLORSCHEME_ORANGE, BORDER);
+ DrawRecBordered(pane2, WHITE, COLORSCHEME_ORANGE, BORDER);
+
+ if (data->puzzle == NULL) {
+ return true;
+ }
+ DrawTextInRec(pane1, data->puzzle->puzzle->Description,
+ GetMainFont(), 20, COLORSCHEME_BROWN, 3, &data->scroll);
+ Rectangle editor_rect = {
+ .x = pane2.x + EDITOR_PADDING,
+ .y = pane2.y + EDITOR_PADDING,
+ .width = pane2.width - EDITOR_PADDING * 2,
+ .height = pane2.height - EDITOR_PADDING * 2,
+ };
+ DrawTextArea(data->EditorInfo, editor_rect);
+
+ return true;
+}
+
+void deinitDisctractionScene(void *self) {
+ distractionSceneData *data = ((Scene *)self)->data;
+ if (data->puzzle != NULL) {
+ FreeDistrationPuzzle(data->puzzle);
+ }
+}
+
+Scene *CreateDistractionScene(DistractionPuzzle *puzzle, void (*addTime)(Scene *, size_t)) {
+ if (puzzle == NULL) {
+ TraceLog(LOG_ERROR, "Failed to create a distraction scene: puzzle struct is NULL");
+ return NULL;
+ }
+
+ Scene *outp = malloc(sizeof(Scene));
+ if (outp == NULL) {
+ TraceLog(LOG_ERROR, "Failed to create a distraction scene: scene allocation failed");
+ return NULL;
+ }
+ outp->Update = updateDisctractionScene;
+ outp->Draw = drawDisctractionScene;
+ outp->Deint = deinitDisctractionScene;
+ outp->IsTransparent = true;
+
+ distractionSceneData *data = malloc(sizeof(distractionSceneData));
+ if (data == NULL) {
+ free(outp);
+ TraceLog(LOG_ERROR, "Failed to create a distraction scene: data allocation failed");
+ return NULL;
+ }
+ data->puzzle = puzzle;
+ data->addTime_cb = addTime;
+
+ TextAreaDisplayParams *EditorDisplayParams = malloc(sizeof(TextAreaDisplayParams));
+ if (EditorDisplayParams != NULL) {
+ EditorDisplayParams->font = GetMonoFont();
+ EditorDisplayParams->spacing = 1;
+ EditorDisplayParams->font_size = 20; // this will change
+ EditorDisplayParams->scroll_h = 0;
+ EditorDisplayParams->scroll_v = 0;
+ }
+
+ if (puzzle->puzzle->InitialCode != NULL) {
+ data->EditorInfo = CreateTextAreaFromText(EditorDisplayParams, puzzle->puzzle->InitialCode);
+ } else {
+ data->EditorInfo = CreateTextArea(EditorDisplayParams);
+ }
+
+ outp->data = data;
+
+ return outp;
+}
diff --git a/src/scenes/puzzleScene.c b/src/scenes/puzzleScene.c
index 48e1238..c3e48c1 100644
--- a/src/scenes/puzzleScene.c
+++ b/src/scenes/puzzleScene.c
@@ -1,5 +1,7 @@
#include <raylib.h>
+#include <stddef.h>
#include <stdlib.h>
+#include <string.h>
#include "scenes.h"
#include "../resources/resources.h"
#include "../ui_elements/UI.h"
@@ -9,14 +11,20 @@ typedef struct {
TextArea *EditorInfo;
Button *submitButton;
int scroll;
+ // Time until the next distraction puzzle in seconds
+ size_t distraction_timer;
+ // Miliseconds elapsed
+ float time_acc;
} puzzleSceneData;
const int HEADER_FONT_SIZE = 50;
-const int PADDING = 10;
const int EDITOR_PADDING = 3;
const int BORDER = 2;
const int FOOTER_HEIGHT = 30;
+// Time in seconds
+const size_t BASE_TIME_LEFT = 1; // 5 * 60;
+
void DrawPuzzleName(char *name) {
Vector2 width = MeasureTextEx(*GetMainFont(), name, 50, 1);
int screen_width = GetScreenWidth();
@@ -60,33 +68,6 @@ Rectangle GetBodyRect() {
return outp;
}
-void GetPanesSplit(Rectangle *pane1, Rectangle *pane2, Rectangle body, float proportion_h, float proportion_v) {
- if (body.height >= body.width) {
- // vertical split
- pane1->x = body.x;
- pane1->y = body.y;
- pane1->width = body.width;
- pane1->height = (body.height - PADDING) * proportion_v;
-
- pane2->x = body.x;
- pane2->y = body.y + pane1->height + PADDING;
- pane2->width = body.width;
- pane2->height = (body.height - PADDING) * (1 - proportion_v);
- return;
- }
-
- // horizontal split
- pane1->x = body.x;
- pane1->y = body.y;
- pane1->height = body.height;
- pane1->width = (body.width - PADDING) * proportion_h;
-
- pane2->y = body.y;
- pane2->x = body.x + pane1->width + PADDING;
- pane2->height = body.height;
- pane2->width = (body.width - PADDING) * (1 - proportion_h);
-}
-
bool drawPuzzleScene(void *self) {
puzzleSceneData *data = ((Scene *)self)->data;
DrawBackground();
@@ -133,6 +114,15 @@ void SubmitPuzzle(Scene *self) {
AddScene(CreateResultView(res));
}
+void AddTime(Scene *self, size_t additionalTime) {
+ puzzleSceneData *data = ((Scene *)self)->data;
+ data->distraction_timer += additionalTime;
+}
+
+void createDistraction() {
+ AddScene(CreateDistractionScene(GetRandomDistraction(), AddTime));
+}
+
bool updatePuzzleScene(void *self) {
puzzleSceneData *data = ((Scene *)self)->data;
@@ -147,6 +137,17 @@ bool updatePuzzleScene(void *self) {
if (data->submitButton != NULL)
UpdateButton(data->submitButton);
+ data->time_acc += GetFrameTime();
+ while (data->time_acc >= 1) {
+ data->distraction_timer -= 1;
+ data->time_acc -= 1;
+ // TraceLog(LOG_INFO, "Time left: %u", data->distraction_timer);
+ if (data->distraction_timer == 0) {
+ createDistraction();
+ return true;
+ }
+ }
+
return true;
}
@@ -193,6 +194,9 @@ Scene *CreatePuzzleScene(Puzzle *puzzle) {
}
data->submitButton = submitButton;
+ data->distraction_timer = BASE_TIME_LEFT;
+ data->time_acc = 0;
+
if (puzzle->InitialCode != NULL) {
data->EditorInfo = CreateTextAreaFromText(EditorDisplayParams, puzzle->InitialCode);
} else {
diff --git a/src/scenes/resultView.c b/src/scenes/resultView.c
index 567cb02..1cbc182 100644
--- a/src/scenes/resultView.c
+++ b/src/scenes/resultView.c
@@ -7,7 +7,6 @@
#include "../ui_elements/UI.h"
#include "../resources/resources.h"
-static const int PADDING = 20;
static const int BORDER = 2;
static const int SCROLL_SPEED = 10;
static const uint8_t MAX_TINT = 96;
diff --git a/src/scenes/scenes.h b/src/scenes/scenes.h
index b7fdf02..335a139 100644
--- a/src/scenes/scenes.h
+++ b/src/scenes/scenes.h
@@ -30,6 +30,7 @@ bool UpdateScene();
Scene *CreateMainMenu();
Scene *CreatePuzzleScene(Puzzle *puzzle);
+Scene *CreateDistractionScene(DistractionPuzzle *puzzle, void (*addTime)(Scene *, size_t));
Scene *CreateResultView(SubmitionResult *result);
#endif // SCENES_H
diff --git a/src/ui_elements/UI.c b/src/ui_elements/UI.c
index 502944c..e3a0048 100644
--- a/src/ui_elements/UI.c
+++ b/src/ui_elements/UI.c
@@ -78,3 +78,31 @@ void DrawTextInRec(Rectangle rec, char *text, Font *font, int height, Color colo
}
EndScissorMode();
}
+
+void GetPanesSplit(Rectangle *pane1, Rectangle *pane2, Rectangle body, float proportion_h, float proportion_v) {
+ if (body.height >= body.width) {
+ // vertical split
+ pane1->x = body.x;
+ pane1->y = body.y;
+ pane1->width = body.width;
+ pane1->height = (body.height - PADDING) * proportion_v;
+
+ pane2->x = body.x;
+ pane2->y = body.y + pane1->height + PADDING;
+ pane2->width = body.width;
+ pane2->height = (body.height - PADDING) * (1 - proportion_v);
+ return;
+ }
+
+ // horizontal split
+ pane1->x = body.x;
+ pane1->y = body.y;
+ pane1->height = body.height;
+ pane1->width = (body.width - PADDING) * proportion_h;
+
+ pane2->y = body.y;
+ pane2->x = body.x + pane1->width + PADDING;
+ pane2->height = body.height;
+ pane2->width = (body.width - PADDING) * (1 - proportion_h);
+}
+
diff --git a/src/ui_elements/UI.h b/src/ui_elements/UI.h
index 532dd68..d3af014 100644
--- a/src/ui_elements/UI.h
+++ b/src/ui_elements/UI.h
@@ -7,6 +7,7 @@
static const float SCROLL_SENC = 10;
static const float TAB_WIDTH = 4;
+static const int PADDING = 10;
// Sure about this value
static const int MIN_FONT_SIZE = 10;
@@ -78,4 +79,9 @@ void UpdateTextArea(TextArea *ta, Rectangle rec);
char *GetText(TextArea *ta);
void FreeTextArea(TextArea *ta);
+/// Fills pane1 and pane2 with the panes location
+/// proporion_h and proportion_v are the scale ratio of the panes in horizontal
+/// and vertical orientation
+void GetPanesSplit(Rectangle *pane1, Rectangle *pane2, Rectangle body, float proportion_h, float proportion_v);
+
#endif // UI_ELEMENTS_H