;IceBreaker Assembler Source
;---------------------------
;Link this file with IceBreaker.c.
;CASE sensitivity ON.

	INCDIR	"INCLUDES:"
	INCLUDE	"exec/exec_lib.i"
	INCLUDE	"dos/gmsdos_lib.i"
	INCLUDE	"libs/graphics_lib.i"
	INCLUDE	"dpkernel/dpkernel.i"
	INCLUDE	"system/debug.i"
	INCLUDE	"system/dpkbase.i"
	INCLUDE	"system/tasks.i"

	;The following values are defined in the C source.

	xref	_DOSBase
	xref	_SysBase
	xref	_conhandle

	;The following values are defined by us so that the C source can
	;access them.

	xdef	_libDebugMessage
	xdef	_libErrorMessage
	xdef	_libStepBack
	xdef	_DebugList
	xdef	_GFXBase
	xdef	_DPKBase
	xdef	_maxstep

	SECTION	IceAssembler,CODE

WText	MACRO		;Simple macro for nice looking source.
	dc.b	\1,0
	even
	ENDM

;===================================================================================;
;                             INTERCEPT DEBUG MESSAGE
;===================================================================================;
;Function: Receives a debug message, copies it to the buffer and then sends a
;	   message to our main task, which tells it new data has appeared in the
;	   buffer.  This function needs to be very very fast.
;
;Requires: d7 = Debug type in low word, flags in high word.
;	   a5 = Message string if type of Error/Formatted/Message.
;Returns:  Nothing.

_libDebugMessage:
	tst.w	InDebug	;ma = Check if we are in IceBreaker.
	beq.s	.cont	;>> = Nope, continue as normal.
	MOVEM.L	D0-D1/D7/A0-A1/A6,-(SP)	;SP = Save registers.
	and.l	#STEP,d7	;d6 = Step necessary?
	beq.s	.qex	;>> = Nope.
	move.l	_DPKBase,a6	;a6 = DPKBase.
	CALL	FindDPKTask	;>> = Find this task.
	tst.l	d0	;d0 = Check if the node exists.
	beq.s	.qex	;>> = No.
	move.l	d0,a0	;a0 = Pointer to Task node.
	addq.w	#1,GT_DebugStep(a0)	;a0 = (DebugStep)+1
.qex	MOVEM.L	(SP)+,D0-D1/D7/A0-A1/A6	;>> = Return registers.
	rts

;-----------------------------------------------------------------------------------;
;Compare the maxstep and debug step values.

.cont	MOVEM.L	D0-D1/D7/A0-A1/A6,-(SP)	;SP = Save registers.
	move.l	_DPKBase,a6	;a6 = DPKBase.
	CALL	FindDPKTask	;>> = Find this task.
	tst.l	d0	;d0 = Check if the node exists.
	beq.s	.dbg	;>> = No, continue anyway.
	move.l	d0,a0	;a0 = Pointer to Task node.
	move.w	_maxstep(pc),d0	;d0 = Maximum step value.
	cmp.w	GT_DebugStep(a0),d0	;a0 = Is (MaxStep > GT_DebugStep)?
	bgt.s	.dbg	;>> = Yes, continue.
	and.l	#STEP,d7	;d6 = Step necessary?
	beq.s	.cexit	;>> = Nope.
	addq.w	#1,GT_DebugStep(a0)	;a0 = (DebugStep)+1
.cexit	MOVEM.L	(SP)+,D0-D1/D7/A0-A1/A6	;SP = Return registers.
	rts

;-----------------------------------------------------------------------------------;
;Print the message.

.dbg	MOVEM.L	(SP)+,D0-D1/A0-A1/D7/A6	;SP = Return registers.

	cmp.w	#DBG_END,d7	;d7 = If (Type < 0) or (Type > DBG_End-1)
	bcs.s	.print	;>> = No, it's safe.
	move.l	d7,d5	;d5 = Remember bad number.
	and.l	#$0000ffff,d5	;d5 = Get rid of special flags.
	move.w	#DBG_BadNumber,d7

.print	move.w	#1,InDebug	;ma = We are now in IceBreaker.
	tst.w	gb_BlitterUsed(a6)	;a6 = Blitter allocated?
	beq.s	.debug	;>> = No, safe.

	MOVEM.L	D0-D1/A0-A1/A6,-(SP)	;SP = Save registers.
	move.l	_GFXBase(pc),a6	;a6 = Graphics base.
	CALL	DisownBlitter	;>> = Disown the blitter.
	CALL	WaitBlit
	bsr.s	.debug	;>> = Now we can send the messaage.
	move.l	_GFXBase(pc),a6	;a6 = Graphics base.
	CALL	OwnBlitter
	CALL	WaitBlit
	MOVEM.L	(SP)+,D0-D1/A0-A1/A6	;SP = Return registers.
	clr.w	InDebug
	rts

;-----------------------------------------------------------------------------------;

.debug	MOVEM.L	A0-A6/D0-D7,-(SP)	;SP = Save used registers.
	move.l	_SysBase,a6	;a6 = Exec Base.
	CALL	Forbid	;>> = Halt all tasks for a moment.

	move.l	d7,d6	;d6 = Save flags.
	and.l	#$0000ffff,d7	;d7 = Get rid of special flags.
	bsr	Stepper	;>> = Function stepper (print step).
	lea	_DebugList(pc),a6	;a6 = Pointer to debug list.
	mulu	#DL_SIZEOF,d7	;d7 = (Type)*DL_SIZEOF
	move.l	DL_Print(a6,d7.l),a6	;a6 = Printer for this type.
	jsr	(a6)	;>> = Go to the printer.
	bsr	NewLine	;>> = Write new line.

	and.l	#STEP,d6	;d6 = Step necessary?
	beq.s	.done	;>> = Nope.
	move.l	_DPKBase,a6	;a6 = DPKBase.
	CALL	FindDPKTask	;>> = Find this task.
	tst.l	d0	;d0 = Check if the node exists.
	beq.s	.done	;>> = No.
	move.l	d0,a0	;a0 = Pointer to Task node.
	addq.w	#1,GT_DebugStep(a0)	;a0 = (DebugStep)+1

