/***************************************
 *              >$.!ArcMind.c.Source   *
 *                                     *
 *   Program    Desktop Mind game      *
 *   Version    2.00  (19 May 1991)    *
 *   Author     Paolo Stra             *
 *   RISC User  Jan/Feb 1991           *
 *   Program    subject to copyright   *
 *                                     *
 ***************************************/



#include  "wimp.h"
#include  "wimpt.h"
#include  "win.h"
#include  "event.h"
#include  "baricon.h"
#include  "sprite.h"
#include  "werr.h"
#include  "res.h"
#include  "resspr.h"
#include  "menu.h"
#include  "template.h"
#include  "bbc.h"
#include  "dbox.h"
#include  "saveas.h"
#include  "visdelay.h"
#include  "xferrecv.h"
#include  "coords.h"
#include  "msgs.h"

#include  <stdio.h>
#include  <stdlib.h>
#include  <time.h>



/*****************************  CONSTANTS  ****************************/



#define BASEX      630
#define BASEY        0
#define WIDTH       56
#define STEP        60

#define MIN_POSX1    2
#define MAX_POSX1  154
#define MIN_POSX2  172       
#define MAX_POSX2  256

#define REPEAT     800

#define MIN_HOLES    3
#define MIN_COLOURS  5



/****************************  GLOBAL DATA  ***************************/



BOOL    all_done;

wimp_w  whandle;
wimp_i  ihandle = 42;
menu    iconbar_menu, main_menu;

struct  game {
            BOOL is_archie;
            enum { OK, NEW, CLR, THINK } action;
            int  games;
            int  solutions;
            int  trials;
            int  holes;
            int  colours;
            int  current;
            int  cmb[5];
};
struct  game arc = { TRUE,  NEW, 0, 0, 0, 5, 10, 0 };
struct  game plr = { FALSE, NEW, 0, 0, 0, 5, 10, 0 };

int     filetype = 0xffd;
int     gamesize = 0x270;
char    sugg_fname[150]    = "ArcGame";
char    checkfile_string[] = "ArcMind";
char    author_string[]    = "Paolo Stra";
char    version_string[]   = "2.00  (19 May 1991)";

int     colour = 1;
int     matrix[22] [12];
int     coltrans[] = { 1, 10, 9, 11, 15, 14, 8, 12, 13, 0, 5, 3, 2};
char    sprite_name[22] [2] = {
                  "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
                  "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v"
                              };



/***********************  FUNCTION PROTOTYPES  ************************/



BOOL task_init(void);
BOOL create_window(char *, wimp_w *);
void iconbar_click(wimp_i);
void iconbar_loader(wimp_eventstr *, void *);
void iconbarmenu_proc(void *, char *);
menu mainmenu_maker(void *);
void mainmenu_proc(void *, char *);
void info_about_program(void);
void display_score(void);
void display_combs(struct game *);
void reset_game(void);
void back(void);
void end_plrgame(void);
void event_handler(wimp_eventstr *, void *);
void iconclick_proc(wimp_mousestr *);
void black_white(wimp_mousestr *);
void set_colour(wimp_mousestr *);
int  select_colour(int);
void process_arc_action(void);
void process_plr_action(void);
void start_arcgame(void);
void process_arcgame(void);
void clear_arcgame(void);
void start_plrgame(void);
void process_plrgame(void);
void clear_plrgame(void);
BOOL get_arctrial(void);
BOOL next_trial(void);
BOOL verify_cmb(int *);
void paint_iconsprite(wimp_i, int, int, int);
void clear_iconsprite(wimp_i, int);
int  set_icontext(wimp_i, int);
void update_dbox(dbox, int, int);
void update_game_table(struct game *);
void unset_icon_holes(int, int);
int  xpos_pointer_in_icon(wimp_mousestr *);
BOOL game_saver(char *, void *);
void save_proc(FILE *, struct game *);
BOOL game_loader(void);
void load_proc(FILE *, struct game *);



/*****************  WIMP INIT, WINDOW, ICONBAR, MENU  *****************/



