[jemini~life-tank:cca5e42d] Jemini jar updated. OSX build error (missing icon) fixed.

  • From: jaymcgavren@kenai.com
  • To: commits@jemini.kenai.com
  • Subject: [jemini~life-tank:cca5e42d] Jemini jar updated. OSX build error (missing icon) fixed.
  • Date: Sun, 28 Feb 2010 00:47:09 +0000

Project:    jemini
Repository: life-tank
Revision:   cca5e42d116d7ffc170314af5a94c23e80fe14fc
Author:     jaymcgavren
Date:       2010-02-28 00:46:43 UTC
Link:       

Log Message:
------------
Jemini jar updated. OSX build error (missing icon) fixed.
Jemini jar updated. OSX build error (missing icon) fixed.


Revisions:
----------
a152cd4ec0d23755fb64b5c21745a7cd5eef250b
cca5e42d116d7ffc170314af5a94c23e80fe14fc


Modified Paths:
---------------
build_configuration.rb
lib/java/jemini.jar
src/behaviors/nuke_shooter.rb
src/behaviors/rolling_mine_shooter.rb
src/behaviors/shell_shooter.rb
src/behaviors/shootable_barrel.rb
src/game_objects/explosion.rb
src/game_objects/ground.rb
src/game_objects/nuke.rb
src/game_objects/nuke_selection.rb
src/game_objects/rolling_mine.rb
src/game_objects/rolling_mine_selection.rb
src/game_objects/shell.rb
src/game_objects/shell_selection.rb
src/game_objects/tank.rb
src/game_objects/tank_wheel.rb
src/inputs/menu_input.rb
src/main.rb
src/states/menu_state.rb
src/states/play_state.rb


Added Paths:
------------
data/armor.png
data/armor.xcf
data/bombard_marker.xcf
data/bombard_marker_default1.png
data/bombard_marker_default2.png
data/jump.png
data/jump.xcf
data/missile.png
data/missile.xcf
data/play/explosion.png
data/play/explosion.xcf
data/play/missile_launch.wav
data/play/tracker_beep.wav
data/play/tracker_clang.wav
data/smoke.xcf
data/smoke_default1.png
data/smoke_default2.png
data/smoke_default3.png
data/smoke_default4.png
data/smoke_default5.png
data/smoke_default6.png
data/smoke_default7.png
src/behaviors/armor_defense.rb
src/behaviors/bombard_shooter.rb
src/behaviors/evasion_defense.rb
src/behaviors/healthy.rb
src/behaviors/missile_shooter.rb
src/behaviors/repel_defense.rb
src/behaviors/selection.rb
src/behaviors/self_destruct_defense.rb
src/game_objects/armor_selection.rb
src/game_objects/bombard_marker.rb
src/game_objects/bombard_selection.rb
src/game_objects/evasion_selection.rb
src/game_objects/missile.rb
src/game_objects/missile_selection.rb
src/game_objects/smoke.rb


Diffs:
------
diff --git a/build_configuration.rb b/build_configuration.rb
index f2419f4..f2bbc14 100644
--- a/build_configuration.rb
+++ b/build_configuration.rb
@@ -27,6 +27,10 @@ configuration do |c|
   # add -verbosegc to see what the GC is doing
   c.jvm_arguments = "-XX:+UseConcMarkSweepGC -Djruby.compile.mode=FORCE 
-Xms256m -Xmx512m"
 
+  c.java_library_path = "lib/java/native_files"
+  c.mac_icon_path     = File.expand_path('icons/jemini.icns')
+  c.windows_icon_path = File.expand_path('icons/jemini.ico')
+
   # Bundler options
   # c.do_not_generate_plist = false
 end