.done	move.l	_SysBase,a6	;a6 = Exec Base.
	CALL	Permit	;>> = Give back multi-tasking.
	MOVEM.L	(SP)+,A0-A6/D0-D7	;SP = Return used registers.
	clr.w	InDebug
	rts

;===================================================================================;
;                             INTERCEPT ERROR MESSAGE
;===================================================================================;
;Function: Receives an error number and prints it out.
;Requires: d0.l = Error code.
;Returns:  Nothing.

_libErrorMessage:
	tst.w	InDebug
	beq.s	.cont
	rts

.cont	move.w	#1,InDebug
	cmp.l	#ERR_END,d0	;d0 = If (Code < 0) or (Code > ERR_END-1).
	bcc.s	.exit	;>> = Error/Unrecognised.
	tst.w	gb_BlitterUsed(a6)	;Has the blitter been grabbed and not
	beq.s	.message	;returned?  If so we better free it before
	MOVEM.L	D0-D7/A0-A6,-(SP)	;SP = Save used registers.
	move.l	_GFXBase,a6	;a6 = Graphics base.
	CALL	DisownBlitter	;>> = Disown the blitter.
	bsr.s	.message	;>> = Print message.
	move.l	_GFXBase,a6	;a6 = Graphics base.
	CALL	OwnBlitter	;>> = Get back blitter.
	MOVEM.L	(SP)+,D0-D7/A0-A6	;SP = Return used registers.
.exit	clr.w	InDebug
	rts

.message
	MOVEM.L	A0-A6/D0-D7,-(SP)	;SP = Save used registers.
	move.l	_SysBase,a6	;a6 = Exec Base.
	CALL	Forbid	;>> = Halt all tasks for a moment.
	bsr	Stepper	;>> = Function stepper.
	lea	TXT_ErrorCode(pc),a0	;a0 = "ErrorCode:"
	bsr	WriteBold	;>> = Write it out.
	lea	ErrorList(pc),a0	;a0 = Pointer to debug list.
	add.l	d0,d0	;d0 = *2
	add.l	d0,d0	;d0 = *4
	move.l	(a0,d0.l),a0	;a0 = Text for this type.
	bsr	WText	;>> = Write it out.
	bsr	NewLine	;>> = Write new line.
	move.l	_SysBase,a6	;a6 = Exec Base.
	CALL	Permit	;>> = Give back multi-tasking.
	MOVEM.L	(SP)+,A0-A6/D0-D7	;SP = Return used registers.
	clr.w	InDebug
	rts

;===================================================================================;
;                           STEP BACK AN ENTRY
;===================================================================================;
;Function: Used to step back an entry after STEP has been specified.
;Requires: Nothing.
;Returns:  Nothing.

_libStepBack:
	MOVEM.L	A0/D0,-(SP)	;SP = Save used registers.
	CALL	FindDPKTask	;>> = Find this task.
	tst.l	d0
	beq.s	.done
	move.l	d0,a0	;a0 = Task node pointer.
	subq.w	#1,GT_DebugStep(a0)	;a0 = (DebugStep)-1
.done	MOVEM.L	(SP)+,A0/D0	;SP = Return used registers.
	rts

;===================================================================================;
;                            FUNCTION STEPPER
;===================================================================================;

Stepper:
	MOVEM.L	D0-D7/A0-A6,-(SP)	;SP = Save used registers.
	move.l	_DPKBase,a6	;a6 = DPKBase
	CALL	FindDPKTask	;>> = Find this task.
	tst.l	d0	;d0 = Check if node exists.
	beq.s	.done	;>> = No, exit...
	move.l	d0,a0	;a0 = Task node.

	move.w	GT_DebugStep(a0),d4	;d4 = Amount of spaces to step.
	beq.s	.done	;>> = No spaces, exit.
	blt.s	.error	;>> = Error...

	move.l	_DOSBase,a6	;a6 = DOSBase.
	subq.w	#1,d4	;d4 = (Step)-1 [for loop]
.loop	move.l	_conhandle,d1	;d1 = Window to output Text.
	move.l	#TXT_Space,d2	;d2 = Start of string.
	moveq	#1,d3	;d3 = One character.
	bsr	IceWrite	;>> = Write out the string.
	dbra	d4,.loop	;d4 = --1 and loop.
.done	MOVEM.L	(SP)+,D0-D7/A0-A6	;SP = Return used registers.
	rts

.error	move.l	_DOSBase,a6	;a6 = DOSBase.
	move.l	_conhandle,d1	;d1 = Window to output Text.
	move.l	#.XXX,d2	;d2 = Start of string.
	moveq	#1,d3	;d3 = One character.
	bsr	IceWrite	;>> = Write out the string.
	MOVEM.L	(SP)+,D0-D7/A0-A6	;SP = Return used registers.
	rts

.XXX	dc.b	"X"
	even

;===================================================================================;
;                                PRINTING FUNCTIONS
;===================================================================================;

PRINT_Error:
	lea	TXT_Error(pc),a0
	bsr	WriteBold
	move.l	a5,a0	;a0 = Message
	bsr	WText	;>> = Write it out.
	rts

PRINT_Formatted:
	lea	TXT_Formatted(pc),a0
	bsr	WriteBold
	move.l	a5,a0	;a0 = Message
	bsr	WText	;>> = Write it out.
	rts

PRINT_BoldMessage:
	lea	TXT_Message(pc),a0
	bsr	WriteBold
	move.l	a5,a0	;a0 = Message
	bsr	WText	;>> = Write it out.
	rts

PRINT_Message:
	lea	TXT_Message(pc),a0
	bsr	WriteFirst
	move.l	a5,a0	;a0 = Message
	bsr	WText	;>> = Write it out.
	rts


PRINT_BadNumber:
	lea	TXT_BadNumber(pc),a0
	bsr	WriteFirst
	move.l	d5,d0
	bsr	WriteDec
	rts

;-----------------------------------------------------------------------------------;
;                             MISCELLANEOUS FUNCTIONS
;-----------------------------------------------------------------------------------;

