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; usemegabombs: boolean; speedup: boolean; speed: single; status: TGUITextObject; info: TGUITextObject; infobutton: TStaticGUIObject; pausescreen: TGUITextObject; pausebutton: TStaticGUIObject; enemytext: TGUITextObject; enemytextStartTime: qword; gametime: qword; function getNextBulletPos: integer; function pauseclick(sender: tobject): boolean; function infoPopup(sender: tobject): boolean; function HideInfo(sender: tobject): boolean; procedure spawnPlayer; procedure spawnTarget1; procedure spawnTarget2; public procedure SpawnEnemyText; 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 uses registry; 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 if iskeydown(VK_W) and iskeydown(VK_I) and iskeydown(VK_N) then begin usedcheats:=true; 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; if keventtype=0 then begin ct:=GetTickCount64; if key=vk_space then begin if ctnil then target1.rotation:=((arctan2(player.y-target1.y, player.x-target1.x))*(180)/pi)+90; if target2<>nil then target2.rotation:=((arctan2(player.y-target2.y, player.x-target2.x))*(180)/pi)+90; if target1<>nil then begin i:=getNextBulletPos; 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; 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; if enemytext<>nil then enemytext.render; end; procedure TGame2.gametick(currentTime: qword; diff: integer); var i,j: integer; megabombsecleft: integer; begin if ticking=false then exit; 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 //.... if target1<>nil then target1.rotation:=((arctan2(player.y-target1.y, player.x-target1.x))*(180)/pi)+90; if target2<>nil then target2.rotation:=((arctan2(player.y-target2.y, player.x-target2.x))*(180)/pi)+90; for i:=0 to length(bullets)-1 do if bullets[i]<>nil then begin if bullets[i].megabomb then begin bullets[i].rotation:=((arctan2(player.y-bullets[i].y, player.x-bullets[i].x))*(180)/pi)+90; bullets[i].speed:=bullets[i].speed+0.00001*(diff/100); end; bullets[i].travel(diff); if bullets[i].checkCollision(player) then begin player.damage(bullets[i].damage); if player.isdead then begin player.explode; //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; //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 begin target1.damage(bullets[i].damage); if target1.isdead then begin target1.explode; if (target2<>nil) and (target2.isdead=false) then begin spawnEnemyText; target2.health:=min(target2.health+20, target2.MaxHealth); //just increase the level of assholerly a little bit more end; end; freeandnil(bullets[i]); end; 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 begin target2.damage(bullets[i].damage); if target2.isdead then begin target2.explode; if (target1<>nil) and (target1.isdead=false) then begin spawnEnemyText; target1.health:=min(target1.health+20, target1.MaxHealth); end; end; 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; if enemytext<>nil then begin megabombsecleft:=ceil(integer((3000-(gametime-enemytextStartTime)))/1000); 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; 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 usemegabombs:=false; if target1<>nil then target1.enemycharged:=false; if target2<>nil then target2.enemycharged:=false; freeandnil(player); spawnplayer; if target1=nil then spawnTarget1; target1.health:=200; if target2=nil then spawnTarget2; target2.health:=200; status.text:=format('Player Health: '#13#10'%d',[player.health]); end; if (target1=nil) and (target2=nil) then begin ticking:=false; showmessage('well done'); 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; gamewon(); exit; end; end; 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:=18; enemytext.Text:='You will pay for this!'#13#10'Activating megabombs'#13#10''+inttostr(3); enemytextStartTime:=gametime; 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:=18; 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:=190; 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; procedure TGame2.spawnPlayer; begin player:=TPlayerWithHealth.create(false); player.x:=0; player.y:=0.8; player.health:=100; player.maxhealth:=100; end; procedure TGame2.spawnTarget1; begin target1:=TPlayerWithHealth.create(true); target1.x:=0-target1.width-0.005; target1.y:=-0.8; target1.health:=200; target1.maxhealth:=200; target1.rotation:=180; end; procedure TGame2.spawnTarget2; begin target2:=TPlayerWithHealth.create(true); target2.x:=target2.width+0.005; target2.y:=-0.8; target2.health:=200; target2.maxhealth:=200; target2.rotation:=180; 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; spawnPlayer; spawnTarget1; spawnTarget2; status:=TGUITextObject.create; status.firstTextBecomesMinWidth:=true; status.font.Size:=78; 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); ticking:=true; end; end.