Grobots Wiki
Advertisement
Walled City
Walled City
One of Walled City's mature colonies

Author

Warren

Strategy

Mobile defensive colony

Last modified

6/2006

Walled City is a side created by Warren in March 2006. It was one of the first mobile colony sides; all colonies were mostly stationary until it was introduced. Inspired by Business Cycle, it consists of various types arranged in concentric defensive rings.

File[]

#side Walled City 2
#author Warren
#date Started 2006 03 23
#color f5f
#seed 2 3 1 4 3 1 3 1 4 2 3

A colony that moves around, favoring food and corners and avoiding enemies.
Has various types in concentric circles inspired by Business Cycle.

Types:
Fighter
Pregnant
Gatherer
Solar
Missile

ToDo:
* Make fight or not decision consistant and clean

Changes from walled-city 1 to walled city 2
* Seed includes solar outlets
* Builds missiles when populuous
* Fighters eat food
* Gatherers stop sitting at home syphoning when down to half energy, since by the time they get out of range they're usually empty anyway.
* Sundry hardware tweaks of questionable value

#code
;;;;;;;; Shared code block ;;;;;;;;;;;;;
;;;;;message-passing channels
#const DANGER_CHANNEL 1
#const HUNGRY_CHANNEL 7


;;;;; shared memory
#const CENTER_MOVE_VOTE 1 ;vec
#const CENTER_UPDATE_TIME 3
#const COLONY_CENTER 5 ;vec

#const FOOD_PLENTY_VOTE 15
#const FOOD_PLENTY_TIME 16
#const FOOD_PLENTY 17

;101-300 are food claims
#const FOOD_CLAIM_BASE 101
#const NUM_FOOD_CLAIMS 100
#const FOOD_CLAIM_SIZE 2

;301-400 are missile claims
#const NUM_ROBOT_CLAIMS 100
#const ROBOT_CLAIM_BASE 301

;robot types
#const FIGHTER_TYPE 1
#const PREGNANT_TYPE 2
#const GATHERER_TYPE 3
#const SOLAR_TYPE 4
#const MISSILE_TYPE 5

;shot type constants (need to match grobots source code)
#const FF_SHOT 5 ;forcefield
#const SYPHON_SHOT 3 ;the friendly sort of syphon

;;;; global vars
#vector center
#vector tv ;temporary vector
#var pregnant-radius
#var wall-radius
#var solar-radius
#var food-plenty

;;;;;code 

set-see-friends:
if
	0 1 ;first is enemies, second is friends
else
	1 0
then 
	robot-sensor-sees-friends! robot-sensor-sees-enemies!
return

rotate-ninety: ;clockwise
	negate swap return

4dup: tv! 2dup tv 2swap tv return

;The adjust-circle function uses the robot sensor and engine to bring this robot into a circle
; with other robots of its type. Far from perfect.
#var circle-adjust-time 0
#var left-cosine 
#var right-cosine
#var left-vel ;angular velocity
#var right-vel
#vector self-vec
#const ADJUST_CIRCLE_PERIOD 50

#vector desired-position

#var relocating-mode 0
#var relocating-angle
adjust-circle: ; radius -> ()
	relocating-mode nif
	wall-collision friendly-collision 3 >= or and-if
		1 relocating-mode!
		world-size 2 vs/ position v- angle -1 1 random + relocating-angle!
	then
relocating-mode if
	relocating-angle polar-to-rect center v+ desired-position!
	desired-position position 2 in-range if
		0 relocating-mode!
	then
else
	time circle-adjust-time ADJUST_CIRCLE_PERIOD + > if
		time circle-adjust-time!
		1 set-see-friends^
		0 robot-sensor-focus-distance!
		fire-robot-sensor sync
		position center v- self-vec!
		robot-sensor-range 2 / self-vec norm 1 max /
		;stack: sin of half the angle we can see
		1.3 * ;fudge factor to make no one seen seem a bit out of range
		1 min arcsin 2 * 
		cos
		 dup left-cosine! right-cosine!