PRINT_AddInputHandler:
	lea	TXT_AddInputHandler(pc),a0
	bsr	WriteFirst
	rts

PRINT_RemInputHandler:
	lea	TXT_RemInputHandler(pc),a0
	bsr	WriteFirst
	rts

PRINT_Switch:
	lea	TXT_Switch(pc),a0
	bsr	WriteFirst
	rts

PRINT_FindDPKTask:
	lea	TXT_FindDPKTask(pc),a0
	bsr	WriteFirst
	rts

PRINT_AllocAudio:
	lea	TXT_AllocAudio(pc),a0
	bsr	WriteFirst
	rts

PRINT_FreeAudio:
	lea	TXT_FreeAudio(pc),a0
	bsr	WriteFirst
	rts

PRINT_DPKOpened:
	lea	TXT_DPKOpened(pc),a0
	bsr	WriteWhite
	rts

PRINT_DPKClosed:
	lea	TXT_DPKClosed(pc),a0
	bsr	WriteWhite
	rts

PRINT_SelfDestruct:
	lea	TXT_SelfDestruct(pc),a0
	bra	WriteFirst

PRINT_Armageddon:
	lea	TXT_Armageddon(pc),a0
	bra	WriteFirst

PRINT_FingerOfDeath:
	lea	TXT_FingerOfDeath(pc),a0
	bra	WriteFirst

PRINT_InitDestruct:
	lea	TXT_InitDestruct(pc),a0
	bra	WriteFirst

PRINT_Awaken:
	lea	TXT_Awaken(pc),a0
	bsr	WriteFirst
	lea	TXT_Task(pc),a0
	bsr	WriteText
	move.l	a1,d0
	bra	WriteAddress

;-----------------------------------------------------------------------------------;
;                                BLITTER FUNCTIONS
;-----------------------------------------------------------------------------------;

PRINT_AllocBlitter:
	lea	TXT_AllocBlitter(pc),a0
	bra	WriteFirst

PRINT_FreeBlitter:
	lea	TXT_FreeBlitter(pc),a0
	bra	WriteFirst


PRINT_CreateMasks:
	lea	TXT_CreateMasks(pc),a0
	bsr	WriteFirst
	rts

PRINT_SetBobFrames:
	lea	TXT_SetBobFrames(pc),a0
	bsr	WriteFirst
	rts

;-----------------------------------------------------------------------------------;
;                                 SCREEN HANDLING
;-----------------------------------------------------------------------------------;

PRINT_MoveToBack:
	move.l	a0,a1
	lea	TXT_MoveToBack(pc),a0
	bsr	WriteFirst
	lea	TXT_ScreenAddr(pc),a0	;a0 = "GameScreen: "
	bsr	WriteText
	move.l	a1,d0
	bra	WriteAddress

PRINT_MoveToFront:
	move.l	a0,a1
	lea	TXT_MoveToFront(pc),a0
	bsr	WriteFirst
	lea	TXT_ScreenAddr(pc),a0	;a0 = "GameScreen: "
	bsr	WriteText
	move.l	a1,d0
	bra	WriteAddress

PRINT_TakeDisplay:
	move.l	a0,a1
	lea	TXT_TakeDisplay(pc),a0
	bsr	WriteFirst
	lea	TXT_ScreenAddr(pc),a0	;a0 = "GameScreen: "
	bsr	WriteText
	move.l	a1,d0
	bra	WriteAddress

PRINT_ReturnDisplay:
	move.l	a0,a1
	lea	TXT_ReturnDisplay(pc),a0
	bra	WriteFirst

PRINT_BlankOn:
	lea	TXT_BlankOn(pc),a0
	bra	WriteFirst

PRINT_BlankOff:
	lea	TXT_BlankOff(pc),a0
	bra	WriteFirst

;-----------------------------------------------------------------------------------;
;                                OBJECT FUNCTIONS
;-----------------------------------------------------------------------------------;

PRINT_GetObject:
	lea	TXT_GetObject(pc),a0
	bsr	WriteFirst
	rts

PRINT_GetObjectList:
	lea	TXT_GetObjectList(pc),a0
	bsr	WriteFirst
	rts

;-----------------------------------------------------------------------------------;
;                                MEMORY FUNCTIONS
;-----------------------------------------------------------------------------------;

PRINT_AllocBlitMem:
	lea	TXT_AllocBlitMem(pc),a0
	bsr	WriteFirst
	bsr.s	Alloc
	lea	TXT_MemBlit(pc),a0
	bra	WriteText

PRINT_AllocVideoMem:
	lea	TXT_AllocVideoMem(pc),a0
	bsr	WriteFirst
	bsr.s	Alloc
	lea	TXT_MemVideo(pc),a0
	bra	WriteText

PRINT_AllocSoundMem:
	lea	TXT_AllocSoundMem(pc),a0
	bsr	WriteFirst
	bsr.s	Alloc
	lea	TXT_MemSound(pc),a0
	bra	WriteText

PRINT_AllocMemBlock:
	lea	TXT_AllocMemBlock(pc),a0
	bsr	WriteFirst
	bsr.s	Alloc
	lea	TXT_MemData(pc),a0
	bra	WriteText

PRINT_FreeMemBlock:
	lea	TXT_FreeMemBlock(pc),a0
	bsr	WriteFirst
	lea	TXT_Address(pc),a0	;a0 = "Address: "
	bsr	WriteText	;>> = Write it out.
	bsr	WriteAddress	;>> = Write out address in d0.
	lea	TXT_Size(pc),a0	;a0 = "Size : "
	bsr	WriteText	;>> = Write it out.
	move.l	d0,a0	;d0 = Address of memory block.
	move.l	-12(a0),d0	;d0 = Size of block.
	bra	WriteDec	;>> = Write it out.

Alloc:	lea	TXT_Size(pc),a0	;a0 = "Size: "
	bsr	WriteText	;>> = Write text.
	bra	WriteDec	;>> = Write out size in d0.

