Compare commits

...

11 Commits

Author SHA1 Message Date
hacker
d1c5b19697 Updated .NET to 8
Some checks failed
Continuous Integration / Linux (.NET 8.0) (push) Has been cancelled
Continuous Integration / Windows (.NET 8.0) (push) Has been cancelled
2026-07-20 20:41:41 +01:00
hacker
7e801c6fd7 Updated version
Some checks failed
Continuous Integration / Linux (.NET 8.0) (push) Has been cancelled
Continuous Integration / Windows (.NET 8.0) (push) Has been cancelled
2026-07-20 20:27:09 +01:00
hacker
93619f2766 Added Dockerfile 2026-07-20 20:22:44 +01:00
hacker
7c44f94755 Log chat messages on the server 2026-07-20 20:22:41 +01:00
Gustas
5c51f458f2 Silence autosave audio notification 2026-02-22 17:17:59 +00:00
Gustas
413aa00ce6 Don't play chat sounds when loading games 2026-02-22 17:17:59 +00:00
Gustas
0a9b493c14 Moved game save notification to StartGameNotification 2026-02-22 17:17:59 +00:00
N.N
3a86c035b3 Rework D2k campaign scripts:
- Add InitialProductionDelay
- Different attacksDelays for early game and late game
- Adjust T3 unit production for selected missions
- Implement InitialAttackDelay, TimeBetweenAttacks
- Implement routines for idle units
- Emergency mode
- Airstrike rework
2026-02-22 17:04:04 +02:00
Vapre
0a933ba09c CellLayer, use span. 2026-02-17 18:16:49 +02:00
Matthias Mailänder
6b04dbc210 Point to the log for long stack traces. 2026-02-17 18:11:26 +02:00
Matthias Mailänder
c651f733a7 Write to error output stream. 2026-02-17 18:11:26 +02:00
141 changed files with 5450 additions and 522 deletions

29
Dockerfile Normal file
View File

@@ -0,0 +1,29 @@
FROM mcr.microsoft.com/dotnet/sdk:8.0
RUN \
apt-get update; \
apt-get -y upgrade; \
apt-get install -y --no-install-recommends \
curl \
wget \
make \
python3 \
unzip \
mono-complete
RUN useradd -d /home/openra -m -s /sbin/nologin openra
WORKDIR /home/openra
COPY . .
RUN chown -R openra:openra .
USER openra
RUN make
EXPOSE 1234
ENTRYPOINT ["./launch-dedicated.sh"]

View File

@@ -40,19 +40,19 @@ namespace OpenRA
if (Size != anotherLayer.Size || GridType != anotherLayer.GridType) if (Size != anotherLayer.Size || GridType != anotherLayer.GridType)
throw new ArgumentException("Layers must have a matching size and shape (grid type).", nameof(anotherLayer)); throw new ArgumentException("Layers must have a matching size and shape (grid type).", nameof(anotherLayer));
Array.Copy(anotherLayer.Entries, Entries, Entries.Length); anotherLayer.Entries.AsSpan().CopyTo(Entries);
} }
/// <summary>Clears the layer contents with their default value.</summary> /// <summary>Clears the layer contents with their default value.</summary>
public virtual void Clear() public virtual void Clear()
{ {
Array.Clear(Entries, 0, Entries.Length); Entries.AsSpan().Clear();
} }
/// <summary>Clears the layer contents with a known value.</summary> /// <summary>Clears the layer contents with a known value.</summary>
public virtual void Clear(T clearValue) public virtual void Clear(T clearValue)
{ {
Array.Fill(Entries, clearValue); Entries.AsSpan().Fill(clearValue);
} }
public IEnumerator<T> GetEnumerator() public IEnumerator<T> GetEnumerator()
@@ -64,5 +64,15 @@ namespace OpenRA
{ {
return GetEnumerator(); return GetEnumerator();
} }
public ReadOnlyMemory<T> AsReadOnlyMemory()
{
return Entries.AsMemory();
}
public Memory<T> AsMemory()
{
return Entries.AsMemory();
}
} }
} }

View File

@@ -55,14 +55,9 @@ namespace OpenRA
return Bounds.Contains(uv.U, uv.V); return Bounds.Contains(uv.U, uv.V);
} }
public int IndexOf(T value, int startIndex)
{
return Array.IndexOf(Entries, value, startIndex);
}
public void SetAll(T value) public void SetAll(T value)
{ {
Array.Fill(Entries, value); Entries.AsSpan().Fill(value);
} }
} }
} }

View File

@@ -269,6 +269,11 @@ namespace OpenRA
return new Order(order, null, false) { IsImmediate = isImmediate, TargetString = targetString }; return new Order(order, null, false) { IsImmediate = isImmediate, TargetString = targetString };
} }
public static Order FromTargetString(string order, string targetString, bool isImmediate, uint extraData)
{
return new Order(order, null, false) { IsImmediate = isImmediate, TargetString = targetString, ExtraData = extraData };
}
public static Order FromGroupedOrder(Order grouped, Actor subject) public static Order FromGroupedOrder(Order grouped, Actor subject)
{ {
return new Order( return new Order(

View File

@@ -30,9 +30,6 @@ namespace OpenRA.Network
[FluentReference] [FluentReference]
const string GameStarted = "notification-game-has-started"; const string GameStarted = "notification-game-has-started";
[FluentReference]
const string GameSaved = "notification-game-saved";
[FluentReference("player")] [FluentReference("player")]
const string GamePaused = "notification-game-paused"; const string GamePaused = "notification-game-paused";
@@ -213,11 +210,8 @@ namespace OpenRA.Network
} }
case "GameSaved": case "GameSaved":
if (!orderManager.World.IsReplay)
TextNotificationsManager.AddSystemLine(GameSaved);
foreach (var nsr in orderManager.World.WorldActor.TraitsImplementing<INotifyGameSaved>()) foreach (var nsr in orderManager.World.WorldActor.TraitsImplementing<INotifyGameSaved>())
nsr.GameSaved(orderManager.World); nsr.GameSaved(orderManager.World, order.ExtraData != 0);
break; break;
case "PauseGame": case "PauseGame":

View File

@@ -51,9 +51,6 @@ namespace OpenRA.Server
[FluentReference] [FluentReference]
const string CustomRules = "notification-custom-rules"; const string CustomRules = "notification-custom-rules";
[FluentReference]
const string BotsDisabled = "notification-map-bots-disabled";
[FluentReference] [FluentReference]
const string TwoHumansRequired = "notification-two-humans-required"; const string TwoHumansRequired = "notification-two-humans-required";
@@ -587,7 +584,8 @@ namespace OpenRA.Server
Log.Write("server", $"{client.Name} ({newConn.EndPoint}) has joined the game."); Log.Write("server", $"{client.Name} ({newConn.EndPoint}) has joined the game.");
SendFluentMessage(Joined, "player", client.Name); var otherConns = Conns.Where(c => c != newConn).ToArray();
SendFluentMessage(otherConns.AsSpan(), Joined, "player", client.Name);
if (Type == ServerType.Dedicated) if (Type == ServerType.Dedicated)
{ {
@@ -598,15 +596,13 @@ namespace OpenRA.Server
var motd = File.ReadAllText(motdFile); var motd = File.ReadAllText(motdFile);
if (!string.IsNullOrEmpty(motd)) if (!string.IsNullOrEmpty(motd))
SendOrderTo(newConn, "Message", motd); SendOrderTo(newConn, "Message", motd);
if (!LobbyInfo.GlobalSettings.EnableSingleplayer)
SendFluentMessageTo(newConn, TwoHumansRequired);
} }
if ((LobbyInfo.GlobalSettings.MapStatus & Session.MapStatus.UnsafeCustomRules) != 0) if (Type != ServerType.Local && (LobbyInfo.GlobalSettings.MapStatus & Session.MapStatus.UnsafeCustomRules) != 0)
SendFluentMessageTo(newConn, CustomRules); SendFluentMessageTo(newConn, CustomRules);
if (!LobbyInfo.GlobalSettings.EnableSingleplayer)
SendFluentMessageTo(newConn, TwoHumansRequired);
else if (Map.Players.Players.Where(p => p.Value.Playable).All(p => !p.Value.AllowBots))
SendFluentMessageTo(newConn, BotsDisabled);
} }
} }
@@ -893,6 +889,17 @@ namespace OpenRA.Server
RecordOrder(frame, data, From); RecordOrder(frame, data, From);
} }
public void DispatchServerOrdersToClients(ReadOnlySpan<Connection> conns, byte[] data, int frame = 0)
{
const int From = 0;
var frameData = CreateFrame(From, frame, data);
foreach (var c in conns)
if (c.Validated)
DispatchFrameToClient(c, From, frameData);
RecordOrder(frame, data, From);
}
public void ReceiveOrders(Connection conn, int frame, byte[] data) public void ReceiveOrders(Connection conn, int frame, byte[] data)
{ {
// Make sure we don't accidentally forward on orders from clients who we have just dropped // Make sure we don't accidentally forward on orders from clients who we have just dropped
@@ -952,9 +959,15 @@ namespace OpenRA.Server
} }
public void SendFluentMessage(string key, params object[] args) public void SendFluentMessage(string key, params object[] args)
{
var conns = Conns.ToArray();
SendFluentMessage(conns, key, args);
}
public void SendFluentMessage(ReadOnlySpan<Connection> conns, string key, params object[] args)
{ {
var text = FluentMessage.Serialize(key, args); var text = FluentMessage.Serialize(key, args);
DispatchServerOrdersToClients(Order.FromTargetString("FluentMessage", text, true)); DispatchServerOrdersToClients(conns, Order.FromTargetString("FluentMessage", text, true).Serialize());
if (Type == ServerType.Dedicated) if (Type == ServerType.Dedicated)
WriteLineWithTimeStamp(FluentProvider.GetMessage(key, args)); WriteLineWithTimeStamp(FluentProvider.GetMessage(key, args));
@@ -1004,9 +1017,12 @@ namespace OpenRA.Server
} }
case "Chat": case "Chat":
{ {
if (!IsMultiplayer || !playerMessageTracker.IsPlayerAtFloodLimit(conn)) var client = GetClient(conn);
DispatchOrdersToClients(conn, 0, o.Serialize()); Console.WriteLine($"[{DateTime.Now.ToString(Settings.TimestampFormat)}] {client.Name}: {o.TargetString}");
if (Type == ServerType.Local || !playerMessageTracker.IsPlayerAtFloodLimit(conn))
DispatchOrdersToClients(conn, 0, o.Serialize());
break; break;
} }
@@ -1043,7 +1059,7 @@ namespace OpenRA.Server
Directory.CreateDirectory(baseSavePath); Directory.CreateDirectory(baseSavePath);
GameSave.Save(Path.Combine(baseSavePath, filename)); GameSave.Save(Path.Combine(baseSavePath, filename));
DispatchServerOrdersToClients(Order.FromTargetString("GameSaved", filename, true)); DispatchServerOrdersToClients(Order.FromTargetString("GameSaved", filename, true, o.ExtraData));
} }
break; break;

View File

@@ -183,12 +183,20 @@ namespace OpenRA.Traits
else else
{ {
// PERF: Most cells are unchanged, use IndexOf for fast vectorized search. // PERF: Most cells are unchanged, use IndexOf for fast vectorized search.
var index = touched.IndexOf(true, 0); var span = touched.AsMemory().Span;
var index = span.IndexOf(true);
while (index != -1) while (index != -1)
{ {
touched[index] = false; span[index] = false;
UpdateCell(index, self); UpdateCell(index, self);
index = touched.IndexOf(true, index + 1);
if (index < span.Length - 1)
{
var sliceIndex = span[++index..].IndexOf(true);
index = sliceIndex == -1 ? -1 : index + sliceIndex;
}
else
index = -1;
} }
} }

View File

@@ -373,7 +373,7 @@ namespace OpenRA.Traits
public interface IPostWorldLoaded { void PostWorldLoaded(World w, WorldRenderer wr); } public interface IPostWorldLoaded { void PostWorldLoaded(World w, WorldRenderer wr); }
public interface INotifyGameLoading { void GameLoading(World w); } public interface INotifyGameLoading { void GameLoading(World w); }
public interface INotifyGameLoaded { void GameLoaded(World w); } public interface INotifyGameLoaded { void GameLoaded(World w); }
public interface INotifyGameSaved { void GameSaved(World w); } public interface INotifyGameSaved { void GameSaved(World w, bool isAutoSave); }
public interface IGameSaveTraitData public interface IGameSaveTraitData
{ {

View File

@@ -562,7 +562,7 @@ namespace OpenRA
} }
} }
public void RequestGameSave(string filename) public void RequestGameSave(string filename, bool isAutosave)
{ {
// Allow traits to save arbitrary data that will be passed back via IGameSaveTraitData.ResolveTraitData // Allow traits to save arbitrary data that will be passed back via IGameSaveTraitData.ResolveTraitData
// at the end of the save restoration // at the end of the save restoration
@@ -580,7 +580,8 @@ namespace OpenRA
i++; i++;
} }
IssueOrder(Order.FromTargetString("CreateGameSave", filename, true)); var extraData = isAutosave ? 1u : 0u;
IssueOrder(Order.FromTargetString("CreateGameSave", filename, true, extraData));
} }
public bool Disposing; public bool Disposing;

View File

@@ -35,7 +35,7 @@ namespace OpenRA.Mods.Cnc.UtilityCommands
public override void ValidateMapFormat(int format) public override void ValidateMapFormat(int format)
{ {
if (format < 2) if (format < 2)
Console.WriteLine($"ERROR: Detected NewINIFormat {format}. Are you trying to import a Tiberian Dawn map?"); Console.Error.WriteLine($"Detected NewINIFormat {format}. Are you trying to import a Tiberian Dawn map?");
} }
// Mapping from RA95 overlay index to type string // Mapping from RA95 overlay index to type string

View File

@@ -33,7 +33,7 @@ namespace OpenRA.Mods.Cnc.UtilityCommands
public override void ValidateMapFormat(int format) public override void ValidateMapFormat(int format)
{ {
if (format > 1) if (format > 1)
Console.WriteLine($"ERROR: Detected NewINIFormat {format}. Are you trying to import a Red Alert map?"); Console.Error.WriteLine($"Detected NewINIFormat {format}. Are you trying to import a Red Alert map?");
} }
static readonly FrozenDictionary<string, (byte Type, byte Index)> OverlayResourceMapping = new Dictionary<string, (byte Type, byte Index)> static readonly FrozenDictionary<string, (byte Type, byte Index)> OverlayResourceMapping = new Dictionary<string, (byte Type, byte Index)>

View File

@@ -80,7 +80,7 @@ namespace OpenRA.Mods.Common.Traits
var dateTime = DateTime.UtcNow.ToString("yyyy-MM-ddTHHmmssZ", CultureInfo.InvariantCulture); var dateTime = DateTime.UtcNow.ToString("yyyy-MM-ddTHHmmssZ", CultureInfo.InvariantCulture);
var fileName = $"{AutoSavePattern}{dateTime}{SaveFileExtension}"; var fileName = $"{AutoSavePattern}{dateTime}{SaveFileExtension}";
self.World.RequestGameSave(fileName); self.World.RequestGameSave(fileName, true);
ticksUntilAutoSave = GetTicksBetweenAutosaves(self); ticksUntilAutoSave = GetTicksBetweenAutosaves(self);
} }

View File

@@ -64,11 +64,13 @@ namespace OpenRA.Mods.Common.Traits
} }
} }
void INotifyGameSaved.GameSaved(World world) void INotifyGameSaved.GameSaved(World world, bool isAutosave)
{ {
if (!world.IsReplay) if (!world.IsReplay)
{ {
Game.Sound.PlayNotification(world.Map.Rules, null, "Speech", info.SavedNotification, world.RenderPlayer?.Faction.InternalName); if (!isAutosave)
Game.Sound.PlayNotification(world.Map.Rules, null, "Speech", info.SavedNotification, world.RenderPlayer?.Faction.InternalName);
TextNotificationsManager.AddTransientLine(null, info.SavedTextNotification); TextNotificationsManager.AddTransientLine(null, info.SavedTextNotification);
} }
} }

View File

@@ -25,11 +25,16 @@ namespace OpenRA.Mods.Common.Widgets.Logic
public class MapGeneratorToolLogic : ChromeLogic public class MapGeneratorToolLogic : ChromeLogic
{ {
[FluentReference("name")] [FluentReference("name")]
const string StrGenerated = "notification-map-generator-generated"; const string MapGenerated = "notification-map-generator-generated";
[FluentReference] [FluentReference]
const string StrFailed = "notification-map-generator-failed"; const string MapGeneratorFailedTitle = "dialog-notification-map-generator-failed.title";
[FluentReference] [FluentReference]
const string StrFailedCancel = "label-map-generator-failed-cancel"; const string MapGeneratorFailedPrompt = "dialog-notification-map-generator-failed.prompt";
[FluentReference]
const string MapGeneratorFailedCancel = "dialog-notification-map-generator-failed.cancel";
readonly EditorActionManager editorActionManager; readonly EditorActionManager editorActionManager;
readonly World world; readonly World world;
@@ -239,14 +244,13 @@ namespace OpenRA.Mods.Common.Widgets.Logic
void DisplayError(Exception e) void DisplayError(Exception e)
{ {
// For any non-MapGenerationException, include more information for debugging purposes. var message = e is MapGenerationException ? e.Message : MapGeneratorFailedPrompt;
var message = e is MapGenerationException ? e.Message : e.ToString();
Log.Write("debug", e); Log.Write("debug", e);
ConfirmationDialogs.ButtonPrompt(modData, ConfirmationDialogs.ButtonPrompt(modData,
title: StrFailed, title: MapGeneratorFailedTitle,
text: message, text: message,
onCancel: () => { }, onCancel: () => { },
cancelText: StrFailedCancel); cancelText: MapGeneratorFailedCancel);
} }
void GenerateMap() void GenerateMap()
@@ -318,7 +322,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
editorActorLayer, editorActorLayer,
false); false);
var description = FluentProvider.GetMessage(StrGenerated, var description = FluentProvider.GetMessage(MapGenerated,
"name", FluentProvider.GetMessage(generator.Name)); "name", FluentProvider.GetMessage(generator.Name));
var action = new RandomMapEditorAction(editorBlit, description); var action = new RandomMapEditorAction(editorBlit, description);
editorActionManager.Add(action); editorActionManager.Add(action);

View File

@@ -377,7 +377,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
void Inner() void Inner()
{ {
world.RequestGameSave(filename); world.RequestGameSave(filename, false);
Ui.CloseWindow(); Ui.CloseWindow();
onExit(); onExit();
} }

View File

@@ -33,6 +33,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic
[FluentReference] [FluentReference]
const string ConfigureBots = "options-slot-admin.configure-bots"; const string ConfigureBots = "options-slot-admin.configure-bots";
[FluentReference]
const string BotsDisabled = "notification-map-bots-disabled";
[FluentReference("count")] [FluentReference("count")]
const string NumberTeams = "options-slot-admin.teams-count"; const string NumberTeams = "options-slot-admin.teams-count";
@@ -588,6 +591,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic
playerLeftSound = yaml.Value; playerLeftSound = yaml.Value;
if (logicArgs.TryGetValue("LobbyOptionChangedSound", out yaml)) if (logicArgs.TryGetValue("LobbyOptionChangedSound", out yaml))
lobbyOptionChangedSound = yaml.Value; lobbyOptionChangedSound = yaml.Value;
Game.Sound.PlayNotification(modRules, null, "Sounds", playerJoinedSound, null);
} }
bool disposed; bool disposed;
@@ -709,6 +714,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic
if (newLobbyOptions.TryGetValue(o.Id, out var s) && (lobbyOptions.TryGetValue(o.Id, out var old) ? s.Value != old.Value : s.Value != o.DefaultValue)) if (newLobbyOptions.TryGetValue(o.Id, out var s) && (lobbyOptions.TryGetValue(o.Id, out var old) ? s.Value != old.Value : s.Value != o.DefaultValue))
TextNotificationsManager.AddSystemLine(OptionValue, "name", o.Name, "value", o.Label(s.Value)); TextNotificationsManager.AddSystemLine(OptionValue, "name", o.Name, "value", o.Label(s.Value));
if (map.Players.Players.Where(p => p.Value.Playable).All(p => !p.Value.AllowBots))
TextNotificationsManager.AddSystemLine(BotsDisabled);
lobbyOptions = newLobbyOptions; lobbyOptions = newLobbyOptions;
} }

View File

@@ -1,6 +1,6 @@
Metadata: Metadata:
Title: All mods Title: All mods
Version: {DEV_VERSION} Version: playtest-20260222
Hidden: true Hidden: true
FileSystem: DefaultFileSystem FileSystem: DefaultFileSystem

View File

@@ -1,6 +1,6 @@
Metadata: Metadata:
Title: mod-title Title: mod-title
Version: {DEV_VERSION} Version: playtest-20260222
Hidden: true Hidden: true
FileSystem: DefaultFileSystem FileSystem: DefaultFileSystem

View File

@@ -21,6 +21,8 @@ notification-ally-under-attack = Our ally is under attack.
notification-silos-needed = Silos needed. notification-silos-needed = Silos needed.
## world.yaml ## world.yaml
notification-game-saved = Game saved.
options-starting-units = options-starting-units =
.mcv-only = MCV Only .mcv-only = MCV Only
.light-support = Light Support .light-support = Light Support

View File

@@ -1,6 +1,6 @@
Metadata: Metadata:
Title: mod-title Title: mod-title
Version: {DEV_VERSION} Version: playtest-20260222
Website: https://www.openra.net Website: https://www.openra.net
WebIcon32: https://www.openra.net/images/icons/cnc_32x32.png WebIcon32: https://www.openra.net/images/icons/cnc_32x32.png
WindowTitle: mod-windowtitle WindowTitle: mod-windowtitle
@@ -39,7 +39,7 @@ FileSystem: ContentInstallerFileSystem
MapFolders: MapFolders:
cnc|maps: System cnc|maps: System
~^SupportDir|maps/cnc/{DEV_VERSION}: User ~^SupportDir|maps/cnc/playtest-20260222: User
Rules: Rules:
cnc|rules/misc.yaml cnc|rules/misc.yaml

View File

@@ -265,6 +265,11 @@ World:
ObjectivesPanel: ObjectivesPanel:
PanelName: SKIRMISH_STATS PanelName: SKIRMISH_STATS
RadarPings: RadarPings:
StartGameNotification:
Notification:
LoadedNotification:
SavedNotification:
SavedTextNotification: notification-game-saved
LoadWidgetAtGameStart: LoadWidgetAtGameStart:
ShellmapRoot: MENU_BACKGROUND ShellmapRoot: MENU_BACKGROUND
ScriptTriggers: ScriptTriggers:

View File

@@ -7,7 +7,6 @@ button-quit = Quit
## Server Orders ## Server Orders
notification-custom-rules = This map contains custom rules. Game experience may change. notification-custom-rules = This map contains custom rules. Game experience may change.
notification-map-bots-disabled = Bots have been disabled on this map.
notification-two-humans-required = This server requires at least two human players to start a match. notification-two-humans-required = This server requires at least two human players to start a match.
notification-unknown-server-command = Unknown server command: { $command }. notification-unknown-server-command = Unknown server command: { $command }.
notification-admin-start-game = Only the host can start the game. notification-admin-start-game = Only the host can start the game.
@@ -87,7 +86,6 @@ notification-lobby-disconnected = { $player } has left.
## UnitOrders ## UnitOrders
notification-game-has-started = The game has started. notification-game-has-started = The game has started.
notification-game-saved = Game saved.
notification-game-paused = The game has been paused by { $player }. notification-game-paused = The game has been paused by { $player }.
notification-game-unpaused = The game has been un-paused by { $player }. notification-game-unpaused = The game has been un-paused by { $player }.
@@ -205,6 +203,7 @@ label-bot-player = AI Player
## LobbyLogic ## LobbyLogic
notification-lobby-option = { $name }: { $value }. notification-lobby-option = { $name }: { $value }.
notification-lobby-option-changed = { $name } changed to { $value }. notification-lobby-option-changed = { $name } changed to { $value }.
notification-map-bots-disabled = Bots have been disabled on this map.
## IngameMenuLogic ## IngameMenuLogic
menu-ingame = menu-ingame =
@@ -1120,9 +1119,12 @@ keycode =
.mouse5 = Mouse 5 .mouse5 = Mouse 5
## MapGeneratorToolLogic ## MapGeneratorToolLogic
label-map-generator-failed-cancel = Dismiss
notification-map-generator-generated = Generated using { $name } notification-map-generator-generated = Generated using { $name }
notification-map-generator-failed = Map generation failed
dialog-notification-map-generator-failed =
.title = Map generation failed
.prompt = See debug.log for details.
.cancel = Dismiss
## EditorTilingPathBrush ## EditorTilingPathBrush
notification-tiling-path-started = Started tiling path notification-tiling-path-started = Started tiling path

View File

@@ -1,6 +1,6 @@
Metadata: Metadata:
Title: mod-title Title: mod-title
Version: {DEV_VERSION} Version: playtest-20260222
Hidden: true Hidden: true
FileSystem: DefaultFileSystem FileSystem: DefaultFileSystem

View File

@@ -76,6 +76,7 @@ smuggler-leader = Smuggler Leader.
were-warned-will-pay = You were warned. Now you will pay. were-warned-will-pay = You were warned. Now you will pay.
destroy-smugglers-mercenaries = Destroy the Smugglers and their mercenaries. destroy-smugglers-mercenaries = Destroy the Smugglers and their mercenaries.
capture-harkonnen-barracks-release-hostages = Capture the Harkonnen barracks to release the hostages. capture-harkonnen-barracks-release-hostages = Capture the Harkonnen barracks to release the hostages.
use-engineer-hint = Use engineers to reclaim destroyed vehicles.
## harkonnen-01ab, harkonnen-03ab ## harkonnen-01ab, harkonnen-03ab
eliminate-atreides-units-reinforcements = Eliminate all Atreides forces and reinforcements in the area. eliminate-atreides-units-reinforcements = Eliminate all Atreides forces and reinforcements in the area.
@@ -112,6 +113,8 @@ destroy-ordos = Destroy the Ordos.
## harkonnen-06ab ## harkonnen-06ab
ixian-transports-detected = Ixian transports detected. ixian-transports-detected = Ixian transports detected.
capture-destroy-ordos-starport = Capture or destroy the Ordos Starport. capture-destroy-ordos-starport = Capture or destroy the Ordos Starport.
smuggler-warning-harkonnen = Mind your own business Harkonnen.
smuggler-warning-ordos = Mind your own business Ordos.
## harkonnen-06ab, harkonnen-09ab ## harkonnen-06ab, harkonnen-09ab
smugglers-now-hostile = The Smugglers are now hostile! smugglers-now-hostile = The Smugglers are now hostile!
@@ -132,6 +135,8 @@ atreides-commander = Atreides Commander
## harkonnen-09ab ## harkonnen-09ab
build-deploy-mcv = Build and deploy an MCV to establish a Construction Yard. build-deploy-mcv = Build and deploy an MCV to establish a Construction Yard.
husk-reclaimed-harkonnen = We reclaimed some Atreides wreckage from battle.
engineers-hint = Our engineers maybe find then useful.
## ordos-01ab, ordos-02ab, ordos-03ab, ordos-04, ordos-05 ## ordos-01ab, ordos-02ab, ordos-03ab, ordos-04, ordos-05
outpost-not-captured-destroyed = Do not let the Outpost be captured or destroyed. outpost-not-captured-destroyed = Do not let the Outpost be captured or destroyed.

View File

@@ -22,6 +22,8 @@ notification-cannot-build-here = Cannot build here.
notification-one-of-our-buildings-has-been-captured = One of our buildings has been captured. notification-one-of-our-buildings-has-been-captured = One of our buildings has been captured.
## world.yaml ## world.yaml
notification-game-saved = Game saved.
dropdown-map-worms = dropdown-map-worms =
.label = Worms .label = Worms
.description = Worms roam the map, devouring unprepared forces .description = Worms roam the map, devouring unprepared forces

View File

