/* * Alizarin Tetris * The user identity file. * * Copyright 2000, Kiri Wagstaff & Westley Weimer */ #include /* go autoconf! */ #include #include "atris.h" #include "display.h" #include "grid.h" #include "identity.h" #include "menu.h" #include "xflame.pro" #include "display.pro" #define ID_FILENAME "Atris.Players" /*************************************************************************** * input_string() * Read input from the user ... on the widget layer. *********************************************************************PROTO*/ char * input_string(SDL_Surface *screen, int x, int y, int opaque) { int pos; char c; char retval[1024]; SDL_Surface *text, *ctext; SDL_Color tc, cc; SDL_Rect rect; SDL_Event event; Uint32 text_color = int_input_color0; Uint32 cursor_color = int_input_color1; Uint32 our_black = opaque ? int_solid_black : int_black; memset(retval, 0, sizeof(retval)); retval[0] = ' '; pos = 1; SDL_GetRGB(text_color, screen->format, &tc.r, &tc.g, &tc.b); SDL_GetRGB(cursor_color, screen->format, &cc.r, &cc.g, &cc.b); ctext = TTF_RenderText_Blended(font, "_", cc); Assert(ctext); while (1) { int changed = 0; /* did they change the text string? */ int blink = 1; /* toggle the blinking the cursor */ Uint32 flip_when = SDL_GetTicks(); /* display the current string */ text = TTF_RenderText_Blended(font, retval, tc); Assert(text); rect.x = x; rect.y = y; rect.w = text->w; rect.h = text->h; SDL_BlitSurface(text, NULL, widget_layer, &rect); /* OK to ignore the intervening flame layer */ SDL_BlitSurface(text, NULL, screen, &rect); SDL_UpdateSafe(screen, 1, &rect); rect.x += rect.w; rect.w = ctext->w; rect.h = ctext->h; changed = 0; while (!changed) { if (SDL_GetTicks() > flip_when) { if (blink) { SDL_BlitSurface(ctext, NULL, screen, &rect); SDL_BlitSurface(ctext, NULL, widget_layer, &rect); } else { SDL_FillRect(widget_layer, &rect, our_black); SDL_FillRect(screen, &rect, our_black); SDL_BlitSurface(flame_layer, &rect, screen, &rect); SDL_BlitSurface(widget_layer, &rect, screen, &rect); } SDL_UpdateSafe(screen, 1, &rect); flip_when = SDL_GetTicks() + 400; blink = !blink; } if (SDL_PollEvent(&event)) { if (event.type == SDL_KEYDOWN) { changed = 1; switch (event.key.keysym.sym) { case SDLK_RETURN: return strdup(retval + 1); case SDLK_BACKSPACE: if (pos > 1) pos--; retval[pos] = 0; rect.x = x; rect.w = text->w + ctext->w; SDL_FillRect(widget_layer, &rect, our_black); SDL_FillRect(screen, &rect, our_black); SDL_BlitSurface(flame_layer, &rect, screen, &rect); SDL_BlitSurface(widget_layer, &rect, screen, &rect); SDL_UpdateSafe(screen, 1, &rect); break; default: c = event.key.keysym.unicode; if (c == 0) break; SDL_FillRect(widget_layer, &rect, our_black); SDL_FillRect(screen, &rect, our_black); SDL_BlitSurface(flame_layer, &rect, screen, &rect); SDL_BlitSurface(widget_layer, &rect, screen, &rect); SDL_UpdateSafe(screen, 1, &rect); if (isalpha(c) || isdigit(c) || isspace(c) || ispunct(c)) retval[pos++] = c; break; } } } else atris_run_flame(); } SDL_FreeSurface(text); } } /*************************************************************************** * load_identity_file() * Parse an identity file. *********************************************************************PROTO*/ identity * load_identity_file() { identity *retval; char buf[2048]; FILE *fin = fopen(ID_FILENAME, "rt"); int count = 0; int i; if (!fin) { Debug("fopen(%s)\n", ID_FILENAME); Debug("Cannot open Identity File.\n"); Calloc(retval,identity *,sizeof(identity)); return retval; } Calloc(retval,identity *,sizeof(identity)); while (!(feof(fin))) { do { fgets(buf,sizeof(buf),fin); } while (!feof(fin) && (buf[0] == '\n' || buf[0] == '#')); if (feof(fin)) break; if (strchr(buf,'\n')) *(strchr(buf,'\n')) = 0; count++; } rewind(fin); retval->n = count; if (!count) { /* do nothing */ } else { Calloc(retval->p,person *,sizeof(person)*count); i = 0; while (!(feof(fin))) { char *p; do { fgets(buf,sizeof(buf),fin); } while (!feof(fin) && (buf[0] == '\n' || buf[0] == '#')); if (feof(fin)) break; if (strchr(buf,'\n')) *(strchr(buf,'\n')) = 0; sscanf(buf,"%d",&retval->p[i].level); p = strchr(buf,' '); if (!p) { retval->p[i].name = "-garbled-"; } else { retval->p[i].name = strdup( p + 1 ); } i++; } } fclose(fin); Debug("Identity File [%s] loaded (%d players).\n",ID_FILENAME, count); return retval; } /*************************************************************************** * save_identity_file() * Saves the information to an identity file. *********************************************************************PROTO*/ void save_identity_file(identity *id, char *new_name, int new_level) { FILE *fin = fopen(ID_FILENAME,"wt"); int i; if (!fin) { Debug("fopen(%s): cannot write Identity File.\n",ID_FILENAME); return; } fprintf(fin,"# Alizarin Tetris Identity File\n" "#\n" "# Format:\n" "#[level] [name] (no space before level, one space after)\n" ); for (i=0; in ;i++) { fprintf(fin,"%d %s\n",id->p[i].level, id->p[i].name); } if (new_name) { fprintf(fin,"%d %s\n",new_level, new_name); } #ifdef DEBUG Debug("Identity File [%s] saved (%d players).\n",ID_FILENAME, id->n + (new_name != NULL)); #endif fclose(fin); return; } /*************************************************************************** * network_choice_action() * What to do when they click on the network choice button ... ***************************************************************************/ static int network_choice_action(WalkRadio *wr) { if (wr->defaultchoice == 0) { /* I am client */ clear_screen_to_flame(); draw_string("Who is the Server?", color_network_menu, screen->w/2, screen->h/2, DRAW_LEFT | DRAW_UPDATE); wr->data = input_string(screen, screen->w/2, screen->h/2, 0); } else if (wr->data) { Free(wr->data); } else wr->data = NULL; return 1; } /*************************************************************************** * network_choice() * Do you want to be the client or the server? Returns the hostname. *********************************************************************PROTO*/ char * network_choice(SDL_Surface *screen) { static WalkRadioGroup *wrg = NULL; SDL_Event event; if (!wrg) { wrg = create_single_wrg( 2 ) ; wrg->wr[0].label[0] = "I am the Client. I will specify a server."; wrg->wr[0].label[1] = "I will be the Server."; setup_radio(&wrg->wr[0]); wrg->wr[0].x = (screen->w - wrg->wr[0].area.w) / 2; wrg->wr[0].y = (screen->h - wrg->wr[0].area.h) / 2; wrg->wr[0].action = network_choice_action; } clear_screen_to_flame(); draw_string("Who is the Server?", color_network_menu, screen->w/2, wrg->wr[0].y, DRAW_CENTER | DRAW_UPDATE | DRAW_ABOVE); draw_radio(&wrg->wr[0], 1); while (1) { int retval; poll_and_flame(&event); retval = handle_radio_event(wrg, &event); if (retval != -1) return wrg->wr[0].data; } } /*************************************************************************** * new_player() * Add another player ... Displays a little dialog so that the new player * can enter a new name and a new level. **************************************************************************/ static void new_player(SDL_Surface * screen, identity **id) { char *new_name, *new_level; int level; clear_screen_to_flame(); draw_string("Enter your name:", color_who_are_you, screen->w / 2, screen->h / 2, DRAW_CLEAR | DRAW_LEFT); new_name = input_string(screen, screen->w/2, screen->h/2, 0); if (strlen(new_name)) { clear_screen_to_flame(); draw_string("Welcome ", color_purple, screen->w/2, screen->h/2, DRAW_CLEAR | DRAW_LEFT | DRAW_LARGE | DRAW_ABOVE); draw_string(new_name, color_purple, screen->w/2, screen->h/2, DRAW_CLEAR | DRAW_LARGE | DRAW_ABOVE); draw_string("Starting level (2-10):", color_who_are_you, screen->w / 2, screen->h / 2, DRAW_CLEAR | DRAW_LEFT); new_level = input_string(screen, screen->w/2, screen->h/2, 0); level = 0; sscanf(new_level,"%d",&level); if (level < 2) level = 2; if (level > 10) level = 10; save_identity_file(*id, new_name, level); (*id) = load_identity_file(); free(new_level); } free(new_name); } /*************************************************************************** * who_are_you() * Asks the player to choose an identity ... * Returns -1 on "cancel". *********************************************************************PROTO*/ int who_are_you(SDL_Surface *screen, identity **id, int taken, int p) { WalkRadioGroup *wrg = NULL; int i; int retval; SDL_Event event; char buf[1024]; restart: /* sigh! */ wrg = create_single_wrg((*id)->n + 2); for (i=0; i<(*id)->n; i++) { if (i == taken) SPRINTF(buf,"%s (already taken!)",(*id)->p[i].name); else SPRINTF(buf,"%s (Level %d)",(*id)->p[i].name, (*id)->p[i].level); wrg->wr[0].label[i] = strdup(buf); } wrg->wr[0].label[(*id)->n] = "-- New Player --"; wrg->wr[0].label[(*id)->n+1] = "-- Cancel --"; setup_radio(&wrg->wr[0]); wrg->wr[0].x = (screen->w - wrg->wr[0].area.w) / 2; wrg->wr[0].y = (screen->h - wrg->wr[0].area.h) / 2; wrg->wr[0].action = NULL /* return default choice */; clear_screen_to_flame(); if (p == 1) { draw_string("Left = A Rotate = W Right = D Drop = S", color_keys_explain, screen->w / 2, 0, DRAW_CENTER | DRAW_UPDATE); draw_string("Player 1: Who Are You?", color_who_are_you, screen->w / 2, wrg->wr[0].y - 30, DRAW_CENTER | DRAW_UPDATE); } else { draw_string("Use the Arrow keys. Rotate = Up Drop = Down", color_keys_explain, screen->w / 2, 0, DRAW_CENTER | DRAW_UPDATE); draw_string("Player 2: Who Are You?", color_who_are_you, screen->w / 2, wrg->wr[0].y - 30, DRAW_CENTER | DRAW_UPDATE); } draw_radio(&wrg->wr[0], 1); while (1) { poll_and_flame(&event); retval = handle_radio_event(wrg, &event); if (retval == -1 || retval == taken) continue; if (retval == (*id)->n) { new_player(screen, id); goto restart; } if (retval == (*id)->n+1) return -1; return retval; } return 0; } /* * $Log: identity.c,v $ * Revision 1.16 2000/11/06 04:44:15 weimer * fixed that who-is-the-server thing * * Revision 1.15 2000/11/02 03:06:20 weimer * better interface for walk-radio menus: we are now ready for Kiri to change * them to add run-time options ... * * Revision 1.14 2000/11/01 03:53:06 weimer * modifications for version 1.0.1: you can pick your starting level, you can * pick the AI difficulty factor, the game is better about placing new pieces * when there is garbage, when things fall out of your control they now fall * at a uniform rate ... * * Revision 1.13 2000/10/29 21:28:58 weimer * fixed a few failures to clear the screen if we didn't have a flaming * backdrop * * Revision 1.12 2000/10/29 21:23:28 weimer * One last round of header-file changes to reflect my newest and greatest * knowledge of autoconf/automake. Now if you fail to have some bizarro * function, we try to go on anyway unless it is vastly needed. * * Revision 1.11 2000/10/29 19:04:33 weimer * minor highscore handling changes: new filename, use the draw_string() and * draw_bordered_rect() and input_string() interfaces, handle the widget layer * and the flame layer, etc. Also fix a minor bug where you would be prevented * from settling if you pressed a key even if it didn't really move you. :-) * * Revision 1.10 2000/10/29 17:23:13 weimer * incorporate "xflame" flaming background for added spiffiness ... * * Revision 1.9 2000/10/28 22:33:18 weimer * add a blinking cursor to the input string widget * * Revision 1.8 2000/10/28 16:40:17 weimer * Further changes: we can now build .tar.gz files and RPMs! * * Revision 1.7 2000/10/21 01:14:43 weimer * massic autoconf/automake restructure ... * * Revision 1.6 2000/10/18 23:57:49 weimer * general fixup, color changes, display changes. * Notable: "Safe" Blits and Updates now perform "clipping". No more X errors, * we hope! * * Revision 1.5 2000/10/18 02:04:02 weimer * playability changes ... * * Revision 1.4 2000/10/14 01:56:35 weimer * remove dates from identity files * * Revision 1.3 2000/10/13 15:41:53 weimer * revamped AI support, now you can pick your AI and have AI duels (such fun!) * the mighty Aliz AI still crashes a bit, though ... :-) * * Revision 1.2 2000/10/13 02:26:54 weimer * rudimentary identity functions, including adding new players * * Revision 1.1 2000/10/12 01:38:07 weimer * added initial support for persistent player identities * */