diff --git a/lib/java/jemini.jar b/lib/java/jemini.jar
index 036eb54..0321157 100644
Binary files a/lib/java/jemini.jar and b/lib/java/jemini.jar differ
diff --git a/data/armor.png b/data/armor.png
new file mode 100644
index 0000000..054eef9
Binary files /dev/null and b/data/armor.png differ
diff --git a/data/armor.xcf b/data/armor.xcf
new file mode 100644
index 0000000..ffb15ee
Binary files /dev/null and b/data/armor.xcf differ
diff --git a/data/bombard_marker.xcf b/data/bombard_marker.xcf
new file mode 100644
index 0000000..63deb4c
Binary files /dev/null and b/data/bombard_marker.xcf differ
diff --git a/data/bombard_marker_default1.png 
b/data/bombard_marker_default1.png
new file mode 100644
index 0000000..a57e3d1
Binary files /dev/null and b/data/bombard_marker_default1.png differ
diff --git a/data/bombard_marker_default2.png 
b/data/bombard_marker_default2.png
new file mode 100644
index 0000000..d0585a0
Binary files /dev/null and b/data/bombard_marker_default2.png differ
diff --git a/data/jump.png b/data/jump.png
new file mode 100644
index 0000000..8fc3a90
Binary files /dev/null and b/data/jump.png differ
diff --git a/data/jump.xcf b/data/jump.xcf
new file mode 100644
index 0000000..72084ac
Binary files /dev/null and b/data/jump.xcf differ
diff --git a/data/missile.png b/data/missile.png
new file mode 100644
index 0000000..29cac7e
Binary files /dev/null and b/data/missile.png differ
diff --git a/data/missile.xcf b/data/missile.xcf
new file mode 100644
index 0000000..6889377
Binary files /dev/null and b/data/missile.xcf differ
diff --git a/data/play/explosion.png b/data/play/explosion.png
new file mode 100644
index 0000000..c62f10d
Binary files /dev/null and b/data/play/explosion.png differ
diff --git a/data/play/explosion.xcf b/data/play/explosion.xcf
new file mode 100644
index 0000000..f721349
Binary files /dev/null and b/data/play/explosion.xcf differ
diff --git a/data/play/missile_launch.wav b/data/play/missile_launch.wav
new file mode 100644
index 0000000..d0254b7
Binary files /dev/null and b/data/play/missile_launch.wav differ
diff --git a/data/play/power_arrow_head.png b/data/play/power_arrow_head.png
deleted file mode 100644
index 159c60d..0000000
Binary files a/data/play/power_arrow_head.png and /dev/null differ
diff --git a/data/play/power_arrow_neck.png b/data/play/power_arrow_neck.png
deleted file mode 100644
index 71f889d..0000000
Binary files a/data/play/power_arrow_neck.png and /dev/null differ
diff --git a/data/play/smoke.png b/data/play/smoke.png
deleted file mode 100644
index c3bb82d..0000000
Binary files a/data/play/smoke.png and /dev/null differ
diff --git a/data/play/tracker_beep.wav b/data/play/tracker_beep.wav
new file mode 100644
index 0000000..5b92ed4
Binary files /dev/null and b/data/play/tracker_beep.wav differ
diff --git a/data/play/tracker_clang.wav b/data/play/tracker_clang.wav
new file mode 100644
index 0000000..4bf8b01
Binary files /dev/null and b/data/play/tracker_clang.wav differ
diff --git a/data/smoke.xcf b/data/smoke.xcf
new file mode 100644
index 0000000..12142f0
Binary files /dev/null and b/data/smoke.xcf differ
diff --git a/data/smoke_default1.png b/data/smoke_default1.png
new file mode 100644
index 0000000..78c7638
Binary files /dev/null and b/data/smoke_default1.png differ
diff --git a/data/smoke_default2.png b/data/smoke_default2.png
new file mode 100644
index 0000000..003aa71
Binary files /dev/null and b/data/smoke_default2.png differ
diff --git a/data/smoke_default3.png b/data/smoke_default3.png
new file mode 100644
index 0000000..6003991
Binary files /dev/null and b/data/smoke_default3.png differ
diff --git a/data/smoke_default4.png b/data/smoke_default4.png
new file mode 100644
index 0000000..44c7bfa
Binary files /dev/null and b/data/smoke_default4.png differ
diff --git a/data/smoke_default5.png b/data/smoke_default5.png
new file mode 100644
index 0000000..82b8121
Binary files /dev/null and b/data/smoke_default5.png differ
diff --git a/data/smoke_default6.png b/data/smoke_default6.png
new file mode 100644
index 0000000..117a05e
Binary files /dev/null and b/data/smoke_default6.png differ
diff --git a/data/smoke_default7.png b/data/smoke_default7.png
new file mode 100644
index 0000000..6003991
Binary files /dev/null and b/data/smoke_default7.png differ
diff --git a/src/behaviors/armor_defense.rb b/src/behaviors/armor_defense.rb
new file mode 100644
index 0000000..d8b7bd4
--- /dev/null
+++ b/src/behaviors/armor_defense.rb
@@ -0,0 +1,9 @@
+class ArmorDefense < Jemini::Behavior
+  ARMOR_REDUCTION_RATE = 0.66
+  
+  def load
+    game_object.on_before_life_changes do |event|
+      event.desired_value = event.previous_value - ((event.previous_value - 
event.desired_value) * ARMOR_REDUCTION_RATE)
+    end
+  end
+end
\ No newline at end of file
diff --git a/src/behaviors/bombard_shooter.rb 
b/src/behaviors/bombard_shooter.rb
new file mode 100644
index 0000000..2d651e9
--- /dev/null
+++ b/src/behaviors/bombard_shooter.rb
@@ -0,0 +1,53 @@
+class BombardShooter < Jemini::Behavior
+  POWER_FACTOR = 240.0
+  BOMBARD_MISSILES = 4
+  MISSILE_OFFSET = 25.0
+
+  depends_on :Timeable
+  depends_on :Audible
+
+  def load
+    game_object.add_behavior :ShootableBarrel
+    game_object.on_countdown_complete :shoot_missile
+    @missiles = []
+  end
+
+  def reload_time
+    10
+  end
+
+  def fire_weapon(power, angle)
+    #TODO: configurable fire_from_distance to replace barrel anchor
+    shell = game_state.create :BombardMarker, game_object.player_id, 
game_object
+    shell_offset =  Vector.new(0.0, -5.0 - @game_object.barrel_width)
+    shell_position = shell_offset.pivot_around_degrees(Vector::ORIGIN, 
@game_object.physical_rotation + angle)
+    shell.body_position = game_object.barrel_offset + shell_position
+    shell.physical_rotation = game_object.physical_rotation + angle + 90.0
+    shell_vector = Vector.from_polar_vector(power * POWER_FACTOR, angle + 
@game_object.physical_rotation)
+    shell.add_force shell_vector
+    game_state.manager(:sound).play_sound :fire_cannon
+    @game_object.add_force shell_vector.negate
+  end
+
+  def bombard(marker)
+    @missiles = []
+    @marker = marker
+    1.upto BOMBARD_MISSILES do |n|
+      game_object.add_countdown "shoot_missiles#{n}", n * 0.5
+    end
+  end
+
+  def shoot_missile(timer)
+    return unless timer =~ /shoot_missiles\d+/
+    missile = game_state.create :Missile
+    missile.body_position = game_object.body_position + Vector.new(0.0, 
-MISSILE_OFFSET)
+    missile.track @marker
+    game_object.emit_sound :missile_launch
+    @missiles.each {|m| missile.add_excluded_physical m }
+    @missiles << missile
+    missile.on_after_remove do
+      @missiles.delete missile
+      game_state.remove @marker if @missiles.empty?
+    end
+  end
+end
\ No newline at end of file
diff --git a/src/behaviors/evasion_defense.rb 
b/src/behaviors/evasion_defense.rb
new file mode 100644
index 0000000..346fb6f
--- /dev/null
+++ b/src/behaviors/evasion_defense.rb
@@ -0,0 +1,36 @@
+class EvasionDefense < Jemini::Behavior
+  PARANOIA_RADIUS  = 150.0
+  EVASION_FORCE    = -500_000.0
+  EVASION_COOLDOWN = 2.5
+  
+  depends_on :Timeable
+  
+  def load
+    game_object.on_update :check_for_incoming
+#    game_object.on_physical_collided :reset_evasion
+    game_object.on_countdown_complete :reset_evasion
+  end
+
+  def check_for_incoming(delta)
+    game_state.manager(:tag).find_by_tag(:weapon).each do |weapon|
+      next if @evading
+      next if weapon.has_tag? game_object.player_id
+      evade if weapon.body_position.near?(game_object.body_position, 
PARANOIA_RADIUS)
+
+    end
+  end
+
+  def reset_evasion(message)
+    return unless message == :evasion_cooldown
+    @evading = false #if message.other.has_tag? :ground
+  end
+
+private
+
+  def evade
+    puts "evading!!"
+    @evading = true
+    game_object.add_force(Vector.new(0, EVASION_FORCE))
+    game_object.add_countdown(:evasion_cooldown, EVASION_COOLDOWN)
+  end
+end
\ No newline at end of file
diff --git a/src/behaviors/healthy.rb b/src/behaviors/healthy.rb
new file mode 100644
index 0000000..3d86f66
--- /dev/null
+++ b/src/behaviors/healthy.rb
@@ -0,0 +1,19 @@
+class Healthy < Jemini::Behavior
+  INITIAL_LIFE = 100.0
+  
+  wrap_with_callbacks :life=
+  wrap_with_callbacks :death
+
+  attr_reader :life
+
+  def load
+    @life = INITIAL_LIFE
+  end
+
+  def life=(amount)
+    @life = amount
+    death if @life <= 0
+  end
+
+  def death; end
+end
\ No newline at end of file
diff --git a/src/behaviors/missile_shooter.rb 
b/src/behaviors/missile_shooter.rb
new file mode 100644
index 0000000..933c4e2
--- /dev/null
+++ b/src/behaviors/missile_shooter.rb
@@ -0,0 +1,131 @@
+class MissileShooter < Jemini::Behavior
+  RELOAD_UPDATES_PER_SECOND = 1.0 / 30.0
+  ANGLE_ADJUSTMENT_FACTOR = 1.5 / 20.0
+  POWER_ADJUSTMENT_FACTOR = 1.0 / 20.0
+  TOTAL_POWER = 100.0
+  BARREL_OUTWARD_OFFSET = 5.0 # moves the barrel outwards
+  BARREL_HEIGHT_OFFSET  = 5.0 # moves the barrel upwards
+
+  depends_on :Updates
+  depends_on :HandlesEvents
+  depends_on :Physical
+  depends_on :Timeable
+
+  attr_accessor :power, :angle, :barrel, :ready_to_fire
+
+  def load
+    @angle = 45.0
+    @power = 50.0
+
+    @zero = Vector.new(0.0, 0.0)
+    @barrel_outward_offset = Vector.new 0.0, BARREL_OUTWARD_OFFSET
+    @barrel = game_state.create :Turret
+
+    @power_arrow_neck = game_state.create :PowerArrowNeck
+    @power_arrow_head = game_state.create :PowerArrowHead
+    @power_changed = true # to set the proper scale on the first update, 
flag as true
+
+    @game_object.handle_event :adjust_angle, :handle_angle_adjustment
+    @game_object.handle_event :adjust_power, :handle_power_adjustment
+    @game_object.handle_event :fire, :fire
+#    @game_object.handle_event :fire_shell, :dispatch_fire_weapon
+#    @game_object.handle_event :fire_nuke, :dispatch_fire_weapon
+#    @game_object.handle_event :fire_rolling_mine, :dispatch_fire_weapon
+
+    game_object.on_update :update_barrel_and_arrow
+
+    game_object.on_countdown_complete do |name|
+      next unless name == :shot
+      self.ready_to_fire = true
+    end
+
+    game_object.on_timer_tick do |timer|
+      percent = timer.percent_complete
+      @power_arrow_head.color = @power_arrow_neck.color = Color.new(percent, 
percent, percent)
+    end
+
+    charge_weapon
+
+  end
+
+  def unload
+    game_state.remove @power_arrow_head
+    game_state.remove @power_arrow_neck
+    game_state.remove @barrel
+  end
+
+  def barrel_anchor
+    @barrel_anchor ||= Vector.new(0.0, -(@barrel.image.width / 2))
+  end
+
+  def barrel_width
+    @barrel.image.width
+  end
+
+  def barrel_offset
+#    game_object.body_position.pivot_around_degrees(Vector.new(0.0, -20), 
game_object.physical_rotation - 90.0)
+    offset = Vector.new(0.0, 0.0).pivot_around_degrees(Vector.new(0.0, 
BARREL_HEIGHT_OFFSET), game_object.physical_rotation)
+    game_object.body_position + offset
+  end
+
+
+  def update_barrel_and_arrow(delta)
+    barrel_position = 
barrel_anchor.pivot_around_degrees(@barrel_outward_offset, 
game_object.physical_rotation + @angle)
+    @barrel.position = barrel_position + barrel_offset #+ 
game_object.body_position
+    @barrel.image_rotation = @angle + game_object.physical_rotation - 90.0
+
+    if @power_changed
+      width_factor = 2 * @power / 100.0
+      @power_arrow_neck.scale_image_from_original width_factor, 1.0
+    end
+
+    neck_offset = barrel_anchor + Vector.new(0.0, -4.0 - 
(@power_arrow_neck.image.width + @barrel.image.width) / 2.0)
+    neck_position = neck_offset.pivot_around_degrees(@zero, 
game_object.physical_rotation + angle)
+    @power_arrow_neck.position = neck_position + barrel_offset #+ 
game_object.body_position
+    @power_arrow_neck.image_rotation = angle + game_object.physical_rotation 
- 90.0
+
+    power_arrow_head_anchor = neck_offset + Vector.new(0.0, (6.0 - 
(@power_arrow_neck.image.width) / 2.0))
+    head_position = power_arrow_head_anchor.pivot_around_degrees(@zero, 
@game_object.physical_rotation + angle)
+    @power_arrow_head.position = head_position + barrel_offset #+ 
game_object.body_position
+    @power_arrow_head.image_rotation = angle + game_object.physical_rotation 
- 90.0
+
+#      game_state.manager(:render).debug(:point, :red,   :position => 
(barrel_position + body_position))
+#      game_state.manager(:render).debug(:point, :green, :position => 
(neck_position + body_position))
+#      game_state.manager(:render).debug(:point, :blue,  :position => 
(head_position + body_position))
+  end
+
+  def charge_weapon
+    self.ready_to_fire = false
+    game_object.add_countdown :shot, game_object.reload_time, 
RELOAD_UPDATES_PER_SECOND
+  end
+
+  def ready_to_fire?
+    @ready_to_fire
+  end
+
+  def ready_to_fire=(value)
+    @ready_to_fire = value
+    color = (value ? Color.new(:yellow) : Color.new(:black))
+    @power_arrow_head.color = @power_arrow_neck.color = color
+  end
+
+  # TODO: Consider auto-wiring messages based on dispatch_ or handle_ method 
names
+  def fire(message)
+    return unless ready_to_fire?
+    game_object.fire_weapon(@power, @angle)
+    charge_weapon
+  end
+
+  def handle_angle_adjustment(message)
+    new_angle = angle + (message.value * ANGLE_ADJUSTMENT_FACTOR * 
message.delta)
+    self.angle = new_angle if new_angle < 90.0 && new_angle > -90.0
+  end
+
+  def handle_power_adjustment(message)
+    new_power = power + (message.value * POWER_ADJUSTMENT_FACTOR * 
message.delta)
+    if new_power < TOTAL_POWER && new_power > 10.0
+      @power_changed = true if new_power != @power # @power_changed is used 
during update
+      self.power = new_power
+    end
+  end
+end
\ No newline at end of file
diff --git a/src/behaviors/nuke_shooter.rb b/src/behaviors/nuke_shooter.rb
index ef48e11..74e31c5 100644
--- a/src/behaviors/nuke_shooter.rb
+++ b/src/behaviors/nuke_shooter.rb
@@ -1,17 +1,20 @@
 class NukeShooter < Jemini::Behavior
   POWER_FACTOR = 240.0
 