int main()
{
    all_done = FALSE;

    if (task_init())
    {
        event_setmask(wimp_EMPTRLEAVE | wimp_EMPTRENTER);
        while (!all_done)
            event_process();
    }
    return (0);
}



BOOL task_init(void)
{
    wimpt_init("ArcMind");
    res_init("ArcMind");
    resspr_init();
    template_init();
    dbox_init();
    msgs_init();

    if (!create_window("MainWindow", &whandle))
        return (FALSE);
    win_register_event_handler(whandle, event_handler, 0);

    if ((iconbar_menu = menu_new("ArcMind", msgs_lookup("menu1"))) == NULL)
        return (FALSE);
    if ((main_menu = menu_new("ArcMind", msgs_lookup("menu2"))) == NULL)
        return (FALSE);

    baricon("!arcmind", (int)resspr_area(), iconbar_click);
    win_register_event_handler(win_ICONBARLOAD, iconbar_loader, 0);

    if (!event_attachmenu(win_ICONBAR, iconbar_menu, iconbarmenu_proc, 0))
        return (FALSE);
    if (!event_attachmenumaker(whandle, mainmenu_maker, mainmenu_proc, 0))
        return (FALSE);

    srand(time(NULL));

    return (TRUE);
}



BOOL create_window(char *name, wimp_w *handle)
{
    wimp_wind *window;

    if (!(window = template_syshandle(name)))
        return (FALSE);

    return (wimpt_complain(wimp_create_wind(window, handle)) == 0);
}



void iconbar_click(wimp_i icon)
{
    wimp_wstate  state;

    if (wimpt_complain(wimp_get_wind_state(whandle, &state)) == 0)
    {
        state.o.behind = -1;
        wimpt_noerr(wimp_open_wind(&state.o));
    }
}



void iconbar_loader(wimp_eventstr *e, void *handle)
{
    if ((e->data.msg.hdr.action == wimp_MDATALOAD) ||
                           (e->data.msg.hdr.action == wimp_MDATAOPEN))
        if (game_loader())
            iconbar_click(NULL);
}

    

void iconbarmenu_proc(void *handle, char *hit)
{
    switch (hit[0])
    {
        case 1:
            info_about_program();
            break;

        case 2:
            reset_game();
            break;

        case 3:
            saveas(filetype, sugg_fname, gamesize, game_saver, 0, 0, 0);
            break;

        case 4:
            all_done = TRUE;
            break;
    }
}



menu mainmenu_maker(void *handle)
{
    menu_setflags(main_menu, 2, 0,
                      (arc.current) && (arc.action == OK) ? 0 : 1);
    menu_setflags(main_menu, 3, 0,
                      (plr.current) && (plr.action == OK) ? 0 : 1);
    return (main_menu);
}



void mainmenu_proc(void *handle, char *hit)
{
    switch (hit[0])
    {
        case 1:
            display_score();
            break;

        case 2:
            back();
            break;

        case 3:
            end_plrgame();
            break;

        case 4:
            display_combs(&arc);
            break;

        case 5:
            display_combs(&plr);
            break;
    }
}



/**************************  DIALOGUE BOXES  **************************/


 
void info_about_program(void)
{
    dbox d;

    if ((d = dbox_new("ProgInfo")) != NULL)
    {
        dbox_setfield(d, 3, author_string);
        dbox_setfield(d, 4, version_string);
        dbox_show(d);
        dbox_fillin(d);
        dbox_dispose(&d);
    }
}                                      



void display_score(void)
{
    dbox d;
    char s[10];
    int average;

    if ((d = dbox_new("Score")) != NULL)
    {

        dbox_setnumeric(d, 1, arc.games);
        dbox_setnumeric(d, 2, arc.solutions);
        average = (arc.solutions) ? (arc.trials * 10) / arc.solutions : 0;
        sprintf(s, "%3.2d ", average);
        s[3] = s[2];
        s[2] = '.';
        dbox_setfield(d, 3, s);

        dbox_setnumeric(d, 4, plr.games);
        dbox_setnumeric(d, 5, plr.solutions);
        average = (plr.solutions) ? (plr.trials * 10) / plr.solutions : 0;
        sprintf(s, "%3.2d", average);
        s[3] = s[2];
        s[2] = '.';
        dbox_setfield(d, 6, s);

        dbox_show(d);
        dbox_fillin(d);
        dbox_dispose(&d);
    }
}



