<commit_before>#include "ui_thread.h"
#include "player.h"
#include "time/sleep.h"
#include "time/ticks.h"
#include "load_opus.h"
#include "audio/audio.h"
#include "font.h"
#include "viewport.h"
#include "window_style.h"
#include <TurboJSON/value.h>
#include <TurboJSON/object.h>
#include <stdlib.h>
#include <stdio.h>

void unit_movement_selection_callback(struct Athena_ButtonArgList *args, struct Athena_MessageList *messages){
    struct Athena_SelectingPosition *const position = Athena_FindTypeInArgList(args, "destination");
    struct Athena_Unit *const unit = Athena_FindTypeInArgList(args, "source_unit");
    if(position && unit){
#ifndef NDEBUG
        printf("Moving unit %s to %i, %i\n", unit->clazz->name, position->x, position->y);
#endif        
        
    }

    if(position)
        free(position);
}

void unit_attack_selection_callback(struct Athena_ButtonArgList *args, struct Athena_MessageList *messages){
    struct Athena_SelectingPosition *const position = Athena_FindTypeInArgList(args, "destination");
    struct Athena_Unit *const unit = Athena_FindTypeInArgList(args, "source_unit");
    if(position && unit && position->unit){

#ifndef NDEBUG
        printf("Attacking unit %s at %i, %i, using unit %s at %i, %i\n", 
            unit->clazz->name, unit->x, unit->y, position->unit->clazz->name, position->x, position->y);
#endif        
        
    }

    if(position)
        free(position);
}

void unit_movement_callback(struct Athena_ButtonArgList *args, struct Athena_MessageList *messages){
    if(!args)
        return;
    else{
        struct Athena_GameState *const state = args->arg;

        if(state->ui.selection_arg)
            Athena_FreeButtonArgList(state->ui.selection_arg);

        Athena_CopyButtonArgList(&state->ui.selection_arg, args);
        
        state->ui.selection_callback = unit_movement_selection_callback;

        if(state->ui.positions_arg)
            Athena_FreeButtonArgList(state->ui.positions_arg);

        Athena_CopyButtonArgList(&state->ui.positions_arg, args);
        state->ui.positions_callback = Athena_MovementPositions;

    }
    Athena_CancelMenuCallback(args, messages);
}

void unit_attack_callback(struct Athena_ButtonArgList *args, struct Athena_MessageList *messages){
    if(!args)
        return;
    else{
        struct Athena_GameState *const state = args->arg;

        if(state->ui.selection_arg)
            Athena_FreeButtonArgList(state->ui.selection_arg);

        Athena_CopyButtonArgList(&state->ui.selection_arg, args);

        state->ui.selection_callback = unit_attack_selection_callback;

        if(state->ui.positions_arg)
            Athena_FreeButtonArgList(state->ui.positions_arg);

        Athena_CopyButtonArgList(&state->ui.positions_arg, args);
        state->ui.positions_callback = Athena_AttackRangePositions;

    }
    Athena_CancelMenuCallback(args, messages);
}

static const struct Athena_Button athena_move_button = { 0, 0, 64, 20, "Move", NULL, unit_movement_callback };
static const struct Athena_Button athena_attack_button = { 0, 0, 64, 20, "Attack", NULL, unit_attack_callback };
static const struct Athena_Button athena_build_button = { 0, 0, 64, 20, "Build Unit", NULL, Athena_CancelMenuCallback };

static struct Athena_Menu *athena_generate_unit_menu(struct Athena_GameState *arg, struct Athena_Unit *unit){
    struct Athena_Menu *unit_menu = malloc(sizeof(struct Athena_Menu));
    struct Athena_ButtonList * const buttons = unit_menu->buttons = malloc(sizeof(struct Athena_ButtonList)),
        * next = buttons->next = malloc(sizeof(struct Athena_ButtonList));

    if(unit->clazz->is_building){
        buttons->button = athena_build_button;        
    }
    else{
        buttons->button = athena_move_button;
        next->button = athena_attack_button;
        next->button.arg = Athena_DefaultButtonArgList(arg);
        Athena_AppendButtonArgList(next->button.arg, unit, "source_unit");
        next->next = malloc(sizeof(struct Athena_ButtonList));
        next = next->next;
    }
    buttons->button.arg = Athena_DefaultButtonArgList(arg);
    Athena_AppendButtonArgList(buttons->button.arg, unit, "source_unit");

    next->button = athena_cancel_button;

    next->button.arg = Athena_DefaultButtonArgList(arg);
    Athena_AppendButtonArgList(next->button.arg, unit, "source_unit");

    next->next = NULL;

    if(unit->clazz->is_building){    
        unit_menu->w = 120;   
        unit_menu->text = "Building Action";
        
    }
    else{
        unit_menu->w = 100;
        unit_menu->text = "Unit Action";
    }

    return unit_menu;
}

void Athena_UIThreadWrapper(void *that){
    Athena_UIThread(that);
}

int Athena_UIThread(struct Athena_GameState *that){

    while(Athena_UIThreadFrame(that)==0)
        Athena_MillisecondSleep(1);

    return 0;
}