;consider walls
		self-vec unitize 15 vs* rotate-ninety^
		2dup position v+ restrict-location-zero^ center v- unitize self-vec unitize dot left-cosine max left-cosine!
		vnegate position v+ restrict-location-zero^ center v- unitize self-vec unitize dot right-cosine max right-cosine!

		0 0 right-vel! left-vel!
		robot-found if
			do
				type robot-type = if
				position center v- unitize robot-position center v- unitize 4dup^ cross
				0 < if
					;bot right of us.
					dot ;now stack is: radius parameter, cosine of angle between us and them
					dup right-cosine > if
						right-cosine!
						robot-position center v- 2dup norm 1 max square vs/ robot-velocity cross right-vel!
					else drop then
				else
					;left of us
					dot
					dup left-cosine > if
						left-cosine!
						robot-position center v- 2dup norm 1 max square vs/ robot-velocity cross left-vel!
					else drop then
				then
				then ;our type?
			next-robot while-loop
		then
		;now seek balance. radius parameter is still on the stack!
		dup 2 / self-vec norm < if
			left-cosine arccos right-cosine arccos - 5 /
		;	position center v- 2dup norm 1 max square vs/ engine-velocity cross 0.8 *
		;	left-vel right-vel + 0.1 * + ADJUST_CIRCLE_PERIOD * + ;follow neighbors
			 position center v- angle +
		else
		;radius is very small, so pay attention to it first
			position center v- angle
		then
		;stack: dist, angle from center to seek
		polar-to-rect center v+ desired-position! 
	else
		drop
	then ;time to scan or not
then ;relocating-mode or not
desired-position position v- tv!
tv 0.03 vs* engine-velocity!
tv norm 5 > shot-found and if engine-max-power else 
 tv norm 0.2 > mass 800 / *
then engine-power! ;max power is 0.02 for std size cell. Allows gatherers to push us around.
;;		desired-position seek-location
return

general-talk:
	FOOD_PLENTY read food-plenty!
	COLONY_CENTER vread center!
	SOLAR_TYPE type-population 4 * 2pi / solar-radius!
	PREGNANT_TYPE type-population 4 * 2pi /
	SOLAR_TYPE type-population 3 0 ifev solar-radius + max pregnant-radius!
	FIGHTER_TYPE type-population 6 * 2pi / pregnant-radius 2 + max wall-radius!
	wall-radius 2 / pregnant-radius max pregnant-radius!
	pregnant-radius 7 - solar-radius max solar-radius!
return

restrict-location: ;x y -> x y
world-height 5 - min 5 max swap
world-width 5 - min 5 max swap return

restrict-location-zero: 
world-height 0 - min 0 max swap
world-width 0 - min 0 max swap return


;returns distance to nearest wall
wall-distance: ; -> dist
	position min
	world-size position v- min
	min return

cry-if-hurt: ; -- was-hurt
	#var last-armor
	armor last-armor < if
		position 2 DANGER_CHANNEL send
		1
	else
		0
	then
	armor last-armor!
return ;returns 1 or 0

;Feeding
#vector hungry-position
#var hungry-time -999
#var hungry-energy-wanted 10
#vector hungry-velocity
#vector current-hungry-position 50 50

calc-chp:
	hungry-position hungry-velocity time hungry-time - 40 min vs* v+ current-hungry-position!
return

#var num-cries
feed-hungry:
	
		HUNGRY_CHANNEL messages 5 - 0 max 0 random-int HUNGRY_CHANNEL skip-messages
		0 num-cries!
		do
			num-cries 5 < if
				HUNGRY_CHANNEL receive
				num-cries 1 + num-cries!
			else 
				0 ;already listened a lot
			then
		while
			;stack: energy time vx vy x y 
			2dup position syphon-range in-range
			current-hungry-position position syphon-range in-range not or
			time hungry-time 100 + > or
			if
 				hungry-position! hungry-velocity!
				hungry-time! hungry-energy-wanted!
				calc-chp^
			else
				2drop 2drop 2drop
			then
		loop
	current-hungry-position position syphon-range in-range if
	energy max-energy 0.1 * > and-if
		syphon-max-rate negate syphon-rate!
		current-hungry-position position v- hungry-velocity velocity v- 5 vs* v+ 
			rect-to-polar syphon-direction! syphon-distance!
	else
		0 syphon-rate!
	then
return

