
%%%==================================================	%%%
%%% WASP SOCCER GAME SERVER 1.1, Dec 3, 2003		%%%
%%%									%%%
%%% Vrije University Amsterdam				%%%
%%%									%%%
%%% (C) Zhisheng Huang						%%%
%%%==================================================	%%%


:-object wsserver : [gg_server].

	var server_port = 4321.
	var client_host = null.
	var client_name = null.	% next client name (1-1 client-server thread)
	var client_addr = null.
	var time_limit = 5000.

	main :-
		gg_server_init(server_port),
		soccer_game_init.


	wsserver(Socket) :-
		gg_server_loop(Socket).


	wsserver(Server, ServerPort) :-
		format('Server at ~w~n', [Server]),
		gg_server_init(ServerPort).


	mk_server(Socket) :-
		new(wsserver(Socket), _).


	free_name_list(FreeList) :-
		FreeList = [blue2, red4, blue3, red5, blue4, red6, blue5, red7, blue6, red8, blue10, red9, red10],
		true.

	default_server_reply(Attributes) :-
		Attributes = [0, none].

	server_reply(InputTerm, ReplyTerm) :-
		InputTerm = [register, soccer, from(ClientHost, ClientAddr)],
		!,
		format('~n~w new client from ~q~n~n', [this, ClientHost]),
		get_field(used_name_list, Others),
		gg_register_client(ClientHost, ClientName),
		client_host := ClientHost,
		client_name := ClientName,
		client_addr := ClientAddr,
		get_field(ball, position, BallPosition),
		wsgame_score <- getGameScoreStruct(Score),
		ReplyTerm = [reply, accept, [client_name, BallPosition, Score, Others]],
		Message = [tell, new_player, [client_name]],
		gg_echo <- broadcast(ClientHost,ClientName, Message).

	server_reply(InputTerm, ReplyTerm) :-
		InputTerm = [unregister, soccer, [user(Host,Name)]],
		!,
		gg_unregister_client(Host, Name, Length),
		ReplyTerm = [reply, unregister, [done, Length]],
		Message = [tell, unregister, [client_name]],
		gg_echo <- broadcast(client_host, to_all_clients, Message).

	server_reply(InputTerm, ReplyTerm) :-
		InputTerm = [tell, position, [user(Host,Name), Position]],
		%% Position = position(X,Y,Z),
		!,
		set_field(Name, position, Position),
		gg_echo <- broadcast(Host, Name, InputTerm),
		gg_echo <- get_broadcasted_data(user(Host,Name), Attributes),
		ReplyTerm = [reply, update, Attributes].

	server_reply(InputTerm, ReplyTerm) :-
		InputTerm = [tell, rotation, [user(Host,Name), Rotation]],
		%% Rotation = rotation(X,Y,Z,R),
		!,
		set_field(Name, rotation, Rotation),
		gg_echo <- broadcast(Host, Name, InputTerm),
		gg_echo <- get_broadcasted_data(user(Host,Name), Attributes),
		ReplyTerm = [reply, update, Attributes].

	server_reply(InputTerm, ReplyTerm) :-
		InputTerm = [tell, position_and_rotation, Data],
		Data = [user(Host,Name), Position, Rotation],
		%% Position = position(X,Y,Z),
		%% Rotation = rotation(XR,YR,ZR,RR),
		!,
		set_field(Name, position, Position),
		set_field(Name, rotation, Rotation),
		gg_echo <- broadcast(Host, Name, InputTerm),
		gg_echo <- get_broadcasted_data(user(Host,Name), Attributes),
		ReplyTerm = [reply, update, Attributes].

	server_reply(InputTerm, ReplyTerm) :-
		InputTerm = [tell, kick_ball, Data],
		!,
		set_queue(ball, [kick_ball, Data]),
		gg_echo <- get_broadcasted_data(user(client_host,client_name), Attributes),
		ReplyTerm = [reply, update, Attributes].

	server_reply(InputTerm, ReplyTerm) :-
		InputTerm = [ask, update, [User]],
		!,
		gg_echo <- get_broadcasted_data(User, Attributes),
		ReplyTerm = [reply, update, Attributes].

	server_reply(InputTerm, ReplyTerm) :-
		InputTerm = shutdown,
		!,
		%% unregister ..
		Message = [tell, browser_exit, [client_name]],
		gg_unregister_client(client_host, client_name, _Length),
		gg_echo <- broadcast(client_host, client_name, Message),
		ReplyTerm = shutdown.

	server_reply(InputTerm, ReplyTerm) :-
		InputTerm = [tell, text, Message],
		Message = [user(Host, Name), [all], _Text],
		!,
		gg_echo <- broadcast(Host, Name, InputTerm),
		ReplyTerm = getChatMessage.


	server_reply(InputTerm, ReplyTerm) :-
		InputTerm = [tell, text, Message],
		Message = [user(Host, _Name), [Recipient], _Text],
		!,
		set_queue(Host, Recipient, InputTerm),
		ReplyTerm = getChatMessage.


	server_reply(InputTerm, ReplyTerm) :-
		ReplyTerm = unknown_message(InputTerm).



soccer_game_init :-
      _Pulse := new(wsclock_pulse),
	set_field(wsserver,clock,time_limit),
%	set_init_value_list([ball,goalKeeper1,goalKeeper2,red2,red3,blue7,blue8]),
	_ball := new(wsball(ball, time_limit)),
	_GoalKeeper1 := new(wsgoalKeeper(goalKeeper1, time_limit)),
	_GoalKeeper2 := new(wsgoalKeeper(goalKeeper2, time_limit)),
%	_Blue9 := new(soccerPlayerServerAgent(blue9, time_limit)),
	_Blue8 := new(soccerPlayerServerAgent(blue8, time_limit)),
	_Blue7 := new(soccerPlayerServerAgent(blue7, time_limit)),
	 _Red2 := new(soccerPlayerServerAgent(red2, time_limit)),
%	_Red3 := new(soccerPlayerServerAgent(red3, time_limit)),
%	_Blue11 := new(soccerPlayerServerAgent(blue11, time_limit)),
%	_Red11 := new(soccerPlayerServerAgent(red11, time_limit)),
%	format('ENTER GAME_SCORE~n'),
	wsgame_score <- setGameScore(red, blue, 0, 0),