static int athena_ui_process_buttons(struct Athena_GameState *that, struct Athena_ButtonList *buttons, const struct Athena_Event *event, struct Athena_MessageList *messages){
    if(!buttons){
        return 0;
    }
    else{
        if(
            (buttons->button.clicked = Athena_IsWithin(buttons->button, event->x, event->y) << 2) &&
            buttons->button.callback){
            if(that->ui.click_sound)
                Athena_SoundPlay(that->ui.click_sound);
            buttons->button.callback(buttons->button.arg, messages);
            return 1;
        }
        return athena_ui_process_buttons(that, buttons->next, event, messages);
    }
}

static int athena_process_selector(const struct Athena_Field *field, struct Athena_UI *ui, const struct Athena_Event *event, struct Athena_MessageList *messages){
    if(!ui->selection_callback)
        return 0;
    else{
        struct Athena_SelectingPosition *position = malloc(sizeof(struct Athena_SelectingPosition));
        int x, y;
        
        Athena_FieldPixelXYToTileXY(field, event->x - ui->camera_x, event->y - ui->camera_y, &x, &y);
        position->unit = Athena_FindUnitAt(field->units, position->x = x, position->y = y);
        Athena_AppendButtonArgList(ui->selection_arg, position, "destination");

        ui->selection_callback(ui->selection_arg, messages);

        ui->selection_callback = NULL;
        if(ui->selection_arg)
            Athena_FreeButtonArgList(ui->selection_arg);
        ui->selection_arg = NULL;

        ui->positions_callback = NULL;
        if(ui->positions_arg)
            Athena_FreeButtonArgList(ui->positions_arg);
        ui->positions_arg = NULL;
        
        return 1;
    }
}

static int athena_test_unit_index(struct Athena_UnitList *units, struct Athena_Unit *unit, int i){
    if(!units)
        return -1;
    else if(unit == &units->unit)
        return i;
    else
        return athena_test_unit_index(units->next, unit, i+1);
}

