obliteration_2009


Information

Created with NetLogo version NetLogo 4.0.4
Running with NetLogoLite.jar version 404.


WHAT IS IT?


Three mortar bases launch bombs in the general direction of the others.
When bombs land they explode, making a crater and throwing up ash and cinders.
Hot cinders rise, cooler ash falls.
The explosion can undercut the nearby terrain.
Undercut and unsupported terrain crumbles.
Hot ash and cinders can also cause bombs to explode.
Some cinders cool and become ash.
If the terrain under a mortar crumbles, the mortar explodes.
When only one mortar remains, it flashes victory, and the world resets.

TRICKS


Sometimes rock/ash (terrain) is patches, sometimes it is a turtle-based particle-system.
When ball hits rock, crater is cleared of rock (colored "air") and filled with moving "ash" turtles, Also the edge of the crater is turned into ash turtles.
When ash turtles settle, they "die", but color the patch beneath themselves the "ash" color.
When ash turtles find rock/ash colored patches *above* themselves, they turn those patches into ash turtles, too. This enables under-cut rock to crumble.
Terrain generator goes by columns, calculating an elevation for each column in a zig-zag fashion.
Sky texturing is a combination of random and gradient coloring.
Rock texturing is a combination of random and sin-wave (with vertical offset) coloring.
When bomb velocity is > 1, the bomb rotates to face the direction of travel. Otherwise, the bomb tumbles.

Bomb Shapes and Animation


Swapping turtle shapes creates the illusion that the bombs are spinning.
The bomb-shape chooser is populated with lists. The list contains not only the bomb-shape name, but also the number of animation frames and the size scalar.

RELATED MODELS


BALL-FALL


GRAVITY


Procedures

NetLogo Version: NetLogo 4.0.4

globals
[ heights ;; contains the list of the terrain elevations
  ;;cannon-a ;; points to one of the cannon
  ;;cannon-b ;; points to the other cannon
  ;; current ;; points to the current cannon
  g ;; the gravity constant
  activity? ;; true when there is game action occuring

  shape-base
  ball-size
  pointer-size
  num-frames
  frame-rate
  A-Loses
  B-Loses
  AB-Lose
  Trees-Killed
  shots 
  hits
  eff
  display-rate
  
  rock-freq
  
]
breed [ emptyset nothing ]
breed [ bases a-base ] ;; the non-rotating part of the cannon
breed [ cannons a-cannon ] ;; the rotating / aiming part of the cannon
breed [ balls a-ball ] ;; the projectile
breed [ smoke a-smoke ]
breed [ ashes an-ash ]
breed [ trees a-tree ] ;; some trees


smoke-own
[ nx ny ]
ashes-own
[ nx ny vx vy]

balls-own
[ vx vy ;; velocity  
  nx ny ;; new coordinates
  ox oy ;; old coordinates
  frame ;; the animation frame for the animated projectile
  off-screen? ;; is the projectile off the top of the screen?
  ascending?
  my-shape
  my-frames
  my-size
]

cannons-own
[ score ;; current score
  power ;; initial velocity of the shot
  aim   ;; heading of the shot
  last-power ;; previous shot power (as yet unused)
  last-aim   ;; previous shot aim (as yet unused)
  target ;; the target
  my-base ;; the base that belongs to this cannon
  my-platform ;; the patches that the base rests on
  my-space
  target-selected?
  on-target?
  reloading?
  reload-countdown
]

trees-own
[ root ]

patches-own [ t ]

to startup reset setup
   ask cannons [ ka-boom! ]
   ask patch max-pxcor 0 
   [ set plabel "OBLITERATE!     OBLITERATE!     OBLITERATE!     OBLITERATE!     OBLITERATE!     "
   ]
   repeat 100
   [ go wait display-rate ]
   reset
   setup
end
   
    

to reset
   set A-Loses 0
   set B-Loses 0
   set AB-Lose 0
   set Trees-Killed 0
   set shots 0
   set hits 0
end