@@ -14,7 +14,7 @@ AttackGroupSize =
hard = 10 hard = 10
} }
AttackDelays = ProductionDelays =
{ {
easy = { DateTime.Seconds(4), DateTime.Seconds(9) }, easy = { DateTime.Seconds(4), DateTime.Seconds(9) },
normal = { DateTime.Seconds(2), DateTime.Seconds(7) }, normal = { DateTime.Seconds(2), DateTime.Seconds(7) },
@@ -25,10 +25,13 @@ HarkonnenInfantryTypes = { "light_inf" }
ActivateAI = function() ActivateAI = function()
IdlingUnits[Harkonnen] = { } IdlingUnits[Harkonnen] = { }
Defending[Harkonnen] = { }
AttackDelay[Harkonnen] = 6000 * DifficultyModifier[Difficulty]
TimeBetweenAttacks[Harkonnen] = 5000 * DifficultyModifier[Difficulty]
DefendAndRepairBase(Harkonnen, HarkonnenBase, 0.75, AttackGroupSize[Difficulty]) DefendAndRepairBase(Harkonnen, HarkonnenBase, 0.75, AttackGroupSize[Difficulty])
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end local delay = function() return Utils.RandomInteger(ProductionDelays[Difficulty][1], ProductionDelays[Difficulty][2] + 1) end
local toBuild = function() return HarkonnenInfantryTypes end local toBuild = function() return HarkonnenInfantryTypes end
local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5 attackThresholdSize = AttackGroupSize[Difficulty] * 2.5
ProduceUnits(Harkonnen, HBarracks, delay, toBuild, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(Harkonnen, HBarracks, delay, toBuild, AttackGroupSize[Difficulty], attackThresholdSize)
end end

View File

@@ -168,6 +168,13 @@ Actors:
HarkonnenRally4: waypoint HarkonnenRally4: waypoint
Owner: Neutral Owner: Neutral
Location: 30,28 Location: 30,28
Actor5: harvester.debris
Owner: Creeps
Facing: 384
Location: 18,18
Actor25: crate
Owner: Neutral
Location: 42,39
Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml

View File

@@ -14,7 +14,7 @@ AttackGroupSize =
hard = 10 hard = 10
} }
AttackDelays = ProductionDelays =
{ {
easy = { DateTime.Seconds(4), DateTime.Seconds(9) }, easy = { DateTime.Seconds(4), DateTime.Seconds(9) },
normal = { DateTime.Seconds(2), DateTime.Seconds(7) }, normal = { DateTime.Seconds(2), DateTime.Seconds(7) },
@@ -25,10 +25,14 @@ HarkonnenInfantryTypes = { "light_inf" }
ActivateAI = function() ActivateAI = function()
IdlingUnits[Harkonnen] = { } IdlingUnits[Harkonnen] = { }
Defending[Harkonnen] = {}
AttackDelay[Harkonnen] = 6000 * DifficultyModifier[Difficulty]
TimeBetweenAttacks[Harkonnen] = 5000 * DifficultyModifier[Difficulty]
LastHarvesterEaten[Harkonnen] = true
DefendAndRepairBase(Harkonnen, HarkonnenBase, 0.75, AttackGroupSize[Difficulty]) DefendAndRepairBase(Harkonnen, HarkonnenBase, 0.75, AttackGroupSize[Difficulty])
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end local delay = function() return Utils.RandomInteger(ProductionDelays[Difficulty][1], ProductionDelays[Difficulty][2] + 1) end
local toBuild = function() return HarkonnenInfantryTypes end local toBuild = function() return HarkonnenInfantryTypes end
local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5 attackThresholdSize = AttackGroupSize[Difficulty] * 2.5
ProduceUnits(Harkonnen, HBarracks, delay, toBuild, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(Harkonnen, HBarracks, delay, toBuild, AttackGroupSize[Difficulty], attackThresholdSize)
end end

View File

@@ -138,6 +138,9 @@ Actors:
HarkonnenRally4: waypoint HarkonnenRally4: waypoint
Owner: Neutral Owner: Neutral
Location: 30,28 Location: 30,28
Actor4: crate
Owner: Neutral
Location: 12,21
Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml

View File

@@ -13,7 +13,8 @@ AttackGroupSize =
normal = 8, normal = 8,
hard = 10 hard = 10
} }
AttackDelays =
ProductionDelays =
{ {
easy = { DateTime.Seconds(4), DateTime.Seconds(9) }, easy = { DateTime.Seconds(4), DateTime.Seconds(9) },
normal = { DateTime.Seconds(2), DateTime.Seconds(7) }, normal = { DateTime.Seconds(2), DateTime.Seconds(7) },
@@ -33,13 +34,16 @@ InitAIUnits = function()
end end
ActivateAI = function() ActivateAI = function()
Defending[Ordos] = { }
AttackDelay[Ordos] = 12000 * DifficultyModifier[Difficulty]
TimeBetweenAttacks[Ordos] = 5000 * DifficultyModifier[Difficulty]
LastHarvesterEaten[Ordos] = true LastHarvesterEaten[Ordos] = true
Trigger.AfterDelay(0, InitAIUnits) Trigger.AfterDelay(0, InitAIUnits)
OConyard.Produce(AtreidesUpgrades[1]) OConyard.Produce(AtreidesUpgrades[1])
OConyard.Produce(AtreidesUpgrades[2]) OConyard.Produce(AtreidesUpgrades[2])
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end local delay = function() return Utils.RandomInteger(ProductionDelays[Difficulty][1], ProductionDelays[Difficulty][2] + 1) end
local infantryToBuild = function() return { Utils.Random(OrdosInfantryTypes) } end local infantryToBuild = function() return { Utils.Random(OrdosInfantryTypes) } end
local vehiclesToBuild = function() return { Utils.Random(OrdosVehicleTypes) } end local vehiclesToBuild = function() return { Utils.Random(OrdosVehicleTypes) } end
local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5 local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5
@@ -49,4 +53,22 @@ ActivateAI = function()
ProduceUnits(Ordos, OBarracks, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(Ordos, OBarracks, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
ProduceUnits(Ordos, OLightFactory, delay, vehiclesToBuild, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(Ordos, OLightFactory, delay, vehiclesToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
end) end)
if Difficulty ~= "easy" then
Ordos.GrantCondition("base-rebuilder")
end
local productionTypes =
{
barracks = infantryToBuild,
light_factory = vehiclesToBuild,
}
Trigger.OnBuildingPlaced(Ordos, function(p, building)
table.insert(OrdosBase, building)
DefendAndRepairBase(Ordos, {building}, 0.75, AttackGroupSize[Difficulty] )
if productionTypes[building.Type] == nil then return end
ProduceUnits(Ordos, building, delay, productionTypes[building.Type], AttackGroupSize[Difficulty], attackThresholdSize)
end)
end end

View File

@@ -143,7 +143,6 @@ WorldLoaded = function()
end end
Trigger.OnRemovedFromWorld(AConyard, function() Trigger.OnRemovedFromWorld(AConyard, function()
-- Mission already failed, no need to check the other conditions as well -- Mission already failed, no need to check the other conditions as well
if checkResourceCapacity() then if checkResourceCapacity() then
return return

Binary file not shown.

View File

@@ -135,6 +135,20 @@ Actors:
OrdosRally2: waypoint OrdosRally2: waypoint
Owner: Neutral Owner: Neutral
Location: 39,30 Location: 39,30
Actor3: crate_explosion
Owner: Neutral
Location: 17,5
Actor4: carryall.debris
Owner: Neutral
Facing: 384
Location: 44,14
Actor6: combat_tank_h.debris
Facing: 384
Location: 18,52
Owner: Creeps
Actor7: crate_explosion
Owner: Neutral
Location: 4,52
Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml

View File

@@ -1,6 +1,33 @@
Player: Player:
PlayerResources: PlayerResources:
DefaultCash: 3000 DefaultCash: 3000
ExternalCondition@AI:
Condition: base-rebuilder
BaseBuilderBotModule@Ordos:
RequiresCondition: base-rebuilder
BuildingQueues: Building, Upgrade
MinimumExcessPower: 0
MaximumExcessPower: 250
MaxBaseRadius: 40
ConstructionYardTypes: construction_yard
RefineryTypes: refinery
PowerTypes: wind_trap
ProductionTypes: light_factory, barracks
SiloTypes: silo
SellRefineryInterval: -1
BuildingLimits:
barracks: 1
refinery: 1
outpost: 1
wind_trap: 4
light_factory: 1
silo: 1
BuildingFractions:
wind_trap: 1
barracks: 1
refinery: 1
outpost: 1
light_factory: 1
World: World:
LuaScript: LuaScript:

View File

@@ -14,7 +14,7 @@ AttackGroupSize =
hard = 10 hard = 10
} }
AttackDelays = ProductionDelays =
{ {
easy = { DateTime.Seconds(4), DateTime.Seconds(7) }, easy = { DateTime.Seconds(4), DateTime.Seconds(7) },
normal = { DateTime.Seconds(2), DateTime.Seconds(5) }, normal = { DateTime.Seconds(2), DateTime.Seconds(5) },
@@ -24,6 +24,10 @@ AttackDelays =
OrdosInfantryTypes = { "light_inf", "light_inf", "light_inf", "trooper", "trooper" } OrdosInfantryTypes = { "light_inf", "light_inf", "light_inf", "trooper", "trooper" }
InitAIUnits = function() InitAIUnits = function()
Defending[Ordos] = {}
AttackDelay[Ordos] = 12000 * DifficultyModifier[Difficulty]
TimeBetweenAttacks[Ordos] = 5000 * DifficultyModifier[Difficulty]
DefencePerimeter[Ordos] = GetCellsInRectangle(CPos.New(9,6), CPos.New(20,27))
IdlingUnits[Ordos] = Reinforcements.Reinforce(Ordos, InitialOrdosReinforcements, OrdosPaths[2]) IdlingUnits[Ordos] = Reinforcements.Reinforce(Ordos, InitialOrdosReinforcements, OrdosPaths[2])
DefendAndRepairBase(Ordos, OrdosBase, 0.75, AttackGroupSize[Difficulty]) DefendAndRepairBase(Ordos, OrdosBase, 0.75, AttackGroupSize[Difficulty])
end end
@@ -34,7 +38,7 @@ ActivateAI = function()
OConyard.Produce(AtreidesUpgrades[1]) OConyard.Produce(AtreidesUpgrades[1])
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end local delay = function() return Utils.RandomInteger(ProductionDelays[Difficulty][1], ProductionDelays[Difficulty][2] + 1) end
local toBuild = function() return { Utils.Random(OrdosInfantryTypes) } end local toBuild = function() return { Utils.Random(OrdosInfantryTypes) } end
local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5 local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5
@@ -42,4 +46,29 @@ ActivateAI = function()
Trigger.AfterDelay(DateTime.Seconds(14), function() Trigger.AfterDelay(DateTime.Seconds(14), function()
ProduceUnits(Ordos, OBarracks, delay, toBuild, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(Ordos, OBarracks, delay, toBuild, AttackGroupSize[Difficulty], attackThresholdSize)
end) end)
if Difficulty ~= "easy" then
Ordos.GrantCondition("base-rebuilder")
end
local productionTypes =
{
barracks = toBuild,
}
Trigger.OnBuildingPlaced(Ordos, function(p, building)
table.insert(OrdosBase, building)
DefendAndRepairBase(Ordos, {building}, 0.75, AttackGroupSize[Difficulty] )
if productionTypes[building.Type] == nil then return end
ProduceUnits(Ordos, building, delay, productionTypes[building.Type], AttackGroupSize[Difficulty], attackThresholdSize)
end)
Utils.Do(OrdosScouts, function(a)
Trigger.OnKilled(a, function(self, killer)
if not killer.IsDead then
CheckArea(Ordos, killer.Location, 4)
end
end)
end)
end end

View File

@@ -9,6 +9,8 @@
OrdosBase = { OBarracks, OWindTrap1, OWindTrap2, OOutpost, OConyard, ORefinery, OSilo } OrdosBase = { OBarracks, OWindTrap1, OWindTrap2, OOutpost, OConyard, ORefinery, OSilo }
OrdosScouts = { OScout1, OScout2, OScout3 }
OrdosReinforcements = OrdosReinforcements =
{ {
easy = easy =
@@ -143,7 +145,6 @@ WorldLoaded = function()
end end
Trigger.OnRemovedFromWorld(AConyard, function() Trigger.OnRemovedFromWorld(AConyard, function()
-- Mission already failed, no need to check the other conditions as well -- Mission already failed, no need to check the other conditions as well
if checkResourceCapacity() then if checkResourceCapacity() then
return return
@@ -176,4 +177,10 @@ WorldLoaded = function()
Media.PlaySpeechNotification(Atreides, "Reinforce") Media.PlaySpeechNotification(Atreides, "Reinforce")
Reinforcements.ReinforceWithTransport(Atreides, "carryall.reinforce", AtreidesReinforcements, AtreidesPath, { AtreidesPath[1] }) Reinforcements.ReinforceWithTransport(Atreides, "carryall.reinforce", AtreidesReinforcements, AtreidesPath, { AtreidesPath[1] })
end) end)
Trigger.OnDamaged(HarvesterDebris, function(self, attacker)
if self.MaxHealth / 2 > self.Health then
self.Deploy()
end
end)
end end

Binary file not shown.

View File

@@ -48,24 +48,9 @@ Actors:
Actor3: wormspawner Actor3: wormspawner
Location: 27,14 Location: 27,14
Owner: Creeps Owner: Creeps
Actor8: light_inf
Location: 48,24
Owner: Ordos
Actor9: light_inf
Location: 19,34
Owner: Ordos
Actor10: light_inf
Location: 35,34
Owner: Ordos
Actor11: trooper
Location: 18,35
Owner: Ordos
Actor12: light_inf Actor12: light_inf
Location: 18,37 Location: 18,37
Owner: Ordos Owner: Ordos
Actor13: trooper
Location: 19,39
Owner: Ordos
Actor14: light_inf Actor14: light_inf
Location: 34,50 Location: 34,50
Owner: Ordos Owner: Ordos
@@ -132,6 +117,33 @@ Actors:
OrdosRally2: waypoint OrdosRally2: waypoint
Owner: Neutral Owner: Neutral
Location: 15,34 Location: 15,34
HarvesterDebris: harvester.debris
Owner: Creeps
Facing: 384
Location: 50,12
Actor0: combat_tank_a.debris
Owner: Creeps
Facing: 384
Location: 22,37
Actor1: harvester.debris
Owner: Creeps
Facing: 384
Location: 25,10
OScout1: light_inf
Location: 48,24
Owner: Ordos
OScout2: light_inf
Location: 35,34
Owner: Ordos
Actor13: trooper
Location: 19,39
Owner: Ordos
Actor9: light_inf
Location: 19,34
Owner: Ordos
OScout3: trooper
Location: 18,35
Owner: Ordos
Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml

View File

@@ -1,6 +1,32 @@
Player: Player:
PlayerResources: PlayerResources:
DefaultCash: 3000 DefaultCash: 3000
ExternalCondition@AI:
Condition: base-rebuilder
BaseBuilderBotModule@Ordos:
RequiresCondition: base-rebuilder
BuildingQueues: Building
MinimumExcessPower: 0
MaximumExcessPower: 250
MaxBaseRadius: 40
ConstructionYardTypes: construction_yard
RefineryTypes: refinery
PowerTypes: wind_trap
ProductionTypes: light_factory, barracks
SiloTypes: silo
DefenseTypes: medium_gun_turret,large_gun_turret
SellRefineryInterval: -1
BuildingLimits:
barracks: 1
refinery: 1
outpost: 1
wind_trap: 2
silo: 1
BuildingFractions:
wind_trap: 1
barracks: 1
refinery: 1
outpost: 1
World: World:
LuaScript: LuaScript:

View File

@@ -14,7 +14,7 @@ AttackGroupSize =
hard = 10 hard = 10
} }
AttackDelays = ProductionDelays =
{ {
easy = { DateTime.Seconds(4), DateTime.Seconds(7) }, easy = { DateTime.Seconds(4), DateTime.Seconds(7) },
normal = { DateTime.Seconds(2), DateTime.Seconds(5) }, normal = { DateTime.Seconds(2), DateTime.Seconds(5) },
@@ -26,22 +26,28 @@ HarkonnenTankType = { "combat_tank_h" }
-- Overwrite the template function because of the message -- Overwrite the template function because of the message
SendAttack = function(owner, size) SendAttack = function(owner, size)
if Attacking[owner] then if Attacking[owner] then return end
return
end
Attacking[owner] = true Attacking[owner] = true
HoldProduction[owner] = true HoldProduction[owner] = true
local units = SetupAttackGroup(owner, size) local units = SetupAttackGroup(owner, size)
Utils.Do(units, IdleHunt) Utils.Do(units, Trigger.ClearAll)
if #units > 0 then if #units > 0 then
Media.DisplayMessage(UserInterface.GetFluentMessage("harkonnen-units-approaching"), UserInterface.GetFluentMessage("fremen-leader")) Media.DisplayMessage(UserInterface.GetFluentMessage("harkonnen-units-approaching"), UserInterface.GetFluentMessage("fremen-leader"))
end end
Trigger.OnAllRemovedFromWorld(units, function() Trigger.AfterDelay(1, function()
Attacking[owner] = false Utils.Do(units, function(u)
HoldProduction[owner] = false u.Stop()
IdleHunt(u)
end)
Trigger.OnAllRemovedFromWorld(units, function()
Attacking[owner] = false
HoldProduction[owner] = false
end)
end) end)
end end
@@ -52,15 +58,34 @@ InitAIUnits = function()
end end
ActivateAI = function() ActivateAI = function()
Defending[Harkonnen] = {}
HarvesterCount[Harkonnen] = 2
AttackDelay[Harkonnen] = 9000 * DifficultyModifier[Difficulty]
TimeBetweenAttacks[Harkonnen] = 9000 * DifficultyModifier[Difficulty]
LastHarvesterEaten[Harkonnen] = true LastHarvesterEaten[Harkonnen] = true
InitAIUnits() InitAIUnits()
FremenProduction() FremenProduction()
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end local delay = function() return Utils.RandomInteger(ProductionDelays[Difficulty][1], ProductionDelays[Difficulty][2] + 1) end
local infantryToBuild = function() return { Utils.Random(HarkonnenInfantryTypes) } end local infantryToBuild = function() return { Utils.Random(HarkonnenInfantryTypes) } end
local tanksToBuild = function() return HarkonnenTankType end local tanksToBuild = function() return HarkonnenTankType end
local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5 local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5
ProduceUnits(Harkonnen, HarkonnenBarracks, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(Harkonnen, HarkonnenBarracks, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
ProduceUnits(Harkonnen, HarkonnenHeavyFact, delay, tanksToBuild, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(Harkonnen, HarkonnenHeavyFact, delay, tanksToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
ActivateCrushLogic()
local productionTypes =
{
barracks = infantryToBuild,
heavy_factory = tanksToBuild
}
Trigger.OnBuildingPlaced(Harkonnen, function(p, building)
table.insert(HarkonnenBase, building)
DefendAndRepairBase(Harkonnen, {building}, 0.75, AttackGroupSize[Difficulty] )
if productionTypes[building.Type] == nil then return end
ProduceUnits(Harkonnen, building, delay, productionTypes[building.Type], AttackGroupSize[Difficulty], attackThresholdSize)
end)
end end

View File

@@ -48,8 +48,8 @@ HarkonnenReinforcements =
HarkonnenAttackDelay = HarkonnenAttackDelay =
{ {
easy = DateTime.Minutes(3), easy = DateTime.Minutes(3),
normal = DateTime.Minutes(2) + DateTime.Seconds(20), normal = DateTime.Minutes(2) + DateTime.Seconds(30),
hard = DateTime.Minutes(1) hard = DateTime.Minutes(2)
} }
HarkonnenAttackWaves = HarkonnenAttackWaves =
@@ -74,6 +74,7 @@ AtreidesReinforcements =
{ "trike", "combat_tank_a", "combat_tank_a" }, { "trike", "combat_tank_a", "combat_tank_a" },
{ "quad", "combat_tank_a", "combat_tank_a" } { "quad", "combat_tank_a", "combat_tank_a" }
} }
AtreidesPath = { AtreidesEntry.Location, AtreidesRally.Location } AtreidesPath = { AtreidesEntry.Location, AtreidesRally.Location }
FremenInterval = FremenInterval =
@@ -85,9 +86,9 @@ FremenInterval =
IntegrityLevel = IntegrityLevel =
{ {
easy = 50, easy = 10,
normal = 75, normal = 50,
hard = 100 hard = 90
} }
FremenProduction = function() FremenProduction = function()
@@ -145,7 +146,7 @@ WorldLoaded = function()
ProtectFremen = AddPrimaryObjective(Atreides, "protect-fremen-sietch") ProtectFremen = AddPrimaryObjective(Atreides, "protect-fremen-sietch")
KillHarkonnen = AddPrimaryObjective(Atreides, "destroy-harkonnen") KillHarkonnen = AddPrimaryObjective(Atreides, "destroy-harkonnen")
local keepSietchIntact = UserInterface.GetFluentMessage("keep-sietch-intact", { ["integrity"] = IntegrityLevel[Difficulty] }) local keepSietchIntact = UserInterface.GetFluentMessage("keep-sietch-intact", { ["integrity"] = IntegrityLevel[Difficulty] })
KeepIntegrity = AddPrimaryObjective(Atreides, keepSietchIntact) KeepIntegrity = AddSecondaryObjective(Atreides, keepSietchIntact)
Camera.Position = AConyard.CenterPosition Camera.Position = AConyard.CenterPosition
HarkonnenAttackLocation = AConyard.Location HarkonnenAttackLocation = AConyard.Location
@@ -164,6 +165,7 @@ WorldLoaded = function()
UserInterface.SetMissionText(UserInterface.GetFluentMessage("sietch-destroyed"), Atreides.Color) UserInterface.SetMissionText(UserInterface.GetFluentMessage("sietch-destroyed"), Atreides.Color)
Atreides.MarkFailedObjective(ProtectFremen) Atreides.MarkFailedObjective(ProtectFremen)
end) end)
Trigger.OnDamaged(Sietch, function() Trigger.OnDamaged(Sietch, function()
if AttackNotifier <= 0 then if AttackNotifier <= 0 then
AttackNotifier = DateTime.Seconds(10) AttackNotifier = DateTime.Seconds(10)
@@ -185,6 +187,7 @@ WorldLoaded = function()
unit.AttackMove(HarkonnenAttackLocation) unit.AttackMove(HarkonnenAttackLocation)
IdleHunt(unit) IdleHunt(unit)
end end
SendCarryallReinforcements(Harkonnen, 0, HarkonnenAttackWaves[Difficulty], HarkonnenAttackDelay[Difficulty], path, HarkonnenReinforcements[Difficulty], waveCondition, huntFunction) SendCarryallReinforcements(Harkonnen, 0, HarkonnenAttackWaves[Difficulty], HarkonnenAttackDelay[Difficulty], path, HarkonnenReinforcements[Difficulty], waveCondition, huntFunction)
Actor.Create("upgrade.barracks", true, { Owner = Harkonnen }) Actor.Create("upgrade.barracks", true, { Owner = Harkonnen })
@@ -194,6 +197,7 @@ WorldLoaded = function()
Media.PlaySpeechNotification(Atreides, "Reinforce") Media.PlaySpeechNotification(Atreides, "Reinforce")
Reinforcements.Reinforce(Atreides, AtreidesReinforcements[1], AtreidesPath) Reinforcements.Reinforce(Atreides, AtreidesReinforcements[1], AtreidesPath)
end) end)
Trigger.AfterDelay(DateTime.Minutes(1) + DateTime.Seconds(40), function() Trigger.AfterDelay(DateTime.Minutes(1) + DateTime.Seconds(40), function()
Media.PlaySpeechNotification(Atreides, "Reinforce") Media.PlaySpeechNotification(Atreides, "Reinforce")
Reinforcements.ReinforceWithTransport(Atreides, "carryall.reinforce", AtreidesReinforcements[2], AtreidesPath, { AtreidesPath[1] }) Reinforcements.ReinforceWithTransport(Atreides, "carryall.reinforce", AtreidesReinforcements[2], AtreidesPath, { AtreidesPath[1] })

Binary file not shown.

View File

@@ -413,7 +413,44 @@ Actors:
Location: 5,23 Location: 5,23
FremenRally: waypoint FremenRally: waypoint
Owner: Neutral Owner: Neutral
Location: 56,54 Location: 56,56
Actor27: combat_tank_h.debris
Owner: Creeps
Facing: 384
Location: 58,50
Actor33: frigate.debris
Owner: Creeps
Location: 33,28
Actor34: crate
Owner: Fremen
Location: 39,57
Actor36: crate
Owner: Fremen
Location: 38,57
Actor53: crate
Owner: Fremen
Location: 37,57
Actor54: crate
Owner: Fremen
Location: 37,56
Actor57: crate
Owner: Fremen
Location: 38,56
Actor59: crate
Owner: Fremen
Location: 39,56
Actor62: combat_tank_a.debris
Owner: Creeps
Facing: 384
Location: 14,45
Actor8: combat_tank_h.debris
Owner: Creeps
Facing: 384
Location: 51,57
Actor63: combat_tank_a.debris
Owner: Creeps
Facing: 384
Location: 31,48
Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml

View File

@@ -7,6 +7,17 @@
information, see COPYING. information, see COPYING.
]] ]]
EarlyGameStage = DateTime.Minutes(5)
InitialProductionDelay = {
HarkonnenMain =
{
easy = DateTime.Seconds(100),
normal = DateTime.Seconds(60),
hard = DateTime.Seconds(30)
}
}
AttackGroupSize = AttackGroupSize =
{ {
easy = 6, easy = 6,
@@ -14,7 +25,14 @@ AttackGroupSize =
hard = 10 hard = 10
} }
AttackDelays = EarlyProductionDelays =
{
easy = { DateTime.Seconds(7), DateTime.Seconds(10) },
normal = { DateTime.Seconds(5), DateTime.Seconds(7) },
hard = { DateTime.Seconds(3), DateTime.Seconds(5) }
}
LateProductionDelays =
{ {
easy = { DateTime.Seconds(4), DateTime.Seconds(7) }, easy = { DateTime.Seconds(4), DateTime.Seconds(7) },
normal = { DateTime.Seconds(2), DateTime.Seconds(5) }, normal = { DateTime.Seconds(2), DateTime.Seconds(5) },
@@ -22,7 +40,9 @@ AttackDelays =
} }
HarkonnenInfantryTypes = { "light_inf", "light_inf", "trooper", "trooper", "trooper" } HarkonnenInfantryTypes = { "light_inf", "light_inf", "trooper", "trooper", "trooper" }
HarkonnenVehicleTypes = { "trike", "trike", "trike", "quad", "quad" } HarkonnenVehicleTypes = { "trike", "trike", "trike", "quad", "quad" }
HarkonnenTankType = { "combat_tank_h" } HarkonnenTankType = { "combat_tank_h" }
InitAIUnits = function() InitAIUnits = function()
@@ -49,7 +69,13 @@ ProduceInfantry = function()
return return
end end
local delay = Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) local delay = 0
if EarlyGameStage >= DateTime.GameTime then
delay = Utils.RandomInteger(EarlyProductionDelays[Difficulty][1], EarlyProductionDelays[Difficulty][2] + 1)
else
delay = Utils.RandomInteger(LateProductionDelays[Difficulty][1], LateProductionDelays[Difficulty][2] + 1)
end
local toBuild = { Utils.Random(HarkonnenInfantryTypes) } local toBuild = { Utils.Random(HarkonnenInfantryTypes) }
Harkonnen.Build(toBuild, function(unit) Harkonnen.Build(toBuild, function(unit)
IdlingUnits[Harkonnen][#IdlingUnits[Harkonnen] + 1] = unit[1] IdlingUnits[Harkonnen][#IdlingUnits[Harkonnen] + 1] = unit[1]
@@ -63,15 +89,56 @@ end
ActivateAI = function() ActivateAI = function()
Harkonnen.Cash = 15000 Harkonnen.Cash = 15000
Defending[Harkonnen] = {}
AttackDelay[Harkonnen] = 6000 * DifficultyModifier[Difficulty]
TimeBetweenAttacks[Harkonnen] = 5000 * DifficultyModifier[Difficulty]
HarvesterCount[Harkonnen] = 1
PatrolPoints[Harkonnen] = { HPatrolPoint1.Location, HPatrolPoint2.Location,HPatrolPoint3.Location }
DefencePerimeter[Harkonnen] = GetCellsInRectangle(CPos.New(13,13), CPos.New(36,25))
LastHarvesterEaten[Harkonnen] = true LastHarvesterEaten[Harkonnen] = true
InitAIUnits() InitAIUnits()
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end local delay = function(player)
local vehilcesToBuild = function() return { Utils.Random(HarkonnenVehicleTypes) } end if EmergencyBuildRate[player] and Difficulty ~= "easy" then
return 1
end
if EarlyGameStage >= DateTime.GameTime then
return Utils.RandomInteger(EarlyProductionDelays[Difficulty][1], EarlyProductionDelays[Difficulty][2] + 1)
else
return Utils.RandomInteger(LateProductionDelays[Difficulty][1], LateProductionDelays[Difficulty][2] + 1)
end
end
local vehiclesToBuild = function() return { Utils.Random(HarkonnenVehicleTypes) } end
local tanksToBuild = function() return HarkonnenTankType end local tanksToBuild = function() return HarkonnenTankType end
local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5 local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5
ProduceInfantry() Trigger.AfterDelay(InitialProductionDelay["HarkonnenMain"][Difficulty], function()
ProduceUnits(Harkonnen, HarkonnenLightFactory, delay, vehilcesToBuild, AttackGroupSize[Difficulty], attackThresholdSize) ProduceInfantry()
ProduceUnits(Harkonnen, HarkonnenHeavyFactory, delay, tanksToBuild, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(Harkonnen, HarkonnenLightFactory, delay, vehiclesToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
ProduceUnits(Harkonnen, HarkonnenHeavyFactory, delay, tanksToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
end)
ActivateCrushLogic()
if Difficulty == "normal" then
Harkonnen.GrantCondition("base-rebuilder")
end
if Difficulty == "hard" then
Harkonnen.GrantCondition("defense-rebuilder")
end
local productionTypes =
{
light_factory = vehiclesToBuild,
heavy_factory = tanksToBuild
}
Trigger.OnBuildingPlaced(Harkonnen, function(p, building)
table.insert(HarkonnenBase, building)
DefendAndRepairBase(Harkonnen, {building}, 0.75, AttackGroupSize[Difficulty] )
if productionTypes[building.Type] == nil then return end
ProduceUnits(Harkonnen, building, delay, productionTypes[building.Type], AttackGroupSize[Difficulty], attackThresholdSize)
end)
end end

View File

@@ -8,6 +8,7 @@
]] ]]
HarkonnenBase = { HarkonnenConstructionYard, HarkonnenWindTrap1, HarkonnenWindTrap2, HarkonnenWindTrap3, HarkonnenWindTrap4, HarkonnenWindTrap5, HarkonnenWindTrap6, HarkonnenWindTrap7, HarkonnenWindTrap8, HarkonnenSilo1, HarkonnenSilo2, HarkonnenSilo3, HarkonnenSilo4, HarkonnenGunTurret1, HarkonnenGunTurret2, HarkonnenGunTurret3, HarkonnenGunTurret4, HarkonnenGunTurret5, HarkonnenGunTurret6, HarkonnenGunTurret7, HarkonnenHeavyFactory, HarkonnenRefinery, HarkonnenOutpost, HarkonnenLightFactory } HarkonnenBase = { HarkonnenConstructionYard, HarkonnenWindTrap1, HarkonnenWindTrap2, HarkonnenWindTrap3, HarkonnenWindTrap4, HarkonnenWindTrap5, HarkonnenWindTrap6, HarkonnenWindTrap7, HarkonnenWindTrap8, HarkonnenSilo1, HarkonnenSilo2, HarkonnenSilo3, HarkonnenSilo4, HarkonnenGunTurret1, HarkonnenGunTurret2, HarkonnenGunTurret3, HarkonnenGunTurret4, HarkonnenGunTurret5, HarkonnenGunTurret6, HarkonnenGunTurret7, HarkonnenHeavyFactory, HarkonnenRefinery, HarkonnenOutpost, HarkonnenLightFactory }
SmugglerBase = { SmugglerWindTrap1, SmugglerWindTrap2 } SmugglerBase = { SmugglerWindTrap1, SmugglerWindTrap2 }
HarkonnenReinforcements = HarkonnenReinforcements =
@@ -59,6 +60,7 @@ HarkonnenInfantryReinforcements =
{ "light_inf", "light_inf", "light_inf", "light_inf", "light_inf", "light_inf", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper", "trooper", "trooper" } { "light_inf", "light_inf", "light_inf", "light_inf", "light_inf", "light_inf", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper", "trooper", "trooper" }
} }
} }
InfantryPath = { HarkonnenEntry3.Location } InfantryPath = { HarkonnenEntry3.Location }
HarkonnenAttackDelay = HarkonnenAttackDelay =
@@ -139,13 +141,14 @@ HarkonnenPaths =
} }
AtreidesReinforcements = { "trike", "combat_tank_a" } AtreidesReinforcements = { "trike", "combat_tank_a" }
AtreidesPath = { AtreidesEntry.Location, AtreidesRally.Location } AtreidesPath = { AtreidesEntry.Location, AtreidesRally.Location }
ContrabandTimes = ContrabandTimes =
{ {
easy = DateTime.Minutes(10), easy = DateTime.Minutes(10),
normal = DateTime.Minutes(5), normal = DateTime.Minutes(9),
hard = DateTime.Minutes(2) + DateTime.Seconds(30) hard = DateTime.Minutes(8)
} }
Wave = 0 Wave = 0
@@ -310,6 +313,10 @@ WorldLoaded = function()
Media.DisplayMessage(contrabandApproaching, Mentat) Media.DisplayMessage(contrabandApproaching, Mentat)
end) end)
Trigger.AfterDelay(500, function()
Media.DisplayMessage(UserInterface.GetFluentMessage("use-engineer-hint"), Mentat)
end)
Trigger.OnAllKilledOrCaptured(HarkonnenBase, function() Trigger.OnAllKilledOrCaptured(HarkonnenBase, function()
Utils.Do(Harkonnen.GetGroundAttackers(), IdleHunt) Utils.Do(Harkonnen.GetGroundAttackers(), IdleHunt)
end) end)
@@ -330,6 +337,7 @@ WorldLoaded = function()
Atreides.MarkFailedObjective(DefendStarport) Atreides.MarkFailedObjective(DefendStarport)
end end
end) end)
Trigger.OnDamaged(Starport, function(_, attacker) Trigger.OnDamaged(Starport, function(_, attacker)
if Starport.Owner ~= Smuggler or attacker.IsDead or attacker.Owner ~= Atreides then if Starport.Owner ~= Smuggler or attacker.IsDead or attacker.Owner ~= Atreides then
return return
@@ -347,6 +355,7 @@ WorldLoaded = function()
end end
end end
end) end)
Trigger.OnCapture(Starport, function() Trigger.OnCapture(Starport, function()
DefendStarport = AddSecondaryObjective(Atreides, "defend-captured-starport") DefendStarport = AddSecondaryObjective(Atreides, "defend-captured-starport")
@@ -366,12 +375,14 @@ WorldLoaded = function()
Trigger.OnKilled(HarkonnenBarracks, function() Trigger.OnKilled(HarkonnenBarracks, function()
Atreides.MarkFailedObjective(CaptureBarracks) Atreides.MarkFailedObjective(CaptureBarracks)
end) end)
Trigger.OnDamaged(HarkonnenBarracks, function() Trigger.OnDamaged(HarkonnenBarracks, function()
if AttackNotifier <= 0 and HarkonnenBarracks.Health < HarkonnenBarracks.MaxHealth * 3/4 then if AttackNotifier <= 0 and HarkonnenBarracks.Health < HarkonnenBarracks.MaxHealth * 3/4 then
AttackNotifier = DateTime.Seconds(10) AttackNotifier = DateTime.Seconds(10)
Media.DisplayMessage(UserInterface.GetFluentMessage("do-not-destroy-barracks"), Mentat) Media.DisplayMessage(UserInterface.GetFluentMessage("do-not-destroy-barracks"), Mentat)
end end
end) end)
Trigger.OnCapture(HarkonnenBarracks, function() Trigger.OnCapture(HarkonnenBarracks, function()
Media.DisplayMessage(UserInterface.GetFluentMessage("hostages-released"), Mentat) Media.DisplayMessage(UserInterface.GetFluentMessage("hostages-released"), Mentat)
@@ -400,7 +411,7 @@ WorldLoaded = function()
if not Warned and a.Owner == Atreides and a.Type ~= "carryall" then if not Warned and a.Owner == Atreides and a.Type ~= "carryall" then
Warned = true Warned = true
Trigger.RemoveFootprintTrigger(id) Trigger.RemoveFootprintTrigger(id)
Media.DisplayMessage(UserInterface.GetFluentMessage("stay-away-from-starport"), UserInterface.GetFluentMessage("smuggler-leader")) Media.DisplayMessage(UserInterface.GetFluentMessage("stay-away-from-starport"), UserInterface.GetFluentMessage("smuggler-leader"), HSLColor.FromHex("9C8408"))
end end
end) end)
@@ -408,7 +419,7 @@ WorldLoaded = function()
if not Paid and a.Owner == Atreides and a.Type ~= "carryall" then if not Paid and a.Owner == Atreides and a.Type ~= "carryall" then
Paid = true Paid = true
Trigger.RemoveFootprintTrigger(id) Trigger.RemoveFootprintTrigger(id)
Media.DisplayMessage(UserInterface.GetFluentMessage("were-warned-will-pay"), UserInterface.GetFluentMessage("smuggler-leader")) Media.DisplayMessage(UserInterface.GetFluentMessage("were-warned-will-pay"), UserInterface.GetFluentMessage("smuggler-leader"), HSLColor.FromHex("9C8408"))
Utils.Do(Smuggler.GetGroundAttackers(), function(unit) Utils.Do(Smuggler.GetGroundAttackers(), function(unit)
unit.AttackMove(SmugglerWaypoint2.Location) unit.AttackMove(SmugglerWaypoint2.Location)
end) end)
@@ -427,4 +438,11 @@ WorldLoaded = function()
StopInfantryProduction = true StopInfantryProduction = true
end end
end) end)
Trigger.OnEnteredProximityTrigger(Trigger1.CenterPosition, WDist.New(2 * 1024), function(a, id)
if HarkonnenTankDebris1.IsInWorld and a.Owner == Atreides then
HarkonnenTankDebris1.Deploy()
Trigger.RemoveProximityTrigger(id)
end
end)
end end

Binary file not shown.

View File

@@ -365,6 +365,41 @@ Actors:
HarkonnenRally4: waypoint HarkonnenRally4: waypoint
Owner: Neutral Owner: Neutral
Location: 49,4 Location: 49,4
HPatrolPoint1: waypoint
Owner: Neutral
Location: 40,27
HPatrolPoint2: waypoint
Owner: Neutral
Location: 21,38
HPatrolPoint3: waypoint
Owner: Neutral
Location: 24,60
Actor0: repair_pad
Owner: Atreides
Location: 59,59
Actor1: combat_tank_a.debris
Owner: Atreides
Facing: 384
Location: 59,63
Actor2: combat_tank_a.debris
Owner: Atreides
Facing: 384
Location: 62,63
Actor3: combat_tank_a.debris
Owner: Atreides
Facing: 384
Location: 56,62
Actor9: harvester.debris
Owner: Creeps
Facing: 384
Location: 17,47
HarkonnenTankDebris1: combat_tank_h.debris
Owner: Creeps
Facing: 384
Location: 8,58
Trigger1: waypoint
Owner: Neutral
Location: 8,58
Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml

View File

@@ -1,6 +1,64 @@
Player: Player:
PlayerResources: PlayerResources:
DefaultCash: 7000 DefaultCash: 7000
ExternalCondition@AI:
Condition: base-rebuilder
ExternalCondition@AIDefense:
Condition: defense-rebuilder
BaseBuilderBotModule@campaign:
RequiresCondition: base-rebuilder
BuildingQueues: Building, Upgrade
MinimumExcessPower: 0
MaximumExcessPower: 250
MaxBaseRadius: 40
ConstructionYardTypes: construction_yard
RefineryTypes: refinery
PowerTypes: wind_trap
ProductionTypes: light_factory, heavy_factory
SiloTypes: silo
DefenseTypes: medium_gun_turret,large_gun_turret
SellRefineryInterval: -1
BuildingLimits:
refinery: 1
outpost: 1
light_factory: 1
heavy_factory: 1
wind_trap: 6
silo: 1
BuildingFractions:
wind_trap: 1
refinery: 1
outpost: 1
light_factory: 1
heavy_factory: 1
BaseBuilderBotModule@defense:
RequiresCondition: defense-rebuilder
BuildingQueues: Building, Upgrade
MinimumExcessPower: 0
MaximumExcessPower: 250
MaxBaseRadius: 40
ConstructionYardTypes: construction_yard
RefineryTypes: refinery
PowerTypes: wind_trap
ProductionTypes: light_factory, heavy_factory
SiloTypes: silo
DefenseTypes: medium_gun_turret
SellRefineryInterval: -1
BuildingLimits:
refinery: 1
outpost: 1
light_factory: 1
heavy_factory: 1
wind_trap: 6
silo: 1
medium_gun_turret: 6
BuildingFractions:
wind_trap: 1
refinery: 1
outpost: 1
light_factory: 1
heavy_factory: 1
medium_gun_turret: 1
World: World:
LuaScript: LuaScript:

View File

