Ich hab mal JavaScript und HTML programmiert, um einen "CPC Adventure Generator" zu basteln, damit kann man relativ einfach komplexe Textadventure-Spiele erzeugen. Der BASIC Code kann direkt ausgegeben werden.
2 Beispiele sind bereits vorhanden.
Der Parser kann wahlweise auch auf Deutsch, Französisch oder Spanisch eingestellt werden, Default-Sprache ist Englisch.
Verwendet im Spiel allerdings keine Umlaute! ;)
Viel Spaß beim Erstellen! Ich bin auf Ergebnisse gespannt!
https://cpcwiki.de/adventure/
Anleitung findet ihr unter "Hilfe" 🕹🕹🕹
Kann man da Anstelle von BASIC auch Maschinen-Sprache nehmen?
Wenn Du Lust hast das einzubauen, dann helfe ich gerne :)
Wozu? ;) Du kannst ja den Code dann in MC umschreiben :P
Da der CPC ja von Haus aus BASIC kann, ist das nicht notwendig, es soll ja die User dazu animieren, auch BASIC zu verstehen...
Aber tu dir keinen Zwang an, du musst nur diesen Teil umschreiben, dass er MC Code (Assembler) erzeugt:
// ========================================
// BASIC CODE GENERATOR v5.4
// With Multilingual Command Support
// ========================================
// ========== WORD WRAP HELPER ==========
function wrapText(text, forPrint) {
if (forPrint === undefined) forPrint = false;
var maxLen = 40;
if (!text || text.length <= maxLen) return text || "";
var separator = forPrint
? "\";CHR$(13);CHR$(10);\""
: "\"+CHR$(13)+CHR$(10)+\"";
var result = "";
var remaining = text;
var first = true;
while (remaining.length > 0) {
if (remaining.length <= maxLen) {
if (!first) {
result += separator;
}
result += remaining;
break;
}
var breakPos = remaining.lastIndexOf(' ', maxLen);
if (breakPos <= 0) {
breakPos = maxLen;
}
if (!first) {
result += separator;
}
result += remaining.substring(0, breakPos);
remaining = remaining.substring(breakPos).trimStart();
first = false;
}
return result;
}
// ========== SAFE STRING HELPER ==========
function safeStr(str, maxLen) {
if (!str) return "";
if (maxLen) return String(str).substring(0, maxLen);
return String(str);
}
// ========== BASIC CODE GENERATOR ==========
function genCode() {
var rc = Object.keys(S.rooms).length;
var ic = Object.keys(S.items).length;
var nc = Object.keys(S.npcs).length;
if (rc === 0) {
console.log("genCode: No rooms found");
return null;
}
var maxR = Math.max.apply(null, Object.values(S.rooms).map(function(r) { return r.num; })) + 5;
var dimI = Math.max(ic + 5, 10);
var dimN = Math.max(nc + 5, 5);
var rooms = Object.entries(S.rooms).sort(function(a, b) { return a[1].num - b[1].num; });
var items = Object.entries(S.items);
var npcs = Object.entries(S.npcs);
var deadly = rooms.filter(function(r) { return r[1].deadly; });
var winItems = S.game.winItems ? S.game.winItems.split(',').map(function(s) { return s.trim(); }).filter(function(s) { return s; }) : [];
var m = S.msg || {};
// ========== COMMAND & KEYWORD SETUP ==========
// Default commands (English fallback)
var defaultCommands = {
north: ["N", "NORTH"],
south: ["S", "SOUTH"],
east: ["E", "EAST"],
west: ["W", "WEST"],
up: ["U", "UP"],
down: ["D", "DOWN", "DN"],
look: ["L", "LOOK"],
inventory: ["I", "INV", "INVENTORY"],
take: ["TAKE", "GET"],
drop: ["DROP"],
use: ["USE"],
examine: ["EXAMINE", "X"],
open: ["OPEN"],
close: ["CLOSE"],
talk: ["TALK"],
give: ["GIVE"],
put: ["PUT"],
score: ["SCORE"],
help: ["HELP", "?"],
save: ["SAVE"],
load: ["LOAD"],
quit: ["QUIT", "Q"]
};
var defaultKeywords = {
to: "TO",
from: "FROM",
in: "IN",
at: "AT"
};
var defaultDirections = {
north: "N",
south: "S",
east: "E",
west: "W",
up: "UP",
down: "DN"
};
var cmd = (m.commands && typeof m.commands === 'object') ? m.commands : defaultCommands;
var kw = (m.keywords && typeof m.keywords === 'object') ? m.keywords : defaultKeywords;
var dirs = (m.directions && typeof m.directions === 'object') ? m.directions : defaultDirections;
// Helper functions
function getKeyword(key) {
var val = kw[key] || defaultKeywords[key] || key;
return String(val).toUpperCase();
}
function getCmdVariants(action) {
var variants = cmd[action];
if (!variants || !Array.isArray(variants) || variants.length === 0) {
// Fallback to default
variants = defaultCommands[action];
if (!variants || !Array.isArray(variants) || variants.length === 0) {
return [action.toUpperCase()];
}
}
return variants.map(function(v) { return String(v).toUpperCase(); });
}
function getPrimaryCmd(action) {
return getCmdVariants(action)[0];
}
function getDirAbbr(dir) {
var name = dirs[dir] || defaultDirections[dir] || dir;
if (typeof name === 'string') {
return name.length <= 2 ? name.toUpperCase() : name.substring(0, 2).toUpperCase();
}
return dir.substring(0, 1).toUpperCase();
}
// Keywords
var KW_TO = getKeyword('to');
var KW_FROM = getKeyword('from');
var KW_IN = getKeyword('in');
var KW_AT = getKeyword('at');
// Primary commands
var CMD_USE = getPrimaryCmd('use');
var CMD_TAKE = getPrimaryCmd('take');
var CMD_DROP = getPrimaryCmd('drop');
var CMD_EXAMINE = getPrimaryCmd('examine');
var CMD_OPEN = getPrimaryCmd('open');
var CMD_CLOSE = getPrimaryCmd('close');
var CMD_TALK = getPrimaryCmd('talk');
var CMD_GIVE = getPrimaryCmd('give');
var CMD_PUT = getPrimaryCmd('put');
var CMD_LOOK = getPrimaryCmd('look');
// Safe message access
function msg(key, fallback, maxLen) {
var val = m[key] || fallback || "";
if (maxLen) return String(val).substring(0, maxLen);
return String(val);
}
var L = [];
// ========== HEADER ==========
L.push("10 REM *** " + safeStr(S.game.title, 28).toUpperCase() + " ***");
L.push("20 REM *** BY " + safeStr(S.game.author, 24).toUpperCase() + " ***");
L.push("30 MODE 1:INK 0,0:INK 1,24:BORDER 0:PEN 1:PAPER 0");
L.push("40 DIM R$(" + maxR + "),D$(" + maxR + "),RL(" + maxR + ",6),RD$(" + maxR + ",6),UL(" + maxR + ",6)");
L.push("50 DIM IT$(" + dimI + "),ID$(" + dimI + "),IL(" + dimI + "),IC(" + dimI + "),IO(" + dimI + "),IP(" + dimI + "),IS(" + dimI + ")");
L.push("60 DIM NP$(" + dimN + "),ND$(" + dimN + "),NT$(" + dimN + "),NW$(" + dimN + "),NR$(" + dimN + "),NS(" + dimN + "),NL(" + dimN + "),NG(" + dimN + ")");
L.push("70 DIM TD(" + Math.max(deadly.length + 1, 3) + "),TM$(" + Math.max(deadly.length + 1, 3) + "),TS$(" + Math.max(deadly.length + 1, 3) + ")");
L.push("80 DIM INV$(20)");
L.push("90 CR=" + S.game.startRoom + ":SC=0:IC=0:ML=" + S.game.invLimit + ":NM=" + ic + ":NN=" + nc + ":RF=1");
L.push("95 GOSUB 1500:GOSUB 3000");
// ========== MAIN LOOP ==========
L.push("100 IF RF=1 THEN GOSUB 200:RF=0");
L.push("110 GOSUB 300");
L.push("120 GOSUB 400");
L.push("130 GOTO 100");
// ========== SHOW ROOM (200-299) ==========
L.push("200 CLS:PRINT:PRINT R$(CR):PRINT STRING$(40,42)");
L.push("210 PRINT D$(CR):PRINT");
L.push("220 FOR J=1 TO NM:IF IL(J)=CR AND IP(J)=0 THEN PRINT \"" + msg('youSee', 'You see: ', 40) + "\";IT$(J)");
L.push("230 NEXT J");
L.push("240 FOR J=1 TO NN:IF NL(J)=CR THEN PRINT \"" + msg('youSee', 'You see: ', 24) + "\";NP$(J)");
L.push("250 NEXT J");
L.push("260 PRINT:PRINT \"" + msg('exits', 'Exits: ', 10) + "\";");
L.push("261 EX$=\"\"");
L.push("262 IF RL(CR,1)>0 THEN EX$=EX$+\"" + getDirAbbr('north') + " \"");
L.push("263 IF RL(CR,2)>0 THEN EX$=EX$+\"" + getDirAbbr('east') + " \"");
L.push("264 IF RL(CR,3)>0 THEN EX$=EX$+\"" + getDirAbbr('south') + " \"");
L.push("265 IF RL(CR,4)>0 THEN EX$=EX$+\"" + getDirAbbr('west') + " \"");
L.push("266 IF RL(CR,5)>0 THEN EX$=EX$+\"" + getDirAbbr('up') + " \"");
L.push("267 IF RL(CR,6)>0 THEN EX$=EX$+\"" + getDirAbbr('down') + " \"");
L.push("268 IF EX$=\"\" THEN EX$=\"" + msg('none', 'none', 6) + "\"");
L.push("270 PRINT EX$:PRINT \"" + msg('score', 'Score: ', 8) + "\";SC");
L.push("280 RETURN");
// ========== INPUT (300-350) ==========
L.push("300 PRINT:PRINT \"> \";:LINE INPUT C$:C$=UPPER$(C$):RETURN");
// ========== PARSE (400-499) - DYNAMIC GENERATION ==========
var pln = 400;
// Movement directions
var directions = [
{ action: 'north', mv: 1 },
{ action: 'south', mv: 3 },
{ action: 'east', mv: 2 },
{ action: 'west', mv: 4 },
{ action: 'up', mv: 5 },
{ action: 'down', mv: 6 }
];
directions.forEach(function(d) {
var variants = getCmdVariants(d.action);
var checks = variants.map(function(v) { return "C$=\"" + v + "\""; }).join(" OR ");
L.push(pln + " IF " + checks + " THEN MV=" + d.mv + ":GOSUB 500:RETURN");
pln += 2;
});
// USE - all variants
getCmdVariants('use').forEach(function(v) {
L.push(pln + " IF LEFT$(C$," + v.length + ")=\"" + v + "\" THEN TK$=MID$(C$," + (v.length + 2) + "):GOSUB 550:RETURN");
pln += 2;
});
// TAKE FROM - all TAKE variants with FROM keyword
getCmdVariants('take').forEach(function(v) {
L.push(pln + " IF LEFT$(C$," + v.length + ")=\"" + v + "\" AND INSTR(C$,\" " + KW_FROM + " \")>0 THEN GOSUB 1600:RETURN");
pln += 2;
});
// TAKE - all variants
getCmdVariants('take').forEach(function(v) {
L.push(pln + " IF LEFT$(C$," + v.length + ")=\"" + v + "\" THEN TK$=MID$(C$," + (v.length + 2) + "):GOSUB 600:RETURN");
pln += 2;
});
// DROP - all variants
getCmdVariants('drop').forEach(function(v) {
L.push(pln + " IF LEFT$(C$," + v.length + ")=\"" + v + "\" THEN TK$=MID$(C$," + (v.length + 2) + "):GOSUB 650:RETURN");
pln += 2;
});
// EXAMINE - all variants
getCmdVariants('examine').forEach(function(v) {
L.push(pln + " IF LEFT$(C$," + v.length + ")=\"" + v + "\" THEN TK$=MID$(C$," + (v.length + 2) + "):GOSUB 700:RETURN");
pln += 2;
});
// LOOK AT - special handling
var lookVariants = getCmdVariants('look');
lookVariants.forEach(function(v) {
var lookAt = v + " " + KW_AT;
L.push(pln + " IF LEFT$(C$," + lookAt.length + ")=\"" + lookAt + "\" THEN TK$=MID$(C$," + (lookAt.length + 2) + "):GOSUB 700:RETURN");
pln += 2;
});
// TALK TO - all variants
getCmdVariants('talk').forEach(function(v) {
var talkTo = v + " " + KW_TO;
L.push(pln + " IF LEFT$(C$," + talkTo.length + ")=\"" + talkTo + "\" THEN TK$=MID$(C$," + (talkTo.length + 2) + "):GOSUB 750:RETURN");
pln += 2;
});
// GIVE - all variants
getCmdVariants('give').forEach(function(v) {
L.push(pln + " IF LEFT$(C$," + v.length + ")=\"" + v + "\" THEN GOSUB 800:RETURN");
pln += 2;
});
// OPEN - all variants
getCmdVariants('open').forEach(function(v) {
L.push(pln + " IF LEFT$(C$," + v.length + ")=\"" + v + "\" THEN TK$=MID$(C$," + (v.length + 2) + "):GOSUB 850:RETURN");
pln += 2;
});
// CLOSE - all variants
getCmdVariants('close').forEach(function(v) {
L.push(pln + " IF LEFT$(C$," + v.length + ")=\"" + v + "\" THEN TK$=MID$(C$," + (v.length + 2) + "):GOSUB 870:RETURN");
pln += 2;
});
// LOOK IN - special handling
lookVariants.forEach(function(v) {
var lookIn = v + " " + KW_IN;
L.push(pln + " IF LEFT$(C$," + lookIn.length + ")=\"" + lookIn + "\" THEN TK$=MID$(C$," + (lookIn.length + 2) + "):GOSUB 890:RETURN");
pln += 2;
});
// PUT - all variants
getCmdVariants('put').forEach(function(v) {
L.push(pln + " IF LEFT$(C$," + v.length + ")=\"" + v + "\" THEN GOSUB 920:RETURN");
pln += 2;
});
// INVENTORY - exact matches
var invVariants = getCmdVariants('inventory');
var invChecks = invVariants.map(function(v) { return "C$=\"" + v + "\""; }).join(" OR ");
L.push(pln + " IF " + invChecks + " THEN GOSUB 980:RETURN");
pln += 2;
// LOOK - exact matches
var lookChecks = lookVariants.map(function(v) { return "C$=\"" + v + "\""; }).join(" OR ");
L.push(pln + " IF " + lookChecks + " THEN RF=1:RETURN");
pln += 2;
// HELP
var helpVariants = getCmdVariants('help');
var helpChecks = helpVariants.map(function(v) { return "C$=\"" + v + "\""; }).join(" OR ");
L.push(pln + " IF " + helpChecks + " THEN GOSUB 1050:RETURN");
pln += 2;
// SAVE
var saveVariants = getCmdVariants('save');
var saveChecks = saveVariants.map(function(v) { return "C$=\"" + v + "\""; }).join(" OR ");
L.push(pln + " IF " + saveChecks + " THEN GOSUB 1100:RETURN");
pln += 2;
// LOAD
var loadVariants = getCmdVariants('load');
var loadChecks = loadVariants.map(function(v) { return "C$=\"" + v + "\""; }).join(" OR ");
L.push(pln + " IF " + loadChecks + " THEN GOSUB 1150:RETURN");
pln += 2;
// SCORE
var scoreVariants = getCmdVariants('score');
var scoreChecks = scoreVariants.map(function(v) { return "C$=\"" + v + "\""; }).join(" OR ");
L.push(pln + " IF " + scoreChecks + " THEN PRINT:PRINT \"" + msg('score', 'Score: ', 8) + "\";SC:GOSUB 1090:RETURN");
pln += 2;
// QUIT
var quitVariants = getCmdVariants('quit');
var quitChecks = quitVariants.map(function(v) { return "C$=\"" + v + "\""; }).join(" OR ");
L.push(pln + " IF " + quitChecks + " THEN PRINT:PRINT \"" + msg('bye', 'Goodbye!', 24) + "\":END");
pln += 2;
// Unknown command
L.push(pln + " PRINT \"" + msg('unknown', 'Huh?', 24) + "\":RETURN");
// ========== MOVE (500-545) ==========
L.push("500 NR=RL(CR,MV):IF NR=0 THEN PRINT \"" + msg('cantGo', "Can't go there.", 18) + "\":RETURN");
L.push("510 RQ$=RD$(CR,MV):IF RQ$=\"OPEN\" OR UL(CR,MV)=1 THEN 530");
L.push("520 PRINT \"" + msg('blocked', 'Blocked.', 12) + " " + msg('need', 'Need: ', 8) + "\";RQ$:RETURN");
L.push("530 CR=NR:RF=1:GOSUB 1200:GOSUB 1300:RETURN");
// ========== USE (550-599) ==========
L.push("550 IF TK$=\"\" THEN PRINT \"" + msg('useWhat', 'Use what?', 15) + "\":RETURN");
L.push("560 FD=0:FOR J=1 TO IC:IF INSTR(INV$(J),TK$)>0 THEN FD=J");
L.push("565 NEXT J:IF FD=0 THEN PRINT \"" + msg('dontHave', "Don't have it.", 18) + "\":RETURN");
L.push("570 FOR MV=1 TO 6:IF RD$(CR,MV)=INV$(FD) AND UL(CR,MV)=0 THEN UL(CR,MV)=1:PRINT \"" + msg('unlocked', 'Unlocked!', 15) + "\":RETURN");
L.push("580 NEXT MV:PRINT \"" + msg('nothing', 'Nothing happens.', 15) + "\":RETURN");
// ========== TAKE (600-645) ==========
L.push("600 IF TK$=\"\" THEN PRINT \"" + msg('what', 'What?', 8) + "\":RETURN");
L.push("605 FOR J=1 TO NM:IF IC(J)=1 THEN 630");
L.push("610 IF IL(J)<>CR THEN 630");
L.push("615 IF IP(J)<>0 THEN 630");
L.push("620 IF INSTR(IT$(J),TK$)>0 THEN 640");
L.push("630 NEXT J:PRINT \"" + msg('notHere', 'Not here.', 12) + "\":RETURN");
L.push("640 IF IC>=ML THEN PRINT \"" + msg('full', 'Full!', 10) + "\":RETURN");
L.push("642 IC=IC+1:INV$(IC)=IT$(J):IL(J)=0:SC=SC+IS(J):IS(J)=0");
L.push("645 PRINT \"" + msg('taken', 'Taken.', 10) + "\":RETURN");
// ========== DROP (650-699) ==========
L.push("650 IF TK$=\"\" THEN PRINT \"" + msg('what', 'What?', 8) + "\":RETURN");
L.push("660 FOR J=1 TO IC:IF INSTR(INV$(J),TK$)>0 THEN 680");
L.push("670 NEXT J:PRINT \"" + msg('dontHave', "Don't have it.", 18) + "\":RETURN");
L.push("680 FOR K=1 TO NM:IF IT$(K)=INV$(J) THEN IL(K)=CR:IP(K)=0");
L.push("685 NEXT K");
L.push("690 FOR K=J TO IC-1:INV$(K)=INV$(K+1):NEXT K:IC=IC-1");
L.push("695 PRINT \"" + msg('dropped', 'Dropped.', 10) + "\":RETURN");
// ========== EXAMINE (700-745) ==========
L.push("700 IF TK$=\"\" THEN PRINT \"" + msg('what', 'What?', 8) + "\":RETURN");
L.push("710 FOR J=1 TO NM:IF INSTR(IT$(J),TK$)>0 THEN IF IL(J)=CR OR IL(J)=0 THEN 730");
L.push("720 NEXT J");
L.push("722 FOR J=1 TO NN:IF INSTR(NP$(J),TK$)>0 AND NL(J)=CR THEN PRINT:PRINT ND$(J):GOSUB 1090:RETURN");
L.push("725 NEXT J:PRINT \"" + msg('notHere', 'Not here.', 12) + "\":RETURN");
L.push("730 IF ID$(J)=\"\" THEN PRINT \"" + msg('examine', 'You see nothing special.', 30) + "\":RETURN");
L.push("735 PRINT:PRINT ID$(J):GOSUB 1090:RETURN");
// ========== TALK (750-795) ==========
L.push("750 IF TK$=\"\" THEN PRINT \"" + msg('talkTo', 'Talk to whom?', 15) + "\":RETURN");
L.push("760 FOR J=1 TO NN:IF INSTR(NP$(J),TK$)>0 AND NL(J)=CR THEN 780");
L.push("770 NEXT J:PRINT \"" + msg('noOne', 'No one here.', 15) + "\":RETURN");
L.push("780 IF NT$(J)=\"\" THEN PRINT \"...\":RETURN");
L.push("785 PRINT:PRINT CHR$(34);NT$(J);CHR$(34):GOSUB 1090:RETURN");
// ========== GIVE (800-845) ==========
var giveLen = CMD_GIVE.length;
var toLen = KW_TO.length;
L.push("800 G1$=\"\":G2$=\"\":P=INSTR(C$,\" " + KW_TO + " \")");
L.push("805 IF P=0 THEN PRINT \"" + CMD_GIVE + " X " + KW_TO + " Y\":RETURN");
L.push("810 G1$=MID$(C$," + (giveLen + 2) + ",P-" + (giveLen + 2) + "):G2$=MID$(C$,P+" + (toLen + 2) + ")");
L.push("815 IF G1$=\"\" THEN PRINT \"" + msg('give', 'Give what?', 12) + "\":RETURN");
L.push("820 IF G2$=\"\" THEN PRINT \"" + msg('toWhom', 'To whom?', 12) + "\":RETURN");
L.push("825 FI=0:FOR J=1 TO IC:IF INSTR(INV$(J),G1$)>0 THEN FI=J");
L.push("830 NEXT J:IF FI=0 THEN PRINT \"" + msg('dontHave', "Don't have it.", 18) + "\":RETURN");
L.push("832 FKN=0:FOR J=1 TO NN:IF INSTR(NP$(J),G2$)>0 AND NL(J)=CR THEN FKN=J");
L.push("835 NEXT J:IF FKN=0 THEN PRINT \"" + msg('noOne', 'No one here.', 15) + "\":RETURN");
L.push("837 IF NG(FKN)=1 THEN PRINT \"" + msg('nothing', 'Nothing happens.', 15) + "\":RETURN");
L.push("840 IF NW$(FKN)<>INV$(FI) THEN PRINT \"" + msg('noWant', "They don't want that.", 20) + "\":RETURN");
L.push("842 FOR K=FI TO IC-1:INV$(K)=INV$(K+1):NEXT K:IC=IC-1");
L.push("843 SC=SC+NS(FKN):NG(FKN)=1:PRINT \"" + msg('thanks', 'Thanks!', 10) + "\"");
L.push("845 IF NR$(FKN)<>\"\" THEN IC=IC+1:INV$(IC)=NR$(FKN):PRINT \"Got: \";NR$(FKN)");
L.push("847 RETURN");
// ========== OPEN (850-869) ==========
L.push("850 IF TK$=\"\" THEN PRINT \"" + msg('what', 'What?', 8) + "\":RETURN");
L.push("855 FOR J=1 TO NM:IF INSTR(IT$(J),TK$)>0 AND IC(J)=1 THEN 857");
L.push("856 NEXT J:PRINT \"" + msg('notContainer', "Can't open that.", 18) + "\":RETURN");
L.push("857 IF IL(J)<>CR AND IL(J)<>0 THEN PRINT \"" + msg('notHere', 'Not here.', 12) + "\":RETURN");
L.push("860 IO(J)=1:PRINT \"" + msg('open', 'Opened.', 12) + "\":RETURN");
// ========== CLOSE (870-889) ==========
L.push("870 IF TK$=\"\" THEN PRINT \"" + msg('what', 'What?', 8) + "\":RETURN");
L.push("875 FOR J=1 TO NM:IF INSTR(IT$(J),TK$)>0 AND IC(J)=1 AND IO(J)=1 THEN 880");
L.push("877 NEXT J:PRINT \"" + msg('notContainer', "Can't open that.", 18) + "\":RETURN");
L.push("880 IO(J)=0:PRINT \"" + msg('close', 'Closed.', 12) + "\":RETURN");
// ========== LOOK IN (890-919) ==========
L.push("890 IF TK$=\"\" THEN PRINT \"" + msg('what', 'What?', 8) + "\":RETURN");
L.push("895 FC=0:FOR J=1 TO NM:IF INSTR(IT$(J),TK$)>0 AND IC(J)=1 THEN FC=J");
L.push("900 NEXT J:IF FC=0 THEN PRINT \"" + msg('notContainer', "Can't open that.", 18) + "\":RETURN");
L.push("905 IF IO(FC)=0 THEN PRINT \"" + msg('blocked', 'Blocked.', 12) + "\":RETURN");
L.push("910 PRINT:PRINT \"" + msg('lookIn', 'Inside: ', 10) + "\"");
L.push("912 FO=0:FOR J=1 TO NM:IF IP(J)=FC THEN PRINT \" \";IT$(J):FO=1");
L.push("914 NEXT J:IF FO=0 THEN PRINT \" " + msg('emptyC', 'Empty.', 8) + "\"");
L.push("916 GOSUB 1090:RETURN");
// ========== PUT IN (920-979) ==========
var putLen = CMD_PUT.length;
var inLen = KW_IN.length;
L.push("920 P=INSTR(C$,\" " + KW_IN + " \"):IF P=0 THEN PRINT \"" + CMD_PUT + " X " + KW_IN + " Y\":RETURN");
L.push("925 G1$=MID$(C$," + (putLen + 2) + ",P-" + (putLen + 2) + "):G2$=MID$(C$,P+" + (inLen + 2) + ")");
L.push("930 IF G1$=\"\" OR G2$=\"\" THEN PRINT \"" + msg('what', 'What?', 8) + "\":RETURN");
L.push("935 FI=0:FOR J=1 TO IC:IF INSTR(INV$(J),G1$)>0 THEN FI=J");
L.push("940 NEXT J:IF FI=0 THEN PRINT \"" + msg('dontHave', "Don't have it.", 18) + "\":RETURN");
L.push("945 FC=0:FOR J=1 TO NM:IF INSTR(IT$(J),G2$)>0 AND IC(J)=1 THEN FC=J");
L.push("950 NEXT J:IF FC=0 THEN PRINT \"" + msg('notContainer', "Can't open that.", 18) + "\":RETURN");
L.push("952 REM Check if container is accessible");
L.push("953 IF IL(FC)<>CR AND IL(FC)<>0 THEN PRINT \"" + msg('notHere', 'Not here.', 12) + "\":RETURN");
L.push("955 IF IO(FC)=0 THEN PRINT \"" + msg('blocked', 'Blocked.', 12) + "\":RETURN");
L.push("960 FOR K=1 TO NM:IF IT$(K)=INV$(FI) THEN IP(K)=FC:IL(K)=IL(FC)");
L.push("965 NEXT K");
L.push("970 FOR K=FI TO IC-1:INV$(K)=INV$(K+1):NEXT K:IC=IC-1");
L.push("975 PRINT \"" + msg('putIn', 'Done.', 10) + "\":RETURN");
// ========== INVENTORY (980-1049) ==========
L.push("980 PRINT:PRINT \"" + msg('inventory', 'Inventory:', 12) + "\"");
L.push("985 IF IC=0 THEN PRINT \" " + msg('empty', 'empty', 8) + "\":GOTO 990");
L.push("987 FOR J=1 TO IC:PRINT \" \";INV$(J):NEXT J");
L.push("990 GOSUB 1090:RETURN");
// ========== HELP (1050-1089) ==========
var moveCmds = directions.map(function(d) { return getPrimaryCmd(d.action); }).join(",");
L.push("1050 PRINT:PRINT \"COMMANDS:\"");
L.push("1052 PRINT \"" + moveCmds.substring(0, 38) + "\"");
L.push("1054 PRINT \"" + CMD_TAKE + " x, " + CMD_DROP + " x\"");
L.push("1056 PRINT \"" + CMD_EXAMINE + " x, " + CMD_USE + " x\"");
L.push("1058 PRINT \"" + CMD_TALK + " " + KW_TO + " x\"");
L.push("1060 PRINT \"" + CMD_GIVE + " x " + KW_TO + " y\"");
L.push("1062 PRINT \"" + CMD_OPEN + " x, " + CMD_CLOSE + " x\"");
L.push("1064 PRINT \"" + CMD_LOOK + " " + KW_IN + " x\"");
L.push("1066 PRINT \"" + CMD_PUT + " x " + KW_IN + " y\"");
L.push("1068 PRINT \"" + CMD_TAKE + " x " + KW_FROM + " y\"");
L.push("1070 PRINT \"" + invVariants[0] + ", " + lookVariants[0] + ", " + scoreVariants[0] + "\"");
L.push("1072 PRINT \"" + saveVariants[0] + ", " + loadVariants[0] + ", " + quitVariants[0] + "\"");
L.push("1080 GOSUB 1090:RETURN");
// ========== WAIT KEY (1090-1099) ==========
L.push("1090 PRINT:PRINT \"" + msg('pressKey', '[key]', 10) + "\";:CALL &BB18:PRINT:RETURN");
// ========== SAVE (1100-1149) ==========
L.push("1100 ON ERROR GOTO 1140");
L.push("1105 OPENOUT \"SAVEGAME\"");
L.push("1110 PRINT #9,CR;SC;IC");
L.push("1115 FOR J=1 TO NM:PRINT #9,IL(J);IP(J);IO(J):NEXT J");
L.push("1120 FOR J=1 TO NN:PRINT #9,NG(J):NEXT J");
L.push("1125 FOR J=1 TO 6:FOR K=1 TO " + maxR + ":PRINT #9,UL(K,J):NEXT K:NEXT J");
L.push("1130 FOR J=1 TO IC:PRINT #9,INV$(J):NEXT J");
L.push("1135 CLOSEOUT:PRINT \"" + msg('saved', 'Game saved.', 15) + "\":RETURN");
L.push("1140 CLOSEOUT:PRINT \"" + msg('cantSave', "Can't save.", 15) + "\":RETURN");
// ========== LOAD (1150-1199) ==========
L.push("1150 ON ERROR GOTO 1190");
L.push("1155 OPENIN \"SAVEGAME\"");
L.push("1160 INPUT #9,CR,SC,IC");
L.push("1165 FOR J=1 TO NM:INPUT #9,IL(J),IP(J),IO(J):NEXT J");
L.push("1170 FOR J=1 TO NN:INPUT #9,NG(J):NEXT J");
L.push("1175 FOR J=1 TO 6:FOR K=1 TO " + maxR + ":INPUT #9,UL(K,J):NEXT K:NEXT J");
L.push("1180 FOR J=1 TO IC:LINE INPUT #9,INV$(J):NEXT J");
L.push("1185 CLOSEIN:RF=1:PRINT \"" + msg('loaded', 'Game loaded.', 15) + "\":RETURN");
L.push("1190 CLOSEIN:PRINT \"" + msg('cantLoad', "Can't load.", 15) + "\":RETURN");
// ========== CHECK DEATH (1200-1299) ==========
L.push("1200 REM CHECK DEATH");
if (deadly.length > 0) {
L.push("1205 FOR X=1 TO " + deadly.length);
L.push("1210 IF TD(X)<>CR THEN 1250");
L.push("1220 IF TS$(X)=\"\" THEN 1240");
L.push("1230 FOR Y=1 TO IC:IF INV$(Y)=TS$(X) THEN 1250");
L.push("1235 NEXT Y");
L.push("1240 CLS:PRINT:PRINT TM$(X):PRINT:PRINT \"" + msg('gameOver', 'GAME OVER', 12) + "\":END");
L.push("1250 NEXT X");
}
L.push("1260 RETURN");
// ========== CHECK WIN (1300-1399) ==========
L.push("1300 REM CHECK WIN");
if (S.game.winRoom > 0) {
L.push("1305 IF CR<>" + S.game.winRoom + " THEN RETURN");
if (winItems.length > 0) {
L.push("1310 WC=0");
L.push("1315 FOR Y=1 TO IC");
winItems.forEach(function(item, idx) {
L.push((1316 + idx) + " IF INV$(Y)=\"" + item + "\" THEN WC=WC+1");
});
L.push("1330 NEXT Y");
L.push("1335 IF WC<" + winItems.length + " THEN RETURN");
}
if (S.game.winScore > 0) {
L.push("1340 IF SC<" + S.game.winScore + " THEN RETURN");
}
L.push("1350 CLS:PRINT:PRINT \"" + wrapText(safeStr(S.game.winMsg, 200).replace(/"/g, "'"), true) + "\"");
L.push("1360 PRINT:PRINT \"" + msg('youWin', 'YOU WIN!', 15) + "\"");
L.push("1370 PRINT:PRINT \"" + msg('score', 'Score: ', 8) + "\";SC:END");
} else {
L.push("1350 RETURN");
}
// ========== TITLE (1500-1599) ==========
L.push("1500 CLS:PRINT:PRINT");
L.push("1510 PRINT TAB(2);\"" + safeStr(S.game.title, 34) + "\"");
L.push("1520 PRINT:PRINT TAB(2);\"" + msg('by', 'by ', 4) + safeStr(S.game.author, 28) + "\"");
L.push("1530 PRINT:PRINT:PRINT TAB(2);\"" + msg('pressKey', '[key]', 15) + "\"");
L.push("1540 CALL &BB18:CLS:RETURN");
// ========== TAKE FROM (1600-1649) ==========
var takeLen = CMD_TAKE.length;
var fromLen = KW_FROM.length;
L.push("1600 P=INSTR(C$,\" " + KW_FROM + " \"):IF P=0 THEN RETURN");
L.push("1605 G1$=MID$(C$," + (takeLen + 2) + ",P-" + (takeLen + 2) + "):G2$=MID$(C$,P+" + (fromLen + 2) + ")");
L.push("1610 IF G1$=\"\" OR G2$=\"\" THEN PRINT \"" + msg('what', 'What?', 8) + "\":RETURN");
L.push("1615 FC=0:FOR J=1 TO NM:IF INSTR(IT$(J),G2$)>0 AND IC(J)=1 THEN FC=J");
L.push("1620 NEXT J:IF FC=0 THEN PRINT \"" + msg('notContainer', "Can't open that.", 18) + "\":RETURN");
L.push("1625 IF IL(FC)<>CR AND IL(FC)<>0 THEN PRINT \"" + msg('notHere', 'Not here.', 12) + "\":RETURN");
L.push("1630 IF IO(FC)=0 THEN PRINT \"" + msg('blocked', 'Blocked.', 12) + "\":RETURN");
L.push("1635 FI=0:FOR J=1 TO NM:IF INSTR(IT$(J),G1$)>0 AND IP(J)=FC THEN FI=J");
L.push("1640 NEXT J:IF FI=0 THEN PRINT \"" + msg('notHere', 'Not here.', 12) + "\":RETURN");
L.push("1642 IF IC>=ML THEN PRINT \"" + msg('full', 'Full!', 10) + "\":RETURN");
L.push("1645 IC=IC+1:INV$(IC)=IT$(FI):IP(FI)=0:IL(FI)=0");
L.push("1647 PRINT \"" + msg('takeFrom', 'Taken.', 40) + "\":RETURN");
// ========== DATA (3000+) ==========
var ln = 3000;
L.push(ln + " REM *** DATA ***");
ln += 10;
// ROOM NAMES & DESCRIPTIONS
rooms.forEach(function(entry) {
var r = entry[1];
L.push(ln + " R$(" + r.num + ")=\"" + wrapText(safeStr(r.name).replace(/"/g, "'"), false) + "\"");
ln += 10;
L.push(ln + " D$(" + r.num + ")=\"" + wrapText(safeStr(r.desc).replace(/"/g, "'"), false) + "\"");
ln += 10;
});
// ROOM CONNECTIONS
rooms.forEach(function(entry) {
var id = entry[0];
var r = entry[1];
var c = S.conns[id];
var g = function(d) {
return c[d].t ? (S.rooms[c[d].t] ? S.rooms[c[d].t].num : 0) : 0;
};
L.push(ln + " RL(" + r.num + ",1)=" + g('north') + ":RL(" + r.num + ",2)=" + g('east') + ":RL(" + r.num + ",3)=" + g('south') + ":RL(" + r.num + ",4)=" + g('west') + ":RL(" + r.num + ",5)=" + g('up') + ":RL(" + r.num + ",6)=" + g('down'));
ln += 10;
});
// ROOM REQUIREMENTS
rooms.forEach(function(entry) {
var id = entry[0];
var r = entry[1];
var c = S.conns[id];
L.push(ln + " RD$(" + r.num + ",1)=\"" + (c.north.r || 'OPEN') + "\":RD$(" + r.num + ",2)=\"" + (c.east.r || 'OPEN') + "\":RD$(" + r.num + ",3)=\"" + (c.south.r || 'OPEN') + "\":RD$(" + r.num + ",4)=\"" + (c.west.r || 'OPEN') + "\":RD$(" + r.num + ",5)=\"" + (c.up.r || 'OPEN') + "\":RD$(" + r.num + ",6)=\"" + (c.down.r || 'OPEN') + "\"");
ln += 10;
});
// DEATH ROOMS
deadly.forEach(function(entry, idx) {
var r = entry[1];
var deathMsg = wrapText(safeStr(r.deathMsg || 'Dead!').replace(/"/g, "'"), false);
L.push(ln + " TD(" + (idx + 1) + ")=" + r.num + ":TM$(" + (idx + 1) + ")=\"" + deathMsg + "\":TS$(" + (idx + 1) + ")=\"" + safeStr(r.survItem) + "\"");
ln += 10;
});
// ITEMS
items.forEach(function(entry, idx) {
var iid = entry[0];
var i = entry[1];
var loc = S.rooms[i.loc] ? S.rooms[i.loc].num : 0;
var j = idx + 1;
var parentIdx = 0;
if (i.parent) {
var pIdx = items.findIndex(function(e) { return e[0] === i.parent; });
if (pIdx >= 0) parentIdx = pIdx + 1;
}
var itemDesc = wrapText(safeStr(i.desc).replace(/"/g, "'"), false);
L.push(ln + " IT$(" + j + ")=\"" + safeStr(i.name, 25) + "\":ID$(" + j + ")=\"" + itemDesc + "\"");
ln += 10;
L.push(ln + " IL(" + j + ")=" + loc + ":IC(" + j + ")=" + (i.container ? 1 : 0) + ":IS(" + j + ")=" + (i.points || 0) + ":IP(" + j + ")=" + parentIdx);
ln += 10;
});
// NPCs
npcs.forEach(function(entry, idx) {
var n = entry[1];
var loc = S.rooms[n.loc] ? S.rooms[n.loc].num : 0;
var j = idx + 1;
var npcDesc = wrapText(safeStr(n.desc).replace(/"/g, "'"), false);
var npcTalk = wrapText(safeStr(n.talk).replace(/"/g, "'"), false);
L.push(ln + " NP$(" + j + ")=\"" + safeStr(n.name, 25) + "\":ND$(" + j + ")=\"" + npcDesc + "\"");
ln += 10;
L.push(ln + " NT$(" + j + ")=\"" + npcTalk + "\"");
ln += 10;
L.push(ln + " NW$(" + j + ")=\"" + safeStr(n.wants) + "\":NR$(" + j + ")=\"" + safeStr(n.gives) + "\":NS(" + j + ")=" + (n.points || 0) + ":NL(" + j + ")=" + loc);
ln += 10;
});
L.push(ln + " RETURN");
return L.join("\n");
}
// ========== EXPORT ==========
if (typeof window !== 'undefined') {
window.genCode = genCode;
window.wrapText = wrapText;
}
Dann lieber komplett neu ;)
Hier mal 2 Adventures, die ich damit erzeugt habe, viel Spaß damit ;)
Erzeugt jetzt auch Assemblercode:
; ========================================
; THE FORGOTTEN MAYA PRINCESS
; By Devil-System
; Z80 Assembly for Amstrad CPC
; ========================================
; === AMSTRAD CPC FIRMWARE CALLS ===
TXT_OUTPUT EQU &BB5A
KM_WAIT_CHAR EQU &BB06
SCR_SET_MODE EQU &BC0E
TXT_CLEAR EQU &BB6C
TXT_SET_PEN EQU &BB90
TXT_SET_PAPER EQU &BB96
SCR_SET_INK EQU &BC32
SCR_SET_BORDER EQU &BC38
TXT_CUR_ON EQU &BB81
TXT_CUR_OFF EQU &BB84
CAS_IN_OPEN EQU &BC77
CAS_IN_DIRECT EQU &BC83
CAS_IN_CLOSE EQU &BC7A
CAS_OUT_OPEN EQU &BC8C
CAS_OUT_DIRECT EQU &BC98
CAS_OUT_CLOSE EQU &BC8F
; === GAME CONSTANTS ===
NUM_ROOMS EQU 25
NUM_ITEMS EQU 32
NUM_NPCS EQU 8
NUM_DEADLY EQU 5
MAX_INV EQU 20
INV_LIMIT EQU 8
START_ROOM EQU 1
WIN_ROOM EQU 25
WIN_SCORE EQU 0
WIN_ITEMS_COUNT EQU 1
INPUT_MAX EQU 78
ORG &4000
; ========================================
; PROGRAM START
; ========================================
start:
LD (original_sp),SP ; Save stack for clean exit
; Set Mode 1 (40 columns)
LD A,1
CALL SCR_SET_MODE
; Set colors: Ink 0 = black, Ink 1 = yellow
LD A,0
LD B,0
LD C,0
CALL SCR_SET_INK
LD A,1
LD B,24
LD C,24
CALL SCR_SET_INK
LD B,0
LD C,0
CALL SCR_SET_BORDER
; Initialize game state
LD A,START_ROOM
LD (current_room),A
XOR A
LD (score),A
LD (score+1),A
LD (inv_count),A
LD A,1
LD (refresh_flag),A
; Initialize items and NPCs
CALL init_data
; Show title screen
CALL show_title
; === MAIN GAME LOOP ===
main_loop:
LD A,(refresh_flag)
OR A
JR Z,main_no_refresh
CALL show_room
XOR A
LD (refresh_flag),A
main_no_refresh:
CALL get_input
CALL parse_command
JR main_loop
; ========== SHOW TITLE SCREEN ==========
show_title:
CALL TXT_CLEAR
CALL print_nl
CALL print_nl
LD HL,str_title
CALL print_str
CALL print_nl
CALL print_nl
LD HL,str_by
CALL print_str
LD HL,str_author
CALL print_str
CALL print_nl
CALL print_nl
CALL print_nl
CALL wait_key
CALL TXT_CLEAR
RET
; ========================================
; SHOW CURRENT ROOM
; ========================================
show_room:
CALL TXT_CLEAR
CALL print_nl
; Get and print room name
LD A,(current_room)
CALL get_room_name_ptr
CALL print_str
CALL print_nl
; Print separator
LD B,40
show_room_sep:
LD A,'*'
CALL TXT_OUTPUT
DJNZ show_room_sep
CALL print_nl
; Get and print room description
LD A,(current_room)
CALL get_room_desc_ptr
CALL print_str
CALL print_nl
CALL print_nl
; Show items in room
CALL show_items_here
; Show NPCs in room
CALL show_npcs_here
; Show exits
CALL show_exits
; Show score
LD HL,msg_score
CALL print_str
LD HL,(score)
CALL print_num
CALL print_nl
RET
; === SHOW ITEMS IN CURRENT ROOM ===
show_items_here:
LD A,NUM_ITEMS
OR A
RET Z
LD B,A
LD C,1 ; item index
sih_loop:
PUSH BC
; Get item location
LD A,C
DEC A
LD HL,item_locations
CALL add_a_to_hl
LD A,(HL)
LD D,A ; D = item location
; Check if in current room
LD A,(current_room)
CP D
JR NZ,sih_next
; Check if item is in container
POP BC
PUSH BC
LD A,C
DEC A
LD HL,item_parents
CALL add_a_to_hl
LD A,(HL)
OR A
JR NZ,sih_next ; in container, skip
; Print 'You see: '
LD HL,msg_yousee
CALL print_str
; Print item name
POP BC
PUSH BC
LD A,C
CALL get_item_name_ptr
CALL print_str
CALL print_nl
sih_next:
POP BC
INC C
DJNZ sih_loop
RET
; === SHOW NPCS IN CURRENT ROOM ===
show_npcs_here:
LD A,NUM_NPCS
OR A
RET Z
LD B,A
LD C,1
snh_loop:
PUSH BC
LD A,C
DEC A
LD HL,npc_locations
CALL add_a_to_hl
LD A,(HL)
LD D,A
LD A,(current_room)
CP D
JR NZ,snh_next
LD HL,msg_yousee
CALL print_str
POP BC
PUSH BC
LD A,C
CALL get_npc_name_ptr
CALL print_str
CALL print_nl
snh_next:
POP BC
INC C
DJNZ snh_loop
RET
; === SHOW AVAILABLE EXITS ===
show_exits:
LD HL,msg_exits
CALL print_str
LD A,(current_room)
LD (temp_room),A ; save room
LD E,0 ; exits found flag
; Check North (direction 1)
LD A,(temp_room)
LD B,1
CALL get_exit
OR A
JP Z,se_east
LD HL,str_dir_n
CALL print_str
LD E,1
se_east:
LD A,(temp_room)
LD B,2
CALL get_exit
OR A
JP Z,se_south
LD HL,str_dir_e
CALL print_str
LD E,1
se_south:
LD A,(temp_room)
LD B,3
CALL get_exit
OR A
JP Z,se_west
LD HL,str_dir_s
CALL print_str
LD E,1
se_west:
LD A,(temp_room)
LD B,4
CALL get_exit
OR A
JP Z,se_up
LD HL,str_dir_w
CALL print_str
LD E,1
se_up:
LD A,(temp_room)
LD B,5
CALL get_exit
OR A
JP Z,se_down
LD HL,str_dir_u
CALL print_str
LD E,1
se_down:
LD A,(temp_room)
LD B,6
CALL get_exit
OR A
JP Z,se_done
LD HL,str_dir_d
CALL print_str
LD E,1
se_done:
LD A,E
OR A
JP NZ,se_has_exits
LD HL,msg_none
CALL print_str
se_has_exits:
CALL print_nl
RET
; ========================================
; GET PLAYER INPUT
; ========================================
get_input:
CALL print_nl
LD A,'>'
CALL TXT_OUTPUT
LD A,' '
CALL TXT_OUTPUT
CALL TXT_CUR_ON
LD HL,input_buffer
LD B,0 ; char count
gi_loop:
CALL KM_WAIT_CHAR
CP 13 ; Enter
JR Z,gi_done
CP 127 ; Delete
JR Z,gi_backspace
CP 8 ; Backspace
JR Z,gi_backspace
CP 32
JR C,gi_loop ; ignore control chars
; Check buffer space
LD C,A
LD A,B
CP INPUT_MAX
JR NC,gi_loop
LD A,C
; Convert to uppercase
CP 'a'
JR C,gi_store
CP 'z'+1
JR NC,gi_store
SUB 32
gi_store:
LD (HL),A
INC HL
INC B
CALL TXT_OUTPUT
JR gi_loop
gi_backspace:
LD A,B
OR A
JR Z,gi_loop
DEC HL
DEC B
LD A,8
CALL TXT_OUTPUT
LD A,' '
CALL TXT_OUTPUT
LD A,8
CALL TXT_OUTPUT
JR gi_loop
gi_done:
LD (HL),0 ; null terminate
LD A,B
LD (input_len),A
CALL TXT_CUR_OFF
CALL print_nl
RET
; ========================================
; PARSE AND EXECUTE COMMAND
; ========================================
parse_command:
LD A,(input_len)
OR A
RET Z ; empty input
; === MOVEMENT COMMANDS ===
LD HL,input_buffer
LD DE,cmd_north
CALL str_equal
JR NZ,pc_north_no
LD A,1
JP do_move
pc_north_no:
LD HL,input_buffer
LD DE,cmd_north1
CALL str_equal
JR NZ,pc_north1_no
LD A,1
JP do_move
pc_north1_no:
LD HL,input_buffer
LD DE,cmd_north2
CALL str_equal
JR NZ,pc_north2_no
LD A,1
JP do_move
pc_north2_no:
LD HL,input_buffer
LD DE,cmd_south
CALL str_equal
JR NZ,pc_south_no
LD A,3
JP do_move
pc_south_no:
LD HL,input_buffer
LD DE,cmd_south1
CALL str_equal
JR NZ,pc_south1_no
LD A,3
JP do_move
pc_south1_no:
LD HL,input_buffer
LD DE,cmd_south2
CALL str_equal
JR NZ,pc_south2_no
LD A,3
JP do_move
pc_south2_no:
LD HL,input_buffer
LD DE,cmd_east
CALL str_equal
JR NZ,pc_east_no
LD A,2
JP do_move
pc_east_no:
LD HL,input_buffer
LD DE,cmd_east1
CALL str_equal
JR NZ,pc_east1_no
LD A,2
JP do_move
pc_east1_no:
LD HL,input_buffer
LD DE,cmd_east2
CALL str_equal
JR NZ,pc_east2_no
LD A,2
JP do_move
pc_east2_no:
LD HL,input_buffer
LD DE,cmd_west
CALL str_equal
JR NZ,pc_west_no
LD A,4
JP do_move
pc_west_no:
LD HL,input_buffer
LD DE,cmd_west1
CALL str_equal
JR NZ,pc_west1_no
LD A,4
JP do_move
pc_west1_no:
LD HL,input_buffer
LD DE,cmd_west2
CALL str_equal
JR NZ,pc_west2_no
LD A,4
JP do_move
pc_west2_no:
LD HL,input_buffer
LD DE,cmd_up
CALL str_equal
JR NZ,pc_up_no
LD A,5
JP do_move
pc_up_no:
LD HL,input_buffer
LD DE,cmd_up1
CALL str_equal
JR NZ,pc_up1_no
LD A,5
JP do_move
pc_up1_no:
LD HL,input_buffer
LD DE,cmd_up2
CALL str_equal
JR NZ,pc_up2_no
LD A,5
JP do_move
pc_up2_no:
LD HL,input_buffer
LD DE,cmd_up3
CALL str_equal
JR NZ,pc_up3_no
LD A,5
JP do_move
pc_up3_no:
LD HL,input_buffer
LD DE,cmd_down
CALL str_equal
JR NZ,pc_down_no
LD A,6
JP do_move
pc_down_no:
LD HL,input_buffer
LD DE,cmd_down1
CALL str_equal
JR NZ,pc_down1_no
LD A,6
JP do_move
pc_down1_no:
LD HL,input_buffer
LD DE,cmd_down2
CALL str_equal
JR NZ,pc_down2_no
LD A,6
JP do_move
pc_down2_no:
LD HL,input_buffer
LD DE,cmd_down3
CALL str_equal
JR NZ,pc_down3_no
LD A,6
JP do_move
pc_down3_no:
LD HL,input_buffer
LD DE,cmd_down4
CALL str_equal
JR NZ,pc_down4_no
LD A,6
JP do_move
pc_down4_no:
; === LOOK IN COMMAND ===
LD HL,input_buffer
LD DE,cmd_lookin
LD B,4
CALL str_prefix
JP NZ,pc_lookin_no
LD A,5
JP do_look_in
pc_lookin_no:
LD HL,input_buffer
LD DE,cmd_lookin1
LD B,7
CALL str_prefix
JP NZ,pc_lookin1_no
LD A,8
JP do_look_in
pc_lookin1_no:
LD HL,input_buffer
LD DE,cmd_lookin2
LD B,15
CALL str_prefix
JP NZ,pc_lookin2_no
LD A,16
JP do_look_in
pc_lookin2_no:
; === LOOK COMMAND ===
LD HL,input_buffer
LD DE,cmd_look
CALL str_equal
JR NZ,pc_look_no
LD A,1
LD (refresh_flag),A
RET
pc_look_no:
LD HL,input_buffer
LD DE,cmd_look1
CALL str_equal
JR NZ,pc_look1_no
LD A,1
LD (refresh_flag),A
RET
pc_look1_no:
LD HL,input_buffer
LD DE,cmd_look2
CALL str_equal
JR NZ,pc_look2_no
LD A,1
LD (refresh_flag),A
RET
pc_look2_no:
; === INVENTORY COMMAND ===
LD HL,input_buffer
LD DE,cmd_inv
CALL str_equal
JR NZ,pc_inv_no
JP do_inventory
pc_inv_no:
LD HL,input_buffer
LD DE,cmd_inv1
CALL str_equal
JR NZ,pc_inv1_no
JP do_inventory
pc_inv1_no:
LD HL,input_buffer
LD DE,cmd_inv2
CALL str_equal
JR NZ,pc_inv2_no
JP do_inventory
pc_inv2_no:
; === TAKE FROM COMMAND ===
LD HL,input_buffer
LD DE,cmd_take
LD B,4
CALL str_prefix
JP NZ,pc_takefrom_no
; Check if FROM keyword present
LD HL,input_buffer
LD DE,str_kw_from
CALL str_find
JP NC,pc_takefrom_no
JP do_take_from
pc_takefrom_no:
LD HL,input_buffer
LD DE,cmd_take1
LD B,3
CALL str_prefix
JP NZ,pc_takefrom1_no
; Check if FROM keyword present
LD HL,input_buffer
LD DE,str_kw_from
CALL str_find
JP NC,pc_takefrom1_no
JP do_take_from
pc_takefrom1_no:
LD HL,input_buffer
LD DE,cmd_take2
LD B,4
CALL str_prefix
JP NZ,pc_takefrom2_no
; Check if FROM keyword present
LD HL,input_buffer
LD DE,str_kw_from
CALL str_find
JP NC,pc_takefrom2_no
JP do_take_from
pc_takefrom2_no:
LD HL,input_buffer
LD DE,cmd_take3
LD B,7
CALL str_prefix
JP NZ,pc_takefrom3_no
; Check if FROM keyword present
LD HL,input_buffer
LD DE,str_kw_from
CALL str_find
JP NC,pc_takefrom3_no
JP do_take_from
pc_takefrom3_no:
; === TAKE COMMAND ===
LD HL,input_buffer
LD DE,cmd_take
LD B,4
CALL str_prefix
JR NZ,pc_take_no
LD A,5
JP do_take
pc_take_no:
LD HL,input_buffer
LD DE,cmd_take1
LD B,3
CALL str_prefix
JR NZ,pc_take1_no
LD A,4
JP do_take
pc_take1_no:
LD HL,input_buffer
LD DE,cmd_take2
LD B,4
CALL str_prefix
JR NZ,pc_take2_no
LD A,5
JP do_take
pc_take2_no:
LD HL,input_buffer
LD DE,cmd_take3
LD B,7
CALL str_prefix
JR NZ,pc_take3_no
LD A,8
JP do_take
pc_take3_no:
; === DROP COMMAND ===
LD HL,input_buffer
LD DE,cmd_drop
LD B,4
CALL str_prefix
JR NZ,pc_drop_no
LD A,5
JP do_drop
pc_drop_no:
LD HL,input_buffer
LD DE,cmd_drop1
LD B,8
CALL str_prefix
JR NZ,pc_drop1_no
LD A,9
JP do_drop
pc_drop1_no:
LD HL,input_buffer
LD DE,cmd_drop2
LD B,5
CALL str_prefix
JR NZ,pc_drop2_no
LD A,6
JP do_drop
pc_drop2_no:
; === EXAMINE COMMAND ===
LD HL,input_buffer
LD DE,cmd_exam
LD B,7
CALL str_prefix
JR NZ,pc_exam_no
LD A,8
JP do_examine
pc_exam_no:
LD HL,input_buffer
LD DE,cmd_exam1
LD B,1
CALL str_prefix
JR NZ,pc_exam1_no
LD A,2
JP do_examine
pc_exam1_no:
LD HL,input_buffer
LD DE,cmd_exam2
LD B,7
CALL str_prefix
JR NZ,pc_exam2_no
LD A,8
JP do_examine
pc_exam2_no:
LD HL,input_buffer
LD DE,cmd_exam3
LD B,5
CALL str_prefix
JR NZ,pc_exam3_no
LD A,6
JP do_examine
pc_exam3_no:
LD HL,input_buffer
LD DE,cmd_exam4
LD B,7
CALL str_prefix
JR NZ,pc_exam4_no
LD A,8
JP do_examine
pc_exam4_no:
; === USE COMMAND ===
LD HL,input_buffer
LD DE,cmd_use
LD B,3
CALL str_prefix
JR NZ,pc_use_no
LD A,4
JP do_use
pc_use_no:
LD HL,input_buffer
LD DE,cmd_use1
LD B,5
CALL str_prefix
JR NZ,pc_use1_no
LD A,6
JP do_use
pc_use1_no:
; === OPEN COMMAND ===
LD HL,input_buffer
LD DE,cmd_open
LD B,4
CALL str_prefix
JR NZ,pc_open_no
LD A,5
JP do_open
pc_open_no:
; === CLOSE COMMAND ===
LD HL,input_buffer
LD DE,cmd_close
LD B,5
CALL str_prefix
JR NZ,pc_close_no
LD A,6
JP do_close
pc_close_no:
LD HL,input_buffer
LD DE,cmd_close1
LD B,4
CALL str_prefix
JR NZ,pc_close1_no
LD A,5
JP do_close
pc_close1_no:
; === TALK COMMAND ===
LD HL,input_buffer
LD DE,cmd_talk
LD B,7
CALL str_prefix
JR NZ,pc_talk_no
LD A,8
JP do_talk
pc_talk_no:
LD HL,input_buffer
LD DE,cmd_talk1
LD B,8
CALL str_prefix
JR NZ,pc_talk1_no
LD A,9
JP do_talk
pc_talk1_no:
LD HL,input_buffer
LD DE,cmd_talk2
LD B,6
CALL str_prefix
JR NZ,pc_talk2_no
LD A,7
JP do_talk
pc_talk2_no:
LD HL,input_buffer
LD DE,cmd_talk3
LD B,6
CALL str_prefix
JR NZ,pc_talk3_no
LD A,7
JP do_talk
pc_talk3_no:
; === GIVE COMMAND ===
LD HL,input_buffer
LD DE,cmd_give
LD B,4
CALL str_prefix
JR NZ,pc_give_no
JP do_give
pc_give_no:
LD HL,input_buffer
LD DE,cmd_give1
LD B,5
CALL str_prefix
JR NZ,pc_give1_no
JP do_give
pc_give1_no:
LD HL,input_buffer
LD DE,cmd_give2
LD B,4
CALL str_prefix
JR NZ,pc_give2_no
JP do_give
pc_give2_no:
; === HELP COMMAND ===
LD HL,input_buffer
LD DE,cmd_help
CALL str_equal
JR NZ,pc_help_no
JP do_help
pc_help_no:
LD HL,input_buffer
LD DE,cmd_help1
CALL str_equal
JR NZ,pc_help1_no
JP do_help
pc_help1_no:
LD HL,input_buffer
LD DE,cmd_help2
CALL str_equal
JR NZ,pc_help2_no
JP do_help
pc_help2_no:
LD HL,input_buffer
LD DE,cmd_help3
CALL str_equal
JR NZ,pc_help3_no
JP do_help
pc_help3_no:
; === SCORE COMMAND ===
LD HL,input_buffer
LD DE,cmd_score
CALL str_equal
JR NZ,pc_score_no
JP do_show_score
pc_score_no:
LD HL,input_buffer
LD DE,cmd_score1
CALL str_equal
JR NZ,pc_score1_no
JP do_show_score
pc_score1_no:
; === SAVE COMMAND ===
LD HL,input_buffer
LD DE,cmd_save
CALL str_equal
JP NZ,pc_save_no
JP do_save
pc_save_no:
LD HL,input_buffer
LD DE,cmd_save1
CALL str_equal
JP NZ,pc_save1_no
JP do_save
pc_save1_no:
; === LOAD COMMAND ===
LD HL,input_buffer
LD DE,cmd_load
CALL str_equal
JP NZ,pc_load_no
JP do_load
pc_load_no:
LD HL,input_buffer
LD DE,cmd_load1
CALL str_equal
JP NZ,pc_load1_no
JP do_load
pc_load1_no:
LD HL,input_buffer
LD DE,cmd_load2
CALL str_equal
JP NZ,pc_load2_no
JP do_load
pc_load2_no:
; === QUIT COMMAND ===
LD HL,input_buffer
LD DE,cmd_quit
CALL str_equal
JR NZ,pc_quit_no
JP do_quit
pc_quit_no:
LD HL,input_buffer
LD DE,cmd_quit1
CALL str_equal
JR NZ,pc_quit1_no
JP do_quit
pc_quit1_no:
LD HL,input_buffer
LD DE,cmd_quit2
CALL str_equal
JR NZ,pc_quit2_no
JP do_quit
pc_quit2_no:
LD HL,input_buffer
LD DE,cmd_quit3
CALL str_equal
JR NZ,pc_quit3_no
JP do_quit
pc_quit3_no:
; Unknown command
LD HL,msg_unknown
CALL print_str
CALL print_nl
RET
; ========================================
; ACTION: MOVE
; A = direction (1-6) on entry
; ========================================
do_move:
LD (temp_dir),A ; save direction
LD B,A ; B = direction for get_exit
LD A,(current_room) ; A = room
CALL get_exit ; A = target room (0=none)
OR A
JP NZ,dm_can_go
LD HL,msg_cantgo
CALL print_str
CALL print_nl
RET
dm_can_go:
LD (temp_target),A ; save target room
; Check if exit has requirement
LD A,(current_room)
LD HL,temp_dir
LD B,(HL) ; B = direction
CALL get_exit_requirement
; HL = requirement string pointer
LD A,(HL)
OR A ; empty = no requirement
JP Z,dm_unlocked ; no requirement, can pass
; Has requirement - check if unlocked
LD A,(current_room)
LD HL,temp_dir
LD B,(HL)
CALL check_exit_unlocked
OR A
JP NZ,dm_unlocked
; Blocked!
LD HL,msg_blocked
CALL print_str
CALL print_nl
RET
dm_unlocked:
LD A,(temp_target)
LD (current_room),A
LD A,1
LD (refresh_flag),A
CALL check_death
CALL check_win
RET
; ========================================
; ACTION: TAKE
; A = offset in input buffer to object name
; ========================================
do_take:
LD HL,input_buffer
CALL add_a_to_hl
LD (temp_ptr),HL
LD A,(HL)
OR A
JP NZ,dt_have_name
LD HL,msg_what
CALL print_str
CALL print_nl
RET
dt_have_name:
LD A,NUM_ITEMS
OR A
JP NZ,dt_search
LD HL,msg_nothere
CALL print_str
CALL print_nl
RET
dt_search:
LD B,A
LD C,1
dt_loop:
PUSH BC
; Check item location
LD A,C
DEC A
LD HL,item_locations
CALL add_a_to_hl
LD A,(HL)
LD D,A
LD A,(current_room)
CP D
JP NZ,dt_next
; Check not in container
POP BC
PUSH BC
LD A,C
DEC A
LD HL,item_parents
CALL add_a_to_hl
LD A,(HL)
OR A
JP NZ,dt_next
; Check not a fixed container
POP BC
PUSH BC
LD A,C
DEC A
LD HL,item_is_container
CALL add_a_to_hl
LD A,(HL)
CP 2
JP Z,dt_next
; Check name matches
POP BC
PUSH BC
LD A,C
CALL get_item_name_ptr
EX DE,HL
LD HL,(temp_ptr)
CALL str_contains
JP NZ,dt_next
; Found it! Check inventory space
LD A,(inv_count)
CP INV_LIMIT
JR C,dt_can_take
POP BC
LD HL,msg_full
CALL print_str
CALL print_nl
RET
dt_can_take:
POP BC
LD A,C
CALL add_to_inventory
; Set item location to 0
LD A,C
DEC A
LD HL,item_locations
CALL add_a_to_hl
LD (HL),0
; Add points
PUSH BC
LD A,C
DEC A
LD HL,item_points
CALL add_a_to_hl
LD A,(HL)
OR A
JR Z,dt_no_points
LD HL,(score)
LD B,0
LD C,A
ADD HL,BC
LD (score),HL
POP BC
PUSH BC
LD A,C
DEC A
LD HL,item_points
CALL add_a_to_hl
LD (HL),0
dt_no_points:
POP BC
LD HL,msg_taken
CALL print_str
CALL print_nl
RET
dt_next:
POP BC
INC C
DEC B
JP NZ,dt_loop
LD HL,msg_nothere
CALL print_str
CALL print_nl
RET
; ========================================
; ACTION: DROP
; ========================================
do_drop:
LD HL,input_buffer
CALL add_a_to_hl
LD (temp_ptr),HL
LD A,(HL)
OR A
JP NZ,dd_have_name
LD HL,msg_what
CALL print_str
CALL print_nl
RET
dd_have_name:
LD A,(inv_count)
OR A
JP NZ,dd_search
LD HL,msg_donthave
CALL print_str
CALL print_nl
RET
dd_search:
LD B,A
LD C,1
dd_loop:
PUSH BC
LD A,C
DEC A
LD HL,inventory
CALL add_a_to_hl
LD A,(HL)
OR A
JP Z,dd_next
PUSH AF
CALL get_item_name_ptr
EX DE,HL
LD HL,(temp_ptr)
CALL str_contains
POP AF
JP NZ,dd_next
; Found - set location to current room
LD D,A
LD A,D
DEC A
LD HL,item_locations
CALL add_a_to_hl
LD A,(current_room)
LD (HL),A
POP BC
LD A,C
CALL remove_from_inventory
LD HL,msg_dropped
CALL print_str
CALL print_nl
RET
dd_next:
POP BC
INC C
DEC B
JP NZ,dd_loop
LD HL,msg_donthave
CALL print_str
CALL print_nl
RET
; ========================================
; ACTION: EXAMINE
; ========================================
do_examine:
LD HL,input_buffer
CALL add_a_to_hl
LD (temp_ptr),HL
LD A,(HL)
OR A
JP NZ,dx_have_name
LD HL,msg_what
CALL print_str
CALL print_nl
RET
dx_have_name:
LD A,NUM_ITEMS
OR A
JP Z,dx_check_npcs
LD B,A
LD C,1
dx_item_loop:
PUSH BC
LD A,C
DEC A
LD HL,item_locations
CALL add_a_to_hl
LD A,(HL)
LD D,A
LD A,(current_room)
CP D
JP Z,dx_item_accessible
LD A,D
OR A
JP NZ,dx_item_next
dx_item_accessible:
POP BC
PUSH BC
LD A,C
CALL get_item_name_ptr
EX DE,HL
LD HL,(temp_ptr)
CALL str_contains
JP NZ,dx_item_next
POP BC
LD A,C
CALL get_item_desc_ptr
LD A,(HL)
OR A
JR NZ,dx_has_desc
LD HL,msg_nothing_special
dx_has_desc:
CALL print_nl
CALL print_str
CALL print_nl
CALL wait_key
RET
dx_item_next:
POP BC
INC C
DEC B
JP NZ,dx_item_loop
dx_check_npcs:
LD A,NUM_NPCS
OR A
JP Z,dx_not_found
LD B,A
LD C,1
dx_npc_loop:
PUSH BC
LD A,C
DEC A
LD HL,npc_locations
CALL add_a_to_hl
LD A,(HL)
LD D,A
LD A,(current_room)
CP D
JP NZ,dx_npc_next
POP BC
PUSH BC
LD A,C
CALL get_npc_name_ptr
EX DE,HL
LD HL,(temp_ptr)
CALL str_contains
JP NZ,dx_npc_next
POP BC
LD A,C
CALL get_npc_desc_ptr
CALL print_nl
CALL print_str
CALL print_nl
CALL wait_key
RET
dx_npc_next:
POP BC
INC C
DEC B
JP NZ,dx_npc_loop
dx_not_found:
LD HL,msg_nothere
CALL print_str
CALL print_nl
RET
; ========================================
; ACTION: USE (unlock exits)
; ========================================
do_use:
LD HL,input_buffer
CALL add_a_to_hl
LD (temp_ptr),HL
LD A,(HL)
OR A
JP NZ,du_have_name
LD HL,msg_usewhat
CALL print_str
CALL print_nl
RET
du_have_name:
LD A,(inv_count)
OR A
JP NZ,du_search
LD HL,msg_donthave
CALL print_str
CALL print_nl
RET
du_search:
LD B,A
LD C,1
du_inv_loop:
PUSH BC
LD A,C
DEC A
LD HL,inventory
CALL add_a_to_hl
LD A,(HL)
OR A
JP Z,du_inv_next
PUSH AF
CALL get_item_name_ptr
EX DE,HL
LD HL,(temp_ptr)
CALL str_contains
POP AF
JP NZ,du_inv_next
; Found item in inventory - try to unlock exits
LD (found_item),A
POP BC
JP du_try_unlock
du_inv_next:
POP BC
INC C
DEC B
JP NZ,du_inv_loop
LD HL,msg_donthave
CALL print_str
CALL print_nl
RET
du_try_unlock:
; Check all 6 directions
LD B,6
LD C,1
du_dir_loop:
PUSH BC
; Get required item for this exit
LD A,(current_room)
LD B,C
CALL get_exit_requirement
LD A,(HL)
OR A
JP Z,du_dir_next
; Compare with our item name
PUSH HL
LD A,(found_item)
CALL get_item_name_ptr
POP DE
CALL str_equal
JP NZ,du_dir_next
; Check if already unlocked
POP BC
PUSH BC
LD A,(current_room)
LD B,C
CALL check_exit_unlocked
OR A
JP NZ,du_dir_next
; Unlock it!
POP BC
LD A,(current_room)
LD B,C
CALL set_exit_unlocked
LD HL,msg_unlocked
CALL print_str
CALL print_nl
RET
du_dir_next:
POP BC
INC C
DEC B
JP NZ,du_dir_loop
LD HL,msg_nothing
CALL print_str
CALL print_nl
RET
; ========================================
; ACTION: OPEN CONTAINER
; ========================================
do_open:
LD HL,input_buffer
CALL add_a_to_hl
LD (temp_ptr),HL
LD A,(HL)
OR A
JP NZ,dop_have_name
LD HL,msg_what
CALL print_str
CALL print_nl
RET
dop_have_name:
LD A,NUM_ITEMS
OR A
JP Z,dop_not_container
LD B,A
LD C,1
dop_loop:
PUSH BC
; Is it a container?
LD A,C
DEC A
LD HL,item_is_container
CALL add_a_to_hl
LD A,(HL)
OR A
JP Z,dop_next
; Is it here or carried?
POP BC
PUSH BC
LD A,C
DEC A
LD HL,item_locations
CALL add_a_to_hl
LD A,(HL)
LD D,A
LD A,(current_room)
CP D
JP Z,dop_accessible
LD A,D
OR A
JP NZ,dop_next
dop_accessible:
POP BC
PUSH BC
LD A,C
CALL get_item_name_ptr
EX DE,HL
LD HL,(temp_ptr)
CALL str_contains
JP NZ,dop_next
; Open it
POP BC
LD A,C
DEC A
LD HL,item_is_open
CALL add_a_to_hl
LD (HL),1
LD HL,msg_opened
CALL print_str
CALL print_nl
RET
dop_next:
POP BC
INC C
DEC B
JP NZ,dop_loop
dop_not_container:
LD HL,msg_notcontainer
CALL print_str
CALL print_nl
RET
; ========================================
; ACTION: CLOSE CONTAINER
; ========================================
do_close:
LD HL,input_buffer
CALL add_a_to_hl
LD (temp_ptr),HL
LD A,(HL)
OR A
JP NZ,dc_have_name
LD HL,msg_what
CALL print_str
CALL print_nl
RET
dc_have_name:
LD A,NUM_ITEMS
OR A
JP Z,dc_not_container
LD B,A
LD C,1
dc_loop:
PUSH BC
LD A,C
DEC A
LD HL,item_is_container
CALL add_a_to_hl
LD A,(HL)
OR A
JP Z,dc_next
POP BC
PUSH BC
LD A,C
DEC A
LD HL,item_is_open
CALL add_a_to_hl
LD A,(HL)
OR A
JP Z,dc_next
POP BC
PUSH BC
LD A,C
CALL get_item_name_ptr
EX DE,HL
LD HL,(temp_ptr)
CALL str_contains
JP NZ,dc_next
POP BC
LD A,C
DEC A
LD HL,item_is_open
CALL add_a_to_hl
LD (HL),0
LD HL,msg_closed
CALL print_str
CALL print_nl
RET
dc_next:
POP BC
INC C
DEC B
JP NZ,dc_loop
dc_not_container:
LD HL,msg_notcontainer
CALL print_str
CALL print_nl
RET
; ========================================
; ACTION: LOOK IN CONTAINER
; A = offset to container name
; ========================================
do_look_in:
LD HL,input_buffer
CALL add_a_to_hl
LD (temp_ptr),HL
LD A,(HL)
OR A
JP NZ,dli_have_name
LD HL,msg_what
CALL print_str
CALL print_nl
RET
dli_have_name:
LD A,NUM_ITEMS
OR A
JP Z,dli_not_found
LD B,A
LD C,1
dli_loop:
PUSH BC
; Is it a container?
LD A,C
DEC A
LD HL,item_is_container
CALL add_a_to_hl
LD A,(HL)
OR A
JP Z,dli_next
; Is it here or carried?
POP BC
PUSH BC
LD A,C
DEC A
LD HL,item_locations
CALL add_a_to_hl
LD A,(HL)
LD D,A
LD A,(current_room)
CP D
JP Z,dli_accessible
LD A,D
OR A
JP NZ,dli_next
dli_accessible:
; Check name matches
POP BC
PUSH BC
LD A,C
CALL get_item_name_ptr
EX DE,HL
LD HL,(temp_ptr)
CALL str_contains
JP NZ,dli_next
; Found container - check if open
POP BC
PUSH BC
LD A,C
DEC A
LD HL,item_is_open
CALL add_a_to_hl
LD A,(HL)
OR A
JP NZ,dli_show_contents
; Closed
POP BC
LD HL,msg_closed
CALL print_str
CALL print_nl
RET
dli_show_contents:
POP BC
LD A,C
LD (temp_container),A
CALL print_nl
LD HL,msg_inside
CALL print_str
CALL print_nl
; Search for items with parent = container
LD A,NUM_ITEMS
OR A
JP Z,dli_empty
LD B,A
LD C,1
LD E,0
dli_content_loop:
PUSH BC
PUSH DE
LD A,C
DEC A
LD HL,item_parents
CALL add_a_to_hl
LD A,(HL)
LD D,A
LD A,(temp_container)
CP D
JP NZ,dli_content_next
; Found item in container
LD HL,msg_indent
CALL print_str
POP DE
POP BC
PUSH BC
PUSH DE
LD A,C
CALL get_item_name_ptr
CALL print_str
CALL print_nl
POP DE
LD E,1
PUSH DE
dli_content_next:
POP DE
POP BC
INC C
DEC B
JP NZ,dli_content_loop
LD A,E
OR A
JP NZ,dli_done
dli_empty:
LD HL,msg_empty_c
CALL print_str
CALL print_nl
dli_done:
CALL wait_key
RET
dli_next:
POP BC
INC C
DEC B
JP NZ,dli_loop
dli_not_found:
LD HL,msg_notcontainer
CALL print_str
CALL print_nl
RET
; ========================================
; ACTION: TAKE ITEM FROM CONTAINER
; ========================================
do_take_from:
; Parse 'TAKE item FROM container'
LD HL,input_buffer
LD DE,str_kw_from
CALL str_find
JP NC,dtf_syntax_err
LD (temp_ptr2),HL ; position of ' FROM '
; Get item name (after TAKE, before FROM)
LD HL,input_buffer
LD B,5 ; skip 'TAKE '
dtf_skip:
INC HL
DJNZ dtf_skip
LD (temp_ptr),HL ; item name start
; Get container name (after ' FROM ')
LD HL,(temp_ptr2)
LD B,6 ; skip ' FROM '
dtf_skip2:
INC HL
DJNZ dtf_skip2
LD A,(HL)
OR A
JP Z,dtf_syntax_err
LD (temp_ptr3),HL ; container name start
; Find container in room or inventory
LD A,NUM_ITEMS
OR A
JP Z,dtf_no_container
LD B,A
LD C,1
dtf_cont_loop:
PUSH BC
; Is it a container?
LD A,C
DEC A
LD HL,item_is_container
CALL add_a_to_hl
LD A,(HL)
OR A
JP Z,dtf_cont_next
; Is it here or carried?
POP BC
PUSH BC
LD A,C
DEC A
LD HL,item_locations
CALL add_a_to_hl
LD A,(HL)
LD D,A
LD A,(current_room)
CP D
JP Z,dtf_cont_accessible
LD A,D
OR A ; 0 = carried
JP NZ,dtf_cont_next
dtf_cont_accessible:
; Check container name matches
POP BC
PUSH BC
LD A,C
CALL get_item_name_ptr
EX DE,HL
LD HL,(temp_ptr3)
CALL str_contains
JP NZ,dtf_cont_next
; Found container!
POP BC
LD A,C
LD (temp_container),A
JP dtf_check_open
dtf_cont_next:
POP BC
INC C
DEC B
JP NZ,dtf_cont_loop
dtf_no_container:
LD HL,msg_notcontainer
CALL print_str
CALL print_nl
RET
dtf_check_open:
; Check if container is open
LD A,(temp_container)
DEC A
LD HL,item_is_open
CALL add_a_to_hl
LD A,(HL)
OR A
JP NZ,dtf_find_item
LD HL,msg_closed
CALL print_str
CALL print_nl
RET
dtf_find_item:
; Find item in container
LD A,NUM_ITEMS
LD B,A
LD C,1
dtf_item_loop:
PUSH BC
; Check if item is in this container
LD A,C
DEC A
LD HL,item_parents
CALL add_a_to_hl
LD A,(HL)
LD D,A
LD A,(temp_container)
CP D
JP NZ,dtf_item_next
; Check item name matches
POP BC
PUSH BC
LD A,C
CALL get_item_name_ptr
EX DE,HL
LD HL,(temp_ptr)
CALL str_partial_match
JP NZ,dtf_item_next
; Found item! Check inventory space
LD A,(inv_count)
CP INV_LIMIT
JP C,dtf_can_take
POP BC
LD HL,msg_full
CALL print_str
CALL print_nl
RET
dtf_can_take:
POP BC
; Add to inventory
LD A,C
CALL add_to_inventory
; Remove from container (set parent to 0)
LD A,C
DEC A
LD HL,item_parents
CALL add_a_to_hl
LD (HL),0
; Set location to 0 (carried)
LD A,C
DEC A
LD HL,item_locations
CALL add_a_to_hl
LD (HL),0
; Add points
PUSH BC
LD A,C
DEC A
LD HL,item_points
CALL add_a_to_hl
LD A,(HL)
OR A
JP Z,dtf_no_points
LD HL,(score)
LD B,0
LD C,A
ADD HL,BC
LD (score),HL
; Clear points
POP BC
PUSH BC
LD A,C
DEC A
LD HL,item_points
CALL add_a_to_hl
LD (HL),0
dtf_no_points:
POP BC
LD HL,msg_taken
CALL print_str
CALL print_nl
RET
dtf_item_next:
POP BC
INC C
DEC B
JP NZ,dtf_item_loop
LD HL,msg_nothere
CALL print_str
CALL print_nl
RET
dtf_syntax_err:
LD HL,msg_takefrom_syntax
CALL print_str
CALL print_nl
RET
; ========================================
; ACTION: TALK TO NPC
; ========================================
do_talk:
LD HL,input_buffer
CALL add_a_to_hl
LD (temp_ptr),HL
LD A,(HL)
OR A
JP NZ,dtk_have_name
LD HL,msg_talkto
CALL print_str
CALL print_nl
RET
dtk_have_name:
LD A,NUM_NPCS
OR A
JP Z,dtk_noone
LD B,A
LD C,1
dtk_loop:
PUSH BC
LD A,C
DEC A
LD HL,npc_locations
CALL add_a_to_hl
LD A,(HL)
LD D,A
LD A,(current_room)
CP D
JP NZ,dtk_next
POP BC
PUSH BC
LD A,C
CALL get_npc_name_ptr
EX DE,HL
LD HL,(temp_ptr)
CALL str_contains
JP NZ,dtk_next
POP BC
LD A,C
CALL get_npc_talk_ptr
LD A,(HL)
OR A
JR NZ,dtk_has_dialog
LD HL,msg_silence
CALL print_str
CALL print_nl
RET
dtk_has_dialog:
CALL print_nl
LD A,34 ; quote char
CALL TXT_OUTPUT
CALL print_str
LD A,34
CALL TXT_OUTPUT
CALL print_nl
CALL wait_key
RET
dtk_next:
POP BC
INC C
DEC B
JP NZ,dtk_loop
dtk_noone:
LD HL,msg_noone
CALL print_str
CALL print_nl
RET
; ========================================
; ACTION: GIVE ITEM TO NPC
; ========================================
do_give:
; Parse 'GIVE item TO npc'
LD HL,input_buffer
LD DE,str_kw_to
CALL str_find
JP NC,dg_syntax_err
LD (temp_ptr2),HL
; Get item name start (after GIVE )
LD HL,input_buffer
LD B,5 ; skip 'GIVE '
dg_skip:
INC HL
DJNZ dg_skip
LD (temp_ptr),HL
; Get NPC name (after ' TO ')
LD HL,(temp_ptr2)
LD B,4 ; skip ' TO '
dg_skip2:
INC HL
DJNZ dg_skip2
LD A,(HL)
OR A
JP Z,dg_syntax_err
LD (temp_ptr3),HL
; Find item in inventory
LD A,(inv_count)
OR A
JP Z,dg_no_item
LD B,A
LD C,1
dg_item_loop:
PUSH BC
LD A,C
DEC A
LD HL,inventory
CALL add_a_to_hl
LD A,(HL)
OR A
JP Z,dg_item_next
PUSH AF
CALL get_item_name_ptr
EX DE,HL
LD HL,(temp_ptr)
CALL str_partial_match
POP AF
JP NZ,dg_item_next
LD (found_item),A
POP BC
LD A,C
LD (found_inv_slot),A
JP dg_find_npc
dg_item_next:
POP BC
INC C
DEC B
JP NZ,dg_item_loop
dg_no_item:
LD HL,msg_donthave
CALL print_str
CALL print_nl
RET
dg_find_npc:
LD A,NUM_NPCS
OR A
JP Z,dg_no_npc
LD B,A
LD C,1
dg_npc_loop:
PUSH BC
LD A,C
DEC A
LD HL,npc_locations
CALL add_a_to_hl
LD A,(HL)
LD D,A
LD A,(current_room)
CP D
JP NZ,dg_npc_next
POP BC
PUSH BC
LD A,C
CALL get_npc_name_ptr
EX DE,HL
LD HL,(temp_ptr3)
CALL str_contains
JP NZ,dg_npc_next
POP BC
LD A,C
LD (found_npc),A
JP dg_do_give
dg_npc_next:
POP BC
INC C
DEC B
JP NZ,dg_npc_loop
dg_no_npc:
LD HL,msg_noone
CALL print_str
CALL print_nl
RET
dg_do_give:
; Check if NPC already got gift
LD A,(found_npc)
DEC A
LD HL,npc_got_gift
CALL add_a_to_hl
LD A,(HL)
OR A
JP NZ,dg_nothing
; Check if NPC wants this item
LD A,(found_npc)
CALL get_npc_wants_ptr
LD A,(HL)
OR A
JP Z,dg_no_want
EX DE,HL
LD A,(found_item)
CALL get_item_name_ptr
CALL str_equal
JP NZ,dg_no_want
; NPC accepts!
LD A,(found_inv_slot)
CALL remove_from_inventory
; Mark NPC
LD A,(found_npc)
DEC A
LD HL,npc_got_gift
CALL add_a_to_hl
LD (HL),1
; Add points
LD A,(found_npc)
DEC A
LD HL,npc_points
CALL add_a_to_hl
LD A,(HL)
OR A
JR Z,dg_no_points
LD HL,(score)
LD B,0
LD C,A
ADD HL,BC
LD (score),HL
dg_no_points:
LD HL,msg_thanks
CALL print_str
CALL print_nl
; Check reward
LD A,(found_npc)
CALL get_npc_gives_ptr
LD A,(HL)
OR A
RET Z
LD HL,msg_got
CALL print_str
LD A,(found_npc)
CALL get_npc_gives_ptr
CALL print_str
CALL print_nl
RET
dg_nothing:
LD HL,msg_nothing
CALL print_str
CALL print_nl
RET
dg_no_want:
LD HL,msg_nowant
CALL print_str
CALL print_nl
RET
dg_syntax_err:
LD HL,msg_give_syntax
CALL print_str
CALL print_nl
RET
; ========================================
; ACTION: SHOW INVENTORY
; ========================================
do_inventory:
CALL print_nl
LD HL,msg_inventory
CALL print_str
CALL print_nl
LD A,(inv_count)
OR A
JR NZ,di_show_items
LD HL,msg_empty
CALL print_str
CALL print_nl
CALL wait_key
RET
di_show_items:
LD B,A
LD C,1
di_loop:
PUSH BC
LD A,C
DEC A
LD HL,inventory
CALL add_a_to_hl
LD A,(HL)
OR A
JR Z,di_next
LD HL,msg_indent
CALL print_str
POP BC
PUSH BC
LD A,C
DEC A
LD HL,inventory
CALL add_a_to_hl
LD A,(HL)
CALL get_item_name_ptr
CALL print_str
CALL print_nl
di_next:
POP BC
INC C
DJNZ di_loop
CALL wait_key
RET
; ========================================
; ACTION: SHOW HELP
; ========================================
do_help:
CALL print_nl
LD HL,str_help_text
CALL print_str
CALL wait_key
RET
; ========================================
; ACTION: SHOW SCORE
; ========================================
do_show_score:
CALL print_nl
LD HL,msg_score
CALL print_str
LD HL,(score)
CALL print_num
CALL print_nl
CALL wait_key
RET
; ========================================
; ACTION: QUIT GAME
; ========================================
do_quit:
CALL print_nl
LD HL,msg_bye
CALL print_str
CALL print_nl
CALL wait_key
; Clean return to BASIC
LD SP,(original_sp) ; Restore original stack
RET ; Return to BASIC
; ========================================
; ACTION: SAVE GAME
; ========================================
do_save:
CALL print_nl
LD HL,msg_filename
CALL print_str
; Get filename from user
CALL get_filename
LD A,(filename_len)
OR A
JP Z,do_save_cancel
; Open file for writing
LD B,A ; B = filename length
LD HL,filename_buf
LD DE,cas_buffer ; 2KB buffer for cassette
CALL CAS_OUT_OPEN
JP NC,do_save_error
; Save game data
LD HL,save_data_start
LD DE,save_data_end-save_data_start
LD BC,0 ; execution address (not used)
LD A,2 ; file type = binary
CALL CAS_OUT_DIRECT
JP NC,do_save_error_close
; Close file
CALL CAS_OUT_CLOSE
LD HL,msg_saved
CALL print_str
CALL print_nl
RET
do_save_error_close:
CALL CAS_OUT_CLOSE
do_save_error:
LD HL,msg_save_error
CALL print_str
CALL print_nl
RET
do_save_cancel:
LD HL,msg_cancelled
CALL print_str
CALL print_nl
RET
; ========================================
; ACTION: LOAD GAME
; ========================================
do_load:
CALL print_nl
LD HL,msg_filename
CALL print_str
; Get filename from user
CALL get_filename
LD A,(filename_len)
OR A
JP Z,do_load_cancel
; Open file for reading
LD B,A ; B = filename length
LD HL,filename_buf
LD DE,cas_buffer ; 2KB buffer for cassette
CALL CAS_IN_OPEN
JP NC,do_load_error
; Load game data
LD HL,save_data_start
CALL CAS_IN_DIRECT
JP NC,do_load_error_close
; Close file
CALL CAS_IN_CLOSE
; Set refresh flag
LD A,1
LD (refresh_flag),A
LD HL,msg_loaded
CALL print_str
CALL print_nl
RET
do_load_error_close:
CALL CAS_IN_CLOSE
do_load_error:
LD HL,msg_load_error
CALL print_str
CALL print_nl
RET
do_load_cancel:
LD HL,msg_cancelled
CALL print_str
CALL print_nl
RET
; ========================================
; GET FILENAME (max 8 chars)
; ========================================
get_filename:
CALL TXT_CUR_ON
LD HL,filename_buf
LD B,0 ; char count
gfn_loop:
CALL KM_WAIT_CHAR
CP 13 ; Enter
JR Z,gfn_done
CP 27 ; Escape
JR Z,gfn_escape
CP 127 ; Delete
JR Z,gfn_backspace
CP 8 ; Backspace
JR Z,gfn_backspace
CP 32 ; Must be >= space
JR C,gfn_loop
CP '.' ; No dots allowed
JR Z,gfn_loop
; Check max length (8 chars)
LD C,A
LD A,B
CP 8
JR NC,gfn_loop ; Already 8 chars
LD A,C
; Convert to uppercase
CP 'a'
JR C,gfn_store
CP 'z'+1
JR NC,gfn_store
SUB 32
gfn_store:
LD (HL),A
INC HL
INC B
CALL TXT_OUTPUT
JR gfn_loop
gfn_backspace:
LD A,B
OR A
JR Z,gfn_loop
DEC HL
DEC B
LD A,8
CALL TXT_OUTPUT
LD A,' '
CALL TXT_OUTPUT
LD A,8
CALL TXT_OUTPUT
JR gfn_loop
gfn_escape:
LD B,0 ; Return empty = cancelled
gfn_done:
LD A,B
LD (filename_len),A
CALL TXT_CUR_OFF
CALL print_nl
RET
; ========================================
; CHECK IF ROOM IS DEADLY
; ========================================
check_death:
LD A,NUM_DEADLY
OR A
RET Z
LD B,A
LD C,0
cd_loop:
PUSH BC
LD A,C
LD HL,deadly_rooms
CALL add_a_to_hl
LD A,(HL)
LD D,A
LD A,(current_room)
CP D
JP NZ,cd_next
; In deadly room - check survival item
POP BC
PUSH BC
LD A,C
CALL get_survival_item_ptr
LD A,(HL)
OR A
JP Z,cd_die
CALL check_have_item
JP C,cd_next
cd_die:
CALL TXT_CLEAR
CALL print_nl
POP BC
LD A,C
CALL get_death_msg_ptr
CALL print_str
CALL print_nl
CALL print_nl
LD HL,msg_gameover
CALL print_str
CALL print_nl
CALL wait_key
LD SP,(original_sp)
RET
cd_next:
POP BC
INC C
DEC B
JP NZ,cd_loop
RET
; ========================================
; CHECK WIN CONDITION
; ========================================
check_win:
LD A,WIN_ROOM
OR A
RET Z
LD B,A
LD A,(current_room)
CP B
RET NZ
; Check score
LD A,WIN_SCORE
OR A
JR Z,cw_check_items
LD HL,(score)
LD B,0
LD C,A
OR A
SBC HL,BC
RET C
cw_check_items:
LD A,WIN_ITEMS_COUNT
OR A
JR Z,cw_win
cw_win:
CALL TXT_CLEAR
CALL print_nl
LD HL,str_winmsg
CALL print_str
CALL print_nl
CALL print_nl
LD HL,msg_youwin
CALL print_str
CALL print_nl
LD HL,msg_score
CALL print_str
LD HL,(score)
CALL print_num
CALL print_nl
CALL wait_key
LD SP,(original_sp)
RET
; ========================================
; UTILITY FUNCTIONS
; ========================================
; Print null-terminated string at HL
print_str:
LD A,(HL)
OR A
RET Z
CALL TXT_OUTPUT
INC HL
JR print_str
; Print CR/LF
print_nl:
LD A,13
CALL TXT_OUTPUT
LD A,10
CALL TXT_OUTPUT
RET
; Print 16-bit number in HL
print_num:
LD DE,10000
CALL pn_digit
LD DE,1000
CALL pn_digit
LD DE,100
CALL pn_digit
LD DE,10
CALL pn_digit
LD A,L
ADD A,'0'
CALL TXT_OUTPUT
RET
pn_digit:
LD A,'0'-1
pn_loop:
INC A
OR A
SBC HL,DE
JR NC,pn_loop
ADD HL,DE
CALL TXT_OUTPUT
RET
; Wait for keypress
wait_key:
LD HL,msg_presskey
CALL print_str
CALL KM_WAIT_CHAR
CALL print_nl
RET
; Add A to HL
add_a_to_hl:
ADD A,L
LD L,A
RET NC
INC H
RET
; Compare strings HL and DE, Z if equal
str_equal:
PUSH HL
PUSH DE
seq_loop:
LD A,(DE)
CP (HL)
JR NZ,seq_ne
OR A
JR Z,seq_eq
INC HL
INC DE
JR seq_loop
seq_eq:
POP DE
POP HL
XOR A
RET
seq_ne:
POP DE
POP HL
OR 1
RET
; Check if HL starts with DE (B chars), Z if match
str_prefix:
PUSH HL
PUSH DE
sp_loop:
LD A,B
OR A
JR Z,sp_match
LD A,(DE)
CP (HL)
JR NZ,sp_no
INC HL
INC DE
DEC B
JR sp_loop
sp_match:
POP DE
POP HL
XOR A
RET
sp_no:
POP DE
POP HL
OR 1
RET
; Check if DE contains HL substring, Z if found
str_contains:
PUSH HL
PUSH DE
sc_outer:
LD A,(DE)
OR A
JR Z,sc_no
PUSH HL
PUSH DE
sc_inner:
LD A,(HL)
OR A
JR Z,sc_yes_pop
LD A,(DE)
OR A
JR Z,sc_no_pop
CP (HL)
JR NZ,sc_no_pop
INC HL
INC DE
JR sc_inner
sc_yes_pop:
POP DE
POP HL
POP DE
POP HL
XOR A
RET
sc_no_pop:
POP DE
POP HL
INC DE
JR sc_outer
sc_no:
POP DE
POP HL
OR 1
RET
; Partial match - HL until space/TO in DE, Z if found
str_partial_match:
PUSH HL
PUSH DE
spm_outer:
LD A,(DE)
OR A
JR Z,spm_no
PUSH HL
PUSH DE
spm_inner:
LD A,(HL)
OR A
JR Z,spm_yes_pop
CP ' '
JR Z,spm_yes_pop
LD A,(DE)
OR A
JR Z,spm_no_pop
CP (HL)
JR NZ,spm_no_pop
INC HL
INC DE
JR spm_inner
spm_yes_pop:
POP DE
POP HL
POP DE
POP HL
XOR A
RET
spm_no_pop:
POP DE
POP HL
INC DE
JR spm_outer
spm_no:
POP DE
POP HL
OR 1
RET
; Find DE substring in HL, C flag if found, HL = match pos
str_find:
LD (sf_de_save),DE ; Save search string pointer
sf_loop:
LD A,(HL)
OR A
JR Z,sf_no ; End of string, not found
PUSH HL ; Save current position
LD DE,(sf_de_save) ; Get search string
sf_cmp:
LD A,(DE)
OR A
JR Z,sf_yes ; End of search string = found!
CP (HL)
JR NZ,sf_cmp_no ; Mismatch
INC HL
INC DE
JR sf_cmp
sf_yes:
POP HL ; HL = position where match started
SCF ; Set carry = found
RET
sf_cmp_no:
POP HL ; Restore position
INC HL ; Try next position
JR sf_loop
sf_no:
OR A ; Clear carry = not found
RET
sf_de_save:
DEFW 0 ; Storage for DE
; ========================================
; DATA ACCESS FUNCTIONS
; ========================================
; Get room name pointer for room A
get_room_name_ptr:
DEC A
SLA A
LD HL,room_name_ptrs
CALL add_a_to_hl
LD A,(HL)
INC HL
LD H,(HL)
LD L,A
RET
; Get room desc pointer for room A
get_room_desc_ptr:
DEC A
SLA A
LD HL,room_desc_ptrs
CALL add_a_to_hl
LD A,(HL)
INC HL
LD H,(HL)
LD L,A
RET
; Get exit: A=room, B=dir(1-6), returns A=target
get_exit:
PUSH BC
DEC A
LD C,A
LD A,B
DEC A
LD B,A
; offset = room * 6 + dir
LD A,C
LD H,0
LD L,A
ADD HL,HL
ADD HL,HL
LD D,0
LD E,A
ADD HL,DE
ADD HL,DE
LD A,B
CALL add_a_to_hl
LD DE,room_exits
ADD HL,DE
LD A,(HL)
POP BC
RET
; Check exit unlocked: A=room, B=dir, A=1 if open
check_exit_unlocked:
PUSH BC
DEC A
LD C,A
LD A,B
DEC A
LD B,A
LD A,C
LD H,0
LD L,A
ADD HL,HL
ADD HL,HL
LD D,0
LD E,A
ADD HL,DE
ADD HL,DE
LD A,B
CALL add_a_to_hl
LD DE,room_unlocked
ADD HL,DE
LD A,(HL)
POP BC
RET
; Set exit unlocked: A=room, B=dir
set_exit_unlocked:
PUSH BC
DEC A
LD C,A
LD A,B
DEC A
LD B,A
LD A,C
LD H,0
LD L,A
ADD HL,HL
ADD HL,HL
LD D,0
LD E,A
ADD HL,DE
ADD HL,DE
LD A,B
CALL add_a_to_hl
LD DE,room_unlocked
ADD HL,DE
LD (HL),1
POP BC
RET
; Get exit requirement: A=room, B=dir, HL=ptr
get_exit_requirement:
PUSH BC
DEC A
LD C,A
LD A,B
DEC A
LD B,A
LD A,C
LD H,0
LD L,A
ADD HL,HL
ADD HL,HL
LD D,0
LD E,A
ADD HL,DE
ADD HL,DE
LD A,B
CALL add_a_to_hl
ADD HL,HL
LD DE,room_req_ptrs
ADD HL,DE
LD A,(HL)
INC HL
LD H,(HL)
LD L,A
POP BC
RET
; Get item name: A=index(1-based), HL=ptr
get_item_name_ptr:
DEC A
SLA A
LD HL,item_name_ptrs
CALL add_a_to_hl
LD A,(HL)
INC HL
LD H,(HL)
LD L,A
RET
; Get item desc: A=index, HL=ptr
get_item_desc_ptr:
DEC A
SLA A
LD HL,item_desc_ptrs
CALL add_a_to_hl
LD A,(HL)
INC HL
LD H,(HL)
LD L,A
RET
; Get NPC name: A=index(1-based), HL=ptr
get_npc_name_ptr:
DEC A
SLA A
LD HL,npc_name_ptrs
CALL add_a_to_hl
LD A,(HL)
INC HL
LD H,(HL)
LD L,A
RET
; Get NPC desc: A=index, HL=ptr
get_npc_desc_ptr:
DEC A
SLA A
LD HL,npc_desc_ptrs
CALL add_a_to_hl
LD A,(HL)
INC HL
LD H,(HL)
LD L,A
RET
; Get NPC talk: A=index, HL=ptr
get_npc_talk_ptr:
DEC A
SLA A
LD HL,npc_talk_ptrs
CALL add_a_to_hl
LD A,(HL)
INC HL
LD H,(HL)
LD L,A
RET
; Get NPC wants: A=index, HL=ptr
get_npc_wants_ptr:
DEC A
SLA A
LD HL,npc_wants_ptrs
CALL add_a_to_hl
LD A,(HL)
INC HL
LD H,(HL)
LD L,A
RET
; Get NPC gives: A=index, HL=ptr
get_npc_gives_ptr:
DEC A
SLA A
LD HL,npc_gives_ptrs
CALL add_a_to_hl
LD A,(HL)
INC HL
LD H,(HL)
LD L,A
RET
; Get death msg: A=index, HL=ptr
get_death_msg_ptr:
SLA A
LD HL,death_msg_ptrs
CALL add_a_to_hl
LD A,(HL)
INC HL
LD H,(HL)
LD L,A
RET
; Get survival item: A=index, HL=ptr
get_survival_item_ptr:
SLA A
LD HL,survival_item_ptrs
CALL add_a_to_hl
LD A,(HL)
INC HL
LD H,(HL)
LD L,A
RET
; ========================================
; INVENTORY MANAGEMENT
; ========================================
; Add item A to inventory
add_to_inventory:
PUSH AF
LD A,(inv_count)
LD HL,inventory
CALL add_a_to_hl
POP AF
LD (HL),A
LD A,(inv_count)
INC A
LD (inv_count),A
RET
; Remove item at slot A
remove_from_inventory:
LD (rfi_slot),A
DEC A
LD HL,inventory
CALL add_a_to_hl
LD D,H
LD E,L
INC DE
LD A,(inv_count)
LD B,A
LD A,(rfi_slot)
SUB B
NEG
JR Z,rfi_done
LD B,A
rfi_shift:
LD A,(DE)
LD (HL),A
INC HL
INC DE
DJNZ rfi_shift
rfi_done:
LD A,(inv_count)
DEC A
LD (inv_count),A
RET
rfi_slot:
DEFB 0
; Check if have item, HL=name, C flag if yes
check_have_item:
LD (chi_name),HL
LD A,(inv_count)
OR A
JR Z,chi_no
LD B,A
LD C,1
chi_loop:
PUSH BC
LD A,C
DEC A
LD HL,inventory
CALL add_a_to_hl
LD A,(HL)
OR A
JR Z,chi_next
CALL get_item_name_ptr
LD DE,(chi_name)
CALL str_contains
JR NZ,chi_next
POP BC
SCF
RET
chi_next:
POP BC
INC C
DJNZ chi_loop
chi_no:
OR A
RET
chi_name:
DEFW 0
; ========================================
; INITIALIZE GAME DATA
; ========================================
init_data:
; Copy initial item locations
LD HL,item_locations_init
LD DE,item_locations
LD BC,NUM_ITEMS
LD A,B
OR C
JR Z,id_skip_items
LDIR
id_skip_items:
; Copy initial item parents
LD HL,item_parents_init
LD DE,item_parents
LD BC,NUM_ITEMS
LD A,B
OR C
JR Z,id_skip_parents
LDIR
id_skip_parents:
; Copy initial NPC locations
LD HL,npc_locations_init
LD DE,npc_locations
LD BC,NUM_NPCS
LD A,B
OR C
JR Z,id_skip_npcs
LDIR
id_skip_npcs:
; Init unlocked flags to 0 (locked by default)
; Exits without requirements are always open (checked in do_move)
LD HL,room_unlocked
LD BC,NUM_ROOMS*6
id_unlock_loop:
XOR A
LD (HL),A
INC HL
DEC BC
LD A,B
OR C
JR NZ,id_unlock_loop
; Clear item open flags
LD HL,item_is_open
LD BC,NUM_ITEMS
LD A,B
OR C
JR Z,id_skip_open
id_open_loop:
XOR A
LD (HL),A
INC HL
DEC BC
LD A,B
OR C
JR NZ,id_open_loop
id_skip_open:
; Clear NPC gift flags
LD HL,npc_got_gift
LD BC,NUM_NPCS
LD A,B
OR C
JR Z,id_skip_gift
id_gift_loop:
XOR A
LD (HL),A
INC HL
DEC BC
LD A,B
OR C
JR NZ,id_gift_loop
id_skip_gift:
; Clear inventory
LD HL,inventory
LD B,MAX_INV
XOR A
id_inv_loop:
LD (HL),A
INC HL
DJNZ id_inv_loop
RET
; ========================================
; GAME DATA
; ========================================
str_title:
DEFB "THE FORGOTTEN MAYA PRINCESS",0
str_author:
DEFB "Devil-System",0
str_by:
DEFB "by ",0
str_winmsg:
DEFB "Princess Ixchel embraces you! Together",13,10
DEFB "you escape into the sunset!",0
str_help_text:
DEFB "COMMANDS:",13,10
DEFB "N,S,E,W,U,D - Move",13,10
DEFB "TAKE, DROP, USE",13,10
DEFB "EXAMINE, OPEN, CLOSE",13,10
DEFB "TALK TO, GIVE X TO Y",13,10
DEFB "I, L, SCORE, QUIT",0
str_dir_n:
DEFB "N ",0
str_dir_e:
DEFB "E ",0
str_dir_s:
DEFB "S ",0
str_dir_w:
DEFB "W ",0
str_dir_u:
DEFB "U ",0
str_dir_d:
DEFB "D ",0
str_kw_to:
DEFB " TO ",0
str_kw_from:
DEFB " FROM ",0
; === MESSAGES ===
msg_filename:
DEFB "SAVEFILE (no ext.):",0
msg_saved:
DEFB "Game saved.",0
msg_loaded:
DEFB "Game loaded.",0
msg_save_error:
DEFB "Can't save.",0
msg_load_error:
DEFB "Can't load.",0
msg_cancelled:
DEFB "Cancelled.",0
msg_takefrom_syntax:
DEFB "TAKE X FROM Y",0
msg_yousee:
DEFB "You see: ",0
msg_inside:
DEFB "Inside: ",0
msg_empty_c:
DEFB " Empty.",0
msg_exits:
DEFB "Exits: ",0
msg_none:
DEFB "none",0
msg_score:
DEFB "Score: ",0
msg_presskey:
DEFB "[key]",0
msg_unknown:
DEFB "Huh?",0
msg_cantgo:
DEFB "Can't go there.",0
msg_blocked:
DEFB "Blocked.",0
msg_what:
DEFB "What?",0
msg_nothere:
DEFB "Not here.",0
msg_donthave:
DEFB "Don't have it.",0
msg_full:
DEFB "Full!",0
msg_taken:
DEFB "Taken.",0
msg_dropped:
DEFB "Dropped.",0
msg_usewhat:
DEFB "Use what?",0
msg_unlocked:
DEFB "Unlocked!",0
msg_nothing:
DEFB "Nothing happens.",0
msg_nothing_special:
DEFB "You see nothing special.",0
msg_opened:
DEFB "Opened.",0
msg_closed:
DEFB "Closed.",0
msg_notcontainer:
DEFB "Can't open that.",0
msg_talkto:
DEFB "Talk to whom?",0
msg_noone:
DEFB "No one here.",0
msg_silence:
DEFB "...",0
msg_thanks:
DEFB "Thanks!",0
msg_nowant:
DEFB "They don't want that.",0
msg_got:
DEFB "Got: ",0
msg_give_syntax:
DEFB "GIVE X TO Y",0
msg_inventory:
DEFB "Inventory:",0
msg_empty:
DEFB " empty",0
msg_indent:
DEFB " ",0
msg_gameover:
DEFB "GAME OVER",0
msg_youwin:
DEFB "YOU WIN!",0
msg_bye:
DEFB "Goodbye!",0
str_empty:
DEFB 0
; === COMMAND STRINGS ===
cmd_north:
DEFB "N",0
cmd_north1:
DEFB "NORTH",0
cmd_north2:
DEFB "GO NORTH",0
cmd_south:
DEFB "S",0
cmd_south1:
DEFB "SOUTH",0
cmd_south2:
DEFB "GO SOUTH",0
cmd_east:
DEFB "E",0
cmd_east1:
DEFB "EAST",0
cmd_east2:
DEFB "GO EAST",0
cmd_west:
DEFB "W",0
cmd_west1:
DEFB "WEST",0
cmd_west2:
DEFB "GO WEST",0
cmd_up:
DEFB "U",0
cmd_up1:
DEFB "UP",0
cmd_up2:
DEFB "GO UP",0
cmd_up3:
DEFB "CLIMB",0
cmd_down:
DEFB "D",0
cmd_down1:
DEFB "DOWN",0
cmd_down2:
DEFB "DN",0
cmd_down3:
DEFB "GO DOWN",0
cmd_down4:
DEFB "DESCEND",0
cmd_lookin:
DEFB "L IN",0
cmd_lookin1:
DEFB "LOOK IN",0
cmd_lookin2:
DEFB "EXAMINE ROOM IN",0
cmd_look:
DEFB "L",0
cmd_look1:
DEFB "LOOK",0
cmd_look2:
DEFB "EXAMINE ROOM",0
cmd_inv:
DEFB "I",0
cmd_inv1:
DEFB "INV",0
cmd_inv2:
DEFB "INVENTORY",0
cmd_take:
DEFB "TAKE",0
cmd_take1:
DEFB "GET",0
cmd_take2:
DEFB "GRAB",0
cmd_take3:
DEFB "PICK UP",0
cmd_drop:
DEFB "DROP",0
cmd_drop1:
DEFB "PUT DOWN",0
cmd_drop2:
DEFB "LEAVE",0
cmd_exam:
DEFB "EXAMINE",0
cmd_exam1:
DEFB "X",0
cmd_exam2:
DEFB "LOOK AT",0
cmd_exam3:
DEFB "CHECK",0
cmd_exam4:
DEFB "INSPECT",0
cmd_use:
DEFB "USE",0
cmd_use1:
DEFB "APPLY",0
cmd_open:
DEFB "OPEN",0
cmd_close:
DEFB "CLOSE",0
cmd_close1:
DEFB "SHUT",0
cmd_talk:
DEFB "TALK TO",0
cmd_talk1:
DEFB "SPEAK TO",0
cmd_talk2:
DEFB "ASK TO",0
cmd_talk3:
DEFB "SAY TO",0
cmd_give:
DEFB "GIVE",0
cmd_give1:
DEFB "OFFER",0
cmd_give2:
DEFB "HAND",0
cmd_help:
DEFB "HELP",0
cmd_help1:
DEFB "?",0
cmd_help2:
DEFB "COMMANDS",0
cmd_help3:
DEFB "HINT",0
cmd_score:
DEFB "SCORE",0
cmd_score1:
DEFB "POINTS",0
cmd_save:
DEFB "SAVE",0
cmd_save1:
DEFB "SAVE GAME",0
cmd_load:
DEFB "LOAD",0
cmd_load1:
DEFB "RESTORE",0
cmd_load2:
DEFB "LOAD GAME",0
cmd_quit:
DEFB "QUIT",0
cmd_quit1:
DEFB "EXIT",0
cmd_quit2:
DEFB "Q",0
cmd_quit3:
DEFB "BYE",0
; === ROOM DATA ===
room_name_ptrs:
DEFW room_1_name
DEFW room_2_name
DEFW room_3_name
DEFW room_4_name
DEFW room_5_name
DEFW room_6_name
DEFW room_7_name
DEFW room_8_name
DEFW room_9_name
DEFW room_10_name
DEFW room_11_name
DEFW room_12_name
DEFW room_13_name
DEFW room_14_name
DEFW room_15_name
DEFW room_16_name
DEFW room_17_name
DEFW room_18_name
DEFW room_19_name
DEFW room_20_name
DEFW room_21_name
DEFW room_22_name
DEFW room_23_name
DEFW room_24_name
DEFW room_25_name
room_desc_ptrs:
DEFW room_1_desc
DEFW room_2_desc
DEFW room_3_desc
DEFW room_4_desc
DEFW room_5_desc
DEFW room_6_desc
DEFW room_7_desc
DEFW room_8_desc
DEFW room_9_desc
DEFW room_10_desc
DEFW room_11_desc
DEFW room_12_desc
DEFW room_13_desc
DEFW room_14_desc
DEFW room_15_desc
DEFW room_16_desc
DEFW room_17_desc
DEFW room_18_desc
DEFW room_19_desc
DEFW room_20_desc
DEFW room_21_desc
DEFW room_22_desc
DEFW room_23_desc
DEFW room_24_desc
DEFW room_25_desc
room_1_name:
DEFB "Base Camp",0
room_1_desc:
DEFB "Your expedition camp at jungle's edge.",13,10
DEFB "A worn tent and smoking fire. Your",13,10
DEFB "guide fled, leaving notes about a",13,10
DEFB "cursed princess of legendary beauty.",0
room_2_name:
DEFB "Jungle Trail",0
room_2_desc:
DEFB "A narrow path through dense",13,10
DEFB "vegetation. Howler monkeys scream",13,10
DEFB "above. The humidity makes your clothes",13,10
DEFB "cling to your body.",0
room_3_name:
DEFB "Riverside",0
room_3_desc:
DEFB "A swift river blocks your path.",13,10
DEFB "Crocodiles bask on muddy banks,",13,10
DEFB "watching hungrily. You need a way to",13,10
DEFB "cross safely.",0
room_4_name:
DEFB "Abandoned Camp",0
room_4_desc:
DEFB "A destroyed campsite. Torn tents and",13,10
DEFB "scattered gear. A skeleton clutches a",13,10
DEFB "journal. Something terrible happened",13,10
DEFB "here.",0
room_5_name:
DEFB "Jungle Clearing",0
room_5_desc:
DEFB "Sunlight breaks through the canopy.",13,10
DEFB "Exotic birds sing. Stone markers hint",13,10
DEFB "at ancient civilization ahead.",0
room_6_name:
DEFB "Shaman's Hut",0
room_6_desc:
DEFB "A hut draped with colorful fabrics.",13,10
DEFB "Incense curls through the air. Strange",13,10
DEFB "masks hang on walls. The smell is",13,10
DEFB "intoxicating.",0
room_7_name:
DEFB "Jaguar's Den",0
room_7_desc:
DEFB "A dark cave reeking of musk. Yellow",13,10
DEFB "eyes gleam from shadows. Low growling",13,10
DEFB "echoes. The beast is hungry.",0
room_8_name:
DEFB "Overgrown Path",0
room_8_desc:
DEFB "Thick vines block your way north.",13,10
DEFB "Carvings on trees depict a beautiful",13,10
DEFB "woman, her curves shown in flowing",13,10
DEFB "robes.",0
room_9_name:
DEFB "Quicksand Marsh",0
room_9_desc:
DEFB "Treacherous boggy ground. Bubbles rise",13,10
DEFB "from hidden pools. One wrong step",13,10
DEFB "means slow death.",0
room_10_name:
DEFB "Sacred Cenote",0
room_10_desc:
DEFB "A deep pool of crystal blue water.",13,10
DEFB "Ancient Maya threw offerings here.",13,10
DEFB "Gold glitters in the depths.",0
room_11_name:
DEFB "Temple Steps",0
room_11_desc:
DEFB "Massive stone steps lead to a pyramid.",13,10
DEFB "Carved reliefs show a princess - full",13,10
DEFB "lips, flowing hair, alluring curves.",0
room_12_name:
DEFB "Serpent Pit",0
room_12_desc:
DEFB "A chamber filled with writhing snakes.",13,10
DEFB "Their hissing echoes. Hundreds of",13,10
DEFB "forked tongues taste the air.",0
room_13_name:
DEFB "Outer Treasury",0
room_13_desc:
DEFB "Gold and jade scattered everywhere.",13,10
DEFB "Silks and perfume bottles hint at a",13,10
DEFB "lady's presence. A faint scent",13,10
DEFB "lingers.",0
room_14_name:
DEFB "Temple Entrance",0
room_14_desc:
DEFB "A vast hall with towering serpent",13,10
DEFB "columns. Torches flicker. Murals",13,10
DEFB "depict ceremonies honoring a beautiful",13,10
DEFB "maiden.",0
room_15_name:
DEFB "Priest's Quarters",0
room_15_desc:
DEFB "Dusty scrolls and ritual objects. A",13,10
DEFB "skeleton in robes sits at a desk,",13,10
DEFB "quill in hand. His message unfinished.",0
room_16_name:
DEFB "Inner Treasury",0
room_16_desc:
DEFB "The princess's treasure room. Jewels",13,10
DEFB "sparkle. Delicate silk garments hint",13,10
DEFB "at her refined tastes.",0
room_17_name:
DEFB "Main Temple Hall",0
room_17_desc:
DEFB "An enormous chamber. Moonlight streams",13,10
DEFB "through openings. Murals show the",13,10
DEFB "princess dancing sensually under",13,10
DEFB "stars.",0
room_18_name:
DEFB "Bathing Pool",0
room_18_desc:
DEFB "A crystal pool surrounded by orchids.",13,10
DEFB "Warm steam rises. Rose petals float.",13,10
DEFB "The princess bathed here.",0
room_19_name:
DEFB "Cursed Altar",0
room_19_desc:
DEFB "A black obsidian altar with glowing",13,10
DEFB "symbols. Dark energy pulses. The",13,10
DEFB "priest cast his curse here.",0
room_20_name:
DEFB "Garden of Desire",0
room_20_desc:
DEFB "A hidden garden with moonflowers. Soft",13,10
DEFB "music plays from nowhere. Aphrodisiac",13,10
DEFB "scents fill the air.",0
room_21_name:
DEFB "Spirit Sanctuary",0
room_21_desc:
DEFB "Ethereal mist swirls here. Candles",13,10
DEFB "float in midair. The boundary between",13,10
DEFB "worlds is thin.",0
room_22_name:
DEFB "Royal Wardrobe",0
room_22_desc:
DEFB "Sheer silk gowns fill wardrobes. Lace",13,10
DEFB "garments lie draped over chairs. A",13,10
DEFB "vanity reflects your flushed face.",0
room_23_name:
DEFB "Princess's Chamber",0
room_23_desc:
DEFB "Silk curtains frame a golden bed.",13,10
DEFB "PRINCESS IXCHEL lies there, caramel",13,10
DEFB "skin glowing, curves beneath thin",13,10
DEFB "white silk.",0
room_24_name:
DEFB "Hidden Passage",0
room_24_desc:
DEFB "A secret tunnel behind the bed. Cool",13,10
DEFB "air flows from ahead. This is the",13,10
DEFB "escape route.",0
room_25_name:
DEFB "Temple Exit",0
room_25_desc:
DEFB "Warm sunlight streams through ancient",13,10
DEFB "doors. The jungle awaits. Freedom for",13,10
DEFB "those who carry true love.",0
room_exits:
DEFB 2,0,0,0,0,0 ; Room 1
DEFB 5,4,1,3,0,0 ; Room 2
DEFB 6,2,0,0,0,0 ; Room 3
DEFB 7,0,0,2,0,0 ; Room 4
DEFB 8,7,2,6,0,0 ; Room 5
DEFB 9,5,3,0,0,0 ; Room 6
DEFB 10,0,4,5,0,0 ; Room 7
DEFB 11,10,5,9,0,0 ; Room 8
DEFB 12,8,6,0,0,0 ; Room 9
DEFB 13,0,7,8,0,0 ; Room 10
DEFB 14,13,8,12,0,0 ; Room 11
DEFB 15,11,9,0,0,0 ; Room 12
DEFB 16,0,10,11,0,0 ; Room 13
DEFB 17,16,11,15,0,0 ; Room 14
DEFB 18,14,12,0,0,0 ; Room 15
DEFB 19,0,13,14,0,0 ; Room 16
DEFB 20,19,14,18,0,0 ; Room 17
DEFB 21,17,15,0,0,0 ; Room 18
DEFB 22,0,16,17,0,0 ; Room 19
DEFB 23,22,17,21,0,0 ; Room 20
DEFB 24,20,18,0,0,0 ; Room 21
DEFB 0,0,19,20,0,0 ; Room 22
DEFB 0,0,20,24,0,0 ; Room 23
DEFB 25,23,21,0,0,0 ; Room 24
DEFB 0,0,24,0,0,0 ; Room 25
room_req_ptrs:
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW room_8_req_north
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW room_11_req_north
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW room_13_req_north
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW room_17_req_north
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW room_20_req_north
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW room_24_req_north
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
room_8_req_north:
DEFB "MACHETE",0
room_11_req_north:
DEFB "TEMPLE KEY",0
room_13_req_north:
DEFB "SILVER KEY",0
room_17_req_north:
DEFB "SPIRIT BLESSING",0
room_20_req_north:
DEFB "GOLDEN KEY",0
room_24_req_north:
DEFB "JADE HEART",0
; === ITEM DATA ===
item_name_ptrs:
DEFW item_1_name
DEFW item_2_name
DEFW item_3_name
DEFW item_4_name
DEFW item_5_name
DEFW item_6_name
DEFW item_7_name
DEFW item_8_name
DEFW item_9_name
DEFW item_10_name
DEFW item_11_name
DEFW item_12_name
DEFW item_13_name
DEFW item_14_name
DEFW item_15_name
DEFW item_16_name
DEFW item_17_name
DEFW item_18_name
DEFW item_19_name
DEFW item_20_name
DEFW item_21_name
DEFW item_22_name
DEFW item_23_name
DEFW item_24_name
DEFW item_25_name
DEFW item_26_name
DEFW item_27_name
DEFW item_28_name
DEFW item_29_name
DEFW item_30_name
DEFW item_31_name
DEFW item_32_name
item_desc_ptrs:
DEFW item_1_desc
DEFW item_2_desc
DEFW item_3_desc
DEFW item_4_desc
DEFW item_5_desc
DEFW item_6_desc
DEFW item_7_desc
DEFW item_8_desc
DEFW item_9_desc
DEFW item_10_desc
DEFW item_11_desc
DEFW item_12_desc
DEFW item_13_desc
DEFW item_14_desc
DEFW item_15_desc
DEFW item_16_desc
DEFW item_17_desc
DEFW item_18_desc
DEFW item_19_desc
DEFW item_20_desc
DEFW item_21_desc
DEFW item_22_desc
DEFW item_23_desc
DEFW item_24_desc
DEFW item_25_desc
DEFW item_26_desc
DEFW item_27_desc
DEFW item_28_desc
DEFW item_29_desc
DEFW item_30_desc
DEFW item_31_desc
DEFW item_32_desc
item_locations_init:
DEFB 1
DEFB 1
DEFB 1
DEFB 2
DEFB 4
DEFB 4
DEFB 4
DEFB 4
DEFB 6
DEFB 6
DEFB 6
DEFB 5
DEFB 10
DEFB 10
DEFB 10
DEFB 11
DEFB 13
DEFB 13
DEFB 13
DEFB 15
DEFB 15
DEFB 16
DEFB 16
DEFB 16
DEFB 18
DEFB 18
DEFB 20
DEFB 20
DEFB 21
DEFB 22
DEFB 22
DEFB 22
item_is_container:
DEFB 1
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 1
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 1
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 1
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
item_points:
DEFB 0
DEFB 5
DEFB 10
DEFB 5
DEFB 15
DEFB 0
DEFB 10
DEFB 10
DEFB 20
DEFB 15
DEFB 10
DEFB 15
DEFB 25
DEFB 15
DEFB 20
DEFB 5
DEFB 0
DEFB 20
DEFB 15
DEFB 20
DEFB 15
DEFB 0
DEFB 30
DEFB 25
DEFB 10
DEFB 15
DEFB 15
DEFB 25
DEFB 35
DEFB 20
DEFB 15
DEFB 20
item_parents_init:
DEFB 0
DEFB 1
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 6
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 17
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 22
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
item_1_name:
DEFB "EXPEDITION BAG",0
item_1_desc:
DEFB "A weathered leather bag left behind.",0
item_2_name:
DEFB "COMPASS",0
item_2_desc:
DEFB "A brass compass. Spins wildly near the",13,10
DEFB "temple.",0
item_3_name:
DEFB "ROPE",0
item_3_desc:
DEFB "A long coil of strong rope.",0
item_4_name:
DEFB "CANTEEN",0
item_4_desc:
DEFB "A metal canteen filled with water.",0
item_5_name:
DEFB "JOURNAL",0
item_5_desc:
DEFB "Describes the princess: 'Skin like",13,10
DEFB "honey, lips like petals, curves that",13,10
DEFB "drive men mad.'",0
item_6_name:
DEFB "WOODEN CHEST",0
item_6_desc:
DEFB "A rotting chest half-buried in mud.",0
item_7_name:
DEFB "MACHETE",0
item_7_desc:
DEFB "A sharp jungle blade for cutting",13,10
DEFB "vines.",0
item_8_name:
DEFB "WOODEN PLANK",0
item_8_desc:
DEFB "A sturdy plank to cross soft ground.",0
item_9_name:
DEFB "SNAKE CHARM",0
item_9_desc:
DEFB "A wooden flute that mesmerizes",13,10
DEFB "serpents.",0
item_10_name:
DEFB "LOVE POTION",0
item_10_desc:
DEFB "Pink liquid in a heart bottle.",13,10
DEFB "'Awakens passion.'",0
item_11_name:
DEFB "RAW MEAT",0
item_11_desc:
DEFB "Fresh meat wrapped in leaves.",13,10
DEFB "Predators love it.",0
item_12_name:
DEFB "EXOTIC ORCHID",0
item_12_desc:
DEFB "A purple flower with intoxicating",13,10
DEFB "fragrance.",0
item_13_name:
DEFB "GOLD COINS",0
item_13_desc:
DEFB "Ancient Maya gold coins. Worth a",13,10
DEFB "fortune.",0
item_14_name:
DEFB "DIVING MASK",0
item_14_desc:
DEFB "Primitive diving mask of glass and",13,10
DEFB "leather.",0
item_15_name:
DEFB "TEMPLE KEY",0
item_15_desc:
DEFB "Heavy bronze key with serpent",13,10
DEFB "engravings.",0
item_16_name:
DEFB "TORCH",0
item_16_desc:
DEFB "A burning torch for dark passages.",0
item_17_name:
DEFB "JEWELED BOX",0
item_17_desc:
DEFB "An ornate box with rubies and",13,10
DEFB "emeralds.",0
item_18_name:
DEFB "SILVER KEY",0
item_18_desc:
DEFB "A delicate silver key shaped like a",13,10
DEFB "flower.",0
item_19_name:
DEFB "SILK SCARF",0
item_19_desc:
DEFB "Rose-colored. Still carries her sweet",13,10
DEFB "perfume.",0
item_20_name:
DEFB "ANCIENT SCROLL",0
item_20_desc:
DEFB "'Only true love's kiss can wake the",13,10
DEFB "sleeping beauty.'",0
item_21_name:
DEFB "RITUAL DAGGER",0
item_21_desc:
DEFB "An obsidian blade for ancient",13,10
DEFB "ceremonies.",0
item_22_name:
DEFB "TREASURE CHEST",0
item_22_desc:
DEFB "A golden chest overflowing with",13,10
DEFB "jewels.",0
item_23_name:
DEFB "JADE AMULET",0
item_23_desc:
DEFB "Protective amulet pulsing with warm",13,10
DEFB "energy.",0
item_24_name:
DEFB "GOLDEN KEY",0
item_24_desc:
DEFB "A heart-shaped key. Unlocks something",13,10
DEFB "precious.",0
item_25_name:
DEFB "ROSE PETALS",0
item_25_desc:
DEFB "Soft petals floating on the pool.",13,10
DEFB "Divine scent.",0
item_26_name:
DEFB "BATH OIL",0
item_26_desc:
DEFB "Crystal vial of seductive scented oil.",0
item_27_name:
DEFB "PASSION FRUIT",0
item_27_desc:
DEFB "Ripe exotic fruit. Its juice awakens",13,10
DEFB "desire.",0
item_28_name:
DEFB "MOONFLOWER",0
item_28_desc:
DEFB "Rare white flower of legendary beauty.",0
item_29_name:
DEFB "JADE NECKLACE",0
item_29_desc:
DEFB "Exquisite necklace with heart-shaped",13,10
DEFB "pendant.",0
item_30_name:
DEFB "SILK GOWN",0
item_30_desc:
DEFB "Sheer white gown leaving little to",13,10
DEFB "imagination.",0
item_31_name:
DEFB "PERFUME",0
item_31_desc:
DEFB "Crystal bottle of seductive tropical",13,10
DEFB "essence.",0
item_32_name:
DEFB "LACE GARMENT",0
item_32_desc:
DEFB "Delicate intimate garment of finest",13,10
DEFB "lace.",0
; === NPC DATA ===
npc_name_ptrs:
DEFW npc_1_name
DEFW npc_2_name
DEFW npc_3_name
DEFW npc_4_name
DEFW npc_5_name
DEFW npc_6_name
DEFW npc_7_name
DEFW npc_8_name
npc_desc_ptrs:
DEFW npc_1_desc
DEFW npc_2_desc
DEFW npc_3_desc
DEFW npc_4_desc
DEFW npc_5_desc
DEFW npc_6_desc
DEFW npc_7_desc
DEFW npc_8_desc
npc_talk_ptrs:
DEFW npc_1_talk
DEFW npc_2_talk
DEFW npc_3_talk
DEFW npc_4_talk
DEFW npc_5_talk
DEFW npc_6_talk
DEFW npc_7_talk
DEFW npc_8_talk
npc_wants_ptrs:
DEFW npc_1_wants
DEFW npc_2_wants
DEFW npc_3_wants
DEFW npc_4_wants
DEFW npc_5_wants
DEFW npc_6_wants
DEFW npc_7_wants
DEFW npc_8_wants
npc_gives_ptrs:
DEFW npc_1_gives
DEFW npc_2_gives
DEFW npc_3_gives
DEFW npc_4_gives
DEFW npc_5_gives
DEFW npc_6_gives
DEFW npc_7_gives
DEFW npc_8_gives
npc_locations_init:
DEFB 6
DEFB 5
DEFB 17
DEFB 18
DEFB 21
DEFB 22
DEFB 23
DEFB 19
npc_points:
DEFB 20
DEFB 25
DEFB 30
DEFB 25
DEFB 50
DEFB 20
DEFB 60
DEFB 30
npc_1_name:
DEFB "OLD SHAMAN",0
npc_1_desc:
DEFB "A wise old man with knowing eyes and",13,10
DEFB "colorful feathers.",0
npc_1_talk:
DEFB "You seek the princess! Take the",13,10
DEFB "charm for serpents. Feed the jaguar.",13,10
DEFB "Women love flowers!",0
npc_1_wants:
DEFB "CANTEEN",0
npc_1_gives:
DEFB "BLESSING POWDER",0
npc_2_name:
DEFB "JUNGLE GUIDE",0
npc_2_desc:
DEFB "Your former guide hiding in bushes. He",13,10
DEFB "looks ashamed.",0
npc_2_talk:
DEFB "Forgive me! Take this temple key",13,10
DEFB "from the cenote. Beware quicksand to",13,10
DEFB "the west!",0
npc_2_wants:
DEFB "GOLD COINS",0
npc_2_gives:
DEFB "TEMPLE MAP",0
npc_3_name:
DEFB "TEMPLE GUARDIAN",0
npc_3_desc:
DEFB "Muscular spirit warrior with ancient",13,10
DEFB "tattoos.",0
npc_3_talk:
DEFB "Prove worthy! Bring the priest's",13,10
DEFB "scroll to pass to the sacred garden!",0
npc_3_wants:
DEFB "ANCIENT SCROLL",0
npc_3_gives:
DEFB "SPIRIT BLESSING",0
npc_4_name:
DEFB "BATHING NYMPH",0
npc_4_desc:
DEFB "Water spirit with glistening wet skin",13,10
DEFB "and playful eyes.",0
npc_4_talk:
DEFB "The princess bathed here. Bring",13,10
DEFB "orchid and I'll share altar secrets.",0
npc_4_wants:
DEFB "EXOTIC ORCHID",0
npc_4_gives:
DEFB "WATER BLESSING",0
npc_5_name:
DEFB "QUEEN IXMUCANE",0
npc_5_desc:
DEFB "Ghost of princess's mother. Still",13,10
DEFB "beautiful in ethereal silks.",0
npc_5_talk:
DEFB "My daughter dreams of rescue! Bring",13,10
DEFB "her necklace for the Jade Heart.",0
npc_5_wants:
DEFB "JADE NECKLACE",0
npc_5_gives:
DEFB "JADE HEART",0
npc_6_name:
DEFB "HANDMAIDEN",0
npc_6_desc:
DEFB "Pretty ghost servant in transparent",13,10
DEFB "robes. She blushes.",0
npc_6_talk:
DEFB "My lady awaits true love! She adores",13,10
DEFB "moonflowers and sweet perfume!",0
npc_6_wants:
DEFB "PERFUME",0
npc_6_gives:
DEFB "CHAMBER KEY",0
npc_7_name:
DEFB "PRINCESS IXCHEL",0
npc_7_desc:
DEFB "Legendary beauty on silken bed.",13,10
DEFB "Caramel skin, dark hair, curves in",13,10
DEFB "thin white silk.",0
npc_7_talk:
DEFB "You came! Kiss me and free me! But",13,10
DEFB "first... flowers for your princess?",0
npc_7_wants:
DEFB "MOONFLOWER",0
npc_7_gives:
DEFB "PRINCESS KISS",0
npc_8_name:
DEFB "CURSED PRIEST",0
npc_8_desc:
DEFB "Skeleton of the jealous priest. Dark",13,10
DEFB "energy swirls around.",0
npc_8_talk:
DEFB "She was meant for ME! The curse",13,10
DEFB "stays... unless you have the jade",13,10
DEFB "amulet!",0
npc_8_wants:
DEFB "RITUAL DAGGER",0
npc_8_gives:
DEFB "CURSE FRAGMENT",0
; === DEADLY ROOMS ===
deadly_rooms:
DEFB 3
DEFB 7
DEFB 9
DEFB 12
DEFB 19
death_msg_ptrs:
DEFW death_msg_0
DEFW death_msg_1
DEFW death_msg_2
DEFW death_msg_3
DEFW death_msg_4
survival_item_ptrs:
DEFW survival_0
DEFW survival_1
DEFW survival_2
DEFW survival_3
DEFW survival_4
death_msg_0:
DEFB "You try to swim! The crocodiles are",13,10
DEFB "faster!",0
survival_0:
DEFB "ROPE",0
death_msg_1:
DEFB "The jaguar pounces! Its claws tear",13,10
DEFB "through you!",0
survival_1:
DEFB "RAW MEAT",0
death_msg_2:
DEFB "You sink into quicksand! Darkness",13,10
DEFB "takes you!",0
survival_2:
DEFB "WOODEN PLANK",0
death_msg_3:
DEFB "The serpents strike! Venom burns",13,10
DEFB "through you!",0
survival_3:
DEFB "SNAKE CHARM",0
death_msg_4:
DEFB "Dark magic engulfs you! Your soul is",13,10
DEFB "torn away!",0
survival_4:
DEFB "JADE AMULET",0
; ========================================
; VARIABLES (RAM)
; ========================================
; === SAVE DATA BLOCK START ===
; All game state that needs to be saved
save_data_start:
current_room:
DEFS 1
score:
DEFS 2
inv_count:
DEFS 1
inventory:
DEFS MAX_INV
item_locations:
DEFS NUM_ITEMS
item_is_open:
DEFS NUM_ITEMS
item_parents:
DEFS NUM_ITEMS
npc_locations:
DEFS NUM_NPCS
npc_got_gift:
DEFS NUM_NPCS
room_unlocked:
DEFS NUM_ROOMS*6
save_data_end:
; === SAVE DATA BLOCK END ===
; === TEMPORARY VARIABLES (not saved) ===
refresh_flag:
DEFS 1
temp_dir:
DEFS 1
temp_room:
DEFS 1
temp_target:
DEFS 1
temp_container:
DEFS 1
temp_ptr:
DEFS 2
temp_ptr2:
DEFS 2
temp_ptr3:
DEFS 2
found_item:
DEFS 1
found_inv_slot:
DEFS 1
found_npc:
DEFS 1
input_len:
DEFS 1
input_buffer:
DEFS INPUT_MAX+1
; === FILENAME INPUT ===
filename_len:
DEFS 1
filename_buf:
DEFS 16 ; Max 8 chars + some padding
; === CASSETTE BUFFER (2KB needed by firmware) ===
cas_buffer:
DEFS 2048
; === ORIGINAL STACK POINTER ===
original_sp:
DEFS 2
; === END ===
Ist noch gründlich zu testen!
Quote from: Devilmarkus on 10. February 2026, 21:35:50Erzeugt jetzt auch Assemblercode:
; ========================================
; THE FORGOTTEN MAYA PRINCESS
; By Devil-System
; Z80 Assembly for Amstrad CPC
; ========================================
; === AMSTRAD CPC FIRMWARE CALLS ===
TXT_OUTPUT EQU &BB5A
KM_WAIT_CHAR EQU &BB06
SCR_SET_MODE EQU &BC0E
TXT_CLEAR EQU &BB6C
TXT_SET_PEN EQU &BB90
TXT_SET_PAPER EQU &BB96
SCR_SET_INK EQU &BC32
SCR_SET_BORDER EQU &BC38
TXT_CUR_ON EQU &BB81
TXT_CUR_OFF EQU &BB84
CAS_IN_OPEN EQU &BC77
CAS_IN_DIRECT EQU &BC83
CAS_IN_CLOSE EQU &BC7A
CAS_OUT_OPEN EQU &BC8C
CAS_OUT_DIRECT EQU &BC98
CAS_OUT_CLOSE EQU &BC8F
; === GAME CONSTANTS ===
NUM_ROOMS EQU 25
NUM_ITEMS EQU 32
NUM_NPCS EQU 8
NUM_DEADLY EQU 5
MAX_INV EQU 20
INV_LIMIT EQU 8
START_ROOM EQU 1
WIN_ROOM EQU 25
WIN_SCORE EQU 0
WIN_ITEMS_COUNT EQU 1
INPUT_MAX EQU 78
ORG &4000
; ========================================
; PROGRAM START
; ========================================
start:
LD (original_sp),SP ; Save stack for clean exit
; Set Mode 1 (40 columns)
LD A,1
CALL SCR_SET_MODE
; Set colors: Ink 0 = black, Ink 1 = yellow
LD A,0
LD B,0
LD C,0
CALL SCR_SET_INK
LD A,1
LD B,24
LD C,24
CALL SCR_SET_INK
LD B,0
LD C,0
CALL SCR_SET_BORDER
; Initialize game state
LD A,START_ROOM
LD (current_room),A
XOR A
LD (score),A
LD (score+1),A
LD (inv_count),A
LD A,1
LD (refresh_flag),A
; Initialize items and NPCs
CALL init_data
; Show title screen
CALL show_title
; === MAIN GAME LOOP ===
main_loop:
LD A,(refresh_flag)
OR A
JR Z,main_no_refresh
CALL show_room
XOR A
LD (refresh_flag),A
main_no_refresh:
CALL get_input
CALL parse_command
JR main_loop
; ========== SHOW TITLE SCREEN ==========
show_title:
CALL TXT_CLEAR
CALL print_nl
CALL print_nl
LD HL,str_title
CALL print_str
CALL print_nl
CALL print_nl
LD HL,str_by
CALL print_str
LD HL,str_author
CALL print_str
CALL print_nl
CALL print_nl
CALL print_nl
CALL wait_key
CALL TXT_CLEAR
RET
; ========================================
; SHOW CURRENT ROOM
; ========================================
show_room:
CALL TXT_CLEAR
CALL print_nl
; Get and print room name
LD A,(current_room)
CALL get_room_name_ptr
CALL print_str
CALL print_nl
; Print separator
LD B,40
show_room_sep:
LD A,'*'
CALL TXT_OUTPUT
DJNZ show_room_sep
CALL print_nl
; Get and print room description
LD A,(current_room)
CALL get_room_desc_ptr
CALL print_str
CALL print_nl
CALL print_nl
; Show items in room
CALL show_items_here
; Show NPCs in room
CALL show_npcs_here
; Show exits
CALL show_exits
; Show score
LD HL,msg_score
CALL print_str
LD HL,(score)
CALL print_num
CALL print_nl
RET
; === SHOW ITEMS IN CURRENT ROOM ===
show_items_here:
LD A,NUM_ITEMS
OR A
RET Z
LD B,A
LD C,1 ; item index
sih_loop:
PUSH BC
; Get item location
LD A,C
DEC A
LD HL,item_locations
CALL add_a_to_hl
LD A,(HL)
LD D,A ; D = item location
; Check if in current room
LD A,(current_room)
CP D
JR NZ,sih_next
; Check if item is in container
POP BC
PUSH BC
LD A,C
DEC A
LD HL,item_parents
CALL add_a_to_hl
LD A,(HL)
OR A
JR NZ,sih_next ; in container, skip
; Print 'You see: '
LD HL,msg_yousee
CALL print_str
; Print item name
POP BC
PUSH BC
LD A,C
CALL get_item_name_ptr
CALL print_str
CALL print_nl
sih_next:
POP BC
INC C
DJNZ sih_loop
RET
; === SHOW NPCS IN CURRENT ROOM ===
show_npcs_here:
LD A,NUM_NPCS
OR A
RET Z
LD B,A
LD C,1
snh_loop:
PUSH BC
LD A,C
DEC A
LD HL,npc_locations
CALL add_a_to_hl
LD A,(HL)
LD D,A
LD A,(current_room)
CP D
JR NZ,snh_next
LD HL,msg_yousee
CALL print_str
POP BC
PUSH BC
LD A,C
CALL get_npc_name_ptr
CALL print_str
CALL print_nl
snh_next:
POP BC
INC C
DJNZ snh_loop
RET
; === SHOW AVAILABLE EXITS ===
show_exits:
LD HL,msg_exits
CALL print_str
LD A,(current_room)
LD (temp_room),A ; save room
LD E,0 ; exits found flag
; Check North (direction 1)
LD A,(temp_room)
LD B,1
CALL get_exit
OR A
JP Z,se_east
LD HL,str_dir_n
CALL print_str
LD E,1
se_east:
LD A,(temp_room)
LD B,2
CALL get_exit
OR A
JP Z,se_south
LD HL,str_dir_e
CALL print_str
LD E,1
se_south:
LD A,(temp_room)
LD B,3
CALL get_exit
OR A
JP Z,se_west
LD HL,str_dir_s
CALL print_str
LD E,1
se_west:
LD A,(temp_room)
LD B,4
CALL get_exit
OR A
JP Z,se_up
LD HL,str_dir_w
CALL print_str
LD E,1
se_up:
LD A,(temp_room)
LD B,5
CALL get_exit
OR A
JP Z,se_down
LD HL,str_dir_u
CALL print_str
LD E,1
se_down:
LD A,(temp_room)
LD B,6
CALL get_exit
OR A
JP Z,se_done
LD HL,str_dir_d
CALL print_str
LD E,1
se_done:
LD A,E
OR A
JP NZ,se_has_exits
LD HL,msg_none
CALL print_str
se_has_exits:
CALL print_nl
RET
; ========================================
; GET PLAYER INPUT
; ========================================
get_input:
CALL print_nl
LD A,'>'
CALL TXT_OUTPUT
LD A,' '
CALL TXT_OUTPUT
CALL TXT_CUR_ON
LD HL,input_buffer
LD B,0 ; char count
gi_loop:
CALL KM_WAIT_CHAR
CP 13 ; Enter
JR Z,gi_done
CP 127 ; Delete
JR Z,gi_backspace
CP 8 ; Backspace
JR Z,gi_backspace
CP 32
JR C,gi_loop ; ignore control chars
; Check buffer space
LD C,A
LD A,B
CP INPUT_MAX
JR NC,gi_loop
LD A,C
; Convert to uppercase
CP 'a'
JR C,gi_store
CP 'z'+1
JR NC,gi_store
SUB 32
gi_store:
LD (HL),A
INC HL
INC B
CALL TXT_OUTPUT
JR gi_loop
gi_backspace:
LD A,B
OR A
JR Z,gi_loop
DEC HL
DEC B
LD A,8
CALL TXT_OUTPUT
LD A,' '
CALL TXT_OUTPUT
LD A,8
CALL TXT_OUTPUT
JR gi_loop
gi_done:
LD (HL),0 ; null terminate
LD A,B
LD (input_len),A
CALL TXT_CUR_OFF
CALL print_nl
RET
; ========================================
; PARSE AND EXECUTE COMMAND
; ========================================
parse_command:
LD A,(input_len)
OR A
RET Z ; empty input
; === MOVEMENT COMMANDS ===
LD HL,input_buffer
LD DE,cmd_north
CALL str_equal
JR NZ,pc_north_no
LD A,1
JP do_move
pc_north_no:
LD HL,input_buffer
LD DE,cmd_north1
CALL str_equal
JR NZ,pc_north1_no
LD A,1
JP do_move
pc_north1_no:
LD HL,input_buffer
LD DE,cmd_north2
CALL str_equal
JR NZ,pc_north2_no
LD A,1
JP do_move
pc_north2_no:
LD HL,input_buffer
LD DE,cmd_south
CALL str_equal
JR NZ,pc_south_no
LD A,3
JP do_move
pc_south_no:
LD HL,input_buffer
LD DE,cmd_south1
CALL str_equal
JR NZ,pc_south1_no
LD A,3
JP do_move
pc_south1_no:
LD HL,input_buffer
LD DE,cmd_south2
CALL str_equal
JR NZ,pc_south2_no
LD A,3
JP do_move
pc_south2_no:
LD HL,input_buffer
LD DE,cmd_east
CALL str_equal
JR NZ,pc_east_no
LD A,2
JP do_move
pc_east_no:
LD HL,input_buffer
LD DE,cmd_east1
CALL str_equal
JR NZ,pc_east1_no
LD A,2
JP do_move
pc_east1_no:
LD HL,input_buffer
LD DE,cmd_east2
CALL str_equal
JR NZ,pc_east2_no
LD A,2
JP do_move
pc_east2_no:
LD HL,input_buffer
LD DE,cmd_west
CALL str_equal
JR NZ,pc_west_no
LD A,4
JP do_move
pc_west_no:
LD HL,input_buffer
LD DE,cmd_west1
CALL str_equal
JR NZ,pc_west1_no
LD A,4
JP do_move
pc_west1_no:
LD HL,input_buffer
LD DE,cmd_west2
CALL str_equal
JR NZ,pc_west2_no
LD A,4
JP do_move
pc_west2_no:
LD HL,input_buffer
LD DE,cmd_up
CALL str_equal
JR NZ,pc_up_no
LD A,5
JP do_move
pc_up_no:
LD HL,input_buffer
LD DE,cmd_up1
CALL str_equal
JR NZ,pc_up1_no
LD A,5
JP do_move
pc_up1_no:
LD HL,input_buffer
LD DE,cmd_up2
CALL str_equal
JR NZ,pc_up2_no
LD A,5
JP do_move
pc_up2_no:
LD HL,input_buffer
LD DE,cmd_up3
CALL str_equal
JR NZ,pc_up3_no
LD A,5
JP do_move
pc_up3_no:
LD HL,input_buffer
LD DE,cmd_down
CALL str_equal
JR NZ,pc_down_no
LD A,6
JP do_move
pc_down_no:
LD HL,input_buffer
LD DE,cmd_down1
CALL str_equal
JR NZ,pc_down1_no
LD A,6
JP do_move
pc_down1_no:
LD HL,input_buffer
LD DE,cmd_down2
CALL str_equal
JR NZ,pc_down2_no
LD A,6
JP do_move
pc_down2_no:
LD HL,input_buffer
LD DE,cmd_down3
CALL str_equal
JR NZ,pc_down3_no
LD A,6
JP do_move
pc_down3_no:
LD HL,input_buffer
LD DE,cmd_down4
CALL str_equal
JR NZ,pc_down4_no
LD A,6
JP do_move
pc_down4_no:
; === LOOK IN COMMAND ===
LD HL,input_buffer
LD DE,cmd_lookin
LD B,4
CALL str_prefix
JP NZ,pc_lookin_no
LD A,5
JP do_look_in
pc_lookin_no:
LD HL,input_buffer
LD DE,cmd_lookin1
LD B,7
CALL str_prefix
JP NZ,pc_lookin1_no
LD A,8
JP do_look_in
pc_lookin1_no:
LD HL,input_buffer
LD DE,cmd_lookin2
LD B,15
CALL str_prefix
JP NZ,pc_lookin2_no
LD A,16
JP do_look_in
pc_lookin2_no:
; === LOOK COMMAND ===
LD HL,input_buffer
LD DE,cmd_look
CALL str_equal
JR NZ,pc_look_no
LD A,1
LD (refresh_flag),A
RET
pc_look_no:
LD HL,input_buffer
LD DE,cmd_look1
CALL str_equal
JR NZ,pc_look1_no
LD A,1
LD (refresh_flag),A
RET
pc_look1_no:
LD HL,input_buffer
LD DE,cmd_look2
CALL str_equal
JR NZ,pc_look2_no
LD A,1
LD (refresh_flag),A
RET
pc_look2_no:
; === INVENTORY COMMAND ===
LD HL,input_buffer
LD DE,cmd_inv
CALL str_equal
JR NZ,pc_inv_no
JP do_inventory
pc_inv_no:
LD HL,input_buffer
LD DE,cmd_inv1
CALL str_equal
JR NZ,pc_inv1_no
JP do_inventory
pc_inv1_no:
LD HL,input_buffer
LD DE,cmd_inv2
CALL str_equal
JR NZ,pc_inv2_no
JP do_inventory
pc_inv2_no:
; === TAKE FROM COMMAND ===
LD HL,input_buffer
LD DE,cmd_take
LD B,4
CALL str_prefix
JP NZ,pc_takefrom_no
; Check if FROM keyword present
LD HL,input_buffer
LD DE,str_kw_from
CALL str_find
JP NC,pc_takefrom_no
JP do_take_from
pc_takefrom_no:
LD HL,input_buffer
LD DE,cmd_take1
LD B,3
CALL str_prefix
JP NZ,pc_takefrom1_no
; Check if FROM keyword present
LD HL,input_buffer
LD DE,str_kw_from
CALL str_find
JP NC,pc_takefrom1_no
JP do_take_from
pc_takefrom1_no:
LD HL,input_buffer
LD DE,cmd_take2
LD B,4
CALL str_prefix
JP NZ,pc_takefrom2_no
; Check if FROM keyword present
LD HL,input_buffer
LD DE,str_kw_from
CALL str_find
JP NC,pc_takefrom2_no
JP do_take_from
pc_takefrom2_no:
LD HL,input_buffer
LD DE,cmd_take3
LD B,7
CALL str_prefix
JP NZ,pc_takefrom3_no
; Check if FROM keyword present
LD HL,input_buffer
LD DE,str_kw_from
CALL str_find
JP NC,pc_takefrom3_no
JP do_take_from
pc_takefrom3_no:
; === TAKE COMMAND ===
LD HL,input_buffer
LD DE,cmd_take
LD B,4
CALL str_prefix
JR NZ,pc_take_no
LD A,5
JP do_take
pc_take_no:
LD HL,input_buffer
LD DE,cmd_take1
LD B,3
CALL str_prefix
JR NZ,pc_take1_no
LD A,4
JP do_take
pc_take1_no:
LD HL,input_buffer
LD DE,cmd_take2
LD B,4
CALL str_prefix
JR NZ,pc_take2_no
LD A,5
JP do_take
pc_take2_no:
LD HL,input_buffer
LD DE,cmd_take3
LD B,7
CALL str_prefix
JR NZ,pc_take3_no
LD A,8
JP do_take
pc_take3_no:
; === DROP COMMAND ===
LD HL,input_buffer
LD DE,cmd_drop
LD B,4
CALL str_prefix
JR NZ,pc_drop_no
LD A,5
JP do_drop
pc_drop_no:
LD HL,input_buffer
LD DE,cmd_drop1
LD B,8
CALL str_prefix
JR NZ,pc_drop1_no
LD A,9
JP do_drop
pc_drop1_no:
LD HL,input_buffer
LD DE,cmd_drop2
LD B,5
CALL str_prefix
JR NZ,pc_drop2_no
LD A,6
JP do_drop
pc_drop2_no:
; === EXAMINE COMMAND ===
LD HL,input_buffer
LD DE,cmd_exam
LD B,7
CALL str_prefix
JR NZ,pc_exam_no
LD A,8
JP do_examine
pc_exam_no:
LD HL,input_buffer
LD DE,cmd_exam1
LD B,1
CALL str_prefix
JR NZ,pc_exam1_no
LD A,2
JP do_examine
pc_exam1_no:
LD HL,input_buffer
LD DE,cmd_exam2
LD B,7
CALL str_prefix
JR NZ,pc_exam2_no
LD A,8
JP do_examine
pc_exam2_no:
LD HL,input_buffer
LD DE,cmd_exam3
LD B,5
CALL str_prefix
JR NZ,pc_exam3_no
LD A,6
JP do_examine
pc_exam3_no:
LD HL,input_buffer
LD DE,cmd_exam4
LD B,7
CALL str_prefix
JR NZ,pc_exam4_no
LD A,8
JP do_examine
pc_exam4_no:
; === USE COMMAND ===
LD HL,input_buffer
LD DE,cmd_use
LD B,3
CALL str_prefix
JR NZ,pc_use_no
LD A,4
JP do_use
pc_use_no:
LD HL,input_buffer
LD DE,cmd_use1
LD B,5
CALL str_prefix
JR NZ,pc_use1_no
LD A,6
JP do_use
pc_use1_no:
; === OPEN COMMAND ===
LD HL,input_buffer
LD DE,cmd_open
LD B,4
CALL str_prefix
JR NZ,pc_open_no
LD A,5
JP do_open
pc_open_no:
; === CLOSE COMMAND ===
LD HL,input_buffer
LD DE,cmd_close
LD B,5
CALL str_prefix
JR NZ,pc_close_no
LD A,6
JP do_close
pc_close_no:
LD HL,input_buffer
LD DE,cmd_close1
LD B,4
CALL str_prefix
JR NZ,pc_close1_no
LD A,5
JP do_close
pc_close1_no:
; === TALK COMMAND ===
LD HL,input_buffer
LD DE,cmd_talk
LD B,7
CALL str_prefix
JR NZ,pc_talk_no
LD A,8
JP do_talk
pc_talk_no:
LD HL,input_buffer
LD DE,cmd_talk1
LD B,8
CALL str_prefix
JR NZ,pc_talk1_no
LD A,9
JP do_talk
pc_talk1_no:
LD HL,input_buffer
LD DE,cmd_talk2
LD B,6
CALL str_prefix
JR NZ,pc_talk2_no
LD A,7
JP do_talk
pc_talk2_no:
LD HL,input_buffer
LD DE,cmd_talk3
LD B,6
CALL str_prefix
JR NZ,pc_talk3_no
LD A,7
JP do_talk
pc_talk3_no:
; === GIVE COMMAND ===
LD HL,input_buffer
LD DE,cmd_give
LD B,4
CALL str_prefix
JR NZ,pc_give_no
JP do_give
pc_give_no:
LD HL,input_buffer
LD DE,cmd_give1
LD B,5
CALL str_prefix
JR NZ,pc_give1_no
JP do_give
pc_give1_no:
LD HL,input_buffer
LD DE,cmd_give2
LD B,4
CALL str_prefix
JR NZ,pc_give2_no
JP do_give
pc_give2_no:
; === HELP COMMAND ===
LD HL,input_buffer
LD DE,cmd_help
CALL str_equal
JR NZ,pc_help_no
JP do_help
pc_help_no:
LD HL,input_buffer
LD DE,cmd_help1
CALL str_equal
JR NZ,pc_help1_no
JP do_help
pc_help1_no:
LD HL,input_buffer
LD DE,cmd_help2
CALL str_equal
JR NZ,pc_help2_no
JP do_help
pc_help2_no:
LD HL,input_buffer
LD DE,cmd_help3
CALL str_equal
JR NZ,pc_help3_no
JP do_help
pc_help3_no:
; === SCORE COMMAND ===
LD HL,input_buffer
LD DE,cmd_score
CALL str_equal
JR NZ,pc_score_no
JP do_show_score
pc_score_no:
LD HL,input_buffer
LD DE,cmd_score1
CALL str_equal
JR NZ,pc_score1_no
JP do_show_score
pc_score1_no:
; === SAVE COMMAND ===
LD HL,input_buffer
LD DE,cmd_save
CALL str_equal
JP NZ,pc_save_no
JP do_save
pc_save_no:
LD HL,input_buffer
LD DE,cmd_save1
CALL str_equal
JP NZ,pc_save1_no
JP do_save
pc_save1_no:
; === LOAD COMMAND ===
LD HL,input_buffer
LD DE,cmd_load
CALL str_equal
JP NZ,pc_load_no
JP do_load
pc_load_no:
LD HL,input_buffer
LD DE,cmd_load1
CALL str_equal
JP NZ,pc_load1_no
JP do_load
pc_load1_no:
LD HL,input_buffer
LD DE,cmd_load2
CALL str_equal
JP NZ,pc_load2_no
JP do_load
pc_load2_no:
; === QUIT COMMAND ===
LD HL,input_buffer
LD DE,cmd_quit
CALL str_equal
JR NZ,pc_quit_no
JP do_quit
pc_quit_no:
LD HL,input_buffer
LD DE,cmd_quit1
CALL str_equal
JR NZ,pc_quit1_no
JP do_quit
pc_quit1_no:
LD HL,input_buffer
LD DE,cmd_quit2
CALL str_equal
JR NZ,pc_quit2_no
JP do_quit
pc_quit2_no:
LD HL,input_buffer
LD DE,cmd_quit3
CALL str_equal
JR NZ,pc_quit3_no
JP do_quit
pc_quit3_no:
; Unknown command
LD HL,msg_unknown
CALL print_str
CALL print_nl
RET
; ========================================
; ACTION: MOVE
; A = direction (1-6) on entry
; ========================================
do_move:
LD (temp_dir),A ; save direction
LD B,A ; B = direction for get_exit
LD A,(current_room) ; A = room
CALL get_exit ; A = target room (0=none)
OR A
JP NZ,dm_can_go
LD HL,msg_cantgo
CALL print_str
CALL print_nl
RET
dm_can_go:
LD (temp_target),A ; save target room
; Check if exit has requirement
LD A,(current_room)
LD HL,temp_dir
LD B,(HL) ; B = direction
CALL get_exit_requirement
; HL = requirement string pointer
LD A,(HL)
OR A ; empty = no requirement
JP Z,dm_unlocked ; no requirement, can pass
; Has requirement - check if unlocked
LD A,(current_room)
LD HL,temp_dir
LD B,(HL)
CALL check_exit_unlocked
OR A
JP NZ,dm_unlocked
; Blocked!
LD HL,msg_blocked
CALL print_str
CALL print_nl
RET
dm_unlocked:
LD A,(temp_target)
LD (current_room),A
LD A,1
LD (refresh_flag),A
CALL check_death
CALL check_win
RET
; ========================================
; ACTION: TAKE
; A = offset in input buffer to object name
; ========================================
do_take:
LD HL,input_buffer
CALL add_a_to_hl
LD (temp_ptr),HL
LD A,(HL)
OR A
JP NZ,dt_have_name
LD HL,msg_what
CALL print_str
CALL print_nl
RET
dt_have_name:
LD A,NUM_ITEMS
OR A
JP NZ,dt_search
LD HL,msg_nothere
CALL print_str
CALL print_nl
RET
dt_search:
LD B,A
LD C,1
dt_loop:
PUSH BC
; Check item location
LD A,C
DEC A
LD HL,item_locations
CALL add_a_to_hl
LD A,(HL)
LD D,A
LD A,(current_room)
CP D
JP NZ,dt_next
; Check not in container
POP BC
PUSH BC
LD A,C
DEC A
LD HL,item_parents
CALL add_a_to_hl
LD A,(HL)
OR A
JP NZ,dt_next
; Check not a fixed container
POP BC
PUSH BC
LD A,C
DEC A
LD HL,item_is_container
CALL add_a_to_hl
LD A,(HL)
CP 2
JP Z,dt_next
; Check name matches
POP BC
PUSH BC
LD A,C
CALL get_item_name_ptr
EX DE,HL
LD HL,(temp_ptr)
CALL str_contains
JP NZ,dt_next
; Found it! Check inventory space
LD A,(inv_count)
CP INV_LIMIT
JR C,dt_can_take
POP BC
LD HL,msg_full
CALL print_str
CALL print_nl
RET
dt_can_take:
POP BC
LD A,C
CALL add_to_inventory
; Set item location to 0
LD A,C
DEC A
LD HL,item_locations
CALL add_a_to_hl
LD (HL),0
; Add points
PUSH BC
LD A,C
DEC A
LD HL,item_points
CALL add_a_to_hl
LD A,(HL)
OR A
JR Z,dt_no_points
LD HL,(score)
LD B,0
LD C,A
ADD HL,BC
LD (score),HL
POP BC
PUSH BC
LD A,C
DEC A
LD HL,item_points
CALL add_a_to_hl
LD (HL),0
dt_no_points:
POP BC
LD HL,msg_taken
CALL print_str
CALL print_nl
RET
dt_next:
POP BC
INC C
DEC B
JP NZ,dt_loop
LD HL,msg_nothere
CALL print_str
CALL print_nl
RET
; ========================================
; ACTION: DROP
; ========================================
do_drop:
LD HL,input_buffer
CALL add_a_to_hl
LD (temp_ptr),HL
LD A,(HL)
OR A
JP NZ,dd_have_name
LD HL,msg_what
CALL print_str
CALL print_nl
RET
dd_have_name:
LD A,(inv_count)
OR A
JP NZ,dd_search
LD HL,msg_donthave
CALL print_str
CALL print_nl
RET
dd_search:
LD B,A
LD C,1
dd_loop:
PUSH BC
LD A,C
DEC A
LD HL,inventory
CALL add_a_to_hl
LD A,(HL)
OR A
JP Z,dd_next
PUSH AF
CALL get_item_name_ptr
EX DE,HL
LD HL,(temp_ptr)
CALL str_contains
POP AF
JP NZ,dd_next
; Found - set location to current room
LD D,A
LD A,D
DEC A
LD HL,item_locations
CALL add_a_to_hl
LD A,(current_room)
LD (HL),A
POP BC
LD A,C
CALL remove_from_inventory
LD HL,msg_dropped
CALL print_str
CALL print_nl
RET
dd_next:
POP BC
INC C
DEC B
JP NZ,dd_loop
LD HL,msg_donthave
CALL print_str
CALL print_nl
RET
; ========================================
; ACTION: EXAMINE
; ========================================
do_examine:
LD HL,input_buffer
CALL add_a_to_hl
LD (temp_ptr),HL
LD A,(HL)
OR A
JP NZ,dx_have_name
LD HL,msg_what
CALL print_str
CALL print_nl
RET
dx_have_name:
LD A,NUM_ITEMS
OR A
JP Z,dx_check_npcs
LD B,A
LD C,1
dx_item_loop:
PUSH BC
LD A,C
DEC A
LD HL,item_locations
CALL add_a_to_hl
LD A,(HL)
LD D,A
LD A,(current_room)
CP D
JP Z,dx_item_accessible
LD A,D
OR A
JP NZ,dx_item_next
dx_item_accessible:
POP BC
PUSH BC
LD A,C
CALL get_item_name_ptr
EX DE,HL
LD HL,(temp_ptr)
CALL str_contains
JP NZ,dx_item_next
POP BC
LD A,C
CALL get_item_desc_ptr
LD A,(HL)
OR A
JR NZ,dx_has_desc
LD HL,msg_nothing_special
dx_has_desc:
CALL print_nl
CALL print_str
CALL print_nl
CALL wait_key
RET
dx_item_next:
POP BC
INC C
DEC B
JP NZ,dx_item_loop
dx_check_npcs:
LD A,NUM_NPCS
OR A
JP Z,dx_not_found
LD B,A
LD C,1
dx_npc_loop:
PUSH BC
LD A,C
DEC A
LD HL,npc_locations
CALL add_a_to_hl
LD A,(HL)
LD D,A
LD A,(current_room)
CP D
JP NZ,dx_npc_next
POP BC
PUSH BC
LD A,C
CALL get_npc_name_ptr
EX DE,HL
LD HL,(temp_ptr)
CALL str_contains
JP NZ,dx_npc_next
POP BC
LD A,C
CALL get_npc_desc_ptr
CALL print_nl
CALL print_str
CALL print_nl
CALL wait_key
RET
dx_npc_next:
POP BC
INC C
DEC B
JP NZ,dx_npc_loop
dx_not_found:
LD HL,msg_nothere
CALL print_str
CALL print_nl
RET
; ========================================
; ACTION: USE (unlock exits)
; ========================================
do_use:
LD HL,input_buffer
CALL add_a_to_hl
LD (temp_ptr),HL
LD A,(HL)
OR A
JP NZ,du_have_name
LD HL,msg_usewhat
CALL print_str
CALL print_nl
RET
du_have_name:
LD A,(inv_count)
OR A
JP NZ,du_search
LD HL,msg_donthave
CALL print_str
CALL print_nl
RET
du_search:
LD B,A
LD C,1
du_inv_loop:
PUSH BC
LD A,C
DEC A
LD HL,inventory
CALL add_a_to_hl
LD A,(HL)
OR A
JP Z,du_inv_next
PUSH AF
CALL get_item_name_ptr
EX DE,HL
LD HL,(temp_ptr)
CALL str_contains
POP AF
JP NZ,du_inv_next
; Found item in inventory - try to unlock exits
LD (found_item),A
POP BC
JP du_try_unlock
du_inv_next:
POP BC
INC C
DEC B
JP NZ,du_inv_loop
LD HL,msg_donthave
CALL print_str
CALL print_nl
RET
du_try_unlock:
; Check all 6 directions
LD B,6
LD C,1
du_dir_loop:
PUSH BC
; Get required item for this exit
LD A,(current_room)
LD B,C
CALL get_exit_requirement
LD A,(HL)
OR A
JP Z,du_dir_next
; Compare with our item name
PUSH HL
LD A,(found_item)
CALL get_item_name_ptr
POP DE
CALL str_equal
JP NZ,du_dir_next
; Check if already unlocked
POP BC
PUSH BC
LD A,(current_room)
LD B,C
CALL check_exit_unlocked
OR A
JP NZ,du_dir_next
; Unlock it!
POP BC
LD A,(current_room)
LD B,C
CALL set_exit_unlocked
LD HL,msg_unlocked
CALL print_str
CALL print_nl
RET
du_dir_next:
POP BC
INC C
DEC B
JP NZ,du_dir_loop
LD HL,msg_nothing
CALL print_str
CALL print_nl
RET
; ========================================
; ACTION: OPEN CONTAINER
; ========================================
do_open:
LD HL,input_buffer
CALL add_a_to_hl
LD (temp_ptr),HL
LD A,(HL)
OR A
JP NZ,dop_have_name
LD HL,msg_what
CALL print_str
CALL print_nl
RET
dop_have_name:
LD A,NUM_ITEMS
OR A
JP Z,dop_not_container
LD B,A
LD C,1
dop_loop:
PUSH BC
; Is it a container?
LD A,C
DEC A
LD HL,item_is_container
CALL add_a_to_hl
LD A,(HL)
OR A
JP Z,dop_next
; Is it here or carried?
POP BC
PUSH BC
LD A,C
DEC A
LD HL,item_locations
CALL add_a_to_hl
LD A,(HL)
LD D,A
LD A,(current_room)
CP D
JP Z,dop_accessible
LD A,D
OR A
JP NZ,dop_next
dop_accessible:
POP BC
PUSH BC
LD A,C
CALL get_item_name_ptr
EX DE,HL
LD HL,(temp_ptr)
CALL str_contains
JP NZ,dop_next
; Open it
POP BC
LD A,C
DEC A
LD HL,item_is_open
CALL add_a_to_hl
LD (HL),1
LD HL,msg_opened
CALL print_str
CALL print_nl
RET
dop_next:
POP BC
INC C
DEC B
JP NZ,dop_loop
dop_not_container:
LD HL,msg_notcontainer
CALL print_str
CALL print_nl
RET
; ========================================
; ACTION: CLOSE CONTAINER
; ========================================
do_close:
LD HL,input_buffer
CALL add_a_to_hl
LD (temp_ptr),HL
LD A,(HL)
OR A
JP NZ,dc_have_name
LD HL,msg_what
CALL print_str
CALL print_nl
RET
dc_have_name:
LD A,NUM_ITEMS
OR A
JP Z,dc_not_container
LD B,A
LD C,1
dc_loop:
PUSH BC
LD A,C
DEC A
LD HL,item_is_container
CALL add_a_to_hl
LD A,(HL)
OR A
JP Z,dc_next
POP BC
PUSH BC
LD A,C
DEC A
LD HL,item_is_open
CALL add_a_to_hl
LD A,(HL)
OR A
JP Z,dc_next
POP BC
PUSH BC
LD A,C
CALL get_item_name_ptr
EX DE,HL
LD HL,(temp_ptr)
CALL str_contains
JP NZ,dc_next
POP BC
LD A,C
DEC A
LD HL,item_is_open
CALL add_a_to_hl
LD (HL),0
LD HL,msg_closed
CALL print_str
CALL print_nl
RET
dc_next:
POP BC
INC C
DEC B
JP NZ,dc_loop
dc_not_container:
LD HL,msg_notcontainer
CALL print_str
CALL print_nl
RET
; ========================================
; ACTION: LOOK IN CONTAINER
; A = offset to container name
; ========================================
do_look_in:
LD HL,input_buffer
CALL add_a_to_hl
LD (temp_ptr),HL
LD A,(HL)
OR A
JP NZ,dli_have_name
LD HL,msg_what
CALL print_str
CALL print_nl
RET
dli_have_name:
LD A,NUM_ITEMS
OR A
JP Z,dli_not_found
LD B,A
LD C,1
dli_loop:
PUSH BC
; Is it a container?
LD A,C
DEC A
LD HL,item_is_container
CALL add_a_to_hl
LD A,(HL)
OR A
JP Z,dli_next
; Is it here or carried?
POP BC
PUSH BC
LD A,C
DEC A
LD HL,item_locations
CALL add_a_to_hl
LD A,(HL)
LD D,A
LD A,(current_room)
CP D
JP Z,dli_accessible
LD A,D
OR A
JP NZ,dli_next
dli_accessible:
; Check name matches
POP BC
PUSH BC
LD A,C
CALL get_item_name_ptr
EX DE,HL
LD HL,(temp_ptr)
CALL str_contains
JP NZ,dli_next
; Found container - check if open
POP BC
PUSH BC
LD A,C
DEC A
LD HL,item_is_open
CALL add_a_to_hl
LD A,(HL)
OR A
JP NZ,dli_show_contents
; Closed
POP BC
LD HL,msg_closed
CALL print_str
CALL print_nl
RET
dli_show_contents:
POP BC
LD A,C
LD (temp_container),A
CALL print_nl
LD HL,msg_inside
CALL print_str
CALL print_nl
; Search for items with parent = container
LD A,NUM_ITEMS
OR A
JP Z,dli_empty
LD B,A
LD C,1
LD E,0
dli_content_loop:
PUSH BC
PUSH DE
LD A,C
DEC A
LD HL,item_parents
CALL add_a_to_hl
LD A,(HL)
LD D,A
LD A,(temp_container)
CP D
JP NZ,dli_content_next
; Found item in container
LD HL,msg_indent
CALL print_str
POP DE
POP BC
PUSH BC
PUSH DE
LD A,C
CALL get_item_name_ptr
CALL print_str
CALL print_nl
POP DE
LD E,1
PUSH DE
dli_content_next:
POP DE
POP BC
INC C
DEC B
JP NZ,dli_content_loop
LD A,E
OR A
JP NZ,dli_done
dli_empty:
LD HL,msg_empty_c
CALL print_str
CALL print_nl
dli_done:
CALL wait_key
RET
dli_next:
POP BC
INC C
DEC B
JP NZ,dli_loop
dli_not_found:
LD HL,msg_notcontainer
CALL print_str
CALL print_nl
RET
; ========================================
; ACTION: TAKE ITEM FROM CONTAINER
; ========================================
do_take_from:
; Parse 'TAKE item FROM container'
LD HL,input_buffer
LD DE,str_kw_from
CALL str_find
JP NC,dtf_syntax_err
LD (temp_ptr2),HL ; position of ' FROM '
; Get item name (after TAKE, before FROM)
LD HL,input_buffer
LD B,5 ; skip 'TAKE '
dtf_skip:
INC HL
DJNZ dtf_skip
LD (temp_ptr),HL ; item name start
; Get container name (after ' FROM ')
LD HL,(temp_ptr2)
LD B,6 ; skip ' FROM '
dtf_skip2:
INC HL
DJNZ dtf_skip2
LD A,(HL)
OR A
JP Z,dtf_syntax_err
LD (temp_ptr3),HL ; container name start
; Find container in room or inventory
LD A,NUM_ITEMS
OR A
JP Z,dtf_no_container
LD B,A
LD C,1
dtf_cont_loop:
PUSH BC
; Is it a container?
LD A,C
DEC A
LD HL,item_is_container
CALL add_a_to_hl
LD A,(HL)
OR A
JP Z,dtf_cont_next
; Is it here or carried?
POP BC
PUSH BC
LD A,C
DEC A
LD HL,item_locations
CALL add_a_to_hl
LD A,(HL)
LD D,A
LD A,(current_room)
CP D
JP Z,dtf_cont_accessible
LD A,D
OR A ; 0 = carried
JP NZ,dtf_cont_next
dtf_cont_accessible:
; Check container name matches
POP BC
PUSH BC
LD A,C
CALL get_item_name_ptr
EX DE,HL
LD HL,(temp_ptr3)
CALL str_contains
JP NZ,dtf_cont_next
; Found container!
POP BC
LD A,C
LD (temp_container),A
JP dtf_check_open
dtf_cont_next:
POP BC
INC C
DEC B
JP NZ,dtf_cont_loop
dtf_no_container:
LD HL,msg_notcontainer
CALL print_str
CALL print_nl
RET
dtf_check_open:
; Check if container is open
LD A,(temp_container)
DEC A
LD HL,item_is_open
CALL add_a_to_hl
LD A,(HL)
OR A
JP NZ,dtf_find_item
LD HL,msg_closed
CALL print_str
CALL print_nl
RET
dtf_find_item:
; Find item in container
LD A,NUM_ITEMS
LD B,A
LD C,1
dtf_item_loop:
PUSH BC
; Check if item is in this container
LD A,C
DEC A
LD HL,item_parents
CALL add_a_to_hl
LD A,(HL)
LD D,A
LD A,(temp_container)
CP D
JP NZ,dtf_item_next
; Check item name matches
POP BC
PUSH BC
LD A,C
CALL get_item_name_ptr
EX DE,HL
LD HL,(temp_ptr)
CALL str_partial_match
JP NZ,dtf_item_next
; Found item! Check inventory space
LD A,(inv_count)
CP INV_LIMIT
JP C,dtf_can_take
POP BC
LD HL,msg_full
CALL print_str
CALL print_nl
RET
dtf_can_take:
POP BC
; Add to inventory
LD A,C
CALL add_to_inventory
; Remove from container (set parent to 0)
LD A,C
DEC A
LD HL,item_parents
CALL add_a_to_hl
LD (HL),0
; Set location to 0 (carried)
LD A,C
DEC A
LD HL,item_locations
CALL add_a_to_hl
LD (HL),0
; Add points
PUSH BC
LD A,C
DEC A
LD HL,item_points
CALL add_a_to_hl
LD A,(HL)
OR A
JP Z,dtf_no_points
LD HL,(score)
LD B,0
LD C,A
ADD HL,BC
LD (score),HL
; Clear points
POP BC
PUSH BC
LD A,C
DEC A
LD HL,item_points
CALL add_a_to_hl
LD (HL),0
dtf_no_points:
POP BC
LD HL,msg_taken
CALL print_str
CALL print_nl
RET
dtf_item_next:
POP BC
INC C
DEC B
JP NZ,dtf_item_loop
LD HL,msg_nothere
CALL print_str
CALL print_nl
RET
dtf_syntax_err:
LD HL,msg_takefrom_syntax
CALL print_str
CALL print_nl
RET
; ========================================
; ACTION: TALK TO NPC
; ========================================
do_talk:
LD HL,input_buffer
CALL add_a_to_hl
LD (temp_ptr),HL
LD A,(HL)
OR A
JP NZ,dtk_have_name
LD HL,msg_talkto
CALL print_str
CALL print_nl
RET
dtk_have_name:
LD A,NUM_NPCS
OR A
JP Z,dtk_noone
LD B,A
LD C,1
dtk_loop:
PUSH BC
LD A,C
DEC A
LD HL,npc_locations
CALL add_a_to_hl
LD A,(HL)
LD D,A
LD A,(current_room)
CP D
JP NZ,dtk_next
POP BC
PUSH BC
LD A,C
CALL get_npc_name_ptr
EX DE,HL
LD HL,(temp_ptr)
CALL str_contains
JP NZ,dtk_next
POP BC
LD A,C
CALL get_npc_talk_ptr
LD A,(HL)
OR A
JR NZ,dtk_has_dialog
LD HL,msg_silence
CALL print_str
CALL print_nl
RET
dtk_has_dialog:
CALL print_nl
LD A,34 ; quote char
CALL TXT_OUTPUT
CALL print_str
LD A,34
CALL TXT_OUTPUT
CALL print_nl
CALL wait_key
RET
dtk_next:
POP BC
INC C
DEC B
JP NZ,dtk_loop
dtk_noone:
LD HL,msg_noone
CALL print_str
CALL print_nl
RET
; ========================================
; ACTION: GIVE ITEM TO NPC
; ========================================
do_give:
; Parse 'GIVE item TO npc'
LD HL,input_buffer
LD DE,str_kw_to
CALL str_find
JP NC,dg_syntax_err
LD (temp_ptr2),HL
; Get item name start (after GIVE )
LD HL,input_buffer
LD B,5 ; skip 'GIVE '
dg_skip:
INC HL
DJNZ dg_skip
LD (temp_ptr),HL
; Get NPC name (after ' TO ')
LD HL,(temp_ptr2)
LD B,4 ; skip ' TO '
dg_skip2:
INC HL
DJNZ dg_skip2
LD A,(HL)
OR A
JP Z,dg_syntax_err
LD (temp_ptr3),HL
; Find item in inventory
LD A,(inv_count)
OR A
JP Z,dg_no_item
LD B,A
LD C,1
dg_item_loop:
PUSH BC
LD A,C
DEC A
LD HL,inventory
CALL add_a_to_hl
LD A,(HL)
OR A
JP Z,dg_item_next
PUSH AF
CALL get_item_name_ptr
EX DE,HL
LD HL,(temp_ptr)
CALL str_partial_match
POP AF
JP NZ,dg_item_next
LD (found_item),A
POP BC
LD A,C
LD (found_inv_slot),A
JP dg_find_npc
dg_item_next:
POP BC
INC C
DEC B
JP NZ,dg_item_loop
dg_no_item:
LD HL,msg_donthave
CALL print_str
CALL print_nl
RET
dg_find_npc:
LD A,NUM_NPCS
OR A
JP Z,dg_no_npc
LD B,A
LD C,1
dg_npc_loop:
PUSH BC
LD A,C
DEC A
LD HL,npc_locations
CALL add_a_to_hl
LD A,(HL)
LD D,A
LD A,(current_room)
CP D
JP NZ,dg_npc_next
POP BC
PUSH BC
LD A,C
CALL get_npc_name_ptr
EX DE,HL
LD HL,(temp_ptr3)
CALL str_contains
JP NZ,dg_npc_next
POP BC
LD A,C
LD (found_npc),A
JP dg_do_give
dg_npc_next:
POP BC
INC C
DEC B
JP NZ,dg_npc_loop
dg_no_npc:
LD HL,msg_noone
CALL print_str
CALL print_nl
RET
dg_do_give:
; Check if NPC already got gift
LD A,(found_npc)
DEC A
LD HL,npc_got_gift
CALL add_a_to_hl
LD A,(HL)
OR A
JP NZ,dg_nothing
; Check if NPC wants this item
LD A,(found_npc)
CALL get_npc_wants_ptr
LD A,(HL)
OR A
JP Z,dg_no_want
EX DE,HL
LD A,(found_item)
CALL get_item_name_ptr
CALL str_equal
JP NZ,dg_no_want
; NPC accepts!
LD A,(found_inv_slot)
CALL remove_from_inventory
; Mark NPC
LD A,(found_npc)
DEC A
LD HL,npc_got_gift
CALL add_a_to_hl
LD (HL),1
; Add points
LD A,(found_npc)
DEC A
LD HL,npc_points
CALL add_a_to_hl
LD A,(HL)
OR A
JR Z,dg_no_points
LD HL,(score)
LD B,0
LD C,A
ADD HL,BC
LD (score),HL
dg_no_points:
LD HL,msg_thanks
CALL print_str
CALL print_nl
; Check reward
LD A,(found_npc)
CALL get_npc_gives_ptr
LD A,(HL)
OR A
RET Z
LD HL,msg_got
CALL print_str
LD A,(found_npc)
CALL get_npc_gives_ptr
CALL print_str
CALL print_nl
RET
dg_nothing:
LD HL,msg_nothing
CALL print_str
CALL print_nl
RET
dg_no_want:
LD HL,msg_nowant
CALL print_str
CALL print_nl
RET
dg_syntax_err:
LD HL,msg_give_syntax
CALL print_str
CALL print_nl
RET
; ========================================
; ACTION: SHOW INVENTORY
; ========================================
do_inventory:
CALL print_nl
LD HL,msg_inventory
CALL print_str
CALL print_nl
LD A,(inv_count)
OR A
JR NZ,di_show_items
LD HL,msg_empty
CALL print_str
CALL print_nl
CALL wait_key
RET
di_show_items:
LD B,A
LD C,1
di_loop:
PUSH BC
LD A,C
DEC A
LD HL,inventory
CALL add_a_to_hl
LD A,(HL)
OR A
JR Z,di_next
LD HL,msg_indent
CALL print_str
POP BC
PUSH BC
LD A,C
DEC A
LD HL,inventory
CALL add_a_to_hl
LD A,(HL)
CALL get_item_name_ptr
CALL print_str
CALL print_nl
di_next:
POP BC
INC C
DJNZ di_loop
CALL wait_key
RET
; ========================================
; ACTION: SHOW HELP
; ========================================
do_help:
CALL print_nl
LD HL,str_help_text
CALL print_str
CALL wait_key
RET
; ========================================
; ACTION: SHOW SCORE
; ========================================
do_show_score:
CALL print_nl
LD HL,msg_score
CALL print_str
LD HL,(score)
CALL print_num
CALL print_nl
CALL wait_key
RET
; ========================================
; ACTION: QUIT GAME
; ========================================
do_quit:
CALL print_nl
LD HL,msg_bye
CALL print_str
CALL print_nl
CALL wait_key
; Clean return to BASIC
LD SP,(original_sp) ; Restore original stack
RET ; Return to BASIC
; ========================================
; ACTION: SAVE GAME
; ========================================
do_save:
CALL print_nl
LD HL,msg_filename
CALL print_str
; Get filename from user
CALL get_filename
LD A,(filename_len)
OR A
JP Z,do_save_cancel
; Open file for writing
LD B,A ; B = filename length
LD HL,filename_buf
LD DE,cas_buffer ; 2KB buffer for cassette
CALL CAS_OUT_OPEN
JP NC,do_save_error
; Save game data
LD HL,save_data_start
LD DE,save_data_end-save_data_start
LD BC,0 ; execution address (not used)
LD A,2 ; file type = binary
CALL CAS_OUT_DIRECT
JP NC,do_save_error_close
; Close file
CALL CAS_OUT_CLOSE
LD HL,msg_saved
CALL print_str
CALL print_nl
RET
do_save_error_close:
CALL CAS_OUT_CLOSE
do_save_error:
LD HL,msg_save_error
CALL print_str
CALL print_nl
RET
do_save_cancel:
LD HL,msg_cancelled
CALL print_str
CALL print_nl
RET
; ========================================
; ACTION: LOAD GAME
; ========================================
do_load:
CALL print_nl
LD HL,msg_filename
CALL print_str
; Get filename from user
CALL get_filename
LD A,(filename_len)
OR A
JP Z,do_load_cancel
; Open file for reading
LD B,A ; B = filename length
LD HL,filename_buf
LD DE,cas_buffer ; 2KB buffer for cassette
CALL CAS_IN_OPEN
JP NC,do_load_error
; Load game data
LD HL,save_data_start
CALL CAS_IN_DIRECT
JP NC,do_load_error_close
; Close file
CALL CAS_IN_CLOSE
; Set refresh flag
LD A,1
LD (refresh_flag),A
LD HL,msg_loaded
CALL print_str
CALL print_nl
RET
do_load_error_close:
CALL CAS_IN_CLOSE
do_load_error:
LD HL,msg_load_error
CALL print_str
CALL print_nl
RET
do_load_cancel:
LD HL,msg_cancelled
CALL print_str
CALL print_nl
RET
; ========================================
; GET FILENAME (max 8 chars)
; ========================================
get_filename:
CALL TXT_CUR_ON
LD HL,filename_buf
LD B,0 ; char count
gfn_loop:
CALL KM_WAIT_CHAR
CP 13 ; Enter
JR Z,gfn_done
CP 27 ; Escape
JR Z,gfn_escape
CP 127 ; Delete
JR Z,gfn_backspace
CP 8 ; Backspace
JR Z,gfn_backspace
CP 32 ; Must be >= space
JR C,gfn_loop
CP '.' ; No dots allowed
JR Z,gfn_loop
; Check max length (8 chars)
LD C,A
LD A,B
CP 8
JR NC,gfn_loop ; Already 8 chars
LD A,C
; Convert to uppercase
CP 'a'
JR C,gfn_store
CP 'z'+1
JR NC,gfn_store
SUB 32
gfn_store:
LD (HL),A
INC HL
INC B
CALL TXT_OUTPUT
JR gfn_loop
gfn_backspace:
LD A,B
OR A
JR Z,gfn_loop
DEC HL
DEC B
LD A,8
CALL TXT_OUTPUT
LD A,' '
CALL TXT_OUTPUT
LD A,8
CALL TXT_OUTPUT
JR gfn_loop
gfn_escape:
LD B,0 ; Return empty = cancelled
gfn_done:
LD A,B
LD (filename_len),A
CALL TXT_CUR_OFF
CALL print_nl
RET
; ========================================
; CHECK IF ROOM IS DEADLY
; ========================================
check_death:
LD A,NUM_DEADLY
OR A
RET Z
LD B,A
LD C,0
cd_loop:
PUSH BC
LD A,C
LD HL,deadly_rooms
CALL add_a_to_hl
LD A,(HL)
LD D,A
LD A,(current_room)
CP D
JP NZ,cd_next
; In deadly room - check survival item
POP BC
PUSH BC
LD A,C
CALL get_survival_item_ptr
LD A,(HL)
OR A
JP Z,cd_die
CALL check_have_item
JP C,cd_next
cd_die:
CALL TXT_CLEAR
CALL print_nl
POP BC
LD A,C
CALL get_death_msg_ptr
CALL print_str
CALL print_nl
CALL print_nl
LD HL,msg_gameover
CALL print_str
CALL print_nl
CALL wait_key
LD SP,(original_sp)
RET
cd_next:
POP BC
INC C
DEC B
JP NZ,cd_loop
RET
; ========================================
; CHECK WIN CONDITION
; ========================================
check_win:
LD A,WIN_ROOM
OR A
RET Z
LD B,A
LD A,(current_room)
CP B
RET NZ
; Check score
LD A,WIN_SCORE
OR A
JR Z,cw_check_items
LD HL,(score)
LD B,0
LD C,A
OR A
SBC HL,BC
RET C
cw_check_items:
LD A,WIN_ITEMS_COUNT
OR A
JR Z,cw_win
cw_win:
CALL TXT_CLEAR
CALL print_nl
LD HL,str_winmsg
CALL print_str
CALL print_nl
CALL print_nl
LD HL,msg_youwin
CALL print_str
CALL print_nl
LD HL,msg_score
CALL print_str
LD HL,(score)
CALL print_num
CALL print_nl
CALL wait_key
LD SP,(original_sp)
RET
; ========================================
; UTILITY FUNCTIONS
; ========================================
; Print null-terminated string at HL
print_str:
LD A,(HL)
OR A
RET Z
CALL TXT_OUTPUT
INC HL
JR print_str
; Print CR/LF
print_nl:
LD A,13
CALL TXT_OUTPUT
LD A,10
CALL TXT_OUTPUT
RET
; Print 16-bit number in HL
print_num:
LD DE,10000
CALL pn_digit
LD DE,1000
CALL pn_digit
LD DE,100
CALL pn_digit
LD DE,10
CALL pn_digit
LD A,L
ADD A,'0'
CALL TXT_OUTPUT
RET
pn_digit:
LD A,'0'-1
pn_loop:
INC A
OR A
SBC HL,DE
JR NC,pn_loop
ADD HL,DE
CALL TXT_OUTPUT
RET
; Wait for keypress
wait_key:
LD HL,msg_presskey
CALL print_str
CALL KM_WAIT_CHAR
CALL print_nl
RET
; Add A to HL
add_a_to_hl:
ADD A,L
LD L,A
RET NC
INC H
RET
; Compare strings HL and DE, Z if equal
str_equal:
PUSH HL
PUSH DE
seq_loop:
LD A,(DE)
CP (HL)
JR NZ,seq_ne
OR A
JR Z,seq_eq
INC HL
INC DE
JR seq_loop
seq_eq:
POP DE
POP HL
XOR A
RET
seq_ne:
POP DE
POP HL
OR 1
RET
; Check if HL starts with DE (B chars), Z if match
str_prefix:
PUSH HL
PUSH DE
sp_loop:
LD A,B
OR A
JR Z,sp_match
LD A,(DE)
CP (HL)
JR NZ,sp_no
INC HL
INC DE
DEC B
JR sp_loop
sp_match:
POP DE
POP HL
XOR A
RET
sp_no:
POP DE
POP HL
OR 1
RET
; Check if DE contains HL substring, Z if found
str_contains:
PUSH HL
PUSH DE
sc_outer:
LD A,(DE)
OR A
JR Z,sc_no
PUSH HL
PUSH DE
sc_inner:
LD A,(HL)
OR A
JR Z,sc_yes_pop
LD A,(DE)
OR A
JR Z,sc_no_pop
CP (HL)
JR NZ,sc_no_pop
INC HL
INC DE
JR sc_inner
sc_yes_pop:
POP DE
POP HL
POP DE
POP HL
XOR A
RET
sc_no_pop:
POP DE
POP HL
INC DE
JR sc_outer
sc_no:
POP DE
POP HL
OR 1
RET
; Partial match - HL until space/TO in DE, Z if found
str_partial_match:
PUSH HL
PUSH DE
spm_outer:
LD A,(DE)
OR A
JR Z,spm_no
PUSH HL
PUSH DE
spm_inner:
LD A,(HL)
OR A
JR Z,spm_yes_pop
CP ' '
JR Z,spm_yes_pop
LD A,(DE)
OR A
JR Z,spm_no_pop
CP (HL)
JR NZ,spm_no_pop
INC HL
INC DE
JR spm_inner
spm_yes_pop:
POP DE
POP HL
POP DE
POP HL
XOR A
RET
spm_no_pop:
POP DE
POP HL
INC DE
JR spm_outer
spm_no:
POP DE
POP HL
OR 1
RET
; Find DE substring in HL, C flag if found, HL = match pos
str_find:
LD (sf_de_save),DE ; Save search string pointer
sf_loop:
LD A,(HL)
OR A
JR Z,sf_no ; End of string, not found
PUSH HL ; Save current position
LD DE,(sf_de_save) ; Get search string
sf_cmp:
LD A,(DE)
OR A
JR Z,sf_yes ; End of search string = found!
CP (HL)
JR NZ,sf_cmp_no ; Mismatch
INC HL
INC DE
JR sf_cmp
sf_yes:
POP HL ; HL = position where match started
SCF ; Set carry = found
RET
sf_cmp_no:
POP HL ; Restore position
INC HL ; Try next position
JR sf_loop
sf_no:
OR A ; Clear carry = not found
RET
sf_de_save:
DEFW 0 ; Storage for DE
; ========================================
; DATA ACCESS FUNCTIONS
; ========================================
; Get room name pointer for room A
get_room_name_ptr:
DEC A
SLA A
LD HL,room_name_ptrs
CALL add_a_to_hl
LD A,(HL)
INC HL
LD H,(HL)
LD L,A
RET
; Get room desc pointer for room A
get_room_desc_ptr:
DEC A
SLA A
LD HL,room_desc_ptrs
CALL add_a_to_hl
LD A,(HL)
INC HL
LD H,(HL)
LD L,A
RET
; Get exit: A=room, B=dir(1-6), returns A=target
get_exit:
PUSH BC
DEC A
LD C,A
LD A,B
DEC A
LD B,A
; offset = room * 6 + dir
LD A,C
LD H,0
LD L,A
ADD HL,HL
ADD HL,HL
LD D,0
LD E,A
ADD HL,DE
ADD HL,DE
LD A,B
CALL add_a_to_hl
LD DE,room_exits
ADD HL,DE
LD A,(HL)
POP BC
RET
; Check exit unlocked: A=room, B=dir, A=1 if open
check_exit_unlocked:
PUSH BC
DEC A
LD C,A
LD A,B
DEC A
LD B,A
LD A,C
LD H,0
LD L,A
ADD HL,HL
ADD HL,HL
LD D,0
LD E,A
ADD HL,DE
ADD HL,DE
LD A,B
CALL add_a_to_hl
LD DE,room_unlocked
ADD HL,DE
LD A,(HL)
POP BC
RET
; Set exit unlocked: A=room, B=dir
set_exit_unlocked:
PUSH BC
DEC A
LD C,A
LD A,B
DEC A
LD B,A
LD A,C
LD H,0
LD L,A
ADD HL,HL
ADD HL,HL
LD D,0
LD E,A
ADD HL,DE
ADD HL,DE
LD A,B
CALL add_a_to_hl
LD DE,room_unlocked
ADD HL,DE
LD (HL),1
POP BC
RET
; Get exit requirement: A=room, B=dir, HL=ptr
get_exit_requirement:
PUSH BC
DEC A
LD C,A
LD A,B
DEC A
LD B,A
LD A,C
LD H,0
LD L,A
ADD HL,HL
ADD HL,HL
LD D,0
LD E,A
ADD HL,DE
ADD HL,DE
LD A,B
CALL add_a_to_hl
ADD HL,HL
LD DE,room_req_ptrs
ADD HL,DE
LD A,(HL)
INC HL
LD H,(HL)
LD L,A
POP BC
RET
; Get item name: A=index(1-based), HL=ptr
get_item_name_ptr:
DEC A
SLA A
LD HL,item_name_ptrs
CALL add_a_to_hl
LD A,(HL)
INC HL
LD H,(HL)
LD L,A
RET
; Get item desc: A=index, HL=ptr
get_item_desc_ptr:
DEC A
SLA A
LD HL,item_desc_ptrs
CALL add_a_to_hl
LD A,(HL)
INC HL
LD H,(HL)
LD L,A
RET
; Get NPC name: A=index(1-based), HL=ptr
get_npc_name_ptr:
DEC A
SLA A
LD HL,npc_name_ptrs
CALL add_a_to_hl
LD A,(HL)
INC HL
LD H,(HL)
LD L,A
RET
; Get NPC desc: A=index, HL=ptr
get_npc_desc_ptr:
DEC A
SLA A
LD HL,npc_desc_ptrs
CALL add_a_to_hl
LD A,(HL)
INC HL
LD H,(HL)
LD L,A
RET
; Get NPC talk: A=index, HL=ptr
get_npc_talk_ptr:
DEC A
SLA A
LD HL,npc_talk_ptrs
CALL add_a_to_hl
LD A,(HL)
INC HL
LD H,(HL)
LD L,A
RET
; Get NPC wants: A=index, HL=ptr
get_npc_wants_ptr:
DEC A
SLA A
LD HL,npc_wants_ptrs
CALL add_a_to_hl
LD A,(HL)
INC HL
LD H,(HL)
LD L,A
RET
; Get NPC gives: A=index, HL=ptr
get_npc_gives_ptr:
DEC A
SLA A
LD HL,npc_gives_ptrs
CALL add_a_to_hl
LD A,(HL)
INC HL
LD H,(HL)
LD L,A
RET
; Get death msg: A=index, HL=ptr
get_death_msg_ptr:
SLA A
LD HL,death_msg_ptrs
CALL add_a_to_hl
LD A,(HL)
INC HL
LD H,(HL)
LD L,A
RET
; Get survival item: A=index, HL=ptr
get_survival_item_ptr:
SLA A
LD HL,survival_item_ptrs
CALL add_a_to_hl
LD A,(HL)
INC HL
LD H,(HL)
LD L,A
RET
; ========================================
; INVENTORY MANAGEMENT
; ========================================
; Add item A to inventory
add_to_inventory:
PUSH AF
LD A,(inv_count)
LD HL,inventory
CALL add_a_to_hl
POP AF
LD (HL),A
LD A,(inv_count)
INC A
LD (inv_count),A
RET
; Remove item at slot A
remove_from_inventory:
LD (rfi_slot),A
DEC A
LD HL,inventory
CALL add_a_to_hl
LD D,H
LD E,L
INC DE
LD A,(inv_count)
LD B,A
LD A,(rfi_slot)
SUB B
NEG
JR Z,rfi_done
LD B,A
rfi_shift:
LD A,(DE)
LD (HL),A
INC HL
INC DE
DJNZ rfi_shift
rfi_done:
LD A,(inv_count)
DEC A
LD (inv_count),A
RET
rfi_slot:
DEFB 0
; Check if have item, HL=name, C flag if yes
check_have_item:
LD (chi_name),HL
LD A,(inv_count)
OR A
JR Z,chi_no
LD B,A
LD C,1
chi_loop:
PUSH BC
LD A,C
DEC A
LD HL,inventory
CALL add_a_to_hl
LD A,(HL)
OR A
JR Z,chi_next
CALL get_item_name_ptr
LD DE,(chi_name)
CALL str_contains
JR NZ,chi_next
POP BC
SCF
RET
chi_next:
POP BC
INC C
DJNZ chi_loop
chi_no:
OR A
RET
chi_name:
DEFW 0
; ========================================
; INITIALIZE GAME DATA
; ========================================
init_data:
; Copy initial item locations
LD HL,item_locations_init
LD DE,item_locations
LD BC,NUM_ITEMS
LD A,B
OR C
JR Z,id_skip_items
LDIR
id_skip_items:
; Copy initial item parents
LD HL,item_parents_init
LD DE,item_parents
LD BC,NUM_ITEMS
LD A,B
OR C
JR Z,id_skip_parents
LDIR
id_skip_parents:
; Copy initial NPC locations
LD HL,npc_locations_init
LD DE,npc_locations
LD BC,NUM_NPCS
LD A,B
OR C
JR Z,id_skip_npcs
LDIR
id_skip_npcs:
; Init unlocked flags to 0 (locked by default)
; Exits without requirements are always open (checked in do_move)
LD HL,room_unlocked
LD BC,NUM_ROOMS*6
id_unlock_loop:
XOR A
LD (HL),A
INC HL
DEC BC
LD A,B
OR C
JR NZ,id_unlock_loop
; Clear item open flags
LD HL,item_is_open
LD BC,NUM_ITEMS
LD A,B
OR C
JR Z,id_skip_open
id_open_loop:
XOR A
LD (HL),A
INC HL
DEC BC
LD A,B
OR C
JR NZ,id_open_loop
id_skip_open:
; Clear NPC gift flags
LD HL,npc_got_gift
LD BC,NUM_NPCS
LD A,B
OR C
JR Z,id_skip_gift
id_gift_loop:
XOR A
LD (HL),A
INC HL
DEC BC
LD A,B
OR C
JR NZ,id_gift_loop
id_skip_gift:
; Clear inventory
LD HL,inventory
LD B,MAX_INV
XOR A
id_inv_loop:
LD (HL),A
INC HL
DJNZ id_inv_loop
RET
; ========================================
; GAME DATA
; ========================================
str_title:
DEFB "THE FORGOTTEN MAYA PRINCESS",0
str_author:
DEFB "Devil-System",0
str_by:
DEFB "by ",0
str_winmsg:
DEFB "Princess Ixchel embraces you! Together",13,10
DEFB "you escape into the sunset!",0
str_help_text:
DEFB "COMMANDS:",13,10
DEFB "N,S,E,W,U,D - Move",13,10
DEFB "TAKE, DROP, USE",13,10
DEFB "EXAMINE, OPEN, CLOSE",13,10
DEFB "TALK TO, GIVE X TO Y",13,10
DEFB "I, L, SCORE, QUIT",0
str_dir_n:
DEFB "N ",0
str_dir_e:
DEFB "E ",0
str_dir_s:
DEFB "S ",0
str_dir_w:
DEFB "W ",0
str_dir_u:
DEFB "U ",0
str_dir_d:
DEFB "D ",0
str_kw_to:
DEFB " TO ",0
str_kw_from:
DEFB " FROM ",0
; === MESSAGES ===
msg_filename:
DEFB "SAVEFILE (no ext.):",0
msg_saved:
DEFB "Game saved.",0
msg_loaded:
DEFB "Game loaded.",0
msg_save_error:
DEFB "Can't save.",0
msg_load_error:
DEFB "Can't load.",0
msg_cancelled:
DEFB "Cancelled.",0
msg_takefrom_syntax:
DEFB "TAKE X FROM Y",0
msg_yousee:
DEFB "You see: ",0
msg_inside:
DEFB "Inside: ",0
msg_empty_c:
DEFB " Empty.",0
msg_exits:
DEFB "Exits: ",0
msg_none:
DEFB "none",0
msg_score:
DEFB "Score: ",0
msg_presskey:
DEFB "[key]",0
msg_unknown:
DEFB "Huh?",0
msg_cantgo:
DEFB "Can't go there.",0
msg_blocked:
DEFB "Blocked.",0
msg_what:
DEFB "What?",0
msg_nothere:
DEFB "Not here.",0
msg_donthave:
DEFB "Don't have it.",0
msg_full:
DEFB "Full!",0
msg_taken:
DEFB "Taken.",0
msg_dropped:
DEFB "Dropped.",0
msg_usewhat:
DEFB "Use what?",0
msg_unlocked:
DEFB "Unlocked!",0
msg_nothing:
DEFB "Nothing happens.",0
msg_nothing_special:
DEFB "You see nothing special.",0
msg_opened:
DEFB "Opened.",0
msg_closed:
DEFB "Closed.",0
msg_notcontainer:
DEFB "Can't open that.",0
msg_talkto:
DEFB "Talk to whom?",0
msg_noone:
DEFB "No one here.",0
msg_silence:
DEFB "...",0
msg_thanks:
DEFB "Thanks!",0
msg_nowant:
DEFB "They don't want that.",0
msg_got:
DEFB "Got: ",0
msg_give_syntax:
DEFB "GIVE X TO Y",0
msg_inventory:
DEFB "Inventory:",0
msg_empty:
DEFB " empty",0
msg_indent:
DEFB " ",0
msg_gameover:
DEFB "GAME OVER",0
msg_youwin:
DEFB "YOU WIN!",0
msg_bye:
DEFB "Goodbye!",0
str_empty:
DEFB 0
; === COMMAND STRINGS ===
cmd_north:
DEFB "N",0
cmd_north1:
DEFB "NORTH",0
cmd_north2:
DEFB "GO NORTH",0
cmd_south:
DEFB "S",0
cmd_south1:
DEFB "SOUTH",0
cmd_south2:
DEFB "GO SOUTH",0
cmd_east:
DEFB "E",0
cmd_east1:
DEFB "EAST",0
cmd_east2:
DEFB "GO EAST",0
cmd_west:
DEFB "W",0
cmd_west1:
DEFB "WEST",0
cmd_west2:
DEFB "GO WEST",0
cmd_up:
DEFB "U",0
cmd_up1:
DEFB "UP",0
cmd_up2:
DEFB "GO UP",0
cmd_up3:
DEFB "CLIMB",0
cmd_down:
DEFB "D",0
cmd_down1:
DEFB "DOWN",0
cmd_down2:
DEFB "DN",0
cmd_down3:
DEFB "GO DOWN",0
cmd_down4:
DEFB "DESCEND",0
cmd_lookin:
DEFB "L IN",0
cmd_lookin1:
DEFB "LOOK IN",0
cmd_lookin2:
DEFB "EXAMINE ROOM IN",0
cmd_look:
DEFB "L",0
cmd_look1:
DEFB "LOOK",0
cmd_look2:
DEFB "EXAMINE ROOM",0
cmd_inv:
DEFB "I",0
cmd_inv1:
DEFB "INV",0
cmd_inv2:
DEFB "INVENTORY",0
cmd_take:
DEFB "TAKE",0
cmd_take1:
DEFB "GET",0
cmd_take2:
DEFB "GRAB",0
cmd_take3:
DEFB "PICK UP",0
cmd_drop:
DEFB "DROP",0
cmd_drop1:
DEFB "PUT DOWN",0
cmd_drop2:
DEFB "LEAVE",0
cmd_exam:
DEFB "EXAMINE",0
cmd_exam1:
DEFB "X",0
cmd_exam2:
DEFB "LOOK AT",0
cmd_exam3:
DEFB "CHECK",0
cmd_exam4:
DEFB "INSPECT",0
cmd_use:
DEFB "USE",0
cmd_use1:
DEFB "APPLY",0
cmd_open:
DEFB "OPEN",0
cmd_close:
DEFB "CLOSE",0
cmd_close1:
DEFB "SHUT",0
cmd_talk:
DEFB "TALK TO",0
cmd_talk1:
DEFB "SPEAK TO",0
cmd_talk2:
DEFB "ASK TO",0
cmd_talk3:
DEFB "SAY TO",0
cmd_give:
DEFB "GIVE",0
cmd_give1:
DEFB "OFFER",0
cmd_give2:
DEFB "HAND",0
cmd_help:
DEFB "HELP",0
cmd_help1:
DEFB "?",0
cmd_help2:
DEFB "COMMANDS",0
cmd_help3:
DEFB "HINT",0
cmd_score:
DEFB "SCORE",0
cmd_score1:
DEFB "POINTS",0
cmd_save:
DEFB "SAVE",0
cmd_save1:
DEFB "SAVE GAME",0
cmd_load:
DEFB "LOAD",0
cmd_load1:
DEFB "RESTORE",0
cmd_load2:
DEFB "LOAD GAME",0
cmd_quit:
DEFB "QUIT",0
cmd_quit1:
DEFB "EXIT",0
cmd_quit2:
DEFB "Q",0
cmd_quit3:
DEFB "BYE",0
; === ROOM DATA ===
room_name_ptrs:
DEFW room_1_name
DEFW room_2_name
DEFW room_3_name
DEFW room_4_name
DEFW room_5_name
DEFW room_6_name
DEFW room_7_name
DEFW room_8_name
DEFW room_9_name
DEFW room_10_name
DEFW room_11_name
DEFW room_12_name
DEFW room_13_name
DEFW room_14_name
DEFW room_15_name
DEFW room_16_name
DEFW room_17_name
DEFW room_18_name
DEFW room_19_name
DEFW room_20_name
DEFW room_21_name
DEFW room_22_name
DEFW room_23_name
DEFW room_24_name
DEFW room_25_name
room_desc_ptrs:
DEFW room_1_desc
DEFW room_2_desc
DEFW room_3_desc
DEFW room_4_desc
DEFW room_5_desc
DEFW room_6_desc
DEFW room_7_desc
DEFW room_8_desc
DEFW room_9_desc
DEFW room_10_desc
DEFW room_11_desc
DEFW room_12_desc
DEFW room_13_desc
DEFW room_14_desc
DEFW room_15_desc
DEFW room_16_desc
DEFW room_17_desc
DEFW room_18_desc
DEFW room_19_desc
DEFW room_20_desc
DEFW room_21_desc
DEFW room_22_desc
DEFW room_23_desc
DEFW room_24_desc
DEFW room_25_desc
room_1_name:
DEFB "Base Camp",0
room_1_desc:
DEFB "Your expedition camp at jungle's edge.",13,10
DEFB "A worn tent and smoking fire. Your",13,10
DEFB "guide fled, leaving notes about a",13,10
DEFB "cursed princess of legendary beauty.",0
room_2_name:
DEFB "Jungle Trail",0
room_2_desc:
DEFB "A narrow path through dense",13,10
DEFB "vegetation. Howler monkeys scream",13,10
DEFB "above. The humidity makes your clothes",13,10
DEFB "cling to your body.",0
room_3_name:
DEFB "Riverside",0
room_3_desc:
DEFB "A swift river blocks your path.",13,10
DEFB "Crocodiles bask on muddy banks,",13,10
DEFB "watching hungrily. You need a way to",13,10
DEFB "cross safely.",0
room_4_name:
DEFB "Abandoned Camp",0
room_4_desc:
DEFB "A destroyed campsite. Torn tents and",13,10
DEFB "scattered gear. A skeleton clutches a",13,10
DEFB "journal. Something terrible happened",13,10
DEFB "here.",0
room_5_name:
DEFB "Jungle Clearing",0
room_5_desc:
DEFB "Sunlight breaks through the canopy.",13,10
DEFB "Exotic birds sing. Stone markers hint",13,10
DEFB "at ancient civilization ahead.",0
room_6_name:
DEFB "Shaman's Hut",0
room_6_desc:
DEFB "A hut draped with colorful fabrics.",13,10
DEFB "Incense curls through the air. Strange",13,10
DEFB "masks hang on walls. The smell is",13,10
DEFB "intoxicating.",0
room_7_name:
DEFB "Jaguar's Den",0
room_7_desc:
DEFB "A dark cave reeking of musk. Yellow",13,10
DEFB "eyes gleam from shadows. Low growling",13,10
DEFB "echoes. The beast is hungry.",0
room_8_name:
DEFB "Overgrown Path",0
room_8_desc:
DEFB "Thick vines block your way north.",13,10
DEFB "Carvings on trees depict a beautiful",13,10
DEFB "woman, her curves shown in flowing",13,10
DEFB "robes.",0
room_9_name:
DEFB "Quicksand Marsh",0
room_9_desc:
DEFB "Treacherous boggy ground. Bubbles rise",13,10
DEFB "from hidden pools. One wrong step",13,10
DEFB "means slow death.",0
room_10_name:
DEFB "Sacred Cenote",0
room_10_desc:
DEFB "A deep pool of crystal blue water.",13,10
DEFB "Ancient Maya threw offerings here.",13,10
DEFB "Gold glitters in the depths.",0
room_11_name:
DEFB "Temple Steps",0
room_11_desc:
DEFB "Massive stone steps lead to a pyramid.",13,10
DEFB "Carved reliefs show a princess - full",13,10
DEFB "lips, flowing hair, alluring curves.",0
room_12_name:
DEFB "Serpent Pit",0
room_12_desc:
DEFB "A chamber filled with writhing snakes.",13,10
DEFB "Their hissing echoes. Hundreds of",13,10
DEFB "forked tongues taste the air.",0
room_13_name:
DEFB "Outer Treasury",0
room_13_desc:
DEFB "Gold and jade scattered everywhere.",13,10
DEFB "Silks and perfume bottles hint at a",13,10
DEFB "lady's presence. A faint scent",13,10
DEFB "lingers.",0
room_14_name:
DEFB "Temple Entrance",0
room_14_desc:
DEFB "A vast hall with towering serpent",13,10
DEFB "columns. Torches flicker. Murals",13,10
DEFB "depict ceremonies honoring a beautiful",13,10
DEFB "maiden.",0
room_15_name:
DEFB "Priest's Quarters",0
room_15_desc:
DEFB "Dusty scrolls and ritual objects. A",13,10
DEFB "skeleton in robes sits at a desk,",13,10
DEFB "quill in hand. His message unfinished.",0
room_16_name:
DEFB "Inner Treasury",0
room_16_desc:
DEFB "The princess's treasure room. Jewels",13,10
DEFB "sparkle. Delicate silk garments hint",13,10
DEFB "at her refined tastes.",0
room_17_name:
DEFB "Main Temple Hall",0
room_17_desc:
DEFB "An enormous chamber. Moonlight streams",13,10
DEFB "through openings. Murals show the",13,10
DEFB "princess dancing sensually under",13,10
DEFB "stars.",0
room_18_name:
DEFB "Bathing Pool",0
room_18_desc:
DEFB "A crystal pool surrounded by orchids.",13,10
DEFB "Warm steam rises. Rose petals float.",13,10
DEFB "The princess bathed here.",0
room_19_name:
DEFB "Cursed Altar",0
room_19_desc:
DEFB "A black obsidian altar with glowing",13,10
DEFB "symbols. Dark energy pulses. The",13,10
DEFB "priest cast his curse here.",0
room_20_name:
DEFB "Garden of Desire",0
room_20_desc:
DEFB "A hidden garden with moonflowers. Soft",13,10
DEFB "music plays from nowhere. Aphrodisiac",13,10
DEFB "scents fill the air.",0
room_21_name:
DEFB "Spirit Sanctuary",0
room_21_desc:
DEFB "Ethereal mist swirls here. Candles",13,10
DEFB "float in midair. The boundary between",13,10
DEFB "worlds is thin.",0
room_22_name:
DEFB "Royal Wardrobe",0
room_22_desc:
DEFB "Sheer silk gowns fill wardrobes. Lace",13,10
DEFB "garments lie draped over chairs. A",13,10
DEFB "vanity reflects your flushed face.",0
room_23_name:
DEFB "Princess's Chamber",0
room_23_desc:
DEFB "Silk curtains frame a golden bed.",13,10
DEFB "PRINCESS IXCHEL lies there, caramel",13,10
DEFB "skin glowing, curves beneath thin",13,10
DEFB "white silk.",0
room_24_name:
DEFB "Hidden Passage",0
room_24_desc:
DEFB "A secret tunnel behind the bed. Cool",13,10
DEFB "air flows from ahead. This is the",13,10
DEFB "escape route.",0
room_25_name:
DEFB "Temple Exit",0
room_25_desc:
DEFB "Warm sunlight streams through ancient",13,10
DEFB "doors. The jungle awaits. Freedom for",13,10
DEFB "those who carry true love.",0
room_exits:
DEFB 2,0,0,0,0,0 ; Room 1
DEFB 5,4,1,3,0,0 ; Room 2
DEFB 6,2,0,0,0,0 ; Room 3
DEFB 7,0,0,2,0,0 ; Room 4
DEFB 8,7,2,6,0,0 ; Room 5
DEFB 9,5,3,0,0,0 ; Room 6
DEFB 10,0,4,5,0,0 ; Room 7
DEFB 11,10,5,9,0,0 ; Room 8
DEFB 12,8,6,0,0,0 ; Room 9
DEFB 13,0,7,8,0,0 ; Room 10
DEFB 14,13,8,12,0,0 ; Room 11
DEFB 15,11,9,0,0,0 ; Room 12
DEFB 16,0,10,11,0,0 ; Room 13
DEFB 17,16,11,15,0,0 ; Room 14
DEFB 18,14,12,0,0,0 ; Room 15
DEFB 19,0,13,14,0,0 ; Room 16
DEFB 20,19,14,18,0,0 ; Room 17
DEFB 21,17,15,0,0,0 ; Room 18
DEFB 22,0,16,17,0,0 ; Room 19
DEFB 23,22,17,21,0,0 ; Room 20
DEFB 24,20,18,0,0,0 ; Room 21
DEFB 0,0,19,20,0,0 ; Room 22
DEFB 0,0,20,24,0,0 ; Room 23
DEFB 25,23,21,0,0,0 ; Room 24
DEFB 0,0,24,0,0,0 ; Room 25
room_req_ptrs:
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW room_8_req_north
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW room_11_req_north
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW room_13_req_north
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW room_17_req_north
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW room_20_req_north
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW room_24_req_north
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
DEFW str_empty
room_8_req_north:
DEFB "MACHETE",0
room_11_req_north:
DEFB "TEMPLE KEY",0
room_13_req_north:
DEFB "SILVER KEY",0
room_17_req_north:
DEFB "SPIRIT BLESSING",0
room_20_req_north:
DEFB "GOLDEN KEY",0
room_24_req_north:
DEFB "JADE HEART",0
; === ITEM DATA ===
item_name_ptrs:
DEFW item_1_name
DEFW item_2_name
DEFW item_3_name
DEFW item_4_name
DEFW item_5_name
DEFW item_6_name
DEFW item_7_name
DEFW item_8_name
DEFW item_9_name
DEFW item_10_name
DEFW item_11_name
DEFW item_12_name
DEFW item_13_name
DEFW item_14_name
DEFW item_15_name
DEFW item_16_name
DEFW item_17_name
DEFW item_18_name
DEFW item_19_name
DEFW item_20_name
DEFW item_21_name
DEFW item_22_name
DEFW item_23_name
DEFW item_24_name
DEFW item_25_name
DEFW item_26_name
DEFW item_27_name
DEFW item_28_name
DEFW item_29_name
DEFW item_30_name
DEFW item_31_name
DEFW item_32_name
item_desc_ptrs:
DEFW item_1_desc
DEFW item_2_desc
DEFW item_3_desc
DEFW item_4_desc
DEFW item_5_desc
DEFW item_6_desc
DEFW item_7_desc
DEFW item_8_desc
DEFW item_9_desc
DEFW item_10_desc
DEFW item_11_desc
DEFW item_12_desc
DEFW item_13_desc
DEFW item_14_desc
DEFW item_15_desc
DEFW item_16_desc
DEFW item_17_desc
DEFW item_18_desc
DEFW item_19_desc
DEFW item_20_desc
DEFW item_21_desc
DEFW item_22_desc
DEFW item_23_desc
DEFW item_24_desc
DEFW item_25_desc
DEFW item_26_desc
DEFW item_27_desc
DEFW item_28_desc
DEFW item_29_desc
DEFW item_30_desc
DEFW item_31_desc
DEFW item_32_desc
item_locations_init:
DEFB 1
DEFB 1
DEFB 1
DEFB 2
DEFB 4
DEFB 4
DEFB 4
DEFB 4
DEFB 6
DEFB 6
DEFB 6
DEFB 5
DEFB 10
DEFB 10
DEFB 10
DEFB 11
DEFB 13
DEFB 13
DEFB 13
DEFB 15
DEFB 15
DEFB 16
DEFB 16
DEFB 16
DEFB 18
DEFB 18
DEFB 20
DEFB 20
DEFB 21
DEFB 22
DEFB 22
DEFB 22
item_is_container:
DEFB 1
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 1
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 1
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 1
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
item_points:
DEFB 0
DEFB 5
DEFB 10
DEFB 5
DEFB 15
DEFB 0
DEFB 10
DEFB 10
DEFB 20
DEFB 15
DEFB 10
DEFB 15
DEFB 25
DEFB 15
DEFB 20
DEFB 5
DEFB 0
DEFB 20
DEFB 15
DEFB 20
DEFB 15
DEFB 0
DEFB 30
DEFB 25
DEFB 10
DEFB 15
DEFB 15
DEFB 25
DEFB 35
DEFB 20
DEFB 15
DEFB 20
item_parents_init:
DEFB 0
DEFB 1
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 6
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 17
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 22
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
DEFB 0
item_1_name:
DEFB "EXPEDITION BAG",0
item_1_desc:
DEFB "A weathered leather bag left behind.",0
item_2_name:
DEFB "COMPASS",0
item_2_desc:
DEFB "A brass compass. Spins wildly near the",13,10
DEFB "temple.",0
item_3_name:
DEFB "ROPE",0
item_3_desc:
DEFB "A long coil of strong rope.",0
item_4_name:
DEFB "CANTEEN",0
item_4_desc:
DEFB "A metal canteen filled with water.",0
item_5_name:
DEFB "JOURNAL",0
item_5_desc:
DEFB "Describes the princess: 'Skin like",13,10
DEFB "honey, lips like petals, curves that",13,10
DEFB "drive men mad.'",0
item_6_name:
DEFB "WOODEN CHEST",0
item_6_desc:
DEFB "A rotting chest half-buried in mud.",0
item_7_name:
DEFB "MACHETE",0
item_7_desc:
DEFB "A sharp jungle blade for cutting",13,10
DEFB "vines.",0
item_8_name:
DEFB "WOODEN PLANK",0
item_8_desc:
DEFB "A sturdy plank to cross soft ground.",0
item_9_name:
DEFB "SNAKE CHARM",0
item_9_desc:
DEFB "A wooden flute that mesmerizes",13,10
DEFB "serpents.",0
item_10_name:
DEFB "LOVE POTION",0
item_10_desc:
DEFB "Pink liquid in a heart bottle.",13,10
DEFB "'Awakens passion.'",0
item_11_name:
DEFB "RAW MEAT",0
item_11_desc:
DEFB "Fresh meat wrapped in leaves.",13,10
DEFB "Predators love it.",0
item_12_name:
DEFB "EXOTIC ORCHID",0
item_12_desc:
DEFB "A purple flower with intoxicating",13,10
DEFB "fragrance.",0
item_13_name:
DEFB "GOLD COINS",0
item_13_desc:
DEFB "Ancient Maya gold coins. Worth a",13,10
DEFB "fortune.",0
item_14_name:
DEFB "DIVING MASK",0
item_14_desc:
DEFB "Primitive diving mask of glass and",13,10
DEFB "leather.",0
item_15_name:
DEFB "TEMPLE KEY",0
item_15_desc:
DEFB "Heavy bronze key with serpent",13,10
DEFB "engravings.",0
item_16_name:
DEFB "TORCH",0
item_16_desc:
DEFB "A burning torch for dark passages.",0
item_17_name:
DEFB "JEWELED BOX",0
item_17_desc:
DEFB "An ornate box with rubies and",13,10
DEFB "emeralds.",0
item_18_name:
DEFB "SILVER KEY",0
item_18_desc:
DEFB "A delicate silver key shaped like a",13,10
DEFB "flower.",0
item_19_name:
DEFB "SILK SCARF",0
item_19_desc:
DEFB "Rose-colored. Still carries her sweet",13,10
DEFB "perfume.",0
item_20_name:
DEFB "ANCIENT SCROLL",0
item_20_desc:
DEFB "'Only true love's kiss can wake the",13,10
DEFB "sleeping beauty.'",0
item_21_name:
DEFB "RITUAL DAGGER",0
item_21_desc:
DEFB "An obsidian blade for ancient",13,10
DEFB "ceremonies.",0
item_22_name:
DEFB "TREASURE CHEST",0
item_22_desc:
DEFB "A golden chest overflowing with",13,10
DEFB "jewels.",0
item_23_name:
DEFB "JADE AMULET",0
item_23_desc:
DEFB "Protective amulet pulsing with warm",13,10
DEFB "energy.",0
item_24_name:
DEFB "GOLDEN KEY",0
item_24_desc:
DEFB "A heart-shaped key. Unlocks something",13,10
DEFB "precious.",0
item_25_name:
DEFB "ROSE PETALS",0
item_25_desc:
DEFB "Soft petals floating on the pool.",13,10
DEFB "Divine scent.",0
item_26_name:
DEFB "BATH OIL",0
item_26_desc:
DEFB "Crystal vial of seductive scented oil.",0
item_27_name:
DEFB "PASSION FRUIT",0
item_27_desc:
DEFB "Ripe exotic fruit. Its juice awakens",13,10
DEFB "desire.",0
item_28_name:
DEFB "MOONFLOWER",0
item_28_desc:
DEFB "Rare white flower of legendary beauty.",0
item_29_name:
DEFB "JADE NECKLACE",0
item_29_desc:
DEFB "Exquisite necklace with heart-shaped",13,10
DEFB "pendant.",0
item_30_name:
DEFB "SILK GOWN",0
item_30_desc:
DEFB "Sheer white gown leaving little to",13,10
DEFB "imagination.",0
item_31_name:
DEFB "PERFUME",0
item_31_desc:
DEFB "Crystal bottle of seductive tropical",13,10
DEFB "essence.",0
item_32_name:
DEFB "LACE GARMENT",0
item_32_desc:
DEFB "Delicate intimate garment of finest",13,10
DEFB "lace.",0
; === NPC DATA ===
npc_name_ptrs:
DEFW npc_1_name
DEFW npc_2_name
DEFW npc_3_name
DEFW npc_4_name
DEFW npc_5_name
DEFW npc_6_name
DEFW npc_7_name
DEFW npc_8_name
npc_desc_ptrs:
DEFW npc_1_desc
DEFW npc_2_desc
DEFW npc_3_desc
DEFW npc_4_desc
DEFW npc_5_desc
DEFW npc_6_desc
DEFW npc_7_desc
DEFW npc_8_desc
npc_talk_ptrs:
DEFW npc_1_talk
DEFW npc_2_talk
DEFW npc_3_talk
DEFW npc_4_talk
DEFW npc_5_talk
DEFW npc_6_talk
DEFW npc_7_talk
DEFW npc_8_talk
npc_wants_ptrs:
DEFW npc_1_wants
DEFW npc_2_wants
DEFW npc_3_wants
DEFW npc_4_wants
DEFW npc_5_wants
DEFW npc_6_wants
DEFW npc_7_wants
DEFW npc_8_wants
npc_gives_ptrs:
DEFW npc_1_gives
DEFW npc_2_gives
DEFW npc_3_gives
DEFW npc_4_gives
DEFW npc_5_gives
DEFW npc_6_gives
DEFW npc_7_gives
DEFW npc_8_gives
npc_locations_init:
DEFB 6
DEFB 5
DEFB 17
DEFB 18
DEFB 21
DEFB 22
DEFB 23
DEFB 19
npc_points:
DEFB 20
DEFB 25
DEFB 30
DEFB 25
DEFB 50
DEFB 20
DEFB 60
DEFB 30
npc_1_name:
DEFB "OLD SHAMAN",0
npc_1_desc:
DEFB "A wise old man with knowing eyes and",13,10
DEFB "colorful feathers.",0
npc_1_talk:
DEFB "You seek the princess! Take the",13,10
DEFB "charm for serpents. Feed the jaguar.",13,10
DEFB "Women love flowers!",0
npc_1_wants:
DEFB "CANTEEN",0
npc_1_gives:
DEFB "BLESSING POWDER",0
npc_2_name:
DEFB "JUNGLE GUIDE",0
npc_2_desc:
DEFB "Your former guide hiding in bushes. He",13,10
DEFB "looks ashamed.",0
npc_2_talk:
DEFB "Forgive me! Take this temple key",13,10
DEFB "from the cenote. Beware quicksand to",13,10
DEFB "the west!",0
npc_2_wants:
DEFB "GOLD COINS",0
npc_2_gives:
DEFB "TEMPLE MAP",0
npc_3_name:
DEFB "TEMPLE GUARDIAN",0
npc_3_desc:
DEFB "Muscular spirit warrior with ancient",13,10
DEFB "tattoos.",0
npc_3_talk:
DEFB "Prove worthy! Bring the priest's",13,10
DEFB "scroll to pass to the sacred garden!",0
npc_3_wants:
DEFB "ANCIENT SCROLL",0
npc_3_gives:
DEFB "SPIRIT BLESSING",0
npc_4_name:
DEFB "BATHING NYMPH",0
npc_4_desc:
DEFB "Water spirit with glistening wet skin",13,10
DEFB "and playful eyes.",0
npc_4_talk:
DEFB "The princess bathed here. Bring",13,10
DEFB "orchid and I'll share altar secrets.",0
npc_4_wants:
DEFB "EXOTIC ORCHID",0
npc_4_gives:
DEFB "WATER BLESSING",0
npc_5_name:
DEFB "QUEEN IXMUCANE",0
npc_5_desc:
DEFB "Ghost of princess's mother. Still",13,10
DEFB "beautiful in ethereal silks.",0
npc_5_talk:
DEFB "My daughter dreams of rescue! Bring",13,10
DEFB "her necklace for the Jade Heart.",0
npc_5_wants:
DEFB "JADE NECKLACE",0
npc_5_gives:
DEFB "JADE HEART",0
npc_6_name:
DEFB "HANDMAIDEN",0
npc_6_desc:
DEFB "Pretty ghost servant in transparent",13,10
DEFB "robes. She blushes.",0
npc_6_talk:
DEFB "My lady awaits true love! She adores",13,10
DEFB "moonflowers and sweet perfume!",0
npc_6_wants:
DEFB "PERFUME",0
npc_6_gives:
DEFB "CHAMBER KEY",0
npc_7_name:
DEFB "PRINCESS IXCHEL",0
npc_7_desc:
DEFB "Legendary beauty on silken bed.",13,10
DEFB "Caramel skin, dark hair, curves in",13,10
DEFB "thin white silk.",0
npc_7_talk:
DEFB "You came! Kiss me and free me! But",13,10
DEFB "first... flowers for your princess?",0
npc_7_wants:
DEFB "MOONFLOWER",0
npc_7_gives:
DEFB "PRINCESS KISS",0
npc_8_name:
DEFB "CURSED PRIEST",0
npc_8_desc:
DEFB "Skeleton of the jealous priest. Dark",13,10
DEFB "energy swirls around.",0
npc_8_talk:
DEFB "She was meant for ME! The curse",13,10
DEFB "stays... unless you have the jade",13,10
DEFB "amulet!",0
npc_8_wants:
DEFB "RITUAL DAGGER",0
npc_8_gives:
DEFB "CURSE FRAGMENT",0
; === DEADLY ROOMS ===
deadly_rooms:
DEFB 3
DEFB 7
DEFB 9
DEFB 12
DEFB 19
death_msg_ptrs:
DEFW death_msg_0
DEFW death_msg_1
DEFW death_msg_2
DEFW death_msg_3
DEFW death_msg_4
survival_item_ptrs:
DEFW survival_0
DEFW survival_1
DEFW survival_2
DEFW survival_3
DEFW survival_4
death_msg_0:
DEFB "You try to swim! The crocodiles are",13,10
DEFB "faster!",0
survival_0:
DEFB "ROPE",0
death_msg_1:
DEFB "The jaguar pounces! Its claws tear",13,10
DEFB "through you!",0
survival_1:
DEFB "RAW MEAT",0
death_msg_2:
DEFB "You sink into quicksand! Darkness",13,10
DEFB "takes you!",0
survival_2:
DEFB "WOODEN PLANK",0
death_msg_3:
DEFB "The serpents strike! Venom burns",13,10
DEFB "through you!",0
survival_3:
DEFB "SNAKE CHARM",0
death_msg_4:
DEFB "Dark magic engulfs you! Your soul is",13,10
DEFB "torn away!",0
survival_4:
DEFB "JADE AMULET",0
; ========================================
; VARIABLES (RAM)
; ========================================
; === SAVE DATA BLOCK START ===
; All game state that needs to be saved
save_data_start:
current_room:
DEFS 1
score:
DEFS 2
inv_count:
DEFS 1
inventory:
DEFS MAX_INV
item_locations:
DEFS NUM_ITEMS
item_is_open:
DEFS NUM_ITEMS
item_parents:
DEFS NUM_ITEMS
npc_locations:
DEFS NUM_NPCS
npc_got_gift:
DEFS NUM_NPCS
room_unlocked:
DEFS NUM_ROOMS*6
save_data_end:
; === SAVE DATA BLOCK END ===
; === TEMPORARY VARIABLES (not saved) ===
refresh_flag:
DEFS 1
temp_dir:
DEFS 1
temp_room:
DEFS 1
temp_target:
DEFS 1
temp_container:
DEFS 1
temp_ptr:
DEFS 2
temp_ptr2:
DEFS 2
temp_ptr3:
DEFS 2
found_item:
DEFS 1
found_inv_slot:
DEFS 1
found_npc:
DEFS 1
input_len:
DEFS 1
input_buffer:
DEFS INPUT_MAX+1
; === FILENAME INPUT ===
filename_len:
DEFS 1
filename_buf:
DEFS 16 ; Max 8 chars + some padding
; === CASSETTE BUFFER (2KB needed by firmware) ===
cas_buffer:
DEFS 2048
; === ORIGINAL STACK POINTER ===
original_sp:
DEFS 2
; === END ===
Ist noch gründlich zu testen!
WoW! Sauber! Das ist ein schöner erster Schritt, und super schnell hinbekommen!!! Respekt und Kudos!
Sage mir bitte bescheid, sobald das stabil läuft, dann könnte man ja eine Version für FutureOS machen, denn dann läuft es wirklich schnell.
Eventuell kann man dann auch Erweiterungs-RAM nutzen. Aber ein Schritt nach dem Anderen :) :) :)
Der Assemblerteil hatte noch Fehler, das ist nun behoben, etwaige Savegames passen allerdings nicht mehr...