to setup
   no-display
   
   let t1 A-Loses
   let t2 B-Loses
   let t3 AB-Lose
   let t4 Trees-Killed
   let t5 shots
   let t6 hits
   ca
   set A-Loses t1
   set B-Loses t2
   set AB-Lose t3
   set Trees-Killed t4
   set shots t5
   set hits t6
   if shots > 0 [ set eff (word (100 * precision (hits / shots) 2)  " %")]
   
   set g -0.04
   set shape-base "bomb"
   set ball-size 5
   set pointer-size 25
   set num-frames 5
   set frame-rate .25
   set display-rate 1 / 45
   set rock-freq 300 + random 90
   set-default-shape smoke "smoke"
   set-default-shape ashes "ash"
   setup-hills
   setup-cannons
   setup-trees   
   display
end

to setup-trees
   ;; find patches on the border tween earth and sky
   let horizon patches with [ is-rock? and [ is-air? ] of patch-at 0 1 ]
   ask n-of 50 horizon
   [ sprout-trees 1
     [ set size 6 + random 6
       let offset ycor - 10 - random 20
       if offset < (min-pycor + 3) [ set offset (min-pycor + 3) ]
       set ycor offset
       set heading 0
       set color gray
       set shape one-of [ "tree0" "tree1" ]
       set root patch-at 0 -3
     ]
   ]
end

to setup-hills
   cp
   
   ;; build a list of elevations that slope up and down
   let dir 1
   set heights [ ]
   let max-peak min-pycor + world-height * .5
   let min-peak min-pycor + world-height * .1
   let peak min-peak + random (max-peak - min-peak - 1)
   
   
   foreach n-values world-width [ min-pxcor + ? ]
   [ if random 100 < 5
     [ set dir (sign dir) * -1 * random-float 2.0 ]
     
     set peak peak + dir
     if peak > max-peak or peak < min-peak
     [ set dir dir * -1
       set peak peak + dir + dir
     ]
     set heights lput floor peak heights
   ]
   
   
   ; color patches according to the elevations
   ask patches
   [ ifelse pycor < item (pxcor - min-pxcor) heights
     [ set pcolor rock ]
     [ set pcolor air  ]
   ]
  
   display
end

to setup-cannons
    set-default-shape cannons "cannons"
    set-default-shape bases "bases"
    set-default-shape balls "banana0"
    
    ask setup-cannon-patch (.1 + random-float .2)
    [ let a-cannon setup-cannon violet ]
    
    ask setup-cannon-patch (.4 + random-float .2)
    [ let a-cannon setup-cannon magenta ]

    ask setup-cannon-patch (.9 - random-float .2)
    [ let a-cannon setup-cannon magenta ]
    
    ask cannons
    [ set target one-of other cannons 
      set power 1
    ]
    ;; set current one-of cannons with [ current != self ]

end

to-report setup-cannon [ new-color ]
   let new-cannon nobody
   ;; the patch creates a cannon
   sprout-cannons 1
   [ set color black
     set size 5
     ;; record the platform patches for this cannon
     set my-platform patches with [ pycor = [pycor] of myself and pxcor + 5 >= [pxcor] of myself and pxcor - 5 <= [pxcor] of myself ]
     set my-space patches with [ pycor > [pycor] of myself and pycor - 5 <= [ pycor ] of myself and pxcor + 5 >= [pxcor] of myself and pxcor - 5 <= [pxcor] of myself ]
     set ycor ycor + .5 * size
     ;; create a base for this cannon
     hatch-bases 1
     [ set color new-color
       set heading 0
       ask myself [ set my-base myself ]
     ]
     set new-cannon self
     ask my-platform [ set pcolor brown - 4 ]
     set on-target? false
     set target-selected? false
     set reloading? true
     set reload-countdown random fire-rate
   ]
   report new-cannon
end     

