% File "herbivor.tu". % % Written by Phil Edmonds, Feb 97. % % A herbivore is a kind of animal that eats grass, and attempts to mate % with other herbivores. The main addition is to override TakeTurn. % %+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ unit class Herbivore inherit Animal in "animal.tu" import FamilyTree in "ftree.tu" export InitHerbivore %========== INSTANCE VARIABLES ============================== %============================================================ var mate : ^Herbivore var ftree : ^FamilyTree var kids : int %========== INITIALIZE ====================================== %============================================================ proc InitHerbivore (x, y : real, n : string, ft : ^FamilyTree) InitAnimal (x, y, n, green, SimVar.H_SPEED, 4, SimVar.H_MAX_ENERGY, SimVar.H_MIN_ENERGY, SimVar.H_COST_PER_MOVE) mate := nil ftree := ft kids := 0 end InitHerbivore %========== PRIVATE FUNCTIONS =============================== %============================================================ % can graze if the terrain is the plains %------------------------------------------------------------ function CanGraze : boolean var t : ^Terrain := world -> WhatTerrain (loc) result (t -> EnergyFromEating > 0) end CanGraze % eat some grass until full. Returns time it takes. %------------------------------------------------------------ function EatGrass : int var t : ^Terrain := world -> WhatTerrain (loc) var time_to_eat := (max_energy - cur_energy) div (t -> EnergyFromEating) cur_energy := max_energy result time_to_eat end EatGrass % same as Animal.Die, but also adds a statistic %------------------------------------------------------------ body proc Die Animal.Die world -> AddStatistic ("Herbivore deaths") end Die % set my destination to my mate's current location %------------------------------------------------------------ proc SetDestToMate assert (mate not= nil) dest -> Copy (mate -> GetLoc) end SetDestToMate % choose a mate %------------------------------------------------------------ proc ChooseMate var m : ^Object := world -> GetRandomDenizen if m not= nil and m not= self then if objectclass (m) >= Herbivore then mate := m end if end if end ChooseMate % make a baby, create a new herbivore %------------------------------------------------------------ function MakeBaby : ^Herbivore var baby : ^Herbivore new baby if baby not= nil then baby -> InitHerbivore (loc -> GetX, loc -> GetY, name + "-" + intstr (kids), ftree) baby -> JoinWorld (world) ftree -> AddMember (self, baby, mate) kids += 1 world -> AddStatistic ("Herbivore births") end if result baby end MakeBaby %========== PUBLIC FUNCTIONS ================================ %============================================================ % circle with a dot in the center or a cross if dead %------------------------------------------------------------ body proc DrawImage var x := round (loc -> GetX) var y := round (loc -> GetY) if IsAlive then % var g : int := floor ( (cur_energy / max_energy) * (girth - 1) + % 1) var g : int := girth Draw.Oval (x, y, g, g, col) Draw.Dot (x, y, col) else Draw.Line (x - girth, y - girth, x + girth, y - girth, col) Draw.Line (x, y - girth, x, y + girth, black) Draw.Line (x - girth div 2, y + girth div 2, x + girth div 2, y + girth div 2, black) end if end DrawImage % Take a turn. % This is a kind of state machine. Different actions are performed % depending certain variables (especially 'mate'). % Essentially, a herbivore roams around randomly, pausing to eat % grass when it gets hungry. When it gets to a random destination % it takes a look around for a mate, and if it finds one, it starts % pursuing the mate until it catches up, at which time they create % a new baby which is released into the world. %------------------------------------------------------------ body proc TakeTurn if not IsAlive then % do nothing elsif OutOfEnergy then % die if I run out of energy Die elsif Hungry and CanGraze then % eat some grass, and schedule when I can move again var time_to_eat := EatGrass world -> Schedule (self, time_to_eat) DrawImage elsif mate = nil then % no mate, so choose one, if I've reached my current Destination if ReachedDestination then ChooseMate % try to choose a mate if mate not= nil then SetDestToMate else SetRandomDestination end if end if Animal.TakeTurn elsif mate not= nil then % Have I reached my mate? If so, try to make a baby. % If the mate is dead now, then stop pursuing. if not mate -> IsAlive then mate := nil SetRandomDestination else SetDestToMate if ReachedDestination and not Hungry and not (mate -> Hungry) then var baby := MakeBaby % try to make a baby mate := nil SetRandomDestination end if end if Animal.TakeTurn end if end TakeTurn end Herbivore