void Being::updateCoords() { if (!mDispName) return; // Monster names show above the sprite instead of below it if (getType() == MONSTER) mDispName->adviseXY(getPixelX(), getPixelY() - getHeight()); else mDispName->adviseXY(getPixelX(), getPixelY() + mDispName->getHeight()); }
void Being::drawSpeech(int offsetX, int offsetY) { const int px = getPixelX() - offsetX; const int speech = config.getIntValue("speech"); // Draw speech above this being if (mSpeechTime == 0) { if (mSpeechBubble->isVisible()) mSpeechBubble->setVisible(false); } else if (mSpeechTime > 0 && (speech == NAME_IN_BUBBLE || speech == NO_NAME_IN_BUBBLE)) { const bool showName = (speech == NAME_IN_BUBBLE); if (mText) { delete mText; mText = NULL; } mSpeechBubble->setCaption(showName ? mName : "", mTextColor); mSpeechBubble->setText(mSpeech, showName); mSpeechBubble->setPosition(px - (mSpeechBubble->getWidth() / 2), getSpeechTextYPosition() - mSpeechBubble->getHeight() - offsetY); mSpeechBubble->setVisible(true); } else if (mSpeechTime > 0 && speech == TEXT_OVERHEAD) { mSpeechBubble->setVisible(false); if (! mText) { mText = new Text(mSpeech, getPixelX(), getPixelY() - getHeight(), gcn::Graphics::CENTER, &userPalette->getColor(UserPalette::PARTICLE), true); } } else if (speech == NO_SPEECH) { mSpeechBubble->setVisible(false); if (mText) delete mText; mText = NULL; } }
void XSpirit::draw(gcn::Graphics *const graphics, const int offsetX, const int offsetY) const { gcn::SDLGraphics *g = static_cast<gcn::SDLGraphics *>(graphics); const int px = getPixelX() + offsetX; const int py = getPixelY() + offsetY; g->drawImage(gcn::Image::load(mImageFile, true), px, py); gcn::Rectangle rect(getPixelX()+offsetX, getPixelY() + offsetY, mWidth, mHeight); g->drawRectangle(rect); gcn::Font *font = globals::gui->getTop()->getFont(); graphics->drawText(name, px + mWidth/2, py-font->getHeight(), gcn::Graphics::CENTER); }
int Actor::getTileX() const { if (!mMap || !mMap->getTileWidth()) return 0; return getPixelX() / mMap->getTileWidth(); }
void Monster::updateCoords() { if (mDispName) { mDispName->adviseXY(getPixelX(), getPixelY() - getHeight() - mDispName->getHeight()); } }
void Being::setPosition(const Vector &pos) { Actor::setPosition(pos); updateCoords(); if (mText) mText->adviseXY(getPixelX(), getSpeechTextYPosition()); }
int Actor::getTileX() const { if (mMap == nullptr || mMap->getTileWidth() == 0) { return 0; } return getPixelX() / mMap->getTileWidth(); }
void Being::setSpeech(const std::string &text, int time) { // Remove colors mSpeech = removeColors(text); // Trim whitespace trim(mSpeech); // Check for links std::string::size_type start = mSpeech.find('['); std::string::size_type end = mSpeech.find(']', start); while (start != std::string::npos && end != std::string::npos) { // Catch multiple embeds and ignore them so it doesn't crash the client. while ((mSpeech.find('[', start + 1) != std::string::npos) && (mSpeech.find('[', start + 1) < end)) { start = mSpeech.find('[', start + 1); } std::string::size_type position = mSpeech.find('|'); if (mSpeech[start + 1] == '@' && mSpeech[start + 2] == '@') { mSpeech.erase(end, 1); mSpeech.erase(start, (position - start) + 1); } position = mSpeech.find('@'); while (position != std::string::npos) { mSpeech.erase(position, 2); position = mSpeech.find('@'); } start = mSpeech.find('[', start + 1); end = mSpeech.find(']', start); } if (!mSpeech.empty()) mSpeechTime = time <= SPEECH_MAX_TIME ? time : SPEECH_MAX_TIME; const int speech = config.getIntValue("speech"); if (speech == TEXT_OVERHEAD) { if (mText) delete mText; mText = new Text(mSpeech, getPixelX(), getSpeechTextYPosition(), gcn::Graphics::CENTER, &userPalette->getColor(UserPalette::PARTICLE), true); } }
void Being::showName() { delete mDispName; mDispName = 0; std::string mDisplayName(mName); Being* player = static_cast<Being*>(this); if (player) { if (config.getBoolValue("showgender")) { if (getGender() == GENDER_FEMALE) mDisplayName += " \u2640"; else if (getGender() == GENDER_MALE) mDisplayName += " \u2642"; } // Display the IP when under tmw-Athena (GM only). if (Net::getNetworkType() == ServerInfo::TMWATHENA && local_player && local_player->getShowIp() && player->getIp()) { mDisplayName += strprintf(" %s", ipToString(player->getIp())); } } if (getType() == MONSTER) { if (config.getBoolValue("showMonstersTakedDamage")) { mDisplayName += ", " + toString(getDamageTaken()); } } gcn::Font *font = 0; if (local_player && local_player->getTarget() == this && getType() != MONSTER) { font = boldFont; } mDispName = new FlashText(mDisplayName, getPixelX(), getPixelY(), gcn::Graphics::CENTER, mNameColor, font); updateCoords(); }
void XLocalPlayer::draw(gcn::Graphics *const graphics, const int offsetX, const int offsetY) const { gcn::SDLGraphics *g = static_cast<gcn::SDLGraphics *>(graphics); int px = getPixelX() + offsetX - getWidth(); int py = getPixelY() + offsetY - getHeight(); if (px <= 0) px = 0; if (py <= 0) py = 0; g->drawImage(gcn::Image::load("./data/img/aa2186.png", true), px, py); std::stringstream ss; ss << "Player X: " << px << ", Y: " << py; g->drawText(ss.str(), 0, 20); //g->setColor(gcn::Color(255, 0, 0, 255)); //g->fillRectangle(gcn::Rectangle(getPixelX(), getPixelY(), 10, 10)); }
bool Sprite::collide(float x, float y, int cameraoffset_x, int cameraoffset_y, float zoom) { //check collision where xtol/ytol is the up/left tolerance //all coords in game coords std::cout << "Sprite::collide: INFO: Checking collison" << std::endl; float sposx = getPixelX(mPos_x, mPos_y, cameraoffset_x, cameraoffset_y, zoom, mScale); float sposy = getPixelY(mPos_x, mPos_y, cameraoffset_x, cameraoffset_y, zoom, mScale); sposx += mClickOffset_x * zoom; sposy += mClickOffset_y * zoom; float xtol = mClickWidth * zoom; float ytol = mClickHeight * zoom; if ( (x - sposx < xtol) && (y - sposy < ytol) && (x - sposx > 0) && (y - sposy > 0) ) { return true; } return false; }
bool ActorSprite::draw(Graphics *graphics, int offsetX, int offsetY) const { int px = getPixelX() + offsetX; int py = getPixelY() + offsetY; if (mUsedTargetCursor) { mUsedTargetCursor->reset(); mUsedTargetCursor->update(tick_time * MILLISECONDS_IN_A_TICK); mUsedTargetCursor->draw(graphics, px, py); } Map *map = Game::instance() ? Game::instance()->getCurrentMap() : 0; if (map) { py += map->getTileHeight() / 2; } return drawSpriteAt(graphics, px, py); }
void Sprite::render(int cameraoffset_x, int cameraoffset_y, float zoom, int height) { float pixel_x = 0; float pixel_y = 0; pixel_y = getPixelY(getPosX(), getPosY(), cameraoffset_x, cameraoffset_y, zoom, mScale) - height; pixel_x = getPixelX(getPosX(), getPosY(), cameraoffset_x, cameraoffset_y, zoom, mScale); //Render only whats visible: const int offscreen_tolerance = 3*TILE_SIZE*zoom; int screen_width; int screen_height; SDL_GetWindowSize(mWindow, &screen_width, &screen_height); if ((pixel_x >= 0-offscreen_tolerance) or (pixel_x+TILE_SIZE*zoom <= screen_width+offscreen_tolerance) or (pixel_y >= 0-offscreen_tolerance) or (pixel_y+TILE_SIZE*zoom <= screen_height+offscreen_tolerance)) { renderTexture(mTexture, mRenderer, pixel_x, pixel_y, mScale*zoom, mScale*zoom); } }
void Being::fireMissile(Being *victim, const std::string &particle) { if (!victim || particle.empty()) return; Particle *missile = particleEngine->addEffect(particle, getPixelX(), getPixelY()); if (missile) { Particle *target = particleEngine->createChild(); target->moveBy(Vector(0.0f, 0.0f, Game::instance()->getCurrentTileWidth())); target->setLifetime(1000); victim->controlParticle(target); missile->setDestination(target, 7, 0); missile->setDieDistance(8); missile->setLifetime(900); } }
bool ActorSprite::draw(Graphics *graphics, int offsetX, int offsetY) const { // TODO: Eventually, we probably should fix all sprite offsets so that // these translations aren't necessary anymore. The sprites know // best where their base point should be. const int px = getPixelX() + offsetX - 16; // Temporary fix to the Y offset. #ifdef MANASERV_SUPPORT const int py = getPixelY() + offsetY - ((Net::getNetworkType() == ServerInfo::MANASERV) ? 15 : 32); #else const int py = getPixelY() + offsetY - 32; #endif if (mUsedTargetCursor) { mUsedTargetCursor->reset(); mUsedTargetCursor->update(tick_time * MILLISECONDS_IN_A_TICK); mUsedTargetCursor->draw(graphics, px + getTargetOffsetX(), py + getTargetOffsetY()); } return drawSpriteAt(graphics, px, py); }
void Being::handleAttack(Being *victim, int damage, int attackId) { // Monsters, NPCs and remote players handle the first attack (id="1") // per default. // TODO: Fix this for Manaserv by sending the attack id. // TODO: Add attack type handling, see Attack struct and AttackType // and make use of it by grouping attacks per attack type and add random // attack use on tA, based on normal and critical attack types. if (this != local_player) setAction(Being::ATTACK, attackId); if (victim) lookAt(victim->getPosition()); if (getType() == PLAYER && victim && mEquippedWeapon) fireMissile(victim, mEquippedWeapon->getMissileParticleFile()); else fireMissile(victim, mInfo->getAttack(attackId)->mMissileParticleFilename); sound.playSfx(mInfo->getSound((damage > 0) ? SOUND_EVENT_HIT : SOUND_EVENT_MISS), getPixelX(), getPixelY()); }
if (player_node && player_node->getTarget() == this) player_node->setTarget(nullptr); // Notify listeners of the destruction. FOR_EACH (ActorSpriteListenerIterator, iter, mActorSpriteListeners) { if (reportFalse(*iter)) (*iter)->actorSpriteDestroyed(*this); } } bool ActorSprite::draw(Graphics *const graphics, const int offsetX, const int offsetY) const { FUNC_BLOCK("ActorSprite::draw", 1) const int px = getPixelX() + offsetX - mapTileSize / 2; // Temporary fix to the Y offset. #ifdef MANASERV_SUPPORT const int py = getPixelY() + offsetY - ((Net::getNetworkType() == ServerInfo::MANASERV) ? 15 : mapTileSize); #else const int py = getPixelY() + offsetY - mapTileSize; #endif if (mUsedTargetCursor) { mUsedTargetCursor->update(tick_time * MILLISECONDS_IN_A_TICK); mUsedTargetCursor->draw(graphics, px + getTargetOffsetX() - mCursorPaddingX, py + getTargetOffsetY() - mCursorPaddingY); }
void LocalPlayer::logic() { // Actions are allowed once per second if (get_elapsed_time(mLastAction) >= 1000) mLastAction = -1; // Show XP messages if (!mMessages.empty()) { if (mMessageTime == 0) { //const Vector &pos = getPosition(); MessagePair info = mMessages.front(); particleEngine->addTextRiseFadeOutEffect( info.first, /*(int) pos.x, (int) pos.y - 48,*/ getPixelX(), getPixelY() - 48, &guiPalette->getColor(info.second), gui->getInfoParticleFont(), true); mMessages.pop_front(); mMessageTime = 30; } mMessageTime--; } if ((mSpecialRechargeUpdateNeeded%11) == 0) { mSpecialRechargeUpdateNeeded = 0; for (std::map<int, Special>::iterator i = mSpecials.begin(); i != mSpecials.end(); i++) { i->second.currentMana += i->second.recharge; if (i->second.currentMana > i->second.neededMana) { i->second.currentMana = i->second.neededMana; } } } mSpecialRechargeUpdateNeeded++; #ifdef EATHENA_SUPPORT // Targeting allowed 4 times a second if (get_elapsed_time(mLastTarget) >= 250) mLastTarget = -1; // Remove target if its been on a being for more than a minute if (get_elapsed_time(mTargetTime) >= 60000) { mTargetTime = -1; setTarget(NULL); mLastTarget = -1; } #endif if (mTarget) { if (mTarget->getType() == Being::NPC) { // NPCs are always in range mTarget->setTargetAnimation( mTargetCursor[0][mTarget->getTargetCursorSize()]); } else { #ifdef TMWSERV_SUPPORT // Find whether target is in range const int rangeX = abs(mTarget->getPosition().x - getPosition().x); const int rangeY = abs(mTarget->getPosition().y - getPosition().y); #else // Find whether target is in range const int rangeX = abs(mTarget->getTileX() - getTileX()); const int rangeY = abs(mTarget->getTileY() - getTileY()); #endif const int attackRange = getAttackRange(); const int inRange = rangeX > attackRange || rangeY > attackRange ? 1 : 0; mTarget->setTargetAnimation( mTargetCursor[inRange][mTarget->getTargetCursorSize()]); if (mTarget->mAction == DEAD) stopAttack(); if (mKeepAttacking && mTarget) attack(mTarget, true); } } Player::logic(); }
void Being::setAction(Action action, int attackId) { std::string currentAction = SpriteAction::INVALID; switch (action) { case MOVE: currentAction = SpriteAction::MOVE; // Note: When adding a run action, // Differentiate walk and run with action name, // while using only the ACTION_MOVE. break; case SIT: currentAction = SpriteAction::SIT; break; case ATTACK: if (mEquippedWeapon) { currentAction = mEquippedWeapon->getAttackAction(); reset(); } else { currentAction = mInfo->getAttack(attackId)->mAction; reset(); // Attack particle effect if (Particle::enabled) { int effectId = mInfo->getAttack(attackId)->mEffectId; int rotation = 0; switch (mSpriteDirection) { case DIRECTION_DOWN: rotation = 0; break; case DIRECTION_LEFT: rotation = 90; break; case DIRECTION_UP: rotation = 180; break; case DIRECTION_RIGHT: rotation = 270; break; default: break; } effectManager->trigger(effectId, this, rotation); } } break; case HURT: //currentAction = SpriteAction::HURT;// Buggy: makes the player stop // attacking and unable to attack // again until he moves. // TODO: fix this! break; case DEAD: currentAction = SpriteAction::DEAD; sound.playSfx(mInfo->getSound(SOUND_EVENT_DIE), getPixelX(), getPixelY()); break; case STAND: currentAction = SpriteAction::STAND; break; } if (currentAction != SpriteAction::INVALID) { play(currentAction); mAction = action; } if (currentAction != SpriteAction::MOVE) mActionTime = tick_time; }
void Being::takeDamage(Being *attacker, int amount, AttackType type, int attackId) { gcn::Font *font; std::string damage = amount ? toString(amount) : type == FLEE ? "dodge" : "miss"; const gcn::Color *color; font = gui->getInfoParticleFont(); // Selecting the right color if (type == CRITICAL || type == FLEE) { if (attacker == local_player) { color = &userPalette->getColor( UserPalette::HIT_LOCAL_PLAYER_CRITICAL); } else { color = &userPalette->getColor(UserPalette::HIT_CRITICAL); } } else if (!amount) { if (attacker == local_player) { // This is intended to be the wrong direction to visually // differentiate between hits and misses color = &userPalette->getColor(UserPalette::HIT_LOCAL_PLAYER_MISS); } else { color = &userPalette->getColor(UserPalette::MISS); } } else if (getType() == MONSTER) { if (attacker == local_player) { color = &userPalette->getColor( UserPalette::HIT_LOCAL_PLAYER_MONSTER); } else { color = &userPalette->getColor( UserPalette::HIT_PLAYER_MONSTER); } } else { color = &userPalette->getColor(UserPalette::HIT_MONSTER_PLAYER); } // Show damage number particleEngine->addTextSplashEffect(damage, getPixelX(), getPixelY() - getHeight(), color, font, true); if (amount > 0) { if (mInfo) { if (attacker) { sound.playSfx(mInfo->getSound(SOUND_EVENT_HURT), attacker->getPixelX(), attacker->getPixelY()); } else { sound.playSfx(mInfo->getSound(SOUND_EVENT_HURT)); } } if (getType() == MONSTER) { mDamageTaken += amount; updateName(); } // Init the particle effect path based on current weapon or default. int hitEffectId = 0; const ItemInfo *attackerWeapon = attacker ? attacker->getEquippedWeapon() : 0; if (attackerWeapon && attacker->getType() == PLAYER) { if (type != CRITICAL) hitEffectId = attackerWeapon->getHitEffectId(); else hitEffectId = attackerWeapon->getCriticalHitEffectId(); } else if (attacker && attacker->getType() == MONSTER) { const Attack *attack = attacker->getInfo()->getAttack(attackId); if (type != CRITICAL) hitEffectId = attack->mHitEffectId; else hitEffectId = attack->mCriticalHitEffectId; } else { if (type != CRITICAL) hitEffectId = paths.getIntValue("hitEffectId"); else hitEffectId = paths.getIntValue("criticalHitEffectId"); } effectManager->trigger(hitEffectId, this); } }
int main(int argc, char **argv) { //------------------------------------------------------------------------------------- // Variable declarations //------------------------------------------------------------------------------------- bool quit = false; SDL_Event event; Timer fpsTimer; int countedFrames = 0; Timer capTimer; int cameraoffset_x = 0; int cameraoffset_y = 0; const int SCROLL_SPEED = 10; int mouse_x = 0; int mouse_y = 0; int screen_width = SCREEN_WIDTH; int screen_height = SCREEN_HEIGHT; bool scroll_active = true; bool fullscreen = false; bool use_custom_cursor = USE_CUSTOM_CURSOR; bool debug_mode = false; float zoom = 1.0; //------------------------------------------------------------------------------------- //Initialization: //------------------------------------------------------------------------------------- //initialise if (SDL_Init(SDL_INIT_EVERYTHING) != 0) { logSDLError(std::cout, "SDL_Init"); return 1; } if ((IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG) != IMG_INIT_PNG) { logSDLError(std::cout, "IMG_Init"); SDL_Quit(); return 1; } if (TTF_Init() != 0) { logSDLError(std::cout, "TTF_Init"); SDL_Quit(); return 1; } SDL_Window *window = nullptr; window = SDL_CreateWindow("Civ", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN); if (window == nullptr) { logSDLError(std::cout, "CreateWindow"); return 1; } SDL_Renderer *renderer = nullptr; if (VSYNC_ACTIVE) { renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); } else { renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); } if (renderer == nullptr) { logSDLError(std::cout, "CreateRenderer"); return 1; } if (use_custom_cursor) { SDL_ShowCursor(false); } //------------------------------------------------------------------------------------- // Create objects: //------------------------------------------------------------------------------------- SDL_Texture *texture_cursor = loadTexture("res/images/cursor.png", renderer, false); Map map(renderer, window); Sprite *sprite_selection = new Sprite("res/images/iso/selection.png", 2, 2, renderer, window, TILE_SIZE); //make an entity and move it std::cout << "Main: INFO: Starting To Make Objects" << std::endl; Unit * unit_you = new Unit(0., 0., "You"); Unit * unit1 = new Unit(4.5, 4.5, "Unit1"); EntityAction * selected_entity = unit_you; //Movement * move1 = new Movement(10., 8.); //unit_you->appendAction(move1); Movement * move2 = new Movement(0., 0.); unit1->appendAction(move2); //Attack * attack = new Attack(unit1); //unit_you->appendAction(attack); //make a group to hold units EntityGroup * Units = new EntityGroup(renderer, window); Units->addEntity(unit_you); Units->addEntity(unit1); //set the image filename of the group std::cout << "Main: INFO: Setting the Units image file" << std::endl; Units->setImage("res/images/units/villager.png"); //make a text maker TextMaker * TextHandler = new TextMaker("res/fonts/KaushanScript-Regular.otf", renderer, window); //TextMaker * TextHandler = new TextMaker("res/fonts/Pacifico.ttf", renderer, window); //TextMaker * TextHandler = new TextMaker("res/fonts/FFF_Tusj.ttf", renderer, window); //TextMaker * TextHandler = new TextMaker("res/fonts/sample.ttf", renderer, window); //make a temp message //TextLine * message = new TextLine(30. + 122., 125., 500., 50., "HELLO WORLD RTS 3", TextHandler); //message->setActive(true); //make a pop_menu PopMenu * pop_menu = new PopMenu(renderer, window, TextHandler); //pop_menu->loadImage("res/images/menu/menu.png"); //make a menu group MenuGroup * Menus = new MenuGroup(); Menus->addMenu(pop_menu); //make a group to hold resources EntityGroup * Resources = new EntityGroup(renderer, window); placeResources(Resources, 1, MAP_SIZE/2); //make a resource //Resource * res_food = new Resource(0., 0., 1, 100.); //Resources->addEntity(res_food); //res_food->setImage(); //make a food item and give it to the unit Item* food1 = new Item(1., 5.); Item* wood1 = new Item(2., 1.); unit_you->addItem(food1); unit_you->addItem(wood1); unit_you->printInventory(); Item* food2 = new Item(1., 5.); unit1->addItem(food2); //make buildings //make a group to hold buildings EntityGroup * Buildings = new EntityGroup(renderer, window); Building * hut = new Building(3., 3., 0); Buildings->addEntity(hut); //make a menu InfoMenu * info_menu = new InfoMenu(renderer, window, TextHandler); info_menu->setActive(false); Menus->addMenu(info_menu); //TEMP /* Menu * sel_menu = new Menu(0, 0, 500, 600, renderer, window, TextHandler);; SelectionMenu * sl = new SelectionMenu(0, 0, 1, 1, sel_menu, Units ); sel_menu->addSelectionMenu( sl ); Menus->addMenu( sel_menu );*/ //Start timers: fpsTimer.start(); //------------------------------------------------------------------------------------- // Main loop: //------------------------------------------------------------------------------------- while (!quit) { if (!VSYNC_ACTIVE) { capTimer.start(); } //------------------------------------------------------------------------------------- // Update Entity states //------------------------------------------------------------------------------------- Units->update(); Resources->update(); Buildings->update(); //------------------------------------------------------------------------------------- // Entity operations //------------------------------------------------------------------------------------- Units->doActions(); Buildings->doActions(); //------------------------------------------------------------------------------------- // Screen //------------------------------------------------------------------------------------- //Mouse position: SDL_GetMouseState(&mouse_x, &mouse_y); //Resolution: SDL_GetWindowSize(window, &screen_width, &screen_height); if (scroll_active) { if (mouse_x < 20 ) // cameraoffset_x > map.getMinPixelX(zoom)) { cameraoffset_x -= SCROLL_SPEED; } if (mouse_x > screen_width-20 ) // cameraoffset_x < map.getMaxPixelX(zoom)-screen_width+TILE_SIZE*zoom) { cameraoffset_x += SCROLL_SPEED; } if (mouse_y > screen_height-20 ) // cameraoffset_y < map.getMaxPixelY(zoom)-screen_height+TILE_SIZE*zoom) { cameraoffset_y += SCROLL_SPEED; } if (mouse_y < 20 ) // cameraoffset_y > map.getMinPixelY(zoom)) { cameraoffset_y -= SCROLL_SPEED; } } //------------------------------------------------------------------------------------- //Events: //------------------------------------------------------------------------------------- while (SDL_PollEvent(&event)) { if (event.type == SDL_QUIT) { quit = true; } else if (event.type == SDL_KEYDOWN) { if (event.key.keysym.sym == SDLK_ESCAPE) { quit = true; } else if (event.key.keysym.sym == SDLK_RIGHT) { cameraoffset_x += SCROLL_SPEED*2; } else if (event.key.keysym.sym == SDLK_LEFT) { cameraoffset_x -= SCROLL_SPEED*2; } else if (event.key.keysym.sym == SDLK_UP) { cameraoffset_y -= SCROLL_SPEED*2; } else if (event.key.keysym.sym == SDLK_DOWN) { cameraoffset_y += SCROLL_SPEED*2; } else if (event.key.keysym.sym == SDLK_f) { fullscreen = not(fullscreen); if (fullscreen) { SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP); } else { SDL_SetWindowFullscreen(window, 0); } } else if (event.key.keysym.sym == SDLK_g) { map.setDrawGrid(not(map.getDrawGrid())); } else if (event.key.keysym.sym == SDLK_c) { use_custom_cursor = not(use_custom_cursor); SDL_ShowCursor(not(use_custom_cursor)); } else if (event.key.keysym.sym == SDLK_d) { debug_mode = not(debug_mode); } else if (event.key.keysym.sym == SDLK_s) { scroll_active = not(scroll_active); } else if (event.key.keysym.sym == SDLK_t) { /*if ( sel_menu->isActive() == false ) sel_menu->setActive(true); std::cout << "Main: Temporary button: There is nothing here" << std::endl; //temporary testing std::cout << "INFO: main: sel_menu has buttons: " << sel_menu->getSizeButtons() << std::endl; std::cout << "INFO: main: sel_menu has text boxes: " << sel_menu->getSizeTextBoxes() << std::endl; std::cout << "INFO: main: sel_menu has selection menus: " << sel_menu->getSizeSelectionMenus() << std::endl; }*/ } } else if (event.type == SDL_MOUSEBUTTONDOWN) { if (event.button.button == SDL_BUTTON_LEFT) { //check if mouse collides with a button Menu * menu_called = Menus->collide(event.button.x, event.button.y); if ( menu_called != nullptr ) { //true if menu is to be cleared (should probably move this into the child classes of menu // that actually use it, like pop menu) if ( menu_called->outcome() == true) { menu_called->setActive(false); menu_called->clear(); } } //remove menu if not clicked and on else { if (Menus->isActive()) { Menus->setAllNotActive(); } } //takes screen pos and gives tile coords float pos_x = getIsoX(event.button.x, event.button.y, cameraoffset_x, cameraoffset_y, zoom, TILE_SIZE); float pos_y = getIsoY(event.button.x, event.button.y, cameraoffset_x, cameraoffset_y, zoom, TILE_SIZE); if ((pos_x >= 0) and (pos_y >= 0) and (pos_x < map.mWidth) and (pos_y < map.mHeight)) { std::cout << "Click at: X=" << pos_x << " Y=" << pos_y << std::endl; } } else if (event.button.button == SDL_BUTTON_RIGHT) { //pop_menu = Menus->getPopMenu(); if (pop_menu != nullptr) { float pos_x = event.button.x; float pos_y = event.button.y; Entity * target_entity; //check for click on unit target_entity = Units->collide(pos_x, pos_y, cameraoffset_x, cameraoffset_y, zoom); if (target_entity == nullptr) { //check for click on building target_entity = Buildings->collide(pos_x, pos_y, cameraoffset_x, cameraoffset_y, zoom); if (target_entity == nullptr) { //check for click on Resource target_entity = Resources->collide(pos_x, pos_y, cameraoffset_x, cameraoffset_y, zoom); } } if (target_entity != nullptr ) { std::cout << "You clicked in the region" << std::endl; } else { std::cout << "Clicked Nothing" << std::endl; } //make the pop menu for the available actions //only make the pop_menu if no other menu is active if ( !pop_menu->isActive() && !Menus->isActive() ) { pop_menu->setXYPositions(event.button.x, event.button.y, cameraoffset_x, cameraoffset_y, zoom); if (target_entity != nullptr ) { makeActionMenu(pop_menu, selected_entity, target_entity, info_menu); } else { makeActionMenu(pop_menu, selected_entity); } } else { pop_menu->clear(); } } } } else if (event.type == SDL_MOUSEMOTION) { //takes screen pos and gives tile coords int pos_x = getIsoCoordinateX(event.button.x, event.button.y, cameraoffset_x, cameraoffset_y, zoom, TILE_SIZE); int pos_y = getIsoCoordinateY(event.button.x, event.button.y, cameraoffset_x, cameraoffset_y, zoom, TILE_SIZE); sprite_selection->setPosX(pos_x); sprite_selection->setPosY(pos_y); } else if (event.type == SDL_MOUSEWHEEL) { if (event.wheel.y > 0 && scroll_active) { if (zoom < 2.0) { //takes screen pos and gives tile coords //int iso_x = getIsoCoordinateX(screen_width/2, screen_height/2, cameraoffset_x, cameraoffset_y, zoom); //int iso_y = getIsoCoordinateY(screen_width/2, screen_height/2, cameraoffset_x, cameraoffset_y, zoom); int iso_x = getIsoX(screen_width/2, screen_height/2, cameraoffset_x, cameraoffset_y, zoom, TILE_SIZE); int iso_y = getIsoY(screen_width/2, screen_height/2, cameraoffset_x, cameraoffset_y, zoom, TILE_SIZE); //Zooming: zoom += 0.25; //Centering: //takes tile coords and gives pixel coords float pixel_x = getPixelX(iso_x, iso_y, 0,0, zoom, TILE_SIZE); float pixel_y = getPixelY(iso_x, iso_y, 0,0, zoom, TILE_SIZE); cameraoffset_x = (pixel_x + (TILE_SIZE*zoom)*0.5) - screen_width*0.5; cameraoffset_y = (pixel_y + (TILE_SIZE*zoom)*0.75) - screen_height*0.5; } } else if (event.wheel.y < 0 && scroll_active) { if (zoom > 0.26) { //takes screen coords and gives tile coords //int iso_x = getIsoCoordinateX(screen_width/2, screen_height/2, cameraoffset_x, cameraoffset_y, zoom); //int iso_y = getIsoCoordinateY(screen_width/2, screen_height/2, cameraoffset_x, cameraoffset_y, zoom); int iso_x = getIsoX(screen_width/2, screen_height/2, cameraoffset_x, cameraoffset_y, zoom, TILE_SIZE); int iso_y = getIsoY(screen_width/2, screen_height/2, cameraoffset_x, cameraoffset_y, zoom, TILE_SIZE); //Zooming: zoom -= 0.25; //Centering: //takes tile coords and gives pixel coords float pixel_x = getPixelX(iso_x, iso_y, 0,0, zoom, TILE_SIZE); float pixel_y = getPixelY(iso_x, iso_y, 0,0, zoom, TILE_SIZE); cameraoffset_x = (pixel_x + (TILE_SIZE*zoom)*0.5) - screen_width*0.5; cameraoffset_y = (pixel_y + (TILE_SIZE*zoom)*0.75) - screen_height*0.5; } } } } //------------------------------------------------------------------------------------- // Rendering: The Order Here Matters //------------------------------------------------------------------------------------- SDL_RenderClear(renderer); map.render(cameraoffset_x, cameraoffset_y, zoom); sprite_selection->render(cameraoffset_x, cameraoffset_y, zoom); //vill->render(cameraoffset_x, cameraoffset_y, zoom); //std::cout << "INFO: Before rendering EntityGroup" << std::endl; Units->render(cameraoffset_x, cameraoffset_y, zoom); //std::cout << "INFO: After rendering EntityGroup" << std::endl; //render resources Resources->render(cameraoffset_x, cameraoffset_y, zoom); //render resources Buildings->render(cameraoffset_x, cameraoffset_y, zoom); //render menu Menus->render(cameraoffset_x, cameraoffset_y, zoom); //render Temp text //message->render(); if (use_custom_cursor) { renderTexture(texture_cursor, renderer, mouse_x, mouse_y); } SDL_RenderPresent(renderer); //FPS: float avgFPS = countedFrames / (fpsTimer.getTicks() / 1000.f); ++countedFrames; if (!VSYNC_ACTIVE) { int frameTicks = capTimer.getTicks(); if (frameTicks < SCREEN_TICKS_PER_FRAME) { SDL_Delay(SCREEN_TICKS_PER_FRAME - frameTicks); } } //Window title: if (debug_mode) { int pos_x = getIsoCoordinateX(mouse_x, mouse_y, cameraoffset_x, cameraoffset_y, zoom); int pos_y = getIsoCoordinateY(mouse_x, mouse_y, cameraoffset_x, cameraoffset_y, zoom); std::stringstream ss; ss << "IsoMap"; ss << " | mouse: " << mouse_x << " " << mouse_y; ss << " | coordinates: " << pos_x << " " << pos_y; ss << " | cameraoffset: " << cameraoffset_x << " " << cameraoffset_y; ss << " | zoom: " << zoom; ss << " | avgFPS: " << int(avgFPS); ss << " | vsync: " << VSYNC_ACTIVE; const std::string tmp = ss.str(); const char *title = tmp.c_str(); SDL_SetWindowTitle(window, title); } else { SDL_SetWindowTitle(window, "IsoMap"); } } //------------------------------------------------------------------------------------- //Cleanup: //------------------------------------------------------------------------------------- delete sprite_selection; delete TextHandler; delete Units; delete Resources; delete Buildings; delete Menus; SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); IMG_Quit(); SDL_Quit(); return 0; }