;-----------------------------------------------------------------------------------;
;                             STRUCTURE MANIPULATION
;-----------------------------------------------------------------------------------;
;a0 = APTR {Object}|{Tags};
;a1 = APTR Container;

PRINT_Init:
	move.l	a0,a2	;a2 = Object.
	move.l	a1,a3	;a3 = Container.
	lea	TXT_Init(pc),a0	;a0 = "Init()"
	bsr	WriteFirst	;>> = Write it out.

	move.w	(a2),d0	;d0 = Object ID.
	cmp.w	#ID_LIST,d0	;d0 = Check for list.
	bne.s	.chkSTags	;>> = Not a list.
	lea	TXT_List(pc),a0	;a0 = "List"
	bsr	WriteText	;>> = Write.
	bra.s	.colon	;>> = Continue on.

.chkSTags
	cmp.w	#ID_SPCTAGS,d0	;d0 = Check for tags.
	bne.s	.print	;>> = Not tags.
	move.w	2(a2),d0	;d0 = Get Object ID.

.print	bsr	PrintObject	;>> = Print the name of the object.
	tst.l	d0	;d0 = Check for recognition.
	bne.s	.error	;>> = No, error.

.colon	lea	TXT_Colon(pc),a0	;a0 = ": "
	bsr	WriteText	;>> = Write it out.
	move.l	a2,d0	;d0 = Address of object.
	bsr	WriteAddress	;>> = Write it out.

	;Write the container details.

	cmp.l	#$00,a3
	beq.s	.done
	move.w	(a3),d0	;d0 = Container ID.
	bsr	PrintObject	;
	tst.l	d0	;
	bne.s	.error	;
	lea	TXT_Colon(pc),a0	;a0 = ": "
	bsr	WriteText	;>> = Write it out.
	move.l	a3,d0	;d0 = Address of object.
	bsr	WriteAddress	;>> = Write it out.
.done
.error	rts

TXT_Colon:
	dc.w	": ",0
	even

;-----------------------------------------------------------------------------------;
;                           PRINT NAME OF ANY SYSOBJECT
;-----------------------------------------------------------------------------------;
;d0 = LONG ID;

PrintObject:
	MOVEM.L	A0-A1/D2/A6,-(SP)
	move.l	_DPKBase,a6	;a6 = DPKBase
	sub.l	a0,a0	;a0 = NULL.
	move.l	d0,d2
	CALL	FindSysObject	;>> = Find first object using ID in d0.
	tst.l	d0	;d0 = Check for error.
	beq.s	.error	;>> = Error, exit.
	move.l	d0,a0	;a0 = Pointer to SysObject.
	move.l	SO_Name(a0),a0	;a0 = Name of the object.
	cmp.l	#$00,a0
	beq.s	.error
	bsr	WriteText	;>> = Write it out.
	MOVEM.L	(SP)+,A0-A1/D2/A6
	moveq	#ERR_OK,d0	;d0 = No errors.
	rts

.error	lea	TXT_ID(pc),a0
	bsr	WriteText
	move.l	d2,d0
	bsr	WriteDec
	MOVEM.L	(SP)+,A0-A1/D2/A6
	moveq	#ERR_FAILED,d0	;d0 = Error, return failed message.
	rts

;-----------------------------------------------------------------------------------;
;                             ACTION: Load()
;-----------------------------------------------------------------------------------;

PRINT_Load:
	move.l	a0,a1	;a1 = Source structure.
	move.l	d0,d2	;d2 = Object ID.
	lea	TXT_Load(pc),a0	;a0 = "Load()"
	bsr	WriteFirst	;>> = Write.

	bsr	PrintSource	;>> = Print source in a1.

	tst.l	d2	;d2 = Test if ID was forced.
	beq.s	.done	;>> = Nope.
	lea	TXT_Space(pc),a0	;a0 = " "
	bsr	WriteText	;>> = Write.
	move.l	d2,d0	;d0 = Object ID.
	bsr	PrintObject	;>> = Print the name of the object.
.done	rts

;-----------------------------------------------------------------------------------;
;                           PRINT SOURCE OBJECT
;-----------------------------------------------------------------------------------;
;a1 = APTR {FileName}|{MemPtr}|{Object}

PrintSource:
	MOVEM.L	A0/A1,-(SP)

.chkfilename
	cmp.w	#ID_FILENAME,(a1)
	bne.s	.chkmem
	lea	TXT_FileName(pc),a0
	bsr	WriteText
	move.l	FN_Name(a1),a0
	bsr	WriteText
	MOVEM.L	(SP)+,A0/A1
	moveq	#ERR_OK,d0
	rts

.chkmem	cmp.w	#ID_MEMPTR,(a1)
	bne.s	.chkfile
	lea	TXT_Source(pc),a0
	bsr	WriteText
	move.l	MPTR_Address(a1),d0
	bsr	WriteHex
	MOVEM.L	(SP)+,A0/A1
	moveq	#ERR_OK,d0
	rts

.chkfile
	cmp.w	#ID_FILE,(a1)
	bne.s	.error
	lea	TXT_File(pc),a0
	bsr	WriteText
	move.l	FL_Source(a1),a0
	move.l	FN_Name(a0),a0
	bsr	WriteText
	MOVEM.L	(SP)+,A0/A1
	moveq	#ERR_OK,d0
	rts

.error	MOVEM.L	(SP)+,A0/A1
	moveq	#ERR_FAILED,d0
	rts

;-----------------------------------------------------------------------------------;
;                                  ACTION: Hide()
;-----------------------------------------------------------------------------------;

PRINT_Hide:
	move.l	a0,a1	;a1 = Save structure.
	lea	TXT_Hide(pc),a0	;a0 = Hide()
	bsr	WriteFirst	;>> = Write.
	bra	PrintDetails

;-----------------------------------------------------------------------------------;
;                                 ACTION: Display()
;-----------------------------------------------------------------------------------;

PRINT_Display:
	move.l	a0,a1	;a1 = Save structure.
	lea	TXT_Display(pc),a0	;a0 = Display()
	bsr	WriteFirst	;>> = Write.
	bra	PrintDetails

