Re-initializing repo leaving out game assets.

This commit is contained in:
Martin Haye 2013-07-20 08:42:23 -07:00
commit 18eb40eda8
24 changed files with 1847 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
*.class
*.2mg
*.swp
ASSETS

7
a2copy/.classpath Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="lib" path="lib/ac.jar" sourcepath="/Users/mhaye/Dropbox/Apple II/Projects/Lawless Legends/AppleCommander-1.3.5.13-src/src"/>
<classpathentry kind="output" path="bin"/>
</classpath>

17
a2copy/.project Normal file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>a2copy</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

BIN
a2copy/a2copy.jar Normal file

Binary file not shown.

16
a2copy/a2copy.jardesc Normal file
View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="MacRoman" standalone="no"?>
<jardesc>
<jar path="a2copy/a2copy.jar"/>
<options buildIfNeeded="true" compress="true" descriptionLocation="/a2copy/a2copy.jardesc" exportErrors="true" exportWarnings="true" includeDirectoryEntries="false" overwrite="true" saveDescription="true" storeRefactorings="false" useSourceFolders="false"/>
<storedRefactorings deprecationInfo="true" structuralOnly="false"/>
<selectedProjects/>
<manifest generateManifest="true" mainClassHandleIdentifier="=a2copy/src&lt;{A2copy.java[A2copy" manifestLocation="" manifestVersion="1.0" reuseManifest="false" saveManifest="false" usesManifest="true">
<sealing sealJar="false">
<packagesToSeal/>
<packagesToUnSeal/>
</sealing>
</manifest>
<selectedElements exportClassFiles="true" exportJavaFiles="false" exportOutputFolder="false">
<javaElement handleIdentifier="=a2copy/src"/>
</selectedElements>
</jardesc>

1
a2copy/lib/VERSIONS Normal file
View File

@ -0,0 +1 @@
ac.jar = AppleCommander-1.3.5.13-ac.jar with Martn's patch for proper sub-directory creation

BIN
a2copy/lib/ac.jar Normal file

Binary file not shown.

321
a2copy/src/A2copy.java Normal file
View File