static int athena_ui_get_unit_menu(struct Athena_GameState *that, struct Athena_UnitList *units, const struct Athena_Event *event, struct Athena_MessageList *messages){
    if(!units)
        return 0;<commit_msg>Added check to limit selection callbacks<commit_after>#include "ui_thread.h"
#include "player.h"
#include "time/sleep.h"
#include "time/ticks.h"
#include "load_opus.h"
#include "audio/audio.h"
#include "font.h"
#include "viewport.h"
#include "window_style.h"
#include <TurboJSON/value.h>
#include <TurboJSON/object.h>
#include <stdlib.h>
#include <stdio.h>

void unit_movement_selection_callback(struct Athena_ButtonArgList *args, struct Athena_MessageList *messages){
    struct Athena_SelectingPosition *const position = Athena_FindTypeInArgList(args, "destination");
    struct Athena_Unit *const unit = Athena_FindTypeInArgList(args, "source_unit");
    if(position && unit){
#ifndef NDEBUG
        printf("Moving unit %s to %i, %i\n", unit->clazz->name, position->x, position->y);
#endif        
        
    }

    if(position)
        free(position);
}

void unit_attack_selection_callback(struct Athena_ButtonArgList *args, struct Athena_MessageList *messages){
    struct Athena_SelectingPosition *const position = Athena_FindTypeInArgList(args, "destination");
    struct Athena_Unit *const unit = Athena_FindTypeInArgList(args, "source_unit");
    if(position && unit && position->unit){

#ifndef NDEBUG
        printf("Attacking unit %s at %i, %i, using unit %s at %i, %i\n", 
            unit->clazz->name, unit->x, unit->y, position->unit->clazz->name, position->x, position->y);
#endif        
        
    }

    if(position)
        free(position);
}

void unit_movement_callback(struct Athena_ButtonArgList *args, struct Athena_MessageList *messages){
    if(!args)
        return;
    else{
        struct Athena_GameState *const state = args->arg;

        if(state->ui.selection_arg)
            Athena_FreeButtonArgList(state->ui.selection_arg);

        Athena_CopyButtonArgList(&state->ui.selection_arg, args);
        
        state->ui.selection_callback = unit_movement_selection_callback;

        if(state->ui.positions_arg)
            Athena_FreeButtonArgList(state->ui.positions_arg);

        Athena_CopyButtonArgList(&state->ui.positions_arg, args);
        state->ui.positions_callback = Athena_MovementPositions;

    }
    Athena_CancelMenuCallback(args, messages);
}

void unit_attack_callback(struct Athena_ButtonArgList *args, struct Athena_MessageList *messages){
    if(!args)
        return;
    else{
        struct Athena_GameState *const state = args->arg;

        if(state->ui.selection_arg)
            Athena_FreeButtonArgList(state->ui.selection_arg);

        Athena_CopyButtonArgList(&state->ui.selection_arg, args);

        state->ui.selection_callback = unit_attack_selection_callback;

        if(state->ui.positions_arg)
            Athena_FreeButtonArgList(state->ui.positions_arg);

        Athena_CopyButtonArgList(&state->ui.positions_arg, args);
        state->ui.positions_callback = Athena_AttackRangePositions;

    }
    Athena_CancelMenuCallback(args, messages);
}

static const struct Athena_Button athena_move_button = { 0, 0, 64, 20, "Move", NULL, unit_movement_callback };
static const struct Athena_Button athena_attack_button = { 0, 0, 64, 20, "Attack", NULL, unit_attack_callback };
static const struct Athena_Button athena_build_button = { 0, 0, 64, 20, "Build Unit", NULL, Athena_CancelMenuCallback };

static struct Athena_Menu *athena_generate_unit_menu(struct Athena_GameState *arg, struct Athena_Unit *unit){
    struct Athena_Menu *unit_menu = malloc(sizeof(struct Athena_Menu));
    struct Athena_ButtonList * const buttons = unit_menu->buttons = malloc(sizeof(struct Athena_ButtonList)),
        * next = buttons->next = malloc(sizeof(struct Athena_ButtonList));

    if(unit->clazz->is_building){
        buttons->button = athena_build_button;        
    }
    else{
        buttons->button = athena_move_button;
        next->button = athena_attack_button;
        next->button.arg = Athena_DefaultButtonArgList(arg);
        Athena_AppendButtonArgList(next->button.arg, unit, "source_unit");
        next->next = malloc(sizeof(struct Athena_ButtonList));
        next = next->next;
    }
    buttons->button.arg = Athena_DefaultButtonArgList(arg);
    Athena_AppendButtonArgList(buttons->button.arg, unit, "source_unit");

    next->button = athena_cancel_button;

    next->button.arg = Athena_DefaultButtonArgList(arg);
    Athena_AppendButtonArgList(next->button.arg, unit, "source_unit");

    next->next = NULL;

    if(unit->clazz->is_building){    
        unit_menu->w = 120;   
        unit_menu->text = "Building Action";
        
    }
    else{
        unit_menu->w = 100;
        unit_menu->text = "Unit Action";
    }

    return unit_menu;
}

void Athena_UIThreadWrapper(void *that){
    Athena_UIThread(that);
}

int Athena_UIThread(struct Athena_GameState *that){

    while(Athena_UIThreadFrame(that)==0)
        Athena_MillisecondSleep(1);

    return 0;
}

static int athena_ui_process_buttons(struct Athena_GameState *that, struct Athena_ButtonList *buttons, const struct Athena_Event *event, struct Athena_MessageList *messages){
    if(!buttons){
        return 0;
    }
    else{
        if(
            (buttons->button.clicked = Athena_IsWithin(buttons->button, event->x, event->y) << 2) &&
            buttons->button.callback){
            if(that->ui.click_sound)
                Athena_SoundPlay(that->ui.click_sound);
            buttons->button.callback(buttons->button.arg, messages);
            return 1;
        }
        return athena_ui_process_buttons(that, buttons->next, event, messages);
    }
}

static int athena_process_selector(const struct Athena_Field *field, struct Athena_UI *ui, const struct Athena_Event *event, struct Athena_MessageList *messages){
    if(!ui->selection_callback)
        return 0;
    else{
        struct Athena_SelectingPosition *position = malloc(sizeof(struct Athena_SelectingPosition));
        int x, y;
        
        struct Athena_PositionList *list = ui->positions_callback(ui->positions_arg);
        
        
        Athena_FieldPixelXYToTileXY(field, event->x - ui->camera_x, event->y - ui->camera_y, &x, &y);
        
        if(list){
            if(Athena_PositionInList(list, x, y)){

                position->unit = Athena_FindUnitAt(field->units, position->x = x, position->y = y);
                Athena_AppendButtonArgList(ui->selection_arg, position, "destination");

                ui->selection_callback(ui->selection_arg, messages);

            }
            Athena_FreePositionList(list);
        }

        ui->selection_callback = NULL;
        if(ui->selection_arg)
            Athena_FreeButtonArgList(ui->selection_arg);
        ui->selection_arg = NULL;

        ui->positions_callback = NULL;
        if(ui->positions_arg)
            Athena_FreeButtonArgList(ui->positions_arg);
        ui->positions_arg = NULL;
        
        return 1;
    }
}

static int athena_test_unit_index(struct Athena_UnitList *units, struct Athena_Unit *unit, int i){
    if(!units)
        return -1;
    else if(unit == &units->unit)
        return i;
    else
        return athena_test_unit_index(units->next, unit, i+1);
}

static int athena_ui_get_unit_menu(struct Athena_GameState *that, struct Athena_UnitList *units, const struct Athena_Event *event, struct Athena_MessageList *messages){
    if(!units)
        return 0;
{'fraction_non_alphanumeric': 0.11177867821713008, 'fraction_numerical': 0.0048903171719994415, 'mean_word_length': 3.408684939944564, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 187, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6091294', 'n_tokens_mistral': 4776, 'n_tokens_neox': 4462, 'n_words': 857}