@@ -32,6 +32,7 @@ AtreidesReinforcements =
} }
AtreidesEntryWaypoints = { AtreidesWaypoint1.Location, AtreidesWaypoint2.Location, AtreidesWaypoint3.Location, AtreidesWaypoint4.Location } AtreidesEntryWaypoints = { AtreidesWaypoint1.Location, AtreidesWaypoint2.Location, AtreidesWaypoint3.Location, AtreidesWaypoint4.Location }
AtreidesAttackDelay = DateTime.Seconds(30) AtreidesAttackDelay = DateTime.Seconds(30)
AtreidesAttackWaves = AtreidesAttackWaves =
@@ -49,6 +50,7 @@ ToHarvest =
} }
HarkonnenReinforcements = { "light_inf", "light_inf", "light_inf", "trike" } HarkonnenReinforcements = { "light_inf", "light_inf", "light_inf", "trike" }
HarkonnenEntryPath = { HarkonnenWaypoint.Location, HarkonnenRally.Location } HarkonnenEntryPath = { HarkonnenWaypoint.Location, HarkonnenRally.Location }
Messages = Messages =
@@ -118,11 +120,8 @@ WorldLoaded = function()
end end
Trigger.OnRemovedFromWorld(HarkonnenConyard, function() Trigger.OnRemovedFromWorld(HarkonnenConyard, function()
-- Mission already failed, no need to check the other conditions as well -- Mission already failed, no need to check the other conditions as well
if checkResourceCapacity() then if checkResourceCapacity() then return end
return
end
local refs = Utils.Where(Map.ActorsInWorld, function(actor) return actor.Type == "refinery" and actor.Owner == Harkonnen end) local refs = Utils.Where(Map.ActorsInWorld, function(actor) return actor.Type == "refinery" and actor.Owner == Harkonnen end)

View File

@@ -32,6 +32,7 @@ AtreidesReinforcements =
} }
AtreidesEntryWaypoints = { AtreidesWaypoint1.Location, AtreidesWaypoint2.Location, AtreidesWaypoint3.Location, AtreidesWaypoint4.Location } AtreidesEntryWaypoints = { AtreidesWaypoint1.Location, AtreidesWaypoint2.Location, AtreidesWaypoint3.Location, AtreidesWaypoint4.Location }
AtreidesAttackDelay = DateTime.Seconds(30) AtreidesAttackDelay = DateTime.Seconds(30)
AtreidesAttackWaves = AtreidesAttackWaves =
@@ -49,6 +50,7 @@ ToHarvest =
} }
HarkonnenReinforcements = { "light_inf", "light_inf", "light_inf", "trike" } HarkonnenReinforcements = { "light_inf", "light_inf", "light_inf", "trike" }
HarkonnenEntryPath = { HarkonnenWaypoint.Location, HarkonnenRally.Location } HarkonnenEntryPath = { HarkonnenWaypoint.Location, HarkonnenRally.Location }
Messages = Messages =
@@ -118,11 +120,8 @@ WorldLoaded = function()
end end
Trigger.OnRemovedFromWorld(HarkonnenConyard, function() Trigger.OnRemovedFromWorld(HarkonnenConyard, function()
-- Mission already failed, no need to check the other conditions as well -- Mission already failed, no need to check the other conditions as well
if checkResourceCapacity() then if checkResourceCapacity() then return end
return
end
local refs = Utils.Where(Map.ActorsInWorld, function(actor) return actor.Type == "refinery" and actor.Owner == Harkonnen end) local refs = Utils.Where(Map.ActorsInWorld, function(actor) return actor.Type == "refinery" and actor.Owner == Harkonnen end)

View File

@@ -14,7 +14,7 @@ AttackGroupSize =
hard = 10 hard = 10
} }
AttackDelays = ProductionDelays =
{ {
easy = { DateTime.Seconds(4), DateTime.Seconds(9) }, easy = { DateTime.Seconds(4), DateTime.Seconds(9) },
normal = { DateTime.Seconds(2), DateTime.Seconds(7) }, normal = { DateTime.Seconds(2), DateTime.Seconds(7) },
@@ -24,10 +24,13 @@ AttackDelays =
AtreidesInfantryTypes = { "light_inf" } AtreidesInfantryTypes = { "light_inf" }
ActivateAI = function() ActivateAI = function()
Defending[Atreides] = {}
AttackDelay[Atreides] = 3000 * DifficultyModifier[Difficulty]
TimeBetweenAttacks[Atreides] = 3000 * DifficultyModifier[Difficulty]
IdlingUnits[Atreides] = { } IdlingUnits[Atreides] = { }
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end local delay = function() return Utils.RandomInteger(ProductionDelays[Difficulty][1], ProductionDelays[Difficulty][2] + 1) end
local toBuild = function() return AtreidesInfantryTypes end local toBuild = function() return AtreidesInfantryTypes end
local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5 attackThresholdSize = AttackGroupSize[Difficulty] * 2.5
DefendAndRepairBase(Atreides, AtreidesBase, 0.75, AttackGroupSize[Difficulty]) DefendAndRepairBase(Atreides, AtreidesBase, 0.75, AttackGroupSize[Difficulty])
ProduceUnits(Atreides, ABarracks, delay, toBuild, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(Atreides, ABarracks, delay, toBuild, AttackGroupSize[Difficulty], attackThresholdSize)

Binary file not shown.

View File

@@ -162,6 +162,12 @@ Actors:
AtreidesRally4: waypoint AtreidesRally4: waypoint
Owner: Neutral Owner: Neutral
Location: 47,4 Location: 47,4
Actor1: crate
Owner: Neutral
Location: 33,47
Actor3: crate_reveal
Owner: Neutral
Location: 27,16
Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml

View File

@@ -14,7 +14,7 @@ AttackGroupSize =
hard = 10 hard = 10
} }
AttackDelays = ProductionDelays =
{ {
easy = { DateTime.Seconds(4), DateTime.Seconds(9) }, easy = { DateTime.Seconds(4), DateTime.Seconds(9) },
normal = { DateTime.Seconds(2), DateTime.Seconds(7) }, normal = { DateTime.Seconds(2), DateTime.Seconds(7) },
@@ -22,16 +22,20 @@ AttackDelays =
} }
AtreidesInfantryTypes = { "light_inf" } AtreidesInfantryTypes = { "light_inf" }
AtreidesVehicleTypes = { "trike" } AtreidesVehicleTypes = { "trike" }
ActivateAI = function() ActivateAI = function()
Defending[Atreides] = {}
AttackDelay[Atreides] = 3000 * DifficultyModifier[Difficulty]
TimeBetweenAttacks[Atreides] = 3000 * DifficultyModifier[Difficulty]
IdlingUnits[Atreides] = { } IdlingUnits[Atreides] = { }
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end local delay = function() return Utils.RandomInteger(ProductionDelays[Difficulty][1], ProductionDelays[Difficulty][2] + 1) end
local infantryToBuild = function() return AtreidesInfantryTypes end local infantryToBuild = function() return AtreidesInfantryTypes end
local vehilcesToBuild = function() return AtreidesVehicleTypes end local vehiclesToBuild = function() return AtreidesVehicleTypes end
local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5 local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5
DefendAndRepairBase(Atreides, AtreidesBase, 0.75, AttackGroupSize[Difficulty]) DefendAndRepairBase(Atreides, AtreidesBase, 0.75, AttackGroupSize[Difficulty])
ProduceUnits(Atreides, ABarracks, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(Atreides, ABarracks, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
ProduceUnits(Atreides, ALightFactory, delay, vehilcesToBuild, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(Atreides, ALightFactory, delay, vehiclesToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
end end

View File

@@ -14,7 +14,7 @@ AttackGroupSize =
hard = 10 hard = 10
} }
AttackDelays = ProductionDelays =
{ {
easy = { DateTime.Seconds(4), DateTime.Seconds(9) }, easy = { DateTime.Seconds(4), DateTime.Seconds(9) },
normal = { DateTime.Seconds(2), DateTime.Seconds(7) }, normal = { DateTime.Seconds(2), DateTime.Seconds(7) },
@@ -22,9 +22,13 @@ AttackDelays =
} }
AtreidesInfantryTypes = { "light_inf", "light_inf", "light_inf", "trooper", "trooper" } AtreidesInfantryTypes = { "light_inf", "light_inf", "light_inf", "trooper", "trooper" }
AtreidesVehicleTypes = { "trike", "trike", "quad" } AtreidesVehicleTypes = { "trike", "trike", "quad" }
ActivateAI = function() ActivateAI = function()
Defending[Atreides] = {}
AttackDelay[Atreides] = 7000 * DifficultyModifier[Difficulty]
TimeBetweenAttacks[Atreides] = 5000 * DifficultyModifier[Difficulty]
IdlingUnits[Atreides] = { } IdlingUnits[Atreides] = { }
LastHarvesterEaten[Atreides] = true LastHarvesterEaten[Atreides] = true
DefendAndRepairBase(Atreides, AtreidesBase, 0.75, AttackGroupSize[Difficulty]) DefendAndRepairBase(Atreides, AtreidesBase, 0.75, AttackGroupSize[Difficulty])
@@ -32,14 +36,31 @@ ActivateAI = function()
AConyard.Produce(HarkonnenUpgrades[1]) AConyard.Produce(HarkonnenUpgrades[1])
AConyard.Produce(HarkonnenUpgrades[2]) AConyard.Produce(HarkonnenUpgrades[2])
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end local delay = function() return Utils.RandomInteger(ProductionDelays[Difficulty][1], ProductionDelays[Difficulty][2] + 1) end
local infantryToBuild = function() return { Utils.Random(AtreidesInfantryTypes) } end local infantryToBuild = function() return { Utils.Random(AtreidesInfantryTypes) } end
local vehilcesToBuild = function() return { Utils.Random(AtreidesVehicleTypes) } end local vehiclesToBuild = function() return { Utils.Random(AtreidesVehicleTypes) } end
local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5 local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5
-- Finish the upgrades first before trying to build something -- Finish the upgrades first before trying to build something
Trigger.AfterDelay(DateTime.Seconds(14), function() Trigger.AfterDelay(DateTime.Seconds(14), function()
ProduceUnits(Atreides, ABarracks, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(Atreides, ABarracks, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
ProduceUnits(Atreides, ALightFactory, delay, vehilcesToBuild, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(Atreides, ALightFactory, delay, vehiclesToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
end)
if Difficulty ~= "easy" then
Atreides.GrantCondition("base-rebuilder")
end
local productionTypes =
{
barracks = infantryToBuild,
light_factory = vehiclesToBuild,
}
Trigger.OnBuildingPlaced(Atreides, function(p, building)
table.insert(OrdosMainBase, building)
DefendAndRepairBase(Atreides, {building}, 0.75, AttackGroupSize[Difficulty] )
if productionTypes[building.Type] == nil then return end
ProduceUnits(Atreides, building, delay, productionTypes[building.Type], AttackGroupSize[Difficulty], attackThresholdSize)
end) end)
end end

View File

@@ -8,6 +8,7 @@
]] ]]
AtreidesBase = { ABarracks, AWindTrap1, AWindTrap2, ALightFactory, AOutpost, AConyard, ARefinery, ASilo } AtreidesBase = { ABarracks, AWindTrap1, AWindTrap2, ALightFactory, AOutpost, AConyard, ARefinery, ASilo }
AtreidesBaseAreaTriggers = AtreidesBaseAreaTriggers =
{ {
{ CPos.New(34, 50), CPos.New(35, 50), CPos.New(36, 50), CPos.New(37, 50), CPos.New(38, 50), CPos.New(39, 50), CPos.New(40, 50), CPos.New(41, 50), CPos.New(14, 57), CPos.New(14, 58), CPos.New(14, 59), CPos.New(14, 60), CPos.New(14, 61), CPos.New(14, 62), CPos.New(14, 63), CPos.New(14, 64), CPos.New(14, 65)}, { CPos.New(34, 50), CPos.New(35, 50), CPos.New(36, 50), CPos.New(37, 50), CPos.New(38, 50), CPos.New(39, 50), CPos.New(40, 50), CPos.New(41, 50), CPos.New(14, 57), CPos.New(14, 58), CPos.New(14, 59), CPos.New(14, 60), CPos.New(14, 61), CPos.New(14, 62), CPos.New(14, 63), CPos.New(14, 64), CPos.New(14, 65)},
@@ -88,9 +89,11 @@ AtreidesHunterPaths =
} }
HarkonnenReinforcements = { "trike", "trike", "quad" } HarkonnenReinforcements = { "trike", "trike", "quad" }
HarkonnenPath = { HarkonnenEntry.Location, HarkonnenRally.Location } HarkonnenPath = { HarkonnenEntry.Location, HarkonnenRally.Location }
HarkonnenBaseBuildings = { "barracks", "light_factory" } HarkonnenBaseBuildings = { "barracks", "light_factory" }
HarkonnenUpgrades = { "upgrade.barracks", "upgrade.light" } HarkonnenUpgrades = { "upgrade.barracks", "upgrade.light" }
MessageCheck = function(index) MessageCheck = function(index)

Binary file not shown.

View File

@@ -177,6 +177,17 @@ Actors:
HarkonnenEntry: waypoint HarkonnenEntry: waypoint
Owner: Neutral Owner: Neutral
Location: 29,2 Location: 29,2
Actor2: carryall.debris
Owner: Creeps
Facing: 384
Location: 24,40
Actor18: crate
Owner: Neutral
Location: 17,33
Actor19: harvester.debris
Owner: Creeps
Facing: 384
Location: 12,61
Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml

View File

@@ -1,6 +1,34 @@
Player: Player:
PlayerResources: PlayerResources:
DefaultCash: 5000 DefaultCash: 5000
ExternalCondition@AI:
Condition: base-rebuilder
BaseBuilderBotModule@campaign:
RequiresCondition: base-rebuilder
BuildingQueues: Building
MinimumExcessPower: 0
MaximumExcessPower: 250
MaxBaseRadius: 40
ConstructionYardTypes: construction_yard
RefineryTypes: refinery
PowerTypes: wind_trap
ProductionTypes: light_factory, barracks
SiloTypes: silo
DefenseTypes: medium_gun_turret,large_gun_turret
SellRefineryInterval: -1
BuildingLimits:
barracks: 1
refinery: 1
outpost: 1
light_factory: 1
wind_trap: 3
silo: 1
BuildingFractions:
wind_trap: 1
barracks: 1
refinery: 1
outpost: 1
light_factory: 1
World: World:
LuaScript: LuaScript:

View File

@@ -14,7 +14,7 @@ AttackGroupSize =
hard = 10 hard = 10
} }
AttackDelays = ProductionDelays =
{ {
easy = { DateTime.Seconds(4), DateTime.Seconds(9) }, easy = { DateTime.Seconds(4), DateTime.Seconds(9) },
normal = { DateTime.Seconds(2), DateTime.Seconds(7) }, normal = { DateTime.Seconds(2), DateTime.Seconds(7) },
@@ -22,29 +22,48 @@ AttackDelays =
} }
AtreidesInfantryTypes = { "light_inf", "light_inf", "light_inf", "trooper", "trooper" } AtreidesInfantryTypes = { "light_inf", "light_inf", "light_inf", "trooper", "trooper" }
AtreidesVehicleTypes = { "trike", "trike", "quad" } AtreidesVehicleTypes = { "trike", "trike", "quad" }
InitAIUnits = function() InitAIUnits = function()
IdlingUnits[Atreides] = Reinforcements.Reinforce(Atreides, AtreidesInitialReinforcements, AtreidesInitialPath) IdlingUnits[Atreides] = Reinforcements.Reinforce(Atreides, AtreidesInitialReinforcements, AtreidesInitialPath)
DefendAndRepairBase(Atreides, AtreidesBase, 0.75, AttackGroupSize[Difficulty]) DefendAndRepairBase(Atreides, AtreidesBase, 0.75, AttackGroupSize[Difficulty])
end end
ActivateAI = function() ActivateAI = function()
Defending[Atreides] = {}
AttackDelay[Atreides] = 7000 * DifficultyModifier[Difficulty]
TimeBetweenAttacks[Atreides] = 5000 * DifficultyModifier[Difficulty]
LastHarvesterEaten[Atreides] = true LastHarvesterEaten[Atreides] = true
Trigger.AfterDelay(0, InitAIUnits) Trigger.AfterDelay(0, InitAIUnits)
AConyard.Produce(HarkonnenUpgrades[1]) AConyard.Produce(HarkonnenUpgrades[1])
AConyard.Produce(HarkonnenUpgrades[2]) AConyard.Produce(HarkonnenUpgrades[2])
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end local delay = function(player) return Utils.RandomInteger(ProductionDelays[Difficulty][1], ProductionDelays[Difficulty][2] + 1) end
local infantryToBuild = function() return { Utils.Random(AtreidesInfantryTypes) } end local infantryToBuild = function() return { Utils.Random(AtreidesInfantryTypes) } end
local vehilcesToBuild = function() return { Utils.Random(AtreidesVehicleTypes) } end local vehiclesToBuild = function() return { Utils.Random(AtreidesVehicleTypes) } end
local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5 local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5
-- Finish the upgrades first before trying to build something -- Finish the upgrades first before trying to build something
Trigger.AfterDelay(DateTime.Seconds(14), function() Trigger.AfterDelay(DateTime.Seconds(14), function()
ProduceUnits(Atreides, ABarracks, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(Atreides, ABarracks, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
ProduceUnits(Atreides, ALightFactory, delay, vehilcesToBuild, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(Atreides, ALightFactory, delay, vehiclesToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
end)
if Difficulty ~= "easy" then
Atreides.GrantCondition("base-rebuilder")
end
local productionTypes =
{
barracks = infantryToBuild,
light_factory = vehiclesToBuild,
}
Trigger.OnBuildingPlaced(Atreides, function(p, building)
table.insert(OrdosMainBase, building)
DefendAndRepairBase(Atreides, {building}, 0.75, AttackGroupSize[Difficulty] )
if productionTypes[building.Type] == nil then return end
ProduceUnits(Atreides, building, delay, productionTypes[building.Type], AttackGroupSize[Difficulty], attackThresholdSize)
end) end)
end end

View File

@@ -8,6 +8,7 @@
]] ]]
AtreidesBase = { ABarracks, AWindTrap1, AWindTrap2, AWindTrap3, ALightFactory, AOutpost, AConyard, ARefinery, ASilo1, ASilo2, ASilo3, ASilo4 } AtreidesBase = { ABarracks, AWindTrap1, AWindTrap2, AWindTrap3, ALightFactory, AOutpost, AConyard, ARefinery, ASilo1, ASilo2, ASilo3, ASilo4 }
AtreidesBaseAreaTriggers = AtreidesBaseAreaTriggers =
{ {
{ CPos.New(10, 53), CPos.New(11, 53), CPos.New(12, 53), CPos.New(13, 53), CPos.New(14, 53), CPos.New(15, 53), CPos.New(16, 53), CPos.New(17, 53), CPos.New(17, 52), CPos.New(17, 51), CPos.New(17, 50), CPos.New(17, 49), CPos.New(17, 48), CPos.New(17, 47), CPos.New(17, 46), CPos.New(17, 45), CPos.New(17, 44), CPos.New(17, 43), CPos.New(17, 42), CPos.New(17, 41), CPos.New(17, 40), CPos.New(17, 39), CPos.New(17, 38), CPos.New(2, 35), CPos.New(3, 35), CPos.New(4, 35), CPos.New(5, 35), CPos.New(6, 35), CPos.New(7, 35), CPos.New(8, 35), CPos.New(9, 35), CPos.New(10, 35), CPos.New(11, 35), CPos.New(12, 35) }, { CPos.New(10, 53), CPos.New(11, 53), CPos.New(12, 53), CPos.New(13, 53), CPos.New(14, 53), CPos.New(15, 53), CPos.New(16, 53), CPos.New(17, 53), CPos.New(17, 52), CPos.New(17, 51), CPos.New(17, 50), CPos.New(17, 49), CPos.New(17, 48), CPos.New(17, 47), CPos.New(17, 46), CPos.New(17, 45), CPos.New(17, 44), CPos.New(17, 43), CPos.New(17, 42), CPos.New(17, 41), CPos.New(17, 40), CPos.New(17, 39), CPos.New(17, 38), CPos.New(2, 35), CPos.New(3, 35), CPos.New(4, 35), CPos.New(5, 35), CPos.New(6, 35), CPos.New(7, 35), CPos.New(8, 35), CPos.New(9, 35), CPos.New(10, 35), CPos.New(11, 35), CPos.New(12, 35) },
@@ -87,12 +88,15 @@ AtreidesHunterPaths =
} }
AtreidesInitialPath = { AtreidesEntry2.Location, AtreidesRally2.Location } AtreidesInitialPath = { AtreidesEntry2.Location, AtreidesRally2.Location }
AtreidesInitialReinforcements = { "light_inf", "light_inf", "quad", "quad", "trike", "trike", "trooper", "trooper" } AtreidesInitialReinforcements = { "light_inf", "light_inf", "quad", "quad", "trike", "trike", "trooper", "trooper" }
HarkonnenReinforcements = { "quad", "quad" } HarkonnenReinforcements = { "quad", "quad" }
HarkonnenPath = { HarkonnenEntry.Location, HarkonnenRally.Location } HarkonnenPath = { HarkonnenEntry.Location, HarkonnenRally.Location }
HarkonnenBaseBuildings = { "barracks", "light_factory" } HarkonnenBaseBuildings = { "barracks", "light_factory" }
HarkonnenUpgrades = { "upgrade.barracks", "upgrade.light" } HarkonnenUpgrades = { "upgrade.barracks", "upgrade.light" }
MessageCheck = function(index) MessageCheck = function(index)
@@ -150,4 +154,10 @@ WorldLoaded = function()
TriggerCarryallReinforcements(Harkonnen, Atreides, AtreidesBaseAreaTriggers[2], AtreidesHunters[2], AtreidesHunterPaths[2]) TriggerCarryallReinforcements(Harkonnen, Atreides, AtreidesBaseAreaTriggers[2], AtreidesHunters[2], AtreidesHunterPaths[2])
TriggerCarryallReinforcements(Harkonnen, Atreides, AtreidesBaseAreaTriggers[3], AtreidesHunters[3], AtreidesHunterPaths[3]) TriggerCarryallReinforcements(Harkonnen, Atreides, AtreidesBaseAreaTriggers[3], AtreidesHunters[3], AtreidesHunterPaths[3])
TriggerCarryallReinforcements(Harkonnen, Atreides, AtreidesBaseAreaTriggers[4], AtreidesHunters[4], AtreidesHunterPaths[4]) TriggerCarryallReinforcements(Harkonnen, Atreides, AtreidesBaseAreaTriggers[4], AtreidesHunters[4], AtreidesHunterPaths[4])
Trigger.OnRemovedFromWorld(CrateScript, function()
VisionPoint.GrantCondition("activate", 150)
Media.PlaySound("MULTI1.WAV")
Camera.Position = VisionPoint.CenterPosition
end)
end end

View File

@@ -207,6 +207,13 @@ Actors:
HarkonnenEntry: waypoint HarkonnenEntry: waypoint
Owner: Neutral Owner: Neutral
Location: 65,45 Location: 65,45
CrateScript: crate_script
Owner: Neutral
Location: 55,9
VisionPoint: vision_provider
Faction:
Location: 46,8
Owner: Harkonnen
Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml

View File

@@ -1,6 +1,34 @@
Player: Player:
PlayerResources: PlayerResources:
DefaultCash: 5000 DefaultCash: 5000
ExternalCondition@AI:
Condition: base-rebuilder
BaseBuilderBotModule@campaign:
RequiresCondition: base-rebuilder
BuildingQueues: Building
MinimumExcessPower: 0
MaximumExcessPower: 250
MaxBaseRadius: 40
ConstructionYardTypes: construction_yard
RefineryTypes: refinery
PowerTypes: wind_trap
ProductionTypes: light_factory, barracks
SiloTypes: silo
DefenseTypes: medium_gun_turret,large_gun_turret
SellRefineryInterval: -1
BuildingLimits:
barracks: 1
refinery: 1
outpost: 1
light_factory: 1
wind_trap: 3
silo: 1
BuildingFractions:
wind_trap: 1
barracks: 1
refinery: 1
outpost: 1
light_factory: 1
World: World:
LuaScript: LuaScript:

View File

@@ -7,6 +7,14 @@
information, see COPYING. information, see COPYING.
]] ]]
EarlyGameStage = DateTime.Minutes(5)
InitialProductionDelay = {
easy = DateTime.Seconds(150),
normal = DateTime.Seconds(100),
hard = DateTime.Seconds(50)
}
AttackGroupSize = AttackGroupSize =
{ {
easy = 6, easy = 6,
@@ -14,7 +22,7 @@ AttackGroupSize =
hard = 10 hard = 10
} }
AttackDelays = ProductionDelays =
{ {
easy = { DateTime.Seconds(4), DateTime.Seconds(7) }, easy = { DateTime.Seconds(4), DateTime.Seconds(7) },
normal = { DateTime.Seconds(2), DateTime.Seconds(5) }, normal = { DateTime.Seconds(2), DateTime.Seconds(5) },
@@ -22,24 +30,71 @@ AttackDelays =
} }
AtreidesInfantryTypes = { "light_inf", "light_inf", "trooper", "trooper", "trooper" } AtreidesInfantryTypes = { "light_inf", "light_inf", "trooper", "trooper", "trooper" }
AtreidesVehicleTypes = { "trike", "trike", "quad" } AtreidesVehicleTypes = { "trike", "trike", "quad" }
AtreidesTankType = { "combat_tank_a" } AtreidesTankType = { "combat_tank_a" }
local attackThresholdSize = AttackGroupSize[Difficulty] * 2
ActivateAI = function() ActivateAI = function()
Defending[Atreides] = { }
Defending[Fremen] = { }
AttackDelay[Atreides] = 5000 * DifficultyModifier[Difficulty]
AttackDelay[Fremen] = 5000 * DifficultyModifier[Difficulty]
TimeBetweenAttacks[Atreides] = 6000 * DifficultyModifier[Difficulty]
TimeBetweenAttacks[Fremen] = 5000 * DifficultyModifier[Difficulty]
HarvesterCount[Atreides] = 2
HarvesterCount[Fremen] = 2
IdlingUnits[Fremen] = { } IdlingUnits[Fremen] = { }
IdlingUnits[Atreides] = Utils.Concat(Reinforcements.Reinforce(Atreides, InitialAtreidesReinforcements[1], AtreidesPaths[2]), Reinforcements.Reinforce(Atreides, InitialAtreidesReinforcements[2], AtreidesPaths[3])) IdlingUnits[Atreides] = Utils.Concat(Reinforcements.Reinforce(Atreides, InitialAtreidesReinforcements[1], AtreidesPaths[2]), Reinforcements.Reinforce(Atreides, InitialAtreidesReinforcements[2], AtreidesPaths[3]))
FremenProduction() FremenProduction()
DefencePerimeter[Atreides] = GetCellsInRectangle(CPos.New(4,68), CPos.New(44,82))
Utils.Do(IdlingUnits[Atreides], function(a) SelectRoutine(Atreides, a) end)
PatrolPoints[Atreides] = { APatrolPoint1.Location, APatrolPoint2.Location, APatrolPoint3.Location, APatrolPoint4.Location }
DefendAndRepairBase(Atreides, AtreidesBase, 0.75, AttackGroupSize[Difficulty]) DefendAndRepairBase(Atreides, AtreidesBase, 0.75, AttackGroupSize[Difficulty])
DefendAndRepairBase(Fremen, FremenBase, 0.75, AttackGroupSize[Difficulty]) DefendAndRepairBase(Fremen, FremenBase, 0.75, AttackGroupSize[Difficulty])
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end local delay = function(player)
if EmergencyBuildRate[player] and Difficulty ~= "easy" then
return 1
end
return Utils.RandomInteger(ProductionDelays[Difficulty][1], ProductionDelays[Difficulty][2] + 1)
end
local infantryToBuild = function() return { Utils.Random(AtreidesInfantryTypes) } end local infantryToBuild = function() return { Utils.Random(AtreidesInfantryTypes) } end
local vehilcesToBuild = function() return { Utils.Random(AtreidesVehicleTypes) } end local vehiclesToBuild = function() return { Utils.Random(AtreidesVehicleTypes) } end
local tanksToBuild = function() return AtreidesTankType end local tanksToBuild = function() return AtreidesTankType end
local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5
ProduceUnits(Atreides, ABarracks, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(Atreides, ABarracks, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
ProduceUnits(Atreides, ALightFactory, delay, vehilcesToBuild, AttackGroupSize[Difficulty], attackThresholdSize) Trigger.AfterDelay(InitialProductionDelay[Difficulty], function()
ProduceUnits(Atreides, AHeavyFactory, delay, tanksToBuild, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(Atreides, ALightFactory, delay, vehiclesToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
ProduceUnits(Atreides, AHeavyFactory, delay, tanksToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
end)
ActivateCrushLogic()
if Difficulty == "normal" then
Atreides.GrantCondition("base-rebuilder")
end
if Difficulty == "hard" then
Atreides.GrantCondition("defense-rebuilder")
end
local productionTypes =
{
barracks = infantryToBuild,
light_factory = vehiclesToBuild,
heavy_factory = tanksToBuild
}
Trigger.OnBuildingPlaced(Atreides, function(p, building)
table.insert(AtreidesBase, building)
DefendAndRepairBase(Atreides, {building}, 0.75, AttackGroupSize[Difficulty] )
if productionTypes[building.Type] == nil then return end
ProduceUnits(Atreides, building, delay, productionTypes[building.Type], AttackGroupSize[Difficulty], attackThresholdSize)
end)
end end

View File

@@ -7,7 +7,8 @@
information, see COPYING. information, see COPYING.
]] ]]
AtreidesBase = { AConyard, AOutpost, ARefinery, AHeavyFactory, ALightFactory, AGunt1, AGunt2, ABarracks, ASilo, APower1, APower2, APower3, APower4, APower5, APower6 } AtreidesBase = { AConyard, AOutpost, ARefinery, AHeavyFactory, ALightFactory, AGunt1, AGunt2, ABarracks, APower1, APower2, APower3, APower4, APower5, APower6 }
FremenBase = { FGunt1, FGunt2 } FremenBase = { FGunt1, FGunt2 }
BaseAreaTriggers = BaseAreaTriggers =
@@ -105,6 +106,8 @@ FremenHunterPaths =
{ FremenEntry3.Location, FremenRally3.Location } { FremenEntry3.Location, FremenRally3.Location }
} }
FremenAmbushSquad = { FremenAmbuser1, FremenAmbuser2, FremenAmbuser3, FremenAmbuser4 }
HarkonnenReinforcements = { "combat_tank_h", "combat_tank_h" } HarkonnenReinforcements = { "combat_tank_h", "combat_tank_h" }
HarkonnenPath = { HarkonnenEntry.Location, HarkonnenRally.Location } HarkonnenPath = { HarkonnenEntry.Location, HarkonnenRally.Location }
@@ -156,7 +159,8 @@ WorldLoaded = function()
Atreides = Player.GetPlayer("Atreides") Atreides = Player.GetPlayer("Atreides")
Fremen = Player.GetPlayer("Fremen") Fremen = Player.GetPlayer("Fremen")
Harkonnen = Player.GetPlayer("Harkonnen") Harkonnen = Player.GetPlayer("Harkonnen")
Defending[Atreides] = {}
Defending[Fremen] = {}
InitObjectives(Harkonnen) InitObjectives(Harkonnen)
KillAtreides = AddPrimaryObjective(Harkonnen, "destroy-atreides") KillAtreides = AddPrimaryObjective(Harkonnen, "destroy-atreides")
KillFremen = AddPrimaryObjective(Harkonnen, "destroy-fremen") KillFremen = AddPrimaryObjective(Harkonnen, "destroy-fremen")
@@ -164,11 +168,7 @@ WorldLoaded = function()
Camera.Position = HConyard.CenterPosition Camera.Position = HConyard.CenterPosition
FremenAttackLocation = HConyard.Location FremenAttackLocation = HConyard.Location
IdleHuntOnBaseDestroyed(Atreides, AtreidesBase)
Trigger.OnAllKilledOrCaptured(AtreidesBase, function()
Utils.Do(Atreides.GetGroundAttackers(), IdleHunt)
end)
Trigger.OnAllKilled(Sietches, function() Trigger.OnAllKilled(Sietches, function()
SietchesAreDestroyed = true SietchesAreDestroyed = true
end) end)
@@ -179,6 +179,7 @@ WorldLoaded = function()
unit.AttackMove(FremenAttackLocation) unit.AttackMove(FremenAttackLocation)
IdleHunt(unit) IdleHunt(unit)
end end
SendCarryallReinforcements(Fremen, 0, FremenAttackWaves[Difficulty], FremenAttackDelay[Difficulty], path, FremenReinforcements[Difficulty], waveCondition, huntFunction) SendCarryallReinforcements(Fremen, 0, FremenAttackWaves[Difficulty], FremenAttackDelay[Difficulty], path, FremenReinforcements[Difficulty], waveCondition, huntFunction)
Actor.Create("upgrade.barracks", true, { Owner = Atreides }) Actor.Create("upgrade.barracks", true, { Owner = Atreides })
@@ -201,4 +202,17 @@ WorldLoaded = function()
TriggerCarryallReinforcements(Harkonnen, Fremen, BaseAreaTriggers[1], FremenHunters[1], FremenHunterPaths[3], fremenCondition) TriggerCarryallReinforcements(Harkonnen, Fremen, BaseAreaTriggers[1], FremenHunters[1], FremenHunterPaths[3], fremenCondition)
TriggerCarryallReinforcements(Harkonnen, Fremen, BaseAreaTriggers[2], FremenHunters[2], FremenHunterPaths[2], fremenCondition) TriggerCarryallReinforcements(Harkonnen, Fremen, BaseAreaTriggers[2], FremenHunters[2], FremenHunterPaths[2], fremenCondition)
TriggerCarryallReinforcements(Harkonnen, Fremen, BaseAreaTriggers[3], FremenHunters[3], FremenHunterPaths[1], fremenCondition) TriggerCarryallReinforcements(Harkonnen, Fremen, BaseAreaTriggers[3], FremenHunters[3], FremenHunterPaths[1], fremenCondition)
Trigger.OnRemovedFromWorld(ExplosionCrate, function()
Utils.Do(FremenAmbushSquad, function(fremen)
fremen.Stance = "AttackAnything"
end)
end)
Trigger.OnAllKilled({AGunt1, AGunt2}, function()
EmergencyBuildRate[Atreides] = true
Trigger.AfterDelay(600, function()
EmergencyBuildRate[Atreides] = false
end)
end)
end end

View File

@@ -376,6 +376,54 @@ Actors:
AtreidesEntry3: waypoint AtreidesEntry3: waypoint
Owner: Neutral Owner: Neutral
Location: 22,91 Location: 22,91
APatrolPoint1: waypoint
Owner: Neutral
Location: 56,67
APatrolPoint2: waypoint
Owner: Neutral
Location: 34,43
APatrolPoint3: waypoint
Owner: Neutral
Location: 23,18
APatrolPoint4: waypoint
Owner: Neutral
Location: 60,17
Actor6: crate
Owner: Neutral
Location: 25,12
Actor8: crate
Owner: Neutral
Location: 8,18
ExplosionCrate: crate_explosion
Owner: Neutral
Location: 18,28
FremenAmbuser1: fremen
Owner: Fremen
Location: 15,25
SubCell: 3
Facing: 384
Stance: ReturnFire
FremenAmbuser2: fremen
Owner: Fremen
Location: 20,25
SubCell: 3
Stance: ReturnFire
Facing: 384
FremenAmbuser3: fremen
Owner: Fremen
Location: 15,28
SubCell: 3
Stance: ReturnFire
Facing: 384
FremenAmbuser4: fremen
Owner: Fremen
Location: 15,29
SubCell: 3
Stance: ReturnFire
Facing: 384
Actor32: crate_reveal
Owner: Neutral
Location: 16,47
Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml

View File

@@ -1,6 +1,68 @@
Player: Player:
PlayerResources: PlayerResources:
DefaultCash: 5000 DefaultCash: 5000
ExternalCondition@AI:
Condition: base-rebuilder
ExternalCondition@AIDefense:
Condition: defense-rebuilder
BaseBuilderBotModule@AIMainBase:
RequiresCondition: base-rebuilder
BuildingQueues: Building, Upgrade
MinimumExcessPower: 0
MaximumExcessPower: 250
MaxBaseRadius: 40
ConstructionYardTypes: construction_yard
RefineryTypes: refinery
PowerTypes: wind_trap
ProductionTypes: light_factory, heavy_factory, barracks, starport
SiloTypes: silo
DefenseTypes: medium_gun_turret,large_gun_turret
SellRefineryInterval: -1
BuildingLimits:
barracks: 1
refinery: 1
outpost: 1
light_factory: 1
heavy_factory: 1
wind_trap: 7
silo: 1
BuildingFractions:
wind_trap: 1
barracks: 1
refinery: 1
outpost: 1
light_factory: 1
heavy_factory: 1
BaseBuilderBotModule@AIMainBaseWithDefense:
RequiresCondition: defense-rebuilder
BuildingQueues: Building, Upgrade
MinimumExcessPower: 0
MaximumExcessPower: 250
MaxBaseRadius: 40
ConstructionYardTypes: construction_yard
RefineryTypes: refinery
PowerTypes: wind_trap
ProductionTypes: light_factory, heavy_factory, barracks, starport
SiloTypes: silo
DefenseTypes: medium_gun_turret,large_gun_turret
SellRefineryInterval: -1
BuildingLimits:
barracks: 1
refinery: 1
outpost: 1
light_factory: 1
heavy_factory: 1
wind_trap: 7
silo: 1
medium_gun_turret: 2
BuildingFractions:
wind_trap: 1
barracks: 1
refinery: 1
outpost: 1
light_factory: 1
heavy_factory: 1
medium_gun_turret: 2
World: World:
LuaScript: LuaScript:

View File

@@ -7,6 +7,24 @@
information, see COPYING. information, see COPYING.
]] ]]
EarlyGameStage = DateTime.Minutes(6)
InitialProductionDelay = {
OrdosMain =
{
easy = DateTime.Seconds(150),
normal = DateTime.Seconds(100),
hard = DateTime.Seconds(50)
},
OrdosSmall =
{
easy = DateTime.Seconds(120),
normal = DateTime.Seconds(60),
hard = DateTime.Seconds(30)
},
}
AttackGroupSize = AttackGroupSize =
{ {
easy = 6, easy = 6,
@@ -14,7 +32,7 @@ AttackGroupSize =
hard = 10 hard = 10
} }
AttackDelays = ProductionDelays =
{ {
easy = { DateTime.Seconds(4), DateTime.Seconds(7) }, easy = { DateTime.Seconds(4), DateTime.Seconds(7) },
normal = { DateTime.Seconds(2), DateTime.Seconds(5) }, normal = { DateTime.Seconds(2), DateTime.Seconds(5) },
@@ -22,28 +40,86 @@ AttackDelays =
} }
OrdosInfantryTypes = { "light_inf", "light_inf", "light_inf", "trooper", "trooper" } OrdosInfantryTypes = { "light_inf", "light_inf", "light_inf", "trooper", "trooper" }
OrdosVehicleTypes = { "raider", "raider", "quad" } OrdosVehicleTypes = { "raider", "raider", "quad" }
OrdosTankType = { "combat_tank_o" } OrdosTankType = { "combat_tank_o" }
ActivateAI = function() ActivateAI = function()
Defending[OrdosMain] = {}
Defending[OrdosSmall] = {}
AttackDelay[OrdosMain] = 8000 * DifficultyModifier[Difficulty]
AttackDelay[OrdosSmall] = 10000 * DifficultyModifier[Difficulty]
AttackDelay[Corrino] = 1000 * DifficultyModifier[Difficulty]
TimeBetweenAttacks[OrdosMain] = 8000 * DifficultyModifier[Difficulty]
TimeBetweenAttacks[OrdosSmall] = 7000 * DifficultyModifier[Difficulty]
TimeBetweenAttacks[Corrino] = 2000 * DifficultyModifier[Difficulty]
HarvesterCount[OrdosMain] = 2
HarvesterCount[OrdosSmall] = 2
Trigger.OnAllKilledOrCaptured(ProductionBuildingsOrdosSmallBase, function()
TimeBetweenAttacks[OrdosMain] = 0
end)
PatrolPoints[OrdosMain] = {OrdosPatrol1.Location, OrdosPatrol2.Location }
PatrolPoints[OrdosSmall] = {OrdosRally1.Location, OrdosRally2.Location, OrdosRally4.Location }
DefencePerimeter[OrdosMain] = GetCellsInRectangle(CPos.New(51,11), CPos.New(67,38))
DefencePerimeter[OrdosSmall] = GetCellsInRectangle(CPos.New(6,69), CPos.New(22,80))
IdlingUnits[OrdosMain] = Utils.Concat(Reinforcements.Reinforce(OrdosMain, InitialOrdosReinforcements[1], InitialOrdosPaths[1]), Reinforcements.Reinforce(OrdosMain, InitialOrdosReinforcements[2], InitialOrdosPaths[2])) IdlingUnits[OrdosMain] = Utils.Concat(Reinforcements.Reinforce(OrdosMain, InitialOrdosReinforcements[1], InitialOrdosPaths[1]), Reinforcements.Reinforce(OrdosMain, InitialOrdosReinforcements[2], InitialOrdosPaths[2]))
IdlingUnits[OrdosSmall] = Reinforcements.Reinforce(OrdosSmall, InitialOrdosReinforcements[1], InitialOrdosPaths[3]) IdlingUnits[OrdosSmall] = Reinforcements.Reinforce(OrdosSmall, InitialOrdosReinforcements[1], InitialOrdosPaths[3])
IdlingUnits[Corrino] = { CSaraukar1, CSaraukar2, CSaraukar3, CSaraukar4, CSaraukar5 } IdlingUnits[Corrino] = { CSardaukar1, CSardaukar2, CSardaukar3, CSardaukar4, CSardaukar5 }
DefendAndRepairBase(OrdosMain, OrdosMainBase, 0.75, AttackGroupSize[Difficulty]) DefendAndRepairBase(OrdosMain, OrdosMainBase, 0.75, AttackGroupSize[Difficulty])
DefendAndRepairBase(OrdosSmall, OrdosSmallBase, 0.75, AttackGroupSize[Difficulty]) DefendAndRepairBase(OrdosSmall, OrdosSmallBase, 0.75, AttackGroupSize[Difficulty])
DefendAndRepairBase(Corrino, CorrinoBase, 0.75, AttackGroupSize[Difficulty]) DefendAndRepairBase(Corrino, CorrinoBase, 0.75, AttackGroupSize[Difficulty])
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end local delay = function(player)
if EmergencyBuildRate[player] and Difficulty ~= "easy" then
return 1
end
return Utils.RandomInteger(ProductionDelays[Difficulty][1], ProductionDelays[Difficulty][2] + 1)
end
local infantryToBuild = function() return { Utils.Random(OrdosInfantryTypes) } end local infantryToBuild = function() return { Utils.Random(OrdosInfantryTypes) } end
local vehilcesToBuild = function() return { Utils.Random(OrdosVehicleTypes) } end local vehiclesToBuild = function() return { Utils.Random(OrdosVehicleTypes) } end
local tanksToBuild = function() return OrdosTankType end local tanksToBuild = function() return OrdosTankType end
local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5 local attackThresholdSize = {}
attackThresholdSize[OrdosMain] = AttackGroupSize[Difficulty] * 3
attackThresholdSize[OrdosSmall] = AttackGroupSize[Difficulty] * 2
ProduceUnits(OrdosMain, OBarracks1, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize) Trigger.AfterDelay(InitialProductionDelay["OrdosMain"][Difficulty], function()
ProduceUnits(OrdosMain, OLightFactory1, delay, vehilcesToBuild, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(OrdosMain, OBarracks1, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize[OrdosMain])
ProduceUnits(OrdosMain, OHeavyFactory, delay, tanksToBuild, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(OrdosMain, OLightFactory1, delay, vehiclesToBuild, AttackGroupSize[Difficulty], attackThresholdSize[OrdosMain])
ProduceUnits(OrdosMain, OHeavyFactory, delay, tanksToBuild, AttackGroupSize[Difficulty], attackThresholdSize[OrdosMain])
end)
ProduceUnits(OrdosSmall, OBarracks3, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize) Trigger.AfterDelay(InitialProductionDelay["OrdosSmall"][Difficulty], function()
ProduceUnits(OrdosSmall, OLightFactory2, delay, vehilcesToBuild, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(OrdosSmall, OBarracks3, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize[OrdosSmall])
ProduceUnits(OrdosSmall, OLightFactory2, delay, vehiclesToBuild, AttackGroupSize[Difficulty], attackThresholdSize[OrdosSmall])
end)
ActivateCrushLogic()
if Difficulty == "normal" then
OrdosMain.GrantCondition("base-rebuilder")
end
if Difficulty == "hard" then
OrdosMain.GrantCondition("defense-rebuilder")
end
local productionTypes =
{
barracks = infantryToBuild,
light_factory = vehiclesToBuild,
heavy_factory = tanksToBuild
}
Trigger.OnBuildingPlaced(OrdosMain, function(p, building)
table.insert(OrdosMainBase, building)
DefendAndRepairBase(OrdosMain, {building}, 0.75, AttackGroupSize[Difficulty] )
if productionTypes[building.Type] == nil then return end
ProduceUnits(OrdosMain, building, delay, productionTypes[building.Type], AttackGroupSize[Difficulty], attackThresholdSize[OrdosMain])
end)
end end

View File

@@ -8,9 +8,15 @@
]] ]]
OrdosMainBase = { OConYard, OOutpost, ORefinery1, ORefinery2, OHeavyFactory, OLightFactory1, OHiTechFactory, OGunt1, OGunt2, OGunt3, OGunt4, OBarracks1, OBarracks2, OPower1, OPower2, OPower3, OPower4, OPower5, OPower6, OPower7, OPower8, OPower9 } OrdosMainBase = { OConYard, OOutpost, ORefinery1, ORefinery2, OHeavyFactory, OLightFactory1, OHiTechFactory, OGunt1, OGunt2, OGunt3, OGunt4, OBarracks1, OBarracks2, OPower1, OPower2, OPower3, OPower4, OPower5, OPower6, OPower7, OPower8, OPower9 }
OrdosSmallBase = { ORefinery3, OBarracks3, OLightFactory2, OGunt5, OGunt6, OPower10, OPower11, OPower12, OPower13, OSilo } OrdosSmallBase = { ORefinery3, OBarracks3, OLightFactory2, OGunt5, OGunt6, OPower10, OPower11, OPower12, OPower13, OSilo }
CorrinoBase = { CStarport, CPower1, CPower2 } CorrinoBase = { CStarport, CPower1, CPower2 }
ProductionBuildingsOrdosSmallBase = { ORefinery3, OBarracks3, OLightFactory2 }
SmugglerSquad = {Smuggler1, Smuggler2, Smuggler3}
BaseAreaTriggers = BaseAreaTriggers =
{ {
{ CPos.New(68, 70), CPos.New(69, 70), CPos.New(70, 70), CPos.New(71, 70) }, { CPos.New(68, 70), CPos.New(69, 70), CPos.New(70, 70), CPos.New(71, 70) },
@@ -135,6 +141,7 @@ SendStarportReinforcements = function()
return return
end end
Media.DisplayMessage(UserInterface.GetFluentMessage("imperial-ships-penetrating-defense-grid"), Mentat)
local units = Reinforcements.ReinforceWithTransport(Corrino, "frigate", CorrinoStarportReinforcements[Difficulty], { CorrinoStarportEntry.Location, CStarport.Location + CVec.New(1, 1) }, { CorrinoStarportExit.Location })[2] local units = Reinforcements.ReinforceWithTransport(Corrino, "frigate", CorrinoStarportReinforcements[Difficulty], { CorrinoStarportEntry.Location, CStarport.Location + CVec.New(1, 1) }, { CorrinoStarportExit.Location })[2]
Utils.Do(units, function(unit) Utils.Do(units, function(unit)
unit.AttackMove(OrdosAttackLocation) unit.AttackMove(OrdosAttackLocation)
@@ -142,12 +149,6 @@ SendStarportReinforcements = function()
end) end)
SendStarportReinforcements() SendStarportReinforcements()
if Harkonnen.IsObjectiveFailed(GuardOutpost) then
return
end
Media.DisplayMessage(UserInterface.GetFluentMessage("imperial-ships-penetrating-defense-grid"), Mentat)
end) end)
end end
@@ -222,13 +223,28 @@ Tick = function()
end end
end end
ChangeOwner = function(old_owner, new_owner)
local units = old_owner.GetActors()
Utils.Do(units, function(unit)
if not unit.IsDead then
unit.Owner = new_owner
end
end)
end
WorldLoaded = function() WorldLoaded = function()
OrdosMain = Player.GetPlayer("Ordos Main Base") OrdosMain = Player.GetPlayer("Ordos Main Base")
OrdosSmall = Player.GetPlayer("Ordos Small Base") OrdosSmall = Player.GetPlayer("Ordos Small Base")
Corrino = Player.GetPlayer("Corrino") Corrino = Player.GetPlayer("Corrino")
Harkonnen = Player.GetPlayer("Harkonnen") Harkonnen = Player.GetPlayer("Harkonnen")
SmugglerNeutral = Player.GetPlayer("Smugglers - Neutral")
SmugglerEnemy = Player.GetPlayer("Smugglers - Enemy")
Defending[OrdosMain] = {}
Defending[OrdosSmall] = {}
Defending[Corrino] = {}
InitObjectives(Harkonnen) InitObjectives(Harkonnen)
KillOrdos = AddPrimaryObjective(Harkonnen, "destroy-ordos") KillOrdos = AddPrimaryObjective(Harkonnen, "destroy-ordos")
KillCorrino = AddPrimaryObjective(Harkonnen, "destroy-imperial-forces") KillCorrino = AddPrimaryObjective(Harkonnen, "destroy-imperial-forces")
GuardOutpost = AddSecondaryObjective(Harkonnen, "keep-modified-outpost-intact") GuardOutpost = AddSecondaryObjective(Harkonnen, "keep-modified-outpost-intact")
@@ -257,17 +273,20 @@ WorldLoaded = function()
Media.DisplayMessage(UserInterface.GetFluentMessage("protect-outpost"), Mentat) Media.DisplayMessage(UserInterface.GetFluentMessage("protect-outpost"), Mentat)
end) end)
Trigger.OnAllKilledOrCaptured({ HOutpost }, function()
SendStarportReinforcements()
end)
local path = function() return Utils.Random(OrdosPaths) end local path = function() return Utils.Random(OrdosPaths) end
local waveCondition = function() return Harkonnen.IsObjectiveCompleted(KillOrdos) end local waveCondition = function() return Harkonnen.IsObjectiveCompleted(KillOrdos) end
local huntFunction = function(unit) local huntFunction = function(unit)
unit.AttackMove(OrdosAttackLocation) unit.AttackMove(OrdosAttackLocation)
IdleHunt(unit) IdleHunt(unit)
end end
SendCarryallReinforcements(OrdosMain, 0, OrdosAttackWaves[Difficulty], OrdosAttackDelay[Difficulty], path, OrdosReinforcements[Difficulty], waveCondition, huntFunction) SendCarryallReinforcements(OrdosMain, 0, OrdosAttackWaves[Difficulty], OrdosAttackDelay[Difficulty], path, OrdosReinforcements[Difficulty], waveCondition, huntFunction)
OrdosReinforcementNotification(0, OrdosAttackWaves[Difficulty]) OrdosReinforcementNotification(0, OrdosAttackWaves[Difficulty])
SendStarportReinforcements()
Actor.Create("upgrade.barracks", true, { Owner = OrdosMain }) Actor.Create("upgrade.barracks", true, { Owner = OrdosMain })
Actor.Create("upgrade.light", true, { Owner = OrdosMain }) Actor.Create("upgrade.light", true, { Owner = OrdosMain })
Actor.Create("upgrade.heavy", true, { Owner = OrdosMain }) Actor.Create("upgrade.heavy", true, { Owner = OrdosMain })