@ -0,0 +1,321 @@
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.List;
import java.util.zip.GZIPInputStream;
import com.webcodepro.applecommander.storage.DirectoryEntry;
import com.webcodepro.applecommander.storage.Disk;
import com.webcodepro.applecommander.storage.DiskFullException;
import com.webcodepro.applecommander.storage.FileEntry;
import com.webcodepro.applecommander.storage.FormattedDisk;
/*
* This class uses AppleCommander's command-line interface to extract an entire
* set of files and directories from an image, or build a whole image from
* files and directories.
*
* Has specific hard-coded addresses for Lawless Legends files; should fix this
* at some point to use a metadata configuration file or something like that.
*/
public class A2copy
{
/*
* Main command-line driver
*/
public static void main(String[] args)
throws IOException, DiskFullException
{
try
{
if (args[0].equals("-extract")) {
extractImg(args[1], args[2]);
return;
}
if (args[0].equals("-create")) {
createImg(args[1], args[2]);
return;
}
}
catch (ArrayIndexOutOfBoundsException e)
{ }
System.err.format("Usage: A2copy [-extract imgFile targetDir] | [-create imgFile sourceDir]\n");
System.exit(1);
}
/**
* Helper to delete a file or directory and all its descendants.
* @throws IOException if something goes wrong
*/
static void delete(File f) throws IOException {
if (f.isDirectory()) {
for (File c : f.listFiles())
delete(c);
}
if (!f.delete())
throw new FileNotFoundException("Failed to delete file: " + f);
}
/**
* Extract all the files and directories from an image file.
* @throws IOException if something goes wrong
*/
@SuppressWarnings("unchecked")
static void extractImg(String imgPath, String targetPath) throws IOException
{
// Ensure the target directory is empty first.
File targetDir = new File(targetPath);
if (targetDir.exists()) {
System.out.format("Note: %s will be overwritten. Continue? ", targetPath);
System.out.flush();
String response = new BufferedReader(new InputStreamReader(System.in)).readLine();
if (!response.toLowerCase().startsWith("y"))
return;
delete(targetDir);
}
// Open the image file and process disks inside it.
Disk disk = new Disk(imgPath);
for (FormattedDisk fd : disk.getFormattedDisks())
extractFiles((List<FileEntry>)fd.getFiles(), targetDir);
}
/**
* Helper for file/directory extraction.
* @param files set of files to extract
* @param targetDir where to put them
* @throws IOException if something goes wrong
*/
@SuppressWarnings("unchecked")
static void extractFiles(List<FileEntry> files, File targetDir) throws IOException
{
// Ensure the target directory exists
targetDir.mkdir();
// Process each entry in the list
for (FileEntry e : files)
{
// Skip deleted things
if (e.isDeleted())
continue;
// Recursively process sub-directories
if (e.isDirectory()) {
File subDir = new File(targetDir, e.getFilename());
extractFiles(((DirectoryEntry)e).getFiles(), subDir);
continue;
}
// Process regular files.
byte[] data = e.getFileData();
// Hi to lo ASCII translation
if (e.getFilename().endsWith(".S"))
data = merlinSrcToAscii(data);
FileOutputStream out = new FileOutputStream(new File(targetDir, e.getFilename()));
out.write(data);
out.close();
}
}
/**
* Creates an image file using dirs/files from the filesystem.
* @param imgPath name of the image file
* @param srcDirPath directory containing files and subdirs
* @throws DiskFullException if the image file fills up
* @throws IOException if something else goes wrong
*/
static void createImg(String imgPath, String srcDirPath)
throws IOException, DiskFullException
{
// Alert the user that we're going to blow away the image.
File imgFile = new File(imgPath);
if (imgFile.exists()) {
System.out.format("Note: %s will be overwritten. Continue? ", imgPath);
System.out.flush();
String response = new BufferedReader(new InputStreamReader(System.in)).readLine();
if (!response.toLowerCase().startsWith("y"))
return;
delete(imgFile);
}
// Re-create the image file with a blank image.
File emptyFile = new File(imgFile.getParent(), "empty.2mg.gz");
if (!emptyFile.canRead())
throw new IOException(String.format("Cannot open template for empty image '%s'", emptyFile.toString()));
InputStream in = new BufferedInputStream(new GZIPInputStream(new FileInputStream(emptyFile)));
OutputStream out = new BufferedOutputStream(new FileOutputStream(imgFile));
byte[] buf = new byte[1024];
while (true) {
int nRead = in.read(buf);
if (nRead < 0)
break;
out.write(buf, 0, nRead);
}
in.close();
out.close();
// Open the empty image file.
Disk disk = new Disk(imgPath);
FormattedDisk fd = disk.getFormattedDisks()[0];
// And fill it up.
insertFiles(fd, fd, new File(srcDirPath));
}
/**
* Helper for image creation.
*
* @param fd disk to insert files into
* @param targetDir directory within the disk
* @param srcDir filesystem directory to read
* @throws DiskFullException if the image file fills up
* @throws IOException if something else goes wrong
*/
private static void insertFiles(FormattedDisk fd, DirectoryEntry targetDir, File srcDir)
throws DiskFullException, IOException
{
// Process each file in the source directory
for (File srcFile : srcDir.listFiles())
{
if (srcFile.isDirectory()) {
DirectoryEntry subDir = targetDir.createDirectory(srcFile.getName().toUpperCase());
insertFiles(fd, subDir, srcFile);
continue;
}
// Create a new entry on the filesystem for this file.
FileEntry ent = targetDir.createFile();
String srcName = srcFile.getName().toUpperCase();
ent.setFilename(srcName);
// Set the file type
if (srcName.equals("PRODOS") || srcName.endsWith(".SYSTEM"))
ent.setFiletype("SYS");
else if (srcName.equals("STARTUP"))
ent.setFiletype("BAS");
else if (srcName.endsWith(".S"))
ent.setFiletype("TXT");
else
ent.setFiletype("BIN");
// Set the address if necessary
if (ent.needsAddress()) {
if (srcName.equals("STARTUP"))
ent.setAddress(0x801);
else if (srcName.equals("COPYIIPL.SYSTEM"))
ent.setAddress(0x1400);
else if (srcName.equals("ED.16"))
ent.setAddress(0x9d60);
else if (srcName.equals("ED"))
ent.setAddress(0x9db6);
else if (srcName.equals("SHELL"))
ent.setAddress(0x300);
else
ent.setAddress(0x2000);
}
// Copy the file data
FileInputStream in = new FileInputStream(srcFile);
byte[] buf = new byte[(int) srcFile.length()];
int nRead = in.read(buf);
if (nRead != srcFile.length())
throw new IOException(String.format("Error reading file '%s'", srcFile.toString()));
// Translate between hi and lo ASCII
if (srcName.endsWith(".S"))
buf = asciiToMerlinSrc(buf);
ent.setFileData(buf);
// And save the new entry.
fd.save();
}
}
/**
* Translates Merlin source code to usable code in the regular ASCII world.
* Performs weird-space to tab translation, and hi bit conversion.
*
* @param buf data to translate
* @return translated data
*/
static byte[] merlinSrcToAscii(byte[] buf)
{
ByteArrayOutputStream ba = new ByteArrayOutputStream(buf.length);
PrintWriter out = new PrintWriter(ba);
boolean inComment = false;
for (byte b : buf)
{
// Handle newlines
if (b == (byte)0x8d) {
out.println();
inComment = false;
}
else {
char c = (char)(b & 0x7f);
// Tabs outside comments
if (c == ';' || c == '*')
inComment = true;
if (c == '\n')
throw new RuntimeException("Newline slipped through");
if (c == ' ' && !inComment)
out.write('\t');
else
out.write(c);
}
}
out.flush();
return ba.toByteArray();
}
/**
* Transforms regular ASCII with tabs to Merlin source code. Handles
* tab to weird space translation, and hi-bit addition.
*
* @param buf data to translate
* @return translated data
*/
static byte[] asciiToMerlinSrc(byte[] buf)
{
ByteArrayOutputStream ba = new ByteArrayOutputStream(buf.length);
boolean inComment = false;
for (int i=0; i<buf.length; i++)
{
// Newline translation
if (buf[i] == '\r') {
ba.write(0x8d);
if (i+1 < buf.length && buf[i+1] == '\n')
++i;
inComment = false;
}
else if (buf[i] == '\n') {
ba.write(0x8d);
if (i+1 < buf.length && buf[i+1] == '\r')
++i;
inComment = false;
}
// Tabs outside comments
else if (buf[i] == '\t')
ba.write(0xA0);
else if (buf[i] == ' ' && inComment)
ba.write(0x20);
else if (buf[i] == 0)
ba.write(0);
else {
if (buf[i] == ';' || buf[i] == '*')
inComment = true;
ba.write((((int)buf[i]) & 0xFF) | 0x80);
}
}
return ba.toByteArray();
}
}