%	format('NEXT GAME_SCORE CALL~n'),
	wsgame_score <- showGameScore.



:-end_object wsserver.

:-object wsball: [common_process_wsserver].

	var steps.
	var xmax = 50.0.
	var xmin = -50.0.
	var zmax = 32.0.
	var zmin = -32.0.
	% var ballstep = 1.5.
	var ballSleepTime=300.0.
	var status := unlock.
	var time_limit = 5000.
	var kickableDistance = 3.0 .


	wsball(Name, TimeLimit) :-
		format('~w thread active.~n',[Name]),
		time_limit := TimeLimit,
		set_init_position(Name),
		activity(Name).


	init_position(ball, 0.0, 0.25, 0.0).

	set_init_position(Name):-
		init_position(Name, X,Y,Z),
		set_field(Name, position, position(X,Y,Z)).


	activity(Name) :-
		repeat,
			sleep(500),
			get_clock(TimeLimit),
			%% format('~w : playing time = ~w~n', [this, TimeLimit]),
			ball_checks(Name),
			%% format('~w : check 1 time = ~w~n', [this, TimeLimit]),
			ball_action(Name),
			%% format('~w : action1 time = ~w~n', [this, TimeLimit]),
			ball_checks(Name),
		TimeLimit > time_limit,
		!,
		wsgame_score <- showGameScore.


	ball_action(Name) :-
		get_queue(ball, Message),
		ball_activity(Name,Message).


	ball_checks(Name) :-
		getPosition(Name,X,Y,Z),
		setValidBallPosition(Name,X,Y,Z).


	ball_activity(Ball, Message) :-
		Message = [ball_position, Data],
		Data = [Ball, Position],
		!,
		set_field(Ball, position, Position).
	ball_activity(Ball, Message) :-
		Message = [kick_ball, Data],
		!,
		check_kick_ball(Ball, Data).
	ball_activity(Ball, Message) :-
		Message = [move_ball, Data],
		Data = [Ball, XB,YB,ZB, XE,YE,ZE, Dist],
		!,
		move_to_position(Ball, translation, stepUnit,
			ballSleepTime,XB,YB,ZB,XE,YE,ZE, Dist).
	ball_activity(Ball, Message) :-
		format('~nUNKNOWN ~w MESSAGE = ~w~n~n', [Ball, Message]).


	check_kick_ball(Ball, Data) :-
		Data = [Player, Ball, X,Y,Z,R1, KickBallForce, KickBallForceY],
		get_field(Ball, position, position(XB,_YB,ZB)),
		get_field(Player, position, position(XP,_YP,ZP)),
		distance2d(XP,ZP,XB,ZB,Dist),
		Dist =< kickableDistance,
		!,
		gg_echo <- broadcast(any_host, any_client, [tell, kick_ball, Data]),
		kickedwithStaticStartRF(Ball, translation, X,Y,Z,R1, KickBallForce, KickBallForceY).
	check_kick_ball(_Ball, _Data) :-
		%% format('~nCHECK_KICK_BALL FAILS: ~w, ~w~n~n', [Ball,Data]),
		true.


	validMinMax(V0, Vmin, Vmax, VN) :-
		askValid_Min(V0, Vmin, V1),
		askValid_Max(V1, Vmax, VN).


	askValid_Min(X, Xmin, Xval) :-
		X < Xmin,
		!,
		Xval = Xmin.
	askValid_Min(X,_Xmin, Xval) :-
		Xval = X.


	askValid_Max(X, Xmax, Xval) :-
		X > Xmax,
		!,
		Xval = Xmax.
	askValid_Max(X,_Xmax, Xval) :-
		Xval = X.


	setValidBallPosition(_Ball,X,_Y,Z):-
		X =< xmax,
		X >= xmin,
		Z =< zmax,
		Z >= zmin,
		!.
	setValidBallPosition(Ball, X, Y, Z) :-
		validMinMax(X, xmin, xmax, Xnew),
		validMinMax(Z, zmin, zmax, Znew),
		setPositionEx(Ball, Xnew,Y,Znew).


	setPositionEx(Ball,X,Y,Z):-
		setPosition(Ball,X,Y,Z),
		%% get_field(Ball, old_pos, OldPos),
		%% OldPos \= position(X,Y,Z),
		!,
		set_field(Ball, old_pos, position(X,Y,Z)),
		%% format('~n~w : broadcast of the ball position~n~n', [this]),
		Message = [tell, ball_position, [Ball, position(X,Y,Z)]],
		local_host(Host, _),
		gg_echo <- broadcast(Host, to_all_clients, Message).
	setPositionEx(Ball,_X,_Y,_Z):-
		format('no position broadcast for ~w~n', [Ball]).


% kickedwithStaticStart(+Ball,+Field,+X,+Y,+Z,+Vx,+Vy,+Vz,+SleepTime).


kickedwithStaticStart(Ball,Field,X,Y,Z,Vx,Vy,Vz,BallSleepTime):-
%		kickedSound(Ball),
		Time is Vy/4.9,
		BallSleepTimeInSecond is BallSleepTime/1000,
		steps := 1,
		repeat,
			sleep(BallSleepTime),
			CurrentTime is steps*BallSleepTimeInSecond,
			Xnew is X+ Vx*CurrentTime,
			Ynew is Y+ Vy*CurrentTime-4.9*CurrentTime*CurrentTime,
			Znew is Z+ Vz*CurrentTime,
			setSFVec3f(Ball,Field,Xnew,Ynew,Znew),
			++steps,
		steps > Time//BallSleepTimeInSecond,
		!.



% kickedwithStaticStartRF(Ball,Field,X,Y,Z,R1,ForceXZ,ForceY)

kickedwithStaticStartRF(Ball,Field,X,Y,Z,R1,F1,Vy):-
		Vx is F1 * cos(R1),
		Vz is F1 * sin(R1),
		kickedwithStaticStart(Ball,Field,X,Y,Z,Vx,Vy,Vz,ballSleepTime),
		fallToGround(Ball,Field),
		!.
kickedwithStaticStartRF(_,_,_,_,_,_,_,_):-
		format('~nKICK STATIC START RF FAILS~n~n').		