Binary file not shown.

View File

@@ -514,6 +514,18 @@ Actors:
HarkonnenEntry2: waypoint HarkonnenEntry2: waypoint
Owner: Neutral Owner: Neutral
Location: 2,29 Location: 2,29
OrdosPatrol1: waypoint
Owner: Neutral
Location: 33,19
OrdosPatrol2: waypoint
Owner: Neutral
Location: 37,41
Actor9: crate
Owner: Neutral
Location: 48,54
Actor10: crate
Owner: Neutral
Location: 49,53
Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml

View File

@@ -1,6 +1,68 @@
Player: Player:
PlayerResources: PlayerResources:
DefaultCash: 6000 DefaultCash: 6000
ExternalCondition@AI:
Condition: base-rebuilder
ExternalCondition@AIDefense:
Condition: defense-rebuilder
BaseBuilderBotModule@campaign:
RequiresCondition: base-rebuilder
BuildingQueues: Building, Upgrade
MinimumExcessPower: 0
MaximumExcessPower: 250
MaxBaseRadius: 40
ConstructionYardTypes: construction_yard
RefineryTypes: refinery
PowerTypes: wind_trap
ProductionTypes: light_factory, heavy_factory, barracks
SiloTypes: silo
DefenseTypes: medium_gun_turret,large_gun_turret
SellRefineryInterval: -1
BuildingLimits:
barracks: 1
refinery: 1
outpost: 1
light_factory: 1
heavy_factory: 1
wind_trap: 8
silo: 1
BuildingFractions:
wind_trap: 1
barracks: 1
refinery: 1
outpost: 1
light_factory: 1
heavy_factory: 1
BaseBuilderBotModule@defense:
RequiresCondition: defense-rebuilder
BuildingQueues: Building, Upgrade
MinimumExcessPower: 0
MaximumExcessPower: 250
MaxBaseRadius: 40
ConstructionYardTypes: construction_yard
RefineryTypes: refinery
PowerTypes: wind_trap
ProductionTypes: light_factory, heavy_factory, barracks
SiloTypes: silo
DefenseTypes: medium_gun_turret
SellRefineryInterval: -1
BuildingLimits:
barracks: 1
refinery: 1
outpost: 1
light_factory: 1
heavy_factory: 1
wind_trap: 8
silo: 1
medium_gun_turret: 4
BuildingFractions:
wind_trap: 1
barracks: 1
refinery: 1
outpost: 1
light_factory: 1
heavy_factory: 1
medium_gun_turret: 1
World: World:
LuaScript: LuaScript:

View File