+  def load
+    game_object.add_behavior :ShootableBarrel
+  end
+
   def reload_time
     6
   end
   
   def fire_weapon(power, angle)
     #TODO: configurable fire_from_distance to replace barrel anchor
-    shell = game_state.create :Nuke
-#    shell_offset =  @game_object.barrel_anchor + Vector.new(0.0, -5.0 + 
@game_object.barrel_anchor.y)
+    shell = game_state.create :Nuke, game_object.player_id
     shell_offset =  Vector.new(0.0, -5.0 - @game_object.barrel_width)
     shell_position = shell_offset.pivot_around_degrees(Vector::ORIGIN, 
@game_object.physical_rotation + angle)
-    shell.body_position = game_object.barrel_offset + shell_position 
#game_object.body_position + shell_position
+    shell.body_position = game_object.barrel_offset + shell_position
     shell.physical_rotation = game_object.physical_rotation + angle + 90.0
     shell_vector = Vector.from_polar_vector(power * POWER_FACTOR, angle + 
@game_object.physical_rotation)
     shell.add_force shell_vector
diff --git a/src/behaviors/repel_defense.rb b/src/behaviors/repel_defense.rb
new file mode 100644
index 0000000..e8df897
--- /dev/null
+++ b/src/behaviors/repel_defense.rb
@@ -0,0 +1,3 @@
+class RepelDefense < Jemini::Behavior
+  
+end
\ No newline at end of file
diff --git a/src/behaviors/rolling_mine_shooter.rb 
b/src/behaviors/rolling_mine_shooter.rb
index e631d4e..ffc51ca 100644
--- a/src/behaviors/rolling_mine_shooter.rb
+++ b/src/behaviors/rolling_mine_shooter.rb
@@ -1,13 +1,17 @@
 class RollingMineShooter < Jemini::Behavior
   POWER_FACTOR = 240.0
 
+  def load
+    game_object.add_behavior :ShootableBarrel
+  end
+
   def reload_time
     4
   end
 
   def fire_weapon(power, angle)
     #TODO: configurable fire_from_distance to replace barrel anchor
-    shell = game_state.create :RollingMine
+    shell = game_state.create :RollingMine, game_object.player_id
 #    shell_offset =  @game_object.barrel_anchor + Vector.new(0.0, -5.0 + 
