/* * game.c * * Game book-keeping * * (c) 2008 Thomas White * * thrust3d - a silly game * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include "types.h" #include "model.h" #include "game.h" #include "render.h" #include "utils.h" #include "audio.h" #define MAX_OBJECTS 100 /* Maximum indicies of the rooms - remember they start at zero */ #define MAX_ROOM_X 0 #define MAX_ROOM_Y 2 #define MAX_ROOM_Z 4 static Room *room_new() { Room *r; r = malloc(sizeof(Room)); if ( r == NULL ) return NULL; r->objects = malloc(MAX_OBJECTS*sizeof(ModelInstance *)); r->num_objects = 0; r->num_connected = 0; r->num_lights = 0; return r; } static ModelInstance *room_add_object(Room *room, ModelContext *ctx, const char *name, GLfloat x, GLfloat y, GLfloat z, ObjectAttrib attribs, RenderContext *render) { if ( room->num_objects == MAX_OBJECTS ) return NULL; room->objects[room->num_objects] = model_instance_new(ctx, name, render); if ( room->objects[room->num_objects] != NULL ) { room->objects[room->num_objects]->x = x; room->objects[room->num_objects]->y = y; room->objects[room->num_objects]->z = z; room->objects[room->num_objects]->attribs = attribs; } room->num_objects++; return room->objects[room->num_objects-1]; } static Room *room_load(int rx, int ry, int rz, ModelContext *models, RenderContext *render) { Room *r; char tmp[64]; FILE *fh; snprintf(tmp, 63, "%s/rooms/%02i-%02i-%02i", DATADIR, rx, ry, rz); fh = fopen(tmp, "r"); if ( fh == NULL ) { fprintf(stderr, "Couldn't load room '%s'\n", tmp); return NULL; } r = room_new(); if ( r == NULL ) return NULL; r->rx = rx; r->ry = ry; r->rz = rz; r->comment = NULL; while ( !feof(fh) ) { int i; char line[1024]; GLfloat x, y, z; int rx, ry, rz; fgets(line, 1023, fh); if ( line[0] == '#' ) { continue; } for ( i=0; i= strlen(line) ) continue; line[i] = '\0'; /* "line" is now the model name */ for ( i=strlen(line)+1; iconnected[r->num_connected].rx = rx; r->connected[r->num_connected].ry = ry; r->connected[r->num_connected].rz = rz; r->num_connected++; } else if ( (strcmp(line, "light") == 0) && (sscanf(line+i, "%f %f %f", &x, &y, &z) == 3) ) { r->lights[r->num_lights].x = x; r->lights[r->num_lights].y = y; r->lights[r->num_lights].z = z; r->num_lights++; } else if ( sscanf(line+i, "%f %f %f", &x, &y, &z) == 3 ) { room_add_object(r, models, line, x, y, z, OBJ_NONE, render); } else if ( strcmp(line, "comment") == 0 ) { r->comment = strdup(line+i); } } fclose(fh); r->needed_this_time = 1; return r; } Room *game_find_room(Game *game, int rx, int ry, int rz) { int i; for ( i=0; inum_rooms; i++ ) { if ( ( game->rooms[i]->rx == rx ) && ( game->rooms[i]->ry == ry ) && ( game->rooms[i]->rz == rz ) ) { return game->rooms[i]; } } return NULL; } static void game_delete_room(Game *game, int idx) { int i; Room *room; room = game->rooms[idx]; for ( i=0; inum_objects; i++ ) { free(room->objects[i]); } free(room->objects); free(room->comment); free(room); /* Shift the list up one place */ for ( i=idx+1; inum_rooms; i++ ) { game->rooms[i-1] = game->rooms[i]; } game->num_rooms--; } /* Load the current room and all rooms causally connected */ static void game_load_all_connected(Game *game) { int i; Room *room; /* Go down the current list of rooms, setting 'needed_this_time' to 0 */ for ( i=0; inum_rooms; i++ ) { game->rooms[i]->needed_this_time = 0; } /* Is the current room in the list? Load it if not */ room = game_find_room(game, game->cur_room_x, game->cur_room_y, game->cur_room_z); if ( room == NULL ) { room = room_load(game->cur_room_x, game->cur_room_y, game->cur_room_z, game->models, game->render); if ( room == NULL ) { /* This room couldn't be loaded. */ return; } game->rooms[game->num_rooms] = room; game->num_rooms++; } room->needed_this_time = 1; /* Check that all connected rooms are loaded as well */ for ( i=0; inum_connected; i++ ) { Room *con; int rx, ry, rz; rx = room->connected[i].rx; ry = room->connected[i].ry; rz = room->connected[i].rz; con = game_find_room(game, rx, ry, rz); if ( con == NULL ) { game->rooms[game->num_rooms] = room_load(rx, ry, rz, game->models, game->render); game->num_rooms++; } else { con->needed_this_time = 1; } } /* Remove any rooms left in the list which are no longer needed */ for ( i=0; inum_rooms; i++ ) { if ( !game->rooms[i]->needed_this_time ) { game_delete_room(game, i); } } } /* Create a new "game" structure */ Game *game_new(int width, int height, int disable_vbos, int disable_fbos, int disable_shaders) { Game *g; g = malloc(sizeof(Game)); if ( g == NULL ) return NULL; g->thrusting = 0; g->turn_left = 0; g->turn_right = 0; g->forward = 0; g->reverse = 0; g->tlast = 0; g->cur_room_x = 0; g->cur_room_y = 0; g->cur_room_z = 0; g->num_rooms = 0; g->view_angle = deg2rad(+20.0); g->view_dist = 5.0; g->paused = 0; g->pause_rel = 1; g->frames = 0; g->t_fps = SDL_GetTicks(); g->fps = 0; g->fuel = 1.0; g->radiation = 0.1; /* Renderer setup */ g->render = render_setup(width, height, disable_vbos, disable_fbos, disable_shaders); if ( g->render == NULL ) { fprintf(stderr, "Couldn't initialise renderer\n"); free(g); return NULL; } /* Note: render_setup() initialises GLEW, which must be done before loading models. */ /* Audio setup */ g->audio = audio_setup(); if ( g->audio == NULL ) { fprintf(stderr, "Couldn't initialise audio\n"); free(g); return NULL; } /* Load models */ g->models = model_init(); if ( g->models == NULL ) { fprintf(stderr, "Couldn't create model context\n"); render_shutdown(g->render); free(g); return NULL; } game_load_all_connected(g); /* Initialise the craft */ g->lander = model_instance_new(g->models, "lander", g->render); g->lander->x = 0.0; g->lander->y = 0.0; g->lander->z = -0.90; g->lander->yaw = deg2rad(30.0); g->lander->attribs = OBJ_GRAVITY; return g; } void game_shutdown(Game *game) { render_shutdown(game->render); audio_shutdown(game->audio); free(game); } /* Check if the player needs to be moved to another room */ void game_check_handoff(Game *game) { /* x-axis handoff */ if ( game->lander->x > 5.0 ) { if ( game->cur_room_x >= MAX_ROOM_X ) { game->lander->x = 5.0; game->lander->vx = 0.0; } else { game->lander->x -= 10.0; game->cur_room_x += 1; game_load_all_connected(game); } } if ( game->lander->x < -5.0 ) { if ( game->cur_room_x <= 0 ) { game->lander->x = -5.0; game->lander->vx = 0.0; } else { game->lander->x += 10.0; game->cur_room_x -= 1; game_load_all_connected(game); } } /* y-axis handoff */ if ( game->lander->y > 5.0 ) { if ( game->cur_room_y >= MAX_ROOM_Y ) { game->lander->y = 5.0; game->lander->vy = 0.0; } else { game->lander->y -= 10.0; game->cur_room_y += 1; game_load_all_connected(game); } } if ( game->lander->y < -5.0 ) { if ( game->cur_room_y <= 0 ) { game->lander->y = -5.0; game->lander->vy = 0.0; } else { game->lander->y += 10.0; game->cur_room_y -= 1; game_load_all_connected(game); } } /* z-axis handoff */ if ( game->lander->z > 5.0 ) { if ( game->cur_room_z >= MAX_ROOM_Z ) { game->lander->z = 5.0; game->lander->vz = 0.0; } else { game->lander->z -= 10.0; game->cur_room_z += 1; game_load_all_connected(game); } } if ( game->lander->z < -5.0 ) { if ( game->cur_room_z <= 0 ) { game->lander->z = -5.0; game->lander->vz = 0.0; } else { game->lander->z += 10.0; game->cur_room_z -= 1; game_load_all_connected(game); } } } void game_pause(Game *game) { if ( game->pause_rel == 0 ) return; if ( game->paused ) { game->paused = 0; game->tlast = SDL_GetTicks(); game->pause_rel = 0; } else { game->paused = 1; game->pause_rel = 0; } }