//----------------------------------------------------------------------------- // Filename: njam.cpp // Created: 30. May 2003. by Milan Babuskov // // Purpose: Initialization of the game // Managing resources // Handling Main Menu // // The order of functions in this file is alphabetical // Except for main() and NjamEngine's ctor and destructor. // // Tabs should be at 4 spaces. // Each section is separated with line: //-------... /*----------------------------------------------------------------------------- Copyright 2003 Milan Babuskov This file is part of Njam (http://njam.sourceforge.net). Njam is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Njam is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Njam in file COPYING; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -----------------------------------------------------------------------------*/ // needed for chdir #ifdef __linux__ #include #include #endif #include #include #include #include "SDL.h" #include "SDL_mixer.h" #include "SDL_thread.h" #include "SDL_image.h" #include "njamutils.h" #include "njamfont.h" #include "njammap.h" #include "njam.h" //----------------------------------------------------------------------------- int main(int argc, char *argv[]) { bool Fullscreen = true; bool SWSurface = true; bool UseDGA = false; if (argc > 1) { for (int i=1; iGetCharHeight(); int Column = 440 / m_FontBlue->GetCharWidth(); while (true) { fgets(buffer, 79, script_file); if (feof(script_file)) { printf("njam.cpp: ERROR: Script.txt not terminated with -- line."); m_ScriptLastPos = 0; break; } if (buffer[0] == '-' && buffer[1] == '-') // -- end of script { m_ScriptLastPos = 0; break; } if (buffer[0] == '-') // end of part { m_ScriptLastPos = ftell(script_file); break; } if (buffer[0] == '<') // image { int i = (int)(buffer[2] - '0'); // image index if (buffer[1] == 'G') // image of a ghost { SDL_Rect src, dest; NjamSetRect(dest, 440, 120); NjamSetRect(src, i*25, 0, 25, 25); SDL_BlitSurface(m_SpriteImage, &src, m_Screen, &dest); } else // image of a map-data { i+=2; for (int j=0; jWriteTextColRow(m_Screen, Column, Row, buffer); Row++; } } } //----------------------------------------------------------------------------- bool NjamEngine::Init(bool Fullscreen, bool SoftwareSurface, bool UseDGA) { #ifdef __linux__ sprintf(linux_sdl_driver, "x11\0"); char *driver_name = getenv("SDL_VIDEODRIVER"); if (driver_name) sprintf(linux_sdl_driver, "%s\0", driver_name); if (UseDGA) { printf("You must be root to run DGA\nType ./njam -? for help\n"); putenv("SDL_VIDEODRIVER=dga"); } #else if (UseDGA) printf("Parameter -d is ignored for non-Linux platforms.\n"); #endif LogFile("Initializing SDL: VIDEO & AUDIO...", true); if ( SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO|SDL_INIT_TIMER ) < 0 ) { fprintf(stderr, "Error initializing SDL: %s\n", SDL_GetError()); return false; } else m_SDL = true; LogFile("OK.\nSetting window title..."); SDL_WM_SetCaption("Njam http://njam.sourceforge.net", NULL); // load .bmp for icon LogFile("done.\nLoading icon..."); m_Icon = SDL_LoadBMP("data/njamicon.bmp"); if (!m_Icon) { LogFile("FAILED.\n"); LogFile((const char *)SDL_GetError()); return false; } LogFile("OK.\n"); SDL_WM_SetIcon(m_Icon, NULL); LogFile("Setting video mode: 800x600x16..."); Uint32 flags = SDL_ANYFORMAT; if (Fullscreen) flags |= SDL_FULLSCREEN; if (SoftwareSurface) flags |= SDL_SWSURFACE; else flags |= SDL_HWSURFACE|SDL_DOUBLEBUF; m_Screen = SDL_SetVideoMode(800, 600, 16, flags); if ( m_Screen == NULL ) { fprintf(stderr, "Couldn't set 800x600x16 video mode: %s\n", SDL_GetError()); return false; } else LogFile("OK\n"); // hide mouse cursor in fullscreen if (Fullscreen) SDL_ShowCursor(SDL_DISABLE); // check & output capabilites: const SDL_VideoInfo *info = SDL_GetVideoInfo(); printf("VIDEO INFORMATION:\n"); printf(" hw_available = %d\n", info->hw_available); printf(" wm_available = %d\n", info->wm_available); printf(" blit_hw = %d\n", info->blit_hw); printf(" blit_hw_CC = %d\n", info->blit_hw_CC); printf(" blit_hw_A = %d\n", info->blit_hw_A); printf(" blit_sw = %d\n", info->blit_sw); printf(" blit_sw_CC = %d\n", info->blit_sw_CC); printf(" blit_sw_A = %d\n", info->blit_sw_A); printf("END VIDEO INFORMATION.\n"); // Loading various resources... LogFile("Loading resources:\n"); // load .bmp for main menu SDL_Surface *temp; LogFile("Loading Main Menu image..."); temp = IMG_Load("data/mainmenu.jpg"); if (!temp) { LogFile("FAILED.\n"); LogFile((const char *)SDL_GetError()); return false; } LogFile("OK.\n"); // Convert image to video format m_MainMenuImage = SDL_DisplayFormat(temp); SDL_FreeSurface(temp); if ( m_MainMenuImage == NULL ) { fprintf(stderr, "Couldn't convert main menu image: %s\n", SDL_GetError()); return false; } // load .bmp for options menu LogFile("Loading Options Menu image..."); temp = IMG_Load("data/options.jpg"); if (!temp) { LogFile("FAILED.\n"); LogFile((const char *)SDL_GetError()); return false; } LogFile("OK.\n"); // Convert image to video format m_OptionsMenuImage = SDL_DisplayFormat(temp); SDL_FreeSurface(temp); if ( m_OptionsMenuImage == NULL ) { fprintf(stderr, "Couldn't convert options menu image: %s\n", SDL_GetError()); return false; } // load .bmp for network-send screen LogFile("Loading Net-send image..."); m_NetSendImage = IMG_Load("data/netsend.jpg"); if (!m_NetSendImage) { LogFile("FAILED.\n"); LogFile((const char *)SDL_GetError()); return false; } LogFile("OK.\n"); LogFile("Loading Hi-score image..."); m_HiScoresImage = IMG_Load("data/hiscore.jpg"); if (!m_HiScoresImage) { LogFile("FAILED.\n"); LogFile((const char *)SDL_GetError()); return false; } LogFile("OK.\n"); LogFile("Loading levelset entry image..."); m_LevelsetImage = IMG_Load("data/levelset.jpg"); if (!m_LevelsetImage) { LogFile("FAILED.\n"); LogFile((const char *)SDL_GetError()); return false; } LogFile("OK.\n"); LogFile("Loading Gameover image..."); m_GameOverImage = IMG_Load("data/gameover.jpg"); if (!m_GameOverImage) { LogFile("FAILED.\n"); LogFile((const char *)SDL_GetError()); return false; } LogFile("OK.\n"); // load .bmp for network-send screen LogFile("Loading Net-lobby image..."); m_NetLobbyImage = SDL_LoadBMP("data/network.bmp"); if (!m_NetLobbyImage) { LogFile("FAILED.\n"); LogFile((const char *)SDL_GetError()); return false; } LogFile("OK.\n"); // load .bmp for enter server IP screen LogFile("Loading enter server IP image..."); m_NetEnterImage = IMG_Load("data/enter-ip.jpg"); if (!m_NetEnterImage) { LogFile("FAILED.\n"); LogFile((const char *)SDL_GetError()); return false; } LogFile("OK.\n"); // load .bmp for stats screen LogFile("Loading Stats screen image..."); temp = IMG_Load("data/stats.jpg"); if (!temp) { LogFile("FAILED.\n"); LogFile((const char *)SDL_GetError()); return false; } LogFile("OK.\n"); // Convert image to video format m_StatsImage = SDL_DisplayFormat(temp); SDL_FreeSurface(temp); if ( m_StatsImage == NULL ) { fprintf(stderr, "Couldn't convert stats screen image: %s\n", SDL_GetError()); return false; } // load .bmp for sprites and menu selector LogFile("Loading Sprites image..."); temp = SDL_LoadBMP("data/sprites.bmp"); if (!temp) { LogFile("FAILED.\n"); LogFile((const char *)SDL_GetError()); return false; } // setting color key for sprites: black is transparent Uint32 black = SDL_MapRGB(temp->format, 0, 0, 0); SDL_SetColorKey(temp, SDL_SRCCOLORKEY, black); LogFile("OK.\n"); // Convert image to video format m_SpriteImage = SDL_DisplayFormat(temp); SDL_FreeSurface(temp); if ( m_SpriteImage == NULL ) { fprintf(stderr, "Couldn't convert sprite image: %s\n", SDL_GetError()); return false; } // loading skins, first check how many is there char Filename[18]; m_NumberOfSkins = 0; while (true) { sprintf(Filename, "skins/Back%03d.bmp\0", m_NumberOfSkins); FILE *fp = fopen(Filename, "r"); if (!fp) break; fclose(fp); m_NumberOfSkins++; } LogFile("Loading skins:\n"); if (m_NumberOfSkins > 0) // alloc memory for pointers m_Skins = new SDL_Surface *[m_NumberOfSkins]; for (int i=0; i= 40) break; buff[i] = '\0'; TopTenScores[number].points = atoi(buff+last); i++; last = i; while (buff[i] != '#' && i < 40) i++; if (i >= 40) break; buff[i] = '\0'; TopTenScores[number].level = atoi(buff+last); number++; } fclose(fp); } LogFile("Opening audio..."); if (Mix_OpenAudio(22050, MIX_DEFAULT_FORMAT, 1, 2048) == -1) { m_GameOptions.PlayMusic = false; m_GameOptions.PlaySound = false; LogFile("Failed.\n"); printf("Mix_OpenAudio: %s\n", Mix_GetError()); } else { m_AudioAvailable = true; LogFile("OK.\n"); printf("Reserving 4 channels for sfx...\n"); int reserved = Mix_ReserveChannels(4); if(reserved != 4) { printf("Reserved %d channels from default mixing.\n",reserved); printf("4 channels were not reserved!\n"); } printf("Loading song: data/satisfy.xm...\n"); m_MainMenuMusic = Mix_LoadMUS("data/satisfy.xm");; if(!m_MainMenuMusic) printf("ERROR: Mix_LoadMUS(): %s\n", Mix_GetError()); printf("Loading song: data/ritam.s3m...\n"); m_GameMusic1 = Mix_LoadMUS("data/ritam.s3m");; if(!m_GameMusic1) printf("ERROR: Mix_LoadMUS(): %s\n", Mix_GetError()); printf("Loading song: data/dali.xm...\n"); m_GameMusic2 = Mix_LoadMUS("data/dali.xm");; if(!m_GameMusic2) printf("ERROR: Mix_LoadMUS(): %s\n", Mix_GetError()); printf("Loading samples..."); m_Sounds[0] = Mix_LoadWAV("data/dead.wav"); m_Sounds[1] = Mix_LoadWAV("data/dead2.wav"); m_Sounds[2] = Mix_LoadWAV("data/dead3.wav"); m_Sounds[3] = Mix_LoadWAV("data/kill.wav"); m_Sounds[4] = Mix_LoadWAV("data/kill2.wav"); m_Sounds[5] = Mix_LoadWAV("data/kill3.wav"); m_Sounds[6] = Mix_LoadWAV("data/killply.wav"); m_Sounds[7] = Mix_LoadWAV("data/mapend.wav"); m_Sounds[8] = Mix_LoadWAV("data/mapend2.wav"); m_Sounds[9] = Mix_LoadWAV("data/juice.wav"); m_Sounds[10] = Mix_LoadWAV("data/teleport.wav"); m_Sounds[11] = Mix_LoadWAV("data/invisible.wav"); m_Sounds[12] = Mix_LoadWAV("data/trapdoor.wav"); m_Sounds[13] = Mix_LoadWAV("data/freeze.wav"); m_Sounds[14] = Mix_LoadWAV("data/tripleding.wav"); m_Sounds[15] = Mix_LoadWAV("data/bonus.wav"); m_Sounds[16] = Mix_LoadWAV("data/50pts.wav"); for (int i=0; i<17; i++) if (!m_Sounds[i]) printf("ERROR loading sample nr. %d\n", i); printf("done.\n"); } return true; } //----------------------------------------------------------------------------- bool NjamEngine::MenuItemSelected(int& SelectedMenuItem) { if (SelectedMenuItem == m_NumberOfMenuItems-1) // last menu item = EXIT { m_ActiveMenu = mtMainMenu; // return to main menu... m_NumberOfMenuItems = 8; // ...which has 7 items SelectedMenuItem = 0; return true; } if (m_ActiveMenu == mtMainMenu) // process all items in main menu { if (SelectedMenuItem == 6) // "LevelEditor" selected { LevelEditor(); return true; } if (SelectedMenuItem == 5) // "Options" menu item selected { m_ActiveMenu = mtOptionsMenu; m_NumberOfMenuItems = 4; // Options menu has 4 items SelectedMenuItem = 0; return true; } else // some of the games is selected { // also other menu items can get here... // play the game StartGame((GameType)SelectedMenuItem); if (m_NetworkAvailable) Disconnect(); // safe to call - checks everthing // play music again (if not playing already) if (m_AudioAvailable && m_MainMenuMusic && m_GameOptions.PlayMusic && !Mix_PlayingMusic() && Mix_PlayMusic(m_MainMenuMusic, -1)==-1) printf("ERROR: njam.cpp: MenuItemSelected: Mix_PlayMusic: %s\n", Mix_GetError()); return true; } } if (m_ActiveMenu == mtOptionsMenu) // process all items in Options menu { if (SelectedMenuItem == 0) // music on/off { m_GameOptions.PlayMusic = !m_GameOptions.PlayMusic; if (!m_AudioAvailable) m_GameOptions.PlayMusic = false; if (m_GameOptions.PlayMusic) { if (m_AudioAvailable && m_MainMenuMusic && Mix_PlayMusic(m_MainMenuMusic, -1)==-1) printf("ERROR: njam.cpp: MenuItemSelected: Mix_PlayMusic: %s\n", Mix_GetError()); } else if (m_AudioAvailable && m_MainMenuMusic && Mix_PlayingMusic()) Mix_HaltMusic(); } else if (SelectedMenuItem == 1) // sound on/off { m_GameOptions.PlaySound = !m_GameOptions.PlaySound; if (!m_AudioAvailable) m_GameOptions.PlaySound = false; } else if (SelectedMenuItem == 2) // skins on/off { m_GameOptions.UsedSkin++; if (m_GameOptions.UsedSkin > m_NumberOfSkins) m_GameOptions.UsedSkin = 0; } } return true; } //--------------------------------------------------------------------------- void NjamEngine::ScrollText() { const char scroll_text[] = "NJAM BY MILAN BABUSKOV USE ARROW KEYS TO NAVIGATE MENU HIT ENTER TO SELECT MENU ITEM VISIT NJAM.SOURCEFORGE.NET ONLINE NJAM IS A FREE GAME, BUT IF YOU WISH TO SUPPORT DEVELOPMENT YOU ARE WELCOME TO SEND SOME MONEY. FIVE USD OR EURO IS QUITE ENOUGH. CONTACT ME AT MBABUSKOV@YAHOO.COM FOR MORE INFO. "; m_ScrollOffset-=2; if (m_ScrollOffset < -3600) // end of message m_ScrollOffset = 820; m_FontYellow->WriteTextXY(m_Screen, m_ScrollOffset, 10, scroll_text); } //----------------------------------------------------------------------------- void NjamEngine::Start() { // play main menu .mod if (m_AudioAvailable && m_GameOptions.PlayMusic && Mix_PlayMusic(m_MainMenuMusic, -1) == -1) printf("ERROR: njam.cpp: Mix_PlayMusic: %s\n", Mix_GetError()); int SelectedMenuItem = 0; m_NumberOfMenuItems = 8; // 7 options in main menu (can be different for other menus, but last option must be: Exit or Back) m_ActiveMenu = mtMainMenu; // MainMenu is active (I used enum to make code readable) while (true) // loop main menu { // this screen has animations, so we want it to look the same on all machines Uint32 StartTime = SDL_GetTicks(); if (0 != SDL_BlitSurface(m_MainMenuImage, NULL, m_Screen, NULL)) // draw main image { LogFile("Failed to blit main menu image.\n"); LogFile((const char *)SDL_GetError()); return; } // if options -- draw options if (m_ActiveMenu == mtOptionsMenu) { SDL_Rect src,dest; dest.x = 50; dest.y = 120; if (0 != SDL_BlitSurface(m_OptionsMenuImage, NULL, m_Screen, &dest)) { LogFile("Failed to blit options menu image.\n"); LogFile((const char *)SDL_GetError()); return; } // draw boxes for selected options for (int i=0; i<2; i++) { bool option; switch (i) { case 0: option = m_GameOptions.PlayMusic; break; case 1: option = m_GameOptions.PlaySound; break; } NjamSetRect(dest, 180, 128+35*i, 45, 32); if (!option) { dest.x = 230; dest.w = 80; } SDL_FillRect(m_Screen, &dest, SDL_MapRGB(m_Screen->format, 255, 255, 255)); dest.x += 2; dest.y += 2; NjamSetRect(src, dest.x - 50, dest.y - 120, dest.w - 4, dest.h - 4); SDL_BlitSurface(m_OptionsMenuImage, &src, m_Screen, &dest); } // draw selected skin, or random if (m_GameOptions.UsedSkin == 0) { NjamSetRect(dest, 110, 202, 302, 27); SDL_FillRect(m_Screen, &dest, SDL_MapRGB(m_Screen->format, 200, 200, 20)); NjamSetRect(dest, 111, 203, 300, 25); SDL_FillRect(m_Screen, &dest, SDL_MapRGB(m_Screen->format, 0, 0, 0)); m_FontYellow->WriteTextXY(m_Screen, 200, 208, "R A N D O M"); } else { NjamSetRect(dest, 110, 202, 302, 27); SDL_FillRect(m_Screen, &dest, SDL_MapRGB(m_Screen->format, 0, 0, 0)); NjamSetRect(dest, 111, 203); SDL_BlitSurface(m_Skins[m_GameOptions.UsedSkin - 1], NULL, m_Screen, &dest); } } // draw menu selector - at pos: SelectedMenuItem SDL_Rect rsrc, rdest; NjamSetRect(rsrc, 100, 0, 25, 25); NjamSetRect(rdest, 22, 130 + 35 * SelectedMenuItem); if (0 != SDL_BlitSurface(m_SpriteImage, &rsrc, m_Screen, &rdest)) { LogFile("Failed to blit menu selector image.\n"); LogFile((const char *)SDL_GetError()); return; } DoScript(); // update info window ScrollText(); // update text that scrolls at the top of screen // draw hiscore table m_FontBlue->WriteTextXY(m_Screen, 714, 470, "LEVEL SCORE"); for (int i=0; i<10; i++) { if (i == m_LastHiscore) { SDL_Rect dst; NjamSetRect(dst, 658, 479+i*10, 124, 11); SDL_FillRect(m_Screen, &dst, SDL_MapRGB(m_Screen->format, 0, 0, 100)); } char text[100]; sprintf(text, "%-11s %2d %5d\0", TopTenScores[i].name, TopTenScores[i].level, TopTenScores[i].points); m_FontBlue->WriteTextXY(m_Screen, 660, 480+i*10, text); } // draw a version number m_FontBlue->WriteTextXY(m_Screen, 92, 85, "VERSION 1.25"); // handle a keypress SDL_Event event; while(SDL_PollEvent(&event)) // Loop until there are no events left on the queue { switch(event.type) { case SDL_KEYDOWN: // Handle a KEYDOWN event if (event.key.keysym.sym==SDLK_ESCAPE) { if (mtMainMenu == m_ActiveMenu) // ESC - exit game return; SelectedMenuItem = m_NumberOfMenuItems - 1; if (!MenuItemSelected(SelectedMenuItem)) // as if last menu item is selected (= Exit from submenu) return; } else if (event.key.keysym.sym==SDLK_UP) // up arrow { if (SelectedMenuItem > 0) SelectedMenuItem--; } else if (event.key.keysym.sym==SDLK_DOWN) // down arrow { if (SelectedMenuItem < m_NumberOfMenuItems-1) SelectedMenuItem++; } else if (event.key.keysym.sym==SDLK_RETURN || event.key.keysym.sym==SDLK_KP_ENTER) // ENTER { if (SelectedMenuItem == m_NumberOfMenuItems-1 && m_ActiveMenu == mtMainMenu) // Exit in main = exit game return; if (!MenuItemSelected(SelectedMenuItem)) // show options/run game/whatever, returns false if fatal error return; } break; } } // About 30fps. So that it doesn't fly on fast machines... while (StartTime + 30 > SDL_GetTicks()) SDL_Delay(2); SDL_Flip(m_Screen); } } //---------------------------------------------------------------------------