diff --git a/planet/Objects.ocd/Helpers.ocd/AI.ocd/AttackModes.ocd/Script.c b/planet/Objects.ocd/Helpers.ocd/AI.ocd/AttackModes.ocd/Script.c index bfff60267..287d73a85 100644 --- a/planet/Objects.ocd/Helpers.ocd/AI.ocd/AttackModes.ocd/Script.c +++ b/planet/Objects.ocd/Helpers.ocd/AI.ocd/AttackModes.ocd/Script.c @@ -100,7 +100,7 @@ private func InitAttackModes() if (!this.FxAI.EditorProps.attack_mode) this.FxAI.EditorProps.attack_mode = AI.FxAI.EditorProps.attack_mode; } -public func RegisterAttackMode(string identifier, proplist am) +public func RegisterAttackMode(string identifier, proplist am, proplist am_default_values) { // Definition call during Definition()-initialization: // Register a new attack mode selectable for the AI clonk @@ -108,11 +108,12 @@ public func RegisterAttackMode(string identifier, proplist am) if (!AttackModes) this->InitAttackModes(); AttackModes[identifier] = am; am.Identifier = identifier; + if (!am_default_values) am_default_values = { Identifier=identifier }; // Add to editor option for AI effect var am_option = { Name = am.Name ?? am->GetName(), EditorHelp = am.EditorHelp, - Value = am + Value = am_default_values }; if (!am_option.EditorHelp && am.GetEditorHelp) am_option.EditorHelp = am->GetEditorHelp(); var editor_opts = this.FxAI.EditorProps.attack_mode.Options; @@ -121,10 +122,10 @@ public func RegisterAttackMode(string identifier, proplist am) private func DefinitionAttackModes(proplist def) { - // Register presets for all the default weapons usable by the AI - this->InitAttackModes(); // Registration only once for base AI if (this != AI) return; + // Register presets for all the default weapons usable by the AI + this->InitAttackModes(); def->RegisterAttackMode("Default", { Name = "$Default$", EditorHelp = "$DefaultHelp$", FindWeapon = AI.FindInventoryWeapon }); def->RegisterAttackMode("Sword", new SingleWeaponAttackMode { Weapon = Sword, Strategy = this.ExecuteMelee }); def->RegisterAttackMode("Club", new SingleWeaponAttackMode { Weapon = Club, Strategy = this.ExecuteMelee }); diff --git a/planet/Objects.ocd/Helpers.ocd/AI.ocd/Script.c b/planet/Objects.ocd/Helpers.ocd/AI.ocd/Script.c index a3c3b11b6..6dfb22342 100644 --- a/planet/Objects.ocd/Helpers.ocd/AI.ocd/Script.c +++ b/planet/Objects.ocd/Helpers.ocd/AI.ocd/Script.c @@ -21,6 +21,8 @@ #include AI_Vehicles #include AI_AttackModes +// Enemy spawn definition depends on this +local DefinitionPriority = 50; // AI Settings. local MaxAggroDistance = 200; // Lose sight to target if it is this far away (unless we're ranged - then always guard the range rect). @@ -285,6 +287,8 @@ local FxAI = new Effect }, SetAttackMode = func(proplist attack_mode) { + // Called by editor delegate when attack mdoe is changed. + // For now, attack mode parameter delegates are not supported. Just set by name. return this.control->SetAttackMode(this.Target, attack_mode.Identifier); }, EditorProps = { diff --git a/planet/Objects.ocd/Helpers.ocd/EnemySpawn.ocd/DefCore.txt b/planet/Objects.ocd/Helpers.ocd/EnemySpawn.ocd/DefCore.txt new file mode 100644 index 000000000..c2c63d6ea --- /dev/null +++ b/planet/Objects.ocd/Helpers.ocd/EnemySpawn.ocd/DefCore.txt @@ -0,0 +1,7 @@ +[DefCore] +id=EnemySpawn +Version=8,0 +Category=C4D_StaticBack|C4D_Environment +Width=16 +Height=16 +Offset=-8,-8 diff --git a/planet/Objects.ocd/Helpers.ocd/EnemySpawn.ocd/Graphics.4.png b/planet/Objects.ocd/Helpers.ocd/EnemySpawn.ocd/Graphics.4.png new file mode 100644 index 000000000..26f86ae4d Binary files /dev/null and b/planet/Objects.ocd/Helpers.ocd/EnemySpawn.ocd/Graphics.4.png differ diff --git a/planet/Objects.ocd/Helpers.ocd/EnemySpawn.ocd/Script.c b/planet/Objects.ocd/Helpers.ocd/EnemySpawn.ocd/Script.c new file mode 100644 index 000000000..8c15667b8 --- /dev/null +++ b/planet/Objects.ocd/Helpers.ocd/EnemySpawn.ocd/Script.c @@ -0,0 +1,507 @@ +/** + EnemySpawn + When activated, spawns one or more AI-controlled enemies that attack the players. + + @author Sven2 +*/ + +local Name="$Name$"; +local Description="$Description$"; +local Visibility=VIS_Editor; + +local SPAWNCOUNT_INFINITE = 0x7fffffff; // magic value for spawn_count: Infinite enemy count. (must be a big value) + +local active; // Triggered or currently spawning +local waiting_for_script_player; // Set to true if rule was activated but still waiting for +local enemy = nil; // No enemy defined +local spawn_position = nil; // Where / in which range to spawn +local spawn_count = 1; // Number of enemies to spawn. SPAWNCOUNT_INFINITE for infinite. +local spawn_delay = 0; // Delay after trigger before first spawn +local spawn_interval = 30; // Delay between spawned enemies +local attack_path = nil; // Optional: Array of points along which the spawned enemy moves/attacks +local auto_activate = false; // If true, the object is activated on the first player join + +local spawned_count; // Number of enemies already spawned in current wave +local spawned_enemies; // Array of spawned enemies. Automatically cleared when clonks die. +local num_enemies_defeated = 0; // Increased for each defeated clonk of this spawner +local num_waves_defeated = 0; // Increased after each defeated activation + +local EnemyDefs; // Proplist of possible enemy spawn definitions; indexed by Type + +static g_enemyspawn_player; // player number of attacking player + +public func IsEnemySpawn() { return true; } + + +/* Parameter interface */ + +public func SetEnemy(proplist new_enemy) { enemy = new_enemy; UpdateEnemyDisplay(); } +public func SetSpawnPosition(proplist new_spawn_position) { spawn_position = new_spawn_position; } +public func SetSpawnCount(int new_spawn_count) { spawn_count = new_spawn_count; } +public func SetSpawnDelay(int new_spawn_delay) { spawn_delay = new_spawn_delay; } +public func SetSpawnInterval(int new_spawn_interval) { spawn_interval = new_spawn_interval; } +public func SetAttackPath(array new_attack_path) { attack_path = new_attack_path; } +public func SetAutoActivate(bool new_auto_activate) { auto_activate = new_auto_activate; } + + +/* Initialization */ + +public func Initialize() +{ + spawned_enemies = []; + // Make sure there's an enemy script player + if (!GetType(g_enemyspawn_player)) + { + // Look for existing enemy player + for (var iplr = 0; iplr < GetPlayerCount(C4PT_Script); ++iplr) + { + var plr = GetPlayerByIndex(iplr, C4PT_Script); + if (GetScriptPlayerExtraID(plr) == GetID()) + { + g_enemyspawn_player = plr; + break; + } + } + // Otherwise join it + if (!GetType(g_enemyspawn_player)) + { + g_enemyspawn_player = NO_OWNER; // Sentinel value: Script player join scheduled but not joined yet + CreateScriptPlayer("$PlayerAttackers$", nil, 0, CSPF_NoEliminationCheck | CSPF_Invisible | CSPF_FixedAttributes | CSPF_NoScenarioInit | CSPF_NoScenarioSave, GetID()); + } + } +} + +private func IsEnemySpawnPlayerJoined() +{ + return GetType(g_enemyspawn_player) && (g_enemyspawn_player != NO_OWNER); +} + + +public func InitializeScriptPlayer(int plr, int team) +{ + // Init the enemy script player: Hostile to all players + if (g_enemyspawn_player == NO_OWNER) + { + // Handle hostility if not done through teams + for (var iplr = 0; iplr < GetPlayerCount(C4PT_User); ++iplr) + { + SetHostility(GetPlayerByIndex(iplr, C4PT_User), plr, true, true, true); // triple true hostility! + } + g_enemyspawn_player = plr; + } + // Perform delayed activation + if (waiting_for_script_player) + { + ActivateSpawn(); + } +} + +public func InitializePlayer(int plr, int x, int y, object base, int team, extra_id) +{ + if (GetPlayerType(plr) == C4PT_User && IsEnemySpawnPlayerJoined()) + { + // Make sure new enemy players are hostile + SetHostility(g_enemyspawn_player, plr, true, true, true); + } +} + + +/* Enemy spawning */ + +public func StartSpawn() +{ + // Timed spawn or immediate spawn? + if (spawn_interval > 0 && spawn_count > 1) + { + // First enemy comes immediately. Then scheduled. + Spawn(); + ScheduleCall(this, this.Spawn, spawn_interval, spawn_count - 1); + } + else + { + // Immediate spawn + // Can't do inifinite and immediate + if (spawn_count == SPAWNCOUNT_INFINITE) + { + SpawnFinished(); + FatalError("EnemySpawn: Spawning of infinite enmies without timer delay disabled, because it would destroy the universe in a big boom (Hawking, Stephen W. \"Black hole explosions.\" Nature 248.5443 (1974): 30-31.)"); + } + for (var i = 0; i < spawn_count; ++i) + { + Spawn(); + } + } +} + +private func SpawnFinished() +{ + // All enemies have been spawned. Mark inactive. + active = waiting_for_script_player = false; + SetClrModulation(); + spawned_count = 0; + // Count finished waves + if (!GetLength(spawned_enemies)) WaveDefeated(); +} + +private func GetAttackPath() +{ + // Get attack path in global coordinates + if (!attack_path) return [ { X = GetX(), Y = GetY() } ]; + var global_attack_path = CreateArray(GetLength(attack_path)), i; + for (var pt in attack_path) + { + global_attack_path[i++] = { X = GetX() + pt.X, Y = GetY() + pt.Y }; + } + return global_attack_path; +} + +private func Spawn() +{ + // Find a spawn location + var spawn_pos = GetSpawnPosition(); + // Spawn the actual enemy + if (enemy) + { + var enemy_def = EnemyDefs[enemy.Type]; + var spawn_function = enemy_def.SpawnFunction; + var enemies = (enemy_def.SpawnCallTarget ?? GetID())->Call(spawn_function, spawn_pos, enemy, enemy_def, GetAttackPath(), this); + // Keep track of enemies. Could be returned as a single enemy or as an array + if (GetType(enemies) == C4V_Array) + { + for (var obj in enemies) + { + TrackSpawnedEnemy(obj); + } + } + else + { + TrackSpawnedEnemy(enemies); + } + } + // Keep track of count + if (++spawned_count == spawn_count) + { + SpawnFinished(); + } +} + +public func TrackSpawnedEnemy(object enemy) +{ + // Remember any spawned enemies + if (enemy) + { + spawned_enemies[GetLength(spawned_enemies)] = enemy; + } +} + +private func WaveDefeated() +{ + // Just keep track of the count + ++num_waves_defeated; +} + +public func CancelSpawn() +{ + // Stop any spawning timers + ClearScheduleCall(this, this.StartSpawn); + ClearScheduleCall(this, this.Spawn); + // Mark inactive + SpawnFinished(); +} + +public func RemoveSpawnedEnemies() +{ + // Remove all spawned enemies + for (var enemy in spawned_enemies) + { + if (enemy) + { + enemy->RemoveObject(); + } + } +} + +public func ActivateSpawn() +{ + // Already triggered or still running? + if (active) return; + // Needs to wait for script player join? + if (!IsEnemySpawnPlayerJoined()) + { + waiting_for_script_player = true; + return; + } + // Activate + waiting_for_script_player = false; + active = true; + SetClrModulation(0xffff2020); + if (spawn_delay) + { + ScheduleCall(this, this.StartSpawn, spawn_delay, 1); + } + else + { + StartSpawn(); + } +} + +public func GetSpawnPosition() +{ + // Evaluate spawn position setting + if (spawn_position) + { + var spawn_position_mode = spawn_position.Mode; + if (spawn_position_mode == "range") + { + // Random position in a circle around this position + var r = Sqrt(Random(spawn_position.Radius * spawn_position.Radius)); + var ang = Random(360); + return [GetX() + Sin(ang, r), GetY() + Cos(ang, r)]; + } + else if (spawn_position_mode == "rectangle") + { + var rect = spawn_position.Area; + return [GetX() + rect[0] + Random(rect[2]), GetY() + rect[1] + Random(rect[3])]; + } + } + // Default: Spawn here + return [GetX(), GetY()]; +} + +public func InitializePlayers() +{ + // Activate auto-triggered spawns + if (auto_activate) ActivateSpawn(); +} + + +/* Clonk spawning */ + +public func SpawnClonk(array pos, proplist clonk_data, proplist enemy_def, array clonk_attack_path, object spawner) +{ + // Spawn it + var clonk = CreateObject(Clonk, pos[0], pos[1], g_enemyspawn_player); + if (!clonk) return []; + clonk->SetController(g_enemyspawn_player); + clonk->MakeCrewMember(g_enemyspawn_player); + // Enemy visuals + if (clonk_data.Skin) + { + clonk->SetSkin(clonk_data.Skin); + } + if (!clonk_data.Backpack) + { + clonk->~RemoveBackpack(); + } + if (clonk_data.ScaleX != 100 || clonk_data.ScaleY != 100) + { + var scale_z = (clonk_data.ScaleX + clonk_data.ScaleY) / 2; + clonk->SetMeshTransformation(Trans_Scale(clonk_data.ScaleX, clonk_data.ScaleY, scale_z), 6); + } + if (clonk_data.Name && GetLength(clonk_data.Name)) + { + clonk->SetName(clonk_data.Name); + } + clonk->SetColor(clonk_data.Color); + // Physical properties + clonk.MaxEnergy = clonk_data.Energy * 1000; + clonk->DoEnergy(10000); + if (clonk_data.Speed != 100) + { + // Speed: Modify Speed in all ActMap entries + if (clonk.ActMap == clonk.Prototype.ActMap) clonk.ActMap = new clonk.ActMap {}; + for (var action in GetProperties(Clonk.ActMap)) + { + if (action == "Prototype") continue; + if (clonk.ActMap[action] == clonk.Prototype.ActMap[action]) clonk.ActMap[action] = new clonk.ActMap[action] {}; + clonk.ActMap[action].Speed = clonk.ActMap[action].Speed * clonk_data.Speed / 100; + } + clonk.JumpSpeed = clonk.JumpSpeed * clonk_data.Speed / 100; + clonk.FlySpeed = clonk.FlySpeed * clonk_data.Speed / 100; + } + clonk.MaxContentsCount = 1; + // Reward for killing enemy + clonk.Bounty = clonk_data.Bounty; + // AI + AI->AddAI(clonk); + AI->SetMaxAggroDistance(clonk, Max(LandscapeWidth(), LandscapeHeight())); + var last_pos = clonk_attack_path[-1]; + AI->SetHome(clonk, last_pos.X, last_pos.Y, Random(2)); + var guard_range = clonk_data.GuardRange ?? { x=last_pos.X-300, y=last_pos.Y-150, wdt=600, hgt=300 }; + AI->SetGuardRange(clonk, guard_range.x,guard_range.y,guard_range.wdt,guard_range.hgt); + if (clonk_data.AttackMode) + { + AI->SetAttackMode(clonk, clonk_data.AttackMode.Identifier); + } + // Return clonk to be added to spawned enemy list + return clonk; +} + + +/* Display */ + +private func UpdateEnemyDisplay() +{ + // Show enemy type as text above this object + var msg; + if (enemy) + { + var enemy_def = EnemyDefs[enemy.Type]; + if (enemy_def.GetInfoString) + { + // Custom dynamic info string + msg = enemy_def->GetInfoString(enemy); + } + else if (enemy_def.InfoString) + { + // Custom fixed info string + msg = enemy_def.InfoString; + } + else if (enemy_def.SpawnType) + { + // No info string. Fall back to object ID. + msg = Format("{{%i}}", enemy_def.SpawnType); + } + else + { + // Can't happen. + msg = enemy_def.Name ?? "??"; + } + } + if (msg) Message("@%s", msg); else Message(""); +} + + +/* Editor props and actions */ + +public func Definition(def) +{ + // EditorActions + if (!def.EditorActions) def.EditorActions = {}; + def.EditorActions.Activate = { Name="$Activate$", EditorHelp = "$ActivateHelp$", Command="ActivateSpawn()" }; + def.EditorActions.Stop = { Name="$Stop$", EditorHelp = "$StopHelp$", Command="CancelSpawn()" }; + def.EditorActions.RemoveSpawnedEnemies = { Name="$RemoveSpawnedEnemies$", EditorHelp = "$RemoveSpawnedEnemiesHelp$", Command="RemoveSpawnedEnemies()" }; + // UserActions + UserAction->AddEvaluator("Action", "$Name$", "$ActActivate$", "$ActivateHelp$", "enemy_spawn_set_active", [def, def.EvalAct_Activate], { Target = { Function="action_object" } }, { Type="proplist", EditorProps = { + Target = UserAction->GetObjectEvaluator("IsEnemySpawn", "$Name$") + } } ); + UserAction->AddEvaluator("Action", "$Name$", "$ActStop$", "$StopHelp$", "enemy_spawn_stop", [def, def.EvalAct_Stop], { Target = { Function="action_object" } }, { Type="proplist", EditorProps = { + Target = UserAction->GetObjectEvaluator("IsEnemySpawn", "$Name$") + } } ); + // EditorProps + if (!def.EditorProps) def.EditorProps = {}; + def.EditorProps.spawn_position = { Name="$SpawnPosition$", Type="enum", OptionKey="Mode", Set="SetSpawnPosition", Save="SpawnPosition", Options = [ + { Name="$Here$" }, + { Name="$InRange$", EditorHelp="$SpawnInRangeHelp$", Value={ Mode="range", Radius=25 }, ValueKey="Radius", Delegate={ Type="circle", Color=0xff8000, Relative=true } }, + { Name="$InRect$", EditorHelp="$SpawnInRectHelp$", Value={ Mode="rectangle", Rect=[-20, -20, 40, 40] }, ValueKey="Rect", Delegate={ Type="rect", Color=0xff8000, Relative=true } } + ] }; + def.EditorProps.spawn_count = { Name="$SpawnCount$", EditorHelp="$SpawnCountHelp$", Type="enum", Set="SetSpawnCount", Save="SpawnCount", Options = [ + { Name="$Infinite$", Value=SPAWNCOUNT_INFINITE }, + { Name="$FixedNumber$", Value=1, Type=C4V_Int, Delegate={ Type="int", Min=1, Set="SetSpawnCount", SetRoot=true } } + ] }; + def.EditorProps.spawn_delay = { Name="$SpawnDelay$", EditorHelp="$SpawnDelayHelp$", Type="int", Min=0, Set="SetSpawnDelay", Save="SpawnDelay" }; + def.EditorProps.spawn_interval = { Name="$SpawnInterval$", EditorHelp="$SpawnIntervalHelp$", Type="int", Min=0, Set="SetSpawnInterval", Save="SpawnInterval" }; + //def.EditorProps.attack_path + def.EditorProps.auto_activate = { Name="$AutoActivate$", EditorHelp="$AutoActivateHelp$", Type="bool", Set="SetAutoActivate", Save="AutoActivate" }; + AddEnemyDef("Clonk", { SpawnType=Clonk, SpawnFunction=def.SpawnClonk }, def->GetAIClonkDefaultPropValues(), def->GetAIClonkEditorProps() ); +} + +public func GetAIClonkEditorProps() +{ + // Return an editor props delegate for AI clonks + if (!this.AIClonkEditorProps) + { + var props = {}; + props.AttackMode = new AI.FxAI.EditorProps.attack_mode { Set=nil, Priority=100 }; + props.GuardRange = { Name="$AttackRange$", EditorHelp="$AttackRangeHelp$", Type="enum", Options = [ + { Name="$Automatic$", EditorHelp="$AutomaticGuardRangeHelp$"}, + { Name="$Custom$", Type=C4V_PropList, Value={}, DefaultValueFunction=this.GetDefaultAIRect, Delegate=AI.FxAI.EditorProps.guard_range } + ] }; + props.Color = { Name="$Color$", Type="color" }; + props.Bounty = { Name="$Bounty$", EditorHelp="$BountyHelp$", Type="int", Min=0, Max=100000 }; + props.ScaleX = { Name="$ScaleX$", EditorHelp="$ScaleXHelp$", Type="int", Min=50, Max=1000 }; + props.ScaleY = { Name="$ScaleY$", EditorHelp="$ScaleYHelp$", Type="int", Min=50, Max=1000 }; + props.Speed = { Name="$Speed$", EditorHelp="$SpeedHelp$", Type="int", Min=5 }; + props.Energy = { Name="$Energy$", EditorHelp="$EnergyHelp$", Type="int", Min=1, Max=100000 }; + props.Backpack = { Name="$Backpack$", EditorHelp="$BackpackHelp$", Type="bool" }; + this.AIClonkEditorProps = { Type="proplist", Name=Clonk->GetName(), EditorProps=props }; + } + return this.AIClonkEditorProps; +} + +public func GetAIClonkDefaultPropValues() +{ + // Default settings for AI enemy clonks + return { + AttackMode = { Identifier="Sword" }, + Color = 0xff0000, + Bounty = 0, + ScaleX = 100, + ScaleY = 100, + Speed = 100, + Energy = 50, + Backpack = true, + }; +} + +private func SetAIClonkAttackMode(proplist attack_mode) +{ + this.AttackMode.Identifier = attack_mode.Identifier; +} + +private func GetDefaultAIRect(object target_object, proplist props) +{ + // Default attack rectangle around spawner + var r = {}; + if (target_object) + { + r.x = target_object->GetX()-300; + r.y = target_object->GetY()-150; + r.wdt = 600; + r.hgt = 300; + } + return r; +} + +public func AddEnemyDef(identifier, enemy_def, default_value, parameter_delegate) +{ + // First-time setup of enemy selection in editor + if (!this.EditorProps) this.EditorProps = {}; + if (!this.EditorProps.enemy) this.EditorProps.enemy = { Name="$Enemy$", EditorHelp="$EnemyHelp$", Type="enum", OptionKey="Type", Set="SetEnemy", Save="Enemy", Sorted=true, Options = [ { Name="$None$", Priority=100 } ] }; + if (!this.EnemyDefs) this.EnemyDefs = {}; + // Remember definition + this.EnemyDefs[identifier] = enemy_def; + // Add editor selection + if (!default_value) default_value = {}; + default_value.Type = identifier; + var enemy_opt = { + Name=enemy_def.Name ?? enemy_def.SpawnType->GetName(), + EditorHelp=enemy_def.EditorHelp, + Delegate=parameter_delegate, + Value=default_value + }; + var opts = this.EditorProps.enemy.Options; + opts[GetLength(opts)] = enemy_opt; +} + +private func EvalAct_Activate(proplist props, proplist context) +{ + // User action: Activate spawner. + var spawner = UserAction->EvaluateValue("Object", props.Target, context); + if (!spawner || !spawner->IsEnemySpawn()) + { + return; + } + spawner->ActivateSpawn(); +} + +private func EvalAct_Stop(proplist props, proplist context) +{ + // User action: Cancel spawner activation. + var spawner = UserAction->EvaluateValue("Object", props.Target, context); + if (!spawner || !spawner->IsEnemySpawn()) + { + return; + } + spawner->CancelSpawn(); +} diff --git a/planet/Objects.ocd/Helpers.ocd/EnemySpawn.ocd/StringTblDE.txt b/planet/Objects.ocd/Helpers.ocd/EnemySpawn.ocd/StringTblDE.txt new file mode 100644 index 000000000..e16758102 --- /dev/null +++ b/planet/Objects.ocd/Helpers.ocd/EnemySpawn.ocd/StringTblDE.txt @@ -0,0 +1,48 @@ +Name=Gegnerspawn +Description=Erzeugt, wenn aktiviert, einen order mehrere KI-gesteuerte Gegner, die die Spieler angreifen. +Activate=Aktivieren +ActivateHelp=Startet das Erzeugen von Gegnern. +Stop=Deaktivieren +StopHelp=Stoppt das Erzeugen von Gegnern. +RemoveSpawnedEnemies=Gegner entfernen +RemoveSpawnedEnemiesHelp=Entfernt alle Gegner, die von diesem Spawner erzeugt wurden. +ActActivate=Gegnerspawn aktivieren +ActStop=Gegnerspawn deaktivieren +SpawnPosition=Position +Here=Hier +InRange=Im Radius +SpawnInRangeHelp=Zufaellige Position innerhalb eines Radius. +InRect=Im Rechteck +SpawnInRectHelp=Zufaellige Position innerhalb eines Rechtecks +SpawnCount=Anzahl +SpawnCountHelp=Zahl erzeugter Gegner. +Infinite=Unendlich +FixedNumber=Feste Anzahl +SpawnDelay=Verzoegerung +SpawnDelayHelp=Zeit in Frames zwischen dem Aktiviern dieses Spawns und dem Erzeugen des ersten Gegners. +SpawnInterval=Intervall +SpawnIntervalHelp=Zeit in Frames zwischen dem Erzeugen jedes einzelnen Gegners. +AutoActivate=Automatisch aktiviert +AutoActivateHelp=Wenn wahr, wird der Spawn beim ersten Spielerbeitritt automatisch aktiviert. +AttackRange=Angriffsbereich +AttackRangeHelp=In welchem Bereich die erzeugten Clonks nach Gegnern suchen. +Automatic=Automatisch +AutomaticGuardRangeHelp=Gegner suchen automatisch in Sichtweite ihres Zielbereiches. +Custom=Benutzerdefiniert +Color=Farbe +Bounty=Kopfgeld +BountyHelp=Clunker, die der Spieler pro getoeteten Gegner dieser Welle bekommt. +Enemy=Gegnertyp +EnemyHelp=Objekttyp des Angreifers. +None=Keiner +PlayerAttackers=Angreifer +ScaleX=Skalierung X +ScaleXHelp=Horizontale Groesse der Clonks in Prozent der Standardgroesse. +ScaleY=Skalierung Y +ScaleYHelp=Vertikale Groesse der Clonks in Prozent der Standardgroesse. +Backpack=Rucksack +BackpackHelp=Ob der Clonk einen Rucksack traegt. +Speed=Geschwindigkeit +SpeedHelp=Geschwindigkeit der Clonks in Prozent der Standardgeschwindigkeit +Energy=Energie +EnergyHelp=Lebenspunkte diff --git a/planet/Objects.ocd/Helpers.ocd/EnemySpawn.ocd/StringTblUS.txt b/planet/Objects.ocd/Helpers.ocd/EnemySpawn.ocd/StringTblUS.txt new file mode 100644 index 000000000..dbfb87d8d --- /dev/null +++ b/planet/Objects.ocd/Helpers.ocd/EnemySpawn.ocd/StringTblUS.txt @@ -0,0 +1,48 @@ +Name=Enemy Spawn +Description=When activated, spawns one or more AI-controlled enemies that attack the players. +Activate=Activate +ActivateHelp=Starts spawning of enemies. +Stop=Deactivate +StopHelp=Stops spawning of enemies. +RemoveSpawnedEnemies=Remove enemies +RemoveSpawnedEnemiesHelp=Removes all enemies created by this spawner. +ActActivate=Activate enemy spawn +ActStop=Stop enemy spawn +SpawnPosition=Position +Here=Here +InRange=In radius +SpawnInRangeHelp=Random position within a radius. +InRect=In rectangle +SpawnInRectHelp=Random position within a rectangle. +SpawnCount=Enemy count +SpawnCountHelp=Number of spawned enemies. +Infinite=Infinite +FixedNumber=Fixed number +SpawnDelay=Delay +SpawnDelayHelp=Time in frames between activation of the spawn and creation of the first enemy. +SpawnInterval=Interval +SpawnIntervalHelp=Time in frames between each enemy creation. 0 for immediate creation of all enemies. +AutoActivate=Auto-activate +AutoActivateHelp=If true, the spawner activates automatically on first player join. +AttackRange=Attack range +AttackRangeHelp=In which range created clonks should look for enemies. +Automatic=Automatic +AutomaticGuardRangeHelp=Enemies automatically search within view of their target location. +Custom=Custom +Color=Color +Bounty=Bounty +BountyHelp=Clunker awarded to the player for killing a spawned enemy of this spawner. +Enemy=Enemy type +EnemyHelp=Object type of the attacker. +None=None +PlayerAttackers=Attacker +ScaleX=Scale X +ScaleXHelp=Horizontal scaling of the spawned clonk in percent of the default size. +ScaleY=Scale Y +ScaleYHelp=Vertical scaling of the spawned clonk in percent of the default size. +Backpack=Backpack +BackpackHelp=Whether the clonk carries a backpack. +Speed=Speed +SpeedHelp=Movement speed of the clonk in percent of the default. +Energy=Energy +EnergyHelp=Life points of the spwned clonk.