;-----------------------------------------------------------------------------------;
;                                 ACTION: Get()
;-----------------------------------------------------------------------------------;
;d0 = LONG ID;

PRINT_Get:
	lea	TXT_Get(pc),a0
	bsr	WriteFirst
	bsr	PrintObject
	rts

;-----------------------------------------------------------------------------------;
;                         ACTION: CopyStructure()
;-----------------------------------------------------------------------------------;

PRINT_CopyStructure:
	lea	TXT_CopyStructure(pc),a0
	bsr	WriteFirst
	rts

;-----------------------------------------------------------------------------------;
;                                 ACTION: Free()
;-----------------------------------------------------------------------------------;
;a0 = APTR Object;

PRINT_Free:
	move.l	a0,a1	;a1 = Save structure.
	lea	TXT_Free(pc),a0	;a0 = Free()
	bsr	WriteFirst	;>> = Write.
	cmp.l	#$00,a1	;a1 = Check for NULL.
	bne.s	PrintDetails
	rts

PrintDetails:
.chkList
	cmp.w	#ID_LIST,(a1)
	bne.s	.chkGTags
	lea	TXT_List(pc),a0
	bra.s	.write

.chkGTags
	cmp.w	#ID_GENTAGS,(a1)
	bne.s	.chkSTags
	lea	TXT_Tags(pc),a0
	bra.s	.write

.chkSTags
	cmp.w	#ID_SPCTAGS,(a1)
	bne.s	.chkStruct
	lea	TXT_Tags(pc),a0
	bra.s	.write

.chkStruct
	move.l	_DPKBase,a6
	moveq	#$00,d0
	move.w	(a1),d0
	sub.l	a0,a0
	CALL	FindSysObject
	tst.l	d0
	bne.s	.sysobj
	lea	TXT_InvalidObj(pc),a0
	bsr	WriteText
	rts

.sysobj	move.l	d0,a2
	move.l	SO_Name(a2),a0	;a0 = Name of the object.
.write	bsr	WriteText	;>> = Write out the name, eg "Picture".
	lea	TXT_Colon,a0	;a0 = ": "
	bsr	WriteText	;>> = Write.
	move.l	a1,d0	;d0 = Structure address.
	bra	WriteAddress

TXT_List:
	dc.b	"List",0
	even

TXT_Tags:
	dc.b	"Tags",0
	even

;-----------------------------------------------------------------------------------;

PRINT_Dead:
	rts

;-----------------------------------------------------------------------------------;
;                                    FILE I/O
;-----------------------------------------------------------------------------------;

PRINT_OpenFile:
	move.l	a0,a1	;a1 = Source structure.
	move.l	d0,d2	;d2 = Object ID.
	lea	TXT_OpenFile(pc),a0	;a0 = "Load()"
	bsr	WriteFirst	;>> = Write.
	bsr	PrintSource	;>> = Print source in a1.

	lea	TXT_Flags(pc),a0	;a0 = ", Flags: $"
	bsr.s	WriteText
	move.l	d2,d0
	bsr	WriteHex	;>> = Write out hex flags in d0.
	rts

;===================================================================================;
;                                NEW LINE
;===================================================================================;

NewLine:
	MOVEM.L	D0-D7/A0-A6,-(SP)	;SP = Save used registers.
	move.l	_DOSBase,a6	;a6 = DOSBase.
	move.l	_conhandle,d1	;d1 = Window to output Text.
	move.l	#TXT_NewLine,d2	;d2 = Start of string.
	moveq	#1,d3	;d3 = One character.
	bsr	IceWrite	;>> = Write out the string.
	MOVEM.L	(SP)+,D0-D7/A0-A6	;SP = Return used registers.
	rts

;===================================================================================;
;                            OUTPUT Text TO OUR WINDOW
;===================================================================================;
;Internal: Writes a string of Text to our window.
;Requires: a0 = Text string.
;Returns:  Nothing.

MAXLETTERS =	23

WriteBold:
	MOVEM.L	A0-A6/D0-D7,-(SP)	;SP = Save used registers.
	move.l	a0,a3	;a3 = Save pointer to text to write.
	move.l	_DOSBase,a6	;a6 = DOSBase.
	move.l	_conhandle,d1	;d1 = Window to output Text.
	move.l	#TXT_Bold,d2	;d2 = Start of string.
	moveq	#4,d3	;d3 = (EndString)-StartString [Length]
	bsr	IceWrite	;>> = Write out the string.
	bra.s	WSkip

WriteWhite:
	MOVEM.L	A0-A6/D0-D7,-(SP)	;SP = Save used registers.
	move.l	a0,a3	;a3 = Save pointer to text to write.
	move.l	_DOSBase,a6	;a6 = DOSBase.
	move.l	_conhandle,d1	;d1 = Window to output Text.
	move.l	#TXT_White,d2	;d2 = Start of string.
	moveq	#5,d3	;d3 = (EndString)-StartString [Length]
	bsr	IceWrite	;>> = Write out the string.
	bra.s	WSkip	;>> = Skip into routine.

WriteFirst:
	MOVEM.L	A0-A6/D0-D7,-(SP)	;SP = Save used registers.
	move.l	a0,a3	;a3 = Save pointer to text to write.
	move.l	_DOSBase,a6	;a6 = DOSBase.
	move.l	_conhandle,d1	;d1 = Window to output Text.
	move.l	#TXT_Flat,d2	;d2 = Start of string.
	moveq	#4,d3	;d3 = (EndString)-StartString [Length]
	bsr	IceWrite	;>> = Write out the string.

WSkip:	move.l	_DPKBase,a6	;a6 = DPKBase.
	move.l	_conhandle,d1	;d1 = Window to output Text.
	move.l	a3,d2	;d2 = Start of string.
	moveq	#-1,d3	;d3 = -1 [length]