fallToGround(Ball,Field):- 
		getSFVec3f(Ball, Field, X, _Y, Z),
		setSFVec3f(Ball, Field, X, 0.25, Z),
		Message = [tell, ball_position, [Ball, position(X,0.25,Z)]],
		local_host(Host, _),
		gg_echo <- broadcast(Host, to_all_clients, Message).

:- end_object wsball.



:-object wsgoalKeeper: [common_process_wsserver].

	var steps.
	var holdableDistance = 2.8.
	var throwableDistance = 45.0.
	var watchableDistance = 30.0.
	var stopableDistance = 8.0.
	var ballstep = 1.5.
	var ballSleepTime = 300.
	var kickBallForce = 10.0.
	var kickBallForceY = 15.0.
	var runstep = 1.5.
	var runSleepTime=750.
	var time_limit = 5000.

	wsgoalKeeper(Name, TimeLimit) :-
		time_limit := TimeLimit,
		set_init_value(Name),
		format('~w thread active.~n', [Name]),		
		activity(Name).


	set_init_value(Player):-
		defaultPositionRotation(Player,Position,Rotation),
		set_field(Player,position,Position),
		set_field(Player,rotation,Rotation).


defaultPositionRotation(goalKeeper1, position(47.0, 1.8,0.0), rotation(0,1,0,-1.5708)) :-
	!.
defaultPositionRotation(goalKeeper2, position(-47.0, 1.8,0.0), rotation(0,1,0,1.5708)).


	activity(Name) :-
		repeat,
			sleep(2000),
			get_clock(TimeLimit),
			%% format('~w thread ~w seconds left.~n', [Name, TimeLimit]),
			setDefaultPosition(Name),
			%% format('~w : look_at_ball~n', [Name]),
			look_at_ball(Name,ball),
			%% format('~w : getPositionInformation~n', [Name]),
			getPositionInformation(Name,ball,X,Y,Z,Xball,Yball,Zball,Dist),
			%% format('~w : findHowtoReact~n', [Name]),
			findHowtoReact(Name,ball,X,Y,Z,Xball,Yball,Zball,Dist,Action),
			nonvar(Action),
			format('~w action: ~w ~n',[Name,Action]),
			doAction(Action, Name,ball,X,Y,Z,Xball,Yball,Zball,Dist),
		TimeLimit > time_limit,
		quitGame(Name),
		!.



stadiumExit(0.0, 0.0, -50.0).

quitGame(Player):-
	format('~w is gone.~n',[Player]),
	getSFVec3f(Player, position, X,Y,Z),
	stadiumExit(X1,Y1,Z1),
	distance2d(X,Z,X1,Z1,Dist),
	run_to_position(Player,X,Y,Z,X1,Y1,Z1,Dist),
	gg_echo <- broadcast(server, Player, [tell,quit,[Player]]).


%getPositionInformation(+Player,+Ball,-X,-Y,-Z,-X1,-Y1,-Z1,-Dist). 

getPositionInformation(Player,Ball,X,Y,Z,X1,Y1,Z1,Dist) :-
	getPosition(Ball,X1,Y1,Z1),
	getSFVec3f(Player,position,X,Y,Z),
	distance2d(X,Z,X1,Z1,Dist).



%findHowtoReact(+Player,+Ball,+X,+Y,+Z,+Xball,+Yball,+Zball,+Dist,-Action).

/***
findHowtoReact(_,_,_,_,_,_,_,_,Dist,do_nothing):-
	var(Dist),
	!.
***/

findHowtoReact(_Player,_,_,_,_,_X1,Y1,_Z1,Dist,run_then_kick):-
	Dist > holdableDistance,
	Dist =< stopableDistance,
	Y1 =< 0.25 ,
	!.

findHowtoReact(_Player,_,_,_,_,_,_,_,Dist,hold_then_throw):-
	Dist =< holdableDistance,
	!.

findHowtoReact(Player,_,_,_,_,X1,_,Z1,_Dist,record_score_then_throw):-
	goalArea(Player,_,GoalXMin,GoalXMax,GoalZMin,GoalZMax),
	GoalXMin =< X1,
	GoalXMax >= X1,
	GoalZMin =< Z1,
	GoalZMax >= Z1,
	!.

findHowtoReact(_,_,_,_,_,_,_,_,Dist,ready_for_goal):-
	Dist > stopableDistance,
	Dist < watchableDistance,
	!.

findHowtoReact(_,_,_,_,_,_,_,_,Dist,do_nothing):-
	Dist > watchableDistance,
	!.

findHowtoReact(_,_,_,_,_,_,_,_,_,_) :-
	format('~n~w : findHowtoReact : CASE UNDEFINED (SHOULD NEVER HAPPEN)~n~n', [this]).


%%	goalArea(Player,Team,GoalXMin,GoalXMax,GoalZMin,GoalZMax).

	goalArea(goalKeeper1, blue, 47.0, 50.0, -3.5, 3.5) :-!.
	goalArea(goalKeeper2, red, -50.0, -47.0, -3.5, 3.5).


	defaultPosition(goalKeeper1, position(47.0, 1.8, 0.0)) :-!.
	defaultPosition(goalKeeper2, position(-47.0, 1.8, 0.0)).


	setDefaultPosition(GoalKeeper):-
		defaultPosition(GoalKeeper,Position),
		set_field(GoalKeeper,position,Position),
		get_field(GoalKeeper, old_pos, OldPos),
		OldPos \= Position,
		!,
		set_field(GoalKeeper, old_pos, Position),
		local_host(ClientHost, _),
		Data = [user(ClientHost,GoalKeeper), Position],
		Message = [tell, position, Data],
		gg_echo <- broadcast(ClientHost, GoalKeeper, Message).

	setDefaultPosition(_GoalKeeper).


%%	ballThrowPosition(Player,Position,X,Z).

	ballThrowPosition(goalKeeper1, top, 5.0, -10.0) :-!.
	ballThrowPosition(goalKeeper2, bottom,  -5.0, 10.0).



%doAction(Action,GoalKeeper,Ball,X,Y,Z,Xball,Yball,Zball,Dist).

doAction(do_nothing, _GoalKeeper,_,_,_,_,_,_,_,_) :-
	!.

