All pastes #1465915 Raw Edit

Mine

public text v1 · immutable
#1465915 ·published 2009-06-19 06:47 UTC
rendered paste body
/*
	The ratter object

	The obj_Ratter object is a bot module designed to be used with
	EVEBOT.  The ratter bot will warp from belt to belt and wtfbbqpwn
	any NPC ships it finds.

	-- GliderPro
*/

objectdef obj_Ratter
{
	variable string SVN_REVISION = "$Rev: 1207 $"
	variable int Version

	variable string CurrentState
	variable time NextPulse
	variable int PulseIntervalInSeconds = 5
	variable float RatWaitCounter
	
	/* Cache for NPCs */
	variable obj_EntityCache RatCache
	variable index:int DoNotKillList
	
	/* Used for calculating battleship chain values */
	variable obj_Targets_Rats RatCalculator
	
	variable bool bPlayerCheck
	
	/* Todo: This, IsOrbiting, and Orbit should all probably be moved to a movement object. -- stealthy */
	variable int iEntityOrbiting
	variable int iEntityKeepingAtRange

	method Initialize()
	{
		Event[OnFrame]:AttachAtom[This:Pulse]
		
		BotModules:Insert["Ratter"]

		RatCache:SetUpdateFrequency[1]
		RatCache:UpdateSearchParams["Unused","CategoryID,CATEGORYID_ENTITY"]

		; Startup in fight mode, so that it checks current belt for rats, if we happen to be in one.
		This.CurrentState:Set["FIGHT"]

		UI:UpdateConsole["obj_Ratter: Initialized", LOG_MINOR]
	}


	method Pulse()
	{
		if !${Config.Common.BotMode.Equal[Ratter]}
		{
			return
		}

	  if ${Time.Timestamp} >= ${This.NextPulse.Timestamp}
		{
			if !${EVEBot.Paused}
			{
				This:SetState[]
			}
			
			bPlayerCheck:Set[${Targets.PC}]

    	This.NextPulse:Set[${Time.Timestamp}]
    	This.NextPulse.Second:Inc[${This.PulseIntervalInSeconds}]
    	This.NextPulse:Update
		}
	}

	method Shutdown()
	{
		Event[OnFrame]:DetachAtom[This:Pulse]
	}

	/* NOTE: The order of these if statements is important!! */

	;; STATE MACHINE:  * -> IDLE -> MOVE -> PCCHECK -> FIGHT -> *
	method SetState()
	{
		UI:UpdateConsole["obj_Ratter: Hiding: ${Defense.Hiding}, Hide Reason: ${Defense.HideReason}",LOG_DEBUG]
		if ${Defense.Hiding}
		{
			This.CurrentState:Set["IDLE"]
			return
		}

		if ${Me.InStation} == TRUE
		{
			This.CurrentState:Set["INSTATION"]
			return
		}

		UI:UpdateConsole["obj_Ratter: NPC Check: ${This.NPCCheck}",LOG_DEBUG]
		if ${Me.GetTargets} > 0 || (${This.NPCCheck} && !${Targets.PC})
		{
			This.CurrentState:Set["FIGHT"]
		}
		else
		{
			This.CurrentState:Set["STATE_CHANGE_BELT"]
		}
	}

	function ProcessState()
	{
		if !${Config.Common.BotMode.Equal[Ratter]}
		{
			return
		}
		UI:UpdateConsole["obj_Ratter: Processing State: ${This.CurrentState}",LOG_DEBUG]
		;UI:UpdateConsole["DEBUG: ${This.CurrentState}"]
		switch ${This.CurrentState}
		{
			case STATE_WAIT_WARP
				break
			case STATE_IDLE
				break
			case STATE_ABORT
				Call Station.Dock
				break
			case INSTATION
			case STATE_DOCKED
				if !${Defense.Hiding}
				{
					; TODO - this could cause dock/redock loops if armor or hull are below minimums, or if drones are still in shortage state -- CyberTech
					call Station.Undock
				}
				break
			case IDLE
				; if we're idle (defense was hiding) but defense is no longer hiding; set state to change belt so that we don't freeze up.
				if !${Defense.Hiding}
				{
					UI:UpdateConsole["obj_Ratter: We were hiding but no longer are; setting state to change belt.",LOG_CRITICAL]
					This.CurrentState:Set[STATE_CHANGE_BELT]
				}
				break
			case STATE_CHANGE_BELT
				Offense:Disable
				; TODO - check for use of belt bookmark object instead - CyberTech
				;if ${Config.Miner.UseFieldBookmarks}
				;{
				;	call BeltBookmarks.WarpToNext
				;}
				;else
				;{
					call Belts.WarpToNext
				;}
				Ship:Activate_SensorBoost
				This.CurrentState:Set["WAITING_FOR_RATS_1"]
				break
			case WAITING_FOR_RATS_1
				This.RatWaitCounter:Inc[0.5]
				if ${Targets.PC}
				{
					This.CurrentState:Set["STATE_CHANGE_BELT"]
				}
				elseif ${This.NPCCheck}
				{
					This.CurrentState:Set["WAITING_FOR_RATS_2"]
				}
				elseif ${This.RatWaitCounter} > 30
				{
					UI:UpdateConsole["Rats didn't show up, moving"]
					This.CurrentState:Set["STATE_CHANGE_BELT"]
				}
				else
				{
					wait 0.5
				}
				break
			case WAITING_FOR_RATS_2
				if ${This.RatWaitCounter} > 1
				{
					; If we had to wait for rats, Wait another second to try to let them get into range/out of warp
					wait 10
				}
				This.RatWaitCounter:Set[0]
				This.CurrentState:Set["FIGHT"]
				break
			case FIGHT
				variable bool bEntityFollowingExists = FALSE
				if ${Me.ToEntity.Following(exists)}
				{
					bEntityFollowingExists:Set[TRUE]
				}
				if !${Offense.Running}
				{
					Offense:Enable
				}
				if !${Targeting.Running}
				{
					Targeting:Enable
				}
				
				This:QueueTargets      
				/* Don't worry about orbiting or keeping at range if we're a missile boat */
				/* Todo: remove this, "It's dangerous in belts" */
				UI:UpdateConsole["obj_Ratter: Me.ActiveTarget(exists): ${Me.ActiveTarget(exists)}, Me.ToEntity.FollowRange: ${Me.ToEntity.FollowRange}, bEntityFollowingExists: ${bEntityFollowingExists}",LOG_DEBUG]
				if !${Config.Combat.ShouldUseMissiles} && ${Me.ActiveTarget(exists)} && \
					((${Me.ToEntity.FollowRange} == 0) || !${bEntityFollowingExists})
				{
               
					Me.ActiveTarget:KeepAtRange[${Ship.GetMinimumTurretRange[1]}]
				}
            
				break
			case STATE_ERROR
				UI:UpdateConsole["CurrentState is ERROR"]
				break
			default
				UI:UpdateConsole["Error: CurrentState is unknown value ${This.CurrentState}"]
				break
		}
	}

	function Move()
	{

		call Belts.WarpToNext

		; TODO - CyberTech - Make this a proper solution instead of this half-ass piss
		; Wait for the rats to warp into the belt. Reports are between 10 and 20 seconds.
		/* I plan to at the very least align to the next belt before waiting so that we'll
		be aligned and ready to go in case nothing shows up after our 30-second waitfest or
		social suddenly becomes unsafe. */
		variable int Count
		for (Count:Set[0] ; ${Count}<=30 ; Count:Inc)
		{
			if ${Targets.PC} || ${This.NPCCheck}
			{
				break
			}
			wait 10
		}

		if (${Count} > 1)
		{
			; If we had to wait for rats, Wait another second to try to let them get into range/out of warp
			wait 10
		}
	}

	/* QueueTargets(): Handle any queueing, prioritizing, chaining, etc. of rats.
		This will do pretty much nothing but queue targets. */
	method QueueTargets()
	{
		/* Activate any sensor boosters */
		Ship:Activate_SensorBoost
		
		/* Get total battleship value for chaining purposes */
		variable int iTotalBSValue = ${RatCalculator.CalcTotalBattleShipValue}
		
		variable bool bHavePriorityTarget = FALSE
		variable bool bHaveSpecialTarget = FALSE
		variable bool bHaveMultipleTypes = FALSE
		variable bool iTempTypeID
		
		RatCache.Entities:GetIterator[RatCache.EntityIterator]
		
		/* Start iterating through */
		if ${RatCache.EntityIterator:First(exists)}
		{
			do
			{
				/* Check for multiple types (if we only have one type of rat it's likely an in-progress chain) */
				if ${iTempTypeID} == 0
				{
					iTempTypeID:Set[${RatCache.EntityIterator.Value.TypeID}]
				}
				if ${iTempTypeID} != ${RatCache.EntityIterator.Value.TypeID}
				{
					bHaveMultipleTypes:Set[TRUE]
				}
					
				/* If this target is already queue in any way, continue on. */
				if ${Targeting.IsQueued[${RatCache.EntityIterator.Value.ID}]} || ${Targeting.IsMandatoryQueued[${RatCache.EntityIterator.Value.ID}]} || \
					${Offense.IsConcordTarget[${RatCache.EntityIterator.Value.GroupID}]} || ${This.IsDoNotKill[${RatCache.EntityIterator.Value.ID}]}
				{
					if ${Targeting.IsMandatoryQueued[${RatCache.EntityIterator.Value.ID}]}
					{
						bHavePriorityTarget:Set[TRUE]
					}
					UI:UpdateConsole["obj_Ratter: ${RatCache.EntityIterator.Value.ID} is queued, concord, or DNK, skipping in priority target iteration.", LOG_DEBUG]
					continue
				}
				
				/* Is our target a "priority" target? If so, we won't continue with the rest of the targeting/chaining until
				all priority targets are dead. Gotta kill those scrambling bastards... */
				if ${Targets.IsPriorityTarget[${RatCache.EntityIterator.Value.Name}]}
				{
					UI:UpdateConsole["obj_Ratter: We have a priority target: ${RatCache.EntityIterator.Value.Name}."]
					bHavePriorityTarget:Set[TRUE]
					/* Queue[ID, Priority, TypeID, Mandatory] */
					/* Queue it mandatory so we make sure it dies. */
					UI:UpdateConsole["obj_Ratter: Queueing priority target: ${RatCache.EntityIterator.Value.Name}"]
					Targeting:Queue[${RatCache.EntityIterator.Value.ID},0,${RatCache.EntityIterator.Value.TypeID},TRUE,TRUE]
				}
			}
			while ${RatCache.EntityIterator:Next(exists)}
		}
		
		; If I have a priority target, just return. Targeting will lock both mandatory and non-mandatory at the same time, which is bad(tm)
		if ${bHavePriorityTarget}
		{
			return
		}
		
		/* Now for the fun task of figuring out chaining. */
		/* If I'm chaining spawns and either I'm chaining solo or I'm not chaining solo but there are others here... */
		/* I also only want to actually chain it if the calculated BS value is above our threshold */
		if (${Config.Combat.ChainSpawns} || (${Config.Combat.ChainSolo} && ${EVE.LocalsCount} == 1)) && \
			${iTotalBSValue} >= ${Config.Combat.MinChainBounty}
		{
			/* Start iterating... */
			if ${RatCache.EntityIterator:First(exists)}
			{
				do
				{
					; If the target is already queued, just continue.
					if ${Targeting.IsQueued[${RatCache.EntityIterator.Value.ID}]} || ${Offense.IsConcordTarget[${RatCache.EntityIterator.Value.GroupID}]} || \
						${This.IsDoNotKill[${RatCache.EntityIterator.Value.ID}]}
					{
						UI:UpdateConsole["obj_Ratter: ${RatCache.EntityIterator.Value.ID} already queued, concord, or DNK, skipping", LOG_DEBUG]
						continue
					}

					; Since we're chaining, if it isn't a special spawn or a battleship, and we've already queued any priority targets, we don't want it.
					; Add it to do not kill.
					UI:UpdateConsole["obj_Ratter: Find Battleship? Name: ${RatCache.EntityIterator.Value.Name}, Group: ${RatCache.EntityIterator.Value.Group}, Exists? ${RatCache.EntityIterator.Value.Group.Find["Battleship"](exists)}, Mutli? ${bHaveMultipleTypes}", LOG_DEBUG]
					if !${RatCache.EntityIterator.Value.Group.Find["Battleship"](exists)} && !${Targets.IsSpecialTarget[${RatCache.EntityIterator.Value.Name}]}
					{
						UI:UpdateConsole["obj_Ratter: ${RatCache.EntityIterator.Value.Name} isn't a battleship or special target -- adding to DNK list.", LOG_DEBUG]
						DoNotKillList:Insert[${RatCache.EntityIterator.Value.ID}]
						continue
					}
					
					; If we have a special target, queue it higher priority.
					; Currently it does nothing because combat doesn't detect "higher priority" targets
					if ${Targets.IsSpecialTarget[${RatCache.EntityIterator.Value.Name}]}
					{
						UI:UpdateConsole["obj_Ratter: Queueing special target ${RatCache.EntityIterator.Value.Name}, ${RatCache.EntityIterator.Value.ID}.",LOG_CRITICAL]
						if ${Config.Common.UseSound}
						{
							Sound:PlayDetectSound
						}
						Targeting:Queue[${RatCache.EntityIterator.Value.ID},1,${RatCache.EntityIterator.Value.TypeID},FALSE]
						continue
					}

					; Basically, the only way we get this far is our entity is a battleship we haven't queued.
					; So queue it!
					UI:UpdateConsole["obj_Ratter: Queueing chainable battleship ${RatCache.EntityIterator.Value.Name}",LOG_DEBUG]
					Targeting:Queue[${RatCache.EntityIterator.Value.ID},2,${RatCache.EntityIterator.Value.TypeID},FALSE]
				}
				while ${RatCache.EntityIterator:Next(exists)}
			}
		}
		else
		{
			if ${RatCache.EntityIterator:First(exists)}
			{
				do
				{
					; If the target is already queued, just continue.
					if ${Targeting.IsQueued[${RatCache.EntityIterator.Value.ID}]} || ${Offense.IsConcordTarget[${RatCache.EntityIterator.Value.GroupID}]} || \
						${This.IsDoNotKill[${RatCache.EntityIterator.Value.ID}]}
					{
						UI:UpdateConsole["obj_Ratter: ${RatCache.EntityIterator.Value.ID} already queued, concord, or DNK, skipping", LOG_DEBUG]
						continue
					}
					
					; If we have a special target, queue it higher priority.
					; Currently it does nothing because combat doesn't detect "higher priority" targets
					if ${Targets.IsSpecialTarget[${RatCache.EntityIterator.Value.Name}]}
					{
						UI:UpdateConsole["obj_Ratter: Not chaining, queueing special target ${RatCache.EntityIterator.Value.Name}, ${RatCache.EntityIterator.Value.ID}.",LOG_CRITICAL]
						if ${Config.Common.UseSound}
						{
							Sound:PlayDetectSound
						}
						Targeting:Queue[${RatCache.EntityIterator.Value.ID},1,${RatCache.EntityIterator.Value.TypeID},FALSE]
						continue
					}
					
					UI:UpdateConsole["obj_Ratter: Not chaining, queueing target ${RatCache.EntityIterator.Value.Name}.",LOG_DEBUG]
					Targeting:Queue[${RatCache.EntityIterator.Value.ID},2,${RatCache.EntityIterator.Value.TypeID},FALSE]
				}
				while ${RatCache.EntityIterator:Next(exists)}
			}
		}
	}
	
	/* bool NPCCheck():
	return true if we have non-donotkill and non-concord npcs nearby and non-singletype */
	member:bool NPCCheck()
	{
		RatCache.Entities:GetIterator[RatCache.EntityIterator]
		variable bool HaveMultipleTypes = FALSE
		variable int TempTypeID
		if ${RatCache.EntityIterator:First(exists)}
		{
			do
			{
				UI:UpdateConsole["obj_Ratter: ${RatCache.EntityIterator.Value.Type} ${RatCache.EntityIterator.Value.TypeID} ${RatCache.EntityIterator.Value.Group} ${RatCache.EntityIterator.Value.GroupID}",LOG_DEBUG]
				if ${TempTypeID} == 0
				{
					TempTypeID:Set[${RatCache.EntityIterator.Value.TypeID}]
				}
				if ${TempTypeID} != ${RatCache.EntityIterator.Value.TypeID}
				{
					HaveMultipleTypes:Set[TRUE]
					break
				}
			}
			while ${RatCache.EntityIterator:Next(exists)}
		}
		UI:UpdateConsole["obj_Ratter: HaveMultipleTypes? ${HaveMultipleTypes}",LOG_DEBUG]
		if ${RatCache.EntityIterator:First(exists)}
		{
			do
			{
				if !${Offense.IsConcordTarget[${RatCache.EntityIterator.Value.GroupID}]} && \
				(${Targets.IsPriorityTarget[${RatCache.EntityIterator.Value.Name}]} || \
				${Targets.IsSpecialTarget[${RatCache.EntityIterator.Value.Name}]} || \
				(!${This.IsDoNotKill[${RatCache.EntityIterator.Value.ID}]} && ${HaveMultipleTypes}))
				{
					return TRUE
				}
			}
			while ${RatCache.EntityIterator:Next(exists)}
		}
		return FALSE
	}
	
	/* bool IsDoNotKill(int entityID): 
	return true if given entity ID is on our do not kill list, otherwise return false */
	member:bool IsDoNotKill(int entityID)
	{
		variable iterator DoNotKillIterator
		DoNotKillList:GetIterator[DoNotKillIterator]
		
		if ${DoNotKillIterator:First(exists)}
		{
			do
			{
				if ${DoNotKillIterator.Value} == ${entityID}
				{
					return TRUE
				}
			}
			while ${DoNotKillIterator:Next(exists)}
		}
		return FALSE
	}
}