.count	addq.l	#1,d3	;d3 = ++1
	tst.b	(a3)+	;a3 = End of string?
	bne.s	.count	;>> = Keep looping.

	moveq	#MAXLETTERS,d5	;d5 = MaxLetters
	sub.l	d3,d5	;d5 = (MaxLetters)-TextLength

	move.l	_DPKBase,a6
	CALL	FindDPKTask
	tst.l	d0
	beq.s	.under
	move.l	d0,a0	;a0 = DPK Task.

	moveq	#$00,d6
	move.w	GT_DebugStep(a0),d6
	sub.l	d6,d5	;d5 = (MaxLetters-TextLength)-Stepped
	bge.s	.under	;>> = Under the maximum amount.
	add.l	d5,d3	;d3 = (Length)-Overflow
.under	bsr	IceWrite	;>> = Write out the string.

.spaces	subq.l	#1,d5
	ble.s	.done
	move.l	_conhandle,d1	;d1 = Output.
	move.l	#TXT_Space,d2	;d2 = Start of text.
	moveq	#1,d3	;d3 = 1 character.
	bsr	IceWrite	;>> = Write out the string.
	bra.s	.spaces	;>> = Loop until finished.
.done	MOVEM.L	(SP)+,A0-A6/D0-D7	;SP = Return used registers.
	rts

;-----------------------------------------------------------------------------------;

WriteText:
	MOVEM.L	A0-A6/D0-D7,-(SP)	;SP = Save used registers.
	move.l	_DOSBase,a6	;a6 = DOSBase.
	move.l	_conhandle,d1	;d1 = Window to output Text.
	move.l	#TXT_Flat,d2	;d2 = Start of string.
	moveq	#4,d3	;d3 = (EndString)-StartString [Length]
	bsr	IceWrite	;>> = Write out the string.
	MOVEM.L	(SP)+,A0-A6/D0-D7	;SP = Return used registers.
	bsr.s	WText
	rts

;-----------------------------------------------------------------------------------;
;a0 = String to write.

WText:	MOVEM.L	A0-A6/D0-D7,-(SP)	;SP = Save used registers.
	move.l	_DOSBase,a6	;a6 = DOSBase.
	move.l	_conhandle,d1	;d1 = Window to output Text.
	move.l	a0,d2	;d2 = Start of string.
.count	tst.b	(a0)+	;a0 = End of string?
	bne.s	.count	;>> = Keep looping.
	subq.w	#1,a0	;a0 = --1 [End of string]
	move.l	a0,d3	;d3 = End of string.
	sub.l	d2,d3	;d3 = (EndString)-StartString [Length]
	cmp.l	#80,d3
	bcc.s	.done
	bsr	IceWrite	;>> = Write out the string.
.done	MOVEM.L	(SP)+,A0-A6/D0-D7	;SP = Return used registers.
	rts


;===================================================================================;
;                              WRITE ADDRESS
;===================================================================================;
;d0 = Address to write.

WriteAddress:
	MOVEM.L	A0-A6/D0-D7,-(SP)	;SP = Save used registers.
	lea	TXT_Hex(pc),a0	;a0 = "$"
	bsr	WriteText	;>> = Write it out.
	bsr	WriteHex	;>> = Write the supplied address.

	;bsr	WriteDec	;>> = Write the supplied address as decimal.
	MOVEM.L	(SP)+,A0-A6/D0-D7	;SP = Save used registers.
	rts

TXT_Hex: dc.b	"$",0
	 even

;===================================================================================;
;                      OUTPUT HEXADECIMAL Text TO OUR WINDOW
;===================================================================================;
;Internal: Outputs a longword value as hexidecimal Text.
;Requires: d0 = Value
;Returns:  Nothing.

WriteHex:
	MOVEM.L	A0-A6/D0-D7,-(SP)	;SP = Save used registers.
	lea	.hex(pc),a0	;a0 = Hex table.
	lea	String(pc),a1	;a1 = Text buffer.
	moveq	#$00,d2
	tst.l	d0
	beq.s	.wzero
	moveq	#8-1,d7	;d7 = (AmtBytes)-1
.loop2	rol.l	#4,d0	;d0 = <<4 [rotate, last nibble first]
	move.l	d0,d1	;d1 = Current value.
	and.l	#$0000000F,d1	;d1 = (Value)&$F [nibble]
	bne.s	.write
	tst.w	d2
	beq.s	.skip
.write	move.b	(a0,d1.w),(a1)+	;a1 = Write out the hex value.
	moveq	#$01,d2
.skip	dbra	d7,.loop2	;d7 = --1 and loop.
	move.w	#$2000,(a1)	;a1 = Clear the final byte.
	lea	String(pc),a0	;a0 = Text buffer.
	bsr	WriteText	;>> = Write it out.
	MOVEM.L	(SP)+,A0-A6/D0-D7	;SP = Return used registers.
	rts

.wzero	lea	.zero(pc),a0	;a0 = "0"
	bsr	WriteText	;>> = Write it out.
	MOVEM.L	(SP)+,A0-A6/D0-D7	;SP = Return used registers.
	rts

.zero	dc.b	"0 ",0
	even

.hex	dc.b	"0123456789ABCDEF"
	even

String:	dc.b	"                ",0
	even

;===================================================================================;
;                             WRITE DECIMAL NUMBER
;===================================================================================;
;Internal: Outputs a longword value as decimal Text.
;Requires: d0 = Value
;	   d7 = AmtBytes (1-8) or -1/0.
;Returns:  Nothing.

WriteDec:
	MOVEM.L	A0-A6/D0-D7,-(SP)	;SP = Save used registers.
	moveq	#-1,d7
	move.l	_DPKBase,a6
	move.w	d7,d1
	lea	String(pc),a0
	bsr	_WriteDec
	move.l	d0,a1
	move.w	#$2000,(a1)
	bsr	WriteText
	MOVEM.L	(SP)+,A0-A6/D0-D7	;SP = Return used registers.
	rts

;===================================================================================;
;                     OUTPUT A VALUE AS A DECIMAL-TEXT NUMBER
;===================================================================================;
;Function: Write a value out as a decimal number.
;Requires: d0 = LONG Value;
;	   d1 = WORD Amount of digits or NULL for dynamic association;
;	   a0 = APTR Text destination;
;Returns:  d0 = APTR End address of written numbers;