to-report setup-cannon-patch [ location ]
   let cannon-index floor (world-width * location)
   let cannon-pxcor cannon-index + min-pxcor
   let cannon-pycor item cannon-index heights
   ask patches with [ pxcor >= cannon-pxcor - 5 and pxcor <= cannon-pxcor + 5 ]
   [   ifelse pycor = cannon-pycor [ set pcolor steel ]
     [ ifelse pycor < cannon-pycor [ if not is-rock? [ set pcolor rock ] ]
                                   [ if not is-air?  [ set pcolor air  ] ]
     ]
   ]
   set location patch cannon-pxcor cannon-pycor
   ask location [ set pcolor white ]
   report location
end

to-report sign [ n ]
      ifelse n < 0 [ report -1
   ][ ifelse n > 0 [ report 1
   ][                report 0
   ]]
end
     
to-report rock ;; report varying shades of a color
  report brown - 2 + random-float 1 * sin ((pycor + .02 * pxcor )* rock-freq) 
end

to-report ash  ;; report varying shades of a color
  report brown - 4 + random-float 2
end

to-report steel ;; report varying shades of a color
   report red - 1 + random-float 2
end

to-report air ;; report varying shades of a color
    report sky - 3 + 5 *  (.1 * scale-color gray pycor min-pycor max-pycor)  + random-float .5
end

to-report fire ;; report varying shades of a color
    report red - 5 + random-float 10
end

to-report smoke-color ;; report varying shades of a color
  report orange - 2 + random-float 3
end  

to go
   every display-rate
   [
   set activity? false
   rocks-smoke-ashes-fire! 
   let blown-up cannons with [ any? my-platform with [ not is-rock? ] ]
   if any? blown-up
   [ ask blown-up
     [ ka-boom!
       
     ]
     set activity? true
   ]
   if any? balls
   [ balls-fly!
     set activity? true
   ]
   if ticks mod 300 = 0 [ garbage-collection ]
   
   ;if is-a-cannon? current
   ;  [ ask current 
   ;    [ if not reloading?
   ;      [ ifelse not target-selected?  [ ready! ]
   ;        [ ifelse not on-target?      [ aim!   ]
   ;                                     [ fire!  ]
   ;        ]
   ;        
   ;      ]
   ;    ]
   ;  ]
   ask cannons
   [ if-else  reloading?
     [ set reload-countdown reload-countdown - 1
       if reload-countdown <= 0
       [ prepare-to-fire ]
     ]
     [ ifelse not target-selected?  [ ready! ]
       [ ifelse not on-target?      [ aim!   ]
                                    [ fire!  ]
       ]
     ]
   ]

     tick
  
     ifelse not activity?
     [ if ticks < 999999999
       [ tick-advance 999999999 - ticks ]
       if ticks > 1000000100
       [ setup
       ]
       if ticks mod 10 = 0
       [ if count cannons = 1
         [ ask cannons [ set color white - color ] ]
       ]
     ]
     [ if ticks > 999999999 [ reset-ticks ] ]
   ]

end

to prepare-to-fire
   set reloading? false
   set target-selected? false
   set on-target? false

end


to ready!
   set target one-of other cannons 
   if-else is-a-cannon? target
   [ set activity? true
     set target-selected? true
     ;; make sure I am not buried.
     ;; If I am buried, apply settings to self-destruct (or clear rubble, if lucky)
     ifelse is-rock?
     [ ask my-space with [ not is-air? ] [ set pcolor air ]
       set power 2
       set aim 0
       set reloading? false
       set target-selected? true
       set on-target? true
     ]
     [ ;; I am not buried--use normal aiming procedures
     
     
       if-else test? 
       [ set aim aim' * (sign subtract-headings (towards target) 0) ; (sign subtract-headings (towards target) 0) * 45
         set power power' ; 1.5
       ]
       [ set power range 1.5 4
         set aim (sign subtract-headings (towards target) 0) * range 5 85
       ]
     ]
   ]
   [ ;; no action for no targets
   ]
   
end

to-report range [ minr maxr ]
   report (minr + random-float (maxr - minr))
end
   

