From 40175c65c9f2c796a8c6add3c1c6fae1d46b54dd Mon Sep 17 00:00:00 2001 From: Meep-Eep Date: Sat, 23 Jan 2010 00:34:27 +0000 Subject: [PATCH] Cleanups and some refactoring of the SuperMelee code. git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@3502 8092fc87-c524-0410-9efc-e669fe64eaf9 --- sc2/ChangeLog | 1 + sc2/build/msvc6/UrQuanMasters.dsp | 16 + sc2/src/uqm/battle.c | 5 +- sc2/src/uqm/gameopt.c | 2 + sc2/src/uqm/netplay/Makeinfo | 2 +- sc2/src/uqm/netplay/netmelee.c | 138 +-- sc2/src/uqm/netplay/netmelee.h | 8 +- sc2/src/uqm/netplay/netmisc.c | 12 +- sc2/src/uqm/netplay/notify.c | 25 +- sc2/src/uqm/netplay/notify.h | 27 +- sc2/src/uqm/netplay/notifyall.c | 146 ++++ sc2/src/uqm/netplay/notifyall.h | 41 + sc2/src/uqm/netplay/packet.h | 2 +- sc2/src/uqm/netplay/packethandlers.c | 37 +- sc2/src/uqm/netplay/packetsenders.c | 24 +- sc2/src/uqm/netplay/packetsenders.h | 19 +- sc2/src/uqm/supermelee/Makeinfo | 2 +- sc2/src/uqm/supermelee/buildpick.c | 226 +++++ sc2/src/uqm/supermelee/buildpick.h | 17 + sc2/src/uqm/supermelee/loadmele.c | 533 ++++++------ sc2/src/uqm/supermelee/loadmele.h | 9 +- sc2/src/uqm/supermelee/melee.c | 1200 +++++++++++--------------- sc2/src/uqm/supermelee/melee.h | 94 +- sc2/src/uqm/supermelee/meleesetup.c | 325 +++++++ sc2/src/uqm/supermelee/meleesetup.h | 144 ++++ sc2/src/uqm/supermelee/meleeship.h | 44 + sc2/src/uqm/supermelee/pickmele.c | 225 ++++- sc2/src/uqm/supermelee/pickmele.h | 4 + sc2/src/uqm/tactrans.c | 2 +- 29 files changed, 2091 insertions(+), 1239 deletions(-) create mode 100644 sc2/src/uqm/netplay/notifyall.c create mode 100644 sc2/src/uqm/netplay/notifyall.h create mode 100644 sc2/src/uqm/supermelee/buildpick.c create mode 100644 sc2/src/uqm/supermelee/buildpick.h create mode 100644 sc2/src/uqm/supermelee/meleesetup.c create mode 100644 sc2/src/uqm/supermelee/meleesetup.h create mode 100644 sc2/src/uqm/supermelee/meleeship.h diff --git a/sc2/ChangeLog b/sc2/ChangeLog index b5dbd06dd..d5311dc28 100644 --- a/sc2/ChangeLog +++ b/sc2/ChangeLog @@ -1,4 +1,5 @@ Changes towards version 0.7: +- Clean up and some refactoring of the SuperMelee code - SvdB - Fixed concurrent screen fades regression (bug #1079) - Alex - Removed some legacy source code files related to resources - SvdB - Put SuperMelee source files in separate subdirectory - SvdB diff --git a/sc2/build/msvc6/UrQuanMasters.dsp b/sc2/build/msvc6/UrQuanMasters.dsp index 01da83ea1..46fee1fbe 100644 --- a/sc2/build/msvc6/UrQuanMasters.dsp +++ b/sc2/build/msvc6/UrQuanMasters.dsp @@ -2973,6 +2973,14 @@ SOURCE=..\..\src\uqm\ships\ship.h # PROP Default_Filter "" # Begin Source File +SOURCE=..\..\src\uqm\supermelee\buildpick.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\uqm\supermelee\buildpick.h +# End Source File +# Begin Source File + SOURCE=..\..\src\uqm\supermelee\loadmele.c # End Source File # Begin Source File @@ -2989,6 +2997,14 @@ SOURCE=..\..\src\uqm\supermelee\melee.h # End Source File # Begin Source File +SOURCE=..\..\src\uqm\supermelee\meleesetup.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\uqm\supermelee\meleesetup.h +# End Source File +# Begin Source File + SOURCE=..\..\src\uqm\supermelee\pickmele.c # End Source File # Begin Source File diff --git a/sc2/src/uqm/battle.c b/sc2/src/uqm/battle.c index a4286a709..d7ce10685 100644 --- a/sc2/src/uqm/battle.c +++ b/sc2/src/uqm/battle.c @@ -32,6 +32,7 @@ # ifdef NETPLAY_CHECKSUM # include "netplay/checksum.h" # endif +# include "netplay/notifyall.h" #endif #include "supermelee/pickmele.h" #include "resinst.h" @@ -187,7 +188,7 @@ ProcessInput (void) if (!(PlayerControl[cur_player] & NETWORK_CONTROL)) { BattleInputBuffer *bib = getBattleInputBuffer(cur_player); - sendBattleInputConnections (InputState); + Netplay_NotifyAll_battleInput (InputState); flushPacketQueues (); BattleInputBuffer_push (bib, InputState); @@ -279,7 +280,7 @@ DoBattle (BATTLE_STATE *bs) crc_processState (&state); checksum = (Checksum) crc_finish (&state); - sendChecksumConnections ((uint32) battleFrameCount, + Netplay_NotifyAll_checksum ((uint32) battleFrameCount, (uint32) checksum); flushPacketQueues (); addLocalChecksum (battleFrameCount, checksum); diff --git a/sc2/src/uqm/gameopt.c b/sc2/src/uqm/gameopt.c index 096c7f87d..5a02e2c58 100644 --- a/sc2/src/uqm/gameopt.c +++ b/sc2/src/uqm/gameopt.c @@ -66,8 +66,10 @@ ConfirmSaveLoad (STAMP *MsgStamp) t.CharCount = (COUNT)~0; if (MsgStamp) t.pStr = GAME_STRING (SAVEGAME_STRING_BASE + 0); + // "Saving . . ." else t.pStr = GAME_STRING (SAVEGAME_STRING_BASE + 1); + // "Loading . . ." TextRect (&t, &r, NULL); r.corner.x -= 4; r.corner.y -= 4; diff --git a/sc2/src/uqm/netplay/Makeinfo b/sc2/src/uqm/netplay/Makeinfo index bab1b01e9..48a2f6d0f 100644 --- a/sc2/src/uqm/netplay/Makeinfo +++ b/sc2/src/uqm/netplay/Makeinfo @@ -1,3 +1,3 @@ uqm_SUBDIRS="proto" -uqm_CFILES="checkbuf.c checksum.c crc.c netconnection.c netinput.c netmelee.c netmisc.c netoptions.c netrcv.c netsend.c netstate.c notify.c packet.c packethandlers.c packetsenders.c packetq.c" +uqm_CFILES="checkbuf.c checksum.c crc.c netconnection.c netinput.c netmelee.c netmisc.c netoptions.c netrcv.c netsend.c netstate.c notify.c notifyall.c packet.c packethandlers.c packetsenders.c packetq.c" diff --git a/sc2/src/uqm/netplay/netmelee.c b/sc2/src/uqm/netplay/netmelee.c index 79e043ef7..78421c378 100644 --- a/sc2/src/uqm/netplay/netmelee.c +++ b/sc2/src/uqm/netplay/netmelee.c @@ -61,6 +61,33 @@ removeNetConnection(int playerNr) { numNetConnections--; } +size_t +getNumNetConnections(void) { + return numNetConnections; +} + +// If the callback function returns 'false', the function will immediately +// return with 'false'. Otherwise it will return 'true' after calling +// the callback function for each connected player. +bool +forEachConnectedPlayer(ForEachConnectionCallback callback, void *arg) { + COUNT player; + + for (player = 0; player < NUM_PLAYERS; player++) + { + NetConnection *conn = netConnections[player]; + if (conn == NULL) + continue; + + if (!NetConnection_isConnected(conn)) + continue; + + if (!(*callback)(conn, arg)) + return false; + } + return true; +} + void closeAllConnections(void) { COUNT player; @@ -87,12 +114,6 @@ closeDisconnectedConnections(void) { } } -size_t -getNumNetConnections(void) { - return numNetConnections; -} - - //////////////////////////////////////////////////////////////////////////// @@ -120,8 +141,7 @@ NetMelee_getBattleState(NetConnection *conn) { //////////////////////////////////////////////////////////////////////////// -static inline -void +static inline void netInputAux(uint32 timeoutMs) { NetManager_process(&timeoutMs); // This may cause more packets to be queued, hence the @@ -249,42 +269,6 @@ allConnected(void) { return true; } -void -sendBattleInputConnections(BATTLE_INPUT_STATE input) { - COUNT player; - - for (player = 0; player < NUM_PLAYERS; player++) - { - NetConnection *conn = netConnections[player]; - if (conn == NULL) - continue; - - if (!NetConnection_isConnected(conn)) - continue; - - Netplay_battleInput(conn, input); - } -} - -#ifdef NETPLAY_CHECKSUM -void -sendChecksumConnections(uint32 frameNr, uint32 checksum) { - COUNT player; - - for (player = 0; player < NUM_PLAYERS; player++) - { - NetConnection *conn = netConnections[player]; - if (conn == NULL) - continue; - - if (!NetConnection_isConnected(conn)) - continue; - - Netplay_sendChecksum(conn, frameNr, checksum); - } -} -#endif /* NETPLAY_CHECKSUM */ - void initBattleStateDataConnections(void) { COUNT player; @@ -415,28 +399,6 @@ closePlayerNetworkConnection(COUNT player) { NetConnection_close(netConnections[player]); } -// If the callback function returns 'false', the function will immediately -// return with 'false'. Otherwise it will return 'true' after calling -// the callback function for each connected player. -bool -forAllConnectedPlayers(ForAllCallback callback, void *arg) { - COUNT player; - - for (player = 0; player < NUM_PLAYERS; player++) - { - NetConnection *conn = netConnections[player]; - if (conn == NULL) - continue; - - if (!NetConnection_isConnected(conn)) - continue; - - if (!(*callback)(conn, arg)) - return false; - } - return true; -} - bool setupInputDelay(size_t localInputDelay) { COUNT player; @@ -466,51 +428,39 @@ setupInputDelay(size_t localInputDelay) { } static bool -sendInputDelayConnection(NetConnection *conn, const size_t *delay) { - Netplay_sendInputDelay(conn, *delay); - return true; -} - -bool -sendInputDelayConnections(size_t delay) { - return forAllConnectedPlayers( - (ForAllCallback) sendInputDelayConnection, &delay); -} - -static bool -setStateConnection(NetConnection *conn, const NetState *state) { +setStateConnection(NetConnection *conn, void *arg) { + const NetState *state = (NetState *) arg; NetConnection_setState(conn, *state); return true; } bool setStateConnections(NetState state) { - return forAllConnectedPlayers( - (bool(*)(NetConnection *, void *)) setStateConnection, &state); + return forEachConnectedPlayer(setStateConnection, &state); } static bool -sendAbortConnection(NetConnection *conn, const NetplayAbortReason *reason) { +sendAbortConnection(NetConnection *conn, void *arg) { + const NetplayAbortReason *reason = (NetplayAbortReason *) arg; sendAbort(conn, *reason); return true; } bool sendAbortConnections(NetplayAbortReason reason) { - return forAllConnectedPlayers( - (bool(*)(NetConnection *, void *)) sendAbortConnection, &reason); + return forEachConnectedPlayer(sendAbortConnection, &reason); } static bool -resetConnection(NetConnection *conn, const NetplayResetReason *reason) { +resetConnection(NetConnection *conn, void *arg) { + const NetplayResetReason *reason = (NetplayResetReason *) arg; Netplay_localReset(conn, *reason); return true; } bool resetConnections(NetplayResetReason reason) { - return forAllConnectedPlayers( - (bool(*)(NetConnection *, void *)) resetConnection, &reason); + return forEachConnectedPlayer(resetConnection, &reason); } ///////////////////////////////////////////////////////////////////////////// @@ -522,9 +472,10 @@ typedef struct { } LocalReadyConnectionArg; static bool -localReadyConnection(NetConnection *conn, LocalReadyConnectionArg *arg) { - Netplay_localReady(conn, arg->readyCallback, arg->readyCallbackArg, - arg->notifyRemote); +localReadyConnection(NetConnection *conn, void *arg) { + LocalReadyConnectionArg *readyArg = (LocalReadyConnectionArg *) arg; + Netplay_localReady(conn, readyArg->readyCallback, + readyArg->readyCallbackArg, readyArg->notifyRemote); return true; } @@ -536,8 +487,7 @@ localReadyConnections(NetConnection_ReadyCallback readyCallback, arg.readyCallbackArg = readyArg; arg.notifyRemote = notifyRemote; - return forAllConnectedPlayers( - (bool(*)(NetConnection *, void *)) localReadyConnection, &arg); + return forEachConnectedPlayer(localReadyConnection, &arg); } @@ -636,7 +586,7 @@ typedef struct WaitReadyState WaitReadyState; struct WaitReadyState { // Common fields of INPUT_STATE_DESC, from which this structure // "inherits". - BOOLEAN(*InputFunc)(void *pInputState); + BOOLEAN (*InputFunc)(void *pInputState); NetConnection *conn; NetConnection_ReadyCallback readyCallback; @@ -760,7 +710,7 @@ out: return NetConnection_isConnected(conn); } -// Wait until we have received a reset packet to all connections. If we +// Wait until we have received a reset packet from all connections. If we // ourselves have not sent a reset packet, one is sent, with reason // 'manualReset'. // XXX: Right now all connections are handled one by one. Handling them all diff --git a/sc2/src/uqm/netplay/netmelee.h b/sc2/src/uqm/netplay/netmelee.h index 36f5dc401..178a00dee 100644 --- a/sc2/src/uqm/netplay/netmelee.h +++ b/sc2/src/uqm/netplay/netmelee.h @@ -40,6 +40,8 @@ void removeNetConnection(int playerNr); void closeAllConnections(void); void closeDisconnectedConnections(void); size_t getNumNetConnections(void); +typedef bool(*ForEachConnectionCallback)(NetConnection *conn, void *arg); +bool forEachConnectedPlayer(ForEachConnectionCallback callback, void *arg); struct melee_state *NetMelee_getMeleeState(NetConnection *conn); struct battlestate_struct *NetMelee_getBattleState(NetConnection *conn); @@ -54,8 +56,6 @@ void connectionsLocalReady(NetConnection_ReadyCallback callback, void *arg); bool allConnected(void); -void sendBattleInputConnections(BATTLE_INPUT_STATE input); -void sendChecksumConnections(uint32 frameNr, uint32 checksum); void initBattleStateDataConnections(void); void setBattleStateConnections(struct battlestate_struct *bs); @@ -65,11 +65,7 @@ BATTLE_INPUT_STATE networkBattleInput(NetworkInputContext *context, NetConnection *openPlayerNetworkConnection(COUNT player, void *extra); void closePlayerNetworkConnection(COUNT player); -typedef bool(*ForAllCallback)(NetConnection *conn, void *arg); -bool forAllConnectedPlayers(ForAllCallback callback, void *arg); - bool setupInputDelay(size_t localInputDelay); -bool sendInputDelayConnections(size_t delay); bool setStateConnections(NetState state); bool sendAbortConnections(NetplayAbortReason reason); bool resetConnections(NetplayResetReason reason); diff --git a/sc2/src/uqm/netplay/netmisc.c b/sc2/src/uqm/netplay/netmisc.c index ff871f8cb..751280aa5 100644 --- a/sc2/src/uqm/netplay/netmisc.c +++ b/sc2/src/uqm/netplay/netmisc.c @@ -20,6 +20,7 @@ #include "netmisc.h" #include "netmelee.h" +#include "notifyall.h" #include "packetsenders.h" #include "proto/ready.h" @@ -118,8 +119,8 @@ NetMelee_enterState_inSetup(NetConnection *conn, void *arg) { connectedFeedback(conn); - entireFleetChanged(meleeState, player); - teamStringChanged(meleeState, player); + Netplay_NotifyAll_setFleet(meleeState, player); + Netplay_NotifyAll_setTeamName(meleeState, player); flushPacketQueues(); @@ -151,13 +152,10 @@ NetMelee_reenterState_inSetup(NetConnection *conn) { for (side = 0; side < NUM_SIDES; side++) { - entireFleetChanged(meleeState, side); - teamStringChanged(meleeState, side); + Netplay_NotifyAll_setFleet(meleeState, side); + Netplay_NotifyAll_setTeamName(meleeState, side); } flushPacketQueues(); } } - - - diff --git a/sc2/src/uqm/netplay/notify.c b/sc2/src/uqm/netplay/notify.c index 92c1ed07f..8b35ead92 100644 --- a/sc2/src/uqm/netplay/notify.c +++ b/sc2/src/uqm/netplay/notify.c @@ -37,14 +37,14 @@ netSide(NetConnection *conn, int side) { } void -Netplay_selectShip(NetConnection *conn, uint16 index) { +Netplay_Notify_shipSelected(NetConnection *conn, FleetShipIndex index) { assert(NetConnection_getState(conn) == NetState_selectShip); sendSelectShip(conn, index); } void -Netplay_battleInput(NetConnection *conn, BATTLE_INPUT_STATE input) { +Netplay_Notify_battleInput(NetConnection *conn, BATTLE_INPUT_STATE input) { assert(NetConnection_getState(conn) == NetState_inBattle || NetConnection_getState(conn) == NetState_endingBattle || NetConnection_getState(conn) == NetState_endingBattle2); @@ -53,18 +53,18 @@ Netplay_battleInput(NetConnection *conn, BATTLE_INPUT_STATE input) { } void -Netplay_teamStringChanged(NetConnection *conn, int player, +Netplay_Notify_setTeamName(NetConnection *conn, int player, const char *name, size_t len) { assert(NetConnection_getState(conn) == NetState_inSetup); assert(!conn->stateFlags.handshake.localOk); - sendTeamString(conn, netSide(conn, player), name, len); + sendTeamName(conn, netSide(conn, player), name, len); } // On initialisation, or load. void -Netplay_entireFleetChanged(NetConnection *conn, int player, - const BYTE *fleet, size_t fleetSize) { +Netplay_Notify_setFleet(NetConnection *conn, int player, + const MeleeShip *fleet, size_t fleetSize) { assert(NetConnection_getState(conn) == NetState_inSetup); assert(!conn->stateFlags.handshake.localOk); @@ -72,8 +72,8 @@ Netplay_entireFleetChanged(NetConnection *conn, int player, } void -Netplay_fleetShipChanged(NetConnection *conn, int player, - size_t index, BYTE ship) { +Netplay_Notify_setShip(NetConnection *conn, int player, + FleetShipIndex index, MeleeShip ship) { assert(NetConnection_getState(conn) == NetState_inSetup); assert(!conn->stateFlags.handshake.localOk); @@ -81,7 +81,7 @@ Netplay_fleetShipChanged(NetConnection *conn, int player, } void -Netplay_seedRandom(NetConnection *conn, uint32 seed) { +Netplay_Notify_seedRandom(NetConnection *conn, uint32 seed) { assert(NetConnection_getState(conn) == NetState_preBattle); sendSeedRandom(conn, seed); @@ -89,14 +89,15 @@ Netplay_seedRandom(NetConnection *conn, uint32 seed) { } void -Netplay_sendInputDelay(NetConnection *conn, uint32 delay) { +Netplay_Notify_inputDelay(NetConnection *conn, uint32 delay) { assert(NetConnection_getState(conn) == NetState_preBattle); sendInputDelay(conn, delay); } void -Netplay_sendFrameCount(NetConnection *conn, BattleFrameCounter frameCount) { +Netplay_Notify_frameCount(NetConnection *conn, + BattleFrameCounter frameCount) { assert(NetConnection_getState(conn) == NetState_endingBattle); sendFrameCount(conn, frameCount); @@ -104,7 +105,7 @@ Netplay_sendFrameCount(NetConnection *conn, BattleFrameCounter frameCount) { #ifdef NETPLAY_CHECKSUM void -Netplay_sendChecksum(NetConnection *conn, BattleFrameCounter frameNr, +Netplay_Notify_checksum(NetConnection *conn, BattleFrameCounter frameNr, Checksum checksum) { assert(NetState_battleActive(NetConnection_getState(conn))); diff --git a/sc2/src/uqm/netplay/notify.h b/sc2/src/uqm/netplay/notify.h index c4290d1bd..55c3f2600 100644 --- a/sc2/src/uqm/netplay/notify.h +++ b/sc2/src/uqm/netplay/notify.h @@ -27,21 +27,26 @@ #ifdef NETPLAY_CHECKSUM # include "checksum.h" #endif +#include "../supermelee/meleeship.h" + // for MeleeShip +#include "../supermelee/meleesetup.h" + // for FleetShipIndex -void Netplay_selectShip(NetConnection *conn, uint16 index); -void Netplay_battleInput(NetConnection *conn, BATTLE_INPUT_STATE input); -void Netplay_teamStringChanged(NetConnection *conn, int player, +void Netplay_Notify_shipSelected(NetConnection *conn, FleetShipIndex index); +void Netplay_Notify_battleInput(NetConnection *conn, + BATTLE_INPUT_STATE input); +void Netplay_Notify_setTeamName(NetConnection *conn, int player, const char *name, size_t len); -void Netplay_entireFleetChanged(NetConnection *conn, int player, - const BYTE *fleet, size_t fleetSize); -void Netplay_fleetShipChanged(NetConnection *conn, int player, - size_t index, BYTE ship); -void Netplay_seedRandom(NetConnection *conn, uint32 seed); -void Netplay_sendInputDelay(NetConnection *conn, uint32 delay); -void Netplay_sendFrameCount(NetConnection *conn, +void Netplay_Notify_setFleet(NetConnection *conn, int player, + const MeleeShip *fleet, size_t fleetSize); +void Netplay_Notify_setShip(NetConnection *conn, int player, + FleetShipIndex index, MeleeShip ship); +void Netplay_Notify_seedRandom(NetConnection *conn, uint32 seed); +void Netplay_Notify_inputDelay(NetConnection *conn, uint32 delay); +void Netplay_Notify_frameCount(NetConnection *conn, BattleFrameCounter frameCount); #ifdef NETPLAY_CHECKSUM -void Netplay_sendChecksum(NetConnection *conn, +void Netplay_Notify_checksum(NetConnection *conn, BattleFrameCounter frameCount, Checksum checksum); #endif diff --git a/sc2/src/uqm/netplay/notifyall.c b/sc2/src/uqm/netplay/notifyall.c new file mode 100644 index 000000000..2d0cc8a16 --- /dev/null +++ b/sc2/src/uqm/netplay/notifyall.c @@ -0,0 +1,146 @@ +/* + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "notifyall.h" + +#include "netmelee.h" +#include "notify.h" + +// Notify the network connections of a team name change. +void +Netplay_NotifyAll_setTeamName (MELEE_STATE *pMS, size_t playerNr) +{ + const char *name; + size_t len; + size_t playerI; + + name = MeleeSetup_getTeamName (pMS->meleeSetup, playerNr); + len = strlen (name); + for (playerI = 0; playerI < NUM_PLAYERS; playerI++) + { + NetConnection *conn = netConnections[playerI]; + + if (conn == NULL) + continue; + + if (!NetConnection_isConnected (conn)) + continue; + + if (NetConnection_getState (conn) != NetState_inSetup) + continue; + + Netplay_Notify_setTeamName (conn, playerNr, name, len); + } +} + +// Notify the network connections of the configuration of a fleet. +void +Netplay_NotifyAll_setFleet (MELEE_STATE *pMS, size_t playerNr) +{ + MeleeSetup *setup = pMS->meleeSetup; + const MeleeShip *ships = MeleeSetup_getFleet (setup, playerNr); + size_t playerI; + + for (playerI = 0; playerI < NUM_PLAYERS; playerI++) { + NetConnection *conn = netConnections[playerI]; + + if (conn == NULL) + continue; + + if (!NetConnection_isConnected (conn)) + continue; + + if (NetConnection_getState (conn) != NetState_inSetup) + continue; + + Netplay_Notify_setFleet (conn, playerNr, ships, MELEE_FLEET_SIZE); + } +} + +// Notify the network of a change in the configuration of a fleet. +void +Netplay_NotifyAll_setShip (MELEE_STATE *pMS, size_t playerNr, size_t index) +{ + MeleeSetup *setup = pMS->meleeSetup; + MeleeShip ship = MeleeSetup_getShip (setup, playerNr, index); + + size_t playerI; + for (playerI = 0; playerI < NUM_PLAYERS; playerI++) + { + NetConnection *conn = netConnections[playerI]; + + if (conn == NULL) + continue; + + if (!NetConnection_isConnected (conn)) + continue; + + if (NetConnection_getState (conn) != NetState_inSetup) + continue; + + Netplay_Notify_setShip (conn, playerNr, index, ship); + } +} + +static bool +Netplay_NotifyAll_inputDelayCallback(NetConnection *conn, void *arg) { + const size_t *delay = (size_t *) arg; + Netplay_Notify_inputDelay(conn, *delay); + return true; +} + +bool +Netplay_NotifyAll_inputDelay(size_t delay) { + return forEachConnectedPlayer(Netplay_NotifyAll_inputDelayCallback, + &delay); +} + +#ifdef NETPLAY_CHECKSUM +void +Netplay_NotifyAll_checksum(BattleFrameCounter frameNr, Checksum checksum) { + COUNT player; + + for (player = 0; player < NUM_PLAYERS; player++) + { + NetConnection *conn = netConnections[player]; + if (conn == NULL) + continue; + + if (!NetConnection_isConnected(conn)) + continue; + + Netplay_Notify_checksum(conn, frameNr, checksum); + } +} +#endif /* NETPLAY_CHECKSUM */ + +void +Netplay_NotifyAll_battleInput(BATTLE_INPUT_STATE input) { + COUNT player; + + for (player = 0; player < NUM_PLAYERS; player++) + { + NetConnection *conn = netConnections[player]; + if (conn == NULL) + continue; + + if (!NetConnection_isConnected(conn)) + continue; + + Netplay_Notify_battleInput(conn, input); + } +} + diff --git a/sc2/src/uqm/netplay/notifyall.h b/sc2/src/uqm/netplay/notifyall.h new file mode 100644 index 000000000..397067bd6 --- /dev/null +++ b/sc2/src/uqm/netplay/notifyall.h @@ -0,0 +1,41 @@ +/* + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef NOTIFYALL_H +#define NOTIFYALL_H + +#include "../battle.h" +#include "../battlecontrols.h" +#include "../supermelee/melee.h" +#ifdef NETPLAY_CHECKSUM +# include "checksum.h" +#endif /* NETPLAY_CHECKSUM */ + +void Netplay_NotifyAll_setTeamName (MELEE_STATE *pMS, size_t playerNr); +void Netplay_NotifyAll_setFleet (MELEE_STATE *pMS, size_t playerNr); +void Netplay_NotifyAll_setShip (MELEE_STATE *pMS, size_t playerNr, + size_t index); + +bool Netplay_NotifyAll_inputDelay(size_t delay); +#ifdef NETPLAY_CHECKSUM +void Netplay_NotifyAll_checksum(BattleFrameCounter frameNr, + Checksum checksum); +#endif /* NETPLAY_CHECKSUM */ +void Netplay_NotifyAll_battleInput(BATTLE_INPUT_STATE input); + + +#endif /* NOTIFYALL_H */ + diff --git a/sc2/src/uqm/netplay/packet.h b/sc2/src/uqm/netplay/packet.h index 4d8d98e34..61bb4c294 100644 --- a/sc2/src/uqm/netplay/packet.h +++ b/sc2/src/uqm/netplay/packet.h @@ -174,7 +174,7 @@ typedef enum { typedef struct { uint8 index; /* Position in the fleet */ - uint8 ship; /* Ship type index */ + uint8 ship; /* Ship type index; actually MeleeShip */ } FleetEntry; // Structure describing an update to a player's fleet. // TODO: use strings as ship identifiers, instead of numbers, diff --git a/sc2/src/uqm/netplay/packethandlers.c b/sc2/src/uqm/netplay/packethandlers.c index 4018d125c..0067baec0 100644 --- a/sc2/src/uqm/netplay/packethandlers.c +++ b/sc2/src/uqm/netplay/packethandlers.c @@ -39,6 +39,8 @@ // for GLOBAL #include "../supermelee/melee.h" // for various update functions. +#include "../supermelee/meleeship.h" + // for MeleeShip #include "../supermelee/pickmele.h" // for various update functions. #include "libs/mathlib.h" @@ -263,16 +265,26 @@ PacketHandler_Fleet(NetConnection *conn, const Packet_Fleet *packet) { } for (i = 0; i < numShips; i++) { - int ship = packet->ships[i].ship; - int index = packet->ships[i].index; + MeleeShip ship = (MeleeShip) packet->ships[i].ship; + FleetShipIndex index = (FleetShipIndex) packet->ships[i].index; - bool updateResult = updateFleetShip( - battleStateData->meleeState, player, index, ship); - if (!updateResult) - { + if (!MeleeShip_valid(ship)) { + log_add (log_Warning, "Invalid ship type number %d (max = %d).\n", + ship, NUM_MELEE_SHIPS - 1); errno = EBADMSG; return -1; } + + if (index >= MELEE_FLEET_SIZE) + { + log_add (log_Warning, "Invalid ship position number %d " + "(max = %d).\n", index, MELEE_FLEET_SIZE - 1); + errno = EBADMSG; + return -1; + } + + Melee_RemoteChange_ship (battleStateData->meleeState, conn, + player, index, ship); } // Padding data may follow; it is ignored. @@ -312,8 +324,17 @@ PacketHandler_TeamName(NetConnection *conn, const Packet_TeamName *packet) { - sizeof (Packet_TeamName) - 1; // The -1 is for not counting the terminating '\0'. - updateTeamName(battleStateData->meleeState, side, - (const char *) packet->name, nameLen); + { + char buf[MAX_TEAM_CHARS + 1]; + + if (nameLen > MAX_TEAM_CHARS) + nameLen = MAX_TEAM_CHARS; + memcpy (buf, (const char *) packet->name, nameLen); + buf[nameLen] = '\0'; + + Melee_RemoteChange_teamName(battleStateData->meleeState, conn, + side, buf); + } // Padding data may follow; it is ignored. return 0; diff --git a/sc2/src/uqm/netplay/packetsenders.c b/sc2/src/uqm/netplay/packetsenders.c index 7734a5b23..78ef2c285 100644 --- a/sc2/src/uqm/netplay/packetsenders.c +++ b/sc2/src/uqm/netplay/packetsenders.c @@ -107,7 +107,7 @@ sendHandshakeCancelAck(NetConnection *conn) { } void -sendTeamString(NetConnection *conn, NetplaySide side, const char *name, +sendTeamName(NetConnection *conn, NetplaySide side, const char *name, size_t len) { Packet_TeamName *packet; @@ -116,30 +116,30 @@ sendTeamString(NetConnection *conn, NetplaySide side, const char *name, } void -sendFleet(NetConnection *conn, NetplaySide side, const BYTE *ships, - size_t numShips) { +sendFleet(NetConnection *conn, NetplaySide side, const MeleeShip *ships, + size_t shipCount) { size_t i; Packet_Fleet *packet; - packet = Packet_Fleet_create(side, numShips); + packet = Packet_Fleet_create(side, shipCount); - for (i = 0; i < numShips; i++) { + for (i = 0; i < shipCount; i++) { packet->ships[i].index = (uint8) i; - packet->ships[i].ship = ships[i]; + packet->ships[i].ship = (uint8) ships[i]; } queuePacket(conn, (Packet *) packet, false); } void -sendFleetShip(NetConnection *conn, NetplaySide side, size_t shipIndex, - BYTE ship) { +sendFleetShip(NetConnection *conn, NetplaySide side, + FleetShipIndex shipIndex, MeleeShip ship) { Packet_Fleet *packet; packet = Packet_Fleet_create(side, 1); - packet->ships[0].index = shipIndex; - packet->ships[0].ship = ship; + packet->ships[0].index = (uint8) shipIndex; + packet->ships[0].ship = (uint8) ship; queuePacket(conn, (Packet *) packet, false); } @@ -161,10 +161,10 @@ sendInputDelay(NetConnection *conn, uint32 delay) { } void -sendSelectShip(NetConnection *conn, COUNT ship) { +sendSelectShip(NetConnection *conn, FleetShipIndex index) { Packet_SelectShip *packet; - packet = Packet_SelectShip_create(ship); + packet = Packet_SelectShip_create((uint16) index); queuePacket(conn, (Packet *) packet, false); } diff --git a/sc2/src/uqm/netplay/packetsenders.h b/sc2/src/uqm/netplay/packetsenders.h index 6e2af7214..06f083d4f 100644 --- a/sc2/src/uqm/netplay/packetsenders.h +++ b/sc2/src/uqm/netplay/packetsenders.h @@ -26,6 +26,10 @@ #include "../controls.h" // for BATTLE_INPUT_STATE +#include "../supermelee/meleeship.h" + // for MeleeShip +#include "../supermelee/meleesetup.h" + // for FleetShipIndex void sendInit(NetConnection *conn); void sendPing(NetConnection *conn, uint32 id); @@ -37,18 +41,19 @@ void sendHandshake0(NetConnection *conn); void sendHandshake1(NetConnection *conn); void sendHandshakeCancel(NetConnection *conn); void sendHandshakeCancelAck(NetConnection *conn); -void sendTeamString(NetConnection *conn, NetplaySide side, +void sendTeamName(NetConnection *conn, NetplaySide side, const char *name, size_t len); -void sendFleet(NetConnection *conn, NetplaySide side, const BYTE *ships, - size_t numShips); +void sendFleet(NetConnection *conn, NetplaySide side, + const MeleeShip *ships, size_t numShips); void sendFleetShip(NetConnection *conn, NetplaySide player, - size_t shipIndex, BYTE ship); + FleetShipIndex shipIndex, MeleeShip ship); void sendSeedRandom(NetConnection *conn, uint32 seed); void sendInputDelay(NetConnection *conn, uint32 delay); -void sendSelectShip(NetConnection *conn, COUNT ship); +void sendSelectShip(NetConnection *conn, FleetShipIndex index); void sendBattleInput(NetConnection *conn, BATTLE_INPUT_STATE input); -void sendFrameCount(NetConnection *conn, uint32 frameCount); -void sendChecksum(NetConnection *conn, uint32 frameNr, uint32 checksum); +void sendFrameCount(NetConnection *conn, BattleFrameCounter frameCount); +void sendChecksum(NetConnection *conn, BattleFrameCounter frameNr, + Checksum checksum); void sendAbort(NetConnection *conn, NetplayAbortReason reason); void sendReset(NetConnection *conn, NetplayResetReason reason); diff --git a/sc2/src/uqm/supermelee/Makeinfo b/sc2/src/uqm/supermelee/Makeinfo index 7dd4191f1..98e9f38c1 100644 --- a/sc2/src/uqm/supermelee/Makeinfo +++ b/sc2/src/uqm/supermelee/Makeinfo @@ -1 +1 @@ -uqm_CFILES="loadmele.c melee.c pickmele.c" +uqm_CFILES="buildpick.c loadmele.c melee.c meleesetup.c pickmele.c" diff --git a/sc2/src/uqm/supermelee/buildpick.c b/sc2/src/uqm/supermelee/buildpick.c new file mode 100644 index 000000000..14ef2731b --- /dev/null +++ b/sc2/src/uqm/supermelee/buildpick.c @@ -0,0 +1,226 @@ +/* + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "buildpick.h" + +#include "../controls.h" +#include "../colors.h" +#include "../fmv.h" +#include "../master.h" +#include "../setup.h" +#include "../sounds.h" +#include "libs/gfxlib.h" + +static FRAME BuildPickFrame; + +void +BuildBuildPickFrame (void) +{ + STAMP s; + RECT r; + COUNT i; + CONTEXT OldContext = SetContext (OffScreenContext); + + // create team building ship selection box + s.origin.x = 0; + s.origin.y = 0; + s.frame = SetAbsFrameIndex (MeleeFrame, 27); + // 5x5 grid of ships to pick from + GetFrameRect (s.frame, &r); + + BuildPickFrame = CaptureDrawable (CreateDrawable ( + WANT_PIXMAP, r.extent.width, r.extent.height, 1)); + SetContextFGFrame (BuildPickFrame); + SetFrameHot (s.frame, MAKE_HOT_SPOT (0, 0)); + DrawStamp (&s); + + for (i = 0; i < NUM_PICK_COLS * NUM_PICK_ROWS; ++i) + DrawPickIcon (i, true); + + SetContext (OldContext); +} + +void +DestroyBuildPickFrame (void) +{ + DestroyDrawable (ReleaseDrawable (BuildPickFrame)); + BuildPickFrame = 0; +} + +// Draw a ship icon in the ship selection popup. +void +DrawPickIcon (MeleeShip ship, bool DrawErase) +{ + STAMP s; + RECT r; + + GetFrameRect (BuildPickFrame, &r); + + s.origin.x = r.corner.x + 20 + (ship % NUM_PICK_COLS) * 18; + s.origin.y = r.corner.y + 5 + (ship / NUM_PICK_COLS) * 18; + s.frame = GetShipIconsFromIndex (ship); + if (DrawErase) + { // draw icon + DrawStamp (&s); + } + else + { // erase icon + Color OldColor; + + OldColor = SetContextForeGroundColor (BLACK_COLOR); + DrawFilledStamp (&s); + SetContextForeGroundColor (OldColor); + } +} + +// Pre: the called holds the GraphicsLock +void +DrawPickFrame (MELEE_STATE *pMS) +{ + RECT r, r0, r1, ship_r; + STAMP s; + + GetShipBox (&r0, 0, 0, 0), + GetShipBox (&r1, 1, NUM_MELEE_ROWS - 1, NUM_MELEE_COLUMNS - 1), + BoxUnion (&r0, &r1, &ship_r); + + s.frame = SetAbsFrameIndex (BuildPickFrame, 0); + GetFrameRect (s.frame, &r); + r.corner.x = -(ship_r.corner.x + + ((ship_r.extent.width - r.extent.width) >> 1)); + if (pMS->side) + r.corner.y = -ship_r.corner.y; + else + r.corner.y = -(ship_r.corner.y + + (ship_r.extent.height - r.extent.height)); + SetFrameHot (s.frame, MAKE_HOT_SPOT (r.corner.x, r.corner.y)); + s.origin.x = 0; + s.origin.y = 0; + DrawStamp (&s); + DrawMeleeShipStrings (pMS, pMS->currentShip); +} + +void +GetBuildPickFrameRect (RECT *r) +{ + GetFrameRect (BuildPickFrame, r); +} + +static BOOLEAN +DoPickShip (MELEE_STATE *pMS) +{ + DWORD TimeIn = GetTimeCounter (); + + /* Cancel any presses of the Pause key. */ + GamePaused = FALSE; + + if (GLOBAL (CurrentActivity) & CHECK_ABORT) + { + pMS->buildPickConfirmed = false; + return FALSE; + } + + SetMenuSounds (MENU_SOUND_ARROWS, MENU_SOUND_SELECT); + + if (PulsedInputState.menu[KEY_MENU_SELECT] || + PulsedInputState.menu[KEY_MENU_CANCEL]) + { + // Confirm selection or cancel. + pMS->buildPickConfirmed = !PulsedInputState.menu[KEY_MENU_CANCEL]; + return FALSE; + } + + if (PulsedInputState.menu[KEY_MENU_SPECIAL] + && (pMS->currentShip != MELEE_NONE)) + { + // Show ship spin video. + DoShipSpin (pMS->currentShip, (MUSIC_REF) 0); + return TRUE; + } + + { + MeleeShip newSelectedShip; + + newSelectedShip = pMS->currentShip; + + if (PulsedInputState.menu[KEY_MENU_LEFT]) + { + if (newSelectedShip % NUM_PICK_COLS == 0) + newSelectedShip += NUM_PICK_COLS; + --newSelectedShip; + } + else if (PulsedInputState.menu[KEY_MENU_RIGHT]) + { + ++newSelectedShip; + if (newSelectedShip % NUM_PICK_COLS == 0) + newSelectedShip -= NUM_PICK_COLS; + } + + if (PulsedInputState.menu[KEY_MENU_UP]) + { + if (newSelectedShip >= NUM_PICK_COLS) + newSelectedShip -= NUM_PICK_COLS; + else + newSelectedShip += NUM_PICK_COLS * (NUM_PICK_ROWS - 1); + } + else if (PulsedInputState.menu[KEY_MENU_DOWN]) + { + if (newSelectedShip < NUM_PICK_COLS * (NUM_PICK_ROWS - 1)) + newSelectedShip += NUM_PICK_COLS; + else + newSelectedShip -= NUM_PICK_COLS * (NUM_PICK_ROWS - 1); + } + + if (newSelectedShip != pMS->currentShip) + { + // A new ship has been selected. + LockMutex (GraphicsLock); + DrawPickIcon (pMS->currentShip, true); + pMS->currentShip = newSelectedShip; + DrawMeleeShipStrings (pMS, newSelectedShip); + UnlockMutex (GraphicsLock); + } + } + + Melee_flashSelection (pMS); + + SleepThreadUntil (TimeIn + ONE_SECOND / 30); + + return TRUE; +} + +// Returns true if a ship has been selected, or false if the operation has +// been cancelled or if the general abort key was pressed (in which case +// 'GLOBAL (CurrentActivity) & CHECK_ABORT' is true as usual. +// If a ship was selected, pMS->currentShip is set to the selected ship. +bool +BuildPickShip (MELEE_STATE *pMS) +{ + FlushInput (); + + if (pMS->currentShip == MELEE_NONE) + pMS->currentShip = 0; + + LockMutex (GraphicsLock); + DrawPickFrame (pMS); + UnlockMutex (GraphicsLock); + + pMS->InputFunc = DoPickShip; + DoInput (pMS, FALSE); + + return pMS->buildPickConfirmed; +} + diff --git a/sc2/src/uqm/supermelee/buildpick.h b/sc2/src/uqm/supermelee/buildpick.h new file mode 100644 index 000000000..52ee4fe39 --- /dev/null +++ b/sc2/src/uqm/supermelee/buildpick.h @@ -0,0 +1,17 @@ +#ifndef BUILDPICK_H +#define BUILDPICK_H + +#include +#include "melee.h" + +void BuildBuildPickFrame (void); +void DestroyBuildPickFrame (void); +bool BuildPickShip (MELEE_STATE *pMS); +void GetBuildPickFrameRect (RECT *r); + +void DrawPickFrame (MELEE_STATE *pMS); +void DrawPickIcon (MeleeShip ship, bool DrawErase); + + +#endif /* BUILDPICK_H */ + diff --git a/sc2/src/uqm/supermelee/loadmele.c b/sc2/src/uqm/supermelee/loadmele.c index 2621091d4..638326706 100644 --- a/sc2/src/uqm/supermelee/loadmele.c +++ b/sc2/src/uqm/supermelee/loadmele.c @@ -18,6 +18,7 @@ // This file handles loading of teams, but the UI and the actual loading. +#define MELEESETUP_INTERNAL #include "melee.h" #include "../controls.h" @@ -25,10 +26,11 @@ #include "../gamestr.h" #include "../globdata.h" #include "../master.h" +#include "meleesetup.h" #include "../save.h" #include "../setup.h" #include "../sounds.h" -#include "../../options.h" +#include "options.h" #include "libs/log.h" #include "libs/memlib.h" @@ -48,53 +50,23 @@ static void DrawFileStrings (MELEE_STATE *pMS); static bool FillFileView (MELEE_STATE *pMS); -bool -ReadTeamImage (TEAM_IMAGE *pTI, uio_Stream *load_fp) -{ - int status; - FleetShipIndex i; - - status = ReadResFile (pTI, sizeof (*pTI), 1, load_fp); - if (status != 1) - return false; - - // Sanity check on the entries. - for (i = 0; i < MELEE_FLEET_SIZE; i++) - { - BYTE StarShip = pTI->ShipList[i]; - - if (StarShip == MELEE_NONE) - continue; - - if (StarShip >= NUM_MELEE_SHIPS) - { - log_add (log_Warning, "Invalid ship type in loaded team (index " - "%d, ship type is %d, max valid is %d).", - i, StarShip, NUM_MELEE_SHIPS - 1); - pTI->ShipList[i] = MELEE_NONE; - } - } - - return true; -} - static bool -LoadTeamImage (DIRENTRY DirEntry, TEAM_IMAGE *pTI) +LoadTeamImage (DIRENTRY DirEntry, MeleeTeam *team) { - const BYTE *fileName; - uio_Stream *load_fp; + const char *fileName; + uio_Stream *stream; bool status; fileName = GetDirEntryAddress (DirEntry); - load_fp = res_OpenResFile (meleeDir, (const char *) fileName, "rb"); - if (load_fp == 0) + + stream = uio_fopen (meleeDir, fileName, "rb"); + if (stream == NULL) return false; - if (LengthResFile (load_fp) != sizeof (*pTI)) - status = false; - else - status = ReadTeamImage (pTI, load_fp); - res_CloseResFile (load_fp); + if (MeleeTeam_deserialize (team, stream) == -1) + return false; + + uio_fclose (stream); return status; } @@ -123,13 +95,13 @@ UnindexFleets (MELEE_STATE *pMS, COUNT index, COUNT count) } static bool -GetFleetByIndex (MELEE_STATE *pMS, COUNT index, TEAM_IMAGE *result) +GetFleetByIndex (MELEE_STATE *pMS, COUNT index, MeleeTeam *result) { COUNT firstIndex; if (index < pMS->load.preBuiltCount) { - *result = pMS->load.preBuiltList[index]; + MeleeTeam_copy (result, pMS->load.preBuiltList[index]); return true; } @@ -144,7 +116,7 @@ GetFleetByIndex (MELEE_STATE *pMS, COUNT index, TEAM_IMAGE *result) break; // Success { - const BYTE *fileName; + const char *fileName; fileName = GetDirEntryAddress (entry); log_add (log_Warning, "Warning: File '%s' is not a valid " "SuperMelee team.", fileName); @@ -167,7 +139,7 @@ GetFleetIndexByFileName (MELEE_STATE *pMS, const char *fileName) { DIRENTRY entry = SetAbsDirEntryTableIndex (pMS->load.dirEntries, pMS->load.entryIndices[index]); - const BYTE *entryName = GetDirEntryAddress (entry); + const char *entryName = GetDirEntryAddress (entry); if (strcasecmp ((const char *) entryName, fileName) == 0) return pMS->load.preBuiltCount + index; @@ -181,8 +153,8 @@ GetFleetIndexByFileName (MELEE_STATE *pMS, const char *fileName) // fleet name and value; if not, only the fleet name and value are drawn. // If highlite is set the text is drawn in the color used for highlighting. static void -DrawFileString (TEAM_IMAGE *pTI, POINT *origin, BOOLEAN drawShips, - BOOLEAN highlite) +DrawFileString (const MeleeTeam *team, const POINT *origin, + BOOLEAN drawShips, BOOLEAN highlite) { SetContextForeGroundColor (highlite ? LOAD_TEAM_NAME_TEXT_COLOR_HILITE : LOAD_TEAM_NAME_TEXT_COLOR); @@ -193,7 +165,7 @@ DrawFileString (TEAM_IMAGE *pTI, POINT *origin, BOOLEAN drawShips, Text.baseline = *origin; Text.align = ALIGN_LEFT; - Text.pStr = pTI->TeamName; + Text.pStr = MeleeTeam_getTeamName(team); Text.CharCount = (COUNT)~0; font_DrawText (&Text); } @@ -203,7 +175,7 @@ DrawFileString (TEAM_IMAGE *pTI, POINT *origin, BOOLEAN drawShips, TEXT Text; UNICODE buf[60]; - sprintf (buf, "%u", GetTeamValue (pTI)); + sprintf (buf, "%u", MeleeTeam_getValue (team)); Text.baseline = *origin; Text.baseline.x += NUM_MELEE_COLUMNS * (LOAD_MELEE_BOX_WIDTH + LOAD_MELEE_BOX_SPACE) - 1; @@ -217,15 +189,15 @@ DrawFileString (TEAM_IMAGE *pTI, POINT *origin, BOOLEAN drawShips, if (drawShips) { STAMP s; - FleetShipIndex index; + FleetShipIndex slotI; s.origin.x = origin->x + 1; s.origin.y = origin->y + 4; - for (index = 0; index < MELEE_FLEET_SIZE; index++) + for (slotI = 0; slotI < MELEE_FLEET_SIZE; slotI++) { BYTE StarShip; - StarShip = pTI->ShipList[index]; + StarShip = team->ships[slotI]; if (StarShip != MELEE_NONE) { s.frame = GetShipIconsFromIndex (StarShip); @@ -247,7 +219,7 @@ FillFileView (MELEE_STATE *pMS) for (viewI = 0; viewI < LOAD_TEAM_VIEW_SIZE; viewI++) { bool success = GetFleetByIndex (pMS, pMS->load.top + viewI, - &pMS->load.view[viewI]); + pMS->load.view[viewI]); if (!success) break; } @@ -278,7 +250,7 @@ SelectFileString (MELEE_STATE *pMS, bool hilite) origin.x = FILE_STRING_ORIGIN_X; origin.y = FILE_STRING_ORIGIN_Y + viewI * ENTRY_HEIGHT; - DrawFileString (&pMS->load.view[viewI], &origin, FALSE, hilite); + DrawFileString (pMS->load.view[viewI], &origin, FALSE, hilite); UnbatchGraphics (); SetContext (OldContext); @@ -303,7 +275,7 @@ DrawFileStrings (MELEE_STATE *pMS) { COUNT i; for (i = pMS->load.top; i < pMS->load.bot; i++) { - DrawFileString (&pMS->load.view[i - pMS->load.top], &origin, + DrawFileString (pMS->load.view[i - pMS->load.top], &origin, TRUE, FALSE); origin.y += ENTRY_HEIGHT; } @@ -379,12 +351,8 @@ DoLoadTeam (MELEE_STATE *pMS) if (PulsedInputState.menu[KEY_MENU_SELECT]) { // Copy the selected fleet to the player. - pMS->SideState[pMS->side].TeamImage = - pMS->load.view[pMS->load.cur - pMS->load.top]; - pMS->SideState[pMS->side].star_bucks = - GetTeamValue (&pMS->SideState[pMS->side].TeamImage); - entireFleetChanged (pMS, pMS->side); - teamStringChanged (pMS, pMS->side); + Melee_Change_team (pMS, pMS->side, + pMS->load.view[pMS->load.cur - pMS->load.top]); } pMS->InputFunc = DoMelee; @@ -470,12 +438,6 @@ DoLoadTeam (MELEE_STATE *pMS) return TRUE; } -int -WriteTeamImage (TEAM_IMAGE *pTI, uio_Stream *save_fp) -{ - return WriteResFile (pTI, sizeof (*pTI), 1, save_fp); -} - void SelectTeamByFileName (MELEE_STATE *pMS, const char *fileName) { @@ -509,73 +471,67 @@ DoSaveTeam (MELEE_STATE *pMS) { STAMP MsgStamp; char file[NAME_MAX]; - uio_Stream *save_fp; + uio_Stream *stream; CONTEXT OldContext; + bool saveOk = false; - sprintf (file, "%s.mle", pMS->SideState[pMS->side].TeamImage.TeamName); + snprintf (file, sizeof file, "%s.mle", + MeleeSetup_getTeamName (pMS->meleeSetup, pMS->side)); LockMutex (GraphicsLock); OldContext = SetContext (ScreenContext); ConfirmSaveLoad (&MsgStamp); - save_fp = res_OpenResFile (meleeDir, file, "wb"); - if (save_fp) - { - BOOLEAN err; + // Show the "Saving . . ." message. + UnlockMutex (GraphicsLock); - err = (BOOLEAN)(WriteTeamImage ( - &pMS->SideState[pMS->side].TeamImage, save_fp) == 0); - if (res_CloseResFile (save_fp) == 0) - err = TRUE; - if (err) - save_fp = 0; + stream = uio_fopen (meleeDir, file, "wb"); + if (stream != NULL) + { + saveOk = (MeleeTeam_serialize (&pMS->meleeSetup->teams[pMS->side], + stream) == 0); + uio_fclose (stream); + + if (!saveOk) + uio_unlink (meleeDir, file); } pMS->load.top = 0; pMS->load.cur = 0; - if (save_fp == 0) - { - DrawStamp (&MsgStamp); - DestroyDrawable (ReleaseDrawable (MsgStamp.frame)); - SetContext (OldContext); - UnlockMutex (GraphicsLock); + // Undo the screen damage done by the "Saving . . ." message. + LockMutex (GraphicsLock); + DrawStamp (&MsgStamp); + DestroyDrawable (ReleaseDrawable (MsgStamp.frame)); + SetContext (OldContext); + UnlockMutex (GraphicsLock); - DeleteResFile (meleeDir, file); + if (!saveOk) SaveProblem (); - } + // Update the team list; a previously existing team may have been + // deleted when save failed. LoadTeamList (pMS); SelectTeamByFileName (pMS, file); - - if (save_fp != 0) - { - DrawStamp (&MsgStamp); - DestroyDrawable (ReleaseDrawable (MsgStamp.frame)); - SetContext (OldContext); - UnlockMutex (GraphicsLock); - } - return (save_fp != 0); + return (stream != 0); } static void InitPreBuilt (MELEE_STATE *pMS) { - TEAM_IMAGE *list; + MeleeTeam **list; #define PREBUILT_COUNT 15 pMS->load.preBuiltList = - HMalloc (PREBUILT_COUNT * sizeof pMS->load.preBuiltList[0]); + HMalloc (PREBUILT_COUNT * sizeof (MeleeTeam *)); pMS->load.preBuiltCount = PREBUILT_COUNT; #undef PREBUILT_COUNT { - FleetShipIndex shipI = 0; - int fleetI; + size_t fleetI; for (fleetI = 0; fleetI < pMS->load.preBuiltCount; fleetI++) - for (shipI = 0; shipI < MELEE_FLEET_SIZE; shipI++) - pMS->load.preBuiltList[fleetI].ShipList[shipI] = MELEE_NONE; + pMS->load.preBuiltList[fleetI] = MeleeTeam_new (); } list = pMS->load.preBuiltList; @@ -583,260 +539,245 @@ InitPreBuilt (MELEE_STATE *pMS) { /* "Balanced Team 1" */ FleetShipIndex i = 0; - utf8StringCopy (list->TeamName, sizeof (list->TeamName), - GAME_STRING (MELEE_STRING_BASE + 4)); - list->ShipList[i++] = MELEE_ANDROSYNTH; - list->ShipList[i++] = MELEE_CHMMR; - list->ShipList[i++] = MELEE_DRUUGE; - list->ShipList[i++] = MELEE_URQUAN; - list->ShipList[i++] = MELEE_MELNORME; - list->ShipList[i++] = MELEE_ORZ; - list->ShipList[i++] = MELEE_SPATHI; - list->ShipList[i++] = MELEE_SYREEN; - list->ShipList[i++] = MELEE_UTWIG; + MeleeTeam_setName (*list, GAME_STRING (MELEE_STRING_BASE + 4)); + MeleeTeam_setShip (*list, i++, MELEE_ANDROSYNTH); + MeleeTeam_setShip (*list, i++, MELEE_CHMMR); + MeleeTeam_setShip (*list, i++, MELEE_DRUUGE); + MeleeTeam_setShip (*list, i++, MELEE_URQUAN); + MeleeTeam_setShip (*list, i++, MELEE_MELNORME); + MeleeTeam_setShip (*list, i++, MELEE_ORZ); + MeleeTeam_setShip (*list, i++, MELEE_SPATHI); + MeleeTeam_setShip (*list, i++, MELEE_SYREEN); + MeleeTeam_setShip (*list, i++, MELEE_UTWIG); list++; } { /* "Balanced Team 2" */ FleetShipIndex i = 0; - utf8StringCopy (list->TeamName, sizeof (list->TeamName), - GAME_STRING (MELEE_STRING_BASE + 5)); - list->ShipList[i++] = MELEE_ARILOU; - list->ShipList[i++] = MELEE_CHENJESU; - list->ShipList[i++] = MELEE_EARTHLING; - list->ShipList[i++] = MELEE_KOHR_AH; - list->ShipList[i++] = MELEE_MYCON; - list->ShipList[i++] = MELEE_YEHAT; - list->ShipList[i++] = MELEE_PKUNK; - list->ShipList[i++] = MELEE_SUPOX; - list->ShipList[i++] = MELEE_THRADDASH; - list->ShipList[i++] = MELEE_ZOQFOTPIK; - list->ShipList[i++] = MELEE_SHOFIXTI; + MeleeTeam_setName (*list, GAME_STRING (MELEE_STRING_BASE + 5)); + MeleeTeam_setShip (*list, i++, MELEE_ARILOU); + MeleeTeam_setShip (*list, i++, MELEE_CHENJESU); + MeleeTeam_setShip (*list, i++, MELEE_EARTHLING); + MeleeTeam_setShip (*list, i++, MELEE_KOHR_AH); + MeleeTeam_setShip (*list, i++, MELEE_MYCON); + MeleeTeam_setShip (*list, i++, MELEE_YEHAT); + MeleeTeam_setShip (*list, i++, MELEE_PKUNK); + MeleeTeam_setShip (*list, i++, MELEE_SUPOX); + MeleeTeam_setShip (*list, i++, MELEE_THRADDASH); + MeleeTeam_setShip (*list, i++, MELEE_ZOQFOTPIK); + MeleeTeam_setShip (*list, i++, MELEE_SHOFIXTI); list++; } { /* "200 points" */ FleetShipIndex i = 0; - utf8StringCopy (list->TeamName, sizeof (list->TeamName), - GAME_STRING (MELEE_STRING_BASE + 6)); - list->ShipList[i++] = MELEE_ANDROSYNTH; - list->ShipList[i++] = MELEE_CHMMR; - list->ShipList[i++] = MELEE_DRUUGE; - list->ShipList[i++] = MELEE_MELNORME; - list->ShipList[i++] = MELEE_EARTHLING; - list->ShipList[i++] = MELEE_KOHR_AH; - list->ShipList[i++] = MELEE_SUPOX; - list->ShipList[i++] = MELEE_ORZ; - list->ShipList[i++] = MELEE_SPATHI; - list->ShipList[i++] = MELEE_ILWRATH; - list->ShipList[i++] = MELEE_VUX; + MeleeTeam_setName (*list, GAME_STRING (MELEE_STRING_BASE + 6)); + MeleeTeam_setShip (*list, i++, MELEE_ANDROSYNTH); + MeleeTeam_setShip (*list, i++, MELEE_CHMMR); + MeleeTeam_setShip (*list, i++, MELEE_DRUUGE); + MeleeTeam_setShip (*list, i++, MELEE_MELNORME); + MeleeTeam_setShip (*list, i++, MELEE_EARTHLING); + MeleeTeam_setShip (*list, i++, MELEE_KOHR_AH); + MeleeTeam_setShip (*list, i++, MELEE_SUPOX); + MeleeTeam_setShip (*list, i++, MELEE_ORZ); + MeleeTeam_setShip (*list, i++, MELEE_SPATHI); + MeleeTeam_setShip (*list, i++, MELEE_ILWRATH); + MeleeTeam_setShip (*list, i++, MELEE_VUX); list++; } { /* "Behemoth Zenith" */ FleetShipIndex i = 0; - utf8StringCopy (list->TeamName, sizeof (list->TeamName), - GAME_STRING (MELEE_STRING_BASE + 7)); - list->ShipList[i++] = MELEE_CHENJESU; - list->ShipList[i++] = MELEE_CHENJESU; - list->ShipList[i++] = MELEE_CHMMR; - list->ShipList[i++] = MELEE_CHMMR; - list->ShipList[i++] = MELEE_KOHR_AH; - list->ShipList[i++] = MELEE_KOHR_AH; - list->ShipList[i++] = MELEE_URQUAN; - list->ShipList[i++] = MELEE_URQUAN; - list->ShipList[i++] = MELEE_UTWIG; - list->ShipList[i++] = MELEE_UTWIG; + MeleeTeam_setName (*list, GAME_STRING (MELEE_STRING_BASE + 7)); + MeleeTeam_setShip (*list, i++, MELEE_CHENJESU); + MeleeTeam_setShip (*list, i++, MELEE_CHENJESU); + MeleeTeam_setShip (*list, i++, MELEE_CHMMR); + MeleeTeam_setShip (*list, i++, MELEE_CHMMR); + MeleeTeam_setShip (*list, i++, MELEE_KOHR_AH); + MeleeTeam_setShip (*list, i++, MELEE_KOHR_AH); + MeleeTeam_setShip (*list, i++, MELEE_URQUAN); + MeleeTeam_setShip (*list, i++, MELEE_URQUAN); + MeleeTeam_setShip (*list, i++, MELEE_UTWIG); + MeleeTeam_setShip (*list, i++, MELEE_UTWIG); list++; } { /* "The Peeled Eyes" */ FleetShipIndex i = 0; - utf8StringCopy (list->TeamName, sizeof (list->TeamName), - GAME_STRING (MELEE_STRING_BASE + 8)); - list->ShipList[i++] = MELEE_URQUAN; - list->ShipList[i++] = MELEE_CHENJESU; - list->ShipList[i++] = MELEE_MYCON; - list->ShipList[i++] = MELEE_SYREEN; - list->ShipList[i++] = MELEE_ZOQFOTPIK; - list->ShipList[i++] = MELEE_SHOFIXTI; - list->ShipList[i++] = MELEE_EARTHLING; - list->ShipList[i++] = MELEE_KOHR_AH; - list->ShipList[i++] = MELEE_MELNORME; - list->ShipList[i++] = MELEE_DRUUGE; - list->ShipList[i++] = MELEE_PKUNK; - list->ShipList[i++] = MELEE_ORZ; + MeleeTeam_setName (*list, GAME_STRING (MELEE_STRING_BASE + 8)); + MeleeTeam_setShip (*list, i++, MELEE_URQUAN); + MeleeTeam_setShip (*list, i++, MELEE_CHENJESU); + MeleeTeam_setShip (*list, i++, MELEE_MYCON); + MeleeTeam_setShip (*list, i++, MELEE_SYREEN); + MeleeTeam_setShip (*list, i++, MELEE_ZOQFOTPIK); + MeleeTeam_setShip (*list, i++, MELEE_SHOFIXTI); + MeleeTeam_setShip (*list, i++, MELEE_EARTHLING); + MeleeTeam_setShip (*list, i++, MELEE_KOHR_AH); + MeleeTeam_setShip (*list, i++, MELEE_MELNORME); + MeleeTeam_setShip (*list, i++, MELEE_DRUUGE); + MeleeTeam_setShip (*list, i++, MELEE_PKUNK); + MeleeTeam_setShip (*list, i++, MELEE_ORZ); list++; } { FleetShipIndex i = 0; - utf8StringCopy (list->TeamName, sizeof (list->TeamName), - "Ford's Fighters"); - list->ShipList[i++] = MELEE_CHMMR; - list->ShipList[i++] = MELEE_ZOQFOTPIK; - list->ShipList[i++] = MELEE_MELNORME; - list->ShipList[i++] = MELEE_SUPOX; - list->ShipList[i++] = MELEE_UTWIG; - list->ShipList[i++] = MELEE_UMGAH; + MeleeTeam_setName (*list, "Ford's Fighters"); + MeleeTeam_setShip (*list, i++, MELEE_CHMMR); + MeleeTeam_setShip (*list, i++, MELEE_ZOQFOTPIK); + MeleeTeam_setShip (*list, i++, MELEE_MELNORME); + MeleeTeam_setShip (*list, i++, MELEE_SUPOX); + MeleeTeam_setShip (*list, i++, MELEE_UTWIG); + MeleeTeam_setShip (*list, i++, MELEE_UMGAH); list++; } { FleetShipIndex i = 0; - utf8StringCopy (list->TeamName, sizeof (list->TeamName), - "Leyland's Lashers"); - list->ShipList[i++] = MELEE_ANDROSYNTH; - list->ShipList[i++] = MELEE_EARTHLING; - list->ShipList[i++] = MELEE_MYCON; - list->ShipList[i++] = MELEE_ORZ; - list->ShipList[i++] = MELEE_URQUAN; + MeleeTeam_setName (*list, "Leyland's Lashers"); + MeleeTeam_setShip (*list, i++, MELEE_ANDROSYNTH); + MeleeTeam_setShip (*list, i++, MELEE_EARTHLING); + MeleeTeam_setShip (*list, i++, MELEE_MYCON); + MeleeTeam_setShip (*list, i++, MELEE_ORZ); + MeleeTeam_setShip (*list, i++, MELEE_URQUAN); list++; } { FleetShipIndex i = 0; - utf8StringCopy (list->TeamName, sizeof (list->TeamName), - "The Gregorizers 200"); - list->ShipList[i++] = MELEE_ANDROSYNTH; - list->ShipList[i++] = MELEE_CHMMR; - list->ShipList[i++] = MELEE_DRUUGE; - list->ShipList[i++] = MELEE_MELNORME; - list->ShipList[i++] = MELEE_EARTHLING; - list->ShipList[i++] = MELEE_KOHR_AH; - list->ShipList[i++] = MELEE_SUPOX; - list->ShipList[i++] = MELEE_ORZ; - list->ShipList[i++] = MELEE_PKUNK; - list->ShipList[i++] = MELEE_SPATHI; + MeleeTeam_setName (*list, "The Gregorizers 200"); + MeleeTeam_setShip (*list, i++, MELEE_ANDROSYNTH); + MeleeTeam_setShip (*list, i++, MELEE_CHMMR); + MeleeTeam_setShip (*list, i++, MELEE_DRUUGE); + MeleeTeam_setShip (*list, i++, MELEE_MELNORME); + MeleeTeam_setShip (*list, i++, MELEE_EARTHLING); + MeleeTeam_setShip (*list, i++, MELEE_KOHR_AH); + MeleeTeam_setShip (*list, i++, MELEE_SUPOX); + MeleeTeam_setShip (*list, i++, MELEE_ORZ); + MeleeTeam_setShip (*list, i++, MELEE_PKUNK); + MeleeTeam_setShip (*list, i++, MELEE_SPATHI); list++; } { FleetShipIndex i = 0; - utf8StringCopy (list->TeamName, sizeof (list->TeamName), - "300 point Armada!"); - list->ShipList[i++] = MELEE_ANDROSYNTH; - list->ShipList[i++] = MELEE_CHMMR; - list->ShipList[i++] = MELEE_CHENJESU; - list->ShipList[i++] = MELEE_DRUUGE; - list->ShipList[i++] = MELEE_EARTHLING; - list->ShipList[i++] = MELEE_KOHR_AH; - list->ShipList[i++] = MELEE_MELNORME; - list->ShipList[i++] = MELEE_MYCON; - list->ShipList[i++] = MELEE_ORZ; - list->ShipList[i++] = MELEE_PKUNK; - list->ShipList[i++] = MELEE_SPATHI; - list->ShipList[i++] = MELEE_SUPOX; - list->ShipList[i++] = MELEE_URQUAN; - list->ShipList[i++] = MELEE_YEHAT; + MeleeTeam_setName (*list, "300 point Armada!"); + MeleeTeam_setShip (*list, i++, MELEE_ANDROSYNTH); + MeleeTeam_setShip (*list, i++, MELEE_CHMMR); + MeleeTeam_setShip (*list, i++, MELEE_CHENJESU); + MeleeTeam_setShip (*list, i++, MELEE_DRUUGE); + MeleeTeam_setShip (*list, i++, MELEE_EARTHLING); + MeleeTeam_setShip (*list, i++, MELEE_KOHR_AH); + MeleeTeam_setShip (*list, i++, MELEE_MELNORME); + MeleeTeam_setShip (*list, i++, MELEE_MYCON); + MeleeTeam_setShip (*list, i++, MELEE_ORZ); + MeleeTeam_setShip (*list, i++, MELEE_PKUNK); + MeleeTeam_setShip (*list, i++, MELEE_SPATHI); + MeleeTeam_setShip (*list, i++, MELEE_SUPOX); + MeleeTeam_setShip (*list, i++, MELEE_URQUAN); + MeleeTeam_setShip (*list, i++, MELEE_YEHAT); list++; } { FleetShipIndex i = 0; - utf8StringCopy (list->TeamName, sizeof (list->TeamName), - "Little Dudes with Attitudes"); - list->ShipList[i++] = MELEE_UMGAH; - list->ShipList[i++] = MELEE_THRADDASH; - list->ShipList[i++] = MELEE_SHOFIXTI; - list->ShipList[i++] = MELEE_EARTHLING; - list->ShipList[i++] = MELEE_VUX; - list->ShipList[i++] = MELEE_ZOQFOTPIK; + MeleeTeam_setName (*list, "Little Dudes with Attitudes"); + MeleeTeam_setShip (*list, i++, MELEE_UMGAH); + MeleeTeam_setShip (*list, i++, MELEE_THRADDASH); + MeleeTeam_setShip (*list, i++, MELEE_SHOFIXTI); + MeleeTeam_setShip (*list, i++, MELEE_EARTHLING); + MeleeTeam_setShip (*list, i++, MELEE_VUX); + MeleeTeam_setShip (*list, i++, MELEE_ZOQFOTPIK); list++; } { FleetShipIndex i = 0; - utf8StringCopy (list->TeamName, sizeof (list->TeamName), - "New Alliance Ships"); - list->ShipList[i++] = MELEE_ARILOU; - list->ShipList[i++] = MELEE_CHMMR; - list->ShipList[i++] = MELEE_EARTHLING; - list->ShipList[i++] = MELEE_ORZ; - list->ShipList[i++] = MELEE_PKUNK; - list->ShipList[i++] = MELEE_SHOFIXTI; - list->ShipList[i++] = MELEE_SUPOX; - list->ShipList[i++] = MELEE_SYREEN; - list->ShipList[i++] = MELEE_UTWIG; - list->ShipList[i++] = MELEE_ZOQFOTPIK; - list->ShipList[i++] = MELEE_YEHAT; - list->ShipList[i++] = MELEE_DRUUGE; - list->ShipList[i++] = MELEE_THRADDASH; - list->ShipList[i++] = MELEE_SPATHI; + MeleeTeam_setName (*list, "New Alliance Ships"); + MeleeTeam_setShip (*list, i++, MELEE_ARILOU); + MeleeTeam_setShip (*list, i++, MELEE_CHMMR); + MeleeTeam_setShip (*list, i++, MELEE_EARTHLING); + MeleeTeam_setShip (*list, i++, MELEE_ORZ); + MeleeTeam_setShip (*list, i++, MELEE_PKUNK); + MeleeTeam_setShip (*list, i++, MELEE_SHOFIXTI); + MeleeTeam_setShip (*list, i++, MELEE_SUPOX); + MeleeTeam_setShip (*list, i++, MELEE_SYREEN); + MeleeTeam_setShip (*list, i++, MELEE_UTWIG); + MeleeTeam_setShip (*list, i++, MELEE_ZOQFOTPIK); + MeleeTeam_setShip (*list, i++, MELEE_YEHAT); + MeleeTeam_setShip (*list, i++, MELEE_DRUUGE); + MeleeTeam_setShip (*list, i++, MELEE_THRADDASH); + MeleeTeam_setShip (*list, i++, MELEE_SPATHI); list++; } { FleetShipIndex i = 0; - utf8StringCopy (list->TeamName, sizeof (list->TeamName), - "Old Alliance Ships"); - list->ShipList[i++] = MELEE_ARILOU; - list->ShipList[i++] = MELEE_CHENJESU; - list->ShipList[i++] = MELEE_EARTHLING; - list->ShipList[i++] = MELEE_MMRNMHRM; - list->ShipList[i++] = MELEE_SHOFIXTI; - list->ShipList[i++] = MELEE_SYREEN; - list->ShipList[i++] = MELEE_YEHAT; + MeleeTeam_setName (*list, "Old Alliance Ships"); + MeleeTeam_setShip (*list, i++, MELEE_ARILOU); + MeleeTeam_setShip (*list, i++, MELEE_CHENJESU); + MeleeTeam_setShip (*list, i++, MELEE_EARTHLING); + MeleeTeam_setShip (*list, i++, MELEE_MMRNMHRM); + MeleeTeam_setShip (*list, i++, MELEE_SHOFIXTI); + MeleeTeam_setShip (*list, i++, MELEE_SYREEN); + MeleeTeam_setShip (*list, i++, MELEE_YEHAT); list++; } { FleetShipIndex i = 0; - utf8StringCopy (list->TeamName, sizeof (list->TeamName), - "Old Hierarchy Ships"); - list->ShipList[i++] = MELEE_ANDROSYNTH; - list->ShipList[i++] = MELEE_ILWRATH; - list->ShipList[i++] = MELEE_MYCON; - list->ShipList[i++] = MELEE_SPATHI; - list->ShipList[i++] = MELEE_UMGAH; - list->ShipList[i++] = MELEE_URQUAN; - list->ShipList[i++] = MELEE_VUX; + MeleeTeam_setName (*list, "Old Hierarchy Ships"); + MeleeTeam_setShip (*list, i++, MELEE_ANDROSYNTH); + MeleeTeam_setShip (*list, i++, MELEE_ILWRATH); + MeleeTeam_setShip (*list, i++, MELEE_MYCON); + MeleeTeam_setShip (*list, i++, MELEE_SPATHI); + MeleeTeam_setShip (*list, i++, MELEE_UMGAH); + MeleeTeam_setShip (*list, i++, MELEE_URQUAN); + MeleeTeam_setShip (*list, i++, MELEE_VUX); list++; } { FleetShipIndex i = 0; - utf8StringCopy (list->TeamName, sizeof (list->TeamName), - "Star Control 1"); - list->ShipList[i++] = MELEE_ANDROSYNTH; - list->ShipList[i++] = MELEE_ARILOU; - list->ShipList[i++] = MELEE_CHENJESU; - list->ShipList[i++] = MELEE_EARTHLING; - list->ShipList[i++] = MELEE_ILWRATH; - list->ShipList[i++] = MELEE_MMRNMHRM; - list->ShipList[i++] = MELEE_MYCON; - list->ShipList[i++] = MELEE_SHOFIXTI; - list->ShipList[i++] = MELEE_SPATHI; - list->ShipList[i++] = MELEE_SYREEN; - list->ShipList[i++] = MELEE_UMGAH; - list->ShipList[i++] = MELEE_URQUAN; - list->ShipList[i++] = MELEE_VUX; - list->ShipList[i++] = MELEE_YEHAT; + MeleeTeam_setName (*list, "Star Control 1"); + MeleeTeam_setShip (*list, i++, MELEE_ANDROSYNTH); + MeleeTeam_setShip (*list, i++, MELEE_ARILOU); + MeleeTeam_setShip (*list, i++, MELEE_CHENJESU); + MeleeTeam_setShip (*list, i++, MELEE_EARTHLING); + MeleeTeam_setShip (*list, i++, MELEE_ILWRATH); + MeleeTeam_setShip (*list, i++, MELEE_MMRNMHRM); + MeleeTeam_setShip (*list, i++, MELEE_MYCON); + MeleeTeam_setShip (*list, i++, MELEE_SHOFIXTI); + MeleeTeam_setShip (*list, i++, MELEE_SPATHI); + MeleeTeam_setShip (*list, i++, MELEE_SYREEN); + MeleeTeam_setShip (*list, i++, MELEE_UMGAH); + MeleeTeam_setShip (*list, i++, MELEE_URQUAN); + MeleeTeam_setShip (*list, i++, MELEE_VUX); + MeleeTeam_setShip (*list, i++, MELEE_YEHAT); list++; } { FleetShipIndex i = 0; - utf8StringCopy (list->TeamName, sizeof (list->TeamName), - "Star Control 2"); - list->ShipList[i++] = MELEE_CHMMR; - list->ShipList[i++] = MELEE_DRUUGE; - list->ShipList[i++] = MELEE_KOHR_AH; - list->ShipList[i++] = MELEE_MELNORME; - list->ShipList[i++] = MELEE_ORZ; - list->ShipList[i++] = MELEE_PKUNK; - list->ShipList[i++] = MELEE_SLYLANDRO; - list->ShipList[i++] = MELEE_SUPOX; - list->ShipList[i++] = MELEE_THRADDASH; - list->ShipList[i++] = MELEE_UTWIG; - list->ShipList[i++] = MELEE_ZOQFOTPIK; - list->ShipList[i++] = MELEE_ZOQFOTPIK; - list->ShipList[i++] = MELEE_ZOQFOTPIK; - list->ShipList[i++] = MELEE_ZOQFOTPIK; + MeleeTeam_setName (*list, "Star Control 2"); + MeleeTeam_setShip (*list, i++, MELEE_CHMMR); + MeleeTeam_setShip (*list, i++, MELEE_DRUUGE); + MeleeTeam_setShip (*list, i++, MELEE_KOHR_AH); + MeleeTeam_setShip (*list, i++, MELEE_MELNORME); + MeleeTeam_setShip (*list, i++, MELEE_ORZ); + MeleeTeam_setShip (*list, i++, MELEE_PKUNK); + MeleeTeam_setShip (*list, i++, MELEE_SLYLANDRO); + MeleeTeam_setShip (*list, i++, MELEE_SUPOX); + MeleeTeam_setShip (*list, i++, MELEE_THRADDASH); + MeleeTeam_setShip (*list, i++, MELEE_UTWIG); + MeleeTeam_setShip (*list, i++, MELEE_ZOQFOTPIK); + MeleeTeam_setShip (*list, i++, MELEE_ZOQFOTPIK); + MeleeTeam_setShip (*list, i++, MELEE_ZOQFOTPIK); + MeleeTeam_setShip (*list, i++, MELEE_ZOQFOTPIK); list++; } @@ -844,21 +785,47 @@ InitPreBuilt (MELEE_STATE *pMS) } static void -UninitPreBuilt (MELEE_STATE *pMS) { +UninitPreBuilt (MELEE_STATE *pMS) +{ + size_t fleetI; + for (fleetI = 0; fleetI < pMS->load.preBuiltCount; fleetI++) + MeleeTeam_delete (pMS->load.preBuiltList[fleetI]); HFree (pMS->load.preBuiltList); pMS->load.preBuiltCount = 0; } +static void +InitLoadView (MELEE_STATE *pMS) +{ + size_t viewI; + MeleeTeam **view = pMS->load.view; + + for (viewI = 0; viewI < LOAD_TEAM_VIEW_SIZE; viewI++) + view[viewI] = MeleeTeam_new (); +} + +static void +UninitLoadView (MELEE_STATE *pMS) +{ + size_t viewI; + MeleeTeam **view = pMS->load.view; + + for (viewI = 0; viewI < LOAD_TEAM_VIEW_SIZE; viewI++) + MeleeTeam_delete(view[viewI]); +} + void InitMeleeLoadState (MELEE_STATE *pMS) { pMS->load.entryIndices = NULL; InitPreBuilt (pMS); + InitLoadView (pMS); } void UninitMeleeLoadState (MELEE_STATE *pMS) { + UninitLoadView (pMS); UninitPreBuilt (pMS); if (pMS->load.entryIndices != NULL) HFree (pMS->load.entryIndices); diff --git a/sc2/src/uqm/supermelee/loadmele.h b/sc2/src/uqm/supermelee/loadmele.h index 333c74b8e..993c56940 100644 --- a/sc2/src/uqm/supermelee/loadmele.h +++ b/sc2/src/uqm/supermelee/loadmele.h @@ -24,17 +24,18 @@ struct melee_load_state; #include "melee.h" +#include "meleesetup.h" struct melee_load_state { - TEAM_IMAGE *preBuiltList; + MeleeTeam **preBuiltList; COUNT preBuiltCount; DIRENTRY dirEntries; COUNT *entryIndices; COUNT numIndices; - TEAM_IMAGE view[LOAD_TEAM_VIEW_SIZE]; + MeleeTeam *view[LOAD_TEAM_VIEW_SIZE]; COUNT top; // Index of the first entry for the view. COUNT bot; @@ -51,8 +52,8 @@ void UninitMeleeLoadState (MELEE_STATE *pMS); BOOLEAN DoLoadTeam (MELEE_STATE *pMS); BOOLEAN DoSaveTeam (MELEE_STATE *pMS); -bool ReadTeamImage (TEAM_IMAGE *pTI, uio_Stream *load_fp); -int WriteTeamImage (TEAM_IMAGE *pTI, uio_Stream *save_fp); +bool ReadTeamImage (MeleeTeam *pTI, uio_Stream *load_fp); +int WriteTeamImage (const MeleeTeam *pTI, uio_Stream *save_fp); void LoadTeamList (MELEE_STATE *pMS); #endif /* _LOADMELE_H */ diff --git a/sc2/src/uqm/supermelee/melee.c b/sc2/src/uqm/supermelee/melee.c index 59f541932..6ae002568 100644 --- a/sc2/src/uqm/supermelee/melee.c +++ b/sc2/src/uqm/supermelee/melee.c @@ -18,15 +18,18 @@ #include "melee.h" +#include "options.h" +#include "buildpick.h" +#include "meleeship.h" +#include "../battle.h" #include "../build.h" #include "../status.h" #include "../colors.h" #include "../comm.h" - // for getLineWithinWidth + // for getLineWithinWidth() #include "../cons_res.h" + // for load_gravity_well() and free_gravity_well() #include "../controls.h" -#include "libs/file.h" -#include "../fmv.h" #include "../gamestr.h" #include "../globdata.h" #include "../intel.h" @@ -36,33 +39,36 @@ # include "../netplay/netconnection.h" # include "../netplay/netmelee.h" # include "../netplay/notify.h" +# include "../netplay/notifyall.h" # include "libs/graphics/widgets.h" + // for DrawShadowedBox() # include "../cnctdlg.h" + // for MeleeConnectDialog() #endif -#include "../../options.h" -#include "../races.h" #include "../resinst.h" #include "../settings.h" #include "../setup.h" #include "../sounds.h" #include "../util.h" + // for DrawStarConBox() #include "../planets/planets.h" // for NUMBER_OF_PLANET_TYPES -#include "libs/graphics/drawable.h" #include "libs/gfxlib.h" #include "libs/mathlib.h" + // for TFB_Random() +#include "libs/reslib.h" #include "libs/log.h" +#include "libs/uio.h" #include -#include #include -#include -static void DrawMeleeShipStrings (MELEE_STATE *pMS, BYTE NewStarShip); static void StartMelee (MELEE_STATE *pMS); +#ifdef NETPLAY static ssize_t numPlayersReady (void); +#endif /* NETPLAY */ enum { @@ -80,7 +86,8 @@ enum NET_BOT, #endif QUIT_BOT, - EDIT_MELEE + EDIT_MELEE, // Editing a fleet or the team name + BUILD_PICK // Selecting a ship to add to a fleet }; #ifdef NETPLAY @@ -96,9 +103,6 @@ enum #define MELEE_BOX_SPACE 1 #define MENU_X_OFFS 29 -#define NAME_AREA_HEIGHT 7 -#define MELEE_WIDTH 149 -#define MELEE_HEIGHT (48 + NAME_AREA_HEIGHT) #define INFO_ORIGIN_X 4 #define INFO_WIDTH 58 @@ -160,11 +164,6 @@ enum #define TEAM_NAME_EDIT_CURS_COLOR \ WHITE_COLOR -#define PICKSHIP_TEAM_NAME_TEXT_COLOR \ - BUILD_COLOR (MAKE_RGB15 (0x0A, 0x0A, 0x1F), 0x09) -#define PICKSHIP_TEAM_START_VALUE_COLOR \ - BUILD_COLOR (MAKE_RGB15 (0x04, 0x05, 0x1F), 0x4B) - #define SHIPBOX_TOPLEFT_COLOR_NORMAL \ BUILD_COLOR (MAKE_RGB15 (0x00, 0x00, 0x09), 0x56) #define SHIPBOX_BOTTOMRIGHT_COLOR_NORMAL \ @@ -183,16 +182,12 @@ enum BUILD_COLOR (MAKE_RGB15 (0x00, 0x14, 0x00), 0x02) -FRAME PickMeleeFrame; FRAME MeleeFrame; // Loaded from melee/melebkgd.ani -static FRAME BuildPickFrame; - // Constructed. MELEE_STATE *pMeleeState; BOOLEAN DoMelee (MELEE_STATE *pMS); static BOOLEAN DoEdit (MELEE_STATE *pMS); -static BOOLEAN DoPickShip (MELEE_STATE *pMS); static BOOLEAN DoConfirmSettings (MELEE_STATE *pMS); #define DTSHS_NORMAL 0 @@ -200,9 +195,13 @@ static BOOLEAN DoConfirmSettings (MELEE_STATE *pMS); #define DTSHS_SELECTED 2 #define DTSHS_REPAIR 4 #define DTSHS_BLOCKCUR 8 - static BOOLEAN DrawTeamString (MELEE_STATE *pMS, COUNT side, - COUNT HiLiteState); + COUNT HiLiteState, const char *str); + +static void Melee_UpdateView_fleetValue (MELEE_STATE *pMS, COUNT side); +static void Melee_UpdateView_ship (MELEE_STATE *pMS, COUNT side, + FleetShipIndex index); +static void Melee_UpdateView_teamName (MELEE_STATE *pMS, COUNT side); // These icons come from melee/melebkgd.ani @@ -217,19 +216,6 @@ DrawMeleeIcon (COUNT which_icon) DrawStamp (&s); } -static void -GetShipBox (RECT *pRect, COUNT side, COUNT row, COUNT col) -{ - pRect->corner.x = MELEE_X_OFFS - + (col * (MELEE_BOX_WIDTH + MELEE_BOX_SPACE)); - pRect->corner.y = MELEE_Y_OFFS - + (side * (MELEE_Y_OFFS + MELEE_BOX_SPACE - + (NUM_MELEE_ROWS * (MELEE_BOX_HEIGHT + MELEE_BOX_SPACE)))) - + (row * (MELEE_BOX_HEIGHT + MELEE_BOX_SPACE)); - pRect->extent.width = MELEE_BOX_WIDTH; - pRect->extent.height = MELEE_BOX_HEIGHT; -} - static FleetShipIndex GetShipIndex (BYTE row, BYTE col) { @@ -248,10 +234,28 @@ GetShipColumn (int index) return index % NUM_MELEE_COLUMNS; } +// Get the rectangle containing the ship slot for the specified side, row, +// and column. +void +GetShipBox (RECT *pRect, COUNT side, COUNT row, COUNT col) +{ + pRect->corner.x = MELEE_X_OFFS + + (col * (MELEE_BOX_WIDTH + MELEE_BOX_SPACE)); + pRect->corner.y = MELEE_Y_OFFS + + (side * (MELEE_Y_OFFS + MELEE_BOX_SPACE + + (NUM_MELEE_ROWS * (MELEE_BOX_HEIGHT + MELEE_BOX_SPACE)))) + + (row * (MELEE_BOX_HEIGHT + MELEE_BOX_SPACE)); + pRect->extent.width = MELEE_BOX_WIDTH; + pRect->extent.height = MELEE_BOX_HEIGHT; +} + +// The caller must hold the GraphicsLock. static void -DrawShipBox (COUNT side, COUNT row, COUNT col, BYTE ship, BOOLEAN HiLite) +DrawShipBox (COUNT side, FleetShipIndex index, MeleeShip ship, BOOLEAN HiLite) { RECT r; + BYTE row = GetShipRow (index); + BYTE col = GetShipColumn (index); GetShipBox (&r, side, row, col); @@ -281,12 +285,24 @@ DrawShipBox (COUNT side, COUNT row, COUNT col, BYTE ship, BOOLEAN HiLite) UnbatchGraphics (); } +// The caller must hold the GraphicsLock. +static void +ClearShipBox (COUNT side, FleetShipIndex index) +{ + RECT rect; + BYTE row = GetShipRow (index); + BYTE col = GetShipColumn (index); + + GetShipBox (&rect, side, row, col); + RepairMeleeFrame (&rect); +} + static void DrawShipBoxCurrent (MELEE_STATE *pMS, BOOLEAN HiLite) { - FleetShipIndex index = GetShipIndex (pMS->row, pMS->col); - BYTE ship = pMS->SideState[pMS->side].TeamImage.ShipList[index]; - DrawShipBox (pMS->side, pMS->row, pMS->col, ship, HiLite); + FleetShipIndex slotI = GetShipIndex (pMS->row, pMS->col); + MeleeShip ship = MeleeSetup_getShip (pMS->meleeSetup, pMS->side, slotI); + DrawShipBox (pMS->side, slotI, ship, HiLite); } // Draw an image for one of the control method selection buttons. @@ -329,36 +345,29 @@ DrawControls (COUNT which_side, BOOLEAN HiLite) } static void -DrawPickFrame (MELEE_STATE *pMS) +DrawTeams (void) { - RECT r, r0, r1, ship_r; - STAMP s; - - GetShipBox (&r0, 0, 0, 0), - GetShipBox (&r1, 1, NUM_MELEE_ROWS - 1, NUM_MELEE_COLUMNS - 1), - BoxUnion (&r0, &r1, &ship_r); + COUNT side; - s.frame = SetAbsFrameIndex (BuildPickFrame, 0); - GetFrameRect (s.frame, &r); - r.corner.x = -(ship_r.corner.x - + ((ship_r.extent.width - r.extent.width) >> 1)); - if (pMS->side) - r.corner.y = -ship_r.corner.y; - else - r.corner.y = -(ship_r.corner.y - + (ship_r.extent.height - r.extent.height)); - SetFrameHot (s.frame, MAKE_HOT_SPOT (r.corner.x, r.corner.y)); - s.origin.x = 0; - s.origin.y = 0; - DrawStamp (&s); + for (side = 0; side < NUM_SIDES; side++) + { + FleetShipIndex index; - UnlockMutex (GraphicsLock); - DrawMeleeShipStrings (pMS, (BYTE)pMS->CurIndex); - LockMutex (GraphicsLock); + DrawControls (side, FALSE); + + for (index = 0; index < MELEE_FLEET_SIZE; index++) + { + MeleeShip ship = MeleeSetup_getShip(pMeleeState->meleeSetup, + side, index); + DrawShipBox (side, index, ship, FALSE); + } + + DrawTeamString (pMeleeState, side, DTSHS_NORMAL, NULL); + } } void -RepairMeleeFrame (RECT *pRect) +RepairMeleeFrame (const RECT *pRect) { RECT r; CONTEXT OldContext; @@ -388,30 +397,10 @@ RepairMeleeFrame (RECT *pRect) DrawMeleeIcon (37); /* "Net..." (bottom, not highlighted) */ #endif DrawMeleeIcon (26); /* "Battle!" (highlighted) */ - { - COUNT side; - COUNT row; - COUNT col; - - for (side = 0; side < NUM_SIDES; side++) - { - DrawControls (side, FALSE); - for (row = 0; row < NUM_MELEE_ROWS; row++) - { - for (col = 0; col < NUM_MELEE_COLUMNS; col++) - { - FleetShipIndex index = GetShipIndex (row, col); - BYTE ship = pMeleeState->SideState[side].TeamImage. - ShipList[index]; - DrawShipBox (side, row, col, ship, FALSE); - } - } - DrawTeamString (pMeleeState, side, DTSHS_NORMAL); - } - } - - if (pMeleeState->InputFunc == DoPickShip) + DrawTeams (); + + if (pMeleeState->MeleeOption == BUILD_PICK) DrawPickFrame (pMeleeState); UnbatchGraphics (); @@ -433,8 +422,10 @@ RedrawMeleeFrame (void) RepairMeleeFrame (&r); } +// If teamName == NULL, the team name is taken from pMS->meleeSetup static BOOLEAN -DrawTeamString (MELEE_STATE *pMS, COUNT side, COUNT HiLiteState) +DrawTeamString (MELEE_STATE *pMS, COUNT side, COUNT HiLiteState, + const char *teamName) { RECT r; TEXT lfText; @@ -447,12 +438,13 @@ DrawTeamString (MELEE_STATE *pMS, COUNT side, COUNT HiLiteState) if (HiLiteState == DTSHS_REPAIR) { RepairMeleeFrame (&r); - return (TRUE); + return TRUE; } SetContextFont (MicroFont); - lfText.pStr = pMS->SideState[side].TeamImage.TeamName; + lfText.pStr = (teamName != NULL) ? teamName : + MeleeSetup_getTeamName (pMS->meleeSetup, side); lfText.baseline.y = r.corner.y + r.extent.height - 3; lfText.baseline.x = r.corner.x + 1; @@ -465,7 +457,7 @@ DrawTeamString (MELEE_STATE *pMS, COUNT side, COUNT HiLiteState) TEXT rtText; UNICODE buf[30]; - sprintf (buf, "%u", pMS->SideState[side].star_bucks); + sprintf (buf, "%u", MeleeSetup_getFleetValue (pMS->meleeSetup, side)); rtText.pStr = buf; rtText.align = ALIGN_RIGHT; rtText.CharCount = (COUNT)~0; @@ -493,7 +485,7 @@ DrawTeamString (MELEE_STATE *pMS, COUNT side, COUNT HiLiteState) // will not fit when displayed later UnbatchGraphics (); // disallow the change - return (FALSE); + return FALSE; } text_r = r; @@ -537,33 +529,7 @@ DrawTeamString (MELEE_STATE *pMS, COUNT side, COUNT HiLiteState) } UnbatchGraphics (); - return (TRUE); -} - -// Draw a ship icon in the ship selection popup. -static void -DrawPickIcon (COUNT iship, BYTE DrawErase) -{ - STAMP s; - RECT r; - - GetFrameRect (BuildPickFrame, &r); - - s.origin.x = r.corner.x + 20 + (iship % NUM_PICK_COLS) * 18; - s.origin.y = r.corner.y + 5 + (iship / NUM_PICK_COLS) * 18; - s.frame = GetShipIconsFromIndex (iship); - if (DrawErase) - { // draw icon - DrawStamp (&s); - } - else - { // erase icon - Color OldColor; - - OldColor = SetContextForeGroundColor (BLACK_COLOR); - DrawFilledStamp (&s); - SetContextForeGroundColor (OldColor); - } + return TRUE; } #ifdef NETPLAY @@ -741,15 +707,17 @@ Deselect (BYTE opt) { if (pMeleeState->row < NUM_MELEE_ROWS) DrawShipBoxCurrent (pMeleeState, FALSE); - else if (pMeleeState->CurIndex == (BYTE)~0) + else if (pMeleeState->CurIndex == MELEE_STATE_INDEX_DONE) + { + // Not currently editing the team name. DrawTeamString (pMeleeState, pMeleeState->side, - DTSHS_NORMAL); - } - else if (pMeleeState->InputFunc == DoPickShip) - { - DrawPickIcon (pMeleeState->CurIndex, 1); + DTSHS_NORMAL, NULL); + } } break; + case BUILD_PICK: + DrawPickIcon (pMeleeState->currentShip, true); + break; } } @@ -791,7 +759,7 @@ Select (BYTE opt) { COUNT which_side; - which_side = opt == CONTROLS_TOP ? 1 : 0; + which_side = (opt == CONTROLS_TOP) ? 1 : 0; DrawControls (which_side, TRUE); break; } @@ -800,18 +768,22 @@ Select (BYTE opt) { if (pMeleeState->row < NUM_MELEE_ROWS) DrawShipBoxCurrent (pMeleeState, TRUE); - else if (pMeleeState->CurIndex == (BYTE)~0) + else if (pMeleeState->CurIndex == MELEE_STATE_INDEX_DONE) + { + // Not currently editing the team name. DrawTeamString (pMeleeState, pMeleeState->side, - DTSHS_SELECTED); + DTSHS_SELECTED, NULL); + } } - else if (pMeleeState->InputFunc == DoPickShip) - DrawPickIcon (pMeleeState->CurIndex, 0); + break; + case BUILD_PICK: + DrawPickIcon (pMeleeState->currentShip, false); break; } } -static void -flashSelection (MELEE_STATE *pMS) +void +Melee_flashSelection (MELEE_STATE *pMS) { #define FLASH_RATE (ONE_SECOND / 9) static TimeCount NextTime = 0; @@ -823,7 +795,7 @@ flashSelection (MELEE_STATE *pMS) CONTEXT OldContext; NextTime = Now + FLASH_RATE; - select ^= true; + select = !select; LockMutex (GraphicsLock); OldContext = SetContext (SpaceContext); @@ -858,14 +830,13 @@ InitMelee (MELEE_STATE *pMS) (void) pMS; } -static void -DrawMeleeShipStrings (MELEE_STATE *pMS, BYTE NewStarShip) +// Pre: The caller holds the GraphicsLock. +void +DrawMeleeShipStrings (MELEE_STATE *pMS, MeleeShip NewStarShip) { RECT r, OldRect; CONTEXT OldContext; - LockMutex (GraphicsLock); - OldContext = SetContext (StatusContext); GetContextClipRect (&OldRect); r = OldRect; @@ -893,6 +864,7 @@ DrawMeleeShipStrings (MELEE_STATE *pMS, BYTE NewStarShip) t.align = ALIGN_CENTER; if (pMS->row < NUM_MELEE_ROWS) { + // A ship is selected (or an empty fleet position). t.pStr = GAME_STRING (MELEE_STRING_BASE + 0); // "Empty" t.CharCount = (COUNT)~0; font_DrawText (&t); @@ -900,6 +872,7 @@ DrawMeleeShipStrings (MELEE_STATE *pMS, BYTE NewStarShip) } else { + // The team name is selected. t.pStr = GAME_STRING (MELEE_STRING_BASE + 2); // "Team" t.CharCount = (COUNT)~0; font_DrawText (&t); @@ -925,25 +898,33 @@ DrawMeleeShipStrings (MELEE_STATE *pMS, BYTE NewStarShip) UnbatchGraphics (); SetContextClipRect (&OldRect); SetContext (OldContext); - - UnlockMutex (GraphicsLock); } +// Set the currently displayed ship to the ship for the slot indicated by +// pMS->row and pMS->col. static void UpdateCurrentShip (MELEE_STATE *pMS) { - FleetShipIndex fleetShipIndex = GetShipIndex (pMS->row, pMS->col); if (pMS->row == NUM_MELEE_ROWS) - pMS->CurIndex = MELEE_NONE; + { + // The team name is selected. + pMS->currentShip = MELEE_NONE; + } else - pMS->CurIndex = - pMS->SideState[pMS->side].TeamImage.ShipList[fleetShipIndex]; - DrawMeleeShipStrings (pMS, (BYTE)(pMS->CurIndex)); + { + FleetShipIndex slotNr = GetShipIndex (pMS->row, pMS->col); + pMS->currentShip = + MeleeSetup_getShip (pMS->meleeSetup, pMS->side, slotNr); + } + + LockMutex (GraphicsLock); + DrawMeleeShipStrings (pMS, pMS->currentShip); + UnlockMutex (GraphicsLock); } // returns (COUNT) ~0 for an invalid ship. -static COUNT -GetShipValue (BYTE StarShip) +COUNT +GetShipValue (MeleeShip StarShip) { COUNT val; @@ -957,43 +938,23 @@ GetShipValue (BYTE StarShip) return val; } -COUNT -GetTeamValue (TEAM_IMAGE *pTI) -{ - FleetShipIndex index; - COUNT val; - - val = 0; - for (index = 0; index < MELEE_FLEET_SIZE; index++) - { - BYTE StarShip = pTI->ShipList[index]; - COUNT shipVal = GetShipValue (StarShip); - if (shipVal == (COUNT)~0) - pTI->ShipList[index] = MELEE_NONE; - val += shipVal; - } - - return val; -} - static void DeleteCurrentShip (MELEE_STATE *pMS) { - RECT r; - FleetShipIndex fleetShipIndex; - int CurIndex; + FleetShipIndex slotI = GetShipIndex (pMS->row, pMS->col); + Melee_Change_ship (pMS, pMS->side, slotI, MELEE_NONE); +} - fleetShipIndex = GetShipIndex (pMS->row, pMS->col); - CurIndex = pMS->SideState[pMS->side].TeamImage.ShipList[fleetShipIndex]; - pMS->SideState[pMS->side].star_bucks -= GetShipCostFromIndex (CurIndex); - pMS->SideState[pMS->side].TeamImage.ShipList[fleetShipIndex] = MELEE_NONE; +static bool +isShipSlotSelected (MELEE_STATE *pMS, COUNT side, FleetShipIndex index) +{ + if (pMS->MeleeOption != EDIT_MELEE) + return false; - LockMutex (GraphicsLock); - GetShipBox (&r, pMS->side, pMS->row, pMS->col); - RepairMeleeFrame (&r); + if (pMS->side != side) + return false; - DrawTeamString (pMS, pMS->side, DTSHS_REPAIR); - UnlockMutex (GraphicsLock); + return (index == GetShipIndex (pMS->row, pMS->col)); } static void @@ -1025,12 +986,46 @@ OnTeamNameChange (TEXTENTRY_STATE *pTES) hl |= DTSHS_BLOCKCUR; LockMutex (GraphicsLock); - ret = DrawTeamString (pMS, pMS->side, hl); + ret = DrawTeamString (pMS, pMS->side, hl, pTES->BaseStr); UnlockMutex (GraphicsLock); return ret; } +static void +BuildPickShipPopup (MELEE_STATE *pMS) +{ + bool buildOk; + + pMS->MeleeOption = BUILD_PICK; + + buildOk = BuildPickShip (pMS); + if (buildOk) + { + // A ship has been selected. + // Add the currently selected ship to the fleet. + FleetShipIndex index = GetShipIndex (pMS->row, pMS->col); + Melee_Change_ship (pMS, pMS->side, index, pMS->currentShip); + AdvanceCursor (pMS); + } + + pMS->MeleeOption = EDIT_MELEE; + // Must set this before the call to RepairMeleeFrame(), so that + // it will not redraw the BuildPickFrame. + + { + RECT r; + + GetBuildPickFrameRect (&r); + LockMutex (GraphicsLock); + RepairMeleeFrame (&r); + UnlockMutex (GraphicsLock); + } + + UpdateCurrentShip (pMS); + pMS->InputFunc = DoEdit; +} + static BOOLEAN DoEdit (MELEE_STATE *pMS) { @@ -1040,16 +1035,12 @@ DoEdit (MELEE_STATE *pMS) GamePaused = FALSE; if (GLOBAL (CurrentActivity) & CHECK_ABORT) - return (FALSE); + return FALSE; SetMenuSounds (MENU_SOUND_ARROWS, MENU_SOUND_SELECT | MENU_SOUND_DELETE); if (!pMS->Initialized) { - FleetShipIndex fleetShipIndex = GetShipIndex (pMS->row, pMS->col); - pMS->CurIndex = - pMS->SideState[pMS->side].TeamImage.ShipList[fleetShipIndex]; - DrawMeleeShipStrings (pMS, (BYTE)pMS->CurIndex); - + UpdateCurrentShip (pMS); pMS->Initialized = TRUE; pMS->InputFunc = DoEdit; return TRUE; @@ -1058,7 +1049,7 @@ DoEdit (MELEE_STATE *pMS) #ifdef NETPLAY netInput (); #endif - if ((pMS->row < NUM_MELEE_ROWS || pMS->CurIndex == (BYTE)~0) + if ((pMS->row < NUM_MELEE_ROWS || pMS->currentShip == MELEE_NONE) && (PulsedInputState.menu[KEY_MENU_CANCEL] || (PulsedInputState.menu[KEY_MENU_RIGHT] && (pMS->col == NUM_MELEE_COLUMNS - 1 @@ -1067,7 +1058,7 @@ DoEdit (MELEE_STATE *pMS) // Done editing the teams. LockMutex (GraphicsLock); Deselect (EDIT_MELEE); - pMS->CurIndex = (COUNT)~0; + pMS->currentShip = MELEE_NONE; pMS->MeleeOption = START_MELEE; pMS->InputFunc = DoMelee; UnlockMutex (GraphicsLock); @@ -1077,9 +1068,8 @@ DoEdit (MELEE_STATE *pMS) && PulsedInputState.menu[KEY_MENU_SELECT]) { // Show a popup to add a new ship to the current team. - pMS->Initialized = 0; - FlushInput (); - DoPickShip (pMS); + Deselect (EDIT_MELEE); + BuildPickShipPopup (pMS); } else if (pMS->row < NUM_MELEE_ROWS && PulsedInputState.menu[KEY_MENU_SPECIAL]) @@ -1087,9 +1077,9 @@ DoEdit (MELEE_STATE *pMS) // TODO: this is a stub; Should we display a ship spin? LockMutex (GraphicsLock); Deselect (EDIT_MELEE); - if (pMS->CurIndex != (BYTE)~0) + if (pMS->currentShip != MELEE_NONE) { - // Do something with pMS->CurIndex here + // Do something with pMS->currentShip here } UnlockMutex (GraphicsLock); } @@ -1097,20 +1087,16 @@ DoEdit (MELEE_STATE *pMS) PulsedInputState.menu[KEY_MENU_DELETE]) { // Remove the currently selected ship from the current team. - FleetShipIndex fleetShipIndex; + Deselect (EDIT_MELEE); DeleteCurrentShip (pMS); - fleetShipIndex = GetShipIndex (pMS->row, pMS->col); - fleetShipChanged (pMS, pMS->side, fleetShipIndex); AdvanceCursor (pMS); UpdateCurrentShip (pMS); } else { - COUNT side, row, col; - - side = pMS->side; - row = pMS->row; - col = pMS->col; + COUNT side = pMS->side; + COUNT row = pMS->row; + COUNT col = pMS->col; if (row == NUM_MELEE_ROWS) { @@ -1118,17 +1104,20 @@ DoEdit (MELEE_STATE *pMS) if (PulsedInputState.menu[KEY_MENU_SELECT]) { TEXTENTRY_STATE tes; + char buf[MAX_TEAM_CHARS + 1]; // going to enter text - // XXX: CurIndex is abused here; DrawTeamString expects - // CurIndex to contain the current cursor position pMS->CurIndex = 0; LockMutex (GraphicsLock); - DrawTeamString (pMS, pMS->side, DTSHS_EDIT); + DrawTeamString (pMS, pMS->side, DTSHS_EDIT, NULL); UnlockMutex (GraphicsLock); + strncpy (buf, MeleeSetup_getTeamName ( + pMS->meleeSetup, pMS->side), MAX_TEAM_CHARS); + buf[MAX_TEAM_CHARS] = '\0'; + tes.Initialized = FALSE; - tes.BaseStr = pMS->SideState[pMS->side].TeamImage.TeamName; + tes.BaseStr = buf; tes.CursorPos = 0; tes.MaxSize = MAX_TEAM_CHARS + 1; tes.CbParam = pMS; @@ -1137,14 +1126,15 @@ DoEdit (MELEE_STATE *pMS) DoTextEntry (&tes); // done entering - pMS->CurIndex = (BYTE)~0; - LockMutex (GraphicsLock); - DrawTeamString (pMS, pMS->side, DTSHS_REPAIR); - UnlockMutex (GraphicsLock); - - teamStringChanged (pMS, pMS->side); + pMS->CurIndex = MELEE_STATE_INDEX_DONE; + if (!Melee_Change_teamName (pMS, pMS->side, buf)) { + // The team name was not changed, so it was not redrawn. + // However, because we now leave edit mode, we still + // need to redraw. + Melee_UpdateView_teamName (pMS, pMS->side); + } - return (TRUE); + return TRUE; } } @@ -1205,133 +1195,14 @@ DoEdit (MELEE_STATE *pMS) flushPacketQueues (); #endif - flashSelection (pMS); + Melee_flashSelection (pMS); SleepThreadUntil (TimeIn + ONE_SECOND / 30); - return (TRUE); -} - -// Handle the popup from which a ship to add to the fleet can be chosen. -static BOOLEAN -DoPickShip (MELEE_STATE *pMS) -{ - DWORD TimeIn = GetTimeCounter (); - - /* Cancel any presses of the Pause key. */ - GamePaused = FALSE; - - if (GLOBAL (CurrentActivity) & CHECK_ABORT) - return (FALSE); - - SetMenuSounds (MENU_SOUND_ARROWS, MENU_SOUND_SELECT); - - if (!pMS->Initialized) - { - if (pMS->CurIndex == (BYTE)~0) - pMS->CurIndex = 0; - - LockMutex (GraphicsLock); - Deselect (EDIT_MELEE); - pMS->InputFunc = DoPickShip; - DrawPickFrame (pMS); - pMS->Initialized = TRUE; - UnlockMutex (GraphicsLock); - } - else if (PulsedInputState.menu[KEY_MENU_SELECT] || - PulsedInputState.menu[KEY_MENU_CANCEL]) - { - FleetShipIndex index = GetShipIndex (pMS->row, pMS->col); - pMS->InputFunc = 0; /* disable ship flashing */ - - if (!PulsedInputState.menu[KEY_MENU_CANCEL]) - { - // Add the currently selected ship to the fleet. - pMS->SideState[pMS->side].star_bucks += - GetShipCostFromIndex (pMS->CurIndex); - pMS->SideState[pMS->side].TeamImage.ShipList[index] = - pMS->CurIndex; - LockMutex (GraphicsLock); - DrawTeamString (pMS, pMS->side, DTSHS_REPAIR); - DrawShipBoxCurrent (pMS, FALSE); - UnlockMutex (GraphicsLock); - AdvanceCursor (pMS); - } - - { - RECT r; - - GetFrameRect (BuildPickFrame, &r); - LockMutex (GraphicsLock); - RepairMeleeFrame (&r); - UnlockMutex (GraphicsLock); - } - - fleetShipChanged (pMS, pMS->side, index); - UpdateCurrentShip (pMS); - - pMS->InputFunc = DoEdit; - - return (TRUE); - } - else if (PulsedInputState.menu[KEY_MENU_SPECIAL] - && (pMeleeState->CurIndex != (BYTE)~0)) - { - DoShipSpin (pMS->CurIndex, (MUSIC_REF)0); - - return (TRUE); - } - - { - BYTE NewStarShip; - - NewStarShip = pMS->CurIndex; - - if (PulsedInputState.menu[KEY_MENU_LEFT]) - { - if (NewStarShip % NUM_PICK_COLS == 0) - NewStarShip += NUM_PICK_COLS; - --NewStarShip; - } - else if (PulsedInputState.menu[KEY_MENU_RIGHT]) - { - ++NewStarShip; - if (NewStarShip % NUM_PICK_COLS == 0) - NewStarShip -= NUM_PICK_COLS; - } - - if (PulsedInputState.menu[KEY_MENU_UP]) - { - if (NewStarShip >= NUM_PICK_COLS) - NewStarShip -= NUM_PICK_COLS; - else - NewStarShip += NUM_PICK_COLS * (NUM_PICK_ROWS - 1); - } - else if (PulsedInputState.menu[KEY_MENU_DOWN]) - { - if (NewStarShip < NUM_PICK_COLS * (NUM_PICK_ROWS - 1)) - NewStarShip += NUM_PICK_COLS; - else - NewStarShip -= NUM_PICK_COLS * (NUM_PICK_ROWS - 1); - } - - if (NewStarShip != pMS->CurIndex) - { - LockMutex (GraphicsLock); - Deselect (EDIT_MELEE); - pMS->CurIndex = NewStarShip; - UnlockMutex (GraphicsLock); - DrawMeleeShipStrings (pMS, NewStarShip); - } - } - - flashSelection (pMS); - - SleepThreadUntil (TimeIn + ONE_SECOND / 30); - - return (TRUE); + return TRUE; } +#ifdef NETPLAY // Returns -1 if a connection has been aborted. static ssize_t numPlayersReady (void) @@ -1348,7 +1219,6 @@ numPlayersReady (void) continue; } -#ifdef NETPLAY { NetConnection *conn; @@ -1360,11 +1230,11 @@ numPlayersReady (void) if (NetConnection_getState (conn) > NetState_inSetup) numDone++; } -#endif } return numDone; } +#endif /* NETPLAY */ // The player has pressed "Start Game", and all Network players are // connected. We're now just waiting for the confirmation of the other @@ -1435,7 +1305,7 @@ DoConfirmSettings (MELEE_STATE *pMS) // All sides have confirmed. // Send our own prefered frame delay. - sendInputDelayConnections (netplayOptions.inputDelay); + Netplay_NotifyAll_inputDelay (netplayOptions.inputDelay); // Synchronise the RNGs: { @@ -1455,7 +1325,7 @@ DoConfirmSettings (MELEE_STATE *pMS) continue; if (NetConnection_getDiscriminant (conn)) - Netplay_seedRandom (conn, SeedRandomNumbers ()); + Netplay_Notify_seedRandom (conn, SeedRandomNumbers ()); } flushPacketQueues (); } @@ -1491,45 +1361,9 @@ DoConfirmSettings (MELEE_STATE *pMS) static void LoadMeleeInfo (MELEE_STATE *pMS) { - STAMP s; - CONTEXT OldContext; - RECT r; - COUNT i; - - // reverting to original behavior - OldContext = SetContext (OffScreenContext); - - if (PickMeleeFrame) - DestroyDrawable (ReleaseDrawable (PickMeleeFrame)); - PickMeleeFrame = CaptureDrawable (CreateDrawable ( - WANT_PIXMAP, MELEE_WIDTH, MELEE_HEIGHT, 2)); - s.origin.x = 0; - s.origin.y = 0; - s.frame = CaptureDrawable (LoadGraphic (MELEE_PICK_MASK_PMAP_ANIM)); - SetContextFGFrame (PickMeleeFrame); - DrawStamp (&s); - - s.frame = IncFrameIndex (s.frame); - SetContextFGFrame (IncFrameIndex (PickMeleeFrame)); - DrawStamp (&s); - DestroyDrawable (ReleaseDrawable (s.frame)); - + BuildPickMeleeFrame (); MeleeFrame = CaptureDrawable (LoadGraphic (MELEE_SCREEN_PMAP_ANIM)); - - // create team building ship selection box - s.frame = SetAbsFrameIndex (MeleeFrame, 27); - // 5x5 grid of ships to pick from - GetFrameRect (s.frame, &r); - BuildPickFrame = CaptureDrawable (CreateDrawable ( - WANT_PIXMAP, r.extent.width, r.extent.height, 1)); - SetContextFGFrame (BuildPickFrame); - SetFrameHot (s.frame, MAKE_HOT_SPOT (0, 0)); - DrawStamp (&s); - - for (i = 0; i < NUM_PICK_COLS * NUM_PICK_ROWS; ++i) - DrawPickIcon (i, 1); - - SetContext (OldContext); + BuildBuildPickFrame (); InitSpace (); @@ -1549,11 +1383,11 @@ FreeMeleeInfo (MELEE_STATE *pMS) } UninitSpace (); - + + DestroyPickMeleeFrame (); DestroyDrawable (ReleaseDrawable (MeleeFrame)); MeleeFrame = 0; - DestroyDrawable (ReleaseDrawable (BuildPickFrame)); - BuildPickFrame = 0; + DestroyBuildPickFrame (); #ifdef NETPLAY closeAllConnections (); @@ -1563,114 +1397,9 @@ FreeMeleeInfo (MELEE_STATE *pMS) static void BuildAndDrawShipList (MELEE_STATE *pMS) { - COUNT i; - CONTEXT OldContext; - - OldContext = SetContext (OffScreenContext); - - for (i = 0; i < NUM_SIDES; ++i) - { - COUNT side; - RECT r; - TEXT t; - STAMP s; - UNICODE buf[30]; - FleetShipIndex index; - - side = !i; - - s.frame = SetAbsFrameIndex (PickMeleeFrame, side); - SetContextFGFrame (s.frame); - - GetFrameRect (s.frame, &r); - t.baseline.x = r.extent.width >> 1; - t.baseline.y = r.extent.height - NAME_AREA_HEIGHT + 4; - - r.corner.x += 2; - r.corner.y += 2; - r.extent.width -= (2 * 2) + (ICON_WIDTH + 2) + 1; - r.extent.height -= (2 * 2) + NAME_AREA_HEIGHT; - SetContextForeGroundColor (PICK_BG_COLOR); - DrawFilledRectangle (&r); - - r.corner.x += 2; - r.extent.width += (ICON_WIDTH + 2) - (2 * 2); - r.corner.y += r.extent.height; - r.extent.height = NAME_AREA_HEIGHT; - DrawFilledRectangle (&r); - - // Team name at the bottom of the frame: - t.align = ALIGN_CENTER; - t.pStr = pMS->SideState[i].TeamImage.TeamName; - t.CharCount = (COUNT)~0; - SetContextFont (TinyFont); - SetContextForeGroundColor (PICKSHIP_TEAM_NAME_TEXT_COLOR); - font_DrawText (&t); - - // Total team value of the starting team: - sprintf (buf, "%u", pMS->SideState[i].star_bucks); - t.baseline.x = 4; - t.baseline.y = 7; - t.align = ALIGN_LEFT; - t.pStr = buf; - t.CharCount = (COUNT)~0; - SetContextForeGroundColor (PICKSHIP_TEAM_START_VALUE_COLOR); - font_DrawText (&t); - - assert (CountLinks (&race_q[side]) == 0); - - for (index = 0; index < MELEE_FLEET_SIZE; index++) - { - BYTE StarShip; - - StarShip = pMS->SideState[i].TeamImage.ShipList[index]; - if (StarShip == MELEE_NONE) - continue; - - { - BYTE row, col; - BYTE ship_cost; - HMASTERSHIP hMasterShip; - HSTARSHIP hBuiltShip; - MASTER_SHIP_INFO *MasterPtr; - STARSHIP *BuiltShipPtr; - BYTE captains_name_index; - - hMasterShip = GetStarShipFromIndex (&master_q, StarShip); - MasterPtr = LockMasterShip (&master_q, hMasterShip); - - captains_name_index = NameCaptain (&race_q[side], - MasterPtr->SpeciesID); - hBuiltShip = Build (&race_q[side], MasterPtr->SpeciesID); - - // Draw the icon. - row = GetShipRow (index); - col = GetShipColumn (index); - s.origin.x = 4 + ((ICON_WIDTH + 2) * col); - s.origin.y = 10 + ((ICON_HEIGHT + 2) * row); - s.frame = MasterPtr->ShipInfo.icons; - DrawStamp (&s); - - ship_cost = MasterPtr->ShipInfo.ship_cost; - UnlockMasterShip (&master_q, hMasterShip); - - BuiltShipPtr = LockStarShip (&race_q[side], hBuiltShip); - BuiltShipPtr->index = index; - BuiltShipPtr->ship_cost = ship_cost; - BuiltShipPtr->playerNr = side; - BuiltShipPtr->captains_name_index = captains_name_index; - // The next ones are not used in Melee - BuiltShipPtr->crew_level = 0; - BuiltShipPtr->max_crew = 0; - BuiltShipPtr->race_strings = 0; - BuiltShipPtr->icons = 0; - BuiltShipPtr->RaceDescPtr = 0; - UnlockStarShip (&race_q[side], hBuiltShip); - } - } - } - - SetContext (OldContext); + FillPickMeleeFrame (pMS->meleeSetup); + // XXX TODO: This also builds the race_q for each player. + // This should be split off. } static void @@ -1722,8 +1451,9 @@ StartMelee (MELEE_STATE *pMS) static void StartMeleeButtonPressed (MELEE_STATE *pMS) { - if (pMS->SideState[0].star_bucks == 0 || - pMS->SideState[1].star_bucks == 0) + // Either fleet must at least have one ship. + if (MeleeSetup_getFleetValue (pMS->meleeSetup, 0) == 0 || + MeleeSetup_getFleetValue (pMS->meleeSetup, 1) == 0) { PlayMenuSound (MENU_SOUND_FAILURE); return; @@ -1824,7 +1554,7 @@ DoConnectingDialog (MELEE_STATE *pMS) GamePaused = FALSE; if (GLOBAL (CurrentActivity) & CHECK_ABORT) - return (FALSE); + return FALSE; SetMenuSounds (MENU_SOUND_NONE, MENU_SOUND_NONE); if (!pMS->Initialized) @@ -1928,12 +1658,11 @@ DoConnectingDialog (MELEE_STATE *pMS) return TRUE; } -/* Check for disconnections, and revert to human control if so */ +/* Check for disconnects, and revert to human control if there is one */ static void -check_for_disconnections (MELEE_STATE *pMS) +check_for_disconnects (MELEE_STATE *pMS) { COUNT player; - bool changed = FALSE; for (player = 0; player < NUM_PLAYERS; player++) { @@ -1949,7 +1678,6 @@ check_for_disconnections (MELEE_STATE *pMS) DrawControls (player, FALSE); log_add (log_User, "Player %d has disconnected; shifting " "controls\n", player); - changed = TRUE; } } @@ -1964,16 +1692,16 @@ nextControlType (COUNT which_side) switch (PlayerControl[which_side]) { case HUMAN_CONTROL | STANDARD_RATING: - PlayerControl[which_side] = COMPUTER_CONTROL | STANDARD_RATING; + PlayerControl[which_side] = COMPUTER_CONTROL | STANDARD_RATING; break; case COMPUTER_CONTROL | STANDARD_RATING: - PlayerControl[which_side] = COMPUTER_CONTROL | GOOD_RATING; + PlayerControl[which_side] = COMPUTER_CONTROL | GOOD_RATING; break; case COMPUTER_CONTROL | GOOD_RATING: - PlayerControl[which_side] = COMPUTER_CONTROL | AWESOME_RATING; + PlayerControl[which_side] = COMPUTER_CONTROL | AWESOME_RATING; break; case COMPUTER_CONTROL | AWESOME_RATING: - PlayerControl[which_side] = HUMAN_CONTROL | STANDARD_RATING; + PlayerControl[which_side] = HUMAN_CONTROL | STANDARD_RATING; break; #ifdef NETPLAY @@ -2026,7 +1754,7 @@ MeleeOptionSelect (MELEE_STATE *pMS) case SAVE_TOP: case SAVE_BOT: pMS->side = pMS->MeleeOption == SAVE_TOP ? 0 : 1; - if (pMS->SideState[pMS->side].star_bucks) + if (MeleeSetup_getFleetValue (pMS->meleeSetup, pMS->side) > 0) DoSaveTeam (pMS); else PlayMenuSound (MENU_SOUND_FAILURE); @@ -2073,7 +1801,7 @@ DoMelee (MELEE_STATE *pMS) GamePaused = FALSE; if (GLOBAL (CurrentActivity) & CHECK_ABORT) - return (FALSE); + return FALSE; SetMenuSounds (MENU_SOUND_ARROWS, MENU_SOUND_SELECT); if (!pMS->Initialized) @@ -2178,45 +1906,52 @@ DoMelee (MELEE_STATE *pMS) { MeleeOptionSelect (pMS); if (GLOBAL (CurrentActivity) & CHECK_ABORT) - return (FALSE); + return FALSE; } } #ifdef NETPLAY flushPacketQueues (); - check_for_disconnections (pMS); + check_for_disconnects (pMS); #endif - flashSelection (pMS); + Melee_flashSelection (pMS); SleepThreadUntil (TimeIn + ONE_SECOND / 30); - return (TRUE); + return TRUE; } int LoadMeleeConfig (MELEE_STATE *pMS) { - uio_Stream *load_fp; + uio_Stream *stream; int status; COUNT side; - load_fp = res_OpenResFile (configDir, "melee.cfg", "rb"); - if (!load_fp) + stream = uio_fopen (configDir, "melee.cfg", "rb"); + if (stream == NULL) goto err; + + { + struct stat sb; - if (LengthResFile (load_fp) != (1 + sizeof (TEAM_IMAGE)) * NUM_SIDES) - goto err; + if (uio_fstat(uio_streamHandle(stream), &sb) == -1) + goto err; + if ((size_t) sb.st_size != (1 + MeleeTeam_size) * NUM_SIDES) + goto err; + } for (side = 0; side < NUM_SIDES; side++) { - status = GetResFileChar (load_fp); - if (status == -1) + status = uio_getc (stream); + if (status == EOF) goto err; - PlayerControl[side] = (BYTE)status; + PlayerControl[side] = (BYTE) status; + // XXX: insert sanity check on PlanetControl here. - if (!ReadTeamImage (&pMS->SideState[side].TeamImage, load_fp)) + if (MeleeSetup_deserializeTeam (pMS->meleeSetup, side, stream) == -1) goto err; /* Do not allow netplay mode at the start. */ @@ -2224,43 +1959,43 @@ LoadMeleeConfig (MELEE_STATE *pMS) PlayerControl[side] = HUMAN_CONTROL | STANDARD_RATING; } - res_CloseResFile (load_fp); + uio_fclose (stream); return 0; err: - if (load_fp) - res_CloseResFile (load_fp); + if (stream) + uio_fclose (stream); return -1; } int WriteMeleeConfig (MELEE_STATE *pMS) { - uio_Stream *save_fp; + uio_Stream *stream; COUNT side; - save_fp = res_OpenResFile (configDir, "melee.cfg", "wb"); - if (!save_fp) + stream = res_OpenResFile (configDir, "melee.cfg", "wb"); + if (stream == NULL) goto err; for (side = 0; side < NUM_SIDES; side++) { - if (PutResFileChar (PlayerControl[side], save_fp) == -1) + if (uio_putc (PlayerControl[side], stream) == EOF) goto err; - if (WriteTeamImage (&pMS->SideState[side].TeamImage, save_fp) == 0) + if (MeleeSetup_serializeTeam (pMS->meleeSetup, side, stream) == -1) goto err; } - if (!res_CloseResFile (save_fp)) + if (!res_CloseResFile (stream)) goto err; return 0; err: - if (save_fp) + if (stream) { - res_CloseResFile (save_fp); + res_CloseResFile (stream); DeleteResFile (configDir, "melee.cfg"); } return -1; @@ -2279,10 +2014,12 @@ Melee (void) MenuState.InputFunc = DoMelee; MenuState.Initialized = FALSE; + MenuState.meleeSetup = MeleeSetup_new (); + MenuState.randomContext = RandomContext_New (); RandomContext_SeedRandom (MenuState.randomContext, GetTimeCounter ()); - // Using the current time still leave the random state a bit + // Using the current time still leaves the random state a bit // predictable, but it is good enough. #ifdef NETPLAY @@ -2293,7 +2030,8 @@ Melee (void) } #endif - MenuState.CurIndex = (COUNT)~0; + MenuState.currentShip = MELEE_NONE; + MenuState.CurIndex = MELEE_STATE_INDEX_DONE; InitMeleeLoadState (&MenuState); GLOBAL (CurrentActivity) = SUPER_MELEE; @@ -2303,20 +2041,12 @@ Melee (void) if (LoadMeleeConfig (&MenuState) == -1) { PlayerControl[0] = HUMAN_CONTROL | STANDARD_RATING; - MenuState.SideState[0].TeamImage = MenuState.load.preBuiltList[0]; + Melee_Change_team (&MenuState, 0, MenuState.load.preBuiltList[0]); PlayerControl[1] = COMPUTER_CONTROL | STANDARD_RATING; - MenuState.SideState[1].TeamImage = MenuState.load.preBuiltList[1]; + Melee_Change_team (&MenuState, 1, MenuState.load.preBuiltList[1]); } - teamStringChanged (&MenuState, 0); - teamStringChanged (&MenuState, 1); - entireFleetChanged (&MenuState, 0); - entireFleetChanged (&MenuState, 1); MenuState.side = 0; - MenuState.SideState[0].star_bucks = - GetTeamValue (&MenuState.SideState[0].TeamImage); - MenuState.SideState[1].star_bucks = - GetTeamValue (&MenuState.SideState[1].TeamImage); SetMenuSounds (MENU_SOUND_ARROWS, MENU_SOUND_SELECT); DoInput (&MenuState, TRUE); @@ -2328,194 +2058,17 @@ Melee (void) DestroySound (ReleaseSound (GameSounds)); GameSounds = 0; - DestroyDrawable (ReleaseDrawable (PickMeleeFrame)); - PickMeleeFrame = 0; - UninitMeleeLoadState (&MenuState); RandomContext_Delete (MenuState.randomContext); + + MeleeSetup_delete (MenuState.meleeSetup); FlushInput (); } } -// Notify the network connections of a team name change. -void -teamStringChanged (MELEE_STATE *pMS, int player) -{ #ifdef NETPLAY - const char *name; - size_t len; - size_t playerI; - - name = pMS->SideState[player].TeamImage.TeamName; - len = strlen (name); - for (playerI = 0; playerI < NUM_PLAYERS; playerI++) - { - NetConnection *conn = netConnections[playerI]; - - if (conn == NULL) - continue; - - if (!NetConnection_isConnected (conn)) - continue; - - if (NetConnection_getState (conn) != NetState_inSetup) - continue; - - Netplay_teamStringChanged (conn, player, name, len); - } -#else - (void) pMS; - (void) player; -#endif -} - -// Notify the network connections of the configuration of a fleet. -void -entireFleetChanged (MELEE_STATE *pMS, int player) -{ -#ifdef NETPLAY - size_t playerI; - for (playerI = 0; playerI < NUM_PLAYERS; playerI++) { - NetConnection *conn = netConnections[playerI]; - - if (conn == NULL) - continue; - - if (!NetConnection_isConnected (conn)) - continue; - - if (NetConnection_getState (conn) != NetState_inSetup) - continue; - - Netplay_entireFleetChanged (conn, player, - pMS->SideState[player].TeamImage.ShipList, MELEE_FLEET_SIZE); - } -#else - (void) player; -#endif - (void) pMS; -} - -// Notify the network of a change in the configuration of a fleet. -void -fleetShipChanged (MELEE_STATE *pMS, int player, size_t index) -{ -#ifdef NETPLAY - size_t playerI; - for (playerI = 0; playerI < NUM_PLAYERS; playerI++) - { - NetConnection *conn = netConnections[playerI]; - - if (conn == NULL) - continue; - - if (!NetConnection_isConnected (conn)) - continue; - - if (NetConnection_getState (conn) != NetState_inSetup) - continue; - - Netplay_fleetShipChanged (conn, player, index, - pMS->SideState[player].TeamImage.ShipList[index]); - } -#else - (void) player; - (void) index; -#endif - (void) pMS; -} - -#ifdef NETPLAY -// NB: 'len' does not include the terminating 0. -// 'len' counts in bytes, not in characters. -void -updateTeamName (MELEE_STATE *pMS, COUNT side, const char *name, - size_t len) -{ - // NB: MAX_TEAM_CHARS is the maximum number of characters, - // without the terminating '\0'. - if (len > MAX_TEAM_CHARS) - len = MAX_TEAM_CHARS; - - // TeamName has space for at least MAX_TEAM_CHARS + 1 bytes. - strncpy (pMS->SideState[side].TeamImage.TeamName, name, len); - pMS->SideState[side].TeamImage.TeamName[len] = '\0'; - - LockMutex (GraphicsLock); -#if 0 /* DTSHS_REPAIR does not combine with other options */ - if (pMS->MeleeOption == EDIT_MELEE && pMS->side == side - && pMS->row == NUM_MELEE_ROWS) - DrawTeamString (pMS, side, DTSHS_REPAIR | DTSHS_SELECTED); - else -#endif - DrawTeamString (pMS, side, DTSHS_REPAIR); - UnlockMutex (GraphicsLock); -} - -// Update a ship in a fleet as specified by a remote party. -bool -updateFleetShip (MELEE_STATE *pMS, COUNT side, COUNT index, BYTE ship) -{ - BYTE row = GetShipRow (index); - BYTE col = GetShipColumn (index); - COUNT val; - - FleetShipIndex selectedShipIndex; - BOOLEAN isSelected; - - if (ship >= NUM_MELEE_SHIPS && ship != MELEE_NONE) { - log_add (log_Warning, "Invalid ship type number %d (max = %d).\n", - ship, NUM_MELEE_SHIPS - 1); - return false; - } - - if (index >= MELEE_FLEET_SIZE) - { - log_add (log_Warning, "Invalid ship position number %d (max = %d).\n", - index, MELEE_FLEET_SIZE - 1); - return false; - } - - val = GetShipValue (ship); - if (val == (COUNT) ~0) - return false; - - pMS->SideState[side].star_bucks -= - GetShipValue (pMS->SideState[side].TeamImage.ShipList[index]); - pMS->SideState[side].star_bucks += val; - - pMS->SideState[side].TeamImage.ShipList[index] = ship; - - selectedShipIndex = GetShipIndex (pMS->row, pMS->col); - isSelected = (pMS->MeleeOption == EDIT_MELEE) && - (pMS->side == side) && (index == selectedShipIndex); - // Ship to be updated is the currently selected one. - - LockMutex (GraphicsLock); - if (ship == MELEE_NONE) - { - RECT r; - GetShipBox (&r, side, row, col); - RepairMeleeFrame (&r); - } else - DrawShipBox (side, row, col, ship, isSelected); - - if (isSelected) - { - pMS->CurIndex = ship; - DrawMeleeShipStrings (pMS, ship); - } - - // Reprint the team value: - //DrawTeamString (pMeleeState, side, DTSHS_NORMAL); - DrawTeamString (pMS, side, DTSHS_REPAIR); - UnlockMutex (GraphicsLock); - - return true; -} - void updateRandomSeed (MELEE_STATE *pMS, COUNT side, DWORD seed) { @@ -2679,3 +2232,222 @@ closeFeedback (NetConnection *conn) #endif /* NETPLAY */ + +/////////////////////////////////////////////////////////////////////////// + +// Melee_UpdateView_xxx() functions are called when some value in the +// supermelee fleet setup screen needs to be updated visually. + +static void +Melee_UpdateView_fleetValue (MELEE_STATE *pMS, COUNT side) +{ + LockMutex (GraphicsLock); + DrawTeamString (pMS, side, DTSHS_REPAIR, NULL); + UnlockMutex (GraphicsLock); +} + +static void +Melee_UpdateView_ship (MELEE_STATE *pMS, COUNT side, FleetShipIndex index) +{ + MeleeShip ship = MeleeSetup_getShip (pMS->meleeSetup, side, index); + + LockMutex (GraphicsLock); + if (ship == MELEE_NONE) + { + ClearShipBox (side, index); + } + else + { + DrawShipBox (side, index, ship, FALSE); + } + UnlockMutex (GraphicsLock); +} + +static void +Melee_UpdateView_teamName (MELEE_STATE *pMS, COUNT side) +{ + LockMutex (GraphicsLock); + DrawTeamString (pMS, side, DTSHS_REPAIR, NULL); + UnlockMutex (GraphicsLock); +} + +/////////////////////////////////////////////////////////////////////////// + +// Melee_Change_xxx() functions are called when some value in the supermelee +// fleet setup screen has changed, eithed locally, or remotely. + +bool +Melee_Change_ship (MELEE_STATE *pMS, COUNT side, FleetShipIndex index, + MeleeShip ship) +{ + if (!MeleeSetup_setShip (pMS->meleeSetup, side, index, ship)) + { + // No change. + return false; + } + + // Update the view + Melee_UpdateView_ship (pMS, side, index); + Melee_UpdateView_fleetValue (pMS, side); + + // If the modified slot is currently selected, display the new ship icon + // on the right of the screen. + if (isShipSlotSelected (pMS, side, index)) + { + pMS->currentShip = ship; + LockMutex (GraphicsLock); + DrawMeleeShipStrings (pMS, ship); + UnlockMutex (GraphicsLock); + } + +#ifdef NETPLAY + // Notify network connections of the change. + Netplay_NotifyAll_setShip (pMS, side, index); +#endif /* NETPLAY */ + + return true; +} + +// Pre: 'name' is '\0'-terminated +bool +Melee_Change_teamName (MELEE_STATE *pMS, COUNT side, const char *name) +{ + MeleeSetup *setup = pMS->meleeSetup; + + if (!MeleeSetup_setTeamName (setup, side, name)) + { + // No change. + return false; + } + + if (pMS->row != NUM_MELEE_ROWS || pMS->side != side || + pMeleeState->CurIndex == MELEE_STATE_INDEX_DONE) + { + // The team name is not currently being edited, so we can + // update it on screen. If it was edited, then this function + // will be called again after it is done. + Melee_UpdateView_teamName (pMS, side); + } + +#ifdef NETPLAY + Netplay_NotifyAll_setTeamName (pMS, side); +#endif /* NETPLAY */ + + return true; +} + +bool +Melee_Change_fleet (MELEE_STATE *pMS, size_t teamNr, const MeleeShip *fleet) +{ + MeleeSetup *setup = pMS->meleeSetup; + FleetShipIndex slotI; + bool changed = false; + + for (slotI = 0; slotI < MELEE_FLEET_SIZE; slotI++) { + if (MeleeSetup_setShip (setup, teamNr, slotI, fleet[slotI])) + changed = true; + } + return changed; +} + +bool +Melee_Change_team (MELEE_STATE *pMS, size_t teamNr, const MeleeTeam *team) +{ + MeleeSetup *setup = pMS->meleeSetup; + const MeleeShip *fleet = MeleeTeam_getFleet (team); + bool changed = false; + + if (Melee_Change_fleet (pMS, teamNr, fleet)) + changed = true; + if (MeleeSetup_setTeamName (setup, teamNr, MeleeTeam_getTeamName (team))) + changed = true; + + return changed; +} + +/////////////////////////////////////////////////////////////////////////// + +// Melee_RemoteChange_xxx() functions are called when some value in the +// supermelee fleet setup screen has changed remotely. + +#ifdef NETPLAY +void +Melee_RemoteChange_ship (MELEE_STATE *pMS, NetConnection *conn, COUNT side, + FleetShipIndex index, MeleeShip ship) +{ + MeleeSetup *setup = pMS->meleeSetup; + + MeleeShip currentShip = MeleeSetup_getShip (setup, side, index); + + if (ship == currentShip) + { + // The remote side has confirmed what we want the value to be. + // If we had made the same local change before, then an update + // has already been sent. If not, then there is nothing to change. + // Either way, we do not need to send an update. + MeleeSetup_setConfirmedShip (setup, side, index, ship); + } else { + // The remote side wants to make a change. + // We accept the change when we don't have any changes of our own, + // or when we do have changes, but we "lose" the tie break. + // If we "win" the tie break, we have already sent an update to the + // remote side when our local change was made, so we do not need to + // send anything. The remote side still needs to confirm this local + // change, of which it will become aware shortly, when the already + // sent update message arrives. + MeleeShip confirmedShip = MeleeSetup_getConfirmedShip (setup, side, + index); + if (currentShip == confirmedShip || + NetConnection_getDiscriminant(conn)) + { + MeleeSetup_setConfirmedShip (setup, side, index, ship); + Melee_Change_ship (pMS, side, index, ship); + // This will also cause a notification of the local + // change to be sent to the remote side, which will act + // as a confirmation. + } + } +} + +void +Melee_RemoteChange_teamName (MELEE_STATE *pMS, NetConnection *conn, COUNT side, + const char *name) +{ + MeleeSetup *setup = pMS->meleeSetup; + + const char *currentName = MeleeSetup_getTeamName (setup, side); + + if (strcmp (name, currentName) == 0) + { + // The remote side has confirmed what we want the value to be. + // If we had made the same local change before, then an update + // has already been sent. If not, then there is nothing to change. + // Either way, we do not need to send an update. + MeleeSetup_setConfirmedTeamName (setup, side, name); + } else { + // The remote side wants to make a change. + // We accept the change when we don't have any changes of our own, + // or when we do have changes, but we "lose" the tie break. + // If we "win" the tie break, we have already sent an update to the + // remote side when our local change was made, so we do not need to + // send anything. The remote side still needs to confirm this local + // change, of which it will become aware shortly, when the already + // sent update message arrives. + const char *confirmedName = + MeleeSetup_getConfirmedTeamName (setup, side); + if (strcmp (currentName, confirmedName) == 0 || + NetConnection_getDiscriminant(conn)) + { + MeleeSetup_setConfirmedTeamName (setup, side, name); + Melee_Change_teamName (pMS, side, name); + // This will also cause a notification of the local + // change to be sent to the remote side, which will act + // as a confirmation. + } + } +} + +/////////////////////////////////////////////////////////////////////////// + +#endif /* NETPLAY */ + diff --git a/sc2/src/uqm/supermelee/melee.h b/sc2/src/uqm/supermelee/melee.h index 52b3d1ca1..df08c230e 100644 --- a/sc2/src/uqm/supermelee/melee.h +++ b/sc2/src/uqm/supermelee/melee.h @@ -30,39 +30,6 @@ typedef struct melee_state MELEE_STATE; -enum -{ - MELEE_ANDROSYNTH, - MELEE_ARILOU, - MELEE_CHENJESU, - MELEE_CHMMR, - MELEE_DRUUGE, - MELEE_EARTHLING, - MELEE_ILWRATH, - MELEE_KOHR_AH, - MELEE_MELNORME, - MELEE_MMRNMHRM, - MELEE_MYCON, - MELEE_ORZ, - MELEE_PKUNK, - MELEE_SHOFIXTI, - MELEE_SLYLANDRO, - MELEE_SPATHI, - MELEE_SUPOX, - MELEE_SYREEN, - MELEE_THRADDASH, - MELEE_UMGAH, - MELEE_URQUAN, - MELEE_UTWIG, - MELEE_VUX, - MELEE_YEHAT, - MELEE_ZOQFOTPIK, - - NUM_MELEE_SHIPS, - - MELEE_NONE = (BYTE) ~0 -}; - #define NUM_MELEE_ROWS 2 #define NUM_MELEE_COLUMNS 7 //#define NUM_MELEE_COLUMNS 6 @@ -82,23 +49,10 @@ extern FRAME PickMeleeFrame; #define NUM_PICK_ROWS 5 typedef BYTE MELEE_OPTIONS; -typedef COUNT FleetShipIndex; - -typedef struct -{ - BYTE ShipList[MELEE_FLEET_SIZE]; - UNICODE TeamName[MAX_TEAM_CHARS + 1 + 24]; - /* The +1 is for the terminating \0; the +24 is in case some - * default name in starcon.txt is unknowingly mangled. */ -} TEAM_IMAGE; #include "loadmele.h" - -struct melee_side_state -{ - TEAM_IMAGE TeamImage; - COUNT star_bucks; -}; +#include "meleesetup.h" +#include "meleeship.h" struct melee_state { @@ -106,10 +60,24 @@ struct melee_state BOOLEAN Initialized; MELEE_OPTIONS MeleeOption; - COUNT side, row, col; - struct melee_side_state SideState[NUM_SIDES]; + COUNT side; + COUNT row; + COUNT col; + MeleeSetup *meleeSetup; struct melee_load_state load; + MeleeShip currentShip; + // The ship currently displayed. Not really needed. + // Also the current ship position when selecting a ship. COUNT CurIndex; +#define MELEE_STATE_INDEX_DONE ((COUNT) -1) + // Current position in the team string when editing it. + // Set to MELEE_STATE_INDEX_DONE when done. + BOOLEAN buildPickConfirmed; + // Used by DoPickShip () to communicate to the calling + // function BuildPickShip() whether a ship has been selected + // to add to the fleet, or whether the operation has been + // cancelled. If a ship was selected, it is set in + // currentShip. RandomContext *randomContext; /* RNG state for all local random decisions, i.e. those * decisions that are not shared among network parties. */ @@ -123,17 +91,14 @@ extern void Melee (void); // Some prototypes for use by loadmele.c: BOOLEAN DoMelee (MELEE_STATE *pMS); void DrawMeleeIcon (COUNT which_icon); -COUNT GetTeamValue (TEAM_IMAGE *pTI); -void RepairMeleeFrame (RECT *pRect); +void GetShipBox (RECT *pRect, COUNT side, COUNT row, COUNT col); +void RepairMeleeFrame (const RECT *pRect); +void DrawMeleeShipStrings (MELEE_STATE *pMS, MeleeShip NewStarShip); extern FRAME MeleeFrame; +void Melee_flashSelection (MELEE_STATE *pMS); -void teamStringChanged (MELEE_STATE *pMS, int player); -void entireFleetChanged (MELEE_STATE *pMS, int player); -void fleetShipChanged (MELEE_STATE *pMS, int player, size_t index); +COUNT GetShipValue (MeleeShip StarShip); -void updateTeamName (MELEE_STATE *pMS, COUNT side, const char *name, - size_t len); -bool updateFleetShip (MELEE_STATE *pMS, COUNT side, COUNT index, BYTE ship); void updateRandomSeed (MELEE_STATE *pMS, COUNT side, DWORD seed); void confirmationCancelled(MELEE_STATE *pMS, COUNT side); void connectedFeedback (NetConnection *conn); @@ -143,5 +108,18 @@ void resetFeedback (NetConnection *conn, NetplayResetReason reason, void errorFeedback (NetConnection *conn); void closeFeedback (NetConnection *conn); +bool Melee_Change_ship (MELEE_STATE *pMS, COUNT side, FleetShipIndex index, + MeleeShip ship); +bool Melee_Change_teamName (MELEE_STATE *pMS, COUNT side, const char *name); +bool Melee_Change_fleet (MELEE_STATE *pMS, size_t teamNr, + const MeleeShip *fleet); +bool Melee_Change_team (MELEE_STATE *pMS, size_t teamNr, + const MeleeTeam *team); + +void Melee_RemoteChange_ship (MELEE_STATE *pMS, NetConnection *conn, + COUNT side, FleetShipIndex index, MeleeShip ship); +void Melee_RemoteChange_teamName (MELEE_STATE *pMS, NetConnection *conn, + COUNT side, const char *name); + #endif /* _MELEE_H */ diff --git a/sc2/src/uqm/supermelee/meleesetup.c b/sc2/src/uqm/supermelee/meleesetup.c new file mode 100644 index 000000000..95bc08314 --- /dev/null +++ b/sc2/src/uqm/supermelee/meleesetup.c @@ -0,0 +1,325 @@ +/* + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#define MELEESETUP_INTERNAL +#include "port.h" +#include "meleesetup.h" + +#include "../master.h" +#include "libs/log.h" + + +/////////////////////////////////////////////////////////////////////////// + +// Temporary +const size_t MeleeTeam_size = sizeof (MeleeTeam); + +void +MeleeTeam_init (MeleeTeam *team) +{ + FleetShipIndex slotI; + + for (slotI = 0; slotI < MELEE_FLEET_SIZE; slotI++) + team->ships[slotI] = MELEE_NONE; +} + +void +MeleeTeam_uninit (MeleeTeam *team) +{ + (void) team; +} + +MeleeTeam * +MeleeTeam_new (void) +{ + MeleeTeam *result = HMalloc (sizeof (MeleeTeam)); + MeleeTeam_init (result); + return result; +} + +void +MeleeTeam_delete (MeleeTeam *team) +{ + MeleeTeam_uninit (team); + HFree (team); +} + +int +MeleeTeam_serialize (const MeleeTeam *team, uio_Stream *stream) +{ + FleetShipIndex slotI; + + for (slotI = 0; slotI < MELEE_FLEET_SIZE; slotI++) { + if (uio_putc ((int) team->ships[slotI], stream) == EOF) + return -1; + } + if (uio_fwrite ((char *) team->name, sizeof team->name, 1, stream) != 1) + return -1; + + return 0; +} + +int +MeleeTeam_deserialize (MeleeTeam *team, uio_Stream *stream) +{ + FleetShipIndex slotI; + + // Sanity check on the ships. + for (slotI = 0; slotI < MELEE_FLEET_SIZE; slotI++) + { + int ship = uio_getc (stream); + if (ship == EOF) + goto err; + team->ships[slotI] = (MeleeShip) ship; + + if (team->ships[slotI] == MELEE_NONE) + continue; + + if (team->ships[slotI] >= NUM_MELEE_SHIPS) + { + log_add (log_Warning, "Invalid ship type in loaded team (index " + "%d, ship type is %d, max valid is %d).", + slotI, team->ships[slotI], NUM_MELEE_SHIPS - 1); + team->ships[slotI] = MELEE_NONE; + } + } + + if (uio_fread (team->name, sizeof team->name, 1, stream) != 1) + goto err; + + team->name[MAX_TEAM_CHARS] = '\0'; + + return 0; + +err: + MeleeTeam_delete(team); + return -1; +} + +// XXX: move this to elsewhere? +COUNT +MeleeTeam_getValue (const MeleeTeam *team) +{ + COUNT total = 0; + FleetShipIndex slotI; + + for (slotI = 0; slotI < MELEE_FLEET_SIZE; slotI++) + { + MeleeShip ship = team->ships[slotI]; + COUNT shipValue = GetShipValue (ship); + if (shipValue == (COUNT)~0) + { + // Invalid ship. + continue; + } + total += shipValue; + } + + return total; +} + +MeleeShip +MeleeTeam_getShip (const MeleeTeam *team, FleetShipIndex slotNr) +{ + return team->ships[slotNr]; +} + +void +MeleeTeam_setShip (MeleeTeam *team, FleetShipIndex slotNr, MeleeShip ship) +{ + team->ships[slotNr] = ship; +} + +const MeleeShip * +MeleeTeam_getFleet (const MeleeTeam *team) +{ + return team->ships; +} + +const char * +MeleeTeam_getTeamName (const MeleeTeam *team) +{ + return team->name; +} + +// Returns true iff the state has actually changed. +void +MeleeTeam_setName (MeleeTeam *team, const UNICODE *name) +{ + strncpy (team->name, name, sizeof team->name - 1); + team->name[sizeof team->name - 1] = '\0'; +} + +void +MeleeTeam_copy (MeleeTeam *copy, const MeleeTeam *original) +{ + *copy = *original; +} + +/////////////////////////////////////////////////////////////////////////// + +MeleeSetup * +MeleeSetup_new (void) +{ + size_t teamI; + MeleeSetup *result = HMalloc (sizeof (MeleeSetup)); + if (result == NULL) + return NULL; + + for (teamI = 0; teamI < NUM_SIDES; teamI++) + { + MeleeTeam_init (&result->teams[teamI]); + result->fleetValue[teamI] = 0; +#ifdef NETPLAY + MeleeTeam_init (&result->confirmedTeams[teamI]); +#endif /* NETPLAY */ + } + return result; +} + +void +MeleeSetup_delete (MeleeSetup *setup) +{ + HFree (setup); +} + +// Returns true iff the state has actually changed. +bool +MeleeSetup_setShip (MeleeSetup *setup, size_t teamNr, FleetShipIndex slotNr, + MeleeShip ship) +{ + MeleeTeam *team = &setup->teams[teamNr]; + MeleeShip oldShip = MeleeTeam_getShip (team, slotNr); + + if (ship == oldShip) + return false; + + if (oldShip != MELEE_NONE) + setup->fleetValue[teamNr] -= GetShipCostFromIndex (oldShip); + + MeleeTeam_setShip (team, slotNr, ship); + + if (ship != MELEE_NONE) + setup->fleetValue[teamNr] += GetShipCostFromIndex (ship); + + return true; +} + +MeleeShip +MeleeSetup_getShip (const MeleeSetup *setup, size_t teamNr, + FleetShipIndex slotNr) +{ + return MeleeTeam_getShip (&setup->teams[teamNr], slotNr); +} + +const MeleeShip * +MeleeSetup_getFleet (const MeleeSetup *setup, size_t teamNr) +{ + return MeleeTeam_getFleet (&setup->teams[teamNr]); +} + +// Returns true iff the state has actually changed. +bool +MeleeSetup_setTeamName (MeleeSetup *setup, size_t teamNr, + const UNICODE *name) +{ + MeleeTeam *team = &setup->teams[teamNr]; + const UNICODE *oldName = MeleeTeam_getTeamName (team); + + if (strcmp (oldName, name) == 0) + return false; + + MeleeTeam_setName (team, name); + return true; +} + +const char * +MeleeSetup_getTeamName (const MeleeSetup *setup, size_t teamNr) +{ + return MeleeTeam_getTeamName (&setup->teams[teamNr]); +} + +COUNT +MeleeSetup_getFleetValue (const MeleeSetup *setup, size_t teamNr) +{ + return setup->fleetValue[teamNr]; +} + +int +MeleeSetup_deserializeTeam (MeleeSetup *setup, size_t teamNr, + uio_Stream *stream) +{ + MeleeTeam *team = &setup->teams[teamNr]; + return MeleeTeam_deserialize (team, stream); +} + +int +MeleeSetup_serializeTeam (const MeleeSetup *setup, size_t teamNr, + uio_Stream *stream) +{ + const MeleeTeam *team = &setup->teams[teamNr]; + return MeleeTeam_serialize (team, stream); +} + +#ifdef NETPLAY +MeleeShip +MeleeSetup_getConfirmedShip (const MeleeSetup *setup, size_t teamNr, + FleetShipIndex slotNr) +{ + return MeleeTeam_getShip (&setup->confirmedTeams[teamNr], slotNr); +} + +const char * +MeleeSetup_getConfirmedTeamName (const MeleeSetup *setup, size_t teamNr) +{ + return MeleeTeam_getTeamName (&setup->confirmedTeams[teamNr]); +} + +// Returns true iff the state has actually changed. +bool +MeleeSetup_setConfirmedShip (MeleeSetup *setup, size_t teamNr, + FleetShipIndex slotNr, MeleeShip ship) +{ + MeleeTeam *team = &setup->confirmedTeams[teamNr]; + MeleeShip oldShip = MeleeTeam_getShip (team, slotNr); + + if (ship == oldShip) + return false; + + MeleeTeam_setShip (team, slotNr, ship); + return true; +} + +// Returns true iff the state has actually changed. +bool +MeleeSetup_setConfirmedTeamName (MeleeSetup *setup, size_t teamNr, + const UNICODE *name) +{ + MeleeTeam *team = &setup->confirmedTeams[teamNr]; + const UNICODE *oldName = MeleeTeam_getTeamName (team); + + if (strcmp (oldName, name) == 0) + return false; + + MeleeTeam_setName (team, name); + return true; +} +#endif /* NETPLAY */ + + +/////////////////////////////////////////////////////////////////////////// + + diff --git a/sc2/src/uqm/supermelee/meleesetup.h b/sc2/src/uqm/supermelee/meleesetup.h new file mode 100644 index 000000000..6afa949f7 --- /dev/null +++ b/sc2/src/uqm/supermelee/meleesetup.h @@ -0,0 +1,144 @@ +/* + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef MELEESETUP_H +#define MELEESETUP_H + +typedef struct MeleeTeam MeleeTeam; +typedef struct MeleeSetup MeleeSetup; + +#ifdef MELEESETUP_INTERNAL +# define MELEETEAM_INTERNAL +#endif /* MELEESETUP_INTERNAL */ + +#include "libs/compiler.h" + +typedef COUNT FleetShipIndex; + +#include "libs/uio.h" +#include "melee.h" +#include "meleeship.h" + +#ifdef MELEETEAM_INTERNAL +struct MeleeTeam +{ + MeleeShip ships[MELEE_FLEET_SIZE]; + UNICODE name[MAX_TEAM_CHARS + 1 + 24]; + /* The +1 is for the terminating \0; the +24 is in case some + * default name in starcon.txt is unknowingly mangled. */ +}; +#endif /* MELEETEAM_INTERNAL */ + +#ifdef MELEESETUP_INTERNAL +// When Netplay is enabled, we keep two copies of the teams: the team as we +// consider it to be locally, and last confirmed team. +// There are no separate change and confirmation messages; a confirmation +// message is a message reporting a change to the value which was specified +// by the remote side. +// When a local change is made, the current team is updated, and a message +// is sent to the other side. +// When we receive a message of a remote update: +// - if the current value is the same as the received value, we change +// the confirmed value to the current/received value +// - if the current value is different from the received value, and +// the current value is the same as the confirmed value, we change both +// the current value and the confirmed value to the received value, +// and sent a message to the remote side of our modification. +// - if the current value is different from the received value, and +// the current value is not the same as the confirmed value, our +// action depends on who "owns" the value: +// - if the change is to the remote fleet, we change the current and +// confirmed value to the received value, and send a message to the +// remote side of our modification (as above) +// - if the change is to the local fleet, we take no action. +// (In this situation, a local change has been made, and a message of +// this has already been sent to the other side, and a confirmation +// from the other side will arrive eventually.) +// XXX: put this in docs/netplay/protocols. +// XXX: this not only works for teams, but also for other properties. +struct MeleeSetup +{ + MeleeTeam teams[NUM_SIDES]; + COUNT fleetValue[NUM_SIDES]; +#ifdef NETPLAY + MeleeTeam confirmedTeams[NUM_SIDES]; + // The least team which both sides agreed upon. + // XXX: this may actually be deallocated when the battle starts. +#endif +}; + +#endif /* MELEESETUP_INTERNAL */ + +extern const size_t MeleeTeam_size; + +void MeleeTeam_init (MeleeTeam *team); +void MeleeTeam_uninit (MeleeTeam *team); +MeleeTeam *MeleeTeam_new (void); +void MeleeTeam_delete (MeleeTeam *team); +int MeleeTeam_serialize (const MeleeTeam *team, uio_Stream *stream); +int MeleeTeam_deserialize (MeleeTeam *team, uio_Stream *stream); +COUNT MeleeTeam_getValue (const MeleeTeam *team); +MeleeShip MeleeTeam_getShip (const MeleeTeam *team, FleetShipIndex slotNr); +void MeleeTeam_setShip (MeleeTeam *team, FleetShipIndex slotNr, + MeleeShip ship); +const MeleeShip *MeleeTeam_getFleet (const MeleeTeam *team); +const char *MeleeTeam_getTeamName (const MeleeTeam *team); +void MeleeTeam_setName (MeleeTeam *team, const UNICODE *name); +void MeleeTeam_copy (MeleeTeam *copy, const MeleeTeam *original); + +#ifdef NETPLAY +MeleeShip MeleeSetup_getConfirmedShip (const MeleeSetup *setup, size_t teamNr, + FleetShipIndex slotNr); +const char *MeleeSetup_getConfirmedTeamName (const MeleeSetup *setup, + size_t teamNr); +bool MeleeSetup_setConfirmedShip (MeleeSetup *setup, size_t teamNr, + FleetShipIndex slotNr, MeleeShip ship); +bool MeleeSetup_setConfirmedTeamName (MeleeSetup *setup, size_t teamNr, + const UNICODE *name); +#endif /* NETPLAY */ + +MeleeSetup *MeleeSetup_new (void); +void MeleeSetup_delete (MeleeSetup *setup); + +bool MeleeSetup_setShip (MeleeSetup *setup, size_t teamNr, + FleetShipIndex slotNr, MeleeShip ship); +MeleeShip MeleeSetup_getShip (const MeleeSetup *setup, size_t teamNr, + FleetShipIndex slotNr); +bool MeleeSetup_setFleet (MeleeSetup *setup, size_t teamNr, + const MeleeShip *fleet); +const MeleeShip *MeleeSetup_getFleet (const MeleeSetup *setup, size_t teamNr); +bool MeleeSetup_setTeamName (MeleeSetup *setup, size_t teamNr, + const UNICODE *name); +const char *MeleeSetup_getTeamName (const MeleeSetup *setup, + size_t teamNr); +COUNT MeleeSetup_getFleetValue (const MeleeSetup *setup, size_t teamNr); +int MeleeSetup_deserializeTeam (MeleeSetup *setup, size_t teamNr, + uio_Stream *stream); +int MeleeSetup_serializeTeam (const MeleeSetup *setup, size_t teamNr, + uio_Stream *stream); + + +void MeleeState_setShip (MELEE_STATE *pMS, size_t teamNr, + FleetShipIndex slotNr, MeleeShip ship); +void MeleeState_setFleet (MELEE_STATE *pMS, size_t teamNr, + const MeleeShip *fleet); +void MeleeState_setTeamName (MELEE_STATE *pMS, size_t teamNr, + const UNICODE *name); +void MeleeState_setTeam (MELEE_STATE *pMS, size_t teamNr, + const MeleeTeam *team); + +#endif /* MELEESETUP_H */ + diff --git a/sc2/src/uqm/supermelee/meleeship.h b/sc2/src/uqm/supermelee/meleeship.h new file mode 100644 index 000000000..ce676b6be --- /dev/null +++ b/sc2/src/uqm/supermelee/meleeship.h @@ -0,0 +1,44 @@ +#ifndef MELEESHIP_H +#define MELEESHIP_H + +#include + +typedef enum MeleeShip { + MELEE_ANDROSYNTH, + MELEE_ARILOU, + MELEE_CHENJESU, + MELEE_CHMMR, + MELEE_DRUUGE, + MELEE_EARTHLING, + MELEE_ILWRATH, + MELEE_KOHR_AH, + MELEE_MELNORME, + MELEE_MMRNMHRM, + MELEE_MYCON, + MELEE_ORZ, + MELEE_PKUNK, + MELEE_SHOFIXTI, + MELEE_SLYLANDRO, + MELEE_SPATHI, + MELEE_SUPOX, + MELEE_SYREEN, + MELEE_THRADDASH, + MELEE_UMGAH, + MELEE_URQUAN, + MELEE_UTWIG, + MELEE_VUX, + MELEE_YEHAT, + MELEE_ZOQFOTPIK, + + MELEE_NONE = (BYTE) ~0 +} MeleeShip; +#define NUM_MELEE_SHIPS (MELEE_ZOQFOTPIK + 1) + +static inline bool +MeleeShip_valid (MeleeShip ship) +{ + return (ship < NUM_MELEE_SHIPS) || (ship == MELEE_NONE); +} + +#endif /* MELEESHIP_H */ + diff --git a/sc2/src/uqm/supermelee/pickmele.c b/sc2/src/uqm/supermelee/pickmele.c index 7bcfd4421..418311fe0 100644 --- a/sc2/src/uqm/supermelee/pickmele.c +++ b/sc2/src/uqm/supermelee/pickmele.c @@ -20,10 +20,14 @@ #include "pickmele.h" #include "../battlecontrols.h" +#include "../battle.h" +#include "../build.h" #include "../controls.h" #include "../flash.h" +#include "../igfxres.h" #include "../intel.h" -#include "../battle.h" +#include "../master.h" +#include "../nameref.h" #include "melee.h" #ifdef NETPLAY # include "../netplay/netmelee.h" @@ -37,15 +41,49 @@ #include "libs/mathlib.h" -#define NUM_MELEE_COLS_ORIG NUM_MELEE_COLUMNS +#define NUM_PICKMELEE_ROWS 2 +#define NUM_PICKMELEE_COLUMNS 7 + #define PICK_X_OFFS 57 #define PICK_Y_OFFS 24 #define PICK_SIDE_OFFS 100 +#define NAME_AREA_HEIGHT 7 +#define MELEE_WIDTH 149 +#define MELEE_HEIGHT (48 + NAME_AREA_HEIGHT) + +#define PICKSHIP_TEAM_NAME_TEXT_COLOR \ + BUILD_COLOR (MAKE_RGB15 (0x0A, 0x0A, 0x1F), 0x09) +#define PICKSHIP_TEAM_START_VALUE_COLOR \ + BUILD_COLOR (MAKE_RGB15 (0x04, 0x05, 0x1F), 0x4B) + + #ifdef NETPLAY static void reportShipSelected (GETMELEE_STATE *gms, COUNT index); #endif + +FRAME PickMeleeFrame; + + +static FleetShipIndex +PickMelee_GetShipIndex (BYTE row, BYTE col) +{ + return row * NUM_PICKMELEE_COLUMNS + col; +} + +static BYTE +PickMelee_GetShipRow (FleetShipIndex index) +{ + return index / NUM_PICKMELEE_COLUMNS; +} + +static BYTE +PickMelee_GetShipColumn (int index) +{ + return index % NUM_PICKMELEE_COLUMNS; +} + // Returns the th ship in the queue, or 0 if it is not available. static HSTARSHIP MeleeShipByQueueIndex (const QUEUE *queue, COUNT index) @@ -161,13 +199,13 @@ SelectShip_processInput (GETMELEE_STATE *gms, COUNT playerI, { if (inputState & BATTLE_WEAPON) { - if (gms->player[playerI].col == NUM_MELEE_COLS_ORIG && + if (gms->player[playerI].col == NUM_PICKMELEE_COLUMNS && gms->player[playerI].row == 0) { // Random ship (void) setShipSelected (gms, playerI, (COUNT) ~0, TRUE); } - else if (gms->player[playerI].col == NUM_MELEE_COLS_ORIG && + else if (gms->player[playerI].col == NUM_PICKMELEE_COLUMNS && gms->player[playerI].row == 1) { // Selected exit @@ -177,10 +215,9 @@ SelectShip_processInput (GETMELEE_STATE *gms, COUNT playerI, else { // Selection is on a ship slot. - COUNT shipI = - (gms->player[playerI].row * NUM_MELEE_COLS_ORIG) - + gms->player[playerI].col; - (void) setShipSelected (gms, playerI, shipI, TRUE); + COUNT slotNr = PickMelee_GetShipIndex (gms->player[playerI].row, + gms->player[playerI].col); + (void) setShipSelected (gms, playerI, slotNr, TRUE); // If the choice is not valid, setShipSelected() // will not set .done. } @@ -195,21 +232,21 @@ SelectShip_processInput (GETMELEE_STATE *gms, COUNT playerI, if (inputState & BATTLE_LEFT) { if (new_col-- == 0) - new_col = NUM_MELEE_COLS_ORIG; + new_col = NUM_PICKMELEE_COLUMNS; } else if (inputState & BATTLE_RIGHT) { - if (new_col++ == NUM_MELEE_COLS_ORIG) + if (new_col++ == NUM_PICKMELEE_COLUMNS) new_col = 0; } if (inputState & BATTLE_THRUST) { if (new_row-- == 0) - new_row = NUM_MELEE_ROWS - 1; + new_row = NUM_PICKMELEE_ROWS - 1; } else if (inputState & BATTLE_DOWN) { - if (++new_row == NUM_MELEE_ROWS) + if (++new_row == NUM_PICKMELEE_ROWS) new_row = 0; } @@ -384,17 +421,19 @@ GetRaceQueueValue (const QUEUE *queue) { // 'shipI' is the index in the ship list. // Pre: caller holds the graphics lock. static void -CrossOutShip (FRAME frame, COUNT shipI) +CrossOutShip (FRAME frame, COUNT shipNr) { CONTEXT OldContext; STAMP s; + BYTE row = PickMelee_GetShipRow (shipNr); + BYTE col = PickMelee_GetShipColumn (shipNr); OldContext = SetContext (OffScreenContext); SetContextFGFrame (frame); - s.origin.x = 3 + ((ICON_WIDTH + 2) * (shipI % NUM_MELEE_COLS_ORIG)); - s.origin.y = 9 + ((ICON_HEIGHT + 2) * (shipI / NUM_MELEE_COLS_ORIG)); + s.origin.x = 3 + ((ICON_WIDTH + 2) * col); + s.origin.y = 9 + ((ICON_HEIGHT + 2) * row); s.frame = SetAbsFrameIndex (StatusFrame, 3); // Cross for through the ship image. DrawStamp (&s); @@ -442,6 +481,158 @@ UpdatePickMeleeFleetValue (FRAME frame, COUNT which_player) SetContext (OldContext); } +// Create a frame for each player to display their current fleet in, +// to be used when selecting the next ship to fight with. +void +BuildPickMeleeFrame (void) +{ + STAMP s; + CONTEXT OldContext = SetContext (OffScreenContext); + + if (PickMeleeFrame) + DestroyDrawable (ReleaseDrawable (PickMeleeFrame)); + + PickMeleeFrame = CaptureDrawable (CreateDrawable ( + WANT_PIXMAP, MELEE_WIDTH, MELEE_HEIGHT, 2)); + s.origin.x = 0; + s.origin.y = 0; + + s.frame = CaptureDrawable (LoadGraphic (MELEE_PICK_MASK_PMAP_ANIM)); + SetContextFGFrame (PickMeleeFrame); + DrawStamp (&s); + + s.frame = IncFrameIndex (s.frame); + SetContextFGFrame (IncFrameIndex (PickMeleeFrame)); + DrawStamp (&s); + + DestroyDrawable (ReleaseDrawable (s.frame)); + + SetContext (OldContext); +} + +// Put the ship icons in the PickMeleeFrame, and create a queue +// for each player. +// XXX TODO: split off creating the queue into a separate function. +void +FillPickMeleeFrame (MeleeSetup *setup) +{ + COUNT sideI; + CONTEXT OldContext; + + OldContext = SetContext (OffScreenContext); + + for (sideI = 0; sideI < NUM_SIDES; ++sideI) + { + COUNT side; + RECT r; + TEXT t; + STAMP s; + UNICODE buf[30]; + FleetShipIndex index; + + side = !sideI; + + s.frame = SetAbsFrameIndex (PickMeleeFrame, side); + SetContextFGFrame (s.frame); + + GetFrameRect (s.frame, &r); + t.baseline.x = r.extent.width >> 1; + t.baseline.y = r.extent.height - NAME_AREA_HEIGHT + 4; + + r.corner.x += 2; + r.corner.y += 2; + r.extent.width -= (2 * 2) + (ICON_WIDTH + 2) + 1; + r.extent.height -= (2 * 2) + NAME_AREA_HEIGHT; + SetContextForeGroundColor (PICK_BG_COLOR); + DrawFilledRectangle (&r); + + r.corner.x += 2; + r.extent.width += (ICON_WIDTH + 2) - (2 * 2); + r.corner.y += r.extent.height; + r.extent.height = NAME_AREA_HEIGHT; + DrawFilledRectangle (&r); + + // Team name at the bottom of the frame: + t.align = ALIGN_CENTER; + t.pStr = MeleeSetup_getTeamName (setup, sideI); + t.CharCount = (COUNT) ~0; + SetContextFont (TinyFont); + SetContextForeGroundColor (PICKSHIP_TEAM_NAME_TEXT_COLOR); + font_DrawText (&t); + + // Total team value of the starting team: + sprintf (buf, "%u", MeleeSetup_getFleetValue (setup, sideI)); + t.baseline.x = 4; + t.baseline.y = 7; + t.align = ALIGN_LEFT; + t.pStr = buf; + t.CharCount = (COUNT)~0; + SetContextForeGroundColor (PICKSHIP_TEAM_START_VALUE_COLOR); + font_DrawText (&t); + + assert (CountLinks (&race_q[side]) == 0); + + for (index = 0; index < MELEE_FLEET_SIZE; index++) + { + MeleeShip StarShip; + + StarShip = MeleeSetup_getShip (setup, sideI, index); + if (StarShip == MELEE_NONE) + continue; + + { + BYTE row, col; + BYTE ship_cost; + HMASTERSHIP hMasterShip; + HSTARSHIP hBuiltShip; + MASTER_SHIP_INFO *MasterPtr; + STARSHIP *BuiltShipPtr; + BYTE captains_name_index; + + hMasterShip = GetStarShipFromIndex (&master_q, StarShip); + MasterPtr = LockMasterShip (&master_q, hMasterShip); + + captains_name_index = NameCaptain (&race_q[side], + MasterPtr->SpeciesID); + hBuiltShip = Build (&race_q[side], MasterPtr->SpeciesID); + + // Draw the icon. + row = PickMelee_GetShipRow (index); + col = PickMelee_GetShipColumn (index); + s.origin.x = 4 + ((ICON_WIDTH + 2) * col); + s.origin.y = 10 + ((ICON_HEIGHT + 2) * row); + s.frame = MasterPtr->ShipInfo.icons; + DrawStamp (&s); + + ship_cost = MasterPtr->ShipInfo.ship_cost; + UnlockMasterShip (&master_q, hMasterShip); + + BuiltShipPtr = LockStarShip (&race_q[side], hBuiltShip); + BuiltShipPtr->index = index; + BuiltShipPtr->ship_cost = ship_cost; + BuiltShipPtr->playerNr = side; + BuiltShipPtr->captains_name_index = captains_name_index; + // The next ones are not used in Melee + BuiltShipPtr->crew_level = 0; + BuiltShipPtr->max_crew = 0; + BuiltShipPtr->race_strings = 0; + BuiltShipPtr->icons = 0; + BuiltShipPtr->RaceDescPtr = 0; + UnlockStarShip (&race_q[side], hBuiltShip); + } + } + } + + SetContext (OldContext); +} + +void +DestroyPickMeleeFrame (void) +{ + DestroyDrawable (ReleaseDrawable (PickMeleeFrame)); + PickMeleeFrame = 0; +} + // Pre: caller holds the graphics lock. static void DrawPickMeleeFrame (COUNT which_player) @@ -574,7 +765,7 @@ GetMeleeStarShips (COUNT playerMask, HSTARSHIP *ships) gmstate.player[playerI].timeIn = now; gmstate.player[playerI].row = 0; - gmstate.player[playerI].col = NUM_MELEE_COLS_ORIG; + gmstate.player[playerI].col = NUM_PICKMELEE_COLUMNS; #ifdef NETPLAY gmstate.player[playerI].remoteSelected = FALSE; #endif @@ -764,7 +955,7 @@ reportShipSelected (GETMELEE_STATE *gms, COUNT index) if (!NetConnection_isConnected (conn)) continue; - Netplay_selectShip (conn, index); + Netplay_Notify_shipSelected (conn, index); } (void) gms; } diff --git a/sc2/src/uqm/supermelee/pickmele.h b/sc2/src/uqm/supermelee/pickmele.h index fc43f9805..90a025a21 100644 --- a/sc2/src/uqm/supermelee/pickmele.h +++ b/sc2/src/uqm/supermelee/pickmele.h @@ -21,9 +21,13 @@ typedef struct getmelee_struct GETMELEE_STATE; #include "../races.h" #include "../battlecontrols.h" +#include "meleesetup.h" #include "libs/compiler.h" BOOLEAN MeleeShipDeath (STARSHIP *ship, COUNT which_player); +void BuildPickMeleeFrame (void); +void DestroyPickMeleeFrame (void); +void FillPickMeleeFrame (MeleeSetup *setup); void MeleeGameOver (void); BOOLEAN GetInitialMeleeStarShips (HSTARSHIP *result); BOOLEAN GetNextMeleeStarShip (COUNT which_player, HSTARSHIP *result); diff --git a/sc2/src/uqm/tactrans.c b/sc2/src/uqm/tactrans.c index da1bc8b92..5799fec9c 100644 --- a/sc2/src/uqm/tactrans.c +++ b/sc2/src/uqm/tactrans.c @@ -90,7 +90,7 @@ readyToEndCallback (NetConnection *conn, void *arg) NetConnection_setState (conn, NetState_endingBattle); if (battleFrameCount + 1 > battleStateData->endFrameCount) battleStateData->endFrameCount = battleFrameCount + 1; - Netplay_sendFrameCount (conn, battleFrameCount + 1); + Netplay_Notify_frameCount (conn, battleFrameCount + 1); // The +1 is to ensure that after the remote side receives the // frame count it will still receive one more frame data packet, // so it will know in advance when the last frame data packet