@game_object.barrel_anchor.y)
     shell_offset =  Vector.new(0.0, -5.0 - @game_object.barrel_width)
     shell_position = shell_offset.pivot_around_degrees(Vector::ORIGIN, 
@game_object.physical_rotation + angle)
diff --git a/src/behaviors/selection.rb b/src/behaviors/selection.rb
new file mode 100644
index 0000000..2b511b1
--- /dev/null
+++ b/src/behaviors/selection.rb
@@ -0,0 +1,40 @@
+class Selection < Jemini::Behavior
+  NAME_OFFSET        = Vector.new(0, 0)
+  DESCRIPTION_OFFSET = Vector.new(0, 50)
+  IMAGE_OFFSET       = Vector.new(0, 50)
+  depends_on :Spatial
+
+  def load
+    game_object.on_after_position_changes :move_name
+#    game_object.on_after_position_changes :move_description
+    game_object.on_after_position_changes :move_image
+    
+  end
+
+  def for_player(number)
+    @player_number = number
+  end
+
+  def move_name(message)
+    @name_text ||= game_state.create :Text, game_object.name
+    @name_text.position = game_object.position + NAME_OFFSET
+  end
+
+  def move_description(message)
+    @description_text ||= game_state.create :Text, game_object.description
+    @description_text.position = game_object.position + DESCRIPTION_OFFSET
+  end
+
+  def move_image(message)
+    @image ||= game_state.create :GameObject, :DrawableImage
+    @image.image = game_object.image
+    @image.position = game_object.position + IMAGE_OFFSET
+  end
+
+  def unload
+    game_state.remove @name_text        if @name_text
+    game_state.remove @description_text if @description_text
+    game_state.remove @image            if @image
+  end
+
+end
\ No newline at end of file
diff --git a/src/behaviors/self_destruct_defense.rb 
b/src/behaviors/self_destruct_defense.rb
new file mode 100644
index 0000000..418998e
--- /dev/null
+++ b/src/behaviors/self_destruct_defense.rb
@@ -0,0 +1,5 @@
+class SelfDestructDefense < Jemini::Behavior
+  def load
+    
+  end
+end
\ No newline at end of file
diff --git a/src/behaviors/shell_shooter.rb b/src/behaviors/shell_shooter.rb
index 3e21395..99ae735 100644
--- a/src/behaviors/shell_shooter.rb
+++ b/src/behaviors/shell_shooter.rb
@@ -1,17 +1,20 @@
 class ShellShooter < Jemini::Behavior
   POWER_FACTOR = 240.0
 
+  def load
+    game_object.add_behavior :ShootableBarrel
+  end
+  
   def reload_time
     3
   end
 
   def fire_weapon(power, angle)
     #TODO: configurable fire_from_distance to replace barrel anchor
-    shell = game_state.create :Shell
-#    shell_offset =  @game_object.barrel_anchor + Vector.new(0.0, -5.0 + 
@game_object.barrel_anchor.y)
+    shell = game_state.create :Shell, game_object.player_id
     shell_offset =  Vector.new(0.0, -5.0 - @game_object.barrel_width)
     shell_position = shell_offset.pivot_around_degrees(Vector::ORIGIN, 
@game_object.physical_rotation + angle)
-    shell.body_position = game_object.barrel_offset + shell_position 
#game_object.body_position + shell_position
+    shell.body_position = game_object.barrel_offset + shell_position
     shell.physical_rotation = game_object.physical_rotation + angle + 90.0
     shell_vector = Vector.from_polar_vector(power * POWER_FACTOR, angle + 
@game_object.physical_rotation)
     shell.add_force shell_vector
diff --git a/src/behaviors/shootable_barrel.rb 
b/src/behaviors/shootable_barrel.rb
index 285322a..4ee740f 100644
--- a/src/behaviors/shootable_barrel.rb
+++ b/src/behaviors/shootable_barrel.rb
@@ -1,9 +1,9 @@
 class ShootableBarrel < Jemini::Behavior
-#  RELOAD_WARMUP_IN_SECONDS = 0.5 #3.5
   RELOAD_UPDATES_PER_SECOND = 1.0 / 30.0
   ANGLE_ADJUSTMENT_FACTOR = 1.5 / 20.0
   POWER_ADJUSTMENT_FACTOR = 1.0 / 20.0
-  TOTAL_POWER = 100.0
+  MINIMUM_POWER =  10.0
+  TOTAL_POWER   = 100.0
   BARREL_OUTWARD_OFFSET = 5.0 # moves the barrel outwards
   BARREL_HEIGHT_OFFSET  = 5.0 # moves the barrel upwards
   
@@ -17,35 +17,28 @@ class ShootableBarrel < Jemini::Behavior
   def load
     @angle = 45.0
     @power = 50.0
-
     @zero = Vector.new(0.0, 0.0)
     @barrel_outward_offset = Vector.new 0.0, BARREL_OUTWARD_OFFSET
     @barrel = game_state.create :Turret
+    @minimum_barrel_width = (8 * MINIMUM_POWER / 100.0) * 
@barrel.image_size.x
 
-    @power_arrow_neck = game_state.create :PowerArrowNeck
-    @power_arrow_head = game_state.create :PowerArrowHead
     @power_changed = true # to set the proper scale on the first update, 
flag as true
 
     @game_object.handle_event :adjust_angle, :handle_angle_adjustment
     @game_object.handle_event :adjust_power, :handle_power_adjustment
     @game_object.handle_event :fire, :fire
-#    @game_object.handle_event :fire_shell, :dispatch_fire_weapon
-#    @game_object.handle_event :fire_nuke, :dispatch_fire_weapon
-#    @game_object.handle_event :fire_rolling_mine, :dispatch_fire_weapon
     
     game_object.on_update :update_barrel_and_arrow
 
     game_object.on_countdown_complete do |name|
-      if name == :shot
-        self.ready_to_fire = true
-      else
-        raise "countdown #{name.inspect} not supported!"
-      end
+      next unless name == :shot
+      self.ready_to_fire = true
     end
 
     game_object.on_timer_tick do |timer|
       percent = timer.percent_complete
-      @power_arrow_head.color = @power_arrow_neck.color = Color.new(percent, 
percent, percent)
+
+      @barrel.color = Color.new(percent, percent, percent)
     end
     
     charge_weapon
@@ -53,8 +46,6 @@ class ShootableBarrel < Jemini::Behavior
   end
 
   def unload
-    game_state.remove @power_arrow_head
-    game_state.remove @power_arrow_neck
     game_state.remove @barrel
   end
 
@@ -67,31 +58,22 @@ class ShootableBarrel < Jemini::Behavior
   end
 
   def barrel_offset
-#    game_object.body_position.pivot_around_degrees(Vector.new(0.0, -20), 
game_object.physical_rotation - 90.0)
     offset = Vector.new(0.0, 0.0).pivot_around_degrees(Vector.new(0.0, 
BARREL_HEIGHT_OFFSET), game_object.physical_rotation)
     game_object.body_position + offset
   end
 
 
   def update_barrel_and_arrow(delta)
-    barrel_position = 
barrel_anchor.pivot_around_degrees(@barrel_outward_offset, 
game_object.physical_rotation + @angle)
-    @barrel.position = barrel_position + barrel_offset #+ 
game_object.body_position
-    @barrel.image_rotation = @angle + game_object.physical_rotation - 90.0
-
     if @power_changed
-      width_factor = 2 * @power / 100.0
-      @power_arrow_neck.scale_image_from_original width_factor, 1.0
+      width_factor = (8 * @power / 750.0) + 0.50
+      @barrel.scale_image_from_original width_factor, 1.0
     end
 
-    neck_offset = barrel_anchor + Vector.new(0.0, -4.0 - 
(@power_arrow_neck.image.width + @barrel.image.width) / 2.0)
-    neck_position = neck_offset.pivot_around_degrees(@zero, 
game_object.physical_rotation + angle)
-    @power_arrow_neck.position = neck_position + barrel_offset #+ 
game_object.body_position
-    @power_arrow_neck.image_rotation = angle + game_object.physical_rotation 
- 90.0
+    barrel_relative_position = Vector.new(0.0, (@barrel.image_size.x / 2.0)) 
+ @barrel_outward_offset
 
