2017-11-07 02:42:53 +01:00
unit GameTutorial2;
{$mode objfpc} {$H+}
//step2:
//2 targets, that shoot at the player as well.
//targets and player share the same health decreasing code
interface
uses
windows, Classes, SysUtils, gamepanel, guitextobject, staticguiobject, gamebase,
target, bullet, Dialogs, Graphics, playerwithhealth, math;
type
TGame2= class( TGameBase)
private
fpanel: Tgamepanel;
player: TPlayerWithHealth;
target1, target2: TPlayerWithHealth;
bullets: array of Tbullet; //max 5 bullets on the screen at once
shotsfired: integer ;
lastshot: qword;
rotatedirection: single ;
2018-05-20 11:16:50 +02:00
usemegabombs: boolean ;
2017-11-07 02:42:53 +01:00
speedup: boolean ;
speed: single ;
status: TGUITextObject;
info: TGUITextObject;
infobutton: TStaticGUIObject;
pausescreen: TGUITextObject;
pausebutton: TStaticGUIObject;
2018-05-20 11:16:50 +02:00
enemytext: TGUITextObject;
enemytextStartTime: qword;
2017-11-07 02:42:53 +01:00
gametime: qword;
function getNextBulletPos: integer ;
function pauseclick( sender: tobject) : boolean ;
function infoPopup( sender: tobject) : boolean ;
function HideInfo( sender: tobject) : boolean ;
2018-05-15 01:43:19 +02:00
procedure spawnPlayer;
2017-11-07 02:42:53 +01:00
procedure spawnTarget1;
procedure spawnTarget2;
public
2018-05-20 11:16:50 +02:00
procedure SpawnEnemyText;
2017-11-07 02:42:53 +01:00
procedure gametick( currentTime: qword; diff: integer ) ; override ;
procedure render; override ;
function KeyHandler( TGamePanel: TObject; keventtype: integer ; Key: Word ; Shift: TShiftState) : boolean ; override ;
constructor create( p: TGamePanel) ;
destructor destroy; override ;
end ;
implementation
2018-12-08 00:05:26 +01:00
uses registry;
2017-11-07 02:42:53 +01:00
function TGame2. getNextBulletPos: integer ;
var i: integer ;
begin
for i: = 0 to length( bullets) - 1 do
if bullets[ i] = nil then exit( i) ;
result : = length( bullets) ;
if result = 0 then
setlength( bullets, 8 )
else
setlength( bullets, length( bullets) * 2 ) ;
for i: = result to length( bullets) - 1 do
bullets[ i] : = nil ;
end ;
function TGame2. KeyHandler( TGamePanel: TObject; keventtype: integer ; Key: Word ; Shift: TShiftState) : boolean ;
var
x: boolean ;
i: integer ;
bulletpos: integer ;
ct: qword;
begin
2018-05-15 01:43:19 +02:00
if iskeydown( VK_W) and iskeydown( VK_I) and iskeydown( VK_N) then
begin
2018-05-20 11:16:50 +02:00
usedcheats: = true ;
2018-05-15 01:43:19 +02:00
target1. explode;
target2. explode;
exit;
end ;
if iskeydown( VK_D) and iskeydown( VK_I) and iskeydown( VK_E) then
begin
rotatedirection: = 0 ;
player. explode;
exit;
end ;
if player. isdead then exit;
2017-11-07 02:42:53 +01:00
if keventtype= 0 then
begin
ct: = GetTickCount64;
if key= vk_space then
begin
if ct< lastshot+ 1 0 0 then exit; //rate limit the amount of bullets
i: = getNextBulletPos;
//create a bullet
bullets[ i] : = tbullet. create( player) ;
bullets[ i] . x: = player. x;
bullets[ i] . y: = player. y;
bullets[ i] . rotation: = player. rotation;
bullets[ i] . damage: = 1 ;
lastshot: = ct;
//let the enemies shoot as well
//target the player pos
2018-05-20 11:16:50 +02:00
if target1< > nil then
target1. rotation: = ( ( arctan2( player. y- target1. y, player. x- target1. x) ) * ( 1 8 0 ) / pi) + 9 0 ;
2017-11-07 02:42:53 +01:00
2018-05-20 11:16:50 +02:00
if target2< > nil then
target2. rotation: = ( ( arctan2( player. y- target2. y, player. x- target2. x) ) * ( 1 8 0 ) / pi) + 9 0 ;
2017-11-07 02:42:53 +01:00
2018-05-20 11:16:50 +02:00
if target1< > nil then
begin
i: = getNextBulletPos;
2017-11-07 02:42:53 +01:00
2018-05-20 11:16:50 +02:00
bullets[ i] : = tbullet. create( target1) ;
bullets[ i] . x: = target1. x;
bullets[ i] . y: = target1. y;
bullets[ i] . rotation: = target1. rotation;
bullets[ i] . damage: = 2 ;
if usemegabombs then
begin
bullets[ i] . speed: = bullets[ i] . speed* 0.4 ;
bullets[ i] . megabomb: = true ;
bullets[ i] . damage: = player. Health+ 1 ;
end ;
end ;
if target2< > nil then
begin
i: = getNextBulletPos;
bullets[ i] : = tbullet. create( target2) ;
bullets[ i] . x: = target2. x;
bullets[ i] . y: = target2. y;
bullets[ i] . rotation: = target2. rotation;
bullets[ i] . damage: = 2 ;
if usemegabombs then
begin
bullets[ i] . speed: = bullets[ i] . speed* 0.4 ;
bullets[ i] . megabomb: = true ;
bullets[ i] . damage: = player. Health+ 1 ;
end ;
end ;
2017-11-07 02:42:53 +01:00
end
else
begin
case key of
VK_LEFT, VK_A: if RotateDirection> = 0 then rotatedirection: = - 0.1 * ( ifthen( ssShift in shift, 3 , 1 ) ) ;
VK_RIGHT, VK_D: if RotateDirection< = 0 then rotatedirection: = + 0.1 * ( ifthen( ssShift in shift, 3 , 1 ) ) ;
VK_UP, VK_W: speedup: = true ;
VK_DOWN, VK_S: speedup: = false ;
end ;
end ;
end
else
begin
case key of
VK_LEFT, VK_A: if RotateDirection< 0 then rotatedirection: = 0 ;
VK_RIGHT, VK_D: if RotateDirection> 0 then rotatedirection: = 0 ;
vk_UP, VK_W: speedup: = false ;
vk_DOWN, VK_S: speedup: = false ;
end ;
end ;
result : = false ;
end ;
procedure TGame2. render;
var i: integer ;
begin
player. render;
if target1< > nil then
target1. render;
if target2< > nil then
target2. render;
for i: = 0 to length( bullets) - 1 do
if bullets[ i] < > nil then
bullets[ i] . render;
if info< > nil then
info. render
else
begin
if infobutton< > nil then
infobutton. render;
end ;
status. render;
pausebutton. render;
if pausescreen< > nil then
pausescreen. render;
2018-05-20 11:16:50 +02:00
if enemytext< > nil then
enemytext. render;
2017-11-07 02:42:53 +01:00
end ;
procedure TGame2. gametick( currentTime: qword; diff: integer ) ;
var i, j: integer ;
2018-05-20 11:16:50 +02:00
megabombsecleft: integer ;
2017-11-07 02:42:53 +01:00
begin
2018-05-20 11:16:50 +02:00
if ticking= false then exit;
2017-11-07 02:42:53 +01:00
if pausescreen< > nil then
exit;
inc( gametime, diff) ;
if player< > nil then
begin
if speedup then
begin
speed: = speed+ 0.0001 ;
if speed> 0.003 then speed: = 0.003 ;
end
else
begin
if speed> 0 then
speed: = speed- 0.0002 ;
if speed< 0 then speed: = 0 ;
end ;
player. rotation: = player. rotation+ rotatedirection* diff;
player. x: = player. x+ ( diff* speed) * sin( degtorad( player. rotation) ) ;
player. y: = player. y+ ( diff* speed) * - cos( degtorad( player. rotation) ) ;
if player. x> 1 then player. x: = 1 ;
if player. x< - 1 then player. x: = - 1 ;
if player. y> 1 then player. y: = 1 ;
if player. y< - 1 then player. y: = - 1 ;
end ;
//adjust targets to point to player
//....
2018-05-15 01:43:19 +02:00
if target1< > nil then
target1. rotation: = ( ( arctan2( player. y- target1. y, player. x- target1. x) ) * ( 1 8 0 ) / pi) + 9 0 ;
if target2< > nil then
target2. rotation: = ( ( arctan2( player. y- target2. y, player. x- target2. x) ) * ( 1 8 0 ) / pi) + 9 0 ;
2017-11-07 02:42:53 +01:00
for i: = 0 to length( bullets) - 1 do
if bullets[ i] < > nil then
begin
2018-05-20 11:16:50 +02:00
if bullets[ i] . megabomb then
begin
bullets[ i] . rotation: = ( ( arctan2( player. y- bullets[ i] . y, player. x- bullets[ i] . x) ) * ( 1 8 0 ) / pi) + 9 0 ;
bullets[ i] . speed: = bullets[ i] . speed+ 0.00001 * ( diff/ 1 0 0 ) ;
end ;
2017-11-07 02:42:53 +01:00
bullets[ i] . travel( diff) ;
if bullets[ i] . checkCollision( player) then
begin
player. damage( bullets[ i] . damage) ;
2018-05-15 01:43:19 +02:00
if player. isdead then
2017-11-07 02:42:53 +01:00
begin
2018-05-15 01:43:19 +02:00
player. explode;
2017-11-07 02:42:53 +01:00
//remove all bullets
for j: = 0 to length( bullets) - 1 do
freeandnil( bullets[ j] ) ;
end ;
status. text : = format( 'Player Health: ' #13 #10 '%d' , [ player. health] ) ;
if bullets[ i] < > nil then
freeandnil( bullets[ i] ) ;
end ;
2018-05-20 11:16:50 +02:00
//and yes, you can let them shoot eachother (except megabombs)
if ( bullets[ i] < > nil ) and ( bullets[ i] . megabomb= false ) and ( target1< > nil ) and ( target1. isdead= false ) and bullets[ i] . checkCollision( target1) then //perhaps use a vector based on old x,y and new x,y
2017-11-07 02:42:53 +01:00
begin
target1. damage( bullets[ i] . damage) ;
2018-05-15 01:43:19 +02:00
if target1. isdead then
2018-05-20 11:16:50 +02:00
begin
2018-05-15 01:43:19 +02:00
target1. explode;
2018-05-20 11:16:50 +02:00
if ( target2< > nil ) and ( target2. isdead= false ) then
2018-05-22 12:40:25 +02:00
begin
2018-05-20 11:16:50 +02:00
spawnEnemyText;
2018-05-22 12:40:25 +02:00
target2. health: = min( target2. health+ 2 0 , target2. MaxHealth) ; //just increase the level of assholerly a little bit more
end ;
2018-05-20 11:16:50 +02:00
end ;
2017-11-07 02:42:53 +01:00
freeandnil( bullets[ i] ) ;
end ;
2018-05-20 11:16:50 +02:00
if ( bullets[ i] < > nil ) and ( bullets[ i] . megabomb= false ) and ( target2< > nil ) and ( target2. isdead= false ) and bullets[ i] . checkCollision( target2) then //perhaps use a vector based on old x,y and new x,y
2017-11-07 02:42:53 +01:00
begin
target2. damage( bullets[ i] . damage) ;
2018-05-15 01:43:19 +02:00
if target2. isdead then
2018-05-20 11:16:50 +02:00
begin
2018-05-15 01:43:19 +02:00
target2. explode;
2018-05-20 11:16:50 +02:00
if ( target1< > nil ) and ( target1. isdead= false ) then
2018-05-22 12:40:25 +02:00
begin
2018-05-20 11:16:50 +02:00
spawnEnemyText;
2018-05-22 12:40:25 +02:00
target1. health: = min( target1. health+ 2 0 , target1. MaxHealth) ;
end ;
2018-05-20 11:16:50 +02:00
end ;
2017-11-07 02:42:53 +01:00
freeandnil( bullets[ i] ) ;
end ;
if ( bullets[ i] < > nil ) and ( ( bullets[ i] . x> 1 ) or ( bullets[ i] . y> 1 ) or ( bullets[ i] . x< - 1 ) or ( bullets[ i] . y< - 1 ) ) then
begin
freeandnil( bullets[ i] ) ;
exit;
end ;
end ;
2018-05-20 11:16:50 +02:00
if enemytext< > nil then
begin
megabombsecleft: = ceil( integer( ( 3 0 0 0 - ( gametime- enemytextStartTime) ) ) / 1 0 0 0 ) ;
enemytext. Text : = 'You will pay for this!' #13 #10 'Activating megabombs' #13 #10 '' + inttostr( megabombsecleft) ;
if megabombsecleft< 0 then
begin
if target1< > nil then
target1. enemycharged: = true ;
if target2< > nil then
target2. enemycharged: = true ;
usemegabombs: = true ;
freeandnil( enemytext) ;
end ;
end ;
2018-05-15 01:43:19 +02:00
if ( target1< > nil ) and target1. isdead and ( target1. blownup) then
freeandnil( target1) ;
if ( target2< > nil ) and target2. isdead and ( target2. blownup) then
freeandnil( target2) ;
if ( player< > nil ) and player. isdead and ( player. blownup) then
begin
//recreate the player
//game over, restart
2018-05-20 11:16:50 +02:00
usemegabombs: = false ;
if target1< > nil then
target1. enemycharged: = false ;
if target2< > nil then
target2. enemycharged: = false ;
2018-05-15 01:43:19 +02:00
freeandnil( player) ;
spawnplayer;
if target1= nil then
spawnTarget1;
target1. health: = 2 0 0 ;
if target2= nil then
spawnTarget2;
target2. health: = 2 0 0 ;
status. text : = format( 'Player Health: ' #13 #10 '%d' , [ player. health] ) ;
end ;
2018-05-20 11:16:50 +02:00
if ( target1= nil ) and ( target2= nil ) then
begin
ticking: = false ;
showmessage( 'well done' ) ;
2018-12-08 00:05:26 +01:00
with tregistry. create do
begin
if OpenKey( '\Software\Cheat Engine\GTutorial' , true ) then
WriteBool( 'This does not count as a solution for tutorial 2' , True ) ;
free;
end ;
2018-05-20 11:16:50 +02:00
gamewon( ) ;
exit;
end ;
end ;
2017-11-07 02:42:53 +01:00
2018-05-20 11:16:50 +02:00
procedure TGame2. SpawnEnemyText;
begin
enemytext: = TGUITextObject. create( nil ) ;
enemytext. firstTextBecomesMinWidth: = true ;
enemytext. width: = 0.8 ;
enemytext. height: = 0.8 ;
enemytext. x: = 0 ;
enemytext. y: = 0 ;
enemytext. rotationpoint. x: = 0 ;
enemytext. rotationpoint. y: = 0 ;
enemytext. color: = clRED;
enemytext. bcolor: = clWhite;
enemytext. font. Size: = 1 8 ;
enemytext. Text : = 'You will pay for this!' #13 #10 'Activating megabombs' #13 #10 '' + inttostr( 3 ) ;
enemytextStartTime: = gametime;
2017-11-07 02:42:53 +01:00
end ;
function TGame2. pauseclick( sender: tobject) : boolean ;
begin
if pausescreen< > nil then
freeandnil( pausescreen)
else
begin
pausescreen: = TGUITextObject. create( fpanel) ;
pausescreen. firstTextBecomesMinWidth: = true ;
pausescreen. width: = 0.8 ;
pausescreen. height: = 0.8 ;
pausescreen. x: = 0 ;
pausescreen. y: = 0 ;
pausescreen. rotationpoint. x: = 0 ;
pausescreen. rotationpoint. y: = 0 ;
pausescreen. color: = clRED;
pausescreen. bcolor: = clWhite;
pausescreen. font. Size: = 1 8 ;
pausescreen. text : = '!PAUSED!' ;
end ;
result : = true ;
end ;
function TGame2. infoPopup( sender: tobject) : boolean ;
begin
if info< > nil then exit( false ) ;
info: = TGUITextObject. create( fpanel) ;
info. firstTextBecomesMinWidth: = true ;
info. width: = 0.8 ;
info. height: = 0.8 ;
info. x: = 0 ;
info. y: = 0 ;
info. rotationpoint. x: = 0 ;
info. rotationpoint. y: = 0 ;
info. color: = clBlack;
info. bcolor: = clWhite;
info. backgroundAlpha: = 1 9 0 ;
info. font. Size: = 9 ;
info. text : = 'Step 2:' #13 #10 +
'These two enemies have more health' #13 #10 +
'and do more damage to you than' #13 #10 +
'you do to them. Destroy them' #13 #10 +
' ' #13 #10 +
'Tip/Warning: Enemy and player are related' #13 #10 +
' ' #13 #10 '(Click to hide)' ;
info. OnClick: = @ HideInfo;
result : = true ;
end ;
function TGame2. HideInfo( sender: tobject) : boolean ;
begin
freeandnil( info) ;
result : = true ;
end ;
2018-05-15 01:43:19 +02:00
procedure TGame2. spawnPlayer;
begin
player: = TPlayerWithHealth. create( false ) ;
player. x: = 0 ;
player. y: = 0.8 ;
player. health: = 1 0 0 ;
player. maxhealth: = 1 0 0 ;
end ;
2017-11-07 02:42:53 +01:00
procedure TGame2. spawnTarget1;
begin
target1: = TPlayerWithHealth. create( true ) ;
target1. x: = 0 - target1. width- 0.005 ;
target1. y: = - 0.8 ;
2018-05-29 15:10:22 +02:00
target1. health: = 2 0 0 ;
2017-11-07 02:42:53 +01:00
target1. maxhealth: = 2 0 0 ;
target1. rotation: = 1 8 0 ;
end ;
procedure TGame2. spawnTarget2;
begin
target2: = TPlayerWithHealth. create( true ) ;
target2. x: = target2. width+ 0.005 ;
target2. y: = - 0.8 ;
2018-05-29 15:10:22 +02:00
target2. health: = 2 0 0 ;
2017-11-07 02:42:53 +01:00
target2. maxhealth: = 2 0 0 ;
target2. rotation: = 1 8 0 ;
end ;
destructor TGame2. destroy;
begin
if player< > nil then
freeandnil( player) ;
if target1< > nil then
freeandnil( target1) ;
if target2< > nil then
freeandnil( target2) ;
if status< > nil then
freeandnil( status) ;
if infobutton< > nil then
freeandnil( infobutton) ;
if info< > nil then
freeandnil( info) ;
inherited destroy;
end ;
constructor TGame2. create( p: TGamePanel) ;
begin
fpanel: = p;
2018-05-15 01:43:19 +02:00
spawnPlayer;
2017-11-07 02:42:53 +01:00
spawnTarget1;
spawnTarget2;
status: = TGUITextObject. create;
status. firstTextBecomesMinWidth: = true ;
status. font. Size: = 7 8 ;
status. width: = 0.4 ;
status. height: = 0.3 ;
status. x: = 1 - status. width;
status. y: = 1 - status. height;
status. textalignment: = taCenter;
status. firstTextBecomesMinWidth: = true ;
status. color: = clred;
status. bcolor: = clgreen;
status. text : = 'Player Health: ' #13 #10 '100' ;
infobutton: = TStaticGUIObject. create( p, 'infobutton.png' , 0.1 , 0.1 ) ;
infobutton. rotationpoint. y: = 1 ; //so the bottom will be the y pos
infobutton. x: = - 1 ;
infobutton. y: = 1 ;
infobutton. OnClick: = @ infopopup;
pausebutton: = TStaticGUIObject. create( p, 'pausebutton.png' , 0.1 , 0.1 ) ;
pausebutton. rotationpoint. y: = 1 ;
pausebutton. x: = - 1 + 0.1 ;
pausebutton. y: = 1 ;
pausebutton. OnClick: = @ pauseclick;
infopopup( infobutton) ;
2018-05-20 11:16:50 +02:00
ticking: = true ;
2017-11-07 02:42:53 +01:00
end ;
end .