Valley of Death – Commodore 64 – Basic V2

Rivista: Micro Adventurer – Numero: 01 – Anno 1983 – Porting: Francesco Fiorentini

Come parte del progetto RetroLiPS voglio proporvi questa volta una piccola variazione sul tema. Il listato che vado a presentarvi é la conversione di un gioco originariamente prodotto per Dragon 32/64 e pubblicato in queste pagine qualche settimana fa.

Sto parlando di un breve RPG che risponde al nome di Valley of Death e che potete trovare recuperare nella sua versione originale qui.

La versione che invece troverete qua sotto é un porting dello stesso gioco per il Commodore 64. A prima vista potrebbe sembrare una cosa piuttosto semplice, ma come vedremo piú avanti, il Basic del Dragon 32/64 si avvale di alcuni comandi che mancano nel Basic V2, rendendo di fatto il porting un po’ piú divertente… Se non ci fosse un minimo di difficoltá, come potremmo divertirci?

Il listato originale di Valley of Death e’ stato pubblicato sulla rivista Micro Adventurer numero 01 di Novembre 1983, edita da Sunshine Books Ltd nel Regno Unito.

Titolo: Valley of Death
Piattaforma: Commodore 64
Linguaggio: Basic V2
Versione originale: ???
Pubblicazione: Micro Adventurer 01 – nov 1983
Anno: 1983
TrascrizioneFrancesco Fiorentini
Anno: 2021
Download: Valley of Death
Note: Porting versione per Commodore 64

Scopo del gioco

Valley Of Death consiste nel guidare un personaggio (rappresentato dal simbolo del $) in una piccola valle. Devi aiutarlo a combattere mostri, viaggiare attraverso paludi e foreste, e alla fine portarlo nelle profondità delle oscure segrete di Darganyon per trovare una chiave. Devi poi correre indietro attraverso i sotterranei, tornare al Palazzo per aprire un forziere e recuperare una pozione magica per curare il tuo Re!

Porting
Come vi accennavo nell’introduzione, il Basic del Dragon 32/64 é differente dal Basic V2 del Commodore 64. Sostanzialmente si tratta di una versione piú evoluta del Microsoft Basic.
Vediamo qualcuna delle differenze che ho incontrato e come ho deciso di effettuare il porting:

RND
L’istruzione RND del Dragon permette di specificare il range direttamente nei parametri della funzione.
Per esempio RND(10) calcolerá un numero random compreso fra 1 e 10.
Il Basic V2 non offre questa flessibilitá, quindi per generare un numero casuale fra 1 e 10 dovremo scrivere: INT(RND(1)*10+1)

PRINT
Anche la funzione PRINT del Dragon é piuttosto evoluta, permettendo di indicare dove stampare.
PRINT@352,”prova” stamperá il messaggio prova all’inizio della riga 11 (il Dragon ha 32 colonne).
Ovviamente il Commodore 64 non mette a disposizione la funzione PRINT AT, quindi dobbiamo per forza richiamare una specifica Routine del KERNAL, il Sistema Operativo (SO) del C64, denominata PLOT:
poke781,11:poke782,0:poke783,0:sys65520:print”prova”
A prima vista puó sembrare complicato, ma é soltanto lungo da scriversi… Chi volesse approfondire puó andare a dare un’occhiata all’articolo di Attilio CapuozzoCome simulare la “PRINT AT” sul C64 con il BASIC V2” pubblicato su RetroMagazine World nr. 28.

READ/DATA
Il modo in cui erano state utilizzate le funzioni READ/DATA, generava errore sul Commodore 64. In questo caso ho riscritto la logica caricando i valori dei DATA in due matrici.

SOUND
Il Basic del Dragon permette di generare un suono piuttosto facilmente tramite l’irstruzione SOUND.
Di nuovo, il Commodore 64 non ha questa funzione a disposizione. Ho dovuto quindi creare una mini routine per generare un suono quando si incappa in un mostro. Si vedano le righe da 10000 a 10200.

Altri piccoli aggiustamenti sono stati necessari e visto che c’ero ho deciso di aggiungere una nota di colore al tutto. Il risultato tutto sommato é abbastanza fedele all’originale anche se con le peculiaritá del C64.

Chi volesse provare il gioco direttamente puó scaricare il file .prg, (si veda la voce Download).

