attempt to make tetris in starbound game.

The Partridge Family were neither partridges nor a family. Discuss.
Post Reply
User avatar
viruskiller
Posts: 399
Joined: June 14th, 2012, 5:07 pm

attempt to make tetris in starbound game.

Post by viruskiller » June 14th, 2014, 9:05 am

so i got alot of time on my hands lately, and decided to take on a close to/imposible task.

making a tetris game inside starbound game! (its a terraria like game ).

the only mechanics i can use are logic gates,and light bulbs for the blocks.

so i'm making this post in hope u can get me some ideas on how to go about it.

so far i got the concept for the block array and the idea for line full check ,deleting and moving the lines down and whatnot, but the real problem comes hadling the shape going down, and probably the hardest part is rotating it.
i was thinking to make like a stack thing to store the coords of the shape and then have some predefined steps for moving it and rotating it, but i don't know how to select what pixel i want to change .
in essence i probably need to make a sort of computer first and have that run tetris, don't think it's possible to have it all hardwired or something.(by hardwired i mean no software to be loaded by some computer thing, think of it like a electronic tetris game or something)

User avatar
chili
Site Admin
Posts: 3948
Joined: December 31st, 2011, 4:53 pm
Location: Japan
Contact:

Re: attempt to make tetris in starbound game.

Post by chili » June 14th, 2014, 12:19 pm

Well, maybe you should start with something simpler. Try to make a simple 4-bit ALU.

I'm not sure once you add all the memory subsystem and try to get a ROM going that your 2D map will give you enough elbow room to route all the signals though.
Chili

User avatar
viruskiller
Posts: 399
Joined: June 14th, 2012, 5:07 pm

Re: attempt to make tetris in starbound game.

Post by viruskiller » June 14th, 2014, 2:15 pm

tetris has a grid of 10x20 so i need to make it 8 bit to be able to address all the points in the table:/ , and the main reason i don't wana do it is because then i'd have to figure out what functions i need for it, and then program the thing , and i'm not even sure if making the whole thing run trough an ALU will be fast enough or if it even run at all..
thre was a guy that made a comuter inside minecraft and that had a draw line function that worked preety much the same way as the one in the tutorials, the problem was that the cpu had a clock cycle of about 2 seconds, so it took like 15 min to calculate all the x and y values for a line about 32 pixels in length.
now i know tetris doesn't require that many calculations per frame, i think i can get away with 1-4 compare operations,and 4-8 increment operations for the shape,the line check and empty line can be hardware handled.
one thing i don't know how to do with that is how to make it loop, guess i have to have a go to instruction built in.
anyway while typing this i just googled tetris assembly to get a glimpse of how is done with such limited instruction set

Code: Select all

---- GAME LOOP, PART 1 START: Choose a tetra randomly and draw it on initial poisition on screen ---- 
    ; Set the tetraType variable randomly:
    mov  si, seed
    call Randomizer
    xor  ah, ah
    mov  bl, MEANING_OF_LIFE
    div  bl
    mov  byte[tetraType], al

    ; Set the rotation to zero and layoutPos to its starting point:
    mov  byte[rotation], 0
	mov  byte[layoutPos], 3
    mov  byte[layoutPos+1], 0
	
    ; Set the control net positions:
    Call SetNewBlockFormation

    ; See if the player has failed:
    mov  byte[rotationTest], 0
	mov  word[layoutPosTest], 0003h
    Call NewFormationCheck
    cmp  dl, 0
    jne  _DrawBlocks
    jmp  GameOver

    ; Draw the block sprites on screen: 
    _DrawBlocks:
	Call CopyNewToOld
    Call UpdateBlockSprites
;---- GAME LOOP, PART 1 END ----


;---- GAME LOOP, PART 2 START: Wait key presses and delay to pass, and do something accordingly ----
CheckCtrl:
    ; Save any present key scancode from port 60h to the keyStroke variable. If it isn't the left ctrl key, check for the left key. 
    GetKey keyStroke
    cmp  byte[keyStroke], LCTRL
    jne  CheckLeft

	; See if enough time has passed to allow a rotation by subtracting rotTime from the current time and see if the difference is large enough:
    Call CentiSec
    mov  ecx, ebx
    sub  ebx, dword[rotTime]
    cmp  ebx, ROTATION_DELAY
    jl   CheckLeft        
	
	; See if a rotation would be possible by increasing the rotationTest variable one step and calling NewFormationCheck:
    mov  al, byte[rotation]
    inc  al
	cmp  al, 4
	jne  _Rot
	mov  al, 0
	_Rot:
    mov  byte[rotationTest], al
    Call NewFormationCheck
	cmp  dl, 1
	jne  CheckLeft
	
	; A rotation was possible, so update the rotation and rotTime variables:
	mov  byte[rotation], al
    mov  dword[rotTime], ecx

	; Save off the old block positions (so that UpdateBlockSprites can put black boxes at these positions), set a new formation according to the updated rotation variable, and update the on-screen sprites accordingly:
    call CopyNewToOld
    Call SetNewBlockFormation
    Call UpdateBlockSprites

