destruction: - destruction (disappear) - destruction (with destroyed object and particles) - old bridge (random parts break when collision with player)
light: - lightning (lightning object with lights on random places) - light_switch (turn on/off light. With two different light mapped objects) - light_time (light turn on/off with time interval) - campfire
!! For some mode scripts you might needsome updated files:
Vietcong\dev\compiler\inc\sc_global.h
Vietcong\dev\compiler\inc\mplevel.inc
( attached to this post)
Vietcong\dev\editor\respawn_points.ini
Vietcong\dev\editor\mp_helpers.ini
( attached to this post)
Main point:
With Automatic global variables map creator don't need to add global variable channels manually for every map and object.
Its created automatically in object script and automatically added synchronization in mode script.
Technical idea:
Object/helper script initialization (SC_OBJ_INFO_EVENT_INIT) is running before than mode script initialization (SC_NET_MES_LEVELINIT).
Every object script adds and remembers its global variable channel number(s).
When mode script is initialized, then on global variable channel 601 already is count of needed Global variables and for those are created synchronization (SC_MP_Gvar_SetSynchro)
Also added variable for server (is or is not server).
// definitions //________________________________
//global variable system for object synchro !!!DONT CHANGE THOSE!!!
#define GVAR_SERVER 600 //channel for server ( dont add SC_MP_Gvar_SetSynchro for that) 0 - not server, 1 - server
#define GVAR_COUNT 601 //channel for count of Global variables (dont add SC_MP_Gvar_SetSynchro for that)
#define GVAR_USE_start 602 //channel for start nr. of Global variable channel
//________________________________
....
....
int ScriptMain(s_SC_NET_info *info)
....
....
case SC_NET_MES_LEVELINIT: //_____________________________________automatic custom global variables_________________
for (i=GVAR_USE_start;i<GVAR_USE_start+SC_ggi(GVAR_COUNT)+1;i++){ //custom global variables
SC_MP_Gvar_SetSynchro(i);
}
//_______________________________________________________________________________
...
...
SC_sgi(GVAR_SERVER,0); // 0 = not server. 0 for all now, but server PC changed it later to 1
if (info->param2){
if (info->param1){// it's server
//____________
SC_sgi(GVAR_SERVER,1);//For object scripts
//then object script have info is it on server or client machine
//its not synchronized Global Variable
//____________
// definitions //___________________________________________________________________
//global variable system for object synchro !!!DONT CHANGE THOSE!!!
#define GVAR_SERVER 600 // don't edit //0 - not server . 1 - server
#define GVAR_COUNT 601 // don't edit //Channel for G-var count
#define GVAR_GPHASE 500 // don't edit // not directly related with Automatic Blobal variables, but help to restart
//___________________________________________________________________
...
...
int my_gvar_count;
int my_gvar;
...
...
int ScriptMain(s_SC_OBJ_info *info){
...
case SC_OBJ_INFO_EVENT_INIT: //creating global variable
my_gvar_count = SC_ggi(GVAR_COUNT)+1;// get latest gvar count and add 1
SC_sgi(GVAR_COUNT,my_gvar_count); // send new gvar count
my_gvar = my_gvar_count+ 601; // my gvar channel = my_gvar_count + 601 (601 is just start point for my custom gvars)
//________________________________
//automatic global variable system for object synchro !!!DONT CHANGE THOSE!!!
#define GVAR_SERVER 600 // server ( dont add SC_MP_Gvar_SetSynchro for that) 0 - not server, 1 - server
#define GVAR_COUNT 601 // count of Global variables ( dont add SC_MP_Gvar_SetSynchro for that)
#define GVAR_USE_start 602 //start nr of Global variable nr
//________________________________
#define GVAR_GPHASE 500
//#define RECOVER_TIME 15.0f // time to global recover
#define NORECOV_TIME 3.0f // disable time of recoverplace after recovering someone there
}// if ((alldeath)&&(gRecoverTime>=0xffff))
else gAllNoAiRecover = 0.0f;
gValidSide0 = valid[0];
switch(gPhase){
case GPHASE_BEGIN:
gPhase_timer -= info->elapsed_time;
if (gPhase_timer<0.0f)
if ((valid[0])&&(valid[1])){
SC_Log(2,"Set GPHASE_GAME");
gPhase_timer = 5.0f;
gPhase = GPHASE_GAME;
}
break;
case GPHASE_GAME:
gPhase_timer -= info->elapsed_time;
if (gPhase_timer<0.0f)
if (!valid[1]){
SC_Log(2,"Set GPHASE_DONE");
gPhase = GPHASE_DONE;
gPhase_timer = 8.0f;
}// if (!valid[1])
break;
case GPHASE_DONE:
case GPHASE_FAILED:
case SC_NET_MES_LEVELINIT:
//_____________________________________automatic custom global variables_________________
for (i=GVAR_USE_start;i<GVAR_USE_start+SC_ggi(GVAR_COUNT)+1;i++){ //custom global variables
SC_MP_Gvar_SetSynchro(i);
}
//_______________________________________________________________________________________
for (i=0;i<REC_MAX;i++){
sprintf(txt,REC_WPNAME_US,i);
if (SC_NET_FillRecover(&gRec[gRecs],txt)) gRecs++;
}
#if _GE_VERSION_ >= 133
i = REC_MAX - gRecs;
SC_MP_GetRecovers(SC_MP_RESPAWN_COOP,&gRec[gRecs],&i);
gRecs += i;
#endif
if (gRecs==0) SC_message("no US recover place defined!");
CLEAR(gRecTimer);
}// if (info->param1)
}//if (info->param2)
if (info->param1)
{
//!!! ++ Reinit AI - NEW
num = 64;
SC_MP_EnumPlayers(enum_pl, &num, SC_P_SIDE_VC);
for (i = 0; i < num; i++)
{
SC_P_ScriptMessage(enum_pl[i].id, SCM_MP_REINIT, 0);
}
//-- Reinit AI - NEW
}
break;// SC_NET_MES_LEVELINIT
case SC_NET_MES_RENDERHUD:
switch(SC_ggi(GVAR_GPHASE)){
case GPHASE_DONE:
j = 1099;
break;
case GPHASE_FAILED:
j = 1049;
break;
default:j = 0;break;
}// switch(SC_ggi(GVAR_GPHASE))
if (j){
witxt = SC_Wtxt(j);
SC_GetScreenRes(&val,NULL);
val -= SC_Fnt_GetWidthW(witxt,1);
SC_Fnt_WriteW(val * 0.5f,15,witxt,1,0xffffffff);
}// if (j)
break;
case SC_NET_MES_SERVER_RECOVER_TIME:
if (info->param2){
info->fval1 = 0.1f;
}
else{
// killed
SC_P_GetInfo(info->param1,&plinfo);
if (plinfo.side==0){
if (gRecoverLimit>0){
if (gRecoverTime>=0xffff) info->fval1 = -1.0f;
else
if (gRecoverTime>0) info->fval1 = gNextRecover;
else info->fval1 = 4.0f;
}
else info->fval1 = -1.0f;
}
else info->fval1 = -1.0f;
}
break;
case SC_NET_MES_SERVER_RECOVER_PLACE:
if (info->param1!=0){
SC_message("No recover for VC");
break;
}
precov = (s_SC_MP_Recover*)info->param2;
i = SC_MP_SRV_GetBestDMrecov(gRec,gRecs,gRecTimer,NORECOV_TIME);
Simple object destruction script.
When object is hit by bullet/knife/explosion it will disappear with some effects
All is restored after restart.
All you see is synchronized and visible to others.
Spoiler:[ShowHide]
Code
// VIETCONG 1
// DESTRUCTION_disapear script v3.0
// made by Ando
// OBJECT BEHAVIOUR IN GAME:
// All you see is synchronised and visible to others.
// When object is hit by bullet/knife/explosion it will dissapear with some effects
// All is restored after restart.
int hit_count = 0;
int Global_state = 0; //global object status
int Local_state = -1; //local object status. -1 = unknown ststus (for start/restart)
int Sub_state = 0; //sub stste of object
int i;
int my_gvar_count;
int my_gvar;
c_Vector3 obj_pos;
char txt[32];
int ScriptMain(s_SC_OBJ_info *info){
switch(info->event_type){
case SC_OBJ_INFO_EVENT_INIT:
Description:
MP synchronized door.
Player can use (open /close) door. Use option appears when player is near door and looking at it.
Door has some kind of collision with player. It means that door don’t move through player, it moves back to last position when player is on its way.
Also bots can use that door. Door open/close automatically when they are near enough.
Max tutorial for custom object:
Door object must be with dummy object on the other side of door rotating point.
You must add some settings to your "door" object in 3DS MAX:
Phy_colshp=2
Phy_misshp=2
Phy_status=0
Script isn't working without those settings!!!
Object
Door object is attached to this post with texture and script.
Script:
Spoiler:[ShowHide]
Code
// VIETCONG 1
// DOOR script v3.0
// Writen for custom object - DE_door.bes
// made by Ando
/*
______________DESCRIPTION:
MP synchronized door.
Player can use (open /close) door. Use option appears when player is near door and looking at it.
Door has some kind of collision with player. It means that door don’t move through player, it moves back to last position when player is on its way.
Also bots can use that door. Door open/close automatically when they are near enough.
_____________HISTORY:
//2.3 orig trans restored bug fixed
//2.4 completly new and better synchronization
//2.5 AI is using doors automatically
//2.6 created fake collision with player
//2.6 start state option
//2.7 automatic Global variable system
//3.0
int Temp = 0; //global object status
int Temp2 = -1; //local object status. -1 = unknown ststus (for start/restart)
int i_items,j;
int my_gvar_count;
int my_gvar;
BOOL startsound = FALSE;
s_SC_P_getinfo pl_info;
dword player;
dword list[32];
int ScriptMain(s_SC_OBJ_info *info){
switch(info->event_type){
case SC_OBJ_INFO_EVENT_INIT:
SC_NOD_GetTransform(info->master_nod,&orig_trans);
SC_NOD_GetWorldPos(info->master_nod,&door_vec);
dum_sub_obj_id = SC_NOD_GetNoMessage(info->master_nod, dum_sub_obj);
return TRUE;
case SC_OBJ_INFO_EVENT_JUSTLOADED:
break;
case SC_OBJ_INFO_EVENT_RELEASE:
SC_NOD_SetTransform(info->master_nod,&orig_trans);
break;
case SC_OBJ_INFO_EVENT_HIT:
break;
case SC_OBJ_INFO_EVENT_DOTICK:
if (SC_ggi(GVAR_GPHASE) == 1){//restarting
Temp2 = -1; //restores unknown state for door
return TRUE;
break;
}//
//______________start/restart status for server____________
if (Temp2 == -1){ //restores stsrt state
if (SC_ggi(GVAR_SERVER) == 1){
SC_sgi(my_gvar,START_STATE); // status on start/restart
}
}
Temp = SC_ggi(my_gvar);
//_________________________________________AI is useing a door
if (SC_ggi(GVAR_SERVER) == 1){
player = SC_GetNearestPlayer(&door_vec, &dist);
if (dist < 2.8f){//was 2.5 before
SC_P_GetInfo(player, &pl_info);
if(pl_info.member_id != 255){
switch(Temp){
case 0: //
if (dist < 2){
SC_sgi(my_gvar,2);//opening
Temp =2;
}
break;
case 1: //
if (dist > 2.1){
SC_sgi(my_gvar,3);//closeing
Temp =3;
}
break;
}
}
}
}
//__________________________________________end of AI is useing a door
//______________use string__________
val = SC_DOBJ_CameraLooksAt(info->master_nod,2);
if (val<1.0f){
if (Temp == 0 || Temp == 3){
use_string = OPENSTRING;
}
if (Temp == 1 || Temp == 2){
use_string = CLOSESTRING;
}
SC_ACTIVE_Add(info->master_nod,2.0f*val,use_string);
}
//_____________CHANGE OBJECT STATUS________________
if (Temp != Temp2){ //temp- Global state Temp2 - Local state
switch(Temp){
case 0: //set door closed status
SC_NOD_SetTransform(info->master_nod,&orig_trans);
startsound = TRUE;//??????
timer=0;
Temp2=0;
break;
case 1: //set door opened status
trans=orig_trans;
trans.rot.z+= DEG_TO_RAD(ROT_ANGLE);
SC_NOD_SetTransform(info->master_nod,&trans);
startsound = TRUE;//?????
timer=0;
Temp2=1;
break;
case 2: //door is opening
if (Temp2==1){ //last state was oposite movement
timer = (OPENINGTIME-timer);//reverse movement time
}
Temp2=0;
if (startsound){
SC_SND_PlaySound3D(OPENSOUND,&door_vec);
startsound = FALSE;
}
timer+=info->time;
trans=orig_trans;
trans.rot.z+=(DEG_TO_RAD(ROT_ANGLE)*timer/OPENINGTIME);
SC_NOD_SetTransform(info->master_nod,&trans);
// ________FAKE COLLISION WITH PLAYER______________________________
if (SC_ggi(GVAR_SERVER) == 1){// only server
sph2.pos=door_vec;
sph2.rad=2;
i_items=32;
SC_GetPls(&sph2,list,&i_items);
for (j=0;j<i_items;j++) {
SC_P_GetInfo(list[j], &pl_info);
if(pl_info.member_id == 255){
SC_NOD_GetWorldPos(dum_sub_obj_id, &dum_pos);
SC_P_GetPos(list[j], &player_pos);
dist=SC_GetLineDist(&player_pos, &dum_pos,&door_vec);
if (dist < 0.33f){
SC_SND_PlaySound3D(COLL_SOUND,&player_pos); //collision sound
SC_sgi(my_gvar,3); //
}
}
}
}
//_________end of FAKE COLLISION______________________________________
if (timer >= OPENINGTIME){
if (SC_ggi(GVAR_SERVER) == 1) SC_sgi(my_gvar,1); //
}
break;
case 3: //door is closing
if (Temp2==0){ //last state was oposite movement
timer = (OPENINGTIME-timer);//reverse movement time
}
Temp2=1;
if (startsound){
SC_SND_PlaySound3D(CLOSESOUND,&door_vec);
startsound = FALSE;
}
timer+=info->time;
trans=orig_trans;
trans.rot.z+=(DEG_TO_RAD(ROT_ANGLE)*(OPENINGTIME-timer)/OPENINGTIME);
SC_NOD_SetTransform(info->master_nod,&trans);
// ________FAKE COLLISION___________________________________________________
if (SC_ggi(GVAR_SERVER) == 1){// only server
sph2.pos=door_vec;
sph2.rad=2;
i_items=32;
SC_GetPls(&sph2,list,&i_items);
for (j=0;j<i_items;j++) {
SC_P_GetInfo(list[j], &pl_info);
if(pl_info.member_id == 255){
SC_NOD_GetWorldPos(dum_sub_obj_id, &dum_pos);
SC_P_GetPos(list[j], &player_pos);
dist=SC_GetLineDist(&player_pos, &dum_pos,&door_vec);
if (dist < 0.33f){
SC_SND_PlaySound3D(COLL_SOUND,&player_pos); //collision sound
SC_sgi(my_gvar,2); //
}
}
}
}
//_________end of FAKE COLLISION______________________________________
if (timer >= OPENINGTIME){
if (SC_ggi(GVAR_SERVER) == 1) SC_sgi(my_gvar,0); //
}
break;
case 5: //
break;
}
}
break;
case SC_OBJ_INFO_EVENT_USED:
Temp = SC_ggi(my_gvar);
switch(Temp){
case 0: // door is closed
case 3: // door is closing
SC_sgi(my_gvar,2); // start opening
break;
case 1: // door is opened
case 2: // door is opening
SC_sgi(my_gvar,3); // start closing
break;
}
break;
}// switch(info->event_type)
return FALSE;
}// int ScriptMain(s_OBJ_info *info)
Description:
Player can open/close a "door" sub object.
Object start state is restored after restart.
Max tutorial for custom object:
You must add some settings to your door sub object in 3DS MAX:
Phy_colshp=2
Phy_misshp=2
Object isn't working without those settings!!!
Object
Closet object is attached to this post with script. Object is using official vc1 texture.
Script:
Spoiler:[ShowHide]
// VIETCONG 1
// CLOSET_DOOR script v3.0
// Writen for custom object - DE_closet.bes
// made by Ando
/*
______________DESCRIPTION:
All you see is synchronised and visible to others.
Player can open/close a "door" sub object.
Object start state is restored after restart.
______________TUTORIAL FOR EDITOR
This script is writen for custom object "DE_closet.bes"
Place object to scene and assign that script to DE_cabinet object.
______________TUTORIAL FOR 3DS MAX:
You must add some settings to your door sub object in 3DS MAX:
Phy_colshp=2
Phy_misshp=2
Script isn't working without those settings!!!
int Temp = 0; //global object status
int Temp2 = -1; //local object status. -1 = unknown ststus (for start/restart)
int i_items,j;
int my_gvar_count;
int my_gvar;
BOOL startsound = FALSE;
int ScriptMain(s_SC_OBJ_info *info){
switch(info->event_type){
case SC_OBJ_INFO_EVENT_INIT:
door_sub_obj_id = SC_NOD_GetNoMessage(info->master_nod, door_sub_obj);
SC_NOD_GetTransform(door_sub_obj_id,&orig_trans);
SC_NOD_GetWorldPos(door_sub_obj_id,&door_pos); //sound location
return TRUE;
case SC_OBJ_INFO_EVENT_JUSTLOADED:
break;
case SC_OBJ_INFO_EVENT_RELEASE:
SC_NOD_SetTransform(door_sub_obj_id,&orig_trans);
break;
case SC_OBJ_INFO_EVENT_HIT:
break;
case SC_OBJ_INFO_EVENT_DOTICK:
switch(SC_ggi(GVAR_GPHASE)){
case 101: // gphase_begin for nonstandart gamemodes
case 102: // gphase_begin for nonstandart gamemodes
case 1:
Temp2 = -1; //restores unknown state for door
return TRUE;
break;
}//switch(gPhase)
//______________start/restart status for server____________
if (Temp2 == -1){ //restores stsrt state
if (SC_ggi(GVAR_SERVER) == 1){
SC_sgi(my_gvar,START_STATE); // status on start/restart
}
}
Temp = SC_ggi(my_gvar);
//______________use string__________
val = SC_DOBJ_CameraLooksAt(door_sub_obj_id,2);
if (val<1.0f){
if (Temp == 0 || Temp == 3){
use_string = OPENSTRING;
}
if (Temp == 1 || Temp == 2){
use_string = CLOSESTRING;
}
SC_ACTIVE_Add(info->master_nod,2.0f*val,use_string);
}
//_____________CHANGE OBJECT STATUS________________
if (Temp != Temp2){ //temp- Global state Temp2 - Local state
switch(Temp){
case 0: //set door closed status
SC_NOD_SetTransform(door_sub_obj_id,&orig_trans);
startsound = TRUE;//
timer=0;
Temp2=0;
break;
case 1: //set door opened status
trans=orig_trans;
trans.rot.z+= DEG_TO_RAD(ROT_ANGLE);
SC_NOD_SetTransform(door_sub_obj_id,&trans);
startsound = TRUE;//
timer=0;
Temp2=1;
break;
case 2: //door is opening
if (Temp2==1){ //last state was oposite movement
timer = (OPENINGTIME-timer);//reverse movement time
}
Temp2=0;
if (startsound){
SC_SND_PlaySound3D(OPENSOUND,&door_pos);
startsound = FALSE;
}
timer+=info->time;
trans=orig_trans;
trans.rot.z+=(DEG_TO_RAD(ROT_ANGLE)*timer/OPENINGTIME);
SC_NOD_SetTransform(door_sub_obj_id,&trans);
if (timer >= OPENINGTIME){
if (SC_ggi(GVAR_SERVER) == 1) SC_sgi(my_gvar,1); //
}
break;
case 3: //door is closing
if (Temp2==0){ //last state was oposite movement
timer = (OPENINGTIME-timer);//reverse movement time
}
Temp2=1;
if (startsound){
SC_SND_PlaySound3D(CLOSESOUND,&door_pos);
startsound = FALSE;
}
timer+=info->time;
trans=orig_trans;
trans.rot.z+=(DEG_TO_RAD(ROT_ANGLE)*(OPENINGTIME-timer)/OPENINGTIME);
SC_NOD_SetTransform(door_sub_obj_id,&trans);
if (timer >= OPENINGTIME){
if (SC_ggi(GVAR_SERVER) == 1) SC_sgi(my_gvar,0); //
}
break;
case 5: //
break;
}
}
break;
case SC_OBJ_INFO_EVENT_USED:
Temp = SC_ggi(my_gvar);
switch(Temp){
case 0: // door is closed
case 3: // door is closing
SC_sgi(my_gvar,2); // start opening
break;
case 1: // door is opened
case 2: // door is opening
SC_sgi(my_gvar,3); // start closing
break;
}
break;
}// switch(info->event_type)
return FALSE;
}// int ScriptMain(s_OBJ_info *info)
Description:
Player can use ammo box to receive ammo.
When player is using it, box cover is moving, one kit is moving up and disappearing from box.Player see message how much kits are left.
DE_AmmoBox.bes contains 16 ammo kit's. When last kit are taken then box stay in open state and player will see message "Box is empty now"
Payer can't use it when he already have ammo full and he receive message "Ammo full".
When ammo boxes are disabled in server settings then box appear in empty state and player see info text "Medic box is disabled by server" when used.
All is restored after restart.
Max tutorial for custom object:
Create objects: box, cover and kit's. Kit's must use same name, except end number is increasing and start with 0.
Example "Kit_0", "Kit_1"... and so on.
Kit's count can be up to 20 and is detected automatically in script.
Fix your cover and kit’s names in this script.
You must add some settings to your "cover" object in 3DS MAX:
Phy_colshp=2
Phy_misshp=2
Phy_status=0
Script isn't working without those settings!!!
Object
Ammo box object is attached to this post with script and textures.
Script:
Spoiler:[ShowHide]
Code
// VIETCONG 1
// DE_AmmoBox script v3.3
// Writen for custom object - DE_AmmoBox.bes
// made by Ando
/*
______________DESCRIPTION:
All you see is synchronized and visible to others.
Player can use ammo box to receive ammo.
When player is using it, box cover is moving, one kit is moving up and disappearing from box.Player see message how much kits are left.
DE_AmmoBox.bes contains 16 ammo kit's. When last kit are taken then box stay in open state and player will see message "Box is empty now"
Payer can't use it when he already have ammo full and he receive message "Ammo full".
When ammo boxes are disabled in server settings then box appear in empty state and player see info text "Medic box is disabled by server" when used.
All is restored after restart.
______________TUTORIAL FOR EDITOR
This script is writen for custom object "DE_ammobox.bes"
Place ammobox object to scene and assign script to that object.
This script is synchronized in multiplayer. You only must use mode script with Automatic sync. support.
Synchronization channel is added automatically
______________TUTORIAL FOR 3DS MAX:
Create objects: box, cover and kit's. Kit's must use same name, except end number is increasing and start with 0.
Example "Kit_0", "Kit_1"... and so on.
Kit's count can be up to 20 and is detected automatically in script.
Fix your cover and kit’s names in this script.
You must add some settings to your "cover" object in 3DS MAX:
Phy_colshp=2
Phy_misshp=2
Phy_status=0
Script isn't working without those settings!!!
_____________HISTORY:
// 1.0 - automatic Global variable system
// 1.2 - cleaned after test
// 2.1 - When ammoboxes are disabled in server then using empty box
// 3.0 - tested with team
// 3.1 - Changed use distance from 0.5 to 0.8 //recommendation by intruder and testers
// 3.1 - added info text "Ammo full" //recommendation by intruder and testers
// 3.1 - added info text "Box is empty now" //recommendation by intruder and testers
// 3.2 - added kit movement
// 3.3 - removed kit's when box is disabled in server
// 3.3 - added info text "Medic box is disabled by server"
*/
//___________________________PART OF AUTOMATIC SYNC. CANNEL________________
#define GVAR_SERVER 600 // 0 - not server, 1 - server
#define GVAR_COUNT 601 // Channel for G-var count
#define GVAR_GPHASE 500 // 1 - game is in starting state (reseting object)
//_________________________________________________________________________
int Temp = 0; //global state of object.
int Temp2 = -1; //local state of object. -1 = unknown ststus (for start/restart)
int Temp3 = 0; //sub stste of object
int i;
int my_gvar_count;
int my_gvar; //object Gver
int obj_count=0;
int curr_obj=0;
int ScriptMain(s_SC_OBJ_info *info){
switch(info->event_type){
case SC_OBJ_INFO_EVENT_INIT:
obj_count=0;
for(i= 1; i < 20; i++){//count of objects
sprintf(txt, med_sub_obj, i);
if (SC_NOD_GetNoMessage(info->master_nod, txt))obj_count++;
}
if (obj_count>0){
sprintf(txt, med_sub_obj, 1);
med_sub_obj_id= SC_NOD_GetNoMessage(info->master_nod, txt);
SC_NOD_GetTransform(med_sub_obj_id,&orig_trans_med);
}
cover_sub_obj_id = SC_NOD_GetNoMessage(info->master_nod, cover_sub_obj);
SC_NOD_GetTransform(cover_sub_obj_id,&orig_trans);
SC_NOD_GetWorldPos(cover_sub_obj_id,&door_vec);
//____________creating global variable
my_gvar_count = SC_ggi(GVAR_COUNT)+1;
SC_sgi(GVAR_COUNT,my_gvar_count);
my_gvar = my_gvar_count+ 601;
//____________
return TRUE;
case SC_OBJ_INFO_EVENT_JUSTLOADED:
break;
case SC_OBJ_INFO_EVENT_RELEASE:
SC_NOD_SetTransform(cover_sub_obj_id,&orig_trans);
for(i= 1; i < obj_count+1; i++){//count of objects
sprintf(txt, med_sub_obj, i);
med_sub_obj_id=SC_NOD_GetNoMessage(info->master_nod, txt);
if (med_sub_obj_id){// to avoid bugs
trans=orig_trans_med;
SC_NOD_SetTransform(med_sub_obj_id,&trans);
}
//net_id = SC_Item_Find(21);
//SC_Osi("item: %d",net_id);
break;
case SC_OBJ_INFO_EVENT_DOTICK:
switch(SC_ggi(GVAR_GPHASE)){
case 101: // gphase_begin for nonstandart gamemodes
case 102: // gphase_begin for nonstandart gamemodes
case 1:
Temp2 = -1; //restores unknown state for door
return TRUE;
break;
}//switch(gPhase)
//______________start/restart status for server____________
if (Temp2 == -1){ //restores stsrt state
if (SC_ggi(GVAR_SERVER) == 1){
//get server ammobox settings
if(SC_MP_GetAmmoBoxesEnabled()){
SC_sgi(my_gvar,0); // status on start/restart
}else{
SC_sgi(my_gvar,-2); // status on start/restart
}
}
}
Temp = SC_ggi(my_gvar);
//______________use string__________
if (Temp == Temp2){
if (obj_count>Temp){
val = SC_DOBJ_CameraLooksAt(cover_sub_obj_id,2);
if (val<USE_DISTANCE){
SC_ACTIVE_Add(info->master_nod,2.0f*val,USE_STRING);
}
}
}
//_____________CHANGE OBJECT STATUS________________
if (Temp != Temp2){ //temp- Global state Temp2 - Local state
if (Temp == -2){//Med box disabled in server
trans=orig_trans;
trans.rot.y+= DEG_TO_RAD(ROT_ANGLE);
SC_NOD_SetTransform(cover_sub_obj_id,&trans);
startsound = TRUE;//??????
timer=0;
Temp2=-2;
Temp3=0;
for(i= 1; i < obj_count+1; i++){//count of objects
sprintf(txt, med_sub_obj, i);
med_sub_obj_id=SC_NOD_GetNoMessage(info->master_nod, txt);
if (med_sub_obj_id){// to avoid bugs
trans=orig_trans_med;
trans.loc.z =-1000;
SC_NOD_SetTransform(med_sub_obj_id,&trans);
}
}
return TRUE;
}
if (Temp==0){//not used
SC_NOD_SetTransform(cover_sub_obj_id,&orig_trans);
startsound = TRUE;//??????
timer=0;
Temp2=0;//?????
Temp3=0;
for(i= 1; i < obj_count+1; i++){//count of objects
sprintf(txt, med_sub_obj, i);
med_sub_obj_id=SC_NOD_GetNoMessage(info->master_nod, txt);
if (med_sub_obj_id){// to avoid bugs
trans=orig_trans_med;
SC_NOD_SetTransform(med_sub_obj_id,&trans);
}
}
return TRUE;
}
//if (Temp>obj_count){//set box empty status
// trans=orig_trans;
// trans.rot.y+= DEG_TO_RAD(ROT_ANGLE);
// SC_NOD_SetTransform(cover_sub_obj_id,&trans);
// startsound = TRUE;//?????
// timer=0;
// Temp2=Temp;
// return TRUE;
//}
if (Temp>0){//use box
timer+=info->time;
switch(Temp3){
case 0: //Temp3//opening box
if (startsound){
SC_SND_PlaySound3D(OPENSOUND,&door_vec);
startsound = FALSE;
}
trans=orig_trans;
trans.rot.y+=1*(DEG_TO_RAD(ROT_ANGLE)/2+(DEG_TO_RAD(ROT_ANGLE)/2 *sin((DEG_TO_RAD(180)*timer/OPENINGTIME)- DEG_TO_RAD(90))));
SC_NOD_SetTransform(cover_sub_obj_id,&trans);
if (timer >= OPENINGTIME){
timer=0;
Temp3++;
}
break;
case 1: //Temp3//stay shortly opened
//move kit object
//SC_Osi("time %1.1f",timer);
for(i= curr_obj; i < Temp; i++){//for - because when 2 players using object in a same time
sprintf(txt, med_sub_obj, i+1);
med_sub_obj_id=SC_NOD_GetNoMessage(info->master_nod, txt);
if (med_sub_obj_id){// to avoid bugs
trans=orig_trans_med;
trans.loc.z+= MOVE_UP_KIT * timer/STAY_OPEN_TIME;
SC_NOD_SetTransform(med_sub_obj_id,&trans);
}
}
if (timer >= (STAY_OPEN_TIME)){
if (Temp>=obj_count){
trans=orig_trans;
trans.rot.y+= DEG_TO_RAD(ROT_ANGLE);
SC_NOD_SetTransform(cover_sub_obj_id,&trans);
startsound = TRUE;//?????
timer=0;
Temp2=Temp;
return TRUE;
}
//remove object
for(i= curr_obj; i < Temp; i++){//for - because when 2 players using object in a same time
sprintf(txt, med_sub_obj, i+1);
med_sub_obj_id=SC_NOD_GetNoMessage(info->master_nod, txt);
if (med_sub_obj_id){// to avoid bugs
trans=orig_trans_med;
trans.loc.z=-1000;
SC_NOD_SetTransform(med_sub_obj_id,&trans);
}
}
curr_obj=Temp;
startsound = TRUE;
timer=0;
Temp3++;
}
break;
case 2: //Temp3//closing box
if (startsound){
if (HasShoot){//add med to PC who used object
SC_P_AddAmmoNoGrenade(SC_PC_Get());
HasShoot= FALSE;
}
SC_SND_PlaySound3D(CLOSESOUND,&door_vec);
startsound = FALSE;
}
trans=orig_trans;
trans.rot.y+=-1*(DEG_TO_RAD(ROT_ANGLE)/2+(DEG_TO_RAD(ROT_ANGLE)/2 *sin((DEG_TO_RAD(180)*timer/OPENINGTIME)- DEG_TO_RAD(90))));
trans.rot.y+=DEG_TO_RAD(ROT_ANGLE);
SC_NOD_SetTransform(cover_sub_obj_id,&trans);
if (timer >= OPENINGTIME){
SC_SND_PlaySound3D(COLL_SOUND,&door_vec);
Temp3++;
}
break;
case 3: //Temp3//box closed
//BOOL SC_P_GetHasShoot(SC_PC_Get());//for ammo box
SC_NOD_SetTransform(cover_sub_obj_id,&orig_trans);
startsound = TRUE;//??????
timer=0;
Temp2=Temp;
Temp3=0;
break;
}
}
}
break;
case SC_OBJ_INFO_EVENT_USED:
if (Temp == -2){//ammo/med box disabled in server
SC_GameInfo(NULL, "Ammo box is disabled by server");
return TRUE;
}
if ((SC_P_GetHasShoot(SC_PC_Get())) || (HasShoot)){
Temp = SC_ggi(my_gvar);
SC_sgi(my_gvar,Temp+1); // start opening
HasShoot=TRUE;
if (Temp>=obj_count-1){
SC_GameInfo(NULL, "Box is empty now");
Max tutorial for custom object:
You must add some settings to your cover sub object in 3DS MAX:
Phy_colshp=2
Phy_misshp=2
Script isn't working without those settings!!!
Script:
Spoiler:[ShowHide]
Code
// VIETCONG 1
// BOX_COVER script v3.0
// made by Ando
/*
______________DESCRIPTION:
Player can open/close a box
This script is synchronized in multiplayer.
______________TUTORIAL:
Assign that script to main "box" object and fix "cover" sub object name on that script.
Script is rotating "cover" object on X axis. You can easily change rotation angle and speed.
You must add some settings to your cover sub object in 3DS MAX:
Phy_colshp=2
Phy_misshp=2
Script isn't working without those settings!!!
int Temp = 0; //global object status
int Temp2 = -1; //local object status. -1 = unknown ststus (for start/restart)
int i_items,j;
int my_gvar_count;
int my_gvar;
BOOL startsound = FALSE;
int ScriptMain(s_SC_OBJ_info *info){
switch(info->event_type){
case SC_OBJ_INFO_EVENT_INIT:
door_sub_obj_id = SC_NOD_GetNoMessage(info->master_nod, door_sub_obj);
SC_NOD_GetTransform(door_sub_obj_id,&orig_trans);
SC_NOD_GetWorldPos(door_sub_obj_id,&door_pos); //sound location
return TRUE;
case SC_OBJ_INFO_EVENT_JUSTLOADED:
break;
case SC_OBJ_INFO_EVENT_RELEASE:
SC_NOD_SetTransform(door_sub_obj_id,&orig_trans);
break;
case SC_OBJ_INFO_EVENT_HIT:
break;
case SC_OBJ_INFO_EVENT_DOTICK:
switch(SC_ggi(GVAR_GPHASE)){
case 101: // gphase_begin for nonstandart gamemodes
case 102: // gphase_begin for nonstandart gamemodes
case 1:
Temp2 = -1; //restores unknown state for door
return TRUE;
break;
}//switch(gPhase)
//______________start/restart status for server____________
if (Temp2 == -1){ //restores stsrt state
if (SC_ggi(GVAR_SERVER) == 1){
SC_sgi(my_gvar,START_STATE); // status on start/restart
}
}
Temp = SC_ggi(my_gvar);
//______________use string__________
val = SC_DOBJ_CameraLooksAt(door_sub_obj_id,2);
if (val<1.0f){
if (Temp == 0 || Temp == 3){
use_string = OPENSTRING;
}
if (Temp == 1 || Temp == 2){
use_string = CLOSESTRING;
}
SC_ACTIVE_Add(info->master_nod,2.0f*val,use_string);
}
//_____________CHANGE OBJECT STATUS________________
if (Temp != Temp2){ //temp- Global state Temp2 - Local state
switch(Temp){
case 0: //set door closed status
SC_NOD_SetTransform(door_sub_obj_id,&orig_trans);
startsound = TRUE;//
timer=0;
Temp2=0;
break;
case 1: //set door opened status
trans=orig_trans;
trans.rot.x+= DEG_TO_RAD(ROT_ANGLE);
SC_NOD_SetTransform(door_sub_obj_id,&trans);
startsound = TRUE;//
timer=0;
Temp2=1;
break;
case 2: //door is opening
if (Temp2==1){ //last state was oposite movement
timer = (OPENINGTIME-timer);//reverse movement time
}
Temp2=0;
if (startsound){
SC_SND_PlaySound3D(OPENSOUND,&door_pos);
startsound = FALSE;
}
timer+=info->time;
trans=orig_trans;
trans.rot.x+=(DEG_TO_RAD(ROT_ANGLE)*timer/OPENINGTIME);
SC_NOD_SetTransform(door_sub_obj_id,&trans);
if (timer >= OPENINGTIME){
if (SC_ggi(GVAR_SERVER) == 1) SC_sgi(my_gvar,1); //
}
break;
case 3: //door is closing
if (Temp2==0){ //last state was oposite movement
timer = (OPENINGTIME-timer);//reverse movement time
}
Temp2=1;
if (startsound){
SC_SND_PlaySound3D(CLOSESOUND,&door_pos);
startsound = FALSE;
}
timer+=info->time;
trans=orig_trans;
trans.rot.x+=(DEG_TO_RAD(ROT_ANGLE)*(OPENINGTIME-timer)/OPENINGTIME);
SC_NOD_SetTransform(door_sub_obj_id,&trans);
if (timer >= OPENINGTIME){
if (SC_ggi(GVAR_SERVER) == 1) SC_sgi(my_gvar,0); //
}
break;
case 5: //
break;
}
}
break;
case SC_OBJ_INFO_EVENT_USED:
Temp = SC_ggi(my_gvar);
switch(Temp){
case 0: // door is closed
case 3: // door is closing
SC_sgi(my_gvar,2); // start opening
break;
case 1: // door is opened
case 2: // door is opening
SC_sgi(my_gvar,3); // start closing
break;
}
break;
}// switch(info->event_type)
return FALSE;
}// int ScriptMain(s_OBJ_info *info)
Description:
All you see is synchronized and visible to others.
Player can use medic box to receive medic kit to slot 7 (keyboard nr 8).
When player is using it box cover is moving, one kit is lifted up from box and player see message how much kits are left.
DE_first_aid.bes contains 12 medic kits. When last kit are taken then box stay in open state and player will see message "Box is empty now"
Payer can't use it when he already have a medic kit, but he receive message "You already have it"
When ammo boxes are disabled in server settings then box appear in empty state and player see info text "Medic box is disabled by server" when used.
All is restored after restart.
Max tutorial for custom object:
Create box object, cover and kit's. Kits must use same name, except end number is increasing and start with 0.
Example "Kit_0", "Kit_1"... and so on.
Kit's count can be up to 20 and is detected automatically in script.
You must add some settings to your "cover" object in 3DS MAX:
Phy_colshp=2
Phy_misshp=2
Phy_status=0
Script isn't working without those settings!!!
Object
Object is attached to this post with textures.
Script:
Spoiler:[ShowHide]
Code
// VIETCONG 1
// FIRST_AID script v3.3
// Writen for custom object - DE_first_aid.bes
// made by Ando
/*
______________DESCRIPTION:
All you see is synchronized and visible to others.
Player can use medic box to receive medic kit to slot 7 (keyboard nr 8).
When player is using it box cover is moving, one kit is lifted up from box and player see message how much kits are left.
DE_first_aid.bes contains 12 medic kits. When last kit are taken then box stay in open state and player will see message "Box is empty now"
Payer can't use it when he already have a medic kit, but he receive message "You already have it"
When ammo boxes are disabled in server settings then box appear in empty state and player see info text "Medic box is disabled by server" when used.
All is restored after restart.
______________TUTORIAL FOR EDITOR
This script is written for custom object "DE_first_aid.bes"
Place that object to scene and assign that script to object.
This script is synchronized in multiplayer. You only must use mode script with Automatic sync. support.
Synchronization channel is added automatically
______________TUTORIAL FOR 3DS MAX:
Create box object, cover and kit's. Kits must use same name, except end number is increasing and start with 0.
Example "Kit_0", "Kit_1"... and so on.
Kit's count can be up to 20 and is detected automatically in script.
You must add some settings to your "cover" object in 3DS MAX:
Phy_colshp=2
Phy_misshp=2
Phy_status=0
Script isn't working without those settings!!!
_____________KNOWN BUGS:
-
_____________HISTORY:
// 1.0 - automatic Global variable system
// 1.2 - cleaned after test
// 2.1 - When ammoboxes are disabled in server then using empty box
// 3.0 - tested with team
// 3.1 - Changed use distance from 0.5 to 0.8 //recommendation by intruder and testers
// 3.1 - added info text "You already have" //recommendation by intruder and testers
// 3.2 - added kit movement
// 3.3 - removed kit's when box is disabled in server
// 3.3 - added info text "Medic box is disabled by server"
*/
//___________________________PART OF AUTOMATIC SYNC. CANNEL________________
#define GVAR_SERVER 600 // 0 - not server, 1 - server
#define GVAR_COUNT 601 // Channel for G-var count
#define GVAR_GPHASE 500 // 1 - game is in starting state (reseting object)
//_________________________________________________________________________
int Temp = 0; //global state of object.
int Temp2 = -1; //local state of object. -1 = unknown ststus (for start/restart)
int Temp3 = 0; //sub stste of object
int i;
int my_gvar_count;
int my_gvar; //object Gver
int obj_count=0;
int curr_obj=0;
BOOL add_med = FALSE;
BOOL startsound = FALSE;
char txt[32];
int ScriptMain(s_SC_OBJ_info *info){
switch(info->event_type){
case SC_OBJ_INFO_EVENT_INIT:
obj_count=0;
for(i= 1; i < 20; i++){//count of objects
sprintf(txt, med_sub_obj, i);
if (SC_NOD_GetNoMessage(info->master_nod, txt))obj_count++;
}
if (obj_count>0){
sprintf(txt, med_sub_obj, 1);
med_sub_obj_id= SC_NOD_GetNoMessage(info->master_nod, txt);
SC_NOD_GetTransform(med_sub_obj_id,&orig_trans_med);
}
cover_sub_obj_id = SC_NOD_GetNoMessage(info->master_nod, cover_sub_obj);
SC_NOD_GetTransform(cover_sub_obj_id,&orig_trans);
SC_NOD_GetWorldPos(cover_sub_obj_id,&door_vec);
//____________creating global variable
my_gvar_count = SC_ggi(GVAR_COUNT)+1;
SC_sgi(GVAR_COUNT,my_gvar_count);
my_gvar = my_gvar_count+ 601;
//____________
return TRUE;
case SC_OBJ_INFO_EVENT_JUSTLOADED:
break;
case SC_OBJ_INFO_EVENT_RELEASE:
SC_NOD_SetTransform(cover_sub_obj_id,&orig_trans);
for(i= 1; i < obj_count+1; i++){//count of objects
sprintf(txt, med_sub_obj, i);
med_sub_obj_id=SC_NOD_GetNoMessage(info->master_nod, txt);
if (med_sub_obj_id){// to avoid bugs
trans=orig_trans_med;
SC_NOD_SetTransform(med_sub_obj_id,&trans);
}
}
break;
case SC_OBJ_INFO_EVENT_HIT:
break;
case SC_OBJ_INFO_EVENT_DOTICK:
switch(SC_ggi(GVAR_GPHASE)){
case 101: // gphase_begin for nonstandart gamemodes
case 102: // gphase_begin for nonstandart gamemodes
case 1:
Temp2 = -1; //restores unknown state for door
return TRUE;
break;
}//switch(gPhase)
//______________start/restart status for server____________
if (Temp2 == -1){ //restores stsrt state
if (SC_ggi(GVAR_SERVER) == 1){
//get server ammobox settings
if(SC_MP_GetAmmoBoxesEnabled()){
SC_sgi(my_gvar,0); // status on start/restart
}else{
SC_sgi(my_gvar,-2); //SC_sgi(my_gvar,obj_count+1);
}
}
}
Temp = SC_ggi(my_gvar);
//______________use string__________
if (Temp == Temp2){
if (obj_count>Temp){
val = SC_DOBJ_CameraLooksAt(cover_sub_obj_id,2);
if (val<USE_DISTANCE){
SC_ACTIVE_Add(info->master_nod,2.0f*val,USE_STRING);
}
}
}
//_____________CHANGE OBJECT STATUS________________
if (Temp != Temp2){ //temp- Global state Temp2 - Local state
if (Temp == -2){//Med box disabled in server
trans=orig_trans;
trans.rot.y+= DEG_TO_RAD(ROT_ANGLE);
SC_NOD_SetTransform(cover_sub_obj_id,&trans);
startsound = TRUE;//??????
timer=0;
Temp2=-2;
Temp3=0;
for(i= 1; i < obj_count+1; i++){//count of objects
sprintf(txt, med_sub_obj, i);
med_sub_obj_id=SC_NOD_GetNoMessage(info->master_nod, txt);
if (med_sub_obj_id){// to avoid bugs
trans=orig_trans_med;
trans.loc.z =-1000;
SC_NOD_SetTransform(med_sub_obj_id,&trans);
}
}
return TRUE;
}
if (Temp==0){//not used
SC_NOD_SetTransform(cover_sub_obj_id,&orig_trans);
startsound = TRUE;//??????
timer=0;
Temp2=0;
Temp3=0;
for(i= 1; i < obj_count+1; i++){//count of objects
sprintf(txt, med_sub_obj, i);
med_sub_obj_id=SC_NOD_GetNoMessage(info->master_nod, txt);
if (med_sub_obj_id){// to avoid bugs
trans=orig_trans_med;
SC_NOD_SetTransform(med_sub_obj_id,&trans);
}
}
return TRUE;
}
//if (Temp>obj_count){//set box empty status
// trans=orig_trans;
// trans.rot.y+= DEG_TO_RAD(ROT_ANGLE);
// SC_NOD_SetTransform(cover_sub_obj_id,&trans);
// startsound = TRUE;//?????
// timer=0;
// Temp2=Temp;
// return TRUE;
//}
if (Temp>0){//use box
timer+=info->time;
switch(Temp3){
case 0: //Temp3//opening box
if (startsound){
SC_SND_PlaySound3D(OPENSOUND,&door_vec);
startsound = FALSE;
}
trans=orig_trans;
trans.rot.y+=1*(DEG_TO_RAD(ROT_ANGLE)/2+(DEG_TO_RAD(ROT_ANGLE)/2 *sin((DEG_TO_RAD(180)*timer/OPENINGTIME)- DEG_TO_RAD(90))));
SC_NOD_SetTransform(cover_sub_obj_id,&trans);
if (timer >= OPENINGTIME){
timer=0;
Temp3++;
}
break;
case 1: //Temp3//stay shortly opened
//move kit object
for(i= curr_obj; i < Temp; i++){//for - because when 2 players using object in a same time
sprintf(txt, med_sub_obj, i+1);
med_sub_obj_id=SC_NOD_GetNoMessage(info->master_nod, txt);
if (med_sub_obj_id){// to avoid bugs
trans=orig_trans_med;
trans.loc.z+= MOVE_UP_KIT * timer/STAY_OPEN_TIME;
SC_NOD_SetTransform(med_sub_obj_id,&trans);
}
}
if (timer >= (STAY_OPEN_TIME)){
if (Temp>obj_count){//set box empty status
trans=orig_trans;
trans.rot.y+= DEG_TO_RAD(ROT_ANGLE);
SC_NOD_SetTransform(cover_sub_obj_id,&trans);
startsound = TRUE;//?????
timer=0;
Temp2=Temp;
return TRUE;
}
//remove object
for(i= curr_obj; i < Temp; i++){//for - because when 2 players using object in a same time
sprintf(txt, med_sub_obj, i+1);
med_sub_obj_id=SC_NOD_GetNoMessage(info->master_nod, txt);
if (med_sub_obj_id){// to avoid bugs
trans=orig_trans_med;
trans.loc.z=-1000;
SC_NOD_SetTransform(med_sub_obj_id,&trans);
}
}
curr_obj=Temp;
startsound = TRUE;
timer=0;
Temp3++;
}
break;
case 2: //Temp3//closing box
if (startsound){
if (add_med){//add med to PC who used object
SC_P_ChangeWeapon(SC_PC_Get(), 7, ADD_WEAPON);
SC_P_SetSelWeapon(SC_PC_Get(), 7);
add_med = FALSE;
}
SC_SND_PlaySound3D(CLOSESOUND,&door_vec);
startsound = FALSE;
}
trans=orig_trans;
trans.rot.y+=-1*(DEG_TO_RAD(ROT_ANGLE)/2+(DEG_TO_RAD(ROT_ANGLE)/2 *sin((DEG_TO_RAD(180)*timer/OPENINGTIME)- DEG_TO_RAD(90))));
trans.rot.y+=DEG_TO_RAD(ROT_ANGLE);
SC_NOD_SetTransform(cover_sub_obj_id,&trans);
if (timer >= OPENINGTIME){
SC_SND_PlaySound3D(COLL_SOUND,&door_vec);
Temp3++;
}
break;
case 3: //Temp3//box closed
//BOOL SC_P_GetHasShoot(dword pl_id);//for ammo box
SC_NOD_SetTransform(cover_sub_obj_id,&orig_trans);
startsound = TRUE;//??????
timer=0;
Temp2=Temp;
Temp3=0;
break;
}
}
}
break;
case SC_OBJ_INFO_EVENT_USED:
if (Temp == -2){//ammo/med box disabled in server
SC_GameInfo(NULL, "Medic box is disabled by server");
return TRUE;
}
if (SC_P_HasWeapon(SC_PC_Get(),ADD_WEAPON)){//if already have that
//void SC_GameInfoW(ushort *text);
SC_GameInfo(NULL, "You already have");
}
else{
Temp = SC_ggi(my_gvar);
SC_sgi(my_gvar,Temp+1); // start opening
add_med = TRUE;
if (Temp>=obj_count-1){
SC_GameInfo(NULL, "Box is empty now");
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
Description 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 object:
-
Object
Tree object is made by LDC-78.
Objects with textures are attached to this post.
Script:
Spoiler:[ShowHide]
Code
// 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 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
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;
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);
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
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);
Description in reality:
Mace Trap: Mace traps take various forms, and may consist of a spiked concrete ball, drum, box or log
suspended in a tree on the end of a rope, or cable. When the trip wire is pulled, the mace swings down
along the path striking anyone in its way.
Description in game:
If player collides with wire then trap is released and mace swings down. If player is on its way then he will be killed.
Wire goes down also when hit by bullet, knife or explosion. Player can also reactivate that trap in game, when mace dont move anymore.
After start/restart trap will appear randomly to some predefined position.
Tutorial for editor:
-Place one _mace_trap.bes and _mace_trap_tree.bes object to map.
- move "_mace_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 object:
-
Object
Objects with textures are attached to this post.
Script:
Spoiler:[ShowHide]
Code
// VIETCONG 1
// Mace_Trap_Random script v3.3 (Writen for custom objects - _mace_trap.bes and _mace_trap_tree.bes)
// made by Ando
/*
______________TRAP DESCRIPTION IN REALITY:
Mace Trap: Mace traps take various forms, and may consist of a spiked concrete ball, drum, box or log
suspended in a tree on the end of a rope, or cable. When the trip wire is pulled, the mace swings down
along the path striking anyone in its way.
______________TRAP BEHAVIOUR IN GAME:
If player collides with wire then trap is released and mace swings down. If player is on its way then he will be killed.
Wire goes down also when hit by bullet, knife or explosion. Player can also reactivate that trap in game, when mace dont move anymore.
After start/restart trap will appear randomly to some predefined position.
______________TUTORIAL FOR EDITOR
-Place one _mace_trap.bes and _mace_trap_tree.bes object to map.
- move "_mace_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
_____________NOTES:
1.3 - new sync system
1.4 - Changed movement
1.5 - new killing system - with death count
1.6 - automatic Global variable system
2.0 - tested with 2x editor
3.0 - tested with team
3.1 - all 3.1 improvements was recomendations by Intruder and his testing team
3.1 - "move" sound is decreasing now faster
3.1 - reset text distance appears now from 1.0m(was 0.5)
3.1 - dont kill player when mace rotation angle is smaller than 55 degrees (before was killing as long as it was moveing)
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
_____________CURRENT BUGS:
none
______________IDEAS:
maybe its reasonable to add option only for engineer to set up that trap again (now its for all)
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;
//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);//new count of custom global variables
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 for light (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 string__________
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_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);
}
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.5f;
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: //first move time
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);
Temp3=1;
break;
case 1: //normal move
if (cur_rot <= 0){//second movement is over
Temp3=2;//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.y+=r_dir*(DEG_TO_RAD(cur_rot));
r_dir=-r_dir; //reverse movement direction
timer=0; //reset time for next swing
cur_rot-=((0.11* cur_rot)+0.1); //degrease angle for next swing
sound_h+= 1.4f; //
SC_NOD_GetWorldPos(mov_sub_obj_id, &vec2);
vec2.z+=sound_h;
SC_SND_PlaySound3D(MOVE_SOUND,&vec2);
}
trans=trans_swing;
trans.rot.y+=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);
//______________________killing player_________
if (cur_rot > 55){
SC_NOD_GetWorldPos(dum_sub_obj_id, &dum_pos);
if (SC_ggi(GVAR_SERVER) == 1){// only server
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
vec2=head_pos;
vec2.z+=sound_h;
SC_SND_PlaySound3D(PL_HIT_SOUND,&vec2);
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
vec2=head_pos;
vec2.z+=sound_h;
SC_SND_PlaySound3D(PL_HIT_SOUND,&vec2);
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;
}//switch(Temp3){
break;
case 2: // drap 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); //
//
There is two parts
1. Create a camera animation ( for location of curve sound)
2. Add a sound to sounds.c script
1. Create camera animation for curve sound
- open your map
- go to start position of your curve sound
- choose menu command "Editor" > "Camera animation editor"
- add some name to "name:" box
- click "Create"
- click "Create Key" ( some blue mark appear to frame slide bar)
Now first position is created
Down in camera animation editor you can see frame selector. And it will look like this: < 0 / 100 >
- There you choose next frame. Click to ">" button on frame slide bar. Now you should see < 1 / 100 >
- turn on "Move" button
- now move to better position ( where you have some overview for curve sound location)
- click and drag your pink camera to next position
- click "Create Key" ( white mark appear to camera position)
- click to next frame ( ">" button )
- click and drag your camera to next position
- click "Create Key"
- continue as long as you need ( ">" ; drag camera ; "Create Key" )
...
- click "Save"
- choose right folder for your camera animation ( LEVELS\mapname\DATA\subname\snd\ )
- choose file name and click "save"
camera animation file must be in right position then its added to map file, when finalized
2. Add curve sound to sound script
Sound.c file is created automatically during finalization. It's located under scripts folder of your map.
- open sound.c file with some text editing program.
anm_filename - your camera animation file for curve sound
snd_id - sound id
max_play_dist - distance from camera animation where player can hear that sound
apply_env_volume - TRUE / FALSE option. If true then curve sound will use environment sound volume.
Description in reality:
When a man falls into the Punji Pit, he will be injured by the pointed
bamboo stakes which will cut his thighs and hips, or stab him through
the back, often these spikes are connected to a hand grenade,
designed to explode when the man is pulled out of the pit.
Description in game:
If player walk over trap cover then it fall down with player.
When player collide with spices then he will die.
Trap cover will fall also when hit by gun/knife 2 times or hit by grenade.
When trap cover is down then player can destroy that trap.
After start/restart trap will appear randomly.
Tutorial for editor:
- Trap hole(s) must be added to terrain in MAX.
- add trap object precisely to hole
- for that use: "Settings" > "Snap settings" and turn on "vertex" only
- turn on "Snap translator"
- now you can move cover precisely to right place
- add script to trap object in level.c script
Max tutorial for custom object:
-
Object
Objects with textures are attached to this post.
Script are not included there, because it's easier to update only in that post, if needed.
Script:
Spoiler:[ShowHide]
Code
// VIETCONG 1
// Punji_Pit_Trap_random script v3.1 (Writen for custom object - punji_pit_trap.BES)
// made by Ando
/*
______________TRAP DESCRIPTION IN REALITY:
When a man falls into the Punji Pit, he will be injured by the pointed
bamboo stakes which will cut his thighs and hips, or stab him through
the back, often these spikes are connected to a hand grenade,
designed to explode when the man is pulled out of the pit.
______________TRAP BEHAVIOUR IN GAME:
If player walk over trap cover then it fall down with player.
When player collide with spices then he will die.
Trap cover will fall also when hit by gun/knife 2 times or hit by grenade.
When trap cover is down then player can destroy that trap.
After start/restart trap will appear randomly.
______________TUTORIAL FOR EDITOR
- Trap hole(s) must be added to terrain in MAX.
- add trap object precisely to hole
- for that use: "Settings" > "Snap settings" and turn on "vertex" only
- turn on "Snap translator"
- now you can move cover precisely to right place
- add script to trap object in level.c script
_____________BUGS:
none
_____________NOTES:
2.2 - removed one rare bug (dont count shots anymore when moveing)
2.2 - improved code (restart area)
2.2 - added particles
3.0 - tested with team (thanks to Intruder)
3.1 - added more particles when cover is falling
3.1 - trap is randomly on/off
3.1 - added sign
3.1 - added option to disarm trap
______________IDEAS:
none
int hit_count = 0;
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;
//creating global variable
my_gvar_count = SC_ggi(GVAR_COUNT)+1;
SC_sgi(GVAR_COUNT,my_gvar_count);
my_gvar = my_gvar_count+ 601;
break;
case SC_OBJ_INFO_EVENT_JUSTLOADED:
break;
case SC_OBJ_INFO_EVENT_RELEASE:
SC_NOD_SetTransform(cover_tr_sub_obj_id,&orig_trans_cover_tr);
SC_NOD_SetTransform(cover_sub_obj_id,&orig_trans_cover);
SC_NOD_SetTransform(spices_sub_obj_id,&orig_trans_spices);
SC_NOD_SetTransform(spices_dstr_sub_obj_id,&orig_trans_spices_dstr);
Temp2 = -1; //restores unknown state
break;
case SC_OBJ_INFO_EVENT_HIT:
//switch(Temp){
//case 0://trap up
// if(info->nod == cover_tr_sub_obj_id){
// hit_count++;
// }
// break;
//case 2://trap down
// break;
//}
if(info->nod == cover_tr_sub_obj_id){
if(Temp == 0){
hit_count++;
if ((hit_count >= HITS_TO_FALL) || (info->hit_by == SC_OBJ_HIT_BY_EXPLOSION)){
SC_sgi(my_gvar,1); //
}
}
}
break;
case SC_OBJ_INFO_EVENT_DOTICK:
if (SC_ggi(GVAR_GPHASE) == 1){//restart
if (SC_ggi(GVAR_SERVER) == 1){ // its server
if (!SRV_restart_done){//restores start state for trap
if((rand() % 2)== 0){
SC_sgi(my_gvar,0); // status on start/restart (trap up)
}else{
SC_sgi(my_gvar,4); // status on start/restart (no trap)
}
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
if (SC_NOD_GetCollision(info->master_nod, cover_tr_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,DISARM_STRING);//USE string
}
break;
}//switch(Temp)
}
//_____________CHANGE OBJECT STATUS________________
if (Temp != Temp2){ //global status != Local status
switch(Temp){
case 0: // trap up
SC_NOD_SetTransform(cover_tr_sub_obj_id,&orig_trans_cover_tr); //visible
trans=orig_trans_cover;
trans.loc.z-=1000;
SC_NOD_SetTransform(cover_sub_obj_id,&trans);// not visible
trans=orig_trans_spices;
trans.loc.z-=1000;
SC_NOD_SetTransform(spices_sub_obj_id,&trans);// not
trans=orig_trans_spices_dstr;
trans.loc.z-=1000;
SC_NOD_SetTransform(spices_dstr_sub_obj_id,&trans);
hit_count = 0;
Temp2=0;
Temp3=0;
SC_NOD_GetCollision(info->master_nod, cover_tr_sub_obj, TRUE);//!!It must be here!! It will remove collision info related with move
break;
case 1: // drap move
switch(Temp3){
case 0: //start moving
SC_NOD_SetTransform(spices_sub_obj_id,&orig_trans_spices);// visible
trans=orig_trans_cover;
trans.loc.z-=1000;
SC_NOD_SetTransform(cover_sub_obj_id,&trans);// not visible
ATGCoop script with automatic global variable system (advanced)
details compared with original ATG:
- added automatic global variable system
- changed mission time for longer missions
- disabled "wait for next round" after join
- added sound for score
- added fade for restart and score respawn
Spoiler:[ShowHide]
Code
// VIETCONG 1
// ATG_Coop script (with automatic global variables for synchronized objects)
// modified by Ando from Eric multiplayer script - ATG - kill the others
// v3.0
// NOTES:
// 1.3 - added variable for server (600) to detect server from object scripts
// 1.3 - new G-var system (object scripts counting g-vars to channel 601 )
// 1.4 - SC_MP_RestartMission()command stops all synchro, even if I create new after that
// I replace it with SC_MP_RecoverAllNoAiPlayers() and SC_MP_RecoverAllAiPlayers()
// 2.0 - added fade for restart and score respawn
// 2.0 - added sound for score
// 3.0 - Created ATGCOOP from ATG
// 3.0 - changed mission time 7200 s (120 min)
// 3.0 - disabled "wait for next round"
//________________________________
//global variable system for object synchro
#define GVAR_SERVER 600 // server ( dont add SC_MP_Gvar_SetSynchro for that) 0 - not server, 1 - server
#define GVAR_COUNT 601 // count of object variables ( dont add SC_MP_Gvar_SetSynchro for that)
#define GVAR_USE_start 602 //start Global variable
//________________________________
#define GVAR_GPHASE 500 // important to use game phase and channel 500 for synchronised objects
//________________________________
#define FADE_TIME 0.8
#define NORECOV_TIME 3.0f // disable time of recoverplace after recovering someone there
void SRV_UpdateMissionTime(float time){
gMissionTime_update -= time;
if (gMissionTime_update<0.0f){
gMissionTime_update = 10.0f;
SC_sgf(GVAR_MISSIONTIME,gMissionTime);
SC_sgi(GVAR_MISSIONTIME_UPDATE,SC_ggi(GVAR_MISSIONTIME_UPDATE)+1);
}// if (gMissionTime_update<0.0f)
}
void Check_ABL(void){
int val;
dword side,nr_to_change;
s_SC_P_getinfo info;
s_SC_MP_EnumPlayers enum_pl[64];
dword i,j,k;
if (!SC_MP_SRV_GetAutoTeamBalance()) return;
val = SC_MP_SRV_GetTeamsNrDifference(TRUE);
if ((val<3)&&(val>-3)) return; // no big difference
if (val>0){
side = 0;
nr_to_change = val/2;
}
else{
side = 1;
nr_to_change = -val/2;
}
// find nr_to_change players of beste players of side 0
j = 64;
if (SC_MP_EnumPlayers(enum_pl,&j,side)){
if (!j) return;
while(nr_to_change!=0){
k = rand()%j;
i = k;
while(
(enum_pl[i].id==0)
||(enum_pl[i].status==SC_MP_P_STATUS_NOTINGAME)){
i++;
if (i==j) i = 0;
if (i==k) return; // no valid found
}
SC_MP_SRV_P_SetSideClass(enum_pl[i].id,1-side,1 + 20*(1-side));
enum_pl[i].id = 0;
nr_to_change--;
}// while(nr_to_change!=0)
}// if (SC_MP_EnumPlayers(enum_pl,&j,SC_MP_ENUMPLAYER_SIDE_ALL))
}// void Check_ABL(dword pl_handle)
case SC_NET_MES_SERVER_TICK:
if (SRV_CheckEndRule(info->elapsed_time)) break;
for (j=0;j<2;j++)
for (i=0;i<gRecs[j];i++)
gRecTimer[j][i] -= info->elapsed_time;
CLEAR(valid);
j = 64;
pilot_pl_id = 0;
if (SC_MP_EnumPlayers(enum_pl,&j,SC_MP_ENUMPLAYER_SIDE_ALL)){
if ((j==0)&&((gSidePoints[0]+gSidePoints[1])!=0)){
gSidePoints[0] = 0;
gSidePoints[1] = 0;
UpdateSidePoints();
}// if ((side[0]+side[1])==0)
for (i=0;i<j;i++)
if (enum_pl[i].status==SC_MP_P_STATUS_INGAME){
if (enum_pl[i].side<2) valid[enum_pl[i].side] = TRUE;
}// if (enum_pl[i].status==SC_MP_P_STATUS_INGAME)
}// if (SC_MP_EnumPlayers(enum_pl,&j,SC_MP_ENUMPLAYER_SIDE_ALL))
gPhase_timer -= info->elapsed_time;
switch(gPhase){
case GPHASE_BEGIN:
SC_MP_SetInstantRecovery(TRUE);
//start with gPhase_timer 5
if (gPhase_timer>2.0f) break;
if ((valid[0])&&(valid[1])){
if (gPhase_timer<-7.0f){
Check_ABL();
SC_MP_SRV_InitGameAfterInactive();
SC_MP_RecoverAllNoAiPlayers();
SC_MP_RecoverAllAiPlayers();
}
else{
gPhase = GPHASE_GAME;
SC_MP_SRV_GetAtgSettings(&atgset);
if (atgset.ATG_round_time>29.0f)
gMissionTime = atgset.ATG_round_time;
else
gMissionTime = GMISSION_TIME;
SRV_UpdateMissionTime(1000);
}
gPhase_timer = 0.0f;//??????????? for game phase
}// switch(valid[0])
break;// GPHASE_BEGIN
case GPHASE_GAME:
SC_MP_SetInstantRecovery(FALSE);
//gPhase_timer += info->elapsed_time;
if (gPhase_timer>-4.0f) break;
if (!valid[0]){
gSidePoints[1]++;
UpdateSidePoints();
gPhase = GPHASE_USKILLED;
gPhase_timer = RESTART_TIMER;
}
else
if (!valid[1]){
gSidePoints[0]++;
UpdateSidePoints();
gPhase = GPHASE_VCKILLED;
gPhase_timer = RESTART_TIMER;
}
else{
// check pilot distance
gMissionTime -= info->elapsed_time;
SRV_UpdateMissionTime(info->elapsed_time);
if (gMissionTime<0.0f){
gPhase = GPHASE_TIMEDONE;
gPhase_timer = 5.0f;
gMissionTime = 0.0f;
SRV_UpdateMissionTime(1000);
}// if (gMissionTime<0.0f)
}
break;// GPHASE_GAME
case GPHASE_BEFORE_RESTART:
if (gPhase_timer<0.0f){ //wait before restart
gPhase = GPHASE_RESTARTING;
}
break;
case GPHASE_RESTARTING:
gTime = 0;
gPhase=GPHASE_BEGIN;
gPhase_timer = 5.0f;
SC_sgi(GVAR_GPHASE,gPhase);//(1 = begin) For sync. objects. server restart
CLEAR(gSidePoints);
UpdateSidePoints();
SC_MP_SetInstantRecovery(TRUE);
SC_MP_SRV_ClearPlsStats();
SC_MP_SRV_InitGameAfterInactive();
SC_MP_RecoverAllNoAiPlayers();
break;
case GPHASE_USKILLED:
case GPHASE_VCKILLED:
case GPHASE_TIMEDONE:
//default:
SC_MP_SetInstantRecovery(FALSE);
if (gPhase_timer<0){
Check_ABL();
//SC_MP_RestartMission();//stops all synchro, even if I create new after that
SC_MP_RecoverAllNoAiPlayers(); //replaced SC_MP_RestartMission with it
SC_MP_RecoverAllAiPlayers(); //replaced SC_MP_RestartMission with it
Coop_us script with automatic global variable system (advanced)
details compared with original coop:
- added automatic global variable system
- added civilian option
- mission restart when civilian is killed by US an message appears who killed civilian
- restart with fade
- switch to next map when mission done
- added sound for "mission FAILED"
- added sound for "mission DONE"
Spoiler:[ShowHide]
Code
// VIETCONG 1
// COOP_US script (with automatic global variables for synchronized objects)
// modified by Ando
// v3.1
// NOTES:
// 1.1 - added global variables system
// 1.2 - added variable for server (600) to detect server from object scripts
// 1.2 - new G-var system (object scripts counting g-vars to channel 601 )
// 1.4 - added mission objectives test (removed later but was working)
// 2.0 - successfully tested with L|DC-78
// 2.1 - added civilian option
// 2.1 - mission restart when civilian is killed by US an message appears who killed civilian
// 2.1 - "mission fail" restart with fast fade
// 2.1 - fade when mission restarts
// 2.2 - switch to next map when mission done
// 3.0 - TESTED WITH TEAM
// 3.1 - added sound for "mission FAILED"
// 3.1 - added sound for "mission DONE"
// IDEAS
// show killed civilian before restart void SC_P_SetLinkedView(dword pl_id, float rz, float rx);
#define DONE_SOUND 6035 //snd 6035 music\slap25.ogg
#define FAILED_SOUND 6057 //snd 6057 music\slap47.ogg
//________________________________
//global variable system for object synchro !!!DONT CHANGE THOSE!!!
#define GVAR_SERVER 600 // server ( dont add SC_MP_Gvar_SetSynchro for that) 0 - not server, 1 - server
#define GVAR_COUNT 601 // count of Global variables ( dont add SC_MP_Gvar_SetSynchro for that)
#define GVAR_USE_start 602 //start nr of Global variable nr
//________________________________
#define GVAR_GPHASE 500 // important to use game phase and channel 500 for synchronised objects
#define GVAR_KILLED 501
#define GVAR_KILLER 502
//#define RECOVER_TIME 15.0f // time to global recover
#define NORECOV_TIME 3.0f // disable time of recoverplace after recovering someone there
switch(info->message){
case SC_NET_MES_SERVER_TICK:
if (SRV_CheckEndRule(info->elapsed_time)) break;
for (j=0;j<4;j++)
for (i=0;i<gRecs;i++)
gRecTimer[i] -= info->elapsed_time;
if (gRecoverTime<0xffff){
gNextRecover -= info->elapsed_time;
if (gNextRecover<0.0f) gNextRecover = (float)gRecoverTime;
}// if (gRecoverTime<0xffff)
if (gAllNoAiRecover>0.0f){
gAllNoAiRecover -= info->elapsed_time;
if (gAllNoAiRecover<=0.0f)
SC_MP_RecoverAllNoAiPlayers();
break;
}// if (gAllNoAiRecover>0.0f)
else{
gAllNoAiRecover -= info->elapsed_time;
}
CLEAR(valid);
j = 64;
alldeath = FALSE;
if (SC_MP_EnumPlayers(enum_pl,&j,SC_MP_ENUMPLAYER_SIDE_ALL)){
alldeath = TRUE;
for (i=0;i<j;i++){
if (enum_pl[i].status==SC_MP_P_STATUS_INGAME){
if (enum_pl[i].side>1);// SC_message("coop script wrong side: %d",enum_pl[i].side);
else{
valid[enum_pl[i].side] = TRUE;
}
}
if ((enum_pl[i].side==0)&&(enum_pl[i].status==SC_MP_P_STATUS_INGAME)) alldeath = FALSE;
}// for (i)
//SC_message("Enum, v[0]: %d v[1]: %d alldeath: %d",valid[0],valid[1],alldeath);
}// if (SC_MP_EnumPlayers(enum_pl,&j,SC_MP_ENUMPLAYER_SIDE_ALL))
else SC_message("NoEnum");
if ((gPhase==GPHASE_GAME)&&(alldeath)&&(gPhase_timer<0.0f)){
if (gRecoverLimit==0){
// mission failed
//SC_Log(2,"Set GPHASE_FAILED");
gPhase = GPHASE_FAILED;
gPhase_timer = 5.0f;
}
else {
// recover unlimited
//SC_message("recover unlimited");
if ((gRecoverTime>=0xffff)&&(gAllNoAiRecover<-5.0f)){
gAllNoAiRecover = 4.0f;
}
}
}// if ((alldeath)&&(gRecoverTime>=0xffff))
else gAllNoAiRecover = 0.0f;
gValidSide0 = valid[0];
gPhase_timer -= info->elapsed_time;
switch(gPhase){
case GPHASE_BEGIN:
if (notincar){
notincar = FALSE;
}
if (gPhase_timer<0.0f)
if ((valid[0])&&(valid[1])){
gPhase_timer = 5.0f;
gPhase = GPHASE_GAME;
}
break;
case GPHASE_GAME:
if (gPhase_timer<0.0f)
if (!valid[1]){
gPhase = GPHASE_DONE;
gPhase_timer = 5.0f;
}// if (!valid[1])
break;
case GPHASE_DONE:
if (gPhase_timer<0.0f){ //wait before restart
SC_MP_LoadNextMap();
}
break;
case GPHASE_FAILED:
if (gPhase_timer<0.0f){ //wait before restart
gPhase_timer = RESTART_TIMER;
gPhase = GPHASE_BEFORE_RESTART;
}
break;
case GPHASE_BEFORE_RESTART:
if (gPhase_timer<0.0f){ //wait before restart
gPhase = GPHASE_RESTARTING;
}
break;
case GPHASE_RESTARTING:
CLEAR(gRecTimer);
gNextRecover = 0.0f;
gTime = 0;
gPhase = GPHASE_BEGIN;
gPhase_timer = 5.0f;
gPhase_send = 0;
gValidSide0 = FALSE;
SC_MP_GetSRVsettings(&SRVset);
gRecoverTime = SRVset.coop_respawn_time;
gRecoverLimit = SRVset.coop_respawn_limit;
gAllNoAiRecover = 0.0f;
SC_MP_SRV_ClearPlsStats();
SC_MP_SRV_InitGameAfterInactive();
SC_MP_RecoverAllAiPlayers();
SC_MP_RecoverAllNoAiPlayers();
//SC_MP_RestartMission(); //restart // causing some truoble //using SC_NET_MES_LEVELINIT
//_________Reinit AI
num = 64;
SC_MP_EnumPlayers(enum_pl, &num, SC_MP_ENUMPLAYER_SIDE_ALL);//SC_MP_ENUMPLAYER_SIDE_ALL is for US_AI and civilian_AI
for (i = 0; i < num; i++){
SC_P_ScriptMessage(enum_pl[i].id, SCM_MP_REINIT, 0);
}
//_____________________
break;
}// switch(gPhase)
SRV_CheckUpdate();
break;
case SC_NET_MES_CLIENT_TICK:
switch(SC_ggi(GVAR_GPHASE)){
case GPHASE_BEGIN:
if (fade_off == FALSE){
SC_FadeTo(FALSE, FADE_TIME);
fade_off=TRUE;
}
break;
case GPHASE_GAME:
break;
case GPHASE_DONE:
if (sound_start==TRUE){
SC_SND_PlaySound2D(DONE_SOUND);
sound_start=FALSE;
}
break;
case GPHASE_FAILED:
if (sound_start==TRUE){
SC_SND_PlaySound2D(FAILED_SOUND);
sound_start=FALSE;
}
break;
case GPHASE_BEFORE_RESTART:
client_fade_timer -= info->elapsed_time;
if (client_fade_timer<FADE_TIME){
SC_FadeTo(TRUE, FADE_TIME);
fade_off=FALSE;
sound_start=TRUE;
client_fade_timer=RESTART_TIMER;
}
break;
case GPHASE_RESTARTING:
break;
}// switch(gPhase)
//SC_message(char *txt,...);
break;// SC_NET_MES_CLIENT_TICK
case SC_NET_MES_LEVELPREINIT:
client_fade_timer=RESTART_TIMER;
SC_sgi(GVAR_MP_MISSIONTYPE,GVAR_MP_MISSIONTYPE_COOP);
gEndRule = info->param1;
gEndValue = info->param2;
gTime = 0.0f;
SC_MP_EnableBotsFromScene(TRUE);
//______________________________________objectives________
Objectives[objective_count].text_id=100;
Objectives[objective_count].status=SC_OBJECTIVE_STATUS_VALID;
objective_count++;
SC_SetObjectives(objective_count,Objectives,100);
//________________________________________________________
break;// SC_NET_MES_LEVELPREINIT
case SC_NET_MES_LEVELINIT:
//_____________________________________automatic custom global variables_________________
for (i=GVAR_USE_start;i<GVAR_USE_start+SC_ggi(GVAR_COUNT)+1;i++){ //custom global variables
SC_MP_Gvar_SetSynchro(i);
}
//_______________________________________________________________________________________
SC_MP_Gvar_SetSynchro(GVAR_KILLED);
SC_MP_Gvar_SetSynchro(GVAR_KILLER);
SC_MP_SRV_SetForceSide(0);
SC_MP_SRV_SetClassLimit(18,0);
SC_MP_SRV_SetClassLimit(19,0);
SC_MP_SRV_SetClassLimit(39,0);
SC_MP_GetSRVsettings(&SRVset);
for (i=0;i<6;i++){
SC_MP_SRV_SetClassLimit(i+1,SRVset.atg_class_limit[i]);
SC_MP_SRV_SetClassLimit(i+21,SRVset.atg_class_limit[i]);
}// for (i)
CLEAR(hudinfo);
hudinfo.title = 1098;
hudinfo.sort_by[0] = SC_HUD_MP_SORTBY_KILLS; //untested. reorder to change what takes precidence
hudinfo.sort_by[1] = SC_HUD_MP_SORTBY_DEATHS | SC_HUD_MP_SORT_DOWNUP;
hudinfo.sort_by[2] = SC_HUD_MP_SORTBY_PINGS | SC_HUD_MP_SORT_DOWNUP; //untested. remove SC_HUD to show hi pinger at top of list
hudinfo.pl_mask = SC_HUD_MP_PL_MASK_KILLS | SC_HUD_MP_PL_MASK_DEATHS | SC_HUD_MP_PL_MASK_CLASS;
hudinfo.use_sides = TRUE;
hudinfo.side_name[0] = 1010;
hudinfo.side_color[0] = 0x44008800; // was --> 0x440000ff; this changes the team HUD colour
hudinfo.side_name[1] = 1011; //untested. possable place VET variable
hudinfo.side_color[1] = 0x44ff0000; // was --> 0x44FFFF00; this changes the team HUD colour
//hudinfo.disableUSside = TRUE;
hudinfo.disableVCside = TRUE; //untested. show VC info in HUD
/*
switch( SC_ggi(SGI_DIFFICULTY) ){
case 0:
break;
case 3:
hudinfo.disableUSside = TRUE; // show VC info in HUD
break;
}
*/
//hudinfo.disableUSside = TRUE; //untested. show VC info in HUD
hudinfo.side_mask = SC_HUD_MP_SIDE_MASK_FRAGS;
SC_MP_HUD_SetTabInfo(&hudinfo);
SC_MP_AllowStPwD(TRUE);
SC_MP_AllowFriendlyFireOFF(TRUE);
SC_MP_SetItemsNoDisappear(TRUE); // untested. stops dropped items from disapearing.
SC_MP_SetChooseValidSides(1);
SC_sgi(GVAR_SERVER,0);
if (info->param2){
if (info->param1){// it's server
//____________
SC_sgi(GVAR_SERVER,1);//For object scripts
//____________
SC_MP_Gvar_SetSynchro(GVAR_GPHASE); //only server can update gphase now
SC_MP_GetSRVsettings(&SRVset);
gRecoverTime = SRVset.coop_respawn_time;
gRecoverLimit = SRVset.coop_respawn_limit;
if (SC_MP_GetAmmoBoxesEnabled()){
SC_MP_SRV_InitWeaponsRecovery(10000.0); // change to allow numbered weapons to be shown like in DM. time based 0.0f =never disapears.
}else{
SC_MP_SRV_InitWeaponsRecovery(-1.0);
}
gRecs = 0;
for (i=0;i<REC_MAX;i++){
sprintf(txt,REC_WPNAME_US,i);
if (SC_NET_FillRecover(&gRec[gRecs],txt)) gRecs++;
}
#if _GE_VERSION_ >= 133
i = REC_MAX - gRecs;
SC_MP_GetRecovers(SC_MP_RESPAWN_COOP,&gRec[gRecs],&i);
gRecs += i;
#endif
if (gRecs==0) SC_message("no US recover place defined!");
CLEAR(gRecTimer);
}// if (info->param1)
}//if (info->param2)
if (info->param1){
//!!! ++ Reinit AI - NEW
num = 64;
SC_MP_EnumPlayers(enum_pl, &num, SC_MP_ENUMPLAYER_SIDE_ALL);//SC_MP_ENUMPLAYER_SIDE_ALL is for US_AI and civilian_AI
for (i = 0; i < num; i++){
SC_P_ScriptMessage(enum_pl[i].id, SCM_MP_REINIT, 0);
//SC_message("SEND_message");
}
//-- Reinit AI - NEW
}
break;// SC_NET_MES_LEVELINIT
case SC_NET_MES_RENDERHUD:
switch(SC_ggi(GVAR_GPHASE)){
case GPHASE_DONE:
j = 1099; //1099 - "US ARMY WIN." #1096: #tee US ARMY WIN. ALL VIETCONG ELIMINATED. #1097: #tee US ARMY WIN. PILOT REACHED THE LZ.
witxt = SC_Wtxt(j);
SC_GetScreenRes(&sc_width,&sc_height);
val= sc_width - SC_Fnt_GetWidthW(witxt,1);
SC_Fnt_WriteW(val * 0.5f,15,witxt,1,0xffffffff);//0x44008800//0xffffffff
if(gPhase_timer > 0){
remaining_time=gPhase_timer;
}
else{
swprintf(wtxt,SC_AnsiToUni("LOADING NEXT MISSION", wtxt2));
}
val= sc_width - SC_Fnt_GetWidthW(wtxt,1);
break;
case GPHASE_FAILED:
swprintf(wtxt,SC_AnsiToUni("%S killed by %S", wtxt2),SC_P_GetName(SC_MP_GetPlofHandle(SC_ggi(GVAR_KILLED))),SC_P_GetName(SC_MP_GetPlofHandle(SC_ggi(GVAR_KILLER))));
//j = 1081; //1049 - "Vietcong win." #1095: #tee VIETCONG WIN. PILOT KILLED. #1081: #tee VIETCONG WIN. #2025: #tee Mission failed #7781: #tee Status: MISSION FAILED\n
witxt = SC_Wtxt(2025);
SC_GetScreenRes(&sc_width,&sc_height);
val= sc_width - SC_Fnt_GetWidthW(witxt,1);
SC_Fnt_WriteW(val * 0.5f,25,witxt,1,0xffff0000);
val= sc_width - SC_Fnt_GetWidthW(wtxt,1);
SC_Fnt_WriteW(val * 0.5f,50,wtxt,1,0xffff0000);
Coop_vc script with automatic global variable system (advanced)
details compared with original coop:
- added automatic global variable system
- added civilian option
- mission restart when civilian is killed by VC an message appears who killed civilian
- restart with fade
- switch to next map when mission done
- added sound for "mission FAILED"
- added sound for "mission DONE"
Spoiler:[ShowHide]
Code
// VIETCONG 1
// COOP_VC script (with automatic global variables for synchronized objects)
// Created by Ando
// v3.1
// NOTES:
// 1.1 - added global wariables system
// 1.2 - added variable for server (600) to detect server from object scripts
// 1.2 - new G-var system (object scripts counting g-vars to channel 601 )
// 1.4 - added mission objectives test
// 2.0 - successfully tested with L|DC-78
// 2.1 - added civilian option
// 2.1 - mission restart when civilian is killed by us an message apears who killed civilian
// 2.1 - "mission fail" restart with fast fade
// 2.1 - fade when mission restarts
// 2.2 - switch to next map when mission done
// 3.0 - TESTED WITH TEAM
// 3.1 - added sound for "mission FAILED"
// 3.1 - added sound for "mission DONE"
//
switch(info->message){
case SC_NET_MES_SERVER_TICK:
if (SRV_CheckEndRule(info->elapsed_time)) break;
for (j=0;j<4;j++)
for (i=0;i<gRecs;i++)
gRecTimer[i] -= info->elapsed_time;
if (gRecoverTime<0xffff){
gNextRecover -= info->elapsed_time;
if (gNextRecover<0.0f) gNextRecover = (float)gRecoverTime;
}// if (gRecoverTime<0xffff)
if (gAllNoAiRecover>0.0f){
gAllNoAiRecover -= info->elapsed_time;
if (gAllNoAiRecover<=0.0f)
SC_MP_RecoverAllNoAiPlayers();
break;
}// if (gAllNoAiRecover>0.0f)
else{
gAllNoAiRecover -= info->elapsed_time;
}
CLEAR(valid);
j = 64;
alldeath = FALSE;
if (SC_MP_EnumPlayers(enum_pl,&j,SC_MP_ENUMPLAYER_SIDE_ALL)){
alldeath = TRUE;
for (i=0;i<j;i++){
if (enum_pl[i].status==SC_MP_P_STATUS_INGAME){
if (enum_pl[i].side>1); //SC_message("coop script wrong side: %d",enum_pl[i].side);
else{
valid[enum_pl[i].side] = TRUE;
}
}
if ((enum_pl[i].side==1)&&(enum_pl[i].status==SC_MP_P_STATUS_INGAME)) alldeath = FALSE;
}// for (i)
//SC_message("Enum, v[0]: %d v[1]: %d alldeath: %d",valid[0],valid[1],alldeath);
}// if (SC_MP_EnumPlayers(enum_pl,&j,SC_MP_ENUMPLAYER_SIDE_ALL))
else SC_message("NoEnum");
if ((gPhase==GPHASE_GAME)&&(alldeath)&&(gPhase_timer<0.0f)){
if (gRecoverLimit==0){
// mission failed
//SC_Log(2,"Set GPHASE_FAILED");
gPhase = GPHASE_FAILED;
gPhase_timer = 5.0f;
}
else {
// recover unlimited
//SC_message("recover unlimited");
if ((gRecoverTime>=0xffff)&&(gAllNoAiRecover<-5.0f)){
gAllNoAiRecover = 4.0f;
}
}
}// if ((alldeath)&&(gRecoverTime>=0xffff))
else gAllNoAiRecover = 0.0f;
gValidSide0 = valid[1];
gPhase_timer -= info->elapsed_time;
switch(gPhase){
case GPHASE_BEGIN:
if (notincar){
notincar = FALSE;
}
if (gPhase_timer<0.0f)
if ((valid[0])&&(valid[1])){
gPhase_timer = 5.0f;
gPhase = GPHASE_GAME;
}
break;
case GPHASE_GAME:
if (gPhase_timer<0.0f)
if (!valid[0]){
gPhase = GPHASE_DONE;
gPhase_timer = 5.0f;
}// if (!valid[0])
break;
case GPHASE_DONE:
if (gPhase_timer<0.0f){ //wait before restart
SC_MP_LoadNextMap();
}
break;
case GPHASE_FAILED:
if (gPhase_timer<0.0f){//wait before restart
gPhase_timer = RESTART_TIMER;
gPhase = GPHASE_BEFORE_RESTART;
}
break;
case GPHASE_BEFORE_RESTART:
if (gPhase_timer<0.0f){ //wait before restart
gPhase = GPHASE_RESTARTING;
}
break;
case GPHASE_RESTARTING:
CLEAR(gRecTimer);
gNextRecover = 0.0f;
gTime = 0;
gPhase = GPHASE_BEGIN;
gPhase_timer = 5.0f;
gPhase_send = 0;
gValidSide0 = FALSE;
SC_MP_GetSRVsettings(&SRVset);
gRecoverTime = SRVset.coop_respawn_time;
gRecoverLimit = SRVset.coop_respawn_limit;
gAllNoAiRecover = 0.0f;
SC_MP_SRV_ClearPlsStats();
SC_MP_SRV_InitGameAfterInactive();
SC_MP_RecoverAllAiPlayers();
SC_MP_RecoverAllNoAiPlayers();
//SC_MP_RestartMission(); //restart // causing some truoble //using SC_NET_MES_LEVELINIT
//_________Reinit AI
num = 64;
SC_MP_EnumPlayers(enum_pl, &num, SC_MP_ENUMPLAYER_SIDE_ALL);//SC_MP_ENUMPLAYER_SIDE_ALL is for US_AI and civilian_AI
for (i = 0; i < num; i++){
SC_P_ScriptMessage(enum_pl[i].id, SCM_MP_REINIT, 0);
}
//_____________________
break;
}// switch(gPhase)
SRV_CheckUpdate();
break;
case SC_NET_MES_CLIENT_TICK:
switch(SC_ggi(GVAR_GPHASE)){
case GPHASE_BEGIN:
if (fade_off == FALSE){
SC_FadeTo(FALSE, FADE_TIME);
fade_off=TRUE;
}
break;
case GPHASE_GAME:
break;
case GPHASE_DONE:
if (sound_start==TRUE){
SC_SND_PlaySound2D(DONE_SOUND);
sound_start=FALSE;
}
break;
case GPHASE_FAILED:
if (sound_start==TRUE){
SC_SND_PlaySound2D(FAILED_SOUND);
sound_start=FALSE;
}
break;
case GPHASE_BEFORE_RESTART:
client_fade_timer -= info->elapsed_time;
if (client_fade_timer<FADE_TIME){
SC_FadeTo(TRUE, FADE_TIME);
fade_off=FALSE;
sound_start=TRUE;
client_fade_timer=RESTART_TIMER;
}
break;
case GPHASE_RESTARTING:
break;
}// switch(gPhase)
//SC_message(char *txt,...);
break;// SC_NET_MES_CLIENT_TICK
case SC_NET_MES_LEVELPREINIT:
client_fade_timer=RESTART_TIMER;
SC_sgi(GVAR_MP_MISSIONTYPE,10);//10 is for custom coop_vc
gEndRule = info->param1;
gEndValue = info->param2;
gTime = 0.0f;
SC_MP_EnableBotsFromScene(TRUE);
break;// SC_NET_MES_LEVELPREINIT
case SC_NET_MES_LEVELINIT:
//_____________________________________automatic custom global variables_________________
for (i=GVAR_USE_start;i<GVAR_USE_start+SC_ggi(GVAR_COUNT)+1;i++){ //custom global variables
SC_MP_Gvar_SetSynchro(i);
}
//_______________________________________________________________________________________
SC_MP_Gvar_SetSynchro(GVAR_KILLED);
SC_MP_Gvar_SetSynchro(GVAR_KILLER);
SC_MP_SRV_SetForceSide(1);
SC_MP_SetItemsNoDisappear(TRUE);
SC_MP_SRV_SetClassLimit(18,0);
SC_MP_SRV_SetClassLimit(19,0);
SC_MP_SRV_SetClassLimit(39,0);
SC_MP_GetSRVsettings(&SRVset);
for (i=0;i<6;i++){
SC_MP_SRV_SetClassLimit(i+1,SRVset.atg_class_limit[i]);
SC_MP_SRV_SetClassLimit(i+21,SRVset.atg_class_limit[i]);
}// for (i)
CLEAR(hudinfo);
hudinfo.title = 1098;
hudinfo.sort_by[0] = SC_HUD_MP_SORTBY_KILLS;
hudinfo.sort_by[1] = SC_HUD_MP_SORTBY_DEATHS | SC_HUD_MP_SORT_DOWNUP;
hudinfo.sort_by[2] = SC_HUD_MP_SORTBY_PINGS | SC_HUD_MP_SORT_DOWNUP;
hudinfo.pl_mask = SC_HUD_MP_PL_MASK_KILLS | SC_HUD_MP_PL_MASK_DEATHS | SC_HUD_MP_PL_MASK_CLASS;
hudinfo.use_sides = TRUE;
hudinfo.side_name[0] = 1010;
hudinfo.side_color[0] = 0x44008800;
hudinfo.side_name[1] = 1011;
hudinfo.side_color[1] = 0x44ff0000;
hudinfo.disableUSside = TRUE;
//hudinfo.disableVCside = TRUE;
hudinfo.side_mask = SC_HUD_MP_SIDE_MASK_FRAGS;
SC_MP_HUD_SetTabInfo(&hudinfo);
SC_MP_AllowStPwD(TRUE);
SC_MP_AllowFriendlyFireOFF(TRUE);
SC_MP_SetItemsNoDisappear(FALSE);
SC_MP_SetChooseValidSides(2);//This function will set the valid sides for the player to choose from. Use 0 for US only, 2 for VC, 3 for both.
SC_sgi(GVAR_SERVER,0);
if (info->param2){
if (info->param1){// it's server
//____________
SC_sgi(GVAR_SERVER,1);//For object scripts
//____________
SC_MP_Gvar_SetSynchro(GVAR_GPHASE);
SC_MP_GetSRVsettings(&SRVset);
gRecoverTime = SRVset.coop_respawn_time;
gRecoverLimit = SRVset.coop_respawn_limit;
if (SC_MP_GetAmmoBoxesEnabled()){
SC_MP_SRV_InitWeaponsRecovery(10000.0); // change to allow numbered weapons to be shown like in DM. time based 0.0f =never disapears.
}else{
SC_MP_SRV_InitWeaponsRecovery(-1.0);
}
gRecs = 0;
for (i=0;i<REC_MAX;i++){
sprintf(txt,REC_WPNAME_US,i);
if (SC_NET_FillRecover(&gRec[gRecs],txt)) gRecs++;
}
#if _GE_VERSION_ >= 133
i = REC_MAX - gRecs;
SC_MP_GetRecovers(100,&gRec[gRecs],&i);
gRecs += i;
#endif
if (gRecs==0) SC_message("no VC recover place defined!");
CLEAR(gRecTimer);
}// if (info->param1)
}//if (info->param2)
if (info->param1){
//!!! ++ Reinit AI - NEW
num = 64;
SC_MP_EnumPlayers(enum_pl, &num, SC_MP_ENUMPLAYER_SIDE_ALL);
for (i = 0; i < num; i++){
SC_P_ScriptMessage(enum_pl[i].id, SCM_MP_REINIT, 0);
}
//-- Reinit AI - NEW
}
break;// SC_NET_MES_LEVELINIT
case SC_NET_MES_RENDERHUD:
switch(SC_ggi(GVAR_GPHASE)){
case GPHASE_DONE:
j = 1049; //1049 - "Vietcong win." #1081: #tee VIETCONG WIN.
witxt = SC_Wtxt(j);
SC_GetScreenRes(&sc_width,&sc_height);
val= sc_width - SC_Fnt_GetWidthW(witxt,1);
SC_Fnt_WriteW(val * 0.5f,15,witxt,1,0xffffffff);//0x44008800//0xffffffff
if(gPhase_timer > 0){
remaining_time=gPhase_timer;
swprintf(wtxt,SC_AnsiToUni("LOAD NEXT MISSION after: %d sec.", wtxt2),(int)(remaining_time));
}
else{
swprintf(wtxt,SC_AnsiToUni("LOADING NEXT MISSION", wtxt2));
}
Wounded /coma / dead script
Description:
When player health is smaller than 10 % then it starts to go slowly worse (small damage after every second)
20 seconds before coma script show and count down seconds (recommendation by testers).
When player health is smaller than 1.5% then he fall down and can’t move (+small damage after every second)
When player health is smaller than 0.23% then he will die.
When player is healed then he will be fine again.
Tutorial for editor:
- add somewhere "killer.bes" object to map. It must use same name in editor ("killer")
- add somewhere dummy object to map and rename it to "view_helper"
- attach this script to "killer" object in level.c
- use only mode script with auto. sync.
Object
Object is attached to this post.
Spoiler:[ShowHide]
Code
// VIETCONG 1
// WOUNDED_COMA_DEAD script v3.1 (Writen for custom object - KILLER.BES)
// made by Ando
/*
______________DESCRIPTION:
MP synchronized player wounded/ coma/dead option.
When player health is smaller than 10 % then it starts to go slowly worse (small damage after every second)
20 seconds before coma script show and count down seconds (recommendation by testers).
When player health is smaller than 1.5% then he fall down and can’t move (+small damage after every second)
When player health is smaller than 0.23% then he will die.
______________TUTORIAL FOR EDITOR
This script must be added to custom object "killer.bes"
Add somewhere "killer.bes" object to map. It must use same name in editor ("killer")
Add somewhere dummy object to map and rename it to "view_helper"
Attach this script to "killer" object in level.c
This script is synchronized in multiplayer. You only must use mode script with Automatic sync. support.
Synchronization channel is added automatically
#define WOUNDED 20.0f //
#define COMA 3.0f //
#define DEAD 0.5f
#define WO_DAMAGE 0.15f // tamage per second
#define CO_DAMAGE 0.05f // tamage per second
#define INF_TIME 20 // show info when alive time is smaller than
trans=orig_trans_kill;// filling scale and rotation (later will add pos only)
trans_view=orig_trans_view;// filling scale and rotation (later will add pos only)
SC_NOD_SetTransform(kill_obj_id,&trans_hidden);
SC_NOD_SetTransform(view_obj_id,&trans_hidden);
w_phase=0;
break;
case SC_OBJ_INFO_EVENT_JUSTLOADED:
break;
case SC_OBJ_INFO_EVENT_RELEASE:
SC_NOD_SetTransform(kill_obj_id,&orig_trans_kill);
SC_NOD_SetTransform(view_obj_id,&orig_trans_view);
break;
case SC_OBJ_INFO_EVENT_HIT:
break;
case SC_OBJ_INFO_EVENT_DOTICK:
timer+=info->time;
if (start_dead == FALSE){// was killed by "KILL" object
player = SC_PC_Get();
SC_P_GetInfo(player,&pl_info);
if (SC_P_IsReady(player)== FALSE){//(pl_info.cur_hp<0.0f ){
SC_NOD_SetTransform(kill_obj_id,&trans_hidden); //hide a kill object again
start_dead = TRUE;
start_coma = TRUE;
start_wounded = TRUE;
}
}
if (timer>1){//check it
timer=0;
j = 64;
if (SC_MP_EnumPlayers(enum_pl,&j,SC_MP_ENUMPLAYER_SIDE_ALL)){
for (i=0;i<j;i++){
SC_P_GetInfo(enum_pl[i].id,&pl_info);
if(pl_info.member_id == 255){//PC //if (enum_pl[i].status==SC_MP_P_STATUS_INGAME){
pl_hp = pl_info.cur_hp;
player = SC_PC_Get();
if (enum_pl[i].id == player) {
if (pl_info.cur_hp < WOUNDED){//PC WOUNDED
if (pl_info.cur_hp < COMA ){
if (pl_info.cur_hp < 0.7f ){//killed by damage
if (pl_info.cur_hp < 0.0f ){//killed by damage
//_________________________DEAD_____________________________
}else{//_________________________KILL_____________________________
if (start_dead){//start kill state
SC_PC_EnableMovementAndLooking(TRUE);
SC_PC_PlayFpvAnim("g\\WEAPONS\\!DEFAULT\\STATIV_LIE.STG");//stop last looped anim
SC_P_GetPos(player,&pl_pos);
trans.loc=pl_pos;
SC_NOD_SetTransform(kill_obj_id,&trans);
pl_pos.z+=0.1;
SC_P_SetPos(player, &pl_pos);//move player up 0.1 m then he fall dawn and cause collision with "kill" object
SC_SetViewAnim(COMA_ANM, 0, 0, 0);//clear view anim
start_dead=FALSE;
}
}
}else{//_________________________PC COMA_____________________________
if (start_coma){//start coma state
SC_PC_EnableMovementAndLooking(FALSE);
if (SC_P_GetPhase(player)<1){
SC_P_SetPhase(player, 1.0f);
}
SC_P_SetSelWeapon(player, 0);//select first slot
SC_P_ChangeWeapon(player, 0, NULL);//remove knife//29 – US knife 30 – VC knife
SC_P_DoAnimLooped(player, "g\\characters\\anims\\A550_DEATHMOVE.STG");//A400 M-16 STAT LEH BM.STG // A550_DEATHMOVE.STG
SC_PC_PlayFpvLooped("g\\WEAPONS\\!DEFAULT\\STATIV_LIE.STG"); //STATIV_LIE.STG //HIDE_LIE.STG
start_coma=FALSE;
SC_P_GetPos(player,&pl_pos);
trans_view.loc = pl_pos;
SC_NOD_SetTransform(view_obj_id,&trans_view);
SC_SetViewAnimEx(COMA_ANM, 0, 1000, 0,view_obj_id );
SC_GameInfo(NULL, "You are too weak to move");
}
sprintf(txt, " %2.0f", ((pl_info.cur_hp-DEAD) / CO_DAMAGE));
SC_GameInfo(NULL, txt);
SC_P_SetHp(enum_pl[i].id, (pl_hp-CO_DAMAGE));//server must do a damage
}
}else{//PC_WOUNDED
if (start_wounded){//start coma state
SC_GameInfo(NULL, "Your health is worsening");
start_wounded=FALSE;
}else{
time_left=((pl_info.cur_hp - COMA) / WO_DAMAGE);
if (time_left <= INF_TIME ){
sprintf(txt, " %2.0f", time_left);
SC_GameInfo(NULL, txt);
}
}
SC_P_SetHp(enum_pl[i].id, (pl_hp-WO_DAMAGE));//server must do a damage
}
}
else{//_________________________PC not in coma
if (start_coma == FALSE){ //PC was incoma but now healed
SC_PC_EnableMovementAndLooking(TRUE);
SC_P_DoAnimLooped(player, NULL);//A400 M-16 STAT LEH BM.STG // A550_DEATHMOVE.STG
SC_PC_PlayFpvLooped(NULL);
SC_SetViewAnim(COMA_ANM, 0, 0, 0);//clear view anim
if (pl_info.side == 0) SC_P_ChangeWeapon(player, 0, 29);//remove knife//29 – US knife 30 – VC knife
if (pl_info.side == 1) SC_P_ChangeWeapon(player, 0, 30);//remove knife//29 – US knife 30 – VC knife
start_dead = TRUE;
start_coma = TRUE;
start_wounded = TRUE;
}
}
}
//_________________________ALL PLAYERS
if (pl_info.cur_hp < WOUNDED){
if (pl_info.cur_hp < COMA ){
if (pl_info.cur_hp < 0.7f ){//killed by damage
}else{//coma
if (SC_ggi(GVAR_SERVER) == 1){// sever
SC_P_SetHp(enum_pl[i].id, (pl_hp-CO_DAMAGE));//server must do a damage
}
//need do remove repeating it
not_in_list=TRUE;
for (k=0;k<10;k++){
if (pl_coma[k]==enum_pl[i].id) {//alreadi in list
not_in_list=FALSE;
break;// exit from "for"
}
}
if (not_in_list){
for (k=0;k<10;k++){
if (pl_coma[k]==0) {//free slot
pl_coma[k] = enum_pl[i].id;
SC_P_DoAnimLooped(enum_pl[i].id, "g\\characters\\anims\\A550_DEATHMOVE.STG");//A400 M-16 STAT LEH BM.STG // A550_DEATHMOVE.STG
break;// exit from "for"
}
}
}
}
}else{//wounded
if (SC_ggi(GVAR_SERVER) == 1){// sever
SC_P_SetHp(enum_pl[i].id, (pl_hp-WO_DAMAGE));//server must do a damage
}
}
}else{
for (k=0;k<10;k++){
if (pl_coma[k]==enum_pl[i].id) {
SC_P_DoAnimLooped(enum_pl[i].id, NULL); // end player animation loop for current PC
pl_coma[k]=0; //remove coma state for that plyer
break;// exit from "for"
}
}
}
}
}
}
}
break;
case SC_OBJ_INFO_EVENT_USED:
break;
}// switch(info->event_type)
return TRUE;
}// int ScriptMain(s_OBJ_info *info)
AI script with extra options Description:
- random ini file
- random weapon
- patrol ( on/off/follow to other AI PM)
- _move mode (walk, aim, run )
- _stand mode (stand, crouch, lie)
- _patrol loop ( on/off)
- _patrol order between bath waypoints (forward, backward, forward-backward, random )
- _automatically detect path waypoint count
- _waypoint object names
- __patrol follow to other player ( pointman id)
- __distance where AI stop following to PM
- __distance where AI continue following to PM
- __distance where AI run to follow to PM
- __right/left angle to aim (degrees from PM direction)
- _ distance where AI stop and look other AI/PC
- _ time how long AI look AI/PC near him
- _ time how long AI ignore AI/PC near him after look
Tutorial for editor:
AI is patrolling only in peace mode.
in editor rename waypoints what AI will pass during patrol ( it is working with "Dummy" objects to)
First number after name must be "0"
example 1:
"patrol_1#0"
"patrol_1#1"
"patrol_1#2"
"patrol_1#3"
...
in script, name for that way is "patrol_1#%d" ("%d" is for script, to replace it with numbers)
You can use any name.
Tip: Sometimes I double waypoint height, then is easier to find my patrol way objects later.
Add your AI near first point.
In game it will go to waypoint "patrol_1#0" > "patrol_1#1" > ....after last again to "patrol_1#0"
There is more options for points order and you see description behind "PATROL_ORDER"
You can add more players to this defined way.
You can add different way for every AI and don't forget to fix that name in script.
AI C file
copy that file to script folder of your map as much you need.
Spoiler:[ShowHide]
Code
// part of vc1 AI script
// created by Ando
//
#include <inc\sc_global.h>
#include <inc\sc_def.h>
//____________________________PATROL______________________________
#define PATROL 0 // 0 - disabled, 1 - normal patrol, 2- follow to player *
#define PATROL_MOVEMODE 0 //0-walk, 1-aim, 2- run
#define PATROL_MOVEMODE_2 0 //0-stand,1-crouch,2-LIE
#define PATROL_LOOPED TRUE
#define PATROL_ORDER 0 //0-forward, 1-backward, 2-forward-backward, 3-random
#define PATROL_POINTS 0 //if 0 then detecting automatically max objects with that(PATROL_OBJECTS) name
#define PATROL_OBJECTS "patrol_1#%d" //waypoint objects (patrol bath waipoint names what must start with end #0( example "patrol_1#0"))
//_____FOLLOW TO PLAYER___(in peace mode)
//only if PATROL = 2
#define PATROL_FOLLOW_TO 10 //player id (must be same side and same group as current player)
#define PATROL_STOP_DIST 2 //stop when dist is smaller than
#define PATROL_FOLLOW_DIST 5 //follow when dist is bigger than
#define PATROL_TOFAR_DIST 8 //run when too far
#define VIEW_ROT_FROM_PM 65.0f // angle in degrees( if 65 then AI will aim 65 degree right from pointman bath)
//_____________________________BEHAVIOUR NEAR OTHER PLAYER_________
#define LOOK_NEAREST_DIST 1.0f // AI will react when somebody is nearer than that ( AI will stop and look other player)
#define LOOK_NEAREST_TIME 3.0f // time what AI will look other player near him
#define LOOK_NEAREST_IGNORE 10.0f // ignore time after looking some player
//_________________________________________________________________
//_________________________________________________________________
//_________________________________________________________________
//__________________________________________________________CREATE CXX
#include <inc\ando\AI\Ando_AI_v2.cxx>
AI CXX file
put that file to "Vietcong\dev\compiler\inc\ando\AI\Ando_AI_v2.cxx"
Spoiler:[ShowHide]
Code
// CXX file for VC AI script
// created by Ando
/*
//_________________________C FILE_________________________
// part of vc1 AI script
// created by Ando
//
#include <inc\sc_global.h>
#include <inc\sc_def.h>
//____________________________PATROL______________________________
#define PATROL 0 // 0 - disabled, 1 - normal patrol, 2- follow to player *
#define PATROL_MOVEMODE 0 //0-walk, 1-aim, 2- run
#define PATROL_MOVEMODE_2 0 //0-stand,1-crouch,2-LIE
#define PATROL_LOOPED TRUE
#define PATROL_ORDER 0 //0-forward, 1-backward, 2-forward-backward, 3-random
#define PATROL_POINTS 0 //if 0 then detecting automatically max objects with that(PATROL_OBJECTS) name
#define PATROL_OBJECTS "patrol_1#%d" //waypoint objects (patrol bath waipoint names what must start with end #0( example "patrol_1#0"))
//_____FOLLOW TO PLAYER___(in peace mode)
//only if PATROL = 2
#define PATROL_FOLLOW_TO 10 //player id (must be same side and same group as current player)
#define PATROL_STOP_DIST 2 //stop when dist is smaller than
#define PATROL_FOLLOW_DIST 5 //follow when dist is bigger than
#define PATROL_TOFAR_DIST 8 //run when too far
#define VIEW_ROT_FROM_PM 65.0f // angle in degrees( if 65 then AI will aim 65 degree right from pointman bath)
//_____________________________BEHAVIOUR NEAR OTHER PLAYER_________
#define LOOK_NEAREST_DIST 1.0f // AI will react when somebody is nearer than that ( AI will stop and look other player)
#define LOOK_NEAREST_TIME 3.0f // time what AI will look other player near him
#define LOOK_NEAREST_IGNORE 10.0f // ignore time after looking some player
//_________________________________________________________________
//_________________________________________________________________
//_________________________________________________________________
//__________________________________________________________CREATE CXX
#include <inc\ando\AI\Ando_AI_v2.cxx>
//_________________________END OF C FILE_________________________
*/
void equipplayer(s_SC_P_CreateEqp *eqp, int *count){
int my_class;
#ifdef P_CLASS
my_class = CLASS
#else
my_class = rand()%5;
#endif
switch(my_class){
case 0:// _______________soldier_______________
//_________head gear
eqp[0].bes = "G\\Equipment\\US\\bes\\EOP_hlmt1US_v03.BES";
eqp[0].eqp = "G\\Equipment\\US\\eqp\\CUP_SFgncsldr01\\velka_polni\\EOP_hlmt1US_v03.eqp";
*count=1;
break;
case 1:// _______________engineer
break;
case 2:// _______________medic
break;
case 3:// _______________machinegunner
break;
case 4:// _______________radioman
break;
case 5:// _______________sniper
break;
}
}
dword my_PM_player;
int ScriptMain(s_SC_P_info *info){
s_SC_P_Create pinfo;
s_SC_P_CreateEqp eqp[10];
s_SC_P_AI_props props;
s_SC_P_getinfo plInfo;
c_Vector3 plPos;
dword i, j;
int eqpcount;
int patrol_back=1;
info->next_exe_time = 0.5f;
switch( info->message ){
case SC_P_MES_TIME:
timer+=info->elapsed_time;
if (SC_ggi(GVAR_MP_MISSIONTYPE)==P_EXIST_MODE){
switch( gPhase ){
case 0:
CLEAR(pinfo);
pinfo.type = SC_P_TYPE_AI;
pinfo.side = P_SIDE;
pinfo.group = P_GROUP;
pinfo.member_id = P_MEMBERID;
//props.max_vis_distance = 120 // maximum visual distance the AI can see, if not specified, AI uses maximum visual distance specified for the level.
//props.watchfulness_zerodist = 2 // how good is AI at recognizing the enemy at zero distance.
//props.watchfulness_maxdistance = 1 // how good is AI at recognizing the enemy at maximum distance.
//props.boldness = 1 // this is used to determine how bold is the AI when in cover and under fire. 0.5 is very cautious player, 2 is medium, 4 is high. 10 is almost suicidal, the AI will not give a damn if someone is shooting at him.
//props.coveramount = 0.5 // how far the AI will run for cover compared to the distance to the closest enemy, default is 0.5.
//props.hear_imprecision = 1 // imprecision of the AI’s hearing. 0 absolute hearing, 1 average, 5 very bad.
//props.hear_distance_mult = 1 // hear distance multiplier – 0.5 is half, 2 is two times better.
//props.hear_distance_max = 1000 // maximum hearing distance.
//props.grenade_min_distance; // minimal distance to throw grenade at (default: 10.0f)
//props.grenade_timing_imprecision = 2.5 // this is maximum time (will be randomized) between impact of the grenade and it’s explosion.
//props.grenade_throw_imprecision = 1 // imprecision of the grenade throwing. 0 perfect, 1 average, 2 quite bad.
//props.grenade_sure_time = 13.737358 // how long the AI will wait until it’s sure the situation demands a grenade.
//props.forget_enemy_mult = 1 // how fast will the AI forgot the enemies it has no more contact? 1 is default, 0.5 means two times slower, 2 mean two times faster.
//disable_peace_crouch = 0;//BOOL // this disables AI crouching in the peace mode.
//props.peace_fakeenemy_run = 1; // this is used to set the movement type under the fake enemy situation. 1 means always run, 0 always walk, 0.5 use run/walk 1:1.
//props.peace_fakeenemy_phase = 0.5 // same as previous, only for the stand/crouch.
//props.shoot_while_hidding = 0.3 // if enabled the AI will shoot even when moving to the hide out.
//props.aimtime_max = 0.7 // maximum time for AI to take an aim, default 0.7 seconds
//props.aimtime_canshoot = 0.1 // minimum time for AI to take an aim, default 0.1 seconds.
//props.aimtime_rotmult = 0.5 // multiplier of the rotation speed when aiming, default 0.5 seconds.
//props.wounded_start_perc = 0.5 // value of the current hp/max hp when the AI aiming starts to be worse
//props.wounded_aimtime_mult_max = 2 // multiplier for the maximum aim time when hit points of the AI is zero.
//props.wounded_shoot_imprec_plus = 0.5 // multiplier for the maximum aim imprecision when hit points of the AI is zero.
//props.shoot_imprecision = D0_SHOOT_PREC; //overload previous (default) setting
//props.shoot_damage_mult = 0.5f;
//props.grenade_throw_imprecision = 1.5f + frnd(0.5f);
switch( current_patrol ){
case 0://PATROL disabled
gPhase = 3;
break;
case 1://Normal PATROL
SC_P_Ai_SetMovePos(info->pl_id, PATROL_MOVEMODE_2); // test
gPhase = 2;
if (PATROL_POINTS==0){
patrol_obj_count=0;
for(i= 0; i < 20; i++){//count of objects
sprintf(txt, PATROL_OBJECTS, i);
if (SC_NOD_GetNoMessage_Entity(txt))patrol_obj_count++;
}
}else{
patrol_obj_count=PATROL_POINTS;
}
break;
case 2://Follow to player
SC_P_Ai_SetMovePos(info->pl_id, PATROL_MOVEMODE_2); // test
gPhase = 2;
//
if (PATROL_POINTS==0){
patrol_obj_count=0;
for(i= 0; i < 20; i++){//count of objects
sprintf(txt, PATROL_OBJECTS, i);
if (SC_NOD_GetNoMessage_Entity(txt))patrol_obj_count++;
}
}else{
patrol_obj_count=PATROL_POINTS;
}
break;
}
break;
case 2://__________________________________PATROL__________________________
if (SC_P_Ai_GetEnemies(info->pl_id) < 1) {//if (SC_P_Ai_GetDanger(info->pl_id) <= 0.001f) {
if (timer >= 0){//ready
switch( current_patrol ){
case 1://Normal PATROL
switch( Pendl_Phase ){
case 0://give task
if (cur_pendl_point== -1){//first start for normal or follower whos PM is dead
SC_message("1");
//search closest PATROL point
SC_P_GetPos(info->pl_id, &Pl_Pos);
for(i = 0; i < patrol_obj_count; i++){
SC_message("1 %d",i);
sprintf(txt, PATROL_OBJECTS, i);
SC_NOD_GetTransform(SC_NOD_GetNoMessage_Entity(txt),&trans);
Target_Pos=trans.loc;
cur_wp_dist = SC_2VectorsDist(&Pl_Pos, &Target_Pos);
if (cur_wp_dist < shortest_dist){
shortest_dist=cur_wp_dist;
cur_pendl_point=i;
}
}
}
sprintf(txt, PATROL_OBJECTS, cur_pendl_point);
SC_P_Ai_SetMode(info->pl_id, SC_P_AI_MODE_SCRIPT);
SC_P_Ai_SetMoveMode(info->pl_id, PATROL_MOVEMODE);
SC_NOD_GetTransform(SC_NOD_GetNoMessage_Entity(txt),&trans);
Target_Pos=trans.loc;
SC_P_Ai_Go(info->pl_id, &Target_Pos);
info->next_exe_time = 0.5f;//
Pendl_Phase=1;
break;
case 1://going
Last_pos=Pl_Pos;
SC_P_GetPos(info->pl_id, &Pl_Pos);
}else{//pointman is not alive
SC_P_GetInfo(my_PM_player, &plInfo);
if (plInfo.cur_hp<=0) {
current_patrol=1;//patrol type changed from "follow" to normal patrol. because PM is dead
return 1;
}
}
}
break;
}
}
}
else{
timer=-15;// switch to script mode after 15 sec of last seen enemy
SC_P_Ai_SetBattleMode(info->pl_id, SC_P_AI_BATTLEMODE_HOLD);//SC_P_AI_BATTLEMODE_HOLD SC_P_AI_BATTLEMODE_GOTO
SC_P_Ai_SetMode(info->pl_id, SC_P_AI_MODE_BATTLE);
}
break;
case 3://
info->next_exe_time = 3.0f;
break;
case 4://player killed
info->next_exe_time = 3.0f;
break;
}//switch( gPhase )
break; //case SC_P_MES_TIME:
}
else{
info->next_exe_time = 3.0f;//
}
case SC_P_MES_KILLED: