Synchronized Eyerok, add SSL to supported levels

Eyerok was synchronized, but I'm still not super pleased with the
result. I had to sacrifice dialog to prevent weird states and he's
completely controlled by the server. His synchronization should be
revisited in the future.

SSL should be fully synchronized now.
This commit is contained in:
MysterD 2020-09-30 18:20:13 -07:00
parent 356029abf6
commit 2f7d432143
9 changed files with 194 additions and 31 deletions

View File

@ -6380,6 +6380,7 @@ const BehaviorScript bhvEyerokBoss[] = {
ID(id_bhvEyerokBoss),
OR_INT(oFlags, (OBJ_FLAG_COMPUTE_ANGLE_TO_MARIO | OBJ_FLAG_COMPUTE_DIST_TO_MARIO | OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE)),
SET_HOME(),
CALL_NATIVE(bhv_eyerok_boss_init),
BEGIN_LOOP(),
CALL_NATIVE(bhv_eyerok_boss_loop),
END_LOOP(),

View File

@ -844,6 +844,8 @@
#define EYEROK_BOSS_ACT_SHOW_INTRO_TEXT 2
#define EYEROK_BOSS_ACT_FIGHT 3
#define EYEROK_BOSS_ACT_DIE 4
#define EYEROK_BOSS_ACT_DEAD 5
#define EYEROK_BOSS_ACT_PAUSE 6
/* Eyerok hand */
/* oAction */
@ -863,6 +865,8 @@
#define EYEROK_HAND_ACT_RECOVER 13
#define EYEROK_HAND_ACT_BECOME_ACTIVE 14
#define EYEROK_HAND_ACT_DIE 15
#define EYEROK_HAND_ACT_DEAD 16
#define EYEROK_HAND_ACT_PAUSE 17
/* Klepto */
/* oAction */

View File

@ -475,6 +475,7 @@
#define /*0x0F8*/ oEyerokReceivedAttack OBJECT_FIELD_S32(0x1C)
#define /*0x0FC*/ oEyerokHandUnkFC OBJECT_FIELD_S32(0x1D)
#define /*0x100*/ oEyerokHandUnk100 OBJECT_FIELD_S32(0x1E)
#define /*0x100*/ oEyerokHandDead OBJECT_FIELD_S32(0x1F)
/* Falling Pillar */
#define /*0x0F4*/ oFallingPillarPitchAcceleration OBJECT_FIELD_F32(0x1B)

View File

@ -11,14 +11,25 @@ if [ ! -f "$FILE" ]; then
FILE=./build/us_pc/sm64.us.f3dex2e
fi
# no debug, discord
#$FILE --discord 2 --configfile sm64config_server.txt &
#$FILE --discord 1 --configfile sm64config_client.txt &
#exit
# no debug, direct
#$FILE --server 27015 --configfile sm64config_server.txt &
#$FILE --client 127.0.0.1 27015 --configfile sm64config_client.txt &
#exit
# debug on server
#$FILE --client 127.0.0.1 27015 --configfile sm64config_client.txt &
#winpty cgdb $FILE -ex 'break debug_breakpoint_here' -ex 'run --server 27015 --configfile sm64config_server.txt' -ex 'quit'
#exit
###################
# debug on client #
###################
$FILE --server 27015 --configfile sm64config_server.txt &
# debug if cgdb exists

View File

@ -531,6 +531,7 @@ void bhv_snufit_loop(void);
void bhv_snufit_balls_loop(void);
void bhv_horizontal_grindel_init(void);
void bhv_horizontal_grindel_update(void);
void bhv_eyerok_boss_init(void);
void bhv_eyerok_boss_loop(void);
void bhv_eyerok_hand_loop(void);
void bhv_klepto_init(void);

View File

@ -11,29 +11,84 @@ struct ObjectHitbox sEyerokHitbox = {
};
s8 D_80331BA4[] = { 0, 1, 3, 2, 1, 0 };
static u8 eyerokBossImmediateUpdate = FALSE;
static s32 eyerok_check_mario_relative_z(s32 arg0) {
if (gMarioObject->oPosZ - o->oHomeZ < arg0) {
struct Object* player = nearest_player_to_object(o);
if (player->oPosZ - o->oHomeZ < arg0) {
return TRUE;
} else {
return FALSE;
}
}
static void eyerok_spawn_hand(s16 side, s32 model, const BehaviorScript *behavior) {
static struct Object* eyerok_spawn_hand(s16 side, s32 model, const BehaviorScript *behavior) {
struct Object *hand;
hand = spawn_object_relative_with_scale(side, -500 * side, 0, 300, 1.5f, o, model, behavior);
if (hand != NULL) {
hand->oFaceAngleYaw -= 0x4000 * side;
}
return hand;
}
void bhv_eyerok_boss_override_ownership(u8* shouldOverride, u8* shouldOwn) {
*shouldOverride = TRUE;
*shouldOwn = (gNetworkType == NT_SERVER);
}
u8 bhv_eyerok_boss_ignore_if_true(void) {
return network_owns_object(o);
}
void bhv_eyerok_boss_init(void) {
struct Object* hands[2];
hands[0] = eyerok_spawn_hand(-1, MODEL_EYEROK_LEFT_HAND, bhvEyerokHand);
hands[1] = eyerok_spawn_hand(1, MODEL_EYEROK_RIGHT_HAND, bhvEyerokHand);
struct SyncObject* so = network_init_object(o, 4000.0f);
so->override_ownership = bhv_eyerok_boss_override_ownership;
so->ignore_if_true = bhv_eyerok_boss_ignore_if_true;
so->minUpdateRate = 1.0f;
so->maxUpdateRate = 1.0f;
so->syncDeathEvent = FALSE;
network_init_object_field(o, &o->oEyerokBossNumHands);
network_init_object_field(o, &o->oEyerokBossUnkFC);
network_init_object_field(o, &o->oEyerokBossActiveHand);
network_init_object_field(o, &o->oEyerokBossUnk104);
network_init_object_field(o, &o->oEyerokBossUnk108);
network_init_object_field(o, &o->oEyerokBossUnk10C);
network_init_object_field(o, &o->oEyerokBossUnk110);
network_init_object_field(o, &o->oEyerokBossUnk1AC);
for (int i = 0; i < 2; i++) {
network_init_object_field(o, &hands[i]->oPosX);
network_init_object_field(o, &hands[i]->oPosY);
network_init_object_field(o, &hands[i]->oPosZ);
network_init_object_field(o, &hands[i]->oVelX);
network_init_object_field(o, &hands[i]->oVelY);
network_init_object_field(o, &hands[i]->oVelZ);
network_init_object_field(o, &hands[i]->oForwardVel);
network_init_object_field(o, &hands[i]->oAction);
network_init_object_field(o, &hands[i]->oPrevAction);
network_init_object_field(o, &hands[i]->oTimer);
network_init_object_field(o, &hands[i]->oHealth);
network_init_object_field(o, &hands[i]->oEyerokHandWakeUpTimer);
network_init_object_field(o, &hands[i]->oEyerokReceivedAttack);
network_init_object_field(o, &hands[i]->oEyerokHandUnkFC);
network_init_object_field(o, &hands[i]->oEyerokHandUnk100);
network_init_object_field(o, &hands[i]->oFaceAngleYaw);
network_init_object_field(o, &hands[i]->oMoveAngleYaw);
network_init_object_field(o, &hands[i]->oGravity);
network_init_object_field(o, &hands[i]->oAnimState);
}
}
static void eyerok_boss_act_sleep(void) {
struct Object* player = nearest_player_to_object(o);
int distanceToPlayer = dist_between_objects(o, player);
if (o->oTimer == 0) {
eyerok_spawn_hand(-1, MODEL_EYEROK_LEFT_HAND, bhvEyerokHand);
eyerok_spawn_hand(1, MODEL_EYEROK_RIGHT_HAND, bhvEyerokHand);
} else if (o->oDistanceToMario < 500.0f) {
} else if (distanceToPlayer < 500.0f) {
cur_obj_play_sound_2(SOUND_OBJ_EYEROK_EXPLODE);
o->oAction = EYEROK_BOSS_ACT_WAKE_UP;
}
@ -65,14 +120,20 @@ static void eyerok_boss_act_wake_up(void) {
u8 eyerok_boss_act_show_intro_text_continue_dialog(void) { return o->oAction == EYEROK_BOSS_ACT_SHOW_INTRO_TEXT; }
static void eyerok_boss_act_show_intro_text(void) {
if (cur_obj_update_dialog_with_cutscene(&gMarioStates[0], 2, 0, CUTSCENE_DIALOG, DIALOG_117, eyerok_boss_act_show_intro_text_continue_dialog)) {
// todo: get dialog working again
/*struct MarioState* marioState = nearest_mario_state_to_object(o);
if (should_start_or_continue_dialog(marioState, o) && cur_obj_update_dialog_with_cutscene(&gMarioStates[0], 2, 0, CUTSCENE_DIALOG, DIALOG_117, eyerok_boss_act_show_intro_text_continue_dialog)) {
o->oAction = EYEROK_BOSS_ACT_FIGHT;
}
network_send_object_reliability(o, TRUE);
}*/
o->oAction = EYEROK_BOSS_ACT_FIGHT;
}
static void eyerok_boss_act_fight(void) {
if (o->oEyerokBossNumHands == 0) {
o->oAction = EYEROK_BOSS_ACT_DIE;
if (network_owns_object(o)) {
o->oAction = EYEROK_BOSS_ACT_DIE;
}
} else if (o->oEyerokBossUnk1AC == 0 && o->oEyerokBossActiveHand == 0) {
if (o->oEyerokBossUnk104 != 0) {
if (approach_f32_ptr(&o->oEyerokBossUnk110, 1.0f, 0.02f)) {
@ -108,7 +169,8 @@ static void eyerok_boss_act_fight(void) {
o->oEyerokBossUnk108 = 1.0f;
}
o->oEyerokBossUnk10C = gMarioObject->oPosZ;
struct Object* player = nearest_player_to_object(o);
o->oEyerokBossUnk10C = player->oPosZ;
clamp_f32(&o->oEyerokBossUnk10C, o->oPosZ + 400.0f, o->oPosZ + 1600.0f);
} else if ((o->oEyerokBossActiveHand = o->oEyerokBossUnkFC & 0x1) == 0) {
o->oEyerokBossActiveHand = -1;
@ -120,8 +182,10 @@ static void eyerok_boss_act_fight(void) {
u8 eyerok_boss_act_die_continue_dialog(void) { return o->oAction == EYEROK_BOSS_ACT_DIE; }
static void eyerok_boss_act_die(void) {
// todo: get dialog working again
/*struct MarioState* marioState = nearest_mario_state_to_object(o);
if (o->oTimer == 60) {
if (cur_obj_update_dialog_with_cutscene(&gMarioStates[0], 2, 0, CUTSCENE_DIALOG, DIALOG_118, eyerok_boss_act_die_continue_dialog)) {
if (should_start_or_continue_dialog(marioState, o) && cur_obj_update_dialog_with_cutscene(&gMarioStates[0], 2, 0, CUTSCENE_DIALOG, DIALOG_118, eyerok_boss_act_die_continue_dialog)) {
spawn_default_star(0.0f, -900.0f, -3700.0f);
} else {
o->oTimer -= 1;
@ -129,10 +193,21 @@ static void eyerok_boss_act_die(void) {
} else if (o->oTimer > 120) {
stop_background_music(SEQUENCE_ARGS(4, SEQ_EVENT_BOSS));
obj_mark_for_deletion(o);
}*/
stop_background_music(SEQUENCE_ARGS(4, SEQ_EVENT_BOSS));
if (network_owns_object(o)) {
spawn_default_star(0.0f, -900.0f, -3700.0f);
network_send_object_reliability(o, TRUE);
}
o->oAction = EYEROK_BOSS_ACT_DEAD;
}
void bhv_eyerok_boss_loop(void) {
if (o->oAction == EYEROK_BOSS_ACT_DEAD) {
return;
}
s16 oldAction = o->oAction;
switch (o->oAction) {
case EYEROK_BOSS_ACT_SLEEP:
eyerok_boss_act_sleep();
@ -148,15 +223,30 @@ void bhv_eyerok_boss_loop(void) {
break;
case EYEROK_BOSS_ACT_DIE:
eyerok_boss_act_die();
break;
return;
}
if (o->oAction != oldAction) {
if (network_owns_object(o->parentObj)) {
eyerokBossImmediateUpdate = TRUE;
} else {
o->oAction = EYEROK_BOSS_ACT_PAUSE;
}
}
if (eyerokBossImmediateUpdate && network_owns_object(o)) {
eyerokBossImmediateUpdate = FALSE;
network_send_object(o);
}
}
static s32 eyerok_hand_check_attacked(void) {
if (o->oEyerokReceivedAttack != 0 && abs_angle_diff(o->oAngleToMario, o->oFaceAngleYaw) < 0x3000) {
struct Object* player = nearest_player_to_object(o);
int angleToPlayer = obj_angle_to_object(o, player);
if (o->oEyerokReceivedAttack != 0 && abs_angle_diff(angleToPlayer, o->oFaceAngleYaw) < 0x3000) {
cur_obj_play_sound_2(SOUND_OBJ2_EYEROK_SOUND_SHORT);
if (--o->oHealth >= 2) {
if (--o->oHealth >= 2 || !network_owns_object(o->parentObj)) {
o->oAction = EYEROK_HAND_ACT_ATTACKED;
o->oVelY = 30.0f;
} else {
@ -210,6 +300,8 @@ static void eyerok_hand_act_sleep(void) {
}
static void eyerok_hand_act_idle(void) {
struct Object* player = nearest_player_to_object(o);
int angleToPlayer = obj_angle_to_object(o, player);
cur_obj_init_animation_with_sound(2);
if (o->parentObj->oAction == EYEROK_BOSS_ACT_FIGHT) {
@ -222,17 +314,17 @@ static void eyerok_hand_act_idle(void) {
if (o->parentObj->oEyerokBossActiveHand == o->oBehParams2ndByte) {
if (eyerok_check_mario_relative_z(400) != 0 || random_u16() % 2 != 0) {
o->oAction = EYEROK_HAND_ACT_TARGET_MARIO;
o->oMoveAngleYaw = o->oAngleToMario;
o->oMoveAngleYaw = angleToPlayer;
o->oGravity = 0.0f;
} else {
o->oAction = EYEROK_HAND_ACT_FIST_PUSH;
if (o->parentObj->oPosX - gMarioObject->oPosX < 0.0f) {
if (o->parentObj->oPosX - player->oPosX < 0.0f) {
o->oMoveAngleYaw = -0x800;
} else {
o->oMoveAngleYaw = 0x800;
}
o->oMoveAngleYaw += o->oAngleToMario;
o->oMoveAngleYaw += angleToPlayer;
o->oGravity = -4.0f;
}
} else {
@ -245,6 +337,8 @@ static void eyerok_hand_act_idle(void) {
}
static void eyerok_hand_act_open(void) {
struct Object* player = nearest_player_to_object(o);
int angleToPlayer = obj_angle_to_object(o, player);
s16 sp1E;
o->parentObj->oEyerokBossUnk1AC = o->oBehParams2ndByte;
@ -257,7 +351,7 @@ static void eyerok_hand_act_open(void) {
o->collisionData = segmented_to_virtual(ssl_seg7_collision_070282F8);
if (o->parentObj->oEyerokBossNumHands != 2) {
sp1E = o->oAngleToMario;
sp1E = angleToPlayer;
clamp_s16(&sp1E, -0x3000, 0x3000);
o->oMoveAngleYaw = sp1E;
o->oForwardVel = 50.0f;
@ -269,6 +363,8 @@ static void eyerok_hand_act_open(void) {
}
static void eyerok_hand_act_show_eye(void) {
struct Object* player = nearest_player_to_object(o);
int angleToPlayer = obj_angle_to_object(o, player);
UNUSED s16 val06;
cur_obj_init_animation_with_sound(5);
@ -279,7 +375,7 @@ static void eyerok_hand_act_show_eye(void) {
if (o->oAnimState < 3) {
o->oAnimState += 1;
} else if (cur_obj_check_if_near_animation_end()) {
val06 = (s16)(o->oAngleToMario - o->oFaceAngleYaw) * o->oBehParams2ndByte;
val06 = (s16)(angleToPlayer - o->oFaceAngleYaw) * o->oBehParams2ndByte;
o->oAction = EYEROK_HAND_ACT_CLOSE;
}
} else {
@ -296,7 +392,7 @@ static void eyerok_hand_act_show_eye(void) {
if (o->parentObj->oEyerokBossNumHands != 2) {
obj_face_yaw_approach(o->oMoveAngleYaw, 0x800);
if (o->oTimer > 10
&& (o->oPosZ - gMarioObject->oPosZ > 0.0f || (o->oMoveFlags & OBJ_MOVE_HIT_EDGE))) {
&& (o->oPosZ - player->oPosZ > 0.0f || (o->oMoveFlags & OBJ_MOVE_HIT_EDGE))) {
o->parentObj->oEyerokBossActiveHand = 0;
o->oForwardVel = 0.0f;
}
@ -343,11 +439,23 @@ static void eyerok_hand_act_become_active(void) {
}
}
static void eyerok_hand_act_die_event(void) {
if (o->oEyerokHandDead) { return; }
o->oEyerokHandDead = TRUE;
s16 activeFlags = o->activeFlags;
obj_explode_and_spawn_coins(150.0f, 1);
o->activeFlags = activeFlags;
cur_obj_disable();
create_sound_spawner(SOUND_OBJ2_EYEROK_SOUND_LONG);
}
static void eyerok_hand_act_die(void) {
if (cur_obj_init_anim_and_check_if_end(1)) {
o->parentObj->oEyerokBossUnk1AC = 0;
obj_explode_and_spawn_coins(150.0f, 1);
create_sound_spawner(SOUND_OBJ2_EYEROK_SOUND_LONG);
eyerok_hand_act_die_event();
o->oAction = EYEROK_HAND_ACT_DEAD;
}
if (o->oMoveFlags & OBJ_MOVE_MASK_ON_GROUND) {
@ -380,7 +488,9 @@ static void eyerok_hand_act_retreat(void) {
}
static void eyerok_hand_act_target_mario(void) {
if (eyerok_check_mario_relative_z(400) != 0 || o->oPosZ - gMarioObject->oPosZ > 0.0f
struct Object* player = nearest_player_to_object(o);
int angleToPlayer = obj_angle_to_object(o, player);
if (eyerok_check_mario_relative_z(400) != 0 || o->oPosZ - player->oPosZ > 0.0f
|| o->oPosZ - o->parentObj->oPosZ > 1700.0f || absf(o->oPosX - o->parentObj->oPosX) > 900.0f
|| (o->oMoveFlags & OBJ_MOVE_HIT_WALL)) {
o->oForwardVel = 0.0f;
@ -390,11 +500,14 @@ static void eyerok_hand_act_target_mario(void) {
} else {
obj_forward_vel_approach(50.0f, 5.0f);
approach_f32_ptr(&o->oPosY, o->oHomeY + 300.0f, 20.0f);
cur_obj_rotate_yaw_toward(o->oAngleToMario, 4000);
cur_obj_rotate_yaw_toward(angleToPlayer, 4000);
}
}
static void eyerok_hand_act_smash(void) {
struct Object* player = nearest_player_to_object(o);
int distanceToPlayer = dist_between_objects(o, player);
int angleToPlayer = obj_angle_to_object(o, player);
s16 sp1E;
if (o->oTimer > 20) {
@ -403,10 +516,10 @@ static void eyerok_hand_act_smash(void) {
eyerok_hand_pound_ground();
o->oGravity = -4.0f;
} else {
sp1E = abs_angle_diff(o->oFaceAngleYaw, o->oAngleToMario);
if (o->oDistanceToMario < 300.0f && sp1E > 0x2000 && sp1E < 0x6000) {
sp1E = abs_angle_diff(o->oFaceAngleYaw, angleToPlayer);
if (distanceToPlayer < 300.0f && sp1E > 0x2000 && sp1E < 0x6000) {
o->oAction = EYEROK_HAND_ACT_FIST_SWEEP;
if ((s16)(o->oFaceAngleYaw - o->oAngleToMario) < 0) {
if ((s16)(o->oFaceAngleYaw - angleToPlayer) < 0) {
o->oMoveAngleYaw = 0x4000;
} else {
o->oMoveAngleYaw = -0x4000;
@ -422,11 +535,12 @@ static void eyerok_hand_act_smash(void) {
}
static void eyerok_hand_act_fist_push(void) {
if (o->oTimer > 5 && (o->oPosZ - gMarioObject->oPosZ > 0.0f || (o->oMoveFlags & OBJ_MOVE_HIT_EDGE))) {
struct Object* player = nearest_player_to_object(o);
if (o->oTimer > 5 && (o->oPosZ - player->oPosZ > 0.0f || (o->oMoveFlags & OBJ_MOVE_HIT_EDGE))) {
o->oAction = EYEROK_HAND_ACT_FIST_SWEEP;
o->oForwardVel = 0.0f;
if (o->oPosX - gMarioObject->oPosX < 0.0f) {
if (o->oPosX - player->oPosX < 0.0f) {
o->oMoveAngleYaw = 0x4000;
} else {
o->oMoveAngleYaw = -0x4000;
@ -492,6 +606,12 @@ static void eyerok_hand_act_double_pound(void) {
}
void bhv_eyerok_hand_loop(void) {
if (o->oAction == EYEROK_HAND_ACT_DEAD) {
eyerok_hand_act_die_event();
return;
}
s16 oldAction = o->oAction;
o->header.gfx.scale[0] = 1.5f;
if (o->oAction == EYEROK_HAND_ACT_SLEEP) {
@ -545,6 +665,8 @@ void bhv_eyerok_hand_loop(void) {
case EYEROK_HAND_ACT_DIE:
eyerok_hand_act_die();
break;
case EYEROK_HAND_ACT_PAUSE:
break;
}
o->oEyerokReceivedAttack = obj_check_attacks(&sEyerokHitbox, o->oAction);
@ -553,4 +675,12 @@ void bhv_eyerok_hand_loop(void) {
load_object_collision_model();
o->header.gfx.scale[0] = 1.5f * o->oBehParams2ndByte;
if (o->oAction != oldAction) {
if (network_owns_object(o->parentObj)) {
eyerokBossImmediateUpdate = TRUE;
} else {
o->oAction = EYEROK_HAND_ACT_PAUSE;
}
}
}

View File

@ -303,7 +303,7 @@ void render_hud_unsupported_level(void) {
case COURSE_BBH: // (5) Big Boo's Haunt
//case COURSE_HMC: // (6) Hazy Maze Cave
case COURSE_LLL: // (7) Lethal Lava Land
//case COURSE_SSL: // (8) Shifting Sand Land
case COURSE_SSL: // (8) Shifting Sand Land
//case COURSE_DDD: // (9) Dire Dire Docks
//case COURSE_SL: // (10) Snowman's Land
//case COURSE_WDW: // (11) Wet Dry World

View File

@ -53,6 +53,7 @@ struct SyncObject {
bool keepRandomSeed;
bool syncDeathEvent;
bool hasStandardFields;
float minUpdateRate;
float maxUpdateRate;
u8 (*ignore_if_true)(void);
void (*on_received_pre)(u8 fromLocalIndex);

View File

@ -64,7 +64,8 @@ struct SyncObject* network_init_object(struct Object *o, float maxSyncDistance)
so->fullObjectSync = false;
so->keepRandomSeed = false;
so->hasStandardFields = (maxSyncDistance >= 0);
so->maxUpdateRate = 0;
so->minUpdateRate = 0.33f;
so->maxUpdateRate = 0.00f;
so->ignore_if_true = NULL;
so->on_received_pre = NULL;
so->on_received_post = NULL;
@ -85,6 +86,19 @@ void network_init_object_field(struct Object *o, void* field) {
bool network_owns_object(struct Object* o) {
struct SyncObject* so = &gSyncObjects[o->oSyncID];
if (so == NULL) { return false; }
// check for override
u8 shouldOverride = FALSE;
u8 shouldOwn = FALSE;
if (so->override_ownership != NULL) {
extern struct Object* gCurrentObject;
struct Object* tmp = gCurrentObject;
gCurrentObject = so->o;
so->override_ownership(&shouldOverride, &shouldOwn);
gCurrentObject = tmp;
if (shouldOverride) { return shouldOwn; }
}
return so->owned;
}
@ -452,7 +466,7 @@ void network_update_objects(void) {
// set max and min update rate
if (so->maxUpdateRate > 0 && updateRate < so->maxUpdateRate) { updateRate = so->maxUpdateRate; }
if (updateRate < 0.33f) { updateRate = 0.33f; }
if (updateRate < so->minUpdateRate) { updateRate = so->minUpdateRate; }
// see if we should update
float timeSinceUpdate = ((float)clock() - (float)so->clockSinceUpdate) / (float)CLOCKS_PER_SEC;