ConfigFile::ConfigFile( std::string Filename ) { ALLEGRO_FILE* fileHnd; std::string document; char buf[1024]; fileHnd = al_fopen( Filename.c_str(), "r" ); if( fileHnd != 0 ) { document.clear(); while( !al_feof( fileHnd ) ) { al_fgets( fileHnd, (char*)&buf, 1024 ); document.append( (char*)&buf ); memset( (void*)buf, 0, 1024 ); } ParseFile( document ); al_fclose( fileHnd ); } }
void load_translation_tags(void) { ALLEGRO_FILE *f = al_fopen(getResource("English.utf8"), "r"); if (!f) { native_error("Couldn't load English.utf8."); } char buf[5000]; while (al_fgets(f, buf, 5000) != NULL) { if (buf[strlen(buf)-1] == 0xa) buf[strlen(buf)-1] = 0; if (buf[strlen(buf)-1] == 0xd) buf[strlen(buf)-1] = 0; for (int i = 0; buf[i]; i++) { if (buf[i] == '^') buf[i] = '\n'; } pre_translated_strings.push_back(std::string(buf)); } al_fclose(f); }
GameLogic::GameLogic(int Width, int Height, float LogicFPS) { Debug = false; Display = NULL; EventQueue = NULL; Timer = NULL; Bitmap.Logo = NULL; Bitmap.Title = NULL; Font.Small = NULL; Font.Medium = NULL; Font.Big = NULL; Sound.HitWall = NULL; Sound.HitPaddle = NULL; Sound.BackgroundMusic = NULL; UserDataFile = NULL; DisplayWidth = Width; DisplayHeight = Height; TimerStep = 1.0 / LogicFPS; bool key[2] = { false, false }; float alpha = 0; float colr = 0; float colg = 0; float colb = 0; int tick = 0; int menu = 0; int high_score = 0; bool restart = true; int score = 0, multi = 1, final_score = 1; bool game_over, redraw; char scoretxt[8] = ""; char multitxt[4] = ""; char final_scoretxt[16] = ""; char hightxt[16] = ""; // intro screen while (1) { ALLEGRO_EVENT ev; al_wait_for_event(EventQueue, &ev); if(ev.type == ALLEGRO_EVENT_TIMER) { // trigger redraw tick++; if(tick < 180) { colr = colg = colb = (0.5 * sin( (tick - 90) * ALLEGRO_PI / 180.0) + 0.5); alpha = 0; } else if(tick < 360) { alpha = (0.5 * sin( (tick + 90) * ALLEGRO_PI / 180.0) + 0.5); colr = colg = colb = 1; } else if(tick > 450 && tick < 630) { colr = colg = colb = alpha = (0.5 * cos( (tick - 90) * ALLEGRO_PI / 180.0) + 0.5); } else if(tick > 632) { break; } redraw = true; } else if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { return; } else if(ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) { break; } if(redraw && al_is_event_queue_empty(EventQueue)) { redraw = false; al_clear_to_color(al_map_rgb_f(colr,colg,colb)); al_draw_tinted_bitmap(Bitmap.Logo, al_map_rgba_f(alpha, alpha, alpha, alpha), (DisplayWidth - al_get_bitmap_width(Bitmap.Logo) ) / 2, (DisplayHeight - al_get_bitmap_height(Bitmap.Logo) )/ 2, 0); al_flip_display(); } } al_flip_display(); al_clear_to_color(al_map_rgb(0,0,0)); // load hiscore info UserDataFile = al_fopen("assets/hiscore.txt", "r"); if(UserDataFile) { char *line = (char*) malloc (17); line = al_fgets(UserDataFile, line, 17); high_score = atoi(line); free(line); } else { high_score = 0; } final_score = 0; sprintf(hightxt, "High: %d", high_score); al_fclose(UserDataFile); // main menu loop while (1) { ALLEGRO_EVENT ev; al_wait_for_event(EventQueue, &ev); if(ev.type == ALLEGRO_EVENT_TIMER) { // trigger redraw redraw = true; } else if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { // exit if the Display is closed return; } else if(ev.type == ALLEGRO_EVENT_MOUSE_AXES || ev.type == ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY) { // track mouse movement if((ev.mouse.y > 350) && (ev.mouse.y < 388) && (ev.mouse.x > 250) && (ev.mouse.x < 388)) { menu = 1; } else { menu = 0; } } else if(ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) { // track mouse clicks if(menu == 1) { break; } } if(redraw && al_is_event_queue_empty(EventQueue)) { // process entire queue and only render if the Timer has ticked redraw = false; al_clear_to_color(al_map_rgb(0,0,0)); al_draw_bitmap(Bitmap.Title, (DisplayWidth - al_get_bitmap_width(Bitmap.Title) ) / 2, 16, 0); al_draw_text(Font.Small, al_map_rgb(128,128,0), DisplayWidth / 2, 250, ALLEGRO_ALIGN_CENTRE, "Version 0.1"); if(menu == 1) { al_draw_text(Font.Medium, al_map_rgb(128,0,0), DisplayWidth / 2, 350, ALLEGRO_ALIGN_CENTRE, "Play Now!"); } else { al_draw_text(Font.Medium, al_map_rgb(128,128,0), DisplayWidth / 2, 350, ALLEGRO_ALIGN_CENTRE, "Play Now!"); } al_flip_display(); } } // seed rand function srand(al_get_time()); // game wrapper lets us restart the game while(restart) { // hide the cursor //al_hide_mouse_cursor(Display); // assume we don't want to play again restart = false; // Base objects Ball StarterBall = Ball(); Paddle StarterPaddle = Paddle(0); Paddle StarterPaddle2 = Paddle(DisplayHeight - 8); Paddle StarterPaddle3 = Paddle(0, true); Paddle StarterPaddle4 = Paddle(DisplayWidth - 8, true); // TODO: load the right map // set Bitmap.Title // set base speed // create list of block entities // Populate entity lists // Remove static data when we get map loading done for(int i=0; i < 64; i++) { Brick SingleBlockyEntity = Brick((i % 16) * 40, 80 + ( (i / 16) * 10), i % 8); Bricks.push_back(SingleBlockyEntity); } Paddles.push_back(StarterPaddle); Paddles.push_back(StarterPaddle2); Paddles.push_back(StarterPaddle3); Paddles.push_back(StarterPaddle4); Balls.push_back(StarterBall); // save high score if the final score is higher if(final_score > high_score) { high_score = final_score; sprintf (hightxt, "High: %d", high_score); } // reset score if not a continuation // init hud // force initial draw redraw = true; // reset physics game_over = false; // main game loop while(1) { ALLEGRO_EVENT ev; al_wait_for_event(EventQueue, &ev); if(ev.type == ALLEGRO_EVENT_TIMER) { // game logic loop if(!game_over) { // calculate each ball's new position and check for... Path CurrentPath; for(int i = 0; i < Balls.size(); i++) { CurrentPath = Balls[i].GetPath(TimerStep); // distance traveled in axis directions in time delta t float NX = Balls[i].Position.DeltaX * TimerStep; float NY = Balls[i].Position.DeltaY * TimerStep; // new unencombered position float NewPositionX = Balls[i].Position.X + NX; float NewPositionY = Balls[i].Position.Y + NY; ClosestEntity Closest; Closest.Magnitude = 10000; // look for collisions for(int j = 0; j < (int)Bricks.size(); j++) { // only check items that haven't been hit in the most recent update if (!Bricks[j].HasBeenHit()) { Intersection Point = Bricks[j].PathIntersect(CurrentPath); if (Point.Type == Intersecting) { // mark this hit so we don't check for it again... // until the next update frame. Bricks[i].Hit = true; // see how far the collision is float Magnitude = sqrt(pow(Point.X - Balls[i].Position.X, 2) + pow(Point.Y - Balls[i].Position.Y, 2)); if (Magnitude < Closest.Magnitude) { // nab the closest collision so we can handle multiple collisions Closest.Magnitude = Magnitude; Closest.EntityIndex = j; Closest.CollisionPoint = Point; } } } } if (Closest.CollisionPoint.Type == Intersecting) { if(Bricks[Closest.EntityIndex].Harm(Balls[i].CollisionDamage)) { // TODO: play a sound // Update the ball to the point of collision Balls[i].Position.X = Closest.CollisionPoint.X; Balls[i].Position.Y = Closest.CollisionPoint.Y; // Reflect the ball in the appropriate direction switch(Closest.CollisionPoint.From) { default: case Top: case Bottom: Balls[i].ReflectY(); break; case Left: case Right: Balls[i].ReflectX(); break; } /* Find the fraction of DeltaT that had to occur before this collision float UnknownT = TimerStep * (Closest.Magnitude / sqrt(pow(NX,2) + pow(NY, 2))); // simlulate the ball movement after the collision Balls[i].GetPath(TimerStep - UnknownT); break;*/ } if(NewPositionX > 0.0f && NewPositionX < DisplayWidth - Balls[i].Width && NewPositionY > 0.0f && NewPositionY < DisplayHeight - Balls[i].Height) { Balls[i].Live = true; Balls[i].Position.X = NewPositionX; Balls[i].Position.Y = NewPositionY; } else { Balls[i].Live = false; } } // make sure at least one ball is in play if(Balls[0].BallCount < 1) { game_over = true; } } } else { // end game animation logic } // trigger a render every tick redraw = true; } else if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { break; } else if(ev.type == ALLEGRO_EVENT_MOUSE_AXES || ev.type == ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY) { if(!game_over) { // update each paddle for(int i = 0; i < Paddles.size(); i++) { // horizontal clip if(Paddles[i].IsHorizontal()) { if(ev.mouse.x < (Paddles[i].Width / 2) ) { Paddles[i].Position.X = 0; } else if(ev.mouse.x > DisplayWidth - (Paddles[i].Width / 2) ) { Paddles[i].Position.X = DisplayWidth - Paddles[i].Width; } else { Paddles[i].Position.X = ev.mouse.x - (Paddles[i].Width / 2); } } else { // vertical clip if(ev.mouse.y < (Paddles[i].Height / 2) ) { Paddles[i].Position.Y = 0; } else if(ev.mouse.y > DisplayHeight - (Paddles[i].Height / 2) ) { Paddles[i].Position.Y = DisplayHeight - Paddles[i].Height; } else { Paddles[i].Position.Y = ev.mouse.y - (Paddles[i].Height / 2); } } } } else { // track mouse movement for retry menu logic } } else if(ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) { if(game_over) { // track mouse clicks for retry menu logic } else { // Debug // add a ball at the current mouse position } } else if(ev.type == ALLEGRO_EVENT_KEY_DOWN) { // set keys we are interested in if pressed switch(ev.keyboard.keycode) { case ALLEGRO_KEY_ESCAPE: key[KEY_ESC] = true; break; case ALLEGRO_KEY_SPACE: key[KEY_SPACE] = true; break; } } else if(ev.type == ALLEGRO_EVENT_KEY_UP) { // release keys we are interested in if let go switch(ev.keyboard.keycode) { case ALLEGRO_KEY_ESCAPE: key[KEY_ESC] = false; break; case ALLEGRO_KEY_SPACE: key[KEY_SPACE] = false; break; } } if(redraw && al_is_event_queue_empty(EventQueue)) { //The render loop redraw = false; if(!game_over) { // game play // blank al_clear_to_color(al_map_rgb(128,128,128)); // render each brick for(int i = 0; i < Bricks.size(); i++) { Bricks[i].Render(); } // render each ball for(int i = 0; i < Balls.size(); i++) { Balls[i].Render(); } // render each paddle for(int i = 0; i < Paddles.size(); i++) { Paddles[i].Render(); } // render HUD sprintf (scoretxt, "%d", score); sprintf (multitxt, "%d", multi); al_draw_text(Font.Medium, al_map_rgb(0,0,0), 8, 8, ALLEGRO_ALIGN_LEFT, "Score"); al_draw_text(Font.Medium, al_map_rgb(255,255,255), 128, 8, ALLEGRO_ALIGN_LEFT, scoretxt); al_draw_text(Font.Medium, al_map_rgb(0,0,0), 300, 8, ALLEGRO_ALIGN_LEFT, "x"); al_draw_text(Font.Medium, al_map_rgb(255,255,255), 316, 8, ALLEGRO_ALIGN_LEFT, multitxt); al_draw_text(Font.Medium, al_map_rgb(0,0,0), 424, 8, ALLEGRO_ALIGN_LEFT, hightxt); } else { // render retry menu al_clear_to_color(al_map_rgb(128,128,128)); } // always flip Display al_flip_display(); } } } // save high score if the final score is higher if(final_score > high_score) { high_score = final_score; } sprintf (hightxt, "%d", high_score); // write highscore to file UserDataFile = al_fopen("assets/hiscore.txt", "w"); if(UserDataFile) { al_fputs(UserDataFile, hightxt); al_fclose(UserDataFile); } // proper cleanup is important! al_destroy_bitmap(Bitmap.Title); al_destroy_bitmap(Bitmap.Logo); al_destroy_timer(Timer); al_destroy_display(Display); al_destroy_event_queue(EventQueue); }
void load(std::vector<Bone> &bones, int bmp_w, int bmp_h, std::string filename) { ALLEGRO_FILE *f; if (engine) { f = engine->get_cpa()->load(filename); } else { f = al_fopen(filename.c_str(), "rb"); } if (!f) { General::log_message("Error loading bones " + filename); return; } char buf[1000]; while (1) { if (al_fgets(f, buf, 1000) == NULL) break; Bones::Type bone_type; sscanf(buf, "<%d>", (int *)&bone_type); if (al_fgets(f, buf, 1000) == NULL) break; std::vector<float> vertices; while (1) { int x, y, n1, n2; if (al_fgets(f, buf, 1000) == NULL) break; if (sscanf(buf, "\t<%d><x>%d</x><y>%d</y></%d>", &n1, &x, &y, &n2) < 4) break; vertices.push_back(x); vertices.push_back(y); } std::vector<int> splits; splits.push_back(vertices.size() / 2); float *verts = new float[vertices.size()]; std::vector< General::Point<float> > outline; for (unsigned int i = 0; i < vertices.size() / 2; i++) { int index = i*2; verts[index] = vertices[index] - bmp_w/2; verts[index+1] = vertices[index+1] - bmp_h; outline.push_back(General::Point<float>( verts[index], verts[index+1] )); } std::vector<Triangulate::Triangle> triangles; Triangulate::get_triangles(outline, splits, triangles); Bone b = Bone(bone_type, outline, triangles, General::Size<int>(bmp_w, bmp_h)); bones.push_back(b); delete[] verts; } al_fclose(f); }
/* get_xdg_path - locate an XDG user dir */ static ALLEGRO_PATH *_get_xdg_path(const char *location) { ALLEGRO_PATH *location_path = NULL; ALLEGRO_PATH *xdg_config_path = NULL; ALLEGRO_FILE *xdg_config_file = NULL; const char *xdg_config_home = getenv("XDG_CONFIG_HOME"); int fd; if (xdg_config_home) { /* use $XDG_CONFIG_HOME since it exists */ xdg_config_path = al_create_path_for_directory(xdg_config_home); } else { /* the default XDG location is ~/.config */ xdg_config_path = al_get_standard_path(ALLEGRO_USER_HOME_PATH); if (!xdg_config_path) return NULL; al_append_path_component(xdg_config_path, ".config"); } al_set_path_filename(xdg_config_path, "user-dirs.dirs"); fd = open(al_path_cstr(xdg_config_path, '/'), O_RDONLY); if (fd != -1) { xdg_config_file = al_fopen_fd(fd, "r"); } al_destroy_path(xdg_config_path); if (!xdg_config_file) return NULL; while (!al_feof(xdg_config_file)) { char line[XDG_MAX_PATH_LEN]; /* one line of the config file */ const char *p = line; /* where we're at in the line */ char component[XDG_MAX_PATH_LEN]; /* the path component being parsed */ int i = 0; /* how long the current component is */ al_fgets(xdg_config_file, line, XDG_MAX_PATH_LEN); /* skip leading white space */ while (*p == ' ' || *p == '\t') p++; /* skip the line if it does not begin with XDG_location_DIR */ if (strncmp(p, "XDG_", 4)) continue; p += 4; if (strncmp(p, location, strlen(location))) continue; p += strlen(location); if (strncmp(p, "_DIR", 4)) continue; p += 4; /* skip past the =", allowing for white space */ while (*p == ' ' || *p == '\t') p++; if (*p++ != '=') continue; while (*p == ' ' || *p == '\t') p++; if (*p++ != '"') continue; /* We've found the right line. Now parse it, basically assuming that it is in a sane format. */ if (!strncmp(p, "$HOME", 5)) { /* $HOME is the only environment variable that the path is allowed to use, and it must be first, by specification. */ location_path = al_get_standard_path(ALLEGRO_USER_HOME_PATH); p += 5; } else { location_path = al_create_path("/"); } while (*p) { if (*p == '"' || *p == '/') { /* add the component (if non-empty) to the path */ if (i > 0) { component[i] = 0; al_append_path_component(location_path, component); i = 0; } if (*p == '"') break; } else { if (*p == '\\') { /* treat any escaped character as a literal */ p++; if (!*p) break; } component[i++] = *p; } p++; } /* Finished parsing the path. */ break; } al_fclose(xdg_config_file); return location_path; }
void WorldStage::LoadMapFromFileOrCreateNewMap() { const int MAP_WIDTH = 80; const int MAP_HEIGHT = 80; const int ARBITRARY_NUMBER_OF_WALLS = 20; const int VALID_VERSION = 0; currentMap = new RegionalMap(); currentMap->InitToField(MAP_WIDTH, MAP_HEIGHT, 0); //Determine map player is on int mapX = 0, mapY = 0; auto player = actorList.GetActor(1); if(player) { mapX = player->x/MAP_WIDTH; mapY = player->y/MAP_HEIGHT; } //Load that one std::stringstream ss; ss << "region." << mapX << "." << mapY; //Try to load the region by that name ALLEGRO_FILE *file = al_fopen(ss.str().c_str(), "r"); if(file) { const int BUF_SIZE = 512; char buffer[BUF_SIZE]; bool isValid = true; if(!al_fgets(file, buffer, BUF_SIZE)) { std::string str = buffer; if(!str.empty() && str[str.length()-1] == '\n') str.erase(str.length()-1); if(strcmp(str.c_str(), "b272bda9bf0c1cdcba614b5ed99c4d62") != 0) { isValid = false; } } if(isValid && !al_fgets(file, buffer, BUF_SIZE)) { std::string str = buffer; if(!str.empty() && str[str.length()-1] == '\n') str.erase(str.length()-1); if(strcmp(str.c_str(), "0") != 0) { isValid = false; } } if(isValid) { for(int y = 0; y < MAP_HEIGHT; y++) for(int x = 0; x < MAP_WIDTH; x++) { //returns bytes read, 32bits = 4 bytes int material = al_fread32le(file); if(!al_feof(file)) { currentMap->tile[x][y].materialTypeIndex = material; } } //Get actor IDs int actorId = al_fread32le(file); while(!al_feof(file)) { currentMap->actorIDs.push_back(actorId); actorId = al_fread32le(file); } } al_fclose(file); } else //no file { for(int nWalls = 0; nWalls < ARBITRARY_NUMBER_OF_WALLS; nWalls++) { //Manually place down some walls to run into int x = rng::Rand(MAP_WIDTH); int y = rng::Rand(MAP_HEIGHT); currentMap->tile[x][y].materialTypeIndex = 1; } } }