
//	VIETCONG 1
//	Whip_Trap_random script v3.3 (Writen for custom objects -  _whip_trap.bes and _whip_trap_tree.bes)
//	made by Ando

/*

	______________TRAP DESCRIPTION IN REALITY:
Whip Trap: Bamboo whips are constructed of a length of green bamboo with spikes (normally bamboo) attached to one end. 
The bamboo pole is bent and held in an arched position by a catch device triggered by a trip wire stretched across the track. 
When released, the bamboo pole whips back into the straight position impaling the person triggering the trap


    ______________TRAP BEHAVIOUR IN GAME:
If player collides with wire then trap is released and bamboo pole whips back into the straight position and kill the player. 
Wire goes down also when hit by bullet, knife or explosion. Player can also reactivate that trap in game. 
After start/restart trap will appear randomly to some predefined position



	______________TUTORIAL FOR EDITOR
-Place one _whip_trap.bes and _whip_trap_tree.bes object to map.
- move "_whip_trap" to exactly same position as is tree object
	(copy "tree" transform x,y,z to "trap" transform x,y,x)
	(now you will see how trap is located with tree)
- link trap to tree object (now trap will be with tree when you move/rotate tree)
- select tree and place it where you need
 for next tree:
- select trap and tree 
- copy 
- link trap to tree object
- select tree and place it where you need
( continue as long as you need but there cant be more than 20 "trees")
- when "trees" are in right position then you can delete trap objects.
- turn on sub object selector
- select and move "sign_place" dummy where you want a sign to appear.
- do it for every "tree"
- Place one "trap" object somewhere on map (where players cant see it)
- add script to trap object in level.c script




	______________MAX TUTORIAL FOR CUSTOM TRAP:
	



	______________NOTES:

1.1 - added second movement 
1.2 - fixed some bugs
1.3 - changed kill player part
1.4 - new killing system - with death count
1.6 - automatic Global variable system
2.0 - tested with 2x editor
2.1 - code improved and cleaned
3.0 - tested with team
3.1 - all 3.1 improvements was recomendations by Intruder and his testing team
3.1 - added option for random places
3.1 - added trap sign
3.2 - added waypoint blocker ( important for random places)
3.3 - changed restart (was bug before when client PC was faster than rerver + netork)
	______________BUGS:
none

	______________IDEAS:
maybe its reasonable to add option only for engineer to set up that trap again (now its for all)

*/






//____________________________OBJECT PARAMETERS____________________________

//OBJECT STATES: 0 - trap up , 1 -  move , 2 -  down , 

#define DISARM_STRING			2806	//#2806: 	#tee to cut the wire.
#define RESET_STRING			7362	//#7362: 	#tee Enable
#define MOVE_SOUND				1869	//1869, 1933 
#define CUT_SOUND				1950	//
#define PL_HIT_SOUND			2344//264		// player hit
#define ROT_ANGLE				-115.0f  //
#define MOVE_TIME				0.3f	//trap movement time
#define SWING_TIME				0.2f	//trap movement time
      

#ifndef tree_obj
	#define tree_obj				"_whip_trap_tree#%d"		//tree object for trap places. objects must start with #0
																//will found count of objects automatically
#endif


#define	mov_sub_obj				"hrabe_rot"		//moving pendel object
#define	stat_sub_obj			"hrabe_stat"	//static pendel object
#define	wire_sub_obj			"drat"			//wire object
#define	dum_sub_obj				"Dummy_hrabe"	//dummy object
#define	dum_trat_sub_obj		"Dummy_drat"	//dummy for waypoint blocker
#define	sign_sub_obj			"sign"			//sign sub object
#define	sign_place_sub_obj		"sign_place"	//sign place sub object on random tree object


//________________________________________________________________________

#include <inc\sc_global.h>
#include <inc\sc_def.h>


//_________________________FOR AUTOMATIC GLOBAL VARIABLES__________________

#define GVAR_SERVER				600 	// don't edit	//"is server" channel //0 - not server . 1 - server
#define GVAR_COUNT				601 	// don't edit   //Channel for G-var count ( every new object 
#define GVAR_GPHASE				500		// don't edit	//game phase channel // 1 - restarting
//_________________________________________________________________________

void		*mov_sub_obj_id;
void		*stat_sub_obj_id;
void		*wire_sub_obj_id;
void		*dum_sub_obj_id;
void		*sign_sub_obj_id;
void		*cur_tree_id;