; Do the equivalent of the above, for the left key:
CheckLeft:
    ; Save any present key scancode from port 60h to the keyStroke variable. If it isn't the left key, check for the right key.
    GetKey keyStroke
    cmp  byte[keyStroke], LEFT
    jne  CheckRight

    Call CentiSec
    mov  ecx, ebx
    sub  ebx, dword[moveTime]
    cmp  ebx, MOVE_DELAY
    jl   CheckRight        

	mov  ax, word[layoutPos]
	cmp  al, 0
	jna  CheckRight
	dec  al
	mov  word[layoutPosTest], ax
	mov  al, byte[rotation]
	mov  byte[rotationTest], al
	Call NewFormationCheck
	cmp  dl, 1
	jne  CheckRight
	
    mov dword[moveTime], ecx

    call CopyNewToOld
    sub  byte[layoutPos], 1    
    Call UpdateBlockSprites

; Do the equivalent of the above, for the right key:
CheckRight:
    GetKey keyStroke
    cmp  byte[keyStroke], RIGHT
    jne  CheckDown

    Call CentiSec
    mov  ecx, ebx
    sub  ebx, dword[moveTime]
    cmp  ebx, MOVE_DELAY
    jl   CheckDown
	
	mov  al, byte[rotation]
	mov  byte[rotationTest], al
	mov  ax, word[layoutPos]
	inc  al
	mov  word[layoutPosTest], ax
    Call NewFormationCheck
	cmp  dl, 1
	jne  CheckDown      

    mov dword[moveTime], ecx

    call CopyNewToOld
    add  byte[layoutPos], 1
    Call UpdateBlockSprites

; Do the equivalent of the above, for the down key:
CheckDown:
    GetKey keyStroke
    cmp  byte[keyStroke], DOWN
    jne  CheckAlt

    Call CentiSec
    mov  ecx, ebx
    sub  ebx, dword[moveTime]
    cmp  ebx, MOVE_DELAY
    jl   CheckAlt
	
	mov  dword[fallTime], ecx
	mov  al, byte[rotation]
	mov  byte[rotationTest], al
	mov  ax, word[layoutPos]
	inc  ah
	mov  word[layoutPosTest], ax
    Call NewFormationCheck
	cmp  dl, 1
	je  _NotBlockedDown        

	Call RecordBlockPositions
	Call TerminateFilledLines
	jmp  GameLoop
	
	_NotBlockedDown:
    mov dword[moveTime], ecx
    call CopyNewToOld
    add  byte[layoutPos+1], 1

    Call UpdateBlockSprites
	
CheckAlt:
    GetKey keyStroke
    cmp  byte[keyStroke], LALT
    jne  CheckFall
	
	Call CentiSec
    mov  ecx, ebx
	sub  ebx, dword[startoverTime]
	cmp  ebx, STARTOVER_DELAY
	jl   CheckCtrl
	mov  ebx, ecx
    sub  ebx, dword[moveTime]
    cmp  ebx, MOVE_DELAY
    jl   CheckFall
	mov  dword[moveTime], ecx
	
	mov  al, byte[rotation]
	mov  byte[rotationTest], al
	mov  ax, word[layoutPos]
	_ShootDown:
	inc  ah
	mov  word[layoutPosTest], ax
    Call NewFormationCheck
	cmp  dl, 1
	je  _ShootDown       
	
	dec  ah
	call CopyNewToOld
    mov  byte[layoutPos+1], ah
	Call RecordBlockPositions
	Call UpdateBlockSprites
	Call TerminateFilledLines
	
	mov  dword[startoverTime], ecx
	jmp  GameLoop

