warzone2100/src/multimenu.cpp

1248 lines
36 KiB
C++
Raw Permalink Normal View History

/*
This file is part of Warzone 2100.
Copyright (C) 1999-2004 Eidos Interactive
Copyright (C) 2005-2013 Warzone 2100 Project
Warzone 2100 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.
Warzone 2100 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 Warzone 2100; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* MultiMenu.c
* Handles the In Game MultiPlayer Screen, alliances etc...
* Also the selection of disk files..
*/
#include "lib/framework/frame.h"
2011-12-17 07:06:21 -08:00
#include "lib/framework/wzapp.h"
#include "lib/framework/strres.h"
#include "lib/framework/physfs_ext.h"
#include "lib/widget/button.h"
#include "lib/widget/widget.h"
#include "display3d.h"
#include "intdisplay.h"
// FIXME Direct iVis implementation include!
#include "lib/ivis_opengl/pieblitfunc.h"
#include "lib/ivis_opengl/piedef.h"
#include "lib/ivis_opengl/piepalette.h"
#include "lib/ivis_opengl/bitimage.h"
#include "lib/gamelib/gtime.h"
#include "lib/ivis_opengl/piematrix.h"
#include "levels.h"
#include "objmem.h" //for droid lists.
#include "component.h" // for disaplycomponentobj.
#include "hci.h" // for wFont def.& intmode.
#include "init.h"
#include "power.h"
#include "loadsave.h" // for drawbluebox
#include "console.h"
#include "ai.h"
#include "frend.h"
#include "lib/netplay/netplay.h"
#include "multiplay.h"
#include "multistat.h"
#include "multimenu.h"
#include "multiint.h"
#include "multigifts.h"
#include "multijoin.h"
#include "mission.h"
#include "scores.h"
#include "keymap.h"
#include "keybind.h"
#include "loop.h"
#include "frontend.h"
// ////////////////////////////////////////////////////////////////////////////
// defines
W_SCREEN *psRScreen; // requester stuff.
extern char MultiCustomMapsPath[PATH_MAX];
bool MultiMenuUp = false;
static UDWORD context = 0;
UDWORD current_tech = 1;
UDWORD current_numplayers = 4;
static std::string current_searchString;
#define MULTIMENU_FORM_X 10 + D_W
#define MULTIMENU_FORM_Y 23 + D_H
#define MULTIMENU_FORM_W 620
#define MULTIMENU_PLAYER_H 32
#define MULTIMENU_FONT_OSET 20
#define MULTIMENU_C0 (MULTIMENU_C2+95)
#define MULTIMENU_C1 30
#define MULTIMENU_C2 (MULTIMENU_C1+30)
#define MULTIMENU_C3 (MULTIMENU_C0+36)
#define MULTIMENU_C4 (MULTIMENU_C3+36)
#define MULTIMENU_C5 (MULTIMENU_C4+32)
#define MULTIMENU_C6 (MULTIMENU_C5+32)
#define MULTIMENU_C7 (MULTIMENU_C6+32)
#define MULTIMENU_C8 (MULTIMENU_C7+45)
#define MULTIMENU_C9 (MULTIMENU_C8+95)
#define MULTIMENU_C10 (MULTIMENU_C9+50)
#define MULTIMENU_C11 (MULTIMENU_C10+45)
#define MULTIMENU_CLOSE (MULTIMENU+1)
#define MULTIMENU_PLAYER (MULTIMENU+2)
#define MULTIMENU_ALLIANCE_BASE (MULTIMENU_PLAYER +MAX_PLAYERS)
#define MULTIMENU_GIFT_RAD (MULTIMENU_ALLIANCE_BASE +MAX_PLAYERS)
#define MULTIMENU_GIFT_RES (MULTIMENU_GIFT_RAD +MAX_PLAYERS)
#define MULTIMENU_GIFT_DRO (MULTIMENU_GIFT_RES +MAX_PLAYERS)
#define MULTIMENU_GIFT_POW (MULTIMENU_GIFT_DRO +MAX_PLAYERS)
#define MULTIMENU_CHANNEL (MULTIMENU_GIFT_POW +MAX_PLAYERS)
/// requester stuff.
#define M_REQUEST_CLOSE (MULTIMENU+49)
#define M_REQUEST (MULTIMENU+50)
#define M_REQUEST_C1 (MULTIMENU+61)
#define M_REQUEST_C2 (MULTIMENU+62)
#define M_REQUEST_C3 (MULTIMENU+63)
#define M_REQUEST_AP (MULTIMENU+70)
#define M_REQUEST_2P (MULTIMENU+71)
#define M_REQUEST_3P (MULTIMENU+72)
#define M_REQUEST_4P (MULTIMENU+73)
#define M_REQUEST_5P (MULTIMENU+74)
#define M_REQUEST_6P (MULTIMENU+75)
#define M_REQUEST_7P (MULTIMENU+76)
#define M_REQUEST_8P (MULTIMENU+77)
2011-01-03 05:48:41 -08:00
#define M_REQUEST_9P (MULTIMENU+78)
#define M_REQUEST_10P (MULTIMENU+79)
#define M_REQUEST_11P (MULTIMENU+80)
#define M_REQUEST_12P (MULTIMENU+81)
#define M_REQUEST_13P (MULTIMENU+82)
#define M_REQUEST_14P (MULTIMENU+83)
#define M_REQUEST_15P (MULTIMENU+84)
#define M_REQUEST_16P (MULTIMENU+85)
static const unsigned M_REQUEST_NP[] = {M_REQUEST_2P, M_REQUEST_3P, M_REQUEST_4P, M_REQUEST_5P, M_REQUEST_6P, M_REQUEST_7P, M_REQUEST_8P, M_REQUEST_9P, M_REQUEST_10P, M_REQUEST_11P, M_REQUEST_12P, M_REQUEST_13P, M_REQUEST_14P, M_REQUEST_15P, M_REQUEST_16P};
#define M_REQUEST_BUT (MULTIMENU+100) // allow loads of buttons.
#define M_REQUEST_BUTM (MULTIMENU+1100)
#define M_REQUEST_X MULTIOP_PLAYERSX
#define M_REQUEST_Y MULTIOP_PLAYERSY
#define M_REQUEST_W MULTIOP_PLAYERSW
#define M_REQUEST_H MULTIOP_PLAYERSH
#define R_BUT_W 105//112
#define R_BUT_H 30
#define HOVER_PREVIEW_TIME 300
bool multiRequestUp = false; //multimenu is up.
2011-12-04 02:09:48 -08:00
static unsigned hoverPreviewId;
static bool giftsUp[MAX_PLAYERS] = {true}; //gift buttons for player are up.
// ////////////////////////////////////////////////////////////////////////////
// Map / force / name load save stuff.
/* Sets the player's text color depending on if alliance formed, or if dead.
* \param mode the specified alliance
* \param player the specified player
*/
static void SetPlayerTextColor( int mode, UDWORD player )
{
// override color if they are dead...
if (!apsDroidLists[player] && !apsStructLists[player])
{
iV_SetTextColour(WZCOL_GREY); // dead text color
}
// the colors were chosen to match the FRIEND/FOE radar map colors.
else if (mode == ALLIANCE_FORMED)
{
iV_SetTextColour(WZCOL_YELLOW); // Human alliance text color
}
else if (isHumanPlayer(player)) // Human player, no alliance
{
iV_SetTextColour(WZCOL_TEXT_BRIGHT); // Normal text color
}
else
{
iV_SetTextColour(WZCOL_RED); // Enemy color
}
}
// ////////////////////////////////////////////////////////////////////////////
// enumerates maps in the gamedesc file.
// returns only maps that are valid the right 'type'
static LEVEL_DATASET *enumerateMultiMaps(bool first, unsigned camToUse, unsigned numPlayers)
{
static LEVEL_DATASET *lev;
unsigned int cam;
if(first)
{
lev = psLevels;
}
while(lev)
{
if (game.type == SKIRMISH)
{
if (lev->type == MULTI_SKIRMISH2)
{
cam = 2;
}
else if (lev->type == MULTI_SKIRMISH3)
{
cam = 3;
}
else
{
cam = 1;
}
if((lev->type == SKIRMISH || lev->type == MULTI_SKIRMISH2 || lev->type == MULTI_SKIRMISH3)
&& (numPlayers == 0 || numPlayers == lev->players)
&& cam == camToUse )
{
LEVEL_DATASET *found = lev;
lev = lev->psNext;
return found;
}
}
lev = lev->psNext;
}
return NULL;
}
// ////////////////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////////////////
void displayRequestOption(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset)
{
LEVEL_DATASET *mapData = (LEVEL_DATASET *)psWidget->pUserData;
int x = xOffset + psWidget->x();
int y = yOffset + psWidget->y();
char butString[255];
sstrcpy(butString, ((W_BUTTON *)psWidget)->pTip.toUtf8().constData());
drawBlueBox(x, y, psWidget->width(), psWidget->height());
iV_SetFont(font_regular); // font
if (mapData && CheckForMod(mapData->realFileName))
{
iV_SetTextColour(WZCOL_RED);
}
else
{
iV_SetTextColour(WZCOL_TEXT_BRIGHT);
}
while (iV_GetTextWidth(butString) > psWidget->width() - 10)
{
butString[strlen(butString)-1]='\0';
}
iV_DrawText(butString, x + 6, y + 12); //draw text
if (mapData != NULL)
{
// Display map hash, so we can see the difference between identically named maps.
Sha256 hash = mapData->realFileHash; // levGetFileHash can be slightly expensive.
static uint32_t lastHashTime = 0;
if (lastHashTime != realTime && hash.isZero())
{
hash = levGetFileHash(mapData);
if (!hash.isZero())
{
lastHashTime = realTime; // We just calculated a hash. Don't calculate any more hashes this frame.
}
}
if (!hash.isZero())
{
iV_SetFont(font_small);
iV_SetTextColour(WZCOL_TEXT_DARK);
sstrcpy(butString, hash.toString().c_str());
while (iV_GetTextWidth(butString) > psWidget->width() - 10 - (8 + mapData->players*6))
{
butString[strlen(butString) - 1] = '\0';
}
iV_DrawText(butString, x + 6 + 8 + mapData->players*6, y + 26);
2013-05-05 18:53:43 -07:00
iV_SetFont(font_regular);
}
// if map, then draw no. of players.
for (int count = 0; count < mapData->players; ++count)
{
iV_DrawImage(FrontImages, IMAGE_WEE_GUY, x + 6*count + 6, y + 16);
}
}
}
// ////////////////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////////////////
static void displayCamTypeBut(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset)
{
int x = xOffset + psWidget->x();
int y = yOffset + psWidget->y();
char buffer[8];
2013-05-05 18:53:43 -07:00
iV_SetFont(font_regular);
drawBlueBox(x, y, psWidget->width(), psWidget->height());
sprintf(buffer, "T%i", (int)(psWidget->UserData));
if ((unsigned int)(psWidget->UserData) == current_tech) {
iV_SetTextColour(WZCOL_TEXT_BRIGHT);
} else {
iV_SetTextColour(WZCOL_TEXT_MEDIUM);
}
iV_DrawText(buffer, x+2, y+12);
}
static void displayNumPlayersBut(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset)
{
int x = xOffset + psWidget->x();
int y = yOffset + psWidget->y();
char buffer[8];
2013-05-05 18:53:43 -07:00
iV_SetFont(font_regular);
drawBlueBox(x, y, psWidget->width(), psWidget->height());
if ((unsigned int)(psWidget->UserData) == current_numplayers) {
iV_SetTextColour(WZCOL_TEXT_BRIGHT);
} else {
iV_SetTextColour(WZCOL_TEXT_MEDIUM);
}
if ((unsigned int)(psWidget->UserData) == 0) {
sprintf(buffer, " *");
} else {
sprintf(buffer, "%iP", (int)(psWidget->UserData));
2011-01-03 05:48:41 -08:00
buffer[2] = '\0'; // Truncate 'P' if 2 digits, since there isn't room.
}
iV_DrawText(buffer, x+2, y+12);
}
static int stringRelevance(std::string const &string, std::string const &search)
{
QString str = QString::fromUtf8(string.c_str()).normalized(QString::NormalizationForm_KD);
QString sea = QString::fromUtf8(search.c_str()).normalized(QString::NormalizationForm_KD);
int strDim = str.size() + 1;
int seaDim = sea.size() + 1;
if (strDim > 10000 || seaDim > 10000 || strDim*seaDim > 100000)
{
return 0;
}
std::vector<unsigned> scores(strDim*seaDim);
for (int sum = 0; sum <= str.size() + sea.size(); ++sum)
for (int iStr = std::max(0, sum - sea.size()); iStr <= std::min(str.size(), sum - 0); ++iStr)
{
int iSea = sum - iStr;
unsigned score = 0;
if (iStr > 0 && iSea > 0)
{
score = (scores[iStr - 1 + (iSea - 1)*strDim] + 1) | 1;
QChar a = str[iStr - 1], b = sea[iSea - 1];
if (a == b)
{
score += 100;
}
else if (a.toUpper() == b.toUpper())
{
score += 80;
}
}
if (iStr > 0)
{
score = std::max(score, scores[iStr - 1 + iSea*strDim] & ~1);
}
if (iSea > 0)
{
score = std::max(score, scores[iStr + (iSea - 1)*strDim] & ~1);
}
scores[iStr + iSea*strDim] = score;
}
return scores[str.size() + sea.size()*strDim];
}
static bool reverseSortByFirst(std::pair<int, W_BUTTON *> const &a, std::pair<int, W_BUTTON *> const &b)
{
return a.first > b.first;
}
/** Searches in the given search directory for files ending with the
* given extension. Then will create a window with buttons for each
* found file.
* \param searchDir the directory to search in
* \param fileExtension the extension files should end with, if the
* extension has a dot (.) then this dot _must_ be present as
* the first char in this parameter
* \param mode (purpose unknown)
* \param numPlayers (purpose unknown)
*/
void addMultiRequest(const char* searchDir, const char* fileExtension, UDWORD mode, UBYTE mapCam, UBYTE numPlayers, std::string const &searchString)
{
const unsigned int extensionLength = strlen(fileExtension);
const unsigned int buttonsX = (mode == MULTIOP_MAP) ? 22 : 17;
context = mode;
if(mode == MULTIOP_MAP)
{ // only save these when they select MAP button
current_tech = mapCam;
current_numplayers = numPlayers;
current_searchString = searchString;
}
char **fileList = PHYSFS_enumerateFiles(searchDir);
psRScreen = new W_SCREEN; ///< move this to intinit or somewhere like that.. (close too.)
WIDGET *parent = psRScreen->psForm;
/* add a form to place the tabbed form on */
IntFormAnimated *requestForm = new IntFormAnimated(parent);
requestForm->id = M_REQUEST;
requestForm->setGeometry(M_REQUEST_X + D_W, M_REQUEST_Y + D_H, M_REQUEST_W, M_REQUEST_H);
// Add the button list.
IntListTabWidget *requestList = new IntListTabWidget(requestForm);
requestList->setChildSize(R_BUT_W, R_BUT_H);
requestList->setChildSpacing(4, 4);
requestList->setGeometry(2 + buttonsX, 2, M_REQUEST_W - buttonsX, M_REQUEST_H - 4);
// Add the close button.
W_BUTINIT sButInit;
sButInit.formID = M_REQUEST;
sButInit.id = M_REQUEST_CLOSE;
sButInit.x = M_REQUEST_W - CLOSE_WIDTH - 3;
sButInit.y = 0;
sButInit.width = CLOSE_WIDTH;
sButInit.height = CLOSE_HEIGHT;
sButInit.pTip = _("Close");
sButInit.pDisplay = intDisplayImageHilight;
sButInit.UserData = PACKDWORD_TRI(0,IMAGE_CLOSEHILIGHT , IMAGE_CLOSE);
widgAddButton(psRScreen, &sButInit);
// Put the buttons on it.
int nextButtonId = M_REQUEST_BUT;
for (char **currFile = fileList; *currFile != NULL; ++currFile)
{
const unsigned int fileNameLength = strlen(*currFile);
// Check to see if this file matches the given extension
if (fileNameLength <= extensionLength
|| strcmp(&(*currFile)[fileNameLength - extensionLength], fileExtension) != 0)
continue;
char *withoutExtension = strdup(*currFile);
withoutExtension[fileNameLength - extensionLength] = '\0';
// Set the tip and add the button
W_BUTTON *button = new W_BUTTON(requestList);
button->id = nextButtonId;
button->setTip(withoutExtension);
button->setString(withoutExtension);
button->displayFunction = displayRequestOption;
requestList->addWidgetToLayout(button);
free(withoutExtension);
/* Update the init struct for the next button */
++nextButtonId;
}
// Make sure to return memory back to PhyscisFS
PHYSFS_freeList(fileList);
multiRequestUp = true;
hoverPreviewId = 0;
if(mode == MULTIOP_MAP)
{
LEVEL_DATASET *mapData;
std::vector<std::pair<int, W_BUTTON *> > buttons;
bool first = true;
while ((mapData = enumerateMultiMaps(first, mapCam, numPlayers)) != NULL)
{
first = false;
// add number of players to string.
W_BUTTON *button = new W_BUTTON(requestList);
button->id = nextButtonId;
button->setTip(mapData->pName);
button->setString(mapData->pName);
button->pUserData = mapData;
button->displayFunction = displayRequestOption;
buttons.push_back(std::make_pair(stringRelevance(mapData->pName, searchString), button));
++nextButtonId;
}
std::stable_sort(buttons.begin(), buttons.end(), reverseSortByFirst);
for (std::vector<std::pair<int, W_BUTTON *> >::const_iterator i = buttons.begin(); i != buttons.end(); ++i)
{
requestList->addWidgetToLayout(i->second);
}
// if it's map select then add the cam style buttons.
sButInit = W_BUTINIT();
sButInit.formID = M_REQUEST;
sButInit.id = M_REQUEST_C1;
sButInit.x = 3;
sButInit.y = 254;
sButInit.width = 17;
sButInit.height = 17;
sButInit.UserData = 1;
sButInit.pTip = _("Technology level 1");
sButInit.pDisplay = displayCamTypeBut;
widgAddButton(psRScreen, &sButInit);
sButInit.id = M_REQUEST_C2;
sButInit.y += 22;
sButInit.UserData = 2;
sButInit.pTip = _("Technology level 2");
widgAddButton(psRScreen, &sButInit);
sButInit.id = M_REQUEST_C3;
sButInit.y += 22;
sButInit.UserData = 3;
sButInit.pTip = _("Technology level 3");
widgAddButton(psRScreen, &sButInit);
sButInit.id = M_REQUEST_AP;
sButInit.y = 17;
sButInit.UserData = 0;
sButInit.pTip = _("Any number of players");
sButInit.pDisplay = displayNumPlayersBut;
widgAddButton(psRScreen, &sButInit);
STATIC_ASSERT(MAX_PLAYERS_IN_GUI <= ARRAY_SIZE(M_REQUEST_NP) + 1);
2011-01-03 05:48:41 -08:00
for (unsigned numPlayers = 2; numPlayers <= MAX_PLAYERS_IN_GUI; ++numPlayers)
{
2013-05-02 11:20:47 -07:00
static char ttip[MAX_PLAYERS_IN_GUI + 1][20];
2011-01-03 05:48:41 -08:00
sButInit.id = M_REQUEST_NP[numPlayers - 2];
sButInit.y += 22;
sButInit.UserData = numPlayers;
ssprintf(ttip[numPlayers], ngettext("%d player", "%d players", numPlayers), numPlayers);
2013-05-02 11:20:47 -07:00
sButInit.pTip = ttip[numPlayers];
2011-01-03 05:48:41 -08:00
widgAddButton(psRScreen, &sButInit);
}
}
}
static void closeMultiRequester(void)
{
multiRequestUp = false;
2012-08-24 20:18:50 -07:00
resetReadyStatus(false);
delete psRScreen; // move this to the frontend shutdown...
psRScreen = NULL;
return;
}
bool runMultiRequester(UDWORD id, UDWORD *mode, QString *chosen, LEVEL_DATASET **chosenValue, bool *isHoverPreview)
{
static unsigned hoverId = 0;
static unsigned hoverStartTime = 0;
if( (id == M_REQUEST_CLOSE) || CancelPressed() ) // user hit close box || hit the cancel key
{
closeMultiRequester();
2011-12-04 02:09:48 -08:00
*mode = 0;
return true;
}
2011-12-04 02:09:48 -08:00
bool hoverPreview = false;
if (id == 0 && context == MULTIOP_MAP)
{
id = widgGetMouseOver(psRScreen);
if (id != hoverId)
{
hoverId = id;
hoverStartTime = wzGetTicks() + HOVER_PREVIEW_TIME;
}
if (id == hoverPreviewId || hoverStartTime > wzGetTicks())
2011-12-04 02:09:48 -08:00
{
id = 0; // Don't re-render preview nor render preview before HOVER_PREVIEW_TIME.
2011-12-04 02:09:48 -08:00
}
hoverPreview = true;
}
if (id >= M_REQUEST_BUT && id <= M_REQUEST_BUTM) // chose a file.
{
*chosen = ((W_BUTTON *)widgGetFromID(psRScreen,id))->pText;
*chosenValue = (LEVEL_DATASET *)((W_BUTTON *)widgGetFromID(psRScreen,id))->pUserData;
*mode = context;
2011-12-04 02:09:48 -08:00
*isHoverPreview = hoverPreview;
hoverPreviewId = id;
if (!hoverPreview)
{
closeMultiRequester();
}
return true;
}
2011-12-04 02:09:48 -08:00
if (hoverPreview)
{
id = 0;
}
switch (id)
{
case M_REQUEST_C1:
closeMultiRequester();
addMultiRequest(MultiCustomMapsPath, ".wrf", MULTIOP_MAP, 1, current_numplayers, current_searchString);
break;
case M_REQUEST_C2:
closeMultiRequester();
addMultiRequest(MultiCustomMapsPath, ".wrf", MULTIOP_MAP, 2, current_numplayers, current_searchString);
break;
case M_REQUEST_C3:
closeMultiRequester();
addMultiRequest(MultiCustomMapsPath, ".wrf", MULTIOP_MAP, 3, current_numplayers, current_searchString);
break;
case M_REQUEST_AP:
closeMultiRequester();
addMultiRequest(MultiCustomMapsPath, ".wrf", MULTIOP_MAP, current_tech, 0, current_searchString);
break;
2011-01-03 05:48:41 -08:00
default:
for (unsigned numPlayers = 2; numPlayers <= MAX_PLAYERS_IN_GUI; ++numPlayers)
{
if (id == M_REQUEST_NP[numPlayers - 2])
{
closeMultiRequester();
addMultiRequest(MultiCustomMapsPath, ".wrf", MULTIOP_MAP, current_tech, numPlayers, current_searchString);
2011-01-03 05:48:41 -08:00
break;
}
}
break;
}
return false;
}
// ////////////////////////////////////////////////////////////////////////////
// Multiplayer in game menu stuff
// ////////////////////////////////////////////////////////////////////////////
// Display Functions
static void displayExtraGubbins(UDWORD height)
{
char str[128];
//draw grid
iV_Line(MULTIMENU_FORM_X+MULTIMENU_C0 -6 , MULTIMENU_FORM_Y,
MULTIMENU_FORM_X+MULTIMENU_C0 -6 , MULTIMENU_FORM_Y+height, WZCOL_BLACK);
iV_Line(MULTIMENU_FORM_X+MULTIMENU_C8 -6 , MULTIMENU_FORM_Y,
MULTIMENU_FORM_X+MULTIMENU_C8 -6 , MULTIMENU_FORM_Y+height, WZCOL_BLACK);
iV_Line(MULTIMENU_FORM_X+MULTIMENU_C9 -6 , MULTIMENU_FORM_Y,
MULTIMENU_FORM_X+MULTIMENU_C9 -6 , MULTIMENU_FORM_Y+height, WZCOL_BLACK);
iV_Line(MULTIMENU_FORM_X+MULTIMENU_C10 -6 , MULTIMENU_FORM_Y,
MULTIMENU_FORM_X+MULTIMENU_C10 -6 , MULTIMENU_FORM_Y+height, WZCOL_BLACK);
iV_Line(MULTIMENU_FORM_X+MULTIMENU_C11 -6 , MULTIMENU_FORM_Y,
MULTIMENU_FORM_X+MULTIMENU_C11 -6 , MULTIMENU_FORM_Y+height, WZCOL_BLACK);
iV_Line(MULTIMENU_FORM_X , MULTIMENU_FORM_Y+MULTIMENU_PLAYER_H,
MULTIMENU_FORM_X+MULTIMENU_FORM_W, MULTIMENU_FORM_Y+MULTIMENU_PLAYER_H, WZCOL_BLACK);
iV_SetFont(font_regular); // font
iV_SetTextColour(WZCOL_TEXT_BRIGHT); // main wz text color
// draw timer
getAsciiTime(str, gameTime);
iV_DrawText(str, MULTIMENU_FORM_X+MULTIMENU_C2, MULTIMENU_FORM_Y+MULTIMENU_FONT_OSET) ;
// draw titles.
iV_DrawText(_("Alliances"), MULTIMENU_FORM_X+MULTIMENU_C0, MULTIMENU_FORM_Y+MULTIMENU_FONT_OSET);
iV_DrawText(_("Score"), MULTIMENU_FORM_X+MULTIMENU_C8, MULTIMENU_FORM_Y+MULTIMENU_FONT_OSET);
iV_DrawText(_("Kills"), MULTIMENU_FORM_X+MULTIMENU_C9, MULTIMENU_FORM_Y+MULTIMENU_FONT_OSET);
iV_DrawText(_("Units"), MULTIMENU_FORM_X+MULTIMENU_C10, MULTIMENU_FORM_Y+MULTIMENU_FONT_OSET);
if (getDebugMappingStatus())
{
iV_DrawText(_("Power"), MULTIMENU_FORM_X+MULTIMENU_C11, MULTIMENU_FORM_Y+MULTIMENU_FONT_OSET);
}
else
{
// ping is useless for non MP games, so display something useful depending on mode.
if (runningMultiplayer())
{
iV_DrawText(_("Ping"), MULTIMENU_FORM_X+MULTIMENU_C11, MULTIMENU_FORM_Y+MULTIMENU_FONT_OSET);
}
else
{
iV_DrawText(_("Structs"), MULTIMENU_FORM_X+MULTIMENU_C11, MULTIMENU_FORM_Y+MULTIMENU_FONT_OSET);
}
}
#ifdef DEBUG
iV_SetFont(font_small);
for (unsigned q = 0; q < 2; ++q)
{
unsigned xPos = 0;
unsigned yPos = q*12;
bool isTotal = q != 0;
char const *srText[2] = {_("Sent/Received per sec —"), _("Total Sent/Received —")};
sprintf(str, srText[q]);
iV_DrawText(str, MULTIMENU_FORM_X + xPos, MULTIMENU_FORM_Y + height + yPos);
xPos += iV_GetTextWidth(str) + 20;
sprintf(str, _("Traf: %u/%u"), NETgetStatistic(NetStatisticRawBytes, true, isTotal), NETgetStatistic(NetStatisticRawBytes, false, isTotal));
iV_DrawText(str, MULTIMENU_FORM_X + xPos, MULTIMENU_FORM_Y + height + yPos);
xPos += iV_GetTextWidth(str) + 20;
sprintf(str, _("Uncompressed: %u/%u"), NETgetStatistic(NetStatisticUncompressedBytes, true, isTotal), NETgetStatistic(NetStatisticUncompressedBytes, false, isTotal));
iV_DrawText(str, MULTIMENU_FORM_X + xPos, MULTIMENU_FORM_Y + height + yPos);
xPos += iV_GetTextWidth(str) + 20;
sprintf(str, _("Pack: %u/%u"), NETgetStatistic(NetStatisticPackets, true, isTotal), NETgetStatistic(NetStatisticPackets, false, isTotal));
iV_DrawText(str, MULTIMENU_FORM_X + xPos, MULTIMENU_FORM_Y + height + yPos);
}
#endif
return;
}
static void displayMultiPlayer(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset)
{
char str[128];
int x = xOffset + psWidget->x();
int y = yOffset + psWidget->y();
unsigned player = psWidget->UserData; // Get the in game player number.
if (responsibleFor(player, 0))
{
displayExtraGubbins(widgGetFromID(psWScreen,MULTIMENU_FORM)->height());
}
iV_SetFont(font_regular); // font
iV_SetTextColour(WZCOL_TEXT_BRIGHT);
const bool isHuman = isHumanPlayer(player);
const bool isAlly = aiCheckAlliances(selectedPlayer, player);
const bool isSelectedPlayer = player == selectedPlayer;
SetPlayerTextColor(alliances[selectedPlayer][player], player);
if (isHuman || (game.type == SKIRMISH && player<game.maxPlayers) )
{
ssprintf(str, "%d: %s", NetPlay.players[player].position, getPlayerName(player));
while (iV_GetTextWidth(str) >= MULTIMENU_C0 - MULTIMENU_C2 - 10)
{
str[strlen(str) - 1] = '\0';
}
iV_DrawText(str, x + MULTIMENU_C2, y + MULTIMENU_FONT_OSET);
//c3-7 alliance
//manage buttons by showing or hiding them. gifts only in campaign,
if (alliancesCanGiveAnything(game.alliance))
{
if (isAlly && !isSelectedPlayer && !giftsUp[player] )
{
if (alliancesCanGiveResearchAndRadar(game.alliance))
{
widgReveal(psWScreen, MULTIMENU_GIFT_RAD + player);
widgReveal(psWScreen, MULTIMENU_GIFT_RES + player);
}
widgReveal(psWScreen, MULTIMENU_GIFT_DRO + player);
widgReveal(psWScreen, MULTIMENU_GIFT_POW + player);
giftsUp[player] = true;
}
else if (!isAlly && !isSelectedPlayer && giftsUp[player])
{
if (alliancesCanGiveResearchAndRadar(game.alliance))
{
widgHide(psWScreen, MULTIMENU_GIFT_RAD + player);
widgHide(psWScreen, MULTIMENU_GIFT_RES + player);
}
widgHide(psWScreen, MULTIMENU_GIFT_DRO + player);
widgHide(psWScreen, MULTIMENU_GIFT_POW + player);
giftsUp[player] = false;
}
}
}
// Let's use the real score for MP games
if (NetPlay.bComms)
{
//c8:score,
if (Cheated)
{
sprintf(str, "(cheated)");
}
else
{
sprintf(str, "%d", getMultiStats(player).recentScore);
}
iV_DrawText(str, x + MULTIMENU_C8, y + MULTIMENU_FONT_OSET);
//c9:kills,
sprintf(str, "%d", getMultiStats(player).recentKills);
iV_DrawText(str, x + MULTIMENU_C9, y + MULTIMENU_FONT_OSET);
}
else
{
// estimate of score for skirmish games
sprintf(str, "%d", ingame.skScores[player][0]);
iV_DrawText(str, x + MULTIMENU_C8, y + MULTIMENU_FONT_OSET);
// estimated kills
sprintf(str, "%d", ingame.skScores[player][1]);
iV_DrawText(str, x + MULTIMENU_C9, y + MULTIMENU_FONT_OSET);
}
//only show player's and allies' unit counts, and nobody elses.
//c10:units
if (isAlly || getDebugMappingStatus())
{
sprintf(str, "%d", getNumDroids(player) + getNumTransporterDroids(player));
iV_DrawText(str, x + MULTIMENU_C10, y + MULTIMENU_FONT_OSET);
}
/* Display player power instead of number of played games
* and number of units instead of ping when in debug mode
*/
if (getDebugMappingStatus()) //Won't pass this when in both release and multiplayer modes
{
//c11: Player power
sprintf(str, "%u", (int)getPower(player));
iV_DrawText(str, MULTIMENU_FORM_X + MULTIMENU_C11, y + MULTIMENU_FONT_OSET);
}
else if (runningMultiplayer())
{
//c11:ping
if (!isSelectedPlayer && isHuman)
{
if (ingame.PingTimes[player] < PING_LIMIT)
{
sprintf(str, "%03d", ingame.PingTimes[player]);
}
else
{
sprintf(str, "");
}
iV_DrawText(str, x + MULTIMENU_C11, y + MULTIMENU_FONT_OSET);
}
}
else
{
//c11: Structures
if (isAlly || getDebugMappingStatus())
{
// NOTE, This tallys up *all* the structures you have. Test out via 'start with no base'.
int num = 0;
for (STRUCTURE *temp = apsStructLists[player]; temp != NULL; temp = temp->psNext)
{
++num;
}
sprintf(str, "%d", num);
iV_DrawText(str, x + MULTIMENU_C11, y + MULTIMENU_FONT_OSET);
}
}
// a droid of theirs.
DROID *displayDroid = apsDroidLists[player];
while (displayDroid != NULL && !displayDroid->visible[selectedPlayer])
{
displayDroid = displayDroid->psNext;
}
if (displayDroid)
{
pie_SetGeometricOffset( MULTIMENU_FORM_X+MULTIMENU_C1 ,y+MULTIMENU_PLAYER_H);
Vector3i rotation(-15, 45, 0);
Position position(0, 0, BUTTON_DEPTH); // Scale them.
if (displayDroid->droidType == DROID_SUPERTRANSPORTER)
{
position.z = 7850;
}
else if (displayDroid->droidType == DROID_TRANSPORTER)
{
position.z = 4100;
}
displayComponentButtonObject(displayDroid, &rotation, &position, 100);
}
else if (apsDroidLists[player])
{
// Show that they have droids, but not which droids, since we can't see them.
iV_DrawImageTc(IntImages, IMAGE_GENERIC_TANK, IMAGE_GENERIC_TANK_TC, MULTIMENU_FORM_X + MULTIMENU_C1 - iV_GetImageWidth(IntImages, IMAGE_GENERIC_TANK)/2, y + MULTIMENU_PLAYER_H - iV_GetImageHeight(IntImages, IMAGE_GENERIC_TANK), pal_GetTeamColour(getPlayerColour(player)));
}
// clean up widgets if player leaves while menu is up.
if (!isHuman && !(game.type == SKIRMISH && player < game.maxPlayers))
{
if (widgGetFromID(psWScreen, MULTIMENU_CHANNEL + player) != NULL)
{
widgDelete(psWScreen, MULTIMENU_CHANNEL + player);
}
if (widgGetFromID(psWScreen, MULTIMENU_ALLIANCE_BASE + player) != NULL)
{
widgDelete(psWScreen, MULTIMENU_ALLIANCE_BASE + player);
widgDelete(psWScreen, MULTIMENU_GIFT_RAD + player);
widgDelete(psWScreen, MULTIMENU_GIFT_RES + player);
widgDelete(psWScreen, MULTIMENU_GIFT_DRO + player);
widgDelete(psWScreen, MULTIMENU_GIFT_POW + player);
giftsUp[player] = false;
}
}
}
// ////////////////////////////////////////////////////////////////////////////
// alliance display funcs
static void displayAllianceState(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset)
{
UDWORD a, b, c, player = psWidget->UserData;
switch(alliances[selectedPlayer][player])
{
case ALLIANCE_BROKEN:
a = 0;
b = IMAGE_MULTI_NOAL_HI;
c = IMAGE_MULTI_NOAL; // replace with real gfx
break;
case ALLIANCE_FORMED:
a = 0;
b = IMAGE_MULTI_AL_HI;
c = IMAGE_MULTI_AL; // replace with real gfx
break;
case ALLIANCE_REQUESTED:
case ALLIANCE_INVITATION:
a = 0;
b = IMAGE_MULTI_OFFAL_HI;
c = IMAGE_MULTI_OFFAL; // replace with real gfx
break;
default:
a = 0;
b = IMAGE_MULTI_NOAL_HI;
c = IMAGE_MULTI_NOAL;
break;
}
psWidget->UserData = PACKDWORD_TRI(a,b,c);
intDisplayImageHilight(psWidget, xOffset, yOffset);
psWidget->UserData = player;
}
static void displayChannelState(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset)
{
UDWORD player = psWidget->UserData;
if (openchannels[player])
{
psWidget->UserData = PACKDWORD_TRI(0, IMAGE_MULTI_CHAN, IMAGE_MULTI_CHAN);
}
else
{
psWidget->UserData = PACKDWORD_TRI(0, IMAGE_MULTI_NOCHAN, IMAGE_MULTI_NOCHAN);
}
intDisplayImageHilight(psWidget, xOffset, yOffset);
psWidget->UserData = player;
}
// ////////////////////////////////////////////////////////////////////////////
static void addMultiPlayer(UDWORD player,UDWORD pos)
{
UDWORD y,id;
y = MULTIMENU_PLAYER_H*(pos+1); // this is the top of the pos.
id = MULTIMENU_PLAYER+player;
// add the whole thing.
W_FORMINIT sFormInit;
sFormInit.formID = MULTIMENU_FORM;
sFormInit.id = id;
sFormInit.style = WFORM_PLAIN;
sFormInit.x = 2;
sFormInit.y = (short)y;
sFormInit.width = MULTIMENU_FORM_W -4;
sFormInit.height = MULTIMENU_PLAYER_H;
sFormInit.pDisplay = displayMultiPlayer;
sFormInit.UserData = player;
widgAddForm(psWScreen, &sFormInit);
//name,
//score,
//kills,
//ping
//ALL DONE IN THE DISPLAY FUNC.
W_BUTINIT sButInit;
// add channel opener.
if(player != selectedPlayer)
{
sButInit.formID = id;
sButInit.x = MULTIMENU_C0;
sButInit.y = 5;
sButInit.width = 35;
sButInit.height = 24;
sButInit.id = MULTIMENU_CHANNEL + player;
sButInit.pTip = _("Channel");
sButInit.pDisplay = displayChannelState;
sButInit.UserData = player;
widgAddButton(psWScreen, &sButInit);
}
if (alliancesCanGiveAnything(game.alliance) && player != selectedPlayer)
{
//alliance
sButInit.x = MULTIMENU_C3;
sButInit.y = 5;
sButInit.width = 35;
sButInit.height = 24;
sButInit.id = MULTIMENU_ALLIANCE_BASE + player;
sButInit.pTip = _("Toggle Alliance State");
sButInit.pDisplay = displayAllianceState;
sButInit.UserData = player;
//can't break alliances in 'Locked Teams' mode
if (!alliancesFixed(game.alliance))
{
widgAddButton(psWScreen, &sButInit);
}
sButInit.pDisplay = intDisplayImageHilight;
// add the gift buttons.
sButInit.y += 1; // move down a wee bit.
if (alliancesCanGiveResearchAndRadar(game.alliance))
{
sButInit.id = MULTIMENU_GIFT_RAD+ player;
sButInit.x = MULTIMENU_C4;
sButInit.pTip = _("Give Visibility Report");
sButInit.UserData = PACKDWORD_TRI(0,IMAGE_MULTI_VIS_HI, IMAGE_MULTI_VIS);
widgAddButton(psWScreen, &sButInit);
sButInit.id = MULTIMENU_GIFT_RES + player;
sButInit.x = MULTIMENU_C5;
sButInit.pTip = _("Leak Technology Documents");
sButInit.UserData = PACKDWORD_TRI(0,IMAGE_MULTI_TEK_HI , IMAGE_MULTI_TEK);
widgAddButton(psWScreen, &sButInit);
}
sButInit.id = MULTIMENU_GIFT_DRO + player;
sButInit.x = MULTIMENU_C6;
sButInit.pTip = _("Hand Over Selected Units");
sButInit.UserData = PACKDWORD_TRI(0,IMAGE_MULTI_DRO_HI , IMAGE_MULTI_DRO);
widgAddButton(psWScreen, &sButInit);
sButInit.id = MULTIMENU_GIFT_POW + player;
sButInit.x = MULTIMENU_C7;
sButInit.pTip = _("Give Power To Player");
sButInit.UserData = PACKDWORD_TRI(0,IMAGE_MULTI_POW_HI , IMAGE_MULTI_POW);
widgAddButton(psWScreen, &sButInit);
giftsUp[player] = true; // note buttons are up!
}
}
bool intAddMultiMenu(void)
{
UDWORD i;
//check for already open.
if(widgGetFromID(psWScreen,MULTIMENU_FORM))
{
intCloseMultiMenu();
return true;
}
if (intMode != INT_INTELMAP)
{
intResetScreen(false);
}
WIDGET *parent = psWScreen->psForm;
// add form
IntFormAnimated *multiMenuForm = new IntFormAnimated(parent);
multiMenuForm->id = MULTIMENU_FORM;
multiMenuForm->setGeometry(MULTIMENU_FORM_X, MULTIMENU_FORM_Y, MULTIMENU_FORM_W, MULTIMENU_PLAYER_H*game.maxPlayers + MULTIMENU_PLAYER_H + 7);
// add any players
for(i=0;i<MAX_PLAYERS;i++)
{
if(isHumanPlayer(i) || (game.type == SKIRMISH && i<game.maxPlayers && game.skDiff[i] ) )
{
addMultiPlayer(i,NetPlay.players[i].position);
}
}
// Add the close button.
W_BUTINIT sButInit;
sButInit.formID = MULTIMENU_FORM;
sButInit.id = MULTIMENU_CLOSE;
sButInit.x = MULTIMENU_FORM_W - CLOSE_WIDTH;
sButInit.y = 0;
sButInit.width = CLOSE_WIDTH;
sButInit.height = CLOSE_HEIGHT;
sButInit.pTip = _("Close");
sButInit.pDisplay = intDisplayImageHilight;
sButInit.UserData = PACKDWORD_TRI(0,IMAGE_CLOSEHILIGHT , IMAGE_CLOSE);
if (!widgAddButton(psWScreen, &sButInit))
{
return false;
}
intShowPowerBar(); // add power bar
if (intMode != INT_INTELMAP)
{
intMode = INT_MULTIMENU; // change interface mode.
}
MultiMenuUp = true;
return true;
}
// ////////////////////////////////////////////////////////////////////////////
void intCloseMultiMenuNoAnim(void)
{
widgDelete(psWScreen, MULTIMENU_FORM);
if (!MultiMenuUp)
{
return;
}
MultiMenuUp = false;
if (intMode != INT_INTELMAP)
{
intMode = INT_NORMAL;
}
}
// ////////////////////////////////////////////////////////////////////////////
bool intCloseMultiMenu(void)
{
if (!MultiMenuUp)
{
return true;
}
// Start the window close animation.
IntFormAnimated *form = (IntFormAnimated *)widgGetFromID(psWScreen, MULTIMENU_FORM);
if (form != nullptr)
{
form->closeAnimateDelete();
MultiMenuUp = false;
}
if (intMode != INT_INTELMAP)
{
intMode = INT_NORMAL;
}
return true;
}
// ////////////////////////////////////////////////////////////////////////////
// In Game Options house keeping stuff.
bool intRunMultiMenu(void)
{
return true;
}
// ////////////////////////////////////////////////////////////////////////////
// process clicks made by user.
void intProcessMultiMenu(UDWORD id)
{
UBYTE i;
//close
if (id == MULTIMENU_CLOSE)
{
intCloseMultiMenu();
}
//alliance button
if(id >=MULTIMENU_ALLIANCE_BASE && id<MULTIMENU_ALLIANCE_BASE+MAX_PLAYERS)
{
i =(UBYTE)( id - MULTIMENU_ALLIANCE_BASE);
switch(alliances[selectedPlayer][i])
{
case ALLIANCE_BROKEN:
requestAlliance((UBYTE)selectedPlayer,i,true,true); // request an alliance
break;
case ALLIANCE_INVITATION:
formAlliance((UBYTE)selectedPlayer,i,true,true,true); // form an alliance
break;
case ALLIANCE_REQUESTED:
breakAlliance((UBYTE)selectedPlayer,i,true,true); // break an alliance
break;
case ALLIANCE_FORMED:
breakAlliance((UBYTE)selectedPlayer,i,true,true); // break an alliance
break;
default:
break;
}
}
//channel opens.
if(id >=MULTIMENU_CHANNEL && id<MULTIMENU_CHANNEL+MAX_PLAYERS)
{
i = id - MULTIMENU_CHANNEL;
openchannels[i] = !openchannels[i];
Let the host kick people in non alliance games. (left+right click over ready button of the player you want kicked) close ticket:3100 close ticket:3121 Fix kick routines that got clobbered by the merge a long time ago, and also implement a in-game kick. Currently, you hold down the right mouse button over the channel icon of the person you want to kick, and it will kick them. There is no more room for a new icon. :( git-svn-id: https://warzone2100.svn.sourceforge.net/svnroot/warzone2100/branches/2.3@11490 4a71c877-e1ca-e34f-864e-861f7616d084 (cherry picked from commit da30725d967cf7076456f56122b28ddbc3202488) Conflicts: src/multiint.cpp src/multimenu.cpp src/multiplay.cpp Allow the host to kick the AI only in 'cheat mode' in skirmish games. Closes ticket:2139 git-svn-id: https://warzone2100.svn.sourceforge.net/svnroot/warzone2100/branches/2.3@11596 4a71c877-e1ca-e34f-864e-861f7616d084 (cherry picked from commit 7a083b154dab6b6fa8f421042db0670a671127f5) Conflicts: src/multimenu.cpp When kicking, make sure they are an actual human player before adding them to the list. git-svn-id: https://warzone2100.svn.sourceforge.net/svnroot/warzone2100/branches/2.3@11506 4a71c877-e1ca-e34f-864e-861f7616d084 (cherry picked from commit 43b180768c71853b3de97d71fa091e6a0fdfc10e) Conflicts: lib/netplay/netplay.c general networking improvements by popular request. git-svn-id: https://warzone2100.svn.sourceforge.net/svnroot/warzone2100/branches/2.3@11568 4a71c877-e1ca-e34f-864e-861f7616d084 (cherry picked from commit 052d03d19ec967d4b8cee5d79446fe5ec1f2b040) Conflicts: lib/netplay/netplay.c src/multiint.cpp src/multijoin.cpp src/multiplay.cpp src/multiplay.h src/multisync.c Fix client side messages. refs ticket:2144 git-svn-id: https://warzone2100.svn.sourceforge.net/svnroot/warzone2100/branches/2.3@11601 4a71c877-e1ca-e34f-864e-861f7616d084 (cherry picked from commit 98723c00a9b7d6a46eab204ccd474df4a62fbd93) Conflicts: lib/netplay/netplay.c src/multiint.cpp src/multiplay.cpp
2012-02-19 14:49:49 -08:00
if(mouseDown(MOUSE_RMB) && NetPlay.isHost) // both buttons....
{
char buf[250];
// Allow the host to kick the AI only in a MP game, or if they activated cheats in a skirmish game
if ((NetPlay.bComms || Cheated) && (NetPlay.players[i].allocated || (NetPlay.players[i].allocated == false && NetPlay.players[i].ai != AI_OPEN)))
Let the host kick people in non alliance games. (left+right click over ready button of the player you want kicked) close ticket:3100 close ticket:3121 Fix kick routines that got clobbered by the merge a long time ago, and also implement a in-game kick. Currently, you hold down the right mouse button over the channel icon of the person you want to kick, and it will kick them. There is no more room for a new icon. :( git-svn-id: https://warzone2100.svn.sourceforge.net/svnroot/warzone2100/branches/2.3@11490 4a71c877-e1ca-e34f-864e-861f7616d084 (cherry picked from commit da30725d967cf7076456f56122b28ddbc3202488) Conflicts: src/multiint.cpp src/multimenu.cpp src/multiplay.cpp Allow the host to kick the AI only in 'cheat mode' in skirmish games. Closes ticket:2139 git-svn-id: https://warzone2100.svn.sourceforge.net/svnroot/warzone2100/branches/2.3@11596 4a71c877-e1ca-e34f-864e-861f7616d084 (cherry picked from commit 7a083b154dab6b6fa8f421042db0670a671127f5) Conflicts: src/multimenu.cpp When kicking, make sure they are an actual human player before adding them to the list. git-svn-id: https://warzone2100.svn.sourceforge.net/svnroot/warzone2100/branches/2.3@11506 4a71c877-e1ca-e34f-864e-861f7616d084 (cherry picked from commit 43b180768c71853b3de97d71fa091e6a0fdfc10e) Conflicts: lib/netplay/netplay.c general networking improvements by popular request. git-svn-id: https://warzone2100.svn.sourceforge.net/svnroot/warzone2100/branches/2.3@11568 4a71c877-e1ca-e34f-864e-861f7616d084 (cherry picked from commit 052d03d19ec967d4b8cee5d79446fe5ec1f2b040) Conflicts: lib/netplay/netplay.c src/multiint.cpp src/multijoin.cpp src/multiplay.cpp src/multiplay.h src/multisync.c Fix client side messages. refs ticket:2144 git-svn-id: https://warzone2100.svn.sourceforge.net/svnroot/warzone2100/branches/2.3@11601 4a71c877-e1ca-e34f-864e-861f7616d084 (cherry picked from commit 98723c00a9b7d6a46eab204ccd474df4a62fbd93) Conflicts: lib/netplay/netplay.c src/multiint.cpp src/multiplay.cpp
2012-02-19 14:49:49 -08:00
{
inputLoseFocus();
Let the host kick people in non alliance games. (left+right click over ready button of the player you want kicked) close ticket:3100 close ticket:3121 Fix kick routines that got clobbered by the merge a long time ago, and also implement a in-game kick. Currently, you hold down the right mouse button over the channel icon of the person you want to kick, and it will kick them. There is no more room for a new icon. :( git-svn-id: https://warzone2100.svn.sourceforge.net/svnroot/warzone2100/branches/2.3@11490 4a71c877-e1ca-e34f-864e-861f7616d084 (cherry picked from commit da30725d967cf7076456f56122b28ddbc3202488) Conflicts: src/multiint.cpp src/multimenu.cpp src/multiplay.cpp Allow the host to kick the AI only in 'cheat mode' in skirmish games. Closes ticket:2139 git-svn-id: https://warzone2100.svn.sourceforge.net/svnroot/warzone2100/branches/2.3@11596 4a71c877-e1ca-e34f-864e-861f7616d084 (cherry picked from commit 7a083b154dab6b6fa8f421042db0670a671127f5) Conflicts: src/multimenu.cpp When kicking, make sure they are an actual human player before adding them to the list. git-svn-id: https://warzone2100.svn.sourceforge.net/svnroot/warzone2100/branches/2.3@11506 4a71c877-e1ca-e34f-864e-861f7616d084 (cherry picked from commit 43b180768c71853b3de97d71fa091e6a0fdfc10e) Conflicts: lib/netplay/netplay.c general networking improvements by popular request. git-svn-id: https://warzone2100.svn.sourceforge.net/svnroot/warzone2100/branches/2.3@11568 4a71c877-e1ca-e34f-864e-861f7616d084 (cherry picked from commit 052d03d19ec967d4b8cee5d79446fe5ec1f2b040) Conflicts: lib/netplay/netplay.c src/multiint.cpp src/multijoin.cpp src/multiplay.cpp src/multiplay.h src/multisync.c Fix client side messages. refs ticket:2144 git-svn-id: https://warzone2100.svn.sourceforge.net/svnroot/warzone2100/branches/2.3@11601 4a71c877-e1ca-e34f-864e-861f7616d084 (cherry picked from commit 98723c00a9b7d6a46eab204ccd474df4a62fbd93) Conflicts: lib/netplay/netplay.c src/multiint.cpp src/multiplay.cpp
2012-02-19 14:49:49 -08:00
ssprintf(buf, _("The host has kicked %s from the game!"), getPlayerName((unsigned int) i));
sendTextMessage(buf, true);
ssprintf(buf, _("kicked %s : %s from the game, and added them to the banned list!"), getPlayerName((unsigned int) i), NetPlay.players[i].IPtextAddress);
NETlogEntry(buf, SYNC_FLAG, (unsigned int) i);
kickPlayer((unsigned int) i, "you are unwanted by the host.", ERROR_KICKED);
return;
}
}
}
//radar gifts
if(id >= MULTIMENU_GIFT_RAD && id< MULTIMENU_GIFT_RAD +MAX_PLAYERS)
{
sendGift(RADAR_GIFT, id - MULTIMENU_GIFT_RAD);
}
// research gift
if(id >= MULTIMENU_GIFT_RES && id<MULTIMENU_GIFT_RES +MAX_PLAYERS)
{
sendGift(RESEARCH_GIFT, id - MULTIMENU_GIFT_RES);
}
//droid gift
if(id >= MULTIMENU_GIFT_DRO && id< MULTIMENU_GIFT_DRO +MAX_PLAYERS)
{
sendGift(DROID_GIFT, id - MULTIMENU_GIFT_DRO);
}
//power gift
if(id >= MULTIMENU_GIFT_POW && id< MULTIMENU_GIFT_POW +MAX_PLAYERS)
{
sendGift(POWER_GIFT, id - MULTIMENU_GIFT_POW);
}
}