;based vaguely on tutorial food-hashing code from Frog Celestial
#var food-hash
#var food-y
claim-food:
;#const FOOD_CLAIM_BASE 1
;#const NUM_FOOD_CLAIMS 100
;first time, then y
	food-position food-y! world-width /
	;stack: between 0 and 1
	NUM_FOOD_CLAIMS * floor
	;stack: probably between 0 inclusive and NUM_FOOD_CLAIMS exclusive
	0 max NUM_FOOD_CLAIMS 1 - min FOOD_CLAIM_SIZE * FOOD_CLAIM_BASE + food-hash!
	food-hash sync read
	dup 0 > swap time 400 - > and if
		;valid time claim already
		0 ;TODO: check y
	else
		;claim expired
		time food-hash write food-y food-hash 1 + write
		1
	then
return


;;;;;; END Shared code ;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Wall ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#type Spiked Wall

A short-range blaster-weilding fighter. Also has weak grenades for no good reason.

;#decoration 000 cross
#color f00
#hardware
energy 460 80
armor 350
processor 34
radio send receive
engine 0.18
solar-cells 0.009

robot-sensor 8 6
shot-sensor 6.9 3
food-sensor 6.5 2
eater 0.5

repair-rate 0.12

grenades 4 7 19

blaster 38 5 19

#code
#vector danger-position
#var danger-time -1000
recent-danger: ;-- bool
time danger-time 50 + <
return

#const BIG_BOMB 103.52 ;if a robot has more than this size bomb, treat it as a missile.
#var hash
#var claimed-robot -1
;Volunteer to be the robot that stops the incoming missile
claim-robot: ; -- bool
robot-bomb BIG_BOMB < if 1 return then
robot-side 7 * robot-type 5 * robot-id + + NUM_ROBOT_CLAIMS mod ROBOT_CLAIM_BASE + hash!
hash claimed-robot = if ;already claimed
	sync
hash read 40 + time > and-if ;has our claim expired?
	time hash write
	1 return
then
sync
hash read 50 + time < if
	time hash write 
	hash claimed-robot!
	1 return
else
	0 return
then
  
targetable-robot-found: ;returns 1 if an ok target is found, 0 otherwise. Leaves robot cursor on target.
robot-found if
  do
    robot-shield-fraction 0.3 > if
    claim-robot^ and-if
		1 return
    then
  next-robot while-loop
then
0 return

;;; the fight-willingness function is in progress and currently unused.
#const BEGIN_FIGHTING_WILL 1.5
#const END_FIGHTING_WILL 0.5
#var fw_dist
#var fw_danger
;parameters: is it shooting? distance from center to object 
fight-willingness: ; bool num -- num
fw_dist! fw_danger!
fw_dist wall-radius 10 + < fw_danger and if
	5 ;under attack, always defend home
else
	fw_danger if
		wall-radius fw_dist / 1 min ;0.2 for 5 wall-radius away, 1 for inside colony
	else
	then
	fw_danger 2 1 ifev + 
	energy max-energy / armor max-armor / * sqrt ;geometric mean of armor and energy
	*
then
return ;returns willingness, greater is more willing


#var last-cry-time
#var fighting 0

#var meal-time
#vector meal-position
#var have-meal

#var tti ;time to intercept
#vector intercept-delta ;for noff
#vector relative-shot-vel
#var enemy-dist
#vector enemy-pos
#var enemy-time
#vector enemy-vel
#var enemy-radius
#var robot-scan-time
#var bomb-squad 0