; Check to see if it's time for the tetra to fall one step; if so, make it fall: 
CheckFall:
    ; Check to see if it's time for a fall, by taking in the current time in centiseconds and subtracting the time from the fallTime variable.
    Call CentiSec
    mov  ecx, ebx
	sub  ebx, dword[startoverTime]
	cmp  ebx, STARTOVER_DELAY
	jl   CheckCtrl
	mov  ebx, ecx
    sub  ebx, dword[fallTime]
    cmp  ebx, FALL_DELAY
    jl   CheckEsc
	
    ; Load the rotationTest and layoutPosTest variables appropriately such that NewFormationCheck will check all block positions one step below:
	mov  al, byte[rotation]
	mov  byte[rotationTest], al
	mov  ax, word[layoutPos]
	inc  ah
	mov  word[layoutPosTest], ax
    Call NewFormationCheck
	cmp  dl, 1
	je  _NotBlockedFall     
    
    ; The tetra is blocked by something below, so record the current block positions in the control net:
	Call RecordBlockPositions
    
    ; Eliminate any filled lines (that have just been filled as a consequence of the stopped tetra): 	
    Call TerminateFilledLines
	mov  dword[startoverTime], ecx
	jmp  GameLoop
	
	; We're not blocked below so move the blocks one step down:
	_NotBlockedFall:
    mov dword[fallTime], ecx
    call CopyNewToOld
    add  byte[layoutPos+1], 1

    Call UpdateBlockSprites
	
; If the user hasn't pressed the escape-key, start the game loop over:
CheckEsc:   
    cmp  byte[keyStroke], ESCAPE
    jne CheckCtrl
	
;---- GAME LOOP, PART 2 END ----

GameOver:

QuitGame:
; Go back to text mode and quit to DOS:
SetTextMode
QuitToDos

;---------------------------------------------------------------------------------------------------------------
; NewFormationCheck -- Checks if the formation proposed by the tetraType and rotationTest variables would
; be possible, at the layout position given by layoutPosTest. "Possible" is defined as the case where the blocks in
; the proposed formation don't overlap with occupied space in the control net and their positions are all within
; the play field. AL is set according to below:
; "Possible"  => AL:=1 
; !"Possible" => AL:=0
;--------------------------------------------------------------------------------------------------------------
NewFormationCheck:
	push eax
	push bx
	push cx
	push si
	push di

	; Copy the suggested formation to a test array, blockPosTest:
    xor  ah, ah					; Calculate the source address and put it in SI.
    mov  al, BYTES_PER_TETRA
    mul  byte[tetraType]
    mov  si, ax

    add  si, tetra

    mov  al, byte[rotationTest]
    xor  ah, ah
    xor  bh, bh
    mov  bl, 8
    mul  bl
    add  si, ax 

    mov  di, blockPosTest		; Set the distination address to DI.

    mov  cx, 2					; Copy all two double words (two bytes for each of the four blocks) of tetra data.
CopyFormation:
    mov  eax, dword[si]
    mov  dword[di], eax
    add  si, 4
    add  di, 4
    loop CopyFormation
	
	; Add the value of layoutPosTest to all of the block positions.
	mov  ax, word[layoutPosTest]
	add  byte[blockPosTest], al
	add  byte[blockPosTest+2], al
	add  byte[blockPosTest+4], al
	add  byte[blockPosTest+6], al
	add  byte[blockPosTest+1], ah
	add  byte[blockPosTest+3], ah
	add  byte[blockPosTest+5], ah
	add  byte[blockPosTest+7], ah
	
	mov  cx, 0
; Loop through each suggested block position; the bytes in blockPosTest.
TestLoop:
	; See if the position's x-component < CONTROLNET_WIDTH. If not, set DL:=0 and ret.
	mov  bx, blockPosTest
	add  bx, cx
	cmp  byte[bx], CONTROLNET_WIDTH
	jl   _CheckY
	mov  dl, 0
	jmp  _Through
	
	; Do the same thing with the position's y-component with CONTROLNET_HEIGHT.
	_CheckY:
	inc  bx
	cmp  byte[bx], CONTROLNET_HEIGHT
	jl   _CheckControlNet
	mov  dl, 0
	jmp  _Through
	
	; Get the byte of the same position in the controlNet array to see if it's 0 or something else. If not 0, set DL:=0 and ret:
	_CheckControlNet:
	mov  al, byte[bx]
	dec  bx
	mov  dl, byte[bx]
	Call GetControlNetValue
	cmp  bl, 0
	je   _LoopAgain
	mov  dl, 0
	jmp  _Through
	
	_LoopAgain:
	add  cx, 2
	cmp  cx, 8
	jl   TestLoop	
	
	; If we've made it this far, it means there are no obstacles to moving in the suggested direction, so set DL:=1 and return:
	mov  dl, 1

	_Through:	
	pop  di
	pop  si
	pop  cx
	pop  bx
	pop  eax
	
    ret
;END of NewFormationCheck

