Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- function ent_create_bullet( params )
- {
- Bullet =
- {
- pos = clone(params.pos),
- dir = clone(params.dir),
- from_player = params.from_player,
- };
- function Bullet.tick( delta )
- {
- p1 = this.pos;
- p2 = p1 + this.dir * 350 * delta;
- hit = null;
- gPhysicsWorld.RayCast( function( fixture, point, normal, fraction ) use( hit )
- {
- owner = fixture.body.userData;
- if( owner )
- {
- hit = owner;
- owner.handleBulletHit( point, normal );
- }
- },
- p1, p2 );
- if( hit )
- gGameWorld.remove_entity( this.id );
- this.pos = p2;
- }
- function Bullet.draw()
- {
- p1 = this.pos;
- p2 = this.pos - this.dir * 10;
- q = 0.3;
- SS_DrawColorLine( p1.x-q, p1.y-q, p2.x-q, p2.y-q, 0.1, 0.1, 0.1, 0.9 );
- SS_DrawColorLine( p1.x+q, p1.y-q, p2.x+q, p2.y-q, 0.1, 0.1, 0.1, 0.9 );
- SS_DrawColorLine( p1.x-q, p1.y+q, p2.x-q, p2.y+q, 0.1, 0.1, 0.1, 0.9 );
- SS_DrawColorLine( p1.x+q, p1.y+q, p2.x+q, p2.y+q, 0.1, 0.1, 0.1, 0.9 );
- SS_DrawColorLine( p1.x, p1.y, p2.x, p2.y, 0.9, 0.8, 0.7, 0.9 );
- }
- return Bullet;
- }
- function char_init( obj, pos, textype )
- {
- bodyDef = Box2D_CreateBodyDef();
- bodyDef.type = Box2D_BodyType_Dynamic;
- bodyDef.position = pos;
- bodyDef.active = true;
- bodyDef.allowSleep = false;
- shape = Box2D_CreateCircleShape();
- shape.radius = 12;
- obj.phy_body = gPhysicsWorld.CreateBody( bodyDef );
- obj.phy_body.CreateFixtureFromShape( shape, 1 );
- obj.pos = pos;
- obj.dir = vec2(1,0);
- obj.move_dir = vec2(0);
- obj.move_speed = 0;
- obj.move_factor = 0;
- obj.move_amount = 0;
- obj.moved = false;
- obj.bob_time = 0;
- obj.tx_char = SS_CreateTexture( "images/"$textype$".png", "nolerp" );
- obj.tx_leg = SS_CreateTexture( "images/"$textype$"_leg.png", "nolerp" );
- obj.ps_shot = ParticleSystem.create( PSFX_Shot );
- obj.ps_hit = ParticleSystem.create( PSFX_BloodHit );
- obj.shoot_timeout = 0;
- obj.texname = textype;
- obj.dead = false;
- char = obj;
- function char.handleBulletHit( point, normal )
- {
- this.ps_hit.emitpos = point;
- this.ps_hit.emitdir = normal;
- this.ps_hit.play();
- this.dead = true;
- if( this.texname == "player" )
- gCurMission.hit_player = true;
- if( this.texname == "enemy" )
- gCurMission.hit_enemy = true;
- }
- function char.added()
- {
- this.phy_body.userData = this;
- }
- function char.removed()
- {
- this.phy_body.userData = null;
- }
- }
- function char_tick( obj, delta, move_dir, move_speed, tgt )
- {
- obj.ps_shot.tick( delta );
- obj.ps_hit.tick( delta );
- if( obj.dead )
- {
- obj.phy_body.linearVelocity = vec2(0);
- return;
- }
- obj.shoot_timeout = max( obj.shoot_timeout - delta, 0 );
- obj.move_dir = move_dir;
- obj.move_speed = move_speed * move_dir.length;
- obj.move_factor = max( 0, min( 1, obj.move_factor + if( move_dir != vec2(0), delta, -delta ) * 5 ) );
- obj.move_amount += obj.move_factor;
- obj.moved = obj.move_amount > 10;
- obj.bob_time += delta * move_speed / 8,
- obj.phy_body.linearVelocity = move_dir * move_speed;
- obj.pos = obj.phy_body.position;
- obj.dir = ( tgt - obj.pos ).normalized;
- }
- function char_draw( obj )
- {
- bob_off = obj.pos + obj.dir.perp * ( sin( obj.bob_time ) * obj.move_factor );
- leg1_off = obj.pos + obj.dir.perp * 4 + obj.move_dir * 4 * sin( obj.bob_time ) * obj.move_factor;
- leg2_off = obj.pos - obj.dir.perp * 4 + obj.move_dir * 4 * -sin( obj.bob_time ) * obj.move_factor;
- if( !obj.dead )
- {
- SS_Draw({ preset = "box", texture = obj.tx_leg, position = leg1_off,
- angle = obj.dir.angle + M_PI * 0.5, scale = vec2(6,12), color = color(1) });
- SS_Draw({ preset = "box", texture = obj.tx_leg, position = leg2_off,
- angle = obj.dir.angle + M_PI * 0.5, scale = vec2(6,12), color = color(1) });
- }
- SS_Draw({ preset = "box", texture = obj.tx_char, position = bob_off,
- angle = obj.dir.angle + M_PI * 0.5, scale = vec2(24), color = color(1) });
- obj.ps_shot.draw();
- obj.ps_hit.draw();
- }
- function char_shoot( obj )
- {
- if( obj.shoot_timeout <= 0 )
- {
- bpos = obj.pos + obj.dir * 8;
- bdir = obj.dir;
- obj.ps_shot.emitpos = bpos;
- obj.ps_shot.emitdir = bdir;
- obj.ps_shot.play();
- gGameWorld.add_entity( EntityBuilder.build( "bullet", {
- pos = bpos,
- dir = bdir,
- from_player = obj.texname == "player",
- }) );
- obj.shoot_timeout = 0.2;
- }
- }
- function ent_create_player( params )
- {
- Player =
- {
- z_index = 100,
- tx_crosshair = SS_CreateTexture( "images/crosshair.png" ),
- };
- char_init( Player, vec2(params.x,params.y), "player" );
- global gCurPlayer = Player;
- gActionMap.add_action( "move_up" );
- gActionMap.add_action( "move_dn" );
- gActionMap.add_action( "move_lf" );
- gActionMap.add_action( "move_rt" );
- gActionMap.add_action( "move_slow" );
- gActionMap.add_action( "shoot" );
- gActionMap.add_default_binding( "move_up", SDLK_W );
- gActionMap.add_default_binding( "move_dn", SDLK_S );
- gActionMap.add_default_binding( "move_lf", SDLK_A );
- gActionMap.add_default_binding( "move_rt", SDLK_D );
- gActionMap.add_default_binding( "move_slow", SDLK_LSHIFT );
- gActionMap.add_default_binding( "shoot", SDLK_LMB );
- function Player.setPos( pos )
- {
- this.pos = pos;
- this.phy_body.position = pos;
- }
- function Player.tick( delta )
- {
- move_dir = vec2(
- gActionMap.get( "move_rt" ) - gActionMap.get( "move_lf" ),
- gActionMap.get( "move_dn" ) - gActionMap.get( "move_up" )
- ).normalized;
- move_speed = lerp( 96, 32, gActionMap.get( "move_slow" ) );
- tgt = gCurWorld.screenToWorld( gCursorPos );
- char_tick( this, delta, move_dir, move_speed, tgt );
- if( gActionMap.is_pressed( "shoot" ) )
- {
- char_shoot( this );
- }
- curpos = gCurWorld.camera_follow_pos;
- curpos = lerp( curpos, this.pos, pow( 0.1, 1 - clamp( delta, 0, 1 ) ) );
- gCurWorld.camera_follow_pos = curpos;
- gCurWorld.light_pos = this.pos;
- gCurWorld.light_dir = this.dir;
- }
- function Player.draw()
- {
- char_draw( this );
- }
- function Player.draw_ui()
- {
- if( !Game.Paused )
- {
- SS_Draw({ preset = "box", texture = this.tx_crosshair,
- position = gCursorPos+vec2(1), scale = vec2(32), color = color(0.5,1,0.5,1) });
- }
- }
- return Player;
- }
- global ENEMY_ENTER_VIEW = 1;
- global ENEMY_ATTACK = 2;
- global ENEMY_WAIT = 3;
- global ENEMY_ESCAPE_VIEW = 4;
- global ENEMY_TILE_MEMORY_LIMIT = 16;
- function ent_create_enemy( params )
- {
- Enemy =
- {
- z_index = 99,
- stage = ENEMY_ENTER_VIEW,
- lastSeenPos = null,
- preWaitTime = 0.7 + randf() * 0.5,
- waitTime = null,
- lastEscapeTiles = [],
- };
- char_init( Enemy, vec2(params.x,params.y), "enemy" );
- function Enemy.added()
- {
- global gCurEnemy = this;
- this.phy_body.userData = this;
- }
- function Enemy.removed()
- {
- global gCurEnemy = null;
- this.phy_body.userData = null;
- }
- function Enemy.isPlayerVisible()
- {
- visionObstructed = false;
- p1 = this.pos;
- p2 = gCurPlayer.pos;
- dir = ( p2 - p1 ).normalized;
- p1 += dir * 13;
- p2 -= dir * 13;
- gPhysicsWorld.RayCast(function() use (visionObstructed)
- {
- visionObstructed = true;
- },
- p1, p2 );
- return !visionObstructed;
- }
- function Enemy.pickNearestTileTowards( tgt, regpos )
- {
- pos = this.pos;
- tiles = gCurWorld.getWalkableTilesRightOutsideAABB( aabb2v( pos, pos ) );
- positions = [];
- factors = [];
- foreach( tile : tiles )
- {
- tilepos = vec2( tile[0] + 0.5, tile[1] + 0.5 ) * 32;
- positions.push( tilepos );
- factors.push( ( tgt - tilepos ).length );
- }
- if( positions )
- {
- positions.sort_mapped( factors );
- pos = positions[0];
- if( regpos )
- {
- // if haven't reached a new tile, just return previous result
- mytilepos = vec2( floor( pos.x / 32 ) + 0.5, floor( pos.y / 32 ) + 0.5 ) * 32;
- if( @this.prevtile == mytilepos && this.lastEscapeTiles )
- return this.lastEscapeTiles.last;
- this.prevtile = mytilepos;
- // if last found tile was same, ignore that it's in the "already found" array
- if( this.lastEscapeTiles.size && this.lastEscapeTiles.last == pos )
- return pos;
- // target tile cannot be visited before
- while( this.lastEscapeTiles.find( pos ) !== null )
- {
- positions.shift();
- if( positions.size )
- pos = positions[0];
- else
- {
- // stuck
- this.lastEscapeTiles.clear(); // panic!
- return null;
- }
- }
- // register currently found tile, pushing out old ones if necessary
- while( this.lastEscapeTiles.size > ENEMY_TILE_MEMORY_LIMIT )
- this.lastEscapeTiles.shift();
- this.lastEscapeTiles.push( pos );
- }
- return pos;
- }
- return null;
- }
- function Enemy.attackOrWait()
- {
- if( this.isPlayerVisible() )
- {
- this.lastSeenPos = clone( gCurPlayer.pos ); // can't have same instance to avoid following
- this.waitTime = randf() * 1.5 + 1.4;
- this.stage = ENEMY_ATTACK;
- }
- else if( this.preWaitTime <= 0 )
- {
- this.waitTime = randf() * 1.5 + 2.4;
- this.stage = ENEMY_WAIT;
- }
- }
- function Enemy.tick( delta )
- {
- move_dir = vec2(0);
- move_speed = 120;
- tgt = this.pos + this.dir;
- // try to move towards player, determine shooting possibility
- if( this.stage == ENEMY_ENTER_VIEW )
- {
- movetgt = this.pickNearestTileTowards( gCurPlayer.pos );
- if( movetgt )
- {
- move_dir = ( movetgt - this.pos ).normalized;
- if( move_dir )
- tgt = this.pos + move_dir * 120;
- }
- this.preWaitTime -= delta;
- this.attackOrWait();
- }
- // attack player
- else if( this.stage == ENEMY_ATTACK )
- {
- tgt = this.lastSeenPos;
- this.waitTime -= delta;
- if( this.waitTime <= 0 )
- this.stage = ENEMY_ESCAPE_VIEW;
- char_shoot( this );
- }
- // wait for some time, look or walk around maybe
- else if( this.stage == ENEMY_WAIT )
- {
- if( this.isPlayerVisible() )
- {
- this.waitTime -= delta * 5;
- if( vec2_dot( this.dir, ( gCurPlayer.pos - this.pos ).normalized ) > 0.5 )
- {
- this.tgt = gCurPlayer.pos;
- char_shoot( this );
- }
- }
- this.waitTime -= delta;
- if( this.waitTime <= 0 )
- this.stage = ENEMY_ESCAPE_VIEW;
- }
- // try to escape
- else if( this.stage == ENEMY_ESCAPE_VIEW )
- {
- ovtgt = this.pos + ( this.pos - gCurPlayer.pos ).normalized * 120;
- movetgt = this.pickNearestTileTowards( ovtgt, true );
- if( movetgt )
- {
- move_dir = ( movetgt - this.pos );
- if( move_dir.length < 4 )
- move_dir = vec2(0);
- move_dir = move_dir.normalized;
- if( move_dir )
- tgt = this.pos + move_dir * 120;
- else
- this.attackOrWait();
- }
- camera_aabb = gCurWorld.getCameraAABB();
- if( !aabb2_intersect( aabb2v( this.pos - vec2(16), this.pos + vec2(16) ), camera_aabb ) )
- {
- // escaped
- gGameWorld.remove_entity( this.id );
- }
- }
- char_tick( this, delta, move_dir, move_speed, tgt );
- }
- function Enemy.draw()
- {
- char_draw( this );
- }
- return Enemy;
- }
- function ent_create_mission( params )
- {
- Mission =
- {
- pos = vec2(params.x,params.y),
- ext = vec2(48),
- player_near = false,
- quitting = false,
- hit_player = false,
- hit_enemy = false,
- chance_timeout = 1,
- };
- function Mission.added()
- {
- global gCurMission = this;
- }
- function Mission.removed()
- {
- global gCurMission = null;
- }
- /* chance, in units per second */
- function Mission.calcSpawnChance()
- {
- chance = 1.2 / 3;
- P = @gCurPlayer;
- if( P )
- chance *= P.move_speed / 160 + 0.4;
- return chance;
- }
- function Mission.findSpawnPoint()
- {
- world = @gCurWorld;
- if( world )
- {
- tiles = world.getTilesNearView();
- positions = [];
- foreach( tile : tiles )
- {
- pos = vec2(tile[0]+0.5,tile[1]+0.5) * 32;
- // not even close to the starting point
- if( ( pos - this.pos ).length < 400 ) continue;
- positions.push( pos );
- }
- if( positions )
- {
- return positions[ rand() % positions.size ];
- }
- }
- return null;
- }
- function Mission.spawnEnemy()
- {
- pos = this.findSpawnPoint();
- if( !pos )
- return false;
- gGameWorld.add_entity( EntityBuilder.build( "enemy", { x = pos.x, y = pos.y } ) );
- return true;
- }
- function Mission.canSpawnEnemy()
- {
- enemy = @gCurEnemy;
- return !enemy;
- }
- function Mission.tick( delta )
- {
- player = @gCurPlayer;
- xmin = this.pos.x - this.ext.x;
- xmax = this.pos.x + this.ext.x;
- ymin = this.pos.y - this.ext.y;
- ymax = this.pos.y + this.ext.y;
- ppos = player.pos;
- this.player_near = false;
- if( player )
- {
- if( ppos.x >= xmin && ppos.x <= xmax &&
- ppos.y >= ymin && ppos.y <= ymax )
- {
- if( ppos.x < this.pos.x && !this.quitting )
- {
- this.quitting = true;
- Game.FadeOutFactor = 0;
- }
- this.player_near = true;
- }
- }
- if( this.hit_player || this.hit_enemy )
- {
- if( !this.quitting )
- {
- this.quitting = true;
- Game.FadeOutFactor = 0;
- }
- if( this.hit_player )
- {
- if( this.hit_enemy )
- Game.PauseText = "Heroic effort.";
- else
- Game.PauseText = "Failure.";
- }
- else
- Game.PauseText = "Success.";
- Game.CanUnpause = false;
- if( Game.FadeOutFactor >= 5 )
- Game.SetPaused( true );
- }
- if( this.quitting && !this.hit_player && !this.hit_enemy )
- {
- Game.PauseText = "Pursuit stopped. Suspect escaped.";
- Game.CanUnpause = false;
- player.setPos(vec2( this.pos.x - Game.FadeOutFactor * 10, ppos.y ));
- if( Game.FadeOutFactor >= 5 )
- Game.SetPaused( true );
- }
- if( this.canSpawnEnemy() )
- {
- this.chance_timeout -= delta;
- while( this.chance_timeout <= 0 )
- {
- mustspawn = this.calcSpawnChance() > randf();
- if( mustspawn )
- {
- this.spawnEnemy();
- // one more second after disappearance to reappear
- this.chance_timeout += 1;
- }
- this.chance_timeout += 1;
- }
- }
- }
- function Mission.draw_ui()
- {
- text = null;
- if( !this.quitting && this.player_near )
- {
- text = "This is a way out. Going through here means stopping the pursuit. Proceed to confirm.";
- }
- else if( !@gCurPlayer.moved )
- {
- text = "Use W/A/S/D to move, Left Shift to walk slowly, Left mouse button to shoot";
- }
- if( text )
- SS_DrawTextRect( text, gActionFont2, color(0.9,0.9), DT_LEFT | DT_BOTTOM, W/5, W*4/5, H/5, H*4/5 );
- }
- return Mission;
- }
- return
- {
- bullet =
- {
- create = ent_create_bullet,
- default = { pos = vec2(0), dir = vec2(0), from_player = false },
- },
- player =
- {
- create = ent_create_player,
- default = { x = 0, y = 0 },
- },
- enemy =
- {
- create = ent_create_enemy,
- default = { x = 0, y = 0 },
- },
- mission =
- {
- create = ent_create_mission,
- default = { x = 0, y = 0 },
- },
- };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement