Esempio n. 1
0
void vs_handle_action(scene *scene, int action) {
    vs_local *local = scene_get_userdata(scene);
    if(dialog_is_visible(&local->too_pathetic_dialog)) {
        dialog_event(&local->too_pathetic_dialog, action);
    } else if(dialog_is_visible(&local->quit_dialog)) {
        dialog_event(&local->quit_dialog, action);
    } else {
        switch (action) {
            case ACT_KICK:
            case ACT_PUNCH:
                game_state_set_next(scene->gs, SCENE_ARENA0+local->arena);
                break;
            case ACT_UP:
            case ACT_LEFT:
                if(game_state_get_player(scene->gs, 1)->selectable) {
                    local->arena--;
                    if (local->arena < 0) {
                        local->arena =4;
                    }
                    object_select_sprite(&local->arena_select, local->arena);
                }
                break;
            case ACT_DOWN:
            case ACT_RIGHT:
                if(game_state_get_player(scene->gs, 1)->selectable) {
                    local->arena++;
                    if (local->arena > 4) {
                        local->arena = 0;
                    }
                    object_select_sprite(&local->arena_select, local->arena);
                }
                break;
        }
    }
}
Esempio n. 2
0
int vs_create(scene *scene) {
    // Init local data
    vs_local *local = malloc(sizeof(vs_local));
    scene_set_userdata(scene, local);
    game_player *player1 = game_state_get_player(scene->gs, 0);
    game_player *player2 = game_state_get_player(scene->gs, 1);

    snprintf(local->vs_str, 128, "%s VS. %s", lang_get(20+player1->pilot_id), lang_get(20+player2->pilot_id));

    animation *ani;

    palette *mpal = video_get_base_palette();
    palette_set_player_color(mpal, 0, player1->colors[2], 0);
    palette_set_player_color(mpal, 0, player1->colors[1], 1);
    palette_set_player_color(mpal, 0, player1->colors[0], 2);
    palette_set_player_color(mpal, 1, player2->colors[2], 0);
    palette_set_player_color(mpal, 1, player2->colors[1], 1);
    palette_set_player_color(mpal, 1, player2->colors[0], 2);
    video_force_pal_refresh();

    // HAR
    ani = &bk_get_info(&scene->bk_data, 5)->ani;
    object_create(&local->player1_har, scene->gs, vec2i_create(160,0), vec2f_create(0, 0));
    object_set_animation(&local->player1_har, ani);
    object_select_sprite(&local->player1_har, player1->har_id);

    object_create(&local->player2_har, scene->gs, vec2i_create(160,0), vec2f_create(0, 0));
    object_set_animation(&local->player2_har, ani);
    object_select_sprite(&local->player2_har, player2->har_id);
    object_set_direction(&local->player2_har, OBJECT_FACE_LEFT);
    object_set_pal_offset(&local->player2_har, 48);

    // PLAYER
    ani = &bk_get_info(&scene->bk_data, 4)->ani;
    object_create(&local->player1_portrait, scene->gs, vec2i_create(-10,150), vec2f_create(0, 0));
    object_set_animation(&local->player1_portrait, ani);
    object_select_sprite(&local->player1_portrait, player1->pilot_id);

    object_create(&local->player2_portrait, scene->gs, vec2i_create(330,150), vec2f_create(0, 0));
    object_set_animation(&local->player2_portrait, ani);
    object_select_sprite(&local->player2_portrait, player2->pilot_id);
    object_set_direction(&local->player2_portrait, OBJECT_FACE_LEFT);

    // clone the left side of the background image
    // Note! We are touching the scene-wide background surface!
    surface_sub(&scene->bk_data.background, // DST Surface
                &scene->bk_data.background, // SRC Surface
                160, 0, // DST
                0, 0, // SRC
                160, 200, // Size
                SUB_METHOD_MIRROR); // Flip the right side horizontally

    if (player2->selectable) {
        // player1 gets to choose, start at arena 0
        local->arena = 0;
    } else {
        // pick a random arena for 1 player mode
        local->arena = rand_int(5); // srand was done in melee
    }

    // Arena
    if(player2->selectable) {
        ani = &bk_get_info(&scene->bk_data, 3)->ani;
        object_create(&local->arena_select, scene->gs, vec2i_create(59,155), vec2f_create(0, 0));
        object_set_animation(&local->arena_select, ani);
        object_select_sprite(&local->arena_select, local->arena);
    }


    // SCIENTIST
    int scientistpos = rand_int(4);
    vec2i scientistcoord = spawn_position(scientistpos, 1);
    if (scientistpos % 2) {
        scientistcoord.x += 50;
    } else {
        scientistcoord.x -= 50;
    }
    object *o_scientist = malloc(sizeof(object));
    ani = &bk_get_info(&scene->bk_data, 8)->ani;
    object_create(o_scientist, scene->gs, scientistcoord, vec2f_create(0, 0));
    object_set_animation(o_scientist, ani);
    object_select_sprite(o_scientist, 0);
    object_set_direction(o_scientist, scientistpos % 2 ? OBJECT_FACE_LEFT : OBJECT_FACE_RIGHT);
    game_state_add_object(scene->gs, o_scientist, RENDER_LAYER_MIDDLE, 0, 0);

    // WELDER
    int welderpos = rand_int(6);
    // welder can't be on the same gantry or the same *side* as the scientist
    // he also can't be on the same 'level'
    // but he has 10 possible starting positions
    while ((welderpos % 2)  == (scientistpos % 2) || (scientistpos < 2 && welderpos < 2) || (scientistpos > 1 && welderpos > 1 && welderpos < 4)) {
        welderpos = rand_int(6);
    }
    object *o_welder = malloc(sizeof(object));
    ani = &bk_get_info(&scene->bk_data, 7)->ani;
    object_create(o_welder, scene->gs, spawn_position(welderpos, 0), vec2f_create(0, 0));
    object_set_animation(o_welder, ani);
    object_select_sprite(o_welder, 0);
    object_set_spawn_cb(o_welder, cb_vs_spawn_object, (void*)scene);
    object_set_destroy_cb(o_welder, cb_vs_destroy_object, (void*)scene);
    object_set_direction(o_welder, welderpos % 2 ? OBJECT_FACE_LEFT : OBJECT_FACE_RIGHT);
    game_state_add_object(scene->gs, o_welder, RENDER_LAYER_MIDDLE, 0, 0);

    // GANTRIES
    object *o_gantry_a = malloc(sizeof(object));
    ani = &bk_get_info(&scene->bk_data, 11)->ani;
    object_create(o_gantry_a, scene->gs, vec2i_create(0,0), vec2f_create(0, 0));
    object_set_animation(o_gantry_a, ani);
    object_select_sprite(o_gantry_a, 0);
    game_state_add_object(scene->gs, o_gantry_a, RENDER_LAYER_TOP, 0, 0);

    object *o_gantry_b = malloc(sizeof(object));
    object_create(o_gantry_b, scene->gs, vec2i_create(320,0), vec2f_create(0, 0));
    object_set_animation(o_gantry_b, ani);
    object_select_sprite(o_gantry_b, 0);
    object_set_direction(o_gantry_b, OBJECT_FACE_LEFT);
    game_state_add_object(scene->gs, o_gantry_b, RENDER_LAYER_TOP, 0, 0);

    // Background tex
    menu_background2_create(&local->arena_select_bg, 211, 50);

    // Quit Dialog
    dialog_create(&local->quit_dialog, DIALOG_STYLE_YES_NO, "ARE YOU SURE YOU WANT TO QUIT THIS GAME?", 72, 60);
    local->quit_dialog.userdata = scene;
    local->quit_dialog.clicked = vs_quit_dialog_clicked;

    // Too Pathetic Dialog
    char insult[512];
    snprintf(insult, 512, lang_get(748), "Veteran", "Major Kreissack");
    dialog_create(&local->too_pathetic_dialog, DIALOG_STYLE_OK, insult, 72, 60);
    local->too_pathetic_dialog.userdata = scene;
    local->too_pathetic_dialog.clicked = vs_too_pathetic_dialog_clicked;

    if (player2->pilot_id == 10 && settings_get()->gameplay.difficulty < 2) {
        // kriessack, but not on Veteran or higher
        dialog_show(&local->too_pathetic_dialog, 1);
    }

    // Callbacks
    scene_set_render_cb(scene, vs_render);
    scene_set_render_overlay_cb(scene, vs_render_overlay);
    scene_set_input_poll_cb(scene, vs_input_tick);
    scene_set_dynamic_tick_cb(scene, vs_dynamic_tick);
    scene_set_static_tick_cb(scene, vs_static_tick);
    scene_set_free_cb(scene, vs_free);

    // Pick renderer
    video_select_renderer(VIDEO_RENDERER_HW);

    return 0;
}
Esempio n. 3
0
void player_run(object *obj) {
    // Some vars for easier life
    player_animation_state *state = &obj->animation_state;
    player_sprite_state *rstate = &obj->sprite_state;
    if(state->finished) return;

    // Handle slide operation
    if(obj->slide_state.timer > 0) {
        obj->pos.x += obj->slide_state.vel.x;
        obj->pos.y += obj->slide_state.vel.y;
        obj->slide_state.timer--;
    }

    // Not sure what this does
    int run_ret;
    if(state->end_frame == UINT32_MAX) {
        run_ret = sd_stringparser_run(
            state->parser, 
            state->ticks - 1);
    } else {
        run_ret = sd_stringparser_run_frames(
            state->parser, 
            state->ticks - 1, 
            state->end_frame);
    }

    // Handle frame
    if(run_ret == 0) {
        // Handle frame switch
        sd_stringparser_frame *param = &state->parser->current_frame;
        sd_stringparser_frame n_param;
        sd_stringparser_frame *f = param;
        sd_stringparser_frame *n = &n_param;
        int real_frame = param->letter - 65;

        // Do something if animation is finished!
        if(param->is_animation_end) {
            if(state->repeat) {
                player_reset(obj);
                sd_stringparser_run(state->parser, state->ticks - 1);
                real_frame = param->letter - 65;
            } else if(obj->finish != NULL) {
                obj->cur_sprite = NULL;
                obj->finish(obj);
                return;
            } else {
                obj->cur_sprite = NULL;
                state->finished = 1;
                return;
            }
        }

        // If frame changed, do something
        if(param->id != state->previous) {
            player_clear_frame(obj);
            
            // Tick management
            if(isset(f, "d"))   {
                cmd_tickjump(obj, get(f, "d"));
                sd_stringparser_reset(state->parser);
            }
        
            // Animation management
            if(isset(f, "m") && state->spawn != NULL) {
                int mx = isset(f, "mx") ? get(f, "mx") : 0;
                int my = isset(f, "my") ? get(f, "my") : 0;
                int mg = isset(f, "mg") ? get(f, "mg") : 0;
                DEBUG("Spawning %d, with g = %d, pos = (%d,%d)", 
                    get(f, "m"), mg, mx, my);
                state->spawn(
                    obj, get(f, "m"), 
                    vec2i_create(mx, my), mg, 
                    state->spawn_userdata);
            }
            if(isset(f, "md") && state->destroy != NULL) { 
                state->destroy(obj, get(f, "md"), state->destroy_userdata);
            }

            // Music playback
            if(isset(f, "smo")) { 
                cmd_music_on(get(f, "smo"));
            }
            if(isset(f, "smf")) { 
                cmd_music_off();
            }

            // Sound playback
            if(isset(f, "s")) {
                float pitch = PITCH_DEFAULT;
                float volume = VOLUME_DEFAULT * (settings_get()->sound.sound_vol/10.0f);
                float panning = PANNING_DEFAULT;
                if(isset(f, "sf")) {
                    int p = clamp(get(f, "sf"), -16, 239);
                    pitch = clampf((p/239.0f)*3.0f + 1.0f, PITCH_MIN, PITCH_MAX);
                }
                if(isset(f, "l")) {
                    int v = clamp(get(f, "l"), 0, 100);
                    volume = (v / 100.0f) * (settings_get()->sound.sound_vol/10.0f);
                }
                if(isset(f, "sb")) {
                    panning = clamp(get(f, "sb"), -100, 100) / 100.0f;
                }
                int sound_id = obj->sound_translation_table[get(f, "s")] - 1;
                sound_play(sound_id, volume, panning, pitch);
            }

            // Blend mode stuff
            if(isset(f, "b1")) { rstate->method_flags &= 0x2000; }
            if(isset(f, "b2")) { rstate->method_flags &= 0x4000; }
            if(isset(f, "bb")) { 
                rstate->method_flags &= 0x0010; 
                rstate->blend_finish = get(f, "bb"); 
            }
            if(isset(f, "be")) { rstate->method_flags &= 0x0800; }
            if(isset(f, "bf")) { 
                rstate->method_flags &= 0x0001; 
                rstate->blend_finish = get(f, "bf"); 
            }
            if(isset(f, "bh")) { rstate->method_flags &= 0x0040; }
            if(isset(f, "bl")) { 
                rstate->method_flags &= 0x0008; 
                rstate->blend_finish = get(f, "bl"); 
            }
            if(isset(f, "bm")) { 
                rstate->method_flags &= 0x0100; 
                rstate->blend_finish = get(f, "bm"); 
            }
            if(isset(f, "bj")) { 
                rstate->method_flags &= 0x0400; 
                rstate->blend_finish = get(f, "bj"); 
            }
            if(isset(f, "bs")) { 
                rstate->blend_start = get(f, "bs"); 
            }
            if(isset(f, "bu")) { rstate->method_flags &= 0x8000; }
            if(isset(f, "bw")) { rstate->method_flags &= 0x0080; }
            if(isset(f, "bx")) { rstate->method_flags &= 0x0002; }

            // Palette tricks
            if(isset(f, "bpd")) { rstate->pal_ref_index = get(f, "bpd"); }
            if(isset(f, "bpn")) { rstate->pal_entry_count = get(f, "bpn"); }
            if(isset(f, "bps")) { rstate->pal_start_index = get(f, "bps"); }
            if(isset(f, "bpb")) { rstate->pal_begin = get(f, "bpb"); }
            if(isset(f, "bpd")) { rstate->pal_end = get(f, "bpd"); }
            if(isset(f, "bz"))  { rstate->pal_tint = get(f, "bz"); }

            // Handle movement
            if (isset(f, "v")) {
                int x = 0, y = 0;
                if(isset(f, "y-")) {
                    y = get(f, "y-") * -1;
                } else if(isset(f, "y+")) {
                    y = get(f, "y+");
                }
                if(isset(f, "x-")) {
                    x = get(f, "x-") * -1 * object_get_direction(obj);
                } else if(isset(f, "x+")) {
                    x = get(f, "x+") * object_get_direction(obj);
                }

                if (x || y) {
                    obj->vel.x += x;
                    obj->vel.y += y;
                }
            }
            // handle scaling on the Y axis
            if(isset(f, "y")) { 
                obj->y_percent = get(f, "y") / 100.0f; 
            }
            if (isset(f, "e")) {
                // x,y relative to *enemy's* position
                int x = 0, y = 0;
                if(isset(f, "y-")) {
                    y = get(f, "y-") * -1;
                } else if(isset(f, "y+")) {
                    y = get(f, "y+");
                }
                if(isset(f, "x-")) {
                    x = get(f, "x-") * -1 * object_get_direction(obj);
                } else if(isset(f, "x+")) {
                    x = get(f, "x+") * object_get_direction(obj);
                }

                float x_dist = dist(obj->pos.x, state->enemy_x + x);
                float y_dist = dist(obj->pos.y, state->enemy_y + y);
                obj->slide_state.timer = param->duration;
                obj->slide_state.vel.x = x_dist / (float)param->duration;
                obj->slide_state.vel.y = y_dist / (float)param->duration;
                DEBUG("Slide object %d for (x,y) = (%f,%f) for %d ticks.", 
                    obj->cur_animation->id,
                    obj->slide_state.vel.x, 
                    obj->slide_state.vel.y, 
                    param->duration);
            }
            if (isset(f, "v") == 0 && 
                isset(f, "e") == 0 && 
                (isset(f, "x+") || isset(f, "y+") || isset(f, "x-") || isset(f, "y-"))) {
                // check for relative X interleaving
                int x = 0, y = 0;
                if(isset(f, "y-")) {
                    y = get(f, "y-") * -1;
                } else if(isset(f, "y+")) {
                    y = get(f, "y+");
                }
                if(isset(f, "x-")) {
                    x = get(f, "x-") * -1 * object_get_direction(obj);
                } else if(isset(f, "x+")) {
                    x = get(f, "x+") * object_get_direction(obj);
                }

                obj->slide_state.timer = param->duration;
                obj->slide_state.vel.x = (float)x / (float)param->duration;
                obj->slide_state.vel.y = (float)y / (float)param->duration;
                DEBUG("Slide object %d for (x,y) = (%f,%f) for %d ticks.",
                    obj->cur_animation->id,
                    obj->slide_state.vel.x, 
                    obj->slide_state.vel.y, 
                    param->duration);
            }

            // Check if next frame contains X=nnn or Y=nnn 
            if(!param->is_final_frame) {
                sd_stringparser_peek(state->parser, param->id + 1, &n_param);
                int slide = 0;
                float xpos = obj->pos.x;
                float ypos = obj->pos.y;
                if(isset(n, "x=") || isset(n, "y=")) {
                    obj->slide_state.vel = vec2f_create(0,0);
                }
                if(isset(n, "x=")) {
                    slide = get(n, "x=");
                    if(object_get_direction(obj) == OBJECT_FACE_LEFT) {
                        // if the sprite is flipped horizontally, adjust the X coordinates
                        slide = 320 - slide;
                    }
                    if(slide != xpos) {
                        obj->slide_state.vel.x = dist(xpos, slide) / (float)param->duration;
                        obj->slide_state.timer = param->duration;
                        DEBUG("Slide object %d for X = %f for a total of %d ticks.", 
                            obj->cur_animation->id,
                            obj->slide_state.vel.x, 
                            param->duration);
                    }
                }
                if(isset(n, "y=")) { 
                    slide = get(n, "y=");
                    if(slide != ypos) {
                        obj->slide_state.vel.y = dist(ypos, slide) / (float)param->duration;
                        obj->slide_state.timer = param->duration;
                        DEBUG("Slide object %d for Y = %f for a total of %d ticks.", 
                            obj->cur_animation->id,
                            obj->slide_state.vel.y, 
                            param->duration);
                    }
                }
            }
            
            // Set render settings
            if(real_frame < 25) {
                object_select_sprite(obj, real_frame);
                if(obj->cur_sprite != NULL) {
                    rstate->duration = param->duration;
                    rstate->blendmode = isset(f, "br") ? BLEND_ADDITIVE : BLEND_ALPHA;
                    if(isset(f, "r")) {
                        rstate->flipmode ^= FLIP_HORIZONTAL;
                    }
                    if(isset(f, "f")) {
                        rstate->flipmode ^= FLIP_VERTICAL;
                    }
                }
            } else {
                obj->cur_sprite = NULL;
            }

        }
        state->previous = param->id;
    }

    // Animation ticks
    if(state->reverse) {
        state->ticks--;
    } else {
        state->ticks++;
    }

    // Sprite ticks
    rstate->timer++;
    
    // All done.
    return;
}
Esempio n. 4
0
// Init mechlab
int mechlab_create(scene *scene) {
    // Alloc
    mechlab_local *local = malloc(sizeof(mechlab_local));
    memset(local, 0, sizeof(mechlab_local));

    animation *bg_ani[3];

    // Init the background
    for(int i = 0; i < sizeof(bg_ani)/sizeof(animation*); i++) {
        sprite *spr = sprite_copy(animation_get_sprite(&bk_get_info(&scene->bk_data, 14)->ani, i));
        bg_ani[i] = create_animation_from_single(spr, spr->pos);
        object_create(&local->bg_obj[i], scene->gs, vec2i_create(0,0), vec2f_create(0,0));
        object_set_animation(&local->bg_obj[i], bg_ani[i]);
        object_select_sprite(&local->bg_obj[i], 0);
        object_set_repeat(&local->bg_obj[i], 1);
        object_set_animation_owner(&local->bg_obj[i], OWNER_OBJECT);
    }

    // Find last saved game ...
    game_player *p1 = game_state_get_player(scene->gs, 0);
    const char* last_name = settings_get()->tournament.last_name;
    if(last_name == NULL || strlen(last_name) == 0) {
        last_name = NULL;
    }

    // ... and attempt to load it, if one was found.
    if(last_name != NULL) {
        int ret = sg_load(&p1->pilot, last_name);
        if(ret != SD_SUCCESS) {
            PERROR("Could not load saved game for playername '%s': %s!", last_name, sd_get_error(ret));
            last_name = NULL;
        } else {
            DEBUG("Loaded savegame for playername '%s'.", last_name);
        }
    }

    // Either initialize a new tournament if no savegame is found,
    // or just show old savegame stats directly if it was.
    local->dashtype = DASHBOARD_NONE;
    if(last_name == NULL) {
        DEBUG("No previous savegame found");
    } else {
        DEBUG("Previous savegame found; loading as default.");
    }
    mechlab_select_dashboard(scene, local, DASHBOARD_STATS);

    // Create main menu
    local->frame = guiframe_create(0, 0, 320, 200);
    guiframe_set_root(local->frame, lab_menu_main_create(scene));
    guiframe_layout(local->frame);

    // Load HAR
    animation *initial_har_ani = &bk_get_info(&scene->bk_data, 15 + p1->pilot.har_id)->ani;
    local->mech = malloc(sizeof(object));
    object_create(local->mech, scene->gs, vec2i_create(0,0), vec2f_create(0,0));
    object_set_animation(local->mech, initial_har_ani);
    object_set_repeat(local->mech, 1);
    object_dynamic_tick(local->mech);

    // Set callbacks
    scene_set_userdata(scene, local);
    scene_set_input_poll_cb(scene, mechlab_input_tick);
    scene_set_event_cb(scene, mechlab_event);
    scene_set_render_cb(scene, mechlab_render);
    scene_set_free_cb(scene, mechlab_free);
    scene_set_dynamic_tick_cb(scene, mechlab_tick);

    // Pick renderer
    video_select_renderer(VIDEO_RENDERER_HW);

    return 0;
}
Esempio n. 5
0
int cutscene_create(scene *scene) {
    cutscene_local *local = malloc(sizeof(cutscene_local));

    game_player *p1 = game_state_get_player(scene->gs, 0);

    const char *text = "";
    switch (scene->id) {
      case SCENE_END:
        cutscene_music(PSM_END);
        text = lang_get(END_TEXT);
        local->text_x = 10;
        local->text_y = 5;
        local->text_width = 300;
        local->color = COLOR_YELLOW;
        break;

      case SCENE_END1:
        text = lang_get(END1_TEXT+p1->pilot_id);
        local->text_x = 10;
        local->text_y = 160;
        local->text_width = 300;
        local->color = COLOR_RED;

        // Pilot face
        animation *ani = &bk_get_info(&scene->bk_data, 3)->ani;
        object *obj = malloc(sizeof(object));
        object_create(obj, scene->gs, vec2i_create(0,0), vec2f_create(0, 0));
        object_set_animation(obj, ani);
        object_select_sprite(obj, p1->pilot_id);
        obj->halt=1;
        game_state_add_object(scene->gs, obj, RENDER_LAYER_TOP);

        // Face effects
        ani = &bk_get_info(&scene->bk_data, 10+p1->pilot_id)->ani;
        obj = malloc(sizeof(object));
        object_create(obj, scene->gs, vec2i_create(0,0), vec2f_create(0, 0));
        object_set_animation(obj, ani);
        game_state_add_object(scene->gs, obj, RENDER_LAYER_TOP);
        break;

      case SCENE_END2:
        text = lang_get(END2_TEXT+p1->pilot_id);
        local->text_x = 10;
        local->text_y = 160;
        local->text_width = 300;
        local->color = COLOR_GREEN;
        break;
    }

    local->len = strlen(text)-1;
    local->pos = 0;
    local->text = malloc(strlen(text)+1);
    strcpy(local->text, text);
    local->current = local->text;
    char *p;

    if ((p = strchr(local->text, '\n'))) {
      // null out the byte
      *p = '\0';
    }

    // Callbacks
    scene_set_userdata(scene, local);
    scene_set_free_cb(scene, cutscene_free);
    scene_set_event_cb(scene, cutscene_event);
    scene_set_startup_cb(scene, cutscene_startup);
    scene_set_render_overlay_cb(scene, cutscene_render_overlay);

    // Pick renderer
    video_select_renderer(VIDEO_RENDERER_HW);

    return 0;
}
Esempio n. 6
0
void player_run(object *obj) {
    // Some vars for easier life
    player_animation_state *state = &obj->animation_state;
    player_sprite_state *rstate = &obj->sprite_state;
    if(state->finished) return;

    // Handle slide operation
    if(obj->slide_state.timer > 0) {
        obj->pos.x += obj->slide_state.vel.x;
        obj->pos.y += obj->slide_state.vel.y;
        obj->slide_state.timer--;
    }

    if(obj->enemy_slide_state.timer > 0) {
        obj->enemy_slide_state.duration++;
        obj->pos.x = state->enemy->pos.x + obj->enemy_slide_state.dest.x;
        obj->pos.y = state->enemy->pos.y + obj->enemy_slide_state.dest.y;
        obj->enemy_slide_state.timer--;
    }

    // Not sure what this does
    const sd_script_frame *frame = sd_script_get_frame_at(&state->parser, state->current_tick);

    // Animation has ended ?
    if(frame == NULL) {
        if(state->repeat) {
            player_reset(obj);
            frame = sd_script_get_frame_at(&state->parser, state->current_tick);
        } else if(obj->finish != NULL) {
            obj->cur_sprite = NULL;
            obj->finish(obj);
            return;
        } else {
            obj->cur_sprite = NULL;
            state->finished = 1;
            return;
        }
    }

    // Handle frame
    state->entered_frame = 0;
    if(frame == NULL) {
        DEBUG("Something went wery wrong!");
        // We shouldn't really get here, unless stringparser messes something up badly
    } else {
        // If frame changed, do something
        if(sd_script_frame_changed(&state->parser, state->previous_tick, state->current_tick)) {
            state->entered_frame = 1;
            player_clear_frame(obj);

            // Tick management
            if(sd_script_isset(frame, "d")) {
                if(!obj->animation_state.disable_d) {
                    state->previous_tick = sd_script_get(frame, "d")-1;
                    state->current_tick = sd_script_get(frame, "d");
                }
            }

            // Hover flag
            if(sd_script_isset(frame, "h")) {
                rstate->disable_gravity = 1;
            } else {
                rstate->disable_gravity = 0;
            }

            if(sd_script_isset(frame, "ua")) {
                obj->animation_state.enemy->sprite_state.disable_gravity = 1;
            }

            // Animation creation command
            if(sd_script_isset(frame, "m") && state->spawn != NULL) {
                int mx = 0;
                if (sd_script_isset(frame, "mrx")) {
                    int mrx = sd_script_get(frame, "mrx");
                    int mm = sd_script_isset(frame, "mm") ? sd_script_get(frame, "mm") : mrx;
                    mx = random_int(&obj->rand_state, 320 - 2*mm) + mrx;
                    DEBUG("randomized mx as %d", mx);
                } else if(sd_script_isset(frame, "mx")) {
                    mx = obj->start.x + (sd_script_get(frame, "mx") * object_get_direction(obj));
                }

                int my = 0;
                if (sd_script_isset(frame, "mry")) {
                    int mry = sd_script_get(frame, "mry");
                    int mm = sd_script_isset(frame, "mm") ? sd_script_get(frame, "mm") : mry;
                    my = random_int(&obj->rand_state, 320 - 2*mm) + mry;
                    DEBUG("randomized my as %d", my);
                } else if(sd_script_isset(frame, "my")) {
                    my = obj->start.y + sd_script_get(frame, "my");
                }

                int mg = sd_script_isset(frame, "mg") ? sd_script_get(frame, "mg") : 0;
                state->spawn(
                    obj,
                    sd_script_get(frame, "m"),
                    vec2i_create(mx, my),
                    mg,
                    state->spawn_userdata);
            }

            // Animation deletion
            if(sd_script_isset(frame, "md") && state->destroy != NULL) {
                state->destroy(obj, sd_script_get(frame, "md"), state->destroy_userdata);
            }

            // Music playback
            if(sd_script_isset(frame, "smo")) {
                if(sd_script_get(frame, "smo") == 0) {
                    music_stop();
                    return;
                }
                music_play(PSM_END + (sd_script_get(frame, "smo") - 1));
            }
            if(sd_script_isset(frame, "smf")) {
                music_stop();
            }

            // Sound playback
            if(sd_script_isset(frame, "s")) {
                float pitch = PITCH_DEFAULT;
                float volume = VOLUME_DEFAULT * (settings_get()->sound.sound_vol/10.0f);
                float panning = PANNING_DEFAULT;
                if(sd_script_isset(frame, "sf")) {
                    int p = clamp(sd_script_get(frame, "sf"), -16, 239);
                    pitch = clampf((p/239.0f)*3.0f + 1.0f, PITCH_MIN, PITCH_MAX);
                }
                if(sd_script_isset(frame, "l")) {
                    int v = clamp(sd_script_get(frame, "l"), 0, 100);
                    volume = (v / 100.0f) * (settings_get()->sound.sound_vol/10.0f);
                }
                if(sd_script_isset(frame, "sb")) {
                    panning = clamp(sd_script_get(frame, "sb"), -100, 100) / 100.0f;
                }
                int sound_id = obj->sound_translation_table[sd_script_get(frame, "s")] - 1;
                sound_play(sound_id, volume, panning, pitch);
            }

            // Blend mode stuff
            if(sd_script_isset(frame, "b1")) { rstate->method_flags &= 0x2000; }
            if(sd_script_isset(frame, "b2")) { rstate->method_flags &= 0x4000; }
            if(sd_script_isset(frame, "bb")) {
                rstate->method_flags &= 0x0010;
                rstate->blend_finish = sd_script_get(frame, "bb");
                rstate->screen_shake_vertical = sd_script_get(frame, "bb");
            }
            if(sd_script_isset(frame, "be")) { rstate->method_flags &= 0x0800; }
            if(sd_script_isset(frame, "bf")) {
                rstate->method_flags &= 0x0001;
                rstate->blend_finish = sd_script_get(frame, "bf");
            }
            if(sd_script_isset(frame, "bh")) { rstate->method_flags &= 0x0040; }
            if(sd_script_isset(frame, "bl")) {
                rstate->method_flags &= 0x0008;
                rstate->blend_finish = sd_script_get(frame, "bl");
                rstate->screen_shake_horizontal = sd_script_get(frame, "bl");
            }
            if(sd_script_isset(frame, "bm")) {
                rstate->method_flags &= 0x0100;
                rstate->blend_finish = sd_script_get(frame, "bm");
            }
            if(sd_script_isset(frame, "bj")) {
                rstate->method_flags &= 0x0400;
                rstate->blend_finish = sd_script_get(frame, "bj");
            }
            if(sd_script_isset(frame, "bs")) {
                rstate->blend_start = sd_script_get(frame, "bs");
            }
            if(sd_script_isset(frame, "bu")) { rstate->method_flags &= 0x8000; }
            if(sd_script_isset(frame, "bw")) { rstate->method_flags &= 0x0080; }
            if(sd_script_isset(frame, "bx")) { rstate->method_flags &= 0x0002; }

            // Palette tricks
            if(sd_script_isset(frame, "bpd")) { rstate->pal_ref_index = sd_script_get(frame, "bpd"); }
            if(sd_script_isset(frame, "bpn")) { rstate->pal_entry_count = sd_script_get(frame, "bpn"); }
            if(sd_script_isset(frame, "bps")) { rstate->pal_start_index = sd_script_get(frame, "bps"); }
            if(sd_script_isset(frame, "bpf")) {
                // Exact values come from master.dat
                if(game_state_get_player(obj->gs, 0)->har == obj) {
                    rstate->pal_start_index =  1;
                    rstate->pal_entry_count = 47;
                } else {
                    rstate->pal_start_index =  48;
                    rstate->pal_entry_count = 48;
                }
            }
            if(sd_script_isset(frame, "bpp")) {
                rstate->pal_end = sd_script_get(frame, "bpp") * 4;
                rstate->pal_begin = sd_script_get(frame, "bpp") * 4;
            }
            if(sd_script_isset(frame, "bpb")) { rstate->pal_begin = sd_script_get(frame, "bpb") * 4; }
            if(sd_script_isset(frame, "bz"))  { rstate->pal_tint = 1; }

            // The following is a hack. We don't REALLY know what these tags do.
            // However, they are only used in CREDITS.BK, so we can just interpret
            // then as we see fit, as long as stuff works.
            if(sd_script_isset(frame, "bc") && frame->tick_len >= 50) {
                rstate->blend_start = 0;
            } else if(sd_script_isset(frame, "bd") && frame->tick_len >= 30) {
                rstate->blend_finish = 0;
            }

            // Handle movement
            if(sd_script_isset(frame, "ox")) {
                DEBUG("changing X from %f to %f", obj->pos.x, obj->pos.x+sd_script_get(frame, "ox"));
                /*obj->pos.x += sd_script_get(frame, "ox");*/
            }

            if(sd_script_isset(frame, "oy")) {
                DEBUG("changing Y from %f to %f", obj->pos.y, obj->pos.y+sd_script_get(frame, "oy"));
                /*obj->pos.y += sd_script_get(frame, "oy");*/
            }

            if (sd_script_isset(frame, "bm")) {
                // hack because we don't have 'walk to other HAR' implemented
                obj->pos.x = state->enemy->pos.x;
                obj->pos.y = state->enemy->pos.y;
                player_next_frame(state->enemy);
            }

            if (sd_script_isset(frame, "v")) {
                int x = 0, y = 0;
                if(sd_script_isset(frame, "y-")) {
                    y = sd_script_get(frame, "y-") * -1;
                } else if(sd_script_isset(frame, "y+")) {
                    y = sd_script_get(frame, "y+");
                }
                if(sd_script_isset(frame, "x-")) {
                    x = sd_script_get(frame, "x-") * -1 * object_get_direction(obj);
                } else if(sd_script_isset(frame, "x+")) {
                    x = sd_script_get(frame, "x+") * object_get_direction(obj);
                }

                if (x || y) {
                    DEBUG("x vel %d, y vel %d", x, y);
                    obj->vel.x += x;
                    obj->vel.y += y;
                }
            }

            if (sd_script_isset(frame, "bu") && obj->vel.y < 0.0f) {
                float x_dist = dist(obj->pos.x, 160);
                // assume that bu is used in conjunction with 'vy-X' and that we want to land in the center of the arena
                obj->slide_state.vel.x = x_dist / (obj->vel.y*-2);
                obj->slide_state.timer = obj->vel.y*-2;
            }

            // handle scaling on the Y axis
            if(sd_script_isset(frame, "y")) {
                obj->y_percent = sd_script_get(frame, "y") / 100.0f;
            }
            if (sd_script_isset(frame, "e")) {
                // x,y relative to *enemy's* position
                int x = 0, y = 0;
                if(sd_script_isset(frame, "y-")) {
                    y = sd_script_get(frame, "y-") * -1;
                } else if(sd_script_isset(frame, "y+")) {
                    y = sd_script_get(frame, "y+");
                }
                if(sd_script_isset(frame, "x-")) {
                    x = sd_script_get(frame, "x-") * -1 * object_get_direction(obj);
                } else if(sd_script_isset(frame, "x+")) {
                    x = sd_script_get(frame, "x+") * object_get_direction(obj);
                }

                if (x || y) {
                    obj->enemy_slide_state.timer = frame->tick_len;
                    obj->enemy_slide_state.duration = 0;
                    obj->enemy_slide_state.dest.x = x;
                    obj->enemy_slide_state.dest.y = y;
                    /*DEBUG("ENEMY Slide object %d for (x,y) = (%f,%f) for %d ticks. (%d,%d)",
                            obj->cur_animation->id,
                            obj->enemy_slide_state.dest.x,
                            obj->enemy_slide_state.dest.y,
                            param->duration,
                            x, y);*/
                }
            }
            if (sd_script_isset(frame, "v") == 0 &&
                sd_script_isset(frame, "e") == 0 &&
                (sd_script_isset(frame, "x+") || sd_script_isset(frame, "y+") || sd_script_isset(frame, "x-") || sd_script_isset(frame, "y-"))) {
                // check for relative X interleaving
                int x = 0, y = 0;
                if(sd_script_isset(frame, "y-")) {
                    y = sd_script_get(frame, "y-") * -1;
                } else if(sd_script_isset(frame, "y+")) {
                    y = sd_script_get(frame, "y+");
                }
                if(sd_script_isset(frame, "x-")) {
                    x = sd_script_get(frame, "x-") * -1 * object_get_direction(obj);
                } else if(sd_script_isset(frame, "x+")) {
                    x = sd_script_get(frame, "x+") * object_get_direction(obj);
                }

                obj->slide_state.timer = frame->tick_len;
                obj->slide_state.vel.x = (float)x;
                obj->slide_state.vel.y = (float)y;
                /*DEBUG("Slide object %d for (x,y) = (%f,%f) for %d ticks.",*/
                    /*obj->cur_animation->id,*/
                    /*obj->slide_state.vel.x, */
                    /*obj->slide_state.vel.y, */
                    /*param->duration);*/
            }

            if(sd_script_isset(frame, "x=") || sd_script_isset(frame, "y=")) {
                obj->slide_state.vel = vec2f_create(0,0);
            }
            if(sd_script_isset(frame, "x=")) {
                obj->pos.x = obj->start.x + (sd_script_get(frame, "x=") * object_get_direction(obj));

                // Find frame ID by tick
                int frame_id = sd_script_next_frame_with_tag(&state->parser, "x=", state->current_tick);
                
                // Handle it!
                if(frame_id >= 0) {
                    int mr = sd_script_get_tick_pos_at_frame(&state->parser, frame_id);
                    int r = mr - state->current_tick;
                    int next_x = sd_script_get(sd_script_get_frame(&state->parser, frame_id), "x=");
                    int slide = obj->start.x + (next_x * object_get_direction(obj));
                    if(slide != obj->pos.x) {
                        obj->slide_state.vel.x = dist(obj->pos.x, slide) / (float)(frame->tick_len + r);
                        obj->slide_state.timer = frame->tick_len + r;
                        /*DEBUG("Slide object %d for X = %f for a total of %d ticks.",*/
                                /*obj->cur_animation->id,*/
                                /*obj->slide_state.vel.x,*/
                                /*param->duration + r);*/
                    }

                }
            }
            if(sd_script_isset(frame, "y=")) {
                obj->pos.y = obj->start.y + sd_script_get(frame, "y=");

                // Find frame ID by tick
                int frame_id = sd_script_next_frame_with_tag(&state->parser, "y=", state->current_tick);

                // handle it!
                if(frame_id >= 0) {
                    int mr = sd_script_get_tick_pos_at_frame(&state->parser, frame_id);
                    int r = mr - state->current_tick;
                    int next_y = sd_script_get(sd_script_get_frame(&state->parser, frame_id), "y=");
                    int slide = next_y + obj->start.y;
                    if(slide != obj->pos.y) {
                        obj->slide_state.vel.y = dist(obj->pos.y, slide) / (float)(frame->tick_len + r);
                        obj->slide_state.timer = frame->tick_len + r;
                        /*DEBUG("Slide object %d for Y = %f for a total of %d ticks.",*/
                                /*obj->cur_animation->id,*/
                                /*obj->slide_state.vel.y,*/
                                /*param->duration + r);*/
                    }

                }
            }
            if(sd_script_isset(frame, "as")) {
                // make the object move around the screen in a circular motion until end of frame
                obj->orbit = 1;
            } else {
                obj->orbit = 0;
            }
            if(sd_script_isset(frame, "q")) {
                // Enable hit on the current and the next n-1 frames.
                obj->hit_frames = sd_script_get(frame, "q");
            }
            if(obj->hit_frames > 0) {
                obj->can_hit = 1;
                obj->hit_frames--;
            }

            if(sd_script_isset(frame, "at")) {
                // set the object's X position to be behind the opponent
                obj->pos.x = obj->animation_state.enemy->pos.x + (15 * object_get_direction(obj));
            }

            if(sd_script_isset(frame, "ar")) {
                DEBUG("flipping direction %d -> %d", object_get_direction(obj), object_get_direction(obj) *-1);
                // reverse direction
                object_set_direction(obj, object_get_direction(obj) * -1);
                DEBUG("flipping direction now %d", object_get_direction(obj));
            }

            // Set render settings
            if(frame->sprite < 25) {
                object_select_sprite(obj, frame->sprite);
                if(obj->cur_sprite != NULL) {
                    rstate->duration = frame->tick_len;
                    rstate->blendmode = sd_script_isset(frame, "br") ? BLEND_ADDITIVE : BLEND_ALPHA;
                    if(sd_script_isset(frame, "r")) {
                        rstate->flipmode ^= FLIP_HORIZONTAL;
                    }
                    if(sd_script_isset(frame, "f")) {
                        rstate->flipmode ^= FLIP_VERTICAL;
                    }
                }
            } else {
                object_select_sprite(obj, -1);
            }

        }
    }

    // Animation ticks
    state->previous_tick = state->current_tick;
    if(state->reverse) {
        state->current_tick--;
    } else {
        state->current_tick++;
    }

    // Sprite ticks
    rstate->timer++;

    // All done.
    return;
}
Esempio n. 7
0
int melee_create(scene *scene) {
    char bitmap[51*36*4];

    // Init local data
    melee_local *local = malloc(sizeof(melee_local));
    memset(local, 0, sizeof(melee_local));
    scene_set_userdata(scene, local);

    game_player *player1 = game_state_get_player(scene->gs, 0);
    game_player *player2 = game_state_get_player(scene->gs, 1);

    controller *player1_ctrl = game_player_get_ctrl(player1);
    controller *player2_ctrl = game_player_get_ctrl(player2);

    palette *mpal = video_get_base_palette();
    palette_set_player_color(mpal, 0, 8, 0);
    palette_set_player_color(mpal, 0, 8, 1);
    palette_set_player_color(mpal, 0, 8, 2);
    video_force_pal_refresh();

    memset(&bitmap, 255, 51*36*4);
    local->ticks = 0;
    local->pulsedir = 0;
    local->selection = 0;
    local->row_a = 0;
    local->column_a = 0;
    local->row_b = 0;
    local->column_b = 4;
    local->done_a = 0;
    local->done_b = 0;

    menu_background2_create(&local->feh, 90, 61);
    menu_background2_create(&local->bleh, 160, 43);
    surface_create_from_data(&local->select_hilight, SURFACE_TYPE_RGBA, 51, 36, bitmap);

    // set up the magic controller hooks
    if(player1_ctrl && player2_ctrl) {
        if(player1_ctrl->type == CTRL_TYPE_NETWORK) {
            controller_add_hook(player2_ctrl, player1_ctrl, player1_ctrl->controller_hook);
        }

        if (player2_ctrl->type == CTRL_TYPE_NETWORK) {
            controller_add_hook(player1_ctrl, player2_ctrl, player2_ctrl->controller_hook);
        }
    }

    animation *ani;
    sprite *spr;
    for(int i = 0; i < 10; i++) {
        ani = &bk_get_info(&scene->bk_data, 3)->ani;
        object_create(&local->pilots[i], scene->gs, vec2i_create(0,0), vec2f_create(0, 0));
        object_set_animation(&local->pilots[i], ani);
        object_select_sprite(&local->pilots[i], i);

        ani = &bk_get_info(&scene->bk_data, 18+i)->ani;
        object_create(&local->har_player1[i], scene->gs, vec2i_create(110,95), vec2f_create(0, 0));
        object_set_animation(&local->har_player1[i], ani);
        object_select_sprite(&local->har_player1[i], 0);
        object_set_repeat(&local->har_player1[i], 1);

        int row = i / 5;
        int col = i % 5;
        spr = sprite_copy(animation_get_sprite(&bk_get_info(&scene->bk_data, 1)->ani, 0));
        mask_sprite(spr->data, 62*col, 42*row, 51, 36);
        ani = create_animation_from_single(spr, spr->pos);
        object_create(&local->harportraits_player1[i], scene->gs, vec2i_create(0, 0), vec2f_create(0, 0));
        object_set_animation(&local->harportraits_player1[i], ani);
        object_select_sprite(&local->harportraits_player1[i], 0);
        object_set_animation_owner(&local->harportraits_player1[i], OWNER_OBJECT);
        if (player2->selectable) {
            spr = sprite_copy(animation_get_sprite(&bk_get_info(&scene->bk_data, 1)->ani, 0));
            mask_sprite(spr->data, 62*col, 42*row, 51, 36);
            ani = create_animation_from_single(spr, spr->pos);
            object_create(&local->harportraits_player2[i], scene->gs, vec2i_create(0, 0), vec2f_create(0, 0));
            object_set_animation(&local->harportraits_player2[i], ani);
            object_select_sprite(&local->harportraits_player2[i], 0);
            object_set_animation_owner(&local->harportraits_player2[i], OWNER_OBJECT);
            object_set_pal_offset(&local->harportraits_player2[i], 48);

            ani = &bk_get_info(&scene->bk_data, 18+i)->ani;
            object_create(&local->har_player2[i], scene->gs, vec2i_create(210,95), vec2f_create(0, 0));
            object_set_animation(&local->har_player2[i], ani);
            object_select_sprite(&local->har_player2[i], 0);
            object_set_repeat(&local->har_player2[i], 1);
            object_set_direction(&local->har_player2[i], OBJECT_FACE_LEFT);
            object_set_pal_offset(&local->har_player2[i], 48);
        }
    }

    ani = &bk_get_info(&scene->bk_data, 4)->ani;
    object_create(&local->bigportrait1, scene->gs, vec2i_create(0,0), vec2f_create(0, 0));
    object_set_animation(&local->bigportrait1, ani);
    object_select_sprite(&local->bigportrait1, 0);

    if (player2->selectable) {
        object_create(&local->bigportrait2, scene->gs, vec2i_create(320,0), vec2f_create(0, 0));
        object_set_animation(&local->bigportrait2, ani);
        object_select_sprite(&local->bigportrait2, 4);
        object_set_direction(&local->bigportrait2, OBJECT_FACE_LEFT);
    }

    ani = &bk_get_info(&scene->bk_data, 5)->ani;
    object_create(&local->player2_placeholder, scene->gs, vec2i_create(0,0), vec2f_create(0, 0));
    object_set_animation(&local->player2_placeholder, ani);
    if (player2->selectable) {
        object_select_sprite(&local->player2_placeholder, 0);
    } else {
        object_select_sprite(&local->player2_placeholder, 1);
    }

    spr = sprite_copy(animation_get_sprite(&bk_get_info(&scene->bk_data, 1)->ani, 0));
    surface_convert_to_rgba(spr->data, video_get_pal_ref(), 0);
    ani = create_animation_from_single(spr, spr->pos);
    object_create(&local->unselected_har_portraits, scene->gs, vec2i_create(0,0), vec2f_create(0, 0));
    object_set_animation(&local->unselected_har_portraits, ani);
    object_select_sprite(&local->unselected_har_portraits, 0);
    object_set_animation_owner(&local->unselected_har_portraits, OWNER_OBJECT);

    for(int i = 0; i < 2; i++) {
        local->bar_power[i] = progressbar_create(PROGRESSBAR_THEME_MELEE, PROGRESSBAR_LEFT, 50);
        local->bar_agility[i] = progressbar_create(PROGRESSBAR_THEME_MELEE, PROGRESSBAR_LEFT, 50);
        local->bar_endurance[i] = progressbar_create(PROGRESSBAR_THEME_MELEE, PROGRESSBAR_LEFT, 50);
    }
    component_layout(local->bar_power[0], 74, 12, 20*4, 8);
    component_layout(local->bar_agility[0], 74, 30, 20*4, 8);
    component_layout(local->bar_endurance[0], 74, 48, 20*4, 8);
    component_layout(local->bar_power[1], 320-66-local->feh.w, 12, 20*4, 8);
    component_layout(local->bar_agility[1], 320-66-local->feh.w, 30, 20*4, 8);
    component_layout(local->bar_endurance[1], 320-66-local->feh.w, 48, 20*4, 8);

    refresh_pilot_stats(local);

    // initialize nova selection cheat
    memset(local->har_selected, 0, sizeof(local->har_selected));
    memset(local->katana_down_count, 0, sizeof(local->katana_down_count));

    // Set callbacks
    scene_set_input_poll_cb(scene, melee_input_tick);
    scene_set_render_cb(scene, melee_render);
    scene_set_free_cb(scene, melee_free);
    scene_set_dynamic_tick_cb(scene, melee_tick);

    // Play correct music
    music_play(PSM_MENU);

    // Pick renderer
    video_select_renderer(VIDEO_RENDERER_HW);

    // All done
    return 0;
}
Esempio n. 8
0
void handle_action(scene *scene, int player, int action) {
    game_player *player1 = game_state_get_player(scene->gs, 0);
    game_player *player2 = game_state_get_player(scene->gs, 1);
    melee_local *local = scene_get_userdata(scene);
    int *row, *column, *done;
    if (player == 1) {
        row = &local->row_a;
        column = &local->column_a;
        done = &local->done_a;
    } else {
        row = &local->row_b;
        column = &local->column_b;
        done = &local->done_b;
    }

    if (*done) {
        return;
    }

    switch (action) {
        case ACT_LEFT:
            (*column)--;
            if (*column < 0) {
                *column = 4;
            }
            sound_play(19, 0.5f, 0.0f, 2.0f);
            break;
        case ACT_RIGHT:
            (*column)++;
            if (*column > 4) {
                *column = 0;
            }
            sound_play(19, 0.5f, 0.0f, 2.0f);
            break;
        case ACT_UP:
            if(*row == 1) {
                *row = 0;
            }
            sound_play(19, 0.5f, 0.0f, 2.0f);
            break;
        case ACT_DOWN:
            if(*row == 0) {
                *row = 1;
            }
            // nova selection cheat
            if(*row == 1 && *column == 0) {
                local->katana_down_count[player-1]++;
                if(local->katana_down_count[player-1] > 11) {
                    local->katana_down_count[player-1] = 11;
                }
            }
            sound_play(19, 0.5f, 0.0f, 2.0f);
            break;
        case ACT_KICK:
        case ACT_PUNCH:
            *done = 1;
            sound_play(20, 0.5f, 0.0f, 2.0f);
            if (local->done_a && (local->done_b || !player2->selectable)) {
                local->done_a = 0;
                local->done_b = 0;
                if (local->selection == 0) {
                    local->selection = 1;
                    local->pilot_id_a = 5*local->row_a + local->column_a;
                    local->pilot_id_b = 5*local->row_b + local->column_b;

                    // nova selection cheat
                    local->har_selected[0][local->pilot_id_a] = 1;
                    local->har_selected[1][local->pilot_id_b] = 1;

                    object_select_sprite(&local->bigportrait1, local->pilot_id_a);
                    // update the player palette
                    palette *base_pal = video_get_base_palette();
                    pilot p_a;
                    pilot_get_info(&p_a, local->pilot_id_a);
                    palette_set_player_color(base_pal, 0, p_a.colors[0], 2);
                    palette_set_player_color(base_pal, 0, p_a.colors[1], 1);
                    palette_set_player_color(base_pal, 0, p_a.colors[2], 0);
                    video_force_pal_refresh();
                    player1->colors[0] = p_a.colors[0];
                    player1->colors[1] = p_a.colors[1];
                    player1->colors[2] = p_a.colors[2];

                    if (player2->selectable) {
                        object_select_sprite(&local->bigportrait2, local->pilot_id_b);
                        // update the player palette
                        pilot_get_info(&p_a, local->pilot_id_b);
                        palette_set_player_color(base_pal, 1, p_a.colors[0], 2);
                        palette_set_player_color(base_pal, 1, p_a.colors[1], 1);
                        palette_set_player_color(base_pal, 1, p_a.colors[2], 0);
                        video_force_pal_refresh();
                        player2->colors[0] = p_a.colors[0];
                        player2->colors[1] = p_a.colors[1];
                        player2->colors[2] = p_a.colors[2];
                    }
                } else {
                    int nova_activated[2] = {1, 1};
                    for(int i = 0;i < 2;i++) {
                        for(int j = 0;j < 10;j++) {
                            if(local->har_selected[i][j] == 0) {
                                nova_activated[i] = 0;
                                break;
                            }
                        }
                        if(local->katana_down_count[i] < 11) {
                            nova_activated[i] = 0;
                        }
                    }
                    if(nova_activated[0] && local->row_a == 1 && local->column_a == 2) {
                        player1->har_id = HAR_NOVA;
                    } else {
                        player1->har_id = 5*local->row_a+local->column_a;
                    }
                    player1->pilot_id = local->pilot_id_a;
                    if (player2->selectable) {
                        if(nova_activated[1] && local->row_b == 1 && local->column_b == 2) {
                            player2->har_id = HAR_NOVA;
                        } else {
                            player2->har_id = 5*local->row_b+local->column_b;
                        }
                        player2->pilot_id = local->pilot_id_b;
                    } else {
                        if (player1->sp_wins == (2046 ^ (2 << player1->pilot_id))) {
                            // everyone but kriessack
                            player2->pilot_id = 10;
                            player2->har_id = HAR_NOVA;
                        } else {
                            // pick an opponent we have not yet beaten
                            while(1) {
                                int i = rand_int(10);
                                if ((2 << i) & player1->sp_wins || i == player1->pilot_id) {
                                    continue;
                                }
                                player2->pilot_id = i;
                                player2->har_id = rand_int(10);
                                break;
                            }
                        }

                        pilot p_a;
                        pilot_get_info(&p_a, player2->pilot_id);
                        player2->colors[0] = p_a.colors[0];
                        player2->colors[1] = p_a.colors[1];
                        player2->colors[2] = p_a.colors[2];
                    }
                    game_state_set_next(scene->gs, SCENE_VS);
                }
            }
            break;
    }

    if(local->selection == 0) {
        object_select_sprite(&local->bigportrait1, 5*local->row_a + local->column_a);
        if (player2->selectable) {
            object_select_sprite(&local->bigportrait2, 5*local->row_b + local->column_b);
        }
    }

    // nova selection cheat
    if(local->selection == 1) {
        local->har_selected[player-1][5 * (*row) + *column] = 1;
    }

    refresh_pilot_stats(local);
}