#!/bin/sh
# -*- tcl -*-
# The next line is executed by /bin/sh, but not tcl \
exec wish "$0" ${1+"$@"}
###
# Droid Warz
#
# Written by Sean Woods
# Copyright 2008
#
# This file is released with the BSD license, yaddity, yaddity,
# no warrenty is expressed, implied, yaddity, yaddita,
# use for your own amusement at your own risk
###
# Version 0.2
#
# Changes: Braced expressions, and I threw in my proportional control
# algorithm for those who take the time to read the code
####
# SIMPLE VECTOR ROUTINES
proc pause {} {
after 100 {set wait 0}
vwait wait
}
set endgame 0
set vectorcode {
set ::pi [expr 4 * atan(1)]
namespace eval ::vector {
proc destination_angle {subject target} {
}
proc heading_normalize heading {
global pi
###
# Normalize the heading
###
while { $heading > $pi } {
set heading [expr [list $heading - (2.0 * $pi)]]
}
while { $heading < -$pi} {
set heading [expr [list $heading + (2.0 * $pi)]]
}
return $heading
}
### Assumes a 3x3 matrix
proc multMatrix {a b} {
set result {{0 0 0} {0 0 0} {0 0 0}}
for {set i 0} { $i < 3 } { incr i } {
for { set j 0 } { $j < 3 } { incr j } {
for { set k 0} { $k < 3 } {incr k} {
lset result $i $j [expr [list [lindex $result $i $j] + [lindex $a $i $k] * [lindex $b $k $j]]]
}
}
}
return $result
}
proc identity_Matrix {} {
return {{1.0 0.0 0.0} {0.0 1.0 0.0} {0.0 0.0 1.0}}
}
proc translation_Matrix {translation} {
return [list \
[list 1.0 0.0 [lindex $translation 0]] \
[list 0.0 1.0 [lindex $translation 1]] \
[list 0.0 0.0 1.0]]
}
proc rotation_Matrix {angle} {
return [list \
[list [expr {cos($angle)}] [expr {-1.0 * sin($angle)}] 0.0] \
[list [expr {sin($angle)}] [expr {cos($angle)}] 0.0] \
[list 0.0 0.0 1.0]]
}
proc rotate_affine {vector angle} {
set m [rotation_Matrix $angle]
for {set i 0} {$i < 2} {incr i} {
lappend result [expr {[lindex $vector 0] * [lindex $m 0 $i] + [lindex $vector 1]*[lindex $m 1 $i] + [lindex $m 2 $i]}]
}
return $result
}
proc rotate {vector angle} {
set result {0 0}
lset result 0 [expr {[lindex $vector 0] * cos($angle) + [lindex $vector 1] * -sin($angle)}]
lset result 1 [expr {[lindex $vector 0] * sin($angle) + [lindex $vector 1] * cos($angle)}]
return $result
}
proc length {a} {
set x [lindex $a 0]
set y [lindex $a 1]
return [expr {sqrt($x*$x + $y*$y)}]
}
proc distance {a b} {
set dx [expr {[lindex $a 0] - [lindex $b 0]}]
set dy [expr {[lindex $a 1] - [lindex $b 1]}]
return [expr {sqrt($dx*$dx + $dy*$dy)}]
}
proc add {a b} {
return [list [expr {[lindex $a 0] + [lindex $b 0]}] [expr {[lindex $a 1] + [lindex $b 1]}]]
}
proc subtract {a b} {
return [list [expr {[lindex $a 0] - [lindex $b 0]}] [expr {[lindex $a 1] - [lindex $b 1]}]]
}
proc scale {a s} {
return [list [expr {[lindex $a 0] * $s}] [expr {[lindex $a 1] * $s}]]
}
}
}
eval $vectorcode
namespace eval arena {
proc init {} {
destroy .play
toplevel .play
canvas .play.c -width 800 -height 800
grid .play.c
}
proc delete name {
set c .play.c
$c delete $name
}
proc draw info {
global pi
foreach {var val} $info {set $var $val}
set c .play.c
$c delete $name
set canpos [vector::add $position {400 400}]
set angle [expr $direction]
if { $range > 0 } {
$c create oval {*}[vector::add $canpos [list -$range -$range]] {*}[vector::add $canpos [list $range $range]] -tags [list $name $class] -dash .
}
#$c bind $name [list ::arena::info show $name %x %y]
#$c bind $name [list ::arena::info hide $name %x %y]
switch $class {
carrier {
foreach p {{-1 0.5} {0.5 0.5} {1 0} {0.5 -0.5} {-1 -0.5}} {
lappend points {*}[vector::add $canpos [::vector::scale [vector::rotate $p $angle] 10]]
}
$c create polygon {*}${points} -tags [list $name $class] -fill $color
$c create text [vector::add $canpos {10 -10}] -anchor w -text $name -tags $name -font {Fixed 10}
}
drone {
foreach p {{1 0} {-1 -0.5} {-1 0.5}} {
lappend points {*}[vector::add $canpos [::vector::scale [vector::rotate $p $angle] 7.5]]
}
$c create polygon {*}${points} -tags [list $name $class] -fill $color
}
default {
$c create oval {*}[vector::add $canpos {-5 -5}] {*}[vector::add $canpos {5 5}] -tags [list $name $class] -fill $color
}
}
}
proc info {cmnd tag x y} {
set c .play.c
if { $cmnd == "show" } {
$c create text $x [expr {$y + 5}] -text $tag -tags info
}
if { $cmnd == "hide" } {
$c delete info
}
}
}
namespace eval game {
variable objects
variable protected_fields {position velocity mass power range direction spin docked team}
variable bombcount 0
variable playercolors {{} red green blue purple orange black grey}
variable playercount 0
proc dump object {
variable objects
return [lindex [array get objects $object] 1]
}
proc cset {object newstate} {
variable objects
foreach {var val} $newstate {
dict set objects($object) $var $val
}
}
proc cget {object field} {
variable objects
return [dict get $objects($object) $field]
}
proc newobj info {
variable objects
set object {
name {}
class {}
team {}
state {}
position {0 0}
velocity {0 0}
color green
range 0
weapon {}
heading 0
direction 0
spin 0
turn 0
power 0
moment 1
thrust 0
mass 0
target {}
hitpoints 1
}
foreach {var val} $info {
dict set object $var $val
}
set name [dict get $object name]
switch [dict get $object class] {
"carrier" {
dict set object mass 1000
dict set object power 75
dict set object range 100
dict set object moment 1000
dict set object hitpoints 100
for {set x 1} { $x <= 16 } {incr x} {
lappend drones $name.$x
}
dict set object docked $drones
}
"drone" {
dict set object mass 0.5
dict set object power 0.1
dict set object range 10
dict set object moment 10
dict set object hitpoints 5
switch [dict get $object weapon] {
"recon" {
dict set object moment 50
dict set object mass 1.0
dict set object range 200
}
"laser" {
dict set object mass 0.75
}
"bomb" {
dict set object moment 100
dict set object mass 1.5
}
}
}
default {
dict set object mass 0.5
}
}
set objects($name) $object
return $object
}
proc delete name {
variable objects
array unset objects $name
arena::delete $name
}
proc physics {obj} {
global pi
set result $obj
foreach {var val} $obj {
set $var $val
}
# Normalize control values
set heading [::vector::heading_normalize $heading]
dict set result heading $heading
set thrust [dict get $obj thrust]
if { $thrust > 1.0 } {
set thrust 1.0
}
if { $thrust < -1.0 } {
set thrust -1.0
}
dict set result thrust $thrust
###
# We are either turning or thrusting
###
if { abs($heading - $direction) > 0.01 } {
set maxturn [expr $power/$moment]
set turn [expr {($direction - $heading)/$moment}]
if { $maxturn > abs($turn) } {
set direction $heading
} else {
if { $direction > $heading } {
set direction [expr {$direction - $maxturn}]
} else {
set direction [expr {$direction + $maxturn}]
}
}
dict set result direction $heading
} else {
dict set result direction $heading
set p [expr {[dict get $obj power] * $thrust}]
set a [expr {$p / $mass}]
set velocity [vector::add $velocity [list [expr {$a * cos($heading)}] [expr {$a * sin($heading)}]]]
dict set result velocity $velocity
dict set result speed [::vector::length $velocity]
}
set position [vector::add $velocity $position]
dict set result position $position
return $result
}
proc update {} {
variable objects
variable protected_fields
global endgame
if { $endgame } {
return
}
###
# Update physical state of model
###
foreach {name obj} [array get objects] {
set newstate [physics $obj]
dict set newstate target {}
cset $name $newstate
::arena::draw $obj
}
###
# Update sensor picture
###
set teams {}
array unset assets
array unset targets
foreach {name obj} [array get objects] {
set position [dict get $obj position]
set range [dict get $obj range]
set team [dict get $obj team]
if { $team ni $teams } {
lappend teams $team
}
foreach {iname iobj} [array get objects] {
set iteam [dict get $iobj team]
if { $iteam == $team } continue
set ipos [dict get $iobj position]
if { [::vector::distance $position $ipos] <= $range } {
dict set targets($team) $iname position $ipos
dict set targets($team) $iname velocity [dict get $iobj velocity]
dict set targets($team) $iname team [dict get $iobj team]
dict set targets($team) $iname class [dict get $iobj class]
dict lappend targets($team) $iname source $name
}
}
dict set assets($team) $name $obj
}
foreach team $teams {
if ![info exists targets($team)] {
set targets($team) {}
}
::process_commands $team [interp eval $team [list gameturn $team $assets($team) $targets($team)]]
}
set liveteams {}
set deadteams {}
set deadites {}
foreach {name obj} [array get objects] {
if ![dict exists $obj target] continue
if { [set t [dict get $obj target]] != {} } {
::game::fire $name $t
}
}
foreach {name obj} [array get objects] {
if { [dict get $obj hitpoints] <= 0 } {
if { [dict get $obj class] == "carrier" } {
set deadteam $name
puts "team $deadteam eliminated"
foreach {a i} $assets($deadteam) {
lappend deadites $a
}
lappend deadteams $deadteam
} else {
lappend deadites $name
puts "$name destroyed"
}
} else {
if { [dict get $obj class] == "carrier" } {
lappend liveteams [dict get $obj team]
}
}
}
foreach name $deadites {
delete $name
}
if { [llength $liveteams] == 0 } {
puts "Game was a draw between $deadteams"
puts "Epic Fail"
set endgame 1
}
if { [llength $liveteams] == 1 } {
puts "Game was a won by [lindex $liveteams 0]"
puts "This sector contains high concentrations of WIN"
set endgame 1
}
}
proc dock {carrier drone} {
variable objects
if { $drone == $carrier } {
return
}
if ![info exists objects($drone)] {
return
}
set cpos [game::cget $carrier position]
set dpos [game::cget $drone position]
if { [vector::distance $cpos $dpos] > 2.0 } {
return
}
puts [list $drone docked with $carrier]
::game::delete $drone
set docked [::game::cget $carrier docked]
lappend docked $drone
::game::cset $carrier [list docked $docked]
}
proc fire {shooter target} {
###
# Does the shooter have a laser?
###
variable objects
if ![info exists objects($shooter)] return
if ![info exists objects($target)] return
set sinfo [dump $shooter]
set tinfo [dump $target]
if ![dict exists $sinfo position] return
if ![dict exists $tinfo position] return
set shots 0
if { [dict get $sinfo class] == "carrier" } {
set shots 2
}
if { [dict get $sinfo class] == "drone" && [dict get $sinfo weapon] == "laser" } {
set shots 1
}
if !$shots {
return
}
###
# Measure relative distance and velocity
###
set deltapos [::vector::distance [dict get $sinfo position] [dict get $tinfo position]]
set deltavel [::vector::distance [dict get $sinfo velocity] [dict get $tinfo velocity]]
set difficulty [expr {($deltapos * $deltapos) * (.001 + $deltavel * $deltavel)}]
###
# The probability starts at 100, divided by the distance and relative velocty
###
# Carriers, with two cannons, have two chances to hit
###
for {set x 0} {$x < $shots} {incr x} {
set hit [expr {rand() * $difficulty}]
if { $hit < 5.0 } {
puts [list $shooter hit $target [game::cget $target hitpoints] $hit $difficulty]
hit $target
} else {
#puts [list $shooter miss $target $hit $difficulty]
}
}
}
proc hit {target {points 1}} {
set hitpoints [cget $target hitpoints]
incr hitpoints [expr {-1 * int($points)}]
cset $target [list hitpoints $hitpoints]
}
proc launch {carrier drone info} {
puts [list $carrier launch $drone $info]
set state [dump $carrier]
set docked [dict get $state docked]
set idx [lsearch $docked $drone]
if {$idx < 0 } {
error "$drone is not docked"
}
set docked [lreplace $docked $idx $idx]
::game::cset $carrier [list docked $docked]
dict unset state docked
dict set state name $drone
dict set state thrust 1
dict set state weapon laser
dict set state class drone
foreach {var val} $info {
dict set state $var $val
}
::game::newobj $state
}
proc bomb_release {team drone} {
variable bombcount
set state [dump $drone]
if { [dict get $state weapon] != "bomb" } return
set heading [dict get $state heading]
set heading [expr {$heading + $::pi / 2.0}]
set position [dict get $state position]
set velocity [dict get $state velocity]
cset $drone [list mass 0.5 weapon {} heading $heading thrust 1]
set name BOMB.[incr bombcount]
puts [list BOMB RELEASE $drone $team]
newobj [list class bomb name $name position $position velocity $velocity team $team]
}
proc bomb_detonate {team bomb} {
set state [dump $bomb]
if ![dict exists $state position] {
return
}
set position [dict get $state position]
variable objects
foreach {name obj} [array get objects] {
if { $name == $bomb } continue
set p [dict get $obj position]
set distance [::vector::distance $p $position]
if { $distance == 0.0 } {
set damage 100
} else {
set damage [expr int(1000/($distance * $distance))]
}
if { $damage > 0 } {
puts [list BLAST DAMAGE $bomb $name $damage [expr int($distance)]]
hit $name $damage
}
}
cset $bomb {hitpoints 0}
}
proc player {team botcode} {
global pi vectorcode
variable playercount
variable playercolors
set state {
name {}
team {}
class carrier
direction 0
heading 0
position {200 200}
color blue
range 100
}
dict set state name $team
dict set state team $team
set heading [expr {rand() * $pi / 8 + $pi/3 * $playercount}]
dict set state position [list [expr {(rand()*100 + 200) * cos($heading)}] [expr {(rand()*100 + 200) * sin($heading)}]]
set heading [expr {$pi - rand() * $pi * 2}]
dict set state heading $heading
dict set state direction $heading
dict set state color [lindex $playercolors [incr playercount]]
game::newobj $state
if [interp exists $team] {
interp delete $team
}
interp create $team
interp eval $team $vectorcode
interp eval $team $botcode
}
}
proc process_commands {team commandlist} {
foreach command $commandlist {
switch [lindex $command 0] {
launch {
::game::launch $team [lindex $command 1] [lindex $command 2]
}
dock {
::game::dock $team [lindex $command 1]
}
bomb_release {
::game::bomb_release $team [lindex $command 1]
}
bomb_detonate {
::game::bomb_detonate $team [lindex $command 1]
}
maneuver {
foreach {field value} [lindex $command 2] {
if {$field in {thrust heading}} {
::game::cset [lindex $command 1] [list $field $value]
}
}
}
fire {
::game::cset [lindex $command 1] [list target [lindex $command 2]]
}
{} {
}
default {
puts [list ? $team $command]
}
}
}
}
set botcommon {
###
# Common Bot Code
###
###
# Improved version of proper_heading that uses
# an error correcting proportional control algorith
# that minumizes turns while elimination the "Hey
# lets come to a stop to change direction" behavior
# of the default"
####
proc proper_heading {objectinfo destination flank} {
global pi
dict with objectinfo {
set px [lindex $position 0]
set py [lindex $position 1]
if { abs($px) > 390 || abs($px) > 390 } {
set destination {0 0}
}
###
# Compute our error in V
###
set v $velocity
set delta [::vector::subtract $destination $position]
set desired_theta [expr atan2([lindex $delta 1],[lindex $delta 0])]
set desiredv [list [expr $flank * cos($desired_theta)] [expr $flank * sin($desired_theta)]]
set dv [vector::subtract $desiredv $velocity]
set thrust [expr [::vector::length $dv] * $mass]
set heading [expr atan2([lindex $dv 1],[lindex $dv 0])]
return [list thrust $thrust heading $heading]
}
}
###
# Select the proper heading to align our craft with
# our intended destination
#
# This is a broken and crufted algorithm that is only left in so we can
# seperate the men from the boys. If you copy and paste this code into
# your bot, you deserve the inherent fail that befalls you
####
proc proper_heading {objectinfo destination flank} {
global pi
dict with objectinfo {
set px [lindex $position 0]
set py [lindex $position 1]
if { abs($px) > 390 || abs($px) > 390 } {
set destination {0 0}
}
set delta [::vector::subtract $destination $position]
set desired [expr {atan2([lindex $delta 1],[lindex $delta 0])}]
set vd [expr {atan2([lindex $velocity 1],[lindex $velocity 0])}]
###
# brake until the direction is right
####
if { abs($desired - $vd) > 0.001 && $speed > 0.01 } {
set thrust [expr {$speed / $mass / $power}]
return [list thrust [expr {$thrust * -1.0}] heading $vd]
}
set thrust [expr {($flank - $speed)/$mass/$power}]
###
# Speed control
###
#if { [vector::length $velocity] > 10.0 } {
# return [list thrust 0.0 heading $desired]
#}
return [list thrust $thrust heading $desired]
}
}
proc select.target {asset info targets} {
dict with info {
###
# Find closest target
###
set mytarget {}
set mydistance 1000
set myposition {}
set myvelocity {}
foreach {target tinfo} $targets {
set tpos [dict get $tinfo position]
set distance [::vector::distance $position $tpos]
if { $distance < $mydistance } {
set mytarget $target
set mydistance $distance
set myposition $tpos
set myvelocity [dict get $tinfo velocity]
}
}
if { $mytarget != {} } {
return $mytarget
}
}
}
proc enemy_trail {myinfo targetinfo} {
set dx [vector::add [dict get $targetinfo position] [dict get $targetinfo velocity]]
set p [dict get $myinfo position]
set distance [vector::distance $p $dx]
if { $distance < 125 } {
set heading [proper_heading $myinfo $dx 2.0]
set angle [dict get $heading heading]
dict set heading heading [expr {$angle + $::pi}]
return [list maneuver [dict get $myinfo name] $heading]
}
# Sweet spot, stay put
if { $distance < 200 } {
set heading [proper_heading $myinfo $dx 0.01]
return [list maneuver [dict get $myinfo name] $heading]
}
set heading [proper_heading $myinfo $dx 2.0]
return [list maneuver [dict get $myinfo name] $heading]
}
proc carrier_dock {asset info} {
dict with info {
set cp $::carrier_location
set cv $::carrier_velocity
set distance [::vector::distance $position $cp]
set cs [vector::length $cv]
if { $distance < 2.0 } {
return [list dock $asset]
}
set speed [expr {0.1 + sqrt($distance)/10.0 + $cs}]
if { $distance < 2.0 } {
set speed $cs
}
set heading [list maneuver $asset [proper_heading $info $cp $speed]]
}
}
proc obj.drone.recon {asset info} {
global pi
dict with info {
if { $hitpoints < 4 } {
return [carrier_dock $asset $info]
}
if { $::rallypoint != {0 0} } {
set delta [::vector::subtract $::rallypoint $position]
if {[vector::length $delta] > ($range * 1.5) } {
###
# Out of bounds? Aim for the center
###
set heading [proper_heading $info $::rallypoint 5.0]
return [list maneuver $asset $heading]
}
if {[vector::length $delta] > ($range * 1.05) } {
###
# Out of bounds? Aim for the center
###
set heading [proper_heading $info $::rallypoint 0.5]
return [list maneuver $asset $heading]
}
if {[vector::length $delta] > ($range * .95) } {
###
# Out of bounds? Aim for the center
###
set heading [proper_heading $info $::rallypoint 0.1]
return [list maneuver $asset $heading]
}
if {[vector::length $delta] < ($range * 0.90)} {
###
# Out of bounds? Aim for the center
###
set heading [proper_heading $info $::rallypoint 0.1]
set angle [dict get $heading heading]
dict set heading heading [expr {$angle + $::pi / 2.0}]
return [list maneuver $asset $heading]
}
}
set thrust [expr {(1.0 - $speed)/$mass}]
return [list maneuver $asset [list thrust $thrust]]
}
}
proc obj.drone.laser {asset info targets} {
dict with info {
###
# Find closest target
###
set firedistance 300
set target [select.target $asset $info $targets]
if { $target == {} } {
if { $hitpoints < 4 } {
return [carrier_dock $asset $info]
}
return [list maneuver $asset [proper_heading $info $::rallypoint 5.0]]
}
set dv [vector::add [dict get $targets $target position] [dict get $targets $target velocity]]
set speed [expr {[::vector::length [dict get $targets $target velocity]] + 2}]
return [list maneuver $asset [proper_heading $info $dv $speed]]
}
}
proc obj.drone.bomb {myinfo targetinfo dockvar} {
dict with myinfo {
upvar 1 dockvar docking
if { $weapon != "bomb" } {
set docking 1
return [carrier_dock $name $myinfo]
}
# Lead the target
set dx [vector::add [dict get $targetinfo position] [::vector::scale [dict get $targetinfo velocity] 3.0]]
set distance [vector::distance $position $dx]
if { $distance < 250 && $speed > 10.0 } {
return [list bomb_release $name]
}
if { $distance < 120 && $speed > 1.0} {
set docking 1
return [list bomb_release $name]
}
set heading [proper_heading $myinfo $dx 20.0]
return [list maneuver $name $heading]
}
}
proc obj.bomb {bomb info assets targets} {
dict with info {
global sympathetic_detonation
global lastdistance
if ![info exists lastdistance($bomb)] {
set lastdistance($bomb) 2000
}
set detonate 0
set firedistance 300
set fire {}
foreach {target tinfo} $targets {
if { [dict get $tinfo class] != "carrier" } continue
set tpos [dict get $tinfo position]
set distance [::vector::distance $position $tpos]
if { $distance > $lastdistance($bomb) && $distance < 100.0 } {
# We are starting to veer away
set detonate 1
set mytarget $target
set mydistance $distance
set myposition $tpos
set myvelocity [dict get $tinfo velocity]
}
set lastdistance($bomb) $distance
}
if !$detonate {
set distance [::vector::distance $position $::rallypoint]
if { $distance < 5.0 } {
set detonate 1
}
}
if { $detonate } {
lappend fire [list bomb_detonate $bomb]
foreach {asset ainfo} $assets {
set apos [dict get $ainfo position]
set aclass [dict get $ainfo class]
if {[vector::distance $apos $position] < 60 && $aclass == "bomb" } {
lappend fire [list bomb_detonate $asset]
}
}
}
return $fire
}
}
}
set unibot $botcommon
append unibot {
###
# A "Housebot" algorithm with known limitations
#
###
set init 0
set aistate search
set rallypoint {0 0}
set slice -1
set scouts {}
set bombers {}
set fighters {}
set timestamp 0
proc gameturn {team assets targets} {
global init pi
global drones
global carrier_location
global slice
global aistate
global scouts fighters bombers
set commands {}
set sector [expr 2.0 * $pi / 6.0]
incr ::timestamp
set ::sympathetic_detonation {}
set docked [lsort -dictionary [dict get $assets $team docked]]
if { $scouts == {} } {
set scouts {}
set fighters {}
set bombers {}
lappend scouts [lindex $docked 0]
foreach d [lrange $docked 1 end] {
switch [expr int(rand() * 6.0)] {
0 - 1 { lappend scouts $d }
2 - 3 - 4 { lappend bombers $d }
4 - 5 - 6 { lappend fighters $d }
}
}
foreach drone [lrange $docked 0 5] {
set heading [list thrust 1 heading [expr $sector * [incr slice]]]
dict set heading weapon recon
lappend commands [list launch $drone $heading]
}
}
set ::carrier_location [dict get $assets $team position]
set ::carrier_velocity [dict get $assets $team velocity]
foreach {name tinfo} $targets {
if { [dict get $tinfo class] == "carrier" } {
set ::destroytarget $tinfo
set ::rallypoint [dict get $tinfo position]
set ::aistate destroy
}
}
foreach {asset info} $assets {
dict with info {
if { ($class == "droid" && $weapon == "laser") || $class == "carrier" } {
if { [set t [select.target $asset $info $targets]] != {} } {
lappend commands [list fire $asset $t]
}
}
if { $class == "bomb" } {
foreach c [obj.bomb $asset $info $assets $targets] {
lappend commands $c
}
}
}
}
set docking 0
if { $::aistate == "search" } {
foreach {asset info} $assets {
lappend commands [obj.drone.recon $asset $info]
}
return $commands
}
foreach drone $docked {
###
# Launch in the direction of the enemy carrier
###
set heading [proper_heading [dict get $assets $team] [vector::add $::rallypoint [list [expr 10 - rand()*20] [expr 10 - rand()*20]]] 10.0]
dict set heading thrust 1.0
if { $drone in $scouts } {
dict set heading weapon recon
}
if { $drone in $fighters } {
dict set heading weapon laser
}
if { $drone in $bombers } {
dict set heading weapon bomb
}
lappend commands [list launch $drone $heading]
break
}
foreach {asset info} $assets {
dict with info {
if { $weapon == "recon" && $asset in $scouts} {
lappend commands [enemy_trail $info $::destroytarget]
} elseif { $weapon == "laser" } {
lappend commands [obj.drone.laser $asset $info $targets]
} elseif { $weapon == "bomb" } {
lappend commands [obj.drone.bomb $info $::destroytarget docking]
} elseif { $class == "carrier" } {
} else {
lappend commands [carrier_dock $asset $info]
}
}
}
set init 1
return $commands
}
}
proc step {count} {
for {set x 0} {$x < $count} {incr x} {
::game::update
pause
if { $::endgame } return
}
}
proc demo {} {
global pi unibot
global endgame
set endgame 0
array unset ::game::objects
::arena::init
wm geometry .play +0+0
::game::player PLAYER1 $unibot
::game::player PLAYER2 $unibot
for {set x 0} {$x < 1000} {incr x} {
::game::update
pause
if $endgame break
}
}
demo