diff --git a/src/action/action_research.cpp b/src/action/action_research.cpp index 6c664fe1d..9f68ac09b 100644 --- a/src/action/action_research.cpp +++ b/src/action/action_research.cpp @@ -100,6 +100,11 @@ void HandleActionResearch(CUnit *unit) unit->Player->Notify(NotifyGreen, unit->X, unit->Y, _("%s: complete"), unit->Type->Name.c_str()); + if (unit->Player == ThisPlayer) { + if (GameSounds.ResearchComplete[unit->Player->Race].Sound) + PlayGameSound(GameSounds.ResearchComplete[unit->Player->Race].Sound, + MaxSampleVolume); + } if (unit->Player->AiEnabled) { AiResearchComplete(unit, upgrade); } diff --git a/src/editor/editloop.cpp b/src/editor/editloop.cpp index 59d54cff8..bae2fe5b1 100644 --- a/src/editor/editloop.cpp +++ b/src/editor/editloop.cpp @@ -1387,7 +1387,7 @@ static void EditorCallbackButtonDown(unsigned button) if (!UnitPlacedThisPress && CursorBuilding) { if (CanBuildUnitType(NULL, CursorBuilding, tileX, tileY, 1)) { - PlayGameSound(GameSounds.PlacementSuccess.Sound, + PlayGameSound(GameSounds.PlacementSuccess[ThisPlayer->Race].Sound, MaxSampleVolume); EditorPlaceUnit(tileX, tileY, CursorBuilding, Players + Editor.SelectedPlayer); @@ -1395,7 +1395,7 @@ static void EditorCallbackButtonDown(unsigned button) UI.StatusLine.Clear(); } else { UI.StatusLine.Set(_("Unit can't be placed here.")); - PlayGameSound(GameSounds.PlacementError.Sound, + PlayGameSound(GameSounds.PlacementError[ThisPlayer->Race].Sound, MaxSampleVolume); } } diff --git a/src/include/netconnect.h b/src/include/netconnect.h index f6494958d..47f2e602e 100644 --- a/src/include/netconnect.h +++ b/src/include/netconnect.h @@ -92,7 +92,7 @@ class CServerSetup { public: unsigned char *Serialize() const; void Deserialize(const unsigned char *p); - static size_t Size() { return 1+1+1+1+1+1+1+1+ 1*PlayerMax + 1*PlayerMax + 1*PlayerMax + 4*PlayerMax; } + static size_t Size() { return 4+4+4+4+4+4+4+4+ 4*PlayerMax + 4*PlayerMax + 4*PlayerMax + 4*PlayerMax; } void Clear() { ResourcesOption = UnitsOption = FogOfWar = RevealMap = GameTypeOption = Difficulty = MapRichness = 0; @@ -101,18 +101,18 @@ public: memset(LastFrame, 0, sizeof(LastFrame)); } - Uint8 ResourcesOption; /// Resources option - Uint8 UnitsOption; /// Unit # option - Uint8 FogOfWar; /// Fog of war option - Uint8 RevealMap; /// Reveal all the map - Uint8 TilesetSelection; /// Tileset select option - Uint8 GameTypeOption; /// Game type option - Uint8 Difficulty; /// Difficulty option - Uint8 MapRichness; /// Map richness option - Uint8 CompOpt[PlayerMax]; /// Free slot option selection {"Available", "Computer", "Closed" } - Uint8 Ready[PlayerMax]; /// Client ready state - Uint8 Race[PlayerMax]; /// Client race selection - Uint32 LastFrame[PlayerMax]; /// Last message received + Uint32 ResourcesOption; /// Resources option + Uint32 UnitsOption; /// Unit # option + Uint32 FogOfWar; /// Fog of war option + Uint32 RevealMap; /// Reveal all the map + Uint32 TilesetSelection; /// Tileset select option + Uint32 GameTypeOption; /// Game type option + Uint32 Difficulty; /// Difficulty option + Uint32 MapRichness; /// Map richness option + Uint32 CompOpt[PlayerMax]; /// Free slot option selection {"Available", "Computer", "Closed" } + Uint32 Ready[PlayerMax]; /// Client ready state + Uint32 Race[PlayerMax]; /// Client race selection + Uint32 LastFrame[PlayerMax]; /// Last message received // Fill in here... }; diff --git a/src/include/sound.h b/src/include/sound.h index 09a01c243..84141ac7d 100644 --- a/src/include/sound.h +++ b/src/include/sound.h @@ -65,14 +65,18 @@ class LuaActionListener; class GameSound { public: - SoundConfig PlacementError; /// used by ui - SoundConfig PlacementSuccess; /// used by ui - SoundConfig Click; /// used by ui - SoundConfig Docking; /// ship reaches coast - SoundConfig BuildingConstruction; /// building under construction - SoundConfig WorkComplete[MAX_RACES]; /// building ready - SoundConfig Rescue[MAX_RACES]; /// rescue units - SoundConfig ChatMessage; /// chat message + SoundConfig PlacementError[MAX_RACES]; /// used by ui + SoundConfig PlacementSuccess[MAX_RACES]; /// used by ui + SoundConfig Click; /// used by ui + SoundConfig Docking; /// ship reaches coast + SoundConfig BuildingConstruction[MAX_RACES]; /// building under construction + SoundConfig WorkComplete[MAX_RACES]; /// building ready + SoundConfig Rescue[MAX_RACES]; /// rescue units + SoundConfig ChatMessage; /// chat message + SoundConfig ResearchComplete[MAX_RACES]; /// research complete message + SoundConfig NotEnough1[MAX_RACES]; /// not enough minerals message + SoundConfig NotEnough2[MAX_RACES]; /// not enough ore message + SoundConfig NotEnoughFood[MAX_RACES]; /// not enough food message }; /** diff --git a/src/include/unit.h b/src/include/unit.h index 1208bbdee..dd2e04ac5 100644 --- a/src/include/unit.h +++ b/src/include/unit.h @@ -471,7 +471,8 @@ enum UnitVoiceGroup { VoiceBuilding, /// only for building under construction VoiceDocking, /// only for transport reaching coast VoiceRepairing, /// repairing - VoiceHarvesting /// harvesting + VoiceHarvesting, /// harvesting + VoiceAttack /// Attack command }; /** diff --git a/src/include/unitsound.h b/src/include/unitsound.h index ea157ab53..ed756466e 100644 --- a/src/include/unitsound.h +++ b/src/include/unitsound.h @@ -70,6 +70,7 @@ class CUnitSound { public: SoundConfig Selected; /// selected by user SoundConfig Acknowledgement; /// acknowledge of use command + SoundConfig Attack; /// attack confirm command SoundConfig Ready; /// unit training... ready SoundConfig Repair; /// unit repairing SoundConfig Harvest[MaxCosts]; /// unit harvesting diff --git a/src/include/util.h b/src/include/util.h index 7b73592a7..3d7fb3340 100644 --- a/src/include/util.h +++ b/src/include/util.h @@ -39,6 +39,7 @@ #ifndef __unix #undef NOUSER +#define _WIN32_WINNT 0x0400 #include <winsock2.h> #include <windows.h> #elif defined(__hpux) diff --git a/src/pathfinder/pathfinder.cpp b/src/pathfinder/pathfinder.cpp index 6ced07a98..147b0cd56 100644 --- a/src/pathfinder/pathfinder.cpp +++ b/src/pathfinder/pathfinder.cpp @@ -208,6 +208,8 @@ int UnitReachable(const CUnit *src, const CUnit *dst, int range) // // Find a path to the goal. // + if (src->Type->Building) + return 0; depth = PlaceReachable(src, dst->X, dst->Y, dst->Type->TileWidth, dst->Type->TileHeight, 0, range); if (depth <= 0) { diff --git a/src/sound/script_sound.cpp b/src/sound/script_sound.cpp index b675f1c57..21d80c820 100644 --- a/src/sound/script_sound.cpp +++ b/src/sound/script_sound.cpp @@ -252,17 +252,49 @@ static int CclDefineGameSounds(lua_State *l) } GameSounds.Click.Sound = (CSound *)data->Data; } else if (!strcmp(value, "placement-error")) { - if (!lua_isuserdata(l, j + 1) || - (data = (LuaUserData *)lua_touserdata(l, j + 1))->Type != LuaSoundType) { + if (!lua_istable(l, j + 1) || lua_objlen(l, j + 1) != 2) { + LuaError(l, "incorrect argument"); + } + lua_rawgeti(l, j + 1, 1); + value = LuaToString(l, -1); + lua_pop(l, 1); + for (i = 0; i < PlayerRaces.Count; ++i) { + if (!strcmp(PlayerRaces.Name[i].c_str(), value)) { + break; + } + } + if (i == PlayerRaces.Count) { + LuaError(l, "Unknown race: %s" _C_ value); + } + lua_rawgeti(l, j + 1, 2); + if (!lua_isuserdata(l, -1) || + (data = (LuaUserData *)lua_touserdata(l, -1))->Type != LuaSoundType) { LuaError(l, "Sound id expected"); } - GameSounds.PlacementError.Sound = (CSound *)data->Data; + lua_pop(l, 1); + GameSounds.PlacementError[i].Sound = (CSound *)data->Data; } else if (!strcmp(value, "placement-success")) { - if (!lua_isuserdata(l, j + 1) || - (data = (LuaUserData *)lua_touserdata(l, j + 1))->Type != LuaSoundType) { + if (!lua_istable(l, j + 1) || lua_objlen(l, j + 1) != 2) { + LuaError(l, "incorrect argument"); + } + lua_rawgeti(l, j + 1, 1); + value = LuaToString(l, -1); + lua_pop(l, 1); + for (i = 0; i < PlayerRaces.Count; ++i) { + if (!strcmp(PlayerRaces.Name[i].c_str(), value)) { + break; + } + } + if (i == PlayerRaces.Count) { + LuaError(l, "Unknown race: %s" _C_ value); + } + lua_rawgeti(l, j + 1, 2); + if (!lua_isuserdata(l, -1) || + (data = (LuaUserData *)lua_touserdata(l, -1))->Type != LuaSoundType) { LuaError(l, "Sound id expected"); } - GameSounds.PlacementSuccess.Sound = (CSound *)data->Data; + lua_pop(l, 1); + GameSounds.PlacementSuccess[i].Sound = (CSound *)data->Data; } else if (!strcmp(value, "work-complete")) { if (!lua_istable(l, j + 1) || lua_objlen(l, j + 1) != 2) { LuaError(l, "incorrect argument"); @@ -285,6 +317,94 @@ static int CclDefineGameSounds(lua_State *l) } lua_pop(l, 1); GameSounds.WorkComplete[i].Sound = (CSound *)data->Data; + } else if (!strcmp(value, "research-complete")) { + if (!lua_istable(l, j + 1) || lua_objlen(l, j + 1) != 2) { + LuaError(l, "incorrect argument"); + } + lua_rawgeti(l, j + 1, 1); + value = LuaToString(l, -1); + lua_pop(l, 1); + for (i = 0; i < PlayerRaces.Count; ++i) { + if (!strcmp(PlayerRaces.Name[i].c_str(), value)) { + break; + } + } + if (i == PlayerRaces.Count) { + LuaError(l, "Unknown race: %s" _C_ value); + } + lua_rawgeti(l, j + 1, 2); + if (!lua_isuserdata(l, -1) || + (data = (LuaUserData *)lua_touserdata(l, -1))->Type != LuaSoundType) { + LuaError(l, "Sound id expected"); + } + lua_pop(l, 1); + GameSounds.ResearchComplete[i].Sound = (CSound *)data->Data; + } else if (!strcmp(value, "not-enough-min")) { + if (!lua_istable(l, j + 1) || lua_objlen(l, j + 1) != 2) { + LuaError(l, "incorrect argument"); + } + lua_rawgeti(l, j + 1, 1); + value = LuaToString(l, -1); + lua_pop(l, 1); + for (i = 0; i < PlayerRaces.Count; ++i) { + if (!strcmp(PlayerRaces.Name[i].c_str(), value)) { + break; + } + } + if (i == PlayerRaces.Count) { + LuaError(l, "Unknown race: %s" _C_ value); + } + lua_rawgeti(l, j + 1, 2); + if (!lua_isuserdata(l, -1) || + (data = (LuaUserData *)lua_touserdata(l, -1))->Type != LuaSoundType) { + LuaError(l, "Sound id expected"); + } + lua_pop(l, 1); + GameSounds.NotEnough1[i].Sound = (CSound *)data->Data; + } else if (!strcmp(value, "not-enough-ore")) { + if (!lua_istable(l, j + 1) || lua_objlen(l, j + 1) != 2) { + LuaError(l, "incorrect argument"); + } + lua_rawgeti(l, j + 1, 1); + value = LuaToString(l, -1); + lua_pop(l, 1); + for (i = 0; i < PlayerRaces.Count; ++i) { + if (!strcmp(PlayerRaces.Name[i].c_str(), value)) { + break; + } + } + if (i == PlayerRaces.Count) { + LuaError(l, "Unknown race: %s" _C_ value); + } + lua_rawgeti(l, j + 1, 2); + if (!lua_isuserdata(l, -1) || + (data = (LuaUserData *)lua_touserdata(l, -1))->Type != LuaSoundType) { + LuaError(l, "Sound id expected"); + } + lua_pop(l, 1); + GameSounds.NotEnough2[i].Sound = (CSound *)data->Data; + }else if (!strcmp(value, "not-enough-food")) { + if (!lua_istable(l, j + 1) || lua_objlen(l, j + 1) != 2) { + LuaError(l, "incorrect argument"); + } + lua_rawgeti(l, j + 1, 1); + value = LuaToString(l, -1); + lua_pop(l, 1); + for (i = 0; i < PlayerRaces.Count; ++i) { + if (!strcmp(PlayerRaces.Name[i].c_str(), value)) { + break; + } + } + if (i == PlayerRaces.Count) { + LuaError(l, "Unknown race: %s" _C_ value); + } + lua_rawgeti(l, j + 1, 2); + if (!lua_isuserdata(l, -1) || + (data = (LuaUserData *)lua_touserdata(l, -1))->Type != LuaSoundType) { + LuaError(l, "Sound id expected"); + } + lua_pop(l, 1); + GameSounds.NotEnoughFood[i].Sound = (CSound *)data->Data; } else if (!strcmp(value, "rescue")) { if (!lua_istable(l, j + 1) || lua_objlen(l, j + 1) != 2) { LuaError(l, "incorrect argument"); diff --git a/src/sound/sound.cpp b/src/sound/sound.cpp index 980cb815c..3ea30900f 100644 --- a/src/sound/sound.cpp +++ b/src/sound/sound.cpp @@ -63,28 +63,8 @@ /** ** Various sounds used in game. -** -** FIXME: @todo support more races. Must remove static config. */ -GameSound GameSounds -#ifndef laterUSE_CCL -// FIXME: Removing this crashes? -={ - SoundConfig("placement error"), - SoundConfig("placement success"), - SoundConfig("click"), - SoundConfig("transport docking"), - SoundConfig("building construction"), - { SoundConfig("basic human voices work complete"), - SoundConfig("basic orc voices work complete"), - }, - { SoundConfig("rescue (human) UNUSED"), - SoundConfig("rescue (orc) UNUSED"), - }, - SoundConfig("click"), -} -#endif - ; +GameSound GameSounds; /** ** Selection handling @@ -187,6 +167,8 @@ static CSound *ChooseUnitVoiceSound(const CUnit *unit, UnitVoiceGroup voice) switch (voice) { case VoiceAcknowledging: return unit->Type->Sound.Acknowledgement.Sound; + case VoiceAttack: + return unit->Type->Sound.Attack.Sound; case VoiceReady: return unit->Type->Sound.Ready.Sound; case VoiceSelected: @@ -198,7 +180,7 @@ static CSound *ChooseUnitVoiceSound(const CUnit *unit, UnitVoiceGroup voice) case VoiceWorkCompleted: return GameSounds.WorkComplete[ThisPlayer->Race].Sound; case VoiceBuilding: - return GameSounds.BuildingConstruction.Sound; + return GameSounds.BuildingConstruction[ThisPlayer->Race].Sound; case VoiceDocking: return GameSounds.Docking.Sound; case VoiceRepairing: @@ -503,14 +485,22 @@ void InitSoundClient(void) } // let's map game sounds, look if already setup in ccl. - if (!GameSounds.PlacementError.Sound) { - GameSounds.PlacementError.Sound = - SoundForName(GameSounds.PlacementError.Name); + for (unsigned int i = 0; i < PlayerRaces.Count; ++i) { + if (!GameSounds.PlacementError[i].Sound && + !GameSounds.PlacementError[i].Name.empty()) { + GameSounds.PlacementError[i].Sound = + SoundForName(GameSounds.PlacementError[i].Name); + } } - if (!GameSounds.PlacementSuccess.Sound) { - GameSounds.PlacementSuccess.Sound = - SoundForName(GameSounds.PlacementSuccess.Name); + + for (unsigned int i = 0; i < PlayerRaces.Count; ++i) { + if (!GameSounds.PlacementSuccess[i].Sound && + !GameSounds.PlacementSuccess[i].Name.empty()) { + GameSounds.PlacementSuccess[i].Sound = + SoundForName(GameSounds.PlacementSuccess[i].Name); + } } + if (!GameSounds.Click.Sound) { GameSounds.Click.Sound = SoundForName(GameSounds.Click.Name); } @@ -518,9 +508,13 @@ void InitSoundClient(void) GameSounds.Docking.Sound = SoundForName(GameSounds.Docking.Name); } - if (!GameSounds.BuildingConstruction.Sound) { - GameSounds.BuildingConstruction.Sound = - SoundForName(GameSounds.BuildingConstruction.Name); + + for (unsigned int i = 0; i < PlayerRaces.Count; ++i) { + if (!GameSounds.BuildingConstruction[i].Sound && + !GameSounds.BuildingConstruction[i].Name.empty()) { + GameSounds.BuildingConstruction[i].Sound = + SoundForName(GameSounds.BuildingConstruction[i].Name); + } } for (unsigned int i = 0; i < PlayerRaces.Count; ++i) { if (!GameSounds.WorkComplete[i].Sound && @@ -529,6 +523,34 @@ void InitSoundClient(void) SoundForName(GameSounds.WorkComplete[i].Name); } } + for (unsigned int i = 0; i < PlayerRaces.Count; ++i) { + if (!GameSounds.ResearchComplete[i].Sound && + !GameSounds.ResearchComplete[i].Name.empty()) { + GameSounds.ResearchComplete[i].Sound = + SoundForName(GameSounds.ResearchComplete[i].Name); + } + } + for (unsigned int i = 0; i < PlayerRaces.Count; ++i) { + if (!GameSounds.NotEnough1[i].Sound && + !GameSounds.NotEnough1[i].Name.empty()) { + GameSounds.NotEnough1[i].Sound = + SoundForName(GameSounds.NotEnough1[i].Name); + } + } + for (unsigned int i = 0; i < PlayerRaces.Count; ++i) { + if (!GameSounds.NotEnough2[i].Sound && + !GameSounds.NotEnough2[i].Name.empty()) { + GameSounds.NotEnough2[i].Sound = + SoundForName(GameSounds.NotEnough2[i].Name); + } + } + for (unsigned int i = 0; i < PlayerRaces.Count; ++i) { + if (!GameSounds.NotEnoughFood[i].Sound && + !GameSounds.NotEnoughFood[i].Name.empty()) { + GameSounds.NotEnoughFood[i].Sound = + SoundForName(GameSounds.NotEnoughFood[i].Name); + } + } for (unsigned int i = 0; i < PlayerRaces.Count; ++i) { if (!GameSounds.Rescue[i].Sound && !GameSounds.Rescue[i].Name.empty()) { GameSounds.Rescue[i].Sound = diff --git a/src/sound/unitsound.cpp b/src/sound/unitsound.cpp index c58bf0f41..7950131c1 100644 --- a/src/sound/unitsound.cpp +++ b/src/sound/unitsound.cpp @@ -145,6 +145,10 @@ void MapUnitSounds(void) INFINITE_SOUND_RANGE); */ } + if (!type->Sound.Attack.Name.empty()) { + type->Sound.Attack.Sound = + SoundForName(type->Sound.Attack.Name); + } if (!type->Sound.Ready.Name.empty()) { type->Sound.Ready.Sound = SoundForName(type->Sound.Ready.Name); diff --git a/src/stratagus/player.cpp b/src/stratagus/player.cpp index 3f6bcb8c9..2d270a8f4 100644 --- a/src/stratagus/player.cpp +++ b/src/stratagus/player.cpp @@ -636,6 +636,14 @@ int CPlayer::CheckCosts(const int *costs) const DefaultResourceNames[i].c_str(), DefaultActions[i].c_str(), DefaultResourceNames[i].c_str()); err |= 1 << i; + if (i==1) + if (GameSounds.NotEnough1[this->Race].Sound) + PlayGameSound(GameSounds.NotEnough1[this->Race].Sound, + MaxSampleVolume); + if (i==2) + if (GameSounds.NotEnough2[this->Race].Sound) + PlayGameSound(GameSounds.NotEnough2[this->Race].Sound, + MaxSampleVolume); } } return err; diff --git a/src/tolua/network.pkg b/src/tolua/network.pkg index 578defeac..041e81071 100644 --- a/src/tolua/network.pkg +++ b/src/tolua/network.pkg @@ -16,14 +16,14 @@ void NetworkServerResyncClients(void); void NetworkDetachFromServer(void); class CServerSetup { - unsigned char ResourcesOption; - unsigned char UnitsOption; - unsigned char FogOfWar; - unsigned char RevealMap; - unsigned char TilesetSelection; - unsigned char GameTypeOption; - unsigned char Difficulty; - unsigned char MapRichness; + unsigned int ResourcesOption; + unsigned int UnitsOption; + unsigned int FogOfWar; + unsigned int RevealMap; + unsigned int TilesetSelection; + unsigned int GameTypeOption; + unsigned int Difficulty; + unsigned int MapRichness; unsigned CompOpt[PlayerMax]; unsigned Ready[PlayerMax]; unsigned Race[PlayerMax]; diff --git a/src/ui/botpanel.cpp b/src/ui/botpanel.cpp index 79f5a5dfb..9a8fd8aca 100644 --- a/src/ui/botpanel.cpp +++ b/src/ui/botpanel.cpp @@ -1040,7 +1040,7 @@ void CButtonPanel::DoClicked(int button) int autocast = 0; if (!SpellTypeTable[spellId]->AutoCast) { - PlayGameSound(GameSounds.PlacementError.Sound, + PlayGameSound(GameSounds.PlacementError[ThisPlayer->Race].Sound, MaxSampleVolume); break; } @@ -1202,7 +1202,10 @@ void CButtonPanel::DoClicked(int button) !(KeyModifiers & ModifierShift)); UI.StatusLine.Clear(); ClearCosts(); - } + } else if (Selected[0]->Player->CheckLimits(type) == -3) + if (GameSounds.NotEnoughFood[Selected[0]->Player->Race].Sound) + PlayGameSound(GameSounds.NotEnoughFood[Selected[0]->Player->Race].Sound, + MaxSampleVolume); break; case ButtonUpgradeTo: diff --git a/src/ui/mouse.cpp b/src/ui/mouse.cpp index aa1282c60..081f54c35 100644 --- a/src/ui/mouse.cpp +++ b/src/ui/mouse.cpp @@ -186,10 +186,6 @@ void DoRightButton(int sx, int sy) continue; } Assert(unit); - if (!acknowledged) { - PlayUnitSound(unit, VoiceAcknowledging); - acknowledged = 1; - } type = unit->Type; action = type->MouseAction; @@ -198,6 +194,10 @@ void DoRightButton(int sx, int sy) // if ((KeyModifiers & ModifierControl) && dest) { dest->Blink = 4; + if (!acknowledged) { + PlayUnitSound(unit, VoiceAcknowledging); + acknowledged = 1; + } SendCommandFollow(unit, dest, flush); continue; } @@ -212,12 +212,20 @@ void DoRightButton(int sx, int sy) if (dest->CanMove() && CanTransport(dest, unit)) { DebugPrint("Send command follow\n"); // is flush value correct ? + if (!acknowledged) { + PlayUnitSound(unit, VoiceAcknowledging); + acknowledged = 1; + } SendCommandFollow(dest, unit, 0); } // FIXME : manage correctly production units. if (!unit->CanMove() || CanTransport(dest, unit)) { dest->Blink = 4; DebugPrint("Board transporter\n"); + if (!acknowledged) { + PlayUnitSound(unit, VoiceAcknowledging); + acknowledged = 1; + } SendCommandBoard(unit, -1, -1, dest, flush); continue; } @@ -229,6 +237,10 @@ void DoRightButton(int sx, int sy) if (unit->CanMove()) { DebugPrint("Send command follow\n"); // is flush value correct ? + if (!acknowledged) { + PlayUnitSound(unit, VoiceAcknowledging); + acknowledged = 1; + } SendCommandFollow(unit, dest, 0); } else if (!dest->CanMove()) { DebugPrint("Want to transport but no unit can move\n"); @@ -236,6 +248,10 @@ void DoRightButton(int sx, int sy) } dest->Blink = 4; DebugPrint("Board transporter\n"); + if (!acknowledged) { + PlayUnitSound(unit, VoiceAcknowledging); + acknowledged = 1; + } SendCommandBoard(dest, -1, -1, unit, flush); continue; } @@ -251,6 +267,10 @@ void DoRightButton(int sx, int sy) dest->Variable[HP_INDEX].Value < dest->Variable[HP_INDEX].Max && (dest->Player == unit->Player || unit->IsAllied(dest))) { dest->Blink = 4; + if (!acknowledged) { + PlayUnitSound(unit, VoiceAcknowledging); + acknowledged = 1; + } SendCommandRepair(unit, x, y, dest, flush); continue; } @@ -262,6 +282,10 @@ void DoRightButton(int sx, int sy) dest->Type->CanStore[unit->CurrentResource] && dest->Player == unit->Player) { dest->Blink = 4; + if (!acknowledged) { + PlayUnitSound(unit, VoiceAcknowledging); + acknowledged = 1; + } SendCommandReturnGoods(unit, dest, flush); continue; } @@ -273,6 +297,10 @@ void DoRightButton(int sx, int sy) (dest->Player == unit->Player || (dest->Player->Index == PlayerNumNeutral))) { dest->Blink = 4; + if (!acknowledged) { + PlayUnitSound(unit, VoiceAcknowledging); + acknowledged = 1; + } SendCommandResource(unit, dest, flush); continue; } @@ -285,6 +313,10 @@ void DoRightButton(int sx, int sy) Map.ForestOnMap(x, y) && ((unit->CurrentResource != res) || (unit->ResourcesHeld < type->ResInfo[res]->ResourceCapacity))) { + if (!acknowledged) { + PlayUnitSound(unit, VoiceAcknowledging); + acknowledged = 1; + } SendCommandResourceLoc(unit, x, y, flush); break; } @@ -298,10 +330,18 @@ void DoRightButton(int sx, int sy) if (UnitUnderCursor != NULL && dest != NULL && dest != unit && (dest->Player == unit->Player || unit->IsAllied(dest))) { dest->Blink = 4; + if (!acknowledged) { + PlayUnitSound(unit, VoiceAcknowledging); + acknowledged = 1; + } SendCommandFollow(unit, dest, flush); continue; } // Move + if (!acknowledged) { + PlayUnitSound(unit, VoiceAcknowledging); + acknowledged = 1; + } SendCommandMove(unit, x, y, flush); continue; } @@ -313,6 +353,10 @@ void DoRightButton(int sx, int sy) if (dest != NULL && unit->CurrentAction() != UnitActionBuilt) { if (unit->IsEnemy(dest)) { dest->Blink = 4; + if (!acknowledged) { + PlayUnitSound(unit, VoiceAttack); + acknowledged = 1; + } if (action == MouseActionSpellCast) { // This is for demolition squads and such Assert(unit->Type->CanCastSpell); @@ -331,6 +375,10 @@ void DoRightButton(int sx, int sy) if ((dest->Player == unit->Player || unit->IsAllied(dest)) && dest != unit) { dest->Blink = 4; + if (!acknowledged) { + PlayUnitSound(unit, VoiceAcknowledging); + acknowledged = 1; + } SendCommandFollow(unit, dest, flush); continue; } @@ -351,14 +399,30 @@ void DoRightButton(int sx, int sy) if ((KeyModifiers & ModifierControl)) { if (RightButtonAttacks) { SendCommandMove(unit, x, y, flush); + if (!acknowledged) { + PlayUnitSound(unit, VoiceAcknowledging); + acknowledged = 1; + } } else { + if (!acknowledged) { + PlayUnitSound(unit, VoiceAttack); + acknowledged = 1; + } SendCommandAttack(unit, x, y, NoUnitP, flush); } } else { if (RightButtonAttacks) { + if (!acknowledged) { + PlayUnitSound(unit, VoiceAttack); + acknowledged = 1; + } SendCommandAttack(unit, x, y, NoUnitP, flush); } else { // Note: move is correct here, right default is move + if (!acknowledged) { + PlayUnitSound(unit, VoiceAcknowledging); + acknowledged = 1; + } SendCommandMove(unit, x, y, flush); } } @@ -371,6 +435,10 @@ void DoRightButton(int sx, int sy) (dest && dest != unit) && (dest->Player == unit->Player || unit->IsAllied(dest))) { dest->Blink = 4; + if (!acknowledged) { + PlayUnitSound(unit, VoiceAcknowledging); + acknowledged = 1; + } SendCommandFollow(unit, dest, flush); continue; } @@ -383,6 +451,10 @@ void DoRightButton(int sx, int sy) dest->Player == unit->Player) { dest->Blink = 4; SendCommandReturnGoods(dest, unit, flush); + if (!acknowledged) { + PlayUnitSound(unit, VoiceAcknowledging); + acknowledged = 1; + } continue; } // tell to go and harvest from a building @@ -403,15 +475,27 @@ void DoRightButton(int sx, int sy) if (dest != NULL && dest->Type->GivesResource && dest->Type->CanHarvest && (dest->Player == unit->Player || dest->Player->Index == PlayerNumNeutral)) { dest->Blink = 4; + if (!acknowledged) { + PlayUnitSound(unit, VoiceAcknowledging); + acknowledged = 1; + } SendCommandResource(unit, dest, flush); continue; } // FIXME: support harvesting more types of terrain. if (Map.IsFieldExplored(unit->Player, x, y) && Map.ForestOnMap(x, y)) { + if (!acknowledged) { + PlayUnitSound(unit, VoiceAcknowledging); + acknowledged = 1; + } SendCommandResourceLoc(unit, x, y, flush); break; } } + if (!acknowledged) { + PlayUnitSound(unit, VoiceAcknowledging); + acknowledged = 1; + } SendCommandMove(unit, x, y, flush); } @@ -1246,7 +1330,15 @@ static void SendCommand(int sx, int sy) if (ret) { // Acknowledge the command with first selected unit. for (int i = 0; i < NumSelected; ++i) { - if (Selected[i]->Type->Sound.Acknowledgement.Sound) { + if (ret==ButtonAttack || ret==ButtonAttackGround || ret==ButtonSpellCast) { + if (Selected[i]->Type->Sound.Attack.Sound) { + PlayUnitSound(Selected[i], VoiceAttack); + break; + } else if (Selected[i]->Type->Sound.Acknowledgement.Sound) { + PlayUnitSound(Selected[i], VoiceAcknowledging); + break; + } + } else if (Selected[i]->Type->Sound.Acknowledgement.Sound) { PlayUnitSound(Selected[i], VoiceAcknowledging); break; } @@ -1502,7 +1594,7 @@ void UIHandleButtonDown(unsigned button) // 0 Test build, don't really build if (CanBuildUnitType(Selected[0], CursorBuilding, x, y, 0) && (explored || ReplayRevealMap)) { - PlayGameSound(GameSounds.PlacementSuccess.Sound, + PlayGameSound(GameSounds.PlacementSuccess[ThisPlayer->Race].Sound, MaxSampleVolume); for (int i = 0; i < NumSelected; ++i) { SendCommandBuildBuilding(Selected[i], x, y, CursorBuilding, @@ -1512,7 +1604,7 @@ void UIHandleButtonDown(unsigned button) CancelBuildingMode(); } } else { - PlayGameSound(GameSounds.PlacementError.Sound, + PlayGameSound(GameSounds.PlacementError[ThisPlayer->Race].Sound, MaxSampleVolume); } } else { diff --git a/src/unit/script_unittype.cpp b/src/unit/script_unittype.cpp index 745c3203e..22d1707a9 100644 --- a/src/unit/script_unittype.cpp +++ b/src/unit/script_unittype.cpp @@ -954,6 +954,10 @@ static int CclDefineUnitType(lua_State *l) lua_rawgeti(l, -1, k + 1); type->Sound.Acknowledgement.Name = LuaToString(l, -1); lua_pop(l, 1); + } else if (!strcmp(value, "attack")) { + lua_rawgeti(l, -1, k + 1); + type->Sound.Attack.Name = LuaToString(l, -1); + lua_pop(l, 1); } else if (!strcmp(value, "ready")) { lua_rawgeti(l, -1, k + 1); type->Sound.Ready.Name = LuaToString(l, -1); diff --git a/src/unit/unit.cpp b/src/unit/unit.cpp index 501d3853f..6b6407ae0 100644 --- a/src/unit/unit.cpp +++ b/src/unit/unit.cpp @@ -3142,6 +3142,7 @@ void HitUnit(CUnit *attacker, CUnit *target, int damage) } /* Target Reaction on Hit */ + if (target->Player->AiEnabled){ switch(target->CurrentAction()) { case UnitActionTrain: case UnitActionUpgradeTo: @@ -3158,12 +3159,12 @@ void HitUnit(CUnit *attacker, CUnit *target, int damage) // return; case UnitActionResource: - if (target->SubAction >= 65/* SUB_STOP_GATHERING */) + if (target->SubAction >= 65) { //Normal return to depot return; } - if (target->SubAction > 55 /* SUB_START_GATHERING */ && + if (target->SubAction > 55 && target->ResourcesHeld > 0) { //escape to Depot with this what you have; target->Data.ResWorker.DoneHarvesting = 1; @@ -3184,11 +3185,12 @@ void HitUnit(CUnit *attacker, CUnit *target, int damage) default: break; } + } // // Attack units in range (which or the attacker?) // - if (attacker && target->IsAgressive()) { + if (attacker && target->IsAgressive() && target->CanMove()) { if (RevealAttacker && CanTarget(target->Type, attacker->Type)) { // Reveal Unit that is attacking goal = attacker; @@ -3200,6 +3202,8 @@ void HitUnit(CUnit *attacker, CUnit *target, int damage) goal = AttackUnitsInReactRange(target); } } + if (target->CurrentAction()!=UnitActionStill && !target->Player->AiEnabled) + return; if (goal) { if (target->SavedOrder.Action == UnitActionStill) { // FIXME: should rewrite command handling diff --git a/src/video/cursor.cpp b/src/video/cursor.cpp index 3346fd05b..e2a74854c 100644 --- a/src/video/cursor.cpp +++ b/src/video/cursor.cpp @@ -232,6 +232,12 @@ static void DrawBuildingCursor(void) DrawShadow(CursorBuilding, CursorBuilding->StillFrame, x, y); DrawUnitType(CursorBuilding, CursorBuilding->Sprite, ThisPlayer->Index, CursorBuilding->StillFrame, x, y); + if (CursorBuilding->CanAttack && CursorBuilding->Stats->Variables[ATTACKRANGE_INDEX].Value>0){ + Video.DrawCircleClip(ColorRed, + x + CursorBuilding->TileWidth * TileSizeX / 2, + y + CursorBuilding->TileHeight * TileSizeY / 2, + (CursorBuilding->Stats->Variables[ATTACKRANGE_INDEX].Max + (CursorBuilding->TileWidth - 1)) * TileSizeX + 1); + } // // Draw the allow overlay diff --git a/src/video/sdl.cpp b/src/video/sdl.cpp index 5e72c376e..4a80b1c0d 100644 --- a/src/video/sdl.cpp +++ b/src/video/sdl.cpp @@ -48,13 +48,16 @@ #include <string.h> #include <limits.h> + #ifndef _MSC_VER #include <sys/time.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #endif + #include "SDL.h" + #ifdef USE_GLES #include "SDL_gles.h" #include "GLES/gl.h" @@ -69,6 +72,7 @@ #ifdef USE_WIN32 #include "net_lowlevel.h" #include "SDL_syswm.h" +#include <shellapi.h> #endif #ifdef USE_MAEMO