-    power_arrow_head_anchor = neck_offset + Vector.new(0.0, (6.0 - 
(@power_arrow_neck.image.width) / 2.0))
-    head_position = power_arrow_head_anchor.pivot_around_degrees(@zero, 
@game_object.physical_rotation + angle)
-    @power_arrow_head.position = head_position + barrel_offset #+ 
game_object.body_position
-    @power_arrow_head.image_rotation = angle + game_object.physical_rotation 
- 90.0
+    barrel_position = @zero.pivot_around_degrees(barrel_relative_position, 
game_object.physical_rotation + @angle)
+    @barrel.position = barrel_position + barrel_offset #+ 
game_object.body_position
+    @barrel.image_rotation = @angle + game_object.physical_rotation - 90.0
 
 #      game_state.manager(:render).debug(:point, :red,   :position => 
(barrel_position + body_position))
 #      game_state.manager(:render).debug(:point, :green, :position => 
(neck_position + body_position))
@@ -110,7 +92,7 @@ class ShootableBarrel < Jemini::Behavior
   def ready_to_fire=(value)
     @ready_to_fire = value
     color = (value ? Color.new(:yellow) : Color.new(:black))
-    @power_arrow_head.color = @power_arrow_neck.color = color
+    @barrel.color = color
   end
 
   # TODO: Consider auto-wiring messages based on dispatch_ or handle_ method 
names
@@ -127,7 +109,7 @@ class ShootableBarrel < Jemini::Behavior
 
   def handle_power_adjustment(message)
     new_power = power + (message.value * POWER_ADJUSTMENT_FACTOR * 
message.delta)
-    if new_power < TOTAL_POWER && new_power > 10.0
+    if new_power < TOTAL_POWER && new_power > MINIMUM_POWER
       @power_changed = true if new_power != @power # @power_changed is used 
during update
       self.power = new_power
     end
diff --git a/src/behaviors/weapon_selection.rb 
b/src/behaviors/weapon_selection.rb
deleted file mode 100644
index 909a701..0000000
--- a/src/behaviors/weapon_selection.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-class WeaponSelection < Jemini::Behavior
-  NAME_OFFSET        = Vector.new(0, 0)
-  DESCRIPTION_OFFSET = Vector.new(0, 50)
-  IMAGE_OFFSET       = Vector.new(0, 50)
-  depends_on :Spatial
-
-  def load
-    game_object.on_after_position_changes :move_name
-#    game_object.on_after_position_changes :move_description
-    game_object.on_after_position_changes :move_image
-    
-  end
-
-  def for_player(number)
-    @player_number = number
-  end
-
-  def move_name(message)
-    @name_text ||= game_state.create :Text, game_object.name
-    @name_text.position = game_object.position + NAME_OFFSET
-  end
-
-  def move_description(message)
-    @description_text ||= game_state.create :Text, game_object.description
-    @description_text.position = game_object.position + DESCRIPTION_OFFSET
-  end
-
-  def move_image(message)
-    @image ||= game_state.create :GameObject, :DrawableImage
-    @image.image = game_object.image
-    @image.position = game_object.position + IMAGE_OFFSET
-  end
-
-  def unload
-    game_state.remove @name_text        if @name_text
-    game_state.remove @description_text if @description_text
-    game_state.remove @image            if @image
-  end
-
-end
\ No newline at end of file
diff --git a/src/game_objects/armor_selection.rb 
b/src/game_objects/armor_selection.rb
new file mode 100644
index 0000000..e2a5b0d
--- /dev/null
+++ b/src/game_objects/armor_selection.rb
@@ -0,0 +1,23 @@
+class ArmorSelection < Jemini::GameObject
+  has_behavior :Selection
+
+  def name
+    "Armor"
+  end
+
+  def description
+    "Reduces all damage done."
+  end
+
+  def image
+    :armor
+  end
+
+  def next
+    :evasion_selection
+  end
+
+  def behavior
+    :armor_defense
+  end
+end
\ No newline at end of file
diff --git a/src/game_objects/bombard_marker.rb 
b/src/game_objects/bombard_marker.rb
new file mode 100644
index 0000000..e12df69
--- /dev/null
+++ b/src/game_objects/bombard_marker.rb
@@ -0,0 +1,51 @@
+class BombardMarker < Jemini::GameObject
+  has_behavior :Launchable
+  has_behavior :Timeable
+  has_behavior :Audible
+  has_behavior :AnimatedImage
+
+  def load(firing_player_number, firing_player)
+    animate_as :bombard_marker
+    @player = firing_player
+    add_tag :weapon
+    add_tag firing_player_number
+    remove_tag :damage
+    set_bounded_image :bombard_marker_default1
+    self.restitution = 0.0
+    on_physical_collided do |event|
+      unless @stuck
+        emit_sound :tracker_clang
+        add_countdown :beep, 0.5 # let them know of their doom
+      end
+      stick_to event.other
+    end
+
+    on_countdown_complete :bombard
+    on_countdown_complete :beep
+  end
+
+  def unload
+    
+  end
+
+  def beep(timer)
+    return unless timer == :beep
+    emit_sound :tracker_beep
+  end
+
+  def stick_to(stickee)
+    return if @stuck
+    @stuck = true
+    join_to_physical stickee, :joint => :fixed, :relaxation => 0.5
+    add_excluded_physical stickee
+    add_excluded_physical stickee.tank if stickee.has_tag? :wheel
+    add_countdown :bombard, 2 
+  end
+
+
+  def bombard(timer)
+    return unless timer == :bombard
+    @player.bombard(self) if @player.respond_to? :bombard # player could 
have died
+  end
+  
+end
\ No newline at end of file
diff --git a/src/game_objects/bombard_selection.rb 
b/src/game_objects/bombard_selection.rb
new file mode 100644
index 0000000..a8320b3
--- /dev/null
+++ b/src/game_objects/bombard_selection.rb
@@ -0,0 +1,23 @@
+class BombardSelection < Jemini::GameObject
+  has_behavior :Selection
+
+  def name
+    "Bombard Marker"
+  end
+
+  def description
+    "Shoots a marker to call a bombardment"
+  end
+
+  def image
+    :bombard_marker_default1
+  end
+
+  def next
+    :shell_selection
+  end
+
+  def behavior
+    :bombard_shooter
+  end
+end
\ No newline at end of file
diff --git a/src/game_objects/evasion_selection.rb 
b/src/game_objects/evasion_selection.rb
new file mode 100644
index 0000000..963277c
--- /dev/null
+++ b/src/game_objects/evasion_selection.rb
@@ -0,0 +1,23 @@
+class EvasionSelection < Jemini::GameObject
+  has_behavior :Selection
+
+  def name
+    "Evasion"
+  end
+
+  def description
+    "Jumps when a shot comes close to the tank"
+  end
+
+  def image
+    :jump
+  end
+
+  def next
+    :armor_selection
+  end
+
+  def behavior
+    :evasion_defense
+  end
+end
\ No newline at end of file
diff --git a/src/game_objects/explosion.rb b/src/game_objects/explosion.rb
index 2408bb2..0d2e8ab 100644
--- a/src/game_objects/explosion.rb
+++ b/src/game_objects/explosion.rb
@@ -20,19 +20,42 @@ class Explosion < Jemini::GameObject
       :sound_pitch => 1.0,
       :damage => 50,
       :radius => 64.0,
-      :force => 50000,
+      :force => 500,
     }.merge(options)
     
-    self.position = (@options[:location])
+    self.position = @options[:location]
     game_state.manager(:sound).play_sound :explosion, 