_WriteDec:
	MOVEM.L	D1-D3/A0-A1,-(SP)	;SP = Save used registers.
	tst.w	d1	;d1 = Check if he knows the amt of digits.
	bgt.s	.Convert	;>> = He knows, convert the number.

.CountDigits
	moveq	#1,d1	;d1 = At least 1 digit.
	moveq	#10,d2	;d2 = 10.
	lea	.dec-4(pc),a1	;a1 = Decimal table (powers of 10).
.floop	cmp.l	(a1),d0	;d0 = Is (Number < 10)?
	blt.s	.Convert	;>> = Yes, convert.
	subq.w	#4,a1	;d2 = (10*10) = 100
	addq.w	#1,d1	;d1 = ++1, extra digit required.
	bra.s	.floop	;>> = Keep looping.

.Convert
	tst.l	d0	;d0 = Check.
	bge.s	.pos	;>> = Number is positive.
	move.b	#"-",(a0)+	;a0 = User now knows it is negative.
	neg.l	d0	;d0 = Make it positive.
.pos	subq.w	#1,d1	;d1 = --1 for loop.
	move.w	d1,d2	;d2 = (AmtDigits)-1.
	add.w	d2,d2	;d2 = (AmtDigits-1)*2
	add.w	d2,d2	;d2 = (AmtDigits-1)*4 [long]
	neg.w	d2	;d2 = -((AmtDigits-1)*4)
	lea	.dec(pc,d2.w),a1	;a1 = List of neggers
.loop	move.l	(a1)+,d2	;d2 = Get negger
	moveq	#'0',d3	;d3 = This digit ($30)
.iloop	sub.l	d2,d0
	bmi.s	.digdun
	addq.b	#1,d3	;d3 = Build digit
	bra.s	.iloop
.digdun	add.l	d2,d0
	move.b	d3,(a0)+
	dbra	d1,.loop
	move.l	a0,d0	;d0 = Address finished writing to.
	MOVEM.L	(SP)+,D1-D3/A0-A1
	rts

	dc.l	1000000000
	dc.l	0100000000
	dc.l	0010000000
	dc.l	0001000000
	dc.l	0000100000
	dc.l	0000010000
	dc.l	0000001000
	dc.l	0000000100
	dc.l	0000000010
.dec	dc.l	0000000001

;===================================================================================;
;                                  SAFE WRITE
;===================================================================================;

IceWrite:
	MOVEM.L	D0-D7/A0-A6,-(SP)
	move.l	_DOSBase,a6
	cmp.l	#100,d3
	bcc.s	.error
	CALL	dosWrite
	MOVEM.L	(SP)+,D0-D7/A0-A6
	rts

.error	move.l	#.message,d2
	move.l	#.messlen,d3
	CALL	Write
	MOVEM.L	(SP)+,D0-D7/A0-A6
	rts

.message
	dc.b	"IceBreaker:  Error in string length.",0
.messlen =	*-.message-1
	even

;===================================================================================;
;                             Text FOR PRINT ROUTINES
;===================================================================================;

_maxstep:  dc.w  2
_GFXBase:  dc.l  0
_DPKBase:  dc.l  0
InDebug:   dc.w  0

TXT_Address:	  WText "Address: "
TXT_Allocated:	  WText "Allocated.  "
TXT_AmtBuffers:	  WText "AmtBuffers: "
TXT_AmtEntries:	  WText ", AmtEntries: "
TXT_CDest:	  WText ", Dest: "
TXT_CSource:	  WText ", Source: "
TXT_File:	  WText "File: "
TXT_FileName:	  WText "FileName: "
TXT_FileBase:	  WText "FileBase: "
TXT_Flags:	  WText ", Flags: $"
TXT_ID:		  WText "ID: "
TXT_InvalidObj:   WText "Invalid object detected."
TXT_MemData:	  WText "(Data)"
TXT_MemVideo:	  WText "(Video)"
TXT_MemBlit:	  WText "(Blit)"
TXT_MemSound:	  WText "(Sound)"
TXT_Name:	  WText "Name: "
TXT_NewLine:	  dc.b  10,0
TXT_RasterAddr:	  WText " Raster: "
TXT_RestoreAddr:  WText "Restorelist: "
TXT_SourceLen:	  WText "Length: "
TXT_Source:	  WText "Source: "
TXT_ScreenAddr:	  WText "Screen: "
TXT_Size:	  WText "Size: "
TXT_Space:	  WText " "
TXT_Structure:	  WText "Structure: "
TXT_Task:	  WText "Task: "
TXT_Unknown:	  WText "Unknown.  "
TXT_Unspecified:  WText "Unspecified.  "

TXT_Flat:	  WText "[0m"
TXT_Bold:	  WText "[1m"
TXT_White:	  WText "[32m"

;-----------------------------------------------------------------------------------;
;                                    ERROR LIST
;-----------------------------------------------------------------------------------;

ErrorList:
	dc.l	ERROR_OK
	dc.l	ERROR_NoMem
	dc.l	ERROR_NoPtr
	dc.l	ERROR_InUse
	dc.l	ERROR_Struct
	dc.l	ERROR_Failed
	dc.l	ERROR_File
	dc.l	ERROR_Data
	dc.l	ERROR_Search
	dc.l	ERROR_ScrType
	dc.l	ERROR_Module
	dc.l	ERROR_RCommand
	dc.l	ERROR_RList
	dc.l	ERROR_NoRaster
	dc.l	ERROR_DiskFull
	dc.l	ERROR_FileMiss
	dc.l	ERROR_WrongVer
	dc.l	ERROR_Monitor
	dc.l	ERROR_Unpack
	dc.l	ERROR_Args
	dc.l	ERROR_NoData
	dc.l	ERROR_Read
	dc.l	ERROR_Write

