1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2012-2013 Alexis Laferrière <alexis.laf@xymus.net>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # Entire game logic for the Dino game
18 # Depends only on Nit standard library
22 fun do_turn
( turn
: Turn ) is abstract
26 var nbr_wanted_cavemen
: Int
29 var cavemen
= new Array[Caveman]
30 var javelins_in_air
= new Array[Javelin]
31 var items_on_ground
= new Array[Entity]
32 var entities
= new Array[Entity].with_items
(dino
)
37 var score
: Container[Int]
39 var random_radius_min
= 200
40 var random_radius_max
= 400
41 protected var random_radius_diff
: Int =
42 random_radius_max
- random_radius_min
44 var entities_sorter
= new EntitiesSorter
46 init( cavemen_nbr
: Int, score
: Container[Int] )
48 srand_from
(cavemen_nbr
)
52 nbr_wanted_cavemen
= cavemen_nbr
54 for n
in [0..nbr_wanted_cavemen
[ do
59 var radius
= (random_radius_min
+ random_radius_diff
.rand
).to_f
60 var angle
= (2.0*pi
).rand
61 man
.pos
.x
= ( angle
.cos
* radius
).to_i
62 man
.pos
.y
= ( angle
.sin
* radius
).to_i
67 bush
.pos
= new GamePos([-300..300[.rand
, [-400..400[.rand
)
68 items_on_ground
.add bush
76 var turn
= new Turn( self )
81 if not man
.is_alive
then
87 for j
in javelins_in_air
do
90 javelins_in_air
.remove
( j
)
92 else if j
.hit_ground
then
93 javelins_in_air
.remove
( j
)
94 items_on_ground
.add
( j
)
98 if over
and over_since
== 0 then
102 # sort for blitting, firsts and in the back
103 entities_sorter
.sort entities
108 fun add_javelin
( j
: Javelin )
110 javelins_in_air
.add
( j
)
114 fun over
: Bool do return dino
.life
<= 0 or cavemen
.is_empty
115 fun won
: Bool do return cavemen
.is_empty
and dino
.is_alive
116 fun lost
: Bool do return not won
118 fun ready_to_start_over
: Bool do return over_since
+ 80 < turn_nbr
142 init copy
( src
: GamePos )
148 fun squared_dist_with
( other
: GamePos ) : Int
156 redef fun to_s
do return "<{x}|{y}>"
162 fun run_over_distance_x
: Int do return 50
163 fun run_over_distance_y
: Int do return 16
165 var pos
= new GamePos( 0, 0 )
167 fun squared_dist_with_dino
( game
: Game ) : Int
169 return pos
.squared_dist_with
( game
.dino
.pos
)
172 fun under_dino
(game
: Game): Bool
174 var dy
= pos
.y
- game
.dino
.pos
.y
175 if dy
.abs
> run_over_distance_y
then return false
177 var dx
= pos
.x
- game
.dino
.pos
.x
178 return dx
.abs
<= run_over_distance_x
185 var going_to
: nullable GamePos = null is writable
187 fun speed
: Int is abstract
189 var going_left
= false
190 var going_right
= false
192 redef fun do_turn
( t
)
194 if going_to
!= null then
195 var ds
= pos
.squared_dist_with
( going_to
.as(not null) )
196 if ds
< speed
*speed
then
197 going_to
= null # is there
199 var dx
= going_to
.x
- pos
.x
200 var dy
= going_to
.y
- pos
.y
201 var a
= atan2
( dy
.to_f
, dx
.to_f
)
202 var mx
= a
.cos
*speed
.to_f
203 var my
= a
.sin
*speed
.to_f
208 going_left
= mx
< 0.0
209 going_right
= mx
> 0.0
218 fun is_alive
: Bool is abstract
225 #var running_until = 0
227 var life
: Int = total_life
229 redef fun speed
do return 8
231 redef fun is_alive
do return life
> 0
233 fun hit
( hitter
: Entity, damage
: Int )
240 redef fun do_turn
( t
)
246 for i
in t
.game
.items_on_ground
do
247 if i
.under_dino
(t
.game
) then
248 t
.game
.items_on_ground
.remove i
249 t
.game
.entities
.remove i
260 var cannot_throw_until
= 0
262 var throw_distance
: Int = 400*40+10.rand
263 var fear_distance
: Int = 300*20+8.rand
264 var flee_distance
: Int = 600*60+16.rand
266 var fear_duration
: Int = 80+40.rand
267 var throw_period
: Int = 40+8.rand
269 var variance_angle
: Float = 2.0*pi
.rand
270 var variance_dist
: Int = throw_distance
.to_f
.sqrt
.to_i-4
271 var variance_x
: Int = (variance_angle
.cos
*variance_dist
.to_f
).to_i
272 var variance_y
: Int = (variance_angle
.sin
*variance_dist
.to_f
).to_i
274 redef var is_alive
: Bool = true
276 redef var speed
: Int = 3+3.rand
278 fun is_afraid
( turn
: Turn ) : Bool do return turn
.nbr
< afraid_until
279 fun can_throw
( turn
: Turn ) : Bool do return cannot_throw_until
< turn
.nbr
280 fun die
(turn
: Turn) do is_alive
= false
282 redef fun do_turn
( t
)
285 if under_dino
(t
.game
) then
286 if t
.game
.dino
.is_alive
then die
(t
)
288 else if is_afraid
( t
) then
289 # going to destination
290 else if t
.game
.dino
.life
<= 0 then
291 # dino is dead, chill
293 var dwd
= squared_dist_with_dino
( t
.game
)
294 if dwd
< fear_distance
then
295 afraid_until
= t
.nbr
+ fear_duration
297 var dino_pos
= t
.game
.dino
.pos
298 var dx
= dino_pos
.x
- pos
.x
299 var dy
= dino_pos
.y
- pos
.y
300 var a
= atan2
( dy
.to_f
, dx
.to_f
)
301 a
+= pi
# get opposite
302 a
+= [-100..100[.rand
.to_f
*pi
/3.0/100.0
303 var x
= a
.cos
*flee_distance
.to_f
304 var y
= a
.sin
*flee_distance
.to_f
305 going_to
= new GamePos( x
.to_i
, y
.to_i
)
306 else if dwd
< throw_distance
then
307 if can_throw
( t
) then
308 cannot_throw_until
= t
.nbr
+ throw_period
309 var javelin
= new Javelin( pos
, t
.game
.dino
.pos
)
310 t
.game
.add_javelin
( javelin
)
315 var dino_pos
= t
.game
.dino
.pos
316 going_to
= new GamePos(dino_pos
.x
+variance_x
, dino_pos
.y
+variance_y
)
329 var angle
: Float = pi
/2.0
331 var thrown_angle_xy
: Float
335 var hit_ground
= false
338 var speed
: Int = 10+2.rand
339 var hit_dino_distance
= 128
341 var gravity
: Int = -3
343 init ( from
: GamePos, to
: GamePos )
347 thrown_angle_xy
= atan2
( dy
.to_f
, dx
.to_f
)
348 pos
= new GamePos.copy
( from
)
351 redef fun do_turn
( t
)
353 var dwd
= squared_dist_with_dino
( t
.game
)
354 if dwd
< hit_dino_distance
and t
.game
.dino
.is_alive
then
355 t
.game
.dino
.hit
( self, hit_damage
)
360 if thrown_angle_xy
.cos
> 0.0 then
361 angle
= pi
*5.0/8.0+(pi
/4.0).rand
364 angle
= pi
*9.0/8.0+(pi
/4.0).rand
371 var mx
= (thrown_angle_xy
.cos
* speed
.to_f
).to_i
373 pos
.y
+= (thrown_angle_xy
.sin
* speed
.to_f
).to_i
376 angle
= atan2
( (speed_z
/10).to_f
, -1.0*speed
.to_f
)-pi
/2.0
378 angle
= atan2
( (speed_z
/10).to_f
, speed
.to_f
)-pi
/2.0
385 class Bush super Entity end
387 # Sort entities on screen in order of Y, entities in the back are drawn first
390 redef type COMPARED: Entity
392 redef fun compare
(a
, b
) do return b
.pos
.y
<=> a
.pos
.y