Istruzioni
All’inizio del gioco dovrete scegliere la classe del vostro personaggio da una lista di 4: Guerriero, Chierico, Barbaro e Mago. La scelta non é fine a se stessa, in quanto in base alla classe avrete a disposizione caratteristiche diverse che influenzeranno le azioni durante il gioco. Dopodiché dovrete dare un nome al vostro personaggio, se non lo farete, verrá automaticamente nominato Mr. X.
A questo punto il gioco comincia e potrete iniziare a vagare per la Valle della Morte in cerca della chiave. Per spostarvi dovete utilizzare i seguenti tasti:

Durante il vostro girovagare vi imbatterete in un numero variabile di mostri, il cui unico scopo é quello di divorarvi. Ad eccezione del Chierico, che puó allontanarsi dai mostri non morti, in tutti gli altri casi dovrete per forza sconfiggere il nemico prima di proseguire nella vostra missione. Per sferrare l’attacco, dovrete premere il pulsante H (hit) in un determinato lasso di tempo quando é il vostro turno di colpire. Attenzione, i mostri sono particolarmente fortunati nello sferrare i colpi. Buona fortuna!!!

Attenzione – Ci siamo resi conto che nel listato i caratteri ‘>’ e ‘<‘ potrebbero venir sostituiti dai rispettivi encoding html ‘&gt’ e ‘&lt’. Nel caso, sostituite questi valori nel listato prima di copiarlo sull’emulatore.