doAction(hold_then_throw, GoalKeeper,Ball,X,Y,Z,X1,Y1,Z1,_):-
	%% format('~w : action = hold_then_throw.~n', [GoalKeeper]),
	Y2 is Y-0.3,
	Z2 is Z+0.2,
	wsball <- setPositionEx(Ball,X,Y2,Z2),	%% set_queue ???
	ballThrowPosition(GoalKeeper,_,X3,Z3),
	look_at_position(GoalKeeper,X3,Z3), 
	sleep(500),	
	getRotation(GoalKeeper,_,_,_,R),
	R1 is R -1.5708,
%	getSFTime(myTimeSensor,time,Time),
%	setSFTime(GoalKeeper,set_gesture5,Time),
	Data = [GoalKeeper, Ball, X1,Y1,Z1,R1, kickBallForce,kickBallForceY],
	set_queue(Ball, [kick_ball, Data]),	%% Ball will broadcast data
	sleep(200),
	!.
doAction(hold_then_throw, _GoalKeeper,Ball,_X,_Y,_Z,_X1,_Y1,_Z1,_):-
	get_field(ball, position, position(XB,YB,ZB)),
	Data = [Ball, position(XB,YB,ZB)],
	Message = [tell, ball_position, Data],
	gg_echo <- broadcast(anyhost, all_clients, Message),
	format('~nHOLD_THEN_THROW FAILS : ~w~n', [this]).


doAction(run_then_kick, GoalKeeper,Ball,_X,Y,_Z,X1,Y1,Z1,_):-
	%% format('~w action: run_then_kick.~n', [GoalKeeper]),
	set_field(GoalKeeper, position, position(X1,Y,Z1)),
	local_host(Host, _),
	KeeperData = [user(Host,GoalKeeper), position(X1,Y,Z1)],
	KeeperMessage = [tell, position, KeeperData],
	gg_echo <- broadcast(Host,to_all_clients, KeeperMessage),

	ballThrowPosition(GoalKeeper,_,X3,Z3),
	look_at_position(GoalKeeper,X3,Z3), 
	get_field(GoalKeeper, rotation, rotation(_,_,_,R)),
	R1 is R -1.5708,
%	getSFTime(myTimeSensor, time, Time),
%	setSFTime(GoalKeeper, set_gesture3, Time),
	KickData = [GoalKeeper, Ball, X1,Y1,Z1,R1, kickBallForce,kickBallForceY],
	set_queue(Ball, [kick_ball, KickData]),
	sleep(200),
	!.

doAction(run_then_kick, _GoalKeeper,Ball,_X,_Y,_Z,_X1,_Y1,_Z1,_):-
	get_field(ball, position, position(XB,YB,ZB)),
	Data = [Ball, position(XB,YB,ZB)],
	Message = [tell, ball_position, Data],
	gg_echo <- broadcast(anyhost, all_clients, Message),
	format('~nRUN THEN KICK FAILS : ~w~n', [this]).

doAction(record_score_then_throw, GoalKeeper,Ball,X,Y,Z,X1,Y1,Z1,_):-
		!,
		format('~none more score!!!~n'),
		opp_team(GoalKeeper,OppTeam),
		wsgame_score <- getTeamScore(OppTeam,Score),
		nonvar(Score),
		NewScore is Score + 1,
		wsgame_score <- setTeamScore(OppTeam,NewScore),
		wsgame_score <- showGameScore,
		setSFVec3f(GoalKeeper, position, X1,Y,Z1),

		local_host(Host, _),
		Data = [user(Host,GoalKeeper), position(X1,Y,Z1)],
		Message = [tell, position, Data],
		gg_echo <- broadcast(Host, GoalKeeper, Message),

%		goalkeeper walks to the ball
%		getSFTime(myTimeSensor,time,Time),
%		setSFTime(GoalKeeper,set_gesture2,Time),
		sleep(1000),
		setSFVec3f(GoalKeeper,position,X,Y,Z),

		Data2 = [user(Host,GoalKeeper), position(X,Y,Z)],
		Message2 = [tell, position, Data2],
		gg_echo <- broadcast(Host,GoalKeeper, Message2),

%		goalKeeper back to the standard position
		doAction(hold_then_throw, GoalKeeper,Ball,X,Y,Z,X1,Y1,Z1,_).

doAction(ready_for_goal, _GoalKeeper, _,_,_,_,_,_,_,_) :-
	!.
doAction(Action,_,_,_,_,_,_,_,_,_) :-
	format('~n~w : UNKNOWN ACTION = ~w~n', [this, Action]).



kick_ball_to_position(Ball,X,Y,Z,X1,Y1,Z1,Dist):-
	move_to_position(Ball,translation, ballstep, ballSleepTime, X,Y,Z,X1,Y1,Z1,Dist),
	!,
	Data = [Ball, X,Y,Z, X1,Y1,Z1, Dist],
	Message = [tell, move_ball, Data],
	local_host(Host, _),
	gg_echo <- broadcast(Host,Ball,Message).	%% set_queue ???

kick_ball_to_position(Ball,_X,_Y,_Z,_X1,_Y1,_Z1,_Dist) :-
	format('~n~w MOVE FAILS ~n', [Ball]).


run_to_position(Player,X,Y,Z,X1,Y1,Z1,Dist):-
	look_at_position(Player,X1,Z1),
	local_host(Host, _),
	Data = [user(Host,Player), X,Y,Z, X1,Y1,Z1, Dist],
	Message = [tell, move_player, Data],
	gg_echo <- broadcast(Host, Player, Message),
	move_to_position(Player,set_position,runstep,runSleepTime,X,Y,Z,X1,Y1,Z1,Dist).


opp_team(goalKeeper1,red) :-
	!.
opp_team(goalKeeper2,blue).


setRotationEx(GoalKeeper,X,Y,Z,R):-
		get_field(GoalKeeper, old_rot, OldRot),
		OldRot \= rotation(X,Y,Z,R),
		!,
		set_field(GoalKeeper, old_rot, rotation(X,Y,Z,R)),
		setRotation(GoalKeeper,X,Y,Z,R),
		local_host(Host, _),
		Data = [user(Host,GoalKeeper), rotation(X,Y,Z,R)],
		Message = [tell, rotation, Data],
		local_host(Host, _),
		gg_echo <- broadcast(Host, GoalKeeper, Message).

setRotationEx(_GoalKeeper,_X,_Y,_Z,_R):-
		%% format('no rotation broadcast for ~w~n', [GoalKeeper]),
		true.

