Improved cnc proc/harv docking.

This commit is contained in:
Paul Chote
2011-01-02 14:34:55 +13:00
parent 9ffdce7957
commit 3674accd0c
6 changed files with 195 additions and 50 deletions

View File

@@ -0,0 +1,101 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using OpenRA.Mods.RA.Activities;
using OpenRA.Traits;
using OpenRA.Traits.Activities;
using System.Collections.Generic;
using OpenRA.Mods.RA.Move;
using OpenRA.Mods.RA;
using OpenRA.Mods.RA.Render;
using System;
namespace OpenRA.Mods.Cnc
{
public class HarvesterDockSequence : IActivity
{
enum State
{
Wait,
Dragin,
Dock,
Loop,
Undock,
Dragout
};
readonly Actor proc;
readonly Harvester harv;
readonly RenderBuilding rb;
State state;
int2 startDock;
int2 endDock;
public HarvesterDockSequence(Actor self, Actor proc)
{
this.proc = proc;
state = State.Dragin;
harv = self.Trait<Harvester>();
rb = proc.Trait<RenderBuilding>();
startDock = self.Trait<IHasLocation>().PxPosition;
endDock = proc.Trait<IHasLocation>().PxPosition + new int2(-15,8);
}
IActivity NextActivity { get; set; }
int unloadTicks = 0;
public IActivity Tick(Actor self)
{
switch (state)
{
case State.Wait:
return this;
case State.Dragin:
state = State.Dock;
return Util.SequenceActivities(new Drag(startDock, endDock, 12), this);
case State.Dock:
harv.Visible = false;
rb.PlayCustomAnimThen(proc, "dock-start", () => {rb.PlayCustomAnimRepeating(proc, "dock-loop"); state = State.Loop;});
state = State.Wait;
return this;
case State.Loop:
if (harv.TickUnload(self, proc))
state = State.Undock;
return this;
case State.Undock:
rb.PlayCustomAnimThen(proc, "dock-end", () => {harv.Visible = true; state = State.Dragout;});
state = State.Wait;
return this;
case State.Dragout:
return Util.SequenceActivities(new Drag(endDock, startDock, 12), NextActivity);
}
throw new InvalidOperationException("Invalid harvester dock state");
}
public void Cancel(Actor self)
{
state = State.Undock;
}
public void Queue( IActivity activity )
{
if( NextActivity != null )
NextActivity.Queue( activity );
else
NextActivity = activity;
}
public IEnumerable<float2> GetCurrentPath()
{
yield break;
}
}
}

View File

@@ -66,6 +66,7 @@
<Compile Include="WithRoof.cs" />
<Compile Include="Missions\CncShellmapScript.cs" />
<Compile Include="WithFire.cs" />
<Compile Include="Activities\HarvesterDockSequence.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">
@@ -97,4 +98,7 @@
copy "$(TargetPath)" "$(SolutionDir)mods/cnc/"
cd "$(SolutionDir)"</PostBuildEvent>
</PropertyGroup>
<ItemGroup>
<Folder Include="Activities\" />
</ItemGroup>
</Project>

View File