@options[:sound_volume], @options[:sound_pitch]
     
-    smoke = game_state.create(:FadingImage, :smoke, Color.new(:white), 
@options[:duration] * 10.0)
-    smoke.set_position position
-    smoke.scale_image_from_original(@options[:radius] / 64.0)
+    explosion = game_state.create(:FadingImage, :explosion, 
Color.new(:white), @options[:duration] * 2.0)
+    explosion.position = position
+    explosion.scale_image_from_original(@options[:radius] / 64.0)
+    explosion.on_before_remove do
+      smoke = game_state.create_on_layer(:FadingImage, :smoke, 
:smoke_default1, Color.new(:white), 3.0)
+      smoke.add_behavior :AnimatedImage
+      smoke.add_behavior :Movable
+      smoke.position = explosion.position
+      smoke.animate_as :smoke
+      smoke.animation_speed = 50
+      smoke.move Vector.new(2.0, 0.75)
+      @smoke_size = 1.0
+      smoke.on_update do
+        @smoke_size += 0.0001
+        smoke.image_scaling((64.0 * @smoke_size) / 64.0)
+      end
+      smoke.on_before_remove { game_state.remove self }
+    end
+
     
     add_countdown(:fade, @options[:duration])
     on_countdown_complete do |name|
-      game_state.remove self if name == :fade
+      next unless name == :fade
+      remove_behavior :Magnetic
+      # due to bug, taggable is removed too
+      # but it cannot be readded.
+      # all we really need is has_tag?g
+      def self.has_tag?(*args)
+        false
+      end
     end
 
     @already_hit = []
diff --git a/src/game_objects/ground.rb b/src/game_objects/ground.rb
index a66a059..f74e928 100644
--- a/src/game_objects/ground.rb
+++ b/src/game_objects/ground.rb
@@ -2,7 +2,7 @@ class Ground < Jemini::GameObject
   POINT_SPACING     = 40
   DIRT_DEATH_FACTOR =  0.50
   MINIMUM_BOTTOM    = 50
-  VARIANCE_FACTOR   =  0.05
+  VARIANCE_FACTOR   =  0.10
   MAX_STEEPNESS     = 18
   
   has_behavior :Taggable
diff --git a/src/game_objects/missile.rb b/src/game_objects/missile.rb
new file mode 100644
index 0000000..e7c67d3
--- /dev/null
+++ b/src/game_objects/missile.rb
@@ -0,0 +1,57 @@
+class Missile < Jemini::GameObject
+  has_behavior :PhysicalImage
+  has_behavior :Taggable
+  has_behavior :Timeable
+
+  def load
+    set_bounded_image :missile
+    self.gravity_effected = false
+    self.mass = 3
+    add_tag :damage
+    on_update :track_marker
+    on_update :align
+    on_countdown_complete :start_tracking
+    on_physical_collided :explode
+  end
+
+  def damage
+    0
+  end
+
+  def align(delta)
+    self.physical_rotation = velocity.polar_angle_degrees + 90.0
+  end
+
+  def track(marker)
+    @marker = marker
+    @marker.on_before_remove { @marker = nil }
+    add_countdown :start_tracking, 1.5
+  end
+
+  def start_tracking(timer)
+    return unless timer == :start_tracking
+    return if @marker.nil?
+    @tracking = true
+    come_to_rest
+  end
+
+  def track_marker(delta)
+    return if @marker.nil?
+    return unless @marker.respond_to? :body_position
+    if @tracking
+      angle = @marker.body_position.angle_from(body_position)
+    else
+      angle = 0.0
+    end
+    magnitude = 50.0 * delta
+    thrust = Vector.from_polar_vector(magnitude, angle)
+    add_force thrust
+
+  end
+
+  def explode(event)
+    return if !@tracking && @marker
+    game_state.create(:Explosion, :location => body_position, :radius => 
75.0, :damage => 750.0)
+    game_state.remove self
+  end
+end
\ No newline at end of file
diff --git a/src/game_objects/missile_selection.rb 
b/src/game_objects/missile_selection.rb
new file mode 100644
index 0000000..d275623
--- /dev/null
+++ b/src/game_objects/missile_selection.rb
@@ -0,0 +1,23 @@
+class MissileSelection < Jemini::GameObject
+  has_behavior :Selection
+
+  def name
+    "Missile"
+  end
+
+  def description
+    "Fires guided projectiles"
+  end
+
+  def image
+    :missile
+  end
+
+  def next
+    :shell_selection
+  end
+
+  def behavior
+    :missile_shooter
+  end
+end
\ No newline at end of file
diff --git a/src/game_objects/nuke.rb b/src/game_objects/nuke.rb
index 5e939f2..3a1a90d 100644
--- a/src/game_objects/nuke.rb
+++ b/src/game_objects/nuke.rb
@@ -1,11 +1,14 @@
 class Nuke < Jemini::GameObject
   has_behavior :Launchable
   has_behavior :TriangleTrailEmittable
-  
-  def load
+  has_behavior :Taggable
+
+  def load(firing_player_number)
     set_bounded_image :nuke
     set_mass 1
-    
+    add_tag :weapon
+    add_tag firing_player_number
+
     emit_triangle_trail_with_radius image.width / 2
     
     on_update :align
diff --git a/src/game_objects/nuke_selection.rb 
b/src/game_objects/nuke_selection.rb
index ad2757f..d535236 100644
--- a/src/game_objects/nuke_selection.rb
+++ b/src/game_objects/nuke_selection.rb
@@ -1,5 +1,5 @@
 class NukeSelection < Jemini::GameObject
-  has_behavior :WeaponSelection
+  has_behavior :Selection
 
   def name
     "Nukes"
@@ -17,7 +17,7 @@ class NukeSelection < Jemini::GameObject
     :rolling_mine_selection
   end
 
-  def weapon_behavior
+  def behavior
     :nuke_shooter
   end
 end
\ No newline at end of file
diff --git a/src/game_objects/rolling_mine.rb 
b/src/game_objects/rolling_mine.rb
index 2843082..ace680f 100644
--- a/src/game_objects/rolling_mine.rb
+++ b/src/game_objects/rolling_mine.rb
@@ -1,16 +1,16 @@
 class RollingMine < Jemini::GameObject
-
   has_behavior :Launchable
 
-  def load
+  def load(firing_player_number)
     set_mass 1
     set_bounded_image :rolling_mine
     set_shape :Circle, image.width / 2.0
     self.restitution = 1
     on_physical_collided do |event|
-      explode(event) if event.other.kind_of?(Tank) or 
event.other.kind_of?(TankWheel)
+      explode(event) if event.other.kind_of?(Tank) || 
event.other.kind_of?(TankWheel)
     end
-    add_tag :damage
+    add_tag :weapon
+    add_tag firing_player_number
   end
 
   def explode(event)
diff --git a/src/game_objects/rolling_mine_selection.rb 
b/src/game_objects/rolling_mine_selection.rb
index 190bfa2..ce00213 100644
--- a/src/game_objects/rolling_mine_selection.rb
+++ b/src/game_objects/rolling_mine_selection.rb
@@ -1,5 +1,5 @@
 class RollingMineSelection < Jemini::GameObject
-  has_behavior :WeaponSelection
+  has_behavior :Selection
   
   def name
     "Rolling Mines"
@@ -14,10 +14,10 @@ class RollingMineSelection < Jemini::GameObject
   end
 
   def next
-    :shell_selection
+    :bombard_selection
   end
 
-  def weapon_behavior
+  def behavior
     :rolling_mine_shooter
   end
 end