;---------------------------------------------------------------------------------------------------------
; UpdateBlockSprites -- Calculates the x and y screen coordinates for all four blocks, from the block
; position byte variables; draws filled black boxes on the old positions and new sprites on the new positions. 
;---------------------------------------------------------------------------------------------------------
UpdateBlockSprites:
    push ax
    push bx
    push cx
    push si
    push di    

    mov  cx, 0
BoxDrawLoop:
    ; Calculate the positions:
    mov  si, layoutPosOld
    mov  bp, blockPosOld     
    Call GetScreenPositions

    ; Draw the black box:
    DrawFullRect word[xpos], word[ypos], BLOCK_WIDTH, BLOCK_HEIGHT, BLACK
    
    inc  cx
    cmp  cx, 4 
    jne  BoxDrawLoop

    mov  cx, 0   
SpriteDrawLoop:    
    ; Calculate the positions:
    mov  si, layoutPos
    mov  bp, blockPos
    Call GetScreenPositions

    ; Calculate the adress of the sprite to use:
    xor  ah, ah
    mov  al, byte[tetraType]
    mov  dx, TETRA_SPRITE_SIZE
    mul  dx
    mov  word[sprite], ax
    add  word[sprite], spritedata
           
    ; Draw the sprite:
    DrawSprite word[xpos], word[ypos], word[sprite]
    
    inc  cx
    cmp  cx, 4
    jne  SpriteDrawLoop

    pop  di
    pop  si
    pop  cx
    pop  bx
    pop  ax

    ret
; END of UpdateBlockSprites

;---------------------------------------------------------------------------------------------------------
; TerminateFilledLines -- Eliminates any filled line that has occurred as a consequence of the tetra that
; just stopped falling.
;---------------------------------------------------------------------------------------------------------
TerminateFilledLines:
	push ax
	push bx
	push cx
	push dx
	push bp
	
	mov  byte[lineCount], 0
	mov  byte[yPosCheck], 21
	mov  byte[yPosCheck+1], 21
	mov  byte[yPosCheck+2], 21
	mov  cx, 7
	add  cx, 2
	
EliminateLine:
	cmp  cx, 1
	je   UpdateControlNet
	
	sub  cx, 2
	
	mov  bx, blockPos
	add  bx, cx
	xor  ah, ah
	mov  al, byte[bx]
	add  al, byte[layoutPos+1]
	
	mov  bx, yPosCheck
	mov  dl, 0
	_CheckYPos:
	cmp  al, byte[bx]
	je   EliminateLine
	inc  bx
	inc  dl
	cmp  dl, 3
	jl   _CheckYPos
	
	mov  dl, 0
	_CheckThroughLine:
	Call GetControlNetValue
	cmp  bl, 0
	je   EliminateLine
	inc  dl
	cmp  dl, CONTROLNET_WIDTH
	jl  _CheckThroughLine
	
	mov  dx, ax
	mov  byte[elimLine], al
	Call MoveControlNetPiece

	cmp  cx, 1
	je   _LineCount
	mov  ax, cx
	mov  bl, 2
	dec  al
	div  bl
	xor  ah, ah
	mov  bp, yPosCheck
	add  bp, ax
	mov  byte[bp], dl
	_LineCount:
	add  byte[lineCount], 1
	jmp  EliminateLine
	
UpdateControlNet:
	cmp  byte[lineCount], 0
	jz   _SkipRedraw
	Call RedrawControlNet
	_SkipRedraw:
	pop  bp
	pop  dx
	pop  cx
	pop  bx
	pop  ax
	
	ret
;END of TerminateFilledLines

;---------------------------------------------------------------------------------------------------------
; MoveControlNetPiece -- Copies data in the control net; the region between X=0, Y=m and X=9, Y=AX-1
; (where m is the smallest Y-coordinate for which the line is not nulled), is displaced one step down.
; If Y!=0, a nulled line is placed at Y' = Y-1.
; - Input:
;	AX: Y-coordinate for the line that is to be eliminated.
; - Outout:
;	Modifications to the controlNet and controlNetTemp arrays according to above.
;---------------------------------------------------------------------------------------------------------
MoveControlNetPiece:
	push ax
	push bx
	push cx
	push dx
	push si
	push di
	push bp

	xor  ah, ah
	mov  bp, ax
	
	; Find m:
	mov  cx, CONTROLNET_WIDTH
	mov  al, 0
	mov  dl, 0
    _FindmLineLoop:
	Call GetControlNetValue
	cmp  bl, 0
	jne  _mFound
	inc  dl
	loop _FindmLineLoop
	
	inc  al
	mov  dl, 0
	mov  cx, CONTROLNET_WIDTH
	jmp  _FindmLineLoop
	_mFound:
	mov  byte[m], al
	