to aim!
   let diff .1 * subtract-headings aim heading
   if-else abs diff > 1
   [ rt diff ]
   [ set heading aim
     ;; see if there is  a clear path for the missle, nearby
     ;; (try to reduce some obvious self-destruction senarios)
     ;; build list of true/false values from patches in line along direction of aim
     let clear-target-path? n-values 5 [ [ is-air? ] of (patch-ahead (5 + 2 * ?)) ]
     ;; reduce to a single true/false value
     ;; (if any false (non-air) values, result is false (not a clear path)
     set clear-target-path? reduce [ ifelse-value ( ?2 = false) [ false ] [ ?1 ] ] clear-target-path?
     ifelse not clear-target-path?
     [ ;; not a clear path, 
       set target-selected? false
       set color red - 3
     ]
     [ ;; proceed with the selected angle
       set on-target? true
       set color black
     ]
   ]
   set activity? true

end

to fire!
   ;; cannon launches a projectile
   set heading aim
   hatch-balls 1
   [ set vx [ dx * power ] of myself
     set vy [ dy * power ] of myself
     set ox xcor
     set oy ycor
     set nx xcor + [ dx * size ] of myself
     set ny ycor + [ dy * size ] of myself
     setxy nx ny
     set frame 0
     set my-shape first bomb-shape
     set my-size item 2 bomb-shape
     set my-frames item 1 bomb-shape
     set size 5 * my-size
     set shape (word my-shape floor frame)
     set color black
     set off-screen? false
     set shots shots + 1
     set ascending? true
   ]
   set reloading? true
   set reload-countdown fire-rate
   set activity? true
end
 
   
to balls-fly!   
   ask balls
   [ ; set vx vx 
     set vy vy  + g
     set ox nx
     set oy ny
     set nx nx + vx
     set ny ny + vy
     ;; flew off side of screen
     if nx < min-pxcor or nx > max-pxcor [ destroy-ball ]
     ;; dropped past bottom of screen
     if ny < min-pycor [ destroy-ball ]
     ;; flew off top of screen
     ifelse ny > max-pycor
     [ ;; track xcor, but hide
       if not off-screen? [ set off-screen? true set shape "pointer-a" set size pointer-size]
       setxy nx max-pycor - size * .5
       set label (word (floor ny * 5) "m")
       if ascending? and oy > ny [ set ascending? false set shape "pointer-d" ]
     ]
     [ ;; still on (or back on) screen
       ;; move to new position
       ; if ox != nx or oy != ny [ set pcolor smoke ]
       ; if ticks mod 5 = 0 [ ask patch-at (- vx) (- vy) [ set pcolor smoke ] ]
       setxy nx ny
       let nearby-balls other balls in-radius size with [ not off-screen? ]
       if any? ashes-here or any? smoke-here or any? nearby-balls or not is-air?
       [ ask nearby-balls [ bang! ]
         bang!
       ]
       ; ask neighbors [ set pcolor air]
       
       if vx != 0 or vy != 0
       [ if-else (vx * vx + vy * vy) <= 1
         [ set heading heading + 10  * sign vx]
         [ let new atan vx vy  
           let diff .2 * subtract-headings new  heading
           set heading heading + diff
         ]
       ]
       
       set frame frame + frame-rate if frame >= my-frames [ set frame 0 ]
       set shape (word my-shape floor frame)
       
       ;; if was hidden, show again
       if off-screen? [ set off-screen? false set size ball-size set label "" ]
     ]
   ]
end

to destroy-ball
   ;if-else count cannons > 1
   ;[ set current one-of cannons with [ self != current ] 
   ;  ask current [ prepare-to-fire ]
   ;]
   ;[ set current nobody ]
   die
end   

to destroy-tree
   set trees-killed trees-killed + 1
   die
end   

to bang!
   let rad 8
   hide-turtle
   let crater patches in-radius rad
   ask crater 
   [ set pcolor air
   ]
   ask crater
   [  if random 5 = 0 
     [ make-smoke make-ashes 1
     ]
   ]
   ask crater
   [
     ask neighbors with [is-rock? ] [ make-ashes 0 ]
   ]
   ask trees in-radius rad [ destroy-tree ]
   destroy-ball
end

to ka-boom!
   set hits hits + 1
   let rad 6
   let big-rad rad * 3
   let cloud  (patch-set [ patches in-radius big-rad ] of (patch-set [ patch-at 0 (2 * big-rad) ] of my-platform ) )
   let column (patch-set [ patches at-points n-values big-rad [ (list 0 ? ) ] ] of my-platform )
   let crater (patch-set [ patches in-radius rad ] of my-platform)
   let total (patch-set cloud column)
   ask n-of 200 total [ let r random 3 if-else r = 2 [ make-smoke ] [ make-ashes r ] ]
   ask crater with [ random 9 = 0 ] [ ifelse random 2 = 0 [ make-smoke] [ make-ashes 1] ]
   ;ask column with [ random 2 = 0 ] [ make-ashes 0 ] 
   ;ask cloud  with [ random 6 = 0 ] [ if-else random 2 = 0 [ make-smoke ][ make-ashes 1 ] ]
   ask trees with [ member? root column or member? root cloud or member? root crater] [ destroy-tree ]
   ask my-base [ die ]
   die
end
   
to rocks-smoke-ashes-fire!
;   let in-air patches with
;     [ pycor > min-pycor and is-rock?
;       and
;       ( value-from patch-at 0 -1 [ is-air? ]
;         or ( ( pycor = max-pycor or value-from patch-at 0 1 [ is-air? ] )
;              and (not any? patches at-points [[-1 -1][1 -1]] with [ is-rock?] )
;            )
;        )
;     ]
;   if any? in-air
;   [ set activity? true
;     ask in-air 
;     [ make-ashes
;       set pcolor air
;     ]
;   ]
   ;  if any? smoke or any? ashes [ set activity? true]
   ask smoke
   [ if pxcor <= min-pxcor or pxcor >= max-pxcor or pycor >= max-pycor or random 1000 < 20
     [ die ]
     setxy (xcor + ((.5 * random 3) - .5)) (ycor + 1)
     set color smoke-color
     rt 5
     
   ]
   ask ashes 
   [ let over neighbors with [ pycor > [pycor] of myself and is-rock? ]
     if any? over
     [ ask over [ make-ashes 0 ] ]
   ]
   ask ashes
   [ ;; accelerate due to gravity
     set vy vy + g
     ;; project next location
     set nx nx + vx
     set ny ny + vy 
     
     ;; if at or passed edge of screen, die
     if nx <= min-pxcor or nx >= max-pxcor or ny <= min-pycor or ny >= max-pycor
     [ die ]
     ;; apply next location
     setxy nx ny
     ;; did we hit rock?
     let under patch-at 0 -1
     let over patch-at 0 1
     if any? neighbors with [ is-rock? ]
     [ ;; stop moving
       set vx 0 set vy -1
       setxy pxcor pycor
       ;; is there rock underneath?
       if is-patch? under and [ is-rock? ] of under
       [ ;; yes. stop.
         set pcolor ash
         set under nobody
         set over nobody
         die
       ]
     ]
   ]
   ask trees with [ [ is-air? ] of root ] [ destroy-tree ]
end

to-report is-air? report shade-of? pcolor sky end
to-report is-rock? report shade-of? pcolor brown end
to-report is-smoke? report shade-of? pcolor orange end
   
to make-ashes [ flying ]
   sprout-ashes 1
   [ set color ash 
     set pcolor air
     set nx xcor
     set ny ycor
     ifelse flying = 1
     [ set vx random-float 2.0 - 1.0
       set vy random-float 1.0 
     ]
     [ if flying = -1
       [ set vy -1 ]
     ] 
   ]
end
to make-smoke
   sprout-smoke 1
   [ set color smoke-color 
     set size 3
     set pcolor air
   ]
end

to garbage-collection
   ;; turn orphaned (floating) rock patches into ash turtles
   ask patches with [ pycor > min-pycor and is-rock? and  [ is-air? ] of patch-at 0 -1 ]
   [ make-ashes 0 ]
end
   

                    


Download Link

View or download the complete model file (to download: right-click, save-link-as):
-- Download obliteration_2009 --