@@ -19,68 +19,63 @@ using OpenRA.Mods.RA.Move;
namespace OpenRA.Mods.Cnc
{
class TiberiumRefineryDockActionInfo : TraitInfo<TiberiumRefineryDockAction> {}
class TiberiumRefineryDockAction : IAcceptOreDockAction, INotifyDamage, INotifySold, INotifyCapture
class TiberiumRefineryDockAction : IAcceptOreDockAction, ITick, INotifyDamage, INotifySold, INotifyCapture
{
Actor dockedHarv = null;
bool preventDock = false;
public void OnDock(Actor self, Actor harv, DeliverResources dockOrder)
{
int2 startDock = harv.Trait<IHasLocation>().PxPosition;
int2 endDock = self.Trait<IHasLocation>().PxPosition + new int2(-15,8);
var mobile = harv.Trait<Mobile>();
var harvester = harv.Trait<Harvester>();
harv.QueueActivity( new Turn(112) );
if (!preventDock)
{
harv.QueueActivity( new CallFunc( () => dockedHarv = harv, false ) );
harv.QueueActivity( new HarvesterDockSequence(harv, self) );
harv.QueueActivity( new CallFunc( () => dockedHarv = null, false ) );
}
// Tell the harvester to start harvesting
// TODO: This belongs on the harv idle activity
harv.QueueActivity( new CallFunc( () =>
{
if (!preventDock)
if (harvester.LastHarvestedCell != int2.Zero)
{
dockedHarv = harv;
self.Trait<RenderBuilding>().PlayCustomAnim(self, "active");
harv.QueueActivity( new Drag(startDock, endDock, 12) );
harv.QueueActivity( new CallFunc( () =>
{
self.World.AddFrameEndTask( w1 =>
{
if (!preventDock)
harvester.Visible = false;
harvester.Deliver(harv, self);
});
}, false ) );
harv.QueueActivity( new Wait(18, false ) );
harv.QueueActivity( new CallFunc( () => harvester.Visible = true, false ) );
harv.QueueActivity( new Drag(endDock, startDock, 12) );
harv.QueueActivity( new CallFunc( () => dockedHarv = null, false ) );
if (harvester.LastHarvestedCell != int2.Zero)
{
harv.QueueActivity( mobile.MoveTo(harvester.LastHarvestedCell, 5) );
harv.SetTargetLine(Target.FromCell(harvester.LastHarvestedCell), Color.Red, false);
}
harv.QueueActivity( mobile.MoveTo(harvester.LastHarvestedCell, 5) );
harv.SetTargetLine(Target.FromCell(harvester.LastHarvestedCell), Color.Red, false);
}
harv.QueueActivity( new Harvest() );
}) );
}));
}
void CancelDock(Actor self, Actor harv)
public void Tick(Actor self)
{
// Harvester was killed while unloading
if (dockedHarv != null && dockedHarv.IsDead())
{
self.Trait<RenderBuilding>().CancelCustomAnim(self);
dockedHarv = null;
}
}
void CancelDock(Actor self)
{
preventDock = true;
if (dockedHarv == null)
return;
// invisible harvester makes ceiling cat cry
if (!harv.IsDead())
harv.Trait<Harvester>().Visible = true;
// Cancel the dock sequence
if (dockedHarv != null && !dockedHarv.IsDead())
dockedHarv.CancelActivity();
}
public void Selling (Actor self) { CancelDock(self, dockedHarv); }
public void Selling (Actor self) { CancelDock(self); }
public void Sold (Actor self) {}
public void Damaged (Actor self, AttackInfo e)
{
if (e.DamageState == DamageState.Dead)
CancelDock(self, dockedHarv);
CancelDock(self);
}
public void OnCapture (Actor self, Actor captor, Player oldOwner, Player newOwner)

View File

@@ -81,6 +81,21 @@ namespace OpenRA.Mods.RA
else contents[type.info]++;
}
// TODO: N-tick harvester unload.
// Currently unloads everything in one go
// Returns true when unloading is complete
public bool TickUnload(Actor self, Actor proc)
{
if (!proc.IsInWorld)
return false; // fail to deliver if there is no proc.
// TODO: Unload part of the load. Return false if the proc is full.
proc.Trait<IAcceptOre>().GiveOre(contents.Sum(kv => kv.Key.ValuePerUnit * kv.Value));
contents.Clear();
return true;
}
public void Deliver(Actor self, Actor proc)
{
if (!proc.IsInWorld)

View File

@@ -90,6 +90,11 @@ namespace OpenRA.Mods.RA.Render
() => { anim.PlayRepeating(NormalizeSequence(self, "idle")); a(); });
}
public void CancelCustomAnim(Actor self)
{
anim.PlayRepeating( NormalizeSequence(self, "idle") );
}
public virtual void Damaged(Actor self, AttackInfo e)
{
if (!e.DamageStateChanged)

View File

@@ -35,22 +35,47 @@ nuke:
Start: 0
Length: *
proc.proxy:
make: procmake
Start: 0
Length: *
proc:
idle:
Start: 0
active:
Start: 0
Length: 30
Length: 6
Tick: 60
enroute:
Start: 6
Length: 6
Tick: 60
dock-start:
Start: 12
Length: 7
Tick: 60
dock-loop:
Start: 19
Length: 5
Tick: 60
dock-end:
Start: 24
Length: 6
Tick: 60
damaged-idle:
Start: 30
damaged-active:
Start: 30
Length: 30
Length: 6
Tick: 60
damaged-enroute:
Start: 36
Length: 6
Tick: 60
damaged-dock-start:
Start: 42
Length: 7
Tick: 60
damaged-dock-loop:
Start: 49
Length: 5
Tick: 60
damaged-dock-end:
Start: 54
Length: 6
Tick: 60
dead:
Start: 60
make: procmake