CalculateAdressDisplacement:
	; Calculate the address displacement for the starting coordinate and put to some register.
	mov  bl, CONTROLNET_WIDTH
	xor  ah, ah
	mul  bl
	mov  dx, ax
	
	; Calculate the address displacement for the ending coordinate and put to some regiser.
	mov  ax, bp
	dec  al
	mul  bl
	add  al, 9
	
	; Calculate the difference of the displacement addresses and put in the second register.
	sub  ax, dx
	
	; Do a copy loop from address controlNet+[starting coordinate adress displacement] in a number of steps equal to the difference above, to the temp variable.
	mov  cx, ax
	inc  cx
	mov  si, controlNet
	add  si, dx
	mov  di, controlNetTemp
	_CopyFromControlNet:
	mov  bl, byte[si]
	mov  byte[di], bl
	inc  si
	inc  di
	loop _CopyFromControlNet
	
	; Add CONTROLNET_WIDTH to the starting coordinate address displacement.
	add  dx, CONTROLNET_WIDTH
	
	; Do a copy loop from the temp variable to control net from the new starting coordinate address.
	mov  cx, ax
	inc  cx
	mov  si, controlNetTemp
	mov  di, controlNet
	add  di, dx
	_CopyToControlNet:
	mov  bl, byte[si]
	mov  byte[di], bl
	inc  si
	inc  di
	loop _CopyToControlNet
	
	; Nullify the m line:
	mov  di, controlNet
	mov  al, byte[m]
	xor  ah, ah
	mov  bl, CONTROLNET_WIDTH
	mul  bl
	add  di, ax
	mov  dword[di], 00000000h
	add  di, 4
	mov  dword[di], 00000000h
	add  di, 4
	mov  word[di], 0000h
	
	pop  bp
	pop  di
	pop  si
	pop  dx
	pop  cx
	pop  bx
	pop  ax
	
	ret
;END of MoveControlNetPiece


;-----------------------------------------------------------------------------------------------------------
; RedrawControlNet -- Updates the on-screen graphics on the playfield according to the updated controlNet
; array. Updates graphics on the screen corresponding to control net coordinates (0, m-lineCount) and (9, DL). 
;------------------------------------------------------------------------------------------------------------
RedrawControlNet:
	push  ax
	push  bx
	push  cx
	push  dx

	; Draw filled black box on the area of interest:
	; . Calculate the starting x and y screen positions:
	mov  al, byte[m]				; AL now containts the control net y coordinate of the line one step above the top line that contains at least one block. 			
	sub  al, byte[lineCount]		; Depending on the number of total lines that were just eliminated, there will be block graphics a number of lines up. 
	add  byte[lineCount], 1
	mov  bl, BLOCK_HEIGHT						
	mul  bl
	add  ax, RECT_Y+2							
	mov  word[ypos], ax							
	mov  word[xpos], RECT_X+2
	
	; . Calculate delta_x and delta_y for the big filled black rectangle:
	mov  dl, byte[elimLine]
	sub  dl, byte[m]
	add  dl, byte[lineCount]
	mov  ax, BLOCK_HEIGHT						
	mul  dl
	mov  word[deltay], ax
	mov  bx, 10 								
	mov  ax, BLOCK_WIDTH						
	mul  bl
	mov  word[deltax], ax
	
	; . Draw the box:
	DrawFullRect word[xpos], word[ypos], word[deltax], word[deltay], BLACK
	
	; Draw block sprites on positions according to the control net at these positions. 
	mov  byte[xCont], 0
	mov  dl, byte[m]
	mov  byte[yCont], dl
	mov  dl, byte[lineCount]
	sub  byte[yCont], dl
	add  byte[yCont], 1

	mov  cl, byte[elimLine]
	inc  cl