;Some things, such as engine control and weapon firing, don't want to wait 10+ frames
; for the main loop to finish. So this is called every 4 frames or so.
#var fast-loop-time -10
fast-loop:
	time fast-loop-time!
	energy max-energy / 0.06 > if
	robot-scan-time fighting 14 30 ifev + 
	time < and-if ;If fighting, jump the gun so we don't waste time
		0 set-see-friends^
		0 robot-sensor-focus-distance!

		do
			blaster-cooldown 3 >=
			;will sync at least twice: once to fire sensor to see enemy, a second time to look for friends
			; Computing will also take several frames
			;don't care if grenades aren't ready
		while
			sync
		loop

		fire-robot-sensor sync
		time robot-scan-time! ;sensor also used for other things so robot-sensor-time won't do
		targetable-robot-found if
			robot-position robot-velocity lead-grenade
			robot-bomb robot-reloading or energy max-energy / 0.4 > and
			 center position wall-radius 13 + in-range or if
				robot-position robot-velocity 28 vs* v+ danger-position!
				time danger-time!
				1 fighting!
			then

			;do noff
			robot-bomb BIG_BOMB >= bomb-squad!
			robot-distance enemy-dist!
			robot-position enemy-pos!
			robot-velocity enemy-vel!
			robot-sensor-time enemy-time!
			robot-radius enemy-radius!

			blaster-speed
			robot-position position v- unitize
			robot-velocity velocity v- dot 
			;stack: blaster-speed, fleeing speed
			- blaster-speed 0.1 * max ;Don't let the velocity correction go crazy
			;stack: blaster closing speed
			robot-distance radius - swap / 
			;stack: tti
			tti!
			tti blaster-lifetime <= if
				robot-velocity velocity v-
				tti vs* intercept-delta! ;what to add to their position to make a straight shot work
				1 set-see-friends^
				robot-position position v- 0.5 vs* rect-to-polar robot-sensor-focus-direction! robot-sensor-focus-distance!
				intercept-delta robot-position v+ position v- unitize blaster-speed vs* relative-shot-vel! 
				fire-robot-sensor sync
				robot-found if
					do
						robot-position enemy-pos position v+ 0.5 vs* enemy-dist 0.5 * in-range Fire& nifg
						;friend is near line of fire.
					;determine if friend might be hit
						robot-velocity velocity v- relative-shot-vel v- unitize
						robot-position position v- cross robot-radius 3 + < NoFire& ifg
					next-robot while-loop
				then
			Fire:
				intercept-delta enemy-pos v+ position v- angle fire-blaster
			NoFire:
			then
;Try grenade a second time, in case it wasn't quite reloaded last time
	;;		robot-position robot-velocity lead-grenade 
		else
			fire-shot-sensor sync
			shot-found if
				do
					shot-velocity or if ;ignores explosions
					shot-type FF_SHOT <> shot-type SYPHON_SHOT <> and 
					center shot-position wall-radius 8 + in-range or and-if
						shot-position shot-velocity unitize -10 vs* v+ danger-position!
						time danger-time!
						energy max-energy / 0.4 > center position wall-radius 4 + in-range or if
							1 fighting!
						then
					then
				next-shot while-loop
			then
		then
		
	then

	fighting if
			enemy-time 30 + time > if
				bomb-squad if

					enemy-pos center v- rect-to-polar swap radius robot-radius + 0.3 - - swap polar-to-rect
					center v+
				;stack: place to be
#vector desired-ev
					position v- rect-to-polar swap 0.1 * 0.2 min swap polar-to-rect
					enemy-vel 0.75 vs* v+ 2dup desired-ev! engine-velocity!
				else
					enemy-pos enemy-vel time enemy-time - vs* v+ ;stack: cur enemy pos
					position v- rect-to-polar swap blaster-range 2.5 - - 0.06 * swap polar-to-rect
				;move to be 0.8 closer than our blaster range
 					enemy-vel 0.95 vs* v+ engine-velocity!
#vector requested-vel ;debug printf
					engine-velocity requested-vel!
				then
				engine-max-power engine-power!
			else
				danger-position seek-location
			then
	then
return

#start
position desired-position!
Begin-normaling:

do
;#var time1
;time time1!
	fast-loop^
	general-talk^
	cry-if-hurt^ drop
;#var time2
;time time2!

	energy max-energy / 0.2 > max-repair-rate 0 ifev repair-rate!
	
	armor max-armor / 0.5 > 0.8 0.55 ifev 
	have-meal if 0.5 * then
	max-energy * energy > if
	time last-cry-time - 37 > and-if
	velocity norm 0.15 < energy max-energy / 0.4 < or and-if
		max-energy energy - time velocity position 6 HUNGRY_CHANNEL send
		time last-cry-time!
	then