30
bin/a2copy.py Executable file
View File

@ -0,0 +1,30 @@
#!/usr/bin/env python
import os, re, subprocess, sys
from os.path import join as pjoin
# This is a simple wrapper that calls the Java a2copy code.
# No matter where we run from, use the right directories.
binDir = os.path.dirname(sys.argv[0])
if not os.path.isabs(binDir):
binDir = pjoin(os.getenv("PWD", os.getcwd()), binDir)
binDir = re.sub("\/?\.?$", "", binDir)
mainDir = os.path.dirname(binDir) # binDir/..
################################################################################
def main():
""" Command-line driver. """
javaCmd = ['java',
'-cp', '%s/a2copy/lib/ac.jar:%s/a2copy/a2copy.jar' % (mainDir, mainDir),
'A2copy']
javaCmd.extend(sys.argv[1:])
proc = subprocess.Popen(javaCmd, stdout = sys.stdout, stderr = sys.stderr)
proc.communicate()
sys.exit(proc.returncode)
################################################################################
main()

32
bin/filesToImg.py Executable file
View File

@ -0,0 +1,32 @@
#!/usr/bin/env python
# This wrapper script takes everything in the 'files' directory and puts it
# into image file 'platform/LL.2mg'.
import os, re, subprocess, sys
from os.path import join as pjoin
# No matter where we run from, use the right directories.
binDir = os.path.dirname(sys.argv[0])
if not os.path.isabs(binDir):
binDir = pjoin(os.getenv("PWD", os.getcwd()), binDir)
binDir = re.sub("\/?\.?$", "", binDir)
mainDir = os.path.dirname(binDir) # binDir/..
################################################################################
def main():
""" Command-line driver. """
os.chdir(mainDir)
javaCmd = ['java',
'-cp', 'a2copy/lib/ac.jar:a2copy/a2copy.jar',
'A2copy',
'-create', 'platform/LL.2mg', 'files/']
proc = subprocess.Popen(javaCmd)
proc.communicate()
sys.exit(proc.returncode)
################################################################################
main()

32
bin/imgToFiles.py Executable file
View File