\ No newline at end of file
diff --git a/src/game_objects/shell.rb b/src/game_objects/shell.rb
index adf90fb..99b8c6f 100644
--- a/src/game_objects/shell.rb
+++ b/src/game_objects/shell.rb
@@ -1,13 +1,17 @@
 class Shell < Jemini::GameObject
   has_behavior :Launchable
   has_behavior :TriangleTrailEmittable
-  
-  def load
+  has_behavior :Taggable
+
+  def load(firing_player_number)
     set_bounded_image :shell
     set_mass 1
+    add_tag :weapon
+    add_tag firing_player_number
 
     emit_triangle_trail_with_radius image.width / 2
-    
+    triangle_trail.color = Color.new(0xfd9c3d)
+
     on_update :align
     on_physical_collided do |event|
       explode(event) unless event.other.has_behavior? :Launchable
@@ -20,7 +24,6 @@ class Shell < Jemini::GameObject
 
   def explode(event)
     explosion = game_state.create(:Explosion, :location => body_position)
-    game_state.remove self
-  end
+    game_state.remove self  end
 
 end
\ No newline at end of file
diff --git a/src/game_objects/shell_selection.rb 
b/src/game_objects/shell_selection.rb
index 1f558bd..b4ec07d 100644
--- a/src/game_objects/shell_selection.rb
+++ b/src/game_objects/shell_selection.rb
@@ -1,5 +1,5 @@
 class ShellSelection < Jemini::GameObject
-  has_behavior :WeaponSelection
+  has_behavior :Selection
 
   def name
     "Shell"
@@ -17,7 +17,7 @@ class ShellSelection < Jemini::GameObject
     :nuke_selection
   end
 
-  def weapon_behavior
+  def behavior
     :shell_shooter
   end
 end
\ No newline at end of file
diff --git a/src/game_objects/smoke.rb b/src/game_objects/smoke.rb
new file mode 100644
index 0000000..934a7d4
--- /dev/null
+++ b/src/game_objects/smoke.rb
@@ -0,0 +1,7 @@
+class Smoke < Jemini::GameObject
+  has_behavior :AnimatedImage
+
+  def load
+
+  end
+end
\ No newline at end of file
diff --git a/src/game_objects/tank.rb b/src/game_objects/tank.rb
index c60bede..601c2b7 100644
--- a/src/game_objects/tank.rb
+++ b/src/game_objects/tank.rb
@@ -2,17 +2,17 @@ class Tank < Jemini::GameObject
   has_behavior :PhysicalImage
   has_behavior :HandlesEvents
   has_behavior :Taggable
+  has_behavior :Healthy
 #  has_behavior :ShootableBarrel
 #  has_behavior :ChargedJumper
 #  has_behavior :ShellShooter
   
-  attr_accessor :player_id, :life
+  attr_accessor :player_id
 
   FLIP_THRESHOLD = 1.0 * 1000.0
   FLIP_LIFT = -40000.0
   FLIP_SPIN = 4.5
   MOVEMENT_FACTOR = 40.0
-  INITIAL_LIFE = 100.0
   BALANCE_OFFSET = 200.0
   COLOR_WHEEL = [:green, :red, :yellow, :blue, :orange, :black].map {|c| 
Color.new c}
 
@@ -27,7 +27,7 @@ class Tank < Jemini::GameObject
     on_after_body_position_changes :update_wheels
     on_after_body_position_changes :update_balance
     @wheels = []
-    @life = INITIAL_LIFE
+    
 
     attach_wheels
     attach_flag
@@ -38,6 +38,7 @@ class Tank < Jemini::GameObject
     handle_event :move, :move_tank
 
     on_physical_collided :take_damage
+    on_after_death :explode
   end
 
   def unload
@@ -47,7 +48,7 @@ class Tank < Jemini::GameObject
   end
 
   def take_damage(collision_event)
-    return unless collision_event.other.has_tag? :damage
+    return unless collision_event.other.respond_to?(:has_tag?) && 
collision_event.other.has_tag?(:damage)
     collision_event.other.remove_tag :damage # so other parts aren't 
damaged, should stop one-shots
     self.life -= collision_event.other.damage
   end
@@ -57,11 +58,6 @@ class Tank < Jemini::GameObject
     game_state.remove self
   end
   
-  def life=(value)
-    @life = value
-    explode if @life < 1
-  end
-  
 private
 
   def attach_flag
@@ -70,7 +66,7 @@ private
   end
 
   def update_tank(delta)
-    if get_collision_events.any? {|collision_event| 
collision_event.other.has_tag? :ground }
+    if get_collision_events.any? {|collision_event| 
collision_event.other.respond_to?(:has_tag?) && 
collision_event.other.has_tag?(:ground) }
       @flip_wait += delta
       if @flip_wait > FLIP_THRESHOLD
         @flip_wait = 0.0
@@ -92,8 +88,8 @@ private
       self.set_force -force.x, -force.y
       self.physical_rotation = 0.0
     end
-    life_percent = @life / INITIAL_LIFE
-    self.color = barrel.color = Color.new(1.0, life_percent, life_percent)
+    life_percent = life / Healthy::INITIAL_LIFE
+    self.color = Color.new(1.0, life_percent, life_percent)
   end
 
   def update_wheels(event)
diff --git a/src/game_objects/tank_wheel.rb b/src/game_objects/tank_wheel.rb
index 1f0c450..8a7db0f 100644
--- a/src/game_objects/tank_wheel.rb
+++ b/src/game_objects/tank_wheel.rb
@@ -1,11 +1,14 @@
 class TankWheel < Jemini::GameObject
   has_behavior :PhysicalImage
   has_behavior :Taggable
-  
-  TURN_RATE = 0.05
+
+  attr_reader :tank
+
+  TURN_RATE = 0.0125
   
   def load(tank)
     @tank = tank
+    add_tag :wheel
     set_image :tank_wheel
     scale_image_from_original 1.25
     set_shape :Circle, image.width / 2.0
diff --git a/src/inputs/menu_input.rb b/src/inputs/menu_input.rb
index 36084b6..36cc848 100644
--- a/src/inputs/menu_input.rb
+++ b/src/inputs/menu_input.rb
@@ -1,8 +1,8 @@
 Jemini::InputBuilder.declare do |i|
   i.in_order_to :start do
-    i.press :space
+    i.release :space
 #    i.press :xbox_360_a
-    i.press :joystick, :button => 11
+    i.release :joystick, :button => 11
   end
 
   i.in_order_to :increase_player_count do
@@ -21,4 +21,12 @@ Jemini::InputBuilder.declare do |i|
       i.press player_number.to_s, :to => player_number
     end
   end
+
+  i.in_order_to :cycle_defense do
+    1.upto 6 do |player_number|
+      i.press :joystick, :button => 14, :id => player_number - 1, :to => 
player_number
+#      i.press player_number.to_s, :to => player_number
+    end
+  end
+
 end
\ No newline at end of file
diff --git a/src/main.rb b/src/main.rb
index 7e37fb4..12bfc92 100644
--- a/src/main.rb
+++ b/src/main.rb
@@ -26,7 +26,7 @@ end
 require 'jemini'
 
 begin
-  game = Jemini::Game.new :title => 'Life Tank', :screen_size => 
Vector.new(800, 600), :fullscreen => true
+  game = Jemini::Game.new :title => 'Life Tank', :screen_size => 
Vector.new(800, 600), :fullscreen => false
   game.app
 
 rescue => e
diff --git a/src/states/menu_state.rb b/src/states/menu_state.rb
index 0f3f63a..4791589 100644
--- a/src/states/menu_state.rb
+++ b/src/states/menu_state.rb
@@ -2,10 +2,14 @@ class MenuState < Jemini::GameState
   MAX_PLAYERS = 6
   MIN_PLAYERS = 2
 
