' 0.42 '' Nanohost AI module '' '' EnerZeus_AI.bi - May 2006 - version 1.0 '' '' Requires NanoShips 0.42 or higher '' - Get Nanohost here: http://ecowles.dyndns.org/Nano '' '' Contact info for coderJeff: '' coderJeff@execulink.com '' http://frontpage.execulink.com/coder/ '' '' This file: '' http://www.execulink.com/~coder/nanoships/EnerZeus_AI.bi '' FUNCTION EnerZeus_AI ( BYVAL ShipData AS ShipData, _ Flag() AS DOUBLE) AS MessageAI ' Hold the return MessageAI DIM AS MessageAI ReturnAI '' flags '' 0 - Mode '' 1 - Last Ship X '' 2 - Last Ship Y '' 3 - Last Enemy X '' 4 - Last Enemy Y '' 5 - Last Laser X '' 6 - Last Laser Y '' 7 - mode counter dim as double shx, shy '' Ship's heading as an X,Y Coord dim as double VX, VY '' ship's velocity as delta X,Y dim as double ShipV '' ship's velocity dim as double EnemyAngle '' relative angle of ship heading to enemy position dim as double EnemyDist '' distance between ship position and enemy dim as double EnemyDX, EnemyDY '' Enemy's position as delta X,Y relative to ship's position dim as double EnemyVX, EnemyVY '' Enemy's velocity as delta X,Y dim as double EnemyVMag '' Magnitude of Enemy's velocity dim as integer IsLaserActive = 0 '' Set to non-zero when a laser is active dim as double LaserDX, LaserDY '' Laser's position as delta X,Y relative to ship's position dim as double LaserVX, LaserVY '' Laser velocity as delta X,Y dim as double LaserAngle '' relative angle of ship heading to laser position dim as double LaserDist '' distance between ship position and laser dim as integer IsTargetActive = 0 '' set to non-zero when a valid target position is calculated dim as double TargetX, TargetY '' Calculated target position dim as double TargetAngle '' Relative angle between missle/enemy rel vel and enemy position dim as double d '' misc calculations dim as double xx, yy, dx, dy '' misc coords dim as double LASER_VELOCITY = 1.0 with ShipData '' Compute ship heading as an X,Y coord shx = cos( .Angle * DEG_TO_RAD ) shy = sin( .Angle * DEG_TO_RAD ) '' Adjust the Enemy position for screen wrapping if abs(.PosX - .EnemyX) > SCRW * 0.5 then .EnemyX += sgn(.PosX - .EnemyX) * SCRW if abs(.PosY - .EnemyY) > SCRH * 0.5 then .EnemyY += sgn(.PosY - .EnemyY) * SCRH '' Compute the Enemy's relative position as a delta X,Y coord EnemyDX = .EnemyX - .PosX EnemyDY = .EnemyY - .PosY '' Compute relative angle of ship heading to enemy position, 0 = directly facing enemy EnemyAngle = atan2( -EnemyDY, EnemyDX ) * RAD_TO_DEG - .Angle if EnemyAngle < -180 then EnemyAngle += 360 if EnemyAngle > 180 then EnemyAngle -= 360 '' Compute distance between ship and enemy EnemyDist = sqr((.EnemyX - .PosX) * (.EnemyX - .PosX) + (.EnemyY - .PosY) * (.EnemyY - .PosY)) '' Compute Ship Velocity VX = .PosX - flag(1) VY = .PosY - flag(2) ShipV = sqr( VX * VX + VY * VY ) '' Compute Enemy Velocity and magnitude EnemyVX = .EnemyX - flag(3) EnemyVY = .EnemyY - flag(4) EnemyVMag = sqr( EnemyVX * EnemyVX + EnemyVY * EnemyVY ) '' Is the laser active if (.LaserX <> -1) and flag(5) <> -1 then IsLaserActive = 1 '' Compute the Laser's relative position as a delta X,Y coord LaserDX = .LaserX - .PosX LaserDY = .LaserY - .PosY '' Compute Laser Velocity LaserVX = .LaserX - flag(5) LaserVY = .LaserY - flag(6) '' Compute relative angle of ship heading to Laser position, 0 = directly facing Laser LaserAngle = atan2( -LaserDY, LaserDX ) * RAD_TO_DEG - .Angle if LaserAngle < -180 then LaserAngle += 360 if LaserAngle > 180 then LaserAngle -= 360 '' Compute Ship to Laser Distance LaserDist = sqr((.LaserX - .PosX) * (.LaserX - .PosX) + (.LaserY - .PosY) * (.LaserY - .PosY)) end if '' Compute the relative velocity between a potential missle and the enemy dx = shx * LASER_VELOCITY - EnemyVX dy = shy * LASER_VELOCITY - EnemyVY '' Compute the relative angle between the relative velocity and the angle to the enemy TargetAngle = (atan2( -dy, dx ) - atan2( -EnemyDY, EnemyDX )) * RAD_TO_DEG if TargetAngle > 180 then TargetAngle -= 360 if TargetAngle < -180 then TargetAngle += 360 '' Decide which program to execute if flag(0) = 0 then '' No program currently selected '' Is the laser active If IsLaserActive then '' Determine if the laser is a threat If LaserDist < 150 then ' Randomly select a dodge program if flag(7) = 1 then flag(0) = 2 '' Select dodge program 1 flag(7) = 30 '' number of cycles to execute else flag(0) = 1 '' Select dodge program 2 flag(7) = 30 '' number of cycles to execute end if end if end if end if '' Count down timer for the current program '' When program ends, reset selected program number to "0" flag(7) -= 1 '' Decrement program counter if flag(7) < 0 then '' less than zero? flag(0) = 0 '' select program #0 (default) flag(7) = 1 '' program counter will toggle 0/1 end if '' If a program is selected, then execute it select case flag(0) case 1 '' DODGE PROGRAM If abs(TargetAngle) < 1 then ReturnAI.Message = "Die mortal!" ReturnAI.Action = SHOOT flag(0) = 3 '' switch to program #3 flag(7) = 35 else '' alternate between turning and thrusting if flag(7) mod 2 = 0 then ReturnAI.Action = TURNCW else ReturnAI.Action = BACKTHRUST end if end if ReturnAI.Message = "You shall not destroy me.." case 2 '' DODGE PROGRAM If abs(TargetAngle) < 1 then ReturnAI.Message = "Die mortal!" ReturnAI.Action = SHOOT flag(0) = 3 flag(7) = 35 else '' alternate between turning and thrusting if flag(7) mod 2 = 0 then ReturnAI.Action = TURNCCW else ReturnAI.Action = BACKTHRUST end if end if ReturnAI.Message = "You shall not destroy me.." case 3 '' BACK PROGRAM ReturnAI.Message = "You shall not survive!" ReturnAI.Action = BACKTHRUST case else if TargetAngle > 1 then ReturnAI.Action = TURNCW elseif TargetAngle < -1 then ReturnAI.Action = TURNCCW else if .Power > 95 and EnemyDist < 225 then ReturnAI.Message = "You shall fall now!" ReturnAI.Action = SHOOT elseif .Power > 50 and EnemyDist < 125 then ReturnAI.Message = "Feel my wrath!" ReturnAI.Action = SHOOT elseif .Power > 25 and EnemyDist < 75 then ReturnAI.Message = "Die mortal!" ReturnAI.Action = SHOOT elseif .Power < 25 or EnemyDist < 150 then ReturnAI.Message = "My strength shall soon return." ReturnAI.Action = BACKTHRUST elseif EnemyDist > 300 then ReturnAI.Message = "Your end is near." ReturnAI.Action = THRUST elseif ShipV < 0.5 then ReturnAI.Message = "Come to me, coward." ReturnAI.Action = THRUST end if end if end select if( .Status = VICTORY ) then if .Health < 25 then ReturnAI.Message = "You have met your fate well." else ReturnAI.Message = "I send you to the underworld." end if end if if( .Status = DEFEAT ) then ReturnAI.Message = "I shall return to defeat you..." end if '' Save Values for next AI call flag(1) = .PosX flag(2) = .PosY flag(3) = .EnemyX flag(4) = .EnemyY flag(5) = .LaserX flag(6) = .LaserY end with RETURN ReturnAI END FUNCTION FUNCTION EnerZeus_DrawLaser ( BYVAL LaserData AS DrawLaserData ) AS INTEGER dim as double x, y, c1, c2, c3, s1, s2, s3, a with LaserData a = 15 + rnd * 30 c1 = cos( (.Angle - a) * DEG_TO_RAD ) s1 = sin( (.Angle - a) * DEG_TO_RAD ) c2 = cos( (.Angle) * DEG_TO_RAD ) s2 = sin( (.Angle) * DEG_TO_RAD ) c3 = cos( (.Angle + a) * DEG_TO_RAD ) s3 = sin( (.Angle + a) * DEG_TO_RAD ) Pset ( .PosX , .PosY ) line -( .PosX + c1 * 4, .PosY + s1 * 4 ) line -( .PosX + c3 * 3, .PosY + s3 * 3 ) line -( .PosX + c2 * 7, .PosY + s2 * 7 ) end with END FUNCTION FUNCTION EnerZeus_DrawShip ( BYVAL ShipData AS DrawShipData ) AS INTEGER '' These two macros allow using X,Y coords to draw the ship '' +X is right of ship heading, -X is left of ship heading '' +Y is forward , -Y is behind #define EnerZeus_Pset(_x, _y, _c) Pset ( x + c * (_y) - s * (_x), y + s * (_y) + c * (_x)), _c #define EnerZeus_Line(_x, _y, _c) Line -( x + c * (_y) - s * (_x), y + s * (_y) + c * (_x)), _c dim as double c, s, x, y, x1, y1, x2, y2, a dim as integer d with ShipData '' The direction of the ship as X,Y coords c = cos(.Angle * DEG_TO_RAD) s = sin(.Angle * DEG_TO_RAD) '' x,y is the local origin to draw at x = .PosX y = .PosY '' x1,y1 and x2,y2 are the "wing-tips" to draw the maneuvering gfx x1 = x + c * (-2) - s * (8) y1 = y + s * (-2) + c * (8) x2 = x + c * (-2) - s * (-8) y2 = y + s * (-2) + c * (-8) '' Draw the body starting at the front EnerZeus_Pset ( 0, 8, .Colour) '' draw right side EnerZeus_Line ( 4, 2, .Colour) EnerZeus_Line ( 2, 2, .Colour) EnerZeus_Line ( 8, -2, .Colour) EnerZeus_Line ( 2, -2, .Colour) EnerZeus_Line ( 4, -8, .Colour) '' the stern EnerZeus_Line ( 0, -6, .Colour) '' back up the left side EnerZeus_Line (-4, -7, .Colour) EnerZeus_Line (-2, -2, .Colour) EnerZeus_Line (-8, -2, .Colour) EnerZeus_Line (-2, 2, .Colour) EnerZeus_Line (-4, 2, .Colour) '' close on the front of the ship EnerZeus_Line ( 0, 8, .Colour) '' set some bits that indicate which extra gfx to draw '' bit 0 = 1 - Right back thruster '' bit 1 = 2 - Right thruster '' bit 2 = 4 - Left back thruster '' bit 3 = 5 - Left thruster select case .Action case THRUST d = 5 case TURNCW d = 6 case TURNCCW d = 9 case BACKTHRUST d = 10 case SHOOT d = 15 end select if d and 1 then x = x1: y = y1 c = cos((.Angle + 150 ) * DEG_TO_RAD) s = sin((.Angle + 150 ) * DEG_TO_RAD) EnerZeus_Pset ( 0, 0, 15) EnerZeus_Line (-1, 5, 15) EnerZeus_Line ( 1, 4, 15) EnerZeus_Line ( 0, 7, 15) end if if d and 2 then x = x1: y = y1 c = cos((.Angle + 30 ) * DEG_TO_RAD) s = sin((.Angle + 30 ) * DEG_TO_RAD) EnerZeus_Pset ( 0, 0, 15) EnerZeus_Line (-1, 5, 15) EnerZeus_Line ( 1, 4, 15) EnerZeus_Line ( 0, 7, 15) end if if d and 4 then x = x2: y = y2 c = cos((.Angle - 150 ) * DEG_TO_RAD) s = sin((.Angle - 150 ) * DEG_TO_RAD) EnerZeus_Pset ( 0, 0, 15) EnerZeus_Line (-1, 5, 15) EnerZeus_Line ( 1, 4, 15) EnerZeus_Line ( 0, 7, 15) end if if d and 8 then x = x2: y = y2 c = cos((.Angle - 30 ) * DEG_TO_RAD) s = sin((.Angle - 30 ) * DEG_TO_RAD) EnerZeus_Pset ( 0, 0, 15) EnerZeus_Line (-1, 5, 15) EnerZeus_Line ( 1, 4, 15) EnerZeus_Line ( 0, 7, 15) end if '' if power is more than 80, then draw a center bolt if .Power > 80 then x = .PosX y = .PosY a = .Angle * DEG_TO_RAD c = cos(a) s = sin(a) EnerZeus_Pset ( 0,-2, 15) EnerZeus_Line (-1, 3, 15) EnerZeus_Line ( 1, 2, 15) EnerZeus_Line ( 0, 5, 15) end if end with '' undefine our macros, not needed anymore #undef EnerZeus_Pset #undef EnerZeus_Line END FUNCTION AI( AI_ID ).Callsign = "EnerZeus" AI( AI_ID ).Colour = 14 AI( AI_ID ).AI = @EnerZeus_AI AI( AI_ID ).DrawShip = @EnerZeus_DrawShip AI( AI_ID ).DrawLaser = @EnerZeus_DrawLaser AI( AI_ID ).WeaponName = "Electros" + "tatic Discharge Concentrator" AI( AI_ID ).ShipDetails = "Overconfidence may be this adversary's " _ + "best stength and worst weakness."