void CClient::initPlayerInterfaces() { for(auto & elem : gs->scenarioOps->playerInfos) { PlayerColor color = elem.first; if(!vstd::contains(CSH->getAllClientPlayers(CSH->c->connectionID), color)) continue; if(vstd::contains(playerint, color)) continue; logNetwork->trace("Preparing interface for player %s", color.getStr()); if(elem.second.isControlledByAI()) { auto AiToGive = aiNameForPlayer(elem.second, false); logNetwork->info("Player %s will be lead by %s", color, AiToGive); installNewPlayerInterface(CDynLibHandler::getNewAI(AiToGive), color); } else { installNewPlayerInterface(std::make_shared<CPlayerInterface>(color), color); } } if(settings["session"]["spectate"].Bool()) { installNewPlayerInterface(std::make_shared<CPlayerInterface>(PlayerColor::SPECTATOR), PlayerColor::SPECTATOR, true); } if(CSH->getAllClientPlayers(CSH->c->connectionID).count(PlayerColor::NEUTRAL)) installNewBattleInterface(CDynLibHandler::getNewBattleAI(settings["server"]["neutralAI"].String()), PlayerColor::NEUTRAL); logNetwork->trace("Initialized player interfaces %d ms", CSH->th->getDiff()); }
const SDL_Color & CMinimapInstance::getTileColor(const int3 & pos) { static const SDL_Color fogOfWar = {0, 0, 0, 255}; const TerrainTile * tile = LOCPLINT->cb->getTile(pos, false); // if tile is not visible it will be black on minimap if(!tile) return fogOfWar; // if object at tile is owned - it will be colored as its owner for(const CGObjectInstance *obj : tile->blockingObjects) { //heroes will be blitted later if (obj->ID == Obj::HERO) continue; PlayerColor player = obj->getOwner(); if(player == PlayerColor::NEUTRAL) return *graphics->neutralColor; else if (player < PlayerColor::PLAYER_LIMIT) return graphics->playerColors[player.getNum()]; } // else - use terrain color (blocked version or normal) if (tile->blocked && (!tile->visitable)) return parent->colors.find(tile->terType)->second.second; else return parent->colors.find(tile->terType)->second.first; }
PlayerColor CMapGenOptions::getNextPlayerColor() const { for(PlayerColor i = PlayerColor(0); i < PlayerColor::PLAYER_LIMIT; i.advance(1)) { if(!players.count(i)) { return i; } } logGlobal->error("Failed to get next player color"); assert(false); return PlayerColor(0); }
void Graphics::blueToPlayersAdv(SDL_Surface * sur, PlayerColor player) { if(sur->format->palette) { SDL_Color *palette = nullptr; if(player < PlayerColor::PLAYER_LIMIT) { palette = playerColorPalette + 32*player.getNum(); } else if(player == PlayerColor::NEUTRAL) { palette = neutralColorPalette; } else { logGlobal->errorStream() << "Wrong player id in blueToPlayersAdv (" << player << ")!"; return; } SDL_SetColors(sur, palette, 224, 32); } else { //TODO: implement. H3 method works only for images with palettes. // Add some kind of player-colored overlay? // Or keep palette approach here and replace only colors of specific value(s) // Or just wait for OpenGL support? logGlobal->warnStream() << "Image must have palette to be player-colored!"; } }
void CQuery::addPlayer(PlayerColor color) { if(color.isValidPlayer()) { players.push_back(color); } }
TeamID LobbyInfo::getPlayerTeamId(PlayerColor color) { if(color < PlayerColor::PLAYER_LIMIT) return getPlayerInfo(color.getNum()).team; else return TeamID::NO_TEAM; }
void CSDL_Ext::setPlayerColor(SDL_Surface * sur, PlayerColor player) { if(player==PlayerColor::UNFLAGGABLE) return; if(sur->format->BitsPerPixel==8) { SDL_Color *color = (player == PlayerColor::NEUTRAL ? graphics->neutralColor : &graphics->playerColors[player.getNum()]); SDL_SetColors(sur, color, 5, 1); } else logGlobal->warnStream() << "Warning, setPlayerColor called on not 8bpp surface!"; }
void CompImage::playerColored(PlayerColor player) { SDL_Color *pal = nullptr; if(player < PlayerColor::PLAYER_LIMIT) { pal = graphics->playerColorPalette + 32*player.getNum(); } else if(player == PlayerColor::NEUTRAL) { pal = graphics->neutralColorPalette; } else assert(0); for(int i=0; i<32; ++i) { CSDL_Ext::colorAssign(palette[224+i],pal[i]); } }
void CInfoBar::CVisibleInfo::loadEnemyTurn(PlayerColor player) { assert(children.empty()); // visible info should be re-created to change type OBJ_CONSTRUCTION_CAPTURING_ALL; new CPicture("ADSTATNX"); new CAnimImage("CREST58", player.getNum(), 0, 20, 51); new CShowableAnim(99, 51, "HOURSAND"); // FIXME: currently there is no way to get progress from VCAI // if this will change at some point switch this ifdef to enable correct code #if 0 //prepare hourglass for updating AI turn aiProgress = new CAnimImage("HOURGLAS", 0, 0, 99, 51); forceRefresh.push_back(aiProgress); #else //create hourglass that will be always animated ignoring AI status new CShowableAnim(99, 51, "HOURGLAS", CShowableAnim::PLAY_ONCE, 40); #endif }
void CompImage::playerColored(PlayerColor player) { SDL_Color *pal = nullptr; if(player < PlayerColor::PLAYER_LIMIT) { pal = graphics->playerColorPalette + 32*player.getNum(); } else if(player == PlayerColor::NEUTRAL) { pal = graphics->neutralColorPalette; } else assert(0); for(int i=0; i<32; ++i) { palette[224+i].r = pal[i].r; palette[224+i].g = pal[i].g; palette[224+i].b = pal[i].b; palette[224+i].unused = pal[i].unused; } }
void MessageOverlordConnection::sendPlayerColor(PlayerColor playerColor) { string jsonMessage = "{\"playerColor\": \"" + playerColor.toHexString() +"\"}"; messageInterface.sendMessage(jsonMessage); }
// Update map window screen // top_tile top left tile to draw. Not necessarily visible. // extRect, extRect = map window on screen // moveX, moveY: when a hero is in movement indicates how to shift the map. Range is -31 to + 31. void CMapHandler::terrainRect( int3 top_tile, ui8 anim, const std::vector< std::vector< std::vector<ui8> > > * visibilityMap, bool otherHeroAnim, ui8 heroAnim, SDL_Surface * extSurf, const SDL_Rect * extRect, int moveX, int moveY, bool puzzleMode, int3 grailPosRel ) const { // Width and height of the portion of the map to process. Units in tiles. ui32 dx = tilesW; ui32 dy = tilesH; // Basic rectangle for a tile. Should be a const but conflicts with SDL headers SDL_Rect rtile = { 0, 0, 32, 32 }; // Absolute coords of the first pixel in the top left corner int srx_init = offsetX + extRect->x; int sry_init = offsetY + extRect->y; int srx, sry; // absolute screen coordinates in pixels // If moving, we need to add an extra column/line if (moveX != 0) { dx++; srx_init += moveX; if (moveX > 0) { // Moving right. We still need to draw the old tile on the // left, so adjust our referential top_tile.x --; srx_init -= 32; } } if (moveY != 0) { dy++; sry_init += moveY; if (moveY > 0) { // Moving down. We still need to draw the tile on the top, // so adjust our referential. top_tile.y --; sry_init -= 32; } } // Reduce sizes if we go out of the full map. if (top_tile.x < -frameW) top_tile.x = -frameW; if (top_tile.y < -frameH) top_tile.y = -frameH; if (top_tile.x + dx > sizes.x + frameW) dx = sizes.x + frameW - top_tile.x; if (top_tile.y + dy > sizes.y + frameH) dy = sizes.y + frameH - top_tile.y; if(!otherHeroAnim) heroAnim = anim; //the same, as it should be SDL_Rect prevClip; SDL_GetClipRect(extSurf, &prevClip); SDL_SetClipRect(extSurf, extRect); //preventing blitting outside of that rect const BlitterWithRotationVal blitterWithRotation = CSDL_Ext::getBlitterWithRotation(extSurf); const BlitterWithRotationVal blitterWithRotationAndAlpha = CSDL_Ext::getBlitterWithRotationAndAlpha(extSurf); //const BlitterWithRotationAndAlphaVal blitterWithRotation = CSDL_Ext::getBlitterWithRotation(extSurf); // printing terrain srx = srx_init; for (int bx = 0; bx < dx; bx++, srx+=32) { // Skip column if not in map if (top_tile.x+bx < 0 || top_tile.x+bx >= sizes.x) continue; sry = sry_init; for (int by=0; by < dy; by++, sry+=32) { int3 pos(top_tile.x+bx, top_tile.y+by, top_tile.z); //blitted tile position // Skip tile if not in map if (pos.y < 0 || pos.y >= sizes.y) continue; const TerrainTile2 & tile = ttiles[pos.x][pos.y][pos.z]; const TerrainTile &tinfo = map->getTile(int3(pos.x, pos.y, pos.z)); SDL_Rect sr; sr.x=srx; sr.y=sry; sr.h=sr.w=32; //blit terrain with river/road if(tile.terbitmap) { //if custom terrain graphic - use it SDL_Rect temp_rect = genRect(sr.h, sr.w, 0, 0); CSDL_Ext::blitSurface(tile.terbitmap, &temp_rect, extSurf, &sr); } else //use default terrain graphic { blitterWithRotation(terrainGraphics[tinfo.terType][tinfo.terView],rtile, extSurf, sr, tinfo.extTileFlags%4); } if(tinfo.riverType) //print river if present { blitterWithRotationAndAlpha(staticRiverDefs[tinfo.riverType-1]->ourImages[tinfo.riverDir].bitmap,rtile, extSurf, sr, (tinfo.extTileFlags>>2)%4); } //Roads are shifted by 16 pixels to bottom. We have to draw both parts separately if (pos.y > 0 && map->getTile(int3(pos.x, pos.y-1, pos.z)).roadType != ERoadType::NO_ROAD) { //part from top tile const TerrainTile &topTile = map->getTile(int3(pos.x, pos.y-1, pos.z)); Rect source(0, 16, 32, 16); Rect dest(sr.x, sr.y, sr.w, sr.h/2); blitterWithRotationAndAlpha(roadDefs[topTile.roadType - 1]->ourImages[topTile.roadDir].bitmap, source, extSurf, dest, (topTile.extTileFlags>>4)%4); } if(tinfo.roadType != ERoadType::NO_ROAD) //print road from this tile { Rect source(0, 0, 32, 32); Rect dest(sr.x, sr.y+16, sr.w, sr.h/2); blitterWithRotationAndAlpha(roadDefs[tinfo.roadType-1]->ourImages[tinfo.roadDir].bitmap, source, extSurf, dest, (tinfo.extTileFlags>>4)%4); } //blit objects const std::vector < std::pair<const CGObjectInstance*,SDL_Rect> > &objects = tile.objects; for(int h=0; h < objects.size(); ++h) { const CGObjectInstance *obj = objects[h].first; if (!graphics->getDef(obj)) processDef(obj->defInfo); PlayerColor color = obj->tempOwner; //checking if object has non-empty graphic on this tile if(obj->ID != Obj::HERO && !obj->coveringAt(top_tile.x + bx - obj->pos.x, top_tile.y + by - obj->pos.y)) continue; static const int notBlittedInPuzzleMode[] = {124}; //don't print flaggable objects in puzzle mode if(puzzleMode && (obj->isVisitable() || std::find(notBlittedInPuzzleMode, notBlittedInPuzzleMode+1, obj->ID) != notBlittedInPuzzleMode+1)) //? continue; SDL_Rect sr2(sr); SDL_Rect pp = objects[h].second; pp.h = sr.h; pp.w = sr.w; const CGHeroInstance * themp = (obj->ID != Obj::HERO ? NULL : static_cast<const CGHeroInstance*>(obj)); //print hero / boat and flag if((themp && themp->moveDir && themp->type) || (obj->ID == Obj::BOAT)) //it's hero or boat { const int IMGVAL = 8; //frames per group of movement animation ui8 dir; std::vector<Cimage> * iv = NULL; std::vector<CDefEssential *> Graphics::*flg = NULL; SDL_Surface * tb = nullptr; //surface to blitted if(themp) //hero { if(themp->tempOwner >= PlayerColor::PLAYER_LIMIT) //Neutral hero? { logGlobal->errorStream() << "A neutral hero (" << themp->name << ") at " << themp->pos << ". Should not happen!"; continue; } dir = themp->moveDir; //pick graphics of hero (or boat if hero is sailing) if (themp->boat) iv = &graphics->boatAnims[themp->boat->subID]->ourImages; else if (themp->sex) iv = &graphics->heroAnims[themp->type->heroClass->imageMapFemale]->ourImages; else iv = &graphics->heroAnims[themp->type->heroClass->imageMapMale]->ourImages; //pick appropriate flag set if(themp->boat) { switch (themp->boat->subID) { case 0: flg = &Graphics::flags1; break; case 1: flg = &Graphics::flags2; break; case 2: flg = &Graphics::flags3; break; default: logGlobal->errorStream() << "Not supported boat subtype: " << themp->boat->subID; } } else { flg = &Graphics::flags4; } } else //boat { const CGBoat *boat = static_cast<const CGBoat*>(obj); dir = boat->direction; iv = &graphics->boatAnims[boat->subID]->ourImages; } if(themp && !themp->isStanding) //hero is moving { size_t gg; for(gg=0; gg<iv->size(); ++gg) { if((*iv)[gg].groupNumber==getHeroFrameNum(dir, true)) { tb = (*iv)[gg+heroAnim%IMGVAL].bitmap; break; } } CSDL_Ext::blit8bppAlphaTo24bpp(tb,&pp,extSurf,&sr2); //printing flag pp.y+=IMGVAL*2-32; sr2.y-=16; CSDL_Ext::blitSurface((graphics->*flg)[color.getNum()]->ourImages[gg+heroAnim%IMGVAL+35].bitmap, &pp, extSurf, &sr2); } else //hero / boat stands still { size_t gg; for(gg=0; gg < iv->size(); ++gg) { if((*iv)[gg].groupNumber==getHeroFrameNum(dir, false)) { tb = (*iv)[gg].bitmap; break; } } CSDL_Ext::blit8bppAlphaTo24bpp(tb,&pp,extSurf,&sr2); //printing flag if(flg && obj->pos.x == top_tile.x + bx && obj->pos.y == top_tile.y + by) { SDL_Rect bufr = sr2; bufr.x-=2*32; bufr.y-=1*32; bufr.h = 64; bufr.w = 96; if(bufr.x-extRect->x>-64) CSDL_Ext::blitSurface((graphics->*flg)[color.getNum()]->ourImages[getHeroFrameNum(dir, false) *8+(heroAnim/4)%IMGVAL].bitmap, NULL, extSurf, &bufr); } } } else //blit normal object { const std::vector<Cimage> &ourImages = graphics->getDef(obj)->ourImages; SDL_Surface *bitmap = ourImages[(anim+getPhaseShift(obj))%ourImages.size()].bitmap; //setting appropriate flag color if(color < PlayerColor::PLAYER_LIMIT || color==PlayerColor::NEUTRAL) CSDL_Ext::setPlayerColor(bitmap, color); if( obj->hasShadowAt(top_tile.x + bx - obj->pos.x, top_tile.y + by - obj->pos.y) ) CSDL_Ext::blit8bppAlphaTo24bpp(bitmap,&pp,extSurf,&sr2); else CSDL_Ext::blitSurface(bitmap,&pp,extSurf,&sr2); } } //objects blitted //X sign if(puzzleMode) { if(bx == grailPosRel.x && by == grailPosRel.y) { CSDL_Ext::blit8bppAlphaTo24bpp(graphics->heroMoveArrows->ourImages[0].bitmap, NULL, extSurf, &sr); } } }
void CMessage::drawBorder(PlayerColor playerColor, SDL_Surface * ret, int w, int h, int x, int y) { std::vector<SDL_Surface *> &box = piecesOfBox[playerColor.getNum()]; // Note: this code assumes that the corner dimensions are all the same. // Horizontal borders int start_x = x + box[0]->w; const int stop_x = x + w - box[1]->w; const int bottom_y = y+h-box[7]->h+1; while (start_x < stop_x) { int cur_w = stop_x - start_x; if (cur_w > box[6]->w) cur_w = box[6]->w; // Top border Rect srcR(0, 0, cur_w, box[6]->h); Rect dstR(start_x, y, 0, 0); CSDL_Ext::blitSurface(box[6], &srcR, ret, &dstR); // Bottom border dstR.y = bottom_y; CSDL_Ext::blitSurface(box[7], &srcR, ret, &dstR); start_x += cur_w; } // Vertical borders int start_y = y + box[0]->h; const int stop_y = y + h - box[2]->h+1; const int right_x = x+w-box[5]->w; while (start_y < stop_y) { int cur_h = stop_y - start_y; if (cur_h > box[4]->h) cur_h = box[4]->h; // Left border Rect srcR(0, 0, box[4]->w, cur_h); Rect dstR(x, start_y, 0, 0); CSDL_Ext::blitSurface(box[4], &srcR, ret, &dstR); // Right border dstR.x = right_x; CSDL_Ext::blitSurface(box[5], &srcR, ret, &dstR); start_y += cur_h; } //corners Rect dstR(x, y, box[0]->w, box[0]->h); CSDL_Ext::blitSurface(box[0], nullptr, ret, &dstR); dstR=Rect(x+w-box[1]->w, y, box[1]->w, box[1]->h); CSDL_Ext::blitSurface(box[1], nullptr, ret, &dstR); dstR=Rect(x, y+h-box[2]->h+1, box[2]->w, box[2]->h); CSDL_Ext::blitSurface(box[2], nullptr, ret, &dstR); dstR=Rect(x+w-box[3]->w, y+h-box[3]->h+1, box[3]->w, box[3]->h); CSDL_Ext::blitSurface(box[3], nullptr, ret, &dstR); }
void Graphics::blueToPlayersAdv(SDL_Surface * sur, PlayerColor player) { // if(player==1) //it is actually blue... // return; if(sur->format->BitsPerPixel == 8) { SDL_Color *palette = nullptr; if(player < PlayerColor::PLAYER_LIMIT) { palette = playerColorPalette + 32*player.getNum(); } else if(player == PlayerColor::NEUTRAL) { palette = neutralColorPalette; } else { logGlobal->errorStream() << "Wrong player id in blueToPlayersAdv (" << player << ")!"; return; } SDL_SetColors(sur, palette, 224, 32); //for(int i=0; i<32; ++i) //{ // sur->format->palette->colors[224+i] = palette[i]; //} } else if(sur->format->BitsPerPixel == 24) //should never happen in general { for(int y=0; y<sur->h; ++y) { for(int x=0; x<sur->w; ++x) { Uint8* cp = (Uint8*)sur->pixels + y*sur->pitch + x*3; if(SDL_BYTEORDER == SDL_BIG_ENDIAN) { if(cp[2]>cp[1] && cp[2]>cp[0]) { std::vector<long long int> sort1; sort1.push_back(cp[0]); sort1.push_back(cp[1]); sort1.push_back(cp[2]); std::vector< std::pair<long long int, Uint8*> > sort2; sort2.push_back(std::make_pair(graphics->playerColors[player.getNum()].r, &(cp[0]))); sort2.push_back(std::make_pair(graphics->playerColors[player.getNum()].g, &(cp[1]))); sort2.push_back(std::make_pair(graphics->playerColors[player.getNum()].b, &(cp[2]))); std::sort(sort1.begin(), sort1.end()); if(sort2[0].first>sort2[1].first) std::swap(sort2[0], sort2[1]); if(sort2[1].first>sort2[2].first) std::swap(sort2[1], sort2[2]); if(sort2[0].first>sort2[1].first) std::swap(sort2[0], sort2[1]); for(int hh=0; hh<3; ++hh) { (*sort2[hh].second) = (sort1[hh] + sort2[hh].first)/2.2; } } } else { if( (/*(mode==0) && (cp[0]>cp[1]) && (cp[0]>cp[2])) || ((mode==1) &&*/ (cp[2]<45) && (cp[0]>80) && (cp[1]<70) && ((cp[0]-cp[1])>40)) ) { std::vector<long long int> sort1; sort1.push_back(cp[2]); sort1.push_back(cp[1]); sort1.push_back(cp[0]); std::vector< std::pair<long long int, Uint8*> > sort2; sort2.push_back(std::make_pair(graphics->playerColors[player.getNum()].r, &(cp[2]))); sort2.push_back(std::make_pair(graphics->playerColors[player.getNum()].g, &(cp[1]))); sort2.push_back(std::make_pair(graphics->playerColors[player.getNum()].b, &(cp[0]))); std::sort(sort1.begin(), sort1.end()); if(sort2[0].first>sort2[1].first) std::swap(sort2[0], sort2[1]); if(sort2[1].first>sort2[2].first) std::swap(sort2[1], sort2[2]); if(sort2[0].first>sort2[1].first) std::swap(sort2[0], sort2[1]); for(int hh=0; hh<3; ++hh) { (*sort2[hh].second) = (sort1[hh]*0.8 + sort2[hh].first)/2; } } } } } } }