-  SELECTION_WIDTH = 600 / 6
+  SELECTION_WIDTH = 800.0 / MAX_PLAYERS
+  SELECTION_OFFSET = 60
   
-  def load(player_count = 2)
-    @player_count = player_count
+  def load(player_count = 2, weapon_selections=[], defense_selections=[])
+    @weapon_selections  = weapon_selections.map  {|s| create s.class.to_s }
+    @defense_selections = defense_selections.map {|s| create s.class.to_s }
+    @player_count       = player_count
+    
     set_manager :physics, create(:BasicPhysicsManager)
     set_manager :tag, create(:TagManager)
     set_manager :sound, create(:SoundManager)
@@ -26,11 +30,12 @@ class MenuState < Jemini::GameState
     menu_handler.handle_event(:increase_player_count) { 
increase_player_count }
     menu_handler.handle_event(:decrease_player_count) { 
decrease_player_count }
     menu_handler.handle_event(:quit) { quit_game }
-    menu_handler.handle_event(:start) { switch_state :PlayState, 
@player_count, @selections }
+    menu_handler.handle_event(:start) { switch_state :PlayState, 
@player_count, @weapon_selections, @defense_selections }
     1.upto MAX_PLAYERS do |player_number|
       player_handler = create :GameObject, :HandlesEvents
       player_handler.handles_events_for player_number
-      player_handler.handle_event(:cycle_weapon) { |message| 
next_selection_for message.to }
+      player_handler.handle_event(:cycle_weapon)  { |message| 
next_weapon_for message.to }
+      player_handler.handle_event(:cycle_defense) { |message| 
next_defense_for message.to }
     end
     
   end
@@ -46,30 +51,51 @@ class MenuState < Jemini::GameState
 #    create :Text, "Release F, ?, or B: Jump!", :position => 
Vector.new(screen_width * 0.20, screen_height * 0.65), :justify => :top_left
   end
 
-  def next_selection_for(player_number)
+  def next_weapon_for(player_number)
+    return if player_number > @player_count
+    current_selection = @weapon_selections[player_number - 1]
+    new_selection = create current_selection.next
+    @weapon_selections[player_number - 1] = new_selection
+    new_selection.position = weapon_selection_position(player_number)
+    remove current_selection
+  end
+
+  def next_defense_for(player_number)
     return if player_number > @player_count
-    current_selection = @selections[player_number - 1]
+    current_selection = @defense_selections[player_number - 1]
     new_selection = create current_selection.next
-    @selections[player_number - 1] = new_selection
-    new_selection.position = selection_position(player_number)
+    @defense_selections[player_number - 1] = new_selection
+    new_selection.position = defense_selection_position(player_number)
     remove current_selection
   end
 
-  def selection_position(number)
-    Vector.new(SELECTION_WIDTH * number, screen_height * 0.70)
+  def weapon_selection_position(number)
+    Vector.new((SELECTION_WIDTH * (number - 1)) + SELECTION_OFFSET, 
screen_height * 0.68)
+  end
+
+  def defense_selection_position(number)
+    Vector.new((SELECTION_WIDTH * (number - 1)) + SELECTION_OFFSET , 
screen_height * 0.80)
   end
 
   def load_selections
-    @selections = []
-    create_default_selection
-    create_default_selection
+    if @weapon_selections.empty? && @defense_selections.empty?
+      1.upto(@player_count) { create_default_selection }
+    else
+      @weapon_selections.each_with_index  {|w, i| w.position = 
weapon_selection_position(i+1)}
+      @defense_selections.each_with_index {|d, i| d.position = 
defense_selection_position(i+1)}
+    end
   end
 
   def create_default_selection
-    default_selection = create(:shell_selection)
-    default_selection.for_player @selections.size + 1
-    @selections << default_selection
-    default_selection.position = selection_position(@selections.size)
+    weapon_selection = create(:shell_selection)
+    weapon_selection.for_player @weapon_selections.size + 1
+    @weapon_selections << weapon_selection
+    weapon_selection.position = 
weapon_selection_position(@weapon_selections.size)
+
+    defense_selection = create(:armor_selection)
+    defense_selection.for_player @defense_selections.size + 1
+    @defense_selections << defense_selection
+    defense_selection.position = 
defense_selection_position(@defense_selections.size)
   end
 
   def increase_player_count
@@ -83,6 +109,7 @@ class MenuState < Jemini::GameState
     return if @player_count <= MIN_PLAYERS 
     @player_count -= 1
     @player_count_text.text = "Press space or A: Start a game with 
#{@player_count} tanks"
-    remove @selections.pop
+    remove @weapon_selections.pop
+    remove @defense_selections.pop
   end
 end
\ No newline at end of file
diff --git a/src/states/play_state.rb b/src/states/play_state.rb
index 30a9422..1f98695 100644
--- a/src/states/play_state.rb
+++ b/src/states/play_state.rb
@@ -1,15 +1,16 @@
 class PlayState < Jemini::GameState
-  def load(player_count, selections)
+  def load(player_count, weapon_selections, defense_selections)
     set_manager :physics, create(:BasicPhysicsManager)
     set_manager :tag, create(:TagManager)
     set_manager :sound, create(:SoundManager)
     set_manager :tangible, create(:TangibleManager)
-    
+
+    manager(:game_object).add_layer_at :smoke,    6
     manager(:game_object).add_layer_at :gui_text, 5
-    manager(:game_object).add_layer_at :logo, 4
-    manager(:game_object).add_layer_at :flag, 3
-    manager(:game_object).add_layer_at :wheels, 2
-    
+    manager(:game_object).add_layer_at :logo,     4
+    manager(:game_object).add_layer_at :flag,     3
+    manager(:game_object).add_layer_at :wheels,   2
+
     manager(:physics).gravity = 70
     
     create :Background, :background
@@ -44,8 +45,9 @@ class PlayState < Jemini::GameState
     @tanks = []
     ground.spawn_along player_count, Vector.new(0.0, -40.0) do |index|
       tank = create :Tank, index
-      tank.add_behavior selections[index].weapon_behavior
-      tank.add_behavior :ShootableBarrel
+      puts "tank #{index}"
+      tank.add_behavior weapon_selections[index].behavior
+      tank.add_behavior defense_selections[index].behavior
       tank.player_id = index
       @tanks << tank
       tank.on_before_remove do |unloading_tank|
@@ -56,7 +58,7 @@ class PlayState < Jemini::GameState
     
     game_end_checker = create :GameObject, :Updates, :HandlesEvents
     game_end_checker.handle_event :quit do
-      switch_state :MenuState, player_count
+      switch_state :MenuState, player_count, weapon_selections, 
defense_selections
     end
     game_end_checker.on_update do
       next if @tanks.size > 1 || @switching_state
@@ -65,7 +67,7 @@ class PlayState < Jemini::GameState
       end_game_text.add_behavior :Timeable
       end_game_text.add_countdown :end_game, 5
       end_game_text.on_countdown_complete do
-        switch_state :MenuState, player_count
+        switch_state :MenuState, player_count, weapon_selections, 
defense_selections
       end
     end




[jemini~life-tank:cca5e42d] Jemini jar updated. OSX build error (missing icon) fixed.

jaymcgavren 02/28/2010
  • Mysql
  • Glassfish
  • Jruby
  • Rails
  • Nblogo
Terms of Use; Privacy Policy;
© 2010, Oracle Corporation and/or its affiliates
(revision 20120518.3c65429)
 
 
Close
loading
Please Confirm
Close