void display_combs(struct game *p)
{
    dbox d;
    BOOL filling     = TRUE;
    int  new_holes   = p->holes;
    int  new_colours = p->colours;

    d = dbox_new((p->is_archie) ? "arc_combs" : "plr_combs");
    if ( d == NULL)
        return;

    update_dbox(d, new_holes, new_colours);

    if (p->action != NEW)
        dbox_fadefield(d, 0);

    dbox_show(d);

    while (filling)
        switch (dbox_fillin(d))
        {
            case 1:
                if (new_holes > MIN_HOLES)
                    update_dbox(d, --new_holes, new_colours);
                break;

            case 2:
                if (new_holes < 5)
                    update_dbox(d, ++new_holes, new_colours);
                break;

            case 3:
                if (new_colours > MIN_COLOURS)
                    update_dbox(d, new_holes, --new_colours);
                break;

            case 4:
                if (new_colours < 10)
                    update_dbox(d, new_holes, ++new_colours);
                break;

            case 0:
                p->holes = new_holes;
                p->colours = new_colours;
                update_game_table(p);
                filling = dbox_persist();
                break;

            case dbox_CLOSE:
                filling = FALSE;
                break;
        }

    dbox_dispose(&d);
}



/************************  HIT MENU FUNCTIONS  ************************/



void reset_game(void)
{
    visdelay_begin();
    win_claim_idle_events((wimp_w) -1);

    plr.games = plr.solutions = plr.trials = 0;
    arc.games = arc.solutions = arc.trials = 0;
    clear_arcgame();
    clear_plrgame();

    arc.holes = plr.holes = 5;
    arc.colours = plr.colours = 10;
    update_game_table(&arc);
    update_game_table(&plr);

    visdelay_end();
}



void back(void)
{
    int j;

    clear_iconsprite(arc.current + 8, 0);
    arc.current--;
    clear_iconsprite(arc.current + 8, 5);
    for(j = 0; j < arc.holes; j++)
        arc.cmb[j] = matrix[arc.current] [j];
}



void end_plrgame(void)
{
    int j;

    for(j = 0; j < plr.holes; j++)
        paint_iconsprite(29, j, 11, plr.cmb[j]);
        
    plr.action = set_icontext(41, CLR);
    plr.games++;
}



/*************************  EVENT HANDLERS  ***************************/



void event_handler(wimp_eventstr *e, void *handle)
{
    int j = 0;

    switch (e->e)
    {
        case wimp_ENULL:
            while ((j++ <REPEAT) && !get_arctrial())
                ;
            break;

        case wimp_EOPEN:
            wimpt_noerr(wimp_open_wind(&e->data.o));
            break;

        case wimp_ECLOSE:
            wimpt_noerr(wimp_close_wind(e->data.o.w));
            break;

        case wimp_EBUT:
            if ((e->data.but.m.bbits & (wimp_BRIGHT | wimp_BLEFT)) &&
                                                 (e->data.but.m.i > 0))
                iconclick_proc(&e->data.but.m);
            break;

        case wimp_ESEND:
        case wimp_ESENDWANTACK:
            if ((e->data.msg.hdr.action == wimp_MDATALOAD) ||
                            (e->data.msg.hdr.action == wimp_MDATAOPEN))
                game_loader();
            break;
    }
}



void iconclick_proc(wimp_mousestr *m)
{
    wimp_i i = m->i;

    if ((i == arc.current + 8) && (arc.action == OK))
        black_white(m);

    else if ((i >= 18) && (i <= plr.current+18) && (plr.action == OK))
        set_colour(m);

    else if ((i == 28) && (arc.action != CLR) && (arc.action != THINK))
        set_colour(m);

    else if ((i >= 30) && (i <= 39))
        colour = select_colour(i - 29);

    else if (i == 40)
        process_arc_action();

    else if (i == 41)
        process_plr_action();
}