Listato:  Valley of Death – Commodore 64 – Basic V2


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
1 rem valley of death
2 rem original version dragon 32/64
3 rem commodore 64 basic v2 version
4 rem by f.fiorentini september 2021
10 printchr$(147):poke53280,0:poke53281,5:poke646,0
15 dim mx$(40):dim mh(40)
16 for c=1to40:readmx$(c):readmh(c):next
30 man=1024:z=16
40 pl=1
70 sm=int(rnd(1)*27)+1:iq=int(rnd(1)*27)+1
80 en=int(rnd(1)*27)+1:sm=sm*5:iq=iq*5:en=en*6
85 print"     {brown}{reverse on}- valley of death -{reverse off}{black}"
88 print"":print"select the class of your hero...
90 print"
1) warrior":print"2) cleric":print"3) barbarian"
100 print"
4) wizard":print"":input">which one (1-4)";a
110 ifa<1ora>4thencl$="
fool":iq=iq-(int(rnd(1)*10)+1)
120 ifa=1thencl$="
warrior":sm=sm+(int(rnd(1)*sm)+1):iq=iq+(int(rnd(1)*10)+1)
130 ifa=2thencl$="
cleric":iq=iq+((int(rnd(1)*10)+1)*2)
140 ifa=3thencl$="
barbarian":iq=iq-(int(rnd(1)*10)+1):sm=sm+(int(rnd(1)*sm)+1)
150 ifa=3thenen=en+(int(rnd(1)*sm)+1)
160 ifa=4thencl$="
wizard":iq=iq+((int(rnd(1)*15)+1)*2):en=en+(int(rnd(1)*5)+1)
170 print"
":input">name";nm$
180 ifnm$="
"thennm$="mr.'x'"
190 printchr$(147)
191 poke781,0:poke782,0:poke783,0:sys65520:print"{red}{reverse on}      - valley of death -       {reverse off}{black}"
195 sp$="{space*30}":sb$="{cm +*32}"
200 print sb$
205 forn=0to7
210 print chr$(166);sp$;chr$(166):next
220 print sb$
230 a$(1)=chr$(166)+"#####################--#######"+chr$(166)
240 a$(2)=chr$(166)+"#----########----##-## --#####"+chr$(166)
250 a$(3)=chr$(166)+"p####-####---####--######----k"+chr$(166)
260 a$(4)=chr$(166)+"######----"+"                    "+chr$(166)
270 j=int(rnd(1)*5)+2
271 poke781,j:poke782,0:poke783,0:sys65520:printa$(1):printa$(2):printa$(3)
280 printa$(4)
360 poke781,14:poke782,0:poke783,0:sys65520:printsp$
361 poke781,15:poke782,0:poke783,0:sys65520:printsp$
362 poke781,14:poke782,0:poke783,0:sys65520:print "    {brown}{reverse on} "nm$;" the ";cl$" {reverse off}{black}"
370 poke781,15:poke782,0:poke783,0:sys65520:print"st:";sm;tab(10);"iq:";iq;tab(20);"en:";
380 printen;:poke781,16:poke782,0:poke783,0:sys65520:print"tr:";tr;tab(20);"ex:";ex;
390 if u=1 then return
400 u=1
410 man=man+((j+2)*40)+1
440 poke man,36
490 gosub 360
500 if int(rnd(1)*4)=2anddead=0andcastle=0andpath=0andpl=0thengosub2770
530 gosub 2300
540 e=e+1:ife=10thenen=en-1:e=0
560 ifpeek(man+d)=166then d=0:man=man+d:goto440
565 ifpeek(man+d)=45thenman=man+d:pokeman-d,z:path=1:z=peek(man):goto660
570 ifpeek(man+d)=11thenman=man+d:pokeman-d,z:castle=1:z=peek(man):goto660
580 ifpeek(man+d)=16thenman=man+d:pokeman-d,z:pl=1:z=peek(man):goto660
650 ifpeek(man+d)<>166thenman=man+d:pokeman-d,z:z=peek(man):goto660
660 ifz<>11thencastle=0
670 ifz<>16thenpl=0
680 ifz<>45thenpath=0
700 poke781,12:poke782,0:poke783,0:sys65520:printsp$
710 ifpath=1thenpoke781,12:poke782,0:poke783,0:sys65520:print"{reverse on}safe on path{reverse off}"
720 ifcastle=1thenpoke781,12:poke782,0:poke783,0:sys65520:print"{reverse on}safe in keep{reverse off}"
750 ifpl=1thenpoke781,12:poke782,0:poke783,0:sys65520:print"{reverse on}safe in palace{reverse off}"
790 goto440
2300 poke198,0:wait 198,1:get a$:ifa$=""then2300
2305 d=0
2310 ifa$="r"thend=-41
2320 ifa$="t"thend=-40
2330 ifa$="y"thend=-39
2340 ifa$="f"thend=-1
2350 ifa$="h"thend=1
2360 ifa$="c"thend=39
2370 ifa$="v"thend=40
2380 ifa$="b"thend=41
2450 return
2770 ifex<2000andtw=0then c=(int(rnd(1)*19)+1):mr$=mx$(c):hits=mh(c)
2780 m=0
2790 ifex>=2000ortw=1then c=(int(rnd(1)*19)+1)+20::mr$=mx$(c):hits=mh(c)
2810 rem forn=1tolen(mr$):mid$(mr$,n,1)=chr$(asc(mid$(mr$,n,1))+32)
2811 rem ifmid$(mr$,n,1)="@"thenmid$(mr$,n,1)=chr$(128):next:mr$;
2816 gosub10000
2820 poke781,12:poke782,0:poke783,0:sys65520:print"{reverse on}you have met a ";mr$;"{reverse off}"
2830 ifcl$="cleric"and(mr$="mummy"ormr$="wraith"ormr$="spectre")and(int(rnd(1)*3)+1)=2thenyz=1
2840 ifyz=1then 2842
2841 goto 2850
2842 forn=0to2000:next:poke781,12:poke782,0:poke783,0:sys65520:print"but you turn it away!"
2843 forn=0to2000:next:poke781,12:poke782,0:poke783,0:sys65520:printsp$:ex=ex+h:yz=0:return
2850 hits=hits+int(rnd(1)*(hits/2)+1):ifhits<int(en/2)then2850
2860 h=hits
2870 forn=0to1000:next
2880 poke781,18:poke782,0:poke783,0:sys65520:print"strike now"
2900 get a$
2910 poke781,20:poke782,0:poke783,0:sys65520:printsp$
2920 poke781,20:poke782,0:poke783,0:sys65520:print"{reverse on}the monster has";hits;"energy{reverse off}";
2930 forn=0to300:poke198,0:wait 198,1:get a$:ifa$<>""then2960
2932 poke781,18:poke782,0:poke783,0:sys65520:printsp$
2935 next:poke781,18:poke782,0:poke783,0:sys65520:print"too slow":
2940 forn=0to2000:next:poke781,18:poke782,0:poke783,0:sys65520:printsp$:goto2990
2960 ifa$="h"and(int(rnd(1)*2)+1)=2thengoto2962
2961 goto2975
2962 g=(int(rnd(1)*en)+1)+(int(rnd(1)*sm)+1)*sd
2963 poke781,18:poke782,0:poke783,0:sys65520:printsp$
2967 poke781,18:poke782,0:poke783,0:sys65520:print"you hit":
2968 forn=0to2000:next:poke781,18:poke782,8:poke783,0:sys65520:print "with";g;"damage!";
2969 forn=0to3000:next:yz=1
2970 ifyz=1thengoto2972
2971 goto2980
2972 poke781,18:poke782,0:poke783,0:sys65520:printsp$:hits=hits-g:
2973 ifa$="h"andyz=0then goto2975
2974 yz=0:goto2980
2975 poke781,18:poke782,0:poke783,0:sys65520:print"you missed"
2976 forn=0to2000:next:poke781,18:poke782,0:poke783,0:sys65520:printsp$;:yz=0
2980 ifg>0then:g=0
2985 ifhits<=0then3110
2990 ifg<=0then 2992
2991 goto 3010
2992 poke781,20:poke782,0:poke783,0:sys65520:printsp$
2993 poke781,20:poke782,0:poke783,0:sys65520:print"{reverse on}the monster has";hits;"energy{reverse off}";
3010 poke781,18:poke782,0:poke783,0:sys65520:print"the monster strikes"
3011 forn=0to2000:next:poke781,18:poke782,0:poke783,0:sys65520:printsp$
3020 if(int(rnd(1)*2)+1)=1thengoto3022
3021 goto3025
3022 m=(int(rnd(1)*hits)+1)
3023 poke781,18:poke782,0:poke783,0:sys65520:print"and hits";:forn=0to2000:next:goto3030
3025 poke781,18:poke782,0:poke783,0:sys65520:print"and misses":yz=1
3030 ifyz=1thenforn=0to2000:next:poke781,16:poke782,0:poke783,0:sys65520:printsp$:yz=0
3040 en=en-m
3050 ifm>0thengoto3053
3051 goto3060
3053 poke781,18:poke782,0:poke783,0:sys65520:printsp$
3055 poke781,18:poke782,0:poke783,0:sys65520:print"doing";m;"damage!";
3056 forn=0to2000:next:poke781,18:poke782,0:poke783,0:sys65520:printsp$
3060 gosub360
3070 m=0
3080 ifen<=0then3770
3100 hits=hits-1:en=en-1:poke198,0:goto2880
3110 poke781,18:poke782,0:poke783,0:sys65520:printsp$
3111 poke781,12:poke782,0:poke783,0:sys65520:printsp$
3112 poke781,18:poke782,0:poke783,0:sys65520:print"you've killed it!":
3113 ex=ex+h:en=en+(int(rnd(1)*(h/2))+1)
3120 forn=0to2000:next:poke781,12:poke782,0:poke783,0:sys65520:printsp$
3122 poke781,18:poke782,0:poke783,0:sys65520:printsp$
3125 poke781,20:poke782,0:poke783,0:sys65520:printsp$
3130 ifen>400thenen=en-(int(rnd(1)*(h/2))+1)
3140 return
3200 data"bandit",20,"berserker",20,"bugbear",60,"carrion crawler",60
3205 data"cockatrice",100,"dwarf",20,"doppleganger",80,"elf",20,"fire beetle",20
3210 data"gargoyle",80,"gelatinus cube",80,"giant ant",40,"giant centipede",5
3215 data"giant rat",10,"gnoll",40,"gnome",10,"goblin",10,"grey ooze",60
3220 data"hippogriff",65,"hobgoblin",15,"black pudding",200,"chimera",180
3225 data"djinni",145,"dragon",220,"giant",200,"griffon",140,"hydra",160
3230 data"werebear",120,"manticore",125,"minotaur",120,"mummy",105,"ogre",120
3235 data"owl bear",110,"purple worm",300,"spectre",120
3240 data"troll",130,"vampire",180,"wight",60,"wraith",80,"hell hound",140
3770 poke781,12:poke782,0:poke783,0:sys65520:printsp$
3772 poke781,12:poke782,0:poke783,0:sys65520:print"{red}{reverse on}you're dead!!!{reverse off}{black}"
3775 gosub10000
3776 gosub10000
3777 gosub10000
3778 poke781,12:poke782,0:poke783,0:sys65520:printsp$
3779 poke781,12:poke782,0:poke783,0:sys65520:print"{reverse on}another game?{reverse off}"
3780 end
10000 rem routine for sound
10005 s=54272
10010 forl=stos+24:pokel,0:next:rem clear sound chip
10020 pokes+5,9:pokes+6,0:pokes+24,15: rem max volume
10060 pokes+1,28:pokes,214:pokes+4,33
10080 fort=1to250:next
10090 pokes+4,32:fort=1to50:next
10100 pokes+1,19:pokes,63:pokes+4,33
10120 fort=1to250:next
10130 pokes+4,32:fort=1to50:next
10200 return

Share

One thought on “Valley of Death – Commodore 64 – Basic V2

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.