DrawControlNetBlocks:
	; . Get the value of the control net at these coordinates with GetControlNetValue.
	mov  al, byte[yCont]
	mov  dl, byte[xCont]
	Call GetControlNetValue
	cmp  bl, 0
	je   _SkipDraw
	; . From the control net byte value, calculate the address to the appropriate block sprite.
	dec  bl
	mov  word[sprite], spritedata  
	mov  ax, TETRA_SPRITE_SIZE
	mul  bl
	add  word[sprite], ax
	DrawSprite word[xpos], word[ypos], word[sprite]
	
	; . Increase xpos by BLOCK_WIDTH, but if xpos=C+10*, set xpos:=0 and ypos=ypos+BLOCK_HEIGHT; and if ypos=CL, quit:
	_SkipDraw:
	add  byte[xCont], 1
	add  byte[xpos], BLOCK_WIDTH
	cmp  byte[xCont], 10
	jne  DrawControlNetBlocks
	mov  byte[xCont], 0
	sub  byte[xpos], 10*BLOCK_WIDTH
	add  byte[yCont], 1
	add  byte[ypos], BLOCK_HEIGHT
	cmp  byte[yCont], cl
	jl   DrawControlNetBlocks
	
	pop  dx
	pop  cx
	pop  bx
	pop  ax
	
	ret
;END of RedrawControlNet

;---------------------------------------------------------------------------------------------------------
; GetScreenPositions -- Calculates the x and y screen coordinates for one of four blocks from the byte values
; of a block position variable, and from a layout position variable. 
; - Input:
;   SI: Address of the first byte of the layout position variable.
;   BP: Address of the first byte of the block position variable.
;   CX: Number of the block in the block position variable to use. 
; - Output:
;   byte[xpos]: X-screen coordinate for the CX:th block in to the block position variable.
;   byte[ypos]: Y-screen coordinate for the CX:th block in to the block position variable.
;---------------------------------------------------------------------------------------------------------
GetScreenPositions:
    ; Set the xpos and ypos variables for each block:
    ; word[xpos] = (RECT_X+2)+BLOCK_WIDTH*(byte[layoutPos]+byte[blockPosOld+2*n])
    ; word[ypos] = (RECT_Y+2)+BLOCK_HEIGHT*(byte[layoutPos+1]+byte[blockPosOld+2*n+1])

    push ax
    push bx
    push di
    push dx    

    ; Calculate the x position:     
    mov  ax, 2
    mul  cx
    mov  di, ax
    add  di, bp
    xor  bh, bh
    mov  bl, byte[di]        
    add  bl, byte[si]
    mov  al, BLOCK_WIDTH
    mul  bl
    mov  bx, ax
    add  bx, BLOCK_X

    ; Move the calculated x value to the xpos variable:
    mov  word[xpos], bx

    ; Calculate the y position:
    mov  ax, 2
    mul  cx
    mov  di, ax
    inc  bp
    add  di, bp
    xor  bh, bh
    mov  bl, byte[di]    
    inc  si
    add  bl, byte[si]
    mov  ax, BLOCK_HEIGHT
    mul  bx
    mov  bx, ax
    add  bx, BLOCK_Y
    
    ; Move the calculated y value to the ypos variable:
    mov  word[ypos], bx

    pop  dx
    pop  di
    pop  bx
    pop  ax
; END of GetScreenPositions


;---------------------------------------------------------------------------------------------------------
; SetNewBlockFormation -- Updates the blocks' control net byte values according to current tetraType and rotation. 
;---------------------------------------------------------------------------------------------------------
SetNewBlockFormation:
    ; Set the block positions appopriately:
    ; for n=0 to 3
    ;  byte[blockPos+2*n] = byte[tetra+BYTES_PER_TETRA*byte[tetraType]+8*rotation+2*n]  <-- x-position
    ;  byte[blockPos+2*n+1] = byte[tetra+BYTES_PER_TETRA*byte[tetraType]+8*rotation+2*n+1]  <-- y-position
    ; end for
	;mov  bx, tetraType
	
    push eax
    push cx
    push si
    push di    
       
    ; Calculate the source address and put it in SI:
    xor  ah, ah					
    mov  al, BYTES_PER_TETRA
    mul  byte[tetraType]
    mov  si, ax

    add  si, tetra

    mov  al, byte[rotation]
    xor  ah, ah
    xor  bh, bh
    mov  bl, 8
    mul  bl
    add  si, ax 

    ; Set the distination address to DI:
    mov  di, blockPos

    ; Copy all two double words (two bytes for each of the four blocks) of tetra data:
    mov  cx, 2
CopyLoop:
    mov  eax, dword[si]
    mov  dword[di], eax
    add  si, 4
    add  di, 4
    loop CopyLoop

    pop  di
    pop  si
    pop  cx
    pop  eax    

    ret
; END of SetNewBlockFormation