void black_white(wimp_mousestr *m)
{
    int old, new;
    int xpos  = xpos_pointer_in_icon(m);
    int index = m->i - 8;

    if ((xpos <= MAX_POSX2) && (xpos >= MIN_POSX2))
    {
        xpos -= MIN_POSX2;
        if (xpos%18 < 14)
        {
            xpos = xpos / 18 + 5;
            old = matrix[index] [xpos];
            new = (old) ? (old ^ 3) : 10;
            if (m->bbits & wimp_BRIGHT)
                new = 0;
            paint_iconsprite(m->i, xpos, old, new);
        }
    }
}



void set_colour(wimp_mousestr *m)
{
    int old, new;
    int xpos  = xpos_pointer_in_icon(m);
    int index = m->i - 8;
    int adjst = (m->bbits & wimp_BRIGHT);
    int max_colours = (index == 20) ? arc.colours : plr.colours;
    
    if ((xpos <= MAX_POSX1) && (xpos >= MIN_POSX1))
    {
        xpos -= MIN_POSX1;
        if (xpos%32 < 26)
        {
            if (matrix[index] [xpos /= 32] == 12)
                return;

            if ((colour > max_colours) && !adjst)
            {
                werr(0, msgs_lookup("err1"), max_colours);
                return;
            }

            if (index >= plr.current + 10)
            {
                old = matrix[index] [xpos];
                new = (adjst) ? 0 : colour;
                if (new != old)
                    paint_iconsprite(m->i, xpos, old, new);
            }
            else
                colour = select_colour(matrix[index] [xpos]);
        } 
    }
}



int select_colour(int colour)
{
    wimp_icreate icon;
    wimp_redrawstr r;

    wimpt_noerr(wimp_delete_icon(whandle, ihandle));

    icon.w = whandle;
    icon.i.box.x0 = BASEX;
    icon.i.box.x1 = BASEX + WIDTH; 
    icon.i.box.y1 = BASEY - (STEP * colour);
    icon.i.box.y0 = icon.i.box.y1 - WIDTH;
    icon.i.flags  = wimp_IBORDER | 
                   (wimp_BIGNORE * wimp_IBTYPE) |
                   (wimp_IFORECOL * 4);
    wimpt_noerr(wimp_create_icon(&icon, &ihandle));

    r.w = whandle;
    r.box.x0 =  BASEX;
    r.box.x1 =  BASEX + WIDTH;
    r.box.y0 =  BASEY - (STEP * 11);
    r.box.y1 =  BASEY - STEP;
    wimp_force_redraw(&r);

    return (colour);
}



void process_arc_action(void)
{
    wimpt_noerr(
       wimp_set_icon_state(whandle, 40, wimp_ISELECTED, wimp_ISELECTED));
    switch (arc.action)
    {
        case (OK):
            process_arcgame();
            break;
        case (NEW):
            start_arcgame();
            break;
        case (CLR):
            clear_arcgame();
            break;
    }
    wimpt_noerr(wimp_set_icon_state(whandle, 40, 0, wimp_ISELECTED));
}



void process_plr_action(void)
{
    wimpt_noerr(
       wimp_set_icon_state(whandle, 41, wimp_ISELECTED, wimp_ISELECTED));
    switch (plr.action)
    {
        case (OK):
            process_plrgame();
            break;
        case (NEW):
            start_plrgame();
            break;
        case (CLR):
            clear_plrgame();
            break;
    }
    wimpt_noerr(wimp_set_icon_state(whandle, 41, 0, wimp_ISELECTED));
}



/*************************  MAIN GAME FUNCTIONS  **********************/



void start_arcgame(void)
{
    int j = 0;

    while (j < arc.holes)
    {
        paint_iconsprite(8, j, 0, rand() % arc.colours + 1);
        arc.cmb[j++] = arc.colours;
    }
    ++arc.cmb[0];
    arc.action = set_icontext(40, OK);
}



