Beispiel #1
0
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());
}
Beispiel #2
0
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;
    }
}
Beispiel #3
0
    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);
    }
Beispiel #4
0
int Actor::getTileX() const
{
    if (!mMap || !mMap->getTileWidth())
        return 0;

    return getPixelX() / mMap->getTileWidth();
}
Beispiel #5
0
void Monster::updateCoords()
{
    if (mDispName)
    {
        mDispName->adviseXY(getPixelX(),
                        getPixelY() - getHeight() - mDispName->getHeight());
    }
}
Beispiel #6
0
void Being::setPosition(const Vector &pos)
{
    Actor::setPosition(pos);

    updateCoords();

    if (mText)
        mText->adviseXY(getPixelX(), getSpeechTextYPosition());
}
Beispiel #7
0
int Actor::getTileX() const
{
    if (mMap == nullptr ||
        mMap->getTileWidth() == 0)
    {
        return 0;
    }

    return getPixelX() / mMap->getTileWidth();
}
Beispiel #8
0
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);
    }
}
Beispiel #9
0
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();
}
Beispiel #10
0
    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));
    }
Beispiel #11
0
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;
}
Beispiel #12
0
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);
}
Beispiel #13
0
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);
    }
}
Beispiel #14
0
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);
    }

}
Beispiel #15
0
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);
}
Beispiel #16
0
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);
    }
Beispiel #18
0
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();
}
Beispiel #19
0
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;
}
Beispiel #20
0
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);
    }
}
Beispiel #21
0
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;
    }