;#var time3
;time time3!
	fast-loop^


	fighting if

		energy max-energy / armor max-armor / min 0.25 > position center wall-radius 8 + in-range or if
		time danger-time 50 + < 
		time danger-time 400 + < 
		danger-position position 1 in-range not and or and-if
			DANGER_CHANNEL clear-messages ;already have a target, so why listen for other cries?
		else 0 fighting! then
	else
		have-meal if
			meal-position position radius in-range
			time meal-time 200 + > or eaten not and if
				0 have-meal!
			then
		then
		have-meal nif
			time food-sensor-time if food-sensor-time else -100 then
				energy 10 < 500 60 ifev
			 + > if
			energy max-energy / 0.9 < and-if
			center position wall-radius 4 + in-range and-if
				fire-food-sensor sync
				food-found if
					Food-check-loop:
					food-velocity norm nif
					claim-food^ and-if
						food-position meal-position!
						time meal-time!
						1 have-meal!
					else
						next-food Food-check-loop& ifg
					then
				then ;food-found
			then
		then

		have-meal if
			meal-position position v- rect-to-polar swap 0.05 * 0.1 min swap polar-to-rect engine-velocity!
			meal-position position radius in-range 0 engine-max-power 0.5 * ifev engine-power!
		else
			;wait in the circle
			wall-radius adjust-circle^
		then
	then

	fast-loop^ ;adjust-circle can take a long time

	fighting nif
		energy max-energy / 0.4 > if
			do
				DANGER_CHANNEL receive
			while
				;stack: position of danger
				danger-position!
				danger-position center wall-radius 8 + in-range
				danger-position position 10 energy max-energy / 15 * + in-range or if
					time danger-time!
					1 fighting!
				then
			loop
		else
			DANGER_CHANNEL clear-messages
		then
	then

forever
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Constructor ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#type Pregnant
#decoration 000 circle
#color 0f0
#hardware
energy 600 0.1
armor 180
processor 10
radio send receive
engine 0.027

constructor 2.6
solar-cells 0.03
repair-rate 0.06

robot-sensor 6 4

#code
#var last-birth-time -1
#var baby-cost

select-type:
	;first, check to see if fighters are needed
	population 0.28 * FIGHTER_TYPE type-population 0 1 random-int + > if
		FIGHTER_TYPE 
	else
		;second check to see if we're overflowing
		baby-cost time last-birth-time - /
		;stack: average power consumption
#var power-consumption
		dup power-consumption!
		constructor-max-rate 0.8 * > if
			PREGNANT_TYPE	
		else
	;third, make missiles if populous
			population 20 > if
			0.4 random-bool and-if
				MISSILE_TYPE
			else
	;third, make gatherers or solars based on whether the gatherers are happy
				food-plenty 0.39 < GATHERER_TYPE type-population and
				SOLAR_TYPE GATHERER_TYPE ifev
			then
		then
	then constructor-type!

	constructor-remaining baby-cost! ;;;hack
	time last-birth-time!
return

#start
	position desired-position!
	time 20 < if
		position COLONY_CENTER vwrite
	then


	constructor-type if
	;;seeded with fetus
		time last-birth-time!
		constructor-remaining baby-cost! ;;;hack
	then
#var last-cry-time -999

do
	general-talk^
	pregnant-radius adjust-circle^
	cry-if-hurt^ drop ;ignore return value

	time last-cry-time - 
	max-energy max-energy energy - 1 + / ;stack: delta_t, max / (1 + max - current)
	61 * >
	velocity norm 0.12 < and if
		max-energy energy - time velocity position 6 HUNGRY_CHANNEL send
		time last-cry-time!
	then
	max-repair-rate repair-rate!

	constructor-type nif
		select-type^
	then
	max-energy 0.03 * energy < constructor-max-rate 0 ifev constructor-rate!
forever

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Gatherer ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#type Gatherer
#decoration 000 cross
#color 00f
#hardware
energy 600 20
armor 111
processor 20
radio send receive
engine 0.04

eater 2.4
solar-cells 0.01
repair-rate 0.03
food-sensor 8 3
shot-sensor 4 2

syphon 2.4 9

#code
#var have-meal 0
#var meal-time
#vector meal-position 0 0
#vector wander-dest
#var homesick 0
#var running-away 0
#var last-danger-time -200
#vector last-danger-position