@ -0,0 +1,32 @@
#!/usr/bin/env python
# This wrapper script copies out the files from 'platform/LL.2mg' into
# the 'files' directory, replacing everything that was in 'files'.
import os, re, subprocess, sys
from os.path import join as pjoin
# No matter where we run from, use the right directories.
binDir = os.path.dirname(sys.argv[0])
if not os.path.isabs(binDir):
binDir = pjoin(os.getenv("PWD", os.getcwd()), binDir)
binDir = re.sub("\/?\.?$", "", binDir)
mainDir = os.path.dirname(binDir) # binDir/..
################################################################################
def main():
""" Command-line driver. """
os.chdir(mainDir)
javaCmd = ['java',
'-cp', 'a2copy/lib/ac.jar:a2copy/a2copy.jar',
'A2copy',
'-extract', 'platform/LL.2mg', 'files/']
proc = subprocess.Popen(javaCmd)
proc.communicate()
sys.exit(proc.returncode)
################################################################################
main()

BIN
files/BASIC.SYSTEM Normal file

Binary file not shown.

BIN
files/COPYIIPL.SYSTEM Normal file

Binary file not shown.

BIN
files/ED Normal file

Binary file not shown.

BIN
files/GAME/RENDER Normal file

Binary file not shown.

1092
files/GAME/RENDER.S Normal file

File diff suppressed because it is too large Load Diff

BIN
files/GAME/SHELL Normal file

Binary file not shown.

202
files/GAME/SHELL.S Normal file
View File

@ -0,0 +1,202 @@
* Tiny shell
LST OFF
XC ; enable 65c02 ops
* Merlin addresses
TEXTSTART = $A
TEXTEND = $E
HIMEM = $C
OBJADDR = $E2
OBJLEN = $E4
ORGADDR = $E6
* Monitor addresses
STARTADDR = $3C
ENDADDR = $3E
DESTADDR = $42
* My zero-pg
MLICMD = $50
* I/O addresses
SETMAINZP = $C008
SETALTZP = $C009
READROM = $C082
LCBANK2 = $C08B
* Other stuff
INBUF = $200
RESETVEC = $3F2
USERVEC = $3F5
CTRLYVEC = $3F8
PRODOSBUF = $BB00
NAMEBUF = $C00
MLI = $BF00
MEMMAP = $BF58
AUXMOVE = $C311
MERLIN = $E003
PRNTAX = $F941
PRHEX = $F944
BASCALC = $FBC1
CALCRESET = $FB6F
INPUT = $FD6A
INPUTZ = $FD6F
CROUT = $FD8E
COUT = $FDED
SETVID = $FE93
PRERR = $FF2D
MONITOR = $FF69
MONSCAN = $FF70
ORG $300
INSTVECS LDA #<TOMON
STA USERVEC+1
LDA #>TOMON
STA USERVEC+2
LDA #<TOMERLIN
STA RESETVEC
STA CTRLYVEC+1
LDA #>TOMERLIN
STA RESETVEC+1
STA CTRLYVEC+2
JMP CALCRESET
* Start of resident code
RUNSHELL
; clear ProDOS memory map
LDX #$18
LDA #1
:MEMLUP
STA MEMMAP-1,X
LDA #0
DEX
BNE :MEMLUP
; display prompt
:LUP LDA PROMPT,X
BEQ :GETNAME
JSR COUT
INX
BNE :LUP
:GETNAME
JSR INPUTZ
TXA
BEQ :MON
:LOADIT
JSR LOADPROG
:MON JMP MONITOR
* Load program, name in INBUF
LOADPROG
; translate filename
LDY #0
STY MLICMD+1 ; filename lo byte
LDA #>NAMEBUF
STA MLICMD+2 ; ...and hi byte
:LUP
LDA INBUF,Y
INY
STA NAMEBUF,Y
CMP #$8D
BNE :LUP
:NAMEDONE
DEY
STY NAMEBUF
LDA #$C4 ; get info
LDX #$A
JSR DOMLI
LDA MLICMD+6 ; addr hi
PHA
LDA MLICMD+5 ; addr lo
PHA
LDA #<PRODOSBUF
STA MLICMD+3
LDA #>PRODOSBUF
STA MLICMD+4
LDA #$C8 ; open
LDX #3
JSR DOMLI
LDA MLICMD+5 ; handle
STA MLICMD+1
PLA ; addr lo
STA MLICMD+2
PLA ; addr hi
STA MLICMD+3
LDA #$CA ; read
STA MLICMD+5 ; also length (more than enough)
INX
JSR DOMLI
; fall through
CLOSE
STZ MLICMD+1 ; close all
LDA #$CC
LDX #1
; fall through
DOMLI
STA MLIOP
STX MLICMD
JSR MLI
MLIOP DFB 0
DA MLICMD
BCS :NO
:OK
RTS
:NO
LDA MLIOP
CMP #$CC
BEQ :OK
; fall through
ERR
JSR PRHEX
JSR CLOSE
JSR PRERR
JMP RUNSHELL
COPYUPPR LDX #$98
LDY #$C0
; fall through
* Copy page X-Y to page A
* Carry: clear = aux2main, set = main2aux
UNITYCOPY TXA
COPY STX STARTADDR+1
STY ENDADDR+1
STA DESTADDR+1
STZ STARTADDR
STZ ENDADDR
STZ DESTADDR
JMP AUXMOVE
TOMON
SEC
JSR COPYUPPR
STA SETMAINZP
BIT READROM
JSR INSTVECS
LDX #$FF
TXS
JSR SETVID
JMP RUNSHELL
TOMERLIN
JSR CLOSE
CLC
JSR COPYUPPR
STA SETALTZP
LDX #$FF
TXS
LDA LCBANK2
JMP MERLIN
PROMPT DFB $8D
ASC "Ld:",00
LST ON
END DFB 0
ERR \$3F0
LST OFF
SAV SHELL