s_SC_NOD_transform	trans;
s_SC_NOD_transform	trans_swing;
s_SC_NOD_transform	orig_trans_stat;
s_SC_NOD_transform	orig_trans_move;
s_SC_NOD_transform	orig_trans_wire;
s_SC_NOD_transform	cur_trans_trap;
s_SC_NOD_transform	orig_trans_master;
s_SC_NOD_transform	orig_trans_sign;

c_Vector3		vec2;
c_Vector3		head_pos;
c_Vector3		dum_pos;
s_sphere		sph2;

float		val = 0.0f;
float		timer = 0.0f;
float		cur_rot = 0.0f;


int			Temp =	0;	//global object status
int			Temp2 =	-1;	//local object status.  -1 = unknown ststus  (for start/restart)
int			Temp3 = 0;	//local movement status
int			r_dir = 1;	// rotation direction
int			my_gvar_count;
int			my_gvar;
int			my_gvar_tree;
int			tree_obj_count=0;
int			current_tree;


s_SC_P_getinfo	pl_info;

dword 		list[32];
dword 		player;
dword       Ai_block;
BOOL		is_block = FALSE;
BOOL		SRV_restart_done = FALSE;
int			i_items,j;


int ScriptMain(s_SC_OBJ_info *info){
	int i;
	char	txt[32];

	switch(info->event_type){
		case SC_OBJ_INFO_EVENT_INIT:

			tree_obj_count=0;

			for(i= 0; i < 20; i++){//count of objects
				sprintf(txt, tree_obj, i);
				if (SC_NOD_GetNoMessage_Entity(txt))tree_obj_count++;
			}
			stat_sub_obj_id = SC_NOD_GetNoMessage(info->master_nod, stat_sub_obj);
			mov_sub_obj_id = SC_NOD_GetNoMessage(info->master_nod, mov_sub_obj);
			wire_sub_obj_id  = SC_NOD_GetNoMessage(info->master_nod, wire_sub_obj);
			dum_sub_obj_id  = SC_NOD_GetNoMessage(info->master_nod, dum_sub_obj);
			sign_sub_obj_id  = SC_NOD_GetNoMessage(info->master_nod, sign_sub_obj);



			SC_NOD_GetTransform(info->master_nod,&orig_trans_master);

			SC_NOD_GetTransform(wire_sub_obj_id,&orig_trans_wire);
			SC_NOD_GetTransform(mov_sub_obj_id,&orig_trans_move);
			SC_NOD_GetTransform(stat_sub_obj_id,&orig_trans_stat);
			SC_NOD_GetTransform(sign_sub_obj_id,&orig_trans_sign);			

			//creating global variable
			my_gvar_count = SC_ggi(GVAR_COUNT)+1;
			my_gvar = my_gvar_count+ 601;
			my_gvar_count++;
			my_gvar_tree = my_gvar_count+ 601;
			SC_sgi(GVAR_COUNT,my_gvar_count);

			
			break;
		case SC_OBJ_INFO_EVENT_JUSTLOADED:
			break;
		case SC_OBJ_INFO_EVENT_RELEASE:
			SC_NOD_SetTransform(info->master_nod,&orig_trans_master);
			SC_NOD_SetTransform(stat_sub_obj_id,&orig_trans_stat); 
			SC_NOD_SetTransform(mov_sub_obj_id,&orig_trans_move); 
			SC_NOD_SetTransform(wire_sub_obj_id,&orig_trans_wire); 
			SC_NOD_SetTransform(sign_sub_obj_id,&orig_trans_sign);	
			Temp2 = -1;	//restores unknown state  (important for restar tmap)
			if (is_block){// remove Ai blocker if exist
				SC_Ai_Blocker_Remove(Ai_block);
				is_block = FALSE;
			}
			break;
		case SC_OBJ_INFO_EVENT_HIT:  
			if(info->nod == wire_sub_obj_id){
				SC_sgi(my_gvar,1); //
			}
			break;
		case SC_OBJ_INFO_EVENT_DOTICK:
			if(SC_ggi(GVAR_GPHASE)==1){//reset after restartmap/gamedone
				if (SC_ggi(GVAR_SERVER) == 1){	// its server
					if (!SRV_restart_done){
						SC_sgi(my_gvar,0); // status on start/restart
						current_tree = rand() % tree_obj_count;// choosing current tree where will be trap
						SC_sgi(my_gvar_tree,current_tree); // status on start/restart
						if (is_block){// remove Ai blocker if exist
							SC_Ai_Blocker_Remove(Ai_block);
							is_block = FALSE;
						}
						SRV_restart_done=TRUE;
					}
				}
				Temp2 = -1;	//restores unknown state for trap
				return TRUE;
			}//

			if (Temp2 == -1){//first run after restart
				if (SC_ggi(GVAR_SERVER) == 1){	// its server
					SRV_restart_done=FALSE;	//for next restert , if needed
				}
			}

			Temp = SC_ggi(my_gvar);
			//______________USE OBJECT__________
			if (Temp == Temp2){	//was strange collision bug without it
				switch(Temp){	//
				case 0:	// trap up
					val = SC_DOBJ_CameraLooksAt(wire_sub_obj_id,2);
					if (val<0.5f){
						SC_ACTIVE_Add(info->master_nod,2.0f*val,DISARM_STRING);
					}
					if (SC_NOD_GetCollision(info->master_nod, wire_sub_obj, TRUE)){//SC_NOD_GetCollision(info->master_nod, wire_sub_obj, TRUE))
						SC_sgi(my_gvar,1); //___sync
						Temp = 1;
					}
					break;
				case 2:	// drap down
					val = SC_DOBJ_CameraLooksAt(info->master_nod,2);
					if (val<1.0f){
						SC_ACTIVE_Add(info->master_nod,2.0f*val,RESET_STRING);//USE string
					}
					break;
				}//switch(Temp)
			}
			//_____________CHANGE OBJECT STATUS________________
			if (Temp != Temp2){	//global status != Local status 
				switch(Temp){
				case 0:	// trap up
					//____move trap to random position
					sprintf(txt, tree_obj, SC_ggi(my_gvar_tree));// current tree name
					
					cur_tree_id = SC_NOD_GetNoMessage_Entity(txt);
					SC_NOD_GetTransform(cur_tree_id,&cur_trans_trap);// current tree transform
					SC_NOD_SetTransform(info->master_nod,&cur_trans_trap); //
					SC_NOD_GetTransform(SC_NOD_GetNoMessage(cur_tree_id, sign_place_sub_obj),&trans);
					SC_NOD_SetTransform(sign_sub_obj_id,&trans);
					//____AI blocker
					if (!is_block){//Ai blocker add if not exist
						SC_NOD_GetWorldPos(SC_NOD_GetNoMessage(info->master_nod, dum_trat_sub_obj), &vec2);
						sph2.pos = vec2;
						sph2.rad = 1.6f;
						Ai_block = SC_Ai_Blocker_Add(&sph2);
						is_block = TRUE;
					}
					//____
					SC_NOD_SetTransform(stat_sub_obj_id,&orig_trans_stat); //
					trans=orig_trans_move;
					trans.loc.z-=1000;
					SC_NOD_SetTransform(mov_sub_obj_id,&trans); //
					SC_NOD_SetTransform(wire_sub_obj_id,&orig_trans_wire); //
					Temp2=0;
					Temp3=0;
					break;
				case 1:	// drap move
					switch(Temp3){
					case 0:	//start moving
						SC_NOD_GetWorldPos(wire_sub_obj_id, &vec2);
						SC_SND_PlaySound3D(CUT_SOUND,&vec2);
						//SC_NOD_GetWorldPos(mov_sub_obj_id, &vec2); 
						SC_SND_PlaySound3D(MOVE_SOUND,&vec2);

						trans=orig_trans_wire;
						trans.loc.z-=1000;
						SC_NOD_SetTransform(wire_sub_obj_id,&trans); //wire

						trans=orig_trans_stat;
						trans.loc.z-=1000;
						SC_NOD_SetTransform(stat_sub_obj_id,&trans); //static 
						
						timer = 0;
						Temp3=1;
						break;
					case 1:	//normal move
						if (timer >= MOVE_TIME){//
							timer = 0;
							Temp3=2;
							r_dir=1;
							cur_rot=20;
							trans_swing=orig_trans_move;
							trans_swing.rot.z+=(DEG_TO_RAD(ROT_ANGLE)); // end position of main rotation
							return TRUE;
							//break;
						}
						timer+=info->time;
						trans=orig_trans_move;
						trans.rot.z+=(DEG_TO_RAD(ROT_ANGLE)*timer/MOVE_TIME);
						SC_NOD_SetTransform(mov_sub_obj_id,&trans); 
						
						//______________________killing player_________

						SC_NOD_GetWorldPos(dum_sub_obj_id, &dum_pos);
						if (SC_ggi(GVAR_SERVER) == 1){// only server can kill players
							
							sph2.pos=dum_pos;
							sph2.rad=2;
							SC_GetPls(&sph2,list,&i_items);
							for (j=0;j<i_items;j++) {
								SC_P_GetHeadPos(list[j], &head_pos);
								if ((SC_2VectorsDist(&dum_pos, &head_pos)) < 0.85){
									SC_P_GetInfo(list[j], &pl_info);
									if((pl_info.cur_hp) > 1){ // player isnt dead
										SC_SND_PlaySound3D(PL_HIT_SOUND,&head_pos);
										SC_P_SetHp(list[j], 0.1f);
										SC_P_GetPos(list[j], &head_pos);
										head_pos.z+=0.1f;
										SC_P_SetPos(list[j], &head_pos);
									}
								}
							}
						} 
						else {
							player =SC_PC_Get();
							SC_P_GetHeadPos(player, &head_pos);
							if ((SC_2VectorsDist(&dum_pos, &head_pos)) < 0.85){
								SC_P_GetInfo(player, &pl_info);
								if((pl_info.cur_hp) > 1){ // player isnt dead
									SC_SND_PlaySound3D(PL_HIT_SOUND,&head_pos);
									SC_P_SetHp(player, 0.1f);
									SC_P_GetPos(player, &head_pos);
									head_pos.z+=0.1f;
									SC_P_SetPos(player, &head_pos);


								}
							}

						}
						//_____________________end of killing player________________________
						break;
					case 2:	//___________________second movement
						if (cur_rot <= 0){//second movement is over
							Temp3=3;//movement over for client
							if (SC_ggi(GVAR_SERVER) == 1){
								SC_sgi(my_gvar,2); //trap down for server
							}
							return TRUE;
							//break;
						}
						timer+=info->time;
						if (timer >= SWING_TIME){// one swing time is over
							trans_swing.rot.z+=r_dir*(DEG_TO_RAD(cur_rot));
							r_dir=-r_dir;	//reverse movement direction
							timer=0;		//reset time for next swing
							cur_rot-=((0.2* cur_rot)+0.1);	//degrease angle for next swing

						}
						trans=trans_swing;
						trans.rot.z+=r_dir*(DEG_TO_RAD(cur_rot)/2+(DEG_TO_RAD(cur_rot)/2 *sin((DEG_TO_RAD(180)*timer/SWING_TIME)- DEG_TO_RAD(90))));
						SC_NOD_SetTransform(mov_sub_obj_id,&trans); 

						break;
					}//switch(Temp3){
					break;
				case 2:	// trap down

					//added here too because when player join after trap starts moving
					sprintf(txt, tree_obj, SC_ggi(my_gvar_tree));// current tree name
					SC_NOD_GetTransform(SC_NOD_GetNoMessage_Entity(txt),&cur_trans_trap);// current tree transform
					SC_NOD_SetTransform(info->master_nod,&cur_trans_trap); //
					//

					trans=orig_trans_stat;
					trans.loc.z-=1000;
					SC_NOD_SetTransform(stat_sub_obj_id,&trans); //
					trans=orig_trans_move;
					trans.rot.z+=(DEG_TO_RAD(ROT_ANGLE+5.2));// 5.2 is working now but its not calculated
					SC_NOD_SetTransform(mov_sub_obj_id,&trans); 
					trans=orig_trans_wire;
					trans.loc.z-=1000;
					SC_NOD_SetTransform(wire_sub_obj_id,&trans); //
					Temp2=2;
					break;
				}
			}
            break;
		case SC_OBJ_INFO_EVENT_USED:
			Temp = SC_ggi(my_gvar);
			switch(Temp){
			case 0:	// execute trap
					SC_sgi(my_gvar,1);
				break;
			case 2:	// reset trap
					SC_sgi(my_gvar,0);

				break;
			}
        break;
   }// switch(info->event_type)
   return FALSE;
}// int ScriptMain(s_OBJ_info *info)