:- end_object wsgoalKeeper.


:-object soccerPlayerServerAgent: [common_process_wsserver].

var time_limit = 5000 . 
var runstep = 2.0 .
var runSleepTime=1000.
var ballstep = 1.5.
var ballSleepTime=250.
var kickableDistance = 1.5.
var runableDistance =30.0.  %%40.0
var kickableGoalDistance = 30.0.
%var watchDistance =40.0.
var passableDistanceMax = 40.0.
var passableDistanceMin = 3.0.
var kickBallForce = 10.0.
var kickBallForceY =6.0.
var steps.
var balldistance.
var xold.
var zold.

defaultPositionRotation(blue9,  position(35.0,  1.8,  4.0), rotation(0.0, 1.0, 0.0, -1.5708)) :-
	!.
defaultPositionRotation(blue8,  position(5.5,   1.8,  4.0), rotation(0.0, 1.0, 0.0, -1.5708)) :-
	!.
defaultPositionRotation(blue7,  position(15.0,  1.8,  4.0), rotation(0.0, 1.0, 0.0, -1.5708)) :-
	!.
defaultPositionRotation(red2,   position(5.0,   1.8, -4.0), rotation(0.0, 1.0, 0.0,  1.5708)) :-
	!.
defaultPositionRotation(red3,   position(25.0,  1.8,  4.0), rotation(0.0, 1.0, 0.0, -1.5708)) :-
	!.
defaultPositionRotation(red10,  position(-10.0, 1.8,  4.0), rotation(0.0, 1.0, 0.0, -1.5708)) :-
	!.
defaultPositionRotation(red4,   position(40.0,  1.8,  9.5), rotation(0.0, 1.0, 0.0, -1.5708)) :-
	!.
defaultPositionRotation(red5,   position(15.0,  1.8,-20.0), rotation(0.0, 1.0, 0.0, -1.5708)) :-
	!.
defaultPositionRotation(red7,   position(15.0,  1.8, 23.0), rotation(0.0, 1.0, 0.0, -1.5708)) :-
	!.
defaultPositionRotation(red8,   position(-40.0, 1.8, 10.0), rotation(0.0, 1.0, 0.0, -1.5708)) :-
	!.
defaultPositionRotation(red9,   position(-35.0, 1.8,-10.0), rotation(0.0, 1.0, 0.0, -1.5708)) :-
	!.
defaultPositionRotation(red11,  position(-45.0, 1.8,-10.0), rotation(0.0, 1.0, 0.0, -1.5708)) :-
	!.
defaultPositionRotation(blue6,  position(15.0,  1.8, 14.0), rotation(0.0, 1.0, 0.0, -1.5708)) :-
	!.
defaultPositionRotation(blue5,  position(-15.0, 1.8,-24.0), rotation(0.0, 1.0, 0.0, -1.5708)) :-
	!.
defaultPositionRotation(blue4,  position(-25.0, 1.8,-14.0), rotation(0.0, 1.0, 0.0, -1.5708)) :-
	!.
defaultPositionRotation(blue3,  position(45.0,  1.8, 14.0), rotation(0.0, 1.0, 0.0, -1.5708)) :-
	!.
defaultPositionRotation(blue2,  position(35.0,  1.8,-16.0), rotation(0.0, 1.0, 0.0, -1.5708)) :-
	!.
defaultPositionRotation(blue10, position(-45.0, 1.8, -9.0), rotation(0.0, 1.0, 0.0, -1.5708)).


soccerPlayerServerAgent(Name, TimeLimit) :-
	time_limit := TimeLimit,
	set_init_value(Name),
	format('~w thread active.~n', [Name]),
	activity(Name).


set_init_value(Player):-
	defaultPositionRotation(Player,Position,Rotation),
	set_field(Player,position,Position),
	set_field(Player,rotation,Rotation).


activity(Name) :-
	repeat,
		sleep(5000),
		get_clock(TimeLimit),
		format('~w : playing time = ~w seconds.~n', [Name, TimeLimit]),
		%% format('~w : look_at_ball~n', [Name]),
		%% look_at_ball(Name,ball),
		%% format('~w : getPositionInformation~n', [Name]),
		getPositionInformation(Name,ball,X,Y,Z,Xball,Yball,Zball,Dist,Xgoal,Zgoal,Dist1),
		%% format('~w : findHowtoReact~n', [Name]),
		findHowtoReact(Name,ball,X,Y,Z,Xball,Yball,Zball,Dist,Xgoal,Zgoal,Dist1,Action),
		nonvar(Action),
		format('~w : action = ~w ~n', [Name, Action]),
		doAction(Action, Name,ball,X,Y,Z,Xball,Yball,Zball,Dist,Xgoal,Zgoal,Dist1),
	TimeLimit > time_limit,
	quitGame(Name),
	!.


%findHowtoReact(+Player,+Ball,+X,+Y,+Z,+Xball,+Yball,+Zball,+Distball,+Xgoal,+Zgoal,+Distgoal,-Action).

findHowtoReact(_, _Ball,_,_,_,_,_,_,Dist,_,_,Dist1, shooting):-
	Dist =< kickableDistance,
	Dist1 =< kickableGoalDistance,
	!.
	
findHowtoReact(_,_Ball,_,_,_,_,_,_,Dist,_,_,Dist1, passing):-
	Dist =< kickableDistance,
	Dist1 > kickableGoalDistance,
	!.

findHowtoReact(Player,_Ball,_,_,_,X1,_,_,Dist,_,_,_,run_to_ball):-
	Dist > kickableDistance,
	getFieldAreaInformation(Player,_,_,FieldMin,FieldMax),
	FieldMin =< X1,
	FieldMax >= X1,
	!.

findHowtoReact(Player,_,_,_,_,X1,_,_,Dist,_,_,_,move_around):-
	Dist > kickableDistance,
	getFieldAreaInformation(Player,_,_,FieldMin,_),
	X1 < FieldMin,
	!.

findHowtoReact(Player,_,_,_,_,X1,_,_,Dist,_,_,_,move_around):-
	Dist > kickableDistance,
	getFieldAreaInformation(Player,_,_,_,FieldMax),
	X1 > FieldMax,
	!.

findHowtoReact(_,_,_,_,_,_,_,_,_,_,_,_,_).