void process_arcgame(void)
{
    int j;
    int black = 0;
    int white = 0;

    for(j = 5; j <= 9; j++)
    {
        if (matrix[arc.current] [j] == 10)
            ++black;
        else if (matrix[arc.current] [j] == 9)
            ++white;
    }
    matrix[arc.current] [10] = black;
    matrix[arc.current] [11] = black + white;

    if ((white == 1) && (black == arc.holes - 1) ||
                                      (black + white > arc.holes))
    {
        werr(0, msgs_lookup("err3"));
        return;
    }
    
    if (black == arc.holes)
    {
         arc.games++;
         arc.solutions++;
         arc.trials += arc.current + 1;
         arc.action = set_icontext(40, CLR);
         return;
    }

    if (arc.current == 9)
    {
        arc.games++;
        arc.action = set_icontext(40,CLR);
        return;
    }

    arc.action = set_icontext(40,THINK);
    win_claim_idle_events(whandle);
}



void clear_arcgame(void)
{
    int j = 0;

    while (j <= arc.current)
        clear_iconsprite(j++ + 8, 0);
    clear_iconsprite(28, 0);

    arc.current = 0;
    arc.action  = set_icontext(40, NEW);
}



void start_plrgame(void)
{
    int j = 0;

    while (j < plr.holes)
    {
        paint_iconsprite(29, j, 0, 11);
        plr.cmb[j++] = rand() % plr.colours + 1;
    }
    plr.action = set_icontext(41, OK);
}
 


void process_plrgame(void)
{
    int j, k;
    int tmp[11] = { 0 };
    int index  = plr.current + 10;
    int pos = 5;

    for(j = 0; j < plr.holes; j++)
        if (!matrix[index] [j])
        {
            werr(FALSE, msgs_lookup("err2"), plr.holes);
            return;
        }


    for(j = 0; j < plr.holes; j++)
    {
        tmp[j] = plr.cmb[j];
        if (matrix[index] [j] == tmp[j])
        {
            tmp[j] = -1;
            paint_iconsprite(index + 8, pos++, 0, 10);
        }
    }

    for(k = 0; k < plr.holes; k++)
        if (tmp[k] != -1)    
            for(j = 0; j < plr.holes; j++)
                if (matrix[index] [k] == tmp[j])
                {
                    tmp[j] = -2;
                    paint_iconsprite(plr.current + 18, pos++, 0, 9);
                    break;
                }


    if (matrix[index] [plr.holes + 4] == 10)
    {
        plr.solutions++;
        plr.trials += plr.current + 1;
        end_plrgame();
    }

    if (++plr.current == 10)
        end_plrgame();
}



void clear_plrgame(void)
{
    int j = 0;

    while (j <= plr.current)
        clear_iconsprite(j++ + 18, 0);
    clear_iconsprite(29, 0);

    plr.current  = 0;
    plr.action = set_icontext(41, NEW);
}




/***************  ARC THINKING FUNCTIONS (Background)  ****************/



BOOL get_arctrial(void)    
{
    int j;

    if (arc.current == 0)
    {
        arc.current++;
        for(j = 0; j < arc.holes; j++)
        {
            int k   = 0;
            int rnd = rand() % arc.colours + 1;
            while (k <= 4)
                if (rnd == matrix[0] [k++])
                {
                    rnd = rand() % arc.colours + 1;
                    k = 0;
                }
            paint_iconsprite(arc.current + 8, j, 0, rnd);
        }          
        arc.action = set_icontext(40, OK);
        win_claim_idle_events((wimp_w) -1);
        return (TRUE);
    }

    if (!next_trial())
    {
        werr(0, msgs_lookup("err6"));
        arc.action = set_icontext(40, OK);
        win_claim_idle_events((wimp_w) -1);
        for(j = 0; j < arc.holes; j++)
            arc.cmb[j] = matrix[arc.current] [j];
        return (TRUE);
    }

    for(j = 0; j <= arc.current; j++)
        if (!verify_cmb(matrix[j]))
            return (FALSE);

    arc.current++;
    arc.action = set_icontext(40,OK);
    win_claim_idle_events((wimp_w) -1);

    for(j = 0; j < arc.holes; j++)
        paint_iconsprite(arc.current + 8, j, 0, arc.cmb[j]);

    return (TRUE);
}