@@ -7,6 +7,24 @@
information, see COPYING. information, see COPYING.
]] ]]
EarlyGameStage = DateTime.Minutes(6)
InitialProductionDelay = {
OrdosMain =
{
easy = DateTime.Seconds(140),
normal = DateTime.Seconds(80),
hard = DateTime.Seconds(40)
},
OrdosSmall =
{
easy = DateTime.Seconds(120),
normal = DateTime.Seconds(60),
hard = DateTime.Seconds(30)
},
}
AttackGroupSize = AttackGroupSize =
{ {
easy = 6, easy = 6,
@@ -14,7 +32,14 @@ AttackGroupSize =
hard = 10 hard = 10
} }
AttackDelays = EarlyProductionDelays =
{
easy = { DateTime.Seconds(10), DateTime.Seconds(13) },
normal = { DateTime.Seconds(6), DateTime.Seconds(8) },
hard = { DateTime.Seconds(3), DateTime.Seconds(5) }
}
LateProductionDelays =
{ {
easy = { DateTime.Seconds(4), DateTime.Seconds(7) }, easy = { DateTime.Seconds(4), DateTime.Seconds(7) },
normal = { DateTime.Seconds(2), DateTime.Seconds(5) }, normal = { DateTime.Seconds(2), DateTime.Seconds(5) },
@@ -22,29 +47,90 @@ AttackDelays =
} }
OrdosInfantryTypes = { "light_inf", "light_inf", "trooper", "trooper", "trooper" } OrdosInfantryTypes = { "light_inf", "light_inf", "trooper", "trooper", "trooper" }
OrdosVehicleTypes = { "raider", "raider", "quad" } OrdosVehicleTypes = { "raider", "raider", "quad" }
OrdosTankTypes = { "combat_tank_o", "combat_tank_o", "siege_tank" } OrdosTankTypes = { "combat_tank_o", "combat_tank_o", "siege_tank" }
OrdosStarportTypes = { "trike.starport", "trike.starport", "quad.starport", "combat_tank_o.starport", "combat_tank_o.starport", "siege_tank.starport", "missile_tank.starport" } OrdosStarportTypes = { "trike.starport", "trike.starport", "quad.starport", "combat_tank_o.starport", "combat_tank_o.starport", "siege_tank.starport", "missile_tank.starport" }
ActivateAI = function() ActivateAI = function()
Defending[OrdosMain] = {}
Defending[OrdosSmall] = {}
AttackDelay[OrdosMain] = 14000 * DifficultyModifier[Difficulty]
AttackDelay[OrdosSmall] = 14000 * DifficultyModifier[Difficulty]
TimeBetweenAttacks[OrdosMain] = 10000 * DifficultyModifier[Difficulty]
TimeBetweenAttacks[OrdosSmall] = 8000 * DifficultyModifier[Difficulty]
HarvesterCount[OrdosMain] = 4
HarvesterCount[OrdosSmall] = 2
Trigger.OnAllKilledOrCaptured(ProductionBuildingsOrdosSmallBase, function()
TimeBetweenAttacks[OrdosMain] = 0
end)
PatrolPoints[OrdosMain] = {OrdosRally5.Location, OrdosRally11.Location, OrdosRally12.Location }
PatrolPoints[OrdosSmall] = {OrdosRally5.Location, OrdosRally7.Location, OrdosRally4.Location, OrdosRally5.Location }
DefencePerimeter[OrdosMain] = Utils.Concat( GetCellsInRectangle(CPos.New(37,30), CPos.New(69,50)), GetCellsInRectangle(CPos.New(54,13), CPos.New(70,30)))
DefencePerimeter[OrdosSmall] = GetCellsInRectangle(CPos.New(4,20), CPos.New(15,40))
IdlingUnits[OrdosMain] = Utils.Concat(Reinforcements.Reinforce(OrdosMain, InitialOrdosReinforcements[1], InitialOrdosPaths[1]), Reinforcements.Reinforce(OrdosMain, InitialOrdosReinforcements[2], InitialOrdosPaths[2])) IdlingUnits[OrdosMain] = Utils.Concat(Reinforcements.Reinforce(OrdosMain, InitialOrdosReinforcements[1], InitialOrdosPaths[1]), Reinforcements.Reinforce(OrdosMain, InitialOrdosReinforcements[2], InitialOrdosPaths[2]))
IdlingUnits[OrdosSmall] = Reinforcements.Reinforce(OrdosSmall, InitialOrdosReinforcements[1], InitialOrdosPaths[3]) IdlingUnits[OrdosSmall] = Reinforcements.Reinforce(OrdosSmall, InitialOrdosReinforcements[1], InitialOrdosPaths[3])
DefendAndRepairBase(OrdosMain, OrdosMainBase, 0.75, AttackGroupSize[Difficulty]) DefendAndRepairBase(OrdosMain, OrdosMainBase, 0.75, AttackGroupSize[Difficulty])
DefendAndRepairBase(OrdosSmall, OrdosSmallBase, 0.75, AttackGroupSize[Difficulty]) DefendAndRepairBase(OrdosSmall, OrdosSmallBase, 0.75, AttackGroupSize[Difficulty])
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end local delay = function(player)
if EmergencyBuildRate[player] and Difficulty ~= "easy" then
return 1
end
if EarlyGameStage >= DateTime.GameTime then
return Utils.RandomInteger(EarlyProductionDelays[Difficulty][1], EarlyProductionDelays[Difficulty][2] + 1)
else
return Utils.RandomInteger(LateProductionDelays[Difficulty][1], LateProductionDelays[Difficulty][2] + 1)
end
end
local infantryToBuild = function() return { Utils.Random(OrdosInfantryTypes) } end local infantryToBuild = function() return { Utils.Random(OrdosInfantryTypes) } end
local vehilcesToBuild = function() return { Utils.Random(OrdosVehicleTypes) } end local vehiclesToBuild = function() return { Utils.Random(OrdosVehicleTypes) } end
local tanksToBuild = function() return { Utils.Random(OrdosTankTypes) } end local tanksToBuild = function() return { Utils.Random(OrdosTankTypes) } end
local unitsToBuy = function() return { Utils.Random(OrdosStarportTypes) } end local unitsToBuy = function() return { Utils.Random(OrdosStarportTypes) } end
local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5 local attackThresholdSize = {}
attackThresholdSize[OrdosMain] = AttackGroupSize[Difficulty] * 3
attackThresholdSize[OrdosSmall] = AttackGroupSize[Difficulty] * 2
ProduceUnits(OrdosMain, OBarracks1, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize) Trigger.AfterDelay(InitialProductionDelay["OrdosMain"][Difficulty], function()
ProduceUnits(OrdosMain, OLightFactory1, delay, vehilcesToBuild, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(OrdosMain, OBarracks1, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize[OrdosMain])
ProduceUnits(OrdosMain, OHeavyFactory1, delay, tanksToBuild, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(OrdosMain, OLightFactory1, delay, vehiclesToBuild, AttackGroupSize[Difficulty], attackThresholdSize[OrdosMain])
ProduceUnits(OrdosMain, OStarport, delay, unitsToBuy, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(OrdosMain, OHeavyFactory1, delay, tanksToBuild, AttackGroupSize[Difficulty], attackThresholdSize[OrdosMain])
ProduceUnits(OrdosMain, OStarport, delay, unitsToBuy, AttackGroupSize[Difficulty], attackThresholdSize[OrdosMain])
end)
ProduceUnits(OrdosSmall, OBarracks2, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize) Trigger.AfterDelay(InitialProductionDelay["OrdosSmall"][Difficulty], function()
ProduceUnits(OrdosSmall, OLightFactory2, delay, vehilcesToBuild, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(OrdosSmall, OBarracks2, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize[OrdosSmall] )
ProduceUnits(OrdosSmall, OLightFactory2, delay, vehiclesToBuild, AttackGroupSize[Difficulty], attackThresholdSize[OrdosSmall] )
end)
ActivateCrushLogic()
if Difficulty == "normal" then
OrdosSmall.GrantCondition("base-rebuilder2")
end
if Difficulty == "hard" then
OrdosSmall.GrantCondition("defense-rebuilder2")
end
local productionTypes =
{
barracks = infantryToBuild,
light_factory = vehiclesToBuild,
heavy_factory = tanksToBuild
}
Trigger.OnBuildingPlaced(OrdosSmall, function(p, building)
table.insert(OrdosSmallBase, building)
DefendAndRepairBase(OrdosSmall, {building}, 0.75, AttackGroupSize[Difficulty] )
if productionTypes[building.Type] == nil then return end
ProduceUnits(OrdosSmall, building, delay, productionTypes[building.Type], AttackGroupSize[Difficulty], attackThresholdSize[OrdosSmall])
end)
end end

View File

@@ -8,8 +8,18 @@
]] ]]
OrdosMainBase = { OOutpost, ORefinery1, ORefinery2, OHeavyFactory1, OHeavyFactory2, OLightFactory1, OHiTechFactory, OResearch, ORepair, OStarport, OGunt1, OGunt2, OGunt3, OGunt4, OGunt5, OGunt6, OGunt7, OGunt8, OGunt9, OGunt10, OGunt11, OGunt12, OBarracks1, OPower1, OPower2, OPower3, OPower4, OPower5, OPower6, OPower7, OPower8, OPower9, OPower10 } OrdosMainBase = { OOutpost, ORefinery1, ORefinery2, OHeavyFactory1, OHeavyFactory2, OLightFactory1, OHiTechFactory, OResearch, ORepair, OStarport, OGunt1, OGunt2, OGunt3, OGunt4, OGunt5, OGunt6, OGunt7, OGunt8, OGunt9, OGunt10, OGunt11, OGunt12, OBarracks1, OPower1, OPower2, OPower3, OPower4, OPower5, OPower6, OPower7, OPower8, OPower9, OPower10 }
OrdosSmallBase = { OConyard, ORefinery3, OBarracks2, OLightFactory2, OGunt13, OGunt14, OGunt15, OGunt16, OPower11, OPower12, OPower13, OPower14 } OrdosSmallBase = { OConyard, ORefinery3, OBarracks2, OLightFactory2, OGunt13, OGunt14, OGunt15, OGunt16, OPower11, OPower12, OPower13, OPower14 }
ProductionBuildingsOrdosSmallBase = { OConyard, ORefinery3, OBarracks2, OLightFactory2 }
SmugglerTriggerZone = Utils.Concat(
GetCellsInRectangle(CPos.New(73,67), CPos.New(81,72)),
GetCellsInRectangle(CPos.New(77,73), CPos.New(82,77))
)
SmugglerPatrol = {Smuggler1, Smuggler2, Smuggler3, Smuggler4, Smuggler5, Smuggler6 }
OrdosReinforcements = OrdosReinforcements =
{ {
easy = easy =
@@ -149,9 +159,62 @@ ChangeOwner = function(old_owner, new_owner)
end) end)
end end
Message = {}
StopFollowing = {}
Trigger.OnEnteredFootprint(SmugglerTriggerZone, function(a, id)
if SmugglerNeutral.HasNoRequiredUnits() then
Trigger.RemoveFootprintTrigger(id)
end
if a.Owner == Harkonnen and not Message[Harkonnen] then
Media.DisplayMessage(UserInterface.GetFluentMessage("smuggler-warning-harkonnen"), "Smugglers", HSLColor.FromHex("7B2910"))
Message[Harkonnen] = true
end
if a.Owner == OrdosMain or a.Owner == OrdosSmall and not Message[Ordos] then
Media.DisplayMessage(UserInterface.GetFluentMessage("smuggler-warning-ordos"), "Smugglers", HSLColor.FromHex("7B2910"))
Message[Ordos] = true
end
if a.Owner ~= SmugglerNeutral then
Utils.Do(SmugglerPatrol, function(u)
if not u.IsDead then
StopFollowing[u] = false
FollowIntruder(u,a)
end
end)
end
end)
Trigger.OnExitedFootprint(SmugglerTriggerZone, function(a, id)
if SmugglerNeutral.HasNoRequiredUnits() then
Trigger.RemoveFootprintTrigger(id)
end
if a.Owner ~= SmugglerNeutral then
Utils.Do(SmugglerPatrol, function(u)
if not u.IsDead then StopFollowing[u] = true end
end)
end
end)
FollowIntruder = function(unit, intruder)
if intruder.IsDead or unit.IsDead then return end
if StopFollowing[unit] == true then unit.Stop() return end
unit.Stop()
unit.AttackMove(intruder.Location,1)
Trigger.AfterDelay(100, function() FollowIntruder(unit, intruder) end)
end
CheckSmugglerEnemies = function() CheckSmugglerEnemies = function()
Utils.Do(SmugglerUnits, function(unit) Utils.Do(SmugglerUnits, function(unit)
Trigger.OnDamaged(unit, function(self, attacker) Trigger.OnDamaged(unit, function(self, attacker)
if Utils.Any(IgnoreDamageFromTypes, function(a) return a == attacker.Type end) then
return
end
if not self.HasProperty("Health") then return end
if self.MaxHealth * 0.9 < self.Health then return end
if unit.Owner == SmugglerNeutral and attacker.Owner == Harkonnen then if unit.Owner == SmugglerNeutral and attacker.Owner == Harkonnen then
ChangeOwner(SmugglerNeutral, SmugglerHarkonnen) ChangeOwner(SmugglerNeutral, SmugglerHarkonnen)
@@ -197,6 +260,25 @@ CheckSmugglerEnemies = function()
end) end)
end end
EmergencyBehaviour = function(player, target)
if player ~= OrdosSmall then return end
if not OGunt15.IsDead and not OGunt16.IsDead then return end
if #IdlingUnits[OrdosMain] > 10 and Utils.Any(ProductionBuildingsOrdosSmallBase, function(a) return not a.IsDead end) then
local reinforcements = SetupAttackGroup(OrdosMain, Utils.RandomInteger(5, #IdlingUnits[OrdosMain]))
Utils.Do(reinforcements, function(unit)
Trigger.ClearAll(unit)
Trigger.AfterDelay(1, function()
unit.Stop()
unit.Move(OrdosRally13.Location,1)
unit.AttackMove(target)
unit.CallFunc(function()
FindTargetsInArea(player, unit)
end)
end)
end)
end
end
Tick = function() Tick = function()
if Harkonnen.HasNoRequiredUnits() then if Harkonnen.HasNoRequiredUnits() then
OrdosMain.MarkCompletedObjective(KillHarkonnen1) OrdosMain.MarkCompletedObjective(KillHarkonnen1)
@@ -234,6 +316,8 @@ Tick = function()
ProtectHarvester(units[1], OrdosSmall, AttackGroupSize[Difficulty]) ProtectHarvester(units[1], OrdosSmall, AttackGroupSize[Difficulty])
end end
end end
if IdlingUnits[OrdosMain] == nil and IdlingUnits[OrdosSmall] == nil then return end
end end
WorldLoaded = function() WorldLoaded = function()
@@ -273,6 +357,7 @@ WorldLoaded = function()
unit.AttackMove(OrdosAttackLocation) unit.AttackMove(OrdosAttackLocation)
IdleHunt(unit) IdleHunt(unit)
end end
SendCarryallReinforcements(OrdosMain, 0, OrdosAttackWaves[Difficulty], OrdosAttackDelay[Difficulty], path, OrdosReinforcements[Difficulty], waveCondition, huntFunction) SendCarryallReinforcements(OrdosMain, 0, OrdosAttackWaves[Difficulty], OrdosAttackDelay[Difficulty], path, OrdosReinforcements[Difficulty], waveCondition, huntFunction)
SendStarportReinforcements() SendStarportReinforcements()

View File

@@ -424,12 +424,14 @@ Actors:
OGunt15: medium_gun_turret OGunt15: medium_gun_turret
Location: 7,37 Location: 7,37
Owner: Ordos Small Base Owner: Ordos Small Base
TurretFacing: 512
Actor111: wall Actor111: wall
Location: 11,37 Location: 11,37
Owner: Ordos Small Base Owner: Ordos Small Base
OGunt16: medium_gun_turret OGunt16: medium_gun_turret
Location: 11,38 Location: 11,38
Owner: Ordos Small Base Owner: Ordos Small Base
TurretFacing: 512
Actor113: wall Actor113: wall
Location: 12,38 Location: 12,38
Owner: Ordos Small Base Owner: Ordos Small Base
@@ -568,18 +570,12 @@ Actors:
Actor158: light_inf Actor158: light_inf
Location: 9,72 Location: 9,72
Owner: Harkonnen Owner: Harkonnen
Actor159: light_inf
Location: 77,72
Owner: Smugglers - Neutral
SSilo3: silo SSilo3: silo
Location: 81,72 Location: 81,72
Owner: Smugglers - Neutral Owner: Smugglers - Neutral
Actor161: trike Actor161: trike
Location: 11,73 Location: 11,73
Owner: Harkonnen Owner: Harkonnen
Actor162: trooper
Location: 80,73
Owner: Smugglers - Neutral
Actor163: trooper Actor163: trooper
Location: 7,74 Location: 7,74
Owner: Harkonnen Owner: Harkonnen
@@ -592,15 +588,9 @@ Actors:
SRefinery: refinery SRefinery: refinery
Location: 78,74 Location: 78,74
Owner: Smugglers - Neutral Owner: Smugglers - Neutral
Actor167: light_inf
Location: 82,74
Owner: Smugglers - Neutral
Actor168: combat_tank_h Actor168: combat_tank_h
Location: 10,75 Location: 10,75
Owner: Harkonnen Owner: Harkonnen
Actor169: trooper
Location: 82,75
Owner: Smugglers - Neutral
Actor170: light_inf Actor170: light_inf
Location: 15,76 Location: 15,76
Owner: Harkonnen Owner: Harkonnen
@@ -625,12 +615,6 @@ Actors:
Actor177: spicebloom.spawnpoint Actor177: spicebloom.spawnpoint
Location: 72,77 Location: 72,77
Owner: Neutral Owner: Neutral
Actor178: light_inf
Location: 82,77
Owner: Smugglers - Neutral
Actor179: light_inf
Location: 83,77
Owner: Smugglers - Neutral
Actor180: light_inf Actor180: light_inf
Location: 11,78 Location: 11,78
Owner: Harkonnen Owner: Harkonnen
@@ -715,6 +699,45 @@ Actors:
HarkonnenEntry2: waypoint HarkonnenEntry2: waypoint
Owner: Neutral Owner: Neutral
Location: 2,68 Location: 2,68
OrdosRally11: waypoint
Owner: Neutral
Location: 51,66
OrdosRally12: waypoint
Owner: Neutral
Location: 79,40
OrdosRally13: waypoint
Owner: Neutral
Location: 19,16
Actor5: crate
Location: 81,67
Faction:
Owner: Smugglers - Neutral
Actor13: crate
Location: 81,69
Faction:
Owner: Smugglers - Neutral
Actor11: crate
Location: 81,71
Faction:
Owner: Smugglers - Neutral
Smuggler1: light_inf
Location: 77,72
Owner: Smugglers - Neutral
Smuggler2: trooper
Location: 80,73
Owner: Smugglers - Neutral
Smuggler3: light_inf
Location: 82,74
Owner: Smugglers - Neutral
Smuggler4: trooper
Location: 82,75
Owner: Smugglers - Neutral
Smuggler5: light_inf
Location: 82,77
Owner: Smugglers - Neutral
Smuggler6: light_inf
Location: 83,77
Owner: Smugglers - Neutral
Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml

View File

@@ -1,6 +1,66 @@
Player: Player:
PlayerResources: PlayerResources:
DefaultCash: 6000 DefaultCash: 6000
ExternalCondition@AISmall:
Condition: base-rebuilder2
ExternalCondition@AISmallDefense:
Condition: defense-rebuilder2
BaseBuilderBotModule@SmallBase:
RequiresCondition: base-rebuilder2
BuildingQueues: Building, Upgrade
MinimumExcessPower: 0
MaximumExcessPower: 250
MaxBaseRadius: 40
ConstructionYardTypes: construction_yard
RefineryTypes: refinery
PowerTypes: wind_trap
ProductionTypes: light_factory, barracks, starport
SiloTypes: silo
DefenseTypes: medium_gun_turret,large_gun_turret
SellRefineryInterval: -1
BuildingLimits:
barracks: 1
refinery: 1
outpost: 1
light_factory: 1
research_centre: 1
high_tech_factory: 1
wind_trap: 4
silo: 1
BuildingFractions:
wind_trap: 1
barracks: 1
refinery: 1
light_factory: 1
research_centre: 1
high_tech_factory: 1
BaseBuilderBotModule@SmallBasewithDefence:
RequiresCondition: defense-rebuilder2
BuildingQueues: Building, Upgrade
MinimumExcessPower: 0
MaximumExcessPower: 250
MaxBaseRadius: 40
ConstructionYardTypes: construction_yard
RefineryTypes: refinery
PowerTypes: wind_trap
ProductionTypes: light_factory, barracks
SiloTypes: silo
DefenseTypes: medium_gun_turret
SellRefineryInterval: -1
PlaceDefenseTowardsEnemyChance: 50
BuildingLimits:
barracks: 1
refinery: 1
light_factory: 1
wind_trap: 4
silo: 1
medium_gun_turret: 4
BuildingFractions:
wind_trap: 1
barracks: 1
refinery: 1
light_factory: 1
medium_gun_turret: 1
World: World:
LuaScript: LuaScript:

View File

@@ -7,6 +7,23 @@
information, see COPYING. information, see COPYING.
]] ]]
EarlyGameStage = DateTime.Minutes(7)
InitialProductionDelay = {
OrdosMain =
{
easy = DateTime.Seconds(180),
normal = DateTime.Seconds(120),
hard = DateTime.Seconds(60)
},
OrdosSmall =
{
easy = DateTime.Seconds(120),
normal = DateTime.Seconds(60),
hard = DateTime.Seconds(0)
}
}
AttackGroupSize = AttackGroupSize =
{ {
easy = 6, easy = 6,
@@ -14,7 +31,7 @@ AttackGroupSize =
hard = 10 hard = 10
} }
AttackDelays = ProductionDelays =
{ {
easy = { DateTime.Seconds(4), DateTime.Seconds(7) }, easy = { DateTime.Seconds(4), DateTime.Seconds(7) },
normal = { DateTime.Seconds(2), DateTime.Seconds(5) }, normal = { DateTime.Seconds(2), DateTime.Seconds(5) },
@@ -22,29 +39,108 @@ AttackDelays =
} }
OrdosInfantryTypes = { "light_inf", "light_inf", "trooper", "trooper", "trooper" } OrdosInfantryTypes = { "light_inf", "light_inf", "trooper", "trooper", "trooper" }
OrdosVehicleTypes = { "raider", "raider", "quad" } OrdosVehicleTypes = { "raider", "raider", "quad" }
OrdosTankTypes = { "combat_tank_o", "combat_tank_o", "siege_tank" } OrdosTankTypes = { "combat_tank_o", "combat_tank_o", "siege_tank" }
OrdosStarportTypes = { "trike.starport", "trike.starport", "quad.starport", "combat_tank_o.starport", "combat_tank_o.starport", "siege_tank.starport", "missile_tank.starport" }
OrdosStarportTypes =
{
EarlyGame = { "trike.starport", "trike.starport", "quad.starport", "combat_tank_o.starport", "combat_tank_o.starport", "siege_tank.starport" },
LateGame = { "trike.starport", "quad.starport", "combat_tank_o.starport", "siege_tank.starport", "missile_tank.starport", "missile_tank.starport" }
}
ActivateAI = function() ActivateAI = function()
Defending[OrdosMain] = {}
Defending[OrdosSmall] = {}
AttackDelay[OrdosMain] = 14000 * DifficultyModifier[Difficulty]
AttackDelay[OrdosSmall] = 12000 * DifficultyModifier[Difficulty]
TimeBetweenAttacks[OrdosMain] = 7000 * DifficultyModifier[Difficulty]
TimeBetweenAttacks[OrdosSmall] = 7000 * DifficultyModifier[Difficulty]
HarvesterCount[OrdosMain] = 4
HarvesterCount[OrdosSmall] = 2
Trigger.OnAllKilledOrCaptured(ProductionBuildingsOrdosSmallBase, function()
TimeBetweenAttacks[OrdosMain] = 0
end)
PatrolPoints[OrdosMain] = {OrdosPatrol3.Location, OrdosPatrol4.Location, OrdosPatrol2.Location }
PatrolPoints[OrdosSmall] = {OrdosPatrol1.Location, OrdosPatrol2.Location, OrdosRally1.Location}
DefencePerimeter[OrdosMain] = GetCellsInRectangle(CPos.New(50,3), CPos.New(94,21))
DefencePerimeter[OrdosSmall] = GetCellsInRectangle(CPos.New(3,3), CPos.New(25,20))
IdlingUnits[OrdosMain] = Utils.Concat(Reinforcements.Reinforce(OrdosMain, InitialOrdosReinforcements[1], InitialOrdosPaths[1]), Reinforcements.Reinforce(OrdosMain, InitialOrdosReinforcements[2], InitialOrdosPaths[2])) IdlingUnits[OrdosMain] = Utils.Concat(Reinforcements.Reinforce(OrdosMain, InitialOrdosReinforcements[1], InitialOrdosPaths[1]), Reinforcements.Reinforce(OrdosMain, InitialOrdosReinforcements[2], InitialOrdosPaths[2]))
IdlingUnits[OrdosSmall] = Reinforcements.Reinforce(OrdosSmall, InitialOrdosReinforcements[1], InitialOrdosPaths[3]) IdlingUnits[OrdosSmall] = Reinforcements.Reinforce(OrdosSmall, InitialOrdosReinforcements[1], InitialOrdosPaths[3])
DefendAndRepairBase(OrdosMain, OrdosMainBase, 0.75, AttackGroupSize[Difficulty]) DefendAndRepairBase(OrdosMain, OrdosMainBase, 0.75, AttackGroupSize[Difficulty])
DefendAndRepairBase(OrdosSmall, OrdosSmallBase, 0.75, AttackGroupSize[Difficulty]) DefendAndRepairBase(OrdosSmall, OrdosSmallBase, 0.75, AttackGroupSize[Difficulty])
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end local delay = function(player)
if EmergencyBuildRate[player] and Difficulty ~= "easy" then
return 1
end
return Utils.RandomInteger(ProductionDelays[Difficulty][1], ProductionDelays[Difficulty][2] + 1)
end
local infantryToBuild = function() return { Utils.Random(OrdosInfantryTypes) } end local infantryToBuild = function() return { Utils.Random(OrdosInfantryTypes) } end
local vehilcesToBuild = function() return { Utils.Random(OrdosVehicleTypes) } end local vehiclesToBuild = function() return { Utils.Random(OrdosVehicleTypes) } end
local tanksToBuild = function() return { Utils.Random(OrdosTankTypes) } end local tanksToBuild = function() return { Utils.Random(OrdosTankTypes) } end
local unitsToBuy = function() return { Utils.Random(OrdosStarportTypes) } end local unitsToBuy = function()
local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5 if EarlyGameStage >= DateTime.GameTime then
return { Utils.Random(OrdosStarportTypes["EarlyGame"]) }
else
return { Utils.Random(OrdosStarportTypes["LateGame"]) }
end
end
ProduceUnits(OrdosMain, OBarracks1, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize) local attackThresholdSize = {}
ProduceUnits(OrdosMain, OLightFactory1, delay, vehilcesToBuild, AttackGroupSize[Difficulty], attackThresholdSize) attackThresholdSize[OrdosMain] = AttackGroupSize[Difficulty] * 3
ProduceUnits(OrdosMain, OHeavyFactory, delay, tanksToBuild, AttackGroupSize[Difficulty], attackThresholdSize) attackThresholdSize[OrdosSmall] = AttackGroupSize[Difficulty] * 2
ProduceUnits(OrdosMain, OStarport, delay, unitsToBuy, AttackGroupSize[Difficulty], attackThresholdSize)
ProduceUnits(OrdosSmall, OBarracks2, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize) Trigger.AfterDelay(InitialProductionDelay["OrdosMain"][Difficulty], function()
ProduceUnits(OrdosSmall, OLightFactory2, delay, vehilcesToBuild, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(OrdosMain, OBarracks1, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize[OrdosMain])
ProduceUnits(OrdosMain, OLightFactory1, delay, vehiclesToBuild, AttackGroupSize[Difficulty], attackThresholdSize[OrdosMain])
ProduceUnits(OrdosMain, OHeavyFactory, delay, tanksToBuild, AttackGroupSize[Difficulty], attackThresholdSize[OrdosMain])
ProduceUnits(OrdosMain, OStarport, delay, unitsToBuy, AttackGroupSize[Difficulty], attackThresholdSize[OrdosMain])
end)
Trigger.AfterDelay(InitialProductionDelay["OrdosSmall"][Difficulty], function()
ProduceUnits(OrdosSmall, OBarracks2, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize[OrdosSmall])
ProduceUnits(OrdosSmall, OLightFactory2, delay, vehiclesToBuild, AttackGroupSize[Difficulty], attackThresholdSize[OrdosSmall])
end)
local crusherTypes = { "combat_tank_o", "combat_tank_o.starport" }
local crusherFactories = { OHeavyFactory, OStarport }
ActivateCrushLogic()
if Difficulty == "easy" then
OrdosMain.GrantCondition("base-rebuilder")
OrdosMain.GrantCondition("base-rebuilder2")
end
if Difficulty == "hard" then
OrdosMain.GrantCondition("defense-rebuilder")
OrdosMain.GrantCondition("base-rebuilder2")
end
local productionTypes =
{
barracks = infantryToBuild,
light_factory = vehiclesToBuild,
heavy_factory = tanksToBuild
}
Trigger.OnBuildingPlaced(OrdosMain, function(p, building)
table.insert(OrdosMainBase, building)
DefendAndRepairBase(OrdosMain, {building}, 0.75, AttackGroupSize[Difficulty] )
if productionTypes[building.Type] == nil then return end
ProduceUnits(OrdosMain, building, delay, productionTypes[building.Type], AttackGroupSize[Difficulty], attackThresholdSize[OrdosMain])
end)
Trigger.OnBuildingPlaced(OrdosSmall, function(p, building)
table.insert(OrdosSmallBase, building)
DefendAndRepairBase(OrdosSmall, {building}, 0.75, AttackGroupSize[Difficulty] )
if productionTypes[building.Type] == nil then return end
ProduceUnits(OrdosSmall, building, delay, productionTypes[building.Type], AttackGroupSize[Difficulty], attackThresholdSize[OrdosSmall])
end)
end end

View File

@@ -8,8 +8,18 @@
]] ]]
OrdosMainBase = { OConYard1, OOutpost, ORefinery1, ORefinery2, OHeavyFactory, OLightFactory1, OHiTechFactory, ORepair, OStarport, OGunt1, OGunt2, OGunt3, OGunt4, OGunt5, OGunt6, ORocket1, ORocket2, OBarracks1, OPower1, OPower2, OPower3, OPower4, OPower5, OPower6, OPower7, OPower8, OPower9, OPower10, OSilo1, OSilo2, OSilo3, OSilo4, OSilo5, OSilo6 } OrdosMainBase = { OConYard1, OOutpost, ORefinery1, ORefinery2, OHeavyFactory, OLightFactory1, OHiTechFactory, ORepair, OStarport, OGunt1, OGunt2, OGunt3, OGunt4, OGunt5, OGunt6, ORocket1, ORocket2, OBarracks1, OPower1, OPower2, OPower3, OPower4, OPower5, OPower6, OPower7, OPower8, OPower9, OPower10, OSilo1, OSilo2, OSilo3, OSilo4, OSilo5, OSilo6 }
OrdosSmallBase = { OConYard2, ORefinery3, OBarracks2, OLightFactory2, OGunt6, OGunt7, ORocket3, ORocket4, OPower11, OPower12, OPower13, OPower14, OSilo7, OSilo8, OSilo9 } OrdosSmallBase = { OConYard2, ORefinery3, OBarracks2, OLightFactory2, OGunt6, OGunt7, ORocket3, ORocket4, OPower11, OPower12, OPower13, OPower14, OSilo7, OSilo8, OSilo9 }
ProductionBuildingsOrdosSmallBase = { OConyard2, ORefinery3, OBarracks2, OLightFactory2 }
SmugglerTriggerZone = Utils.Concat(
GetCellsInRectangle(CPos.New(48,24), CPos.New(53,29)),
GetCellsInRectangle(CPos.New(43,30), CPos.New(53,35))
)
SmugglerPatrol = {Smuggler1, Smuggler2, Smuggler3, Smuggler4, Smuggler5, Smuggler6 }
OrdosReinforcements = OrdosReinforcements =
{ {
easy = easy =
@@ -118,6 +128,53 @@ SendStarportReinforcements = function()
end) end)
end end
Message = {}
StopFollowing = {}
Trigger.OnEnteredFootprint(SmugglerTriggerZone, function(a, id)
if SmugglerNeutral.HasNoRequiredUnits() then
Trigger.RemoveFootprintTrigger(id)
end
if a.Owner == Harkonnen and not Message[Harkonnen] then
Media.DisplayMessage(UserInterface.GetFluentMessage("smuggler-warning-harkonnen"), "Smugglers", HSLColor.FromHex("7B2910"))
Message[Harkonnen] = true
end
if a.Owner == OrdosMain or a.Owner == OrdosSmall and not Message[OrdosMain] then
Media.DisplayMessage(UserInterface.GetFluentMessage("smuggler-warning-ordos"), "Smugglers", HSLColor.FromHex("7B2910"))
Message[OrdosMain] = true
end
if a.Owner ~= SmugglerNeutral then
Utils.Do(SmugglerPatrol, function(u)
if not u.IsDead then
StopFollowing[u] = false
FollowIntruder(u,a)
end
end)
end
end)
Trigger.OnExitedFootprint(SmugglerTriggerZone, function(a, id)
if SmugglerNeutral.HasNoRequiredUnits() then
Trigger.RemoveFootprintTrigger(id)
end
if a.Owner ~= SmugglerNeutral then
Utils.Do(SmugglerPatrol, function(u)
if not u.IsDead then StopFollowing[u] = true end
end)
end
end)
FollowIntruder = function(unit, intruder)
if intruder.IsDead or unit.IsDead then return end
if StopFollowing[unit] == true then unit.Stop() return end
unit.Stop()
unit.AttackMove(intruder.Location,1)
Trigger.AfterDelay(100, function() FollowIntruder(unit, intruder) end)
end
ChangeOwner = function(old_owner, new_owner) ChangeOwner = function(old_owner, new_owner)
local units = old_owner.GetActors() local units = old_owner.GetActors()
Utils.Do(units, function(unit) Utils.Do(units, function(unit)
@@ -130,20 +187,47 @@ end
CheckSmugglerEnemies = function() CheckSmugglerEnemies = function()
Utils.Do(SmugglerUnits, function(unit) Utils.Do(SmugglerUnits, function(unit)
Trigger.OnDamaged(unit, function(self, attacker) Trigger.OnDamaged(unit, function(self, attacker)
if Utils.Any(IgnoreDamageFromTypes, function(a) return a == attacker.Type end) then
return
end
if not self.HasProperty("Health") then return end
if self.MaxHealth * 0.9 < self.Health then return end
if unit.Owner == SmugglerNeutral and attacker.Owner == Harkonnen then if unit.Owner == SmugglerNeutral and attacker.Owner == Harkonnen then
ChangeOwner(SmugglerNeutral, SmugglerHarkonnen) ChangeOwner(SmugglerNeutral, SmugglerHarkonnen)
-- Ensure that harvesters that was on a carryall switched sides.
Trigger.AfterDelay(DateTime.Seconds(15), function()
ChangeOwner(SmugglerNeutral, SmugglerHarkonnen)
end)
end end
if unit.Owner == SmugglerOrdos and attacker.Owner == Harkonnen then if unit.Owner == SmugglerOrdos and attacker.Owner == Harkonnen then
ChangeOwner(SmugglerOrdos, SmugglerBoth) ChangeOwner(SmugglerOrdos, SmugglerBoth)
-- Ensure that harvesters that was on a carryall switched sides.
Trigger.AfterDelay(DateTime.Seconds(15), function()
ChangeOwner(SmugglerOrdos, SmugglerBoth)
end)
end end
if unit.Owner == SmugglerNeutral and (attacker.Owner == OrdosMain or attacker.Owner == OrdosSmall) then if unit.Owner == SmugglerNeutral and (attacker.Owner == OrdosMain or attacker.Owner == OrdosSmall) then
ChangeOwner(SmugglerNeutral, SmugglerOrdos) ChangeOwner(SmugglerNeutral, SmugglerOrdos)
-- Ensure that harvesters that was on a carryall switched sides.
Trigger.AfterDelay(DateTime.Seconds(15), function()
ChangeOwner(SmugglerNeutral, SmugglerOrdos)
end)
end end
if unit.Owner == SmugglerHarkonnen and (attacker.Owner == OrdosMain or attacker.Owner == OrdosSmall) then if unit.Owner == SmugglerHarkonnen and (attacker.Owner == OrdosMain or attacker.Owner == OrdosSmall) then
ChangeOwner(SmugglerHarkonnen, SmugglerBoth) ChangeOwner(SmugglerHarkonnen, SmugglerBoth)
-- Ensure that harvesters that was on a carryall switched sides.
Trigger.AfterDelay(DateTime.Seconds(15), function()
ChangeOwner(SmugglerHarkonnen, SmugglerBoth)
end)
end end
if attacker.Owner == Harkonnen and not MessageCheck then if attacker.Owner == Harkonnen and not MessageCheck then
@@ -155,6 +239,13 @@ CheckSmugglerEnemies = function()
end) end)
end end
EmergencyBehaviour = function(player, target)
if player ~= OrdosSmall then return end
if #IdlingUnits[OrdosMain] > 10 and Utils.Any(OrdosSmallBase, function(a) return not a.IsDead end) then
CheckArea(OrdosMain, target, 10)
end
end
Tick = function() Tick = function()
if Harkonnen.HasNoRequiredUnits() then if Harkonnen.HasNoRequiredUnits() then
OrdosMain.MarkCompletedObjective(KillHarkonnen1) OrdosMain.MarkCompletedObjective(KillHarkonnen1)
@@ -231,8 +322,8 @@ WorldLoaded = function()
unit.AttackMove(OrdosAttackLocation) unit.AttackMove(OrdosAttackLocation)
IdleHunt(unit) IdleHunt(unit)
end end
SendCarryallReinforcements(OrdosMain, 0, OrdosAttackWaves[Difficulty], OrdosAttackDelay[Difficulty], path, OrdosReinforcements[Difficulty], waveCondition, huntFunction)
SendCarryallReinforcements(OrdosMain, 0, OrdosAttackWaves[Difficulty], OrdosAttackDelay[Difficulty], path, OrdosReinforcements[Difficulty], waveCondition, huntFunction)
SendStarportReinforcements() SendStarportReinforcements()
Actor.Create("upgrade.barracks", true, { Owner = OrdosMain }) Actor.Create("upgrade.barracks", true, { Owner = OrdosMain })

Binary file not shown.

View File

@@ -394,9 +394,11 @@ Actors:
OGunt6: medium_gun_turret OGunt6: medium_gun_turret
Location: 9,17 Location: 9,17
Owner: Ordos Small Base Owner: Ordos Small Base
TurretFacing: 512
OGunt7: medium_gun_turret OGunt7: medium_gun_turret
Location: 14,17 Location: 14,17
Owner: Ordos Small Base Owner: Ordos Small Base
TurretFacing: 512
Actor102: wall Actor102: wall
Location: 15,17 Location: 15,17
Owner: Ordos Small Base Owner: Ordos Small Base
@@ -463,12 +465,6 @@ Actors:
SSilo3: silo SSilo3: silo
Location: 51,26 Location: 51,26
Owner: Smugglers - Neutral Owner: Smugglers - Neutral
Actor124: trooper
Location: 51,28
Owner: Smugglers - Neutral
Actor125: light_inf
Location: 53,28
Owner: Smugglers - Neutral
Actor126: wormspawner Actor126: wormspawner
Location: 76,28 Location: 76,28
Owner: Creeps Owner: Creeps
@@ -487,24 +483,12 @@ Actors:
SPower2: wind_trap SPower2: wind_trap
Location: 50,30 Location: 50,30
Owner: Smugglers - Neutral Owner: Smugglers - Neutral
Actor132: light_inf
Location: 53,30
Owner: Smugglers - Neutral
SRefinery: refinery SRefinery: refinery
Location: 43,33 Location: 43,33
Owner: Smugglers - Neutral Owner: Smugglers - Neutral
Actor134: light_inf
Location: 50,33
Owner: Smugglers - Neutral
Actor135: harvester Actor135: harvester
Location: 46,35 Location: 46,35
Owner: Smugglers - Neutral Owner: Smugglers - Neutral
Actor136: light_inf
Location: 48,35
Owner: Smugglers - Neutral
Actor137: light_inf
Location: 52,35
Owner: Smugglers - Neutral
Actor138: light_inf Actor138: light_inf
Location: 42,36 Location: 42,36
Owner: Smugglers - Neutral Owner: Smugglers - Neutral
@@ -652,6 +636,42 @@ Actors:
OrdosStarportExit: waypoint OrdosStarportExit: waypoint
Owner: Neutral Owner: Neutral
Location: 2,9 Location: 2,9
Smuggler1: trooper
Location: 51,28
Owner: Smugglers - Neutral
Smuggler2: light_inf
Location: 53,28
Owner: Smugglers - Neutral
Smuggler3: light_inf
Location: 53,30
Owner: Smugglers - Neutral
Smuggler4: light_inf
Location: 50,33
Owner: Smugglers - Neutral
Smuggler5: light_inf
Location: 48,35
Owner: Smugglers - Neutral
Smuggler6: light_inf
Location: 52,35
Owner: Smugglers - Neutral
OrdosPatrol1: waypoint
Owner: Neutral
Location: 26,49
OrdosPatrol2: waypoint
Owner: Neutral
Location: 36,33
OrdosPatrol3: waypoint
Owner: Neutral
Location: 60,29
OrdosPatrol4: waypoint
Owner: Neutral
Location: 82,43
Actor4: crate_reveal
Owner: Neutral
Location: 13,27
Actor5: crate
Owner: Neutral
Location: 82,48
Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml

View File

@@ -1,6 +1,136 @@
Player: Player:
PlayerResources: PlayerResources:
DefaultCash: 5000 DefaultCash: 5000
ExternalCondition@AIMain:
Condition: base-rebuilder
ExternalCondition@AISmall:
Condition: base-rebuilder2
ExternalCondition@AIMainWithDefense:
Condition: defense-rebuilder
ExternalCondition@AISmallWithDefense:
Condition: defense-rebuilder2
BaseBuilderBotModule@MainBase:
RequiresCondition: base-rebuilder
BuildingQueues: Building, Upgrade
MinimumExcessPower: 0
MaximumExcessPower: 250
MaxBaseRadius: 40
ConstructionYardTypes: construction_yard
RefineryTypes: refinery
PowerTypes: wind_trap
ProductionTypes: light_factory, heavy_factory, barracks
SiloTypes: silo
DefenseTypes: medium_gun_turret,large_gun_turret
SellRefineryInterval: -1
BuildingLimits:
barracks: 1
refinery: 1
outpost: 1
light_factory: 1
heavy_factory: 1
high_tech_factory: 1
wind_trap: 9
silo: 1
BuildingFractions:
wind_trap: 1
barracks: 1
refinery: 1
outpost: 1
light_factory: 1
heavy_factory: 1
high_tech_factory: 1
BaseBuilderBotModule@MainBaseWithDefence:
RequiresCondition: defense-rebuilder
BuildingQueues: Building, Upgrade
MinimumExcessPower: 0
MaximumExcessPower: 250
MaxBaseRadius: 40
ConstructionYardTypes: construction_yard
RefineryTypes: refinery
PowerTypes: wind_trap
ProductionTypes: light_factory, heavy_factory, barracks
SiloTypes: silo
DefenseTypes: medium_gun_turret,large_gun_turret
PlaceDefenseTowardsEnemyChance: 50
SellRefineryInterval: -1
BuildingLimits:
barracks: 1
refinery: 1
outpost: 1
light_factory: 1
heavy_factory: 1
high_tech_factory: 1
wind_trap: 7
silo: 1
medium_gun_turret: 5
large_gun_turret: 2
BuildingFractions:
wind_trap: 1
barracks: 1
refinery: 1
outpost: 1
light_factory: 1
heavy_factory: 1
high_tech_factory: 1
medium_gun_turret: 1
large_gun_turret: 1
BaseBuilderBotModule@SmallBase:
RequiresCondition: base-rebuilder2
BuildingQueues: Building, Upgrade
MinimumExcessPower: 0
MaximumExcessPower: 250
MaxBaseRadius: 40
ConstructionYardTypes: construction_yard
RefineryTypes: refinery
PowerTypes: wind_trap
ProductionTypes: light_factory, barracks
SiloTypes: silo
DefenseTypes: medium_gun_turret,large_gun_turret
SellRefineryInterval: -1
BuildingLimits:
barracks: 1
refinery: 1
outpost: 1
light_factory: 1
wind_trap: 4
silo: 1
BuildingFractions:
wind_trap: 1
barracks: 1
refinery: 1
outpost: 1
light_factory: 1
BaseBuilderBotModule@SmallBasewithDefence:
RequiresCondition: defense-rebuilder2
BuildingQueues: Building, Upgrade
MinimumExcessPower: 0
MaximumExcessPower: 250
MaxBaseRadius: 40
ConstructionYardTypes: construction_yard
RefineryTypes: refinery
PowerTypes: wind_trap
ProductionTypes: light_factory, barracks
SiloTypes: silo
DefenseTypes: medium_gun_turret
SellRefineryInterval: -1
PlaceDefenseTowardsEnemyChance: 50
BuildingLimits:
barracks: 1
refinery: 1
outpost: 1
light_factory: 1
wind_trap: 4
silo: 1
medium_gun_turret: 2
large_gun_turret: 2
BuildingFractions:
wind_trap: 1
barracks: 1
refinery: 1
outpost: 1
light_factory: 1
medium_gun_turret: 1
large_gun_turret: 2
World: World:
LuaScript: LuaScript:

View File

@@ -6,6 +6,30 @@
the License, or (at your option) any later version. For more the License, or (at your option) any later version. For more
information, see COPYING. information, see COPYING.
]] ]]
EarlyGameStage = DateTime.Minutes(10)
InitialProductionDelay = {
AtreidesMain =
{
easy = DateTime.Seconds(400),
normal = DateTime.Seconds(300),
hard = DateTime.Seconds(150)
},
AtreidesSmall =
{
easy = DateTime.Seconds(300),
normal = DateTime.Seconds(200),
hard = DateTime.Seconds(100)
},
Corrino =
{
easy = DateTime.Seconds(100),
normal = DateTime.Seconds(120),
hard = DateTime.Seconds(60)
}
}
AttackGroupSize = AttackGroupSize =
{ {
@@ -14,29 +38,60 @@ AttackGroupSize =
hard = 10 hard = 10
} }
AttackDelays = EarlyProductionDelays =
{ {
easy = { DateTime.Seconds(4), DateTime.Seconds(7) }, easy = { DateTime.Seconds(11), DateTime.Seconds(15) },
normal = { DateTime.Seconds(2), DateTime.Seconds(5) }, normal = { DateTime.Seconds(10), DateTime.Seconds(12) },
hard = { DateTime.Seconds(1), DateTime.Seconds(3) } hard = { DateTime.Seconds(8), DateTime.Seconds(10) }
} }
InitialProductionDelay = LateProductionDelays =
{ {
easy = DateTime.Seconds(30), easy = { DateTime.Seconds(6), DateTime.Seconds(10) },
normal = DateTime.Seconds(15), normal = { DateTime.Seconds(4), DateTime.Seconds(6) },
hard = 0 hard = { DateTime.Seconds(2), DateTime.Seconds(4) }
} }
AtreidesInfantryTypes = { "light_inf", "light_inf", "light_inf", "trooper", "trooper" } AtreidesInfantryTypes = { "light_inf", "light_inf", "light_inf", "trooper", "trooper" }
AtreidesVehicleTypes = { "trike", "trike", "quad" } AtreidesVehicleTypes = { "trike", "trike", "quad" }
AtreidesMainTankTypes = { "combat_tank_a", "combat_tank_a", "siege_tank", "missile_tank", "sonic_tank" }
AtreidesMainTankTypes =
{
EarlyGame = { "combat_tank_a", "combat_tank_a" },
LateGame = { "combat_tank_a", "siege_tank", "missile_tank", "sonic_tank" }
}
AtreidesSmallTankTypes = { "combat_tank_a", "combat_tank_a", "siege_tank" } AtreidesSmallTankTypes = { "combat_tank_a", "combat_tank_a", "siege_tank" }
AtreidesStarportTypes = { "trike.starport", "trike.starport", "quad.starport", "combat_tank_a.starport", "combat_tank_a.starport", "siege_tank.starport", "missile_tank.starport" } AtreidesStarportTypes = { "trike.starport", "trike.starport", "quad.starport", "combat_tank_a.starport", "combat_tank_a.starport", "siege_tank.starport", "missile_tank.starport" }
CorrinoInfantryTypes = { "light_inf", "trooper", "sardaukar" } CorrinoInfantryTypes = { "light_inf", "trooper", "sardaukar" }
ActivateAI = function() ActivateAI = function()
Defending[AtreidesMain] = {}
Defending[AtreidesSmall] = {}
Defending[Corrino] = {}
-- this is also first attack timing
AttackDelay[AtreidesMain] = 10000
AttackDelay[AtreidesSmall] = 8000
AttackDelay[Corrino] = 7000
TimeBetweenAttacks[AtreidesMain] = 12000
TimeBetweenAttacks[AtreidesSmall] = 5000
TimeBetweenAttacks[Corrino] = 11000
HarvesterCount[AtreidesMain] = 2
HarvesterCount[AtreidesSmall] = 2
Trigger.OnAllKilledOrCaptured(AtreidesSmallBase, function()
TimeBetweenAttacks[AtreidesMain] = 0
end)
PatrolPoints[AtreidesMain] = {AtreidesPoint1.Location, AtreidesPoint2.Location, AtreidesPoint3.Location }
PatrolPoints[AtreidesSmall] = {AtreidesPoint4.Location, AtreidesPoint5.Location, AtreidesPoint6.Location }
DefencePerimeter[AtreidesMain] = Utils.Concat( GetCellsInRectangle(CPos.New(73,9), CPos.New(88,26)), GetCellsInRectangle(CPos.New(65,44), CPos.New(82,56)))
DefencePerimeter[AtreidesSmall] = GetCellsInRectangle(CPos.New(5,18), CPos.New(16,32))
DefencePerimeter[Corrino] = GetCellsInRectangle(CPos.New(89,27), CPos.New(95,35))
IdlingUnits[AtreidesMain] = Utils.Concat(Reinforcements.Reinforce(AtreidesMain, InitialAtreidesReinforcements[Difficulty][1], InitialAtreidesPaths[1]), Reinforcements.Reinforce(AtreidesMain, InitialAtreidesReinforcements[Difficulty][2], InitialAtreidesPaths[2])) IdlingUnits[AtreidesMain] = Utils.Concat(Reinforcements.Reinforce(AtreidesMain, InitialAtreidesReinforcements[Difficulty][1], InitialAtreidesPaths[1]), Reinforcements.Reinforce(AtreidesMain, InitialAtreidesReinforcements[Difficulty][2], InitialAtreidesPaths[2]))
IdlingUnits[AtreidesSmall] = Reinforcements.Reinforce(AtreidesSmall, InitialAtreidesReinforcements[Difficulty][1], InitialAtreidesPaths[3]) IdlingUnits[AtreidesSmall] = Reinforcements.Reinforce(AtreidesSmall, InitialAtreidesReinforcements[Difficulty][1], InitialAtreidesPaths[3])
IdlingUnits[Corrino] = Reinforcements.Reinforce(Corrino, InitialCorrinoReinforcements, InitialCorrinoPath) IdlingUnits[Corrino] = Reinforcements.Reinforce(Corrino, InitialCorrinoReinforcements, InitialCorrinoPath)
@@ -45,23 +100,77 @@ ActivateAI = function()
DefendAndRepairBase(AtreidesSmall, AtreidesSmallBase, 0.75, AttackGroupSize[Difficulty]) DefendAndRepairBase(AtreidesSmall, AtreidesSmallBase, 0.75, AttackGroupSize[Difficulty])
DefendAndRepairBase(Corrino, CorrinoBase, 0.75, AttackGroupSize[Difficulty]) DefendAndRepairBase(Corrino, CorrinoBase, 0.75, AttackGroupSize[Difficulty])
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end local delay = function(player)
if EmergencyBuildRate[player] and Difficulty ~= "easy" then
return 1
end
if EarlyGameStage >= DateTime.GameTime then
return Utils.RandomInteger(EarlyProductionDelays[Difficulty][1], EarlyProductionDelays[Difficulty][2] + 1)
else
return Utils.RandomInteger(LateProductionDelays[Difficulty][1], LateProductionDelays[Difficulty][2] + 1)
end
end
local infantryToBuildAtreides = function() return { Utils.Random(AtreidesInfantryTypes) } end local infantryToBuildAtreides = function() return { Utils.Random(AtreidesInfantryTypes) } end
local infantryToBuildCorrino = function() return { Utils.Random(CorrinoInfantryTypes) } end local infantryToBuildCorrino = function() return { Utils.Random(CorrinoInfantryTypes) } end
local vehilcesToBuild = function() return { Utils.Random(AtreidesVehicleTypes) } end local vehiclesToBuild = function() return { Utils.Random(AtreidesVehicleTypes) } end
local tanksToBuildMain = function() return { Utils.Random(AtreidesMainTankTypes) } end local tanksToBuildMain = function()
if EarlyGameStage >= DateTime.GameTime then
return { Utils.Random(AtreidesMainTankTypes["EarlyGame"]) }
else
return { Utils.Random(AtreidesMainTankTypes["LateGame"]) }
end
end
local tanksToBuildSmall = function() return { Utils.Random(AtreidesSmallTankTypes) } end local tanksToBuildSmall = function() return { Utils.Random(AtreidesSmallTankTypes) } end
local unitsToBuy = function() return { Utils.Random(AtreidesStarportTypes) } end local unitsToBuy = function() return { Utils.Random(AtreidesStarportTypes) } end
local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5 local attackThresholdSize = {}
attackThresholdSize[AtreidesMain] = AttackGroupSize[Difficulty] * 3
attackThresholdSize[AtreidesSmall] = AttackGroupSize[Difficulty] * 2
Trigger.AfterDelay(InitialProductionDelay[Difficulty], function() Trigger.AfterDelay(InitialProductionDelay["AtreidesMain"][Difficulty], function()
ProduceUnits(AtreidesMain, ALightFactory1, delay, vehilcesToBuild, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(AtreidesMain, ALightFactory1, delay, vehiclesToBuild, AttackGroupSize[Difficulty], attackThresholdSize[AtreidesMain])
ProduceUnits(AtreidesMain, AHeavyFactory1, delay, tanksToBuildMain, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(AtreidesMain, AHeavyFactory1, delay, tanksToBuildMain, AttackGroupSize[Difficulty], attackThresholdSize[AtreidesMain])
ProduceUnits(AtreidesMain, AStarport, delay, unitsToBuy, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(AtreidesMain, AStarport, delay, unitsToBuy, AttackGroupSize[Difficulty], attackThresholdSize[AtreidesMain])
ProduceUnits(AtreidesSmall, ABarracks, delay, infantryToBuildAtreides, AttackGroupSize[Difficulty], attackThresholdSize)
ProduceUnits(AtreidesSmall, AHeavyFactory2, delay, tanksToBuildSmall, AttackGroupSize[Difficulty], attackThresholdSize)
ProduceUnits(Corrino, CBarracks, delay, infantryToBuildCorrino, AttackGroupSize[Difficulty], attackThresholdSize)
end) end)
Trigger.AfterDelay(InitialProductionDelay["AtreidesSmall"][Difficulty], function()
ProduceUnits(AtreidesSmall, ABarracks, delay, infantryToBuildAtreides, AttackGroupSize[Difficulty], attackThresholdSize[AtreidesSmall])
ProduceUnits(AtreidesSmall, AHeavyFactory2, delay, tanksToBuildSmall, AttackGroupSize[Difficulty], attackThresholdSize[AtreidesSmall])
end)
Trigger.AfterDelay(InitialProductionDelay["Corrino"][Difficulty], function()
ProduceUnits(Corrino, CBarracks, delay, infantryToBuildCorrino, AttackGroupSize[Difficulty], attackThresholdSize[AtreidesSmall])
end)
if Difficulty == "normal" then
AtreidesMain.GrantCondition("base-rebuilder")
end
if Difficulty == "hard" then
AtreidesMain.GrantCondition("defense-rebuilder")
end
local productionTypes =
{
barracks = infantryToBuildAtreides,
light_factory = vehiclesToBuild,
heavy_factory = tanksToBuildMain
}
Trigger.OnBuildingPlaced(AtreidesMain, function(p, building)
table.insert(AtreidesMainBase, building)
DefendAndRepairBase(AtreidesMain, {building}, 0.5, AttackGroupSize[Difficulty] )
if productionTypes[building.Type] == nil then return end
ProduceUnits(AtreidesMain, building, delay, productionTypes[building.Type], AttackGroupSize[Difficulty], attackThresholdSize[AtreidesMain])
end)
Trigger.OnBuildingPlaced(AtreidesSmall, function(p, building)
table.insert(AtreidesSmallBase, building)
DefendAndRepairBase(AtreidesSmall, {building}, 0.75, AttackGroupSize[Difficulty] )
if productionTypes[building.Type] == nil then return end
ProduceUnits(AtreidesSmall, building, delay, productionTypes[building.Type], AttackGroupSize[Difficulty], attackThresholdSize[AtreidesSmall])
end)
ActivateCrushLogic()
end end

View File

@@ -8,9 +8,13 @@
]] ]]
AtreidesMainBase = { AConYard1, AOutpost1, ARefinery1, ARefinery2, AHeavyFactory1, ALightFactory1, ALightFactory2, AHiTechFactory, AResearch, ARepair, AStarport, AGunt1, AGunt2, AGunt3, AGunt4, AGunt5, AGunt6, ARock1, ARock2, ARock3, ARock4, ARock5, ARock6, APower1, APower2, APower3, APower4, APower5, APower6, APower7, APower8, APower9, APower10, APower11, APower12, APower13, APower14, APower15, APower16, APower17, APower18, APower19, APower20, APower21, APower22, ASilo1, ASilo2, ASilo3 } AtreidesMainBase = { AConYard1, AOutpost1, ARefinery1, ARefinery2, AHeavyFactory1, ALightFactory1, ALightFactory2, AHiTechFactory, AResearch, ARepair, AStarport, AGunt1, AGunt2, AGunt3, AGunt4, AGunt5, AGunt6, ARock1, ARock2, ARock3, ARock4, ARock5, ARock6, APower1, APower2, APower3, APower4, APower5, APower6, APower7, APower8, APower9, APower10, APower11, APower12, APower13, APower14, APower15, APower16, APower17, APower18, APower19, APower20, APower21, APower22, ASilo1, ASilo2, ASilo3 }
AtreidesSmallBase = { AOutpost2, ARefinery3, ABarracks, AHeavyFactory2, AGunt7, AGunt8, APower23, APower24, APower25, APower26, ASilo4, ASilo5, ASilo6, ASilo7 } AtreidesSmallBase = { AOutpost2, ARefinery3, ABarracks, AHeavyFactory2, AGunt7, AGunt8, APower23, APower24, APower25, APower26, ASilo4, ASilo5, ASilo6, ASilo7 }
CorrinoBase = { CBarracks, COutpost, CPower1, CPower2, CPower3, CRock1, CRock2 } CorrinoBase = { CBarracks, COutpost, CPower1, CPower2, CPower3, CRock1, CRock2 }
EarlyGameStage = DateTime.Minutes(7)
AtreidesReinforcements = AtreidesReinforcements =
{ {
easy = { "sonic_tank" }, easy = { "sonic_tank" },
@@ -41,16 +45,16 @@ CorrinoReinforcements =
EnemyAttackDelay = EnemyAttackDelay =
{ {
easy = DateTime.Minutes(3) + DateTime.Seconds(30), easy = 7000 ,
normal = DateTime.Minutes(2) + DateTime.Seconds(30), normal = 6500 ,
hard = DateTime.Minutes(1) + DateTime.Seconds(30) hard = 6000
} }
CorrinoInitialAttackDelay = CorrinoInitialAttackDelay =
{ {
easy = DateTime.Seconds(45), easy = DateTime.Minutes(4) ,
normal = DateTime.Seconds(30), normal = DateTime.Minutes(3) ,
hard = DateTime.Seconds(15) hard = DateTime.Minutes(2)
} }
InitialAtreidesReinforcements = InitialAtreidesReinforcements =
@@ -112,8 +116,8 @@ HarkonnenReinforcements =
hard = hard =
{ {
{ "trooper", "trooper", "light_inf", "light_inf", "light_inf" }, { "trooper", "trooper", "light_inf", "light_inf", "light_inf", "light_inf" },
{ "quad", "trike", "trike", "combat_tank_h", "combat_tank_h" } { "quad", "trike", "trike", "combat_tank_h", "combat_tank_h", "siege_tank" }
}, },
} }
@@ -147,8 +151,32 @@ SendEnemyReinforcements = function(player, delay, path, unitTypes, customConditi
end) end)
end end
SendAirStrike = function() AirStrikeTimer = 7500
if HiTechIsDead then AirStrikeChargeTime = 7500
AirstrikeLogic = function(airstrikeProvider)
if airstrikeProvider.IsDead then
return
end
if DateTime.GameTime <= AirStrikeTimer then
Trigger.AfterDelay(AirStrikeTimer - DateTime.GameTime + 1, function()
AirstrikeLogic(airstrikeProvider)
end)
return
end
-- randomly choose if wait again or strike. During waiting Airstrike can still be used by DefensiveAirStrike
if Utils.RandomInteger(1, 100) < 30 then
Trigger.AfterDelay(1000, function() AirstrikeLogic(airstrikeProvider)end)
else
AirStrikeVSBuilding(airstrikeProvider)
Trigger.AfterDelay(7500, function() AirstrikeLogic(airstrikeProvider) end)
IsAirstrikeReady = false
end
end
AirStrikeVSBuilding = function(airstrikeProvider)
if airstrikeProvider.IsDead or DateTime.GameTime < AirStrikeTimer then
return return
end end
@@ -163,10 +191,32 @@ SendAirStrike = function()
end) end)
if #targets > 0 then if #targets > 0 then
AHiTechFactory.TargetAirstrike(Utils.Random(targets).CenterPosition) airstrikeProvider.TargetAirstrike(Utils.Random(targets).CenterPosition)
AirStrikeTimer = DateTime.GameTime + AirStrikeChargeTime
end end
end
Trigger.AfterDelay(DateTime.Minutes(5), SendAirStrike) DefensiveAirStrike = function(airstrikeProvider, possibleTargets)
if airstrikeProvider.IsDead or DateTime.GameTime <= AirStrikeTimer then return end
local bestValue = {}
local bestIndex = 1
for i = 1, #possibleTargets, 1 do
local ActorsInCircle = Map.ActorsInCircle(possibleTargets[i].CenterPosition, WDist.FromCells(4), function(a)
return
a.Owner == Harkonnen
and not a.IsDead
and a.HasProperty("Attack")
end)
bestValue[i] = 0
Utils.Do(ActorsInCircle, function(a)
bestValue[i] = bestValue[i] + Actor.Cost(a.Type)
end)
if bestValue[i] > bestValue[bestIndex] then
bestIndex = i
end
end
airstrikeProvider.TargetAirstrike(possibleTargets[bestIndex].CenterPosition)
AirStrikeTimer = DateTime.GameTime + AirStrikeChargeTime
end end
Tick = function() Tick = function()
@@ -195,12 +245,12 @@ Tick = function()
HiTechIsDead = true HiTechIsDead = true
end end
if DateTime.GameTime % DateTime.Seconds(10) == 0 and LastHarvesterEaten[OrdosMain] then if DateTime.GameTime % DateTime.Seconds(10) == 0 and LastHarvesterEaten[AtreidesMain] then
local units = OrdosMain.GetActorsByType("harvester") local units = AtreidesMain.GetActorsByType("harvester")
if #units > 0 then if #units > 0 then
LastHarvesterEaten[OrdosMain] = false LastHarvesterEaten[AtreidesMain] = false
ProtectHarvester(units[1], OrdosMain, AttackGroupSize[Difficulty]) ProtectHarvester(units[1], AtreidesMain, AttackGroupSize[Difficulty])
end end
end end
@@ -212,15 +262,40 @@ Tick = function()
ProtectHarvester(units[1], OrdosSmall, AttackGroupSize[Difficulty]) ProtectHarvester(units[1], OrdosSmall, AttackGroupSize[Difficulty])
end end
end end
if IdlingUnits[AtreidesMain] == nil then return end
end
EmergencyBehaviour = function(player, target)
if HiTechIsDead or not IsAirstrikeReady or player == Corrino then return end
local targets = {}
if player == AtreidesMain then
targets = Map.ActorsInBox(Map.CenterOfCell(CPos.New(73,9)), Map.CenterOfCell(CPos.New(88,26)))
else
targets = Map.ActorsInBox(Map.CenterOfCell(CPos.New(5,18)), Map.CenterOfCell(CPos.New(16,32)))
end
targets = Utils.Where(targets, function(a)
return a.Owner == Harkonnen
and not a.IsDead
and a.HasProperty("Attack")
end)
if targets[1] == nil then return end
DefensiveAirStrike(AHiTechFactory, targets)
end end
WorldLoaded = function() WorldLoaded = function()
AtreidesMain = Player.GetPlayer("Atreides Main Base") AtreidesMain = Player.GetPlayer("Atreides Main Base")
AtreidesSmall = Player.GetPlayer("Atreides Small Base") AtreidesSmall = Player.GetPlayer("Atreides Small Base")
Corrino = Player.GetPlayer("Corrino") Corrino = Player.GetPlayer("Corrino")
AtreidesMain.Cash = 5000
AtreidesSmall.Cash = 5000
Corrino.Cash = 5000
Harkonnen = Player.GetPlayer("Harkonnen") Harkonnen = Player.GetPlayer("Harkonnen")
InitObjectives(Harkonnen) InitObjectives(Harkonnen)
CaptureAtreidesConYard = AddPrimaryObjective(Harkonnen, "capture-atreides-construction-yard-south") CaptureAtreidesConYard = AddPrimaryObjective(Harkonnen, "capture-atreides-construction-yard-south")
KillAtreides = AddPrimaryObjective(Harkonnen, "destroy-atreides") KillAtreides = AddPrimaryObjective(Harkonnen, "destroy-atreides")
KillCorrino = AddPrimaryObjective(Harkonnen, "destroy-corrino") KillCorrino = AddPrimaryObjective(Harkonnen, "destroy-corrino")
@@ -232,8 +307,7 @@ WorldLoaded = function()
Camera.Position = HEngineer.CenterPosition Camera.Position = HEngineer.CenterPosition
AtreidesAttackLocation = AConYard2.Location AtreidesAttackLocation = AConYard2.Location
Trigger.AfterDelay(EarlyGameStage,function() AirstrikeLogic(AHiTechFactory) end)
Trigger.AfterDelay(DateTime.Minutes(5), SendAirStrike)
Trigger.OnCapture(AConYard2, function() Trigger.OnCapture(AConYard2, function()
Harkonnen.MarkCompletedObjective(CaptureAtreidesConYard) Harkonnen.MarkCompletedObjective(CaptureAtreidesConYard)
@@ -257,7 +331,9 @@ WorldLoaded = function()
unit.AttackMove(AtreidesAttackLocation) unit.AttackMove(AtreidesAttackLocation)
IdleHunt(unit) IdleHunt(unit)
end end
SendEnemyReinforcements(AtreidesMain, EnemyAttackDelay[Difficulty], AtreidesPath, AtreidesReinforcements[Difficulty], atreidesWaveCondition, huntFunction) SendEnemyReinforcements(AtreidesMain, EnemyAttackDelay[Difficulty], AtreidesPath, AtreidesReinforcements[Difficulty], atreidesWaveCondition, huntFunction)
Trigger.AfterDelay(CorrinoInitialAttackDelay[Difficulty], function() Trigger.AfterDelay(CorrinoInitialAttackDelay[Difficulty], function()
SendEnemyReinforcements(Corrino, EnemyAttackDelay[Difficulty], CorrinoPaths[1], CorrinoReinforcements[Difficulty][1], corrinoWaveCondition, huntFunction) SendEnemyReinforcements(Corrino, EnemyAttackDelay[Difficulty], CorrinoPaths[1], CorrinoReinforcements[Difficulty][1], corrinoWaveCondition, huntFunction)
SendEnemyReinforcements(Corrino, EnemyAttackDelay[Difficulty], CorrinoPaths[2], CorrinoReinforcements[Difficulty][2], corrinoWaveCondition, huntFunction) SendEnemyReinforcements(Corrino, EnemyAttackDelay[Difficulty], CorrinoPaths[2], CorrinoReinforcements[Difficulty][2], corrinoWaveCondition, huntFunction)
@@ -273,4 +349,14 @@ WorldLoaded = function()
SendHarkonnenReinforcements(1) SendHarkonnenReinforcements(1)
SendHarkonnenReinforcements(2) SendHarkonnenReinforcements(2)
Trigger.AfterDelay(7000, function()
SendHarkonnenReinforcements(1)
end)
Trigger.OnRemovedFromWorld(Crate1, function()
VisionPoint.GrantCondition("activate", 100)
Media.PlaySound("MULTI1.WAV")
Camera.Position = VisionPoint.CenterPosition
end)
end end

Binary file not shown.

View File

@@ -298,6 +298,7 @@ Actors:
AGunt1: medium_gun_turret AGunt1: medium_gun_turret
Location: 80,27 Location: 80,27
Owner: Atreides Main Base Owner: Atreides Main Base
TurretFacing: 512
Actor77: wall Actor77: wall
Location: 81,27 Location: 81,27
Owner: Atreides Main Base Owner: Atreides Main Base
@@ -769,6 +770,33 @@ Actors:
AtreidesEntry2: waypoint AtreidesEntry2: waypoint
Owner: Neutral Owner: Neutral
Location: 2,27 Location: 2,27
AtreidesPoint2: waypoint
Owner: Neutral
Location: 72,13
AtreidesPoint3: waypoint
Owner: Neutral
Location: 55,53
AtreidesPoint4: waypoint
Owner: Neutral
Location: 24,33
AtreidesPoint5: waypoint
Owner: Neutral
Location: 28,55
AtreidesPoint6: waypoint
Owner: Neutral
Location: 33,9
VisionPoint: vision_provider
Owner: Harkonnen
Location: 64,64
Crate1: crate_script
Owner: Harkonnen
Location: 57,62
AtreidesPoint1: waypoint
Owner: Neutral
Location: 54,6
Actor7: crate
Owner: Neutral
Location: 49,9
Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml

View File

@@ -1,6 +1,79 @@
Player: Player:
PlayerResources: PlayerResources:
DefaultCash: 6000 DefaultCash: 7000
ExternalCondition@AIMain:
Condition: base-rebuilder
ExternalCondition@AIMainWithDefense:
Condition: defense-rebuilder
BaseBuilderBotModule@MainBase:
RequiresCondition: base-rebuilder
BuildingQueues: Building, Upgrade
MinimumExcessPower: 0
MaximumExcessPower: 250
MaxBaseRadius: 40
ConstructionYardTypes: construction_yard
RefineryTypes: refinery
PowerTypes: wind_trap
ProductionTypes: light_factory, heavy_factory, barracks
SiloTypes: silo
DefenseTypes: medium_gun_turret,large_gun_turret
SellRefineryInterval: -1
BuildingLimits:
barracks: 1
refinery: 1
outpost: 1
light_factory: 1
heavy_factory: 1
high_tech_factory: 1
starport: 1
wind_trap: 7
silo: 1
BuildingFractions:
wind_trap: 1
barracks: 1
starport: 1
refinery: 1
outpost: 1
light_factory: 1
heavy_factory: 1
high_tech_factory: 1
BaseBuilderBotModule@MainBaseWithDefence:
RequiresCondition: defense-rebuilder
BuildingQueues: Building, Upgrade
MinimumExcessPower: 0
MaximumExcessPower: 250
MaxBaseRadius: 40
ConstructionYardTypes: construction_yard
RefineryTypes: refinery
PowerTypes: wind_trap
ProductionTypes: light_factory, heavy_factory, barracks
SiloTypes: silo
DefenseTypes: medium_gun_turret,large_gun_turret
PlaceDefenseTowardsEnemyChance: 50
SellRefineryInterval: -1
BuildingLimits:
barracks: 1
refinery: 1
outpost: 1
light_factory: 1
heavy_factory: 1
high_tech_factory: 1
starport: 1
wind_trap: 7
silo: 1
medium_gun_turret: 4
large_gun_turret: 4
BuildingFractions:
wind_trap: 1
barracks: 1
refinery: 1
outpost: 1
starport: 1
light_factory: 1
heavy_factory: 1
high_tech_factory: 1
medium_gun_turret: 1
large_gun_turret: 1
World: World:
LuaScript: LuaScript:

View File

@@ -7,6 +7,31 @@
information, see COPYING. information, see COPYING.
]] ]]
EarlyGameStage = DateTime.Minutes(7)
InitialProductionDelay = {
Ordos =
{
easy = DateTime.Seconds(150),
normal = DateTime.Seconds(120),
hard = DateTime.Seconds(60)
},
AtreidesEnemy =
{
easy = DateTime.Seconds(180),
normal = DateTime.Seconds(120),
hard = DateTime.Seconds(60)
},
MercenaryEnemy =
{
easy = DateTime.Seconds(160),
normal = DateTime.Seconds(80),
hard = DateTime.Seconds(30)
}
}
AttackGroupSize = AttackGroupSize =
{ {
easy = 6, easy = 6,
@@ -14,7 +39,14 @@ AttackGroupSize =
hard = 10 hard = 10
} }
AttackDelays = EarlyProductionDelays =
{
easy = { DateTime.Seconds(10), DateTime.Seconds(13) },
normal = { DateTime.Seconds(6), DateTime.Seconds(8) },
hard = { DateTime.Seconds(3), DateTime.Seconds(5) }
}
LateProductionDelays =
{ {
easy = { DateTime.Seconds(4), DateTime.Seconds(7) }, easy = { DateTime.Seconds(4), DateTime.Seconds(7) },
normal = { DateTime.Seconds(2), DateTime.Seconds(5) }, normal = { DateTime.Seconds(2), DateTime.Seconds(5) },
@@ -24,16 +56,61 @@ AttackDelays =
EnemyInfantryTypes = { "light_inf", "light_inf", "trooper", "trooper", "trooper" } EnemyInfantryTypes = { "light_inf", "light_inf", "trooper", "trooper", "trooper" }
OrdosVehicleTypes = { "raider", "raider", "quad" } OrdosVehicleTypes = { "raider", "raider", "quad" }
OrdosTankTypes = { "combat_tank_o", "combat_tank_o", "siege_tank", "deviator" }
OrdosStarportTypes = { "trike.starport", "trike.starport", "quad.starport", "combat_tank_o.starport", "combat_tank_o.starport", "siege_tank.starport", "missile_tank.starport" } OrdosTankTypes =
{
EarlyGame = { "combat_tank_o", "combat_tank_o", "siege_tank"},
LateGame = { "combat_tank_o", "combat_tank_o", "siege_tank", "deviator" }
}
OrdosStarportTypes =
{
EarlyGame = { "trike.starport", "trike.starport", "quad.starport", "combat_tank_o.starport" },
LateGame = { "trike.starport", "trike.starport", "quad.starport", "combat_tank_o.starport", "combat_tank_o.starport", "siege_tank.starport", "missile_tank.starport" }
}
AtreidesVehicleTypes = { "trike", "trike", "quad" } AtreidesVehicleTypes = { "trike", "trike", "quad" }
AtreidesTankTypes = { "combat_tank_a", "combat_tank_a", "siege_tank" }
AtreidesStarportTypes = { "trike.starport", "trike.starport", "quad.starport", "combat_tank_a.starport", "combat_tank_a.starport", "siege_tank.starport", "missile_tank.starport" } AtreidesTankTypes =
{
EarlyGame = { "combat_tank_a" },
LateGame = { "combat_tank_a", "combat_tank_a", "siege_tank" }
}
AtreidesStarportTypes =
{
EarlyGame ={ "trike.starport", "trike.starport", "quad.starport", "combat_tank_a.starport", "combat_tank_a.starport" },
LateGame ={ "trike.starport", "quad.starport", "combat_tank_a.starport", "combat_tank_a.starport", "siege_tank.starport", "missile_tank.starport" }
}
MercenaryTankTypes = { "combat_tank_o", "combat_tank_o", "siege_tank" } MercenaryTankTypes = { "combat_tank_o", "combat_tank_o", "siege_tank" }
ActivateAI = function() ActivateAI = function()
Defending[Ordos] = {}
Defending[AtreidesEnemy] = {}
Defending[AtreidesNeutral] = {}
Defending[MercenaryEnemy] = {}
Defending[MercenaryAlly] = {}
-- this is also first attack timing
AttackDelay[Ordos] = 16000
AttackDelay[AtreidesEnemy] = 10000
AttackDelay[MercenaryEnemy] = 7000
TimeBetweenAttacks[Ordos] = 8000 * DifficultyModifier[Difficulty]
TimeBetweenAttacks[AtreidesEnemy] = 7000 * DifficultyModifier[Difficulty]
TimeBetweenAttacks[MercenaryEnemy] = 7000 * DifficultyModifier[Difficulty]
HarvesterCount[Ordos] = 4
HarvesterCount[AtreidesEnemy] = 4
HarvesterCount[AtreidesNeutral] = 0
HarvesterCount[MercenaryEnemy] = 0
HarvesterCount[MercenaryAlly] = 0
PatrolPoints[Ordos] = {OrdosPatrolPoint1.Location, OrdosPatrolPoint2.Location, OrdosPatrolPoint3.Location, OrdosPatrolPoint4.Location }
PatrolPoints[AtreidesEnemy] = {AtreidesPatrolPoint1.Location, AtreidesPatrolPoint2.Location, OrdosPatrolPoint3.Location }
DefencePerimeter[Ordos] = GetCellsInRectangle(CPos.New(39,36), CPos.New(71,54))
DefencePerimeter[AtreidesEnemy] = Utils.Concat(GetCellsInRectangle(CPos.New(3,3), CPos.New(17,20)), GetCellsInRectangle(CPos.New(18,3), CPos.New(31,9)))
DefencePerimeter[MercenaryEnemy] = GetCellsInRectangle(CPos.New(29,64), CPos.New(40,71))
DefencePerimeter[MercenaryAlly] = DefencePerimeter[MercenaryEnemy]
DefencePerimeter[AtreidesNeutral] = DefencePerimeter[AtreidesEnemy]
IdlingUnits[Ordos] = Utils.Concat(Reinforcements.Reinforce(Ordos, InitialOrdosReinforcements[1], InitialOrdosPaths[1]), Reinforcements.Reinforce(Ordos, InitialOrdosReinforcements[2], InitialOrdosPaths[2])) IdlingUnits[Ordos] = Utils.Concat(Reinforcements.Reinforce(Ordos, InitialOrdosReinforcements[1], InitialOrdosPaths[1]), Reinforcements.Reinforce(Ordos, InitialOrdosReinforcements[2], InitialOrdosPaths[2]))
IdlingUnits[AtreidesEnemy] = Reinforcements.Reinforce(AtreidesEnemy, InitialAtreidesReinforcements, InitialAtreidesPath) IdlingUnits[AtreidesEnemy] = Reinforcements.Reinforce(AtreidesEnemy, InitialAtreidesReinforcements, InitialAtreidesPath)
IdlingUnits[AtreidesNeutral] = { } IdlingUnits[AtreidesNeutral] = { }
@@ -44,26 +121,112 @@ ActivateAI = function()
DefendAndRepairBase(AtreidesEnemy, AtreidesBase, 0.75, AttackGroupSize[Difficulty]) DefendAndRepairBase(AtreidesEnemy, AtreidesBase, 0.75, AttackGroupSize[Difficulty])
DefendAndRepairBase(MercenaryEnemy, MercenaryBase, 0.75, AttackGroupSize[Difficulty]) DefendAndRepairBase(MercenaryEnemy, MercenaryBase, 0.75, AttackGroupSize[Difficulty])
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end local delay = function(player)
if EmergencyBuildRate[player] and Difficulty ~= "easy" then
return 1
end
if EarlyGameStage >= DateTime.GameTime then
return Utils.RandomInteger(EarlyProductionDelays[Difficulty][1], EarlyProductionDelays[Difficulty][2] + 1)
else
return Utils.RandomInteger(LateProductionDelays[Difficulty][1], LateProductionDelays[Difficulty][2] + 1)
end
end
local infantryToBuild = function() return { Utils.Random(EnemyInfantryTypes) } end local infantryToBuild = function() return { Utils.Random(EnemyInfantryTypes) } end
local vehilcesToBuildOrdos = function() return { Utils.Random(OrdosVehicleTypes) } end local vehiclesToBuildOrdos = function() return { Utils.Random(OrdosVehicleTypes) } end
local vehilcesToBuildAtreides = function() return { Utils.Random(AtreidesVehicleTypes) } end local vehiclesToBuildAtreides = function() return { Utils.Random(AtreidesVehicleTypes) } end
local tanksToBuildOrdos = function() return { Utils.Random(OrdosTankTypes) } end
local tanksToBuildAtreides = function() return { Utils.Random(AtreidesTankTypes) } end local tanksToBuildOrdos = function()
if EarlyGameStage >= DateTime.GameTime then
return { Utils.Random(OrdosTankTypes["EarlyGame"]) }
else
return { Utils.Random(OrdosTankTypes["LateGame"]) }
end
end
local tanksToBuildAtreides = function()
if EarlyGameStage >= DateTime.GameTime then
return { Utils.Random(AtreidesTankTypes["EarlyGame"]) }
else
return { Utils.Random(AtreidesTankTypes["LateGame"]) }
end
end
local tanksToBuildMercenary = function() return { Utils.Random(MercenaryTankTypes) } end local tanksToBuildMercenary = function() return { Utils.Random(MercenaryTankTypes) } end
local unitsToBuyOrdos = function() return { Utils.Random(OrdosStarportTypes) } end local unitsToBuyOrdos = function()
local unitsToBuyAtreides = function() return { Utils.Random(AtreidesStarportTypes) } end if EarlyGameStage >= DateTime.GameTime then
return { Utils.Random(OrdosStarportTypes["EarlyGame"]) }
else
return { Utils.Random(OrdosStarportTypes["LateGame"]) }
end
end
local unitsToBuyAtreides = function()
if EarlyGameStage >= DateTime.GameTime then
return { Utils.Random(AtreidesStarportTypes["EarlyGame"]) }
else
return { Utils.Random(AtreidesStarportTypes["LateGame"]) }
end
end
local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5 local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5
ProduceUnits(Ordos, OBarracks1, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize) Trigger.AfterDelay(InitialProductionDelay["Ordos"][Difficulty], function ()
ProduceUnits(Ordos, OLightFactory, delay, vehilcesToBuildOrdos, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(Ordos, OBarracks1, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
ProduceUnits(Ordos, OHeavyFactory, delay, tanksToBuildOrdos, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(Ordos, OLightFactory, delay, vehiclesToBuildOrdos, AttackGroupSize[Difficulty], attackThresholdSize)
ProduceUnits(Ordos, OStarport, delay, unitsToBuyOrdos, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(Ordos, OHeavyFactory, delay, tanksToBuildOrdos, AttackGroupSize[Difficulty], attackThresholdSize)
ProduceUnits(Ordos, OStarport, delay, unitsToBuyOrdos, AttackGroupSize[Difficulty], attackThresholdSize)
end)
ProduceUnits(AtreidesEnemy, ABarracks1, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize) Trigger.AfterDelay(InitialProductionDelay["AtreidesEnemy"][Difficulty], function ()
ProduceUnits(AtreidesEnemy, ALightFactory, delay, vehilcesToBuildAtreides, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(AtreidesEnemy, ABarracks1, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
ProduceUnits(AtreidesEnemy, AHeavyFactory, delay, tanksToBuildAtreides, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(AtreidesEnemy, ALightFactory, delay, vehiclesToBuildAtreides, AttackGroupSize[Difficulty], attackThresholdSize)
ProduceUnits(AtreidesEnemy, AStarport, delay, unitsToBuyAtreides, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(AtreidesEnemy, AHeavyFactory, delay, tanksToBuildAtreides, AttackGroupSize[Difficulty], attackThresholdSize)
ProduceUnits(AtreidesEnemy, AStarport, delay, unitsToBuyAtreides, AttackGroupSize[Difficulty], attackThresholdSize)
end)
ProduceUnits(MercenaryEnemy, MHeavyFactory, delay, tanksToBuildMercenary, AttackGroupSize[Difficulty], attackThresholdSize) Trigger.AfterDelay(InitialProductionDelay["AtreidesEnemy"][Difficulty], function ()
ProduceUnits(MercenaryEnemy, MHeavyFactory, delay, tanksToBuildMercenary, AttackGroupSize[Difficulty], attackThresholdSize)
end)
ActivateCrushLogic()
if Difficulty == "normal" then
Ordos.GrantCondition("base-rebuilder")
AtreidesEnemy.GrantCondition("base-rebuilder2")
end
if Difficulty == "hard" then
Ordos.GrantCondition("defense-rebuilder")
AtreidesEnemy.GrantCondition("defense-rebuilder2")
end
local productionTypesAtreidis =
{
barracks = infantryToBuild,
light_factory = vehiclesToBuildAtreides,
heavy_factory = tanksToBuildAtreides
}
local productionTypesOrdos =
{
barracks = infantryToBuild,
light_factory = vehiclesToBuildOrdos,
heavy_factory = tanksToBuildOrdos
}
Trigger.OnBuildingPlaced(Ordos, function(p, building)
table.insert(OrdosBase, building)
DefendAndRepairBase(Ordos, {building}, 0.5, AttackGroupSize[Difficulty] )
if productionTypesOrdos[building.Type] == nil then return end
ProduceUnits(Ordos, building, delay, productionTypesOrdos[building.Type], AttackGroupSize[Difficulty], attackThresholdSize)
end)
Trigger.OnBuildingPlaced(AtreidesEnemy, function(p, building)
table.insert(AtreidesBase, building)
DefendAndRepairBase(AtreidesEnemy, {building}, 0.75, AttackGroupSize[Difficulty] )
if productionTypesAtreidis[building.Type] == nil then return end
ProduceUnits(AtreidesEnemy, building, delay, productionTypesAtreidis[building.Type], AttackGroupSize[Difficulty], attackThresholdSize)
end)
end end

View File

@@ -8,7 +8,9 @@
]] ]]
OrdosBase = { OConYard, OOutpost, OPalace, ORefinery1, ORefinery2, OHeavyFactory, OLightFactory, OHiTechFactory, OResearch, ORepair, OStarport, OGunt1, OGunt2, OGunt3, OGunt4, OGunt5, OGunt6, ORock1, ORock2, ORock3, ORock4, OBarracks1, OBarracks2, OPower1, OPower2, OPower3, OPower4, OPower5, OPower6, OPower7, OPower8, OPower9, OPower10, OPower11, OPower12, OPower13 } OrdosBase = { OConYard, OOutpost, OPalace, ORefinery1, ORefinery2, OHeavyFactory, OLightFactory, OHiTechFactory, OResearch, ORepair, OStarport, OGunt1, OGunt2, OGunt3, OGunt4, OGunt5, OGunt6, ORock1, ORock2, ORock3, ORock4, OBarracks1, OBarracks2, OPower1, OPower2, OPower3, OPower4, OPower5, OPower6, OPower7, OPower8, OPower9, OPower10, OPower11, OPower12, OPower13 }
AtreidesBase = { AConYard, AOutpost, ARefinery1, ARefinery2, AHeavyFactory, ALightFactory, AHiTechFactory, ARepair, AStarport, AGunt1, AGunt2, ARock1, ARock2, APower1, APower2, APower3, APower4, APower5, APower6, APower7, APower8, APower9 }
AtreidesBase = { AConYard,ABarracks1, ABarracks2, AOutpost, ARefinery1, ARefinery2, AHeavyFactory, ALightFactory, AHiTechFactory, ARepair, AStarport, AGunt1, AGunt2, ARock1, ARock2, APower1, APower2, APower3, APower4, APower5, APower6, APower7, APower8, APower9 }
MercenaryBase = { MHeavyFactory, MStarport, MGunt, MPower1, MPower2 } MercenaryBase = { MHeavyFactory, MStarport, MGunt, MPower1, MPower2 }
OrdosReinforcements = OrdosReinforcements =
@@ -56,7 +58,7 @@ OrdosAttackDelay =
hard = DateTime.Minutes(1) hard = DateTime.Minutes(1)
} }
MercenaryStarportDelay = DateTime.Minutes(1) + DateTime.Seconds(20) MercenaryStarportDelay = 4970
OrdosAttackWaves = OrdosAttackWaves =
{ {
@@ -92,7 +94,9 @@ InitialOrdosPaths =
SaboteurPaths = SaboteurPaths =
{ {
{ SaboteurWaypoint1.Location, SaboteurWaypoint2.Location, SaboteurWaypoint3.Location }, { SaboteurWaypoint1.Location, SaboteurWaypoint2.Location, SaboteurWaypoint3.Location },
{ SaboteurWaypoint4.Location, SaboteurWaypoint5.Location, SaboteurWaypoint6.Location } { SaboteurWaypoint4.Location, SaboteurWaypoint5.Location, SaboteurWaypoint6.Location },
{ SaboteurWaypoint1.Location, OrdosPatrolPoint2.Location, OrdosRally1.Location, SaboteurWaypoint6.Location },
{ OrdosRally4.Location, OrdosPatrolPoint3.Location, OrdosPatrolPoint2.Location}
} }
InitialAtreidesPath = { AStarport.Location, AtreidesRally.Location } InitialAtreidesPath = { AStarport.Location, AtreidesRally.Location }
@@ -117,14 +121,36 @@ SendStarportReinforcements = function(faction)
end) end)
end end
SendAirStrike = function() AirStrikeTimer = 7500
if AHiTechFactory.IsDead or AHiTechFactory.Owner ~= AtreidesEnemy then AirStrikeChargeTime = 7500
AirstrikeLogic = function(airstrikeProvider)
if airstrikeProvider.IsDead then
return
end
if DateTime.GameTime <= AirStrikeTimer then
Trigger.AfterDelay(AirStrikeTimer - DateTime.GameTime + 1, function()
AirstrikeLogic(airstrikeProvider)
end)
return
end
-- randomly choose if wait again or strike. During waiting Airstrike can still be used by DefensiveAirStrike
if Utils.RandomInteger(1, 100) < 30 then
Trigger.AfterDelay(1000, function() AirstrikeLogic(airstrikeProvider)end)
else
AirStrikeVSBuilding(airstrikeProvider)
Trigger.AfterDelay(7500, function() AirstrikeLogic(airstrikeProvider) end)
IsAirstrikeReady = false
end
end
AirStrikeVSBuilding = function(airstrikeProvider)
if airstrikeProvider.IsDead or DateTime.GameTime < AirStrikeTimer then
return return
end end
local targets = Utils.Where(Harkonnen.GetActors(), function(actor) local targets = Utils.Where(Harkonnen.GetActors(), function(actor)
return return actor.HasProperty("Sell") and
actor.HasProperty("Sell") and
actor.Type ~= "wall" and actor.Type ~= "wall" and
actor.Type ~= "medium_gun_turret" and actor.Type ~= "medium_gun_turret" and
actor.Type ~= "large_gun_turret" and actor.Type ~= "large_gun_turret" and
@@ -133,16 +159,40 @@ SendAirStrike = function()
end) end)
if #targets > 0 then if #targets > 0 then
AHiTechFactory.TargetAirstrike(Utils.Random(targets).CenterPosition) airstrikeProvider.TargetAirstrike(Utils.Random(targets).CenterPosition)
AirStrikeTimer = DateTime.GameTime + AirStrikeChargeTime
end
end
DefensiveAirStrike = function(airstrikeProvider, possibleTargets)
if airstrikeProvider.IsDead or DateTime.GameTime <= AirStrikeTimer then return end
local bestValue = {}
local bestIndex = 1
for i = 1, #possibleTargets, 1 do
local ActorsInCircle = Map.ActorsInCircle(possibleTargets[i].CenterPosition, WDist.FromCells(4), function(a)
return
a.Owner == Harkonnen
and not a.IsDead
and a.HasProperty("Attack")
end)
bestValue[i] = 0
Utils.Do(ActorsInCircle, function(a)
bestValue[i] = bestValue[i] + Actor.Cost(a.Type)
end)
if bestValue[i] > bestValue[bestIndex] then
bestIndex = i
end
end end
Trigger.AfterDelay(DateTime.Minutes(5), SendAirStrike) airstrikeProvider.TargetAirstrike(possibleTargets[bestIndex].CenterPosition)
AirStrikeTimer = DateTime.GameTime + AirStrikeChargeTime
end end
GetSaboteurTargets = function(player) GetSaboteurTargets = function(player)
return Utils.Where(player.GetActors(), function(actor) return Utils.Where(player.GetActors(), function(actor)
return return actor.HasProperty("Sell") and
actor.HasProperty("Sell") and
actor.Type ~= "wall" and actor.Type ~= "wall" and
actor.Type ~= "medium_gun_turret" and actor.Type ~= "medium_gun_turret" and
actor.Type ~= "large_gun_turret" and actor.Type ~= "large_gun_turret" and
@@ -162,14 +212,54 @@ BuildSaboteur = function()
saboteur.Wait(DateTime.Seconds(5)) saboteur.Wait(DateTime.Seconds(5))
local path = Utils.Random(SaboteurPaths) local path = Utils.Random(SaboteurPaths)
saboteur.Move(path[1]) Utils.Do(path, function(waypoint)
saboteur.Move(path[2]) saboteur.Move(waypoint)
saboteur.Move(path[3]) end)
SendSaboteur(saboteur) SendSaboteur(saboteur)
ScanForBetterTargets(saboteur)
end end
Trigger.AfterDelay(DateTime.Minutes(1) + DateTime.Seconds(30), BuildSaboteur) Trigger.AfterDelay(DateTime.Minutes(5) + DateTime.Seconds(30), BuildSaboteur)
end
DemolishType = { "harvester", "mcv", "siege_tank", "missile_tank", "sonic_tank", "devastator", "deviator", "combat_tank_a", "combat_tank_h", "combat_tank_o"}
ScanForBetterTargets = function(saboteur)
if saboteur.IsDead or not saboteur.IsInWorld then return end
local possibleTargets = Map.ActorsInCircle(saboteur.CenterPosition, WDist.FromCells(6), function(a)
return not saboteur.Owner.IsAlliedWith(a.Owner) and
Utils.Any(DemolishType, function(d) return d == a.Type end)
end)
if possibleTargets[1] == nil then
Trigger.AfterDelay(200, function()
ScanForBetterTargets(saboteur)
end)
return
end
-- filter out targets where infantry is nearby
for index = #possibleTargets, 1, -1 do
local infantryunits = Map.ActorsInCircle(possibleTargets[index].CenterPosition, WDist.New(1536), function(u) return u.Type == "light_inf" or u.Type == "trooper" end)
if infantryunits[1] ~= nil then
table.remove(possibleTargets, index)
end
end
if possibleTargets[1] ~= nil then
saboteur.Stop()
local dfd = Utils.Random(possibleTargets)
saboteur.Demolish(dfd)
saboteur.CallFunc(function()
ScanForBetterTargets(saboteur)
end)
else
Trigger.AfterDelay(200, function()
ScanForBetterTargets(saboteur)
end)
end
end end
SendSaboteur = function(saboteur) SendSaboteur = function(saboteur)
@@ -216,6 +306,21 @@ ChangeOwner = function(old_owner, new_owner)
end) end)
end end
EmergencyBehaviour = function(player, target)
HoldProduction[player] = false
if player == Ordos and not AtreidesEnemy.HasNoRequiredUnits() then
if AHiTechFactory.IsDead then return end
local enemyunits = Map.ActorsInCircle(Map.CenterOfCell(target), WDist.FromCells(15), function(a)
return a.Owner == Harkonnen
and not a.IsDead
and a.HasProperty("Attack")
end)
if enemyunits[1] == nil then return end
DefensiveAirStrike(AHiTechFactory, enemyunits)
end
end
Tick = function() Tick = function()
if Harkonnen.HasNoRequiredUnits() then if Harkonnen.HasNoRequiredUnits() then
Ordos.MarkCompletedObjective(KillHarkonnen1) Ordos.MarkCompletedObjective(KillHarkonnen1)
@@ -239,7 +344,6 @@ Tick = function()
if DateTime.GameTime % DateTime.Seconds(10) == 0 and LastHarvesterEaten[Ordos] then if DateTime.GameTime % DateTime.Seconds(10) == 0 and LastHarvesterEaten[Ordos] then
local units = Ordos.GetActorsByType("harvester") local units = Ordos.GetActorsByType("harvester")
if #units > 0 then if #units > 0 then
LastHarvesterEaten[Ordos] = false LastHarvesterEaten[Ordos] = false
ProtectHarvester(units[1], Ordos, AttackGroupSize[Difficulty]) ProtectHarvester(units[1], Ordos, AttackGroupSize[Difficulty])
@@ -248,7 +352,6 @@ Tick = function()
if DateTime.GameTime % DateTime.Seconds(10) == 0 and LastHarvesterEaten[AtreidesEnemy] then if DateTime.GameTime % DateTime.Seconds(10) == 0 and LastHarvesterEaten[AtreidesEnemy] then
local units = AtreidesEnemy.GetActorsByType("harvester") local units = AtreidesEnemy.GetActorsByType("harvester")
if #units > 0 then if #units > 0 then
LastHarvesterEaten[AtreidesEnemy] = false LastHarvesterEaten[AtreidesEnemy] = false
ProtectHarvester(units[1], AtreidesEnemy, AttackGroupSize[Difficulty]) ProtectHarvester(units[1], AtreidesEnemy, AttackGroupSize[Difficulty])
@@ -275,8 +378,8 @@ WorldLoaded = function()
OrdosAttackLocation = HMCV.Location OrdosAttackLocation = HMCV.Location
MercenaryAttackLocation = HMCV.Location MercenaryAttackLocation = HMCV.Location
Trigger.AfterDelay(DateTime.Minutes(5), SendAirStrike) Trigger.AfterDelay(EarlyGameStage, function() AirstrikeLogic(AHiTechFactory) end)
Trigger.AfterDelay(DateTime.Minutes(1) + DateTime.Seconds(30), BuildSaboteur) Trigger.AfterDelay(EarlyGameStage, BuildSaboteur)
Trigger.OnCapture(MHeavyFactory, function() Trigger.OnCapture(MHeavyFactory, function()
Harkonnen.MarkCompletedObjective(AllyWithMercenaries) Harkonnen.MarkCompletedObjective(AllyWithMercenaries)
@@ -296,7 +399,7 @@ WorldLoaded = function()
end) end)
Trigger.OnKilledOrCaptured(OPalace, function() Trigger.OnKilledOrCaptured(OPalace, function()
Media.DisplayMessage(UserInterface.GetFluentMessage("cannot-stand-harkonnen-must-become-neutral"), UserInterface.GetFluentMessage("atreides-commander")) Media.DisplayMessage(UserInterface.GetFluentMessage("cannot-stand-harkonnen-must-become-neutral"), UserInterface.GetFluentMessage("atreides-commander"), HSLColor.FromHex("5A7394"))
ChangeOwner(AtreidesEnemy, AtreidesNeutral) ChangeOwner(AtreidesEnemy, AtreidesNeutral)
DefendAndRepairBase(AtreidesNeutral, AtreidesBase, 0.75, AttackGroupSize[Difficulty]) DefendAndRepairBase(AtreidesNeutral, AtreidesBase, 0.75, AttackGroupSize[Difficulty])
@@ -328,8 +431,8 @@ WorldLoaded = function()
unit.AttackMove(OrdosAttackLocation) unit.AttackMove(OrdosAttackLocation)
IdleHunt(unit) IdleHunt(unit)
end end
SendCarryallReinforcements(Ordos, 0, OrdosAttackWaves[Difficulty], OrdosAttackDelay[Difficulty], path, OrdosReinforcements[Difficulty], waveCondition, huntFunction)
SendCarryallReinforcements(Ordos, 0, OrdosAttackWaves[Difficulty], OrdosAttackDelay[Difficulty], path, OrdosReinforcements[Difficulty], waveCondition, huntFunction)
SendStarportReinforcements(MercenaryEnemy) SendStarportReinforcements(MercenaryEnemy)
Actor.Create("upgrade.barracks", true, { Owner = Ordos }) Actor.Create("upgrade.barracks", true, { Owner = Ordos })

View File

@@ -643,15 +643,33 @@ Actors:
SaboteurWaypoint4: waypoint SaboteurWaypoint4: waypoint
Owner: Neutral Owner: Neutral
Location: 18,59 Location: 18,59
SaboteurWaypoint5: waypoint
Owner: Neutral
Location: 31,91
SaboteurWaypoint6: waypoint SaboteurWaypoint6: waypoint
Owner: Neutral Owner: Neutral
Location: 64,91 Location: 64,91
MercenaryAttackPoint: waypoint MercenaryAttackPoint: waypoint
Owner: Neutral Owner: Neutral
Location: 53,38 Location: 53,38
OrdosPatrolPoint1: waypoint
Owner: Neutral
Location: 78,45
OrdosPatrolPoint2: waypoint
Owner: Neutral
Location: 55,63
OrdosPatrolPoint3: waypoint
Owner: Neutral
Location: 30,54
OrdosPatrolPoint4: waypoint
Owner: Neutral
Location: 73,21
AtreidesPatrolPoint1: waypoint
Owner: Neutral
Location: 14,65
AtreidesPatrolPoint2: waypoint
Owner: Neutral
Location: 48,10
SaboteurWaypoint5: waypoint
Owner: Neutral
Location: 31,81
Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml

View File

@@ -1,6 +1,150 @@
Player: Player:
PlayerResources: PlayerResources:
DefaultCash: 7000 DefaultCash: 7000
ExternalCondition@AIOrdos:
Condition: base-rebuilder
ExternalCondition@AIOrdosDefense:
Condition: defense-rebuilder
ExternalCondition@AIAtreides:
Condition: base-rebuilder2
ExternalCondition@AIAtreidesDefense:
Condition: defense-rebuilder2
BaseBuilderBotModule@Ordos:
RequiresCondition: base-rebuilder
BuildingQueues: Building, Upgrade
MinimumExcessPower: 0
MaximumExcessPower: 250
MaxBaseRadius: 40
ConstructionYardTypes: construction_yard
RefineryTypes: refinery
PowerTypes: wind_trap
ProductionTypes: light_factory, heavy_factory, barracks, starport
SiloTypes: silo
DefenseTypes: medium_gun_turret,large_gun_turret
SellRefineryInterval: -1
BuildingLimits:
barracks: 2
refinery: 1
outpost: 1
light_factory: 1
heavy_factory: 1
high_tech_factory: 1
starport: 1
wind_trap: 12
silo: 1
BuildingFractions:
wind_trap: 1
barracks: 2
high_tech_factory: 1
starport: 1
refinery: 1
outpost: 1
light_factory: 1
heavy_factory: 1
BaseBuilderBotModule@OrdosDefnse:
RequiresCondition: defense-rebuilder
BuildingQueues: Building, Upgrade
MinimumExcessPower: 0
MaximumExcessPower: 250
MaxBaseRadius: 40
ConstructionYardTypes: construction_yard
RefineryTypes: refinery
PowerTypes: wind_trap
ProductionTypes: light_factory, heavy_factory, barracks, starport
SiloTypes: silo
DefenseTypes: medium_gun_turret,large_gun_turret
SellRefineryInterval: -1
BuildingLimits:
barracks: 2
refinery: 1
outpost: 1
light_factory: 1
heavy_factory: 1
wind_trap: 12
silo: 1
high_tech_factory: 1
starport: 1
medium_gun_turret: 8
large_gun_turret: 4
BuildingFractions:
wind_trap: 1
barracks: 1
refinery: 1
outpost: 1
light_factory: 1
heavy_factory: 1
high_tech_factory: 1
starport: 1
medium_gun_turret: 6
large_gun_turret: 4
BaseBuilderBotModule@Atreides:
RequiresCondition: base-rebuilder2
BuildingQueues: Building, Upgrade
MinimumExcessPower: 0
MaximumExcessPower: 250
MaxBaseRadius: 40
ConstructionYardTypes: construction_yard
RefineryTypes: refinery
PowerTypes: wind_trap
ProductionTypes: light_factory, heavy_factory, barracks, starport
SiloTypes: silo
DefenseTypes: medium_gun_turret,large_gun_turret
SellRefineryInterval: -1
BuildingLimits:
barracks: 2
refinery: 1
outpost: 1
light_factory: 1
heavy_factory: 1
high_tech_factory: 1
starport: 1
wind_trap: 12
silo: 1
BuildingFractions:
wind_trap: 1
barracks: 1
high_tech_factory: 1
starport: 1
refinery: 1
outpost: 1
light_factory: 1
heavy_factory: 1
BaseBuilderBotModule@AtreidesDefense:
RequiresCondition: defense-rebuilder2
BuildingQueues: Building, Upgrade
MinimumExcessPower: 0
MaximumExcessPower: 250
MaxBaseRadius: 40
ConstructionYardTypes: construction_yard
RefineryTypes: refinery
PowerTypes: wind_trap
ProductionTypes: light_factory, heavy_factory, barracks, starport
SiloTypes: silo
DefenseTypes: medium_gun_turret,large_gun_turret
SellRefineryInterval: -1
BuildingLimits:
barracks: 2
refinery: 1
outpost: 1
light_factory: 1
heavy_factory: 1
wind_trap: 9
silo: 1
high_tech_factory: 1
starport: 1
medium_gun_turret: 6
large_gun_turret: 6
BuildingFractions:
wind_trap: 1
barracks: 1
refinery: 1
outpost: 1
light_factory: 1
heavy_factory: 1
high_tech_factory: 1
starport: 1
medium_gun_turret: 1
large_gun_turret: 1
World: World:
LuaScript: LuaScript:

View File

@@ -7,6 +7,8 @@
information, see COPYING. information, see COPYING.
]] ]]
EarlyGameStage = DateTime.Minutes(10)
AttackGroupSize = AttackGroupSize =
{ {
easy = 6, easy = 6,
@@ -14,26 +16,117 @@ AttackGroupSize =
hard = 10 hard = 10
} }
AttackDelays = EarlyProductionDelays =
{ {
easy = { DateTime.Seconds(4), DateTime.Seconds(7) },
normal = { DateTime.Seconds(2), DateTime.Seconds(5) }, easy = { DateTime.Seconds(12), DateTime.Seconds(15) },
hard = { DateTime.Seconds(1), DateTime.Seconds(3) } normal = { DateTime.Seconds(10), DateTime.Seconds(13) },
hard = { DateTime.Seconds(9), DateTime.Seconds(10) }
}
LateProductionDelays =
{
easy = { DateTime.Seconds(5), DateTime.Seconds(8) },
normal = { DateTime.Seconds(3), DateTime.Seconds(6) },
hard = { DateTime.Seconds(2), DateTime.Seconds(4) }
}
InitialProductionDelay = {
AtreidesMain =
{
easy = DateTime.Seconds(200),
normal = DateTime.Seconds(150),
hard = DateTime.Seconds(100)
},
AtreidesSmall =
{
easy = DateTime.Seconds(160),
normal = DateTime.Seconds(80),
hard = DateTime.Seconds(50)
},
CorrinoMain =
{
easy = DateTime.Seconds(250),
normal = DateTime.Seconds(200),
hard = DateTime.Seconds(150)
},
CorrinoSmall =
{
easy = DateTime.Seconds(100),
normal = DateTime.Seconds(80),
hard = DateTime.Seconds(60)
}
} }
EnemyInfantryTypes = { "light_inf", "light_inf", "light_inf", "trooper", "trooper" } EnemyInfantryTypes = { "light_inf", "light_inf", "light_inf", "trooper", "trooper" }
EnemyVehicleTypes = { "trike", "trike", "quad" } EnemyVehicleTypes = { "trike", "trike", "quad" }
AtreidesMainTankTypes = { "combat_tank_a", "combat_tank_a", "siege_tank", "missile_tank", "sonic_tank" } AtreidesMainTankTypes = {
EarlyGame = { "combat_tank_a", "combat_tank_a", "siege_tank", "missile_tank" },
LateGame = {"combat_tank_a", "siege_tank", "missile_tank", "sonic_tank"}
}
AtreidesSmallTankTypes = { "combat_tank_a", "combat_tank_a", "siege_tank" } AtreidesSmallTankTypes = { "combat_tank_a", "combat_tank_a", "siege_tank" }
AtreidesStarportTypes = { "trike.starport", "trike.starport", "quad.starport", "combat_tank_a.starport", "combat_tank_a.starport", "siege_tank.starport", "missile_tank.starport" }
CorrinoMainInfantryTypes = { "light_inf", "light_inf", "trooper", "sardaukar" } CorrinoMainInfantryTypes = { "light_inf", "light_inf", "trooper", "sardaukar" }
CorrinoMainTankTypes = { "combat_tank_h", "combat_tank_h", "siege_tank", "missile_tank" }
CorrinoMainTankTypes = {
EarlyGame = { "combat_tank_h" },
LateGame = { "combat_tank_h", "combat_tank_h", "siege_tank", "missile_tank" }
}
CorrinoSmallTankTypes = { "combat_tank_h", "combat_tank_h", "siege_tank" } CorrinoSmallTankTypes = { "combat_tank_h", "combat_tank_h", "siege_tank" }
CorrinoStarportTypes = { "trike.starport", "trike.starport", "quad.starport", "combat_tank_h.starport", "combat_tank_h.starport", "siege_tank.starport", "missile_tank.starport" }
ActivateAI = function() ActivateAI = function()
Defending[AtreidesMain] = {}
Defending[AtreidesSmall1] = {}
Defending[AtreidesSmall2] = {}
Defending[CorrinoMain] = {}
Defending[CorrinoSmall] = {}
-- this is also first attack timing
AttackDelay[AtreidesMain] = 16000
AttackDelay[AtreidesSmall1] = 16000
AttackDelay[AtreidesSmall2] = 16000
AttackDelay[CorrinoMain] = 16000
AttackDelay[CorrinoSmall] = 16000
TimeBetweenAttacks[AtreidesMain] = 13000 * DifficultyModifier[Difficulty]
TimeBetweenAttacks[AtreidesSmall1] = 1000 * DifficultyModifier[Difficulty]
TimeBetweenAttacks[AtreidesSmall2] = 4000 * DifficultyModifier[Difficulty]
TimeBetweenAttacks[CorrinoMain] = 12000 * DifficultyModifier[Difficulty]
TimeBetweenAttacks[CorrinoSmall] = 10000 * DifficultyModifier[Difficulty]
Trigger.OnAllKilledOrCaptured(AtreidesSmall1Base, function()
TimeBetweenAttacks[AtreidesMain] = 0
end)
Trigger.OnAllKilledOrCaptured(CorrinoMainBase, function()
TimeBetweenAttacks[CorrinoSmall] = 0
end)
Trigger.OnAllKilledOrCaptured(CorrinoSmallBase, function()
TimeBetweenAttacks[CorrinoMain] = 0
end)
HarvesterCount[AtreidesMain] = 4
HarvesterCount[AtreidesSmall1] = 2
HarvesterCount[AtreidesSmall2] = 2
HarvesterCount[CorrinoMain] = 4
HarvesterCount[CorrinoSmall] = 2
PatrolPoints[AtreidesMain] = {AtreidesPatrolPoint3.Location, AtreidesPatrolPoint4.Location, AtreidesPatrolPoint2.Location, AtreidesRally10.Location, AtreidesPatrolPoint5.Location }
PatrolPoints[AtreidesSmall1] = {AtreidesPatrolPoint1.Location, AtreidesPatrolPoint2.Location, AtreidesRally3.Location }
PatrolPoints[CorrinoMain] = {CorrinoPatrolPoint1.Location, CorrinoPatrolPoint2.Location, AtreidesPatrolPoint5.Location }
PatrolPoints[CorrinoSmall] = {CorrinoPatrolPoint3.Location, AtreidesPatrolPoint3.Location, AtreidesPatrolPoint5.Location }
DefencePerimeter[AtreidesMain] = GetCellsInRectangle(CPos.New(36,15), CPos.New(57,30))
DefencePerimeter[AtreidesSmall1] = GetCellsInRectangle(CPos.New(34,51), CPos.New(46,74))
DefencePerimeter[AtreidesSmall2] = GetCellsInRectangle(CPos.New(18,32), CPos.New(30,37))
DefencePerimeter[CorrinoMain] = GetCellsInRectangle(CPos.New(3,13), CPos.New(24,26))
DefencePerimeter[CorrinoSmall] = GetCellsInRectangle(CPos.New(74,27), CPos.New(96,48))
IdlingUnits[AtreidesMain] = Utils.Concat(Reinforcements.Reinforce(AtreidesMain, InitialAtreidesReinforcements[1], InitialAtreidesPaths[1]), Utils.Concat(Reinforcements.Reinforce(AtreidesMain, InitialAtreidesReinforcements[2], InitialAtreidesPaths[2]), Reinforcements.Reinforce(AtreidesMain, InitialAtreidesReinforcements[3], InitialAtreidesPaths[3]))) IdlingUnits[AtreidesMain] = Utils.Concat(Reinforcements.Reinforce(AtreidesMain, InitialAtreidesReinforcements[1], InitialAtreidesPaths[1]), Utils.Concat(Reinforcements.Reinforce(AtreidesMain, InitialAtreidesReinforcements[2], InitialAtreidesPaths[2]), Reinforcements.Reinforce(AtreidesMain, InitialAtreidesReinforcements[3], InitialAtreidesPaths[3])))
IdlingUnits[AtreidesSmall1] = Utils.Concat(Reinforcements.Reinforce(AtreidesSmall1, InitialAtreidesReinforcements[4], InitialAtreidesPaths[4]), Reinforcements.Reinforce(AtreidesSmall1, InitialAtreidesReinforcements[5], InitialAtreidesPaths[5])) IdlingUnits[AtreidesSmall1] = Utils.Concat(Reinforcements.Reinforce(AtreidesSmall1, InitialAtreidesReinforcements[4], InitialAtreidesPaths[4]), Reinforcements.Reinforce(AtreidesSmall1, InitialAtreidesReinforcements[5], InitialAtreidesPaths[5]))
IdlingUnits[AtreidesSmall2] = Reinforcements.Reinforce(AtreidesSmall2, InitialAtreidesReinforcements[6], InitialAtreidesPaths[6]) IdlingUnits[AtreidesSmall2] = Reinforcements.Reinforce(AtreidesSmall2, InitialAtreidesReinforcements[6], InitialAtreidesPaths[6])
@@ -46,35 +139,118 @@ ActivateAI = function()
DefendAndRepairBase(CorrinoMain, CorrinoMainBase, 0.75, AttackGroupSize[Difficulty]) DefendAndRepairBase(CorrinoMain, CorrinoMainBase, 0.75, AttackGroupSize[Difficulty])
DefendAndRepairBase(CorrinoSmall, CorrinoSmallBase, 0.75, AttackGroupSize[Difficulty]) DefendAndRepairBase(CorrinoSmall, CorrinoSmallBase, 0.75, AttackGroupSize[Difficulty])
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end local delay = function(player)
if EmergencyBuildRate[player] and Difficulty ~= "easy" then
return 1
end
if EarlyGameStage >= DateTime.GameTime then
return Utils.RandomInteger(EarlyProductionDelays[Difficulty][1], EarlyProductionDelays[Difficulty][2] + 1)
else
return Utils.RandomInteger(LateProductionDelays[Difficulty][1], LateProductionDelays[Difficulty][2] + 1)
end
end
local infantryToBuild = function() return { Utils.Random(EnemyInfantryTypes) } end local infantryToBuild = function() return { Utils.Random(EnemyInfantryTypes) } end
local infantryToBuildCorrinoMain = function() return { Utils.Random(CorrinoMainInfantryTypes) } end local infantryToBuildCorrinoMain = function() return { Utils.Random(CorrinoMainInfantryTypes) } end
local vehilcesToBuild = function() return { Utils.Random(EnemyVehicleTypes) } end local vehiclesToBuild = function() return { Utils.Random(EnemyVehicleTypes) } end
local tanksToBuildAtreidesMain = function() return { Utils.Random(AtreidesMainTankTypes) } end local tanksToBuildAtreidesMain = function()
if EarlyGameStage >= DateTime.GameTime then
return { Utils.Random(AtreidesMainTankTypes["EarlyGame"]) }
else
return { Utils.Random(AtreidesMainTankTypes["LateGame"]) }
end
end
local tanksToBuildAtreidesSmall = function() return { Utils.Random(AtreidesSmallTankTypes) } end local tanksToBuildAtreidesSmall = function() return { Utils.Random(AtreidesSmallTankTypes) } end
local tanksToBuildCorrinoMain = function() return { Utils.Random(CorrinoMainTankTypes) } end
local tanksToBuildCorrinoMain = function()
if EarlyGameStage >= DateTime.GameTime then
return { Utils.Random(CorrinoMainTankTypes["EarlyGame"]) }
else
return { Utils.Random(CorrinoMainTankTypes["LateGame"]) }
end
end
local tanksToBuildCorrinoSmall = function() return { Utils.Random(CorrinoSmallTankTypes) } end local tanksToBuildCorrinoSmall = function() return { Utils.Random(CorrinoSmallTankTypes) } end
local unitsToBuyAtreides = function() return { Utils.Random(AtreidesStarportTypes) } end local attackThresholdSize = AttackGroupSize[Difficulty] * 3
local unitsToBuyCorrino = function() return { Utils.Random(CorrinoStarportTypes) } end local attackThresholdSizeCorrino = AttackGroupSize[Difficulty] * 4
local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5 local attackThresholdSizeSmallBase = AttackGroupSize[Difficulty] * 2
Trigger.AfterDelay(InitialProductionDelay["AtreidesMain"][Difficulty], function ()
ProduceUnits(AtreidesMain, ABarracks1, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
ProduceUnits(AtreidesMain, ALightFactory1, delay, vehiclesToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
ProduceUnits(AtreidesMain, AHeavyFactory1, delay, tanksToBuildAtreidesMain, AttackGroupSize[Difficulty], attackThresholdSize)
--ProduceUnits(AtreidesMain, AStarport, delay, unitsToBuyAtreides, AttackGroupSize[Difficulty], AttackThresholdSize)
end)
ProduceUnits(AtreidesMain, ABarracks1, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize) Trigger.AfterDelay(InitialProductionDelay["AtreidesSmall"][Difficulty], function ()
ProduceUnits(AtreidesMain, ALightFactory1, delay, vehilcesToBuild, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(AtreidesSmall1, ABarracks3, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSizeSmallBase)
ProduceUnits(AtreidesMain, AHeavyFactory1, delay, tanksToBuildAtreidesMain, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(AtreidesSmall1, ALightFactory2, delay, vehiclesToBuild, AttackGroupSize[Difficulty], attackThresholdSizeSmallBase)
ProduceUnits(AtreidesMain, AStarport, delay, unitsToBuyAtreides, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(AtreidesSmall1, AHeavyFactory2, delay, tanksToBuildAtreidesSmall, AttackGroupSize[Difficulty], attackThresholdSizeSmallBase)
end)
ProduceUnits(AtreidesSmall1, ABarracks3, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(AtreidesSmall2, ABarracks4, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSizeSmallBase)
ProduceUnits(AtreidesSmall1, ALightFactory2, delay, vehilcesToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
ProduceUnits(AtreidesSmall1, AHeavyFactory2, delay, tanksToBuildAtreidesSmall, AttackGroupSize[Difficulty], attackThresholdSize)
ProduceUnits(AtreidesSmall2, ABarracks4, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize) Trigger.AfterDelay(InitialProductionDelay["CorrinoMain"][Difficulty], function ()
ProduceUnits(CorrinoMain, CBarracks1, delay, infantryToBuildCorrinoMain, AttackGroupSize[Difficulty], attackThresholdSizeCorrino)
ProduceUnits(CorrinoMain, CLightFactory1, delay, vehiclesToBuild, AttackGroupSize[Difficulty], attackThresholdSizeCorrino)
ProduceUnits(CorrinoMain, CHeavyFactory1, delay, tanksToBuildCorrinoMain, AttackGroupSize[Difficulty], attackThresholdSizeCorrino)
--ProduceUnits(CorrinoMain, CStarport, delay, unitsToBuyCorrino, AttackGroupSize[Difficulty], AttackThresholdSize)
end)
ProduceUnits(CorrinoMain, CBarracks1, delay, infantryToBuildCorrinoMain, AttackGroupSize[Difficulty], attackThresholdSize) Trigger.AfterDelay(InitialProductionDelay["CorrinoSmall"][Difficulty], function ()
ProduceUnits(CorrinoMain, CLightFactory1, delay, vehilcesToBuild, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(CorrinoSmall, CBarracks2, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSizeSmallBase)
ProduceUnits(CorrinoMain, CHeavyFactory1, delay, tanksToBuildCorrinoMain, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(CorrinoSmall, CLightFactory2, delay, vehiclesToBuild, AttackGroupSize[Difficulty], attackThresholdSizeSmallBase)
ProduceUnits(CorrinoMain, CStarport, delay, unitsToBuyCorrino, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(CorrinoSmall, CHeavyFactory2, delay, tanksToBuildCorrinoSmall, AttackGroupSize[Difficulty], attackThresholdSizeSmallBase)
end)
ProduceUnits(CorrinoSmall, CBarracks2, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize) local crusherTypes = { "combat_tank_a", "combat_tank_a.starport", "combat_tank_h", "combat_tank_h.starport" }
ProduceUnits(CorrinoSmall, CLightFactory2, delay, vehilcesToBuild, AttackGroupSize[Difficulty], attackThresholdSize) local crusherFactories = { AStarport, AHeavyFactory1, AHeavyFactory2, CHeavyFactory1, CHeavyFactory2, CStarport }
ProduceUnits(CorrinoSmall, CHeavyFactory2, delay, tanksToBuildCorrinoSmall, AttackGroupSize[Difficulty], attackThresholdSize) ActivateCrusherLogic(crusherTypes, crusherFactories)
if Difficulty == "normal" then
AtreidesMain.GrantCondition("base-rebuilder")
AtreidesSmall1.GrantCondition("base-rebuilder2")
CorrinoSmall.GrantCondition("base-rebuilder3")
end
if Difficulty == "hard" then
AtreidesMain.GrantCondition("defense-rebuilder")
AtreidesSmall1.GrantCondition("defense-rebuilder2")
CorrinoSmall.GrantCondition("defense-rebuilder3")
end
local productionTypesAtreidis =
{
barracks = infantryToBuild,
light_factory = vehiclesToBuild,
heavy_factory = tanksToBuildAtreidesMain
}
local productionTypesCorrino =
{
barracks = infantryToBuild,
light_factory = vehiclesToBuild,
heavy_factory = tanksToBuildCorrinoSmall
}
Trigger.OnBuildingPlaced(AtreidesMain, function(p, building)
table.insert(AtreidesMainBase, building)
DefendAndRepairBase(AtreidesMain, {building}, 0.5, AttackGroupSize[Difficulty] )
if productionTypesAtreidis[building.Type] == nil then return end
ProduceUnits(AtreidesMain, building, delay, productionTypesAtreidis[building.Type], AttackGroupSize[Difficulty], attackThresholdSize)
end)
Trigger.OnBuildingPlaced(AtreidesSmall1, function(p, building)
table.insert(AtreidesSmallBase, building)
DefendAndRepairBase(AtreidesSmall1, {building}, 0.5, AttackGroupSize[Difficulty] )
if productionTypesAtreidis[building.Type] == nil then return end
ProduceUnits(AtreidesSmall1, building, delay, productionTypesAtreidis[building.Type], AttackGroupSize[Difficulty], attackThresholdSize)
end)
Trigger.OnBuildingPlaced(CorrinoMain, function(p, building)
table.insert(CorrinoMainBase, building)
DefendAndRepairBase(CorrinoMain, {building}, 0.5, AttackGroupSize[Difficulty] )
if productionTypesCorrino[building.Type] == nil then return end
ProduceUnits(CorrinoMain, building, delay, productionTypesCorrino[building.Type], AttackGroupSize[Difficulty], attackThresholdSize)
end)
end end

View File

@@ -8,9 +8,13 @@
]] ]]
AtreidesMainBase = { AConYard1, AOutpost1, APalace, ARefinery1, ARefinery2, ARefinery3, AHeavyFactory1, ALightFactory1, AStarport, AHiTechFactory, AResearch, AGunt1, AGunt2, AGunt3, AGunt4, AGunt5, ARock1, ARock2, ARock3, ARock4, ABarracks1, ABarracks2, APower1, APower2, APower3, APower4, APower5, APower6, APower7, APower8, APower9, APower10, APower11, APower12, APower13, APower14 } AtreidesMainBase = { AConYard1, AOutpost1, APalace, ARefinery1, ARefinery2, ARefinery3, AHeavyFactory1, ALightFactory1, AStarport, AHiTechFactory, AResearch, AGunt1, AGunt2, AGunt3, AGunt4, AGunt5, ARock1, ARock2, ARock3, ARock4, ABarracks1, ABarracks2, APower1, APower2, APower3, APower4, APower5, APower6, APower7, APower8, APower9, APower10, APower11, APower12, APower13, APower14 }
AtreidesSmall1Base = { AConYard2, ARefinery4, ABarracks3, AHeavyFactory2, ALightFactory2, ARepair, ARock5, ARock6, ARock7, ARock8, ARock9, APower15, APower16, APower17, APower18, APower19, APower20, APower21 } AtreidesSmall1Base = { AConYard2, ARefinery4, ABarracks3, AHeavyFactory2, ALightFactory2, ARepair, ARock5, ARock6, ARock7, ARock8, ARock9, APower15, APower16, APower17, APower18, APower19, APower20, APower21 }
AtreidesSmall2Base = { AOutpost2, ABarracks4, AGunt6, AGunt7, AGunt8, ARock10, APower22, APower23 } AtreidesSmall2Base = { AOutpost2, ABarracks4, AGunt6, AGunt7, AGunt8, ARock10, APower22, APower23 }
CorrinoMainBase = { COutpost, CPalace, CRefinery1, CHeavyFactory1, CLightFactory1, CStarport, CResearch, CGunt1, CGunt2, CRock1, CRock2, CBarracks1, CPower1, CPower2, CPower3, CPower4, CPower5, CPower6, CPower7 } CorrinoMainBase = { COutpost, CPalace, CRefinery1, CHeavyFactory1, CLightFactory1, CStarport, CResearch, CGunt1, CGunt2, CRock1, CRock2, CBarracks1, CPower1, CPower2, CPower3, CPower4, CPower5, CPower6, CPower7 }
CorrinoSmallBase = { CConYard, CRefinery2, CHeavyFactory2, CLightFactory2, CRock3, CRock4, CBarracks2, CPower8, CPower9, CPower10, CPower11 } CorrinoSmallBase = { CConYard, CRefinery2, CHeavyFactory2, CLightFactory2, CRock3, CRock4, CBarracks2, CPower8, CPower9, CPower10, CPower11 }
AtreidesReinforcements = AtreidesReinforcements =
@@ -131,9 +135,13 @@ InitialCorrinoPaths =
{ CorrinoEntry2.Location, CorrinoRally2.Location } { CorrinoEntry2.Location, CorrinoRally2.Location }
} }
HarkonnenReinforcements = { "combat_tank_h", "combat_tank_h", "siege_tank", "siege_tank", "missile_tank" } HarkonnenReinforcements = {
{ "combat_tank_h", "combat_tank_h", "siege_tank", "siege_tank", "missile_tank" },
HarkonnenPath = { HarkonnenEntry.Location, HarkonnenRally.Location } { "trooper", "light_inf", "light_inf", "light_inf", "trooper", "light_inf", "trooper", "light_inf", "trooper", "light_inf", "trooper" },
{ "trooper", "light_inf", "quad", "trike", "quad" },
{ "devastator", "light_inf", "quad", "trike", "quad" },
{ "trooper", "combat_tank_h", "combat_tank_h", "combat_tank_h", "quad" }
}
SendStarportReinforcements = function() SendStarportReinforcements = function()
Trigger.AfterDelay(CorrinoStarportDelay[Difficulty], function() Trigger.AfterDelay(CorrinoStarportDelay[Difficulty], function()
@@ -142,7 +150,6 @@ SendStarportReinforcements = function()
end end
local reinforcements = Utils.Random(CorrinoStarportReinforcements[Difficulty]) local reinforcements = Utils.Random(CorrinoStarportReinforcements[Difficulty])
local units = Reinforcements.ReinforceWithTransport(CorrinoMain, "frigate", reinforcements, { CorrinoStarportEntry.Location, CStarport.Location + CVec.New(1, 1) }, { CorrinoStarportExit.Location })[2] local units = Reinforcements.ReinforceWithTransport(CorrinoMain, "frigate", reinforcements, { CorrinoStarportEntry.Location, CStarport.Location + CVec.New(1, 1) }, { CorrinoStarportExit.Location })[2]
Utils.Do(units, function(unit) Utils.Do(units, function(unit)
unit.AttackMove(AtreidesAttackLocation) unit.AttackMove(AtreidesAttackLocation)
@@ -153,23 +160,56 @@ SendStarportReinforcements = function()
end) end)
end end
SendHarkonnenReinforcements = function(delay) HarkonnenPaths =
{
{ HarkonnenEntry.Location, HarkonnenRally.Location },
{ AtreidesEntry3.Location, HarkonnenRally1.Location },
{ HarkonnenEntry.Location, HarkonnenRally2.Location },
{ AtreidesEntry3.Location, AtreidesRally3.Location },
{ HarkonnenRally3.Location, AtreidesRally9.Location },
{ HarkonnenRally4.Location, AtreidesRally8.Location }
}
SendHarkonnenReinforcements = function(delay, number)
Trigger.AfterDelay(delay, function() Trigger.AfterDelay(delay, function()
Reinforcements.ReinforceWithTransport(Harkonnen, "carryall.reinforce", HarkonnenReinforcements, HarkonnenPath, { HarkonnenPath[1] }) Reinforcements.ReinforceWithTransport(Harkonnen, "carryall.reinforce", HarkonnenReinforcements[number], HarkonnenPaths[number], { HarkonnenPaths[number][1] })
Trigger.AfterDelay(DateTime.Seconds(5), function() Trigger.AfterDelay(DateTime.Seconds(5), function()
Media.PlaySpeechNotification(Harkonnen, "Reinforce") Media.PlaySpeechNotification(Harkonnen, "Reinforce")
end) end)
end) end)
end end
SendAirStrike = function() AirStrikeTimer = 7500
if AHiTechFactory.IsDead or AHiTechFactory.Owner ~= AtreidesMain then AirStrikeChargeTime = 7500
AirstrikeLogic = function(airstrikeProvider)
if airstrikeProvider.IsDead then
return
end
if DateTime.GameTime <= AirStrikeTimer then
Trigger.AfterDelay(AirStrikeTimer - DateTime.GameTime + 1, function()
AirstrikeLogic(airstrikeProvider)
end)
return
end
-- randomly choose if wait again or strike. During waiting Airstrike can still be used by DefensiveAirStrike
if Utils.RandomInteger(1, 100) < 30 then
Trigger.AfterDelay(1000, function() AirstrikeLogic(airstrikeProvider)end)
else
AirStrikeVSBuilding(airstrikeProvider)
Trigger.AfterDelay(7500, function() AirstrikeLogic(airstrikeProvider) end)
IsAirstrikeReady = false
end
end
AirStrikeVSBuilding = function(airstrikeProvider)
if airstrikeProvider.IsDead or DateTime.GameTime < AirStrikeTimer then
return return
end end
local targets = Utils.Where(Harkonnen.GetActors(), function(actor) local targets = Utils.Where(Harkonnen.GetActors(), function(actor)
return return actor.HasProperty("Sell") and
actor.HasProperty("Sell") and
actor.Type ~= "wall" and actor.Type ~= "wall" and
actor.Type ~= "medium_gun_turret" and actor.Type ~= "medium_gun_turret" and
actor.Type ~= "large_gun_turret" and actor.Type ~= "large_gun_turret" and
@@ -178,12 +218,86 @@ SendAirStrike = function()
end) end)
if #targets > 0 then if #targets > 0 then
AHiTechFactory.TargetAirstrike(Utils.Random(targets).CenterPosition) airstrikeProvider.TargetAirstrike(Utils.Random(targets).CenterPosition)
AirStrikeTimer = DateTime.GameTime + AirStrikeChargeTime
end
end
DefensiveAirStrike = function(airstrikeProvider, possibleTargets)
if airstrikeProvider.IsDead or DateTime.GameTime <= AirStrikeTimer then return end
local bestValue = {}
local bestIndex = 1
for i = 1, #possibleTargets, 1 do
local ActorsInCircle = Map.ActorsInCircle(possibleTargets[i].CenterPosition, WDist.FromCells(4), function(a)
return a.Owner == Harkonnen
and not a.IsDead
and a.HasProperty("Attack")
end)
bestValue[i] = 0
Utils.Do(ActorsInCircle, function(a)
bestValue[i] = bestValue[i] + Actor.Cost(a.Type)
end)
if bestValue[i] > bestValue[bestIndex] then
bestIndex = i
end
end
airstrikeProvider.TargetAirstrike(possibleTargets[bestIndex].CenterPosition)
AirStrikeTimer = DateTime.GameTime + AirStrikeChargeTime
end
EmergencyBehaviour = function(player,target)
if player == AtreidesMain or player == AtreidesSmall1 then
if AHiTechFactory.IsDead then return end
local enemyunits = Map.ActorsInCircle(Map.CenterOfCell(target), WDist.FromCells(15), function(a)
return a.Owner == Harkonnen
and not a.IsDead
and a.HasProperty("Attack")
end)
if enemyunits[1] == nil then return end
DefensiveAirStrike(AHiTechFactory, enemyunits)
end end
Trigger.AfterDelay(DateTime.Minutes(5), SendAirStrike) if player == AtreidesSmall1 and #IdlingUnits[AtreidesMain] > 10 then
local reinforcements = SetupAttackGroup(AtreidesMain, Utils.RandomInteger(10, #IdlingUnits[AtreidesMain]))
Utils.Do(reinforcements, function(unit)
Trigger.ClearAll(unit)
Trigger.AfterDelay(1, function()
unit.Stop()
unit.Move(CorrinoPatrolPoint1.Location,1)
unit.AttackMove(target)
unit.CallFunc(function()
FindTargetsInArea(player, unit)
end)
end)
end)
end
if player == AtreidesSmall2 and #IdlingUnits[AtreidesMain] > 10 then
CheckArea(AtreidesMain, target, 10)
end
end end
ReleaseSardaukars = true
Trigger.OnDamaged(CPalace, function(self)
if self.Health < self.MaxHealth * 0.8 and ReleaseSardaukars then
local index = 0
while index < 100 do
index = index + 5
Trigger.AfterDelay(index,function()
if self.IsDead then return end
local actor = Actor.Create("sardaukar", true, { Owner = CorrinoMain, Location = CPalace.Location + CVec.New(1,2) })
actor.Move(CPos.New(3,31))
IdlingUnits[CorrinoMain][#IdlingUnits[CorrinoMain] + 1] = actor
end)
end
ReleaseSardaukars = false
end
end)
BuildFremen = function() BuildFremen = function()
if APalace.IsDead or APalace.Owner ~= AtreidesMain then if APalace.IsDead or APalace.Owner ~= AtreidesMain then
return return
@@ -194,7 +308,6 @@ BuildFremen = function()
Trigger.AfterDelay(DateTime.Seconds(5), function() Trigger.AfterDelay(DateTime.Seconds(5), function()
IdleFremen = Utils.Where(AtreidesMain.GetActorsByType('fremen'), function(actor) return actor.IsIdle end) IdleFremen = Utils.Where(AtreidesMain.GetActorsByType('fremen'), function(actor) return actor.IsIdle end)
if #IdleFremen >= FremenGroupSize[Difficulty] then if #IdleFremen >= FremenGroupSize[Difficulty] then
SendFremen() SendFremen()
end end
@@ -231,7 +344,6 @@ Tick = function()
if DateTime.GameTime % DateTime.Seconds(10) == 0 and LastHarvesterEaten[AtreidesMain] then if DateTime.GameTime % DateTime.Seconds(10) == 0 and LastHarvesterEaten[AtreidesMain] then
local units = AtreidesMain.GetActorsByType("harvester") local units = AtreidesMain.GetActorsByType("harvester")
if #units > 0 then if #units > 0 then
LastHarvesterEaten[AtreidesMain] = false LastHarvesterEaten[AtreidesMain] = false
ProtectHarvester(units[1], AtreidesMain, AttackGroupSize[Difficulty]) ProtectHarvester(units[1], AtreidesMain, AttackGroupSize[Difficulty])
@@ -240,7 +352,6 @@ Tick = function()
if DateTime.GameTime % DateTime.Seconds(10) == 0 and LastHarvesterEaten[AtreidesSmall1] then if DateTime.GameTime % DateTime.Seconds(10) == 0 and LastHarvesterEaten[AtreidesSmall1] then
local units = AtreidesSmall1.GetActorsByType("harvester") local units = AtreidesSmall1.GetActorsByType("harvester")
if #units > 0 then if #units > 0 then
LastHarvesterEaten[AtreidesSmall1] = false LastHarvesterEaten[AtreidesSmall1] = false
ProtectHarvester(units[1], AtreidesSmall1, AttackGroupSize[Difficulty]) ProtectHarvester(units[1], AtreidesSmall1, AttackGroupSize[Difficulty])
@@ -249,7 +360,6 @@ Tick = function()
if DateTime.GameTime % DateTime.Seconds(10) == 0 and LastHarvesterEaten[CorrinoMain] then if DateTime.GameTime % DateTime.Seconds(10) == 0 and LastHarvesterEaten[CorrinoMain] then
local units = CorrinoMain.GetActorsByType("harvester") local units = CorrinoMain.GetActorsByType("harvester")
if #units > 0 then if #units > 0 then
LastHarvesterEaten[CorrinoMain] = false LastHarvesterEaten[CorrinoMain] = false
ProtectHarvester(units[1], CorrinoMain, AttackGroupSize[Difficulty]) ProtectHarvester(units[1], CorrinoMain, AttackGroupSize[Difficulty])
@@ -258,7 +368,6 @@ Tick = function()
if DateTime.GameTime % DateTime.Seconds(10) == 0 and LastHarvesterEaten[CorrinoSmall] then if DateTime.GameTime % DateTime.Seconds(10) == 0 and LastHarvesterEaten[CorrinoSmall] then
local units = CorrinoSmall.GetActorsByType("harvester") local units = CorrinoSmall.GetActorsByType("harvester")
if #units > 0 then if #units > 0 then
LastHarvesterEaten[CorrinoSmall] = false LastHarvesterEaten[CorrinoSmall] = false
ProtectHarvester(units[1], CorrinoSmall, AttackGroupSize[Difficulty]) ProtectHarvester(units[1], CorrinoSmall, AttackGroupSize[Difficulty])
@@ -286,8 +395,8 @@ WorldLoaded = function()
Camera.Position = HMCV.CenterPosition Camera.Position = HMCV.CenterPosition
AtreidesAttackLocation = HarkonnenRally.Location AtreidesAttackLocation = HarkonnenRally.Location
Trigger.AfterDelay(DateTime.Minutes(5), SendAirStrike) Trigger.AfterDelay(DateTime.Minutes(10), function() AirstrikeLogic(AHiTechFactory) end )
Trigger.AfterDelay(DateTime.Minutes(1) + DateTime.Seconds (30), BuildFremen) Trigger.AfterDelay(DateTime.Minutes(3) + DateTime.Seconds (30), BuildFremen)
Trigger.OnAllKilledOrCaptured(AtreidesMainBase, function() Trigger.OnAllKilledOrCaptured(AtreidesMainBase, function()
Utils.Do(AtreidesMain.GetGroundAttackers(), IdleHunt) Utils.Do(AtreidesMain.GetGroundAttackers(), IdleHunt)
@@ -315,8 +424,8 @@ WorldLoaded = function()
unit.AttackMove(AtreidesAttackLocation) unit.AttackMove(AtreidesAttackLocation)
IdleHunt(unit) IdleHunt(unit)
end end
SendCarryallReinforcements(AtreidesMain, 0, AtreidesAttackWaves[Difficulty], AtreidesAttackDelay[Difficulty], path, AtreidesReinforcements[Difficulty], waveCondition, huntFunction)
SendCarryallReinforcements(AtreidesMain, 0, AtreidesAttackWaves[Difficulty], AtreidesAttackDelay[Difficulty], path, AtreidesReinforcements[Difficulty], waveCondition, huntFunction)
SendStarportReinforcements() SendStarportReinforcements()
Actor.Create("upgrade.barracks", true, { Owner = AtreidesMain }) Actor.Create("upgrade.barracks", true, { Owner = AtreidesMain })
@@ -335,5 +444,19 @@ WorldLoaded = function()
Actor.Create("upgrade.heavy", true, { Owner = CorrinoSmall }) Actor.Create("upgrade.heavy", true, { Owner = CorrinoSmall })
Trigger.AfterDelay(0, ActivateAI) Trigger.AfterDelay(0, ActivateAI)
SendHarkonnenReinforcements(DateTime.Minutes(2) + DateTime.Seconds(30)) SendHarkonnenReinforcements(DateTime.Minutes(2) + DateTime.Seconds(30), 1)
SendHarkonnenReinforcements(17030,2)
SendHarkonnenReinforcements(17020,3)
Trigger.OnAllKilled({ARock6, ARock7, ARock8}, function()
SendHarkonnenReinforcements(0,4)
SendHarkonnenReinforcements(10,5)
end)
end end
Trigger.OnDamaged(DebrisHarvester2, function(self)
if self.Health < self.MaxHealth * 0.6 then
self.Deploy()
Trigger.ClearAll(self)
end
end)

Binary file not shown.

View File

@@ -562,9 +562,6 @@ Actors:
ARock4: large_gun_turret ARock4: large_gun_turret
Location: 54,27 Location: 54,27
Owner: Atreides Main Base Owner: Atreides Main Base
CPalace: palace
Location: 2,28
Owner: Corrino Main Base
Actor161: wall Actor161: wall
Location: 49,28 Location: 49,28
Owner: Atreides Main Base Owner: Atreides Main Base
@@ -844,6 +841,7 @@ Actors:
ARock6: large_gun_turret ARock6: large_gun_turret
Location: 47,62 Location: 47,62
Owner: Atreides Small Base 1 Owner: Atreides Small Base 1
TurretFacing: 512
AHeavyFactory2: heavy_factory AHeavyFactory2: heavy_factory
Location: 36,63 Location: 36,63
Owner: Atreides Small Base 1 Owner: Atreides Small Base 1
@@ -862,12 +860,10 @@ Actors:
ARock7: large_gun_turret ARock7: large_gun_turret
Location: 44,66 Location: 44,66
Owner: Atreides Small Base 1 Owner: Atreides Small Base 1
TurretFacing: 512
APower21: wind_trap APower21: wind_trap
Location: 38,67 Location: 38,67
Owner: Atreides Small Base 1 Owner: Atreides Small Base 1
ARock8: large_gun_turret
Location: 44,67
Owner: Atreides Small Base 1
ABarracks3: barracks ABarracks3: barracks
Location: 36,68 Location: 36,68
Owner: Atreides Small Base 1 Owner: Atreides Small Base 1
@@ -967,18 +963,12 @@ Actors:
AtreidesRally1: waypoint AtreidesRally1: waypoint
Owner: Neutral Owner: Neutral
Location: 96,87 Location: 96,87
AtreidesEntry1: waypoint
Owner: Neutral
Location: 97,87
AtreidesRally2: waypoint AtreidesRally2: waypoint
Owner: Neutral Owner: Neutral
Location: 76,93 Location: 76,93
AtreidesEntry2: waypoint AtreidesEntry2: waypoint
Owner: Neutral Owner: Neutral
Location: 76,97 Location: 76,97
AtreidesRally3: waypoint
Owner: Neutral
Location: 63,65
AtreidesEntry3: waypoint AtreidesEntry3: waypoint
Owner: Neutral Owner: Neutral
Location: 97,65 Location: 97,65
@@ -1042,6 +1032,85 @@ Actors:
CorrinoStarportExit: waypoint CorrinoStarportExit: waypoint
Owner: Neutral Owner: Neutral
Location: 2,13 Location: 2,13
AtreidesPatrolPoint2: waypoint
Owner: Neutral
Location: 16,63
AtreidesPatrolPoint3: waypoint
Owner: Neutral
Location: 62,47
AtreidesPatrolPoint4: waypoint
Owner: Neutral
Location: 72,28
CorrinoPatrolPoint1: waypoint
Owner: Neutral
Location: 13,39
CorrinoPatrolPoint2: waypoint
Owner: Neutral
Location: 32,29
AtreidesPatrolPoint5: waypoint
Owner: Neutral
Location: 44,42
CorrinoPatrolPoint3: waypoint
Owner: Neutral
Location: 72,50
Actor5: combat_tank_a.debris
Owner: Creeps
Facing: 384
Location: 93,53
Actor8: frigate.debris
Owner: Creeps
Location: 86,54
Actor1: harvester.debris
Owner: Creeps
Facing: 384
Location: 77,63
Actor9: carryall.debris
Owner: Creeps
Facing: 384
Location: 48,75
Actor6: siege_tank.debris
Owner: Creeps
Facing: 384
Location: 92,58
Actor10: combat_tank_h.debris
Owner: Creeps
Facing: 384
Location: 88,54
HarkonnenRally1: waypoint
Owner: Neutral
Location: 74,71
HarkonnenRally2: waypoint
Owner: Neutral
Location: 68,79
AtreidesEntry1: waypoint
Owner: Neutral
Location: 97,87
Actor11: crate
Owner: Neutral
Location: 6,76
ARock8: large_gun_turret
Owner: Atreides Small Base 1
Location: 44,67
TurretFacing: 512
HarkonnenRally4: waypoint
Owner: Neutral
Location: 97,57
HarkonnenRally3: waypoint
Owner: Neutral
Location: 97,70
AtreidesRally3: waypoint
Owner: Neutral
Location: 51,65
AtreidesPatrolPoint1: waypoint
Owner: Neutral
Location: 46,84
DebrisHarvester2: harvester.debris
Owner: Creeps
Facing: 384
Location: 58,39
CPalace: palace
Owner: Corrino Main Base
Location: 2,26
Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml

View File

@@ -1,6 +1,204 @@
Player: Player:
PlayerResources: PlayerResources:
DefaultCash: 7000 DefaultCash: 7000
ExternalCondition@AIAMail:
Condition: base-rebuilder
ExternalCondition@AIASmall:
Condition: base-rebuilder2
ExternalCondition@AICSmall:
Condition: base-rebuilder3
ExternalCondition@AIAMail-defense:
Condition: defense-rebuilder
ExternalCondition@AIASmall-defense:
Condition: defense-rebuilder2
ExternalCondition@AICSmall-defense:
Condition: defense-rebuilder3
BaseBuilderBotModule@AIAMainBase:
RequiresCondition: base-rebuilder
BuildingQueues: Building, Upgrade
MinimumExcessPower: 0
MaximumExcessPower: 250
MaxBaseRadius: 40
ConstructionYardTypes: construction_yard
RefineryTypes: refinery
PowerTypes: wind_trap
ProductionTypes: light_factory, heavy_factory, barracks, starport
SiloTypes: silo
DefenseTypes: medium_gun_turret,large_gun_turret
SellRefineryInterval: -1
BuildingLimits:
barracks: 1
refinery: 3
outpost: 1
light_factory: 1
starport: 1
palace: 1
heavy_factory: 1
high_tech_factory: 1
wind_trap: 11
silo: 1
BuildingFractions:
wind_trap: 1
barracks: 1
refinery: 1
outpost: 1
starport: 1
high_tech_factory: 1
palace: 1
light_factory: 1
heavy_factory: 1
BaseBuilderBotModule@AIASmallBase:
RequiresCondition: base-rebuilder2
BuildingQueues: Building, Upgrade
MinimumExcessPower: 0
MaximumExcessPower: 250
MaxBaseRadius: 40
ConstructionYardTypes: construction_yard
RefineryTypes: refinery
PowerTypes: wind_trap
ProductionTypes: light_factory, heavy_factory, barracks, starport
SiloTypes: silo
DefenseTypes: medium_gun_turret,large_gun_turret
SellRefineryInterval: -1
BuildingLimits:
barracks: 1
refinery: 1
outpost: 1
light_factory: 1
palace: 1
heavy_factory: 1
wind_trap: 7
silo: 1
BuildingFractions:
wind_trap: 1
barracks: 1
refinery: 1
outpost: 1
light_factory: 1
heavy_factory: 1
BaseBuilderBotModule@AIAMainCorrino:
RequiresCondition: base-rebuilder3
BuildingQueues: Building, Upgrade
MinimumExcessPower: 0
MaximumExcessPower: 250
MaxBaseRadius: 40
ConstructionYardTypes: construction_yard
RefineryTypes: refinery
PowerTypes: wind_trap
ProductionTypes: light_factory, heavy_factory, barracks, starport
SiloTypes: silo
DefenseTypes: medium_gun_turret,large_gun_turret
SellRefineryInterval: -1
BuildingLimits:
barracks: 1
refinery: 3
outpost: 1
light_factory: 1
heavy_factory: 1
wind_trap: 4
silo: 1
BuildingFractions:
wind_trap: 1
barracks: 1
refinery: 1
outpost: 1
light_factory: 1
heavy_factory: 1
BaseBuilderBotModule@AIAMainDefense:
RequiresCondition: defense-rebuilder
BuildingQueues: Building, Upgrade
MinimumExcessPower: 0
MaximumExcessPower: 250
MaxBaseRadius: 40
ConstructionYardTypes: construction_yard
RefineryTypes: refinery
PowerTypes: wind_trap
ProductionTypes: light_factory, heavy_factory, barracks, starport
SiloTypes: silo
DefenseTypes: medium_gun_turret,large_gun_turret
SellRefineryInterval: -1
BuildingLimits:
barracks: 1
refinery: 3
outpost: 1
light_factory: 1
starport: 1
palace: 1
heavy_factory: 1
high_tech_factory: 1
wind_trap: 11
silo: 1
medium_gun_turret: 5
large_gun_turret: 4
BuildingFractions:
wind_trap: 1
barracks: 1
refinery: 1
outpost: 1
starport: 1
high_tech_factory: 1
palace: 1
light_factory: 1
heavy_factory: 1
medium_gun_turret: 1
large_gun_turret: 1
BaseBuilderBotModule@AIASmallDefense:
RequiresCondition: defense-rebuilder2
BuildingQueues: Building, Upgrade
MinimumExcessPower: 0
MaximumExcessPower: 250
MaxBaseRadius: 40
ConstructionYardTypes: construction_yard
RefineryTypes: refinery
PowerTypes: wind_trap
ProductionTypes: light_factory, heavy_factory, barracks
SiloTypes: silo
DefenseTypes: large_gun_turret
SellRefineryInterval: -1
BuildingLimits:
barracks: 1
refinery: 1
light_factory: 1
palace: 1
heavy_factory: 1
wind_trap: 7
silo: 1
large_gun_turret: 5
BuildingFractions:
wind_trap: 1
barracks: 1
refinery: 1
light_factory: 1
heavy_factory: 1
large_gun_turret: 1
BaseBuilderBotModule@AISmallCorrino:
RequiresCondition: defense-rebuilder3
BuildingQueues: Building, Upgrade
MinimumExcessPower: 0
MaximumExcessPower: 250
MaxBaseRadius: 40
ConstructionYardTypes: construction_yard
RefineryTypes: refinery
PowerTypes: wind_trap
ProductionTypes: light_factory, heavy_factory, barracks, starport
SiloTypes: silo
DefenseTypes: medium_gun_turret,large_gun_turret
SellRefineryInterval: -1
BuildingLimits:
barracks: 1
refinery: 1
light_factory: 1
heavy_factory: 1
wind_trap: 4
silo: 1
large_gun_turret: 2
BuildingFractions:
wind_trap: 1
barracks: 1
refinery: 1
light_factory: 1
heavy_factory: 1
large_gun_turret: 2
World: World:
LuaScript: LuaScript:

View File

@@ -7,6 +7,38 @@
information, see COPYING. information, see COPYING.
]] ]]
EarlyGameStage = DateTime.Minutes(7)
InitialProductionDelay = {
AtreidesMain =
{
easy = DateTime.Seconds(180),
normal = DateTime.Seconds(120),
hard = DateTime.Seconds(60)
},
AtreidesSmall =
{
easy = DateTime.Seconds(120),
normal = DateTime.Seconds(60),
hard = DateTime.Seconds(0)
},
CorrinoMain =
{
easy = DateTime.Seconds(160),
normal = DateTime.Seconds(120),
hard = DateTime.Seconds(80)
},
CorrinoSmall =
{
easy = DateTime.Seconds(80),
normal = DateTime.Seconds(60),
hard = DateTime.Seconds(30)
}
}
AttackGroupSize = AttackGroupSize =
{ {
easy = 6, easy = 6,
@@ -14,25 +46,81 @@ AttackGroupSize =
hard = 10 hard = 10
} }
AttackDelays = EarlyProductionDelays =
{
easy = { DateTime.Seconds(9), DateTime.Seconds(12) },
normal = { DateTime.Seconds(6), DateTime.Seconds(8) },
hard = { DateTime.Seconds(4), DateTime.Seconds(7) }
}
LateProductionDelays =
{ {
easy = { DateTime.Seconds(4), DateTime.Seconds(7) }, easy = { DateTime.Seconds(4), DateTime.Seconds(7) },
normal = { DateTime.Seconds(2), DateTime.Seconds(5) }, normal = { DateTime.Seconds(2), DateTime.Seconds(5) },
hard = { DateTime.Seconds(1), DateTime.Seconds(3) } hard = { DateTime.Seconds(1), DateTime.Seconds(3) }
} }
EnemyInfantryTypes = { "light_inf", "light_inf", "light_inf", "trooper", "trooper" } EnemyInfantryTypes = { "light_inf", "light_inf", "light_inf", "trooper", "trooper" }
EnemyVehicleTypes = { "trike", "trike", "quad" } EnemyVehicleTypes = { "trike", "trike", "quad" }
AtreidesMainTankTypes = { "combat_tank_a", "combat_tank_a", "siege_tank", "missile_tank", "sonic_tank" } AtreidesMainTankTypes = {
EarlyGame = { "combat_tank_a", "combat_tank_a", "siege_tank", "missile_tank" },
LateGame = { "combat_tank_a", "combat_tank_a", "siege_tank", "missile_tank", "sonic_tank" }
}
AtreidesSmallTankTypes = { "combat_tank_a", "combat_tank_a", "siege_tank" } AtreidesSmallTankTypes = { "combat_tank_a", "combat_tank_a", "siege_tank" }
AtreidesStarportTypes = { "trike.starport", "trike.starport", "quad.starport", "combat_tank_a.starport", "combat_tank_a.starport", "siege_tank.starport", "missile_tank.starport" }
CorrinoMainInfantryTypes = { "light_inf", "light_inf", "trooper", "sardaukar" } CorrinoMainInfantryTypes = { "light_inf", "light_inf", "trooper", "sardaukar" }
CorrinoTankTypes = { "combat_tank_h", "combat_tank_h", "siege_tank", "missile_tank" }
CorrinoStarportTypes = { "trike.starport", "trike.starport", "quad.starport", "combat_tank_h.starport", "combat_tank_h.starport", "siege_tank.starport", "missile_tank.starport" } CorrinoTankTypes = {
EarlyGame = { "combat_tank_h" },
LateGame = { "combat_tank_h", "combat_tank_h", "siege_tank", "missile_tank" }
}
ActivateAI = function() ActivateAI = function()
Defending[AtreidesMain] = {}
Defending[AtreidesSmall] = {}
Defending[CorrinoMain] = {}
Defending[CorrinoSmall] = {}
-- this is also first attack timing
AttackDelay[AtreidesMain] = 15000 * DifficultyModifier[Difficulty]
AttackDelay[AtreidesSmall] = 10000 * DifficultyModifier[Difficulty]
AttackDelay[CorrinoMain] = 15000 * DifficultyModifier[Difficulty]
AttackDelay[CorrinoSmall] = 15000 * DifficultyModifier[Difficulty]
TimeBetweenAttacks[AtreidesMain] = 13000 * DifficultyModifier[Difficulty]
TimeBetweenAttacks[AtreidesSmall] = 4000 * DifficultyModifier[Difficulty]
TimeBetweenAttacks[CorrinoMain] = 8600 * DifficultyModifier[Difficulty]
TimeBetweenAttacks[CorrinoSmall] = 8600 * DifficultyModifier[Difficulty]
Trigger.OnKilledOrCaptured(AConYard1, function()
TimeBetweenAttacks[AtreidesMain] = 0
TimeBetweenAttacks[CorrinoMain] = 0
end)
Trigger.OnAllKilledOrCaptured(CorrinoMainBase, function()
TimeBetweenAttacks[CorrinoSmall] = 0
TimeBetweenAttacks[AtreidesMain] = 0
end)
Trigger.OnAllKilledOrCaptured(CorrinoSmallBase, function()
TimeBetweenAttacks[CorrinoMain] = 0
end)
HarvesterCount[AtreidesMain] = 4
HarvesterCount[AtreidesSmall] = 2
HarvesterCount[CorrinoMain] = 4
HarvesterCount[CorrinoSmall] = 1
PatrolPoints[AtreidesMain] = {APatrolPoint1.Location, APatrolPoint2.Location, APatrolPoint3.Location, APatrolPoint4.Location }
PatrolPoints[AtreidesSmall] = {APatrolPoint5.Location, APatrolPoint6.Location, APatrolPoint7.Location }
PatrolPoints[CorrinoMain] = {APatrolPoint7.Location, AtreidesRally5.Location, CPatrolPoint1.Location }
PatrolPoints[CorrinoSmall] = {CPatrolPoint2.Location, AtreidesRally4.Location, APatrolPoint4.Location }
DefencePerimeter[AtreidesMain] = GetCellsInRectangle(CPos.New(25,58), CPos.New(47,70))
DefencePerimeter[AtreidesSmall] = GetCellsInRectangle(CPos.New(103,5), CPos.New(119,18))
DefencePerimeter[CorrinoMain] = GetCellsInRectangle(CPos.New(65,38), CPos.New(91,55))
DefencePerimeter[CorrinoSmall] = GetCellsInRectangle(CPos.New(33,35), CPos.New(49,52))
IdlingUnits[AtreidesMain] = Utils.Concat(Reinforcements.Reinforce(AtreidesMain, InitialAtreidesReinforcements[1], InitialAtreidesPaths[1]), Reinforcements.Reinforce(AtreidesMain, InitialAtreidesReinforcements[2], InitialAtreidesPaths[2])) IdlingUnits[AtreidesMain] = Utils.Concat(Reinforcements.Reinforce(AtreidesMain, InitialAtreidesReinforcements[1], InitialAtreidesPaths[1]), Reinforcements.Reinforce(AtreidesMain, InitialAtreidesReinforcements[2], InitialAtreidesPaths[2]))
IdlingUnits[AtreidesSmall] = Reinforcements.Reinforce(AtreidesSmall, InitialAtreidesReinforcements[3], InitialAtreidesPaths[3]) IdlingUnits[AtreidesSmall] = Reinforcements.Reinforce(AtreidesSmall, InitialAtreidesReinforcements[3], InitialAtreidesPaths[3])
IdlingUnits[CorrinoMain] = Utils.Concat(Reinforcements.Reinforce(CorrinoMain, InitialCorrinoReinforcements[1], InitialCorrinoPaths[1]), Reinforcements.Reinforce(CorrinoMain, InitialCorrinoReinforcements[2], InitialCorrinoPaths[2])) IdlingUnits[CorrinoMain] = Utils.Concat(Reinforcements.Reinforce(CorrinoMain, InitialCorrinoReinforcements[1], InitialCorrinoPaths[1]), Reinforcements.Reinforce(CorrinoMain, InitialCorrinoReinforcements[2], InitialCorrinoPaths[2]))
@@ -43,31 +131,109 @@ ActivateAI = function()
DefendAndRepairBase(CorrinoMain, CorrinoMainBase, 0.75, AttackGroupSize[Difficulty]) DefendAndRepairBase(CorrinoMain, CorrinoMainBase, 0.75, AttackGroupSize[Difficulty])
DefendAndRepairBase(CorrinoSmall, CorrinoSmallBase, 0.75, AttackGroupSize[Difficulty]) DefendAndRepairBase(CorrinoSmall, CorrinoSmallBase, 0.75, AttackGroupSize[Difficulty])
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end local delay = function(player)
if EmergencyBuildRate[player] and Difficulty ~= "easy" then
return 1
end
if EarlyGameStage >= DateTime.GameTime then
return Utils.RandomInteger(EarlyProductionDelays[Difficulty][1], EarlyProductionDelays[Difficulty][2] + 1)
else
return Utils.RandomInteger(LateProductionDelays[Difficulty][1], LateProductionDelays[Difficulty][2] + 1)
end
end
local infantryToBuild = function() return { Utils.Random(EnemyInfantryTypes) } end local infantryToBuild = function() return { Utils.Random(EnemyInfantryTypes) } end
local infantryToBuildCorrinoMain = function() return { Utils.Random(CorrinoMainInfantryTypes) } end local infantryToBuildCorrinoMain = function() return { Utils.Random(CorrinoMainInfantryTypes) } end
local vehilcesToBuild = function() return { Utils.Random(EnemyVehicleTypes) } end local vehiclesToBuild = function() return { Utils.Random(EnemyVehicleTypes) } end
local tanksToBuildAtreidesMain = function() return { Utils.Random(AtreidesMainTankTypes) } end local tanksToBuildAtreidesMain = function()
if EarlyGameStage >= DateTime.GameTime then
return { Utils.Random(AtreidesMainTankTypes["EarlyGame"]) }
else
return { Utils.Random(AtreidesMainTankTypes["LateGame"]) }
end
end
local tanksToBuildAtreidesSmall = function() return { Utils.Random(AtreidesSmallTankTypes) } end local tanksToBuildAtreidesSmall = function() return { Utils.Random(AtreidesSmallTankTypes) } end
local tanksToBuildCorrino = function() return { Utils.Random(CorrinoTankTypes) } end local tanksToBuildCorrino = function()
local unitsToBuyAtreides = function() return { Utils.Random(AtreidesStarportTypes) } end if EarlyGameStage >= DateTime.GameTime then
local unitsToBuyCorrino = function() return { Utils.Random(CorrinoStarportTypes) } end return { Utils.Random(CorrinoTankTypes["EarlyGame"]) }
local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5 else
return { Utils.Random(CorrinoTankTypes["LateGame"]) }
end
end
ProduceUnits(AtreidesMain, ABarracks1, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize) local attackThresholdSize = AttackGroupSize[Difficulty] * 3
ProduceUnits(AtreidesMain, ALightFactory1, delay, vehilcesToBuild, AttackGroupSize[Difficulty], attackThresholdSize) local attackThresholdSizeSmall = AttackGroupSize[Difficulty] * 2
ProduceUnits(AtreidesMain, AHeavyFactory1, delay, tanksToBuildAtreidesMain, AttackGroupSize[Difficulty], attackThresholdSize) local attackThresholdSizeEmperor = AttackGroupSize[Difficulty] * 5
ProduceUnits(AtreidesMain, AStarport1, delay, unitsToBuyAtreides, AttackGroupSize[Difficulty], attackThresholdSize)
ProduceUnits(AtreidesSmall, ABarracks3, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize) Trigger.AfterDelay(InitialProductionDelay["AtreidesMain"][Difficulty], function ()
ProduceUnits(AtreidesSmall, ALightFactory2, delay, vehilcesToBuild, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(AtreidesMain, ABarracks1, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
ProduceUnits(AtreidesSmall, AHeavyFactory2, delay, tanksToBuildAtreidesSmall, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(AtreidesMain, ALightFactory1, delay, vehiclesToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
ProduceUnits(AtreidesSmall, AStarport2, delay, unitsToBuyAtreides, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(AtreidesMain, AHeavyFactory1, delay, tanksToBuildAtreidesMain, AttackGroupSize[Difficulty], attackThresholdSize)
--ProduceUnits(AtreidesMain, AStarport1, delay, unitsToBuyAtreides, AttackGroupSize[Difficulty], AttackThresholdSize)
end)
ProduceUnits(CorrinoMain, CBarracks1, delay, infantryToBuildCorrinoMain, AttackGroupSize[Difficulty], attackThresholdSize) Trigger.AfterDelay(InitialProductionDelay["AtreidesSmall"][Difficulty], function ()
ProduceUnits(CorrinoMain, CHeavyFactory, delay, tanksToBuildCorrino, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(AtreidesSmall, ABarracks3, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSizeSmall)
ProduceUnits(AtreidesSmall, ALightFactory2, delay, vehiclesToBuild, AttackGroupSize[Difficulty], attackThresholdSizeSmall)
ProduceUnits(AtreidesSmall, AHeavyFactory2, delay, tanksToBuildAtreidesSmall, AttackGroupSize[Difficulty], attackThresholdSizeSmall)
end)
ProduceUnits(CorrinoSmall, CBarracks3, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize) Trigger.AfterDelay(InitialProductionDelay["CorrinoMain"][Difficulty], function ()
ProduceUnits(CorrinoSmall, CLightFactory, delay, vehilcesToBuild, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(CorrinoMain, CBarracks1, delay, infantryToBuildCorrinoMain, AttackGroupSize[Difficulty], attackThresholdSizeEmperor)
ProduceUnits(CorrinoSmall, CStarport, delay, unitsToBuyCorrino, AttackGroupSize[Difficulty], attackThresholdSize) ProduceUnits(CorrinoMain, CHeavyFactory, delay, tanksToBuildCorrino, AttackGroupSize[Difficulty], attackThresholdSizeEmperor)
end)
Trigger.AfterDelay(InitialProductionDelay["CorrinoSmall"][Difficulty], function ()
ProduceUnits(CorrinoSmall, CBarracks3, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSizeSmall)
ProduceUnits(CorrinoSmall, CLightFactory, delay, vehiclesToBuild, AttackGroupSize[Difficulty], attackThresholdSizeSmall)
end)
local productionTypesAtreidis =
{
barracks = infantryToBuild,
light_factory = vehiclesToBuild,
heavy_factory = tanksToBuildAtreidesMain
}
local productionTypesCorrino =
{
barracks = infantryToBuildCorrinoMain,
heavy_factory = tanksToBuildCorrino
}
if Difficulty == "normal" then
AtreidesMain.GrantCondition("base-rebuilder")
AtreidesSmall.GrantCondition("base-rebuilder2")
CorrinoMain.GrantCondition("base-rebuilder3")
end
if Difficulty == "hard" then
AtreidesMain.GrantCondition("defense-rebuilder")
AtreidesSmall.GrantCondition("defense-rebuilder2")
CorrinoMain.GrantCondition("defense-rebuilder3")
end
Trigger.OnBuildingPlaced(AtreidesMain, function(p, building)
table.insert(AtreidesMainBase, building)
DefendAndRepairBase(AtreidesMain, {building}, 0.5, AttackGroupSize[Difficulty] )
if productionTypesAtreidis[building.Type] == nil then return end
ProduceUnits(AtreidesMain, building, delay, productionTypesAtreidis[building.Type], AttackGroupSize[Difficulty], attackThresholdSize)
end)
Trigger.OnBuildingPlaced(AtreidesSmall, function(p, building)
table.insert(AtreidesSmallBase, building)
DefendAndRepairBase(AtreidesSmall, {building}, 0.5, AttackGroupSize[Difficulty] )
if productionTypesAtreidis[building.Type] == nil then return end
ProduceUnits(AtreidesSmall, building, delay, productionTypesAtreidis[building.Type], AttackGroupSize[Difficulty], attackThresholdSize)
end)
Trigger.OnBuildingPlaced(CorrinoMain, function(p, building)
table.insert(CorrinoMainBase, building)
DefendAndRepairBase(CorrinoMain, {building}, 0.5, AttackGroupSize[Difficulty] )
if productionTypesCorrino[building.Type] == nil then return end
ProduceUnits(CorrinoMain, building, delay, productionTypesCorrino[building.Type], AttackGroupSize[Difficulty], attackThresholdSize)
end)
ActivateCrushLogic()
end end

View File

@@ -8,8 +8,11 @@
]] ]]
AtreidesMainBase = { AConYard1, AOutpost1, APalace, ARefinery1, ARefinery2, AHeavyFactory1, ALightFactory1, ARepair1, AStarport1, AHiTechFactory, AResearch, ARock1, ARock2, ARock3, ARock4, ARock5, ARock6, ARock7, ARock8, ARock9, ARock10, ABarracks1, ABarracks2, APower1, APower2, APower3, APower4, APower5, APower6, APower7, APower8, APower9, APower10, APower11, ASilo1, ASilo2, ASilo3 } AtreidesMainBase = { AConYard1, AOutpost1, APalace, ARefinery1, ARefinery2, AHeavyFactory1, ALightFactory1, ARepair1, AStarport1, AHiTechFactory, AResearch, ARock1, ARock2, ARock3, ARock4, ARock5, ARock6, ARock7, ARock8, ARock9, ARock10, ABarracks1, ABarracks2, APower1, APower2, APower3, APower4, APower5, APower6, APower7, APower8, APower9, APower10, APower11, ASilo1, ASilo2, ASilo3 }
AtreidesSmallBase = { AConYard2, ARefinery3, ABarracks3, AHeavyFactory2, ALightFactory2, ARepair2, AGunt1, AGunt2, ARock11, APower12, APower13, APower14, APower15, APower16, APower17, APower18, APower19, APower20 } AtreidesSmallBase = { AConYard2, ARefinery3, ABarracks3, AHeavyFactory2, ALightFactory2, ARepair2, AGunt1, AGunt2, ARock11, APower12, APower13, APower14, APower15, APower16, APower17, APower18, APower19, APower20 }
CorrinoMainBase = { CConYard, COutpost, CPalace, CRefinery1, CHeavyFactory, CResearch, CGunt1, CGunt2, CGunt3, CGunt4, CGunt5, CGunt6, CRock1, CRock2, CRock3, CRock4, CBarracks1, CBarracks2, CPower1, CPower2, CPower3, CPower4, CPower5, CPower6, CPower7, CPower8 } CorrinoMainBase = { CConYard, COutpost, CPalace, CRefinery1, CHeavyFactory, CResearch, CGunt1, CGunt2, CGunt3, CGunt4, CGunt5, CGunt6, CRock1, CRock2, CRock3, CRock4, CBarracks1, CBarracks2, CPower1, CPower2, CPower3, CPower4, CPower5, CPower6, CPower7, CPower8 }
CorrinoSmallBase = { CRefinery2, CLightFactory, CStarport, CGunt7, CGunt8, CBarracks3, CPower9, CPower10, CPower11, CPower12, CSilo1, CSilo2, CSilo3, CSilo4 } CorrinoSmallBase = { CRefinery2, CLightFactory, CStarport, CGunt7, CGunt8, CBarracks3, CPower9, CPower10, CPower11, CPower12, CSilo1, CSilo2, CSilo3, CSilo4 }
AtreidesReinforcements = AtreidesReinforcements =
@@ -148,7 +151,6 @@ SendStarportReinforcements = function()
end end
local reinforcements = Utils.Random(CorrinoStarportReinforcements[Difficulty]) local reinforcements = Utils.Random(CorrinoStarportReinforcements[Difficulty])
local units = Reinforcements.ReinforceWithTransport(CorrinoSmall, "frigate", reinforcements, { CorrinoStarportEntry.Location, CStarport.Location + CVec.New(1, 1) }, { CorrinoStarportExit.Location })[2] local units = Reinforcements.ReinforceWithTransport(CorrinoSmall, "frigate", reinforcements, { CorrinoStarportEntry.Location, CStarport.Location + CVec.New(1, 1) }, { CorrinoStarportExit.Location })[2]
Utils.Do(units, function(unit) Utils.Do(units, function(unit)
unit.AttackMove(AtreidesAttackLocation) unit.AttackMove(AtreidesAttackLocation)
@@ -168,14 +170,33 @@ SendHarkonnenReinforcements = function(delay)
end) end)
end end
SendAirStrike = function() AirStrikeTimer = 7500
if AHiTechFactory.IsDead or AHiTechFactory.Owner ~= AtreidesMain then AirStrikeChargeTime = 7500
AirstrikeLogic = function(airstrikeProvider)
if airstrikeProvider.IsDead then return end
if DateTime.GameTime <= AirStrikeTimer then
Trigger.AfterDelay(AirStrikeTimer - DateTime.GameTime + 1, function()
AirstrikeLogic(airstrikeProvider)
end)
return return
end end
-- randomly choose if wait again or strike. During waiting Airstrike can still be used by DefensiveAirStrike
if Utils.RandomInteger(1, 100) < 30 then
Trigger.AfterDelay(1501, function() AirstrikeLogic(airstrikeProvider)end)
else
AirStrikeVSBuilding(airstrikeProvider)
Trigger.AfterDelay(7500, function() AirstrikeLogic(airstrikeProvider) end)
IsAirstrikeReady = false
end
end
AirStrikeVSBuilding = function(airstrikeProvider)
if airstrikeProvider.IsDead then return end
local targets = Utils.Where(Harkonnen.GetActors(), function(actor) local targets = Utils.Where(Harkonnen.GetActors(), function(actor)
return return actor.HasProperty("Sell") and
actor.HasProperty("Sell") and
actor.Type ~= "wall" and actor.Type ~= "wall" and
actor.Type ~= "medium_gun_turret" and actor.Type ~= "medium_gun_turret" and
actor.Type ~= "large_gun_turret" and actor.Type ~= "large_gun_turret" and
@@ -184,12 +205,71 @@ SendAirStrike = function()
end) end)
if #targets > 0 then if #targets > 0 then
AHiTechFactory.TargetAirstrike(Utils.Random(targets).CenterPosition) airstrikeProvider.TargetAirstrike(Utils.Random(targets).CenterPosition)
AirStrikeTimer = DateTime.GameTime + AirStrikeChargeTime
end end
Trigger.AfterDelay(DateTime.Minutes(5), SendAirStrike)
end end
DefensiveAirStrike = function(airstrikeProvider, possibleTargets)
if airstrikeProvider.IsDead then return end
local bestValue = {}
local bestIndex = 1
for i = 1, #possibleTargets, 1 do
local ActorsInCircle = Map.ActorsInCircle(possibleTargets[i].CenterPosition, WDist.FromCells(4), function(a)
return
a.Owner == Harkonnen
and not a.IsDead
and a.HasProperty("Attack")
end)
bestValue[i] = 0
Utils.Do(ActorsInCircle, function(a)
bestValue[i] = bestValue[i] + Actor.Cost(a.Type)
end)
if bestValue[i] > bestValue[bestIndex] then
bestIndex = i
end
end
airstrikeProvider.TargetAirstrike(possibleTargets[bestIndex].CenterPosition)
AirStrikeTimer = DateTime.GameTime + AirStrikeChargeTime
end
EmergencyBehaviour = function(player,target)
if player == AtreidesMain or player == AtreidesSmall then
if AHiTechFactory.IsDead then return end
local enemyunits = Map.ActorsInCircle(Map.CenterOfCell(target), WDist.FromCells(15), function(a)
return a.Owner == Harkonnen
and not a.IsDead
and a.HasProperty("Attack")
end)
if enemyunits[1] == nil then return end
DefensiveAirStrike(AHiTechFactory, enemyunits)
end
if player == CorrinoSmall then
player.Cash = player.Cash + 2000
end
end
ReleaseSardaukars = true
Trigger.OnDamaged(CPalace, function(self)
if self.Health < self.MaxHealth * 0.8 and ReleaseSardaukars then
local index = 0
while index < 100 do
index = index + 5
Trigger.AfterDelay(index,function()
if self.IsDead then return end
local actor = Actor.Create("sardaukar", true, {Owner = CorrinoMain, Location = CPalace.Location + CVec.New(1,2)})
actor.Move(CPos.New(90,45))
IdlingUnits[CorrinoMain][#IdlingUnits[CorrinoMain] + 1] = actor
end)
end
ReleaseSardaukars = false
end
end)
BuildFremen = function() BuildFremen = function()
if APalace.IsDead or APalace.Owner ~= AtreidesMain then if APalace.IsDead or APalace.Owner ~= AtreidesMain then
return return
@@ -302,7 +382,6 @@ Tick = function()
if DateTime.GameTime % DateTime.Seconds(10) == 0 and LastHarvesterEaten[AtreidesMain] then if DateTime.GameTime % DateTime.Seconds(10) == 0 and LastHarvesterEaten[AtreidesMain] then
local units = AtreidesMain.GetActorsByType("harvester") local units = AtreidesMain.GetActorsByType("harvester")
if #units > 0 then if #units > 0 then
LastHarvesterEaten[AtreidesMain] = false LastHarvesterEaten[AtreidesMain] = false
ProtectHarvester(units[1], AtreidesMain, AttackGroupSize[Difficulty]) ProtectHarvester(units[1], AtreidesMain, AttackGroupSize[Difficulty])
@@ -311,7 +390,6 @@ Tick = function()
if DateTime.GameTime % DateTime.Seconds(10) == 0 and LastHarvesterEaten[AtreidesSmall] then if DateTime.GameTime % DateTime.Seconds(10) == 0 and LastHarvesterEaten[AtreidesSmall] then
local units = AtreidesSmall.GetActorsByType("harvester") local units = AtreidesSmall.GetActorsByType("harvester")
if #units > 0 then if #units > 0 then
LastHarvesterEaten[AtreidesSmall] = false LastHarvesterEaten[AtreidesSmall] = false
ProtectHarvester(units[1], AtreidesSmall, AttackGroupSize[Difficulty]) ProtectHarvester(units[1], AtreidesSmall, AttackGroupSize[Difficulty])
@@ -320,7 +398,6 @@ Tick = function()
if DateTime.GameTime % DateTime.Seconds(10) == 0 and LastHarvesterEaten[CorrinoMain] then if DateTime.GameTime % DateTime.Seconds(10) == 0 and LastHarvesterEaten[CorrinoMain] then
local units = CorrinoMain.GetActorsByType("harvester") local units = CorrinoMain.GetActorsByType("harvester")
if #units > 0 then if #units > 0 then
LastHarvesterEaten[CorrinoMain] = false LastHarvesterEaten[CorrinoMain] = false
ProtectHarvester(units[1], CorrinoMain, AttackGroupSize[Difficulty]) ProtectHarvester(units[1], CorrinoMain, AttackGroupSize[Difficulty])
@@ -329,7 +406,6 @@ Tick = function()
if DateTime.GameTime % DateTime.Seconds(10) == 0 and LastHarvesterEaten[CorrinoSmall] then if DateTime.GameTime % DateTime.Seconds(10) == 0 and LastHarvesterEaten[CorrinoSmall] then
local units = CorrinoSmall.GetActorsByType("harvester") local units = CorrinoSmall.GetActorsByType("harvester")
if #units > 0 then if #units > 0 then
LastHarvesterEaten[CorrinoSmall] = false LastHarvesterEaten[CorrinoSmall] = false
ProtectHarvester(units[1], CorrinoSmall, AttackGroupSize[Difficulty]) ProtectHarvester(units[1], CorrinoSmall, AttackGroupSize[Difficulty])
@@ -366,8 +442,8 @@ WorldLoaded = function()
Camera.Position = HBarracks.CenterPosition Camera.Position = HBarracks.CenterPosition
AtreidesAttackLocation = HBarracks.Location AtreidesAttackLocation = HBarracks.Location
Trigger.AfterDelay(DateTime.Minutes(5), SendAirStrike) Trigger.AfterDelay(DateTime.Minutes(10), function() AirstrikeLogic(AHiTechFactory) end )
Trigger.AfterDelay(DateTime.Minutes(1) + DateTime.Seconds (30), BuildFremen) Trigger.AfterDelay(EarlyGameStage, BuildFremen)
Trigger.OnAllKilledOrCaptured(AtreidesMainBase, function() Trigger.OnAllKilledOrCaptured(AtreidesMainBase, function()
Utils.Do(AtreidesMain.GetGroundAttackers(), IdleHunt) Utils.Do(AtreidesMain.GetGroundAttackers(), IdleHunt)
@@ -385,14 +461,22 @@ WorldLoaded = function()
Utils.Do(CorrinoSmall.GetGroundAttackers(), IdleHunt) Utils.Do(CorrinoSmall.GetGroundAttackers(), IdleHunt)
end) end)
Trigger.AfterDelay(300, function()
Media.DisplayMessage(UserInterface.GetFluentMessage("husk-reclaimed-harkonnen"), Mentat)
end)
Trigger.AfterDelay(350, function()
Media.DisplayMessage(UserInterface.GetFluentMessage("engineers-hint"), Mentat)
end)
local path = function() return Utils.Random(AtreidesPaths) end local path = function() return Utils.Random(AtreidesPaths) end
local waveCondition = function() return Harkonnen.IsObjectiveCompleted(KillAtreides) end local waveCondition = function() return Harkonnen.IsObjectiveCompleted(KillAtreides) end
local huntFunction = function(unit) local huntFunction = function(unit)
unit.AttackMove(AtreidesAttackLocation) unit.AttackMove(AtreidesAttackLocation)
IdleHunt(unit) IdleHunt(unit)
end end
SendCarryallReinforcements(AtreidesMain, 0, AtreidesAttackWaves[Difficulty], AtreidesAttackDelay[Difficulty], path, AtreidesReinforcements[Difficulty], waveCondition, huntFunction)
SendCarryallReinforcements(AtreidesMain, 0, AtreidesAttackWaves[Difficulty], AtreidesAttackDelay[Difficulty], path, AtreidesReinforcements[Difficulty], waveCondition, huntFunction)
SendStarportReinforcements() SendStarportReinforcements()
Actor.Create("upgrade.barracks", true, { Owner = AtreidesMain }) Actor.Create("upgrade.barracks", true, { Owner = AtreidesMain })

Binary file not shown.

View File

@@ -454,9 +454,6 @@ Actors:
COutpost: outpost COutpost: outpost
Location: 79,42 Location: 79,42
Owner: Corrino Main Base Owner: Corrino Main Base
CPalace: palace
Location: 89,42
Owner: Corrino Main Base
Actor116: wall Actor116: wall
Location: 93,42 Location: 93,42
Owner: Corrino Main Base Owner: Corrino Main Base
@@ -1005,6 +1002,68 @@ Actors:
CPower8: wind_trap CPower8: wind_trap
Owner: Corrino Main Base Owner: Corrino Main Base
Location: 90,48 Location: 90,48
APatrolPoint1: waypoint
Owner: Neutral
Location: 10,60
APatrolPoint2: waypoint
Owner: Neutral
Location: 38,85
APatrolPoint3: waypoint
Owner: Neutral
Location: 75,73
APatrolPoint4: waypoint
Owner: Neutral
Location: 44,32
APatrolPoint5: waypoint
Owner: Neutral
Location: 99,33
APatrolPoint6: waypoint
Owner: Neutral
Location: 82,17
APatrolPoint7: waypoint
Owner: Neutral
Location: 65,30
CPatrolPoint1: waypoint
Owner: Neutral
Location: 49,13
CPatrolPoint2: waypoint
Owner: Neutral
Location: 15,47
Actor6: combat_tank_h.debris
Owner: Harkonnen
Facing: 384
Location: 17,3
Actor7: siege_tank.debris
Owner: Harkonnen
Facing: 384
Location: 16,3
Actor5: combat_tank_a.debris
Facing: 384
Faction:
Owner: Atreides Small Base
Location: 14,3
CPalace: palace
Owner: Corrino Main Base
Location: 89,41
Actor10: light_inf
Owner: Smugglers - Neutral
Facing: 384
Location: 12,89
SubCell: 3
Actor9: trooper
Owner: Smugglers - Neutral
Facing: 384
Location: 11,88
SubCell: 3
Actor15: siege_tank.debris
Owner: Smugglers - Neutral
Facing: 384
Location: 10,88
Actor8: engineer
Owner: Smugglers - Neutral
Facing: 384
Location: 9,88
SubCell: 3
Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml

View File

@@ -1,6 +1,208 @@
Player: Player:
PlayerResources: PlayerResources:
DefaultCash: 5000 DefaultCash: 5000
ExternalCondition@AIAMail:
Condition: base-rebuilder
ExternalCondition@AIASmall:
Condition: base-rebuilder2
ExternalCondition@AICSmall:
Condition: base-rebuilder3
ExternalCondition@AIAMail-defense:
Condition: defense-rebuilder
ExternalCondition@AIASmall-defense:
Condition: defense-rebuilder2
ExternalCondition@AICSmall-defense:
Condition: defense-rebuilder3
BaseBuilderBotModule@AtreidesMain:
RequiresCondition: base-rebuilder
BuildingQueues: Building, Upgrade
MinimumExcessPower: 0
MaximumExcessPower: 250
MaxBaseRadius: 40
ConstructionYardTypes: construction_yard
RefineryTypes: refinery
PowerTypes: wind_trap
ProductionTypes: light_factory, heavy_factory, barracks, starport
SiloTypes: silo
DefenseTypes: medium_gun_turret,large_gun_turret
SellRefineryInterval: -1
BuildingLimits:
barracks: 1
refinery: 3
outpost: 1
light_factory: 1
starport: 1
palace: 1
heavy_factory: 1
high_tech_factory: 1
wind_trap: 11
research_centre: 1
silo: 1
BuildingFractions:
wind_trap: 1
barracks: 1
refinery: 1
research_centre: 1
outpost: 1
starport: 1
high_tech_factory: 1
palace: 1
light_factory: 1
heavy_factory: 1
BaseBuilderBotModule@AtreidesSmallBase:
RequiresCondition: base-rebuilder2
BuildingQueues: Building, Upgrade
MinimumExcessPower: 0
MaximumExcessPower: 250
MaxBaseRadius: 40
ConstructionYardTypes: construction_yard
RefineryTypes: refinery
PowerTypes: wind_trap
ProductionTypes: light_factory, heavy_factory, barracks, starport
SiloTypes: silo
DefenseTypes: medium_gun_turret,large_gun_turret
SellRefineryInterval: -1
BuildingLimits:
barracks: 1
refinery: 1
outpost: 1
light_factory: 1
palace: 1
heavy_factory: 1
wind_trap: 7
silo: 1
BuildingFractions:
wind_trap: 1
barracks: 1
refinery: 1
outpost: 1
light_factory: 1
heavy_factory: 1
BaseBuilderBotModule@CorrinoMain:
RequiresCondition: base-rebuilder3
BuildingQueues: Building, Upgrade
MinimumExcessPower: 0
MaximumExcessPower: 250
MaxBaseRadius: 40
ConstructionYardTypes: construction_yard
RefineryTypes: refinery
PowerTypes: wind_trap
ProductionTypes: light_factory, heavy_factory, barracks, starport
SiloTypes: silo
DefenseTypes: medium_gun_turret,large_gun_turret
SellRefineryInterval: -1
BuildingLimits:
barracks: 1
refinery: 3
outpost: 1
heavy_factory: 1
wind_trap: 4
silo: 1
BuildingFractions:
wind_trap: 1
barracks: 1
refinery: 1
outpost: 1
heavy_factory: 1
BaseBuilderBotModule@AtreidesMainDefense:
RequiresCondition: defense-rebuilder
BuildingQueues: Building, Upgrade
MinimumExcessPower: 0
MaximumExcessPower: 250
MaxBaseRadius: 40
ConstructionYardTypes: construction_yard
RefineryTypes: refinery
PowerTypes: wind_trap
ProductionTypes: light_factory, heavy_factory, barracks, starport
SiloTypes: silo
DefenseTypes: large_gun_turret
SellRefineryInterval: -1
BuildingLimits:
barracks: 1
refinery: 3
outpost: 1
light_factory: 1
starport: 1
palace: 1
heavy_factory: 1
high_tech_factory: 1
wind_trap: 11
silo: 1
research_centre: 1
large_gun_turret: 10
BuildingFractions:
wind_trap: 1
barracks: 1
refinery: 1
outpost: 1
starport: 1
high_tech_factory: 1
palace: 1
light_factory: 1
research_centre: 1
heavy_factory: 1
large_gun_turret: 1
BaseBuilderBotModule@AtreidesSmallBaseDefense:
RequiresCondition: defense-rebuilder2
BuildingQueues: Building, Upgrade
MinimumExcessPower: 0
MaximumExcessPower: 250
MaxBaseRadius: 40
ConstructionYardTypes: construction_yard
RefineryTypes: refinery
PowerTypes: wind_trap
ProductionTypes: light_factory, heavy_factory, barracks, starport
SiloTypes: silo
DefenseTypes: medium_gun_turret,large_gun_turret
SellRefineryInterval: -1
BuildingLimits:
barracks: 1
refinery: 1
outpost: 1
light_factory: 1
palace: 1
heavy_factory: 1
wind_trap: 7
silo: 1
large_gun_turret: 1
medium_gun_turret: 2
BuildingFractions:
wind_trap: 1
barracks: 1
refinery: 1
outpost: 1
light_factory: 1
heavy_factory: 1
large_gun_turret: 1
medium_gun_turret: 1
BaseBuilderBotModule@CorrinoMainDefense:
RequiresCondition: defense-rebuilder3
BuildingQueues: Building, Upgrade
MinimumExcessPower: 0
MaximumExcessPower: 250
MaxBaseRadius: 40
ConstructionYardTypes: construction_yard
RefineryTypes: refinery
PowerTypes: wind_trap
ProductionTypes: heavy_factory, barracks, starport
SiloTypes: silo
DefenseTypes: medium_gun_turret,large_gun_turret
SellRefineryInterval: -1
BuildingLimits:
barracks: 1
refinery: 3
outpost: 1
heavy_factory: 1
wind_trap: 4
silo: 1
large_gun_turret: 2
BuildingFractions:
wind_trap: 1
barracks: 1
refinery: 1
outpost: 1
heavy_factory: 1
large_gun_turret: 2
World: World:
LuaScript: LuaScript:
@@ -62,3 +264,28 @@ grenadier:
thumper: thumper:
Buildable: Buildable:
Prerequisites: ~disabled Prerequisites: ~disabled
palace:
ProduceActorPower@ReleaseSardaukars:
Name: actor-palace.produceactorpower-fremen-name
Description: actor-palace.produceactorpower-fremen-description
Icon: fremen
PauseOnCondition: disabled
RequiresCondition: corrino
Prerequisites: ~techlevel.superweapons, ~palace.sardaukar
Actors: mpsardaukar, mpsardaukar, mpsardaukar, mpsardaukar, mpsardaukar
Type: sardaukar
ChargeInterval: 2250
EndChargeTextNotification: notification-fremen-ready
ReadyAudio: Reinforce
ReadyTextNotification: notification-reinforcements-have-arrived
BlockedAudio: NoRoom
BlockedTextNotification: notification-no-room-for-new-unit
OrderName: ProduceActorPower.Fremen
SupportPowerPaletteOrder: 2040
GrantConditionOnFaction@corrino:
Condition: corrino
Factions: corrino
Production@Corrino:
Produces: sardaukar
RequiresCondition: corrino

Some files were not shown because too many files have changed in this diff Show More