%getFiledAreaInformation(+Player,-Team,-Role,-FieldMin,-FieldMax).

getFieldAreaInformation(Player,Team,Role,FieldMin,FieldMax):-
	playerRole(Player,Role),
	team(Team,Player),
	fieldArea(Team,Role,FieldMin,FieldMax).


doAction(shooting, _Player, Ball,_,_,_,X1,Y1,Z1,_,Xgoal,Zgoal,Dist1):-
	!,
%	getSFTime(myTimeSensor,time,Time),
%	setSFTime(Player,set_gesture3,Time),
	kick_ball_to_position(Ball,X1,Y1,Z1,Xgoal,0.0,Zgoal,Dist1),
	true.

doAction(passing,Player,Ball,X,Y,Z,X1,Y1,Z1,_,_,_,_):-
	!,
	findCoTeammate(Player,X,Y,Z,Teammate,X2,_,Z2,_),
	doPassing(Player,Ball,X,Y,Z,X1,Y1,Z1,Teammate,X2,_,Z2),
	true.


doAction(run_to_ball,Player,Ball,X,Y,Z,_X1,_Y1,_Z1,_Dist,_,_,_):-
	!,
	%%
	run_and_trace(Player,Ball,X,Y,Z,kickableDistance,runableDistance,runstep,runSleepTime).
		
	
doAction(move_around,Player,_,X,Y,Z,_,_,_,_,_,_,_):-
	!,
%	getFieldAreaInformation(Player,_,_,FieldMin,FieldMax),
%	FieldMid is (FieldMin+FieldMax)/2,
%	distance2d(X,Z,FieldMid,Z,Dist),
%	run_to_position(Player,X,Y,Z,FieldMid,Y,Z,Dist).
	defaultPositionRotation(Player,position(X1,Y1,Z1),_),
	distance2d(X,Z,X1,Z1,Dist),
	run_to_position(Player,X,Y,Z,X1,Y1,Z1,Dist).

doAction(do_nothing,_,_,_,_,_,_,_,_,_,_,_,_) :-
	!.

doAction(Action,_,_,_,_,_,_,_,_,_,_,_,_) :-
	format('~n~w : unknown action = ~w~n', [this, Action]).



%doPassing(_Player,_Ball, _X,_Y,_Z,_X1,_Y1,_Z1,_Teammate,_X2,_Y2,_Z2).

doPassing(Player,Ball,X,_,_,X1,Y1,Z1,Teammate,X2,_,Z2):-
	nonvar(Teammate),
	%% format('player ~w is passing the ball to the teammate ~w.~n', [Player,Teammate]),
	kickBalltoDirection(Player,Ball,X,_,_,X1,Y1,Z1,X2,_,Z2),
	!.


doPassing(Player,Ball,X,_,_,X1,Y1,Z1,Teammate,_,_,_):-
	var(Teammate),
	team(Team,Player),
	goalPosition(Team,X2,Z2),
	%% format('player ~w is kicking the ball.~n', [Player]),
	kickBalltoDirection(Player,Ball,X,_,_,X1,Y1,Z1,X2,_,Z2),
	!.



%kickBalltoDirection(_Player, _Ball,_X,_Y,_Z,_X1,_Y1,_Z1,_X2,_Y2,_Z2).

kickBalltoDirection(Player,Ball,X,_,_,X1,Y1,Z1,X2,_,Z2):-
	look_at_position(Player,X2,Z2),
	getRotation(Player,_,_,_,R),
	getCorrectKickRotation(X,X1,R,R1),
	KickBallForceY is kickBallForceY + random*10.0,
%	getSFTime(myTimeSensor,time,Time),
%	setSFTime(Player,set_gesture3,Time),
	!,
	Data = [Player, Ball, X1,Y1,Z1,R1, kickBallForce, KickBallForceY],
	set_queue(Ball, [kick_ball, Data]),
	sleep(200),
	true.


getCorrectKickRotation(X,X1,R,R1):-
	X =< X1,
	!,
	R1 is R - 1.5708.

getCorrectKickRotation(X,X1,R,R1):-
	X > X1,
	R1 is 1.5708 - R.


getPositionInformation(Player,Ball,X,Y,Z,X1,Y1,Z1,Dist,Xgoal,Zgoal,Dist1) :-
	get_field(Ball, position, position(X1,Y1,Z1)),
	get_field(Player, position, position(X,Y,Z)),
	distance2d(X,Z,X1,Z1,Dist),
	distanceGoal(Player,X,Y,Z,Xgoal,Zgoal,Dist1).


kick_ball_to_position(Ball,X,Y,Z,X1,Y1,Z1,Dist):-
	Data = [Ball, X,Y,Z, X1,Y1,Z1, Dist],
	Message = [tell, move_ball, Data],
	local_host(Host, _),
	gg_echo <- broadcast(Host,Ball,Message),	%% ??? set_queue
	move_to_position(Ball,translation, ballstep, ballSleepTime, X,Y,Z,X1,Y1,Z1,Dist).


run_to_position(_,X,_,Z,X,_,Z,_):-
	!.
run_to_position(Player,X,Y,Z,X1,Y1,Z1,Dist):-
	look_at_position(Player,X1,Z1),
	!,
	move_to_position(Player,set_position,runstep,runSleepTime,X,Y,Z,X1,Y1,Z1,Dist),
	local_host(Host, _),
	Data = [user(Host,Player), X,Y,Z, X1,Y1,Z1, Dist],
	Message = [tell, move_player, Data],
	gg_echo <- broadcast(Host, to_all_clients, Message).
run_to_position(Player,_X,_Y,_Z,_X1,_Y1,_Z1,_Dist):-
	format('~w RUN TO POSITION FAILS~n',[Player]).