BOOL next_trial(void)
{
    if (--arc.cmb[0])
        return (TRUE);
    arc.cmb[0] = arc.colours;

    if (--arc.cmb[1])
        return (TRUE);
    arc.cmb[1] = arc.colours;

    if (--arc.cmb[2])
        return (TRUE);
    if (arc.holes == 3)
        return (FALSE);
    arc.cmb[2] = arc.colours;

    if (--arc.cmb[3])
        return (TRUE);
    if (arc.holes == 4)
        return (FALSE);
    arc.cmb[3] = arc.colours;

    return (--arc.cmb[4] != 0);
}



BOOL verify_cmb(int *tent)
{
    int tmp[5];
    register j, k;
    register count = 0;


    for(j = 0; j < arc.holes; j++)
        if (tent[j] == arc.cmb[j])
            count++;

    if (count != tent[10])
        return (FALSE);

    for(j = 0; j < arc.holes; j++)
        tmp[j] = arc.cmb[j];
    count = 0;

    for(k = 0; k < arc.holes; k++)
        for(j = 0; j < arc.holes; j++)
            if (tent[k] == tmp[j])
            {
                count++;
                tmp[j] = 0;
                break;
            }
    
    return (count == tent[11]);
}



/*************************  SERVICE FUNCTIONS  ************************/



void paint_iconsprite(wimp_i i, int hole, int old_colour, int new_colour)
{
    sprite_id id;
    sprite_state state;
    int x;

    id.s.name = sprite_name[i-8];
    id.tag = sprite_id_name;

    wimpt_complain(
              sprite_outputtosprite(resspr_area(), &id, NULL, &state));

    bbc_gcol(0,coltrans[old_colour] + 128);
    bbc_gcol(0,coltrans[new_colour]);

    x = (hole <= 4) ? (hole * 32 + 15) : (hole * 18 + 85);
        
    if ((new_colour == 12) || (old_colour == 12))
    {
        bbc_move(x - 4, 12);
        bbc_draw(x + 3, 20);
        bbc_move(x - 4, 20);
        bbc_draw(x + 3, 12);
    }
    else
        bbc_fill(x, 16);

    wimpt_complain(sprite_outputtoscreen(NULL, &state));
    wimpt_noerr(wimp_set_icon_state(whandle, i, 0, 0));
    matrix[i - 8] [hole] = new_colour;
}



void clear_iconsprite(wimp_i i, int start)
{
    int old, j;
    int indx = i - 8;

    for(j = start; j <= 9; j++)
    {
        old = matrix[indx] [j];
        if (old && (old != 12) && ((old != 11) || (indx == 21)))
            paint_iconsprite(i, j, old, 0);
    }
    matrix[indx] [10] = matrix[indx] [11] = 0;
}



int set_icontext(wimp_i i, int act)
{
    char *t, *text;
    wimp_icon r;

    switch (act)
    {
        case OK:
            text = msgs_lookup("act1");
            break;
        case NEW:
            text = msgs_lookup("act2");
            break;
        case CLR:
            text = msgs_lookup("act3");
            break;
        case THINK:
            text = msgs_lookup("act4");
            break;
    }
    wimpt_noerr(wimp_get_icon_info(whandle, i, &r));
    t = r.data.indirecttext.buffer;
    while ((*t++ = *text++) >= 32)
        ;
    wimpt_noerr(wimp_set_icon_state(whandle, i, 0, 0));
    return (act);
}



void update_dbox(dbox d, int holes, int colours)
{
    int j = 0;
    int power = 1;
    char s[20];

    while (++j <= holes)
        power *= colours;

    dbox_setnumeric(d, 5, holes);
    dbox_setnumeric(d, 6, colours);

    sprintf(s, msgs_lookup("dial"), power);
    dbox_setfield(d, 7, s);
}



