스크립트에 대한 설명:
ahk포럼에서 가져온 테트리스 게임입니다.
스크립트를 전체적으로 이해를 못할지라도 한줄 한줄 천천히 보다 보면 나중에 반드시 하나라도 얻는게 있을겁니다.
<--------------------------------------------- AHK 스크립트 내용 --------------------------------------------->
; ManyTetris 0.17
; Customizable Pocket Tetris
; Danny Ben Shitrit (aka Icarus) 2008
;
;-------------------------------------------------------------------------------
NameString := "ManyTetris"
VersionString := "0.17"
#SingleInstance Force
Gosub Init
Gosub Main
Return
;-------------------------------------------------------------------------------
; MAINS
;-------------------------------------------------------------------------------
Init:
SetWorkingDir %A_scriptDir%
IniFile = %NameString%.ini
OnMessage(0x06, "WM_ACTIVATE") ; Capture gui focus
ColorString := "Options_OnColor,Options_OffColor,Options_GuiColor,Options_FontColor"
IniHelper( "Read", IniFile, "GUI", ColorString . ",Options_Inverse" )
IniHelper( "Read", IniFile, "Sound", "Options_EnableSound" )
IniHelper( "Read", IniFile, "Recent", "Options_LastGame,Options_WinX,Options_WinY" )
Score_MaxScore := Score_GetMaxScore( Options_LastGame )
If( Options_Inverse ) {
Loop Parse, ColorString, `,
%A_LoopField% := InverseColor( %A_LoopField% )
}
Game_PushDownSpeed := 20
Game_IsPaused := false
; Arrange games drop down list
Loop games*.txt
{
SplitPath A_LoopFilename,,,,OutNameNoExt
If( A_Index = 1 and Not FileExist( "games" . Options_LastGame . ".txt" ) )
Options_LastGame := OutnameNoExt
If( A_Index <> 1 )
Gui_GamesDdl .= "|"
Gui_GamesDdl .= OutNameNoExt
}
Game_ReadGameConfig( Options_LastGame )
Loop %Game_Piece0% {
PieceID := A_Index
StringSplit PiecePart, Game_Piece%A_Index%, %A_Space%
Game_PieceStates%PieceID% := PiecePart0
Loop %PiecePart0% {
StateID := A_Index
Game_Piece%PieceID%_State%StateID% := PiecePart%A_Index%
}
}
Active_DropSpeed := Game_DropSpeed
Gosub Game_BuildGui
Return
Main:
Game_PiecesDropped := 0
Active_PlaceNewPiece()
SetTimer Game_ProgressGame, -%Active_DropSpeed%
Return
GuiEscape:
GuiClose:
Gosub SaveSettings
ExitApp
Return
;-------------------------------------------------------------------------------
; GAME
;-------------------------------------------------------------------------------
Game_ReadGameConfig( file ) {
Local FileString, ThisLine
FileRead FileString, games\%file%.txt
Game_Piece0 := 1
Loop Parse, FileString, `n,`r
{
ThisLine = %A_LoopField%
If( SubStr( ThisLine, 1, 1 ) = "#" ) {
StringTrimLeft, ThisLine, ThisLine, 1
StringSplit Param, ThisLine, %A_Space%
Game_%Param1% := Param%Param0%
Continue
}
If( ThisLine = "" or SubStr( ThisLine,1,1 ) = ";" )
Continue
If( ThisLine = "*" ) {
StringTrimRight Game_Piece%Game_Piece0%, Game_Piece%Game_Piece0%, 1
Game_Piece0++
}
Else If( ThisLine = "=" ) {
StringTrimRight Game_Piece%Game_Piece0%, Game_Piece%Game_Piece0%, 1
Game_Piece%Game_Piece0% .= " "
}
Else {
Game_Piece%Game_Piece0% .= ThisLine . "|"
}
}
; Set some defaults, in case the game configuration file does not contain
; all the elements.
; Mainly for backwards compatibility with older game templates.
If( Game_LineScore = "" )
Game_LineScore := 10
If( Game_PieceScore = "" )
Game_PieceScore := 2
If( Game_PausePenalty = "" )
Game_PausePenalty := 5
}
Game_BuildGui:
Gui Margin,2,2
Gui Color, %Options_GuiColor%,%Options_GuiColor%
Gui Font, c%Options_FontColor%
W := Game_Cols * ( Game_BoxSize+1 ) - 83
Gui Add, DDL, -TabStop w%W% vGui_GamesDdl, %Gui_GamesDdl%
GuiControl ChooseString, Gui_GamesDdl, %Options_LastGame%
Gui Add, Button, 0x8000 x+2 yp w80 hp+1 -wrap vGui_StartButton gGame_RestartGame, Start
W := Game_Cols * ( Game_BoxSize+1 ) - 1
Gui Font, s12 Bold
Gui Add, Text, x2 y+2 w%W% h21 vGui_Score Center Border, 0
Game_UpdateScore( 0 )
Game_UpdateScore( "Top: " . Score_MaxScore, true )
Gui Font, s9 Norm
X := 2
Y := 48
W := Game_BoxSize
Loop %Game_Rows% {
i := A_Index
Loop %Game_Cols% {
j := A_Index
Gui Add, ListView, x%X% y%Y% w%W% h%W% vGuiBox_%i%_%j% -TabStop -E0X200 0x4000 +Background%Options_OffColor%
DataBox_%i%_%j% := 0
X += W + 1
}
Y += W + 1
X := 2
}
GuiControl Focus, Gui_StartButton
Gui Show, x%Options_WinX% y%Options_WinY%,%NameString% %VersionString%
Return
Game_RestartGame:
Gui Submit, NoHide
Options_LastGame := Gui_GamesDdl
Gosub Reload
Return
Game_ProgressGame:
Game_ProgressGame()
Return
Game_ProgressGame() {
Global
; Drops a piece by one row if possible
; Else, remove the completed lines if any
; And create a new piece on top
If( Not Active_DropPiece() ) {
Game_SetNewDropSpeed()
If( Active_PrevDropSpeed )
Active_PrevDropSpeed := Active_DropSpeed
Active_CheckCompletedLines()
Active_PlaceNewPiece()
SetTimer Game_ProgressGame, -%Active_DropSpeed%
}
}
Game_SetNewDropSpeed() {
Global
If( Game_DropSpeedPoints )
Active_DropSpeed := Game_DropSpeed - ( Trim( Game_Score/Game_DropSpeedPoints )*Game_DropSpeedIncrease )
Else
Active_DropSpeed := Game_DropSpeed - ( Game_PiecesDropped*Game_DropSpeedIncrease )
If( Active_DropSpeed < Game_MaxDropSpeed )
Active_DropSpeed := Game_MaxDropSpeed
;Tooltip % Active_DropSpeed ; DEBUG SPEED
}
Game_DataToGui( fromRow, toRow ) {
; Reads a range of rows in the data grid, and reflect it in the GUI
;_____________________________________________________________________________
Local Row, Color
Loop %toRow% {
Row := fromRow + A_Index - 1
Loop %Game_Cols% {
Col := A_Index
Color := DataBox_%Row%_%Col% ? Options_OnColor : Options_OffColor
GuiControl ,+Background%Color%, GuiBox_%Row%_%Col%
}
}
}
Game_GameOver() {
; Called when we can longer place new pieces
;_____________________________________________________________________________
Local Row, Col
SetTimer Game_ProgressGame, Off
Critical
SoundPlay( "Over" )
Loop %Game_Rows% {
Active_RemoveRow( Game_Rows )
Game_DataToGui( 1, Game_Rows )
Sleep 50
}
Critical Off
Game_SaveHighScore()
Sleep 2000
Game_UpdateScore( 0 )
Active_DropSpeed := Game_DropSpeed
Gosub Main
}
Game_UpdateScore( score, displayonly=false ) {
Global Game_Score
If( score = 0 ) {
Game_Score := 0
GuiControl,,Gui_Score, 0
}
Else If( not displayOnly ) {
Game_Score += score
GuiControl,,Gui_Score, % Game_Score
}
Else {
GuiControl,,Gui_Score, % score
}
}
Game_SaveHighScore() {
Global
If( Game_Score > Score_MaxScore ) {
Score_MaxScore := Game_Score
Score_SetMaxScore( Options_LastGame, Score_MaxScore )
}
}
;-------------------------------------------------------------------------------
; ACTIVE
;-------------------------------------------------------------------------------
Active_PlaceNewPiece() {
; Gets a random piece and places it at the top of the board
; Ends the game if it cannot place that piece
;_____________________________________________________________________________
Local Col, Row, Failed, PieceRows
Random Active_Piece, 1, %Game_Piece0%
Game_PiecesDropped++
Active_PieceStates := Game_PieceStates%Active_Piece%
Active_PieceState := 1
Active_PieceString := Game_Piece%Active_Piece%_State1
StringSplit PieceRow, Game_Piece%Active_Piece%_State1, |
Active_BaseRow := 1
Active_PieceCols := StrLen( PieceRow1 )
Active_BaseCol := Round( 1 + (Game_Cols/2) - (Active_PieceCols/2 ) )
; Update the data grid
Failed := false
Col := Active_BaseCol
Row := Active_BaseRow
Loop Parse, Active_PieceString
{
If( A_LoopField = "+" ) {
If( DataBox_%Row%_%Col% <> 1 )
DataBox_%Row%_%Col% := 2
Else
Failed := true
}
Else If( A_LoopField = "|" ) {
Col := Active_BaseCol-1
Row++
}
Col++
}
Active_PieceRows := Row
; Update the GUI
If( Failed ) {
Game_DataToGui( 1, Active_PieceRows )
Game_GameOver()
}
Else {
SoundPlay( "Piece" )
Game_DataToGui( 1, Active_PieceRows )
}
Return true
}
Active_PieceCanMove( fromRow, toRow, rowOffset, colOffset ) {
; Gets a range of rows to check and row+col offsets and returns true if the
; piece (that was found in the range of rows) can move to the specified
; offsets.
;_____________________________________________________________________________
Local Result, OldRow, OldCol, NewRow, NewCol
Result := true
Loop %Active_PieceRows% {
OldRow := Active_BaseRow + Active_PieceRows - A_Index
NewRow := OldRow+rowOffset
Loop %Game_Cols% {
OldCol := A_Index
NewCol := OldCol+ColOffset
If( ( DataBox_%OldRow%_%OldCol% = 2 ) and ( DataBox_%NewRow%_%NewCol% = 1 or NewRow > Game_Rows or NewCol < 1 or NewCol > Game_Cols ) ) {
Result := false
Break
}
}
}
Return Result
}
Active_LockPiece( fromRow, toRow ) {
; Locks a piece in place, in the data grid only (not GUI)
; It will replace all the 2 values in the specified row range to 1
;_____________________________________________________________________________
Local Row, Col
Loop %toRow% {
Row := fromRow + A_Index - 1
Loop %Game_Cols% {
Col := A_Index
If( DataBox_%Row%_%Col% = 2 )
DataBox_%Row%_%Col% := 1
}
}
}
Active_DropPiece() {
; Drops the piece by one line
; If it is unable to, it will lock the piece in place (convert 2s to 1s)
;_____________________________________________________________________________
Local OldRow, NewRow
; If cant drop piece anymore, change active piece to static and return false
If( Not Active_PieceCanMove( Active_BaseRow, Active_BaseRow + Active_PieceRows, 1, 0 ) ) {
Active_LockPiece( Active_BaseRow, Active_BaseRow+Active_PieceRows-1 )
Return false
}
Critical
Loop %Active_PieceRows% {
OldRow := Active_BaseRow + Active_PieceRows - A_Index
NewRow := OldRow+1
Loop %Game_Cols% {
Col := A_Index
If( DataBox_%OldRow%_%Col% = 2 ) {
DataBox_%OldRow%_%Col% := 0
DataBox_%NewRow%_%Col% = 2
}
}
}
If( Active_DropSpeed > Game_PushDownSpeed )
SoundPlay( "Step" )
Game_DataToGui( Active_BaseRow, Active_PieceRows+1 )
Active_BaseRow++
SetTimer Game_ProgressGame, -%Active_DropSpeed%
Critical Off
Return true
}
Active_MovePiece( dir ) {
; Moves a piece one block to the right (1) or left (-1)
; Returns false on failure
;_____________________________________________________________________________
Local OldCol, NewCol
; If cant move piece anymore, return false
If( Not Active_PieceCanMove( Active_BaseRow, Active_BaseRow + Active_PieceRows, 0, dir ) ) {
Return false
}
Critical
Loop %Active_PieceRows% {
Row := Active_BaseRow + A_Index - 1
Loop %Game_Cols% {
OldCol := dir < 0 ? A_Index : Game_Cols - A_Index + 1
NewCol := OldCol + dir
If( DataBox_%Row%_%OldCol% = 2 ) {
DataBox_%Row%_%OldCol% := 0
DataBox_%Row%_%NewCol% := 2
}
}
}
Active_BaseCol += dir
Game_DataToGui( Active_BaseRow, Active_PieceRows+1 )
Critical Off
Return true
}
Active_PieceCanRotate( fromState, toState ) {
; Returns true if the active piece can rotate
;_____________________________________________________________________________
Local Result, Row, Col
Result := true
; Check GUI edges
If( Active_BaseCol < 1 or Active_BaseCol+Active_PieceCols-1 > Game_Cols )
Result := false
; Check collision with other pieces
Loop %Active_PieceRows% {
If( not Result )
Break
Row := Active_BaseRow+A_Index-1
Loop %Active_PieceCols% {
Col := Active_BaseCol+A_Index-1
If( DataBox_%Row%_%Col% = 1 ) {
Result := false
Break
}
}
}
Return Result
}
Active_RotatePiece() {
; Rotates a piece
;_____________________________________________________________________________
Local Col, Row, NewPieceState
NewPieceState := Active_PieceState < Active_PieceStates ? Active_PieceState+1 : 1
; If cant move piece anymore, return false
If( Not Active_PieceCanRotate( Active_PieceState, NewPieceState ) ) {
Return false
}
Else {
Critical
Active_PieceState := NewPieceState
Active_PieceString := Game_Piece%Active_Piece%_State%Active_PieceState%
Row := Active_BaseRow
Col := Active_BaseCol
Loop Parse, Active_PieceString
{
If( A_LoopField = "+" )
DataBox_%Row%_%Col% := 2
Else If( A_LoopField = "-" )
DataBox_%Row%_%Col% := 0
Else If( A_LoopField = "|" ) {
Col := Active_BaseCol-1
Row++
}
Col++
}
Critical Off
}
Game_DataToGui( Active_BaseRow, Active_PieceRows+1 )
Return true
}
Active_CheckCompletedLines() {
; Check for completed lines and update the score (even if there are no
; completed lines)
Local Row, FullRow
Critical
; Identify rows for removal
Loop %Game_Rows% {
FullRow := true
Row := Game_Rows-A_Index+1
Loop %Game_Cols% {
Col := A_Index
If( DataBox_%Row%_%Col% <> 1 ) {
FullRow := false
Continue
}
}
If( FullRow ) {
Active_ScoreFactor++
Active_CycleScore += ( Active_ScoreFactor * Game_LineScore )
Active_RemoveRow( Row )
Active_CheckCompletedLines()
Game_DataToGui( 1, Game_Rows )
Return
}
}
If( Active_CycleScore ) {
Gui Submit, NoHide
SoundPlay( "Line", true )
Game_UpdateScore( Active_CycleScore )
}
Else {
Gui Submit, NoHide
Game_UpdateScore( Game_PieceScore )
}
Active_ScoreFactor := 0
Active_CycleScore := 0
Critical Off
}
Active_RemoveRow( targetRow ) {
Local Col, Row, HigherRow
Critical
Loop % targetRow-1 {
Row := targetRow-A_Index+1
HigherRow := Row-1
Loop %Game_Cols% {
Col := A_Index
DataBox_%Row%_%Col% := DataBox_%HigherRow%_%Col%
}
}
; Reset first row to zeros
Loop %Game_Cols% {
Col := A_Index
DataBox_1_%Col% := 0
}
Critical Off
}
Active_DropKeyReleased:
; Called by timer whenever the Down key is pressed.
; Will restore original drop speed when key is released.
If( not GetKeyState( "Down", "P" ) ) {
SetTimer Active_DropKeyReleased, Off
Active_DropSpeed := Active_PrevDropSpeed
Active_PrevDropSpeed := 0
}
Return
;-------------------------------------------------------------------------------
; SCORE
;-------------------------------------------------------------------------------
Score_GetMaxScore( game ) {
Global IniFile
NiceGameName := RegExReplace( game, "[W]" )
IniRead Result, %IniFile%, Score, %NiceGameName%, 0
Return Result
}
Score_SetMaxScore( game, score ) {
Global IniFile
NiceGameName := RegExReplace( game, "[W]" )
IniWrite %score%, %IniFile%, Score, %NiceGameName%
}
;-------------------------------------------------------------------------------
; DEBUG
;-------------------------------------------------------------------------------
Debug_ShowGrid() {
Local Row, Col, Result
Result := ""
Loop %Game_Rows% {
Row := A_Index
Loop %Game_Cols% {
Col := A_Index
Result .= DataBox_%Row%_%Col% . " "
}
Result .= "`n"
}
Msgbox % Result
}
;-------------------------------------------------------------------------------
; MISC
;-------------------------------------------------------------------------------
IniHelper( op, file, section, keys ) {
; Reads or writes specific keys from an INI section, and sets the values as
; global variables
;_____________________________________________________________________________
Global
StringSplit iniKey, keys, `,
Loop %iniKey0% {
If( op = "Read" ) {
IniKey := % iniKey%A_Index%
IniRead %IniKey%, %file%, %section%, %IniKey%
}
Else If( op = "Write" ) {
IniValue := % iniKey%A_Index%
IniValue := %IniValue%
IniKey := iniKey%A_Index%
IniWrite %IniValue%, %file%, %section%, %IniKey%
}
}
}
InverseColor( color ) {
SetFormat Integer, H
Result := ""
Loop Parse, Color
{
Result .= 0xF - A_LoopField
StringReplace Result, Result, 0x
}
SetFormat Integer, D
Return Result
}
SoundPlay( sound, wait=false ) {
Global Options_EnableSound
If( Not Options_EnableSound )
Return
Wait := wait ? "WAIT" : ""
SoundPlay sounds\%sound%.wav, %WAIT%
}
Trim( num ) {
StringSplit NumElement, num, .
Return %NumElement1%
}
SaveSettings:
Gui +LastFound
WinGetPos Options_WinX, Options_WinY
IniHelper( "Write", IniFile, "Recent", "Options_LastGame,Options_WinX,Options_WinY" )
Game_SaveHighScore()
Return
Reload:
Gosub SaveSettings
Reload
Return
WM_ACTIVATE() {
Global NameString, Game_IsPaused
IfWinActive %NameString% ahk_Class AutoHotkeyGUI
{
If( Game_IsPaused )
Gosub p
}
Else If( !Game_IsPaused )
Gosub p
}
;-------------------------------------------------------------------------------
; HOTKEYS
;-------------------------------------------------------------------------------
#IfWinActive ManyTetris ahk_Class AutoHotkeyGUI
Right::
If( Game_IsPaused )
Gosub p
Active_MovePiece( 1 )
Return
Left::
If( Game_IsPaused )
Gosub p
Active_MovePiece( -1 )
Return
Up::
If( Game_IsPaused )
Gosub p
Active_RotatePiece()
Return
Down::
If( Game_IsPaused )
Gosub p
; If key is already pushed, do nothing (the Active_DropKeyReleased is working)
If( Active_PrevDropSpeed )
Return
SetTimer Game_ProgressGame, Off
Active_PrevDropSpeed := Active_DropSpeed
Active_DropSpeed := Game_PushDownSpeed
SetTimer Active_DropKeyReleased, 20
Gosub Game_ProgressGame
Return
p::
Game_IsPaused := !Game_IsPaused
If( Game_IsPaused )
SetTimer Game_ProgressGame, Off
Else {
If( Game_Score > 0 )
Game_Score -= Game_PausePenalty
SetTimer Game_ProgressGame, -%Active_DropSpeed%
}
Return
'AutoHotKey' 카테고리의 다른 글
gui연습삼아 만든 가위바위보; ( 스크랩 ) (0) | 2014.09.20 |
---|---|
프리셀 게임 보조프로그램 (0) | 2014.09.20 |
암호 디컴파일 스크립트 (0) | 2014.09.20 |
디아블로3 2컴용 자동사냥 봇(공부용 스크립트) (1) | 2014.09.20 |
오토핫키 강좌 (초보편 #08)_스크랩 (0) | 2014.09.20 |