warzone2100/src/multilimit.cpp

380 lines
9.6 KiB
C++

/*
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
*/
/*
* multilimit.c
*
* interface for setting limits to the game, bots, structlimits etc...
*/
#include "lib/framework/frame.h"
#include "lib/framework/frameresource.h"
#include "lib/framework/strres.h"
#include "lib/widget/slider.h"
#include "lib/widget/widget.h"
#include "hci.h"
#include "intimage.h"
#include "intdisplay.h"
#include "init.h" // for gameheap
#include "frend.h"
#include "stats.h"
#include "frontend.h"
#include "component.h"
#include "loadsave.h"
#include "wrappers.h" // for loading screen
#include "lib/gamelib/gtime.h"
#include "console.h"
#include "lib/ivis_opengl/bitimage.h" // GFX incs
#include "lib/ivis_opengl/textdraw.h"
// FIXME Direct iVis implementation include!
#include "lib/ivis_opengl/piematrix.h"
#include "lib/ivis_opengl/piestate.h"
#include "lib/netplay/netplay.h"
#include "multiplay.h"
#include "multirecv.h"
#include "multiint.h"
#include "multilimit.h"
#include "lib/ivis_opengl/piemode.h"
#include "lib/script/script.h"
#include "challenge.h"
// ////////////////////////////////////////////////////////////////////////////
// defines
#define IDLIMITS 22000
#define IDLIMITS_RETURN (IDLIMITS+1)
#define IDLIMITS_OK (IDLIMITS+2)
#define IDLIMITS_ENTRIES_START (IDLIMITS+4)
#define IDLIMITS_ENTRIES_END (IDLIMITS+99)
#define LIMITSX 25
#define LIMITSY 30
#define LIMITSW 580
#define LIMITSH 430
#define LIMITS_OKX (LIMITSW-90)
#define LIMITS_OKY (LIMITSH-42)
#define BARWIDTH 480
#define BARHEIGHT 40
// ////////////////////////////////////////////////////////////////////////////
// protos.
static void displayStructureBar(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset);
// ////////////////////////////////////////////////////////////////////////////
static inline void freeLimitSet(void)
{
// Free the old set if required
if (ingame.numStructureLimits)
{
free(ingame.pStructureLimits);
ingame.numStructureLimits = 0;
ingame.pStructureLimits = NULL;
}
}
// ////////////////////////////////////////////////////////////////////////////
bool startLimitScreen(void)
{
addBackdrop();//background
// load stats...
if(!bLimiterLoaded)
{
initLoadingScreen(true);
if (!resLoad("wrf/limiter_data.wrf", 503))
{
return false;
}
bLimiterLoaded = true;
closeLoadingScreen();
}
if (challengeActive)
{
// reset the sliders..
// it's a HACK since the actual limiter structure was cleared in the startMultiOptions function
for (unsigned i = 0; i < numStructureStats; ++i)
{
asStructLimits[0][i].limit = asStructLimits[0][i].globalLimit;
}
// turn off the sliders
sliderEnableDrag(false);
}
else
{
//enable the sliders
sliderEnableDrag(true);
}
addSideText(FRONTEND_SIDETEXT1,LIMITSX-2,LIMITSY,"LIMITS"); // draw sidetext...
WIDGET *parent = widgGetFromID(psWScreen, FRONTEND_BACKDROP);
IntFormAnimated *limitsForm = new IntFormAnimated(parent, false);
limitsForm->id = IDLIMITS;
limitsForm->setGeometry(LIMITSX, LIMITSY, LIMITSW, LIMITSH);
// return button.
addMultiBut(psWScreen,IDLIMITS,IDLIMITS_RETURN,
LIMITS_OKX-40,LIMITS_OKY,
iV_GetImageWidth(FrontImages, IMAGE_NO),
iV_GetImageHeight(FrontImages, IMAGE_NO),
_("Apply Defaults and Return To Previous Screen"),IMAGE_NO,IMAGE_NO,true);
// ok button
addMultiBut(psWScreen,IDLIMITS,IDLIMITS_OK,
LIMITS_OKX,LIMITS_OKY,
iV_GetImageWidth(FrontImages,IMAGE_OK),
iV_GetImageHeight(FrontImages,IMAGE_OK),
_("Accept Settings"),IMAGE_OK,IMAGE_OK,true);
// add tab form..
IntListTabWidget *limitsList = new IntListTabWidget(limitsForm);
limitsList->setChildSize(BARWIDTH, BARHEIGHT);
limitsList->setChildSpacing(5, 5);
limitsList->setGeometry(50, 10, BARWIDTH, 370);
//Put the buttons on it
int limitsButtonId = IDLIMITS_ENTRIES_START;
for (unsigned i = 0; i < numStructureStats; ++i)
{
if (asStructLimits[0][i].globalLimit != LOTS_OF)
{
W_FORM *button = new W_FORM(limitsList);
button->id = limitsButtonId;
button->displayFunction = displayStructureBar;
button->UserData = i;
limitsList->addWidgetToLayout(button);
++limitsButtonId;
addFESlider(limitsButtonId, limitsButtonId - 1, 290, 11,
asStructLimits[0][i].globalLimit,
asStructLimits[0][i].limit);
++limitsButtonId;
}
}
return true;
}
// ////////////////////////////////////////////////////////////////////////////
void runLimitScreen(void)
{
frontendMultiMessages(); // network stuff.
WidgetTriggers const &triggers = widgRunScreen(psWScreen);
unsigned id = triggers.empty()? 0 : triggers.front().widget->id; // Just use first click here, since the next click could be on another menu.
// sliders
if((id > IDLIMITS_ENTRIES_START) && (id< IDLIMITS_ENTRIES_END))
{
unsigned statid = widgGetFromID(psWScreen,id-1)->UserData;
if(statid)
{
asStructLimits[0][statid].limit = (UBYTE) ((W_SLIDER*)(widgGetFromID(psWScreen,id)))->pos;
}
}
else
{
// icons that are always about.
switch(id)
{
case IDLIMITS_RETURN:
// reset the sliders..
for (unsigned i = 0; i < numStructureStats; ++i)
{
asStructLimits[0][i].limit = asStructLimits[0][i].globalLimit;
}
// free limiter structure
freeLimitSet();
//inform others
if (bHosted)
{
sendOptions();
}
eventReset();
changeTitleMode(MULTIOPTION);
// make some noize.
if(!ingame.localOptionsReceived)
{
addConsoleMessage(_("Limits reset to default values"),DEFAULT_JUSTIFY, SYSTEM_MESSAGE);
}
else
{
sendTextMessage("Limits Reset To Default Values",true);
}
break;
case IDLIMITS_OK:
resetReadyStatus(false);
createLimitSet();
changeTitleMode(MULTIOPTION);
break;
default:
break;
}
}
widgDisplayScreen(psWScreen); // show the widgets currently running
}
// ////////////////////////////////////////////////////////////////////////////
void createLimitSet(void)
{
UDWORD i, numchanges = 0, bufSize, idx = 0;
MULTISTRUCTLIMITS *pEntry;
debug(LOG_NET, "LimitSet created");
// free old limiter structure
freeLimitSet();
// don't bother creating if a challenge mode is active
// there are no settings loaded from the .ini file for now...
if (challengeActive)
{
return;
}
// Count the number of changes
for (i = 0; i < numStructureStats; i++)
{
// If the limit differs from the default
if (asStructLimits[0][i].limit != LOTS_OF)
{
numchanges++;
}
}
// Allocate some memory for the changes
bufSize = numchanges * sizeof(MULTISTRUCTLIMITS);
pEntry = (MULTISTRUCTLIMITS *)malloc(bufSize);
memset(pEntry, 255, bufSize);
// Prepare chunk
ASSERT(numStructureStats < UBYTE_MAX, "Too many structure stats");
for (i = 0; i < numStructureStats; i++)
{
if (asStructLimits[0][i].limit != LOTS_OF)
{
ASSERT(idx < numchanges, "Bad number of changed limits");
pEntry[idx].id = i;
pEntry[idx].limit = asStructLimits[0][i].limit;
idx++;
}
}
ingame.numStructureLimits = numchanges;
ingame.pStructureLimits = pEntry;
if (bHosted)
{
sendOptions();
}
}
// ////////////////////////////////////////////////////////////////////////////
void applyLimitSet(void)
{
MULTISTRUCTLIMITS *pEntry = ingame.pStructureLimits;
unsigned int i;
if (ingame.numStructureLimits == 0)
{
return;
}
// Get the limits and decode
for (i = 0; i < ingame.numStructureLimits; ++i)
{
UBYTE id = pEntry[i].id;
// So long as the ID is valid
if (id < numStructureStats)
{
unsigned int j;
for (j = 0; j < MAX_PLAYERS; ++j)
{
asStructLimits[j][id].limit = pEntry[i].limit;
}
}
}
freeLimitSet();
}
// ////////////////////////////////////////////////////////////////////////////
static void displayStructureBar(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset)
{
int x = xOffset + psWidget->x();
int y = yOffset + psWidget->y();
int w = psWidget->width();
int h = psWidget->height();
STRUCTURE_STATS *stat = asStructureStats + psWidget->UserData;
Position position;
Vector3i rotation;
char str[20];
UDWORD scale,Radius;
drawBlueBox(x,y,w,h);
// draw image
pie_SetGeometricOffset(x + 35, y + psWidget->height()/2 + 9);
rotation.x = -15;
rotation.y = ((realTime/45)%360) ; //45
rotation.z = 0;
position.x = 0;
position.y = 0;
position.z = BUTTON_DEPTH*2;//getStructureStatSize(stat) * 38 * OBJECT_RADIUS;
Radius = getStructureStatSizeMax(stat);
if(Radius <= 128) {
scale = SMALL_STRUCT_SCALE;
} else if(Radius <= 256) {
scale = MED_STRUCT_SCALE;
} else {
scale = LARGE_STRUCT_SCALE;
}
pie_SetDepthBufferStatus(DEPTH_CMP_LEQ_WRT_ON);
displayStructureStatButton(stat, &rotation, &position, scale);
pie_SetDepthBufferStatus(DEPTH_CMP_ALWAYS_WRT_ON);
// draw name
iV_SetFont(font_regular); // font
iV_SetTextColour(WZCOL_TEXT_BRIGHT);
iV_DrawText(_(getName(stat)), x + 80, y + psWidget->height()/2 + 3);
// draw limit
ssprintf(str, "%d", ((W_SLIDER *)widgGetFromID(psWScreen, psWidget->id + 1))->pos);
iV_DrawText(str, x + 270, y + psWidget->height()/2 + 3);
return;
}