void update_game_table(struct game *p)
{
    int start = (p->is_archie) ? 0 : 10;
    int j     = start;

    while (j <= start + 9)
        unset_icon_holes(j++, p->holes);

    if (p->is_archie)
        unset_icon_holes(20, p->holes);
    else
        unset_icon_holes(21, p->holes);
}



void unset_icon_holes(int tent, int holes)
{
    int j, old, new;

    for(j = 0; j <= 4; j++)
    {
        old = matrix[tent] [j];
        new = (j < holes) ? 0 : 12;
        if (new != old)
            paint_iconsprite(tent + 8, j, old, new);
    }
}



int xpos_pointer_in_icon(wimp_mousestr *m)
{
    wimp_wstate w;
    wimp_icon i;

    wimpt_noerr(wimp_get_wind_state(whandle, &w));
    wimpt_noerr(wimp_get_icon_info(whandle, m->i, &i));

    return (
       coords_x_toworkarea(m->x, (coords_cvtstr *)&w.o.box) - i.box.x0);
}



/*********************  SAVE / LOAD FUNCTIONS  ************************/



BOOL game_saver(char *filename, void *handle)
{
    FILE *fp;
    int j, k;
    char sys[80];

    if ((fp = fopen(filename, "w")) == NULL)
    {
        werr(0, msgs_lookup("err4"));
        return (FALSE);
    }

    visdelay_begin();

    fprintf(fp, "%s ", checkfile_string);

    save_proc(fp, &arc);
    save_proc(fp, &plr);

    for(k = 0; k <= 21; k++)
        for(j = 0; j <= 11; j++)
            fprintf(fp, "%d ", matrix[k] [j]);

    fclose(fp);

    sprintf(sys, "SetType %s %X", filename, filetype);
    system(sys);

    visdelay_end();

    for(j = 0; sugg_fname[j] = filename[j]; j++)
        ;

    return (TRUE);
}



void save_proc(FILE *fp, struct game *p)
{
    int j = 0;

    fprintf(fp, "%d ", p->action);   
    fprintf(fp, "%d %d %d ", p->games, p->solutions, p->trials);
    fprintf(fp, "%d %d %d ", p->holes, p->colours, p->current);
    while (j <= 4)
        fprintf(fp, "%d ", p->cmb[j++]);
}



BOOL game_loader(void)
{
    FILE *fp;
    int j, k, colour;
    char *filename, *p;

    if (xferrecv_checkinsert(&filename) != filetype)
    {
        werr(FALSE, msgs_lookup("err5"));
        return (FALSE);
    }

    if ((fp = fopen(filename, "r")) == NULL)
    {
        werr(0, msgs_lookup("err4"));
        return (FALSE);
    }

    p = checkfile_string;

    while (*p != 0)
        if (getc(fp) != *p++)
        {
            werr(0, msgs_lookup("err5"));
            fclose(fp);
            return (FALSE);
        }

    visdelay_begin();

    load_proc(fp, &arc);
    load_proc(fp, &plr);

    for(k = 0; k <= 21; k++)
    {
        for(j = 0; j <= 9; j++)
        {
            fscanf(fp, "%d", &colour);
            if (matrix[k] [j] != colour)
            {
                if (matrix[k] [j] == 12)
                    paint_iconsprite(k + 8, j, 12, 0);
                if (colour == 12)
                    paint_iconsprite(k + 8, j, matrix[k] [j], 0);
                paint_iconsprite(k + 8, j, matrix[k] [j], colour);
            }
        }
        fscanf(fp, "%d %d", &matrix[k] [10], &matrix[k] [11]);
    }
    fclose(fp);

    set_icontext(40, arc.action);
    set_icontext(41, plr.action);
    visdelay_end();

    for(j = 0; sugg_fname[j] = filename[j]; j++)
        ;

    return (TRUE);
}



void load_proc(FILE *fp, struct game *p)
{
    int j = 0;

    fscanf(fp, "%d ", &p->action);   
    fscanf(fp, "%d %d %d ", &p->games, &p->solutions, &p->trials);
    fscanf(fp, "%d %d %d ", &p->holes, &p->colours, &p->current);
    while (j <= 4)
        fscanf(fp, "%d ", &p->cmb[j++]);
}
