/** * Command for spawning new entities into the world. * Copyright 2022 Anton Tarasenko *------------------------------------------------------------------------------ * This file is part of Acedia. * * Acedia is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 3 of the License, or * (at your option) any later version. * * Acedia is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Acedia. If not, see . */ class ACommandSpawn extends Command; // TODO: use spawned name for errors output? var private ACommandSpawn_Announcer announcer; protected function Finalizer() { _.memory.Free(announcer); super.Finalizer(); } protected function BuildData(CommandDataBuilder builder) { builder.Group(P("debug")); builder.Summary(P("Spawns new entity on the map.")); builder.ParamText(P("template"),, P("entity")); builder.Describe(P("Spawns new entity based on the given template at the point" @ "player is currently looking at.")); builder.SubCommand(P("at")); builder.ParamText(P("template"),, P("entity")); builder.ParamNumber(P("x")); builder.ParamNumber(P("y")); builder.ParamNumber(P("z")); builder.Describe(P("Spawns new entity based on the given template at" @ "the point, given by the coordinates")); announcer = ACommandSpawn_Announcer( _.memory.Allocate(class'ACommandSpawn_Announcer')); } protected function Executed( CallData arguments, EPlayer instigator, CommandPermissions permissions ) { local HashTable value; local Vector spawnLocation; announcer.Setup(none, instigator, othersConsole); value = arguments.parameters.GetHashTable(P("template")); if (arguments.subCommandName.IsEmpty()) { SpawnInInstigatorSight(instigator, value); } else if (arguments.subCommandName.Compare(P("at"), SCASE_INSENSITIVE)) { spawnLocation.x = arguments.parameters.GetFloat(P("x")); spawnLocation.y = arguments.parameters.GetFloat(P("y")); spawnLocation.z = arguments.parameters.GetFloat(P("z")); SpawnAt(instigator, value, spawnLocation); } _.memory.Free(value); } private final function SpawnAt( EPlayer instigator, HashTable value, Vector spawnLocation ) { local Text humanReadable, template; local EPlaceable result; humanReadable = value.GetText(P("alias")); template = value.GetText(P("value")); result = _server.kf.world.Spawn(template, spawnLocation); if (result != none) { announcer.AnnounceSpawned(humanReadable); } else { announcer.AnnounceSpawningFailed(humanReadable); } _.memory.Free2(humanReadable, result); } private final function SpawnInInstigatorSight( EPlayer instigator, HashTable value ) { local EPlaceable result; local Vector spawnLocation; local TracingIterator iter; local Text humanReadable, template; humanReadable = value.GetText(P("alias")); template = value.GetText(P("value")); iter = _server.kf.world.TracePlayerSight(instigator); iter.LeaveOnlyVisible(); if (iter.HasFinished()) { announcer.AnnounceFailedTrace(); return; } spawnLocation = iter.GetHitLocation(); result = _server.kf.world.Spawn(template, spawnLocation); // Shift position back a little and try again; // this should fix a ton of spawning failures if (result == none) { spawnLocation = spawnLocation + Normal(iter.GetTracingStart() - spawnLocation) * 100; result = _server.kf.world.Spawn(template, spawnLocation); } if (result != none) { announcer.AnnounceSpawned(humanReadable); } else { announcer.AnnounceSpawningFailed(humanReadable); } _.memory.Free4(result, iter, humanReadable, result); } defaultproperties { preferredName = "spawn" }