#include #if !defined (__APPLE__) #include #else #include #endif #include "sdl.h" #include "../stubs.h" #include "../main.h" #include "../common.h" #include "../player.h" #include "../game.h" #include "../context.h" #include "../tiles/tiles.h" #include "../tile.h" #include "../console.h" #include "../net/sockets.h" void interfaceSetInterval(const char *input_string) { if (input_string) { int new_tickrate = atoi(input_string); SDL_RemoveTimer(timer_id); if (new_tickrate > 0) { tickrate = new_tickrate; timer_id = SDL_AddTimer(tickrate, pushTickEvent, NULL); } } } static int networkThread(void *nada) { int reuse = 1; int net_socket; struct sockaddr_in server_address; if ((net_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { consoleLog("socket() success'd"); return ERROR; } consoleLog("socket() success'd"); if (setsockopt(net_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse)) < 0) { consoleLog("setsockopt() error'd"); } consoleLog("setsockopt() success'd"); //fcntl(net_socket, F_SETFL, O_NONBLOCK); memset(&server_address, 0, sizeof(server_address)); server_address.sin_family = AF_INET; server_address.sin_addr.s_addr = htonl(INADDR_ANY); server_address.sin_port = htons(31337); if (bind(net_socket, (struct sockaddr *) &server_address, sizeof(server_address)) < 0) { consoleLog("bind() error'd"); return ERROR; } consoleLog("bind() success'd"); if (listen(net_socket, 32) < 0) { consoleLog("listen() error'd"); return ERROR; } consoleLog("listen() success'd"); char test_string[31]; sprintf(test_string, "server running on fd %d!", net_socket); consoleLog(test_string); /******/ // fd_set master_fds; // fd_set read_fds; // int max_fd; int i; // current fd in for char data_buffer[2048]; /* set up our fds */ FD_ZERO(&master_fds); FD_ZERO(&read_fds); FD_SET(net_socket, &master_fds); max_fd = net_socket; SDL_Event event; SDL_UserEvent user_event; user_event.type = SDL_USEREVENT; user_event.code = EVENT_NET; user_event.data1 = NULL; user_event.data2 = NULL; event.type = SDL_USEREVENT; event.user = user_event; while(1 == 1) { //while (is_networking) { read_fds = master_fds; if (select(max_fd+1, &read_fds, NULL, NULL, NULL) == -1) { consoleLog("error on network select()"); } for (i=0;i <= max_fd; i++) { if (FD_ISSET(i, &read_fds)) { if (i == net_socket) { struct sockaddr_storage client_address; socklen_t address_length = sizeof(client_address); int new_fd = accept(net_socket, (struct sockaddr *)&client_address, &address_length); if (new_fd == -1) { consoleLog("accept() error'd"); } else { FD_SET(new_fd, &master_fds); if (new_fd > max_fd) { max_fd = new_fd; } char remote_ip[INET6_ADDRSTRLEN]; event.user.data1 = (void *)new_fd; event.user.data2 = (void *)inet_ntop(client_address.ss_family, get_in_addr((struct sockaddr *)&client_address), remote_ip, INET6_ADDRSTRLEN); event.user.code = EVENT_NET_ACCEPT; SDL_PushEvent(&event); } } else if (i == client_socket) { int bytes = 0; if((bytes = recv(i, data_buffer, sizeof data_buffer, 0)) <= 0) { if (bytes == 0) { event.user.code = EVENT_NET_CLIENT_LOST; event.user.data1 = (void *)i; } else { event.user.code = EVENT_NET_CLIENT_ERROR; event.user.data1 = (void *)i; } SDL_PushEvent(&event); close(i); FD_CLR(i, &master_fds); } else { data_buffer[bytes] = '\0'; // TEMP struct NetMessage *net_message; net_message = malloc(sizeof(struct NetMessage)); net_message->fd = i; net_message->size = bytes; net_message->data = (void *)data_buffer; event.user.code = EVENT_NET_CLIENT_RECV; event.user.data1 = (void *)i; event.user.data2 = (void *)net_message; SDL_PushEvent(&event); } } else if (i > net_socket) { // handle existing client data int bytes = 0; if((bytes = recv(i, data_buffer, sizeof data_buffer, 0)) <= 0) { if (bytes == 0) { event.user.code = EVENT_NET_LOST; event.user.data1 = (void *)i; } else { event.user.code = EVENT_NET_ERROR; event.user.data1 = (void *)i; } SDL_PushEvent(&event); close(i); FD_CLR(i, &master_fds); } else { // good data data_buffer[bytes] = '\0'; // TEMP struct NetMessage *net_message; net_message = malloc(sizeof(struct NetMessage)); net_message->fd = i; net_message->size = bytes; net_message->data = (void *)data_buffer; event.user.code = EVENT_NET_RECV; event.user.data1 = (void *)i; event.user.data2 = (void *)net_message; SDL_PushEvent(&event); } } } } } return 0; } Uint32 pushTickEvent(Uint32 interval, void *param) { SDL_Event event; SDL_UserEvent user_event; user_event.type = SDL_USEREVENT; user_event.code = EVENT_TICK; user_event.data1 = NULL; user_event.data2 = NULL; event.type = SDL_USEREVENT; event.user = user_event; SDL_PushEvent(&event); return interval; } int interfaceInit() { // TODO: read OS's best fullscreen resolution and use it video_width = 800; video_height = 600; video_mode = 0; // Load it up! // since we use threads, Mac OS 10+ support only. Also threaded os. #if _WIN32 | _WIN64 SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_EVENTTHREAD); #else SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER); #endif // Enable Unicode, for later text input SDL_EnableUNICODE(SDL_ENABLE); // Set up our SDL Window if (interfaceVideoSet()) return ERROR; SDL_WM_SetCaption(NAME, NULL); consoleAddCommand("tickrate", interfaceSetInterval); consoleAddCommand("set_video", interfaceVideoSetSize); camera_surface = SDL_CreateRGBSurface(screen->flags, screen->w, screen->h, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask); /* load our surfaces from memory */ font_spritesheet = IMG_Load_RW(SDL_RWFromMem(&font_images, font_images_length), 1); player_spritesheet = IMG_Load_RW(SDL_RWFromMem(&player_images, player_images_length), 1); npc_spritesheet = IMG_Load_RW(SDL_RWFromMem(&npc_images, npc_images_length), 1); wall_spritesheet = IMG_Load_RW(SDL_RWFromMem(&wall_images, wall_images_length), 1); floor_spritesheet = IMG_Load_RW(SDL_RWFromMem(&floor_images, floor_images_length), 1); door_spritesheet = IMG_Load_RW(SDL_RWFromMem(&door_images, door_images_length), 1); shadow_spritesheet = IMG_Load_RW(SDL_RWFromMem(&shadow_images, shadow_images_length), 1); // Fill our screen w/ black SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 32, 128, 64)); // Update! SDL_Flip(screen); /* now we load up our timer, woo */ tickrate = 500; timer_id = SDL_AddTimer(tickrate, pushTickEvent, NULL); /* now we spawn a network thread that will push user events to SDL */ network_thread = SDL_CreateThread(networkThread, NULL); return SUCCESS; } /* draw the player's current view */ void cameraDraw() { SDL_Rect camera_rect = {0, 0, screen->w, screen->h}; int step_x = player->x - ((struct PlayerTile*)player->data)->vision; int step_y = player->y - ((struct PlayerTile*)player->data)->vision; int end_x = player->x + ((struct PlayerTile*)player->data)->vision; int end_y = player->y + ((struct PlayerTile*)player->data)->vision; // TODO: The camera's center offset should change based upon distance to the map's width/height! // TODO: Use zoomed copies of spritesheets for tile zooming based on player vision. float camera_offset_x = (player->x+1)*TILE_WIDTH - (camera_rect.w/2); float camera_offset_y = (player->y+1)*TILE_WIDTH - (camera_rect.h/2); while (step_x < end_x) { step_y = player->y - ((struct PlayerTile*)player->data)->vision; while (step_y < end_y) { // TODO: draw the layer immediately in front of the player at partial translucency if (step_x >= 0 && step_y >= 0 && step_x < current_map->width && step_y < current_map->height) { struct Tile *current_tile; current_tile = &(current_map)->matrix[step_x][step_y]; int tile_id = current_tile->id; while(current_tile) { int x_offset = current_tile->id / 16; // 16 tiles across in spritesheet int y_offset = current_tile->id - (x_offset*16); SDL_Rect sprite_offset = { x_offset*TILE_WIDTH, y_offset*TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT}; SDL_Rect tile_rect = {(step_x*TILE_WIDTH)-camera_offset_x, (step_y*TILE_WIDTH)-camera_offset_y, TILE_WIDTH, TILE_HEIGHT}; switch (current_tile->tid) { case WALL: SDL_BlitSurface(wall_spritesheet, &sprite_offset, camera_surface, &tile_rect); break; case FLOOR: SDL_BlitSurface(floor_spritesheet, &sprite_offset, camera_surface, &tile_rect); break; case NPC: SDL_BlitSurface(npc_spritesheet, &sprite_offset, camera_surface, &tile_rect); break; case DOOR: tile_id = tile_id*4; tile_id += ((struct DoorTile*)current_tile->data)->state; y_offset = tile_id / 16; x_offset = tile_id - (y_offset*16); sprite_offset.x = x_offset*TILE_WIDTH; sprite_offset.y = y_offset*TILE_HEIGHT; SDL_BlitSurface(door_spritesheet, &sprite_offset, camera_surface, &tile_rect); break; case PLAYER: y_offset = current_tile->id / TOTAL_CLASSES; x_offset = current_tile->id - (y_offset*TOTAL_CLASSES); sprite_offset.x = x_offset*TILE_WIDTH; sprite_offset.y = y_offset*TILE_HEIGHT; SDL_BlitSurface(shadow_spritesheet, NULL, camera_surface, &tile_rect); SDL_BlitSurface(player_spritesheet, &sprite_offset, camera_surface, &tile_rect); break; } current_tile = current_tile->next; } } else { SDL_Rect tile_rect = {(step_x*TILE_WIDTH)-camera_offset_x, (step_y*TILE_WIDTH)-camera_offset_y, TILE_WIDTH, TILE_HEIGHT}; SDL_FillRect(camera_surface, &tile_rect, SDL_MapRGB(camera_surface->format, 0, 0, 0)); } step_y++; // move down } step_x++; // move right } //SDL_BlitSurface(interfaceScaleSurface(camera_surface, camera_surface->w*(camera_surface->w/camera_rect.w), camera_surface->h*(camera_surface->h/camera_rect.h)), NULL, screen, &camera_rect); SDL_BlitSurface(camera_surface, NULL, screen, &camera_rect); char test[12]; itoa(tickrate, test, 10); interfaceDrawString(test, screen->w-strlen(test)*TILE_WIDTH, 0); } int interfaceLoop() { while (SDL_WaitEvent(&event)) { switch(event.type) { case SDL_USEREVENT: if (event.user.code == EVENT_TICK) { // timer gameLoop(); } else if (event.user.code == EVENT_NET_ACCEPT) { // net char string[127]; sprintf(string, "net accept of %s on fd %d", (char*)event.user.data2, (int*)event.user.data1); consoleLog(string); } else if (event.user.code == EVENT_NET_RECV) { char string[255]; struct NetMessage *net_message = (struct NetMessage*)event.user.data2; sprintf(string, "client(%d): %s", net_message->fd, net_message->data); consoleLog(string); sprintf(string, "%s", net_message->data); send(net_message->fd, string, net_message->size, 0); free(net_message); } else if (event.user.code == EVENT_NET_LOST) { char string[23]; sprintf(string, "net lost for fd %d", (int*)event.user.data1); consoleLog(string); } else if (event.user.code == EVENT_NET_ERROR) { char string[23]; sprintf(string, "net error for fd %d", (int*)event.user.data1); consoleLog(string); } else if (event.user.code == EVENT_NET_CLIENT_RECV) {// begin client char string[255]; struct NetMessage *net_message = (struct NetMessage*)event.user.data2; sprintf(string, "server(%d): %s", net_message->fd, net_message->data); consoleLog(string); free(net_message); } break; case SDL_QUIT: return 0; break; case SDL_KEYDOWN: switch(event.key.keysym.sym) { case 304: case 306: case 308: case 310: break; default: globalContext(event.key.keysym.unicode); break; } break; case SDL_VIDEORESIZE: video_width = event.resize.w; video_height = event.resize.h; interfaceVideoSet(); interfaceDraw(); // redraw break; } interfaceDraw(); // redraw } return 1; } void interfaceDraw() { // TODO: instead of redrawing whole screen, redraw last positions of tiles //SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0)); cameraDraw(); // draw our current view if (current_context == &consoleContext) { interfaceDrawConsole(); } SDL_Flip(screen); // redraw! } void interfaceDrawConsole() { int line; struct ConsoleEntry *entry; entry = console_last_entry; SDL_Rect print_area = {0, 0, screen->w, 9*TILE_HEIGHT}; SDL_FillRect(screen, &print_area, SDL_MapRGB(screen->format, 0, 128, 28)); for (line = 7;line >= 0;line--) { if (entry->size > 0) { interfaceDrawString(entry->string, 0, line*TILE_HEIGHT); } if (entry->prev != NULL) entry = entry->prev; } interfaceDrawChar('>', 0, 8*TILE_HEIGHT); interfaceDrawString(console_cmd, TILE_WIDTH*2, 8*TILE_HEIGHT); } void interfaceDrawChar(char ch, int start_x, int start_y) { int y_offset = ch / 16; // 16 tiles across in spritesheet int x_offset = ch - (y_offset*16); SDL_Rect character_offset = { x_offset*TILE_WIDTH, y_offset*TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT}; SDL_Rect render_position = {start_x, start_y, TILE_WIDTH, TILE_HEIGHT}; SDL_BlitSurface(font_spritesheet, &character_offset, screen, &render_position); } void interfaceDrawString(const char *string, int start_x, int start_y) { int i = 0; while (string[i] != '\0') { interfaceDrawChar(string[i], (start_x)+i*TILE_WIDTH, start_y); i++; } } void interfacePrint(const char *string) { int i = 0; SDL_Rect print_area = {0, screen->h-TILE_HEIGHT, screen->w, TILE_HEIGHT}; SDL_FillRect(screen, &print_area, SDL_MapRGB(screen->format,128, 128, 0)); while (string[i] != '\0') { int y_offset = string[i] / 16; // 16 tiles across in spritesheet int x_offset = string[i] - (y_offset*16); SDL_Rect character_offset = { x_offset*TILE_WIDTH, y_offset*TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT}; SDL_Rect render_position = {i*TILE_WIDTH, 512, TILE_WIDTH, TILE_HEIGHT}; SDL_BlitSurface(font_spritesheet, &character_offset, screen, &render_position); i++; } consoleLog(string); } Uint32 getpixel(SDL_Surface *surface, int x, int y) { int bpp = surface->format->BytesPerPixel; /* Here p is the address to the pixel we want to retrieve */ Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp; switch(bpp) { case 1: return *p; break; case 2: return *(Uint16 *)p; break; case 3: if(SDL_BYTEORDER == SDL_BIG_ENDIAN) return p[0] << 16 | p[1] << 8 | p[2]; else return p[0] | p[1] << 8 | p[2] << 16; break; case 4: return *(Uint32 *)p; break; default: return 0; /* shouldn't happen, but avoids warnings */ } } void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel) { int bpp = surface->format->BytesPerPixel; /* Here p is the address to the pixel we want to set */ Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp; switch(bpp) { case 1: *p = pixel; break; case 2: *(Uint16 *)p = pixel; break; case 3: if(SDL_BYTEORDER == SDL_BIG_ENDIAN) { p[0] = (pixel >> 16) & 0xff; p[1] = (pixel >> 8) & 0xff; p[2] = pixel & 0xff; } else { p[0] = pixel & 0xff; p[1] = (pixel >> 8) & 0xff; p[2] = (pixel >> 16) & 0xff; } break; case 4: *(Uint32 *)p = pixel; break; } } SDL_Surface *interfaceScaleSurface(SDL_Surface *Surface, Uint16 Width, Uint16 Height) { if(!Surface || !Width || !Height) return 0; SDL_Surface *_ret = SDL_CreateRGBSurface(Surface->flags, Width, Height, Surface->format->BitsPerPixel, Surface->format->Rmask, Surface->format->Gmask, Surface->format->Bmask, Surface->format->Amask); double _stretch_factor_x = ((double)(Width) / (double)(Surface->w)), _stretch_factor_y = ((double)(Height) / (double)(Surface->h)); Sint32 x, y, o_x, o_y; for(y = 0; y < Surface->h; y++) for(x = 0; x < Surface->w; x++) for(o_y = 0; o_y < _stretch_factor_y; ++o_y) for(o_x = 0; o_x < _stretch_factor_x; ++o_x) putpixel(_ret, (Sint32)(_stretch_factor_x * x) + o_x, (Sint32)(_stretch_factor_y * y) + o_y, getpixel(Surface, x, y)); return _ret; } int interfaceVideoSet() { if ((screen = SDL_SetVideoMode(video_width, video_height, 32, SDL_SWSURFACE|SDL_DOUBLEBUF|SDL_RESIZABLE|video_fullscreen)) == NULL) { return ERROR; } free(camera_surface); camera_surface = SDL_CreateRGBSurface(screen->flags, screen->w, screen->h, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask); return SUCCESS; } void interfaceVideoSetSize(const char *input_string) { if (input_string) { int i = 0; int j = 0; char height[15]; char width[15]; char fullscreen[1]; int position = 0; while(input_string[i] != '\0') { if (input_string[i] == 'x') { width[j] = '\0'; position = 1; i++; // skip the x j = 0; } else if (input_string[i] == ' ') { height[j] = '\0'; position = 2; i++; // skip the space j = 0; } if (position == 0) { width[j] = input_string[i]; } else if (position == 1) { height[j] = input_string[i]; } else if (position == 2) { fullscreen[j] = input_string[i]; break; // just a boolean, so let's break } j++; i++; } video_height = atoi(height); // ... had to reverse order for it to work on win... video_width = atoi(width); if (fullscreen[0] == '1') { // fullscreen video_fullscreen = SDL_FULLSCREEN; } else if (fullscreen[0] == '0') { // windowed video_fullscreen = 0; } interfaceVideoSet(); } else { consoleLog("Syntax: widthxheight 0|1"); } } void interfaceClose() { SDL_Quit(); }