#var status 2
#const VOTED 1
#const UPDATED 2
#vector run-away-debug
#vector get-food-debug
vote:
	time 100 mod 20 < if
	status UPDATED = and-if
		;time to vote
		time last-danger-time 180 + < if
			last-danger-position center v- unitize -8 vs*
		else
			meal-position or if
				;have ever seen a food
				meal-position center v- unitize 3 vs*
			else
				;neither eating nor running away. Move colony towards center of world to get us food
				world-size 2 vs/ center v- unitize 0.1 vs*
			then
		then

		have-meal 1 0 ifev
		;stack is: movement-vote food-vote
		sync
		FOOD_PLENTY_VOTE read + FOOD_PLENTY_VOTE write
		CENTER_MOVE_VOTE vread v+ CENTER_MOVE_VOTE vwrite
		VOTED status!
	then

	time 100 mod 30 > if
	time 100 mod 50 < and-if
	status VOTED = and-if
 		time 50 - CENTER_UPDATE_TIME
		;stack: time-50, CENTER_UPDATE_TIME
		sync
		read > if
			time CENTER_UPDATE_TIME write
			;now we can take our time computing, since the time has already been written. If we die, center is delayed
			; by 100 frames; no big deal.
			CENTER_MOVE_VOTE vread 
			GATHERER_TYPE type-population 10 max vs/  ;10 max keeps us from moving so quickly when population is small
		;vector with length about 1
			2dup get-food-debug!
			center world-size 2 vs/ v- 
			signum swap signum swap
			 0.15 vs*  2dup run-away-debug! v+ ;run away from center. length 0.1 * sqrt(2) = 0.14
			rect-to-polar swap 2 min swap polar-to-rect
			COLONY_CENTER vread v+
			restrict-location^
			COLONY_CENTER vwrite
			0 0 CENTER_MOVE_VOTE vwrite
		then
		time 50 - FOOD_PLENTY_TIME
		sync
		read > if
			time FOOD_PLENTY_TIME write
			FOOD_PLENTY_VOTE read GATHERER_TYPE type-population /
			FOOD_PLENTY read + 2 / FOOD_PLENTY write
			0 FOOD_PLENTY_VOTE write
		then

		UPDATED status!
	then
return

#const edge-space 4
;this subroutine copied from eventually 12 (via Untouchable 4)
random-edge-position:
  0 1 random-int if
    0 1 random-int edge-space world-width edge-space - ifev
    edge-space world-height edge-space - random
  else
    edge-space world-width edge-space - random
    0 1 random-int edge-space world-height edge-space - ifev
  then
return


new-wander-loc:
0.4 random-bool if
	center wall-radius 1.2 * 10 + random-angle polar-to-rect v+ restrict-location^
else
	random-edge-position center v- rect-to-polar swap wall-radius 1.2 * 13 + min swap
	polar-to-rect center v+
then
 wander-dest!
return

run-away:
		new-wander-loc^
		0 have-meal!
		1 running-away!
		time last-danger-time!
		position last-danger-position!

return

#start
new-wander-loc^
do
;#var begin-loop-time
;	time begin-loop-time!
	vote^
	general-talk^
	energy max-energy / 0.2 > max-repair-rate 0 ifev repair-rate!
	
	time shot-sensor-time 30 + > energy max-energy / 0.1 > and if
		fire-shot-sensor sync
		shot-found if
			run-away^
		then
	then
	cry-if-hurt^ if
		run-away^
	then
;#var time2
;	time time2!

	;; feed-hungry and general-talk are really slow, so food seeking is in the code 2 places.
	have-meal if
		meal-position seek-location
	then

	feed-hungry^ ;this takes about 5 frames!
;#var time3
;	time time3!

homesick running-away or nif
	have-meal if
		meal-position position radius in-range
		time meal-time 200 + > or eaten not and if
			0 have-meal!
		then
	then
	have-meal nif
		time food-sensor-time 
			energy 10 < 150 30 ifev
		 + > if
			fire-food-sensor sync
			food-found if
				Food-check-loop:
				food-velocity norm nif
				claim-food^ and-if
					food-position meal-position!
					time meal-time!
					1 have-meal!
				else
					next-food Food-check-loop& ifg
				then
			then ;food-found
		then
	then

	have-meal if
		meal-position seek-location
	else
		wander-dest position 2 in-range 
		center wander-dest wall-radius 30 + in-range not or if
			new-wander-loc^
		then
		energy 5 < if
			0 engine-power!
		else
			wander-dest position v- unitize 0.07 vs* engine-velocity! engine-max-power engine-power!
		then
	then
	energy max-energy / 
	have-meal 0.95 0.7 ifev > if
		1 homesick!
		0 have-meal!
		0.5 random-bool if
			new-wander-loc^ ;to avoid the useless gliding colony problem
			;meal-position wander-dest! ;last place we found food is good place to wander to
		then
	then
