/**-
* Name: City Evacuation
* Author: Mathieu Bourgais & Patrick Taillandier
* Description:  Example model concerning the  use of the simpleBDI plug-in  with emotions. 
* A technological accident is simulated in one of the buildings of the city center.

* Tags: simple_bdi, emotion, evacuation
*/
 
model City_Evacuation

global {
	file shapefile_roads <- file("../includes/Rouen roads.shp");
	file shapefile_hazard <- file("../includes/Technological hazard.shp");
	file shapefile_shelters <- file("../includes/Escapes.shp");
	geometry shape <- envelope(shapefile_roads);
	graph road_network;
	map current_weights;
	
	float hazard_distance <- 400.0;
	float catastrophe_distance <- 100.0;
	float proba_detect_hazard <- 0.2;
	float proba_detect_other_escape <- 0.01;
	float other_distance <- 10.0;
	
	init {
		create road from: shapefile_roads;
		create hazard from: shapefile_hazard;
		create catastrophe;
		create shelter from: shapefile_shelters;
		
		//at the begining of the simulation, we add to the people agent the desire to go to their target.
		create people number: 200{
			location <- any_location_in(one_of(road));
			do add_desire(at_target);
			
		 	//the agent has also the desire that there is no catastrophe (we set the piority of this desire to 0 as it is a general desire)
			do add_desire(nonCatastrophe ,0.0);
			
			// we give the agent a random charisma and receptivity (built-in variables linked to the emotions)
			charisma<-rnd(1.0);
			receptivity<-rnd(1.0);
			
			if(flip(0.9)){
				fearful<-true;
			}else{
				fearful <- false;
			}
      	}
      	road_network <- as_edge_graph(road);
      	current_weights <- road as_map (each::each.shape.perimeter);
	}
	
	reflex update_speeds when: every(10#cycle){
		current_weights <- road as_map (each::each.shape.perimeter / each.speed_coeff);
		road_network <- road_network with_weights current_weights;
	}
	
	reflex stop_sim when: empty(people) {
		do pause;
	}
}
 
species people skills: [moving] control: simple_bdi{
	point target;
	float speed <- 30 #km/#h;
	rgb color <- #blue;
	bool escape_mode <- false;
	bool fearful;
	
	//in order to simplify the model we define  4 desires as variables
	predicate at_target <- new_predicate("at_target");
	predicate in_shelter <- new_predicate("shelter");
	predicate has_target <- new_predicate("has target");
	predicate has_shelter <- new_predicate("has shelter");

    //we give them as well 2 beliefs as variables
	predicate catastropheP <- new_predicate("catastrophe");
	predicate nonCatastrophe <- new_predicate("catastrophe",false);
	
	//at last we define 2 emotion linked to the knowledge of the catastrophe
	emotion fearConfirmed <- new_emotion("fear_confirmed",catastropheP);
	emotion fear <- new_emotion("fear",catastropheP);
	
	bool noTarget<-true;
	
	//we set this built-in variable to true to use the emotional process
	bool use_emotions_architecture <- true;

    //if the agent perceive that their is something that is not normal (a hazard), it has a probability proba_detect_hazard to suppose (add to its unertainty base) that there is a catastrophe occuring
	perceive target:hazard in: hazard_distance when: not escape_mode and flip(proba_detect_hazard){
		focus id:"catastrophe" is_uncertain: true;
		ask myself {
			if(fearful){
				do to_escape_mode;
			}else{
				color<-#green;
			}
		}
	}

	//if the agent perceive the catastrophe, it adds a belief about it and pass in escape mode
	perceive target:catastrophe in:catastrophe_distance{
		focus id:"catastrophe";
		ask myself{
			if(not escape_mode){
				do to_escape_mode;
			}
		}
	}

	//if the agent perceives other people agents in their neighborhood that have fear, it can be contaminate by this emotion
	perceive target:people in: other_distance when: not escape_mode {
		emotional_contagion emotion_detected:fearConfirmed when: fearful;
		emotional_contagion emotion_detected:new_emotion("fear") charisma: charisma receptivity:receptivity;
		emotional_contagion emotion_detected:fearConfirmed emotion_created:fear;
	}
	emotion joy <- nil;
	
	
	perceive target:people in: other_distance{
		emotional_contagion emotion_detected: joy;
		emotional_contagion emotion_detected:fearConfirmed emotion_created:fear;
	}
	
	//if the agent has a fear confirmed, it has the desire to go to a shelter
	rule emotion:fearConfirmed remove_intention: at_target new_desire:in_shelter strength:5.0;
	
	//if the agent has the belief that there is a a catastrophe,  it has the desire to go to a shelter
	rule belief:new_predicate("catastrophe") remove_intention:at_target new_desire:in_shelter strength:5.0;
	
	rule emotion:new_emotion("fear" ,new_predicate("catastrophe")) new_desire:in_shelter remove_intention:at_target when: fearful strength:5.0;
	
	//normal move plan
	plan normal_move intention: at_target  {
		if (target = nil) {
			target <- any_location_in(one_of(road));
		} else {
			do goto target: target on: road_network move_weights: current_weights recompute_path: false;
			if (target = location)  {
				target <- nil;
				noTarget<-true;
			}
		}
	}
	
	//fast evacuation plan in case where the agent has a fear confirmed
	plan evacuationFast intention: in_shelter emotion: fearConfirmed priority:2 {
		color <- #yellow;
		speed <- 60 #km/#h;
		if (target = nil or noTarget) {
			target <- (shelter with_min_of (each.location distance_to location)).location;
			noTarget <- false;
		}
		else  {
			do goto target: target on: road_network move_weights: current_weights recompute_path: false;
			if (target = location)  {
				do die;
			}		
		}
	}	
	
	//normal evacuation plan
	plan evacuation intention: in_shelter finished_when: has_emotion(fearConfirmed){
		color <-#darkred;
		if (target = nil or noTarget) {
			target <- (shelter with_min_of (each.location distance_to location)).location;
			noTarget <- false;
		}
		else  {
			do goto target: target on: road_network move_weights: current_weights recompute_path: false;
			if (target = location)  {
				do die;
			}		
		}
	}
	
	action to_escape_mode {
		escape_mode <- true;
		color <- #darkred;
		target <- nil;	
		noTarget <- true;
		do remove_intention(at_target, true);
	}
	
	
	aspect default {
		draw triangle(30) rotate: heading + 90 color: color;
	}
}

species road {
	float capacity <- 1 + shape.perimeter/50;
	int nb_people <- 0 update: length(people at_distance 1);
	float speed_coeff <- 1.0 update:  exp(-nb_people/capacity) min: 0.1;
	
	aspect default {
		draw shape color: #black;
	}
}

species shelter {
	aspect default {
		draw circle(30) color: rgb(#gamablue,0.8) border: #gamablue depth:10;
	}
}

species hazard {
	aspect default {
		draw circle(hazard_distance) color: rgb(#gamaorange,0.3) border:#gamaorange depth:5;
	}
}

species catastrophe{
	init{
		location <- first(hazard).location;
	}
	aspect default{
		draw circle(catastrophe_distance) color: rgb(#gamared,0.4) border:#gamared depth:10;
	}
}

experiment main type: gui {
	float minimum_cycle_duration <- 0.02;
	output {
		display map type: opengl{
			species shelter refresh: false;
			species road refresh: false;
			species people;
			species catastrophe;
			species hazard;
		}
	}
}