%run_and_trace(+Player,+Ball,+X,+Y,+Z,+kickableDistance,+RunableDist,+runstep,+runSleepTime).
run_and_trace(Player,Ball,X,Y,Z,KickableDistance,Dist,Runstep,RunSleepTime):-
	Data = [user(ServerHost,Player), Ball,X,Y,Z,KickableDistance,Dist,Runstep,RunSleepTime],
	Message = [tell, run_and_trace, Data],
	gg_echo <- broadcast(ServerHost, to_all_clients,  Message),
	xold := X,
	zold := Z,
	repeat,
		%% format('RUN_AND_TRACE 1 : ~w~n', [position(xold,zold)]),
		sleep(RunSleepTime),
		getPosition(Ball,X1,_,Z1),
		look_at_position(Player,X1,Z1),
		getRotation(Player,_,_,_,R),
		R1 is R + 1.5708,
		Xnew is xold-Runstep * cos(R1),
		Znew is zold+Runstep * sin(R1),
		setSFVec3f(Player,set_position, Xnew, Y, Znew),

		%% local_host(Host, _),
		%% Data = [user(Host,Player), position(Xnew,Y,Znew)],
		%% Message = [tell, position, Data],
		%% gg_echo <- broadcast(Host, to_all_clients, Message),

		%% format('RUN_AND_TRACE 2 : ~w~n', [position(xold,zold)]),
		xold := Xnew,
		zold := Znew,
		distance2d(Xnew,Znew,X1,Z1,Distball),
		balldistance := Distball,
  	end_of_run_and_trace(balldistance, KickableDistance, Dist),
	!.

run_and_trace(Player,_Ball,_X,_Y,_Z,_KickableDist,_Dist,_Runstep,_RunSleepTime) :-
	format('~nRUN_AND_TRACE FAILS : ~w~n', [Player]).


end_of_run_and_trace(BallDist, KickDist, _Dist) :-
        BallDist =< KickDist,
        !.

end_of_run_and_trace(BallDist, _KickDist, Dist) :-
        BallDist > Dist.



team(red, goalKeeper2).
team(red, red2).
team(red, red3).
team(blue, goalKeeper1).
%team(blue, blue9).
team(blue, blue8).
team(blue, blue7).
%team(red, red10).
%team(blue,blue11).
%team(red, red11).

playerRole(red2, midfielder).
playerRole(red3, forward).
playerRole(blue7,midfielder).
playerRole(blue8,forward).
%playerRole(blue9,defender).
%playerRole(red10,midfielder).
%playerRole(red11,defender).
%playerRole(blue11,forward).

goalPosition(red, 49.0, -3.0).
goalPosition(blue, -49.0, -3.0).

fieldArea(red,  midfielder, -25.0,  20.0).
fieldArea(blue, midfielder, -20.0,  25.0).
fieldArea(red,  defender,   -50.0, -25.0).
fieldArea(blue, defender,    25.0,  50.0).
fieldArea(blue, forward,    -50.0,  20.0).
fieldArea(red,  forward,     20.0,  50.0).


stadiumExit(0.0, 0.0, -50.0).

quitGame(Player):-
	format('~n~w is gone.~n',[Player]),
	getSFVec3f(Player, position, X,Y,Z),
	stadiumExit(X1, Y1,Z1),
	distance2d(X,Z,X1,Z1,Dist),
	run_to_position(Player,X,Y,Z,X1,Y1,Z1,Dist),
%%	setSFInt32(Player,whichChoice, -1),
	gg_echo <- broadcast(any_host, any_client, [tell,quit,[Player]]).


teammate(Player1,Player2,Team) :-
	team(Team,Player1),
	team(Team,Player2),
	Player1 \== Player2.

%teammateRole(Player+,Team+,Role+,Mate-).

teammateRole(Player,Team,Role,Mate) :-
	team(Team,Mate),
	Player \== Mate,
	playerRole(Mate,Role).


distanceGoal(Player,X,_,Z,X1,Z1,Dist) :-
	team(Team,Player),
	goalPosition(Team,X1,Z2),
	Z1 := Z2 + random* 7.0,
% set goal shooting point as a random point around the gate
	distance2d(X,Z,X1,Z1,Dist).



%findCoTeammate(Player+,X+,Y+,Z+,Teammate-,X1-,Y1-,Z1-,Dist-).

findCoTeammate(Player,X,Y,Z,Teammate,X1,Y1,Z1,Dist):-
	playerRole(Player,Role),
	roleOrder(Role,TeammateRole,attack),
	%% format('Teammate role is ~w~n',[TeammateRole]),
	findRoleTeammate(Player,X,Y,Z,TeammateRole,Teammate,X1,Y1,Z1,Dist),
	nonvar(Dist),
	Dist =< passableDistanceMax,
	Dist > passableDistanceMin,
	!.

findCoTeammate(_,_,_,_,_,_,_,_,_).	


%roleOrder(Role1, Role2, strategy).

roleOrder(midfielder,forward,attack).
roleOrder(defender,midfielder,attack).
roleOrder(forward,forward,attack).
roleOrder(midfielder,midfielder,attack).
roleOrder(defender,defender,attack).

%findRoleTeammate(Player+,X+,Y+,Z+,Role+,Mate-,X1-,Y1-,Z1-,Dist-).

findRoleTeammate(Player,X,_,Z,Role,Mate,X1,Y1,Z1,Dist):-
		team(Team,Player),
		teammateRole(Player,Team,Role,Mate),
		%% format('Mate is ~w~n',[Mate]),
		getSFVec3f(Mate,position,X1,Y1,Z1),
		distance2d(X,Z,X1,Z1,Dist),
		!.
findRoleTeammate(_,_,_,_,_,_,_,_,_,_).
				

:- end_object soccerPlayerServerAgent.



:-object common_process_wsserver: [getsets].

	var steps.

	distance2d(X,Z,X1,Z1,Dist):-
		Xdif is X1-X,
		Zdif is Z1-Z,
		Dist is sqrt(Xdif*Xdif + Zdif*Zdif).

	distance3d(X,Y,Z,X1,Y1,Z1,Dist):-
		Xdif is X1-X,
		Ydif is Y1-Y,
		Zdif is Z1-Z,
		Dist is sqrt(Xdif*Xdif + Ydif*Ydif + Zdif*Zdif).


	distance2dObject(Object1,Field1,Object2,Field2,Dist):-
		getSFVec3f(Object1, Field1, X1, _, Z1),
		getSFVec3f(Object2, Field2, X2, _, Z2),
		distance2d(X1,Z1,X2,Z2,Dist).


	distance3dObject(Object1,Field1,Object2,Field2,Dist):-
		getSFVec3f(Object1, Field1, X1, Y1, Z1),
		getSFVec3f(Object2, Field2, X2, Y2, Z2),
		distance3d(X1,Y1,Z1,X2,Y2,Z2,Dist).


	distanceBall(Player,Ball, Dist) :-
		distance2dObject(Player,position,Ball,position,Dist).



	distancePlayer(Player1,Player2, Dist) :-
		distance2dObject(Player1,position,Player2,position,Dist).


	look_at_ball(Player, Ball) :-
		get_field(Player, position, position(X,_,Z)),
		get_field(Ball, position, position(X1,_,Z1)),
		X \= X1,
		!,
		Xdif is X-X1,
		Zdif is Z1-Z,
		R is atan(Zdif/Xdif) - sign(Xdif) * 1.5708 ,
		set_field(Player, rotation, rotation(0.0, 1.0, 0.0, R)).

	look_at_ball(_,_).