else ;eat or not

homesick if
	hungry-position position syphon-range 0.8 * in-range if
		0 engine-power!
	else
		hungry-position center wall-radius 10 + in-range 
		if hungry-position else center then seek-location
	then
	energy max-energy / 0.5 < if
		0 homesick! ; ok to do this prematurely, since we'll continue to syphon
	then

then

running-away if
	center position 4 in-range if
		0 running-away!
	then
	center seek-location
then
then ;eat or not

forever

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#type Solar Outlet
#decoration 000 cross
#color 0ff

Based on untouchable 3's solar outlet.

#hardware

processor 15 ;big CPU to process hungry calls
armor 80
energy 150 0
constructor 0.3 ;emergency anti-overflow use only
engine 0.023

radio receive

solar-cells 0.4
robot-sensor 4 3
syphon 0.55 8

#code

#start

do
	general-talk^
	solar-radius adjust-circle^
	cry-if-hurt^ drop
    	feed-hungry^

	PREGNANT_TYPE constructor-type!
	energy max-energy / 0.8 > constructor-max-rate 0 ifev constructor-rate!
forever


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Missile ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#type Boom

#decoration fcc dot
#color f00
#hardware
energy 300 300
armor 280
processor 30
radio send receive
engine 0.18

robot-sensor 11 12
shot-sensor 6 2

bomb 1100

#code
#vector danger-position
#var danger-time -1000
recent-danger: ;-- bool
time danger-time 50 + <
return
  
#var exploring 1
#var expected-damage 0
#var max-expected-damage
#vector wander-loc
#var total-mass-seen

targetable-robot-found: ;returns 1 if an ok target is found, 0 otherwise. Leaves robot cursor on target.
robot-found if
  do
    robot-shield-fraction 0.3 > if
		1 return
    then
  next-robot while-loop
then
0 return

#const edge-space 4
;this subroutine copied from eventually 12 (via Untouchable 4 and Walled City)
random-edge-position:
  0 1 random-int if
    0 1 random-int edge-space world-width edge-space - ifev
    edge-space world-height edge-space - random
  else
    edge-space world-width edge-space - random
    0 1 random-int edge-space world-height edge-space - ifev
  then
return

new-wander-loc:
	random-edge-position^ wander-loc!
return

#vector robots-center
#var importance
#var max-expected-damage-time
#const EXPL_RADIUS 6
#start
new-wander-loc^

do
	time robot-sensor-time exploring 40 15 ifev + > if
		fire-robot-sensor sync
		robot-found if
			0 0 robots-center!
			0 expected-damage!
			0 importance!
			0 ;mass - leave on stack
			do
				robot-mass +
				1 robot-distance EXPL_RADIUS / - 0 max robot-mass * expected-damage + expected-damage!
				robot-position 
				robot-mass robot-distance EXPL_RADIUS < 1 0.1 ifev *
				;stack: mass-accum, robot-position, robot-importance
				dup importance + importance!
				vs* robots-center v+ robots-center!
			next-robot while-loop
			total-mass-seen!
			robots-center importance vs/ robots-center!

			energy max-energy / armor max-armor / min
			exploring 120 80 ifev * total-mass-seen < if
				0 exploring!
			else
				1 exploring!
			then
			
			expected-damage 35 > if
			max-expected-damage 0.8 * expected-damage >
			time max-expected-damage-time 200 + > or and-if
				die sync
			then
			max-expected-damage expected-damage  < if
				expected-damage max-expected-damage!
				time  max-expected-damage-time!
			then
		then
	then
	exploring if
		wander-loc position 5 in-range if new-wander-loc^ then
		wander-loc position v- unitize 0.15 vs* engine-velocity!
	else
		robots-center seek-location
		;0.3 robot-direction-overall polar-to-rect engine-velocity!
		;;TODO: this is a terrible place to go towards.
	then
	engine-max-power engine-power!
	sync sync  ;save CPU
forever

#end
Advertisement