https://github.com/libsdl-org/Maelstrom/commit/2fc35f8e59dfe3e5eda73d658492b0bfcc3e703e
From 2fc35f8e59dfe3e5eda73d658492b0bfcc3e703e Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Fri, 25 Nov 2011 11:02:40 -0500
Subject: [PATCH] Added a new kids mode where you have air brakes and automatic
shields
---
game/Maelstrom_Globals.h | 1 +
game/game.cpp | 23 +++++++++++++-----
game/gameinfo.cpp | 18 ++++++++++++--
game/gameinfo.h | 15 +++++++++++-
game/lobby.cpp | 3 ++-
game/main.cpp | 4 ++--
game/object.h | 12 +++++++---
game/player.cpp | 51 +++++++++++++++++++++-------------------
game/player.h | 8 ++++++-
9 files changed, 95 insertions(+), 40 deletions(-)
diff --git a/game/Maelstrom_Globals.h b/game/Maelstrom_Globals.h
index 0a93dfc7..37650180 100644
--- a/game/Maelstrom_Globals.h
+++ b/game/Maelstrom_Globals.h
@@ -46,6 +46,7 @@
// Preferences keys
#define PREFERENCES_HANDLE "Handle"
#define PREFERENCES_DEATHMATCH "Network.Deathmatch"
+#define PREFERENCES_KIDMODE "Cheat.KidMode"
// The Font Server :)
extern FontServ *fontserv;
diff --git a/game/game.cpp b/game/game.cpp
index b9e03efc..463ef41f 100644
--- a/game/game.cpp
+++ b/game/game.cpp
@@ -188,7 +188,7 @@ GamePanelDelegate::OnShow()
if (!gPlayers[i]->IsValid()) {
continue;
}
- gPlayers[i]->NewGame(gGameInfo.lives, gGameInfo.deathMatch);
+ gPlayers[i]->NewGame(gGameInfo.lives);
}
gLastStar = STAR_DELAY;
gLastDrawn = 0L;
@@ -209,7 +209,7 @@ GamePanelDelegate::OnShow()
m_multiplayerColor->Hide();
}
}
- if ( gGameInfo.deathMatch ) {
+ if ( gGameInfo.IsDeathmatch() ) {
if (m_fragsLabel) {
m_fragsLabel->Show();
}
@@ -321,6 +321,17 @@ GamePanelDelegate::OnTick()
if ( ! gPlayers[j]->Alive() )
continue;
+ if (gGameInfo.IsKidMode()) {
+ bool enableShield = false;
+ OBJ_LOOP(i, gNumSprites) {
+ if (gSprites[i]->Collide(gPlayers[j], false)) {
+ enableShield = true;
+ break;
+ }
+ }
+ gPlayers[j]->SetKidShield(enableShield);
+ }
+
/* This loop looks funny because gNumSprites can change
dynamically during the loop as sprites are killed/created.
This same logic is used whenever looping where sprites
@@ -332,7 +343,7 @@ GamePanelDelegate::OnTick()
gSprites[i] = gSprites[gNumSprites];
}
}
- if ( gGameInfo.deathMatch ) {
+ if ( gGameInfo.IsDeathmatch() ) {
OBJ_LOOP(i, MAX_PLAYERS) {
if (!gPlayers[i]->IsValid()) {
continue;
@@ -536,7 +547,7 @@ GamePanelDelegate::DrawStatus(Bool first)
m_score->SetText(numbuf);
}
- if (!gGameInfo.deathMatch) {
+ if (!gGameInfo.IsDeathmatch()) {
if (lastScores[i] == Score)
continue;
@@ -1011,7 +1022,7 @@ static void DoGameOver(void)
final[i].Score = gPlayers[i]->GetScore();
final[i].Frags = gPlayers[i]->GetFrags();
}
- if ( gGameInfo.deathMatch )
+ if ( gGameInfo.IsDeathmatch() )
qsort(final,MAX_PLAYERS,sizeof(struct FinalScore),cmp_byfrags);
else
qsort(final,MAX_PLAYERS,sizeof(struct FinalScore),cmp_byscore);
@@ -1041,7 +1052,7 @@ static void DoGameOver(void)
if (!label) {
continue;
}
- if (gGameInfo.deathMatch) {
+ if (gGameInfo.IsDeathmatch()) {
sprintf(num1, "%7d", final[i].Score);
sprintf(num2, "%3d", final[i].Frags);
sprintf(buffer, "Player %d: %s Points, %s Frags", final[i].Player, num1, num2);
diff --git a/game/gameinfo.cpp b/game/gameinfo.cpp
index 17393959..b0bc786c 100644
--- a/game/gameinfo.cpp
+++ b/game/gameinfo.cpp
@@ -43,21 +43,30 @@ GameInfo::Reset()
lives = 0;
turbo = 0;
deathMatch = 0;
+ gameMode = 0;
+ deathMatch = 0;
numNodes = 0;
SDL_zero(nodes);
SDL_zero(players);
}
void
-GameInfo::SetHost(Uint8 wave, Uint8 lives, Uint8 turbo, Uint8 deathMatch)
+GameInfo::SetHost(Uint8 wave, Uint8 lives, Uint8 turbo, Uint8 deathMatch, bool kidMode)
{
Reset();
this->gameID = localID;
this->seed = GetRandSeed();
this->wave = wave;
- this->lives = lives;
+ this->lives = deathMatch ? deathMatch : lives;
this->turbo = turbo;
+ this->gameMode = 0;
+ if (kidMode) {
+ this->gameMode |= GAME_MODE_KIDS;
+ }
+ if (deathMatch) {
+ this->gameMode |= GAME_MODE_DEATHMATCH;
+ }
this->deathMatch = deathMatch;
// We are the host node
@@ -136,6 +145,7 @@ GameInfo::CopyFrom(const GameInfo &rhs)
wave = rhs.wave;
lives = rhs.lives;
turbo = rhs.turbo;
+ gameMode = rhs.gameMode;
deathMatch = rhs.deathMatch;
for (i = 0; i < MAX_NODES; ++i) {
@@ -199,6 +209,9 @@ GameInfo::ReadFromPacket(DynamicPacket &packet)
if (!packet.Read(turbo)) {
return false;
}
+ if (!packet.Read(gameMode)) {
+ return false;
+ }
if (!packet.Read(deathMatch)) {
return false;
}
@@ -251,6 +264,7 @@ GameInfo::WriteToPacket(DynamicPacket &packet)
packet.Write(wave);
packet.Write(lives);
packet.Write(turbo);
+ packet.Write(gameMode);
packet.Write(deathMatch);
packet.Write(numNodes);
diff --git a/game/gameinfo.h b/game/gameinfo.h
index f30f7183..d211e54b 100644
--- a/game/gameinfo.h
+++ b/game/gameinfo.h
@@ -47,6 +47,11 @@ enum PLAYER_CONTROL {
#endif
};
+enum GAME_MODE {
+ GAME_MODE_DEATHMATCH = 0x01,
+ GAME_MODE_KIDS = 0x02,
+};
+
#define IS_LOCAL_CONTROL(X) (X != CONTROL_NONE && X != CONTROL_NETWORK && X != CONTROL_REPLAY)
enum NODE_STATE_FLAG {
@@ -118,7 +123,7 @@ class GameInfo
localID = uniqueID;
}
- void SetHost(Uint8 wave, Uint8 lives, Uint8 turbo, Uint8 deathMatch);
+ void SetHost(Uint8 wave, Uint8 lives, Uint8 turbo, Uint8 deathMatch, bool kidMode);
void SetPlayerSlot(int slot, const char *name, Uint8 controlMask);
void SetPlayerName(int slot, const char *name);
@@ -186,6 +191,13 @@ class GameInfo
bool IsFull() const;
+ bool IsDeathmatch() const {
+ return (gameMode & GAME_MODE_DEATHMATCH) != 0;
+ }
+ bool IsKidMode() const {
+ return (gameMode & GAME_MODE_KIDS) != 0;
+ }
+
void SetNodeState(int index, Uint8 state);
Uint8 GetNodeState(int index) const;
@@ -212,6 +224,7 @@ class GameInfo
Uint8 wave;
Uint8 lives;
Uint8 turbo;
+ Uint8 gameMode;
Uint8 deathMatch;
Uint32 localID;
diff --git a/game/lobby.cpp b/game/lobby.cpp
index 20f88a4e..4dbfb305 100644
--- a/game/lobby.cpp
+++ b/game/lobby.cpp
@@ -438,7 +438,8 @@ LobbyDialogDelegate::SetState(LOBBY_STATE state)
m_game.SetHost(DEFAULT_START_WAVE,
DEFAULT_START_LIVES,
DEFAULT_START_TURBO,
- prefs->GetNumber(PREFERENCES_DEATHMATCH));
+ prefs->GetNumber(PREFERENCES_DEATHMATCH),
+ prefs->GetBool(PREFERENCES_KIDMODE));
// Set up the controls for this game
for (i = 0; i < MAX_PLAYERS; ++i) {
diff --git a/game/main.cpp b/game/main.cpp
index 6e1d670f..84fc64d0 100644
--- a/game/main.cpp
+++ b/game/main.cpp
@@ -72,7 +72,7 @@ static void RunSinglePlayerGame()
}
static void RunPlayGame(void*)
{
- gGameInfo.SetHost(DEFAULT_START_WAVE, DEFAULT_START_LIVES, DEFAULT_START_TURBO, 0);
+ gGameInfo.SetHost(DEFAULT_START_WAVE, DEFAULT_START_LIVES, DEFAULT_START_TURBO, 0, prefs->GetBool(PREFERENCES_KIDMODE));
gGameInfo.SetPlayerSlot(0, prefs->GetString(PREFERENCES_HANDLE), CONTROL_LOCAL);
RunSinglePlayerGame();
}
@@ -173,7 +173,7 @@ static void CheatDialogDone(UIDialog *dialog, int status)
Delay(SOUND_DELAY);
sound->PlaySound(gNewLife, 5);
Delay(SOUND_DELAY);
- gGameInfo.SetHost(wave, lives, turbo, 0);
+ gGameInfo.SetHost(wave, lives, turbo, 0, prefs->GetBool(PREFERENCES_KIDMODE));
gGameInfo.SetPlayerSlot(0, prefs->GetString(PREFERENCES_HANDLE), CONTROL_LOCAL);
RunSinglePlayerGame();
}
diff --git a/game/object.h b/game/object.h
index a6cf8d0d..bf933525 100644
--- a/game/object.h
+++ b/game/object.h
@@ -69,14 +69,21 @@ class Object {
/* This function is called to see if we shot something */
return(NULL);
}
- virtual int Collide(Object *object) {
+ virtual int Collide(Object *object, bool exact = true) {
/* Set up the location rectangles */
Rect *R1=&HitRect, *R2=&object->HitRect;
+ if ( ! solid || ! object->solid )
+ return(0);
+
/* No collision if no overlap */
if ( ! Overlap(R1, R2) )
return(0);
+ /* See if that's enough to check collision */
+ if ( ! exact )
+ return(1);
+
/* Check the bitmasks to see if the sprites really intersect */
int xoff1, xoff2;
int roff;
@@ -129,8 +136,7 @@ class Object {
if ( BeenShot(ship, shot) > 0 )
return(-1);
}
- if ( (solid && ship->solid) &&
- Collide(ship) && (BeenRunOver(ship) > 0) )
+ if ( Collide(ship) && (BeenRunOver(ship) > 0) )
return(-1);
return(0);
}
diff --git a/game/player.cpp b/game/player.cpp
index fcf233d8..ee8e0259 100644
--- a/game/player.cpp
+++ b/game/player.cpp
@@ -26,8 +26,6 @@
#include "player.h"
#include "objects.h"
-// Define this to be invincible
-//#define KID_MODE
/* ----------------------------------------------------------------- */
/* -- The thrust sound callback */
@@ -74,10 +72,10 @@ Player::~Player()
/* Note that the lives argument is ignored during deathmatches */
void
-Player::NewGame(int lives, int deathMatch)
+Player::NewGame(int lives)
{
Playing = 1;
- if ( deathMatch )
+ if ( gGameInfo.IsDeathmatch() )
Lives = 1;
else
Lives = lives;
@@ -147,8 +145,14 @@ Player::NewShip(void)
Dead = 0;
Exploding = 0;
Set_TTL(-1);
- if ( ! gGameInfo.deathMatch )
+ if ( ! gGameInfo.IsDeathmatch() )
--Lives;
+
+ // In Kid Mode you automatically get air brakes and full shields
+ if ( gGameInfo.IsKidMode() ) {
+ special |= AIR_BRAKES;
+ ShieldLevel = MAX_SHIELD;
+ }
return(Lives);
}
@@ -157,7 +161,7 @@ void
Player::IncrFrags(void)
{
++Frags;
- if ( gGameInfo.deathMatch && (Frags >= gGameInfo.deathMatch) ) {
+ if ( gGameInfo.IsDeathmatch() && (Frags >= gGameInfo.deathMatch) ) {
/* Game over, we got a stud. :) */
int i;
OBJ_LOOP(i, MAX_PLAYERS) {
@@ -176,7 +180,7 @@ error("Killing player %d\n", i+1);
void
Player::IncrLives(int lives)
{
- if ( gGameInfo.deathMatch && (lives > 0) )
+ if ( gGameInfo.IsDeathmatch() && (lives > 0) )
return;
Lives += lives;
}
@@ -185,9 +189,6 @@ Player::IncrLives(int lives)
int
Player::BeenShot(Object *ship, Shot *shot)
{
-#ifdef KID_MODE
- return(0);
-#else
if ( Exploding || !Alive() )
return(0);
if ( AutoShield || (ShieldOn && (ShieldLevel > 0)) )
@@ -197,15 +198,12 @@ Player::BeenShot(Object *ship, Shot *shot)
return(0);
}
return(Object::BeenShot(ship, shot));
-#endif
}
/* We've been run over! (returns 1 if we are dead) */
int
-Player::BeenRunOver(Object *ship) {
-#ifdef KID_MODE
- return(0);
-#else
+Player::BeenRunOver(Object *ship)
+{
if ( Exploding || !Alive() )
return(0);
if ( AutoShield || (ShieldOn && (ShieldLevel > 0)) )
@@ -217,16 +215,12 @@ Player::BeenRunOver(Object *ship) {
return(0);
}
return(Object::BeenRunOver(ship));
-#endif
}
/* We've been run over by a rock or something */
int
Player::BeenDamaged(int damage)
{
-#ifdef KID_MODE
- return(0);
-#else
if ( Exploding || !Alive() )
return(0);
if ( AutoShield || (ShieldOn && (ShieldLevel > 0)) )
@@ -236,7 +230,6 @@ Player::BeenDamaged(int damage)
return(0);
}
return(Object::BeenDamaged(damage));
-#endif
}
/* We expired (returns -1 if our sprite should be deleted) */
@@ -248,7 +241,7 @@ Player::BeenTimedOut(void)
((SCREEN_WIDTH/2-((gGameInfo.GetNumPlayers()/2-Index)*(2*SPRITES_WIDTH)))*SCALE_FACTOR),
((SCREEN_HEIGHT/2)*SCALE_FACTOR)
);
- if ( gGameInfo.deathMatch )
+ if ( gGameInfo.IsDeathmatch() )
Dead = (DEAD_DELAY/2);
else
Dead = DEAD_DELAY;
@@ -475,7 +468,7 @@ printf("\n");
WasShielded = 1;
}
--ShieldLevel;
- } else {
+ } else if ( ShieldOn & SHIELD_MANUAL ) {
sound->PlaySound(gNoShieldSound, 2);
}
} else
@@ -549,7 +542,7 @@ Player::HandleKeys(void)
Rotating |= 0x10;
break;
case SHIELD_KEY:
- ShieldOn = 1;
+ ShieldOn |= SHIELD_MANUAL;
break;
case FIRE_KEY:
Shooting = 1;
@@ -571,7 +564,7 @@ Player::HandleKeys(void)
Rotating &= ~0x10;
break;
case SHIELD_KEY:
- ShieldOn = 0;
+ ShieldOn &= ~SHIELD_MANUAL;
break;
case FIRE_KEY:
Shooting = 0;
@@ -631,6 +624,16 @@ Player::ExplodeSound(void)
sound->PlaySound(gShipHitSound, 3);
}
+void
+Player::SetKidShield(bool enabled)
+{
+ if (enabled) {
+ ShieldOn |= SHIELD_KIDS;
+ } else {
+ ShieldOn &= ~SHIELD_KIDS;
+ }
+}
+
void
Player::SetControlType(Uint8 controlType)
{
diff --git a/game/player.h b/game/player.h
index 359e8e3b..33095dfa 100644
--- a/game/player.h
+++ b/game/player.h
@@ -31,6 +31,10 @@
#define LONG_RANGE 0x08
#define LUCKY_IRISH 0x80
+/* Different shield modes */
+#define SHIELD_MANUAL 0x01
+#define SHIELD_KIDS 0x02
+
class Player : public Object {
public:
@@ -49,7 +53,7 @@ class Player : public Object {
virtual int Kicking(void) {
return(Playing);
}
- virtual void NewGame(int lives, int deathMatch);
+ virtual void NewGame(int lives);
virtual void NewWave(void);
/* NewShip() MUST be called before Move() */
virtual int NewShip(void);
@@ -123,6 +127,8 @@ class Player : public Object {
virtual void HitSound(void);
virtual void ExplodeSound(void);
+ void SetKidShield(bool enabled);
+
void SetControlType(Uint8 controlType);
Uint8 GetControlType() {
return controlType;