///////////////////////// robot.sgs ////////////////////////////// // ROBOT COMPONENT // - physics // - rendering // - attachments function Robot_init( core_mesh, pos ) { this. { attachments = [], inventory = [], position = vec3(pos.x,pos.y,pos.z), matrix = mat4(), movedir = vec2(0,0), turndir = vec2(1,0), elevation = 0.5, mi_core = mi_core = gSGR_Scene.createMeshInstance(), body = null, }; this.matrix.scale(0.5,0.5,0.5).translate_v3( this.position ); mi_core.matrix = this.matrix; mi_core.mesh = gSGR_GetMesh( core_mesh ); sh_capsuleZ = Bullet_CreateSphereShape( 0.5 ); rbci = Bullet_CreateRigidBodyCreationInfo(); rbci.collisionShape = sh_capsuleZ; rbci.position = this.position; rbci.mass = 120; rbci.localInertia = sh_capsuleZ.calculateLocalInertia( 120 ) * vec3(0,0,1); rbci.friction = 0.1; this.body = body = Bullet_CreateRigidBody( rbci ); body.activationState = Bullet_DISABLE_DEACTIVATION; body.linearDamping = 0.5; gSGR_BulletWorld.addRigidBody( body, 0x04 ); } function Robot_destroy() { gSGR_BulletWorld.removeRigidBody( this.body ); } function Robot_tick( dt ) { movedir = this.movedir; this.body.clearForces(); this.body.applyCentralImpulse( vec3(movedir.x,movedir.y,0) * 50 ); this.position = this.body.position; this.mi_core.matrix = this.matrix = mat4().scale(0.5,0.5,0.5).rotate_quat( this.body.orientation.invert() ).translate_v3( this.position ); foreach( atch : this.attachments ) { atch.tick( this, dt ); } } function Robot_setMoveDir( movedir ){ this.movedir = movedir; } function Robot_setTurnDir( turndir ){ this.turndir = turndir; } function Robot_setElevation( elev ){ this.elevation = elev; } function Robot_addAttachment( code ) { atch_func = Robot_Attachments.(code); atch = this!atch_func(); this.attachments.push( atch ); } function Robot_dropAttachments( type ) { foreach( i, atch : this.attachments ) { if( atch.type == type ) { // this!Robot_createAttachmentEntity( atch ); // TODO this.attachments[ i ] = null; } } this.attachments = array_filter( this.attachments ); } function Robot_setAttachment( code ) { if( code.length > 0 ) this!Robot_dropAttachments( code[0] ); if( code.length > 1 ) this!Robot_addAttachment( code ); } global Robot_Attachments = {}; function Robot_Attachments.EP1() { EP1 = { type = "E", name = "EP1", fullname = "Elevation, propeller-based, v1", mi_stat = mi_stat = gSGR_Scene.createMeshInstance(), mi_rot = mi_rot = gSGR_Scene.createMeshInstance(), }; mi_stat.mesh = gSGR_GetMesh( "sb_EP1_stat" ); mi_rot.mesh = gSGR_GetMesh( "sb_EP1_rot" ); function EP1.transform( mtx ) { this.mi_stat.matrix = mat4().translate( 0, 0, -0.67 ).multiply( mtx ); this.mi_rot.matrix = mat4().rotateZ( ftime() ).translate( 0, 0, -0.67 ).multiply( mtx ); } global Robot_EP1_offsets = [ vec3( 0, 0, 0 ), vec3( -1, 0, 0 ), vec3( 1, 0, 0 ), vec3( 0, -1, 0 ), vec3( 0, 1, 0 ) ]; function EP1.tick( robot, dt ) { this.transform( robot.matrix ); pow_dir = vec3( 0, 0, -5 -15 * robot.elevation ); pow_pos = robot.position + vec3( 0, 0, -0.17 ); avgdist = 0; foreach( off : Robot_EP1_offsets ) { (rr,cs,rn,rp) = gSGR_BulletWorld.rayTestClosest( pow_pos, pow_pos + pow_dir, 0x01, 0x01 ); avgdist += rr ?? 1.0; } powermul = 0.2 - avgdist / Robot_EP1_offsets.size; // htdiff = 5 - robot.body.position.z; // robot.body.applyCentralImpulse( vec3(0,0,htdiff) * 50 - robot.body.linearVelocity * 0.9 ); if( powermul > 0 ) robot.body.applyCentralImpulse( -pow_dir * powermul * 2000 * dt - robot.body.linearVelocity * 0.99 ); // if( powermul > 0 ) // robot.body.applyCentralForce( -pow_dir * ( 120 + powermul * 50 ) ); } return EP1; } function Robot_Attachments.SP1() { SP1 = { type = "S", name = "SP1", fullname = "Steering, propeller-based, v1", mi_statL = mi_statL = gSGR_Scene.createMeshInstance(), mi_statR = mi_statR = gSGR_Scene.createMeshInstance(), mi_rotL = mi_rotL = gSGR_Scene.createMeshInstance(), mi_rotR = mi_rotR = gSGR_Scene.createMeshInstance(), }; mi_statL.mesh = gSGR_GetMesh( "sb_SP1_lft" ); mi_statR.mesh = gSGR_GetMesh( "sb_SP1_rgt" ); mi_rotR.mesh = mi_rotL.mesh = gSGR_GetMesh( "sb_SP1_rot" ); function SP1.transform( mtx ) { this.mi_statL.matrix = mat4().translate( 1.90796, 0.12344, 0.04181 ).multiply( mtx ); this.mi_rotL.matrix = mat4().rotateY( ftime() ).translate( 1.96693, 0.12344, 0.04181 ).multiply( mtx ); this.mi_statR.matrix = mat4().translate( -1.90796, 0.12344, 0.04181 ).multiply( mtx ); this.mi_rotR.matrix = mat4().rotateY( ftime() ).translate( -1.90796, 0.12344, 0.04181 ).multiply( mtx ); } function SP1.tick( robot, dt ) { this.transform( robot.matrix ); vcur = vec2( robot.body.orientation.invert().mat3.transform( vec3(0,-1,0) ) ); vtgt = robot.turndir; powermul = acos( min( 1, vec2_dot( vcur, vtgt ) ) ) * if( vcur.x * vtgt.y - vtgt.x * vcur.y > 0, 1, -1 ); robot.body.applyTorqueImpulse( vec3(0,0,powermul*3 - robot.body.angularVelocity.z * 0.99) ); } return SP1; } function Robot_Attachments.WT1() { WT1 = { type = "W", name = "WT1", fullname = "Weapon, turret, v1", mi_stat = mi_stat = gSGR_Scene.createMeshInstance(), mi_rot = mi_rot = gSGR_Scene.createMeshInstance(), }; mi_stat.mesh = gSGR_GetMesh( "sb_WT1_stat" ); mi_rot.mesh = gSGR_GetMesh( "sb_WT1_rot" ); function WT1.transform( mtx ) { this.mi_stat.matrix = mat4().translate( 0, -0.40267, 0.63235 ).multiply( mtx ); this.mi_rot.matrix = mat4().translate( 0, -0.22267, 1.03222 ).multiply( mtx ); } function WT1.tick( robot, dt ) { this.transform( robot.matrix ); } return WT1; } ///////////////////////// player.sgs ////////////////////////// function ENTITY_CREATE_player( params ) { Player = { direction = @params.direction.normalized || vec3( 0, 1, 0 ), camera = null, cam_angle = 0.0, cam_zangle = 0.0, cam_ignoreOnce = true, move_noclip = false, health = 20, hint_text = null, hint_time = 0, use_info = [], use_index = null, tgt_elevation = 0.5, elev_change_timeout = 0, }; Player.cam_angle = vec2(Player.direction.x,Player.direction.y).angle; Player!Robot_init( "sb_core", params.position ); Player!Robot_addAttachment( "EP1" ); Player!Robot_addAttachment( "SP1" ); Player!Robot_addAttachment( "WT1" ); gSGR_Actions.add_action( "move_fwd" ); gSGR_Actions.add_action( "move_lft" ); gSGR_Actions.add_action( "move_bwd" ); gSGR_Actions.add_action( "move_rgt" ); gSGR_Actions.add_action( "enable_noclip" ); gSGR_Actions.add_action( "elev_raise" ); gSGR_Actions.add_action( "elev_lower" ); gSGR_Actions.add_action( "use" ); gSGR_Actions.add_default_binding( "move_fwd", SDLK_W ); gSGR_Actions.add_default_binding( "move_lft", SDLK_A ); gSGR_Actions.add_default_binding( "move_bwd", SDLK_S ); gSGR_Actions.add_default_binding( "move_rgt", SDLK_D ); // gSGR_Actions.add_default_binding( "elev_raise", "scrollup" ); // gSGR_Actions.add_default_binding( "elev_lower", "scrolldown" ); gSGR_Actions.add_default_binding( "elev_raise", SDLK_UP ); gSGR_Actions.add_default_binding( "elev_lower", SDLK_DOWN ); gSGR_Actions.add_default_binding( "use", SDLK_E ); gSGR_Actions.add_default_binding( "enable_noclip", SDLK_N ); Player.ui_font = SS_CreateFont( "fonts/gauge-heavy.ttf", gSGR_Window.height / 30 ); Player.ui_font_2 = SS_CreateFont( "fonts/gauge-heavy.ttf", gSGR_Window.height / 50 ); function Player.added() { this.camera = camera = SS3D_CreateCamera(); gSGR_Scene.camera = camera; global PLAYER = this; this.camera.angle = 90; this.camera.znear = 0.01; this.camera.zfar = 1000; } function Player.removed() { global PLAYER = null; this!Robot_destroy(); } function Player.serialize() { innerdata = { cam_angle = this.cam_angle, cam_zangle = this.cam_zangle, cam_ignoreOnce = this.cam_ignoreOnce, move_noclip = this.move_noclip, health = this.health, }; p = this.position; return "player", { x = p.x, y = p.y, z = p.z, direction = this.direction }, innerdata; } function Player.can_reuse( type, params, data ) { return type == "player"; } function Player.unserialize( data ) { this. { cam_angle = data.cam_angle, cam_zangle = data.cam_zangle, cam_ignoreOnce = data.cam_ignoreOnce, move_noclip = data.move_noclip, health = data.health, }; } function Player.updateHint( text ) { this.hint_text = text; this.hint_time = 2.1; } function Player.updateDirection( mmspeed ) { joyviewaxis = vec2( toreal( @gSGR_Keys[ "joyaxis2" ] ), toreal( @gSGR_Keys[ "joyaxis4" ] ) ); viewmove = gSGR_MouseMove + joyviewaxis * 5; if( viewmove.length && !current_cutscene ) { if( !this.cam_ignoreOnce && !Game.PrevPaused ) { this.cam_angle -= viewmove.x * mmspeed; this.cam_zangle -= viewmove.y * mmspeed; } else this.cam_ignoreOnce = false; } this.cam_zangle = clamp( this.cam_zangle, -M_PI*0.49, M_PI*0.49 ); cos_angle = cos( this.cam_angle ); sin_angle = sin( this.cam_angle ); cos_zangle = cos( this.cam_zangle ); sin_zangle = sin( this.cam_zangle ); this.direction = vec3( cos_angle * cos_zangle, sin_angle * cos_zangle, sin_zangle ); } function Player.updateNoclip( dt ) { this.updateDirection( 0.02 ); cos_angle = cos( this.cam_angle ); sin_angle = sin( this.cam_angle ); cos_zangle = cos( this.cam_zangle ); sin_zangle = sin( this.cam_zangle ); dir = this.direction; right = vec3( sin_angle, -cos_angle, 0 ); speed = 10; // if( gSGR_Actions.get( "move_faster" ) ) speed *= 5; if( gSGR_Actions.get( "move_fwd" ) ) this.position += dir * dt * speed; if( gSGR_Actions.get( "move_bwd" ) ) this.position -= dir * dt * speed; if( gSGR_Actions.get( "move_rgt" ) ) this.position += right * dt * speed; if( gSGR_Actions.get( "move_lft" ) ) this.position -= right * dt * speed; } function Player.updateMovement( dt ) { if( this.health <= 0 ) return; this.updateDirection( 0.01 ); this!Robot_setTurnDir( vec2(this.direction.x,this.direction.y) ); speed = 2000; cos_angle = cos( this.cam_angle ); sin_angle = sin( this.cam_angle ); fwdir = vec2( cos_angle, sin_angle ); right = vec2( sin_angle, -cos_angle ); if( !current_cutscene ) { movedir = vec2(0,0); if( gSGR_Actions.get( "move_fwd" ) ) movedir += fwdir; if( gSGR_Actions.get( "move_bwd" ) ) movedir -= fwdir; if( gSGR_Actions.get( "move_rgt" ) ) movedir += right; if( gSGR_Actions.get( "move_lft" ) ) movedir -= right; if( @gSGR_Keys[ "joyaxis0" ] ) movedir += right * gSGR_Keys[ "joyaxis0" ]; if( @gSGR_Keys[ "joyaxis1" ] ) movedir -= fwdir * gSGR_Keys[ "joyaxis1" ]; movedir = movedir.normalized; this!Robot_setMoveDir( movedir ); } } function Player.updateCamera() { if( current_cutscene ) return; this.camera.position = this.position - this.direction * 2 + vec3(0,0,0.3); this.camera.direction = this.direction; this.camera.aspect = gSGR_Window.width / gSGR_Window.height; } function Player.hit() { this.health -= 2; } function Player.isInAction() { foreach( osc : Game.OverlayScreens ) if( @osc.wdi ) return true; return false; } function Player.updateUseInfo() { this.use_info = use_info = QueryInteractive( 10 ); best_idx = null; best_q = 99999; foreach( i, ui_item : use_info ) { dist = ( ui_item.pos - this.position ).length; if( dist < 2 ) { cur_q = ui_item.area + ui_item.dist + dist; if( cur_q < best_q ) { best_q = cur_q; best_idx = i; } } } this.use_index = best_idx; } function Player.tick( dt ) { this!Robot_tick( dt ); if( this.health > 0 ) this.updateUseInfo(); in_action = this.isInAction(); if( !in_action ) { if( gSGR_Actions.is_pressed( "enable_noclip" ) ) this.move_noclip = !this.move_noclip; if( gSGR_Actions.is_pressed( "use" ) || ( (@gSGR_Keys[ "joybtn0" ]) && !(@gSGR_PrevKeys[ "joybtn0" ]) ) ) { if( this.use_index !== null ) { ent = this.use_info[ this.use_index ].ent; if( @ent.interact ) ent.interact(); } } } if( this.elev_change_timeout > 0 ) this.elev_change_timeout -= dt; else if( !in_action ) { if( gSGR_Actions.get( "elev_raise" ) || gSGR_Actions.get( "elev_lower" ) || @gSGR_Keys[ "joyhatup" ] || @gSGR_Keys[ "joyhatdn" ] ) { this.tgt_elevation += 0.05 * ( !!gSGR_Actions.get( "elev_raise" ) - !!gSGR_Actions.get( "elev_lower" ) + !!(@gSGR_Keys[ "joyhatup" ]) - !!(@gSGR_Keys[ "joyhatdn" ]) ); this.elev_change_timeout = 0.2; } this!Robot_setElevation( this.tgt_elevation ); } if( !in_action ) { if( this.move_noclip ) this.updateNoclip( dt ); else this.updateMovement( dt ); } p = this.position; if( @gSGR_Keys[ SDLK_0 ] ) this.health = 0; if( this.health <= 0 ) { this.death_timeout -= dt; if( this.death_timeout <= 0 ) { Game.SetPaused( true ); Game.OverlayScreens.push( PauseScreen ); } } this.updateCamera(); if( this.hint_time > 0 ) this.hint_time -= dt; } function Player.draw_ui() { W = gSGR_Window.width; H = gSGR_Window.height; if( current_cutscene || mission_complete ) return; if( this.hint_time > 0 ) { SS_DrawTextRect( this.hint_text, this.ui_font, color(1,clamp(this.hint_time,0,1)), DT_CENTER | DT_VCENTER, W*1/4, W*3/4, H*2/4, H*3/4 ); } if( intlist = this.use_info ) { bsz = ceil( min( W, H ) / 60 ); sqsz = ceil( min( W, H ) / 300 ); hsqsz = sqsz / 2; foreach( idx, intitem : intlist ) { aabb = intitem.aabb; if( this.use_index === idx ){ cr = 0.9; cg = 0.1; cb = 0.0; ca = 0.8; } else { cr = 0.3; cg = 0.7; cb = 0.9; ca = 0.8; } SS_DrawColorRect( aabb.x1 - hsqsz + 1, aabb.y1 - hsqsz + 1, aabb.x1 + bsz + hsqsz + 1, aabb.y1 + hsqsz + 1, 0.1, 0.1, 0.1, 0.8 ); SS_DrawColorRect( aabb.x1 - hsqsz + 1, aabb.y1 + hsqsz + 1, aabb.x1 + hsqsz + 1, aabb.y1 + bsz + hsqsz + 1, 0.1, 0.1, 0.1, 0.8 ); SS_DrawColorRect( aabb.x2 - bsz - hsqsz + 1, aabb.y2 - hsqsz + 1, aabb.x2 + hsqsz + 1, aabb.y2 + hsqsz + 1, 0.1, 0.1, 0.1, 0.8 ); SS_DrawColorRect( aabb.x2 - hsqsz + 1, aabb.y2 - bsz - hsqsz + 1, aabb.x2 + hsqsz + 1, aabb.y2 - hsqsz + 1, 0.1, 0.1, 0.1, 0.8 ); SS_DrawTextLine_BL( intitem.name, this.ui_font_2, aabb.x1 + 1, aabb.y1 - 1, color(0.1,0.1,0.1,0.8) ); text = intitem.name; if( this.use_index === idx ) { SS_DrawColorRect( aabb.x1, aabb.y1, aabb.x2, aabb.y2, cr, cg, cb, 0.3 ); text = "[Press Button 1] " $ text; } SS_DrawColorRect( aabb.x1 - hsqsz, aabb.y1 - hsqsz, aabb.x1 + bsz + hsqsz, aabb.y1 + hsqsz, cr, cg, cb, ca ); SS_DrawColorRect( aabb.x1 - hsqsz, aabb.y1 + hsqsz, aabb.x1 + hsqsz, aabb.y1 + bsz + hsqsz, cr, cg, cb, ca ); SS_DrawColorRect( aabb.x2 - bsz - hsqsz, aabb.y2 - hsqsz, aabb.x2 + hsqsz, aabb.y2 + hsqsz, cr, cg, cb, ca ); SS_DrawColorRect( aabb.x2 - hsqsz, aabb.y2 - bsz - hsqsz, aabb.x2 + hsqsz, aabb.y2 - hsqsz, cr, cg, cb, ca ); SS_DrawTextLine_BL( text, this.ui_font_2, aabb.x1, aabb.y1 - 2, color(0.9,0.9,0.9,0.8) ); // SS_DrawColorRect( aabb.x1, aabb.y1, aabb.x2, aabb.y2, 0.2, 0.4, 0.6, 0.5 ); } // SS_DrawTextLine( "Press E to "$act, this.ui_font, W - unit*20, unit*3, color(1,1) ); } unit = H / 30; SS_DrawTextLine( "HEALTH: " $ string_repeat( "|", max( 0, this.health ) ), this.ui_font, unit*3, unit*3, color(1,1) ); SS_DrawTextLine( "ELEVATION: " $ string_repeat( "|", 20 ), this.ui_font, unit*3, unit*5, color(0.1,1) ); SS_DrawTextLine( "ELEVATION: " $ string_repeat( "|", max( 0, this.tgt_elevation * 20 ) ), this.ui_font, unit*3, unit*5, color(0.3,0.6,0.9,1) ); // rr = gSGR_BulletWorld.rayTestClosest( this.position, this.position + this.direction * 5 ); // SS_DrawTextLine( "RAYCAST: "$rr, gSGR_DefaultFont, 100, 100, color(1,1) ); if( time_since_saved < 3 ) { SS_DrawTextLine( "Game saved!", this.ui_font, W / 3, unit, color(1,1-time_since_saved/3) ); } if( max_see_time > 0 ) { text = if( max_see_time >= 1, "TURRET ALERT!", "TURRET ALERT" ); SS_DrawTextLine( text, this.ui_font, W / 2 - unit * 4, unit * 3, color(1,0.1,0.05,1) ); } } return Player; }