ERROR_OK:	WText "OK: No problem!"
ERROR_NoMem:	WText "NOMEM: Not enough memory available."
ERROR_NoPtr:	WText "NOPTR: A required address pointer is not present."
ERROR_InUse:	WText "INUSE: Previous allocations have not been freed."
ERROR_Struct:	WText "STRUCT: Structure version not supported or found."
ERROR_Failed:	WText "FAILED: General/Miscellaneous failure."
ERROR_File:	WText "FILE: File error, eg file not found, disk full etc."
ERROR_Data:	WText "DATA: There is an error in the given data."
ERROR_Search:	WText "SEARCH: An internal search was performed and it failed."
ERROR_ScrType:	WText "SCRTYPE: Screen Type not recognised."
ERROR_Module:	WText "MODULE: Trouble initialising a system module."
ERROR_RCommand: WText "RASTCOMMAND: Invalid raster command detected."
ERROR_RList:	WText "RASTERLIST: Complete rasterlist failure."
ERROR_NoRaster: WText "NORASTER: Raster object missing from GS_Raster."
ERROR_DiskFull: WText "DISKFULL: Disk full error."
ERROR_FileMiss: WText "FILEMISSING: File not found."
ERROR_WrongVer: WText "WRONGVER: Wrong version or version not supported."
ERROR_Monitor:  WText "MONITOR: Monitor driver not found or not supported."
ERROR_Unpack:   WText "UNPACK: Problem with unpacking of data."
ERROR_Args:	WText "ARGS: Invalid arguments passed to function."
ERROR_NoData:	WText "NODATA: No data is available for use."
ERROR_Read:	WText "READ: Error reading data from file."
ERROR_Write:	WText "WRITE: Error writing data to file."

;-----------------------------------------------------------------------------------;
;                                    DEBUG LIST
;-----------------------------------------------------------------------------------;

    STRUCTURE	DataListEntry,0
	WORD	DL_State	;On = 1 / Off = 0.
	APTR	DL_Print	;Pointer to the function printer.
	LABEL	DL_SIZEOF

	MACRO	Entry
	dc.w	1	;On = 1 / Off = 0.
	dc.l	PRINT_\1	;Print function called by WriteBuffer.
	ENDM

_DebugList:
	Entry	Error	;0 
	Entry	Formatted	;1 
	Entry	BoldMessage	;2 
	Entry	Message	;3
	Entry	FreeMemBlock	;4
	Entry	Load	;5
	Entry	CopyStructure	;6
	Entry	AddInputHandler	;7
	Entry	RemInputHandler	;8
	Entry	Dead	;9
	Entry	AllocBlitter	;10
	Entry	FreeBlitter	;11
	Entry	AllocBlitMem	;12
	Entry	AllocVideoMem	;13
	Entry	AllocSoundMem	;14
	Entry	AllocAudio	;15
	Entry	FreeAudio	;16
	Entry	Dead	;17
	Entry	Dead	;18
	Entry	FindDPKTask	;19
	Entry	MoveToFront	;20
	Entry	Switch	;21
	Entry	DPKOpened	;22
	Entry	DPKClosed	;23
	Entry	Dead	;24
	Entry	Get	;25
	Entry	SelfDestruct	;26
	Entry	Armageddon	;27
	Entry	FingerOfDeath	;28
	Entry	InitDestruct	;29
	Entry	BlankOn	;30
	Entry	BlankOff	;31
	Entry	GetObjectList	;32
	Entry	GetObject	;33
	Entry	OpenFile	;34
	Entry	Free	;35
	Entry	MoveToBack	;36
	Entry	TakeDisplay	;37
	Entry	ReturnDisplay	;38
	Entry	Awaken	;39
	Entry	CreateMasks	;40
	Entry	SetBobFrames	;41
	Entry	AllocMemBlock	;42
	Entry	Init	;43
	Entry	Display	;44
	Entry	Hide	;45
	Entry	BadNumber	;46

;---------------------------------------------------------------------------;

TXT_DPKOpened:        WText "PROGRAM OPENED    "
TXT_DPKClosed:        dc.b  "PROGRAM CLOSED    ",10,0
		      even

TXT_ErrorCode:	      WText "ErrorCode:"
TXT_Error:	      WText "Error:"
TXT_Formatted:	      WText "Message:"
TXT_Message:	      WText "Message:"

TXT_AllocMemBlock:    WText "AllocMemBlock()"
TXT_FreeMemBlock:     WText "FreeMemBlock()"
TXT_AddInputHandler:  WText "AddInputHandler()"
TXT_RemInputHandler:  WText "RemInputHandler()"
TXT_AllocBlitter:     WText "AllocBlitter()"
TXT_FreeBlitter:      WText "FreeBlitter()"
TXT_AllocBlitMem:     WText "AllocBlitMem()"
TXT_AllocVideoMem:    WText "AllocVideoMem()"
TXT_AllocSoundMem:    WText "AllocSoundMem()"
TXT_AllocAudio:       WText "AllocAudio()"
TXT_FreeAudio:	      WText "FreeAudio()"
TXT_FindDPKTask:      WText "FindTask()"
TXT_MoveToFront:      WText "MoveToFront()"
TXT_Switch:           WText "Switch()"
TXT_Get:              WText "Get()"
TXT_SelfDestruct:     WText "SelfDestruct()"
TXT_Armageddon:       WText "Armageddon()"
TXT_FingerOfDeath:    WText "FingerOfDeath()"
TXT_InitDestruct:     WText "InitDestruct()"
TXT_BlankOn:          WText "BlankOn()"
TXT_BlankOff:         WText "BlankOff()"
TXT_GetObjectList:    WText "GetObjectList()"
TXT_GetObject:        WText "GetObject()"
TXT_OpenFile:	      WText "OpenFile()"
TXT_Free:             WText "Free()"
TXT_MoveToBack:       WText "MoveToBack()"
TXT_TakeDisplay:      WText "TakeDisplay()"
TXT_ReturnDisplay:    WText "ReturnDisplay()"
TXT_Awaken:	      WText "Awaken()"
TXT_CreateMasks:      WText "CreateMasks()"
TXT_SetBobFrames:     WText "SetBobFrames()"
TXT_Init:             WText "Init()"
TXT_Display:          WText "Display()"
TXT_Hide:             WText "Hide()"
TXT_Load:             WText "Load()"
TXT_CopyStructure:    WText "CopyStructure()"
TXT_BadNumber:	      WText "ERROR #"