look_at_position(Player,X1,Z1) :-
	get_field(Player, position, position(X,_,Z)),
	X = X1,
	Z = Z1,
	!.

look_at_position(Player,X1,Z1) :-
	get_field(Player, position, position(X,_,Z)),
	X \= X1,	%% CCC : added
	!,
	Xdif is X-X1,
	Zdif is Z1-Z,
	R is atan(Zdif/Xdif) - sign(Xdif)*1.5708,
	setRotationEx(Player, 0.0, 1.0, 0.0, R).
%%%	set_field(Player, rotation, rotation(0.0, 1.0, 0.0, R)).

look_at_position(_Player,_X1,_Z1).	%% CCC : added (see above)





setRotationEx(Player,X,Y,Z,R):-
		set_field(Player, rotation, rotation(X,Y,Z,R)),
		get_field(Player, old_rot, OldRot),
		OldRot \= rotation(X,Y,Z,R),
		!,
		set_field(Player, old_rot, rotation(X,Y,Z,R)),
		local_host(Host, _),
		Data = [user(Host,Player), rotation(X,Y,Z,R)],
		Message = [tell, rotation, Data],
		gg_echo <- broadcast(Host, Player, Message),
		true.

setRotationEx(_Player,_X,_Y,_Z,_R) :-
		%% format('NO ROTATION BROADCAST FOR ~w~n', [Player]),
		true.



%move_to_position(+Object,+Field,+Steplength,+Sleeptime,+X,+Y,+Z,+X1,+Y1,+Z1,+Dist).

move_to_position(_,_,_,_,X,_,Z,X,_,Z,_) :-
	!.
move_to_position(Object,Field, StepUnit, SleepTime, X,Y,Z,X1,_,Z1,Dist) :-
	Xstep is sign(X-X1)*StepUnit*abs(X-X1)/Dist,
	Zstep is sign(Z-Z1)*StepUnit*abs(Z-Z1)/Dist,
	steps := Dist // StepUnit,
	repeat,
		sleep(SleepTime),
		Steps is Dist // StepUnit - steps + 1,
		Xnew is X - Xstep*Steps,
		Znew is Z - Zstep*Steps,
		setSFVec3f(Object,Field,Xnew,Y,Znew),
		-- steps,
	steps < 1,
	!.

%% move_to_position(_,_,_,_,_,_,_,_,_,_,_).

	get_clock(Time) :-
		get_field(wsserver, clock, Time).

	set_clock(Time) :-
		set_field(wsserver, clock, Time).

:-end_object common_process_wsserver.



:-object getsets.

	getPosition(Name, X,Y,Z):-
		get_field(Name, position, position(X,Y,Z)).

	setPosition(Name, X,Y,Z):-
		set_field(Name, position, position(X,Y,Z)).

	getRotation(Name, X,Y,Z,R):-
		get_field(Name, rotation, rotation(X,Y,Z,R)).

	setRotation(Name, X,Y,Z,R):-
		set_field(Name, rotation, rotation(X,Y,Z,R)).


	getSFVec3f(Name, position, X,Y,Z):-
		!,
		get_field(Name, position, position(X,Y,Z)).
	getSFVec3f(Name,set_position,X,Y,Z):-
		!,
		get_field(Name, position, position(X,Y,Z)).
	getSFVec3f(Name, translation, X,Y,Z):-
		get_field(Name, position, position(X,Y,Z)).


	setSFVec3f(Name, position, X,Y,Z) :-
		!,
		%% format('NEW ~w POSITION = ~w~n', [Name, position(X,Y,Z)]),
		set_field(Name, position, position(X,Y,Z)).
	setSFVec3f(Name, set_position, X,Y,Z) :-
		!,
		%% format('NEW ~w SET_POSITION = ~w~n', [Name, position(X,Y,Z)]),
		set_field(Name, position, position(X,Y,Z)).
	setSFVec3f(Name, translation, X,Y,Z) :-
		%% format('NEW ~w TRANSLATION = ~w~n', [Name, position(X,Y,Z)]),
		set_field(Name, position, position(X,Y,Z)).

:-end_object getsets.



:-object wsgame_score.

	var score1 = 0.
	var score2 = 0.
	var team1 = unknown.
	var team2 = unknown.


	setGameScore(Team1, Team2, Score1, Score2) :-
		team1 := Team1,
		team2 := Team2,
		score1 := Score1,
		score2 := Score2.

	getGameScore(Team1, Team2, Score1, Score2) :-
		Team1 = team1,
		Team2 = team2,
		Score1 = score1,
		Score2 = score2.


	getGameScoreStruct(Score) :-
		Score = score(team1:team2 / score1:score2).


	getTeamScore(team1, Score) :-
		!,
		Score = score1.
	getTeamScore(team2, Score) :-
		Score = score2.


	setTeamScore(team1, Score) :-
		!,
		score1 := Score.
	setTeamScore(team2, Score) :-
		score2 := Score.		


	showGameScore :-
                getGameScoreStruct(Score),
                format('~ngame score: ~w~n', [Score]),
		Message = [tell, game_score, Score],
		local_host(Host, _),
                format('game score: ~w~n', [Host]),
		gg_echo <- broadcast(Host,server,Message).



:-end_object wsgame_score.


:-object wsclock_pulse: [common_process_wsserver].

	wsclock_pulse:-
		repeat,
			sleep(1000),
			get_clock(Time),
			Left is Time - 1,
			set_clock(Left),
		Left < 1,
		!.



:-end_object wsclock_pulse.


/**
</pre>
</body>
</html>
**/