BIN
files/MERLIN.SYSTEM Normal file

Binary file not shown.

BIN
files/PARMS Normal file

Binary file not shown.

93
files/PARMS.S Normal file
View File

@ -0,0 +1,93 @@
********************************
* *
* PARMS *
* *
* for Merlin - ProDOS version. *
* *
* Glen E. Bredon 8/11/85 *
* *
********************************
SAVOBJ KBD "Save the object code? (1=Y, 0=N)"
DATA
DFB 60 ;# lines/page for PRTR
DFB 0 ;Page skip (formfeed if 0)
DFB 80 ;# printer columns
DFB $80 ;- if printer does CR at
; end of # columns
DFB $83 ;80 col flag (DO NOT CHANGE)
;(Except V-bit which will
; cause ProDOS to be moved to
; aux memory and Merlin to
; load into main memory.
; I.e., use $C3 for this.)
*-------------------------------------------------
* Source address must be above $8A0. We use $901
* to maintain compatibility. It can be set higher
* to protect an area of memory for any purpose:
*-------------------------------------------------
SOURCE = $901
DA SOURCE ;Start of source
DA $AA00 ;Don't change this
DA SOURCE ;End of source
DFB <"^" ;Editor's wild card
DFB 4 ;# of symbol columns
DFB 0 ;Search chr for "Update..."
; (Question skipped if 0)
DFB 14,20,31 ;Default tabs
DFB 8 ;# obj bytes/line after 1st
DFB $45 ;High bit neg. forces infinite
; wait for key upon assembly
; errors.
;V-bit set defeats bells.
;Low nibble is Ultraterm entry
; mode (e.g., 5, $45, $85 or $C5
; gives 32x80 interlace mode)
DFB 0 ;Regular cursor if $40
;Block cursor if 0
;(Ignored if Apple card)
DFB 0 ;Default for LSTDO opcode:
;Do off areas listed if 0 or 1,
; not if >1.
;Bit 0, if clear, causes shift
; to 40 columns on a PRTR1 cmd
DFB 80-8 ;Column for cycle count
DFB $EC ;Ultraterm cursor in default
; mode. (This must be changed
; if the ultraterm mode is
; changed.)
ERR *-DATA-23 ;23 data bytes to here.
* User file type names (change to fit your desires):
ASC "$F1"
ASC "$F2"
ASC "$F3"
ASC "$F4"
ASC "$F5"
ASC "$F6"
ASC "$F7"
ERR *-DATA-44 ;44 bytes in all
; no more, no less
*----------------------------------------------
* Be sure to change the following pathname if
* you want this on a volume with another name.
* The PARMS file must be in the MAIN DIRECTORY!
*----------------------------------------------
DO SAVOBJ
SAV /LL/PARMS
FIN

BIN
files/PRODOS Normal file

Binary file not shown.

BIN
files/STARTUP Normal file

Binary file not shown.

BIN
platform/empty.2mg.gz Normal file

Binary file not shown.