;---------------------------------------------------------------------------------------------------------------
; CopyNewToOld -- Copies the current values of the blockPos and layoutPos variables to their "old" counterparts.  
;---------------------------------------------------------------------------------------------------------------
CopyNewToOld:
    push si
    push di
    push cx
    push eax    

    mov  si, blockPos
    mov  di, blockPosOld

	mov  cx, 2	
	_blockPosCopy:
    mov  eax, dword[si]
    mov  dword[di], eax
    add  si, 4
    add  di, 4
    loop _blockPosCopy

    mov  ax, word[layoutPos]
    mov  word[layoutPosOld], ax
    
    pop  eax
    pop  cx
    pop  di
    pop  si
    
    ret
;END of CopyNewToOld


;---------------------------------------------------------------------------------------------------------------
; GetControlNetValue -- Get the byte-value of the control net array at the position given in AX, and set
; AL to that byte-value.
; - Input: 
;   AL: Y-coordinate of the control net space.
;	DL: X-coordinate of the control net space.
; - Output:
;   BL: Byte in the controlNet array at the given coordinates.
;--------------------------------------------------------------------------------------------------------------
GetControlNetValue:
	push ax
	push dx

	mov  bl, CONTROLNET_WIDTH
	xor  ah, ah
	mul  bl
	xor  dh, dh
	add  ax, dx

	mov  bx, controlNet
	add  bx, ax
	mov  al, byte[bx]
	mov  bl, al
	
	pop  dx
	pop  ax
	
	ret
;END of GetControlNetValue


;---------------------------------------------------------------------------------------------------------------
; RecordBlockPositions -- Sets byte[tetraType]+1 - bytes at places in controlNet according to the blockPosition and
; layoutNet variables. 
;--------------------------------------------------------------------------------------------------------------
RecordBlockPositions:
	push  ax
	push  cx
	push  bp
	push  dx
	push  bx

	mov  cx, 0
RecordLoop:
	; Copy the appropriate word (with firt byte=x-position and second byte=y-position in layout net) from blockPos to half-registers bl and dl:
	mov  bp, blockPos
	add  bp, cx
	mov  bl, byte[bp]
	inc  bp
	mov  dl, byte[bp]
	
	; Add the layoutPos bytes to the bytes in those half-registers such that they then contain the control net coordinates:
	add  bl, byte[layoutPos]
	add  dl, byte[layoutPos+1]
	
	; Calculate the memory adress displacement from controlNet, from the half-register coordinates:
	mov  ax, CONTROLNET_WIDTH
	mul  dl							; Multiply the y-coordinate with the control net width and put product in AX.
	xor  bh, bh
	add  ax, bx						; Add the X-coordinate.
	
	; Make BX contain the address to the byte where the 01h-byte will be put:
	mov  bx, controlNet				; Load BX with the controlNet address.
	add  bx, ax						; Add the memory adress displacement to get the address to byte of interest. 
	
	; Set a byte[tetraType]+1 - byte at the memory location pointed to by BX.
	mov  al, byte[tetraType]
	inc  al
	mov  byte[bx], al
	
	add  cx, 2
	cmp  cx, 8
	jne  RecordLoop
	
	pop  bx 
	pop  dx
	pop  bp
	pop  cx
	pop  ax
	
	ret
;END of RecordBlockPositions

;---------------------------------------------------------------------------------------------------------------
; NullifyControlNet -- Sets all the values in the controlNet array to zero.
;--------------------------------------------------------------------------------------------------------------
NullifyControlNet:
	push ax
	push cx
	push di
	
	; Set CX to the number of words in controlNet, 105:
	mov  cx, 105
	
	; Set DI to controlNet:
	mov  di, controlNet
	
	; Copy!
NullifyLoop:
	mov  word[di], 0000h
	add  di, 2
	sub  cx, 1
	jnz  NullifyLoop
	
	pop  di
	pop  cx
	pop  ax
	
; END of NullifyControlNet
%include "ttrfun.asm"


[SECTION .data]
%include "palette.asm"				; Palette data.
%include "sprdata.asm"				; Block sprites.
%include "ttrdat.asm"				; Tetra positions.
rotation db 0
rotationC db 0
rotationTest db 0
rotTime dd 0
moveTime dd 0
fallTime dd 0
startoverTime dd 0
score dw 0
oldLineNumber dw 11
lineCount db 1
m db 0
yPosCheck db 21, 21, 21

