Diuna 3

Strategia czasu rzeczywistego

Planeta Diuna

< Poprzedni rozdział | Następny rozdział >


Realizacja silnika część 1.

Plansza

Niniejszy dokument będzie poświęcony zagadnieniom realizacji punktu I planu ramowego. Plansza złożona jest z pól. Jest to prostokątna struktura złożona z pól. Dla szybkości obliczeń szerokośc mapy (oraz wysokość) będą potęgami liczby 2. Każde pole będzie 64-bitowe i będzie zawierało wszelakie informacje o statusie pól, jak rodzaj kafla, obecność melanżu na pustyni, powiązana struktura (budynek), bądź stacjonujaca jednostka. Poza tym pole będzie przechowywało status mgły wojny.

Struktura pola będzie tworzona dynamicznie. Na razie wiadomo ile ona zajmuje, czyli dwa długie słowa. Pomieścimy tu wszystkie niezbędne informacje. Niech dane będą podzielone na 16-bitowe części. Oto zapis bitowy i legenda:

%---rodzaj kafla-- -rodzaj nakładki- -powiązany obiekt- ------flagi------

Środowisko pracy

Zanim przejdziemy do sedna sprawy, warto przygotować rozsądne środowisko pracy. Na początku program musi pobrać wiadomość od Workbencha, celem pobrania parametrów programu oraz umożliwienia używania operacji biblioteki DOS przez nasz program.

Program będę pisał w asemblerze, ale uprzednio tworząc pseudokod podobny do języka C lub Pascal. Pseudokod ma na celu przygotowanie do pisania danej funkcji oraz uodpornienia jej na błędy, które często zdarzają się w programach pisanych w asemblerze.

Zatem szkielet kodu startowego/zamykającego będzie następujący:

;program Diuna 
;begin
;	a1 := NULL;
;	d0 := FindTask(); (* Pobierz strukturę Task/Process *)
;	a0 := d0
;	a0 := &( a0->pr_MsgPort ); (* Załaduj adres portu procesu *)
;
;	if( ( d2 := d0 := GetMsg() ) <> NULL ) begin (* Pobierz wiadomość Workbencha *)
;		a0 := d0;
;		get_tooltypes(); (* Pobierz parametry *)
;	end;
;
;	program(); (* Wywołanie programu *)
;
;	if( d2 <> NULL ) begin
;		Forbid();
;		a1 := d2;
;		ReplyMsg(); (* Zwróc wiadomość Workbencha *)
;	end;
;end.

W asemblerze:

start:
	suba.l		a1,a1
	CallExec	FindTask	; Pobierz Process
	movea.l		d0,a0
	lea		pr_MsgPort(a0),a0
	CallExec	GetMsg		; Pobierz WBStartup
	move.l		d0,d2
	beq.s		.no_wb

	movea.l		d0,a0
	bsr.s		get_tooltypes	; Pobierz ToolTypes
.no_wb:
	bsr.s		program		; Wykonaj program główny
	tst.l		d2
	beq.s		.no_wb2

	CallExec	Forbid()
	movea.l		d2,a1
	CallExec	ReplyMsg	; Zwróć WBStartup

.no_wb2:
	moveq		#0,d0		; Gotowe
	rts

Jaki będzie szkielet programu głównego? Warto zastanowić się chwilę. Najpierw należy przygotować środowisko wejścia/wyjścia. Póki co zastosujemy konsolę do tego celu, ale oczywiście docelowo będzie to osobny ekran oraz kontrola za pomocą myszy i klawiatury.

Stwórzmy funkcję InitIO, która zainicjuje to środowisko:

;procedure InitIO
;	a1 := &( intuiname );
;	d0 := 39;
;	if( intuibase := d0 := OpenLibrary() ) begin
;		a0 := &( nw );
;		if( window := d0 := OpenWindow() ) begin
;			if( conmp := d0 := CreateMsgPort() ) begin
;				a0 := d0;	
;				d0 := IOSTD_SIZE;
;				if( conio := d0 := CreateIORequest() ) begin
;					a1 := d0;
;					a1->io_Data := window;
;					a1->io_Length := Window_SIZEOF;					
;					a0 := &( conname );
;					d0 := CONU_SNIPMAP;
;					d1 := 0;
;					if( ( d0 := OpenDevice() ) == 0 ) begin
;						return 0;
;					a0 := conio;
;					DeleteIORequest();
;				end;
;				a0 := conmp;
;				DeleteMsgPort();
;			end;
;			a0 := window;
;			CloseWindow();
;		end;
;		a1 := intuibase;
;		CloseLibrary();
;	end 
;	return -1;
;end;

initio:
	lea		intuiname(pc),a1
	moveq		#39,d0
	CallExec	OpenLibrary
	move.l		d0,intuibase
	beq.s		.nointui
	
	lea		newwindow(pc),a0
	CallIntui	OpenWindow	
	move.l		d0,window
	beq.s		.nowindow

	CallExec	CreateMsgPort
	move.l		d0,conmp
	beq.s		.noconmp

	movea.l		d0,a0
	move.l		#IOSTD_SIZE,d0
	CallExec	CreateIORequest
	move.l		d0,conio
	beq.s		.noconio

	movea.l		d0,a1
	move.l		window(pc),io_Data(a1)
	move.l		#Window_SIZEOF,io_Length(a1)
	lea		conname(pc),a0
	move.l		#CONU_SNIPMAP,d0
	clr.l		d1
	CallExec	OpenDevice
	tst.l		d0
	bne.s		.nocon

	rts
.nocon:
	movea.l		conio(pc),a0
	CallExec	DeleteIORequest
.nooconio:

	movea.l		conmp(pc),a0
	CallExec	DeleteMsgPort
.noconmp:

	movea.l		window(pc),a0
	CallIntui	CloseWindow
.nowindow:

	movea.l		intuibase(pc),a1
	CallExec	CloseLibrary
.nointui:
	moveq		#-1,d0
	rts

newwindow:
	dc.w	0, 56, 640, 200
	dc.b	0, 1
	dc.l	IDCMP_CLOSEWINDOW
	dc.l	WFLG_CLOSEGADGET!WFLG_DRAGBAR!WFLG_DEPTHGADGET!WFLG_SIMPLE_REFRESH!WFLG_NOCAREREFRESH
	dc.l	0
	dc.l	0
	dc.l	title
	dc.l	0
	dc.l	0
	dc.w	0, 0, ~0, ~0
	dc.w	WBENCHSCREEN


Autor strony: Robert Szacki, Ostatnia modyfikacja artykułu: 05.04.2017

Valid XHTML 1.0 Transitional