[SECTION .bss]
elimLine resb 1
a resb 1
b resb 1
keyStroke resb 1				    ; Byte for temporary storage of key-stroke bytes.
layoutPos resb 2				    ; The offset position from which all the block positions are set. First byte=x, second byte=y.
layoutPosTest resb 2				; The offset position from which all the block positions are set. First byte=x, second byte=y.´
layoutPosOld resb 2
blockPos resb 8 					; x and y control net positions per block.
blockPosTest resb 8
blockPosOld resb 8 					; The old control net positions (positions corresponding the positions of the sprites until UpdateBlockSprites erases them).
controlNet resb 210 				; The control net where information about whether each position is set or not, is stored.						
controlNetTemp resb 210
tetraType resb 1	    			; Variable indicating the identification number of the current tetra. 					
seed resd 1			    		    ; Seed data for the Randomizer function.
posInfoOffset resw 1
blockPosOffset resw 1
xpos resw 1
ypos resw 1
sprite resw 1
blockPosAdr resw 1
layoutPosAdr resw 1
deltax resw 1
deltay resw 1
xCont resb 1
yCont resb 1
i can get rid of a good chunk of this code by not needing to handle the lines, but still generating new shape, moving and rotating still takes quite a bit.
i might need more than 8 bit address space,unless i somehow make it so it switches memory set or something, like have the collision check on one memory bank, the rotation on another one and moving the shape on the last one, and then at the end of each i have a special call that switches all the lines to the other bank, i'm preety sure this has been done already irl...... gota stop googling while i type, just found out is called extended memory,feels like i'd have to reinvent quite a few wheels to make this:)

User avatar
viruskiller
Posts: 399
Joined: June 14th, 2012, 5:07 pm

Re: attempt to make tetris in starbound game.

Post by viruskiller » June 15th, 2014, 4:19 am

i think i'm going to let this go for now:/ the game mechanics are kinda hindering me to do any complicated build
i started to make the ram first, and only made 3 bytes and is already a complete mess

this is how it looks without the wiring shown
http://snag.gy/7SiCL.jpg
as u can see it's preety neat looking, but to work with it and connect the parts i have to see the wiring of the entire thing and below is what it looks like

http://snag.gy/jI97T.jpg

so i guess minecraft may be slower but atleast it scales better , and also has tools to support copy/pasting. i tought that not having to bother with phisical wires would make it much more easyer to get things compact and fast because i'd not have to wory about wires crossing eachother and stuff
but then it gets bigger and bigger and it gets to be a big mess


this analogy i think its perfect to describe old programing style versus OOP, i think of it as OOP is the first picture, each object has it's own function and u don't see the interaction between them,
the second picture is what hardcoding stuff does , u see the entire thing, and the bigger it gets the harder is to understand

engi
Posts: 161
Joined: April 7th, 2014, 6:00 am
Location: Brazil

Re: attempt to make tetris in starbound game.

Post by engi » June 15th, 2014, 4:44 am

Well don't feel about it it's difficult to create a CPU even when you have a proper framework to work with.

The people making computers in Minecraft usually use a good set of mods to facilitate everything and also have worked with FPGAs previously.

Plus you might have trouble wiring everything, TBH I didn't play Starbound much, but if it's wiring mechanics are anything like Terraria there will be only so much you can do.
0x5f3759df

User avatar
chili
Site Admin
Posts: 3948
Joined: December 31st, 2011, 4:53 pm
Location: Japan
Contact:

Re: attempt to make tetris in starbound game.

Post by chili » June 16th, 2014, 1:14 pm

From what I saw that thing seems to be missing tri-state buffers, so you'd be screwed for any kind of data bus. It'd all have to be done with multiplexers.
Chili

User avatar
viruskiller
Posts: 399
Joined: June 14th, 2012, 5:07 pm

Re: attempt to make tetris in starbound game.

Post by viruskiller » June 16th, 2014, 11:13 pm

the latches act as tri state buffers, the only problem is that they get stuck sending the last signal if u close the gate before the input signal.
but as i said in previous post the real problem is the mechanics of wiring the circuits,there must be some way to turn certain parts off, so u can see what u work on,the way it is now u'd have to have all things separated by long distance and the lines going at different angles to see what u're doing.

User avatar
chili
Site Admin
Posts: 3948
Joined: December 31st, 2011, 4:53 pm
Location: Japan
Contact:

Re: attempt to make tetris in starbound game.

Post by chili » June 17th, 2014, 1:52 am

Nope, they are simple latches. There is no high-impedance enabling input for them so they cannot act as tri-state buffers.

The problem you're having is that you're trying to use a latch like a flip-flop. To fix that, you need to connect two latches together in master-slave configuration. That will give you an edge-sensitive flip flop that you can use for synchronous processing.

http://en.wikipedia.org/wiki/Flip-flop_ ... _flip-flop

But yeah, the real problem is that while Starbound might be an okay game, it's a shitty logic design tool :P
Chili

Post Reply